1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: MSW Implementation of wxDisplay class
4 // Author: Royce Mitchell III
8 // Copyright: (c) wxWindows team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
21 #pragma implementation "display.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
34 #include "wx/dynarray.h"
37 #include "wx/dynload.h"
39 #include "wx/display.h"
41 // the following define is necessary to access the multi-monitor function
42 // declarations in a manner safe to use w/ Windows 95
43 #define COMPILE_MULTIMON_STUBS
45 // if you don't have multimon.h you can download the file from:
47 // http://www.microsoft.com/msj/0697/monitor/monitortextfigs.htm#fig4
51 // as (m)any standard header, this one doesn't compile without warnings
53 #pragma warning(disable:4706)
59 #pragma warning(default:4706)
63 #define MAKE_WFUNC(x) #x "W"
64 #define WINFUNC(x) L ## MAKE_WFUNC(x)
66 #define WINFUNC(x) #x "A"
69 // ----------------------------------------------------------------------------
71 // ----------------------------------------------------------------------------
73 typedef LONG (WINAPI
*ChangeDisplaySettingsEx_t
)(LPCTSTR lpszDeviceName
,
79 // ----------------------------------------------------------------------------
81 // ----------------------------------------------------------------------------
86 // handle of this monitor used by MonitorXXX() functions, never NULL
89 // the entire area of this monitor in virtual screen coordinates
92 // the display device name for this monitor, empty initially and retrieved
93 // on demand by DoGetName()
96 wxDisplayInfo() { m_hmon
= NULL
; }
99 WX_DECLARE_OBJARRAY(wxDisplayInfo
, wxDisplayInfoArray
);
100 #include "wx/arrimpl.cpp"
101 WX_DEFINE_OBJARRAY(wxDisplayInfoArray
);
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
105 static wxDisplayInfoArray
*g_displays
= NULL
;
108 // this module is used to cleanup g_displays array
109 class wxDisplayModule
: public wxModule
112 virtual bool OnInit() { return TRUE
; }
113 virtual void OnExit();
115 DECLARE_DYNAMIC_CLASS(wxDisplayModule
)
118 IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule
, wxModule
)
120 // ===========================================================================
122 // ===========================================================================
124 // ----------------------------------------------------------------------------
126 // ----------------------------------------------------------------------------
128 static BOOL CALLBACK
wxmswMonitorEnumProc (
129 HMONITOR hMonitor
, // handle to display monitor
130 HDC hdcMonitor
, // handle to monitor-appropriate device context (NULL)
131 LPRECT lprcMonitor
, // pointer to monitor intersection rectangle
132 LPARAM dwData
// data passed from EnumDisplayMonitors (unused)
135 wxDisplayInfo
* info
= new wxDisplayInfo();
137 // we need hMonitor to be able to map display id to it which is needed for
138 // MonitorXXX() functions, in particular MonitorFromPoint()
139 info
->m_hmon
= hMonitor
;
141 // we also store the display geometry
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
);
147 // now add this monitor to the array
148 g_displays
->Add(info
);
150 // continue the enumeration
154 // this function must be called before accessing g_displays array as it
155 // creates and initializes it
156 static void InitDisplays()
161 g_displays
= new wxDisplayInfoArray();
163 // enumerate all displays
164 if ( !::EnumDisplayMonitors(NULL
, NULL
, wxmswMonitorEnumProc
, 0) )
166 wxLogLastError(wxT("EnumDisplayMonitors"));
168 // TODO: still create at least one (valid) entry in g_displays for the
173 // convert a DEVMODE to our wxVideoMode
174 wxVideoMode
ConvertToVideoMode(const DEVMODE
& dm
)
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
,
181 dm
.dmDisplayFrequency
> 1 ? dm
.dmDisplayFrequency
: 0);
184 // emulation of ChangeDisplaySettingsEx() for Win95
185 LONG WINAPI
ChangeDisplaySettingsExForWin95(LPCTSTR
WXUNUSED(lpszDeviceName
),
189 LPVOID
WXUNUSED(lParam
))
191 return ::ChangeDisplaySettings(lpDevMode
, dwFlags
);
194 // ----------------------------------------------------------------------------
196 // ----------------------------------------------------------------------------
198 void wxDisplayModule::OnExit()
203 // ---------------------------------------------------------------------------
205 // ---------------------------------------------------------------------------
207 // helper of GetFromPoint() and GetFromWindow()
208 static int DisplayFromHMONITOR(HMONITOR hmon
)
212 const size_t count
= wxDisplay::GetCount();
214 for ( size_t n
= 0; n
< count
; n
++ )
216 if ( hmon
== (*g_displays
)[n
].m_hmon
)
225 size_t wxDisplayBase::GetCount()
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?") );
234 return g_displays
->GetCount();
238 int wxDisplayBase::GetFromPoint ( const wxPoint
& pt
)
244 return DisplayFromHMONITOR(::MonitorFromPoint(pt2
, MONITOR_DEFAULTTONULL
));
248 int wxDisplayBase::GetFromWindow(wxWindow
*window
)
250 return DisplayFromHMONITOR
252 ::MonitorFromWindow(GetHwndOf(window
), MONITOR_DEFAULTTONULL
)
256 wxDisplay::wxDisplay ( size_t n
)
257 : wxDisplayBase ( n
)
259 // if we do this in ctor we won't have to call it from all the member
264 wxRect
wxDisplay::GetGeometry() const
266 return (*g_displays
)[m_index
].m_rect
;
269 wxString
wxDisplay::GetName() const
271 wxDisplayInfo
& dpyInfo
= (*g_displays
)[m_index
];
272 if ( dpyInfo
.m_devName
.empty() )
274 MONITORINFOEX monInfo
;
275 wxZeroMemory(monInfo
);
276 monInfo
.cbSize
= sizeof(monInfo
);
278 if ( !::GetMonitorInfo(dpyInfo
.m_hmon
, &monInfo
) )
280 wxLogLastError(_T("GetMonitorInfo"));
284 dpyInfo
.m_devName
= monInfo
.szDevice
;
288 return dpyInfo
.m_devName
;
291 wxString
wxDisplay::GetNameForEnumSettings() const
294 const bool isWin95
= wxGetOsVersion(&major
, &minor
) == wxWIN95
&&
295 major
== 4 && minor
== 0;
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
307 wxArrayVideoModes
wxDisplay::GetModes(const wxVideoMode
& modeMatch
) const
309 wxArrayVideoModes modes
;
311 const wxString name
= GetNameForEnumSettings();
313 const wxChar
* const deviceName
= name
.empty() ? NULL
: name
.c_str();
316 for ( int iModeNum
= 0;
317 ::EnumDisplaySettings(deviceName
, iModeNum
, &dm
);
320 const wxVideoMode mode
= ConvertToVideoMode(dm
);
321 if ( mode
.Matches(modeMatch
) )
330 wxVideoMode
wxDisplay::GetCurrentMode() const
334 const wxString name
= GetNameForEnumSettings();
337 if ( !::EnumDisplaySettings(name
.empty() ? NULL
: name
.c_str(),
338 ENUM_CURRENT_SETTINGS
,
341 wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
345 mode
= ConvertToVideoMode(dm
);
351 bool wxDisplay::ChangeMode(const wxVideoMode
& mode
)
353 // prepare ChangeDisplaySettingsEx() parameters
358 if ( mode
== wxDefaultVideoMode
)
360 // reset the video mode to default
364 else // change to the given mode
366 wxCHECK_MSG( mode
.w
&& mode
.h
, FALSE
,
367 _T("at least the width and height must be specified") );
370 dm
.dmSize
= sizeof(dm
);
371 dm
.dmFields
= DM_PELSWIDTH
| DM_PELSHEIGHT
;
372 dm
.dmPelsWidth
= mode
.w
;
373 dm
.dmPelsHeight
= mode
.h
;
377 dm
.dmFields
|= DM_BITSPERPEL
;
378 dm
.dmBitsPerPel
= mode
.bpp
;
383 dm
.dmFields
|= DM_DISPLAYFREQUENCY
;
384 dm
.dmDisplayFrequency
= mode
.refresh
;
389 flags
= CDS_FULLSCREEN
;
393 // get pointer to the function dynamically
395 // we're only called from the main thread, so it's ok to use static
397 static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx
= NULL
;
398 if ( !pfnChangeDisplaySettingsEx
)
400 wxDynamicLibrary
dllUser32(_T("user32.dll"));
401 if ( dllUser32
.IsLoaded() )
403 pfnChangeDisplaySettingsEx
= (ChangeDisplaySettingsEx_t
)
404 dllUser32
.GetSymbol(WINFUNC(ChangeDisplaySettingsEx
));
406 //else: huh, no user32.dll??
408 if ( !pfnChangeDisplaySettingsEx
)
410 // we must be under Win95 and so there is no multiple monitors
412 pfnChangeDisplaySettingsEx
= ChangeDisplaySettingsExForWin95
;
416 // do change the mode
417 switch ( pfnChangeDisplaySettingsEx
419 GetName(), // display name
420 pDevMode
, // dev mode or NULL to reset
423 NULL
// pointer to video parameters (not used)
426 case DISP_CHANGE_SUCCESSFUL
:
430 case DISP_CHANGE_BADMODE
:
431 // don't complain about this, this is the only "expected" error
435 wxFAIL_MSG( _T("unexpected ChangeDisplaySettingsEx() return value") );
441 #endif // wxUSE_DISPLAY