]> git.saurik.com Git - wxWidgets.git/blame - src/msw/display.cpp
Fix compile problem with VS 2005
[wxWidgets.git] / src / msw / display.cpp
CommitLineData
a536e411 1/////////////////////////////////////////////////////////////////////////////
2ad495fb 2// Name: src/msw/display.cpp
a536e411 3// Purpose: MSW Implementation of wxDisplay class
d20c3f41 4// Author: Royce Mitchell III
06efac1f 5// Modified by: VZ (resolutions enumeration/change support, DirectDraw, ...)
2ad495fb 6// Ryan Norton (IsPrimary override)
a536e411
JS
7// Created: 06/21/02
8// RCS-ID: $Id$
77ffb593 9// Copyright: (c) 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
30#ifndef WX_PRECOMP
f29cfd77 31 #include "wx/app.h"
a536e411 32 #include "wx/dynarray.h"
f29cfd77 33 #include "wx/frame.h"
a536e411
JS
34#endif
35
8585e2b5
VZ
36#include "wx/dynload.h"
37
a536e411
JS
38#include "wx/display.h"
39
01c54165
VZ
40// Mingw's w32api headers don't include ddraw.h, though the user may have
41// installed it. If using configure, we actually probe for ddraw.h there
42// and set HAVE_DDRAW_H. Otherwise, assume we don't have it if using
43// the w32api headers, and that we do otherwise.
44#if !defined HAVE_W32API_H && !defined HAVE_DDRAW_H
45#define HAVE_DDRAW_H 1
a536e411
JS
46#endif
47
2ad495fb 48#ifndef __WXWINCE__
01c54165 49 // Older versions of windef.h don't define HMONITOR. Unfortunately, we
bcc1153a
VZ
50 // can't directly test whether HMONITOR is defined or not in windef.h as
51 // it's not a macro but a typedef, so we test for an unrelated symbol which
52 // is only defined in winuser.h if WINVER >= 0x0500
53 #if !defined(HMONITOR_DECLARED) && !defined(MNS_NOCHECK)
54 DECLARE_HANDLE(HMONITOR);
55 #define HMONITOR_DECLARED
56 #endif
2ad495fb 57#endif // !__WXWINCE__
a536e411 58
01c54165 59#ifdef HAVE_DDRAW_H
06efac1f
VZ
60#include <ddraw.h>
61
62// we don't want to link with ddraw.lib which contains the real
63// IID_IDirectDraw2 definition
64const GUID wxIID_IDirectDraw2 =
65 { 0xB3A6F3E0, 0x2B43, 0x11CF, { 0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 } };
01c54165 66#endif
06efac1f
VZ
67
68// ----------------------------------------------------------------------------
69// macros
70// ----------------------------------------------------------------------------
71
8585e2b5 72#ifdef _UNICODE
06efac1f 73 #define WINFUNC(x) _T(#x) L"W"
8585e2b5
VZ
74#else
75 #define WINFUNC(x) #x "A"
76#endif
a536e411
JS
77
78// ----------------------------------------------------------------------------
06efac1f 79// typedefs for dynamically loaded Windows functions
a536e411
JS
80// ----------------------------------------------------------------------------
81
8585e2b5
VZ
82typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName,
83 LPDEVMODE lpDevMode,
84 HWND hwnd,
85 DWORD dwFlags,
86 LPVOID lParam);
a536e411 87
01c54165 88#ifdef HAVE_DDRAW_H
06efac1f
VZ
89typedef BOOL (PASCAL *DDEnumExCallback_t)(GUID *pGuid,
90 LPTSTR driverDescription,
91 LPTSTR driverName,
92 LPVOID lpContext,
93 HMONITOR hmon);
94
95typedef HRESULT (WINAPI *DirectDrawEnumerateEx_t)(DDEnumExCallback_t lpCallback,
96 LPVOID lpContext,
97 DWORD dwFlags);
98
99typedef HRESULT (WINAPI *DirectDrawCreate_t)(GUID *lpGUID,
100 LPDIRECTDRAW *lplpDD,
101 IUnknown *pUnkOuter);
01c54165
VZ
102#endif
103
104typedef BOOL (WINAPI *EnumDisplayMonitors_t)(HDC,LPCRECT,MONITORENUMPROC,LPARAM);
105typedef HMONITOR (WINAPI *MonitorFromPoint_t)(POINT,DWORD);
106typedef HMONITOR (WINAPI *MonitorFromWindow_t)(HWND,DWORD);
107typedef BOOL (WINAPI *GetMonitorInfo_t)(HMONITOR,LPMONITORINFO);
108
109static EnumDisplayMonitors_t gs_EnumDisplayMonitors = NULL;
110static MonitorFromPoint_t gs_MonitorFromPoint = NULL;
111static MonitorFromWindow_t gs_MonitorFromWindow = NULL;
112static GetMonitorInfo_t gs_GetMonitorInfo = NULL;
06efac1f 113
8585e2b5
VZ
114// ----------------------------------------------------------------------------
115// private classes
116// ----------------------------------------------------------------------------
a536e411 117
8585e2b5 118class wxDisplayInfo
a536e411
JS
119{
120public:
8585e2b5
VZ
121 // handle of this monitor used by MonitorXXX() functions, never NULL
122 HMONITOR m_hmon;
123
06efac1f 124 // IDirectDraw object used to control this display, may be NULL
01c54165 125#ifdef HAVE_DDRAW_H
06efac1f 126 IDirectDraw2 *m_pDD2;
01c54165
VZ
127#else
128 void *m_pDD2;
129#endif
06efac1f
VZ
130
131 // DirectDraw GUID for this display, only valid when using DirectDraw
132 GUID m_guid;
133
8585e2b5 134 // the entire area of this monitor in virtual screen coordinates
a536e411 135 wxRect m_rect;
8585e2b5
VZ
136
137 // the display device name for this monitor, empty initially and retrieved
138 // on demand by DoGetName()
139 wxString m_devName;
140
06efac1f 141 wxDisplayInfo() { m_hmon = NULL; m_pDD2 = NULL; }
01c54165
VZ
142 ~wxDisplayInfo() {
143#ifdef HAVE_DDRAW_H
144 if ( m_pDD2 ) m_pDD2->Release();
145#endif
146 }
a536e411
JS
147};
148
8585e2b5
VZ
149WX_DECLARE_OBJARRAY(wxDisplayInfo, wxDisplayInfoArray);
150#include "wx/arrimpl.cpp"
151WX_DEFINE_OBJARRAY(wxDisplayInfoArray);
a536e411 152
06efac1f 153// this module is used to cleanup gs_displays array
8585e2b5
VZ
154class wxDisplayModule : public wxModule
155{
156public:
06efac1f 157 virtual bool OnInit() { return true; }
8585e2b5
VZ
158 virtual void OnExit();
159
160 DECLARE_DYNAMIC_CLASS(wxDisplayModule)
161};
162
163IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule)
a536e411 164
06efac1f
VZ
165// ----------------------------------------------------------------------------
166// globals
167// ----------------------------------------------------------------------------
168
01c54165 169#ifdef HAVE_DDRAW_H
06efac1f
VZ
170// do we use DirectX?
171static bool gs_useDirectX = false;
01c54165 172#endif
06efac1f 173
01c54165
VZ
174// Try to look up the functions needed for supporting multiple monitors. If
175// they aren't available (probably because we're running on Win95 or NT4 which
176// predate this API), set a flag which makes wxDisplay return results for a
177// single screen.
178static bool OsSupportsMultipleMonitors()
179{
180 static int isNewEnough = -1;
181 if ( isNewEnough == -1 )
182 {
183 isNewEnough = 0;
184 wxDynamicLibrary dllUser32(_T("user32.dll"));
185 // Check for one of the symbols to avoid logging errors just because
186 // we happen to be running on Win95 or NT4.
187 if ( dllUser32.IsLoaded() &&
188 dllUser32.HasSymbol(wxT("EnumDisplayMonitors")) )
189 {
190 // GetMonitorInfo has Unicode/ANSI variants, the others don't.
191 gs_EnumDisplayMonitors = (EnumDisplayMonitors_t)
192 dllUser32.GetSymbol(wxT("EnumDisplayMonitors"));
193 gs_MonitorFromPoint = (MonitorFromPoint_t)
194 dllUser32.GetSymbol(wxT("MonitorFromPoint"));
195 gs_MonitorFromWindow = (MonitorFromWindow_t)
196 dllUser32.GetSymbol(wxT("MonitorFromWindow"));
197 gs_GetMonitorInfo = (GetMonitorInfo_t)
198 dllUser32.GetSymbol(WINFUNC(GetMonitorInfo));
199 if ( gs_EnumDisplayMonitors != NULL &&
200 gs_MonitorFromPoint != NULL &&
201 gs_MonitorFromWindow != NULL &&
202 gs_GetMonitorInfo != NULL )
203 {
204 isNewEnough = 1;
205 }
206 }
207 }
208 return (isNewEnough != 0);
209}
210
211#ifdef HAVE_DDRAW_H
06efac1f
VZ
212// dynamically resolved DirectDrawCreate()
213static DirectDrawCreate_t gs_DirectDrawCreate = NULL;
01c54165 214#endif
06efac1f
VZ
215
216// this is not really MT-unsafe as wxDisplay is only going to be used from the
217// main thread, i.e. we consider that it's a GUI class and so don't protect it
218static wxDisplayInfoArray *gs_displays = NULL;
219
a536e411
JS
220// ===========================================================================
221// implementation
222// ===========================================================================
223
8585e2b5 224// ----------------------------------------------------------------------------
06efac1f 225// callbacks for monitor/modes enumeration stuff
8585e2b5
VZ
226// ----------------------------------------------------------------------------
227
228static BOOL CALLBACK wxmswMonitorEnumProc (
2eb10e2a
VZ
229 HMONITOR hMonitor, // handle to display monitor
230 HDC WXUNUSED(hdcMonitor), // handle to monitor-appropriate device context
231 LPRECT lprcMonitor, // pointer to monitor intersection rectangle
232 LPARAM WXUNUSED(dwData) // data passed from EnumDisplayMonitors (unused)
a536e411
JS
233)
234{
06efac1f 235 wxDisplayInfo *info = new wxDisplayInfo();
8585e2b5
VZ
236
237 // we need hMonitor to be able to map display id to it which is needed for
238 // MonitorXXX() functions, in particular MonitorFromPoint()
a536e411 239 info->m_hmon = hMonitor;
8585e2b5
VZ
240
241 // we also store the display geometry
a536e411
JS
242 info->m_rect.SetX ( lprcMonitor->left );
243 info->m_rect.SetY ( lprcMonitor->top );
244 info->m_rect.SetWidth ( lprcMonitor->right - lprcMonitor->left );
245 info->m_rect.SetHeight ( lprcMonitor->bottom - lprcMonitor->top );
8585e2b5 246
a536e411 247 // now add this monitor to the array
06efac1f 248 gs_displays->Add(info);
a536e411 249
8585e2b5 250 // continue the enumeration
06efac1f 251 return true;
a536e411
JS
252}
253
01c54165 254#ifdef HAVE_DDRAW_H
06efac1f
VZ
255BOOL PASCAL
256wxDDEnumExCallback(GUID *pGuid,
2eb10e2a 257 LPTSTR WXUNUSED(driverDescription),
06efac1f 258 LPTSTR driverName,
2eb10e2a 259 LPVOID WXUNUSED(lpContext),
06efac1f 260 HMONITOR hmon)
a536e411 261{
06efac1f
VZ
262 if ( pGuid )
263 {
264 wxDisplayInfo *info = new wxDisplayInfo();
265
266 info->m_hmon = hmon;
267 info->m_guid = *pGuid;
268 info->m_devName = driverName;
269
270 gs_displays->Add(info);
271 }
272 //else: we're called for the primary monitor, skip it
273
274 // continue the enumeration
275 return true;
276}
277
d71cc120 278HRESULT WINAPI wxDDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc,
06efac1f
VZ
279 LPVOID lpContext)
280{
281 // we need at least the mode size
f29cfd77 282 static const DWORD FLAGS_REQUIRED = DDSD_HEIGHT | DDSD_WIDTH;
06efac1f
VZ
283 if ( (lpDDSurfaceDesc->dwFlags & FLAGS_REQUIRED) == FLAGS_REQUIRED )
284 {
285 wxArrayVideoModes * const modes = (wxArrayVideoModes *)lpContext;
286
287 modes->Add(wxVideoMode(lpDDSurfaceDesc->dwWidth,
288 lpDDSurfaceDesc->dwHeight,
289 lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
290 lpDDSurfaceDesc->dwRefreshRate));
291 }
292
293 // continue the enumeration
294 return DDENUMRET_OK;
295}
01c54165 296#endif
06efac1f
VZ
297
298// ----------------------------------------------------------------------------
299// local functions
300// ----------------------------------------------------------------------------
301
01c54165 302#ifdef HAVE_DDRAW_H
06efac1f
VZ
303// initialize gs_displays using DirectX functions
304static bool DoInitDirectX()
305{
0b4f47a3 306#if wxUSE_LOG
06efac1f
VZ
307 // suppress the errors if ddraw.dll is not found
308 wxLog::EnableLogging(false);
0b4f47a3 309#endif
a536e411 310
06efac1f 311 wxDynamicLibrary dllDX(_T("ddraw.dll"));
a536e411 312
0b4f47a3
DS
313#if wxUSE_LOG
314 wxLog::EnableLogging();
315#endif
06efac1f
VZ
316
317 if ( !dllDX.IsLoaded() )
318 return false;
319
320 DirectDrawEnumerateEx_t pDDEnumEx = (DirectDrawEnumerateEx_t)
321 dllDX.GetSymbol(WINFUNC(DirectDrawEnumerateEx));
322 if ( !pDDEnumEx )
323 return false;
324
325 // we'll also need DirectDrawCreate() later, resolve it right now
326 gs_DirectDrawCreate = (DirectDrawCreate_t)
327 dllDX.GetSymbol(_T("DirectDrawCreate"));
328 if ( !gs_DirectDrawCreate )
329 return false;
330
331 if ( (*pDDEnumEx)(wxDDEnumExCallback,
332 NULL,
333 DDENUM_ATTACHEDSECONDARYDEVICES) != DD_OK )
334 {
335 return false;
336 }
337
338 // ok, it seems like we're going to use DirectDraw and so we're going to
339 // need ddraw.dll all the time, don't unload it
340 dllDX.Detach();
341
342 return true;
343}
01c54165 344#endif
06efac1f
VZ
345
346// initialize gs_displays using the standard Windows functions
347static void DoInitStdWindows()
348{
8585e2b5 349 // enumerate all displays
01c54165 350 if ( !gs_EnumDisplayMonitors(NULL, NULL, wxmswMonitorEnumProc, 0) )
a536e411 351 {
8585e2b5
VZ
352 wxLogLastError(wxT("EnumDisplayMonitors"));
353
06efac1f 354 // TODO: still create at least one (valid) entry in gs_displays for the
8585e2b5 355 // primary display!
a536e411 356 }
8585e2b5 357}
a536e411 358
06efac1f
VZ
359// this function must be called before accessing gs_displays array as it
360// creates and initializes it
361static void InitDisplays()
362{
363 if ( gs_displays )
364 return;
365
366 gs_displays = new wxDisplayInfoArray();
367
01c54165 368#ifdef HAVE_DDRAW_H
82eba826 369 if ( !gs_useDirectX || !DoInitDirectX() )
06efac1f
VZ
370 {
371 // either we were told not to try to use DirectX or fall back to std
372 // functions if DirectX method failed
373 gs_useDirectX = false;
374
375 DoInitStdWindows();
376 }
01c54165
VZ
377#else
378 DoInitStdWindows();
379#endif
06efac1f
VZ
380}
381
8585e2b5
VZ
382// convert a DEVMODE to our wxVideoMode
383wxVideoMode ConvertToVideoMode(const DEVMODE& dm)
384{
385 // note that dmDisplayFrequency may be 0 or 1 meaning "standard one" and
386 // although 0 is ok for us we don't want to return modes with 1hz refresh
387 return wxVideoMode(dm.dmPelsWidth,
388 dm.dmPelsHeight,
389 dm.dmBitsPerPel,
390 dm.dmDisplayFrequency > 1 ? dm.dmDisplayFrequency : 0);
391}
a536e411 392
2ad495fb 393#ifndef __WXWINCE__
8585e2b5
VZ
394// emulation of ChangeDisplaySettingsEx() for Win95
395LONG WINAPI ChangeDisplaySettingsExForWin95(LPCTSTR WXUNUSED(lpszDeviceName),
396 LPDEVMODE lpDevMode,
397 HWND WXUNUSED(hwnd),
398 DWORD dwFlags,
399 LPVOID WXUNUSED(lParam))
400{
401 return ::ChangeDisplaySettings(lpDevMode, dwFlags);
402}
2ad495fb 403#endif // !__WXWINCE__
a536e411 404
8585e2b5
VZ
405// ----------------------------------------------------------------------------
406// wxDisplayModule
407// ----------------------------------------------------------------------------
a536e411 408
8585e2b5
VZ
409void wxDisplayModule::OnExit()
410{
06efac1f 411 delete gs_displays;
8585e2b5 412}
a536e411 413
8585e2b5
VZ
414// ---------------------------------------------------------------------------
415// wxDisplay
416// ---------------------------------------------------------------------------
a536e411 417
06efac1f
VZ
418/* static */
419void wxDisplay::UseDirectX(bool useDX)
420{
421 wxCHECK_RET( !gs_displays, _T("it is too late to call UseDirectX") );
422
01c54165
VZ
423#ifdef HAVE_DDRAW_H
424 // DirectDrawEnumerateEx requires Win98 or Win2k anyway.
425 if ( OsSupportsMultipleMonitors() ) gs_useDirectX = useDX;
61373fa8
WS
426#else
427 wxUnusedVar(useDX);
01c54165 428#endif
06efac1f
VZ
429}
430
01c54165 431// helper for GetFromPoint() and GetFromWindow()
8585e2b5
VZ
432static int DisplayFromHMONITOR(HMONITOR hmon)
433{
434 if ( hmon )
435 {
436 const size_t count = wxDisplay::GetCount();
a536e411 437
8585e2b5 438 for ( size_t n = 0; n < count; n++ )
a536e411 439 {
06efac1f 440 if ( hmon == (*gs_displays)[n].m_hmon )
8585e2b5 441 return n;
a536e411 442 }
a536e411 443 }
a536e411 444
8585e2b5 445 return wxNOT_FOUND;
a536e411
JS
446}
447
8585e2b5 448/* static */
a536e411
JS
449size_t wxDisplayBase::GetCount()
450{
01c54165
VZ
451 if ( !OsSupportsMultipleMonitors() ) return 1;
452
8585e2b5
VZ
453 InitDisplays();
454
6fcf77f4
RN
455 //RN: FIXME: This is wrong - the display info array should reload after every call
456 //to GetCount() - otherwise it will not be accurate.
457 //The user can change the number of displays in display properties/settings
2ad495fb 458 //after GetCount or similar is called and really mess this up...
6fcf77f4
RN
459 //wxASSERT_MSG( gs_displays->GetCount() == (size_t)::GetSystemMetrics(SM_CMONITORS),
460 // _T("So how many displays does this system have?") );
8585e2b5 461
06efac1f 462 return gs_displays->GetCount();
a536e411
JS
463}
464
8585e2b5 465/* static */
a536e411
JS
466int wxDisplayBase::GetFromPoint ( const wxPoint& pt )
467{
01c54165
VZ
468 if ( !OsSupportsMultipleMonitors() )
469 {
470 const wxSize size = wxGetDisplaySize();
471 if (pt.x >= 0 && pt.x < size.GetWidth() &&
472 pt.y >= 0 && pt.y < size.GetHeight())
473 {
474 return 0;
475 }
476 return wxNOT_FOUND;
477 }
478
a536e411
JS
479 POINT pt2;
480 pt2.x = pt.x;
481 pt2.y = pt.y;
482
01c54165 483 return DisplayFromHMONITOR(gs_MonitorFromPoint(pt2, MONITOR_DEFAULTTONULL));
8585e2b5 484}
a536e411 485
8585e2b5
VZ
486/* static */
487int wxDisplayBase::GetFromWindow(wxWindow *window)
488{
01c54165
VZ
489 if ( !OsSupportsMultipleMonitors() )
490 {
491 const wxRect r(window->GetRect());
492 const wxSize size = wxGetDisplaySize();
493 if (r.x < size.GetWidth() && r.x + r.width >= 0 &&
494 r.y < size.GetHeight() && r.y + r.height >= 0)
495 {
496 return 0;
497 }
498 return wxNOT_FOUND;
499 }
500
8585e2b5
VZ
501 return DisplayFromHMONITOR
502 (
01c54165 503 gs_MonitorFromWindow(GetHwndOf(window), MONITOR_DEFAULTTONULL)
8585e2b5
VZ
504 );
505}
506
06efac1f
VZ
507// ----------------------------------------------------------------------------
508// wxDisplay ctor/dtor
509// ----------------------------------------------------------------------------
510
8585e2b5
VZ
511wxDisplay::wxDisplay ( size_t n )
512 : wxDisplayBase ( n )
513{
01c54165
VZ
514 if ( !OsSupportsMultipleMonitors() ) return;
515
8585e2b5
VZ
516 // if we do this in ctor we won't have to call it from all the member
517 // functions
518 InitDisplays();
06efac1f 519
01c54165 520#ifdef HAVE_DDRAW_H
06efac1f
VZ
521 if ( gs_useDirectX )
522 {
523 wxDisplayInfo& dpyInfo = (*gs_displays)[n];
524
525 LPDIRECTDRAW2& pDD2 = dpyInfo.m_pDD2;
526 if ( !pDD2 )
527 {
528 if ( !gs_DirectDrawCreate )
529 {
530 // what to do??
531 return;
532 }
533
534 IDirectDraw *pDD;
535 HRESULT hr = (*gs_DirectDrawCreate)(&dpyInfo.m_guid, &pDD, NULL);
536
537 if ( FAILED(hr) || !pDD )
538 {
539 // what to do??
540 wxLogApiError(_T("DirectDrawCreate"), hr);
541 }
542 else // got IDirectDraw, we want IDirectDraw2
543 {
544 hr = pDD->QueryInterface(wxIID_IDirectDraw2, (void **)&pDD2);
545 if ( FAILED(hr) || !pDD2 )
546 {
547 wxLogApiError(_T("IDirectDraw::QueryInterface(IDD2)"), hr);
548 }
549
550 pDD->Release();
551 }
552 }
553 //else: DirectDraw object corresponding to our display already exists
554
555 // increment its ref count to account for Release() in dtor
556 //
557 // NB: pDD2 will be only really Release()d when gs_displays is
558 // destroyed which is ok as we don't want to recreate DD objects
559 // all the time
560 pDD2->AddRef();
561 }
01c54165 562#endif
06efac1f
VZ
563}
564
565wxDisplay::~wxDisplay()
566{
01c54165
VZ
567#ifdef HAVE_DDRAW_H
568 if ( !OsSupportsMultipleMonitors() ) return;
569
06efac1f
VZ
570 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
571
572 LPDIRECTDRAW2& pDD2 = dpyInfo.m_pDD2;
573 if ( pDD2 )
574 {
575 pDD2->Release();
576 }
01c54165 577#endif
06efac1f
VZ
578}
579
580// ----------------------------------------------------------------------------
581// wxDisplay simple accessors
582// ----------------------------------------------------------------------------
583
584bool wxDisplay::IsOk() const
585{
01c54165 586#ifdef HAVE_DDRAW_H
06efac1f
VZ
587 return m_index < GetCount() &&
588 (!gs_useDirectX || (*gs_displays)[m_index].m_pDD2);
01c54165
VZ
589#else
590 return m_index < GetCount();
591#endif
8585e2b5
VZ
592}
593
594wxRect wxDisplay::GetGeometry() const
595{
01c54165
VZ
596 if ( !OsSupportsMultipleMonitors() )
597 {
598 wxSize size = wxGetDisplaySize();
599 return wxRect(0, 0, size.GetWidth(), size.GetHeight());
600 }
601
06efac1f
VZ
602 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
603 wxRect& rect = dpyInfo.m_rect;
604 if ( !rect.width )
605 {
606 MONITORINFO monInfo;
607 wxZeroMemory(monInfo);
608 monInfo.cbSize = sizeof(monInfo);
609
01c54165 610 if ( !gs_GetMonitorInfo(dpyInfo.m_hmon, &monInfo) )
06efac1f
VZ
611 {
612 wxLogLastError(_T("GetMonitorInfo"));
613 }
614 else
615 {
616 wxCopyRECTToRect(monInfo.rcMonitor, rect);
617 }
618 }
619
620 return rect;
8585e2b5
VZ
621}
622
623wxString wxDisplay::GetName() const
624{
01c54165
VZ
625 if ( !OsSupportsMultipleMonitors() ) return wxT("");
626
06efac1f 627 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
8585e2b5 628 if ( dpyInfo.m_devName.empty() )
a536e411 629 {
8585e2b5
VZ
630 MONITORINFOEX monInfo;
631 wxZeroMemory(monInfo);
632 monInfo.cbSize = sizeof(monInfo);
633
f29cfd77
VS
634 // NB: Cast from MONITORINFOEX* to MONITORINFO* is done because
635 // Mingw headers - unlike the ones from Microsoft's Platform SDK -
636 // don't derive the former from the latter in C++ mode and so
637 // the pointer's type is not converted implicitly.
01c54165 638 if ( !gs_GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) )
8585e2b5
VZ
639 {
640 wxLogLastError(_T("GetMonitorInfo"));
641 }
642 else
643 {
644 dpyInfo.m_devName = monInfo.szDevice;
645 }
a536e411
JS
646 }
647
8585e2b5 648 return dpyInfo.m_devName;
a536e411
JS
649}
650
24d2b4f5
RN
651// ----------------------------------------------------------------------------
652// determine if this is the primary display
653// ----------------------------------------------------------------------------
654
655bool wxDisplay::IsPrimary() const
656{
01c54165
VZ
657 if ( !OsSupportsMultipleMonitors() ) return true;
658
24d2b4f5
RN
659 wxDisplayInfo& dpyInfo = (*gs_displays)[m_index];
660
661 MONITORINFOEX monInfo;
662 wxZeroMemory(monInfo);
663 monInfo.cbSize = sizeof(monInfo);
664
665 // NB: Cast from MONITORINFOEX* to MONITORINFO* is done because
666 // Mingw headers - unlike the ones from Microsoft's Platform SDK -
667 // don't derive the former from the latter in C++ mode and so
668 // the pointer's type is not converted implicitly.
01c54165 669 if ( !gs_GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) )
24d2b4f5
RN
670 {
671 wxLogLastError(_T("GetMonitorInfo"));
672 }
673
674 return (monInfo.dwFlags & MONITORINFOF_PRIMARY) == MONITORINFOF_PRIMARY;
675}
676
06efac1f
VZ
677// ----------------------------------------------------------------------------
678// video modes enumeration
679// ----------------------------------------------------------------------------
680
01c54165 681#ifdef HAVE_DDRAW_H
06efac1f 682wxArrayVideoModes
2eb10e2a 683wxDisplay::DoGetModesDirectX(const wxVideoMode& WXUNUSED(modeMatch)) const
06efac1f
VZ
684{
685 wxArrayVideoModes modes;
686
687 IDirectDraw2 *pDD = (*gs_displays)[m_index].m_pDD2;
688
689 if ( pDD )
690 {
691 HRESULT hr = pDD->EnumDisplayModes
692 (
693 DDEDM_REFRESHRATES,
694 NULL, // all modes (TODO: use modeMatch!)
695 &modes, // callback parameter
696 wxDDEnumModesCallback
697 );
698
699 if ( FAILED(hr) )
700 {
701 wxLogApiError(_T("IDirectDraw::EnumDisplayModes"), hr);
702 }
703 }
704
705 return modes;
706}
01c54165 707#endif
06efac1f
VZ
708
709wxArrayVideoModes
710wxDisplay::DoGetModesWindows(const wxVideoMode& modeMatch) const
a536e411 711{
8585e2b5
VZ
712 wxArrayVideoModes modes;
713
01c54165
VZ
714 // The first parameter of EnumDisplaySettings() must be NULL under Win95
715 // according to MSDN. The version of GetName() we implement for Win95
716 // returns an empty string.
717 const wxString name = GetName();
8585e2b5
VZ
718 const wxChar * const deviceName = name.empty() ? NULL : name.c_str();
719
720 DEVMODE dm;
01c54165
VZ
721 dm.dmSize = sizeof(dm);
722 dm.dmDriverExtra = 0;
8585e2b5
VZ
723 for ( int iModeNum = 0;
724 ::EnumDisplaySettings(deviceName, iModeNum, &dm);
725 iModeNum++ )
726 {
727 const wxVideoMode mode = ConvertToVideoMode(dm);
728 if ( mode.Matches(modeMatch) )
729 {
730 modes.Add(mode);
731 }
732 }
733
734 return modes;
a536e411
JS
735}
736
06efac1f
VZ
737wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& modeMatch) const
738{
01c54165 739#ifdef HAVE_DDRAW_H
06efac1f
VZ
740 return gs_useDirectX ? DoGetModesDirectX(modeMatch)
741 : DoGetModesWindows(modeMatch);
01c54165
VZ
742#else
743 return DoGetModesWindows(modeMatch);
744#endif
06efac1f
VZ
745}
746
8585e2b5 747wxVideoMode wxDisplay::GetCurrentMode() const
a536e411 748{
8585e2b5
VZ
749 wxVideoMode mode;
750
01c54165
VZ
751 // The first parameter of EnumDisplaySettings() must be NULL under Win95
752 // according to MSDN. The version of GetName() we implement for Win95
753 // returns an empty string.
754 const wxString name = GetName();
755 const wxChar * const deviceName = name.empty() ? NULL : name.c_str();
8585e2b5
VZ
756
757 DEVMODE dm;
01c54165
VZ
758 dm.dmSize = sizeof(dm);
759 dm.dmDriverExtra = 0;
760 if ( !::EnumDisplaySettings(deviceName, ENUM_CURRENT_SETTINGS, &dm) )
8585e2b5
VZ
761 {
762 wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
763 }
764 else
765 {
766 mode = ConvertToVideoMode(dm);
767 }
768
769 return mode;
a536e411
JS
770}
771
06efac1f
VZ
772// ----------------------------------------------------------------------------
773// video mode switching
774// ----------------------------------------------------------------------------
775
01c54165 776#ifdef HAVE_DDRAW_H
06efac1f
VZ
777bool wxDisplay::DoChangeModeDirectX(const wxVideoMode& mode)
778{
779 IDirectDraw2 *pDD = (*gs_displays)[m_index].m_pDD2;
780 if ( !pDD )
781 return false;
782
783 wxWindow *winTop = wxTheApp->GetTopWindow();
784 wxCHECK_MSG( winTop, false, _T("top level window required for DirectX") );
785
786 HRESULT hr = pDD->SetCooperativeLevel
787 (
788 GetHwndOf(winTop),
789 DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN
790 );
791 if ( FAILED(hr) )
792 {
793 wxLogApiError(_T("IDirectDraw::SetCooperativeLevel"), hr);
794
795 return false;
796 }
797
798 hr = pDD->SetDisplayMode(mode.w, mode.h, mode.bpp, mode.refresh, 0);
799 if ( FAILED(hr) )
800 {
801 wxLogApiError(_T("IDirectDraw::SetDisplayMode"), hr);
802
803 return false;
804 }
805
d71cc120 806
06efac1f
VZ
807 return true;
808}
01c54165 809#endif
06efac1f
VZ
810
811bool wxDisplay::DoChangeModeWindows(const wxVideoMode& mode)
a536e411 812{
8585e2b5 813 // prepare ChangeDisplaySettingsEx() parameters
61373fa8
WS
814 DEVMODE dm;
815 DEVMODE *pDevMode;
816
8585e2b5
VZ
817 int flags;
818
819 if ( mode == wxDefaultVideoMode )
820 {
821 // reset the video mode to default
822 pDevMode = NULL;
823 flags = 0;
824 }
825 else // change to the given mode
826 {
06efac1f 827 wxCHECK_MSG( mode.w && mode.h, false,
8585e2b5
VZ
828 _T("at least the width and height must be specified") );
829
830 wxZeroMemory(dm);
831 dm.dmSize = sizeof(dm);
01c54165 832 dm.dmDriverExtra = 0;
8585e2b5
VZ
833 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
834 dm.dmPelsWidth = mode.w;
835 dm.dmPelsHeight = mode.h;
836
837 if ( mode.bpp )
838 {
839 dm.dmFields |= DM_BITSPERPEL;
840 dm.dmBitsPerPel = mode.bpp;
841 }
842
843 if ( mode.refresh )
844 {
845 dm.dmFields |= DM_DISPLAYFREQUENCY;
846 dm.dmDisplayFrequency = mode.refresh;
847 }
848
849 pDevMode = &dm;
850
2ad495fb
WS
851#ifdef __WXWINCE__
852 flags = 0;
853#else // !__WXWINCE__
8585e2b5 854 flags = CDS_FULLSCREEN;
2ad495fb 855#endif // __WXWINCE__/!__WXWINCE__
8585e2b5
VZ
856 }
857
858
859 // get pointer to the function dynamically
860 //
861 // we're only called from the main thread, so it's ok to use static
862 // variable
863 static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx = NULL;
864 if ( !pfnChangeDisplaySettingsEx )
865 {
866 wxDynamicLibrary dllUser32(_T("user32.dll"));
867 if ( dllUser32.IsLoaded() )
868 {
869 pfnChangeDisplaySettingsEx = (ChangeDisplaySettingsEx_t)
870 dllUser32.GetSymbol(WINFUNC(ChangeDisplaySettingsEx));
871 }
872 //else: huh, no user32.dll??
873
2ad495fb 874#ifndef __WXWINCE__
8585e2b5
VZ
875 if ( !pfnChangeDisplaySettingsEx )
876 {
877 // we must be under Win95 and so there is no multiple monitors
878 // support anyhow
879 pfnChangeDisplaySettingsEx = ChangeDisplaySettingsExForWin95;
880 }
2ad495fb 881#endif // !__WXWINCE__
8585e2b5
VZ
882 }
883
884 // do change the mode
885 switch ( pfnChangeDisplaySettingsEx
886 (
887 GetName(), // display name
888 pDevMode, // dev mode or NULL to reset
889 NULL, // reserved
890 flags,
891 NULL // pointer to video parameters (not used)
892 ) )
893 {
894 case DISP_CHANGE_SUCCESSFUL:
895 // ok
920b9675
JS
896 {
897 // If we have a top-level, full-screen frame, emulate
898 // the DirectX behavior and resize it. This makes this
899 // API quite a bit easier to use.
900 wxWindow *winTop = wxTheApp->GetTopWindow();
901 wxFrame *frameTop = wxDynamicCast(winTop, wxFrame);
902 if (frameTop && frameTop->IsFullScreen())
903 {
904 wxVideoMode current = GetCurrentMode();
905 frameTop->SetClientSize(current.w, current.h);
906 }
907 }
06efac1f 908 return true;
8585e2b5
VZ
909
910 case DISP_CHANGE_BADMODE:
911 // don't complain about this, this is the only "expected" error
912 break;
913
914 default:
915 wxFAIL_MSG( _T("unexpected ChangeDisplaySettingsEx() return value") );
916 }
917
06efac1f
VZ
918 return false;
919}
920
921bool wxDisplay::ChangeMode(const wxVideoMode& mode)
922{
01c54165 923#ifdef HAVE_DDRAW_H
06efac1f
VZ
924 return gs_useDirectX ? DoChangeModeDirectX(mode)
925 : DoChangeModeWindows(mode);
01c54165
VZ
926#else
927 return DoChangeModeWindows(mode);
928#endif
a536e411
JS
929}
930
8585e2b5 931#endif // wxUSE_DISPLAY