Remove unused wxDisplay implementation using DirectDraw from wxMSW.
[wxWidgets.git] / src / msw / display.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/display.cpp
3 // Purpose: MSW Implementation of wxDisplay class
4 // Author: Royce Mitchell III, Vadim Zeitlin
5 // Modified by: Ryan Norton (IsPrimary override)
6 // Created: 06/21/02
7 // RCS-ID: $Id$
8 // Copyright: (c) wxWidgets team
9 // Copyright: (c) 2002-2006 wxWidgets team
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 // ===========================================================================
14 // declarations
15 // ===========================================================================
16
17 // ---------------------------------------------------------------------------
18 // headers
19 // ---------------------------------------------------------------------------
20
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23
24 #ifdef __BORLANDC__
25 #pragma hdrstop
26 #endif
27
28 #if wxUSE_DISPLAY
29
30 #include "wx/display.h"
31
32 #ifndef WX_PRECOMP
33 #include "wx/dynarray.h"
34 #include "wx/app.h"
35 #include "wx/frame.h"
36 #endif
37
38 #include "wx/dynload.h"
39 #include "wx/sysopt.h"
40
41 #include "wx/display_impl.h"
42 #include "wx/msw/wrapwin.h"
43 #include "wx/msw/missing.h"
44 #include "wx/msw/private.h"
45
46 #ifndef __WXWINCE__
47 // Older versions of windef.h don't define HMONITOR. Unfortunately, we
48 // can't directly test whether HMONITOR is defined or not in windef.h as
49 // it's not a macro but a typedef, so we test for an unrelated symbol which
50 // is only defined in winuser.h if WINVER >= 0x0500
51 #if !defined(HMONITOR_DECLARED) && !defined(MNS_NOCHECK)
52 DECLARE_HANDLE(HMONITOR);
53 typedef BOOL(CALLBACK * MONITORENUMPROC )(HMONITOR, HDC, LPRECT, LPARAM);
54 typedef struct tagMONITORINFO
55 {
56 DWORD cbSize;
57 RECT rcMonitor;
58 RECT rcWork;
59 DWORD dwFlags;
60 } MONITORINFO, *LPMONITORINFO;
61 typedef struct tagMONITORINFOEX : public tagMONITORINFO
62 {
63 TCHAR szDevice[CCHDEVICENAME];
64 } MONITORINFOEX, *LPMONITORINFOEX;
65 #define MONITOR_DEFAULTTONULL 0x00000000
66 #define MONITOR_DEFAULTTOPRIMARY 0x00000001
67 #define MONITOR_DEFAULTTONEAREST 0x00000002
68 #define MONITORINFOF_PRIMARY 0x00000001
69 #define HMONITOR_DECLARED
70 #endif
71 #endif // !__WXWINCE__
72
73 // display functions are found in different DLLs under WinCE and normal Win32
74 #ifdef __WXWINCE__
75 static const wxChar displayDllName[] = wxT("coredll.dll");
76 #else
77 static const wxChar displayDllName[] = wxT("user32.dll");
78 #endif
79
80 // ----------------------------------------------------------------------------
81 // typedefs for dynamically loaded Windows functions
82 // ----------------------------------------------------------------------------
83
84 typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName,
85 LPDEVMODE lpDevMode,
86 HWND hwnd,
87 DWORD dwFlags,
88 LPVOID lParam);
89
90 typedef BOOL (WINAPI *EnumDisplayMonitors_t)(HDC,LPCRECT,MONITORENUMPROC,LPARAM);
91 typedef HMONITOR (WINAPI *MonitorFromPoint_t)(POINT,DWORD);
92 typedef HMONITOR (WINAPI *MonitorFromWindow_t)(HWND,DWORD);
93 typedef BOOL (WINAPI *GetMonitorInfo_t)(HMONITOR,LPMONITORINFO);
94
95 #ifndef __WXWINCE__
96 // emulation of ChangeDisplaySettingsEx() for Win95
97 LONG WINAPI ChangeDisplaySettingsExForWin95(LPCTSTR WXUNUSED(lpszDeviceName),
98 LPDEVMODE lpDevMode,
99 HWND WXUNUSED(hwnd),
100 DWORD dwFlags,
101 LPVOID WXUNUSED(lParam))
102 {
103 return ::ChangeDisplaySettings(lpDevMode, dwFlags);
104 }
105 #endif // !__WXWINCE__
106
107 // ----------------------------------------------------------------------------
108 // display information classes
109 // ----------------------------------------------------------------------------
110
111 struct wxDisplayInfo
112 {
113 wxDisplayInfo(HMONITOR hmon = NULL)
114 {
115 m_hmon = hmon;
116 m_flags = (DWORD)-1;
117 }
118
119 virtual ~wxDisplayInfo() { }
120
121
122 // use GetMonitorInfo() to fill in all of our fields if needed (i.e. if it
123 // hadn't been done before)
124 void Initialize();
125
126
127 // handle of this monitor used by MonitorXXX() functions, never NULL
128 HMONITOR m_hmon;
129
130 // the entire area of this monitor in virtual screen coordinates
131 wxRect m_rect;
132
133 // the work or client area, i.e. the area available for the normal windows
134 wxRect m_rectClient;
135
136 // the display device name for this monitor, empty initially and retrieved
137 // on demand by DoGetName()
138 wxString m_devName;
139
140 // the flags of this monitor, also used as initialization marker: if this
141 // is -1, GetMonitorInfo() hadn't been called yet
142 DWORD m_flags;
143 };
144
145 WX_DEFINE_ARRAY_PTR(wxDisplayInfo *, wxDisplayInfoArray);
146
147 // ----------------------------------------------------------------------------
148 // common base class for all Win32 wxDisplayImpl versions
149 // ----------------------------------------------------------------------------
150
151 class wxDisplayImplWin32Base : public wxDisplayImpl
152 {
153 public:
154 wxDisplayImplWin32Base(unsigned n, wxDisplayInfo& info)
155 : wxDisplayImpl(n),
156 m_info(info)
157 {
158 }
159
160 virtual wxRect GetGeometry() const;
161 virtual wxRect GetClientArea() const;
162 virtual wxString GetName() const;
163 virtual bool IsPrimary() const;
164
165 virtual wxVideoMode GetCurrentMode() const;
166
167 protected:
168 // convert a DEVMODE to our wxVideoMode
169 static wxVideoMode ConvertToVideoMode(const DEVMODE& dm)
170 {
171 // note that dmDisplayFrequency may be 0 or 1 meaning "standard one"
172 // and although 0 is ok for us we don't want to return modes with 1hz
173 // refresh
174 return wxVideoMode(dm.dmPelsWidth,
175 dm.dmPelsHeight,
176 dm.dmBitsPerPel,
177 dm.dmDisplayFrequency > 1 ? dm.dmDisplayFrequency : 0);
178 }
179
180 wxDisplayInfo& m_info;
181 };
182
183 // ----------------------------------------------------------------------------
184 // common base class for all Win32 wxDisplayFactory versions
185 // ----------------------------------------------------------------------------
186
187 // functions dynamically bound by wxDisplayFactoryWin32Base::Initialize()
188 static MonitorFromPoint_t gs_MonitorFromPoint = NULL;
189 static MonitorFromWindow_t gs_MonitorFromWindow = NULL;
190 static GetMonitorInfo_t gs_GetMonitorInfo = NULL;
191
192 class wxDisplayFactoryWin32Base : public wxDisplayFactory
193 {
194 public:
195 virtual ~wxDisplayFactoryWin32Base();
196
197 bool IsOk() const { return !m_displays.empty(); }
198
199 virtual unsigned GetCount() { return unsigned(m_displays.size()); }
200 virtual int GetFromPoint(const wxPoint& pt);
201 virtual int GetFromWindow(const wxWindow *window);
202
203 protected:
204 // ctor checks if the current system supports multimon API and dynamically
205 // bind the functions we need if this is the case and sets
206 // ms_supportsMultimon if they're available
207 wxDisplayFactoryWin32Base();
208
209 // delete all m_displays elements: can be called from the derived class
210 // dtor if it is important to do this before destroying it,
211 // otherwise will be done by our dtor
212 void Clear();
213
214 // find the monitor corresponding to the given handle, return wxNOT_FOUND
215 // if not found
216 int FindDisplayFromHMONITOR(HMONITOR hmon) const;
217
218
219 // flag indicating whether gs_MonitorXXX functions are available
220 static int ms_supportsMultimon;
221
222 // the array containing information about all available displays, should be
223 // filled by the derived class ctors
224 wxDisplayInfoArray m_displays;
225
226
227 wxDECLARE_NO_COPY_CLASS(wxDisplayFactoryWin32Base);
228 };
229
230 // ----------------------------------------------------------------------------
231 // wxDisplay implementation using Windows multi-monitor support functions
232 // ----------------------------------------------------------------------------
233
234 class wxDisplayImplMultimon : public wxDisplayImplWin32Base
235 {
236 public:
237 wxDisplayImplMultimon(unsigned n, wxDisplayInfo& info)
238 : wxDisplayImplWin32Base(n, info)
239 {
240 }
241
242 virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
243 virtual bool ChangeMode(const wxVideoMode& mode);
244
245 private:
246 wxDECLARE_NO_COPY_CLASS(wxDisplayImplMultimon);
247 };
248
249 class wxDisplayFactoryMultimon : public wxDisplayFactoryWin32Base
250 {
251 public:
252 wxDisplayFactoryMultimon();
253
254 virtual wxDisplayImpl *CreateDisplay(unsigned n);
255
256 private:
257 // EnumDisplayMonitors() callback
258 static BOOL CALLBACK MultimonEnumProc(HMONITOR hMonitor,
259 HDC hdcMonitor,
260 LPRECT lprcMonitor,
261 LPARAM dwData);
262
263 // add a monitor description to m_displays array
264 void AddDisplay(HMONITOR hMonitor, LPRECT lprcMonitor);
265 };
266
267
268 // ============================================================================
269 // common classes implementation
270 // ============================================================================
271
272 // ----------------------------------------------------------------------------
273 // wxDisplay
274 // ----------------------------------------------------------------------------
275
276 /* static */ wxDisplayFactory *wxDisplay::CreateFactory()
277 {
278 wxDisplayFactoryMultimon *factoryMM = new wxDisplayFactoryMultimon;
279
280 if ( factoryMM->IsOk() )
281 return factoryMM;
282
283 delete factoryMM;
284
285 // finally fall back to a stub implementation if all else failed (Win95?)
286 return new wxDisplayFactorySingle;
287 }
288
289
290 // ----------------------------------------------------------------------------
291 // wxDisplayInfo
292 // ----------------------------------------------------------------------------
293
294 void wxDisplayInfo::Initialize()
295 {
296 if ( m_flags == (DWORD)-1 )
297 {
298 WinStruct<MONITORINFOEX> monInfo;
299 if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) )
300 {
301 wxLogLastError(wxT("GetMonitorInfo"));
302 m_flags = 0;
303 return;
304 }
305
306 wxCopyRECTToRect(monInfo.rcMonitor, m_rect);
307 wxCopyRECTToRect(monInfo.rcWork, m_rectClient);
308 m_devName = monInfo.szDevice;
309 m_flags = monInfo.dwFlags;
310 }
311 }
312
313 // ----------------------------------------------------------------------------
314 // wxDisplayImplWin32Base
315 // ----------------------------------------------------------------------------
316
317 wxRect wxDisplayImplWin32Base::GetGeometry() const
318 {
319 if ( m_info.m_rect.IsEmpty() )
320 m_info.Initialize();
321
322 return m_info.m_rect;
323 }
324
325 wxRect wxDisplayImplWin32Base::GetClientArea() const
326 {
327 if ( m_info.m_rectClient.IsEmpty() )
328 m_info.Initialize();
329
330 return m_info.m_rectClient;
331 }
332
333 wxString wxDisplayImplWin32Base::GetName() const
334 {
335 if ( m_info.m_devName.empty() )
336 m_info.Initialize();
337
338 return m_info.m_devName;
339 }
340
341 bool wxDisplayImplWin32Base::IsPrimary() const
342 {
343 if ( m_info.m_flags == (DWORD)-1 )
344 m_info.Initialize();
345
346 return (m_info.m_flags & MONITORINFOF_PRIMARY) != 0;
347 }
348
349 wxVideoMode wxDisplayImplWin32Base::GetCurrentMode() const
350 {
351 wxVideoMode mode;
352
353 // The first parameter of EnumDisplaySettings() must be NULL under Win95
354 // according to MSDN. The version of GetName() we implement for Win95
355 // returns an empty string.
356 const wxString name = GetName();
357 const wxChar * const deviceName = name.empty()
358 ? (const wxChar*)NULL
359 : (const wxChar*)name.c_str();
360
361 DEVMODE dm;
362 dm.dmSize = sizeof(dm);
363 dm.dmDriverExtra = 0;
364 if ( !::EnumDisplaySettings(deviceName, ENUM_CURRENT_SETTINGS, &dm) )
365 {
366 wxLogLastError(wxT("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
367 }
368 else
369 {
370 mode = ConvertToVideoMode(dm);
371 }
372
373 return mode;
374 }
375
376 // ----------------------------------------------------------------------------
377 // wxDisplayFactoryWin32Base
378 // ----------------------------------------------------------------------------
379
380 int wxDisplayFactoryWin32Base::ms_supportsMultimon = -1;
381
382 wxDisplayFactoryWin32Base::wxDisplayFactoryWin32Base()
383 {
384 if ( ms_supportsMultimon == -1 )
385 {
386 ms_supportsMultimon = 0;
387
388 wxDynamicLibrary dllDisplay(displayDllName, wxDL_VERBATIM | wxDL_QUIET);
389
390 if ( (wxDL_INIT_FUNC(gs_, MonitorFromPoint, dllDisplay)) == NULL ||
391 (wxDL_INIT_FUNC(gs_, MonitorFromWindow, dllDisplay)) == NULL ||
392 (wxDL_INIT_FUNC_AW(gs_, GetMonitorInfo, dllDisplay)) == NULL )
393 return;
394
395 ms_supportsMultimon = 1;
396
397 // we can safely let dllDisplay go out of scope, the DLL itself will
398 // still remain loaded as all programs link to it statically anyhow
399 }
400 }
401
402 void wxDisplayFactoryWin32Base::Clear()
403 {
404 WX_CLEAR_ARRAY(m_displays);
405 }
406
407 wxDisplayFactoryWin32Base::~wxDisplayFactoryWin32Base()
408 {
409 Clear();
410 }
411
412 // helper for GetFromPoint() and GetFromWindow()
413 int wxDisplayFactoryWin32Base::FindDisplayFromHMONITOR(HMONITOR hmon) const
414 {
415 if ( hmon )
416 {
417 const size_t count = m_displays.size();
418 for ( size_t n = 0; n < count; n++ )
419 {
420 if ( hmon == m_displays[n]->m_hmon )
421 return n;
422 }
423 }
424
425 return wxNOT_FOUND;
426 }
427
428 int wxDisplayFactoryWin32Base::GetFromPoint(const wxPoint& pt)
429 {
430 POINT pt2;
431 pt2.x = pt.x;
432 pt2.y = pt.y;
433
434 return FindDisplayFromHMONITOR(gs_MonitorFromPoint(pt2,
435 MONITOR_DEFAULTTONULL));
436 }
437
438 int wxDisplayFactoryWin32Base::GetFromWindow(const wxWindow *window)
439 {
440 return FindDisplayFromHMONITOR(gs_MonitorFromWindow(GetHwndOf(window),
441 MONITOR_DEFAULTTONULL));
442 }
443
444 // ============================================================================
445 // wxDisplay implementation using Win32 multimon API
446 // ============================================================================
447
448 // ----------------------------------------------------------------------------
449 // wxDisplayFactoryMultimon initialization
450 // ----------------------------------------------------------------------------
451
452 wxDisplayFactoryMultimon::wxDisplayFactoryMultimon()
453 {
454 if ( !ms_supportsMultimon )
455 return;
456
457 // look up EnumDisplayMonitors()
458 EnumDisplayMonitors_t pfnEnumDisplayMonitors;
459 {
460 wxDynamicLibrary dllDisplay(displayDllName, wxDL_VERBATIM | wxDL_QUIET);
461 if ( (wxDL_INIT_FUNC(pfn, EnumDisplayMonitors, dllDisplay)) == NULL )
462 return;
463 }
464
465 // enumerate all displays
466 if ( !pfnEnumDisplayMonitors(NULL, NULL, MultimonEnumProc, (LPARAM)this) )
467 {
468 wxLogLastError(wxT("EnumDisplayMonitors"));
469 }
470 }
471
472 /* static */
473 BOOL CALLBACK
474 wxDisplayFactoryMultimon::MultimonEnumProc(
475 HMONITOR hMonitor, // handle to display monitor
476 HDC WXUNUSED(hdcMonitor), // handle to monitor-appropriate device context
477 LPRECT lprcMonitor, // pointer to monitor intersection rectangle
478 LPARAM dwData // data passed from EnumDisplayMonitors (this)
479 )
480 {
481 wxDisplayFactoryMultimon *const self = (wxDisplayFactoryMultimon *)dwData;
482 self->AddDisplay(hMonitor, lprcMonitor);
483
484 // continue the enumeration
485 return TRUE;
486 }
487
488 // ----------------------------------------------------------------------------
489 // wxDisplayFactoryMultimon helper functions
490 // ----------------------------------------------------------------------------
491
492 void wxDisplayFactoryMultimon::AddDisplay(HMONITOR hMonitor, LPRECT lprcMonitor)
493 {
494 wxDisplayInfo *info = new wxDisplayInfo(hMonitor);
495
496 // we also store the display geometry
497 info->m_rect = wxRect(lprcMonitor->left, lprcMonitor->top,
498 lprcMonitor->right - lprcMonitor->left,
499 lprcMonitor->bottom - lprcMonitor->top);
500
501 // now add this monitor to the array
502 m_displays.Add(info);
503 }
504
505 // ----------------------------------------------------------------------------
506 // wxDisplayFactoryMultimon inherited pure virtuals implementation
507 // ----------------------------------------------------------------------------
508
509 wxDisplayImpl *wxDisplayFactoryMultimon::CreateDisplay(unsigned n)
510 {
511 wxCHECK_MSG( n < m_displays.size(), NULL, wxT("invalid display index") );
512
513 return new wxDisplayImplMultimon(n, *(m_displays[n]));
514 }
515
516 // ----------------------------------------------------------------------------
517 // wxDisplayImplMultimon implementation
518 // ----------------------------------------------------------------------------
519
520 wxArrayVideoModes
521 wxDisplayImplMultimon::GetModes(const wxVideoMode& modeMatch) const
522 {
523 wxArrayVideoModes modes;
524
525 // The first parameter of EnumDisplaySettings() must be NULL under Win95
526 // according to MSDN. The version of GetName() we implement for Win95
527 // returns an empty string.
528 const wxString name = GetName();
529 const wxChar * const deviceName = name.empty()
530 ? (const wxChar*)NULL
531 : (const wxChar*)name.c_str();
532
533 DEVMODE dm;
534 dm.dmSize = sizeof(dm);
535 dm.dmDriverExtra = 0;
536 for ( int iModeNum = 0;
537 ::EnumDisplaySettings(deviceName, iModeNum, &dm);
538 iModeNum++ )
539 {
540 const wxVideoMode mode = ConvertToVideoMode(dm);
541 if ( mode.Matches(modeMatch) )
542 {
543 modes.Add(mode);
544 }
545 }
546
547 return modes;
548 }
549
550 bool wxDisplayImplMultimon::ChangeMode(const wxVideoMode& mode)
551 {
552 // prepare ChangeDisplaySettingsEx() parameters
553 DEVMODE dm;
554 DEVMODE *pDevMode;
555
556 int flags;
557
558 if ( mode == wxDefaultVideoMode )
559 {
560 // reset the video mode to default
561 pDevMode = NULL;
562 flags = 0;
563 }
564 else // change to the given mode
565 {
566 wxCHECK_MSG( mode.GetWidth() && mode.GetHeight(), false,
567 wxT("at least the width and height must be specified") );
568
569 wxZeroMemory(dm);
570 dm.dmSize = sizeof(dm);
571 dm.dmDriverExtra = 0;
572 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
573 dm.dmPelsWidth = mode.GetWidth();
574 dm.dmPelsHeight = mode.GetHeight();
575
576 if ( mode.GetDepth() )
577 {
578 dm.dmFields |= DM_BITSPERPEL;
579 dm.dmBitsPerPel = mode.GetDepth();
580 }
581
582 if ( mode.GetRefresh() )
583 {
584 dm.dmFields |= DM_DISPLAYFREQUENCY;
585 dm.dmDisplayFrequency = mode.GetRefresh();
586 }
587
588 pDevMode = &dm;
589
590 #ifdef __WXWINCE__
591 flags = 0;
592 #else // !__WXWINCE__
593 flags = CDS_FULLSCREEN;
594 #endif // __WXWINCE__/!__WXWINCE__
595 }
596
597
598 // get pointer to the function dynamically
599 //
600 // we're only called from the main thread, so it's ok to use static
601 // variable
602 static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx = NULL;
603 if ( !pfnChangeDisplaySettingsEx )
604 {
605 wxDynamicLibrary dllDisplay(displayDllName, wxDL_VERBATIM | wxDL_QUIET);
606 if ( dllDisplay.IsLoaded() )
607 {
608 wxDL_INIT_FUNC_AW(pfn, ChangeDisplaySettingsEx, dllDisplay);
609 }
610 //else: huh, no this DLL must always be present, what's going on??
611
612 #ifndef __WXWINCE__
613 if ( !pfnChangeDisplaySettingsEx )
614 {
615 // we must be under Win95 and so there is no multiple monitors
616 // support anyhow
617 pfnChangeDisplaySettingsEx = ChangeDisplaySettingsExForWin95;
618 }
619 #endif // !__WXWINCE__
620 }
621
622 // do change the mode
623 switch ( pfnChangeDisplaySettingsEx
624 (
625 GetName().wx_str(), // display name
626 pDevMode, // dev mode or NULL to reset
627 NULL, // reserved
628 flags,
629 NULL // pointer to video parameters (not used)
630 ) )
631 {
632 case DISP_CHANGE_SUCCESSFUL:
633 // ok
634 {
635 // If we have a top-level, full-screen frame, emulate
636 // the DirectX behavior and resize it. This makes this
637 // API quite a bit easier to use.
638 wxWindow *winTop = wxTheApp->GetTopWindow();
639 wxFrame *frameTop = wxDynamicCast(winTop, wxFrame);
640 if (frameTop && frameTop->IsFullScreen())
641 {
642 wxVideoMode current = GetCurrentMode();
643 frameTop->SetClientSize(current.GetWidth(), current.GetHeight());
644 }
645 }
646 return true;
647
648 case DISP_CHANGE_BADMODE:
649 // don't complain about this, this is the only "expected" error
650 break;
651
652 default:
653 wxFAIL_MSG( wxT("unexpected ChangeDisplaySettingsEx() return value") );
654 }
655
656 return false;
657 }
658
659 #endif // wxUSE_DISPLAY