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