XDesktop(Display* dpy_, Geometry *geometry_)
: dpy(dpy_), geometry(geometry_), pb(0), server(0),
oldButtonMask(0), haveXtest(false), haveDamage(false),
- maxButtons(0), running(false), ledMasks(), ledState(0),
- codeMap(0), codeMapLen(0)
- haveXfixes(false), maxButtons(0), running(false)
++ haveXfixes(false), maxButtons(0), running(false),
++ ledMasks(), ledState(0), codeMap(0), codeMapLen(0)
{
+ int major, minor;
+
+ int xkbOpcode, xkbErrorBase;
+
+ major = XkbMajorVersion;
+ minor = XkbMinorVersion;
+ if (!XkbQueryExtension(dpy, &xkbOpcode, &xkbEventBase,
+ &xkbErrorBase, &major, &minor)) {
+ vlog.error("XKEYBOARD extension not present");
+ throw Exception();
+ }
+
+ XkbSelectEvents(dpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask,
+ XkbIndicatorStateNotifyMask);
+
+ // figure out bit masks for the indicators we are interested in
+ for (int i = 0; i < N_LEDS; i++) {
+ Atom a;
+ int shift;
+ Bool on;
+
+ a = XInternAtom(dpy, ledNames[i], True);
+ if (!a || !XkbGetNamedIndicator(dpy, a, &shift, &on, NULL, NULL))
+ continue;
+
+ ledMasks[i] = 1u << shift;
+ vlog.debug("Mask for '%s' is 0x%x", ledNames[i], ledMasks[i]);
+ if (on)
+ ledState |= 1u << i;
+ }
+
+ // X11 unfortunately uses keyboard driver specific keycodes and provides no
+ // direct way to query this, so guess based on the keyboard mapping
+ XkbDescPtr desc = XkbGetKeyboard(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
+ if (desc && desc->names) {
+ char *keycodes = XGetAtomName(dpy, desc->names->keycodes);
+
+ if (keycodes) {
+ if (strncmp("evdev", keycodes, strlen("evdev")) == 0) {
+ codeMap = code_map_qnum_to_xorgevdev;
+ codeMapLen = code_map_qnum_to_xorgevdev_len;
+ vlog.info("Using evdev codemap\n");
+ } else if (strncmp("xfree86", keycodes, strlen("xfree86")) == 0) {
+ codeMap = code_map_qnum_to_xorgkbd;
+ codeMapLen = code_map_qnum_to_xorgkbd_len;
+ vlog.info("Using xorgkbd codemap\n");
+ } else {
+ vlog.info("Unknown keycode '%s', no codemap\n", keycodes);
+ }
+ XFree(keycodes);
+ } else {
+ vlog.debug("Unable to get keycode map\n");
+ }
+
+ XkbFreeKeyboard(desc, XkbAllComponentsMask, True);
+ }
+
#ifdef HAVE_XTEST
int xtestEventBase;
int xtestErrorBase;
}
#endif
- if (not haveDamage)
- TXWindow::setGlobalEventHandler(this);
+ #ifdef HAVE_XFIXES
+ int xfixesErrorBase;
+
+ if (XFixesQueryExtension(dpy, &xfixesEventBase, &xfixesErrorBase)) {
+ haveXfixes = true;
+ } else {
+ #endif
+ vlog.info("XFIXES extension not present");
+ vlog.info("Will not be able to display cursors");
+ #ifdef HAVE_XFIXES
+ }
+ #endif
++
+ TXWindow::setGlobalEventHandler(this);
}
virtual ~XDesktop() {
stop();
}
#endif
+ #ifdef HAVE_XFIXES
+ if (haveXfixes) {
+ XFixesSelectCursorInput(dpy, DefaultRootWindow(dpy),
+ XFixesDisplayCursorNotifyMask);
+ }
+ #endif
+
+ server->setLEDState(ledState);
+
running = true;
}
server->add_changed(rect);
return true;
- }
#endif
-
+ #ifdef HAVE_XFIXES
- if (ev->type == xfixesEventBase + XFixesCursorNotify) {
++ } else if (ev->type == xfixesEventBase + XFixesCursorNotify) {
+ XFixesCursorNotifyEvent* cev;
+ XFixesCursorImage *cim;
+
+ if (!running)
+ return true;
+
+ cev = (XFixesCursorNotifyEvent*)ev;
+
+ if (cev->subtype != XFixesDisplayCursorNotify)
+ return false;
+
+ cim = XFixesGetCursorImage(dpy);
+ if (cim == NULL)
+ return false;
+
+ // Copied from XserverDesktop::setCursor() in
+ // unix/xserver/hw/vnc/XserverDesktop.cc and adapted to
+ // handle long -> U32 conversion for 64-bit Xlib
+ rdr::U8* cursorData;
+ rdr::U8 *out;
+ const unsigned long *pixels;
+
+ cursorData = new rdr::U8[cim->width * cim->height * 4];
+
+ // Un-premultiply alpha
+ pixels = cim->pixels;
+ out = cursorData;
+ for (int y = 0; y < cim->height; y++) {
+ for (int x = 0; x < cim->width; x++) {
+ rdr::U8 alpha;
+ rdr::U32 pixel = *pixels++;
+ rdr::U8 *in = (rdr::U8 *) &pixel;
+
+ alpha = in[3];
+ if (alpha == 0)
+ alpha = 1; // Avoid division by zero
+
+ *out++ = (unsigned)*in++ * 255/alpha;
+ *out++ = (unsigned)*in++ * 255/alpha;
+ *out++ = (unsigned)*in++ * 255/alpha;
+ *out++ = *in++;
+ }
+ }
+
+ try {
+ server->setCursor(cim->width, cim->height, Point(cim->xhot, cim->yhot),
+ cursorData);
+ } catch (rdr::Exception& e) {
+ vlog.error("XserverDesktop::setCursor: %s",e.str());
+ }
+
+ delete [] cursorData;
+ XFree(cim);
+ return true;
- }
+ #endif
+ }
return false;
}
int oldButtonMask;
bool haveXtest;
bool haveDamage;
+ bool haveXfixes;
int maxButtons;
+ std::map<KeySym, KeyCode> pressedKeys;
bool running;
#ifdef HAVE_XDAMAGE
Damage damage;
int xdamageEventBase;
#endif
+ int xkbEventBase;
+ #ifdef HAVE_XFIXES
+ int xfixesEventBase;
+ #endif
+ int ledMasks[N_LEDS];
+ unsigned ledState;
+ const unsigned short *codeMap;
+ unsigned codeMapLen;
};