]> git.saurik.com Git - wxWidgets.git/blob - src/msw/display.cpp
don't require multimon.h any more now (patch 1446030); enable wxUSE_DISPLAY by default
[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 #endif
427 }
428
429 // helper for GetFromPoint() and GetFromWindow()
430 static int DisplayFromHMONITOR(HMONITOR hmon)
431 {
432 if ( hmon )
433 {
434 const size_t count = wxDisplay::GetCount();
435
436 for ( size_t n = 0; n < count; n++ )
437 {
438 if ( hmon == (*gs_displays)[n].m_hmon )
439 return n;
440 }
441 }
442
443 return wxNOT_FOUND;
444 }
445
446 /* static */
447 size_t wxDisplayBase::GetCount()
448 {
449 if ( !OsSupportsMultipleMonitors() ) return 1;
450
451 InitDisplays();
452
453 //RN: FIXME: This is wrong - the display info array should reload after every call
454 //to GetCount() - otherwise it will not be accurate.
455 //The user can change the number of displays in display properties/settings
456 //after GetCount or similar is called and really mess this up...
457 //wxASSERT_MSG( gs_displays->GetCount() == (size_t)::GetSystemMetrics(SM_CMONITORS),
458 // _T("So how many displays does this system have?") );
459
460 return gs_displays->GetCount();
461 }
462
463 /* static */
464 int wxDisplayBase::GetFromPoint ( const wxPoint& pt )
465 {
466 if ( !OsSupportsMultipleMonitors() )
467 {
468 const wxSize size = wxGetDisplaySize();
469 if (pt.x >= 0 && pt.x < size.GetWidth() &&
470 pt.y >= 0 && pt.y < size.GetHeight())
471 {
472 return 0;
473 }
474 return wxNOT_FOUND;
475 }
476
477 POINT pt2;
478 pt2.x = pt.x;
479 pt2.y = pt.y;
480
481 return DisplayFromHMONITOR(gs_MonitorFromPoint(pt2, MONITOR_DEFAULTTONULL));
482 }
483
484 /* static */
485 int wxDisplayBase::GetFromWindow(wxWindow *window)
486 {
487 if ( !OsSupportsMultipleMonitors() )
488 {
489 const wxRect r(window->GetRect());
490 const wxSize size = wxGetDisplaySize();
491 if (r.x < size.GetWidth() && r.x + r.width >= 0 &&
492 r.y < size.GetHeight() && r.y + r.height >= 0)
493 {
494 return 0;
495 }
496 return wxNOT_FOUND;
497 }
498
499 return DisplayFromHMONITOR
500 (
501 gs_MonitorFromWindow(GetHwndOf(window), MONITOR_DEFAULTTONULL)
502 );
503 }
504
505 // ----------------------------------------------------------------------------
506 // wxDisplay ctor/dtor
507 // ----------------------------------------------------------------------------
508
509 wxDisplay::wxDisplay ( size_t n )
510 : wxDisplayBase ( n )
511 {
512 if ( !OsSupportsMultipleMonitors() ) return;
513
514 // if we do this in ctor we won't have to call it from all the member
515 // functions
516 InitDisplays();
517
518 #ifdef HAVE_DDRAW_H
519 if ( gs_useDirectX )
520 {
521 wxDisplayInfo& dpyInfo = (*gs_displays)[n];
522
523 LPDIRECTDRAW2& pDD2 = dpyInfo.m_pDD2;
524 if ( !pDD2 )
525 {
526 if ( !gs_DirectDrawCreate )
527 {
528 // what to do??
529 return;
530 }
531
532 IDirectDraw *pDD;
533 HRESULT hr = (*gs_DirectDrawCreate)(&dpyInfo.m_guid, &pDD, NULL);
534
535 if ( FAILED(hr) || !pDD )
536 {
537 // what to do??
538 wxLogApiError(_T("DirectDrawCreate"), hr);
539 }
540 else // got IDirectDraw, we want IDirectDraw2
541 {
542 hr = pDD->QueryInterface(wxIID_IDirectDraw2, (void **)&pDD2);
543 if ( FAILED(hr) || !pDD2 )
544 {
545 wxLogApiError(_T("IDirectDraw::QueryInterface(IDD2)"), hr);
546 }
547
548 pDD->Release();
549 }
550 }
551 //else: DirectDraw object corresponding to our display already exists
552
553 // increment its ref count to account for Release() in dtor
554 //
555 // NB: pDD2 will be only really Release()d when gs_displays is
556 // destroyed which is ok as we don't want to recreate DD objects
557 // all the time
558 pDD2->AddRef();
559 }
560 #endif
561 }
562
563 wxDisplay::~wxDisplay()
564 {
565 #ifdef HAVE_DDRAW_H
566 if ( !OsSupportsMultipleMonitors() ) return;
567
568 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
569
570 LPDIRECTDRAW2& pDD2 = dpyInfo.m_pDD2;
571 if ( pDD2 )
572 {
573 pDD2->Release();
574 }
575 #endif
576 }
577
578 // ----------------------------------------------------------------------------
579 // wxDisplay simple accessors
580 // ----------------------------------------------------------------------------
581
582 bool wxDisplay::IsOk() const
583 {
584 #ifdef HAVE_DDRAW_H
585 return m_index < GetCount() &&
586 (!gs_useDirectX || (*gs_displays)[m_index].m_pDD2);
587 #else
588 return m_index < GetCount();
589 #endif
590 }
591
592 wxRect wxDisplay::GetGeometry() const
593 {
594 if ( !OsSupportsMultipleMonitors() )
595 {
596 wxSize size = wxGetDisplaySize();
597 return wxRect(0, 0, size.GetWidth(), size.GetHeight());
598 }
599
600 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
601 wxRect& rect = dpyInfo.m_rect;
602 if ( !rect.width )
603 {
604 MONITORINFO monInfo;
605 wxZeroMemory(monInfo);
606 monInfo.cbSize = sizeof(monInfo);
607
608 if ( !gs_GetMonitorInfo(dpyInfo.m_hmon, &monInfo) )
609 {
610 wxLogLastError(_T("GetMonitorInfo"));
611 }
612 else
613 {
614 wxCopyRECTToRect(monInfo.rcMonitor, rect);
615 }
616 }
617
618 return rect;
619 }
620
621 wxString wxDisplay::GetName() const
622 {
623 if ( !OsSupportsMultipleMonitors() ) return wxT("");
624
625 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
626 if ( dpyInfo.m_devName.empty() )
627 {
628 MONITORINFOEX monInfo;
629 wxZeroMemory(monInfo);
630 monInfo.cbSize = sizeof(monInfo);
631
632 // NB: Cast from MONITORINFOEX* to MONITORINFO* is done because
633 // Mingw headers - unlike the ones from Microsoft's Platform SDK -
634 // don't derive the former from the latter in C++ mode and so
635 // the pointer's type is not converted implicitly.
636 if ( !gs_GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) )
637 {
638 wxLogLastError(_T("GetMonitorInfo"));
639 }
640 else
641 {
642 dpyInfo.m_devName = monInfo.szDevice;
643 }
644 }
645
646 return dpyInfo.m_devName;
647 }
648
649 // ----------------------------------------------------------------------------
650 // determine if this is the primary display
651 // ----------------------------------------------------------------------------
652
653 bool wxDisplay::IsPrimary() const
654 {
655 if ( !OsSupportsMultipleMonitors() ) return true;
656
657 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
658
659 MONITORINFOEX monInfo;
660 wxZeroMemory(monInfo);
661 monInfo.cbSize = sizeof(monInfo);
662
663 // NB: Cast from MONITORINFOEX* to MONITORINFO* is done because
664 // Mingw headers - unlike the ones from Microsoft's Platform SDK -
665 // don't derive the former from the latter in C++ mode and so
666 // the pointer's type is not converted implicitly.
667 if ( !gs_GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) )
668 {
669 wxLogLastError(_T("GetMonitorInfo"));
670 }
671
672 return (monInfo.dwFlags & MONITORINFOF_PRIMARY) == MONITORINFOF_PRIMARY;
673 }
674
675 // ----------------------------------------------------------------------------
676 // video modes enumeration
677 // ----------------------------------------------------------------------------
678
679 #ifdef HAVE_DDRAW_H
680 wxArrayVideoModes
681 wxDisplay::DoGetModesDirectX(const wxVideoMode& WXUNUSED(modeMatch)) const
682 {
683 wxArrayVideoModes modes;
684
685 IDirectDraw2 *pDD = (*gs_displays)[m_index].m_pDD2;
686
687 if ( pDD )
688 {
689 HRESULT hr = pDD->EnumDisplayModes
690 (
691 DDEDM_REFRESHRATES,
692 NULL, // all modes (TODO: use modeMatch!)
693 &modes, // callback parameter
694 wxDDEnumModesCallback
695 );
696
697 if ( FAILED(hr) )
698 {
699 wxLogApiError(_T("IDirectDraw::EnumDisplayModes"), hr);
700 }
701 }
702
703 return modes;
704 }
705 #endif
706
707 wxArrayVideoModes
708 wxDisplay::DoGetModesWindows(const wxVideoMode& modeMatch) const
709 {
710 wxArrayVideoModes modes;
711
712 // The first parameter of EnumDisplaySettings() must be NULL under Win95
713 // according to MSDN. The version of GetName() we implement for Win95
714 // returns an empty string.
715 const wxString name = GetName();
716 const wxChar * const deviceName = name.empty() ? NULL : name.c_str();
717
718 DEVMODE dm;
719 dm.dmSize = sizeof(dm);
720 dm.dmDriverExtra = 0;
721 for ( int iModeNum = 0;
722 ::EnumDisplaySettings(deviceName, iModeNum, &dm);
723 iModeNum++ )
724 {
725 const wxVideoMode mode = ConvertToVideoMode(dm);
726 if ( mode.Matches(modeMatch) )
727 {
728 modes.Add(mode);
729 }
730 }
731
732 return modes;
733 }
734
735 wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& modeMatch) const
736 {
737 #ifdef HAVE_DDRAW_H
738 return gs_useDirectX ? DoGetModesDirectX(modeMatch)
739 : DoGetModesWindows(modeMatch);
740 #else
741 return DoGetModesWindows(modeMatch);
742 #endif
743 }
744
745 wxVideoMode wxDisplay::GetCurrentMode() const
746 {
747 wxVideoMode mode;
748
749 // The first parameter of EnumDisplaySettings() must be NULL under Win95
750 // according to MSDN. The version of GetName() we implement for Win95
751 // returns an empty string.
752 const wxString name = GetName();
753 const wxChar * const deviceName = name.empty() ? NULL : name.c_str();
754
755 DEVMODE dm;
756 dm.dmSize = sizeof(dm);
757 dm.dmDriverExtra = 0;
758 if ( !::EnumDisplaySettings(deviceName, ENUM_CURRENT_SETTINGS, &dm) )
759 {
760 wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
761 }
762 else
763 {
764 mode = ConvertToVideoMode(dm);
765 }
766
767 return mode;
768 }
769
770 // ----------------------------------------------------------------------------
771 // video mode switching
772 // ----------------------------------------------------------------------------
773
774 #ifdef HAVE_DDRAW_H
775 bool wxDisplay::DoChangeModeDirectX(const wxVideoMode& mode)
776 {
777 IDirectDraw2 *pDD = (*gs_displays)[m_index].m_pDD2;
778 if ( !pDD )
779 return false;
780
781 wxWindow *winTop = wxTheApp->GetTopWindow();
782 wxCHECK_MSG( winTop, false, _T("top level window required for DirectX") );
783
784 HRESULT hr = pDD->SetCooperativeLevel
785 (
786 GetHwndOf(winTop),
787 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN
788 );
789 if ( FAILED(hr) )
790 {
791 wxLogApiError(_T("IDirectDraw::SetCooperativeLevel"), hr);
792
793 return false;
794 }
795
796 hr = pDD->SetDisplayMode(mode.w, mode.h, mode.bpp, mode.refresh, 0);
797 if ( FAILED(hr) )
798 {
799 wxLogApiError(_T("IDirectDraw::SetDisplayMode"), hr);
800
801 return false;
802 }
803
804
805 return true;
806 }
807 #endif
808
809 bool wxDisplay::DoChangeModeWindows(const wxVideoMode& mode)
810 {
811 // prepare ChangeDisplaySettingsEx() parameters
812 DEVMODE dm,
813 *pDevMode;
814 int flags;
815
816 if ( mode == wxDefaultVideoMode )
817 {
818 // reset the video mode to default
819 pDevMode = NULL;
820 flags = 0;
821 }
822 else // change to the given mode
823 {
824 wxCHECK_MSG( mode.w && mode.h, false,
825 _T("at least the width and height must be specified") );
826
827 wxZeroMemory(dm);
828 dm.dmSize = sizeof(dm);
829 dm.dmDriverExtra = 0;
830 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
831 dm.dmPelsWidth = mode.w;
832 dm.dmPelsHeight = mode.h;
833
834 if ( mode.bpp )
835 {
836 dm.dmFields |= DM_BITSPERPEL;
837 dm.dmBitsPerPel = mode.bpp;
838 }
839
840 if ( mode.refresh )
841 {
842 dm.dmFields |= DM_DISPLAYFREQUENCY;
843 dm.dmDisplayFrequency = mode.refresh;
844 }
845
846 pDevMode = &dm;
847
848 #ifdef __WXWINCE__
849 flags = 0;
850 #else // !__WXWINCE__
851 flags = CDS_FULLSCREEN;
852 #endif // __WXWINCE__/!__WXWINCE__
853 }
854
855
856 // get pointer to the function dynamically
857 //
858 // we're only called from the main thread, so it's ok to use static
859 // variable
860 static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx = NULL;
861 if ( !pfnChangeDisplaySettingsEx )
862 {
863 wxDynamicLibrary dllUser32(_T("user32.dll"));
864 if ( dllUser32.IsLoaded() )
865 {
866 pfnChangeDisplaySettingsEx = (ChangeDisplaySettingsEx_t)
867 dllUser32.GetSymbol(WINFUNC(ChangeDisplaySettingsEx));
868 }
869 //else: huh, no user32.dll??
870
871 #ifndef __WXWINCE__
872 if ( !pfnChangeDisplaySettingsEx )
873 {
874 // we must be under Win95 and so there is no multiple monitors
875 // support anyhow
876 pfnChangeDisplaySettingsEx = ChangeDisplaySettingsExForWin95;
877 }
878 #endif // !__WXWINCE__
879 }
880
881 // do change the mode
882 switch ( pfnChangeDisplaySettingsEx
883 (
884 GetName(), // display name
885 pDevMode, // dev mode or NULL to reset
886 NULL, // reserved
887 flags,
888 NULL // pointer to video parameters (not used)
889 ) )
890 {
891 case DISP_CHANGE_SUCCESSFUL:
892 // ok
893 {
894 // If we have a top-level, full-screen frame, emulate
895 // the DirectX behavior and resize it. This makes this
896 // API quite a bit easier to use.
897 wxWindow *winTop = wxTheApp->GetTopWindow();
898 wxFrame *frameTop = wxDynamicCast(winTop, wxFrame);
899 if (frameTop && frameTop->IsFullScreen())
900 {
901 wxVideoMode current = GetCurrentMode();
902 frameTop->SetClientSize(current.w, current.h);
903 }
904 }
905 return true;
906
907 case DISP_CHANGE_BADMODE:
908 // don't complain about this, this is the only "expected" error
909 break;
910
911 default:
912 wxFAIL_MSG( _T("unexpected ChangeDisplaySettingsEx() return value") );
913 }
914
915 return false;
916 }
917
918 bool wxDisplay::ChangeMode(const wxVideoMode& mode)
919 {
920 #ifdef HAVE_DDRAW_H
921 return gs_useDirectX ? DoChangeModeDirectX(mode)
922 : DoChangeModeWindows(mode);
923 #else
924 return DoChangeModeWindows(mode);
925 #endif
926 }
927
928 #endif // wxUSE_DISPLAY
929