]> git.saurik.com Git - wxWidgets.git/blame - src/msw/display.cpp
Modified vc.t according to last changes to makefile.vc, and regenerated
[wxWidgets.git] / src / msw / display.cpp
CommitLineData
a536e411
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: display.cpp
3// Purpose: MSW Implementation of wxDisplay class
4// Author: Royce Mitchell III
5// Modified by:
6// Created: 06/21/02
7// RCS-ID: $Id$
8// Copyright: (c) wxWindows team
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "display.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#if wxUSE_DISPLAY
32
33#ifndef WX_PRECOMP
34 #include "wx/dynarray.h"
35#endif
36
8585e2b5
VZ
37#include "wx/dynload.h"
38
a536e411
JS
39#include "wx/display.h"
40
41// the following define is necessary to access the multi-monitor function
42// declarations in a manner safe to use w/ Windows 95
a536e411 43#define COMPILE_MULTIMON_STUBS
8585e2b5
VZ
44
45// if you don't have multimon.h you can download the file from:
46//
47// http://www.microsoft.com/msj/0697/monitor/monitortextfigs.htm#fig4
48//
49
50#ifdef _MSC_VER
51 // as (m)any standard header, this one doesn't compile without warnings
52 // with VC++ 6 <sigh>
53 #pragma warning(disable:4706)
a536e411
JS
54#endif
55
8585e2b5 56#include <multimon.h>
a536e411 57
8585e2b5
VZ
58#ifdef _MSC_VER
59 #pragma warning(default:4706)
60#endif
a536e411 61
8585e2b5
VZ
62#ifdef _UNICODE
63 #define MAKE_WFUNC(x) #x "W"
64 #define WINFUNC(x) L ## MAKE_WFUNC(x)
65#else
66 #define WINFUNC(x) #x "A"
67#endif
a536e411
JS
68
69// ----------------------------------------------------------------------------
8585e2b5 70// typedefs
a536e411
JS
71// ----------------------------------------------------------------------------
72
8585e2b5
VZ
73typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName,
74 LPDEVMODE lpDevMode,
75 HWND hwnd,
76 DWORD dwFlags,
77 LPVOID lParam);
a536e411 78
8585e2b5
VZ
79// ----------------------------------------------------------------------------
80// private classes
81// ----------------------------------------------------------------------------
a536e411 82
8585e2b5 83class wxDisplayInfo
a536e411
JS
84{
85public:
8585e2b5
VZ
86 // handle of this monitor used by MonitorXXX() functions, never NULL
87 HMONITOR m_hmon;
88
89 // the entire area of this monitor in virtual screen coordinates
a536e411 90 wxRect m_rect;
8585e2b5
VZ
91
92 // the display device name for this monitor, empty initially and retrieved
93 // on demand by DoGetName()
94 wxString m_devName;
95
96 wxDisplayInfo() { m_hmon = NULL; }
a536e411
JS
97};
98
8585e2b5
VZ
99WX_DECLARE_OBJARRAY(wxDisplayInfo, wxDisplayInfoArray);
100#include "wx/arrimpl.cpp"
101WX_DEFINE_OBJARRAY(wxDisplayInfoArray);
a536e411 102
8585e2b5
VZ
103// this is not really MT-unsafe as wxDisplay is only going to be used from the
104// main thread, i.e. we consider that it's a GUI class and so don't protect it
105static wxDisplayInfoArray *g_displays = NULL;
106
107
108// this module is used to cleanup g_displays array
109class wxDisplayModule : public wxModule
110{
111public:
112 virtual bool OnInit() { return TRUE; }
113 virtual void OnExit();
114
115 DECLARE_DYNAMIC_CLASS(wxDisplayModule)
116};
117
118IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule)
a536e411
JS
119
120// ===========================================================================
121// implementation
122// ===========================================================================
123
8585e2b5
VZ
124// ----------------------------------------------------------------------------
125// local functions
126// ----------------------------------------------------------------------------
127
128static BOOL CALLBACK wxmswMonitorEnumProc (
a536e411 129 HMONITOR hMonitor, // handle to display monitor
8585e2b5 130 HDC hdcMonitor, // handle to monitor-appropriate device context (NULL)
a536e411 131 LPRECT lprcMonitor, // pointer to monitor intersection rectangle
8585e2b5 132 LPARAM dwData // data passed from EnumDisplayMonitors (unused)
a536e411
JS
133)
134{
8585e2b5
VZ
135 wxDisplayInfo* info = new wxDisplayInfo();
136
137 // we need hMonitor to be able to map display id to it which is needed for
138 // MonitorXXX() functions, in particular MonitorFromPoint()
a536e411 139 info->m_hmon = hMonitor;
8585e2b5
VZ
140
141 // we also store the display geometry
a536e411
JS
142 info->m_rect.SetX ( lprcMonitor->left );
143 info->m_rect.SetY ( lprcMonitor->top );
144 info->m_rect.SetWidth ( lprcMonitor->right - lprcMonitor->left );
145 info->m_rect.SetHeight ( lprcMonitor->bottom - lprcMonitor->top );
8585e2b5 146
a536e411 147 // now add this monitor to the array
8585e2b5 148 g_displays->Add(info);
a536e411 149
8585e2b5
VZ
150 // continue the enumeration
151 return TRUE;
a536e411
JS
152}
153
8585e2b5
VZ
154// this function must be called before accessing g_displays array as it
155// creates and initializes it
156static void InitDisplays()
a536e411 157{
8585e2b5
VZ
158 if ( g_displays )
159 return;
a536e411 160
8585e2b5 161 g_displays = new wxDisplayInfoArray();
a536e411 162
8585e2b5
VZ
163 // enumerate all displays
164 if ( !::EnumDisplayMonitors(NULL, NULL, wxmswMonitorEnumProc, 0) )
a536e411 165 {
8585e2b5
VZ
166 wxLogLastError(wxT("EnumDisplayMonitors"));
167
168 // TODO: still create at least one (valid) entry in g_displays for the
169 // primary display!
a536e411 170 }
8585e2b5 171}
a536e411 172
8585e2b5
VZ
173// convert a DEVMODE to our wxVideoMode
174wxVideoMode ConvertToVideoMode(const DEVMODE& dm)
175{
176 // note that dmDisplayFrequency may be 0 or 1 meaning "standard one" and
177 // although 0 is ok for us we don't want to return modes with 1hz refresh
178 return wxVideoMode(dm.dmPelsWidth,
179 dm.dmPelsHeight,
180 dm.dmBitsPerPel,
181 dm.dmDisplayFrequency > 1 ? dm.dmDisplayFrequency : 0);
182}
a536e411 183
8585e2b5
VZ
184// emulation of ChangeDisplaySettingsEx() for Win95
185LONG WINAPI ChangeDisplaySettingsExForWin95(LPCTSTR WXUNUSED(lpszDeviceName),
186 LPDEVMODE lpDevMode,
187 HWND WXUNUSED(hwnd),
188 DWORD dwFlags,
189 LPVOID WXUNUSED(lParam))
190{
191 return ::ChangeDisplaySettings(lpDevMode, dwFlags);
192}
a536e411 193
8585e2b5
VZ
194// ----------------------------------------------------------------------------
195// wxDisplayModule
196// ----------------------------------------------------------------------------
a536e411 197
8585e2b5
VZ
198void wxDisplayModule::OnExit()
199{
200 delete g_displays;
201}
a536e411 202
8585e2b5
VZ
203// ---------------------------------------------------------------------------
204// wxDisplay
205// ---------------------------------------------------------------------------
a536e411 206
8585e2b5
VZ
207// helper of GetFromPoint() and GetFromWindow()
208static int DisplayFromHMONITOR(HMONITOR hmon)
209{
210 if ( hmon )
211 {
212 const size_t count = wxDisplay::GetCount();
a536e411 213
8585e2b5 214 for ( size_t n = 0; n < count; n++ )
a536e411 215 {
8585e2b5
VZ
216 if ( hmon == (*g_displays)[n].m_hmon )
217 return n;
a536e411 218 }
a536e411 219 }
a536e411 220
8585e2b5 221 return wxNOT_FOUND;
a536e411
JS
222}
223
8585e2b5 224/* static */
a536e411
JS
225size_t wxDisplayBase::GetCount()
226{
8585e2b5
VZ
227 InitDisplays();
228
229 // I'm not sure if they really always return the same thing and if this is
230 // not true I'd like to know in which situation does it happen
231 wxASSERT_MSG( g_displays->GetCount() == (size_t)::GetSystemMetrics(SM_CMONITORS),
232 _T("So how many displays does this system have?") );
233
234 return g_displays->GetCount();
a536e411
JS
235}
236
8585e2b5 237/* static */
a536e411
JS
238int wxDisplayBase::GetFromPoint ( const wxPoint& pt )
239{
240 POINT pt2;
241 pt2.x = pt.x;
242 pt2.y = pt.y;
243
8585e2b5
VZ
244 return DisplayFromHMONITOR(::MonitorFromPoint(pt2, MONITOR_DEFAULTTONULL));
245}
a536e411 246
8585e2b5
VZ
247/* static */
248int wxDisplayBase::GetFromWindow(wxWindow *window)
249{
250 return DisplayFromHMONITOR
251 (
252 ::MonitorFromWindow(GetHwndOf(window), MONITOR_DEFAULTTONULL)
253 );
254}
255
256wxDisplay::wxDisplay ( size_t n )
257 : wxDisplayBase ( n )
258{
259 // if we do this in ctor we won't have to call it from all the member
260 // functions
261 InitDisplays();
262}
263
264wxRect wxDisplay::GetGeometry() const
265{
266 return (*g_displays)[m_index].m_rect;
267}
268
269wxString wxDisplay::GetName() const
270{
271 wxDisplayInfo& dpyInfo = (*g_displays)[m_index];
272 if ( dpyInfo.m_devName.empty() )
a536e411 273 {
8585e2b5
VZ
274 MONITORINFOEX monInfo;
275 wxZeroMemory(monInfo);
276 monInfo.cbSize = sizeof(monInfo);
277
278 if ( !::GetMonitorInfo(dpyInfo.m_hmon, &monInfo) )
279 {
280 wxLogLastError(_T("GetMonitorInfo"));
281 }
282 else
283 {
284 dpyInfo.m_devName = monInfo.szDevice;
285 }
a536e411
JS
286 }
287
8585e2b5 288 return dpyInfo.m_devName;
a536e411
JS
289}
290
8585e2b5 291wxString wxDisplay::GetNameForEnumSettings() const
a536e411 292{
8585e2b5
VZ
293 int major, minor;
294 const bool isWin95 = wxGetOsVersion(&major, &minor) == wxWIN95 &&
295 major == 4 && minor == 0;
296
297 // the first parameter of EnumDisplaySettings() must be NULL under Win95
298 // according to MSDN but GetMonitorInfo() stub in multimon.h still returns
299 // something even in this case, so we have to correct this manually
300 wxString name;
301 if ( !isWin95 )
302 name = GetName();
303
304 return name;
a536e411
JS
305}
306
8585e2b5 307wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& modeMatch) const
a536e411 308{
8585e2b5
VZ
309 wxArrayVideoModes modes;
310
311 const wxString name = GetNameForEnumSettings();
312
313 const wxChar * const deviceName = name.empty() ? NULL : name.c_str();
314
315 DEVMODE dm;
316 for ( int iModeNum = 0;
317 ::EnumDisplaySettings(deviceName, iModeNum, &dm);
318 iModeNum++ )
319 {
320 const wxVideoMode mode = ConvertToVideoMode(dm);
321 if ( mode.Matches(modeMatch) )
322 {
323 modes.Add(mode);
324 }
325 }
326
327 return modes;
a536e411
JS
328}
329
8585e2b5 330wxVideoMode wxDisplay::GetCurrentMode() const
a536e411 331{
8585e2b5
VZ
332 wxVideoMode mode;
333
334 const wxString name = GetNameForEnumSettings();
335
336 DEVMODE dm;
337 if ( !::EnumDisplaySettings(name.empty() ? NULL : name.c_str(),
338 ENUM_CURRENT_SETTINGS,
339 &dm) )
340 {
341 wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
342 }
343 else
344 {
345 mode = ConvertToVideoMode(dm);
346 }
347
348 return mode;
a536e411
JS
349}
350
8585e2b5 351bool wxDisplay::ChangeMode(const wxVideoMode& mode)
a536e411 352{
8585e2b5
VZ
353 // prepare ChangeDisplaySettingsEx() parameters
354 DEVMODE dm,
355 *pDevMode;
356 int flags;
357
358 if ( mode == wxDefaultVideoMode )
359 {
360 // reset the video mode to default
361 pDevMode = NULL;
362 flags = 0;
363 }
364 else // change to the given mode
365 {
366 wxCHECK_MSG( mode.w && mode.h, FALSE,
367 _T("at least the width and height must be specified") );
368
369 wxZeroMemory(dm);
370 dm.dmSize = sizeof(dm);
371 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
372 dm.dmPelsWidth = mode.w;
373 dm.dmPelsHeight = mode.h;
374
375 if ( mode.bpp )
376 {
377 dm.dmFields |= DM_BITSPERPEL;
378 dm.dmBitsPerPel = mode.bpp;
379 }
380
381 if ( mode.refresh )
382 {
383 dm.dmFields |= DM_DISPLAYFREQUENCY;
384 dm.dmDisplayFrequency = mode.refresh;
385 }
386
387 pDevMode = &dm;
388
389 flags = CDS_FULLSCREEN;
390 }
391
392
393 // get pointer to the function dynamically
394 //
395 // we're only called from the main thread, so it's ok to use static
396 // variable
397 static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx = NULL;
398 if ( !pfnChangeDisplaySettingsEx )
399 {
400 wxDynamicLibrary dllUser32(_T("user32.dll"));
401 if ( dllUser32.IsLoaded() )
402 {
403 pfnChangeDisplaySettingsEx = (ChangeDisplaySettingsEx_t)
404 dllUser32.GetSymbol(WINFUNC(ChangeDisplaySettingsEx));
405 }
406 //else: huh, no user32.dll??
407
408 if ( !pfnChangeDisplaySettingsEx )
409 {
410 // we must be under Win95 and so there is no multiple monitors
411 // support anyhow
412 pfnChangeDisplaySettingsEx = ChangeDisplaySettingsExForWin95;
413 }
414 }
415
416 // do change the mode
417 switch ( pfnChangeDisplaySettingsEx
418 (
419 GetName(), // display name
420 pDevMode, // dev mode or NULL to reset
421 NULL, // reserved
422 flags,
423 NULL // pointer to video parameters (not used)
424 ) )
425 {
426 case DISP_CHANGE_SUCCESSFUL:
427 // ok
428 return TRUE;
429
430 case DISP_CHANGE_BADMODE:
431 // don't complain about this, this is the only "expected" error
432 break;
433
434 default:
435 wxFAIL_MSG( _T("unexpected ChangeDisplaySettingsEx() return value") );
436 }
437
438 return FALSE;
a536e411
JS
439}
440
8585e2b5
VZ
441#endif // wxUSE_DISPLAY
442