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