summaryrefslogtreecommitdiffstats
path: root/win/rfb_win32/MonitorInfo.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'win/rfb_win32/MonitorInfo.cxx')
-rw-r--r--win/rfb_win32/MonitorInfo.cxx205
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);
+}
+
+