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