]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/display.cpp
Add wxDataViewCtrl::GTKPathToItem() function and use it.
[wxWidgets.git] / src / msw / display.cpp
... / ...
CommitLineData
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__
92static const wxChar displayDllName[] = wxT("coredll.dll");
93#else
94static const wxChar displayDllName[] = wxT("user32.dll");
95#endif
96
97// ----------------------------------------------------------------------------
98// typedefs for dynamically loaded Windows functions
99// ----------------------------------------------------------------------------
100
101typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName,
102 LPDEVMODE lpDevMode,
103 HWND hwnd,
104 DWORD dwFlags,
105 LPVOID lParam);
106
107#if wxUSE_DIRECTDRAW
108typedef BOOL (PASCAL *DDEnumExCallback_t)(GUID *pGuid,
109 LPTSTR driverDescription,
110 LPTSTR driverName,
111 LPVOID lpContext,
112 HMONITOR hmon);
113
114typedef HRESULT (WINAPI *DirectDrawEnumerateEx_t)(DDEnumExCallback_t lpCallback,
115 LPVOID lpContext,
116 DWORD dwFlags);
117
118typedef HRESULT (WINAPI *DirectDrawCreate_t)(GUID *lpGUID,
119 LPDIRECTDRAW *lplpDD,
120 IUnknown *pUnkOuter);
121#endif // wxUSE_DIRECTDRAW
122
123typedef BOOL (WINAPI *EnumDisplayMonitors_t)(HDC,LPCRECT,MONITORENUMPROC,LPARAM);
124typedef HMONITOR (WINAPI *MonitorFromPoint_t)(POINT,DWORD);
125typedef HMONITOR (WINAPI *MonitorFromWindow_t)(HWND,DWORD);
126typedef BOOL (WINAPI *GetMonitorInfo_t)(HMONITOR,LPMONITORINFO);
127
128#ifndef __WXWINCE__
129// emulation of ChangeDisplaySettingsEx() for Win95
130LONG 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
144struct 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
178WX_DEFINE_ARRAY_PTR(wxDisplayInfo *, wxDisplayInfoArray);
179
180// ----------------------------------------------------------------------------
181// common base class for all Win32 wxDisplayImpl versions
182// ----------------------------------------------------------------------------
183
184class wxDisplayImplWin32Base : public wxDisplayImpl
185{
186public:
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
200protected:
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()
221static MonitorFromPoint_t gs_MonitorFromPoint = NULL;
222static MonitorFromWindow_t gs_MonitorFromWindow = NULL;
223static GetMonitorInfo_t gs_GetMonitorInfo = NULL;
224
225class wxDisplayFactoryWin32Base : public wxDisplayFactory
226{
227public:
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
236protected:
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
267class wxDisplayImplMultimon : public wxDisplayImplWin32Base
268{
269public:
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
278private:
279 wxDECLARE_NO_COPY_CLASS(wxDisplayImplMultimon);
280};
281
282class wxDisplayFactoryMultimon : public wxDisplayFactoryWin32Base
283{
284public:
285 wxDisplayFactoryMultimon();
286
287 virtual wxDisplayImpl *CreateDisplay(unsigned n);
288
289private:
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
307struct 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
334class wxDisplayImplDirectDraw : public wxDisplayImplWin32Base
335{
336public:
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
352private:
353 IDirectDraw2 *m_pDD2;
354
355 wxDECLARE_NO_COPY_CLASS(wxDisplayImplDirectDraw);
356};
357
358class wxDisplayFactoryDirectDraw : public wxDisplayFactoryWin32Base
359{
360public:
361 wxDisplayFactoryDirectDraw();
362 virtual ~wxDisplayFactoryDirectDraw();
363
364 virtual wxDisplayImpl *CreateDisplay(unsigned n);
365
366private:
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
430void 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
453wxRect wxDisplayImplWin32Base::GetGeometry() const
454{
455 if ( m_info.m_rect.IsEmpty() )
456 m_info.Initialize();
457
458 return m_info.m_rect;
459}
460
461wxRect wxDisplayImplWin32Base::GetClientArea() const
462{
463 if ( m_info.m_rectClient.IsEmpty() )
464 m_info.Initialize();
465
466 return m_info.m_rectClient;
467}
468
469wxString wxDisplayImplWin32Base::GetName() const
470{
471 if ( m_info.m_devName.empty() )
472 m_info.Initialize();
473
474 return m_info.m_devName;
475}
476
477bool 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
485wxVideoMode 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
516int wxDisplayFactoryWin32Base::ms_supportsMultimon = -1;
517
518wxDisplayFactoryWin32Base::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
538void wxDisplayFactoryWin32Base::Clear()
539{
540 WX_CLEAR_ARRAY(m_displays);
541}
542
543wxDisplayFactoryWin32Base::~wxDisplayFactoryWin32Base()
544{
545 Clear();
546}
547
548// helper for GetFromPoint() and GetFromWindow()
549int 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
564int 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
574int 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
588wxDisplayFactoryMultimon::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 */
610BOOL CALLBACK
611wxDisplayFactoryMultimon::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
629void 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
646wxDisplayImpl *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
657wxArrayVideoModes
658wxDisplayImplMultimon::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
687bool 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
807wxDisplayFactoryDirectDraw::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
835wxDisplayFactoryDirectDraw::~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
846BOOL WINAPI
847wxDisplayFactoryDirectDraw::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
869void 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
880wxDisplayImpl *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
928class wxDDVideoModesAdder
929{
930public:
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
944private:
945 wxArrayVideoModes& m_modes;
946 const wxVideoMode& m_modeMatch;
947
948 wxDECLARE_NO_COPY_CLASS(wxDDVideoModesAdder);
949};
950
951HRESULT 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
971wxArrayVideoModes
972wxDisplayImplDirectDraw::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
997bool 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