From: Pierre Ossman Date: Fri, 15 Sep 2017 11:10:54 +0000 (+0200) Subject: Merge branch 'cursor' of https://github.com/alanc/tigervnc X-Git-Tag: v1.8.90~111 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=d092f05f0d1fe8d3955acfdf4d4babdb408d7be7;p=tigervnc.git Merge branch 'cursor' of https://github.com/alanc/tigervnc --- d092f05f0d1fe8d3955acfdf4d4babdb408d7be7 diff --cc unix/x0vncserver/x0vncserver.cxx index 025a0953,315d30c5..d3042db0 --- a/unix/x0vncserver/x0vncserver.cxx +++ b/unix/x0vncserver/x0vncserver.cxx @@@ -160,66 -144,8 +163,66 @@@ public 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; @@@ -250,7 -178,20 +253,20 @@@ } #endif + #ifdef HAVE_XFIXES + int xfixesErrorBase; + + if (XFixesQueryExtension(dpy, &xfixesEventBase, &xfixesErrorBase)) { - if (not haveDamage) - TXWindow::setGlobalEventHandler(this); + 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(); @@@ -289,8 -230,13 +305,15 @@@ } #endif + #ifdef HAVE_XFIXES + if (haveXfixes) { + XFixesSelectCursorInput(dpy, DefaultRootWindow(dpy), + XFixesDisplayCursorNotifyMask); + } + #endif + + server->setLEDState(ledState); + running = true; } @@@ -437,8 -310,67 +460,65 @@@ 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; } @@@ -451,18 -383,16 +531,22 @@@ protected int oldButtonMask; bool haveXtest; bool haveDamage; + bool haveXfixes; int maxButtons; + std::map 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; };