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