]> git.saurik.com Git - wxWidgets.git/blame - src/msw/display.cpp
1. fixed compilation after wxList::compatibility_iterator changes
[wxWidgets.git] / src / msw / display.cpp
CommitLineData
a536e411 1/////////////////////////////////////////////////////////////////////////////
2ad495fb 2// Name: src/msw/display.cpp
a536e411 3// Purpose: MSW Implementation of wxDisplay class
fd921f35
VZ
4// Author: Royce Mitchell III, Vadim Zeitlin
5// Modified by: Ryan Norton (IsPrimary override)
a536e411
JS
6// Created: 06/21/02
7// RCS-ID: $Id$
77ffb593 8// Copyright: (c) wxWidgets team
fd921f35 9// Copyright: (c) 2002-2006 wxWidgets team
65571936 10// Licence: wxWindows licence
a536e411
JS
11/////////////////////////////////////////////////////////////////////////////
12
13// ===========================================================================
14// declarations
15// ===========================================================================
16
17// ---------------------------------------------------------------------------
18// headers
19// ---------------------------------------------------------------------------
20
a536e411
JS
21// For compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23
24#ifdef __BORLANDC__
25 #pragma hdrstop
26#endif
27
28#if wxUSE_DISPLAY
29
30#ifndef WX_PRECOMP
f29cfd77 31 #include "wx/app.h"
a536e411 32 #include "wx/dynarray.h"
f29cfd77 33 #include "wx/frame.h"
a536e411
JS
34#endif
35
8585e2b5 36#include "wx/dynload.h"
ef1717a9 37#include "wx/sysopt.h"
8585e2b5 38
a536e411 39#include "wx/display.h"
ef1717a9 40#include "wx/display_impl.h"
a536e411 41
01c54165
VZ
42// Mingw's w32api headers don't include ddraw.h, though the user may have
43// installed it. If using configure, we actually probe for ddraw.h there
ef1717a9 44// and set wxUSE_DIRECTDRAW. Otherwise, assume we don't have it if using
01c54165
VZ
45// the w32api headers, and that we do otherwise.
46#if !defined HAVE_W32API_H && !defined HAVE_DDRAW_H
ef1717a9
VZ
47 #define HAVE_DDRAW_H
48#endif
49
50// user may disable compilation of DirectDraw code by setting
51// wxUSE_DIRECTDRAW to 0 in the makefile/project settings
52#if defined(HAVE_DDRAW_H) && !defined(wxUSE_DIRECTDRAW)
53 #define wxUSE_DIRECTDRAW 1
a536e411
JS
54#endif
55
2ad495fb 56#ifndef __WXWINCE__
01c54165 57 // Older versions of windef.h don't define HMONITOR. Unfortunately, we
bcc1153a
VZ
58 // can't directly test whether HMONITOR is defined or not in windef.h as
59 // it's not a macro but a typedef, so we test for an unrelated symbol which
60 // is only defined in winuser.h if WINVER >= 0x0500
61 #if !defined(HMONITOR_DECLARED) && !defined(MNS_NOCHECK)
62 DECLARE_HANDLE(HMONITOR);
63 #define HMONITOR_DECLARED
64 #endif
2ad495fb 65#endif // !__WXWINCE__
a536e411 66
ef1717a9 67#ifdef wxUSE_DIRECTDRAW
06efac1f
VZ
68#include <ddraw.h>
69
70// we don't want to link with ddraw.lib which contains the real
71// IID_IDirectDraw2 definition
72const GUID wxIID_IDirectDraw2 =
73 { 0xB3A6F3E0, 0x2B43, 0x11CF, { 0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 } };
ef1717a9 74#endif // wxUSE_DIRECTDRAW
06efac1f 75
a536e411 76// ----------------------------------------------------------------------------
06efac1f 77// typedefs for dynamically loaded Windows functions
a536e411
JS
78// ----------------------------------------------------------------------------
79
8585e2b5
VZ
80typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName,
81 LPDEVMODE lpDevMode,
82 HWND hwnd,
83 DWORD dwFlags,
84 LPVOID lParam);
a536e411 85
ef1717a9 86#ifdef wxUSE_DIRECTDRAW
06efac1f
VZ
87typedef BOOL (PASCAL *DDEnumExCallback_t)(GUID *pGuid,
88 LPTSTR driverDescription,
89 LPTSTR driverName,
90 LPVOID lpContext,
91 HMONITOR hmon);
92
93typedef HRESULT (WINAPI *DirectDrawEnumerateEx_t)(DDEnumExCallback_t lpCallback,
94 LPVOID lpContext,
95 DWORD dwFlags);
96
97typedef HRESULT (WINAPI *DirectDrawCreate_t)(GUID *lpGUID,
98 LPDIRECTDRAW *lplpDD,
99 IUnknown *pUnkOuter);
ef1717a9 100#endif // wxUSE_DIRECTDRAW
01c54165
VZ
101
102typedef BOOL (WINAPI *EnumDisplayMonitors_t)(HDC,LPCRECT,MONITORENUMPROC,LPARAM);
103typedef HMONITOR (WINAPI *MonitorFromPoint_t)(POINT,DWORD);
104typedef HMONITOR (WINAPI *MonitorFromWindow_t)(HWND,DWORD);
105typedef BOOL (WINAPI *GetMonitorInfo_t)(HMONITOR,LPMONITORINFO);
106
ef1717a9
VZ
107#ifndef __WXWINCE__
108// emulation of ChangeDisplaySettingsEx() for Win95
109LONG WINAPI ChangeDisplaySettingsExForWin95(LPCTSTR WXUNUSED(lpszDeviceName),
110 LPDEVMODE lpDevMode,
111 HWND WXUNUSED(hwnd),
112 DWORD dwFlags,
113 LPVOID WXUNUSED(lParam))
114{
115 return ::ChangeDisplaySettings(lpDevMode, dwFlags);
116}
117#endif // !__WXWINCE__
06efac1f 118
8585e2b5 119// ----------------------------------------------------------------------------
ef1717a9 120// display information classes
8585e2b5 121// ----------------------------------------------------------------------------
a536e411 122
ef1717a9 123struct wxDisplayInfo
a536e411 124{
ef1717a9
VZ
125 wxDisplayInfo(HMONITOR hmon = NULL)
126 {
127 m_hmon = hmon;
128 m_flags = (DWORD)-1;
129 }
8585e2b5 130
ef1717a9 131 virtual ~wxDisplayInfo() { }
06efac1f 132
ef1717a9
VZ
133
134 // use GetMonitorInfo() to fill in all of our fields if needed (i.e. if it
135 // hadn't been done before)
136 void Initialize();
137
138
139 // handle of this monitor used by MonitorXXX() functions, never NULL
140 HMONITOR m_hmon;
06efac1f 141
8585e2b5 142 // the entire area of this monitor in virtual screen coordinates
a536e411 143 wxRect m_rect;
8585e2b5 144
6c5d6291
VZ
145 // the work or client area, i.e. the area available for the normal windows
146 wxRect m_rectClient;
147
8585e2b5
VZ
148 // the display device name for this monitor, empty initially and retrieved
149 // on demand by DoGetName()
150 wxString m_devName;
151
ef1717a9
VZ
152 // the flags of this monitor, also used as initialization marker: if this
153 // is -1, GetMonitorInfo() hadn't been called yet
154 DWORD m_flags;
8585e2b5
VZ
155};
156
ef1717a9 157WX_DEFINE_ARRAY_PTR(wxDisplayInfo *, wxDisplayInfoArray);
a536e411 158
06efac1f 159// ----------------------------------------------------------------------------
ef1717a9 160// common base class for all Win32 wxDisplayImpl versions
06efac1f
VZ
161// ----------------------------------------------------------------------------
162
ef1717a9 163class wxDisplayImplWin32Base : public wxDisplayImpl
01c54165 164{
ef1717a9
VZ
165public:
166 wxDisplayImplWin32Base(size_t n, wxDisplayInfo& info)
167 : wxDisplayImpl(n),
168 m_info(info)
01c54165 169 {
01c54165 170 }
01c54165 171
ef1717a9 172 virtual wxRect GetGeometry() const;
6c5d6291 173 virtual wxRect GetClientArea() const;
ef1717a9
VZ
174 virtual wxString GetName() const;
175 virtual bool IsPrimary() const;
06efac1f 176
ef1717a9 177 virtual wxVideoMode GetCurrentMode() const;
06efac1f 178
ef1717a9
VZ
179protected:
180 // convert a DEVMODE to our wxVideoMode
181 static wxVideoMode ConvertToVideoMode(const DEVMODE& dm)
182 {
183 // note that dmDisplayFrequency may be 0 or 1 meaning "standard one"
184 // and although 0 is ok for us we don't want to return modes with 1hz
185 // refresh
186 return wxVideoMode(dm.dmPelsWidth,
187 dm.dmPelsHeight,
188 dm.dmBitsPerPel,
189 dm.dmDisplayFrequency > 1 ? dm.dmDisplayFrequency : 0);
190 }
191
192 wxDisplayInfo& m_info;
193};
a536e411 194
8585e2b5 195// ----------------------------------------------------------------------------
ef1717a9 196// common base class for all Win32 wxDisplayFactory versions
8585e2b5
VZ
197// ----------------------------------------------------------------------------
198
ef1717a9
VZ
199// functions dynamically bound by wxDisplayFactoryWin32Base::Initialize()
200static MonitorFromPoint_t gs_MonitorFromPoint = NULL;
201static MonitorFromWindow_t gs_MonitorFromWindow = NULL;
202static GetMonitorInfo_t gs_GetMonitorInfo = NULL;
8585e2b5 203
ef1717a9
VZ
204class wxDisplayFactoryWin32Base : public wxDisplayFactory
205{
206public:
207 virtual ~wxDisplayFactoryWin32Base();
8585e2b5 208
ef1717a9 209 bool IsOk() const { return !m_displays.empty(); }
8585e2b5 210
ef1717a9
VZ
211 virtual size_t GetCount() { return m_displays.size(); }
212 virtual int GetFromPoint(const wxPoint& pt);
213 virtual int GetFromWindow(wxWindow *window);
a536e411 214
ef1717a9
VZ
215protected:
216 // ctor checks if the current system supports multimon API and dynamically
217 // bind the functions we need if this is the case and sets
218 // ms_supportsMultimon if they're available
219 wxDisplayFactoryWin32Base();
a536e411 220
ef1717a9
VZ
221 // delete all m_displays elements: can be called from the derived class
222 // dtor if it is important to do this before destroying it (as in
223 // wxDisplayFactoryDirectDraw case), otherwise will be done by our dtor
224 void Clear();
06efac1f 225
ef1717a9
VZ
226 // find the monitor corresponding to the given handle, return wxNOT_FOUND
227 // if not found
228 int FindDisplayFromHMONITOR(HMONITOR hmon) const;
06efac1f 229
06efac1f 230
ef1717a9
VZ
231 // flag indicating whether gs_MonitorXXX functions are available
232 static int ms_supportsMultimon;
06efac1f 233
ef1717a9
VZ
234 // the array containing information about all available displays, should be
235 // filled by the derived class ctors
236 wxDisplayInfoArray m_displays;
06efac1f 237
06efac1f 238
ef1717a9
VZ
239 DECLARE_NO_COPY_CLASS(wxDisplayFactoryWin32Base)
240};
06efac1f
VZ
241
242// ----------------------------------------------------------------------------
ef1717a9 243// wxDisplay implementation using Windows multi-monitor support functions
06efac1f
VZ
244// ----------------------------------------------------------------------------
245
ef1717a9 246class wxDisplayImplMultimon : public wxDisplayImplWin32Base
06efac1f 247{
ef1717a9
VZ
248public:
249 wxDisplayImplMultimon(size_t n, wxDisplayInfo& info)
250 : wxDisplayImplWin32Base(n, info)
251 {
252 }
a536e411 253
ef1717a9
VZ
254 virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
255 virtual bool ChangeMode(const wxVideoMode& mode);
a536e411 256
ef1717a9
VZ
257private:
258 DECLARE_NO_COPY_CLASS(wxDisplayImplMultimon)
259};
06efac1f 260
d14e03f5 261class wxDisplayFactoryMultimon : public wxDisplayFactoryWin32Base
ef1717a9
VZ
262{
263public:
264 wxDisplayFactoryMultimon();
06efac1f 265
ef1717a9 266 virtual wxDisplayImpl *CreateDisplay(size_t n);
06efac1f 267
ef1717a9
VZ
268private:
269 // EnumDisplayMonitors() callback
270 static BOOL CALLBACK MultimonEnumProc(HMONITOR hMonitor,
271 HDC hdcMonitor,
272 LPRECT lprcMonitor,
273 LPARAM dwData);
06efac1f 274
06efac1f 275
ef1717a9
VZ
276 // add a monitor description to m_displays array
277 void AddDisplay(HMONITOR hMonitor, LPRECT lprcMonitor);
278};
06efac1f 279
ef1717a9
VZ
280// ----------------------------------------------------------------------------
281// wxDisplay implementation using DirectDraw
282// ----------------------------------------------------------------------------
06efac1f 283
ef1717a9
VZ
284#ifdef wxUSE_DIRECTDRAW
285
286struct wxDisplayInfoDirectDraw : wxDisplayInfo
06efac1f 287{
ef1717a9
VZ
288 wxDisplayInfoDirectDraw(const GUID& guid, HMONITOR hmon, LPTSTR name)
289 : wxDisplayInfo(hmon),
290 m_guid(guid)
a536e411 291 {
ef1717a9
VZ
292 m_pDD2 = NULL;
293 m_devName = name;
294 }
8585e2b5 295
ef1717a9
VZ
296 virtual ~wxDisplayInfoDirectDraw()
297 {
298 if ( m_pDD2 )
299 m_pDD2->Release();
a536e411
JS
300 }
301
06efac1f 302
ef1717a9
VZ
303 // IDirectDraw object used to control this display, may be NULL
304 IDirectDraw2 *m_pDD2;
305
306 // DirectDraw GUID for this display, only valid when using DirectDraw
307 const GUID m_guid;
308
309
310 DECLARE_NO_COPY_CLASS(wxDisplayInfoDirectDraw)
311};
06efac1f 312
ef1717a9
VZ
313class wxDisplayImplDirectDraw : public wxDisplayImplWin32Base
314{
315public:
316 wxDisplayImplDirectDraw(size_t n, wxDisplayInfo& info, IDirectDraw2 *pDD2)
317 : wxDisplayImplWin32Base(n, info),
318 m_pDD2(pDD2)
06efac1f 319 {
ef1717a9
VZ
320 m_pDD2->AddRef();
321 }
06efac1f 322
ef1717a9
VZ
323 virtual ~wxDisplayImplDirectDraw()
324 {
325 m_pDD2->Release();
06efac1f 326 }
06efac1f 327
ef1717a9
VZ
328 virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
329 virtual bool ChangeMode(const wxVideoMode& mode);
a536e411 330
ef1717a9
VZ
331private:
332 IDirectDraw2 *m_pDD2;
a536e411 333
ef1717a9
VZ
334 DECLARE_NO_COPY_CLASS(wxDisplayImplDirectDraw)
335};
a536e411 336
d14e03f5 337class wxDisplayFactoryDirectDraw : public wxDisplayFactoryWin32Base
8585e2b5 338{
ef1717a9
VZ
339public:
340 wxDisplayFactoryDirectDraw();
341 virtual ~wxDisplayFactoryDirectDraw();
a536e411 342
ef1717a9 343 virtual wxDisplayImpl *CreateDisplay(size_t n);
a536e411 344
ef1717a9
VZ
345private:
346 // callback used with DirectDrawEnumerateEx()
347 static BOOL WINAPI DDEnumExCallback(GUID *pGuid,
348 LPTSTR driverDescription,
349 LPTSTR driverName,
350 LPVOID lpContext,
351 HMONITOR hmon);
06efac1f 352
ef1717a9
VZ
353 // add a monitor description to m_displays array
354 void AddDisplay(const GUID& guid, HMONITOR hmon, LPTSTR name);
06efac1f 355
a536e411 356
ef1717a9
VZ
357 // ddraw.dll
358 wxDynamicLibrary m_dllDDraw;
a536e411 359
ef1717a9
VZ
360 // dynamically resolved DirectDrawCreate()
361 DirectDrawCreate_t m_pfnDirectDrawCreate;
a536e411 362
ef1717a9
VZ
363 DECLARE_NO_COPY_CLASS(wxDisplayFactoryDirectDraw)
364};
01c54165 365
ef1717a9 366#endif // wxUSE_DIRECTDRAW
8585e2b5 367
8585e2b5 368
ef1717a9
VZ
369// ============================================================================
370// common classes implementation
371// ============================================================================
a536e411 372
ef1717a9
VZ
373// ----------------------------------------------------------------------------
374// wxDisplay
375// ----------------------------------------------------------------------------
376
377/* static */ wxDisplayFactory *wxDisplay::CreateFactory()
a536e411 378{
ef1717a9
VZ
379 // we have 2 implementations for modern Windows: one using standard Win32
380 // and another using DirectDraw, the choice between them is done using a
381 // system option
7487919e
WS
382
383#ifdef wxUSE_DIRECTDRAW
ef1717a9 384 if ( wxSystemOptions::GetOptionInt(_T("msw.display.directdraw")) )
01c54165 385 {
ef1717a9
VZ
386 wxDisplayFactoryDirectDraw *factoryDD = new wxDisplayFactoryDirectDraw;
387 if ( factoryDD->IsOk() )
388 return factoryDD;
389
390 delete factoryDD;
01c54165 391 }
7487919e 392#endif // wxUSE_DIRECTDRAW
01c54165 393
ef1717a9
VZ
394 wxDisplayFactoryMultimon *factoryMM = new wxDisplayFactoryMultimon;
395 if ( factoryMM->IsOk() )
396 return factoryMM;
a536e411 397
ef1717a9
VZ
398 delete factoryMM;
399
400
401 // finally fall back to a stub implementation if all else failed (Win95?)
402 return new wxDisplayFactorySingle;
8585e2b5 403}
a536e411 404
ef1717a9
VZ
405// ----------------------------------------------------------------------------
406// wxDisplayInfo
407// ----------------------------------------------------------------------------
408
409void wxDisplayInfo::Initialize()
8585e2b5 410{
ef1717a9 411 if ( m_flags == (DWORD)-1 )
01c54165 412 {
ef1717a9
VZ
413 WinStruct<MONITORINFOEX> monInfo;
414 if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) )
01c54165 415 {
ef1717a9
VZ
416 wxLogLastError(_T("GetMonitorInfo"));
417 m_flags = 0;
418 return;
01c54165 419 }
01c54165 420
ef1717a9 421 wxCopyRECTToRect(monInfo.rcMonitor, m_rect);
6c5d6291 422 wxCopyRECTToRect(monInfo.rcWork, m_rectClient);
ef1717a9
VZ
423 m_devName = monInfo.szDevice;
424 m_flags = monInfo.dwFlags;
425 }
8585e2b5
VZ
426}
427
06efac1f 428// ----------------------------------------------------------------------------
ef1717a9 429// wxDisplayImplWin32Base
06efac1f
VZ
430// ----------------------------------------------------------------------------
431
ef1717a9 432wxRect wxDisplayImplWin32Base::GetGeometry() const
8585e2b5 433{
ef1717a9
VZ
434 if ( m_info.m_rect.IsEmpty() )
435 m_info.Initialize();
06efac1f 436
ef1717a9
VZ
437 return m_info.m_rect;
438}
06efac1f 439
6c5d6291
VZ
440wxRect wxDisplayImplWin32Base::GetClientArea() const
441{
442 if ( m_info.m_rectClient.IsEmpty() )
443 m_info.Initialize();
444
445 return m_info.m_rectClient;
446}
447
ef1717a9
VZ
448wxString wxDisplayImplWin32Base::GetName() const
449{
450 if ( m_info.m_devName.IsEmpty() )
451 m_info.Initialize();
06efac1f 452
ef1717a9
VZ
453 return m_info.m_devName;
454}
06efac1f 455
ef1717a9
VZ
456bool wxDisplayImplWin32Base::IsPrimary() const
457{
458 if ( m_info.m_flags == (DWORD)-1 )
459 m_info.Initialize();
06efac1f 460
ef1717a9 461 return (m_info.m_flags & MONITORINFOF_PRIMARY) != 0;
06efac1f
VZ
462}
463
ef1717a9 464wxVideoMode wxDisplayImplWin32Base::GetCurrentMode() const
06efac1f 465{
ef1717a9 466 wxVideoMode mode;
01c54165 467
ef1717a9
VZ
468 // The first parameter of EnumDisplaySettings() must be NULL under Win95
469 // according to MSDN. The version of GetName() we implement for Win95
470 // returns an empty string.
471 const wxString name = GetName();
472 const wxChar * const deviceName = name.empty() ? NULL : name.c_str();
06efac1f 473
ef1717a9
VZ
474 DEVMODE dm;
475 dm.dmSize = sizeof(dm);
476 dm.dmDriverExtra = 0;
477 if ( !::EnumDisplaySettings(deviceName, ENUM_CURRENT_SETTINGS, &dm) )
06efac1f 478 {
ef1717a9 479 wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
06efac1f 480 }
ef1717a9
VZ
481 else
482 {
483 mode = ConvertToVideoMode(dm);
484 }
485
486 return mode;
06efac1f
VZ
487}
488
489// ----------------------------------------------------------------------------
ef1717a9 490// wxDisplayFactoryWin32Base
06efac1f
VZ
491// ----------------------------------------------------------------------------
492
ef1717a9 493int wxDisplayFactoryWin32Base::ms_supportsMultimon = -1;
8585e2b5 494
ef1717a9 495wxDisplayFactoryWin32Base::wxDisplayFactoryWin32Base()
8585e2b5 496{
ef1717a9 497 if ( ms_supportsMultimon == -1 )
01c54165 498 {
ef1717a9 499 ms_supportsMultimon = 0;
01c54165 500
ef1717a9 501 wxDynamicLibrary dllUser32(_T("user32.dll"));
06efac1f 502
ef1717a9
VZ
503 wxLogNull noLog;
504
505 gs_MonitorFromPoint = (MonitorFromPoint_t)
506 dllUser32.GetSymbol(wxT("MonitorFromPoint"));
507 if ( !gs_MonitorFromPoint )
508 return;
509
510 gs_MonitorFromWindow = (MonitorFromWindow_t)
511 dllUser32.GetSymbol(wxT("MonitorFromWindow"));
512 if ( !gs_MonitorFromWindow )
513 return;
514
515 gs_GetMonitorInfo = (GetMonitorInfo_t)
516 dllUser32.GetSymbolAorW(wxT("GetMonitorInfo"));
517 if ( !gs_GetMonitorInfo )
518 return;
519
520 ms_supportsMultimon = 1;
521
522 // we can safely let dllUser32 go out of scope, the DLL itself will
523 // still remain loaded as all Win32 programs use it
06efac1f 524 }
ef1717a9 525}
06efac1f 526
ef1717a9
VZ
527void wxDisplayFactoryWin32Base::Clear()
528{
529 WX_CLEAR_ARRAY(m_displays);
8585e2b5
VZ
530}
531
ef1717a9 532wxDisplayFactoryWin32Base::~wxDisplayFactoryWin32Base()
8585e2b5 533{
ef1717a9
VZ
534 Clear();
535}
01c54165 536
ef1717a9
VZ
537// helper for GetFromPoint() and GetFromWindow()
538int wxDisplayFactoryWin32Base::FindDisplayFromHMONITOR(HMONITOR hmon) const
539{
540 if ( hmon )
a536e411 541 {
ef1717a9
VZ
542 const size_t count = m_displays.size();
543 for ( size_t n = 0; n < count; n++ )
8585e2b5 544 {
ef1717a9
VZ
545 if ( hmon == m_displays[n]->m_hmon )
546 return n;
8585e2b5 547 }
a536e411
JS
548 }
549
ef1717a9 550 return wxNOT_FOUND;
a536e411
JS
551}
552
ef1717a9
VZ
553int wxDisplayFactoryWin32Base::GetFromPoint(const wxPoint& pt)
554{
555 POINT pt2;
556 pt2.x = pt.x;
557 pt2.y = pt.y;
558
559 return FindDisplayFromHMONITOR(gs_MonitorFromPoint(pt2,
560 MONITOR_DEFAULTTONULL));
561}
562
563int wxDisplayFactoryWin32Base::GetFromWindow(wxWindow *window)
564{
565 return FindDisplayFromHMONITOR(gs_MonitorFromWindow(GetHwndOf(window),
566 MONITOR_DEFAULTTONULL));
567}
568
569// ============================================================================
570// wxDisplay implementation using Win32 multimon API
571// ============================================================================
572
24d2b4f5 573// ----------------------------------------------------------------------------
ef1717a9 574// wxDisplayFactoryMultimon initialization
24d2b4f5
RN
575// ----------------------------------------------------------------------------
576
ef1717a9 577wxDisplayFactoryMultimon::wxDisplayFactoryMultimon()
24d2b4f5 578{
ef1717a9
VZ
579 if ( !ms_supportsMultimon )
580 return;
01c54165 581
ef1717a9
VZ
582 // look up EnumDisplayMonitors() which we don't need with DirectDraw
583 // implementation
584 EnumDisplayMonitors_t pfnEnumDisplayMonitors;
585 {
586 wxLogNull noLog;
24d2b4f5 587
ef1717a9
VZ
588 wxDynamicLibrary dllUser32(_T("user32.dll"));
589 pfnEnumDisplayMonitors = (EnumDisplayMonitors_t)
590 dllUser32.GetSymbol(wxT("EnumDisplayMonitors"));
591 if ( !pfnEnumDisplayMonitors )
592 return;
593 }
24d2b4f5 594
ef1717a9
VZ
595 // enumerate all displays
596 if ( !pfnEnumDisplayMonitors(NULL, NULL, MultimonEnumProc, (LPARAM)this) )
24d2b4f5 597 {
ef1717a9 598 wxLogLastError(wxT("EnumDisplayMonitors"));
24d2b4f5 599 }
ef1717a9
VZ
600}
601
602/* static */
603BOOL CALLBACK
604wxDisplayFactoryMultimon::MultimonEnumProc(
605 HMONITOR hMonitor, // handle to display monitor
606 HDC WXUNUSED(hdcMonitor), // handle to monitor-appropriate device context
607 LPRECT lprcMonitor, // pointer to monitor intersection rectangle
608 LPARAM dwData // data passed from EnumDisplayMonitors (this)
609)
610{
611 wxDisplayFactoryMultimon *const self = (wxDisplayFactoryMultimon *)dwData;
612 self->AddDisplay(hMonitor, lprcMonitor);
24d2b4f5 613
ef1717a9
VZ
614 // continue the enumeration
615 return TRUE;
24d2b4f5
RN
616}
617
06efac1f 618// ----------------------------------------------------------------------------
ef1717a9 619// wxDisplayFactoryMultimon helper functions
06efac1f
VZ
620// ----------------------------------------------------------------------------
621
ef1717a9 622void wxDisplayFactoryMultimon::AddDisplay(HMONITOR hMonitor, LPRECT lprcMonitor)
06efac1f 623{
ef1717a9 624 wxDisplayInfo *info = new wxDisplayInfo(hMonitor);
06efac1f 625
ef1717a9
VZ
626 // we also store the display geometry
627 info->m_rect = wxRect(lprcMonitor->left, lprcMonitor->top,
628 lprcMonitor->right - lprcMonitor->left,
629 lprcMonitor->bottom - lprcMonitor->top);
06efac1f 630
ef1717a9
VZ
631 // now add this monitor to the array
632 m_displays.Add(info);
633}
06efac1f 634
ef1717a9
VZ
635// ----------------------------------------------------------------------------
636// wxDisplayFactoryMultimon inherited pure virtuals implementation
637// ----------------------------------------------------------------------------
06efac1f 638
ef1717a9
VZ
639wxDisplayImpl *wxDisplayFactoryMultimon::CreateDisplay(size_t n)
640{
641 wxCHECK_MSG( n < m_displays.size(), NULL, _T("invalid display index") );
642
643 return new wxDisplayImplMultimon(n, *(m_displays[n]));
06efac1f 644}
ef1717a9
VZ
645
646// ----------------------------------------------------------------------------
647// wxDisplayImplMultimon implementation
648// ----------------------------------------------------------------------------
06efac1f
VZ
649
650wxArrayVideoModes
ef1717a9 651wxDisplayImplMultimon::GetModes(const wxVideoMode& modeMatch) const
a536e411 652{
8585e2b5
VZ
653 wxArrayVideoModes modes;
654
01c54165
VZ
655 // The first parameter of EnumDisplaySettings() must be NULL under Win95
656 // according to MSDN. The version of GetName() we implement for Win95
657 // returns an empty string.
658 const wxString name = GetName();
8585e2b5
VZ
659 const wxChar * const deviceName = name.empty() ? NULL : name.c_str();
660
661 DEVMODE dm;
01c54165
VZ
662 dm.dmSize = sizeof(dm);
663 dm.dmDriverExtra = 0;
8585e2b5
VZ
664 for ( int iModeNum = 0;
665 ::EnumDisplaySettings(deviceName, iModeNum, &dm);
666 iModeNum++ )
667 {
668 const wxVideoMode mode = ConvertToVideoMode(dm);
669 if ( mode.Matches(modeMatch) )
670 {
671 modes.Add(mode);
672 }
673 }
674
675 return modes;
a536e411
JS
676}
677
ef1717a9 678bool wxDisplayImplMultimon::ChangeMode(const wxVideoMode& mode)
a536e411 679{
8585e2b5 680 // prepare ChangeDisplaySettingsEx() parameters
61373fa8
WS
681 DEVMODE dm;
682 DEVMODE *pDevMode;
683
8585e2b5
VZ
684 int flags;
685
686 if ( mode == wxDefaultVideoMode )
687 {
688 // reset the video mode to default
689 pDevMode = NULL;
690 flags = 0;
691 }
692 else // change to the given mode
693 {
06efac1f 694 wxCHECK_MSG( mode.w && mode.h, false,
8585e2b5
VZ
695 _T("at least the width and height must be specified") );
696
697 wxZeroMemory(dm);
698 dm.dmSize = sizeof(dm);
01c54165 699 dm.dmDriverExtra = 0;
8585e2b5
VZ
700 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
701 dm.dmPelsWidth = mode.w;
702 dm.dmPelsHeight = mode.h;
703
704 if ( mode.bpp )
705 {
706 dm.dmFields |= DM_BITSPERPEL;
707 dm.dmBitsPerPel = mode.bpp;
708 }
709
710 if ( mode.refresh )
711 {
712 dm.dmFields |= DM_DISPLAYFREQUENCY;
713 dm.dmDisplayFrequency = mode.refresh;
714 }
715
716 pDevMode = &dm;
717
2ad495fb
WS
718#ifdef __WXWINCE__
719 flags = 0;
720#else // !__WXWINCE__
8585e2b5 721 flags = CDS_FULLSCREEN;
2ad495fb 722#endif // __WXWINCE__/!__WXWINCE__
8585e2b5
VZ
723 }
724
725
726 // get pointer to the function dynamically
727 //
728 // we're only called from the main thread, so it's ok to use static
729 // variable
730 static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx = NULL;
731 if ( !pfnChangeDisplaySettingsEx )
732 {
733 wxDynamicLibrary dllUser32(_T("user32.dll"));
734 if ( dllUser32.IsLoaded() )
735 {
736 pfnChangeDisplaySettingsEx = (ChangeDisplaySettingsEx_t)
fd921f35 737 dllUser32.GetSymbolAorW(_T("ChangeDisplaySettingsEx"));
8585e2b5
VZ
738 }
739 //else: huh, no user32.dll??
740
2ad495fb 741#ifndef __WXWINCE__
8585e2b5
VZ
742 if ( !pfnChangeDisplaySettingsEx )
743 {
744 // we must be under Win95 and so there is no multiple monitors
745 // support anyhow
746 pfnChangeDisplaySettingsEx = ChangeDisplaySettingsExForWin95;
747 }
2ad495fb 748#endif // !__WXWINCE__
8585e2b5
VZ
749 }
750
751 // do change the mode
752 switch ( pfnChangeDisplaySettingsEx
753 (
754 GetName(), // display name
755 pDevMode, // dev mode or NULL to reset
756 NULL, // reserved
757 flags,
758 NULL // pointer to video parameters (not used)
759 ) )
760 {
761 case DISP_CHANGE_SUCCESSFUL:
762 // ok
920b9675
JS
763 {
764 // If we have a top-level, full-screen frame, emulate
765 // the DirectX behavior and resize it. This makes this
766 // API quite a bit easier to use.
767 wxWindow *winTop = wxTheApp->GetTopWindow();
768 wxFrame *frameTop = wxDynamicCast(winTop, wxFrame);
769 if (frameTop && frameTop->IsFullScreen())
770 {
771 wxVideoMode current = GetCurrentMode();
772 frameTop->SetClientSize(current.w, current.h);
773 }
774 }
06efac1f 775 return true;
8585e2b5
VZ
776
777 case DISP_CHANGE_BADMODE:
778 // don't complain about this, this is the only "expected" error
779 break;
780
781 default:
782 wxFAIL_MSG( _T("unexpected ChangeDisplaySettingsEx() return value") );
783 }
784
06efac1f
VZ
785 return false;
786}
787
ef1717a9
VZ
788
789// ============================================================================
790// DirectDraw-based wxDisplay implementation
791// ============================================================================
792
793#if wxUSE_DIRECTDRAW
794
795// ----------------------------------------------------------------------------
796// wxDisplayFactoryDirectDraw initialization
797// ----------------------------------------------------------------------------
798
799wxDisplayFactoryDirectDraw::wxDisplayFactoryDirectDraw()
06efac1f 800{
ef1717a9
VZ
801 if ( !ms_supportsMultimon )
802 return;
803
804#if wxUSE_LOG
805 // suppress the errors if ddraw.dll is not found, we're prepared to handle
806 // this
807 wxLogNull noLog;
01c54165 808#endif
ef1717a9
VZ
809
810 m_dllDDraw.Load(_T("ddraw.dll"));
811
812 if ( !m_dllDDraw.IsLoaded() )
813 return;
814
815 DirectDrawEnumerateEx_t pDDEnumEx = (DirectDrawEnumerateEx_t)
816 m_dllDDraw.GetSymbolAorW(_T("DirectDrawEnumerateEx"));
817 if ( !pDDEnumEx )
818 return;
819
820 // we can't continue without DirectDrawCreate() later, so resolve it right
821 // now and fail the initialization if it's not available
822 m_pfnDirectDrawCreate = (DirectDrawCreate_t)
823 m_dllDDraw.GetSymbol(_T("DirectDrawCreate"));
824 if ( !m_pfnDirectDrawCreate )
825 return;
826
827 if ( (*pDDEnumEx)(DDEnumExCallback,
828 this,
829 DDENUM_ATTACHEDSECONDARYDEVICES) != DD_OK )
830 {
831 wxLogLastError(_T("DirectDrawEnumerateEx"));
832 }
833}
834
835wxDisplayFactoryDirectDraw::~wxDisplayFactoryDirectDraw()
836{
837 // we must clear m_displays now, before m_dllDDraw is unloaded as otherwise
838 // calling m_pDD2->Release() later would crash
839 Clear();
840}
841
842// ----------------------------------------------------------------------------
843// callbacks for monitor/modes enumeration stuff
844// ----------------------------------------------------------------------------
845
846BOOL WINAPI
847wxDisplayFactoryDirectDraw::DDEnumExCallback(GUID *pGuid,
848 LPTSTR WXUNUSED(driverDescription),
849 LPTSTR driverName,
850 LPVOID lpContext,
851 HMONITOR hmon)
852{
853 if ( pGuid )
854 {
855 wxDisplayFactoryDirectDraw * self =
856 wx_static_cast(wxDisplayFactoryDirectDraw *, lpContext);
857 self->AddDisplay(*pGuid, hmon, driverName);
858 }
859 //else: we're called for the primary monitor, skip it
860
861 // continue the enumeration
862 return TRUE;
863}
864
865// ----------------------------------------------------------------------------
866// wxDisplayFactoryDirectDraw helpers
867// ----------------------------------------------------------------------------
868
869void wxDisplayFactoryDirectDraw::AddDisplay(const GUID& guid,
870 HMONITOR hmon,
871 LPTSTR name)
872{
873 m_displays.Add(new wxDisplayInfoDirectDraw(guid, hmon, name));
874}
875
876// ----------------------------------------------------------------------------
877// wxDisplayFactoryDirectDraw inherited pure virtuals implementation
878// ----------------------------------------------------------------------------
879
880wxDisplayImpl *wxDisplayFactoryDirectDraw::CreateDisplay(size_t n)
881{
882 wxCHECK_MSG( n < m_displays.size(), NULL, _T("invalid display index") );
883
884 wxDisplayInfoDirectDraw *
885 info = wx_static_cast(wxDisplayInfoDirectDraw *, m_displays[n]);
886
887 if ( !info->m_pDD2 )
888 {
889 IDirectDraw *pDD;
890 GUID guid(info->m_guid);
891 HRESULT hr = (*m_pfnDirectDrawCreate)(&guid, &pDD, NULL);
892
893 if ( FAILED(hr) || !pDD )
894 {
895 // what to do??
896 wxLogApiError(_T("DirectDrawCreate"), hr);
897 return NULL;
898 }
899
900 // we got IDirectDraw, but we need IDirectDraw2
901 hr = pDD->QueryInterface(wxIID_IDirectDraw2, (void **)&info->m_pDD2);
902 pDD->Release();
903
904 if ( FAILED(hr) || !info->m_pDD2 )
905 {
906 wxLogApiError(_T("IDirectDraw::QueryInterface(IDD2)"), hr);
907 return NULL;
908 }
909
910 // NB: m_pDD2 will now be only destroyed when m_displays is destroyed
911 // which is ok as we don't want to recreate DD objects all the time
912 }
913 //else: DirectDraw object corresponding to our display already exists
914
915 return new wxDisplayImplDirectDraw(n, *info, info->m_pDD2);
916}
917
918// ============================================================================
919// wxDisplayImplDirectDraw
920// ============================================================================
921
922// ----------------------------------------------------------------------------
923// video modes enumeration
924// ----------------------------------------------------------------------------
925
926// tiny helper class used to pass information from GetModes() to
927// wxDDEnumModesCallback
928class wxDDVideoModesAdder
929{
930public:
931 // our Add() method will add modes matching modeMatch to modes array
932 wxDDVideoModesAdder(wxArrayVideoModes& modes, const wxVideoMode& modeMatch)
933 : m_modes(modes),
934 m_modeMatch(modeMatch)
935 {
936 }
937
938 void Add(const wxVideoMode& mode)
939 {
940 if ( mode.Matches(m_modeMatch) )
941 m_modes.Add(mode);
942 }
943
944private:
945 wxArrayVideoModes& m_modes;
946 const wxVideoMode& m_modeMatch;
947
948 DECLARE_NO_COPY_CLASS(wxDDVideoModesAdder)
949};
950
951HRESULT WINAPI wxDDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc,
952 LPVOID lpContext)
953{
954 // we need at least the mode size
955 static const DWORD FLAGS_REQUIRED = DDSD_HEIGHT | DDSD_WIDTH;
956 if ( (lpDDSurfaceDesc->dwFlags & FLAGS_REQUIRED) == FLAGS_REQUIRED )
957 {
958 wxDDVideoModesAdder * const vmodes =
959 wx_static_cast(wxDDVideoModesAdder *, lpContext);
960
961 vmodes->Add(wxVideoMode(lpDDSurfaceDesc->dwWidth,
962 lpDDSurfaceDesc->dwHeight,
963 lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
964 lpDDSurfaceDesc->dwRefreshRate));
965 }
966
967 // continue the enumeration
968 return DDENUMRET_OK;
969}
970
971wxArrayVideoModes
972wxDisplayImplDirectDraw::GetModes(const wxVideoMode& modeMatch) const
973{
974 wxArrayVideoModes modes;
975 wxDDVideoModesAdder modesAdder(modes, modeMatch);
976
977 HRESULT hr = m_pDD2->EnumDisplayModes
978 (
979 DDEDM_REFRESHRATES,
980 NULL, // all modes
981 &modesAdder, // callback parameter
982 wxDDEnumModesCallback
983 );
984
985 if ( FAILED(hr) )
986 {
987 wxLogApiError(_T("IDirectDraw::EnumDisplayModes"), hr);
988 }
989
990 return modes;
a536e411
JS
991}
992
ef1717a9
VZ
993// ----------------------------------------------------------------------------
994// video mode switching
995// ----------------------------------------------------------------------------
996
997bool wxDisplayImplDirectDraw::ChangeMode(const wxVideoMode& mode)
998{
999 wxWindow *winTop = wxTheApp->GetTopWindow();
1000 wxCHECK_MSG( winTop, false, _T("top level window required for DirectX") );
1001
1002 HRESULT hr = m_pDD2->SetCooperativeLevel
1003 (
1004 GetHwndOf(winTop),
1005 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN
1006 );
1007 if ( FAILED(hr) )
1008 {
1009 wxLogApiError(_T("IDirectDraw2::SetCooperativeLevel"), hr);
1010
1011 return false;
1012 }
1013
1014 hr = m_pDD2->SetDisplayMode(mode.w, mode.h, mode.bpp, mode.refresh, 0);
1015 if ( FAILED(hr) )
1016 {
1017 wxLogApiError(_T("IDirectDraw2::SetDisplayMode"), hr);
1018
1019 return false;
1020 }
1021
1022 return true;
1023}
1024
1025#endif // wxUSE_DIRECTDRAW
1026
8585e2b5 1027#endif // wxUSE_DISPLAY