]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/display.cpp
Update copyright year in the version information resource.
[wxWidgets.git] / src / msw / display.cpp
index f9ef4e3171d671f76f63ea1a337b5767cd0dc92f..ae087f9cd94683fb6cfc7ba358d783a283ebe2ae 100644 (file)
     #include "wx/frame.h"
 #endif
 
-#include "wx/dynload.h"
+#include "wx/dynlib.h"
 #include "wx/sysopt.h"
 
 #include "wx/display_impl.h"
 #include "wx/msw/wrapwin.h"
 #include "wx/msw/missing.h"
 #include "wx/msw/private.h"
+#include "wx/msw/private/hiddenwin.h"
 
 #ifndef __WXWINCE__
     // Older versions of windef.h don't define HMONITOR.  Unfortunately, we
@@ -140,6 +141,10 @@ protected:
                            dm.dmDisplayFrequency > 1 ? dm.dmDisplayFrequency : 0);
     }
 
+    // Call GetMonitorInfo() and fill in the provided struct and return true if
+    // it succeeded, otherwise return false.
+    bool GetMonInfo(MONITORINFOEX& monInfo) const;
+
     HMONITOR m_hmon;
 
 private:
@@ -167,6 +172,9 @@ public:
     // m_displays array if they're available
     wxDisplayFactoryMSW();
 
+    // Dtor destroys the hidden window we use for getting WM_SETTINGCHANGE.
+    virtual ~wxDisplayFactoryMSW();
+
     bool IsOk() const { return !m_displays.empty(); }
 
     virtual wxDisplayImpl *CreateDisplay(unsigned n);
@@ -174,6 +182,11 @@ public:
     virtual int GetFromPoint(const wxPoint& pt);
     virtual int GetFromWindow(const wxWindow *window);
 
+    // Called when we receive WM_SETTINGCHANGE to refresh the list of monitor
+    // handles.
+    static void RefreshMonitors() { ms_factory->DoRefreshMonitors(); }
+
+
 private:
     // EnumDisplayMonitors() callback
     static BOOL CALLBACK MultimonEnumProc(HMONITOR hMonitor,
@@ -185,13 +198,29 @@ private:
     // return wxNOT_FOUND if not found
     int FindDisplayFromHMONITOR(HMONITOR hmon) const;
 
+    // Update m_displays array, used by RefreshMonitors().
+    void DoRefreshMonitors();
+
+
+    // The unique factory being used (as we don't have direct access to the
+    // global factory pointer in the common code so we just duplicate this
+    // variable (also making it of correct type for us) here).
+    static wxDisplayFactoryMSW* ms_factory;
+
+
     // the array containing information about all available displays, filled by
     // MultimonEnumProc()
     wxMonitorHandleArray m_displays;
 
+    // The hidden window we use for receiving WM_SETTINGCHANGE and its class
+    // name.
+    HWND m_hiddenHwnd;
+    const wxChar* m_hiddenClass;
+
     wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryMSW);
 };
 
+wxDisplayFactoryMSW* wxDisplayFactoryMSW::ms_factory = NULL;
 
 // ----------------------------------------------------------------------------
 // wxDisplay implementation
@@ -215,18 +244,24 @@ private:
 // wxDisplayMSW implementation
 // ----------------------------------------------------------------------------
 
-wxRect wxDisplayMSW::GetGeometry() const
+bool wxDisplayMSW::GetMonInfo(MONITORINFOEX& monInfo) const
 {
-    WinStruct<MONITORINFOEX> monInfo;
-
-    if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) )
+    if ( !gs_GetMonitorInfo(m_hmon, &monInfo) )
     {
-        wxLogLastError(wxT(__FUNCTION__));
-        return wxRect();
+        wxLogLastError(wxT("GetMonitorInfo"));
+        return false;
     }
 
+    return true;
+}
+
+wxRect wxDisplayMSW::GetGeometry() const
+{
+    WinStruct<MONITORINFOEX> monInfo;
+
     wxRect rect;
-    wxCopyRECTToRect(monInfo.rcMonitor, rect);
+    if ( GetMonInfo(monInfo) )
+        wxCopyRECTToRect(monInfo.rcMonitor, rect);
 
     return rect;
 }
@@ -235,14 +270,9 @@ wxRect wxDisplayMSW::GetClientArea() const
 {
     WinStruct<MONITORINFOEX> monInfo;
 
-    if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) )
-    {
-        wxLogLastError(wxT(__FUNCTION__));
-        return wxRect();
-    }
-
     wxRect rectClient;
-    wxCopyRECTToRect(monInfo.rcWork, rectClient);
+    if ( GetMonInfo(monInfo) )
+        wxCopyRECTToRect(monInfo.rcWork, rectClient);
 
     return rectClient;
 }
@@ -251,24 +281,19 @@ wxString wxDisplayMSW::GetName() const
 {
     WinStruct<MONITORINFOEX> monInfo;
 
-    if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) )
-    {
-        wxLogLastError(wxT(__FUNCTION__));
-        return "";
-    }
+    wxString name;
+    if ( GetMonInfo(monInfo) )
+        name = monInfo.szDevice;
 
