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