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) 
   8 // Copyright:   (c) wxWidgets team 
   9 // Copyright:   (c) 2002-2006 wxWidgets team 
  10 // Licence:     wxWindows licence 
  11 ///////////////////////////////////////////////////////////////////////////// 
  13 // =========================================================================== 
  15 // =========================================================================== 
  17 // --------------------------------------------------------------------------- 
  19 // --------------------------------------------------------------------------- 
  21 // For compilers that support precompilation, includes "wx.h". 
  22 #include "wx/wxprec.h" 
  30 #include "wx/display.h" 
  33     #include "wx/dynarray.h" 
  38 #include "wx/dynload.h" 
  39 #include "wx/sysopt.h" 
  41 #include "wx/display_impl.h" 
  42 #include "wx/msw/wrapwin.h" 
  43 #include "wx/msw/missing.h" 
  45 // define this to use DirectDraw for display mode switching: this is disabled 
  46 // by default because ddraw.h is now always available and also it's not really 
  47 // clear what are the benefits of using DirectDraw compared to the standard API 
  49 #if !defined(wxUSE_DIRECTDRAW) 
  50     #define wxUSE_DIRECTDRAW 0 
  54     // Older versions of windef.h don't define HMONITOR.  Unfortunately, we 
  55     // can't directly test whether HMONITOR is defined or not in windef.h as 
  56     // it's not a macro but a typedef, so we test for an unrelated symbol which 
  57     // is only defined in winuser.h if WINVER >= 0x0500 
  58     #if !defined(HMONITOR_DECLARED) && !defined(MNS_NOCHECK) 
  59         DECLARE_HANDLE(HMONITOR
); 
  60         typedef BOOL(CALLBACK 
* MONITORENUMPROC 
)(HMONITOR
, HDC
, LPRECT
, LPARAM
); 
  61         typedef struct tagMONITORINFO
 
  67         } MONITORINFO
, *LPMONITORINFO
; 
  68         typedef struct tagMONITORINFOEX 
: public tagMONITORINFO
 
  70             TCHAR       szDevice
[CCHDEVICENAME
]; 
  71         } MONITORINFOEX
, *LPMONITORINFOEX
; 
  72         #define MONITOR_DEFAULTTONULL       0x00000000 
  73         #define MONITOR_DEFAULTTOPRIMARY    0x00000001 
  74         #define MONITOR_DEFAULTTONEAREST    0x00000002 
  75         #define MONITORINFOF_PRIMARY        0x00000001 
  76         #define HMONITOR_DECLARED 
  78 #endif // !__WXWINCE__ 
  83     // we don't want to link with ddraw.lib which contains the real 
  84     // IID_IDirectDraw2 definition 
  85     const GUID wxIID_IDirectDraw2 
