diff options
Diffstat (limited to 'vncviewer/cview.cxx')
-rw-r--r-- | vncviewer/cview.cxx | 1742 |
1 files changed, 0 insertions, 1742 deletions
diff --git a/vncviewer/cview.cxx b/vncviewer/cview.cxx deleted file mode 100644 index 03c68e20..00000000 --- a/vncviewer/cview.cxx +++ /dev/null @@ -1,1742 +0,0 @@ -/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved. - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#define WIN32_LEAN_AND_MEAN -#if (_WIN32_WINNT < 0x0400) -#define _WIN32_WINNT 0x0400 -#endif -#include <windows.h> -#include <winsock2.h> -#include <tchar.h> -#include <commctrl.h> - -#include <network/TcpSocket.h> - -#include <vncviewer/CView.h> -#include <vncviewer/UserPasswdDialog.h> -#include <vncviewer/resource.h> - -#include <rfb/encodings.h> -#include <rfb/secTypes.h> -#include <rfb/CSecurityNone.h> -#include <rfb/CSecurityVncAuth.h> -#include <rfb/CMsgWriter.h> -#include <rfb/Configuration.h> -#include <rfb/LogWriter.h> - -#include <rfb_win32/WMShatter.h> - -using namespace rfb; -using namespace rfb::win32; -using namespace rdr; - -// - Statics & consts - -static LogWriter vlog("CView"); - -const int IDM_FULLSCREEN = ID_FULLSCREEN; -const int IDM_SEND_MENU_KEY = ID_SEND_MENU_KEY; -const int IDM_SEND_CAD = ID_SEND_CAD; -const int IDM_SEND_CTLESC = ID_SEND_CTLESC; -const int IDM_ABOUT = ID_ABOUT; -const int IDM_OPTIONS = ID_OPTIONS; -const int IDM_INFO = ID_INFO; -const int IDM_NEWCONN = ID_NEW_CONNECTION; -const int IDM_REQUEST_REFRESH = ID_REQUEST_REFRESH; -const int IDM_CTRL_KEY = ID_CTRL_KEY; -const int IDM_ALT_KEY = ID_ALT_KEY; -const int IDM_FILE_TRANSFER = ID_FILE_TRANSFER; -const int IDM_CONN_SAVE_AS = ID_CONN_SAVE_AS; - -const int TIMER_BUMPSCROLL = 1; -const int TIMER_POINTER_INTERVAL = 2; -const int TIMER_POINTER_3BUTTON = 3; - -const int HOTKEY_ALTTAB = 0; - - -IntParameter debugDelay("DebugDelay","Milliseconds to display inverted " - "pixel data - a debugging feature", 0); - - -// -// -=- CViewClass - -// -// Window class used as the basis for all CView instances -// - -class CViewClass { -public: - CViewClass(); - ~CViewClass(); - ATOM classAtom; - HINSTANCE instance; -}; - -LRESULT CALLBACK CViewProc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { - LRESULT result; - - // *** vlog.debug("CViewMsg %x->(%x, %x, %x)", wnd, msg, wParam, lParam); - - if (msg == WM_CREATE) - SetWindowLong(wnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams); - else if (msg == WM_DESTROY) - SetWindowLong(wnd, GWL_USERDATA, 0); - CView* _this = (CView*) GetWindowLong(wnd, GWL_USERDATA); - if (!_this) { - vlog.info("null _this in %x, message %u", wnd, msg); - return rfb::win32::SafeDefWindowProc(wnd, msg, wParam, lParam); - } - - try { - result = _this->processMessage(msg, wParam, lParam); - } catch (rdr::Exception& e) { - vlog.error("untrapped: %s", e.str()); - } - - return result; -}; - -HCURSOR dotCursor = (HCURSOR)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDC_DOT_CURSOR), IMAGE_CURSOR, 0, 0, LR_SHARED); -HCURSOR arrowCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED); - -CViewClass::CViewClass() : classAtom(0) { - WNDCLASS wndClass; - wndClass.style = 0; - wndClass.lpfnWndProc = CViewProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = 0; - wndClass.hInstance = instance = GetModuleHandle(0); - wndClass.hIcon = (HICON)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 0, 0, LR_SHARED); - if (!wndClass.hIcon) - printf("unable to load icon:%ld", GetLastError()); - wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); - wndClass.hbrBackground = NULL; - wndClass.lpszMenuName = 0; - wndClass.lpszClassName = _T("rfb::win32::CViewClass"); - classAtom = RegisterClass(&wndClass); - if (!classAtom) { - throw rdr::SystemException("unable to register CView window class", GetLastError()); - } -} - -CViewClass::~CViewClass() { - if (classAtom) { - UnregisterClass((const TCHAR*)classAtom, instance); - } -} - -CViewClass baseClass; - -// -// -=- FrameClass - -// -// Window class used to display the rfb data -// - -class FrameClass { -public: - FrameClass(); - ~FrameClass(); - ATOM classAtom; - HINSTANCE instance; -}; - -LRESULT CALLBACK FrameProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - LRESULT result; - - if (msg == WM_CREATE) - SetWindowLong(hwnd, GWL_USERDATA, (long)((CREATESTRUCT*)lParam)->lpCreateParams); - else if (msg == WM_DESTROY) - SetWindowLong(hwnd, GWL_USERDATA, 0); - CView* _this = (CView*) GetWindowLong(hwnd, GWL_USERDATA); - if (!_this) { - vlog.info("null _this in %x, message %u", hwnd, msg); - return DefWindowProc(hwnd, msg, wParam, lParam); - } - - try { - result = _this->processFrameMessage(msg, wParam, lParam); - } catch (rdr::Exception& e) { - vlog.error("untrapped: %s", e.str()); - } - - return result; -} - -FrameClass::FrameClass() : classAtom(0) { - WNDCLASS wndClass; - wndClass.style = 0; - wndClass.lpfnWndProc = FrameProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = 0; - wndClass.hInstance = instance = GetModuleHandle(0); - wndClass.hIcon = 0; - wndClass.hCursor = NULL; - wndClass.hbrBackground = 0; - wndClass.lpszMenuName = 0; - wndClass.lpszClassName = _T("FrameClass"); - classAtom = RegisterClass(&wndClass); - if (!classAtom) { - throw rdr::SystemException("unable to register frame window class", - GetLastError()); - } -} - -FrameClass::~FrameClass() { - if (classAtom) { - UnregisterClass((const TCHAR*)classAtom, instance); - } -} - -FrameClass frameClass; - -// -// -=- CView instance implementation -// - -RegKey CView::userConfigKey; - - -CView::CView() - : quit_on_destroy(false), buffer(0), sock(0), readyToRead(false), - client_size(0, 0, 16, 16), window_size(0, 0, 32, 32), - cursorVisible(false), cursorAvailable(false), cursorInBuffer(false), - systemCursorVisible(true), trackingMouseLeave(false), - hwnd(0), frameHwnd(0), requestUpdate(false), has_focus(false), - palette_changed(false), sameMachine(false), encodingChange(false), - formatChange(false), lastUsedEncoding_(encodingRaw), fullScreenActive(false), - bumpScroll(false), manager(0), toolbar(true) { - - // Create the main window - const TCHAR* name = _T("VNC Viewer 4.0b"); - hwnd = CreateWindow((const TCHAR*)baseClass.classAtom, name, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, - 0, 0, 10, 10, 0, 0, baseClass.instance, this); - if (!hwnd) { - throw rdr::SystemException("unable to create WMNotifier window instance", GetLastError()); - } - vlog.debug("created window \"%s\" (%x)", (const char*)CStr(name), hwnd); - - // Create the viewer toolbar - tb.create(getHandle()); - vlog.debug("created toolbar window \"%s\" (%x)", "ViewerToolBar", tb.getHandle()); - - // Create the frame window - frameHwnd = CreateWindowEx(WS_EX_CLIENTEDGE, (const TCHAR*)frameClass.classAtom, - 0, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, getHandle(), 0, frameClass.instance, this); - if (!frameHwnd) { - throw rdr::SystemException("unable to create rfb frame window instance", GetLastError()); - } - vlog.debug("created window \"%s\" (%x)", "Frame Window", frameHwnd); - - // Initialise the CPointer pointer handler - ptr.setHWND(getFrameHandle()); - ptr.setIntervalTimerId(TIMER_POINTER_INTERVAL); - ptr.set3ButtonTimerId(TIMER_POINTER_3BUTTON); - - // Initialise the bumpscroll timer - bumpScrollTimer.setHWND(getHandle()); - bumpScrollTimer.setId(TIMER_BUMPSCROLL); - - // Grab AltTab - setAltTabGrab(options.sendSysKeys); - - // Hook the clipboard - clipboard.setNotifier(this); - - // Create the backing buffer - buffer = new win32::DIBSectionBuffer(getFrameHandle()); -} - -CView::~CView() { - vlog.debug("~CView"); - showSystemCursor(); - if (hwnd) { - setVisible(false); - DestroyWindow(hwnd); - hwnd = 0; - } - delete buffer; - vlog.debug("~CView done"); -} - -bool CView::initialise(network::Socket* s) { - // Update the window menu - HMENU wndmenu = GetSystemMenu(hwnd, FALSE); - AppendMenu(wndmenu, MF_SEPARATOR, 0, 0); - AppendMenu(wndmenu, MF_STRING, IDM_FULLSCREEN, _T("&Full screen")); - AppendMenu(wndmenu, (options.showToolbar ? MF_STRING | MF_CHECKED : MF_STRING), - IDM_SHOW_TOOLBAR, _T("Show tool&bar")); - AppendMenu(wndmenu, MF_SEPARATOR, 0, 0); - AppendMenu(wndmenu, MF_STRING, IDM_CTRL_KEY, _T("Ctr&l")); - AppendMenu(wndmenu, MF_STRING, IDM_ALT_KEY, _T("Al&t")); - AppendMenu(wndmenu, MF_STRING, IDM_SEND_CAD, _T("Send Ctrl-Alt-&Del")); - AppendMenu(wndmenu, MF_STRING, IDM_SEND_CTLESC, _T("Send Ctrl-&Esc")); - AppendMenu(wndmenu, MF_STRING, IDM_REQUEST_REFRESH, _T("Refres&h Screen")); - AppendMenu(wndmenu, MF_SEPARATOR, 0, 0); - if (manager) AppendMenu(wndmenu, MF_STRING, IDM_NEWCONN, _T("Ne&w Connection...")); - AppendMenu(wndmenu, MF_STRING, IDM_OPTIONS, _T("&Options...")); - AppendMenu(wndmenu, MF_STRING, IDM_INFO, _T("Connection &Info...")); - AppendMenu(wndmenu, MF_STRING, IDM_ABOUT, _T("&About...")); - - // Set the server's name for MRU purposes - CharArray endpoint(s->getPeerEndpoint()); - setServerName(endpoint.buf); - if (!options.host.buf) - options.setHost(endpoint.buf); - - // Initialise the underlying CConnection - setStreams(&s->inStream(), &s->outStream()); - - // Enable processing of window messages while blocked on I/O - s->inStream().setBlockCallback(this); - - // Initialise the viewer options - applyOptions(options); - - // - Set which auth schemes we support - addSecType(secTypeNone); - addSecType(secTypeVncAuth); - - initialiseProtocol(); - WSAAsyncSelect(s->getFd(), getHandle(), WM_USER, FD_READ | FD_CLOSE); - sock = s; - - m_fileTransfer.initialize(&s->inStream(), &s->outStream()); - - // Show toolbar if needed - toolbar = options.showToolbar; - if (options.showToolbar) tb.show(); - else tb.hide(); - - return true; -} - - -void -CView::applyOptions(CViewOptions& opt) { - // *** CHANGE THIS TO USE CViewOptions::operator= *** - - // - Take the username, password, config filename, and host spec - options.setUserName(opt.userName.buf); - options.setPassword(opt.password.buf); - options.setHost(opt.host.buf); - options.setConfigFileName(opt.configFileName.buf); - options.setMonitor(opt.monitor.buf); - - // - Set optional features in ConnParams - encodingChange |= ((options.useLocalCursor != opt.useLocalCursor) || - (options.useDesktopResize != opt.useDesktopResize)); - cp.supportsLocalCursor = options.useLocalCursor = opt.useLocalCursor; - cp.supportsDesktopResize = options.useDesktopResize = opt.useDesktopResize; - - encodingChange |= ((options.customCompressLevel != opt.customCompressLevel) || - (options.compressLevel != opt.compressLevel) || - (options.noJpeg != opt.noJpeg) || - (options.qualityLevel != opt.qualityLevel)); - cp.customCompressLevel = options.customCompressLevel = opt.customCompressLevel; - cp.compressLevel = options.compressLevel = opt.compressLevel; - cp.noJpeg = options.noJpeg = opt.noJpeg; - cp.qualityLevel = options.qualityLevel = opt.qualityLevel; - - if (cursorAvailable) - hideLocalCursor(); - cursorAvailable = cursorAvailable && options.useLocalCursor; - - // - Switch full-screen mode on/off - options.fullScreen = opt.fullScreen; - setFullscreen(options.fullScreen); - - // - Handle format/encoding options - encodingChange |= (options.preferredEncoding != opt.preferredEncoding); - options.preferredEncoding = opt.preferredEncoding; - - formatChange |= (options.fullColour != opt.fullColour); - options.fullColour = opt.fullColour; - - if (!options.fullColour) - formatChange |= (options.lowColourLevel != opt.lowColourLevel); - options.lowColourLevel = opt.lowColourLevel; - - options.autoSelect = opt.autoSelect; - - // - Sharing - options.shared = opt.shared; - setShared(options.shared); - - // - Inputs - options.sendPtrEvents = opt.sendPtrEvents; - options.sendKeyEvents = opt.sendKeyEvents; - options.sendSysKeys = opt.sendSysKeys; - setAltTabGrab(options.sendSysKeys); - options.clientCutText = opt.clientCutText; - options.serverCutText = opt.serverCutText; - options.emulate3 = opt.emulate3; - ptr.enableEmulate3(opt.emulate3); - options.pointerEventInterval = opt.pointerEventInterval; - ptr.enableInterval(opt.pointerEventInterval); - options.menuKey = opt.menuKey; - - // - Protocol version override - options.protocol3_3 = opt.protocol3_3; - setProtocol3_3(options.protocol3_3); - - // - Bell - options.acceptBell = opt.acceptBell; - - // - Show/hide toolbar - options.showToolbar = opt.showToolbar; -} - -void -CView::setFullscreen(bool fs) { - // Set the menu fullscreen option tick - CheckMenuItem(GetSystemMenu(getHandle(), FALSE), IDM_FULLSCREEN, - (options.fullScreen ? MF_CHECKED : 0) | MF_BYCOMMAND); - - // If the fullscreen mode is active then disable the menu point - // "Show toolbar", otherwise enable the menu point. - EnableMenuItem(GetSystemMenu(getHandle(), FALSE), IDM_SHOW_TOOLBAR, - (options.fullScreen ? MF_GRAYED : MF_ENABLED) | MF_BYCOMMAND); - - // If the window is not visible then we ignore the request. - // setVisible() will call us to correct the full-screen state when - // the window is visible, to keep things consistent. - if (!IsWindowVisible(getHandle())) - return; - - if (fs && !fullScreenActive) { - fullScreenActive = bumpScroll = true; - - // Un-minimize the window if required - if (GetWindowLong(getHandle(), GWL_STYLE) & WS_MINIMIZE) - ShowWindow(getHandle(), SW_RESTORE); - - // Save the non-fullscreen window position - RECT wrect; - GetWindowRect(getHandle(), &wrect); - fullScreenOldRect = Rect(wrect.left, wrect.top, wrect.right, wrect.bottom); - - // Find the size of the display the window is on - MonitorInfo mi(getHandle()); - - // Set the window full-screen - DWORD flags = GetWindowLong(getHandle(), GWL_STYLE); - fullScreenOldFlags = flags; - flags = flags & ~(WS_CAPTION | WS_THICKFRAME | WS_MAXIMIZE | WS_MINIMIZE); - vlog.debug("flags=%x", flags); - - if (toolbar) tb.hide(); - SetWindowLong(getFrameHandle(), GWL_EXSTYLE, 0); - SetWindowLong(getHandle(), GWL_STYLE, flags); - SetWindowPos(getHandle(), HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top, - mi.rcMonitor.right-mi.rcMonitor.left, - mi.rcMonitor.bottom-mi.rcMonitor.top, - SWP_FRAMECHANGED); - } else if (!fs && fullScreenActive) { - fullScreenActive = bumpScroll = false; - - // Set the window non-fullscreen - if (toolbar) tb.show(); - SetWindowLong(getFrameHandle(), GWL_EXSTYLE, WS_EX_CLIENTEDGE); - SetWindowLong(getHandle(), GWL_STYLE, fullScreenOldFlags); - SetWindowPos(getHandle(), HWND_NOTOPMOST, - fullScreenOldRect.tl.x, fullScreenOldRect.tl.y, - fullScreenOldRect.width(), fullScreenOldRect.height(), - SWP_FRAMECHANGED); - } - - // Adjust the viewport offset to cope with change in size between FS - // and previous window state. - setViewportOffset(scrolloffset); -} - - -bool CView::setViewportOffset(const Point& tl) { -/* *** - Point np = Point(max(0, min(maxscrolloffset.x, tl.x)), - max(0, min(maxscrolloffset.y, tl.y))); - */ - Point np = Point(max(0, min(tl.x, buffer->width()-client_size.width())), - max(0, min(tl.y, buffer->height()-client_size.height()))); - Point delta = np.translate(scrolloffset.negate()); - if (!np.equals(scrolloffset)) { - scrolloffset = np; - ScrollWindowEx(getFrameHandle(), -delta.x, -delta.y, 0, 0, 0, 0, SW_INVALIDATE); - UpdateWindow(getFrameHandle()); - return true; - } - return false; -} - - -bool CView::processBumpScroll(const Point& pos) -{ - if (!bumpScroll) return false; - int bumpScrollPixels = 20; - bumpScrollDelta = Point(); - - if (pos.x == client_size.width()-1) - bumpScrollDelta.x = bumpScrollPixels; - else if (pos.x == 0) - bumpScrollDelta.x = -bumpScrollPixels; - if (pos.y == client_size.height()-1) - bumpScrollDelta.y = bumpScrollPixels; - else if (pos.y == 0) - bumpScrollDelta.y = -bumpScrollPixels; - - if (bumpScrollDelta.x || bumpScrollDelta.y) { - if (bumpScrollTimer.isActive()) return true; - if (setViewportOffset(scrolloffset.translate(bumpScrollDelta))) { - bumpScrollTimer.start(25); - return true; - } - } - - bumpScrollTimer.stop(); - return false; -} - - -LRESULT -CView::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) { - switch (msg) { - - // -=- Process standard window messages - - case WM_NOTIFY: - if (wParam = (ID_TOOLBAR)) tb.processWM_NOTIFY(wParam, lParam); - break; - - case WM_DISPLAYCHANGE: - // Display has changed - use new pixel format - calculateFullColourPF(); - break; - - // -=- Window position - - // Prevent the window from being resized to be too large if in normal mode. - // If maximized or fullscreen the allow oversized windows. - - case WM_WINDOWPOSCHANGING: - { - WINDOWPOS* wpos = (WINDOWPOS*)lParam; - if (wpos->flags & SWP_NOSIZE) - break; - - // Work out how big the window should ideally be - DWORD frame_current_style = GetWindowLong(getFrameHandle(), GWL_STYLE); - DWORD frame_style = frame_current_style & ~(WS_VSCROLL | WS_HSCROLL); - DWORD frame_ex_style = GetWindowLong(getFrameHandle(), GWL_EXSTYLE); - - RECT r; - SetRect(&r, 0, 0, buffer->width(), buffer->height()); - AdjustWindowRectEx(&r, frame_style, FALSE, frame_ex_style); - Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom); - if (frame_current_style & WS_VSCROLL) - reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL); - if (frame_current_style & WS_HSCROLL) - reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL); - r.left = reqd_size.tl.x; r.right = reqd_size.br.x; - r.top = reqd_size.tl.y; r.bottom = reqd_size.br.y; - if (tb.isVisible()) r.bottom += tb.getHeight(); - AdjustWindowRect(&r, GetWindowLong(getHandle(), GWL_STYLE), FALSE); - reqd_size = Rect(r.left, r.top, r.right, r.bottom); - RECT current; - GetWindowRect(getHandle(), ¤t); - - // Ensure that the window isn't resized too large - // If the window is maximized or full-screen then any size is allowed - if (!(GetWindowLong(getHandle(), GWL_STYLE) & WS_MAXIMIZE) && !fullScreenActive) { - if (wpos->cx > reqd_size.width()) { - wpos->cx = reqd_size.width(); - wpos->x = current.left; - } - if (wpos->cy > reqd_size.height()) { - wpos->cy = reqd_size.height(); - wpos->y = current.top; - } - } - - } - break; - - // Resize child windows and update window size info we have cached. - - case WM_SIZE: - { - Point old_offset = bufferToClient(Point(0, 0)); - - // Resize the child windows - RECT r; - GetClientRect(getHandle(), &r); - if (tb.isVisible()) { - MoveWindow(getFrameHandle(), 0, tb.getHeight(), r.right, - r.bottom - tb.getHeight(), TRUE); - } else { - MoveWindow(getFrameHandle(), 0, 0, r.right, r.bottom, TRUE); - } - tb.autoSize(); - - // Update the cached sizing information - GetWindowRect(getFrameHandle(), &r); - window_size = Rect(r.left, r.top, r.right, r.bottom); - GetClientRect(getFrameHandle(), &r); - client_size = Rect(r.left, r.top, r.right, r.bottom); - - // Determine whether scrollbars are required - calculateScrollBars(); - - // Redraw if required - if (!old_offset.equals(bufferToClient(Point(0, 0)))) - InvalidateRect(getFrameHandle(), 0, TRUE); - } - break; - - // -=- Bump-scrolling - - case WM_TIMER: - switch (wParam) { - case TIMER_BUMPSCROLL: - if (!setViewportOffset(scrolloffset.translate(bumpScrollDelta))) - bumpScrollTimer.stop(); - break; - case TIMER_POINTER_INTERVAL: - case TIMER_POINTER_3BUTTON: - try { - ptr.handleTimer(writer(), wParam); - } catch (rdr::Exception& e) { - close(e.str()); - } - break; - } - break; - - // -=- Track whether or not the window has focus - - case WM_SETFOCUS: - has_focus = true; - // Re-register AltTab hotkey - setAltTabGrab(options.sendSysKeys); - break; - case WM_KILLFOCUS: - has_focus = false; - cursorOutsideBuffer(); - // Unregister AltTab hotkey - setAltTabGrab(false); - // Restore the remote keys to consistent states - try { - kbd.releaseAllKeys(writer()); - } catch (rdr::Exception& e) { - close(e.str()); - } - break; - - // -=- Handle the extra window menu items - - // Process the items added to the system menu - case WM_SYSCOMMAND: - - // - First check whether it's one of our messages - switch (wParam) { - case IDM_FULLSCREEN: - options.fullScreen = !options.fullScreen; - setFullscreen(options.fullScreen); - return 0; - case IDM_SHOW_TOOLBAR: - toolbar = !toolbar; - CheckMenuItem(GetSystemMenu(getHandle(), FALSE), IDM_SHOW_TOOLBAR, - (toolbar ? MF_CHECKED : MF_UNCHECKED) | MF_BYCOMMAND); - if (toolbar) tb.show(); - else tb.hide(); - return 0; - case IDM_CTRL_KEY: - writeKeyEvent(VK_CONTROL, 0, !kbd.keyPressed(VK_CONTROL)); - return 0; - case IDM_ALT_KEY: - writeKeyEvent(VK_MENU, 0, !kbd.keyPressed(VK_MENU)); - return 0; - case IDM_SEND_MENU_KEY: - writeKeyEvent(options.menuKey, 0, true); - writeKeyEvent(options.menuKey, 0, false); - return 0; - case IDM_SEND_CAD: - writeKeyEvent(VK_CONTROL, 0, true); - writeKeyEvent(VK_MENU, 0, true); - writeKeyEvent(VK_DELETE, 0, true); - writeKeyEvent(VK_DELETE, 0, false); - writeKeyEvent(VK_MENU, 0, false); - writeKeyEvent(VK_CONTROL, 0, false); - return 0; - case IDM_SEND_CTLESC: - writeKeyEvent(VK_CONTROL, 0, true); - writeKeyEvent(VK_ESCAPE, 0, true); - writeKeyEvent(VK_CONTROL, 0, false); - writeKeyEvent(VK_ESCAPE, 0, false); - return 0; - case IDM_REQUEST_REFRESH: - try { - writer()->writeFramebufferUpdateRequest(Rect(0,0,cp.width,cp.height), false); - requestUpdate = false; - } catch (rdr::Exception& e) { - close(e.str()); - } - return 0; - case IDM_NEWCONN: - manager->addClient(0); - return 0; - case IDM_OPTIONS: - // Update the monitor device name in the CViewOptions instance - { - MonitorInfo mi(getHandle()); - options.setMonitor(mi.szDevice); - optionsDialog.showDialog(this); - return 0; - } - case IDM_INFO: - infoDialog.showDialog(this); - return 0; - case IDM_ABOUT: - AboutDialog::instance.showDialog(); - return 0; - case IDM_FILE_TRANSFER: - m_fileTransfer.show(getHandle()); - return 0; - case IDM_CONN_SAVE_AS: - return 0; - case ID_CLOSE: - PostQuitMessage(0); - return 0; - }; - - // - Not one of our messages, so process it as a system message - switch (wParam & 0xfff0) { - - // When restored, ensure that full-screen mode is re-enabled if required. - case SC_RESTORE: - rfb::win32::SafeDefWindowProc(getHandle(), msg, wParam, lParam); - setFullscreen(options.fullScreen); - return 0; - - // If we are maximized or minimized then that cancels full-screen mode. - case SC_MINIMIZE: - case SC_MAXIMIZE: - setFullscreen(false); - break; - - // If the system menu is shown then make sure it's up to date - case SC_KEYMENU: - case SC_MOUSEMENU: - updateF8Menu(false); - break; - - }; - break; - - // Treat all menu commands as system menu commands - case WM_COMMAND: - SendMessage(getHandle(), WM_SYSCOMMAND, wParam, lParam); - return 0; - - case WM_MENUCHAR: - vlog.debug("menuchar"); - break; - - // -=- Handle keyboard input - - case WM_HOTKEY: - if (wParam == HOTKEY_ALTTAB) { - writeKeyEvent(VK_TAB, 0, true); - writeKeyEvent(VK_TAB, 0, false); - return 0; - } - break; - - case WM_SYSKEYDOWN: - // Translate Alt-Space and Alt-F4 to WM_SYSCHAR and WM_CLOSE, - // since we are not using TranslateMessage(). - if (!options.sendSysKeys) { - switch (wParam) { - case VK_SPACE: - writeKeyEvent(VK_MENU, 0, false); - SendMessage(getHandle(), WM_SYSCHAR, wParam, lParam); - return 0; - case VK_F4: - SendMessage(getHandle(), WM_CLOSE, wParam, lParam); - return 0; - } - } - - case WM_SYSKEYUP: - // When we have registered for AltTab as a hotkey, SYSKEYUPs for - // Tabs are sent (but no SYSKEYDOWNs). AltTab is handled by - // WM_HOTKEY, though. - if (wParam == VK_TAB) return 0; - - case WM_KEYUP: - case WM_KEYDOWN: - // Hook the MenuKey to pop-up the window menu - if (options.menuKey && (wParam == options.menuKey)) { - - bool ctrlDown = (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0; - bool altDown = (GetAsyncKeyState(VK_MENU) & 0x8000) != 0; - bool shiftDown = (GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0; - if (!(ctrlDown || altDown || shiftDown)) { - - // If MenuKey is being released then pop-up the menu - if ((msg == WM_KEYDOWN)) { - // Make sure it's up to date - updateF8Menu(true); - - // Show it under the pointer - POINT pt; - GetCursorPos(&pt); - cursorInBuffer = false; - TrackPopupMenu(GetSystemMenu(getHandle(), FALSE), - TPM_CENTERALIGN | TPM_VCENTERALIGN, pt.x, pt.y, 0, getHandle(), 0); - } - - // Ignore the MenuKey keypress for both press & release events - return 0; - } - } - - writeKeyEvent(wParam, lParam, (msg == WM_KEYDOWN) || (msg == WM_SYSKEYDOWN)); - return 0; - - // -=- Handle the window closing - - case WM_CLOSE: - vlog.debug("WM_CLOSE %x", getHandle()); - if (quit_on_destroy) { - vlog.debug("posting WM_QUIT"); - PostQuitMessage(0); - } else { - vlog.debug("not posting WM_QUIT"); - } - break; - - // -=- Process incoming socket data - - case WM_USER: - readyToRead = true; - break; - - } - - return rfb::win32::SafeDefWindowProc(getHandle(), msg, wParam, lParam); -} - -LRESULT CView::processFrameMessage(UINT msg, WPARAM wParam, LPARAM lParam) { - switch (msg) { - - // -=- Palette management - - case WM_PALETTECHANGED: - vlog.debug("WM_PALETTECHANGED"); - if ((HWND)wParam == getFrameHandle()) { - vlog.debug("ignoring"); - break; - } - case WM_QUERYNEWPALETTE: - vlog.debug("re-selecting palette"); - { - WindowDC wdc(getFrameHandle()); - PaletteSelector pSel(wdc, windowPalette.getHandle()); - if (pSel.isRedrawRequired()) { - InvalidateRect(getFrameHandle(), 0, FALSE); - UpdateWindow(getFrameHandle()); - } - } - return TRUE; - - // Paint the remote frame buffer - - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC paintDC = BeginPaint(getFrameHandle(), &ps); - if (!paintDC) - throw SystemException("unable to BeginPaint", GetLastError()); - Rect pr = Rect(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom); - - if (!pr.is_empty()) { - - // Draw using the correct palette - PaletteSelector pSel(paintDC, windowPalette.getHandle()); - - if (buffer->bitmap) { - // Update the bitmap's palette - if (palette_changed) { - palette_changed = false; - buffer->refreshPalette(); - } - - // Get device context - BitmapDC bitmapDC(paintDC, buffer->bitmap); - - // Blit the border if required - Rect bufpos = bufferToClient(buffer->getRect()); - if (!pr.enclosed_by(bufpos)) { - vlog.debug("draw border"); - HBRUSH black = (HBRUSH) GetStockObject(BLACK_BRUSH); - RECT r; - SetRect(&r, 0, 0, bufpos.tl.x, client_size.height()); FillRect(paintDC, &r, black); - SetRect(&r, bufpos.tl.x, 0, bufpos.br.x, bufpos.tl.y); FillRect(paintDC, &r, black); - SetRect(&r, bufpos.br.x, 0, client_size.width(), client_size.height()); FillRect(paintDC, &r, black); - SetRect(&r, bufpos.tl.x, bufpos.br.y, bufpos.br.x, client_size.height()); FillRect(paintDC, &r, black); - } - - // Do the blit - Point buf_pos = clientToBuffer(pr.tl); - if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(), - bitmapDC, buf_pos.x, buf_pos.y, SRCCOPY)) - throw SystemException("unable to BitBlt to window", GetLastError()); - - } else { - // Blit a load of black - if (!BitBlt(paintDC, pr.tl.x, pr.tl.y, pr.width(), pr.height(), - 0, 0, 0, BLACKNESS)) - throw SystemException("unable to BitBlt to blank window", GetLastError()); - } - } - - EndPaint(getFrameHandle(), &ps); - - // - Request the next update from the server, if required - requestNewUpdate(); - } - return 0; - - // Process the frame scroll messages - - case WM_VSCROLL: - case WM_HSCROLL: - { - Point delta; - int newpos = (msg == WM_VSCROLL) ? scrolloffset.y : scrolloffset.x; - - switch (LOWORD(wParam)) { - case SB_PAGEUP: newpos -= 50; break; - case SB_PAGEDOWN: newpos += 50; break; - case SB_LINEUP: newpos -= 5; break; - case SB_LINEDOWN: newpos += 5; break; - case SB_THUMBTRACK: - case SB_THUMBPOSITION: newpos = HIWORD(wParam); break; - default: vlog.info("received unknown scroll message"); - }; - - if (msg == WM_HSCROLL) - setViewportOffset(Point(newpos, scrolloffset.y)); - else - setViewportOffset(Point(scrolloffset.x, newpos)); - - SCROLLINFO si; - si.cbSize = sizeof(si); - si.fMask = SIF_POS; - si.nPos = newpos; - SetScrollInfo(getFrameHandle(), (msg == WM_VSCROLL) ? SB_VERT : SB_HORZ, &si, TRUE); - } - break; - - // -=- Cursor shape/visibility handling - - case WM_SETCURSOR: - if (LOWORD(lParam) != HTCLIENT) - break; - SetCursor(cursorInBuffer ? dotCursor : arrowCursor); - return TRUE; - - case WM_MOUSELEAVE: - trackingMouseLeave = false; - cursorOutsideBuffer(); - return 0; - - // -=- Mouse input handling - - case WM_MOUSEMOVE: - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_MOUSEWHEEL: - if (has_focus) - { - if (!trackingMouseLeave) { - TRACKMOUSEEVENT tme; - tme.cbSize = sizeof(TRACKMOUSEEVENT); - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = getFrameHandle(); - _TrackMouseEvent(&tme); - trackingMouseLeave = true; - } - int mask = 0; - if (LOWORD(wParam) & MK_LBUTTON) mask |= 1; - if (LOWORD(wParam) & MK_MBUTTON) mask |= 2; - if (LOWORD(wParam) & MK_RBUTTON) mask |= 4; - - if (msg == WM_MOUSEWHEEL) { - int delta = (short)HIWORD(wParam); - int repeats = (abs(delta)+119) / 120; - int wheelMask = (delta > 0) ? 8 : 16; - vlog.debug("repeats %d, mask %d\n",repeats,wheelMask); - for (int i=0; i<repeats; i++) { - writePointerEvent(oldpos.x, oldpos.y, mask | wheelMask); - writePointerEvent(oldpos.x, oldpos.y, mask); - } - } else { - Point clientPos = Point(LOWORD(lParam), HIWORD(lParam)); - Point p = clientToBuffer(clientPos); - - // If the mouse is not within the server buffer area, do nothing - cursorInBuffer = buffer->getRect().contains(p); - if (!cursorInBuffer) { - cursorOutsideBuffer(); - break; - } - - // If we're locally rendering the cursor then redraw it - if (cursorAvailable) { - // - Render the cursor! - if (!p.equals(cursorPos)) { - hideLocalCursor(); - cursorPos = p; - showLocalCursor(); - if (cursorVisible) - hideSystemCursor(); - } - } - - // If we are doing bump-scrolling then try that first... - if (processBumpScroll(clientPos)) - break; - - // Send a pointer event to the server - writePointerEvent(p.x, p.y, mask); - oldpos = p; - } - } else { - cursorOutsideBuffer(); - } - break; - } - - return rfb::win32::SafeDefWindowProc(getFrameHandle(), msg, wParam, lParam); -} - -void CView::blockCallback() { - // - An InStream has blocked on I/O while processing an RFB message - // We re-enable socket event notifications, so we'll know when more - // data is available, then we sit and dispatch window events until - // the notification arrives. - readyToRead = false; - WSAAsyncSelect(sock->getFd(), getHandle(), WM_USER, FD_READ | FD_CLOSE); - MSG msg; - while (true) { - if (readyToRead) { - // - Network event notification. Return control to I/O routine. - WSAAsyncSelect(sock->getFd(), getHandle(), WM_USER, 0); - return; - } - - DWORD result = GetMessage(&msg, NULL, 0, 0); - if (result == 0) { - vlog.debug("WM_QUIT"); - throw QuitMessage(msg.wParam); - } else if (result < 0) { - throw rdr::SystemException("GetMessage error", GetLastError()); - } - - // IMPORTANT: We mustn't call TranslateMessage() here, because instead we - // call ToAscii() in CKeyboard::keyEvent(). ToAscii() stores dead key - // state from one call to the next, which would be messed up by calls to - // TranslateMessage() (actually it looks like TranslateMessage() calls - // ToAscii() internally). - DispatchMessage(&msg); - } -} - - -void -CView::hideLocalCursor() { - // - Blit the cursor backing store over the cursor - // *** ALWAYS call this BEFORE changing buffer PF!!! - if (cursorVisible) { - cursorVisible = false; - buffer->imageRect(cursorBackingRect, cursorBacking.data); - invalidateBufferRect(cursorBackingRect); - } -} - -void -CView::showLocalCursor() { - if (cursorAvailable && !cursorVisible && cursorInBuffer) { - if (!cp.pf().equal(cursor.getPF()) || - cursor.getRect().is_empty()) { - vlog.info("attempting to render invalid local cursor"); - cursorAvailable = false; - showSystemCursor(); - return; - } - cursorVisible = true; - - cursorBackingRect = cursor.getRect().translate(cursorPos).translate(cursor.hotspot.negate()); - cursorBackingRect = cursorBackingRect.intersect(buffer->getRect()); - buffer->getImage(cursorBacking.data, cursorBackingRect); - - renderLocalCursor(); - - invalidateBufferRect(cursorBackingRect); - } -} - -void CView::cursorOutsideBuffer() -{ - cursorInBuffer = false; - hideLocalCursor(); - showSystemCursor(); -} - -void -CView::renderLocalCursor() -{ - Rect r = cursor.getRect(); - r = r.translate(cursorPos).translate(cursor.hotspot.negate()); - buffer->maskRect(r, cursor.data, cursor.mask.buf); -} - -void -CView::hideSystemCursor() { - if (systemCursorVisible) { - vlog.debug("hide system cursor"); - systemCursorVisible = false; - ShowCursor(FALSE); - } -} - -void -CView::showSystemCursor() { - if (!systemCursorVisible) { - vlog.debug("show system cursor"); - systemCursorVisible = true; - ShowCursor(TRUE); - } -} - -void -CView::setAltTabGrab(bool grab) { - BOOL hotKeyResult; - static bool grabstate = false; - - // Do not call RegisterHotKey/UnregisterHotKey if not necessary - if (grabstate == grab) - return; - - grabstate = grab; - - // Only works for NT/2k/XP - if (grab) { - hotKeyResult = RegisterHotKey(hwnd, HOTKEY_ALTTAB, MOD_ALT, VK_TAB); - if (!hotKeyResult) - vlog.debug("RegisterHotkey failed with error %d", GetLastError()); - } else { - hotKeyResult = UnregisterHotKey(hwnd, HOTKEY_ALTTAB); - } -} - -bool -CView::invalidateBufferRect(const Rect& crect) { - Rect rect = bufferToClient(crect); - if (rect.intersect(client_size).is_empty()) return false; - RECT invalid = {rect.tl.x, rect.tl.y, rect.br.x, rect.br.y}; - InvalidateRect(getFrameHandle(), &invalid, FALSE); - return true; -} - - -void -CView::notifyClipboardChanged(const char* text, int len) { - if (!options.clientCutText) return; - if (state() != RFBSTATE_NORMAL) return; - try { - writer()->writeClientCutText(text, len); - } catch (rdr::Exception& e) { - close(e.str()); - } -} - - -CSecurity* CView::getCSecurity(int secType) -{ - switch (secType) { - case secTypeNone: - return new CSecurityNone(); - case secTypeVncAuth: - return new CSecurityVncAuth(this); - default: - throw Exception("Unsupported secType?"); - } -} - - -void -CView::setColourMapEntries(int first, int count, U16* rgbs) { - vlog.debug("setColourMapEntries: first=%d, count=%d", first, count); - int i; - for (i=0;i<count;i++) { - buffer->setColour(i+first, rgbs[i*3], rgbs[i*3+1], rgbs[i*3+2]); - } - // *** change to 0, 256? - refreshWindowPalette(first, count); - palette_changed = true; - InvalidateRect(getHandle(), 0, FALSE); -} - -void -CView::bell() { - if (options.acceptBell) - MessageBeep(-1); -} - - -void -CView::setDesktopSize(int w, int h) { - vlog.debug("setDesktopSize %dx%d", w, h); - - // If the locally-rendered cursor is visible then remove it - hideLocalCursor(); - - // Resize the backing buffer - buffer->setSize(w, h); - - // If the window is not maximised or full-screen then resize it - if (!(GetWindowLong(getHandle(), GWL_STYLE) & WS_MAXIMIZE) && !fullScreenActive) { - // Resize the window to the required size - RECT r = {0, 0, w, h}; - AdjustWindowRectEx(&r, GetWindowLong(getFrameHandle(), GWL_STYLE), FALSE, - GetWindowLong(getFrameHandle(), GWL_EXSTYLE)); - if (tb.isVisible()) r.bottom += tb.getHeight(); - AdjustWindowRect(&r, GetWindowLong(getHandle(), GWL_STYLE), FALSE); - SetWindowPos(getHandle(), 0, 0, 0, r.right-r.left, r.bottom-r.top, - SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER); - - // Move the window to the desired monitor - if (options.monitor.buf) - moveToMonitor(getHandle(), options.monitor.buf); - - // Clip to the system work area - centerWindow(getHandle(), 0, true); - } else { - // Ensure the screen contents are consistent - InvalidateRect(getFrameHandle(), 0, FALSE); - } - - // Tell the underlying CConnection - CConnection::setDesktopSize(w, h); - - // Enable/disable scrollbars as appropriate - calculateScrollBars(); -} - -void -CView::setCursor(const Point& hotspot, const Point& size, void* data, void* mask) { - if (!options.useLocalCursor) return; - hideLocalCursor(); - - cursor.hotspot = hotspot; - - cursor.setSize(size.x, size.y); - cursor.setPF(cp.pf()); - cursor.imageRect(cursor.getRect(), data); - memcpy(cursor.mask.buf, mask, cursor.maskLen()); - cursor.crop(); - - cursorBacking.setSize(size.x, size.y); - cursorBacking.setPF(cp.pf()); - - cursorAvailable = true; - - showLocalCursor(); -} - -PixelFormat -CView::getNativePF() const { - vlog.debug("getNativePF()"); - return WindowDC(getHandle()).getPF(); -} - -void -CView::setVisible(bool visible) { - ShowWindow(getHandle(), visible ? SW_SHOW : SW_HIDE); - if (visible) { - // When the window becomes visible, make it active - SetForegroundWindow(getHandle()); - SetActiveWindow(getHandle()); - // If the window should be full-screen, then do so - setFullscreen(options.fullScreen); - } else { - // Disable full-screen mode - setFullscreen(false); - } -} - -void -CView::close(const char* reason) { - setVisible(false); - if (reason) { - vlog.info("closing - %s", reason); - MsgBox(NULL, TStr(reason), MB_ICONINFORMATION | MB_OK); - } - SendMessage(getHandle(), WM_CLOSE, 0, 0); -} - - -void -CView::framebufferUpdateEnd() { - if (debugDelay != 0) { - vlog.debug("debug delay %d",(int)debugDelay); - UpdateWindow(getHandle()); - Sleep(debugDelay); - std::list<rfb::Rect>::iterator i; - for (i = debugRects.begin(); i != debugRects.end(); i++) { - invertRect(*i); - } - debugRects.clear(); - } - if (options.autoSelect) - autoSelectFormatAndEncoding(); - - // Always request the next update - requestUpdate = true; - - // Check that at least part of the window has changed - if (!GetUpdateRect(getHandle(), 0, FALSE)) { - if (!(GetWindowLong(getHandle(), GWL_STYLE) & WS_MINIMIZE)) - requestNewUpdate(); - } - - showLocalCursor(); -} - - -// Note: The method below is duplicated in vncviewer_unix/CConn.cxx! - -// autoSelectFormatAndEncoding() chooses the format and encoding appropriate -// to the connection speed: -// -// Above 16Mbps (timing for at least a second), switch to hextile -// Otherwise, switch to ZRLE -// -// Above 256Kbps, use full colour mode -// -void -CView::autoSelectFormatAndEncoding() { - int kbitsPerSecond = sock->inStream().kbitsPerSecond(); - unsigned int newEncoding = options.preferredEncoding; - bool newFullColour = options.fullColour; - unsigned int timeWaited = sock->inStream().timeWaited(); - - // Select best encoding - if (kbitsPerSecond > 16000 && timeWaited >= 10000) { - newEncoding = encodingHextile; - } else { - newEncoding = encodingZRLE; - } - - if (newEncoding != options.preferredEncoding) { - vlog.info("Throughput %d kbit/s - changing to %s encoding", - kbitsPerSecond, encodingName(newEncoding)); - options.preferredEncoding = newEncoding; - encodingChange = true; - } - - if (kbitsPerSecond == 0) { - return; - } - - if (cp.beforeVersion(3, 8)) { - // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with - // cursors "asynchronously". If this happens in the middle of a - // pixel format change, the server will encode the cursor with - // the old format, but the client will try to decode it - // according to the new format. This will lead to a - // crash. Therefore, we do not allow automatic format change for - // old servers. - return; - } - - // Select best color level - newFullColour = (kbitsPerSecond > 256); - if (newFullColour != options.fullColour) { - vlog.info("Throughput %d kbit/s - full color is now %s", - kbitsPerSecond, - newFullColour ? "enabled" : "disabled"); - options.fullColour = newFullColour; - formatChange = true; - } -} - -void -CView::requestNewUpdate() { - if (!requestUpdate) return; - - if (formatChange) { - // Hide the rendered cursor, if any, to prevent - // the backing buffer being used in the wrong format - hideLocalCursor(); - - // Select the required pixel format - if (options.fullColour) { - buffer->setPF(fullColourPF); - } else { - switch (options.lowColourLevel) { - case 0: - buffer->setPF(PixelFormat(8,3,0,1,1,1,1,2,1,0)); - break; - case 1: - buffer->setPF(PixelFormat(8,6,0,1,3,3,3,4,2,0)); - break; - case 2: - buffer->setPF(PixelFormat(8,8,0,0,0,0,0,0,0,0)); - break; - } - } - - // Print the current pixel format - char str[256]; - buffer->getPF().print(str, 256); - vlog.info("Using pixel format %s",str); - - // Save the connection pixel format and tell server to use it - cp.setPF(buffer->getPF()); - writer()->writeSetPixelFormat(cp.pf()); - - // Correct the local window's palette - if (!getNativePF().trueColour) - refreshWindowPalette(0, 1 << cp.pf().depth); - } - - if (encodingChange) { - vlog.info("Using %s encoding",encodingName(options.preferredEncoding)); - writer()->writeSetEncodings(options.preferredEncoding, true); - } - - writer()->writeFramebufferUpdateRequest(Rect(0, 0, cp.width, cp.height), - !formatChange); - - encodingChange = formatChange = requestUpdate = false; -} - - -void -CView::writeKeyEvent(rdr::U8 vkey, rdr::U32 flags, bool down) { - if (!options.sendKeyEvents) return; - try { - kbd.keyEvent(writer(), vkey, flags, down); - } catch (rdr::Exception& e) { - close(e.str()); - } -} - -void -CView::writePointerEvent(int x, int y, int buttonMask) { - if (!options.sendPtrEvents) return; - try { - ptr.pointerEvent(writer(), x, y, buttonMask); - } catch (rdr::Exception& e) { - close(e.str()); - } -} - - -void -CView::refreshWindowPalette(int start, int count) { - vlog.debug("refreshWindowPalette(%d, %d)", start, count); - - Colour colours[256]; - if (count > 256) { - vlog.debug("%d palette entries", count); - throw rdr::Exception("too many palette entries"); - } - - // Copy the palette from the DIBSectionBuffer - ColourMap* cm = buffer->getColourMap(); - if (!cm) return; - for (int i=0; i<count; i++) { - int r, g, b; - cm->lookup(i, &r, &g, &b); - colours[i].r = r; - colours[i].g = g; - colours[i].b = b; - } - - // Set the window palette - windowPalette.setEntries(start, count, colours); - - // Cause the window to be redrawn - InvalidateRect(getHandle(), 0, 0); -} - - -void CView::calculateScrollBars() { - // Calculate the required size of window - DWORD current_style = GetWindowLong(getFrameHandle(), GWL_STYLE); - DWORD style = current_style & ~(WS_VSCROLL | WS_HSCROLL); - DWORD ex_style = GetWindowLong(getFrameHandle(), GWL_EXSTYLE); - DWORD old_style; - RECT r; - SetRect(&r, 0, 0, buffer->width(), buffer->height()); - AdjustWindowRectEx(&r, style, FALSE, ex_style); - Rect reqd_size = Rect(r.left, r.top, r.right, r.bottom); - - if (!bumpScroll) { - // We only enable scrollbars if bump-scrolling is not active. - // Effectively, this means if full-screen is not active, - // but I think it's better to make these things explicit. - // Work out whether scroll bars are required - do { - old_style = style; - - if (!(style & WS_HSCROLL) && (reqd_size.width() > window_size.width())) { - style |= WS_HSCROLL; - reqd_size.br.y += GetSystemMetrics(SM_CXHSCROLL); - } - if (!(style & WS_VSCROLL) && (reqd_size.height() > window_size.height())) { - style |= WS_VSCROLL; - reqd_size.br.x += GetSystemMetrics(SM_CXVSCROLL); - } - } while (style != old_style); - } - - // Tell Windows to update the window style & cached settings - if (style != current_style) { - SetWindowLong(getFrameHandle(), GWL_STYLE, style); - SetWindowPos(getFrameHandle(), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - } - - // Update the scroll settings - SCROLLINFO si; - if (style & WS_VSCROLL) { - si.cbSize = sizeof(si); - si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; - si.nMin = 0; - si.nMax = buffer->height(); - si.nPage = buffer->height() - (reqd_size.height() - window_size.height()); - maxscrolloffset.y = max(0, si.nMax-si.nPage); - scrolloffset.y = min(maxscrolloffset.y, scrolloffset.y); - si.nPos = scrolloffset.y; - SetScrollInfo(getFrameHandle(), SB_VERT, &si, TRUE); - } - if (style & WS_HSCROLL) { - si.cbSize = sizeof(si); - si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; - si.nMin = 0; - si.nMax = buffer->width(); - si.nPage = buffer->width() - (reqd_size.width() - window_size.width()); - maxscrolloffset.x = max(0, si.nMax-si.nPage); - scrolloffset.x = min(maxscrolloffset.x, scrolloffset.x); - si.nPos = scrolloffset.x; - SetScrollInfo(getFrameHandle(), SB_HORZ, &si, TRUE); - } - - // Update the cached client size - GetClientRect(getFrameHandle(), &r); - client_size = Rect(r.left, r.top, r.right, r.bottom); -} - - -void -CView::calculateFullColourPF() { - // If the server is palette based then use palette locally - // Also, don't bother doing bgr222 - if (!serverDefaultPF.trueColour || (serverDefaultPF.depth < 6)) { - fullColourPF = serverDefaultPF; - options.fullColour = true; - } else { - // If server is trueColour, use lowest depth PF - PixelFormat native = getNativePF(); - if ((serverDefaultPF.bpp < native.bpp) || - ((serverDefaultPF.bpp == native.bpp) && - (serverDefaultPF.depth < native.depth))) - fullColourPF = serverDefaultPF; - else - fullColourPF = getNativePF(); - } - formatChange = true; -} - - -void -CView::updateF8Menu(bool hideSystemCommands) { - HMENU menu = GetSystemMenu(getHandle(), FALSE); - - if (hideSystemCommands) { - // Gray out menu items that might cause a World Of Pain - HMENU menu = GetSystemMenu(getHandle(), FALSE); - EnableMenuItem(menu, SC_SIZE, MF_BYCOMMAND | MF_GRAYED); - EnableMenuItem(menu, SC_MOVE, MF_BYCOMMAND | MF_GRAYED); - EnableMenuItem(menu, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED); - EnableMenuItem(menu, SC_MINIMIZE, MF_BYCOMMAND | MF_ENABLED); - EnableMenuItem(menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_ENABLED); - } - - // Update the modifier key menu items - UINT ctrlCheckFlags = kbd.keyPressed(VK_CONTROL) ? MF_CHECKED : MF_UNCHECKED; - UINT altCheckFlags = kbd.keyPressed(VK_MENU) ? MF_CHECKED : MF_UNCHECKED; - CheckMenuItem(menu, IDM_CTRL_KEY, MF_BYCOMMAND | ctrlCheckFlags); - CheckMenuItem(menu, IDM_ALT_KEY, MF_BYCOMMAND | altCheckFlags); - - // Ensure that the Send <MenuKey> menu item has the correct text - if (options.menuKey) { - TCharArray menuKeyStr(options.menuKeyName()); - TCharArray tmp(_tcslen(menuKeyStr.buf) + 6); - _stprintf(tmp.buf, _T("Send %s"), menuKeyStr.buf); - if (!ModifyMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf)) - InsertMenu(menu, IDM_SEND_CAD, MF_BYCOMMAND | MF_STRING, IDM_SEND_MENU_KEY, tmp.buf); - } else { - RemoveMenu(menu, IDM_SEND_MENU_KEY, MF_BYCOMMAND); - } -} - - -void -CView::setName(const char* name) { - vlog.debug("setName %s", name); - ::SetWindowText(getHandle(), TStr(name)); - CConnection::setName(name); -} - - -void CView::serverInit() { - CConnection::serverInit(); - - // If using AutoSelect with old servers, start in FullColor - // mode. See comment in autoSelectFormatAndEncoding. - if (cp.beforeVersion(3, 8) && options.autoSelect) { - options.fullColour = true; - } - - // Save the server's current format - serverDefaultPF = cp.pf(); - - // Calculate the full-colour format to use - calculateFullColourPF(); - - // Request the initial update - vlog.info("requesting initial update"); - formatChange = encodingChange = requestUpdate = true; - requestNewUpdate(); - - // Show the window - setVisible(true); -} - -void -CView::serverCutText(const char* str, int len) { - if (!options.serverCutText) return; - CharArray t(len+1); - memcpy(t.buf, str, len); - t.buf[len] = 0; - clipboard.setClipText(t.buf); -} - - -void CView::beginRect(const Rect& r, unsigned int encoding) { - sock->inStream().startTiming(); -} - -void CView::endRect(const Rect& r, unsigned int encoding) { - sock->inStream().stopTiming(); - lastUsedEncoding_ = encoding; - if (debugDelay != 0) { - invertRect(r); - debugRects.push_back(r); - } -} - -void CView::fillRect(const Rect& r, Pixel pix) { - if (cursorBackingRect.overlaps(r)) hideLocalCursor(); - buffer->fillRect(r, pix); - invalidateBufferRect(r); -} -void CView::imageRect(const Rect& r, void* pixels) { - if (cursorBackingRect.overlaps(r)) hideLocalCursor(); - buffer->imageRect(r, pixels); - invalidateBufferRect(r); -} -void CView::copyRect(const Rect& r, int srcX, int srcY) { - if (cursorBackingRect.overlaps(r) || - cursorBackingRect.overlaps(Rect(srcX, srcY, srcX+r.width(), srcY+r.height()))) - hideLocalCursor(); - buffer->copyRect(r, Point(r.tl.x-srcX, r.tl.y-srcY)); - invalidateBufferRect(r); -} - -void CView::invertRect(const Rect& r) { - int stride; - rdr::U8* p = buffer->getPixelsRW(r, &stride); - for (int y = 0; y < r.height(); y++) { - for (int x = 0; x < r.width(); x++) { - switch (buffer->getPF().bpp) { - case 8: ((rdr::U8* )p)[x+y*stride] ^= 0xff; break; - case 16: ((rdr::U16*)p)[x+y*stride] ^= 0xffff; break; - case 32: ((rdr::U32*)p)[x+y*stride] ^= 0xffffffff; break; - } - } - } - invalidateBufferRect(r); -} - -bool CView::getUserPasswd(char** user, char** password) { - if (!user && options.passwordFile.buf[0]) { - FILE* fp = fopen(options.passwordFile.buf, "rb"); - if (!fp) return false; - char data[256]; - int datalen = fread(data, 1, 256, fp); - fclose(fp); - if (datalen != 8) return false; - vncAuthUnobfuscatePasswd(data); - *password = strDup(data); - memset(data, 0, strlen(data)); - return true; - } - - if (user && options.userName.buf) - *user = strDup(options.userName.buf); - if (password && options.password.buf) - *password = strDup(options.password.buf); - if ((user && !*user) || (password && !*password)) { - // Missing username or password - prompt the user - UserPasswdDialog userPasswdDialog; - userPasswdDialog.setCSecurity(getCurrentCSecurity()); - if (!userPasswdDialog.getUserPasswd(user, password)) - return false; - } - if (user) options.setUserName(*user); - if (password) options.setPassword(*password); - return true; -} - -bool CView::processFTMsg(int type) -{ - return m_fileTransfer.processFTMsg(type); -}
\ No newline at end of file |