compilation fix for old SDK headers (such as shipped with VC6)
[wxWidgets.git] / src / msw / display.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/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 "wx/msw/wrapwin.h"
58
59 #ifndef __WXWINCE__
60 #include <multimon.h>
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
74 #endif // !__WXWINCE__
75
76 #ifdef _MSC_VER
77 #pragma warning(default:4706)
78 #endif
79
80 #include <ddraw.h>
81
82 // we don't want to link with ddraw.lib which contains the real
83 // IID_IDirectDraw2 definition
84 const GUID wxIID_IDirectDraw2 =
85 { 0xB3A6F3E0, 0x2B43, 0x11CF, { 0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 } };
86
87 // ----------------------------------------------------------------------------
88 // macros
89 // ----------------------------------------------------------------------------
90
91 #ifdef _UNICODE
92 #define WINFUNC(x) _T(#x) L"W"
93 #else
94 #define WINFUNC(x) #x "A"
95 #endif
96
97 // ----------------------------------------------------------------------------
98 // typedefs for dynamically loaded Windows functions
99 // ----------------------------------------------------------------------------
100
101 typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName,
102 LPDEVMODE lpDevMode,
103 HWND hwnd,
104 DWORD dwFlags,
105 LPVOID lParam);
106
107 typedef BOOL (PASCAL *DDEnumExCallback_t)(GUID *pGuid,
108 LPTSTR driverDescription,
109 LPTSTR driverName,
110 LPVOID lpContext,
111 HMONITOR hmon);
112
113 typedef HRESULT (WINAPI *DirectDrawEnumerateEx_t)(DDEnumExCallback_t lpCallback,
114 LPVOID lpContext,
115 DWORD dwFlags);
116
117 typedef HRESULT (WINAPI *DirectDrawCreate_t)(GUID *lpGUID,
118 LPDIRECTDRAW *lplpDD,
119 IUnknown *pUnkOuter);
120
121 // ----------------------------------------------------------------------------
122 // private classes
123 // ----------------------------------------------------------------------------
124
125 class wxDisplayInfo
126 {
127 public:
128 // handle of this monitor used by MonitorXXX() functions, never NULL
129 HMONITOR m_hmon;
130
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
137 // the entire area of this monitor in virtual screen coordinates
138 wxRect m_rect;
139
140 // the display device name for this monitor, empty initially and retrieved
141 // on demand by DoGetName()
142 wxString m_devName;
143
144 wxDisplayInfo() { m_hmon = NULL; m_pDD2 = NULL; }
145 ~wxDisplayInfo() { if ( m_pDD2 ) m_pDD2->Release(); }
146 };
147
148 WX_DECLARE_OBJARRAY(wxDisplayInfo, wxDisplayInfoArray);
149 #include "wx/arrimpl.cpp"
150 WX_DEFINE_OBJARRAY(wxDisplayInfoArray);
151
152 // this module is used to cleanup gs_displays array
153 class wxDisplayModule : public wxModule
154 {
155 public:
156 virtual bool OnInit() { return true; }
157 virtual void OnExit();
158
159 DECLARE_DYNAMIC_CLASS(wxDisplayModule)
160 };
161
162 IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule)
163
164 // ----------------------------------------------------------------------------
165 // globals
166 // ----------------------------------------------------------------------------
167
168 // do we use DirectX?
169 static bool gs_useDirectX = false;
170
171 // dynamically resolved DirectDrawCreate()
172 static 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
176 static wxDisplayInfoArray *gs_displays = NULL;
177
178 // ===========================================================================
179 // implementation
180 // ===========================================================================
181
182 // ----------------------------------------------------------------------------
183 // callbacks for monitor/modes enumeration stuff
184 // ----------------------------------------------------------------------------
185
186 static BOOL CALLBACK wxmswMonitorEnumProc (
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)
191 )
192 {
193 wxDisplayInfo *info = new wxDisplayInfo();
194
195 // we need hMonitor to be able to map display id to it which is needed for
196 // MonitorXXX() functions, in particular MonitorFromPoint()
197 info->m_hmon = hMonitor;
198
199 // we also store the display geometry
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 );
204
205 // now add this monitor to the array
206 gs_displays->Add(info);
207
208 // continue the enumeration
209 return true;
210 }
211
212 BOOL PASCAL
213 wxDDEnumExCallback(GUID *pGuid,
214 LPTSTR WXUNUSED(driverDescription),
215 LPTSTR driverName,
216 LPVOID WXUNUSED(lpContext),
217 HMONITOR hmon)
218 {
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
235 HRESULT WINAPI wxDDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc,
236 LPVOID lpContext)
237 {
238 // we need at least the mode size
239 static const DWORD FLAGS_REQUIRED = DDSD_HEIGHT | DDSD_WIDTH;
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
259 static bool DoInitDirectX()
260 {
261 #if wxUSE_LOG
262 // suppress the errors if ddraw.dll is not found
263 wxLog::EnableLogging(false);
264 #endif
265
266 wxDynamicLibrary dllDX(_T("ddraw.dll"));
267
268 #if wxUSE_LOG
269 wxLog::EnableLogging();
270 #endif
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
301 static void DoInitStdWindows()
302 {
303 // enumerate all displays
304 if ( !::EnumDisplayMonitors(NULL, NULL, wxmswMonitorEnumProc, 0) )
305 {
306 wxLogLastError(wxT("EnumDisplayMonitors"));
307
308 // TODO: still create at least one (valid) entry in gs_displays for the
309 // primary display!
310 }
311 }
312
313 // this function must be called before accessing gs_displays array as it
314 // creates and initializes it
315 static void InitDisplays()
316 {
317 if ( gs_displays )
318 return;
319
320 gs_displays = new wxDisplayInfoArray();
321
322 if ( !gs_useDirectX || !DoInitDirectX() )
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
332 // convert a DEVMODE to our wxVideoMode
333 wxVideoMode 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 }
342
343 #ifndef __WXWINCE__
344 // emulation of ChangeDisplaySettingsEx() for Win95
345 LONG 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 }
353 #endif // !__WXWINCE__
354
355 // ----------------------------------------------------------------------------
356 // wxDisplayModule
357 // ----------------------------------------------------------------------------
358
359 void wxDisplayModule::OnExit()
360 {
361 delete gs_displays;
362 }
363
364 // ---------------------------------------------------------------------------
365 // wxDisplay
366 // ---------------------------------------------------------------------------
367
368 /* static */
369 void 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
376 // helper of GetFromPoint() and GetFromWindow()
377 static int DisplayFromHMONITOR(HMONITOR hmon)
378 {
379 if ( hmon )
380 {
381 const size_t count = wxDisplay::GetCount();
382
383 for ( size_t n = 0; n < count; n++ )
384 {
385 if ( hmon == (*gs_displays)[n].m_hmon )
386 return n;
387 }
388 }
389
390 return wxNOT_FOUND;
391 }
392
393 /* static */
394 size_t wxDisplayBase::GetCount()
395 {
396 InitDisplays();
397
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
401 //after GetCount or similar is called and really mess this up...
402 //wxASSERT_MSG( gs_displays->GetCount() == (size_t)::GetSystemMetrics(SM_CMONITORS),
403 // _T("So how many displays does this system have?") );
404
405 return gs_displays->GetCount();
406 }
407
408 /* static */
409 int wxDisplayBase::GetFromPoint ( const wxPoint& pt )
410 {
411 POINT pt2;
412 pt2.x = pt.x;
413 pt2.y = pt.y;
414
415 return DisplayFromHMONITOR(::MonitorFromPoint(pt2, MONITOR_DEFAULTTONULL));
416 }
417
418 /* static */
419 int wxDisplayBase::GetFromWindow(wxWindow *window)
420 {
421 return DisplayFromHMONITOR
422 (
423 ::MonitorFromWindow(GetHwndOf(window), MONITOR_DEFAULTTONULL)
424 );
425 }
426
427 // ----------------------------------------------------------------------------
428 // wxDisplay ctor/dtor
429 // ----------------------------------------------------------------------------
430
431 wxDisplay::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();
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
481 wxDisplay::~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
496 bool wxDisplay::IsOk() const
497 {
498 return m_index < GetCount() &&
499 (!gs_useDirectX || (*gs_displays)[m_index].m_pDD2);
500 }
501
502 wxRect wxDisplay::GetGeometry() const
503 {
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;
523 }
524
525 wxString wxDisplay::GetName() const
526 {
527 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
528 if ( dpyInfo.m_devName.empty() )
529 {
530 MONITORINFOEX monInfo;
531 wxZeroMemory(monInfo);
532 monInfo.cbSize = sizeof(monInfo);
533
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) )
539 {
540 wxLogLastError(_T("GetMonitorInfo"));
541 }
542 else
543 {
544 dpyInfo.m_devName = monInfo.szDevice;
545 }
546 }
547
548 return dpyInfo.m_devName;
549 }
550
551 wxString wxDisplay::GetNameForEnumSettings() const
552 {
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;
565 }
566
567 // ----------------------------------------------------------------------------
568 // determine if this is the primary display
569 // ----------------------------------------------------------------------------
570
571 bool 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
591 // ----------------------------------------------------------------------------
592 // video modes enumeration
593 // ----------------------------------------------------------------------------
594
595 wxArrayVideoModes
596 wxDisplay::DoGetModesDirectX(const wxVideoMode& WXUNUSED(modeMatch)) const
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
621 wxArrayVideoModes
622 wxDisplay::DoGetModesWindows(const wxVideoMode& modeMatch) const
623 {
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;
643 }
644
645 wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& modeMatch) const
646 {
647 return gs_useDirectX ? DoGetModesDirectX(modeMatch)
648 : DoGetModesWindows(modeMatch);
649 }
650
651 wxVideoMode wxDisplay::GetCurrentMode() const
652 {
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;
670 }
671
672 // ----------------------------------------------------------------------------
673 // video mode switching
674 // ----------------------------------------------------------------------------
675
676 bool 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
705
706 return true;
707 }
708
709 bool wxDisplay::DoChangeModeWindows(const wxVideoMode& mode)
710 {
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 {
724 wxCHECK_MSG( mode.w && mode.h, false,
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
747 #ifdef __WXWINCE__
748 flags = 0;
749 #else // !__WXWINCE__
750 flags = CDS_FULLSCREEN;
751 #endif // __WXWINCE__/!__WXWINCE__
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
770 #ifndef __WXWINCE__
771 if ( !pfnChangeDisplaySettingsEx )
772 {
773 // we must be under Win95 and so there is no multiple monitors
774 // support anyhow
775 pfnChangeDisplaySettingsEx = ChangeDisplaySettingsExForWin95;
776 }
777 #endif // !__WXWINCE__
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
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 }
804 return true;
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
814 return false;
815 }
816
817 bool wxDisplay::ChangeMode(const wxVideoMode& mode)
818 {
819 return gs_useDirectX ? DoChangeModeDirectX(mode)
820 : DoChangeModeWindows(mode);
821 }
822
823 #endif // wxUSE_DISPLAY
824