= 
  86      { 0xB3A6F3E0, 0x2B43, 0x11CF, { 0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 } }; 
  87 #endif // wxUSE_DIRECTDRAW 
  89 // ---------------------------------------------------------------------------- 
  90 // typedefs for dynamically loaded Windows functions 
  91 // ---------------------------------------------------------------------------- 
  93 typedef LONG (WINAPI 
*ChangeDisplaySettingsEx_t
)(LPCTSTR lpszDeviceName
, 
 100 typedef BOOL (PASCAL 
*DDEnumExCallback_t
)(GUID 
*pGuid
, 
 101                                           LPTSTR driverDescription
, 
 106 typedef HRESULT (WINAPI 
*DirectDrawEnumerateEx_t
)(DDEnumExCallback_t lpCallback
, 
 110 typedef HRESULT (WINAPI 
*DirectDrawCreate_t
)(GUID 
*lpGUID
, 
 111                                              LPDIRECTDRAW 
*lplpDD
, 
 112                                              IUnknown 
*pUnkOuter
); 
 113 #endif // wxUSE_DIRECTDRAW 
 115 typedef BOOL (WINAPI 
*EnumDisplayMonitors_t
)(HDC
,LPCRECT
,MONITORENUMPROC
,LPARAM
); 
 116 typedef HMONITOR (WINAPI 
*MonitorFromPoint_t
)(POINT
,DWORD
); 
 117 typedef HMONITOR (WINAPI 
*MonitorFromWindow_t
)(HWND
,DWORD
); 
 118 typedef BOOL (WINAPI 
*GetMonitorInfo_t
)(HMONITOR
,LPMONITORINFO
); 
 121 // emulation of ChangeDisplaySettingsEx() for Win95 
 122 LONG WINAPI 
ChangeDisplaySettingsExForWin95(LPCTSTR 
WXUNUSED(lpszDeviceName
), 
 126                                             LPVOID 
WXUNUSED(lParam
)) 
 128     return ::ChangeDisplaySettings(lpDevMode
, dwFlags
); 
 130 #endif // !__WXWINCE__ 
 132 // ---------------------------------------------------------------------------- 
 133 // display information classes 
 134 // ---------------------------------------------------------------------------- 
 138     wxDisplayInfo(HMONITOR hmon 
= NULL
) 
 144     virtual ~wxDisplayInfo() { } 
 147     // use GetMonitorInfo() to fill in all of our fields if needed (i.e. if it 
 148     // hadn't been done before) 
 152     // handle of this monitor used by MonitorXXX() functions, never NULL 
 155     // the entire area of this monitor in virtual screen coordinates 
 158     // the work or client area, i.e. the area available for the normal windows 
 161     // the display device name for this monitor, empty initially and retrieved 
 162     // on demand by DoGetName() 
 165     // the flags of this monitor, also used as initialization marker: if this 
 166     // is -1, GetMonitorInfo() hadn't been called yet 
 170 WX_DEFINE_ARRAY_PTR(wxDisplayInfo 
*, wxDisplayInfoArray
); 
 172 // ---------------------------------------------------------------------------- 
 173 // common base class for all Win32 wxDisplayImpl versions 
 174 // ---------------------------------------------------------------------------- 
 176 class wxDisplayImplWin32Base 
: public wxDisplayImpl
 
 179     wxDisplayImplWin32Base(unsigned n
, wxDisplayInfo
& info
) 
 185     virtual wxRect 
GetGeometry() const; 
 186     virtual wxRect 
GetClientArea() const; 
 187     virtual wxString 
GetName() const; 
 188     virtual bool IsPrimary() const; 
 190     virtual wxVideoMode 
GetCurrentMode() const; 
 193     // convert a DEVMODE to our wxVideoMode 
 194     static wxVideoMode 
ConvertToVideoMode(const DEVMODE
& dm
) 
 196         // note that dmDisplayFrequency may be 0 or 1 meaning "standard one" 
 197         // and although 0 is ok for us we don't want to return modes with 1hz 
 199         return wxVideoMode(dm
.dmPelsWidth
, 
 202                            dm
.dmDisplayFrequency 
> 1 ? dm
.dmDisplayFrequency 
: 0); 
 205     wxDisplayInfo
& m_info
; 
 208 // ---------------------------------------------------------------------------- 
 209 // common base class for all Win32 wxDisplayFactory versions 
 210 // ---------------------------------------------------------------------------- 
 212 // functions dynamically bound by wxDisplayFactoryWin32Base::Initialize() 
 213 static MonitorFromPoint_t gs_MonitorFromPoint 
= NULL
; 
 214 static MonitorFromWindow_t gs_MonitorFromWindow 
= NULL
; 
 215 static GetMonitorInfo_t gs_GetMonitorInfo 
= NULL
; 
 217 class wxDisplayFactoryWin32Base 
: public wxDisplayFactory
 
 220     virtual ~wxDisplayFactoryWin32Base(); 
 222     bool IsOk() const { return !m_displays
.empty(); } 
 224     virtual unsigned GetCount() { return unsigned(m_displays
.size()); } 
 225     virtual int GetFromPoint(const wxPoint
& pt
); 
 226     virtual int GetFromWindow(wxWindow 
*window
); 
 229     // ctor checks if the current system supports multimon API and dynamically 
 230     // bind the functions we need if this is the case and sets 
 231     // ms_supportsMultimon if they're available 
 232     wxDisplayFactoryWin32Base(); 
 234     // delete all m_displays elements: can be called from the derived class 
 235     // dtor if it is important to do this before destroying it (as in 
 236     // wxDisplayFactoryDirectDraw case), otherwise will be done by our dtor 
 239     // find the monitor corresponding to the given handle, return wxNOT_FOUND 
 241     int FindDisplayFromHMONITOR(HMONITOR hmon
) const; 
 244     // flag indicating whether gs_MonitorXXX functions are available 
 245     static int ms_supportsMultimon
; 
 247     // the array containing information about all available displays, should be 
 248     // filled by the derived class ctors 
 249     wxDisplayInfoArray m_displays
; 
 252     DECLARE_NO_COPY_CLASS(wxDisplayFactoryWin32Base
) 
 255 // ---------------------------------------------------------------------------- 
 256 // wxDisplay implementation using Windows multi-monitor support functions 
 257 // ---------------------------------------------------------------------------- 
 259 class wxDisplayImplMultimon 
: public wxDisplayImplWin32Base
 
 262     wxDisplayImplMultimon(unsigned n
, wxDisplayInfo
& info
) 
 263         : wxDisplayImplWin32Base(n
, info
) 
 267     virtual wxArrayVideoModes 
GetModes(const wxVideoMode
& mode
) const; 
 268     virtual bool ChangeMode(const wxVideoMode
& mode
); 
 271     DECLARE_NO_COPY_CLASS(wxDisplayImplMultimon
) 
 274 class wxDisplayFactoryMultimon 
: public wxDisplayFactoryWin32Base
 
 277     wxDisplayFactoryMultimon(); 
 279     virtual wxDisplayImpl 
*CreateDisplay(unsigned n
); 
 282     // EnumDisplayMonitors() callback 
 283     static BOOL CALLBACK 
MultimonEnumProc(HMONITOR hMonitor
, 
 289     // add a monitor description to m_displays array 
 290     void AddDisplay(HMONITOR hMonitor
, LPRECT lprcMonitor
); 
 293 // ---------------------------------------------------------------------------- 
 294 // wxDisplay implementation using DirectDraw 
 295 // ---------------------------------------------------------------------------- 
 299 struct wxDisplayInfoDirectDraw 
: wxDisplayInfo
 
 301     wxDisplayInfoDirectDraw(const GUID
& guid
, HMONITOR hmon
, LPTSTR name
) 
 302         : wxDisplayInfo(hmon
), 
 309     virtual ~wxDisplayInfoDirectDraw() 
 316     // IDirectDraw object used to control this display, may be NULL 
 317     IDirectDraw2 
*m_pDD2
; 
 319     // DirectDraw GUID for this display, only valid when using DirectDraw 
 323     DECLARE_NO_COPY_CLASS(wxDisplayInfoDirectDraw
) 
 326 class wxDisplayImplDirectDraw 
: public wxDisplayImplWin32Base
 
 329     wxDisplayImplDirectDraw(unsigned n
, wxDisplayInfo
& info
, IDirectDraw2 
*pDD2
) 
 330         : wxDisplayImplWin32Base(n
, info
), 
 336     virtual ~wxDisplayImplDirectDraw() 
 341     virtual wxArrayVideoModes 
GetModes(const wxVideoMode
& mode
) const; 
 342     virtual bool ChangeMode(const wxVideoMode
& mode
); 
 345     IDirectDraw2 
*m_pDD2
; 
 347     DECLARE_NO_COPY_CLASS(wxDisplayImplDirectDraw
) 
 350 class wxDisplayFactoryDirectDraw 
: public wxDisplayFactoryWin32Base
 
 353     wxDisplayFactoryDirectDraw(); 
 354     virtual ~wxDisplayFactoryDirectDraw(); 
 356     virtual wxDisplayImpl 
*CreateDisplay(unsigned n
); 
 359     // callback used with DirectDrawEnumerateEx() 
 360     static BOOL WINAPI 
DDEnumExCallback(GUID 
*pGuid
, 
 361                                         LPTSTR driverDescription
, 
 366     // add a monitor description to m_displays array 
 367     void AddDisplay(const GUID
& guid
, HMONITOR hmon
, LPTSTR name
); 
 371     wxDynamicLibrary m_dllDDraw
; 
 373     // dynamically resolved DirectDrawCreate() 
 374     DirectDrawCreate_t m_pfnDirectDrawCreate
; 
 376     DECLARE_NO_COPY_CLASS(wxDisplayFactoryDirectDraw
) 
 379 #endif // wxUSE_DIRECTDRAW 
 382 // ============================================================================ 
 383 // common classes implementation 
 384 // ============================================================================ 
 386 // ---------------------------------------------------------------------------- 
 388 // ---------------------------------------------------------------------------- 
 390 /* static */ wxDisplayFactory 
*wxDisplay::CreateFactory() 
 392     // we have 2 implementations for modern Windows: one using standard Win32 
 393     // and another using DirectDraw, the choice between them is done using a 
 397     if ( wxSystemOptions::GetOptionInt(_T("msw.display.directdraw")) ) 
 399         wxDisplayFactoryDirectDraw 
*factoryDD 
= new wxDisplayFactoryDirectDraw
; 
 400         if ( factoryDD
->IsOk() ) 
 405 #endif // wxUSE_DIRECTDRAW 
 407     wxDisplayFactoryMultimon 
*factoryMM 
= new wxDisplayFactoryMultimon
; 
 408     if ( factoryMM
->IsOk() ) 
 414     // finally fall back to a stub implementation if all else failed (Win95?) 
 415     return new wxDisplayFactorySingle
; 
 418 // ---------------------------------------------------------------------------- 
 420 // ---------------------------------------------------------------------------- 
 422 void wxDisplayInfo::Initialize() 
 424     if ( m_flags 
== (DWORD
)-1 ) 
 426         WinStruct
<MONITORINFOEX
> monInfo
; 
 427         if ( !gs_GetMonitorInfo(m_hmon
, (LPMONITORINFO
)&monInfo
) ) 
 429             wxLogLastError(_T("GetMonitorInfo")); 
 434         wxCopyRECTToRect(monInfo
.rcMonitor
, m_rect
); 
 435         wxCopyRECTToRect(monInfo
.rcWork
, m_rectClient
); 
 436         m_devName 
= monInfo
.szDevice
; 
 437         m_flags 
= monInfo
.dwFlags
; 
 441 // ---------------------------------------------------------------------------- 
 442 // wxDisplayImplWin32Base 
 443 // ---------------------------------------------------------------------------- 
 445 wxRect 
wxDisplayImplWin32Base::GetGeometry() const 
 447     if ( m_info
.m_rect
.IsEmpty() ) 
 450     return m_info
.m_rect
; 
 453 wxRect 
wxDisplayImplWin32Base::GetClientArea() const 
 455     if ( m_info
.m_rectClient
.IsEmpty() ) 
 458     return m_info
.m_rectClient
; 
 461 wxString 
wxDisplayImplWin32Base::GetName() const 
 463     if ( m_info
.m_devName
.empty() ) 
 466     return m_info
.m_devName
; 
 469 bool wxDisplayImplWin32Base::IsPrimary() const 
 471     if ( m_info
.m_flags 
== (DWORD
)-1 ) 
 474     return (m_info
.m_flags 
& MONITORINFOF_PRIMARY
) != 0; 
 477 wxVideoMode 
wxDisplayImplWin32Base::GetCurrentMode() const 
 481     // The first parameter of EnumDisplaySettings() must be NULL under Win95 
 482     // according to MSDN.  The version of GetName() we implement for Win95 
 483     // returns an empty string. 
 484     const wxString name 
= GetName(); 
 485     const wxChar 
* const deviceName 
= name
.empty() ? NULL 
: name
.c_str(); 
 488     dm
.dmSize 
= sizeof(dm
); 
 489     dm
.dmDriverExtra 
= 0; 
 490     if ( !::EnumDisplaySettings(deviceName
, ENUM_CURRENT_SETTINGS
, &dm
) ) 
 492         wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)")); 
 496         mode 
= ConvertToVideoMode(dm
); 
 502 // ---------------------------------------------------------------------------- 
 503 // wxDisplayFactoryWin32Base 
 504 // ---------------------------------------------------------------------------- 
 506 int wxDisplayFactoryWin32Base::ms_supportsMultimon 
= -1; 
 508 wxDisplayFactoryWin32Base::wxDisplayFactoryWin32Base() 
 510     if ( ms_supportsMultimon 
== -1 ) 
 512         ms_supportsMultimon 
= 0; 
 514         wxDynamicLibrary 
dllUser32(_T("user32.dll")); 
 518         gs_MonitorFromPoint 
= (MonitorFromPoint_t
) 
 519             dllUser32
.GetSymbol(wxT("MonitorFromPoint")); 
 520         if ( !gs_MonitorFromPoint 
) 
 523         gs_MonitorFromWindow 
= (MonitorFromWindow_t
) 
 524             dllUser32
.GetSymbol(wxT("MonitorFromWindow")); 
 525         if ( !gs_MonitorFromWindow 
) 
 528         gs_GetMonitorInfo 
= (GetMonitorInfo_t
) 
 529             dllUser32
.GetSymbolAorW(wxT("GetMonitorInfo")); 
 530         if ( !gs_GetMonitorInfo 
) 
 533         ms_supportsMultimon 
= 1; 
 535         // we can safely let dllUser32 go out of scope, the DLL itself will 
 536         // still remain loaded as all Win32 programs use it 
 540 void wxDisplayFactoryWin32Base::Clear() 
 542     WX_CLEAR_ARRAY(m_displays
); 
 545 wxDisplayFactoryWin32Base::~wxDisplayFactoryWin32Base() 
 550 // helper for GetFromPoint() and GetFromWindow() 
 551 int wxDisplayFactoryWin32Base::FindDisplayFromHMONITOR(HMONITOR hmon
) const 
 555         const size_t count 
= m_displays
.size(); 
 556         for ( size_t n 
= 0; n 
< count
; n
++ ) 
 558             if ( hmon 
== m_displays
[n
]->m_hmon 
) 
 566 int wxDisplayFactoryWin32Base::GetFromPoint(const wxPoint
& pt
) 
 572     return FindDisplayFromHMONITOR(gs_MonitorFromPoint(pt2
, 
 573                                                        MONITOR_DEFAULTTONULL
)); 
 576 int wxDisplayFactoryWin32Base::GetFromWindow(wxWindow 
*window
) 
 578     return FindDisplayFromHMONITOR(gs_MonitorFromWindow(GetHwndOf(window
), 
 579                                                         MONITOR_DEFAULTTONULL
)); 
 582 // ============================================================================ 
 583 // wxDisplay implementation using Win32 multimon API 
 584 // ============================================================================ 
 586 // ---------------------------------------------------------------------------- 
 587 // wxDisplayFactoryMultimon initialization 
 588 // ---------------------------------------------------------------------------- 
 590 wxDisplayFactoryMultimon::wxDisplayFactoryMultimon() 
 592     if ( !ms_supportsMultimon 
) 
 595     // look up EnumDisplayMonitors() which we don't need with DirectDraw 
 597     EnumDisplayMonitors_t pfnEnumDisplayMonitors
; 
 601         wxDynamicLibrary 
dllUser32(_T("user32.dll")); 
 602         pfnEnumDisplayMonitors 
= (EnumDisplayMonitors_t
) 
 603             dllUser32
.GetSymbol(wxT("EnumDisplayMonitors")); 
 604         if ( !pfnEnumDisplayMonitors 
) 
 608     // enumerate all displays 
 609     if ( !pfnEnumDisplayMonitors(NULL
, NULL
, MultimonEnumProc
, (LPARAM
)this) ) 
 611         wxLogLastError(wxT("EnumDisplayMonitors")); 
 617 wxDisplayFactoryMultimon::MultimonEnumProc( 
 618   HMONITOR hMonitor
,        // handle to display monitor 
 619   HDC 
WXUNUSED(hdcMonitor
), // handle to monitor-appropriate device context 
 620   LPRECT lprcMonitor
,       // pointer to monitor intersection rectangle 
 621   LPARAM dwData             
// data passed from EnumDisplayMonitors (this) 
 624     wxDisplayFactoryMultimon 
*const self 
= (wxDisplayFactoryMultimon 
*)dwData
; 
 625     self
->AddDisplay(hMonitor
, lprcMonitor
); 
 627     // continue the enumeration 
 631 // ---------------------------------------------------------------------------- 
 632 // wxDisplayFactoryMultimon helper functions 
 633 // ---------------------------------------------------------------------------- 
 635 void wxDisplayFactoryMultimon::AddDisplay(HMONITOR hMonitor
, LPRECT lprcMonitor
) 
 637     wxDisplayInfo 
*info 
= new wxDisplayInfo(hMonitor
); 
 639     // we also store the display geometry 
 640     info
->m_rect 
= wxRect(lprcMonitor
->left
, lprcMonitor
->top
, 
 641                           lprcMonitor
->right 
- lprcMonitor
->left
, 
 642                           lprcMonitor
->bottom 
- lprcMonitor
->top
); 
 644     // now add this monitor to the array 
 645     m_displays
.Add(info
); 
 648 // ---------------------------------------------------------------------------- 
 649 // wxDisplayFactoryMultimon inherited pure virtuals implementation 
 650 // ---------------------------------------------------------------------------- 
 652 wxDisplayImpl 
*wxDisplayFactoryMultimon::CreateDisplay(unsigned n
) 
 654     wxCHECK_MSG( n 
< m_displays
.size(), NULL
, _T("invalid display index") ); 
 656     return new wxDisplayImplMultimon(n
, *(m_displays
[n
])); 
 659 // ---------------------------------------------------------------------------- 
 660 // wxDisplayImplMultimon implementation 
 661 // ---------------------------------------------------------------------------- 
 664 wxDisplayImplMultimon::GetModes(const wxVideoMode
& modeMatch
) const 
 666     wxArrayVideoModes modes
; 
 668     // The first parameter of EnumDisplaySettings() must be NULL under Win95 
 669     // according to MSDN.  The version of GetName() we implement for Win95 
 670     // returns an empty string. 
 671     const wxString name 
= GetName(); 
 672     const wxChar 
* const deviceName 
= name
.empty() ? NULL 
: name
.c_str(); 
 675     dm
.dmSize 
= sizeof(dm
); 
 676     dm
.dmDriverExtra 
= 0; 
 677     for ( int iModeNum 
= 0; 
 678           ::EnumDisplaySettings(deviceName
, iModeNum
, &dm
); 
 681         const wxVideoMode mode 
= ConvertToVideoMode(dm
); 
 682         if ( mode
.Matches(modeMatch
) ) 
 691 bool wxDisplayImplMultimon::ChangeMode(const wxVideoMode
& mode
) 
 693     // prepare ChangeDisplaySettingsEx() parameters 
 699     if ( mode 
== wxDefaultVideoMode 
) 
 701         // reset the video mode to default 
 705     else // change to the given mode 
 707         wxCHECK_MSG( mode
.w 
&& mode
.h
, false, 
 708                         _T("at least the width and height must be specified") ); 
 711         dm
.dmSize 
= sizeof(dm
); 
 712         dm
.dmDriverExtra 
= 0; 
 713         dm
.dmFields 
= DM_PELSWIDTH 
| DM_PELSHEIGHT
; 
 714         dm
.dmPelsWidth 
= mode
.w
; 
 715         dm
.dmPelsHeight 
= mode
.h
; 
 719             dm
.dmFields 
|= DM_BITSPERPEL
; 
 720             dm
.dmBitsPerPel 
= mode
.bpp
; 
 725             dm
.dmFields 
|= DM_DISPLAYFREQUENCY
; 
 726             dm
.dmDisplayFrequency 
= mode
.refresh
; 
 733 #else // !__WXWINCE__ 
 734         flags 
= CDS_FULLSCREEN
; 
 735 #endif // __WXWINCE__/!__WXWINCE__ 
 739     // get pointer to the function dynamically 
 741     // we're only called from the main thread, so it's ok to use static 
 743     static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx 
= NULL
; 
 744     if ( !pfnChangeDisplaySettingsEx 
) 
 746         wxDynamicLibrary 
dllUser32(_T("user32.dll")); 
 747         if ( dllUser32
.IsLoaded() ) 
 749             pfnChangeDisplaySettingsEx 
= (ChangeDisplaySettingsEx_t
) 
 750                 dllUser32
.GetSymbolAorW(_T("ChangeDisplaySettingsEx")); 
 752         //else: huh, no user32.dll?? 
 755         if ( !pfnChangeDisplaySettingsEx 
) 
 757             // we must be under Win95 and so there is no multiple monitors 
 759             pfnChangeDisplaySettingsEx 
= ChangeDisplaySettingsExForWin95
; 
 761 #endif // !__WXWINCE__ 
 764     // do change the mode 
 765     switch ( pfnChangeDisplaySettingsEx
 
 767                 GetName(),      // display name 
 768                 pDevMode
,       // dev mode or NULL to reset 
 771                 NULL            
// pointer to video parameters (not used) 
 774         case DISP_CHANGE_SUCCESSFUL
: 
 777                 // If we have a top-level, full-screen frame, emulate 
 778                 // the DirectX behavior and resize it.  This makes this 
 779                 // API quite a bit easier to use. 
 780                 wxWindow 
*winTop 
= wxTheApp
->GetTopWindow(); 
 781                 wxFrame 
*frameTop 
= wxDynamicCast(winTop
, wxFrame
); 
 782                 if (frameTop 
&& frameTop
->IsFullScreen()) 
 784                     wxVideoMode current 
= GetCurrentMode(); 
 785                     frameTop
->SetClientSize(current
.w
, current
.h
); 
 790         case DISP_CHANGE_BADMODE
: 
 791             // don't complain about this, this is the only "expected" error 
 795             wxFAIL_MSG( _T("unexpected ChangeDisplaySettingsEx() return value") ); 
 802 // ============================================================================ 
 803 // DirectDraw-based wxDisplay implementation 
 804 // ============================================================================ 
 808 // ---------------------------------------------------------------------------- 
 809 // wxDisplayFactoryDirectDraw initialization 
 810 // ---------------------------------------------------------------------------- 
 812 wxDisplayFactoryDirectDraw::wxDisplayFactoryDirectDraw() 
 814     if ( !ms_supportsMultimon 
) 
 818     // suppress the errors if ddraw.dll is not found, we're prepared to handle 
 823     m_dllDDraw
.Load(_T("ddraw.dll")); 
 825     if ( !m_dllDDraw
.IsLoaded() ) 
 828     DirectDrawEnumerateEx_t pDDEnumEx 
= (DirectDrawEnumerateEx_t
) 
 829         m_dllDDraw
.GetSymbolAorW(_T("DirectDrawEnumerateEx")); 
 833     // we can't continue without DirectDrawCreate() later, so resolve it right 
 834     // now and fail the initialization if it's not available 
 835     m_pfnDirectDrawCreate 
= (DirectDrawCreate_t
) 
 836         m_dllDDraw
.GetSymbol(_T("DirectDrawCreate")); 
 837     if ( !m_pfnDirectDrawCreate 
) 
 840     if ( (*pDDEnumEx
)(DDEnumExCallback
, 
 842                       DDENUM_ATTACHEDSECONDARYDEVICES
) != DD_OK 
) 
 844         wxLogLastError(_T("DirectDrawEnumerateEx")); 
 848 wxDisplayFactoryDirectDraw::~wxDisplayFactoryDirectDraw() 
 850     // we must clear m_displays now, before m_dllDDraw is unloaded as otherwise 
 851     // calling m_pDD2->Release() later would crash 
 855 // ---------------------------------------------------------------------------- 
 856 // callbacks for monitor/modes enumeration stuff 
 857 // ---------------------------------------------------------------------------- 
 860 wxDisplayFactoryDirectDraw::DDEnumExCallback(GUID 
*pGuid
, 
 861                                              LPTSTR 
WXUNUSED(driverDescription
), 
 868         wxDisplayFactoryDirectDraw 
* self 
= 
 869             wx_static_cast(wxDisplayFactoryDirectDraw 
*, lpContext
); 
 870         self
->AddDisplay(*pGuid
, hmon
, driverName
); 
 872     //else: we're called for the primary monitor, skip it 
 874     // continue the enumeration 
 878 // ---------------------------------------------------------------------------- 
 879 // wxDisplayFactoryDirectDraw helpers 
 880 // ---------------------------------------------------------------------------- 
 882 void wxDisplayFactoryDirectDraw::AddDisplay(const GUID
& guid
, 
 886     m_displays
.Add(new wxDisplayInfoDirectDraw(guid
, hmon
, name
)); 
 889 // ---------------------------------------------------------------------------- 
 890 // wxDisplayFactoryDirectDraw inherited pure virtuals implementation 
 891 // ---------------------------------------------------------------------------- 
 893 wxDisplayImpl 
*wxDisplayFactoryDirectDraw::CreateDisplay(unsigned n
) 
 895     wxCHECK_MSG( n 
< m_displays
.size(), NULL
, _T("invalid display index") ); 
 897     wxDisplayInfoDirectDraw 
* 
 898         info 
= wx_static_cast(wxDisplayInfoDirectDraw 
*, m_displays
[n
]); 
 903         GUID 
guid(info
->m_guid
); 
 904         HRESULT hr 
= (*m_pfnDirectDrawCreate
)(&guid
, &pDD
, NULL
); 
 906         if ( FAILED(hr
) || !pDD 
) 
 909             wxLogApiError(_T("DirectDrawCreate"), hr
); 
 913         // we got IDirectDraw, but we need IDirectDraw2 
 914         hr 
= pDD
->QueryInterface(wxIID_IDirectDraw2
, (void **)&info
->m_pDD2
); 
 917         if ( FAILED(hr
) || !info
->m_pDD2 
) 
 919             wxLogApiError(_T("IDirectDraw::QueryInterface(IDD2)"), hr
); 
 923         // NB: m_pDD2 will now be only destroyed when m_displays is destroyed 
 924         //     which is ok as we don't want to recreate DD objects all the time 
 926     //else: DirectDraw object corresponding to our display already exists 
 928     return new wxDisplayImplDirectDraw(n
, *info
, info
->m_pDD2
); 
 931 // ============================================================================ 
 932 // wxDisplayImplDirectDraw 
 933 // ============================================================================ 
 935 // ---------------------------------------------------------------------------- 
 936 // video modes enumeration 
 937 // ---------------------------------------------------------------------------- 
 939 // tiny helper class used to pass information from GetModes() to 
 940 // wxDDEnumModesCallback 
 941 class wxDDVideoModesAdder
 
 944     // our Add() method will add modes matching modeMatch to modes array 
 945     wxDDVideoModesAdder(wxArrayVideoModes
& modes
, const wxVideoMode
& modeMatch
) 
 947           m_modeMatch(modeMatch
) 
 951     void Add(const wxVideoMode
& mode
) 
 953         if ( mode
.Matches(m_modeMatch
) ) 
 958     wxArrayVideoModes
& m_modes
; 
 959     const wxVideoMode
& m_modeMatch
; 
 961     DECLARE_NO_COPY_CLASS(wxDDVideoModesAdder
) 
 964 HRESULT WINAPI 
wxDDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc
, 
 967     // we need at least the mode size 
 968     static const DWORD FLAGS_REQUIRED 
= DDSD_HEIGHT 
| DDSD_WIDTH
; 
 969     if ( (lpDDSurfaceDesc
->dwFlags 
& FLAGS_REQUIRED
) == FLAGS_REQUIRED 
) 
 971         wxDDVideoModesAdder 
* const vmodes 
= 
 972             wx_static_cast(wxDDVideoModesAdder 
*, lpContext
); 
 974         vmodes
->Add(wxVideoMode(lpDDSurfaceDesc
->dwWidth
, 
 975                                 lpDDSurfaceDesc
->dwHeight
, 
 976                                 lpDDSurfaceDesc
->ddpfPixelFormat
.dwRGBBitCount
, 
 977                                 lpDDSurfaceDesc
->dwRefreshRate
)); 
 980     // continue the enumeration 
 985 wxDisplayImplDirectDraw::GetModes(const wxVideoMode
& modeMatch
) const 
 987     wxArrayVideoModes modes
; 
 988     wxDDVideoModesAdder 
modesAdder(modes
, modeMatch
); 
 990     HRESULT hr 
= m_pDD2
->EnumDisplayModes
 
 994                             &modesAdder
,            // callback parameter 
 995                             wxDDEnumModesCallback
 
1000         wxLogApiError(_T("IDirectDraw::EnumDisplayModes"), hr
); 
1006 // ---------------------------------------------------------------------------- 
1007 // video mode switching 
1008 // ---------------------------------------------------------------------------- 
1010 bool wxDisplayImplDirectDraw::ChangeMode(const wxVideoMode
& mode
) 
1012     wxWindow 
*winTop 
= wxTheApp
->GetTopWindow(); 
1013     wxCHECK_MSG( winTop
, false, _T("top level window required for DirectX") ); 
1015     HRESULT hr 
= m_pDD2
->SetCooperativeLevel
 
1018                             DDSCL_EXCLUSIVE 
| DDSCL_FULLSCREEN
 
1022         wxLogApiError(_T("IDirectDraw2::SetCooperativeLevel"), hr
); 
1027     hr 
= m_pDD2
->SetDisplayMode(mode
.w
, mode
.h
, mode
.bpp
, mode
.refresh
, 0); 
1030         wxLogApiError(_T("IDirectDraw2::SetDisplayMode"), hr
); 
1038 #endif // wxUSE_DIRECTDRAW 
1040 #endif // wxUSE_DISPLAY