diff options
Diffstat (limited to 'win/rfb_win32/MonitorInfo.cxx')
-rw-r--r-- | win/rfb_win32/MonitorInfo.cxx | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/win/rfb_win32/MonitorInfo.cxx b/win/rfb_win32/MonitorInfo.cxx new file mode 100644 index 00000000..03772e97 --- /dev/null +++ b/win/rfb_win32/MonitorInfo.cxx @@ -0,0 +1,205 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include <rfb_win32/DynamicFn.h> +#include <rfb_win32/MonitorInfo.h> +#include <rfb_win32/Win32Util.h> +#include <rdr/Exception.h> +#include <rfb/LogWriter.h> + +using namespace rfb; +using namespace win32; + +static LogWriter vlog("MonitorInfo"); + + +// If we are building in multi-monitor support (i.e. the headers support it) +// then do dynamic imports of the required system calls, and provide any +// other code that wouldn't otherwise compile. +#ifdef RFB_HAVE_MONITORINFO +#include <tchar.h> +typedef HMONITOR (WINAPI *_MonitorFromWindow_proto)(HWND,DWORD); +static rfb::win32::DynamicFn<_MonitorFromWindow_proto> _MonitorFromWindow(_T("user32.dll"), "MonitorFromWindow"); +typedef HMONITOR (WINAPI *_MonitorFromRect_proto)(LPCRECT,DWORD); +static rfb::win32::DynamicFn<_MonitorFromRect_proto> _MonitorFromRect(_T("user32.dll"), "MonitorFromRect"); +typedef BOOL (WINAPI *_GetMonitorInfo_proto)(HMONITOR,LPMONITORINFO); +static rfb::win32::DynamicFn<_GetMonitorInfo_proto> _GetMonitorInfo(_T("user32.dll"), "GetMonitorInfoA"); +typedef BOOL (WINAPI *_EnumDisplayMonitors_proto)(HDC, LPCRECT, MONITORENUMPROC, LPARAM); +static rfb::win32::DynamicFn<_EnumDisplayMonitors_proto> _EnumDisplayMonitors(_T("user32.dll"), "EnumDisplayMonitors"); +static void fillMonitorInfo(HMONITOR monitor, MonitorInfo* mi) { + vlog.debug("monitor=%lx", monitor); + if (!_GetMonitorInfo.isValid()) + throw rdr::Exception("no GetMonitorInfo"); + memset(mi, 0, sizeof(MONITORINFOEXA)); + mi->cbSize = sizeof(MONITORINFOEXA); + if (!(*_GetMonitorInfo)(monitor, mi)) + throw rdr::SystemException("failed to GetMonitorInfo", GetLastError()); + vlog.debug("monitor is %d,%d-%d,%d", mi->rcMonitor.left, mi->rcMonitor.top, mi->rcMonitor.right, mi->rcMonitor.bottom); + vlog.debug("work area is %d,%d-%d,%d", mi->rcWork.left, mi->rcWork.top, mi->rcWork.right, mi->rcWork.bottom); + vlog.debug("device is \"%s\"", mi->szDevice); +} +#else +#pragma message(" NOTE: Not building Multi-Monitor support.") +#endif + + +MonitorInfo::MonitorInfo(HWND window) { + cbSize = sizeof(MonitorInfo); + szDevice[0] = 0; + +#ifdef RFB_HAVE_MONITORINFO + try { + if (_MonitorFromWindow.isValid()) { + HMONITOR monitor = (*_MonitorFromWindow)(window, MONITOR_DEFAULTTONEAREST); + if (!monitor) + throw rdr::SystemException("failed to get monitor", GetLastError()); + fillMonitorInfo(monitor, this); + return; + } + } catch (rdr::Exception& e) { + vlog.error(e.str()); + } +#endif + + // Legacy fallbacks - just return the desktop settings + vlog.debug("using legacy fall-backs"); + HWND desktop = GetDesktopWindow(); + GetWindowRect(desktop, &rcMonitor); + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0); + dwFlags = 0; +} + +MonitorInfo::MonitorInfo(const RECT& r) { + cbSize = sizeof(MonitorInfo); + szDevice[0] = 0; + +#ifdef RFB_HAVE_MONITORINFO + try { + if (_MonitorFromRect.isValid()) { + HMONITOR monitor = (*_MonitorFromRect)(&r, MONITOR_DEFAULTTONEAREST); + if (!monitor) + throw rdr::SystemException("failed to get monitor", GetLastError()); + fillMonitorInfo(monitor, this); + return; + } + } catch (rdr::Exception& e) { + vlog.error(e.str()); + } +#endif + + // Legacy fallbacks - just return the desktop settings + vlog.debug("using legacy fall-backs"); + HWND desktop = GetDesktopWindow(); + GetWindowRect(desktop, &rcMonitor); + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0); + dwFlags = 0; +} + + +#ifdef RFB_HAVE_MONITORINFO + +struct monitorByNameData { + MonitorInfo* info; + const char* monitorName; +}; + +static BOOL CALLBACK monitorByNameEnumProc(HMONITOR monitor, + HDC dc, + LPRECT pos, + LPARAM d) { + monitorByNameData* data = (monitorByNameData*)d; + memset(data->info, 0, sizeof(MONITORINFOEXA)); + data->info->cbSize = sizeof(MONITORINFOEXA); + if ((*_GetMonitorInfo)(monitor, data->info)) { + if (stricmp(data->monitorName, data->info->szDevice) == 0) + return FALSE; + } + + return TRUE; +} + +#endif + +MonitorInfo::MonitorInfo(const char* devName) { +#ifdef RFB_HAVE_MONITORINFO + if (!_EnumDisplayMonitors.isValid()) { + vlog.debug("EnumDisplayMonitors not found"); + } else { + monitorByNameData data; + data.info = this; + data.monitorName = devName; + + (*_EnumDisplayMonitors)(0, 0, &monitorByNameEnumProc, (LPARAM)&data); + if (stricmp(data.monitorName, szDevice) == 0) + return; + } +#endif + // If multi-monitor is not built, or not supported by the OS, + // or if the named monitor is not found, revert to the primary monitor. + vlog.debug("reverting to primary monitor"); + cbSize = sizeof(MonitorInfo); + szDevice[0] = 0; + + HWND desktop = GetDesktopWindow(); + GetWindowRect(desktop, &rcMonitor); + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0); + dwFlags = 0; +} + +void MonitorInfo::moveTo(HWND handle) { + vlog.debug("moveTo monitor=%s", szDevice); + +#ifdef RFB_HAVE_MONITORINFO + MonitorInfo mi(handle); + if (strcmp(szDevice, mi.szDevice) != 0) { + centerWindow(handle, rcWork); + clipTo(handle); + } +#endif +} + +void MonitorInfo::clipTo(RECT* r) { + vlog.debug("clipTo monitor=%s", szDevice); + + if (r->top < rcWork.top) { + r->bottom += rcWork.top - r->top; r->top = rcWork.top; + } + if (r->left < rcWork.left) { + r->right += rcWork.left - r->left; r->left = rcWork.left; + } + if (r->bottom > rcWork.bottom) { + r->top += rcWork.bottom - r->bottom; r->bottom = rcWork.bottom; + } + if (r->right > rcWork.right) { + r->left += rcWork.right - r->right; r->right = rcWork.right; + } + r->left = max(r->left, rcWork.left); + r->right = min(r->right, rcWork.right); + r->top = max(r->top, rcWork.top); + r->bottom = min(r->bottom, rcWork.bottom); +} + +void MonitorInfo::clipTo(HWND handle) { + RECT r; + GetWindowRect(handle, &r); + clipTo(&r); + SetWindowPos(handle, 0, r.left, r.top, r.right-r.left, r.bottom-r.top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER); +} + + |