]> git.saurik.com Git - wxWidgets.git/blame - src/msw/display.cpp
define UDM_{SETRANGE|SETPOS|GETPOS}32 if we don't have them in the headers to allow...
[wxWidgets.git] / src / msw / display.cpp
CommitLineData
a536e411 1/////////////////////////////////////////////////////////////////////////////
2ad495fb 2// Name: src/msw/display.cpp
a536e411 3// Purpose: MSW Implementation of wxDisplay class
d20c3f41 4// Author: Royce Mitchell III
06efac1f 5// Modified by: VZ (resolutions enumeration/change support, DirectDraw, ...)
2ad495fb 6// Ryan Norton (IsPrimary override)
a536e411
JS
7// Created: 06/21/02
8// RCS-ID: $Id$
77ffb593 9// Copyright: (c) 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
VZ
36#include "wx/dynload.h"
37
a536e411
JS
38#include "wx/display.h"
39
40// the following define is necessary to access the multi-monitor function
41// declarations in a manner safe to use w/ Windows 95
a536e411 42#define COMPILE_MULTIMON_STUBS
8585e2b5
VZ
43
44// if you don't have multimon.h you can download the file from:
45//
46// http://www.microsoft.com/msj/0697/monitor/monitortextfigs.htm#fig4
47//
48
49#ifdef _MSC_VER
06efac1f 50 // as (m)any standard header(s), this one doesn't compile without warnings
8585e2b5
VZ
51 // with VC++ 6 <sigh>
52 #pragma warning(disable:4706)
a536e411
JS
53#endif
54
8193d58f
VZ
55// with mingw32, we must include windows.h first and it doesn't hurt with other
56// compilers
2ad495fb 57#include "wx/msw/wrapwin.h"
8193d58f 58
2ad495fb
WS
59#ifndef __WXWINCE__
60 #include <multimon.h>
bcc1153a
VZ
61
62 // HMONITOR can be declared either in new enough windef.h or in multimon.h
63 // itself if _WIN32_WINNT < 0x0500, but the trouble is that we set
64 // _WIN32_WINNT to maximal possible value ourselves in wx/msw/wrapwin.h so
65 // that multimon.h doesn't define it but with old headers, neither does
66 // windef.h, in spite of _WIN32_WINNT value. Even more unfortunately, we
67 // can't directly test whether HMONITOR is defined or not in windef.h as
68 // it's not a macro but a typedef, so we test for an unrelated symbol which
69 // is only defined in winuser.h if WINVER >= 0x0500
70 #if !defined(HMONITOR_DECLARED) && !defined(MNS_NOCHECK)
71 DECLARE_HANDLE(HMONITOR);
72 #define HMONITOR_DECLARED
73 #endif
2ad495fb 74#endif // !__WXWINCE__
a536e411 75
8585e2b5
VZ
76#ifdef _MSC_VER
77 #pragma warning(default:4706)
78#endif
a536e411 79
06efac1f
VZ
80#include <ddraw.h>
81
82// we don't want to link with ddraw.lib which contains the real
83// IID_IDirectDraw2 definition
84const GUID wxIID_IDirectDraw2 =
85 { 0xB3A6F3E0, 0x2B43, 0x11CF, { 0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 } };
86
87// ----------------------------------------------------------------------------
88// macros
89// ----------------------------------------------------------------------------
90
8585e2b5 91#ifdef _UNICODE
06efac1f 92 #define WINFUNC(x) _T(#x) L"W"
8585e2b5
VZ
93#else
94 #define WINFUNC(x) #x "A"
95#endif
a536e411
JS
96
97// ----------------------------------------------------------------------------
06efac1f 98// typedefs for dynamically loaded Windows functions
a536e411
JS
99// ----------------------------------------------------------------------------
100
8585e2b5
VZ
101typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName,
102 LPDEVMODE lpDevMode,
103 HWND hwnd,
104 DWORD dwFlags,
105 LPVOID lParam);
a536e411 106
06efac1f
VZ
107typedef BOOL (PASCAL *DDEnumExCallback_t)(GUID *pGuid,
108 LPTSTR driverDescription,
109 LPTSTR driverName,
110 LPVOID lpContext,
111 HMONITOR hmon);
112
113typedef HRESULT (WINAPI *DirectDrawEnumerateEx_t)(DDEnumExCallback_t lpCallback,
114 LPVOID lpContext,
115 DWORD dwFlags);
116
117typedef HRESULT (WINAPI *DirectDrawCreate_t)(GUID *lpGUID,
118 LPDIRECTDRAW *lplpDD,
119 IUnknown *pUnkOuter);
120
8585e2b5
VZ
121// ----------------------------------------------------------------------------
122// private classes
123// ----------------------------------------------------------------------------
a536e411 124
8585e2b5 125class wxDisplayInfo
a536e411
JS
126{
127public:
8585e2b5
VZ
128 // handle of this monitor used by MonitorXXX() functions, never NULL
129 HMONITOR m_hmon;
130
06efac1f
VZ
131 // IDirectDraw object used to control this display, may be NULL
132 IDirectDraw2 *m_pDD2;
133
134 // DirectDraw GUID for this display, only valid when using DirectDraw
135 GUID m_guid;
136
8585e2b5 137 // the entire area of this monitor in virtual screen coordinates
a536e411 138 wxRect m_rect;
8585e2b5
VZ
139
140 // the display device name for this monitor, empty initially and retrieved
141 // on demand by DoGetName()
142 wxString m_devName;
143
06efac1f
VZ
144 wxDisplayInfo() { m_hmon = NULL; m_pDD2 = NULL; }
145 ~wxDisplayInfo() { if ( m_pDD2 ) m_pDD2->Release(); }
a536e411
JS
146};
147
8585e2b5
VZ
148WX_DECLARE_OBJARRAY(wxDisplayInfo, wxDisplayInfoArray);
149#include "wx/arrimpl.cpp"
150WX_DEFINE_OBJARRAY(wxDisplayInfoArray);
a536e411 151
06efac1f 152// this module is used to cleanup gs_displays array
8585e2b5
VZ
153class wxDisplayModule : public wxModule
154{
155public:
06efac1f 156 virtual bool OnInit() { return true; }
8585e2b5
VZ
157 virtual void OnExit();
158
159 DECLARE_DYNAMIC_CLASS(wxDisplayModule)
160};
161
162IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule)
a536e411 163
06efac1f
VZ
164// ----------------------------------------------------------------------------
165// globals
166// ----------------------------------------------------------------------------
167
168// do we use DirectX?
169static bool gs_useDirectX = false;
170
171// dynamically resolved DirectDrawCreate()
172static DirectDrawCreate_t gs_DirectDrawCreate = NULL;
173
174// this is not really MT-unsafe as wxDisplay is only going to be used from the
175// main thread, i.e. we consider that it's a GUI class and so don't protect it
176static wxDisplayInfoArray *gs_displays = NULL;
177
a536e411
JS
178// ===========================================================================
179// implementation
180// ===========================================================================
181
8585e2b5 182// ----------------------------------------------------------------------------
06efac1f 183// callbacks for monitor/modes enumeration stuff
8585e2b5
VZ
184// ----------------------------------------------------------------------------
185
186static BOOL CALLBACK wxmswMonitorEnumProc (
2eb10e2a
VZ
187 HMONITOR hMonitor, // handle to display monitor
188 HDC WXUNUSED(hdcMonitor), // handle to monitor-appropriate device context
189 LPRECT lprcMonitor, // pointer to monitor intersection rectangle
190 LPARAM WXUNUSED(dwData) // data passed from EnumDisplayMonitors (unused)
a536e411
JS
191)
192{
06efac1f 193 wxDisplayInfo *info = new wxDisplayInfo();
8585e2b5
VZ
194
195 // we need hMonitor to be able to map display id to it which is needed for
196 // MonitorXXX() functions, in particular MonitorFromPoint()
a536e411 197 info->m_hmon = hMonitor;
8585e2b5
VZ
198
199 // we also store the display geometry
a536e411
JS
200 info->m_rect.SetX ( lprcMonitor->left );
201 info->m_rect.SetY ( lprcMonitor->top );
202 info->m_rect.SetWidth ( lprcMonitor->right - lprcMonitor->left );
203 info->m_rect.SetHeight ( lprcMonitor->bottom - lprcMonitor->top );
8585e2b5 204
a536e411 205 // now add this monitor to the array
06efac1f 206 gs_displays->Add(info);
a536e411 207
8585e2b5 208 // continue the enumeration
06efac1f 209 return true;
a536e411
JS
210}
211
06efac1f
VZ
212BOOL PASCAL
213wxDDEnumExCallback(GUID *pGuid,
2eb10e2a 214 LPTSTR WXUNUSED(driverDescription),
06efac1f 215 LPTSTR driverName,
2eb10e2a 216 LPVOID WXUNUSED(lpContext),
06efac1f 217 HMONITOR hmon)
a536e411 218{
06efac1f
VZ
219 if ( pGuid )
220 {
221 wxDisplayInfo *info = new wxDisplayInfo();
222
223 info->m_hmon = hmon;
224 info->m_guid = *pGuid;
225 info->m_devName = driverName;
226
227 gs_displays->Add(info);
228 }
229 //else: we're called for the primary monitor, skip it
230
231 // continue the enumeration
232 return true;
233}
234
d71cc120 235HRESULT WINAPI wxDDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc,
06efac1f
VZ
236 LPVOID lpContext)
237{
238 // we need at least the mode size
f29cfd77 239 static const DWORD FLAGS_REQUIRED = DDSD_HEIGHT | DDSD_WIDTH;
06efac1f
VZ
240 if ( (lpDDSurfaceDesc->dwFlags & FLAGS_REQUIRED) == FLAGS_REQUIRED )
241 {
242 wxArrayVideoModes * const modes = (wxArrayVideoModes *)lpContext;
243
244 modes->Add(wxVideoMode(lpDDSurfaceDesc->dwWidth,
245 lpDDSurfaceDesc->dwHeight,
246 lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
247 lpDDSurfaceDesc->dwRefreshRate));
248 }
249
250 // continue the enumeration
251 return DDENUMRET_OK;
252}
253
254// ----------------------------------------------------------------------------
255// local functions
256// ----------------------------------------------------------------------------
257
258// initialize gs_displays using DirectX functions
259static bool DoInitDirectX()
260{
0b4f47a3 261#if wxUSE_LOG
06efac1f
VZ
262 // suppress the errors if ddraw.dll is not found
263 wxLog::EnableLogging(false);
0b4f47a3 264#endif
a536e411 265
06efac1f 266 wxDynamicLibrary dllDX(_T("ddraw.dll"));
a536e411 267
0b4f47a3
DS
268#if wxUSE_LOG
269 wxLog::EnableLogging();
270#endif
06efac1f
VZ
271
272 if ( !dllDX.IsLoaded() )
273 return false;
274
275 DirectDrawEnumerateEx_t pDDEnumEx = (DirectDrawEnumerateEx_t)
276 dllDX.GetSymbol(WINFUNC(DirectDrawEnumerateEx));
277 if ( !pDDEnumEx )
278 return false;
279
280 // we'll also need DirectDrawCreate() later, resolve it right now
281 gs_DirectDrawCreate = (DirectDrawCreate_t)
282 dllDX.GetSymbol(_T("DirectDrawCreate"));
283 if ( !gs_DirectDrawCreate )
284 return false;
285
286 if ( (*pDDEnumEx)(wxDDEnumExCallback,
287 NULL,
288 DDENUM_ATTACHEDSECONDARYDEVICES) != DD_OK )
289 {
290 return false;
291 }
292
293 // ok, it seems like we're going to use DirectDraw and so we're going to
294 // need ddraw.dll all the time, don't unload it
295 dllDX.Detach();
296
297 return true;
298}
299
300// initialize gs_displays using the standard Windows functions
301static void DoInitStdWindows()
302{
8585e2b5
VZ
303 // enumerate all displays
304 if ( !::EnumDisplayMonitors(NULL, NULL, wxmswMonitorEnumProc, 0) )
a536e411 305 {
8585e2b5
VZ
306 wxLogLastError(wxT("EnumDisplayMonitors"));
307
06efac1f 308 // TODO: still create at least one (valid) entry in gs_displays for the
8585e2b5 309 // primary display!
a536e411 310 }
8585e2b5 311}
a536e411 312
06efac1f
VZ
313// this function must be called before accessing gs_displays array as it
314// creates and initializes it
315static void InitDisplays()
316{
317 if ( gs_displays )
318 return;
319
320 gs_displays = new wxDisplayInfoArray();
321
82eba826 322 if ( !gs_useDirectX || !DoInitDirectX() )
06efac1f
VZ
323 {
324 // either we were told not to try to use DirectX or fall back to std
325 // functions if DirectX method failed
326 gs_useDirectX = false;
327
328 DoInitStdWindows();
329 }
330}
331
8585e2b5
VZ
332// convert a DEVMODE to our wxVideoMode
333wxVideoMode ConvertToVideoMode(const DEVMODE& dm)
334{
335 // note that dmDisplayFrequency may be 0 or 1 meaning "standard one" and
336 // although 0 is ok for us we don't want to return modes with 1hz refresh
337 return wxVideoMode(dm.dmPelsWidth,
338 dm.dmPelsHeight,
339 dm.dmBitsPerPel,
340 dm.dmDisplayFrequency > 1 ? dm.dmDisplayFrequency : 0);
341}
a536e411 342
2ad495fb 343#ifndef __WXWINCE__
8585e2b5
VZ
344// emulation of ChangeDisplaySettingsEx() for Win95
345LONG WINAPI ChangeDisplaySettingsExForWin95(LPCTSTR WXUNUSED(lpszDeviceName),
346 LPDEVMODE lpDevMode,
347 HWND WXUNUSED(hwnd),
348 DWORD dwFlags,
349 LPVOID WXUNUSED(lParam))
350{
351 return ::ChangeDisplaySettings(lpDevMode, dwFlags);
352}
2ad495fb 353#endif // !__WXWINCE__
a536e411 354
8585e2b5
VZ
355// ----------------------------------------------------------------------------
356// wxDisplayModule
357// ----------------------------------------------------------------------------
a536e411 358
8585e2b5
VZ
359void wxDisplayModule::OnExit()
360{
06efac1f 361 delete gs_displays;
8585e2b5 362}
a536e411 363
8585e2b5
VZ
364// ---------------------------------------------------------------------------
365// wxDisplay
366// ---------------------------------------------------------------------------
a536e411 367
06efac1f
VZ
368/* static */
369void wxDisplay::UseDirectX(bool useDX)
370{
371 wxCHECK_RET( !gs_displays, _T("it is too late to call UseDirectX") );
372
373 gs_useDirectX = useDX;
374}
375
8585e2b5
VZ
376// helper of GetFromPoint() and GetFromWindow()
377static int DisplayFromHMONITOR(HMONITOR hmon)
378{
379 if ( hmon )
380 {
381 const size_t count = wxDisplay::GetCount();
a536e411 382
8585e2b5 383 for ( size_t n = 0; n < count; n++ )
a536e411 384 {
06efac1f 385 if ( hmon == (*gs_displays)[n].m_hmon )
8585e2b5 386 return n;
a536e411 387 }
a536e411 388 }
a536e411 389
8585e2b5 390 return wxNOT_FOUND;
a536e411
JS
391}
392
8585e2b5 393/* static */
a536e411
JS
394size_t wxDisplayBase::GetCount()
395{
8585e2b5
VZ
396 InitDisplays();
397
6fcf77f4
RN
398 //RN: FIXME: This is wrong - the display info array should reload after every call
399 //to GetCount() - otherwise it will not be accurate.
400 //The user can change the number of displays in display properties/settings
2ad495fb 401 //after GetCount or similar is called and really mess this up...
6fcf77f4
RN
402 //wxASSERT_MSG( gs_displays->GetCount() == (size_t)::GetSystemMetrics(SM_CMONITORS),
403 // _T("So how many displays does this system have?") );
8585e2b5 404
06efac1f 405 return gs_displays->GetCount();
a536e411
JS
406}
407
8585e2b5 408/* static */
a536e411
JS
409int wxDisplayBase::GetFromPoint ( const wxPoint& pt )
410{
411 POINT pt2;
412 pt2.x = pt.x;
413 pt2.y = pt.y;
414
8585e2b5
VZ
415 return DisplayFromHMONITOR(::MonitorFromPoint(pt2, MONITOR_DEFAULTTONULL));
416}
a536e411 417
8585e2b5
VZ
418/* static */
419int wxDisplayBase::GetFromWindow(wxWindow *window)
420{
421 return DisplayFromHMONITOR
422 (
423 ::MonitorFromWindow(GetHwndOf(window), MONITOR_DEFAULTTONULL)
424 );
425}
426
06efac1f
VZ
427// ----------------------------------------------------------------------------
428// wxDisplay ctor/dtor
429// ----------------------------------------------------------------------------
430
8585e2b5
VZ
431wxDisplay::wxDisplay ( size_t n )
432 : wxDisplayBase ( n )
433{
434 // if we do this in ctor we won't have to call it from all the member
435 // functions
436 InitDisplays();
06efac1f
VZ
437
438 if ( gs_useDirectX )
439 {
440 wxDisplayInfo& dpyInfo = (*gs_displays)[n];
441
442 LPDIRECTDRAW2& pDD2 = dpyInfo.m_pDD2;
443 if ( !pDD2 )
444 {
445 if ( !gs_DirectDrawCreate )
446 {
447 // what to do??
448 return;
449 }
450
451 IDirectDraw *pDD;
452 HRESULT hr = (*gs_DirectDrawCreate)(&dpyInfo.m_guid, &pDD, NULL);
453
454 if ( FAILED(hr) || !pDD )
455 {
456 // what to do??
457 wxLogApiError(_T("DirectDrawCreate"), hr);
458 }
459 else // got IDirectDraw, we want IDirectDraw2
460 {
461 hr = pDD->QueryInterface(wxIID_IDirectDraw2, (void **)&pDD2);
462 if ( FAILED(hr) || !pDD2 )
463 {
464 wxLogApiError(_T("IDirectDraw::QueryInterface(IDD2)"), hr);
465 }
466
467 pDD->Release();
468 }
469 }
470 //else: DirectDraw object corresponding to our display already exists
471
472 // increment its ref count to account for Release() in dtor
473 //
474 // NB: pDD2 will be only really Release()d when gs_displays is
475 // destroyed which is ok as we don't want to recreate DD objects
476 // all the time
477 pDD2->AddRef();
478 }
479}
480
481wxDisplay::~wxDisplay()
482{
483 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
484
485 LPDIRECTDRAW2& pDD2 = dpyInfo.m_pDD2;
486 if ( pDD2 )
487 {
488 pDD2->Release();
489 }
490}
491
492// ----------------------------------------------------------------------------
493// wxDisplay simple accessors
494// ----------------------------------------------------------------------------
495
496bool wxDisplay::IsOk() const
497{
498 return m_index < GetCount() &&
499 (!gs_useDirectX || (*gs_displays)[m_index].m_pDD2);
8585e2b5
VZ
500}
501
502wxRect wxDisplay::GetGeometry() const
503{
06efac1f
VZ
504 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
505 wxRect& rect = dpyInfo.m_rect;
506 if ( !rect.width )
507 {
508 MONITORINFO monInfo;
509 wxZeroMemory(monInfo);
510 monInfo.cbSize = sizeof(monInfo);
511
512 if ( !::GetMonitorInfo(dpyInfo.m_hmon, &monInfo) )
513 {
514 wxLogLastError(_T("GetMonitorInfo"));
515 }
516 else
517 {
518 wxCopyRECTToRect(monInfo.rcMonitor, rect);
519 }
520 }
521
522 return rect;
8585e2b5
VZ
523}
524
525wxString wxDisplay::GetName() const
526{
06efac1f 527 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
8585e2b5 528 if ( dpyInfo.m_devName.empty() )
a536e411 529 {
8585e2b5
VZ
530 MONITORINFOEX monInfo;
531 wxZeroMemory(monInfo);
532 monInfo.cbSize = sizeof(monInfo);
533
f29cfd77
VS
534 // NB: Cast from MONITORINFOEX* to MONITORINFO* is done because
535 // Mingw headers - unlike the ones from Microsoft's Platform SDK -
536 // don't derive the former from the latter in C++ mode and so
537 // the pointer's type is not converted implicitly.
538 if ( !::GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) )
8585e2b5
VZ
539 {
540 wxLogLastError(_T("GetMonitorInfo"));
541 }
542 else
543 {
544 dpyInfo.m_devName = monInfo.szDevice;
545 }
a536e411
JS
546 }
547
8585e2b5 548 return dpyInfo.m_devName;
a536e411
JS
549}
550
8585e2b5 551wxString wxDisplay::GetNameForEnumSettings() const
a536e411 552{
8585e2b5
VZ
553 int major, minor;
554 const bool isWin95 = wxGetOsVersion(&major, &minor) == wxWIN95 &&
555 major == 4 && minor == 0;
556
557 // the first parameter of EnumDisplaySettings() must be NULL under Win95
558 // according to MSDN but GetMonitorInfo() stub in multimon.h still returns
559 // something even in this case, so we have to correct this manually
560 wxString name;
561 if ( !isWin95 )
562 name = GetName();
563
564 return name;
a536e411
JS
565}
566
24d2b4f5
RN
567// ----------------------------------------------------------------------------
568// determine if this is the primary display
569// ----------------------------------------------------------------------------
570
571bool wxDisplay::IsPrimary() const
572{
573 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
574
575 MONITORINFOEX monInfo;
576 wxZeroMemory(monInfo);
577 monInfo.cbSize = sizeof(monInfo);
578
579 // NB: Cast from MONITORINFOEX* to MONITORINFO* is done because
580 // Mingw headers - unlike the ones from Microsoft's Platform SDK -
581 // don't derive the former from the latter in C++ mode and so
582 // the pointer's type is not converted implicitly.
583 if ( !::GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) )
584 {
585 wxLogLastError(_T("GetMonitorInfo"));
586 }
587
588 return (monInfo.dwFlags & MONITORINFOF_PRIMARY) == MONITORINFOF_PRIMARY;
589}
590
06efac1f
VZ
591// ----------------------------------------------------------------------------
592// video modes enumeration
593// ----------------------------------------------------------------------------
594
595wxArrayVideoModes
2eb10e2a 596wxDisplay::DoGetModesDirectX(const wxVideoMode& WXUNUSED(modeMatch)) const
06efac1f
VZ
597{
598 wxArrayVideoModes modes;
599
600 IDirectDraw2 *pDD = (*gs_displays)[m_index].m_pDD2;
601
602 if ( pDD )
603 {
604 HRESULT hr = pDD->EnumDisplayModes
605 (
606 DDEDM_REFRESHRATES,
607 NULL, // all modes (TODO: use modeMatch!)
608 &modes, // callback parameter
609 wxDDEnumModesCallback
610 );
611
612 if ( FAILED(hr) )
613 {
614 wxLogApiError(_T("IDirectDraw::EnumDisplayModes"), hr);
615 }
616 }
617
618 return modes;
619}
620
621wxArrayVideoModes
622wxDisplay::DoGetModesWindows(const wxVideoMode& modeMatch) const
a536e411 623{
8585e2b5
VZ
624 wxArrayVideoModes modes;
625
626 const wxString name = GetNameForEnumSettings();
627
628 const wxChar * const deviceName = name.empty() ? NULL : name.c_str();
629
630 DEVMODE dm;
631 for ( int iModeNum = 0;
632 ::EnumDisplaySettings(deviceName, iModeNum, &dm);
633 iModeNum++ )
634 {
635 const wxVideoMode mode = ConvertToVideoMode(dm);
636 if ( mode.Matches(modeMatch) )
637 {
638 modes.Add(mode);
639 }
640 }
641
642 return modes;
a536e411
JS
643}
644
06efac1f
VZ
645wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& modeMatch) const
646{
647 return gs_useDirectX ? DoGetModesDirectX(modeMatch)
648 : DoGetModesWindows(modeMatch);
649}
650
8585e2b5 651wxVideoMode wxDisplay::GetCurrentMode() const
a536e411 652{
8585e2b5
VZ
653 wxVideoMode mode;
654
655 const wxString name = GetNameForEnumSettings();
656
657 DEVMODE dm;
658 if ( !::EnumDisplaySettings(name.empty() ? NULL : name.c_str(),
659 ENUM_CURRENT_SETTINGS,
660 &dm) )
661 {
662 wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
663 }
664 else
665 {
666 mode = ConvertToVideoMode(dm);
667 }
668
669 return mode;
a536e411
JS
670}
671
06efac1f
VZ
672// ----------------------------------------------------------------------------
673// video mode switching
674// ----------------------------------------------------------------------------
675
676bool wxDisplay::DoChangeModeDirectX(const wxVideoMode& mode)
677{
678 IDirectDraw2 *pDD = (*gs_displays)[m_index].m_pDD2;
679 if ( !pDD )
680 return false;
681
682 wxWindow *winTop = wxTheApp->GetTopWindow();
683 wxCHECK_MSG( winTop, false, _T("top level window required for DirectX") );
684
685 HRESULT hr = pDD->SetCooperativeLevel
686 (
687 GetHwndOf(winTop),
688 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN
689 );
690 if ( FAILED(hr) )
691 {
692 wxLogApiError(_T("IDirectDraw::SetCooperativeLevel"), hr);
693
694 return false;
695 }
696
697 hr = pDD->SetDisplayMode(mode.w, mode.h, mode.bpp, mode.refresh, 0);
698 if ( FAILED(hr) )
699 {
700 wxLogApiError(_T("IDirectDraw::SetDisplayMode"), hr);
701
702 return false;
703 }
704
d71cc120 705
06efac1f
VZ
706 return true;
707}
708
709bool wxDisplay::DoChangeModeWindows(const wxVideoMode& mode)
a536e411 710{
8585e2b5
VZ
711 // prepare ChangeDisplaySettingsEx() parameters
712 DEVMODE dm,
713 *pDevMode;
714 int flags;
715
716 if ( mode == wxDefaultVideoMode )
717 {
718 // reset the video mode to default
719 pDevMode = NULL;
720 flags = 0;
721 }
722 else // change to the given mode
723 {
06efac1f 724 wxCHECK_MSG( mode.w && mode.h, false,
8585e2b5
VZ
725 _T("at least the width and height must be specified") );
726
727 wxZeroMemory(dm);
728 dm.dmSize = sizeof(dm);
729 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
730 dm.dmPelsWidth = mode.w;
731 dm.dmPelsHeight = mode.h;
732
733 if ( mode.bpp )
734 {
735 dm.dmFields |= DM_BITSPERPEL;
736 dm.dmBitsPerPel = mode.bpp;
737 }
738
739 if ( mode.refresh )
740 {
741 dm.dmFields |= DM_DISPLAYFREQUENCY;
742 dm.dmDisplayFrequency = mode.refresh;
743 }
744
745 pDevMode = &dm;
746
2ad495fb
WS
747#ifdef __WXWINCE__
748 flags = 0;
749#else // !__WXWINCE__
8585e2b5 750 flags = CDS_FULLSCREEN;
2ad495fb 751#endif // __WXWINCE__/!__WXWINCE__
8585e2b5
VZ
752 }
753
754
755 // get pointer to the function dynamically
756 //
757 // we're only called from the main thread, so it's ok to use static
758 // variable
759 static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx = NULL;
760 if ( !pfnChangeDisplaySettingsEx )
761 {
762 wxDynamicLibrary dllUser32(_T("user32.dll"));
763 if ( dllUser32.IsLoaded() )
764 {
765 pfnChangeDisplaySettingsEx = (ChangeDisplaySettingsEx_t)
766 dllUser32.GetSymbol(WINFUNC(ChangeDisplaySettingsEx));
767 }
768 //else: huh, no user32.dll??
769
2ad495fb 770#ifndef __WXWINCE__
8585e2b5
VZ
771 if ( !pfnChangeDisplaySettingsEx )
772 {
773 // we must be under Win95 and so there is no multiple monitors
774 // support anyhow
775 pfnChangeDisplaySettingsEx = ChangeDisplaySettingsExForWin95;
776 }
2ad495fb 777#endif // !__WXWINCE__
8585e2b5
VZ
778 }
779
780 // do change the mode
781 switch ( pfnChangeDisplaySettingsEx
782 (
783 GetName(), // display name
784 pDevMode, // dev mode or NULL to reset
785 NULL, // reserved
786 flags,
787 NULL // pointer to video parameters (not used)
788 ) )
789 {
790 case DISP_CHANGE_SUCCESSFUL:
791 // ok
920b9675
JS
792 {
793 // If we have a top-level, full-screen frame, emulate
794 // the DirectX behavior and resize it. This makes this
795 // API quite a bit easier to use.
796 wxWindow *winTop = wxTheApp->GetTopWindow();
797 wxFrame *frameTop = wxDynamicCast(winTop, wxFrame);
798 if (frameTop && frameTop->IsFullScreen())
799 {
800 wxVideoMode current = GetCurrentMode();
801 frameTop->SetClientSize(current.w, current.h);
802 }
803 }
06efac1f 804 return true;
8585e2b5
VZ
805
806 case DISP_CHANGE_BADMODE:
807 // don't complain about this, this is the only "expected" error
808 break;
809
810 default:
811 wxFAIL_MSG( _T("unexpected ChangeDisplaySettingsEx() return value") );
812 }
813
06efac1f
VZ
814 return false;
815}
816
817bool wxDisplay::ChangeMode(const wxVideoMode& mode)
818{
819 return gs_useDirectX ? DoChangeModeDirectX(mode)
820 : DoChangeModeWindows(mode);
a536e411
JS
821}
822
8585e2b5
VZ
823#endif // wxUSE_DISPLAY
824