Encapsulate event handling in VNCServerST

There is some client coordination needed which is better encapsulated
inside VNCServerST. This also helps hiding the desktop from the
individual clients.
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index 7b79139..c83254f 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -84,12 +84,9 @@
 
     vlog.debug("Releasing key 0x%x / 0x%x on client disconnect",
                keysym, keycode);
-    server->desktop->keyEvent(keysym, keycode, false);
+    server->keyEvent(keysym, keycode, false);
   }
 
-  if (server->pointerClient == this)
-    server->pointerClient = 0;
-
   // Remove this client from the server
   server->clients.remove(this);
 
@@ -497,36 +494,29 @@
 void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask)
 {
   pointerEventTime = lastEventTime = time(0);
-  server->lastUserInputTime = lastEventTime;
   if (!(accessRights & AccessPtrEvents)) return;
   if (!rfb::Server::acceptPointerEvents) return;
-  if (!server->pointerClient || server->pointerClient == this) {
-    pointerEventPos = pos;
-    if (buttonMask)
-      server->pointerClient = this;
-    else
-      server->pointerClient = 0;
-    server->desktop->pointerEvent(pointerEventPos, buttonMask);
-  }
+  pointerEventPos = pos;
+  server->pointerEvent(this, pointerEventPos, buttonMask);
 }
 
 
 class VNCSConnectionSTShiftPresser {
 public:
-  VNCSConnectionSTShiftPresser(SDesktop* desktop_)
-    : desktop(desktop_), pressed(false) {}
+  VNCSConnectionSTShiftPresser(VNCServerST* server_)
+    : server(server_), pressed(false) {}
   ~VNCSConnectionSTShiftPresser() {
     if (pressed) {
       vlog.debug("Releasing fake Shift_L");
-      desktop->keyEvent(XK_Shift_L, 0, false);
+      server->keyEvent(XK_Shift_L, 0, false);
     }
   }
   void press() {
     vlog.debug("Pressing fake Shift_L");
-    desktop->keyEvent(XK_Shift_L, 0, true);
+    server->keyEvent(XK_Shift_L, 0, true);
     pressed = true;
   }
-  SDesktop* desktop;
+  VNCServerST* server;
   bool pressed;
 };
 
@@ -536,7 +526,6 @@
   rdr::U32 lookup;
 
   lastEventTime = time(0);
-  server->lastUserInputTime = lastEventTime;
   if (!(accessRights & AccessKeyEvents)) return;
   if (!rfb::Server::acceptKeyEvents) return;
 
@@ -545,16 +534,6 @@
   else
     vlog.debug("Key released: 0x%x / 0x%x", keysym, keycode);
 
-  // Remap the key if required
-  if (server->keyRemapper) {
-    rdr::U32 newkey;
-    newkey = server->keyRemapper->remapKey(keysym);
-    if (newkey != keysym) {
-      vlog.debug("Key remapped to 0x%x", newkey);
-      keysym = newkey;
-    }
-  }
-
   // Avoid lock keys if we don't know the server state
   if ((server->getLEDState() == ledUnknown) &&
       ((keysym == XK_Caps_Lock) ||
@@ -588,8 +567,8 @@
 
         if (lock == (uppercase == shift)) {
           vlog.debug("Inserting fake CapsLock to get in sync with client");
-          server->desktop->keyEvent(XK_Caps_Lock, 0, true);
-          server->desktop->keyEvent(XK_Caps_Lock, 0, false);
+          server->keyEvent(XK_Caps_Lock, 0, true);
+          server->keyEvent(XK_Caps_Lock, 0, false);
         }
       }
 
@@ -618,15 +597,15 @@
           //
         } else if (lock == (number == shift)) {
           vlog.debug("Inserting fake NumLock to get in sync with client");
-          server->desktop->keyEvent(XK_Num_Lock, 0, true);
-          server->desktop->keyEvent(XK_Num_Lock, 0, false);
+          server->keyEvent(XK_Num_Lock, 0, true);
+          server->keyEvent(XK_Num_Lock, 0, false);
         }
       }
     }
   }
 
   // Turn ISO_Left_Tab into shifted Tab.
-  VNCSConnectionSTShiftPresser shiftPresser(server->desktop);
+  VNCSConnectionSTShiftPresser shiftPresser(server);
   if (keysym == XK_ISO_Left_Tab) {
     if (!isShiftPressed())
       shiftPresser.press();
@@ -652,14 +631,14 @@
       return;
   }
 
-  server->desktop->keyEvent(keysym, keycode, down);
+  server->keyEvent(keysym, keycode, down);
 }
 
 void VNCSConnectionST::clientCutText(const char* str, int len)
 {
   if (!(accessRights & AccessCutText)) return;
   if (!rfb::Server::acceptCutText) return;
-  server->desktop->clientCutText(str, len);
+  server->clientCutText(str, len);
 }
 
 void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx
index 7e36876..6affe92 100644
--- a/common/rfb/VNCServerST.cxx
+++ b/common/rfb/VNCServerST.cxx
@@ -147,6 +147,10 @@
   std::list<VNCSConnectionST*>::iterator ci;
   for (ci = clients.begin(); ci != clients.end(); ci++) {
     if ((*ci)->getSock() == sock) {
+      // - Release the cursor if this client owns it
+      if (pointerClient == *ci)
+        pointerClient = NULL;
+
       // - Delete the per-Socket resources
       delete *ci;
 
@@ -467,6 +471,48 @@
   }
 }
 
+// Event handlers
+
+void VNCServerST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
+{
+  lastUserInputTime = time(0);
+
+  // Remap the key if required
+  if (keyRemapper) {
+    rdr::U32 newkey;
+    newkey = keyRemapper->remapKey(keysym);
+    if (newkey != keysym) {
+      slog.debug("Key remapped to 0x%x", newkey);
+      keysym = newkey;
+    }
+  }
+
+  desktop->keyEvent(keysym, keycode, down);
+}
+
+void VNCServerST::pointerEvent(VNCSConnectionST* client,
+                               const Point& pos, int buttonMask)
+{
+  lastUserInputTime = time(0);
+
+  // Let one client own the cursor whilst buttons are pressed in order
+  // to provide a bit more sane user experience
+  if ((pointerClient != NULL) && (pointerClient != client))
+    return;
+
+  if (buttonMask)
+    pointerClient = client;
+  else
+    pointerClient = NULL;
+
+  desktop->pointerEvent(pos, buttonMask);
+}
+
+void VNCServerST::clientCutText(const char* str, int len)
+{
+  desktop->clientCutText(str, len);
+}
+
 // Other public methods
 
 void VNCServerST::approveConnection(network::Socket* sock, bool accept,
diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h
index ef83619..eff52d0 100644
--- a/common/rfb/VNCServerST.h
+++ b/common/rfb/VNCServerST.h
@@ -120,6 +120,11 @@
     const char* getName() const { return name.buf; }
     unsigned getLEDState() const { return ledState; }
 
+    // Event handlers
+    void keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down);
+    void pointerEvent(VNCSConnectionST* client, const Point& pos, int buttonMask);
+    void clientCutText(const char* str, int len);
+
     // closeClients() closes all RFB sessions, except the specified one (if
     // any), and logs the specified reason for closure.
     void closeClients(const char* reason, network::Socket* sock);