From 8b1cd8f95f46065eca122838bfe7e75d98e60953 Mon Sep 17 00:00:00 2001 From: CentOS Buildsys Date: Mar 10 2014 16:16:04 +0000 Subject: import tigervnc-1.2.80-0.30.20130314svn5065.el7.src.rpm --- diff --git a/SOURCES/tigervnc-CVE-2014-0011.patch b/SOURCES/tigervnc-CVE-2014-0011.patch new file mode 100644 index 0000000..0075720 --- /dev/null +++ b/SOURCES/tigervnc-CVE-2014-0011.patch @@ -0,0 +1,49 @@ +diff -up tigervnc-1.3.0/common/CMakeLists.txt.CVE-2014-0011 tigervnc-1.3.0/common/CMakeLists.txt +--- tigervnc-1.3.0/common/CMakeLists.txt.CVE-2014-0011 2013-07-01 13:42:01.000000000 +0100 ++++ tigervnc-1.3.0/common/CMakeLists.txt 2014-02-04 16:59:10.840037314 +0000 +@@ -23,3 +23,6 @@ if(CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_S + set_target_properties(zlib PROPERTIES COMPILE_FLAGS -fPIC) + endif() + endif() ++ ++# Turn asserts on. ++set_target_properties(rdr rfb PROPERTIES COMPILE_FLAGS -UNDEBUG) +diff -up tigervnc-1.3.0/common/rfb/zrleDecode.h.CVE-2014-0011 tigervnc-1.3.0/common/rfb/zrleDecode.h +--- tigervnc-1.3.0/common/rfb/zrleDecode.h.CVE-2014-0011 2013-07-01 13:41:59.000000000 +0100 ++++ tigervnc-1.3.0/common/rfb/zrleDecode.h 2014-02-04 16:17:00.881565540 +0000 +@@ -25,9 +25,10 @@ + // FILL_RECT - fill a rectangle with a single colour + // IMAGE_RECT - draw a rectangle of pixel data from a buffer + ++#include + #include + #include +-#include ++#include + + namespace rfb { + +@@ -143,7 +144,10 @@ void ZRLE_DECODE (const Rect& r, rdr::In + len += b; + } while (b == 255); + +- assert(len <= end - ptr); ++ if (end - ptr < len) { ++ fprintf (stderr, "ZRLE decode error\n"); ++ throw Exception ("ZRLE decode error"); ++ } + + #ifdef FAVOUR_FILL_RECT + int i = ptr - buf; +@@ -193,7 +197,10 @@ void ZRLE_DECODE (const Rect& r, rdr::In + len += b; + } while (b == 255); + +- assert(len <= end - ptr); ++ if (end - ptr < len) { ++ fprintf (stderr, "ZRLE decode error\n"); ++ throw Exception ("ZRLE decode error"); ++ } + } + + index &= 127; diff --git a/SOURCES/tigervnc-cursor.patch b/SOURCES/tigervnc-cursor.patch new file mode 100644 index 0000000..349c950 --- /dev/null +++ b/SOURCES/tigervnc-cursor.patch @@ -0,0 +1,12 @@ +diff -up tigervnc-1.3.0/vncviewer/Viewport.cxx.cursor tigervnc-1.3.0/vncviewer/Viewport.cxx +--- tigervnc-1.3.0/vncviewer/Viewport.cxx.cursor 2013-12-17 13:28:23.170400013 +0000 ++++ tigervnc-1.3.0/vncviewer/Viewport.cxx 2013-12-17 13:29:46.095784064 +0000 +@@ -931,7 +931,7 @@ void Viewport::popupContextMenu() + + // Back to our proper mouse pointer. + #ifdef HAVE_FLTK_CURSOR +- if (Fl::belowmouse() == this) ++ if (Fl::belowmouse() == this && cursor) + window()->cursor(cursor, cursorHotspot.x, cursorHotspot.y); + #endif + diff --git a/SOURCES/tigervnc-input.patch b/SOURCES/tigervnc-input.patch new file mode 100644 index 0000000..e1e7b0b --- /dev/null +++ b/SOURCES/tigervnc-input.patch @@ -0,0 +1,2569 @@ +diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.cc.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.cc +--- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.cc.input 2012-08-29 09:56:37.000000000 +0100 ++++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.cc 2014-01-17 16:01:13.140109450 +0000 +@@ -1,5 +1,6 @@ + /* Copyright (C) 2009 TightVNC Team + * Copyright (C) 2009 Red Hat, Inc. ++ * Copyright 2013 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -34,16 +35,6 @@ extern "C" { + #include "inpututils.h" + #endif + #include "mi.h" +-#ifndef XKB_IN_SERVER +-#define XKB_IN_SERVER +-#endif +-#ifdef XKB +-/* +- * This include is needed to use XkbConvertCase instead of XConvertCase even if +- * we don't use XKB extension. +- */ +-#include +-#endif + #if XORG >= 16 + #include "exevents.h" + #endif +@@ -58,6 +49,7 @@ CopyKeyClass(DeviceIntPtr device, Device + extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey; + #endif + #include ++#include + #include + #undef public + #undef class +@@ -72,12 +64,9 @@ using namespace rfb; + + static LogWriter vlog("Input"); + +-#define BUTTONS 7 +-static int pointerProc(DeviceIntPtr pDevice, int onoff); ++rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock", "Avoid fake Shift presses for keys affected by NumLock.", true); + +-static int keyboardProc(DeviceIntPtr pDevice, int onoff); +-static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col); +-static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col); ++#define BUTTONS 7 + + /* Event queue is shared between all devices. */ + #if XORG == 15 +@@ -128,26 +117,16 @@ static void enqueueEvents(DeviceIntPtr d + #endif /* XORG < 111 */ + + InputDevice::InputDevice(rfb::VNCServerST *_server) +- : server(_server), oldButtonMask(0) ++ : server(_server), initialized(false), oldButtonMask(0) + { +-#if XORG < 17 +- pointerDev = AddInputDevice( +-#if XORG >= 16 +- serverClient, +-#endif +- pointerProc, TRUE); +- RegisterPointerDevice(pointerDev); ++ int i; + +- keyboardDev = AddInputDevice( +-#if XORG >= 16 +- serverClient, +-#endif +- keyboardProc, TRUE); +- RegisterKeyboardDevice(keyboardDev); +-#endif + #if XORG < 111 + initEventq(); + #endif ++ ++ for (i = 0;i < 256;i++) ++ pressedKeys[i] = NoSymbol; + } + + void InputDevice::PointerButtonAction(int buttonMask) +@@ -160,8 +139,6 @@ void InputDevice::PointerButtonAction(in + ValuatorMask mask; + #endif + +- initInputDevice(); +- + for (i = 0; i < BUTTONS; i++) { + if ((buttonMask ^ oldButtonMask) & (1 << i)) { + int action = (buttonMask & (1< 0) ++ vncBell(); ++} ++ ++extern void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap); ++ ++static int keyboardProc(DeviceIntPtr pDevice, int onoff) ++{ ++#if XORG < 17 ++ KeySymsRec keySyms; ++ CARD8 modMap[MAP_LENGTH]; ++#endif ++ DevicePtr pDev = (DevicePtr)pDevice; ++ ++ switch (onoff) { ++ case DEVICE_INIT: ++#if XORG < 17 ++ GetInitKeyboardMap(&keySyms, modMap); ++#endif ++ InitKeyboardDeviceStruct( + #if XORG >= 17 +- int ret; +- static int initialized = 0; ++ pDevice, NULL, ++#else ++ pDev, &keySyms, modMap, ++#endif ++ keyboardBell, (KbdCtrlProcPtr)NoopDDA); ++ break; ++ case DEVICE_ON: ++ pDev->on = TRUE; ++ break; ++ case DEVICE_OFF: ++ pDev->on = FALSE; ++ break; ++ } + +- if (initialized != 0) ++ return Success; ++} ++ ++void InputDevice::InitInputDevice(void) ++{ ++ if (initialized) + return; + +- initialized = 1; ++ initialized = true; ++ ++#if XORG < 17 ++ pointerDev = AddInputDevice( ++#if XORG >= 16 ++ serverClient, ++#endif ++ pointerProc, TRUE); ++ RegisterPointerDevice(pointerDev); ++ ++ keyboardDev = AddInputDevice( ++#if XORG >= 16 ++ serverClient, ++#endif ++ keyboardProc, TRUE); ++ RegisterKeyboardDevice(keyboardDev); ++ ++ if (ActivateDevice(pointerDev) != Success || ++ ActivateDevice(keyboardDev) != Success) ++ FatalError("Failed to activate TigerVNC devices\n"); ++ ++ if (!EnableDevice(pointerDev) || ++ !EnableDevice(keyboardDev)) ++ FatalError("Failed to enable TigerVNC devices\n"); ++#else /* < 17 */ ++ int ret; + + ret = AllocDevicePair(serverClient, "TigerVNC", &pointerDev, + &keyboardDev, pointerProc, keyboardProc, +@@ -312,7 +349,9 @@ void InputDevice::initInputDevice(void) + if (!EnableDevice(pointerDev, TRUE) || + !EnableDevice(keyboardDev, TRUE)) + FatalError("Failed to activate TigerVNC devices\n"); +-#endif ++#endif /* 17 */ ++ ++ PrepareInputDevices(); + } + + static inline void pressKey(DeviceIntPtr dev, int kc, bool down, const char *msg) +@@ -334,143 +373,6 @@ static inline void pressKey(DeviceIntPtr + #endif + } + +-#define IS_PRESSED(keyc, keycode) \ +- ((keyc)->down[(keycode) >> 3] & (1 << ((keycode) & 7))) +- +-/* +- * ModifierState is a class which helps simplify generating a "fake" press or +- * release of shift, ctrl, alt, etc. An instance of the class is created for +- * every modifier which may need to be pressed or released. Then either +- * press() or release() may be called to make sure that the corresponding keys +- * are in the right state. The destructor of the class automatically reverts +- * to the previous state. Each modifier may have multiple keys associated with +- * it, so in the case of a fake release, this may involve releasing more than +- * one key. +- */ +- +-class ModifierState { +-public: +- ModifierState(DeviceIntPtr _dev, int _modIndex) +- : modIndex(_modIndex), nKeys(0), keys(0), pressed(false), +- dev(_dev) {} +- +- ~ModifierState() +- { +- for (int i = 0; i < nKeys; i++) +- pressKey(dev, keys[i], !pressed, "fake keycode"); +- delete [] keys; +- } +- +- void press() +- { +- int state, maxKeysPerMod, keycode; +-#if XORG >= 17 +- KeyCode *modmap = NULL; +-#if XORG >= 111 +- state = XkbStateFieldFromRec(&dev->master->key->xkbInfo->state); +-#else /* XORG >= 111 */ +- state = XkbStateFieldFromRec(&dev->u.master->key->xkbInfo->state); +-#endif /* XORG >= 111 */ +-#else +- KeyClassPtr keyc = dev->key; +- state = keyc->state; +-#endif +- if ((state & (1 << modIndex)) != 0) +- return; +- +-#if XORG >= 17 +- if (generate_modkeymap(serverClient, dev, &modmap, +- &maxKeysPerMod) != Success) { +- vlog.error("generate_modkeymap failed"); +- return; +- } +- +- if (maxKeysPerMod == 0) { +- vlog.debug("Keyboard has no modifiers"); +- xfree(modmap); +- return; +- } +- +- keycode = modmap[modIndex * maxKeysPerMod]; +- xfree(modmap); +-#else +- maxKeysPerMod = keyc->maxKeysPerModifier; +- keycode = keyc->modifierKeyMap[modIndex * maxKeysPerMod]; +-#endif +- tempKeyEvent(keycode, true, maxKeysPerMod); +- pressed = true; +- } +- +- void release() +- { +- int state, maxKeysPerMod; +- KeyClassPtr keyc; +-#if XORG >= 17 +- KeyCode *modmap = NULL; +- +-#if XORG >= 111 +- keyc = dev->master->key; +-#else /* XORG >= 111 */ +- keyc = dev->u.master->key; +-#endif /* XORG >= 111 */ +- state = XkbStateFieldFromRec(&keyc->xkbInfo->state); +-#else +- keyc = dev->key; +- state = keyc->state; +-#endif +- if ((state & (1 << modIndex)) == 0) +- return; +- +-#if XORG >= 17 +- if (generate_modkeymap(serverClient, dev, &modmap, +- &maxKeysPerMod) != Success) { +- vlog.error("generate_modkeymap failed"); +- return; +- } +- +- if (maxKeysPerMod == 0) { +- vlog.debug("Keyboard has no modifiers"); +- xfree(modmap); +- return; +- } +-#else +- maxKeysPerMod = keyc->maxKeysPerModifier; +-#endif +- +- for (int k = 0; k < maxKeysPerMod; k++) { +- int keycode; +- int index = modIndex * maxKeysPerMod + k; +-#if XORG >= 17 +- keycode = modmap[index]; +-#else +- keycode = keyc->modifierKeyMap[index]; +-#endif +- if (keycode && IS_PRESSED(keyc, keycode)) +- tempKeyEvent(keycode, false, maxKeysPerMod); +- } +-#if XORG >= 17 +- xfree(modmap); +-#endif +- } +- +-private: +- void tempKeyEvent(int keycode, bool down, int maxKeysPerMod) +- { +- if (keycode) { +- if (!keys) keys = new int[maxKeysPerMod]; +- keys[nKeys++] = keycode; +- pressKey(dev, keycode, down, "fake keycode"); +- } +- } +- +- int modIndex; +- int nKeys; +- int *keys; +- bool pressed; +- DeviceIntPtr dev; +-}; +- +- + /* altKeysym is a table of alternative keysyms which have the same meaning. */ + + static struct altKeysym_t { +@@ -517,102 +419,48 @@ static struct altKeysym_t { + { XK_KP_7, XK_7 }, + { XK_KP_8, XK_8 }, + { XK_KP_9, XK_9 }, ++ { XK_ISO_Level3_Shift, XK_Mode_switch }, + }; + + /* + * keyEvent() - work out the best keycode corresponding to the keysym sent by +- * the viewer. This is non-trivial because we can't assume much about the +- * local keyboard layout. We must also find out which column of the keyboard +- * mapping the keysym is in, and alter the shift state appropriately. Column 0 +- * means both shift and "mode_switch" (AltGr) must be released, column 1 means +- * shift must be pressed and mode_switch released, column 2 means shift must be +- * released and mode_switch pressed, and column 3 means both shift and +- * mode_switch must be pressed. +- * +- * Magic, which dynamically adds keysym<->keycode mapping depends on X.Org +- * version. Quick explanation of that "magic": +- * +- * 1.5 +- * - has only one core keyboard so we have to keep core keyboard mapping +- * synchronized with vncKeyboardDevice. Do it via SwitchCoreKeyboard() +- * +- * 1.6 (aka MPX - Multi pointer X) +- * - multiple master devices (= core devices) exists, keep vncKeyboardDevice +- * synchronized with proper master device +- */ +- +-#if XORG >= 17 +-#define FREE_MAPS \ +- do { \ +- xfree(modmap); \ +- xfree(keymap->map); \ +- xfree(keymap); \ +- } while (0); +-#else +-#define FREE_MAPS +-#endif +- +-#if XORG >= 17 +-/* +- * Modifier keysyms must be handled differently. Instead of finding +- * the right row and collumn in the keymap, directly press/release +- * the keycode which is mapped as modifier with the same keysym. +- * +- * This will avoid issues when there are multiple modifier keysyms +- * in the keymap but only some of them are mapped as modifiers in +- * the modmap. +- * +- * Returns keycode of the modifier key. ++ * the viewer. This is basically impossible in the general case, but we make ++ * a best effort by assuming that all useful keysyms can be reached using ++ * just the Shift and Level 3 (AltGr) modifiers. For core keyboards this is ++ * basically always true, and should be true for most sane, western XKB ++ * layouts. + */ +- +-static inline int isModifier(KeySymsPtr keymap, KeyCode *modmap, +- int maxKeysPerMod, rdr::U32 keysym) ++void InputDevice::keyEvent(rdr::U32 keysym, bool down) + { +- KeySym *map = keymap->map; +- KeyCode minKeyCode = keymap->minKeyCode; +- int mapWidth = keymap->mapWidth; +- int i, j, k; +- +- /* Find modifier index in the modmap */ +- for (i = 0; i < 8; i++) { +- for (k = 0; k < maxKeysPerMod; k++) { +- int index = i * maxKeysPerMod + k; +- int keycode = modmap[index]; ++ int i; ++ unsigned state, new_state; ++ KeyCode keycode; + +- if (keycode == 0) +- continue; ++ unsigned level_three_mask; ++ KeyCode shift_press, level_three_press; ++ std::list shift_release, level_three_release; + +- for (j = 0; j < mapWidth; j++) { +- if (map[(keycode - minKeyCode) * mapWidth + j] +- == keysym) { +- return keycode; +- } ++ /* ++ * Release events must match the press event, so look up what ++ * keycode we sent for the press. ++ */ ++ if (!down) { ++ for (i = 0;i < 256;i++) { ++ if (pressedKeys[i] == keysym) { ++ pressedKeys[i] = NoSymbol; ++ pressKey(keyboardDev, i, false, "keycode"); ++ mieqProcessInputEvents(); ++ return; + } + } +- } +- +- return -1; /* Not a modifier */ +-} +-#endif + +-void InputDevice::keyEvent(rdr::U32 keysym, bool down) +-{ +-#if XORG < 17 +- DeviceIntPtr master; +-#endif +- KeyClassPtr keyc; +- KeySymsPtr keymap = NULL; +- KeySym *map = NULL; +- KeyCode minKeyCode, maxKeyCode; +- KeyCode *modmap = NULL; +- int mapWidth; +- unsigned int i; +- int j, k, state, maxKeysPerMod; +-#if XORG >= 17 +- KeybdCtrl ctrl; +-#endif +- +- initInputDevice(); ++ /* ++ * This can happen quite often as we ignore some ++ * key presses. ++ */ ++ vlog.debug("Unexpected release of keysym 0x%x", keysym); ++ return; ++ } + + /* + * Since we are checking the current state to determine if we need +@@ -622,543 +470,214 @@ void InputDevice::keyEvent(rdr::U32 keys + */ + mieqProcessInputEvents(); + +- if (keysym == XK_Caps_Lock) { +- vlog.debug("Ignoring caps lock"); +- return; +- } ++ state = getKeyboardState(); + +-#if XORG >= 17 +-#if XORG >= 111 +- keyc = keyboardDev->master->key; +-#else /* XORG >= 111 */ +- keyc = keyboardDev->u.master->key; +-#endif /* XORG >= 111 */ +- +- keymap = XkbGetCoreMap(keyboardDev); +- if (!keymap) { +- vlog.error("VNC keyboard device has no map"); +- return; +- } ++ keycode = keysymToKeycode(keysym, state, &new_state); + +- if (generate_modkeymap(serverClient, keyboardDev, &modmap, +- &maxKeysPerMod) != Success) { +- vlog.error("generate_modkeymap failed"); +- xfree(keymap->map); +- xfree(keymap); +- return; +- } +- +- if (maxKeysPerMod == 0) +- vlog.debug("Keyboard has no modifiers"); +- +- state = XkbStateFieldFromRec(&keyc->xkbInfo->state); +-#else +- keyc = keyboardDev->key; +- state = keyc->state; +- maxKeysPerMod = keyc->maxKeysPerModifier; +- keymap = &keyc->curKeySyms; +- modmap = keyc->modifierKeyMap; +-#endif +- map = keymap->map; +- minKeyCode = keymap->minKeyCode; +- maxKeyCode = keymap->maxKeyCode; +- mapWidth = keymap->mapWidth; +- +-#if XORG >= 17 +- /* +- * No server-side key repeating, please. Some clients won't work well, +- * check https://bugzilla.redhat.com/show_bug.cgi?id=607866. +- */ +- ctrl = keyboardDev->kbdfeed->ctrl; +- if (ctrl.autoRepeat != FALSE) { +- ctrl.autoRepeat = FALSE; +- XkbSetRepeatKeys(keyboardDev, -1, ctrl.autoRepeat); +- } +-#endif +- +- /* find which modifier Mode_switch is on. */ +- int modeSwitchMapIndex = 0; +- for (i = 3; i < 8; i++) { +- for (k = 0; k < maxKeysPerMod; k++) { +- int index = i * maxKeysPerMod + k; +- int keycode = modmap[index]; +- +- if (keycode == 0) ++ /* Try some equivalent keysyms if we couldn't find a perfect match */ ++ if (keycode == 0) { ++ for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) { ++ KeySym altsym; ++ ++ if (altKeysym[i].a == keysym) ++ altsym = altKeysym[i].b; ++ else if (altKeysym[i].b == keysym) ++ altsym = altKeysym[i].a; ++ else + continue; + +- for (j = 0; j < mapWidth; j++) { +- if (map[(keycode - minKeyCode) * mapWidth + j] +- == XK_Mode_switch) { +- modeSwitchMapIndex = i; +- goto ModeSwitchFound; +- } +- } ++ keycode = keysymToKeycode(altsym, state, &new_state); ++ if (keycode != 0) ++ break; + } + } +-ModeSwitchFound: + +- int kc; +- int col = 0; ++ /* We don't have lock synchronisation... */ ++ if (isLockModifier(keycode, new_state)) { ++ vlog.debug("Ignoring lock key (e.g. caps lock)"); ++ return; ++ } + +-#if XORG >= 17 +- if ((kc = isModifier(keymap, modmap, maxKeysPerMod, keysym)) != -1) { +- /* +- * It is a modifier key event. +- * +- * Don't do any auto-repeat because the X server will translate +- * each press into a release followed by a press. +- */ +- if (IS_PRESSED(keyc, kc) && down) { +- FREE_MAPS; ++ /* No matches. Will have to add a new entry... */ ++ if (keycode == 0) { ++ keycode = addKeysym(keysym, state); ++ if (keycode == 0) { ++ vlog.error("Failure adding new keysym 0x%x", keysym); + return; + } + +- goto press; +- } +-#endif +- +- if (maxKeysPerMod != 0) { +- if ((state & (1 << ShiftMapIndex)) != 0) +- col |= 1; +- if (modeSwitchMapIndex != 0 && +- ((state & (1 << modeSwitchMapIndex))) != 0) +- col |= 2; +- } +- +- kc = KeysymToKeycode(keymap, keysym, &col); ++ vlog.info("Added unknown keysym 0x%x to keycode %d", ++ keysym, keycode); + +- /* +- * Sort out the "shifted Tab" mess. If we are sent a shifted Tab, +- * generate a local shifted Tab regardless of what the "shifted Tab" +- * keysym is on the local keyboard (it might be Tab, ISO_Left_Tab or +- * HP's private BackTab keysym, and quite possibly some others too). +- * We never get ISO_Left_Tab here because it's already been translated +- * in VNCSConnectionST. +- */ +- if (maxKeysPerMod != 0 && keysym == XK_Tab && +- ((state & (1 << ShiftMapIndex))) != 0) +- col |= 1; +- +- if (kc == 0) { + /* +- * Not a direct match in the local keyboard mapping. Check for +- * alternative keysyms with the same meaning. ++ * The state given to addKeysym() is just a hint and ++ * the actual result might still require some state ++ * changes. + */ +- for (i = 0; i < sizeof(altKeysym) / sizeof(altKeysym_t); i++) { +- if (keysym == altKeysym[i].a) +- kc = KeysymToKeycode(keymap, altKeysym[i].b, +- &col); +- else if (keysym == altKeysym[i].b) +- kc = KeysymToKeycode(keymap, altKeysym[i].a, +- &col); +- if (kc) +- break; ++ keycode = keysymToKeycode(keysym, state, &new_state); ++ if (keycode == 0) { ++ vlog.error("Newly added keysym 0x%x cannot be generated", keysym); ++ return; + } + } + +- if (kc == 0) { +- /* Dynamically add a new key to the keyboard mapping. */ +- for (kc = maxKeyCode; kc >= minKeyCode; kc--) { +- if (map[(kc - minKeyCode) * mapWidth] != 0) ++ /* ++ * X11 generally lets shift toggle the keys on the numeric pad ++ * the same way NumLock does. This is however not the case on ++ * other systems like Windows. As a result, some applications ++ * get confused when we do a fake shift to get the same effect ++ * that having NumLock active would produce. ++ * ++ * Until we have proper NumLock synchronisation (so we can ++ * avoid faking shift), we try to avoid the fake shifts if we ++ * can use an alternative keysym. ++ */ ++ if (((state & ShiftMask) != (new_state & ShiftMask)) && ++ avoidShiftNumLock && isAffectedByNumLock(keycode)) { ++ KeyCode keycode2; ++ unsigned new_state2; ++ ++ vlog.debug("Finding alternative to keysym 0x%x to avoid fake shift for numpad", keysym); ++ ++ for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) { ++ KeySym altsym; ++ ++ if (altKeysym[i].a == keysym) ++ altsym = altKeysym[i].b; ++ else if (altKeysym[i].b == keysym) ++ altsym = altKeysym[i].a; ++ else + continue; + +- map[(kc - minKeyCode) * mapWidth] = keysym; +- col = 0; ++ keycode2 = keysymToKeycode(altsym, state, &new_state2); ++ if (keycode2 == 0) ++ continue; + +- vlog.info("Added unknown keysym 0x%x to keycode %d", +- keysym, kc); ++ if (((state & ShiftMask) != (new_state2 & ShiftMask)) && ++ isAffectedByNumLock(keycode2)) ++ continue; + +-#if XORG < 17 +-#if XORG == 15 +- master = inputInfo.keyboard; +-#else +- master = keyboardDev->u.master; +-#endif +- void *slave = dixLookupPrivate(&master->devPrivates, +- CoreDevicePrivateKey); +- if (keyboardDev == slave) { +- dixSetPrivate(&master->devPrivates, +- CoreDevicePrivateKey, NULL); +-#if XORG == 15 +- SwitchCoreKeyboard(keyboardDev); +-#else +- CopyKeyClass(keyboardDev, master); +-#endif +- } +-#else /* XORG < 17 */ +- XkbApplyMappingChange(keyboardDev, keymap, minKeyCode, +- maxKeyCode - minKeyCode + 1, +- NULL, serverClient); +-#if XORG >= 111 +- XkbCopyDeviceKeymap(keyboardDev->master, keyboardDev); +-#else +- XkbCopyDeviceKeymap(keyboardDev->u.master, keyboardDev); +-#endif +-#endif /* XORG < 17 */ + break; + } +- } + +- if (kc < minKeyCode) { +- vlog.info("Keyboard mapping full - ignoring unknown keysym " +- "0x%x",keysym); +- FREE_MAPS; +- return; +- } +- +-#if XORG < 17 +- /* +- * See if it's a modifier key. If so, then don't do any auto-repeat, +- * because the X server will translate each press into a release +- * followed by a press. +- */ +- for (i = 0; i < 8; i++) { +- for (k = 0; k < maxKeysPerMod; k++) { +- int index = i * maxKeysPerMod + k; +- if (kc == modmap[index] && IS_PRESSED(keyc,kc) && down) { +- FREE_MAPS; +- return; +- } ++ if (i == sizeof(altKeysym)/sizeof(altKeysym[0])) ++ vlog.debug("No alternative keysym found"); ++ else { ++ keycode = keycode2; ++ new_state = new_state2; + } + } +-#else ++ + /* +- * If you would like to press a key which is already pressed then +- * viewer didn't send the "release" event. In this case release it +- * before the press. ++ * "Shifted Tab" is a bit of a mess. Some systems have varying, ++ * special keysyms for this symbol. VNC mandates that clients ++ * should always send the plain XK_Tab keysym and the server ++ * should deduce the meaning based on current Shift state. ++ * To comply with this, we will find the keycode that sends ++ * XK_Tab, and make sure that Shift isn't cleared. This can ++ * possibly result in a different keysym than XK_Tab, but that ++ * is the desired behaviour. ++ * ++ * Note: We never get ISO_Left_Tab here because it's already ++ * been translated in VNCSConnectionST. + */ +- if (IS_PRESSED(keyc, kc) && down) { +- vlog.debug("KeyRelease for %d wasn't sent, releasing", kc); +- pressKey(keyboardDev, kc, false, "fixing keycode"); +- } +-#endif ++ if (keysym == XK_Tab && (state & ShiftMask)) ++ new_state |= ShiftMask; + +- if (maxKeysPerMod != 0) { +- ModifierState shift(keyboardDev, ShiftMapIndex); +- ModifierState modeSwitch(keyboardDev, modeSwitchMapIndex); +- if (down) { +- if (col & 1) +- shift.press(); +- else +- shift.release(); +- if (modeSwitchMapIndex) { +- if (col & 2) +- modeSwitch.press(); +- else +- modeSwitch.release(); +- } +- } +- /* +- * Ensure ModifierState objects are not destroyed before +- * pressKey call, otherwise fake modifier keypress can be lost. +- */ +- pressKey(keyboardDev, kc, down, "keycode"); +- } else { +-press: +- pressKey(keyboardDev, kc, down, "keycode"); +- } +- +- +- FREE_MAPS; +- + /* +- * When faking a modifier we are putting a keycode (which can +- * currently activate the desired modifier) on the input +- * queue. A future modmap change can change the mapping so +- * that this keycode means something else entirely. Guard +- * against this by processing the queue now. ++ * We need a bigger state change than just shift, ++ * so we need to know what the mask is for level 3 shifts. + */ +- mieqProcessInputEvents(); +-} +- +-static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col) +-{ +- int per = keymap->mapWidth; +- KeySym *syms; +- KeySym lsym, usym; +- +- if ((col < 0) || ((col >= per) && (col > 3)) || +- (keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode)) +- return NoSymbol; +- +- syms = &keymap->map[(keycode - keymap->minKeyCode) * per]; +- if (col >= 4) +- return syms[col]; +- +- if (col > 1) { +- while ((per > 2) && (syms[per - 1] == NoSymbol)) +- per--; +- if (per < 3) +- col -= 2; +- } +- +- if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) { +- XkbConvertCase +- (syms[col&~1], &lsym, &usym); +- if (!(col & 1)) +- return lsym; +- /* +- * I'm commenting out this logic because it's incorrect even +- * though it was copied from the Xlib sources. The X protocol +- * book quite clearly states that where a group consists of +- * element 1 being a non-alphabetic keysym and element 2 being +- * NoSymbol that you treat the second element as being the +- * same as the first. This also tallies with the behaviour +- * produced by the installed Xlib on my linux box (I believe +- * this is because it uses some XKB code rather than the +- * original Xlib code - compare XKBBind.c with KeyBind.c in +- * lib/X11). +- */ +-#if 0 +- else if (usym == lsym) +- return NoSymbol; +-#endif +- else +- return usym; +- } +- +- return syms[col]; +-} ++ if ((new_state & ~ShiftMask) != (state & ~ShiftMask)) ++ level_three_mask = getLevelThreeMask(); ++ else ++ level_three_mask = 0; ++ ++ shift_press = level_three_press = 0; ++ ++ /* Need a fake press or release of shift? */ ++ if (!(state & ShiftMask) && (new_state & ShiftMask)) { ++ shift_press = pressShift(); ++ if (shift_press == 0) { ++ vlog.error("Unable to find a modifier key for Shift"); ++ return; ++ } + +-/* +- * KeysymToKeycode() - find the keycode and column corresponding to the given +- * keysym. The value of col passed in should be the column determined from the +- * current shift state. If the keysym can be found in that column we prefer +- * that to finding it in a different column (which would require fake events to +- * alter the shift state). +- */ +-static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col) +-{ +- int i, j; ++ pressKey(keyboardDev, shift_press, true, "temp shift"); ++ } else if ((state & ShiftMask) && !(new_state & ShiftMask)) { ++ std::list::const_iterator iter; ++ ++ shift_release = releaseShift(); ++ if (shift_release.empty()) { ++ vlog.error("Unable to find the modifier key(s) for releasing Shift"); ++ return; ++ } + +- j = *col; +- for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { +- if (KeyCodetoKeySym(keymap, i, j) == ks) +- return i; ++ for (iter = shift_release.begin();iter != shift_release.end();++iter) ++ pressKey(keyboardDev, *iter, false, "temp shift"); + } + +- for (j = 0; j < keymap->mapWidth; j++) { +- for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { +- if (KeyCodetoKeySym(keymap, i, j) == ks) { +- *col = j; +- return i; +- } ++ /* Need a fake press or release of level three shift? */ ++ if (!(state & level_three_mask) && (new_state & level_three_mask)) { ++ level_three_press = pressLevelThree(); ++ if (level_three_press == 0) { ++ vlog.error("Unable to find a modifier key for ISO_Level3_Shift/Mode_Switch"); ++ return; + } +- } + +- return 0; +-} +- +-#if XORG < 17 +-/* Fairly standard US PC Keyboard */ +- +-#define MIN_KEY 8 +-#define MAX_KEY 255 +-#define MAP_LEN (MAX_KEY - MIN_KEY + 1) +-#define KEYSYMS_PER_KEY 2 +-KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = { +- NoSymbol, NoSymbol, +- XK_Escape, NoSymbol, +- XK_1, XK_exclam, +- XK_2, XK_at, +- XK_3, XK_numbersign, +- XK_4, XK_dollar, +- XK_5, XK_percent, +- XK_6, XK_asciicircum, +- XK_7, XK_ampersand, +- XK_8, XK_asterisk, +- XK_9, XK_parenleft, +- XK_0, XK_parenright, +- XK_minus, XK_underscore, +- XK_equal, XK_plus, +- XK_BackSpace, NoSymbol, +- XK_Tab, NoSymbol, +- XK_q, XK_Q, +- XK_w, XK_W, +- XK_e, XK_E, +- XK_r, XK_R, +- XK_t, XK_T, +- XK_y, XK_Y, +- XK_u, XK_U, +- XK_i, XK_I, +- XK_o, XK_O, +- XK_p, XK_P, +- XK_bracketleft, XK_braceleft, +- XK_bracketright, XK_braceright, +- XK_Return, NoSymbol, +- XK_Control_L, NoSymbol, +- XK_a, XK_A, +- XK_s, XK_S, +- XK_d, XK_D, +- XK_f, XK_F, +- XK_g, XK_G, +- XK_h, XK_H, +- XK_j, XK_J, +- XK_k, XK_K, +- XK_l, XK_L, +- XK_semicolon, XK_colon, +- XK_apostrophe, XK_quotedbl, +- XK_grave, XK_asciitilde, +- XK_Shift_L, NoSymbol, +- XK_backslash, XK_bar, +- XK_z, XK_Z, +- XK_x, XK_X, +- XK_c, XK_C, +- XK_v, XK_V, +- XK_b, XK_B, +- XK_n, XK_N, +- XK_m, XK_M, +- XK_comma, XK_less, +- XK_period, XK_greater, +- XK_slash, XK_question, +- XK_Shift_R, NoSymbol, +- XK_KP_Multiply, NoSymbol, +- XK_Alt_L, XK_Meta_L, +- XK_space, NoSymbol, +- XK_Caps_Lock, NoSymbol, +- XK_F1, NoSymbol, +- XK_F2, NoSymbol, +- XK_F3, NoSymbol, +- XK_F4, NoSymbol, +- XK_F5, NoSymbol, +- XK_F6, NoSymbol, +- XK_F7, NoSymbol, +- XK_F8, NoSymbol, +- XK_F9, NoSymbol, +- XK_F10, NoSymbol, +- XK_Num_Lock, XK_Pointer_EnableKeys, +- XK_Scroll_Lock, NoSymbol, +- XK_KP_Home, XK_KP_7, +- XK_KP_Up, XK_KP_8, +- XK_KP_Prior, XK_KP_9, +- XK_KP_Subtract, NoSymbol, +- XK_KP_Left, XK_KP_4, +- XK_KP_Begin, XK_KP_5, +- XK_KP_Right, XK_KP_6, +- XK_KP_Add, NoSymbol, +- XK_KP_End, XK_KP_1, +- XK_KP_Down, XK_KP_2, +- XK_KP_Next, XK_KP_3, +- XK_KP_Insert, XK_KP_0, +- XK_KP_Delete, XK_KP_Decimal, +- NoSymbol, NoSymbol, +- NoSymbol, NoSymbol, +- NoSymbol, NoSymbol, +- XK_F11, NoSymbol, +- XK_F12, NoSymbol, +- XK_Home, NoSymbol, +- XK_Up, NoSymbol, +- XK_Prior, NoSymbol, +- XK_Left, NoSymbol, +- NoSymbol, NoSymbol, +- XK_Right, NoSymbol, +- XK_End, NoSymbol, +- XK_Down, NoSymbol, +- XK_Next, NoSymbol, +- XK_Insert, NoSymbol, +- XK_Delete, NoSymbol, +- XK_KP_Enter, NoSymbol, +- XK_Control_R, NoSymbol, +- XK_Pause, XK_Break, +- XK_Print, XK_Execute, +- XK_KP_Divide, NoSymbol, +- XK_Alt_R, XK_Meta_R, +- NoSymbol, NoSymbol, +- XK_Super_L, NoSymbol, +- XK_Super_R, NoSymbol, +- XK_Menu, NoSymbol, +-}; ++ pressKey(keyboardDev, level_three_press, true, "temp level 3 shift"); ++ } else if ((state & level_three_mask) && !(new_state & level_three_mask)) { ++ std::list::const_iterator iter; ++ ++ level_three_release = releaseLevelThree(); ++ if (level_three_release.empty()) { ++ vlog.error("Unable to find the modifier key(s) for releasing ISO_Level3_Shift/Mode_Switch"); ++ return; ++ } + +-static Bool GetMappings(KeySymsPtr pKeySyms, CARD8 *pModMap) +-{ +- int i; ++ for (iter = level_three_release.begin();iter != level_three_release.end();++iter) ++ pressKey(keyboardDev, *iter, false, "temp level 3 shift"); ++ } + +- for (i = 0; i < MAP_LENGTH; i++) +- pModMap[i] = NoSymbol; ++ /* Now press the actual key */ ++ pressKey(keyboardDev, keycode, true, "keycode"); + +- for (i = 0; i < MAP_LEN; i++) { +- switch (keyboardMap[i * KEYSYMS_PER_KEY]) { +- case XK_Shift_L: +- case XK_Shift_R: +- pModMap[i + MIN_KEY] = ShiftMask; +- break; +- case XK_Caps_Lock: +- pModMap[i + MIN_KEY] = LockMask; +- break; +- case XK_Control_L: +- case XK_Control_R: +- pModMap[i + MIN_KEY] = ControlMask; +- break; +- case XK_Alt_L: +- case XK_Alt_R: +- pModMap[i + MIN_KEY] = Mod1Mask; +- break; +- case XK_Num_Lock: +- pModMap[i + MIN_KEY] = Mod2Mask; +- break; +- /* No defaults for Mod3Mask yet */ +- case XK_Super_L: +- case XK_Super_R: +- case XK_Hyper_L: +- case XK_Hyper_R: +- pModMap[i + MIN_KEY] = Mod4Mask; +- break; +- case XK_ISO_Level3_Shift: +- case XK_Mode_switch: +- pModMap[i + MIN_KEY] = Mod5Mask; +- break; ++ /* And store the mapping so that we can do a proper release later */ ++ for (i = 0;i < 256;i++) { ++ if (i == keycode) ++ continue; ++ if (pressedKeys[i] == keysym) { ++ vlog.error("Keysym 0x%x generated by both keys %d and %d", keysym, i, keycode); ++ pressedKeys[i] = NoSymbol; + } + } + +- pKeySyms->minKeyCode = MIN_KEY; +- pKeySyms->maxKeyCode = MAX_KEY; +- pKeySyms->mapWidth = KEYSYMS_PER_KEY; +- pKeySyms->map = keyboardMap; ++ pressedKeys[keycode] = keysym; + +- return TRUE; +-} +-#endif +- +-static void keyboardBell(int percent, DeviceIntPtr device, pointer ctrl, +- int class_) +-{ +- if (percent > 0) +- vncBell(); +-} +- +-static int keyboardProc(DeviceIntPtr pDevice, int onoff) +-{ +-#if XORG < 17 +- KeySymsRec keySyms; +- CARD8 modMap[MAP_LENGTH]; +-#endif +- DevicePtr pDev = (DevicePtr)pDevice; ++ /* Undo any fake level three shift */ ++ if (level_three_press != 0) ++ pressKey(keyboardDev, level_three_press, false, "temp level 3 shift"); ++ else if (!level_three_release.empty()) { ++ std::list::const_iterator iter; ++ for (iter = level_three_release.begin();iter != level_three_release.end();++iter) ++ pressKey(keyboardDev, *iter, true, "temp level 3 shift"); ++ } + +- switch (onoff) { +- case DEVICE_INIT: +-#if XORG < 17 +- GetMappings(&keySyms, modMap); +-#endif +- InitKeyboardDeviceStruct( +-#if XORG >= 17 +- pDevice, NULL, +-#else +- pDev, &keySyms, modMap, +-#endif +- keyboardBell, (KbdCtrlProcPtr)NoopDDA); +- break; +- case DEVICE_ON: +- pDev->on = TRUE; +- break; +- case DEVICE_OFF: +- pDev->on = FALSE; +- break; +-#if 0 +- case DEVICE_CLOSE: +- break; +-#endif ++ /* Undo any fake shift */ ++ if (shift_press != 0) ++ pressKey(keyboardDev, shift_press, false, "temp shift"); ++ else if (!shift_release.empty()) { ++ std::list::const_iterator iter; ++ for (iter = shift_release.begin();iter != shift_release.end();++iter) ++ pressKey(keyboardDev, *iter, true, "temp shift"); + } + +- return Success; ++ /* ++ * When faking a modifier we are putting a keycode (which can ++ * currently activate the desired modifier) on the input ++ * queue. A future modmap change can change the mapping so ++ * that this keycode means something else entirely. Guard ++ * against this by processing the queue now. ++ */ ++ mieqProcessInputEvents(); + } +- +diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputCore.cc.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputCore.cc +--- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputCore.cc.input 2014-01-17 16:01:13.141109454 +0000 ++++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputCore.cc 2014-01-17 16:01:13.141109454 +0000 +@@ -0,0 +1,594 @@ ++/* Copyright (C) 2009 TightVNC Team ++ * Copyright (C) 2009 Red Hat, Inc. ++ * Copyright 2013 Pierre Ossman for Cendio AB ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#ifdef HAVE_DIX_CONFIG_H ++#include ++#endif ++ ++#include "Input.h" ++#include "xorg-version.h" ++ ++extern "C" { ++#define public c_public ++#define class c_class ++#include "inputstr.h" ++#ifndef XKB_IN_SERVER ++#define XKB_IN_SERVER ++#endif ++#ifdef XKB ++/* ++ * This include is needed to use XkbConvertCase instead of XConvertCase even if ++ * we don't use XKB extension. ++ */ ++#include ++#endif ++/* These defines give us access to all keysyms we need */ ++#define XK_PUBLISHING ++#define XK_TECHNICAL ++#include ++#include ++#include ++#include ++#undef public ++#undef class ++} ++ ++#if XORG < 17 ++ ++#define IS_PRESSED(dev, keycode) \ ++ ((dev)->key->down[(keycode) >> 3] & (1 << ((keycode) & 7))) ++ ++/* Fairly standard US PC Keyboard */ ++ ++#define MIN_KEY 8 ++#define MAX_KEY 255 ++#define MAP_LEN (MAX_KEY - MIN_KEY + 1) ++#define KEYSYMS_PER_KEY 2 ++KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = { ++ NoSymbol, NoSymbol, ++ XK_Escape, NoSymbol, ++ XK_1, XK_exclam, ++ XK_2, XK_at, ++ XK_3, XK_numbersign, ++ XK_4, XK_dollar, ++ XK_5, XK_percent, ++ XK_6, XK_asciicircum, ++ XK_7, XK_ampersand, ++ XK_8, XK_asterisk, ++ XK_9, XK_parenleft, ++ XK_0, XK_parenright, ++ XK_minus, XK_underscore, ++ XK_equal, XK_plus, ++ XK_BackSpace, NoSymbol, ++ XK_Tab, NoSymbol, ++ XK_q, XK_Q, ++ XK_w, XK_W, ++ XK_e, XK_E, ++ XK_r, XK_R, ++ XK_t, XK_T, ++ XK_y, XK_Y, ++ XK_u, XK_U, ++ XK_i, XK_I, ++ XK_o, XK_O, ++ XK_p, XK_P, ++ XK_bracketleft, XK_braceleft, ++ XK_bracketright, XK_braceright, ++ XK_Return, NoSymbol, ++ XK_Control_L, NoSymbol, ++ XK_a, XK_A, ++ XK_s, XK_S, ++ XK_d, XK_D, ++ XK_f, XK_F, ++ XK_g, XK_G, ++ XK_h, XK_H, ++ XK_j, XK_J, ++ XK_k, XK_K, ++ XK_l, XK_L, ++ XK_semicolon, XK_colon, ++ XK_apostrophe, XK_quotedbl, ++ XK_grave, XK_asciitilde, ++ XK_Shift_L, NoSymbol, ++ XK_backslash, XK_bar, ++ XK_z, XK_Z, ++ XK_x, XK_X, ++ XK_c, XK_C, ++ XK_v, XK_V, ++ XK_b, XK_B, ++ XK_n, XK_N, ++ XK_m, XK_M, ++ XK_comma, XK_less, ++ XK_period, XK_greater, ++ XK_slash, XK_question, ++ XK_Shift_R, NoSymbol, ++ XK_KP_Multiply, NoSymbol, ++ XK_Alt_L, XK_Meta_L, ++ XK_space, NoSymbol, ++ XK_Caps_Lock, NoSymbol, ++ XK_F1, NoSymbol, ++ XK_F2, NoSymbol, ++ XK_F3, NoSymbol, ++ XK_F4, NoSymbol, ++ XK_F5, NoSymbol, ++ XK_F6, NoSymbol, ++ XK_F7, NoSymbol, ++ XK_F8, NoSymbol, ++ XK_F9, NoSymbol, ++ XK_F10, NoSymbol, ++ XK_Num_Lock, XK_Pointer_EnableKeys, ++ XK_Scroll_Lock, NoSymbol, ++ XK_KP_Home, XK_KP_7, ++ XK_KP_Up, XK_KP_8, ++ XK_KP_Prior, XK_KP_9, ++ XK_KP_Subtract, NoSymbol, ++ XK_KP_Left, XK_KP_4, ++ XK_KP_Begin, XK_KP_5, ++ XK_KP_Right, XK_KP_6, ++ XK_KP_Add, NoSymbol, ++ XK_KP_End, XK_KP_1, ++ XK_KP_Down, XK_KP_2, ++ XK_KP_Next, XK_KP_3, ++ XK_KP_Insert, XK_KP_0, ++ XK_KP_Delete, XK_KP_Decimal, ++ NoSymbol, NoSymbol, ++ NoSymbol, NoSymbol, ++ NoSymbol, NoSymbol, ++ XK_F11, NoSymbol, ++ XK_F12, NoSymbol, ++ XK_Home, NoSymbol, ++ XK_Up, NoSymbol, ++ XK_Prior, NoSymbol, ++ XK_Left, NoSymbol, ++ NoSymbol, NoSymbol, ++ XK_Right, NoSymbol, ++ XK_End, NoSymbol, ++ XK_Down, NoSymbol, ++ XK_Next, NoSymbol, ++ XK_Insert, NoSymbol, ++ XK_Delete, NoSymbol, ++ XK_KP_Enter, NoSymbol, ++ XK_Control_R, NoSymbol, ++ XK_Pause, XK_Break, ++ XK_Print, XK_Execute, ++ XK_KP_Divide, NoSymbol, ++ XK_Alt_R, XK_Meta_R, ++ NoSymbol, NoSymbol, ++ XK_Super_L, NoSymbol, ++ XK_Super_R, NoSymbol, ++ XK_Menu, NoSymbol, ++}; ++ ++void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap) ++{ ++ int i; ++ ++ for (i = 0; i < MAP_LENGTH; i++) ++ modmap[i] = NoSymbol; ++ ++ for (i = 0; i < MAP_LEN; i++) { ++ switch (keyboardMap[i * KEYSYMS_PER_KEY]) { ++ case XK_Shift_L: ++ case XK_Shift_R: ++ modmap[i + MIN_KEY] = ShiftMask; ++ break; ++ case XK_Caps_Lock: ++ modmap[i + MIN_KEY] = LockMask; ++ break; ++ case XK_Control_L: ++ case XK_Control_R: ++ modmap[i + MIN_KEY] = ControlMask; ++ break; ++ case XK_Alt_L: ++ case XK_Alt_R: ++ modmap[i + MIN_KEY] = Mod1Mask; ++ break; ++ case XK_Num_Lock: ++ modmap[i + MIN_KEY] = Mod2Mask; ++ break; ++ /* No defaults for Mod3Mask yet */ ++ case XK_Super_L: ++ case XK_Super_R: ++ case XK_Hyper_L: ++ case XK_Hyper_R: ++ modmap[i + MIN_KEY] = Mod4Mask; ++ break; ++ case XK_ISO_Level3_Shift: ++ case XK_Mode_switch: ++ modmap[i + MIN_KEY] = Mod5Mask; ++ break; ++ } ++ } ++ ++ keysyms->minKeyCode = MIN_KEY; ++ keysyms->maxKeyCode = MAX_KEY; ++ keysyms->mapWidth = KEYSYMS_PER_KEY; ++ keysyms->map = keyboardMap; ++} ++ ++void InputDevice::PrepareInputDevices(void) ++{ ++ /* Don't need to do anything here */ ++} ++ ++unsigned InputDevice::getKeyboardState(void) ++{ ++ return keyboardDev->key->state; ++} ++ ++unsigned InputDevice::getLevelThreeMask(void) ++{ ++ int i, j, k; ++ ++ int minKeyCode, mapWidth; ++ KeySym *map; ++ ++ int maxKeysPerMod; ++ CARD8 *modmap; ++ ++ minKeyCode = keyboardDev->key->curKeySyms.minKeyCode; ++ mapWidth = keyboardDev->key->curKeySyms.mapWidth; ++ map = keyboardDev->key->curKeySyms.map; ++ ++ maxKeysPerMod = keyboardDev->key->maxKeysPerModifier; ++ modmap = keyboardDev->key->modifierKeyMap; ++ ++ for (i = 3; i < 8; i++) { ++ for (k = 0; k < maxKeysPerMod; k++) { ++ int index = i * maxKeysPerMod + k; ++ int keycode = modmap[index]; ++ ++ if (keycode == 0) ++ continue; ++ ++ for (j = 0; j < mapWidth; j++) { ++ KeySym keysym; ++ keysym = map[(keycode - minKeyCode) * mapWidth + j]; ++ if (keysym == XK_Mode_switch) ++ return 1 << i; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++KeyCode InputDevice::pressShift(void) ++{ ++ int maxKeysPerMod; ++ ++ maxKeysPerMod = keyboardDev->key->maxKeysPerModifier; ++ return keyboardDev->key->modifierKeyMap[ShiftMapIndex * maxKeysPerMod]; ++} ++ ++std::list InputDevice::releaseShift(void) ++{ ++ std::list keys; ++ ++ int maxKeysPerMod; ++ ++ maxKeysPerMod = keyboardDev->key->maxKeysPerModifier; ++ for (int k = 0; k < maxKeysPerMod; k++) { ++ int keycode; ++ int index; ++ ++ index = ShiftMapIndex * maxKeysPerMod + k; ++ ++ keycode = keyboardDev->key->modifierKeyMap[index]; ++ if (keycode == 0) ++ continue; ++ ++ if (!IS_PRESSED(keyboardDev, keycode)) ++ continue; ++ ++ keys.push_back(keycode); ++ } ++ ++ return keys; ++} ++ ++KeyCode InputDevice::pressLevelThree(void) ++{ ++ unsigned mask, index; ++ int maxKeysPerMod; ++ ++ mask = getLevelThreeMask(); ++ if (mask == 0) ++ return 0; ++ ++ index = ffs(mask) - 1; ++ maxKeysPerMod = keyboardDev->key->maxKeysPerModifier; ++ return keyboardDev->key->modifierKeyMap[index * maxKeysPerMod]; ++} ++ ++std::list InputDevice::releaseLevelThree(void) ++{ ++ std::list keys; ++ ++ unsigned mask, msindex; ++ int maxKeysPerMod; ++ ++ mask = getLevelThreeMask(); ++ if (mask == 0) ++ return keys; ++ ++ msindex = ffs(mask) - 1; ++ ++ maxKeysPerMod = keyboardDev->key->maxKeysPerModifier; ++ for (int k = 0; k < maxKeysPerMod; k++) { ++ int keycode; ++ int index; ++ ++ index = msindex * maxKeysPerMod + k; ++ ++ keycode = keyboardDev->key->modifierKeyMap[index]; ++ if (keycode == 0) ++ continue; ++ ++ if (!IS_PRESSED(keyboardDev, keycode)) ++ continue; ++ ++ keys.push_back(keycode); ++ } ++ ++ return keys; ++} ++ ++static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col) ++{ ++ int per = keymap->mapWidth; ++ KeySym *syms; ++ KeySym lsym, usym; ++ ++ if ((col < 0) || ((col >= per) && (col > 3)) || ++ (keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode)) ++ return NoSymbol; ++ ++ syms = &keymap->map[(keycode - keymap->minKeyCode) * per]; ++ if (col >= 4) ++ return syms[col]; ++ ++ if (col > 1) { ++ while ((per > 2) && (syms[per - 1] == NoSymbol)) ++ per--; ++ if (per < 3) ++ col -= 2; ++ } ++ ++ if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) { ++ XkbConvertCase(syms[col&~1], &lsym, &usym); ++ if (!(col & 1)) ++ return lsym; ++ /* ++ * I'm commenting out this logic because it's incorrect even ++ * though it was copied from the Xlib sources. The X protocol ++ * book quite clearly states that where a group consists of ++ * element 1 being a non-alphabetic keysym and element 2 being ++ * NoSymbol that you treat the second element as being the ++ * same as the first. This also tallies with the behaviour ++ * produced by the installed Xlib on my linux box (I believe ++ * this is because it uses some XKB code rather than the ++ * original Xlib code - compare XKBBind.c with KeyBind.c in ++ * lib/X11). ++ */ ++#if 0 ++ else if (usym == lsym) ++ return NoSymbol; ++#endif ++ else ++ return usym; ++ } ++ ++ return syms[col]; ++} ++ ++KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state) ++{ ++ int i, j; ++ unsigned mask; ++ ++ KeySymsPtr keymap; ++ int mapWidth; ++ ++ mask = getLevelThreeMask(); ++ ++ keymap = &keyboardDev->key->curKeySyms; ++ ++ /* ++ * Column 0 means both shift and "mode_switch" (AltGr) must be released, ++ * column 1 means shift must be pressed and mode_switch released, ++ * column 2 means shift must be released and mode_switch pressed, and ++ * column 3 means both shift and mode_switch must be pressed. ++ */ ++ j = 0; ++ if (state & ShiftMask) ++ j |= 0x1; ++ if (state & mask) ++ j |= 0x2; ++ ++ *new_state = state; ++ for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { ++ if (KeyCodetoKeySym(keymap, i, j) == keysym) ++ return i; ++ } ++ ++ /* Only the first four columns have well-defined meaning */ ++ mapWidth = keymap->mapWidth; ++ if (mapWidth > 4) ++ mapWidth = 4; ++ ++ for (j = 0; j < mapWidth; j++) { ++ for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { ++ if (KeyCodetoKeySym(keymap, i, j) == keysym) { ++ *new_state = state & ~(ShiftMask|mask); ++ if (j & 0x1) ++ *new_state |= ShiftMask; ++ if (j & 0x2) ++ *new_state |= mask; ++ ++ return i; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++bool InputDevice::isLockModifier(KeyCode keycode, unsigned state) ++{ ++ int i, j, k; ++ ++ int minKeyCode, mapWidth; ++ KeySym *map; ++ ++ int maxKeysPerMod; ++ CARD8 *modmap; ++ ++ int num_lock_index; ++ ++ minKeyCode = keyboardDev->key->curKeySyms.minKeyCode; ++ mapWidth = keyboardDev->key->curKeySyms.mapWidth; ++ map = keyboardDev->key->curKeySyms.map; ++ ++ maxKeysPerMod = keyboardDev->key->maxKeysPerModifier; ++ modmap = keyboardDev->key->modifierKeyMap; ++ ++ /* Caps Lock is fairly easy as it has a dedicated modmap entry */ ++ for (k = 0; k < maxKeysPerMod; k++) { ++ int index; ++ ++ index = LockMapIndex * maxKeysPerMod + k; ++ if (keycode == modmap[index]) ++ return true; ++ } ++ ++ /* For Num Lock we need to find the correct modmap entry */ ++ num_lock_index = i; ++ for (i = 3; i < 8; i++) { ++ for (k = 0; k < maxKeysPerMod; k++) { ++ int index = i * maxKeysPerMod + k; ++ int keycode = modmap[index]; ++ ++ if (keycode == 0) ++ continue; ++ ++ for (j = 0; j < mapWidth; j++) { ++ KeySym keysym; ++ keysym = map[(keycode - minKeyCode) * mapWidth + j]; ++ if (keysym == XK_Num_Lock) { ++ num_lock_index = i; ++ goto done; ++ } ++ } ++ } ++ } ++done: ++ ++ if (num_lock_index == 0) ++ return false; ++ ++ /* Now we can look in the modmap */ ++ for (k = 0; k < maxKeysPerMod; k++) { ++ int index; ++ ++ index = num_lock_index * maxKeysPerMod + k; ++ if (keycode == modmap[index]) ++ return true; ++ } ++ ++ return false; ++} ++ ++bool InputDevice::isAffectedByNumLock(KeyCode keycode) ++{ ++ KeySymsPtr keymap; ++ int i, per; ++ KeySym *syms; ++ ++ keymap = &keyboardDev->key->curKeySyms; ++ per = keymap->mapWidth; ++ syms = &keymap->map[(keycode - keymap->minKeyCode) * per]; ++ ++ for (i = 0;i < per;i++) { ++ if (IsKeypadKey(syms[i])) ++ return true; ++ if (IsPrivateKeypadKey(syms[i])) ++ return true; ++ } ++ ++ return false; ++} ++ ++KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state) ++{ ++ KeyCode kc; ++ ++ int minKeyCode, maxKeyCode, mapWidth; ++ KeySym *map; ++ ++ minKeyCode = keyboardDev->key->curKeySyms.minKeyCode; ++ maxKeyCode = keyboardDev->key->curKeySyms.maxKeyCode; ++ mapWidth = keyboardDev->key->curKeySyms.mapWidth; ++ map = keyboardDev->key->curKeySyms.map; ++ ++ /* ++ * Magic, which dynamically adds keysym<->keycode mapping ++ * depends on X.Org version. Quick explanation of that "magic": ++ * ++ * 1.5 ++ * - has only one core keyboard so we have to keep core ++ * keyboard mapping synchronized with vncKeyboardDevice. Do ++ * it via SwitchCoreKeyboard() ++ * ++ * 1.6 (aka MPX - Multi pointer X) ++ * - multiple master devices (= core devices) exists, keep ++ * vncKeyboardDevice synchronized with proper master device ++ */ ++ for (kc = maxKeyCode; kc >= minKeyCode; kc--) { ++ DeviceIntPtr master; ++ ++ if (map[(kc - minKeyCode) * mapWidth] != 0) ++ continue; ++ ++ map[(kc - minKeyCode) * mapWidth] = keysym; ++ ++#if XORG == 15 ++ master = inputInfo.keyboard; ++#else ++ master = keyboardDev->u.master; ++#endif ++ void *slave = dixLookupPrivate(&master->devPrivates, ++ CoreDevicePrivateKey); ++ if (keyboardDev == slave) { ++ dixSetPrivate(&master->devPrivates, ++ CoreDevicePrivateKey, NULL); ++#if XORG == 15 ++ SwitchCoreKeyboard(keyboardDev); ++#else ++ CopyKeyClass(keyboardDev, master); ++#endif ++ } ++ ++ return kc; ++ } ++ ++ return 0; ++} ++ ++#endif ++ +diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.h.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.h +--- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.h.input 2010-04-14 10:24:06.000000000 +0100 ++++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Input.h 2014-01-17 16:01:13.141109454 +0000 +@@ -1,6 +1,7 @@ + /* Copyright (C) 2009 TightVNC Team + * Copyright (C) 2009, 2010 Red Hat, Inc. + * Copyright (C) 2009, 2010 TigerVNC Team ++ * Copyright 2013 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -26,12 +27,16 @@ + #include + #endif + ++#include ++ + #include + + extern "C" { + #include "input.h" + }; + ++#include "xorg-version.h" ++ + /* Represents input device (keyboard + pointer) */ + class InputDevice { + public: +@@ -55,24 +60,58 @@ public: + + void KeyboardPress(rdr::U32 keysym) { keyEvent(keysym, true); } + void KeyboardRelease(rdr::U32 keysym) { keyEvent(keysym, false); } +-private: ++ + /* + * Init input device. This cannot be done in the constructor + * because constructor is called during X server extensions + * initialization. Devices must be initialized after core + * pointer/keyboard initialization which is actually after extesions + * initialization. Check InitExtensions(), InitCoreDevices() and +- * InitInput() calls in dix/main.c ++ * InitInput() calls in dix/main.c. Instead it is called from ++ * XserverDesktop at an appropriate time. + */ +- void initInputDevice(void); ++ void InitInputDevice(void); + ++private: + void keyEvent(rdr::U32 keysym, bool down); + ++ /* Backend dependent functions below here */ ++ void PrepareInputDevices(void); ++ ++ unsigned getKeyboardState(void); ++ unsigned getLevelThreeMask(void); ++ ++ KeyCode pressShift(void); ++ std::list releaseShift(void); ++ ++ KeyCode pressLevelThree(void); ++ std::list releaseLevelThree(void); ++ ++ KeyCode keysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state); ++ ++ bool isLockModifier(KeyCode keycode, unsigned state); ++ ++ bool isAffectedByNumLock(KeyCode keycode); ++ ++ KeyCode addKeysym(KeySym keysym, unsigned state); ++ ++private: ++#if XORG >= 17 ++ static void vncXkbProcessDeviceEvent(int screenNum, ++ InternalEvent *event, ++ DeviceIntPtr dev); ++#endif ++ ++private: + rfb::VNCServerST *server; ++ bool initialized; + DeviceIntPtr keyboardDev; + DeviceIntPtr pointerDev; ++ + int oldButtonMask; + rfb::Point cursorPos, oldCursorPos; ++ ++ KeySym pressedKeys[256]; + }; + + #endif +diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputXKB.cc.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputXKB.cc +--- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputXKB.cc.input 2014-01-17 16:01:13.141109454 +0000 ++++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/InputXKB.cc 2014-01-17 16:01:13.141109454 +0000 +@@ -0,0 +1,669 @@ ++/* Copyright (C) 2009 TightVNC Team ++ * Copyright (C) 2009 Red Hat, Inc. ++ * Copyright 2013 Pierre Ossman for Cendio AB ++ * ++ * This is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This software is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this software; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ * USA. ++ */ ++ ++#ifdef HAVE_DIX_CONFIG_H ++#include ++#endif ++ ++#include "Input.h" ++#include "xorg-version.h" ++ ++#if XORG >= 17 ++ ++extern "C" { ++#define public c_public ++#define class c_class ++#include "xkbsrv.h" ++#include "xkbstr.h" ++#include "eventstr.h" ++#include "scrnintstr.h" ++#include "mi.h" ++#include ++#include ++#include ++#undef public ++#undef class ++} ++ ++#if XORG < 19 ++static int vncXkbScreenPrivateKeyIndex; ++static DevPrivateKey vncXkbScreenPrivateKey = &vncXkbScreenPrivateKeyIndex; ++#else ++static DevPrivateKeyRec vncXkbPrivateKeyRec; ++#define vncXkbScreenPrivateKey (&vncXkbPrivateKeyRec) ++#endif ++ ++#define vncXkbScreenPrivate(pScreen) \ ++ (*(InputDevice**) dixLookupPrivate(&(pScreen)->devPrivates, \ ++ vncXkbScreenPrivateKey)) ++ ++#ifndef KEYBOARD_OR_FLOAT ++#define KEYBOARD_OR_FLOAT MASTER_KEYBOARD ++#endif ++ ++/* Stolen from libX11 */ ++static Bool ++XkbTranslateKeyCode(register XkbDescPtr xkb, KeyCode key, ++ register unsigned int mods, unsigned int *mods_rtrn, ++ KeySym *keysym_rtrn) ++{ ++ XkbKeyTypeRec *type; ++ int col,nKeyGroups; ++ unsigned preserve,effectiveGroup; ++ KeySym *syms; ++ ++ if (mods_rtrn!=NULL) ++ *mods_rtrn = 0; ++ ++ nKeyGroups= XkbKeyNumGroups(xkb,key); ++ if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) { ++ if (keysym_rtrn!=NULL) ++ *keysym_rtrn = NoSymbol; ++ return False; ++ } ++ ++ syms = XkbKeySymsPtr(xkb,key); ++ ++ /* find the offset of the effective group */ ++ col = 0; ++ effectiveGroup= XkbGroupForCoreState(mods); ++ if ( effectiveGroup>=nKeyGroups ) { ++ unsigned groupInfo= XkbKeyGroupInfo(xkb,key); ++ switch (XkbOutOfRangeGroupAction(groupInfo)) { ++ default: ++ effectiveGroup %= nKeyGroups; ++ break; ++ case XkbClampIntoRange: ++ effectiveGroup = nKeyGroups-1; ++ break; ++ case XkbRedirectIntoRange: ++ effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo); ++ if (effectiveGroup>=nKeyGroups) ++ effectiveGroup= 0; ++ break; ++ } ++ } ++ col= effectiveGroup*XkbKeyGroupsWidth(xkb,key); ++ type = XkbKeyKeyType(xkb,key,effectiveGroup); ++ ++ preserve= 0; ++ if (type->map) { /* find the column (shift level) within the group */ ++ register int i; ++ register XkbKTMapEntryPtr entry; ++ for (i=0,entry=type->map;imap_count;i++,entry++) { ++ if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) { ++ col+= entry->level; ++ if (type->preserve) ++ preserve= type->preserve[i].mask; ++ break; ++ } ++ } ++ } ++ ++ if (keysym_rtrn!=NULL) ++ *keysym_rtrn= syms[col]; ++ if (mods_rtrn) ++ *mods_rtrn= type->mods.mask&(~preserve); ++ ++ return (syms[col]!=NoSymbol); ++} ++ ++static XkbAction *XkbKeyActionPtr(XkbDescPtr xkb, KeyCode key, unsigned int mods) ++{ ++ XkbKeyTypeRec *type; ++ int col,nKeyGroups; ++ unsigned effectiveGroup; ++ XkbAction *acts; ++ ++ if (!XkbKeyHasActions(xkb, key)) ++ return NULL; ++ ++ nKeyGroups= XkbKeyNumGroups(xkb,key); ++ if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) ++ return NULL; ++ ++ acts = XkbKeyActionsPtr(xkb,key); ++ ++ /* find the offset of the effective group */ ++ col = 0; ++ effectiveGroup= XkbGroupForCoreState(mods); ++ if ( effectiveGroup>=nKeyGroups ) { ++ unsigned groupInfo= XkbKeyGroupInfo(xkb,key); ++ switch (XkbOutOfRangeGroupAction(groupInfo)) { ++ default: ++ effectiveGroup %= nKeyGroups; ++ break; ++ case XkbClampIntoRange: ++ effectiveGroup = nKeyGroups-1; ++ break; ++ case XkbRedirectIntoRange: ++ effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo); ++ if (effectiveGroup>=nKeyGroups) ++ effectiveGroup= 0; ++ break; ++ } ++ } ++ col= effectiveGroup*XkbKeyGroupsWidth(xkb,key); ++ type = XkbKeyKeyType(xkb,key,effectiveGroup); ++ ++ if (type->map) { /* find the column (shift level) within the group */ ++ register int i; ++ register XkbKTMapEntryPtr entry; ++ for (i=0,entry=type->map;imap_count;i++,entry++) { ++ if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) { ++ col+= entry->level; ++ break; ++ } ++ } ++ } ++ ++ return &acts[col]; ++} ++ ++static unsigned XkbKeyEffectiveGroup(XkbDescPtr xkb, KeyCode key, unsigned int mods) ++{ ++ int nKeyGroups; ++ unsigned effectiveGroup; ++ ++ nKeyGroups= XkbKeyNumGroups(xkb,key); ++ if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) ++ return 0; ++ ++ effectiveGroup= XkbGroupForCoreState(mods); ++ if ( effectiveGroup>=nKeyGroups ) { ++ unsigned groupInfo= XkbKeyGroupInfo(xkb,key); ++ switch (XkbOutOfRangeGroupAction(groupInfo)) { ++ default: ++ effectiveGroup %= nKeyGroups; ++ break; ++ case XkbClampIntoRange: ++ effectiveGroup = nKeyGroups-1; ++ break; ++ case XkbRedirectIntoRange: ++ effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo); ++ if (effectiveGroup>=nKeyGroups) ++ effectiveGroup= 0; ++ break; ++ } ++ } ++ ++ return effectiveGroup; ++} ++ ++void InputDevice::PrepareInputDevices(void) ++{ ++#if XORG < 19 ++ if (!dixRequestPrivate(vncXkbScreenPrivateKey, sizeof(InputDevice*))) ++ FatalError("Failed to register TigerVNC XKB screen key\n"); ++#else ++ if (!dixRegisterPrivateKey(vncXkbScreenPrivateKey, PRIVATE_SCREEN, ++ sizeof(InputDevice*))) ++ FatalError("Failed to register TigerVNC XKB screen key\n"); ++#endif ++ ++ for (int scr = 0; scr < screenInfo.numScreens; scr++) ++ vncXkbScreenPrivate(screenInfo.screens[scr]) = this; ++ ++ /* ++ * Not ideal since these callbacks do not stack, but it's the only ++ * decent way we can reliably catch events for both the slave and ++ * master device. ++ */ ++ mieqSetHandler(ET_KeyPress, vncXkbProcessDeviceEvent); ++ mieqSetHandler(ET_KeyRelease, vncXkbProcessDeviceEvent); ++} ++ ++unsigned InputDevice::getKeyboardState(void) ++{ ++ return XkbStateFieldFromRec(&keyboardDev->master->key->xkbInfo->state); ++} ++ ++unsigned InputDevice::getLevelThreeMask(void) ++{ ++ unsigned state; ++ KeyCode keycode; ++ XkbDescPtr xkb; ++ XkbAction *act; ++ ++ /* Group state is still important */ ++ state = getKeyboardState(); ++ state &= ~0xff; ++ ++ keycode = keysymToKeycode(XK_ISO_Level3_Shift, state, NULL); ++ if (keycode == 0) { ++ keycode = keysymToKeycode(XK_Mode_switch, state, NULL); ++ if (keycode == 0) ++ return 0; ++ } ++ ++ xkb = keyboardDev->master->key->xkbInfo->desc; ++ ++ act = XkbKeyActionPtr(xkb, keycode, state); ++ if (act == NULL) ++ return 0; ++ if (act->type != XkbSA_SetMods) ++ return 0; ++ ++ if (act->mods.flags & XkbSA_UseModMapMods) ++ return xkb->map->modmap[keycode]; ++ else ++ return act->mods.mask; ++} ++ ++KeyCode InputDevice::pressShift(void) ++{ ++ unsigned state; ++ ++ XkbDescPtr xkb; ++ unsigned int key; ++ ++ state = getKeyboardState(); ++ if (state & ShiftMask) ++ return 0; ++ ++ xkb = keyboardDev->master->key->xkbInfo->desc; ++ for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) { ++ XkbAction *act; ++ unsigned char mask; ++ ++ act = XkbKeyActionPtr(xkb, key, state); ++ if (act == NULL) ++ continue; ++ ++ if (act->type != XkbSA_SetMods) ++ continue; ++ ++ if (act->mods.flags & XkbSA_UseModMapMods) ++ mask = xkb->map->modmap[key]; ++ else ++ mask = act->mods.mask; ++ ++ if ((mask & ShiftMask) == ShiftMask) ++ return key; ++ } ++ ++ return 0; ++} ++ ++std::list InputDevice::releaseShift(void) ++{ ++ unsigned state; ++ std::list keys; ++ ++ DeviceIntPtr master; ++ XkbDescPtr xkb; ++ unsigned int key; ++ ++ state = getKeyboardState(); ++ if (!(state & ShiftMask)) ++ return keys; ++ ++ master = keyboardDev->master; ++ xkb = master->key->xkbInfo->desc; ++ for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) { ++ XkbAction *act; ++ unsigned char mask; ++ ++ if (!key_is_down(master, key, KEY_PROCESSED)) ++ continue; ++ ++ act = XkbKeyActionPtr(xkb, key, state); ++ if (act == NULL) ++ continue; ++ ++ if (act->type != XkbSA_SetMods) ++ continue; ++ ++ if (act->mods.flags & XkbSA_UseModMapMods) ++ mask = xkb->map->modmap[key]; ++ else ++ mask = act->mods.mask; ++ ++ if (!(mask & ShiftMask)) ++ continue; ++ ++ keys.push_back(key); ++ } ++ ++ return keys; ++} ++ ++KeyCode InputDevice::pressLevelThree(void) ++{ ++ unsigned state, mask; ++ ++ KeyCode keycode; ++ XkbDescPtr xkb; ++ XkbAction *act; ++ ++ mask = getLevelThreeMask(); ++ if (mask == 0) ++ return 0; ++ ++ state = getKeyboardState(); ++ if (state & mask) ++ return 0; ++ ++ keycode = keysymToKeycode(XK_ISO_Level3_Shift, state, NULL); ++ if (keycode == 0) { ++ keycode = keysymToKeycode(XK_Mode_switch, state, NULL); ++ if (keycode == 0) ++ return 0; ++ } ++ ++ xkb = keyboardDev->master->key->xkbInfo->desc; ++ ++ act = XkbKeyActionPtr(xkb, keycode, state); ++ if (act == NULL) ++ return 0; ++ if (act->type != XkbSA_SetMods) ++ return 0; ++ ++ return keycode; ++} ++ ++std::list InputDevice::releaseLevelThree(void) ++{ ++ unsigned state, mask; ++ std::list keys; ++ ++ DeviceIntPtr master; ++ XkbDescPtr xkb; ++ unsigned int key; ++ ++ mask = getLevelThreeMask(); ++ if (mask == 0) ++ return keys; ++ ++ state = getKeyboardState(); ++ if (!(state & mask)) ++ return keys; ++ ++ master = keyboardDev->master; ++ xkb = master->key->xkbInfo->desc; ++ for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) { ++ XkbAction *act; ++ unsigned char key_mask; ++ ++ if (!key_is_down(master, key, KEY_PROCESSED)) ++ continue; ++ ++ act = XkbKeyActionPtr(xkb, key, state); ++ if (act == NULL) ++ continue; ++ ++ if (act->type != XkbSA_SetMods) ++ continue; ++ ++ if (act->mods.flags & XkbSA_UseModMapMods) ++ key_mask = xkb->map->modmap[key]; ++ else ++ key_mask = act->mods.mask; ++ ++ if (!(key_mask & mask)) ++ continue; ++ ++ keys.push_back(key); ++ } ++ ++ return keys; ++} ++ ++KeyCode InputDevice::keysymToKeycode(KeySym keysym, unsigned state, ++ unsigned *new_state) ++{ ++ XkbDescPtr xkb; ++ unsigned int key; ++ KeySym ks; ++ unsigned level_three_mask; ++ ++ if (new_state != NULL) ++ *new_state = state; ++ ++ xkb = keyboardDev->master->key->xkbInfo->desc; ++ for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) { ++ unsigned int state_out; ++ KeySym dummy; ++ ++ XkbTranslateKeyCode(xkb, key, state, &state_out, &ks); ++ if (ks == NoSymbol) ++ continue; ++ ++ /* ++ * Despite every known piece of documentation on ++ * XkbTranslateKeyCode() stating that mods_rtrn returns ++ * the unconsumed modifiers, in reality it always ++ * returns the _potentially consumed_ modifiers. ++ */ ++ state_out = state & ~state_out; ++ if (state_out & LockMask) ++ XkbConvertCase(ks, &dummy, &ks); ++ ++ if (ks == keysym) ++ return key; ++ } ++ ++ if (new_state == NULL) ++ return 0; ++ ++ *new_state = (state & ~ShiftMask) | ++ ((state & ShiftMask) ? 0 : ShiftMask); ++ key = keysymToKeycode(keysym, *new_state, NULL); ++ if (key != 0) ++ return key; ++ ++ level_three_mask = getLevelThreeMask(); ++ if (level_three_mask == 0) ++ return 0; ++ ++ *new_state = (state & ~level_three_mask) | ++ ((state & level_three_mask) ? 0 : level_three_mask); ++ key = keysymToKeycode(keysym, *new_state, NULL); ++ if (key != 0) ++ return key; ++ ++ *new_state = (state & ~(ShiftMask | level_three_mask)) | ++ ((state & ShiftMask) ? 0 : ShiftMask) | ++ ((state & level_three_mask) ? 0 : level_three_mask); ++ key = keysymToKeycode(keysym, *new_state, NULL); ++ if (key != 0) ++ return key; ++ ++ return 0; ++} ++ ++bool InputDevice::isLockModifier(KeyCode keycode, unsigned state) ++{ ++ XkbDescPtr xkb; ++ XkbAction *act; ++ ++ xkb = keyboardDev->master->key->xkbInfo->desc; ++ ++ act = XkbKeyActionPtr(xkb, keycode, state); ++ if (act == NULL) ++ return false; ++ ++ if (act->type != XkbSA_LockMods) ++ return false; ++ ++ return true; ++} ++ ++bool InputDevice::isAffectedByNumLock(KeyCode keycode) ++{ ++ unsigned state; ++ ++ KeyCode numlock_keycode; ++ unsigned numlock_mask; ++ ++ XkbDescPtr xkb; ++ XkbAction *act; ++ ++ unsigned group; ++ XkbKeyTypeRec *type; ++ ++ /* Group state is still important */ ++ state = getKeyboardState(); ++ state &= ~0xff; ++ ++ /* ++ * Not sure if hunting for a virtual modifier called "NumLock", ++ * or following the keysym Num_Lock is the best approach. We ++ * try the latter. ++ */ ++ numlock_keycode = keysymToKeycode(XK_Num_Lock, state, NULL); ++ if (numlock_keycode == 0) ++ return false; ++ ++ xkb = keyboardDev->master->key->xkbInfo->desc; ++ ++ act = XkbKeyActionPtr(xkb, numlock_keycode, state); ++ if (act == NULL) ++ return false; ++ if (act->type != XkbSA_LockMods) ++ return false; ++ ++ if (act->mods.flags & XkbSA_UseModMapMods) ++ numlock_mask = xkb->map->modmap[keycode]; ++ else ++ numlock_mask = act->mods.mask; ++ ++ group = XkbKeyEffectiveGroup(xkb, keycode, state); ++ type = XkbKeyKeyType(xkb, keycode, group); ++ if ((type->mods.mask & numlock_mask) == 0) ++ return false; ++ ++ return true; ++} ++ ++KeyCode InputDevice::addKeysym(KeySym keysym, unsigned state) ++{ ++ DeviceIntPtr master; ++ XkbDescPtr xkb; ++ unsigned int key; ++ ++ XkbEventCauseRec cause; ++ XkbChangesRec changes; ++ ++ int types[1]; ++ KeySym *syms; ++ KeySym upper, lower; ++ ++ master = keyboardDev->master; ++ xkb = master->key->xkbInfo->desc; ++ for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) { ++ if (XkbKeyNumGroups(xkb, key) == 0) ++ break; ++ } ++ ++ if (key < xkb->min_key_code) ++ return 0; ++ ++ memset(&changes, 0, sizeof(changes)); ++ memset(&cause, 0, sizeof(cause)); ++ ++ XkbSetCauseUnknown(&cause); ++ ++ /* ++ * Tools like xkbcomp get confused if there isn't a name ++ * assigned to the keycode we're trying to use. ++ */ ++ if (xkb->names && xkb->names->keys && ++ (xkb->names->keys[key].name[0] == '\0')) { ++ xkb->names->keys[key].name[0] = 'I'; ++ xkb->names->keys[key].name[1] = '0' + (key / 100) % 10; ++ xkb->names->keys[key].name[2] = '0' + (key / 10) % 10; ++ xkb->names->keys[key].name[3] = '0' + (key / 1) % 10; ++ ++ changes.names.changed |= XkbKeyNamesMask; ++ changes.names.first_key = key; ++ changes.names.num_keys = 1; ++ } ++ ++ /* FIXME: Verify that ONE_LEVEL/ALPHABETIC isn't screwed up */ ++ ++ /* ++ * For keysyms that are affected by Lock, we are better off ++ * using ALPHABETIC rather than ONE_LEVEL as the latter ++ * generally cannot produce lower case when Lock is active. ++ */ ++ XkbConvertCase(keysym, &lower, &upper); ++ if (upper == lower) ++ types[XkbGroup1Index] = XkbOneLevelIndex; ++ else ++ types[XkbGroup1Index] = XkbAlphabeticIndex; ++ ++ XkbChangeTypesOfKey(xkb, key, 1, XkbGroup1Mask, types, &changes.map); ++ ++ syms = XkbKeySymsPtr(xkb,key); ++ if (upper == lower) ++ syms[0] = keysym; ++ else { ++ syms[0] = lower; ++ syms[1] = upper; ++ } ++ ++ changes.map.changed |= XkbKeySymsMask; ++ changes.map.first_key_sym = key; ++ changes.map.num_key_syms = 1; ++ ++ XkbSendNotification(master, &changes, &cause); ++ ++ return key; ++} ++ ++void InputDevice::vncXkbProcessDeviceEvent(int screenNum, ++ InternalEvent *event, ++ DeviceIntPtr dev) ++{ ++ InputDevice *self = vncXkbScreenPrivate(screenInfo.screens[screenNum]); ++ unsigned int backupctrls; ++ ++ if (event->device_event.sourceid == self->keyboardDev->id) { ++ XkbControlsPtr ctrls; ++ ++ /* ++ * We need to bypass AccessX since it is timing sensitive and ++ * the network can cause fake event delays. ++ */ ++ ctrls = dev->key->xkbInfo->desc->ctrls; ++ backupctrls = ctrls->enabled_ctrls; ++ ctrls->enabled_ctrls &= ~XkbAllFilteredEventsMask; ++ ++ /* ++ * This flag needs to be set for key repeats to be properly ++ * respected. ++ */ ++ if ((event->device_event.type == ET_KeyPress) && ++ key_is_down(dev, event->device_event.detail.key, KEY_PROCESSED)) ++ event->device_event.key_repeat = TRUE; ++ } ++ ++ dev->c_public.processInputProc(event, dev); ++ ++ if (event->device_event.sourceid == self->keyboardDev->id) { ++ XkbControlsPtr ctrls; ++ ++ ctrls = dev->key->xkbInfo->desc->ctrls; ++ ctrls->enabled_ctrls = backupctrls; ++ } ++} ++ ++#endif /* XORG >= 117 */ +diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Makefile.am.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Makefile.am +--- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Makefile.am.input 2014-01-17 16:01:04.154064515 +0000 ++++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/Makefile.am 2014-01-17 16:01:13.142109459 +0000 +@@ -14,7 +14,7 @@ HDRS = RegionHelper.h vncExtInit.h vncHo + Input.h + + libvnccommon_la_SOURCES = $(HDRS) vncExtInit.cc vncHooks.cc XserverDesktop.cc \ +- Input.cc ++ Input.cc InputCore.cc InputXKB.cc + + libvnccommon_la_CPPFLAGS = -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \ + -DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(TIGERVNC_SRCDIR)/common -UHAVE_CONFIG_H \ +diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc.input tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc +--- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc.input 2014-01-17 16:01:32.532206349 +0000 ++++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc 2014-01-17 16:02:13.775412129 +0000 +@@ -579,6 +579,12 @@ static struct timeval XserverDesktopTime + + void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout) + { ++ // We don't have a good callback for when we can init input devices[1], ++ // so we abuse the fact that this routine will be called first thing ++ // once the dix is done initialising. ++ // [1] Technically Xvnc has InitInput(), but libvnc.so has nothing. ++ inputDevice->InitInputDevice(); ++ + try { + int nextTimeout; + diff --git a/SOURCES/tigervnc-xstartup.patch b/SOURCES/tigervnc-xstartup.patch new file mode 100644 index 0000000..696d92b --- /dev/null +++ b/SOURCES/tigervnc-xstartup.patch @@ -0,0 +1,32 @@ +diff -up tigervnc-1.3.0/unix/vncserver.xstartup tigervnc-1.3.0/unix/vncserver +--- tigervnc-1.3.0/unix/vncserver.xstartup 2014-02-10 14:52:39.902673875 +0000 ++++ tigervnc-1.3.0/unix/vncserver 2014-02-10 14:53:30.398847723 +0000 +@@ -59,27 +59,7 @@ $defaultXStartup + = ("#!/bin/sh\n\n". + "unset SESSION_MANAGER\n". + "unset DBUS_SESSION_BUS_ADDRESS\n". +- "OS=`uname -s`\n". +- "if [ \$OS = 'Linux' ]; then\n". +- " case \"\$WINDOWMANAGER\" in\n". +- " \*gnome\*)\n". +- " if [ -e /etc/SuSE-release ]; then\n". +- " PATH=\$PATH:/opt/gnome/bin\n". +- " export PATH\n". +- " fi\n". +- " ;;\n". +- " esac\n". +- "fi\n". +- "if [ -x /etc/X11/xinit/xinitrc ]; then\n". +- " exec /etc/X11/xinit/xinitrc\n". +- "fi\n". +- "if [ -f /etc/X11/xinit/xinitrc ]; then\n". +- " exec sh /etc/X11/xinit/xinitrc\n". +- "fi\n". +- "[ -r \$HOME/.Xresources ] && xrdb \$HOME/.Xresources\n". +- "xsetroot -solid grey\n". +- "xterm -geometry 80x24+10+10 -ls -title \"\$VNCDESKTOP Desktop\" &\n". +- "twm &\n"); ++ "exec /etc/X11/xinit/xinitrc\n"); + + chop($host = `uname -n`); + diff --git a/SOURCES/tigervnc-zrle-crash.patch b/SOURCES/tigervnc-zrle-crash.patch new file mode 100644 index 0000000..74545d7 --- /dev/null +++ b/SOURCES/tigervnc-zrle-crash.patch @@ -0,0 +1,69 @@ +diff -up tigervnc-1.3.0/common/rfb/ZRLEEncoder.cxx.zrle-crash tigervnc-1.3.0/common/rfb/ZRLEEncoder.cxx +--- tigervnc-1.3.0/common/rfb/ZRLEEncoder.cxx.zrle-crash 2013-07-01 13:41:59.000000000 +0100 ++++ tigervnc-1.3.0/common/rfb/ZRLEEncoder.cxx 2013-12-12 17:30:48.510007365 +0000 +@@ -55,16 +55,19 @@ Encoder* ZRLEEncoder::create(SMsgWriter* + } + + ZRLEEncoder::ZRLEEncoder(SMsgWriter* writer_) +- : writer(writer_), zos(0,0,zlibLevel) ++ : writer(writer_) + { + if (sharedMos) + mos = sharedMos; + else + mos = new rdr::MemOutStream(129*1024); ++ ++ zos = new rdr::ZlibOutStream(0, 0, zlibLevel); + } + + ZRLEEncoder::~ZRLEEncoder() + { ++ delete zos; + if (!sharedMos) + delete mos; + } +@@ -78,10 +81,10 @@ bool ZRLEEncoder::writeRect(const Rect& + + switch (writer->bpp()) { + case 8: +- wroteAll = zrleEncode8(r, mos, &zos, imageBuf, maxLen, actual, ig); ++ wroteAll = zrleEncode8(r, mos, zos, imageBuf, maxLen, actual, ig); + break; + case 16: +- wroteAll = zrleEncode16(r, mos, &zos, imageBuf, maxLen, actual, ig); ++ wroteAll = zrleEncode16(r, mos, zos, imageBuf, maxLen, actual, ig); + break; + case 32: + { +@@ -94,16 +97,16 @@ bool ZRLEEncoder::writeRect(const Rect& + if ((fitsInLS3Bytes && pf.isLittleEndian()) || + (fitsInMS3Bytes && pf.isBigEndian())) + { +- wroteAll = zrleEncode24A(r, mos, &zos, imageBuf, maxLen, actual, ig); ++ wroteAll = zrleEncode24A(r, mos, zos, imageBuf, maxLen, actual, ig); + } + else if ((fitsInLS3Bytes && pf.isBigEndian()) || + (fitsInMS3Bytes && pf.isLittleEndian())) + { +- wroteAll = zrleEncode24B(r, mos, &zos, imageBuf, maxLen, actual, ig); ++ wroteAll = zrleEncode24B(r, mos, zos, imageBuf, maxLen, actual, ig); + } + else + { +- wroteAll = zrleEncode32(r, mos, &zos, imageBuf, maxLen, actual, ig); ++ wroteAll = zrleEncode32(r, mos, zos, imageBuf, maxLen, actual, ig); + } + break; + } +diff -up tigervnc-1.3.0/common/rfb/ZRLEEncoder.h.zrle-crash tigervnc-1.3.0/common/rfb/ZRLEEncoder.h +--- tigervnc-1.3.0/common/rfb/ZRLEEncoder.h.zrle-crash 2013-07-01 13:42:01.000000000 +0100 ++++ tigervnc-1.3.0/common/rfb/ZRLEEncoder.h 2013-12-12 17:30:48.510007365 +0000 +@@ -45,7 +45,7 @@ namespace rfb { + private: + ZRLEEncoder(SMsgWriter* writer); + SMsgWriter* writer; +- rdr::ZlibOutStream zos; ++ rdr::ZlibOutStream* zos; + rdr::MemOutStream* mos; + static rdr::MemOutStream* sharedMos; + static int maxLen; diff --git a/SOURCES/tigervnc12-xorg113-glx.patch b/SOURCES/tigervnc12-xorg113-glx.patch index 09a3ca9..c5a5621 100644 --- a/SOURCES/tigervnc12-xorg113-glx.patch +++ b/SOURCES/tigervnc12-xorg113-glx.patch @@ -1,63 +1,15 @@ -diff -up tigervnc-1.2.80-20120905svn4996/unix/xserver/hw/vnc/Makefile.am.jx tigervnc-1.2.80-20120905svn4996/unix/xserver/hw/vnc/Makefile.am ---- tigervnc-1.2.80-20120905svn4996/unix/xserver/hw/vnc/Makefile.am.jx 2012-09-28 13:24:53.000000000 -0400 -+++ tigervnc-1.2.80-20120905svn4996/unix/xserver/hw/vnc/Makefile.am 2012-09-28 13:35:59.918561641 -0400 -@@ -8,6 +8,10 @@ XREGION_LIB=$(LIB_DIR)/Xregion/libXregio - OS_LIB=$(LIB_DIR)/os/libos.la - COMMON_LIBS=$(NETWORK_LIB) $(RFB_LIB) $(RDR_LIB) $(XREGION_LIB) - -+if GLX -+GLX_LIB = $(top_srcdir)/glx/libglx.la -+endif -+ - noinst_LTLIBRARIES = libvnccommon.la - - HDRS = RegionHelper.h vncExtInit.h vncHooks.h XserverDesktop.h xorg-version.h \ -@@ -35,7 +39,8 @@ Xvnc_CPPFLAGS = $(XVNC_CPPFLAGS) -DTIGER - -UHAVE_CONFIG_H \ - -DXFree86Server -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \ - -DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(TIGERVNC_SRCDIR)/common \ -- -I$(top_srcdir)/include ${XSERVERLIBS_CFLAGS} -I$(includedir) -+ -I$(top_srcdir)/include ${XSERVERLIBS_CFLAGS} -I$(includedir) \ -+ -I$(top_srcdir)/glx - - Xvnc_LDADD = $(XVNC_LIBS) libvnccommon.la $(COMMON_LIBS) \ - $(XSERVER_LIBS) $(XSERVER_SYS_LIBS) $(XVNC_SYS_LIBS) -lX11 -@@ -56,7 +61,7 @@ libvnc_la_CPPFLAGS = $(XVNC_CPPFLAGS) -I - - libvnc_la_LDFLAGS = -module -avoid-version -Wl,-z,now - --libvnc_la_LIBADD = libvnccommon.la $(COMMON_LIBS) $(OS_LIB) -+libvnc_la_LIBADD = libvnccommon.la $(COMMON_LIBS) $(OS_LIB) $(GLX_LIB) - - EXTRA_DIST = Xvnc.man - ---- tigervnc-1.2.80-20120905svn4996/unix/xserver/hw/vnc/xvnc.cc.jx 2012-09-05 09:29:19.000000000 -0400 -+++ tigervnc-1.2.80-20120905svn4996/unix/xserver/hw/vnc/xvnc.cc 2012-09-28 13:39:41.178815125 -0400 -@@ -87,6 +87,17 @@ extern "C" { - #include "version-config.h" - #include "site.h" - #endif -+ -+#if XORG >= 113 -+#ifdef GLXEXT -+/* C++ really is the worst */ -+#define private _private -+#include "glxserver.h" -+#undef private -+#include "glx_extinit.h" -+#endif -+#endif -+ - #undef class - #undef public - } -@@ -1562,6 +1573,16 @@ static void vfbClientStateChange(Callbac +diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/xvnc.cc.glx tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/xvnc.cc +--- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/xvnc.cc.glx 2013-02-19 13:51:29.000000000 +0000 ++++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/xvnc.cc 2013-12-09 17:03:52.147179079 +0000 +@@ -1564,6 +1564,18 @@ static void vfbClientStateChange(Callbac dispatchException &= ~DE_RESET; } +#if XORG >= 113 +#ifdef GLXEXT -+static ExtensionModule vnc_glx_ext = { ++extern "C" void GlxExtensionInit(void); ++ ++static ExtensionModule glxExt = { + GlxExtensionInit, + "GLX", + &noGlxExtension @@ -68,14 +20,14 @@ diff -up tigervnc-1.2.80-20120905svn4996/unix/xserver/hw/vnc/Makefile.am.jx tige void InitOutput(ScreenInfo *screenInfo, int argc, char **argv) { -@@ -1571,6 +1592,13 @@ InitOutput(ScreenInfo *screenInfo, int a +@@ -1573,6 +1585,13 @@ InitOutput(ScreenInfo *screenInfo, int a int i; int NumFormats = 0; +#if XORG >= 113 +#ifdef GLXEXT + if (serverGeneration == 1) -+ LoadExtension(&vnc_glx_ext, TRUE); ++ LoadExtension(&glxExt, TRUE); +#endif +#endif + diff --git a/SOURCES/vncserver.service b/SOURCES/vncserver.service index 3976e02..4d55de2 100644 --- a/SOURCES/vncserver.service +++ b/SOURCES/vncserver.service @@ -34,10 +34,12 @@ Description=Remote desktop service (VNC) After=syslog.target network.target [Service] -Type=simple +Type=forking # Clean any existing files in /tmp/.X11-unix environment ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :' -ExecStart=/sbin/runuser -l -c "/usr/bin/vncserver -fg %i" +ExecStart=/sbin/runuser -l -c "/usr/bin/vncserver %i" +PIDFile=/home//.vnc/%H%i.pid +ExecStop=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :' [Install] WantedBy=multi-user.target diff --git a/SPECS/tigervnc.spec b/SPECS/tigervnc.spec index 5dbdb90..659aa18 100644 --- a/SPECS/tigervnc.spec +++ b/SPECS/tigervnc.spec @@ -2,7 +2,7 @@ Name: tigervnc Version: 1.2.80 -Release: 0.20.%{snap}%{?dist} +Release: 0.30.%{snap}%{?dist} Summary: A TigerVNC remote display system Group: User Interface/Desktops @@ -49,6 +49,11 @@ Patch16: tigervnc-setcursor-crash.patch Patch17: tigervnc-manpages.patch Patch18: tigervnc-shebang.patch Patch19: tigervnc-1.3.0-xserver-1.15.patch +Patch20: tigervnc-zrle-crash.patch +Patch21: tigervnc-cursor.patch +Patch22: tigervnc-input.patch +Patch23: tigervnc-xstartup.patch +Patch24: tigervnc-CVE-2014-0011.patch %description Virtual Network Computing (VNC) is a remote display system which @@ -173,6 +178,21 @@ popd # source compatibility with xserver 1.15 %patch19 -p1 -b .115 +# Avoid invalid read when ZRLE connection closed (upstream bug #133). +%patch20 -p1 -b .zrle-crash + +# Fixed viewer crash when cursor has not been set (bug #1051333). +%patch21 -p1 -b .cursor + +# Use keyboard input code from tigervnc-1.3.0 (bug #1053536). +%patch22 -p1 -b .input + +# Clearer xstartup file (bug #923655). +%patch23 -p1 -b .xstartup + +# Fixed heap-based buffer overflow (CVE-2014-0011, bug #1050928). +%patch24 -p1 -b .CVE-2014-0011 + %build %ifarch sparcv9 sparc64 s390 s390x export CFLAGS="$RPM_OPT_FLAGS -fPIC" @@ -342,6 +362,36 @@ fi %{_datadir}/icons/hicolor/*/apps/* %changelog +* Mon Mar 10 2014 Tim Waugh - 1.2.80-0.30.20130314svn5065 +- Fixed heap-based buffer overflow (CVE-2014-0011, bug #1050928). + +* Tue Feb 18 2014 Tim Waugh - 1.2.80-0.29.20130314svn5065 +- Previous patch was not applied. + +* Mon Feb 10 2014 Tim Waugh - 1.2.80-0.28.20130314svn5065 +- Clearer xstartup file (bug #923655). + +* Tue Jan 28 2014 Tim Waugh - 1.2.80-0.27.20130314svn5065 +- Use keyboard input code from tigervnc-1.3.0 (bug #1053536). + +* Fri Jan 24 2014 Daniel Mach - 1.2.80-0.26.20130314svn5065 +- Mass rebuild 2014-01-24 + +* Fri Jan 10 2014 Tim Waugh - 1.2.80-0.25.20130314svn5065 +- Fixed viewer crash when cursor has not been set (bug #1051333). + +* Fri Dec 27 2013 Daniel Mach - 1.2.80-0.24.20130314svn5065 +- Mass rebuild 2013-12-27 + +* Thu Dec 12 2013 Tim Waugh 1.2.80-0.23.20130314svn5065 +- Avoid invalid read when ZRLE connection closed (bug #1039926). + +* Tue Dec 10 2013 Tim Waugh 1.2.80-0.22.20130314svn5065 +- Fixed GLX initialisation (bug #1039126). + +* Tue Nov 19 2013 Tim Waugh 1.2.80-0.21.20130314svn5065 +- Better fix for PIDFile problem (bug #1031625). + * Fri Nov 08 2013 Adam Jackson 1.2.80-0.20.20130314svn5065 - Rebuild against xserver 1.15RC1