Migrating to new directory structure adopted from the RealVNC's source tree. More changes will follow.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@591 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/win/vncviewer/CConn.cxx b/win/vncviewer/CConn.cxx
new file mode 100644
index 0000000..73597f5
--- /dev/null
+++ b/win/vncviewer/CConn.cxx
@@ -0,0 +1,712 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <windows.h>
+#include <winsock2.h>
+#include <vncviewer/UserPasswdDialog.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/CConnThread.h>
+#include <vncviewer/resource.h>
+#include <rfb/encodings.h>
+#include <rfb/secTypes.h>
+#include <rfb/CSecurityNone.h>
+#include <rfb/CSecurityVncAuth.h>
+#include <rfb/CMsgWriter.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/AboutDialog.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+using namespace rdr;
+
+// - Statics & consts
+
+static LogWriter vlog("CConn");
+
+
+const int IDM_FULLSCREEN = ID_FULLSCREEN;
+const int IDM_SEND_MENU_KEY = ID_SEND_MENU_KEY;
+const int IDM_SEND_CAD = ID_SEND_CAD;
+const int IDM_SEND_CTLESC = ID_SEND_CTLESC;
+const int IDM_ABOUT = ID_ABOUT;
+const int IDM_OPTIONS = ID_OPTIONS;
+const int IDM_INFO = ID_INFO;
+const int IDM_NEWCONN = ID_NEW_CONNECTION;
+const int IDM_REQUEST_REFRESH = ID_REQUEST_REFRESH;
+const int IDM_CTRL_KEY = ID_CTRL_KEY;
+const int IDM_ALT_KEY = ID_ALT_KEY;
+const int IDM_FILE_TRANSFER = ID_FILE_TRANSFER;
+const int IDM_CONN_SAVE_AS = ID_CONN_SAVE_AS;
+
+
+static IntParameter debugDelay("DebugDelay","Milliseconds to display inverted "
+ "pixel data - a debugging feature", 0);
+
+
+//
+// -=- CConn implementation
+//
+
+RegKey CConn::userConfigKey;
+
+
+CConn::CConn()
+ : window(0), sock(0), sockEvent(CreateEvent(0, TRUE, FALSE, 0)), requestUpdate(false),
+ sameMachine(false), encodingChange(false), formatChange(false),
+ reverseConnection(false), lastUsedEncoding_(encodingRaw), isClosed_(false) {
+}
+
+CConn::~CConn() {
+ delete window;
+}
+
+bool CConn::initialise(network::Socket* s, bool reverse) {
+ // Set the server's name for MRU purposes
+ CharArray endpoint(s->getPeerEndpoint());
+ setServerName(endpoint.buf);
+ if (!options.host.buf)
+ options.setHost(endpoint.buf);
+
+ // Initialise the underlying CConnection
+ setStreams(&s->inStream(), &s->outStream());
+
+ // Enable processing of window messages while blocked on I/O
+ s->inStream().setBlockCallback(this);
+
+ // Initialise the viewer options
+ applyOptions(options);
+
+ // - Set which auth schemes we support, in order of preference
+ addSecType(secTypeVncAuth);
+ addSecType(secTypeNone);
+
+ // Start the RFB protocol
+ sock = s;
+ reverseConnection = reverse;
+ initialiseProtocol();
+
+ m_fileTransfer.initialize(&s->inStream(), &s->outStream());
+
+ return true;
+}
+
+
+void
+CConn::applyOptions(CConnOptions& opt) {
+ // - If any encoding-related settings have changed then we must
+ // notify the server of the new settings
+ encodingChange |= ((options.useLocalCursor != opt.useLocalCursor) ||
+ (options.useDesktopResize != opt.useDesktopResize) ||
+ (options.customCompressLevel != opt.customCompressLevel) ||
+ (options.compressLevel != opt.compressLevel) ||
+ (options.noJpeg != opt.noJpeg) ||
+ (options.qualityLevel != opt.qualityLevel) ||
+ (options.preferredEncoding != opt.preferredEncoding));
+
+ // - If the preferred pixel format has changed then notify the server
+ formatChange |= (options.fullColour != opt.fullColour);
+ if (!opt.fullColour)
+ formatChange |= (options.lowColourLevel != opt.lowColourLevel);
+
+ // - Save the new set of options
+ options = opt;
+
+ // - Set optional features in ConnParams
+ cp.supportsLocalCursor = options.useLocalCursor;
+ cp.supportsDesktopResize = options.useDesktopResize;
+ cp.customCompressLevel = options.customCompressLevel;
+ cp.compressLevel = options.compressLevel;
+ cp.noJpeg = options.noJpeg;
+ cp.qualityLevel = options.qualityLevel;
+
+ // - Configure connection sharing on/off
+ setShared(options.shared);
+
+ // - Whether to use protocol 3.3 for legacy compatibility
+ setProtocol3_3(options.protocol3_3);
+
+ // - Apply settings that affect the window, if it is visible
+ if (window) {
+ window->setMonitor(options.monitor.buf);
+ window->setFullscreen(options.fullScreen);
+ window->setEmulate3(options.emulate3);
+ window->setPointerEventInterval(options.pointerEventInterval);
+ window->setMenuKey(options.menuKey);
+ window->setDisableWinKeys(options.disableWinKeys);
+ window->setShowToolbar(options.showToolbar);
+ if (!options.useLocalCursor)
+ window->setCursor(0, 0, Point(), 0, 0);
+ }
+}
+
+
+void
+CConn::displayChanged() {
+ // Display format has changed - recalculate the full-colour pixel format
+ calculateFullColourPF();
+}
+
+void
+CConn::paintCompleted() {
+ // A repaint message has just completed - request next update if necessary
+ requestNewUpdate();
+}
+
+bool
+CConn::sysCommand(WPARAM wParam, LPARAM lParam) {
+ // - If it's one of our (F8 Menu) messages
+ switch (wParam) {
+ case IDM_FULLSCREEN:
+ options.fullScreen = !window->isFullscreen();
+ window->setFullscreen(options.fullScreen);
+ return true;
+ case IDM_SHOW_TOOLBAR:
+ options.showToolbar = !window->isToolbarEnabled();
+ window->setShowToolbar(options.showToolbar);
+ return true;
+ case IDM_CTRL_KEY:
+ window->kbd.keyEvent(this, VK_CONTROL, 0, !window->kbd.keyPressed(VK_CONTROL));
+ return true;
+ case IDM_ALT_KEY:
+ window->kbd.keyEvent(this, VK_MENU, 0, !window->kbd.keyPressed(VK_MENU));
+ return true;
+ case IDM_SEND_MENU_KEY:
+ window->kbd.keyEvent(this, options.menuKey, 0, true);
+ window->kbd.keyEvent(this, options.menuKey, 0, false);
+ return true;
+ case IDM_SEND_CAD:
+ window->kbd.keyEvent(this, VK_CONTROL, 0, true);
+ window->kbd.keyEvent(this, VK_MENU, 0, true);
+ window->kbd.keyEvent(this, VK_DELETE, 0x1000000, true);
+ window->kbd.keyEvent(this, VK_DELETE, 0x1000000, false);
+ window->kbd.keyEvent(this, VK_MENU, 0, false);
+ window->kbd.keyEvent(this, VK_CONTROL, 0, false);
+ return true;
+ case IDM_SEND_CTLESC:
+ window->kbd.keyEvent(this, VK_CONTROL, 0, true);
+ window->kbd.keyEvent(this, VK_ESCAPE, 0, true);
+ window->kbd.keyEvent(this, VK_ESCAPE, 0, false);
+ window->kbd.keyEvent(this, VK_CONTROL, 0, false);
+ return true;
+ case IDM_REQUEST_REFRESH:
+ try {
+ writer()->writeFramebufferUpdateRequest(Rect(0,0,cp.width,cp.height), false);
+ requestUpdate = false;
+ } catch (rdr::Exception& e) {
+ close(e.str());
+ }
+ return true;
+ case IDM_NEWCONN:
+ {
+ Thread* newThread = new CConnThread;
+ }
+ return true;
+ case IDM_OPTIONS:
+ // Update the monitor device name in the CConnOptions instance
+ options.monitor.replaceBuf(window->getMonitor());
+ showOptionsDialog();
+ return true;
+ case IDM_INFO:
+ infoDialog.showDialog(this);
+ return true;
+ case IDM_ABOUT:
+ AboutDialog::instance.showDialog();
+ return true;
+ case IDM_FILE_TRANSFER:
+ m_fileTransfer.show(window->getHandle());
+ return true;
+ case IDM_CONN_SAVE_AS:
+ return true;
+ case ID_CLOSE:
+ // FIXME: Remove the corresponding toolbar button.
+ return true;
+ };
+ return false;
+}
+
+
+void
+CConn::closeWindow() {
+ vlog.info("window closed");
+ close();
+}
+
+
+void
+CConn::refreshMenu(bool enableSysItems) {
+ HMENU menu = GetSystemMenu(window->getHandle(), FALSE);
+
+ if (!enableSysItems) {
+ // Gray out menu items that might cause a World Of Pain
+ EnableMenuItem(menu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
+ EnableMenuItem(menu, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
+ EnableMenuItem(menu, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED);
+ EnableMenuItem(menu, SC_MINIMIZE, MF_BYCOMMAND | MF_ENABLED);
+ EnableMenuItem(menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_ENABLED);
+ }
+
+ // Update the modifier key menu items
+ UINT ctrlCheckFlags = window->kbd.keyPressed(VK_CONTROL) ? MF_CHECKED : MF_UNCHECKED;
+ UINT altCheckFlags = window->kbd.keyPressed(VK_MENU) ? MF_CHECKED : MF_UNCHECKED;
+ CheckMenuItem(menu, IDM_CTRL_KEY, MF_BYCOMMAND | ctrlCheckFlags);
+ CheckMenuItem(menu, IDM_ALT_KEY, MF_BYCOMMAND | altCheckFlags);
+
+ // Ensure that the Send <MenuKey> menu item has the correct text
+ if (options.menuKey) {
+ TCharArray menuKeyStr(options.menuKeyName());
+ TCharArray tmp(_tcslen(menuKeyStr.buf) + 6);
+ _stprintf(tmp.buf, _T("Send %s"), menuKeyStr.buf);
+ if (!ModifyMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf))
+ InsertMenu(menu, IDM_SEND_CAD, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf);
+ } else {
+ RemoveMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND);
+ }
+
+ // Set the menu fullscreen option tick
+ CheckMenuItem(menu, IDM_FULLSCREEN, (window->isFullscreen() ? MF_CHECKED : 0) | MF_BYCOMMAND);
+
+ // Set the menu toolbar option tick
+ int toolbarFlags = window->isToolbarEnabled() ? MF_CHECKED : 0;
+ CheckMenuItem(menu, IDM_SHOW_TOOLBAR, MF_BYCOMMAND | toolbarFlags);
+
+ // In the full-screen mode, "Show toolbar" should be grayed.
+ toolbarFlags = window->isFullscreen() ? MF_GRAYED : MF_ENABLED;
+ EnableMenuItem(menu, IDM_SHOW_TOOLBAR, MF_BYCOMMAND | toolbarFlags);
+}
+
+
+void
+CConn::blockCallback() {
+ // - An InStream has blocked on I/O while processing an RFB message
+ // We re-enable socket event notifications, so we'll know when more
+ // data is available, then we sit and dispatch window events until
+ // the notification arrives.
+ if (!isClosed()) {
+ if (WSAEventSelect(sock->getFd(), sockEvent, FD_READ | FD_CLOSE) == SOCKET_ERROR)
+ throw rdr::SystemException("Unable to wait for sokcet data", WSAGetLastError());
+ }
+ while (true) {
+ // If we have closed then we can't block waiting for data
+ if (isClosed())
+ throw rdr::EndOfStream();
+
+ // Wait for socket data, or a message to process
+ DWORD result = MsgWaitForMultipleObjects(1, &sockEvent.h, FALSE, INFINITE, QS_ALLINPUT);
+ if (result == WAIT_OBJECT_0) {
+ // - Network event notification. Return control to I/O routine.
+ break;
+ } else if (result == WAIT_FAILED) {
+ // - The wait operation failed - raise an exception
+ throw rdr::SystemException("blockCallback wait error", GetLastError());
+ }
+
+ // - There should be a message in the message queue
+ MSG msg;
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ // IMPORTANT: We mustn't call TranslateMessage() here, because instead we
+ // call ToAscii() in CKeyboard::keyEvent(). ToAscii() stores dead key
+ // state from one call to the next, which would be messed up by calls to
+ // TranslateMessage() (actually it looks like TranslateMessage() calls
+ // ToAscii() internally).
+ DispatchMessage(&msg);
+ }
+ }
+
+ // Before we return control to the InStream, reset the network event
+ WSAEventSelect(sock->getFd(), sockEvent, 0);
+ ResetEvent(sockEvent);
+}
+
+
+void CConn::keyEvent(rdr::U32 key, bool down) {
+ if (!options.sendKeyEvents) return;
+ try {
+ writer()->keyEvent(key, down);
+ } catch (rdr::Exception& e) {
+ close(e.str());
+ }
+}
+void CConn::pointerEvent(const Point& pos, int buttonMask) {
+ if (!options.sendPtrEvents) return;
+ try {
+ writer()->pointerEvent(pos, buttonMask);
+ } catch (rdr::Exception& e) {
+ close(e.str());
+ }
+}
+void CConn::clientCutText(const char* str, int len) {
+ if (!options.clientCutText) return;
+ if (state() != RFBSTATE_NORMAL) return;
+ try {
+ writer()->clientCutText(str, len);
+ } catch (rdr::Exception& e) {
+ close(e.str());
+ }
+}
+
+
+CSecurity* CConn::getCSecurity(int secType)
+{
+ switch (secType) {
+ case secTypeNone:
+ return new CSecurityNone();
+ case secTypeVncAuth:
+ return new CSecurityVncAuth(this);
+ default:
+ throw Exception("Unsupported secType?");
+ }
+}
+
+
+void
+CConn::setColourMapEntries(int first, int count, U16* rgbs) {
+ vlog.debug("setColourMapEntries: first=%d, count=%d", first, count);
+ int i;
+ for (i=0;i<count;i++)
+ window->setColour(i+first, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]);
+ // *** change to 0, 256?
+ window->refreshWindowPalette(first, count);
+}
+
+void
+CConn::bell() {
+ if (options.acceptBell)
+ MessageBeep(-1);
+}
+
+
+void
+CConn::setDesktopSize(int w, int h) {
+ vlog.debug("setDesktopSize %dx%d", w, h);
+
+ // Resize the window's buffer
+ if (window)
+ window->setSize(w, h);
+
+ // Tell the underlying CConnection
+ CConnection::setDesktopSize(w, h);
+}
+
+void
+CConn::setCursor(int w, int h, const Point& hotspot, void* data, void* mask) {
+ if (!options.useLocalCursor) return;
+
+ // Set the window to use the new cursor
+ window->setCursor(w, h, hotspot, data, mask);
+}
+
+
+void
+CConn::close(const char* reason) {
+ // If already closed then ignore this
+ if (isClosed())
+ return;
+
+ // Hide the window, if it exists
+ if (window)
+ ShowWindow(window->getHandle(), SW_HIDE);
+
+ // Save the reason & flag that we're closed & shutdown the socket
+ isClosed_ = true;
+ closeReason_.replaceBuf(strDup(reason));
+ sock->shutdown();
+}
+
+
+void
+CConn::showOptionsDialog() {
+ optionsDialog.showDialog(this);
+}
+
+
+void
+CConn::framebufferUpdateEnd() {
+ if (debugDelay != 0) {
+ vlog.debug("debug delay %d",(int)debugDelay);
+ UpdateWindow(window->getHandle());
+ Sleep(debugDelay);
+ std::list<rfb::Rect>::iterator i;
+ for (i = debugRects.begin(); i != debugRects.end(); i++) {
+ window->invertRect(*i);
+ }
+ debugRects.clear();
+ }
+ if (options.autoSelect)
+ autoSelectFormatAndEncoding();
+
+ // Always request the next update
+ requestUpdate = true;
+
+ // Check that at least part of the window has changed
+ if (!GetUpdateRect(window->getHandle(), 0, FALSE)) {
+ if (!(GetWindowLong(window->getHandle(), GWL_STYLE) & WS_MINIMIZE))
+ requestNewUpdate();
+ }
+
+ // Make sure the local cursor is shown
+ window->showCursor();
+}
+
+
+// Note: The method below is duplicated in vncviewer_unix/CConn.cxx!
+
+// autoSelectFormatAndEncoding() chooses the format and encoding appropriate
+// to the connection speed:
+//
+// Above 16Mbps (timing for at least a second), switch to hextile
+// Otherwise, switch to ZRLE
+//
+// Above 256Kbps, use full colour mode
+//
+void
+CConn::autoSelectFormatAndEncoding() {
+ int kbitsPerSecond = sock->inStream().kbitsPerSecond();
+ unsigned int newEncoding = options.preferredEncoding;
+
+ bool newFullColour = options.fullColour;
+ unsigned int timeWaited = sock->inStream().timeWaited();
+
+ // Select best encoding
+ if (kbitsPerSecond > 16000 && timeWaited >= 10000) {
+ newEncoding = encodingHextile;
+ } else {
+ newEncoding = encodingZRLE;
+ }
+
+ if (newEncoding != options.preferredEncoding) {
+ vlog.info("Throughput %d kbit/s - changing to %s encoding",
+ kbitsPerSecond, encodingName(newEncoding));
+ options.preferredEncoding = newEncoding;
+ encodingChange = true;
+ }
+
+ if (kbitsPerSecond == 0) {
+ return;
+ }
+
+ if (cp.beforeVersion(3, 8)) {
+ // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with
+ // cursors "asynchronously". If this happens in the middle of a
+ // pixel format change, the server will encode the cursor with
+ // the old format, but the client will try to decode it
+ // according to the new format. This will lead to a
+ // crash. Therefore, we do not allow automatic format change for
+ // old servers.
+ return;
+ }
+
+ // Select best color level
+ newFullColour = (kbitsPerSecond > 256);
+ if (newFullColour != options.fullColour) {
+ vlog.info("Throughput %d kbit/s - full color is now %s",
+ kbitsPerSecond,
+ newFullColour ? "enabled" : "disabled");
+ options.fullColour = newFullColour;
+ formatChange = true;
+ }
+}
+
+void
+CConn::requestNewUpdate() {
+ if (!requestUpdate) return;
+
+ if (formatChange) {
+ // Select the required pixel format
+ if (options.fullColour) {
+ window->setPF(fullColourPF);
+ } else {
+ switch (options.lowColourLevel) {
+ case 0:
+ window->setPF(PixelFormat(8,3,0,1,1,1,1,2,1,0));
+ break;
+ case 1:
+ window->setPF(PixelFormat(8,6,0,1,3,3,3,4,2,0));
+ break;
+ case 2:
+ window->setPF(PixelFormat(8,8,0,0,0,0,0,0,0,0));
+ break;
+ }
+ }
+
+ // Print the current pixel format
+ char str[256];
+ window->getPF().print(str, 256);
+ vlog.info("Using pixel format %s",str);
+
+ // Save the connection pixel format and tell server to use it
+ cp.setPF(window->getPF());
+ writer()->writeSetPixelFormat(cp.pf());
+
+ // Correct the local window's palette
+ if (!window->getNativePF().trueColour)
+ window->refreshWindowPalette(0, 1 << cp.pf().depth);
+ }
+
+ if (encodingChange) {
+ vlog.info("Using %s encoding",encodingName(options.preferredEncoding));
+ writer()->writeSetEncodings(options.preferredEncoding, true);
+ }
+
+ writer()->writeFramebufferUpdateRequest(Rect(0, 0, cp.width, cp.height),
+ !formatChange);
+
+ encodingChange = formatChange = requestUpdate = false;
+}
+
+
+void
+CConn::calculateFullColourPF() {
+ // If the server is palette based then use palette locally
+ // Also, don't bother doing bgr222
+ if (!serverDefaultPF.trueColour || (serverDefaultPF.depth < 6)) {
+ fullColourPF = serverDefaultPF;
+ options.fullColour = true;
+ } else {
+ // If server is trueColour, use lowest depth PF
+ PixelFormat native = window->getNativePF();
+ if ((serverDefaultPF.bpp < native.bpp) ||
+ ((serverDefaultPF.bpp == native.bpp) &&
+ (serverDefaultPF.depth < native.depth)))
+ fullColourPF = serverDefaultPF;
+ else
+ fullColourPF = window->getNativePF();
+ }
+ formatChange = true;
+}
+
+
+void
+CConn::setName(const char* name) {
+ if (window)
+ window->setName(name);
+ CConnection::setName(name);
+}
+
+
+void CConn::serverInit() {
+ CConnection::serverInit();
+
+ // If using AutoSelect with old servers, start in FullColor
+ // mode. See comment in autoSelectFormatAndEncoding.
+ if (cp.beforeVersion(3, 8) && options.autoSelect) {
+ options.fullColour = true;
+ }
+
+ // Show the window
+ window = new DesktopWindow(this);
+ window->setName(cp.name());
+ window->setSize(cp.width, cp.height);
+ applyOptions(options);
+
+ // Save the server's current format
+ serverDefaultPF = cp.pf();
+
+ // Calculate the full-colour format to use
+ calculateFullColourPF();
+
+ // Request the initial update
+ vlog.info("requesting initial update");
+ formatChange = encodingChange = requestUpdate = true;
+ requestNewUpdate();
+
+ // Update the window menu
+ HMENU wndmenu = GetSystemMenu(window->getHandle(), FALSE);
+ int toolbarChecked = options.showToolbar ? MF_CHECKED : 0;
+
+ AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
+ AppendMenu(wndmenu, MF_STRING, IDM_FULLSCREEN, _T("&Full screen"));
+ AppendMenu(wndmenu, MF_STRING | toolbarChecked, IDM_SHOW_TOOLBAR,
+ _T("Show tool&bar"));
+ AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
+ AppendMenu(wndmenu, MF_STRING, IDM_CTRL_KEY, _T("Ctr&l"));
+ AppendMenu(wndmenu, MF_STRING, IDM_ALT_KEY, _T("Al&t"));
+ AppendMenu(wndmenu, MF_STRING, IDM_SEND_CAD, _T("Send Ctrl-Alt-&Del"));
+ AppendMenu(wndmenu, MF_STRING, IDM_SEND_CTLESC, _T("Send Ctrl-&Esc"));
+ AppendMenu(wndmenu, MF_STRING, IDM_REQUEST_REFRESH, _T("Refres&h Screen"));
+ AppendMenu(wndmenu, MF_SEPARATOR, 0, 0);
+ AppendMenu(wndmenu, MF_STRING, IDM_NEWCONN, _T("Ne&w Connection..."));
+ AppendMenu(wndmenu, MF_STRING, IDM_OPTIONS, _T("&Options..."));
+ AppendMenu(wndmenu, MF_STRING, IDM_INFO, _T("Connection &Info..."));
+ AppendMenu(wndmenu, MF_STRING, IDM_ABOUT, _T("&About..."));
+}
+
+void
+CConn::serverCutText(const char* str, int len) {
+ if (!options.serverCutText) return;
+ window->serverCutText(str, len);
+}
+
+
+void CConn::beginRect(const Rect& r, unsigned int encoding) {
+ sock->inStream().startTiming();
+}
+
+void CConn::endRect(const Rect& r, unsigned int encoding) {
+ sock->inStream().stopTiming();
+ lastUsedEncoding_ = encoding;
+ if (debugDelay != 0) {
+ window->invertRect(r);
+ debugRects.push_back(r);
+ }
+}
+
+void CConn::fillRect(const Rect& r, Pixel pix) {
+ window->fillRect(r, pix);
+}
+void CConn::imageRect(const Rect& r, void* pixels) {
+ window->imageRect(r, pixels);
+}
+void CConn::copyRect(const Rect& r, int srcX, int srcY) {
+ window->copyRect(r, srcX, srcY);
+}
+
+void CConn::getUserPasswd(char** user, char** password) {
+ if (!user && options.passwordFile.buf[0]) {
+ FILE* fp = fopen(options.passwordFile.buf, "rb");
+ if (fp) {
+ char data[256];
+ int datalen = fread(data, 1, 256, fp);
+ fclose(fp);
+ if (datalen == 8) {
+ ObfuscatedPasswd obfPwd;
+ obfPwd.buf = data;
+ obfPwd.length = datalen;
+ PlainPasswd passwd(obfPwd);
+ *password = strDup(passwd.buf);
+ memset(data, 0, strlen(data));
+ }
+ }
+ }
+ if (user && options.userName.buf)
+ *user = strDup(options.userName.buf);
+ if (password && options.password.buf)
+ *password = strDup(options.password.buf);
+ if ((user && !*user) || (password && !*password)) {
+ // Missing username or password - prompt the user
+ UserPasswdDialog userPasswdDialog;
+ userPasswdDialog.setCSecurity(getCurrentCSecurity());
+ userPasswdDialog.getUserPasswd(user, password);
+ }
+ if (user) options.setUserName(*user);
+ if (password) options.setPassword(*password);
+}
+
+bool CConn::processFTMsg(int type) {
+ return m_fileTransfer.processFTMsg(type);
+}
diff --git a/win/vncviewer/CConn.h b/win/vncviewer/CConn.h
new file mode 100644
index 0000000..29023f3
--- /dev/null
+++ b/win/vncviewer/CConn.h
@@ -0,0 +1,165 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- CConn.h
+
+// Windows-specific implementation of CConnection
+
+#ifndef __RFB_WIN32_CCONN_H__
+#define __RFB_WIN32_CCONN_H__
+
+#include <network/Socket.h>
+#include <rfb/CConnection.h>
+#include <rfb/Cursor.h>
+#include <rfb/UserPasswdGetter.h>
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/Handle.h>
+#include <vncviewer/InfoDialog.h>
+#include <vncviewer/OptionsDialog.h>
+#include <vncviewer/CConnOptions.h>
+#include <vncviewer/DesktopWindow.h>
+#include <vncviewer/FileTransfer.h>
+#include <list>
+
+
+namespace rfb {
+
+ namespace win32 {
+
+ class CConn : public CConnection,
+ UserPasswdGetter,
+ DesktopWindow::Callback,
+ rdr::FdInStreamBlockCallback
+ {
+ public:
+ CConn();
+ ~CConn();
+
+ // - Start the VNC session on the supplied socket
+ // The socket must already be connected to a host
+ bool initialise(network::Socket* s, bool reverse=false);
+
+ // - Set/get the session options
+ void applyOptions(CConnOptions& opt);
+ const CConnOptions& getOptions() const { return options; };
+
+ // - Show the options dialog for the connection
+ void showOptionsDialog();
+
+ // - Close the socket & set the reason for closure
+ void close(const char* reason=0);
+ bool isClosed() const { return isClosed_; }
+ const char* closeReason() const { return closeReason_.buf; }
+
+ // - Last received encoding, for the Info dialog
+ int lastUsedEncoding() const { return lastUsedEncoding_; }
+
+ // - Get at the DesktopWindow, if any
+ DesktopWindow* getWindow() { return window; }
+
+ // - Get at the underlying Socket
+ network::Socket* getSocket() { return sock; }
+
+ // - Get the server's preferred format
+ const PixelFormat& getServerDefaultPF() const { return serverDefaultPF; }
+
+ // Global user-config registry key
+ static RegKey userConfigKey;
+
+ bool processFTMsg(int type);
+
+ protected:
+ // InputHandler interface (via DesktopWindow::Callback)
+ void keyEvent(rdr::U32 key, bool down);
+ void pointerEvent(const Point& pos, int buttonMask);
+ void clientCutText(const char* str, int len);
+
+ // DesktopWindow::Callback interface
+ void displayChanged();
+ void paintCompleted();
+ bool sysCommand(WPARAM wParam, LPARAM lParam);
+ void closeWindow();
+ void refreshMenu(bool enableSysCommands);
+
+ // CConnection interface
+ CSecurity* getCSecurity(int secType);
+ void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs);
+ void bell();
+ void framebufferUpdateEnd();
+ void setDesktopSize(int w, int h);
+ void setCursor(int w, int h, const Point& hotspot, void* data, void* mask);
+ void setName(const char* name);
+ void serverInit();
+ void serverCutText(const char* str, int len);
+ void beginRect(const Rect& r, unsigned int encoding);
+ void endRect(const Rect& r, unsigned int encoding);
+ void fillRect(const Rect& r, Pixel pix);
+ void imageRect(const Rect& r, void* pixels);
+ void copyRect(const Rect& r, int srcX, int srcY);
+
+ // rdr::FdInStreamBlockCallback interface
+ void blockCallback();
+
+ // UserPasswdGetter interface
+ // (overridden to allow a pre-supplied username & password)
+ void getUserPasswd(char** user, char** password);
+
+ // CConn-specific internal interface
+ void autoSelectFormatAndEncoding();
+ void requestNewUpdate();
+ void calculateFullColourPF();
+
+ // The desktop window
+ DesktopWindow* window;
+
+ // Info and Options dialogs
+ OptionsDialog optionsDialog;
+ InfoDialog infoDialog;
+
+ // VNC Viewer options
+ CConnOptions options;
+
+ // Pixel format and encoding
+ PixelFormat serverDefaultPF;
+ PixelFormat fullColourPF;
+ bool sameMachine;
+ bool encodingChange;
+ bool formatChange;
+ int lastUsedEncoding_;
+
+ // Networking and RFB protocol
+ network::Socket* sock;
+ Handle sockEvent;
+ bool reverseConnection;
+ bool requestUpdate;
+
+ // Debugging/logging
+ std::list<Rect> debugRects;
+ CharArray closeReason_;
+ bool isClosed_;
+
+ FileTransfer m_fileTransfer;
+ };
+
+ };
+
+};
+
+#endif
+
+
diff --git a/win/vncviewer/CConnOptions.cxx b/win/vncviewer/CConnOptions.cxx
new file mode 100644
index 0000000..4ea0ada
--- /dev/null
+++ b/win/vncviewer/CConnOptions.cxx
@@ -0,0 +1,450 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <vncviewer/CConnOptions.h>
+#include <rfb/Configuration.h>
+#include <rfb/encodings.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/Registry.h>
+#include <rdr/HexInStream.h>
+#include <rdr/HexOutStream.h>
+#include <stdlib.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static StringParameter passwordFile("PasswordFile",
+ "Password file for VNC authentication", "");
+
+// - Settings stored in the registry & in .vnc files, by Save Defaults and
+// Save Configuration respectively.
+
+static BoolParameter useLocalCursor("UseLocalCursor", "Render the mouse cursor locally", true);
+static BoolParameter useDesktopResize("UseDesktopResize", "Support dynamic desktop resizing", true);
+
+static BoolParameter fullColour("FullColor",
+ "Use full color", true);
+static AliasParameter fullColourAlias("FullColour", "Alias for FullColor", &fullColour);
+
+static IntParameter lowColourLevel("LowColorLevel",
+ "Color level to use on slow connections. "
+ "0 = Very Low (8 colors), 1 = Low (64 colors), 2 = Medium (256 colors)",
+ 2);
+static AliasParameter lowColourLevelAlias("LowColourLevel", "Alias for LowColorLevel", &lowColourLevel);
+
+static BoolParameter fullScreen("FullScreen",
+ "Use the whole display to show the remote desktop."
+ "(Press F8 to access the viewer menu)",
+ false);
+static StringParameter preferredEncoding("PreferredEncoding",
+ "Preferred encoding to use (Tight, ZRLE, Hextile or"
+ " Raw)", "Tight");
+static BoolParameter autoSelect("AutoSelect",
+ "Auto select pixel format and encoding. "
+ "Default if PreferredEncoding and FullColor are not specified.",
+ true);
+static BoolParameter sharedConnection("Shared",
+ "Allow existing connections to the server to continue."
+ "(Default is to disconnect all other clients)",
+ false);
+
+static BoolParameter sendPtrEvents("SendPointerEvents",
+ "Send pointer (mouse) events to the server.", true);
+static BoolParameter sendKeyEvents("SendKeyEvents",
+ "Send key presses (and releases) to the server.", true);
+
+static BoolParameter clientCutText("ClientCutText",
+ "Send clipboard changes to the server.", true);
+static BoolParameter serverCutText("ServerCutText",
+ "Accept clipboard changes from the server.", true);
+
+static BoolParameter disableWinKeys("DisableWinKeys",
+ "Pass special Windows keys directly to the server.", true);
+
+static BoolParameter protocol3_3("Protocol3.3",
+ "Only use protocol version 3.3", false);
+
+static IntParameter ptrEventInterval("PointerEventInterval",
+ "The interval to delay between sending one pointer event "
+ "and the next.", 0);
+static BoolParameter emulate3("Emulate3",
+ "Emulate middle mouse button when left and right buttons "
+ "are used simulatenously.", false);
+
+static BoolParameter acceptBell("AcceptBell",
+ "Produce a system beep when requested to by the server.",
+ true);
+
+static BoolParameter showToolbar("ShowToolbar", "Show toolbar by default.", true);
+
+static StringParameter monitor("Monitor", "The monitor to open the VNC Viewer window on, if available.", "");
+static StringParameter menuKey("MenuKey", "The key which brings up the popup menu", "F8");
+static BoolParameter autoReconnect("AutoReconnect", "Offer to reconnect to the remote server if the connection"
+ "is dropped because an error occurs.", true);
+
+static BoolParameter customCompressLevel("CustomCompressLevel",
+ "Use custom compression level. "
+ "Default if CompressLevel is specified.", false);
+
+static IntParameter compressLevel("CompressLevel",
+ "Use specified compression level"
+ "0 = Low, 9 = High",
+ 6);
+
+static BoolParameter noJpeg("NoJPEG",
+ "Disable lossy JPEG compression in Tight encoding.",
+ false);
+
+static IntParameter qualityLevel("QualityLevel",
+ "JPEG quality level. "
+ "0 = Low, 9 = High",
+ 6);
+
+CConnOptions::CConnOptions()
+: useLocalCursor(::useLocalCursor), useDesktopResize(::useDesktopResize),
+autoSelect(::autoSelect), fullColour(::fullColour), fullScreen(::fullScreen),
+shared(::sharedConnection), sendPtrEvents(::sendPtrEvents), sendKeyEvents(::sendKeyEvents),
+preferredEncoding(encodingZRLE), clientCutText(::clientCutText), serverCutText(::serverCutText),
+disableWinKeys(::disableWinKeys), protocol3_3(::protocol3_3), acceptBell(::acceptBell),
+lowColourLevel(::lowColourLevel), pointerEventInterval(ptrEventInterval),
+emulate3(::emulate3), monitor(::monitor.getData()), showToolbar(::showToolbar),
+customCompressLevel(::customCompressLevel), compressLevel(::compressLevel),
+noJpeg(::noJpeg), qualityLevel(::qualityLevel), passwordFile(::passwordFile.getData()),
+autoReconnect(::autoReconnect)
+{
+ if (autoSelect) {
+ preferredEncoding = encodingZRLE;
+ } else {
+ CharArray encodingName(::preferredEncoding.getData());
+ preferredEncoding = encodingNum(encodingName.buf);
+ }
+ setMenuKey(CharArray(::menuKey.getData()).buf);
+
+ if (!::autoSelect.hasBeenSet()) {
+ // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used
+ autoSelect = (!::preferredEncoding.hasBeenSet()
+ && !::fullColour.hasBeenSet()
+ && !::fullColourAlias.hasBeenSet());
+ }
+ if (!::customCompressLevel.hasBeenSet()) {
+ // Default to CustomCompressLevel=1 if CompressLevel is used.
+ customCompressLevel = ::compressLevel.hasBeenSet();
+ }
+}
+
+
+void CConnOptions::readFromFile(const char* filename) {
+ FILE* f = fopen(filename, "r");
+ if (!f)
+ throw rdr::Exception("Failed to read configuration file");
+
+ try {
+ char line[4096];
+ CharArray section;
+
+ CharArray hostTmp;
+ int portTmp = 0;
+
+ while (!feof(f)) {
+ // Read the next line
+ if (!fgets(line, sizeof(line), f)) {
+ if (feof(f))
+ break;
+ throw rdr::SystemException("fgets", ferror(f));
+ }
+ int len=strlen(line);
+ if (line[len-1] == '\n') {
+ line[len-1] = 0;
+ len--;
+ }
+
+ // Process the line
+ if (line[0] == ';') {
+ // Comment
+ } else if (line[0] == '[') {
+ // Entering a new section
+ if (!strSplit(&line[1], ']', §ion.buf, 0))
+ throw rdr::Exception("bad Section");
+ } else {
+ // Reading an option
+ CharArray name;
+ CharArray value;
+ if (!strSplit(line, '=', &name.buf, &value.buf))
+ throw rdr::Exception("bad Name/Value pair");
+
+ if (stricmp(section.buf, "Connection") == 0) {
+ if (stricmp(name.buf, "Host") == 0) {
+ hostTmp.replaceBuf(value.takeBuf());
+ } else if (stricmp(name.buf, "Port") == 0) {
+ portTmp = atoi(value.buf);
+ } else if (stricmp(name.buf, "UserName") == 0) {
+ userName.replaceBuf(value.takeBuf());
+ } else if (stricmp(name.buf, "Password") == 0) {
+ ObfuscatedPasswd obfPwd;
+ rdr::HexInStream::hexStrToBin(value.buf, (char**)&obfPwd.buf, &obfPwd.length);
+ PlainPasswd passwd(obfPwd);
+ password.replaceBuf(passwd.takeBuf());
+ }
+ } else if (stricmp(section.buf, "Options") == 0) {
+ // V4 options
+ if (stricmp(name.buf, "UseLocalCursor") == 0) {
+ useLocalCursor = atoi(value.buf);
+ } else if (stricmp(name.buf, "UseDesktopResize") == 0) {
+ useDesktopResize = atoi(value.buf);
+ } else if (stricmp(name.buf, "FullScreen") == 0) {
+ fullScreen = atoi(value.buf);
+ } else if (stricmp(name.buf, "FullColour") == 0) {
+ fullColour = atoi(value.buf);
+ } else if (stricmp(name.buf, "LowColourLevel") == 0) {
+ lowColourLevel = atoi(value.buf);
+ } else if (stricmp(name.buf, "PreferredEncoding") == 0) {
+ preferredEncoding = encodingNum(value.buf);
+ } else if ((stricmp(name.buf, "AutoDetect") == 0) ||
+ (stricmp(name.buf, "AutoSelect") == 0)) {
+ autoSelect = atoi(value.buf);
+ } else if (stricmp(name.buf, "Shared") == 0) {
+ shared = atoi(value.buf);
+ } else if (stricmp(name.buf, "SendPtrEvents") == 0) {
+ sendPtrEvents = atoi(value.buf);
+ } else if (stricmp(name.buf, "SendKeyEvents") == 0) {
+ sendKeyEvents = atoi(value.buf);
+ } else if (stricmp(name.buf, "SendCutText") == 0) {
+ clientCutText = atoi(value.buf);
+ } else if (stricmp(name.buf, "AcceptCutText") == 0) {
+ serverCutText = atoi(value.buf);
+ } else if (stricmp(name.buf, "DisableWinKeys") == 0) {
+ disableWinKeys = atoi(value.buf);
+ } else if (stricmp(name.buf, "AcceptBell") == 0) {
+ acceptBell = atoi(value.buf);
+ } else if (stricmp(name.buf, "Emulate3") == 0) {
+ emulate3 = atoi(value.buf);
+ } else if (stricmp(name.buf, "ShowToolbar") == 0) {
+ showToolbar = atoi(value.buf);
+ } else if (stricmp(name.buf, "PointerEventInterval") == 0) {
+ pointerEventInterval = atoi(value.buf);
+ } else if (stricmp(name.buf, "Monitor") == 0) {
+ monitor.replaceBuf(value.takeBuf());
+ } else if (stricmp(name.buf, "MenuKey") == 0) {
+ setMenuKey(value.buf);
+ } else if (stricmp(name.buf, "AutoReconnect") == 0) {
+ autoReconnect = atoi(value.buf);
+
+ } else if (stricmp(name.buf, "CustomCompressLevel") == 0) {
+ customCompressLevel = atoi(value.buf);
+ } else if (stricmp(name.buf, "CompressLevel") == 0) {
+ compressLevel = atoi(value.buf);
+ } else if (stricmp(name.buf, "NoJPEG") == 0) {
+ noJpeg = atoi(value.buf);
+ } else if (stricmp(name.buf, "QualityLevel") == 0) {
+ qualityLevel = atoi(value.buf);
+ // Legacy options
+ } else if (stricmp(name.buf, "Preferred_Encoding") == 0) {
+ preferredEncoding = atoi(value.buf);
+ } else if (stricmp(name.buf, "8bit") == 0) {
+ fullColour = !atoi(value.buf);
+ } else if (stricmp(name.buf, "FullScreen") == 0) {
+ fullScreen = atoi(value.buf);
+ } else if (stricmp(name.buf, "ViewOnly") == 0) {
+ sendPtrEvents = sendKeyEvents = !atoi(value.buf);
+ } else if (stricmp(name.buf, "DisableClipboard") == 0) {
+ clientCutText = serverCutText = !atoi(value.buf);
+ }
+ }
+ }
+ }
+ fclose(f); f=0;
+
+ // Process the Host and Port
+ if (hostTmp.buf) {
+ int hostLen = strlen(hostTmp.buf) + 2 + 17;
+ host.replaceBuf(new char[hostLen]);
+ strCopy(host.buf, hostTmp.buf, hostLen);
+ if (portTmp) {
+ strncat(host.buf, "::", hostLen-1);
+ char tmp[16];
+ sprintf(tmp, "%d", portTmp);
+ strncat(host.buf, tmp, hostLen-1);
+ }
+ }
+
+ // If AutoSelect is enabled then override the preferred encoding
+ if (autoSelect)
+ preferredEncoding = encodingZRLE;
+
+ setConfigFileName(filename);
+ } catch (rdr::Exception&) {
+ if (f) fclose(f);
+ throw;
+ }
+}
+
+void CConnOptions::writeToFile(const char* filename) {
+ FILE* f = fopen(filename, "w");
+ if (!f)
+ throw rdr::Exception("Failed to write configuration file");
+
+ try {
+ // - Split server into host and port and save
+ fprintf(f, "[Connection]\n");
+
+ fprintf(f, "Host=%s\n", host.buf);
+ if (userName.buf)
+ fprintf(f, "UserName=%s\n", userName.buf);
+ if (password.buf) {
+ // - Warn the user before saving the password
+ if (MsgBox(0, _T("Do you want to include the VNC Password in this configuration file?\n")
+ _T("Storing the password is more convenient but poses a security risk."),
+ MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) == IDYES) {
+ ObfuscatedPasswd obfPwd(password);
+ CharArray obfuscatedHex = rdr::HexOutStream::binToHexStr(obfPwd.buf, obfPwd.length);
+ fprintf(f, "Password=%s\n", obfuscatedHex.buf);
+ }
+ }
+
+ // - Save the other options
+ fprintf(f, "[Options]\n");
+
+ fprintf(f, "UseLocalCursor=%d\n", (int)useLocalCursor);
+ fprintf(f, "UseDesktopResize=%d\n", (int)useDesktopResize);
+ fprintf(f, "FullScreen=%d\n", (int)fullScreen);
+ fprintf(f, "FullColour=%d\n", (int)fullColour);
+ fprintf(f, "LowColourLevel=%d\n", lowColourLevel);
+ fprintf(f, "PreferredEncoding=%s\n", encodingName(preferredEncoding));
+ fprintf(f, "AutoSelect=%d\n", (int)autoSelect);
+ fprintf(f, "Shared=%d\n", (int)shared);
+ fprintf(f, "SendPtrEvents=%d\n", (int)sendPtrEvents);
+ fprintf(f, "SendKeyEvents=%d\n", (int)sendKeyEvents);
+ fprintf(f, "SendCutText=%d\n", (int)clientCutText);
+ fprintf(f, "AcceptCutText=%d\n", (int)serverCutText);
+ fprintf(f, "DisableWinKeys=%d\n", (int)disableWinKeys);
+ fprintf(f, "AcceptBell=%d\n", (int)acceptBell);
+ fprintf(f, "Emulate3=%d\n", (int)emulate3);
+ fprintf(f, "ShowToolbar=%d\n", (int)showToolbar);
+ fprintf(f, "PointerEventInterval=%d\n", pointerEventInterval);
+ if (monitor.buf)
+ fprintf(f, "Monitor=%s\n", monitor.buf);
+ fprintf(f, "MenuKey=%s\n", CharArray(menuKeyName()).buf);
+ fprintf(f, "AutoReconnect=%d\n", (int)autoReconnect);
+ fprintf(f, "CustomCompressLevel=%d\n", customCompressLevel);
+ fprintf(f, "CompressLevel=%d\n", compressLevel);
+ fprintf(f, "NoJPEG=%d\n", noJpeg);
+ fprintf(f, "QualityLevel=%d\n", qualityLevel);
+ fclose(f); f=0;
+
+ setConfigFileName(filename);
+ } catch (rdr::Exception&) {
+ if (f) fclose(f);
+ throw;
+ }
+}
+
+
+void CConnOptions::writeDefaults() {
+ RegKey key;
+ key.createKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCviewer4"));
+ key.setBool(_T("UseLocalCursor"), useLocalCursor);
+ key.setBool(_T("UseDesktopResize"), useDesktopResize);
+ key.setBool(_T("FullScreen"), fullScreen);
+ key.setBool(_T("FullColour"), fullColour);
+ key.setInt(_T("LowColourLevel"), lowColourLevel);
+ key.setString(_T("PreferredEncoding"), TStr(encodingName(preferredEncoding)));
+ key.setBool(_T("AutoSelect"), autoSelect);
+ key.setBool(_T("Shared"), shared);
+ key.setBool(_T("SendPointerEvents"), sendPtrEvents);
+ key.setBool(_T("SendKeyEvents"), sendKeyEvents);
+ key.setBool(_T("ClientCutText"), clientCutText);
+ key.setBool(_T("ServerCutText"), serverCutText);
+ key.setBool(_T("DisableWinKeys"), disableWinKeys);
+ key.setBool(_T("Protocol3.3"), protocol3_3);
+ key.setBool(_T("AcceptBell"), acceptBell);
+ key.setBool(_T("ShowToolbar"), showToolbar);
+ key.setBool(_T("Emulate3"), emulate3);
+ key.setInt(_T("PointerEventInterval"), pointerEventInterval);
+ if (monitor.buf)
+ key.setString(_T("Monitor"), TStr(monitor.buf));
+ key.setString(_T("MenuKey"), TCharArray(menuKeyName()).buf);
+ key.setBool(_T("AutoReconnect"), autoReconnect);
+ key.setInt(_T("CustomCompressLevel"), customCompressLevel);
+ key.setInt(_T("CompressLevel"), compressLevel);
+ key.setInt(_T("NoJPEG"), noJpeg);
+ key.setInt(_T("QualityLevel"), qualityLevel);
+}
+
+
+void CConnOptions::setUserName(const char* user) {userName.replaceBuf(strDup(user));}
+void CConnOptions::setPassword(const char* pwd) {password.replaceBuf(strDup(pwd));}
+void CConnOptions::setConfigFileName(const char* cfn) {configFileName.replaceBuf(strDup(cfn));}
+void CConnOptions::setHost(const char* h) {host.replaceBuf(strDup(h));}
+void CConnOptions::setMonitor(const char* m) {monitor.replaceBuf(strDup(m));}
+
+void CConnOptions::setMenuKey(const char* keyName) {
+ if (!keyName[0]) {
+ menuKey = 0;
+ } else {
+ menuKey = VK_F8;
+ if (keyName[0] == 'F') {
+ UINT fKey = atoi(&keyName[1]);
+ if (fKey >= 1 && fKey <= 12)
+ menuKey = fKey-1 + VK_F1;
+ }
+ }
+}
+char* CConnOptions::menuKeyName() {
+ int fNum = (menuKey-VK_F1)+1;
+ if (fNum<1 || fNum>12)
+ return strDup("");
+ CharArray menuKeyStr(4);
+ sprintf(menuKeyStr.buf, "F%d", fNum);
+ return menuKeyStr.takeBuf();
+}
+
+
+CConnOptions& CConnOptions::operator=(const CConnOptions& o) {
+ useLocalCursor = o.useLocalCursor;
+ useDesktopResize = o.useDesktopResize;
+ fullScreen = o.fullScreen;
+ fullColour = o.fullColour;
+ lowColourLevel = o.lowColourLevel;
+ preferredEncoding = o.preferredEncoding;
+ autoSelect = o.autoSelect;
+ shared = o.shared;
+ sendPtrEvents = o.sendPtrEvents;
+ sendKeyEvents = o.sendKeyEvents;
+ clientCutText = o.clientCutText;
+ serverCutText = o.serverCutText;
+ disableWinKeys = o.disableWinKeys;
+ emulate3 = o.emulate3;
+ pointerEventInterval = o.pointerEventInterval;
+ protocol3_3 = o.protocol3_3;
+ acceptBell = o.acceptBell;
+ showToolbar = o.showToolbar;
+ setUserName(o.userName.buf);
+ setPassword(o.password.buf);
+ setConfigFileName(o.configFileName.buf);
+ setHost(o.host.buf);
+ setMonitor(o.monitor.buf);
+ menuKey = o.menuKey;
+ autoReconnect = o.autoReconnect;
+ customCompressLevel = o.customCompressLevel;
+ compressLevel = o.compressLevel;
+ noJpeg = o.noJpeg;
+ qualityLevel = o.qualityLevel;
+
+ return *this;
+}
diff --git a/win/vncviewer/CConnOptions.h b/win/vncviewer/CConnOptions.h
new file mode 100644
index 0000000..59fd0a3
--- /dev/null
+++ b/win/vncviewer/CConnOptions.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- CConnOptions.h
+
+// Definition of the CConnOptions class, responsible for storing the
+// current & requested VNC Viewer options.
+
+#ifndef __RFB_WIN32_CCONN_OPTIONS_H__
+#define __RFB_WIN32_CCONN_OPTIONS_H__
+
+#include <rfb/Password.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ //
+ // -=- Options structure. Each viewer option has a corresponding
+ // entry in CConnOptions. The viewer options are set by calling
+ // CConn::applyOptions(...)
+ // The CConnOptions structure automatically picks up the default
+ // value of each option from the Configuration system
+ // The readFromFile and writeFromFile methods can be used to load
+ // and save VNC configuration files. readFromFile is backwards
+ // compatible with 3.3 releases, while writeToFile is not.
+
+ class CConnOptions {
+ public:
+ CConnOptions();
+ CConnOptions(const CConnOptions& o) {operator=(o);}
+ CConnOptions& operator=(const CConnOptions& o);
+ void readFromFile(const char* filename_);
+ void writeToFile(const char* filename_);
+ void writeDefaults();
+ bool useLocalCursor;
+ bool useDesktopResize;
+ bool fullScreen;
+ bool fullColour;
+ int lowColourLevel;
+ int preferredEncoding;
+ bool autoSelect;
+ bool shared;
+ bool sendPtrEvents;
+ bool sendKeyEvents;
+ bool showToolbar;
+ bool clientCutText;
+ bool serverCutText;
+ bool disableWinKeys;
+ bool emulate3;
+ int pointerEventInterval;
+ bool protocol3_3;
+ bool acceptBell;
+ CharArray userName;
+ void setUserName(const char* user);
+ PlainPasswd password;
+ void setPassword(const char* pwd);
+ CharArray configFileName;
+ void setConfigFileName(const char* cfn);
+ CharArray host;
+ void setHost(const char* h);
+ CharArray monitor;
+ void setMonitor(const char* m);
+ unsigned int menuKey;
+ void setMenuKey(const char* keyName);
+ char* menuKeyName();
+ bool autoReconnect;
+
+ bool customCompressLevel;
+ int compressLevel;
+ bool noJpeg;
+ int qualityLevel;
+
+ CharArray passwordFile;
+ };
+
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/CConnThread.cxx b/win/vncviewer/CConnThread.cxx
new file mode 100644
index 0000000..cfd2695
--- /dev/null
+++ b/win/vncviewer/CConnThread.cxx
@@ -0,0 +1,198 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- CConnThread.cxx
+
+// A CConnThread instance is created for each new connection.
+// The CConnThread creates the corresponding CConn instance
+// and manages it.
+
+#include <stdlib.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Hostname.h>
+#include <rfb_win32/MsgBox.h>
+#include <network/TcpSocket.h>
+#include <vncviewer/CConnThread.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/ConnectionDialog.h>
+#include <vncviewer/ConnectingDialog.h>
+#include <vncviewer/UserPasswdDialog.h>
+#include <set>
+
+using namespace rfb;
+using namespace win32;
+
+static LogWriter vlog("CConnThread");
+
+static std::set<CConnThread*> threads;
+static Mutex threadsLock;
+static Handle noMoreThreads(CreateEvent(0, TRUE, FALSE, 0));
+
+
+CConnThread::CConnThread() : Thread("CConnThread"), isConfig(false),
+ sock(0), reverse(false) {
+ vlog.info("CConnThread (dialog)");
+ setDeleteAfterRun();
+ Lock l(threadsLock);
+ threads.insert(this);
+ start();
+}
+
+CConnThread::CConnThread(const char* hostOrConfig_, bool isConfig_)
+ : Thread("CConnThread"), hostOrConfig(strDup(hostOrConfig_)),
+ isConfig(isConfig_), sock(0), reverse(false) {
+ vlog.info("CConnThread (host/port)");
+ setDeleteAfterRun();
+ Lock l(threadsLock);
+ threads.insert(this);
+ start();
+}
+
+CConnThread::CConnThread(network::Socket* sock_, bool reverse_)
+ : Thread("CConnThread"), isConfig(false), sock(sock_), reverse(reverse_) {
+ vlog.info("CConnThread (reverse connection)");
+ setDeleteAfterRun();
+ Lock l(threadsLock);
+ threads.insert(this);
+ start();
+}
+
+CConnThread::~CConnThread() {
+ Lock l(threadsLock);
+ threads.erase(this);
+ if (threads.empty())
+ SetEvent(noMoreThreads);
+ delete sock;
+}
+
+
+void CConnThread::run() {
+ CConnOptions options;
+ bool reconnect;
+
+ do {
+ {
+ CConn conn;
+ reconnect = false;
+
+ // If there is no socket object then set the host & port info
+ if (!sock && !options.host.buf) {
+ try {
+ if (isConfig) {
+ // A configuration file name was specified - load it
+ CharArray filename = hostOrConfig.takeBuf();
+ options.readFromFile(filename.buf);
+ } else {
+ // An actual hostname (and possibly port) was specified
+ options.host.replaceBuf(hostOrConfig.takeBuf());
+ }
+
+ if (!options.host.buf) {
+ // No host was specified - prompt for one
+ ConnectionDialog connDlg(&conn);
+ if (!connDlg.showDialog())
+ return;
+ options = conn.getOptions();
+ options.setHost(CStr(connDlg.hostname.buf));
+ }
+ } catch (rdr::Exception& e) {
+ MsgBox(0, TStr(e.str()), MB_ICONERROR | MB_OK);
+ return;
+ }
+ }
+
+ // Apply the connection options to the CConn
+ conn.applyOptions(options);
+
+ if (!sock) {
+ // There is no existing connection - better make one
+ const char* hostAndPort = conn.getOptions().host.buf;
+
+ try {
+ ConnectingDialog dlg;
+ sock = dlg.connect(hostAndPort);
+
+ // If the connection was cancelled by the user, just quit
+ if (!sock)
+ return;
+ } catch(rdr::Exception& e) {
+ MsgBox(NULL, TStr(e.str()), MB_ICONERROR | MB_OK);
+ return;
+ }
+
+ // Try to add the caller to the MRU
+ MRU::addToMRU(hostAndPort);
+ }
+
+ // Run the RFB protocol over the connected socket
+ conn.initialise(sock, reverse);
+ while (!conn.isClosed()) {
+ try {
+ conn.getInStream()->check(1,1);
+ conn.processMsg();
+ } catch (rdr::EndOfStream) {
+ if (conn.state() == CConnection::RFBSTATE_NORMAL)
+ conn.close();
+ else
+ conn.close("The connection closed unexpectedly");
+ } catch (rfb::AuthCancelledException) {
+ conn.close();
+ } catch (rfb::AuthFailureException& e) {
+ // Clear the password, in case we auto-reconnect
+ options = conn.getOptions();
+ options.password.replaceBuf(0);
+ conn.applyOptions(options);
+ conn.close(e.str());
+ } catch (rdr::Exception& e) {
+ conn.close(e.str());
+ }
+ }
+
+ // If there is a cause for closing the connection logged then display it
+ if (conn.closeReason()) {
+ reconnect = !reverse && conn.getOptions().autoReconnect;
+ if (!reconnect) {
+ MsgBox(0, TStr(conn.closeReason()), MB_ICONINFORMATION | MB_OK);
+ } else {
+ options = conn.getOptions();
+ const char* format = "%s\nDo you wish to attempt to reconnect to %s?";
+ CharArray message(strlen(conn.closeReason()) + strlen(format) +
+ strlen(conn.getOptions().host.buf));
+ sprintf(message.buf, format, conn.closeReason(), conn.getOptions().host.buf);
+ if (MsgBox(0, TStr(message.buf), MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES)
+ reconnect = false;
+ }
+ }
+ } // Exit the CConn's scope, implicitly destroying it & making it safe to delete the TcpSocket
+
+ // Clean up the old socket, if any
+ delete sock; sock = 0;
+ } while (reconnect);
+}
+
+
+BOOL CConnThread::getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg) {
+ while (!PeekMessage(msg, hwnd, minMsg, maxMsg, PM_REMOVE)) {
+ DWORD result = MsgWaitForMultipleObjects(1, &noMoreThreads.h, FALSE, INFINITE, QS_ALLINPUT);
+ if (result == WAIT_OBJECT_0)
+ return FALSE;
+ else if (result == WAIT_FAILED)
+ throw rdr::SystemException("CConnThread::getMessage wait failed", GetLastError());
+ }
+ return msg->message != WM_QUIT;
+}
diff --git a/win/vncviewer/CConnThread.h b/win/vncviewer/CConnThread.h
new file mode 100644
index 0000000..7a8451c
--- /dev/null
+++ b/win/vncviewer/CConnThread.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- CConnThread.h
+
+// CConn-managing Thread implementation.
+
+#ifndef __RFB_WIN32_CCONN_THREAD_H__
+#define __RFB_WIN32_CCONN_THREAD_H__
+
+#include <network/Socket.h>
+#include <rfb/Threading.h>
+#include <rfb/util.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class CConnThread : public Thread {
+ public:
+ CConnThread();
+ CConnThread(const char* hostOrConfig, bool isConfig=false);
+ CConnThread(network::Socket* sock, bool reverse=false);
+ ~CConnThread();
+
+ void run();
+
+ // Special getMessage call that returns FALSE if message is WM_QUIT,
+ // OR if there are no more CConnThreads running.
+ static BOOL getMessage(MSG* msg, HWND hwnd, UINT minMsg, UINT maxMsg);
+ protected:
+ CharArray hostOrConfig;
+ bool isConfig;
+ network::Socket* sock;
+ bool reverse;
+ };
+
+ };
+
+};
+
+#endif // __RFB_WIN32_CCONN_THREAD_H__
diff --git a/win/vncviewer/ConnectingDialog.cxx b/win/vncviewer/ConnectingDialog.cxx
new file mode 100644
index 0000000..60fcb66
--- /dev/null
+++ b/win/vncviewer/ConnectingDialog.cxx
@@ -0,0 +1,160 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ConnectingDialog.cxx
+
+#include <stdlib.h>
+#include <vncviewer/ConnectingDialog.h>
+#include <vncviewer/resource.h>
+#include <network/TcpSocket.h>
+#include <rfb/Threading.h>
+#include <rfb/Hostname.h>
+#include <map>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+// ConnectingDialog callback
+static BOOL CALLBACK ConnectingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
+ bool* activePtr = (bool*)GetWindowLong(hwnd, GWL_USERDATA);
+ switch (uMsg) {
+ case WM_INITDIALOG:
+ SetWindowLong(hwnd, GWL_USERDATA, lParam);
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDCANCEL:
+ if (activePtr)
+ *activePtr = false;
+ return TRUE;
+ }
+ break;
+ case WM_DESTROY:
+ if (activePtr)
+ *activePtr = false;
+ return TRUE;
+ }
+ return 0;
+}
+
+
+// Global map, used by ConnectingDialog::Threads to call back to their owning
+// ConnectingDialogs, while coping with the fact that the owner may already have quit.
+static std::map<int, ConnectingDialog*> dialogs;
+static int nextDialogId = 0;
+static Mutex dialogsLock;
+
+
+// ConnectingDialog::Thread
+// Attempts to connect to the specified host. If the connection succeeds, the
+// socket is saved in the owning ConnectingDialog, if still available, and the
+// event is signalled. If the connection fails, the Exception text is returned
+// to the dialog. If the dialog is already gone, the Exception/socket are discarded.
+// NB: This thread class cleans itself up on exit - DO NOT join()!
+class ConnectingDialog::Thread : public rfb::Thread {
+public:
+ Thread(int dialogId_, const char* hostAndPort) : dialogId(dialogId_) {
+ setDeleteAfterRun();
+ getHostAndPort(hostAndPort, &host.buf, &port);
+ }
+ virtual void run() {
+ try {
+ returnSock(new network::TcpSocket(host.buf, port));
+ } catch (rdr::Exception& e) {
+ returnException(e);
+ }
+ }
+ void returnSock(network::Socket* s) {
+ Lock l(dialogsLock);
+ if (dialogs.count(dialogId)) {
+ dialogs[dialogId]->newSocket = s;
+ SetEvent(dialogs[dialogId]->readyEvent);
+ } else {
+ delete s;
+ }
+ }
+ void returnException(const rdr::Exception& e) {
+ Lock l(dialogsLock);
+ if (dialogs.count(dialogId)) {
+ dialogs[dialogId]->errMsg.replaceBuf(strDup(e.str()));
+ SetEvent(dialogs[dialogId]->readyEvent);
+ }
+ };
+ CharArray host;
+ int port;
+ int dialogId;
+};
+
+
+ConnectingDialog::ConnectingDialog() : dialog(0), readyEvent(CreateEvent(0, TRUE, FALSE, 0)),
+ newSocket(0), dialogId(0) {
+}
+
+network::Socket* ConnectingDialog::connect(const char* hostAndPort) {
+ Thread* connectThread = 0;
+ bool active = true;
+ errMsg.replaceBuf(0);
+ newSocket = 0;
+
+ // Get a unique dialog identifier and create the dialog window
+ {
+ Lock l(dialogsLock);
+ dialogId = ++nextDialogId;
+ dialogs[dialogId] = this;
+ dialog = CreateDialogParam(GetModuleHandle(0),
+ MAKEINTRESOURCE(IDD_CONNECTING_DLG), 0, &ConnectingDlgProc, (long)&active);
+ ShowWindow(dialog, SW_SHOW);
+ ResetEvent(readyEvent);
+ }
+
+ // Create and start the connection thread
+ try {
+ connectThread = new Thread(dialogId, hostAndPort);
+ connectThread->start();
+ } catch (rdr::Exception& e) {
+ errMsg.replaceBuf(strDup(e.str()));
+ active = false;
+ }
+
+ // Process window messages until the connection thread signals readyEvent, or the dialog is cancelled
+ while (active && (MsgWaitForMultipleObjects(1, &readyEvent.h, FALSE, INFINITE, QS_ALLINPUT) == WAIT_OBJECT_0 + 1)) {
+ MSG msg;
+ while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ DispatchMessage(&msg);
+ }
+
+ // Remove this dialog from the table
+ // NB: If the dialog was cancelled then the thread is still running, and will only
+ // discover that we're gone when it looks up our unique Id in the dialog table.
+ {
+ Lock l(dialogsLock);
+ dialogs.erase(dialogId);
+ }
+
+ // Close the dialog window
+ DestroyWindow(dialog); dialog=0;
+
+ // Throw the exception, if there was one
+ if (errMsg.buf)
+ throw rdr::Exception(errMsg.buf);
+
+ // Otherwise, return the socket
+ // NB: The socket will be null if the dialog was cancelled
+ return newSocket;
+}
diff --git a/win/vncviewer/ConnectingDialog.h b/win/vncviewer/ConnectingDialog.h
new file mode 100644
index 0000000..c38b3a1
--- /dev/null
+++ b/win/vncviewer/ConnectingDialog.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ConnectingDialog.h
+
+// ConnectingDialog instances are used to display a status dialog while a
+// connection attempt is in progress. The connection attempt is performed
+// in a background thread by the ConnectingDialog, to allow the status dialog
+// to remain interactive. If the dialog is cancelled then it will close and
+// the connection dialog will eventually tidy itself up.
+
+#ifndef __RFB_WIN32_CONNECTING_DLG_H__
+#define __RFB_WIN32_CONNECTING_DLG_H__
+
+#include <windows.h>
+#include <network/Socket.h>
+#include <rfb/util.h>
+#include <rfb_win32/Handle.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class ConnectingDialog {
+ public:
+ ConnectingDialog();
+
+ // connect
+ // Show a Connecting dialog and attempt to connect to the specified host
+ // in the background.
+ // If the connection succeeds then the Socket is returned.
+ // If an error occurs, an Exception is thrown.
+ // If the dialog is cancelled then null is returned.
+ network::Socket* connect(const char* hostAndPort);
+ protected:
+ HWND dialog;
+ network::Socket* newSocket;
+ CharArray errMsg;
+ Handle readyEvent;
+ int dialogId;
+
+ class Thread;
+ friend class Thread;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/ConnectionDialog.cxx b/win/vncviewer/ConnectionDialog.cxx
new file mode 100644
index 0000000..e7c6b0a
--- /dev/null
+++ b/win/vncviewer/ConnectionDialog.cxx
@@ -0,0 +1,79 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <vncviewer/ConnectionDialog.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/resource.h>
+#include <rfb_win32/AboutDialog.h>
+
+#include <tchar.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+ConnectionDialog::ConnectionDialog(CConn* conn_) : Dialog(GetModuleHandle(0)), conn(conn_) {
+}
+
+
+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);
+
+ // Fill out the Security: drop-down and select the preferred option
+ HWND security = GetDlgItem(handle, IDC_SECURITY_LEVEL);
+ LRESULT n = SendMessage(security, CB_ADDSTRING, 0, (LPARAM)_T("Always Off"));
+ if (n != CB_ERR)
+ SendMessage(security, CB_SETCURSEL, n, 0);
+ enableItem(IDC_SECURITY_LEVEL, false);
+}
+
+
+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:
+ conn->showOptionsDialog();
+ return true;
+ };
+ return false;
+}
diff --git a/win/vncviewer/ConnectionDialog.h b/win/vncviewer/ConnectionDialog.h
new file mode 100644
index 0000000..f739280
--- /dev/null
+++ b/win/vncviewer/ConnectionDialog.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- 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 CConn;
+
+ class ConnectionDialog : Dialog {
+ public:
+ ConnectionDialog(CConn* view);
+ virtual bool showDialog();
+ virtual void initDialog();
+ virtual bool onOk();
+ virtual bool onCommand(int id, int cmd);
+ TCharArray hostname;
+ protected:
+ CConn* conn;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/DesktopWindow.cxx b/win/vncviewer/DesktopWindow.cxx
new file mode 100644
index 0000000..27ef2dc
--- /dev/null
+++ b/win/vncviewer/DesktopWindow.cxx
@@ -0,0 +1,1103 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+#include <rfb/Configuration.h>
+#include <rfb/LogWriter.h>
+#include <rfb_win32/WMShatter.h>
+#include <rfb_win32/LowLevelKeyEvents.h>
+#include <rfb_win32/MonitorInfo.h>
+#include <rfb_win32/DeviceContext.h>
+#include <rfb_win32/Win32Util.h>
+#include <vncviewer/DesktopWindow.h>
+#include <vncviewer/resource.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+// - Statics & consts
+
+static LogWriter vlog("DesktopWindow");
+
+const int TIMER_BUMPSCROLL = 1;
+const int TIMER_POINTER_INTERVAL = 2;
+const int TIMER_POINTER_3BUTTON = 3;
+
+
+//
+// -=- DesktopWindowClass
+
+//
+// Window class used as the basis for all DesktopWindow instances
+//
+
+class DesktopWindowClass {
+public:
+ DesktopWindowClass();
+ ~DesktopWindowClass();
+ ATOM classAtom;
+ HINSTANCE instance;
+};
+
+LRESULT CALLBACK DesktopWindowProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ LRESULT result;
+ if (msg == WM_CREATE)
+ SetWindowLong(wnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+ else if (msg == WM_DESTROY)
+ SetWindowLong(wnd, GWL_USERDATA, 0);
+ DesktopWindow* _this = (DesktopWindow*) GetWindowLong(wnd, GWL_USERDATA);
+ if (!_this) {
+ vlog.info("null _this in %x, message %u", wnd, msg);
+ return rfb::win32::SafeDefWindowProc(wnd, msg, wParam, lParam);
+ }
+
+ try {
+ result = _this->processMessage(msg, wParam, lParam);
+ } catch (rdr::Exception& e) {
+ vlog.error("untrapped: %s", e.str());
+ }
+
+ return result;
+};
+
+static HCURSOR dotCursor = (HCURSOR)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDC_DOT_CURSOR), IMAGE_CURSOR, 0, 0, LR_SHARED);
+static HCURSOR arrowCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
+
+DesktopWindowClass::DesktopWindowClass() : classAtom(0) {
+ WNDCLASS wndClass;
+ wndClass.style = 0;
+ wndClass.lpfnWndProc = DesktopWindowProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hInstance = instance = GetModuleHandle(0);
+ wndClass.hIcon = (HICON)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 0, 0, LR_SHARED);
+ if (!wndClass.hIcon)
+ printf("unable to load icon:%ld", GetLastError());
+ wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndClass.hbrBackground = NULL;
+ wndClass.lpszMenuName = 0;
+ wndClass.lpszClassName = _T("rfb::win32::DesktopWindowClass");
+ classAtom = RegisterClass(&wndClass);
+ if (!classAtom) {
+ throw rdr::SystemException("unable to register DesktopWindow window class", GetLastError());
+ }
+}
+
+DesktopWindowClass::~DesktopWindowClass() {
+ if (classAtom) {
+ UnregisterClass((const TCHAR*)classAtom, instance);
+ }
+}
+
+DesktopWindowClass baseClass;
+
+//
+// -=- FrameClass
+
+//
+// Window class used for child windows that display pixel data
+//
+
+class FrameClass {
+public:
+ FrameClass();
+ ~FrameClass();
+ ATOM classAtom;
+ HINSTANCE instance;
+};
+
+LRESULT CALLBACK FrameProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ LRESULT result;
+ if (msg == WM_CREATE)
+ SetWindowLong(wnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams);
+ else if (msg == WM_DESTROY)
+ SetWindowLong(wnd, GWL_USERDATA, 0);
+ DesktopWindow* _this = (DesktopWindow*) GetWindowLong(wnd, GWL_USERDATA);
+ if (!_this) {
+ vlog.info("null _this in %x, message %u", wnd, msg);
+ return rfb::win32::SafeDefWindowProc(wnd, msg, wParam, lParam);
+ }
+
+ try {
+ result = _this->processFrameMessage(msg, wParam, lParam);
+ } catch (rdr::Exception& e) {
+ vlog.error("untrapped: %s", e.str());
+ }
+
+ return result;
+}
+
+FrameClass::FrameClass() : classAtom(0) {
+ WNDCLASS wndClass;
+ wndClass.style = 0;
+ wndClass.lpfnWndProc = FrameProc;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hInstance = instance = GetModuleHandle(0);
+ wndClass.hIcon = 0;
+ wndClass.hCursor = NULL;
+ wndClass.hbrBackground = NULL;
+ wndClass.lpszMenuName = 0;
+ wndClass.lpszClassName = _T("rfb::win32::FrameClass");
+ classAtom = RegisterClass(&wndClass);
+ if (!classAtom) {
+ throw rdr::SystemException("unable to register Frame window class", GetLastError());
+ }
+}
+
+FrameClass::~FrameClass() {
+ if (classAtom) {
+ UnregisterClass((const TCHAR*)classAtom, instance);
+ }
+}
+
+FrameClass frameClass;
+
+
+//
+// -=- DesktopWindow instance implementation
+//
+
+DesktopWindow::DesktopWindow(Callback* cb)
+ : buffer(0),
+ showToolbar(false),
+ client_size(0, 0, 16, 16), window_size(0, 0, 32, 32),
+ cursorVisible(false), cursorAvailable(false), cursorInBuffer(false),
+ systemCursorVisible(true), trackingMouseLeave(false),
+ handle(0), frameHandle(0), has_focus(false), palette_changed(false),
+ fullscreenActive(false), fullscreenRestore(false),
+ bumpScroll(false), callback(cb) {
+
+ // Create the window
+ const char* name = "DesktopWindow";
+ handle = CreateWindow((const TCHAR*)baseClass.classAtom, TStr(name),
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+ 0, 0, 10, 10, 0, 0, baseClass.instance, this);
+ if (!handle)
+ throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError());
+ vlog.debug("created window \"%s\" (%x)", name, handle);
+
+ // Create the toolbar
+ tb.create(handle);
+ vlog.debug("created toolbar window \"%s\" (%x)", "ViewerToolBar", tb.getHandle());
+
+ // Create the frame window
+ frameHandle = CreateWindowEx(WS_EX_CLIENTEDGE, (const TCHAR*)frameClass.classAtom,
+ 0, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+ CW_USEDEFAULT, CW_USEDEFAULT, handle, 0, frameClass.instance, this);
+ if (!frameHandle) {
+ throw rdr::SystemException("unable to create rfb frame window instance", GetLastError());
+ }
+ vlog.debug("created window \"%s\" (%x)", "Frame Window", frameHandle);
+
+ // Initialise the CPointer pointer handler
+ ptr.setHWND(frameHandle);
+ ptr.setIntervalTimerId(TIMER_POINTER_INTERVAL);
+ ptr.set3ButtonTimerId(TIMER_POINTER_3BUTTON);
+
+ // Initialise the bumpscroll timer
+ bumpScrollTimer.setHWND(handle);
+ bumpScrollTimer.setId(TIMER_BUMPSCROLL);
+
+ // Hook the clipboard
+ clipboard.setNotifier(this);
+
+ // Create the backing buffer
+ buffer = new win32::ScaledDIBSectionBuffer(frameHandle);
+
+ // Show the window
+ centerWindow(handle, 0);
+ ShowWindow(handle, SW_SHOW);
+}
+
+DesktopWindow::~DesktopWindow() {
+ vlog.debug("~DesktopWindow");
+ showSystemCursor();
+ if (handle) {
+ disableLowLevelKeyEvents(handle);
+ DestroyWindow(handle);
+ handle = 0;
+ }
+ delete buffer;
+ vlog.debug("~DesktopWindow done");
+}
+
+
+void DesktopWindow::setFullscreen(bool fs) {
+ if (fs && !fullscreenActive) {
+ fullscreenActive = bumpScroll = true;
+
+ // Un-minimize the window if required
+ if (GetWindowLong(handle, GWL_STYLE) & WS_MINIMIZE)
+ ShowWindow(handle, SW_RESTORE);
+
+ // Save the current window position
+ GetWindowRect(handle, &fullscreenOldRect);
+
+ // Find the size of the display the window is on
+ MonitorInfo mi(handle);
+
+ // Hide the toolbar
+ if (tb.isVisible())
+ tb.hide();
+ SetWindowLong(frameHandle, GWL_EXSTYLE, 0);
+
+ // Set the window full-screen
+ DWORD flags = GetWindowLong(handle, GWL_STYLE);
+ fullscreenOldFlags = flags;
+ flags = flags & ~(WS_CAPTION | WS_THICKFRAME | WS_MAXIMIZE | WS_MINIMIZE);
+ vlog.debug("flags=%x", flags);
+
+ SetWindowLong(handle, GWL_STYLE, flags);
+ SetWindowPos(handle, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top,
+ mi.rcMonitor.right-mi.rcMonitor.left,
+ mi.rcMonitor.bottom-mi.rcMonitor.top,
+ SWP_FRAMECHANGED);
+ } else if (!fs && fullscreenActive) {
+ fullscreenActive = bumpScroll = false;
+
+ // Show the toolbar
+ if (showToolbar)
+ tb.show();
+ SetWindowLong(frameHandle, GWL_EXSTYLE, WS_EX_CLIENTEDGE);
+
+ // Set the window non-fullscreen
+ SetWindowLong(handle, GWL_STYLE, fullscreenOldFlags);
+
+ // Set the window position
+ SetWindowPos(handle, HWND_NOTOPMOST,
+ fullscreenOldRect.left, fullscreenOldRect.top,
+ fullscreenOldRect.right - fullscreenOldRect.left,
+ fullscreenOldRect.bottom - fullscreenOldRect.top,
+ SWP_FRAMECHANGED);
+ }
+
+ // Adjust the viewport offset to cope with change in size between FS
+ // and previous window state.
+ setViewportOffset(scrolloffset);
+}
+
+void DesktopWindow::setShowToolbar(bool st)
+{
+ showToolbar = st;
+
+ if (showToolbar && !tb.isVisible() && !fullscreenActive) {
+ tb.show();
+ } else if (!showToolbar && tb.isVisible()) {
+ tb.hide();
+ }
+}
+
+void DesktopWindow::setDisableWinKeys(bool dwk) {
+ // Enable low-level event hooking, so we get special keys directly
+ if (dwk)
+ enableLowLevelKeyEvents(handle);
+ else
+ disableLowLevelKeyEvents(handle);
+}
+
+
+void DesktopWindow::setMonitor(const char* monitor) {
+ MonitorInfo mi(monitor);
+ mi.moveTo(handle);
+}
+
+char* DesktopWindow::getMonitor() const {
+ MonitorInfo mi(handle);
+ return strDup(mi.szDevice);
+}
+
+
+bool DesktopWindow::setViewportOffset(const Point& tl) {
+ Point np = Point(max(0, min(tl.x, buffer->width()-client_size.width())),
+ max(0, min(tl.y, buffer->height()-client_size.height())));
+ Point delta = np.translate(scrolloffset.negate());
+ if (!np.equals(scrolloffset)) {
+ scrolloffset = np;
+ ScrollWindowEx(frameHandle, -delta.x, -delta.y, 0, 0, 0, 0, SW_INVALIDATE);
+ UpdateWindow(frameHandle);
+ return true;
+ }
+ return false;
+}
+
+
+bool DesktopWindow::processBumpScroll(const Point& pos)
+{
+ if (!bumpScroll) return false;
+ int bumpScrollPixels = 20;
+ bumpScrollDelta = Point();
+
+ if (pos.x == client_size.width()-1)
+ bumpScrollDelta.x = bumpScrollPixels;
+ else if (pos.x == 0)
+ bumpScrollDelta.x = -bumpScrollPixels;
+ if (pos.y == client_size.height()-1)
+ bumpScrollDelta.y = bumpScrollPixels;
+ else if (pos.y == 0)
+ bumpScrollDelta.y = -bumpScrollPixels;
+
+ if (bumpScrollDelta.x || bumpScrollDelta.y) {
+ if (bumpScrollTimer.isActive()) return true;
+ if (setViewportOffset(scrolloffset.translate(bumpScrollDelta))) {
+ bumpScrollTimer.start(25);
+ return true;
+ }
+ }
+
+ bumpScrollTimer.stop();
+ return false;
+}
+
+
+LRESULT
+DesktopWindow::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch (msg) {
+
+ // -=- Process standard window messages
+
+ case WM_NOTIFY:
+ if (wParam == ID_TOOLBAR)
+ tb.processWM_NOTIFY(wParam, lParam);
+ break;
+
+ case WM_DISPLAYCHANGE:
+ // Display format has changed - notify callback
+ callback->displayChanged();
+ break;
+
+ // -=- Window position
+
+ // Prevent the window from being resized to be too large if in normal mode.
+ // If maximized or fullscreen the allow oversized windows.
+
+ case WM_WINDOWPOSCHANGING:
+ {
+ WINDOWPOS* wpos = (WINDOWPOS*)lParam;
+ if (wpos->flags & SWP_NOSIZE)
+ break;
+
+ // Work out how big the window should ideally be
+ DWORD current_style = GetWindowLong(frameHandle, GWL_STYLE);
+ DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+ DWORD style_ex = GetWindowLong(frameHandle, GWL_EXSTYLE);
+
+ RECT r;
+ SetRect(&r, 0, 0, buffer->width(), buffer->height());
+ AdjustWindowRectEx(&r, style, FALSE, style_ex);
+ Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+ if (current_style & WS_VSCROLL)
+ reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
+ if (current_style & WS_HSCROLL)
+ reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
+
+ SetRect(&r, reqd_size.tl.x, reqd_size.tl.y, reqd_size.br.x, reqd_size.br.y);
+ if (tb.isVisible())
+ r.bottom += tb.getHeight();
+ AdjustWindowRect(&r, GetWindowLong(handle, GWL_STYLE), FALSE);
+ reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+
+ RECT current;
+ GetWindowRect(handle, ¤t);
+
+ if (!(GetWindowLong(handle, GWL_STYLE) & WS_MAXIMIZE) && !fullscreenActive) {
+ // Ensure that the window isn't resized too large
+ if (wpos->cx > reqd_size.width()) {
+ wpos->cx = reqd_size.width();
+ wpos->x = current.left;
+ }
+ if (wpos->cy > reqd_size.height()) {
+ wpos->cy = reqd_size.height();
+ wpos->y = current.top;
+ }
+ }
+ }
+ break;
+
+ // Resize child windows and update window size info we have cached.
+
+ case WM_SIZE:
+ {
+ Point old_offset = desktopToClient(Point(0, 0));
+ RECT r;
+
+ // Resize child windows
+ GetClientRect(handle, &r);
+ if (tb.isVisible()) {
+ MoveWindow(frameHandle, 0, tb.getHeight(),
+ r.right, r.bottom - tb.getHeight(), TRUE);
+ } else {
+ MoveWindow(frameHandle, 0, 0, r.right, r.bottom, TRUE);
+ }
+ tb.autoSize();
+
+ // Update the cached sizing information
+ GetWindowRect(frameHandle, &r);
+ window_size = Rect(r.left, r.top, r.right, r.bottom);
+ GetClientRect(frameHandle, &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+
+ // Determine whether scrollbars are required
+ calculateScrollBars();
+
+ // Redraw if required
+ if ((!old_offset.equals(desktopToClient(Point(0, 0)))))
+ InvalidateRect(frameHandle, 0, TRUE);
+ }
+ break;
+
+ // -=- Bump-scrolling
+
+ case WM_TIMER:
+ switch (wParam) {
+ case TIMER_BUMPSCROLL:
+ if (!setViewportOffset(scrolloffset.translate(bumpScrollDelta)))
+ bumpScrollTimer.stop();
+ break;
+ case TIMER_POINTER_INTERVAL:
+ case TIMER_POINTER_3BUTTON:
+ ptr.handleTimer(callback, wParam);
+ break;
+ }
+ break;
+
+ // -=- Track whether or not the window has focus
+
+ case WM_SETFOCUS:
+ has_focus = true;
+ break;
+ case WM_KILLFOCUS:
+ has_focus = false;
+ cursorOutsideBuffer();
+ // Restore the keyboard to a consistent state
+ kbd.releaseAllKeys(callback);
+ break;
+
+ // -=- If the menu is about to be shown, make sure it's up to date
+
+ case WM_INITMENU:
+ callback->refreshMenu(true);
+ break;
+
+ // -=- Handle the extra window menu items
+
+ // Pass system menu messages to the callback and only attempt
+ // to process them ourselves if the callback returns false.
+ case WM_SYSCOMMAND:
+ // Call the supplied callback
+ if (callback->sysCommand(wParam, lParam))
+ break;
+
+ // - Not processed by the callback, so process it as a system message
+ switch (wParam & 0xfff0) {
+
+ // When restored, ensure that full-screen mode is re-enabled if required.
+ case SC_RESTORE:
+ {
+ if (GetWindowLong(handle, GWL_STYLE) & WS_MINIMIZE) {
+ rfb::win32::SafeDefWindowProc(handle, msg, wParam, lParam);
+ setFullscreen(fullscreenRestore);
+ }
+ else if (fullscreenActive)
+ setFullscreen(false);
+ else
+ rfb::win32::SafeDefWindowProc(handle, msg, wParam, lParam);
+
+ return 0;
+ }
+
+ // If we are maximized or minimized then that cancels full-screen mode.
+ case SC_MINIMIZE:
+ case SC_MAXIMIZE:
+ fullscreenRestore = fullscreenActive;
+ setFullscreen(false);
+ break;
+
+ }
+ break;
+
+ // Treat all menu commands as system menu commands
+ case WM_COMMAND:
+ SendMessage(handle, WM_SYSCOMMAND, wParam, lParam);
+ return 0;
+
+ // -=- Handle keyboard input
+
+ case WM_KEYUP:
+ case WM_KEYDOWN:
+ // Hook the MenuKey to pop-up the window menu
+ if (menuKey && (wParam == menuKey)) {
+
+ bool ctrlDown = (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0;
+ bool altDown = (GetAsyncKeyState(VK_MENU) & 0x8000) != 0;
+ bool shiftDown = (GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0;
+ if (!(ctrlDown || altDown || shiftDown)) {
+
+ // If MenuKey is being released then pop-up the menu
+ if ((msg == WM_KEYDOWN)) {
+ // Make sure it's up to date
+ //
+ // NOTE: Here we call refreshMenu only to grey out Move and Size
+ // menu items. Other things will be refreshed once again
+ // while processing the WM_INITMENU message.
+ //
+ callback->refreshMenu(false);
+
+ // Show it under the pointer
+ POINT pt;
+ GetCursorPos(&pt);
+ cursorInBuffer = false;
+ TrackPopupMenu(GetSystemMenu(handle, FALSE),
+ TPM_CENTERALIGN | TPM_VCENTERALIGN, pt.x, pt.y, 0, handle, 0);
+ }
+
+ // Ignore the MenuKey keypress for both press & release events
+ return 0;
+ }
+ }
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ kbd.keyEvent(callback, wParam, lParam, (msg == WM_KEYDOWN) || (msg == WM_SYSKEYDOWN));
+ return 0;
+
+ // -=- Handle the window closing
+
+ case WM_CLOSE:
+ vlog.debug("WM_CLOSE %x", handle);
+ callback->closeWindow();
+ break;
+
+ }
+
+ return rfb::win32::SafeDefWindowProc(handle, msg, wParam, lParam);
+}
+
+LRESULT
+DesktopWindow::processFrameMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch (msg) {
+
+ // -=- Paint the remote frame buffer
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC paintDC = BeginPaint(frameHandle, &ps);
+ if (!paintDC)
+ throw rdr::SystemException("unable to BeginPaint", GetLastError());
+ Rect pr = Rect(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom);
+
+ if (!pr.is_empty()) {
+
+ // Draw using the correct palette
+ PaletteSelector pSel(paintDC, windowPalette.getHandle());
+
+ if (buffer->bitmap) {
+ // Update the bitmap's palette
+ if (palette_changed) {
+ palette_changed = false;
+ buffer->refreshPalette();
+ }
+
+ // Get device context
+ BitmapDC bitmapDC(paintDC, buffer->bitmap);
+
+ // Blit the border if required
+ Rect bufpos = desktopToClient(buffer->getRect());
+ if (!pr.enclosed_by(bufpos)) {
+ vlog.debug("draw border");
+ HBRUSH black = (HBRUSH) GetStockObject(BLACK_BRUSH);
+ RECT r;
+ SetRect(&r, 0, 0, bufpos.tl.x, client_size.height()); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.tl.x, 0, bufpos.br.x, bufpos.tl.y); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.br.x, 0, client_size.width(), client_size.height()); FillRect(paintDC, &r, black);
+ SetRect(&r, bufpos.tl.x, bufpos.br.y, bufpos.br.x, client_size.height()); FillRect(paintDC, &r, black);
+ }
+
+ // Do the blit
+ Point buf_pos = clientToDesktop(pr.tl);
+
+ if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(),
+ bitmapDC, buf_pos.x, buf_pos.y, SRCCOPY))
+ throw rdr::SystemException("unable to BitBlt to window", GetLastError());
+ }
+ }
+
+ EndPaint(frameHandle, &ps);
+
+ // - Notify the callback that a paint message has finished processing
+ callback->paintCompleted();
+ }
+ return 0;
+
+ // -=- Palette management
+
+ case WM_PALETTECHANGED:
+ vlog.debug("WM_PALETTECHANGED");
+ if ((HWND)wParam == frameHandle) {
+ vlog.debug("ignoring");
+ break;
+ }
+ case WM_QUERYNEWPALETTE:
+ vlog.debug("re-selecting palette");
+ {
+ WindowDC wdc(frameHandle);
+ PaletteSelector pSel(wdc, windowPalette.getHandle());
+ if (pSel.isRedrawRequired()) {
+ InvalidateRect(frameHandle, 0, FALSE);
+ UpdateWindow(frameHandle);
+ }
+ }
+ return TRUE;
+
+ case WM_VSCROLL:
+ case WM_HSCROLL:
+ {
+ Point delta;
+ int newpos = (msg == WM_VSCROLL) ? scrolloffset.y : scrolloffset.x;
+
+ switch (LOWORD(wParam)) {
+ case SB_PAGEUP: newpos -= 50; break;
+ case SB_PAGEDOWN: newpos += 50; break;
+ case SB_LINEUP: newpos -= 5; break;
+ case SB_LINEDOWN: newpos += 5; break;
+ case SB_THUMBTRACK:
+ case SB_THUMBPOSITION: newpos = HIWORD(wParam); break;
+ default: vlog.info("received unknown scroll message");
+ };
+
+ if (msg == WM_HSCROLL)
+ setViewportOffset(Point(newpos, scrolloffset.y));
+ else
+ setViewportOffset(Point(scrolloffset.x, newpos));
+
+ SCROLLINFO si;
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_POS;
+ si.nPos = newpos;
+ SetScrollInfo(frameHandle, (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ, &si, TRUE);
+ }
+ break;
+
+ // -=- Cursor shape/visibility handling
+
+ case WM_SETCURSOR:
+ if (LOWORD(lParam) != HTCLIENT)
+ break;
+ SetCursor(cursorInBuffer ? dotCursor : arrowCursor);
+ return TRUE;
+
+ case WM_MOUSELEAVE:
+ trackingMouseLeave = false;
+ cursorOutsideBuffer();
+ return 0;
+
+ // -=- Mouse input handling
+
+ case WM_MOUSEMOVE:
+ case WM_LBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_LBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+#ifdef WM_MOUSEWHEEL
+ case WM_MOUSEWHEEL:
+#endif
+ if (has_focus)
+ {
+ if (!trackingMouseLeave) {
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = frameHandle;
+ _TrackMouseEvent(&tme);
+ trackingMouseLeave = true;
+ }
+ int mask = 0;
+ if (LOWORD(wParam) & MK_LBUTTON) mask |= 1;
+ if (LOWORD(wParam) & MK_MBUTTON) mask |= 2;
+ if (LOWORD(wParam) & MK_RBUTTON) mask |= 4;
+
+#ifdef WM_MOUSEWHEEL
+ if (msg == WM_MOUSEWHEEL) {
+ int delta = (short)HIWORD(wParam);
+ int repeats = (abs(delta)+119) / 120;
+ int wheelMask = (delta > 0) ? 8 : 16;
+ vlog.debug("repeats %d, mask %d\n",repeats,wheelMask);
+ for (int i=0; i<repeats; i++) {
+ ptr.pointerEvent(callback, oldpos, mask | wheelMask);
+ ptr.pointerEvent(callback, oldpos, mask);
+ }
+ } else {
+#endif
+ Point clientPos = Point(LOWORD(lParam), HIWORD(lParam));
+ Point p = clientToDesktop(clientPos);
+
+ // If the mouse is not within the server buffer area, do nothing
+ cursorInBuffer = buffer->getRect().contains(p);
+ if (!cursorInBuffer) {
+ cursorOutsideBuffer();
+ break;
+ }
+
+ // If we're locally rendering the cursor then redraw it
+ if (cursorAvailable) {
+ // - Render the cursor!
+ if (!p.equals(cursorPos)) {
+ hideLocalCursor();
+ cursorPos = p;
+ showLocalCursor();
+ if (cursorVisible)
+ hideSystemCursor();
+ }
+ }
+
+ // If we are doing bump-scrolling then try that first...
+ if (processBumpScroll(clientPos))
+ break;
+
+ // Send a pointer event to the server
+ oldpos = p;
+ if (buffer->isScaling()) {
+ p.x /= double(buffer->getScale()) / 100.0;
+ p.y /= double(buffer->getScale()) / 100.0;
+ }
+ ptr.pointerEvent(callback, p, mask);
+#ifdef WM_MOUSEWHEEL
+ }
+#endif
+ } else {
+ cursorOutsideBuffer();
+ }
+ break;
+ }
+
+ return rfb::win32::SafeDefWindowProc(frameHandle, msg, wParam, lParam);
+}
+
+
+void
+DesktopWindow::hideLocalCursor() {
+ // - Blit the cursor backing store over the cursor
+ // *** ALWAYS call this BEFORE changing buffer PF!!!
+ if (cursorVisible) {
+ cursorVisible = false;
+ buffer->DIBSectionBuffer::imageRect(cursorBackingRect, cursorBacking.data);
+ invalidateDesktopRect(cursorBackingRect, false);
+ }
+}
+
+void
+DesktopWindow::showLocalCursor() {
+ if (cursorAvailable && !cursorVisible && cursorInBuffer) {
+ if (!buffer->getPF().equal(cursor.getPF()) ||
+ cursor.getRect().is_empty()) {
+ vlog.info("attempting to render invalid local cursor");
+ cursorAvailable = false;
+ showSystemCursor();
+ return;
+ }
+ cursorVisible = true;
+
+ cursorBackingRect = cursor.getRect().translate(cursorPos).translate(cursor.hotspot.negate());
+ cursorBackingRect = cursorBackingRect.intersect(buffer->getRect());
+ buffer->getImage(cursorBacking.data, cursorBackingRect);
+
+ renderLocalCursor();
+
+ invalidateDesktopRect(cursorBackingRect, false);
+ }
+}
+
+void DesktopWindow::cursorOutsideBuffer()
+{
+ cursorInBuffer = false;
+ hideLocalCursor();
+ showSystemCursor();
+}
+
+void
+DesktopWindow::renderLocalCursor()
+{
+ Rect r = cursor.getRect();
+ r = r.translate(cursorPos).translate(cursor.hotspot.negate());
+ buffer->DIBSectionBuffer::maskRect(r, cursor.data, cursor.mask.buf);
+}
+
+void
+DesktopWindow::hideSystemCursor() {
+ if (systemCursorVisible) {
+ vlog.debug("hide system cursor");
+ systemCursorVisible = false;
+ ShowCursor(FALSE);
+ }
+}
+
+void
+DesktopWindow::showSystemCursor() {
+ if (!systemCursorVisible) {
+ vlog.debug("show system cursor");
+ systemCursorVisible = true;
+ ShowCursor(TRUE);
+ }
+}
+
+
+bool
+DesktopWindow::invalidateDesktopRect(const Rect& crect, bool scaling) {
+ Rect rect;
+ if (buffer->isScaling() && scaling) {
+ rect = desktopToClient(buffer->calculateScaleBoundary(crect));
+ } else rect = desktopToClient(crect);
+ if (rect.intersect(client_size).is_empty()) return false;
+ RECT invalid = {rect.tl.x, rect.tl.y, rect.br.x, rect.br.y};
+ InvalidateRect(frameHandle, &invalid, FALSE);
+ return true;
+}
+
+
+void
+DesktopWindow::notifyClipboardChanged(const char* text, int len) {
+ callback->clientCutText(text, len);
+}
+
+
+void
+DesktopWindow::setPF(const PixelFormat& pf) {
+ // If the cursor is the wrong format then clear it
+ if (!pf.equal(buffer->getPF()))
+ setCursor(0, 0, Point(), 0, 0);
+
+ // Update the desktop buffer
+ buffer->setPF(pf);
+
+ // Redraw the window
+ InvalidateRect(frameHandle, 0, FALSE);
+}
+
+void
+DesktopWindow::setSize(int w, int h) {
+ vlog.debug("setSize %dx%d", w, h);
+
+ // If the locally-rendered cursor is visible then remove it
+ hideLocalCursor();
+
+ // Resize the backing buffer
+ buffer->setSize(w, h);
+
+ // If the window is not maximised or full-screen then resize it
+ if (!(GetWindowLong(handle, GWL_STYLE) & WS_MAXIMIZE) && !fullscreenActive) {
+ // Resize the window to the required size
+ RECT r = {0, 0, w, h};
+ AdjustWindowRectEx(&r, GetWindowLong(frameHandle, GWL_STYLE), FALSE,
+ GetWindowLong(frameHandle, GWL_EXSTYLE));
+ if (tb.isVisible())
+ r.bottom += tb.getHeight();
+ AdjustWindowRect(&r, GetWindowLong(handle, GWL_STYLE), FALSE);
+
+ // Resize about the center of the window, and clip to current monitor
+ MonitorInfo mi(handle);
+ resizeWindow(handle, r.right-r.left, r.bottom-r.top);
+ mi.clipTo(handle);
+ } else {
+ // Ensure the screen contents are consistent
+ InvalidateRect(frameHandle, 0, FALSE);
+ }
+
+ // Enable/disable scrollbars as appropriate
+ calculateScrollBars();
+}
+
+void
+DesktopWindow::setCursor(int w, int h, const Point& hotspot, void* data, void* mask) {
+ hideLocalCursor();
+
+ cursor.hotspot = hotspot;
+
+ cursor.setSize(w, h);
+ cursor.setPF(buffer->getPF());
+ cursor.imageRect(cursor.getRect(), data);
+ memcpy(cursor.mask.buf, mask, cursor.maskLen());
+ cursor.crop();
+
+ cursorBacking.setSize(w, h);
+ cursorBacking.setPF(buffer->getPF());
+
+ cursorAvailable = true;
+
+ showLocalCursor();
+}
+
+PixelFormat
+DesktopWindow::getNativePF() const {
+ vlog.debug("getNativePF()");
+ return WindowDC(handle).getPF();
+}
+
+
+void
+DesktopWindow::refreshWindowPalette(int start, int count) {
+ vlog.debug("refreshWindowPalette(%d, %d)", start, count);
+
+ Colour colours[256];
+ if (count > 256) {
+ vlog.debug("%d palette entries", count);
+ throw rdr::Exception("too many palette entries");
+ }
+
+ // Copy the palette from the DIBSectionBuffer
+ ColourMap* cm = buffer->getColourMap();
+ if (!cm) return;
+ for (int i=0; i<count; i++) {
+ int r, g, b;
+ cm->lookup(i, &r, &g, &b);
+ colours[i].r = r;
+ colours[i].g = g;
+ colours[i].b = b;
+ }
+
+ // Set the window palette
+ windowPalette.setEntries(start, count, colours);
+
+ // Cause the window to be redrawn
+ palette_changed = true;
+ InvalidateRect(handle, 0, FALSE);
+}
+
+
+void DesktopWindow::calculateScrollBars() {
+ // Calculate the required size of window
+ DWORD current_style = GetWindowLong(frameHandle, GWL_STYLE);
+ DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL);
+ DWORD style_ex = GetWindowLong(frameHandle, GWL_EXSTYLE);
+ DWORD old_style;
+ RECT r;
+ SetRect(&r, 0, 0, buffer->width(), buffer->height());
+ AdjustWindowRectEx(&r, style, FALSE, style_ex);
+ Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom);
+
+ if (!bumpScroll) {
+ // We only enable scrollbars if bump-scrolling is not active.
+ // Effectively, this means if full-screen is not active,
+ // but I think it's better to make these things explicit.
+
+ // Work out whether scroll bars are required
+ do {
+ old_style = style;
+
+ if (!(style & WS_HSCROLL) && (reqd_size.width() > window_size.width())) {
+ style |= WS_HSCROLL;
+ reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL);
+ }
+ if (!(style & WS_VSCROLL) && (reqd_size.height() > window_size.height())) {
+ style |= WS_VSCROLL;
+ reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL);
+ }
+ } while (style != old_style);
+ }
+
+ // Tell Windows to update the window style & cached settings
+ if (style != current_style) {
+ SetWindowLong(frameHandle, GWL_STYLE, style);
+ SetWindowPos(frameHandle, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+ }
+
+ // Update the scroll settings
+ SCROLLINFO si;
+ if (style & WS_VSCROLL) {
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = buffer->height();
+ si.nPage = buffer->height() - (reqd_size.height() - window_size.height());
+ maxscrolloffset.y = max(0, si.nMax-si.nPage);
+ scrolloffset.y = min(maxscrolloffset.y, scrolloffset.y);
+ si.nPos = scrolloffset.y;
+ SetScrollInfo(frameHandle, SB_VERT, &si, TRUE);
+ }
+ if (style & WS_HSCROLL) {
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+ si.nMin = 0;
+ si.nMax = buffer->width();
+ si.nPage = buffer->width() - (reqd_size.width() - window_size.width());
+ maxscrolloffset.x = max(0, si.nMax-si.nPage);
+ scrolloffset.x = min(maxscrolloffset.x, scrolloffset.x);
+ si.nPos = scrolloffset.x;
+ SetScrollInfo(frameHandle, SB_HORZ, &si, TRUE);
+ }
+
+ // Update the cached client size
+ GetClientRect(frameHandle, &r);
+ client_size = Rect(r.left, r.top, r.right, r.bottom);
+}
+
+
+void
+DesktopWindow::setName(const char* name) {
+ SetWindowText(handle, TStr(name));
+}
+
+
+void
+DesktopWindow::serverCutText(const char* str, int len) {
+ CharArray t(len+1);
+ memcpy(t.buf, str, len);
+ t.buf[len] = 0;
+ clipboard.setClipText(t.buf);
+}
+
+
+void DesktopWindow::fillRect(const Rect& r, Pixel pix) {
+ Rect img_rect = buffer->isScaling() ? buffer->calculateScaleBoundary(r) : r;
+ if (cursorBackingRect.overlaps(img_rect)) hideLocalCursor();
+ buffer->fillRect(r, pix);
+ invalidateDesktopRect(r);
+}
+void DesktopWindow::imageRect(const Rect& r, void* pixels) {
+ Rect img_rect = buffer->isScaling() ? buffer->calculateScaleBoundary(r) : r;
+ if (cursorBackingRect.overlaps(img_rect)) hideLocalCursor();
+ buffer->imageRect(r, pixels);
+ invalidateDesktopRect(r);
+}
+void DesktopWindow::copyRect(const Rect& r, int srcX, int srcY) {
+ Rect img_rect = buffer->isScaling() ? buffer->calculateScaleBoundary(r) : r;
+ if (cursorBackingRect.overlaps(img_rect) ||
+ cursorBackingRect.overlaps(Rect(srcX, srcY, srcX+img_rect.width(), srcY+img_rect.height())))
+ hideLocalCursor();
+ buffer->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY));
+ invalidateDesktopRect(r);
+}
+
+void DesktopWindow::invertRect(const Rect& r) {
+ int stride;
+ rdr::U8* p = buffer->isScaling() ? buffer->getPixelsRW(buffer->calculateScaleBoundary(r), &stride)
+ : buffer->getPixelsRW(r, &stride);
+ for (int y = 0; y < r.height(); y++) {
+ for (int x = 0; x < r.width(); x++) {
+ switch (buffer->getPF().bpp) {
+ case 8: ((rdr::U8* )p)[x+y*stride] ^= 0xff; break;
+ case 16: ((rdr::U16*)p)[x+y*stride] ^= 0xffff; break;
+ case 32: ((rdr::U32*)p)[x+y*stride] ^= 0xffffffff; break;
+ }
+ }
+ }
+ invalidateDesktopRect(r);
+}
diff --git a/win/vncviewer/DesktopWindow.h b/win/vncviewer/DesktopWindow.h
new file mode 100644
index 0000000..3d2211f
--- /dev/null
+++ b/win/vncviewer/DesktopWindow.h
@@ -0,0 +1,254 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- DesktopWindow.h
+
+// Each VNC connection instance (CConn) creates a DesktopWindow the
+// server initialisation message has been received. The CConn is
+// responsible for all RFB-specific and network issues. The
+// DesktopWindow is responsible for all GUI management issues.
+//
+// DesktopWindow provides a FullFramePixelBuffer interface for the
+// CConn to render updates into. It also requires a callback object
+// to be supplied, which will be notified when various events occur.
+
+#ifndef __RFB_WIN32_DESKTOP_WINDOW_H__
+#define __RFB_WIN32_DESKTOP_WINDOW_H__
+
+#include <rfb/Cursor.h>
+#include <rfb_win32/CKeyboard.h>
+#include <rfb_win32/CPointer.h>
+#include <rfb_win32/Clipboard.h>
+#include <rfb_win32/ScaledDIBSectionBuffer.h>
+#include <rfb_win32/LogicalPalette.h>
+#include <vncviewer/ViewerToolBar.h>
+
+
+namespace rfb {
+
+ namespace win32 {
+
+ class DesktopWindow : rfb::win32::Clipboard::Notifier {
+ public:
+ class Callback;
+
+ DesktopWindow(Callback* cb_);
+ ~DesktopWindow();
+
+ // - Window message handling procedure
+ LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+ // - Window message handling procedure for the framebuffer window
+ LRESULT processFrameMessage(UINT msg, WPARAM wParam, LPARAM lParam);
+
+ // - Determine the native pixel format of the window
+ // This can (and often will) differ from the PixelBuffer format
+ PixelFormat getNativePF() const;
+
+ // - Get the underlying window handle
+ // This is used by F8Menu to modify the window's menu
+ HWND getHandle() const {return handle;}
+
+ // - Get the framebuffer window handle
+ HWND getFrameHandle() const {return frameHandle;}
+
+ // - Set the window title
+ void setName(const char* name);
+
+ // - Set the key that causes the system/F8 menu to be displayed
+ void setMenuKey(rdr::U8 key) { menuKey = key; }
+
+ // - Pointer event handling
+ void setEmulate3(bool em3) { ptr.enableEmulate3(em3); }
+ void setPointerEventInterval(int interval) { ptr.enableInterval(interval); }
+
+ // - Set the pixel format, size etc of the underlying PixelBuffer
+ void setPF(const PixelFormat& pf);
+ PixelFormat getPF() const { return buffer->getPF(); }
+ void setSize(int w, int h);
+ void setColour(int i, int r, int g, int b) {buffer->setColour(i, r, g, b);}
+
+ // - Set the cursor to render when the pointer is within the desktop buffer
+ void setCursor(int w, int h, const Point& hotspot, void* data, void* mask);
+ void showCursor() { showLocalCursor(); }
+
+ // - Set the window fullscreen / determine whether it is fullscreen
+ void setFullscreen(bool fs);
+ bool isFullscreen() { return fullscreenActive; }
+
+ // - Set/get the toolbar's state
+ void setShowToolbar(bool st);
+ bool isToolbarEnabled() { return showToolbar; }
+
+ // - Set whether to disable special Windows keys & pass them straight to server
+ void setDisableWinKeys(bool dwk);
+
+ // - Set/get which monitor the window should be displayed on
+ void setMonitor(const char* monitor);
+ char* getMonitor() const;
+
+ // - Set the local clipboard
+ void serverCutText(const char* str, int len);
+
+ // - Draw into the desktop buffer & update the window
+ void fillRect(const Rect& r, Pixel pix);
+ void imageRect(const Rect& r, void* pixels);
+ void copyRect(const Rect& r, int srcX, int srcY);
+
+ void invertRect(const Rect& r);
+
+ // - Update the window palette if the display is palette-based.
+ // Colours are pulled from the desktop buffer's ColourMap.
+ // Only the specified range of indexes is dealt with.
+ // After the update, the entire window is redrawn.
+ void refreshWindowPalette(int start, int count);
+
+ // Clipboard::Notifier interface
+ void notifyClipboardChanged(const char* text, int len);
+
+ // DesktopWindow Callback interface
+ class Callback : public InputHandler {
+ public:
+ virtual ~Callback() {}
+ virtual void displayChanged() = 0;
+ virtual void paintCompleted() = 0;
+ virtual bool sysCommand(WPARAM wParam, LPARAM lParam) = 0;
+ virtual void closeWindow() = 0;
+ virtual void refreshMenu(bool enableSysItems) = 0;
+ };
+
+ // Currently accessible so that the CConn can releaseAllKeys & check
+ // whether Ctrl and Alt are down...
+ rfb::win32::CKeyboard kbd;
+
+ protected:
+ // Routines to convert between Desktop and client (window) coordinates
+ Point desktopToClient(const Point& p) {
+ Point pos = p;
+ if (client_size.width() > buffer->width())
+ pos.x += (client_size.width() - buffer->width()) / 2;
+ else if (client_size.width() < buffer->width())
+ pos.x -= scrolloffset.x;
+ if (client_size.height() > buffer->height())
+ pos.y += (client_size.height() - buffer->height()) / 2;
+ else if (client_size.height() < buffer->height())
+ pos.y -= scrolloffset.y;
+ return pos;
+ }
+ Rect desktopToClient(const Rect& r) {
+ return Rect(desktopToClient(r.tl), desktopToClient(r.br));
+ }
+ Point clientToDesktop(const Point& p) {
+ Point pos = p;
+ if (client_size.width() > buffer->width())
+ pos.x -= (client_size.width() - buffer->width()) / 2;
+ else if (client_size.width() < buffer->width())
+ pos.x += scrolloffset.x;
+ if (client_size.height() > buffer->height())
+ pos.y -= (client_size.height() - buffer->height()) / 2;
+ else if (client_size.height() < buffer->height())
+ pos.y += scrolloffset.y;
+ return pos;
+ }
+ Rect clientToDesktop(const Rect& r) {
+ return Rect(clientToDesktop(r.tl), clientToDesktop(r.br));
+ }
+
+ // Internal routine used by the scrollbars & bump scroller to select
+ // the portion of the Desktop to display
+ bool setViewportOffset(const Point& tl);
+
+ // Bump scroll handling. Bump scrolling is used if the window is
+ // in fullscreen mode and the Desktop is larger than the window
+ bool processBumpScroll(const Point& cursorPos);
+ void setBumpScroll(bool on);
+ bool bumpScroll;
+ Point bumpScrollDelta;
+ IntervalTimer bumpScrollTimer;
+
+ // Locally-rendered VNC cursor
+ void hideLocalCursor();
+ void showLocalCursor();
+ void renderLocalCursor();
+
+ // The system-rendered cursor
+ void hideSystemCursor();
+ void showSystemCursor();
+
+ // cursorOutsideBuffer() is called whenever we detect that the mouse has
+ // moved outside the desktop. It restores the system arrow cursor.
+ void cursorOutsideBuffer();
+
+ // Returns true if part of the supplied rect is visible, false otherwise
+ bool invalidateDesktopRect(const Rect& crect, bool scaling=true);
+
+ // Determine whether or not we need to enable/disable scrollbars and set the
+ // window style accordingly
+ void calculateScrollBars();
+
+ // Win32-specific input handling
+ rfb::win32::CPointer ptr;
+ Point oldpos;
+ rfb::win32::Clipboard clipboard;
+
+ // Palette handling
+ LogicalPalette windowPalette;
+ bool palette_changed;
+
+ // - Full-screen mode
+ RECT fullscreenOldRect;
+ DWORD fullscreenOldFlags;
+ bool fullscreenActive;
+ bool fullscreenRestore;
+
+ // Cursor handling
+ Cursor cursor;
+ bool systemCursorVisible; // Should system-cursor be drawn?
+ bool trackingMouseLeave;
+ bool cursorInBuffer; // Is cursor position within server buffer? (ONLY for LocalCursor)
+ bool cursorVisible; // Is cursor currently rendered?
+ bool cursorAvailable; // Is cursor available for rendering?
+ Point cursorPos;
+ ManagedPixelBuffer cursorBacking;
+ Rect cursorBackingRect;
+
+ // ToolBar handling
+ ViewerToolBar tb;
+ bool showToolbar;
+
+ // Local window state
+ win32::ScaledDIBSectionBuffer* buffer;
+ bool has_focus;
+ Rect window_size;
+ Rect client_size;
+ Point scrolloffset;
+ Point maxscrolloffset;
+ HWND handle;
+ HWND frameHandle;
+ rdr::U8 menuKey;
+
+ Callback* callback;
+ };
+
+ };
+
+};
+
+#endif // __RFB_WIN32_DESKTOP_WINDOW_H__
+
+
diff --git a/win/vncviewer/FTBrowseDlg.cxx b/win/vncviewer/FTBrowseDlg.cxx
new file mode 100644
index 0000000..1b6dfb6
--- /dev/null
+++ b/win/vncviewer/FTBrowseDlg.cxx
@@ -0,0 +1,196 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTBrpwseDlg.cxx
+
+#include <vncviewer/FTBrowseDlg.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FTBrowseDlg::FTBrowseDlg(FTDialog *pFTDlg)
+{
+ m_pFTDlg = pFTDlg;
+ m_hwndDlg = NULL;
+ m_hwndTree = NULL;
+ m_hParentItem = NULL;
+}
+
+FTBrowseDlg::~FTBrowseDlg()
+{
+ destroy();
+}
+
+bool
+FTBrowseDlg::create()
+{
+ m_hwndDlg = CreateDialogParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_FTBROWSE),
+ m_pFTDlg->getWndHandle(), (DLGPROC) FTBrowseDlgProc,
+ (LONG) this);
+
+ if (m_hwndDlg == NULL) return false;
+
+ m_hwndTree = GetDlgItem(m_hwndDlg, IDC_FTBROWSETREE);
+
+ ShowWindow(m_hwndDlg, SW_SHOW);
+ UpdateWindow(m_hwndDlg);
+
+ return true;
+}
+
+void
+FTBrowseDlg::destroy()
+{
+ EndDialog(m_hwndDlg, 0);
+}
+
+void
+FTBrowseDlg::addItems(FileInfo *pFI)
+{
+ TVITEM tvi;
+ TVINSERTSTRUCT tvins;
+
+ if (pFI->getNumEntries() <= 0) return;
+
+ for (unsigned int i = 0; i < pFI->getNumEntries(); i++)
+ {
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = pFI->getNameAt(i);;
+ tvins.hParent = m_hParentItem;
+ tvins.item = tvi;
+ tvins.hParent = TreeView_InsertItem(m_hwndTree, &tvins);
+ TreeView_InsertItem(m_hwndTree, &tvins);
+ }
+}
+
+char *
+FTBrowseDlg::getTVPath(HTREEITEM hTItem)
+{
+ char path[FT_FILENAME_SIZE];
+ char szText[FT_FILENAME_SIZE];
+
+ TVITEM tvi;
+ path[0] = '\0';
+
+ do {
+ tvi.mask = TVIF_TEXT | TVIF_HANDLE;
+ tvi.hItem = hTItem;
+ tvi.pszText = szText;
+ tvi.cchTextMax = FT_FILENAME_SIZE;
+ TreeView_GetItem(m_hwndTree, &tvi);
+ sprintf(path, "%s\\%s", path, tvi.pszText);
+ hTItem = TreeView_GetParent(m_hwndTree, hTItem);
+ } while(hTItem != NULL);
+
+ return pathInvert(path);
+}
+
+char *
+FTBrowseDlg::pathInvert(char *pPath)
+{
+ int len = strlen(pPath);
+ m_szPath[0] = '\0';
+ char *pos = NULL;
+
+ while ((pos = strrchr(pPath, '\\')) != NULL) {
+ if (strlen(m_szPath) == 0) {
+ strcpy(m_szPath, (pos + 1));
+ } else {
+ sprintf(m_szPath, "%s\\%s", m_szPath, (pos + 1));
+ }
+ *pos = '\0';
+ }
+
+ m_szPath[len] = '\0';
+ return m_szPath;
+}
+
+char *
+FTBrowseDlg::getPath()
+{
+ GetDlgItemText(m_hwndDlg, IDC_FTBROWSEPATH, m_szPath, FT_FILENAME_SIZE);
+ return m_szPath;
+}
+
+void
+FTBrowseDlg::deleteChildItems()
+{
+ while (TreeView_GetChild(m_hwndTree, m_hParentItem) != NULL) {
+ TreeView_DeleteItem(m_hwndTree, TreeView_GetChild(m_hwndTree, m_hParentItem));
+ }
+}
+
+BOOL CALLBACK
+FTBrowseDlg::FTBrowseDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ FTBrowseDlg *_this = (FTBrowseDlg *) GetWindowLong(hwnd, GWL_USERDATA);
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ SetWindowLong(hwnd, GWL_USERDATA, lParam);
+ return FALSE;
+ }
+ break;
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ _this->m_pFTDlg->onEndBrowseDlg(true);
+ return FALSE;
+ case IDCANCEL:
+ _this->m_pFTDlg->onEndBrowseDlg(false);
+ return FALSE;
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ switch (LOWORD(wParam))
+ {
+ case IDC_FTBROWSETREE:
+ switch (((LPNMHDR) lParam)->code)
+ {
+ case TVN_SELCHANGED:
+ SetDlgItemText(hwnd, IDC_FTBROWSEPATH, _this->getTVPath(((NMTREEVIEW *) lParam)->itemNew.hItem));
+ return FALSE;
+// case TVN_ITEMEXPANDING:
+ case TVN_ITEMEXPANDED:
+ {
+ NMTREEVIEW *nmCode = (NMTREEVIEW *) lParam;
+ if (nmCode->action == 2) {
+ _this->m_hParentItem = nmCode->itemNew.hItem;
+ _this->deleteChildItems();
+ _this->m_pFTDlg->getBrowseItems(_this->getTVPath(_this->m_hParentItem));
+ }
+ }
+ return FALSE;
+ }
+ break;
+ case WM_CLOSE:
+ _this->m_pFTDlg->onEndBrowseDlg(false);
+ return FALSE;
+ }
+ }
+ return 0;
+}
diff --git a/win/vncviewer/FTBrowseDlg.h b/win/vncviewer/FTBrowseDlg.h
new file mode 100644
index 0000000..5c9ba35
--- /dev/null
+++ b/win/vncviewer/FTBrowseDlg.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTBrowseDlg.h
+
+#ifndef __RFB_WIN32_FTBROWSEDLG_H__
+#define __RFB_WIN32_FTBROWSEDLG_H__
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <rfb/FileInfo.h>
+#include <vncviewer/FTDialog.h>
+#include <vncviewer/resource.h>
+
+namespace rfb {
+ namespace win32 {
+ class FTDialog;
+
+ class FTBrowseDlg
+ {
+ public:
+ FTBrowseDlg(FTDialog *pFTDlg);
+ ~FTBrowseDlg();
+
+ static BOOL CALLBACK FTBrowseDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ bool create();
+ void destroy();
+
+ void addItems(FileInfo *pFI);
+ char *getPath();
+
+ void deleteChildItems();
+
+ private:
+ HWND m_hwndDlg;
+ HWND m_hwndTree;
+ FTDialog *m_pFTDlg;
+ HTREEITEM m_hParentItem;
+
+ char m_szPath[FT_FILENAME_SIZE];
+
+ char *pathInvert(char *pPath);
+ char *getTVPath(HTREEITEM hTItem);
+ };
+ }
+}
+
+#endif // __RFB_WIN32_FTBROWSEDLG_H__
diff --git a/win/vncviewer/FTDialog.cxx b/win/vncviewer/FTDialog.cxx
new file mode 100644
index 0000000..5f71f7d
--- /dev/null
+++ b/win/vncviewer/FTDialog.cxx
@@ -0,0 +1,1162 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTDialog.cxx
+
+#include <vncviewer/FTDialog.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+const char FTDialog::szCheckDeleteQueueText[] = "TightVNC.Viewer.CheckDeleteQueue.Msg";
+const char FTDialog::szCheckTransferQueueText[] = "TightVNC.Viewer.CheckTransferQueue.Msg";
+const char FTDialog::szUploadFilePortionText[] = "TightVNC.Viewer.UploadFilePortion.Msg";
+
+FTDialog::FTDialog(HINSTANCE hInst, FileTransfer *pFT)
+{
+ m_pFileTransfer = pFT;
+ m_hInstance = hInst;
+
+ m_bDlgShown = false;
+ m_bLocalBrowsing = true;
+ m_bCloseDlgAfterCancel = false;
+
+ m_pLocalLV = NULL;
+ m_pRemoteLV = NULL;
+ m_pProgress = NULL;
+ m_pCancelingDlg = NULL;
+ m_pCreateFolderDlg = NULL;
+ m_pRenameDlg = NULL;
+ m_pBrowseDlg = NULL;
+
+ m_hwndFTDialog = NULL;
+ m_hwndLocalPath = NULL;
+ m_hwndRemotePath = NULL;
+
+ m_FTMenuSource = 0;
+ m_dwNumStatusStrings = 0;
+
+ m_szLocalPath[0] = '\0';
+ m_szRemotePath[0] = '\0';
+ m_szLocalPathTmp[0] = '\0';
+ m_szRemotePathTmp[0] = '\0';
+ m_szCreateFolderName[0] = '\0';
+}
+
+FTDialog::~FTDialog()
+{
+ destroyFTDialog();
+}
+
+bool
+FTDialog::createFTDialog(HWND hwndParent)
+{
+ if (m_hwndFTDialog != NULL) {
+ ShowWindow(m_hwndFTDialog, SW_SHOW);
+ m_bDlgShown = true;
+ showLocalLVItems();
+ showRemoteLVItems();
+ return true;
+ }
+
+ if (!initFTWndMsgs()) return false;
+
+ m_hwndFTDialog = CreateDialogParam(m_hInstance,
+ MAKEINTRESOURCE(IDD_FILETRANSFER_DLG),
+ hwndParent,
+ (DLGPROC) FTDialogProc,
+ (LONG) this);
+
+ if (m_hwndFTDialog == NULL) return false;
+
+ HWND hwndLocalList = GetDlgItem(m_hwndFTDialog, IDC_FTLOCALLIST);
+ HWND hwndRemoteList = GetDlgItem(m_hwndFTDialog, IDC_FTREMOTELIST);
+
+ if ((hwndLocalList == NULL) || (hwndRemoteList == NULL)) {
+ destroyFTDialog();
+ return false;
+ }
+
+ m_pLocalLV = new FTListView(hwndLocalList);
+ m_pRemoteLV = new FTListView(hwndRemoteList);
+
+ m_pProgress = new FTProgress(m_hwndFTDialog);
+
+ if ((m_pLocalLV == NULL) || (m_pRemoteLV == NULL) || (m_pProgress == NULL)) {
+ destroyFTDialog();
+ return false;
+ }
+
+ initFTDialog();
+
+ ShowWindow(m_hwndFTDialog, SW_SHOW);
+ UpdateWindow(m_hwndFTDialog);
+ m_bDlgShown = true;
+ return true;
+}
+
+bool
+FTDialog::initFTDialog()
+{
+ m_pLocalLV->initialize(m_hInstance);
+ m_pRemoteLV->initialize(m_hInstance);
+
+ m_hwndLocalPath = GetDlgItem(m_hwndFTDialog, IDC_FTLOCALPATH);
+ m_hwndRemotePath = GetDlgItem(m_hwndFTDialog, IDC_FTREMOTEPATH);
+
+ setIcon(IDC_FTLOCALUP, IDI_FTUP);
+ setIcon(IDC_FTREMOTEUP, IDI_FTUP);
+ setIcon(IDC_FTLOCALRELOAD, IDI_FTRELOAD);
+ setIcon(IDC_FTREMOTERELOAD, IDI_FTRELOAD);
+
+ showLocalLVItems();
+ showRemoteLVItems();
+
+ return true;
+}
+
+bool
+FTDialog::initFTWndMsgs()
+{
+ m_msgCheckDeleteQueue = RegisterWindowMessage(szCheckDeleteQueueText);
+ m_msgCheckTransferQueue = RegisterWindowMessage(szCheckTransferQueueText);
+ m_msgUploadFilePortion = RegisterWindowMessage(szUploadFilePortionText);
+
+ if ((m_msgCheckDeleteQueue) &&
+ (m_msgCheckTransferQueue) &&
+ (m_msgUploadFilePortion)) return true;
+
+ return false;
+}
+
+bool
+FTDialog::closeFTDialog()
+{
+ ShowWindow(m_hwndFTDialog, SW_HIDE);
+ m_bDlgShown = false;
+ return true;
+}
+
+void
+FTDialog::destroyFTDialog()
+{
+ if (m_pLocalLV != NULL) {
+ delete m_pLocalLV;
+ m_pLocalLV = NULL;
+ }
+
+ if (m_pRemoteLV != NULL) {
+ delete m_pRemoteLV;
+ m_pRemoteLV = NULL;
+ }
+
+ if (m_pProgress != NULL) {
+ delete m_pProgress;
+ m_pProgress = NULL;
+ }
+
+ if(m_pCancelingDlg != NULL) {
+ delete m_pCancelingDlg;
+ m_pCancelingDlg = NULL;
+ }
+
+ if (m_pCreateFolderDlg != NULL) {
+ delete m_pCreateFolderDlg;
+ m_pCreateFolderDlg = NULL;
+ }
+
+ if(m_pRenameDlg != NULL) {
+ delete m_pRenameDlg;
+ m_pRenameDlg = NULL;
+ }
+
+ if (DestroyWindow(m_hwndFTDialog)) m_hwndFTDialog = NULL;
+}
+
+BOOL CALLBACK
+FTDialog::FTDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ FTDialog *_this = (FTDialog *) GetWindowLong(hwnd, GWL_USERDATA);
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ _this = (FTDialog*)lParam;
+ SetWindowLong(hwnd, GWL_USERDATA, (LONG) lParam);
+ SetForegroundWindow(hwnd);
+ return TRUE;
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_FTLOCALPATH:
+ switch (HIWORD (wParam))
+ {
+ case CBN_SETFOCUS:
+ _this->setButtonsState();
+ return FALSE;
+ }
+ break;
+ case IDC_FTREMOTEPATH:
+ switch (HIWORD (wParam))
+ {
+ case CBN_SETFOCUS:
+ _this->setButtonsState();
+ return FALSE;
+ }
+ break;
+ case IDC_FTCLOSE:
+ _this->onClose();
+ return FALSE;
+ case IDC_FTLOCALBROWSE:
+ _this->onLocalBrowse();
+ return FALSE;
+ case IDC_FTREMOTEBROWSE:
+ _this->onRemoteBrowse();
+ return FALSE;
+ case IDC_FTLOCALUP:
+ _this->setButtonsState();
+ _this->onLocalOneUpFolder();
+ return FALSE;
+ case IDC_FTREMOTEUP:
+ _this->setButtonsState();
+ _this->onRemoteOneUpFolder();
+ return FALSE;
+ case IDC_FTLOCALRELOAD:
+ _this->setButtonsState();
+ _this->onLocalReload();
+ return FALSE;
+ case IDC_FTREMOTERELOAD:
+ _this->setButtonsState();
+ _this->onRemoteReload();
+ return FALSE;
+ case IDC_FTUPLOAD:
+ _this->onUpload();
+ return FALSE;
+ case IDC_FTDOWNLOAD:
+ _this->onDownload();
+ return FALSE;
+ case IDC_FTCANCEL:
+ _this->onFTCancel();
+ return FALSE;
+ case IDM_FTCOPY:
+ case IDM_FTRENAME:
+ case IDM_FTDELETE:
+ case IDM_FTCANCEL:
+ case IDM_FTCREATEFOLDER:
+ _this->onFTMenuCommand(LOWORD(wParam));
+ return FALSE;
+ }
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch (LOWORD(wParam))
+ {
+ case IDC_FTLOCALLIST:
+ switch (((LPNMHDR) lParam)->code)
+ {
+ case NM_CLICK:
+ case NM_SETFOCUS:
+ case LVN_ITEMCHANGED:
+ _this->setButtonsState();
+ return FALSE;
+ case LVN_GETDISPINFO:
+ _this->m_pLocalLV->onGetDispInfo((NMLVDISPINFO *) lParam);
+ return FALSE;
+ case LVN_ITEMACTIVATE:
+ _this->onLocalItemActivate((LPNMITEMACTIVATE) lParam);
+ return FALSE;
+ case NM_RCLICK:
+ _this->onLocalRButton();
+ return FALSE;
+ }
+ break;
+ case IDC_FTREMOTELIST:
+ switch (((LPNMHDR) lParam)->code)
+ {
+ case NM_CLICK:
+ case NM_SETFOCUS:
+ case LVN_ITEMCHANGED:
+ _this->setButtonsState();
+ case LVN_GETDISPINFO:
+ _this->m_pRemoteLV->onGetDispInfo((NMLVDISPINFO *) lParam);
+ return FALSE;
+ case LVN_ITEMACTIVATE:
+ _this->onRemoteItemActivate((LPNMITEMACTIVATE) lParam);
+ return FALSE;
+ case NM_RCLICK:
+ _this->onRemoteRButton();
+ return FALSE;
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ _this->onClose();
+ return FALSE;
+ }
+
+ if (_this != NULL) {
+ if (uMsg == _this->m_msgCheckTransferQueue)
+ _this->m_pFileTransfer->checkTransferQueue();
+
+ if (uMsg == _this->m_msgUploadFilePortion)
+ _this->m_pFileTransfer->uploadFilePortion();
+
+ if (uMsg == _this->m_msgCheckDeleteQueue)
+ _this->m_pFileTransfer->checkDeleteQueue();
+ }
+
+ return FALSE;
+}
+
+void
+FTDialog::onClose()
+{
+ if (m_pFileTransfer->isTransferEnable()) {
+ m_bCloseDlgAfterCancel = true;
+ onFTCancel();
+ } else {
+ closeFTDialog();
+ }
+}
+
+void
+FTDialog::onLocalItemActivate(LPNMITEMACTIVATE lpnmia)
+{
+ if (strlen(m_szLocalPath) == 0) {
+ strcpy(m_szLocalPathTmp, m_pLocalLV->getActivateItemName(lpnmia));
+ } else {
+ sprintf(m_szLocalPathTmp, "%s\\%s", m_szLocalPath, m_pLocalLV->getActivateItemName(lpnmia));
+ }
+ showLocalLVItems();
+}
+
+void
+FTDialog::onRemoteItemActivate(LPNMITEMACTIVATE lpnmia)
+{
+ if (strlen(m_szRemotePath) == 0) {
+ strcpy(m_szRemotePathTmp, m_pRemoteLV->getActivateItemName(lpnmia));
+ } else {
+ sprintf(m_szRemotePathTmp, "%s\\%s", m_szRemotePath, m_pRemoteLV->getActivateItemName(lpnmia));
+ }
+ showRemoteLVItems();
+}
+
+void
+FTDialog::onEndBrowseDlg(bool bResult)
+{
+ if (m_pBrowseDlg == NULL) return;
+
+ if (bResult) {
+ if (m_bLocalBrowsing) {
+ strcpy(m_szLocalPathTmp, m_pBrowseDlg->getPath());
+ showLocalLVItems();
+ } else {
+ strcpy(m_szRemotePathTmp, m_pBrowseDlg->getPath());
+ showRemoteLVItems();
+ }
+ }
+ delete m_pBrowseDlg;
+ m_pBrowseDlg = NULL;
+}
+
+void
+FTDialog::onLocalBrowse()
+{
+ if (m_pBrowseDlg != NULL) return;
+
+ m_bLocalBrowsing = true;
+
+ m_pBrowseDlg = new FTBrowseDlg(this);
+ m_pBrowseDlg->create();
+
+ getBrowseItems("");
+}
+
+void
+FTDialog::onRemoteBrowse()
+{
+ if (m_pBrowseDlg != NULL) return;
+
+ m_bLocalBrowsing = false;
+
+ m_pBrowseDlg = new FTBrowseDlg(this);
+ if (m_pBrowseDlg->create()) {
+ m_pFileTransfer->requestFileList("", FT_FLR_DEST_BROWSE, true);
+ } else {
+ delete m_pBrowseDlg;
+ m_pBrowseDlg = NULL;
+ }
+}
+
+void
+FTDialog::onLocalReload()
+{
+ strcpy(m_szLocalPathTmp, m_szLocalPath);
+ showLocalLVItems();
+}
+
+void
+FTDialog::onRemoteReload()
+{
+ strcpy(m_szRemotePathTmp, m_szRemotePath);
+ showRemoteLVItems();
+}
+
+void
+FTDialog::showLocalLVItems()
+{
+ FolderManager fm;
+ FileInfo fileInfo;
+ if (fm.getDirInfo(m_szLocalPathTmp, &fileInfo, 0)) {
+ fileInfo.sort();
+ m_pLocalLV->deleteAllItems();
+ m_pLocalLV->addItems(&fileInfo);
+ strcpy(m_szLocalPath, m_szLocalPathTmp);
+ SetWindowText(m_hwndLocalPath, m_szLocalPath);
+ }
+}
+
+void
+FTDialog::showRemoteLVItems()
+{
+ m_pFileTransfer->requestFileList(m_szRemotePathTmp, FT_FLR_DEST_MAIN, false);
+}
+
+void
+FTDialog::addRemoteLVItems(FileInfo *pFI)
+{
+ pFI->sort();
+ m_pRemoteLV->deleteAllItems();
+ m_pRemoteLV->addItems(pFI);
+ strcpy(m_szRemotePath, m_szRemotePathTmp);
+ SetWindowText(m_hwndRemotePath, m_szRemotePath);
+ UpdateWindow(m_hwndFTDialog);
+}
+
+void
+FTDialog::onLocalOneUpFolder()
+{
+ strcpy(m_szLocalPathTmp, m_szLocalPath);
+ makeOneUpFolder(m_szLocalPathTmp);
+ showLocalLVItems();
+}
+
+void
+FTDialog::onRemoteOneUpFolder()
+{
+ strcpy(m_szRemotePathTmp, m_szRemotePath);
+ makeOneUpFolder(m_szRemotePathTmp);
+ showRemoteLVItems();
+}
+
+void
+FTDialog::reqFolderUnavailable()
+{
+ strcpy(m_szRemotePathTmp, m_szRemotePath);
+ SetWindowText(m_hwndRemotePath, m_szRemotePath);
+ UpdateWindow(m_hwndFTDialog);
+}
+
+int
+FTDialog::makeOneUpFolder(char *pPath)
+{
+ if (strcmp(pPath, "") == 0) return strlen(pPath);
+ for (int i=(strlen(pPath)-2); i>=0; i--) {
+ if (pPath[i] == '\\') {
+ pPath[i] = '\0';
+ break;
+ }
+ if (i == 0) pPath[0] = '\0';
+ }
+ return strlen(pPath);
+}
+
+void
+FTDialog::onUpload()
+{
+ FileInfo fi;
+ char prefix[FT_FILENAME_SIZE];
+ prefix[0] = '\0';
+
+ if (m_pFileTransfer->isTransferEnable())
+ strcpy(prefix, "File Transfer is active.\nDo you want to add selected file(s)/folder(s) to transfer queue?\n\n");
+
+ int numSel = m_pLocalLV->getSelectedItems(&fi);
+ if (numSel > 0) {
+ char *pBuf = new char [(numSel + 4) * (MAX_PATH + 3) + strlen(prefix) + 1];
+ sprintf(pBuf, "%sFrom: Local Computer %s\\\n\n", prefix, m_szLocalPath);
+
+ for (unsigned int i = 0; i < fi.getNumEntries(); i++)
+ sprintf(pBuf, "%s%s, ", pBuf, fi.getNameAt(i));
+
+ sprintf(pBuf, "%s\n\nTo: Remote Computer %s\\", pBuf, m_szRemotePath);
+
+ if (strlen(pBuf) > 2048)
+ sprintf(pBuf, "%sFrom: Local Computer %s\\\n\nTo: Remote Computer %s\\\n\nTotal %d file(s)/folder(s)",
+ prefix, m_szLocalPath, m_szRemotePath, numSel);
+
+ if (MessageBox(m_hwndFTDialog, pBuf, "Copy Selected Files and Folders", MB_OKCANCEL) == IDOK)
+ m_pFileTransfer->addTransferQueue(m_szLocalPath, m_szRemotePath, &fi, FT_ATTR_COPY_UPLOAD);
+
+ setButtonsState();
+
+ delete [] pBuf;
+ return;
+ }
+
+ setButtonsState();
+ setStatusText("File Transfer Impossible. No file(s) selected for transfer");
+}
+
+void
+FTDialog::onDownload()
+{
+ FileInfo fi;
+ char prefix[FT_FILENAME_SIZE];
+ prefix[0] = '\0';
+
+ if (m_pFileTransfer->isTransferEnable())
+ strcpy(prefix, "File Transfer is active.\nDo you want to add selected file(s)/folder(s) to transfer queue?\n\n");
+
+ int numSel = m_pRemoteLV->getSelectedItems(&fi);
+ if (numSel > 0) {
+ char *pBuf = new char [(numSel + 4) * (MAX_PATH + 3) + strlen(prefix) + 1];
+ sprintf(pBuf, "%sFrom: Remote Computer %s\\\n\n", prefix, m_szRemotePath);
+
+ for (unsigned int i = 0; i < fi.getNumEntries(); i++)
+ sprintf(pBuf, "%s%s, ", pBuf, fi.getNameAt(i));
+
+ sprintf(pBuf, "%s\n\nTo: Local Computer %s\\", pBuf, m_szLocalPath);
+
+ if (strlen(pBuf) > 2048)
+ sprintf(pBuf, "%sFrom: Remote Computer %s\\\n\nTo: Local Computer %s\\\n\nTotal %d file(s)/folder(s)",
+ prefix, m_szRemotePath, m_szLocalPath, numSel);
+
+ if (MessageBox(m_hwndFTDialog, pBuf, "Copy Selected Files and Folders", MB_OKCANCEL) == IDOK)
+ m_pFileTransfer->addTransferQueue(m_szLocalPath, m_szRemotePath, &fi, FT_ATTR_COPY_DOWNLOAD);
+
+ setButtonsState();
+
+ delete [] pBuf;
+ return;
+ }
+
+ setButtonsState();
+ setStatusText("File Transfer Impossible. No file(s) selected for transfer");
+}
+
+void
+FTDialog::onLocalRename()
+{
+ if (m_pRenameDlg != NULL) return;
+
+ FileInfo fi;
+ if (m_pLocalLV->getSelectedItems(&fi) == 1) {
+ unsigned int flags = fi.getFlagsAt(0);
+ m_pRenameDlg = new FTDialog::RenameDlg(this);
+ if (m_pRenameDlg != NULL) {
+ if (flags & FT_ATTR_DIR) {
+ m_pRenameDlg->create(fi.getNameAt(0), true);
+ } else {
+ m_pRenameDlg->create(fi.getNameAt(0), false);
+ }
+ if (strlen(m_pRenameDlg->getFolderName()) > 0) {
+ FolderManager fm;
+ fm.renameIt(m_szLocalPath, fi.getNameAt(0), m_pRenameDlg->getFolderName());
+ showLocalLVItems();
+ }
+ delete m_pRenameDlg;
+ m_pRenameDlg = NULL;
+ }
+ }
+ setButtonsState();
+}
+
+void
+FTDialog::onRemoteRename()
+{
+ if (m_pRenameDlg != NULL) return;
+
+ FileInfo fi;
+ if (m_pRemoteLV->getSelectedItems(&fi) == 1) {
+ unsigned int flags = fi.getFlagsAt(0);
+ m_pRenameDlg = new FTDialog::RenameDlg(this);
+ if (m_pRenameDlg != NULL) {
+ if (flags & FT_ATTR_DIR) {
+ m_pRenameDlg->create(fi.getNameAt(0), true);
+ } else {
+ m_pRenameDlg->create(fi.getNameAt(0), false);
+ }
+ if (strlen(m_pRenameDlg->getFolderName()) > 0) {
+ m_pFileTransfer->renameRemote(m_szRemotePath, fi.getNameAt(0), m_pRenameDlg->getFolderName());
+ }
+ delete m_pRenameDlg;
+ m_pRenameDlg = NULL;
+ }
+ }
+ setButtonsState();
+}
+
+void
+FTDialog::onLocalDelete()
+{
+ FileInfo fi;
+ if (m_pLocalLV->getSelectedItems(&fi) > 0) {
+ m_pFileTransfer->addDeleteQueue(m_szLocalPath, &fi, FT_ATTR_DELETE_LOCAL);
+ }
+ setButtonsState();
+}
+
+void
+FTDialog::onRemoteDelete()
+{
+ FileInfo fi;
+ if (m_pRemoteLV->getSelectedItems(&fi) > 0) {
+ m_pFileTransfer->addDeleteQueue(m_szRemotePath, &fi, FT_ATTR_DELETE_REMOTE);
+ }
+ setButtonsState();
+}
+
+bool
+FTDialog::getCreateFolderName()
+{
+ if (m_pCreateFolderDlg != NULL) return false;
+
+ bool bResult = false;
+
+ m_pCreateFolderDlg = new FTDialog::CreateFolderDlg(this);
+ m_pCreateFolderDlg->create();
+ if (strlen(m_pCreateFolderDlg->getFolderName()) != 0) {
+ strcpy(m_szCreateFolderName, m_pCreateFolderDlg->getFolderName());
+ bResult = true;
+ } else {
+ m_szCreateFolderName[0] = '\0';
+ bResult = false;
+ }
+ delete m_pCreateFolderDlg;
+ m_pCreateFolderDlg = NULL;
+
+ return bResult;
+}
+
+void
+FTDialog::onLocalCreateFolder()
+{
+ if (getCreateFolderName()) {
+ char path[FT_FILENAME_SIZE];
+ sprintf(path, "%s\\%s", m_szLocalPath, m_szCreateFolderName);
+ setStatusText("Creating Local Folder: %s", path);
+ FolderManager fm;
+ if (fm.createDir(path)) showLocalLVItems();
+ }
+}
+
+void
+FTDialog::onRemoteCreateFolder()
+{
+ if (getCreateFolderName()) {
+ m_pFileTransfer->createRemoteFolder(m_szRemotePath, m_szCreateFolderName);
+ }
+}
+
+void
+FTDialog::onFTCancel()
+{
+ if (m_pCancelingDlg != NULL) return;
+
+ m_pCancelingDlg = new CancelingDlg(this);
+
+ m_pCancelingDlg->create();
+}
+
+void
+FTDialog::cancelTransfer(bool bResult)
+{
+ if (m_pCancelingDlg != NULL) {
+ delete m_pCancelingDlg;
+ m_pCancelingDlg = NULL;
+ }
+
+ setButtonsState();
+
+ if ((m_bCloseDlgAfterCancel) && (bResult)) {
+ m_bCloseDlgAfterCancel = false;
+ closeFTDialog();
+ }
+
+ m_pFileTransfer->m_bCancel = bResult;
+}
+
+void
+FTDialog::afterCancelTransfer()
+{
+ if (m_pCancelingDlg != NULL) {
+ delete m_pCancelingDlg;
+ m_pCancelingDlg = NULL;
+ }
+}
+
+void
+FTDialog::onFTMenuCommand(int command)
+{
+ switch (command)
+ {
+ case IDM_FTCOPY:
+ {
+ switch (m_FTMenuSource)
+ {
+ case IDC_FTLOCALLIST: onUpload(); break;
+ case IDC_FTREMOTELIST: onDownload(); break;
+ default: break;
+ }
+ }
+ break;
+ case IDM_FTRENAME:
+ {
+ switch (m_FTMenuSource)
+ {
+ case IDC_FTLOCALLIST: onLocalRename(); break;
+ case IDC_FTREMOTELIST: onRemoteRename(); break;
+ default: break;
+ }
+ }
+ break;
+ case IDM_FTDELETE:
+ {
+ switch (m_FTMenuSource)
+ {
+ case IDC_FTLOCALLIST: onLocalDelete(); break;
+ case IDC_FTREMOTELIST: onRemoteDelete(); break;
+ default: break;
+ }
+ }
+ break;
+ case IDM_FTCANCEL: onFTCancel(); break;
+ case IDM_FTCREATEFOLDER:
+ {
+ switch (m_FTMenuSource)
+ {
+ case IDC_FTLOCALLIST: onLocalCreateFolder(); break;
+ case IDC_FTREMOTELIST: onRemoteCreateFolder(); break;
+ default: break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void
+FTDialog::onLocalRButton()
+{
+ refreshBtnState();
+ m_FTMenuSource = IDC_FTLOCALLIST;
+ showFTMenu(m_BtnState.uploadBtn, m_BtnState.createLocalFldBtn,
+ m_BtnState.renameLocalBtn, m_BtnState.deleteLocalBtn,
+ m_BtnState.cancelBtn);
+}
+
+void
+FTDialog::onRemoteRButton()
+{
+ refreshBtnState();
+ m_FTMenuSource = IDC_FTREMOTELIST;
+ showFTMenu(m_BtnState.downloadBtn, m_BtnState.createRemoteFldBtn,
+ m_BtnState.renameRemoteBtn, m_BtnState.deleteRemoteBtn,
+ m_BtnState.cancelBtn);
+}
+
+void
+FTDialog::showFTMenu(bool copyBtnState, bool createFldBtnState, bool renameBtnState,
+ bool deleteBtnState, bool cancelBtnState)
+{
+ HMENU hMenu = LoadMenu(m_hInstance, MAKEINTRESOURCE(IDR_FTMENU));
+ HMENU hFTMenu = GetSubMenu(hMenu, 0);
+
+ SetMenuDefaultItem(hFTMenu, IDM_FTCOPY, FALSE);
+
+ SetForegroundWindow(m_hwndFTDialog);
+
+ if (copyBtnState) {
+ EnableMenuItem(hMenu, IDM_FTCOPY, MF_ENABLED);
+ } else {
+ EnableMenuItem(hMenu, IDM_FTCOPY, MF_DISABLED | MF_GRAYED);
+ }
+ if (createFldBtnState) {
+ EnableMenuItem(hMenu, IDM_FTCREATEFOLDER, MF_ENABLED);
+ } else {
+ EnableMenuItem(hMenu, IDM_FTCREATEFOLDER, MF_DISABLED | MF_GRAYED);
+ }
+ if (renameBtnState) {
+ EnableMenuItem(hMenu, IDM_FTRENAME, MF_ENABLED);
+ } else {
+ EnableMenuItem(hMenu, IDM_FTRENAME, MF_DISABLED | MF_GRAYED);
+ }
+ if (deleteBtnState) {
+ EnableMenuItem(hMenu, IDM_FTDELETE, MF_ENABLED);
+ } else {
+ EnableMenuItem(hMenu, IDM_FTDELETE, MF_DISABLED | MF_GRAYED);
+ }
+ if (cancelBtnState) {
+ EnableMenuItem(hMenu, IDM_FTCANCEL, MF_ENABLED);
+ } else {
+ EnableMenuItem(hMenu, IDM_FTCANCEL, MF_DISABLED | MF_GRAYED);
+ }
+ DrawMenuBar(m_hwndFTDialog);
+
+ POINT cursorPosition;
+ GetCursorPos(&cursorPosition);
+ TrackPopupMenu(hFTMenu, 0, cursorPosition.x, cursorPosition.y, 0, m_hwndFTDialog, 0);
+ DestroyMenu(hFTMenu);
+}
+
+void
+FTDialog::setIcon(int dest, int idIcon)
+{
+ HANDLE hIcon = LoadImage(m_hInstance, MAKEINTRESOURCE(idIcon), IMAGE_ICON, 16, 16, LR_SHARED);
+ SendMessage(GetDlgItem(m_hwndFTDialog, dest), BM_SETIMAGE, (WPARAM) IMAGE_ICON, (LPARAM) hIcon);
+ DestroyIcon((HICON) hIcon);
+}
+
+void
+FTDialog::refreshBtnState()
+{
+ if (!m_bDlgShown) return;
+
+ int locPathLen = strlen(m_szLocalPath);
+ int remPathLen = strlen(m_szRemotePath);
+
+ if (GetFocus() == m_pLocalLV->getWndHandle()) {
+ m_BtnState.downloadBtn = false;
+ if (strlen(m_szLocalPath) != 0) {
+ m_BtnState.createLocalFldBtn = true;
+ int nCount = ListView_GetSelectedCount(m_pLocalLV->getWndHandle());
+ if (nCount <= 0) {
+ m_BtnState.uploadBtn = false;
+ m_BtnState.deleteLocalBtn = false;
+ m_BtnState.renameLocalBtn = false;
+ } else {
+ m_BtnState.deleteLocalBtn = true;
+ if (remPathLen == 0) {
+ m_BtnState.uploadBtn = false;
+ } else {
+ m_BtnState.uploadBtn = true;
+ }
+ if (nCount == 1) {
+ m_BtnState.renameLocalBtn = true;
+ } else {
+ m_BtnState.renameLocalBtn = false;
+ }
+ }
+ } else {
+ m_BtnState.uploadBtn = false;
+ m_BtnState.createLocalFldBtn = false;
+ m_BtnState.deleteLocalBtn = false;
+ m_BtnState.renameLocalBtn = false;
+ m_BtnState.downloadBtn = false;
+ }
+ } else {
+ if (GetFocus() == m_pRemoteLV->getWndHandle()) {
+ m_BtnState.uploadBtn = false;
+ if (strlen(m_szRemotePath) != 0) {
+ m_BtnState.createRemoteFldBtn = true;
+ int nCount = ListView_GetSelectedCount(m_pRemoteLV->getWndHandle());
+ if (nCount <= 0) {
+ m_BtnState.downloadBtn = false;
+ m_BtnState.deleteRemoteBtn = false;
+ m_BtnState.renameRemoteBtn = false;
+ } else {
+ m_BtnState.deleteRemoteBtn = true;
+ if (locPathLen == 0) {
+ m_BtnState.downloadBtn = false;
+ } else {
+ m_BtnState.downloadBtn = true;
+ }
+ if (nCount == 1) {
+ m_BtnState.renameRemoteBtn = true;
+ } else {
+ m_BtnState.renameRemoteBtn = false;
+ }
+ }
+ } else {
+ m_BtnState.downloadBtn = false;
+ m_BtnState.createRemoteFldBtn = false;
+ m_BtnState.deleteRemoteBtn = false;
+ m_BtnState.renameRemoteBtn = false;
+ m_BtnState.uploadBtn = false;
+ }
+ } else {
+ }
+ }
+ if (m_pFileTransfer->isTransferEnable())
+ m_BtnState.cancelBtn = true;
+ else
+ m_BtnState.cancelBtn = false;
+}
+
+void
+FTDialog::setButtonsState()
+{
+ refreshBtnState();
+
+ switch (m_BtnState.uploadBtn)
+ {
+ case false: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTUPLOAD), FALSE); break;
+ case true: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTUPLOAD), TRUE); break;
+ }
+
+ switch (m_BtnState.downloadBtn)
+ {
+ case false: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTDOWNLOAD), FALSE); break;
+ case true: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTDOWNLOAD), TRUE); break;
+ }
+
+ switch (m_BtnState.cancelBtn)
+ {
+ case false: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTCANCEL), FALSE); break;
+ case true: EnableWindow(GetDlgItem(m_hwndFTDialog, IDC_FTCANCEL), TRUE); break;
+ }
+
+ UpdateWindow(m_hwndFTDialog);
+}
+
+void
+FTDialog::setStatusText(LPCSTR format,...)
+{
+ char text[1024];
+ va_list args;
+ va_start(args, format);
+ int nSize = _vsnprintf(text, sizeof(text), format, args);
+
+ HWND hStatusBox = GetDlgItem(m_hwndFTDialog, IDC_FTSTATUS);
+
+ LRESULT lRes = SendMessage(hStatusBox, (UINT) CB_INSERTSTRING, (WPARAM) 0, (LPARAM) text);
+ if ((lRes != CB_ERR) && (lRes != CB_ERRSPACE)) {
+ lRes = SendMessage(hStatusBox, (UINT) CB_SETCURSEL, (WPARAM) lRes, (LPARAM) 0);
+ }
+
+ m_dwNumStatusStrings++;
+ if (m_dwNumStatusStrings > FT_MAX_STATUS_STRINGS) {
+ int numItems = SendMessage(hStatusBox, (UINT) CB_GETCOUNT, (WPARAM) 0, (LPARAM) 0);
+ if (numItems != CB_ERR) {
+ m_dwNumStatusStrings--;
+ SendMessage(hStatusBox, (UINT) CB_DELETESTRING, (WPARAM) numItems - 1, (LPARAM) 0);
+ }
+ }
+}
+
+void
+FTDialog::getBrowseItems(char *pPath)
+{
+ if (m_bLocalBrowsing) {
+ FileInfo fi;
+ FolderManager fm;
+ fm.getDirInfo(pPath, &fi, 1);
+ if (m_pBrowseDlg != NULL) m_pBrowseDlg->addItems(&fi);
+ } else {
+ m_pFileTransfer->requestFileList(pPath, FT_FLR_DEST_BROWSE, true);
+ }
+}
+
+void
+FTDialog::addBrowseItems(FileInfo *pFI)
+{
+ if (m_pBrowseDlg == NULL) return;
+
+ m_pBrowseDlg->addItems(pFI);
+}
+
+void
+FTDialog::processDlgMsgs()
+{
+ MSG msg;
+ while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+}
+
+void
+FTDialog::postCheckTransferQueueMsg()
+{
+ PostMessage(m_hwndFTDialog, m_msgCheckTransferQueue, 0, 0);
+}
+
+void
+FTDialog::postUploadFilePortionMsg()
+{
+ PostMessage(m_hwndFTDialog, m_msgUploadFilePortion, 0, 0);
+}
+
+void
+FTDialog::postCheckDeleteQueueMsg()
+{
+ PostMessage(m_hwndFTDialog, m_msgCheckDeleteQueue, 0, 0);
+}
+
+FTDialog::CancelingDlg::CancelingDlg(FTDialog *pFTDlg)
+{
+ m_pFTDlg = pFTDlg;
+ m_hwndDlg = NULL;
+}
+
+FTDialog::CancelingDlg::~CancelingDlg()
+{
+ destroy();
+}
+
+bool
+FTDialog::CancelingDlg::create()
+{
+ if (m_hwndDlg != NULL) return false;
+
+ m_hwndDlg = CreateDialogParam(GetModuleHandle(0),
+ MAKEINTRESOURCE(IDD_FTCANCELING),
+ NULL,
+ (DLGPROC) cancelingDlgProc,
+ (LONG) this);
+
+ if (m_hwndDlg == NULL) return false;
+
+ ShowWindow(m_hwndDlg, SW_SHOW);
+ DrawIcon(GetDC(m_hwndDlg), 15, 22, LoadIcon(NULL, IDI_QUESTION));
+ UpdateWindow(m_hwndDlg);
+
+ return true;
+}
+
+bool
+FTDialog::CancelingDlg::destroy()
+{
+ if (m_hwndDlg == NULL) return true;
+
+ if (DestroyWindow(m_hwndDlg)) {
+ m_hwndDlg = NULL;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool
+FTDialog::CancelingDlg::close(bool bResult)
+{
+ if (m_hwndDlg == NULL) return true;
+
+ destroy();
+
+ m_pFTDlg->cancelTransfer(bResult);
+
+ return false;
+}
+
+BOOL CALLBACK
+FTDialog::CancelingDlg::cancelingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ FTDialog::CancelingDlg *_this = (FTDialog::CancelingDlg *) GetWindowLong(hwnd, GWL_USERDATA);
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ SetWindowLong(hwnd, GWL_USERDATA, (LONG) lParam);
+ SetForegroundWindow(hwnd);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ _this->close(true);
+ return TRUE;
+ case IDCANCEL:
+ _this->close(false);
+ return TRUE;
+ }
+ break;
+ case WM_CLOSE:
+ _this->close(false);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+FTDialog::CreateFolderDlg::CreateFolderDlg(FTDialog *pFTDlg) : Dialog(GetModuleHandle(0))
+{
+ m_pFTDlg = pFTDlg;
+ m_szFolderName[0] = '\0';
+}
+
+FTDialog::CreateFolderDlg::~CreateFolderDlg()
+{
+
+}
+
+bool
+FTDialog::CreateFolderDlg::create()
+{
+ return showDialog(MAKEINTRESOURCE(IDD_FTCREATEFOLDER), m_pFTDlg->getWndHandle());
+}
+
+bool
+FTDialog::CreateFolderDlg::onOk()
+{
+ strcpy(m_szFolderName, getItemString(IDC_FTFOLDERNAME));
+ return true;
+}
+
+FTDialog::RenameDlg::RenameDlg(FTDialog *pFTDlg) : CreateFolderDlg(pFTDlg)
+{
+ m_bFolder = false;
+}
+
+FTDialog::RenameDlg::~RenameDlg()
+{
+}
+
+bool
+FTDialog::RenameDlg::create(char *pFilename, bool bFolder)
+{
+ m_bFolder = bFolder;
+ strcpy(m_szFilename, pFilename);
+ return showDialog(MAKEINTRESOURCE(IDD_FTCREATEFOLDER), m_pFTDlg->getWndHandle());
+}
+
+void
+FTDialog::RenameDlg::initDialog()
+{
+ char buf[2*FT_FILENAME_SIZE];
+ if (m_bFolder) {
+ SetWindowText(handle, "Rename Folder");
+ sprintf(buf, "Rename Folder '%s'", m_szFilename);
+ } else {
+ SetWindowText(handle, "Rename File");
+ sprintf(buf, "Rename File '%s'", m_szFilename);
+ }
+
+ setItemString(IDC_FTTEXT, buf);
+ setItemString(IDC_FTFOLDERNAME, m_szFilename);
+ SendDlgItemMessage(handle, IDC_FTFOLDERNAME, EM_SETSEL, (WPARAM) 0, (LPARAM) -1);
+}
diff --git a/win/vncviewer/FTDialog.h b/win/vncviewer/FTDialog.h
new file mode 100644
index 0000000..a4b5546
--- /dev/null
+++ b/win/vncviewer/FTDialog.h
@@ -0,0 +1,243 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTDialog.h
+
+#ifndef __RFB_WIN32_FTDIALOG_H__
+#define __RFB_WIN32_FTDIALOG_H__
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <rfb/FileInfo.h>
+#include <rfb_win32/Dialog.h>
+#include <vncviewer/FileTransfer.h>
+#include <vncviewer/FTListView.h>
+#include <vncviewer/FTProgress.h>
+#include <vncviewer/FTBrowseDlg.h>
+#include <vncviewer/resource.h>
+
+namespace rfb {
+ namespace win32 {
+ class FileTransfer;
+ class FTBrowseDlg;
+
+ class FTDialog
+ {
+ public:
+ FTDialog(HINSTANCE hInst, FileTransfer *pFT);
+ ~FTDialog();
+
+ bool createFTDialog(HWND hwndParent);
+ bool closeFTDialog();
+ void destroyFTDialog();
+
+ void processDlgMsgs();
+
+ void cancelTransfer(bool bResult);
+ void afterCancelTransfer();
+
+ static BOOL CALLBACK FTDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ void addRemoteLVItems(FileInfo *pFI);
+ void reqFolderUnavailable();
+
+ void onEndBrowseDlg(bool bResult);
+ void getBrowseItems(char *pPath);
+ void addBrowseItems(FileInfo *pFI);
+
+ void setStatusText(LPCSTR format,...);
+
+ HWND getWndHandle() { return m_hwndFTDialog; }
+
+ void postCheckDeleteQueueMsg();
+ void postCheckTransferQueueMsg();
+ void postUploadFilePortionMsg();
+ void postDownloadFilePortionMsg();
+
+ char *getLocalPath() { return m_szLocalPath; }
+ char *getRemotePath() { return m_szRemotePath; }
+
+ FTProgress *m_pProgress;
+ FileTransfer *m_pFileTransfer;
+
+ private:
+ HWND m_hwndFTDialog;
+ HWND m_hwndLocalPath;
+ HWND m_hwndRemotePath;
+ HINSTANCE m_hInstance;
+
+ void showLocalLVItems();
+ void showRemoteLVItems();
+
+ void onClose();
+
+ void onLocalItemActivate(LPNMITEMACTIVATE lpnmia);
+ void onRemoteItemActivate(LPNMITEMACTIVATE lpnmia);
+
+ void onLocalBrowse();
+ void onRemoteBrowse();
+
+ void onLocalReload();
+ void onRemoteReload();
+
+ void onLocalRButton();
+ void onRemoteRButton();
+
+ bool getCreateFolderName();
+ void onLocalCreateFolder();
+ void onRemoteCreateFolder();
+
+ void showFTMenu(bool copyBtnState, bool createFldBtnState,
+ bool renameBtnState, bool deleteBtnState,
+ bool cancelBtnState);
+ void onFTMenuCommand(int command);
+
+ void onUpload();
+ void onDownload();
+
+ void onLocalRename();
+ void onRemoteRename();
+
+ void onLocalDelete();
+ void onRemoteDelete();
+
+ void onFTCancel();
+
+ void setIcon(int dest, int idIcon);
+ bool initFTDialog();
+ bool initFTWndMsgs();
+
+ void onLocalOneUpFolder();
+ void onRemoteOneUpFolder();
+ int makeOneUpFolder(char *pPath);
+
+ void refreshBtnState();
+ void setButtonsState();
+
+ bool m_bDlgShown;
+ bool m_bLocalBrowsing;
+ bool m_bCloseDlgAfterCancel;
+
+ UINT m_msgCheckDeleteQueue;
+ UINT m_msgCheckTransferQueue;
+ UINT m_msgUploadFilePortion;
+ UINT m_msgDownloadFilePortion;
+
+ DWORD m_dwNumStatusStrings;
+
+ FTListView *m_pLocalLV;
+ FTListView *m_pRemoteLV;
+
+ FTBrowseDlg *m_pBrowseDlg;
+
+ int m_FTMenuSource;
+
+ char m_szLocalPath[FT_FILENAME_SIZE];
+ char m_szRemotePath[FT_FILENAME_SIZE];
+ char m_szLocalPathTmp[FT_FILENAME_SIZE];
+ char m_szRemotePathTmp[FT_FILENAME_SIZE];
+ char m_szCreateFolderName[FT_FILENAME_SIZE];
+
+ static const char szCheckDeleteQueueText[];
+ static const char szCheckTransferQueueText[];
+ static const char szUploadFilePortionText[];
+
+ typedef struct tagFTBUTTONSSTATE
+ {
+ bool uploadBtn;
+ bool downloadBtn;
+ bool createLocalFldBtn;
+ bool createRemoteFldBtn;
+ bool renameLocalBtn;
+ bool renameRemoteBtn;
+ bool deleteLocalBtn;
+ bool deleteRemoteBtn;
+ bool cancelBtn;
+ } FTBUTTONSSTATE;
+
+ FTBUTTONSSTATE m_BtnState;
+
+ public:
+ class CancelingDlg
+ {
+ public:
+ CancelingDlg(FTDialog *pFTDlg);
+ ~CancelingDlg();
+
+ static BOOL CALLBACK cancelingDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ bool create();
+ bool destroy();
+
+ private:
+ FTDialog *m_pFTDlg;
+ HWND m_hwndDlg;
+
+ bool close(bool bResult);
+ };
+
+ private:
+ CancelingDlg *m_pCancelingDlg;
+
+ public:
+ class CreateFolderDlg : public Dialog
+ {
+ public:
+ CreateFolderDlg(FTDialog *pFTDlg);
+ ~CreateFolderDlg();
+
+ bool onOk();
+ bool create();
+ char *getFolderName() { return m_szFolderName; }
+
+ protected:
+ FTDialog *m_pFTDlg;
+ char m_szFolderName[FT_FILENAME_SIZE];
+ };
+
+ private:
+ CreateFolderDlg *m_pCreateFolderDlg;
+
+ public:
+ class RenameDlg : public CreateFolderDlg
+ {
+ public:
+ RenameDlg(FTDialog *pFTDlg);
+ ~RenameDlg();
+
+ bool create(char *pFilename, bool bFolder);
+ void initDialog();
+
+ private:
+ bool m_bFolder;
+ char m_szFilename[FT_FILENAME_SIZE];
+ };
+
+ private:
+ RenameDlg *m_pRenameDlg;
+ };
+ }
+}
+
+#endif // __RFB_WIN32_FTDIALOG_H__
diff --git a/win/vncviewer/FTListView.cxx b/win/vncviewer/FTListView.cxx
new file mode 100644
index 0000000..8f41abf
--- /dev/null
+++ b/win/vncviewer/FTListView.cxx
@@ -0,0 +1,211 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTListView.cxx
+
+#include <vncviewer/FTListView.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FTListView::FTListView(HWND hListView)
+{
+ m_bInitialized = false;
+ m_hListView = hListView;
+ m_fileInfo.free();
+}
+
+FTListView::~FTListView()
+{
+ m_fileInfo.free();
+}
+
+
+bool
+FTListView::initialize(HINSTANCE hInst)
+{
+ if (m_bInitialized) return false;
+
+ initImageList(hInst);
+
+ RECT Rect;
+ GetClientRect(m_hListView, &Rect);
+ Rect.right -= GetSystemMetrics(SM_CXHSCROLL);
+ int xwidth0 = (int) (0.35 * Rect.right);
+ int xwidth1 = (int) (0.22 * Rect.right);
+ int xwidth2 = (int) (0.43 * Rect.right);
+
+ addColumn("Name", 0, xwidth0, LVCFMT_LEFT);
+ addColumn("Size", 1, xwidth1, LVCFMT_RIGHT);
+ addColumn("Data", 2, xwidth2, LVCFMT_LEFT);
+
+ ListView_SetExtendedListViewStyleEx(m_hListView, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
+
+ return true;
+}
+
+void
+FTListView::onGetDispInfo(NMLVDISPINFO *pDI)
+{
+ if (m_fileInfo.getFlagsAt(pDI->item.iItem) & FT_ATTR_DIR) {
+ pDI->item.iImage = 0;
+ } else {
+ pDI->item.iImage = 1;
+ }
+
+ switch (pDI->item.iSubItem)
+ {
+ case 0:
+ pDI->item.pszText = m_fileInfo.getNameAt(pDI->item.iItem);
+ break;
+ case 1:
+ {
+ unsigned int flags = m_fileInfo.getFlagsAt(pDI->item.iItem);
+ switch(flags & 0x000000FF)
+ {
+ case FT_ATTR_FILE:
+ {
+ char buf[32];
+ unsigned int size = m_fileInfo.getSizeAt(pDI->item.iItem);
+ sprintf(buf, "%u", size);
+ pDI->item.pszText = buf;
+ }
+ break;
+ case FT_ATTR_DIR:
+ pDI->item.pszText = "";
+ break;
+ default:
+ pDI->item.pszText = "Unspecified";
+ }
+ }
+ break;
+ case 2:
+ {
+ unsigned int data = m_fileInfo.getDataAt(pDI->item.iItem);
+ if (data == 0) {
+ pDI->item.pszText = "Unspecified";
+ } else {
+ FILETIME ft;
+ FolderManager fm;
+ fm.getFiletime(data, &ft);
+
+ SYSTEMTIME st;
+ FileTimeToSystemTime(&ft, &st);
+
+ char pDateTimeStr[1024];
+ char timeFmt[128];
+ GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, timeFmt, 128);
+ char dateFmt[128];
+ GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, dateFmt, 128);
+
+ char timeStr[128];
+ GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, timeFmt, timeStr, 128);
+ char dateStr[128];
+ GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, dateFmt, dateStr, 128);
+
+ sprintf(pDateTimeStr, "%s %s", dateStr, timeStr);
+ pDI->item.pszText = pDateTimeStr;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void
+FTListView::addItems(FileInfo *pFI)
+{
+ m_fileInfo.add(pFI);
+ LVITEM LVItem;
+ LVItem.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
+ LVItem.state = 0;
+ LVItem.stateMask = 0;
+ for (unsigned int i = 0; i < m_fileInfo.getNumEntries(); i++) {
+ LVItem.iItem = i;
+ LVItem.iSubItem = 0;
+ LVItem.iImage = I_IMAGECALLBACK;
+ LVItem.pszText = LPSTR_TEXTCALLBACK;
+ ListView_InsertItem(m_hListView, &LVItem);
+ }
+}
+
+void
+FTListView::deleteAllItems()
+{
+ ListView_DeleteAllItems(m_hListView);
+ m_fileInfo.free();
+}
+
+char *
+FTListView::getActivateItemName(LPNMITEMACTIVATE lpnmia)
+{
+ return m_fileInfo.getNameAt(lpnmia->iItem);
+}
+
+int
+FTListView::getSelectedItems(FileInfo *pFI)
+{
+ int selCount = ListView_GetSelectedCount(m_hListView);
+ int selItem = ListView_GetSelectionMark(m_hListView);
+ if ((selCount < 1) || (selItem < 0)) return -1;
+
+ selItem = -1;
+ selItem = ListView_GetNextItem(m_hListView, selItem, LVNI_SELECTED);
+ do {
+ pFI->add(m_fileInfo.getFullDataAt(selItem));
+ selItem = ListView_GetNextItem(m_hListView, selItem, LVNI_SELECTED);
+ } while (selItem >= 0);
+
+ return selCount;
+}
+
+void
+FTListView::initImageList(HINSTANCE hInst)
+{
+ m_hImageList = ImageList_Create(16, 16, ILC_MASK, 2, 2);
+
+ HICON hiconItem = LoadIcon(hInst, MAKEINTRESOURCE(IDI_FTDIR));
+ ImageList_AddIcon(m_hImageList, hiconItem);
+ DestroyIcon(hiconItem);
+
+ hiconItem = LoadIcon(hInst, MAKEINTRESOURCE(IDI_FTFILE));
+ ImageList_AddIcon(m_hImageList, hiconItem);
+ DestroyIcon(hiconItem);
+
+ ListView_SetImageList(m_hListView, m_hImageList, LVSIL_SMALL);
+}
+
+void
+FTListView::addColumn(char *iText, int iOrder, int xWidth, int alignFmt)
+{
+ LVCOLUMN lvc;
+ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER;
+ lvc.fmt = alignFmt;
+ lvc.iSubItem = iOrder;
+ lvc.pszText = iText;
+ lvc.cchTextMax = 32;
+ lvc.cx = xWidth;
+ lvc.iOrder = iOrder;
+ ListView_InsertColumn(m_hListView, iOrder, &lvc);
+}
diff --git a/win/vncviewer/FTListView.h b/win/vncviewer/FTListView.h
new file mode 100644
index 0000000..c920fa0
--- /dev/null
+++ b/win/vncviewer/FTListView.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTListView.h
+
+#ifndef __RFB_WIN32_FTLISTVIEW_H__
+#define __RFB_WIN32_FTLISTVIEW_H__
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <rfb/FileInfo.h>
+#include <rfb_win32/FolderManager.h>
+#include <vncviewer/resource.h>
+
+namespace rfb {
+ namespace win32{
+ class FTListView
+ {
+ public:
+ FTListView(HWND hListView);
+ ~FTListView();
+
+ bool initialize(HINSTANCE hInst);
+
+ void onGetDispInfo(NMLVDISPINFO *di);
+ void addItems(FileInfo *pFI);
+ void deleteAllItems();
+
+ char *getActivateItemName(LPNMITEMACTIVATE lpnmia);
+ int getSelectedItems(FileInfo *pFI);
+
+ HWND getWndHandle() { return m_hListView; };
+
+ private:
+ HWND m_hListView;
+ FileInfo m_fileInfo;
+ HIMAGELIST m_hImageList;
+
+ bool m_bInitialized;
+
+ void addColumn(char *iText, int iOrder, int xWidth, int alignFmt);
+ void initImageList(HINSTANCE hInst);
+
+ };
+ }
+}
+
+#endif // __RFB_WIN32_FTLISTVIEW_H__
diff --git a/win/vncviewer/FTProgress.cxx b/win/vncviewer/FTProgress.cxx
new file mode 100644
index 0000000..e6cc952
--- /dev/null
+++ b/win/vncviewer/FTProgress.cxx
@@ -0,0 +1,151 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTProgress.cxx
+
+#include <vncviewer/FTProgress.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FTProgress::FTProgress(HWND hwndParent)
+{
+ m_bInitialized = false;
+ m_hwndParent = hwndParent;
+
+ m_pSingleProgress = NULL;
+ m_pGeneralProgress = NULL;
+
+ m_hwndSinglePercent = GetDlgItem(m_hwndParent, IDC_FTSINGLEPERCENT);
+ m_hwndGeneralPercent = GetDlgItem(m_hwndParent, IDC_FTGENERALPERCENT);
+
+ m_bInitialized = createProgressBarObjects();
+}
+
+FTProgress::~FTProgress()
+{
+ destroyProgressBarObjects();
+}
+
+void
+FTProgress::increase(DWORD value)
+{
+ if (!m_bInitialized) return;
+
+ m_pSingleProgress->increase(value);
+ m_pGeneralProgress->increase(value);
+
+ setProgressText();
+}
+
+void
+FTProgress::clearAndInitGeneral(DWORD64 dw64MaxValue, DWORD64 dw64Position)
+{
+ if (!m_bInitialized) return;
+
+ m_pGeneralProgress->clear();
+ m_pGeneralProgress->init(dw64MaxValue, dw64Position);
+
+ setProgressText();
+}
+
+void
+FTProgress::clearAndInitSingle(DWORD dwMaxValue, DWORD dwPosition)
+{
+ if (!m_bInitialized) return;
+
+ m_pSingleProgress->clear();
+ m_pSingleProgress->init(dwMaxValue, dwPosition);
+
+ setProgressText();
+}
+
+void
+FTProgress::clearAll()
+{
+ if (!m_bInitialized) return;
+
+ m_pSingleProgress->clear();
+ m_pGeneralProgress->clear();
+
+ setProgressText();
+}
+
+bool
+FTProgress::createProgressBarObjects()
+{
+ if ((m_pSingleProgress != NULL) || (m_pGeneralProgress != NULL)) {
+ return false;
+ } else {
+ HWND hwndSingleProgr = GetDlgItem(m_hwndParent, IDC_FTSINGLEPROGRESS);
+ HWND hwndGeneralProgr = GetDlgItem(m_hwndParent, IDC_FTGENERALPROGRESS);
+
+ m_pSingleProgress = new ProgressControl(hwndSingleProgr);
+ if (m_pSingleProgress == NULL) return false;
+
+ m_pGeneralProgress = new ProgressControl(hwndGeneralProgr);
+ if (m_pGeneralProgress == NULL) {
+ delete m_pSingleProgress;
+ m_pSingleProgress = NULL;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+FTProgress::destroyProgressBarObjects()
+{
+ clearAll();
+
+ if (m_pSingleProgress != NULL) {
+ delete m_pSingleProgress;
+ m_pSingleProgress = NULL;
+ }
+
+ if (m_pGeneralProgress != NULL) {
+ delete m_pGeneralProgress;
+ m_pGeneralProgress = NULL;
+ }
+
+ return true;
+}
+
+void
+FTProgress::setProgressText()
+{
+ char buf[16] = {0};
+ char buf2[16] = {0};
+
+ int percent = m_pSingleProgress->getCurrentPercent();
+ sprintf(buf, "%d%%", percent);
+ GetWindowText(m_hwndSinglePercent, buf2, 16);
+ if (strcmp(buf, buf2) != 0)
+ SetWindowText(m_hwndSinglePercent, buf);
+
+ percent = m_pGeneralProgress->getCurrentPercent();
+ sprintf(buf, "%d%%", percent);
+ GetWindowText(m_hwndGeneralPercent, buf2, 16);
+ if (strcmp(buf, buf2) != 0)
+ SetWindowText(m_hwndGeneralPercent, buf);
+}
\ No newline at end of file
diff --git a/win/vncviewer/FTProgress.h b/win/vncviewer/FTProgress.h
new file mode 100644
index 0000000..caad779
--- /dev/null
+++ b/win/vncviewer/FTProgress.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FTProgress.h
+
+#ifndef __RFB_WIN32_FTPROGRESS_H__
+#define __RFB_WIN32_FTPROGRESS_H__
+
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+
+#include <rfb_win32/ProgressControl.h>
+#include <vncviewer/resource.h>
+
+namespace rfb {
+ namespace win32 {
+ class FTProgress
+ {
+ public:
+ FTProgress(HWND hwndParent);
+ ~FTProgress();
+
+ void increase(DWORD value);
+ void clearAndInitGeneral(DWORD64 dw64MaxValue, DWORD64 dw64Position);
+ void clearAndInitSingle(DWORD dwMaxValue, DWORD dwPosition);
+ void clearAll();
+
+ private:
+ ProgressControl *m_pSingleProgress;
+ ProgressControl *m_pGeneralProgress;
+
+ HWND m_hwndParent;
+ HWND m_hwndSinglePercent;
+ HWND m_hwndGeneralPercent;
+
+ bool m_bInitialized;
+
+ void setProgressText();
+ bool createProgressBarObjects();
+ bool destroyProgressBarObjects();
+ };
+ }
+}
+
+#endif // __RFB_WIN32_FTPROGRESS_H__
diff --git a/win/vncviewer/FileTransfer.cxx b/win/vncviewer/FileTransfer.cxx
new file mode 100644
index 0000000..cf57072
--- /dev/null
+++ b/win/vncviewer/FileTransfer.cxx
@@ -0,0 +1,803 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky.
+ *
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileTransfer.cxx
+
+#include <vncviewer/FileTransfer.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+FileTransfer::FileTransfer()
+{
+ m_bFTDlgShown = false;
+ m_bInitialized = false;
+ m_bResized = false;
+ m_bCancel = false;
+ m_bOverwriteAll = false;
+
+ m_pFTDialog = new FTDialog(GetModuleHandle(0), this);
+
+ m_pReader = NULL;
+ m_pWriter = NULL;
+
+ m_dw64SizeSending = 0;
+ m_dirSizeRqstNum = 0;
+}
+
+FileTransfer::~FileTransfer()
+{
+ if (m_pFTDialog != NULL) {
+ delete m_pFTDialog;
+ m_pFTDialog = NULL;
+ }
+
+ if (m_pReader != NULL) {
+ delete m_pReader;
+ m_pReader = NULL;
+ }
+
+ if (m_pWriter != NULL) {
+ delete m_pWriter;
+ m_pWriter = NULL;
+ }
+
+ freeQueues();
+}
+
+bool
+FileTransfer::initialize(rdr::InStream *pIS, rdr::OutStream *pOS)
+{
+ if (m_bInitialized) return false;
+
+ m_pReader = new CFTMsgReader(pIS);
+ m_pWriter = new CFTMsgWriter(pOS);
+
+ freeQueues();
+
+ m_bInitialized = true;
+ return true;
+}
+
+bool
+FileTransfer::show(HWND hwndParent)
+{
+ if (!m_bInitialized) return false;
+
+ m_bFTDlgShown = m_pFTDialog->createFTDialog(hwndParent);
+
+ return m_bFTDlgShown;
+}
+
+bool
+FileTransfer::processFTMsg(int type)
+{
+ if (!m_bInitialized) return false;
+
+ switch (type)
+ {
+ case msgTypeFileListData:
+ return procFileListDataMsg();
+ case msgTypeFileDownloadData:
+ return procFileDownloadDataMsg();
+ case msgTypeFileUploadCancel:
+ return procFileUploadCancelMsg();
+ case msgTypeFileDownloadFailed:
+ return procFileDownloadFailedMsg();
+ case msgTypeFileDirSizeData:
+ return procFileDirSizeDataMsg();
+ case msgTypeFileLastRequestFailed:
+ return procFileLastRqstFailedMsg();
+ default:
+ return false;
+ }
+}
+
+bool
+FileTransfer::isTransferEnable()
+{
+ if (m_TransferQueue.getNumEntries() > 0) return true; else return false;
+}
+
+void
+FileTransfer::addDeleteQueue(char *pPathPrefix, FileInfo *pFI, unsigned int flags)
+{
+ if ((m_bFTDlgShown) && (m_DeleteQueue.getNumEntries() > 0))
+ m_pFTDialog->setStatusText("Starting Delete Operation");
+
+ m_DeleteQueue.add(pPathPrefix, pPathPrefix, pFI, flags);
+
+ checkDeleteQueue();
+}
+
+void
+FileTransfer::checkDeleteQueue()
+{
+ if (m_DeleteQueue.getNumEntries() > 0) {
+ if (m_bFTDlgShown)
+ m_pFTDialog->setStatusText("Delete Operation Executing: %s", m_DeleteQueue.getFullLocPathAt(0));
+ if (m_DeleteQueue.getFlagsAt(0) & FT_ATTR_DELETE_LOCAL) {
+ FolderManager fm;
+ if (!fm.deleteIt(m_DeleteQueue.getFullLocPathAt(0))) {
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Delete Operation Failed");
+ } else {
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Delete Operation Completed");
+ }
+ m_DeleteQueue.deleteAt(0);
+ m_pFTDialog->postCheckDeleteQueueMsg();
+ } else {
+ if (m_DeleteQueue.getFlagsAt(0) & FT_ATTR_DELETE_REMOTE) {
+ writeFileDeleteRqst(strlen(m_DeleteQueue.getFullLocPathAt(0)),
+ m_DeleteQueue.getFullLocPathAt(0));
+
+ char *pPath = m_DeleteQueue.getLocPathAt(0);
+ m_queueFileListRqst.add(pPath, 0, 0, FT_FLR_DEST_DELETE);
+ writeFileListRqst(strlen(pPath), pPath, false);
+ }
+ }
+ } else {
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Delete Operation Completed Successfully");
+ PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTLOCALRELOAD, 0), 0);
+ PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTREMOTERELOAD, 0), 0);
+ }
+ }
+}
+
+void
+FileTransfer::addTransferQueue(char *pLocalPath, char *pRemotePath,
+ FileInfo *pFI, unsigned int flags)
+{
+ if (!isTransferEnable()) {
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Starting Copy Operation");
+ m_bTransferSuccess = true;
+ }
+
+ m_TransferQueue.add(pLocalPath, pRemotePath, pFI, (flags | FT_ATTR_RESIZE_NEEDED));
+
+ checkTransferQueue();
+}
+
+bool
+FileTransfer::resizeSending()
+{
+ for (unsigned int i = 0; i < m_TransferQueue.getNumEntries(); i++) {
+ unsigned int flags = m_TransferQueue.getFlagsAt(i);
+ if (flags & FT_ATTR_RESIZE_NEEDED) {
+ if (flags & FT_ATTR_FILE) {
+ m_bResized = true;
+ m_dw64SizeSending += m_TransferQueue.getSizeAt(i);
+ m_TransferQueue.clearFlagAt(i, FT_ATTR_RESIZE_NEEDED);
+ } else {
+ if (flags & FT_ATTR_DIR) {
+ if (flags & FT_ATTR_COPY_DOWNLOAD) {
+ m_bResized = true;
+ char *pPath = m_TransferQueue.getFullRemPathAt(i);
+ m_dirSizeRqstNum = i;
+ writeFileDirSizeRqst(strlen(pPath), pPath);
+ return false;
+ } else {
+ if (flags & FT_ATTR_COPY_UPLOAD) {
+ FolderManager fm;
+ DWORD64 dw64Size;
+ m_bResized = true;
+ fm.getDirSize(m_TransferQueue.getFullLocPathAt(i), &dw64Size);
+ m_dw64SizeSending += dw64Size;
+ m_TransferQueue.clearFlagAt(i, FT_ATTR_RESIZE_NEEDED);
+ }
+ } // if (flags & FT_ATTR_COPY_DOWNLOAD)
+ } // if (flags & FT_ATTR_FOLDER)
+ } // if (flags & FT_ATTR_FILE)
+ } // if (flags & FT_ATTR_NEEDED_RESIZE)
+ } // for (unsigned int i = 0; i < m_TransferQueue.getNumEntries(); i++)
+
+ if ((m_bFTDlgShown) && (m_bResized)) {
+ m_pFTDialog->m_pProgress->clearAndInitGeneral(m_dw64SizeSending, 0);
+ m_bResized = false;
+ }
+
+ return true;
+}
+
+void
+FileTransfer::checkTransferQueue()
+{
+ if (!isTransferEnable()) {
+ if (m_bFTDlgShown) {
+ m_pFTDialog->m_pProgress->clearAll();
+ m_dw64SizeSending = 0;
+ m_bResized = false;
+
+ if (m_bTransferSuccess)
+ m_pFTDialog->setStatusText("File Transfer Operation Completed Successfully");
+ else
+ m_pFTDialog->setStatusText("File Transfer Operation Completed");
+
+ m_pFTDialog->afterCancelTransfer();
+ PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTLOCALRELOAD, 0), 0);
+ PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTREMOTERELOAD, 0), 0);
+ return;
+ }
+ } else {
+ if (!resizeSending()) return;
+
+ unsigned int flag0 = m_TransferQueue.getFlagsAt(0);
+
+ if (flag0 & FT_ATTR_COPY_UPLOAD) {
+ if (flag0 & FT_ATTR_FILE) {
+ uploadFile();
+ return;
+ }
+ if (flag0 & FT_ATTR_DIR) {
+ char *pFullPath = m_TransferQueue.getFullRemPathAt(0);
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Creating Remote Folder. %s", pFullPath);
+ writeFileCreateDirRqst(strlen(pFullPath), pFullPath);
+
+ char *pPath = m_TransferQueue.getRemPathAt(0);
+ m_TransferQueue.setFlagsAt(0, (flag0 | FT_ATTR_FLR_UPLOAD_CHECK));
+ m_queueFileListRqst.add(pPath, 0, 0, FT_FLR_DEST_UPLOAD);
+ writeFileListRqst(strlen(pPath), pPath, false);
+ return;
+ }
+ } else {
+ if (flag0 & FT_ATTR_COPY_DOWNLOAD) {
+ if (flag0 & FT_ATTR_FILE) {
+ downloadFile();
+ return;
+ }
+ if (flag0 & FT_ATTR_DIR) {
+ FolderManager fm;
+ char *pLocPath = m_TransferQueue.getFullLocPathAt(0);
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Creating Local Folder. %s", pLocPath);
+
+ if (!fm.createDir(pLocPath)) {
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Creating Local Folder Failed.");
+ m_bTransferSuccess = false;
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ return;
+ } else {
+ if ((m_bFTDlgShown) && (strcmp(m_TransferQueue.getLocPathAt(0), m_pFTDialog->getLocalPath()) == 0))
+ PostMessage(m_pFTDialog->getWndHandle(), WM_COMMAND, MAKEWPARAM(IDC_FTLOCALRELOAD, 0), 0);
+
+ m_TransferQueue.setFlagsAt(0, (m_TransferQueue.getFlagsAt(0) | FT_ATTR_FLR_DOWNLOAD_ADD));
+ char *pRemPath = m_TransferQueue.getFullRemPathAt(0);
+ m_queueFileListRqst.add(pRemPath, 0, 0, FT_FLR_DEST_DOWNLOAD);
+ writeFileListRqst(strlen(pRemPath), pRemPath, 0);
+ return;
+ }
+ }
+ }
+ }
+ m_bTransferSuccess = false;
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("File Transfer Operation Failed. Unknown data in the transfer queue");
+ } // if (!isTransferEnable())
+}
+
+bool
+FileTransfer::uploadFile()
+{
+ if (m_TransferQueue.getFlagsAt(0) & FT_ATTR_FILE) {
+ if (m_fileReader.create(m_TransferQueue.getFullLocPathAt(0))) {
+
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Upload Started: %s to %s",
+ m_TransferQueue.getFullLocPathAt(0),
+ m_TransferQueue.getFullRemPathAt(0));
+ m_pFTDialog->m_pProgress->clearAndInitSingle(m_TransferQueue.getSizeAt(0), 0);
+ }
+
+ writeFileUploadRqst(strlen(m_TransferQueue.getFullRemPathAt(0)),
+ m_TransferQueue.getFullRemPathAt(0), 0);
+ uploadFilePortion();
+ }
+ }
+ return false;
+}
+
+bool
+FileTransfer::downloadFile()
+{
+ if (m_TransferQueue.getFlagsAt(0) & FT_ATTR_FILE) {
+ if (m_fileWriter.create(m_TransferQueue.getFullLocPathAt(0))) {
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Download Started: %s to %s",
+ m_TransferQueue.getFullRemPathAt(0),
+ m_TransferQueue.getFullLocPathAt(0));
+ m_pFTDialog->m_pProgress->clearAndInitSingle(m_TransferQueue.getSizeAt(0), 0);
+ }
+ writeFileDownloadRqst(strlen(m_TransferQueue.getFullRemPathAt(0)),
+ m_TransferQueue.getFullRemPathAt(0), 0);
+ return true;
+ } else return false;
+ }
+ return false;
+}
+
+void
+FileTransfer::uploadFilePortion()
+{
+ if (checkCancelOperations()) {
+ char reason[] = "The user cancel transfer";
+ m_pWriter->writeFileUploadFailed(strlen(reason), reason);
+ }
+
+ if (m_fileReader.isCreated()) {
+ char buf[FT_MAX_SENDING_SIZE];
+ unsigned int bytesRead = 0;
+ if (m_fileReader.read((void *)buf, FT_MAX_SENDING_SIZE, &bytesRead)) {
+ if (bytesRead == 0) {
+ m_pWriter->writeFileUploadData(m_TransferQueue.getDataAt(0));
+ m_fileReader.close();
+ if (m_bFTDlgShown) {
+ m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+ m_pFTDialog->setStatusText("Upload Completed");
+ }
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ } else {
+ if (m_bFTDlgShown) m_pFTDialog->m_pProgress->increase(bytesRead);
+ m_pWriter->writeFileUploadData(bytesRead, (char *)buf);
+ m_pFTDialog->postUploadFilePortionMsg();
+ }
+ } else {
+ m_fileReader.close();
+ m_bTransferSuccess = false;
+ char reason[] = "Error While Reading File";
+ m_pWriter->writeFileUploadFailed(strlen(reason), reason);
+ if (m_bFTDlgShown) {
+ m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+ m_pFTDialog->setStatusText("Upload Failed");
+ }
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ }
+ }
+}
+
+void
+FileTransfer::createRemoteFolder(char *pPath, char *pName)
+{
+ char fullPath[FT_FILENAME_SIZE];
+ sprintf(fullPath, "%s\\%s", pPath, pName);
+ m_pFTDialog->setStatusText("Creating Remote Folder: %s", fullPath);
+ writeFileCreateDirRqst(strlen(fullPath), fullPath);
+ requestFileList(pPath, FT_FLR_DEST_MAIN, false);
+}
+
+void
+FileTransfer::renameRemote(char *pPath, char *pOldName, char *pNewName)
+{
+ char fullOldName[FT_FILENAME_SIZE];
+ char fullNewName[FT_FILENAME_SIZE];
+
+ sprintf(fullOldName, "%s\\%s", pPath, pOldName);
+ sprintf(fullNewName, "%s\\%s", pPath, pNewName);
+
+ writeFileRenameRqst(strlen(fullOldName), strlen(fullNewName),
+ fullOldName, fullNewName);
+ requestFileList(pPath, FT_FLR_DEST_MAIN, false);
+}
+
+bool
+FileTransfer::procFileListDataMsg()
+{
+ FileInfo fileInfo;
+ int res = m_pReader->readFileListData(&fileInfo);
+
+ bool bResult;
+ switch (m_queueFileListRqst.getFlagsAt(0))
+ {
+ case FT_FLR_DEST_MAIN:
+ if (!m_bFTDlgShown) break;
+
+ if (res < 0) {
+ m_pFTDialog->reqFolderUnavailable();
+ bResult = true;
+ } else {
+ bResult = procFLRMain(&fileInfo);
+ }
+ break;
+ case FT_FLR_DEST_BROWSE:
+ bResult = procFLRBrowse(&fileInfo);
+ break;
+ case FT_FLR_DEST_UPLOAD:
+ bResult = procFLRUpload(&fileInfo);
+ break;
+ case FT_FLR_DEST_DOWNLOAD:
+ bResult = procFLRDownload(&fileInfo);
+ break;
+ case FT_FLR_DEST_DELETE:
+ bResult = procFLRDelete(&fileInfo);
+ break;
+ case FT_FLR_DEST_RENAME:
+ bResult = procFLRRename(&fileInfo);
+ break;
+ }
+ m_queueFileListRqst.deleteAt(0);
+ return bResult;
+}
+
+bool
+FileTransfer::procFileDownloadDataMsg()
+{
+ unsigned int bufSize = 0;
+ unsigned int modTime = 0;
+
+ void *pFile = m_pReader->readFileDownloadData(&bufSize, &modTime);
+
+ if (checkCancelOperations()) {
+ char reason[] = "The user cancel transfer";
+ m_pWriter->writeFileDownloadCancel(strlen(reason), reason);
+ }
+
+ if ((!m_fileWriter.isCreated()) || (!isTransferEnable())) {
+ m_bTransferSuccess = false;
+ if (pFile != NULL) delete [] pFile;
+ return false;
+ }
+
+ if (bufSize > 0) {
+ unsigned int bytesWritten = 0;
+ m_fileWriter.write(pFile, bufSize, &bytesWritten);
+ delete [] pFile;
+ if (bytesWritten != bufSize) {
+ m_bTransferSuccess = false;
+ char reason[] = "Error File Writting to File";
+ m_pWriter->writeFileDownloadCancel(strlen(reason), reason);
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Download Failed");
+ m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+ }
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ return false;
+ } else {
+ if (m_bFTDlgShown) {
+ m_pFTDialog->m_pProgress->increase(bufSize);
+ }
+ }
+ return true;
+ } else {
+ if (modTime != 0) {
+ m_fileWriter.setTime(modTime);
+ m_fileWriter.close();
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Download Completed");
+ m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+ }
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ return true;
+ } else {
+ m_fileWriter.close();
+ m_bTransferSuccess = false;
+ char reason[] = "Error File Writting";
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Download Failed");
+ m_pFTDialog->m_pProgress->clearAndInitSingle(0, 0);
+ }
+ m_pWriter->writeFileDownloadCancel(strlen(reason), reason);
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ }
+ }
+ return false;
+}
+
+bool
+FileTransfer::procFileUploadCancelMsg()
+{
+ unsigned int reasonSize = 0;
+ char *pReason = m_pReader->readFileUploadCancel(&reasonSize);
+
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Upload Canceled by Remote Computer : %s", pReason);
+ }
+ endUndoneOperation();
+ m_pFTDialog->postCheckTransferQueueMsg();
+
+ delete [] pReason;
+ return true;
+}
+
+bool
+FileTransfer::procFileDownloadFailedMsg()
+{
+ unsigned int reasonSize = 0;
+ char *pReason = m_pReader->readFileDownloadFailed(&reasonSize);
+
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("Download Failed by Remote Computer : %s", pReason);
+ }
+ endUndoneOperation();
+ m_pFTDialog->postCheckTransferQueueMsg();
+
+ delete [] pReason;
+ return true;
+}
+
+bool
+FileTransfer::procFileDirSizeDataMsg()
+{
+ DWORD64 dw64DirSize = 0;
+ unsigned short dirSizeLow16 = 0;
+ unsigned int dirSizeHigh32 = 0;
+ m_pReader->readFileDirSizeData(&dirSizeLow16, &dirSizeHigh32);
+
+ dw64DirSize = dirSizeLow16;
+ dw64DirSize = (dw64DirSize << 32) + dirSizeHigh32;
+
+ m_dw64SizeSending += dw64DirSize;
+ m_TransferQueue.clearFlagAt(m_dirSizeRqstNum, FT_ATTR_RESIZE_NEEDED);
+ checkTransferQueue();
+ return true;
+}
+
+bool
+FileTransfer::procFileLastRqstFailedMsg()
+{
+ unsigned int reasonSize = 0;
+ int requestType;
+ char *pReason = m_pReader->readFileLastRqstFailed(&requestType, &reasonSize);
+ delete [] pReason;
+ return true;
+}
+
+bool
+FileTransfer::procFLRMain(FileInfo *pFI)
+{
+ if (m_bFTDlgShown) m_pFTDialog->addRemoteLVItems(pFI);
+ return true;
+}
+
+bool
+FileTransfer::procFLRBrowse(FileInfo *pFI)
+{
+ m_pFTDialog->addBrowseItems(pFI);
+ return false;
+}
+
+bool
+FileTransfer::procFLRUpload(FileInfo *pFI)
+{
+ unsigned int flags = m_TransferQueue.getFlagsAt(0);
+ if (flags & FT_ATTR_FLR_UPLOAD_CHECK) {
+ int num = isExistName(pFI, m_TransferQueue.getRemNameAt(0));
+ if (num >= 0) {
+ if ((m_bFTDlgShown) && (strcmp(m_TransferQueue.getRemPathAt(0), m_pFTDialog->getRemotePath()) == 0)) {
+ m_pFTDialog->addRemoteLVItems(pFI);
+ }
+ } else {
+ if (flags & FT_ATTR_DIR) {
+ m_TransferQueue.deleteAt(0);
+ m_bTransferSuccess = false;
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Create Remote Folder Failed.");
+ }
+ }
+ }
+ FolderManager fm;
+ FileInfo fi;
+ flags = m_TransferQueue.getFlagsAt(0);
+ if (flags & FT_ATTR_FILE) {
+ uploadFile();
+ return true;
+ } else {
+ if (fm.getDirInfo(m_TransferQueue.getFullLocPathAt(0), &fi, 0)) {
+ m_TransferQueue.add(m_TransferQueue.getFullLocPathAt(0),
+ m_TransferQueue.getFullRemPathAt(0),
+ &fi, FT_ATTR_COPY_UPLOAD);
+ }
+ }
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ return true;
+}
+
+bool
+FileTransfer::procFLRDownload(FileInfo *pFI)
+{
+ unsigned int flags = m_TransferQueue.getFlagsAt(0);
+
+ if ((flags & FT_ATTR_DIR) && (flags & FT_ATTR_FLR_DOWNLOAD_ADD)) {
+ m_TransferQueue.add(m_TransferQueue.getFullLocPathAt(0),
+ m_TransferQueue.getFullRemPathAt(0),
+ pFI, FT_ATTR_COPY_DOWNLOAD);
+ m_TransferQueue.deleteAt(0);
+ m_pFTDialog->postCheckTransferQueueMsg();
+ return true;
+ } else {
+ m_bTransferSuccess = false;
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("File Transfer Operation Failed: Unknown data from server.");
+ }
+ return false;
+}
+
+bool
+FileTransfer::procFLRDelete(FileInfo *pFI)
+{
+ if (isExistName(pFI, m_DeleteQueue.getLocNameAt(0)) >= 0) {
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Delete Operation Failed.");
+ } else {
+ if (m_bFTDlgShown) m_pFTDialog->setStatusText("Delete Operation Completed.");
+ }
+ m_DeleteQueue.deleteAt(0);
+ checkDeleteQueue();
+ return true;
+}
+
+bool
+FileTransfer::procFLRRename(FileInfo *pFI)
+{
+ return false;
+}
+
+void
+FileTransfer::requestFileList(char *pPath, int dest, bool bDirOnly)
+{
+ m_queueFileListRqst.add(pPath, 0, 0, dest);
+
+ writeFileListRqst(strlen(pPath), pPath, bDirOnly);
+}
+
+int
+FileTransfer::isExistName(FileInfo *pFI, char *pName)
+{
+ for (unsigned int i = 0; i < pFI->getNumEntries(); i++) {
+ if (strcmp(pFI->getNameAt(i), pName) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+bool
+FileTransfer::checkCancelOperations()
+{
+ if (m_bFTDlgShown) m_pFTDialog->processDlgMsgs();
+ if (m_bCancel) {
+ endUndoneOperation();
+ if (m_bFTDlgShown) {
+ m_pFTDialog->setStatusText("All Operations Canceled");
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void
+FileTransfer::endUndoneOperation()
+{
+ m_bCancel = false;
+ m_bTransferSuccess = false;
+ m_fileReader.close();
+ m_fileWriter.close();
+ freeQueues();
+ m_dw64SizeSending = 0;
+ m_pFTDialog->m_pProgress->clearAll();
+}
+
+void
+FileTransfer::freeQueues()
+{
+ m_TransferQueue.free();
+ m_DeleteQueue.free();
+ m_queueFileListRqst.free();
+}
+
+int
+FileTransfer::convertToUnixPath(char *path)
+{
+ int len = strlen(path);
+ if (len >= FT_FILENAME_SIZE) return -1;
+ if (len == 0) {strcpy(path, "/"); return 1;}
+ for (int i = (len - 1); i >= 0; i--) {
+ if (path[i] == '\\') path[i] = '/';
+ path[i+1] = path[i];
+ }
+ path[len + 1] = '\0';
+ path[0] = '/';
+ return strlen(path);
+}
+
+bool
+FileTransfer::writeFileListRqst(unsigned short dirnameLen, char *pDirName, bool bDirOnly)
+{
+ char dirName[FT_FILENAME_SIZE];
+ strcpy(dirName, pDirName);
+ int len = convertToUnixPath(dirName);
+ if (len <= 0) return false;
+
+ return m_pWriter->writeFileListRqst(len, dirName, bDirOnly);
+}
+
+bool
+FileTransfer::writeFileDownloadRqst(unsigned short filenameLen, char *pFilename,
+ unsigned int position)
+{
+ char filename[FT_FILENAME_SIZE];
+ strcpy(filename, pFilename);
+ unsigned short len = (unsigned short) convertToUnixPath(filename);
+ if (len <= 0) return false;
+
+ return m_pWriter->writeFileDownloadRqst(len, filename, position);
+}
+
+bool
+FileTransfer::writeFileUploadRqst(unsigned short filenameLen, char *pFilename,
+ unsigned int position)
+{
+ char filename[FT_FILENAME_SIZE];
+ strcpy(filename, pFilename);
+ unsigned short len = (unsigned short) convertToUnixPath(filename);
+ if (len <= 0) return false;
+
+ return m_pWriter->writeFileUploadRqst(len, filename, position);
+}
+
+bool
+FileTransfer::writeFileCreateDirRqst(unsigned short dirNameLen, char *pDirName)
+{
+ char path[FT_FILENAME_SIZE];
+ strcpy(path, pDirName);
+ int nameLen = convertToUnixPath(path);
+
+ return m_pWriter->writeFileCreateDirRqst(nameLen, path);
+}
+
+bool
+FileTransfer::writeFileDirSizeRqst(unsigned short dirNameLen, char *pDirName)
+{
+ char path[FT_FILENAME_SIZE];
+ strcpy(path, pDirName);
+ int nameLen = convertToUnixPath(path);
+
+ return m_pWriter->writeFileDirSizeRqst(nameLen, path);
+}
+
+bool
+FileTransfer::writeFileRenameRqst(unsigned short oldNameLen, unsigned short newNameLen,
+ char *pOldName, char *pNewName)
+{
+ char oldName[FT_FILENAME_SIZE];
+ char newName[FT_FILENAME_SIZE];
+
+ strcpy(oldName, pOldName);
+ strcpy(newName, pNewName);
+
+ int _oldNameLen = convertToUnixPath(oldName);
+ int _newNameLen = convertToUnixPath(newName);
+
+ return m_pWriter->writeFileRenameRqst(_oldNameLen, _newNameLen, oldName, newName);
+}
+
+bool
+FileTransfer::writeFileDeleteRqst(unsigned short nameLen, char *pName)
+{
+ char path[FT_FILENAME_SIZE];
+ strcpy(path, pName);
+ int _nameLen = convertToUnixPath(path);
+
+ return m_pWriter->writeFileDeleteRqst(_nameLen, path);
+}
diff --git a/win/vncviewer/FileTransfer.h b/win/vncviewer/FileTransfer.h
new file mode 100644
index 0000000..1bfded2
--- /dev/null
+++ b/win/vncviewer/FileTransfer.h
@@ -0,0 +1,136 @@
+/* Copyright (C) 2005 TightVNC Team. All Rights Reserved.
+ *
+ * Developed by Dennis Syrovatsky
+ *
+ * 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.
+ *
+ * TightVNC distribution homepage on the Web: http://www.tightvnc.com/
+ *
+ */
+
+// -=- FileTransfer.h
+
+#ifndef __RFB_WIN32_FILETRANSFER_H__
+#define __RFB_WIN32_FILETRANSFER_H__
+
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/FileInfo.h>
+#include <rfb/FileReader.h>
+#include <rfb/FileWriter.h>
+#include <rfb/TransferQueue.h>
+#include <rfb/CFTMsgReader.h>
+#include <rfb/CFTMsgWriter.h>
+#include <vncviewer/FTDialog.h>
+
+namespace rfb {
+ namespace win32 {
+ class FTDialog;
+
+ class FileTransfer
+ {
+ public:
+ FileTransfer();
+ ~FileTransfer();
+
+ bool initialize(rdr::InStream *pIS, rdr::OutStream *pOS);
+ bool processFTMsg(int type);
+ bool show(HWND hwndParent);
+
+ void requestFileList(char *pPath, int dest, bool bDirOnly);
+
+ void addTransferQueue(char *pLocalPath, char *pRemotePath,
+ FileInfo *pFI, unsigned int flags);
+ void addDeleteQueue(char *pPathPrefix, FileInfo *pFI,
+ unsigned int flags);
+
+ bool isTransferEnable();
+
+ void checkTransferQueue();
+ void checkDeleteQueue();
+ bool checkCancelOperations();
+
+ void uploadFilePortion();
+
+ void createRemoteFolder(char *pPath, char *pName);
+ void renameRemote(char *pPath, char *pOldName, char *pNewName);
+
+ bool m_bCancel;
+
+ private:
+ bool m_bFTDlgShown;
+ bool m_bInitialized;
+ bool m_bResized;
+ bool m_bTransferSuccess;
+ bool m_bOverwriteAll;
+
+ FTDialog *m_pFTDialog;
+
+ rfb::CFTMsgReader *m_pReader;
+ rfb::CFTMsgWriter *m_pWriter;
+
+ FileReader m_fileReader;
+ FileWriter m_fileWriter;
+
+ FileInfo m_queueFileListRqst;
+
+ TransferQueue m_TransferQueue;
+ TransferQueue m_DeleteQueue;
+
+ bool resizeSending();
+ bool uploadFile();
+ bool downloadFile();
+
+ int isExistName(FileInfo *pFI, char *pName);
+ void freeQueues();
+
+ void endUndoneOperation();
+
+ bool procFileListDataMsg();
+ bool procFileDownloadDataMsg();
+ bool procFileUploadCancelMsg();
+ bool procFileDownloadFailedMsg();
+ bool procFileDirSizeDataMsg();
+ bool procFileLastRqstFailedMsg();
+
+ bool procFLRMain(FileInfo *pFI);
+ bool procFLRBrowse(FileInfo *pFI);
+ bool procFLRUpload(FileInfo *pFI);
+ bool procFLRDownload(FileInfo *pFI);
+ bool procFLRDelete(FileInfo *pFI);
+ bool procFLRRename(FileInfo *pFI);
+
+ int convertToUnixPath(char *path);
+
+ bool writeFileListRqst(unsigned short dirnameLen, char *pDirName, bool bDirOnly);
+ bool writeFileDownloadRqst(unsigned short filenameLen, char *pFilename,
+ unsigned int position);
+ bool writeFileUploadRqst(unsigned short filenameLen, char *pFilename,
+ unsigned int position);
+ bool writeFileCreateDirRqst(unsigned short dirNameLen, char *pDirName);
+ bool writeFileDirSizeRqst(unsigned short dirNameLen, char *pDirName);
+ bool writeFileRenameRqst(unsigned short oldNameLen, unsigned short newNameLen,
+ char *pOldName, char *pNewName);
+ bool writeFileDeleteRqst(unsigned short nameLen, char *pName);
+
+ DWORD64 m_dw64SizeSending;
+ unsigned int m_dirSizeRqstNum;
+ };
+ }
+}
+
+#endif // __RFB_WIN32_FILETRANSFER_H__
diff --git a/win/vncviewer/InfoDialog.cxx b/win/vncviewer/InfoDialog.cxx
new file mode 100644
index 0000000..e74896d
--- /dev/null
+++ b/win/vncviewer/InfoDialog.cxx
@@ -0,0 +1,65 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <vncviewer/InfoDialog.h>
+#include <vncviewer/resource.h>
+#include <vncviewer/CConn.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(CConn* cc) {
+ conn = cc;
+ return Dialog::showDialog(MAKEINTRESOURCE(IDD_CONNECTION_INFO));
+}
+
+void InfoDialog::initDialog() {
+ char buf[256];
+
+ setItemString(IDC_INFO_NAME, TStr(conn->cp.name()));
+
+ setItemString(IDC_INFO_HOST, TCharArray(conn->getSocket()->getPeerAddress()).buf);
+
+ sprintf(buf, "%dx%d", conn->cp.width, conn->cp.height);
+ setItemString(IDC_INFO_SIZE, TStr(buf));
+
+ conn->cp.pf().print(buf, 256);
+ setItemString(IDC_INFO_PF, TStr(buf));
+
+ conn->getServerDefaultPF().print(buf, 256);
+ setItemString(IDC_INFO_DEF_PF, TStr(buf));
+
+ setItemString(IDC_REQUESTED_ENCODING, TStr(encodingName(conn->getOptions().preferredEncoding)));
+ setItemString(IDC_LAST_ENCODING, TStr(encodingName(conn->lastUsedEncoding())));
+
+ sprintf(buf, "%d kbits/s", conn->getSocket()->inStream().kbitsPerSecond());
+ setItemString(IDC_INFO_LINESPEED, TStr(buf));
+
+ sprintf(buf, "%d.%d", conn->cp.majorVersion, conn->cp.minorVersion);
+ setItemString(IDC_INFO_VERSION, TStr(buf));
+
+ const CSecurity* cSec = conn->getCurrentCSecurity();
+ setItemString(IDC_INFO_SECURITY, TStr(secTypeName(cSec->getType())));
+ setItemString(IDC_INFO_ENCRYPTION, TStr(cSec->description()));
+}
diff --git a/win/vncviewer/InfoDialog.h b/win/vncviewer/InfoDialog.h
new file mode 100644
index 0000000..752d53c
--- /dev/null
+++ b/win/vncviewer/InfoDialog.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- 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 CConn;
+
+ class InfoDialog : Dialog {
+ public:
+ InfoDialog() : Dialog(GetModuleHandle(0)), conn(0) {}
+ virtual bool showDialog(CConn* vw);
+ virtual void initDialog();
+ protected:
+ CConn* conn;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/ListenServer.h b/win/vncviewer/ListenServer.h
new file mode 100644
index 0000000..4d1590c
--- /dev/null
+++ b/win/vncviewer/ListenServer.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ListenServer.h
+
+#ifndef __RFB_WIN32_LISTEN_SERVER_H__
+#define __RFB_WIN32_LISTEN_SERVER_H__
+
+#include <windows.h>
+#include <winsock2.h>
+#include <network/Socket.h>
+#include <rfb_win32/MsgWindow.h>
+#include <vncviewer/CConnThread.h>
+
+
+namespace rfb {
+ namespace win32 {
+
+ class ListenServer : MsgWindow {
+ public:
+ ListenServer(network::SocketListener* l) : MsgWindow(_T("rfb::win32::ListenServer")), sock(l) {
+ if (WSAAsyncSelect(l->getFd(), getHandle(), WM_USER, FD_ACCEPT) == SOCKET_ERROR)
+ throw rdr::SystemException("unable to monitor listen socket", WSAGetLastError());
+ }
+
+ LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ if (msg == WM_USER) {
+ network::Socket* newConn = sock->accept();
+ Thread* newThread = new CConnThread(newConn, true);
+ return 0;
+ }
+ return MsgWindow::processMessage(msg, wParam, lParam);
+ }
+ protected:
+ network::SocketListener* sock;
+ };
+
+ };
+};
+
+#endif
\ No newline at end of file
diff --git a/win/vncviewer/ListenTrayIcon.h b/win/vncviewer/ListenTrayIcon.h
new file mode 100644
index 0000000..7e334d9
--- /dev/null
+++ b/win/vncviewer/ListenTrayIcon.h
@@ -0,0 +1,95 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- ListenTrayIcon.h
+
+#ifndef __RFB_WIN32_LISTEN_TRAY_ICON_H__
+#define __RFB_WIN32_LISTEN_TRAY_ICON_H__
+
+#include <rfb_win32/TrayIcon.h>
+#include <rfb_win32/AboutDialog.h>
+
+namespace rfb {
+ namespace win32 {
+
+ class ListenTrayIcon : public TrayIcon {
+ public:
+ ListenTrayIcon() {
+ setIcon(IDI_ICON);
+ setToolTip(_T("VNC Viewer"));
+ }
+ virtual LRESULT processMessage(UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch(msg) {
+
+ case WM_USER:
+ switch (lParam) {
+ case WM_LBUTTONDBLCLK:
+ SendMessage(getHandle(), WM_COMMAND, ID_NEW_CONNECTION, 0);
+ break;
+ case WM_RBUTTONUP:
+ HMENU menu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(IDR_TRAY));
+ HMENU trayMenu = GetSubMenu(menu, 0);
+
+ // First item is New Connection, the default
+ SetMenuDefaultItem(trayMenu, ID_NEW_CONNECTION, FALSE);
+
+ // SetForegroundWindow is required, otherwise Windows ignores the
+ // TrackPopupMenu because the window isn't the foreground one, on
+ // some older Windows versions...
+ SetForegroundWindow(getHandle());
+
+ // Display the menu
+ POINT pos;
+ GetCursorPos(&pos);
+ TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, getHandle(), 0);
+ break;
+ }
+ return 0;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case ID_NEW_CONNECTION:
+ {
+ Thread* connThread = new CConnThread();
+ break;
+ }
+ case ID_OPTIONS:
+ OptionsDialog::global.showDialog(0);
+ break;
+ case ID_ABOUT:
+ AboutDialog::instance.showDialog();
+ break;
+ case ID_CLOSE:
+ SendMessage(getHandle(), WM_CLOSE, 0, 0);
+ break;
+ }
+ return 0;
+
+ case WM_CLOSE:
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ return TrayIcon::processMessage(msg, wParam, lParam);
+ }
+ };
+
+ };
+};
+
+#endif // __RFB_WIN32_LISTEN_TRAY_ICON_H__
\ No newline at end of file
diff --git a/win/vncviewer/MRU.h b/win/vncviewer/MRU.h
new file mode 100644
index 0000000..ae703b3
--- /dev/null
+++ b/win/vncviewer/MRU.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#ifndef __VIEWER_MRU_H__
+#define __VIEWER_MRU_H__
+
+#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\\TightVNC\\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 (stricmp(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;
+ }
+
+ 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;
+
+ TCharArray keyname = rdr::HexOutStream::binToHexStr((char*)&keycode, 1);
+ key.setString(keyname.buf, TStr(name));
+ key.setBinary(_T("Order"), order, orderlen);
+ }
+
+ };
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/OptionsDialog.cxx b/win/vncviewer/OptionsDialog.cxx
new file mode 100644
index 0000000..2e43b38
--- /dev/null
+++ b/win/vncviewer/OptionsDialog.cxx
@@ -0,0 +1,337 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <vncviewer/OptionsDialog.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/resource.h>
+#include <rfb_win32/Registry.h>
+#include <rfb_win32/MsgBox.h>
+#include <rfb_win32/OSVersion.h>
+#include <rfb/encodings.h>
+#include <rfb/CConnection.h>
+#include <commdlg.h>
+#include <rfb/LogWriter.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+static LogWriter vlog("Options");
+
+
+struct OptionsInfo {
+ CConn* view;
+ CConnOptions options;
+};
+
+
+OptionsDialog rfb::win32::OptionsDialog::global;
+
+
+class ViewerOptions : public PropSheet {
+public:
+ ViewerOptions(OptionsInfo& info_, std::list<PropSheetPage*> pages)
+ : PropSheet(GetModuleHandle(0),
+ info_.view ? _T("VNC Viewer Options") : _T("VNC Viewer Defaults"), pages),
+ info(info_), changed(false) {
+ }
+ ~ViewerOptions() {
+ 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 encodingTight: setItemChecked(IDC_ENCODING_TIGHT, true); break;
+ case encodingZRLE: setItemChecked(IDC_ENCODING_ZRLE, true); break;
+ case encodingHextile: setItemChecked(IDC_ENCODING_HEXTILE, true); break;
+ case encodingRaw: setItemChecked(IDC_ENCODING_RAW, true); break;
+ }
+ setItemChecked(IDC_CUSTOM_COMPRESSLEVEL, dlg->options.customCompressLevel);
+ setItemInt(IDC_COMPRESSLEVEL, dlg->options.compressLevel);
+ setItemChecked(IDC_ALLOW_JPEG, !dlg->options.noJpeg);
+ setItemInt(IDC_QUALITYLEVEL, dlg->options.qualityLevel);
+ onCommand(IDC_ENCODING_AUTO, 0 /* ? */); // Force enableItem status to refresh
+ onCommand(IDC_CUSTOM_COMPRESSLEVEL, 0 /* ? */); // Force enableItem status to refresh
+ onCommand(IDC_ALLOW_JPEG, 0 /* ? */); // Force enableItem status to refresh
+ }
+ virtual bool onOk() {
+ dlg->options.autoSelect = isItemChecked(IDC_ENCODING_AUTO);
+ dlg->options.fullColour = isItemChecked(IDC_FORMAT_FULLCOLOUR);
+ dlg->options.customCompressLevel = isItemChecked(IDC_CUSTOM_COMPRESSLEVEL);
+ dlg->options.compressLevel = getItemInt(IDC_COMPRESSLEVEL);
+ dlg->options.noJpeg = !isItemChecked(IDC_ALLOW_JPEG);
+ dlg->options.qualityLevel = getItemInt(IDC_QUALITYLEVEL);
+ 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 = encodingTight;
+ if (isItemChecked(IDC_ENCODING_ZRLE))
+ dlg->options.preferredEncoding = encodingZRLE;
+ if (isItemChecked(IDC_ENCODING_HEXTILE))
+ dlg->options.preferredEncoding = encodingHextile;
+ if (isItemChecked(IDC_ENCODING_RAW))
+ dlg->options.preferredEncoding = encodingRaw;
+ ((ViewerOptions*)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_TIGHT, ok);
+ enableItem(IDC_ENCODING_ZRLE, ok);
+ enableItem(IDC_ENCODING_HEXTILE, ok);
+ enableItem(IDC_ENCODING_RAW, ok);
+ enableItem(IDC_FORMAT_FULLCOLOUR, ok);
+ enableItem(IDC_FORMAT_MEDIUMCOLOUR, ok);
+ enableItem(IDC_FORMAT_LOWCOLOUR, ok);
+ enableItem(IDC_FORMAT_VERYLOWCOLOUR, ok);
+ return true;
+ }
+ if (id == IDC_CUSTOM_COMPRESSLEVEL) {
+ enableItem(IDC_COMPRESSLEVEL, isItemChecked(IDC_CUSTOM_COMPRESSLEVEL));
+ return true;
+ }
+ if (id == IDC_ALLOW_JPEG) {
+ enableItem(IDC_QUALITYLEVEL, isItemChecked(IDC_ALLOW_JPEG));
+ 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);
+ setItemChecked(IDC_AUTO_RECONNECT, dlg->options.autoReconnect);
+ setItemChecked(IDC_SHOW_TOOLBAR, dlg->options.showToolbar);
+ }
+ 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);
+ dlg->options.autoReconnect = isItemChecked(IDC_AUTO_RECONNECT);
+ dlg->options.showToolbar = isItemChecked(IDC_SHOW_TOOLBAR);
+ ((ViewerOptions*)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_DISABLE_WINKEYS, dlg->options.disableWinKeys && !osVersion.isPlatformWindows);
+ enableItem(IDC_DISABLE_WINKEYS, !osVersion.isPlatformWindows);
+ setItemChecked(IDC_EMULATE3, dlg->options.emulate3);
+ setItemChecked(IDC_POINTER_INTERVAL, dlg->options.pointerEventInterval != 0);
+
+ // 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.disableWinKeys = isItemChecked(IDC_DISABLE_WINKEYS);
+ 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));
+
+ ((ViewerOptions*)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) {
+ switch (id) {
+ case IDC_LOAD_DEFAULTS:
+ dlg->options = CConnOptions();
+ 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(handle, _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 = handle;
+ 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(handle, _T("Options saved successfully"),
+ MB_OK | MB_ICONINFORMATION);
+ return 0;
+ };
+ propSheet->reInitPages();
+ return true;
+ }
+protected:
+ OptionsInfo* dlg;
+};
+
+
+OptionsDialog::OptionsDialog() : visible(false) {
+}
+
+bool OptionsDialog::showDialog(CConn* 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
+ ViewerOptions dialog(info, pages);
+ dialog.showPropSheet(view && view->getWindow() ? view->getWindow()->getHandle() : 0,
+ false, false, capture);
+
+ visible = false;
+ return dialog.changed;
+}
diff --git a/win/vncviewer/OptionsDialog.h b/win/vncviewer/OptionsDialog.h
new file mode 100644
index 0000000..fcddc71
--- /dev/null
+++ b/win/vncviewer/OptionsDialog.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- OptionsDialog.h
+
+// Options dialog for VNC Viewer 4.0
+
+#ifndef __RFB_WIN32_OPTIONS_DIALOG_H__
+#define __RFB_WIN32_OPTIONS_DIALOG_H__
+
+#include <rfb_win32/Dialog.h>
+
+namespace rfb {
+
+ namespace win32 {
+
+ class CConn;
+
+ class OptionsDialog {
+ public:
+ OptionsDialog();
+ virtual bool showDialog(CConn* cfg, bool capture=false);
+
+ static OptionsDialog global;
+ protected:
+ bool visible;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/UserPasswdDialog.cxx b/win/vncviewer/UserPasswdDialog.cxx
new file mode 100644
index 0000000..2eea0ea
--- /dev/null
+++ b/win/vncviewer/UserPasswdDialog.cxx
@@ -0,0 +1,85 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <vncviewer/UserPasswdDialog.h>
+#include <vncviewer/resource.h>
+#include <rfb/Exception.h>
+
+using namespace rfb;
+using namespace rfb::win32;
+
+
+UserPasswdDialog::UserPasswdDialog() : Dialog(GetModuleHandle(0)),
+ showUsername(false), showPassword(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);
+ if (password.buf)
+ setItemString(IDC_PASSWORD, password.buf);
+ if (!showUsername) {
+ setItemString(IDC_USERNAME, _T(""));
+ enableItem(IDC_USERNAME, false);
+ }
+ if (!showPassword) {
+ setItemString(IDC_PASSWORD, _T(""));
+ enableItem(IDC_PASSWORD, false);
+ }
+ if (description.buf) {
+ TCharArray title(128);
+ GetWindowText(handle, title.buf, 128);
+ _tcsncat(title.buf, _T(" ["), 128);
+ _tcsncat(title.buf, description.buf, 128);
+ _tcsncat(title.buf, _T("]"), 128);
+ SetWindowText(handle, title.buf);
+ }
+}
+
+bool UserPasswdDialog::onOk() {
+ username.replaceBuf(getItemString(IDC_USERNAME));
+ password.replaceBuf(getItemString(IDC_PASSWORD));
+ return true;
+}
+
+
+void UserPasswdDialog::getUserPasswd(char** user, char** passwd) {
+ showUsername = user != 0;
+ showPassword = passwd != 0;
+ if (user && *user)
+ username.replaceBuf(tstrDup(*user));
+ if (passwd && *passwd)
+ password.replaceBuf(tstrDup(*passwd));
+
+ if (!showDialog())
+ throw rfb::AuthCancelledException();
+
+ if (user)
+ *user = strDup(username.buf);
+ if (passwd)
+ *passwd = strDup(password.buf);
+}
diff --git a/win/vncviewer/UserPasswdDialog.h b/win/vncviewer/UserPasswdDialog.h
new file mode 100644
index 0000000..bf006f4
--- /dev/null
+++ b/win/vncviewer/UserPasswdDialog.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- UserPasswdDialog.h
+
+// Username and password dialog for VNC Viewer 4.0
+// Note that the password and username fields are only freed
+// when the dialog instance is deleted - it is important to
+// ensure that the instance is deleted as early as possible, to
+// avoid the password being retained in memory for too long.
+
+#ifndef __RFB_WIN32_USERPASSWD_DIALOG_H__
+#define __RFB_WIN32_USERPASSWD_DIALOG_H__
+
+#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 void getUserPasswd(char** user, char** passwd);
+ void setCSecurity(const CSecurity* cs);
+ protected:
+ TCharArray username;
+ TPlainPasswd password;
+ bool showUsername, showPassword;
+ TCharArray description;
+ };
+
+ };
+
+};
+
+#endif
diff --git a/win/vncviewer/ViewerToolBar.cxx b/win/vncviewer/ViewerToolBar.cxx
new file mode 100644
index 0000000..29b8030
--- /dev/null
+++ b/win/vncviewer/ViewerToolBar.cxx
@@ -0,0 +1,117 @@
+/* Copyright (C) 2005 TightVNC Team. 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.
+ */
+
+// -=- ViewerToolBar.cxx
+
+#include <vncviewer/ViewerToolBar.h>
+#include <vncviewer/resource.h>
+
+void ViewerToolBar::create(HWND parentHwnd) {
+ // Create the toolbar panel
+ ToolBar::create(ID_TOOLBAR, parentHwnd, WS_CHILD |
+ TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NORESIZE);
+ addBitmap(4, IDB_TOOLBAR);
+
+ // Create the control buttons
+ addButton(0, ID_OPTIONS);
+ addButton(1, ID_INFO);
+ addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ addButton(2, ID_FULLSCREEN);
+ addButton(3, ID_REQUEST_REFRESH);
+ addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ addButton(4, ID_SEND_CAD);
+ addButton(5, ID_SEND_CTLESC);
+ addButton(6, ID_CTRL_KEY);
+ addButton(7, ID_ALT_KEY);
+ addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ addButton(8, ID_FILE_TRANSFER);
+ addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
+ addButton(9, ID_NEW_CONNECTION);
+ addButton(10, ID_CONN_SAVE_AS);
+ addButton(11, ID_CLOSE);
+
+ // Resize the toolbar window
+ autoSize();
+}
+
+LRESULT ViewerToolBar::processWM_NOTIFY(WPARAM wParam, LPARAM lParam) {
+ switch (((LPNMHDR)lParam)->code) {
+ // Process tooltips text
+ case TTN_NEEDTEXT:
+ {
+ LPTOOLTIPTEXT TTStr = (LPTOOLTIPTEXT)lParam;
+ if (TTStr->hdr.code != TTN_NEEDTEXT)
+ return 0;
+
+ switch (TTStr->hdr.idFrom) {
+ case ID_OPTIONS:
+ TTStr->lpszText = "Connection options...";
+ break;
+ case ID_INFO:
+ TTStr->lpszText = "Connection info";
+ break;
+ case ID_FULLSCREEN:
+ TTStr->lpszText = "Full screen";
+ break;
+ case ID_REQUEST_REFRESH:
+ TTStr->lpszText = "Request screen refresh";
+ break;
+ case ID_SEND_CAD:
+ TTStr->lpszText = "Send Ctrl-Alt-Del";
+ break;
+ case ID_SEND_CTLESC:
+ TTStr->lpszText = "Send Ctrl-Esc";
+ break;
+ case ID_CTRL_KEY:
+ TTStr->lpszText = "Send Ctrl key press/release";
+ break;
+ case ID_ALT_KEY:
+ TTStr->lpszText = "Send Alt key press/release";
+ break;
+ case ID_FILE_TRANSFER:
+ TTStr->lpszText = "Transfer files...";
+ break;
+ case ID_NEW_CONNECTION:
+ TTStr->lpszText = "New connection...";
+ break;
+ case ID_CONN_SAVE_AS:
+ TTStr->lpszText = "Save connection info as...";
+ break;
+ case ID_CLOSE:
+ TTStr->lpszText = "Disconnect";
+ break;
+ default:
+ break;
+ }
+ }
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+void ViewerToolBar::show() {
+ ShowWindow(getHandle(), SW_SHOW);
+ SendMessage(parentHwnd, WM_SIZE, 0, 0);
+}
+
+void ViewerToolBar::hide() {
+ ShowWindow(getHandle(), SW_HIDE);
+ SendMessage(parentHwnd, WM_SIZE, 0, 0);
+}
diff --git a/win/vncviewer/ViewerToolBar.h b/win/vncviewer/ViewerToolBar.h
new file mode 100644
index 0000000..30e7708
--- /dev/null
+++ b/win/vncviewer/ViewerToolBar.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2005 TightVNC Team. 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.
+ */
+
+// -=- ViewerToolBar.h
+
+// ToolBar for the Vnc Viewer
+
+#include <rfb_win32/ToolBar.h>
+
+using namespace rfb::win32;
+
+class ViewerToolBar : public ToolBar {
+public:
+ ViewerToolBar() {}
+ ~ViewerToolBar() {}
+
+ void create(HWND parentHwnd);
+
+ LRESULT processWM_NOTIFY(WPARAM wParam, LPARAM lParam);
+
+ void show();
+ void hide();
+};
diff --git a/win/vncviewer/buildTime.cxx b/win/vncviewer/buildTime.cxx
new file mode 100644
index 0000000..9f37b38
--- /dev/null
+++ b/win/vncviewer/buildTime.cxx
@@ -0,0 +1,18 @@
+/* Copyright (C) 2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+const char* buildTime = "Built on " __DATE__ " at " __TIME__;
diff --git a/win/vncviewer/cursor1.cur b/win/vncviewer/cursor1.cur
new file mode 100644
index 0000000..20a713f
--- /dev/null
+++ b/win/vncviewer/cursor1.cur
Binary files differ
diff --git a/win/vncviewer/ftdir.ico b/win/vncviewer/ftdir.ico
new file mode 100644
index 0000000..7a7f741
--- /dev/null
+++ b/win/vncviewer/ftdir.ico
Binary files differ
diff --git a/win/vncviewer/ftfile.ico b/win/vncviewer/ftfile.ico
new file mode 100644
index 0000000..a8084b8
--- /dev/null
+++ b/win/vncviewer/ftfile.ico
Binary files differ
diff --git a/win/vncviewer/ftreload.ico b/win/vncviewer/ftreload.ico
new file mode 100644
index 0000000..34383e9
--- /dev/null
+++ b/win/vncviewer/ftreload.ico
Binary files differ
diff --git a/win/vncviewer/ftup.ico b/win/vncviewer/ftup.ico
new file mode 100644
index 0000000..fc215ad
--- /dev/null
+++ b/win/vncviewer/ftup.ico
Binary files differ
diff --git a/win/vncviewer/resource.h b/win/vncviewer/resource.h
new file mode 100644
index 0000000..5493fd0
--- /dev/null
+++ b/win/vncviewer/resource.h
@@ -0,0 +1,154 @@
+//{{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 IDB_BITMAP 120
+#define IDD_FILETRANSFER_DLG 121
+#define IDB_TOOLBAR 122
+#define IDD_FTCONFIRM_DLG 124
+#define IDI_FTUP 125
+#define IDI_FTDIR 126
+#define IDI_FTFILE 127
+#define IDI_FTRELOAD 128
+#define IDR_FTMENU 130
+#define IDD_FTCANCELING 131
+#define IDD_FTCREATEFOLDER 132
+#define IDD_FTBROWSE 133
+#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_FTLOCALLIST 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_SHOW_TOOLBAR 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 IDC_SECURITY_LEVEL 1054
+#define IDC_INFO_ENCRYPTION 1055
+#define IDC_AUTO_RECONNECT 1056
+#define IDC_DISABLE_WINKEYS 1057
+#define IDC_QUALITYLEVEL 1058
+#define IDC_FTLOCALUP 1058
+#define IDC_SEND_SYSKEYS 1059
+#define IDC_FTLOCALBROWSE 1059
+#define IDC_FTREMOTERELOAD 1060
+#define IDC_FTREMOTEUP 1061
+#define IDC_FTREMOTEBROWSE 1062
+#define IDC_FTPROGRESS 1063
+#define IDC_FTGENERALPROGRESS 1063
+#define IDC_PROGRESS 1064
+#define IDC_FTSINGLEPROGRESS 1064
+#define IDC_FTSTATUS 1065
+#define IDC_FTCURRENTPROCENT 1066
+#define IDC_FTSINGLEPERCENT 1066
+#define IDC_FTTOTALPROCENT 1067
+#define IDC_FTGENERALPERCENT 1067
+#define IDC_FTUPLOAD 1072
+#define IDC_FTCANCEL 1073
+#define IDC_FTDOWNLOAD 1074
+#define IDC_FTCLOSE 1075
+#define IDC_FTLOCALLABEL 1076
+#define IDC_FTREMOTELABEL 1077
+#define IDC_FTDIRNAME 1078
+#define IDC_CONFIRM_YESTOALL 1079
+#define IDC_CONFIRM_TEXT 1080
+#define IDC_EDIT2 1082
+#define IDC_FTFOLDERNAME 1083
+#define IDC_FTTEXT 1084
+#define IDC_FTBROWSEPATH 1085
+#define IDC_FTBROWSETREE 1086
+#define IDC_TYPE 1088
+#define IDC_ENCODING_TIGHT 1089
+#define IDC_FTLOCALPATH 1090
+#define IDC_CUSTOM_COMPRESSLEVEL 1091
+#define IDC_FTREMOTEPATH 1092
+#define IDC_COMPRESSLEVEL 1093
+#define IDC_FTREMOTELIST 1094
+#define IDC_ALLOW_JPEG 1095
+#define IDC_FTLOCALRELOAD 1096
+#define ID_TOOLBAR 40002
+#define ID_CLOSE 40003
+#define ID_OPTIONS 40004
+#define ID_NEW_CONNECTION 40005
+#define ID_ABOUT 40006
+#define ID_FULLSCREEN 40007
+#define ID_SEND_CAD 40008
+#define ID_INFO 40009
+#define ID_REQUEST_REFRESH 40010
+#define ID_CTRL_KEY 40011
+#define ID_ALT_KEY 40012
+#define ID_SEND_MENU_KEY 40013
+#define ID_SEND_CTLESC 40014
+#define ID_CONN_SAVE_AS 40015
+#define ID_FILE_TRANSFER 40016
+#define IDM_FTCOPY 40022
+#define IDM_FTRENAME 40023
+#define IDM_FTDELETE 40024
+#define IDM_FTCANCEL 40025
+#define IDM_FTCREATEFOLDER 40026
+#define IDM_SHOW_TOOLBAR 40027
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 134
+#define _APS_NEXT_COMMAND_VALUE 40028
+#define _APS_NEXT_CONTROL_VALUE 1097
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/win/vncviewer/toolbar.bmp b/win/vncviewer/toolbar.bmp
new file mode 100644
index 0000000..0a14636
--- /dev/null
+++ b/win/vncviewer/toolbar.bmp
Binary files differ
diff --git a/win/vncviewer/vncviewer.bmp b/win/vncviewer/vncviewer.bmp
new file mode 100644
index 0000000..4ea9c37
--- /dev/null
+++ b/win/vncviewer/vncviewer.bmp
Binary files differ
diff --git a/win/vncviewer/vncviewer.cxx b/win/vncviewer/vncviewer.cxx
new file mode 100644
index 0000000..3a5214a
--- /dev/null
+++ b/win/vncviewer/vncviewer.cxx
@@ -0,0 +1,295 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+// -=- VNC Viewer for Win32
+
+#include <string.h>
+#ifdef WIN32
+#define strcasecmp _stricmp
+#endif
+#include <list>
+
+#include <vncviewer/resource.h>
+#include <vncviewer/CConn.h>
+#include <vncviewer/CConnThread.h>
+#include <vncviewer/OptionsDialog.h>
+#include <vncviewer/ListenServer.h>
+#include <vncviewer/ListenTrayIcon.h>
+#include <network/TcpSocket.h>
+#include <rfb/Logger_stdio.h>
+#include <rfb/Logger_file.h>
+#include <rfb/LogWriter.h>
+#include <rfb/Exception.h>
+#include <rfb_win32/RegConfig.h>
+#include <rfb_win32/MsgBox.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;
+
+
+//
+// -=- 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 VNC Viewer 3.3 settings file\n");
+ printf(" -console - Run with a console window visible.\n");
+ printf(" <setting>=<value> - Set the named configuration parameter.\n");
+ printf(" (Parameter values specified on the command-line override those specified by other configuration methods.)\n");
+ printf("\nLog names:\n");
+ LogWriter::listLogWriters();
+ printf("\nLog destinations:\n");
+ Logger::listLoggers();
+ printf("\nParameters:\n");
+ Configuration::listParams();
+ printf("Press Enter/Return key to continue\n");
+ char c = getchar();
+ exit(1);
+}
+
+
+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 if (strContains(argv[i], '\\')) {
+ configFiles.push_back(strDup(argv[i]));
+ } 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) {
+ CConn::userConfigKey.openKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\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::RegConfigThread config;
+ config.start(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
+
+ // - Tell the rest of VNC Viewer where to write config data to
+ CConn::userConfigKey.createKey(HKEY_CURRENT_USER, _T("Software\\TightVNC\\VNCViewer4"));
+
+ if (acceptIncoming) {
+ int port = 5500;
+
+ // Listening viewer
+ if (hosts.size() > 1)
+ programUsage();
+ if (!hosts.empty())
+ port = atoi(hosts.front());
+
+ // Show the tray icon & menu
+ ListenTrayIcon tray;
+
+ // Listen for reverse connections
+ network::TcpListener sock(port);
+ ListenServer listener(&sock);
+
+ // Run the view manager
+ // Also processes the tray icon if necessary
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0) > 0) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ } else {
+ // Read each config file in turn
+ while (!configFiles.empty()) {
+ char* filename = configFiles.front();
+ Thread* connThread = new CConnThread(filename, true);
+ strFree(filename);
+ configFiles.pop_front();
+ }
+
+ // Connect to each client in turn
+ while (!hosts.empty()) {
+ char* hostinfo = hosts.front();
+ Thread* connThread = new CConnThread(hostinfo);
+ strFree(hostinfo);
+ hosts.pop_front();
+ }
+
+ // Run the view manager
+ MSG msg;
+ while (CConnThread::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/win/vncviewer/vncviewer.dsp b/win/vncviewer/vncviewer.dsp
new file mode 100644
index 0000000..e245cd6
--- /dev/null
+++ b/win/vncviewer/vncviewer.dsp
@@ -0,0 +1,321 @@
+# 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\vncviewer"
+# 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 ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /YX /FD /c
+# ADD BASE RSC /l 0x809 /d "NDEBUG"
+# ADD RSC /l 0x809 /d "NDEBUG"
+BSC32=bscmake.exe
+# 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 /Fo..\Release\ /Fd..\Release\vncviewer /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\vncviewer"
+# 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 ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_DEBUG" /D "_WINDOWS" /D "WIN32" /D "_MBCS" /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x809 /d "_DEBUG"
+# ADD RSC /l 0x809 /d "_DEBUG"
+BSC32=bscmake.exe
+# 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 /Fo..\Debug\ /Fd..\Debug\vncviewer /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\vncviewer"
+# 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 ".." /I "../../common" /FI"rdr/msvcwarning.h" /D "_WINDOWS" /D "_DEBUG" /D "WIN32" /D "_UNICODE" /D "UNICODE" /FR /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 /Fo..\Debug_Unicode\ /Fd..\Debug_Unicode\vncviewer /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=.\CConn.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnOptions.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnThread.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConnectingDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConnectionDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\DesktopWindow.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileTransfer.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTBrowseDlg.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTDialog.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTListView.cxx
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTProgress.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=.\ViewerToolBar.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=.\CConn.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnOptions.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CConnThread.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConnectingDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConnectionDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\DesktopWindow.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileTransfer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTBrowseDlg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTListView.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FTProgress.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\InfoDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ListenServer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ListenTrayIcon.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MRU.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\OptionsDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UserPasswdDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ViewerToolBar.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=.\ftdir.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftfile.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftreload.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\ftup.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\toolbar.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncviewer.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncviewer.exe.manifest
+# End Source File
+# Begin Source File
+
+SOURCE=.\vncviewer.ico
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/win/vncviewer/vncviewer.exe.manifest b/win/vncviewer/vncviewer.exe.manifest
new file mode 100644
index 0000000..7fd947f
--- /dev/null
+++ b/win/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="TightVNC.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/win/vncviewer/vncviewer.ico b/win/vncviewer/vncviewer.ico
new file mode 100644
index 0000000..6572661
--- /dev/null
+++ b/win/vncviewer/vncviewer.ico
Binary files differ
diff --git a/win/vncviewer/vncviewer.rc b/win/vncviewer/vncviewer.rc
new file mode 100644
index 0000000..ea5dd65
--- /dev/null
+++ b/win/vncviewer/vncviewer.rc
@@ -0,0 +1,708 @@
+//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"
+IDI_FTDIR ICON DISCARDABLE "ftdir.ico"
+IDI_FTFILE ICON DISCARDABLE "ftfile.ico"
+IDI_FTRELOAD ICON DISCARDABLE "ftreload.ico"
+IDI_FTUP ICON DISCARDABLE "ftup.ico"
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 4,1,1,0
+ PRODUCTVERSION 4,1,1,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "Comments", "\0"
+ VALUE "CompanyName", "Constantin Kaplinsky\0"
+ VALUE "FileDescription", "TightVNC Viewer for Win32\0"
+ VALUE "FileVersion", "4.1.1\0"
+ VALUE "InternalName", "free4/vncviewer/win\0"
+ VALUE "LegalCopyright", "Copyright (C) 1998-2006 [many holders]\0"
+ VALUE "LegalTrademarks", "TightVNC\0"
+ VALUE "OriginalFilename", "vncviewer.exe\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "TightVNC Viewer\0"
+ VALUE "ProductVersion", "4.1.1\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x809, 1200
+ END
+END
+
+#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,85,6,100,14,ES_AUTOHSCROLL
+ EDITTEXT IDC_PASSWORD,85,25,100,15,ES_PASSWORD | ES_AUTOHSCROLL |
+ ES_WANTRETURN
+ DEFPUSHBUTTON "OK",IDOK,190,6,45,14
+ PUSHBUTTON "Cancel",IDCANCEL,190,25,45,15
+ CONTROL 120,IDI_ICON,"Static",SS_BITMAP,7,6,21,20
+ LTEXT "Username:",IDC_STATIC,45,6,35,14
+ LTEXT "Password:",IDC_STATIC,45,25,35,15
+END
+
+IDD_CONNECTING_DLG DIALOG DISCARDABLE 0, 0, 185, 47
+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
+ CTEXT "Attempting to connect to host...",IDC_CONNECTING_TEXT,7,
+ 7,171,14,SS_CENTERIMAGE
+END
+
+IDD_CONNECTION_DLG DIALOG DISCARDABLE 0, 0, 224, 66
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "VNC Viewer : Connection Details"
+FONT 8, "MS Sans Serif"
+BEGIN
+ COMBOBOX IDC_SERVER_EDIT,85,6,105,234,CBS_DROPDOWN |
+ CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "&About...",IDC_ABOUT,5,45,50,14
+ PUSHBUTTON "&Options...",IDC_OPTIONS,60,45,50,14
+ DEFPUSHBUTTON "OK",IDOK,115,45,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,170,45,48,14
+ CONTROL 120,IDI_ICON,"Static",SS_BITMAP | SS_REALSIZEIMAGE,5,6,
+ 20,20
+ RTEXT "Server:",IDC_STATIC,43,6,37,13,SS_CENTERIMAGE
+ RTEXT "Encryption:",IDC_STATIC,43,24,37,12,SS_CENTERIMAGE
+ COMBOBOX IDC_SECURITY_LEVEL,85,24,105,76,CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_ABOUT DIALOG DISCARDABLE 0, 0, 249, 92
+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
+ CONTROL 120,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,7,
+ 10,33,31
+ LTEXT ">appname<",IDC_DESCRIPTION,46,10,119,15
+ LTEXT ">version<",IDC_VERSION,165,10,77,15
+ LTEXT ">buildtime<",IDC_BUILDTIME,46,25,196,15
+ LTEXT ">copyright<",IDC_COPYRIGHT,46,40,196,15
+ LTEXT "Visit www.tightvnc.com for more information on TightVNC.",
+ IDC_STATIC,46,55,196,15
+END
+
+IDD_FORMAT DIALOG DISCARDABLE 0, 0, 201, 161
+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,20,83,75
+ CONTROL "Tight",IDC_ENCODING_TIGHT,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,10,30,75,14
+ CONTROL "ZRLE",IDC_ENCODING_ZRLE,"Button",BS_AUTORADIOBUTTON,10,
+ 45,75,14
+ CONTROL "Hextile",IDC_ENCODING_HEXTILE,"Button",
+ BS_AUTORADIOBUTTON,10,60,75,16
+ CONTROL "Raw",IDC_ENCODING_RAW,"Button",BS_AUTORADIOBUTTON,10,75,
+ 75,15
+ GROUPBOX "Color level",IDC_STATIC,95,20,99,75
+ CONTROL "&Full (all available colors)",IDC_FORMAT_FULLCOLOUR,
+ "Button",BS_AUTORADIOBUTTON | WS_GROUP,100,30,90,15
+ CONTROL "&Medium (256 colors)",IDC_FORMAT_MEDIUMCOLOUR,"Button",
+ BS_AUTORADIOBUTTON,100,45,90,14
+ CONTROL "&Low (64 colors)",IDC_FORMAT_LOWCOLOUR,"Button",
+ BS_AUTORADIOBUTTON,100,60,90,16
+ CONTROL "&Very low (8 colors)",IDC_FORMAT_VERYLOWCOLOUR,"Button",
+ BS_AUTORADIOBUTTON,100,75,90,15
+ CONTROL "Custom compression level:",IDC_CUSTOM_COMPRESSLEVEL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,100,99,10
+ EDITTEXT IDC_COMPRESSLEVEL,25,111,15,12,ES_AUTOHSCROLL |
+ ES_NUMBER
+ LTEXT "level (1=fast, 9=best)",IDC_STATIC,44,114,81,9,NOT
+ WS_GROUP
+ CONTROL "Allow JPEG compression:",IDC_ALLOW_JPEG,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,10,126,96,10
+ EDITTEXT IDC_QUALITYLEVEL,25,137,15,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "quality (1=poor, 9=best)",IDC_STATIC,44,140,81,9
+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,99,15
+ CONTROL "Show toolbar",IDC_SHOW_TOOLBAR,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,106,25,100,15
+ CONTROL "Render cursor locally",IDC_LOCAL_CURSOR,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,40,199,15
+ CONTROL "Allow dynamic desktop resizing",IDC_DESKTOP_RESIZE,
+ "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,85,199,15
+ CONTROL "Offer to automatically reconnect",IDC_AUTO_RECONNECT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,199,15
+END
+
+IDD_INPUTS DIALOG DISCARDABLE 0, 0, 186, 162
+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
+ CONTROL "Pass special keys directly to server",
+ IDC_DISABLE_WINKEYS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,7,115,172,15
+END
+
+IDD_CONNECTION_INFO DIALOG DISCARDABLE 0, 0, 239, 199
+STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_CENTER | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "VNC Connection Info"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,182,178,50,14
+ LTEXT "Desktop Name:",IDC_STATIC,7,10,73,15
+ LTEXT "Host:",IDC_STATIC,7,25,73,15
+ LTEXT "Size:",IDC_STATIC,7,40,73,15
+ 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
+ LTEXT "Static",IDC_INFO_ENCRYPTION,80,160,152,15
+ LTEXT "Encryption:",IDC_STATIC,7,160,73,15
+END
+
+IDD_DEFAULTS DIALOG DISCARDABLE 0, 0, 217, 87
+STYLE DS_MODALFRAME | DS_CONTROL | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Load / Save"
+FONT 8, "MS Sans Serif"
+BEGIN
+ PUSHBUTTON "&Reload",IDC_LOAD_CONFIG,15,20,85,15
+ PUSHBUTTON "&Save",IDC_SAVE_CONFIG,15,40,85,15
+ PUSHBUTTON "Save &As ...",IDC_SAVE_CONFIG_AS,15,60,85,15
+ PUSHBUTTON "R&eload",IDC_LOAD_DEFAULTS,120,20,85,15
+ PUSHBUTTON "S&ave",IDC_SAVE_DEFAULTS,120,40,85,15
+ GROUPBOX "Configuration File",IDC_STATIC,7,7,100,74
+ GROUPBOX "Defaults",IDC_STATIC,113,7,97,53
+END
+
+IDD_FILETRANSFER_DLG DIALOGEX 0, 0, 530, 282
+STYLE DS_MODALFRAME | DS_CONTEXTHELP | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+EXSTYLE WS_EX_CONTEXTHELP | WS_EX_CONTROLPARENT
+CAPTION "TightVNC File Transfers"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+ CONTROL "List1",IDC_FTLOCALLIST,"SysListView32",LVS_REPORT |
+ LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,7,40,200,196
+ CONTROL "List2",IDC_FTREMOTELIST,"SysListView32",LVS_REPORT |
+ LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,323,40,200,196
+ PUSHBUTTON "Upload Files and Folders",IDC_FTUPLOAD,218,66,94,12,
+ WS_DISABLED
+ PUSHBUTTON "Download Files and Folders",IDC_FTDOWNLOAD,218,85,94,12,
+ WS_DISABLED
+ PUSHBUTTON "Cancel File Transfer",IDC_FTCANCEL,218,167,94,12,
+ WS_DISABLED
+ PUSHBUTTON "Close",IDC_FTCLOSE,218,217,94,12
+ EDITTEXT IDC_FTLOCALPATH,7,20,155,12,ES_AUTOHSCROLL | NOT
+ WS_TABSTOP
+ CTEXT "Local Computer",IDC_FTLOCALLABEL,7,7,200,10
+ PUSHBUTTON "...",IDC_FTLOCALBROWSE,165,20,14,12,NOT WS_TABSTOP
+ PUSHBUTTON "",IDC_FTLOCALUP,179,20,14,12,BS_ICON | NOT WS_TABSTOP
+ PUSHBUTTON "",IDC_FTLOCALRELOAD,193,20,14,12,BS_ICON | NOT
+ WS_TABSTOP
+ CONTROL "Progress1",IDC_FTGENERALPROGRESS,"msctls_progress32",
+ WS_BORDER,55,244,128,10
+ LTEXT "File Transfer",IDC_STATIC,7,245,40,8
+ COMBOBOX IDC_FTSTATUS,7,263,516,65,CBS_DROPDOWNLIST |
+ CBS_NOINTEGRALHEIGHT | WS_VSCROLL
+ CONTROL "Progress1",IDC_FTSINGLEPROGRESS,"msctls_progress32",
+ WS_BORDER,370,244,128,10
+ EDITTEXT IDC_FTREMOTEPATH,323,20,155,12,ES_AUTOHSCROLL | NOT
+ WS_TABSTOP
+ PUSHBUTTON "...",IDC_FTREMOTEBROWSE,481,20,14,12,NOT WS_TABSTOP
+ PUSHBUTTON "",IDC_FTREMOTEUP,495,20,14,12,BS_ICON | NOT WS_TABSTOP
+ PUSHBUTTON "",IDC_FTREMOTERELOAD,509,20,14,12,BS_ICON | NOT
+ WS_TABSTOP
+ CTEXT "TightVNC Server",IDC_FTREMOTELABEL,323,7,200,10
+ LTEXT "Current File",IDC_STATIC,323,245,36,8
+ CTEXT "0%",IDC_FTGENERALPERCENT,189,245,18,8
+ CTEXT "0%",IDC_FTSINGLEPERCENT,505,245,18,8
+END
+
+IDD_FTBROWSE DIALOGEX 0, 0, 183, 196
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Browse Folders"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,38,175,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,95,175,50,14
+ EDITTEXT IDC_FTBROWSEPATH,7,7,169,12,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_TABSTOP
+ CONTROL "Tree1",IDC_FTBROWSETREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP |
+ TVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,7,25,169,143
+END
+
+IDD_FTCANCELING DIALOG DISCARDABLE 0, 0, 193, 63
+STYLE DS_SYSMODAL | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Canceling Active File Transfer"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "Yes",IDOK,40,42,50,14
+ PUSHBUTTON "No",IDCANCEL,102,42,50,14
+ LTEXT "FileTransfer is active.\nAre you sure you want to cancel transfer?",
+ IDC_STATIC,42,14,133,19
+END
+
+IDD_FTCONFIRM_DLG DIALOG DISCARDABLE 0, 0, 188, 143
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "Yes",IDOK,69,122,50,14,WS_GROUP
+ PUSHBUTTON "No",IDCANCEL,131,122,50,14
+ PUSHBUTTON "Yes to All",IDC_CONFIRM_YESTOALL,7,122,50,14
+ LTEXT "Static",IDC_CONFIRM_TEXT,7,7,174,107
+END
+
+IDD_FTCREATEFOLDER DIALOG DISCARDABLE 0, 0, 193, 63
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Create a New Folder"
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_FTFOLDERNAME,7,19,179,14,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,80,42,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,136,42,50,14
+ LTEXT "New folder name:",IDC_FTTEXT,7,7,179,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_VNC_AUTH_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 235
+ VERTGUIDE, 45
+ VERTGUIDE, 80
+ VERTGUIDE, 85
+ VERTGUIDE, 185
+ VERTGUIDE, 190
+ 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, 218
+ VERTGUIDE, 30
+ VERTGUIDE, 43
+ VERTGUIDE, 55
+ VERTGUIDE, 60
+ VERTGUIDE, 80
+ VERTGUIDE, 85
+ VERTGUIDE, 110
+ VERTGUIDE, 115
+ VERTGUIDE, 165
+ VERTGUIDE, 170
+ VERTGUIDE, 190
+ TOPMARGIN, 6
+ BOTTOMMARGIN, 59
+ HORZGUIDE, 19
+ HORZGUIDE, 24
+ HORZGUIDE, 36
+ HORZGUIDE, 45
+ END
+
+ IDD_ABOUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 242
+ VERTGUIDE, 46
+ 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, 154
+ 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
+ VERTGUIDE, 106
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 130
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ HORZGUIDE, 85
+ HORZGUIDE, 100
+ HORZGUIDE, 115
+ HORZGUIDE, 130
+ END
+
+ IDD_INPUTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ VERTGUIDE, 105
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 155
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ HORZGUIDE, 85
+ HORZGUIDE, 100
+ HORZGUIDE, 115
+ HORZGUIDE, 130
+ HORZGUIDE, 145
+ END
+
+ IDD_CONNECTION_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 232
+ VERTGUIDE, 80
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 192
+ HORZGUIDE, 10
+ HORZGUIDE, 25
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 70
+ HORZGUIDE, 85
+ HORZGUIDE, 100
+ HORZGUIDE, 115
+ HORZGUIDE, 130
+ HORZGUIDE, 145
+ HORZGUIDE, 160
+ HORZGUIDE, 175
+ END
+
+ IDD_DEFAULTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 210
+ VERTGUIDE, 15
+ VERTGUIDE, 100
+ VERTGUIDE, 107
+ VERTGUIDE, 113
+ VERTGUIDE, 120
+ VERTGUIDE, 205
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 80
+ HORZGUIDE, 20
+ HORZGUIDE, 35
+ HORZGUIDE, 40
+ HORZGUIDE, 55
+ HORZGUIDE, 60
+ HORZGUIDE, 75
+ END
+
+ IDD_FILETRANSFER_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 523
+ VERTGUIDE, 207
+ VERTGUIDE, 265
+ VERTGUIDE, 323
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 275
+ HORZGUIDE, 12
+ HORZGUIDE, 26
+ HORZGUIDE, 40
+ HORZGUIDE, 47
+ HORZGUIDE, 249
+ END
+
+ IDD_FTBROWSE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 176
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 189
+ END
+
+ IDD_FTCANCELING, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 186
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 56
+ END
+
+ IDD_FTCONFIRM_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 181
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 136
+ END
+
+ IDD_FTCREATEFOLDER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 186
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 56
+ 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
+
+IDR_FTMENU MENU DISCARDABLE
+BEGIN
+ POPUP "File Transfer"
+ BEGIN
+ MENUITEM "Copy Files and Folders", IDM_FTCOPY
+ MENUITEM SEPARATOR
+ MENUITEM "Create a Folder", IDM_FTCREATEFOLDER
+ MENUITEM "Rename File or Folder", IDM_FTRENAME
+ MENUITEM "Delete Files and Folders", IDM_FTDELETE
+ MENUITEM SEPARATOR
+ MENUITEM "Cancel File Transfer", IDM_FTCANCEL
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 24
+//
+
+IDR_MANIFEST 24 DISCARDABLE "vncviewer.exe.manifest"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_BITMAP BITMAP DISCARDABLE "vncviewer.bmp"
+IDB_TOOLBAR BITMAP DISCARDABLE "toolbar.bmp"
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+