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