summaryrefslogtreecommitdiffstats
path: root/vncviewer
diff options
context:
space:
mode:
authorConstantin Kaplinsky <const@tightvnc.com>2006-05-18 11:08:21 +0000
committerConstantin Kaplinsky <const@tightvnc.com>2006-05-18 11:08:21 +0000
commit8d9f5139332ca8509ab84601c53634d361ab4a2d (patch)
tree499e7ce0e3bfec1a5d374794126ef7b35565e9b2 /vncviewer
parent265d3c8752f2e9799dab2b048dde64994f891cb6 (diff)
parent590db877c7bbadc2f95751c3a6ea6f6c93bca37a (diff)
downloadtigervnc-8d9f5139332ca8509ab84601c53634d361ab4a2d.tar.gz
tigervnc-8d9f5139332ca8509ab84601c53634d361ab4a2d.zip
Merged the changes from branch/merge-with-vnc-4.1.1, revisions 520:558.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@559 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'vncviewer')
-rw-r--r--vncviewer/CConn.cxx710
-rw-r--r--vncviewer/CConn.h165
-rw-r--r--vncviewer/CConnOptions.cxx (renamed from vncviewer/CViewOptions.cxx)101
-rw-r--r--vncviewer/CConnOptions.h (renamed from vncviewer/CViewOptions.h)35
-rw-r--r--vncviewer/CConnThread.cxx198
-rw-r--r--vncviewer/CConnThread.h57
-rw-r--r--vncviewer/CViewManager.cxx252
-rw-r--r--vncviewer/ConnectingDialog.cxx160
-rw-r--r--vncviewer/ConnectingDialog.h88
-rw-r--r--vncviewer/ConnectionDialog.cxx19
-rw-r--r--vncviewer/ConnectionDialog.h10
-rw-r--r--vncviewer/DesktopWindow.cxx1092
-rw-r--r--vncviewer/DesktopWindow.h254
-rw-r--r--vncviewer/InfoDialog.cxx34
-rw-r--r--vncviewer/InfoDialog.h12
-rw-r--r--vncviewer/ListenServer.h (renamed from vncviewer/CViewManager.h)58
-rw-r--r--vncviewer/ListenTrayIcon.h95
-rw-r--r--vncviewer/MRU.h13
-rw-r--r--vncviewer/OptionsDialog.cxx58
-rw-r--r--vncviewer/OptionsDialog.h9
-rw-r--r--vncviewer/UserPasswdDialog.cxx47
-rw-r--r--vncviewer/UserPasswdDialog.h14
-rw-r--r--vncviewer/buildTime.cxx19
-rw-r--r--vncviewer/cview.cxx1742
-rw-r--r--vncviewer/cview.h312
-rw-r--r--vncviewer/msvcwarning.h19
-rw-r--r--vncviewer/resource.h29
-rw-r--r--vncviewer/vncviewer.bmpbin0 -> 2006 bytes
-rw-r--r--vncviewer/vncviewer.cxx131
-rw-r--r--vncviewer/vncviewer.dsp48
-rw-r--r--vncviewer/vncviewer.rc558
31 files changed, 3332 insertions, 3007 deletions
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx
new file mode 100644
index 00000000..d141e50c
--- /dev/null
+++ b/vncviewer/CConn.cxx
@@ -0,0 +1,710 @@
+/* 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 = !window->isToolbarEnabled();
+ window->setShowToolbar(options.showToolbar);
+ 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);
+
+ // Set the menu toolbar option tick
+ int toolbarFlags = window->isToolbarEnabled() ? MF_CHECKED : 0;
+ CheckMenuItem(menu, IDM_SHOW_TOOLBAR, MF_BYCOMMAND | toolbarFlags);
+
+ // In the full-screen mode, "Show toolbar" should be grayed.
+ toolbarFlags = window->isFullscreen() ? 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
index 00000000..29023f39
--- /dev/null
+++ b/vncviewer/CConn.h
@@ -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/CViewOptions.cxx b/vncviewer/CConnOptions.cxx
index 76a624b2..4ea0ada1 100644
--- a/vncviewer/CViewOptions.cxx
+++ b/vncviewer/CConnOptions.cxx
@@ -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
@@ -16,12 +16,11 @@
* USA.
*/
-#include <vncviewer/CViewOptions.h>
+#include <vncviewer/CConnOptions.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/MsgBox.h>
#include <rfb_win32/Registry.h>
#include <rdr/HexInStream.h>
#include <rdr/HexOutStream.h>
@@ -33,6 +32,9 @@ 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);
@@ -66,14 +68,15 @@ 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);
@@ -92,6 +95,8 @@ 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. "
@@ -111,18 +116,24 @@ static IntParameter qualityLevel("QualityLevel",
"0 = Low, 9 = High",
6);
-CViewOptions::CViewOptions()
+CConnOptions::CConnOptions()
: useLocalCursor(::useLocalCursor), useDesktopResize(::useDesktopResize),
autoSelect(::autoSelect), fullColour(::fullColour), fullScreen(::fullScreen),
-shared(::sharedConnection), sendPtrEvents(::sendPtrEvents), sendKeyEvents(::sendKeyEvents), sendSysKeys(::sendSysKeys),
+shared(::sharedConnection), sendPtrEvents(::sendPtrEvents), sendKeyEvents(::sendKeyEvents),
preferredEncoding(encodingZRLE), clientCutText(::clientCutText), serverCutText(::serverCutText),
-protocol3_3(::protocol3_3), acceptBell(::acceptBell), showToolbar(::showToolbar), lowColourLevel(::lowColourLevel),
-pointerEventInterval(ptrEventInterval), emulate3(::emulate3), monitor(::monitor.getData()),
+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())
+noJpeg(::noJpeg), qualityLevel(::qualityLevel), passwordFile(::passwordFile.getData()),
+autoReconnect(::autoReconnect)
{
- CharArray encodingName(::preferredEncoding.getData());
- preferredEncoding = encodingNum(encodingName.buf);
+ if (autoSelect) {
+ preferredEncoding = encodingZRLE;
+ } else {
+ CharArray encodingName(::preferredEncoding.getData());
+ preferredEncoding = encodingNum(encodingName.buf);
+ }
setMenuKey(CharArray(::menuKey.getData()).buf);
if (!::autoSelect.hasBeenSet()) {
@@ -138,7 +149,7 @@ noJpeg(::noJpeg), qualityLevel(::qualityLevel), passwordFile(::passwordFile.getD
}
-void CViewOptions::readFromFile(const char* filename) {
+void CConnOptions::readFromFile(const char* filename) {
FILE* f = fopen(filename, "r");
if (!f)
throw rdr::Exception("Failed to read configuration file");
@@ -185,15 +196,10 @@ void CViewOptions::readFromFile(const char* filename) {
} 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;
- }
+ 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
@@ -218,12 +224,12 @@ void CViewOptions::readFromFile(const char* filename) {
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) {
@@ -236,6 +242,9 @@ void CViewOptions::readFromFile(const char* filename) {
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) {
@@ -274,6 +283,10 @@ void CViewOptions::readFromFile(const char* filename) {
}
}
+ // If AutoSelect is enabled then override the preferred encoding
+ if (autoSelect)
+ preferredEncoding = encodingZRLE;
+
setConfigFileName(filename);
} catch (rdr::Exception&) {
if (f) fclose(f);
@@ -281,7 +294,7 @@ void CViewOptions::readFromFile(const char* filename) {
}
}
-void CViewOptions::writeToFile(const char* filename) {
+void CConnOptions::writeToFile(const char* filename) {
FILE* f = fopen(filename, "w");
if (!f)
throw rdr::Exception("Failed to write configuration file");
@@ -298,11 +311,8 @@ void CViewOptions::writeToFile(const char* filename) {
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);
+ ObfuscatedPasswd obfPwd(password);
+ CharArray obfuscatedHex = rdr::HexOutStream::binToHexStr(obfPwd.buf, obfPwd.length);
fprintf(f, "Password=%s\n", obfuscatedHex.buf);
}
}
@@ -320,9 +330,9 @@ void CViewOptions::writeToFile(const char* filename) {
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);
@@ -330,6 +340,7 @@ void CViewOptions::writeToFile(const char* filename) {
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);
@@ -344,7 +355,7 @@ void CViewOptions::writeToFile(const char* filename) {
}
-void CViewOptions::writeDefaults() {
+void CConnOptions::writeDefaults() {
RegKey key;
key.createKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCviewer4"));
key.setBool(_T("UseLocalCursor"), useLocalCursor);
@@ -357,9 +368,9 @@ void CViewOptions::writeDefaults() {
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);
@@ -368,6 +379,7 @@ void CViewOptions::writeDefaults() {
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);
@@ -375,13 +387,13 @@ void CViewOptions::writeDefaults() {
}
-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 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 CViewOptions::setMenuKey(const char* keyName) {
+void CConnOptions::setMenuKey(const char* keyName) {
if (!keyName[0]) {
menuKey = 0;
} else {
@@ -393,7 +405,7 @@ void CViewOptions::setMenuKey(const char* keyName) {
}
}
}
-char* CViewOptions::menuKeyName() {
+char* CConnOptions::menuKeyName() {
int fNum = (menuKey-VK_F1)+1;
if (fNum<1 || fNum>12)
return strDup("");
@@ -403,7 +415,7 @@ char* CViewOptions::menuKeyName() {
}
-CViewOptions& CViewOptions::operator=(const CViewOptions& o) {
+CConnOptions& CConnOptions::operator=(const CConnOptions& o) {
useLocalCursor = o.useLocalCursor;
useDesktopResize = o.useDesktopResize;
fullScreen = o.fullScreen;
@@ -414,9 +426,9 @@ CViewOptions& CViewOptions::operator=(const CViewOptions& o) {
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;
@@ -428,6 +440,7 @@ CViewOptions& CViewOptions::operator=(const CViewOptions& o) {
setHost(o.host.buf);
setMonitor(o.monitor.buf);
menuKey = o.menuKey;
+ autoReconnect = o.autoReconnect;
customCompressLevel = o.customCompressLevel;
compressLevel = o.compressLevel;
noJpeg = o.noJpeg;
diff --git a/vncviewer/CViewOptions.h b/vncviewer/CConnOptions.h
index febd2842..59fd0a3c 100644
--- a/vncviewer/CViewOptions.h
+++ b/vncviewer/CConnOptions.h
@@ -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
@@ -16,15 +16,15 @@
* USA.
*/
-// -=- CViewOptions.h
+// -=- CConnOptions.h
-// Definition of the CViewOptions class, responsible for storing the
-// current & requested VNCviewer options.
+// Definition of the CConnOptions class, responsible for storing the
+// current & requested VNC Viewer options.
-#ifndef __RFB_WIN32_CVIEW_OPTIONS_H__
-#define __RFB_WIN32_CVIEW_OPTIONS_H__
+#ifndef __RFB_WIN32_CCONN_OPTIONS_H__
+#define __RFB_WIN32_CCONN_OPTIONS_H__
-#include <rfb/util.h>
+#include <rfb/Password.h>
namespace rfb {
@@ -32,19 +32,19 @@ namespace rfb {
//
// -=- 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
+ // 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 CViewOptions {
+ class CConnOptions {
public:
- CViewOptions();
- CViewOptions(const CViewOptions& o) {operator=(o);}
- CViewOptions& operator=(const CViewOptions& o);
+ CConnOptions();
+ CConnOptions(const CConnOptions& o) {operator=(o);}
+ CConnOptions& operator=(const CConnOptions& o);
void readFromFile(const char* filename_);
void writeToFile(const char* filename_);
void writeDefaults();
@@ -58,17 +58,17 @@ namespace rfb {
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);
- CharArray password;
+ PlainPasswd password;
void setPassword(const char* pwd);
CharArray configFileName;
void setConfigFileName(const char* cfn);
@@ -79,6 +79,7 @@ namespace rfb {
unsigned int menuKey;
void setMenuKey(const char* keyName);
char* menuKeyName();
+ bool autoReconnect;
bool customCompressLevel;
int compressLevel;
diff --git a/vncviewer/CConnThread.cxx b/vncviewer/CConnThread.cxx
new file mode 100644
index 00000000..cfd26952
--- /dev/null
+++ b/vncviewer/CConnThread.cxx
@@ -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
index 00000000..7a8451c1
--- /dev/null
+++ b/vncviewer/CConnThread.h
@@ -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
index 09ed1fe8..00000000
--- a/vncviewer/CViewManager.cxx
+++ /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/ConnectingDialog.cxx b/vncviewer/ConnectingDialog.cxx
new file mode 100644
index 00000000..60fcb661
--- /dev/null
+++ b/vncviewer/ConnectingDialog.cxx
@@ -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;
+}
diff --git a/vncviewer/ConnectingDialog.h b/vncviewer/ConnectingDialog.h
index b146ced6..c38b3a1b 100644
--- a/vncviewer/ConnectingDialog.h
+++ b/vncviewer/ConnectingDialog.h
@@ -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
@@ -18,78 +18,48 @@
// -=- 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
diff --git a/vncviewer/ConnectionDialog.cxx b/vncviewer/ConnectionDialog.cxx
index c083444c..e7c6b0a5 100644
--- a/vncviewer/ConnectionDialog.cxx
+++ b/vncviewer/ConnectionDialog.cxx
@@ -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
@@ -15,9 +15,11 @@
* 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;
diff --git a/vncviewer/ConnectionDialog.h b/vncviewer/ConnectionDialog.h
index 554c86fb..f739280c 100644
--- a/vncviewer/ConnectionDialog.h
+++ b/vncviewer/ConnectionDialog.h
@@ -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
index 00000000..eee55ff1
--- /dev/null
+++ b/vncviewer/DesktopWindow.cxx
@@ -0,0 +1,1092 @@
+/* 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(false),
+ 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(handle);
+ 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, handle, 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 (tb.isVisible())
+ 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::setShowToolbar(bool st)
+{
+ showToolbar = st;
+
+ if (showToolbar && !tb.isVisible()) {
+ tb.show();
+ } else if (!showToolbar && tb.isVisible()) {
+ tb.hide();
+ }
+}
+
+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.tl.y, reqd_size.br.x, 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(handle, &r);
+ if (tb.isVisible()) {
+ MoveWindow(frameHandle, 0, tb.getHeight(),
+ r.right, r.bottom - tb.getHeight(), TRUE);
+ } else {
+ MoveWindow(frameHandle, 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;
+
+ // -=- If the menu is about to be shown, make sure it's up to date
+
+ case WM_INITMENU:
+ callback->refreshMenu(true);
+ 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;
+
+ }
+ 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
+ //
+ // NOTE: Here we call refreshMenu only to grey out Move and Size
+ // menu items. Other things will be refreshed once again
+ // while processing the WM_INITMENU message.
+ //
+ 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(frameHandle, 0, FALSE);
+}
+
+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
index 00000000..d54cd5f7
--- /dev/null
+++ b/vncviewer/DesktopWindow.h
@@ -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 the window fullscreen / determine whether it is fullscreen
+ void setFullscreen(bool fs);
+ bool isFullscreen() { return fullscreenActive; }
+
+ // - Set/get the toolbar's state
+ void setShowToolbar(bool st);
+ bool isToolbarEnabled() { return showToolbar; }
+
+ // - 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__
+
+
diff --git a/vncviewer/InfoDialog.cxx b/vncviewer/InfoDialog.cxx
index 0d2313a5..e74896dc 100644
--- a/vncviewer/InfoDialog.cxx
+++ b/vncviewer/InfoDialog.cxx
@@ -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()));
}
diff --git a/vncviewer/InfoDialog.h b/vncviewer/InfoDialog.h
index 7a64d383..752d53c5 100644
--- a/vncviewer/InfoDialog.h
+++ b/vncviewer/InfoDialog.h
@@ -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/CViewManager.h b/vncviewer/ListenServer.h
index 3d11dd96..4d1590c0 100644
--- a/vncviewer/CViewManager.h
+++ b/vncviewer/ListenServer.h
@@ -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
@@ -16,49 +16,41 @@
* USA.
*/
-// -=- CViewManager.h
-
-// Creates and manages threads to run CView instances.
+// -=- ListenServer.h
-#ifndef __RFB_WIN32_CVIEW_MANAGER_H__
-#define __RFB_WIN32_CVIEW_MANAGER_H__
+#ifndef __RFB_WIN32_LISTEN_SERVER_H__
+#define __RFB_WIN32_LISTEN_SERVER_H__
-#include <list>
+#include <windows.h>
+#include <winsock2.h>
#include <network/Socket.h>
-#include <rfb/Threading.h>
#include <rfb_win32/MsgWindow.h>
+#include <vncviewer/CConnThread.h>
-namespace rfb {
+namespace rfb {
namespace win32 {
- class CViewManager : public MsgWindow {
+ class ListenServer : 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);
-
+ 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:
- std::list<network::SocketListener*> socks;
- std::list<Thread*> threads;
- Mutex threadsMutex;
- Condition threadsSig;
- Thread* mainThread;
+ network::SocketListener* sock;
};
};
-
};
-#endif
+#endif \ No newline at end of file
diff --git a/vncviewer/ListenTrayIcon.h b/vncviewer/ListenTrayIcon.h
new file mode 100644
index 00000000..7e334d91
--- /dev/null
+++ b/vncviewer/ListenTrayIcon.h
@@ -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
diff --git a/vncviewer/MRU.h b/vncviewer/MRU.h
index f065a06e..ae703b3a 100644
--- a/vncviewer/MRU.h
+++ b/vncviewer/MRU.h
@@ -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
@@ -18,13 +18,10 @@
#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);
diff --git a/vncviewer/OptionsDialog.cxx b/vncviewer/OptionsDialog.cxx
index 0985f5b1..2e43b38f 100644
--- a/vncviewer/OptionsDialog.cxx
+++ b/vncviewer/OptionsDialog.cxx
@@ -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
@@ -16,20 +16,16 @@
* 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:
@@ -190,9 +188,10 @@ public:
virtual void initDialog() {
setItemChecked(IDC_SEND_POINTER, dlg->options.sendPtrEvents);
setItemChecked(IDC_SEND_KEYS, dlg->options.sendKeyEvents);
- 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);
@@ -213,9 +212,9 @@ public:
virtual bool onOk() {
dlg->options.sendPtrEvents = isItemChecked(IDC_SEND_POINTER);
dlg->options.sendKeyEvents = isItemChecked(IDC_SEND_KEYS);
- 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 +228,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 +245,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 +259,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 +278,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 +295,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 +310,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 +328,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;
diff --git a/vncviewer/OptionsDialog.h b/vncviewer/OptionsDialog.h
index eec9b96a..fcddc71c 100644
--- a/vncviewer/OptionsDialog.h
+++ b/vncviewer/OptionsDialog.h
@@ -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
@@ -23,19 +23,18 @@
#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:
diff --git a/vncviewer/UserPasswdDialog.cxx b/vncviewer/UserPasswdDialog.cxx
index 8ab4ba4c..2eea0ea0 100644
--- a/vncviewer/UserPasswdDialog.cxx
+++ b/vncviewer/UserPasswdDialog.cxx
@@ -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
@@ -18,12 +18,14 @@
#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;
}
diff --git a/vncviewer/UserPasswdDialog.h b/vncviewer/UserPasswdDialog.h
index 998a49f1..bf006f4d 100644
--- a/vncviewer/UserPasswdDialog.h
+++ b/vncviewer/UserPasswdDialog.h
@@ -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
@@ -19,6 +19,10 @@
// -=- 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;
};
diff --git a/vncviewer/buildTime.cxx b/vncviewer/buildTime.cxx
index bab2e137..9f37b387 100644
--- a/vncviewer/buildTime.cxx
+++ b/vncviewer/buildTime.cxx
@@ -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
index 03c68e20..00000000
--- a/vncviewer/cview.cxx
+++ /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
index 0dc00662..00000000
--- a/vncviewer/cview.h
+++ /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
index 53a0678d..00000000
--- a/vncviewer/msvcwarning.h
+++ /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
diff --git a/vncviewer/resource.h b/vncviewer/resource.h
index 59eee86e..5493fd0b 100644
--- a/vncviewer/resource.h
+++ b/vncviewer/resource.h
@@ -16,9 +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 IDD_FTDIRNAME_DLG 123
+#define IDB_BITMAP 120
+#define IDD_FILETRANSFER_DLG 121
+#define IDB_TOOLBAR 122
#define IDD_FTCONFIRM_DLG 124
#define IDI_FTUP 125
#define IDI_FTDIR 126
@@ -77,14 +77,10 @@
#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
@@ -115,6 +111,15 @@
#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
@@ -143,7 +148,7 @@
#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
index 00000000..4ea9c378
--- /dev/null
+++ b/vncviewer/vncviewer.bmp
Binary files differ
diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
index f0c9f208..3a5214a3 100644
--- a/vncviewer/vncviewer.cxx
+++ b/vncviewer/vncviewer.cxx
@@ -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
@@ -25,21 +25,18 @@
#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>
@@ -80,72 +77,6 @@ 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);
}
diff --git a/vncviewer/vncviewer.dsp b/vncviewer/vncviewer.dsp
index 4620dc0b..49a17cca 100644
--- a/vncviewer/vncviewer.dsp
+++ b/vncviewer/vncviewer.dsp
@@ -44,7 +44,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /FI"msvcwarning.h" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x809 /d "NDEBUG"
# ADD RSC /l 0x809 /d "NDEBUG"
BSC32=bscmake.exe
@@ -73,7 +73,7 @@ PreLink_Cmds=cl /c /nologo /FoRelease\ /FdRelease\ /MT buildTime.cxx
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
-# 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
+# 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
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
BSC32=bscmake.exe
@@ -103,7 +103,7 @@ PreLink_Cmds=cl /c /nologo /FoDebug\ /FdDebug\ /MTd buildTime.cxx
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# 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
-# 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
+# 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
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
BSC32=bscmake.exe
@@ -134,19 +134,27 @@ SOURCE=.\buildTime.cxx
# End Source File
# Begin Source File
-SOURCE=.\ConnectionDialog.cxx
+SOURCE=.\CConn.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnOptions.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnThread.cxx
# End Source File
# Begin Source File
-SOURCE=.\cview.cxx
+SOURCE=.\ConnectingDialog.cxx
# End Source File
# Begin Source File
-SOURCE=.\CViewManager.cxx
+SOURCE=.\ConnectionDialog.cxx
# End Source File
# Begin Source File
-SOURCE=.\CViewOptions.cxx
+SOURCE=.\DesktopWindow.cxx
# End Source File
# Begin Source File
@@ -198,23 +206,27 @@ SOURCE=.\vncviewer.rc
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
-SOURCE=.\ConnectingDialog.h
+SOURCE=.\CConn.h
# End Source File
# Begin Source File
-SOURCE=.\ConnectionDialog.h
+SOURCE=.\CConnOptions.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnThread.h
# End Source File
# Begin Source File
-SOURCE=.\cview.h
+SOURCE=.\ConnectingDialog.h
# End Source File
# Begin Source File
-SOURCE=.\CViewManager.h
+SOURCE=.\ConnectionDialog.h
# End Source File
# Begin Source File
-SOURCE=.\CViewOptions.h
+SOURCE=.\DesktopWindow.h
# End Source File
# Begin Source File
@@ -242,6 +254,14 @@ SOURCE=.\InfoDialog.h
# End Source File
# Begin Source File
+SOURCE=.\ListenServer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ListenTrayIcon.h
+# End Source File
+# Begin Source File
+
SOURCE=.\MRU.h
# End Source File
# Begin Source File
@@ -286,6 +306,10 @@ SOURCE=.\toolbar.bmp
# End Source File
# Begin Source File
+SOURCE=.\vncviewer.bmp
+# End Source File
+# Begin Source File
+
SOURCE=.\vncviewer.exe.manifest
# End Source File
# Begin Source File
diff --git a/vncviewer/vncviewer.rc b/vncviewer/vncviewer.rc
index 94e3f377..ea5dd65c 100644
--- a/vncviewer/vncviewer.rc
+++ b/vncviewer/vncviewer.rc
@@ -13,127 +13,37 @@
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
+// English (U.K.) resources
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
#endif //_WIN32
+#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
-// Dialog
+// TEXTINCLUDE
//
-IDD_FILETRANSFER_DLG DIALOGEX 0, 0, 530, 282
-STYLE DS_MODALFRAME | DS_CONTEXTHELP | WS_POPUP | WS_VISIBLE | WS_CAPTION |
- WS_SYSMENU
-EXSTYLE WS_EX_CONTEXTHELP | WS_EX_CONTROLPARENT
-CAPTION "TightVNC File Transfers"
-FONT 8, "MS Sans Serif"
+1 TEXTINCLUDE DISCARDABLE
BEGIN
- CONTROL "List1",IDC_FTLOCALLIST,"SysListView32",LVS_REPORT |
- LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER |
- WS_TABSTOP,7,40,200,196
- CONTROL "List2",IDC_FTREMOTELIST,"SysListView32",LVS_REPORT |
- LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER |
- WS_TABSTOP,323,40,200,196
- PUSHBUTTON "Upload Files and Folders",IDC_FTUPLOAD,218,66,94,12,
- WS_DISABLED
- PUSHBUTTON "Download Files and Folders",IDC_FTDOWNLOAD,218,85,94,12,
- WS_DISABLED
- PUSHBUTTON "Cancel File Transfer",IDC_FTCANCEL,218,167,94,12,
- WS_DISABLED
- PUSHBUTTON "Close File Transfers",IDC_FTCLOSE,218,217,94,12
- EDITTEXT IDC_FTLOCALPATH,7,20,155,12,ES_AUTOHSCROLL | NOT
- WS_TABSTOP
- CTEXT "Local Computer",IDC_FTLOCALLABEL,7,7,200,10
- PUSHBUTTON "...",IDC_FTLOCALBROWSE,165,20,14,12,NOT WS_TABSTOP
- PUSHBUTTON "",IDC_FTLOCALUP,179,20,14,12,BS_ICON | NOT WS_TABSTOP
- PUSHBUTTON "",IDC_FTLOCALRELOAD,193,20,14,12,BS_ICON | NOT
- WS_TABSTOP
- CONTROL "Progress1",IDC_FTGENERALPROGRESS,"msctls_progress32",
- WS_BORDER,55,244,128,10
- LTEXT "File Transfer",IDC_STATIC,7,245,40,8
- COMBOBOX IDC_FTSTATUS,7,263,516,65,CBS_DROPDOWNLIST |
- CBS_NOINTEGRALHEIGHT | WS_VSCROLL
- CONTROL "Progress1",IDC_FTSINGLEPROGRESS,"msctls_progress32",
- WS_BORDER,370,244,128,10
- EDITTEXT IDC_FTREMOTEPATH,323,20,155,12,ES_AUTOHSCROLL | NOT
- WS_TABSTOP
- PUSHBUTTON "...",IDC_FTREMOTEBROWSE,481,20,14,12,NOT WS_TABSTOP
- PUSHBUTTON "",IDC_FTREMOTEUP,495,20,14,12,BS_ICON | NOT WS_TABSTOP
- PUSHBUTTON "",IDC_FTREMOTERELOAD,509,20,14,12,BS_ICON | NOT
- WS_TABSTOP
- CTEXT "TightVNC Server",IDC_FTREMOTELABEL,323,7,200,10
- LTEXT "Current File",IDC_STATIC,323,245,36,8
- CTEXT "0%",IDC_FTGENERALPERCENT,189,245,18,8
- CTEXT "0%",IDC_FTSINGLEPERCENT,505,245,18,8
+ "resource.h\0"
END
-IDD_FTDIRNAME_DLG DIALOG DISCARDABLE 0, 0, 193, 63
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Create a New Folder"
-FONT 8, "MS Sans Serif"
+2 TEXTINCLUDE DISCARDABLE
BEGIN
- DEFPUSHBUTTON "OK",IDOK,80,42,50,14
- PUSHBUTTON "Cancel",IDCANCEL,136,42,50,14
- EDITTEXT IDC_FTDIRNAME,7,19,179,14,ES_AUTOHSCROLL
- LTEXT "New Folder Name",IDC_STATIC,7,7,93,8
+ "#include ""afxres.h""\r\n"
+ "\0"
END
-IDD_FTCONFIRM_DLG DIALOG DISCARDABLE 0, 0, 188, 143
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-FONT 8, "MS Sans Serif"
+3 TEXTINCLUDE DISCARDABLE
BEGIN
- DEFPUSHBUTTON "Yes",IDOK,69,122,50,14
- PUSHBUTTON "No",IDCANCEL,131,122,50,14
- PUSHBUTTON "Yes to All",IDC_CONFIRM_YESTOALL,7,122,50,14
- LTEXT "Static",IDC_CONFIRM_TEXT,7,7,174,107
+ "\r\n"
+ "\0"
END
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO DISCARDABLE
-BEGIN
- IDD_FILETRANSFER_DLG, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 523
- VERTGUIDE, 207
- VERTGUIDE, 265
- VERTGUIDE, 323
- TOPMARGIN, 7
- BOTTOMMARGIN, 275
- HORZGUIDE, 12
- HORZGUIDE, 26
- HORZGUIDE, 40
- HORZGUIDE, 47
- HORZGUIDE, 249
- END
-
- IDD_FTDIRNAME_DLG, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 186
- TOPMARGIN, 7
- BOTTOMMARGIN, 56
- END
-
- IDD_FTCONFIRM_DLG, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 181
- TOPMARGIN, 7
- BOTTOMMARGIN, 136
- END
-END
#endif // APSTUDIO_INVOKED
@@ -144,22 +54,57 @@ END
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
-IDI_FTUP ICON DISCARDABLE "ftup.ico"
+IDI_ICON ICON DISCARDABLE "vncviewer.ico"
IDI_FTDIR ICON DISCARDABLE "ftdir.ico"
IDI_FTFILE ICON DISCARDABLE "ftfile.ico"
IDI_FTRELOAD ICON DISCARDABLE "ftreload.ico"
-#endif // English (U.S.) resources
+IDI_FTUP ICON DISCARDABLE "ftup.ico"
+
+#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 4,1,1,0
+ PRODUCTVERSION 4,1,1,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "Comments", "\0"
+ VALUE "CompanyName", "Constantin Kaplinsky\0"
+ VALUE "FileDescription", "TightVNC Viewer for Win32\0"
+ VALUE "FileVersion", "4.1.1\0"
+ VALUE "InternalName", "free4/vncviewer/win\0"
+ VALUE "LegalCopyright", "Copyright (C) 1998-2006 [many holders]\0"
+ VALUE "LegalTrademarks", "TightVNC\0"
+ VALUE "OriginalFilename", "vncviewer.exe\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "TightVNC Viewer\0"
+ VALUE "ProductVersion", "4.1.1\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x809, 1200
+ END
+END
-/////////////////////////////////////////////////////////////////////////////
-// English (U.K.) resources
+#endif // !_MAC
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
-#pragma code_page(1252)
-#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
@@ -171,14 +116,14 @@ STYLE DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION
CAPTION "VNC Viewer : Authentication"
FONT 8, "MS Sans Serif"
BEGIN
- EDITTEXT IDC_USERNAME,75,6,95,14,ES_AUTOHSCROLL
- EDITTEXT IDC_PASSWORD,75,25,95,15,ES_PASSWORD | ES_AUTOHSCROLL |
+ EDITTEXT IDC_USERNAME,85,6,100,14,ES_AUTOHSCROLL
+ EDITTEXT IDC_PASSWORD,85,25,100,15,ES_PASSWORD | ES_AUTOHSCROLL |
ES_WANTRETURN
- DEFPUSHBUTTON "OK",IDOK,181,6,53,14
- PUSHBUTTON "Cancel",IDCANCEL,181,25,53,15
- ICON IDI_ICON,IDI_ICON,7,6,20,20
- LTEXT "Username:",IDC_STATIC,35,6,35,14
- LTEXT "Password:",IDC_STATIC,35,25,35,15
+ DEFPUSHBUTTON "OK",IDOK,190,6,45,14
+ PUSHBUTTON "Cancel",IDCANCEL,190,25,45,15
+ CONTROL 120,IDI_ICON,"Static",SS_BITMAP,7,6,21,20
+ LTEXT "Username:",IDC_STATIC,45,6,35,14
+ LTEXT "Password:",IDC_STATIC,45,25,35,15
END
IDD_CONNECTING_DLG DIALOG DISCARDABLE 0, 0, 185, 47
@@ -186,25 +131,29 @@ STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION
CAPTION "VNC Viewer : Connecting"
FONT 8, "MS Sans Serif"
BEGIN
- PUSHBUTTON "Cancel",IDCANCEL,128,26,50,14,WS_DISABLED
+ PUSHBUTTON "Cancel",IDCANCEL,128,26,50,14
CTEXT "Attempting to connect to host...",IDC_CONNECTING_TEXT,7,
7,171,14,SS_CENTERIMAGE
END
-IDD_CONNECTION_DLG DIALOG DISCARDABLE 0, 0, 241, 54
+IDD_CONNECTION_DLG DIALOG DISCARDABLE 0, 0, 224, 66
STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "VNC Viewer : Connection Details"
FONT 8, "MS Sans Serif"
BEGIN
- COMBOBOX IDC_SERVER_EDIT,70,6,110,234,CBS_DROPDOWN |
+ COMBOBOX IDC_SERVER_EDIT,85,6,105,234,CBS_DROPDOWN |
CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
- PUSHBUTTON "&About...",IDC_ABOUT,15,30,50,17
- PUSHBUTTON "&Options...",IDC_OPTIONS,70,30,50,17
- DEFPUSHBUTTON "OK",IDOK,130,30,50,17
- PUSHBUTTON "Cancel",IDCANCEL,185,30,50,17
- ICON IDI_ICON,IDI_ICON,5,6,20,20
- LTEXT "Server:",IDC_STATIC,35,6,30,14
+ PUSHBUTTON "&About...",IDC_ABOUT,5,45,50,14
+ PUSHBUTTON "&Options...",IDC_OPTIONS,60,45,50,14
+ DEFPUSHBUTTON "OK",IDOK,115,45,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,170,45,48,14
+ CONTROL 120,IDI_ICON,"Static",SS_BITMAP | SS_REALSIZEIMAGE,5,6,
+ 20,20
+ RTEXT "Server:",IDC_STATIC,43,6,37,13,SS_CENTERIMAGE
+ RTEXT "Encryption:",IDC_STATIC,43,24,37,12,SS_CENTERIMAGE
+ COMBOBOX IDC_SECURITY_LEVEL,85,24,105,76,CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_TABSTOP
END
IDD_ABOUT DIALOG DISCARDABLE 0, 0, 249, 92
@@ -214,18 +163,19 @@ CAPTION "About VNC Viewer for Windows"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,195,70,47,15
- ICON IDI_ICON,IDC_STATIC,7,10,20,20
- LTEXT ">appname<",IDC_DESCRIPTION,40,10,125,15
+ CONTROL 120,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,7,
+ 10,33,31
+ LTEXT ">appname<",IDC_DESCRIPTION,46,10,119,15
LTEXT ">version<",IDC_VERSION,165,10,77,15
- LTEXT ">buildtime<",IDC_BUILDTIME,40,25,202,15
- LTEXT ">copyright<",IDC_COPYRIGHT,40,40,202,15
- LTEXT "See http://www.tightvnc.com for more information on TightVNC.",
- IDC_STATIC,40,55,202,15
+ LTEXT ">buildtime<",IDC_BUILDTIME,46,25,196,15
+ LTEXT ">copyright<",IDC_COPYRIGHT,46,40,196,15
+ LTEXT "Visit www.tightvnc.com for more information on TightVNC.",
+ IDC_STATIC,46,55,196,15
END
-IDD_FORMAT DIALOG DISCARDABLE 0, 0, 201, 160
+IDD_FORMAT DIALOG DISCARDABLE 0, 0, 201, 161
STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Color/Encoding"
+CAPTION "Colour && Encoding"
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "&Auto select",IDC_ENCODING_AUTO,"Button",
@@ -269,7 +219,9 @@ BEGIN
IDC_CONN_SHARED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,
10,199,15
CONTROL "Full-screen mode",IDC_FULL_SCREEN,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,7,25,199,15
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,25,99,15
+ CONTROL "Show toolbar",IDC_SHOW_TOOLBAR,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,106,25,100,15
CONTROL "Render cursor locally",IDC_LOCAL_CURSOR,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,7,40,199,15
CONTROL "Allow dynamic desktop resizing",IDC_DESKTOP_RESIZE,
@@ -277,12 +229,12 @@ BEGIN
CONTROL "Only use protocol version 3.3",IDC_PROTOCOL_3_3,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,7,70,199,15
CONTROL "Beep when requested to by the server",IDC_ACCEPT_BELL,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,85,199,14
- CONTROL "Show toolbar by default",IDC_SHOW_TOOLBAR,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,7,100,199,15
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,85,199,15
+ CONTROL "Offer to automatically reconnect",IDC_AUTO_RECONNECT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,199,15
END
-IDD_INPUTS DIALOG DISCARDABLE 0, 0, 186, 138
+IDD_INPUTS DIALOG DISCARDABLE 0, 0, 186, 162
STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Inputs"
FONT 8, "MS Sans Serif"
@@ -291,30 +243,30 @@ BEGIN
BS_AUTOCHECKBOX | WS_TABSTOP,7,10,172,15
CONTROL "Send keyboard events to server",IDC_SEND_KEYS,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,7,25,172,15
- CONTROL "Send system keys (Alt combinations) to server",
- IDC_SEND_SYSKEYS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,
- 40,172,15
CONTROL "Send clipboard changes to server",IDC_CLIENT_CUTTEXT,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,55,172,15
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,40,172,15
CONTROL "Accept clipboard changes from server",
IDC_SERVER_CUTTEXT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
- 7,70,172,15
+ 7,55,172,15
CONTROL "Enable 3-button mouse emulation",IDC_EMULATE3,"Button",
- BS_AUTOCHECKBOX | WS_TABSTOP,7,85,172,15
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,70,172,15
CONTROL "Rate-limit mouse move events",IDC_POINTER_INTERVAL,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,172,14
- LTEXT "Menu key",IDC_STATIC,7,115,98,15,SS_CENTERIMAGE
- COMBOBOX IDC_MENU_KEY,105,115,74,105,CBS_DROPDOWNLIST | CBS_SORT |
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,86,172,14
+ LTEXT "Menu key",IDC_STATIC,7,100,98,15,SS_CENTERIMAGE
+ COMBOBOX IDC_MENU_KEY,105,100,74,105,CBS_DROPDOWNLIST | CBS_SORT |
WS_VSCROLL | WS_TABSTOP
+ CONTROL "Pass special keys directly to server",
+ IDC_DISABLE_WINKEYS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,7,115,172,15
END
-IDD_CONNECTION_INFO DIALOG DISCARDABLE 0, 0, 239, 186
+IDD_CONNECTION_INFO DIALOG DISCARDABLE 0, 0, 239, 199
STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "VNC Connection Info"
FONT 8, "MS Sans Serif"
BEGIN
- DEFPUSHBUTTON "OK",IDOK,182,165,50,14
+ DEFPUSHBUTTON "OK",IDOK,182,178,50,14
LTEXT "Desktop Name:",IDC_STATIC,7,10,73,15
LTEXT "Host:",IDC_STATIC,7,25,73,15
LTEXT "Size:",IDC_STATIC,7,40,73,15
@@ -335,19 +287,83 @@ BEGIN
LTEXT "Last Used Encoding:",IDC_STATIC,7,100,73,15
LTEXT "",IDC_REQUESTED_ENCODING,80,86,152,15
LTEXT "",IDC_LAST_ENCODING,80,100,152,15
+ LTEXT "Static",IDC_INFO_ENCRYPTION,80,160,152,15
+ LTEXT "Encryption:",IDC_STATIC,7,160,73,15
END
-IDD_DEFAULTS DIALOG DISCARDABLE 0, 0, 131, 113
+IDD_DEFAULTS DIALOG DISCARDABLE 0, 0, 217, 87
STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Defaults"
+CAPTION "Load / Save"
FONT 8, "MS Sans Serif"
BEGIN
- PUSHBUTTON "Reload &Defaults",IDC_LOAD_DEFAULTS,7,10,117,15
- PUSHBUTTON "&Save As Defaults",IDC_SAVE_DEFAULTS,7,30,117,15
- PUSHBUTTON "Reload Configuration &File",IDC_LOAD_CONFIG,7,50,117,15
- PUSHBUTTON "Save &Configuration File",IDC_SAVE_CONFIG,7,70,117,15
- PUSHBUTTON "Save Configuration File &As ...",IDC_SAVE_CONFIG_AS,7,
- 90,117,15
+ PUSHBUTTON "&Reload",IDC_LOAD_CONFIG,15,20,85,15
+ PUSHBUTTON "&Save",IDC_SAVE_CONFIG,15,40,85,15
+ PUSHBUTTON "Save &As ...",IDC_SAVE_CONFIG_AS,15,60,85,15
+ PUSHBUTTON "R&eload",IDC_LOAD_DEFAULTS,120,20,85,15
+ PUSHBUTTON "S&ave",IDC_SAVE_DEFAULTS,120,40,85,15
+ GROUPBOX "Configuration File",IDC_STATIC,7,7,100,74
+ GROUPBOX "Defaults",IDC_STATIC,113,7,97,53
+END
+
+IDD_FILETRANSFER_DLG DIALOGEX 0, 0, 530, 282
+STYLE DS_MODALFRAME | DS_CONTEXTHELP | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+EXSTYLE WS_EX_CONTEXTHELP | WS_EX_CONTROLPARENT
+CAPTION "TightVNC File Transfers"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+ CONTROL "List1",IDC_FTLOCALLIST,"SysListView32",LVS_REPORT |
+ LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,7,40,200,196
+ CONTROL "List2",IDC_FTREMOTELIST,"SysListView32",LVS_REPORT |
+ LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,323,40,200,196
+ PUSHBUTTON "Upload Files and Folders",IDC_FTUPLOAD,218,66,94,12,
+ WS_DISABLED
+ PUSHBUTTON "Download Files and Folders",IDC_FTDOWNLOAD,218,85,94,12,
+ WS_DISABLED
+ PUSHBUTTON "Cancel File Transfer",IDC_FTCANCEL,218,167,94,12,
+ WS_DISABLED
+ PUSHBUTTON "Close",IDC_FTCLOSE,218,217,94,12
+ EDITTEXT IDC_FTLOCALPATH,7,20,155,12,ES_AUTOHSCROLL | NOT
+ WS_TABSTOP
+ CTEXT "Local Computer",IDC_FTLOCALLABEL,7,7,200,10
+ PUSHBUTTON "...",IDC_FTLOCALBROWSE,165,20,14,12,NOT WS_TABSTOP
+ PUSHBUTTON "",IDC_FTLOCALUP,179,20,14,12,BS_ICON | NOT WS_TABSTOP
+ PUSHBUTTON "",IDC_FTLOCALRELOAD,193,20,14,12,BS_ICON | NOT
+ WS_TABSTOP
+ CONTROL "Progress1",IDC_FTGENERALPROGRESS,"msctls_progress32",
+ WS_BORDER,55,244,128,10
+ LTEXT "File Transfer",IDC_STATIC,7,245,40,8
+ COMBOBOX IDC_FTSTATUS,7,263,516,65,CBS_DROPDOWNLIST |
+ CBS_NOINTEGRALHEIGHT | WS_VSCROLL
+ CONTROL "Progress1",IDC_FTSINGLEPROGRESS,"msctls_progress32",
+ WS_BORDER,370,244,128,10
+ EDITTEXT IDC_FTREMOTEPATH,323,20,155,12,ES_AUTOHSCROLL | NOT
+ WS_TABSTOP
+ PUSHBUTTON "...",IDC_FTREMOTEBROWSE,481,20,14,12,NOT WS_TABSTOP
+ PUSHBUTTON "",IDC_FTREMOTEUP,495,20,14,12,BS_ICON | NOT WS_TABSTOP
+ PUSHBUTTON "",IDC_FTREMOTERELOAD,509,20,14,12,BS_ICON | NOT
+ WS_TABSTOP
+ CTEXT "TightVNC Server",IDC_FTREMOTELABEL,323,7,200,10
+ LTEXT "Current File",IDC_STATIC,323,245,36,8
+ CTEXT "0%",IDC_FTGENERALPERCENT,189,245,18,8
+ CTEXT "0%",IDC_FTSINGLEPERCENT,505,245,18,8
+END
+
+IDD_FTBROWSE DIALOGEX 0, 0, 183, 196
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Browse Folders"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,38,175,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,95,175,50,14
+ EDITTEXT IDC_FTBROWSEPATH,7,7,169,12,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_TABSTOP
+ CONTROL "Tree1",IDC_FTBROWSETREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP |
+ TVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,7,25,169,143
END
IDD_FTCANCELING DIALOG DISCARDABLE 0, 0, 193, 63
@@ -361,30 +377,25 @@ BEGIN
IDC_STATIC,42,14,133,19
END
-IDD_FTCREATEFOLDER DIALOG DISCARDABLE 0, 0, 193, 63
+IDD_FTCONFIRM_DLG DIALOG DISCARDABLE 0, 0, 188, 143
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Create a New Folder"
FONT 8, "MS Sans Serif"
BEGIN
- EDITTEXT IDC_FTFOLDERNAME,7,19,179,14,ES_AUTOHSCROLL
- DEFPUSHBUTTON "OK",IDOK,80,42,50,14
- PUSHBUTTON "Cancel",IDCANCEL,136,42,50,14
- LTEXT "New Folder Name",IDC_FTTEXT,7,7,179,8
+ DEFPUSHBUTTON "Yes",IDOK,69,122,50,14,WS_GROUP
+ PUSHBUTTON "No",IDCANCEL,131,122,50,14
+ PUSHBUTTON "Yes to All",IDC_CONFIRM_YESTOALL,7,122,50,14
+ LTEXT "Static",IDC_CONFIRM_TEXT,7,7,174,107
END
-IDD_FTBROWSE DIALOGEX 0, 0, 183, 196
+IDD_FTCREATEFOLDER DIALOG DISCARDABLE 0, 0, 193, 63
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_CONTROLPARENT
-CAPTION "Browse Folders"
+CAPTION "Create a New Folder"
FONT 8, "MS Sans Serif"
BEGIN
- DEFPUSHBUTTON "OK",IDOK,38,175,50,14
- PUSHBUTTON "Cancel",IDCANCEL,95,175,50,14
- EDITTEXT IDC_FTBROWSEPATH,7,7,169,12,ES_AUTOHSCROLL | ES_READONLY |
- NOT WS_TABSTOP
- CONTROL "Tree1",IDC_FTBROWSETREE,"SysTreeView32",TVS_HASBUTTONS |
- TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP |
- TVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,7,25,169,143
+ EDITTEXT IDC_FTFOLDERNAME,7,19,179,14,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,80,42,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,136,42,50,14
+ LTEXT "New folder name:",IDC_FTTEXT,7,7,179,8
END
@@ -399,10 +410,12 @@ BEGIN
IDD_VNC_AUTH_DLG, DIALOG
BEGIN
LEFTMARGIN, 7
- RIGHTMARGIN, 234
- VERTGUIDE, 35
- VERTGUIDE, 70
- VERTGUIDE, 75
+ RIGHTMARGIN, 235
+ VERTGUIDE, 45
+ VERTGUIDE, 80
+ VERTGUIDE, 85
+ VERTGUIDE, 185
+ VERTGUIDE, 190
TOPMARGIN, 6
BOTTOMMARGIN, 40
HORZGUIDE, 20
@@ -423,27 +436,31 @@ BEGIN
IDD_CONNECTION_DLG, DIALOG
BEGIN
LEFTMARGIN, 5
- RIGHTMARGIN, 235
- VERTGUIDE, 15
- VERTGUIDE, 35
- VERTGUIDE, 65
- VERTGUIDE, 70
- VERTGUIDE, 120
- VERTGUIDE, 130
- VERTGUIDE, 180
- VERTGUIDE, 185
+ RIGHTMARGIN, 218
+ VERTGUIDE, 30
+ VERTGUIDE, 43
+ VERTGUIDE, 55
+ VERTGUIDE, 60
+ VERTGUIDE, 80
+ VERTGUIDE, 85
+ VERTGUIDE, 110
+ VERTGUIDE, 115
+ VERTGUIDE, 165
+ VERTGUIDE, 170
+ VERTGUIDE, 190
TOPMARGIN, 6
- BOTTOMMARGIN, 47
- HORZGUIDE, 20
- HORZGUIDE, 30
- HORZGUIDE, 40
+ BOTTOMMARGIN, 59
+ HORZGUIDE, 19
+ HORZGUIDE, 24
+ HORZGUIDE, 36
+ HORZGUIDE, 45
END
IDD_ABOUT, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 242
- VERTGUIDE, 40
+ VERTGUIDE, 46
VERTGUIDE, 165
VERTGUIDE, 195
TOPMARGIN, 7
@@ -467,7 +484,7 @@ BEGIN
VERTGUIDE, 105
VERTGUIDE, 190
TOPMARGIN, 7
- BOTTOMMARGIN, 94
+ BOTTOMMARGIN, 154
HORZGUIDE, 10
HORZGUIDE, 20
HORZGUIDE, 25
@@ -482,6 +499,7 @@ BEGIN
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 206
+ VERTGUIDE, 106
TOPMARGIN, 7
BOTTOMMARGIN, 130
HORZGUIDE, 10
@@ -492,6 +510,7 @@ BEGIN
HORZGUIDE, 85
HORZGUIDE, 100
HORZGUIDE, 115
+ HORZGUIDE, 130
END
IDD_INPUTS, DIALOG
@@ -500,7 +519,7 @@ BEGIN
RIGHTMARGIN, 179
VERTGUIDE, 105
TOPMARGIN, 7
- BOTTOMMARGIN, 131
+ BOTTOMMARGIN, 155
HORZGUIDE, 10
HORZGUIDE, 25
HORZGUIDE, 40
@@ -509,6 +528,8 @@ BEGIN
HORZGUIDE, 85
HORZGUIDE, 100
HORZGUIDE, 115
+ HORZGUIDE, 130
+ HORZGUIDE, 145
END
IDD_CONNECTION_INFO, DIALOG
@@ -517,7 +538,7 @@ BEGIN
RIGHTMARGIN, 232
VERTGUIDE, 80
TOPMARGIN, 7
- BOTTOMMARGIN, 179
+ BOTTOMMARGIN, 192
HORZGUIDE, 10
HORZGUIDE, 25
HORZGUIDE, 40
@@ -529,132 +550,78 @@ BEGIN
HORZGUIDE, 130
HORZGUIDE, 145
HORZGUIDE, 160
+ HORZGUIDE, 175
END
IDD_DEFAULTS, DIALOG
BEGIN
LEFTMARGIN, 7
- RIGHTMARGIN, 124
+ RIGHTMARGIN, 210
+ VERTGUIDE, 15
+ VERTGUIDE, 100
+ VERTGUIDE, 107
+ VERTGUIDE, 113
+ VERTGUIDE, 120
+ VERTGUIDE, 205
TOPMARGIN, 7
- BOTTOMMARGIN, 106
- HORZGUIDE, 10
- HORZGUIDE, 25
- HORZGUIDE, 30
- HORZGUIDE, 45
- HORZGUIDE, 50
- HORZGUIDE, 65
- HORZGUIDE, 70
- HORZGUIDE, 85
- HORZGUIDE, 90
- HORZGUIDE, 105
+ BOTTOMMARGIN, 80
+ HORZGUIDE, 20
+ HORZGUIDE, 35
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 60
+ HORZGUIDE, 75
END
- IDD_FTCANCELING, DIALOG
+ IDD_FILETRANSFER_DLG, DIALOG
BEGIN
LEFTMARGIN, 7
- RIGHTMARGIN, 186
+ RIGHTMARGIN, 523
+ VERTGUIDE, 207
+ VERTGUIDE, 265
+ VERTGUIDE, 323
TOPMARGIN, 7
- BOTTOMMARGIN, 56
+ BOTTOMMARGIN, 275
+ HORZGUIDE, 12
+ HORZGUIDE, 26
+ HORZGUIDE, 40
+ HORZGUIDE, 47
+ HORZGUIDE, 249
END
- IDD_FTCREATEFOLDER, DIALOG
+ IDD_FTBROWSE, DIALOG
BEGIN
LEFTMARGIN, 7
- RIGHTMARGIN, 186
+ RIGHTMARGIN, 176
TOPMARGIN, 7
- BOTTOMMARGIN, 56
+ BOTTOMMARGIN, 189
END
- IDD_FTBROWSE, DIALOG
+ IDD_FTCANCELING, DIALOG
BEGIN
LEFTMARGIN, 7
- RIGHTMARGIN, 176
+ RIGHTMARGIN, 186
TOPMARGIN, 7
- BOTTOMMARGIN, 189
+ BOTTOMMARGIN, 56
END
-END
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDI_ICON ICON DISCARDABLE "vncviewer.ico"
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE DISCARDABLE
-BEGIN
- "resource.h\0"
-END
-
-2 TEXTINCLUDE DISCARDABLE
-BEGIN
- "#include ""afxres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE DISCARDABLE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-#ifndef _MAC
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION 4,0,0,26
- PRODUCTVERSION 4,0,0,26
- FILEFLAGSMASK 0x3fL
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x40004L
- FILETYPE 0x1L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
+ IDD_FTCONFIRM_DLG, DIALOG
BEGIN
- BLOCK "080904b0"
- BEGIN
- VALUE "Comments", "\0"
- VALUE "CompanyName", "Constantin Kaplinsky\0"
- VALUE "FileDescription", "TightVNC Viewer for Win32\0"
- VALUE "FileVersion", "4.0\0"
- VALUE "InternalName", "VNCViewer 4.0\0"
- VALUE "LegalCopyright", "Copyright (C) 1998-2004 [many holders]\0"
- VALUE "LegalTrademarks", "TightVNC\0"
- VALUE "OriginalFilename", "vncviewer.exe\0"
- VALUE "PrivateBuild", "\0"
- VALUE "ProductName", "TightVNC Viewer 4.0\0"
- VALUE "ProductVersion", "4.0\0"
- VALUE "SpecialBuild", "\0"
- END
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 181
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 136
END
- BLOCK "VarFileInfo"
+
+ IDD_FTCREATEFOLDER, DIALOG
BEGIN
- VALUE "Translation", 0x809, 1200
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 186
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 56
END
END
-
-#endif // !_MAC
+#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
@@ -722,6 +689,7 @@ IDR_MANIFEST 24 DISCARDABLE "vncviewer.exe.manifest"
// Bitmap
//
+IDB_BITMAP BITMAP DISCARDABLE "vncviewer.bmp"
IDB_TOOLBAR BITMAP DISCARDABLE "toolbar.bmp"
#endif // English (U.K.) resources
/////////////////////////////////////////////////////////////////////////////