]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/display.cpp
Initialize all fields of struct tm used by wxDateTime::Format().
[wxWidgets.git] / src / msw / display.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/display.cpp
3// Purpose: MSW Implementation of wxDisplay class
4// Author: Royce Mitchell III, Vadim Zeitlin
5// Modified by: Ryan Norton (IsPrimary override)
6// Created: 06/21/02
7// RCS-ID: $Id$
8// Copyright: (c) wxWidgets team
9// Copyright: (c) 2002-2006 wxWidgets team
10// Licence: wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
13// ===========================================================================
14// declarations
15// ===========================================================================
16
17// ---------------------------------------------------------------------------
18// headers
19// ---------------------------------------------------------------------------
20
21// For compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23
24#ifdef __BORLANDC__
25 #pragma hdrstop
26#endif
27
28#if wxUSE_DISPLAY
29
30#include "wx/display.h"
31
32#ifndef WX_PRECOMP
33 #include "wx/dynarray.h"
34 #include "wx/app.h"
35 #include "wx/frame.h"
36#endif
37
38#include "wx/dynload.h"
39#include "wx/sysopt.h"
40
41#include "wx/display_impl.h"
42#include "wx/msw/wrapwin.h"
43#include "wx/msw/missing.h"
44#include "wx/msw/private.h"
45
46#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__
75static const wxChar displayDllName[] = wxT("coredll.dll");
76#else
77static const wxChar displayDllName[] = wxT("user32.dll");
78#endif
79
80// ----------------------------------------------------------------------------
81// typedefs for dynamically loaded Windows functions
82// ----------------------------------------------------------------------------
83
84typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName,
85 LPDEVMODE lpDevMode,
86 HWND hwnd,
87 DWORD dwFlags,
88 LPVOID lParam);
89
90typedef BOOL (WINAPI *EnumDisplayMonitors_t)(HDC,LPCRECT,MONITORENUMPROC,LPARAM);
91typedef HMONITOR (WINAPI *MonitorFromPoint_t)(POINT,DWORD);
92typedef HMONITOR (WINAPI *MonitorFromWindow_t)(HWND,DWORD);
93typedef BOOL (WINAPI *GetMonitorInfo_t)(HMONITOR,LPMONITORINFO);
94
95#ifndef __WXWINCE__
96// emulation of ChangeDisplaySettingsEx() for Win95
97LONG 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
111struct 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
145WX_DEFINE_ARRAY_PTR(wxDisplayInfo *, wxDisplayInfoArray);
146
147// ----------------------------------------------------------------------------
148// common base class for all Win32 wxDisplayImpl versions
149// ----------------------------------------------------------------------------
150
151class wxDisplayImplWin32Base : public wxDisplayImpl
152{
153public:
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
167protected:
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()
188static MonitorFromPoint_t gs_MonitorFromPoint = NULL;
189static MonitorFromWindow_t gs_MonitorFromWindow = NULL;
190static GetMonitorInfo_t gs_GetMonitorInfo = NULL;
191
192class wxDisplayFactoryWin32Base : public wxDisplayFactory
193{
194public:
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
203protected:
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
234class wxDisplayImplMultimon : public wxDisplayImplWin32Base
235{
236public:
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
245private:
246 wxDECLARE_NO_COPY_CLASS(wxDisplayImplMultimon);
247};
248
249class wxDisplayFactoryMultimon : public wxDisplayFactoryWin32Base
250{
251public:
252 wxDisplayFactoryMultimon();
253
254 virtual wxDisplayImpl *CreateDisplay(unsigned n);
255
256private:
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
294void 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
317wxRect wxDisplayImplWin32Base::GetGeometry() const
318{
319 if ( m_info.m_rect.IsEmpty() )
320 m_info.Initialize();
321
322 return m_info.m_rect;
323}
324
325wxRect wxDisplayImplWin32Base::GetClientArea() const
326{
327 if ( m_info.m_rectClient.IsEmpty() )
328 m_info.Initialize();
329
330 return m_info.m_rectClient;
331}
332
333wxString wxDisplayImplWin32Base::GetName() const
334{
335 if ( m_info.m_devName.empty() )
336 m_info.Initialize();
337
338 return m_info.m_devName;
339}
340
341bool 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
349wxVideoMode 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
380int wxDisplayFactoryWin32Base::ms_supportsMultimon = -1;
381
382wxDisplayFactoryWin32Base::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
402void wxDisplayFactoryWin32Base::Clear()
403{
404 WX_CLEAR_ARRAY(m_displays);
405}
406
407wxDisplayFactoryWin32Base::~wxDisplayFactoryWin32Base()
408{
409 Clear();
410}
411
412// helper for GetFromPoint() and GetFromWindow()
413int 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
428int 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
438int 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
452wxDisplayFactoryMultimon::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 */
473BOOL CALLBACK
474wxDisplayFactoryMultimon::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
492void 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
509wxDisplayImpl *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
520wxArrayVideoModes
521wxDisplayImplMultimon::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
550bool 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