]> source.dussan.org Git - tigervnc.git/commitdiff
Win32 vncviewer merged with VNC 4.1.1 code. The merge is incomplete - the code compil...
authorConstantin Kaplinsky <const@tightvnc.com>
Tue, 16 May 2006 08:48:31 +0000 (08:48 +0000)
committerConstantin Kaplinsky <const@tightvnc.com>
Tue, 16 May 2006 08:48:31 +0000 (08:48 +0000)
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/branches/merge-with-vnc-4.1.1@552 3789f03b-4d11-0410-bbf8-ca57d06f2519

33 files changed:
vncviewer/CConn.cxx [new file with mode: 0644]
vncviewer/CConn.h [new file with mode: 0644]
vncviewer/CConnOptions.cxx [new file with mode: 0644]
vncviewer/CConnOptions.h [new file with mode: 0644]
vncviewer/CConnThread.cxx [new file with mode: 0644]
vncviewer/CConnThread.h [new file with mode: 0644]
vncviewer/CViewManager.cxx [deleted file]
vncviewer/CViewManager.h [deleted file]
vncviewer/CViewOptions.cxx [deleted file]
vncviewer/CViewOptions.h [deleted file]
vncviewer/ConnectingDialog.cxx [new file with mode: 0644]
vncviewer/ConnectingDialog.h
vncviewer/ConnectionDialog.cxx
vncviewer/ConnectionDialog.h
vncviewer/DesktopWindow.cxx [new file with mode: 0644]
vncviewer/DesktopWindow.h [new file with mode: 0644]
vncviewer/InfoDialog.cxx
vncviewer/InfoDialog.h
vncviewer/ListenServer.h [new file with mode: 0644]
vncviewer/ListenTrayIcon.h [new file with mode: 0644]
vncviewer/MRU.h
vncviewer/OptionsDialog.cxx
vncviewer/OptionsDialog.h
vncviewer/UserPasswdDialog.cxx
vncviewer/UserPasswdDialog.h
vncviewer/buildTime.cxx
vncviewer/cview.cxx [deleted file]
vncviewer/cview.h [deleted file]
vncviewer/msvcwarning.h [deleted file]
vncviewer/resource.h
vncviewer/vncviewer.bmp [new file with mode: 0644]
vncviewer/vncviewer.cxx
vncviewer/vncviewer.dsp

diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
new file mode 100644 (file)
index 0000000..2d90730
--- /dev/null
@@ -0,0 +1,708 @@
+/* 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.
+ */
+
+#include <windows.h>
+#include <winsock2.h>
+#include <vncviewer/UserPasswdDialog.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/CConnThread.h>
+#include <vncviewer/resource.h>
+#include <rfb/encodings.h>
+#include <rfb/secTypes.h>
+#include <rfb/CSecurityNone.h>
+#include <rfb/CSecurityVncAuth.h>
+#include <rfb/CMsgWriter.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/AboutDialog.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+using namespace rdr;
+
+// - Statics & consts
+
+static LogWriter vlog("CConn");
+
+
+const int IDM_FULLSCREEN = ID_FULLSCREEN;
+const int IDM_SEND_MENU_KEY = ID_SEND_MENU_KEY;
+const int IDM_SEND_CAD = ID_SEND_CAD;
+const int IDM_SEND_CTLESC = ID_SEND_CTLESC;
+const int IDM_ABOUT = ID_ABOUT;
+const int IDM_OPTIONS = ID_OPTIONS;
+const int IDM_INFO = ID_INFO;
+const int IDM_NEWCONN = ID_NEW_CONNECTION;
+const int IDM_REQUEST_REFRESH = ID_REQUEST_REFRESH;
+const int IDM_CTRL_KEY = ID_CTRL_KEY;
+const int IDM_ALT_KEY = ID_ALT_KEY;
+const int IDM_FILE_TRANSFER = ID_FILE_TRANSFER;
+const int IDM_CONN_SAVE_AS = ID_CONN_SAVE_AS;
+
+
+static IntParameter debugDelay("DebugDelay","Milliseconds to display inverted "
+                               "pixel data - a debugging feature", 0);
+
+
+//
+// -=- CConn implementation
+//
+
+RegKey            CConn::userConfigKey;
+
+
+CConn::CConn() 
+  : window(0), sock(0), sockEvent(CreateEvent(0, TRUE, FALSE, 0)), requestUpdate(false),
+    sameMachine(false), encodingChange(false), formatChange(false),
+    reverseConnection(false), lastUsedEncoding_(encodingRaw), isClosed_(false) {
+}
+
+CConn::~CConn() {
+  delete window;
+}
+
+bool CConn::initialise(network::Socket* s, bool reverse) {
+  // Set the server's name for MRU purposes
+  CharArray endpoint(s->getPeerEndpoint());
+  setServerName(endpoint.buf);
+  if (!options.host.buf)
+    options.setHost(endpoint.buf);
+
+  // Initialise the underlying CConnection
+  setStreams(&s->inStream(), &s->outStream());
+
+  // Enable processing of window messages while blocked on I/O
+  s->inStream().setBlockCallback(this);
+
+  // Initialise the viewer options
+  applyOptions(options);
+
+  // - Set which auth schemes we support, in order of preference
+  addSecType(secTypeVncAuth);
+  addSecType(secTypeNone);
+
+  // Start the RFB protocol
+  sock = s;
+  reverseConnection = reverse;
+  initialiseProtocol();
+
+  m_fileTransfer.initialize(&s->inStream(), &s->outStream());
+
+  return true;
+}
+
+
+void
+CConn::applyOptions(CConnOptions& opt) {
+  // - If any encoding-related settings have changed then we must
+  //   notify the server of the new settings
+  encodingChange |= ((options.useLocalCursor != opt.useLocalCursor) ||
+                     (options.useDesktopResize != opt.useDesktopResize) ||
+                     (options.customCompressLevel != opt.customCompressLevel) ||
+                     (options.compressLevel != opt.compressLevel) ||
+                     (options.noJpeg != opt.noJpeg) ||
+                     (options.qualityLevel != opt.qualityLevel) ||
+                     (options.preferredEncoding != opt.preferredEncoding));
+
+  // - If the preferred pixel format has changed then notify the server
+  formatChange |= (options.fullColour != opt.fullColour);
+  if (!opt.fullColour)
+    formatChange |= (options.lowColourLevel != opt.lowColourLevel);
+
+  // - Save the new set of options
+  options = opt;
+
+  // - Set optional features in ConnParams
+  cp.supportsLocalCursor = options.useLocalCursor;
+  cp.supportsDesktopResize = options.useDesktopResize;
+  cp.customCompressLevel = options.customCompressLevel;
+  cp.compressLevel = options.compressLevel;
+  cp.noJpeg = options.noJpeg;
+  cp.qualityLevel = options.qualityLevel;
+
+  // - Configure connection sharing on/off
+  setShared(options.shared);
+
+  // - Whether to use protocol 3.3 for legacy compatibility
+  setProtocol3_3(options.protocol3_3);
+
+  // - Apply settings that affect the window, if it is visible
+  if (window) {
+    window->setMonitor(options.monitor.buf);
+    window->setFullscreen(options.fullScreen);
+    window->setEmulate3(options.emulate3);
+    window->setPointerEventInterval(options.pointerEventInterval);
+    window->setMenuKey(options.menuKey);
+    window->setDisableWinKeys(options.disableWinKeys);
+    window->setShowToolbar(options.showToolbar);
+    if (!options.useLocalCursor)
+      window->setCursor(0, 0, Point(), 0, 0);
+  }
+}
+
+
+void
+CConn::displayChanged() {
+  // Display format has changed - recalculate the full-colour pixel format
+  calculateFullColourPF();
+}
+
+void
+CConn::paintCompleted() {
+  // A repaint message has just completed - request next update if necessary
+  requestNewUpdate();
+}
+
+bool
+CConn::sysCommand(WPARAM wParam, LPARAM lParam) {
+  // - If it's one of our (F8 Menu) messages
+  switch (wParam) {
+  case IDM_FULLSCREEN:
+    options.fullScreen = !window->isFullscreen();
+    window->setFullscreen(options.fullScreen);
+    return true;
+  case IDM_SHOW_TOOLBAR:
+    options.showToolbar = !options.showToolbar;
+    window->setShowToolbar(options.showToolbar);
+    // FIXME: Update menu in DesktopWindow?
+    // FIXME: Actually show or hide the toolbar?
+    return true;
+  case IDM_CTRL_KEY:
+    window->kbd.keyEvent(this, VK_CONTROL, 0, !window->kbd.keyPressed(VK_CONTROL));
+    return true;
+  case IDM_ALT_KEY:
+    window->kbd.keyEvent(this, VK_MENU, 0, !window->kbd.keyPressed(VK_MENU));
+    return true;
+  case IDM_SEND_MENU_KEY:
+    window->kbd.keyEvent(this, options.menuKey, 0, true);
+    window->kbd.keyEvent(this, options.menuKey, 0, false);
+    return true;
+  case IDM_SEND_CAD:
+    window->kbd.keyEvent(this, VK_CONTROL, 0, true);
+    window->kbd.keyEvent(this, VK_MENU, 0, true);
+    window->kbd.keyEvent(this, VK_DELETE, 0x1000000, true);
+    window->kbd.keyEvent(this, VK_DELETE, 0x1000000, false);
+    window->kbd.keyEvent(this, VK_MENU, 0, false);
+    window->kbd.keyEvent(this, VK_CONTROL, 0, false);
+    return true;
+  case IDM_SEND_CTLESC:
+    window->kbd.keyEvent(this, VK_CONTROL, 0, true);
+    window->kbd.keyEvent(this, VK_ESCAPE, 0, true);
+    window->kbd.keyEvent(this, VK_ESCAPE, 0, false);
+    window->kbd.keyEvent(this, VK_CONTROL, 0, false);
+    return true;
+  case IDM_REQUEST_REFRESH:
+    try {
+      writer()->writeFramebufferUpdateRequest(Rect(0,0,cp.width,cp.height), false);
+      requestUpdate = false;
+    } catch (rdr::Exception& e) {
+      close(e.str());
+    }
+    return true;
+  case IDM_NEWCONN:
+    {
+      Thread* newThread = new CConnThread;
+    }
+    return true;
+  case IDM_OPTIONS:
+    // Update the monitor device name in the CConnOptions instance
+    options.monitor.replaceBuf(window->getMonitor());
+    showOptionsDialog();
+    return true;
+  case IDM_INFO:
+    infoDialog.showDialog(this);
+    return true;
+  case IDM_ABOUT:
+    AboutDialog::instance.showDialog();
+    return true;
+  case IDM_FILE_TRANSFER:
+    m_fileTransfer.show(window->getHandle());
+    return true;
+  case IDM_CONN_SAVE_AS:
+    return true;
+  case ID_CLOSE:
+    // FIXME: Remove the corresponding toolbar button.
+    return true;
+  };
+  return false;
+}
+
+
+void
+CConn::closeWindow() {
+  vlog.info("window closed");
+  close();
+}
+
+
+void
+CConn::refreshMenu(bool enableSysItems) {
+  HMENU menu = GetSystemMenu(window->getHandle(), FALSE);
+
+  if (!enableSysItems) {
+    // Gray out menu items that might cause a World Of Pain
+    EnableMenuItem(menu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
+    EnableMenuItem(menu, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
+    EnableMenuItem(menu, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED);
+    EnableMenuItem(menu, SC_MINIMIZE, MF_BYCOMMAND | MF_ENABLED);
+    EnableMenuItem(menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_ENABLED);
+  }
+
+  // Update the modifier key menu items
+  UINT ctrlCheckFlags = window->kbd.keyPressed(VK_CONTROL) ? MF_CHECKED : MF_UNCHECKED;
+  UINT altCheckFlags = window->kbd.keyPressed(VK_MENU) ? MF_CHECKED : MF_UNCHECKED;
+  CheckMenuItem(menu, IDM_CTRL_KEY, MF_BYCOMMAND | ctrlCheckFlags);
+  CheckMenuItem(menu, IDM_ALT_KEY, MF_BYCOMMAND | altCheckFlags);
+
+  // Ensure that the Send <MenuKey> menu item has the correct text
+  if (options.menuKey) {
+    TCharArray menuKeyStr(options.menuKeyName());
+    TCharArray tmp(_tcslen(menuKeyStr.buf) + 6);
+    _stprintf(tmp.buf, _T("Send %s"), menuKeyStr.buf);
+    if (!ModifyMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf))
+      InsertMenu(menu, IDM_SEND_CAD, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf);
+  } else {
+    RemoveMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND);
+  }
+
+  // Set the menu fullscreen option tick
+  CheckMenuItem(menu, IDM_FULLSCREEN, (window->isFullscreen() ? MF_CHECKED : 0) | MF_BYCOMMAND);
+
+  // In the full-screen mode, "Show toolbar" should be grayed.
+  int toolbarFlags = options.fullScreen ? MF_GRAYED : MF_ENABLED;
+  EnableMenuItem(menu, IDM_SHOW_TOOLBAR, MF_BYCOMMAND | toolbarFlags);
+}
+
+
+void
+CConn::blockCallback() {
+  // - An InStream has blocked on I/O while processing an RFB message
+  //   We re-enable socket event notifications, so we'll know when more
+  //   data is available, then we sit and dispatch window events until
+  //   the notification arrives.
+  if (!isClosed()) {
+    if (WSAEventSelect(sock->getFd(), sockEvent, FD_READ | FD_CLOSE) == SOCKET_ERROR)
+      throw rdr::SystemException("Unable to wait for sokcet data", WSAGetLastError());
+  }
+  while (true) {
+    // If we have closed then we can't block waiting for data
+    if (isClosed())
+      throw rdr::EndOfStream();
+
+    // Wait for socket data, or a message to process
+    DWORD result = MsgWaitForMultipleObjects(1, &sockEvent.h, FALSE, INFINITE, QS_ALLINPUT);
+    if (result == WAIT_OBJECT_0) {
+      // - Network event notification.  Return control to I/O routine.
+      break;
+    } else if (result == WAIT_FAILED) {
+      // - The wait operation failed - raise an exception
+      throw rdr::SystemException("blockCallback wait error", GetLastError());
+    }
+
+    // - There should be a message in the message queue
+    MSG msg;
+    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+      // IMPORTANT: We mustn't call TranslateMessage() here, because instead we
+      // call ToAscii() in CKeyboard::keyEvent().  ToAscii() stores dead key
+      // state from one call to the next, which would be messed up by calls to
+      // TranslateMessage() (actually it looks like TranslateMessage() calls
+      // ToAscii() internally).
+      DispatchMessage(&msg);
+    }
+  }
+
+  // Before we return control to the InStream, reset the network event
+  WSAEventSelect(sock->getFd(), sockEvent, 0);
+  ResetEvent(sockEvent);
+}
+
+
+void CConn::keyEvent(rdr::U32 key, bool down) {
+  if (!options.sendKeyEvents) return;
+  try {
+    writer()->keyEvent(key, down);
+  } catch (rdr::Exception& e) {
+    close(e.str());
+  }
+}
+void CConn::pointerEvent(const Point& pos, int buttonMask) {
+  if (!options.sendPtrEvents) return;
+  try {
+    writer()->pointerEvent(pos, buttonMask);
+  } catch (rdr::Exception& e) {
+    close(e.str());
+  }
+}
+void CConn::clientCutText(const char* str, int len) {
+  if (!options.clientCutText) return;
+  if (state() != RFBSTATE_NORMAL) return;
+  try {
+    writer()->clientCutText(str, len);
+  } catch (rdr::Exception& e) {
+    close(e.str());
+  }
+}
+
+
+CSecurity* CConn::getCSecurity(int secType)
+{
+  switch (secType) {
+  case secTypeNone:
+    return new CSecurityNone();
+  case secTypeVncAuth:
+    return new CSecurityVncAuth(this);
+  default:
+    throw Exception("Unsupported secType?");
+  }
+}
+
+
+void
+CConn::setColourMapEntries(int first, int count, U16* rgbs) {
+  vlog.debug("setColourMapEntries: first=%d, count=%d", first, count);
+  int i;
+  for (i=0;i<count;i++)
+    window->setColour(i+first, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
+  // *** change to 0, 256?
+  window->refreshWindowPalette(first, count);
+}
+
+void
+CConn::bell() {
+  if (options.acceptBell)
+    MessageBeep(-1);
+}
+
+
+void
+CConn::setDesktopSize(int w, int h) {
+  vlog.debug("setDesktopSize %dx%d", w, h);
+
+  // Resize the window's buffer
+  if (window)
+    window->setSize(w, h);
+
+  // Tell the underlying CConnection
+  CConnection::setDesktopSize(w, h);
+}
+
+void
+CConn::setCursor(int w, int h, const Point& hotspot, void* data, void* mask) {
+  if (!options.useLocalCursor) return;
+
+  // Set the window to use the new cursor
+  window->setCursor(w, h, hotspot, data, mask);
+}
+
+
+void
+CConn::close(const char* reason) {
+  // If already closed then ignore this
+  if (isClosed())
+    return;
+
+  // Hide the window, if it exists
+  if (window)
+    ShowWindow(window->getHandle(), SW_HIDE);
+
+  // Save the reason & flag that we're closed & shutdown the socket
+  isClosed_ = true;
+  closeReason_.replaceBuf(strDup(reason));
+  sock->shutdown();
+}
+
+
+void
+CConn::showOptionsDialog() {
+  optionsDialog.showDialog(this);
+}
+
+
+void
+CConn::framebufferUpdateEnd() {
+  if (debugDelay != 0) {
+    vlog.debug("debug delay %d",(int)debugDelay);
+    UpdateWindow(window->getHandle());
+    Sleep(debugDelay);
+    std::list<rfb::Rect>::iterator i;
+    for (i = debugRects.begin(); i != debugRects.end(); i++) {
+      window->invertRect(*i);
+    }
+    debugRects.clear();
+  }
+  if (options.autoSelect)
+    autoSelectFormatAndEncoding();
+
+  // Always request the next update
+  requestUpdate = true;
+
+  // Check that at least part of the window has changed
+  if (!GetUpdateRect(window->getHandle(), 0, FALSE)) {
+    if (!(GetWindowLong(window->getHandle(), GWL_STYLE) & WS_MINIMIZE))
+      requestNewUpdate();
+  }
+
+  // Make sure the local cursor is shown
+  window->showCursor();
+}
+
+
+// Note: The method below is duplicated in vncviewer_unix/CConn.cxx!
+
+// autoSelectFormatAndEncoding() chooses the format and encoding appropriate
+// to the connection speed:
+//
+//   Above 16Mbps (timing for at least a second), switch to hextile
+//   Otherwise, switch to ZRLE
+//
+//   Above 256Kbps, use full colour mode
+//
+void
+CConn::autoSelectFormatAndEncoding() {
+  int kbitsPerSecond = sock->inStream().kbitsPerSecond();
+  unsigned int newEncoding = options.preferredEncoding;
+
+  bool newFullColour = options.fullColour;
+  unsigned int timeWaited = sock->inStream().timeWaited();
+
+  // Select best encoding
+  if (kbitsPerSecond > 16000 && timeWaited >= 10000) {
+    newEncoding = encodingHextile;
+  } else {
+    newEncoding = encodingZRLE;
+  }
+
+  if (newEncoding != options.preferredEncoding) {
+    vlog.info("Throughput %d kbit/s - changing to %s encoding",
+            kbitsPerSecond, encodingName(newEncoding));
+    options.preferredEncoding = newEncoding;
+    encodingChange = true;
+  }
+
+  if (kbitsPerSecond == 0) {
+    return;
+  }
+
+  if (cp.beforeVersion(3, 8)) {
+    // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
+    // cursors "asynchronously". If this happens in the middle of a
+    // pixel format change, the server will encode the cursor with
+    // the old format, but the client will try to decode it
+    // according to the new format. This will lead to a
+    // crash. Therefore, we do not allow automatic format change for
+    // old servers.
+    return;
+  }
+  
+  // Select best color level
+  newFullColour = (kbitsPerSecond > 256);
+  if (newFullColour != options.fullColour) {
+    vlog.info("Throughput %d kbit/s - full color is now %s", 
+              kbitsPerSecond,
+              newFullColour ? "enabled" : "disabled");
+    options.fullColour = newFullColour;
+    formatChange = true;
+  }
+}
+
+void
+CConn::requestNewUpdate() {
+  if (!requestUpdate) return;
+
+  if (formatChange) {
+    // Select the required pixel format
+    if (options.fullColour) {
+      window->setPF(fullColourPF);
+    } else {
+      switch (options.lowColourLevel) {
+      case 0:
+        window->setPF(PixelFormat(8,3,0,1,1,1,1,2,1,0));
+        break;
+      case 1:
+        window->setPF(PixelFormat(8,6,0,1,3,3,3,4,2,0));
+        break;
+      case 2:
+        window->setPF(PixelFormat(8,8,0,0,0,0,0,0,0,0));
+        break;
+      }
+    }
+
+    // Print the current pixel format
+    char str[256];
+    window->getPF().print(str, 256);
+    vlog.info("Using pixel format %s",str);
+
+    // Save the connection pixel format and tell server to use it
+    cp.setPF(window->getPF());
+    writer()->writeSetPixelFormat(cp.pf());
+
+    // Correct the local window's palette
+    if (!window->getNativePF().trueColour)
+      window->refreshWindowPalette(0, 1 << cp.pf().depth);
+  }
+
+  if (encodingChange) {
+    vlog.info("Using %s encoding",encodingName(options.preferredEncoding));
+    writer()->writeSetEncodings(options.preferredEncoding, true);
+  }
+
+  writer()->writeFramebufferUpdateRequest(Rect(0, 0, cp.width, cp.height),
+                                          !formatChange);
+
+  encodingChange = formatChange = requestUpdate = false;
+}
+
+
+void
+CConn::calculateFullColourPF() {
+  // If the server is palette based then use palette locally
+  // Also, don't bother doing bgr222
+  if (!serverDefaultPF.trueColour || (serverDefaultPF.depth < 6)) {
+    fullColourPF = serverDefaultPF;
+    options.fullColour = true;
+  } else {
+    // If server is trueColour, use lowest depth PF
+    PixelFormat native = window->getNativePF();
+    if ((serverDefaultPF.bpp < native.bpp) ||
+        ((serverDefaultPF.bpp == native.bpp) &&
+        (serverDefaultPF.depth < native.depth)))
+      fullColourPF = serverDefaultPF;
+    else
+      fullColourPF = window->getNativePF();
+  }
+  formatChange = true;
+}
+
+
+void
+CConn::setName(const char* name) {
+  if (window)
+    window->setName(name);
+  CConnection::setName(name);
+}
+
+
+void CConn::serverInit() {
+  CConnection::serverInit();
+
+  // If using AutoSelect with old servers, start in FullColor
+  // mode. See comment in autoSelectFormatAndEncoding. 
+  if (cp.beforeVersion(3, 8) && options.autoSelect) {
+    options.fullColour = true;
+  }
+
+  // Show the window
+  window = new DesktopWindow(this);
+  window->setName(cp.name());
+  window->setSize(cp.width, cp.height);
+  applyOptions(options);
+
+  // Save the server's current format
+  serverDefaultPF = cp.pf();
+
+  // Calculate the full-colour format to use
+  calculateFullColourPF();
+
+  // Request the initial update
+  vlog.info("requesting initial update");
+  formatChange = encodingChange = requestUpdate = true;
+  requestNewUpdate();
+
+  // Update the window menu
+  HMENU wndmenu = GetSystemMenu(window->getHandle(), FALSE);
+  int toolbarChecked = options.showToolbar ? MF_CHECKED : 0;
+
+  AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
+  AppendMenu(wndmenu, MF_STRING, IDM_FULLSCREEN, _T("&Full screen"));
+  AppendMenu(wndmenu, MF_STRING | toolbarChecked, IDM_SHOW_TOOLBAR,
+             _T("Show tool&bar"));
+  AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
+  AppendMenu(wndmenu, MF_STRING, IDM_CTRL_KEY, _T("Ctr&l"));
+  AppendMenu(wndmenu, MF_STRING, IDM_ALT_KEY, _T("Al&t"));
+  AppendMenu(wndmenu, MF_STRING, IDM_SEND_CAD, _T("Send Ctrl-Alt-&Del"));
+  AppendMenu(wndmenu, MF_STRING, IDM_SEND_CTLESC, _T("Send Ctrl-&Esc"));
+  AppendMenu(wndmenu, MF_STRING, IDM_REQUEST_REFRESH, _T("Refres&h Screen"));
+  AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
+  AppendMenu(wndmenu, MF_STRING, IDM_NEWCONN, _T("Ne&w Connection..."));
+  AppendMenu(wndmenu, MF_STRING, IDM_OPTIONS, _T("&Options..."));
+  AppendMenu(wndmenu, MF_STRING, IDM_INFO, _T("Connection &Info..."));
+  AppendMenu(wndmenu, MF_STRING, IDM_ABOUT, _T("&About..."));
+}
+
+void
+CConn::serverCutText(const char* str, int len) {
+  if (!options.serverCutText) return;
+  window->serverCutText(str, len);
+}
+
+
+void CConn::beginRect(const Rect& r, unsigned int encoding) {
+  sock->inStream().startTiming();
+}
+
+void CConn::endRect(const Rect& r, unsigned int encoding) {
+  sock->inStream().stopTiming();
+  lastUsedEncoding_ = encoding;
+  if (debugDelay != 0) {
+    window->invertRect(r);
+    debugRects.push_back(r);
+  }
+}
+
+void CConn::fillRect(const Rect& r, Pixel pix) {
+  window->fillRect(r, pix);
+}
+void CConn::imageRect(const Rect& r, void* pixels) {
+  window->imageRect(r, pixels);
+}
+void CConn::copyRect(const Rect& r, int srcX, int srcY) {
+  window->copyRect(r, srcX, srcY);
+}
+
+void CConn::getUserPasswd(char** user, char** password) {
+/*
+  if (!user && options.passwordFile.buf[0]) {
+    FILE* fp = fopen(options.passwordFile.buf, "rb");
+    if (!fp) return false;
+    char data[256];
+    int datalen = fread(data, 1, 256, fp);
+    fclose(fp);
+    if (datalen != 8) return false;
+    vncAuthUnobfuscatePasswd(data);
+    *password = strDup(data);
+    memset(data, 0, strlen(data));
+    return true;
+  }
+*/
+  if (user && options.userName.buf)
+    *user = strDup(options.userName.buf);
+  if (password && options.password.buf)
+    *password = strDup(options.password.buf);
+  if ((user && !*user) || (password && !*password)) {
+    // Missing username or password - prompt the user
+    UserPasswdDialog userPasswdDialog;
+    userPasswdDialog.setCSecurity(getCurrentCSecurity());
+    userPasswdDialog.getUserPasswd(user, password);
+  }
+  if (user) options.setUserName(*user);
+  if (password) options.setPassword(*password);
+}
+
+bool CConn::processFTMsg(int type) {
+  return m_fileTransfer.processFTMsg(type);
+}
diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h
new file mode 100644 (file)
index 0000000..29023f3
--- /dev/null
@@ -0,0 +1,165 @@
+/* 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.
+ */
+
+// -=- CConn.h
+
+// Windows-specific implementation of CConnection
+
+#ifndef __RFB_WIN32_CCONN_H__
+#define __RFB_WIN32_CCONN_H__
+
+#include <network/Socket.h>
+#include <rfb/CConnection.h>
+#include <rfb/Cursor.h>
+#include <rfb/UserPasswdGetter.h>
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Handle.h>
+#include <vncviewer/InfoDialog.h>
+#include <vncviewer/OptionsDialog.h>
+#include <vncviewer/CConnOptions.h>
+#include <vncviewer/DesktopWindow.h>
+#include <vncviewer/FileTransfer.h>
+#include <list>
+
+
+namespace rfb {
+
+  namespace win32 {
+
+    class CConn : public CConnection,
+                  UserPasswdGetter,
+                  DesktopWindow::Callback,
+                  rdr::FdInStreamBlockCallback
+    {
+    public:
+      CConn();
+      ~CConn();
+
+      // - Start the VNC session on the supplied socket
+      //   The socket must already be connected to a host
+      bool initialise(network::Socket* s, bool reverse=false);
+
+      // - Set/get the session options
+      void applyOptions(CConnOptions& opt);
+      const CConnOptions& getOptions() const { return options; };
+
+      // - Show the options dialog for the connection
+      void showOptionsDialog();
+
+      // - Close the socket & set the reason for closure
+      void close(const char* reason=0);
+      bool isClosed() const { return isClosed_; }
+      const char* closeReason() const { return closeReason_.buf; }
+
+      // - Last received encoding, for the Info dialog
+      int lastUsedEncoding() const { return lastUsedEncoding_; }
+
+      // - Get at the DesktopWindow, if any
+      DesktopWindow* getWindow() { return window; }
+
+      // - Get at the underlying Socket
+      network::Socket* getSocket() { return sock; }
+
+      // - Get the server's preferred format
+      const PixelFormat& getServerDefaultPF() const { return serverDefaultPF; }
+
+      // Global user-config registry key
+      static RegKey userConfigKey;
+
+      bool processFTMsg(int type);
+
+    protected:
+      // InputHandler interface (via DesktopWindow::Callback)
+      void keyEvent(rdr::U32 key, bool down);
+      void pointerEvent(const Point& pos, int buttonMask);
+      void clientCutText(const char* str, int len);
+
+      // DesktopWindow::Callback interface
+      void displayChanged();
+      void paintCompleted();
+      bool sysCommand(WPARAM wParam, LPARAM lParam);
+      void closeWindow();
+      void refreshMenu(bool enableSysCommands);
+
+      // CConnection interface
+      CSecurity* getCSecurity(int secType);
+      void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs);
+      void bell();
+      void framebufferUpdateEnd();
+      void setDesktopSize(int w, int h);
+      void setCursor(int w, int h, const Point& hotspot, void* data, void* mask);
+      void setName(const char* name);
+      void serverInit();
+      void serverCutText(const char* str, int len);
+      void beginRect(const Rect& r, unsigned int encoding);
+      void endRect(const Rect& r, unsigned int encoding);
+      void fillRect(const Rect& r, Pixel pix);
+      void imageRect(const Rect& r, void* pixels);
+      void copyRect(const Rect& r, int srcX, int srcY);
+
+      // rdr::FdInStreamBlockCallback interface
+      void blockCallback();
+
+      // UserPasswdGetter interface
+      // (overridden to allow a pre-supplied username & password)
+      void getUserPasswd(char** user, char** password);
+
+      // CConn-specific internal interface
+      void autoSelectFormatAndEncoding();
+      void requestNewUpdate();
+      void calculateFullColourPF();
+
+      // The desktop window
+      DesktopWindow* window;
+
+      // Info and Options dialogs
+      OptionsDialog optionsDialog;
+      InfoDialog infoDialog;
+
+      // VNC Viewer options
+      CConnOptions options;
+
+      // Pixel format and encoding
+      PixelFormat serverDefaultPF;
+      PixelFormat fullColourPF;
+      bool sameMachine;
+      bool encodingChange;
+      bool formatChange;
+      int lastUsedEncoding_;
+
+      // Networking and RFB protocol
+      network::Socket* sock;
+      Handle sockEvent;
+      bool reverseConnection;
+      bool requestUpdate;
+
+      // Debugging/logging
+      std::list<Rect> debugRects;
+      CharArray closeReason_;
+      bool isClosed_;
+
+      FileTransfer m_fileTransfer;
+    };
+
+  };
+
+};
+
+#endif
+
+
diff --git a/vncviewer/CConnOptions.cxx b/vncviewer/CConnOptions.cxx
new file mode 100644 (file)
index 0000000..0c35acc
--- /dev/null
@@ -0,0 +1,457 @@
+/* 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.
+ */
+
+#include <vncviewer/CConnOptions.h>
+#include <rfb/Configuration.h>
+#include <rfb/encodings.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/Registry.h>
+#include <rdr/HexInStream.h>
+#include <rdr/HexOutStream.h>
+#include <stdlib.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static StringParameter passwordFile("PasswordFile",
+                                   "Password file for VNC authentication", "");
+
+// - Settings stored in the registry & in .vnc files, by Save Defaults and
+//   Save Configuration respectively.
+
+static BoolParameter useLocalCursor("UseLocalCursor", "Render the mouse cursor locally", true);
+static BoolParameter useDesktopResize("UseDesktopResize", "Support dynamic desktop resizing", true);
+
+static BoolParameter fullColour("FullColor",
+                               "Use full color", true);
+static AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
+
+static IntParameter lowColourLevel("LowColorLevel",
+                         "Color level to use on slow connections. "
+                         "0 = Very Low (8 colors), 1 = Low (64 colors), 2 = Medium (256 colors)",
+                         2);
+static AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
+
+static BoolParameter fullScreen("FullScreen",
+                         "Use the whole display to show the remote desktop."
+                         "(Press F8 to access the viewer menu)",
+                         false);
+static StringParameter preferredEncoding("PreferredEncoding",
+                                        "Preferred encoding to use (Tight, ZRLE, Hextile or"
+                                        " Raw)", "Tight");
+static BoolParameter autoSelect("AutoSelect", 
+                               "Auto select pixel format and encoding. "
+                               "Default if PreferredEncoding and FullColor are not specified.", 
+                               true);
+static BoolParameter sharedConnection("Shared",
+                         "Allow existing connections to the server to continue."
+                         "(Default is to disconnect all other clients)",
+                         false);
+
+static BoolParameter sendPtrEvents("SendPointerEvents",
+                         "Send pointer (mouse) events to the server.", true);
+static BoolParameter sendKeyEvents("SendKeyEvents",
+                         "Send key presses (and releases) to the server.", true);
+static BoolParameter sendSysKeys("SendSysKeys",
+                         "Send system keys (Alt combinations) to the server.", true);
+
+static BoolParameter clientCutText("ClientCutText",
+                         "Send clipboard changes to the server.", true);
+static BoolParameter serverCutText("ServerCutText",
+                         "Accept clipboard changes from the server.", true);
+
+static BoolParameter disableWinKeys("DisableWinKeys",
+                         "Pass special Windows keys directly to the server.", true);
+
+static BoolParameter protocol3_3("Protocol3.3",
+                         "Only use protocol version 3.3", false);
+
+static IntParameter ptrEventInterval("PointerEventInterval",
+                         "The interval to delay between sending one pointer event "
+                         "and the next.", 0);
+static BoolParameter emulate3("Emulate3",
+                         "Emulate middle mouse button when left and right buttons "
+                         "are used simulatenously.", false);
+
+static BoolParameter acceptBell("AcceptBell",
+                         "Produce a system beep when requested to by the server.",
+                         true);
+
+static BoolParameter showToolbar("ShowToolbar", "Show toolbar by default.", true);
+
+static StringParameter monitor("Monitor", "The monitor to open the VNC Viewer window on, if available.", "");
+static StringParameter menuKey("MenuKey", "The key which brings up the popup menu", "F8");
+static BoolParameter autoReconnect("AutoReconnect", "Offer to reconnect to the remote server if the connection"
+                                   "is dropped because an error occurs.", true);
+
+static BoolParameter customCompressLevel("CustomCompressLevel",
+                                        "Use custom compression level. "
+                                        "Default if CompressLevel is specified.", false);
+
+static IntParameter compressLevel("CompressLevel",
+                                 "Use specified compression level"
+                                 "0 = Low, 9 = High",
+                                 6);
+
+static BoolParameter noJpeg("NoJPEG",
+                           "Disable lossy JPEG compression in Tight encoding.",
+                           false);
+
+static IntParameter qualityLevel("QualityLevel",
+                                "JPEG quality level. "
+                                "0 = Low, 9 = High",
+                                6);
+
+CConnOptions::CConnOptions()
+: useLocalCursor(::useLocalCursor), useDesktopResize(::useDesktopResize),
+autoSelect(::autoSelect), fullColour(::fullColour), fullScreen(::fullScreen),
+shared(::sharedConnection), sendPtrEvents(::sendPtrEvents), sendKeyEvents(::sendKeyEvents), sendSysKeys(::sendSysKeys),
+preferredEncoding(encodingZRLE), clientCutText(::clientCutText), serverCutText(::serverCutText),
+disableWinKeys(::disableWinKeys), protocol3_3(::protocol3_3), acceptBell(::acceptBell),
+lowColourLevel(::lowColourLevel), pointerEventInterval(ptrEventInterval),
+emulate3(::emulate3), monitor(::monitor.getData()), showToolbar(::showToolbar),
+customCompressLevel(::customCompressLevel), compressLevel(::compressLevel), 
+noJpeg(::noJpeg), qualityLevel(::qualityLevel), passwordFile(::passwordFile.getData()),
+autoReconnect(::autoReconnect)
+{
+  if (autoSelect) {
+    preferredEncoding = encodingZRLE;
+  } else {
+    CharArray encodingName(::preferredEncoding.getData());
+    preferredEncoding = encodingNum(encodingName.buf);
+  }
+  setMenuKey(CharArray(::menuKey.getData()).buf);
+
+  if (!::autoSelect.hasBeenSet()) {
+      // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used
+    autoSelect = (!::preferredEncoding.hasBeenSet() 
+                 && !::fullColour.hasBeenSet()
+                 && !::fullColourAlias.hasBeenSet());
+  }
+  if (!::customCompressLevel.hasBeenSet()) {
+    // Default to CustomCompressLevel=1 if CompressLevel is used.
+    customCompressLevel = ::compressLevel.hasBeenSet();
+  }
+}
+
+
+void CConnOptions::readFromFile(const char* filename) {
+  FILE* f = fopen(filename, "r");
+  if (!f)
+    throw rdr::Exception("Failed to read configuration file");
+
+  try { 
+    char line[4096];
+    CharArray section;
+
+    CharArray hostTmp;
+    int portTmp = 0;
+
+    while (!feof(f)) {
+      // Read the next line
+      if (!fgets(line, sizeof(line), f)) {
+        if (feof(f))
+          break;
+        throw rdr::SystemException("fgets", ferror(f));
+      }
+      int len=strlen(line);
+      if (line[len-1] == '\n') {
+        line[len-1] = 0;
+        len--;
+      }
+
+      // Process the line
+      if (line[0] == ';') {
+        // Comment
+      } else if (line[0] == '[') {
+        // Entering a new section
+        if (!strSplit(&line[1], ']', &section.buf, 0))
+          throw rdr::Exception("bad Section");
+      } else {
+        // Reading an option
+        CharArray name;
+        CharArray value;
+        if (!strSplit(line, '=', &name.buf, &value.buf))
+          throw rdr::Exception("bad Name/Value pair");
+
+        if (stricmp(section.buf, "Connection") == 0) {
+          if (stricmp(name.buf, "Host") == 0) {
+            hostTmp.replaceBuf(value.takeBuf());
+          } else if (stricmp(name.buf, "Port") == 0) {
+            portTmp = atoi(value.buf);
+          } else if (stricmp(name.buf, "UserName") == 0) {
+            userName.replaceBuf(value.takeBuf());
+          } else if (stricmp(name.buf, "Password") == 0) {
+            ObfuscatedPasswd obfPwd;
+            rdr::HexInStream::hexStrToBin(value.buf, (char**)&obfPwd.buf, &obfPwd.length);
+            PlainPasswd passwd(obfPwd);
+            password.replaceBuf(passwd.takeBuf());
+          }
+        } else if (stricmp(section.buf, "Options") == 0) {
+            // V4 options
+          if (stricmp(name.buf, "UseLocalCursor") == 0) {
+            useLocalCursor = atoi(value.buf);
+          } else if (stricmp(name.buf, "UseDesktopResize") == 0) {
+            useDesktopResize = atoi(value.buf);
+          } else if (stricmp(name.buf, "FullScreen") == 0) {
+            fullScreen = atoi(value.buf);
+          } else if (stricmp(name.buf, "FullColour") == 0) {
+            fullColour = atoi(value.buf);
+          } else if (stricmp(name.buf, "LowColourLevel") == 0) {
+            lowColourLevel = atoi(value.buf);
+          } else if (stricmp(name.buf, "PreferredEncoding") == 0) {
+            preferredEncoding = encodingNum(value.buf);
+          } else if ((stricmp(name.buf, "AutoDetect") == 0) ||
+                     (stricmp(name.buf, "AutoSelect") == 0)) {
+            autoSelect = atoi(value.buf);
+          } else if (stricmp(name.buf, "Shared") == 0) {
+            shared = atoi(value.buf);
+          } else if (stricmp(name.buf, "SendPtrEvents") == 0) {
+            sendPtrEvents = atoi(value.buf);
+          } else if (stricmp(name.buf, "SendKeyEvents") == 0) {
+            sendKeyEvents = atoi(value.buf);
+          } else if (stricmp(name.buf, "SendSysKeys") == 0) {
+            sendSysKeys = atoi(value.buf);
+          } else if (stricmp(name.buf, "SendCutText") == 0) {
+            clientCutText = atoi(value.buf);
+          } else if (stricmp(name.buf, "AcceptCutText") == 0) {
+            serverCutText = atoi(value.buf);
+          } else if (stricmp(name.buf, "DisableWinKeys") == 0) {
+            disableWinKeys = atoi(value.buf);
+          } else if (stricmp(name.buf, "AcceptBell") == 0) {
+            acceptBell = atoi(value.buf);
+          } else if (stricmp(name.buf, "Emulate3") == 0) {
+            emulate3 = atoi(value.buf);
+          } else if (stricmp(name.buf, "ShowToolbar") == 0) {
+            showToolbar = atoi(value.buf);
+          } else if (stricmp(name.buf, "PointerEventInterval") == 0) {
+            pointerEventInterval = atoi(value.buf);
+          } else if (stricmp(name.buf, "Monitor") == 0) {
+            monitor.replaceBuf(value.takeBuf());
+          } else if (stricmp(name.buf, "MenuKey") == 0) {
+            setMenuKey(value.buf);
+          } else if (stricmp(name.buf, "AutoReconnect") == 0) {
+            autoReconnect = atoi(value.buf);
+
+          } else if (stricmp(name.buf, "CustomCompressLevel") == 0) {
+           customCompressLevel = atoi(value.buf);
+          } else if (stricmp(name.buf, "CompressLevel") == 0) {
+           compressLevel = atoi(value.buf);
+          } else if (stricmp(name.buf, "NoJPEG") == 0) {
+           noJpeg = atoi(value.buf);
+          } else if (stricmp(name.buf, "QualityLevel") == 0) {
+           qualityLevel = atoi(value.buf);
+            // Legacy options
+          } else if (stricmp(name.buf, "Preferred_Encoding") == 0) {
+            preferredEncoding = atoi(value.buf);
+          } else if (stricmp(name.buf, "8bit") == 0) {
+            fullColour = !atoi(value.buf);
+          } else if (stricmp(name.buf, "FullScreen") == 0) {
+            fullScreen = atoi(value.buf);
+          } else if (stricmp(name.buf, "ViewOnly") == 0) {
+            sendPtrEvents = sendKeyEvents = !atoi(value.buf);
+          } else if (stricmp(name.buf, "DisableClipboard") == 0) {
+            clientCutText = serverCutText = !atoi(value.buf);
+          }
+        }
+      }
+    }
+    fclose(f); f=0;
+
+    // Process the Host and Port
+    if (hostTmp.buf) {
+      int hostLen = strlen(hostTmp.buf) + 2 + 17;
+      host.replaceBuf(new char[hostLen]);
+      strCopy(host.buf, hostTmp.buf, hostLen);
+      if (portTmp) {
+        strncat(host.buf, "::", hostLen-1);
+        char tmp[16];
+        sprintf(tmp, "%d", portTmp);
+        strncat(host.buf, tmp, hostLen-1);
+      }
+    }
+
+    // If AutoSelect is enabled then override the preferred encoding
+    if (autoSelect)
+      preferredEncoding = encodingZRLE;
+
+    setConfigFileName(filename);
+  } catch (rdr::Exception&) {
+    if (f) fclose(f);
+    throw;
+  }
+}
+
+void CConnOptions::writeToFile(const char* filename) {
+  FILE* f = fopen(filename, "w");
+  if (!f)
+    throw rdr::Exception("Failed to write configuration file");
+
+  try {
+    // - Split server into host and port and save
+    fprintf(f, "[Connection]\n");
+
+    fprintf(f, "Host=%s\n", host.buf);
+    if (userName.buf)
+      fprintf(f, "UserName=%s\n", userName.buf);
+    if (password.buf) {
+      // - Warn the user before saving the password
+      if (MsgBox(0, _T("Do you want to include the VNC Password in this configuration file?\n")
+                    _T("Storing the password is more convenient but poses a security risk."),
+                    MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) == IDYES) {
+        ObfuscatedPasswd obfPwd(password);
+        CharArray obfuscatedHex = rdr::HexOutStream::binToHexStr(obfPwd.buf, obfPwd.length);
+        fprintf(f, "Password=%s\n", obfuscatedHex.buf);
+      }
+    }
+
+    // - Save the other options
+    fprintf(f, "[Options]\n");
+
+    fprintf(f, "UseLocalCursor=%d\n", (int)useLocalCursor);
+    fprintf(f, "UseDesktopResize=%d\n", (int)useDesktopResize);
+    fprintf(f, "FullScreen=%d\n", (int)fullScreen);
+    fprintf(f, "FullColour=%d\n", (int)fullColour);
+    fprintf(f, "LowColourLevel=%d\n", lowColourLevel);
+    fprintf(f, "PreferredEncoding=%s\n", encodingName(preferredEncoding));
+    fprintf(f, "AutoSelect=%d\n", (int)autoSelect);
+    fprintf(f, "Shared=%d\n", (int)shared);
+    fprintf(f, "SendPtrEvents=%d\n", (int)sendPtrEvents);
+    fprintf(f, "SendKeyEvents=%d\n", (int)sendKeyEvents);
+    fprintf(f, "SendSysKeys=%d\n", (int)sendSysKeys);
+    fprintf(f, "SendCutText=%d\n", (int)clientCutText);
+    fprintf(f, "AcceptCutText=%d\n", (int)serverCutText);
+    fprintf(f, "DisableWinKeys=%d\n", (int)disableWinKeys);
+    fprintf(f, "AcceptBell=%d\n", (int)acceptBell);
+    fprintf(f, "Emulate3=%d\n", (int)emulate3);
+    fprintf(f, "ShowToolbar=%d\n", (int)showToolbar);
+    fprintf(f, "PointerEventInterval=%d\n", pointerEventInterval);
+    if (monitor.buf)
+      fprintf(f, "Monitor=%s\n", monitor.buf);
+    fprintf(f, "MenuKey=%s\n", CharArray(menuKeyName()).buf);
+    fprintf(f, "AutoReconnect=%d\n", (int)autoReconnect);
+    fprintf(f, "CustomCompressLevel=%d\n", customCompressLevel);
+    fprintf(f, "CompressLevel=%d\n", compressLevel);
+    fprintf(f, "NoJPEG=%d\n", noJpeg);
+    fprintf(f, "QualityLevel=%d\n", qualityLevel);
+    fclose(f); f=0;
+
+    setConfigFileName(filename);
+  } catch (rdr::Exception&) {
+    if (f) fclose(f);
+    throw;
+  }
+}
+
+
+void CConnOptions::writeDefaults() {
+  RegKey key;
+  key.createKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCviewer4"));
+  key.setBool(_T("UseLocalCursor"), useLocalCursor);
+  key.setBool(_T("UseDesktopResize"), useDesktopResize);
+  key.setBool(_T("FullScreen"), fullScreen);
+  key.setBool(_T("FullColour"), fullColour);
+  key.setInt(_T("LowColourLevel"), lowColourLevel);
+  key.setString(_T("PreferredEncoding"), TStr(encodingName(preferredEncoding)));
+  key.setBool(_T("AutoSelect"), autoSelect);
+  key.setBool(_T("Shared"), shared);
+  key.setBool(_T("SendPointerEvents"), sendPtrEvents);
+  key.setBool(_T("SendKeyEvents"), sendKeyEvents);
+  key.setBool(_T("SendSysKeys"), sendSysKeys);
+  key.setBool(_T("ClientCutText"), clientCutText);
+  key.setBool(_T("ServerCutText"), serverCutText);
+  key.setBool(_T("DisableWinKeys"), disableWinKeys);
+  key.setBool(_T("Protocol3.3"), protocol3_3);
+  key.setBool(_T("AcceptBell"), acceptBell);
+  key.setBool(_T("ShowToolbar"), showToolbar);
+  key.setBool(_T("Emulate3"), emulate3);
+  key.setInt(_T("PointerEventInterval"), pointerEventInterval);
+  if (monitor.buf)
+    key.setString(_T("Monitor"), TStr(monitor.buf));
+  key.setString(_T("MenuKey"), TCharArray(menuKeyName()).buf);
+  key.setBool(_T("AutoReconnect"), autoReconnect);
+  key.setInt(_T("CustomCompressLevel"), customCompressLevel);
+  key.setInt(_T("CompressLevel"), compressLevel);
+  key.setInt(_T("NoJPEG"), noJpeg);
+  key.setInt(_T("QualityLevel"), qualityLevel);
+}
+
+
+void CConnOptions::setUserName(const char* user) {userName.replaceBuf(strDup(user));}
+void CConnOptions::setPassword(const char* pwd) {password.replaceBuf(strDup(pwd));}
+void CConnOptions::setConfigFileName(const char* cfn) {configFileName.replaceBuf(strDup(cfn));}
+void CConnOptions::setHost(const char* h) {host.replaceBuf(strDup(h));}
+void CConnOptions::setMonitor(const char* m) {monitor.replaceBuf(strDup(m));}
+
+void CConnOptions::setMenuKey(const char* keyName) {
+  if (!keyName[0]) {
+    menuKey = 0;
+  } else {
+    menuKey = VK_F8;
+    if (keyName[0] == 'F') {
+      UINT fKey = atoi(&keyName[1]);
+      if (fKey >= 1 && fKey <= 12)
+        menuKey = fKey-1 + VK_F1;
+    }
+  }
+}
+char* CConnOptions::menuKeyName() {
+  int fNum = (menuKey-VK_F1)+1;
+  if (fNum<1 || fNum>12)
+    return strDup("");
+  CharArray menuKeyStr(4);
+  sprintf(menuKeyStr.buf, "F%d", fNum);
+  return menuKeyStr.takeBuf();
+}
+
+
+CConnOptions& CConnOptions::operator=(const CConnOptions& o) {
+  useLocalCursor = o.useLocalCursor;
+  useDesktopResize = o.useDesktopResize;
+  fullScreen = o.fullScreen;
+  fullColour = o.fullColour;
+  lowColourLevel = o.lowColourLevel;
+  preferredEncoding = o.preferredEncoding;
+  autoSelect = o.autoSelect;
+  shared = o.shared;
+  sendPtrEvents = o.sendPtrEvents;
+  sendKeyEvents = o.sendKeyEvents;
+  sendSysKeys = o.sendSysKeys;
+  clientCutText = o.clientCutText;
+  serverCutText = o.serverCutText;
+  disableWinKeys = o.disableWinKeys;
+  emulate3 = o.emulate3;
+  pointerEventInterval = o.pointerEventInterval;
+  protocol3_3 = o.protocol3_3;
+  acceptBell = o.acceptBell;
+  showToolbar = o.showToolbar;
+  setUserName(o.userName.buf);
+  setPassword(o.password.buf);
+  setConfigFileName(o.configFileName.buf);
+  setHost(o.host.buf);
+  setMonitor(o.monitor.buf);
+  menuKey = o.menuKey;
+  autoReconnect = o.autoReconnect;
+  customCompressLevel = o.customCompressLevel;
+  compressLevel = o.compressLevel;
+  noJpeg = o.noJpeg;
+  qualityLevel = o.qualityLevel;
+
+  return *this;
+}
diff --git a/vncviewer/CConnOptions.h b/vncviewer/CConnOptions.h
new file mode 100644 (file)
index 0000000..52c3996
--- /dev/null
@@ -0,0 +1,98 @@
+/* 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.
+ */
+
+// -=- CConnOptions.h
+
+// Definition of the CConnOptions class, responsible for storing the
+// current & requested VNC Viewer options.
+
+#ifndef __RFB_WIN32_CCONN_OPTIONS_H__
+#define __RFB_WIN32_CCONN_OPTIONS_H__
+
+#include <rfb/Password.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    //
+    // -=- Options structure.  Each viewer option has a corresponding
+    //     entry in CConnOptions.  The viewer options are set by calling
+    //     CConn::applyOptions(...)
+    //     The CConnOptions structure automatically picks up the default
+    //     value of each option from the Configuration system
+    //     The readFromFile and writeFromFile methods can be used to load
+    //     and save VNC configuration files.  readFromFile is backwards
+    //     compatible with 3.3 releases, while writeToFile is not.
+
+    class CConnOptions {
+    public:
+      CConnOptions();
+      CConnOptions(const CConnOptions& o) {operator=(o);}
+      CConnOptions& operator=(const CConnOptions& o);
+      void readFromFile(const char* filename_);
+      void writeToFile(const char* filename_);
+      void writeDefaults();
+      bool useLocalCursor;
+      bool useDesktopResize;
+      bool fullScreen;
+      bool fullColour;
+      int lowColourLevel;
+      int preferredEncoding;
+      bool autoSelect;
+      bool shared;
+      bool sendPtrEvents;
+      bool sendKeyEvents;
+      bool sendSysKeys;
+      bool showToolbar;
+      bool clientCutText;
+      bool serverCutText;
+      bool disableWinKeys;
+      bool emulate3;
+      int pointerEventInterval;
+      bool protocol3_3;
+      bool acceptBell;
+      CharArray userName;
+      void setUserName(const char* user);
+      PlainPasswd password;
+      void setPassword(const char* pwd);
+      CharArray configFileName;
+      void setConfigFileName(const char* cfn);
+      CharArray host;
+      void setHost(const char* h);
+      CharArray monitor;
+      void setMonitor(const char* m);
+      unsigned int menuKey;
+      void setMenuKey(const char* keyName);
+      char* menuKeyName();
+      bool autoReconnect;
+
+      bool customCompressLevel;
+      int compressLevel;
+      bool noJpeg;
+      int qualityLevel;
+
+      CharArray passwordFile;
+    };
+
+
+  };
+
+};
+
+#endif
diff --git a/vncviewer/CConnThread.cxx b/vncviewer/CConnThread.cxx
new file mode 100644 (file)
index 0000000..cfd2695
--- /dev/null
@@ -0,0 +1,198 @@
+/* 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.
+ */
+
+// -=- CConnThread.cxx
+
+// A CConnThread instance is created for each new connection.
+// The CConnThread creates the corresponding CConn instance
+// and manages it.
+
+#include <stdlib.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Hostname.h>
+#include <rfb_win32/MsgBox.h>
+#include <network/TcpSocket.h>
+#include <vncviewer/CConnThread.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/ConnectionDialog.h>
+#include <vncviewer/ConnectingDialog.h>
+#include <vncviewer/UserPasswdDialog.h>
+#include <set>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("CConnThread");
+
+static std::set<CConnThread*> threads;
+static Mutex threadsLock;
+static Handle noMoreThreads(CreateEvent(0, TRUE, FALSE, 0));
+
+
+CConnThread::CConnThread() : Thread("CConnThread"), isConfig(false),
+                             sock(0), reverse(false) {
+  vlog.info("CConnThread (dialog)");
+  setDeleteAfterRun();
+  Lock l(threadsLock);
+  threads.insert(this);
+  start();
+}
+
+CConnThread::CConnThread(const char* hostOrConfig_, bool isConfig_)
+ : Thread("CConnThread"), hostOrConfig(strDup(hostOrConfig_)),
+   isConfig(isConfig_), sock(0), reverse(false) {
+  vlog.info("CConnThread (host/port)");
+  setDeleteAfterRun();
+  Lock l(threadsLock);
+  threads.insert(this);
+  start();
+}
+
+CConnThread::CConnThread(network::Socket* sock_, bool reverse_)
+ : Thread("CConnThread"), isConfig(false), sock(sock_), reverse(reverse_) {
+  vlog.info("CConnThread (reverse connection)");
+  setDeleteAfterRun();
+  Lock l(threadsLock);
+  threads.insert(this);
+  start();
+}
+
+CConnThread::~CConnThread() {
+  Lock l(threadsLock);
+  threads.erase(this);
+  if (threads.empty())
+    SetEvent(noMoreThreads);
+  delete sock;
+}
+
+
+void CConnThread::run() {
+  CConnOptions options;
+  bool reconnect;
+
+  do {
+    {
+      CConn conn;
+      reconnect = false;
+
+      // If there is no socket object then set the host & port info
+      if (!sock && !options.host.buf) {
+        try {
+          if (isConfig) {
+            // A configuration file name was specified - load it
+            CharArray filename = hostOrConfig.takeBuf();
+            options.readFromFile(filename.buf);
+          } else {
+            // An actual hostname (and possibly port) was specified
+            options.host.replaceBuf(hostOrConfig.takeBuf());
+          }
+
+          if (!options.host.buf) {
+            // No host was specified - prompt for one
+            ConnectionDialog connDlg(&conn);
+            if (!connDlg.showDialog())
+              return;
+            options = conn.getOptions();
+            options.setHost(CStr(connDlg.hostname.buf));
+          }
+        } catch (rdr::Exception& e) {
+          MsgBox(0, TStr(e.str()), MB_ICONERROR | MB_OK);
+          return;
+        }
+      }
+
+      // Apply the connection options to the CConn
+      conn.applyOptions(options);
+
+      if (!sock) {
+        // There is no existing connection - better make one
+        const char* hostAndPort = conn.getOptions().host.buf;
+
+        try {
+          ConnectingDialog dlg;
+          sock = dlg.connect(hostAndPort);
+
+          // If the connection was cancelled by the user, just quit
+          if (!sock)
+            return;
+        } catch(rdr::Exception& e) {
+          MsgBox(NULL, TStr(e.str()), MB_ICONERROR | MB_OK);
+          return;
+        }
+
+        // Try to add the caller to the MRU
+        MRU::addToMRU(hostAndPort);
+      }
+
+      // Run the RFB protocol over the connected socket
+      conn.initialise(sock, reverse);
+      while (!conn.isClosed()) {
+        try {
+          conn.getInStream()->check(1,1);
+          conn.processMsg();
+        } catch (rdr::EndOfStream) {
+          if (conn.state() == CConnection::RFBSTATE_NORMAL)
+            conn.close();
+          else
+            conn.close("The connection closed unexpectedly");
+        } catch (rfb::AuthCancelledException) {
+          conn.close();
+        } catch (rfb::AuthFailureException& e) {
+          // Clear the password, in case we auto-reconnect
+          options = conn.getOptions();
+          options.password.replaceBuf(0);
+          conn.applyOptions(options);
+          conn.close(e.str());
+        } catch (rdr::Exception& e) {
+          conn.close(e.str());
+        }
+      }
+
+      // If there is a cause for closing the connection logged then display it
+      if (conn.closeReason()) {
+        reconnect = !reverse && conn.getOptions().autoReconnect;
+        if (!reconnect) {
+          MsgBox(0, TStr(conn.closeReason()), MB_ICONINFORMATION | MB_OK);
+        } else {
+          options = conn.getOptions();
+          const char* format = "%s\nDo you wish to attempt to reconnect to %s?";
+          CharArray message(strlen(conn.closeReason()) + strlen(format) +
+                            strlen(conn.getOptions().host.buf));
+          sprintf(message.buf, format, conn.closeReason(), conn.getOptions().host.buf);
+          if (MsgBox(0, TStr(message.buf), MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES)
+            reconnect = false;
+        }
+      }
+    } // Exit the CConn's scope, implicitly destroying it & making it safe to delete the TcpSocket
+
+    // Clean up the old socket, if any
+    delete sock; sock = 0;
+  } while (reconnect);
+}
+
+
+BOOL CConnThread::getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg) {
+  while (!PeekMessage(msg, hwnd, minMsg, maxMsg, PM_REMOVE)) {
+    DWORD result = MsgWaitForMultipleObjects(1, &noMoreThreads.h, FALSE, INFINITE, QS_ALLINPUT);
+    if (result == WAIT_OBJECT_0)
+      return FALSE;
+    else if (result == WAIT_FAILED)
+      throw rdr::SystemException("CConnThread::getMessage wait failed", GetLastError());
+  }
+  return msg->message != WM_QUIT;
+}
diff --git a/vncviewer/CConnThread.h b/vncviewer/CConnThread.h
new file mode 100644 (file)
index 0000000..7a8451c
--- /dev/null
@@ -0,0 +1,57 @@
+/* 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.
+ */
+
+// -=- CConnThread.h
+
+// CConn-managing Thread implementation.
+
+#ifndef __RFB_WIN32_CCONN_THREAD_H__
+#define __RFB_WIN32_CCONN_THREAD_H__
+
+#include <network/Socket.h>
+#include <rfb/Threading.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+  namespace win32 {
+
+    class CConnThread : public Thread {
+    public:
+      CConnThread();
+      CConnThread(const char* hostOrConfig, bool isConfig=false);
+      CConnThread(network::Socket* sock, bool reverse=false);
+      ~CConnThread();
+
+      void run();
+
+      // Special getMessage call that returns FALSE if message is WM_QUIT,
+      // OR if there are no more CConnThreads running.
+      static BOOL getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg);
+    protected:
+      CharArray hostOrConfig;
+      bool isConfig;
+      network::Socket* sock;
+      bool reverse;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_CCONN_THREAD_H__
diff --git a/vncviewer/CViewManager.cxx b/vncviewer/CViewManager.cxx
deleted file mode 100644 (file)
index 09ed1fe..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/* Copyright (C) 2002-2003 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.
- */
-#include <winsock2.h>
-#include <vncviewer/CViewManager.h>
-#include <vncviewer/CView.h>
-#include <vncviewer/ConnectionDialog.h>
-#include <vncviewer/ConnectingDialog.h>
-#include <rfb/Hostname.h>
-#include <rfb/util.h>
-#include <rfb/LogWriter.h>
-#include <rfb/vncAuth.h>
-#include <rdr/HexInStream.h>
-#include <network/TcpSocket.h>
-
-using namespace rfb;
-using namespace win32;
-
-static LogWriter vlog("CViewManager");
-
-
-// -=- Custom thread class used internally
-
-class CViewThread : public Thread {
-public:
-  CViewThread(network::Socket* s, CViewManager& cvm);
-  CViewThread(const char* conninfo, CViewManager& cvm, bool infoIsConfigFile);
-  virtual ~CViewThread();
-
-  virtual void run();
-protected:
-  void setSocket(network::Socket* sock);
-
-  network::Socket* sock;
-  CharArray hostname;
-  CViewManager& manager;
-
-  bool useConfigFile;
-};
-
-
-CViewThread::CViewThread(network::Socket* s, CViewManager& cvm)
-: Thread("CView"), sock(s), manager(cvm) {
-  setDeleteAfterRun();
-}
-
-CViewThread::CViewThread(const char* h, CViewManager& cvm, bool hIsConfigFile)
-: Thread("CView"), sock(0), manager(cvm), useConfigFile(hIsConfigFile) {
-  setDeleteAfterRun();
-  if (h) hostname.buf = strDup(h);
-}
-
-
-CViewThread::~CViewThread() {
-  vlog.debug("~CViewThread");
-  manager.remThread(this);
-  delete sock;
-}
-
-
-void CViewThread::run() {
-  try {
-    CView view;
-    view.setManager(&manager);
-
-    if (!sock) {
-      try {
-        // If the hostname is actually a config filename then read it
-        if (useConfigFile) {
-          CharArray filename = hostname.takeBuf();
-          CViewOptions options;
-          options.readFromFile(filename.buf);
-          if (options.host.buf)
-            hostname.buf = strDup(options.host.buf);
-          view.applyOptions(options);
-        }
-
-        // If there is no hostname then present the connection
-        // dialog
-        if (!hostname.buf) {
-          ConnectionDialog conn(&view);
-          if (!conn.showDialog())
-            return;
-          hostname.buf = strDup(conn.hostname.buf);
-
-          // *** hack - Tell the view object the hostname
-          CViewOptions opt(view.getOptions());
-          opt.setHost(hostname.buf);
-          view.applyOptions(opt);
-        }
-
-        // Parse the host name & port
-        CharArray host;
-        int port;
-        getHostAndPort(hostname.buf, &host.buf, &port);
-
-        // Attempt to connect
-        ConnectingDialog dlg;
-        // this is a nasty hack to get round a Win2K and later "feature" which
-        // puts your second window in the background unless the first window
-        // you put up actually gets some input.  Just generate a fake shift
-        // event, which seems to do the trick.
-        keybd_event(VK_SHIFT, MapVirtualKey(VK_SHIFT, 0), 0, 0);
-        keybd_event(VK_SHIFT, MapVirtualKey(VK_SHIFT, 0), KEYEVENTF_KEYUP, 0);
-        sock = new network::TcpSocket(host.buf, port);
-      } catch(rdr::Exception& e) {
-        vlog.error("unable to connect to %s (%s)", hostname, e.str());
-        MsgBox(NULL, TStr(e.str()), MB_ICONERROR | MB_OK);
-        return;
-      }
-
-      // Try to add the caller to the MRU
-      MRU::addToMRU(hostname.buf);
-    }
-
-    view.initialise(sock);
-    try {
-      view.postQuitOnDestroy(true);
-      while (true) {
-        // - processMsg is designed to be callable in response to select().
-        //   As a result, it can be called when FdInStream data is available,
-        //   BUT there may be no actual RFB data available.  This is the case
-        //   for example when reading data over an encrypted stream - an
-        //   entire block must be read from the FdInStream before any data
-        //   becomes available through the top-level encrypted stream.
-        //   Since we are using blockCallback and not doing a select() here,
-        //   we simply check() for some data on the top-level RFB stream.
-        //   This ensures that processMsg will only be called when there is
-        //   actually something to do.  In the meantime, blockCallback()
-        //   will be called, keeping the user interface responsive.
-        view.getInStream()->check(1,1);
-        view.processMsg();
-      }
-    } catch (CView::QuitMessage& e) {
-      // - Cope silently with WM_QUIT messages
-      vlog.debug("QuitMessage received (wParam=%d)", e.wParam);
-    } catch (rdr::EndOfStream& e) {
-      // - Copy silently with disconnection if in NORMAL state
-      if (view.state() == CConnection::RFBSTATE_NORMAL)
-        vlog.debug(e.str());
-      else {
-        view.postQuitOnDestroy(false);
-        throw rfb::Exception("server closed connection unexpectedly");
-      }
-    } catch (rdr::Exception&) {
-      // - We MUST do this, otherwise ~CView will cause a
-      //   PostQuitMessage and any MessageBox call will quit immediately.
-      view.postQuitOnDestroy(false);
-      throw;
-    }
-  } catch(rdr::Exception& e) {
-    // - Something went wrong - display the error
-    vlog.error("error: %s", e.str());
-    MsgBox(NULL, TStr(e.str()), MB_ICONERROR | MB_OK);
-  }
-}
-
-
-// -=- CViewManager itself
-
-CViewManager::CViewManager()
-: MsgWindow(_T("CViewManager")), threadsSig(threadsMutex),
-  mainThread(Thread::self()) {
-}
-
-CViewManager::~CViewManager() {
-  while (!socks.empty()) {
-    network::SocketListener* sock = socks.front();
-    delete sock;
-    socks.pop_front();
-  }
-  awaitEmpty();
-}
-
-
-void CViewManager::awaitEmpty() {
-  Lock l(threadsMutex);
-  while (!threads.empty()) {
-    threadsSig.wait(true);
-  }
-}
-
-
-void CViewManager::addThread(Thread* t) {
-  Lock l(threadsMutex);
-  threads.push_front(t);
-}
-
-void CViewManager::remThread(Thread* t) {
-  Lock l(threadsMutex);
-  threads.remove(t);
-  threadsSig.signal();
-
-  // If there are no listening sockets then post a quit message when the
-  // last client disconnects
-  if (socks.empty())
-    PostThreadMessage(mainThread->getThreadId(), WM_QUIT, 0, 0);
-}
-
-
-bool CViewManager::addClient(const char* hostinfo, bool isConfigFile) {
-  CViewThread* thread = new CViewThread(hostinfo, *this, isConfigFile);
-  addThread(thread);
-  thread->start();
-  return true;
-}
-
-bool CViewManager::addListener(network::SocketListener* sock) {
-  socks.push_back(sock);
-  WSAAsyncSelect(sock->getFd(), getHandle(), WM_USER, FD_ACCEPT);
-  return true;
-}
-
-bool CViewManager::addDefaultTCPListener(int port) {
-  return addListener(new network::TcpListener(port));
-}
-
-
-LRESULT CViewManager::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
-  switch (msg) {
-  case WM_USER:
-    std::list<network::SocketListener*>::iterator i;
-    for (i=socks.begin(); i!=socks.end(); i++) {
-      if (wParam == (*i)->getFd()) {
-        network::Socket* new_sock = (*i)->accept();
-        CharArray connname;
-        connname.buf = new_sock->getPeerEndpoint();
-        vlog.debug("accepted connection: %s", connname);
-        CViewThread* thread = new CViewThread(new_sock, *this);
-        addThread(thread);
-        thread->start();
-        break;
-      }
-    }
-    break;
-  }
-  return MsgWindow::processMessage(msg, wParam, lParam);
-}
diff --git a/vncviewer/CViewManager.h b/vncviewer/CViewManager.h
deleted file mode 100644 (file)
index 3d11dd9..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Copyright (C) 2002-2003 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.
- */
-
-// -=- CViewManager.h
-
-// Creates and manages threads to run CView instances.
-
-#ifndef __RFB_WIN32_CVIEW_MANAGER_H__
-#define __RFB_WIN32_CVIEW_MANAGER_H__
-
-#include <list>
-#include <network/Socket.h>
-#include <rfb/Threading.h>
-#include <rfb_win32/MsgWindow.h>
-
-namespace rfb {
-
-  namespace win32 {
-
-    class CViewManager : public MsgWindow {
-    public:
-      CViewManager();
-      ~CViewManager();
-
-      void awaitEmpty();
-
-      void addThread(Thread* t);
-      void remThread(Thread* t);
-
-      bool addClient(const char* hostinfo, bool isConfigFile=false);
-
-      bool addListener(network::SocketListener* sock);
-      bool addDefaultTCPListener(int port);
-
-      LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
-
-    protected:
-      std::list<network::SocketListener*> socks;
-      std::list<Thread*> threads;
-      Mutex threadsMutex;
-      Condition threadsSig;
-      Thread* mainThread;
-    };
-
-  };
-
-};
-
-#endif
diff --git a/vncviewer/CViewOptions.cxx b/vncviewer/CViewOptions.cxx
deleted file mode 100644 (file)
index 76a624b..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-/* Copyright (C) 2002-2004 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.
- */
-
-#include <vncviewer/CViewOptions.h>
-#include <rfb/Configuration.h>
-#include <rfb/encodings.h>
-#include <rfb/vncAuth.h>
-#include <rfb/LogWriter.h>
-#include <rfb_win32/Win32Util.h>
-#include <rfb_win32/Registry.h>
-#include <rdr/HexInStream.h>
-#include <rdr/HexOutStream.h>
-#include <stdlib.h>
-
-using namespace rfb;
-using namespace rfb::win32;
-
-static StringParameter passwordFile("PasswordFile",
-                                   "Password file for VNC authentication", "");
-
-static BoolParameter useLocalCursor("UseLocalCursor", "Render the mouse cursor locally", true);
-static BoolParameter useDesktopResize("UseDesktopResize", "Support dynamic desktop resizing", true);
-
-static BoolParameter fullColour("FullColor",
-                               "Use full color", true);
-static AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
-
-static IntParameter lowColourLevel("LowColorLevel",
-                         "Color level to use on slow connections. "
-                         "0 = Very Low (8 colors), 1 = Low (64 colors), 2 = Medium (256 colors)",
-                         2);
-static AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
-
-static BoolParameter fullScreen("FullScreen",
-                         "Use the whole display to show the remote desktop."
-                         "(Press F8 to access the viewer menu)",
-                         false);
-static StringParameter preferredEncoding("PreferredEncoding",
-                                        "Preferred encoding to use (Tight, ZRLE, Hextile or"
-                                        " Raw)", "Tight");
-static BoolParameter autoSelect("AutoSelect", 
-                               "Auto select pixel format and encoding. "
-                               "Default if PreferredEncoding and FullColor are not specified.", 
-                               true);
-static BoolParameter sharedConnection("Shared",
-                         "Allow existing connections to the server to continue."
-                         "(Default is to disconnect all other clients)",
-                         false);
-
-static BoolParameter sendPtrEvents("SendPointerEvents",
-                         "Send pointer (mouse) events to the server.", true);
-static BoolParameter sendKeyEvents("SendKeyEvents",
-                         "Send key presses (and releases) to the server.", true);
-static BoolParameter sendSysKeys("SendSysKeys",
-                         "Send system keys (Alt combinations) to the server.", true);
-
-static BoolParameter clientCutText("ClientCutText",
-                         "Send clipboard changes to the server.", true);
-static BoolParameter serverCutText("ServerCutText",
-                         "Accept clipboard changes from the server.", true);
-
-static BoolParameter protocol3_3("Protocol3.3",
-                         "Only use protocol version 3.3", false);
-
-static IntParameter ptrEventInterval("PointerEventInterval",
-                         "The interval to delay between sending one pointer event "
-                         "and the next.", 0);
-static BoolParameter emulate3("Emulate3",
-                         "Emulate middle mouse button when left and right buttons "
-                         "are used simulatenously.", false);
-
-static BoolParameter acceptBell("AcceptBell",
-                         "Produce a system beep when requested to by the server.",
-                         true);
-
-static BoolParameter showToolbar("ShowToolbar", "Show toolbar by default.", true);
-
-static StringParameter monitor("Monitor", "The monitor to open the VNC Viewer window on, if available.", "");
-static StringParameter menuKey("MenuKey", "The key which brings up the popup menu", "F8");
-
-static BoolParameter customCompressLevel("CustomCompressLevel",
-                                        "Use custom compression level. "
-                                        "Default if CompressLevel is specified.", false);
-
-static IntParameter compressLevel("CompressLevel",
-                                 "Use specified compression level"
-                                 "0 = Low, 9 = High",
-                                 6);
-
-static BoolParameter noJpeg("NoJPEG",
-                           "Disable lossy JPEG compression in Tight encoding.",
-                           false);
-
-static IntParameter qualityLevel("QualityLevel",
-                                "JPEG quality level. "
-                                "0 = Low, 9 = High",
-                                6);
-
-CViewOptions::CViewOptions()
-: useLocalCursor(::useLocalCursor), useDesktopResize(::useDesktopResize),
-autoSelect(::autoSelect), fullColour(::fullColour), fullScreen(::fullScreen),
-shared(::sharedConnection), sendPtrEvents(::sendPtrEvents), sendKeyEvents(::sendKeyEvents), sendSysKeys(::sendSysKeys),
-preferredEncoding(encodingZRLE), clientCutText(::clientCutText), serverCutText(::serverCutText),
-protocol3_3(::protocol3_3), acceptBell(::acceptBell), showToolbar(::showToolbar), lowColourLevel(::lowColourLevel),
-pointerEventInterval(ptrEventInterval), emulate3(::emulate3), monitor(::monitor.getData()),
-customCompressLevel(::customCompressLevel), compressLevel(::compressLevel), 
-noJpeg(::noJpeg), qualityLevel(::qualityLevel), passwordFile(::passwordFile.getData())
-{
-  CharArray encodingName(::preferredEncoding.getData());
-  preferredEncoding = encodingNum(encodingName.buf);
-  setMenuKey(CharArray(::menuKey.getData()).buf);
-
-  if (!::autoSelect.hasBeenSet()) {
-      // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used
-    autoSelect = (!::preferredEncoding.hasBeenSet() 
-                 && !::fullColour.hasBeenSet()
-                 && !::fullColourAlias.hasBeenSet());
-  }
-  if (!::customCompressLevel.hasBeenSet()) {
-    // Default to CustomCompressLevel=1 if CompressLevel is used.
-    customCompressLevel = ::compressLevel.hasBeenSet();
-  }
-}
-
-
-void CViewOptions::readFromFile(const char* filename) {
-  FILE* f = fopen(filename, "r");
-  if (!f)
-    throw rdr::Exception("Failed to read configuration file");
-
-  try { 
-    char line[4096];
-    CharArray section;
-
-    CharArray hostTmp;
-    int portTmp = 0;
-
-    while (!feof(f)) {
-      // Read the next line
-      if (!fgets(line, sizeof(line), f)) {
-        if (feof(f))
-          break;
-        throw rdr::SystemException("fgets", ferror(f));
-      }
-      int len=strlen(line);
-      if (line[len-1] == '\n') {
-        line[len-1] = 0;
-        len--;
-      }
-
-      // Process the line
-      if (line[0] == ';') {
-        // Comment
-      } else if (line[0] == '[') {
-        // Entering a new section
-        if (!strSplit(&line[1], ']', &section.buf, 0))
-          throw rdr::Exception("bad Section");
-      } else {
-        // Reading an option
-        CharArray name;
-        CharArray value;
-        if (!strSplit(line, '=', &name.buf, &value.buf))
-          throw rdr::Exception("bad Name/Value pair");
-
-        if (stricmp(section.buf, "Connection") == 0) {
-          if (stricmp(name.buf, "Host") == 0) {
-            hostTmp.replaceBuf(value.takeBuf());
-          } else if (stricmp(name.buf, "Port") == 0) {
-            portTmp = atoi(value.buf);
-          } else if (stricmp(name.buf, "UserName") == 0) {
-            userName.replaceBuf(value.takeBuf());
-          } else if (stricmp(name.buf, "Password") == 0) {
-            int len = 0;
-            CharArray obfuscated;
-            rdr::HexInStream::hexStrToBin(value.buf, &obfuscated.buf, &len);
-            if (len == 8) {
-              password.replaceBuf(new char[9]);
-              memcpy(password.buf, obfuscated.buf, 8);
-              vncAuthUnobfuscatePasswd(password.buf);
-              password.buf[8] = 0;
-            }
-          }
-        } else if (stricmp(section.buf, "Options") == 0) {
-            // V4 options
-          if (stricmp(name.buf, "UseLocalCursor") == 0) {
-            useLocalCursor = atoi(value.buf);
-          } else if (stricmp(name.buf, "UseDesktopResize") == 0) {
-            useDesktopResize = atoi(value.buf);
-          } else if (stricmp(name.buf, "FullScreen") == 0) {
-            fullScreen = atoi(value.buf);
-          } else if (stricmp(name.buf, "FullColour") == 0) {
-            fullColour = atoi(value.buf);
-          } else if (stricmp(name.buf, "LowColourLevel") == 0) {
-            lowColourLevel = atoi(value.buf);
-          } else if (stricmp(name.buf, "PreferredEncoding") == 0) {
-            preferredEncoding = encodingNum(value.buf);
-          } else if ((stricmp(name.buf, "AutoDetect") == 0) ||
-                     (stricmp(name.buf, "AutoSelect") == 0)) {
-            autoSelect = atoi(value.buf);
-          } else if (stricmp(name.buf, "Shared") == 0) {
-            shared = atoi(value.buf);
-          } else if (stricmp(name.buf, "SendPtrEvents") == 0) {
-            sendPtrEvents = atoi(value.buf);
-          } else if (stricmp(name.buf, "SendKeyEvents") == 0) {
-            sendKeyEvents = atoi(value.buf);
-          } else if (stricmp(name.buf, "SendSysKeys") == 0) {
-            sendSysKeys = atoi(value.buf);
-          } else if (stricmp(name.buf, "SendCutText") == 0) {
-            clientCutText = atoi(value.buf);
-          } else if (stricmp(name.buf, "AcceptCutText") == 0) {
-            serverCutText = atoi(value.buf);
-          } else if (stricmp(name.buf, "AcceptBell") == 0) {
-            acceptBell = atoi(value.buf);
-          } else if (stricmp(name.buf, "Emulate3") == 0) {
-            emulate3 = atoi(value.buf);
-          } else if (stricmp(name.buf, "ShowToolbar") == 0) {
-            showToolbar = atoi(value.buf);
-          } else if (stricmp(name.buf, "PointerEventInterval") == 0) {
-            pointerEventInterval = atoi(value.buf);
-          } else if (stricmp(name.buf, "Monitor") == 0) {
-            monitor.replaceBuf(value.takeBuf());
-          } else if (stricmp(name.buf, "MenuKey") == 0) {
-            setMenuKey(value.buf);
-          } else if (stricmp(name.buf, "CustomCompressLevel") == 0) {
-           customCompressLevel = atoi(value.buf);
-          } else if (stricmp(name.buf, "CompressLevel") == 0) {
-           compressLevel = atoi(value.buf);
-          } else if (stricmp(name.buf, "NoJPEG") == 0) {
-           noJpeg = atoi(value.buf);
-          } else if (stricmp(name.buf, "QualityLevel") == 0) {
-           qualityLevel = atoi(value.buf);
-            // Legacy options
-          } else if (stricmp(name.buf, "Preferred_Encoding") == 0) {
-            preferredEncoding = atoi(value.buf);
-          } else if (stricmp(name.buf, "8bit") == 0) {
-            fullColour = !atoi(value.buf);
-          } else if (stricmp(name.buf, "FullScreen") == 0) {
-            fullScreen = atoi(value.buf);
-          } else if (stricmp(name.buf, "ViewOnly") == 0) {
-            sendPtrEvents = sendKeyEvents = !atoi(value.buf);
-          } else if (stricmp(name.buf, "DisableClipboard") == 0) {
-            clientCutText = serverCutText = !atoi(value.buf);
-          }
-        }
-      }
-    }
-    fclose(f); f=0;
-
-    // Process the Host and Port
-    if (hostTmp.buf) {
-      int hostLen = strlen(hostTmp.buf) + 2 + 17;
-      host.replaceBuf(new char[hostLen]);
-      strCopy(host.buf, hostTmp.buf, hostLen);
-      if (portTmp) {
-        strncat(host.buf, "::", hostLen-1);
-        char tmp[16];
-        sprintf(tmp, "%d", portTmp);
-        strncat(host.buf, tmp, hostLen-1);
-      }
-    }
-
-    setConfigFileName(filename);
-  } catch (rdr::Exception&) {
-    if (f) fclose(f);
-    throw;
-  }
-}
-
-void CViewOptions::writeToFile(const char* filename) {
-  FILE* f = fopen(filename, "w");
-  if (!f)
-    throw rdr::Exception("Failed to write configuration file");
-
-  try {
-    // - Split server into host and port and save
-    fprintf(f, "[Connection]\n");
-
-    fprintf(f, "Host=%s\n", host.buf);
-    if (userName.buf)
-      fprintf(f, "UserName=%s\n", userName.buf);
-    if (password.buf) {
-      // - Warn the user before saving the password
-      if (MsgBox(0, _T("Do you want to include the VNC Password in this configuration file?\n")
-                    _T("Storing the password is more convenient but poses a security risk."),
-                    MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) == IDYES) {
-        char obfuscated[9];
-        memset(obfuscated, 0, sizeof(obfuscated));
-        strCopy(obfuscated, password.buf, sizeof(obfuscated));
-        vncAuthObfuscatePasswd(obfuscated);
-        CharArray obfuscatedHex = rdr::HexOutStream::binToHexStr(obfuscated, 8);
-        fprintf(f, "Password=%s\n", obfuscatedHex.buf);
-      }
-    }
-
-    // - Save the other options
-    fprintf(f, "[Options]\n");
-
-    fprintf(f, "UseLocalCursor=%d\n", (int)useLocalCursor);
-    fprintf(f, "UseDesktopResize=%d\n", (int)useDesktopResize);
-    fprintf(f, "FullScreen=%d\n", (int)fullScreen);
-    fprintf(f, "FullColour=%d\n", (int)fullColour);
-    fprintf(f, "LowColourLevel=%d\n", lowColourLevel);
-    fprintf(f, "PreferredEncoding=%s\n", encodingName(preferredEncoding));
-    fprintf(f, "AutoSelect=%d\n", (int)autoSelect);
-    fprintf(f, "Shared=%d\n", (int)shared);
-    fprintf(f, "SendPtrEvents=%d\n", (int)sendPtrEvents);
-    fprintf(f, "SendKeyEvents=%d\n", (int)sendKeyEvents);
-    fprintf(f, "SendSysKeys=%d\n", (int)sendSysKeys);
-    fprintf(f, "SendCutText=%d\n", (int)clientCutText);
-    fprintf(f, "AcceptCutText=%d\n", (int)serverCutText);
-    fprintf(f, "AcceptBell=%d\n", (int)acceptBell);
-    fprintf(f, "Emulate3=%d\n", (int)emulate3);
-    fprintf(f, "ShowToolbar=%d\n", (int)showToolbar);
-    fprintf(f, "PointerEventInterval=%d\n", pointerEventInterval);
-    if (monitor.buf)
-      fprintf(f, "Monitor=%s\n", monitor.buf);
-    fprintf(f, "MenuKey=%s\n", CharArray(menuKeyName()).buf);
-    fprintf(f, "CustomCompressLevel=%d\n", customCompressLevel);
-    fprintf(f, "CompressLevel=%d\n", compressLevel);
-    fprintf(f, "NoJPEG=%d\n", noJpeg);
-    fprintf(f, "QualityLevel=%d\n", qualityLevel);
-    fclose(f); f=0;
-
-    setConfigFileName(filename);
-  } catch (rdr::Exception&) {
-    if (f) fclose(f);
-    throw;
-  }
-}
-
-
-void CViewOptions::writeDefaults() {
-  RegKey key;
-  key.createKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCviewer4"));
-  key.setBool(_T("UseLocalCursor"), useLocalCursor);
-  key.setBool(_T("UseDesktopResize"), useDesktopResize);
-  key.setBool(_T("FullScreen"), fullScreen);
-  key.setBool(_T("FullColour"), fullColour);
-  key.setInt(_T("LowColourLevel"), lowColourLevel);
-  key.setString(_T("PreferredEncoding"), TStr(encodingName(preferredEncoding)));
-  key.setBool(_T("AutoSelect"), autoSelect);
-  key.setBool(_T("Shared"), shared);
-  key.setBool(_T("SendPointerEvents"), sendPtrEvents);
-  key.setBool(_T("SendKeyEvents"), sendKeyEvents);
-  key.setBool(_T("SendSysKeys"), sendSysKeys);
-  key.setBool(_T("ClientCutText"), clientCutText);
-  key.setBool(_T("ServerCutText"), serverCutText);
-  key.setBool(_T("Protocol3.3"), protocol3_3);
-  key.setBool(_T("AcceptBell"), acceptBell);
-  key.setBool(_T("ShowToolbar"), showToolbar);
-  key.setBool(_T("Emulate3"), emulate3);
-  key.setInt(_T("PointerEventInterval"), pointerEventInterval);
-  if (monitor.buf)
-    key.setString(_T("Monitor"), TStr(monitor.buf));
-  key.setString(_T("MenuKey"), TCharArray(menuKeyName()).buf);
-  key.setInt(_T("CustomCompressLevel"), customCompressLevel);
-  key.setInt(_T("CompressLevel"), compressLevel);
-  key.setInt(_T("NoJPEG"), noJpeg);
-  key.setInt(_T("QualityLevel"), qualityLevel);
-}
-
-
-void CViewOptions::setUserName(const char* user) {userName.replaceBuf(strDup(user));}
-void CViewOptions::setPassword(const char* pwd) {password.replaceBuf(strDup(pwd));}
-void CViewOptions::setConfigFileName(const char* cfn) {configFileName.replaceBuf(strDup(cfn));}
-void CViewOptions::setHost(const char* h) {host.replaceBuf(strDup(h));}
-void CViewOptions::setMonitor(const char* m) {monitor.replaceBuf(strDup(m));}
-
-void CViewOptions::setMenuKey(const char* keyName) {
-  if (!keyName[0]) {
-    menuKey = 0;
-  } else {
-    menuKey = VK_F8;
-    if (keyName[0] == 'F') {
-      UINT fKey = atoi(&keyName[1]);
-      if (fKey >= 1 && fKey <= 12)
-        menuKey = fKey-1 + VK_F1;
-    }
-  }
-}
-char* CViewOptions::menuKeyName() {
-  int fNum = (menuKey-VK_F1)+1;
-  if (fNum<1 || fNum>12)
-    return strDup("");
-  CharArray menuKeyStr(4);
-  sprintf(menuKeyStr.buf, "F%d", fNum);
-  return menuKeyStr.takeBuf();
-}
-
-
-CViewOptions& CViewOptions::operator=(const CViewOptions& o) {
-  useLocalCursor = o.useLocalCursor;
-  useDesktopResize = o.useDesktopResize;
-  fullScreen = o.fullScreen;
-  fullColour = o.fullColour;
-  lowColourLevel = o.lowColourLevel;
-  preferredEncoding = o.preferredEncoding;
-  autoSelect = o.autoSelect;
-  shared = o.shared;
-  sendPtrEvents = o.sendPtrEvents;
-  sendKeyEvents = o.sendKeyEvents;
-  sendSysKeys = o.sendSysKeys;
-  clientCutText = o.clientCutText;
-  serverCutText = o.serverCutText;
-  emulate3 = o.emulate3;
-  pointerEventInterval = o.pointerEventInterval;
-  protocol3_3 = o.protocol3_3;
-  acceptBell = o.acceptBell;
-  showToolbar = o.showToolbar;
-  setUserName(o.userName.buf);
-  setPassword(o.password.buf);
-  setConfigFileName(o.configFileName.buf);
-  setHost(o.host.buf);
-  setMonitor(o.monitor.buf);
-  menuKey = o.menuKey;
-  customCompressLevel = o.customCompressLevel;
-  compressLevel = o.compressLevel;
-  noJpeg = o.noJpeg;
-  qualityLevel = o.qualityLevel;
-
-  return *this;
-}
diff --git a/vncviewer/CViewOptions.h b/vncviewer/CViewOptions.h
deleted file mode 100644 (file)
index febd284..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Copyright (C) 2002-2004 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.
- */
-
-// -=- CViewOptions.h
-
-// Definition of the CViewOptions class, responsible for storing the
-// current & requested VNCviewer options.
-
-#ifndef __RFB_WIN32_CVIEW_OPTIONS_H__
-#define __RFB_WIN32_CVIEW_OPTIONS_H__
-
-#include <rfb/util.h>
-
-namespace rfb {
-
-  namespace win32 {
-
-    //
-    // -=- Options structure.  Each viewer option has a corresponding
-    //     entry in CViewOptions.  The viewer options are set by calling
-    //     CView::applyOptions(...)
-    //     The CViewOptions structure automatically picks up the default
-    //     value of each option from the Configuration system
-    //     The readFromFile and writeFromFile methods can be used to load
-    //     and save VNC configuration files.  readFromFile is backwards
-    //     compatible with 3.3 releases, while writeToFile is not.
-
-    class CViewOptions {
-    public:
-      CViewOptions();
-      CViewOptions(const CViewOptions& o) {operator=(o);}
-      CViewOptions& operator=(const CViewOptions& o);
-      void readFromFile(const char* filename_);
-      void writeToFile(const char* filename_);
-      void writeDefaults();
-      bool useLocalCursor;
-      bool useDesktopResize;
-      bool fullScreen;
-      bool fullColour;
-      int lowColourLevel;
-      int preferredEncoding;
-      bool autoSelect;
-      bool shared;
-      bool sendPtrEvents;
-      bool sendKeyEvents;
-      bool sendSysKeys;
-      bool showToolbar;
-      bool clientCutText;
-      bool serverCutText;
-      bool emulate3;
-      int pointerEventInterval;
-      bool protocol3_3;
-      bool acceptBell;
-      CharArray userName;
-      void setUserName(const char* user);
-      CharArray password;
-      void setPassword(const char* pwd);
-      CharArray configFileName;
-      void setConfigFileName(const char* cfn);
-      CharArray host;
-      void setHost(const char* h);
-      CharArray monitor;
-      void setMonitor(const char* m);
-      unsigned int menuKey;
-      void setMenuKey(const char* keyName);
-      char* menuKeyName();
-
-      bool customCompressLevel;
-      int compressLevel;
-      bool noJpeg;
-      int qualityLevel;
-
-      CharArray passwordFile;
-    };
-
-
-  };
-
-};
-
-#endif
diff --git a/vncviewer/ConnectingDialog.cxx b/vncviewer/ConnectingDialog.cxx
new file mode 100644 (file)
index 0000000..60fcb66
--- /dev/null
@@ -0,0 +1,160 @@
+/* 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.
+ */
+
+// -=- ConnectingDialog.cxx
+
+#include <stdlib.h>
+#include <vncviewer/ConnectingDialog.h>
+#include <vncviewer/resource.h>
+#include <network/TcpSocket.h>
+#include <rfb/Threading.h>
+#include <rfb/Hostname.h>
+#include <map>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+// ConnectingDialog callback
+static BOOL CALLBACK ConnectingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
+  bool* activePtr = (bool*)GetWindowLong(hwnd, GWL_USERDATA);
+  switch (uMsg) {
+  case WM_INITDIALOG:
+    SetWindowLong(hwnd, GWL_USERDATA, lParam);
+    return TRUE;
+       case WM_COMMAND:
+         switch (LOWORD(wParam)) {
+         case IDCANCEL:
+      if (activePtr)
+        *activePtr = false;
+                 return TRUE;
+               }
+               break;
+       case WM_DESTROY:
+    if (activePtr)
+      *activePtr = false;
+         return TRUE;
+       }
+       return 0;
+}
+
+
+// Global map, used by ConnectingDialog::Threads to call back to their owning
+// ConnectingDialogs, while coping with the fact that the owner may already have quit.
+static std::map<int, ConnectingDialog*> dialogs;
+static int nextDialogId = 0;
+static Mutex dialogsLock;
+
+
+// ConnectingDialog::Thread
+//   Attempts to connect to the specified host.  If the connection succeeds, the
+//   socket is saved in the owning ConnectingDialog, if still available, and the
+//   event is signalled.  If the connection fails, the Exception text is returned
+//   to the dialog.  If the dialog is already gone, the Exception/socket are discarded.
+//   NB: This thread class cleans itself up on exit - DO NOT join()!
+class ConnectingDialog::Thread : public rfb::Thread {
+public:
+  Thread(int dialogId_, const char* hostAndPort) : dialogId(dialogId_) {
+    setDeleteAfterRun();
+    getHostAndPort(hostAndPort, &host.buf, &port);
+  }
+  virtual void run() {
+    try {
+      returnSock(new network::TcpSocket(host.buf, port));
+    } catch (rdr::Exception& e) {
+      returnException(e);
+    }
+  }
+  void returnSock(network::Socket* s) {
+    Lock l(dialogsLock);
+    if (dialogs.count(dialogId)) {
+      dialogs[dialogId]->newSocket = s;
+      SetEvent(dialogs[dialogId]->readyEvent);
+    } else {
+      delete s;
+    }
+  }
+  void returnException(const rdr::Exception& e) {
+    Lock l(dialogsLock);
+    if (dialogs.count(dialogId)) {
+      dialogs[dialogId]->errMsg.replaceBuf(strDup(e.str()));
+      SetEvent(dialogs[dialogId]->readyEvent);
+    }
+  };
+  CharArray host;
+  int port;
+  int dialogId;
+};
+
+
+ConnectingDialog::ConnectingDialog() : dialog(0), readyEvent(CreateEvent(0, TRUE, FALSE, 0)),
+                                       newSocket(0), dialogId(0) {
+}
+
+network::Socket* ConnectingDialog::connect(const char* hostAndPort) {
+  Thread* connectThread = 0;
+  bool active = true;
+  errMsg.replaceBuf(0);
+  newSocket = 0;
+
+  // Get a unique dialog identifier and create the dialog window
+  {
+    Lock l(dialogsLock);
+    dialogId = ++nextDialogId;
+    dialogs[dialogId] = this;
+    dialog = CreateDialogParam(GetModuleHandle(0),
+      MAKEINTRESOURCE(IDD_CONNECTING_DLG), 0, &ConnectingDlgProc, (long)&active);
+    ShowWindow(dialog, SW_SHOW);
+    ResetEvent(readyEvent);
+  }
+
+  // Create and start the connection thread
+  try {
+    connectThread = new Thread(dialogId, hostAndPort);
+    connectThread->start();
+  } catch (rdr::Exception& e) {
+    errMsg.replaceBuf(strDup(e.str()));
+    active = false;
+  }
+
+  // Process window messages until the connection thread signals readyEvent, or the dialog is cancelled
+  while (active && (MsgWaitForMultipleObjects(1, &readyEvent.h, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)) {
+    MSG msg;
+    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+      DispatchMessage(&msg);
+  }
+
+  // Remove this dialog from the table
+  //   NB: If the dialog was cancelled then the thread is still running, and will only
+  //       discover that we're gone when it looks up our unique Id in the dialog table.
+  {
+    Lock l(dialogsLock);
+    dialogs.erase(dialogId);
+  }
+
+  // Close the dialog window
+  DestroyWindow(dialog); dialog=0;
+
+  // Throw the exception, if there was one
+  if (errMsg.buf)
+    throw rdr::Exception(errMsg.buf);
+
+  // Otherwise, return the socket
+  //   NB: The socket will be null if the dialog was cancelled
+  return newSocket;
+}
index b146ced6ce81c044cea6e79060b2718a931b6a16..c38b3a1b86d4c88fb15dca49588f33d9b7a3d2a6 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* 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
 
 // -=- ConnectingDialog.h
 
-// Dialog to indicate to the user that the viewer is attempting to make an
-// outgoing connection.
+// ConnectingDialog instances are used to display a status dialog while a
+// connection attempt is in progress.  The connection attempt is performed
+// in a background thread by the ConnectingDialog, to allow the status dialog
+// to remain interactive.  If the dialog is cancelled then it will close and
+// the connection dialog will eventually tidy itself up.
 
 #ifndef __RFB_WIN32_CONNECTING_DLG_H__
 #define __RFB_WIN32_CONNECTING_DLG_H__
 
-#include <rfb_win32/Dialog.h>
-#include <rfb/Threading.h>
-#include <vncviewer/resource.h>
+#include <windows.h>
+#include <network/Socket.h>
+#include <rfb/util.h>
+#include <rfb_win32/Handle.h>
 
 namespace rfb {
 
   namespace win32 {
 
-    BOOL CALLBACK ConnectingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
-           switch (uMsg) {
-           case WM_INITDIALOG:
-                   {
-                           SetWindowLong(hwnd, GWL_USERDATA, lParam);
-                           return TRUE;
-                   }
-           case WM_COMMAND:
-                   switch (LOWORD(wParam)) {
-                   case IDCANCEL:
-          network::Socket* sock = (network::Socket*) GetWindowLong(hwnd, GWL_USERDATA);
-          sock->shutdown();
-                           EndDialog(hwnd, FALSE);
-                           return TRUE;
-                   }
-                   break;
-           case WM_DESTROY:
-                   EndDialog(hwnd, TRUE);
-                   return TRUE;
-           }
-           return 0;
-    }
-
-    // *** hacky bit - should use async connect so dialog behaves properly
-    class ConnectingDialog : public Thread {
+    class ConnectingDialog {
     public:
-      ConnectingDialog() : Thread("ConnectingDialog") {
-        dialog = 0;
-        active = true;
-        start();
-      }
-      virtual ~ConnectingDialog() {
-        // *** join() required here because otherwise ~Thread calls Thread::join()
-        join();
-      }
-      virtual void run() {
-        dialog = CreateDialogParam(GetModuleHandle(0),
-          MAKEINTRESOURCE(IDD_CONNECTING_DLG), 0, &ConnectingDlgProc, 0);
-        ShowWindow(dialog, SW_SHOW);
-        MSG msg;
-        while (active && GetMessage(&msg, dialog, 0, 0)) {
-          DispatchMessage(&msg);
-        }
-        DestroyWindow(dialog);
-      }
-      virtual Thread* join() {
-        active = false;
-        if (dialog)
-          PostMessage(dialog, WM_QUIT, 0, 0);
-        return Thread::join();
-      }
+      ConnectingDialog();
+
+      // connect
+      //   Show a Connecting dialog and attempt to connect to the specified host
+      //   in the background.
+      //   If the connection succeeds then the Socket is returned.
+      //   If an error occurs, an Exception is thrown.
+      //   If the dialog is cancelled then null is returned.
+      network::Socket* connect(const char* hostAndPort);
     protected:
       HWND dialog;
-      bool active;
+      network::Socket* newSocket;
+      CharArray errMsg;
+      Handle readyEvent;
+      int dialogId;
+
+      class Thread;
+      friend class Thread;
     };
 
   };
 
 };
 
-#endif
\ No newline at end of file
+#endif
index c083444c5b2f150798c4c6b3e75126fdd0dafb1d..e7c6b0a5bc1d4076e38f9f7ccb59d11b5cd78a83 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* 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
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  * USA.
  */
+
 #include <vncviewer/ConnectionDialog.h>
-#include <vncviewer/CView.h>
+#include <vncviewer/CConn.h>
 #include <vncviewer/resource.h>
+#include <rfb_win32/AboutDialog.h>
 
 #include <tchar.h>
 
@@ -25,7 +27,7 @@ using namespace rfb;
 using namespace rfb::win32;
 
 
-ConnectionDialog::ConnectionDialog(CView* view_) : Dialog(GetModuleHandle(0)), view(view_) {
+ConnectionDialog::ConnectionDialog(CConn* conn_) : Dialog(GetModuleHandle(0)), conn(conn_) {
 }
 
 
@@ -47,6 +49,13 @@ void ConnectionDialog::initDialog() {
 
   // Select the first item in the list
   SendMessage(box, CB_SETCURSEL, 0, 0);
+
+  // Fill out the Security: drop-down and select the preferred option
+  HWND security = GetDlgItem(handle, IDC_SECURITY_LEVEL);
+  LRESULT n = SendMessage(security, CB_ADDSTRING, 0, (LPARAM)_T("Always Off"));
+  if (n != CB_ERR)
+    SendMessage(security, CB_SETCURSEL, n, 0);
+  enableItem(IDC_SECURITY_LEVEL, false);
 }
 
 
@@ -63,7 +72,7 @@ bool ConnectionDialog::onCommand(int id, int cmd) {
     AboutDialog::instance.showDialog();
     return true;
   case IDC_OPTIONS:
-    view->optionsDialog.showDialog(view);
+    conn->showOptionsDialog();
     return true;
   };
   return false;
index 554c86fb2810fb96d5cc8841f0d4bb113936f4d6..f739280ce54968f14a1a99553f5ee4eb2077713b 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* 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
@@ -31,18 +31,18 @@ namespace rfb {
 
   namespace win32 {
 
-    class CView;
+    class CConn;
 
     class ConnectionDialog : Dialog {
     public:
-      ConnectionDialog(CView* view);
+      ConnectionDialog(CConn* view);
       virtual bool showDialog();
       virtual void initDialog();
       virtual bool onOk();
       virtual bool onCommand(int id, int cmd);
       TCharArray hostname;
     protected:
-      CView* view;
+      CConn* conn;
     };
 
   };
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
new file mode 100644 (file)
index 0000000..311a586
--- /dev/null
@@ -0,0 +1,1076 @@
+/* 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.
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/WMShatter.h>
+#include <rfb_win32/LowLevelKeyEvents.h>
+#include <rfb_win32/MonitorInfo.h>
+#include <rfb_win32/DeviceContext.h>
+#include <rfb_win32/Win32Util.h>
+#include <vncviewer/DesktopWindow.h>
+#include <vncviewer/resource.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+// - Statics & consts
+
+static LogWriter vlog("DesktopWindow");
+
+const int TIMER_BUMPSCROLL = 1;
+const int TIMER_POINTER_INTERVAL = 2;
+const int TIMER_POINTER_3BUTTON = 3;
+
+
+//
+// -=- DesktopWindowClass
+
+//
+// Window class used as the basis for all DesktopWindow instances
+//
+
+class DesktopWindowClass {
+public:
+  DesktopWindowClass();
+  ~DesktopWindowClass();
+  ATOM classAtom;
+  HINSTANCE instance;
+};
+
+LRESULT CALLBACK DesktopWindowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+  LRESULT result;
+  if (msg == WM_CREATE)
+    SetWindowLong(wnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+  else if (msg == WM_DESTROY)
+    SetWindowLong(wnd, GWL_USERDATA, 0);
+  DesktopWindow* _this = (DesktopWindow*) GetWindowLong(wnd, GWL_USERDATA);
+  if (!_this) {
+    vlog.info("null _this in %x, message %u", wnd, msg);
+    return rfb::win32::SafeDefWindowProc(wnd, msg, wParam, lParam);
+  }
+
+  try {
+    result = _this->processMessage(msg, wParam, lParam);
+  } catch (rdr::Exception& e) {
+    vlog.error("untrapped: %s", e.str());
+  }
+
+  return result;
+};
+
+static HCURSOR dotCursor = (HCURSOR)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDC_DOT_CURSOR), IMAGE_CURSOR, 0, 0, LR_SHARED);
+static HCURSOR arrowCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED); 
+
+DesktopWindowClass::DesktopWindowClass() : classAtom(0) {
+  WNDCLASS wndClass;
+  wndClass.style = 0;
+  wndClass.lpfnWndProc = DesktopWindowProc;
+  wndClass.cbClsExtra = 0;
+  wndClass.cbWndExtra = 0;
+  wndClass.hInstance = instance = GetModuleHandle(0);
+  wndClass.hIcon = (HICON)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 0, 0, LR_SHARED);
+  if (!wndClass.hIcon)
+    printf("unable to load icon:%ld", GetLastError());
+  wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+  wndClass.hbrBackground = NULL;
+  wndClass.lpszMenuName = 0;
+  wndClass.lpszClassName = _T("rfb::win32::DesktopWindowClass");
+  classAtom = RegisterClass(&wndClass);
+  if (!classAtom) {
+    throw rdr::SystemException("unable to register DesktopWindow window class", GetLastError());
+  }
+}
+
+DesktopWindowClass::~DesktopWindowClass() {
+  if (classAtom) {
+    UnregisterClass((const TCHAR*)classAtom, instance);
+  }
+}
+
+DesktopWindowClass baseClass;
+
+//
+// -=- FrameClass
+
+//
+// Window class used for child windows that display pixel data
+//
+
+class FrameClass {
+public:
+  FrameClass();
+  ~FrameClass();
+  ATOM classAtom;
+  HINSTANCE instance;
+};
+
+LRESULT CALLBACK FrameProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+  LRESULT result;
+  if (msg == WM_CREATE)
+    SetWindowLong(wnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+  else if (msg == WM_DESTROY)
+    SetWindowLong(wnd, GWL_USERDATA, 0);
+  DesktopWindow* _this = (DesktopWindow*) GetWindowLong(wnd, GWL_USERDATA);
+  if (!_this) {
+    vlog.info("null _this in %x, message %u", wnd, msg);
+    return rfb::win32::SafeDefWindowProc(wnd, msg, wParam, lParam);
+  }
+
+  try {
+    result = _this->processFrameMessage(msg, wParam, lParam);
+  } catch (rdr::Exception& e) {
+    vlog.error("untrapped: %s", e.str());
+  }
+
+  return result;
+}
+
+FrameClass::FrameClass() : classAtom(0) {
+  WNDCLASS wndClass;
+  wndClass.style = 0;
+  wndClass.lpfnWndProc = FrameProc;
+  wndClass.cbClsExtra = 0;
+  wndClass.cbWndExtra = 0;
+  wndClass.hInstance = instance = GetModuleHandle(0);
+  wndClass.hIcon = 0;
+  wndClass.hCursor = NULL;
+  wndClass.hbrBackground = NULL;
+  wndClass.lpszMenuName = 0;
+  wndClass.lpszClassName = _T("rfb::win32::FrameClass");
+  classAtom = RegisterClass(&wndClass);
+  if (!classAtom) {
+    throw rdr::SystemException("unable to register Frame window class", GetLastError());
+  }
+}
+
+FrameClass::~FrameClass() {
+  if (classAtom) {
+    UnregisterClass((const TCHAR*)classAtom, instance);
+  }
+}
+
+FrameClass frameClass;
+
+
+//
+// -=- DesktopWindow instance implementation
+//
+
+DesktopWindow::DesktopWindow(Callback* cb) 
+  : buffer(0),
+    showToolbar(true),
+    client_size(0, 0, 16, 16), window_size(0, 0, 32, 32),
+    cursorVisible(false), cursorAvailable(false), cursorInBuffer(false),
+    systemCursorVisible(true), trackingMouseLeave(false),
+    handle(0), frameHandle(0), has_focus(false), palette_changed(false),
+    fullscreenActive(false), fullscreenRestore(false),
+    bumpScroll(false), callback(cb) {
+
+  // Create the window
+  const char* name = "DesktopWindow";
+  handle = CreateWindow((const TCHAR*)baseClass.classAtom, TStr(name),
+    WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+    0, 0, 10, 10, 0, 0, baseClass.instance, this);
+  if (!handle)
+    throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError());
+  vlog.debug("created window \"%s\" (%x)", name, handle);
+
+  // Create the toolbar
+  tb.create(getHandle());
+  vlog.debug("created toolbar window \"%s\" (%x)", "ViewerToolBar", tb.getHandle());
+
+  // Create the frame window
+  frameHandle = CreateWindowEx(WS_EX_CLIENTEDGE, (const TCHAR*)frameClass.classAtom,
+    0, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+    CW_USEDEFAULT, CW_USEDEFAULT, getHandle(), 0, frameClass.instance, this);
+  if (!frameHandle) {
+    throw rdr::SystemException("unable to create rfb frame window instance", GetLastError());
+  }
+  vlog.debug("created window \"%s\" (%x)", "Frame Window", frameHandle);
+
+  // Initialise the CPointer pointer handler
+  ptr.setHWND(frameHandle);
+  ptr.setIntervalTimerId(TIMER_POINTER_INTERVAL);
+  ptr.set3ButtonTimerId(TIMER_POINTER_3BUTTON);
+
+  // Initialise the bumpscroll timer
+  bumpScrollTimer.setHWND(handle);
+  bumpScrollTimer.setId(TIMER_BUMPSCROLL);
+
+  // Hook the clipboard
+  clipboard.setNotifier(this);
+
+  // Create the backing buffer
+  buffer = new win32::DIBSectionBuffer(frameHandle);
+
+  // Show the window
+  centerWindow(handle, 0);
+  ShowWindow(handle, SW_SHOW);
+}
+
+DesktopWindow::~DesktopWindow() {
+  vlog.debug("~DesktopWindow");
+  showSystemCursor();
+  if (handle) {
+    disableLowLevelKeyEvents(handle);
+    DestroyWindow(handle);
+    handle = 0;
+  }
+  delete buffer;
+  vlog.debug("~DesktopWindow done");
+}
+
+
+void DesktopWindow::setFullscreen(bool fs) {
+  if (fs && !fullscreenActive) {
+    fullscreenActive = bumpScroll = true;
+
+    // Un-minimize the window if required
+    if (GetWindowLong(handle, GWL_STYLE) & WS_MINIMIZE)
+      ShowWindow(handle, SW_RESTORE);
+
+    // Save the current window position
+    GetWindowRect(handle, &fullscreenOldRect);
+
+    // Find the size of the display the window is on
+    MonitorInfo mi(handle);
+
+    // Hide the toolbar
+    if (showToolbar)
+      tb.hide();
+    SetWindowLong(frameHandle, GWL_EXSTYLE, 0);
+
+    // Set the window full-screen
+    DWORD flags = GetWindowLong(handle, GWL_STYLE);
+    fullscreenOldFlags = flags;
+    flags = flags & ~(WS_CAPTION | WS_THICKFRAME | WS_MAXIMIZE | WS_MINIMIZE);
+    vlog.debug("flags=%x", flags);
+
+    SetWindowLong(handle, GWL_STYLE, flags);
+    SetWindowPos(handle, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top,
+      mi.rcMonitor.right-mi.rcMonitor.left,
+      mi.rcMonitor.bottom-mi.rcMonitor.top,
+      SWP_FRAMECHANGED);
+  } else if (!fs && fullscreenActive) {
+    fullscreenActive = bumpScroll = false;
+
+    // Show the toolbar
+    if (showToolbar)
+      tb.show();
+    SetWindowLong(frameHandle, GWL_EXSTYLE, WS_EX_CLIENTEDGE);
+
+    // Set the window non-fullscreen
+    SetWindowLong(handle, GWL_STYLE, fullscreenOldFlags);
+
+    // Set the window position
+    SetWindowPos(handle, HWND_NOTOPMOST,
+      fullscreenOldRect.left, fullscreenOldRect.top,
+      fullscreenOldRect.right - fullscreenOldRect.left, 
+      fullscreenOldRect.bottom - fullscreenOldRect.top,
+      SWP_FRAMECHANGED);
+  }
+
+  // Adjust the viewport offset to cope with change in size between FS
+  // and previous window state.
+  setViewportOffset(scrolloffset);
+}
+
+void DesktopWindow::setDisableWinKeys(bool dwk) {
+  // Enable low-level event hooking, so we get special keys directly
+  if (dwk)
+    enableLowLevelKeyEvents(handle);
+  else
+    disableLowLevelKeyEvents(handle);
+}
+
+
+void DesktopWindow::setMonitor(const char* monitor) {
+  MonitorInfo mi(monitor);
+  mi.moveTo(handle);
+}
+
+char* DesktopWindow::getMonitor() const {
+  MonitorInfo mi(handle);
+  return strDup(mi.szDevice);
+}
+
+
+bool DesktopWindow::setViewportOffset(const Point& tl) {
+  Point np = Point(max(0, min(tl.x, buffer->width()-client_size.width())),
+    max(0, min(tl.y, buffer->height()-client_size.height())));
+  Point delta = np.translate(scrolloffset.negate());
+  if (!np.equals(scrolloffset)) {
+    scrolloffset = np;
+    ScrollWindowEx(frameHandle, -delta.x, -delta.y, 0, 0, 0, 0, SW_INVALIDATE);
+    UpdateWindow(frameHandle);
+    return true;
+  }
+  return false;
+}
+
+
+bool DesktopWindow::processBumpScroll(const Point& pos)
+{
+  if (!bumpScroll) return false;
+  int bumpScrollPixels = 20;
+  bumpScrollDelta = Point();
+
+  if (pos.x == client_size.width()-1)
+    bumpScrollDelta.x = bumpScrollPixels;
+  else if (pos.x == 0)
+    bumpScrollDelta.x = -bumpScrollPixels;
+  if (pos.y == client_size.height()-1)
+    bumpScrollDelta.y = bumpScrollPixels;
+  else if (pos.y == 0)
+    bumpScrollDelta.y = -bumpScrollPixels;
+
+  if (bumpScrollDelta.x || bumpScrollDelta.y) {
+    if (bumpScrollTimer.isActive()) return true;
+    if (setViewportOffset(scrolloffset.translate(bumpScrollDelta))) {
+      bumpScrollTimer.start(25);
+      return true;
+    }
+  }
+
+  bumpScrollTimer.stop();
+  return false;
+}
+
+
+LRESULT
+DesktopWindow::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+  switch (msg) {
+
+    // -=- Process standard window messages
+
+  case WM_NOTIFY:
+    if (wParam == ID_TOOLBAR)
+      tb.processWM_NOTIFY(wParam, lParam);
+    break;
+
+  case WM_DISPLAYCHANGE:
+    // Display format has changed - notify callback
+    callback->displayChanged();
+    break;
+
+    // -=- Window position
+
+    // Prevent the window from being resized to be too large if in normal mode.
+    // If maximized or fullscreen the allow oversized windows.
+
+  case WM_WINDOWPOSCHANGING:
+    {
+      WINDOWPOS* wpos = (WINDOWPOS*)lParam;
+      if (wpos->flags & SWP_NOSIZE)
+        break;
+
+      // Work out how big the window should ideally be
+      DWORD current_style = GetWindowLong(frameHandle, GWL_STYLE);
+      DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+      DWORD style_ex = GetWindowLong(frameHandle, GWL_EXSTYLE);
+
+      RECT r;
+      SetRect(&r, 0, 0, buffer->width(), buffer->height());
+      AdjustWindowRectEx(&r, style, FALSE, style_ex);
+      Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+      if (current_style & WS_VSCROLL)
+        reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
+      if (current_style & WS_HSCROLL)
+        reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
+
+      SetRect(&r, reqd_size.tl.x, reqd_size.br.x, reqd_size.tl.y, reqd_size.br.y);
+      if (tb.isVisible())
+        r.bottom += tb.getHeight();
+      AdjustWindowRect(&r, GetWindowLong(handle, GWL_STYLE), FALSE);
+      reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+
+      RECT current;
+      GetWindowRect(handle, &current);
+
+      if (!(GetWindowLong(handle, GWL_STYLE) & WS_MAXIMIZE) && !fullscreenActive) {
+        // Ensure that the window isn't resized too large
+        if (wpos->cx > reqd_size.width()) {
+          wpos->cx = reqd_size.width();
+          wpos->x = current.left;
+        }
+        if (wpos->cy > reqd_size.height()) {
+          wpos->cy = reqd_size.height();
+          wpos->y = current.top;
+        }
+      }
+    }
+    break;
+
+    // Resize child windows and update window size info we have cached.
+
+  case WM_SIZE:
+    {
+      Point old_offset = desktopToClient(Point(0, 0));
+      RECT r;
+
+      // Resize child windows
+      GetClientRect(getHandle(), &r);
+      if (tb.isVisible()) {
+        MoveWindow(getFrameHandle(), 0, tb.getHeight(),
+                   r.right, r.bottom - tb.getHeight(), TRUE);
+      } else {
+        MoveWindow(getFrameHandle(), 0, 0, r.right, r.bottom, TRUE);
+      }
+      tb.autoSize();
+      // Update the cached sizing information
+      GetWindowRect(frameHandle, &r);
+      window_size = Rect(r.left, r.top, r.right, r.bottom);
+      GetClientRect(frameHandle, &r);
+      client_size = Rect(r.left, r.top, r.right, r.bottom);
+
+      // Determine whether scrollbars are required
+      calculateScrollBars();
+
+      // Redraw if required
+      if ((!old_offset.equals(desktopToClient(Point(0, 0)))))
+        InvalidateRect(frameHandle, 0, TRUE);
+    }
+    break;
+
+    // -=- Bump-scrolling
+
+  case WM_TIMER:
+    switch (wParam) {
+    case TIMER_BUMPSCROLL:
+      if (!setViewportOffset(scrolloffset.translate(bumpScrollDelta)))
+        bumpScrollTimer.stop();
+      break;
+    case TIMER_POINTER_INTERVAL:
+    case TIMER_POINTER_3BUTTON:
+      ptr.handleTimer(callback, wParam);
+      break;
+    }
+    break;
+
+    // -=- Track whether or not the window has focus
+
+  case WM_SETFOCUS:
+    has_focus = true;
+    break;
+  case WM_KILLFOCUS:
+    has_focus = false;
+    cursorOutsideBuffer();
+    // Restore the keyboard to a consistent state
+    kbd.releaseAllKeys(callback);
+    break;
+
+    // -=- Handle the extra window menu items
+
+    // Pass system menu messages to the callback and only attempt
+    // to process them ourselves if the callback returns false.
+  case WM_SYSCOMMAND:
+    // Call the supplied callback
+    if (callback->sysCommand(wParam, lParam))
+      break;
+
+    // - Not processed by the callback, so process it as a system message
+    switch (wParam & 0xfff0) {
+
+      // When restored, ensure that full-screen mode is re-enabled if required.
+    case SC_RESTORE:
+      {
+      if (GetWindowLong(handle, GWL_STYLE) & WS_MINIMIZE) {
+        rfb::win32::SafeDefWindowProc(handle, msg, wParam, lParam);
+        setFullscreen(fullscreenRestore);
+      }
+      else if (fullscreenActive)
+        setFullscreen(false);
+      else
+        rfb::win32::SafeDefWindowProc(handle, msg, wParam, lParam);
+
+      return 0;
+      }
+
+      // If we are maximized or minimized then that cancels full-screen mode.
+    case SC_MINIMIZE:
+    case SC_MAXIMIZE:
+      fullscreenRestore = fullscreenActive;
+      setFullscreen(false);
+      break;
+
+      // If the menu is about to be shown, make sure it's up to date
+    case SC_KEYMENU:
+    case SC_MOUSEMENU:
+      callback->refreshMenu(true);
+      break;
+
+    };
+    break;
+
+    // Treat all menu commands as system menu commands
+  case WM_COMMAND:
+    SendMessage(handle, WM_SYSCOMMAND, wParam, lParam);
+    return 0;
+
+    // -=- Handle keyboard input
+
+  case WM_KEYUP:
+  case WM_KEYDOWN:
+    // Hook the MenuKey to pop-up the window menu
+    if (menuKey && (wParam == menuKey)) {
+
+      bool ctrlDown = (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0;
+      bool altDown = (GetAsyncKeyState(VK_MENU) & 0x8000) != 0;
+      bool shiftDown = (GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0;
+      if (!(ctrlDown || altDown || shiftDown)) {
+
+        // If MenuKey is being released then pop-up the menu
+        if ((msg == WM_KEYDOWN)) {
+          // Make sure it's up to date
+          callback->refreshMenu(false);
+
+          // Show it under the pointer
+          POINT pt;
+          GetCursorPos(&pt);
+          cursorInBuffer = false;
+          TrackPopupMenu(GetSystemMenu(handle, FALSE),
+            TPM_CENTERALIGN | TPM_VCENTERALIGN, pt.x, pt.y, 0, handle, 0);
+        }
+
+        // Ignore the MenuKey keypress for both press & release events
+        return 0;
+      }
+    }
+       case WM_SYSKEYDOWN:
+       case WM_SYSKEYUP:
+    kbd.keyEvent(callback, wParam, lParam, (msg == WM_KEYDOWN) || (msg == WM_SYSKEYDOWN));
+    return 0;
+
+    // -=- Handle the window closing
+
+  case WM_CLOSE:
+    vlog.debug("WM_CLOSE %x", handle);
+    callback->closeWindow();
+    break;
+
+  }
+
+  return rfb::win32::SafeDefWindowProc(handle, msg, wParam, lParam);
+}
+
+LRESULT
+DesktopWindow::processFrameMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+  switch (msg) {
+
+    // -=- Paint the remote frame buffer
+
+  case WM_PAINT:
+    {
+      PAINTSTRUCT ps;
+      HDC paintDC = BeginPaint(frameHandle, &ps);
+      if (!paintDC)
+        throw rdr::SystemException("unable to BeginPaint", GetLastError());
+      Rect pr = Rect(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
+
+      if (!pr.is_empty()) {
+
+        // Draw using the correct palette
+        PaletteSelector pSel(paintDC, windowPalette.getHandle());
+
+        if (buffer->bitmap) {
+          // Update the bitmap's palette
+          if (palette_changed) {
+            palette_changed = false;
+            buffer->refreshPalette();
+          }
+
+          // Get device context
+          BitmapDC bitmapDC(paintDC, buffer->bitmap);
+
+          // Blit the border if required
+          Rect bufpos = desktopToClient(buffer->getRect());
+          if (!pr.enclosed_by(bufpos)) {
+            vlog.debug("draw border");
+            HBRUSH black = (HBRUSH) GetStockObject(BLACK_BRUSH);
+            RECT r;
+            SetRect(&r, 0, 0, bufpos.tl.x, client_size.height()); FillRect(paintDC, &r, black);
+            SetRect(&r, bufpos.tl.x, 0, bufpos.br.x, bufpos.tl.y); FillRect(paintDC, &r, black);
+            SetRect(&r, bufpos.br.x, 0, client_size.width(), client_size.height()); FillRect(paintDC, &r, black);
+            SetRect(&r, bufpos.tl.x, bufpos.br.y, bufpos.br.x, client_size.height()); FillRect(paintDC, &r, black);
+          }
+
+          // Do the blit
+          Point buf_pos = clientToDesktop(pr.tl);
+
+          if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
+                      bitmapDC, buf_pos.x, buf_pos.y, SRCCOPY))
+            throw rdr::SystemException("unable to BitBlt to window", GetLastError());
+        }
+      }
+
+      EndPaint(frameHandle, &ps);
+
+      // - Notify the callback that a paint message has finished processing
+      callback->paintCompleted();
+    }
+    return 0;
+
+    // -=- Palette management
+
+  case WM_PALETTECHANGED:
+    vlog.debug("WM_PALETTECHANGED");
+    if ((HWND)wParam == frameHandle) {
+      vlog.debug("ignoring");
+      break;
+    }
+  case WM_QUERYNEWPALETTE:
+    vlog.debug("re-selecting palette");
+    {
+      WindowDC wdc(frameHandle);
+      PaletteSelector pSel(wdc, windowPalette.getHandle());
+      if (pSel.isRedrawRequired()) {
+        InvalidateRect(frameHandle, 0, FALSE);
+        UpdateWindow(frameHandle);
+      }
+    }
+    return TRUE;
+
+  case WM_VSCROLL:
+  case WM_HSCROLL: 
+    {
+      Point delta;
+      int newpos = (msg == WM_VSCROLL) ? scrolloffset.y : scrolloffset.x;
+
+      switch (LOWORD(wParam)) {
+      case SB_PAGEUP: newpos -= 50; break;
+      case SB_PAGEDOWN: newpos += 50; break;
+      case SB_LINEUP: newpos -= 5; break;
+      case SB_LINEDOWN: newpos += 5; break;
+      case SB_THUMBTRACK:
+      case SB_THUMBPOSITION: newpos = HIWORD(wParam); break;
+      default: vlog.info("received unknown scroll message");
+      };
+
+      if (msg == WM_HSCROLL)
+        setViewportOffset(Point(newpos, scrolloffset.y));
+      else
+        setViewportOffset(Point(scrolloffset.x, newpos));
+  
+      SCROLLINFO si;
+      si.cbSize = sizeof(si); 
+      si.fMask  = SIF_POS; 
+      si.nPos   = newpos; 
+      SetScrollInfo(frameHandle, (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ, &si, TRUE); 
+    }
+    break;
+
+    // -=- Cursor shape/visibility handling
+
+  case WM_SETCURSOR:
+    if (LOWORD(lParam) != HTCLIENT)
+      break;
+    SetCursor(cursorInBuffer ? dotCursor : arrowCursor);
+    return TRUE;
+
+  case WM_MOUSELEAVE:
+    trackingMouseLeave = false;
+    cursorOutsideBuffer();
+    return 0;
+
+    // -=- Mouse input handling
+
+  case WM_MOUSEMOVE:
+  case WM_LBUTTONUP:
+  case WM_MBUTTONUP:
+  case WM_RBUTTONUP:
+  case WM_LBUTTONDOWN:
+  case WM_MBUTTONDOWN:
+  case WM_RBUTTONDOWN:
+#ifdef WM_MOUSEWHEEL
+  case WM_MOUSEWHEEL:
+#endif
+    if (has_focus)
+    {
+      if (!trackingMouseLeave) {
+        TRACKMOUSEEVENT tme;
+        tme.cbSize = sizeof(TRACKMOUSEEVENT);
+        tme.dwFlags = TME_LEAVE;
+        tme.hwndTrack = frameHandle;
+        _TrackMouseEvent(&tme);
+        trackingMouseLeave = true;
+      }
+      int mask = 0;
+      if (LOWORD(wParam) & MK_LBUTTON) mask |= 1;
+      if (LOWORD(wParam) & MK_MBUTTON) mask |= 2;
+      if (LOWORD(wParam) & MK_RBUTTON) mask |= 4;
+
+#ifdef WM_MOUSEWHEEL
+      if (msg == WM_MOUSEWHEEL) {
+        int delta = (short)HIWORD(wParam);
+        int repeats = (abs(delta)+119) / 120;
+        int wheelMask = (delta > 0) ? 8 : 16;
+        vlog.debug("repeats %d, mask %d\n",repeats,wheelMask);
+        for (int i=0; i<repeats; i++) {
+          ptr.pointerEvent(callback, oldpos, mask | wheelMask);
+          ptr.pointerEvent(callback, oldpos, mask);
+        }
+      } else {
+#endif
+        Point clientPos = Point(LOWORD(lParam), HIWORD(lParam));
+        Point p = clientToDesktop(clientPos);
+
+        // If the mouse is not within the server buffer area, do nothing
+        cursorInBuffer = buffer->getRect().contains(p);
+        if (!cursorInBuffer) {
+          cursorOutsideBuffer();
+          break;
+        }
+
+        // If we're locally rendering the cursor then redraw it
+        if (cursorAvailable) {
+          // - Render the cursor!
+          if (!p.equals(cursorPos)) {
+            hideLocalCursor();
+            cursorPos = p;
+            showLocalCursor();
+            if (cursorVisible)
+              hideSystemCursor();
+          }
+        }
+
+        // If we are doing bump-scrolling then try that first...
+        if (processBumpScroll(clientPos))
+          break;
+
+        // Send a pointer event to the server
+        ptr.pointerEvent(callback, p, mask);
+        oldpos = p;
+#ifdef WM_MOUSEWHEEL
+      }
+#endif
+    } else {
+      cursorOutsideBuffer();
+    }
+    break;
+  }
+
+  return rfb::win32::SafeDefWindowProc(frameHandle, msg, wParam, lParam);
+}
+
+
+void
+DesktopWindow::hideLocalCursor() {
+  // - Blit the cursor backing store over the cursor
+  // *** ALWAYS call this BEFORE changing buffer PF!!!
+  if (cursorVisible) {
+    cursorVisible = false;
+    buffer->imageRect(cursorBackingRect, cursorBacking.data);
+    invalidateDesktopRect(cursorBackingRect);
+  }
+}
+
+void
+DesktopWindow::showLocalCursor() {
+  if (cursorAvailable && !cursorVisible && cursorInBuffer) {
+    if (!buffer->getPF().equal(cursor.getPF()) ||
+      cursor.getRect().is_empty()) {
+      vlog.info("attempting to render invalid local cursor");
+      cursorAvailable = false;
+      showSystemCursor();
+      return;
+    }
+    cursorVisible = true;
+    
+    cursorBackingRect = cursor.getRect().translate(cursorPos).translate(cursor.hotspot.negate());
+    cursorBackingRect = cursorBackingRect.intersect(buffer->getRect());
+    buffer->getImage(cursorBacking.data, cursorBackingRect);
+
+    renderLocalCursor();
+
+    invalidateDesktopRect(cursorBackingRect);
+  }
+}
+
+void DesktopWindow::cursorOutsideBuffer()
+{
+  cursorInBuffer = false;
+  hideLocalCursor();
+  showSystemCursor();
+}
+
+void
+DesktopWindow::renderLocalCursor()
+{
+  Rect r = cursor.getRect();
+  r = r.translate(cursorPos).translate(cursor.hotspot.negate());
+  buffer->maskRect(r, cursor.data, cursor.mask.buf);
+}
+
+void
+DesktopWindow::hideSystemCursor() {
+  if (systemCursorVisible) {
+    vlog.debug("hide system cursor");
+    systemCursorVisible = false;
+    ShowCursor(FALSE);
+  }
+}
+
+void
+DesktopWindow::showSystemCursor() {
+  if (!systemCursorVisible) {
+    vlog.debug("show system cursor");
+    systemCursorVisible = true;
+    ShowCursor(TRUE);
+  }
+}
+
+
+bool
+DesktopWindow::invalidateDesktopRect(const Rect& crect) {
+  Rect rect = desktopToClient(crect);
+  if (rect.intersect(client_size).is_empty()) return false;
+  RECT invalid = {rect.tl.x, rect.tl.y, rect.br.x, rect.br.y};
+  InvalidateRect(frameHandle, &invalid, FALSE);
+  return true;
+}
+
+
+void
+DesktopWindow::notifyClipboardChanged(const char* text, int len) {
+  callback->clientCutText(text, len);
+}
+
+
+void
+DesktopWindow::setPF(const PixelFormat& pf) {
+  // If the cursor is the wrong format then clear it
+  if (!pf.equal(buffer->getPF()))
+    setCursor(0, 0, Point(), 0, 0);
+
+  // Update the desktop buffer
+  buffer->setPF(pf);
+  
+  // Redraw the window
+  InvalidateRect(handle, 0, 0);
+}
+
+void
+DesktopWindow::setSize(int w, int h) {
+  vlog.debug("setSize %dx%d", w, h);
+
+  // If the locally-rendered cursor is visible then remove it
+  hideLocalCursor();
+
+  // Resize the backing buffer
+  buffer->setSize(w, h);
+
+  // If the window is not maximised or full-screen then resize it
+  if (!(GetWindowLong(handle, GWL_STYLE) & WS_MAXIMIZE) && !fullscreenActive) {
+    // Resize the window to the required size
+    RECT r = {0, 0, w, h};
+    AdjustWindowRectEx(&r, GetWindowLong(frameHandle, GWL_STYLE), FALSE,
+                       GetWindowLong(frameHandle, GWL_EXSTYLE));
+    if (tb.isVisible())
+      r.bottom += tb.getHeight();
+    AdjustWindowRect(&r, GetWindowLong(handle, GWL_STYLE), FALSE);
+
+    // Resize about the center of the window, and clip to current monitor
+    MonitorInfo mi(handle);
+    resizeWindow(handle, r.right-r.left, r.bottom-r.top);
+    mi.clipTo(handle);
+  } else {
+    // Ensure the screen contents are consistent
+    InvalidateRect(frameHandle, 0, FALSE);
+  }
+
+  // Enable/disable scrollbars as appropriate
+  calculateScrollBars();
+}
+
+void
+DesktopWindow::setCursor(int w, int h, const Point& hotspot, void* data, void* mask) {
+  hideLocalCursor();
+
+  cursor.hotspot = hotspot;
+
+  cursor.setSize(w, h);
+  cursor.setPF(buffer->getPF());
+  cursor.imageRect(cursor.getRect(), data);
+  memcpy(cursor.mask.buf, mask, cursor.maskLen());
+  cursor.crop();
+
+  cursorBacking.setSize(w, h);
+  cursorBacking.setPF(buffer->getPF());
+
+  cursorAvailable = true;
+
+  showLocalCursor();
+}
+
+PixelFormat
+DesktopWindow::getNativePF() const {
+  vlog.debug("getNativePF()");
+  return WindowDC(handle).getPF();
+}
+
+
+void
+DesktopWindow::refreshWindowPalette(int start, int count) {
+  vlog.debug("refreshWindowPalette(%d, %d)", start, count);
+
+  Colour colours[256];
+  if (count > 256) {
+    vlog.debug("%d palette entries", count);
+    throw rdr::Exception("too many palette entries");
+  }
+
+  // Copy the palette from the DIBSectionBuffer
+  ColourMap* cm = buffer->getColourMap();
+  if (!cm) return;
+  for (int i=0; i<count; i++) {
+    int r, g, b;
+    cm->lookup(i, &r, &g, &b);
+    colours[i].r = r;
+    colours[i].g = g;
+    colours[i].b = b;
+  }
+
+  // Set the window palette
+  windowPalette.setEntries(start, count, colours);
+
+  // Cause the window to be redrawn
+  palette_changed = true;
+  InvalidateRect(handle, 0, FALSE);
+}
+
+
+void DesktopWindow::calculateScrollBars() {
+  // Calculate the required size of window
+  DWORD current_style = GetWindowLong(frameHandle, GWL_STYLE);
+  DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+  DWORD style_ex = GetWindowLong(frameHandle, GWL_EXSTYLE);
+  DWORD old_style;
+  RECT r;
+  SetRect(&r, 0, 0, buffer->width(), buffer->height());
+  AdjustWindowRectEx(&r, style, FALSE, style_ex);
+  Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+
+  if (!bumpScroll) {
+    // We only enable scrollbars if bump-scrolling is not active.
+    // Effectively, this means if full-screen is not active,
+    // but I think it's better to make these things explicit.
+    
+    // Work out whether scroll bars are required
+    do {
+      old_style = style;
+
+      if (!(style & WS_HSCROLL) && (reqd_size.width() > window_size.width())) {
+        style |= WS_HSCROLL;
+        reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
+      }
+      if (!(style & WS_VSCROLL) && (reqd_size.height() > window_size.height())) {
+        style |= WS_VSCROLL;
+        reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
+      }
+    } while (style != old_style);
+  }
+
+  // Tell Windows to update the window style & cached settings
+  if (style != current_style) {
+    SetWindowLong(frameHandle, GWL_STYLE, style);
+    SetWindowPos(frameHandle, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+  }
+
+  // Update the scroll settings
+  SCROLLINFO si;
+  if (style & WS_VSCROLL) {
+    si.cbSize = sizeof(si); 
+    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS; 
+    si.nMin   = 0; 
+    si.nMax   = buffer->height(); 
+    si.nPage  = buffer->height() - (reqd_size.height() - window_size.height()); 
+    maxscrolloffset.y = max(0, si.nMax-si.nPage);
+    scrolloffset.y = min(maxscrolloffset.y, scrolloffset.y);
+    si.nPos   = scrolloffset.y;
+    SetScrollInfo(frameHandle, SB_VERT, &si, TRUE);
+  }
+  if (style & WS_HSCROLL) {
+    si.cbSize = sizeof(si); 
+    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS; 
+    si.nMin   = 0;
+    si.nMax   = buffer->width(); 
+    si.nPage  = buffer->width() - (reqd_size.width() - window_size.width()); 
+    maxscrolloffset.x = max(0, si.nMax-si.nPage);
+    scrolloffset.x = min(maxscrolloffset.x, scrolloffset.x);
+    si.nPos   = scrolloffset.x;
+    SetScrollInfo(frameHandle, SB_HORZ, &si, TRUE);
+  }
+
+  // Update the cached client size
+  GetClientRect(frameHandle, &r);
+  client_size = Rect(r.left, r.top, r.right, r.bottom);
+}
+
+
+void
+DesktopWindow::setName(const char* name) {
+  SetWindowText(handle, TStr(name));
+}
+
+
+void
+DesktopWindow::serverCutText(const char* str, int len) {
+  CharArray t(len+1);
+  memcpy(t.buf, str, len);
+  t.buf[len] = 0;
+  clipboard.setClipText(t.buf);
+}
+
+
+void DesktopWindow::fillRect(const Rect& r, Pixel pix) {
+  if (cursorBackingRect.overlaps(r)) hideLocalCursor();
+  buffer->fillRect(r, pix);
+  invalidateDesktopRect(r);
+}
+void DesktopWindow::imageRect(const Rect& r, void* pixels) {
+  if (cursorBackingRect.overlaps(r)) hideLocalCursor();
+  buffer->imageRect(r, pixels);
+  invalidateDesktopRect(r);
+}
+void DesktopWindow::copyRect(const Rect& r, int srcX, int srcY) {
+  if (cursorBackingRect.overlaps(r) ||
+      cursorBackingRect.overlaps(Rect(srcX, srcY, srcX+r.width(), srcY+r.height())))
+    hideLocalCursor();
+  buffer->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
+  invalidateDesktopRect(r);
+}
+
+void DesktopWindow::invertRect(const Rect& r) {
+  int stride;
+  rdr::U8* p = buffer->getPixelsRW(r, &stride);
+  for (int y = 0; y < r.height(); y++) {
+    for (int x = 0; x < r.width(); x++) {
+      switch (buffer->getPF().bpp) {
+      case 8:  ((rdr::U8* )p)[x+y*stride] ^= 0xff;       break;
+      case 16: ((rdr::U16*)p)[x+y*stride] ^= 0xffff;     break;
+      case 32: ((rdr::U32*)p)[x+y*stride] ^= 0xffffffff; break;
+      }
+    }
+  }
+  invalidateDesktopRect(r);
+}
diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h
new file mode 100644 (file)
index 0000000..dd1bcdc
--- /dev/null
@@ -0,0 +1,254 @@
+/* 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.
+ */
+
+// -=- DesktopWindow.h
+
+// Each VNC connection instance (CConn) creates a DesktopWindow the
+// server initialisation message has been received.  The CConn is
+// responsible for all RFB-specific and network issues.  The
+// DesktopWindow is responsible for all GUI management issues.
+//
+// DesktopWindow provides a FullFramePixelBuffer interface for the
+// CConn to render updates into.  It also requires a callback object
+// to be supplied, which will be notified when various events occur.
+
+#ifndef __RFB_WIN32_DESKTOP_WINDOW_H__
+#define __RFB_WIN32_DESKTOP_WINDOW_H__
+
+#include <rfb/Cursor.h>
+#include <rfb_win32/CKeyboard.h>
+#include <rfb_win32/CPointer.h>
+#include <rfb_win32/Clipboard.h>
+#include <rfb_win32/DIBSectionBuffer.h>
+#include <rfb_win32/LogicalPalette.h>
+#include <vncviewer/ViewerToolBar.h>
+
+
+namespace rfb {
+
+  namespace win32 {
+
+    class DesktopWindow : rfb::win32::Clipboard::Notifier {
+    public:
+      class Callback;
+
+      DesktopWindow(Callback* cb_);
+      ~DesktopWindow();
+
+      // - Window message handling procedure
+      LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+      // - Window message handling procedure for the framebuffer window
+      LRESULT processFrameMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+      // - Determine the native pixel format of the window
+      //   This can (and often will) differ from the PixelBuffer format
+      PixelFormat getNativePF() const;
+
+      // - Get the underlying window handle
+      //   This is used by F8Menu to modify the window's menu
+      HWND getHandle() const {return handle;}
+
+      // - Get the framebuffer window handle
+      HWND getFrameHandle() const {return frameHandle;}
+
+      // - Set the window title
+      void setName(const char* name);
+
+      // - Set the key that causes the system/F8 menu to be displayed
+      void setMenuKey(rdr::U8 key) { menuKey = key; }
+
+      // - Pointer event handling
+      void setEmulate3(bool em3) { ptr.enableEmulate3(em3); }
+      void setPointerEventInterval(int interval) { ptr.enableInterval(interval); }
+
+      // - Set the pixel format, size etc of the underlying PixelBuffer
+      void setPF(const PixelFormat& pf);
+      PixelFormat getPF() const { return buffer->getPF(); }
+      void setSize(int w, int h);
+      void setColour(int i, int r, int g, int b) {buffer->setColour(i, r, g, b);}
+
+      // - Set the cursor to render when the pointer is within the desktop buffer
+      void setCursor(int w, int h, const Point& hotspot, void* data, void* mask);
+      void showCursor() { showLocalCursor(); }
+
+      // - Set whether to show the toolbar
+      // FIXME: Actually show/hide the toolbar.
+      void setShowToolbar(bool st) { showToolbar = st; }
+
+      // - Set the window fullscreen / determine whether it is fullscreen
+      void setFullscreen(bool fs);
+      bool isFullscreen() { return fullscreenActive; }
+
+      // - Set whether to disable special Windows keys & pass them straight to server
+      void setDisableWinKeys(bool dwk);
+
+      // - Set/get which monitor the window should be displayed on
+      void setMonitor(const char* monitor);
+      char* getMonitor() const;
+
+      // - Set the local clipboard
+      void serverCutText(const char* str, int len);
+
+      // - Draw into the desktop buffer & update the window
+      void fillRect(const Rect& r, Pixel pix);
+      void imageRect(const Rect& r, void* pixels);
+      void copyRect(const Rect& r, int srcX, int srcY);
+
+      void invertRect(const Rect& r);
+
+      // - Update the window palette if the display is palette-based.
+      //   Colours are pulled from the desktop buffer's ColourMap.
+      //   Only the specified range of indexes is dealt with.
+      //   After the update, the entire window is redrawn.
+      void refreshWindowPalette(int start, int count);
+
+      // Clipboard::Notifier interface
+      void notifyClipboardChanged(const char* text, int len);
+
+      // DesktopWindow Callback interface
+      class Callback : public InputHandler {
+      public:
+        virtual ~Callback() {}
+        virtual void displayChanged() = 0;
+        virtual void paintCompleted() = 0;
+        virtual bool sysCommand(WPARAM wParam, LPARAM lParam) = 0;
+        virtual void closeWindow() = 0;
+        virtual void refreshMenu(bool enableSysItems) = 0;
+      };
+
+      // Currently accessible so that the CConn can releaseAllKeys & check
+      // whether Ctrl and Alt are down...
+      rfb::win32::CKeyboard kbd;
+
+    protected:
+      // Routines to convert between Desktop and client (window) coordinates
+      Point desktopToClient(const Point& p) {
+        Point pos = p;
+        if (client_size.width() > buffer->width())
+          pos.x += (client_size.width() - buffer->width()) / 2;
+        else if (client_size.width() < buffer->width())
+          pos.x -= scrolloffset.x;
+        if (client_size.height() > buffer->height())
+          pos.y += (client_size.height() - buffer->height()) / 2;
+        else if (client_size.height() < buffer->height())
+          pos.y -= scrolloffset.y;
+        return pos;
+      }
+      Rect desktopToClient(const Rect& r) {
+        return Rect(desktopToClient(r.tl), desktopToClient(r.br));
+      }
+      Point clientToDesktop(const Point& p) {
+        Point pos = p;
+        if (client_size.width() > buffer->width())
+          pos.x -= (client_size.width() - buffer->width()) / 2;
+        else if (client_size.width() < buffer->width())
+          pos.x += scrolloffset.x;
+        if (client_size.height() > buffer->height())
+          pos.y -= (client_size.height() - buffer->height()) / 2;
+        else if (client_size.height() < buffer->height())
+          pos.y += scrolloffset.y;
+        return pos;
+      }
+      Rect clientToDesktop(const Rect& r) {
+        return Rect(clientToDesktop(r.tl), clientToDesktop(r.br));
+      }
+
+      // Internal routine used by the scrollbars & bump scroller to select
+      // the portion of the Desktop to display
+      bool setViewportOffset(const Point& tl);
+    
+      // Bump scroll handling.  Bump scrolling is used if the window is
+      // in fullscreen mode and the Desktop is larger than the window
+      bool processBumpScroll(const Point& cursorPos);
+      void setBumpScroll(bool on);
+      bool bumpScroll;
+      Point bumpScrollDelta;
+      IntervalTimer bumpScrollTimer;
+
+      // Locally-rendered VNC cursor
+      void hideLocalCursor();
+      void showLocalCursor();
+      void renderLocalCursor();
+
+      // The system-rendered cursor
+      void hideSystemCursor();
+      void showSystemCursor();
+
+      // cursorOutsideBuffer() is called whenever we detect that the mouse has
+      // moved outside the desktop.  It restores the system arrow cursor.
+      void cursorOutsideBuffer();
+
+      // Returns true if part of the supplied rect is visible, false otherwise
+      bool invalidateDesktopRect(const Rect& crect);
+
+      // Determine whether or not we need to enable/disable scrollbars and set the
+      // window style accordingly
+      void calculateScrollBars();
+
+      // Win32-specific input handling
+      rfb::win32::CPointer ptr;
+      Point oldpos;
+      rfb::win32::Clipboard clipboard;
+
+      // Palette handling
+      LogicalPalette windowPalette;
+      bool palette_changed;
+
+      // - Full-screen mode
+      RECT fullscreenOldRect;
+      DWORD fullscreenOldFlags;
+      bool fullscreenActive;
+      bool fullscreenRestore;
+
+      // Cursor handling
+      Cursor cursor;
+      bool systemCursorVisible;  // Should system-cursor be drawn?
+      bool trackingMouseLeave;
+      bool cursorInBuffer;    // Is cursor position within server buffer? (ONLY for LocalCursor)
+      bool cursorVisible;     // Is cursor currently rendered?
+      bool cursorAvailable;   // Is cursor available for rendering?
+      Point cursorPos;
+      ManagedPixelBuffer cursorBacking;
+      Rect cursorBackingRect;
+
+      // ToolBar handling
+      ViewerToolBar tb;
+      bool showToolbar;
+
+      // Local window state
+      win32::DIBSectionBuffer* buffer;
+      bool has_focus;
+      Rect window_size;
+      Rect client_size;
+      Point scrolloffset;
+      Point maxscrolloffset;
+      HWND handle;
+      HWND frameHandle;
+      rdr::U8 menuKey;
+
+      Callback* callback;
+    };
+
+  };
+
+};
+
+#endif // __RFB_WIN32_DESKTOP_WINDOW_H__
+
+
index 0d2313a55ade5ae7cf040ef54de727f970244919..e74896dcbe22fbc03b493743f094243d8f871599 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* 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
@@ -17,7 +17,7 @@
  */
 #include <vncviewer/InfoDialog.h>
 #include <vncviewer/resource.h>
-#include <vncviewer/CView.h>
+#include <vncviewer/CConn.h>
 #include <rfb/secTypes.h>
 #include <rfb/encodings.h>
 #include <rfb/CSecurity.h>
@@ -29,37 +29,37 @@ using namespace rfb::win32;
 static LogWriter vlog("Info");
 
 
-bool InfoDialog::showDialog(CView* vw) {
-  view = vw;
+bool InfoDialog::showDialog(CConn* cc) {
+  conn = cc;
   return Dialog::showDialog(MAKEINTRESOURCE(IDD_CONNECTION_INFO));
 }
 
 void InfoDialog::initDialog() {
   char buf[256];
 
-  setItemString(IDC_INFO_NAME, TStr(view->cp.name()));
+  setItemString(IDC_INFO_NAME, TStr(conn->cp.name()));
 
-  setItemString(IDC_INFO_HOST, TCharArray(view->sock->getPeerAddress()).buf);
+  setItemString(IDC_INFO_HOST, TCharArray(conn->getSocket()->getPeerAddress()).buf);
 
-  Rect bufRect = view->buffer->getRect();
-  sprintf(buf, "%dx%d", bufRect.width(), bufRect.height());
+  sprintf(buf, "%dx%d", conn->cp.width, conn->cp.height);
   setItemString(IDC_INFO_SIZE, TStr(buf));
 
-  view->cp.pf().print(buf, 256);
+  conn->cp.pf().print(buf, 256);
   setItemString(IDC_INFO_PF, TStr(buf));
 
-  view->serverDefaultPF.print(buf, 256);
+  conn->getServerDefaultPF().print(buf, 256);
   setItemString(IDC_INFO_DEF_PF, TStr(buf));
 
-  setItemString(IDC_REQUESTED_ENCODING, TStr(encodingName(view->getOptions().preferredEncoding)));
-  setItemString(IDC_LAST_ENCODING, TStr(encodingName(view->lastUsedEncoding())));
+  setItemString(IDC_REQUESTED_ENCODING, TStr(encodingName(conn->getOptions().preferredEncoding)));
+  setItemString(IDC_LAST_ENCODING, TStr(encodingName(conn->lastUsedEncoding())));
 
-  sprintf(buf, "%d kbits/s", view->sock->inStream().kbitsPerSecond());
+  sprintf(buf, "%d kbits/s", conn->getSocket()->inStream().kbitsPerSecond());
   setItemString(IDC_INFO_LINESPEED, TStr(buf));
 
-  sprintf(buf, "%d.%d", view->cp.majorVersion, view->cp.minorVersion);
+  sprintf(buf, "%d.%d", conn->cp.majorVersion, conn->cp.minorVersion);
   setItemString(IDC_INFO_VERSION, TStr(buf));
 
-  int secType = view->getCurrentCSecurity()->getType();
-  setItemString(IDC_INFO_SECURITY, TStr(secTypeName(secType)));
+  const CSecurity* cSec = conn->getCurrentCSecurity();
+  setItemString(IDC_INFO_SECURITY, TStr(secTypeName(cSec->getType())));
+  setItemString(IDC_INFO_ENCRYPTION, TStr(cSec->description()));
 }
index 7a64d38333df2c369ce970229599d4300ef11def..752d53c5e4b706d6a46a7098ef241e6ef1ab3737 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* 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
@@ -30,15 +30,15 @@ namespace rfb {
 
   namespace win32 {
 
-    class CView;
+    class CConn;
 
     class InfoDialog : Dialog {
     public:
-      InfoDialog() : Dialog(GetModuleHandle(0)), view(0) {}
-      virtual bool showDialog(CView* vw);
+      InfoDialog() : Dialog(GetModuleHandle(0)), conn(0) {}
+      virtual bool showDialog(CConn* vw);
       virtual void initDialog();
     protected:
-      CView* view;
+      CConn* conn;
     };
 
   };
diff --git a/vncviewer/ListenServer.h b/vncviewer/ListenServer.h
new file mode 100644 (file)
index 0000000..4d1590c
--- /dev/null
@@ -0,0 +1,56 @@
+/* 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.
+ */
+
+// -=- ListenServer.h
+
+#ifndef __RFB_WIN32_LISTEN_SERVER_H__
+#define __RFB_WIN32_LISTEN_SERVER_H__
+
+#include <windows.h>
+#include <winsock2.h>
+#include <network/Socket.h>
+#include <rfb_win32/MsgWindow.h>
+#include <vncviewer/CConnThread.h>
+
+
+namespace rfb {
+  namespace win32 {
+
+    class ListenServer : MsgWindow {
+    public:
+      ListenServer(network::SocketListener* l) : MsgWindow(_T("rfb::win32::ListenServer")), sock(l) {
+        if (WSAAsyncSelect(l->getFd(), getHandle(), WM_USER, FD_ACCEPT) == SOCKET_ERROR)
+          throw rdr::SystemException("unable to monitor listen socket", WSAGetLastError());
+      }
+
+      LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+        if (msg == WM_USER) {
+          network::Socket* newConn = sock->accept();
+          Thread* newThread = new CConnThread(newConn, true);
+          return 0;
+        }
+        return MsgWindow::processMessage(msg, wParam, lParam);
+      }
+    protected:
+      network::SocketListener* sock;
+    };
+
+  };
+};
+
+#endif
\ No newline at end of file
diff --git a/vncviewer/ListenTrayIcon.h b/vncviewer/ListenTrayIcon.h
new file mode 100644 (file)
index 0000000..7e334d9
--- /dev/null
@@ -0,0 +1,95 @@
+/* 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.
+ */
+
+// -=- ListenTrayIcon.h
+
+#ifndef __RFB_WIN32_LISTEN_TRAY_ICON_H__
+#define __RFB_WIN32_LISTEN_TRAY_ICON_H__
+
+#include <rfb_win32/TrayIcon.h>
+#include <rfb_win32/AboutDialog.h>
+
+namespace rfb {
+  namespace win32 {
+
+    class ListenTrayIcon : public TrayIcon {
+    public:
+      ListenTrayIcon() {
+        setIcon(IDI_ICON);
+        setToolTip(_T("VNC Viewer"));
+      }
+      virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+        switch(msg) {
+
+        case WM_USER:
+          switch (lParam) {
+          case WM_LBUTTONDBLCLK:
+            SendMessage(getHandle(), WM_COMMAND, ID_NEW_CONNECTION, 0);
+            break;
+          case WM_RBUTTONUP:
+            HMENU menu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(IDR_TRAY));
+            HMENU trayMenu = GetSubMenu(menu, 0);
+
+            // First item is New Connection, the default
+            SetMenuDefaultItem(trayMenu, ID_NEW_CONNECTION, FALSE);
+
+            // SetForegroundWindow is required, otherwise Windows ignores the
+            // TrackPopupMenu because the window isn't the foreground one, on
+            // some older Windows versions...
+            SetForegroundWindow(getHandle());
+
+            // Display the menu
+            POINT pos;
+            GetCursorPos(&pos);
+            TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, getHandle(), 0);
+            break;
+                           } 
+                           return 0;
+
+        case WM_COMMAND:
+          switch (LOWORD(wParam)) {
+          case ID_NEW_CONNECTION:
+            {
+              Thread* connThread = new CConnThread();
+              break;
+            }
+          case ID_OPTIONS:
+            OptionsDialog::global.showDialog(0);
+            break;
+          case ID_ABOUT:
+            AboutDialog::instance.showDialog();
+            break;
+          case ID_CLOSE:
+            SendMessage(getHandle(), WM_CLOSE, 0, 0);
+            break;
+          }
+          return 0;
+
+        case WM_CLOSE:
+          PostQuitMessage(0);
+          return 0;
+        }
+
+        return TrayIcon::processMessage(msg, wParam, lParam);
+      }
+    };
+
+  };
+};
+
+#endif // __RFB_WIN32_LISTEN_TRAY_ICON_H__
\ No newline at end of file
index f065a06ead122beb66bc6c84e7f5a3e6145be624..ae703b3a1469d7f1de5bb48b62e83538b3c3bb9d 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* 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
 #ifndef __VIEWER_MRU_H__
 #define __VIEWER_MRU_H__
 
-#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <list>
 #include <set>
-
 #include <rfb_win32/Registry.h>
-
 #include <rfb/util.h>
 #include <rdr/HexOutStream.h>
 
@@ -85,7 +82,7 @@ namespace rfb {
             TCharArray keyname = rdr::HexOutStream::binToHexStr(&order[i], 1);
             try {
               TCharArray hostname = key.getString(keyname.buf);
-              if (strcmp(name, CStr(hostname.buf)) == 0) {
+              if (stricmp(name, CStr(hostname.buf)) == 0) {
                 keycode = order[i];
                 found = true;
                 break;
@@ -109,8 +106,6 @@ namespace rfb {
           orderlen = 0;
         }
 
-        printf("keycode=%d\n", (int)keycode);
-
         orderlen++;
         int i, j=orderlen-1;
         for (i=0; i<orderlen-1; i++) {
@@ -124,8 +119,6 @@ namespace rfb {
           order[i] = order[i-1];
         order[0] = keycode;
 
-        printf("selected %d\n", (int)keycode);
-
         TCharArray keyname = rdr::HexOutStream::binToHexStr((char*)&keycode, 1);
         key.setString(keyname.buf, TStr(name));
         key.setBinary(_T("Order"), order, orderlen);
index 0985f5b1e751f761e80b2210527a76c25a04e912..93e033aa82d1d7edc09e823f28790e826413a694 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* 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
  * USA.
  */
 
-#define WIN32_LEAN_AND_MEAN
-#if (_WIN32_WINNT < 0x0400)
-#define _WIN32_WINNT 0x0400
-#endif
-#include <windows.h>
-#include <commdlg.h>
-
 #include <vncviewer/OptionsDialog.h>
-#include <vncviewer/CView.h>
+#include <vncviewer/CConn.h>
 #include <vncviewer/resource.h>
 #include <rfb_win32/Registry.h>
-#include <rfb/LogWriter.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/OSVersion.h>
 #include <rfb/encodings.h>
 #include <rfb/CConnection.h>
+#include <commdlg.h>
+#include <rfb/LogWriter.h>
 
 using namespace rfb;
 using namespace rfb::win32;
@@ -38,22 +34,22 @@ static LogWriter vlog("Options");
 
 
 struct OptionsInfo {
-  CView* view;
-  CViewOptions options;
+  CConn* view;
+  CConnOptions options;
 };
 
 
 OptionsDialog rfb::win32::OptionsDialog::global;
 
 
-class VNCviewerOptions : public PropSheet {
+class ViewerOptions : public PropSheet {
 public:
-  VNCviewerOptions(OptionsInfo& info_, std::list<PropSheetPage*> pages)
+  ViewerOptions(OptionsInfo& info_, std::list<PropSheetPage*> pages)
     : PropSheet(GetModuleHandle(0), 
     info_.view ? _T("VNC Viewer Options") : _T("VNC Viewer Defaults"), pages),
     info(info_), changed(false) {
   }
-  ~VNCviewerOptions() {
+  ~ViewerOptions() {
     if (changed) {
       if (info.view)
         // Apply the settings to the supplied session object
@@ -121,7 +117,7 @@ public:
       dlg->options.preferredEncoding = encodingHextile;
     if (isItemChecked(IDC_ENCODING_RAW))
       dlg->options.preferredEncoding = encodingRaw;
-    ((VNCviewerOptions*)propSheet)->setChanged();
+    ((ViewerOptions*)propSheet)->setChanged();
     return true;
   }
   virtual bool onCommand(int id, int cmd) {
@@ -165,6 +161,7 @@ public:
     enableItem(IDC_PROTOCOL_3_3, (!dlg->view) || (dlg->view->state() != CConnection::RFBSTATE_NORMAL));
     setItemChecked(IDC_PROTOCOL_3_3, dlg->options.protocol3_3);
     setItemChecked(IDC_ACCEPT_BELL, dlg->options.acceptBell);
+    setItemChecked(IDC_AUTO_RECONNECT, dlg->options.autoReconnect);
     setItemChecked(IDC_SHOW_TOOLBAR, dlg->options.showToolbar);
   }
   virtual bool onOk() {
@@ -174,8 +171,9 @@ public:
     dlg->options.useDesktopResize = isItemChecked(IDC_DESKTOP_RESIZE);
     dlg->options.protocol3_3 = isItemChecked(IDC_PROTOCOL_3_3);
     dlg->options.acceptBell = isItemChecked(IDC_ACCEPT_BELL);
+    dlg->options.autoReconnect = isItemChecked(IDC_AUTO_RECONNECT);
     dlg->options.showToolbar = isItemChecked(IDC_SHOW_TOOLBAR);
-    ((VNCviewerOptions*)propSheet)->setChanged();
+    ((ViewerOptions*)propSheet)->setChanged();
     return true;
   }
 protected:
@@ -193,6 +191,8 @@ public:
     setItemChecked(IDC_SEND_SYSKEYS, dlg->options.sendSysKeys);
     setItemChecked(IDC_CLIENT_CUTTEXT, dlg->options.clientCutText);
     setItemChecked(IDC_SERVER_CUTTEXT, dlg->options.serverCutText);
+    setItemChecked(IDC_DISABLE_WINKEYS, dlg->options.disableWinKeys && !osVersion.isPlatformWindows);
+    enableItem(IDC_DISABLE_WINKEYS, !osVersion.isPlatformWindows);
     setItemChecked(IDC_EMULATE3, dlg->options.emulate3);
     setItemChecked(IDC_POINTER_INTERVAL, dlg->options.pointerEventInterval != 0);
 
@@ -216,6 +216,7 @@ public:
     dlg->options.sendSysKeys = isItemChecked(IDC_SEND_SYSKEYS);
     dlg->options.clientCutText = isItemChecked(IDC_CLIENT_CUTTEXT);
     dlg->options.serverCutText = isItemChecked(IDC_SERVER_CUTTEXT);
+    dlg->options.disableWinKeys = isItemChecked(IDC_DISABLE_WINKEYS);
     dlg->options.emulate3 = isItemChecked(IDC_EMULATE3);
     dlg->options.pointerEventInterval = 
       isItemChecked(IDC_POINTER_INTERVAL) ? 200 : 0;
@@ -229,14 +230,13 @@ public:
     else
       dlg->options.setMenuKey(CStr(keyName.buf));
 
-    ((VNCviewerOptions*)propSheet)->setChanged();
+    ((ViewerOptions*)propSheet)->setChanged();
     return true;
   }
 protected:
   OptionsInfo* dlg;
 };
 
-
 class DefaultsPage : public PropSheetPage {
 public:
   DefaultsPage(OptionsInfo* dlg_)
@@ -247,10 +247,9 @@ public:
     enableItem(IDC_SAVE_CONFIG, dlg->options.configFileName.buf);
   }
   virtual bool onCommand(int id, int cmd) {
-    HWND hwnd = dlg->view ? dlg->view->getHandle() : 0;
     switch (id) {
     case IDC_LOAD_DEFAULTS:
-      dlg->options = CViewOptions();
+      dlg->options = CConnOptions();
       break;
     case IDC_SAVE_DEFAULTS:
       propSheet->commitPages();
@@ -262,7 +261,7 @@ public:
     case IDC_SAVE_CONFIG:
       propSheet->commitPages();
       dlg->options.writeToFile(dlg->options.configFileName.buf);
-      MsgBox(hwnd, _T("Options saved successfully"),
+      MsgBox(handle, _T("Options saved successfully"),
              MB_OK | MB_ICONINFORMATION);
       return 0;
     case IDC_SAVE_CONFIG_AS:
@@ -281,7 +280,7 @@ public:
 #else
       ofn.lStructSize = sizeof(ofn);
 #endif
-      ofn.hwndOwner = hwnd;
+      ofn.hwndOwner = handle;
       ofn.lpstrFilter = _T("VNC Connection Options\000*.vnc\000");
       ofn.lpstrFile = newFilename;
       currentDir[0] = 0;
@@ -298,7 +297,7 @@ public:
 
       // Save the Options
       dlg->options.writeToFile(CStr(newFilename));
-      MsgBox(hwnd, _T("Options saved successfully"),
+      MsgBox(handle, _T("Options saved successfully"),
              MB_OK | MB_ICONINFORMATION);
       return 0;
     };
@@ -313,7 +312,7 @@ protected:
 OptionsDialog::OptionsDialog() : visible(false) {
 }
 
-bool OptionsDialog::showDialog(CView* view, bool capture) {
+bool OptionsDialog::showDialog(CConn* view, bool capture) {
   if (visible) return false;
   visible = true;
 
@@ -331,8 +330,9 @@ bool OptionsDialog::showDialog(CView* view, bool capture) {
   DefaultsPage defPage(&info); if (view) pages.push_back(&defPage);
 
   // Show the property sheet
-  VNCviewerOptions dialog(info, pages);
-  dialog.showPropSheet(view ? view->getHandle() : 0, false, false, capture);
+  ViewerOptions dialog(info, pages);
+  dialog.showPropSheet(view && view->getWindow() ? view->getWindow()->getHandle() : 0,
+                       false, false, capture);
 
   visible = false;
   return dialog.changed;
index eec9b96a234fe65afd8144b5df156fd382ed5a32..fcddc71c69b040736a07fd8712918972ce055deb 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2003 RealVNC Ltd.  All Rights Reserved.
- *    
+/* 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
 #ifndef __RFB_WIN32_OPTIONS_DIALOG_H__
 #define __RFB_WIN32_OPTIONS_DIALOG_H__
 
-#include <vncviewer/CViewOptions.h>
 #include <rfb_win32/Dialog.h>
 
 namespace rfb {
 
   namespace win32 {
 
-    class CView;
+    class CConn;
 
     class OptionsDialog {
     public:
       OptionsDialog();
-      virtual bool showDialog(CView* cfg, bool capture=false);
+      virtual bool showDialog(CConn* cfg, bool capture=false);
 
       static OptionsDialog global;
     protected:
index 8ab4ba4c9b32e1d74cfbb63f52b385d149b4878c..2eea0ea071bc617b9193010044e2cb07837406af 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* 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
 
 #include <vncviewer/UserPasswdDialog.h>
 #include <vncviewer/resource.h>
+#include <rfb/Exception.h>
 
 using namespace rfb;
 using namespace rfb::win32;
 
 
-UserPasswdDialog::UserPasswdDialog() : Dialog(GetModuleHandle(0)), showUsername(false) {
+UserPasswdDialog::UserPasswdDialog() : Dialog(GetModuleHandle(0)),
+  showUsername(false), showPassword(false) {
 }
 
 
@@ -36,18 +38,18 @@ bool UserPasswdDialog::showDialog() {
 }
 
 void UserPasswdDialog::initDialog() {
-  if (username.buf) {
+  if (username.buf)
     setItemString(IDC_USERNAME, username.buf);
-    tstrFree(username.takeBuf());
-  }
-  if (password.buf) {
+  if (password.buf)
     setItemString(IDC_PASSWORD, password.buf);
-    tstrFree(password.takeBuf());
-  }
   if (!showUsername) {
     setItemString(IDC_USERNAME, _T(""));
     enableItem(IDC_USERNAME, false);
   }
+  if (!showPassword) {
+    setItemString(IDC_PASSWORD, _T(""));
+    enableItem(IDC_PASSWORD, false);
+  }
   if (description.buf) {
     TCharArray title(128);
     GetWindowText(handle, title.buf, 128);
@@ -59,26 +61,25 @@ void UserPasswdDialog::initDialog() {
 }
 
 bool UserPasswdDialog::onOk() {
-       username.buf = getItemString(IDC_USERNAME);
-       password.buf = getItemString(IDC_PASSWORD);
+       username.replaceBuf(getItemString(IDC_USERNAME));
+       password.replaceBuf(getItemString(IDC_PASSWORD));
   return true;
 }
 
 
-bool UserPasswdDialog::getUserPasswd(char** user, char** passwd) {
-  bool result = false;
+void UserPasswdDialog::getUserPasswd(char** user, char** passwd) {
   showUsername = user != 0;
+  showPassword = passwd != 0;
   if (user && *user)
-    username.buf = tstrDup(*user);
+    username.replaceBuf(tstrDup(*user));
   if (passwd && *passwd)
-    password.buf = tstrDup(*passwd);
-  if (showDialog()) {
-    if (user)
-      *user = strDup(username.buf);
+    password.replaceBuf(tstrDup(*passwd));
+
+  if (!showDialog())
+    throw rfb::AuthCancelledException();
+
+  if (user)
+    *user = strDup(username.buf);
+  if (passwd)
     *passwd = strDup(password.buf);
-    result = true;
-  }
-  tstrFree(username.takeBuf());
-  tstrFree(password.takeBuf());
-  return result;
 }
index 998a49f19f9753e8f42018703ac0bbf7e23c4c94..bf006f4d59c1feb61f430f8ea1f4e3ec7fc3ce1f 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* 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
 // -=- UserPasswdDialog.h
 
 // Username and password dialog for VNC Viewer 4.0
+// Note that the password and username fields are only freed
+// when the dialog instance is deleted - it is important to
+// ensure that the instance is deleted as early as possible, to
+// avoid the password being retained in memory for too long.
 
 #ifndef __RFB_WIN32_USERPASSWD_DIALOG_H__
 #define __RFB_WIN32_USERPASSWD_DIALOG_H__
@@ -38,12 +42,12 @@ namespace rfb {
       virtual bool showDialog();
       virtual void initDialog();
       virtual bool onOk();
-      virtual bool getUserPasswd(char** user, char** passwd);
+      virtual void getUserPasswd(char** user, char** passwd);
       void setCSecurity(const CSecurity* cs);
     protected:
       TCharArray username;
-      TCharArray password;
-      bool showUsername;
+      TPlainPasswd password;
+      bool showUsername, showPassword;
       TCharArray description;
     };
 
index bab2e137e23d11dc4ae5ca96423de3c290b7df32..9f37b3874b8203203e71b3701a7bcb1b6a061dee 100644 (file)
@@ -1 +1,18 @@
-const char* buildTime = "Built on " __DATE__ " at " __TIME__;
\ No newline at end of file
+/* Copyright (C) 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.
+ */
+const char* buildTime = "Built on " __DATE__ " at " __TIME__;
diff --git a/vncviewer/cview.cxx b/vncviewer/cview.cxx
deleted file mode 100644 (file)
index 03c68e2..0000000
+++ /dev/null
@@ -1,1742 +0,0 @@
-/* Copyright (C) 2002-2004 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.
- */
-#define WIN32_LEAN_AND_MEAN
-#if (_WIN32_WINNT < 0x0400)
-#define _WIN32_WINNT 0x0400
-#endif
-#include <windows.h>
-#include <winsock2.h>
-#include <tchar.h>
-#include <commctrl.h>
-
-#include <network/TcpSocket.h>
-
-#include <vncviewer/CView.h>
-#include <vncviewer/UserPasswdDialog.h>
-#include <vncviewer/resource.h>
-
-#include <rfb/encodings.h>
-#include <rfb/secTypes.h>
-#include <rfb/CSecurityNone.h>
-#include <rfb/CSecurityVncAuth.h>
-#include <rfb/CMsgWriter.h>
-#include <rfb/Configuration.h>
-#include <rfb/LogWriter.h>
-
-#include <rfb_win32/WMShatter.h>
-
-using namespace rfb;
-using namespace rfb::win32;
-using namespace rdr;
-
-// - Statics & consts
-
-static LogWriter vlog("CView");
-
-const int IDM_FULLSCREEN = ID_FULLSCREEN;
-const int IDM_SEND_MENU_KEY = ID_SEND_MENU_KEY;
-const int IDM_SEND_CAD = ID_SEND_CAD;
-const int IDM_SEND_CTLESC = ID_SEND_CTLESC;
-const int IDM_ABOUT = ID_ABOUT;
-const int IDM_OPTIONS = ID_OPTIONS;
-const int IDM_INFO = ID_INFO;
-const int IDM_NEWCONN = ID_NEW_CONNECTION;
-const int IDM_REQUEST_REFRESH = ID_REQUEST_REFRESH;
-const int IDM_CTRL_KEY = ID_CTRL_KEY;
-const int IDM_ALT_KEY = ID_ALT_KEY;
-const int IDM_FILE_TRANSFER = ID_FILE_TRANSFER;
-const int IDM_CONN_SAVE_AS = ID_CONN_SAVE_AS;
-
-const int TIMER_BUMPSCROLL = 1;
-const int TIMER_POINTER_INTERVAL = 2;
-const int TIMER_POINTER_3BUTTON = 3;
-
-const int HOTKEY_ALTTAB = 0;
-
-
-IntParameter debugDelay("DebugDelay","Milliseconds to display inverted "
-                        "pixel data - a debugging feature", 0);
-
-
-//
-// -=- CViewClass
-
-//
-// Window class used as the basis for all CView instances
-//
-
-class CViewClass {
-public:
-  CViewClass();
-  ~CViewClass();
-  ATOM classAtom;
-  HINSTANCE instance;
-};
-
-LRESULT CALLBACK CViewProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
-  LRESULT result;
-
-  // *** vlog.debug("CViewMsg %x->(%x, %x, %x)", wnd, msg, wParam, lParam);
-
-  if (msg == WM_CREATE)
-    SetWindowLong(wnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
-  else if (msg == WM_DESTROY)
-    SetWindowLong(wnd, GWL_USERDATA, 0);
-  CView* _this = (CView*) GetWindowLong(wnd, GWL_USERDATA);
-  if (!_this) {
-    vlog.info("null _this in %x, message %u", wnd, msg);
-    return rfb::win32::SafeDefWindowProc(wnd, msg, wParam, lParam);
-  }
-
-  try {
-    result = _this->processMessage(msg, wParam, lParam);
-  } catch (rdr::Exception& e) {
-    vlog.error("untrapped: %s", e.str());
-  }
-
-  return result;
-};
-
-HCURSOR dotCursor = (HCURSOR)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDC_DOT_CURSOR), IMAGE_CURSOR, 0, 0, LR_SHARED);
-HCURSOR arrowCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED); 
-
-CViewClass::CViewClass() : classAtom(0) {
-  WNDCLASS wndClass;
-  wndClass.style = 0;
-  wndClass.lpfnWndProc = CViewProc;
-  wndClass.cbClsExtra = 0;
-  wndClass.cbWndExtra = 0;
-  wndClass.hInstance = instance = GetModuleHandle(0);
-  wndClass.hIcon = (HICON)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 0, 0, LR_SHARED);
-  if (!wndClass.hIcon)
-    printf("unable to load icon:%ld", GetLastError());
-  wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
-  wndClass.hbrBackground = NULL;
-  wndClass.lpszMenuName = 0;
-  wndClass.lpszClassName = _T("rfb::win32::CViewClass");
-  classAtom = RegisterClass(&wndClass);
-  if (!classAtom) {
-    throw rdr::SystemException("unable to register CView window class", GetLastError());
-  }
-}
-
-CViewClass::~CViewClass() {
-  if (classAtom) {
-    UnregisterClass((const TCHAR*)classAtom, instance);
-  }
-}
-
-CViewClass baseClass;
-
-//
-// -=- FrameClass
-
-//
-// Window class used to display the rfb data
-//
-
-class FrameClass {
-public:
-  FrameClass();
-  ~FrameClass();
-  ATOM classAtom;
-  HINSTANCE instance;
-};
-
-LRESULT CALLBACK FrameProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
-  LRESULT result;
-
-  if (msg == WM_CREATE)
-    SetWindowLong(hwnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
-  else if (msg == WM_DESTROY)
-    SetWindowLong(hwnd, GWL_USERDATA, 0);
-  CView* _this = (CView*) GetWindowLong(hwnd, GWL_USERDATA);
-  if (!_this) {
-    vlog.info("null _this in %x, message %u", hwnd, msg);
-    return DefWindowProc(hwnd, msg, wParam, lParam);
-  }
-
-  try {
-    result = _this->processFrameMessage(msg, wParam, lParam);
-  } catch (rdr::Exception& e) {
-    vlog.error("untrapped: %s", e.str());
-  }
-
-  return result;
-}
-
-FrameClass::FrameClass() : classAtom(0) {
-  WNDCLASS wndClass;
-  wndClass.style = 0;
-  wndClass.lpfnWndProc = FrameProc;
-  wndClass.cbClsExtra = 0;
-  wndClass.cbWndExtra = 0;
-  wndClass.hInstance = instance = GetModuleHandle(0);
-  wndClass.hIcon = 0;
-  wndClass.hCursor = NULL;
-  wndClass.hbrBackground = 0;
-  wndClass.lpszMenuName = 0;
-  wndClass.lpszClassName = _T("FrameClass");
-  classAtom = RegisterClass(&wndClass);
-  if (!classAtom) {
-    throw rdr::SystemException("unable to register frame window class",
-                               GetLastError());
-  }
-}
-
-FrameClass::~FrameClass() {
-  if (classAtom) {
-    UnregisterClass((const TCHAR*)classAtom, instance);
-  }
-}
-
-FrameClass frameClass;
-
-//
-// -=- CView instance implementation
-//
-
-RegKey CView::userConfigKey;
-
-
-CView::CView() 
-  : quit_on_destroy(false), buffer(0), sock(0), readyToRead(false),
-    client_size(0, 0, 16, 16), window_size(0, 0, 32, 32),
-    cursorVisible(false), cursorAvailable(false), cursorInBuffer(false),
-    systemCursorVisible(true), trackingMouseLeave(false),
-    hwnd(0), frameHwnd(0), requestUpdate(false), has_focus(false), 
-    palette_changed(false), sameMachine(false), encodingChange(false), 
-    formatChange(false), lastUsedEncoding_(encodingRaw), fullScreenActive(false),
-    bumpScroll(false), manager(0), toolbar(true) {
-
-  // Create the main window
-  const TCHAR* name = _T("VNC Viewer 4.0b");
-  hwnd = CreateWindow((const TCHAR*)baseClass.classAtom, name, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
-    0, 0, 10, 10, 0, 0, baseClass.instance, this);
-  if (!hwnd) {
-    throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError());
-  }
-  vlog.debug("created window \"%s\" (%x)", (const char*)CStr(name), hwnd);
-
-  // Create the viewer toolbar
-  tb.create(getHandle());
-  vlog.debug("created toolbar window \"%s\" (%x)", "ViewerToolBar", tb.getHandle());
-
-  // Create the frame window
-  frameHwnd = CreateWindowEx(WS_EX_CLIENTEDGE, (const TCHAR*)frameClass.classAtom,
-    0, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
-    CW_USEDEFAULT, CW_USEDEFAULT, getHandle(), 0, frameClass.instance, this);
-  if (!frameHwnd) {
-    throw rdr::SystemException("unable to create rfb frame window instance", GetLastError());
-  }
-  vlog.debug("created window \"%s\" (%x)", "Frame Window", frameHwnd);
-
-  // Initialise the CPointer pointer handler
-  ptr.setHWND(getFrameHandle());
-  ptr.setIntervalTimerId(TIMER_POINTER_INTERVAL);
-  ptr.set3ButtonTimerId(TIMER_POINTER_3BUTTON);
-
-  // Initialise the bumpscroll timer
-  bumpScrollTimer.setHWND(getHandle());
-  bumpScrollTimer.setId(TIMER_BUMPSCROLL);
-
-  // Grab AltTab
-  setAltTabGrab(options.sendSysKeys);
-
-  // Hook the clipboard
-  clipboard.setNotifier(this);
-
-  // Create the backing buffer
-  buffer = new win32::DIBSectionBuffer(getFrameHandle());
-}
-
-CView::~CView() {
-  vlog.debug("~CView");
-  showSystemCursor();
-  if (hwnd) {
-    setVisible(false);
-    DestroyWindow(hwnd);
-    hwnd = 0;
-  }
-  delete buffer;
-  vlog.debug("~CView done");
-}
-
-bool CView::initialise(network::Socket* s) {
-  // Update the window menu
-  HMENU wndmenu = GetSystemMenu(hwnd, FALSE);
-  AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
-  AppendMenu(wndmenu, MF_STRING, IDM_FULLSCREEN, _T("&Full screen"));
-  AppendMenu(wndmenu, (options.showToolbar ? MF_STRING | MF_CHECKED : MF_STRING), 
-    IDM_SHOW_TOOLBAR, _T("Show tool&bar"));
-  AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
-  AppendMenu(wndmenu, MF_STRING, IDM_CTRL_KEY, _T("Ctr&l"));
-  AppendMenu(wndmenu, MF_STRING, IDM_ALT_KEY, _T("Al&t"));
-  AppendMenu(wndmenu, MF_STRING, IDM_SEND_CAD, _T("Send Ctrl-Alt-&Del"));
-  AppendMenu(wndmenu, MF_STRING, IDM_SEND_CTLESC, _T("Send Ctrl-&Esc"));
-  AppendMenu(wndmenu, MF_STRING, IDM_REQUEST_REFRESH, _T("Refres&h Screen"));
-  AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
-  if (manager) AppendMenu(wndmenu, MF_STRING, IDM_NEWCONN, _T("Ne&w Connection..."));
-  AppendMenu(wndmenu, MF_STRING, IDM_OPTIONS, _T("&Options..."));
-  AppendMenu(wndmenu, MF_STRING, IDM_INFO, _T("Connection &Info..."));
-  AppendMenu(wndmenu, MF_STRING, IDM_ABOUT, _T("&About..."));
-
-  // Set the server's name for MRU purposes
-  CharArray endpoint(s->getPeerEndpoint());
-  setServerName(endpoint.buf);
-  if (!options.host.buf)
-    options.setHost(endpoint.buf);
-
-  // Initialise the underlying CConnection
-  setStreams(&s->inStream(), &s->outStream());
-
-  // Enable processing of window messages while blocked on I/O
-  s->inStream().setBlockCallback(this);
-
-  // Initialise the viewer options
-  applyOptions(options);
-
-  // - Set which auth schemes we support
-  addSecType(secTypeNone);
-  addSecType(secTypeVncAuth);
-
-  initialiseProtocol();
-  WSAAsyncSelect(s->getFd(), getHandle(), WM_USER, FD_READ | FD_CLOSE);
-  sock = s;
-
-  m_fileTransfer.initialize(&s->inStream(), &s->outStream());
-
-  // Show toolbar if needed
-  toolbar = options.showToolbar;
-  if (options.showToolbar) tb.show();
-  else tb.hide();
-
-  return true;
-}
-
-
-void
-CView::applyOptions(CViewOptions& opt) {
-  // *** CHANGE THIS TO USE CViewOptions::operator= ***
-
-  // - Take the username, password, config filename, and host spec
-  options.setUserName(opt.userName.buf);
-  options.setPassword(opt.password.buf);
-  options.setHost(opt.host.buf);
-  options.setConfigFileName(opt.configFileName.buf);
-  options.setMonitor(opt.monitor.buf);
-
-  // - Set optional features in ConnParams
-  encodingChange |= ((options.useLocalCursor != opt.useLocalCursor) ||
-    (options.useDesktopResize != opt.useDesktopResize));
-  cp.supportsLocalCursor = options.useLocalCursor = opt.useLocalCursor;
-  cp.supportsDesktopResize = options.useDesktopResize = opt.useDesktopResize;
-
-  encodingChange |= ((options.customCompressLevel != opt.customCompressLevel) ||
-                    (options.compressLevel != opt.compressLevel) ||
-                    (options.noJpeg != opt.noJpeg) ||
-                    (options.qualityLevel != opt.qualityLevel));
-  cp.customCompressLevel = options.customCompressLevel = opt.customCompressLevel;
-  cp.compressLevel = options.compressLevel = opt.compressLevel;
-  cp.noJpeg = options.noJpeg = opt.noJpeg;
-  cp.qualityLevel = options.qualityLevel = opt.qualityLevel;
-
-  if (cursorAvailable)
-    hideLocalCursor();
-  cursorAvailable = cursorAvailable && options.useLocalCursor;
-
-  // - Switch full-screen mode on/off
-  options.fullScreen = opt.fullScreen;
-  setFullscreen(options.fullScreen);
-
-  // - Handle format/encoding options
-  encodingChange |= (options.preferredEncoding != opt.preferredEncoding);
-  options.preferredEncoding = opt.preferredEncoding;
-
-  formatChange |= (options.fullColour != opt.fullColour);
-  options.fullColour = opt.fullColour;
-
-  if (!options.fullColour)
-    formatChange |= (options.lowColourLevel != opt.lowColourLevel);
-  options.lowColourLevel = opt.lowColourLevel;
-
-  options.autoSelect = opt.autoSelect;
-
-  // - Sharing
-  options.shared = opt.shared;
-  setShared(options.shared);
-
-  // - Inputs
-  options.sendPtrEvents = opt.sendPtrEvents;
-  options.sendKeyEvents = opt.sendKeyEvents;
-  options.sendSysKeys = opt.sendSysKeys;
-  setAltTabGrab(options.sendSysKeys);
-  options.clientCutText = opt.clientCutText;
-  options.serverCutText = opt.serverCutText;
-  options.emulate3 = opt.emulate3;
-  ptr.enableEmulate3(opt.emulate3);
-  options.pointerEventInterval = opt.pointerEventInterval;
-  ptr.enableInterval(opt.pointerEventInterval);
-  options.menuKey = opt.menuKey;
-
-  // - Protocol version override
-  options.protocol3_3 = opt.protocol3_3;
-  setProtocol3_3(options.protocol3_3);
-
-  // - Bell
-  options.acceptBell = opt.acceptBell;
-
-  // - Show/hide toolbar
-  options.showToolbar = opt.showToolbar;
-}
-
-void
-CView::setFullscreen(bool fs) {
-  // Set the menu fullscreen option tick
-  CheckMenuItem(GetSystemMenu(getHandle(), FALSE), IDM_FULLSCREEN,
-    (options.fullScreen ? MF_CHECKED : 0) | MF_BYCOMMAND);
-
-  // If the fullscreen mode is active then disable the menu point 
-  // "Show toolbar", otherwise enable the menu point.
-  EnableMenuItem(GetSystemMenu(getHandle(), FALSE), IDM_SHOW_TOOLBAR,
-    (options.fullScreen ? MF_GRAYED : MF_ENABLED) | MF_BYCOMMAND);
-
-  // If the window is not visible then we ignore the request.
-  // setVisible() will call us to correct the full-screen state when
-  // the window is visible, to keep things consistent.
-  if (!IsWindowVisible(getHandle()))
-    return;
-
-  if (fs && !fullScreenActive) {
-    fullScreenActive = bumpScroll = true;
-
-    // Un-minimize the window if required
-    if (GetWindowLong(getHandle(), GWL_STYLE) & WS_MINIMIZE)
-      ShowWindow(getHandle(), SW_RESTORE);
-
-    // Save the non-fullscreen window position
-    RECT wrect;
-    GetWindowRect(getHandle(), &wrect);
-    fullScreenOldRect = Rect(wrect.left, wrect.top, wrect.right, wrect.bottom);
-
-    // Find the size of the display the window is on
-    MonitorInfo mi(getHandle());
-
-    // Set the window full-screen
-    DWORD flags = GetWindowLong(getHandle(), GWL_STYLE);
-    fullScreenOldFlags = flags;
-    flags = flags & ~(WS_CAPTION | WS_THICKFRAME | WS_MAXIMIZE | WS_MINIMIZE);
-    vlog.debug("flags=%x", flags);
-
-    if (toolbar) tb.hide();
-    SetWindowLong(getFrameHandle(), GWL_EXSTYLE, 0);
-    SetWindowLong(getHandle(), GWL_STYLE, flags);
-    SetWindowPos(getHandle(), HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top,
-      mi.rcMonitor.right-mi.rcMonitor.left,
-      mi.rcMonitor.bottom-mi.rcMonitor.top,
-      SWP_FRAMECHANGED);
-  } else if (!fs && fullScreenActive) {
-    fullScreenActive = bumpScroll = false;
-
-    // Set the window non-fullscreen
-    if (toolbar) tb.show();
-    SetWindowLong(getFrameHandle(), GWL_EXSTYLE, WS_EX_CLIENTEDGE);
-    SetWindowLong(getHandle(), GWL_STYLE, fullScreenOldFlags);
-    SetWindowPos(getHandle(), HWND_NOTOPMOST,
-      fullScreenOldRect.tl.x, fullScreenOldRect.tl.y,
-      fullScreenOldRect.width(), fullScreenOldRect.height(),
-      SWP_FRAMECHANGED);
-  }
-
-  // Adjust the viewport offset to cope with change in size between FS
-  // and previous window state.
-  setViewportOffset(scrolloffset);
-}
-
-
-bool CView::setViewportOffset(const Point& tl) {
-/* ***
-  Point np = Point(max(0, min(maxscrolloffset.x, tl.x)),
-    max(0, min(maxscrolloffset.y, tl.y)));
-    */
-  Point np = Point(max(0, min(tl.x, buffer->width()-client_size.width())),
-    max(0, min(tl.y, buffer->height()-client_size.height())));
-  Point delta = np.translate(scrolloffset.negate());
-  if (!np.equals(scrolloffset)) {
-    scrolloffset = np;
-    ScrollWindowEx(getFrameHandle(), -delta.x, -delta.y, 0, 0, 0, 0, SW_INVALIDATE);
-    UpdateWindow(getFrameHandle());
-    return true;
-  }
-  return false;
-}
-
-
-bool CView::processBumpScroll(const Point& pos)
-{
-  if (!bumpScroll) return false;
-  int bumpScrollPixels = 20;
-  bumpScrollDelta = Point();
-
-  if (pos.x == client_size.width()-1)
-    bumpScrollDelta.x = bumpScrollPixels;
-  else if (pos.x == 0)
-    bumpScrollDelta.x = -bumpScrollPixels;
-  if (pos.y == client_size.height()-1)
-    bumpScrollDelta.y = bumpScrollPixels;
-  else if (pos.y == 0)
-    bumpScrollDelta.y = -bumpScrollPixels;
-
-  if (bumpScrollDelta.x || bumpScrollDelta.y) {
-    if (bumpScrollTimer.isActive()) return true;
-    if (setViewportOffset(scrolloffset.translate(bumpScrollDelta))) {
-      bumpScrollTimer.start(25);
-      return true;
-    }
-  }
-
-  bumpScrollTimer.stop();
-  return false;
-}
-
-
-LRESULT
-CView::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
-  switch (msg) {
-
-    // -=- Process standard window messages
-
-  case WM_NOTIFY:
-    if (wParam = (ID_TOOLBAR)) tb.processWM_NOTIFY(wParam, lParam);
-    break;
-
-  case WM_DISPLAYCHANGE:
-    // Display has changed - use new pixel format
-    calculateFullColourPF();
-    break;
-
-    // -=- Window position
-
-    // Prevent the window from being resized to be too large if in normal mode.
-    // If maximized or fullscreen the allow oversized windows.
-
-  case WM_WINDOWPOSCHANGING:
-    {
-      WINDOWPOS* wpos = (WINDOWPOS*)lParam;
-      if (wpos->flags &  SWP_NOSIZE)
-        break;
-
-      // Work out how big the window should ideally be
-      DWORD frame_current_style = GetWindowLong(getFrameHandle(), GWL_STYLE);
-      DWORD frame_style = frame_current_style & ~(WS_VSCROLL | WS_HSCROLL);
-      DWORD frame_ex_style = GetWindowLong(getFrameHandle(), GWL_EXSTYLE);
-
-      RECT r;
-      SetRect(&r, 0, 0, buffer->width(), buffer->height());
-      AdjustWindowRectEx(&r, frame_style, FALSE, frame_ex_style);
-      Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
-      if (frame_current_style & WS_VSCROLL)
-        reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
-      if (frame_current_style & WS_HSCROLL)
-        reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
-      r.left = reqd_size.tl.x; r.right  = reqd_size.br.x;
-      r.top  = reqd_size.tl.y; r.bottom = reqd_size.br.y;
-      if (tb.isVisible()) r.bottom += tb.getHeight();
-      AdjustWindowRect(&r, GetWindowLong(getHandle(), GWL_STYLE), FALSE);
-      reqd_size = Rect(r.left, r.top, r.right, r.bottom);
-      RECT current;
-      GetWindowRect(getHandle(), &current);
-
-      // Ensure that the window isn't resized too large
-      // If the window is maximized or full-screen then any size is allowed
-      if (!(GetWindowLong(getHandle(), GWL_STYLE) & WS_MAXIMIZE) && !fullScreenActive) {
-        if (wpos->cx > reqd_size.width()) {
-          wpos->cx = reqd_size.width();
-          wpos->x = current.left;
-        }
-        if (wpos->cy > reqd_size.height()) {
-          wpos->cy = reqd_size.height();
-          wpos->y = current.top;
-        }
-      }
-
-    }
-    break;
-
-    // Resize child windows and update window size info we have cached.
-
-  case WM_SIZE:
-    {
-      Point old_offset = bufferToClient(Point(0, 0));
-
-      // Resize the child windows
-      RECT r;
-      GetClientRect(getHandle(), &r);
-      if (tb.isVisible()) {
-        MoveWindow(getFrameHandle(), 0, tb.getHeight(), r.right,
-          r.bottom - tb.getHeight(), TRUE);
-      } else {
-        MoveWindow(getFrameHandle(), 0, 0, r.right, r.bottom, TRUE);
-      }
-      tb.autoSize();
-      // Update the cached sizing information
-      GetWindowRect(getFrameHandle(), &r);
-      window_size = Rect(r.left, r.top, r.right, r.bottom);
-      GetClientRect(getFrameHandle(), &r);
-      client_size = Rect(r.left, r.top, r.right, r.bottom);
-
-      // Determine whether scrollbars are required
-      calculateScrollBars();
-         
-      // Redraw if required
-      if (!old_offset.equals(bufferToClient(Point(0, 0))))
-        InvalidateRect(getFrameHandle(), 0, TRUE);
-    }
-    break;
-
-    // -=- Bump-scrolling
-
-  case WM_TIMER:
-    switch (wParam) {
-    case TIMER_BUMPSCROLL:
-      if (!setViewportOffset(scrolloffset.translate(bumpScrollDelta)))
-        bumpScrollTimer.stop();
-      break;
-    case TIMER_POINTER_INTERVAL:
-    case TIMER_POINTER_3BUTTON:
-      try {
-        ptr.handleTimer(writer(), wParam);
-      } catch (rdr::Exception& e) {
-        close(e.str());
-      }
-      break;
-    }
-    break;
-
-    // -=- Track whether or not the window has focus
-
-  case WM_SETFOCUS:
-    has_focus = true;
-    // Re-register AltTab hotkey
-    setAltTabGrab(options.sendSysKeys);
-    break;
-  case WM_KILLFOCUS:
-    has_focus = false;
-    cursorOutsideBuffer();
-    // Unregister AltTab hotkey
-    setAltTabGrab(false);
-    // Restore the remote keys to consistent states
-    try {
-      kbd.releaseAllKeys(writer());
-    } catch (rdr::Exception& e) {
-      close(e.str());
-    }
-    break;
-
-    // -=- Handle the extra window menu items
-
-    // Process the items added to the system menu
-  case WM_SYSCOMMAND:
-
-    // - First check whether it's one of our messages
-    switch (wParam) {
-    case IDM_FULLSCREEN:
-      options.fullScreen = !options.fullScreen;
-      setFullscreen(options.fullScreen);
-      return 0;
-    case IDM_SHOW_TOOLBAR:
-      toolbar = !toolbar;
-      CheckMenuItem(GetSystemMenu(getHandle(), FALSE), IDM_SHOW_TOOLBAR,
-        (toolbar ? MF_CHECKED : MF_UNCHECKED) | MF_BYCOMMAND);
-      if (toolbar) tb.show();
-      else tb.hide();
-      return 0;
-    case IDM_CTRL_KEY:
-      writeKeyEvent(VK_CONTROL, 0, !kbd.keyPressed(VK_CONTROL));
-      return 0;
-    case IDM_ALT_KEY:
-      writeKeyEvent(VK_MENU, 0, !kbd.keyPressed(VK_MENU));
-      return 0;
-    case IDM_SEND_MENU_KEY:
-      writeKeyEvent(options.menuKey, 0, true);
-      writeKeyEvent(options.menuKey, 0, false);
-      return 0;
-    case IDM_SEND_CAD:
-      writeKeyEvent(VK_CONTROL, 0, true);
-      writeKeyEvent(VK_MENU, 0, true);
-      writeKeyEvent(VK_DELETE, 0, true);
-      writeKeyEvent(VK_DELETE, 0, false);
-      writeKeyEvent(VK_MENU, 0, false);
-      writeKeyEvent(VK_CONTROL, 0, false);
-      return 0;
-    case IDM_SEND_CTLESC:
-      writeKeyEvent(VK_CONTROL, 0, true);
-      writeKeyEvent(VK_ESCAPE, 0, true);
-      writeKeyEvent(VK_CONTROL, 0, false);
-      writeKeyEvent(VK_ESCAPE, 0, false);
-      return 0;
-    case IDM_REQUEST_REFRESH:
-      try {
-        writer()->writeFramebufferUpdateRequest(Rect(0,0,cp.width,cp.height), false);
-        requestUpdate = false;
-      } catch (rdr::Exception& e) {
-        close(e.str());
-      }
-      return 0;
-    case IDM_NEWCONN:
-      manager->addClient(0);
-      return 0;
-    case IDM_OPTIONS:
-      // Update the monitor device name in the CViewOptions instance
-      {
-        MonitorInfo mi(getHandle());
-        options.setMonitor(mi.szDevice);
-        optionsDialog.showDialog(this);
-        return 0;
-      }
-    case IDM_INFO:
-      infoDialog.showDialog(this);
-      return 0;
-    case IDM_ABOUT:
-      AboutDialog::instance.showDialog();
-      return 0;
-    case IDM_FILE_TRANSFER:
-      m_fileTransfer.show(getHandle());
-      return 0;
-    case IDM_CONN_SAVE_AS:
-      return 0;
-    case ID_CLOSE:
-      PostQuitMessage(0);
-      return 0;
-    };
-
-    // - Not one of our messages, so process it as a system message
-    switch (wParam & 0xfff0) {
-
-      // When restored, ensure that full-screen mode is re-enabled if required.
-    case SC_RESTORE:
-      rfb::win32::SafeDefWindowProc(getHandle(), msg, wParam, lParam);
-      setFullscreen(options.fullScreen);
-      return 0;
-
-      // If we are maximized or minimized then that cancels full-screen mode.
-    case SC_MINIMIZE:
-    case SC_MAXIMIZE:
-      setFullscreen(false);
-      break;
-
-      // If the system menu is shown then make sure it's up to date
-    case SC_KEYMENU:
-    case SC_MOUSEMENU:
-      updateF8Menu(false);
-      break;
-
-    };
-    break;
-
-    // Treat all menu commands as system menu commands
-  case WM_COMMAND:
-    SendMessage(getHandle(), WM_SYSCOMMAND, wParam, lParam);
-    return 0;
-
-  case WM_MENUCHAR:
-    vlog.debug("menuchar");
-    break;
-
-    // -=- Handle keyboard input
-
-  case WM_HOTKEY:
-    if (wParam == HOTKEY_ALTTAB) {
-      writeKeyEvent(VK_TAB, 0, true);
-      writeKeyEvent(VK_TAB, 0, false);
-      return 0;
-    }
-    break;
-
-  case WM_SYSKEYDOWN:
-    // Translate Alt-Space and Alt-F4 to WM_SYSCHAR and WM_CLOSE,
-    // since we are not using TranslateMessage(). 
-    if (!options.sendSysKeys) {
-      switch (wParam) {
-      case VK_SPACE:
-       writeKeyEvent(VK_MENU, 0, false);
-       SendMessage(getHandle(), WM_SYSCHAR, wParam, lParam);
-       return 0; 
-      case VK_F4:
-       SendMessage(getHandle(), WM_CLOSE, wParam, lParam);
-       return 0; 
-      }
-    }
-
-  case WM_SYSKEYUP:
-    // When we have registered for AltTab as a hotkey, SYSKEYUPs for
-    // Tabs are sent (but no SYSKEYDOWNs). AltTab is handled by
-    // WM_HOTKEY, though.
-    if (wParam == VK_TAB) return 0; 
-
-  case WM_KEYUP:
-  case WM_KEYDOWN:
-    // Hook the MenuKey to pop-up the window menu
-    if (options.menuKey && (wParam == options.menuKey)) {
-
-      bool ctrlDown = (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0;
-      bool altDown = (GetAsyncKeyState(VK_MENU) & 0x8000) != 0;
-      bool shiftDown = (GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0;
-      if (!(ctrlDown || altDown || shiftDown)) {
-
-        // If MenuKey is being released then pop-up the menu
-        if ((msg == WM_KEYDOWN)) {
-          // Make sure it's up to date
-          updateF8Menu(true);
-
-          // Show it under the pointer
-          POINT pt;
-          GetCursorPos(&pt);
-          cursorInBuffer = false;
-          TrackPopupMenu(GetSystemMenu(getHandle(), FALSE),
-            TPM_CENTERALIGN | TPM_VCENTERALIGN, pt.x, pt.y, 0, getHandle(), 0);
-        }
-
-       // Ignore the MenuKey keypress for both press & release events
-       return 0;
-      }
-    }
-
-    writeKeyEvent(wParam, lParam, (msg == WM_KEYDOWN) || (msg == WM_SYSKEYDOWN));
-    return 0;
-
-    // -=- Handle the window closing
-
-  case WM_CLOSE:
-    vlog.debug("WM_CLOSE %x", getHandle());
-    if (quit_on_destroy) {
-      vlog.debug("posting WM_QUIT");
-      PostQuitMessage(0);
-    } else {
-      vlog.debug("not posting WM_QUIT");
-    }
-    break;
-
-    // -=- Process incoming socket data
-
-  case WM_USER:
-    readyToRead = true;
-    break;
-
-  }
-
-  return rfb::win32::SafeDefWindowProc(getHandle(), msg, wParam, lParam);
-}
-
-LRESULT CView::processFrameMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
-  switch (msg) {
-
-    // -=- Palette management
-
-  case WM_PALETTECHANGED:
-    vlog.debug("WM_PALETTECHANGED");
-    if ((HWND)wParam == getFrameHandle()) {
-      vlog.debug("ignoring");
-      break;
-    }
-  case WM_QUERYNEWPALETTE:
-    vlog.debug("re-selecting palette");
-    {
-      WindowDC wdc(getFrameHandle());
-      PaletteSelector pSel(wdc, windowPalette.getHandle());
-      if (pSel.isRedrawRequired()) {
-        InvalidateRect(getFrameHandle(), 0, FALSE);
-        UpdateWindow(getFrameHandle());
-      }
-    }
-    return TRUE;
-
-    // Paint the remote frame buffer
-
-  case WM_PAINT:
-    {
-      PAINTSTRUCT ps;
-      HDC paintDC = BeginPaint(getFrameHandle(), &ps);
-      if (!paintDC)
-        throw SystemException("unable to BeginPaint", GetLastError());
-      Rect pr = Rect(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
-
-      if (!pr.is_empty()) {
-
-        // Draw using the correct palette
-        PaletteSelector pSel(paintDC, windowPalette.getHandle());
-
-        if (buffer->bitmap) {
-          // Update the bitmap's palette
-          if (palette_changed) {
-            palette_changed = false;
-            buffer->refreshPalette();
-          }
-
-          // Get device context
-          BitmapDC bitmapDC(paintDC, buffer->bitmap);
-
-          // Blit the border if required
-          Rect bufpos = bufferToClient(buffer->getRect());
-          if (!pr.enclosed_by(bufpos)) {
-            vlog.debug("draw border");
-            HBRUSH black = (HBRUSH) GetStockObject(BLACK_BRUSH);
-            RECT r;
-            SetRect(&r, 0, 0, bufpos.tl.x, client_size.height()); FillRect(paintDC, &r, black);
-            SetRect(&r, bufpos.tl.x, 0, bufpos.br.x, bufpos.tl.y); FillRect(paintDC, &r, black);
-            SetRect(&r, bufpos.br.x, 0, client_size.width(), client_size.height()); FillRect(paintDC, &r, black);
-            SetRect(&r, bufpos.tl.x, bufpos.br.y, bufpos.br.x, client_size.height()); FillRect(paintDC, &r, black);
-          }
-
-          // Do the blit
-          Point buf_pos = clientToBuffer(pr.tl);
-          if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
-            bitmapDC, buf_pos.x, buf_pos.y, SRCCOPY))
-            throw SystemException("unable to BitBlt to window", GetLastError());
-
-        } else {
-          // Blit a load of black
-          if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
-            0, 0, 0, BLACKNESS))
-            throw SystemException("unable to BitBlt to blank window", GetLastError());
-        }
-      }
-
-      EndPaint(getFrameHandle(), &ps);
-
-      // - Request the next update from the server, if required
-      requestNewUpdate();
-    }
-    return 0;
-
-    // Process the frame scroll messages
-
-  case WM_VSCROLL:
-  case WM_HSCROLL: 
-    {
-      Point delta;
-      int newpos = (msg == WM_VSCROLL) ? scrolloffset.y : scrolloffset.x;
-
-      switch (LOWORD(wParam)) {
-      case SB_PAGEUP: newpos -= 50; break;
-      case SB_PAGEDOWN: newpos += 50; break;
-      case SB_LINEUP: newpos -= 5; break;
-      case SB_LINEDOWN: newpos += 5; break;
-      case SB_THUMBTRACK:
-      case SB_THUMBPOSITION: newpos = HIWORD(wParam); break;
-      default: vlog.info("received unknown scroll message");
-      };
-
-      if (msg == WM_HSCROLL)
-        setViewportOffset(Point(newpos, scrolloffset.y));
-      else
-        setViewportOffset(Point(scrolloffset.x, newpos));
-  
-      SCROLLINFO si;
-      si.cbSize = sizeof(si); 
-      si.fMask  = SIF_POS; 
-      si.nPos   = newpos; 
-      SetScrollInfo(getFrameHandle(), (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ, &si, TRUE); 
-    }
-    break;
-
-    // -=- Cursor shape/visibility handling
-
-  case WM_SETCURSOR:
-    if (LOWORD(lParam) != HTCLIENT)
-      break;
-    SetCursor(cursorInBuffer ? dotCursor : arrowCursor);
-    return TRUE;
-
-  case WM_MOUSELEAVE:
-    trackingMouseLeave = false;
-    cursorOutsideBuffer();
-    return 0;
-
-    // -=- Mouse input handling
-
-  case WM_MOUSEMOVE:
-  case WM_LBUTTONUP:
-  case WM_MBUTTONUP:
-  case WM_RBUTTONUP:
-  case WM_LBUTTONDOWN:
-  case WM_MBUTTONDOWN:
-  case WM_RBUTTONDOWN:
-  case WM_MOUSEWHEEL:
-    if (has_focus)
-    {
-      if (!trackingMouseLeave) {
-        TRACKMOUSEEVENT tme;
-        tme.cbSize = sizeof(TRACKMOUSEEVENT);
-        tme.dwFlags = TME_LEAVE;
-        tme.hwndTrack = getFrameHandle();
-        _TrackMouseEvent(&tme);
-        trackingMouseLeave = true;
-      }
-      int mask = 0;
-      if (LOWORD(wParam) & MK_LBUTTON) mask |= 1;
-      if (LOWORD(wParam) & MK_MBUTTON) mask |= 2;
-      if (LOWORD(wParam) & MK_RBUTTON) mask |= 4;
-
-      if (msg == WM_MOUSEWHEEL) {
-        int delta = (short)HIWORD(wParam);
-        int repeats = (abs(delta)+119) / 120;
-        int wheelMask = (delta > 0) ? 8 : 16;
-        vlog.debug("repeats %d, mask %d\n",repeats,wheelMask);
-        for (int i=0; i<repeats; i++) {
-          writePointerEvent(oldpos.x, oldpos.y, mask | wheelMask);
-          writePointerEvent(oldpos.x, oldpos.y, mask);
-        }
-      } else {
-        Point clientPos = Point(LOWORD(lParam), HIWORD(lParam));
-        Point p = clientToBuffer(clientPos);
-
-        // If the mouse is not within the server buffer area, do nothing
-        cursorInBuffer = buffer->getRect().contains(p);
-        if (!cursorInBuffer) {
-          cursorOutsideBuffer();
-          break;
-        }
-
-        // If we're locally rendering the cursor then redraw it
-        if (cursorAvailable) {
-          // - Render the cursor!
-          if (!p.equals(cursorPos)) {
-            hideLocalCursor();
-            cursorPos = p;
-            showLocalCursor();
-            if (cursorVisible)
-              hideSystemCursor();
-          }
-        }
-
-        // If we are doing bump-scrolling then try that first...
-        if (processBumpScroll(clientPos))
-          break;
-
-        // Send a pointer event to the server
-        writePointerEvent(p.x, p.y, mask);
-        oldpos = p;
-      }
-    } else {
-      cursorOutsideBuffer();
-    }
-    break;
-  }
-
-  return rfb::win32::SafeDefWindowProc(getFrameHandle(), msg, wParam, lParam);
-}
-
-void CView::blockCallback() {
-  // - An InStream has blocked on I/O while processing an RFB message
-  //   We re-enable socket event notifications, so we'll know when more
-  //   data is available, then we sit and dispatch window events until
-  //   the notification arrives.
-  readyToRead = false;
-  WSAAsyncSelect(sock->getFd(), getHandle(), WM_USER, FD_READ | FD_CLOSE);
-  MSG msg;
-  while (true) {
-    if (readyToRead) {
-      // - Network event notification.  Return control to I/O routine.
-      WSAAsyncSelect(sock->getFd(), getHandle(), WM_USER, 0);
-      return;
-    }
-
-    DWORD result = GetMessage(&msg, NULL, 0, 0);
-    if (result == 0) {
-      vlog.debug("WM_QUIT");
-      throw QuitMessage(msg.wParam);
-    } else if (result < 0) {
-      throw rdr::SystemException("GetMessage error", GetLastError());
-    }
-
-    // IMPORTANT: We mustn't call TranslateMessage() here, because instead we
-    // call ToAscii() in CKeyboard::keyEvent().  ToAscii() stores dead key
-    // state from one call to the next, which would be messed up by calls to
-    // TranslateMessage() (actually it looks like TranslateMessage() calls
-    // ToAscii() internally).
-    DispatchMessage(&msg);
-  }
-}
-
-
-void
-CView::hideLocalCursor() {
-  // - Blit the cursor backing store over the cursor
-  // *** ALWAYS call this BEFORE changing buffer PF!!!
-  if (cursorVisible) {
-    cursorVisible = false;
-    buffer->imageRect(cursorBackingRect, cursorBacking.data);
-    invalidateBufferRect(cursorBackingRect);
-  }
-}
-
-void
-CView::showLocalCursor() {
-  if (cursorAvailable && !cursorVisible && cursorInBuffer) {
-    if (!cp.pf().equal(cursor.getPF()) ||
-      cursor.getRect().is_empty()) {
-      vlog.info("attempting to render invalid local cursor");
-      cursorAvailable = false;
-      showSystemCursor();
-      return;
-    }
-    cursorVisible = true;
-    
-    cursorBackingRect = cursor.getRect().translate(cursorPos).translate(cursor.hotspot.negate());
-    cursorBackingRect = cursorBackingRect.intersect(buffer->getRect());
-    buffer->getImage(cursorBacking.data, cursorBackingRect);
-
-    renderLocalCursor();
-
-    invalidateBufferRect(cursorBackingRect);
-  }
-}
-
-void CView::cursorOutsideBuffer()
-{
-  cursorInBuffer = false;
-  hideLocalCursor();
-  showSystemCursor();
-}
-
-void
-CView::renderLocalCursor()
-{
-  Rect r = cursor.getRect();
-  r = r.translate(cursorPos).translate(cursor.hotspot.negate());
-  buffer->maskRect(r, cursor.data, cursor.mask.buf);
-}
-
-void
-CView::hideSystemCursor() {
-  if (systemCursorVisible) {
-    vlog.debug("hide system cursor");
-    systemCursorVisible = false;
-    ShowCursor(FALSE);
-  }
-}
-
-void
-CView::showSystemCursor() {
-  if (!systemCursorVisible) {
-    vlog.debug("show system cursor");
-    systemCursorVisible = true;
-    ShowCursor(TRUE);
-  }
-}
-
-void
-CView::setAltTabGrab(bool grab) {
-  BOOL hotKeyResult;
-  static bool grabstate = false;
-
-  // Do not call RegisterHotKey/UnregisterHotKey if not necessary
-  if (grabstate == grab)
-    return;
-
-  grabstate = grab;
-    
-  // Only works for NT/2k/XP
-  if (grab) {
-    hotKeyResult = RegisterHotKey(hwnd, HOTKEY_ALTTAB, MOD_ALT, VK_TAB);
-    if (!hotKeyResult)
-      vlog.debug("RegisterHotkey failed with error %d", GetLastError());
-  } else {
-    hotKeyResult = UnregisterHotKey(hwnd, HOTKEY_ALTTAB);
-  }
-}
-
-bool
-CView::invalidateBufferRect(const Rect& crect) {
-  Rect rect = bufferToClient(crect);
-  if (rect.intersect(client_size).is_empty()) return false;
-  RECT invalid = {rect.tl.x, rect.tl.y, rect.br.x, rect.br.y};
-  InvalidateRect(getFrameHandle(), &invalid, FALSE);
-  return true;
-}
-
-
-void
-CView::notifyClipboardChanged(const char* text, int len) {
-  if (!options.clientCutText) return;
-  if (state() != RFBSTATE_NORMAL) return;
-  try {
-    writer()->writeClientCutText(text, len);
-  } catch (rdr::Exception& e) {
-    close(e.str());
-  }
-}
-
-
-CSecurity* CView::getCSecurity(int secType)
-{
-  switch (secType) {
-  case secTypeNone:
-    return new CSecurityNone();
-  case secTypeVncAuth:
-    return new CSecurityVncAuth(this);
-  default:
-    throw Exception("Unsupported secType?");
-  }
-}
-
-
-void
-CView::setColourMapEntries(int first, int count, U16* rgbs) {
-  vlog.debug("setColourMapEntries: first=%d, count=%d", first, count);
-  int i;
-  for (i=0;i<count;i++) {
-    buffer->setColour(i+first, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
-  }
-  // *** change to 0, 256?
-  refreshWindowPalette(first, count);
-  palette_changed = true;
-  InvalidateRect(getHandle(), 0, FALSE);
-}
-
-void
-CView::bell() {
-  if (options.acceptBell)
-    MessageBeep(-1);
-}
-
-
-void
-CView::setDesktopSize(int w, int h) {
-  vlog.debug("setDesktopSize %dx%d", w, h);
-
-  // If the locally-rendered cursor is visible then remove it
-  hideLocalCursor();
-
-  // Resize the backing buffer
-  buffer->setSize(w, h);
-
-  // If the window is not maximised or full-screen then resize it
-  if (!(GetWindowLong(getHandle(), GWL_STYLE) & WS_MAXIMIZE) && !fullScreenActive) {
-    // Resize the window to the required size
-    RECT r = {0, 0, w, h};
-    AdjustWindowRectEx(&r, GetWindowLong(getFrameHandle(), GWL_STYLE), FALSE,
-      GetWindowLong(getFrameHandle(), GWL_EXSTYLE));
-    if (tb.isVisible()) r.bottom += tb.getHeight();
-    AdjustWindowRect(&r, GetWindowLong(getHandle(), GWL_STYLE), FALSE);
-    SetWindowPos(getHandle(), 0, 0, 0, r.right-r.left, r.bottom-r.top,
-      SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
-
-    // Move the window to the desired monitor
-    if (options.monitor.buf)
-      moveToMonitor(getHandle(), options.monitor.buf);
-
-    // Clip to the system work area
-    centerWindow(getHandle(), 0, true);
-  } else {
-    // Ensure the screen contents are consistent
-    InvalidateRect(getFrameHandle(), 0, FALSE);
-  }
-
-  // Tell the underlying CConnection
-  CConnection::setDesktopSize(w, h);
-
-  // Enable/disable scrollbars as appropriate
-  calculateScrollBars();
-}
-
-void
-CView::setCursor(const Point& hotspot, const Point& size, void* data, void* mask) {
-  if (!options.useLocalCursor) return;
-  hideLocalCursor();
-
-  cursor.hotspot = hotspot;
-
-  cursor.setSize(size.x, size.y);
-  cursor.setPF(cp.pf());
-  cursor.imageRect(cursor.getRect(), data);
-  memcpy(cursor.mask.buf, mask, cursor.maskLen());
-  cursor.crop();
-
-  cursorBacking.setSize(size.x, size.y);
-  cursorBacking.setPF(cp.pf());
-
-  cursorAvailable = true;
-
-  showLocalCursor();
-}
-
-PixelFormat
-CView::getNativePF() const {
-  vlog.debug("getNativePF()");
-  return WindowDC(getHandle()).getPF();
-}
-
-void
-CView::setVisible(bool visible) {
-  ShowWindow(getHandle(), visible ? SW_SHOW : SW_HIDE);
-  if (visible) {
-    // When the window becomes visible, make it active
-    SetForegroundWindow(getHandle());
-    SetActiveWindow(getHandle());
-    // If the window should be full-screen, then do so
-    setFullscreen(options.fullScreen);
-  } else {
-    // Disable full-screen mode
-    setFullscreen(false);
-  }
-}
-
-void
-CView::close(const char* reason) {
-  setVisible(false);
-  if (reason) {
-    vlog.info("closing - %s", reason);
-    MsgBox(NULL, TStr(reason), MB_ICONINFORMATION | MB_OK);
-  }
-  SendMessage(getHandle(), WM_CLOSE, 0, 0);
-}
-
-
-void
-CView::framebufferUpdateEnd() {
-  if (debugDelay != 0) {
-    vlog.debug("debug delay %d",(int)debugDelay);
-    UpdateWindow(getHandle());
-    Sleep(debugDelay);
-    std::list<rfb::Rect>::iterator i;
-    for (i = debugRects.begin(); i != debugRects.end(); i++) {
-      invertRect(*i);
-    }
-    debugRects.clear();
-  }
-  if (options.autoSelect)
-    autoSelectFormatAndEncoding();
-
-  // Always request the next update
-  requestUpdate = true;
-
-  // Check that at least part of the window has changed
-  if (!GetUpdateRect(getHandle(), 0, FALSE)) {
-    if (!(GetWindowLong(getHandle(), GWL_STYLE) & WS_MINIMIZE))
-      requestNewUpdate();
-  }
-
-  showLocalCursor();
-}
-
-
-// Note: The method below is duplicated in vncviewer_unix/CConn.cxx!
-
-// autoSelectFormatAndEncoding() chooses the format and encoding appropriate
-// to the connection speed:
-//
-//   Above 16Mbps (timing for at least a second), switch to hextile
-//   Otherwise, switch to ZRLE
-//
-//   Above 256Kbps, use full colour mode
-//
-void 
-CView::autoSelectFormatAndEncoding() {
-  int kbitsPerSecond = sock->inStream().kbitsPerSecond();
-  unsigned int newEncoding = options.preferredEncoding;
-  bool newFullColour = options.fullColour;
-  unsigned int timeWaited = sock->inStream().timeWaited();
-
-  // Select best encoding
-  if (kbitsPerSecond > 16000 && timeWaited >= 10000) {
-    newEncoding = encodingHextile;
-  } else {
-    newEncoding = encodingZRLE;
-  }
-
-  if (newEncoding != options.preferredEncoding) {
-    vlog.info("Throughput %d kbit/s - changing to %s encoding",
-              kbitsPerSecond, encodingName(newEncoding));
-    options.preferredEncoding = newEncoding;
-    encodingChange = true;
-  }
-
-  if (kbitsPerSecond == 0) {
-    return;
-  }
-
-  if (cp.beforeVersion(3, 8)) {
-    // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
-    // cursors "asynchronously". If this happens in the middle of a
-    // pixel format change, the server will encode the cursor with
-    // the old format, but the client will try to decode it
-    // according to the new format. This will lead to a
-    // crash. Therefore, we do not allow automatic format change for
-    // old servers.
-    return;
-  }
-  
-  // Select best color level
-  newFullColour = (kbitsPerSecond > 256);
-  if (newFullColour != options.fullColour) {
-    vlog.info("Throughput %d kbit/s - full color is now %s", 
-             kbitsPerSecond,
-             newFullColour ? "enabled" : "disabled");
-    options.fullColour = newFullColour;
-    formatChange = true;
-  } 
-}
-
-void
-CView::requestNewUpdate() {
-  if (!requestUpdate) return;
-
-  if (formatChange) {
-    // Hide the rendered cursor, if any, to prevent
-    // the backing buffer being used in the wrong format
-    hideLocalCursor();
-
-    // Select the required pixel format
-    if (options.fullColour) {
-      buffer->setPF(fullColourPF);
-    } else {
-      switch (options.lowColourLevel) {
-      case 0:
-        buffer->setPF(PixelFormat(8,3,0,1,1,1,1,2,1,0));
-        break;
-      case 1:
-        buffer->setPF(PixelFormat(8,6,0,1,3,3,3,4,2,0));
-        break;
-      case 2:
-        buffer->setPF(PixelFormat(8,8,0,0,0,0,0,0,0,0));
-        break;
-      }
-    }
-
-    // Print the current pixel format
-    char str[256];
-    buffer->getPF().print(str, 256);
-    vlog.info("Using pixel format %s",str);
-
-    // Save the connection pixel format and tell server to use it
-    cp.setPF(buffer->getPF());
-    writer()->writeSetPixelFormat(cp.pf());
-
-    // Correct the local window's palette
-    if (!getNativePF().trueColour)
-      refreshWindowPalette(0, 1 << cp.pf().depth);
-  }
-
-  if (encodingChange) {
-    vlog.info("Using %s encoding",encodingName(options.preferredEncoding));
-    writer()->writeSetEncodings(options.preferredEncoding, true);
-  }
-
-  writer()->writeFramebufferUpdateRequest(Rect(0, 0, cp.width, cp.height),
-                                          !formatChange);
-
-  encodingChange = formatChange = requestUpdate = false;
-}
-
-
-void
-CView::writeKeyEvent(rdr::U8 vkey, rdr::U32 flags, bool down) {
-  if (!options.sendKeyEvents) return;
-  try {
-    kbd.keyEvent(writer(), vkey, flags, down);
-  } catch (rdr::Exception& e) {
-    close(e.str());
-  }
-}
-
-void
-CView::writePointerEvent(int x, int y, int buttonMask) {
-  if (!options.sendPtrEvents) return;
-  try {
-    ptr.pointerEvent(writer(), x, y, buttonMask);
-  } catch (rdr::Exception& e) {
-    close(e.str());
-  }
-}
-
-
-void
-CView::refreshWindowPalette(int start, int count) {
-  vlog.debug("refreshWindowPalette(%d, %d)", start, count);
-
-  Colour colours[256];
-  if (count > 256) {
-    vlog.debug("%d palette entries", count);
-    throw rdr::Exception("too many palette entries");
-  }
-
-  // Copy the palette from the DIBSectionBuffer
-  ColourMap* cm = buffer->getColourMap();
-  if (!cm) return;
-  for (int i=0; i<count; i++) {
-    int r, g, b;
-    cm->lookup(i, &r, &g, &b);
-    colours[i].r = r;
-    colours[i].g = g;
-    colours[i].b = b;
-  }
-
-  // Set the window palette
-  windowPalette.setEntries(start, count, colours);
-
-  // Cause the window to be redrawn
-  InvalidateRect(getHandle(), 0, 0);
-}
-
-
-void CView::calculateScrollBars() {
-  // Calculate the required size of window
-  DWORD current_style = GetWindowLong(getFrameHandle(), GWL_STYLE);
-  DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
-  DWORD ex_style = GetWindowLong(getFrameHandle(), GWL_EXSTYLE);
-  DWORD old_style;
-  RECT r;
-  SetRect(&r, 0, 0, buffer->width(), buffer->height());
-  AdjustWindowRectEx(&r, style, FALSE, ex_style);
-  Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
-
-  if (!bumpScroll) {
-    // We only enable scrollbars if bump-scrolling is not active.
-    // Effectively, this means if full-screen is not active,
-    // but I think it's better to make these things explicit.
-    // Work out whether scroll bars are required
-    do {
-      old_style = style;
-
-      if (!(style & WS_HSCROLL) && (reqd_size.width() > window_size.width())) {
-        style |= WS_HSCROLL;
-        reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
-      }
-      if (!(style & WS_VSCROLL) && (reqd_size.height() > window_size.height())) {
-        style |= WS_VSCROLL;
-        reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
-      }
-    } while (style != old_style);
-  }
-  
-  // Tell Windows to update the window style & cached settings
-  if (style != current_style) {
-    SetWindowLong(getFrameHandle(), GWL_STYLE, style);
-    SetWindowPos(getFrameHandle(), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
-  }
-
-  // Update the scroll settings
-  SCROLLINFO si;
-  if (style & WS_VSCROLL) {
-    si.cbSize = sizeof(si);
-    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
-    si.nMin   = 0;
-    si.nMax   = buffer->height();
-    si.nPage  = buffer->height() - (reqd_size.height() - window_size.height());
-    maxscrolloffset.y = max(0, si.nMax-si.nPage);
-    scrolloffset.y = min(maxscrolloffset.y, scrolloffset.y);
-    si.nPos   = scrolloffset.y;
-    SetScrollInfo(getFrameHandle(), SB_VERT, &si, TRUE);
-  }
-  if (style & WS_HSCROLL) {
-    si.cbSize = sizeof(si);
-    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
-    si.nMin   = 0;
-    si.nMax   = buffer->width();
-    si.nPage  = buffer->width() - (reqd_size.width() - window_size.width());
-    maxscrolloffset.x = max(0, si.nMax-si.nPage);
-    scrolloffset.x = min(maxscrolloffset.x, scrolloffset.x);
-    si.nPos   = scrolloffset.x;
-    SetScrollInfo(getFrameHandle(), SB_HORZ, &si, TRUE);
-  }
-
-  // Update the cached client size
-  GetClientRect(getFrameHandle(), &r);
-  client_size = Rect(r.left, r.top, r.right, r.bottom);
-}
-
-
-void
-CView::calculateFullColourPF() {
-  // If the server is palette based then use palette locally
-  // Also, don't bother doing bgr222
-  if (!serverDefaultPF.trueColour || (serverDefaultPF.depth < 6)) {
-    fullColourPF = serverDefaultPF;
-    options.fullColour = true;
-  } else {
-    // If server is trueColour, use lowest depth PF
-    PixelFormat native = getNativePF();
-    if ((serverDefaultPF.bpp < native.bpp) ||
-      ((serverDefaultPF.bpp == native.bpp) &&
-      (serverDefaultPF.depth < native.depth)))
-      fullColourPF = serverDefaultPF;
-    else
-      fullColourPF = getNativePF();
-  }
-  formatChange = true;
-}
-
-
-void
-CView::updateF8Menu(bool hideSystemCommands) {
-  HMENU menu = GetSystemMenu(getHandle(), FALSE);
-
-  if (hideSystemCommands) {  
-    // Gray out menu items that might cause a World Of Pain
-    HMENU menu = GetSystemMenu(getHandle(), FALSE);
-    EnableMenuItem(menu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
-    EnableMenuItem(menu, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
-    EnableMenuItem(menu, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED);
-    EnableMenuItem(menu, SC_MINIMIZE, MF_BYCOMMAND | MF_ENABLED);
-    EnableMenuItem(menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_ENABLED);
-  }
-
-  // Update the modifier key menu items
-  UINT ctrlCheckFlags = kbd.keyPressed(VK_CONTROL) ? MF_CHECKED : MF_UNCHECKED;
-  UINT altCheckFlags = kbd.keyPressed(VK_MENU) ? MF_CHECKED : MF_UNCHECKED;
-  CheckMenuItem(menu, IDM_CTRL_KEY, MF_BYCOMMAND | ctrlCheckFlags);
-  CheckMenuItem(menu, IDM_ALT_KEY, MF_BYCOMMAND | altCheckFlags);
-
-  // Ensure that the Send <MenuKey> menu item has the correct text
-  if (options.menuKey) {
-    TCharArray menuKeyStr(options.menuKeyName());
-    TCharArray tmp(_tcslen(menuKeyStr.buf) + 6);
-    _stprintf(tmp.buf, _T("Send %s"), menuKeyStr.buf);
-    if (!ModifyMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf))
-      InsertMenu(menu, IDM_SEND_CAD, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf);
-  } else {
-    RemoveMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND);
-  }
-}
-
-
-void
-CView::setName(const char* name) {
-  vlog.debug("setName %s", name);
-  ::SetWindowText(getHandle(), TStr(name));
-  CConnection::setName(name);
-}
-
-
-void CView::serverInit() {
-  CConnection::serverInit();
-
-  // If using AutoSelect with old servers, start in FullColor
-  // mode. See comment in autoSelectFormatAndEncoding. 
-  if (cp.beforeVersion(3, 8) && options.autoSelect) {
-    options.fullColour = true;
-  }
-
-  // Save the server's current format
-  serverDefaultPF = cp.pf();
-
-  // Calculate the full-colour format to use
-  calculateFullColourPF();
-
-  // Request the initial update
-  vlog.info("requesting initial update");
-  formatChange = encodingChange = requestUpdate = true;
-  requestNewUpdate();
-
-  // Show the window
-  setVisible(true);
-}
-
-void
-CView::serverCutText(const char* str, int len) {
-  if (!options.serverCutText) return;
-  CharArray t(len+1);
-  memcpy(t.buf, str, len);
-  t.buf[len] = 0;
-  clipboard.setClipText(t.buf);
-}
-
-
-void CView::beginRect(const Rect& r, unsigned int encoding) {
-  sock->inStream().startTiming();
-}
-
-void CView::endRect(const Rect& r, unsigned int encoding) {
-  sock->inStream().stopTiming();
-  lastUsedEncoding_ = encoding;
-  if (debugDelay != 0) {
-    invertRect(r);
-    debugRects.push_back(r);
-  }
-}
-
-void CView::fillRect(const Rect& r, Pixel pix) {
-  if (cursorBackingRect.overlaps(r)) hideLocalCursor();
-  buffer->fillRect(r, pix);
-  invalidateBufferRect(r);
-}
-void CView::imageRect(const Rect& r, void* pixels) {
-  if (cursorBackingRect.overlaps(r)) hideLocalCursor();
-  buffer->imageRect(r, pixels);
-  invalidateBufferRect(r);
-}
-void CView::copyRect(const Rect& r, int srcX, int srcY) {
-  if (cursorBackingRect.overlaps(r) ||
-      cursorBackingRect.overlaps(Rect(srcX, srcY, srcX+r.width(), srcY+r.height())))
-    hideLocalCursor();
-  buffer->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
-  invalidateBufferRect(r);
-}
-
-void CView::invertRect(const Rect& r) {
-  int stride;
-  rdr::U8* p = buffer->getPixelsRW(r, &stride);
-  for (int y = 0; y < r.height(); y++) {
-    for (int x = 0; x < r.width(); x++) {
-      switch (buffer->getPF().bpp) {
-      case 8:  ((rdr::U8* )p)[x+y*stride] ^= 0xff;       break;
-      case 16: ((rdr::U16*)p)[x+y*stride] ^= 0xffff;     break;
-      case 32: ((rdr::U32*)p)[x+y*stride] ^= 0xffffffff; break;
-      }
-    }
-  }
-  invalidateBufferRect(r);
-}
-
-bool CView::getUserPasswd(char** user, char** password) {
-  if (!user && options.passwordFile.buf[0]) {
-    FILE* fp = fopen(options.passwordFile.buf, "rb");
-    if (!fp) return false;
-    char data[256];
-    int datalen = fread(data, 1, 256, fp);
-    fclose(fp);
-    if (datalen != 8) return false;
-    vncAuthUnobfuscatePasswd(data);
-    *password = strDup(data);
-    memset(data, 0, strlen(data));
-    return true;
-  }
-
-  if (user && options.userName.buf)
-    *user = strDup(options.userName.buf);
-  if (password && options.password.buf)
-    *password = strDup(options.password.buf);
-  if ((user && !*user) || (password && !*password)) {
-    // Missing username or password - prompt the user
-    UserPasswdDialog userPasswdDialog;
-    userPasswdDialog.setCSecurity(getCurrentCSecurity());
-    if (!userPasswdDialog.getUserPasswd(user, password))
-      return false;
-  }
-  if (user) options.setUserName(*user);
-  if (password) options.setPassword(*password);
-  return true;
-}
-
-bool CView::processFTMsg(int type)
-{
-  return m_fileTransfer.processFTMsg(type);
-}
\ No newline at end of file
diff --git a/vncviewer/cview.h b/vncviewer/cview.h
deleted file mode 100644 (file)
index 0dc0066..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-/* Copyright (C) 2002-2004 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.
- */
-
-// -=- CView.h
-
-// An instance of the CView class is created for each VNC Viewer connection.
-
-#ifndef __RFB_WIN32_CVIEW_H__
-#define __RFB_WIN32_CVIEW_H__
-
-#include <network/Socket.h>
-
-#include <rfb/CConnection.h>
-#include <rfb/Cursor.h>
-#include <rfb/UserPasswdGetter.h>
-
-#include <rfb_win32/Clipboard.h>
-#include <rfb_win32/DIBSectionBuffer.h>
-#include <rfb_win32/Win32Util.h>
-#include <rfb_win32/Registry.h>
-#include <rfb_win32/AboutDialog.h>
-#include <rfb_win32/CKeyboard.h>
-#include <rfb_win32/CPointer.h>
-
-#include <vncviewer/InfoDialog.h>
-#include <vncviewer/OptionsDialog.h>
-#include <vncviewer/ViewerToolBar.h>
-#include <vncviewer/CViewOptions.h>
-#include <vncviewer/CViewManager.h>
-#include <vncviewer/FileTransfer.h>
-#include <list>
-
-
-namespace rfb {
-
-  namespace win32 {
-
-    class CView : public CConnection,
-                  public UserPasswdGetter,
-                  rfb::win32::Clipboard::Notifier,
-                  rdr::FdInStreamBlockCallback
-    {
-    public:
-      CView();
-      virtual ~CView();
-
-      bool initialise(network::Socket* s);
-
-      void setManager(CViewManager* m) {manager = m;}
-
-      void applyOptions(CViewOptions& opt);
-      const CViewOptions& getOptions() const {return options;};
-
-      // -=- Window Message handling
-
-      virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
-      virtual LRESULT processFrameMessage(UINT msg, WPARAM wParam, LPARAM lParam);
-
-      // -=- Socket blocking handling
-      //     blockCallback will throw QuitMessage(result) when
-      //     it processes a WM_QUIT message.
-      //     The caller may catch that to cope gracefully with
-      //     a request to quit.
-
-      class QuitMessage : public rdr::Exception {
-      public:
-        QuitMessage(WPARAM wp) : rdr::Exception("QuitMessage") {}
-        WPARAM wParam;
-      };
-      virtual void blockCallback();
-
-      // -=- Window interface
-
-      void postQuitOnDestroy(bool qod) {quit_on_destroy = qod;}
-      PixelFormat getNativePF() const;
-      void setVisible(bool visible);
-      void close(const char* reason=0);
-      HWND getHandle() const {return hwnd;}
-      HWND getFrameHandle() const {return frameHwnd;}
-
-      void notifyClipboardChanged(const char* text, int len);
-
-      // -=- Coordinate conversions
-
-      inline Point bufferToClient(const Point& p) {
-        Point pos = p;
-        if (client_size.width() > buffer->width())
-          pos.x += (client_size.width() - buffer->width()) / 2;
-        else if (client_size.width() < buffer->width())
-          pos.x -= scrolloffset.x;
-        if (client_size.height() > buffer->height())
-          pos.y += (client_size.height() - buffer->height()) / 2;
-        else if (client_size.height() < buffer->height())
-          pos.y -= scrolloffset.y;
-        return pos;
-      }
-      inline Rect bufferToClient(const Rect& r) {
-        return Rect(bufferToClient(r.tl), bufferToClient(r.br));
-      }
-
-      inline Point clientToBuffer(const Point& p) {
-        Point pos = p;
-        if (client_size.width() > buffer->width())
-          pos.x -= (client_size.width() - buffer->width()) / 2;
-        else if (client_size.width() < buffer->width())
-          pos.x += scrolloffset.x;
-        if (client_size.height() > buffer->height())
-          pos.y -= (client_size.height() - buffer->height()) / 2;
-        else if (client_size.height() < buffer->height())
-          pos.y += scrolloffset.y;
-        return pos;
-      }
-      inline Rect clientToBuffer(const Rect& r) {
-        return Rect(clientToBuffer(r.tl), clientToBuffer(r.br));
-      }
-
-      void setFullscreen(bool fs);
-
-      bool setViewportOffset(const Point& tl);
-
-      bool processBumpScroll(const Point& cursorPos);
-      void setBumpScroll(bool on);
-
-      int lastUsedEncoding() const { return lastUsedEncoding_; }
-
-      // -=- CConnection interface overrides
-
-      virtual CSecurity* getCSecurity(int secType);
-
-      virtual void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs);
-      virtual void bell();
-
-      virtual void framebufferUpdateEnd();
-
-      virtual void setDesktopSize(int w, int h);
-      virtual void setCursor(const Point& hotspot, const Point& size, void* data, void* mask);
-      virtual void setName(const char* name);
-      virtual void serverInit();
-
-      virtual void serverCutText(const char* str, int len);
-
-      virtual void beginRect(const Rect& r, unsigned int encoding);
-      virtual void endRect(const Rect& r, unsigned int encoding);
-
-      virtual void fillRect(const Rect& r, Pixel pix);
-      virtual void imageRect(const Rect& r, void* pixels);
-      virtual void copyRect(const Rect& r, int srcX, int srcY);
-
-      void invertRect(const Rect& r);
-
-      // VNCviewer dialog objects
-
-      OptionsDialog optionsDialog;
-
-      friend class InfoDialog;
-      InfoDialog infoDialog;
-
-      // UserPasswdGetter overrides, used to support a pre-supplied VNC password
-      virtual bool getUserPasswd(char** user, char** password);
-
-      // Global user-config registry key
-      static RegKey userConfigKey;
-
-      bool processFTMsg(int type);
-
-    protected:
-
-      // Locally-rendered VNC cursor
-      void hideLocalCursor();
-      void showLocalCursor();
-      void renderLocalCursor();
-
-      // The system-rendered cursor
-      void hideSystemCursor();
-      void showSystemCursor();
-
-      // Grab AltTab?
-      void setAltTabGrab(bool grab);
-
-      // cursorOutsideBuffer() is called whenever we detect that the mouse has
-      // moved outside the desktop.  It restores the system arrow cursor.
-      void cursorOutsideBuffer();
-
-      // Returns true if part of the supplied rect is visible, false otherwise
-      bool invalidateBufferRect(const Rect& crect);
-
-      // Auto-encoding selector
-      void autoSelectFormatAndEncoding();
-
-      // Request an update with appropriate setPixelFormat and setEncodings calls
-      void requestNewUpdate();
-
-      // Update the window palette if the display is palette-based.
-      // Colours are pulled from the DIBSectionBuffer's ColourMap.
-      // Only the specified range of indexes is dealt with.
-      // After the update, the entire window is redrawn.
-      void refreshWindowPalette(int start, int count);
-
-      // Determine whether or not we need to enable/disable scrollbars and set the
-      // window style accordingly
-      void calculateScrollBars();
-
-      // Recalculate the most suitable full-colour pixel format
-      void calculateFullColourPF();
-
-      // Enable/disable/check/uncheck the F8 menu items as appropriate.
-      void updateF8Menu(bool hideSystemCommands);
-
-      // VNCviewer options
-
-      CViewOptions options;
-
-      // Input handling
-      void writeKeyEvent(rdr::U8 vkey, rdr::U32 flags, bool down);
-      void writePointerEvent(int x, int y, int buttonMask);
-      rfb::win32::CKeyboard kbd;
-      rfb::win32::CPointer ptr;
-      Point oldpos;
-
-      // Clipboard handling
-      rfb::win32::Clipboard clipboard;
-
-      // Pixel format and encoding
-      PixelFormat serverDefaultPF;
-      PixelFormat fullColourPF;
-      bool sameMachine;
-      bool encodingChange;
-      bool formatChange;
-      int lastUsedEncoding_;
-
-      // Networking and RFB protocol
-      network::Socket* sock;
-      bool readyToRead;
-      bool requestUpdate;
-
-      // Palette handling
-      LogicalPalette windowPalette;
-      bool palette_changed;
-
-      // - Full-screen mode
-      Rect fullScreenOldRect;
-      DWORD fullScreenOldFlags;
-      bool fullScreenActive;
-
-      // Bump-scrolling (used in full-screen mode)
-      bool bumpScroll;
-      Point bumpScrollDelta;
-      IntervalTimer bumpScrollTimer;
-
-      // Cursor handling
-      Cursor cursor;
-      bool systemCursorVisible;  // Should system-cursor be drawn?
-      bool trackingMouseLeave;
-      bool cursorInBuffer;    // Is cursor position within server buffer? (ONLY for LocalCursor)
-      bool cursorVisible;     // Is cursor currently rendered?
-      bool cursorAvailable;   // Is cursor available for rendering?
-      Point cursorPos;
-      ManagedPixelBuffer cursorBacking;
-      Rect cursorBackingRect;
-
-      // ** Debugging/logging
-      /*
-      int update_rect_count;
-      int update_pixel_count;
-      Rect update_extent;
-      */
-      std::list<Rect> debugRects;
-
-      // ToolBar handling
-      ViewerToolBar tb;
-      bool toolbar;
-
-      // Local window state
-      win32::DIBSectionBuffer* buffer;
-      bool has_focus;
-      bool quit_on_destroy;
-      Rect window_size;
-      Rect client_size;
-      Point scrolloffset;
-      Point maxscrolloffset;
-      HWND hwnd;
-      HWND frameHwnd;
-
-      // Handle back to CViewManager instance, if any
-      CViewManager* manager;
-
-      FileTransfer m_fileTransfer;
-
-    };
-
-  };
-
-};
-
-#endif
-
-
diff --git a/vncviewer/msvcwarning.h b/vncviewer/msvcwarning.h
deleted file mode 100644 (file)
index 53a0678..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Copyright (C) 2002-2003 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.
- */
-#pragma warning( disable : 4800 ) // forcing bool 'true' or 'false'
-#pragma warning( disable : 4786 ) // debug identifier truncated
index 59eee86efc0374359f86fbaae89a42afef816c4e..b3c7c8cef1201de154829ac403dc5827469ed7e6 100644 (file)
@@ -16,8 +16,9 @@
 #define IDR_TRAY                        112
 #define IDD_CONNECTION_INFO             113
 #define IDD_DEFAULTS                    116
-#define IDD_FILETRANSFER_DLG            120
-#define IDB_TOOLBAR                     121
+#define IDB_BITMAP                      120
+#define IDD_FILETRANSFER_DLG            121
+#define IDB_TOOLBAR                     122
 #define IDD_FTDIRNAME_DLG               123
 #define IDD_FTCONFIRM_DLG               124
 #define IDI_FTUP                        125
 #define IDC_MENU_KEY                    1051
 #define IDC_REQUESTED_ENCODING          1052
 #define IDC_LAST_ENCODING               1053
-#define IDC_ENCODING_TIGHT              1054
-#define IDC_FTLOCALPATH                 1054
-#define IDC_CUSTOM_COMPRESSLEVEL        1055
-#define IDC_FTREMOTEPATH                1055
-#define IDC_COMPRESSLEVEL               1056
-#define IDC_FTREMOTELIST                1056
-#define IDC_ALLOW_JPEG                  1057
-#define IDC_FTLOCALRELOAD               1057
+#define IDC_SECURITY_LEVEL              1054
+#define IDC_INFO_ENCRYPTION             1055
+#define IDC_AUTO_RECONNECT              1056
+#define IDC_DISABLE_WINKEYS             1057
 #define IDC_QUALITYLEVEL                1058
 #define IDC_FTLOCALUP                   1058
 #define IDC_SEND_SYSKEYS                1059
 #define IDC_FTTEXT                      1084
 #define IDC_FTBROWSEPATH                1085
 #define IDC_FTBROWSETREE                1086
+#define IDC_TYPE                        1088
+#define IDC_ENCODING_TIGHT              1089
+#define IDC_FTLOCALPATH                 1090
+#define IDC_CUSTOM_COMPRESSLEVEL        1091
+#define IDC_FTREMOTEPATH                1092
+#define IDC_COMPRESSLEVEL               1093
+#define IDC_FTREMOTELIST                1094
+#define IDC_ALLOW_JPEG                  1095
+#define IDC_FTLOCALRELOAD               1096
 #define ID_TOOLBAR                      40002
 #define ID_CLOSE                        40003
 #define ID_OPTIONS                      40004
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        134
 #define _APS_NEXT_COMMAND_VALUE         40028
-#define _APS_NEXT_CONTROL_VALUE         1087
+#define _APS_NEXT_CONTROL_VALUE         1097
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
diff --git a/vncviewer/vncviewer.bmp b/vncviewer/vncviewer.bmp
new file mode 100644 (file)
index 0000000..4ea9c37
Binary files /dev/null and b/vncviewer/vncviewer.bmp differ
index f0c9f20816d467f66e6f05bfd05c8019f556767a..3a5214a35ee39f87bac6e8106edb25976f6d331f 100644 (file)
@@ -1,5 +1,5 @@
-/* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
- *    
+/* 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
 #include <list>
 
 #include <vncviewer/resource.h>
-#include <vncviewer/CViewManager.h>
-#include <vncviewer/CView.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/CConnThread.h>
 #include <vncviewer/OptionsDialog.h>
-
+#include <vncviewer/ListenServer.h>
+#include <vncviewer/ListenTrayIcon.h>
+#include <network/TcpSocket.h>
 #include <rfb/Logger_stdio.h>
 #include <rfb/Logger_file.h>
 #include <rfb/LogWriter.h>
 #include <rfb/Exception.h>
-
 #include <rfb_win32/RegConfig.h>
-#include <rfb_win32/TrayIcon.h>
-#include <rfb_win32/Win32Util.h>
-#include <rfb_win32/AboutDialog.h>
-
-#include <network/TcpSocket.h>
+#include <rfb_win32/MsgBox.h>
 
 #ifdef _DIALOG_CAPTURE
 #include <extra/LoadBMP.h>
@@ -79,72 +76,6 @@ const WORD rfb::win32::AboutDialog::BuildTime = IDC_BUILDTIME;
 const WORD rfb::win32::AboutDialog::Description = IDC_DESCRIPTION;
 
 
-//
-// -=- VNCviewer Tray Icon
-//
-
-class CViewTrayIcon : public TrayIcon {
-public:
-  CViewTrayIcon(CViewManager& mgr) : manager(mgr) {
-    setIcon(IDI_ICON);
-    setToolTip(_T("VNC Viewer"));
-  }
-  virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
-    switch(msg) {
-
-    case WM_USER:
-      switch (lParam) {
-      case WM_LBUTTONDBLCLK:
-        SendMessage(getHandle(), WM_COMMAND, ID_NEW_CONNECTION, 0);
-        break;
-      case WM_RBUTTONUP:
-        HMENU menu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(IDR_TRAY));
-        HMENU trayMenu = GetSubMenu(menu, 0);
-
-        // First item is New Connection, the default
-        SetMenuDefaultItem(trayMenu, ID_NEW_CONNECTION, FALSE);
-
-        // SetForegroundWindow is required, otherwise Windows ignores the
-        // TrackPopupMenu because the window isn't the foreground one, on
-        // some older Windows versions...
-        SetForegroundWindow(getHandle());
-
-        // Display the menu
-        POINT pos;
-        GetCursorPos(&pos);
-        TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, getHandle(), 0);
-        break;
-                       } 
-                       return 0;
-
-    case WM_COMMAND:
-      switch (LOWORD(wParam)) {
-      case ID_NEW_CONNECTION:
-        manager.addClient(0);
-        break;
-      case ID_OPTIONS:
-        OptionsDialog::global.showDialog(0);
-        break;
-      case ID_ABOUT:
-        AboutDialog::instance.showDialog();
-        break;
-      case ID_CLOSE:
-        SendMessage(getHandle(), WM_CLOSE, 0, 0);
-        break;
-      }
-      return 0;
-
-    case WM_CLOSE:
-      PostQuitMessage(0);
-      return 0;
-    }
-
-    return TrayIcon::processMessage(msg, wParam, lParam);
-  }
-protected:
-  CViewManager& manager;
-};
-
 //
 // -=- processParams
 //     Read in the command-line parameters and interpret them.
@@ -166,7 +97,7 @@ programUsage() {
   printf("usage: vncviewer <options> <hostname>[:<display>]\n");
   printf("Command-line options:\n");
   printf("  -help                                - Provide usage information.\n");
-  printf("  -config <file>                       - Load connection settings from VNCViewer 3.3 settings file\n");
+  printf("  -config <file>                       - Load connection settings from VNC Viewer 3.3 settings file\n");
   printf("  -console                             - Run with a console window visible.\n");
   printf("  <setting>=<value>                    - Set the named configuration parameter.\n");
   printf("    (Parameter values specified on the command-line override those specified by other configuration methods.)\n");
@@ -176,6 +107,9 @@ programUsage() {
   Logger::listLoggers();
   printf("\nParameters:\n");
   Configuration::listParams();
+  printf("Press Enter/Return key to continue\n");
+  char c = getchar();
+  exit(1);
 }
 
 
@@ -224,6 +158,8 @@ processParams(int argc, char* argv[]) {
           sprintf(tmp.buf, fmt, argv[i]);
           MsgBox(0, TStr(tmp.buf), MB_ICONSTOP | MB_OK);
           exit(1);
+        } else if (strContains(argv[i], '\\')) {
+          configFiles.push_back(strDup(argv[i]));
         } else {
           hosts.push_back(strDup(argv[i]));
         }
@@ -241,7 +177,6 @@ processParams(int argc, char* argv[]) {
 //
 
 int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdShow) {
-
   try {
 
     // - Initialise the available loggers
@@ -270,7 +205,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdSho
 
 #ifdef _DIALOG_CAPTURE
     if (captureDialogs) {
-      CView::userConfigKey.openKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
+      CConn::userConfigKey.openKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
       OptionsDialog::global.showDialog(0, true);
       return 0;
     }
@@ -285,35 +220,27 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdSho
     // - Connect to the clients
     if (!configFiles.empty() || !hosts.empty() || acceptIncoming) {
       // - Configure the registry configuration reader
-      win32::RegistryReader reg_reader;
-      reg_reader.setKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
+      win32::RegConfigThread config;
+      config.start(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
 
       // - Tell the rest of VNC Viewer where to write config data to
-      CView::userConfigKey.openKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
-
-      // - Start the Socket subsystem for TCP
-      TcpSocket::initTcpSockets();
-
-      // Create the client connection manager
-      CViewManager view_manager;
+      CConn::userConfigKey.createKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
 
       if (acceptIncoming) {
         int port = 5500;
 
         // Listening viewer
-        if (hosts.size() > 1) {
+        if (hosts.size() > 1)
           programUsage();
-          exit(2);
-        }
-        if (!hosts.empty()) {
+        if (!hosts.empty())
           port = atoi(hosts.front());  
-        }
 
-        vlog.debug("opening listener");
+        // Show the tray icon & menu
+        ListenTrayIcon tray;
 
-        CViewTrayIcon tray(view_manager);
-
-        view_manager.addDefaultTCPListener(port);
+        // Listen for reverse connections
+        network::TcpListener sock(port);
+        ListenServer listener(&sock);
 
         // Run the view manager
         // Also processes the tray icon if necessary
@@ -322,13 +249,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdSho
           TranslateMessage(&msg);
           DispatchMessage(&msg);
         }
-
-        vlog.debug("quitting viewer");
       } else {
         // Read each config file in turn
         while (!configFiles.empty()) {
           char* filename = configFiles.front();
-          view_manager.addClient(filename, true);
+          Thread* connThread = new CConnThread(filename, true);
           strFree(filename);
           configFiles.pop_front();
         }
@@ -336,14 +261,14 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdSho
         // Connect to each client in turn
         while (!hosts.empty()) {
           char* hostinfo = hosts.front();
-          view_manager.addClient(hostinfo);
+          Thread* connThread = new CConnThread(hostinfo);
           strFree(hostinfo);
           hosts.pop_front();
         }
 
         // Run the view manager
         MSG msg;
-        while (GetMessage(&msg, NULL, 0, 0) > 0) {
+        while (CConnThread::getMessage(&msg, NULL, 0, 0) > 0) {
           TranslateMessage(&msg);
           DispatchMessage(&msg);
         }
index 071b3e408914bfe28098bb477bf91b38043c0b55..3c96f0090817aab1c4daa9531d8dc21aee7baec1 100644 (file)
@@ -44,7 +44,7 @@ RSC=rc.exe
 # PROP Ignore_Export_Lib 0\r
 # PROP Target_Dir ""\r
 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c\r
-# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /FI"msvcwarning.h" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /c\r
+# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /c\r
 # ADD BASE RSC /l 0x809 /d "NDEBUG"\r
 # ADD RSC /l 0x809 /d "NDEBUG"\r
 BSC32=bscmake.exe\r
@@ -73,7 +73,7 @@ PreLink_Cmds=cl /c /nologo /FoRelease\ /FdRelease\ /MT buildTime.cxx
 # PROP Ignore_Export_Lib 0\r
 # PROP Target_Dir ""\r
 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /FR /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /FR /YX /FD /GZ /c\r
 # ADD BASE RSC /l 0x809 /d "_DEBUG"\r
 # ADD RSC /l 0x809 /d "_DEBUG"\r
 BSC32=bscmake.exe\r
@@ -103,7 +103,7 @@ PreLink_Cmds=cl /c /nologo /FoDebug\ /FdDebug\ /MTd buildTime.cxx
 # PROP Ignore_Export_Lib 0\r
 # PROP Target_Dir ""\r
 # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /GZ /c\r
-# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"msvcwarning.h" /D "_WINDOWS" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c\r
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /FI"rdr/msvcwarning.h" /D "_WINDOWS" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /YX /FD /GZ /c\r
 # ADD BASE RSC /l 0x809 /d "_DEBUG"\r
 # ADD RSC /l 0x809 /d "_DEBUG"\r
 BSC32=bscmake.exe\r
@@ -134,19 +134,27 @@ SOURCE=.\buildTime.cxx
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\ConnectionDialog.cxx\r
+SOURCE=.\CConn.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CConnOptions.cxx\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CConnThread.cxx\r
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\cview.cxx\r
+SOURCE=.\ConnectingDialog.cxx\r
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\CViewManager.cxx\r
+SOURCE=.\ConnectionDialog.cxx\r
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\CViewOptions.cxx\r
+SOURCE=.\DesktopWindow.cxx\r
 # End Source File\r
 # Begin Source File\r
 \r
@@ -206,23 +214,27 @@ SOURCE=.\vncviewer.rc
 # PROP Default_Filter "h;hpp;hxx;hm;inl"\r
 # Begin Source File\r
 \r
-SOURCE=.\ConnectingDialog.h\r
+SOURCE=.\CConn.h\r
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\ConnectionDialog.h\r
+SOURCE=.\CConnOptions.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\CConnThread.h\r
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\cview.h\r
+SOURCE=.\ConnectingDialog.h\r
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\CViewManager.h\r
+SOURCE=.\ConnectionDialog.h\r
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\CViewOptions.h\r
+SOURCE=.\DesktopWindow.h\r
 # End Source File\r
 # Begin Source File\r
 \r
@@ -258,6 +270,14 @@ SOURCE=.\InfoDialog.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\ListenServer.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\ListenTrayIcon.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\MRU.h\r
 # End Source File\r
 # Begin Source File\r
@@ -302,6 +322,10 @@ SOURCE=.\toolbar.bmp
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\vncviewer.bmp\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\vncviewer.exe.manifest\r
 # End Source File\r
 # Begin Source File\r