wxDisplay build fix for missing Direct Draw.
[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, Vadim Zeitlin
5 // Modified by: Ryan Norton (IsPrimary override)
6 // Created: 06/21/02
7 // RCS-ID: $Id$
8 // Copyright: (c) wxWidgets team
9 // Copyright: (c) 2002-2006 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 #include "wx/sysopt.h"
38
39 #include "wx/display.h"
40 #include "wx/display_impl.h"
41
42 // Mingw's w32api headers don't include ddraw.h, though the user may have
43 // installed it. If using configure, we actually probe for ddraw.h there
44 // and set wxUSE_DIRECTDRAW. Otherwise, assume we don't have it if using
45 // the w32api headers, and that we do otherwise.
46 #if !defined HAVE_W32API_H && !defined HAVE_DDRAW_H
47 #define HAVE_DDRAW_H
48 #endif
49
50 // user may disable compilation of DirectDraw code by setting
51 // wxUSE_DIRECTDRAW to 0 in the makefile/project settings
52 #if defined(HAVE_DDRAW_H) && !defined(wxUSE_DIRECTDRAW)
53 #define wxUSE_DIRECTDRAW 1
54 #endif
55
56 #ifndef __WXWINCE__
57 // Older versions of windef.h don't define HMONITOR. Unfortunately, we
58 // can't directly test whether HMONITOR is defined or not in windef.h as
59 // it's not a macro but a typedef, so we test for an unrelated symbol which
60 // is only defined in winuser.h if WINVER >= 0x0500
61 #if !defined(HMONITOR_DECLARED) && !defined(MNS_NOCHECK)
62 DECLARE_HANDLE(HMONITOR);
63 #define HMONITOR_DECLARED
64 #endif
65 #endif // !__WXWINCE__
66
67 #ifdef wxUSE_DIRECTDRAW
68 #include <ddraw.h>
69
70 // we don't want to link with ddraw.lib which contains the real
71 // IID_IDirectDraw2 definition
72 const GUID wxIID_IDirectDraw2 =
73 { 0xB3A6F3E0, 0x2B43, 0x11CF, { 0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 } };
74 #endif // wxUSE_DIRECTDRAW
75
76 // ----------------------------------------------------------------------------
77 // typedefs for dynamically loaded Windows functions
78 // ----------------------------------------------------------------------------
79
80 typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName,
81 LPDEVMODE lpDevMode,
82 HWND hwnd,
83 DWORD dwFlags,
84 LPVOID lParam);
85
86 #ifdef wxUSE_DIRECTDRAW
87 typedef BOOL (PASCAL *DDEnumExCallback_t)(GUID *pGuid,
88 LPTSTR driverDescription,
89 LPTSTR driverName,
90 LPVOID lpContext,
91 HMONITOR hmon);
92
93 typedef HRESULT (WINAPI *DirectDrawEnumerateEx_t)(DDEnumExCallback_t lpCallback,
94 LPVOID lpContext,
95 DWORD dwFlags);
96
97 typedef HRESULT (WINAPI *DirectDrawCreate_t)(GUID *lpGUID,
98 LPDIRECTDRAW *lplpDD,
99 IUnknown *pUnkOuter);
100 #endif // wxUSE_DIRECTDRAW
101
102 typedef BOOL (WINAPI *EnumDisplayMonitors_t)(HDC,LPCRECT,MONITORENUMPROC,LPARAM);
103 typedef HMONITOR (WINAPI *MonitorFromPoint_t)(POINT,DWORD);
104 typedef HMONITOR (WINAPI *MonitorFromWindow_t)(HWND,DWORD);
105 typedef BOOL (WINAPI *GetMonitorInfo_t)(HMONITOR,LPMONITORINFO);
106
107 #ifndef __WXWINCE__
108 // emulation of ChangeDisplaySettingsEx() for Win95
109 LONG WINAPI ChangeDisplaySettingsExForWin95(LPCTSTR WXUNUSED(lpszDeviceName),
110 LPDEVMODE lpDevMode,
111 HWND WXUNUSED(hwnd),
112 DWORD dwFlags,
113 LPVOID WXUNUSED(lParam))
114 {
115 return ::ChangeDisplaySettings(lpDevMode, dwFlags);
116 }
117 #endif // !__WXWINCE__
118
119 // ----------------------------------------------------------------------------
120 // display information classes
121 // ----------------------------------------------------------------------------
122
123 struct wxDisplayInfo
124 {
125 wxDisplayInfo(HMONITOR hmon = NULL)
126 {
127 m_hmon = hmon;
128 m_flags = (DWORD)-1;
129 }
130
131 virtual ~wxDisplayInfo() { }
132
133
134 // use GetMonitorInfo() to fill in all of our fields if needed (i.e. if it
135 // hadn't been done before)
136 void Initialize();
137
138
139 // handle of this monitor used by MonitorXXX() functions, never NULL
140 HMONITOR m_hmon;
141
142 // the entire area of this monitor in virtual screen coordinates
143 wxRect m_rect;
144
145 // the display device name for this monitor, empty initially and retrieved
146 // on demand by DoGetName()
147 wxString m_devName;
148
149 // the flags of this monitor, also used as initialization marker: if this
150 // is -1, GetMonitorInfo() hadn't been called yet
151 DWORD m_flags;
152 };
153
154 WX_DEFINE_ARRAY_PTR(wxDisplayInfo *, wxDisplayInfoArray);
155
156 // ----------------------------------------------------------------------------
157 // common base class for all Win32 wxDisplayImpl versions
158 // ----------------------------------------------------------------------------
159
160 class wxDisplayImplWin32Base : public wxDisplayImpl
161 {
162 public:
163 wxDisplayImplWin32Base(size_t n, wxDisplayInfo& info)
164 : wxDisplayImpl(n),
165 m_info(info)
166 {
167 }
168
169 virtual wxRect GetGeometry() const;
170 virtual wxString GetName() const;
171 virtual bool IsPrimary() const;
172
173 virtual wxVideoMode GetCurrentMode() const;
174
175 protected:
176 // convert a DEVMODE to our wxVideoMode
177 static wxVideoMode ConvertToVideoMode(const DEVMODE& dm)
178 {
179 // note that dmDisplayFrequency may be 0 or 1 meaning "standard one"
180 // and although 0 is ok for us we don't want to return modes with 1hz
181 // refresh
182 return wxVideoMode(dm.dmPelsWidth,
183 dm.dmPelsHeight,
184 dm.dmBitsPerPel,
185 dm.dmDisplayFrequency > 1 ? dm.dmDisplayFrequency : 0);
186 }
187
188 wxDisplayInfo& m_info;
189 };
190
191 // ----------------------------------------------------------------------------
192 // common base class for all Win32 wxDisplayFactory versions
193 // ----------------------------------------------------------------------------
194
195 // functions dynamically bound by wxDisplayFactoryWin32Base::Initialize()
196 static MonitorFromPoint_t gs_MonitorFromPoint = NULL;
197 static MonitorFromWindow_t gs_MonitorFromWindow = NULL;
198 static GetMonitorInfo_t gs_GetMonitorInfo = NULL;
199
200 class wxDisplayFactoryWin32Base : public wxDisplayFactory
201 {
202 public:
203 virtual ~wxDisplayFactoryWin32Base();
204
205 bool IsOk() const { return !m_displays.empty(); }
206
207 virtual size_t GetCount() { return m_displays.size(); }
208 virtual int GetFromPoint(const wxPoint& pt);
209 virtual int GetFromWindow(wxWindow *window);
210
211 protected:
212 // ctor checks if the current system supports multimon API and dynamically
213 // bind the functions we need if this is the case and sets
214 // ms_supportsMultimon if they're available
215 wxDisplayFactoryWin32Base();
216
217 // delete all m_displays elements: can be called from the derived class
218 // dtor if it is important to do this before destroying it (as in
219 // wxDisplayFactoryDirectDraw case), otherwise will be done by our dtor
220 void Clear();
221
222 // find the monitor corresponding to the given handle, return wxNOT_FOUND
223 // if not found
224 int FindDisplayFromHMONITOR(HMONITOR hmon) const;
225
226
227 // flag indicating whether gs_MonitorXXX functions are available
228 static int ms_supportsMultimon;
229
230 // the array containing information about all available displays, should be
231 // filled by the derived class ctors
232 wxDisplayInfoArray m_displays;
233
234
235 DECLARE_NO_COPY_CLASS(wxDisplayFactoryWin32Base)
236 };
237
238 // ----------------------------------------------------------------------------
239 // wxDisplay implementation using Windows multi-monitor support functions
240 // ----------------------------------------------------------------------------
241
242 class wxDisplayImplMultimon : public wxDisplayImplWin32Base
243 {
244 public:
245 wxDisplayImplMultimon(size_t n, wxDisplayInfo& info)
246 : wxDisplayImplWin32Base(n, info)
247 {
248 }
249
250 virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
251 virtual bool ChangeMode(const wxVideoMode& mode);
252
253 private:
254 DECLARE_NO_COPY_CLASS(wxDisplayImplMultimon)
255 };
256
257 class WXDLLEXPORT wxDisplayFactoryMultimon : public wxDisplayFactoryWin32Base
258 {
259 public:
260 wxDisplayFactoryMultimon();
261
262 virtual wxDisplayImpl *CreateDisplay(size_t n);
263
264 private:
265 // EnumDisplayMonitors() callback
266 static BOOL CALLBACK MultimonEnumProc(HMONITOR hMonitor,
267 HDC hdcMonitor,
268 LPRECT lprcMonitor,
269 LPARAM dwData);
270
271
272 // add a monitor description to m_displays array
273 void AddDisplay(HMONITOR hMonitor, LPRECT lprcMonitor);
274 };
275
276 // ----------------------------------------------------------------------------
277 // wxDisplay implementation using DirectDraw
278 // ----------------------------------------------------------------------------
279
280 #ifdef wxUSE_DIRECTDRAW
281
282 struct wxDisplayInfoDirectDraw : wxDisplayInfo
283 {
284 wxDisplayInfoDirectDraw(const GUID& guid, HMONITOR hmon, LPTSTR name)
285 : wxDisplayInfo(hmon),
286 m_guid(guid)
287 {
288 m_pDD2 = NULL;
289 m_devName = name;
290 }
291
292 virtual ~wxDisplayInfoDirectDraw()
293 {
294 if ( m_pDD2 )
295 m_pDD2->Release();
296 }
297
298
299 // IDirectDraw object used to control this display, may be NULL
300 IDirectDraw2 *m_pDD2;
301
302 // DirectDraw GUID for this display, only valid when using DirectDraw
303 const GUID m_guid;
304
305
306 DECLARE_NO_COPY_CLASS(wxDisplayInfoDirectDraw)
307 };
308
309 class wxDisplayImplDirectDraw : public wxDisplayImplWin32Base
310 {
311 public:
312 wxDisplayImplDirectDraw(size_t n, wxDisplayInfo& info, IDirectDraw2 *pDD2)
313 : wxDisplayImplWin32Base(n, info),
314 m_pDD2(pDD2)
315 {
316 m_pDD2->AddRef();
317 }
318
319 virtual ~wxDisplayImplDirectDraw()
320 {
321 m_pDD2->Release();
322 }
323
324 virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
325 virtual bool ChangeMode(const wxVideoMode& mode);
326
327 private:
328 IDirectDraw2 *m_pDD2;
329
330 DECLARE_NO_COPY_CLASS(wxDisplayImplDirectDraw)
331 };
332
333 class WXDLLEXPORT wxDisplayFactoryDirectDraw : public wxDisplayFactoryWin32Base
334 {
335 public:
336 wxDisplayFactoryDirectDraw();
337 virtual ~wxDisplayFactoryDirectDraw();
338
339 virtual wxDisplayImpl *CreateDisplay(size_t n);
340
341 private:
342 // callback used with DirectDrawEnumerateEx()
343 static BOOL WINAPI DDEnumExCallback(GUID *pGuid,
344 LPTSTR driverDescription,
345 LPTSTR driverName,
346 LPVOID lpContext,
347 HMONITOR hmon);
348
349 // add a monitor description to m_displays array
350 void AddDisplay(const GUID& guid, HMONITOR hmon, LPTSTR name);
351
352
353 // ddraw.dll
354 wxDynamicLibrary m_dllDDraw;
355
356 // dynamically resolved DirectDrawCreate()
357 DirectDrawCreate_t m_pfnDirectDrawCreate;
358
359 DECLARE_NO_COPY_CLASS(wxDisplayFactoryDirectDraw)
360 };
361
362 #endif // wxUSE_DIRECTDRAW
363
364
365 // ============================================================================
366 // common classes implementation
367 // ============================================================================
368
369 // ----------------------------------------------------------------------------
370 // wxDisplay
371 // ----------------------------------------------------------------------------
372
373 /* static */ wxDisplayFactory *wxDisplay::CreateFactory()
374 {
375 // we have 2 implementations for modern Windows: one using standard Win32
376 // and another using DirectDraw, the choice between them is done using a
377 // system option
378
379 #ifdef wxUSE_DIRECTDRAW
380 if ( wxSystemOptions::GetOptionInt(_T("msw.display.directdraw")) )
381 {
382 wxDisplayFactoryDirectDraw *factoryDD = new wxDisplayFactoryDirectDraw;
383 if ( factoryDD->IsOk() )
384 return factoryDD;
385
386 delete factoryDD;
387 }
388 #endif // wxUSE_DIRECTDRAW
389
390 wxDisplayFactoryMultimon *factoryMM = new wxDisplayFactoryMultimon;
391 if ( factoryMM->IsOk() )
392 return factoryMM;
393
394 delete factoryMM;
395
396
397 // finally fall back to a stub implementation if all else failed (Win95?)
398 return new wxDisplayFactorySingle;
399 }
400
401 // ----------------------------------------------------------------------------
402 // wxDisplayInfo
403 // ----------------------------------------------------------------------------
404
405 void wxDisplayInfo::Initialize()
406 {
407 if ( m_flags == (DWORD)-1 )
408 {
409 WinStruct<MONITORINFOEX> monInfo;
410 if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) )
411 {
412 wxLogLastError(_T("GetMonitorInfo"));
413 m_flags = 0;
414 return;
415 }
416
417 wxCopyRECTToRect(monInfo.rcMonitor, m_rect);
418 m_devName = monInfo.szDevice;
419 m_flags = monInfo.dwFlags;
420 }
421 }
422
423 // ----------------------------------------------------------------------------
424 // wxDisplayImplWin32Base
425 // ----------------------------------------------------------------------------
426
427 wxRect wxDisplayImplWin32Base::GetGeometry() const
428 {
429 if ( m_info.m_rect.IsEmpty() )
430 m_info.Initialize();
431
432 return m_info.m_rect;
433 }
434
435 wxString wxDisplayImplWin32Base::GetName() const
436 {
437 if ( m_info.m_devName.IsEmpty() )
438 m_info.Initialize();
439
440 return m_info.m_devName;
441 }
442
443 bool wxDisplayImplWin32Base::IsPrimary() const
444 {
445 if ( m_info.m_flags == (DWORD)-1 )
446 m_info.Initialize();
447
448 return (m_info.m_flags & MONITORINFOF_PRIMARY) != 0;
449 }
450
451 wxVideoMode wxDisplayImplWin32Base::GetCurrentMode() const
452 {
453 wxVideoMode mode;
454
455 // The first parameter of EnumDisplaySettings() must be NULL under Win95
456 // according to MSDN. The version of GetName() we implement for Win95
457 // returns an empty string.
458 const wxString name = GetName();
459 const wxChar * const deviceName = name.empty() ? NULL : name.c_str();
460
461 DEVMODE dm;
462 dm.dmSize = sizeof(dm);
463 dm.dmDriverExtra = 0;
464 if ( !::EnumDisplaySettings(deviceName, ENUM_CURRENT_SETTINGS, &dm) )
465 {
466 wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
467 }
468 else
469 {
470 mode = ConvertToVideoMode(dm);
471 }
472
473 return mode;
474 }
475
476 // ----------------------------------------------------------------------------
477 // wxDisplayFactoryWin32Base
478 // ----------------------------------------------------------------------------
479
480 int wxDisplayFactoryWin32Base::ms_supportsMultimon = -1;
481
482 wxDisplayFactoryWin32Base::wxDisplayFactoryWin32Base()
483 {
484 if ( ms_supportsMultimon == -1 )
485 {
486 ms_supportsMultimon = 0;
487
488 wxDynamicLibrary dllUser32(_T("user32.dll"));
489
490 wxLogNull noLog;
491
492 gs_MonitorFromPoint = (MonitorFromPoint_t)
493 dllUser32.GetSymbol(wxT("MonitorFromPoint"));
494 if ( !gs_MonitorFromPoint )
495 return;
496
497 gs_MonitorFromWindow = (MonitorFromWindow_t)
498 dllUser32.GetSymbol(wxT("MonitorFromWindow"));
499 if ( !gs_MonitorFromWindow )
500 return;
501
502 gs_GetMonitorInfo = (GetMonitorInfo_t)
503 dllUser32.GetSymbolAorW(wxT("GetMonitorInfo"));
504 if ( !gs_GetMonitorInfo )
505 return;
506
507 ms_supportsMultimon = 1;
508
509 // we can safely let dllUser32 go out of scope, the DLL itself will
510 // still remain loaded as all Win32 programs use it
511 }
512 }
513
514 void wxDisplayFactoryWin32Base::Clear()
515 {
516 WX_CLEAR_ARRAY(m_displays);
517 }
518
519 wxDisplayFactoryWin32Base::~wxDisplayFactoryWin32Base()
520 {
521 Clear();
522 }
523
524 // helper for GetFromPoint() and GetFromWindow()
525 int wxDisplayFactoryWin32Base::FindDisplayFromHMONITOR(HMONITOR hmon) const
526 {
527 if ( hmon )
528 {
529 const size_t count = m_displays.size();
530 for ( size_t n = 0; n < count; n++ )
531 {
532 if ( hmon == m_displays[n]->m_hmon )
533 return n;
534 }
535 }
536
537 return wxNOT_FOUND;
538 }
539
540 int wxDisplayFactoryWin32Base::GetFromPoint(const wxPoint& pt)
541 {
542 POINT pt2;
543 pt2.x = pt.x;
544 pt2.y = pt.y;
545
546 return FindDisplayFromHMONITOR(gs_MonitorFromPoint(pt2,
547 MONITOR_DEFAULTTONULL));
548 }
549
550 int wxDisplayFactoryWin32Base::GetFromWindow(wxWindow *window)
551 {
552 return FindDisplayFromHMONITOR(gs_MonitorFromWindow(GetHwndOf(window),
553 MONITOR_DEFAULTTONULL));
554 }
555
556 // ============================================================================
557 // wxDisplay implementation using Win32 multimon API
558 // ============================================================================
559
560 // ----------------------------------------------------------------------------
561 // wxDisplayFactoryMultimon initialization
562 // ----------------------------------------------------------------------------
563
564 wxDisplayFactoryMultimon::wxDisplayFactoryMultimon()
565 {
566 if ( !ms_supportsMultimon )
567 return;
568
569 // look up EnumDisplayMonitors() which we don't need with DirectDraw
570 // implementation
571 EnumDisplayMonitors_t pfnEnumDisplayMonitors;
572 {
573 wxLogNull noLog;
574
575 wxDynamicLibrary dllUser32(_T("user32.dll"));
576 pfnEnumDisplayMonitors = (EnumDisplayMonitors_t)
577 dllUser32.GetSymbol(wxT("EnumDisplayMonitors"));
578 if ( !pfnEnumDisplayMonitors )
579 return;
580 }
581
582 // enumerate all displays
583 if ( !pfnEnumDisplayMonitors(NULL, NULL, MultimonEnumProc, (LPARAM)this) )
584 {
585 wxLogLastError(wxT("EnumDisplayMonitors"));
586 }
587 }
588
589 /* static */
590 BOOL CALLBACK
591 wxDisplayFactoryMultimon::MultimonEnumProc(
592 HMONITOR hMonitor, // handle to display monitor
593 HDC WXUNUSED(hdcMonitor), // handle to monitor-appropriate device context
594 LPRECT lprcMonitor, // pointer to monitor intersection rectangle
595 LPARAM dwData // data passed from EnumDisplayMonitors (this)
596 )
597 {
598 wxDisplayFactoryMultimon *const self = (wxDisplayFactoryMultimon *)dwData;
599 self->AddDisplay(hMonitor, lprcMonitor);
600
601 // continue the enumeration
602 return TRUE;
603 }
604
605 // ----------------------------------------------------------------------------
606 // wxDisplayFactoryMultimon helper functions
607 // ----------------------------------------------------------------------------
608
609 void wxDisplayFactoryMultimon::AddDisplay(HMONITOR hMonitor, LPRECT lprcMonitor)
610 {
611 wxDisplayInfo *info = new wxDisplayInfo(hMonitor);
612
613 // we also store the display geometry
614 info->m_rect = wxRect(lprcMonitor->left, lprcMonitor->top,
615 lprcMonitor->right - lprcMonitor->left,
616 lprcMonitor->bottom - lprcMonitor->top);
617
618 // now add this monitor to the array
619 m_displays.Add(info);
620 }
621
622 // ----------------------------------------------------------------------------
623 // wxDisplayFactoryMultimon inherited pure virtuals implementation
624 // ----------------------------------------------------------------------------
625
626 wxDisplayImpl *wxDisplayFactoryMultimon::CreateDisplay(size_t n)
627 {
628 wxCHECK_MSG( n < m_displays.size(), NULL, _T("invalid display index") );
629
630 return new wxDisplayImplMultimon(n, *(m_displays[n]));
631 }
632
633 // ----------------------------------------------------------------------------
634 // wxDisplayImplMultimon implementation
635 // ----------------------------------------------------------------------------
636
637 wxArrayVideoModes
638 wxDisplayImplMultimon::GetModes(const wxVideoMode& modeMatch) const
639 {
640 wxArrayVideoModes modes;
641
642 // The first parameter of EnumDisplaySettings() must be NULL under Win95
643 // according to MSDN. The version of GetName() we implement for Win95
644 // returns an empty string.
645 const wxString name = GetName();
646 const wxChar * const deviceName = name.empty() ? NULL : name.c_str();
647
648 DEVMODE dm;
649 dm.dmSize = sizeof(dm);
650 dm.dmDriverExtra = 0;
651 for ( int iModeNum = 0;
652 ::EnumDisplaySettings(deviceName, iModeNum, &dm);
653 iModeNum++ )
654 {
655 const wxVideoMode mode = ConvertToVideoMode(dm);
656 if ( mode.Matches(modeMatch) )
657 {
658 modes.Add(mode);
659 }
660 }
661
662 return modes;
663 }
664
665 bool wxDisplayImplMultimon::ChangeMode(const wxVideoMode& mode)
666 {
667 // prepare ChangeDisplaySettingsEx() parameters
668 DEVMODE dm;
669 DEVMODE *pDevMode;
670
671 int flags;
672
673 if ( mode == wxDefaultVideoMode )
674 {
675 // reset the video mode to default
676 pDevMode = NULL;
677 flags = 0;
678 }
679 else // change to the given mode
680 {
681 wxCHECK_MSG( mode.w && mode.h, false,
682 _T("at least the width and height must be specified") );
683
684 wxZeroMemory(dm);
685 dm.dmSize = sizeof(dm);
686 dm.dmDriverExtra = 0;
687 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
688 dm.dmPelsWidth = mode.w;
689 dm.dmPelsHeight = mode.h;
690
691 if ( mode.bpp )
692 {
693 dm.dmFields |= DM_BITSPERPEL;
694 dm.dmBitsPerPel = mode.bpp;
695 }
696
697 if ( mode.refresh )
698 {
699 dm.dmFields |= DM_DISPLAYFREQUENCY;
700 dm.dmDisplayFrequency = mode.refresh;
701 }
702
703 pDevMode = &dm;
704
705 #ifdef __WXWINCE__
706 flags = 0;
707 #else // !__WXWINCE__
708 flags = CDS_FULLSCREEN;
709 #endif // __WXWINCE__/!__WXWINCE__
710 }
711
712
713 // get pointer to the function dynamically
714 //
715 // we're only called from the main thread, so it's ok to use static
716 // variable
717 static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx = NULL;
718 if ( !pfnChangeDisplaySettingsEx )
719 {
720 wxDynamicLibrary dllUser32(_T("user32.dll"));
721 if ( dllUser32.IsLoaded() )
722 {
723 pfnChangeDisplaySettingsEx = (ChangeDisplaySettingsEx_t)
724 dllUser32.GetSymbolAorW(_T("ChangeDisplaySettingsEx"));
725 }
726 //else: huh, no user32.dll??
727
728 #ifndef __WXWINCE__
729 if ( !pfnChangeDisplaySettingsEx )
730 {
731 // we must be under Win95 and so there is no multiple monitors
732 // support anyhow
733 pfnChangeDisplaySettingsEx = ChangeDisplaySettingsExForWin95;
734 }
735 #endif // !__WXWINCE__
736 }
737
738 // do change the mode
739 switch ( pfnChangeDisplaySettingsEx
740 (
741 GetName(), // display name
742 pDevMode, // dev mode or NULL to reset
743 NULL, // reserved
744 flags,
745 NULL // pointer to video parameters (not used)
746 ) )
747 {
748 case DISP_CHANGE_SUCCESSFUL:
749 // ok
750 {
751 // If we have a top-level, full-screen frame, emulate
752 // the DirectX behavior and resize it. This makes this
753 // API quite a bit easier to use.
754 wxWindow *winTop = wxTheApp->GetTopWindow();
755 wxFrame *frameTop = wxDynamicCast(winTop, wxFrame);
756 if (frameTop && frameTop->IsFullScreen())
757 {
758 wxVideoMode current = GetCurrentMode();
759 frameTop->SetClientSize(current.w, current.h);
760 }
761 }
762 return true;
763
764 case DISP_CHANGE_BADMODE:
765 // don't complain about this, this is the only "expected" error
766 break;
767
768 default:
769 wxFAIL_MSG( _T("unexpected ChangeDisplaySettingsEx() return value") );
770 }
771
772 return false;
773 }
774
775
776 // ============================================================================
777 // DirectDraw-based wxDisplay implementation
778 // ============================================================================
779
780 #if wxUSE_DIRECTDRAW
781
782 // ----------------------------------------------------------------------------
783 // wxDisplayFactoryDirectDraw initialization
784 // ----------------------------------------------------------------------------
785
786 wxDisplayFactoryDirectDraw::wxDisplayFactoryDirectDraw()
787 {
788 if ( !ms_supportsMultimon )
789 return;
790
791 #if wxUSE_LOG
792 // suppress the errors if ddraw.dll is not found, we're prepared to handle
793 // this
794 wxLogNull noLog;
795 #endif
796
797 m_dllDDraw.Load(_T("ddraw.dll"));
798
799 if ( !m_dllDDraw.IsLoaded() )
800 return;
801
802 DirectDrawEnumerateEx_t pDDEnumEx = (DirectDrawEnumerateEx_t)
803 m_dllDDraw.GetSymbolAorW(_T("DirectDrawEnumerateEx"));
804 if ( !pDDEnumEx )
805 return;
806
807 // we can't continue without DirectDrawCreate() later, so resolve it right
808 // now and fail the initialization if it's not available
809 m_pfnDirectDrawCreate = (DirectDrawCreate_t)
810 m_dllDDraw.GetSymbol(_T("DirectDrawCreate"));
811 if ( !m_pfnDirectDrawCreate )
812 return;
813
814 if ( (*pDDEnumEx)(DDEnumExCallback,
815 this,
816 DDENUM_ATTACHEDSECONDARYDEVICES) != DD_OK )
817 {
818 wxLogLastError(_T("DirectDrawEnumerateEx"));
819 }
820 }
821
822 wxDisplayFactoryDirectDraw::~wxDisplayFactoryDirectDraw()
823 {
824 // we must clear m_displays now, before m_dllDDraw is unloaded as otherwise
825 // calling m_pDD2->Release() later would crash
826 Clear();
827 }
828
829 // ----------------------------------------------------------------------------
830 // callbacks for monitor/modes enumeration stuff
831 // ----------------------------------------------------------------------------
832
833 BOOL WINAPI
834 wxDisplayFactoryDirectDraw::DDEnumExCallback(GUID *pGuid,
835 LPTSTR WXUNUSED(driverDescription),
836 LPTSTR driverName,
837 LPVOID lpContext,
838 HMONITOR hmon)
839 {
840 if ( pGuid )
841 {
842 wxDisplayFactoryDirectDraw * self =
843 wx_static_cast(wxDisplayFactoryDirectDraw *, lpContext);
844 self->AddDisplay(*pGuid, hmon, driverName);
845 }
846 //else: we're called for the primary monitor, skip it
847
848 // continue the enumeration
849 return TRUE;
850 }
851
852 // ----------------------------------------------------------------------------
853 // wxDisplayFactoryDirectDraw helpers
854 // ----------------------------------------------------------------------------
855
856 void wxDisplayFactoryDirectDraw::AddDisplay(const GUID& guid,
857 HMONITOR hmon,
858 LPTSTR name)
859 {
860 m_displays.Add(new wxDisplayInfoDirectDraw(guid, hmon, name));
861 }
862
863 // ----------------------------------------------------------------------------
864 // wxDisplayFactoryDirectDraw inherited pure virtuals implementation
865 // ----------------------------------------------------------------------------
866
867 wxDisplayImpl *wxDisplayFactoryDirectDraw::CreateDisplay(size_t n)
868 {
869 wxCHECK_MSG( n < m_displays.size(), NULL, _T("invalid display index") );
870
871 wxDisplayInfoDirectDraw *
872 info = wx_static_cast(wxDisplayInfoDirectDraw *, m_displays[n]);
873
874 if ( !info->m_pDD2 )
875 {
876 IDirectDraw *pDD;
877 GUID guid(info->m_guid);
878 HRESULT hr = (*m_pfnDirectDrawCreate)(&guid, &pDD, NULL);
879
880 if ( FAILED(hr) || !pDD )
881 {
882 // what to do??
883 wxLogApiError(_T("DirectDrawCreate"), hr);
884 return NULL;
885 }
886
887 // we got IDirectDraw, but we need IDirectDraw2
888 hr = pDD->QueryInterface(wxIID_IDirectDraw2, (void **)&info->m_pDD2);
889 pDD->Release();
890
891 if ( FAILED(hr) || !info->m_pDD2 )
892 {
893 wxLogApiError(_T("IDirectDraw::QueryInterface(IDD2)"), hr);
894 return NULL;
895 }
896
897 // NB: m_pDD2 will now be only destroyed when m_displays is destroyed
898 // which is ok as we don't want to recreate DD objects all the time
899 }
900 //else: DirectDraw object corresponding to our display already exists
901
902 return new wxDisplayImplDirectDraw(n, *info, info->m_pDD2);
903 }
904
905 // ============================================================================
906 // wxDisplayImplDirectDraw
907 // ============================================================================
908
909 // ----------------------------------------------------------------------------
910 // video modes enumeration
911 // ----------------------------------------------------------------------------
912
913 // tiny helper class used to pass information from GetModes() to
914 // wxDDEnumModesCallback
915 class wxDDVideoModesAdder
916 {
917 public:
918 // our Add() method will add modes matching modeMatch to modes array
919 wxDDVideoModesAdder(wxArrayVideoModes& modes, const wxVideoMode& modeMatch)
920 : m_modes(modes),
921 m_modeMatch(modeMatch)
922 {
923 }
924
925 void Add(const wxVideoMode& mode)
926 {
927 if ( mode.Matches(m_modeMatch) )
928 m_modes.Add(mode);
929 }
930
931 private:
932 wxArrayVideoModes& m_modes;
933 const wxVideoMode& m_modeMatch;
934
935 DECLARE_NO_COPY_CLASS(wxDDVideoModesAdder)
936 };
937
938 HRESULT WINAPI wxDDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc,
939 LPVOID lpContext)
940 {
941 // we need at least the mode size
942 static const DWORD FLAGS_REQUIRED = DDSD_HEIGHT | DDSD_WIDTH;
943 if ( (lpDDSurfaceDesc->dwFlags & FLAGS_REQUIRED) == FLAGS_REQUIRED )
944 {
945 wxDDVideoModesAdder * const vmodes =
946 wx_static_cast(wxDDVideoModesAdder *, lpContext);
947
948 vmodes->Add(wxVideoMode(lpDDSurfaceDesc->dwWidth,
949 lpDDSurfaceDesc->dwHeight,
950 lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
951 lpDDSurfaceDesc->dwRefreshRate));
952 }
953
954 // continue the enumeration
955 return DDENUMRET_OK;
956 }
957
958 wxArrayVideoModes
959 wxDisplayImplDirectDraw::GetModes(const wxVideoMode& modeMatch) const
960 {
961 wxArrayVideoModes modes;
962 wxDDVideoModesAdder modesAdder(modes, modeMatch);
963
964 HRESULT hr = m_pDD2->EnumDisplayModes
965 (
966 DDEDM_REFRESHRATES,
967 NULL, // all modes
968 &modesAdder, // callback parameter
969 wxDDEnumModesCallback
970 );
971
972 if ( FAILED(hr) )
973 {
974 wxLogApiError(_T("IDirectDraw::EnumDisplayModes"), hr);
975 }
976
977 return modes;
978 }
979
980 // ----------------------------------------------------------------------------
981 // video mode switching
982 // ----------------------------------------------------------------------------
983
984 bool wxDisplayImplDirectDraw::ChangeMode(const wxVideoMode& mode)
985 {
986 wxWindow *winTop = wxTheApp->GetTopWindow();
987 wxCHECK_MSG( winTop, false, _T("top level window required for DirectX") );
988
989 HRESULT hr = m_pDD2->SetCooperativeLevel
990 (
991 GetHwndOf(winTop),
992 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN
993 );
994 if ( FAILED(hr) )
995 {
996 wxLogApiError(_T("IDirectDraw2::SetCooperativeLevel"), hr);
997
998 return false;
999 }
1000
1001 hr = m_pDD2->SetDisplayMode(mode.w, mode.h, mode.bpp, mode.refresh, 0);
1002 if ( FAILED(hr) )
1003 {
1004 wxLogApiError(_T("IDirectDraw2::SetDisplayMode"), hr);
1005
1006 return false;
1007 }
1008
1009 return true;
1010 }
1011
1012 #endif // wxUSE_DIRECTDRAW
1013
1014 #endif // wxUSE_DISPLAY