X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d5947fad64ffb5bd695620fc82e5d4f20d51fb47..43c42c18d36c703a88b1b7b697bac27fe5608eca:/src/msw/display.cpp diff --git a/src/msw/display.cpp b/src/msw/display.cpp index f9ef4e3171..ae087f9cd9 100644 --- a/src/msw/display.cpp +++ b/src/msw/display.cpp @@ -35,13 +35,14 @@ #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 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 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 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 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 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 +}