#endif
#include "XDisplay.h"
-#include "XScreen.h"
#include "Util.h"
#include <iostream>
#include <algorithm>
using std::cerr;
+using std::endl;
-int XDisplay::XErrorHandler(Display *d, XErrorEvent *e) {
- d=d;e=e;
- return 0;
+std::string XDisplay::_app_name;
+Window XDisplay::_last_bad_window = None;
+
+/*
+ * X error handler to handle all X errors while the application is
+ * running.
+ */
+int XDisplay::errorHandler(Display *d, XErrorEvent *e) {
+#ifdef DEBUG
+ char errtxt[128];
+ XGetErrorText(d, e->error_code, errtxt, sizeof(errtxt)/sizeof(char));
+ cerr << _app_name.c_str() << ": X error: " <<
+ errtxt << "(" << e->error_code << ") opcodes " <<
+ e->request_code << "/" << e->minor_code << endl;
+ cerr.flags(std::ios_base::hex);
+ cerr << " resource 0x" << e->resourceid << endl;
+ cerr.flags(std::ios_base::dec);
+#endif
+
+ if (e->error_code == BadWindow)
+ _last_bad_window = e->resourceid;
+
+ return False;
}
-XDisplay::XDisplay(const char *dpyname) {
+XDisplay::XDisplay(const std::string &application_name, const char *dpyname) {
+ _app_name = application_name;
_grabs = 0;
_hasshape = false;
}
_name = XDisplayName(dpyname);
- XSetErrorHandler(XErrorHandler);
+ XSetErrorHandler(errorHandler);
#ifdef SHAPE
int waste;
_hasshape = XShapeQueryExtension(_display, &_shape_event_base, &waste);
#endif // SHAPE
- const unsigned int scount = ScreenCount(_display);
- _screens.reserve(scount);
- for (unsigned int s = 0; s < scount; s++)
- _screens.push_back(new XScreen(this, s));
+#ifndef NOCLOBBER
+ getLockModifiers();
+#endif
}
}
-/*
- * Return information about a screen.
- */
-XScreen *XDisplay::screen(unsigned int s) const {
- ASSERT(s < _screens.size());
- return _screens[s];
-}
-
-
/*
* Grab the X server
*/
if (--_grabs == 0)
XUngrabServer(_display);
}
+
+
+/*
+ * Gets the next event on the queue from the X server.
+ *
+ * Returns: true if e contains a new event; false if there is no event to be
+ * returned.
+ */
+bool XDisplay::nextEvent(XEvent &e) {
+ if(!XPending(_display))
+ return false;
+ XNextEvent(_display, &e);
+ if (_last_bad_window != None) {
+ if (e.xany.window == _last_bad_window) {
+ cerr << "XDisplay::nextEvent(): Removing event for bad window from " <<
+ "event queue\n";
+ return false;
+ } else
+ _last_bad_window = None;
+ }
+ return true;
+}
+
+
+int XDisplay::connectionNumber() const {
+ return ConnectionNumber(_display);
+}
+
+
+/*
+ * Creates a font cursor in the X server and returns it.
+ */
+Cursor createCursor(unsigned int shape) const {
+ return XCreateFontCursor(_display, shape);
+}
+
+
+#ifndef NOCLOBBER
+void XDisplay::getLockModifers() {
+ NumLockMask = ScrollLockMask = 0;
+
+ const XModifierKeymap* const modmap = XGetModifierMapping(display);
+ if (modmap && modmap->max_keypermod > 0) {
+ const int mask_table[] = {
+ ShiftMask, LockMask, ControlMask, Mod1Mask,
+ Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
+ };
+ const size_t size = (sizeof(mask_table) / sizeof(mask_table[0])) *
+ modmap->max_keypermod;
+ // get the values of the keyboard lock modifiers
+ // Note: Caps lock is not retrieved the same way as Scroll and Num lock
+ // since it doesn't need to be.
+ const KeyCode num_lock_code = XKeysymToKeycode(display, XK_Num_Lock);
+ const KeyCode scroll_lock_code = XKeysymToKeycode(display, XK_Scroll_Lock);
+
+ for (size_t cnt = 0; cnt < size; ++cnt) {
+ if (! modmap->modifiermap[cnt]) continue;
+
+ if (num_lock_code == modmap->modifiermap[cnt])
+ NumLockMask = mask_table[cnt / modmap->max_keypermod];
+ if (scroll_lock_code == modmap->modifiermap[cnt])
+ ScrollLockMask = mask_table[cnt / modmap->max_keypermod];
+ }
+ }
+
+ MaskList[0] = 0;
+ MaskList[1] = LockMask;
+ MaskList[2] = NumLockMask;
+ MaskList[3] = ScrollLockMask;
+ MaskList[4] = LockMask | NumLockMask;
+ MaskList[5] = NumLockMask | ScrollLockMask;
+ MaskList[6] = LockMask | ScrollLockMask;
+ MaskList[7] = LockMask | NumLockMask | ScrollLockMask;
+
+ if (modmap) XFreeModifiermap(const_cast<XModifierKeymap*>(modmap));
+}
+#endif // NOCLOBBER
+
+unsigned int XDisplay::stripModifiers(const unsigned int state) const {
+#ifndef NOCLOBBER
+ return state &= ~(NumLockMask() | ScrollLockMask | LockMask);
+#else
+ return state &= ~LockMask;
+#endif
+}
+
+
+/*
+ * Verifies that a window has not requested to be destroyed/unmapped, so
+ * if it is a valid window or not.
+ * Returns: true if the window is valid; false if it is no longer valid.
+ */
+bool XDisplay::validateWindow(Window window) {
+ XEvent event;
+ if (XCheckTypedWindowEvent(_display, window, DestroyNotify, &event)) {
+ XPutBackEvent(display, &event);
+ return false;
+ }
+ return true;
+}
+
+
+/*
+ * Grabs a button, but also grabs the button in every possible combination with
+ * the keyboard lock keys, so that they do not cancel out the event.
+ */
+void BaseDisplay::grabButton(unsigned int button, unsigned int modifiers,
+ Window grab_window, Bool owner_events,
+ unsigned int event_mask, int pointer_mode,
+ int keybaord_mode, Window confine_to,
+ Cursor cursor) const
+{
+#ifndef NOCLOBBER
+ for (size_t cnt = 0; cnt < 8; ++cnt)
+ XGrabButton(_display, button, modifiers | MaskList[cnt], grab_window,
+ owner_events, event_mask, pointer_mode, keybaord_mode,
+ confine_to, cursor);
+#else // NOCLOBBER
+ XGrabButton(_display, button, modifiers, grab_window,
+ owner_events, event_mask, pointer_mode, keybaord_mode,
+ confine_to, cursor);
+#endif // NOCLOBBER
+}
+
+
+/*
+ * Releases the grab on a button, and ungrabs all possible combinations of the
+ * keyboard lock keys.
+ */
+void BaseDisplay::ungrabButton(unsigned int button, unsigned int modifiers,
+ Window grab_window) const {
+#ifndef NOCLOBBER
+ for (size_t cnt = 0; cnt < 8; ++cnt)
+ XUngrabButton(display, button, modifiers | MaskList[cnt], grab_window);
+#else // NOCLOBBER
+ XUngrabButton(display, button, modifiers, grab_window);
+#endif // NOCLOBBER
+}