]> git.saurik.com Git - wxWidgets.git/blame - src/msw/display.cpp
Better markup.
[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
d71cc120 219HRESULT WINAPI wxDDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc,
06efac1f
VZ
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{
0b4f47a3 245#if wxUSE_LOG
06efac1f
VZ
246 // suppress the errors if ddraw.dll is not found
247 wxLog::EnableLogging(false);
0b4f47a3 248#endif
a536e411 249
06efac1f 250 wxDynamicLibrary dllDX(_T("ddraw.dll"));
a536e411 251
0b4f47a3
DS
252#if wxUSE_LOG
253 wxLog::EnableLogging();
254#endif
06efac1f
VZ
255
256 if ( !dllDX.IsLoaded() )
257 return false;
258
259 DirectDrawEnumerateEx_t pDDEnumEx = (DirectDrawEnumerateEx_t)
260 dllDX.GetSymbol(WINFUNC(DirectDrawEnumerateEx));
261 if ( !pDDEnumEx )
262 return false;
263
264 // we'll also need DirectDrawCreate() later, resolve it right now
265 gs_DirectDrawCreate = (DirectDrawCreate_t)
266 dllDX.GetSymbol(_T("DirectDrawCreate"));
267 if ( !gs_DirectDrawCreate )
268 return false;
269
270 if ( (*pDDEnumEx)(wxDDEnumExCallback,
271 NULL,
272 DDENUM_ATTACHEDSECONDARYDEVICES) != DD_OK )
273 {
274 return false;
275 }
276
277 // ok, it seems like we're going to use DirectDraw and so we're going to
278 // need ddraw.dll all the time, don't unload it
279 dllDX.Detach();
280
281 return true;
282}
283
284// initialize gs_displays using the standard Windows functions
285static void DoInitStdWindows()
286{
8585e2b5
VZ
287 // enumerate all displays
288 if ( !::EnumDisplayMonitors(NULL, NULL, wxmswMonitorEnumProc, 0) )
a536e411 289 {
8585e2b5
VZ
290 wxLogLastError(wxT("EnumDisplayMonitors"));
291
06efac1f 292 // TODO: still create at least one (valid) entry in gs_displays for the
8585e2b5 293 // primary display!
a536e411 294 }
8585e2b5 295}
a536e411 296
06efac1f
VZ
297// this function must be called before accessing gs_displays array as it
298// creates and initializes it
299static void InitDisplays()
300{
301 if ( gs_displays )
302 return;
303
304 gs_displays = new wxDisplayInfoArray();
305
82eba826 306 if ( !gs_useDirectX || !DoInitDirectX() )
06efac1f
VZ
307 {
308 // either we were told not to try to use DirectX or fall back to std
309 // functions if DirectX method failed
310 gs_useDirectX = false;
311
312 DoInitStdWindows();
313 }
314}
315
8585e2b5
VZ
316// convert a DEVMODE to our wxVideoMode
317wxVideoMode ConvertToVideoMode(const DEVMODE& dm)
318{
319 // note that dmDisplayFrequency may be 0 or 1 meaning "standard one" and
320 // although 0 is ok for us we don't want to return modes with 1hz refresh
321 return wxVideoMode(dm.dmPelsWidth,
322 dm.dmPelsHeight,
323 dm.dmBitsPerPel,
324 dm.dmDisplayFrequency > 1 ? dm.dmDisplayFrequency : 0);
325}
a536e411 326
8585e2b5
VZ
327// emulation of ChangeDisplaySettingsEx() for Win95
328LONG WINAPI ChangeDisplaySettingsExForWin95(LPCTSTR WXUNUSED(lpszDeviceName),
329 LPDEVMODE lpDevMode,
330 HWND WXUNUSED(hwnd),
331 DWORD dwFlags,
332 LPVOID WXUNUSED(lParam))
333{
334 return ::ChangeDisplaySettings(lpDevMode, dwFlags);
335}
a536e411 336
8585e2b5
VZ
337// ----------------------------------------------------------------------------
338// wxDisplayModule
339// ----------------------------------------------------------------------------
a536e411 340
8585e2b5
VZ
341void wxDisplayModule::OnExit()
342{
06efac1f 343 delete gs_displays;
8585e2b5 344}
a536e411 345
8585e2b5
VZ
346// ---------------------------------------------------------------------------
347// wxDisplay
348// ---------------------------------------------------------------------------
a536e411 349
06efac1f
VZ
350/* static */
351void wxDisplay::UseDirectX(bool useDX)
352{
353 wxCHECK_RET( !gs_displays, _T("it is too late to call UseDirectX") );
354
355 gs_useDirectX = useDX;
356}
357
8585e2b5
VZ
358// helper of GetFromPoint() and GetFromWindow()
359static int DisplayFromHMONITOR(HMONITOR hmon)
360{
361 if ( hmon )
362 {
363 const size_t count = wxDisplay::GetCount();
a536e411 364
8585e2b5 365 for ( size_t n = 0; n < count; n++ )
a536e411 366 {
06efac1f 367 if ( hmon == (*gs_displays)[n].m_hmon )
8585e2b5 368 return n;
a536e411 369 }
a536e411 370 }
a536e411 371
8585e2b5 372 return wxNOT_FOUND;
a536e411
JS
373}
374
8585e2b5 375/* static */
a536e411
JS
376size_t wxDisplayBase::GetCount()
377{
8585e2b5
VZ
378 InitDisplays();
379
380 // I'm not sure if they really always return the same thing and if this is
381 // not true I'd like to know in which situation does it happen
06efac1f 382 wxASSERT_MSG( gs_displays->GetCount() == (size_t)::GetSystemMetrics(SM_CMONITORS),
8585e2b5
VZ
383 _T("So how many displays does this system have?") );
384
06efac1f 385 return gs_displays->GetCount();
a536e411
JS
386}
387
8585e2b5 388/* static */
a536e411
JS
389int wxDisplayBase::GetFromPoint ( const wxPoint& pt )
390{
391 POINT pt2;
392 pt2.x = pt.x;
393 pt2.y = pt.y;
394
8585e2b5
VZ
395 return DisplayFromHMONITOR(::MonitorFromPoint(pt2, MONITOR_DEFAULTTONULL));
396}
a536e411 397
8585e2b5
VZ
398/* static */
399int wxDisplayBase::GetFromWindow(wxWindow *window)
400{
401 return DisplayFromHMONITOR
402 (
403 ::MonitorFromWindow(GetHwndOf(window), MONITOR_DEFAULTTONULL)
404 );
405}
406
06efac1f
VZ
407// ----------------------------------------------------------------------------
408// wxDisplay ctor/dtor
409// ----------------------------------------------------------------------------
410
8585e2b5
VZ
411wxDisplay::wxDisplay ( size_t n )
412 : wxDisplayBase ( n )
413{
414 // if we do this in ctor we won't have to call it from all the member
415 // functions
416 InitDisplays();
06efac1f
VZ
417
418 if ( gs_useDirectX )
419 {
420 wxDisplayInfo& dpyInfo = (*gs_displays)[n];
421
422 LPDIRECTDRAW2& pDD2 = dpyInfo.m_pDD2;
423 if ( !pDD2 )
424 {
425 if ( !gs_DirectDrawCreate )
426 {
427 // what to do??
428 return;
429 }
430
431 IDirectDraw *pDD;
432 HRESULT hr = (*gs_DirectDrawCreate)(&dpyInfo.m_guid, &pDD, NULL);
433
434 if ( FAILED(hr) || !pDD )
435 {
436 // what to do??
437 wxLogApiError(_T("DirectDrawCreate"), hr);
438 }
439 else // got IDirectDraw, we want IDirectDraw2
440 {
441 hr = pDD->QueryInterface(wxIID_IDirectDraw2, (void **)&pDD2);
442 if ( FAILED(hr) || !pDD2 )
443 {
444 wxLogApiError(_T("IDirectDraw::QueryInterface(IDD2)"), hr);
445 }
446
447 pDD->Release();
448 }
449 }
450 //else: DirectDraw object corresponding to our display already exists
451
452 // increment its ref count to account for Release() in dtor
453 //
454 // NB: pDD2 will be only really Release()d when gs_displays is
455 // destroyed which is ok as we don't want to recreate DD objects
456 // all the time
457 pDD2->AddRef();
458 }
459}
460
461wxDisplay::~wxDisplay()
462{
463 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
464
465 LPDIRECTDRAW2& pDD2 = dpyInfo.m_pDD2;
466 if ( pDD2 )
467 {
468 pDD2->Release();
469 }
470}
471
472// ----------------------------------------------------------------------------
473// wxDisplay simple accessors
474// ----------------------------------------------------------------------------
475
476bool wxDisplay::IsOk() const
477{
478 return m_index < GetCount() &&
479 (!gs_useDirectX || (*gs_displays)[m_index].m_pDD2);
8585e2b5
VZ
480}
481
482wxRect wxDisplay::GetGeometry() const
483{
06efac1f
VZ
484 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
485 wxRect& rect = dpyInfo.m_rect;
486 if ( !rect.width )
487 {
488 MONITORINFO monInfo;
489 wxZeroMemory(monInfo);
490 monInfo.cbSize = sizeof(monInfo);
491
492 if ( !::GetMonitorInfo(dpyInfo.m_hmon, &monInfo) )
493 {
494 wxLogLastError(_T("GetMonitorInfo"));
495 }
496 else
497 {
498 wxCopyRECTToRect(monInfo.rcMonitor, rect);
499 }
500 }
501
502 return rect;
8585e2b5
VZ
503}
504
505wxString wxDisplay::GetName() const
506{
06efac1f 507 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
8585e2b5 508 if ( dpyInfo.m_devName.empty() )
a536e411 509 {
8585e2b5
VZ
510 MONITORINFOEX monInfo;
511 wxZeroMemory(monInfo);
512 monInfo.cbSize = sizeof(monInfo);
513
f29cfd77
VS
514 // NB: Cast from MONITORINFOEX* to MONITORINFO* is done because
515 // Mingw headers - unlike the ones from Microsoft's Platform SDK -
516 // don't derive the former from the latter in C++ mode and so
517 // the pointer's type is not converted implicitly.
518 if ( !::GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) )
8585e2b5
VZ
519 {
520 wxLogLastError(_T("GetMonitorInfo"));
521 }
522 else
523 {
524 dpyInfo.m_devName = monInfo.szDevice;
525 }
a536e411
JS
526 }
527
8585e2b5 528 return dpyInfo.m_devName;
a536e411
JS
529}
530
8585e2b5 531wxString wxDisplay::GetNameForEnumSettings() const
a536e411 532{
8585e2b5
VZ
533 int major, minor;
534 const bool isWin95 = wxGetOsVersion(&major, &minor) == wxWIN95 &&
535 major == 4 && minor == 0;
536
537 // the first parameter of EnumDisplaySettings() must be NULL under Win95
538 // according to MSDN but GetMonitorInfo() stub in multimon.h still returns
539 // something even in this case, so we have to correct this manually
540 wxString name;
541 if ( !isWin95 )
542 name = GetName();
543
544 return name;
a536e411
JS
545}
546
06efac1f
VZ
547// ----------------------------------------------------------------------------
548// video modes enumeration
549// ----------------------------------------------------------------------------
550
551wxArrayVideoModes
2eb10e2a 552wxDisplay::DoGetModesDirectX(const wxVideoMode& WXUNUSED(modeMatch)) const
06efac1f
VZ
553{
554 wxArrayVideoModes modes;
555
556 IDirectDraw2 *pDD = (*gs_displays)[m_index].m_pDD2;
557
558 if ( pDD )
559 {
560 HRESULT hr = pDD->EnumDisplayModes
561 (
562 DDEDM_REFRESHRATES,
563 NULL, // all modes (TODO: use modeMatch!)
564 &modes, // callback parameter
565 wxDDEnumModesCallback
566 );
567
568 if ( FAILED(hr) )
569 {
570 wxLogApiError(_T("IDirectDraw::EnumDisplayModes"), hr);
571 }
572 }
573
574 return modes;
575}
576
577wxArrayVideoModes
578wxDisplay::DoGetModesWindows(const wxVideoMode& modeMatch) const
a536e411 579{
8585e2b5
VZ
580 wxArrayVideoModes modes;
581
582 const wxString name = GetNameForEnumSettings();
583
584 const wxChar * const deviceName = name.empty() ? NULL : name.c_str();
585
586 DEVMODE dm;
587 for ( int iModeNum = 0;
588 ::EnumDisplaySettings(deviceName, iModeNum, &dm);
589 iModeNum++ )
590 {
591 const wxVideoMode mode = ConvertToVideoMode(dm);
592 if ( mode.Matches(modeMatch) )
593 {
594 modes.Add(mode);
595 }
596 }
597
598 return modes;
a536e411
JS
599}
600
06efac1f
VZ
601wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& modeMatch) const
602{
603 return gs_useDirectX ? DoGetModesDirectX(modeMatch)
604 : DoGetModesWindows(modeMatch);
605}
606
8585e2b5 607wxVideoMode wxDisplay::GetCurrentMode() const
a536e411 608{
8585e2b5
VZ
609 wxVideoMode mode;
610
611 const wxString name = GetNameForEnumSettings();
612
613 DEVMODE dm;
614 if ( !::EnumDisplaySettings(name.empty() ? NULL : name.c_str(),
615 ENUM_CURRENT_SETTINGS,
616 &dm) )
617 {
618 wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
619 }
620 else
621 {
622 mode = ConvertToVideoMode(dm);
623 }
624
625 return mode;
a536e411
JS
626}
627
06efac1f
VZ
628// ----------------------------------------------------------------------------
629// video mode switching
630// ----------------------------------------------------------------------------
631
632bool wxDisplay::DoChangeModeDirectX(const wxVideoMode& mode)
633{
634 IDirectDraw2 *pDD = (*gs_displays)[m_index].m_pDD2;
635 if ( !pDD )
636 return false;
637
638 wxWindow *winTop = wxTheApp->GetTopWindow();
639 wxCHECK_MSG( winTop, false, _T("top level window required for DirectX") );
640
641 HRESULT hr = pDD->SetCooperativeLevel
642 (
643 GetHwndOf(winTop),
644 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN
645 );
646 if ( FAILED(hr) )
647 {
648 wxLogApiError(_T("IDirectDraw::SetCooperativeLevel"), hr);
649
650 return false;
651 }
652
653 hr = pDD->SetDisplayMode(mode.w, mode.h, mode.bpp, mode.refresh, 0);
654 if ( FAILED(hr) )
655 {
656 wxLogApiError(_T("IDirectDraw::SetDisplayMode"), hr);
657
658 return false;
659 }
660
d71cc120 661
06efac1f
VZ
662 return true;
663}
664
665bool wxDisplay::DoChangeModeWindows(const wxVideoMode& mode)
a536e411 666{
8585e2b5
VZ
667 // prepare ChangeDisplaySettingsEx() parameters
668 DEVMODE dm,
669 *pDevMode;
670 int flags;
671
672 if ( mode == wxDefaultVideoMode )
673 {
674 // reset the video mode to default
675 pDevMode = NULL;
676 flags = 0;
677 }
678 else // change to the given mode
679 {
06efac1f 680 wxCHECK_MSG( mode.w && mode.h, false,
8585e2b5
VZ
681 _T("at least the width and height must be specified") );
682
683 wxZeroMemory(dm);
684 dm.dmSize = sizeof(dm);
685 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
686 dm.dmPelsWidth = mode.w;
687 dm.dmPelsHeight = mode.h;
688
689 if ( mode.bpp )
690 {
691 dm.dmFields |= DM_BITSPERPEL;
692 dm.dmBitsPerPel = mode.bpp;
693 }
694
695 if ( mode.refresh )
696 {
697 dm.dmFields |= DM_DISPLAYFREQUENCY;
698 dm.dmDisplayFrequency = mode.refresh;
699 }
700
701 pDevMode = &dm;
702
703 flags = CDS_FULLSCREEN;
704 }
705
706
707 // get pointer to the function dynamically
708 //
709 // we're only called from the main thread, so it's ok to use static
710 // variable
711 static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx = NULL;
712 if ( !pfnChangeDisplaySettingsEx )
713 {
714 wxDynamicLibrary dllUser32(_T("user32.dll"));
715 if ( dllUser32.IsLoaded() )
716 {
717 pfnChangeDisplaySettingsEx = (ChangeDisplaySettingsEx_t)
718 dllUser32.GetSymbol(WINFUNC(ChangeDisplaySettingsEx));
719 }
720 //else: huh, no user32.dll??
721
722 if ( !pfnChangeDisplaySettingsEx )
723 {
724 // we must be under Win95 and so there is no multiple monitors
725 // support anyhow
726 pfnChangeDisplaySettingsEx = ChangeDisplaySettingsExForWin95;
727 }
728 }
729
730 // do change the mode
731 switch ( pfnChangeDisplaySettingsEx
732 (
733 GetName(), // display name
734 pDevMode, // dev mode or NULL to reset
735 NULL, // reserved
736 flags,
737 NULL // pointer to video parameters (not used)
738 ) )
739 {
740 case DISP_CHANGE_SUCCESSFUL:
741 // ok
920b9675
JS
742 {
743 // If we have a top-level, full-screen frame, emulate
744 // the DirectX behavior and resize it. This makes this
745 // API quite a bit easier to use.
746 wxWindow *winTop = wxTheApp->GetTopWindow();
747 wxFrame *frameTop = wxDynamicCast(winTop, wxFrame);
748 if (frameTop && frameTop->IsFullScreen())
749 {
750 wxVideoMode current = GetCurrentMode();
751 frameTop->SetClientSize(current.w, current.h);
752 }
753 }
06efac1f 754 return true;
8585e2b5
VZ
755
756 case DISP_CHANGE_BADMODE:
757 // don't complain about this, this is the only "expected" error
758 break;
759
760 default:
761 wxFAIL_MSG( _T("unexpected ChangeDisplaySettingsEx() return value") );
762 }
763
06efac1f
VZ
764 return false;
765}
766
767bool wxDisplay::ChangeMode(const wxVideoMode& mode)
768{
769 return gs_useDirectX ? DoChangeModeDirectX(mode)
770 : DoChangeModeWindows(mode);
a536e411
JS
771}
772
8585e2b5
VZ
773#endif // wxUSE_DISPLAY
774