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