diff options
author | Constantin Kaplinsky <const@tightvnc.com> | 2004-10-08 09:43:57 +0000 |
---|---|---|
committer | Constantin Kaplinsky <const@tightvnc.com> | 2004-10-08 09:43:57 +0000 |
commit | 47ed8d321c32c6b741cff1f4ff686165c4f269f4 (patch) | |
tree | da413648adbff4ff10c8ee26124673f8e7cf238a /rfb_win32/WMHooks.cxx | |
parent | 266bb36cd47555280fffd3aab1ed86683e26d748 (diff) | |
download | tigervnc-47ed8d321c32c6b741cff1f4ff686165c4f269f4.tar.gz tigervnc-47ed8d321c32c6b741cff1f4ff686165c4f269f4.zip |
Initial revision
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@2 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'rfb_win32/WMHooks.cxx')
-rw-r--r-- | rfb_win32/WMHooks.cxx | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/rfb_win32/WMHooks.cxx b/rfb_win32/WMHooks.cxx new file mode 100644 index 00000000..26a2363c --- /dev/null +++ b/rfb_win32/WMHooks.cxx @@ -0,0 +1,324 @@ +/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// -=- WMHooks.cxx + +#include <wm_hooks/wm_hooks.h> + +#include <rfb_win32/WMHooks.h> +#include <rfb_win32/Service.h> +#include <rfb/Threading.h> +#include <rfb/LogWriter.h> + +#include <list> + +using namespace rfb; +using namespace rfb::win32; + +static LogWriter vlog("WMHooks"); + +class WMHooksThread : public Thread { +public: + WMHooksThread() : Thread("WMHookThread"), active(true) {} + virtual void run(); + virtual Thread* join(); +protected: + bool active; +}; + +WMHooksThread* hook_mgr = 0; +std::list<WMHooks*> hooks; +std::list<WMCursorHooks*> cursor_hooks; +Mutex hook_mgr_lock; +HCURSOR hook_cursor = (HCURSOR)LoadImage(0, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED); + + +bool +StartHookThread() { + if (hook_mgr) return true; + vlog.debug("opening hook thread"); + hook_mgr = new WMHooksThread(); + if (!WM_Hooks_Install(hook_mgr->getThreadId(), 0)) { + vlog.error("failed to initialise hooks"); + delete hook_mgr->join(); + hook_mgr = 0; + return false; + } + hook_mgr->start(); + return true; +} + +void +StopHookThread() { + if (!hook_mgr) return; + if (!hooks.empty() || !cursor_hooks.empty()) return; + vlog.debug("closing hook thread"); + delete hook_mgr->join(); + hook_mgr = 0; +} + + +bool +AddHook(WMHooks* hook) { + vlog.debug("adding hook"); + Lock l(hook_mgr_lock); + if (!StartHookThread()) return false; + hooks.push_back(hook); + return true; +} + +bool +AddCursorHook(WMCursorHooks* hook) { + vlog.debug("adding cursor hook"); + Lock l(hook_mgr_lock); + if (cursor_hooks.empty()) WM_Hooks_EnableCursorShape(TRUE); + if (!StartHookThread()) return false; + cursor_hooks.push_back(hook); + return true; +} + +bool +RemHook(WMHooks* hook) { + { + vlog.debug("removing hook"); + Lock l(hook_mgr_lock); + hooks.remove(hook); + } + StopHookThread(); + return true; +} + +bool +RemCursorHook(WMCursorHooks* hook) { + { + vlog.debug("removing cursor hook"); + Lock l(hook_mgr_lock); + cursor_hooks.remove(hook); + } + StopHookThread(); + if (cursor_hooks.empty()) WM_Hooks_EnableCursorShape(FALSE); + return true; +} + +void +NotifyHooksRegion(const Region& r) { + Lock l(hook_mgr_lock); + std::list<WMHooks*>::iterator i; + for (i=hooks.begin(); i!=hooks.end(); i++) { + (*i)->new_changes.add_changed(r); + if (!(*i)->notified) { + (*i)->notified = true; + PostMessage((*i)->getHandle(), WM_USER, 0, 0); + } + } +} + +void +NotifyHooksCursor(HCURSOR c) { + Lock l(hook_mgr_lock); + hook_cursor = c; +} + +void +WMHooksThread::run() { + UINT windowMsg = WM_Hooks_WindowChanged(); + UINT clientAreaMsg = WM_Hooks_WindowClientAreaChanged(); + UINT borderMsg = WM_Hooks_WindowBorderChanged(); + UINT rectangleMsg = WM_Hooks_RectangleChanged(); + UINT cursorMsg = WM_Hooks_CursorChanged(); +#ifdef _DEBUG + UINT diagnosticMsg = WM_Hooks_Diagnostic(); +#endif + MSG msg; + RECT wrect; + HWND hwnd; + int count = 0; + + vlog.debug("starting hook thread"); + + while (active && GetMessage(&msg, NULL, 0, 0)) { + count++; + if (msg.message == windowMsg) { + hwnd = (HWND) msg.lParam; + if (IsWindow(hwnd) && IsWindowVisible(hwnd) && !IsIconic(hwnd) && + GetWindowRect(hwnd, &wrect) && !IsRectEmpty(&wrect)) + { + NotifyHooksRegion(Rect(wrect.left, wrect.top, + wrect.right, wrect.bottom)); + + } + } else if (msg.message == clientAreaMsg) { + hwnd = (HWND) msg.lParam; + if (IsWindow(hwnd) && IsWindowVisible(hwnd) && !IsIconic(hwnd) && + GetClientRect(hwnd, &wrect) && !IsRectEmpty(&wrect)) + { + POINT pt = {0,0}; + if (ClientToScreen(hwnd, &pt)) { + NotifyHooksRegion(Rect(wrect.left+pt.x, wrect.top+pt.y, + wrect.right+pt.x, wrect.bottom+pt.y)); + } + } + } else if (msg.message == borderMsg) { + hwnd = (HWND) msg.lParam; + if (IsWindow(hwnd) && IsWindowVisible(hwnd) && !IsIconic(hwnd) && + GetWindowRect(hwnd, &wrect) && !IsRectEmpty(&wrect)) + { + Region changed(Rect(wrect.left, wrect.top, wrect.right, wrect.bottom)); + RECT crect; + POINT pt = {0,0}; + if (GetClientRect(hwnd, &crect) && ClientToScreen(hwnd, &pt) && + !IsRectEmpty(&crect)) + { + changed.assign_subtract(Rect(crect.left+pt.x, crect.top+pt.y, + crect.right+pt.x, crect.bottom+pt.y)); + } + NotifyHooksRegion(changed); + } + } else if (msg.message == rectangleMsg) { + Rect r = Rect(LOWORD(msg.wParam), HIWORD(msg.wParam), + LOWORD(msg.lParam), HIWORD(msg.lParam)); + if (!r.is_empty()) { + NotifyHooksRegion(r); + } + } else if (msg.message == cursorMsg) { + NotifyHooksCursor((HCURSOR)msg.lParam); +#ifdef _DEBUG + } else if (msg.message == diagnosticMsg) { + vlog.info("DIAG msg=%x(%d) wnd=%lx", msg.wParam, msg.wParam, msg.lParam); +#endif + } + } + + vlog.debug("stopping hook thread - processed %d events", count); + WM_Hooks_Remove(getThreadId()); +} + +Thread* +WMHooksThread::join() { + vlog.debug("stopping WMHooks thread"); + active = false; + PostThreadMessage(thread_id, WM_QUIT, 0, 0); + vlog.debug("joining WMHooks thread"); + return Thread::join(); +} + +// -=- WMHooks class + +rfb::win32::WMHooks::WMHooks() + : clipper(0), new_changes(true), fg_window(0), + notified(false), MsgWindow(_T("WMHooks")) { +} + +rfb::win32::WMHooks::~WMHooks() { + RemHook(this); + if (clipper) delete clipper; +} + +LRESULT +rfb::win32::WMHooks::processMessage(UINT msg, WPARAM wParam, LPARAM lParam) { + switch (msg) { + case WM_USER: + { + // *** Yield, to allow the triggering update event to be processed + // BEFORE we try to grab the resulting changes. + // *** IMPROVES THINGS NOTICABLY ON WinXP + Sleep(0); + // *** + + Lock l(hook_mgr_lock); + notified = false; + new_changes.get_update(*clipper); + new_changes.clear(); + } + break; + } + return MsgWindow::processMessage(msg, wParam, lParam); +} + +bool +rfb::win32::WMHooks::setClipRect(const Rect& r) { + clip_region = r; + if (clipper) clipper->set_clip_region(clip_region); + return true; +} + +bool +rfb::win32::WMHooks::setUpdateTracker(UpdateTracker* ut) { + if (clipper) delete clipper; + clipper = new ClippedUpdateTracker(*ut); + clipper->set_clip_region(clip_region); + return AddHook(this); +} + +#ifdef _DEBUG +void +rfb::win32::WMHooks::setDiagnosticRange(UINT min, UINT max) { + WM_Hooks_SetDiagnosticRange(min, max); +} +#endif + + +// -=- WMBlockInput class + +Mutex blockMutex; +int blockCount = 0; + +rfb::win32::WMBlockInput::WMBlockInput() : active(false) { +} + +rfb::win32::WMBlockInput::~WMBlockInput() { + blockInputs(false); +} + +bool rfb::win32::WMBlockInput::blockInputs(bool on) { + if (on == active) return true; + vlog.debug("blockInput changed"); + Lock l(blockMutex); + int newCount = blockCount; + if (on) + newCount++; + else + newCount--; + if (WM_Hooks_EnableRealInputs(newCount==0, newCount==0)) { + vlog.debug("set blocking to %d", newCount); + blockCount = newCount; + active = on; + return true; + } + return false; +} + + +// -=- WMCursorHooks class + +rfb::win32::WMCursorHooks::WMCursorHooks() { +} + +rfb::win32::WMCursorHooks::~WMCursorHooks() { + RemCursorHook(this); +} + +bool +rfb::win32::WMCursorHooks::start() { + return AddCursorHook(this); +} + +HCURSOR +rfb::win32::WMCursorHooks::getCursor() const { + return hook_cursor; +} |