The "rfb_win32" library merged with VNC 4.1.1 code.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/branches/merge-with-vnc-4.1.1@523 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/rfb_win32/MonitorInfo.cxx b/rfb_win32/MonitorInfo.cxx
new file mode 100644
index 0000000..03772e9
--- /dev/null
+++ b/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);
+}
+
+