]> git.saurik.com Git - wxWidgets.git/blame - src/msw/display.cpp
fixed crash on startup under GTK
[wxWidgets.git] / src / msw / display.cpp
CommitLineData
a536e411
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: display.cpp
3// Purpose: MSW Implementation of wxDisplay class
4// Author: Royce Mitchell III
06efac1f 5// Modified by: VZ (resolutions enumeration/change support, DirectDraw, ...)
a536e411
JS
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
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
a536e411
JS
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
8585e2b5
VZ
37#include "wx/dynload.h"
38
a536e411
JS
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
a536e411 43#define COMPILE_MULTIMON_STUBS
8585e2b5
VZ
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
06efac1f 51 // as (m)any standard header(s), this one doesn't compile without warnings
8585e2b5
VZ
52 // with VC++ 6 <sigh>
53 #pragma warning(disable:4706)
a536e411
JS
54#endif
55
8585e2b5 56#include <multimon.h>
a536e411 57
8585e2b5
VZ
58#ifdef _MSC_VER
59 #pragma warning(default:4706)
60#endif
a536e411 61
06efac1f
VZ
62#include <ddraw.h>
63
64// we don't want to link with ddraw.lib which contains the real
65// IID_IDirectDraw2 definition
66const GUID wxIID_IDirectDraw2 =
67 { 0xB3A6F3E0, 0x2B43, 0x11CF, { 0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 } };
68
69// ----------------------------------------------------------------------------
70// macros
71// ----------------------------------------------------------------------------
72
8585e2b5 73#ifdef _UNICODE
06efac1f 74 #define WINFUNC(x) _T(#x) L"W"
8585e2b5
VZ
75#else
76 #define WINFUNC(x) #x "A"
77#endif
a536e411
JS
78
79// ----------------------------------------------------------------------------
06efac1f 80// typedefs for dynamically loaded Windows functions
a536e411
JS
81// ----------------------------------------------------------------------------
82
8585e2b5
VZ
83typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName,
84 LPDEVMODE lpDevMode,
85 HWND hwnd,
86 DWORD dwFlags,
87 LPVOID lParam);
a536e411 88
06efac1f
VZ
89typedef BOOL (PASCAL *DDEnumExCallback_t)(GUID *pGuid,
90 LPTSTR driverDescription,
91 LPTSTR driverName,
92 LPVOID lpContext,
93 HMONITOR hmon);
94
95typedef HRESULT (WINAPI *DirectDrawEnumerateEx_t)(DDEnumExCallback_t lpCallback,
96 LPVOID lpContext,
97 DWORD dwFlags);
98
99typedef HRESULT (WINAPI *DirectDrawCreate_t)(GUID *lpGUID,
100 LPDIRECTDRAW *lplpDD,
101 IUnknown *pUnkOuter);
102
8585e2b5
VZ
103// ----------------------------------------------------------------------------
104// private classes
105// ----------------------------------------------------------------------------
a536e411 106
8585e2b5 107class wxDisplayInfo
a536e411
JS
108{
109public:
8585e2b5
VZ
110 // handle of this monitor used by MonitorXXX() functions, never NULL
111 HMONITOR m_hmon;
112
06efac1f
VZ
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
8585e2b5 119 // the entire area of this monitor in virtual screen coordinates
a536e411 120 wxRect m_rect;
8585e2b5
VZ
121
122 // the display device name for this monitor, empty initially and retrieved
123 // on demand by DoGetName()
124 wxString m_devName;
125
06efac1f
VZ
126 wxDisplayInfo() { m_hmon = NULL; m_pDD2 = NULL; }
127 ~wxDisplayInfo() { if ( m_pDD2 ) m_pDD2->Release(); }
a536e411
JS
128};
129
8585e2b5
VZ
130WX_DECLARE_OBJARRAY(wxDisplayInfo, wxDisplayInfoArray);
131#include "wx/arrimpl.cpp"
132WX_DEFINE_OBJARRAY(wxDisplayInfoArray);
a536e411 133
06efac1f 134// this module is used to cleanup gs_displays array
8585e2b5
VZ
135class wxDisplayModule : public wxModule
136{
137public:
06efac1f 138 virtual bool OnInit() { return true; }
8585e2b5
VZ
139 virtual void OnExit();
140
141 DECLARE_DYNAMIC_CLASS(wxDisplayModule)
142};
143
144IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule)
a536e411 145
06efac1f
VZ
146// ----------------------------------------------------------------------------
147// globals
148// ----------------------------------------------------------------------------
149
150// do we use DirectX?
151static bool gs_useDirectX = false;
152
153// dynamically resolved DirectDrawCreate()
154static 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
158static wxDisplayInfoArray *gs_displays = NULL;
159
a536e411
JS
160// ===========================================================================
161// implementation
162// ===========================================================================
163
8585e2b5 164// ----------------------------------------------------------------------------
06efac1f 165// callbacks for monitor/modes enumeration stuff
8585e2b5
VZ
166// ----------------------------------------------------------------------------
167
168static BOOL CALLBACK wxmswMonitorEnumProc (
2eb10e2a
VZ
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)
a536e411
JS
173)
174{
06efac1f 175 wxDisplayInfo *info = new wxDisplayInfo();
8585e2b5
VZ
176
177 // we need hMonitor to be able to map display id to it which is needed for
178 // MonitorXXX() functions, in particular MonitorFromPoint()
a536e411 179 info->m_hmon = hMonitor;
8585e2b5
VZ
180
181 // we also store the display geometry
a536e411
JS
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 );
8585e2b5 186
a536e411 187 // now add this monitor to the array
06efac1f 188 gs_displays->Add(info);
a536e411 189
8585e2b5 190 // continue the enumeration
06efac1f 191 return true;
a536e411
JS
192}
193
06efac1f
VZ
194BOOL PASCAL
195wxDDEnumExCallback(GUID *pGuid,
2eb10e2a 196 LPTSTR WXUNUSED(driverDescription),
06efac1f 197 LPTSTR driverName,
2eb10e2a 198 LPVOID WXUNUSED(lpContext),
06efac1f 199 HMONITOR hmon)
a536e411 200{
06efac1f
VZ
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
217HRESULT 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
241static bool DoInitDirectX()
242{
243 // suppress the errors if ddraw.dll is not found
244 wxLog::EnableLogging(false);
a536e411 245
06efac1f 246 wxDynamicLibrary dllDX(_T("ddraw.dll"));
a536e411 247
06efac1f
VZ
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
279static void DoInitStdWindows()
280{
8585e2b5
VZ
281 // enumerate all displays
282 if ( !::EnumDisplayMonitors(NULL, NULL, wxmswMonitorEnumProc, 0) )
a536e411 283 {
8585e2b5
VZ
284 wxLogLastError(wxT("EnumDisplayMonitors"));
285
06efac1f 286 // TODO: still create at least one (valid) entry in gs_displays for the
8585e2b5 287 // primary display!
a536e411 288 }
8585e2b5 289}
a536e411 290
06efac1f
VZ
291// this function must be called before accessing gs_displays array as it
292// creates and initializes it
293static void InitDisplays()
294{
295 if ( gs_displays )
296 return;
297
298 gs_displays = new wxDisplayInfoArray();
299
82eba826 300 if ( !gs_useDirectX || !DoInitDirectX() )
06efac1f
VZ
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
8585e2b5
VZ
310// convert a DEVMODE to our wxVideoMode
311wxVideoMode 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}
a536e411 320
8585e2b5
VZ
321// emulation of ChangeDisplaySettingsEx() for Win95
322LONG 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}
a536e411 330
8585e2b5
VZ
331// ----------------------------------------------------------------------------
332// wxDisplayModule
333// ----------------------------------------------------------------------------
a536e411 334
8585e2b5
VZ
335void wxDisplayModule::OnExit()
336{
06efac1f 337 delete gs_displays;
8585e2b5 338}
a536e411 339
8585e2b5
VZ
340// ---------------------------------------------------------------------------
341// wxDisplay
342// ---------------------------------------------------------------------------
a536e411 343
06efac1f
VZ
344/* static */
345void 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
8585e2b5
VZ
352// helper of GetFromPoint() and GetFromWindow()
353static int DisplayFromHMONITOR(HMONITOR hmon)
354{
355 if ( hmon )
356 {
357 const size_t count = wxDisplay::GetCount();
a536e411 358
8585e2b5 359 for ( size_t n = 0; n < count; n++ )
a536e411 360 {
06efac1f 361 if ( hmon == (*gs_displays)[n].m_hmon )
8585e2b5 362 return n;
a536e411 363 }
a536e411 364 }
a536e411 365
8585e2b5 366 return wxNOT_FOUND;
a536e411
JS
367}
368
8585e2b5 369/* static */
a536e411
JS
370size_t wxDisplayBase::GetCount()
371{
8585e2b5
VZ
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
06efac1f 376 wxASSERT_MSG( gs_displays->GetCount() == (size_t)::GetSystemMetrics(SM_CMONITORS),
8585e2b5
VZ
377 _T("So how many displays does this system have?") );
378
06efac1f 379 return gs_displays->GetCount();
a536e411
JS
380}
381
8585e2b5 382/* static */
a536e411
JS
383int wxDisplayBase::GetFromPoint ( const wxPoint& pt )
384{
385 POINT pt2;
386 pt2.x = pt.x;
387 pt2.y = pt.y;
388
8585e2b5
VZ
389 return DisplayFromHMONITOR(::MonitorFromPoint(pt2, MONITOR_DEFAULTTONULL));
390}
a536e411 391
8585e2b5
VZ
392/* static */
393int wxDisplayBase::GetFromWindow(wxWindow *window)
394{
395 return DisplayFromHMONITOR
396 (
397 ::MonitorFromWindow(GetHwndOf(window), MONITOR_DEFAULTTONULL)
398 );
399}
400
06efac1f
VZ
401// ----------------------------------------------------------------------------
402// wxDisplay ctor/dtor
403// ----------------------------------------------------------------------------
404
8585e2b5
VZ
405wxDisplay::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();
06efac1f
VZ
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
455wxDisplay::~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
470bool wxDisplay::IsOk() const
471{
472 return m_index < GetCount() &&
473 (!gs_useDirectX || (*gs_displays)[m_index].m_pDD2);
8585e2b5
VZ
474}
475
476wxRect wxDisplay::GetGeometry() const
477{
06efac1f
VZ
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;
8585e2b5
VZ
497}
498
499wxString wxDisplay::GetName() const
500{
06efac1f 501 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
8585e2b5 502 if ( dpyInfo.m_devName.empty() )
a536e411 503 {
8585e2b5
VZ
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 }
a536e411
JS
516 }
517
8585e2b5 518 return dpyInfo.m_devName;
a536e411
JS
519}
520
8585e2b5 521wxString wxDisplay::GetNameForEnumSettings() const
a536e411 522{
8585e2b5
VZ
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;
a536e411
JS
535}
536
06efac1f
VZ
537// ----------------------------------------------------------------------------
538// video modes enumeration
539// ----------------------------------------------------------------------------
540
541wxArrayVideoModes
2eb10e2a 542wxDisplay::DoGetModesDirectX(const wxVideoMode& WXUNUSED(modeMatch)) const
06efac1f
VZ
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
567wxArrayVideoModes
568wxDisplay::DoGetModesWindows(const wxVideoMode& modeMatch) const
a536e411 569{
8585e2b5
VZ
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;
a536e411
JS
589}
590
06efac1f
VZ
591wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& modeMatch) const
592{
593 return gs_useDirectX ? DoGetModesDirectX(modeMatch)
594 : DoGetModesWindows(modeMatch);
595}
596
8585e2b5 597wxVideoMode wxDisplay::GetCurrentMode() const
a536e411 598{
8585e2b5
VZ
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;
a536e411
JS
616}
617
06efac1f
VZ
618// ----------------------------------------------------------------------------
619// video mode switching
620// ----------------------------------------------------------------------------
621
622bool 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
655bool wxDisplay::DoChangeModeWindows(const wxVideoMode& mode)
a536e411 656{
8585e2b5
VZ
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 {
06efac1f 670 wxCHECK_MSG( mode.w && mode.h, false,
8585e2b5
VZ
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
920b9675
JS
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 }
06efac1f 744 return true;
8585e2b5
VZ
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
06efac1f
VZ
754 return false;
755}
756
757bool wxDisplay::ChangeMode(const wxVideoMode& mode)
758{
759 return gs_useDirectX ? DoChangeModeDirectX(mode)
760 : DoChangeModeWindows(mode);
a536e411
JS
761}
762
8585e2b5
VZ
763#endif // wxUSE_DISPLAY
764