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__
107 // ----------------------------------------------------------------------------
108 // display information classes
109 // ----------------------------------------------------------------------------
113 wxDisplayInfo(HMONITOR hmon
= NULL
)
119 virtual ~wxDisplayInfo() { }
122 // use GetMonitorInfo() to fill in all of our fields if needed (i.e. if it
123 // hadn't been done before)
127 // handle of this monitor used by MonitorXXX() functions, never NULL
130 // the entire area of this monitor in virtual screen coordinates
133 // the work or client area, i.e. the area available for the normal windows
136 // the display device name for this monitor, empty initially and retrieved
137 // on demand by DoGetName()
140 // the flags of this monitor, also used as initialization marker: if this
141 // is -1, GetMonitorInfo() hadn't been called yet
145 WX_DEFINE_ARRAY_PTR(wxDisplayInfo
*, wxDisplayInfoArray
);
147 // ----------------------------------------------------------------------------
148 // common base class for all Win32 wxDisplayImpl versions
149 // ----------------------------------------------------------------------------
151 class wxDisplayImplWin32Base
: public wxDisplayImpl
154 wxDisplayImplWin32Base(unsigned n
, wxDisplayInfo
& info
)
160 virtual wxRect
GetGeometry() const;
161 virtual wxRect
GetClientArea() const;
162 virtual wxString
GetName() const;
163 virtual bool IsPrimary() const;
165 virtual wxVideoMode
GetCurrentMode() const;
168 // convert a DEVMODE to our wxVideoMode
169 static wxVideoMode
ConvertToVideoMode(const DEVMODE
& dm
)
171 // note that dmDisplayFrequency may be 0 or 1 meaning "standard one"
172 // and although 0 is ok for us we don't want to return modes with 1hz
174 return wxVideoMode(dm
.dmPelsWidth
,
177 dm
.dmDisplayFrequency
> 1 ? dm
.dmDisplayFrequency
: 0);
180 wxDisplayInfo
& m_info
;
183 // ----------------------------------------------------------------------------
184 // common base class for all Win32 wxDisplayFactory versions
185 // ----------------------------------------------------------------------------
187 // functions dynamically bound by wxDisplayFactoryWin32Base::Initialize()
188 static MonitorFromPoint_t gs_MonitorFromPoint
= NULL
;
189 static MonitorFromWindow_t gs_MonitorFromWindow
= NULL
;
190 static GetMonitorInfo_t gs_GetMonitorInfo
= NULL
;
192 class wxDisplayFactoryWin32Base
: public wxDisplayFactory
195 virtual ~wxDisplayFactoryWin32Base();
197 bool IsOk() const { return !m_displays
.empty(); }
199 virtual unsigned GetCount() { return unsigned(m_displays
.size()); }
200 virtual int GetFromPoint(const wxPoint
& pt
);
201 virtual int GetFromWindow(const wxWindow
*window
);
204 // ctor checks if the current system supports multimon API and dynamically
205 // bind the functions we need if this is the case and sets
206 // ms_supportsMultimon if they're available
207 wxDisplayFactoryWin32Base();
209 // delete all m_displays elements: can be called from the derived class
210 // dtor if it is important to do this before destroying it,
211 // otherwise will be done by our dtor
214 // find the monitor corresponding to the given handle, return wxNOT_FOUND
216 int FindDisplayFromHMONITOR(HMONITOR hmon
) const;
219 // flag indicating whether gs_MonitorXXX functions are available
220 static int ms_supportsMultimon
;
222 // the array containing information about all available displays, should be
223 // filled by the derived class ctors
224 wxDisplayInfoArray m_displays
;
227 wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryWin32Base
);
230 // ----------------------------------------------------------------------------
231 // wxDisplay implementation using Windows multi-monitor support functions
232 // ----------------------------------------------------------------------------
234 class wxDisplayImplMultimon
: public wxDisplayImplWin32Base
237 wxDisplayImplMultimon(unsigned n
, wxDisplayInfo
& info
)
238 : wxDisplayImplWin32Base(n
, info
)
242 virtual wxArrayVideoModes
GetModes(const wxVideoMode
& mode
) const;
243 virtual bool ChangeMode(const wxVideoMode
& mode
);
246 wxDECLARE_NO_COPY_CLASS(wxDisplayImplMultimon
);
249 class wxDisplayFactoryMultimon
: public wxDisplayFactoryWin32Base
252 wxDisplayFactoryMultimon();
254 virtual wxDisplayImpl
*CreateDisplay(unsigned n
);
257 // EnumDisplayMonitors() callback
258 static BOOL CALLBACK
MultimonEnumProc(HMONITOR hMonitor
,
263 // add a monitor description to m_displays array
264 void AddDisplay(HMONITOR hMonitor
, LPRECT lprcMonitor
);
268 // ============================================================================
269 // common classes implementation
270 // ============================================================================
272 // ----------------------------------------------------------------------------
274 // ----------------------------------------------------------------------------
276 /* static */ wxDisplayFactory
*wxDisplay::CreateFactory()
278 wxDisplayFactoryMultimon
*factoryMM
= new wxDisplayFactoryMultimon
;
280 if ( factoryMM
->IsOk() )
285 // finally fall back to a stub implementation if all else failed (Win95?)
286 return new wxDisplayFactorySingle
;
290 // ----------------------------------------------------------------------------
292 // ----------------------------------------------------------------------------
294 void wxDisplayInfo::Initialize()
296 if ( m_flags
== (DWORD
)-1 )
298 WinStruct
<MONITORINFOEX
> monInfo
;
299 if ( !gs_GetMonitorInfo(m_hmon
, (LPMONITORINFO
)&monInfo
) )
301 wxLogLastError(wxT("GetMonitorInfo"));
306 wxCopyRECTToRect(monInfo
.rcMonitor
, m_rect
);
307 wxCopyRECTToRect(monInfo
.rcWork
, m_rectClient
);
308 m_devName
= monInfo
.szDevice
;
309 m_flags
= monInfo
.dwFlags
;
313 // ----------------------------------------------------------------------------
314 // wxDisplayImplWin32Base
315 // ----------------------------------------------------------------------------
317 wxRect
wxDisplayImplWin32Base::GetGeometry() const
319 if ( m_info
.m_rect
.IsEmpty() )
322 return m_info
.m_rect
;
325 wxRect
wxDisplayImplWin32Base::GetClientArea() const
327 if ( m_info
.m_rectClient
.IsEmpty() )
330 return m_info
.m_rectClient
;
333 wxString
wxDisplayImplWin32Base::GetName() const
335 if ( m_info
.m_devName
.empty() )
338 return m_info
.m_devName
;
341 bool wxDisplayImplWin32Base::IsPrimary() const
343 if ( m_info
.m_flags
== (DWORD
)-1 )
346 return (m_info
.m_flags
& MONITORINFOF_PRIMARY
) != 0;
349 wxVideoMode
wxDisplayImplWin32Base::GetCurrentMode() const
353 // The first parameter of EnumDisplaySettings() must be NULL under Win95
354 // according to MSDN. The version of GetName() we implement for Win95
355 // returns an empty string.
356 const wxString name
= GetName();
357 const wxChar
* const deviceName
= name
.empty()
358 ? (const wxChar
*)NULL
359 : (const wxChar
*)name
.c_str();
362 dm
.dmSize
= sizeof(dm
);
363 dm
.dmDriverExtra
= 0;
364 if ( !::EnumDisplaySettings(deviceName
, ENUM_CURRENT_SETTINGS
, &dm
) )
366 wxLogLastError(wxT("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
370 mode
= ConvertToVideoMode(dm
);
376 // ----------------------------------------------------------------------------
377 // wxDisplayFactoryWin32Base
378 // ----------------------------------------------------------------------------
380 int wxDisplayFactoryWin32Base::ms_supportsMultimon
= -1;
382 wxDisplayFactoryWin32Base::wxDisplayFactoryWin32Base()
384 if ( ms_supportsMultimon
== -1 )
386 ms_supportsMultimon
= 0;
388 wxDynamicLibrary
dllDisplay(displayDllName
, wxDL_VERBATIM
| wxDL_QUIET
);
390 if ( (wxDL_INIT_FUNC(gs_
, MonitorFromPoint
, dllDisplay
)) == NULL
||
391 (wxDL_INIT_FUNC(gs_
, MonitorFromWindow
, dllDisplay
)) == NULL
||
392 (wxDL_INIT_FUNC_AW(gs_
, GetMonitorInfo
, dllDisplay
)) == NULL
)
395 ms_supportsMultimon
= 1;
397 // we can safely let dllDisplay go out of scope, the DLL itself will
398 // still remain loaded as all programs link to it statically anyhow
402 void wxDisplayFactoryWin32Base::Clear()
404 WX_CLEAR_ARRAY(m_displays
);
407 wxDisplayFactoryWin32Base::~wxDisplayFactoryWin32Base()
412 // helper for GetFromPoint() and GetFromWindow()
413 int wxDisplayFactoryWin32Base::FindDisplayFromHMONITOR(HMONITOR hmon
) const
417 const size_t count
= m_displays
.size();
418 for ( size_t n
= 0; n
< count
; n
++ )
420 if ( hmon
== m_displays
[n
]->m_hmon
)
428 int wxDisplayFactoryWin32Base::GetFromPoint(const wxPoint
& pt
)
434 return FindDisplayFromHMONITOR(gs_MonitorFromPoint(pt2
,
435 MONITOR_DEFAULTTONULL
));
438 int wxDisplayFactoryWin32Base::GetFromWindow(const wxWindow
*window
)
440 return FindDisplayFromHMONITOR(gs_MonitorFromWindow(GetHwndOf(window
),
441 MONITOR_DEFAULTTONULL
));
444 // ============================================================================
445 // wxDisplay implementation using Win32 multimon API
446 // ============================================================================
448 // ----------------------------------------------------------------------------
449 // wxDisplayFactoryMultimon initialization
450 // ----------------------------------------------------------------------------
452 wxDisplayFactoryMultimon::wxDisplayFactoryMultimon()
454 if ( !ms_supportsMultimon
)
457 // look up EnumDisplayMonitors()
458 EnumDisplayMonitors_t pfnEnumDisplayMonitors
;
460 wxDynamicLibrary
dllDisplay(displayDllName
, wxDL_VERBATIM
| wxDL_QUIET
);
461 if ( (wxDL_INIT_FUNC(pfn
, EnumDisplayMonitors
, dllDisplay
)) == NULL
)
465 // enumerate all displays
466 if ( !pfnEnumDisplayMonitors(NULL
, NULL
, MultimonEnumProc
, (LPARAM
)this) )
468 wxLogLastError(wxT("EnumDisplayMonitors"));
474 wxDisplayFactoryMultimon::MultimonEnumProc(
475 HMONITOR hMonitor
, // handle to display monitor
476 HDC
WXUNUSED(hdcMonitor
), // handle to monitor-appropriate device context
477 LPRECT lprcMonitor
, // pointer to monitor intersection rectangle
478 LPARAM dwData
// data passed from EnumDisplayMonitors (this)
481 wxDisplayFactoryMultimon
*const self
= (wxDisplayFactoryMultimon
*)dwData
;
482 self
->AddDisplay(hMonitor
, lprcMonitor
);
484 // continue the enumeration
488 // ----------------------------------------------------------------------------
489 // wxDisplayFactoryMultimon helper functions
490 // ----------------------------------------------------------------------------
492 void wxDisplayFactoryMultimon::AddDisplay(HMONITOR hMonitor
, LPRECT lprcMonitor
)
494 wxDisplayInfo
*info
= new wxDisplayInfo(hMonitor
);
496 // we also store the display geometry
497 info
->m_rect
= wxRect(lprcMonitor
->left
, lprcMonitor
->top
,
498 lprcMonitor
->right
- lprcMonitor
->left
,
499 lprcMonitor
->bottom
- lprcMonitor
->top
);
501 // now add this monitor to the array
502 m_displays
.Add(info
);
505 // ----------------------------------------------------------------------------
506 // wxDisplayFactoryMultimon inherited pure virtuals implementation
507 // ----------------------------------------------------------------------------
509 wxDisplayImpl
*wxDisplayFactoryMultimon::CreateDisplay(unsigned n
)
511 wxCHECK_MSG( n
< m_displays
.size(), NULL
, wxT("invalid display index") );
513 return new wxDisplayImplMultimon(n
, *(m_displays
[n
]));
516 // ----------------------------------------------------------------------------
517 // wxDisplayImplMultimon implementation
518 // ----------------------------------------------------------------------------
521 wxDisplayImplMultimon::GetModes(const wxVideoMode
& modeMatch
) const
523 wxArrayVideoModes modes
;
525 // The first parameter of EnumDisplaySettings() must be NULL under Win95
526 // according to MSDN. The version of GetName() we implement for Win95
527 // returns an empty string.
528 const wxString name
= GetName();
529 const wxChar
* const deviceName
= name
.empty()
530 ? (const wxChar
*)NULL
531 : (const wxChar
*)name
.c_str();
534 dm
.dmSize
= sizeof(dm
);
535 dm
.dmDriverExtra
= 0;
536 for ( int iModeNum
= 0;
537 ::EnumDisplaySettings(deviceName
, iModeNum
, &dm
);
540 const wxVideoMode mode
= ConvertToVideoMode(dm
);
541 if ( mode
.Matches(modeMatch
) )
550 bool wxDisplayImplMultimon::ChangeMode(const wxVideoMode
& mode
)
552 // prepare ChangeDisplaySettingsEx() parameters
558 if ( mode
== wxDefaultVideoMode
)
560 // reset the video mode to default
564 else // change to the given mode
566 wxCHECK_MSG( mode
.GetWidth() && mode
.GetHeight(), false,
567 wxT("at least the width and height must be specified") );
570 dm
.dmSize
= sizeof(dm
);
571 dm
.dmDriverExtra
= 0;
572 dm
.dmFields
= DM_PELSWIDTH
| DM_PELSHEIGHT
;
573 dm
.dmPelsWidth
= mode
.GetWidth();
574 dm
.dmPelsHeight
= mode
.GetHeight();
576 if ( mode
.GetDepth() )
578 dm
.dmFields
|= DM_BITSPERPEL
;
579 dm
.dmBitsPerPel
= mode
.GetDepth();
582 if ( mode
.GetRefresh() )
584 dm
.dmFields
|= DM_DISPLAYFREQUENCY
;
585 dm
.dmDisplayFrequency
= mode
.GetRefresh();
592 #else // !__WXWINCE__
593 flags
= CDS_FULLSCREEN
;
594 #endif // __WXWINCE__/!__WXWINCE__
598 // get pointer to the function dynamically
600 // we're only called from the main thread, so it's ok to use static
602 static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx
= NULL
;
603 if ( !pfnChangeDisplaySettingsEx
)
605 wxDynamicLibrary
dllDisplay(displayDllName
, wxDL_VERBATIM
| wxDL_QUIET
);
606 if ( dllDisplay
.IsLoaded() )
608 wxDL_INIT_FUNC_AW(pfn
, ChangeDisplaySettingsEx
, dllDisplay
);
610 //else: huh, no this DLL must always be present, what's going on??
613 if ( !pfnChangeDisplaySettingsEx
)
615 // we must be under Win95 and so there is no multiple monitors
617 pfnChangeDisplaySettingsEx
= ChangeDisplaySettingsExForWin95
;
619 #endif // !__WXWINCE__
622 // do change the mode
623 switch ( pfnChangeDisplaySettingsEx
625 GetName().wx_str(), // display name
626 pDevMode
, // dev mode or NULL to reset
629 NULL
// pointer to video parameters (not used)
632 case DISP_CHANGE_SUCCESSFUL
:
635 // If we have a top-level, full-screen frame, emulate
636 // the DirectX behavior and resize it. This makes this
637 // API quite a bit easier to use.
638 wxWindow
*winTop
= wxTheApp
->GetTopWindow();
639 wxFrame
*frameTop
= wxDynamicCast(winTop
, wxFrame
);
640 if (frameTop
&& frameTop
->IsFullScreen())
642 wxVideoMode current
= GetCurrentMode();
643 frameTop
->SetClientSize(current
.GetWidth(), current
.GetHeight());
648 case DISP_CHANGE_BADMODE
:
649 // don't complain about this, this is the only "expected" error
653 wxFAIL_MSG( wxT("unexpected ChangeDisplaySettingsEx() return value") );
659 #endif // wxUSE_DISPLAY