summaryrefslogtreecommitdiffstats
path: root/vncviewer
diff options
context:
space:
mode:
authorConstantin Kaplinsky <const@tightvnc.com>2004-10-08 09:43:57 +0000
committerConstantin Kaplinsky <const@tightvnc.com>2004-10-08 09:43:57 +0000
commit47ed8d321c32c6b741cff1f4ff686165c4f269f4 (patch)
treeda413648adbff4ff10c8ee26124673f8e7cf238a /vncviewer
parent266bb36cd47555280fffd3aab1ed86683e26d748 (diff)
downloadtigervnc-47ed8d321c32c6b741cff1f4ff686165c4f269f4.tar.gz
tigervnc-47ed8d321c32c6b741cff1f4ff686165c4f269f4.zip
Initial revision
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'vncviewer')
-rw-r--r--vncviewer/CViewManager.cxx252
-rw-r--r--vncviewer/CViewManager.h64
-rw-r--r--vncviewer/CViewOptions.cxx364
-rw-r--r--vncviewer/CViewOptions.h87
-rw-r--r--vncviewer/ConnectingDialog.h95
-rw-r--r--vncviewer/ConnectionDialog.cxx70
-rw-r--r--vncviewer/ConnectionDialog.h52
-rw-r--r--vncviewer/InfoDialog.cxx65
-rw-r--r--vncviewer/InfoDialog.h48
-rw-r--r--vncviewer/MRU.h140
-rw-r--r--vncviewer/OptionsDialog.cxx309
-rw-r--r--vncviewer/OptionsDialog.h49
-rw-r--r--vncviewer/UserPasswdDialog.cxx84
-rw-r--r--vncviewer/UserPasswdDialog.h54
-rw-r--r--vncviewer/buildTime.cxx1
-rw-r--r--vncviewer/cursor1.curbin0 -> 326 bytes
-rw-r--r--vncviewer/cview.cxx1468
-rw-r--r--vncviewer/cview.h296
-rw-r--r--vncviewer/msvcwarning.h19
-rw-r--r--vncviewer/resource.h80
-rw-r--r--vncviewer/vncviewer.cxx370
-rw-r--r--vncviewer/vncviewer.dsp229
-rw-r--r--vncviewer/vncviewer.exe.manifest22
-rw-r--r--vncviewer/vncviewer.icobin0 -> 8478 bytes
-rw-r--r--vncviewer/vncviewer.rc500
25 files changed, 4718 insertions, 0 deletions
diff --git a/vncviewer/CViewManager.cxx b/vncviewer/CViewManager.cxx
new file mode 100644
index 00000000..09ed1fe8
--- /dev/null
+++ b/vncviewer/CViewManager.cxx
@@ -0,0 +1,252 @@
+/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <winsock2.h>
+#include <vncviewer/CViewManager.h>
+#include <vncviewer/CView.h>
+#include <vncviewer/ConnectionDialog.h>
+#include <vncviewer/ConnectingDialog.h>
+#include <rfb/Hostname.h>
+#include <rfb/util.h>
+#include <rfb/LogWriter.h>
+#include <rfb/vncAuth.h>
+#include <rdr/HexInStream.h>
+#include <network/TcpSocket.h>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("CViewManager");
+
+
+// -=- Custom thread class used internally
+
+class CViewThread : public Thread {
+public:
+ CViewThread(network::Socket* s, CViewManager& cvm);
+ CViewThread(const char* conninfo, CViewManager& cvm, bool infoIsConfigFile);
+ virtual ~CViewThread();
+
+ virtual void run();
+protected:
+ void setSocket(network::Socket* sock);
+
+ network::Socket* sock;
+ CharArray hostname;
+ CViewManager& manager;
+
+ bool useConfigFile;
+};
+
+
+CViewThread::CViewThread(network::Socket* s, CViewManager& cvm)
+: Thread("CView"), sock(s), manager(cvm) {
+ setDeleteAfterRun();
+}
+
+CViewThread::CViewThread(const char* h, CViewManager& cvm, bool hIsConfigFile)
+: Thread("CView"), sock(0), manager(cvm), useConfigFile(hIsConfigFile) {
+ setDeleteAfterRun();
+ if (h) hostname.buf = strDup(h);
+}
+
+
+CViewThread::~CViewThread() {
+ vlog.debug("~CViewThread");
+ manager.remThread(this);
+ delete sock;
+}
+
+
+void CViewThread::run() {
+ try {
+ CView view;
+ view.setManager(&manager);
+
+ if (!sock) {
+ try {
+ // If the hostname is actually a config filename then read it
+ if (useConfigFile) {
+ CharArray filename = hostname.takeBuf();
+ CViewOptions options;
+ options.readFromFile(filename.buf);
+ if (options.host.buf)
+ hostname.buf = strDup(options.host.buf);
+ view.applyOptions(options);
+ }
+
+ // If there is no hostname then present the connection
+ // dialog
+ if (!hostname.buf) {
+ ConnectionDialog conn(&view);
+ if (!conn.showDialog())
+ return;
+ hostname.buf = strDup(conn.hostname.buf);
+
+ // *** hack - Tell the view object the hostname
+ CViewOptions opt(view.getOptions());
+ opt.setHost(hostname.buf);
+ view.applyOptions(opt);
+ }
+
+ // Parse the host name & port
+ CharArray host;
+ int port;
+ getHostAndPort(hostname.buf, &host.buf, &port);
+
+ // Attempt to connect
+ ConnectingDialog dlg;
+ // this is a nasty hack to get round a Win2K and later "feature" which
+ // puts your second window in the background unless the first window
+ // you put up actually gets some input. Just generate a fake shift
+ // event, which seems to do the trick.
+ keybd_event(VK_SHIFT, MapVirtualKey(VK_SHIFT, 0), 0, 0);
+ keybd_event(VK_SHIFT, MapVirtualKey(VK_SHIFT, 0), KEYEVENTF_KEYUP, 0);
+ sock = new network::TcpSocket(host.buf, port);
+ } catch(rdr::Exception& e) {
+ vlog.error("unable to connect to %s (%s)", hostname, e.str());
+ MsgBox(NULL, TStr(e.str()), MB_ICONERROR | MB_OK);
+ return;
+ }
+
+ // Try to add the caller to the MRU
+ MRU::addToMRU(hostname.buf);
+ }
+
+ view.initialise(sock);
+ try {
+ view.postQuitOnDestroy(true);
+ while (true) {
+ // - processMsg is designed to be callable in response to select().
+ // As a result, it can be called when FdInStream data is available,
+ // BUT there may be no actual RFB data available. This is the case
+ // for example when reading data over an encrypted stream - an
+ // entire block must be read from the FdInStream before any data
+ // becomes available through the top-level encrypted stream.
+ // Since we are using blockCallback and not doing a select() here,
+ // we simply check() for some data on the top-level RFB stream.
+ // This ensures that processMsg will only be called when there is
+ // actually something to do. In the meantime, blockCallback()
+ // will be called, keeping the user interface responsive.
+ view.getInStream()->check(1,1);
+ view.processMsg();
+ }
+ } catch (CView::QuitMessage& e) {
+ // - Cope silently with WM_QUIT messages
+ vlog.debug("QuitMessage received (wParam=%d)", e.wParam);
+ } catch (rdr::EndOfStream& e) {
+ // - Copy silently with disconnection if in NORMAL state
+ if (view.state() == CConnection::RFBSTATE_NORMAL)
+ vlog.debug(e.str());
+ else {
+ view.postQuitOnDestroy(false);
+ throw rfb::Exception("server closed connection unexpectedly");
+ }
+ } catch (rdr::Exception&) {
+ // - We MUST do this, otherwise ~CView will cause a
+ // PostQuitMessage and any MessageBox call will quit immediately.
+ view.postQuitOnDestroy(false);
+ throw;
+ }
+ } catch(rdr::Exception& e) {
+ // - Something went wrong - display the error
+ vlog.error("error: %s", e.str());
+ MsgBox(NULL, TStr(e.str()), MB_ICONERROR | MB_OK);
+ }
+}
+
+
+// -=- CViewManager itself
+
+CViewManager::CViewManager()
+: MsgWindow(_T("CViewManager")), threadsSig(threadsMutex),
+ mainThread(Thread::self()) {
+}
+
+CViewManager::~CViewManager() {
+ while (!socks.empty()) {
+ network::SocketListener* sock = socks.front();
+ delete sock;
+ socks.pop_front();
+ }
+ awaitEmpty();
+}
+
+
+void CViewManager::awaitEmpty() {
+ Lock l(threadsMutex);
+ while (!threads.empty()) {
+ threadsSig.wait(true);
+ }
+}
+
+
+void CViewManager::addThread(Thread* t) {
+ Lock l(threadsMutex);
+ threads.push_front(t);
+}
+
+void CViewManager::remThread(Thread* t) {
+ Lock l(threadsMutex);
+ threads.remove(t);
+ threadsSig.signal();
+
+ // If there are no listening sockets then post a quit message when the
+ // last client disconnects
+ if (socks.empty())
+ PostThreadMessage(mainThread->getThreadId(), WM_QUIT, 0, 0);
+}
+
+
+bool CViewManager::addClient(const char* hostinfo, bool isConfigFile) {
+ CViewThread* thread = new CViewThread(hostinfo, *this, isConfigFile);
+ addThread(thread);
+ thread->start();
+ return true;
+}
+
+bool CViewManager::addListener(network::SocketListener* sock) {
+ socks.push_back(sock);
+ WSAAsyncSelect(sock->getFd(), getHandle(), WM_USER, FD_ACCEPT);
+ return true;
+}
+
+bool CViewManager::addDefaultTCPListener(int port) {
+ return addListener(new network::TcpListener(port));
+}
+
+
+LRESULT CViewManager::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch (msg) {
+ case WM_USER:
+ std::list<network::SocketListener*>::iterator i;
+ for (i=socks.begin(); i!=socks.end(); i++) {
+ if (wParam == (*i)->getFd()) {
+ network::Socket* new_sock = (*i)->accept();
+ CharArray connname;
+ connname.buf = new_sock->getPeerEndpoint();
+ vlog.debug("accepted connection: %s", connname);
+ CViewThread* thread = new CViewThread(new_sock, *this);
+ addThread(thread);
+ thread->start();
+ break;
+ }
+ }
+ break;
+ }
+ return MsgWindow::processMessage(msg, wParam, lParam);
+}
diff --git a/vncviewer/CViewManager.h b/vncviewer/CViewManager.h
new file mode 100644
index 00000000..3d11dd96
--- /dev/null
+++ b/vncviewer/CViewManager.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- CViewManager.h
+
+// Creates and manages threads to run CView instances.
+
+#ifndef __RFB_WIN32_CVIEW_MANAGER_H__
+#define __RFB_WIN32_CVIEW_MANAGER_H__
+
+#include <list>
+#include <network/Socket.h>
+#include <rfb/Threading.h>
+#include <rfb_win32/MsgWindow.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class CViewManager : public MsgWindow {
+ public:
+ CViewManager();
+ ~CViewManager();
+
+ void awaitEmpty();
+
+ void addThread(Thread* t);
+ void remThread(Thread* t);
+
+ bool addClient(const char* hostinfo, bool isConfigFile=false);
+
+ bool addListener(network::SocketListener* sock);
+ bool addDefaultTCPListener(int port);
+
+ LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+ protected:
+ std::list<network::SocketListener*> socks;
+ std::list<Thread*> threads;
+ Mutex threadsMutex;
+ Condition threadsSig;
+ Thread* mainThread;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/vncviewer/CViewOptions.cxx b/vncviewer/CViewOptions.cxx
new file mode 100644
index 00000000..089c4c43
--- /dev/null
+++ b/vncviewer/CViewOptions.cxx
@@ -0,0 +1,364 @@
+/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <vncviewer/CViewOptions.h>
+#include <rfb/Configuration.h>
+#include <rfb/encodings.h>
+#include <rfb/vncAuth.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/Win32Util.h>
+#include <rfb_win32/Registry.h>
+#include <rdr/HexInStream.h>
+#include <rdr/HexOutStream.h>
+#include <stdlib.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+static BoolParameter useLocalCursor("UseLocalCursor", "Render the mouse cursor locally", true);
+static BoolParameter useDesktopResize("UseDesktopResize", "Support dynamic desktop resizing", true);
+
+static BoolParameter fullColour("FullColour",
+ "Use full colour (default is to use low colour "
+ "unless auto select decides the link is fast enough)",
+ false);
+static IntParameter lowColourLevel("LowColourLevel",
+ "Colour level to use on slow connections. "
+ "0 = Very Low (8 colours), 1 = Low (64 colours), 2 = Medium (256 colours)",
+ 1);
+static BoolParameter fullScreen("FullScreen",
+ "Use the whole display to show the remote desktop."
+ "(Press F8 to access the viewer menu)",
+ false);
+static StringParameter preferredEncoding("PreferredEncoding",
+ "Preferred graphical encoding to use - overridden by AutoSelect if set. "
+ "(ZRLE, Hextile or Raw)", "ZRLE");
+
+static BoolParameter autoSelect("AutoSelect", "Auto select pixel format and encoding", true);
+static BoolParameter sharedConnection("Shared",
+ "Allow existing connections to the server to continue."
+ "(Default is to disconnect all other clients)",
+ false);
+
+static BoolParameter sendPtrEvents("SendPointerEvents",
+ "Send pointer (mouse) events to the server.", true);
+static BoolParameter sendKeyEvents("SendKeyEvents",
+ "Send key presses (and releases) to the server.", true);
+
+static BoolParameter clientCutText("ClientCutText",
+ "Send clipboard changes to the server.", true);
+static BoolParameter serverCutText("ServerCutText",
+ "Accept clipboard changes from the server.", true);
+
+static BoolParameter protocol3_3("Protocol3.3",
+ "Only use protocol version 3.3", false);
+
+static IntParameter ptrEventInterval("PointerEventInterval",
+ "The interval to delay between sending one pointer event "
+ "and the next.", 0);
+static BoolParameter emulate3("Emulate3",
+ "Emulate middle mouse button when left and right buttons "
+ "are used simulatenously.", false);
+
+static BoolParameter acceptBell("AcceptBell",
+ "Produce a system beep when requested to by the server.",
+ true);
+
+static 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");
+
+
+CViewOptions::CViewOptions()
+: useLocalCursor(::useLocalCursor), useDesktopResize(::useDesktopResize),
+autoSelect(::autoSelect), fullColour(::fullColour), fullScreen(::fullScreen),
+shared(::sharedConnection), sendPtrEvents(::sendPtrEvents), sendKeyEvents(::sendKeyEvents),
+preferredEncoding(encodingZRLE), clientCutText(::clientCutText), serverCutText(::serverCutText),
+protocol3_3(::protocol3_3), acceptBell(::acceptBell), lowColourLevel(::lowColourLevel),
+pointerEventInterval(ptrEventInterval), emulate3(::emulate3), monitor(::monitor.getData())
+{
+ CharArray encodingName(::preferredEncoding.getData());
+ preferredEncoding = encodingNum(encodingName.buf);
+ setMenuKey(CharArray(::menuKey.getData()).buf);
+}
+
+
+void CViewOptions::readFromFile(const char* filename) {
+ FILE* f = fopen(filename, "r");
+ if (!f)
+ throw rdr::Exception("Failed to read configuration file");
+
+ try {
+ char line[4096];
+ CharArray section;
+
+ CharArray hostTmp;
+ int portTmp = 0;
+
+ while (!feof(f)) {
+ // Read the next line
+ if (!fgets(line, sizeof(line), f)) {
+ if (feof(f))
+ break;
+ throw rdr::SystemException("fgets", ferror(f));
+ }
+ int len=strlen(line);
+ if (line[len-1] == '\n') {
+ line[len-1] = 0;
+ len--;
+ }
+
+ // Process the line
+ if (line[0] == ';') {
+ // Comment
+ } else if (line[0] == '[') {
+ // Entering a new section
+ if (!strSplit(&line[1], ']', &section.buf, 0))
+ throw rdr::Exception("bad Section");
+ } else {
+ // Reading an option
+ CharArray name;
+ CharArray value;
+ if (!strSplit(line, '=', &name.buf, &value.buf))
+ throw rdr::Exception("bad Name/Value pair");
+
+ if (stricmp(section.buf, "Connection") == 0) {
+ if (stricmp(name.buf, "Host") == 0) {
+ hostTmp.replaceBuf(value.takeBuf());
+ } else if (stricmp(name.buf, "Port") == 0) {
+ portTmp = atoi(value.buf);
+ } else if (stricmp(name.buf, "UserName") == 0) {
+ userName.replaceBuf(value.takeBuf());
+ } else if (stricmp(name.buf, "Password") == 0) {
+ int len = 0;
+ CharArray obfuscated;
+ rdr::HexInStream::hexStrToBin(value.buf, &obfuscated.buf, &len);
+ if (len == 8) {
+ password.replaceBuf(new char[9]);
+ memcpy(password.buf, obfuscated.buf, 8);
+ vncAuthUnobfuscatePasswd(password.buf);
+ password.buf[8] = 0;
+ }
+ }
+ } else if (stricmp(section.buf, "Options") == 0) {
+ // V4 options
+ if (stricmp(name.buf, "UseLocalCursor") == 0) {
+ useLocalCursor = atoi(value.buf);
+ } else if (stricmp(name.buf, "UseDesktopResize") == 0) {
+ useDesktopResize = atoi(value.buf);
+ } else if (stricmp(name.buf, "FullScreen") == 0) {
+ fullScreen = atoi(value.buf);
+ } else if (stricmp(name.buf, "FullColour") == 0) {
+ fullColour = atoi(value.buf);
+ } else if (stricmp(name.buf, "LowColourLevel") == 0) {
+ lowColourLevel = atoi(value.buf);
+ } else if (stricmp(name.buf, "PreferredEncoding") == 0) {
+ preferredEncoding = encodingNum(value.buf);
+ } else if ((stricmp(name.buf, "AutoDetect") == 0) ||
+ (stricmp(name.buf, "AutoSelect") == 0)) {
+ autoSelect = atoi(value.buf);
+ } else if (stricmp(name.buf, "Shared") == 0) {
+ shared = atoi(value.buf);
+ } else if (stricmp(name.buf, "SendPtrEvents") == 0) {
+ sendPtrEvents = atoi(value.buf);
+ } else if (stricmp(name.buf, "SendKeyEvents") == 0) {
+ sendKeyEvents = atoi(value.buf);
+ } else if (stricmp(name.buf, "SendCutText") == 0) {
+ clientCutText = atoi(value.buf);
+ } else if (stricmp(name.buf, "AcceptCutText") == 0) {
+ serverCutText = atoi(value.buf);
+ } else if (stricmp(name.buf, "Emulate3") == 0) {
+ emulate3 = atoi(value.buf);
+ } else if (stricmp(name.buf, "PointerEventInterval") == 0) {
+ pointerEventInterval = atoi(value.buf);
+ } else if (stricmp(name.buf, "Monitor") == 0) {
+ monitor.replaceBuf(value.takeBuf());
+ } else if (stricmp(name.buf, "MenuKey") == 0) {
+ setMenuKey(value.buf);
+
+ // Legacy options
+ } else if (stricmp(name.buf, "Preferred_Encoding") == 0) {
+ preferredEncoding = atoi(value.buf);
+ } else if (stricmp(name.buf, "8bit") == 0) {
+ fullColour = !atoi(value.buf);
+ } else if (stricmp(name.buf, "FullScreen") == 0) {
+ fullScreen = atoi(value.buf);
+ } else if (stricmp(name.buf, "ViewOnly") == 0) {
+ sendPtrEvents = sendKeyEvents = !atoi(value.buf);
+ } else if (stricmp(name.buf, "DisableClipboard") == 0) {
+ clientCutText = serverCutText = !atoi(value.buf);
+ }
+ }
+ }
+ }
+ fclose(f); f=0;
+
+ // Process the Host and Port
+ if (hostTmp.buf) {
+ int hostLen = strlen(hostTmp.buf) + 2 + 17;
+ host.replaceBuf(new char[hostLen]);
+ strCopy(host.buf, hostTmp.buf, hostLen);
+ if (portTmp) {
+ strncat(host.buf, "::", hostLen-1);
+ char tmp[16];
+ sprintf(tmp, "%d", portTmp);
+ strncat(host.buf, tmp, hostLen-1);
+ }
+ }
+
+ setConfigFileName(filename);
+ } catch (rdr::Exception&) {
+ if (f) fclose(f);
+ throw;
+ }
+}
+
+void CViewOptions::writeToFile(const char* filename) {
+ FILE* f = fopen(filename, "w");
+ if (!f)
+ throw rdr::Exception("Failed to write configuration file");
+
+ try {
+ // - Split server into host and port and save
+ fprintf(f, "[Connection]\n");
+
+ fprintf(f, "Host=%s\n", host.buf);
+ if (userName.buf)
+ fprintf(f, "UserName=%s\n", userName.buf);
+ if (password.buf) {
+ // - Warn the user before saving the password
+ if (MsgBox(0, _T("Do you want to include the VNC Password in this configuration file?\n")
+ _T("Storing the password is more convenient but poses a security risk."),
+ MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) == IDYES) {
+ char obfuscated[9];
+ memset(obfuscated, 0, sizeof(obfuscated));
+ strCopy(obfuscated, password.buf, sizeof(obfuscated));
+ vncAuthObfuscatePasswd(obfuscated);
+ CharArray obfuscatedHex = rdr::HexOutStream::binToHexStr(obfuscated, 8);
+ fprintf(f, "Password=%s\n", obfuscatedHex.buf);
+ }
+ }
+
+ // - Save the other options
+ fprintf(f, "[Options]\n");
+
+ fprintf(f, "UseLocalCursor=%d\n", (int)useLocalCursor);
+ fprintf(f, "UseDesktopResize=%d\n", (int)useDesktopResize);
+ fprintf(f, "FullScreen=%d\n", (int)fullScreen);
+ fprintf(f, "FullColour=%d\n", (int)fullColour);
+ fprintf(f, "LowColourLevel=%d\n", lowColourLevel);
+ fprintf(f, "PreferredEncoding=%s\n", encodingName(preferredEncoding));
+ fprintf(f, "AutoSelect=%d\n", (int)autoSelect);
+ fprintf(f, "Shared=%d\n", (int)shared);
+ fprintf(f, "SendPtrEvents=%d\n", (int)sendPtrEvents);
+ fprintf(f, "SendKeyEvents=%d\n", (int)sendKeyEvents);
+ fprintf(f, "SendCutText=%d\n", (int)clientCutText);
+ fprintf(f, "AcceptCutText=%d\n", (int)serverCutText);
+ fprintf(f, "Emulate3=%d\n", (int)emulate3);
+ fprintf(f, "PointerEventInterval=%d\n", pointerEventInterval);
+ if (monitor.buf)
+ fprintf(f, "Monitor=%s\n", monitor.buf);
+ fprintf(f, "MenuKey=%s\n", CharArray(menuKeyName()).buf);
+ fclose(f); f=0;
+
+ setConfigFileName(filename);
+ } catch (rdr::Exception&) {
+ if (f) fclose(f);
+ throw;
+ }
+}
+
+
+void CViewOptions::writeDefaults() {
+ RegKey key;
+ key.createKey(HKEY_CURRENT_USER, _T("Software\\RealVNC\\VNCviewer4"));
+ key.setBool(_T("UseLocalCursor"), useLocalCursor);
+ key.setBool(_T("UseDesktopResize"), useDesktopResize);
+ key.setBool(_T("FullScreen"), fullScreen);
+ key.setBool(_T("FullColour"), fullColour);
+ key.setInt(_T("LowColourLevel"), lowColourLevel);
+ key.setString(_T("PreferredEncoding"), TStr(encodingName(preferredEncoding)));
+ key.setBool(_T("AutoSelect"), autoSelect);
+ key.setBool(_T("Shared"), shared);
+ key.setBool(_T("SendPointerEvents"), sendPtrEvents);
+ key.setBool(_T("SendKeyEvents"), sendKeyEvents);
+ key.setBool(_T("ClientCutText"), clientCutText);
+ key.setBool(_T("ServerCutText"), serverCutText);
+ key.setBool(_T("Protocol3.3"), protocol3_3);
+ key.setBool(_T("AcceptBell"), acceptBell);
+ key.setBool(_T("Emulate3"), emulate3);
+ key.setInt(_T("PointerEventInterval"), pointerEventInterval);
+ if (monitor.buf)
+ key.setString(_T("Monitor"), TStr(monitor.buf));
+ key.setString(_T("MenuKey"), TCharArray(menuKeyName()).buf);
+}
+
+
+void CViewOptions::setUserName(const char* user) {userName.replaceBuf(strDup(user));}
+void CViewOptions::setPassword(const char* pwd) {password.replaceBuf(strDup(pwd));}
+void CViewOptions::setConfigFileName(const char* cfn) {configFileName.replaceBuf(strDup(cfn));}
+void CViewOptions::setHost(const char* h) {host.replaceBuf(strDup(h));}
+void CViewOptions::setMonitor(const char* m) {monitor.replaceBuf(strDup(m));}
+
+void CViewOptions::setMenuKey(const char* keyName) {
+ if (!keyName[0]) {
+ menuKey = 0;
+ } else {
+ menuKey = VK_F8;
+ if (keyName[0] == 'F') {
+ UINT fKey = atoi(&keyName[1]);
+ if (fKey >= 1 && fKey <= 12)
+ menuKey = fKey-1 + VK_F1;
+ }
+ }
+}
+char* CViewOptions::menuKeyName() {
+ int fNum = (menuKey-VK_F1)+1;
+ if (fNum<1 || fNum>12)
+ return strDup("");
+ CharArray menuKeyStr(4);
+ sprintf(menuKeyStr.buf, "F%d", fNum);
+ return menuKeyStr.takeBuf();
+}
+
+
+CViewOptions& CViewOptions::operator=(const CViewOptions& o) {
+ useLocalCursor = o.useLocalCursor;
+ useDesktopResize = o.useDesktopResize;
+ fullScreen = o.fullScreen;
+ fullColour = o.fullColour;
+ lowColourLevel = o.lowColourLevel;
+ preferredEncoding = o.preferredEncoding;
+ autoSelect = o.autoSelect;
+ shared = o.shared;
+ sendPtrEvents = o.sendPtrEvents;
+ sendKeyEvents = o.sendKeyEvents;
+ clientCutText = o.clientCutText;
+ serverCutText = o.serverCutText;
+ emulate3 = o.emulate3;
+ pointerEventInterval = o.pointerEventInterval;
+ protocol3_3 = o.protocol3_3;
+ acceptBell = o.acceptBell;
+ setUserName(o.userName.buf);
+ setPassword(o.password.buf);
+ setConfigFileName(o.configFileName.buf);
+ setHost(o.host.buf);
+ setMonitor(o.monitor.buf);
+ menuKey = o.menuKey;
+ return *this;
+} \ No newline at end of file
diff --git a/vncviewer/CViewOptions.h b/vncviewer/CViewOptions.h
new file mode 100644
index 00000000..9120bde2
--- /dev/null
+++ b/vncviewer/CViewOptions.h
@@ -0,0 +1,87 @@
+/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- CViewOptions.h
+
+// Definition of the CViewOptions class, responsible for storing the
+// current & requested VNCviewer options.
+
+#ifndef __RFB_WIN32_CVIEW_OPTIONS_H__
+#define __RFB_WIN32_CVIEW_OPTIONS_H__
+
+#include <rfb/util.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ //
+ // -=- Options structure. Each viewer option has a corresponding
+ // entry in CViewOptions. The viewer options are set by calling
+ // CView::applyOptions(...)
+ // The CViewOptions structure automatically picks up the default
+ // value of each option from the Configuration system
+ // The readFromFile and writeFromFile methods can be used to load
+ // and save VNC configuration files. readFromFile is backwards
+ // compatible with 3.3 releases, while writeToFile is not.
+
+ class CViewOptions {
+ public:
+ CViewOptions();
+ CViewOptions(const CViewOptions& o) {operator=(o);}
+ CViewOptions& operator=(const CViewOptions& o);
+ void readFromFile(const char* filename_);
+ void writeToFile(const char* filename_);
+ void writeDefaults();
+ bool useLocalCursor;
+ bool useDesktopResize;
+ bool fullScreen;
+ bool fullColour;
+ int lowColourLevel;
+ int preferredEncoding;
+ bool autoSelect;
+ bool shared;
+ bool sendPtrEvents;
+ bool sendKeyEvents;
+ bool clientCutText;
+ bool serverCutText;
+ bool emulate3;
+ int pointerEventInterval;
+ bool protocol3_3;
+ bool acceptBell;
+ CharArray userName;
+ void setUserName(const char* user);
+ CharArray password;
+ void setPassword(const char* pwd);
+ CharArray configFileName;
+ void setConfigFileName(const char* cfn);
+ CharArray host;
+ void setHost(const char* h);
+ CharArray monitor;
+ void setMonitor(const char* m);
+ unsigned int menuKey;
+ void setMenuKey(const char* keyName);
+ char* menuKeyName();
+ };
+
+
+ };
+
+};
+
+#endif
diff --git a/vncviewer/ConnectingDialog.h b/vncviewer/ConnectingDialog.h
new file mode 100644
index 00000000..b146ced6
--- /dev/null
+++ b/vncviewer/ConnectingDialog.h
@@ -0,0 +1,95 @@
+/* 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.
+ */
+
+// -=- ConnectingDialog.h
+
+// Dialog to indicate to the user that the viewer is attempting to make an
+// outgoing connection.
+
+#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>
+
+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 {
+ 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();
+ }
+ protected:
+ HWND dialog;
+ bool active;
+ };
+
+ };
+
+};
+
+#endif \ No newline at end of file
diff --git a/vncviewer/ConnectionDialog.cxx b/vncviewer/ConnectionDialog.cxx
new file mode 100644
index 00000000..c083444c
--- /dev/null
+++ b/vncviewer/ConnectionDialog.cxx
@@ -0,0 +1,70 @@
+/* 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 <vncviewer/ConnectionDialog.h>
+#include <vncviewer/CView.h>
+#include <vncviewer/resource.h>
+
+#include <tchar.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+ConnectionDialog::ConnectionDialog(CView* view_) : Dialog(GetModuleHandle(0)), view(view_) {
+}
+
+
+bool ConnectionDialog::showDialog() {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_CONNECTION_DLG));
+}
+
+void ConnectionDialog::initDialog() {
+ HWND box = GetDlgItem(handle, IDC_SERVER_EDIT);
+
+ std::list<char*> mru = MRU::getEntries();
+ std::list<char*>::iterator i;
+
+ // Locate the combo-box
+ // NB: TCharArray converts the supplied char* and assumes ownership!
+ for (i=mru.begin(); i!=mru.end(); i++) {
+ int index = SendMessage(box, CB_ADDSTRING, 0, (LPARAM)TCharArray(*i).buf);
+ }
+
+ // Select the first item in the list
+ SendMessage(box, CB_SETCURSEL, 0, 0);
+}
+
+
+bool ConnectionDialog::onOk() {
+ delete [] hostname.buf;
+ hostname.buf = 0;
+ hostname.buf = getItemString(IDC_SERVER_EDIT);
+ return hostname.buf[0] != 0;
+}
+
+bool ConnectionDialog::onCommand(int id, int cmd) {
+ switch (id) {
+ case IDC_ABOUT:
+ AboutDialog::instance.showDialog();
+ return true;
+ case IDC_OPTIONS:
+ view->optionsDialog.showDialog(view);
+ return true;
+ };
+ return false;
+}
diff --git a/vncviewer/ConnectionDialog.h b/vncviewer/ConnectionDialog.h
new file mode 100644
index 00000000..554c86fb
--- /dev/null
+++ b/vncviewer/ConnectionDialog.h
@@ -0,0 +1,52 @@
+/* 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.
+ */
+
+// -=- ConnectionDialog.h
+
+// Connection dialog for VNC Viewer 4.0
+
+#ifndef __RFB_WIN32_CONN_DIALOG_H__
+#define __RFB_WIN32_CONN_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+#include <vncviewer/MRU.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class CView;
+
+ class ConnectionDialog : Dialog {
+ public:
+ ConnectionDialog(CView* view);
+ virtual bool showDialog();
+ virtual void initDialog();
+ virtual bool onOk();
+ virtual bool onCommand(int id, int cmd);
+ TCharArray hostname;
+ protected:
+ CView* view;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/vncviewer/InfoDialog.cxx b/vncviewer/InfoDialog.cxx
new file mode 100644
index 00000000..0d2313a5
--- /dev/null
+++ b/vncviewer/InfoDialog.cxx
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <vncviewer/InfoDialog.h>
+#include <vncviewer/resource.h>
+#include <vncviewer/CView.h>
+#include <rfb/secTypes.h>
+#include <rfb/encodings.h>
+#include <rfb/CSecurity.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("Info");
+
+
+bool InfoDialog::showDialog(CView* vw) {
+ view = vw;
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_CONNECTION_INFO));
+}
+
+void InfoDialog::initDialog() {
+ char buf[256];
+
+ setItemString(IDC_INFO_NAME, TStr(view->cp.name()));
+
+ setItemString(IDC_INFO_HOST, TCharArray(view->sock->getPeerAddress()).buf);
+
+ Rect bufRect = view->buffer->getRect();
+ sprintf(buf, "%dx%d", bufRect.width(), bufRect.height());
+ setItemString(IDC_INFO_SIZE, TStr(buf));
+
+ view->cp.pf().print(buf, 256);
+ setItemString(IDC_INFO_PF, TStr(buf));
+
+ view->serverDefaultPF.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())));
+
+ sprintf(buf, "%d kbits/s", view->sock->inStream().kbitsPerSecond());
+ setItemString(IDC_INFO_LINESPEED, TStr(buf));
+
+ sprintf(buf, "%d.%d", view->cp.majorVersion, view->cp.minorVersion);
+ setItemString(IDC_INFO_VERSION, TStr(buf));
+
+ int secType = view->getCurrentCSecurity()->getType();
+ setItemString(IDC_INFO_SECURITY, TStr(secTypeName(secType)));
+}
diff --git a/vncviewer/InfoDialog.h b/vncviewer/InfoDialog.h
new file mode 100644
index 00000000..7a64d383
--- /dev/null
+++ b/vncviewer/InfoDialog.h
@@ -0,0 +1,48 @@
+/* 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.
+ */
+
+// -=- InfoDialog.h
+
+// Info dialog for VNC Viewer 4.0
+
+#ifndef __RFB_WIN32_INFO_DIALOG_H__
+#define __RFB_WIN32_INFO_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class CView;
+
+ class InfoDialog : Dialog {
+ public:
+ InfoDialog() : Dialog(GetModuleHandle(0)), view(0) {}
+ virtual bool showDialog(CView* vw);
+ virtual void initDialog();
+ protected:
+ CView* view;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/vncviewer/MRU.h b/vncviewer/MRU.h
new file mode 100644
index 00000000..9e993956
--- /dev/null
+++ b/vncviewer/MRU.h
@@ -0,0 +1,140 @@
+/* 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.
+ */
+#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>
+
+namespace rfb {
+
+ namespace win32 {
+
+ namespace MRU {
+
+ static const RegKey RegRoot = HKEY_CURRENT_USER;
+ static const TCHAR* RegPath = _T("Software\\RealVNC\\VNCViewer4\\MRU");
+ static const int MaxMRUEntries = 256;
+ static const int MRUEntries = 10;
+
+ static std::list<char*> getEntries() {
+ std::list<char*> mru;
+
+ try {
+ RegKey key;
+ key.openKey(RegRoot, RegPath);
+
+ CharArray order;
+ int length;
+ key.getBinary(_T("Order"), (void**)&order.buf, &length);
+
+ for (int i=0; i<length; i++) {
+ TCharArray keyname = rdr::HexOutStream::binToHexStr(&order.buf[i], 1);
+ try {
+ TCharArray entry = key.getString(keyname.buf);
+ mru.push_back(strDup(entry.buf));
+ } catch (rdr::Exception) {
+ }
+ }
+ } catch (rdr::Exception) {
+ }
+
+ return mru;
+ }
+
+ static void addToMRU(const char* name) {
+ RegKey key;
+ key.createKey(RegRoot, RegPath);
+
+ BYTE keycode;
+ CharArray old_order;
+ char order[MaxMRUEntries];
+ int orderlen;
+
+ try {
+ key.getBinary(_T("Order"), (void**)&old_order.buf, &orderlen);
+ if (orderlen)
+ memcpy(order, old_order.buf, orderlen);
+
+ std::set<int> ordercodes;
+ keycode = 0;
+ bool found = false;
+ for (int i=0; i<orderlen; i++) {
+ TCharArray keyname = rdr::HexOutStream::binToHexStr(&order[i], 1);
+ try {
+ TCharArray hostname = key.getString(keyname.buf);
+ if (strcmp(name, CStr(hostname.buf)) == 0) {
+ keycode = order[i];
+ found = true;
+ break;
+ }
+ } catch (rdr::Exception) {
+ }
+ ordercodes.insert(order[i]);
+ }
+
+ if (!found) {
+ if (orderlen <= MRUEntries) {
+ while (ordercodes.find(keycode) != ordercodes.end()) keycode++;
+ } else {
+ keycode = order[orderlen-1];
+ orderlen--;
+ }
+ }
+
+ } catch (rdr::Exception) {
+ keycode = 0;
+ orderlen = 0;
+ }
+
+ printf("keycode=%d\n", (int)keycode);
+
+ orderlen++;
+ int i, j=orderlen-1;
+ for (i=0; i<orderlen-1; i++) {
+ if (order[i] == keycode) {
+ j = i;
+ orderlen--;
+ break;
+ }
+ }
+ for (i=j; i>0; i--)
+ 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);
+ }
+
+ };
+
+ };
+
+};
+
+#endif \ No newline at end of file
diff --git a/vncviewer/OptionsDialog.cxx b/vncviewer/OptionsDialog.cxx
new file mode 100644
index 00000000..ab45f8ce
--- /dev/null
+++ b/vncviewer/OptionsDialog.cxx
@@ -0,0 +1,309 @@
+/* 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 <commdlg.h>
+
+#include <vncviewer/OptionsDialog.h>
+#include <vncviewer/CView.h>
+#include <vncviewer/resource.h>
+#include <rfb_win32/Registry.h>
+#include <rfb/LogWriter.h>
+#include <rfb/encodings.h>
+#include <rfb/CConnection.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("Options");
+
+
+struct OptionsInfo {
+ CView* view;
+ CViewOptions options;
+};
+
+
+OptionsDialog rfb::win32::OptionsDialog::global;
+
+
+class VNCviewerOptions : public PropSheet {
+public:
+ VNCviewerOptions(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() {
+ if (changed) {
+ if (info.view)
+ // Apply the settings to the supplied session object
+ info.view->applyOptions(info.options);
+ else {
+ // Commit the settings to the user's registry area
+ info.options.writeDefaults();
+ }
+ }
+ }
+
+ void setChanged() {changed = true;}
+
+ bool changed;
+ OptionsInfo& info;
+};
+
+
+class FormatPage : public PropSheetPage {
+public:
+ FormatPage(OptionsInfo* dlg_)
+ : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_FORMAT)), dlg(dlg_) {
+ }
+ virtual void initDialog() {
+ setItemChecked(IDC_ENCODING_AUTO, dlg->options.autoSelect);
+ setItemChecked(IDC_FORMAT_FULLCOLOUR, dlg->options.fullColour);
+ if (!dlg->options.fullColour) {
+ switch (dlg->options.lowColourLevel) {
+ case 0: setItemChecked(IDC_FORMAT_VERYLOWCOLOUR, true); break;
+ case 1: setItemChecked(IDC_FORMAT_LOWCOLOUR, true); break;
+ case 2: setItemChecked(IDC_FORMAT_MEDIUMCOLOUR, true); break;
+ }
+ }
+ switch (dlg->options.preferredEncoding) {
+ case encodingZRLE: setItemChecked(IDC_ENCODING_ZRLE, true); break;
+ case encodingHextile: setItemChecked(IDC_ENCODING_HEXTILE, true); break;
+ case encodingRaw: setItemChecked(IDC_ENCODING_RAW, true); break;
+ }
+ onCommand(IDC_ENCODING_AUTO, 0 /* ? */); // Force enableItem status to refresh
+ }
+ virtual bool onOk() {
+ dlg->options.autoSelect = isItemChecked(IDC_ENCODING_AUTO);
+ dlg->options.fullColour = isItemChecked(IDC_FORMAT_FULLCOLOUR);
+ if (isItemChecked(IDC_FORMAT_VERYLOWCOLOUR))
+ dlg->options.lowColourLevel = 0;
+ if (isItemChecked(IDC_FORMAT_LOWCOLOUR))
+ dlg->options.lowColourLevel = 1;
+ if (isItemChecked(IDC_FORMAT_MEDIUMCOLOUR))
+ dlg->options.lowColourLevel = 2;
+ dlg->options.preferredEncoding = encodingZRLE;
+ if (isItemChecked(IDC_ENCODING_HEXTILE))
+ dlg->options.preferredEncoding = encodingHextile;
+ if (isItemChecked(IDC_ENCODING_RAW))
+ dlg->options.preferredEncoding = encodingRaw;
+ ((VNCviewerOptions*)propSheet)->setChanged();
+ return true;
+ }
+ virtual bool onCommand(int id, int cmd) {
+ if (id == IDC_ENCODING_AUTO) {
+ bool ok = !isItemChecked(IDC_ENCODING_AUTO);
+ enableItem(IDC_ENCODING_ZRLE, ok);
+ enableItem(IDC_ENCODING_HEXTILE, ok);
+ enableItem(IDC_ENCODING_RAW, ok);
+ return true;
+ }
+ return false;
+ }
+protected:
+ OptionsInfo* dlg;
+};
+
+class MiscPage : public PropSheetPage {
+public:
+ MiscPage(OptionsInfo* dlg_)
+ : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_MISC)), dlg(dlg_) {
+ }
+ virtual void initDialog() {
+ setItemChecked(IDC_CONN_SHARED, dlg->options.shared);
+ enableItem(IDC_CONN_SHARED, (!dlg->view) || (dlg->view->state() != CConnection::RFBSTATE_NORMAL));
+ setItemChecked(IDC_FULL_SCREEN, dlg->options.fullScreen);
+ setItemChecked(IDC_LOCAL_CURSOR, dlg->options.useLocalCursor);
+ setItemChecked(IDC_DESKTOP_RESIZE, dlg->options.useDesktopResize);
+ 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);
+ }
+ virtual bool onOk() {
+ dlg->options.shared = isItemChecked(IDC_CONN_SHARED);
+ dlg->options.fullScreen = isItemChecked(IDC_FULL_SCREEN);
+ dlg->options.useLocalCursor = isItemChecked(IDC_LOCAL_CURSOR);
+ dlg->options.useDesktopResize = isItemChecked(IDC_DESKTOP_RESIZE);
+ dlg->options.protocol3_3 = isItemChecked(IDC_PROTOCOL_3_3);
+ dlg->options.acceptBell = isItemChecked(IDC_ACCEPT_BELL);
+ ((VNCviewerOptions*)propSheet)->setChanged();
+ return true;
+ }
+protected:
+ OptionsInfo* dlg;
+};
+
+class InputsPage : public PropSheetPage {
+public:
+ InputsPage(OptionsInfo* dlg_)
+ : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_INPUTS)), dlg(dlg_) {
+ }
+ virtual void initDialog() {
+ setItemChecked(IDC_SEND_POINTER, dlg->options.sendPtrEvents);
+ setItemChecked(IDC_SEND_KEYS, dlg->options.sendKeyEvents);
+ setItemChecked(IDC_CLIENT_CUTTEXT, dlg->options.clientCutText);
+ setItemChecked(IDC_SERVER_CUTTEXT, dlg->options.serverCutText);
+ setItemChecked(IDC_EMULATE3, dlg->options.emulate3);
+ setItemChecked(IDC_POINTER_INTERVAL, dlg->options.pointerEventInterval != 0);
+
+ // Populate the Menu Key tab
+ HWND menuKey = GetDlgItem(handle, IDC_MENU_KEY);
+ SendMessage(menuKey, CB_RESETCONTENT, 0, 0);
+ SendMessage(menuKey, CB_ADDSTRING, 0, (LPARAM)_T("none"));
+ if (!dlg->options.menuKey)
+ SendMessage(menuKey, CB_SETCURSEL, 0, 0);
+ for (int i=0; i<12; i++) {
+ TCHAR buf[4];
+ _stprintf(buf, _T("F%d"), i+1);
+ int index = SendMessage(menuKey, CB_ADDSTRING, 0, (LPARAM)buf);
+ if (i == (dlg->options.menuKey - VK_F1))
+ SendMessage(menuKey, CB_SETCURSEL, index, 0);
+ }
+ }
+ virtual bool onOk() {
+ dlg->options.sendPtrEvents = isItemChecked(IDC_SEND_POINTER);
+ dlg->options.sendKeyEvents = isItemChecked(IDC_SEND_KEYS);
+ dlg->options.clientCutText = isItemChecked(IDC_CLIENT_CUTTEXT);
+ dlg->options.serverCutText = isItemChecked(IDC_SERVER_CUTTEXT);
+ dlg->options.emulate3 = isItemChecked(IDC_EMULATE3);
+ dlg->options.pointerEventInterval =
+ isItemChecked(IDC_POINTER_INTERVAL) ? 200 : 0;
+
+ HWND mkHwnd = GetDlgItem(handle, IDC_MENU_KEY);
+ int index = SendMessage(mkHwnd, CB_GETCURSEL, 0, 0);
+ TCharArray keyName(SendMessage(mkHwnd, CB_GETLBTEXTLEN, index, 0)+1);
+ SendMessage(mkHwnd, CB_GETLBTEXT, index, (LPARAM)keyName.buf);
+ if (_tcscmp(keyName.buf, _T("none")) == 0)
+ dlg->options.setMenuKey("");
+ else
+ dlg->options.setMenuKey(CStr(keyName.buf));
+
+ ((VNCviewerOptions*)propSheet)->setChanged();
+ return true;
+ }
+protected:
+ OptionsInfo* dlg;
+};
+
+
+class DefaultsPage : public PropSheetPage {
+public:
+ DefaultsPage(OptionsInfo* dlg_)
+ : PropSheetPage(GetModuleHandle(0), MAKEINTRESOURCE(IDD_DEFAULTS)), dlg(dlg_) {
+ }
+ virtual void initDialog() {
+ enableItem(IDC_LOAD_CONFIG, dlg->options.configFileName.buf);
+ 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();
+ break;
+ case IDC_SAVE_DEFAULTS:
+ propSheet->commitPages();
+ dlg->options.writeDefaults();
+ break;
+ case IDC_LOAD_CONFIG:
+ dlg->options.readFromFile(dlg->options.configFileName.buf);
+ break;
+ case IDC_SAVE_CONFIG:
+ propSheet->commitPages();
+ dlg->options.writeToFile(dlg->options.configFileName.buf);
+ MsgBox(hwnd, _T("Options saved successfully"),
+ MB_OK | MB_ICONINFORMATION);
+ return 0;
+ case IDC_SAVE_CONFIG_AS:
+ propSheet->commitPages();
+ // Get a filename to save to
+ TCHAR newFilename[4096];
+ TCHAR currentDir[4096];
+ if (dlg->options.configFileName.buf)
+ _tcscpy(newFilename, TStr(dlg->options.configFileName.buf));
+ else
+ newFilename[0] = 0;
+ OPENFILENAME ofn;
+ memset(&ofn, 0, sizeof(ofn));
+#ifdef OPENFILENAME_SIZE_VERSION_400
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+#else
+ ofn.lStructSize = sizeof(ofn);
+#endif
+ ofn.hwndOwner = hwnd;
+ ofn.lpstrFilter = _T("VNC Connection Options\000*.vnc\000");
+ ofn.lpstrFile = newFilename;
+ currentDir[0] = 0;
+ GetCurrentDirectory(4096, currentDir);
+ ofn.lpstrInitialDir = currentDir;
+ ofn.nMaxFile = 4096;
+ ofn.lpstrDefExt = _T(".vnc");
+ ofn.Flags = OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
+ if (!GetSaveFileName(&ofn)) {
+ if (CommDlgExtendedError())
+ throw rdr::Exception("GetSaveFileName failed");
+ return 0;
+ }
+
+ // Save the Options
+ dlg->options.writeToFile(CStr(newFilename));
+ MsgBox(hwnd, _T("Options saved successfully"),
+ MB_OK | MB_ICONINFORMATION);
+ return 0;
+ };
+ propSheet->reInitPages();
+ return true;
+ }
+protected:
+ OptionsInfo* dlg;
+};
+
+
+OptionsDialog::OptionsDialog() : visible(false) {
+}
+
+bool OptionsDialog::showDialog(CView* view, bool capture) {
+ if (visible) return false;
+ visible = true;
+
+ // Grab the current properties
+ OptionsInfo info;
+ if (view)
+ info.options = view->getOptions();
+ info.view = view;
+
+ // Build a list of pages to display
+ std::list<PropSheetPage*> pages;
+ FormatPage formatPage(&info); pages.push_back(&formatPage);
+ InputsPage inputsPage(&info); pages.push_back(&inputsPage);
+ MiscPage miscPage(&info); pages.push_back(&miscPage);
+ 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);
+
+ visible = false;
+ return dialog.changed;
+}
diff --git a/vncviewer/OptionsDialog.h b/vncviewer/OptionsDialog.h
new file mode 100644
index 00000000..eec9b96a
--- /dev/null
+++ b/vncviewer/OptionsDialog.h
@@ -0,0 +1,49 @@
+/* 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.
+ */
+
+// -=- OptionsDialog.h
+
+// Options dialog for VNC Viewer 4.0
+
+#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 OptionsDialog {
+ public:
+ OptionsDialog();
+ virtual bool showDialog(CView* cfg, bool capture=false);
+
+ static OptionsDialog global;
+ protected:
+ bool visible;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/vncviewer/UserPasswdDialog.cxx b/vncviewer/UserPasswdDialog.cxx
new file mode 100644
index 00000000..8ab4ba4c
--- /dev/null
+++ b/vncviewer/UserPasswdDialog.cxx
@@ -0,0 +1,84 @@
+/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <vncviewer/UserPasswdDialog.h>
+#include <vncviewer/resource.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+UserPasswdDialog::UserPasswdDialog() : Dialog(GetModuleHandle(0)), showUsername(false) {
+}
+
+
+void UserPasswdDialog::setCSecurity(const CSecurity* cs) {
+ description.replaceBuf(tstrDup(cs->description()));
+}
+
+bool UserPasswdDialog::showDialog() {
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_VNC_AUTH_DLG));
+}
+
+void UserPasswdDialog::initDialog() {
+ if (username.buf) {
+ setItemString(IDC_USERNAME, username.buf);
+ tstrFree(username.takeBuf());
+ }
+ if (password.buf) {
+ setItemString(IDC_PASSWORD, password.buf);
+ tstrFree(password.takeBuf());
+ }
+ if (!showUsername) {
+ setItemString(IDC_USERNAME, _T(""));
+ enableItem(IDC_USERNAME, false);
+ }
+ if (description.buf) {
+ TCharArray title(128);
+ GetWindowText(handle, title.buf, 128);
+ _tcsncat(title.buf, _T(" ["), 128);
+ _tcsncat(title.buf, description.buf, 128);
+ _tcsncat(title.buf, _T("]"), 128);
+ SetWindowText(handle, title.buf);
+ }
+}
+
+bool UserPasswdDialog::onOk() {
+ username.buf = getItemString(IDC_USERNAME);
+ password.buf = getItemString(IDC_PASSWORD);
+ return true;
+}
+
+
+bool UserPasswdDialog::getUserPasswd(char** user, char** passwd) {
+ bool result = false;
+ showUsername = user != 0;
+ if (user && *user)
+ username.buf = tstrDup(*user);
+ if (passwd && *passwd)
+ password.buf = tstrDup(*passwd);
+ if (showDialog()) {
+ if (user)
+ *user = strDup(username.buf);
+ *passwd = strDup(password.buf);
+ result = true;
+ }
+ tstrFree(username.takeBuf());
+ tstrFree(password.takeBuf());
+ return result;
+}
diff --git a/vncviewer/UserPasswdDialog.h b/vncviewer/UserPasswdDialog.h
new file mode 100644
index 00000000..998a49f1
--- /dev/null
+++ b/vncviewer/UserPasswdDialog.h
@@ -0,0 +1,54 @@
+/* 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.
+ */
+
+// -=- UserPasswdDialog.h
+
+// Username and password dialog for VNC Viewer 4.0
+
+#ifndef __RFB_WIN32_USERPASSWD_DIALOG_H__
+#define __RFB_WIN32_USERPASSWD_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+#include <rfb_win32/TCharArray.h>
+#include <rfb/CSecurity.h>
+#include <rfb/UserPasswdGetter.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class UserPasswdDialog : Dialog, public UserPasswdGetter {
+ public:
+ UserPasswdDialog();
+ virtual bool showDialog();
+ virtual void initDialog();
+ virtual bool onOk();
+ virtual bool getUserPasswd(char** user, char** passwd);
+ void setCSecurity(const CSecurity* cs);
+ protected:
+ TCharArray username;
+ TCharArray password;
+ bool showUsername;
+ TCharArray description;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/vncviewer/buildTime.cxx b/vncviewer/buildTime.cxx
new file mode 100644
index 00000000..bab2e137
--- /dev/null
+++ b/vncviewer/buildTime.cxx
@@ -0,0 +1 @@
+const char* buildTime = "Built on " __DATE__ " at " __TIME__; \ No newline at end of file
diff --git a/vncviewer/cursor1.cur b/vncviewer/cursor1.cur
new file mode 100644
index 00000000..20a713f7
--- /dev/null
+++ b/vncviewer/cursor1.cur
Binary files differ
diff --git a/vncviewer/cview.cxx b/vncviewer/cview.cxx
new file mode 100644
index 00000000..7d5653df
--- /dev/null
+++ b/vncviewer/cview.cxx
@@ -0,0 +1,1468 @@
+/* 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 = 1;
+const int IDM_SEND_MENU_KEY = 2;
+const int IDM_SEND_CAD = 3;
+const int IDM_ABOUT = 4;
+const int IDM_OPTIONS = 5;
+const int IDM_INFO = 6;
+const int IDM_NEWCONN = 7;
+const int IDM_REQUEST_REFRESH = 9;
+const int IDM_CTRL_KEY = 10;
+const int IDM_ALT_KEY = 11;
+
+const int TIMER_BUMPSCROLL = 1;
+const int TIMER_POINTER_INTERVAL = 2;
+const int TIMER_POINTER_3BUTTON = 3;
+
+
+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 = NULL;
+ 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;
+
+
+//
+// -=- 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), requestUpdate(false), has_focus(false), palette_changed(false),
+ sameMachine(false), encodingChange(false), formatChange(false),
+ lastUsedEncoding_(encodingRaw), fullScreenActive(false),
+ bumpScroll(false), manager(0) {
+
+ // Create the window
+ const TCHAR* name = _T("VNC Viewer 4.0b");
+ hwnd = CreateWindow((const TCHAR*)baseClass.classAtom, name, WS_OVERLAPPEDWINDOW,
+ 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);
+
+ // Initialise the CPointer pointer handler
+ ptr.setHWND(getHandle());
+ ptr.setIntervalTimerId(TIMER_POINTER_INTERVAL);
+ ptr.set3ButtonTimerId(TIMER_POINTER_3BUTTON);
+
+ // Initialise the bumpscroll timer
+ bumpScrollTimer.setHWND(getHandle());
+ bumpScrollTimer.setId(TIMER_BUMPSCROLL);
+
+ // Hook the clipboard
+ clipboard.setNotifier(this);
+
+ // Create the backing buffer
+ buffer = new win32::DIBSectionBuffer(getHandle());
+}
+
+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, 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_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;
+
+ 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;
+ 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.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;
+}
+
+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 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);
+
+ 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
+ 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(getHandle(), -delta.x, -delta.y, 0, 0, 0, 0, SW_INVALIDATE);
+ UpdateWindow(getHandle());
+ 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_DISPLAYCHANGE:
+ // Display has changed - use new pixel format
+ calculateFullColourPF();
+ break;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC paintDC = BeginPaint(getHandle(), &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(getHandle(), &ps);
+
+ // - Request the next update from the server, if required
+ requestNewUpdate();
+ }
+ return 0;
+
+ // -=- Palette management
+
+ case WM_PALETTECHANGED:
+ vlog.debug("WM_PALETTECHANGED");
+ if ((HWND)wParam == getHandle()) {
+ vlog.debug("ignoring");
+ break;
+ }
+ case WM_QUERYNEWPALETTE:
+ vlog.debug("re-selecting palette");
+ {
+ WindowDC wdc(getHandle());
+ PaletteSelector pSel(wdc, windowPalette.getHandle());
+ if (pSel.isRedrawRequired()) {
+ InvalidateRect(getHandle(), 0, FALSE);
+ UpdateWindow(getHandle());
+ }
+ }
+ return TRUE;
+
+ // -=- 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(getHandle(), GWL_STYLE);
+ DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+ RECT r;
+ SetRect(&r, 0, 0, buffer->width(), buffer->height());
+ AdjustWindowRect(&r, style, FALSE);
+ 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);
+ 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;
+
+ // Add scrollbars if required and update window size info we have cached.
+
+ case WM_SIZE:
+ {
+ Point old_offset = bufferToClient(Point(0, 0));
+
+ // Update the cached sizing information
+ RECT r;
+ GetWindowRect(getHandle(), &r);
+ window_size = Rect(r.left, r.top, r.right, r.bottom);
+ GetClientRect(getHandle(), &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(getHandle(), 0, TRUE);
+ }
+ break;
+
+ 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(getHandle(), (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ, &si, 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;
+
+ // -=- 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 = hwnd;
+ _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;
+
+ // -=- Track whether or not the window has focus
+
+ case WM_SETFOCUS:
+ has_focus = true;
+ break;
+ case WM_KILLFOCUS:
+ has_focus = false;
+ cursorOutsideBuffer();
+ // 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_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_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;
+ };
+
+ // - 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_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;
+ }
+ }
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ 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);
+}
+
+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);
+ }
+}
+
+
+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(getHandle(), &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};
+ 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(getHandle(), 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();
+}
+
+// autoSelectFormatAndEncoding() chooses the format and encoding appropriate
+// to the connection speed:
+// Above 16Mbps (timing for at least a second), same machine, switch to raw
+// Above 3Mbps, switch to hextile
+// Below 1.5Mbps, switch to ZRLE
+// Above 1Mbps, switch to full colour mode
+void
+CView::autoSelectFormatAndEncoding() {
+ int kbitsPerSecond = sock->inStream().kbitsPerSecond();
+ unsigned int newEncoding = options.preferredEncoding;
+
+ if (kbitsPerSecond > 16000 && sameMachine &&
+ sock->inStream().timeWaited() >= 10000) {
+ newEncoding = encodingRaw;
+ } else if (kbitsPerSecond > 3000) {
+ newEncoding = encodingHextile;
+ } else if (kbitsPerSecond < 1500) {
+ 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 > 1000) {
+ if (!options.fullColour) {
+ vlog.info("Throughput %d kbit/s - changing to full colour",
+ kbitsPerSecond);
+ options.fullColour = true;
+ 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(getHandle(), GWL_STYLE);
+ DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+ DWORD old_style;
+ RECT r;
+ SetRect(&r, 0, 0, buffer->width(), buffer->height());
+ AdjustWindowRect(&r, style, FALSE);
+ 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(getHandle(), GWL_STYLE, style);
+ SetWindowPos(getHandle(), 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(getHandle(), 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(getHandle(), SB_HORZ, &si, TRUE);
+ }
+}
+
+
+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();
+
+ // 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.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;
+}
+
diff --git a/vncviewer/cview.h b/vncviewer/cview.h
new file mode 100644
index 00000000..2bee1c48
--- /dev/null
+++ b/vncviewer/cview.h
@@ -0,0 +1,296 @@
+/* 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/CViewOptions.h>
+#include <vncviewer/CViewManager.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);
+
+ // -=- 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;}
+
+ 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;
+
+ protected:
+
+ // 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 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;
+
+ // 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;
+
+ // Handle back to CViewManager instance, if any
+ CViewManager* manager;
+
+ };
+
+ };
+
+};
+
+#endif
+
+
diff --git a/vncviewer/msvcwarning.h b/vncviewer/msvcwarning.h
new file mode 100644
index 00000000..53a0678d
--- /dev/null
+++ b/vncviewer/msvcwarning.h
@@ -0,0 +1,19 @@
+/* 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
new file mode 100644
index 00000000..351a2b0a
--- /dev/null
+++ b/vncviewer/resource.h
@@ -0,0 +1,80 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by vncviewer.rc
+//
+#define IDR_MANIFEST 1
+#define IDI_ICON 101
+#define IDD_VNC_AUTH_DLG 102
+#define IDD_CONNECTING_DLG 103
+#define IDD_CONNECTION_DLG 104
+#define IDC_DOT_CURSOR 105
+#define IDD_ABOUT 107
+#define IDD_FORMAT 108
+#define IDD_MISC 109
+#define IDD_INPUTS 110
+#define IDD_SERVER_KEYS 111
+#define IDR_TRAY 112
+#define IDD_CONNECTION_INFO 113
+#define IDD_DEFAULTS 116
+#define IDC_PASSWORD 1000
+#define IDC_CONNECTING_TEXT 1001
+#define IDC_SERVER_EDIT 1002
+#define IDC_USERNAME 1005
+#define IDC_VERSION 1008
+#define IDC_BUILDTIME 1009
+#define IDC_ENCODING_AUTO 1010
+#define IDC_FORMAT_FULLCOLOUR 1011
+#define IDC_ENCODING_ZRLE 1012
+#define IDC_ENCODING_HEXTILE 1013
+#define IDC_CONN_SHARED 1013
+#define IDC_ENCODING_RAW 1014
+#define IDC_FULL_SCREEN 1014
+#define IDC_SEND_POINTER 1015
+#define IDC_SEND_KEYS 1016
+#define IDC_CLIENT_CUTTEXT 1017
+#define IDC_SERVER_CUTTEXT 1018
+#define IDC_LOCAL_CURSOR 1019
+#define IDC_DESKTOP_RESIZE 1020
+#define IDC_COPYRIGHT 1021
+#define IDC_DESCRIPTION 1022
+#define IDC_OPTIONS 1023
+#define IDC_ABOUT 1024
+#define IDC_LIST1 1025
+#define IDC_INFO_NAME 1026
+#define IDC_INFO_HOST 1027
+#define IDC_INFO_SIZE 1028
+#define IDC_INFO_PF 1029
+#define IDC_INFO_DEF_PF 1030
+#define IDC_INFO_LINESPEED 1031
+#define IDC_INFO_VERSION 1032
+#define IDC_PROTOCOL_3_3 1034
+#define IDC_ACCEPT_BELL 1035
+#define IDC_FORMAT_VERYLOWCOLOUR 1036
+#define IDC_FORMAT_LOWCOLOUR 1037
+#define IDC_FORMAT_MEDIUMCOLOUR 1038
+#define IDC_LOAD_DEFAULTS 1040
+#define IDC_SAVE_DEFAULTS 1041
+#define IDC_LOAD_CONFIG 1042
+#define IDC_EMULATE3 1043
+#define IDC_POINTER_INTERVAL 1044
+#define IDC_SAVE_CONFIG 1045
+#define IDC_INFO_SECURITY 1046
+#define IDC_SAVE_CONFIG_AS 1048
+#define IDC_MENU_KEY 1051
+#define IDC_REQUESTED_ENCODING 1052
+#define IDC_LAST_ENCODING 1053
+#define ID_CLOSE 40002
+#define ID_OPTIONS 40003
+#define ID_NEW_CONNECTION 40004
+#define ID_ABOUT 40005
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 120
+#define _APS_NEXT_COMMAND_VALUE 40006
+#define _APS_NEXT_CONTROL_VALUE 1054
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
new file mode 100644
index 00000000..59e2d00b
--- /dev/null
+++ b/vncviewer/vncviewer.cxx
@@ -0,0 +1,370 @@
+/* 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.
+ */
+
+// -=- VNC Viewer for Win32
+
+#include <string.h>
+#ifdef WIN32
+#define strcasecmp _stricmp
+#endif
+#include <list>
+
+#include <vncviewer/resource.h>
+#include <vncviewer/CViewManager.h>
+#include <vncviewer/CView.h>
+#include <vncviewer/OptionsDialog.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>
+
+#ifdef _DIALOG_CAPTURE
+#include <extra/LoadBMP.h>
+#endif
+
+using namespace rfb;
+using namespace rfb::win32;
+using namespace rdr;
+using namespace network;
+
+static LogWriter vlog("main");
+
+TStr rfb::win32::AppName("VNC Viewer");
+
+
+#ifdef _DIALOG_CAPTURE
+BoolParameter captureDialogs("CaptureDialogs", "", false);
+#endif
+
+//
+// -=- Listener
+// Class to handle listening on a particular port for incoming connections
+// from servers, and spawning of clients
+//
+
+static BoolParameter acceptIncoming("Listen", "Accept incoming connections from VNC servers.", false);
+
+
+//
+// -=- AboutDialog global values
+//
+
+const WORD rfb::win32::AboutDialog::DialogId = IDD_ABOUT;
+const WORD rfb::win32::AboutDialog::Copyright = IDC_COPYRIGHT;
+const WORD rfb::win32::AboutDialog::Version = IDC_VERSION;
+const WORD rfb::win32::AboutDialog::BuildTime = IDC_BUILDTIME;
+const WORD rfb::win32::AboutDialog::Description = IDC_DESCRIPTION;
+
+
+//
+// -=- VNCviewer Tray Icon
+//
+
+class CViewTrayIcon : public TrayIcon {
+public:
+ CViewTrayIcon(CViewManager& mgr) : manager(mgr) {
+ setIcon(IDI_ICON);
+ setToolTip(_T("VNC Viewer"));
+ }
+ virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch(msg) {
+
+ case WM_USER:
+ switch (lParam) {
+ case WM_LBUTTONDBLCLK:
+ SendMessage(getHandle(), WM_COMMAND, ID_NEW_CONNECTION, 0);
+ break;
+ case WM_RBUTTONUP:
+ HMENU menu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(IDR_TRAY));
+ HMENU trayMenu = GetSubMenu(menu, 0);
+
+ // First item is New Connection, the default
+ SetMenuDefaultItem(trayMenu, ID_NEW_CONNECTION, FALSE);
+
+ // SetForegroundWindow is required, otherwise Windows ignores the
+ // TrackPopupMenu because the window isn't the foreground one, on
+ // some older Windows versions...
+ SetForegroundWindow(getHandle());
+
+ // Display the menu
+ POINT pos;
+ GetCursorPos(&pos);
+ TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, getHandle(), 0);
+ break;
+ }
+ return 0;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case ID_NEW_CONNECTION:
+ manager.addClient(0);
+ break;
+ case ID_OPTIONS:
+ OptionsDialog::global.showDialog(0);
+ break;
+ case ID_ABOUT:
+ AboutDialog::instance.showDialog();
+ break;
+ case ID_CLOSE:
+ SendMessage(getHandle(), WM_CLOSE, 0, 0);
+ break;
+ }
+ return 0;
+
+ case WM_CLOSE:
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ return TrayIcon::processMessage(msg, wParam, lParam);
+ }
+protected:
+ CViewManager& manager;
+};
+
+//
+// -=- processParams
+// Read in the command-line parameters and interpret them.
+//
+
+void
+programInfo() {
+ win32::FileVersionInfo inf;
+ _tprintf(_T("%s - %s, Version %s\n"),
+ inf.getVerString(_T("ProductName")),
+ inf.getVerString(_T("FileDescription")),
+ inf.getVerString(_T("FileVersion")));
+ printf("%s\n", buildTime);
+ _tprintf(_T("%s\n\n"), inf.getVerString(_T("LegalCopyright")));
+}
+
+void
+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(" -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");
+ printf("\nLog names:\n");
+ LogWriter::listLogWriters();
+ printf("\nLog destinations:\n");
+ Logger::listLoggers();
+ printf("\nParameters:\n");
+ Configuration::listParams();
+}
+
+
+bool print_usage = false;
+bool close_console = true;
+std::list<char*> hosts;
+std::list<char*> configFiles;
+
+void
+processParams(int argc, char* argv[]) {
+ for (int i=1; i<argc; i++) {
+ try {
+
+ if (strcasecmp(argv[i], "-console") == 0) {
+ close_console = false;
+
+ } else if (((strcasecmp(argv[i], "-config") == 0) ||
+ (strcasecmp(argv[i], "/config") == 0)) && (i < argc-1)) {
+ configFiles.push_back(strDup(argv[i+1]));
+ i++;
+
+ } else if ((strcasecmp(argv[i], "-help") == 0) ||
+ (strcasecmp(argv[i], "--help") == 0) ||
+ (strcasecmp(argv[i], "-h") == 0) ||
+ (strcasecmp(argv[i], "/?") == 0)) {
+ print_usage = true;
+ close_console = false;
+ break;
+
+ } else {
+ // Try to process <option>=<value>, or -<bool>
+ if (Configuration::setParam(argv[i], true))
+ continue;
+ // Try to process -<option> <value>
+ if ((argv[i][0] == '-') && (i+1 < argc)) {
+ if (Configuration::setParam(&argv[i][1], argv[i+1], true)) {
+ i++;
+ continue;
+ }
+ }
+ // If it's -<option> then it's not recognised - error
+ // If it's <host> then add it to the list to connect to.
+ if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
+ const char* fmt = "The option %s was not recognized. Use -help to see VNC Viewer usage";
+ CharArray tmp(strlen(argv[i])+strlen(fmt)+1);
+ sprintf(tmp.buf, fmt, argv[i]);
+ MsgBox(0, TStr(tmp.buf), MB_ICONSTOP | MB_OK);
+ exit(1);
+ } else {
+ hosts.push_back(strDup(argv[i]));
+ }
+ }
+
+ } catch (rdr::Exception& e) {
+ vlog.error(e.str());
+ }
+ }
+}
+
+
+//
+// -=- main
+//
+
+int WINAPI WinMain(HINSTANCE inst, HINSTANCE prevInst, char* cmdLine, int cmdShow) {
+
+ try {
+
+ // - Initialise the available loggers
+ initStdIOLoggers();
+ initFileLogger("C:\\temp\\vncviewer4.log");
+
+ // - By default, just log errors to stderr
+ logParams.setDefault("*:stderr:0");
+
+ // - Process the command-line
+ int argc = __argc;
+ char** argv = __argv;
+ processParams(argc, argv);
+
+ // - By default the console will be closed
+ if (close_console) {
+ if (!FreeConsole())
+ vlog.info("unable to close console:%u", GetLastError());
+ } else {
+ AllocConsole();
+ freopen("CONIN$","rb",stdin);
+ freopen("CONOUT$","wb",stdout);
+ freopen("CONOUT$","wb",stderr);
+ setbuf(stderr, 0);
+ }
+
+#ifdef _DIALOG_CAPTURE
+ if (captureDialogs) {
+ CView::userConfigKey.openKey(HKEY_CURRENT_USER, _T("Software\\RealVNC\\VNCViewer4"));
+ OptionsDialog::global.showDialog(0, true);
+ return 0;
+ }
+#endif
+
+ // - If no clients are specified, bring up a connection dialog
+ if (configFiles.empty() && hosts.empty() && !acceptIncoming && !print_usage)
+ hosts.push_back(0);
+
+ programInfo();
+
+ // - 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\\RealVNC\\VNCViewer4"));
+
+ // - Tell the rest of VNC Viewer where to write config data to
+ CView::userConfigKey.openKey(HKEY_CURRENT_USER, _T("Software\\RealVNC\\VNCViewer4"));
+
+ // - Start the Socket subsystem for TCP
+ TcpSocket::initTcpSockets();
+
+ // Create the client connection manager
+ CViewManager view_manager;
+
+ if (acceptIncoming) {
+ int port = 5500;
+
+ // Listening viewer
+ if (hosts.size() > 1) {
+ programUsage();
+ exit(2);
+ }
+ if (!hosts.empty()) {
+ port = atoi(hosts.front());
+ }
+
+ vlog.debug("opening listener");
+
+ CViewTrayIcon tray(view_manager);
+
+ view_manager.addDefaultTCPListener(port);
+
+ // Run the view manager
+ // Also processes the tray icon if necessary
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0) > 0) {
+ 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);
+ strFree(filename);
+ configFiles.pop_front();
+ }
+
+ // Connect to each client in turn
+ while (!hosts.empty()) {
+ char* hostinfo = hosts.front();
+ view_manager.addClient(hostinfo);
+ strFree(hostinfo);
+ hosts.pop_front();
+ }
+
+ // Run the view manager
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0) > 0) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ vlog.debug("quitting viewer");
+ }
+
+ }
+
+ // - If necessary, print the program's usage info
+ if (print_usage)
+ programUsage();
+
+ if (!close_console) {
+ printf("Press Enter/Return key to continue\n");
+ char c = getchar();
+ }
+
+ } catch (rdr::Exception& e) {
+ MsgBox(0, TStr(e.str()), MB_ICONSTOP | MB_OK);
+ }
+
+ return 0;
+}
diff --git a/vncviewer/vncviewer.dsp b/vncviewer/vncviewer.dsp
new file mode 100644
index 00000000..25d358f8
--- /dev/null
+++ b/vncviewer/vncviewer.dsp
@@ -0,0 +1,229 @@
+# Microsoft Developer Studio Project File - Name="vncviewer" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=vncviewer - Win32 Debug Unicode
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "vncviewer.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "vncviewer.mak" CFG="vncviewer - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "vncviewer - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "vncviewer - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "vncviewer - Win32 Debug Unicode" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "vncviewer - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "..\Release"
+# PROP Intermediate_Dir "Release"
+# 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 BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib comdlg32.lib /nologo /subsystem:windows /machine:I386
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Desc=Updating buildTime
+PreLink_Cmds=cl /c /nologo /FoRelease\ /FdRelease\ /MT buildTime.cxx
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "vncviewer - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug"
+# PROP Intermediate_Dir "Debug"
+# 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" /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib comdlg32.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386 /pdbtype:sept
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Desc=Updating buildTime
+PreLink_Cmds=cl /c /nologo /FoDebug\ /FdDebug\ /MTd buildTime.cxx
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "vncviewer - Win32 Debug Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "vncviewer___Win32_Debug_Unicode"
+# PROP BASE Intermediate_Dir "vncviewer___Win32_Debug_Unicode"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "..\Debug_Unicode"
+# PROP Intermediate_Dir "Debug_Unicode"
+# 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 BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 user32.lib gdi32.lib advapi32.lib ws2_32.lib version.lib comctl32.lib shell32.lib comdlg32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PreLink_Desc=Updating buildTime
+PreLink_Cmds=cl /c /nologo /FoDebug_Unicode\ /FdDebug_Unicode\ /MTd buildTime.cxx
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "vncviewer - Win32 Release"
+# Name "vncviewer - Win32 Debug"
+# Name "vncviewer - Win32 Debug Unicode"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\buildTime.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConnectionDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\cview.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CViewManager.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CViewOptions.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\InfoDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\OptionsDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\UserPasswdDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncviewer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncviewer.rc
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\ConnectingDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConnectionDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\cview.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CViewManager.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CViewOptions.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\InfoDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MRU.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\OptionsDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UserPasswdDialog.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\cursor1.cur
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncviewer.exe.manifest
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncviewer.ico
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/vncviewer/vncviewer.exe.manifest b/vncviewer/vncviewer.exe.manifest
new file mode 100644
index 00000000..557e4563
--- /dev/null
+++ b/vncviewer/vncviewer.exe.manifest
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity
+ version="4.0.0.26"
+ processorArchitecture="X86"
+ name="RealVNC.vncviewer.exe"
+ type="win32"
+/>
+<description>.NET control deployment tool</description>
+<dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32"
+ name="Microsoft.Windows.Common-Controls"
+ version="6.0.0.0"
+ processorArchitecture="X86"
+ publicKeyToken="6595b64144ccf1df"
+ language="*"
+ />
+ </dependentAssembly>
+</dependency>
+</assembly>
diff --git a/vncviewer/vncviewer.ico b/vncviewer/vncviewer.ico
new file mode 100644
index 00000000..98e5578d
--- /dev/null
+++ b/vncviewer/vncviewer.ico
Binary files differ
diff --git a/vncviewer/vncviewer.rc b/vncviewer/vncviewer.rc
new file mode 100644
index 00000000..bd9ab6d0
--- /dev/null
+++ b/vncviewer/vncviewer.rc
@@ -0,0 +1,500 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+#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
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON ICON DISCARDABLE "vncviewer.ico"
+
+#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"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "Comments", "\0"
+ VALUE "CompanyName", "RealVNC Ltd.\0"
+ VALUE "FileDescription", "VNC Viewer for Win32\0"
+ VALUE "FileVersion", "4.0\0"
+ VALUE "InternalName", "VNCViewer 4.0\0"
+ VALUE "LegalCopyright", "Copyright © RealVNC Ltd. 2002-2004\0"
+ VALUE "LegalTrademarks", "RealVNC\0"
+ VALUE "OriginalFilename", "vncviewer.exe\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "VNC Viewer 4.0\0"
+ VALUE "ProductVersion", "4.0\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x809, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_VNC_AUTH_DLG DIALOG DISCARDABLE 0, 0, 241, 46
+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 |
+ 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
+END
+
+IDD_CONNECTING_DLG DIALOG DISCARDABLE 0, 0, 185, 47
+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
+ 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
+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 |
+ 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
+END
+
+IDD_ABOUT DIALOG DISCARDABLE 0, 0, 249, 92
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
+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
+ 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.realvnc.com for more information on VNC.",
+ IDC_STATIC,40,55,202,15
+END
+
+IDD_FORMAT DIALOG DISCARDABLE 0, 0, 201, 101
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Colour/Encoding"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "&Auto select",IDC_ENCODING_AUTO,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,7,88,13
+ GROUPBOX "Preferred encoding",IDC_STATIC,7,25,83,60
+ CONTROL "ZRLE",IDC_ENCODING_ZRLE,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,10,35,75,14
+ CONTROL "Hextile",IDC_ENCODING_HEXTILE,"Button",
+ BS_AUTORADIOBUTTON,10,49,75,16
+ CONTROL "Raw",IDC_ENCODING_RAW,"Button",BS_AUTORADIOBUTTON,10,65,
+ 75,15
+ GROUPBOX "Colour level",IDC_STATIC,95,10,99,75
+ CONTROL "&Full (all available colours)",IDC_FORMAT_FULLCOLOUR,
+ "Button",BS_AUTORADIOBUTTON | WS_GROUP,100,20,90,15
+ CONTROL "&Medium (256 colours)",IDC_FORMAT_MEDIUMCOLOUR,"Button",
+ BS_AUTORADIOBUTTON,100,35,90,14
+ CONTROL "&Low (64 colours)",IDC_FORMAT_LOWCOLOUR,"Button",
+ BS_AUTORADIOBUTTON,100,49,90,16
+ CONTROL "&Very low (8 colours)",IDC_FORMAT_VERYLOWCOLOUR,"Button",
+ BS_AUTORADIOBUTTON,100,65,90,15
+END
+
+IDD_MISC DIALOG DISCARDABLE 0, 0, 213, 137
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Misc"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "Shared connection (do not disconnect other viewers)",
+ 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
+ CONTROL "Render cursor locally",IDC_LOCAL_CURSOR,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,40,199,15
+ CONTROL "Allow dynamic desktop resizing",IDC_DESKTOP_RESIZE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,55,199,15
+ 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,86,199,15
+END
+
+IDD_INPUTS DIALOG DISCARDABLE 0, 0, 186, 138
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Inputs"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "Send pointer events to server",IDC_SEND_POINTER,"Button",
+ 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 clipboard changes to server",IDC_CLIENT_CUTTEXT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,40,172,15
+ CONTROL "Accept clipboard changes from server",
+ IDC_SERVER_CUTTEXT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 7,55,172,15
+ CONTROL "Enable 3-button mouse emulation",IDC_EMULATE3,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,70,172,15
+ CONTROL "Rate-limit mouse move events",IDC_POINTER_INTERVAL,
+ "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
+END
+
+IDD_CONNECTION_INFO DIALOG DISCARDABLE 0, 0, 239, 186
+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
+ 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
+ LTEXT "Pixel Format:",IDC_STATIC,7,55,73,15
+ LTEXT "Server Default:",IDC_STATIC,7,70,73,15
+ LTEXT "Line Speed Estimate:",IDC_STATIC,7,115,73,15
+ LTEXT "Protocol Version:",IDC_STATIC,7,130,73,15
+ LTEXT "",IDC_INFO_NAME,80,10,152,15
+ LTEXT "",IDC_INFO_HOST,80,25,152,15
+ LTEXT "",IDC_INFO_SIZE,80,40,152,15
+ LTEXT "",IDC_INFO_PF,80,55,152,15
+ LTEXT "",IDC_INFO_DEF_PF,80,70,152,15
+ LTEXT "",IDC_INFO_LINESPEED,80,115,152,15
+ LTEXT "",IDC_INFO_VERSION,80,130,152,15
+ LTEXT "Security Method:",IDC_STATIC,7,145,73,15
+ LTEXT "",IDC_INFO_SECURITY,80,145,152,15
+ LTEXT "Requested Encoding:",IDC_STATIC,7,85,73,15
+ 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
+END
+
+IDD_DEFAULTS DIALOG DISCARDABLE 0, 0, 131, 113
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Defaults"
+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
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_VNC_AUTH_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 234
+ VERTGUIDE, 35
+ VERTGUIDE, 70
+ VERTGUIDE, 75
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 40
+ HORZGUIDE, 20
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ END
+
+ IDD_CONNECTING_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 178
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 40
+ HORZGUIDE, 21
+ HORZGUIDE, 26
+ END
+
+ 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
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 47
+ HORZGUIDE, 20
+ HORZGUIDE, 30
+ HORZGUIDE, 40
+ END
+
+ IDD_ABOUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 242
+ VERTGUIDE, 40
+ VERTGUIDE, 165
+ VERTGUIDE, 195
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 85
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ END
+
+ IDD_FORMAT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 194
+ VERTGUIDE, 10
+ VERTGUIDE, 85
+ VERTGUIDE, 90
+ VERTGUIDE, 95
+ VERTGUIDE, 100
+ VERTGUIDE, 105
+ VERTGUIDE, 190
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 94
+ HORZGUIDE, 10
+ HORZGUIDE, 20
+ HORZGUIDE, 25
+ HORZGUIDE, 35
+ HORZGUIDE, 49
+ HORZGUIDE, 65
+ HORZGUIDE, 80
+ HORZGUIDE, 85
+ END
+
+ IDD_MISC, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 206
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 130
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ HORZGUIDE, 85
+ HORZGUIDE, 100
+ END
+
+ IDD_INPUTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ VERTGUIDE, 105
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 131
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ HORZGUIDE, 85
+ HORZGUIDE, 100
+ HORZGUIDE, 115
+ END
+
+ IDD_CONNECTION_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 232
+ VERTGUIDE, 80
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 179
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ HORZGUIDE, 85
+ HORZGUIDE, 100
+ HORZGUIDE, 115
+ HORZGUIDE, 130
+ HORZGUIDE, 145
+ HORZGUIDE, 160
+ END
+
+ IDD_DEFAULTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 124
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 106
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 30
+ HORZGUIDE, 45
+ HORZGUIDE, 50
+ HORZGUIDE, 65
+ HORZGUIDE, 70
+ HORZGUIDE, 85
+ HORZGUIDE, 90
+ HORZGUIDE, 105
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_DOT_CURSOR CURSOR DISCARDABLE "cursor1.cur"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog Info
+//
+
+IDD_CONNECTION_DLG DLGINIT
+BEGIN
+ IDC_SERVER_EDIT, 0x403, 16, 0
+0x796d, 0x616d, 0x6863, 0x6e69, 0x2e65, 0x726f, 0x3a67, 0x0031,
+ 0
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_TRAY MENU DISCARDABLE
+BEGIN
+ POPUP "Tray Menu"
+ BEGIN
+ MENUITEM "&New Connection...", ID_NEW_CONNECTION
+ MENUITEM SEPARATOR
+ MENUITEM "Default &Options...", ID_OPTIONS
+ MENUITEM SEPARATOR
+ MENUITEM "&Close Daemon", ID_CLOSE
+ MENUITEM "&About...", ID_ABOUT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 24
+//
+
+IDR_MANIFEST 24 DISCARDABLE "vncviewer.exe.manifest"
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+