1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/display.cpp
3 // Purpose: MSW Implementation of wxDisplay class
4 // Author: Royce Mitchell III, Vadim Zeitlin
5 // Modified by: Ryan Norton (IsPrimary override)
8 // Copyright: (c) wxWidgets team
9 // Copyright: (c) 2002-2006 wxWidgets team
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
13 // ===========================================================================
15 // ===========================================================================
17 // ---------------------------------------------------------------------------
19 // ---------------------------------------------------------------------------
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
30 #include "wx/display.h"
33 #include "wx/dynarray.h"
38 #include "wx/dynload.h"
39 #include "wx/sysopt.h"
41 #include "wx/display_impl.h"
42 #include "wx/msw/wrapwin.h"
43 #include "wx/msw/missing.h"
44 #include "wx/msw/private.h"
47 // Older versions of windef.h don't define HMONITOR. Unfortunately, we
48 // can't directly test whether HMONITOR is defined or not in windef.h as
49 // it's not a macro but a typedef, so we test for an unrelated symbol which
50 // is only defined in winuser.h if WINVER >= 0x0500
51 #if !defined(HMONITOR_DECLARED) && !defined(MNS_NOCHECK)
52 DECLARE_HANDLE(HMONITOR
);
53 typedef BOOL(CALLBACK
* MONITORENUMPROC
)(HMONITOR
, HDC
, LPRECT
, LPARAM
);
54 typedef struct tagMONITORINFO
60 } MONITORINFO
, *LPMONITORINFO
;
61 typedef struct tagMONITORINFOEX
: public tagMONITORINFO
63 TCHAR szDevice
[CCHDEVICENAME
];
64 } MONITORINFOEX
, *LPMONITORINFOEX
;
65 #define MONITOR_DEFAULTTONULL 0x00000000
66 #define MONITOR_DEFAULTTOPRIMARY 0x00000001
67 #define MONITOR_DEFAULTTONEAREST 0x00000002
68 #define MONITORINFOF_PRIMARY 0x00000001
69 #define HMONITOR_DECLARED
71 #endif // !__WXWINCE__
73 // display functions are found in different DLLs under WinCE and normal Win32
75 static const wxChar displayDllName
[] = wxT("coredll.dll");
77 static const wxChar displayDllName
[] = wxT("user32.dll");
80 // ----------------------------------------------------------------------------
81 // typedefs for dynamically loaded Windows functions
82 // ----------------------------------------------------------------------------
84 typedef LONG (WINAPI
*ChangeDisplaySettingsEx_t
)(LPCTSTR lpszDeviceName
,
90 typedef BOOL (WINAPI
*EnumDisplayMonitors_t
)(HDC
,LPCRECT
,MONITORENUMPROC
,LPARAM
);
91 typedef HMONITOR (WINAPI
*MonitorFromPoint_t
)(POINT
,DWORD
);
92 typedef HMONITOR (WINAPI
*MonitorFromWindow_t
)(HWND
,DWORD
);
93 typedef BOOL (WINAPI
*GetMonitorInfo_t
)(HMONITOR
,LPMONITORINFO
);
96 // emulation of ChangeDisplaySettingsEx() for Win95
97 LONG WINAPI
ChangeDisplaySettingsExForWin95(LPCTSTR
WXUNUSED(lpszDeviceName
),
101 LPVOID
WXUNUSED(lParam
))
103 return ::ChangeDisplaySettings(lpDevMode
, dwFlags
);
105 #endif // !__WXWINCE__
108 // ----------------------------------------------------------------------------
109 // wxDisplayMSW declaration
110 // ----------------------------------------------------------------------------
112 class wxDisplayMSW
: public wxDisplayImpl
115 wxDisplayMSW(unsigned n
, HMONITOR hmon
)
121 virtual wxRect
GetGeometry() const;
122 virtual wxRect
GetClientArea() const;
123 virtual wxString
GetName() const;
124 virtual bool IsPrimary() const;
126 virtual wxVideoMode
GetCurrentMode() const;
127 virtual wxArrayVideoModes
GetModes(const wxVideoMode
& mode
) const;
128 virtual bool ChangeMode(const wxVideoMode
& mode
);
131 // convert a DEVMODE to our wxVideoMode
132 static wxVideoMode
ConvertToVideoMode(const DEVMODE
& dm
)
134 // note that dmDisplayFrequency may be 0 or 1 meaning "standard one"
135 // and although 0 is ok for us we don't want to return modes with 1hz
137 return wxVideoMode(dm
.dmPelsWidth
,
140 dm
.dmDisplayFrequency
> 1 ? dm
.dmDisplayFrequency
: 0);
143 // Call GetMonitorInfo() and fill in the provided struct and return true if
144 // it succeeded, otherwise return false.
145 bool GetMonInfo(MONITORINFOEX
& monInfo
) const;
150 wxDECLARE_NO_COPY_CLASS(wxDisplayMSW
);
154 // ----------------------------------------------------------------------------
155 // wxDisplayFactoryMSW declaration
156 // ----------------------------------------------------------------------------
158 WX_DEFINE_ARRAY(HMONITOR
, wxMonitorHandleArray
);
160 // functions dynamically bound by wxDisplayFactoryMSW ctor.
161 static MonitorFromPoint_t gs_MonitorFromPoint
= NULL
;
162 static MonitorFromWindow_t gs_MonitorFromWindow
= NULL
;
163 static GetMonitorInfo_t gs_GetMonitorInfo
= NULL
;
164 static EnumDisplayMonitors_t gs_EnumDisplayMonitors
= NULL
;
166 class wxDisplayFactoryMSW
: public wxDisplayFactory
169 // ctor checks if the current system supports multimon API and dynamically
170 // bind the functions we need if this is the case and fills the
171 // m_displays array if they're available
172 wxDisplayFactoryMSW();
174 bool IsOk() const { return !m_displays
.empty(); }
176 virtual wxDisplayImpl
*CreateDisplay(unsigned n
);
177 virtual unsigned GetCount() { return unsigned(m_displays
.size()); }
178 virtual int GetFromPoint(const wxPoint
& pt
);
179 virtual int GetFromWindow(const wxWindow
*window
);
182 // EnumDisplayMonitors() callback
183 static BOOL CALLBACK
MultimonEnumProc(HMONITOR hMonitor
,
188 // find the monitor corresponding to the given handle,
189 // return wxNOT_FOUND if not found
190 int FindDisplayFromHMONITOR(HMONITOR hmon
) const;
192 // the array containing information about all available displays, filled by
193 // MultimonEnumProc()
194 wxMonitorHandleArray m_displays
;
196 wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryMSW
);
200 // ----------------------------------------------------------------------------
201 // wxDisplay implementation
202 // ----------------------------------------------------------------------------
204 /* static */ wxDisplayFactory
*wxDisplay::CreateFactory()
206 wxDisplayFactoryMSW
*factoryMM
= new wxDisplayFactoryMSW
;
208 if ( factoryMM
->IsOk() )
213 // fall back to a stub implementation if no multimon support (Win95?)
214 return new wxDisplayFactorySingle
;
218 // ----------------------------------------------------------------------------
219 // wxDisplayMSW implementation
220 // ----------------------------------------------------------------------------
222 bool wxDisplayMSW::GetMonInfo(MONITORINFOEX
& monInfo
) const
224 if ( !gs_GetMonitorInfo(m_hmon
, &monInfo
) )
226 wxLogLastError(wxT("GetMonitorInfo"));
233 wxRect
wxDisplayMSW::GetGeometry() const
235 WinStruct
<MONITORINFOEX
> monInfo
;
238 if ( GetMonInfo(monInfo
) )
239 wxCopyRECTToRect(monInfo
.rcMonitor
, rect
);
244 wxRect
wxDisplayMSW::GetClientArea() const
246 WinStruct
<MONITORINFOEX
> monInfo
;
249 if ( GetMonInfo(monInfo
) )
250 wxCopyRECTToRect(monInfo
.rcWork
, rectClient
);
255 wxString
wxDisplayMSW::GetName() const
257 WinStruct
<MONITORINFOEX
> monInfo
;
260 if ( GetMonInfo(monInfo
) )
261 name
= monInfo
.szDevice
;
266 bool wxDisplayMSW::IsPrimary() const
268 WinStruct
<MONITORINFOEX
> monInfo
;
270 if ( !GetMonInfo(monInfo
) )
273 return (monInfo
.dwFlags
& MONITORINFOF_PRIMARY
) != 0;
276 wxVideoMode
wxDisplayMSW::GetCurrentMode() const
280 // The first parameter of EnumDisplaySettings() must be NULL under Win95
281 // according to MSDN. The version of GetName() we implement for Win95
282 // returns an empty string.
283 const wxString name
= GetName();
284 const wxChar
* const deviceName
= name
.empty()
285 ? (const wxChar
*)NULL
286 : (const wxChar
*)name
.c_str();
289 dm
.dmSize
= sizeof(dm
);
290 dm
.dmDriverExtra
= 0;
292 if ( !::EnumDisplaySettings(deviceName
, ENUM_CURRENT_SETTINGS
, &dm
) )
294 wxLogLastError(wxT("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
298 mode
= ConvertToVideoMode(dm
);
304 wxArrayVideoModes
wxDisplayMSW::GetModes(const wxVideoMode
& modeMatch
) const
306 wxArrayVideoModes modes
;
308 // The first parameter of EnumDisplaySettings() must be NULL under Win95
309 // according to MSDN. The version of GetName() we implement for Win95
310 // returns an empty string.
311 const wxString name
= GetName();
312 const wxChar
* const deviceName
= name
.empty()
313 ? (const wxChar
*)NULL
314 : (const wxChar
*)name
.c_str();
317 dm
.dmSize
= sizeof(dm
);
318 dm
.dmDriverExtra
= 0;
320 for ( int iModeNum
= 0;
321 ::EnumDisplaySettings(deviceName
, iModeNum
, &dm
);
324 const wxVideoMode mode
= ConvertToVideoMode(dm
);
325 if ( mode
.Matches(modeMatch
) )
334 bool wxDisplayMSW::ChangeMode(const wxVideoMode
& mode
)
336 // prepare ChangeDisplaySettingsEx() parameters
342 if ( mode
== wxDefaultVideoMode
)
344 // reset the video mode to default
348 else // change to the given mode
350 wxCHECK_MSG( mode
.GetWidth() && mode
.GetHeight(), false,
351 wxT("at least the width and height must be specified") );
354 dm
.dmSize
= sizeof(dm
);
355 dm
.dmDriverExtra
= 0;
356 dm
.dmFields
= DM_PELSWIDTH
| DM_PELSHEIGHT
;
357 dm
.dmPelsWidth
= mode
.GetWidth();
358 dm
.dmPelsHeight
= mode
.GetHeight();
360 if ( mode
.GetDepth() )
362 dm
.dmFields
|= DM_BITSPERPEL
;
363 dm
.dmBitsPerPel
= mode
.GetDepth();
366 if ( mode
.GetRefresh() )
368 dm
.dmFields
|= DM_DISPLAYFREQUENCY
;
369 dm
.dmDisplayFrequency
= mode
.GetRefresh();
376 #else // !__WXWINCE__
377 flags
= CDS_FULLSCREEN
;
378 #endif // __WXWINCE__/!__WXWINCE__
382 // get pointer to the function dynamically
384 // we're only called from the main thread, so it's ok to use static
386 static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx
= NULL
;
387 if ( !pfnChangeDisplaySettingsEx
)
389 wxDynamicLibrary
dllDisplay(displayDllName
, wxDL_VERBATIM
| wxDL_QUIET
);
390 if ( dllDisplay
.IsLoaded() )
392 wxDL_INIT_FUNC_AW(pfn
, ChangeDisplaySettingsEx
, dllDisplay
);
394 //else: huh, no this DLL must always be present, what's going on??
397 if ( !pfnChangeDisplaySettingsEx
)
399 // we must be under Win95 and so there is no multiple monitors
401 pfnChangeDisplaySettingsEx
= ChangeDisplaySettingsExForWin95
;
403 #endif // !__WXWINCE__
406 // do change the mode
407 switch ( pfnChangeDisplaySettingsEx
409 GetName().wx_str(), // display name
410 pDevMode
, // dev mode or NULL to reset
413 NULL
// pointer to video parameters (not used)
416 case DISP_CHANGE_SUCCESSFUL
:
419 // If we have a top-level, full-screen frame, emulate
420 // the DirectX behaviour and resize it. This makes this
421 // API quite a bit easier to use.
422 wxWindow
*winTop
= wxTheApp
->GetTopWindow();
423 wxFrame
*frameTop
= wxDynamicCast(winTop
, wxFrame
);
424 if (frameTop
&& frameTop
->IsFullScreen())
426 wxVideoMode current
= GetCurrentMode();
427 frameTop
->SetClientSize(current
.GetWidth(), current
.GetHeight());
432 case DISP_CHANGE_BADMODE
:
433 // don't complain about this, this is the only "expected" error
437 wxFAIL_MSG( wxT("unexpected ChangeDisplaySettingsEx() return value") );
444 // ----------------------------------------------------------------------------
445 // wxDisplayFactoryMSW implementation
446 // ----------------------------------------------------------------------------
448 wxDisplayFactoryMSW::wxDisplayFactoryMSW()
450 if ( gs_MonitorFromPoint
==NULL
|| gs_MonitorFromWindow
==NULL
451 || gs_GetMonitorInfo
==NULL
|| gs_EnumDisplayMonitors
==NULL
)
453 // First initialization, or last initialization failed.
454 wxDynamicLibrary
dllDisplay(displayDllName
, wxDL_VERBATIM
| wxDL_QUIET
);
456 wxDL_INIT_FUNC(gs_
, MonitorFromPoint
, dllDisplay
);
457 wxDL_INIT_FUNC(gs_
, MonitorFromWindow
, dllDisplay
);
458 wxDL_INIT_FUNC_AW(gs_
, GetMonitorInfo
, dllDisplay
);
459 wxDL_INIT_FUNC(gs_
, EnumDisplayMonitors
, dllDisplay
);
461 // we can safely let dllDisplay go out of scope, the DLL itself will
462 // still remain loaded as all programs link to it statically anyhow
465 if ( gs_MonitorFromPoint
==NULL
|| gs_MonitorFromWindow
==NULL
466 || gs_GetMonitorInfo
==NULL
|| gs_EnumDisplayMonitors
==NULL
)
469 // enumerate all displays
470 if ( !gs_EnumDisplayMonitors(NULL
, NULL
, MultimonEnumProc
, (LPARAM
)this) )
472 wxLogLastError(wxT("EnumDisplayMonitors"));
478 wxDisplayFactoryMSW::MultimonEnumProc(
479 HMONITOR hMonitor
, // handle to display monitor
480 HDC
WXUNUSED(hdcMonitor
), // handle to monitor-appropriate device context
481 LPRECT
WXUNUSED(lprcMonitor
), // pointer to monitor intersection rectangle
482 LPARAM dwData
) // data passed from EnumDisplayMonitors (this)
484 wxDisplayFactoryMSW
*const self
= (wxDisplayFactoryMSW
*)dwData
;
486 self
->m_displays
.Add(hMonitor
);
488 // continue the enumeration
492 wxDisplayImpl
*wxDisplayFactoryMSW::CreateDisplay(unsigned n
)
494 wxCHECK_MSG( n
< m_displays
.size(), NULL
, wxT("An invalid index was passed to wxDisplay") );
496 return new wxDisplayMSW(n
, m_displays
[n
]);
499 // helper for GetFromPoint() and GetFromWindow()
500 int wxDisplayFactoryMSW::FindDisplayFromHMONITOR(HMONITOR hmon
) const
504 const size_t count
= m_displays
.size();
505 for ( size_t n
= 0; n
< count
; n
++ )
507 if ( hmon
== m_displays
[n
] )
515 int wxDisplayFactoryMSW::GetFromPoint(const wxPoint
& pt
)
521 return FindDisplayFromHMONITOR(gs_MonitorFromPoint(pt2
,
522 MONITOR_DEFAULTTONULL
));
525 int wxDisplayFactoryMSW::GetFromWindow(const wxWindow
*window
)
527 return FindDisplayFromHMONITOR(gs_MonitorFromWindow(GetHwndOf(window
),
528 MONITOR_DEFAULTTONULL
));
531 #endif // wxUSE_DISPLAY