-    return monInfo.szDevice;
+    return name;
 }
 
 bool wxDisplayMSW::IsPrimary() const
 {
     WinStruct<MONITORINFOEX> monInfo;
 
-    if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) )
-    {
-        wxLogLastError(wxT(__FUNCTION__));
+    if ( !GetMonInfo(monInfo) )
         return false;
-    }
 
     return (monInfo.dwFlags & MONITORINFOF_PRIMARY) != 0;
 }
@@ -406,7 +431,7 @@ bool wxDisplayMSW::ChangeMode(const wxVideoMode& mode)
     // do change the mode
     switch ( pfnChangeDisplaySettingsEx
              (
-                GetName().wx_str(), // display name
+                GetName().t_str(),  // display name
                 pDevMode,           // dev mode or NULL to reset
                 NULL,               // reserved
                 flags,
@@ -417,7 +442,7 @@ bool wxDisplayMSW::ChangeMode(const wxVideoMode& mode)
             // ok
             {
                 // If we have a top-level, full-screen frame, emulate
-                // the DirectX behavior and resize it.  This makes this
+                // the DirectX behaviour and resize it.  This makes this
                 // API quite a bit easier to use.
                 wxWindow *winTop = wxTheApp->GetTopWindow();
                 wxFrame *frameTop = wxDynamicCast(winTop, wxFrame);
@@ -445,8 +470,30 @@ bool wxDisplayMSW::ChangeMode(const wxVideoMode& mode)
 // wxDisplayFactoryMSW implementation
 // ----------------------------------------------------------------------------
 
+LRESULT APIENTRY
+wxDisplayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    if ( msg == WM_SETTINGCHANGE )
+    {
+        wxDisplayFactoryMSW::RefreshMonitors();
+
+        return 0;
+    }
+
+    return ::DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
 wxDisplayFactoryMSW::wxDisplayFactoryMSW()
 {
+    // This is not supposed to happen with the current code, the factory is
+    // implicitly a singleton.
+    wxASSERT_MSG( !ms_factory, wxS("Using more than one factory?") );
+
+    ms_factory = this;
+
+    m_hiddenHwnd = NULL;
+    m_hiddenClass = NULL;
+
     if ( gs_MonitorFromPoint==NULL || gs_MonitorFromWindow==NULL
          || gs_GetMonitorInfo==NULL || gs_EnumDisplayMonitors==NULL )
     {
@@ -466,7 +513,44 @@ wxDisplayFactoryMSW::wxDisplayFactoryMSW()
          || gs_GetMonitorInfo==NULL || gs_EnumDisplayMonitors==NULL )
         return;
 
-    // enumerate all displays
+    DoRefreshMonitors();
+
+    // Also create a hidden window to listen for WM_SETTINGCHANGE that we
+    // receive when a monitor is added to or removed from the system as we must
+    // refresh our monitor handles information then.
+    m_hiddenHwnd = wxCreateHiddenWindow
+                   (
+                    &m_hiddenClass,
+                    wxT("wxDisplayHiddenWindow"),
+                    wxDisplayWndProc
+                   );
+}
+
+wxDisplayFactoryMSW::~wxDisplayFactoryMSW()
+{
+    if ( m_hiddenHwnd )
+    {
+        if ( !::DestroyWindow(m_hiddenHwnd) )
+        {
+            wxLogLastError(wxT("DestroyWindow(wxDisplayHiddenWindow)"));
+        }
+
+        if ( m_hiddenClass )
+        {
+            if ( !::UnregisterClass(m_hiddenClass, wxGetInstance()) )
+            {
+                wxLogLastError(wxT("UnregisterClass(wxDisplayHiddenWindow)"));
+            }
+        }
+    }
+
+    ms_factory = NULL;
+}
+
+void wxDisplayFactoryMSW::DoRefreshMonitors()
+{
+    m_displays.Clear();
+
     if ( !gs_EnumDisplayMonitors(NULL, NULL, MultimonEnumProc, (LPARAM)this) )
     {
         wxLogLastError(wxT("EnumDisplayMonitors"));
@@ -524,8 +608,34 @@ int wxDisplayFactoryMSW::GetFromPoint(const wxPoint& pt)
 
 int wxDisplayFactoryMSW::GetFromWindow(const wxWindow *window)
 {
+#ifdef __WXMSW__
     return FindDisplayFromHMONITOR(gs_MonitorFromWindow(GetHwndOf(window),
                                                         MONITOR_DEFAULTTONULL));
+#else
+    const wxSize halfsize = window->GetSize() / 2;
+    wxPoint pt = window->GetScreenPosition();
+    pt.x += halfsize.x;
+    pt.y += halfsize.y;
+    return GetFromPoint(pt);
+#endif
 }
 
 #endif // wxUSE_DISPLAY
+
+void wxClientDisplayRect(int *x, int *y, int *width, int *height)
+{
+#if defined(__WXMICROWIN__)
+    *x = 0; *y = 0;
+    wxDisplaySize(width, height);
+#else
+    // Determine the desktop dimensions minus the taskbar and any other
+    // special decorations...
+    RECT r;
+
+    SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
+    if (x)      *x = r.left;
+    if (y)      *y = r.top;
+    if (width)  *width = r.right - r.left;
+    if (height) *height = r.bottom - r.top;
+#endif
+}