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