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