]> source.dussan.org Git - tigervnc.git/commitdiff
Restructure Xvnc/libvnc.so code to avoid C++ header hacks
authorPierre Ossman <ossman@cendio.se>
Mon, 26 Jan 2015 13:37:04 +0000 (14:37 +0100)
committerPierre Ossman <ossman@cendio.se>
Mon, 26 Jan 2015 14:14:33 +0000 (15:14 +0100)
The internal Xorg headers are very incompatible with C++ and we've had
to resort to all kinds of hacks in order to include them in our C++
code. This approach isn't really viable long term so restructure things
so that we have a glue layer written in C that bridges the Xorg core
with the RFB classes.

31 files changed:
common/rfb/ServerCore.cxx
common/rfb/ServerCore.h
common/rfb/VNCSConnectionST.cxx
common/rfb/VNCSConnectionST.h
unix/xserver/hw/vnc/Input.c [new file with mode: 0644]
unix/xserver/hw/vnc/Input.cc [deleted file]
unix/xserver/hw/vnc/Input.h
unix/xserver/hw/vnc/InputCore.c [new file with mode: 0644]
unix/xserver/hw/vnc/InputCore.cc [deleted file]
unix/xserver/hw/vnc/InputXKB.c [new file with mode: 0644]
unix/xserver/hw/vnc/InputXKB.cc [deleted file]
unix/xserver/hw/vnc/Makefile.am
unix/xserver/hw/vnc/RFBGlue.cc [new file with mode: 0644]
unix/xserver/hw/vnc/RFBGlue.h [new file with mode: 0644]
unix/xserver/hw/vnc/RegionHelper.h [deleted file]
unix/xserver/hw/vnc/XorgGlue.c [new file with mode: 0644]
unix/xserver/hw/vnc/XorgGlue.h [new file with mode: 0644]
unix/xserver/hw/vnc/XserverDesktop.cc
unix/xserver/hw/vnc/XserverDesktop.h
unix/xserver/hw/vnc/vncBlockHandler.c [new file with mode: 0644]
unix/xserver/hw/vnc/vncBlockHandler.h [new file with mode: 0644]
unix/xserver/hw/vnc/vncExt.c [new file with mode: 0644]
unix/xserver/hw/vnc/vncExtInit.cc
unix/xserver/hw/vnc/vncExtInit.h
unix/xserver/hw/vnc/vncHooks.c [new file with mode: 0644]
unix/xserver/hw/vnc/vncHooks.cc [deleted file]
unix/xserver/hw/vnc/vncHooks.h
unix/xserver/hw/vnc/vncModule.c [new file with mode: 0644]
unix/xserver/hw/vnc/xf86vncModule.cc [deleted file]
unix/xserver/hw/vnc/xvnc.c [new file with mode: 0644]
unix/xserver/hw/vnc/xvnc.cc [deleted file]

index b11a352a9ad55046c1388562711d12b7b5871be8..6e221d5397855ca1aba1d85d57ea97a5e0c91704 100644 (file)
@@ -97,4 +97,8 @@ rfb::BoolParameter rfb::Server::queryConnect
 ("QueryConnect",
  "Prompt the local user to accept or reject incoming connections.",
  false);
-
+rfb::IntParameter rfb::Server::queryConnectTimeout
+("QueryConnectTimeout",
+ "Number of seconds to show the Accept Connection dialog before "
+ "rejecting the connection",
+ 10);
index 5fc996ff1b6244dcf76f5c929ac05f465cd3e5c7..c4d7d5379f87e115e0792a28b6452b1b1acd1eca 100644 (file)
@@ -48,6 +48,7 @@ namespace rfb {
     static BoolParameter sendCutText;
     static BoolParameter acceptSetDesktopSize;
     static BoolParameter queryConnect;
+    static IntParameter queryConnectTimeout;
 
   };
 
index e30b4f429d0b7038e21923b7f443f1cf247abb0d..746bb9019d320f22d035ab9df968e7f646845cc4 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright 2009-2014 Pierre Ossman for Cendio AB
+ * Copyright 2009-2015 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
@@ -66,7 +66,8 @@ struct RTTInfo {
 
 VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
                                    bool reverse)
-  : SConnection(reverse), sock(s), inProcessMessages(false),
+  : SConnection(reverse), sock(s),
+    queryConnectTimer(this), inProcessMessages(false),
     pendingSyncFence(false), syncFence(false), fenceFlags(0),
     fenceDataLen(0), fenceData(NULL),
     baseRTT(-1), minRTT(-1), seenCongestion(false), pingCounter(0),
@@ -434,8 +435,10 @@ void VNCSConnectionST::queryConnection(const char* userName)
   CharArray reason;
   VNCServerST::queryResult qr = server->queryConnection(sock, userName,
                                                         &reason.buf);
-  if (qr == VNCServerST::PENDING)
+  if (qr == VNCServerST::PENDING) {
+    queryConnectTimer.start(rfb::Server::queryConnectTimeout * 1000);
     return;
+  }
 
   // - If server returns ACCEPT/REJECT then pass result to SConnection
   approveConnection(qr == VNCServerST::ACCEPT, reason.buf);
@@ -714,6 +717,10 @@ bool VNCSConnectionST::handleTimeout(Timer* t)
       writeFramebufferUpdate();
     else if (t == &congestionTimer)
       updateCongestion();
+    else if (t == &queryConnectTimer) {
+      if (state() == RFBSTATE_QUERYING)
+        approveConnection(false, "The attempt to prompt the user to accept the connection failed");
+    }
   } catch (rdr::Exception& e) {
     close(e.str());
   }
index fd1897a628ddf1b86022cdba1a2f2a0e4fd5c98d..7b25570de61008ed6b63b2097c45c5c59b868f28 100644 (file)
@@ -174,6 +174,8 @@ namespace rfb {
     network::Socket* sock;
     CharArray peerEndpoint;
 
+    Timer queryConnectTimer;
+
     bool inProcessMessages;
 
     bool pendingSyncFence, syncFence;
diff --git a/unix/xserver/hw/vnc/Input.c b/unix/xserver/hw/vnc/Input.c
new file mode 100644 (file)
index 0000000..db9bf66
--- /dev/null
@@ -0,0 +1,691 @@
+/* Copyright (C) 2009 TightVNC Team
+ * Copyright (C) 2009, 2014 Red Hat, Inc.
+ * Copyright 2013-2015 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 "xorg-version.h"
+
+#include "Input.h"
+#include "vncExtInit.h"
+
+#include "inputstr.h"
+#if XORG >= 110
+#include "inpututils.h"
+#endif
+#include "mi.h"
+#if XORG >= 16
+#include "exevents.h"
+#endif
+#if XORG == 16
+extern void
+CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master);
+#endif
+#if XORG >= 17
+#include "xkbsrv.h"
+#include "xkbstr.h"
+#include "xserver-properties.h"
+extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey;
+#endif
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#define BUTTONS 7
+
+/* Event queue is shared between all devices. */
+#if XORG == 15
+static xEvent *eventq = NULL;
+#elif XORG < 111
+static EventList *eventq = NULL;
+#endif
+
+DeviceIntPtr vncKeyboardDev;
+DeviceIntPtr vncPointerDev;
+
+static int oldButtonMask;
+static int cursorPosX, cursorPosY;
+
+static KeySym pressedKeys[256];
+
+#if XORG < 17
+extern void vncGetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap);
+#endif
+
+static int vncPointerProc(DeviceIntPtr pDevice, int onoff);
+static void vncKeyboardBell(int percent, DeviceIntPtr device,
+                            void * ctrl, int class);
+static int vncKeyboardProc(DeviceIntPtr pDevice, int onoff);
+
+#define LOG_NAME "Input"
+
+#define LOG_ERROR(...) vncLogError(LOG_NAME, __VA_ARGS__)
+#define LOG_STATUS(...) vncLogStatus(LOG_NAME, __VA_ARGS__)
+#define LOG_INFO(...) vncLogInfo(LOG_NAME, __VA_ARGS__)
+#define LOG_DEBUG(...) vncLogDebug(LOG_NAME, __VA_ARGS__)
+
+/*
+ * Init input device.
+ * This has to be called after core pointer/keyboard
+ * initialization which unfortunately is after extesions
+ * initialization (which means we cannot call it in
+ * vncExtensionInit(). Check InitExtensions(),
+ * InitCoreDevices() and InitInput() calls in dix/main.c.
+ * Instead we call it from XserverDesktop at an appropriate
+ * time.
+ */
+void vncInitInputDevice(void)
+{
+       int i, ret;
+
+       if ((vncPointerDev != NULL) || (vncKeyboardDev != NULL))
+               return;
+
+       for (i = 0;i < 256;i++)
+               pressedKeys[i] = NoSymbol;
+
+#if XORG < 17
+       vncPointerDev = AddInputDevice(
+#if XORG >= 16
+                                   serverClient,
+#endif
+                                   vncPointerProc, TRUE);
+       RegisterPointerDevice(vncPointerDev);
+
+       vncKeyboardDev = AddInputDevice(
+#if XORG >= 16
+                                    serverClient,
+#endif
+                                    vncKeyboardProc, TRUE);
+       RegisterKeyboardDevice(vncKeyboardDev);
+
+       if (ActivateDevice(vncPointerDev) != Success ||
+           ActivateDevice(vncKeyboardDev) != Success)
+               FatalError("Failed to activate TigerVNC devices\n");
+
+       if (!EnableDevice(vncPointerDev) ||
+           !EnableDevice(vncKeyboardDev))
+               FatalError("Failed to enable TigerVNC devices\n");
+#else /* < 17 */
+       ret = AllocDevicePair(serverClient, "TigerVNC",
+                             &vncPointerDev, &vncKeyboardDev,
+                             vncPointerProc, vncKeyboardProc,
+                             FALSE);
+
+       if (ret != Success)
+               FatalError("Failed to initialize TigerVNC input devices\n");
+
+       if (ActivateDevice(vncPointerDev, TRUE) != Success ||
+           ActivateDevice(vncKeyboardDev, TRUE) != Success)
+               FatalError("Failed to activate TigerVNC devices\n");
+
+       if (!EnableDevice(vncPointerDev, TRUE) ||
+           !EnableDevice(vncKeyboardDev, TRUE))
+               FatalError("Failed to activate TigerVNC devices\n");
+#endif /* 17 */
+
+#if XORG < 111
+       /* eventq is never free()-ed because it exists during server life. */
+       if (eventq == NULL) {
+#if XORG == 15
+               eventq = (xEvent *)xcalloc(sizeof(xEvent),
+                                          GetMaximumEventsNum());
+               if (!eventq)
+                       FatalError("Couldn't allocate eventq\n");
+#else
+               GetEventList(&eventq);
+#endif
+       }
+#endif
+
+       vncPrepareInputDevices();
+}
+
+void vncPointerButtonAction(int buttonMask)
+{
+       int i;
+#if XORG < 111
+       int n;
+#endif
+#if XORG >= 110
+       ValuatorMask mask;
+#endif
+
+       for (i = 0; i < BUTTONS; i++) {
+               if ((buttonMask ^ oldButtonMask) & (1 << i)) {
+                       int action = (buttonMask & (1<<i)) ?
+                                    ButtonPress : ButtonRelease;
+#if XORG < 110
+                       n = GetPointerEvents(eventq, vncPointerDev,
+                                            action, i + 1,
+                                            POINTER_RELATIVE, 0, 0, NULL);
+                       enqueueEvents(vncPointerDev, n);
+#elif XORG < 111
+                       valuator_mask_set_range(&mask, 0, 0, NULL);
+                       n = GetPointerEvents(eventq, vncPointerDev,
+                                            action, i + 1,
+                                            POINTER_RELATIVE, &mask);
+                       enqueueEvents(vncPointerDev, n);
+#else
+                       valuator_mask_set_range(&mask, 0, 0, NULL);
+                       QueuePointerEvents(vncPointerDev, action, i + 1,
+                                          POINTER_RELATIVE, &mask);
+#endif
+               }
+       }
+
+       oldButtonMask = buttonMask;
+}
+
+void vncPointerMove(int x, int y)
+{
+       int valuators[2];
+#if XORG < 111
+       int n;
+#endif
+#if XORG >= 110
+       ValuatorMask mask;
+#endif
+
+       if (cursorPosX == x && cursorPosY == y)
+               return;
+
+       valuators[0] = x;
+       valuators[1] = y;
+#if XORG < 110
+       n = GetPointerEvents(eventq, vncPointerDev, MotionNotify, 0,
+                            POINTER_ABSOLUTE, 0, 2, valuators);
+       enqueueEvents(vncPointerDev, n);
+#elif XORG < 111
+       valuator_mask_set_range(&mask, 0, 2, valuators);
+       n = GetPointerEvents(eventq, vncPointerDev, MotionNotify, 0,
+                            POINTER_ABSOLUTE, &mask);
+       enqueueEvents(vncPointerDev, n);
+#else
+       valuator_mask_set_range(&mask, 0, 2, valuators);
+       QueuePointerEvents(vncPointerDev, MotionNotify, 0,
+                          POINTER_ABSOLUTE, &mask);
+#endif
+
+       cursorPosX = x;
+       cursorPosY = y;
+}
+
+void vncGetPointerPos(int *x, int *y)
+{
+       if (vncPointerDev != NULL)
+               GetSpritePosition(vncPointerDev, &cursorPosX, &cursorPosY);
+
+       *x = cursorPosX;
+       *y = cursorPosY;
+}
+
+#if XORG < 111
+static void enqueueEvents(DeviceIntPtr dev, int n)
+{
+       int i;
+
+       for (i = 0; i < n; i++) {
+               /*
+                * Passing arguments in global variable eventq is probably not
+                * good programming practise but in this case it is safe and
+                * clear.
+                */
+               mieqEnqueue(dev,
+#if XORG == 15
+                           eventq + i
+#elif XORG == 16
+                           (eventq + i)->event
+#else
+                           (InternalEvent *) (eventq + i)->event
+#endif
+                          );
+       }
+}
+#endif /* XORG < 111 */
+
+static int vncPointerProc(DeviceIntPtr pDevice, int onoff)
+{
+       BYTE map[BUTTONS + 1];
+       DevicePtr pDev = (DevicePtr)pDevice;
+       int i;
+#if XORG >= 17
+       /*
+        * NOTE: map[] array is one element longer than btn_labels[] array. This
+        * is not a bug.
+        */
+       Atom btn_labels[BUTTONS];
+       Atom axes_labels[2];
+#endif
+
+       switch (onoff) {
+       case DEVICE_INIT:
+               for (i = 0; i < BUTTONS + 1; i++)
+                       map[i] = i;
+
+#if XORG >= 17
+               btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
+               btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
+               btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
+               btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
+               btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
+               btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
+               btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
+
+               axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
+               axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
+#endif
+
+               InitPointerDeviceStruct(pDev, map, BUTTONS,
+#if XORG == 15
+                                       GetMotionHistory,
+#elif XORG >= 17
+                                       btn_labels,
+#endif
+                                       (PtrCtrlProcPtr)NoopDDA,
+                                       GetMotionHistorySize(), 2
+#if XORG >= 17
+                                       , axes_labels
+#endif
+                                       );
+               break;
+       case DEVICE_ON:
+               pDev->on = TRUE;
+               break;
+       case DEVICE_OFF:
+               pDev->on = FALSE;
+               break;
+       case DEVICE_CLOSE:
+               vncPointerDev = NULL;
+               break;
+       }
+
+       return Success;
+}
+
+static void vncKeyboardBell(int percent, DeviceIntPtr device,
+                            void * ctrl, int class)
+{
+       if (percent > 0)
+               vncBell();
+}
+
+static int vncKeyboardProc(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
+               vncGetInitKeyboardMap(&keySyms, modMap);
+#endif
+               InitKeyboardDeviceStruct(
+#if XORG >= 17
+                                        pDevice, NULL,
+#else
+                                        pDev, &keySyms, modMap,
+#endif
+                                        vncKeyboardBell,
+                                        (KbdCtrlProcPtr)NoopDDA);
+               break;
+       case DEVICE_ON:
+               pDev->on = TRUE;
+               break;
+       case DEVICE_OFF:
+               pDev->on = FALSE;
+               break;
+       case DEVICE_CLOSE:
+               vncKeyboardDev = NULL;
+               break;
+       }
+
+       return Success;
+}
+
+static inline void pressKey(DeviceIntPtr dev, int kc, Bool down, const char *msg)
+{
+       int action;
+#if XORG < 111
+       unsigned int n;
+#endif
+
+       if (msg != NULL)
+               LOG_DEBUG("%s %d %s", msg, kc, down ? "down" : "up");
+
+       action = down ? KeyPress : KeyRelease;
+#if XORG < 111
+       n = GetKeyboardEvents(eventq, dev, action, kc);
+       enqueueEvents(dev, n);
+#else
+       QueueKeyboardEvents(dev, action, kc, NULL);
+#endif
+}
+
+/* altKeysym is a table of alternative keysyms which have the same meaning. */
+
+static struct altKeysym_t {
+       KeySym a, b;
+} altKeysym[] = {
+       { XK_Shift_L,           XK_Shift_R },
+       { XK_Control_L,         XK_Control_R },
+       { XK_Meta_L,            XK_Meta_R },
+       { XK_Alt_L,             XK_Alt_R },
+       { XK_Super_L,           XK_Super_R },
+       { XK_Hyper_L,           XK_Hyper_R },
+       { XK_KP_Space,          XK_space },
+       { XK_KP_Tab,            XK_Tab },
+       { XK_KP_Enter,          XK_Return },
+       { XK_KP_F1,             XK_F1 },
+       { XK_KP_F2,             XK_F2 },
+       { XK_KP_F3,             XK_F3 },
+       { XK_KP_F4,             XK_F4 },
+       { XK_KP_Home,           XK_Home },
+       { XK_KP_Left,           XK_Left },
+       { XK_KP_Up,             XK_Up },
+       { XK_KP_Right,          XK_Right },
+       { XK_KP_Down,           XK_Down },
+       { XK_KP_Page_Up,        XK_Page_Up },
+       { XK_KP_Page_Down,      XK_Page_Down },
+       { XK_KP_End,            XK_End },
+       { XK_KP_Begin,          XK_Begin },
+       { XK_KP_Insert,         XK_Insert },
+       { XK_KP_Delete,         XK_Delete },
+       { XK_KP_Equal,          XK_equal },
+       { XK_KP_Multiply,       XK_asterisk },
+       { XK_KP_Add,            XK_plus },
+       { XK_KP_Separator,      XK_comma },
+       { XK_KP_Subtract,       XK_minus },
+       { XK_KP_Decimal,        XK_period },
+       { XK_KP_Divide,         XK_slash },
+       { XK_KP_0,              XK_0 },
+       { XK_KP_1,              XK_1 },
+       { XK_KP_2,              XK_2 },
+       { XK_KP_3,              XK_3 },
+       { XK_KP_4,              XK_4 },
+       { XK_KP_5,              XK_5 },
+       { XK_KP_6,              XK_6 },
+       { XK_KP_7,              XK_7 },
+       { XK_KP_8,              XK_8 },
+       { XK_KP_9,              XK_9 },
+       { XK_ISO_Level3_Shift,  XK_Mode_switch },
+};
+
+/*
+ * vncKeyboardEvent() - work out the best keycode corresponding to the keysym
+ * sent by 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.
+ */
+void vncKeyboardEvent(KeySym keysym, int down)
+{
+       int i;
+       unsigned state, new_state;
+       KeyCode keycode;
+
+       unsigned level_three_mask;
+       KeyCode shift_press, level_three_press;
+       KeyCode shift_release[8], level_three_release[8];
+       size_t shift_release_count, level_three_release_count;
+
+       /*
+        * 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(vncKeyboardDev, i, FALSE, "keycode");
+                               mieqProcessInputEvents();
+                               return;
+                       }
+               }
+
+               /*
+                * This can happen quite often as we ignore some
+                * key presses.
+                */
+               LOG_DEBUG("Unexpected release of keysym 0x%x", keysym);
+               return;
+       }
+
+       /* 
+        * Since we are checking the current state to determine if we need
+        * to fake modifiers, we must make sure that everything put on the
+        * input queue is processed before we start. Otherwise, shift may be
+        * stuck down.
+        */ 
+       mieqProcessInputEvents();
+
+       state = vncGetKeyboardState();
+
+       keycode = vncKeysymToKeycode(keysym, state, &new_state);
+
+       /* 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;
+
+                       keycode = vncKeysymToKeycode(altsym, state, &new_state);
+                       if (keycode != 0)
+                               break;
+               }
+       }
+
+       /* We don't have lock synchronisation... */
+       if (vncIsLockModifier(keycode, new_state)) {
+               LOG_DEBUG("Ignoring lock key (e.g. caps lock)");
+               return;
+       }
+
+       /* No matches. Will have to add a new entry... */
+       if (keycode == 0) {
+               keycode = vncAddKeysym(keysym, state);
+               if (keycode == 0) {
+                       LOG_ERROR("Failure adding new keysym 0x%x", keysym);
+                       return;
+               }
+
+               LOG_INFO("Added unknown keysym 0x%x to keycode %d",
+                        keysym, keycode);
+
+               /*
+                * The state given to addKeysym() is just a hint and
+                * the actual result might still require some state
+                * changes.
+                */
+               keycode = vncKeysymToKeycode(keysym, state, &new_state);
+               if (keycode == 0) {
+                       LOG_ERROR("Newly added keysym 0x%x cannot be generated", keysym);
+                       return;
+               }
+       }
+
+       /*
+        * 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)) &&
+           vncGetAvoidShiftNumLock() && vncIsAffectedByNumLock(keycode)) {
+               KeyCode keycode2;
+               unsigned new_state2;
+
+               LOG_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;
+
+                       keycode2 = vncKeysymToKeycode(altsym, state, &new_state2);
+                       if (keycode2 == 0)
+                               continue;
+
+                       if (((state & ShiftMask) != (new_state2 & ShiftMask)) &&
+                           vncIsAffectedByNumLock(keycode2))
+                               continue;
+
+                       break;
+               }
+
+               if (i == sizeof(altKeysym)/sizeof(altKeysym[0]))
+                       LOG_DEBUG("No alternative keysym found");
+               else {
+                       keycode = keycode2;
+                       new_state = new_state2;
+               }
+       }
+
+       /*
+        * "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 (keysym == XK_Tab && (state & ShiftMask))
+               new_state |= ShiftMask;
+
+       /*
+        * We need a bigger state change than just shift,
+        * so we need to know what the mask is for level 3 shifts.
+        */
+       if ((new_state & ~ShiftMask) != (state & ~ShiftMask))
+               level_three_mask = vncGetLevelThreeMask();
+       else
+               level_three_mask = 0;
+
+       shift_press = level_three_press = 0;
+       shift_release_count = level_three_release_count = 0;
+
+       /* Need a fake press or release of shift? */
+       if (!(state & ShiftMask) && (new_state & ShiftMask)) {
+               shift_press = vncPressShift();
+               if (shift_press == 0) {
+                       LOG_ERROR("Unable to find a modifier key for Shift");
+                       return;
+               }
+
+               pressKey(vncKeyboardDev, shift_press, TRUE, "temp shift");
+       } else if ((state & ShiftMask) && !(new_state & ShiftMask)) {
+               shift_release_count = vncReleaseShift(shift_release,
+                                                     sizeof(shift_release)/sizeof(*shift_release));
+               if (shift_release_count == 0) {
+                       LOG_ERROR("Unable to find the modifier key(s) for releasing Shift");
+                       return;
+               }
+
+               for (i = 0;i < shift_release_count;i++)
+                       pressKey(vncKeyboardDev, shift_release[i], FALSE, "temp shift");
+       }
+
+       /* Need a fake press or release of level three shift? */
+       if (!(state & level_three_mask) && (new_state & level_three_mask)) {
+               level_three_press = vncPressLevelThree();
+               if (level_three_press == 0) {
+                       LOG_ERROR("Unable to find a modifier key for ISO_Level3_Shift/Mode_Switch");
+                       return;
+               }
+
+               pressKey(vncKeyboardDev, level_three_press, TRUE, "temp level 3 shift");
+       } else if ((state & level_three_mask) && !(new_state & level_three_mask)) {
+               level_three_release_count = vncReleaseLevelThree(level_three_release,
+                                                                sizeof(level_three_release)/sizeof(*level_three_release));
+               if (level_three_release_count == 0) {
+                       LOG_ERROR("Unable to find the modifier key(s) for releasing ISO_Level3_Shift/Mode_Switch");
+                       return;
+               }
+
+               for (i = 0;i < level_three_release_count;i++)
+                       pressKey(vncKeyboardDev, level_three_release[i], FALSE, "temp level 3 shift");
+       }
+
+       /* Now press the actual key */
+       pressKey(vncKeyboardDev, keycode, TRUE, "keycode");
+
+       /* 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) {
+                       LOG_ERROR("Keysym 0x%x generated by both keys %d and %d", keysym, i, keycode);
+                       pressedKeys[i] = NoSymbol;
+               }
+       }
+
+       pressedKeys[keycode] = keysym;
+
+       /* Undo any fake level three shift */
+       if (level_three_press != 0)
+               pressKey(vncKeyboardDev, level_three_press, FALSE, "temp level 3 shift");
+       else if (level_three_release_count != 0) {
+               for (i = 0;i < level_three_release_count;i++)
+                       pressKey(vncKeyboardDev, level_three_release[i], TRUE, "temp level 3 shift");
+       }
+
+       /* Undo any fake shift */
+       if (shift_press != 0)
+               pressKey(vncKeyboardDev, shift_press, FALSE, "temp shift");
+       else if (shift_release_count != 0) {
+               for (i = 0;i < shift_release_count;i++)
+                       pressKey(vncKeyboardDev, shift_release[i], TRUE, "temp shift");
+       }
+
+       /*
+        * 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 --git a/unix/xserver/hw/vnc/Input.cc b/unix/xserver/hw/vnc/Input.cc
deleted file mode 100644 (file)
index 3aae5db..0000000
+++ /dev/null
@@ -1,692 +0,0 @@
-/* Copyright (C) 2009 TightVNC Team
- * Copyright (C) 2009, 2014 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 <rfb/LogWriter.h>
-#include "Input.h"
-#include "xorg-version.h"
-#include "vncExtInit.h"
-
-extern "C" {
-#define public c_public
-#define class c_class
-#include "inputstr.h"
-#if XORG >= 110
-#include "inpututils.h"
-#endif
-#include "mi.h"
-#if XORG >= 16
-#include "exevents.h"
-#endif
-#if XORG == 16
-extern void
-CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master);
-#endif
-#if XORG >= 17
-#include "xkbsrv.h"
-#include "xkbstr.h"
-#include "xserver-properties.h"
-extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey;
-#endif
-#include <X11/keysym.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#undef public
-#undef class
-}
-
-#if XORG >= 110
-#define Xfree free
-#endif
-
-using namespace rdr;
-using namespace rfb;
-
-static LogWriter vlog("Input");
-
-rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock", "Avoid fake Shift presses for keys affected by NumLock.", true);
-
-#define BUTTONS 7
-
-class InputDevice *vncInputDevice;
-InputDevice InputDevice::singleton;
-
-/* Event queue is shared between all devices. */
-#if XORG == 15
-static xEvent *eventq = NULL;
-#elif XORG < 111
-static EventList *eventq = NULL;
-#endif
-
-#if XORG < 111
-static void initEventq(void)
-{
-       /* eventq is never free()-ed because it exists during server life. */
-       if (eventq == NULL) {
-#if XORG == 15
-               eventq = (xEvent *)xcalloc(sizeof(xEvent),
-                                          GetMaximumEventsNum());
-               if (!eventq)
-                       FatalError("Couldn't allocate eventq\n");
-#else
-               GetEventList(&eventq);
-#endif
-       }
-}
-#endif /* XORG < 111 */
-
-#if XORG < 111
-static void enqueueEvents(DeviceIntPtr dev, int n)
-{
-       int i;
-
-       for (i = 0; i < n; i++) {
-               /*
-                * Passing arguments in global variable eventq is probably not
-                * good programming practise but in this case it is safe and
-                * clear.
-                */
-               mieqEnqueue(dev,
-#if XORG == 15
-                           eventq + i
-#elif XORG == 16
-                           (eventq + i)->event
-#else
-                           (InternalEvent *) (eventq + i)->event
-#endif
-                          );
-       }
-}
-#endif /* XORG < 111 */
-
-InputDevice::InputDevice()
-       : oldButtonMask(0)
-{
-       int i;
-
-       vncInputDevice = this;
-
-       for (i = 0;i < 256;i++)
-               pressedKeys[i] = NoSymbol;
-}
-
-void InputDevice::PointerButtonAction(int buttonMask)
-{
-       int i;
-#if XORG < 111
-       int n;
-#endif
-#if XORG >= 110
-       ValuatorMask mask;
-#endif
-
-       for (i = 0; i < BUTTONS; i++) {
-               if ((buttonMask ^ oldButtonMask) & (1 << i)) {
-                       int action = (buttonMask & (1<<i)) ?
-                                    ButtonPress : ButtonRelease;
-#if XORG < 110
-                       n = GetPointerEvents(eventq, pointerDev, action, i + 1,
-                                            POINTER_RELATIVE, 0, 0, NULL);
-                       enqueueEvents(pointerDev, n);
-#elif XORG < 111
-                       valuator_mask_set_range(&mask, 0, 0, NULL);
-                       n = GetPointerEvents(eventq, pointerDev, action, i + 1,
-                                            POINTER_RELATIVE, &mask);
-                       enqueueEvents(pointerDev, n);
-#else
-                       valuator_mask_set_range(&mask, 0, 0, NULL);
-                       QueuePointerEvents(pointerDev, action, i + 1,
-                                          POINTER_RELATIVE, &mask);
-#endif
-               }
-       }
-
-       oldButtonMask = buttonMask;
-}
-
-void InputDevice::PointerMove(const rfb::Point &pos)
-{
-       int valuators[2];
-#if XORG < 111
-       int n;
-#endif
-#if XORG >= 110
-       ValuatorMask mask;
-#endif
-
-       if (pos.equals(cursorPos))
-               return;
-
-       valuators[0] = pos.x;
-       valuators[1] = pos.y;
-#if XORG < 110
-       n = GetPointerEvents(eventq, pointerDev, MotionNotify, 0, POINTER_ABSOLUTE, 0,
-                            2, valuators);
-       enqueueEvents(pointerDev, n);
-#elif XORG < 111
-       valuator_mask_set_range(&mask, 0, 2, valuators);
-       n = GetPointerEvents(eventq, pointerDev, MotionNotify, 0, POINTER_ABSOLUTE,
-                            &mask);
-       enqueueEvents(pointerDev, n);
-#else
-       valuator_mask_set_range(&mask, 0, 2, valuators);
-       QueuePointerEvents(pointerDev, MotionNotify, 0, POINTER_ABSOLUTE, &mask);
-#endif
-
-       cursorPos = pos;
-}
-
-const rfb::Point &InputDevice::getPointerPos(void)
-{
-       if (pointerDev != NULL) {
-               int x, y;
-
-               GetSpritePosition (pointerDev, &x, &y);
-               cursorPos.x = x;
-               cursorPos.y = y;
-       }
-
-       return cursorPos;
-}
-
-int InputDevice::pointerProc(DeviceIntPtr pDevice, int onoff)
-{
-       BYTE map[BUTTONS + 1];
-       DevicePtr pDev = (DevicePtr)pDevice;
-       int i;
-#if XORG >= 17
-       /*
-        * NOTE: map[] array is one element longer than btn_labels[] array. This
-        * is not a bug.
-        */
-       Atom btn_labels[BUTTONS];
-       Atom axes_labels[2];
-#endif
-
-       switch (onoff) {
-       case DEVICE_INIT:
-               for (i = 0; i < BUTTONS + 1; i++)
-                       map[i] = i;
-
-#if XORG >= 17
-               btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
-               btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
-               btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
-               btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
-               btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
-               btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
-               btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
-
-               axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
-               axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
-#endif
-
-               InitPointerDeviceStruct(pDev, map, BUTTONS,
-#if XORG == 15
-                                       GetMotionHistory,
-#elif XORG >= 17
-                                       btn_labels,
-#endif
-                                       (PtrCtrlProcPtr)NoopDDA,
-                                       GetMotionHistorySize(), 2
-#if XORG >= 17
-                                       , axes_labels
-#endif
-                                       );
-               break;
-       case DEVICE_ON:
-               pDev->on = TRUE;
-               break;
-       case DEVICE_OFF:
-               pDev->on = FALSE;
-               break;
-       case DEVICE_CLOSE:
-               singleton.pointerDev = NULL;
-               break;
-       }
-
-       return Success;
-}
-
-static void keyboardBell(int percent, DeviceIntPtr device, void * ctrl,
-                        int class_)
-{
-       if (percent > 0)
-               vncBell();
-}
-
-int InputDevice::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
-                                        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;
-       case DEVICE_CLOSE:
-               singleton.keyboardDev = NULL;
-               break;
-       }
-
-       return Success;
-}
-
-void InputDevice::InitInputDevice(void)
-{
-       if ((pointerDev != NULL) || (keyboardDev != NULL))
-               return;
-
-#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,
-                             FALSE);
-
-       if (ret != Success)
-               FatalError("Failed to initialize TigerVNC input devices\n");
-
-       if (ActivateDevice(pointerDev, TRUE) != Success ||
-           ActivateDevice(keyboardDev, TRUE) != Success)
-               FatalError("Failed to activate TigerVNC devices\n");
-
-       if (!EnableDevice(pointerDev, TRUE) ||
-           !EnableDevice(keyboardDev, TRUE))
-               FatalError("Failed to activate TigerVNC devices\n");
-#endif /* 17 */
-
-#if XORG < 111
-       initEventq();
-#endif
-
-       PrepareInputDevices();
-}
-
-static inline void pressKey(DeviceIntPtr dev, int kc, bool down, const char *msg)
-{
-       int action;
-#if XORG < 111
-       unsigned int n;
-#endif
-
-       if (msg != NULL)
-               vlog.debug("%s %d %s", msg, kc, down ? "down" : "up");
-
-       action = down ? KeyPress : KeyRelease;
-#if XORG < 111
-       n = GetKeyboardEvents(eventq, dev, action, kc);
-       enqueueEvents(dev, n);
-#else
-       QueueKeyboardEvents(dev, action, kc, NULL);
-#endif
-}
-
-/* altKeysym is a table of alternative keysyms which have the same meaning. */
-
-static struct altKeysym_t {
-       KeySym a, b;
-} altKeysym[] = {
-       { XK_Shift_L,           XK_Shift_R },
-       { XK_Control_L,         XK_Control_R },
-       { XK_Meta_L,            XK_Meta_R },
-       { XK_Alt_L,             XK_Alt_R },
-       { XK_Super_L,           XK_Super_R },
-       { XK_Hyper_L,           XK_Hyper_R },
-       { XK_KP_Space,          XK_space },
-       { XK_KP_Tab,            XK_Tab },
-       { XK_KP_Enter,          XK_Return },
-       { XK_KP_F1,             XK_F1 },
-       { XK_KP_F2,             XK_F2 },
-       { XK_KP_F3,             XK_F3 },
-       { XK_KP_F4,             XK_F4 },
-       { XK_KP_Home,           XK_Home },
-       { XK_KP_Left,           XK_Left },
-       { XK_KP_Up,             XK_Up },
-       { XK_KP_Right,          XK_Right },
-       { XK_KP_Down,           XK_Down },
-       { XK_KP_Page_Up,        XK_Page_Up },
-       { XK_KP_Page_Down,      XK_Page_Down },
-       { XK_KP_End,            XK_End },
-       { XK_KP_Begin,          XK_Begin },
-       { XK_KP_Insert,         XK_Insert },
-       { XK_KP_Delete,         XK_Delete },
-       { XK_KP_Equal,          XK_equal },
-       { XK_KP_Multiply,       XK_asterisk },
-       { XK_KP_Add,            XK_plus },
-       { XK_KP_Separator,      XK_comma },
-       { XK_KP_Subtract,       XK_minus },
-       { XK_KP_Decimal,        XK_period },
-       { XK_KP_Divide,         XK_slash },
-       { XK_KP_0,              XK_0 },
-       { XK_KP_1,              XK_1 },
-       { XK_KP_2,              XK_2 },
-       { XK_KP_3,              XK_3 },
-       { XK_KP_4,              XK_4 },
-       { XK_KP_5,              XK_5 },
-       { XK_KP_6,              XK_6 },
-       { 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 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.
- */
-void InputDevice::keyEvent(rdr::U32 keysym, bool down)
-{
-       int i;
-       unsigned state, new_state;
-       KeyCode keycode;
-
-       unsigned level_three_mask;
-       KeyCode shift_press, level_three_press;
-       std::list<KeyCode> shift_release, level_three_release;
-
-       /*
-        * 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;
-                       }
-               }
-
-               /*
-                * 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
-        * to fake modifiers, we must make sure that everything put on the
-        * input queue is processed before we start. Otherwise, shift may be
-        * stuck down.
-        */ 
-       mieqProcessInputEvents();
-
-       state = getKeyboardState();
-
-       keycode = keysymToKeycode(keysym, state, &new_state);
-
-       /* 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;
-
-                       keycode = keysymToKeycode(altsym, state, &new_state);
-                       if (keycode != 0)
-                               break;
-               }
-       }
-
-       /* We don't have lock synchronisation... */
-       if (isLockModifier(keycode, new_state)) {
-               vlog.debug("Ignoring lock key (e.g. caps lock)");
-               return;
-       }
-
-       /* 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;
-               }
-
-               vlog.info("Added unknown keysym 0x%x to keycode %d",
-                         keysym, keycode);
-
-               /*
-                * The state given to addKeysym() is just a hint and
-                * the actual result might still require some state
-                * changes.
-                */
-               keycode = keysymToKeycode(keysym, state, &new_state);
-               if (keycode == 0) {
-                       vlog.error("Newly added keysym 0x%x cannot be generated", keysym);
-                       return;
-               }
-       }
-
-       /*
-        * 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;
-
-                       keycode2 = keysymToKeycode(altsym, state, &new_state2);
-                       if (keycode2 == 0)
-                               continue;
-
-                       if (((state & ShiftMask) != (new_state2 & ShiftMask)) &&
-                           isAffectedByNumLock(keycode2))
-                               continue;
-
-                       break;
-               }
-
-               if (i == sizeof(altKeysym)/sizeof(altKeysym[0]))
-                       vlog.debug("No alternative keysym found");
-               else {
-                       keycode = keycode2;
-                       new_state = new_state2;
-               }
-       }
-
-       /*
-        * "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 (keysym == XK_Tab && (state & ShiftMask))
-               new_state |= ShiftMask;
-
-       /*
-        * We need a bigger state change than just shift,
-        * so we need to know what the mask is for level 3 shifts.
-        */
-       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;
-               }
-
-               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;
-               }
-
-               for (iter = shift_release.begin();iter != shift_release.end();++iter)
-                       pressKey(keyboardDev, *iter, false, "temp shift");
-       }
-
-       /* 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;
-               }
-
-               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;
-               }
-
-               for (iter = level_three_release.begin();iter != level_three_release.end();++iter)
-                       pressKey(keyboardDev, *iter, false, "temp level 3 shift");
-       }
-
-       /* Now press the actual key */
-       pressKey(keyboardDev, keycode, true, "keycode");
-
-       /* 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;
-               }
-       }
-
-       pressedKeys[keycode] = keysym;
-
-       /* 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");
-       }
-
-       /* 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");
-       }
-
-       /*
-        * 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();
-}
index 90b392cf001bcc6ab6e30b3e59b9ea719caa9137..11e887108e8a7dcea25881a3e3f0f49386bc4ea9 100644 (file)
@@ -1,7 +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
+ * Copyright 2013-2015 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
 #ifndef INPUT_H_
 #define INPUT_H_
 
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <list>
-
-#include <rdr/types.h>
-#include <rfb/Rect.h>
+#include <stdlib.h>
+#include <X11/X.h>
 
+#ifdef __cplusplus
 extern "C" {
-#include "input.h"
-/* The Xorg headers define macros that wreak havoc with STL */
-#undef max
-};
-
-#include "xorg-version.h"
-
-/*
- * Represents input device (keyboard + pointer)
- *
- * Is a singleton as input devices are global in the X server so
- * we do not have one per desktop (i.e. per screen).
- */
-extern class InputDevice *vncInputDevice;
-
-class InputDevice {
-public:
-       /*
-        * Press or release buttons. Relationship between buttonMask and
-        * buttons is specified in RFB protocol.
-        */
-       void PointerButtonAction(int buttonMask);
-
-       /* Move pointer to target location (point coords are absolute). */
-       void PointerMove(const rfb::Point &point);
-
-       /* Get current known location of the pointer */
-       const rfb::Point &getPointerPos(void);
-
-       /* Press or release one or more keys to get the given symbol */
-       void KeyboardPress(rdr::U32 keysym) { keyEvent(keysym, true); }
-       void KeyboardRelease(rdr::U32 keysym) { keyEvent(keysym, false); }
+#endif
 
-       /*
-        * Init input device.
-        * This has to be called after core pointer/keyboard
-        * initialization which unfortunately is after extesions
-        * initialization (which means we cannot call it in
-        * vncExtensionInit(). Check InitExtensions(),
-        * InitCoreDevices() and InitInput() calls in dix/main.c.
-        * Instead we call it from XserverDesktop at an appropriate
-        * time.
-        */
-       void InitInputDevice(void);
+void vncInitInputDevice(void);
 
-private:
-       InputDevice();
+void vncPointerButtonAction(int buttonMask);
+void vncPointerMove(int x, int y);
+void vncGetPointerPos(int *x, int *y);
 
-       void keyEvent(rdr::U32 keysym, bool down);
+void vncKeyboardEvent(KeySym keysym, int down);
 
-       /* Backend dependent functions below here */
-       void PrepareInputDevices(void);
+/* Backend dependent functions below here */
 
-       unsigned getKeyboardState(void);
-       unsigned getLevelThreeMask(void);
+void vncPrepareInputDevices(void);
 
-       KeyCode pressShift(void);
-       std::list<KeyCode> releaseShift(void);
+unsigned vncGetKeyboardState(void);
+unsigned vncGetLevelThreeMask(void);
 
-       KeyCode pressLevelThree(void);
-       std::list<KeyCode> releaseLevelThree(void);
+KeyCode vncPressShift(void);
+size_t vncReleaseShift(KeyCode *keys, size_t maxKeys);
 
-       KeyCode keysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state);
+KeyCode vncPressLevelThree(void);
+size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys);
 
-       bool isLockModifier(KeyCode keycode, unsigned state);
+KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state);
 
-       bool isAffectedByNumLock(KeyCode keycode);
+int vncIsLockModifier(KeyCode keycode, unsigned state);
 
-       KeyCode addKeysym(KeySym keysym, unsigned state);
+int vncIsAffectedByNumLock(KeyCode keycode);
 
-private:
-       static int pointerProc(DeviceIntPtr pDevice, int onoff);
-       static int keyboardProc(DeviceIntPtr pDevice, int onoff);
+KeyCode vncAddKeysym(KeySym keysym, unsigned state);
 
-#if XORG >= 17
-       static void vncXkbProcessDeviceEvent(int screenNum,
-                                            InternalEvent *event,
-                                            DeviceIntPtr dev);
-#else
-       static void GetInitKeyboardMap(KeySymsPtr keysyms, CARD8 *modmap);
+#ifdef __cplusplus
+}
 #endif
 
-private:
-       DeviceIntPtr keyboardDev;
-       DeviceIntPtr pointerDev;
-
-       int oldButtonMask;
-       rfb::Point cursorPos;
-
-       KeySym pressedKeys[256];
-
-private:
-       static InputDevice singleton;
-};
-
 #endif
diff --git a/unix/xserver/hw/vnc/InputCore.c b/unix/xserver/hw/vnc/InputCore.c
new file mode 100644 (file)
index 0000000..0467766
--- /dev/null
@@ -0,0 +1,596 @@
+/* Copyright (C) 2009 TightVNC Team
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright 2013-2015 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"
+
+#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>
+
+extern DeviceIntPtr vncKeyboardDev;
+
+#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
+static 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 vncGetInitKeyboardMap(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 vncPrepareInputDevices(void)
+{
+       /* Don't need to do anything here */
+}
+
+unsigned vncGetKeyboardState(void)
+{
+       return vncKeyboardDev->key->state;
+}
+
+unsigned vncGetLevelThreeMask(void)
+{
+       int i, j, k;
+
+       int minKeyCode, mapWidth;
+       KeySym *map;
+
+       int maxKeysPerMod;
+       CARD8 *modmap;
+
+       minKeyCode = vncKeyboardDev->key->curKeySyms.minKeyCode;
+       mapWidth = vncKeyboardDev->key->curKeySyms.mapWidth;
+       map = vncKeyboardDev->key->curKeySyms.map;
+
+       maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
+       modmap = vncKeyboardDev->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 vncPressShift(void)
+{
+       int maxKeysPerMod;
+
+       maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
+       return vncKeyboardDev->key->modifierKeyMap[ShiftMapIndex * maxKeysPerMod];
+}
+
+size_t vncReleaseShift(KeyCode *keys, size_t maxKeys)
+{
+       size_t count;
+       int maxKeysPerMod;
+
+       count = 0;
+       maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
+       for (int k = 0; k < maxKeysPerMod; k++) {
+               int keycode;
+               int index;
+
+               index = ShiftMapIndex * maxKeysPerMod + k;
+
+               keycode = vncKeyboardDev->key->modifierKeyMap[index];
+               if (keycode == 0)
+                       continue;
+
+               if (!IS_PRESSED(vncKeyboardDev, keycode))
+                       continue;
+
+               if (count >= maxKeys)
+                       return 0;
+
+               keys[count++] = keycode;
+       }
+
+       return count;
+}
+
+KeyCode vncPressLevelThree(void)
+{
+       unsigned mask, index;
+       int maxKeysPerMod;
+
+       mask = getLevelThreeMask();
+       if (mask == 0)
+               return 0;
+
+       index = ffs(mask) - 1;
+       maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
+       return vncKeyboardDev->key->modifierKeyMap[index * maxKeysPerMod];
+}
+
+size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys)
+{
+       size_t count;
+       unsigned mask, msindex;
+       int maxKeysPerMod;
+
+       mask = getLevelThreeMask();
+       if (mask == 0)
+               return 0;
+
+       msindex = ffs(mask) - 1;
+
+       count = 0;
+       maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
+       for (int k = 0; k < maxKeysPerMod; k++) {
+               int keycode;
+               int index;
+
+               index = msindex * maxKeysPerMod + k;
+
+               keycode = vncKeyboardDev->key->modifierKeyMap[index];
+               if (keycode == 0)
+                       continue;
+
+               if (!IS_PRESSED(vncKeyboardDev, keycode))
+                       continue;
+
+               if (count >= maxKeys)
+                       return 0;
+
+               keys[count++] = keycode;
+       }
+
+       return count;
+}
+
+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 vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
+{
+       int i, j;
+       unsigned mask;
+
+       KeySymsPtr keymap;
+       int mapWidth;
+
+       mask = vncGetLevelThreeMask();
+
+       keymap = &vncKeyboardDev->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;
+}
+
+int vncIsLockModifier(KeyCode keycode, unsigned state)
+{
+       int i, j, k;
+
+       int minKeyCode, mapWidth;
+       KeySym *map;
+
+       int maxKeysPerMod;
+       CARD8 *modmap;
+
+       int num_lock_index;
+
+       minKeyCode = vncKeyboardDev->key->curKeySyms.minKeyCode;
+       mapWidth = vncKeyboardDev->key->curKeySyms.mapWidth;
+       map = vncKeyboardDev->key->curKeySyms.map;
+
+       maxKeysPerMod = vncKeyboardDev->key->maxKeysPerModifier;
+       modmap = vncKeyboardDev->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 1;
+       }
+
+       /* 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 0;
+
+       /* 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 1;
+       }
+
+       return 0;
+}
+
+int vncIsAffectedByNumLock(KeyCode keycode)
+{
+       KeySymsPtr keymap;
+       int i, per;
+       KeySym *syms;
+
+       keymap = &vncKeyboardDev->key->curKeySyms;
+       per = keymap->mapWidth;
+       syms = &keymap->map[(keycode - keymap->minKeyCode) * per];
+
+       for (i = 0;i < per;i++) {
+               if (IsKeypadKey(syms[i]))
+                       return 1;
+               if (IsPrivateKeypadKey(syms[i]))
+                       return 1;
+       }
+
+       return 0;
+}
+
+KeyCode vncAddKeysym(KeySym keysym, unsigned state)
+{
+       KeyCode kc;
+
+       int minKeyCode, maxKeyCode, mapWidth;
+       KeySym *map;
+
+       minKeyCode = vncKeyboardDev->key->curKeySyms.minKeyCode;
+       maxKeyCode = vncKeyboardDev->key->curKeySyms.maxKeyCode;
+       mapWidth = vncKeyboardDev->key->curKeySyms.mapWidth;
+       map = vncKeyboardDev->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 = vncKeyboardDev->u.master;
+#endif
+               void *slave = dixLookupPrivate(&master->devPrivates,
+                                              CoreDevicePrivateKey);
+               if (vncKeyboardDev == slave) {
+                       dixSetPrivate(&master->devPrivates,
+                                     CoreDevicePrivateKey, NULL);
+#if XORG == 15
+                       SwitchCoreKeyboard(vncKeyboardDev);
+#else
+                       CopyKeyClass(vncKeyboardDev, master);
+#endif
+               }
+
+               return kc;
+       }
+
+       return 0;
+}
+
+#endif
+
diff --git a/unix/xserver/hw/vnc/InputCore.cc b/unix/xserver/hw/vnc/InputCore.cc
deleted file mode 100644 (file)
index b565c73..0000000
+++ /dev/null
@@ -1,594 +0,0 @@
-/* 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 InputDevice::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 --git a/unix/xserver/hw/vnc/InputXKB.c b/unix/xserver/hw/vnc/InputXKB.c
new file mode 100644 (file)
index 0000000..e639d5e
--- /dev/null
@@ -0,0 +1,662 @@
+/* Copyright (C) 2009 TightVNC Team
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright 2013-2015 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 "xorg-version.h"
+
+#if XORG >= 17
+
+#include <stdio.h>
+
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "xkbsrv.h"
+#include "xkbstr.h"
+#include "eventstr.h"
+#include "scrnintstr.h"
+#include "mi.h"
+
+#include "Input.h"
+
+#ifndef KEYBOARD_OR_FLOAT
+#define KEYBOARD_OR_FLOAT MASTER_KEYBOARD
+#endif
+
+extern DeviceIntPtr vncKeyboardDev;
+
+static void vncXkbProcessDeviceEvent(int screenNum,
+                                     InternalEvent *event,
+                                     DeviceIntPtr dev);
+
+/* 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 vncPrepareInputDevices(void)
+{
+       /*
+        * 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 vncGetKeyboardState(void)
+{
+       DeviceIntPtr master;
+
+       master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
+       return XkbStateFieldFromRec(&master->key->xkbInfo->state);
+}
+
+unsigned vncGetLevelThreeMask(void)
+{
+       unsigned state;
+       KeyCode keycode;
+       XkbDescPtr xkb;
+       XkbAction *act;
+
+       /* Group state is still important */
+       state = vncGetKeyboardState();
+       state &= ~0xff;
+
+       keycode = vncKeysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
+       if (keycode == 0) {
+               keycode = vncKeysymToKeycode(XK_Mode_switch, state, NULL);
+               if (keycode == 0)
+                       return 0;
+       }
+
+       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->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 vncPressShift(void)
+{
+       unsigned state;
+
+       XkbDescPtr xkb;
+       unsigned int key;
+
+       state = vncGetKeyboardState();
+       if (state & ShiftMask)
+               return 0;
+
+       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->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;
+}
+
+size_t vncReleaseShift(KeyCode *keys, size_t maxKeys)
+{
+       size_t count;
+
+       unsigned state;
+
+       DeviceIntPtr master;
+       XkbDescPtr xkb;
+       unsigned int key;
+
+       state = vncGetKeyboardState();
+       if (!(state & ShiftMask))
+               return 0;
+
+       count = 0;
+
+       master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
+       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;
+
+               if (count >= maxKeys)
+                       return 0;
+
+               keys[count++] = key;
+       }
+
+       return count;
+}
+
+KeyCode vncPressLevelThree(void)
+{
+       unsigned state, mask;
+
+       KeyCode keycode;
+       XkbDescPtr xkb;
+       XkbAction *act;
+
+       mask = vncGetLevelThreeMask();
+       if (mask == 0)
+               return 0;
+
+       state = vncGetKeyboardState();
+       if (state & mask)
+               return 0;
+
+       keycode = vncKeysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
+       if (keycode == 0) {
+               keycode = vncKeysymToKeycode(XK_Mode_switch, state, NULL);
+               if (keycode == 0)
+                       return 0;
+       }
+
+       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+
+       act = XkbKeyActionPtr(xkb, keycode, state);
+       if (act == NULL)
+               return 0;
+       if (act->type != XkbSA_SetMods)
+               return 0;
+
+       return keycode;
+}
+
+size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys)
+{
+       size_t count;
+
+       unsigned state, mask;
+
+       DeviceIntPtr master;
+       XkbDescPtr xkb;
+       unsigned int key;
+
+       mask = vncGetLevelThreeMask();
+       if (mask == 0)
+               return 0;
+
+       state = vncGetKeyboardState();
+       if (!(state & mask))
+               return 0;
+
+       count = 0;
+
+       master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
+       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;
+
+               if (count >= maxKeys)
+                       return 0;
+
+               keys[count++] = key;
+       }
+
+       return count;
+}
+
+KeyCode vncKeysymToKeycode(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 = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->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 = vncKeysymToKeycode(keysym, *new_state, NULL);
+       if (key != 0)
+               return key;
+
+       level_three_mask = vncGetLevelThreeMask();
+       if (level_three_mask == 0)
+               return 0;
+
+       *new_state = (state & ~level_three_mask) | 
+                    ((state & level_three_mask) ? 0 : level_three_mask);
+       key = vncKeysymToKeycode(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 = vncKeysymToKeycode(keysym, *new_state, NULL);
+       if (key != 0)
+               return key;
+
+       return 0;
+}
+
+int vncIsLockModifier(KeyCode keycode, unsigned state)
+{
+       XkbDescPtr xkb;
+       XkbAction *act;
+
+       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+
+       act = XkbKeyActionPtr(xkb, keycode, state);
+       if (act == NULL)
+               return 0;
+
+       if (act->type != XkbSA_LockMods)
+               return 0;
+
+       return 1;
+}
+
+int vncIsAffectedByNumLock(KeyCode keycode)
+{
+       unsigned state;
+
+       KeyCode numlock_keycode;
+       unsigned numlock_mask;
+
+       XkbDescPtr xkb;
+       XkbAction *act;
+
+       unsigned group;
+       XkbKeyTypeRec *type;
+
+       /* Group state is still important */
+       state = vncGetKeyboardState();
+       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 = vncKeysymToKeycode(XK_Num_Lock, state, NULL);
+       if (numlock_keycode == 0)
+               return 0;
+
+       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+
+       act = XkbKeyActionPtr(xkb, numlock_keycode, state);
+       if (act == NULL)
+               return 0;
+       if (act->type != XkbSA_LockMods)
+               return 0;
+
+       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 0;
+
+       return 1;
+}
+
+KeyCode vncAddKeysym(KeySym keysym, unsigned state)
+{
+       DeviceIntPtr master;
+       XkbDescPtr xkb;
+       unsigned int key;
+
+       XkbEventCauseRec cause;
+       XkbChangesRec changes;
+
+       int types[1];
+       KeySym *syms;
+       KeySym upper, lower;
+
+       master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
+       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;
+}
+
+static void vncXkbProcessDeviceEvent(int screenNum,
+                                     InternalEvent *event,
+                                     DeviceIntPtr dev)
+{
+       unsigned int backupctrls;
+
+       if (event->device_event.sourceid == vncKeyboardDev->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->public.processInputProc(event, dev);
+
+       if (event->device_event.sourceid == vncKeyboardDev->id) {
+               XkbControlsPtr ctrls;
+
+               ctrls = dev->key->xkbInfo->desc->ctrls;
+               ctrls->enabled_ctrls = backupctrls;
+       }
+}
+
+#endif /* XORG >= 117 */
diff --git a/unix/xserver/hw/vnc/InputXKB.cc b/unix/xserver/hw/vnc/InputXKB.cc
deleted file mode 100644 (file)
index 92288aa..0000000
+++ /dev/null
@@ -1,647 +0,0 @@
-/* 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
-}
-
-#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)
-{
-       /*
-        * 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)
-{
-       DeviceIntPtr master;
-
-       master = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT);
-       return XkbStateFieldFromRec(&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 = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->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 = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->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 = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT);
-       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 = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->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 = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT);
-       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 = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->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 = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->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 = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT)->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 = GetMaster(keyboardDev, KEYBOARD_OR_FLOAT);
-       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)
-{
-       unsigned int backupctrls;
-
-       if (event->device_event.sourceid == singleton.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 == singleton.keyboardDev->id) {
-               XkbControlsPtr ctrls;
-
-               ctrls = dev->key->xkbInfo->desc->ctrls;
-               ctrls->enabled_ctrls = backupctrls;
-       }
-}
-
-#endif /* XORG >= 117 */
index 372a57f56aa27963c02095ceab2741e5d4aab3df..902aabf302ed397ff973e7df7c43bd13507fa2d8 100644 (file)
@@ -7,16 +7,16 @@ NETWORK_LIB=$(LIB_DIR)/network/libnetwork.la
 XREGION_LIB=$(LIB_DIR)/Xregion/libXregion.la
 COMMON_LIBS=$(NETWORK_LIB) $(RFB_LIB) $(RDR_LIB) $(XREGION_LIB)
 
-# Hack to get the C headers to work when included from C++ code
-AM_CXXFLAGS = -fpermissive
-
 noinst_LTLIBRARIES = libvnccommon.la
 
-HDRS = RegionHelper.h vncExtInit.h vncHooks.h XserverDesktop.h xorg-version.h \
-       Input.h
+HDRS = vncExtInit.h vncHooks.h \
+       vncBlockHandler.h XorgGlue.h \
+       XserverDesktop.h xorg-version.h \
+       Input.h RFBGlue.h
 
-libvnccommon_la_SOURCES = $(HDRS) vncExtInit.cc vncHooks.cc XserverDesktop.cc \
-       Input.cc InputCore.cc InputXKB.cc
+libvnccommon_la_SOURCES = $(HDRS) vncExt.c vncExtInit.cc vncHooks.c \
+       vncBlockHandler.c XorgGlue.c RFBGlue.cc XserverDesktop.cc \
+       Input.c InputCore.c InputXKB.c
 
 libvnccommon_la_CPPFLAGS = -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \
        -DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(TIGERVNC_SRCDIR)/common -UHAVE_CONFIG_H \
@@ -27,12 +27,10 @@ bin_PROGRAMS = Xvnc
 
 man1_MANS = Xvnc.man
 
-Xvnc_SOURCES = xvnc.cc \
+Xvnc_SOURCES = xvnc.c \
        $(top_srcdir)/Xi/stubs.c $(top_srcdir)/mi/miinitext.c \
        $(top_srcdir)/fb/fbcmap_mi.c buildtime.c
 
-nodist_Xvnc_SOURCES = fbrop.h fb.h pixman.h
-
 Xvnc_CPPFLAGS = $(XVNC_CPPFLAGS) -DTIGERVNC -DNO_MODULE_EXTS \
        -UHAVE_CONFIG_H \
        -DXFree86Server -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \
@@ -47,7 +45,7 @@ Xvnc_LDFLAGS = $(LD_EXPORT_SYMBOLS_FLAG)
 libvnc_la_LTLIBRARIES = libvnc.la
 libvnc_ladir = $(moduledir)/extensions
 
-libvnc_la_SOURCES = xf86vncModule.cc
+libvnc_la_SOURCES = vncModule.c
 
 libvnc_la_CPPFLAGS = $(XVNC_CPPFLAGS) -I$(TIGERVNC_SRCDIR)/common -UHAVE_CONFIG_H \
        -I$(top_srcdir)/hw/xfree86/common \
@@ -61,24 +59,3 @@ libvnc_la_LDFLAGS = -module -avoid-version
 libvnc_la_LIBADD = libvnccommon.la $(COMMON_LIBS)
 
 EXTRA_DIST = Xvnc.man
-
-# C++ hacks
-BUILT_SOURCES = $(nodist_Xvnc_SOURCES)
-
-fb.h: $(top_srcdir)/fb/fb.h
-       cat $(top_srcdir)/fb/fb.h | sed -e 's,and,c_and,g' -e 's,xor,c_xor,g' > $(srcdir)/fb.h
-
-pixman.h:
-       for i in ${XSERVERLIBS_CFLAGS}; do \
-               if [[ "$$i" =~ "pixman" ]]; then \
-                       PIXMANINCDIR=`echo $$i | sed s/-I//g`; \
-               fi; \
-       done; \
-       if [ ! "$$PIXMANINCDIR" = "" ]; then \
-               cat $$PIXMANINCDIR/pixman.h | sed 's/xor/c_xor/' > $(srcdir)/pixman.h; \
-       else \
-               echo Pixman include directory not set in XSERVERLIBS_CFLAGS \(perhaps Pixman was not found by configure?\); \
-       fi
-
-fbrop.h: $(top_srcdir)/fb/fbrop.h
-       cat $(top_srcdir)/fb/fbrop.h | sed -e 's,and,c_and,g' -e 's,xor,c_xor,g' > $(srcdir)/fbrop.h
diff --git a/unix/xserver/hw/vnc/RFBGlue.cc b/unix/xserver/hw/vnc/RFBGlue.cc
new file mode 100644 (file)
index 0000000..7747d88
--- /dev/null
@@ -0,0 +1,195 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011-2015 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.
+ */
+
+#include <stdlib.h>
+
+#include <network/TcpSocket.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Logger_stdio.h>
+
+#include "RFBGlue.h"
+
+using namespace rfb;
+
+// Loggers used by C code must be created here
+static LogWriter inputLog("Input");
+
+void vncInitRFB(void)
+{
+  rfb::initStdIOLoggers();
+  rfb::LogWriter::setLogParams("*:stderr:30");
+  rfb::Configuration::enableServerParams();
+}
+
+void vncLogError(const char *name, const char *format, ...)
+{
+  LogWriter *vlog;
+  va_list ap;
+  vlog = LogWriter::getLogWriter(name);
+  if (vlog == NULL)
+    return;
+  va_start(ap, format);
+  vlog->error(format, ap);
+  va_end(ap);
+}
+
+void vncLogStatus(const char *name, const char *format, ...)
+{
+  LogWriter *vlog;
+  va_list ap;
+  vlog = LogWriter::getLogWriter(name);
+  if (vlog == NULL)
+    return;
+  va_start(ap, format);
+  vlog->status(format, ap);
+  va_end(ap);
+}
+
+void vncLogInfo(const char *name, const char *format, ...)
+{
+  LogWriter *vlog;
+  va_list ap;
+  vlog = LogWriter::getLogWriter(name);
+  if (vlog == NULL)
+    return;
+  va_start(ap, format);
+  vlog->info(format, ap);
+  va_end(ap);
+}
+
+void vncLogDebug(const char *name, const char *format, ...)
+{
+  LogWriter *vlog;
+  va_list ap;
+  vlog = LogWriter::getLogWriter(name);
+  if (vlog == NULL)
+    return;
+  va_start(ap, format);
+  vlog->debug(format, ap);
+  va_end(ap);
+}
+
+int vncSetParam(const char *name, const char *value)
+{
+  return rfb::Configuration::setParam(name, value);
+}
+
+int vncSetParamSimple(const char *nameAndValue)
+{
+  return rfb::Configuration::setParam(nameAndValue);
+}
+
+char* vncGetParam(const char *name)
+{
+  rfb::VoidParameter *param;
+  char *value;
+  char *ret;
+
+  // Hack to avoid exposing password!
+  if (strcasecmp(name, "Password") == 0)
+    return NULL;
+
+  param = rfb::Configuration::getParam(name);
+  if (param == NULL)
+    return NULL;
+
+  value = param->getValueStr();
+  if (value == NULL)
+    return NULL;
+
+  ret = strdup(value);
+
+  delete [] value;
+
+  return ret;
+}
+
+const char* vncGetParamDesc(const char *name)
+{
+  rfb::VoidParameter *param;
+
+  param = rfb::Configuration::getParam(name);
+  if (param == NULL)
+    return NULL;
+
+  return param->getDescription();
+}
+
+int vncGetParamCount(void)
+{
+  int count;
+
+  count = 0;
+  for (ParameterIterator i; i.param; i.next())
+    count++;
+
+  return count;
+}
+
+char *vncGetParamList(void)
+{
+  int len;
+  char *data, *ptr;
+
+  len = 0;
+
+  for (ParameterIterator i; i.param; i.next()) {
+    int l = strlen(i.param->getName());
+    if (l <= 255)
+      len += l + 1;
+  }
+
+  data = (char*)malloc(len + 1);
+  if (data == NULL)
+    return NULL;
+
+  ptr = data;
+  for (ParameterIterator i; i.param; i.next()) {
+    int l = strlen(i.param->getName());
+    if (l <= 255) {
+      *ptr++ = l;
+      memcpy(ptr, i.param->getName(), l);
+      ptr += l;
+    }
+  }
+  *ptr = '\0';
+
+  return data;
+}
+
+void vncListParams(int width, int nameWidth)
+{
+  rfb::Configuration::listParams(width, nameWidth);
+}
+
+int vncGetSocketPort(int fd)
+{
+  return network::TcpSocket::getSockPort(fd);
+}
+
+int vncIsTCPPortUsed(int port)
+{
+  try {
+    network::TcpListener l(NULL, port);
+  } catch (rdr::Exception& e) {
+    return 0;
+  }
+  return 1;
+}
diff --git a/unix/xserver/hw/vnc/RFBGlue.h b/unix/xserver/hw/vnc/RFBGlue.h
new file mode 100644 (file)
index 0000000..a63afd0
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011-2015 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.
+ */
+
+#ifndef RFB_GLUE_H
+#define RFB_GLUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void vncInitRFB(void);
+
+#ifdef __GNUC__
+#  define __printf_attr(a, b) __attribute__((__format__ (__printf__, a, b)))
+#else
+#  define __printf_attr(a, b)
+#endif // __GNUC__
+
+void vncLogError(const char *name, const char *format, ...) __printf_attr(2, 3);
+void vncLogStatus(const char *name, const char *format, ...) __printf_attr(2, 3);
+void vncLogInfo(const char *name, const char *format, ...) __printf_attr(2, 3);
+void vncLogDebug(const char *name, const char *format, ...) __printf_attr(2, 3);
+
+int vncSetParam(const char *name, const char *value);
+int vncSetParamSimple(const char *nameAndValue);
+char* vncGetParam(const char *name);
+const char* vncGetParamDesc(const char *name);
+
+int vncGetParamCount(void);
+char *vncGetParamList(void);
+void vncListParams(int width, int nameWidth);
+
+int vncGetSocketPort(int fd);
+int vncIsTCPPortUsed(int port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/unix/xserver/hw/vnc/RegionHelper.h b/unix/xserver/hw/vnc/RegionHelper.h
deleted file mode 100644 (file)
index 61dc89f..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * 
- * 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.
- */
-#ifndef __REGIONHELPER_H__
-#define __REGIONHELPER_H__
-
-// RegionHelper is a class which helps in using X server regions by
-// automatically freeing them in the destructor.  It also fixes a problem with
-// REGION_INIT when given an empty rectangle.
-
-// REGION_NULL was introduced in the Xorg tree as the way to initialise an
-// empty region.  If it's not already defined do it the old way.  Note that the
-// old way causes a segfault in the new tree...
-#ifndef REGION_NULL
-#define REGION_NULL(pScreen,pReg) REGION_INIT(pScreen,pReg,NullBox,0)
-#endif
-
-class RegionHelper {
-public:
-
-  // constructor from a single rect
-  RegionHelper(ScreenPtr pScreen_, BoxPtr rect, int size)
-    : pScreen(pScreen_), reg(0)
-  {
-    init(rect, size);
-  }
-
-  // constructor from an existing X server region
-  RegionHelper(ScreenPtr pScreen_, RegionPtr pRegion)
-    : pScreen(pScreen_), reg(&regRec)
-  {
-    REGION_NULL(pScreen, reg);
-    REGION_COPY(pScreen, reg, pRegion);
-  }
-
-  // constructor from an array of rectangles
-  RegionHelper(ScreenPtr pScreen_, int nrects, xRectanglePtr rects,
-               int ctype=CT_NONE)
-    : pScreen(pScreen_)
-  {
-    reg = RECTS_TO_REGION(pScreen, nrects, rects, ctype);
-  }
-
-  // constructor for calling init() later
-  RegionHelper(ScreenPtr pScreen_) : pScreen(pScreen_), reg(0) {
-  }
-
-  void init(BoxPtr rect, int size) {
-    reg = &regRec;
-    if (!rect || (rect && (rect->x2 == rect->x1 || rect->y2 == rect->y1))) {
-      REGION_NULL(pScreen, reg);
-    } else {
-      REGION_INIT(pScreen, reg, rect, size);
-    }
-  }
-
-  // destructor frees as appropriate
-  ~RegionHelper() {
-    if (reg == &regRec) {
-      REGION_UNINIT(pScreen, reg);
-    } else if (reg) {
-      REGION_DESTROY(pScreen, reg);
-    }
-  }
-  ScreenPtr pScreen;
-  RegionRec regRec;
-  RegionPtr reg;
-};
-
-#endif
diff --git a/unix/xserver/hw/vnc/XorgGlue.c b/unix/xserver/hw/vnc/XorgGlue.c
new file mode 100644 (file)
index 0000000..630d67d
--- /dev/null
@@ -0,0 +1,362 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011-2015 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 <assert.h>
+
+#include "scrnintstr.h"
+#ifdef RANDR
+#include "randrstr.h"
+#endif
+
+#include "XorgGlue.h"
+
+#ifdef RANDR
+extern RRModePtr vncRandRModeGet(int width, int height);
+#endif
+
+const char *vncGetDisplay(void)
+{
+  return display;
+}
+
+unsigned long vncGetServerGeneration(void)
+{
+  return serverGeneration;
+}
+
+int vncGetScreenCount(void)
+{
+  return screenInfo.numScreens;
+}
+
+void vncGetScreenFormat(int scrIdx, int *depth, int *bpp,
+                        int *trueColour, int *bigEndian,
+                        int *redMask, int *greenMask, int *blueMask)
+{
+  int i;
+  VisualPtr vis = NULL;
+
+  assert(depth);
+  assert(bpp);
+  assert(trueColour);
+  assert(bigEndian);
+  assert(redMask);
+  assert(greenMask);
+  assert(blueMask);
+
+  *depth = screenInfo.screens[scrIdx]->rootDepth;
+
+  for (i = 0; i < screenInfo.numPixmapFormats; i++) {
+    if (screenInfo.formats[i].depth == *depth) {
+      *bpp = screenInfo.formats[i].bitsPerPixel;
+      break;
+    }
+  }
+
+  if (i == screenInfo.numPixmapFormats)
+    FatalError("No pixmap format for root depth\n");
+
+  *bigEndian = (screenInfo.imageByteOrder == MSBFirst);
+
+  for (i = 0; i < screenInfo.screens[scrIdx]->numVisuals; i++) {
+    if (screenInfo.screens[scrIdx]->visuals[i].vid == 
+        screenInfo.screens[scrIdx]->rootVisual) {
+      vis = &screenInfo.screens[scrIdx]->visuals[i];
+      break;
+    }
+  }
+
+  if (i == screenInfo.screens[scrIdx]->numVisuals)
+    FatalError("No visual record for root visual\n");
+
+  *trueColour = (vis->class == TrueColor);
+
+  *redMask = vis->redMask;
+  *greenMask = vis->greenMask;
+  *blueMask = vis->blueMask;
+}
+
+int vncGetScreenWidth(int scrIdx)
+{
+  return screenInfo.screens[scrIdx]->width;
+}
+
+int vncGetScreenHeight(int scrIdx)
+{
+  return screenInfo.screens[scrIdx]->height;
+}
+
+int vncRandRResizeScreen(int scrIdx, int width, int height)
+{
+#ifdef RANDR
+  ScreenPtr pScreen = screenInfo.screens[scrIdx];
+  /* Try to retain DPI when we resize */
+  return RRScreenSizeSet(pScreen, width, height,
+                         pScreen->mmWidth * width / pScreen->width,
+                         pScreen->mmHeight * height / pScreen->height);
+#else
+  return -1;
+#endif
+}
+
+void vncRandRUpdateSetTime(int scrIdx)
+{
+#ifdef RANDR
+  rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+  rp->lastSetTime = currentTime;
+#endif
+}
+
+int vncRandRHasOutputClones(int scrIdx)
+{
+#ifdef RANDR
+  rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+  for (int i = 0;i < rp->numCrtcs;i++) {
+    if (rp->crtcs[i]->numOutputs > 1)
+      return 1;
+  }
+#endif
+  return 0;
+}
+
+int vncRandRGetOutputCount(int scrIdx)
+{
+#ifdef RANDR
+  rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+  return rp->numOutputs;
+#else
+  return 0;
+#endif
+}
+
+int vncRandRGetAvailableOutputs(int scrIdx)
+{
+#ifdef RANDR
+  rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+  int availableOutputs;
+  RRCrtcPtr *usedCrtcs;
+  int numUsed;
+
+  int i, j, k;
+
+  usedCrtcs = malloc(sizeof(RRCrtcPtr) * rp->numCrtcs);
+  if (usedCrtcs == NULL)
+    return 0;
+
+  /*
+   * This gets slightly complicated because we might need to hook a CRTC
+   * up to the output, but also check that we don't try to use the same
+   * CRTC for multiple outputs.
+   */
+  availableOutputs = 0;
+  numUsed = 0;
+  for (i = 0;i < rp->numOutputs;i++) {
+    RROutputPtr output;
+
+    output = rp->outputs[i];
+
+    if (output->crtc != NULL)
+      availableOutputs++;
+    else {
+      for (j = 0;j < output->numCrtcs;j++) {
+        if (output->crtcs[j]->numOutputs != 0)
+          continue;
+
+        for (k = 0;k < numUsed;k++) {
+          if (usedCrtcs[k] == output->crtcs[j])
+            break;
+        }
+        if (k != numUsed)
+          continue;
+
+        availableOutputs++;
+
+        usedCrtcs[numUsed] = output->crtcs[j];
+        numUsed++;
+
+        break;
+      }
+    }
+  }
+
+  free(usedCrtcs);
+
+  return availableOutputs;
+#else
+  return 0;
+#endif
+}
+
+const char *vncRandRGetOutputName(int scrIdx, int outputIdx)
+{
+#ifdef RANDR
+  rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+  return rp->outputs[outputIdx]->name;
+#else
+  return "";
+#endif
+}
+
+int vncRandRIsOutputEnabled(int scrIdx, int outputIdx)
+{
+#ifdef RANDR
+  rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+  if (rp->outputs[outputIdx]->crtc == NULL)
+    return 0;
+  if (rp->outputs[outputIdx]->crtc->mode == NULL)
+    return 0;
+
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+int vncRandRIsOutputUsable(int scrIdx, int outputIdx)
+{
+#ifdef RANDR
+  rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+  RROutputPtr output;
+  int i;
+
+  output = rp->outputs[outputIdx];
+  if (output->crtc != NULL)
+    return 1;
+
+  /* Any unused CRTCs? */
+  for (i = 0;i < output->numCrtcs;i++) {
+    if (output->crtcs[i]->numOutputs == 0)
+      return 1;
+  }
+#endif
+
+  return 0;
+}
+
+int vncRandRDisableOutput(int scrIdx, int outputIdx)
+{
+#ifdef RANDR
+  rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+  RRCrtcPtr crtc;
+
+  crtc = rp->outputs[outputIdx]->crtc;
+  if (crtc == NULL)
+    return 0;
+
+  return RRCrtcSet(crtc, NULL, crtc->x, crtc->y, crtc->rotation, 0, NULL);
+#else
+  return -1;
+#endif
+}
+
+intptr_t vncRandRGetOutputId(int scrIdx, int outputIdx)
+{
+#ifdef RANDR
+  rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+  return (intptr_t)rp->outputs[outputIdx];
+#else
+  return 0;
+#endif
+}
+
+void vncRandRGetOutputDimensions(int scrIdx, int outputIdx,
+                            int *x, int *y, int *width, int *height)
+{
+#ifdef RANDR
+  rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+  *x = rp->outputs[outputIdx]->crtc->x;
+  *y = rp->outputs[outputIdx]->crtc->y;
+  *width = rp->outputs[outputIdx]->crtc->mode->mode.width;
+  *height = rp->outputs[outputIdx]->crtc->mode->mode.height;
+#endif
+}
+
+#ifdef RANDR
+static RRModePtr findRandRMode(RROutputPtr output, int width, int height)
+{
+  RRModePtr mode;
+
+  for (int i = 0;i < output->numModes;i++) {
+    if ((output->modes[i]->mode.width == width) &&
+        (output->modes[i]->mode.height == height))
+      return output->modes[i];
+  }
+
+  mode = vncRandRModeGet(width, height);
+  if (mode != NULL)
+    return mode;
+
+  return NULL;
+}
+#endif
+
+int vncRandRReconfigureOutput(int scrIdx, int outputIdx, int x, int y,
+                              int width, int height)
+{
+#ifdef RANDR
+  rrScrPrivPtr rp = rrGetScrPriv(screenInfo.screens[scrIdx]);
+
+  RROutputPtr output;
+  RRCrtcPtr crtc;
+  RRModePtr mode;
+
+  int i;
+
+  output = rp->outputs[outputIdx];
+  crtc = output->crtc;
+
+  /* Need a CRTC? */
+  if (crtc == NULL) {
+    for (i = 0;i < output->numCrtcs;i++) {
+      if (output->crtcs[i]->numOutputs != 0)
+        continue;
+
+      crtc = output->crtcs[i];
+      break;
+    }
+
+    /* Couldn't find one... */
+    if (crtc == NULL)
+      return -1;
+  }
+
+  mode = crtc->mode;
+
+  /* Need to switch mode? */
+  if ((mode == NULL) ||
+      (mode->mode.width != width) || (mode->mode.height != height)) {
+    mode = findRandRMode(output, width, height);
+    if (mode == NULL)
+      return -1;
+  }
+
+  /* Reconfigure new mode and position */
+  return RRCrtcSet(crtc, mode, x, y, crtc->rotation, 1, &output);
+#else
+  return -1;
+#endif
+}
diff --git a/unix/xserver/hw/vnc/XorgGlue.h b/unix/xserver/hw/vnc/XorgGlue.h
new file mode 100644 (file)
index 0000000..abca48d
--- /dev/null
@@ -0,0 +1,67 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011-2015 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.
+ */
+
+#ifndef XORG_GLUE_H
+#define XORG_GLUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *vncGetDisplay(void);
+unsigned long vncGetServerGeneration(void);
+
+int vncGetScreenCount(void);
+
+void vncGetScreenFormat(int scrIdx, int *depth, int *bpp,
+                        int *trueColour, int *bigEndian,
+                        int *redMask, int *greenMask, int *blueMask);
+
+int vncGetScreenWidth(int scrIdx);
+int vncGetScreenHeight(int scrIdx);
+
+int vncRandRResizeScreen(int scrIdx, int width, int height);
+void vncRandRUpdateSetTime(int scrIdx);
+
+int vncRandRHasOutputClones(int scrIdx);
+
+int vncRandRGetOutputCount(int scrIdx);
+int vncRandRGetAvailableOutputs(int scrIdx);
+
+const char *vncRandRGetOutputName(int scrIdx, int outputIdx);
+
+int vncRandRIsOutputEnabled(int scrIdx, int outputIdx);
+int vncRandRIsOutputUsable(int scrIdx, int outputIdx);
+
+int vncRandRDisableOutput(int scrIdx, int outputIdx);
+int vncRandRReconfigureOutput(int scrIdx, int outputIdx, int x, int y,
+                              int width, int height);
+
+intptr_t vncRandRGetOutputId(int scrIdx, int outputIdx);
+void vncRandRGetOutputDimensions(int scrIdx, int outputIdx,
+                                 int *x, int *y, int *width, int *height);
+
+// This one hides in xvnc.c or vncModule.c
+int vncRandRCreateOutputs(int scrIdx, int extraOutputs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 3ab1103488d012f237907f6fd61937e462867bdb..3774b7f6ffa718210c32d9065b8e1c3e396755ba 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright 2009-2011 Pierre Ossman for Cendio AB
+ * Copyright 2009-2015 Pierre Ossman for Cendio AB
  * Copyright 2014 Brian P. Hinz
  * 
  * This is free software; you can redistribute it and/or modify
 // XserverDesktop.cxx
 //
 
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
 #include <assert.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <strings.h>
 #include <unistd.h>
 #include <pwd.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <sys/utsname.h>
+
 #include <network/TcpSocket.h>
 #include <rfb/Exception.h>
 #include <rfb/VNCServerST.h>
 #include <rfb/HTTPServer.h>
 #include <rfb/LogWriter.h>
 #include <rfb/Configuration.h>
+#include <rfb/ServerCore.h>
+
 #include "XserverDesktop.h"
 #include "vncExtInit.h"
-#include "xorg-version.h"
+#include "vncHooks.h"
+#include "XorgGlue.h"
 #include "Input.h"
 
-extern "C" {
-#define public c_public
-#define class c_class
-
-#ifdef RANDR
-#include "randrstr.h"
-#endif
-#include "cursorstr.h"
-#undef public
-#undef class
-}
+// Hack to catch when inetd has let us go
+extern "C" void vncClientGone(int fd);
 
 using namespace rfb;
 using namespace network;
 
 static LogWriter vlog("XserverDesktop");
 
-IntParameter queryConnectTimeout("QueryConnectTimeout",
-                                 "Number of seconds to show the Accept Connection dialog before "
-                                 "rejecting the connection",
-                                 10);
-
-static rdr::U8 reverseBits[] = {
-  0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0,
-  0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
-  0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4,
-  0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
-  0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc,
-  0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
-  0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca,
-  0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
-  0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6,
-  0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
-  0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
-  0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
-  0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
-  0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
-  0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd,
-  0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
-  0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3,
-  0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
-  0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7,
-  0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
-  0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf,
-  0x3f, 0xbf, 0x7f, 0xff
-};
-
-
 class FileHTTPServer : public rfb::HTTPServer {
 public:
   FileHTTPServer(XserverDesktop* d) : desktop(d) {}
@@ -132,22 +93,22 @@ public:
 };
 
 
-XserverDesktop::XserverDesktop(ScreenPtr pScreen_,
+XserverDesktop::XserverDesktop(int screenIndex_,
                                network::TcpListener* listener_,
                                network::TcpListener* httpListener_,
                                const char* name, const rfb::PixelFormat &pf,
+                               int width, int height,
                                void* fbptr, int stride)
-  : pScreen(pScreen_),
+  : screenIndex(screenIndex_),
     server(0), httpServer(0),
     listener(listener_), httpListener(httpListener_),
-    deferredUpdateTimerSet(false),
-    grabbing(false), ignoreHooks_(false), directFbptr(true),
+    deferredUpdateTimerSet(false), directFbptr(true),
     queryConnectId(0)
 {
   format = pf;
 
   server = new VNCServerST(name, this);
-  setFramebuffer(pScreen->width, pScreen->height, fbptr, stride);
+  setFramebuffer(width, height, fbptr, stride);
   server->setQueryConnectionHandler(this);
 
   if (httpListener)
@@ -206,25 +167,21 @@ void XserverDesktop::refreshScreenLayout()
 ScreenSet XserverDesktop::computeScreenLayout()
 {
   ScreenSet layout;
-
-#ifdef RANDR
-  rrScrPrivPtr rp = rrGetScrPriv(pScreen);
   OutputIdMap newIdMap;
 
-  for (int i = 0;i < rp->numOutputs;i++) {
-      RROutputPtr output;
-      RRCrtcPtr crtc;
-
-      output = rp->outputs[i];
-      crtc = output->crtc;
+  for (int i = 0;i < vncRandRGetOutputCount(screenIndex);i++) {
+      intptr_t outputId;
+      int x, y, width, height;
 
       /* Disabled? */
-      if ((crtc == NULL) || (crtc->mode == NULL))
+      if (!vncRandRIsOutputEnabled(screenIndex, i))
           continue;
 
+      outputId = vncRandRGetOutputId(screenIndex, i);
+
       /* Known output? */
-      if (outputIdMap.count(output) == 1)
-        newIdMap[output] = outputIdMap[output];
+      if (outputIdMap.count(outputId) == 1)
+        newIdMap[outputId] = outputIdMap[outputId];
       else {
         rdr::U32 id;
         OutputIdMap::const_iterator iter;
@@ -239,52 +196,28 @@ ScreenSet XserverDesktop::computeScreenLayout()
             break;
         }
 
-        newIdMap[output] = id;
+        newIdMap[outputId] = id;
       }
 
-      layout.add_screen(Screen(newIdMap[output], crtc->x, crtc->y,
-                               crtc->mode->mode.width,
-                               crtc->mode->mode.height,
-                               0));
+      vncRandRGetOutputDimensions(screenIndex, i, &x, &y, &width, &height);
+
+      layout.add_screen(Screen(newIdMap[outputId], x, y, width, height, 0));
   }
 
   /* Only keep the entries that are currently active */
   outputIdMap = newIdMap;
-#endif
 
   /*
    * Make sure we have something to display. Hopefully it's just temporary
    * that we have no active outputs...
    */
   if (layout.num_screens() == 0)
-    layout.add_screen(Screen(0, 0, 0, pScreen->width, pScreen->height, 0));
+    layout.add_screen(Screen(0, 0, 0, vncGetScreenWidth(screenIndex),
+                             vncGetScreenHeight(screenIndex), 0));
 
   return layout;
 }
 
-#ifdef RANDR
-
-extern RRModePtr vncRandRModeGet(int width, int height);
-
-RRModePtr XserverDesktop::findRandRMode(RROutputPtr output, int width, int height)
-{
-  RRModePtr mode;
-
-  for (int i = 0;i < output->numModes;i++) {
-    if ((output->modes[i]->mode.width == width) &&
-        (output->modes[i]->mode.height == height))
-      return output->modes[i];
-  }
-
-  mode = vncRandRModeGet(width, height);
-  if (mode != NULL)
-    return mode;
-
-  return NULL;
-}
-
-#endif
-
 char* XserverDesktop::substitute(const char* varName)
 {
   if (strcmp(varName, "$$") == 0) {
@@ -325,7 +258,7 @@ char* XserverDesktop::substitute(const char* varName)
     strncpy(str, uts.nodename, 240);
     str[239] = '\0'; /* Ensure string is zero-terminated */
     strcat(str, ":");
-    strncat(str, display, 10);
+    strncat(str, vncGetDisplay(), 10);
     return str;
   }
   if (strcmp(varName, "$USER") == 0) {
@@ -338,17 +271,28 @@ char* XserverDesktop::substitute(const char* varName)
 rfb::VNCServerST::queryResult
 XserverDesktop::queryConnection(network::Socket* sock,
                                 const char* userName,
-                                char** reason) {
+                                char** reason)
+{
+  int count;
+
   if (queryConnectId) {
     *reason = strDup("Another connection is currently being queried.");
     return rfb::VNCServerST::REJECT;
   }
+
   queryConnectAddress.replaceBuf(sock->getPeerAddress());
   if (!userName)
     userName = "(anonymous)";
   queryConnectUsername.replaceBuf(strDup(userName));
-  queryConnectId = sock;
-  vncQueryConnect(this, sock);
+  queryConnectId = (uint32_t)(intptr_t)sock;
+  queryConnectSocket = sock;
+
+  count = vncNotifyQueryConnect();
+  if (count == 0) {
+    *reason = strDup("Unable to query the local user to accept the connection.");
+    return rfb::VNCServerST::REJECT;
+  }
+
   return rfb::VNCServerST::PENDING;
 }
 
@@ -375,148 +319,77 @@ void XserverDesktop::setDesktopName(const char* name)
   }
 }
 
-void XserverDesktop::setCursor(CursorPtr cursor)
+void XserverDesktop::setCursor(int width, int height, int hotX, int hotY,
+                               const unsigned char *rgbaData)
 {
-  try {
-    int w = cursor->bits->width;
-    int h = cursor->bits->height;
-
-    rdr::U8* cursorData = new rdr::U8[w * h * (getPF().bpp / 8)];
-
-    int rfbMaskBytesPerRow = (w + 7) / 8;
+  rdr::U8* cursorData;
+  rdr::U8* cursorMask;
+  int rfbMaskBytesPerRow;
 
-    rdr::U8* cursorMask = new rdr::U8[rfbMaskBytesPerRow * h];
+  rdr::U8 *out;
+  const unsigned char *in;
+  rdr::U8 rgb[3];
 
-#ifdef ARGB_CURSOR
-    if (cursor->bits->argb) {
-      rdr::U8 *out;
-      CARD32 *in;
+  cursorData = new rdr::U8[width * height * (getPF().bpp / 8)];
 
-      rdr::U8 rgb[3];
+  rfbMaskBytesPerRow = (width + 7) / 8;
 
-      memset(cursorMask, 0, rfbMaskBytesPerRow * h);
+  cursorMask = new rdr::U8[rfbMaskBytesPerRow * height];
 
-      in = cursor->bits->argb;
-      out = cursorData;
-      for (int y = 0; y < h; y++) {
-        for (int x = 0; x < w; x++) {
-          rgb[0] = (*in >> 16) & 0xff;
-          rgb[1] = (*in >>  8) & 0xff;
-          rgb[2] = (*in >>  0) & 0xff;
+  memset(cursorMask, 0, rfbMaskBytesPerRow * height);
 
-          getPF().bufferFromRGB(out, rgb, 1);
+  in = rgbaData;
+  out = cursorData;
+  for (int y = 0; y < height; y++) {
+    for (int x = 0; x < width; x++) {
+      rgb[0] = *in++;
+      rgb[1] = *in++;
+      rgb[2] = *in++;
 
-          if (((*in >> 24) & 0xff) > 127)
-            cursorMask[y * rfbMaskBytesPerRow + x/8] |= 0x80>>(x%8);
+      getPF().bufferFromRGB(out, rgb, 1);
 
-          in++;
-          out += getPF().bpp/8;
-        }
-      }
-    } else {
-#endif
-      rdr::U8 rgb[3];
-      rdr::U8 fg[4], bg[4];
-
-      rdr::U8* buffer;
-
-      rgb[0] = cursor->foreRed;
-      rgb[1] = cursor->foreGreen;
-      rgb[2] = cursor->foreBlue;
-      getPF().bufferFromRGB(fg, rgb, 1);
-
-      rgb[0] = cursor->backRed;
-      rgb[1] = cursor->backGreen;
-      rgb[2] = cursor->backBlue;
-      getPF().bufferFromRGB(bg, rgb, 1);
-
-      int xMaskBytesPerRow = BitmapBytePad(w);
-
-      buffer = cursorData;
-
-      for (int y = 0; y < h; y++) {
-        for (int x = 0; x < w; x++) {
-          rdr::U8 *pixel;
-          int byte = y * xMaskBytesPerRow + x / 8;
-#if (BITMAP_BIT_ORDER == MSBFirst)
-          int bit = 7 - x % 8;
-#else
-          int bit = x % 8;
-#endif
-
-          if (cursor->bits->source[byte] & (1 << bit))
-            pixel = fg;
-          else
-            pixel = bg;
-
-          memcpy(buffer, pixel, getPF().bpp/8);
-          buffer += getPF().bpp/8;
-        }
-      }
+      if (*in++ > 127)
+        cursorMask[y * rfbMaskBytesPerRow + x/8] |= 0x80>>(x%8);
 
-      for (int j = 0; j < h; j++) {
-        for (int i = 0; i < rfbMaskBytesPerRow; i++)
-#if (BITMAP_BIT_ORDER == MSBFirst)
-          cursorMask[j * rfbMaskBytesPerRow + i]
-            = cursor->bits->mask[j * xMaskBytesPerRow + i];
-#else
-          cursorMask[j * rfbMaskBytesPerRow + i]
-            = reverseBits[cursor->bits->mask[j * xMaskBytesPerRow + i]];
-#endif
-      }
-#ifdef ARGB_CURSOR
+      out += getPF().bpp/8;
     }
-#endif
+  }
 
-    server->setCursor(cursor->bits->width, cursor->bits->height,
-                      Point(cursor->bits->xhot, cursor->bits->yhot),
-                      cursorData, cursorMask);
-    delete [] cursorData;
-    delete [] cursorMask;
+  try {
+    server->setCursor(width, height, Point(hotX, hotY), cursorData, cursorMask);
   } catch (rdr::Exception& e) {
     vlog.error("XserverDesktop::setCursor: %s",e.str());
   }
+
+  delete [] cursorData;
+  delete [] cursorMask;
 }
 
-void XserverDesktop::add_changed(RegionPtr reg)
+void XserverDesktop::add_changed(const rfb::Region &region)
 {
-  if (ignoreHooks_) return;
-  if (grabbing) return;
   try {
-    rfb::Region rfbReg;
-    rfbReg.setExtentsAndOrderedRects((ShortRect*)REGION_EXTENTS(pScreen, reg),
-                                     REGION_NUM_RECTS(reg),
-                                     (ShortRect*)REGION_RECTS(reg));
-    server->add_changed(rfbReg);
+    server->add_changed(region);
   } catch (rdr::Exception& e) {
     vlog.error("XserverDesktop::add_changed: %s",e.str());
   }
 }
 
-void XserverDesktop::add_copied(RegionPtr dst, int dx, int dy)
+void XserverDesktop::add_copied(const rfb::Region &dest, const rfb::Point &delta)
 {
-  if (ignoreHooks_) return;
-  if (grabbing) return;
   try {
-    rfb::Region rfbReg;
-    rfbReg.setExtentsAndOrderedRects((ShortRect*)REGION_EXTENTS(pScreen, dst),
-                                     REGION_NUM_RECTS(dst),
-                                     (ShortRect*)REGION_RECTS(dst));
-    server->add_copied(rfbReg, rfb::Point(dx, dy));
+    server->add_copied(dest, delta);
   } catch (rdr::Exception& e) {
     vlog.error("XserverDesktop::add_copied: %s",e.str());
   }
 }
 
-static struct timeval XserverDesktopTimeout;
-
-void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout)
+void XserverDesktop::readBlockHandler(fd_set* fds, struct timeval ** 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.
-  vncInputDevice->InitInputDevice();
+  vncInitInputDevice();
 
   try {
     int nextTimeout;
@@ -565,9 +438,9 @@ void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout)
           ((*timeout)->tv_sec > (nextTimeout/1000)) ||
           (((*timeout)->tv_sec == (nextTimeout/1000)) &&
            ((*timeout)->tv_usec > ((nextTimeout%1000)*1000)))) {
-        XserverDesktopTimeout.tv_sec = nextTimeout/1000;
-        XserverDesktopTimeout.tv_usec = (nextTimeout%1000)*1000;
-        *timeout = &XserverDesktopTimeout;
+        dixTimeout.tv_sec = nextTimeout/1000;
+        dixTimeout.tv_usec = (nextTimeout%1000)*1000;
+        *timeout = &dixTimeout;
       }
     }
 
@@ -576,7 +449,7 @@ void XserverDesktop::blockHandler(fd_set* fds, OSTimePtr timeout)
   }
 }
 
-void XserverDesktop::wakeupHandler(fd_set* fds, int nfds)
+void XserverDesktop::readWakeupHandler(fd_set* fds, int nfds)
 {
   try {
     // First check for file descriptors with something to do
@@ -625,8 +498,11 @@ void XserverDesktop::wakeupHandler(fd_set* fds, int nfds)
       }
 
       // We are responsible for propagating mouse movement between clients
-      if (!oldCursorPos.equals(vncInputDevice->getPointerPos())) {
-        oldCursorPos = vncInputDevice->getPointerPos();
+      int cursorX, cursorY;
+      vncGetPointerPos(&cursorX, &cursorY);
+      if (oldCursorPos.x != cursorX || oldCursorPos.y != cursorY) {
+        oldCursorPos.x = cursorX;
+        oldCursorPos.y = cursorY;
         server->setCursorPos(oldCursorPos);
       }
     }
@@ -639,7 +515,7 @@ void XserverDesktop::wakeupHandler(fd_set* fds, int nfds)
   }
 }
 
-void XserverDesktop::writeBlockHandler(fd_set* fds)
+void XserverDesktop::writeBlockHandler(fd_set* fds, struct timeval ** timeout)
 {
   try {
     std::list<Socket*> sockets;
@@ -724,26 +600,29 @@ void XserverDesktop::disconnectClients()
 }
 
 
-int XserverDesktop::getQueryTimeout(void* opaqueId,
-                                    const char** address,
-                                    const char** username)
+void XserverDesktop::getQueryConnect(uint32_t* opaqueId,
+                                     const char** address,
+                                     const char** username,
+                                     int *timeout)
 {
-  if (opaqueId && queryConnectId == opaqueId) {
-    vlog.info("address=%s, username=%s, timeout=%d",
-              queryConnectAddress.buf, queryConnectUsername.buf,
-              (int)queryConnectTimeout);
-    if (address) *address = queryConnectAddress.buf;
-    if (username) *username = queryConnectUsername.buf;
-    return queryConnectTimeout;
+  *opaqueId = queryConnectId;
+
+  if (queryConnectId == 0) {
+    *address = "";
+    *username = "";
+    *timeout = 0;
+  } else {
+    *address = queryConnectAddress.buf;
+    *username = queryConnectUsername.buf;
+    *timeout = rfb::Server::queryConnectTimeout;
   }
-  return 0;
 }
 
-void XserverDesktop::approveConnection(void* opaqueId, bool accept,
+void XserverDesktop::approveConnection(uint32_t opaqueId, bool accept,
                                        const char* rejectMsg)
 {
   if (queryConnectId == opaqueId) {
-    server->approveConnection((network::Socket*)opaqueId, accept, rejectMsg);
+    server->approveConnection(queryConnectSocket, accept, rejectMsg);
     queryConnectId = 0;
   }
 }
@@ -755,8 +634,8 @@ void XserverDesktop::approveConnection(void* opaqueId, bool accept,
 
 void XserverDesktop::pointerEvent(const Point& pos, int buttonMask)
 {
-  vncInputDevice->PointerMove(pos);
-  vncInputDevice->PointerButtonAction(buttonMask);
+  vncPointerMove(pos.x, pos.y);
+  vncPointerButtonAction(buttonMask);
 }
 
 void XserverDesktop::clientCutText(const char* str, int len)
@@ -764,79 +643,42 @@ void XserverDesktop::clientCutText(const char* str, int len)
   vncClientCutText(str, len);
 }
 
-extern RROutputPtr vncRandROutputCreate(ScreenPtr pScreen);
-
 unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
                                              const rfb::ScreenSet& layout)
 {
-#ifndef RANDR
-  return rfb::resultProhibited;
-#else
+  int ret;
   int availableOutputs;
-  Bool ret;
 
-  rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+  // RandR support?
+  if (vncRandRGetOutputCount(screenIndex) == 0)
+    return rfb::resultProhibited;
 
   /*
    * First check that we don't have any active clone modes. That's just
    * too messy to deal with.
    */
-  for (int i = 0;i < rp->numCrtcs;i++) {
-    if (rp->crtcs[i]->numOutputs > 1) {
-      vlog.error("Clone mode active. Refusing to touch screen layout.");
-      return rfb::resultInvalid;
-    }
+  if (vncRandRHasOutputClones(screenIndex)) {
+    vlog.error("Clone mode active. Refusing to touch screen layout.");
+    return rfb::resultInvalid;
   }
 
-  /*
-   * Next count how many useful outputs we have...
-   *
-   * This gets slightly complicated because we might need to hook a CRTC
-   * up to the output, but also check that we don't try to use the same
-   * CRTC for multiple outputs.
-   */
-  std::set<RRCrtcPtr> usedCrtcs;
-  availableOutputs = 0;
-  for (int i = 0;i < rp->numOutputs;i++) {
-    RROutputPtr output;
-
-    output = rp->outputs[i];
-
-    if (output->crtc != NULL)
-      availableOutputs++;
-    else {
-      for (int j = 0;j < output->numCrtcs;j++) {
-        if (output->crtcs[j]->numOutputs != 0)
-          continue;
-        if (usedCrtcs.count(output->crtcs[j]) != 0)
-          continue;
-
-        availableOutputs++;
-        usedCrtcs.insert(output->crtcs[j]);
-
-        break;
-      }
-    }
-  }
+  /* Next count how many useful outputs we have... */
+  availableOutputs = vncRandRGetAvailableOutputs(screenIndex);
 
   /* Try to create more outputs if needed... (only works on Xvnc) */
   if (layout.num_screens() > availableOutputs) {
-    for (int i = 0;i < (layout.num_screens() - availableOutputs);i++) {
-      RROutputPtr output;
-      output = vncRandROutputCreate(pScreen);
-      if (output == NULL) {
-        vlog.error("Unable to create more screens, as needed by the new client layout.");
-        return rfb::resultInvalid;
-      }
+    ret = vncRandRCreateOutputs(screenIndex,
+                                layout.num_screens() - availableOutputs);
+    if (ret < 0) {
+      vlog.error("Unable to create more screens, as needed by the new client layout.");
+      return rfb::resultInvalid;
     }
   }
 
   /* First we might need to resize the screen */
-  if ((fb_width != pScreen->width) || (fb_height != pScreen->height)) {
-    /* Try to retain DPI when we resize */
-    ret = RRScreenSizeSet(pScreen, fb_width, fb_height,
-                          pScreen->mmWidth * fb_width / pScreen->width,
-                          pScreen->mmHeight * fb_height / pScreen->height);
+  if ((fb_width != vncGetScreenWidth(screenIndex)) ||
+      (fb_height != vncGetScreenHeight(screenIndex))) {
+    ret = vncRandRResizeScreen(screenIndex, fb_width, fb_height);
     if (!ret) {
       vlog.error("Failed to resize screen to %dx%d", fb_width, fb_height);
       return rfb::resultInvalid;
@@ -844,27 +686,17 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
   }
 
   /* Next, reconfigure all known outputs, and turn off the other ones */
-  for (int i = 0;i < rp->numOutputs;i++) {
-    RROutputPtr output;
-    RRCrtcPtr crtc;
-    RRModePtr mode;
+  for (int i = 0;i < vncRandRGetOutputCount(screenIndex);i++) {
+    intptr_t output;
 
     ScreenSet::const_iterator iter;
 
-    output = rp->outputs[i];
-    crtc = output->crtc;
+    output = vncRandRGetOutputId(screenIndex, i);
 
     /* Known? */
     if (outputIdMap.count(output) == 0)
       continue;
 
-    /* A known output should have a CRTC, but double check... */
-    if (crtc == NULL) {
-      vlog.error("Existing output '%s' has unexpectedly been disabled",
-                 output->name);
-      continue;
-    }
-
     /* Find the corresponding screen... */
     for (iter = layout.begin();iter != layout.end();++iter) {
       if (iter->id == outputIdMap[output])
@@ -874,37 +706,25 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
     /* Missing? */
     if (iter == layout.end()) {
       /* Disable and move on... */
-      ret = RRCrtcSet(crtc, NULL, crtc->x, crtc->y, crtc->rotation, 0, NULL);
+      ret = vncRandRDisableOutput(screenIndex, i);
       if (!ret) {
-        vlog.error("Failed to disable unused CRTC for output '%s'",
-                   output->name);
+        vlog.error("Failed to disable unused output '%s'",
+                   vncRandRGetOutputName(screenIndex, i));
         return rfb::resultInvalid;
       }
       outputIdMap.erase(output);
       continue;
     }
 
-    /* Need to switch mode? */
-    if ((crtc->mode->mode.width == iter->dimensions.width()) &&
-        (crtc->mode->mode.height == iter->dimensions.height()))
-      mode = crtc->mode;
-    else {
-      mode = findRandRMode(output, iter->dimensions.width(),
-                           iter->dimensions.height());
-      if (mode == NULL) {
-        vlog.error("Failed to find a suitable mode for %dx%d for output '%s'",
-                   iter->dimensions.width(), iter->dimensions.height(),
-                   output->name);
-        return rfb::resultInvalid;
-      }
-    }
-
     /* Reconfigure new mode and position */
-    ret = RRCrtcSet(crtc, mode, iter->dimensions.tl.x, iter->dimensions.tl.y,
-                    crtc->rotation, crtc->numOutputs, crtc->outputs);
+    ret = vncRandRReconfigureOutput(screenIndex, i,
+                                    iter->dimensions.tl.x,
+                                    iter->dimensions.tl.y,
+                                    iter->dimensions.width(),
+                                    iter->dimensions.height());
     if (!ret) {
       vlog.error("Failed to reconfigure output '%s' to %dx%d+%d+%d",
-                 output->name,
+                 vncRandRGetOutputName(screenIndex, i),
                  iter->dimensions.width(), iter->dimensions.height(),
                  iter->dimensions.tl.x, iter->dimensions.tl.y);
       return rfb::resultInvalid;
@@ -915,11 +735,7 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
   ScreenSet::const_iterator iter;
   for (iter = layout.begin();iter != layout.end();++iter) {
     OutputIdMap::const_iterator oi;
-
-    RROutputPtr output;
-    RRCrtcPtr crtc;
-    RRModePtr mode;
-
+    intptr_t output;
     int i;
 
     /* Does this screen have an output already? */
@@ -932,53 +748,24 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
       continue;
 
     /* Find an unused output */
-    for (i = 0;i < rp->numOutputs;i++) {
-      output = rp->outputs[i];
-      crtc = output->crtc;
+    for (i = 0;i < vncRandRGetOutputCount(screenIndex);i++) {
+      output = vncRandRGetOutputId(screenIndex, i);
 
       /* In use? */
       if (outputIdMap.count(output) == 1)
         continue;
 
-      /* Need a CRTC? */
-      if (crtc == NULL) {
-        for (int j = 0;j < output->numCrtcs;j++) {
-          if (output->crtcs[j]->numOutputs != 0)
-            continue;
-
-          crtc = output->crtcs[j];
-          break;
-        }
-
-        /* Couldn't find one... */
-        if (crtc == NULL)
-          continue;
-
-        ret = RRCrtcSet(crtc, NULL, 0, 0, RR_Rotate_0,
-                        1, &output);
-        if (!ret) {
-          vlog.error("Failed to associate a CRTC with output '%s'",
-                     output->name);
-          return rfb::resultInvalid;
-        }
-      }
+      /* Can it be used? */
+      if (!vncRandRIsOutputUsable(screenIndex, i))
+        continue;
 
       break;
     }
 
     /* Shouldn't happen */
-    if (i == rp->numOutputs)
+    if (i == vncRandRGetOutputCount(screenIndex))
         return rfb::resultInvalid;
 
-    mode = findRandRMode(output, iter->dimensions.width(),
-                         iter->dimensions.height());
-    if (mode == NULL) {
-      vlog.error("Failed to find a suitable mode for %dx%d for output '%s'",
-                 iter->dimensions.width(), iter->dimensions.height(),
-                 output->name);
-      return rfb::resultInvalid;
-    }
-
     /*
      * Make sure we already have an entry for this, or
      * computeScreenLayout() will think it is a brand new output and
@@ -987,11 +774,14 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
     outputIdMap[output] = iter->id;
 
     /* Reconfigure new mode and position */
-    ret = RRCrtcSet(crtc, mode,  iter->dimensions.tl.x, iter->dimensions.tl.y,
-                    crtc->rotation, crtc->numOutputs, crtc->outputs);
+    ret = vncRandRReconfigureOutput(screenIndex, i,
+                                    iter->dimensions.tl.x,
+                                    iter->dimensions.tl.y,
+                                    iter->dimensions.width(),
+                                    iter->dimensions.height());
     if (!ret) {
       vlog.error("Failed to reconfigure output '%s' to %dx%d+%d+%d",
-                 output->name,
+                 vncRandRGetOutputName(screenIndex, i),
                  iter->dimensions.width(), iter->dimensions.height(),
                  iter->dimensions.tl.x, iter->dimensions.tl.y);
       return rfb::resultInvalid;
@@ -1003,50 +793,31 @@ unsigned int XserverDesktop::setScreenLayout(int fb_width, int fb_height,
    * This is normally done in the X11 request handlers, which is
    * why we have to deal with it manually here.
    */
-  rp->lastSetTime = currentTime;
+  vncRandRUpdateSetTime(screenIndex);
 
   return rfb::resultSuccess;
-#endif
 }
 
 void XserverDesktop::grabRegion(const rfb::Region& region)
 {
-  if (directFbptr) return;
-  if (!pScreen->GetImage) {
-    vlog.error("VNC error: pScreen->GetImage == 0");
+  if (directFbptr)
     return;
-  }
-
-  grabbing = true;
-
-  int bytesPerPixel = format.bpp/8;
-  int bytesPerRow = pScreen->width * bytesPerPixel;
 
   std::vector<rfb::Rect> rects;
   std::vector<rfb::Rect>::iterator i;
   region.get_rects(&rects);
   for (i = rects.begin(); i != rects.end(); i++) {
-    for (int y = i->tl.y; y < i->br.y; y++) {
-      DrawablePtr pDrawable;
-#if XORG < 19
-      pDrawable = (DrawablePtr) WindowTable[pScreen->myNum];
-#else
-      pDrawable = (DrawablePtr) pScreen->root;
-#endif
-
-      (*pScreen->GetImage) (pDrawable, i->tl.x, y, i->width(), 1,
-                            ZPixmap, (unsigned long)~0L,
-                            ((char*)data
-                             + y * bytesPerRow + i->tl.x * bytesPerPixel));
-    }
+    rdr::U8 *buffer;
+    int stride;
+
+    buffer = getBufferRW(*i, &stride);
+    vncGetScreenImage(screenIndex, i->tl.x, i->tl.y, i->width(), i->height(),
+                      (char*)buffer, stride * format.bpp/8);
+    commitBufferRW(*i);
   }
-  grabbing = false;
 }
 
 void XserverDesktop::keyEvent(rdr::U32 keysym, bool down)
 {
-       if (down)
-               vncInputDevice->KeyboardPress(keysym);
-       else
-               vncInputDevice->KeyboardRelease(keysym);
+  vncKeyboardEvent(keysym, down);
 }
index 5b4c23000f5d6938819a515e76b5749be088d314..7dcaa29e455042d0321eef77d4eedaa34802abab 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright 2009-2011 Pierre Ossman for Cendio AB
+ * Copyright 2009-2015 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
@@ -29,6 +29,8 @@
 
 #include <map>
 
+#include <stdint.h>
+
 #include <rfb/SDesktop.h>
 #include <rfb/HTTPServer.h>
 #include <rfb/PixelBuffer.h>
 #include <rdr/SubstitutingInStream.h>
 #include "Input.h"
 
-extern "C" {
-#define class c_class
-#include <scrnintstr.h>
-#include <os.h>
-#ifdef RANDR
-#include <randrstr.h>
-#endif
-#undef class
-}
-
 namespace rfb {
   class VNCServerST;
 }
@@ -58,10 +50,10 @@ class XserverDesktop : public rfb::SDesktop, public rfb::FullFramePixelBuffer,
                        public rfb::VNCServerST::QueryConnectionHandler {
 public:
 
-  XserverDesktop(ScreenPtr pScreen, network::TcpListener* listener,
+  XserverDesktop(int screenIndex, network::TcpListener* listener,
                  network::TcpListener* httpListener_,
                  const char* name, const rfb::PixelFormat &pf,
-                 void* fbptr, int stride);
+                 int width, int height, void* fbptr, int stride);
   virtual ~XserverDesktop();
 
   // methods called from X server code
@@ -72,31 +64,27 @@ public:
   void bell();
   void serverCutText(const char* str, int len);
   void setDesktopName(const char* name);
-  void setCursor(CursorPtr cursor);
-  void add_changed(RegionPtr reg);
-  void add_copied(RegionPtr dst, int dx, int dy);
-  void ignoreHooks(bool b) { ignoreHooks_ = b; }
-  void blockHandler(fd_set* fds, OSTimePtr timeout);
-  void wakeupHandler(fd_set* fds, int nfds);
-  void writeBlockHandler(fd_set* fds);
+  void setCursor(int width, int height, int hotX, int hotY,
+                 const unsigned char *rgbaData);
+  void add_changed(const rfb::Region &region);
+  void add_copied(const rfb::Region &dest, const rfb::Point &delta);
+  void readBlockHandler(fd_set* fds, struct timeval ** timeout);
+  void readWakeupHandler(fd_set* fds, int nfds);
+  void writeBlockHandler(fd_set* fds, struct timeval ** timeout);
   void writeWakeupHandler(fd_set* fds, int nfds);
   void addClient(network::Socket* sock, bool reverse);
   void disconnectClients();
 
   // QueryConnect methods called from X server code
-  // getQueryTimeout()
-  //   Returns the timeout associated with a particular
-  //   connection, identified by an opaque Id passed to the
-  //   X code earlier.  Also optionally gets the address and
-  //   name associated with that connection.
-  //   Returns zero if the Id is not recognised.
-  int getQueryTimeout(void* opaqueId,
-                      const char** address=0,
-                      const char** username=0);
+  // getQueryConnect()
+  //   Returns information about the currently waiting query
+  //   (or an id of 0 if there is none waiting)
+  void getQueryConnect(uint32_t* opaqueId, const char** address,
+                       const char** username, int *timeout);
 
   // approveConnection()
   //   Used by X server code to supply the result of a query.
-  void approveConnection(void* opaqueId, bool accept,
+  void approveConnection(uint32_t opaqueId, bool accept,
                          const char* rejectMsg=0);
 
   // rfb::SDesktop callbacks
@@ -120,26 +108,23 @@ public:
 
 private:
   rfb::ScreenSet computeScreenLayout();
-#ifdef RANDR
-  RRModePtr findRandRMode(RROutputPtr output, int width, int height);
-#endif
 
-  ScreenPtr pScreen;
+  int screenIndex;
   rfb::VNCServerST* server;
   rfb::HTTPServer* httpServer;
   network::TcpListener* listener;
   network::TcpListener* httpListener;
   bool deferredUpdateTimerSet;
-  bool grabbing;
-  bool ignoreHooks_;
   bool directFbptr;
+  struct timeval dixTimeout;
 
-  void* queryConnectId;
+  uint32_t queryConnectId;
+  network::Socket* queryConnectSocket;
   rfb::CharArray queryConnectAddress;
   rfb::CharArray queryConnectUsername;
 
 #ifdef RANDR
-  typedef std::map<RROutputPtr, rdr::U32> OutputIdMap;
+  typedef std::map<intptr_t, rdr::U32> OutputIdMap;
   OutputIdMap outputIdMap;
 #endif
 
diff --git a/unix/xserver/hw/vnc/vncBlockHandler.c b/unix/xserver/hw/vnc/vncBlockHandler.c
new file mode 100644 (file)
index 0000000..c9a7428
--- /dev/null
@@ -0,0 +1,143 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011-2014 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 <errno.h>
+
+#include <X11/Xpoll.h>
+
+#include "dix.h"
+#include "scrnintstr.h"
+
+#include "vncExtInit.h"
+#include "vncBlockHandler.h"
+
+static void vncBlockHandler(void * data, OSTimePtr t, void * readmask);
+static void vncWakeupHandler(void * data, int nfds, void * readmask);
+void vncWriteBlockHandler(fd_set *fds);
+void vncWriteWakeupHandler(int nfds, fd_set *fds);
+
+void vncRegisterBlockHandlers(void)
+{
+  if (!RegisterBlockAndWakeupHandlers(vncBlockHandler, vncWakeupHandler, 0))
+    FatalError("RegisterBlockAndWakeupHandlers() failed\n");
+}
+
+static void vncWriteBlockHandlerFallback(OSTimePtr timeout);
+static void vncWriteWakeupHandlerFallback(void);
+
+//
+// vncBlockHandler - called just before the X server goes into select().  Call
+// on to the block handler for each desktop.  Then check whether any of the
+// selections have changed, and if so, notify any interested X clients.
+//
+
+static void vncBlockHandler(void * data, OSTimePtr timeout, void * readmask)
+{
+  fd_set* fds = (fd_set*)readmask;
+
+  vncWriteBlockHandlerFallback(timeout);
+
+  vncCallReadBlockHandlers(fds, timeout);
+}
+
+static void vncWakeupHandler(void * data, int nfds, void * readmask)
+{
+  fd_set* fds = (fd_set*)readmask;
+
+  vncCallReadWakeupHandlers(fds, nfds);
+
+  vncWriteWakeupHandlerFallback();
+}
+
+//
+// vncWriteBlockHandler - extra hack to be able to get the main select loop
+// to monitor writeable fds and not just readable. This requirers a modified
+// Xorg and might therefore not be called. When it is called though, it will
+// do so before vncBlockHandler (and vncWriteWakeupHandler called after
+// vncWakeupHandler).
+//
+
+static Bool needFallback = TRUE;
+static fd_set fallbackFds;
+static struct timeval tw;
+
+void vncWriteBlockHandler(fd_set *fds)
+{
+  struct timeval *dummy;
+
+  needFallback = FALSE;
+
+  dummy = NULL;
+  vncCallWriteBlockHandlers(fds, &dummy);
+}
+
+void vncWriteWakeupHandler(int nfds, fd_set *fds)
+{
+  vncCallWriteWakeupHandlers(fds, nfds);
+}
+
+static void vncWriteBlockHandlerFallback(OSTimePtr timeout)
+{
+  if (!needFallback)
+    return;
+
+  FD_ZERO(&fallbackFds);
+  vncWriteBlockHandler(&fallbackFds);
+
+  if (!XFD_ANYSET(&fallbackFds))
+    return;
+
+  if ((*timeout == NULL) ||
+      ((*timeout)->tv_sec > 0) || ((*timeout)->tv_usec > 10000)) {
+    tw.tv_sec = 0;
+    tw.tv_usec = 10000;
+    *timeout = &tw;
+  }
+}
+
+static void vncWriteWakeupHandlerFallback(void)
+{
+  int ret;
+  struct timeval timeout;
+
+  if (!needFallback)
+    return;
+
+  if (!XFD_ANYSET(&fallbackFds))
+    return;
+
+  timeout.tv_sec = 0;
+  timeout.tv_usec = 0;
+
+  ret = select(XFD_SETSIZE, NULL, &fallbackFds, NULL, &timeout);
+  if (ret < 0) {
+    ErrorF("vncWriteWakeupHandlerFallback(): select: %s\n",
+           strerror(errno));
+    return;
+  }
+
+  if (ret == 0)
+    return;
+
+  vncWriteWakeupHandler(ret, &fallbackFds);
+}
diff --git a/unix/xserver/hw/vnc/vncBlockHandler.h b/unix/xserver/hw/vnc/vncBlockHandler.h
new file mode 100644 (file)
index 0000000..556528b
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011-2014 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.
+ */
+
+#ifndef VNCBLOCKHANDLER_H
+#define VNCBLOCKHANDLER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void vncRegisterBlockHandlers(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/unix/xserver/hw/vnc/vncExt.c b/unix/xserver/hw/vnc/vncExt.c
new file mode 100644 (file)
index 0000000..2330eee
--- /dev/null
@@ -0,0 +1,771 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011-2015 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
+
+#define NEED_EVENTS
+#include "misc.h"
+#include "os.h"
+#include "dixstruct.h"
+#include "extnsionst.h"
+#include "scrnintstr.h"
+#include "selection.h"
+
+#define _VNCEXT_SERVER_
+#define _VNCEXT_PROTO_
+#include "vncExt.h"
+
+#include "xorg-version.h"
+
+#include "vncExtInit.h"
+#include "RFBGlue.h"
+
+static int ProcVncExtDispatch(ClientPtr client);
+static int SProcVncExtDispatch(ClientPtr client);
+static void vncResetProc(ExtensionEntry* extEntry);
+
+static void vncClientStateChange(CallbackListPtr*, void *, void *);
+
+static void vncSelectionCallback(CallbackListPtr *callbacks,
+                                 void * data, void * args);
+
+static int vncErrorBase = 0;
+static int vncEventBase = 0;
+
+int vncNoClipboard = 0;
+
+static char* clientCutText = NULL;
+static int clientCutTextLen = 0;
+
+static struct VncInputSelect* vncInputSelectHead = NULL;
+
+struct VncInputSelect {
+  ClientPtr client;
+  Window window;
+  int mask;
+  struct VncInputSelect* next;
+};
+
+int vncAddExtension(void)
+{
+  ExtensionEntry* extEntry;
+
+  extEntry = AddExtension(VNCEXTNAME, VncExtNumberEvents, VncExtNumberErrors,
+                          ProcVncExtDispatch, SProcVncExtDispatch, vncResetProc,
+                          StandardMinorOpcode);
+  if (!extEntry) {
+    ErrorF("vncAddExtension: AddExtension failed\n");
+    return -1;
+  }
+
+  vncErrorBase = extEntry->errorBase;
+  vncEventBase = extEntry->eventBase;
+
+  if (!AddCallback(&ClientStateCallback, vncClientStateChange, 0)) {
+    FatalError("Add ClientStateCallback failed\n");
+  }
+
+  if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0)) {
+    FatalError("Add SelectionCallback failed\n");
+  }
+
+  return 0;
+}
+
+int vncNotifyQueryConnect(void)
+{
+  int count;
+  xVncExtQueryConnectNotifyEvent ev;
+
+  ev.type = vncEventBase + VncExtQueryConnectNotify;
+
+  count = 0;
+  for (struct VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
+    if (cur->mask & VncExtQueryConnectMask) {
+      ev.sequenceNumber = cur->client->sequence;
+      ev.window = cur->window;
+      if (cur->client->swapped) {
+#if XORG < 112
+        int n;
+        swaps(&ev.sequenceNumber, n);
+        swapl(&ev.window, n);
+#else
+        swaps(&ev.sequenceNumber);
+        swapl(&ev.window);
+#endif
+      }
+      WriteToClient(cur->client, sizeof(xVncExtQueryConnectNotifyEvent),
+                    (char *)&ev);
+      count++;
+    }
+  }
+
+  return count;
+}
+
+void vncClientCutText(const char* str, int len)
+{
+  if (clientCutText != NULL)
+    free(clientCutText);
+  clientCutTextLen = 0;
+
+  clientCutText = malloc(len);
+  if (clientCutText == NULL) {
+    ErrorF("Could not allocate clipboard buffer\n");
+    return;
+  }
+
+  memcpy(clientCutText, str, len);
+  clientCutTextLen = len;
+
+  xVncExtClientCutTextNotifyEvent ev;
+  ev.type = vncEventBase + VncExtClientCutTextNotify;
+  for (struct VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
+    if (cur->mask & VncExtClientCutTextMask) {
+      ev.sequenceNumber = cur->client->sequence;
+      ev.window = cur->window;
+      ev.time = GetTimeInMillis();
+      if (cur->client->swapped) {
+#if XORG < 112
+        int n;
+        swaps(&ev.sequenceNumber, n);
+        swapl(&ev.window, n);
+        swapl(&ev.time, n);
+#else
+        swaps(&ev.sequenceNumber);
+        swapl(&ev.window);
+        swapl(&ev.time);
+#endif
+      }
+      WriteToClient(cur->client, sizeof(xVncExtClientCutTextNotifyEvent),
+                    (char *)&ev);
+    }
+  }
+}
+
+static int ProcVncExtSetParam(ClientPtr client)
+{
+  char *param;
+
+  REQUEST(xVncExtSetParamReq);
+  REQUEST_FIXED_SIZE(xVncExtSetParamReq, stuff->paramLen);
+
+  param = malloc(stuff->paramLen+1);
+  if (param == NULL)
+    return BadAlloc;
+  strncpy(param, (char*)&stuff[1], stuff->paramLen);
+  param[stuff->paramLen] = '\0';
+
+  xVncExtSetParamReply rep;
+  rep.type = X_Reply;
+  rep.length = 0;
+  rep.success = 0;
+  rep.sequenceNumber = client->sequence;
+
+  /*
+   * Allow to change only certain parameters.
+   * Changing other parameters (for example PAM service name)
+   * could have negative security impact.
+   */
+  if (strncasecmp(param, "desktop", 7) != 0 &&
+      strncasecmp(param, "AcceptPointerEvents", 19) != 0 &&
+      (vncNoClipboard || strncasecmp(param, "SendCutText", 11) != 0) &&
+      (vncNoClipboard || strncasecmp(param, "AcceptCutText", 13) != 0))
+    goto deny;
+
+  vncSetParamSimple(param);
+  rep.success = 1;
+
+  // Send DesktopName update if desktop name has been changed
+  if (strncasecmp(param, "desktop", 7) != 0)
+    vncUpdateDesktopName();
+
+deny:
+  free(param);
+
+  if (client->swapped) {
+#if XORG < 112
+    int n;
+    swaps(&rep.sequenceNumber, n);
+    swapl(&rep.length, n);
+#else
+    swaps(&rep.sequenceNumber);
+    swapl(&rep.length);
+#endif
+  }
+  WriteToClient(client, sizeof(xVncExtSetParamReply), (char *)&rep);
+  return (client->noClientException);
+}
+
+static int SProcVncExtSetParam(ClientPtr client)
+{
+  REQUEST(xVncExtSetParamReq);
+#if XORG < 112
+  register char n;
+  swaps(&stuff->length, n);
+#else
+  swaps(&stuff->length);
+#endif
+  REQUEST_AT_LEAST_SIZE(xVncExtSetParamReq);
+  return ProcVncExtSetParam(client);
+}
+
+static int ProcVncExtGetParam(ClientPtr client)
+{
+  char* param;
+  char* value;
+  size_t len;
+
+  REQUEST(xVncExtGetParamReq);
+  REQUEST_FIXED_SIZE(xVncExtGetParamReq, stuff->paramLen);
+
+  param = malloc(stuff->paramLen+1);
+  if (param == NULL)
+    return BadAlloc;
+  strncpy(param, (char*)&stuff[1], stuff->paramLen);
+  param[stuff->paramLen] = 0;
+
+  value = vncGetParam(param);
+  len = value ? strlen(value) : 0;
+
+  free(param);
+
+  xVncExtGetParamReply rep;
+  rep.type = X_Reply;
+  rep.sequenceNumber = client->sequence;
+  rep.success = 0;
+  if (value)
+    rep.success = 1;
+  rep.length = (len + 3) >> 2;
+  rep.valueLen = len;
+  if (client->swapped) {
+#if XORG < 112
+    int n;
+    swaps(&rep.sequenceNumber, n);
+    swapl(&rep.length, n);
+    swaps(&rep.valueLen, n);
+#else
+    swaps(&rep.sequenceNumber);
+    swapl(&rep.length);
+    swaps(&rep.valueLen);
+#endif
+  }
+  WriteToClient(client, sizeof(xVncExtGetParamReply), (char *)&rep);
+  if (value)
+    WriteToClient(client, len, value);
+  free(value);
+  return (client->noClientException);
+}
+
+static int SProcVncExtGetParam(ClientPtr client)
+{
+  REQUEST(xVncExtGetParamReq);
+#if XORG < 112
+  register char n;
+  swaps(&stuff->length, n);
+#else
+  swaps(&stuff->length);
+#endif
+  REQUEST_AT_LEAST_SIZE(xVncExtGetParamReq);
+  return ProcVncExtGetParam(client);
+}
+
+static int ProcVncExtGetParamDesc(ClientPtr client)
+{
+  char* param;
+  const char* desc;
+  size_t len;
+
+  REQUEST(xVncExtGetParamDescReq);
+  REQUEST_FIXED_SIZE(xVncExtGetParamDescReq, stuff->paramLen);
+
+  param = malloc(stuff->paramLen+1);
+  if (param == NULL)
+    return BadAlloc;
+  strncpy(param, (char*)&stuff[1], stuff->paramLen);
+  param[stuff->paramLen] = 0;
+
+  desc = vncGetParamDesc(param);
+  len = desc ? strlen(desc) : 0;
+
+  free(param);
+
+  xVncExtGetParamDescReply rep;
+  rep.type = X_Reply;
+  rep.sequenceNumber = client->sequence;
+  rep.success = 0;
+  if (desc)
+    rep.success = 1;
+  rep.length = (len + 3) >> 2;
+  rep.descLen = len;
+  if (client->swapped) {
+#if XORG < 112
+    int n;
+    swaps(&rep.sequenceNumber, n);
+    swapl(&rep.length, n);
+    swaps(&rep.descLen, n);
+#else
+    swaps(&rep.sequenceNumber);
+    swapl(&rep.length);
+    swaps(&rep.descLen);
+#endif
+  }
+  WriteToClient(client, sizeof(xVncExtGetParamDescReply), (char *)&rep);
+  if (desc)
+    WriteToClient(client, len, (char*)desc);
+  return (client->noClientException);
+}
+
+static int SProcVncExtGetParamDesc(ClientPtr client)
+{
+  REQUEST(xVncExtGetParamDescReq);
+#if XORG < 112
+  register char n;
+  swaps(&stuff->length, n);
+#else
+  swaps(&stuff->length);
+#endif
+  REQUEST_AT_LEAST_SIZE(xVncExtGetParamDescReq);
+  return ProcVncExtGetParamDesc(client);
+}
+
+static int ProcVncExtListParams(ClientPtr client)
+{
+  REQUEST(xVncExtListParamsReq);
+  REQUEST_SIZE_MATCH(xVncExtListParamsReq);
+
+  xVncExtListParamsReply rep;
+  rep.type = X_Reply;
+  rep.sequenceNumber = client->sequence;
+
+  char *params;
+  size_t len;
+
+  params = vncGetParamList();
+  if (params == NULL)
+    return BadAlloc;
+
+  len = strlen(params);
+
+  rep.length = (len + 3) >> 2;
+  rep.nParams = vncGetParamCount();
+  if (client->swapped) {
+#if XORG < 112
+    int n;
+    swaps(&rep.sequenceNumber, n);
+    swapl(&rep.length, n);
+    swaps(&rep.nParams, n);
+#else
+    swaps(&rep.sequenceNumber);
+    swapl(&rep.length);
+    swaps(&rep.nParams);
+#endif
+  }
+  WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep);
+  WriteToClient(client, len, (char*)params);
+  free(params);
+  return (client->noClientException);
+}
+
+static int SProcVncExtListParams(ClientPtr client)
+{
+  REQUEST(xVncExtListParamsReq);
+#if XORG < 112
+  register char n;
+  swaps(&stuff->length, n);
+#else
+  swaps(&stuff->length);
+#endif
+  REQUEST_SIZE_MATCH(xVncExtListParamsReq);
+  return ProcVncExtListParams(client);
+}
+
+static int ProcVncExtSetServerCutText(ClientPtr client)
+{
+  REQUEST(xVncExtSetServerCutTextReq);
+  REQUEST_FIXED_SIZE(xVncExtSetServerCutTextReq, stuff->textLen);
+  vncServerCutText((const char*)&stuff[1], stuff->textLen);
+  return (client->noClientException);
+}
+
+static int SProcVncExtSetServerCutText(ClientPtr client)
+{
+  REQUEST(xVncExtSetServerCutTextReq);
+#if XORG < 112
+  register char n;
+  swaps(&stuff->length, n);
+#else
+  swaps(&stuff->length);
+#endif
+  REQUEST_AT_LEAST_SIZE(xVncExtSetServerCutTextReq);
+#if XORG < 112
+  swapl(&stuff->textLen, n);
+#else
+  swapl(&stuff->textLen);
+#endif
+  return ProcVncExtSetServerCutText(client);
+}
+
+static int ProcVncExtGetClientCutText(ClientPtr client)
+{
+  REQUEST(xVncExtGetClientCutTextReq);
+  REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
+
+  xVncExtGetClientCutTextReply rep;
+  rep.type = X_Reply;
+  rep.length = (clientCutTextLen + 3) >> 2;
+  rep.sequenceNumber = client->sequence;
+  rep.textLen = clientCutTextLen;
+  if (client->swapped) {
+#if XORG < 112
+    int n;
+    swaps(&rep.sequenceNumber, n);
+    swapl(&rep.length, n);
+    swapl(&rep.textLen, n);
+#else
+    swaps(&rep.sequenceNumber);
+    swapl(&rep.length);
+    swapl(&rep.textLen);
+#endif
+  }
+  WriteToClient(client, sizeof(xVncExtGetClientCutTextReply), (char *)&rep);
+  if (clientCutText)
+    WriteToClient(client, clientCutTextLen, clientCutText);
+  return (client->noClientException);
+}
+
+static int SProcVncExtGetClientCutText(ClientPtr client)
+{
+  REQUEST(xVncExtGetClientCutTextReq);
+#if XORG < 112
+  register char n;
+  swaps(&stuff->length, n);
+#else
+  swaps(&stuff->length);
+#endif
+  REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
+  return ProcVncExtGetClientCutText(client);
+}
+
+static int ProcVncExtSelectInput(ClientPtr client)
+{
+  struct VncInputSelect** nextPtr;
+  struct VncInputSelect* cur;
+  REQUEST(xVncExtSelectInputReq);
+  REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
+  nextPtr = &vncInputSelectHead;
+  for (cur = vncInputSelectHead; cur; cur = *nextPtr) {
+    if (cur->client == client && cur->window == stuff->window) {
+      cur->mask = stuff->mask;
+      if (!cur->mask) {
+        *nextPtr = cur->next;
+        free(cur);
+      }
+      break;
+    }
+    nextPtr = &cur->next;
+  }
+  if (!cur) {
+    cur = malloc(sizeof(struct VncInputSelect));
+    if (cur == NULL)
+      return BadAlloc;
+    memset(cur, 0, sizeof(struct VncInputSelect));
+
+    cur->client = client;
+    cur->window = stuff->window;
+    cur->mask = stuff->mask;
+
+    cur->next = vncInputSelectHead;
+    vncInputSelectHead = cur;
+  }
+  return (client->noClientException);
+}
+
+static int SProcVncExtSelectInput(ClientPtr client)
+{
+  REQUEST(xVncExtSelectInputReq);
+#if XORG < 112
+  register char n;
+  swaps(&stuff->length, n);
+#else
+  swaps(&stuff->length);
+#endif
+  REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
+#if XORG < 112
+  swapl(&stuff->window, n);
+  swapl(&stuff->mask, n);
+#else
+  swapl(&stuff->window);
+  swapl(&stuff->mask);
+#endif
+  return ProcVncExtSelectInput(client);
+}
+
+static int ProcVncExtConnect(ClientPtr client)
+{
+  char *address;
+
+  REQUEST(xVncExtConnectReq);
+  REQUEST_FIXED_SIZE(xVncExtConnectReq, stuff->strLen);
+
+  address = malloc(stuff->strLen+1);
+  if (address == NULL)
+    return BadAlloc;
+  strncpy(address, (char*)&stuff[1], stuff->strLen);
+  address[stuff->strLen] = 0;
+
+  xVncExtConnectReply rep;
+  rep.success = 0;
+  if (vncConnectClient(address) == 0)
+        rep.success = 1;
+
+  rep.type = X_Reply;
+  rep.length = 0;
+  rep.sequenceNumber = client->sequence;
+  if (client->swapped) {
+#if XORG < 112
+    int n;
+    swaps(&rep.sequenceNumber, n);
+    swapl(&rep.length, n);
+#else
+    swaps(&rep.sequenceNumber);
+    swapl(&rep.length);
+#endif
+  }
+  WriteToClient(client, sizeof(xVncExtConnectReply), (char *)&rep);
+
+  free(address);
+
+  return (client->noClientException);
+}
+
+static int SProcVncExtConnect(ClientPtr client)
+{
+  REQUEST(xVncExtConnectReq);
+#if XORG < 112
+  register char n;
+  swaps(&stuff->length, n);
+#else
+  swaps(&stuff->length);
+#endif
+  REQUEST_AT_LEAST_SIZE(xVncExtConnectReq);
+  return ProcVncExtConnect(client);
+}
+
+
+static int ProcVncExtGetQueryConnect(ClientPtr client)
+{
+  REQUEST(xVncExtGetQueryConnectReq);
+  REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
+
+  uint32_t opaqueId;
+  const char *qcAddress, *qcUsername;
+  int qcTimeout;
+
+  vncGetQueryConnect(&opaqueId, &qcAddress, &qcUsername, &qcTimeout);
+
+  xVncExtGetQueryConnectReply rep;
+  rep.type = X_Reply;
+  rep.sequenceNumber = client->sequence;
+  rep.timeout = qcTimeout;
+  rep.addrLen = qcTimeout ? strlen(qcAddress) : 0;
+  rep.userLen = qcTimeout ? strlen(qcUsername) : 0;
+  rep.opaqueId = (CARD32)(long)opaqueId;
+  rep.length = ((rep.userLen + 3) >> 2) + ((rep.addrLen + 3) >> 2);
+  if (client->swapped) {
+#if XORG < 112
+    int n;
+    swaps(&rep.sequenceNumber, n);
+    swapl(&rep.addrLen, n);
+    swapl(&rep.userLen, n);
+    swapl(&rep.timeout, n);
+    swapl(&rep.opaqueId, n);
+    swapl(&rep.length, n);
+#else
+    swaps(&rep.sequenceNumber);
+    swapl(&rep.addrLen);
+    swapl(&rep.userLen);
+    swapl(&rep.timeout);
+    swapl(&rep.opaqueId);
+    swapl(&rep.length);
+#endif
+  }
+  WriteToClient(client, sizeof(xVncExtGetQueryConnectReply), (char *)&rep);
+  if (qcTimeout)
+    WriteToClient(client, strlen(qcAddress), (char*)qcAddress);
+  if (qcTimeout)
+    WriteToClient(client, strlen(qcUsername), (char*)qcUsername);
+  return (client->noClientException);
+}
+
+static int SProcVncExtGetQueryConnect(ClientPtr client)
+{
+  REQUEST(xVncExtGetQueryConnectReq);
+#if XORG < 112
+  register char n;
+  swaps(&stuff->length, n);
+#else
+  swaps(&stuff->length);
+#endif
+  REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
+  return ProcVncExtGetQueryConnect(client);
+}
+
+
+static int ProcVncExtApproveConnect(ClientPtr client)
+{
+  REQUEST(xVncExtApproveConnectReq);
+  REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
+  vncApproveConnection(stuff->opaqueId, stuff->approve);
+  // Inform other clients of the event and tidy up
+  vncNotifyQueryConnect();
+  return (client->noClientException);
+}
+
+static int SProcVncExtApproveConnect(ClientPtr client)
+{
+  REQUEST(xVncExtApproveConnectReq);
+#if XORG < 112
+  register char n;
+  swaps(&stuff->length, n);
+  swapl(&stuff->opaqueId, n);
+#else
+  swaps(&stuff->length);
+  swapl(&stuff->opaqueId);
+#endif
+  REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
+  return ProcVncExtApproveConnect(client);
+}
+
+
+static int ProcVncExtDispatch(ClientPtr client)
+{
+  REQUEST(xReq);
+  switch (stuff->data) {
+  case X_VncExtSetParam:
+    return ProcVncExtSetParam(client);
+  case X_VncExtGetParam:
+    return ProcVncExtGetParam(client);
+  case X_VncExtGetParamDesc:
+    return ProcVncExtGetParamDesc(client);
+  case X_VncExtListParams:
+    return ProcVncExtListParams(client);
+  case X_VncExtSetServerCutText:
+    return ProcVncExtSetServerCutText(client);
+  case X_VncExtGetClientCutText:
+    return ProcVncExtGetClientCutText(client);
+  case X_VncExtSelectInput:
+    return ProcVncExtSelectInput(client);
+  case X_VncExtConnect:
+    return ProcVncExtConnect(client);
+  case X_VncExtGetQueryConnect:
+    return ProcVncExtGetQueryConnect(client);
+  case X_VncExtApproveConnect:
+    return ProcVncExtApproveConnect(client);
+  default:
+    return BadRequest;
+  }
+}
+
+static int SProcVncExtDispatch(ClientPtr client)
+{
+  REQUEST(xReq);
+  switch (stuff->data) {
+  case X_VncExtSetParam:
+    return SProcVncExtSetParam(client);
+  case X_VncExtGetParam:
+    return SProcVncExtGetParam(client);
+  case X_VncExtGetParamDesc:
+    return SProcVncExtGetParamDesc(client);
+  case X_VncExtListParams:
+    return SProcVncExtListParams(client);
+  case X_VncExtSetServerCutText:
+    return SProcVncExtSetServerCutText(client);
+  case X_VncExtGetClientCutText:
+    return SProcVncExtGetClientCutText(client);
+  case X_VncExtSelectInput:
+    return SProcVncExtSelectInput(client);
+  case X_VncExtConnect:
+    return SProcVncExtConnect(client);
+  case X_VncExtGetQueryConnect:
+    return SProcVncExtGetQueryConnect(client);
+  case X_VncExtApproveConnect:
+    return SProcVncExtApproveConnect(client);
+  default:
+    return BadRequest;
+  }
+}
+
+static void vncResetProc(ExtensionEntry* extEntry)
+{
+}
+
+static void vncClientStateChange(CallbackListPtr * l, void * d, void * p)
+{
+  ClientPtr client = ((NewClientInfoRec*)p)->client;
+  if (client->clientState == ClientStateGone) {
+    struct VncInputSelect** nextPtr = &vncInputSelectHead;
+    for (struct VncInputSelect* cur = vncInputSelectHead; cur; cur = *nextPtr) {
+      if (cur->client == client) {
+        *nextPtr = cur->next;
+        free(cur);
+        continue;
+      }
+      nextPtr = &cur->next;
+    }
+  }
+}
+
+static void SendSelectionChangeEvent(Atom selection)
+{
+  xVncExtSelectionChangeNotifyEvent ev;
+  ev.type = vncEventBase + VncExtSelectionChangeNotify;
+  for (struct VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
+    if (cur->mask & VncExtSelectionChangeMask) {
+      ev.sequenceNumber = cur->client->sequence;
+      ev.window = cur->window;
+      ev.selection = selection;
+      if (cur->client->swapped) {
+#if XORG < 112
+        int n;
+        swaps(&ev.sequenceNumber, n);
+        swapl(&ev.window, n);
+        swapl(&ev.selection, n);
+#else
+        swaps(&ev.sequenceNumber);
+        swapl(&ev.window);
+        swapl(&ev.selection);
+#endif
+      }
+      WriteToClient(cur->client, sizeof(xVncExtSelectionChangeNotifyEvent),
+                    (char *)&ev);
+    }
+  }
+}
+
+static void vncSelectionCallback(CallbackListPtr *callbacks, void * data, void * args)
+{
+  SelectionInfoRec *info = (SelectionInfoRec *) args;
+  Selection *selection = info->selection;
+
+  SendSelectionChangeEvent(selection->selection);
+}
+
index ff81321cdc47b9b8bed1c0661e59d1e041dfd0ca..2277783904fcdd228587fe48a27ffb7a14338b3c 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright 2011 Pierre Ossman for Cendio AB
+ * Copyright 2011-2015 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
  * USA.
  */
 
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
 #include <stdio.h>
 #include <errno.h>
 
-extern "C" {
-#define class c_class
-#define public c_public
-#define NEED_EVENTS
-#include <X11/X.h>
-#include <X11/Xproto.h>
-#include <X11/Xpoll.h>
-#include "misc.h"
-#include "os.h"
-#include "dixstruct.h"
-#include "extnsionst.h"
-#include "scrnintstr.h"
-#include "selection.h"
-#define _VNCEXT_SERVER_
-#define _VNCEXT_PROTO_
-#include "vncExt.h"
-#undef class
-#undef xalloc
-#undef public
-}
-
 #include <rfb/Configuration.h>
 #include <rfb/Logger_stdio.h>
 #include <rfb/LogWriter.h>
@@ -52,67 +27,29 @@ extern "C" {
 #include <rfb/ServerCore.h>
 #include <rdr/HexOutStream.h>
 #include <rfb/LogWriter.h>
-#undef max
-#undef min
+#include <rfb/Hostname.h>
+#include <rfb/Region.h>
 #include <network/TcpSocket.h>
 
 #include "XserverDesktop.h"
-#include "vncHooks.h"
 #include "vncExtInit.h"
-#include "xorg-version.h"
-
-extern "C" {
-
-  extern void vncExtensionInit();
-  static void vncResetProc(ExtensionEntry* extEntry);
-  static void vncBlockHandler(void * data, OSTimePtr t, void * readmask);
-  static void vncWakeupHandler(void * data, int nfds, void * readmask);
-  void vncWriteBlockHandler(fd_set *fds);
-  void vncWriteWakeupHandler(int nfds, fd_set *fds);
-  static void vncClientStateChange(CallbackListPtr*, void *, void *);
-  static void SendSelectionChangeEvent(Atom selection);
-  static int ProcVncExtDispatch(ClientPtr client);
-  static int SProcVncExtDispatch(ClientPtr client);
-  static void vncSelectionCallback(CallbackListPtr *callbacks, void * data,
-                                  void * args);
-
-  extern char *listenaddr;
-}
+#include "vncHooks.h"
+#include "vncBlockHandler.h"
+#include "XorgGlue.h"
 
 using namespace rfb;
 
 static rfb::LogWriter vlog("vncext");
 
+// We can't safely get this from Xorg
+#define MAXSCREENS 16
+
 static unsigned long vncExtGeneration = 0;
 static bool initialised = false;
 static XserverDesktop* desktop[MAXSCREENS] = { 0, };
 void* vncFbptr[MAXSCREENS] = { 0, };
 int vncFbstride[MAXSCREENS];
 
-static char* clientCutText = 0;
-static int clientCutTextLen = 0;
-bool noclipboard = false;
-
-static XserverDesktop* queryConnectDesktop = 0;
-static void* queryConnectId = 0;
-static int queryConnectTimeout = 0;
-static OsTimerPtr queryConnectTimer = 0;
-
-static struct VncInputSelect* vncInputSelectHead = 0;
-struct VncInputSelect {
-  VncInputSelect(ClientPtr c, Window w, int m) : client(c), window(w), mask(m)
-  {
-    next = vncInputSelectHead;
-    vncInputSelectHead = this;
-  }
-  ClientPtr client;
-  Window window;
-  int mask;
-  VncInputSelect* next;
-};
-
-static int vncErrorBase = 0;
-static int vncEventBase = 0;
 int vncInetdSock = -1;
 
 rfb::StringParameter httpDir("httpd",
@@ -126,93 +63,67 @@ rfb::StringParameter desktopName("desktop", "Name of VNC desktop","x11");
 rfb::BoolParameter localhostOnly("localhost",
                                  "Only allow connections from localhost",
                                  false);
+rfb::StringParameter interface("interface",
+                               "listen on the specified network address",
+                               "all");
+rfb::BoolParameter avoidShiftNumLock("AvoidShiftNumLock",
+                                     "Avoid fake Shift presses for keys affected by NumLock.",
+                                     true);
 
-static PixelFormat vncGetPixelFormat(ScreenPtr pScreen)
+static PixelFormat vncGetPixelFormat(int scrIdx)
 {
   int depth, bpp;
   int trueColour, bigEndian;
+  int redMask, greenMask, blueMask;
+
   int redShift, greenShift, blueShift;
   int redMax, greenMax, blueMax;
 
-  int i;
-  VisualPtr vis = NULL;
-
-  depth = pScreen->rootDepth;
-
-  for (i = 0; i < screenInfo.numPixmapFormats; i++) {
-    if (screenInfo.formats[i].depth == depth) {
-      bpp = screenInfo.formats[i].bitsPerPixel;
-      break;
-    }
-  }
-
-  if (i == screenInfo.numPixmapFormats) {
-    fprintf(stderr,"no pixmap format for root depth???\n");
-    abort();
-  }
-
-  bigEndian = (screenInfo.imageByteOrder == MSBFirst);
-
-  for (i = 0; i < pScreen->numVisuals; i++) {
-    if (pScreen->visuals[i].vid == pScreen->rootVisual) {
-      vis = &pScreen->visuals[i];
-      break;
-    }
-  }
-
-  if (i == pScreen->numVisuals) {
-    fprintf(stderr,"no visual rec for root visual???\n");
-    abort();
-  }
-
-  trueColour = (vis->c_class == TrueColor);
+  vncGetScreenFormat(scrIdx, &depth, &bpp, &trueColour, &bigEndian,
+                     &redMask, &greenMask, &blueMask);
 
   if (!trueColour) {
-    fprintf(stderr,"pseudocolour not supported");
+    vlog.error("pseudocolour not supported");
     abort();
   }
 
-  redShift   = ffs(vis->redMask) - 1;
-  greenShift = ffs(vis->greenMask) - 1;
-  blueShift  = ffs(vis->blueMask) - 1;
-  redMax     = vis->redMask   >> redShift;
-  greenMax   = vis->greenMask >> greenShift;
-  blueMax    = vis->blueMask  >> blueShift;
+  redShift   = ffs(redMask) - 1;
+  greenShift = ffs(greenMask) - 1;
+  blueShift  = ffs(blueMask) - 1;
+  redMax     = redMask   >> redShift;
+  greenMax   = greenMask >> greenShift;
+  blueMax    = blueMask  >> blueShift;
 
   return PixelFormat(bpp, depth, bigEndian, trueColour,
                      redMax, greenMax, blueMax,
                      redShift, greenShift, blueShift);
 }
 
-void vncExtensionInit()
+void vncExtensionInit(void)
 {
-  if (vncExtGeneration == serverGeneration) {
+  int ret;
+
+  if (vncExtGeneration == vncGetServerGeneration()) {
     vlog.error("vncExtensionInit: called twice in same generation?");
     return;
   }
-  vncExtGeneration = serverGeneration;
+  vncExtGeneration = vncGetServerGeneration();
 
-  ExtensionEntry* extEntry
-    = AddExtension(VNCEXTNAME, VncExtNumberEvents, VncExtNumberErrors,
-                   ProcVncExtDispatch, SProcVncExtDispatch, vncResetProc,
-                   StandardMinorOpcode);
-  if (!extEntry) {
-    ErrorF("vncExtInit: AddExtension failed\n");
+  if (vncGetScreenCount() > MAXSCREENS) {
+    vlog.error("vncExtensionInit: too many screens");
     return;
   }
 
-  vncErrorBase = extEntry->errorBase;
-  vncEventBase = extEntry->eventBase;
-
-  vlog.info("VNC extension running!");
-
-  if (!AddCallback(&ClientStateCallback, vncClientStateChange, 0)) {
-    FatalError("Add ClientStateCallback failed\n");
+  if (sizeof(ShortRect) != sizeof(struct UpdateRect)) {
+    vlog.error("vncExtensionInit: Incompatible ShortRect size");
+    return;
   }
 
-  if (!AddCallback(&SelectionCallback, vncSelectionCallback, 0)) {
-    FatalError("Add SelectionCallback failed\n");
-  }
+  ret = vncAddExtension();
+  if (ret == -1)
+    return;
+
+  vlog.info("VNC extension running!");
 
   try {
     if (!initialised) {
@@ -220,7 +131,7 @@ void vncExtensionInit()
       initialised = true;
     }
 
-    for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+    for (int scr = 0; scr < vncGetScreenCount(); scr++) {
 
       if (!desktop[scr]) {
         network::TcpListener* listener = 0;
@@ -234,30 +145,35 @@ void vncExtensionInit()
           }
         } else {
           int port = rfbport;
-          if (port == 0) port = 5900 + atoi(display);
+          if (port == 0) port = 5900 + atoi(vncGetDisplay());
           port += 1000 * scr;
-          listener = new network::TcpListener(listenaddr, port, localhostOnly);
+          if (strcasecmp(interface, "all") == 0)
+            listener = new network::TcpListener(NULL, port, localhostOnly);
+          else
+            listener = new network::TcpListener(interface, port, localhostOnly);
           vlog.info("Listening for VNC connections on %s interface(s), port %d",
-                   listenaddr == NULL ? "all" : listenaddr, port);
+                    (const char*)interface, port);
           CharArray httpDirStr(httpDir.getData());
           if (httpDirStr.buf[0]) {
             port = httpPort;
-            if (port == 0) port = 5800 + atoi(display);
+            if (port == 0) port = 5800 + atoi(vncGetDisplay());
             port += 1000 * scr;
-            httpListener = new network::TcpListener(listenaddr, port, localhostOnly);
+            httpListener = new network::TcpListener(interface, port, localhostOnly);
             vlog.info("Listening for HTTP connections on %s interface(s), port %d",
-                     listenaddr == NULL ? "all" : listenaddr, port);
+                      (const char*)interface, port);
           }
         }
 
         CharArray desktopNameStr(desktopName.getData());
-        PixelFormat pf = vncGetPixelFormat(screenInfo.screens[scr]);
+        PixelFormat pf = vncGetPixelFormat(scr);
 
-        desktop[scr] = new XserverDesktop(screenInfo.screens[scr],
+        desktop[scr] = new XserverDesktop(scr,
                                           listener,
                                           httpListener,
                                           desktopNameStr.buf,
                                           pf,
+                                          vncGetScreenWidth(scr),
+                                          vncGetScreenHeight(scr),
                                           vncFbptr[scr],
                                           vncFbstride[scr]);
         vlog.info("created VNC server for screen %d", scr);
@@ -269,889 +185,182 @@ void vncExtensionInit()
         }
       }
 
-      vncHooksInit(screenInfo.screens[scr], desktop[scr]);
+      vncHooksInit(scr);
     }
-
-    RegisterBlockAndWakeupHandlers(vncBlockHandler, vncWakeupHandler, 0);
-
   } catch (rdr::Exception& e) {
     vlog.error("vncExtInit: %s",e.str());
   }
-}
 
-static void vncResetProc(ExtensionEntry* extEntry)
-{
-}
-
-static void vncSelectionCallback(CallbackListPtr *callbacks, void * data, void * args)
-{
-  SelectionInfoRec *info = (SelectionInfoRec *) args;
-  Selection *selection = info->selection;
-
-  SendSelectionChangeEvent(selection->selection);
+  vncRegisterBlockHandlers();
 }
 
-static void vncWriteBlockHandlerFallback(OSTimePtr timeout);
-static void vncWriteWakeupHandlerFallback();
-
-//
-// vncBlockHandler - called just before the X server goes into select().  Call
-// on to the block handler for each desktop.  Then check whether any of the
-// selections have changed, and if so, notify any interested X clients.
-//
-
-static void vncBlockHandler(void * data, OSTimePtr timeout, void * readmask)
+void vncCallReadBlockHandlers(fd_set * fds, struct timeval ** timeout)
 {
-  fd_set* fds = (fd_set*)readmask;
-
-  vncWriteBlockHandlerFallback(timeout);
-
-  for (int scr = 0; scr < screenInfo.numScreens; scr++)
+  for (int scr = 0; scr < vncGetScreenCount(); scr++)
     if (desktop[scr])
-      desktop[scr]->blockHandler(fds, timeout);
+      desktop[scr]->readBlockHandler(fds, timeout);
 }
 
-static void vncWakeupHandler(void * data, int nfds, void * readmask)
+void vncCallReadWakeupHandlers(fd_set * fds, int nfds)
 {
-  fd_set* fds = (fd_set*)readmask;
-
-  for (int scr = 0; scr < screenInfo.numScreens; scr++) {
-    if (desktop[scr]) {
-      desktop[scr]->wakeupHandler(fds, nfds);
-    }
-  }
-
-  vncWriteWakeupHandlerFallback();
+  for (int scr = 0; scr < vncGetScreenCount(); scr++)
+    if (desktop[scr])
+      desktop[scr]->readWakeupHandler(fds, nfds);
 }
 
-//
-// vncWriteBlockHandler - extra hack to be able to get the main select loop
-// to monitor writeable fds and not just readable. This requirers a modified
-// Xorg and might therefore not be called. When it is called though, it will
-// do so before vncBlockHandler (and vncWriteWakeupHandler called after
-// vncWakeupHandler).
-//
-
-static bool needFallback = true;
-static fd_set fallbackFds;
-static struct timeval tw;
-
-void vncWriteBlockHandler(fd_set *fds)
+void vncCallWriteBlockHandlers(fd_set * fds, struct timeval ** timeout)
 {
-  needFallback = false;
-
-  for (int scr = 0; scr < screenInfo.numScreens; scr++)
+  for (int scr = 0; scr < vncGetScreenCount(); scr++)
     if (desktop[scr])
-      desktop[scr]->writeBlockHandler(fds);
+      desktop[scr]->writeBlockHandler(fds, timeout);
 }
 
-void vncWriteWakeupHandler(int nfds, fd_set *fds)
+void vncCallWriteWakeupHandlers(fd_set * fds, int nfds)
 {
-  for (int scr = 0; scr < screenInfo.numScreens; scr++) {
-    if (desktop[scr]) {
+  for (int scr = 0; scr < vncGetScreenCount(); scr++)
+    if (desktop[scr])
       desktop[scr]->writeWakeupHandler(fds, nfds);
-    }
-  }
 }
 
-static void vncWriteBlockHandlerFallback(OSTimePtr timeout)
+int vncGetAvoidShiftNumLock(void)
 {
-  if (!needFallback)
-    return;
-
-  FD_ZERO(&fallbackFds);
-  vncWriteBlockHandler(&fallbackFds);
-  needFallback = true;
-
-  if (!XFD_ANYSET(&fallbackFds))
-    return;
-
-  if ((*timeout == NULL) ||
-      ((*timeout)->tv_sec > 0) || ((*timeout)->tv_usec > 10000)) {
-    tw.tv_sec = 0;
-    tw.tv_usec = 10000;
-    *timeout = &tw;
-  }
+  return (bool)avoidShiftNumLock;
 }
 
-static void vncWriteWakeupHandlerFallback()
+void vncUpdateDesktopName(void)
 {
-  int ret;
-  struct timeval timeout;
-
-  if (!needFallback)
-    return;
-
-  if (!XFD_ANYSET(&fallbackFds))
-    return;
-
-  timeout.tv_sec = 0;
-  timeout.tv_usec = 0;
-
-  ret = select(XFD_SETSIZE, NULL, &fallbackFds, NULL, &timeout);
-  if (ret < 0) {
-    ErrorF("vncWriteWakeupHandlerFallback(): select: %s\n",
-           strerror(errno));
-    return;
+  for (int scr = 0; scr < vncGetScreenCount(); scr++) {
+    if (desktop[scr] == NULL)
+      continue;
+    desktop[scr]->setDesktopName(desktopName);
   }
-
-  if (ret == 0)
-    return;
-
-  vncWriteWakeupHandler(ret, &fallbackFds);
 }
 
-static void vncClientStateChange(CallbackListPtr*, void *, void * p)
+void vncServerCutText(const char *text, size_t len)
 {
-  ClientPtr client = ((NewClientInfoRec*)p)->client;
-  if (client->clientState == ClientStateGone) {
-    VncInputSelect** nextPtr = &vncInputSelectHead;
-    for (VncInputSelect* cur = vncInputSelectHead; cur; cur = *nextPtr) {
-      if (cur->client == client) {
-        *nextPtr = cur->next;
-        delete cur;
-        continue;
-      }
-      nextPtr = &cur->next;
-    }
+  for (int scr = 0; scr < vncGetScreenCount(); scr++) {
+    if (desktop[scr] == NULL)
+      continue;
+    desktop[scr]->serverCutText(text, len);
   }
 }
 
-void vncBell()
+int vncConnectClient(const char *addr)
 {
-  for (int scr = 0; scr < screenInfo.numScreens; scr++) {
-    if (desktop[scr]) {
-      desktop[scr]->bell();
-    }
-  }
-}
+  if (desktop[0] == NULL)
+    return -1;
 
-void vncClientGone(int fd)
-{
-  if (fd == vncInetdSock) {
-    fprintf(stderr,"inetdSock client gone\n");
-    GiveUp(0);
-  }
-}
-
-void vncClientCutText(const char* str, int len)
-{
-  delete [] clientCutText;
-  clientCutText = new char[len];
-  memcpy(clientCutText, str, len);
-  clientCutTextLen = len;
-  xVncExtClientCutTextNotifyEvent ev;
-  ev.type = vncEventBase + VncExtClientCutTextNotify;
-  for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
-    if (cur->mask & VncExtClientCutTextMask) {
-      ev.sequenceNumber = cur->client->sequence;
-      ev.window = cur->window;
-      ev.time = GetTimeInMillis();
-      if (cur->client->swapped) {
-#if XORG < 112
-        int n;
-        swaps(&ev.sequenceNumber, n);
-        swapl(&ev.window, n);
-        swapl(&ev.time, n);
-#else
-        swaps(&ev.sequenceNumber);
-        swapl(&ev.window);
-        swapl(&ev.time);
-#endif
-      }
-      WriteToClient(cur->client, sizeof(xVncExtClientCutTextNotifyEvent),
-                    (char *)&ev);
+  if (strlen(addr) == 0) {
+    try {
+      desktop[0]->disconnectClients();
+    } catch (rdr::Exception& e) {
+      vlog.error("Disconnecting all clients: %s",e.str());
+      return -1;
     }
+    return 0;
   }
-}
-
 
-static CARD32 queryConnectTimerCallback(OsTimerPtr timer,
-                                        CARD32 now, void * arg)
-{
-  if (queryConnectTimeout)
-    queryConnectDesktop->approveConnection(queryConnectId, false, "The attempt to prompt the user to accept the connection failed");
-  // Re-notify clients, causing them to discover that we're done
-  vncQueryConnect(queryConnectDesktop, queryConnectId);
-  return 0;
-}
+  char *host;
+  int port;
 
-void vncQueryConnect(XserverDesktop* desktop, void* opaqueId)
-{
-  // Only one query can be processed at any one time
-  if (queryConnectTimeout && ((desktop != queryConnectDesktop) ||
-                              (opaqueId != queryConnectId))) {
-    desktop->approveConnection(opaqueId, false,
-                               "Another connection is currently being queried.");
-    return;
-  }
+  getHostAndPort(addr, &host, &port, 5500);
 
-  // Get the query timeout.  If it's zero, there is no query.
-  queryConnectTimeout = desktop->getQueryTimeout(opaqueId);
-  queryConnectId = queryConnectTimeout ? opaqueId : 0;
-  queryConnectDesktop = queryConnectTimeout ? desktop : 0;
-
-  // Notify clients
-  bool notified = false;
-  xVncExtQueryConnectNotifyEvent ev;
-  ev.type = vncEventBase + VncExtQueryConnectNotify;
-  for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
-    if (cur->mask & VncExtQueryConnectMask) {
-      ev.sequenceNumber = cur->client->sequence;
-      ev.window = cur->window;
-      if (cur->client->swapped) {
-#if XORG < 112
-        int n;
-        swaps(&ev.sequenceNumber, n);
-        swapl(&ev.window, n);
-#else
-        swaps(&ev.sequenceNumber);
-        swapl(&ev.window);
-#endif
-      }
-      WriteToClient(cur->client, sizeof(xVncExtQueryConnectNotifyEvent),
-                    (char *)&ev);
-      notified = true;
-    }
-  }
-
-  // If we're being asked to query a connection (rather than to cancel
-  //   a query), and haven't been able to notify clients then reject it.
-  if (queryConnectTimeout && !notified) {
-    queryConnectTimeout = 0;
-    queryConnectId = 0;
-    queryConnectDesktop = 0;
-    desktop->approveConnection(opaqueId, false,
-                               "Unable to query the local user to accept the connection.");
-    return;
-  }    
-
-  // Set a timer so that if no-one ever responds, we will eventually 
-  //   reject the connection
-  //   NB: We don't set a timer if sock is null, since that indicates
-  //       that pending queries should be cancelled.
-  if (queryConnectDesktop)
-    queryConnectTimer = TimerSet(queryConnectTimer, 0,
-                                 queryConnectTimeout*2000,
-                                 queryConnectTimerCallback, 0);
-  else
-    TimerCancel(queryConnectTimer);
-}
-
-static void SendSelectionChangeEvent(Atom selection)
-{
-  xVncExtSelectionChangeNotifyEvent ev;
-  ev.type = vncEventBase + VncExtSelectionChangeNotify;
-  for (VncInputSelect* cur = vncInputSelectHead; cur; cur = cur->next) {
-    if (cur->mask & VncExtSelectionChangeMask) {
-      ev.sequenceNumber = cur->client->sequence;
-      ev.window = cur->window;
-      ev.selection = selection;
-      if (cur->client->swapped) {
-#if XORG < 112
-        int n;
-        swaps(&ev.sequenceNumber, n);
-        swapl(&ev.window, n);
-        swapl(&ev.selection, n);
-#else
-        swaps(&ev.sequenceNumber);
-        swapl(&ev.window);
-        swapl(&ev.selection);
-#endif
-      }
-      WriteToClient(cur->client, sizeof(xVncExtSelectionChangeNotifyEvent),
-                    (char *)&ev);
-    }
-  }
-}
-
-static int ProcVncExtSetParam(ClientPtr client)
-{
-  char* value1 = 0;
-  char* value2 = 0;
-  rfb::VoidParameter *desktop1, *desktop2;
-
-  REQUEST(xVncExtSetParamReq);
-  REQUEST_FIXED_SIZE(xVncExtSetParamReq, stuff->paramLen);
-  CharArray param(stuff->paramLen+1);
-  strncpy(param.buf, (char*)&stuff[1], stuff->paramLen);
-  param.buf[stuff->paramLen] = 0;
-
-  xVncExtSetParamReply rep;
-  rep.type = X_Reply;
-  rep.length = 0;
-  rep.success = 0;
-  rep.sequenceNumber = client->sequence;
-
-  // Retrieve desktop name before setting
-  desktop1 = rfb::Configuration::getParam("desktop");
-  if (desktop1)
-    value1 = desktop1->getValueStr();
-
-  /*
-   * Allow to change only certain parameters.
-   * Changing other parameters (for example PAM service name)
-   * could have negative security impact.
-   */
-  if (strncasecmp(param.buf, "desktop", 7) != 0 &&
-      strncasecmp(param.buf, "AcceptPointerEvents", 19) != 0 &&
-      (noclipboard || strncasecmp(param.buf, "SendCutText", 11) != 0) &&
-      (noclipboard || strncasecmp(param.buf, "AcceptCutText", 13) != 0))
-    goto deny;
-
-  rep.success = rfb::Configuration::setParam(param.buf);
-
-  // Send DesktopName update if desktop name has been changed
-  desktop2 = rfb::Configuration::getParam("desktop");
-  if (desktop2)
-    value2 = desktop2->getValueStr();
-  if (value1 && value2 && strcmp(value1, value2)) {
-    for (int scr = 0; scr < screenInfo.numScreens; scr++) {
-      if (desktop[scr]) {
-       desktop[scr]->setDesktopName(value2);
-      }
-    }
-  }
-  if (value1)
-    delete [] value1;
-  if (value2)
-    delete [] value2;
-
-deny:
-  if (client->swapped) {
-#if XORG < 112
-    int n;
-    swaps(&rep.sequenceNumber, n);
-    swapl(&rep.length, n);
-#else
-    swaps(&rep.sequenceNumber);
-    swapl(&rep.length);
-#endif
-  }
-  WriteToClient(client, sizeof(xVncExtSetParamReply), (char *)&rep);
-  return (client->noClientException);
-}
-
-static int SProcVncExtSetParam(ClientPtr client)
-{
-  REQUEST(xVncExtSetParamReq);
-#if XORG < 112
-  register char n;
-  swaps(&stuff->length, n);
-#else
-  swaps(&stuff->length);
-#endif
-  REQUEST_AT_LEAST_SIZE(xVncExtSetParamReq);
-  return ProcVncExtSetParam(client);
-}
-
-static int ProcVncExtGetParam(ClientPtr client)
-{
-  REQUEST(xVncExtGetParamReq);
-  REQUEST_FIXED_SIZE(xVncExtGetParamReq, stuff->paramLen);
-  CharArray param(stuff->paramLen+1);
-  strncpy(param.buf, (char*)&stuff[1], stuff->paramLen);
-  param.buf[stuff->paramLen] = 0;
-
-  xVncExtGetParamReply rep;
-  rep.type = X_Reply;
-  rep.sequenceNumber = client->sequence;
-  rep.success = 0;
-  int len = 0;
-  char* value = 0;
-  rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf);
-  // Hack to avoid exposing password!
-  if (strcasecmp(param.buf, "Password") == 0)
-    p = 0;
-  if (p) {
-    value = p->getValueStr();
-    rep.success = 1;
-    len = value ? strlen(value) : 0;
-  }
-  rep.length = (len + 3) >> 2;
-  rep.valueLen = len;
-  if (client->swapped) {
-#if XORG < 112
-    int n;
-    swaps(&rep.sequenceNumber, n);
-    swapl(&rep.length, n);
-    swaps(&rep.valueLen, n);
-#else
-    swaps(&rep.sequenceNumber);
-    swapl(&rep.length);
-    swaps(&rep.valueLen);
-#endif
-  }
-  WriteToClient(client, sizeof(xVncExtGetParamReply), (char *)&rep);
-  if (value)
-    WriteToClient(client, len, value);
-  delete [] value;
-  return (client->noClientException);
-}
-
-static int SProcVncExtGetParam(ClientPtr client)
-{
-  REQUEST(xVncExtGetParamReq);
-#if XORG < 112
-  register char n;
-  swaps(&stuff->length, n);
-#else
-  swaps(&stuff->length);
-#endif
-  REQUEST_AT_LEAST_SIZE(xVncExtGetParamReq);
-  return ProcVncExtGetParam(client);
-}
-
-static int ProcVncExtGetParamDesc(ClientPtr client)
-{
-  REQUEST(xVncExtGetParamDescReq);
-  REQUEST_FIXED_SIZE(xVncExtGetParamDescReq, stuff->paramLen);
-  CharArray param(stuff->paramLen+1);
-  strncpy(param.buf, (char*)&stuff[1], stuff->paramLen);
-  param.buf[stuff->paramLen] = 0;
-
-  xVncExtGetParamDescReply rep;
-  rep.type = X_Reply;
-  rep.sequenceNumber = client->sequence;
-  rep.success = 0;
-  int len = 0;
-  const char* desc = 0;
-  rfb::VoidParameter* p = rfb::Configuration::getParam(param.buf);
-  if (p) {
-    desc = p->getDescription();
-    rep.success = 1;
-    len = desc ? strlen(desc) : 0;
-  }
-  rep.length = (len + 3) >> 2;
-  rep.descLen = len;
-  if (client->swapped) {
-#if XORG < 112
-    int n;
-    swaps(&rep.sequenceNumber, n);
-    swapl(&rep.length, n);
-    swaps(&rep.descLen, n);
-#else
-    swaps(&rep.sequenceNumber);
-    swapl(&rep.length);
-    swaps(&rep.descLen);
-#endif
+  try {
+    network::Socket* sock = new network::TcpSocket(host, port);
+    delete [] host;
+    desktop[0]->addClient(sock, true);
+  } catch (rdr::Exception& e) {
+    vlog.error("Reverse connection: %s",e.str());
+    return -1;
   }
-  WriteToClient(client, sizeof(xVncExtGetParamDescReply), (char *)&rep);
-  if (desc)
-    WriteToClient(client, len, (char*)desc);
-  return (client->noClientException);
-}
 
-static int SProcVncExtGetParamDesc(ClientPtr client)
-{
-  REQUEST(xVncExtGetParamDescReq);
-#if XORG < 112
-  register char n;
-  swaps(&stuff->length, n);
-#else
-  swaps(&stuff->length);
-#endif
-  REQUEST_AT_LEAST_SIZE(xVncExtGetParamDescReq);
-  return ProcVncExtGetParamDesc(client);
+  return 0;
 }
 
-static int ProcVncExtListParams(ClientPtr client)
+void vncGetQueryConnect(uint32_t *opaqueId, const char**username,
+                        const char **address, int *timeout)
 {
-  REQUEST(xVncExtListParamsReq);
-  REQUEST_SIZE_MATCH(xVncExtListParamsReq);
-
-  xVncExtListParamsReply rep;
-  rep.type = X_Reply;
-  rep.sequenceNumber = client->sequence;
-
-  int nParams = 0;
-  int len = 0;
-  for (ParameterIterator i; i.param; i.next()) {
-    int l = strlen(i.param->getName());
-    if (l <= 255) {
-      nParams++;
-      len += l + 1;
-    }
-  }
-  rep.length = (len + 3) >> 2;
-  rep.nParams = nParams;
-  if (client->swapped) {
-#if XORG < 112
-    int n;
-    swaps(&rep.sequenceNumber, n);
-    swapl(&rep.length, n);
-    swaps(&rep.nParams, n);
-#else
-    swaps(&rep.sequenceNumber);
-    swapl(&rep.length);
-    swaps(&rep.nParams);
-#endif
-  }
-  WriteToClient(client, sizeof(xVncExtListParamsReply), (char *)&rep);
-  rdr::U8* data = new rdr::U8[len];
-  rdr::U8* ptr = data;
-  for (ParameterIterator i; i.param; i.next()) {
-    int l = strlen(i.param->getName());
-    if (l <= 255) {
-      *ptr++ = l;
-      memcpy(ptr, i.param->getName(), l);
-      ptr += l;
-    }
+  for (int scr = 0; scr < vncGetScreenCount(); scr++) {
+    if (desktop[scr] == NULL)
+      continue;
+    desktop[scr]->getQueryConnect(opaqueId, username, address, timeout);
+    if (opaqueId != 0)
+      break;
   }
-  WriteToClient(client, len, (char*)data);
-  delete [] data;
-  return (client->noClientException);
 }
 
-static int SProcVncExtListParams(ClientPtr client)
+void vncApproveConnection(uint32_t opaqueId, int approve)
 {
-  REQUEST(xVncExtListParamsReq);
-#if XORG < 112
-  register char n;
-  swaps(&stuff->length, n);
-#else
-  swaps(&stuff->length);
-#endif
-  REQUEST_SIZE_MATCH(xVncExtListParamsReq);
-  return ProcVncExtListParams(client);
-}
-
-static int ProcVncExtSetServerCutText(ClientPtr client)
-{
-  REQUEST(xVncExtSetServerCutTextReq);
-  REQUEST_FIXED_SIZE(xVncExtSetServerCutTextReq, stuff->textLen);
-  char* str = new char[stuff->textLen+1];
-  strncpy(str, (char*)&stuff[1], stuff->textLen);
-  str[stuff->textLen] = 0;
-  for (int scr = 0; scr < screenInfo.numScreens; scr++) {
-    if (desktop[scr]) {
-      desktop[scr]->serverCutText(str, stuff->textLen);
-    }
+  for (int scr = 0; scr < vncGetScreenCount(); scr++) {
+    if (desktop[scr] == NULL)
+      continue;
+    desktop[scr]->approveConnection(opaqueId, approve,
+                                    "Connection rejected by local user");
   }
-  delete [] str;
-  return (client->noClientException);
-}
-
-static int SProcVncExtSetServerCutText(ClientPtr client)
-{
-  REQUEST(xVncExtSetServerCutTextReq);
-#if XORG < 112
-  register char n;
-  swaps(&stuff->length, n);
-#else
-  swaps(&stuff->length);
-#endif
-  REQUEST_AT_LEAST_SIZE(xVncExtSetServerCutTextReq);
-#if XORG < 112
-  swapl(&stuff->textLen, n);
-#else
-  swapl(&stuff->textLen);
-#endif
-  return ProcVncExtSetServerCutText(client);
 }
 
-static int ProcVncExtGetClientCutText(ClientPtr client)
+void vncBell()
 {
-  REQUEST(xVncExtGetClientCutTextReq);
-  REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
-
-  xVncExtGetClientCutTextReply rep;
-  rep.type = X_Reply;
-  rep.length = (clientCutTextLen + 3) >> 2;
-  rep.sequenceNumber = client->sequence;
-  rep.textLen = clientCutTextLen;
-  if (client->swapped) {
-#if XORG < 112
-    int n;
-    swaps(&rep.sequenceNumber, n);
-    swapl(&rep.length, n);
-    swapl(&rep.textLen, n);
-#else
-    swaps(&rep.sequenceNumber);
-    swapl(&rep.length);
-    swapl(&rep.textLen);
-#endif
+  for (int scr = 0; scr < vncGetScreenCount(); scr++) {
+    if (desktop[scr] == NULL)
+      continue;
+    desktop[scr]->bell();
   }
-  WriteToClient(client, sizeof(xVncExtGetClientCutTextReply), (char *)&rep);
-  if (clientCutText)
-    WriteToClient(client, clientCutTextLen, clientCutText);
-  return (client->noClientException);
-}
-
-static int SProcVncExtGetClientCutText(ClientPtr client)
-{
-  REQUEST(xVncExtGetClientCutTextReq);
-#if XORG < 112
-  register char n;
-  swaps(&stuff->length, n);
-#else
-  swaps(&stuff->length);
-#endif
-  REQUEST_SIZE_MATCH(xVncExtGetClientCutTextReq);
-  return ProcVncExtGetClientCutText(client);
 }
 
-static int ProcVncExtSelectInput(ClientPtr client)
+void vncAddChanged(int scrIdx, const struct UpdateRect *extents,
+                   int nRects, const struct UpdateRect *rects)
 {
-  REQUEST(xVncExtSelectInputReq);
-  REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
-  VncInputSelect** nextPtr = &vncInputSelectHead;
-  VncInputSelect* cur;
-  for (cur = vncInputSelectHead; cur; cur = *nextPtr) {
-    if (cur->client == client && cur->window == stuff->window) {
-      cur->mask = stuff->mask;
-      if (!cur->mask) {
-        *nextPtr = cur->next;
-        delete cur;
-      }
-      break;
-    }
-    nextPtr = &cur->next;
-  }
-  if (!cur) {
-    cur = new VncInputSelect(client, stuff->window, stuff->mask);
-  }
-  return (client->noClientException);
-}
+  Region reg;
 
-static int SProcVncExtSelectInput(ClientPtr client)
-{
-  REQUEST(xVncExtSelectInputReq);
-#if XORG < 112
-  register char n;
-  swaps(&stuff->length, n);
-#else
-  swaps(&stuff->length);
-#endif
-  REQUEST_SIZE_MATCH(xVncExtSelectInputReq);
-#if XORG < 112
-  swapl(&stuff->window, n);
-  swapl(&stuff->mask, n);
-#else
-  swapl(&stuff->window);
-  swapl(&stuff->mask);
-#endif
-  return ProcVncExtSelectInput(client);
+  reg.setExtentsAndOrderedRects((ShortRect*)extents,
+                                nRects, (ShortRect*)rects);
+  desktop[scrIdx]->add_changed(reg);
 }
 
-static int ProcVncExtConnect(ClientPtr client)
+void vncAddCopied(int scrIdx, const struct UpdateRect *extents,
+                  int nRects, const struct UpdateRect *rects,
+                  int dx, int dy)
 {
-  REQUEST(xVncExtConnectReq);
-  REQUEST_FIXED_SIZE(xVncExtConnectReq, stuff->strLen);
-  CharArray str(stuff->strLen+1);
-  strncpy(str.buf, (char*)&stuff[1], stuff->strLen);
-  str.buf[stuff->strLen] = 0;
-
-  xVncExtConnectReply rep;
-  rep.success = 0;
-  if (desktop[0]) {
-    if (stuff->strLen == 0) {
-      try {
-        desktop[0]->disconnectClients();
-        rep.success = 1;
-      } catch (rdr::Exception& e) {
-        vlog.error("Disconnecting all clients: %s",e.str());
-      }
-    } else {
-      int port = 5500;
-      for (int i = 0; i < stuff->strLen; i++) {
-        if (str.buf[i] == ':') {
-          port = atoi(&str.buf[i+1]);
-          str.buf[i] = 0;
-          break;
-        }
-      }
-
-      try {
-        network::Socket* sock = new network::TcpSocket(str.buf, port);
-        desktop[0]->addClient(sock, true);
-       rep.success = 1;
-      } catch (rdr::Exception& e) {
-        vlog.error("Reverse connection: %s",e.str());
-      }
-    }
-  }
+  Region reg;
 
-  rep.type = X_Reply;
-  rep.length = 0;
-  rep.sequenceNumber = client->sequence;
-  if (client->swapped) {
-#if XORG < 112
-    int n;
-    swaps(&rep.sequenceNumber, n);
-    swapl(&rep.length, n);
-#else
-    swaps(&rep.sequenceNumber);
-    swapl(&rep.length);
-#endif
-  }
-  WriteToClient(client, sizeof(xVncExtConnectReply), (char *)&rep);
-  return (client->noClientException);
+  reg.setExtentsAndOrderedRects((ShortRect*)extents,
+                                nRects, (ShortRect*)rects);
+  desktop[scrIdx]->add_copied(reg, rfb::Point(dx, dy));
 }
 
-static int SProcVncExtConnect(ClientPtr client)
+void vncSetCursor(int scrIdx, int width, int height, int hotX, int hotY,
+                  const unsigned char *rgbaData)
 {
-  REQUEST(xVncExtConnectReq);
-#if XORG < 112
-  register char n;
-  swaps(&stuff->length, n);
-#else
-  swaps(&stuff->length);
-#endif
-  REQUEST_AT_LEAST_SIZE(xVncExtConnectReq);
-  return ProcVncExtConnect(client);
+  desktop[scrIdx]->setCursor(width, height, hotX, hotY, rgbaData);
 }
 
-
-static int ProcVncExtGetQueryConnect(ClientPtr client)
+void vncPreScreenResize(int scrIdx)
 {
-  REQUEST(xVncExtGetQueryConnectReq);
-  REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
-
-  const char *qcAddress=0, *qcUsername=0;
-  int qcTimeout;
-  if (queryConnectDesktop)
-    qcTimeout = queryConnectDesktop->getQueryTimeout(queryConnectId,
-                                                     &qcAddress, &qcUsername);
-  else
-    qcTimeout = 0;
-
-  xVncExtGetQueryConnectReply rep;
-  rep.type = X_Reply;
-  rep.sequenceNumber = client->sequence;
-  rep.timeout = qcTimeout;
-  rep.addrLen = qcTimeout ? strlen(qcAddress) : 0;
-  rep.userLen = qcTimeout ? strlen(qcUsername) : 0;
-  rep.opaqueId = (CARD32)(long)queryConnectId;
-  rep.length = ((rep.userLen + 3) >> 2) + ((rep.addrLen + 3) >> 2);
-  if (client->swapped) {
-#if XORG < 112
-    int n;
-    swaps(&rep.sequenceNumber, n);
-    swapl(&rep.addrLen, n);
-    swapl(&rep.userLen, n);
-    swapl(&rep.timeout, n);
-    swapl(&rep.opaqueId, n);
-    swapl(&rep.length, n);
-#else
-    swaps(&rep.sequenceNumber);
-    swapl(&rep.addrLen);
-    swapl(&rep.userLen);
-    swapl(&rep.timeout);
-    swapl(&rep.opaqueId);
-    swapl(&rep.length);
-#endif
-  }
-  WriteToClient(client, sizeof(xVncExtGetQueryConnectReply), (char *)&rep);
-  if (qcTimeout)
-    WriteToClient(client, strlen(qcAddress), (char*)qcAddress);
-  if (qcTimeout)
-    WriteToClient(client, strlen(qcUsername), (char*)qcUsername);
-  return (client->noClientException);
+  // We need to prevent the RFB core from accessing the framebuffer
+  // for a while as there might be updates thrown our way inside
+  // the routines that change the screen (i.e. before we have a
+  // pointer to the new framebuffer).
+  desktop[scrIdx]->blockUpdates();
 }
 
-static int SProcVncExtGetQueryConnect(ClientPtr client)
+void vncPostScreenResize(int scrIdx, int success, int width, int height)
 {
-  REQUEST(xVncExtGetQueryConnectReq);
-#if XORG < 112
-  register char n;
-  swaps(&stuff->length, n);
-#else
-  swaps(&stuff->length);
-#endif
-  REQUEST_SIZE_MATCH(xVncExtGetQueryConnectReq);
-  return ProcVncExtGetQueryConnect(client);
-}
-
-
-static int ProcVncExtApproveConnect(ClientPtr client)
-{
-  REQUEST(xVncExtApproveConnectReq);
-  REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
-  if ((CARD32)(long)queryConnectId == stuff->opaqueId) {
-    for (int scr = 0; scr < screenInfo.numScreens; scr++) {
-      if (desktop[scr]) {
-        desktop[scr]->approveConnection(queryConnectId, stuff->approve,
-                                        "Connection rejected by local user");
-      }
-    }
-    // Inform other clients of the event and tidy up
-    vncQueryConnect(queryConnectDesktop, queryConnectId);
+  if (success) {
+    // Let the RFB core know of the new dimensions and framebuffer
+    desktop[scrIdx]->setFramebuffer(width, height,
+                                    vncFbptr[scrIdx], vncFbstride[scrIdx]);
   }
-  return (client->noClientException);
-}
-
-static int SProcVncExtApproveConnect(ClientPtr client)
-{
-  REQUEST(xVncExtApproveConnectReq);
-#if XORG < 112
-  register char n;
-  swaps(&stuff->length, n);
-  swapl(&stuff->opaqueId, n);
-#else
-  swaps(&stuff->length);
-  swapl(&stuff->opaqueId);
-#endif
-  REQUEST_SIZE_MATCH(xVncExtApproveConnectReq);
-  return ProcVncExtApproveConnect(client);
-}
 
+  desktop[scrIdx]->unblockUpdates();
 
-static int ProcVncExtDispatch(ClientPtr client)
-{
-  REQUEST(xReq);
-  switch (stuff->data) {
-  case X_VncExtSetParam:
-    return ProcVncExtSetParam(client);
-  case X_VncExtGetParam:
-    return ProcVncExtGetParam(client);
-  case X_VncExtGetParamDesc:
-    return ProcVncExtGetParamDesc(client);
-  case X_VncExtListParams:
-    return ProcVncExtListParams(client);
-  case X_VncExtSetServerCutText:
-    return ProcVncExtSetServerCutText(client);
-  case X_VncExtGetClientCutText:
-    return ProcVncExtGetClientCutText(client);
-  case X_VncExtSelectInput:
-    return ProcVncExtSelectInput(client);
-  case X_VncExtConnect:
-    return ProcVncExtConnect(client);
-  case X_VncExtGetQueryConnect:
-    return ProcVncExtGetQueryConnect(client);
-  case X_VncExtApproveConnect:
-    return ProcVncExtApproveConnect(client);
-  default:
-    return BadRequest;
+  if (success) {
+    // Mark entire screen as changed
+    desktop[scrIdx]->add_changed(Region(Rect(0, 0, width, height)));
   }
 }
 
-static int SProcVncExtDispatch(ClientPtr client)
+void vncRefreshScreenLayout(int scrIdx)
 {
-  REQUEST(xReq);
-  switch (stuff->data) {
-  case X_VncExtSetParam:
-    return SProcVncExtSetParam(client);
-  case X_VncExtGetParam:
-    return SProcVncExtGetParam(client);
-  case X_VncExtGetParamDesc:
-    return SProcVncExtGetParamDesc(client);
-  case X_VncExtListParams:
-    return SProcVncExtListParams(client);
-  case X_VncExtSetServerCutText:
-    return SProcVncExtSetServerCutText(client);
-  case X_VncExtGetClientCutText:
-    return SProcVncExtGetClientCutText(client);
-  case X_VncExtSelectInput:
-    return SProcVncExtSelectInput(client);
-  case X_VncExtConnect:
-    return SProcVncExtConnect(client);
-  case X_VncExtGetQueryConnect:
-    return SProcVncExtGetQueryConnect(client);
-  case X_VncExtApproveConnect:
-    return SProcVncExtApproveConnect(client);
-  default:
-    return BadRequest;
-  }
+  desktop[scrIdx]->refreshScreenLayout();
 }
-
index 931c28f32ef72d7b8a88a1c17292594692181586..6c9857c0c04adbce22bc4a03078f4d1e35159abb 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2011-2015 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
 #ifndef __VNCEXTINIT_H__
 #define __VNCEXTINIT_H__
 
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
+#include <stdint.h>
+#include <sys/select.h>
+
+// Only from C++
+#ifdef __cplusplus
+namespace rfb { class StringParameter; };
+
+extern rfb::StringParameter httpDir;
 #endif
 
-#include <rfb/Configuration.h>
-#include "XserverDesktop.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// vncExt.c
+extern int vncNoClipboard;
+
+int vncAddExtension(void);
 
-extern void vncClientCutText(const char* str, int len);
-extern void vncQueryConnect(XserverDesktop* desktop, void* opaqueId);
-extern void vncClientGone(int fd);
-extern void vncBell();
+int vncNotifyQueryConnect(void);
+
+void vncClientCutText(const char* str, int len);
+
+// vncExtInit.cc
 extern void* vncFbptr[];
 extern int vncFbstride[];
-extern bool noclipboard;
+
 extern int vncInetdSock;
-extern rfb::StringParameter httpDir;
+
+void vncExtensionInit(void);
+
+void vncCallReadBlockHandlers(fd_set * fds, struct timeval ** timeout);
+void vncCallReadWakeupHandlers(fd_set * fds, int nfds);
+void vncCallWriteBlockHandlers(fd_set * fds, struct timeval ** timeout);
+void vncCallWriteWakeupHandlers(fd_set * fds, int nfds);
+
+int vncGetAvoidShiftNumLock(void);
+
+void vncUpdateDesktopName(void);
+
+void vncServerCutText(const char *text, size_t len);
+
+int vncConnectClient(const char *addr);
+
+void vncGetQueryConnect(uint32_t *opaqueId, const char**username,
+                        const char **address, int *timeout);
+void vncApproveConnection(uint32_t opaqueId, int approve);
+
+void vncBell(void);
+
+// Must match rfb::ShortRect in common/rfb/Region.h, and BoxRec in the
+// Xorg source.
+struct UpdateRect {
+  short x1, y1, x2, y2;
+};
+
+void vncAddChanged(int scrIdx, const struct UpdateRect *extents,
+                   int nRects, const struct UpdateRect *rects);
+void vncAddCopied(int scrIdx, const struct UpdateRect *extents,
+                  int nRects, const struct UpdateRect *rects,
+                  int dx, int dy);
+
+void vncSetCursor(int scrIdx, int width, int height, int hotX, int hotY,
+                  const unsigned char *rgbaData);
+
+void vncPreScreenResize(int scrIdx);
+void vncPostScreenResize(int scrIdx, int success, int width, int height);
+void vncRefreshScreenLayout(int scrIdx);
+
+#ifdef __cplusplus
+}
+#endif
 
 #endif
diff --git a/unix/xserver/hw/vnc/vncHooks.c b/unix/xserver/hw/vnc/vncHooks.c
new file mode 100644 (file)
index 0000000..dc2b811
--- /dev/null
@@ -0,0 +1,2105 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2009-2015 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 <stdio.h>
+
+#include "vncHooks.h"
+#include "vncExtInit.h"
+
+#include "xorg-version.h"
+
+#include "scrnintstr.h"
+#include "windowstr.h"
+#include "cursorstr.h"
+#include "gcstruct.h"
+#include "regionstr.h"
+#include "dixfontstr.h"
+#include "colormapst.h"
+#ifdef RENDER
+#include "picturestr.h"
+#endif
+#ifdef RANDR
+#include "randrstr.h"
+#endif
+
+#define DBGPRINT(x) //(fprintf x)
+
+// REGION_NULL was introduced in the Xorg tree as the way to initialise an
+// empty region.  If it's not already defined do it the old way.  Note that the
+// old way causes a segfault in the new tree...
+#ifndef REGION_NULL
+#define REGION_NULL(pScreen,pReg) REGION_INIT(pScreen,pReg,NullBox,0)
+#endif
+
+// MAX_RECTS_PER_OP is the maximum number of rectangles we generate from
+// operations like Polylines and PolySegment.  If the operation is more complex
+// than this, we simply use the bounding box.  Ideally it would be a
+// command-line option, but that would involve an extra malloc each time, so we
+// fix it here.
+#define MAX_RECTS_PER_OP 5
+
+// vncHooksScreenRec and vncHooksGCRec contain pointers to the original
+// functions which we "wrap" in order to hook the screen changes.  The screen
+// functions are each wrapped individually, while the GC "funcs" and "ops" are
+// wrapped as a unit.
+
+typedef struct _vncHooksScreenRec {
+  int                          ignoreHooks;
+
+  CloseScreenProcPtr           CloseScreen;
+  CreateGCProcPtr              CreateGC;
+  CopyWindowProcPtr            CopyWindow;
+  ClearToBackgroundProcPtr     ClearToBackground;
+#if XORG < 110
+  RestoreAreasProcPtr          RestoreAreas;
+#endif
+  DisplayCursorProcPtr         DisplayCursor;
+  ScreenBlockHandlerProcPtr    BlockHandler;
+#ifdef RENDER
+  CompositeProcPtr             Composite;
+  GlyphsProcPtr                Glyphs;
+#endif
+#ifdef RANDR
+  RRSetConfigProcPtr           RandRSetConfig;
+  RRScreenSetSizeProcPtr       RandRScreenSetSize;
+  RRCrtcSetProcPtr             RandRCrtcSet;
+#endif
+} vncHooksScreenRec, *vncHooksScreenPtr;
+
+typedef struct _vncHooksGCRec {
+#if XORG >= 116
+    const GCFuncs *wrappedFuncs;
+    const GCOps *wrappedOps;
+#else
+    GCFuncs *wrappedFuncs;
+    GCOps *wrappedOps;
+#endif
+} vncHooksGCRec, *vncHooksGCPtr;
+
+#if XORG == 15
+static DevPrivateKey vncHooksScreenPrivateKey = &vncHooksScreenPrivateKey;
+static DevPrivateKey vncHooksGCPrivateKey = &vncHooksGCPrivateKey;
+#elif XORG < 19
+static int vncHooksScreenPrivateKeyIndex;
+static int vncHooksGCPrivateKeyIndex;
+static DevPrivateKey vncHooksScreenPrivateKey = &vncHooksScreenPrivateKeyIndex;
+static DevPrivateKey vncHooksGCPrivateKey = &vncHooksGCPrivateKeyIndex;
+#else
+static DevPrivateKeyRec vncHooksScreenKeyRec;
+static DevPrivateKeyRec vncHooksGCKeyRec;
+#define vncHooksScreenPrivateKey (&vncHooksScreenKeyRec)
+#define vncHooksGCPrivateKey (&vncHooksGCKeyRec)
+#endif
+
+#define vncHooksScreenPrivate(pScreen) \
+        (vncHooksScreenPtr) dixLookupPrivate(&(pScreen)->devPrivates, \
+                                             vncHooksScreenPrivateKey)
+#define vncHooksGCPrivate(pGC) \
+        (vncHooksGCPtr) dixLookupPrivate(&(pGC)->devPrivates, \
+                                         vncHooksGCPrivateKey)
+
+// screen functions
+
+#if XORG <= 112
+static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen);
+#else
+static Bool vncHooksCloseScreen(ScreenPtr pScreen);
+#endif
+static Bool vncHooksCreateGC(GCPtr pGC);
+static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
+                               RegionPtr pOldRegion);
+static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
+                                      int h, Bool generateExposures);
+#if XORG < 110
+static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed);
+#endif
+static Bool vncHooksDisplayCursor(
+#if XORG >= 16
+                                 DeviceIntPtr pDev,
+#endif
+                                 ScreenPtr pScreen, CursorPtr cursor);
+#if XORG <= 112
+static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
+                                 pointer pReadmask);
+#else
+static void vncHooksBlockHandler(ScreenPtr pScreen, void * pTimeout,
+                                 void * pReadmask);
+#endif
+#ifdef RENDER
+static void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, 
+                             PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, 
+                             INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
+static void vncHooksGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 
+                             PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists, 
+                             GlyphListPtr lists, GlyphPtr * glyphs);
+#endif
+#ifdef RANDR
+static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
+                                   int rate, RRScreenSizePtr pSize);
+static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
+                                       CARD16 width, CARD16 height,
+                                       CARD32 mmWidth, CARD32 mmHeight);
+static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
+                                 RRModePtr mode, int x, int y,
+                                 Rotation rotation, int numOutputs,
+                                 RROutputPtr *outputs);
+#endif
+
+// GC "funcs"
+
+static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
+                               DrawablePtr pDrawable);
+static void vncHooksChangeGC(GCPtr pGC, unsigned long mask);
+static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst);
+static void vncHooksDestroyGC(GCPtr pGC);
+static void vncHooksChangeClip(GCPtr pGC, int type, void * pValue,int nrects);
+static void vncHooksDestroyClip(GCPtr pGC);
+static void vncHooksCopyClip(GCPtr dst, GCPtr src);
+
+static GCFuncs vncHooksGCFuncs = {
+  vncHooksValidateGC, vncHooksChangeGC, vncHooksCopyGC, vncHooksDestroyGC,
+  vncHooksChangeClip, vncHooksDestroyClip, vncHooksCopyClip,
+};
+
+// GC "ops"
+
+static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
+                              DDXPointPtr pptInit, int *pwidthInit,
+                              int fSorted);
+static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+                             DDXPointPtr ppt, int *pwidth, int nspans,
+                             int fSorted);
+static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
+                             int x, int y, int w, int h, int leftPad,
+                             int format, char *pBits);
+static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
+                                  GCPtr pGC, int srcx, int srcy, int w, int h,
+                                  int dstx, int dsty);
+static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
+                                   GCPtr pGC, int srcx, int srcy, int w, int h,
+                                   int dstx, int dsty, unsigned long plane);
+static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
+                              int npt, xPoint *pts);
+static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
+                              int npt, DDXPointPtr ppts);
+static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
+                                xSegment *segs);
+static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
+                                  xRectangle *rects);
+static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
+                            xArc *arcs);
+static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
+                                int mode, int count, DDXPointPtr pts);
+static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
+                                 xRectangle *rects);
+static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
+                                xArc *arcs);
+static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
+                             int count, char *chars);
+static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
+                              int count, unsigned short *chars);
+static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
+                               int count, char *chars);
+static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
+                                int count, unsigned short *chars);
+static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
+                                  int y, unsigned int nglyph,
+                                  CharInfoPtr *ppci, void * pglyphBase);
+static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
+                                 int y, unsigned int nglyph,
+                                 CharInfoPtr *ppci, void * pglyphBase);
+static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
+                               DrawablePtr pDrawable, int w, int h, int x,
+                               int y);
+
+static GCOps vncHooksGCOps = {
+  vncHooksFillSpans, vncHooksSetSpans, vncHooksPutImage, vncHooksCopyArea,
+  vncHooksCopyPlane, vncHooksPolyPoint, vncHooksPolylines, vncHooksPolySegment,
+  vncHooksPolyRectangle, vncHooksPolyArc, vncHooksFillPolygon,
+  vncHooksPolyFillRect, vncHooksPolyFillArc, vncHooksPolyText8,
+  vncHooksPolyText16, vncHooksImageText8, vncHooksImageText16,
+  vncHooksImageGlyphBlt, vncHooksPolyGlyphBlt, vncHooksPushPixels
+};
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// vncHooksInit() is called at initialisation time and every time the server
+// resets.  It is called once for each screen, but the indexes are only
+// allocated once for each server generation.
+
+int vncHooksInit(int scrIdx)
+{
+  ScreenPtr pScreen;
+  vncHooksScreenPtr vncHooksScreen;
+
+#ifdef RENDER
+  PictureScreenPtr ps;
+#endif
+#ifdef RANDR
+  rrScrPrivPtr rp;
+#endif
+
+  pScreen = screenInfo.screens[scrIdx];
+
+  if (sizeof(BoxRec) != sizeof(struct UpdateRect)) {
+    ErrorF("vncHooksInit: Incompatible BoxRec size\n");
+    return FALSE;
+  }
+
+#if XORG < 19
+  if (!dixRequestPrivate(vncHooksScreenPrivateKey, sizeof(vncHooksScreenRec))) {
+    ErrorF("vncHooksInit: Allocation of vncHooksScreen failed\n");
+    return FALSE;
+  }
+  if (!dixRequestPrivate(vncHooksGCPrivateKey, sizeof(vncHooksGCRec))) {
+    ErrorF("vncHooksInit: Allocation of vncHooksGCRec failed\n");
+    return FALSE;
+  }
+
+#else
+  if (!dixRegisterPrivateKey(&vncHooksScreenKeyRec, PRIVATE_SCREEN,
+      sizeof(vncHooksScreenRec))) {
+    ErrorF("vncHooksInit: Allocation of vncHooksScreen failed\n");
+    return FALSE;
+  }
+  if (!dixRegisterPrivateKey(&vncHooksGCKeyRec, PRIVATE_GC,
+      sizeof(vncHooksGCRec))) {
+    ErrorF("vncHooksInit: Allocation of vncHooksGCRec failed\n");
+    return FALSE;
+  }
+
+#endif
+
+  vncHooksScreen = vncHooksScreenPrivate(pScreen);
+
+  vncHooksScreen->ignoreHooks = 0;
+
+  vncHooksScreen->CloseScreen = pScreen->CloseScreen;
+  vncHooksScreen->CreateGC = pScreen->CreateGC;
+  vncHooksScreen->CopyWindow = pScreen->CopyWindow;
+  vncHooksScreen->ClearToBackground = pScreen->ClearToBackground;
+#if XORG < 110
+  vncHooksScreen->RestoreAreas = pScreen->RestoreAreas;
+#endif
+  vncHooksScreen->DisplayCursor = pScreen->DisplayCursor;
+  vncHooksScreen->BlockHandler = pScreen->BlockHandler;
+#ifdef RENDER
+  ps = GetPictureScreenIfSet(pScreen);
+  if (ps) {
+    vncHooksScreen->Composite = ps->Composite;
+    vncHooksScreen->Glyphs = ps->Glyphs;
+  }
+#endif
+#ifdef RANDR
+  rp = rrGetScrPriv(pScreen);
+  if (rp) {
+    vncHooksScreen->RandRSetConfig = rp->rrSetConfig;
+    vncHooksScreen->RandRScreenSetSize = rp->rrScreenSetSize;
+    vncHooksScreen->RandRCrtcSet = rp->rrCrtcSet;
+  }
+#endif
+
+  pScreen->CloseScreen = vncHooksCloseScreen;
+  pScreen->CreateGC = vncHooksCreateGC;
+  pScreen->CopyWindow = vncHooksCopyWindow;
+  pScreen->ClearToBackground = vncHooksClearToBackground;
+#if XORG < 110
+  pScreen->RestoreAreas = vncHooksRestoreAreas;
+#endif
+  pScreen->DisplayCursor = vncHooksDisplayCursor;
+  pScreen->BlockHandler = vncHooksBlockHandler;
+#ifdef RENDER
+  if (ps) {
+    ps->Composite = vncHooksComposite;
+    ps->Glyphs = vncHooksGlyphs;
+  }
+#endif
+#ifdef RANDR
+  if (rp) {
+    /* Some RandR callbacks are optional */
+    if (rp->rrSetConfig)
+      rp->rrSetConfig = vncHooksRandRSetConfig;
+    if (rp->rrScreenSetSize)
+      rp->rrScreenSetSize = vncHooksRandRScreenSetSize;
+    if (rp->rrCrtcSet)
+      rp->rrCrtcSet = vncHooksRandRCrtcSet;
+  }
+#endif
+
+  return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// vncGetScreenImage() grabs a chunk of data from the main screen into the
+// provided buffer. It lives here rather than in XorgGlue.c because it
+// temporarily pauses the hooks.
+
+void vncGetScreenImage(int scrIdx, int x, int y, int width, int height,
+                       char *buffer, int strideBytes)
+{
+  ScreenPtr pScreen = screenInfo.screens[scrIdx];
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+
+  int i;
+
+  vncHooksScreen->ignoreHooks++;
+
+  // We do one line at a time since GetImage() cannot handle stride
+  for (i = y; i < y + height; i++) {
+    DrawablePtr pDrawable;
+#if XORG < 19
+    pDrawable = (DrawablePtr) WindowTable[scrIdx];
+#else
+    pDrawable = (DrawablePtr) pScreen->root;
+#endif
+
+    (*pScreen->GetImage) (pDrawable, x, i, width, 1,
+                          ZPixmap, (unsigned long)~0L, buffer);
+
+    buffer += strideBytes;
+  }
+
+  vncHooksScreen->ignoreHooks--;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Helper functions for adding changes and copies
+//
+
+static inline void add_changed(ScreenPtr pScreen, RegionPtr reg)
+{
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+  if (vncHooksScreen->ignoreHooks)
+    return;
+  vncAddChanged(pScreen->myNum,
+                (const struct UpdateRect*)REGION_EXTENTS(pScreen, reg),
+                REGION_NUM_RECTS(reg),
+                (const struct UpdateRect*)REGION_RECTS(reg));
+}
+
+static inline void add_copied(ScreenPtr pScreen, RegionPtr dst,
+                              int dx, int dy)
+{
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+  if (vncHooksScreen->ignoreHooks)
+    return;
+  vncAddCopied(pScreen->myNum,
+               (const struct UpdateRect*)REGION_EXTENTS(pScreen, dst),
+               REGION_NUM_RECTS(dst),
+               (const struct UpdateRect*)REGION_RECTS(dst), dx, dy);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// screen functions
+//
+
+// SCREEN_UNWRAP and SCREEN_REWRAP unwrap and rewrap the given screen function.
+
+#define SCREEN_UNWRAP(scrn,field)                                         \
+  ScreenPtr pScreen = scrn;                                               \
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);      \
+  pScreen->field = vncHooksScreen->field;                                 \
+  DBGPRINT((stderr,"vncHooks" #field " called\n"));
+
+#define SCREEN_REWRAP(field) pScreen->field = vncHooks##field;
+
+
+// CloseScreen - unwrap the screen functions and call the original CloseScreen
+// function
+
+#if XORG <= 112
+static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen_)
+#else
+static Bool vncHooksCloseScreen(ScreenPtr pScreen_)
+#endif
+{
+#ifdef RENDER
+  PictureScreenPtr ps;
+#endif
+#ifdef RANDR
+  rrScrPrivPtr rp;
+#endif
+
+  SCREEN_UNWRAP(pScreen_, CloseScreen);
+
+  pScreen->CreateGC = vncHooksScreen->CreateGC;
+  pScreen->CopyWindow = vncHooksScreen->CopyWindow;
+  pScreen->ClearToBackground = vncHooksScreen->ClearToBackground;
+#if XORG < 110
+  pScreen->RestoreAreas = vncHooksScreen->RestoreAreas;
+#endif
+  pScreen->DisplayCursor = vncHooksScreen->DisplayCursor;
+  pScreen->BlockHandler = vncHooksScreen->BlockHandler;
+#ifdef RENDER
+  ps = GetPictureScreenIfSet(pScreen);
+  if (ps) {
+    ps->Composite = vncHooksScreen->Composite;
+    ps->Glyphs = vncHooksScreen->Glyphs;
+  }
+#endif
+#ifdef RANDR
+  rp = rrGetScrPriv(pScreen);
+  if (rp) {
+    rp->rrSetConfig = vncHooksScreen->RandRSetConfig;
+    rp->rrScreenSetSize = vncHooksScreen->RandRScreenSetSize;
+    rp->rrCrtcSet = vncHooksScreen->RandRCrtcSet;
+  }
+#endif
+
+  DBGPRINT((stderr,"vncHooksCloseScreen: unwrapped screen functions\n"));
+
+#if XORG <= 112
+  return (*pScreen->CloseScreen)(i, pScreen);
+#else
+  return (*pScreen->CloseScreen)(pScreen);
+#endif
+}
+
+// CreateGC - wrap the "GC funcs"
+
+static Bool vncHooksCreateGC(GCPtr pGC)
+{
+  vncHooksGCPtr vncHooksGC = vncHooksGCPrivate(pGC);
+  Bool ret;
+
+  SCREEN_UNWRAP(pGC->pScreen, CreateGC);
+
+  ret = (*pScreen->CreateGC) (pGC);
+
+  vncHooksGC->wrappedOps = 0;
+  vncHooksGC->wrappedFuncs = pGC->funcs;
+  pGC->funcs = &vncHooksGCFuncs;
+
+  SCREEN_REWRAP(CreateGC);
+
+  return ret;
+}
+
+// CopyWindow - destination of the copy is the old region, clipped by
+// borderClip, translated by the delta.  This call only does the copy - it
+// doesn't affect any other bits.
+
+static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
+                               RegionPtr pOldRegion)
+{
+  int dx, dy;
+  BoxRec screen_box;
+  RegionRec copied, screen_rgn;
+
+  SCREEN_UNWRAP(pWin->drawable.pScreen, CopyWindow);
+
+  REGION_NULL(pScreen, &copied);
+  REGION_COPY(pScreen, &copied, pOldRegion);
+
+  screen_box.x1 = 0;
+  screen_box.y1 = 0;
+  screen_box.x2 = pScreen->width;
+  screen_box.y2 = pScreen->height;
+
+  REGION_INIT(pScreen, &screen_rgn, &screen_box, 1);
+
+  dx = pWin->drawable.x - ptOldOrg.x;
+  dy = pWin->drawable.y - ptOldOrg.y;
+
+  // RFB tracks copies in terms of destination rectangle, not source.
+  // We also need to copy with changes to the Window's clipping region.
+  // Finally, make sure we don't get copies to or from regions outside
+  // the framebuffer.
+  REGION_INTERSECT(pScreen, &copied, &copied, &screen_rgn);
+  REGION_TRANSLATE(pScreen, &copied, dx, dy);
+  REGION_INTERSECT(pScreen, &copied, &copied, &screen_rgn);
+  REGION_INTERSECT(pScreen, &copied, &copied, &pWin->borderClip);
+
+  (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion);
+
+  if (REGION_NOTEMPTY(pScreen, &copied))
+    add_copied(pScreen, &copied, dx, dy);
+
+  REGION_UNINIT(pScreen, &copied);
+  REGION_UNINIT(pScreen, &screen_rgn);
+
+  SCREEN_REWRAP(CopyWindow);
+}
+
+// ClearToBackground - changed region is the given rectangle, clipped by
+// clipList, but only if generateExposures is false.
+
+static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
+                                      int h, Bool generateExposures)
+{
+  BoxRec box;
+  RegionRec reg;
+
+  SCREEN_UNWRAP(pWin->drawable.pScreen, ClearToBackground);
+
+  box.x1 = x + pWin->drawable.x;
+  box.y1 = y + pWin->drawable.y;
+  box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width);
+  box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height);
+
+  REGION_INIT(pScreen, &reg, &box, 0);
+  REGION_INTERSECT(pScreen, &reg, &reg, &pWin->clipList);
+
+  (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
+
+  if (!generateExposures) {
+    add_changed(pScreen, &reg);
+  }
+
+  REGION_UNINIT(pScreen, &reg);
+
+  SCREEN_REWRAP(ClearToBackground);
+}
+
+#if XORG < 110
+// RestoreAreas - changed region is the given region
+
+static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr pRegion)
+{
+  RegionRec reg;
+
+  SCREEN_UNWRAP(pWin->drawable.pScreen, RestoreAreas);
+
+  REGION_NULL(pScreen, &reg);
+  REGION_COPY(pScreen, &reg, pRegion);
+
+  RegionPtr result = (*pScreen->RestoreAreas) (pWin, pRegion);
+
+  add_changed(pScreen, &reg);
+
+  REGION_UNINIT(pScreen, &reg);
+
+  SCREEN_REWRAP(RestoreAreas);
+
+  return result;
+}
+#endif
+
+// DisplayCursor - get the cursor shape
+
+static Bool vncHooksDisplayCursor(
+#if XORG >= 16
+                                 DeviceIntPtr pDev,
+#endif
+                                 ScreenPtr pScreen_, CursorPtr cursor)
+{
+  Bool ret;
+
+  SCREEN_UNWRAP(pScreen_, DisplayCursor);
+
+  ret = (*pScreen->DisplayCursor) (
+#if XORG >= 16
+                                       pDev,
+#endif
+                                       pScreen, cursor);
+
+#if XORG >= 16
+  /*
+   * XXX DIX calls this function with NULL argument to remove cursor sprite from
+   * screen. Should we handle this in setCursor as well?
+   */
+  if (cursor != NullCursor)
+#endif
+  {
+    int width, height;
+    int hotX, hotY;
+
+    unsigned char *rgbaData;
+
+    width = cursor->bits->width;
+    height = cursor->bits->height;
+
+    hotX = cursor->bits->xhot;
+    hotY = cursor->bits->yhot;
+
+    rgbaData = malloc(width * height * 4);
+    if (rgbaData == NULL)
+      goto out;
+
+#ifdef ARGB_CURSOR
+    if (cursor->bits->argb) {
+      unsigned char *out;
+      CARD32 *in;
+      int i;
+
+      in = cursor->bits->argb;
+      out = rgbaData;
+      for (i = 0; i < width*height; i++) {
+        out[0] = (*in >> 16) & 0xff;
+        out[1] = (*in >>  8) & 0xff;
+        out[2] = (*in >>  0) & 0xff;
+        out[3] = (*in >> 24) & 0xff;
+        out += 4;
+        in++;
+      }
+    } else {
+#endif
+      unsigned char *out;
+      int xMaskBytesPerRow;
+
+      xMaskBytesPerRow = BitmapBytePad(width);
+
+      out = rgbaData;
+      for (int y = 0; y < height; y++) {
+        for (int x = 0; x < width; x++) {
+          int byte = y * xMaskBytesPerRow + x / 8;
+#if (BITMAP_BIT_ORDER == MSBFirst)
+          int bit = 7 - x % 8;
+#else
+          int bit = x % 8;
+#endif
+
+          if (cursor->bits->source[byte] & (1 << bit)) {
+            out[0] = cursor->foreRed;
+            out[1] = cursor->foreGreen;
+            out[2] = cursor->foreBlue;
+          } else {
+            out[0] = cursor->backRed;
+            out[1] = cursor->backGreen;
+            out[2] = cursor->backBlue;
+          }
+
+          if (cursor->bits->mask[byte] & (1 << bit))
+            out[3] = 0xff;
+          else
+            out[3] = 0x00;
+
+          out += 4;
+        }
+      }
+#ifdef ARGB_CURSOR
+    }
+#endif
+
+    vncSetCursor(pScreen->myNum, width, height, hotX, hotY, rgbaData);
+  }
+
+out:
+  SCREEN_REWRAP(DisplayCursor);
+
+  return ret;
+}
+
+// BlockHandler - ignore any changes during the block handler - it's likely
+// these are just drawing the cursor.
+
+#if XORG <= 112
+static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
+                                 pointer pReadmask)
+#else
+static void vncHooksBlockHandler(ScreenPtr pScreen_, void * pTimeout,
+                                 void * pReadmask)
+#endif
+{
+#if XORG <= 112
+  SCREEN_UNWRAP(screenInfo.screens[i], BlockHandler);
+#else
+  SCREEN_UNWRAP(pScreen_, BlockHandler);
+#endif
+
+  vncHooksScreen->ignoreHooks++;
+
+#if XORG <= 112
+  (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
+#else
+  (*pScreen->BlockHandler) (pScreen, pTimeout, pReadmask);
+#endif
+
+  vncHooksScreen->ignoreHooks--;
+
+  SCREEN_REWRAP(BlockHandler);
+}
+
+#ifdef RENDER
+
+// Composite - The core of XRENDER
+
+void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, 
+                      PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, 
+                      INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
+{
+  ScreenPtr pScreen = pDst->pDrawable->pScreen;
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+  PictureScreenPtr ps = GetPictureScreen(pScreen);
+
+  RegionRec changed;
+
+  if (pDst->pDrawable->type == DRAWABLE_WINDOW &&
+      ((WindowPtr) pDst->pDrawable)->viewable) {
+    BoxRec box;
+
+    box.x1 = max(pDst->pDrawable->x + xDst, 0);
+    box.y1 = max(pDst->pDrawable->y + yDst, 0);
+    box.x2 = min(box.x1 + width, pScreen->width);
+    box.y2 = min(box.y1 + height, pScreen->height);
+
+    REGION_INIT(pScreen, &changed, &box, 0);
+  } else {
+    REGION_NULL(pScreen, &changed);
+  }
+
+
+  ps->Composite = vncHooksScreen->Composite;
+  (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
+                  xMask, yMask, xDst, yDst, width, height);
+  ps->Composite = vncHooksComposite;
+
+  if (REGION_NOTEMPTY(pScreen, &changed))
+    add_changed(pScreen, &changed);
+
+  REGION_UNINIT(pScreen, &changed);
+}
+
+static int
+GlyphCount(int nlist, GlyphListPtr list, GlyphPtr * glyphs)
+{
+  int count;
+
+  count = 0;
+  while (nlist--) {
+    count += list->len;
+    list++;
+  }
+
+  return count;
+}
+
+static RegionPtr
+GlyphsToRegion(ScreenPtr pScreen, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
+{
+  int n;
+  GlyphPtr glyph;
+  int x, y;
+
+  int nrects = GlyphCount(nlist, list, glyphs);
+  xRectangle rects[nrects];
+  xRectanglePtr rect;
+
+  x = 0;
+  y = 0;
+  rect = &rects[0];
+  while (nlist--) {
+    x += list->xOff;
+    y += list->yOff;
+    n = list->len;
+    list++;
+    while (n--) {
+      glyph = *glyphs++;
+      rect->x = x - glyph->info.x;
+      rect->y = y - glyph->info.y;
+      rect->width = glyph->info.width;
+      rect->height = glyph->info.height;
+      x += glyph->info.xOff;
+      y += glyph->info.yOff;
+      rect++;
+    }
+  }
+
+  return RECTS_TO_REGION(pScreen, nrects, rects, CT_NONE);
+}
+
+// Glyphs - Glyph specific version of Composite (caches and whatnot)
+
+void vncHooksGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 
+           PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists, 
+           GlyphListPtr lists, GlyphPtr * glyphs)
+{
+  ScreenPtr pScreen = pDst->pDrawable->pScreen;
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+  PictureScreenPtr ps = GetPictureScreen(pScreen);
+
+  RegionPtr changed;
+
+  if (pDst->pDrawable->type == DRAWABLE_WINDOW &&
+      ((WindowPtr) pDst->pDrawable)->viewable) {
+    BoxRec fbbox;
+    RegionRec fbreg;
+
+    changed = GlyphsToRegion(pScreen, nlists, lists, glyphs);
+    REGION_TRANSLATE(pScreen, changed,
+                     pDst->pDrawable->x, pDst->pDrawable->y);
+
+    fbbox.x1 = 0;
+    fbbox.y1 = 0;
+    fbbox.x2 = pScreen->width;
+    fbbox.y2 = pScreen->height;
+    REGION_INIT(pScreen, &fbreg, &fbbox, 0);
+
+    REGION_INTERSECT(pScreen, changed, changed, &fbreg);
+
+    REGION_UNINIT(pScreen, &fbreg);
+  } else {
+    changed = REGION_CREATE(pScreen, NullBox, 0);
+  }
+
+  ps->Glyphs = vncHooksScreen->Glyphs;
+  (*ps->Glyphs)(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlists, lists, glyphs);
+  ps->Glyphs = vncHooksGlyphs;
+
+  if (REGION_NOTEMPTY(pScreen, changed))
+    add_changed(pScreen, changed);
+
+  REGION_DESTROY(pScreen, changed);
+}
+
+#endif /* RENDER */
+
+// RandRSetConfig - follow any framebuffer changes
+
+#ifdef RANDR
+
+static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
+                                   int rate, RRScreenSizePtr pSize)
+{
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+  rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+  Bool ret;
+
+  vncPreScreenResize(pScreen->myNum);
+
+  rp->rrSetConfig = vncHooksScreen->RandRSetConfig;
+  ret = (*rp->rrSetConfig)(pScreen, rotation, rate, pSize);
+  rp->rrSetConfig = vncHooksRandRSetConfig;
+
+  vncPostScreenResize(pScreen->myNum, ret, pScreen->width, pScreen->height);
+
+  if (!ret)
+    return FALSE;
+
+  return TRUE;
+}
+
+static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
+                                       CARD16 width, CARD16 height,
+                                       CARD32 mmWidth, CARD32 mmHeight)
+{
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+  rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+  Bool ret;
+
+  vncPreScreenResize(pScreen->myNum);
+
+  rp->rrScreenSetSize = vncHooksScreen->RandRScreenSetSize;
+  ret = (*rp->rrScreenSetSize)(pScreen, width, height, mmWidth, mmHeight);
+  rp->rrScreenSetSize = vncHooksRandRScreenSetSize;
+
+  vncPostScreenResize(pScreen->myNum, ret, pScreen->width, pScreen->height);
+
+  if (!ret)
+    return FALSE;
+
+  return TRUE;
+}
+
+static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
+                                 RRModePtr mode, int x, int y,
+                                 Rotation rotation, int num_outputs,
+                                 RROutputPtr *outputs)
+{
+  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
+  rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+  Bool ret;
+
+  rp->rrCrtcSet = vncHooksScreen->RandRCrtcSet;
+  ret = (*rp->rrCrtcSet)(pScreen, crtc, mode, x, y, rotation,
+                         num_outputs, outputs);
+  rp->rrCrtcSet = vncHooksRandRCrtcSet;
+
+  if (!ret)
+    return FALSE;
+
+  vncRefreshScreenLayout(pScreen->myNum);
+
+  return TRUE;
+}
+
+#endif /* RANDR */
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// GC "funcs"
+//
+
+// Unwrap and rewrap helpers
+
+#define GC_FUNC_PROLOGUE(pGC, name)\
+    vncHooksGCPtr pGCPriv = vncHooksGCPrivate(pGC);\
+    (pGC)->funcs = pGCPriv->wrappedFuncs;\
+    if(pGCPriv->wrappedOps)\
+        (pGC)->ops = pGCPriv->wrappedOps; \
+    DBGPRINT((stderr,"vncHooks" #name " called\n"))
+
+#define GC_FUNC_EPILOGUE(pGC)\
+    pGCPriv->wrappedFuncs = (pGC)->funcs;\
+    (pGC)->funcs = &vncHooksGCFuncs;\
+    if(pGCPriv->wrappedOps) {\
+        pGCPriv->wrappedOps = (pGC)->ops;\
+        (pGC)->ops = &vncHooksGCOps;\
+    }
+
+// ValidateGC - wrap the "ops" if a viewable window OR the screen pixmap
+
+static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
+                               DrawablePtr pDrawable)
+{
+  GC_FUNC_PROLOGUE(pGC, ValidateGC);
+  (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
+  if ((pDrawable->type == DRAWABLE_WINDOW &&
+       ((WindowPtr) pDrawable)->viewable) ||
+      (pDrawable == &pGC->pScreen->GetScreenPixmap(pGC->pScreen)->drawable)) {
+    pGCPriv->wrappedOps = pGC->ops;
+    DBGPRINT((stderr,"vncHooksValidateGC: wrapped GC ops\n"));
+  } else {
+    pGCPriv->wrappedOps = NULL;
+  }
+  GC_FUNC_EPILOGUE(pGC);
+}
+
+// Other GC funcs - just unwrap and call on
+
+static void vncHooksChangeGC(GCPtr pGC, unsigned long mask) {
+  GC_FUNC_PROLOGUE(pGC, ChangeGC);
+  (*pGC->funcs->ChangeGC) (pGC, mask);
+  GC_FUNC_EPILOGUE(pGC);
+}
+static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst) {
+  GC_FUNC_PROLOGUE(dst, CopyGC);
+  (*dst->funcs->CopyGC) (src, mask, dst);
+  GC_FUNC_EPILOGUE(dst);
+}
+static void vncHooksDestroyGC(GCPtr pGC) {
+  GC_FUNC_PROLOGUE(pGC, DestroyGC);
+  (*pGC->funcs->DestroyGC) (pGC);
+  GC_FUNC_EPILOGUE(pGC);
+}
+static void vncHooksChangeClip(GCPtr pGC, int type, void * pValue, int nrects)
+{
+  GC_FUNC_PROLOGUE(pGC, ChangeClip);
+  (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects);
+  GC_FUNC_EPILOGUE(pGC);
+}
+static void vncHooksDestroyClip(GCPtr pGC) {
+  GC_FUNC_PROLOGUE(pGC, DestroyClip);
+  (*pGC->funcs->DestroyClip) (pGC);
+  GC_FUNC_EPILOGUE(pGC);
+}
+static void vncHooksCopyClip(GCPtr dst, GCPtr src) {
+  GC_FUNC_PROLOGUE(dst, CopyClip);
+  (*dst->funcs->CopyClip) (dst, src);
+  GC_FUNC_EPILOGUE(dst);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// GC "ops"
+//
+
+// Unwrap and rewrap helpers
+
+#define GC_OP_PROLOGUE(pGC, name)\
+    vncHooksGCPtr pGCPriv = vncHooksGCPrivate(pGC);\
+    GCFuncs *oldFuncs = pGC->funcs;\
+    pGC->funcs = pGCPriv->wrappedFuncs;\
+    pGC->ops = pGCPriv->wrappedOps; \
+    DBGPRINT((stderr,"vncHooks" #name " called\n"))
+
+#define GC_OP_EPILOGUE(pGC)\
+    pGCPriv->wrappedOps = pGC->ops;\
+    pGC->funcs = oldFuncs;\
+    pGC->ops   = &vncHooksGCOps
+
+// FillSpans - assume the entire clip region is damaged. This is pessimistic,
+// but I believe this function is rarely used so it doesn't matter.
+
+static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
+                              DDXPointPtr pptInit, int *pwidthInit,
+                              int fSorted)
+{
+  RegionRec reg;
+
+  GC_OP_PROLOGUE(pGC, FillSpans);
+
+  REGION_NULL(pGC->pScreen, &reg);
+  REGION_COPY(pGC->pScreen, &reg, pGC->pCompositeClip);
+
+  if (pDrawable->type == DRAWABLE_WINDOW)
+    REGION_INTERSECT(pScreen, &reg, &reg, &((WindowPtr)pDrawable)->borderClip);
+
+  (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+  GC_OP_EPILOGUE(pGC);
+}
+
+// SetSpans - assume the entire clip region is damaged.  This is pessimistic,
+// but I believe this function is rarely used so it doesn't matter.
+
+static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
+                             DDXPointPtr ppt, int *pwidth, int nspans,
+                             int fSorted)
+{
+  RegionRec reg;
+
+  GC_OP_PROLOGUE(pGC, SetSpans);
+
+  REGION_NULL(pGC->pScreen, &reg);
+  REGION_COPY(pGC->pScreen, &reg, pGC->pCompositeClip);
+
+  if (pDrawable->type == DRAWABLE_WINDOW)
+    REGION_INTERSECT(pScreen, &reg, &reg, &((WindowPtr)pDrawable)->borderClip);
+
+  (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+  GC_OP_EPILOGUE(pGC);
+}
+
+// PutImage - changed region is the given rectangle, clipped by pCompositeClip
+
+static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
+                             int x, int y, int w, int h, int leftPad,
+                             int format, char *pBits)
+{
+  BoxRec box;
+  RegionRec reg;
+
+  GC_OP_PROLOGUE(pGC, PutImage);
+
+  box.x1 = x + pDrawable->x;
+  box.y1 = y + pDrawable->y;
+  box.x2 = box.x1 + w;
+  box.y2 = box.y1 + h;
+
+  REGION_INIT(pGC->pScreen, &reg, &box, 0);
+  REGION_INTERSECT(pGC->pScreen, &reg, &reg, pGC->pCompositeClip);
+
+  (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format,
+                         pBits);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+  GC_OP_EPILOGUE(pGC);
+}
+
+// CopyArea - destination of the copy is the dest rectangle, clipped by
+// pCompositeClip.  Any parts of the destination which cannot be copied from
+// the source (could be all of it) go into the changed region.
+
+static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
+                                  GCPtr pGC, int srcx, int srcy, int w, int h,
+                                  int dstx, int dsty)
+{
+  BoxRec box;
+  RegionRec dst, src, changed;
+
+  RegionPtr ret;
+
+  GC_OP_PROLOGUE(pGC, CopyArea);
+
+  box.x1 = dstx + pDst->x;
+  box.y1 = dsty + pDst->y;
+  box.x2 = box.x1 + w;
+  box.y2 = box.y1 + h;
+
+  REGION_INIT(pGC->pScreen, &dst, &box, 0);
+  REGION_INTERSECT(pGC->pScreen, &dst, &dst, pGC->pCompositeClip);
+
+  // The source of the data has to be something that's on screen.
+  // This means either a window, or the screen pixmap.
+  if ((pSrc->pScreen == pGC->pScreen) &&
+      ((pSrc->type == DRAWABLE_WINDOW) ||
+       (pSrc == &pGC->pScreen->GetScreenPixmap(pGC->pScreen)->drawable))) {
+    box.x1 = srcx + pSrc->x;
+    box.y1 = srcy + pSrc->y;
+    box.x2 = box.x1 + w;
+    box.y2 = box.y1 + h;
+
+    REGION_INIT(pGC->pScreen, &src, &box, 0);
+
+    if ((pSrc->type == DRAWABLE_WINDOW) &&
+        REGION_NOTEMPTY(pScreen, &((WindowPtr)pSrc)->clipList)) {
+      REGION_INTERSECT(pScreen, &src, &src, &((WindowPtr)pSrc)->clipList);
+    }
+
+    REGION_TRANSLATE(pScreen, &src,
+                     dstx + pDst->x - srcx - pSrc->x,
+                     dsty + pDst->y - srcy - pSrc->y);
+  } else {
+    REGION_NULL(pGC->pScreen, &src);
+  }
+
+  REGION_NULL(pGC->pScreen, &changed);
+
+  REGION_SUBTRACT(pScreen, &changed, &dst, &src);
+  REGION_INTERSECT(pScreen, &dst, &dst, &src);
+
+  ret = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
+
+  if (REGION_NOTEMPTY(pScreen, &dst))
+    add_copied(pGC->pScreen, &dst,
+               dstx + pDst->x - srcx - pSrc->x,
+               dsty + pDst->y - srcy - pSrc->y);
+
+  if (REGION_NOTEMPTY(pScreen, &changed))
+    add_changed(pGC->pScreen, &changed);
+
+  REGION_UNINIT(pGC->pScreen, &dst);
+  REGION_UNINIT(pGC->pScreen, &src);
+  REGION_UNINIT(pGC->pScreen, &changed);
+
+  GC_OP_EPILOGUE(pGC);
+
+  return ret;
+}
+
+
+// CopyPlane - changed region is the destination rectangle, clipped by
+// pCompositeClip
+
+static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
+                                   GCPtr pGC, int srcx, int srcy, int w, int h,
+                                   int dstx, int dsty, unsigned long plane)
+{
+  BoxRec box;
+  RegionRec reg;
+
+  RegionPtr ret;
+
+  GC_OP_PROLOGUE(pGC, CopyPlane);
+
+  box.x1 = dstx + pDst->x;
+  box.y1 = dsty + pDst->y;
+  box.x2 = box.x1 + w;
+  box.y2 = box.y1 + h;
+
+  REGION_INIT(pGC->pScreen, &reg, &box, 0);
+  REGION_INTERSECT(pGC->pScreen, &reg, &reg, pGC->pCompositeClip);
+
+  ret = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
+                                dstx, dsty, plane);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+  GC_OP_EPILOGUE(pGC);
+
+  return ret;
+}
+
+// PolyPoint - changed region is the bounding rect, clipped by pCompositeClip
+
+static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
+                              int npt, xPoint *pts)
+{
+  int minX, minY, maxX, maxY;
+  int i;
+
+  BoxRec box;
+  RegionRec reg;
+
+  GC_OP_PROLOGUE(pGC, PolyPoint);
+
+  if (npt == 0) {
+    (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
+    goto out;
+  }
+
+  minX = pts[0].x;
+  maxX = pts[0].x;
+  minY = pts[0].y;
+  maxY = pts[0].y;
+
+  if (mode == CoordModePrevious) {
+    int x = pts[0].x;
+    int y = pts[0].y;
+
+    for (i = 1; i < npt; i++) {
+      x += pts[i].x;
+      y += pts[i].y;
+      if (x < minX) minX = x;
+      if (x > maxX) maxX = x;
+      if (y < minY) minY = y;
+      if (y > maxY) maxY = y;
+    }
+  } else {
+    for (i = 1; i < npt; i++) {
+      if (pts[i].x < minX) minX = pts[i].x;
+      if (pts[i].x > maxX) maxX = pts[i].x;
+      if (pts[i].y < minY) minY = pts[i].y;
+      if (pts[i].y > maxY) maxY = pts[i].y;
+    }
+  }
+
+  box.x1 = minX + pDrawable->x;
+  box.y1 = minY + pDrawable->y;
+  box.x2 = maxX + 1 + pDrawable->x;
+  box.y2 = maxY + 1 + pDrawable->y;
+
+  REGION_INIT(pGC->pScreen, &reg, &box, 0);
+  REGION_INTERSECT(pGC->pScreen, &reg, &reg, pGC->pCompositeClip);
+
+  (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+}
+
+// Polylines - changed region is the union of the bounding rects of each line,
+// clipped by pCompositeClip.  If there are more than MAX_RECTS_PER_OP lines,
+// just use the bounding rect of all the lines.
+
+static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
+                              int npt, DDXPointPtr ppts)
+{
+  int nRegRects;
+  xRectangle regRects[MAX_RECTS_PER_OP];
+
+  int lw;
+
+  RegionPtr reg;
+
+  GC_OP_PROLOGUE(pGC, Polylines);
+
+  if (npt == 0) {
+    (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
+    goto out;
+  }
+
+  nRegRects = npt - 1;
+
+  lw = pGC->lineWidth;
+  if (lw == 0)
+    lw = 1;
+
+  if (npt == 1)
+  {
+    // a single point
+    nRegRects = 1;
+    regRects[0].x = pDrawable->x + ppts[0].x - lw;
+    regRects[0].y = pDrawable->y + ppts[0].y - lw;
+    regRects[0].width = 2*lw;
+    regRects[0].height = 2*lw;
+  }
+  else
+  {
+    /*
+     * mitered joins can project quite a way from
+     * the line end; the 11 degree miter limit limits
+     * this extension to lw / (2 * tan(11/2)), rounded up
+     * and converted to int yields 6 * lw
+     */
+
+    int extra;
+
+    int prevX, prevY, curX, curY;
+    int rectX1, rectY1, rectX2, rectY2;
+    int minX, minY, maxX, maxY;
+
+    int i;
+
+    extra = lw / 2;
+    if (pGC->joinStyle == JoinMiter) {
+      extra = 6 * lw;
+    }
+
+    prevX = ppts[0].x + pDrawable->x;
+    prevY = ppts[0].y + pDrawable->y;
+    minX = maxX = prevX;
+    minY = maxY = prevY;
+
+    for (i = 0; i < nRegRects; i++) {
+      if (mode == CoordModeOrigin) {
+        curX = pDrawable->x + ppts[i+1].x;
+        curY = pDrawable->y + ppts[i+1].y;
+      } else {
+        curX = prevX + ppts[i+1].x;
+        curY = prevY + ppts[i+1].y;
+      }
+
+      if (prevX > curX) {
+        rectX1 = curX - extra;
+        rectX2 = prevX + extra + 1;
+      } else {
+        rectX1 = prevX - extra;
+        rectX2 = curX + extra + 1;
+      }
+
+      if (prevY > curY) {
+        rectY1 = curY - extra;
+        rectY2 = prevY + extra + 1;
+      } else {
+        rectY1 = prevY - extra;
+        rectY2 = curY + extra + 1;
+      }
+
+      if (nRegRects <= MAX_RECTS_PER_OP) {
+        regRects[i].x = rectX1;
+        regRects[i].y = rectY1;
+        regRects[i].width = rectX2 - rectX1;
+        regRects[i].height = rectY2 - rectY1;
+      } else {
+        if (rectX1 < minX) minX = rectX1;
+        if (rectY1 < minY) minY = rectY1;
+        if (rectX2 > maxX) maxX = rectX2;
+        if (rectY2 > maxY) maxY = rectY2;
+      }
+
+      prevX = curX;
+      prevY = curY;
+    }
+
+    if (nRegRects > MAX_RECTS_PER_OP) {
+      regRects[0].x = minX;
+      regRects[0].y = minY;
+      regRects[0].width = maxX - minX;
+      regRects[0].height = maxY - minY;
+      nRegRects = 1;
+    }
+  }
+
+  reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
+  REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip);
+
+  (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
+
+  add_changed(pGC->pScreen, reg);
+
+  REGION_DESTROY(pGC->pScreen, reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+}
+
+// PolySegment - changed region is the union of the bounding rects of each
+// segment, clipped by pCompositeClip.  If there are more than MAX_RECTS_PER_OP
+// segments, just use the bounding rect of all the segments.
+
+static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
+                                xSegment *segs)
+{
+  xRectangle regRects[MAX_RECTS_PER_OP];
+  int nRegRects;
+
+  int lw, extra;
+
+  int rectX1, rectY1, rectX2, rectY2;
+  int minX, minY, maxX, maxY;
+
+  int i;
+
+  RegionPtr reg;
+
+  GC_OP_PROLOGUE(pGC, PolySegment);
+
+  if (nseg == 0) {
+    (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
+    goto out;
+  }
+
+  nRegRects = nseg;
+
+  lw = pGC->lineWidth;
+  extra = lw / 2;
+
+  minX = maxX = segs[0].x1;
+  minY = maxY = segs[0].y1;
+
+  for (i = 0; i < nseg; i++) {
+    if (segs[i].x1 > segs[i].x2) {
+      rectX1 = pDrawable->x + segs[i].x2 - extra;
+      rectX2 = pDrawable->x + segs[i].x1 + extra + 1;
+    } else {
+      rectX1 = pDrawable->x + segs[i].x1 - extra;
+      rectX2 = pDrawable->x + segs[i].x2 + extra + 1;
+    }
+
+    if (segs[i].y1 > segs[i].y2) {
+      rectY1 = pDrawable->y + segs[i].y2 - extra;
+      rectY2 = pDrawable->y + segs[i].y1 + extra + 1;
+    } else {
+      rectY1 = pDrawable->y + segs[i].y1 - extra;
+      rectY2 = pDrawable->y + segs[i].y2 + extra + 1;
+    }
+
+    if (nseg <= MAX_RECTS_PER_OP) {
+      regRects[i].x = rectX1;
+      regRects[i].y = rectY1;
+      regRects[i].width = rectX2 - rectX1;
+      regRects[i].height = rectY2 - rectY1;
+    } else {
+      if (rectX1 < minX) minX = rectX1;
+      if (rectY1 < minY) minY = rectY1;
+      if (rectX2 > maxX) maxX = rectX2;
+      if (rectY2 > maxY) maxY = rectY2;
+    }
+  }
+
+  if (nseg > MAX_RECTS_PER_OP) {
+    regRects[0].x = minX;
+    regRects[0].y = minY;
+    regRects[0].width = maxX - minX;
+    regRects[0].height = maxY - minY;
+    nRegRects = 1;
+  }
+
+  reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
+  REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip);
+
+  (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
+
+  add_changed(pGC->pScreen, reg);
+
+  REGION_DESTROY(pGC->pScreen, reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+}
+
+// PolyRectangle - changed region is the union of the bounding rects around
+// each side of the outline rectangles, clipped by pCompositeClip.  If there
+// are more than MAX_RECTS_PER_OP rectangles, just use the bounding rect of all
+// the rectangles.
+
+static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
+                                  xRectangle *rects)
+{
+  xRectangle regRects[MAX_RECTS_PER_OP*4];
+  int nRegRects;
+
+  int lw, extra;
+
+  int rectX1, rectY1, rectX2, rectY2;
+  int minX, minY, maxX, maxY;
+
+  int i;
+
+  RegionPtr reg;
+
+  GC_OP_PROLOGUE(pGC, PolyRectangle);
+
+  if (nrects == 0) {
+    (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
+    goto out;
+  }
+
+  nRegRects = nrects * 4;
+
+  lw = pGC->lineWidth;
+  extra = lw / 2;
+
+  minX = maxX = rects[0].x;
+  minY = maxY = rects[0].y;
+
+  for (i = 0; i < nrects; i++) {
+    if (nrects <= MAX_RECTS_PER_OP) {
+      regRects[i*4].x = rects[i].x - extra + pDrawable->x;
+      regRects[i*4].y = rects[i].y - extra + pDrawable->y;
+      regRects[i*4].width = rects[i].width + 1 + 2 * extra;
+      regRects[i*4].height = 1 + 2 * extra;
+
+      regRects[i*4+1].x = rects[i].x - extra + pDrawable->x;
+      regRects[i*4+1].y = rects[i].y - extra + pDrawable->y;
+      regRects[i*4+1].width = 1 + 2 * extra;
+      regRects[i*4+1].height = rects[i].height + 1 + 2 * extra;
+
+      regRects[i*4+2].x = rects[i].x + rects[i].width - extra + pDrawable->x;
+      regRects[i*4+2].y = rects[i].y - extra + pDrawable->y;
+      regRects[i*4+2].width = 1 + 2 * extra;
+      regRects[i*4+2].height = rects[i].height + 1 + 2 * extra;
+
+      regRects[i*4+3].x = rects[i].x - extra + pDrawable->x;
+      regRects[i*4+3].y = rects[i].y + rects[i].height - extra + pDrawable->y;
+      regRects[i*4+3].width = rects[i].width + 1 + 2 * extra;
+      regRects[i*4+3].height = 1 + 2 * extra;
+    } else {
+      rectX1 = pDrawable->x + rects[i].x - extra;
+      rectY1 = pDrawable->y + rects[i].y - extra;
+      rectX2 = pDrawable->x + rects[i].x + rects[i].width + extra+1;
+      rectY2 = pDrawable->y + rects[i].y + rects[i].height + extra+1;
+      if (rectX1 < minX) minX = rectX1;
+      if (rectY1 < minY) minY = rectY1;
+      if (rectX2 > maxX) maxX = rectX2;
+      if (rectY2 > maxY) maxY = rectY2;
+    }
+  }
+
+  if (nrects > MAX_RECTS_PER_OP) {
+    regRects[0].x = minX;
+    regRects[0].y = minY;
+    regRects[0].width = maxX - minX;
+    regRects[0].height = maxY - minY;
+    nRegRects = 1;
+  }
+
+  reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
+  REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip);
+
+  (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
+
+  add_changed(pGC->pScreen, reg);
+
+  REGION_DESTROY(pGC->pScreen, reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+}
+
+// PolyArc - changed region is the union of bounding rects around each arc,
+// clipped by pCompositeClip.  If there are more than MAX_RECTS_PER_OP
+// arcs, just use the bounding rect of all the arcs.
+
+static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
+                            xArc *arcs)
+{
+  xRectangle regRects[MAX_RECTS_PER_OP];
+  int nRegRects;
+
+  int lw, extra;
+
+  int rectX1, rectY1, rectX2, rectY2;
+  int minX, minY, maxX, maxY;
+
+  int i;
+
+  RegionPtr reg;
+
+  GC_OP_PROLOGUE(pGC, PolyArc);
+
+  if (narcs == 0) {
+    (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
+    goto out;
+  }
+
+  nRegRects = narcs;
+
+  lw = pGC->lineWidth;
+  if (lw == 0)
+    lw = 1;
+  extra = lw / 2;
+
+  minX = maxX = arcs[0].x;
+  minY = maxY = arcs[0].y;
+
+  for (i = 0; i < narcs; i++) {
+    if (narcs <= MAX_RECTS_PER_OP) {
+      regRects[i].x = arcs[i].x - extra + pDrawable->x;
+      regRects[i].y = arcs[i].y - extra + pDrawable->y;
+      regRects[i].width = arcs[i].width + lw;
+      regRects[i].height = arcs[i].height + lw;
+    } else {
+      rectX1 = pDrawable->x + arcs[i].x - extra;
+      rectY1 = pDrawable->y + arcs[i].y - extra;
+      rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
+      rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
+      if (rectX1 < minX) minX = rectX1;
+      if (rectY1 < minY) minY = rectY1;
+      if (rectX2 > maxX) maxX = rectX2;
+      if (rectY2 > maxY) maxY = rectY2;
+    }
+  }
+
+  if (narcs > MAX_RECTS_PER_OP) {
+    regRects[0].x = minX;
+    regRects[0].y = minY;
+    regRects[0].width = maxX - minX;
+    regRects[0].height = maxY - minY;
+    nRegRects = 1;
+  }
+
+  reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
+  REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip);
+
+  (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
+
+  add_changed(pGC->pScreen, reg);
+
+  REGION_DESTROY(pGC->pScreen, reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+}
+
+
+// FillPolygon - changed region is the bounding rect around the polygon,
+// clipped by pCompositeClip
+
+static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
+                                int mode, int count, DDXPointPtr pts)
+{
+  int minX, minY, maxX, maxY;
+  int i;
+
+  BoxRec box;
+  RegionRec reg;
+
+  GC_OP_PROLOGUE(pGC, FillPolygon);
+
+  if (count == 0) {
+    (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
+    goto out;
+  }
+
+  minX = pts[0].x;
+  maxX = pts[0].x;
+  minY = pts[0].y;
+  maxY = pts[0].y;
+
+  if (mode == CoordModePrevious) {
+    int x = pts[0].x;
+    int y = pts[0].y;
+
+    for (i = 1; i < count; i++) {
+      x += pts[i].x;
+      y += pts[i].y;
+      if (x < minX) minX = x;
+      if (x > maxX) maxX = x;
+      if (y < minY) minY = y;
+      if (y > maxY) maxY = y;
+    }
+  } else {
+    for (i = 1; i < count; i++) {
+      if (pts[i].x < minX) minX = pts[i].x;
+      if (pts[i].x > maxX) maxX = pts[i].x;
+      if (pts[i].y < minY) minY = pts[i].y;
+      if (pts[i].y > maxY) maxY = pts[i].y;
+    }
+  }
+
+  box.x1 = minX + pDrawable->x;
+  box.y1 = minY + pDrawable->y;
+  box.x2 = maxX + 1 + pDrawable->x;
+  box.y2 = maxY + 1 + pDrawable->y;
+
+  REGION_INIT(pGC->pScreen, &reg, &box, 0);
+  REGION_INTERSECT(pGC->pScreen, &reg, &reg, pGC->pCompositeClip);
+
+  (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+}
+
+// PolyFillRect - changed region is the union of the rectangles, clipped by
+// pCompositeClip.  If there are more than MAX_RECTS_PER_OP rectangles, just
+// use the bounding rect of all the rectangles.
+
+static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
+                                 xRectangle *rects)
+{
+  xRectangle regRects[MAX_RECTS_PER_OP];
+  int nRegRects;
+  int rectX1, rectY1, rectX2, rectY2;
+  int minX, minY, maxX, maxY;
+  int i;
+
+  RegionPtr reg;
+
+  GC_OP_PROLOGUE(pGC, PolyFillRect);
+
+  if (nrects == 0) {
+    (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
+    goto out;
+  }
+
+  nRegRects = nrects;
+  minX = maxX = rects[0].x;
+  minY = maxY = rects[0].y;
+
+  for (i = 0; i < nrects; i++) {
+    if (nrects <= MAX_RECTS_PER_OP) {
+      regRects[i].x = rects[i].x + pDrawable->x;
+      regRects[i].y = rects[i].y + pDrawable->y;
+      regRects[i].width = rects[i].width;
+      regRects[i].height = rects[i].height;
+    } else {
+      rectX1 = pDrawable->x + rects[i].x;
+      rectY1 = pDrawable->y + rects[i].y;
+      rectX2 = pDrawable->x + rects[i].x + rects[i].width;
+      rectY2 = pDrawable->y + rects[i].y + rects[i].height;
+      if (rectX1 < minX) minX = rectX1;
+      if (rectY1 < minY) minY = rectY1;
+      if (rectX2 > maxX) maxX = rectX2;
+      if (rectY2 > maxY) maxY = rectY2;
+    }
+  }
+
+  if (nrects > MAX_RECTS_PER_OP) {
+    regRects[0].x = minX;
+    regRects[0].y = minY;
+    regRects[0].width = maxX - minX;
+    regRects[0].height = maxY - minY;
+    nRegRects = 1;
+  }
+
+  reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
+  REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip);
+
+  (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
+
+  add_changed(pGC->pScreen, reg);
+
+  REGION_DESTROY(pGC->pScreen, reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+}
+
+// PolyFillArc - changed region is the union of bounding rects around each arc,
+// clipped by pCompositeClip.  If there are more than MAX_RECTS_PER_OP arcs,
+// just use the bounding rect of all the arcs.
+
+static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
+                                xArc *arcs)
+{
+  xRectangle regRects[MAX_RECTS_PER_OP];
+  int nRegRects;
+
+  int lw, extra;
+
+  int rectX1, rectY1, rectX2, rectY2;
+  int minX, minY, maxX, maxY;
+
+  int i;
+
+  RegionPtr reg;
+
+  GC_OP_PROLOGUE(pGC, PolyFillArc);
+
+  if (narcs == 0) {
+    (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
+    goto out;
+  }
+
+  nRegRects = narcs;
+
+  lw = pGC->lineWidth;
+  if (lw == 0)
+    lw = 1;
+  extra = lw / 2;
+
+  minX = maxX = arcs[0].x;
+  minY = maxY = arcs[0].y;
+
+  for (i = 0; i < narcs; i++) {
+    if (narcs <= MAX_RECTS_PER_OP) {
+      regRects[i].x = arcs[i].x - extra + pDrawable->x;
+      regRects[i].y = arcs[i].y - extra + pDrawable->y;
+      regRects[i].width = arcs[i].width + lw;
+      regRects[i].height = arcs[i].height + lw;
+    } else {
+      rectX1 = pDrawable->x + arcs[i].x - extra;
+      rectY1 = pDrawable->y + arcs[i].y - extra;
+      rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
+      rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
+      if (rectX1 < minX) minX = rectX1;
+      if (rectY1 < minY) minY = rectY1;
+      if (rectX2 > maxX) maxX = rectX2;
+      if (rectY2 > maxY) maxY = rectY2;
+    }
+  }
+
+  if (narcs > MAX_RECTS_PER_OP) {
+    regRects[0].x = minX;
+    regRects[0].y = minY;
+    regRects[0].width = maxX - minX;
+    regRects[0].height = maxY - minY;
+    nRegRects = 1;
+  }
+
+  reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
+  REGION_INTERSECT(pGC->pScreen, reg, reg, pGC->pCompositeClip);
+
+  (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
+
+  add_changed(pGC->pScreen, reg);
+
+  REGION_DESTROY(pGC->pScreen, reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+}
+
+// GetTextBoundingRect - calculate a bounding rectangle around n chars of a
+// font.  Not particularly accurate, but good enough.
+
+static void GetTextBoundingRect(DrawablePtr pDrawable, FontPtr font, int x,
+                                int y, int nchars, BoxPtr box)
+{
+  int ascent = max(FONTASCENT(font), FONTMAXBOUNDS(font, ascent));
+  int descent = max(FONTDESCENT(font), FONTMAXBOUNDS(font, descent));
+  int charWidth = max(FONTMAXBOUNDS(font,rightSideBearing),
+                      FONTMAXBOUNDS(font,characterWidth));
+
+  box->x1 = pDrawable->x + x;
+  box->y1 = pDrawable->y + y - ascent;
+  box->x2 = box->x1 + charWidth * nchars;
+  box->y2 = box->y1 + ascent + descent;
+
+  if (FONTMINBOUNDS(font,leftSideBearing) < 0)
+    box->x1 += FONTMINBOUNDS(font,leftSideBearing);
+}
+
+// PolyText8 - changed region is bounding rect around count chars, clipped by
+// pCompositeClip
+
+static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
+                             int count, char *chars)
+{
+  int ret;
+  BoxRec box;
+  RegionRec reg;
+
+  GC_OP_PROLOGUE(pGC, PolyText8);
+
+  if (count == 0) {
+    ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
+    goto out;
+  }
+
+  GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
+
+  REGION_INIT(pGC->pScreen, &reg, &box, 0);
+  REGION_INTERSECT(pGC->pScreen, &reg, &reg, pGC->pCompositeClip);
+
+  ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+
+  return ret;
+}
+
+// PolyText16 - changed region is bounding rect around count chars, clipped by
+// pCompositeClip
+
+static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
+                              int count, unsigned short *chars)
+{
+  int ret;
+  BoxRec box;
+  RegionRec reg;
+
+  GC_OP_PROLOGUE(pGC, PolyText16);
+
+  if (count == 0) {
+    ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
+    goto out;
+  }
+
+  GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
+
+  REGION_INIT(pGC->pScreen, &reg, &box, 0);
+  REGION_INTERSECT(pGC->pScreen, &reg, &reg, pGC->pCompositeClip);
+
+  ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+
+  return ret;
+}
+
+// ImageText8 - changed region is bounding rect around count chars, clipped by
+// pCompositeClip
+
+static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
+                               int count, char *chars)
+{
+  BoxRec box;
+  RegionRec reg;
+
+  GC_OP_PROLOGUE(pGC, ImageText8);
+
+  if (count == 0) {
+    (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
+    goto out;
+  }
+
+  GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
+
+  REGION_INIT(pGC->pScreen, &reg, &box, 0);
+  REGION_INTERSECT(pGC->pScreen, &reg, &reg, pGC->pCompositeClip);
+
+  (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+}
+
+// ImageText16 - changed region is bounding rect around count chars, clipped by
+// pCompositeClip
+
+static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
+                                int count, unsigned short *chars)
+{
+  BoxRec box;
+  RegionRec reg;
+
+  GC_OP_PROLOGUE(pGC, ImageText16);
+
+  if (count == 0) {
+    (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
+    goto out;
+  }
+
+  GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
+
+  REGION_INIT(pGC->pScreen, &reg, &box, 0);
+  REGION_INTERSECT(pGC->pScreen, &reg, &reg, pGC->pCompositeClip);
+
+  (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+}
+
+// ImageGlyphBlt - changed region is bounding rect around nglyph chars, clipped
+// by pCompositeClip
+
+static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
+                                  int y, unsigned int nglyph,
+                                  CharInfoPtr *ppci, void * pglyphBase)
+{
+  BoxRec box;
+  RegionRec reg;
+
+  GC_OP_PROLOGUE(pGC, ImageGlyphBlt);
+
+  if (nglyph == 0) {
+    (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
+    goto out;
+  }
+
+  GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
+
+  REGION_INIT(pGC->pScreen, &reg, &box, 0);
+  REGION_INTERSECT(pGC->pScreen, &reg, &reg, pGC->pCompositeClip);
+
+  (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+}
+
+// PolyGlyphBlt - changed region is bounding rect around nglyph chars, clipped
+// by pCompositeClip
+
+static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
+                                 int y, unsigned int nglyph,
+                                 CharInfoPtr *ppci, void * pglyphBase)
+{
+  BoxRec box;
+  RegionRec reg;
+
+  GC_OP_PROLOGUE(pGC, PolyGlyphBlt);
+
+  if (nglyph == 0) {
+    (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
+    goto out;
+  }
+
+  GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
+
+  REGION_INIT(pGC->pScreen, &reg, &box, 0);
+  REGION_INTERSECT(pGC->pScreen, &reg, &reg, pGC->pCompositeClip);
+
+  (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+out:
+  GC_OP_EPILOGUE(pGC);
+}
+
+// PushPixels - changed region is the given rectangle, clipped by
+// pCompositeClip
+
+static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
+                               DrawablePtr pDrawable, int w, int h, int x,
+                               int y)
+{
+  BoxRec box;
+  RegionRec reg;
+
+  GC_OP_PROLOGUE(pGC, PushPixels);
+
+  box.x1 = x + pDrawable->x;
+  box.y1 = y + pDrawable->y;
+  box.x2 = box.x1 + w;
+  box.y2 = box.y1 + h;
+
+  REGION_INIT(pGC->pScreen, &reg, &box, 0);
+  REGION_INTERSECT(pGC->pScreen, &reg, &reg, pGC->pCompositeClip);
+
+  (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
+
+  add_changed(pGC->pScreen, &reg);
+
+  REGION_UNINIT(pGC->pScreen, &reg);
+
+  GC_OP_EPILOGUE(pGC);
+}
diff --git a/unix/xserver/hw/vnc/vncHooks.cc b/unix/xserver/hw/vnc/vncHooks.cc
deleted file mode 100644 (file)
index f75a2d4..0000000
+++ /dev/null
@@ -1,1836 +0,0 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * Copyright 2009 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 <stdio.h>
-#include "XserverDesktop.h"
-#include "vncHooks.h"
-#include "vncExtInit.h"
-#include "xorg-version.h"
-
-extern "C" {
-#define class c_class
-#define private c_private
-#define public c_public
-#include "scrnintstr.h"
-#include "windowstr.h"
-#include "gcstruct.h"
-#include "regionstr.h"
-#include "dixfontstr.h"
-#include "colormapst.h"
-#ifdef RENDER
-#include "picturestr.h"
-#endif
-#ifdef RANDR
-#include "randrstr.h"
-#endif
-
-#undef class
-#undef private
-#undef public
-}
-
-#include "RegionHelper.h"
-
-#define DBGPRINT(x) //(fprintf x)
-
-// MAX_RECTS_PER_OP is the maximum number of rectangles we generate from
-// operations like Polylines and PolySegment.  If the operation is more complex
-// than this, we simply use the bounding box.  Ideally it would be a
-// command-line option, but that would involve an extra malloc each time, so we
-// fix it here.
-#define MAX_RECTS_PER_OP 5
-
-// vncHooksScreenRec and vncHooksGCRec contain pointers to the original
-// functions which we "wrap" in order to hook the screen changes.  The screen
-// functions are each wrapped individually, while the GC "funcs" and "ops" are
-// wrapped as a unit.
-
-typedef struct {
-  XserverDesktop* desktop;
-
-  CloseScreenProcPtr           CloseScreen;
-  CreateGCProcPtr              CreateGC;
-  CopyWindowProcPtr            CopyWindow;
-  ClearToBackgroundProcPtr     ClearToBackground;
-#if XORG < 110
-  RestoreAreasProcPtr          RestoreAreas;
-#endif
-  DisplayCursorProcPtr         DisplayCursor;
-  ScreenBlockHandlerProcPtr    BlockHandler;
-#ifdef RENDER
-  CompositeProcPtr             Composite;
-  GlyphsProcPtr                Glyphs;
-#endif
-#ifdef RANDR
-  RRSetConfigProcPtr           RandRSetConfig;
-  RRScreenSetSizeProcPtr       RandRScreenSetSize;
-  RRCrtcSetProcPtr             RandRCrtcSet;
-#endif
-} vncHooksScreenRec, *vncHooksScreenPtr;
-
-typedef struct {
-#if XORG >= 116
-    const GCFuncs *wrappedFuncs;
-    const GCOps *wrappedOps;
-#else
-    GCFuncs *wrappedFuncs;
-    GCOps *wrappedOps;
-#endif
-} vncHooksGCRec, *vncHooksGCPtr;
-
-#if XORG == 15
-static DevPrivateKey vncHooksScreenPrivateKey = &vncHooksScreenPrivateKey;
-static DevPrivateKey vncHooksGCPrivateKey = &vncHooksGCPrivateKey;
-#elif XORG < 19
-static int vncHooksScreenPrivateKeyIndex;
-static int vncHooksGCPrivateKeyIndex;
-static DevPrivateKey vncHooksScreenPrivateKey = &vncHooksScreenPrivateKeyIndex;
-static DevPrivateKey vncHooksGCPrivateKey = &vncHooksGCPrivateKeyIndex;
-#else
-static DevPrivateKeyRec vncHooksScreenKeyRec;
-static DevPrivateKeyRec vncHooksGCKeyRec;
-#define vncHooksScreenPrivateKey (&vncHooksScreenKeyRec)
-#define vncHooksGCPrivateKey (&vncHooksGCKeyRec)
-#endif
-
-#define vncHooksScreenPrivate(pScreen) \
-        (vncHooksScreenPtr) dixLookupPrivate(&(pScreen)->devPrivates, \
-                                             vncHooksScreenPrivateKey)
-#define vncHooksGCPrivate(pGC) \
-        (vncHooksGCPtr) dixLookupPrivate(&(pGC)->devPrivates, \
-                                         vncHooksGCPrivateKey)
-
-// screen functions
-
-#if XORG <= 112
-static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen);
-#else
-static Bool vncHooksCloseScreen(ScreenPtr pScreen);
-#endif
-static Bool vncHooksCreateGC(GCPtr pGC);
-static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
-                               RegionPtr pOldRegion);
-static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
-                                      int h, Bool generateExposures);
-#if XORG < 110
-static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed);
-#endif
-static Bool vncHooksDisplayCursor(
-#if XORG >= 16
-                                 DeviceIntPtr pDev,
-#endif
-                                 ScreenPtr pScreen, CursorPtr cursor);
-#if XORG <= 112
-static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
-                                 pointer pReadmask);
-#else
-static void vncHooksBlockHandler(ScreenPtr pScreen, void * pTimeout,
-                                 void * pReadmask);
-#endif
-#ifdef RENDER
-static void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, 
-                             PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, 
-                             INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
-static void vncHooksGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 
-                             PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists, 
-                             GlyphListPtr lists, GlyphPtr * glyphs);
-#endif
-#ifdef RANDR
-static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
-                                   int rate, RRScreenSizePtr pSize);
-static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
-                                       CARD16 width, CARD16 height,
-                                       CARD32 mmWidth, CARD32 mmHeight);
-static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
-                                 RRModePtr mode, int x, int y,
-                                 Rotation rotation, int numOutputs,
-                                 RROutputPtr *outputs);
-#endif
-
-// GC "funcs"
-
-static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
-                               DrawablePtr pDrawable);
-static void vncHooksChangeGC(GCPtr pGC, unsigned long mask);
-static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst);
-static void vncHooksDestroyGC(GCPtr pGC);
-static void vncHooksChangeClip(GCPtr pGC, int type, void * pValue,int nrects);
-static void vncHooksDestroyClip(GCPtr pGC);
-static void vncHooksCopyClip(GCPtr dst, GCPtr src);
-
-static GCFuncs vncHooksGCFuncs = {
-  vncHooksValidateGC, vncHooksChangeGC, vncHooksCopyGC, vncHooksDestroyGC,
-  vncHooksChangeClip, vncHooksDestroyClip, vncHooksCopyClip,
-};
-
-// GC "ops"
-
-static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
-                              DDXPointPtr pptInit, int *pwidthInit,
-                              int fSorted);
-static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
-                             DDXPointPtr ppt, int *pwidth, int nspans,
-                             int fSorted);
-static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
-                             int x, int y, int w, int h, int leftPad,
-                             int format, char *pBits);
-static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
-                                  GCPtr pGC, int srcx, int srcy, int w, int h,
-                                  int dstx, int dsty);
-static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
-                                   GCPtr pGC, int srcx, int srcy, int w, int h,
-                                   int dstx, int dsty, unsigned long plane);
-static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
-                              int npt, xPoint *pts);
-static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
-                              int npt, DDXPointPtr ppts);
-static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
-                                xSegment *segs);
-static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
-                                  xRectangle *rects);
-static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
-                            xArc *arcs);
-static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
-                                int mode, int count, DDXPointPtr pts);
-static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
-                                 xRectangle *rects);
-static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
-                                xArc *arcs);
-static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
-                             int count, char *chars);
-static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
-                              int count, unsigned short *chars);
-static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
-                               int count, char *chars);
-static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
-                                int count, unsigned short *chars);
-static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
-                                  int y, unsigned int nglyph,
-                                  CharInfoPtr *ppci, void * pglyphBase);
-static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
-                                 int y, unsigned int nglyph,
-                                 CharInfoPtr *ppci, void * pglyphBase);
-static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
-                               DrawablePtr pDrawable, int w, int h, int x,
-                               int y);
-
-static GCOps vncHooksGCOps = {
-  vncHooksFillSpans, vncHooksSetSpans, vncHooksPutImage, vncHooksCopyArea,
-  vncHooksCopyPlane, vncHooksPolyPoint, vncHooksPolylines, vncHooksPolySegment,
-  vncHooksPolyRectangle, vncHooksPolyArc, vncHooksFillPolygon,
-  vncHooksPolyFillRect, vncHooksPolyFillArc, vncHooksPolyText8,
-  vncHooksPolyText16, vncHooksImageText8, vncHooksImageText16,
-  vncHooksImageGlyphBlt, vncHooksPolyGlyphBlt, vncHooksPushPixels
-};
-
-
-
-/////////////////////////////////////////////////////////////////////////////
-// vncHooksInit() is called at initialisation time and every time the server
-// resets.  It is called once for each screen, but the indexes are only
-// allocated once for each server generation.
-
-Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop)
-{
-  vncHooksScreenPtr vncHooksScreen;
-
-#if XORG < 19
-  if (!dixRequestPrivate(vncHooksScreenPrivateKey, sizeof(vncHooksScreenRec))) {
-    ErrorF("vncHooksInit: Allocation of vncHooksScreen failed\n");
-    return FALSE;
-  }
-  if (!dixRequestPrivate(vncHooksGCPrivateKey, sizeof(vncHooksGCRec))) {
-    ErrorF("vncHooksInit: Allocation of vncHooksGCRec failed\n");
-    return FALSE;
-  }
-
-#else
-  if (!dixRegisterPrivateKey(&vncHooksScreenKeyRec, PRIVATE_SCREEN,
-      sizeof(vncHooksScreenRec))) {
-    ErrorF("vncHooksInit: Allocation of vncHooksScreen failed\n");
-    return FALSE;
-  }
-  if (!dixRegisterPrivateKey(&vncHooksGCKeyRec, PRIVATE_GC,
-      sizeof(vncHooksGCRec))) {
-    ErrorF("vncHooksInit: Allocation of vncHooksGCRec failed\n");
-    return FALSE;
-  }
-
-#endif
-
-  vncHooksScreen = vncHooksScreenPrivate(pScreen);
-
-  vncHooksScreen->desktop = desktop;
-
-  vncHooksScreen->CloseScreen = pScreen->CloseScreen;
-  vncHooksScreen->CreateGC = pScreen->CreateGC;
-  vncHooksScreen->CopyWindow = pScreen->CopyWindow;
-  vncHooksScreen->ClearToBackground = pScreen->ClearToBackground;
-#if XORG < 110
-  vncHooksScreen->RestoreAreas = pScreen->RestoreAreas;
-#endif
-  vncHooksScreen->DisplayCursor = pScreen->DisplayCursor;
-  vncHooksScreen->BlockHandler = pScreen->BlockHandler;
-#ifdef RENDER
-  PictureScreenPtr ps;
-  ps = GetPictureScreenIfSet(pScreen);
-  if (ps) {
-    vncHooksScreen->Composite = ps->Composite;
-    vncHooksScreen->Glyphs = ps->Glyphs;
-  }
-#endif
-#ifdef RANDR
-  rrScrPrivPtr rp;
-  rp = rrGetScrPriv(pScreen);
-  if (rp) {
-    vncHooksScreen->RandRSetConfig = rp->rrSetConfig;
-    vncHooksScreen->RandRScreenSetSize = rp->rrScreenSetSize;
-    vncHooksScreen->RandRCrtcSet = rp->rrCrtcSet;
-  }
-#endif
-
-  pScreen->CloseScreen = vncHooksCloseScreen;
-  pScreen->CreateGC = vncHooksCreateGC;
-  pScreen->CopyWindow = vncHooksCopyWindow;
-  pScreen->ClearToBackground = vncHooksClearToBackground;
-#if XORG < 110
-  pScreen->RestoreAreas = vncHooksRestoreAreas;
-#endif
-  pScreen->DisplayCursor = vncHooksDisplayCursor;
-  pScreen->BlockHandler = vncHooksBlockHandler;
-#ifdef RENDER
-  if (ps) {
-    ps->Composite = vncHooksComposite;
-    ps->Glyphs = vncHooksGlyphs;
-  }
-#endif
-#ifdef RANDR
-  if (rp) {
-    /* Some RandR callbacks are optional */
-    if (rp->rrSetConfig)
-      rp->rrSetConfig = vncHooksRandRSetConfig;
-    if (rp->rrScreenSetSize)
-      rp->rrScreenSetSize = vncHooksRandRScreenSetSize;
-    if (rp->rrCrtcSet)
-      rp->rrCrtcSet = vncHooksRandRCrtcSet;
-  }
-#endif
-
-  return TRUE;
-}
-
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// screen functions
-//
-
-// SCREEN_UNWRAP and SCREEN_REWRAP unwrap and rewrap the given screen function.
-// It would be nice to do this with a C++ class, but each function is of a
-// distinct type, so it would have to use templates, and it's not worth that
-// much pain.
-
-#define SCREEN_UNWRAP(scrn,field)                                         \
-  ScreenPtr pScreen = scrn;                                               \
-  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);      \
-  pScreen->field = vncHooksScreen->field;                                 \
-  DBGPRINT((stderr,"vncHooks" #field " called\n"));
-
-#define SCREEN_REWRAP(field) pScreen->field = vncHooks##field;
-
-
-// CloseScreen - unwrap the screen functions and call the original CloseScreen
-// function
-
-#if XORG <= 112
-static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen_)
-#else
-static Bool vncHooksCloseScreen(ScreenPtr pScreen_)
-#endif
-{
-  SCREEN_UNWRAP(pScreen_, CloseScreen);
-
-  pScreen->CreateGC = vncHooksScreen->CreateGC;
-  pScreen->CopyWindow = vncHooksScreen->CopyWindow;
-  pScreen->ClearToBackground = vncHooksScreen->ClearToBackground;
-#if XORG < 110
-  pScreen->RestoreAreas = vncHooksScreen->RestoreAreas;
-#endif
-  pScreen->DisplayCursor = vncHooksScreen->DisplayCursor;
-  pScreen->BlockHandler = vncHooksScreen->BlockHandler;
-#ifdef RENDER
-  PictureScreenPtr ps;
-  ps = GetPictureScreenIfSet(pScreen);
-  if (ps) {
-    ps->Composite = vncHooksScreen->Composite;
-    ps->Glyphs = vncHooksScreen->Glyphs;
-  }
-#endif
-#ifdef RANDR
-  rrScrPrivPtr rp;
-  rp = rrGetScrPriv(pScreen);
-  if (rp) {
-    rp->rrSetConfig = vncHooksScreen->RandRSetConfig;
-    rp->rrScreenSetSize = vncHooksScreen->RandRScreenSetSize;
-    rp->rrCrtcSet = vncHooksScreen->RandRCrtcSet;
-  }
-#endif
-
-  DBGPRINT((stderr,"vncHooksCloseScreen: unwrapped screen functions\n"));
-
-#if XORG <= 112
-  return (*pScreen->CloseScreen)(i, pScreen);
-#else
-  return (*pScreen->CloseScreen)(pScreen);
-#endif
-}
-
-// CreateGC - wrap the "GC funcs"
-
-static Bool vncHooksCreateGC(GCPtr pGC)
-{
-  SCREEN_UNWRAP(pGC->pScreen, CreateGC);
-
-  vncHooksGCPtr vncHooksGC = vncHooksGCPrivate(pGC);
-
-  Bool ret = (*pScreen->CreateGC) (pGC);
-
-  vncHooksGC->wrappedOps = 0;
-  vncHooksGC->wrappedFuncs = pGC->funcs;
-  pGC->funcs = &vncHooksGCFuncs;
-
-  SCREEN_REWRAP(CreateGC);
-
-  return ret;
-}
-
-// CopyWindow - destination of the copy is the old region, clipped by
-// borderClip, translated by the delta.  This call only does the copy - it
-// doesn't affect any other bits.
-
-static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
-                               RegionPtr pOldRegion)
-{
-  SCREEN_UNWRAP(pWin->drawable.pScreen, CopyWindow);
-
-  int dx, dy;
-  RegionHelper copied(pScreen, pOldRegion);
-
-  BoxRec screen_box = {0, 0, pScreen->width, pScreen->height};
-  RegionHelper screen_rgn(pScreen, &screen_box, 1);
-
-  dx = pWin->drawable.x - ptOldOrg.x;
-  dy = pWin->drawable.y - ptOldOrg.y;
-
-  // RFB tracks copies in terms of destination rectangle, not source.
-  // We also need to copy with changes to the Window's clipping region.
-  // Finally, make sure we don't get copies to or from regions outside
-  // the framebuffer.
-  REGION_INTERSECT(pScreen, copied.reg, copied.reg, screen_rgn.reg);
-  REGION_TRANSLATE(pScreen, copied.reg, dx, dy);
-  REGION_INTERSECT(pScreen, copied.reg, copied.reg, screen_rgn.reg);
-  REGION_INTERSECT(pScreen, copied.reg, copied.reg, &pWin->borderClip);
-
-  (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion);
-
-  if (REGION_NOTEMPTY(pScreen, copied.reg))
-    vncHooksScreen->desktop->add_copied(copied.reg, dx, dy);
-
-  SCREEN_REWRAP(CopyWindow);
-}
-
-// ClearToBackground - changed region is the given rectangle, clipped by
-// clipList, but only if generateExposures is false.
-
-static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
-                                      int h, Bool generateExposures)
-{
-  SCREEN_UNWRAP(pWin->drawable.pScreen, ClearToBackground);
-
-  BoxRec box;
-  box.x1 = x + pWin->drawable.x;
-  box.y1 = y + pWin->drawable.y;
-  box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width);
-  box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height);
-
-  RegionHelper changed(pScreen, &box, 0);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, &pWin->clipList);
-
-  (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
-
-  if (!generateExposures) {
-    vncHooksScreen->desktop->add_changed(changed.reg);
-  }
-
-  SCREEN_REWRAP(ClearToBackground);
-}
-
-#if XORG < 110
-// RestoreAreas - changed region is the given region
-
-static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr pRegion)
-{
-  SCREEN_UNWRAP(pWin->drawable.pScreen, RestoreAreas);
-
-  RegionHelper changed(pScreen, pRegion);
-
-  RegionPtr result = (*pScreen->RestoreAreas) (pWin, pRegion);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-
-  SCREEN_REWRAP(RestoreAreas);
-
-  return result;
-}
-#endif
-
-// DisplayCursor - get the cursor shape
-
-static Bool vncHooksDisplayCursor(
-#if XORG >= 16
-                                 DeviceIntPtr pDev,
-#endif
-                                 ScreenPtr pScreen_, CursorPtr cursor)
-{
-  SCREEN_UNWRAP(pScreen_, DisplayCursor);
-
-  Bool ret = (*pScreen->DisplayCursor) (
-#if XORG >= 16
-                                       pDev,
-#endif
-                                       pScreen, cursor);
-#if XORG >= 16
-  /*
-   * XXX DIX calls this function with NULL argument to remove cursor sprite from
-   * screen. Should we handle this in setCursor as well?
-   */
-  if (cursor != NullCursor) {
-#endif
-    vncHooksScreen->desktop->setCursor(cursor);
-#if XORG >= 16
-  }
-#endif
-
-  SCREEN_REWRAP(DisplayCursor);
-
-  return ret;
-}
-
-// BlockHandler - ignore any changes during the block handler - it's likely
-// these are just drawing the cursor.
-
-#if XORG <= 112
-static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
-                                 pointer pReadmask)
-#else
-static void vncHooksBlockHandler(ScreenPtr pScreen_, void * pTimeout,
-                                 void * pReadmask)
-#endif
-{
-#if XORG <= 112
-  SCREEN_UNWRAP(screenInfo.screens[i], BlockHandler);
-#else
-  SCREEN_UNWRAP(pScreen_, BlockHandler);
-#endif
-
-  vncHooksScreen->desktop->ignoreHooks(true);
-
-#if XORG <= 112
-  (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
-#else
-  (*pScreen->BlockHandler) (pScreen, pTimeout, pReadmask);
-#endif
-
-  vncHooksScreen->desktop->ignoreHooks(false);
-
-  SCREEN_REWRAP(BlockHandler);
-}
-
-#ifdef RENDER
-
-// Composite - The core of XRENDER
-
-void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, 
-                      PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, 
-                      INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
-{
-  ScreenPtr pScreen = pDst->pDrawable->pScreen;
-  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
-  PictureScreenPtr ps = GetPictureScreen(pScreen);
-
-  RegionHelper changed(pScreen);
-
-  if (pDst->pDrawable->type == DRAWABLE_WINDOW &&
-      ((WindowPtr) pDst->pDrawable)->viewable) {
-    BoxRec box;
-    rfb::Rect rect1, rect2;
-
-    rect1.setXYWH(pDst->pDrawable->x + xDst,
-                 pDst->pDrawable->y + yDst,
-                 width,
-                 height);
-        
-    rect2 = rect1.intersect(vncHooksScreen->desktop->getRect());
-
-    box.x1 = rect2.tl.x;
-    box.y1 = rect2.tl.y;
-    box.x2 = rect2.br.x;
-    box.y2 = rect2.br.y;
-
-    changed.init(&box, 0);
-  } else {
-    changed.init(NullBox, 0);
-  }
-
-
-  ps->Composite = vncHooksScreen->Composite;
-  (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
-                  xMask, yMask, xDst, yDst, width, height);
-  ps->Composite = vncHooksComposite;
-
-  if (REGION_NOTEMPTY(pScreen, changed.reg))
-    vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-static int
-GlyphCount(int nlist, GlyphListPtr list, GlyphPtr * glyphs)
-{
-  int count;
-
-  count = 0;
-  while (nlist--) {
-    count += list->len;
-    list++;
-  }
-
-  return count;
-}
-
-static RegionPtr
-GlyphsToRegion(ScreenPtr pScreen, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
-{
-  int n;
-  GlyphPtr glyph;
-  int x, y;
-
-  int nrects = GlyphCount(nlist, list, glyphs);
-  xRectangle rects[nrects];
-  xRectanglePtr rect;
-
-  x = 0;
-  y = 0;
-  rect = &rects[0];
-  while (nlist--) {
-    x += list->xOff;
-    y += list->yOff;
-    n = list->len;
-    list++;
-    while (n--) {
-      glyph = *glyphs++;
-      rect->x = x - glyph->info.x;
-      rect->y = y - glyph->info.y;
-      rect->width = glyph->info.width;
-      rect->height = glyph->info.height;
-      x += glyph->info.xOff;
-      y += glyph->info.yOff;
-      rect++;
-    }
-  }
-
-  return RECTS_TO_REGION(pScreen, nrects, rects, CT_NONE);
-}
-
-// Glyphs - Glyph specific version of Composite (caches and whatnot)
-
-void vncHooksGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, 
-           PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists, 
-           GlyphListPtr lists, GlyphPtr * glyphs)
-{
-  ScreenPtr pScreen = pDst->pDrawable->pScreen;
-  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
-  PictureScreenPtr ps = GetPictureScreen(pScreen);
-
-  RegionHelper changed(pScreen);
-
-  if (pDst->pDrawable->type == DRAWABLE_WINDOW &&
-      ((WindowPtr) pDst->pDrawable)->viewable) {
-    rfb::Rect fbrect;
-    BoxRec fbbox;
-    RegionRec fbreg;
-
-    changed.reg = GlyphsToRegion(pScreen, nlists, lists, glyphs);
-    REGION_TRANSLATE(pScreen, changed.reg,
-                     pDst->pDrawable->x, pDst->pDrawable->y);
-
-    fbrect = vncHooksScreen->desktop->getRect();
-    fbbox.x1 = fbrect.tl.x;
-    fbbox.y1 = fbrect.tl.y;
-    fbbox.x2 = fbrect.br.x;
-    fbbox.y2 = fbrect.br.y;
-    REGION_INIT(pScreen, &fbreg, &fbbox, 0);
-
-    REGION_INTERSECT(pScreen, changed.reg, changed.reg, &fbreg);
-
-    REGION_UNINIT(pScreen, &fbreg);
-  } else {
-    changed.init(NullBox, 0);
-  }
-
-  ps->Glyphs = vncHooksScreen->Glyphs;
-  (*ps->Glyphs)(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlists, lists, glyphs);
-  ps->Glyphs = vncHooksGlyphs;
-
-  if (REGION_NOTEMPTY(pScreen, changed.reg))
-    vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-#endif /* RENDER */
-
-// RandRSetConfig - follow any framebuffer changes
-
-#ifdef RANDR
-
-static void vncPreScreenResize(ScreenPtr pScreen)
-{
-  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
-
-  // We need to prevent the RFB core from accessing the framebuffer
-  // for a while as there might be updates thrown our way inside
-  // the routines that change the screen (i.e. before we have a
-  // pointer to the new framebuffer).
-  vncHooksScreen->desktop->blockUpdates();
-}
-
-static void vncPostScreenResize(ScreenPtr pScreen, Bool success)
-{
-  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
-
-  RegionRec reg;
-  BoxRec box;
-
-  if (success) {
-    // Let the RFB core know of the new dimensions and framebuffer
-    vncHooksScreen->desktop->setFramebuffer(pScreen->width, pScreen->height,
-                                            vncFbptr[pScreen->myNum],
-                                            vncFbstride[pScreen->myNum]);
-  }
-
-  vncHooksScreen->desktop->unblockUpdates();
-
-  if (success) {
-    // Mark entire screen as changed
-    box.x1 = 0;
-    box.y1 = 0;
-    box.x2 = pScreen->width;
-    box.y2 = pScreen->height;
-    REGION_INIT(pScreen, &reg, &box, 1);
-
-    vncHooksScreen->desktop->add_changed(&reg);
-  }
-}
-
-static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
-                                   int rate, RRScreenSizePtr pSize)
-{
-  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
-  rrScrPrivPtr rp = rrGetScrPriv(pScreen);
-  Bool ret;
-
-  vncPreScreenResize(pScreen);
-
-  rp->rrSetConfig = vncHooksScreen->RandRSetConfig;
-  ret = (*rp->rrSetConfig)(pScreen, rotation, rate, pSize);
-  rp->rrSetConfig = vncHooksRandRSetConfig;
-
-  vncPostScreenResize(pScreen, ret);
-
-  if (!ret)
-    return FALSE;
-
-  return TRUE;
-}
-
-static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
-                                       CARD16 width, CARD16 height,
-                                       CARD32 mmWidth, CARD32 mmHeight)
-{
-  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
-  rrScrPrivPtr rp = rrGetScrPriv(pScreen);
-  Bool ret;
-
-  vncPreScreenResize(pScreen);
-
-  rp->rrScreenSetSize = vncHooksScreen->RandRScreenSetSize;
-  ret = (*rp->rrScreenSetSize)(pScreen, width, height, mmWidth, mmHeight);
-  rp->rrScreenSetSize = vncHooksRandRScreenSetSize;
-
-  vncPostScreenResize(pScreen, ret);
-
-  if (!ret)
-    return FALSE;
-
-  return TRUE;
-}
-
-static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
-                                 RRModePtr mode, int x, int y,
-                                 Rotation rotation, int num_outputs,
-                                 RROutputPtr *outputs)
-{
-  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
-  rrScrPrivPtr rp = rrGetScrPriv(pScreen);
-  Bool ret;
-
-  rp->rrCrtcSet = vncHooksScreen->RandRCrtcSet;
-  ret = (*rp->rrCrtcSet)(pScreen, crtc, mode, x, y, rotation,
-                         num_outputs, outputs);
-  rp->rrCrtcSet = vncHooksRandRCrtcSet;
-
-  if (!ret)
-    return FALSE;
-
-  vncHooksScreen->desktop->refreshScreenLayout();
-
-  return TRUE;
-}
-
-#endif /* RANDR */
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// GC "funcs"
-//
-
-// GCFuncUnwrapper is a helper class which unwraps the GC funcs and ops in its
-// constructor and rewraps them in its destructor.
-
-class GCFuncUnwrapper {
-public:
-  GCFuncUnwrapper(GCPtr pGC_) : pGC(pGC_) {
-    vncHooksGC = vncHooksGCPrivate(pGC);
-    pGC->funcs = vncHooksGC->wrappedFuncs;
-    if (vncHooksGC->wrappedOps)
-      pGC->ops = vncHooksGC->wrappedOps;
-  }
-  ~GCFuncUnwrapper() {
-    vncHooksGC->wrappedFuncs = pGC->funcs;
-    pGC->funcs = &vncHooksGCFuncs;
-    if (vncHooksGC->wrappedOps) {
-      vncHooksGC->wrappedOps = pGC->ops;
-      pGC->ops = &vncHooksGCOps;
-    }
-  }
-  GCPtr pGC;
-  vncHooksGCPtr vncHooksGC;
-};
-
-
-// ValidateGC - wrap the "ops" if a viewable window OR the screen pixmap
-
-static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
-                               DrawablePtr pDrawable)
-{
-  GCFuncUnwrapper u(pGC);
-
-  DBGPRINT((stderr,"vncHooksValidateGC called\n"));
-
-  (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
-
-  u.vncHooksGC->wrappedOps = 0;
-  if ((pDrawable->type == DRAWABLE_WINDOW &&
-       ((WindowPtr) pDrawable)->viewable) ||
-      (pDrawable == &pGC->pScreen->GetScreenPixmap(pGC->pScreen)->drawable)) {
-    u.vncHooksGC->wrappedOps = pGC->ops;
-    DBGPRINT((stderr,"vncHooksValidateGC: wrapped GC ops\n"));
-  }    
-}
-
-// Other GC funcs - just unwrap and call on
-
-static void vncHooksChangeGC(GCPtr pGC, unsigned long mask) {
-  GCFuncUnwrapper u(pGC);
-  (*pGC->funcs->ChangeGC) (pGC, mask);
-}
-static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst) {
-  GCFuncUnwrapper u(dst);
-  (*dst->funcs->CopyGC) (src, mask, dst);
-}
-static void vncHooksDestroyGC(GCPtr pGC) {
-  GCFuncUnwrapper u(pGC);
-  (*pGC->funcs->DestroyGC) (pGC);
-}
-static void vncHooksChangeClip(GCPtr pGC, int type, void * pValue, int nrects)
-{
-  GCFuncUnwrapper u(pGC);
-  (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects);
-}
-static void vncHooksDestroyClip(GCPtr pGC) {
-  GCFuncUnwrapper u(pGC);
-  (*pGC->funcs->DestroyClip) (pGC);
-}
-static void vncHooksCopyClip(GCPtr dst, GCPtr src) {
-  GCFuncUnwrapper u(dst);
-  (*dst->funcs->CopyClip) (dst, src);
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// GC "ops"
-//
-
-// GCOpUnwrapper is a helper class which unwraps the GC funcs and ops in its
-// constructor and rewraps them in its destructor.
-
-class GCOpUnwrapper {
-public:
-  GCOpUnwrapper(DrawablePtr pDrawable, GCPtr pGC_)
-    : pGC(pGC_), pScreen(pDrawable->pScreen)
-  {
-    vncHooksGC = vncHooksGCPrivate(pGC);
-    oldFuncs = pGC->funcs;
-    pGC->funcs = vncHooksGC->wrappedFuncs;
-    pGC->ops = vncHooksGC->wrappedOps;
-  }
-  ~GCOpUnwrapper() {
-    vncHooksGC->wrappedOps = pGC->ops;
-    pGC->funcs = oldFuncs;
-    pGC->ops = &vncHooksGCOps;
-  }
-  GCPtr pGC;
-  vncHooksGCPtr vncHooksGC;
-#if XORG >= 116
-  const GCFuncs* oldFuncs;
-#else
-  GCFuncs* oldFuncs;
-#endif
-  ScreenPtr pScreen;
-};
-
-#define GC_OP_UNWRAPPER(pDrawable, pGC, name)                             \
-  GCOpUnwrapper u(pDrawable, pGC);                                        \
-  ScreenPtr pScreen = (pDrawable)->pScreen;                               \
-  vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);      \
-  DBGPRINT((stderr,"vncHooks" #name " called\n"));
-
-
-// FillSpans - assume the entire clip region is damaged. This is pessimistic,
-// but I believe this function is rarely used so it doesn't matter.
-
-static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
-                              DDXPointPtr pptInit, int *pwidthInit,
-                              int fSorted)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, FillSpans);
-
-  RegionHelper changed(pScreen, pGC->pCompositeClip);
-
-  if (pDrawable->type == DRAWABLE_WINDOW)
-    REGION_INTERSECT(pScreen, changed.reg, changed.reg,
-                     &((WindowPtr)pDrawable)->borderClip);
-
-  (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// SetSpans - assume the entire clip region is damaged.  This is pessimistic,
-// but I believe this function is rarely used so it doesn't matter.
-
-static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
-                             DDXPointPtr ppt, int *pwidth, int nspans,
-                             int fSorted)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, SetSpans);
-
-  RegionHelper changed(pScreen, pGC->pCompositeClip);
-
-  if (pDrawable->type == DRAWABLE_WINDOW)
-    REGION_INTERSECT(pScreen, changed.reg, changed.reg,
-                     &((WindowPtr)pDrawable)->borderClip);
-
-  (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// PutImage - changed region is the given rectangle, clipped by pCompositeClip
-
-static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
-                             int x, int y, int w, int h, int leftPad,
-                             int format, char *pBits)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, PutImage);
-
-  BoxRec box;
-  box.x1 = x + pDrawable->x;
-  box.y1 = y + pDrawable->y;
-  box.x2 = box.x1 + w;
-  box.y2 = box.y1 + h;
-
-  RegionHelper changed(pScreen, &box, 0);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format,
-                         pBits);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// CopyArea - destination of the copy is the dest rectangle, clipped by
-// pCompositeClip.  Any parts of the destination which cannot be copied from
-// the source (could be all of it) go into the changed region.
-
-static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
-                                  GCPtr pGC, int srcx, int srcy, int w, int h,
-                                  int dstx, int dsty)
-{
-  GC_OP_UNWRAPPER(pDst, pGC, CopyArea);
-
-  BoxRec box;
-  box.x1 = dstx + pDst->x;
-  box.y1 = dsty + pDst->y;
-  box.x2 = box.x1 + w;
-  box.y2 = box.y1 + h;
-
-  RegionHelper dst(pScreen, &box, 0);
-  REGION_INTERSECT(pScreen, dst.reg, dst.reg, pGC->pCompositeClip);
-
-  RegionHelper src(pScreen);
-
-  // The source of the data has to be something that's on screen.
-  // This means either a window, or the screen pixmap.
-  if ((pSrc->pScreen == pScreen) &&
-      ((pSrc->type == DRAWABLE_WINDOW) ||
-       (pSrc == &pScreen->GetScreenPixmap(pScreen)->drawable))) {
-    box.x1 = srcx + pSrc->x;
-    box.y1 = srcy + pSrc->y;
-    box.x2 = box.x1 + w;
-    box.y2 = box.y1 + h;
-
-    src.init(&box, 0);
-
-    if ((pSrc->type == DRAWABLE_WINDOW) &&
-        REGION_NOTEMPTY(pScreen, &((WindowPtr)pSrc)->clipList)) {
-      REGION_INTERSECT(pScreen, src.reg, src.reg, &((WindowPtr)pSrc)->clipList);
-    }
-
-    REGION_TRANSLATE(pScreen, src.reg,
-                     dstx + pDst->x - srcx - pSrc->x,
-                     dsty + pDst->y - srcy - pSrc->y);
-  } else {
-    src.init(NullBox, 0);
-  }
-
-  RegionHelper changed(pScreen, NullBox, 0);
-  REGION_SUBTRACT(pScreen, changed.reg, dst.reg, src.reg);
-  REGION_INTERSECT(pScreen, dst.reg, dst.reg, src.reg);
-
-  RegionPtr rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h,
-                                         dstx, dsty);
-
-  if (REGION_NOTEMPTY(pScreen, dst.reg))
-    vncHooksScreen->desktop->add_copied(dst.reg,
-                                        dstx + pDst->x - srcx - pSrc->x,
-                                        dsty + pDst->y - srcy - pSrc->y);
-
-  if (REGION_NOTEMPTY(pScreen, changed.reg))
-    vncHooksScreen->desktop->add_changed(changed.reg);
-
-  return rgn;
-}
-
-
-// CopyPlane - changed region is the destination rectangle, clipped by
-// pCompositeClip
-
-static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
-                                   GCPtr pGC, int srcx, int srcy, int w, int h,
-                                   int dstx, int dsty, unsigned long plane)
-{
-  GC_OP_UNWRAPPER(pDst, pGC, CopyPlane);
-
-  BoxRec box;
-  box.x1 = dstx + pDst->x;
-  box.y1 = dsty + pDst->y;
-  box.x2 = box.x1 + w;
-  box.y2 = box.y1 + h;
-
-  RegionHelper changed(pScreen, &box, 0);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  RegionPtr rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
-                                          dstx, dsty, plane);
-  vncHooksScreen->desktop->add_changed(changed.reg);
-
-  return rgn;
-}
-
-// PolyPoint - changed region is the bounding rect, clipped by pCompositeClip
-
-static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
-                              int npt, xPoint *pts)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, PolyPoint);
-
-  if (npt == 0) {
-    (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
-    return;
-  }
-
-  int minX = pts[0].x;
-  int maxX = pts[0].x;
-  int minY = pts[0].y;
-  int maxY = pts[0].y;
-
-  if (mode == CoordModePrevious) {
-    int x = pts[0].x;
-    int y = pts[0].y;
-
-    for (int i = 1; i < npt; i++) {
-      x += pts[i].x;
-      y += pts[i].y;
-      if (x < minX) minX = x;
-      if (x > maxX) maxX = x;
-      if (y < minY) minY = y;
-      if (y > maxY) maxY = y;
-    }
-  } else {
-    for (int i = 1; i < npt; i++) {
-      if (pts[i].x < minX) minX = pts[i].x;
-      if (pts[i].x > maxX) maxX = pts[i].x;
-      if (pts[i].y < minY) minY = pts[i].y;
-      if (pts[i].y > maxY) maxY = pts[i].y;
-    }
-  }
-
-  BoxRec box;
-  box.x1 = minX + pDrawable->x;
-  box.y1 = minY + pDrawable->y;
-  box.x2 = maxX + 1 + pDrawable->x;
-  box.y2 = maxY + 1 + pDrawable->y;
-
-  RegionHelper changed(pScreen, &box, 0);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// Polylines - changed region is the union of the bounding rects of each line,
-// clipped by pCompositeClip.  If there are more than MAX_RECTS_PER_OP lines,
-// just use the bounding rect of all the lines.
-
-static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
-                              int npt, DDXPointPtr ppts)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, Polylines);
-
-  if (npt == 0) {
-    (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
-    return;
-  }
-
-  int nRegRects = npt - 1;
-  xRectangle regRects[MAX_RECTS_PER_OP];
-
-  int lw = pGC->lineWidth;
-  if (lw == 0) lw = 1;
-
-  if (npt == 1)
-  {
-    // a single point
-    nRegRects = 1;
-    regRects[0].x = pDrawable->x + ppts[0].x - lw;
-    regRects[0].y = pDrawable->y + ppts[0].y - lw;
-    regRects[0].width = 2*lw;
-    regRects[0].height = 2*lw;
-  }
-  else
-  {
-    /*
-     * mitered joins can project quite a way from
-     * the line end; the 11 degree miter limit limits
-     * this extension to lw / (2 * tan(11/2)), rounded up
-     * and converted to int yields 6 * lw
-     */
-
-    int extra = lw / 2;
-    if (pGC->joinStyle == JoinMiter) {
-      extra = 6 * lw;
-    }
-
-    int prevX, prevY, curX, curY;
-    int rectX1, rectY1, rectX2, rectY2;
-    int minX, minY, maxX, maxY;
-
-    prevX = ppts[0].x + pDrawable->x;
-    prevY = ppts[0].y + pDrawable->y;
-    minX = maxX = prevX;
-    minY = maxY = prevY;
-
-    for (int i = 0; i < nRegRects; i++) {
-      if (mode == CoordModeOrigin) {
-        curX = pDrawable->x + ppts[i+1].x;
-        curY = pDrawable->y + ppts[i+1].y;
-      } else {
-        curX = prevX + ppts[i+1].x;
-        curY = prevY + ppts[i+1].y;
-      }
-
-      if (prevX > curX) {
-        rectX1 = curX - extra;
-        rectX2 = prevX + extra + 1;
-      } else {
-        rectX1 = prevX - extra;
-        rectX2 = curX + extra + 1;
-      }
-
-      if (prevY > curY) {
-        rectY1 = curY - extra;
-        rectY2 = prevY + extra + 1;
-      } else {
-        rectY1 = prevY - extra;
-        rectY2 = curY + extra + 1;
-      }
-
-      if (nRegRects <= MAX_RECTS_PER_OP) {
-        regRects[i].x = rectX1;
-        regRects[i].y = rectY1;
-        regRects[i].width = rectX2 - rectX1;
-        regRects[i].height = rectY2 - rectY1;
-      } else {
-        if (rectX1 < minX) minX = rectX1;
-        if (rectY1 < minY) minY = rectY1;
-        if (rectX2 > maxX) maxX = rectX2;
-        if (rectY2 > maxY) maxY = rectY2;
-      }
-
-      prevX = curX;
-      prevY = curY;
-    }
-
-    if (nRegRects > MAX_RECTS_PER_OP) {
-      regRects[0].x = minX;
-      regRects[0].y = minY;
-      regRects[0].width = maxX - minX;
-      regRects[0].height = maxY - minY;
-      nRegRects = 1;
-    }
-  }
-
-  RegionHelper changed(pScreen, nRegRects, regRects);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// PolySegment - changed region is the union of the bounding rects of each
-// segment, clipped by pCompositeClip.  If there are more than MAX_RECTS_PER_OP
-// segments, just use the bounding rect of all the segments.
-
-static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
-                                xSegment *segs)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, PolySegment);
-
-  if (nseg == 0) {
-    (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
-    return;
-  }
-
-  xRectangle regRects[MAX_RECTS_PER_OP];
-  int nRegRects = nseg;
-
-  int lw = pGC->lineWidth;
-  int extra = lw / 2;
-
-  int rectX1, rectY1, rectX2, rectY2;
-  int minX, minY, maxX, maxY;
-
-  minX = maxX = segs[0].x1;
-  minY = maxY = segs[0].y1;
-
-  for (int i = 0; i < nseg; i++) {
-    if (segs[i].x1 > segs[i].x2) {
-      rectX1 = pDrawable->x + segs[i].x2 - extra;
-      rectX2 = pDrawable->x + segs[i].x1 + extra + 1;
-    } else {
-      rectX1 = pDrawable->x + segs[i].x1 - extra;
-      rectX2 = pDrawable->x + segs[i].x2 + extra + 1;
-    }
-
-    if (segs[i].y1 > segs[i].y2) {
-      rectY1 = pDrawable->y + segs[i].y2 - extra;
-      rectY2 = pDrawable->y + segs[i].y1 + extra + 1;
-    } else {
-      rectY1 = pDrawable->y + segs[i].y1 - extra;
-      rectY2 = pDrawable->y + segs[i].y2 + extra + 1;
-    }
-
-    if (nseg <= MAX_RECTS_PER_OP) {
-      regRects[i].x = rectX1;
-      regRects[i].y = rectY1;
-      regRects[i].width = rectX2 - rectX1;
-      regRects[i].height = rectY2 - rectY1;
-    } else {
-      if (rectX1 < minX) minX = rectX1;
-      if (rectY1 < minY) minY = rectY1;
-      if (rectX2 > maxX) maxX = rectX2;
-      if (rectY2 > maxY) maxY = rectY2;
-    }
-  }
-
-  if (nseg > MAX_RECTS_PER_OP) {
-    regRects[0].x = minX;
-    regRects[0].y = minY;
-    regRects[0].width = maxX - minX;
-    regRects[0].height = maxY - minY;
-    nRegRects = 1;
-  }
-
-  RegionHelper changed(pScreen, nRegRects, regRects);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// PolyRectangle - changed region is the union of the bounding rects around
-// each side of the outline rectangles, clipped by pCompositeClip.  If there
-// are more than MAX_RECTS_PER_OP rectangles, just use the bounding rect of all
-// the rectangles.
-
-static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
-                                  xRectangle *rects)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, PolyRectangle);
-
-  if (nrects == 0) {
-    (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
-    return;
-  }
-
-  xRectangle regRects[MAX_RECTS_PER_OP*4];
-  int nRegRects = nrects * 4;
-
-  int lw = pGC->lineWidth;
-  int extra = lw / 2;
-
-  int rectX1, rectY1, rectX2, rectY2;
-  int minX, minY, maxX, maxY;
-
-  minX = maxX = rects[0].x;
-  minY = maxY = rects[0].y;
-
-  for (int i = 0; i < nrects; i++) {
-    if (nrects <= MAX_RECTS_PER_OP) {
-      regRects[i*4].x = rects[i].x - extra + pDrawable->x;
-      regRects[i*4].y = rects[i].y - extra + pDrawable->y;
-      regRects[i*4].width = rects[i].width + 1 + 2 * extra;
-      regRects[i*4].height = 1 + 2 * extra;
-
-      regRects[i*4+1].x = rects[i].x - extra + pDrawable->x;
-      regRects[i*4+1].y = rects[i].y - extra + pDrawable->y;
-      regRects[i*4+1].width = 1 + 2 * extra;
-      regRects[i*4+1].height = rects[i].height + 1 + 2 * extra;
-
-      regRects[i*4+2].x = rects[i].x + rects[i].width - extra + pDrawable->x;
-      regRects[i*4+2].y = rects[i].y - extra + pDrawable->y;
-      regRects[i*4+2].width = 1 + 2 * extra;
-      regRects[i*4+2].height = rects[i].height + 1 + 2 * extra;
-
-      regRects[i*4+3].x = rects[i].x - extra + pDrawable->x;
-      regRects[i*4+3].y = rects[i].y + rects[i].height - extra + pDrawable->y;
-      regRects[i*4+3].width = rects[i].width + 1 + 2 * extra;
-      regRects[i*4+3].height = 1 + 2 * extra;
-    } else {
-      rectX1 = pDrawable->x + rects[i].x - extra;
-      rectY1 = pDrawable->y + rects[i].y - extra;
-      rectX2 = pDrawable->x + rects[i].x + rects[i].width + extra+1;
-      rectY2 = pDrawable->y + rects[i].y + rects[i].height + extra+1;
-      if (rectX1 < minX) minX = rectX1;
-      if (rectY1 < minY) minY = rectY1;
-      if (rectX2 > maxX) maxX = rectX2;
-      if (rectY2 > maxY) maxY = rectY2;
-    }
-  }
-
-  if (nrects > MAX_RECTS_PER_OP) {
-    regRects[0].x = minX;
-    regRects[0].y = minY;
-    regRects[0].width = maxX - minX;
-    regRects[0].height = maxY - minY;
-    nRegRects = 1;
-  }
-
-  RegionHelper changed(pScreen, nRegRects, regRects);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// PolyArc - changed region is the union of bounding rects around each arc,
-// clipped by pCompositeClip.  If there are more than MAX_RECTS_PER_OP
-// arcs, just use the bounding rect of all the arcs.
-
-static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
-                            xArc *arcs)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, PolyArc);
-
-  if (narcs == 0) {
-    (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
-    return;
-  }
-
-  xRectangle regRects[MAX_RECTS_PER_OP];
-  int nRegRects = narcs;
-
-  int lw = pGC->lineWidth;
-  if (lw == 0) lw = 1;
-  int extra = lw / 2;
-
-  int rectX1, rectY1, rectX2, rectY2;
-  int minX, minY, maxX, maxY;
-
-  minX = maxX = arcs[0].x;
-  minY = maxY = arcs[0].y;
-
-  for (int i = 0; i < narcs; i++) {
-    if (narcs <= MAX_RECTS_PER_OP) {
-      regRects[i].x = arcs[i].x - extra + pDrawable->x;
-      regRects[i].y = arcs[i].y - extra + pDrawable->y;
-      regRects[i].width = arcs[i].width + lw;
-      regRects[i].height = arcs[i].height + lw;
-    } else {
-      rectX1 = pDrawable->x + arcs[i].x - extra;
-      rectY1 = pDrawable->y + arcs[i].y - extra;
-      rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
-      rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
-      if (rectX1 < minX) minX = rectX1;
-      if (rectY1 < minY) minY = rectY1;
-      if (rectX2 > maxX) maxX = rectX2;
-      if (rectY2 > maxY) maxY = rectY2;
-    }
-  }
-
-  if (narcs > MAX_RECTS_PER_OP) {
-    regRects[0].x = minX;
-    regRects[0].y = minY;
-    regRects[0].width = maxX - minX;
-    regRects[0].height = maxY - minY;
-    nRegRects = 1;
-  }
-
-  RegionHelper changed(pScreen, nRegRects, regRects);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-
-// FillPolygon - changed region is the bounding rect around the polygon,
-// clipped by pCompositeClip
-
-static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
-                                int mode, int count, DDXPointPtr pts)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, FillPolygon);
-
-  if (count == 0) {
-    (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
-    return;
-  }
-
-  int minX = pts[0].x;
-  int maxX = pts[0].x;
-  int minY = pts[0].y;
-  int maxY = pts[0].y;
-
-  if (mode == CoordModePrevious) {
-    int x = pts[0].x;
-    int y = pts[0].y;
-
-    for (int i = 1; i < count; i++) {
-      x += pts[i].x;
-      y += pts[i].y;
-      if (x < minX) minX = x;
-      if (x > maxX) maxX = x;
-      if (y < minY) minY = y;
-      if (y > maxY) maxY = y;
-    }
-  } else {
-    for (int i = 1; i < count; i++) {
-      if (pts[i].x < minX) minX = pts[i].x;
-      if (pts[i].x > maxX) maxX = pts[i].x;
-      if (pts[i].y < minY) minY = pts[i].y;
-      if (pts[i].y > maxY) maxY = pts[i].y;
-    }
-  }
-
-  BoxRec box;
-  box.x1 = minX + pDrawable->x;
-  box.y1 = minY + pDrawable->y;
-  box.x2 = maxX + 1 + pDrawable->x;
-  box.y2 = maxY + 1 + pDrawable->y;
-
-  RegionHelper changed(pScreen, &box, 0);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// PolyFillRect - changed region is the union of the rectangles, clipped by
-// pCompositeClip.  If there are more than MAX_RECTS_PER_OP rectangles, just
-// use the bounding rect of all the rectangles.
-
-static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
-                                 xRectangle *rects)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillRect);
-
-  if (nrects == 0) {
-    (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
-    return;
-  }
-
-  xRectangle regRects[MAX_RECTS_PER_OP];
-  int nRegRects = nrects;
-  int rectX1, rectY1, rectX2, rectY2;
-  int minX, minY, maxX, maxY;
-  minX = maxX = rects[0].x;
-  minY = maxY = rects[0].y;
-
-  for (int i = 0; i < nrects; i++) {
-    if (nrects <= MAX_RECTS_PER_OP) {
-      regRects[i].x = rects[i].x + pDrawable->x;
-      regRects[i].y = rects[i].y + pDrawable->y;
-      regRects[i].width = rects[i].width;
-      regRects[i].height = rects[i].height;
-    } else {
-      rectX1 = pDrawable->x + rects[i].x;
-      rectY1 = pDrawable->y + rects[i].y;
-      rectX2 = pDrawable->x + rects[i].x + rects[i].width;
-      rectY2 = pDrawable->y + rects[i].y + rects[i].height;
-      if (rectX1 < minX) minX = rectX1;
-      if (rectY1 < minY) minY = rectY1;
-      if (rectX2 > maxX) maxX = rectX2;
-      if (rectY2 > maxY) maxY = rectY2;
-    }
-  }
-
-  if (nrects > MAX_RECTS_PER_OP) {
-    regRects[0].x = minX;
-    regRects[0].y = minY;
-    regRects[0].width = maxX - minX;
-    regRects[0].height = maxY - minY;
-    nRegRects = 1;
-  }
-
-  RegionHelper changed(pScreen, nRegRects, regRects);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// PolyFillArc - changed region is the union of bounding rects around each arc,
-// clipped by pCompositeClip.  If there are more than MAX_RECTS_PER_OP arcs,
-// just use the bounding rect of all the arcs.
-
-static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
-                                xArc *arcs)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillArc);
-
-  if (narcs == 0) {
-    (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
-    return;
-  }
-
-  xRectangle regRects[MAX_RECTS_PER_OP];
-  int nRegRects = narcs;
-
-  int lw = pGC->lineWidth;
-  if (lw == 0) lw = 1;
-  int extra = lw / 2;
-
-  int rectX1, rectY1, rectX2, rectY2;
-  int minX, minY, maxX, maxY;
-
-  minX = maxX = arcs[0].x;
-  minY = maxY = arcs[0].y;
-
-  for (int i = 0; i < narcs; i++) {
-    if (narcs <= MAX_RECTS_PER_OP) {
-      regRects[i].x = arcs[i].x - extra + pDrawable->x;
-      regRects[i].y = arcs[i].y - extra + pDrawable->y;
-      regRects[i].width = arcs[i].width + lw;
-      regRects[i].height = arcs[i].height + lw;
-    } else {
-      rectX1 = pDrawable->x + arcs[i].x - extra;
-      rectY1 = pDrawable->y + arcs[i].y - extra;
-      rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
-      rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
-      if (rectX1 < minX) minX = rectX1;
-      if (rectY1 < minY) minY = rectY1;
-      if (rectX2 > maxX) maxX = rectX2;
-      if (rectY2 > maxY) maxY = rectY2;
-    }
-  }
-
-  if (narcs > MAX_RECTS_PER_OP) {
-    regRects[0].x = minX;
-    regRects[0].y = minY;
-    regRects[0].width = maxX - minX;
-    regRects[0].height = maxY - minY;
-    nRegRects = 1;
-  }
-
-  RegionHelper changed(pScreen, nRegRects, regRects);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// GetTextBoundingRect - calculate a bounding rectangle around n chars of a
-// font.  Not particularly accurate, but good enough.
-
-static void GetTextBoundingRect(DrawablePtr pDrawable, FontPtr font, int x,
-                                int y, int nchars, BoxPtr box)
-{
-  int ascent = __rfbmax(FONTASCENT(font), FONTMAXBOUNDS(font, ascent));
-  int descent = __rfbmax(FONTDESCENT(font), FONTMAXBOUNDS(font, descent));
-  int charWidth = __rfbmax(FONTMAXBOUNDS(font,rightSideBearing),
-                           FONTMAXBOUNDS(font,characterWidth));
-
-  box->x1 = pDrawable->x + x;
-  box->y1 = pDrawable->y + y - ascent;
-  box->x2 = box->x1 + charWidth * nchars;
-  box->y2 = box->y1 + ascent + descent;
-
-  if (FONTMINBOUNDS(font,leftSideBearing) < 0)
-    box->x1 += FONTMINBOUNDS(font,leftSideBearing);
-}
-
-// PolyText8 - changed region is bounding rect around count chars, clipped by
-// pCompositeClip
-
-static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
-                             int count, char *chars)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, PolyText8);
-
-  if (count == 0)
-    return (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
-
-  BoxRec box;
-  GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
-
-  RegionHelper changed(pScreen, &box, 0);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  int ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-
-  return ret;
-}
-
-// PolyText16 - changed region is bounding rect around count chars, clipped by
-// pCompositeClip
-
-static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
-                              int count, unsigned short *chars)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, PolyText16);
-
-  if (count == 0)
-    return (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
-
-  BoxRec box;
-  GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
-
-  RegionHelper changed(pScreen, &box, 0);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  int ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-
-  return ret;
-}
-
-// ImageText8 - changed region is bounding rect around count chars, clipped by
-// pCompositeClip
-
-static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
-                               int count, char *chars)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, ImageText8);
-
-  if (count == 0) {
-    (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
-    return;
-  }
-
-  BoxRec box;
-  GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
-
-  RegionHelper changed(pScreen, &box, 0);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// ImageText16 - changed region is bounding rect around count chars, clipped by
-// pCompositeClip
-
-static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
-                                int count, unsigned short *chars)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, ImageText16);
-
-  if (count == 0) {
-    (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
-    return;
-  }
-
-  BoxRec box;
-  GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
-
-  RegionHelper changed(pScreen, &box, 0);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// ImageGlyphBlt - changed region is bounding rect around nglyph chars, clipped
-// by pCompositeClip
-
-static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
-                                  int y, unsigned int nglyph,
-                                  CharInfoPtr *ppci, void * pglyphBase)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, ImageGlyphBlt);
-
-  if (nglyph == 0) {
-    (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
-    return;
-  }
-
-  BoxRec box;
-  GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
-
-  RegionHelper changed(pScreen, &box, 0);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// PolyGlyphBlt - changed region is bounding rect around nglyph chars, clipped
-// by pCompositeClip
-
-static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
-                                 int y, unsigned int nglyph,
-                                 CharInfoPtr *ppci, void * pglyphBase)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, PolyGlyphBlt);
-
-  if (nglyph == 0) {
-    (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
-    return;
-  }
-
-  BoxRec box;
-  GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
-
-  RegionHelper changed(pScreen, &box, 0);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
-
-// PushPixels - changed region is the given rectangle, clipped by
-// pCompositeClip
-
-static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
-                               DrawablePtr pDrawable, int w, int h, int x,
-                               int y)
-{
-  GC_OP_UNWRAPPER(pDrawable, pGC, PushPixels);
-
-  BoxRec box;
-  box.x1 = x + pDrawable->x;
-  box.y1 = y + pDrawable->y;
-  box.x2 = box.x1 + w;
-  box.y2 = box.y1 + h;
-
-  RegionHelper changed(pScreen, &box, 0);
-
-  REGION_INTERSECT(pScreen, changed.reg, changed.reg, pGC->pCompositeClip);
-
-  (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
-
-  vncHooksScreen->desktop->add_changed(changed.reg);
-}
index 30b51dbd07f7440cc4d5997cb3336655ed1067b1..eb096103f8e449024da5988272877fc1c69649e0 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2009-2015 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
 #ifndef __VNCHOOKS_H__
 #define __VNCHOOKS_H__
 
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
+#ifdef __cplusplus
+extern "C" {
 #endif
 
-extern "C" {
-#include <screenint.h>
-  extern Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop);
+int vncHooksInit(int scrIdx);
+
+void vncGetScreenImage(int scrIdx, int x, int y, int width, int height,
+                       char *buffer, int strideBytes);
+
+#ifdef __cplusplus
 }
+#endif
 
 #endif
diff --git a/unix/xserver/hw/vnc/vncModule.c b/unix/xserver/hw/vnc/vncModule.c
new file mode 100644 (file)
index 0000000..051f6b4
--- /dev/null
@@ -0,0 +1,116 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+ * Copyright 2015 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.
+ */
+/*  This is the xf86 module code for the vnc extension.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "opaque.h"
+#ifdef RANDR
+#include "randrstr.h"
+#endif
+
+#include "xorg-version.h"
+
+#include "xf86.h"
+#include "xf86Module.h"
+
+#include "vncExtInit.h"
+#include "RFBGlue.h"
+
+static void vncModuleInit(INITARGS);
+
+static MODULESETUPPROTO(vncSetup);
+
+ExtensionModule vncExt =
+{
+    vncModuleInit,
+    "VNC",
+#if XORG < 112
+    NULL,
+    NULL,
+#endif
+    NULL
+};
+
+static XF86ModuleVersionInfo vncVersRec =
+{
+    "vnc",
+    "Constantin Kaplinsky",
+    MODINFOSTRING1,
+    MODINFOSTRING2,
+    XORG_VERSION_CURRENT,
+    1, 0, 0,
+    ABI_CLASS_EXTENSION,         /* needs the server extension ABI */
+    ABI_EXTENSION_VERSION,
+    MOD_CLASS_EXTENSION,
+    {0,0,0,0}
+};
+
+_X_EXPORT XF86ModuleData vncModuleData = { &vncVersRec, vncSetup, NULL };
+
+static void *
+vncSetup(void * module, void * opts, int *errmaj, int *errmin) {
+#if XORG >= 116
+    LoadExtensionList(&vncExt, 1, FALSE);
+#else
+    LoadExtension(&vncExt, FALSE);
+#endif
+    /* Need a non-NULL return value to indicate success */
+    return (void *)1;
+}
+
+static void vncModuleInit(INITARGS)
+{
+  static char once = 0;
+
+  if (!once) {
+    once++;
+
+    vncInitRFB();
+
+    for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+      ScrnInfoPtr pScrn;
+      XF86OptionPtr option;
+
+      pScrn = xf86Screens[scr];
+      option = pScrn->options;
+      while (option != NULL) {
+        vncSetParam(xf86OptionName(option), xf86OptionValue(option));
+        option = xf86NextOption(option);
+      }
+    }
+  }
+
+  vncExtensionInit();
+}
+
+#ifdef RANDR
+RRModePtr vncRandRModeGet(int width, int height)
+{
+    return NULL;
+}
+
+int vncRandRCreateOutputs(int scrIdx, int extraOutputs)
+{
+  return -1;
+}
+#endif
diff --git a/unix/xserver/hw/vnc/xf86vncModule.cc b/unix/xserver/hw/vnc/xf86vncModule.cc
deleted file mode 100644 (file)
index 6bf5e3d..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
- * 
- * 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.
- */
-/*  This is the xf86 module code for the vnc extension.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <rfb/Configuration.h>
-#include <rfb/Logger_stdio.h>
-#include <rfb/LogWriter.h>
-#include <rfb/ScreenSet.h>
-#include <rfb/screenTypes.h>
-
-#include "xorg-version.h"
-
-extern "C" {
-#define class c_class
-#define private c_private
-#define bool c_bool
-#define new c_new
-#include "xf86.h"
-#include "xf86Module.h"
-#ifdef RANDR
-#include "randrstr.h"
-#endif /* RANDR */
-#undef class
-#undef private
-#undef bool
-#undef new
-
-using namespace rfb;
-
-extern void vncExtensionInit();
-static void vncExtensionInitWithParams(INITARGS);
-
-char *listenaddr = NULL;
-
-static MODULESETUPPROTO(vncSetup);
-
-ExtensionModule vncExt =
-{
-    vncExtensionInitWithParams,
-    "VNC",
-#if XORG < 112
-    NULL,
-    NULL,
-#endif
-    NULL
-};
-
-static XF86ModuleVersionInfo vncVersRec =
-{
-    "vnc",
-    "Constantin Kaplinsky",
-    MODINFOSTRING1,
-    MODINFOSTRING2,
-    XORG_VERSION_CURRENT,
-    1, 0, 0,
-    ABI_CLASS_EXTENSION,         /* needs the server extension ABI */
-    ABI_EXTENSION_VERSION,
-    MOD_CLASS_EXTENSION,
-    {0,0,0,0}
-};
-
-_X_EXPORT XF86ModuleData vncModuleData = { &vncVersRec, vncSetup, NULL };
-
-static void *
-vncSetup(void * module, void * opts, int *errmaj, int *errmin) {
-#if XORG >= 116
-    LoadExtensionList(&vncExt, 1, FALSE);
-#else
-    LoadExtension(&vncExt, FALSE);
-#endif
-    /* Need a non-NULL return value to indicate success */
-    return (void *)1;
-}
-
-static void vncExtensionInitWithParams(INITARGS)
-{
-  static char once = 0;
-
-  if (!once) {
-    once++;
-    rfb::initStdIOLoggers();
-    rfb::LogWriter::setLogParams("*:stderr:30");
-    rfb::Configuration::enableServerParams();
-
-    for (int scr = 0; scr < screenInfo.numScreens; scr++) {
-      ScrnInfoPtr pScrn = xf86Screens[scr];
-
-      for (ParameterIterator i; i.param; i.next()) {
-        const char *val;
-#if XORG < 112
-        val = xf86FindOptionValue(pScrn->options, i.param->getName());
-#else
-        val = xf86FindOptionValue((XF86OptionPtr)pScrn->options, i.param->getName());
-#endif
-        if (val)
-          i.param->setParam(val);
-      }
-    }
-  }
-
-  vncExtensionInit();
-}
-}
-
-RRModePtr vncRandRModeGet(int width, int height)
-{
-    return NULL;
-}
-
-RROutputPtr vncRandROutputCreate(ScreenPtr pScreen)
-{
-    return NULL;
-}
diff --git a/unix/xserver/hw/vnc/xvnc.c b/unix/xserver/hw/vnc/xvnc.c
new file mode 100644 (file)
index 0000000..3498d0f
--- /dev/null
@@ -0,0 +1,1700 @@
+/* Copyright (c) 1993  X Consortium
+   Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
+   Copyright 2009-2015 Pierre Ossman for Cendio AB
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the X Consortium.
+
+*/
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "vncExtInit.h"
+#include "RFBGlue.h"
+#include "xorg-version.h"
+
+#ifdef WIN32
+#include <X11/Xwinsock.h>
+#endif
+#include <stdio.h>
+#include <X11/X.h>
+#define NEED_EVENTS
+#include <X11/Xproto.h>
+#include <X11/Xos.h>
+#include "scrnintstr.h"
+#include "servermd.h"
+#include "fb.h"
+#include "mi.h"
+#if XORG < 114
+#include "mibstore.h"
+#endif
+#include "colormapst.h"
+#include "gcstruct.h"
+#include "input.h"
+#include "mipointer.h"
+#include "micmap.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#ifndef WIN32
+#include <sys/param.h>
+#endif
+#include <X11/XWDFile.h>
+#ifdef HAS_SHM
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif /* HAS_SHM */
+#include "dix.h"
+#include "miline.h"
+#include "inputstr.h"
+#ifdef RANDR
+#include "randrstr.h"
+#endif /* RANDR */
+#include <X11/keysym.h>
+  extern char buildtime[];
+#if XORG >= 17
+#undef VENDOR_RELEASE
+#undef VENDOR_STRING
+#include "version-config.h"
+#endif
+#include "site.h"
+
+#if XORG >= 110
+#define Xalloc malloc
+#define Xfree free
+#endif
+
+#define XVNCVERSION "TigerVNC 1.4.80"
+#define XVNCCOPYRIGHT ("Copyright (C) 1999-2013 TigerVNC Team and many others (see README.txt)\n" \
+                       "See http://www.tigervnc.org for information on TigerVNC.\n")
+
+
+extern int monitorResolution;
+
+#define VFB_DEFAULT_WIDTH  1024
+#define VFB_DEFAULT_HEIGHT 768
+#define VFB_DEFAULT_DEPTH  24
+#define VFB_DEFAULT_WHITEPIXEL 0xffffffff
+#define VFB_DEFAULT_BLACKPIXEL 0
+#define VFB_DEFAULT_LINEBIAS 0
+#define XWD_WINDOW_NAME_LEN 60
+
+typedef struct
+{
+    int width;
+    int height;
+
+    int depth;
+
+    /* Computed when allocated */
+
+    int paddedBytesWidth;
+    int paddedWidth;
+
+    int bitsPerPixel;
+
+    /* Private */
+
+    int sizeInBytes;
+
+    void *pfbMemory;
+
+#ifdef HAS_SHM
+    int shmid;
+#endif
+} vfbFramebufferInfo, *vfbFramebufferInfoPtr;
+
+typedef struct
+{
+    int scrnum;
+
+    Pixel blackPixel;
+    Pixel whitePixel;
+
+    unsigned int lineBias;
+
+    CloseScreenProcPtr closeScreen;
+
+    vfbFramebufferInfo fb;
+
+    Bool pixelFormatDefined;
+    Bool rgbNotBgr;
+    int redBits, greenBits, blueBits;
+} vfbScreenInfo, *vfbScreenInfoPtr;
+
+static int vfbNumScreens;
+static vfbScreenInfo vfbScreens[MAXSCREENS];
+static Bool vfbPixmapDepths[33];
+typedef enum { NORMAL_MEMORY_FB, SHARED_MEMORY_FB } fbMemType;
+static fbMemType fbmemtype = NORMAL_MEMORY_FB;
+static int lastScreen = -1;
+static Bool Render = TRUE;
+
+static Bool displaySpecified = FALSE;
+static char displayNumStr[16];
+
+static int vncVerbose = DEFAULT_LOG_VERBOSITY;
+
+
+static void
+vfbInitializePixmapDepths(void)
+{
+    int i;
+    vfbPixmapDepths[1] = TRUE; /* always need bitmaps */
+    for (i = 2; i <= 32; i++)
+       vfbPixmapDepths[i] = FALSE;
+}
+
+static void
+vfbInitializeDefaultScreens(void)
+{
+    int i;
+
+    for (i = 0; i < MAXSCREENS; i++)
+    {
+       vfbScreens[i].scrnum = i;
+       vfbScreens[i].blackPixel = VFB_DEFAULT_BLACKPIXEL;
+       vfbScreens[i].whitePixel = VFB_DEFAULT_WHITEPIXEL;
+       vfbScreens[i].lineBias = VFB_DEFAULT_LINEBIAS;
+       vfbScreens[i].fb.width  = VFB_DEFAULT_WIDTH;
+       vfbScreens[i].fb.height = VFB_DEFAULT_HEIGHT;
+       vfbScreens[i].fb.pfbMemory = NULL;
+       vfbScreens[i].fb.depth  = VFB_DEFAULT_DEPTH;
+       vfbScreens[i].pixelFormatDefined = FALSE;
+    }
+    vfbNumScreens = 1;
+}
+
+static int
+vfbBitsPerPixel(int depth)
+{
+    if (depth == 1) return 1;
+    else if (depth <= 8) return 8;
+    else if (depth <= 16) return 16;
+    else return 32;
+}
+
+static void vfbFreeFramebufferMemory(vfbFramebufferInfoPtr pfb);
+
+#ifdef DPMSExtension
+    /* Why support DPMS? Because stupid modern desktop environments
+       such as Unity 2D on Ubuntu 11.10 crashes if DPMS is not
+       available. (DPMSSet is called by dpms.c, but the return value
+       is ignored.) */
+int DPMSSet(ClientPtr client, int level)
+{
+    return Success;
+}
+
+Bool DPMSSupported()
+{
+    /* Causes DPMSCapable to return false, meaning no devices are DPMS
+       capable */
+    return FALSE;
+}
+#endif
+
+#if XORG < 111
+void ddxGiveUp()
+#else
+void ddxGiveUp(enum ExitCode error)
+#endif
+{
+    int i;
+
+    /* clean up the framebuffers */
+    for (i = 0; i < vfbNumScreens; i++)
+        vfbFreeFramebufferMemory(&vfbScreens[i].fb);
+}
+
+void
+#if XORG < 111
+AbortDDX()
+#else
+AbortDDX(enum ExitCode error)
+#endif
+{
+#if XORG < 111
+    ddxGiveUp();
+#else
+    ddxGiveUp(error);
+#endif
+}
+
+#ifdef __DARWIN__
+void
+DarwinHandleGUI(int argc, char *argv[])
+{
+}
+
+void GlxExtensionInit();
+void GlxWrapInitVisuals(void *procPtr);
+
+void
+DarwinGlxExtensionInit()
+{
+    GlxExtensionInit();
+}
+
+void
+DarwinGlxWrapInitVisuals(
+    void *procPtr)
+{
+    GlxWrapInitVisuals(procPtr);
+}
+#endif
+
+void
+OsVendorInit()
+{
+}
+
+void
+#if XORG < 113
+OsVendorFatalError()
+#else
+OsVendorFatalError(const char *f, va_list args)
+#endif
+{
+}
+
+void ddxBeforeReset(void)
+{
+    return;
+}
+
+void 
+ddxUseMsg()
+{
+    ErrorF("\nXvnc %s - built %s\n%s", XVNCVERSION, buildtime, XVNCCOPYRIGHT);
+    ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE,
+           VENDOR_STRING);
+    ErrorF("-screen scrn WxHxD     set screen's width, height, depth\n");
+    ErrorF("-pixdepths list-of-int support given pixmap depths\n");
+#ifdef RENDER
+    ErrorF("+/-render             turn on/off RENDER extension support"
+          "(default on)\n");
+#endif
+    ErrorF("-linebias n            adjust thin line pixelization\n");
+    ErrorF("-blackpixel n          pixel value for black\n");
+    ErrorF("-whitepixel n          pixel value for white\n");
+
+#ifdef HAS_SHM
+    ErrorF("-shmem                 put framebuffers in shared memory\n");
+#endif
+
+    ErrorF("-geometry WxH          set screen 0's width, height\n");
+    ErrorF("-depth D               set screen 0's depth\n");
+    ErrorF("-pixelformat fmt       set pixel format (rgbNNN or bgrNNN)\n");
+    ErrorF("-inetd                 has been launched from inetd\n");
+    ErrorF("-noclipboard           disable clipboard settings modification via vncconfig utility\n");
+    ErrorF("-verbose [n]           verbose startup messages\n");
+    ErrorF("-quiet                 minimal startup messages\n");
+    ErrorF("\nVNC parameters:\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"
+            "Other valid forms are <param>=<value> -<param>=<value> "
+            "--<param>=<value>\n"
+            "Parameter names are case-insensitive.  The parameters are:\n\n");
+    vncListParams(79, 14);
+}
+
+/* ddxInitGlobals - called by |InitGlobals| from os/util.c */
+void ddxInitGlobals(void)
+{
+}
+
+static 
+Bool displayNumFree(int num)
+{
+    char file[256];
+    if (vncIsTCPPortUsed(6000+num))
+        return FALSE;
+    sprintf(file, "/tmp/.X%d-lock", num);
+    if (access(file, F_OK) == 0)
+        return FALSE;
+    sprintf(file, "/tmp/.X11-unix/X%d", num);
+    if (access(file, F_OK) == 0)
+        return FALSE;
+    sprintf(file, "/usr/spool/sockets/X11/%d", num);
+    if (access(file, F_OK) == 0)
+        return FALSE;
+    return TRUE;
+}
+
+int 
+ddxProcessArgument(int argc, char *argv[], int i)
+{
+    static Bool firstTime = TRUE;
+
+    if (firstTime)
+    {
+       vfbInitializeDefaultScreens();
+       vfbInitializePixmapDepths();
+       firstTime = FALSE;
+       vncInitRFB();
+    }
+
+    if (argv[i][0] ==  ':')
+        displaySpecified = TRUE;
+
+    if (strcmp (argv[i], "-screen") == 0)      /* -screen n WxHxD */
+    {
+       int screenNum;
+       if (i + 2 >= argc) UseMsg();
+       screenNum = atoi(argv[i+1]);
+       if (screenNum < 0 || screenNum >= MAXSCREENS)
+       {
+           ErrorF("Invalid screen number %d\n", screenNum);
+           UseMsg();
+       }
+       if (3 != sscanf(argv[i+2], "%dx%dx%d",
+                       &vfbScreens[screenNum].fb.width,
+                       &vfbScreens[screenNum].fb.height,
+                       &vfbScreens[screenNum].fb.depth))
+       {
+           ErrorF("Invalid screen configuration %s\n", argv[i+2]);
+           UseMsg();
+       }
+
+       if (screenNum >= vfbNumScreens)
+           vfbNumScreens = screenNum + 1;
+       lastScreen = screenNum;
+       return 3;
+    }
+
+    if (strcmp (argv[i], "-pixdepths") == 0)   /* -pixdepths list-of-depth */
+    {
+       int depth, ret = 1;
+
+       if (++i >= argc) UseMsg();
+       while ((i < argc) && (depth = atoi(argv[i++])) != 0)
+       {
+           if (depth < 0 || depth > 32)
+           {
+               ErrorF("Invalid pixmap depth %d\n", depth);
+               UseMsg();
+           }
+           vfbPixmapDepths[depth] = TRUE;
+           ret++;
+       }
+       return ret;
+    }
+    
+    if (strcmp (argv[i], "+render") == 0)      /* +render */
+    {
+       Render = TRUE;
+       return 1;
+    }
+  
+    if (strcmp (argv[i], "-render") == 0)      /* -render */
+    {
+       Render = FALSE;
+       return 1;
+    }
+
+    if (strcmp (argv[i], "-blackpixel") == 0)  /* -blackpixel n */
+    {
+       Pixel pix;
+       if (++i >= argc) UseMsg();
+       pix = atoi(argv[i]);
+       if (-1 == lastScreen)
+       {
+           int i;
+           for (i = 0; i < MAXSCREENS; i++)
+           {
+               vfbScreens[i].blackPixel = pix;
+           }
+       }
+       else
+       {
+           vfbScreens[lastScreen].blackPixel = pix;
+       }
+       return 2;
+    }
+
+    if (strcmp (argv[i], "-whitepixel") == 0)  /* -whitepixel n */
+    {
+       Pixel pix;
+       if (++i >= argc) UseMsg();
+       pix = atoi(argv[i]);
+       if (-1 == lastScreen)
+       {
+           int i;
+           for (i = 0; i < MAXSCREENS; i++)
+           {
+               vfbScreens[i].whitePixel = pix;
+           }
+       }
+       else
+       {
+           vfbScreens[lastScreen].whitePixel = pix;
+       }
+       return 2;
+    }
+    
+    if (strcmp (argv[i], "-linebias") == 0)    /* -linebias n */
+    {
+       unsigned int linebias;
+       if (++i >= argc) UseMsg();
+       linebias = atoi(argv[i]);
+       if (-1 == lastScreen)
+       {
+           int i;
+           for (i = 0; i < MAXSCREENS; i++)
+           {
+               vfbScreens[i].lineBias = linebias;
+           }
+       }
+       else
+       {
+           vfbScreens[lastScreen].lineBias = linebias;
+       }
+       return 2;
+    }
+
+#ifdef HAS_SHM
+    if (strcmp (argv[i], "-shmem") == 0)       /* -shmem */
+    {
+       fbmemtype = SHARED_MEMORY_FB;
+       return 1;
+    }
+#endif
+    
+    if (strcmp(argv[i], "-geometry") == 0)
+    {
+       if (++i >= argc) UseMsg();
+       if (sscanf(argv[i],"%dx%d",&vfbScreens[0].fb.width,
+                  &vfbScreens[0].fb.height) != 2) {
+           ErrorF("Invalid geometry %s\n", argv[i]);
+           UseMsg();
+       }
+       return 2;
+    }
+    
+    if (strcmp(argv[i], "-depth") == 0)
+    {
+       if (++i >= argc) UseMsg();
+       vfbScreens[0].fb.depth = atoi(argv[i]);
+       return 2;
+    }
+
+    if (strcmp(argv[i], "-pixelformat") == 0)
+    {
+       char rgbbgr[4];
+       int bits1, bits2, bits3;
+       if (++i >= argc) UseMsg();
+       if (sscanf(argv[i], "%3s%1d%1d%1d", rgbbgr,&bits1,&bits2,&bits3) < 4) {
+           ErrorF("Invalid pixel format %s\n", argv[i]);
+           UseMsg();
+       }
+
+#define SET_PIXEL_FORMAT(vfbScreen)                     \
+    (vfbScreen).pixelFormatDefined = TRUE;              \
+    (vfbScreen).fb.depth = bits1 + bits2 + bits3;          \
+    (vfbScreen).greenBits = bits2;                      \
+    if (strcasecmp(rgbbgr, "bgr") == 0) {               \
+        (vfbScreen).rgbNotBgr = FALSE;                  \
+        (vfbScreen).redBits = bits3;                    \
+        (vfbScreen).blueBits = bits1;                   \
+    } else if (strcasecmp(rgbbgr, "rgb") == 0) {        \
+        (vfbScreen).rgbNotBgr = TRUE;                   \
+        (vfbScreen).redBits = bits1;                    \
+        (vfbScreen).blueBits = bits3;                   \
+    } else {                                            \
+        ErrorF("Invalid pixel format %s\n", argv[i]);   \
+        UseMsg();                                       \
+    }
+
+       if (-1 == lastScreen)
+       {
+           int i;
+           for (i = 0; i < MAXSCREENS; i++)
+           {
+               SET_PIXEL_FORMAT(vfbScreens[i]);
+           }
+       }
+       else
+       {
+           SET_PIXEL_FORMAT(vfbScreens[lastScreen]);
+       }
+
+       return 2;
+    }
+
+    if (strcmp(argv[i], "-inetd") == 0)
+    {
+       dup2(0,3);
+       vncInetdSock = 3;
+       close(2);
+       
+       if (!displaySpecified) {
+           int port = vncGetSocketPort(vncInetdSock);
+           int displayNum = port - 5900;
+           if (displayNum < 0 || displayNum > 99 || !displayNumFree(displayNum)) {
+               for (displayNum = 1; displayNum < 100; displayNum++)
+                   if (displayNumFree(displayNum)) break;
+               
+               if (displayNum == 100)
+                   FatalError("Xvnc error: no free display number for -inetd");
+           }
+           
+           display = displayNumStr;
+           sprintf(displayNumStr, "%d", displayNum);
+       }
+       
+       return 1;
+    }
+
+    if (strcmp(argv[i], "-noclipboard") == 0) {
+       vncNoClipboard = 1;
+       return 1;
+    }
+
+    if (!strcmp(argv[i], "-verbose")) {
+        if (++i < argc && argv[i]) {
+            char *end;
+            long val;
+
+            val = strtol(argv[i], &end, 0);
+            if (*end == '\0') {
+                vncVerbose = val;
+                LogSetParameter(XLOG_VERBOSITY, vncVerbose);
+                return 2;
+            }
+        }
+        vncVerbose++;
+        LogSetParameter(XLOG_VERBOSITY, vncVerbose);
+        return 1;
+    }
+
+    if (!strcmp(argv[i], "-quiet")) {
+        vncVerbose = -1;
+        LogSetParameter(XLOG_VERBOSITY, vncVerbose);
+        return 1;
+    }
+
+    if (vncSetParamSimple(argv[i]))
+       return 1;
+    
+    if (argv[i][0] == '-' && i+1 < argc) {
+       if (vncSetParam(&argv[i][1], argv[i+1]))
+           return 2;
+    }
+    
+    return 0;
+}
+
+#ifdef DDXTIME /* from ServerOSDefines */
+CARD32
+GetTimeInMillis()
+{
+    struct timeval  tp;
+
+    X_GETTIMEOFDAY(&tp);
+    return(tp.tv_sec * 1000) + (tp.tv_usec / 1000);
+}
+#endif
+
+#if XORG < 113
+static ColormapPtr InstalledMaps[MAXSCREENS];
+#else
+static DevPrivateKeyRec cmapScrPrivateKeyRec;
+#define cmapScrPrivateKey (&cmapScrPrivateKeyRec)
+#define GetInstalledColormap(s) ((ColormapPtr) dixLookupPrivate(&(s)->devPrivates, cmapScrPrivateKey))
+#define SetInstalledColormap(s,c) (dixSetPrivate(&(s)->devPrivates, cmapScrPrivateKey, c))
+#endif
+
+static int 
+vfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps)
+{
+    /* By the time we are processing requests, we can guarantee that there
+     * is always a colormap installed */
+#if XORG < 113
+    *pmaps = InstalledMaps[pScreen->myNum]->mid;
+#else
+    *pmaps = GetInstalledColormap(pScreen)->mid;
+#endif
+    return (1);
+}
+
+
+static void 
+vfbInstallColormap(ColormapPtr pmap)
+{
+#if XORG < 113
+    int index = pmap->pScreen->myNum;
+#endif
+    ColormapPtr oldpmap;
+
+#if XORG < 113
+    oldpmap = InstalledMaps[index];
+#else
+    oldpmap = GetInstalledColormap(pmap->pScreen);
+#endif
+
+    if (pmap != oldpmap)
+    {
+       int entries;
+       VisualPtr pVisual;
+       Pixel *     ppix;
+       xrgb *      prgb;
+       xColorItem *defs;
+       int i;
+
+       if(oldpmap != (ColormapPtr)None)
+           WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid);
+       /* Install pmap */
+#if XORG < 113
+       InstalledMaps[index] = pmap;
+#else
+       SetInstalledColormap(pmap->pScreen, pmap);
+#endif
+       WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid);
+
+       entries = pmap->pVisual->ColormapEntries;
+       pVisual = pmap->pVisual;
+
+       ppix = (Pixel *)xalloc(entries * sizeof(Pixel));
+       prgb = (xrgb *)xalloc(entries * sizeof(xrgb));
+       defs = (xColorItem *)xalloc(entries * sizeof(xColorItem));
+
+       for (i = 0; i < entries; i++)  ppix[i] = i;
+       /* XXX truecolor */
+#if XORG < 19
+       QueryColors(pmap, entries, ppix, prgb);
+#else
+       QueryColors(pmap, entries, ppix, prgb, serverClient);
+#endif
+
+       for (i = 0; i < entries; i++) { /* convert xrgbs to xColorItems */
+           defs[i].pixel = ppix[i] & 0xff; /* change pixel to index */
+           defs[i].red = prgb[i].red;
+           defs[i].green = prgb[i].green;
+           defs[i].blue = prgb[i].blue;
+           defs[i].flags =  DoRed|DoGreen|DoBlue;
+       }
+       (*pmap->pScreen->StoreColors)(pmap, entries, defs);
+       
+       xfree(ppix);
+       xfree(prgb);
+       xfree(defs);
+    }
+}
+
+static void
+vfbUninstallColormap(ColormapPtr pmap)
+{
+#if XORG < 113
+    ColormapPtr curpmap = InstalledMaps[pmap->pScreen->myNum];
+#else
+    ColormapPtr curpmap = GetInstalledColormap(pmap->pScreen);
+#endif
+
+    if(pmap == curpmap)
+    {
+       if (pmap->mid != pmap->pScreen->defColormap)
+       {
+#if XORG < 111
+           curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
+                                                  RT_COLORMAP);
+#else
+           dixLookupResourceByType((void * *) &curpmap, pmap->pScreen->defColormap,
+                                   RT_COLORMAP, serverClient, DixUnknownAccess);
+#endif
+           (*pmap->pScreen->InstallColormap)(curpmap);
+       }
+    }
+}
+
+static Bool
+vfbSaveScreen(ScreenPtr pScreen, int on)
+{
+    return TRUE;
+}
+
+#ifdef HAS_SHM
+static void
+vfbAllocateSharedMemoryFramebuffer(vfbFramebufferInfoPtr pfb)
+{
+    /* create the shared memory segment */
+
+    pfb->shmid = shmget(IPC_PRIVATE, pfb->sizeInBytes, IPC_CREAT|0777);
+    if (pfb->shmid < 0) {
+        perror("shmget");
+        ErrorF("shmget %d bytes failed, errno %d", pfb->sizeInBytes, errno);
+        return;
+    }
+
+    /* try to attach it */
+
+    pfb->pfbMemory = shmat(pfb->shmid, 0, 0);
+    if (-1 == (long)pfb->pfbMemory) {
+        perror("shmat");
+        ErrorF("shmat failed, errno %d", errno);
+        pfb->pfbMemory = NULL; 
+        return;
+    }
+}
+#endif /* HAS_SHM */
+
+
+static void *
+vfbAllocateFramebufferMemory(vfbFramebufferInfoPtr pfb)
+{
+    if (pfb->pfbMemory != NULL)
+        return pfb->pfbMemory; /* already done */
+
+    /* Compute memory layout */
+    pfb->paddedBytesWidth = PixmapBytePad(pfb->width, pfb->depth);
+    pfb->bitsPerPixel = vfbBitsPerPixel(pfb->depth);
+    pfb->paddedWidth = pfb->paddedBytesWidth * 8 / pfb->bitsPerPixel;
+    pfb->sizeInBytes = pfb->paddedBytesWidth * pfb->height;
+
+    /* And allocate buffer */
+    switch (fbmemtype) {
+#ifdef HAS_SHM
+    case SHARED_MEMORY_FB:
+        vfbAllocateSharedMemoryFramebuffer(pfb);
+        break;
+#else
+    case SHARED_MEMORY_FB:
+        break;
+#endif
+    case NORMAL_MEMORY_FB:
+        pfb->pfbMemory = Xalloc(pfb->sizeInBytes);
+        break;
+    }
+
+    /* This will be NULL if any of the above failed */
+    return pfb->pfbMemory;
+}
+
+static void
+vfbFreeFramebufferMemory(vfbFramebufferInfoPtr pfb)
+{
+    if ((pfb == NULL) || (pfb->pfbMemory == NULL))
+        return;
+
+    switch (fbmemtype) {
+#ifdef HAS_SHM
+    case SHARED_MEMORY_FB:
+        if (-1 == shmdt(pfb->pfbMemory)) {
+            perror("shmdt");
+            ErrorF("shmdt failed, errno %d", errno);
+        }
+        break;
+#else /* HAS_SHM */
+    case SHARED_MEMORY_FB:
+        break;
+#endif /* HAS_SHM */
+    case NORMAL_MEMORY_FB:
+        Xfree(pfb->pfbMemory);
+        break;
+    }
+
+    pfb->pfbMemory = NULL;
+}
+
+static Bool
+vfbCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y)
+{
+    return FALSE;
+}
+
+static void
+vfbCrossScreen (ScreenPtr pScreen, Bool entering)
+{
+}
+
+static Bool vfbRealizeCursor(
+#if XORG >= 16
+                            DeviceIntPtr pDev,
+#endif
+                            ScreenPtr pScreen, CursorPtr pCursor) {
+    return TRUE;
+}
+
+static Bool vfbUnrealizeCursor(
+#if XORG >= 16
+                              DeviceIntPtr pDev,
+#endif
+                              ScreenPtr pScreen, CursorPtr pCursor) {
+    return TRUE;
+}
+
+static void vfbSetCursor(
+#if XORG >= 16
+                        DeviceIntPtr pDev,
+#endif
+                        ScreenPtr pScreen, CursorPtr pCursor, int x, int y) 
+{
+}
+
+static void vfbMoveCursor(
+#if XORG >= 16
+                         DeviceIntPtr pDev,
+#endif
+                         ScreenPtr pScreen, int x, int y) 
+{
+}
+
+#if XORG >= 16
+static Bool
+vfbDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
+{   
+    return TRUE;
+}
+
+static void
+vfbDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
+{ 
+}
+#endif
+
+static miPointerSpriteFuncRec vfbPointerSpriteFuncs = {
+    vfbRealizeCursor,
+    vfbUnrealizeCursor,
+    vfbSetCursor,
+    vfbMoveCursor
+#if XORG >= 16
+    , vfbDeviceCursorInitialize,
+    vfbDeviceCursorCleanup
+#endif
+};
+
+static miPointerScreenFuncRec vfbPointerCursorFuncs = {
+    vfbCursorOffScreen,
+    vfbCrossScreen,
+    miPointerWarpCursor
+};
+
+#ifdef RANDR
+
+static Bool vncRandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
+{
+  // We update all information right away, so there is nothing to
+  // do here.
+  return TRUE;
+}
+
+/* from hw/xfree86/common/xf86Helper.c */
+
+#include "mivalidate.h"
+static void
+xf86SetRootClip (ScreenPtr pScreen, Bool enable)
+{
+#if XORG < 19
+    WindowPtr  pWin = WindowTable[pScreen->myNum];
+#else
+    WindowPtr  pWin = pScreen->root;
+#endif
+    WindowPtr  pChild;
+    Bool       WasViewable = (Bool)(pWin->viewable);
+    Bool       anyMarked = FALSE;
+#if XORG < 110
+    RegionPtr  pOldClip = NULL, bsExposed;
+#ifdef DO_SAVE_UNDERS
+    Bool       dosave = FALSE;
+#endif
+#endif
+    WindowPtr   pLayerWin;
+    BoxRec     box;
+
+    if (WasViewable)
+    {
+       for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
+       {
+           (void) (*pScreen->MarkOverlappedWindows)(pChild,
+                                                    pChild,
+                                                    &pLayerWin);
+       }
+       (*pScreen->MarkWindow) (pWin);
+       anyMarked = TRUE;
+       if (pWin->valdata)
+       {
+           if (HasBorder (pWin))
+           {
+               RegionPtr       borderVisible;
+
+               borderVisible = REGION_CREATE(pScreen, NullBox, 1);
+               REGION_SUBTRACT(pScreen, borderVisible,
+                               &pWin->borderClip, &pWin->winSize);
+               pWin->valdata->before.borderVisible = borderVisible;
+           }
+           pWin->valdata->before.resized = TRUE;
+       }
+    }
+    
+    /*
+     * Use REGION_BREAK to avoid optimizations in ValidateTree
+     * that assume the root borderClip can't change well, normally
+     * it doesn't...)
+     */
+    if (enable)
+    {
+       box.x1 = 0;
+       box.y1 = 0;
+       box.x2 = pScreen->width;
+       box.y2 = pScreen->height;
+       REGION_INIT (pScreen, &pWin->winSize, &box, 1);
+       REGION_INIT (pScreen, &pWin->borderSize, &box, 1);
+       if (WasViewable)
+           REGION_RESET(pScreen, &pWin->borderClip, &box);
+       pWin->drawable.width = pScreen->width;
+       pWin->drawable.height = pScreen->height;
+        REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
+    }
+    else
+    {
+       REGION_EMPTY(pScreen, &pWin->borderClip);
+       REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
+    }
+    
+    ResizeChildrenWinSize (pWin, 0, 0, 0, 0);
+    
+    if (WasViewable)
+    {
+#if XORG < 110
+       if (pWin->backStorage)
+       {
+           pOldClip = REGION_CREATE(pScreen, NullBox, 1);
+           REGION_COPY(pScreen, pOldClip, &pWin->clipList);
+       }
+#endif
+
+       if (pWin->firstChild)
+       {
+           anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild,
+                                                          pWin->firstChild,
+                                                          (WindowPtr *)NULL);
+       }
+       else
+       {
+           (*pScreen->MarkWindow) (pWin);
+           anyMarked = TRUE;
+       }
+
+#if XORG < 110 && defined(DO_SAVE_UNDERS)
+       if (DO_SAVE_UNDERS(pWin))
+       {
+           dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin);
+       }
+#endif /* DO_SAVE_UNDERS */
+
+       if (anyMarked)
+           (*pScreen->ValidateTree)(pWin, NullWindow, VTOther);
+    }
+
+#if XORG < 110
+    if (pWin->backStorage &&
+       ((pWin->backingStore == Always) || WasViewable))
+    {
+       if (!WasViewable)
+           pOldClip = &pWin->clipList; /* a convenient empty region */
+       bsExposed = (*pScreen->TranslateBackingStore)
+                            (pWin, 0, 0, pOldClip,
+                             pWin->drawable.x, pWin->drawable.y);
+       if (WasViewable)
+           REGION_DESTROY(pScreen, pOldClip);
+       if (bsExposed)
+       {
+           RegionPtr   valExposed = NullRegion;
+    
+           if (pWin->valdata)
+               valExposed = &pWin->valdata->after.exposed;
+           (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
+           if (valExposed)
+               REGION_EMPTY(pScreen, valExposed);
+           REGION_DESTROY(pScreen, bsExposed);
+       }
+    }
+#endif
+    if (WasViewable)
+    {
+       if (anyMarked)
+           (*pScreen->HandleExposures)(pWin);
+
+#if XORG < 110 && defined(DO_SAVE_UNDERS)
+       if (dosave)
+           (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin);
+#endif /* DO_SAVE_UNDERS */
+       if (anyMarked && pScreen->PostValidateTree)
+           (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther);
+    }
+    if (pWin->realized)
+       WindowsRestructured ();
+    FlushAllOutput ();
+}
+
+RRModePtr vncRandRModeGet(int width, int height);
+static Bool vncRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode,
+                            int x, int y, Rotation rotation, int num_outputs,
+                            RROutputPtr *outputs);
+
+static Bool vncRandRScreenSetSize(ScreenPtr pScreen,
+                                  CARD16 width, CARD16 height,
+                                  CARD32 mmWidth, CARD32 mmHeight)
+{
+    vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
+    vfbFramebufferInfo fb;
+    rrScrPrivPtr rp = rrGetScrPriv(pScreen);
+    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+    void *pbits;
+    Bool ret;
+    int oldwidth, oldheight, oldmmWidth, oldmmHeight;
+
+    /* Prevent updates while we fiddle */
+    xf86SetRootClip(pScreen, FALSE);
+
+    /* Store current state in case we fail */
+    oldwidth = pScreen->width;
+    oldheight = pScreen->height;
+    oldmmWidth = pScreen->mmWidth;
+    oldmmHeight = pScreen->mmHeight;
+
+    /* Then set the new dimensions */
+    pScreen->width = width;
+    pScreen->height = height;
+    pScreen->mmWidth = mmWidth;
+    pScreen->mmHeight = mmHeight;
+
+    /* Allocate a new framebuffer */
+    memset(&fb, 0, sizeof(vfbFramebufferInfo));
+
+    fb.width = pScreen->width;
+    fb.height = pScreen->height;
+    fb.depth = pvfb->fb.depth;
+
+    pbits = vfbAllocateFramebufferMemory(&fb);
+    if (!pbits) {
+        /* Allocation failed. Restore old state */
+        pScreen->width = oldwidth;
+        pScreen->height = oldheight;
+        pScreen->mmWidth = oldmmWidth;
+        pScreen->mmHeight = oldmmHeight;
+
+        xf86SetRootClip(pScreen, TRUE);
+
+        return FALSE;
+    }
+
+    /* Update root pixmap with the new dimensions and buffer */
+    ret = pScreen->ModifyPixmapHeader(rootPixmap, fb.width, fb.height,
+                                      -1, -1, fb.paddedBytesWidth, pbits);
+    if (!ret) {
+        /* Update failed. Free the new framebuffer and restore old state */
+        vfbFreeFramebufferMemory(&fb);
+
+        pScreen->width = oldwidth;
+        pScreen->height = oldheight;
+        pScreen->mmWidth = oldmmWidth;
+        pScreen->mmHeight = oldmmHeight;
+
+        xf86SetRootClip(pScreen, TRUE);
+
+        return FALSE;
+    }
+
+    /* Free the old framebuffer and keep the info about the new one */
+    vfbFreeFramebufferMemory(&pvfb->fb);
+    memcpy(&pvfb->fb, &fb, sizeof(vfbFramebufferInfo));
+
+    /* Let VNC get the new framebuffer (actual update is in vncHooks.cc) */
+    vncFbptr[pScreen->myNum] = pbits;
+    vncFbstride[pScreen->myNum] = fb.paddedWidth;
+
+    /* Restore ability to update screen, now with new dimensions */
+    xf86SetRootClip(pScreen, TRUE);
+
+    /*
+     * Let RandR know we changed something (it doesn't assume that
+     * TRUE means something changed for some reason...).
+     */
+    RRScreenSizeNotify(pScreen);
+
+    /* Crop all CRTCs to the new screen */
+    for (int i = 0;i < rp->numCrtcs;i++) {
+        RRCrtcPtr crtc;
+        RRModePtr mode;
+
+        crtc = rp->crtcs[i];
+
+        /* Disabled? */
+        if (crtc->mode == NULL)
+            continue;
+
+        /* Fully inside? */
+        if ((crtc->x + crtc->mode->mode.width <= width) &&
+            (crtc->y + crtc->mode->mode.height <= height))
+            continue;
+
+        /* Fully outside? */
+        if ((crtc->x >= width) || (crtc->y >= height)) {
+            /* Disable it */
+            ret = vncRandRCrtcSet(pScreen, crtc, NULL,
+                                  crtc->x, crtc->y, crtc->rotation, 0, NULL);
+            if (!ret)
+                ErrorF("Warning: Unable to disable CRTC that is outside of new screen dimensions");
+            continue;
+        }
+
+        /* Just needs to be resized */
+        mode = vncRandRModeGet(width - crtc->x, height - crtc->y);
+        if (mode == NULL) {
+            ErrorF("Warning: Unable to create custom mode for %dx%d",
+                   width - crtc->x, height - crtc->y);
+            continue;
+        }
+
+        ret = vncRandRCrtcSet(pScreen, crtc, mode,
+                              crtc->x, crtc->y, crtc->rotation,
+                              crtc->numOutputs, crtc->outputs);
+        RRModeDestroy(mode);
+        if (!ret)
+            ErrorF("Warning: Unable to crop CRTC to new screen dimensions");
+    }
+
+    return TRUE;
+}
+
+static Bool vncRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode,
+                            int x, int y, Rotation rotation, int num_outputs,
+                            RROutputPtr *outputs)
+{
+    Bool ret;
+    int i;
+
+    /*
+     * Some applications get confused by a connected output without a
+     * mode or CRTC, so we need to fiddle with the connection state as well.
+     */
+    for (i = 0;i < crtc->numOutputs;i++)
+        RROutputSetConnection(crtc->outputs[i], RR_Disconnected);
+
+    for (i = 0;i < num_outputs;i++) {
+        if (mode != NULL)
+            RROutputSetConnection(outputs[i], RR_Connected);
+        else
+            RROutputSetConnection(outputs[i], RR_Disconnected);
+    }
+
+    /* Let RandR know we approve, and let it update its internal state */
+    ret = RRCrtcNotify(crtc, mode, x, y, rotation,
+#if XORG >= 16
+                       NULL,
+#endif
+                       num_outputs, outputs);
+    if (!ret)
+        return FALSE;
+
+    return TRUE;
+}
+
+static Bool vncRandROutputValidateMode(ScreenPtr pScreen,
+                                       RROutputPtr output, RRModePtr mode)
+{
+    /* We have no hardware so any mode works */
+    return TRUE;
+}
+
+static void vncRandRModeDestroy(ScreenPtr pScreen, RRModePtr mode)
+{
+    /* We haven't allocated anything so nothing to destroy */
+}
+
+static const int vncRandRWidths[] =  { 1920, 1920, 1600, 1680, 1400, 1360, 1280, 1280, 1280, 1280, 1024, 800, 640 };
+static const int vncRandRHeights[] = { 1200, 1080, 1200, 1050, 1050,  768, 1024,  960,  800,  720,  768, 600, 480 };
+
+static int vncRandRIndex = 0;
+
+/* This is a global symbol since XserverDesktop also uses it */
+RRModePtr vncRandRModeGet(int width, int height)
+{
+    xRRModeInfo        modeInfo;
+    char name[100];
+    RRModePtr mode;
+
+    memset(&modeInfo, 0, sizeof(modeInfo));
+    sprintf(name, "%dx%d", width, height);
+    
+    modeInfo.width = width;
+    modeInfo.height = height;
+    modeInfo.hTotal = width;
+    modeInfo.vTotal = height;
+    modeInfo.dotClock = ((CARD32)width * (CARD32)height * 60);
+    modeInfo.nameLength = strlen(name);
+    mode = RRModeGet(&modeInfo, name);
+    if (mode == NULL)
+        return NULL;
+
+    return mode;
+}
+
+static RRCrtcPtr vncRandRCrtcCreate(ScreenPtr pScreen)
+{
+    RRCrtcPtr crtc;
+    RROutputPtr output;
+    RRModePtr mode;
+    char name[100];
+
+    /* First we create the CRTC... */
+    crtc = RRCrtcCreate(pScreen, NULL);
+
+    /* We don't actually support gamma, but xrandr complains when it is missing */
+    RRCrtcGammaSetSize (crtc, 256);
+
+    /* Then we create a dummy output for it... */
+    sprintf(name, "VNC-%d", vncRandRIndex);
+    vncRandRIndex++;
+
+    output = RROutputCreate(pScreen, name, strlen(name), NULL);
+
+    RROutputSetCrtcs(output, &crtc, 1);
+    RROutputSetConnection(output, RR_Disconnected);
+
+    /* Make sure the CRTC has this output set */
+    vncRandRCrtcSet(pScreen, crtc, NULL, 0, 0, RR_Rotate_0, 1, &output);
+
+    /* Populate a list of default modes */
+    RRModePtr modes[sizeof(vncRandRWidths)/sizeof(*vncRandRWidths)];
+    int num_modes;
+
+    num_modes = 0;
+    for (int i = 0;i < sizeof(vncRandRWidths)/sizeof(*vncRandRWidths);i++) {
+        mode = vncRandRModeGet(vncRandRWidths[i], vncRandRHeights[i]);
+        if (mode != NULL) {
+            modes[num_modes] = mode;
+            num_modes++;
+        }
+    }
+
+    RROutputSetModes(output, modes, num_modes, 0);
+
+    return crtc;
+}
+
+/* Used from XserverDesktop when it needs more outputs... */
+int vncRandRCreateOutputs(int scrIdx, int extraOutputs)
+{
+    RRCrtcPtr crtc;
+
+    while (extraOutputs > 0) {
+        crtc = vncRandRCrtcCreate(screenInfo.screens[scrIdx]);
+        if (crtc == NULL)
+            return -1;
+        extraOutputs--;
+    }
+
+    return 0;
+}
+
+static Bool vncRandRInit(ScreenPtr pScreen)
+{
+    RRCrtcPtr crtc;
+    RRModePtr mode;
+    Bool ret;
+
+    if (!RRInit())
+        return FALSE;
+
+    /* These are completely arbitrary */
+    RRScreenSetSizeRange(pScreen, 32, 32, 32768, 32768);
+
+    /*
+     * Start with a single CRTC with a single output. More will be
+     * allocated as needed...
+     */
+    crtc = vncRandRCrtcCreate(pScreen);
+
+    /* Make sure the current screen size is the active mode */
+    mode = vncRandRModeGet(pScreen->width, pScreen->height);
+    if (mode == NULL)
+        return FALSE;
+
+    ret = vncRandRCrtcSet(pScreen, crtc, mode, 0, 0, RR_Rotate_0,
+                          crtc->numOutputs, crtc->outputs);
+    RRModeDestroy(mode);
+    if (!ret)
+        return FALSE;
+
+    return TRUE;
+}
+
+#endif
+
+static Bool
+#if XORG < 113
+vfbCloseScreen(int index, ScreenPtr pScreen)
+#else
+vfbCloseScreen(ScreenPtr pScreen)
+#endif
+{
+#if XORG < 113
+    vfbScreenInfoPtr pvfb = &vfbScreens[index];
+#else
+    vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
+#endif
+    int i;
+    pScreen->CloseScreen = pvfb->closeScreen;
+
+    /*
+     * XXX probably lots of stuff to clean.  For now,
+     * clear installed colormaps so that server reset works correctly.
+     */
+#if XORG < 113
+    for (i = 0; i < MAXSCREENS; i++)
+       InstalledMaps[i] = NULL;
+
+    return pScreen->CloseScreen(index, pScreen);
+#else
+    for (i = 0; i < screenInfo.numScreens; i++)
+       SetInstalledColormap(screenInfo.screens[i], NULL);
+
+    /*
+     * fb overwrites miCloseScreen, so do this here
+     */
+    if (pScreen->devPrivate)
+        (*pScreen->DestroyPixmap) ((PixmapPtr) pScreen->devPrivate);
+    pScreen->devPrivate = NULL;
+
+    return pScreen->CloseScreen(pScreen);
+#endif
+}
+
+static Bool
+#if XORG < 113
+vfbScreenInit(int index, ScreenPtr pScreen, int argc, char **argv)
+#else
+vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
+#endif
+{
+#if XORG < 113
+    vfbScreenInfoPtr pvfb = &vfbScreens[index];
+#else
+    vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
+#endif
+    int dpi;
+    int ret;
+    void *pbits;
+
+#if XORG >= 113
+    if (!dixRegisterPrivateKey(&cmapScrPrivateKeyRec, PRIVATE_SCREEN, 0))
+       return FALSE;
+#endif
+
+    /* 96 is the default used by most other systems */
+    dpi = 96;
+    if (monitorResolution)
+        dpi = monitorResolution;
+
+    pbits = vfbAllocateFramebufferMemory(&pvfb->fb);
+    if (!pbits) return FALSE;
+#if XORG < 113
+    vncFbptr[index] = pbits;
+    vncFbstride[index] = pvfb->fb.paddedWidth;
+#else
+    vncFbptr[pScreen->myNum] = pbits;
+    vncFbstride[pScreen->myNum] = pvfb->fb.paddedWidth;
+#endif
+
+    miSetPixmapDepths();
+
+    switch (pvfb->fb.depth) {
+    case 8:
+       miSetVisualTypesAndMasks (8,
+                                 ((1 << StaticGray) |
+                                 (1 << GrayScale) |
+                                 (1 << StaticColor) |
+                                 (1 << PseudoColor) |
+                                 (1 << TrueColor) |
+                                 (1 << DirectColor)),
+                                 8, PseudoColor, 0, 0, 0);
+       break;
+    case 16:
+       miSetVisualTypesAndMasks (16,
+                                 ((1 << TrueColor) |
+                                 (1 << DirectColor)),
+                                 8, TrueColor, 0xf800, 0x07e0, 0x001f);
+       break;
+    case 24:
+       miSetVisualTypesAndMasks (24,
+                                 ((1 << TrueColor) |
+                                 (1 << DirectColor)),
+                                 8, TrueColor, 0xff0000, 0x00ff00, 0x0000ff);
+       break;
+    case 32:
+       miSetVisualTypesAndMasks (32,
+                                 ((1 << TrueColor) |
+                                 (1 << DirectColor)),
+                                 8, TrueColor, 0xff000000, 0x00ff0000, 0x0000ff00);
+       break;
+    default:
+       return FALSE;
+    }
+
+    ret = fbScreenInit(pScreen, pbits, pvfb->fb.width, pvfb->fb.height,
+                      dpi, dpi, pvfb->fb.paddedWidth, pvfb->fb.bitsPerPixel);
+  
+#ifdef RENDER
+    if (ret && Render) 
+       ret = fbPictureInit (pScreen, 0, 0);
+#endif
+
+    if (!ret) return FALSE;
+
+#if XORG < 110
+    miInitializeBackingStore(pScreen);
+#endif
+
+    /*
+     * Circumvent the backing store that was just initialised.  This amounts
+     * to a truely bizarre way of initialising SaveDoomedAreas and friends.
+     */
+
+    pScreen->InstallColormap = vfbInstallColormap;
+    pScreen->UninstallColormap = vfbUninstallColormap;
+    pScreen->ListInstalledColormaps = vfbListInstalledColormaps;
+
+    pScreen->SaveScreen = vfbSaveScreen;
+    
+    miPointerInitialize(pScreen, &vfbPointerSpriteFuncs, &vfbPointerCursorFuncs,
+                       FALSE);
+    
+    pScreen->blackPixel = pvfb->blackPixel;
+    pScreen->whitePixel = pvfb->whitePixel;
+
+    if (!pvfb->pixelFormatDefined) {
+       switch (pvfb->fb.depth) {
+       case 16:
+           pvfb->pixelFormatDefined = TRUE;
+           pvfb->rgbNotBgr = TRUE;
+           pvfb->blueBits = pvfb->redBits = 5;
+           pvfb->greenBits = 6;
+           break;
+       case 24:
+       case 32:
+           pvfb->pixelFormatDefined = TRUE;
+           pvfb->rgbNotBgr = TRUE;
+           pvfb->blueBits = pvfb->redBits = pvfb->greenBits = 8;
+           break;
+       }
+    }
+
+    if (pvfb->pixelFormatDefined) {
+       VisualPtr vis = pScreen->visuals;
+       for (int i = 0; i < pScreen->numVisuals; i++) {
+           if (pvfb->rgbNotBgr) {
+               vis->offsetBlue = 0;
+               vis->blueMask = (1 << pvfb->blueBits) - 1;
+               vis->offsetGreen = pvfb->blueBits;
+               vis->greenMask = ((1 << pvfb->greenBits) - 1) << vis->offsetGreen;
+               vis->offsetRed = vis->offsetGreen + pvfb->greenBits;
+               vis->redMask = ((1 << pvfb->redBits) - 1) << vis->offsetRed;
+           } else {
+               vis->offsetRed = 0;
+               vis->redMask = (1 << pvfb->redBits) - 1;
+               vis->offsetGreen = pvfb->redBits;
+               vis->greenMask = ((1 << pvfb->greenBits) - 1) << vis->offsetGreen;
+               vis->offsetBlue = vis->offsetGreen + pvfb->greenBits;
+               vis->blueMask = ((1 << pvfb->blueBits) - 1) << vis->offsetBlue;
+           }
+           vis++;
+       }
+    }
+    
+    ret = fbCreateDefColormap(pScreen);
+    if (!ret) return FALSE;
+
+    miSetZeroLineBias(pScreen, pvfb->lineBias);
+
+    pvfb->closeScreen = pScreen->CloseScreen;
+    pScreen->CloseScreen = vfbCloseScreen;
+
+#ifdef RANDR
+    rrScrPrivPtr rp;
+
+    ret = RRScreenInit(pScreen);
+    if (!ret) return FALSE;
+
+    rp = rrGetScrPriv(pScreen);
+
+    rp->rrGetInfo = vncRandRGetInfo;
+    rp->rrSetConfig = NULL;
+    rp->rrScreenSetSize = vncRandRScreenSetSize;
+    rp->rrCrtcSet = vncRandRCrtcSet;
+    rp->rrOutputValidateMode = vncRandROutputValidateMode;
+    rp->rrModeDestroy = vncRandRModeDestroy;
+
+    ret = vncRandRInit(pScreen);
+    if (!ret) return FALSE;
+#endif
+
+
+  return TRUE;
+
+} /* end vfbScreenInit */
+
+
+static void vfbClientStateChange(CallbackListPtr *a, void *b, void *c) {
+  dispatchException &= ~DE_RESET;
+}
+#if XORG >= 113
+#ifdef GLXEXT
+extern void GlxExtensionInit(void);
+
+static ExtensionModule glxExt = {
+    GlxExtensionInit,
+    "GLX",
+    &noGlxExtension
+};
+#endif
+#endif
+
+void
+InitOutput(ScreenInfo *screenInfo, int argc, char **argv)
+{
+    int i;
+    int NumFormats = 0;
+
+  ErrorF("\nXvnc %s - built %s\n%s", XVNCVERSION, buildtime, XVNCCOPYRIGHT);
+  ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE,
+         VENDOR_STRING);
+
+#if XORG >= 113
+#ifdef GLXEXT
+    if (serverGeneration == 1)
+#if XORG >= 116
+        LoadExtensionList(&glxExt, 1, TRUE);
+#else
+        LoadExtension(&glxExt, TRUE);
+#endif
+#endif
+#endif
+
+    /* initialize pixmap formats */
+
+    /* must have a pixmap depth to match every screen depth */
+    for (i = 0; i < vfbNumScreens; i++)
+    {
+       vfbPixmapDepths[vfbScreens[i].fb.depth] = TRUE;
+    }
+
+    /* RENDER needs a good set of pixmaps. */
+    if (Render) {
+       vfbPixmapDepths[1] = TRUE;
+       vfbPixmapDepths[4] = TRUE;
+       vfbPixmapDepths[8] = TRUE;
+/*     vfbPixmapDepths[15] = TRUE; */
+       vfbPixmapDepths[16] = TRUE;
+       vfbPixmapDepths[24] = TRUE;
+       vfbPixmapDepths[32] = TRUE;
+    }
+
+    for (i = 1; i <= 32; i++)
+    {
+       if (vfbPixmapDepths[i])
+       {
+           if (NumFormats >= MAXFORMATS)
+               FatalError ("MAXFORMATS is too small for this server\n");
+           screenInfo->formats[NumFormats].depth = i;
+           screenInfo->formats[NumFormats].bitsPerPixel = vfbBitsPerPixel(i);
+           screenInfo->formats[NumFormats].scanlinePad = BITMAP_SCANLINE_PAD;
+           NumFormats++;
+       }
+    }
+
+    screenInfo->imageByteOrder = IMAGE_BYTE_ORDER;
+    screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT;
+    screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD;
+    screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER;
+    screenInfo->numPixmapFormats = NumFormats;
+
+    /* initialize screens */
+
+    for (i = 0; i < vfbNumScreens; i++)
+    {
+       if (-1 == AddScreen(vfbScreenInit, argc, argv))
+       {
+           FatalError("Couldn't add screen %d", i);
+       }
+    }
+
+    if (!AddCallback(&ClientStateCallback, vfbClientStateChange, 0)) {
+       FatalError("AddCallback failed\n");
+    }
+} /* end InitOutput */
+
+/* this is just to get the server to link on AIX */
+#ifdef AIXV3
+int SelectWaitTime = 10000; /* usec */
+#endif
+
+void DDXRingBell(int percent, int pitch, int duration)
+{
+  if (percent > 0)
+    vncBell();
+}
+
+Bool LegalModifier(unsigned int key, DeviceIntPtr pDev)
+{
+  return TRUE;
+}
+
+void ProcessInputEvents()
+{
+  mieqProcessInputEvents();
+#if XORG == 15
+  miPointerUpdate();
+#endif
+}
+
+// InitInput is called after InitExtensions, so we're guaranteed that
+// vncExtensionInit() has already been called.
+
+void InitInput(int argc, char *argv[])
+{
+  mieqInit ();
+}
+
+#if XORG > 17
+void CloseInput(void)
+{
+}
+#endif
+
+void vncClientGone(int fd)
+{
+  if (fd == vncInetdSock) {
+    ErrorF("inetdSock client gone\n");
+    GiveUp(0);
+  }
+}
diff --git a/unix/xserver/hw/vnc/xvnc.cc b/unix/xserver/hw/vnc/xvnc.cc
deleted file mode 100644 (file)
index 0fd7b0c..0000000
+++ /dev/null
@@ -1,1724 +0,0 @@
-/* Copyright (c) 1993  X Consortium
-   Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
-   Copyright 2009 Pierre Ossman for Cendio AB
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
-OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of the X Consortium shall
-not be used in advertising or otherwise to promote the sale, use or
-other dealings in this Software without prior written authorization
-from the X Consortium.
-
-*/
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <rfb/Configuration.h>
-#include <rfb/Logger_stdio.h>
-#include <rfb/LogWriter.h>
-#include <network/TcpSocket.h>
-#include "vncExtInit.h"
-#include "xorg-version.h"
-
-extern "C" {
-#define class c_class
-#define public c_public
-#ifdef WIN32
-#include <X11/Xwinsock.h>
-#endif
-#include <stdio.h>
-#include <X11/X.h>
-#define NEED_EVENTS
-#include <X11/Xproto.h>
-#include <X11/Xos.h>
-#include "scrnintstr.h"
-#include "servermd.h"
-#include "fb.h"
-#include "mi.h"
-#if XORG < 114
-#include "mibstore.h"
-#endif
-#include "colormapst.h"
-#include "gcstruct.h"
-#include "input.h"
-#include "mipointer.h"
-#define new New
-#include "micmap.h"
-#undef new
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#ifndef WIN32
-#include <sys/param.h>
-#endif
-#include <X11/XWDFile.h>
-#ifdef HAS_SHM
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#endif /* HAS_SHM */
-#include "dix.h"
-#include "miline.h"
-#include "inputstr.h"
-#ifdef RANDR
-#include "randrstr.h"
-#endif /* RANDR */
-#include <X11/keysym.h>
-  extern char buildtime[];
-#if XORG >= 17
-#undef VENDOR_RELEASE
-#undef VENDOR_STRING
-#include "version-config.h"
-#endif
-#include "site.h"
-#undef class
-#undef public
-}
-
-#if XORG >= 110
-#define Xalloc malloc
-#define Xfree free
-#endif
-
-#define XVNCVERSION "TigerVNC 1.4.80"
-#define XVNCCOPYRIGHT ("Copyright (C) 1999-2013 TigerVNC Team and many others (see README.txt)\n" \
-                       "See http://www.tigervnc.org for information on TigerVNC.\n")
-
-
-extern int monitorResolution;
-
-#define VFB_DEFAULT_WIDTH  1024
-#define VFB_DEFAULT_HEIGHT 768
-#define VFB_DEFAULT_DEPTH  24
-#define VFB_DEFAULT_WHITEPIXEL 0xffffffff
-#define VFB_DEFAULT_BLACKPIXEL 0
-#define VFB_DEFAULT_LINEBIAS 0
-#define XWD_WINDOW_NAME_LEN 60
-
-typedef struct
-{
-    int width;
-    int height;
-
-    int depth;
-
-    /* Computed when allocated */
-
-    int paddedBytesWidth;
-    int paddedWidth;
-
-    int bitsPerPixel;
-
-    /* Private */
-
-    int sizeInBytes;
-
-    void *pfbMemory;
-
-#ifdef HAS_SHM
-    int shmid;
-#endif
-} vfbFramebufferInfo, *vfbFramebufferInfoPtr;
-
-typedef struct
-{
-    int scrnum;
-
-    Pixel blackPixel;
-    Pixel whitePixel;
-
-    unsigned int lineBias;
-
-    CloseScreenProcPtr closeScreen;
-
-    vfbFramebufferInfo fb;
-
-    Bool pixelFormatDefined;
-    Bool rgbNotBgr;
-    int redBits, greenBits, blueBits;
-} vfbScreenInfo, *vfbScreenInfoPtr;
-
-static int vfbNumScreens;
-static vfbScreenInfo vfbScreens[MAXSCREENS];
-static Bool vfbPixmapDepths[33];
-typedef enum { NORMAL_MEMORY_FB, SHARED_MEMORY_FB } fbMemType;
-static fbMemType fbmemtype = NORMAL_MEMORY_FB;
-static int lastScreen = -1;
-static Bool Render = TRUE;
-
-static bool displaySpecified = false;
-static char displayNumStr[16];
-
-char *listenaddr = NULL;
-
-static int vncVerbose = DEFAULT_LOG_VERBOSITY;
-
-
-static void
-vfbInitializePixmapDepths(void)
-{
-    int i;
-    vfbPixmapDepths[1] = TRUE; /* always need bitmaps */
-    for (i = 2; i <= 32; i++)
-       vfbPixmapDepths[i] = FALSE;
-}
-
-static void
-vfbInitializeDefaultScreens(void)
-{
-    int i;
-
-    for (i = 0; i < MAXSCREENS; i++)
-    {
-       vfbScreens[i].scrnum = i;
-       vfbScreens[i].blackPixel = VFB_DEFAULT_BLACKPIXEL;
-       vfbScreens[i].whitePixel = VFB_DEFAULT_WHITEPIXEL;
-       vfbScreens[i].lineBias = VFB_DEFAULT_LINEBIAS;
-       vfbScreens[i].fb.width  = VFB_DEFAULT_WIDTH;
-       vfbScreens[i].fb.height = VFB_DEFAULT_HEIGHT;
-       vfbScreens[i].fb.pfbMemory = NULL;
-       vfbScreens[i].fb.depth  = VFB_DEFAULT_DEPTH;
-       vfbScreens[i].pixelFormatDefined = FALSE;
-    }
-    vfbNumScreens = 1;
-}
-
-static int
-vfbBitsPerPixel(int depth)
-{
-    if (depth == 1) return 1;
-    else if (depth <= 8) return 8;
-    else if (depth <= 16) return 16;
-    else return 32;
-}
-
-static void vfbFreeFramebufferMemory(vfbFramebufferInfoPtr pfb);
-
-extern "C" {
-
-#ifdef DPMSExtension
-    /* Why support DPMS? Because stupid modern desktop environments
-       such as Unity 2D on Ubuntu 11.10 crashes if DPMS is not
-       available. (DPMSSet is called by dpms.c, but the return value
-       is ignored.) */
-int DPMSSet(ClientPtr client, int level)
-{
-    return Success;
-}
-
-Bool DPMSSupported()
-{
-    /* Causes DPMSCapable to return false, meaning no devices are DPMS
-       capable */
-    return FALSE;
-}
-#endif
-
-#if XORG < 111
-void ddxGiveUp()
-#else
-void ddxGiveUp(enum ExitCode error)
-#endif
-{
-    int i;
-
-    /* clean up the framebuffers */
-    for (i = 0; i < vfbNumScreens; i++)
-        vfbFreeFramebufferMemory(&vfbScreens[i].fb);
-}
-
-void
-#if XORG < 111
-AbortDDX()
-#else
-AbortDDX(enum ExitCode error)
-#endif
-{
-#if XORG < 111
-    ddxGiveUp();
-#else
-    ddxGiveUp(error);
-#endif
-}
-
-#ifdef __DARWIN__
-void
-DarwinHandleGUI(int argc, char *argv[])
-{
-}
-
-void GlxExtensionInit();
-void GlxWrapInitVisuals(void *procPtr);
-
-void
-DarwinGlxExtensionInit()
-{
-    GlxExtensionInit();
-}
-
-void
-DarwinGlxWrapInitVisuals(
-    void *procPtr)
-{
-    GlxWrapInitVisuals(procPtr);
-}
-#endif
-
-void
-OsVendorInit()
-{
-}
-
-void
-#if XORG < 113
-OsVendorFatalError()
-#else
-OsVendorFatalError(const char *f, va_list args)
-#endif
-{
-}
-
-void ddxBeforeReset(void)
-{
-    return;
-}
-
-void 
-ddxUseMsg()
-{
-    ErrorF("\nXvnc %s - built %s\n%s", XVNCVERSION, buildtime, XVNCCOPYRIGHT);
-    ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE,
-           VENDOR_STRING);
-    ErrorF("-screen scrn WxHxD     set screen's width, height, depth\n");
-    ErrorF("-pixdepths list-of-int support given pixmap depths\n");
-#ifdef RENDER
-    ErrorF("+/-render             turn on/off RENDER extension support"
-          "(default on)\n");
-#endif
-    ErrorF("-linebias n            adjust thin line pixelization\n");
-    ErrorF("-blackpixel n          pixel value for black\n");
-    ErrorF("-whitepixel n          pixel value for white\n");
-
-#ifdef HAS_SHM
-    ErrorF("-shmem                 put framebuffers in shared memory\n");
-#endif
-
-    ErrorF("-geometry WxH          set screen 0's width, height\n");
-    ErrorF("-depth D               set screen 0's depth\n");
-    ErrorF("-pixelformat fmt       set pixel format (rgbNNN or bgrNNN)\n");
-    ErrorF("-inetd                 has been launched from inetd\n");
-    ErrorF("-interface IP_address  listen on specified interface\n");
-    ErrorF("-noclipboard           disable clipboard settings modification via vncconfig utility\n");
-    ErrorF("-verbose [n]           verbose startup messages\n");
-    ErrorF("-quiet                 minimal startup messages\n");
-    ErrorF("\nVNC parameters:\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"
-            "Other valid forms are <param>=<value> -<param>=<value> "
-            "--<param>=<value>\n"
-            "Parameter names are case-insensitive.  The parameters are:\n\n");
-    rfb::Configuration::listParams(79, 14);
-  }
-}
-
-/* ddxInitGlobals - called by |InitGlobals| from os/util.c */
-void ddxInitGlobals(void)
-{
-}
-
-static 
-bool displayNumFree(int num)
-{
-    try {
-       network::TcpListener l(NULL, 6000+num);
-    } catch (rdr::Exception& e) {
-       return false;
-    }
-    char file[256];
-    sprintf(file, "/tmp/.X%d-lock", num);
-    if (access(file, F_OK) == 0) return false;
-    sprintf(file, "/tmp/.X11-unix/X%d", num);
-    if (access(file, F_OK) == 0) return false;
-    sprintf(file, "/usr/spool/sockets/X11/%d", num);
-    if (access(file, F_OK) == 0) return false;
-    return true;
-}
-
-int 
-ddxProcessArgument(int argc, char *argv[], int i)
-{
-    static Bool firstTime = TRUE;
-
-    if (firstTime)
-    {
-       vfbInitializeDefaultScreens();
-       vfbInitializePixmapDepths();
-       firstTime = FALSE;
-       rfb::initStdIOLoggers();
-       rfb::LogWriter::setLogParams("*:stderr:30");
-       rfb::Configuration::enableServerParams();
-    }
-
-    if (argv[i][0] ==  ':')
-       displaySpecified = true;
-
-    if (strcmp (argv[i], "-screen") == 0)      /* -screen n WxHxD */
-    {
-       int screenNum;
-       if (i + 2 >= argc) UseMsg();
-       screenNum = atoi(argv[i+1]);
-       if (screenNum < 0 || screenNum >= MAXSCREENS)
-       {
-           ErrorF("Invalid screen number %d\n", screenNum);
-           UseMsg();
-       }
-       if (3 != sscanf(argv[i+2], "%dx%dx%d",
-                       &vfbScreens[screenNum].fb.width,
-                       &vfbScreens[screenNum].fb.height,
-                       &vfbScreens[screenNum].fb.depth))
-       {
-           ErrorF("Invalid screen configuration %s\n", argv[i+2]);
-           UseMsg();
-       }
-
-       if (screenNum >= vfbNumScreens)
-           vfbNumScreens = screenNum + 1;
-       lastScreen = screenNum;
-       return 3;
-    }
-
-    if (strcmp (argv[i], "-pixdepths") == 0)   /* -pixdepths list-of-depth */
-    {
-       int depth, ret = 1;
-
-       if (++i >= argc) UseMsg();
-       while ((i < argc) && (depth = atoi(argv[i++])) != 0)
-       {
-           if (depth < 0 || depth > 32)
-           {
-               ErrorF("Invalid pixmap depth %d\n", depth);
-               UseMsg();
-           }
-           vfbPixmapDepths[depth] = TRUE;
-           ret++;
-       }
-       return ret;
-    }
-    
-    if (strcmp (argv[i], "+render") == 0)      /* +render */
-    {
-       Render = TRUE;
-       return 1;
-    }
-  
-    if (strcmp (argv[i], "-render") == 0)      /* -render */
-    {
-       Render = FALSE;
-       return 1;
-    }
-
-    if (strcmp (argv[i], "-blackpixel") == 0)  /* -blackpixel n */
-    {
-       Pixel pix;
-       if (++i >= argc) UseMsg();
-       pix = atoi(argv[i]);
-       if (-1 == lastScreen)
-       {
-           int i;
-           for (i = 0; i < MAXSCREENS; i++)
-           {
-               vfbScreens[i].blackPixel = pix;
-           }
-       }
-       else
-       {
-           vfbScreens[lastScreen].blackPixel = pix;
-       }
-       return 2;
-    }
-
-    if (strcmp (argv[i], "-whitepixel") == 0)  /* -whitepixel n */
-    {
-       Pixel pix;
-       if (++i >= argc) UseMsg();
-       pix = atoi(argv[i]);
-       if (-1 == lastScreen)
-       {
-           int i;
-           for (i = 0; i < MAXSCREENS; i++)
-           {
-               vfbScreens[i].whitePixel = pix;
-           }
-       }
-       else
-       {
-           vfbScreens[lastScreen].whitePixel = pix;
-       }
-       return 2;
-    }
-    
-    if (strcmp (argv[i], "-linebias") == 0)    /* -linebias n */
-    {
-       unsigned int linebias;
-       if (++i >= argc) UseMsg();
-       linebias = atoi(argv[i]);
-       if (-1 == lastScreen)
-       {
-           int i;
-           for (i = 0; i < MAXSCREENS; i++)
-           {
-               vfbScreens[i].lineBias = linebias;
-           }
-       }
-       else
-       {
-           vfbScreens[lastScreen].lineBias = linebias;
-       }
-       return 2;
-    }
-
-#ifdef HAS_SHM
-    if (strcmp (argv[i], "-shmem") == 0)       /* -shmem */
-    {
-       fbmemtype = SHARED_MEMORY_FB;
-       return 1;
-    }
-#endif
-    
-    if (strcmp(argv[i], "-geometry") == 0)
-    {
-       if (++i >= argc) UseMsg();
-       if (sscanf(argv[i],"%dx%d",&vfbScreens[0].fb.width,
-                  &vfbScreens[0].fb.height) != 2) {
-           ErrorF("Invalid geometry %s\n", argv[i]);
-           UseMsg();
-       }
-       return 2;
-    }
-    
-    if (strcmp(argv[i], "-depth") == 0)
-    {
-       if (++i >= argc) UseMsg();
-       vfbScreens[0].fb.depth = atoi(argv[i]);
-       return 2;
-    }
-
-    if (strcmp(argv[i], "-pixelformat") == 0)
-    {
-       char rgbbgr[4];
-       int bits1, bits2, bits3;
-       if (++i >= argc) UseMsg();
-       if (sscanf(argv[i], "%3s%1d%1d%1d", rgbbgr,&bits1,&bits2,&bits3) < 4) {
-           ErrorF("Invalid pixel format %s\n", argv[i]);
-           UseMsg();
-       }
-
-#define SET_PIXEL_FORMAT(vfbScreen)                     \
-    (vfbScreen).pixelFormatDefined = TRUE;              \
-    (vfbScreen).fb.depth = bits1 + bits2 + bits3;          \
-    (vfbScreen).greenBits = bits2;                      \
-    if (strcasecmp(rgbbgr, "bgr") == 0) {               \
-        (vfbScreen).rgbNotBgr = FALSE;                  \
-        (vfbScreen).redBits = bits3;                    \
-        (vfbScreen).blueBits = bits1;                   \
-    } else if (strcasecmp(rgbbgr, "rgb") == 0) {        \
-        (vfbScreen).rgbNotBgr = TRUE;                   \
-        (vfbScreen).redBits = bits1;                    \
-        (vfbScreen).blueBits = bits3;                   \
-    } else {                                            \
-        ErrorF("Invalid pixel format %s\n", argv[i]);   \
-        UseMsg();                                       \
-    }
-
-       if (-1 == lastScreen)
-       {
-           int i;
-           for (i = 0; i < MAXSCREENS; i++)
-           {
-               SET_PIXEL_FORMAT(vfbScreens[i]);
-           }
-       }
-       else
-       {
-           SET_PIXEL_FORMAT(vfbScreens[lastScreen]);
-       }
-
-       return 2;
-    }
-
-    if (strcmp(argv[i], "-inetd") == 0)
-    {
-       dup2(0,3);
-       vncInetdSock = 3;
-       close(2);
-       
-       if (!displaySpecified) {
-           int port = network::TcpSocket::getSockPort(vncInetdSock);
-           int displayNum = port - 5900;
-           if (displayNum < 0 || displayNum > 99 || !displayNumFree(displayNum)) {
-               for (displayNum = 1; displayNum < 100; displayNum++)
-                   if (displayNumFree(displayNum)) break;
-               
-               if (displayNum == 100)
-                   FatalError("Xvnc error: no free display number for -inetd");
-           }
-           
-           display = displayNumStr;
-           sprintf(displayNumStr, "%d", displayNum);
-       }
-       
-       return 1;
-    }
-
-    if (strcmp(argv[i], "-interface") == 0 ||
-       strcmp(argv[i], "-i") == 0) {
-       if (++i >= argc) {
-           UseMsg();
-           return 2;
-       }
-
-       if (listenaddr != NULL) /* Only first -interface is valid */
-               return 2;
-
-       listenaddr = strdup(argv[i]);
-       if (listenaddr == NULL)
-           FatalError("Not enough memory");
-
-       return 2;
-    }
-
-    if (strcmp(argv[i], "-noclipboard") == 0) {
-       noclipboard = true;
-       return 1;
-    }
-
-    if (!strcmp(argv[i], "-verbose")) {
-        if (++i < argc && argv[i]) {
-            char *end;
-            long val;
-
-            val = strtol(argv[i], &end, 0);
-            if (*end == '\0') {
-                vncVerbose = val;
-                LogSetParameter(XLOG_VERBOSITY, vncVerbose);
-                return 2;
-            }
-        }
-        vncVerbose++;
-        LogSetParameter(XLOG_VERBOSITY, vncVerbose);
-        return 1;
-    }
-
-    if (!strcmp(argv[i], "-quiet")) {
-        vncVerbose = -1;
-        LogSetParameter(XLOG_VERBOSITY, vncVerbose);
-        return 1;
-    }
-
-    if (rfb::Configuration::setParam(argv[i]))
-       return 1;
-    
-    if (argv[i][0] == '-' && i+1 < argc) {
-       if (rfb::Configuration::setParam(&argv[i][1], argv[i+1]))
-           return 2;
-    }
-    
-    return 0;
-}
-
-#ifdef DDXTIME /* from ServerOSDefines */
-CARD32
-GetTimeInMillis()
-{
-    struct timeval  tp;
-
-    X_GETTIMEOFDAY(&tp);
-    return(tp.tv_sec * 1000) + (tp.tv_usec / 1000);
-}
-#endif
-
-#if XORG < 113
-static ColormapPtr InstalledMaps[MAXSCREENS];
-#else
-static DevPrivateKeyRec cmapScrPrivateKeyRec;
-#define cmapScrPrivateKey (&cmapScrPrivateKeyRec)
-#define GetInstalledColormap(s) ((ColormapPtr) dixLookupPrivate(&(s)->devPrivates, cmapScrPrivateKey))
-#define SetInstalledColormap(s,c) (dixSetPrivate(&(s)->devPrivates, cmapScrPrivateKey, c))
-#endif
-
-static int 
-vfbListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps)
-{
-    /* By the time we are processing requests, we can guarantee that there
-     * is always a colormap installed */
-#if XORG < 113
-    *pmaps = InstalledMaps[pScreen->myNum]->mid;
-#else
-    *pmaps = GetInstalledColormap(pScreen)->mid;
-#endif
-    return (1);
-}
-
-
-static void 
-vfbInstallColormap(ColormapPtr pmap)
-{
-#if XORG < 113
-    int index = pmap->pScreen->myNum;
-#endif
-    ColormapPtr oldpmap;
-
-#if XORG < 113
-    oldpmap = InstalledMaps[index];
-#else
-    oldpmap = GetInstalledColormap(pmap->pScreen);
-#endif
-
-    if (pmap != oldpmap)
-    {
-       int entries;
-       VisualPtr pVisual;
-       Pixel *     ppix;
-       xrgb *      prgb;
-       xColorItem *defs;
-       int i;
-
-       if(oldpmap != (ColormapPtr)None)
-           WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid);
-       /* Install pmap */
-#if XORG < 113
-       InstalledMaps[index] = pmap;
-#else
-       SetInstalledColormap(pmap->pScreen, pmap);
-#endif
-       WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid);
-
-       entries = pmap->pVisual->ColormapEntries;
-       pVisual = pmap->pVisual;
-
-       ppix = (Pixel *)xalloc(entries * sizeof(Pixel));
-       prgb = (xrgb *)xalloc(entries * sizeof(xrgb));
-       defs = (xColorItem *)xalloc(entries * sizeof(xColorItem));
-
-       for (i = 0; i < entries; i++)  ppix[i] = i;
-       /* XXX truecolor */
-#if XORG < 19
-       QueryColors(pmap, entries, ppix, prgb);
-#else
-       QueryColors(pmap, entries, ppix, prgb, serverClient);
-#endif
-
-       for (i = 0; i < entries; i++) { /* convert xrgbs to xColorItems */
-           defs[i].pixel = ppix[i] & 0xff; /* change pixel to index */
-           defs[i].red = prgb[i].red;
-           defs[i].green = prgb[i].green;
-           defs[i].blue = prgb[i].blue;
-           defs[i].flags =  DoRed|DoGreen|DoBlue;
-       }
-       (*pmap->pScreen->StoreColors)(pmap, entries, defs);
-       
-       xfree(ppix);
-       xfree(prgb);
-       xfree(defs);
-    }
-}
-
-static void
-vfbUninstallColormap(ColormapPtr pmap)
-{
-#if XORG < 113
-    ColormapPtr curpmap = InstalledMaps[pmap->pScreen->myNum];
-#else
-    ColormapPtr curpmap = GetInstalledColormap(pmap->pScreen);
-#endif
-
-    if(pmap == curpmap)
-    {
-       if (pmap->mid != pmap->pScreen->defColormap)
-       {
-#if XORG < 111
-           curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
-                                                  RT_COLORMAP);
-#else
-           dixLookupResourceByType((void * *) &curpmap, pmap->pScreen->defColormap,
-                                   RT_COLORMAP, serverClient, DixUnknownAccess);
-#endif
-           (*pmap->pScreen->InstallColormap)(curpmap);
-       }
-    }
-}
-
-static Bool
-vfbSaveScreen(ScreenPtr pScreen, int on)
-{
-    return TRUE;
-}
-
-#ifdef HAS_SHM
-static void
-vfbAllocateSharedMemoryFramebuffer(vfbFramebufferInfoPtr pfb)
-{
-    /* create the shared memory segment */
-
-    pfb->shmid = shmget(IPC_PRIVATE, pfb->sizeInBytes, IPC_CREAT|0777);
-    if (pfb->shmid < 0) {
-        perror("shmget");
-        ErrorF("shmget %d bytes failed, errno %d", pfb->sizeInBytes, errno);
-        return;
-    }
-
-    /* try to attach it */
-
-    pfb->pfbMemory = shmat(pfb->shmid, 0, 0);
-    if (-1 == (long)pfb->pfbMemory) {
-        perror("shmat");
-        ErrorF("shmat failed, errno %d", errno);
-        pfb->pfbMemory = NULL; 
-        return;
-    }
-}
-#endif /* HAS_SHM */
-
-
-static void *
-vfbAllocateFramebufferMemory(vfbFramebufferInfoPtr pfb)
-{
-    if (pfb->pfbMemory != NULL)
-        return pfb->pfbMemory; /* already done */
-
-    /* Compute memory layout */
-    pfb->paddedBytesWidth = PixmapBytePad(pfb->width, pfb->depth);
-    pfb->bitsPerPixel = vfbBitsPerPixel(pfb->depth);
-    pfb->paddedWidth = pfb->paddedBytesWidth * 8 / pfb->bitsPerPixel;
-    pfb->sizeInBytes = pfb->paddedBytesWidth * pfb->height;
-
-    /* And allocate buffer */
-    switch (fbmemtype) {
-#ifdef HAS_SHM
-    case SHARED_MEMORY_FB:
-        vfbAllocateSharedMemoryFramebuffer(pfb);
-        break;
-#else
-    case SHARED_MEMORY_FB:
-        break;
-#endif
-    case NORMAL_MEMORY_FB:
-        pfb->pfbMemory = Xalloc(pfb->sizeInBytes);
-        break;
-    }
-
-    /* This will be NULL if any of the above failed */
-    return pfb->pfbMemory;
-}
-
-static void
-vfbFreeFramebufferMemory(vfbFramebufferInfoPtr pfb)
-{
-    if ((pfb == NULL) || (pfb->pfbMemory == NULL))
-        return;
-
-    switch (fbmemtype) {
-#ifdef HAS_SHM
-    case SHARED_MEMORY_FB:
-        if (-1 == shmdt(pfb->pfbMemory)) {
-            perror("shmdt");
-            ErrorF("shmdt failed, errno %d", errno);
-        }
-        break;
-#else /* HAS_SHM */
-    case SHARED_MEMORY_FB:
-        break;
-#endif /* HAS_SHM */
-    case NORMAL_MEMORY_FB:
-        Xfree(pfb->pfbMemory);
-        break;
-    }
-
-    pfb->pfbMemory = NULL;
-}
-
-static Bool
-vfbCursorOffScreen (ScreenPtr *ppScreen, int *x, int *y)
-{
-    return FALSE;
-}
-
-static void
-vfbCrossScreen (ScreenPtr pScreen, Bool entering)
-{
-}
-
-static Bool vfbRealizeCursor(
-#if XORG >= 16
-                            DeviceIntPtr pDev,
-#endif
-                            ScreenPtr pScreen, CursorPtr pCursor) {
-    return TRUE;
-}
-
-static Bool vfbUnrealizeCursor(
-#if XORG >= 16
-                              DeviceIntPtr pDev,
-#endif
-                              ScreenPtr pScreen, CursorPtr pCursor) {
-    return TRUE;
-}
-
-static void vfbSetCursor(
-#if XORG >= 16
-                        DeviceIntPtr pDev,
-#endif
-                        ScreenPtr pScreen, CursorPtr pCursor, int x, int y) 
-{
-}
-
-static void vfbMoveCursor(
-#if XORG >= 16
-                         DeviceIntPtr pDev,
-#endif
-                         ScreenPtr pScreen, int x, int y) 
-{
-}
-
-#if XORG >= 16
-static Bool
-vfbDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScreen)
-{   
-    return TRUE;
-}
-
-static void
-vfbDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScreen)
-{ 
-}
-#endif
-
-static miPointerSpriteFuncRec vfbPointerSpriteFuncs = {
-    vfbRealizeCursor,
-    vfbUnrealizeCursor,
-    vfbSetCursor,
-    vfbMoveCursor
-#if XORG >= 16
-    , vfbDeviceCursorInitialize,
-    vfbDeviceCursorCleanup
-#endif
-};
-
-static miPointerScreenFuncRec vfbPointerCursorFuncs = {
-    vfbCursorOffScreen,
-    vfbCrossScreen,
-    miPointerWarpCursor
-};
-
-#ifdef RANDR
-
-static Bool vncRandRGetInfo (ScreenPtr pScreen, Rotation *rotations)
-{
-  // We update all information right away, so there is nothing to
-  // do here.
-  return TRUE;
-}
-
-/* from hw/xfree86/common/xf86Helper.c */
-
-#include "mivalidate.h"
-static void
-xf86SetRootClip (ScreenPtr pScreen, Bool enable)
-{
-#if XORG < 19
-    WindowPtr  pWin = WindowTable[pScreen->myNum];
-#else
-    WindowPtr  pWin = pScreen->root;
-#endif
-    WindowPtr  pChild;
-    Bool       WasViewable = (Bool)(pWin->viewable);
-    Bool       anyMarked = FALSE;
-#if XORG < 110
-    RegionPtr  pOldClip = NULL, bsExposed;
-#ifdef DO_SAVE_UNDERS
-    Bool       dosave = FALSE;
-#endif
-#endif
-    WindowPtr   pLayerWin;
-    BoxRec     box;
-
-    if (WasViewable)
-    {
-       for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
-       {
-           (void) (*pScreen->MarkOverlappedWindows)(pChild,
-                                                    pChild,
-                                                    &pLayerWin);
-       }
-       (*pScreen->MarkWindow) (pWin);
-       anyMarked = TRUE;
-       if (pWin->valdata)
-       {
-           if (HasBorder (pWin))
-           {
-               RegionPtr       borderVisible;
-
-               borderVisible = REGION_CREATE(pScreen, NullBox, 1);
-               REGION_SUBTRACT(pScreen, borderVisible,
-                               &pWin->borderClip, &pWin->winSize);
-               pWin->valdata->before.borderVisible = borderVisible;
-           }
-           pWin->valdata->before.resized = TRUE;
-       }
-    }
-    
-    /*
-     * Use REGION_BREAK to avoid optimizations in ValidateTree
-     * that assume the root borderClip can't change well, normally
-     * it doesn't...)
-     */
-    if (enable)
-    {
-       box.x1 = 0;
-       box.y1 = 0;
-       box.x2 = pScreen->width;
-       box.y2 = pScreen->height;
-       REGION_INIT (pScreen, &pWin->winSize, &box, 1);
-       REGION_INIT (pScreen, &pWin->borderSize, &box, 1);
-       if (WasViewable)
-           REGION_RESET(pScreen, &pWin->borderClip, &box);
-       pWin->drawable.width = pScreen->width;
-       pWin->drawable.height = pScreen->height;
-        REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
-    }
-    else
-    {
-       REGION_EMPTY(pScreen, &pWin->borderClip);
-       REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList);
-    }
-    
-    ResizeChildrenWinSize (pWin, 0, 0, 0, 0);
-    
-    if (WasViewable)
-    {
-#if XORG < 110
-       if (pWin->backStorage)
-       {
-           pOldClip = REGION_CREATE(pScreen, NullBox, 1);
-           REGION_COPY(pScreen, pOldClip, &pWin->clipList);
-       }
-#endif
-
-       if (pWin->firstChild)
-       {
-           anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild,
-                                                          pWin->firstChild,
-                                                          (WindowPtr *)NULL);
-       }
-       else
-       {
-           (*pScreen->MarkWindow) (pWin);
-           anyMarked = TRUE;
-       }
-
-#if XORG < 110 && defined(DO_SAVE_UNDERS)
-       if (DO_SAVE_UNDERS(pWin))
-       {
-           dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin);
-       }
-#endif /* DO_SAVE_UNDERS */
-
-       if (anyMarked)
-           (*pScreen->ValidateTree)(pWin, NullWindow, VTOther);
-    }
-
-#if XORG < 110
-    if (pWin->backStorage &&
-       ((pWin->backingStore == Always) || WasViewable))
-    {
-       if (!WasViewable)
-           pOldClip = &pWin->clipList; /* a convenient empty region */
-       bsExposed = (*pScreen->TranslateBackingStore)
-                            (pWin, 0, 0, pOldClip,
-                             pWin->drawable.x, pWin->drawable.y);
-       if (WasViewable)
-           REGION_DESTROY(pScreen, pOldClip);
-       if (bsExposed)
-       {
-           RegionPtr   valExposed = NullRegion;
-    
-           if (pWin->valdata)
-               valExposed = &pWin->valdata->after.exposed;
-           (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
-           if (valExposed)
-               REGION_EMPTY(pScreen, valExposed);
-           REGION_DESTROY(pScreen, bsExposed);
-       }
-    }
-#endif
-    if (WasViewable)
-    {
-       if (anyMarked)
-           (*pScreen->HandleExposures)(pWin);
-
-#if XORG < 110 && defined(DO_SAVE_UNDERS)
-       if (dosave)
-           (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin);
-#endif /* DO_SAVE_UNDERS */
-       if (anyMarked && pScreen->PostValidateTree)
-           (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther);
-    }
-    if (pWin->realized)
-       WindowsRestructured ();
-    FlushAllOutput ();
-}
-
-RRModePtr vncRandRModeGet(int width, int height);
-static Bool vncRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode,
-                            int x, int y, Rotation rotation, int num_outputs,
-                            RROutputPtr *outputs);
-
-static Bool vncRandRScreenSetSize(ScreenPtr pScreen,
-                                  CARD16 width, CARD16 height,
-                                  CARD32 mmWidth, CARD32 mmHeight)
-{
-    vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
-    vfbFramebufferInfo fb;
-    rrScrPrivPtr rp = rrGetScrPriv(pScreen);
-    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
-    void *pbits;
-    Bool ret;
-    int oldwidth, oldheight, oldmmWidth, oldmmHeight;
-
-    /* Prevent updates while we fiddle */
-    xf86SetRootClip(pScreen, FALSE);
-
-    /* Store current state in case we fail */
-    oldwidth = pScreen->width;
-    oldheight = pScreen->height;
-    oldmmWidth = pScreen->mmWidth;
-    oldmmHeight = pScreen->mmHeight;
-
-    /* Then set the new dimensions */
-    pScreen->width = width;
-    pScreen->height = height;
-    pScreen->mmWidth = mmWidth;
-    pScreen->mmHeight = mmHeight;
-
-    /* Allocate a new framebuffer */
-    memset(&fb, 0, sizeof(vfbFramebufferInfo));
-
-    fb.width = pScreen->width;
-    fb.height = pScreen->height;
-    fb.depth = pvfb->fb.depth;
-
-    pbits = vfbAllocateFramebufferMemory(&fb);
-    if (!pbits) {
-        /* Allocation failed. Restore old state */
-        pScreen->width = oldwidth;
-        pScreen->height = oldheight;
-        pScreen->mmWidth = oldmmWidth;
-        pScreen->mmHeight = oldmmHeight;
-
-        xf86SetRootClip(pScreen, TRUE);
-
-        return FALSE;
-    }
-
-    /* Update root pixmap with the new dimensions and buffer */
-    ret = pScreen->ModifyPixmapHeader(rootPixmap, fb.width, fb.height,
-                                      -1, -1, fb.paddedBytesWidth, pbits);
-    if (!ret) {
-        /* Update failed. Free the new framebuffer and restore old state */
-        vfbFreeFramebufferMemory(&fb);
-
-        pScreen->width = oldwidth;
-        pScreen->height = oldheight;
-        pScreen->mmWidth = oldmmWidth;
-        pScreen->mmHeight = oldmmHeight;
-
-        xf86SetRootClip(pScreen, TRUE);
-
-        return FALSE;
-    }
-
-    /* Free the old framebuffer and keep the info about the new one */
-    vfbFreeFramebufferMemory(&pvfb->fb);
-    memcpy(&pvfb->fb, &fb, sizeof(vfbFramebufferInfo));
-
-    /* Let VNC get the new framebuffer (actual update is in vncHooks.cc) */
-    vncFbptr[pScreen->myNum] = pbits;
-    vncFbstride[pScreen->myNum] = fb.paddedWidth;
-
-    /* Restore ability to update screen, now with new dimensions */
-    xf86SetRootClip(pScreen, TRUE);
-
-    /*
-     * Let RandR know we changed something (it doesn't assume that
-     * TRUE means something changed for some reason...).
-     */
-    RRScreenSizeNotify(pScreen);
-
-    /* Crop all CRTCs to the new screen */
-    for (int i = 0;i < rp->numCrtcs;i++) {
-        RRCrtcPtr crtc;
-        RRModePtr mode;
-
-        crtc = rp->crtcs[i];
-
-        /* Disabled? */
-        if (crtc->mode == NULL)
-            continue;
-
-        /* Fully inside? */
-        if ((crtc->x + crtc->mode->mode.width <= width) &&
-            (crtc->y + crtc->mode->mode.height <= height))
-            continue;
-
-        /* Fully outside? */
-        if ((crtc->x >= width) || (crtc->y >= height)) {
-            /* Disable it */
-            ret = vncRandRCrtcSet(pScreen, crtc, NULL,
-                                  crtc->x, crtc->y, crtc->rotation, 0, NULL);
-            if (!ret)
-                ErrorF("Warning: Unable to disable CRTC that is outside of new screen dimensions");
-            continue;
-        }
-
-        /* Just needs to be resized */
-        mode = vncRandRModeGet(width - crtc->x, height - crtc->y);
-        if (mode == NULL) {
-            ErrorF("Warning: Unable to create custom mode for %dx%d",
-                   width - crtc->x, height - crtc->y);
-            continue;
-        }
-
-        ret = vncRandRCrtcSet(pScreen, crtc, mode,
-                              crtc->x, crtc->y, crtc->rotation,
-                              crtc->numOutputs, crtc->outputs);
-        RRModeDestroy(mode);
-        if (!ret)
-            ErrorF("Warning: Unable to crop CRTC to new screen dimensions");
-    }
-
-    return TRUE;
-}
-
-static Bool vncRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode,
-                            int x, int y, Rotation rotation, int num_outputs,
-                            RROutputPtr *outputs)
-{
-    Bool ret;
-    int i;
-
-    /*
-     * Some applications get confused by a connected output without a
-     * mode or CRTC, so we need to fiddle with the connection state as well.
-     */
-    for (i = 0;i < crtc->numOutputs;i++)
-        RROutputSetConnection(crtc->outputs[i], RR_Disconnected);
-
-    for (i = 0;i < num_outputs;i++) {
-        if (mode != NULL)
-            RROutputSetConnection(outputs[i], RR_Connected);
-        else
-            RROutputSetConnection(outputs[i], RR_Disconnected);
-    }
-
-    /* Let RandR know we approve, and let it update its internal state */
-    ret = RRCrtcNotify(crtc, mode, x, y, rotation,
-#if XORG >= 16
-                       NULL,
-#endif
-                       num_outputs, outputs);
-    if (!ret)
-        return FALSE;
-
-    return TRUE;
-}
-
-static Bool vncRandROutputValidateMode(ScreenPtr pScreen,
-                                       RROutputPtr output, RRModePtr mode)
-{
-    /* We have no hardware so any mode works */
-    return TRUE;
-}
-
-static void vncRandRModeDestroy(ScreenPtr pScreen, RRModePtr mode)
-{
-    /* We haven't allocated anything so nothing to destroy */
-}
-
-static const int vncRandRWidths[] =  { 1920, 1920, 1600, 1680, 1400, 1360, 1280, 1280, 1280, 1280, 1024, 800, 640 };
-static const int vncRandRHeights[] = { 1200, 1080, 1200, 1050, 1050,  768, 1024,  960,  800,  720,  768, 600, 480 };
-
-static int vncRandRIndex = 0;
-
-/* This is a global symbol since XserverDesktop also uses it */
-RRModePtr vncRandRModeGet(int width, int height)
-{
-    xRRModeInfo        modeInfo;
-    char name[100];
-    RRModePtr mode;
-
-    memset(&modeInfo, 0, sizeof(modeInfo));
-    sprintf(name, "%dx%d", width, height);
-    
-    modeInfo.width = width;
-    modeInfo.height = height;
-    modeInfo.hTotal = width;
-    modeInfo.vTotal = height;
-    modeInfo.dotClock = ((CARD32)width * (CARD32)height * 60);
-    modeInfo.nameLength = strlen(name);
-    mode = RRModeGet(&modeInfo, name);
-    if (mode == NULL)
-        return NULL;
-
-    return mode;
-}
-
-static RRCrtcPtr vncRandRCrtcCreate(ScreenPtr pScreen)
-{
-    RRCrtcPtr crtc;
-    RROutputPtr output;
-    RRModePtr mode;
-    char name[100];
-
-    /* First we create the CRTC... */
-    crtc = RRCrtcCreate(pScreen, NULL);
-
-    /* We don't actually support gamma, but xrandr complains when it is missing */
-    RRCrtcGammaSetSize (crtc, 256);
-
-    /* Then we create a dummy output for it... */
-    sprintf(name, "VNC-%d", vncRandRIndex);
-    vncRandRIndex++;
-
-    output = RROutputCreate(pScreen, name, strlen(name), NULL);
-
-    RROutputSetCrtcs(output, &crtc, 1);
-    RROutputSetConnection(output, RR_Disconnected);
-
-    /* Make sure the CRTC has this output set */
-    vncRandRCrtcSet(pScreen, crtc, NULL, 0, 0, RR_Rotate_0, 1, &output);
-
-    /* Populate a list of default modes */
-    RRModePtr modes[sizeof(vncRandRWidths)/sizeof(*vncRandRWidths)];
-    int num_modes;
-
-    num_modes = 0;
-    for (int i = 0;i < sizeof(vncRandRWidths)/sizeof(*vncRandRWidths);i++) {
-        mode = vncRandRModeGet(vncRandRWidths[i], vncRandRHeights[i]);
-        if (mode != NULL) {
-            modes[num_modes] = mode;
-            num_modes++;
-        }
-    }
-
-    RROutputSetModes(output, modes, num_modes, 0);
-
-    return crtc;
-}
-
-/* Used from XserverDesktop when it needs more outputs... */
-RROutputPtr vncRandROutputCreate(ScreenPtr pScreen)
-{
-    RRCrtcPtr crtc;
-
-    crtc = vncRandRCrtcCreate(pScreen);
-    if (crtc == NULL)
-        return NULL;
-
-    return crtc->outputs[0];
-}
-
-static Bool vncRandRInit(ScreenPtr pScreen)
-{
-    RRCrtcPtr crtc;
-    RRModePtr mode;
-    Bool ret;
-
-    if (!RRInit())
-        return FALSE;
-
-    /* These are completely arbitrary */
-    RRScreenSetSizeRange(pScreen, 32, 32, 32768, 32768);
-
-    /*
-     * Start with a single CRTC with a single output. More will be
-     * allocated as needed...
-     */
-    crtc = vncRandRCrtcCreate(pScreen);
-
-    /* Make sure the current screen size is the active mode */
-    mode = vncRandRModeGet(pScreen->width, pScreen->height);
-    if (mode == NULL)
-        return FALSE;
-
-    ret = vncRandRCrtcSet(pScreen, crtc, mode, 0, 0, RR_Rotate_0,
-                          crtc->numOutputs, crtc->outputs);
-    RRModeDestroy(mode);
-    if (!ret)
-        return FALSE;
-
-    return TRUE;
-}
-
-#endif
-
-static Bool
-#if XORG < 113
-vfbCloseScreen(int index, ScreenPtr pScreen)
-#else
-vfbCloseScreen(ScreenPtr pScreen)
-#endif
-{
-#if XORG < 113
-    vfbScreenInfoPtr pvfb = &vfbScreens[index];
-#else
-    vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
-#endif
-    int i;
-    pScreen->CloseScreen = pvfb->closeScreen;
-
-    /*
-     * XXX probably lots of stuff to clean.  For now,
-     * clear installed colormaps so that server reset works correctly.
-     */
-#if XORG < 113
-    for (i = 0; i < MAXSCREENS; i++)
-       InstalledMaps[i] = NULL;
-
-    return pScreen->CloseScreen(index, pScreen);
-#else
-    for (i = 0; i < screenInfo.numScreens; i++)
-       SetInstalledColormap(screenInfo.screens[i], NULL);
-
-    /*
-     * fb overwrites miCloseScreen, so do this here
-     */
-    if (pScreen->devPrivate)
-        (*pScreen->DestroyPixmap) ((PixmapPtr) pScreen->devPrivate);
-    pScreen->devPrivate = NULL;
-
-    return pScreen->CloseScreen(pScreen);
-#endif
-}
-
-static Bool
-#if XORG < 113
-vfbScreenInit(int index, ScreenPtr pScreen, int argc, char **argv)
-#else
-vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
-#endif
-{
-#if XORG < 113
-    vfbScreenInfoPtr pvfb = &vfbScreens[index];
-#else
-    vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
-#endif
-    int dpi;
-    int ret;
-    void *pbits;
-
-#if XORG >= 113
-    if (!dixRegisterPrivateKey(&cmapScrPrivateKeyRec, PRIVATE_SCREEN, 0))
-       return FALSE;
-#endif
-
-    /* 96 is the default used by most other systems */
-    dpi = 96;
-    if (monitorResolution)
-        dpi = monitorResolution;
-
-    pbits = vfbAllocateFramebufferMemory(&pvfb->fb);
-    if (!pbits) return FALSE;
-#if XORG < 113
-    vncFbptr[index] = pbits;
-    vncFbstride[index] = pvfb->fb.paddedWidth;
-#else
-    vncFbptr[pScreen->myNum] = pbits;
-    vncFbstride[pScreen->myNum] = pvfb->fb.paddedWidth;
-#endif
-
-    miSetPixmapDepths();
-
-    switch (pvfb->fb.depth) {
-    case 8:
-       miSetVisualTypesAndMasks (8,
-                                 ((1 << StaticGray) |
-                                 (1 << GrayScale) |
-                                 (1 << StaticColor) |
-                                 (1 << PseudoColor) |
-                                 (1 << TrueColor) |
-                                 (1 << DirectColor)),
-                                 8, PseudoColor, 0, 0, 0);
-       break;
-    case 16:
-       miSetVisualTypesAndMasks (16,
-                                 ((1 << TrueColor) |
-                                 (1 << DirectColor)),
-                                 8, TrueColor, 0xf800, 0x07e0, 0x001f);
-       break;
-    case 24:
-       miSetVisualTypesAndMasks (24,
-                                 ((1 << TrueColor) |
-                                 (1 << DirectColor)),
-                                 8, TrueColor, 0xff0000, 0x00ff00, 0x0000ff);
-       break;
-    case 32:
-       miSetVisualTypesAndMasks (32,
-                                 ((1 << TrueColor) |
-                                 (1 << DirectColor)),
-                                 8, TrueColor, 0xff000000, 0x00ff0000, 0x0000ff00);
-       break;
-    default:
-       return FALSE;
-    }
-
-    ret = fbScreenInit(pScreen, pbits, pvfb->fb.width, pvfb->fb.height,
-                      dpi, dpi, pvfb->fb.paddedWidth, pvfb->fb.bitsPerPixel);
-  
-#ifdef RENDER
-    if (ret && Render) 
-       ret = fbPictureInit (pScreen, 0, 0);
-#endif
-
-    if (!ret) return FALSE;
-
-#if XORG < 110
-    miInitializeBackingStore(pScreen);
-#endif
-
-    /*
-     * Circumvent the backing store that was just initialised.  This amounts
-     * to a truely bizarre way of initialising SaveDoomedAreas and friends.
-     */
-
-    pScreen->InstallColormap = vfbInstallColormap;
-    pScreen->UninstallColormap = vfbUninstallColormap;
-    pScreen->ListInstalledColormaps = vfbListInstalledColormaps;
-
-    pScreen->SaveScreen = vfbSaveScreen;
-    
-    miPointerInitialize(pScreen, &vfbPointerSpriteFuncs, &vfbPointerCursorFuncs,
-                       FALSE);
-    
-    pScreen->blackPixel = pvfb->blackPixel;
-    pScreen->whitePixel = pvfb->whitePixel;
-
-    if (!pvfb->pixelFormatDefined) {
-       switch (pvfb->fb.depth) {
-       case 16:
-           pvfb->pixelFormatDefined = TRUE;
-           pvfb->rgbNotBgr = TRUE;
-           pvfb->blueBits = pvfb->redBits = 5;
-           pvfb->greenBits = 6;
-           break;
-       case 24:
-       case 32:
-           pvfb->pixelFormatDefined = TRUE;
-           pvfb->rgbNotBgr = TRUE;
-           pvfb->blueBits = pvfb->redBits = pvfb->greenBits = 8;
-           break;
-       }
-    }
-
-    if (pvfb->pixelFormatDefined) {
-       VisualPtr vis = pScreen->visuals;
-       for (int i = 0; i < pScreen->numVisuals; i++) {
-           if (pvfb->rgbNotBgr) {
-               vis->offsetBlue = 0;
-               vis->blueMask = (1 << pvfb->blueBits) - 1;
-               vis->offsetGreen = pvfb->blueBits;
-               vis->greenMask = ((1 << pvfb->greenBits) - 1) << vis->offsetGreen;
-               vis->offsetRed = vis->offsetGreen + pvfb->greenBits;
-               vis->redMask = ((1 << pvfb->redBits) - 1) << vis->offsetRed;
-           } else {
-               vis->offsetRed = 0;
-               vis->redMask = (1 << pvfb->redBits) - 1;
-               vis->offsetGreen = pvfb->redBits;
-               vis->greenMask = ((1 << pvfb->greenBits) - 1) << vis->offsetGreen;
-               vis->offsetBlue = vis->offsetGreen + pvfb->greenBits;
-               vis->blueMask = ((1 << pvfb->blueBits) - 1) << vis->offsetBlue;
-           }
-           vis++;
-       }
-    }
-    
-    ret = fbCreateDefColormap(pScreen);
-    if (!ret) return FALSE;
-
-    miSetZeroLineBias(pScreen, pvfb->lineBias);
-
-    pvfb->closeScreen = pScreen->CloseScreen;
-    pScreen->CloseScreen = vfbCloseScreen;
-
-#ifdef RANDR
-    rrScrPrivPtr rp;
-
-    ret = RRScreenInit(pScreen);
-    if (!ret) return FALSE;
-
-    rp = rrGetScrPriv(pScreen);
-
-    rp->rrGetInfo = vncRandRGetInfo;
-    rp->rrSetConfig = NULL;
-    rp->rrScreenSetSize = vncRandRScreenSetSize;
-    rp->rrCrtcSet = vncRandRCrtcSet;
-    rp->rrOutputValidateMode = vncRandROutputValidateMode;
-    rp->rrModeDestroy = vncRandRModeDestroy;
-
-    ret = vncRandRInit(pScreen);
-    if (!ret) return FALSE;
-#endif
-
-
-  return TRUE;
-
-} /* end vfbScreenInit */
-
-
-static void vfbClientStateChange(CallbackListPtr*, void *, void *) {
-  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)
-{
-  ErrorF("\nXvnc %s - built %s\n%s", XVNCVERSION, buildtime, XVNCCOPYRIGHT);
-  ErrorF("Underlying X server release %d, %s\n\n", VENDOR_RELEASE,
-         VENDOR_STRING);
-    int i;
-    int NumFormats = 0;
-
-#if XORG >= 113
-#ifdef GLXEXT
-    if (serverGeneration == 1)
-#if XORG >= 116
-        LoadExtensionList(&glxExt, 1, TRUE);
-#else
-        LoadExtension(&glxExt, TRUE);
-#endif
-#endif
-#endif
-
-    /* initialize pixmap formats */
-
-    /* must have a pixmap depth to match every screen depth */
-    for (i = 0; i < vfbNumScreens; i++)
-    {
-       vfbPixmapDepths[vfbScreens[i].fb.depth] = TRUE;
-    }
-
-    /* RENDER needs a good set of pixmaps. */
-    if (Render) {
-       vfbPixmapDepths[1] = TRUE;
-       vfbPixmapDepths[4] = TRUE;
-       vfbPixmapDepths[8] = TRUE;
-/*     vfbPixmapDepths[15] = TRUE; */
-       vfbPixmapDepths[16] = TRUE;
-       vfbPixmapDepths[24] = TRUE;
-       vfbPixmapDepths[32] = TRUE;
-    }
-
-    for (i = 1; i <= 32; i++)
-    {
-       if (vfbPixmapDepths[i])
-       {
-           if (NumFormats >= MAXFORMATS)
-               FatalError ("MAXFORMATS is too small for this server\n");
-           screenInfo->formats[NumFormats].depth = i;
-           screenInfo->formats[NumFormats].bitsPerPixel = vfbBitsPerPixel(i);
-           screenInfo->formats[NumFormats].scanlinePad = BITMAP_SCANLINE_PAD;
-           NumFormats++;
-       }
-    }
-
-    screenInfo->imageByteOrder = IMAGE_BYTE_ORDER;
-    screenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT;
-    screenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD;
-    screenInfo->bitmapBitOrder = BITMAP_BIT_ORDER;
-    screenInfo->numPixmapFormats = NumFormats;
-
-    /* initialize screens */
-
-    for (i = 0; i < vfbNumScreens; i++)
-    {
-       if (-1 == AddScreen(vfbScreenInit, argc, argv))
-       {
-           FatalError("Couldn't add screen %d", i);
-       }
-    }
-
-    if (!AddCallback(&ClientStateCallback, vfbClientStateChange, 0)) {
-       FatalError("AddCallback failed\n");
-    }
-} /* end InitOutput */
-
-/* this is just to get the server to link on AIX */
-#ifdef AIXV3
-int SelectWaitTime = 10000; /* usec */
-#endif
-
-void DDXRingBell(int percent, int pitch, int duration)
-{
-  if (percent > 0)
-    vncBell();
-}
-
-Bool LegalModifier(unsigned int key, DeviceIntPtr pDev)
-{
-  return TRUE;
-}
-
-void ProcessInputEvents()
-{
-  mieqProcessInputEvents();
-#if XORG == 15
-  miPointerUpdate();
-#endif
-}
-
-// InitInput is called after InitExtensions, so we're guaranteed that
-// vncExtensionInit() has already been called.
-
-void InitInput(int argc, char *argv[])
-{
-  mieqInit ();
-}
-
-#if XORG > 17
-void CloseInput(void)
-{
-}
-#endif