X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4c51a665c649f7579fb39e62070cef4f66b3210d..739c5499fcab1c165b8dd0591c9fd9e2329b3cf9:/src/msw/display.cpp?ds=sidebyside diff --git a/src/msw/display.cpp b/src/msw/display.cpp index b7abb30192..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 @@ -171,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); @@ -178,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, @@ -189,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 @@ -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, @@ -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 +}