X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8585e2b5065cff7dfd733c8a4780dba91bde2cb2..404b319a85dadd7decf7a5a5331020520031a41c:/src/msw/display.cpp diff --git a/src/msw/display.cpp b/src/msw/display.cpp index e85dd3e787..ae087f9cd9 100644 --- a/src/msw/display.cpp +++ b/src/msw/display.cpp @@ -1,11 +1,12 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: display.cpp +// Name: src/msw/display.cpp // Purpose: MSW Implementation of wxDisplay class -// Author: Royce Mitchell III -// Modified by: +// Author: Royce Mitchell III, Vadim Zeitlin +// Modified by: Ryan Norton (IsPrimary override) // Created: 06/21/02 // RCS-ID: $Id$ -// Copyright: (c) wxWindows team +// Copyright: (c) wxWidgets team +// Copyright: (c) 2002-2006 wxWidgets team // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -17,10 +18,6 @@ // headers // --------------------------------------------------------------------------- -#ifdef __GNUG__ - #pragma implementation "display.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -30,44 +27,59 @@ #if wxUSE_DISPLAY -#ifndef WX_PRECOMP - #include "wx/dynarray.h" -#endif - -#include "wx/dynload.h" - #include "wx/display.h" -// the following define is necessary to access the multi-monitor function -// declarations in a manner safe to use w/ Windows 95 -#define COMPILE_MULTIMON_STUBS - -// if you don't have multimon.h you can download the file from: -// -// http://www.microsoft.com/msj/0697/monitor/monitortextfigs.htm#fig4 -// - -#ifdef _MSC_VER - // as (m)any standard header, this one doesn't compile without warnings - // with VC++ 6 - #pragma warning(disable:4706) -#endif - -#include - -#ifdef _MSC_VER - #pragma warning(default:4706) +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/app.h" + #include "wx/frame.h" #endif -#ifdef _UNICODE - #define MAKE_WFUNC(x) #x "W" - #define WINFUNC(x) L ## MAKE_WFUNC(x) +#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 + // can't directly test whether HMONITOR is defined or not in windef.h as + // it's not a macro but a typedef, so we test for an unrelated symbol which + // is only defined in winuser.h if WINVER >= 0x0500 + #if !defined(HMONITOR_DECLARED) && !defined(MNS_NOCHECK) + DECLARE_HANDLE(HMONITOR); + typedef BOOL(CALLBACK * MONITORENUMPROC )(HMONITOR, HDC, LPRECT, LPARAM); + typedef struct tagMONITORINFO + { + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; + } MONITORINFO, *LPMONITORINFO; + typedef struct tagMONITORINFOEX : public tagMONITORINFO + { + TCHAR szDevice[CCHDEVICENAME]; + } MONITORINFOEX, *LPMONITORINFOEX; + #define MONITOR_DEFAULTTONULL 0x00000000 + #define MONITOR_DEFAULTTOPRIMARY 0x00000001 + #define MONITOR_DEFAULTTONEAREST 0x00000002 + #define MONITORINFOF_PRIMARY 0x00000001 + #define HMONITOR_DECLARED + #endif +#endif // !__WXWINCE__ + +// display functions are found in different DLLs under WinCE and normal Win32 +#ifdef __WXWINCE__ +static const wxChar displayDllName[] = wxT("coredll.dll"); #else - #define WINFUNC(x) #x "A" +static const wxChar displayDllName[] = wxT("user32.dll"); #endif // ---------------------------------------------------------------------------- -// typedefs +// typedefs for dynamically loaded Windows functions // ---------------------------------------------------------------------------- typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName, @@ -76,243 +88,260 @@ typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName, DWORD dwFlags, LPVOID lParam); +typedef BOOL (WINAPI *EnumDisplayMonitors_t)(HDC,LPCRECT,MONITORENUMPROC,LPARAM); +typedef HMONITOR (WINAPI *MonitorFromPoint_t)(POINT,DWORD); +typedef HMONITOR (WINAPI *MonitorFromWindow_t)(HWND,DWORD); +typedef BOOL (WINAPI *GetMonitorInfo_t)(HMONITOR,LPMONITORINFO); + +#ifndef __WXWINCE__ +// emulation of ChangeDisplaySettingsEx() for Win95 +LONG WINAPI ChangeDisplaySettingsExForWin95(LPCTSTR WXUNUSED(lpszDeviceName), + LPDEVMODE lpDevMode, + HWND WXUNUSED(hwnd), + DWORD dwFlags, + LPVOID WXUNUSED(lParam)) +{ + return ::ChangeDisplaySettings(lpDevMode, dwFlags); +} +#endif // !__WXWINCE__ + + // ---------------------------------------------------------------------------- -// private classes +// wxDisplayMSW declaration // ---------------------------------------------------------------------------- -class wxDisplayInfo +class wxDisplayMSW : public wxDisplayImpl { public: - // handle of this monitor used by MonitorXXX() functions, never NULL - HMONITOR m_hmon; + wxDisplayMSW(unsigned n, HMONITOR hmon) + : wxDisplayImpl(n), + m_hmon(hmon) + { + } - // the entire area of this monitor in virtual screen coordinates - wxRect m_rect; + virtual wxRect GetGeometry() const; + virtual wxRect GetClientArea() const; + virtual wxString GetName() const; + virtual bool IsPrimary() const; - // the display device name for this monitor, empty initially and retrieved - // on demand by DoGetName() - wxString m_devName; + virtual wxVideoMode GetCurrentMode() const; + virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const; + virtual bool ChangeMode(const wxVideoMode& mode); - wxDisplayInfo() { m_hmon = NULL; } +protected: + // convert a DEVMODE to our wxVideoMode + static wxVideoMode ConvertToVideoMode(const DEVMODE& dm) + { + // note that dmDisplayFrequency may be 0 or 1 meaning "standard one" + // and although 0 is ok for us we don't want to return modes with 1hz + // refresh + return wxVideoMode(dm.dmPelsWidth, + dm.dmPelsHeight, + dm.dmBitsPerPel, + 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: + wxDECLARE_NO_COPY_CLASS(wxDisplayMSW); }; -WX_DECLARE_OBJARRAY(wxDisplayInfo, wxDisplayInfoArray); -#include "wx/arrimpl.cpp" -WX_DEFINE_OBJARRAY(wxDisplayInfoArray); -// this is not really MT-unsafe as wxDisplay is only going to be used from the -// main thread, i.e. we consider that it's a GUI class and so don't protect it -static wxDisplayInfoArray *g_displays = NULL; +// ---------------------------------------------------------------------------- +// wxDisplayFactoryMSW declaration +// ---------------------------------------------------------------------------- + +WX_DEFINE_ARRAY(HMONITOR, wxMonitorHandleArray); +// functions dynamically bound by wxDisplayFactoryMSW ctor. +static MonitorFromPoint_t gs_MonitorFromPoint = NULL; +static MonitorFromWindow_t gs_MonitorFromWindow = NULL; +static GetMonitorInfo_t gs_GetMonitorInfo = NULL; +static EnumDisplayMonitors_t gs_EnumDisplayMonitors = NULL; -// this module is used to cleanup g_displays array -class wxDisplayModule : public wxModule +class wxDisplayFactoryMSW : public wxDisplayFactory { public: - virtual bool OnInit() { return TRUE; } - virtual void OnExit(); + // ctor checks if the current system supports multimon API and dynamically + // bind the functions we need if this is the case and fills the + // m_displays array if they're available + wxDisplayFactoryMSW(); - DECLARE_DYNAMIC_CLASS(wxDisplayModule) -}; + // Dtor destroys the hidden window we use for getting WM_SETTINGCHANGE. + virtual ~wxDisplayFactoryMSW(); -IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule) + bool IsOk() const { return !m_displays.empty(); } -// =========================================================================== -// implementation -// =========================================================================== + virtual wxDisplayImpl *CreateDisplay(unsigned n); + virtual unsigned GetCount() { return unsigned(m_displays.size()); } + virtual int GetFromPoint(const wxPoint& pt); + virtual int GetFromWindow(const wxWindow *window); -// ---------------------------------------------------------------------------- -// local functions -// ---------------------------------------------------------------------------- + // Called when we receive WM_SETTINGCHANGE to refresh the list of monitor + // handles. + static void RefreshMonitors() { ms_factory->DoRefreshMonitors(); } -static BOOL CALLBACK wxmswMonitorEnumProc ( - HMONITOR hMonitor, // handle to display monitor - HDC hdcMonitor, // handle to monitor-appropriate device context (NULL) - LPRECT lprcMonitor, // pointer to monitor intersection rectangle - LPARAM dwData // data passed from EnumDisplayMonitors (unused) -) -{ - wxDisplayInfo* info = new wxDisplayInfo(); - // we need hMonitor to be able to map display id to it which is needed for - // MonitorXXX() functions, in particular MonitorFromPoint() - info->m_hmon = hMonitor; +private: + // EnumDisplayMonitors() callback + static BOOL CALLBACK MultimonEnumProc(HMONITOR hMonitor, + HDC hdcMonitor, + LPRECT lprcMonitor, + LPARAM dwData); - // we also store the display geometry - info->m_rect.SetX ( lprcMonitor->left ); - info->m_rect.SetY ( lprcMonitor->top ); - info->m_rect.SetWidth ( lprcMonitor->right - lprcMonitor->left ); - info->m_rect.SetHeight ( lprcMonitor->bottom - lprcMonitor->top ); + // find the monitor corresponding to the given handle, + // return wxNOT_FOUND if not found + int FindDisplayFromHMONITOR(HMONITOR hmon) const; - // now add this monitor to the array - g_displays->Add(info); + // Update m_displays array, used by RefreshMonitors(). + void DoRefreshMonitors(); - // continue the enumeration - return TRUE; -} -// this function must be called before accessing g_displays array as it -// creates and initializes it -static void InitDisplays() -{ - if ( g_displays ) - return; + // 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; - g_displays = new wxDisplayInfoArray(); - // enumerate all displays - if ( !::EnumDisplayMonitors(NULL, NULL, wxmswMonitorEnumProc, 0) ) - { - wxLogLastError(wxT("EnumDisplayMonitors")); + // the array containing information about all available displays, filled by + // MultimonEnumProc() + wxMonitorHandleArray m_displays; - // TODO: still create at least one (valid) entry in g_displays for the - // primary display! - } -} + // The hidden window we use for receiving WM_SETTINGCHANGE and its class + // name. + HWND m_hiddenHwnd; + const wxChar* m_hiddenClass; -// convert a DEVMODE to our wxVideoMode -wxVideoMode ConvertToVideoMode(const DEVMODE& dm) -{ - // note that dmDisplayFrequency may be 0 or 1 meaning "standard one" and - // although 0 is ok for us we don't want to return modes with 1hz refresh - return wxVideoMode(dm.dmPelsWidth, - dm.dmPelsHeight, - dm.dmBitsPerPel, - dm.dmDisplayFrequency > 1 ? dm.dmDisplayFrequency : 0); -} + wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryMSW); +}; -// emulation of ChangeDisplaySettingsEx() for Win95 -LONG WINAPI ChangeDisplaySettingsExForWin95(LPCTSTR WXUNUSED(lpszDeviceName), - LPDEVMODE lpDevMode, - HWND WXUNUSED(hwnd), - DWORD dwFlags, - LPVOID WXUNUSED(lParam)) -{ - return ::ChangeDisplaySettings(lpDevMode, dwFlags); -} +wxDisplayFactoryMSW* wxDisplayFactoryMSW::ms_factory = NULL; // ---------------------------------------------------------------------------- -// wxDisplayModule +// wxDisplay implementation // ---------------------------------------------------------------------------- -void wxDisplayModule::OnExit() +/* static */ wxDisplayFactory *wxDisplay::CreateFactory() { - delete g_displays; + wxDisplayFactoryMSW *factoryMM = new wxDisplayFactoryMSW; + + if ( factoryMM->IsOk() ) + return factoryMM; + + delete factoryMM; + + // fall back to a stub implementation if no multimon support (Win95?) + return new wxDisplayFactorySingle; } -// --------------------------------------------------------------------------- -// wxDisplay -// --------------------------------------------------------------------------- -// helper of GetFromPoint() and GetFromWindow() -static int DisplayFromHMONITOR(HMONITOR hmon) +// ---------------------------------------------------------------------------- +// wxDisplayMSW implementation +// ---------------------------------------------------------------------------- + +bool wxDisplayMSW::GetMonInfo(MONITORINFOEX& monInfo) const { - if ( hmon ) + if ( !gs_GetMonitorInfo(m_hmon, &monInfo) ) { - const size_t count = wxDisplay::GetCount(); - - for ( size_t n = 0; n < count; n++ ) - { - if ( hmon == (*g_displays)[n].m_hmon ) - return n; - } + wxLogLastError(wxT("GetMonitorInfo")); + return false; } - return wxNOT_FOUND; + return true; } -/* static */ -size_t wxDisplayBase::GetCount() +wxRect wxDisplayMSW::GetGeometry() const { - InitDisplays(); + WinStruct monInfo; - // I'm not sure if they really always return the same thing and if this is - // not true I'd like to know in which situation does it happen - wxASSERT_MSG( g_displays->GetCount() == (size_t)::GetSystemMetrics(SM_CMONITORS), - _T("So how many displays does this system have?") ); + wxRect rect; + if ( GetMonInfo(monInfo) ) + wxCopyRECTToRect(monInfo.rcMonitor, rect); - return g_displays->GetCount(); + return rect; } -/* static */ -int wxDisplayBase::GetFromPoint ( const wxPoint& pt ) +wxRect wxDisplayMSW::GetClientArea() const { - POINT pt2; - pt2.x = pt.x; - pt2.y = pt.y; + WinStruct monInfo; - return DisplayFromHMONITOR(::MonitorFromPoint(pt2, MONITOR_DEFAULTTONULL)); -} + wxRect rectClient; + if ( GetMonInfo(monInfo) ) + wxCopyRECTToRect(monInfo.rcWork, rectClient); -/* static */ -int wxDisplayBase::GetFromWindow(wxWindow *window) -{ - return DisplayFromHMONITOR - ( - ::MonitorFromWindow(GetHwndOf(window), MONITOR_DEFAULTTONULL) - ); + return rectClient; } -wxDisplay::wxDisplay ( size_t n ) - : wxDisplayBase ( n ) +wxString wxDisplayMSW::GetName() const { - // if we do this in ctor we won't have to call it from all the member - // functions - InitDisplays(); -} + WinStruct monInfo; -wxRect wxDisplay::GetGeometry() const -{ - return (*g_displays)[m_index].m_rect; + wxString name; + if ( GetMonInfo(monInfo) ) + name = monInfo.szDevice; + + return name; } -wxString wxDisplay::GetName() const +bool wxDisplayMSW::IsPrimary() const { - wxDisplayInfo& dpyInfo = (*g_displays)[m_index]; - if ( dpyInfo.m_devName.empty() ) - { - MONITORINFOEX monInfo; - wxZeroMemory(monInfo); - monInfo.cbSize = sizeof(monInfo); + WinStruct monInfo; - if ( !::GetMonitorInfo(dpyInfo.m_hmon, &monInfo) ) - { - wxLogLastError(_T("GetMonitorInfo")); - } - else - { - dpyInfo.m_devName = monInfo.szDevice; - } - } + if ( !GetMonInfo(monInfo) ) + return false; - return dpyInfo.m_devName; + return (monInfo.dwFlags & MONITORINFOF_PRIMARY) != 0; } -wxString wxDisplay::GetNameForEnumSettings() const +wxVideoMode wxDisplayMSW::GetCurrentMode() const { - int major, minor; - const bool isWin95 = wxGetOsVersion(&major, &minor) == wxWIN95 && - major == 4 && minor == 0; + wxVideoMode mode; - // the first parameter of EnumDisplaySettings() must be NULL under Win95 - // according to MSDN but GetMonitorInfo() stub in multimon.h still returns - // something even in this case, so we have to correct this manually - wxString name; - if ( !isWin95 ) - name = GetName(); + // The first parameter of EnumDisplaySettings() must be NULL under Win95 + // according to MSDN. The version of GetName() we implement for Win95 + // returns an empty string. + const wxString name = GetName(); + const wxChar * const deviceName = name.empty() + ? (const wxChar*)NULL + : (const wxChar*)name.c_str(); - return name; + DEVMODE dm; + dm.dmSize = sizeof(dm); + dm.dmDriverExtra = 0; + + if ( !::EnumDisplaySettings(deviceName, ENUM_CURRENT_SETTINGS, &dm) ) + { + wxLogLastError(wxT("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)")); + } + else + { + mode = ConvertToVideoMode(dm); + } + + return mode; } -wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& modeMatch) const +wxArrayVideoModes wxDisplayMSW::GetModes(const wxVideoMode& modeMatch) const { wxArrayVideoModes modes; - const wxString name = GetNameForEnumSettings(); - - const wxChar * const deviceName = name.empty() ? NULL : name.c_str(); + // The first parameter of EnumDisplaySettings() must be NULL under Win95 + // according to MSDN. The version of GetName() we implement for Win95 + // returns an empty string. + const wxString name = GetName(); + const wxChar * const deviceName = name.empty() + ? (const wxChar*)NULL + : (const wxChar*)name.c_str(); DEVMODE dm; + dm.dmSize = sizeof(dm); + dm.dmDriverExtra = 0; + for ( int iModeNum = 0; ::EnumDisplaySettings(deviceName, iModeNum, &dm); iModeNum++ ) @@ -327,32 +356,12 @@ wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& modeMatch) const return modes; } -wxVideoMode wxDisplay::GetCurrentMode() const +bool wxDisplayMSW::ChangeMode(const wxVideoMode& mode) { - wxVideoMode mode; - - const wxString name = GetNameForEnumSettings(); - + // prepare ChangeDisplaySettingsEx() parameters DEVMODE dm; - if ( !::EnumDisplaySettings(name.empty() ? NULL : name.c_str(), - ENUM_CURRENT_SETTINGS, - &dm) ) - { - wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)")); - } - else - { - mode = ConvertToVideoMode(dm); - } - - return mode; -} + DEVMODE *pDevMode; -bool wxDisplay::ChangeMode(const wxVideoMode& mode) -{ - // prepare ChangeDisplaySettingsEx() parameters - DEVMODE dm, - *pDevMode; int flags; if ( mode == wxDefaultVideoMode ) @@ -363,30 +372,35 @@ bool wxDisplay::ChangeMode(const wxVideoMode& mode) } else // change to the given mode { - wxCHECK_MSG( mode.w && mode.h, FALSE, - _T("at least the width and height must be specified") ); + wxCHECK_MSG( mode.GetWidth() && mode.GetHeight(), false, + wxT("at least the width and height must be specified") ); wxZeroMemory(dm); dm.dmSize = sizeof(dm); + dm.dmDriverExtra = 0; dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; - dm.dmPelsWidth = mode.w; - dm.dmPelsHeight = mode.h; + dm.dmPelsWidth = mode.GetWidth(); + dm.dmPelsHeight = mode.GetHeight(); - if ( mode.bpp ) + if ( mode.GetDepth() ) { dm.dmFields |= DM_BITSPERPEL; - dm.dmBitsPerPel = mode.bpp; + dm.dmBitsPerPel = mode.GetDepth(); } - if ( mode.refresh ) + if ( mode.GetRefresh() ) { dm.dmFields |= DM_DISPLAYFREQUENCY; - dm.dmDisplayFrequency = mode.refresh; + dm.dmDisplayFrequency = mode.GetRefresh(); } pDevMode = &dm; +#ifdef __WXWINCE__ + flags = 0; +#else // !__WXWINCE__ flags = CDS_FULLSCREEN; +#endif // __WXWINCE__/!__WXWINCE__ } @@ -397,46 +411,231 @@ bool wxDisplay::ChangeMode(const wxVideoMode& mode) static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx = NULL; if ( !pfnChangeDisplaySettingsEx ) { - wxDynamicLibrary dllUser32(_T("user32.dll")); - if ( dllUser32.IsLoaded() ) + wxDynamicLibrary dllDisplay(displayDllName, wxDL_VERBATIM | wxDL_QUIET); + if ( dllDisplay.IsLoaded() ) { - pfnChangeDisplaySettingsEx = (ChangeDisplaySettingsEx_t) - dllUser32.GetSymbol(WINFUNC(ChangeDisplaySettingsEx)); + wxDL_INIT_FUNC_AW(pfn, ChangeDisplaySettingsEx, dllDisplay); } - //else: huh, no user32.dll?? + //else: huh, no this DLL must always be present, what's going on?? +#ifndef __WXWINCE__ if ( !pfnChangeDisplaySettingsEx ) { // we must be under Win95 and so there is no multiple monitors // support anyhow pfnChangeDisplaySettingsEx = ChangeDisplaySettingsExForWin95; } +#endif // !__WXWINCE__ } // do change the mode switch ( pfnChangeDisplaySettingsEx ( - GetName(), // display name - pDevMode, // dev mode or NULL to reset - NULL, // reserved + GetName().t_str(), // display name + pDevMode, // dev mode or NULL to reset + NULL, // reserved flags, - NULL // pointer to video parameters (not used) + NULL // pointer to video parameters (not used) ) ) { case DISP_CHANGE_SUCCESSFUL: // ok - return TRUE; + { + // If we have a top-level, full-screen frame, emulate + // 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); + if (frameTop && frameTop->IsFullScreen()) + { + wxVideoMode current = GetCurrentMode(); + frameTop->SetClientSize(current.GetWidth(), current.GetHeight()); + } + } + return true; case DISP_CHANGE_BADMODE: // don't complain about this, this is the only "expected" error break; default: - wxFAIL_MSG( _T("unexpected ChangeDisplaySettingsEx() return value") ); + wxFAIL_MSG( wxT("unexpected ChangeDisplaySettingsEx() return value") ); + } + + return false; +} + + +// ---------------------------------------------------------------------------- +// 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 ) + { + // First initialization, or last initialization failed. + wxDynamicLibrary dllDisplay(displayDllName, wxDL_VERBATIM | wxDL_QUIET); + + wxDL_INIT_FUNC(gs_, MonitorFromPoint, dllDisplay); + wxDL_INIT_FUNC(gs_, MonitorFromWindow, dllDisplay); + wxDL_INIT_FUNC_AW(gs_, GetMonitorInfo, dllDisplay); + wxDL_INIT_FUNC(gs_, EnumDisplayMonitors, dllDisplay); + + // we can safely let dllDisplay go out of scope, the DLL itself will + // still remain loaded as all programs link to it statically anyhow + } + + if ( gs_MonitorFromPoint==NULL || gs_MonitorFromWindow==NULL + || gs_GetMonitorInfo==NULL || gs_EnumDisplayMonitors==NULL ) + return; + + 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)")); + } + } } - return FALSE; + ms_factory = NULL; +} + +void wxDisplayFactoryMSW::DoRefreshMonitors() +{ + m_displays.Clear(); + + if ( !gs_EnumDisplayMonitors(NULL, NULL, MultimonEnumProc, (LPARAM)this) ) + { + wxLogLastError(wxT("EnumDisplayMonitors")); + } +} + +/* static */ +BOOL CALLBACK +wxDisplayFactoryMSW::MultimonEnumProc( + HMONITOR hMonitor, // handle to display monitor + HDC WXUNUSED(hdcMonitor), // handle to monitor-appropriate device context + LPRECT WXUNUSED(lprcMonitor), // pointer to monitor intersection rectangle + LPARAM dwData) // data passed from EnumDisplayMonitors (this) +{ + wxDisplayFactoryMSW *const self = (wxDisplayFactoryMSW *)dwData; + + self->m_displays.Add(hMonitor); + + // continue the enumeration + return TRUE; +} + +wxDisplayImpl *wxDisplayFactoryMSW::CreateDisplay(unsigned n) +{ + wxCHECK_MSG( n < m_displays.size(), NULL, wxT("An invalid index was passed to wxDisplay") ); + + return new wxDisplayMSW(n, m_displays[n]); +} + +// helper for GetFromPoint() and GetFromWindow() +int wxDisplayFactoryMSW::FindDisplayFromHMONITOR(HMONITOR hmon) const +{ + if ( hmon ) + { + const size_t count = m_displays.size(); + for ( size_t n = 0; n < count; n++ ) + { + if ( hmon == m_displays[n] ) + return n; + } + } + + return wxNOT_FOUND; +} + +int wxDisplayFactoryMSW::GetFromPoint(const wxPoint& pt) +{ + POINT pt2; + pt2.x = pt.x; + pt2.y = pt.y; + + return FindDisplayFromHMONITOR(gs_MonitorFromPoint(pt2, + MONITOR_DEFAULTTONULL)); +} + +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 +}