]> git.saurik.com Git - wxWidgets.git/blame - src/msw/display.cpp
Implement wxChoice::Insert.
[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
a536e411
JS
21// For compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23
24#ifdef __BORLANDC__
25 #pragma hdrstop
26#endif
27
28#if wxUSE_DISPLAY
29
30#ifndef WX_PRECOMP
f29cfd77 31 #include "wx/app.h"
a536e411 32 #include "wx/dynarray.h"
f29cfd77 33 #include "wx/frame.h"
a536e411
JS
34#endif
35
8585e2b5
VZ
36#include "wx/dynload.h"
37
a536e411
JS
38#include "wx/display.h"
39
40// the following define is necessary to access the multi-monitor function
41// declarations in a manner safe to use w/ Windows 95
a536e411 42#define COMPILE_MULTIMON_STUBS
8585e2b5
VZ
43
44// if you don't have multimon.h you can download the file from:
45//
46// http://www.microsoft.com/msj/0697/monitor/monitortextfigs.htm#fig4
47//
48
49#ifdef _MSC_VER
06efac1f 50 // as (m)any standard header(s), this one doesn't compile without warnings
8585e2b5
VZ
51 // with VC++ 6 <sigh>
52 #pragma warning(disable:4706)
a536e411
JS
53#endif
54
8193d58f
VZ
55// with mingw32, we must include windows.h first and it doesn't hurt with other
56// compilers
57#include <windows.h>
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
6fcf77f4
RN
381 //RN: FIXME: This is wrong - the display info array should reload after every call
382 //to GetCount() - otherwise it will not be accurate.
383 //The user can change the number of displays in display properties/settings
384 //after GetCount or similar is called and really mess this up...
385 //wxASSERT_MSG( gs_displays->GetCount() == (size_t)::GetSystemMetrics(SM_CMONITORS),
386 // _T("So how many displays does this system have?") );
8585e2b5 387
06efac1f 388 return gs_displays->GetCount();
a536e411
JS
389}
390
8585e2b5 391/* static */
a536e411
JS
392int wxDisplayBase::GetFromPoint ( const wxPoint& pt )
393{
394 POINT pt2;
395 pt2.x = pt.x;
396 pt2.y = pt.y;
397
8585e2b5
VZ
398 return DisplayFromHMONITOR(::MonitorFromPoint(pt2, MONITOR_DEFAULTTONULL));
399}
a536e411 400
8585e2b5
VZ
401/* static */
402int wxDisplayBase::GetFromWindow(wxWindow *window)
403{
404 return DisplayFromHMONITOR
405 (
406 ::MonitorFromWindow(GetHwndOf(window), MONITOR_DEFAULTTONULL)
407 );
408}
409
06efac1f
VZ
410// ----------------------------------------------------------------------------
411// wxDisplay ctor/dtor
412// ----------------------------------------------------------------------------
413
8585e2b5
VZ
414wxDisplay::wxDisplay ( size_t n )
415 : wxDisplayBase ( n )
416{
417 // if we do this in ctor we won't have to call it from all the member
418 // functions
419 InitDisplays();
06efac1f
VZ
420
421 if ( gs_useDirectX )
422 {
423 wxDisplayInfo& dpyInfo = (*gs_displays)[n];
424
425 LPDIRECTDRAW2& pDD2 = dpyInfo.m_pDD2;
426 if ( !pDD2 )
427 {
428 if ( !gs_DirectDrawCreate )
429 {
430 // what to do??
431 return;
432 }
433
434 IDirectDraw *pDD;
435 HRESULT hr = (*gs_DirectDrawCreate)(&dpyInfo.m_guid, &pDD, NULL);
436
437 if ( FAILED(hr) || !pDD )
438 {
439 // what to do??
440 wxLogApiError(_T("DirectDrawCreate"), hr);
441 }
442 else // got IDirectDraw, we want IDirectDraw2
443 {
444 hr = pDD->QueryInterface(wxIID_IDirectDraw2, (void **)&pDD2);
445 if ( FAILED(hr) || !pDD2 )
446 {
447 wxLogApiError(_T("IDirectDraw::QueryInterface(IDD2)"), hr);
448 }
449
450 pDD->Release();
451 }
452 }
453 //else: DirectDraw object corresponding to our display already exists
454
455 // increment its ref count to account for Release() in dtor
456 //
457 // NB: pDD2 will be only really Release()d when gs_displays is
458 // destroyed which is ok as we don't want to recreate DD objects
459 // all the time
460 pDD2->AddRef();
461 }
462}
463
464wxDisplay::~wxDisplay()
465{
466 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
467
468 LPDIRECTDRAW2& pDD2 = dpyInfo.m_pDD2;
469 if ( pDD2 )
470 {
471 pDD2->Release();
472 }
473}
474
475// ----------------------------------------------------------------------------
476// wxDisplay simple accessors
477// ----------------------------------------------------------------------------
478
479bool wxDisplay::IsOk() const
480{
481 return m_index < GetCount() &&
482 (!gs_useDirectX || (*gs_displays)[m_index].m_pDD2);
8585e2b5
VZ
483}
484
485wxRect wxDisplay::GetGeometry() const
486{
06efac1f
VZ
487 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
488 wxRect& rect = dpyInfo.m_rect;
489 if ( !rect.width )
490 {
491 MONITORINFO monInfo;
492 wxZeroMemory(monInfo);
493 monInfo.cbSize = sizeof(monInfo);
494
495 if ( !::GetMonitorInfo(dpyInfo.m_hmon, &monInfo) )
496 {
497 wxLogLastError(_T("GetMonitorInfo"));
498 }
499 else
500 {
501 wxCopyRECTToRect(monInfo.rcMonitor, rect);
502 }
503 }
504
505 return rect;
8585e2b5
VZ
506}
507
508wxString wxDisplay::GetName() const
509{
06efac1f 510 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
8585e2b5 511 if ( dpyInfo.m_devName.empty() )
a536e411 512 {
8585e2b5
VZ
513 MONITORINFOEX monInfo;
514 wxZeroMemory(monInfo);
515 monInfo.cbSize = sizeof(monInfo);
516
f29cfd77
VS
517 // NB: Cast from MONITORINFOEX* to MONITORINFO* is done because
518 // Mingw headers - unlike the ones from Microsoft's Platform SDK -
519 // don't derive the former from the latter in C++ mode and so
520 // the pointer's type is not converted implicitly.
521 if ( !::GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) )
8585e2b5
VZ
522 {
523 wxLogLastError(_T("GetMonitorInfo"));
524 }
525 else
526 {
527 dpyInfo.m_devName = monInfo.szDevice;
528 }
a536e411
JS
529 }
530
8585e2b5 531 return dpyInfo.m_devName;
a536e411
JS
532}
533
8585e2b5 534wxString wxDisplay::GetNameForEnumSettings() const
a536e411 535{
8585e2b5
VZ
536 int major, minor;
537 const bool isWin95 = wxGetOsVersion(&major, &minor) == wxWIN95 &&
538 major == 4 && minor == 0;
539
540 // the first parameter of EnumDisplaySettings() must be NULL under Win95
541 // according to MSDN but GetMonitorInfo() stub in multimon.h still returns
542 // something even in this case, so we have to correct this manually
543 wxString name;
544 if ( !isWin95 )
545 name = GetName();
546
547 return name;
a536e411
JS
548}
549
24d2b4f5
RN
550// ----------------------------------------------------------------------------
551// determine if this is the primary display
552// ----------------------------------------------------------------------------
553
554bool wxDisplay::IsPrimary() const
555{
556 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
557
558 MONITORINFOEX monInfo;
559 wxZeroMemory(monInfo);
560 monInfo.cbSize = sizeof(monInfo);
561
562 // NB: Cast from MONITORINFOEX* to MONITORINFO* is done because
563 // Mingw headers - unlike the ones from Microsoft's Platform SDK -
564 // don't derive the former from the latter in C++ mode and so
565 // the pointer's type is not converted implicitly.
566 if ( !::GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) )
567 {
568 wxLogLastError(_T("GetMonitorInfo"));
569 }
570
571 return (monInfo.dwFlags & MONITORINFOF_PRIMARY) == MONITORINFOF_PRIMARY;
572}
573
06efac1f
VZ
574// ----------------------------------------------------------------------------
575// video modes enumeration
576// ----------------------------------------------------------------------------
577
578wxArrayVideoModes
2eb10e2a 579wxDisplay::DoGetModesDirectX(const wxVideoMode& WXUNUSED(modeMatch)) const
06efac1f
VZ
580{
581 wxArrayVideoModes modes;
582
583 IDirectDraw2 *pDD = (*gs_displays)[m_index].m_pDD2;
584
585 if ( pDD )
586 {
587 HRESULT hr = pDD->EnumDisplayModes
588 (
589 DDEDM_REFRESHRATES,
590 NULL, // all modes (TODO: use modeMatch!)
591 &modes, // callback parameter
592 wxDDEnumModesCallback
593 );
594
595 if ( FAILED(hr) )
596 {
597 wxLogApiError(_T("IDirectDraw::EnumDisplayModes"), hr);
598 }
599 }
600
601 return modes;
602}
603
604wxArrayVideoModes
605wxDisplay::DoGetModesWindows(const wxVideoMode& modeMatch) const
a536e411 606{
8585e2b5
VZ
607 wxArrayVideoModes modes;
608
609 const wxString name = GetNameForEnumSettings();
610
611 const wxChar * const deviceName = name.empty() ? NULL : name.c_str();
612
613 DEVMODE dm;
614 for ( int iModeNum = 0;
615 ::EnumDisplaySettings(deviceName, iModeNum, &dm);
616 iModeNum++ )
617 {
618 const wxVideoMode mode = ConvertToVideoMode(dm);
619 if ( mode.Matches(modeMatch) )
620 {
621 modes.Add(mode);
622 }
623 }
624
625 return modes;
a536e411
JS
626}
627
06efac1f
VZ
628wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& modeMatch) const
629{
630 return gs_useDirectX ? DoGetModesDirectX(modeMatch)
631 : DoGetModesWindows(modeMatch);
632}
633
8585e2b5 634wxVideoMode wxDisplay::GetCurrentMode() const
a536e411 635{
8585e2b5
VZ
636 wxVideoMode mode;
637
638 const wxString name = GetNameForEnumSettings();
639
640 DEVMODE dm;
641 if ( !::EnumDisplaySettings(name.empty() ? NULL : name.c_str(),
642 ENUM_CURRENT_SETTINGS,
643 &dm) )
644 {
645 wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
646 }
647 else
648 {
649 mode = ConvertToVideoMode(dm);
650 }
651
652 return mode;
a536e411
JS
653}
654
06efac1f
VZ
655// ----------------------------------------------------------------------------
656// video mode switching
657// ----------------------------------------------------------------------------
658
659bool wxDisplay::DoChangeModeDirectX(const wxVideoMode& mode)
660{
661 IDirectDraw2 *pDD = (*gs_displays)[m_index].m_pDD2;
662 if ( !pDD )
663 return false;
664
665 wxWindow *winTop = wxTheApp->GetTopWindow();
666 wxCHECK_MSG( winTop, false, _T("top level window required for DirectX") );
667
668 HRESULT hr = pDD->SetCooperativeLevel
669 (
670 GetHwndOf(winTop),
671 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN
672 );
673 if ( FAILED(hr) )
674 {
675 wxLogApiError(_T("IDirectDraw::SetCooperativeLevel"), hr);
676
677 return false;
678 }
679
680 hr = pDD->SetDisplayMode(mode.w, mode.h, mode.bpp, mode.refresh, 0);
681 if ( FAILED(hr) )
682 {
683 wxLogApiError(_T("IDirectDraw::SetDisplayMode"), hr);
684
685 return false;
686 }
687
d71cc120 688
06efac1f
VZ
689 return true;
690}
691
692bool wxDisplay::DoChangeModeWindows(const wxVideoMode& mode)
a536e411 693{
8585e2b5
VZ
694 // prepare ChangeDisplaySettingsEx() parameters
695 DEVMODE dm,
696 *pDevMode;
697 int flags;
698
699 if ( mode == wxDefaultVideoMode )
700 {
701 // reset the video mode to default
702 pDevMode = NULL;
703 flags = 0;
704 }
705 else // change to the given mode
706 {
06efac1f 707 wxCHECK_MSG( mode.w && mode.h, false,
8585e2b5
VZ
708 _T("at least the width and height must be specified") );
709
710 wxZeroMemory(dm);
711 dm.dmSize = sizeof(dm);
712 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
713 dm.dmPelsWidth = mode.w;
714 dm.dmPelsHeight = mode.h;
715
716 if ( mode.bpp )
717 {
718 dm.dmFields |= DM_BITSPERPEL;
719 dm.dmBitsPerPel = mode.bpp;
720 }
721
722 if ( mode.refresh )
723 {
724 dm.dmFields |= DM_DISPLAYFREQUENCY;
725 dm.dmDisplayFrequency = mode.refresh;
726 }
727
728 pDevMode = &dm;
729
730 flags = CDS_FULLSCREEN;
731 }
732
733
734 // get pointer to the function dynamically
735 //
736 // we're only called from the main thread, so it's ok to use static
737 // variable
738 static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx = NULL;
739 if ( !pfnChangeDisplaySettingsEx )
740 {
741 wxDynamicLibrary dllUser32(_T("user32.dll"));
742 if ( dllUser32.IsLoaded() )
743 {
744 pfnChangeDisplaySettingsEx = (ChangeDisplaySettingsEx_t)
745 dllUser32.GetSymbol(WINFUNC(ChangeDisplaySettingsEx));
746 }
747 //else: huh, no user32.dll??
748
749 if ( !pfnChangeDisplaySettingsEx )
750 {
751 // we must be under Win95 and so there is no multiple monitors
752 // support anyhow
753 pfnChangeDisplaySettingsEx = ChangeDisplaySettingsExForWin95;
754 }
755 }
756
757 // do change the mode
758 switch ( pfnChangeDisplaySettingsEx
759 (
760 GetName(), // display name
761 pDevMode, // dev mode or NULL to reset
762 NULL, // reserved
763 flags,
764 NULL // pointer to video parameters (not used)
765 ) )
766 {
767 case DISP_CHANGE_SUCCESSFUL:
768 // ok
920b9675
JS
769 {
770 // If we have a top-level, full-screen frame, emulate
771 // the DirectX behavior and resize it. This makes this
772 // API quite a bit easier to use.
773 wxWindow *winTop = wxTheApp->GetTopWindow();
774 wxFrame *frameTop = wxDynamicCast(winTop, wxFrame);
775 if (frameTop && frameTop->IsFullScreen())
776 {
777 wxVideoMode current = GetCurrentMode();
778 frameTop->SetClientSize(current.w, current.h);
779 }
780 }
06efac1f 781 return true;
8585e2b5
VZ
782
783 case DISP_CHANGE_BADMODE:
784 // don't complain about this, this is the only "expected" error
785 break;
786
787 default:
788 wxFAIL_MSG( _T("unexpected ChangeDisplaySettingsEx() return value") );
789 }
790
06efac1f
VZ
791 return false;
792}
793
794bool wxDisplay::ChangeMode(const wxVideoMode& mode)
795{
796 return gs_useDirectX ? DoChangeModeDirectX(mode)
797 : DoChangeModeWindows(mode);
a536e411
JS
798}
799
8585e2b5
VZ
800#endif // wxUSE_DISPLAY
801