123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350 |
- /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- * Copyright (C) 2010 D. R. Commander. 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 <math.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 <rfb_win32/MsgBox.h>
- #include <rfb/util.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;
- const int TIMER_UPDATE = 4;
-
-
- //
- // -=- 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 = 0;
- if (msg == WM_CREATE)
- SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)((CREATESTRUCT*)lParam)->lpCreateParams);
- else if (msg == WM_DESTROY)
- SetWindowLongPtr(wnd, GWLP_USERDATA, 0);
- DesktopWindow* _this = (DesktopWindow*) GetWindowLongPtr(wnd, GWLP_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 (rfb::UnsupportedPixelFormatException &e) {
- MsgBox(0, (TCHAR *) e.str(), MB_OK | MB_ICONINFORMATION);
- _this->getCallback()->closeWindow();
- } 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);
- }
- }
-
- static 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 = 0;
- if (msg == WM_CREATE)
- SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)((CREATESTRUCT*)lParam)->lpCreateParams);
- else if (msg == WM_DESTROY)
- SetWindowLongPtr(wnd, GWLP_USERDATA, 0);
- DesktopWindow* _this = (DesktopWindow*) GetWindowLongPtr(wnd, GWLP_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)
- : bumpScroll(false), palette_changed(false), fullscreenActive(false),
- fullscreenRestore(false), systemCursorVisible(true), trackingMouseLeave(false),
- cursorInBuffer(false), cursorVisible(false), cursorAvailable(false),
- internalSetCursor(false), cursorImage(0), cursorMask(0),
- cursorWidth(0), cursorHeight(0), showToolbar(false),
- buffer(0), has_focus(false), autoScaling(false),
- window_size(0, 0, 32, 32), client_size(0, 0, 16, 16), handle(0),
- frameHandle(0), 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);
-
- // Initialise the update timer
- updateTimer.setHWND(handle);
- updateTimer.setId(TIMER_UPDATE);
-
- // 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;
- if (cursorImage) delete [] cursorImage;
- if (cursorMask) delete [] cursorMask;
- 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 (fullscreenActive) return;
-
- RECT r;
- GetWindowRect(handle, &r);
- bool maximized = GetWindowLong(handle, GWL_STYLE) & WS_MAXIMIZE;
-
- if (showToolbar && !tb.isVisible()) {
- refreshToolbarButtons();
- tb.show();
- if (!maximized) r.bottom += tb.getHeight();
- } else if (!showToolbar && tb.isVisible()) {
- tb.hide();
- if (!maximized) r.bottom -= tb.getHeight();
- }
- // Resize the chiled windows even if the parent window size
- // has not been changed (the main window is maximized)
- if (maximized) SendMessage(handle, WM_SIZE, 0, 0);
- else SetWindowPos(handle, NULL, 0, 0, r.right-r.left, r.bottom-r.top, SWP_NOMOVE | SWP_NOZORDER);
- }
-
- void DesktopWindow::refreshToolbarButtons() {
- int scale = getDesktopScale();
- if (scale <= 10) {
- tb.enableButton(ID_ZOOM_IN, true);
- tb.enableButton(ID_ZOOM_OUT, false);
- } else if (scale >= 200) {
- tb.enableButton(ID_ZOOM_IN, false);
- tb.enableButton(ID_ZOOM_OUT, true);
- } else {
- tb.enableButton(ID_ZOOM_IN, true);
- tb.enableButton(ID_ZOOM_OUT, true);
- }
- if (buffer->isScaling() || isAutoScaling()) tb.enableButton(ID_ACTUAL_SIZE, true);
- else tb.enableButton(ID_ACTUAL_SIZE, false);
- if (isAutoScaling()) tb.pressButton(ID_AUTO_SIZE, true);
- else tb.pressButton(ID_AUTO_SIZE, false);
- }
-
- 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(__rfbmax(0, __rfbmin(tl.x, buffer->width()-client_size.width())),
- __rfbmax(0, __rfbmin(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) || isAutoScaling())
- break;
-
- // Calculate the minimum size of main window
- RECT r;
- Rect min_size;
- int tbMinWidth = 0, tbMinHeight = 0;
- if (isToolbarEnabled()) {
- tbMinWidth = tb.getTotalWidth();
- tbMinHeight = tb.getHeight();
- SetRect(&r, 0, 0, tbMinWidth, tbMinHeight);
- AdjustWindowRect(&r, GetWindowLong(handle, GWL_STYLE), FALSE);
- min_size = Rect(r.left, r.top, r.right, r.bottom);
- }
-
- // 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);
-
- 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 (isToolbarEnabled())
- 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 (min_size.width() > reqd_size.width()) {
- reqd_size.tl.x = min_size.tl.x;
- reqd_size.br.x = min_size.br.x;
- }
- if (min_size.height() > reqd_size.height()) {
- reqd_size.tl.y = min_size.tl.y;
- reqd_size.br.y = min_size.br.y;
- }
-
- if (!(GetWindowLong(handle, GWL_STYLE) & WS_MAXIMIZE) && !fullscreenActive) {
- // Ensure that the window isn't resized too large or too small
- if ((wpos->cx < min_size.width()) && isToolbarEnabled()) {
- wpos->cx = min_size.width();
- wpos->x = current.left;
- } else if ((wpos->cx > reqd_size.width())) {
- wpos->cx = reqd_size.width();
- wpos->x = current.left;
- }
- if ((wpos->cy < min_size.height()) && isToolbarEnabled()) {
- wpos->cy = min_size.height();
- wpos->y = current.top;
- } else 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);
-
- // Perform the AutoScaling operation
- if (isAutoScaling()) {
- fitBufferToWindow(false);
- } else {
- // Determine whether scrollbars are required
- calculateScrollBars();
- }
-
- // Redraw if required
- if ((!old_offset.equals(desktopToClient(Point(0, 0)))) || isAutoScaling())
- 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;
- case TIMER_UPDATE:
- updateWindow();
- 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 mouse wheel scroll events
-
- #ifdef WM_MOUSEWHEEL
- case WM_MOUSEWHEEL:
- processMouseMessage(msg, wParam, lParam);
- break;
- #endif
-
- // -=- 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);
- }
- 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:
- processMouseMessage(msg, wParam, lParam);
- break;
- }
-
- return rfb::win32::SafeDefWindowProc(frameHandle, msg, wParam, lParam);
- }
-
- void
- DesktopWindow::processMouseMessage(UINT msg, WPARAM wParam, LPARAM lParam)
- {
- if (!has_focus) {
- cursorOutsideBuffer();
- return;
- }
-
- 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();
- return;
- }
-
- // 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))
- return;
-
- // Send a pointer event to the server
- oldpos = p;
- if (buffer->isScaling()) {
- p.x /= buffer->getScaleRatioX();
- p.y /= buffer->getScaleRatioY();
- }
- ptr.pointerEvent(callback, p, mask);
- #ifdef WM_MOUSEWHEEL
- }
- #endif
- }
-
- void DesktopWindow::updateWindow()
- {
- Rect rect;
-
- updateTimer.stop();
-
- rect = damage.get_bounding_rect();
- damage.clear();
-
- RECT invalid = {rect.tl.x, rect.tl.y, rect.br.x, rect.br.y};
- InvalidateRect(frameHandle, &invalid, FALSE);
- }
-
- 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->getScaledPixelFormat().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);
- // Since we render the cursor onto the framebuffer, we need to update
- // right away to get a responsive cursor.
- updateWindow();
- }
- }
-
- 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;
- damage.assign_union(rfb::Region(rect));
- if (!updateTimer.isActive())
- updateTimer.start(100);
- 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->getScaledPixelFormat()))
- 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);
-
- // Calculate the pixel buffer aspect correlation. It's used
- // for the autoScaling operation.
- aspect_corr = (double)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 (isToolbarEnabled())
- 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::setAutoScaling(bool as) {
- autoScaling = as;
- if (isToolbarEnabled()) refreshToolbarButtons();
- if (as) fitBufferToWindow();
- }
-
- void DesktopWindow::setDesktopScale(int scale_) {
- if (buffer->getScale() == scale_ || scale_ <= 0) return;
- bool state = buffer->isScaling();
- buffer->setScale(scale_);
- state ^= buffer->isScaling();
- if (state) convertCursorToBuffer();
- if (isToolbarEnabled()) refreshToolbarButtons();
- if (!(isAutoScaling() || isFullscreen() || (GetWindowLong(handle, GWL_STYLE) & WS_MAXIMIZE))) resizeDesktopWindowToBuffer();
- printScale();
- InvalidateRect(frameHandle, 0, FALSE);
- }
-
- void DesktopWindow::setDesktopScaleFilter(unsigned int scaleFilterID) {
- if (scaleFilterID == getDesktopScaleFilterID() || scaleFilterID > scaleFilterMaxNumber) return;
- buffer->setScaleFilter(scaleFilterID);
- InvalidateRect(frameHandle, 0, FALSE);
- }
-
- void DesktopWindow::convertCursorToBuffer() {
- if (memcmp(&(cursor.getPF()), &(buffer->getPF()), sizeof(PixelBuffer)) == 0) return;
- internalSetCursor = true;
- setCursor(cursorWidth, cursorHeight, cursorHotspot, cursorImage, cursorMask);
- internalSetCursor = false;
- }
-
- void DesktopWindow::fitBufferToWindow(bool repaint) {
- double scale_ratio;
- double resized_aspect_corr = double(client_size.width()) / client_size.height();
- DWORD style = GetWindowLong(frameHandle, GWL_STYLE);
- if (style & (WS_VSCROLL | WS_HSCROLL)) {
- style &= ~(WS_VSCROLL | WS_HSCROLL);
- SetWindowLong(frameHandle, GWL_STYLE, style);
- SetWindowPos(frameHandle, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
- // Update the cached client size
- RECT r;
- GetClientRect(frameHandle, &r);
- client_size = Rect(r.left, r.top, r.right, r.bottom);
- }
- bool state = buffer->isScaling();
- if (resized_aspect_corr > aspect_corr) {
- scale_ratio = (double)client_size.height() / buffer->getSrcHeight();
- buffer->setScaleWindowSize(ceil(buffer->getSrcWidth()*scale_ratio), client_size.height());
- } else {
- scale_ratio = (double)client_size.width() / buffer->getSrcWidth();
- buffer->setScaleWindowSize(client_size.width(), ceil(buffer->getSrcHeight()*scale_ratio));
- }
- state ^= buffer->isScaling();
- if (state) convertCursorToBuffer();
- printScale();
- InvalidateRect(frameHandle, 0, FALSE);
- }
-
- void DesktopWindow::printScale() {
- setName(desktopName);
- }
-
- 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->getScaledPixelFormat());
-
- // Convert the current cursor pixel format to bpp32 if scaling mode is on.
- // It need because ScaledDIBSection buffer always works with bpp32 pixel data
- // in scaling mode.
- if (buffer->isScaling()) {
- U8 *ptr = (U8*)cursor.data;
- U8 *dataPtr = (U8*)data;
- U32 pixel = 0;
- int bytesPerPixel = buffer->getPixelFormat().bpp / 8;
- int pixelCount = w * h;
- PixelFormat pf = buffer->getPixelFormat();
-
- while (pixelCount--) {
- if (bytesPerPixel == 1) {
- pixel = *dataPtr++;
- } else if (bytesPerPixel == 2) {
- int b0 = *dataPtr++; int b1 = *dataPtr++;
- pixel = b1 << 8 | b0;
- } else if (bytesPerPixel == 4) {
- int b0 = *dataPtr++; int b1 = *dataPtr++;
- int b2 = *dataPtr++; int b3 = *dataPtr++;
- pixel = b3 << 24 | b2 << 16 | b1 << 8 | b0;
- } else {
- pixel = 0;
- }
- *ptr++ = (U8)((((pixel >> pf.blueShift ) & pf.blueMax ) * 255 + pf.blueMax /2) / pf.blueMax);
- *ptr++ = (U8)((((pixel >> pf.greenShift) & pf.greenMax) * 255 + pf.greenMax/2) / pf.greenMax);
- *ptr++ = (U8)((((pixel >> pf.redShift ) & pf.redMax ) * 255 + pf.redMax /2) / pf.redMax);
- *ptr++ = (U8)0;
- }
- } else {
- cursor.imageRect(cursor.getRect(), data);
- }
- memcpy(cursor.mask.buf, mask, cursor.maskLen());
- cursor.crop();
-
- cursorBacking.setSize(w, h);
- cursorBacking.setPF(buffer->getScaledPixelFormat());
-
- cursorAvailable = true;
-
- showLocalCursor();
-
- // Save the cursor parameters
- if (!internalSetCursor) {
- if (cursorImage) delete [] cursorImage;
- if (cursorMask) delete [] cursorMask;
- int cursorImageSize = (buffer->getPixelFormat().bpp/8) * w * h;
- cursorImage = new U8[cursorImageSize];
- cursorMask = new U8[cursor.maskLen()];
- memcpy(cursorImage, data, cursorImageSize);
- memcpy(cursorMask, mask, cursor.maskLen());
- cursorWidth = w;
- cursorHeight = h;
- cursorHotspot = hotspot;
- }
- }
-
- 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 = __rfbmax(0, si.nMax-si.nPage);
- scrolloffset.y = __rfbmin(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 = __rfbmax(0, si.nMax-si.nPage);
- scrolloffset.x = __rfbmin(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::resizeDesktopWindowToBuffer() {
- RECT r;
- DWORD style = GetWindowLong(frameHandle, GWL_STYLE) & ~(WS_VSCROLL | WS_HSCROLL);
- DWORD style_ex = GetWindowLong(frameHandle, GWL_EXSTYLE);
-
- // Calculate the required size of the desktop window
- SetRect(&r, 0, 0, buffer->width(), buffer->height());
- AdjustWindowRectEx(&r, style, FALSE, style_ex);
- if (isToolbarEnabled())
- r.bottom += tb.getHeight();
- AdjustWindowRect(&r, GetWindowLong(handle, GWL_STYLE), FALSE);
-
- // Set the required size, center the main window and clip to the current monitor
- SetWindowPos(handle, 0, 0, 0, r.right-r.left, r.bottom-r.top, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
- centerWindow(handle, NULL);
- MonitorInfo mi(getMonitor());
- mi.clipTo(handle);
-
- // Enable/disable scrollbars as appropriate
- calculateScrollBars();
- }
-
-
- void DesktopWindow::framebufferUpdateEnd()
- {
- updateWindow();
- }
-
-
- void
- DesktopWindow::setName(const char* name) {
- if (name != desktopName) {
- strCopy(desktopName, name, sizeof(desktopName));
- }
- char *newTitle = new char[strlen(desktopName)+20];
- sprintf(newTitle, "TigerVNC: %.240s @ %i%%", desktopName, getDesktopScale());
- SetWindowText(handle, TStr(newTitle));
- delete [] newTitle;
- }
-
-
- void
- DesktopWindow::serverCutText(const char* str, rdr::U32 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);
- }
|