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