diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..27a84a4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/tigervnc-1.2.80-20130314svn5065.tar.bz2
diff --git a/.tigervnc.metadata b/.tigervnc.metadata
new file mode 100644
index 0000000..afeeeab
--- /dev/null
+++ b/.tigervnc.metadata
@@ -0,0 +1 @@
+581d9ec01dee4602c554ef1d2ae8434d9ea53774 SOURCES/tigervnc-1.2.80-20130314svn5065.tar.bz2
diff --git a/README.md b/README.md
deleted file mode 100644
index 0e7897f..0000000
--- a/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-The master branch has no content
- 
-Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6
- 
-If you find this file in a distro specific branch, it means that no content has been checked in yet
diff --git a/SOURCES/10-libvnc.conf b/SOURCES/10-libvnc.conf
new file mode 100644
index 0000000..a053a7d
--- /dev/null
+++ b/SOURCES/10-libvnc.conf
@@ -0,0 +1,19 @@
+# This file contains configuration of libvnc.so module
+#
+# To get libvnc.so module working, do this:
+# 1. run "vncpasswd" from tigervnc-server package as root user
+# 2. uncomment configuration lines below
+#
+# Please note you can specify any option which Xvnc accepts.
+# Refer to `Xvnc -help` output for detailed list of options.
+
+#Section "Module"
+#    Load "vnc"
+#EndSection
+
+#Section "Screen"
+#    Identifier "Screen0
+#    DefaultDepth 16
+#    Option "SecurityTypes" "VncAuth"
+#    Option "PasswordFile" "/root/.vnc/passwd"
+#EndSection
diff --git a/SOURCES/tigervnc-1.3.0-xserver-1.15.patch b/SOURCES/tigervnc-1.3.0-xserver-1.15.patch
new file mode 100644
index 0000000..d070a70
--- /dev/null
+++ b/SOURCES/tigervnc-1.3.0-xserver-1.15.patch
@@ -0,0 +1,15 @@
+diff -up tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h.jx tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h
+--- tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h.jx	2013-07-01 08:41:24.000000000 -0400
++++ tigervnc-1.3.0/unix/xserver/hw/vnc/xorg-version.h	2013-11-07 11:39:49.749992669 -0500
+@@ -44,8 +44,10 @@
+ #define XORG 113
+ #elif XORG_VERSION_CURRENT < ((1 * 10000000) + (14 * 100000) + (99 * 1000))
+ #define XORG 114
++#elif XORG_VERSION_CURRENT < ((1 * 10000000) + (15 * 100000) + (99 * 1000))
++#define XORG 115
+ #else
+-#error "X.Org newer than 1.14 is not supported"
++#error "X.Org newer than 1.15 is not supported"
+ #endif
+ 
+ #endif
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 <stdio.h>
+ #include <rdr/InStream.h>
+ #include <rdr/ZlibInStream.h>
+-#include <assert.h>
++#include <rfb/Exception.h>
+ 
+ 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-cookie.patch b/SOURCES/tigervnc-cookie.patch
new file mode 100644
index 0000000..c066a5f
--- /dev/null
+++ b/SOURCES/tigervnc-cookie.patch
@@ -0,0 +1,37 @@
+diff -up tigervnc-1.0.90-20091221svn3929/unix/vncserver.cookie tigervnc-1.0.90-20091221svn3929/unix/vncserver
+--- tigervnc-1.0.90-20091221svn3929/unix/vncserver.cookie	2009-11-12 11:39:54.000000000 +0100
++++ tigervnc-1.0.90-20091221svn3929/unix/vncserver	2009-12-21 16:15:01.907799091 +0100
+@@ -189,27 +189,12 @@ $vncPort = 5900 + $displayNumber;
+ $desktopLog = "$vncUserDir/$host:$displayNumber.log";
+ unlink($desktopLog);
+ 
+-# Make an X server cookie - use /dev/urandom on systems that have it,
+-# otherwise use perl's random number generator, seeded with the sum
+-# of the current time, our PID and part of the encrypted form of the password.
+-
+-my $cookie = "";
+-if (open(URANDOM, '<', '/dev/urandom')) {
+-  my $randata;
+-  if (sysread(URANDOM, $randata, 16) == 16) {
+-    $cookie = unpack 'h*', $randata;
+-  }
+-  close(URANDOM);
+-}
+-if ($cookie eq "") {
+-  srand(time+$$+unpack("L",`cat $vncUserDir/passwd`));
+-  for (1..16) {
+-    $cookie .= sprintf("%02x", int(rand(256)) % 256);
+-  }
+-}
+-
+-system("xauth -f $xauthorityFile add $host:$displayNumber . $cookie");
+-system("xauth -f $xauthorityFile add $host/unix:$displayNumber . $cookie"); 
++# Make an X server cookie - use mcookie
++$cookie = `/usr/bin/mcookie`;
++open (XAUTH, "|xauth -f $xauthorityFile source -");
++print XAUTH "add $host:$displayNumber . $cookie\n";
++print XAUTH "add $host/unix:$displayNumber . $cookie\n";
++close XAUTH;
+ 
+ if ($opt{'-name'}) {
+     $desktopName = $opt{'-name'};
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-inetd-nowait.patch b/SOURCES/tigervnc-inetd-nowait.patch
new file mode 100644
index 0000000..89b3d19
--- /dev/null
+++ b/SOURCES/tigervnc-inetd-nowait.patch
@@ -0,0 +1,53 @@
+diff -up tigervnc-1.2.80-20130314svn5065/common/network/TcpSocket.cxx.inetd-nowait tigervnc-1.2.80-20130314svn5065/common/network/TcpSocket.cxx
+--- tigervnc-1.2.80-20130314svn5065/common/network/TcpSocket.cxx.inetd-nowait	2013-05-23 12:20:35.836386218 +0100
++++ tigervnc-1.2.80-20130314svn5065/common/network/TcpSocket.cxx	2013-05-23 12:23:04.698003213 +0100
+@@ -325,18 +325,12 @@ bool TcpSocket::cork(int sock, bool enab
+ #endif
+ }
+ 
+-bool TcpSocket::isSocket(int sock)
++bool TcpSocket::isListening(int sock)
+ {
+-  struct sockaddr_in info;
+-  socklen_t info_size = sizeof(info);
+-  return getsockname(sock, (struct sockaddr *)&info, &info_size) >= 0;
+-}
+-
+-bool TcpSocket::isConnected(int sock)
+-{
+-  struct sockaddr_in info;
+-  socklen_t info_size = sizeof(info);
+-  return getpeername(sock, (struct sockaddr *)&info, &info_size) >= 0;
++  int listening = 0;
++  socklen_t listening_size = sizeof(listening);
++  return getsockopt(sock, SOL_SOCKET, SO_ACCEPTCONN, &listening,
++                    &listening_size) >= 0 && listening;
+ }
+ 
+ int TcpSocket::getSockPort(int sock)
+diff -up tigervnc-1.2.80-20130314svn5065/common/network/TcpSocket.h.inetd-nowait tigervnc-1.2.80-20130314svn5065/common/network/TcpSocket.h
+--- tigervnc-1.2.80-20130314svn5065/common/network/TcpSocket.h.inetd-nowait	2013-05-23 12:20:35.835386220 +0100
++++ tigervnc-1.2.80-20130314svn5065/common/network/TcpSocket.h	2013-05-23 12:21:58.861730647 +0100
+@@ -57,8 +57,7 @@ namespace network {
+ 
+     static bool enableNagles(int sock, bool enable);
+     static bool cork(int sock, bool enable);
+-    static bool isSocket(int sock);
+-    static bool isConnected(int sock);
++    static bool isListening(int sock);
+     static int getSockPort(int sock);
+   private:
+     bool closeFd;
+diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/vncExtInit.cc.inetd-nowait tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/vncExtInit.cc
+--- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/vncExtInit.cc.inetd-nowait	2013-03-14 17:11:22.000000000 +0000
++++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/vncExtInit.cc	2013-05-23 12:21:10.545530308 +0100
+@@ -225,8 +225,7 @@ void vncExtensionInit()
+         network::TcpListener* listener = 0;
+         network::TcpListener* httpListener = 0;
+         if (scr == 0 && vncInetdSock != -1) {
+-          if (network::TcpSocket::isSocket(vncInetdSock) &&
+-              !network::TcpSocket::isConnected(vncInetdSock))
++          if (network::TcpSocket::isListening(vncInetdSock))
+           {
+             listener = new network::TcpListener(NULL, 0, 0, vncInetdSock, true);
+             vlog.info("inetd wait");
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 <xkbsrv.h>
+-#endif
+ #if XORG >= 16
+ #include "exevents.h"
+ #endif
+@@ -58,6 +49,7 @@ CopyKeyClass(DeviceIntPtr device, Device
+ extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey;
+ #endif
+ #include <X11/keysym.h>
++#include <X11/Xlib.h>
+ #include <X11/Xutil.h>
+ #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<<i)) ?
+@@ -199,8 +176,6 @@ void InputDevice::PointerMove(const rfb:
+ 	if (pos.equals(cursorPos))
+ 		return;
+ 
+-	initInputDevice();
+-
+ 	valuators[0] = pos.x;
+ 	valuators[1] = pos.y;
+ #if XORG < 110
+@@ -287,16 +262,78 @@ static int pointerProc(DeviceIntPtr pDev
+ 	return Success;
+ }
+ 
+-void InputDevice::initInputDevice(void)
++static void keyboardBell(int percent, DeviceIntPtr device, pointer ctrl,
++			 int class_)
+ {
++	if (percent > 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<KeyCode> 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<KeyCode>::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<KeyCode>::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<KeyCode>::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<KeyCode>::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 <dix-config.h>
++#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 <xkbsrv.h>
++#endif
++/* These defines give us access to all keysyms we need */
++#define XK_PUBLISHING
++#define XK_TECHNICAL
++#include <X11/keysym.h>
++#include <X11/XF86keysym.h>
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++#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<KeyCode> InputDevice::releaseShift(void)
++{
++	std::list<KeyCode> 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<KeyCode> InputDevice::releaseLevelThree(void)
++{
++	std::list<KeyCode> 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 <dix-config.h>
+ #endif
+ 
++#include <list>
++
+ #include <rfb/VNCServerST.h>
+ 
+ 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<KeyCode> releaseShift(void);
++
++	KeyCode pressLevelThree(void);
++	std::list<KeyCode> 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 <dix-config.h>
++#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 <X11/keysym.h>
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++#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;i<type->map_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;i<type->map_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<KeyCode> InputDevice::releaseShift(void)
++{
++	unsigned state;
++	std::list<KeyCode> 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<KeyCode> InputDevice::releaseLevelThree(void)
++{
++	unsigned state, mask;
++	std::list<KeyCode> 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-manpages.patch b/SOURCES/tigervnc-manpages.patch
new file mode 100644
index 0000000..7acf128
--- /dev/null
+++ b/SOURCES/tigervnc-manpages.patch
@@ -0,0 +1,236 @@
+diff -up tigervnc-1.2.80-20130314svn5065/unix/vncserver.man.manpages tigervnc-1.2.80-20130314svn5065/unix/vncserver.man
+--- tigervnc-1.2.80-20130314svn5065/unix/vncserver.man.manpages	2013-07-03 12:44:03.820392690 +0100
++++ tigervnc-1.2.80-20130314svn5065/unix/vncserver.man	2013-07-03 12:44:44.222587028 +0100
+@@ -92,6 +92,10 @@ argument.  Thus, you can invoke "vncserv
+ end of your xstartup file after a particular application exits.
+ 
+ .TP
++.B \-list
++Lists running VNC servers.
++
++.TP
+ .B \-fp \fIfont-path\fP
+ If the vncserver script detects that the X Font Server (XFS) is running, it
+ will attempt to start Xvnc and configure Xvnc to use XFS for font handling.
+diff -up tigervnc-1.2.80-20130314svn5065/unix/vncserver.manpages tigervnc-1.2.80-20130314svn5065/unix/vncserver
+--- tigervnc-1.2.80-20130314svn5065/unix/vncserver.manpages	2013-07-03 12:39:08.754980784 +0100
++++ tigervnc-1.2.80-20130314svn5065/unix/vncserver	2013-07-03 12:43:57.932364387 +0100
+@@ -551,6 +551,7 @@ sub Usage
+ 	"                 [-geometry <width>x<height>]\n".
+ 	"                 [-pixelformat rgbNNN|bgrNNN]\n".
+ 	"                 [-fp <font-path>]\n".
++	"                 [-cc <visual>]\n".
+ 	"                 [-fg]\n".
+ 	"                 [-autokill]\n".
+ 	"                 <Xvnc-options>...\n\n".
+diff -up tigervnc-1.2.80-20130314svn5065/unix/x0vncserver/x0vncserver.cxx.manpages tigervnc-1.2.80-20130314svn5065/unix/x0vncserver/x0vncserver.cxx
+diff -up tigervnc-1.2.80-20130314svn5065/unix/x0vncserver/x0vncserver.man.manpages tigervnc-1.2.80-20130314svn5065/unix/x0vncserver/x0vncserver.man
+--- tigervnc-1.2.80-20130314svn5065/unix/x0vncserver/x0vncserver.man.manpages	2013-07-03 12:46:17.814038117 +0100
++++ tigervnc-1.2.80-20130314svn5065/unix/x0vncserver/x0vncserver.man	2013-07-03 12:58:32.814621597 +0100
+@@ -68,7 +68,13 @@ to accept connections from any IP addres
+ Specify which security scheme to use for incoming connections.  Valid values
+ are \fBNone\fP and \fBVncAuth\fP.  Default is \fBVncAuth\fP.
+ .TP
+-.B PasswordFile
++.B pam_server
++Service name for pam password validation (default is "vnc").
++.TP
++.B PlainUsers
++Users permission to access via Plain security type.
++.TP
++.B PasswordFile, rfbauth
+ Password file for VNC authentication.  There is no default, you should
+ specify the password file explicitly.  Password file should be created with
+ the \fBvncpasswd\fP(1) utility.
+@@ -113,6 +119,16 @@ Accept key press and release events from
+ .B AcceptPointerEvents
+ Accept pointer events from clients.  Default is on.
+ .TP
++.B AcceptCutText
++Accept clipboard updates from clients.  Default is on.
++.TP
++.B MaxCutText
++Maximum permitted length of an incoming clipboard update (default is
++262144).
++.TP
++.B SendCutText
++Send clipboard changes to clients.  Default is on.
++.TP
+ .B RemapKeys
+ Comma-separated list of incoming keysyms to remap.  Mappings are expressed as
+ two hex values, prefixed by \fB0x\fP, and separated by \fB->\fP (`dash' and
+@@ -154,23 +170,6 @@ clients may choose video selection thems
+ \fBVideoArea\fP parameter will take effect.  If the argument is empty, no
+ video area is set (this is the default).
+ .TP
+-.B VideoPriority
+-Specify the priority of sending video updates.  \fBx0vncserver\fP can be
+-instructed to treat certain rectangular part of the screen as a video area
+-and handle it in a special way for improved performance (see documentation on
+-the \fBVideoArea\fP parameter).  \fBVideoPriority\fP value controls how often
+-video area will be sent to clients as compared to the rest of the screen.
+-The priority must be an integer between 0 and 8, and the default value is 2.
+-
+-\fBVideoPriority\fP set to 1 gives the same priority both to video and to
+-other pixels.  Higher values give more priority to video.  For example, the
+-value 5 specifies that the rate of sending video will be five times higher
+-than the rate of updating the rest of the screen.  If \fBVideoPriority\fP is
+-set to 0, it gives equal priority to video and other updates (just like the
+-value 1) and also disables special encoding for video data.  In other words,
+-\fBVideoPriority\fP video area will be sent as a part of other screen
+-contents.
+-.TP
+ .B CompareFB
+ Perform pixel comparison on framebuffer to reduce unnecessary updates.
+ Default is on.
+@@ -185,15 +184,6 @@ This enables system-specific access to c
+ screen (the default X visual often provides 256 colors).  Also, in overlay
+ mode, \fBx0vncserver\fP can show correct mouse cursor.  Default is on.
+ .TP
+-.B UseHardwareJPEG
+-Use hardware-accelerated JPEG compressor for video if available.
+-\fBx0vncserver\fP can be instructed to treat certain rectangular part of the
+-screen as a video area and handle it in a special way for improved
+-performance.  If the client supports Tight encoding and JPEG compression,
+-such video areas will be sent as JPEG-encoded rectangles.  And if this option
+-is on, compression will be hardware-accelerated (currently, supported only in
+-SGI/IRIX equipped with appropriate hardware).  Default is on.
+-.TP
+ .B ZlibLevel
+ Zlib compression level for ZRLE encoding (it does not affect Tight encoding).
+ Acceptable values are between 0 and 9.  Default is to use the standard
+@@ -222,6 +212,18 @@ Terminate after \fIN\fP seconds of user
+ .B ClientWaitTimeMillis
+ The number of milliseconds to wait for a client which is no longer
+ responding.  Default is 20000.
++.TP
++.B DeferUpdate
++Time in milliseconds to defer updates (default is 1).
++.TP
++.B AlwaysSetDeferUpdateTimer
++Always reset the defer update timer on every change.
++.TP
++.B x509key
++Path to key of the x509 certificate in PEM format.
++.TP
++.B 509cert
++Path to x509 certificate in PEM format.
+ .SH SEE ALSO
+ .BR Xvnc (1),
+ .BR vncpasswd (1),
+diff -up tigervnc-1.2.80-20130314svn5065/vncviewer/vncviewer.cxx.manpages tigervnc-1.2.80-20130314svn5065/vncviewer/vncviewer.cxx
+--- tigervnc-1.2.80-20130314svn5065/vncviewer/vncviewer.cxx.manpages	2013-07-03 12:00:58.005856116 +0100
++++ tigervnc-1.2.80-20130314svn5065/vncviewer/vncviewer.cxx	2013-07-03 12:04:26.083023050 +0100
+@@ -261,6 +261,11 @@ static void usage(const char *programNam
+           "       %s [parameters] -listen [port] [parameters]\n",
+           programName, programName);
+   fprintf(stderr,"\n"
++	  "Options:\n\n"
++	  "  -display Xdisplay - Specifies the X display for the viewer window\n"
++	  "  -geometry geometry - Standard X position and sizing specification.\n");
++
++  fprintf(stderr,"\n"
+           "Parameters can be turned on with -<param> or off with -<param>=0\n"
+           "Parameters which take a value can be specified as "
+           "-<param> <value>\n"
+diff -up tigervnc-1.2.80-20130314svn5065/vncviewer/vncviewer.man.manpages tigervnc-1.2.80-20130314svn5065/vncviewer/vncviewer.man
+--- tigervnc-1.2.80-20130314svn5065/vncviewer/vncviewer.man.manpages	2013-07-03 11:40:48.905078300 +0100
++++ tigervnc-1.2.80-20130314svn5065/vncviewer/vncviewer.man	2013-07-03 12:00:13.116604372 +0100
+@@ -113,12 +113,53 @@ Xvnc supports reverse connections with a
+ .B vncconfig.
+ 
+ .TP
+-.B \-passwd \fIpassword-file\fP
++.B \-passwd \fIpassword-file\fP, \-PasswordFile \fIpassword-file\fP
+ If you are on a filesystem which gives you access to the password file used by
+ the server, you can specify it here to avoid typing it in.  It will usually be
+ "~/.vnc/passwd".
+ 
+ .TP
++.B \-DotWhenNoCursor
++Show the dot cursor when the server sends an invisible cursor.
++
++.TP
++.B \-PointerEventInterval
++Time in milliseconds to rate-limit successive pointer events.
++
++.TP
++.B \-ImprovedHextile
++Try harder to compress data (default).
++
++.TP
++.B \-QualityLevel \fIlevel\fP
++JPEG quality level (default is 8).
++
++.TP
++.B \-NoJPEG
++Disable lossy JPEG compression in Tight encoding.
++
++.TP
++.B CompressLevel \fIlevel\fP
++Use specified compression level (default is 2).
++
++.TP
++.B CustomCompressLevel \fIlevel\fP
++Use custom compression level. Default is CompressLevel is specified.
++
++.TP
++.B \-SendPrimary
++Send the primary selection and cut buffer to the server as well as the
++clipboard selection (default).
++
++.TP
++.B \-SendClipboard
++Send clipboard changes to the server (default).
++
++.TP
++.B \-AcceptClipboard
++Accept clipboard changes from the server (default).
++
++.TP
+ .B \-Shared
+ When you make a connection to a VNC server, all other existing connections are
+ normally closed.  This option requests that they be left open, allowing you to
+@@ -140,6 +181,19 @@ Maximize viewer window.
+ Start in full-screen mode.
+ 
+ .TP
++.B \-FullScreenAllMonitors
++Enable full screen over all monitors (default).
++
++.TP
++.B \-FullscreenSystemKeys
++Pass special keys directly to the server in full-screen mode.
++
++.TP
++.B \-RemoteResize
++Dynamically resize the remote desktop size as the size of the local
++client window changes (default).
++
++.TP
+ .B \-DesktopSize \fIwidth\fPx\fIheight\fP
+ Instead of keeping the existing remote screen size, the client will attempt to
+ switch to the specified since when connecting. If the server does not support
+@@ -214,6 +268,22 @@ command is executed with the environment
+ host, the port number on the remote host, and the gateway machine
+ respectively.
+ 
++.TP
++\fB\-ZlibLevel\fR \fIlevel\fR
++Zlib compression level.
++
++.TP
++.B \-x509crl \fIfile\fP
++X509 CRL file
++
++.TP
++.B \-x509ca \fIfile\fP
++X509 CA certificate
++
++.TP
++.B \-SecurityTypes \fItypes\fP
++Specify which security scheme to use.
++
+ .SH SEE ALSO
+ .BR Xvnc (1),
+ .BR vncpasswd (1),
diff --git a/SOURCES/tigervnc-setcursor-crash.patch b/SOURCES/tigervnc-setcursor-crash.patch
new file mode 100644
index 0000000..1efbd0e
--- /dev/null
+++ b/SOURCES/tigervnc-setcursor-crash.patch
@@ -0,0 +1,13 @@
+diff -up tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc.jx tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc
+--- tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc.jx	2012-08-27 09:02:47.000000000 -0400
++++ tigervnc-1.2.80-20130314svn5065/unix/xserver/hw/vnc/XserverDesktop.cc	2013-06-17 09:42:14.310725996 -0400
+@@ -479,6 +479,9 @@ void XserverDesktop::setCursor(CursorPtr
+       }
+     } else {
+ #endif
++      if (!cmap)
++	return;
++
+       xColorItem fg, bg;
+       fg.red   = cursor->foreRed;
+       fg.green = cursor->foreGreen;
diff --git a/SOURCES/tigervnc-shebang.patch b/SOURCES/tigervnc-shebang.patch
new file mode 100644
index 0000000..f76af87
--- /dev/null
+++ b/SOURCES/tigervnc-shebang.patch
@@ -0,0 +1,9 @@
+diff -up tigervnc-1.3.0/unix/vncserver.shebang tigervnc-1.3.0/unix/vncserver
+--- tigervnc-1.3.0/unix/vncserver.shebang	2013-07-24 12:22:34.962158378 +0100
++++ tigervnc-1.3.0/unix/vncserver	2013-07-24 12:22:41.593188190 +0100
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #
+ #  Copyright (C) 2009-2010 D. R. Commander.  All Rights Reserved.
+ #  Copyright (C) 2005-2006 Sun Microsystems, Inc.  All Rights Reserved.
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/tigervnc11-gethomedir.patch b/SOURCES/tigervnc11-gethomedir.patch
new file mode 100644
index 0000000..0a4252d
--- /dev/null
+++ b/SOURCES/tigervnc11-gethomedir.patch
@@ -0,0 +1,20 @@
+diff -up tigervnc-1.2.0/unix/xserver/hw/vnc/Makefile.am.gethomedir tigervnc-1.2.0/unix/xserver/hw/vnc/Makefile.am
+--- tigervnc-1.2.0/unix/xserver/hw/vnc/Makefile.am.gethomedir	2012-08-22 15:52:01.876216608 +0200
++++ tigervnc-1.2.0/unix/xserver/hw/vnc/Makefile.am	2012-08-22 15:52:45.973143684 +0200
+@@ -5,6 +5,7 @@ RFB_LIB=$(LIB_DIR)/rfb/librfb.la
+ RDR_LIB=$(LIB_DIR)/rdr/librdr.la
+ NETWORK_LIB=$(LIB_DIR)/network/libnetwork.la
+ XREGION_LIB=$(LIB_DIR)/Xregion/libXregion.la
++OS_LIB=$(LIB_DIR)/os/libos.la
+ COMMON_LIBS=$(NETWORK_LIB) $(RFB_LIB) $(RDR_LIB) $(XREGION_LIB)
+ 
+ noinst_LTLIBRARIES = libvnccommon.la
+@@ -55,7 +56,7 @@ libvnc_la_CPPFLAGS = $(XVNC_CPPFLAGS) -I
+ 
+ libvnc_la_LDFLAGS = -module -avoid-version -Wl,-z,now
+ 
+-libvnc_la_LIBADD = libvnccommon.la $(COMMON_LIBS)
++libvnc_la_LIBADD = libvnccommon.la $(COMMON_LIBS) $(OS_LIB)
+ 
+ EXTRA_DIST = Xvnc.man
+ 
diff --git a/SOURCES/tigervnc11-ldnow.patch b/SOURCES/tigervnc11-ldnow.patch
new file mode 100644
index 0000000..f6edd09
--- /dev/null
+++ b/SOURCES/tigervnc11-ldnow.patch
@@ -0,0 +1,12 @@
+diff -up tigervnc-1.2.0/unix/xserver/hw/vnc/Makefile.am.ldnow tigervnc-1.2.0/unix/xserver/hw/vnc/Makefile.am
+--- tigervnc-1.2.0/unix/xserver/hw/vnc/Makefile.am.ldnow	2011-10-31 09:14:40.000000000 +0100
++++ tigervnc-1.2.0/unix/xserver/hw/vnc/Makefile.am	2012-08-22 15:51:47.013241342 +0200
+@@ -53,7 +53,7 @@ libvnc_la_CPPFLAGS = $(XVNC_CPPFLAGS) -I
+ 	-I$(top_srcdir)/include \
+ 	${XSERVERLIBS_CFLAGS} -I$(includedir)
+ 
+-libvnc_la_LDFLAGS = -module -avoid-version
++libvnc_la_LDFLAGS = -module -avoid-version -Wl,-z,now
+ 
+ libvnc_la_LIBADD = libvnccommon.la $(COMMON_LIBS)
+ 
diff --git a/SOURCES/tigervnc11-rh692048.patch b/SOURCES/tigervnc11-rh692048.patch
new file mode 100644
index 0000000..924c1cf
--- /dev/null
+++ b/SOURCES/tigervnc11-rh692048.patch
@@ -0,0 +1,44 @@
+diff -up tigervnc-1.0.90-20110314svn4359/common/rfb/SecurityClient.cxx.rh690245 tigervnc-1.0.90-20110314svn4359/common/rfb/SecurityClient.cxx
+--- tigervnc-1.0.90-20110314svn4359/common/rfb/SecurityClient.cxx.rh690245	2011-02-21 14:14:16.000000000 +0100
++++ tigervnc-1.0.90-20110314svn4359/common/rfb/SecurityClient.cxx	2011-03-31 09:47:34.519099718 +0200
+@@ -45,7 +45,7 @@ StringParameter SecurityClient::secTypes
+ ("SecurityTypes",
+  "Specify which security scheme to use (None, VncAuth)",
+ #ifdef HAVE_GNUTLS
+- "X509Plain,TLSPlain,X509Vnc,TLSVnc,X509None,TLSNone,VncAuth,None",
++ "VeNCrypt,X509Plain,TLSPlain,X509Vnc,TLSVnc,X509None,TLSNone,VncAuth,None",
+ #else
+  "VncAuth,None",
+ #endif
+diff -up tigervnc-1.0.90-20110314svn4359/common/rfb/Security.cxx.rh690245 tigervnc-1.0.90-20110314svn4359/common/rfb/Security.cxx
+--- tigervnc-1.0.90-20110314svn4359/common/rfb/Security.cxx.rh690245	2011-02-21 14:14:16.000000000 +0100
++++ tigervnc-1.0.90-20110314svn4359/common/rfb/Security.cxx	2011-03-31 09:47:34.519099718 +0200
+@@ -67,7 +67,6 @@ const std::list<rdr::U8> Security::GetEn
+   list<rdr::U8> result;
+   list<U32>::iterator i;
+ 
+-  result.push_back(secTypeVeNCrypt);
+   for (i = enabledSecTypes.begin(); i != enabledSecTypes.end(); i++)
+     if (*i < 0x100)
+       result.push_back(*i);
+@@ -105,8 +104,6 @@ bool Security::IsSupported(U32 secType)
+   for (i = enabledSecTypes.begin(); i != enabledSecTypes.end(); i++)
+     if (*i == secType)
+       return true;
+-  if (secType == secTypeVeNCrypt)
+-    return true;
+ 
+   return false;
+ }
+diff -up tigervnc-1.0.90-20110314svn4359/common/rfb/SecurityServer.cxx.rh690245 tigervnc-1.0.90-20110314svn4359/common/rfb/SecurityServer.cxx
+--- tigervnc-1.0.90-20110314svn4359/common/rfb/SecurityServer.cxx.rh690245	2011-02-21 14:50:17.000000000 +0100
++++ tigervnc-1.0.90-20110314svn4359/common/rfb/SecurityServer.cxx	2011-03-31 10:06:43.595362302 +0200
+@@ -39,7 +39,7 @@ StringParameter SecurityServer::secTypes
+ ("SecurityTypes",
+  "Specify which security scheme to use (None, VncAuth)",
+ #ifdef HAVE_GNUTLS
+- "VncAuth,TLSVnc",
++ "VncAuth",
+ #else
+  "VncAuth",
+ #endif
diff --git a/SOURCES/tigervnc12-xorg113-glx.patch b/SOURCES/tigervnc12-xorg113-glx.patch
new file mode 100644
index 0000000..c5a5621
--- /dev/null
+++ b/SOURCES/tigervnc12-xorg113-glx.patch
@@ -0,0 +1,36 @@
+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
++extern "C" void GlxExtensionInit(void);
++
++static ExtensionModule glxExt = {
++    GlxExtensionInit,
++    "GLX",
++    &noGlxExtension
++};
++#endif
++#endif
++
+ void
+ InitOutput(ScreenInfo *screenInfo, int argc, char **argv)
+ {
+@@ -1573,6 +1585,13 @@ InitOutput(ScreenInfo *screenInfo, int a
+     int i;
+     int NumFormats = 0;
+ 
++#if XORG >= 113
++#ifdef GLXEXT
++    if (serverGeneration == 1)
++        LoadExtension(&glxExt, TRUE);
++#endif
++#endif
++
+     /* initialize pixmap formats */
+ 
+     /* must have a pixmap depth to match every screen depth */
diff --git a/SOURCES/vncserver.service b/SOURCES/vncserver.service
new file mode 100644
index 0000000..4d55de2
--- /dev/null
+++ b/SOURCES/vncserver.service
@@ -0,0 +1,45 @@
+# The vncserver service unit file
+#
+# Quick HowTo:
+# 1. Copy this file to /etc/systemd/system/vncserver@:<display>.service
+# 2. Edit <USER> and vncserver parameters appropriately
+#   ("runuser -l <USER> -c /usr/bin/vncserver %i -arg1 -arg2")
+# 3. Run `systemctl daemon-reload`
+# 4. Run `systemctl enable vncserver@:<display>.service`
+#
+# DO NOT RUN THIS SERVICE if your local area network is
+# untrusted!  For a secure way of using VNC, you should
+# limit connections to the local host and then tunnel from
+# the machine you want to view VNC on (host A) to the machine
+# whose VNC output you want to view (host B)
+#
+# [user@hostA ~]$ ssh -v -C -L 590N:localhost:590M hostB
+#
+# this will open a connection on port 590N of your hostA to hostB's port 590M
+# (in fact, it ssh-connects to hostB and then connects to localhost (on hostB).
+# See the ssh man page for details on port forwarding)
+#
+# You can then point a VNC client on hostA at vncdisplay N of localhost and with
+# the help of ssh, you end up seeing what hostB makes available on port 590M
+#
+# Use "-nolisten tcp" to prevent X connections to your VNC server via TCP.
+#
+# Use "-localhost" to prevent remote VNC clients connecting except when
+# doing so through a secure tunnel.  See the "-via" option in the
+# `man vncviewer' manual page.
+
+
+[Unit]
+Description=Remote desktop service (VNC)
+After=syslog.target network.target
+
+[Service]
+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 <USER> -c "/usr/bin/vncserver %i"
+PIDFile=/home/<USER>/.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/SOURCES/vncserver.sysconfig b/SOURCES/vncserver.sysconfig
new file mode 100644
index 0000000..4d0489b
--- /dev/null
+++ b/SOURCES/vncserver.sysconfig
@@ -0,0 +1 @@
+# THIS FILE HAS BEEN REPLACED BY /lib/systemd/system/vncserver@.service
diff --git a/SOURCES/vncviewer.desktop b/SOURCES/vncviewer.desktop
new file mode 100644
index 0000000..fab46f0
--- /dev/null
+++ b/SOURCES/vncviewer.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Name=TigerVNC Viewer
+Name[fr]=Visionneur TigerVNC
+Comment=Connect to VNC server and display remote desktop
+Comment[fr]=Se connecter à un serveur VNC et afficher le bureau distant
+Exec=/usr/bin/vncviewer
+Icon=tigervnc
+Terminal=false
+Type=Application
+StartupWMClass=TigerVNC Viewer: Connection Details
+Categories=Network;RemoteAccess;
diff --git a/SPECS/tigervnc.spec b/SPECS/tigervnc.spec
new file mode 100644
index 0000000..f046a6f
--- /dev/null
+++ b/SPECS/tigervnc.spec
@@ -0,0 +1,775 @@
+%global		snap 20130314svn5065
+
+Name:		tigervnc
+Version:	1.2.80
+Release:	0.31.%{snap}%{?dist}
+Summary:	A TigerVNC remote display system
+
+Group:		User Interface/Desktops
+License:	GPLv2+
+URL:		http://www.tigervnc.com
+
+Source0:	%{name}-%{version}-%{snap}.tar.bz2
+Source1:	vncserver.service
+Source2:	vncserver.sysconfig
+Source3:	10-libvnc.conf
+Source6:	vncviewer.desktop
+BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+BuildRequires:	libX11-devel, automake, autoconf, libtool, gettext, gettext-autopoint
+BuildRequires:	libXext-devel, xorg-x11-server-source, libXi-devel
+BuildRequires:	xorg-x11-xtrans-devel, xorg-x11-util-macros, libXtst-devel
+BuildRequires:	libdrm-devel, libXt-devel, pixman-devel libXfont-devel
+BuildRequires:	libxkbfile-devel, openssl-devel, libpciaccess-devel
+BuildRequires:	mesa-libGL-devel, libXinerama-devel, ImageMagick
+BuildRequires:  freetype-devel, libXdmcp-devel
+BuildRequires:	desktop-file-utils, java-devel, jpackage-utils
+BuildRequires:	libjpeg-turbo-devel, gnutls-devel, pam-devel
+BuildRequires:	systemd, cmake, fltk-devel
+
+Requires(post):	coreutils
+Requires(postun):coreutils
+
+Requires:	hicolor-icon-theme
+Requires:	tigervnc-license
+Requires:	tigervnc-icons
+
+Provides:	vnc = 4.1.3-2, vnc-libs = 4.1.3-2
+Obsoletes:	vnc < 4.1.3-2, vnc-libs < 4.1.3-2
+Provides:	tightvnc = 1.5.0-0.15.20090204svn3586
+Obsoletes:	tightvnc < 1.5.0-0.15.20090204svn3586
+
+Patch4:		tigervnc-cookie.patch
+Patch10:	tigervnc11-ldnow.patch
+Patch11:	tigervnc11-gethomedir.patch
+Patch13:	tigervnc11-rh692048.patch
+Patch14:	tigervnc12-xorg113-glx.patch
+Patch15:	tigervnc-inetd-nowait.patch
+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
+allows you to view a computing 'desktop' environment not only on the
+machine where it is running, but from anywhere on the Internet and
+from a wide variety of machine architectures.  This package contains a
+client which will allow you to connect to other desktops running a VNC
+server.
+
+%package server
+Summary:	A TigerVNC server
+Group:		User Interface/X
+Provides:	vnc-server = 4.1.3-2, vnc-libs = 4.1.3-2
+Obsoletes:	vnc-server < 4.1.3-2, vnc-libs < 4.1.3-2
+Provides:	tightvnc-server = 1.5.0-0.15.20090204svn3586
+Obsoletes:	tightvnc-server < 1.5.0-0.15.20090204svn3586
+Requires:	perl
+Requires:	tigervnc-server-minimal
+Requires:	xorg-x11-xauth
+Requires:	xorg-x11-xinit
+Requires(post): systemd
+Requires(preun): systemd
+Requires(postun): systemd
+Requires(post):	systemd-sysv chkconfig
+
+%description server
+The VNC system allows you to access the same desktop from a wide
+variety of platforms.  This package includes set of utilities
+which make usage of TigerVNC server more user friendly. It also
+contains x0vncserver program which can export your active
+X session.
+
+%package server-minimal
+Summary:	A minimal installation of TigerVNC server
+Group:		User Interface/X
+Requires(post):	chkconfig
+Requires(preun):chkconfig
+Requires(preun):initscripts
+Requires(postun):initscripts
+
+Requires:	mesa-dri-drivers, xkeyboard-config, xorg-x11-xkb-utils
+Requires:	tigervnc-license
+
+%description server-minimal
+The VNC system allows you to access the same desktop from a wide
+variety of platforms. This package contains minimal installation
+of TigerVNC server, allowing others to access the desktop on your
+machine.
+
+%ifnarch s390 s390x
+%package server-module
+Summary:	TigerVNC module to Xorg
+Group:		User Interface/X
+Provides:	vnc-server = 4.1.3-2, vnc-libs = 4.1.3-2
+Obsoletes:	vnc-server < 4.1.3-2, vnc-libs < 4.1.3-2
+Provides:	tightvnc-server-module = 1.5.0-0.15.20090204svn3586
+Obsoletes:	tightvnc-server-module < 1.5.0-0.15.20090204svn3586
+Requires:	xorg-x11-server-Xorg
+Requires:	tigervnc-license
+
+%description server-module
+This package contains libvnc.so module to X server, allowing others
+to access the desktop on your machine.
+%endif
+
+%package server-applet
+Summary:	Java TigerVNC viewer applet for TigerVNC server
+Group:		User Interface/X
+Requires:	tigervnc-server, java, jpackage-utils
+BuildArch:	noarch
+
+%description server-applet
+The Java TigerVNC viewer applet for web browsers. Install this package to allow
+clients to use web browser when connect to the TigerVNC server.
+
+%package license
+Summary:	License of TigerVNC suite
+Group:		User Interface/X
+BuildArch:	noarch
+
+%description license
+This package contains license of the TigerVNC suite
+
+%package icons
+Summary:	Icons for TigerVNC viewer
+Group:		User Interface/X
+BuildArch:	noarch
+
+%description icons
+This package contains icons for TigerVNC viewer
+
+%prep
+%setup -q -n %{name}-%{version}-%{snap}
+
+%patch4 -p1 -b .cookie
+%patch10 -p1 -b .ldnow
+%patch11 -p1 -b .gethomedir
+%patch13 -p1 -b .rh692048
+
+cp -r /usr/share/xorg-x11-server-source/* unix/xserver
+pushd unix/xserver
+for all in `find . -type f -perm -001`; do
+	chmod -x "$all"
+done
+patch -p1 -b --suffix .vnc < ../xserver114.patch
+popd
+
+%patch14 -p1 -b .glx
+
+# Applied Debian patch to fix busy loop when run from inetd in nowait
+# mode (bug #920373).
+%patch15 -p1 -b .inetd-nowait
+
+%patch16 -p1 -b .setcursor-crash
+
+# Synchronise manpages and --help output (bug #980870).
+%patch17 -p1 -b .manpages
+
+# Don't use shebang in vncserver script.
+%patch18 -p1 -b .shebang
+
+# 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"
+%else
+export CFLAGS="$RPM_OPT_FLAGS -fpic"
+%endif
+export CXXFLAGS="$CFLAGS"
+
+%{cmake} .
+make %{?_smp_mflags}
+
+pushd unix/xserver
+autoreconf -fiv
+%configure \
+	--disable-xorg --disable-xnest --disable-xvfb --disable-dmx \
+	--disable-xwin --disable-xephyr --disable-kdrive --with-pic \
+	--disable-static --disable-xinerama \
+	--with-default-font-path="catalogue:%{_sysconfdir}/X11/fontpath.d,built-ins" \
+	--with-fontdir=%{_datadir}/X11/fonts \
+	--with-xkb-output=%{_localstatedir}/lib/xkb \
+	--enable-install-libxf86config \
+	--enable-glx --disable-dri --enable-dri2 \
+	--disable-wayland \
+	--disable-present \
+	--disable-config-dbus \
+	--disable-config-hal \
+	--disable-config-udev \
+	--with-dri-driver-path=%{_libdir}/dri \
+	--without-dtrace \
+	--disable-unit-tests \
+	--disable-devel-docs \
+	--disable-selective-werror
+
+make %{?_smp_mflags}
+popd
+
+# Build icons
+pushd media
+make
+popd
+
+# Build Java applet
+pushd java
+%{cmake} .
+make
+popd
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+
+pushd unix/xserver/hw/vnc
+make install DESTDIR=$RPM_BUILD_ROOT
+popd
+
+# Install systemd unit file
+mkdir -p %{buildroot}%{_unitdir}
+install -m644 %{SOURCE1} %{buildroot}%{_unitdir}/vncserver@.service
+rm -rf %{buildroot}%{_initrddir}
+
+mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig
+install -m644 %{SOURCE2} $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/vncservers
+
+# Install desktop stuff
+mkdir -p $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/{16x16,24x24,48x48}/apps
+
+pushd media/icons
+for s in 16 24 48; do
+install -m644 tigervnc_$s.png $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/${s}x$s/apps/tigervnc.png
+done
+popd
+
+mkdir $RPM_BUILD_ROOT%{_datadir}/applications
+desktop-file-install \
+	--dir $RPM_BUILD_ROOT%{_datadir}/applications \
+	%{SOURCE6}
+
+# Install Java applet
+pushd java
+mkdir -p $RPM_BUILD_ROOT%{_datadir}/vnc/classes
+install -m755 VncViewer.jar $RPM_BUILD_ROOT%{_datadir}/vnc/classes
+install -m644 com/tigervnc/vncviewer/index.vnc $RPM_BUILD_ROOT%{_datadir}/vnc/classes
+popd
+
+%find_lang %{name} %{name}.lang
+
+# remove unwanted files
+rm -f  $RPM_BUILD_ROOT%{_libdir}/xorg/modules/extensions/libvnc.la
+
+%ifarch s390 s390x
+rm -f $RPM_BUILD_ROOT%{_libdir}/xorg/modules/extensions/libvnc.so
+%else
+mkdir -p %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/
+install -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf
+%endif
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+touch -c %{_datadir}/icons/hicolor
+if [ -x %{_bindir}/gtk-update-icon-cache ]; then
+	%{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor || :
+fi
+
+%postun
+touch -c %{_datadir}/icons/hicolor
+if [ -x %{_bindir}/gtk-update-icon-cache ]; then
+	%{_bindir}/gtk-update-icon-cache -q %{_datadir}/icons/hicolor || :
+fi
+
+%post server
+%systemd_post vncserver.service
+
+%triggerun -- tigervnc-server < 1.0.90-6
+%{_bindir}/systemd-sysv-convert --save vncserver >/dev/null 2>&1 ||:
+/sbin/chkconfig --del vncserver >/dev/null 2>&1 || :
+
+%preun server
+%systemd_preun vncserver.service
+
+%postun server
+%systemd_postun
+
+%files -f %{name}.lang
+%defattr(-,root,root,-)
+%doc README.txt
+%{_bindir}/vncviewer
+%{_datadir}/applications/*
+%{_mandir}/man1/vncviewer.1*
+
+%files server
+%defattr(-,root,root,-)
+%config(noreplace) %{_sysconfdir}/sysconfig/vncservers
+%{_unitdir}/vncserver@.service
+%{_bindir}/x0vncserver
+%{_bindir}/vncserver
+%{_mandir}/man1/vncserver.1*
+%{_mandir}/man1/x0vncserver.1*
+
+%files server-minimal
+%defattr(-,root,root,-)
+%{_bindir}/vncconfig
+%{_bindir}/vncpasswd
+%{_bindir}/Xvnc
+%{_mandir}/man1/Xvnc.1*
+%{_mandir}/man1/vncpasswd.1*
+%{_mandir}/man1/vncconfig.1*
+
+%ifnarch s390 s390x
+%files server-module
+%defattr(-,root,root,-)
+%{_libdir}/xorg/modules/extensions/libvnc.so
+%config %{_sysconfdir}/X11/xorg.conf.d/10-libvnc.conf
+%endif
+
+%files server-applet
+%defattr(-,root,root,-)
+%doc java/com/tigervnc/vncviewer/README
+%{_datadir}/vnc/classes/*
+
+%files license
+%doc LICENCE.TXT
+
+%files icons
+%defattr(-,root,root,-)
+%{_datadir}/icons/hicolor/*/apps/*
+
+%changelog
+* Tue Sep 23 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.31.20130314svn5065
+- Rebuilt against xorg-x11-server to pick up ppc64le fix (bug #1140424).
+
+* Mon Mar 10 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.30.20130314svn5065
+- Fixed heap-based buffer overflow (CVE-2014-0011, bug #1050928).
+
+* Tue Feb 18 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.29.20130314svn5065
+- Previous patch was not applied.
+
+* Mon Feb 10 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.28.20130314svn5065
+- Clearer xstartup file (bug #923655).
+
+* Tue Jan 28 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.27.20130314svn5065
+- Use keyboard input code from tigervnc-1.3.0 (bug #1053536).
+
+* Fri Jan 24 2014 Daniel Mach <dmach@redhat.com> - 1.2.80-0.26.20130314svn5065
+- Mass rebuild 2014-01-24
+
+* Fri Jan 10 2014 Tim Waugh <twaugh@redhat.com> - 1.2.80-0.25.20130314svn5065
+- Fixed viewer crash when cursor has not been set (bug #1051333).
+
+* Fri Dec 27 2013 Daniel Mach <dmach@redhat.com> - 1.2.80-0.24.20130314svn5065
+- Mass rebuild 2013-12-27
+
+* Thu Dec 12 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.23.20130314svn5065
+- Avoid invalid read when ZRLE connection closed (bug #1039926).
+
+* Tue Dec 10 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.22.20130314svn5065
+- Fixed GLX initialisation (bug #1039126).
+
+* Tue Nov 19 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.21.20130314svn5065
+- Better fix for PIDFile problem (bug #1031625).
+
+* Fri Nov 08 2013 Adam Jackson <ajax@redhat.com> 1.2.80-0.20.20130314svn5065
+- Rebuild against xserver 1.15RC1
+
+* Wed Jul 24 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.18.20130314svn5065
+- Avoid PIDFile problems in systemd unit file (bug #983232).
+- Don't use shebang in vncserver script.
+
+* Wed Jul  3 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.18.20130314svn5065
+- Removed systemd_requires macro in order to fix the build.
+
+* Wed Jul  3 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.17.20130314svn5065
+- Synchronise manpages and --help output (bug #980870).
+
+* Mon Jun 17 2013 Adam Jackson <ajax@redhat.com> 1.2.80-0.16.20130314svn5065
+- tigervnc-setcursor-crash.patch: Attempt to paper over a crash in Xvnc when
+  setting the cursor.
+
+* Sat Jun 08 2013 Dennis Gilmore <dennis@ausil.us> 1.2.80-0.15.20130314svn5065
+- bump to rebuild and pick up bugfix causing X to crash on ppc and arm
+
+* Thu May 23 2013 Tim Waugh <twaugh@redhat.com> 1.2.80-0.14.20130314svn5065
+- Use systemd rpm macros (bug #850340).  Moved systemd requirements
+  from main package to server sub-package.
+- Applied Debian patch to fix busy loop when run from inetd in nowait
+  mode (bug #920373).
+- Added dependency on xorg-x11-xinit to server sub-package so that
+  default window manager can be found (bug #896284, bug #923655).
+- Fixed bogus changelog date.
+
+* Thu Mar 14 2013 Adam Jackson <ajax@redhat.com> 1.2.80-0.13.20130314svn5065
+- Less RHEL customization
+
+* Thu Mar 14 2013 Adam Tkac <atkac redhat com> - 1.2.80-0.12.20130314svn5065
+- include /etc/X11/xorg.conf.d/10-libvnc.conf sample configuration (#712482)
+- vncserver now honors specified -geometry parameter (#755947)
+
+* Tue Mar 12 2013 Adam Tkac <atkac redhat com> - 1.2.80-0.11.20130307svn5060
+- update to r5060
+- split icons to separate package to avoid multilib issues
+
+* Tue Feb 19 2013 Adam Tkac <atkac redhat com> - 1.2.80-0.10.20130219svn5047
+- update to r5047 (X.Org 1.14 support)
+
+* Fri Feb 15 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.2.80-0.9.20121126svn5015
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
+
+* Mon Jan 21 2013 Adam Tkac <atkac redhat com> - 1.2.80-0.8.20121126svn5015
+- rebuild due to "jpeg8-ABI" feature drop
+
+* Wed Jan 16 2013 Adam Tkac <atkac redhat com> 1.2.80-0.7.20121126svn5015
+- rebuild
+
+* Tue Dec 04 2012 Adam Tkac <atkac redhat com> 1.2.80-0.6.20121126svn5015
+- rebuild against new fltk
+
+* Mon Nov 26 2012 Adam Tkac <atkac redhat com> 1.2.80-0.5.20121126svn5015
+- update to r5015
+- build with -fpic instead of -fPIC on all archs except s390/sparc
+
+* Wed Nov  7 2012 Peter Robinson <pbrobinson@fedoraproject.org> 1.2.80-0.4.20120905svn4996
+- Build with -fPIC to fix FTBFS on ARM
+
+* Wed Oct 31 2012 Adam Jackson <ajax@redhat.com> 1.2.80-0.3.20120905svn4996
+- tigervnc12-xorg113-glx.patch: Fix to only init glx on the first server
+  generation
+
+* Fri Sep 28 2012 Adam Jackson <ajax@redhat.com> 1.2.80-0.2.20120905svn4996
+- tigervnc12-xorg113-glx.patch: Re-enable GLX against xserver 1.13
+
+* Fri Aug 17 2012 Adam Tkac <atkac redhat com> 1.2.80-0.1.20120905svn4996
+- update to 1.2.80
+- remove deprecated patches
+  - tigervnc-102434.patch
+  - tigervnc-viewer-reparent.patch
+  - tigervnc11-java7.patch
+- patches merged
+  - tigervnc11-xorg111.patch
+  - tigervnc11-xorg112.patch
+
+* Fri Aug 10 2012 Dave Airlie <airlied@redhat.com> 1.1.0-10
+- fix build against newer X server
+
+* Mon Jul 23 2012 Adam Jackson <ajax@redhat.com> 1.1.0-9
+- Build with the Composite extension for feature parity with other X servers
+
+* Sat Jul 21 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.1.0-8
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Thu Jul 19 2012 Dave Airlie <airlied@redhat.com> 1.1.0-7
+- fix building against X.org 1.13
+
+* Wed Apr 04 2012 Adam Jackson <ajax@redhat.com> 1.1.0-6
+- RHEL exclusion for -server-module on ppc* too
+
+* Mon Mar 26 2012 Adam Tkac <atkac redhat com> - 1.1.0-5
+- clean Xvnc's /tmp environment in service file before startup
+- fix building against the latest JAVA 7 and X.Org 1.12
+
+* Sat Jan 14 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.1.0-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Tue Nov 22 2011 Adam Tkac <atkac redhat com> - 1.1.0-3
+- don't build X.Org devel docs (#755782)
+- applet: BR generic java-devel instead of java-gcj-devel (#755783)
+- use runuser to start Xvnc in systemd service file (#754259)
+- don't attepmt to restart Xvnc session during update/erase (#753216)
+
+* Fri Nov 11 2011 Adam Tkac <atkac redhat com> - 1.1.0-2
+- libvnc.so: don't use unexported GetMaster function (#744881)
+- remove nasm buildreq
+
+* Mon Sep 12 2011 Adam Tkac <atkac redhat com> - 1.1.0-1
+- update to 1.1.0
+- update the xorg11 patch
+- patches merged
+  - tigervnc11-glx.patch
+  - tigervnc11-CVE-2011-1775.patch
+  - 0001-Use-memmove-instead-of-memcpy-in-fbblt.c-when-memory.patch
+
+* Thu Jul 28 2011 Adam Tkac <atkac redhat com> - 1.0.90-6
+- add systemd service file and remove legacy SysV initscript (#717227)
+
+* Thu May 12 2011 Adam Tkac <atkac redhat com> - 1.0.90-5
+- make Xvnc buildable against X.Org 1.11
+
+* Tue May 10 2011 Adam Tkac <atkac redhat com> - 1.0.90-4
+- viewer can send password without proper validation of X.509 certs
+  (CVE-2011-1775)
+
+* Wed Apr 13 2011 Adam Tkac <atkac redhat com> - 1.0.90-3
+- fix wrong usage of memcpy which caused screen artifacts (#652590)
+- don't point to inaccessible link in sysconfig/vncservers (#644975)
+
+* Fri Apr 08 2011 Adam Tkac <atkac redhat com> - 1.0.90-2
+- improve compatibility with vinagre client (#692048)
+
+* Tue Mar 22 2011 Adam Tkac <atkac redhat com> - 1.0.90-1
+- update to 1.0.90
+
+* Wed Feb 09 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.0.90-0.32.20110117svn4237
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Mon Jan 17 2011 Adam Tkac <atkac redhat com> 1.0.90-0.31.20110117svn4237
+- fix libvnc.so module loading
+
+* Mon Jan 17 2011 Adam Tkac <atkac redhat com> 1.0.90-0.30.20110117svn4237
+- update to r4237
+- patches merged
+  - tigervnc11-optionsdialog.patch
+  - tigervnc11-rh607866.patch
+
+* Fri Jan 14 2011 Adam Tkac <atkac redhat com> 1.0.90-0.29.20101208svn4225
+- improve patch for keyboard issues
+
+* Fri Jan 14 2011 Adam Tkac <atkac redhat com> 1.0.90-0.28.20101208svn4225
+- attempt to fix various keyboard-related issues (key repeating etc)
+
+* Fri Jan 07 2011 Adam Tkac <atkac redhat com> 1.0.90-0.27.20101208svn4225
+- render "Ok" and "Cancel" buttons in the options dialog correctly
+
+* Wed Dec 15 2010 Jan Görig <jgorig redhat com> 1.0.90-0.26.20101208svn4225
+- added vncserver lock file (#662784)
+
+* Fri Dec 10 2010 Adam Tkac <atkac redhat com> 1.0.90-0.25.20101208svn4225
+- update to r4225
+- patches merged
+  - tigervnc11-rh611677.patch
+  - tigervnc11-rh633931.patch
+  - tigervnc11-xorg1.10.patch
+- enable VeNCrypt and PAM support
+
+* Mon Dec 06 2010 Adam Tkac <atkac redhat com> 1.0.90-0.24.20100813svn4123
+- rebuild against xserver 1.10.X
+- 0001-Return-Success-from-generate_modkeymap-when-max_keys.patch merged
+
+* Wed Sep 29 2010 jkeating - 1.0.90-0.23.20100813svn4123
+- Rebuilt for gcc bug 634757
+
+* Tue Sep 21 2010 Adam Tkac <atkac redhat com> 1.0.90-0.22.20100420svn4030
+- drop xorg-x11-fonts-misc dependency (#636170)
+
+* Tue Sep 21 2010 Adam Tkac <atkac redhat com> 1.0.90-0.21.20100420svn4030
+- improve patch for #633645 (fix tcsh incompatibilities)
+
+* Thu Sep 16 2010 Adam Tkac <atkac redhat com> 1.0.90-0.20.20100813svn4123
+- press fake modifiers correctly (#633931)
+- supress unneeded debug information emitted from initscript (#633645)
+
+* Wed Aug 25 2010 Adam Tkac <atkac redhat com> 1.0.90-0.19.20100813svn4123
+- separate Xvnc, vncpasswd and vncconfig to -server-minimal subpkg (#626946)
+- move license to separate subpkg and Requires it from main subpkgs
+- Xvnc: handle situations when no modifiers exist well (#611677)
+
+* Fri Aug 13 2010 Adam Tkac <atkac redhat com> 1.0.90-0.18.20100813svn4123
+- update to r4123 (#617973)
+- add perl requires to -server subpkg (#619791)
+
+* Thu Jul 22 2010 Adam Tkac <atkac redhat com> 1.0.90-0.17.20100721svn4113
+- update to r4113
+- patches merged
+  - tigervnc11-rh586406.patch
+  - tigervnc11-libvnc.patch
+  - tigervnc11-rh597172.patch
+  - tigervnc11-rh600070.patch
+  - tigervnc11-options.patch
+- don't own %%{_datadir}/icons directory (#614301)
+- minor improvements in the .desktop file (#616340)
+- bundled libjpeg configure requires nasm; is executed even if system-wide
+  libjpeg is used
+
+* Fri Jul 02 2010 Adam Tkac <atkac redhat com> 1.0.90-0.16.20100420svn4030
+- build against system-wide libjpeg-turbo (#494458)
+- build no longer requires nasm
+
+* Mon Jun 28 2010 Adam Tkac <atkac redhat com> 1.0.90-0.15.20100420svn4030
+- vncserver: accept <+optname> option when specified as the first one
+
+* Thu Jun 24 2010 Adam Tkac <atkac redhat com> 1.0.90-0.14.20100420svn4030
+- fix memory leak in Xvnc input code (#597172)
+- don't crash when receive negative encoding (#600070)
+- explicitly disable udev configuration support
+- add gettext-autopoint to BR
+
+* Mon Jun 14 2010 Adam Tkac <atkac redhat com> 1.0.90-0.13.20100420svn4030
+- update URL about SSH tunneling in the sysconfig file (#601996)
+
+* Fri Jun 11 2010 Adam Tkac <atkac redhat com> 1.0.90-0.12.20100420svn4030
+- use newer gettext
+- autopoint now uses git instead of cvs, adjust BuildRequires appropriately
+
+* Thu May 13 2010 Adam Tkac <atkac redhat com> 1.0.90-0.11.20100420svn4030
+- link libvnc.so "now" to catch "undefined symbol" errors during Xorg startup
+- use always XkbConvertCase instead of XConvertCase (#580159, #586406)
+- don't link libvnc.so against libXi.la, libdix.la and libxkb.la; use symbols
+  from Xorg instead
+
+* Thu May 13 2010 Adam Tkac <atkac redhat com> 1.0.90-0.10.20100420svn4030
+- update to r4030 snapshot
+- patches merged to upstream
+  - tigervnc11-rh522369.patch
+  - tigervnc11-rh551262.patch
+  - tigervnc11-r4002.patch
+  - tigervnc11-r4014.patch
+
+* Thu Apr 08 2010 Adam Tkac <atkac redhat com> 1.0.90-0.9.20100219svn3993
+- add server-applet subpackage which contains Java vncviewer applet
+- fix Java applet; it didn't work when run from web browser
+- add xorg-x11-xkb-utils to server Requires
+
+* Fri Mar 12 2010 Adam Tkac <atkac redhat com> 1.0.90-0.8.20100219svn3993
+- add French translation to vncviewer.desktop (thanks to Alain Portal)
+
+* Thu Mar 04 2010 Adam Tkac <atkac redhat com> 1.0.90-0.7.20100219svn3993
+- don't crash during pixel format change (#522369, #551262)
+
+* Mon Mar 01 2010 Adam Tkac <atkac redhat com> 1.0.90-0.6.20100219svn3993
+- add mesa-dri-drivers and xkeyboard-config to -server Requires
+- update to r3993 1.0.90 snapshot
+  - tigervnc11-noexecstack.patch merged
+  - tigervnc11-xorg18.patch merged
+  - xserver18.patch is no longer needed
+
+* Wed Jan 27 2010 Jan Gorig <jgorig redhat com> 1.0.90-0.5.20091221svn3929
+- initscript LSB compliance fixes (#523974)
+
+* Fri Jan 22 2010 Adam Tkac <atkac redhat com> 1.0.90-0.4.20091221svn3929
+- mark stack as non-executable in jpeg ASM code
+- add xorg-x11-xauth to Requires
+- add support for X.Org 1.8
+- drop shave sources, they are no longer needed
+
+* Thu Jan 21 2010 Adam Tkac <atkac redhat com> 1.0.90-0.3.20091221svn3929
+- drop tigervnc-xorg25909.patch, it has been merged to X.Org upstream
+
+* Thu Jan 07 2010 Adam Tkac <atkac redhat com> 1.0.90-0.2.20091221svn3929
+- add patch for upstream X.Org issue #25909
+- add libXdmcp-devel to build requires to build Xvnc with XDMCP support (#552322)
+
+* Mon Dec 21 2009 Adam Tkac <atkac redhat com> 1.0.90-0.1.20091221svn3929
+- update to 1.0.90 snapshot
+- patches merged
+  - tigervnc10-compat.patch
+  - tigervnc10-rh510185.patch
+  - tigervnc10-rh524340.patch
+  - tigervnc10-rh516274.patch
+
+* Mon Oct 26 2009 Adam Tkac <atkac redhat com> 1.0.0-3
+- create Xvnc keyboard mapping before first keypress (#516274)
+
+* Thu Oct 08 2009 Adam Tkac <atkac redhat com> 1.0.0-2
+- update underlying X source to 1.6.4-0.3.fc11
+- remove bogus '-nohttpd' parameter from /etc/sysconfig/vncservers (#525629)
+- initscript LSB compliance fixes (#523974)
+- improve -LowColorSwitch documentation and handling (#510185)
+- honor dotWhenNoCursor option (and it's changes) every time (#524340)
+
+* Fri Aug 28 2009 Adam Tkac <atkac redhat com> 1.0.0-1
+- update to 1.0.0
+- tigervnc10-rh495457.patch merged to upstream
+
+* Mon Aug 24 2009 Karsten Hopp <karsten@redhat.com> 0.0.91-0.17
+- fix ifnarch s390x for server-module
+
+* Fri Aug 21 2009 Tomas Mraz <tmraz@redhat.com> - 0.0.91-0.16
+- rebuilt with new openssl
+
+* Tue Aug 04 2009 Adam Tkac <atkac redhat com> 0.0.91-0.15
+- make Xvnc compilable
+
+* Sun Jul 26 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.0.91-0.14.1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
+
+* Mon Jul 13 2009 Adam Tkac <atkac redhat com> 0.0.91-0.13.1
+- don't write warning when initscript is called with condrestart param (#508367)
+
+* Tue Jun 23 2009 Adam Tkac <atkac redhat com> 0.0.91-0.13
+- temporary use F11 Xserver base to make Xvnc compilable
+- BuildRequires: libXi-devel
+- don't ship tigervnc-server-module on s390/s390x
+
+* Mon Jun 22 2009 Adam Tkac <atkac redhat com> 0.0.91-0.12
+- fix local rendering of cursor (#495457)
+
+* Thu Jun 18 2009 Adam Tkac <atkac redhat com> 0.0.91-0.11
+- update to 0.0.91 (1.0.0 RC1)
+- patches merged
+  - tigervnc10-rh499401.patch
+  - tigervnc10-rh497592.patch
+  - tigervnc10-rh501832.patch
+- after discusion in upstream drop tigervnc-bounds.patch
+- configure flags cleanup
+
+* Thu May 21 2009 Adam Tkac <atkac redhat com> 0.0.90-0.10
+- rebuild against 1.6.1.901 X server (#497835)
+- disable i18n, vncviewer is not UTF-8 compatible (#501832)
+
+* Mon May 18 2009 Adam Tkac <atkac redhat com> 0.0.90-0.9
+- fix vncpasswd crash on long passwords (#499401)
+- start session dbus daemon correctly (#497592)
+
+* Mon May 11 2009 Adam Tkac <atkac redhat com> 0.0.90-0.8.1
+- remove merged tigervnc-manminor.patch
+
+* Tue May 05 2009 Adam Tkac <atkac redhat com> 0.0.90-0.8
+- update to 0.0.90
+
+* Thu Apr 30 2009 Adam Tkac <atkac redhat com> 0.0.90-0.7.20090427svn3789
+- server package now requires xorg-x11-fonts-misc (#498184)
+
+* Mon Apr 27 2009 Adam Tkac <atkac redhat com> 0.0.90-0.6.20090427svn3789
+- update to r3789
+  - tigervnc-rh494801.patch merged
+- tigervnc-newfbsize.patch is no longer needed
+- fix problems when vncviewer and Xvnc run on different endianess (#496653)
+- UltraVNC and TightVNC clients work fine again (#496786)
+
+* Wed Apr 08 2009 Adam Tkac <atkac redhat com> 0.0.90-0.5.20090403svn3751
+- workaround broken fontpath handling in vncserver script (#494801)
+
+* Fri Apr 03 2009 Adam Tkac <atkac redhat com> 0.0.90-0.4.20090403svn3751
+- update to r3751
+- patches merged
+  - tigervnc-xclients.patch
+  - tigervnc-clipboard.patch
+  - tigervnc-rh212985.patch
+- basic RandR support in Xvnc (resize of the desktop)
+- use built-in libjpeg (SSE2/MMX accelerated encoding on x86 platform)
+- use Tight encoding by default
+- use TigerVNC icons
+
+* Tue Mar 03 2009 Adam Tkac <atkac redhat com> 0.0.90-0.3.20090303svn3631
+- update to r3631
+
+* Tue Mar 03 2009 Adam Tkac <atkac redhat com> 0.0.90-0.2.20090302svn3621
+- package review related fixes
+
+* Mon Mar 02 2009 Adam Tkac <atkac redhat com> 0.0.90-0.1.20090302svn3621
+- initial package, r3621