};
XDesktop::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)
+ : 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)
{
- int major, minor;
+ int major, minor;
- int xkbOpcode, xkbErrorBase;
+ int xkbOpcode, xkbErrorBase;
- major = XkbMajorVersion;
- minor = XkbMinorVersion;
- if (!XkbQueryExtension(dpy, &xkbOpcode, &xkbEventBase,
- &xkbErrorBase, &major, &minor)) {
- vlog.error("XKEYBOARD extension not present");
- throw Exception();
- }
+ 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);
+ XkbSelectEvents(dpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask,
+ XkbIndicatorStateNotifyMask);
- // figure out bit masks for the indicators we are interested in
- for (int i = 0; i < XDESKTOP_N_LEDS; i++) {
- Atom a;
- int shift;
- Bool on;
+ // figure out bit masks for the indicators we are interested in
+ for (int i = 0; i < XDESKTOP_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;
+ 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;
- }
+ 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);
+ // 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.debug("Unable to get keycode map\n");
+ vlog.info("Unknown keycode '%s', no codemap\n", keycodes);
}
-
- XkbFreeKeyboard(desc, XkbAllComponentsMask, True);
+ XFree(keycodes);
+ } else {
+ vlog.debug("Unable to get keycode map\n");
}
+ XkbFreeKeyboard(desc, XkbAllComponentsMask, True);
+ }
+
#ifdef HAVE_XTEST
- int xtestEventBase;
- int xtestErrorBase;
-
- if (XTestQueryExtension(dpy, &xtestEventBase,
- &xtestErrorBase, &major, &minor)) {
- XTestGrabControl(dpy, True);
- vlog.info("XTest extension present - version %d.%d",major,minor);
- haveXtest = true;
- } else {
+ int xtestEventBase;
+ int xtestErrorBase;
+
+ if (XTestQueryExtension(dpy, &xtestEventBase,
+ &xtestErrorBase, &major, &minor)) {
+ XTestGrabControl(dpy, True);
+ vlog.info("XTest extension present - version %d.%d",major,minor);
+ haveXtest = true;
+ } else {
#endif
- vlog.info("XTest extension not present");
- vlog.info("Unable to inject events or display while server is grabbed");
+ vlog.info("XTest extension not present");
+ vlog.info("Unable to inject events or display while server is grabbed");
#ifdef HAVE_XTEST
- }
+ }
#endif
#ifdef HAVE_XDAMAGE
- int xdamageErrorBase;
+ int xdamageErrorBase;
- if (XDamageQueryExtension(dpy, &xdamageEventBase, &xdamageErrorBase)) {
- haveDamage = true;
- } else {
+ if (XDamageQueryExtension(dpy, &xdamageEventBase, &xdamageErrorBase)) {
+ haveDamage = true;
+ } else {
#endif
- vlog.info("DAMAGE extension not present");
- vlog.info("Will have to poll screen for changes");
+ vlog.info("DAMAGE extension not present");
+ vlog.info("Will have to poll screen for changes");
#ifdef HAVE_XDAMAGE
- }
+ }
#endif
#ifdef HAVE_XFIXES
- int xfixesErrorBase;
+ int xfixesErrorBase;
- if (XFixesQueryExtension(dpy, &xfixesEventBase, &xfixesErrorBase)) {
- XFixesSelectCursorInput(dpy, DefaultRootWindow(dpy),
- XFixesDisplayCursorNotifyMask);
- } else {
+ if (XFixesQueryExtension(dpy, &xfixesEventBase, &xfixesErrorBase)) {
+ XFixesSelectCursorInput(dpy, DefaultRootWindow(dpy),
+ XFixesDisplayCursorNotifyMask);
+ } else {
#endif
- vlog.info("XFIXES extension not present");
- vlog.info("Will not be able to display cursors");
+ vlog.info("XFIXES extension not present");
+ vlog.info("Will not be able to display cursors");
#ifdef HAVE_XFIXES
- }
+ }
#endif
- TXWindow::setGlobalEventHandler(this);
+ TXWindow::setGlobalEventHandler(this);
}
XDesktop::~XDesktop() {
- if (running)
- stop();
+ if (running)
+ stop();
}
void XDesktop::poll() {
- if (pb and not haveDamage)
- pb->poll(server);
- if (running) {
- Window root, child;
- int x, y, wx, wy;
- unsigned int mask;
- XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
- &x, &y, &wx, &wy, &mask);
- server->setCursorPos(rfb::Point(x, y));
- }
+ if (pb and not haveDamage)
+ pb->poll(server);
+ if (running) {
+ Window root, child;
+ int x, y, wx, wy;
+ unsigned int mask;
+ XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
+ &x, &y, &wx, &wy, &mask);
+ server->setCursorPos(rfb::Point(x, y));
}
+}
void XDesktop::start(VNCServer* vs) {
- // Determine actual number of buttons of the X pointer device.
- unsigned char btnMap[8];
- int numButtons = XGetPointerMapping(dpy, btnMap, 8);
- maxButtons = (numButtons > 8) ? 8 : numButtons;
- vlog.info("Enabling %d button%s of X pointer device",
- maxButtons, (maxButtons != 1) ? "s" : "");
+ // Determine actual number of buttons of the X pointer device.
+ unsigned char btnMap[8];
+ int numButtons = XGetPointerMapping(dpy, btnMap, 8);
+ maxButtons = (numButtons > 8) ? 8 : numButtons;
+ vlog.info("Enabling %d button%s of X pointer device",
+ maxButtons, (maxButtons != 1) ? "s" : "");
- // Create an ImageFactory instance for producing Image objects.
- ImageFactory factory((bool)useShm);
+ // Create an ImageFactory instance for producing Image objects.
+ ImageFactory factory((bool)useShm);
- // Create pixel buffer and provide it to the server object.
- pb = new XPixelBuffer(dpy, factory, geometry->getRect());
- vlog.info("Allocated %s", pb->getImage()->classDesc());
+ // Create pixel buffer and provide it to the server object.
+ pb = new XPixelBuffer(dpy, factory, geometry->getRect());
+ vlog.info("Allocated %s", pb->getImage()->classDesc());
- server = (VNCServerST *)vs;
- server->setPixelBuffer(pb);
+ server = (VNCServerST *)vs;
+ server->setPixelBuffer(pb);
#ifdef HAVE_XDAMAGE
- if (haveDamage) {
- damage = XDamageCreate(dpy, DefaultRootWindow(dpy),
- XDamageReportRawRectangles);
- }
+ if (haveDamage) {
+ damage = XDamageCreate(dpy, DefaultRootWindow(dpy),
+ XDamageReportRawRectangles);
+ }
#endif
#ifdef HAVE_XFIXES
- setCursor();
+ setCursor();
#endif
- server->setLEDState(ledState);
+ server->setLEDState(ledState);
- running = true;
+ running = true;
}
void XDesktop::stop() {
- running = false;
+ running = false;
#ifdef HAVE_XDAMAGE
- if (haveDamage)
- XDamageDestroy(dpy, damage);
+ if (haveDamage)
+ XDamageDestroy(dpy, damage);
#endif
- server->setPixelBuffer(0);
- server = 0;
+ server->setPixelBuffer(0);
+ server = 0;
- delete pb;
- pb = 0;
+ delete pb;
+ pb = 0;
}
bool XDesktop::isRunning() {
- return running;
+ return running;
}
void XDesktop::pointerEvent(const Point& pos, int buttonMask) {
#ifdef HAVE_XTEST
- if (!haveXtest) return;
- XTestFakeMotionEvent(dpy, DefaultScreen(dpy),
- geometry->offsetLeft() + pos.x,
- geometry->offsetTop() + pos.y,
- CurrentTime);
- if (buttonMask != oldButtonMask) {
- for (int i = 0; i < maxButtons; i++) {
- if ((buttonMask ^ oldButtonMask) & (1<<i)) {
- if (buttonMask & (1<<i)) {
- XTestFakeButtonEvent(dpy, i+1, True, CurrentTime);
- } else {
- XTestFakeButtonEvent(dpy, i+1, False, CurrentTime);
- }
+ if (!haveXtest) return;
+ XTestFakeMotionEvent(dpy, DefaultScreen(dpy),
+ geometry->offsetLeft() + pos.x,
+ geometry->offsetTop() + pos.y,
+ CurrentTime);
+ if (buttonMask != oldButtonMask) {
+ for (int i = 0; i < maxButtons; i++) {
+ if ((buttonMask ^ oldButtonMask) & (1<<i)) {
+ if (buttonMask & (1<<i)) {
+ XTestFakeButtonEvent(dpy, i+1, True, CurrentTime);
+ } else {
+ XTestFakeButtonEvent(dpy, i+1, False, CurrentTime);
}
}
}
- oldButtonMask = buttonMask;
+ }
+ oldButtonMask = buttonMask;
#endif
}
#ifdef HAVE_XTEST
KeyCode XDesktop::XkbKeysymToKeycode(Display* dpy, KeySym keysym) {
- XkbDescPtr xkb;
- XkbStateRec state;
- unsigned keycode;
-
- xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
- if (!xkb)
- return 0;
-
- XkbGetState(dpy, XkbUseCoreKbd, &state);
-
- for (keycode = xkb->min_key_code;
- keycode <= xkb->max_key_code;
- keycode++) {
- KeySym cursym;
- unsigned int mods, out_mods;
- // XkbStateFieldFromRec() doesn't work properly because
- // state.lookup_mods isn't properly updated, so we do this manually
- mods = XkbBuildCoreState(XkbStateMods(&state), state.group);
- XkbTranslateKeyCode(xkb, keycode, mods, &out_mods, &cursym);
- if (cursym == keysym)
- break;
- }
+ XkbDescPtr xkb;
+ XkbStateRec state;
+ unsigned keycode;
+
+ xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
+ if (!xkb)
+ return 0;
+
+ XkbGetState(dpy, XkbUseCoreKbd, &state);
+
+ for (keycode = xkb->min_key_code;
+ keycode <= xkb->max_key_code;
+ keycode++) {
+ KeySym cursym;
+ unsigned int mods, out_mods;
+ // XkbStateFieldFromRec() doesn't work properly because
+ // state.lookup_mods isn't properly updated, so we do this manually
+ mods = XkbBuildCoreState(XkbStateMods(&state), state.group);
+ XkbTranslateKeyCode(xkb, keycode, mods, &out_mods, &cursym);
+ if (cursym == keysym)
+ break;
+ }
- if (keycode > xkb->max_key_code)
- keycode = 0;
+ if (keycode > xkb->max_key_code)
+ keycode = 0;
- XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);
+ XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);
- return keycode;
+ return keycode;
}
#endif
void XDesktop::keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) {
#ifdef HAVE_XTEST
- int keycode = 0;
-
- if (!haveXtest)
- return;
-
- // Use scan code if provided and mapping exists
- if (codeMap && rawKeyboard && xtcode < codeMapLen)
- keycode = codeMap[xtcode];
-
- if (!keycode) {
- if (pressedKeys.find(keysym) != pressedKeys.end())
- keycode = pressedKeys[keysym];
- else {
- // XKeysymToKeycode() doesn't respect state, so we have to use
- // something slightly more complex
- keycode = XkbKeysymToKeycode(dpy, keysym);
- }
+ int keycode = 0;
+
+ if (!haveXtest)
+ return;
+
+ // Use scan code if provided and mapping exists
+ if (codeMap && rawKeyboard && xtcode < codeMapLen)
+ keycode = codeMap[xtcode];
+
+ if (!keycode) {
+ if (pressedKeys.find(keysym) != pressedKeys.end())
+ keycode = pressedKeys[keysym];
+ else {
+ // XKeysymToKeycode() doesn't respect state, so we have to use
+ // something slightly more complex
+ keycode = XkbKeysymToKeycode(dpy, keysym);
}
+ }
- if (!keycode)
- return;
+ if (!keycode)
+ return;
- if (down)
- pressedKeys[keysym] = keycode;
- else
- pressedKeys.erase(keysym);
+ if (down)
+ pressedKeys[keysym] = keycode;
+ else
+ pressedKeys.erase(keysym);
- XTestFakeKeyEvent(dpy, keycode, down, CurrentTime);
+ XTestFakeKeyEvent(dpy, keycode, down, CurrentTime);
#endif
}
bool XDesktop::handleGlobalEvent(XEvent* ev) {
- if (ev->type == xkbEventBase + XkbEventCode) {
- XkbEvent *kb = (XkbEvent *)ev;
+ if (ev->type == xkbEventBase + XkbEventCode) {
+ XkbEvent *kb = (XkbEvent *)ev;
- if (kb->any.xkb_type != XkbIndicatorStateNotify)
- return false;
+ if (kb->any.xkb_type != XkbIndicatorStateNotify)
+ return false;
- vlog.debug("Got indicator update, mask is now 0x%x", kb->indicators.state);
+ vlog.debug("Got indicator update, mask is now 0x%x", kb->indicators.state);
- ledState = 0;
- for (int i = 0; i < XDESKTOP_N_LEDS; i++) {
- if (kb->indicators.state & ledMasks[i])
- ledState |= 1u << i;
- }
+ ledState = 0;
+ for (int i = 0; i < XDESKTOP_N_LEDS; i++) {
+ if (kb->indicators.state & ledMasks[i])
+ ledState |= 1u << i;
+ }
- if (running)
- server->setLEDState(ledState);
+ if (running)
+ server->setLEDState(ledState);
- return true;
+ return true;
#ifdef HAVE_XDAMAGE
- } else if (ev->type == xdamageEventBase) {
- XDamageNotifyEvent* dev;
- Rect rect;
+ } else if (ev->type == xdamageEventBase) {
+ XDamageNotifyEvent* dev;
+ Rect rect;
- if (!running)
- return true;
+ if (!running)
+ return true;
- dev = (XDamageNotifyEvent*)ev;
- rect.setXYWH(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
- server->add_changed(rect);
+ dev = (XDamageNotifyEvent*)ev;
+ rect.setXYWH(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
+ server->add_changed(rect);
- return true;
+ return true;
#endif
#ifdef HAVE_XFIXES
- } else if (ev->type == xfixesEventBase + XFixesCursorNotify) {
- XFixesCursorNotifyEvent* cev;
+ } else if (ev->type == xfixesEventBase + XFixesCursorNotify) {
+ XFixesCursorNotifyEvent* cev;
- if (!running)
- return true;
+ if (!running)
+ return true;
- cev = (XFixesCursorNotifyEvent*)ev;
+ cev = (XFixesCursorNotifyEvent*)ev;
- if (cev->subtype != XFixesDisplayCursorNotify)
- return false;
+ if (cev->subtype != XFixesDisplayCursorNotify)
+ return false;
- return setCursor();
+ return setCursor();
#endif
- }
+ }
- return false;
+ return false;
}
bool XDesktop::setCursor()
{
- XFixesCursorImage *cim;
-
- 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++;
- }
- }
+ XFixesCursorImage *cim;
- try {
- server->setCursor(cim->width, cim->height, Point(cim->xhot, cim->yhot),
- cursorData);
- } catch (rdr::Exception& e) {
- vlog.error("XserverDesktop::setCursor: %s",e.str());
- }
+ cim = XFixesGetCursorImage(dpy);
+ if (cim == NULL)
+ return false;
- delete [] cursorData;
- XFree(cim);
- return true;
+ // 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;
}