X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/24d2b4f5ba8ceffe55e7520a233ba6b3046aa27e..7d90194ccb382badfd569d0a791f03853d7e6a9a:/src/msw/display.cpp diff --git a/src/msw/display.cpp b/src/msw/display.cpp index 2933da9ef7..e284a22039 100644 --- a/src/msw/display.cpp +++ b/src/msw/display.cpp @@ -1,8 +1,9 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: display.cpp +// Name: src/msw/display.cpp // Purpose: MSW Implementation of wxDisplay class -// Author: Royce Mitchell III, Ryan Norton +// Author: Royce Mitchell III // Modified by: VZ (resolutions enumeration/change support, DirectDraw, ...) +// Ryan Norton (IsPrimary override) // Created: 06/21/02 // RCS-ID: $Id$ // Copyright: (c) wxWidgets team @@ -17,10 +18,6 @@ // headers // --------------------------------------------------------------------------- -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) - #pragma implementation "display.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -40,33 +37,33 @@ #include "wx/display.h" -// the following define is necessary to access the multi-monitor function -// declarations in a manner safe to use w/ Windows 95 -#define COMPILE_MULTIMON_STUBS - -// if you don't have multimon.h you can download the file from: -// -// http://www.microsoft.com/msj/0697/monitor/monitortextfigs.htm#fig4 -// - -#ifdef _MSC_VER - // as (m)any standard header(s), this one doesn't compile without warnings - // with VC++ 6 - #pragma warning(disable:4706) -#endif - -#include - -#ifdef _MSC_VER - #pragma warning(default:4706) +// Mingw's w32api headers don't include ddraw.h, though the user may have +// installed it. If using configure, we actually probe for ddraw.h there +// and set HAVE_DDRAW_H. Otherwise, assume we don't have it if using +// the w32api headers, and that we do otherwise. +#if !defined HAVE_W32API_H && !defined HAVE_DDRAW_H +#define HAVE_DDRAW_H 1 #endif +#ifndef __WXWINCE__ + // Older versions of windef.h don't define HMONITOR. Unfortunately, we + // can't directly test whether HMONITOR is defined or not in windef.h as + // it's not a macro but a typedef, so we test for an unrelated symbol which + // is only defined in winuser.h if WINVER >= 0x0500 + #if !defined(HMONITOR_DECLARED) && !defined(MNS_NOCHECK) + DECLARE_HANDLE(HMONITOR); + #define HMONITOR_DECLARED + #endif +#endif // !__WXWINCE__ + +#ifdef HAVE_DDRAW_H #include // we don't want to link with ddraw.lib which contains the real // IID_IDirectDraw2 definition const GUID wxIID_IDirectDraw2 = { 0xB3A6F3E0, 0x2B43, 0x11CF, { 0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 } }; +#endif // ---------------------------------------------------------------------------- // macros @@ -88,6 +85,7 @@ typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName, DWORD dwFlags, LPVOID lParam); +#ifdef HAVE_DDRAW_H typedef BOOL (PASCAL *DDEnumExCallback_t)(GUID *pGuid, LPTSTR driverDescription, LPTSTR driverName, @@ -101,6 +99,17 @@ typedef HRESULT (WINAPI *DirectDrawEnumerateEx_t)(DDEnumExCallback_t lpCallback, typedef HRESULT (WINAPI *DirectDrawCreate_t)(GUID *lpGUID, LPDIRECTDRAW *lplpDD, IUnknown *pUnkOuter); +#endif + +typedef BOOL (WINAPI *EnumDisplayMonitors_t)(HDC,LPCRECT,MONITORENUMPROC,LPARAM); +typedef HMONITOR (WINAPI *MonitorFromPoint_t)(POINT,DWORD); +typedef HMONITOR (WINAPI *MonitorFromWindow_t)(HWND,DWORD); +typedef BOOL (WINAPI *GetMonitorInfo_t)(HMONITOR,LPMONITORINFO); + +static EnumDisplayMonitors_t gs_EnumDisplayMonitors = NULL; +static MonitorFromPoint_t gs_MonitorFromPoint = NULL; +static MonitorFromWindow_t gs_MonitorFromWindow = NULL; +static GetMonitorInfo_t gs_GetMonitorInfo = NULL; // ---------------------------------------------------------------------------- // private classes @@ -113,7 +122,11 @@ public: HMONITOR m_hmon; // IDirectDraw object used to control this display, may be NULL +#ifdef HAVE_DDRAW_H IDirectDraw2 *m_pDD2; +#else + void *m_pDD2; +#endif // DirectDraw GUID for this display, only valid when using DirectDraw GUID m_guid; @@ -126,7 +139,11 @@ public: wxString m_devName; wxDisplayInfo() { m_hmon = NULL; m_pDD2 = NULL; } - ~wxDisplayInfo() { if ( m_pDD2 ) m_pDD2->Release(); } + ~wxDisplayInfo() { +#ifdef HAVE_DDRAW_H + if ( m_pDD2 ) m_pDD2->Release(); +#endif + } }; WX_DECLARE_OBJARRAY(wxDisplayInfo, wxDisplayInfoArray); @@ -149,11 +166,52 @@ IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule) // globals // ---------------------------------------------------------------------------- +#ifdef HAVE_DDRAW_H // do we use DirectX? static bool gs_useDirectX = false; +#endif +// Try to look up the functions needed for supporting multiple monitors. If +// they aren't available (probably because we're running on Win95 or NT4 which +// predate this API), set a flag which makes wxDisplay return results for a +// single screen. +static bool OsSupportsMultipleMonitors() +{ + static int isNewEnough = -1; + if ( isNewEnough == -1 ) + { + isNewEnough = 0; + wxDynamicLibrary dllUser32(_T("user32.dll")); + // Check for one of the symbols to avoid logging errors just because + // we happen to be running on Win95 or NT4. + if ( dllUser32.IsLoaded() && + dllUser32.HasSymbol(wxT("EnumDisplayMonitors")) ) + { + // GetMonitorInfo has Unicode/ANSI variants, the others don't. + gs_EnumDisplayMonitors = (EnumDisplayMonitors_t) + dllUser32.GetSymbol(wxT("EnumDisplayMonitors")); + gs_MonitorFromPoint = (MonitorFromPoint_t) + dllUser32.GetSymbol(wxT("MonitorFromPoint")); + gs_MonitorFromWindow = (MonitorFromWindow_t) + dllUser32.GetSymbol(wxT("MonitorFromWindow")); + gs_GetMonitorInfo = (GetMonitorInfo_t) + dllUser32.GetSymbol(WINFUNC(GetMonitorInfo)); + if ( gs_EnumDisplayMonitors != NULL && + gs_MonitorFromPoint != NULL && + gs_MonitorFromWindow != NULL && + gs_GetMonitorInfo != NULL ) + { + isNewEnough = 1; + } + } + } + return (isNewEnough != 0); +} + +#ifdef HAVE_DDRAW_H // dynamically resolved DirectDrawCreate() static DirectDrawCreate_t gs_DirectDrawCreate = NULL; +#endif // this is not really MT-unsafe as wxDisplay is only going to be used from the // main thread, i.e. we consider that it's a GUI class and so don't protect it @@ -193,6 +251,7 @@ static BOOL CALLBACK wxmswMonitorEnumProc ( return true; } +#ifdef HAVE_DDRAW_H BOOL PASCAL wxDDEnumExCallback(GUID *pGuid, LPTSTR WXUNUSED(driverDescription), @@ -234,11 +293,13 @@ HRESULT WINAPI wxDDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc, // continue the enumeration return DDENUMRET_OK; } +#endif // ---------------------------------------------------------------------------- // local functions // ---------------------------------------------------------------------------- +#ifdef HAVE_DDRAW_H // initialize gs_displays using DirectX functions static bool DoInitDirectX() { @@ -280,12 +341,13 @@ static bool DoInitDirectX() return true; } +#endif // initialize gs_displays using the standard Windows functions static void DoInitStdWindows() { // enumerate all displays - if ( !::EnumDisplayMonitors(NULL, NULL, wxmswMonitorEnumProc, 0) ) + if ( !gs_EnumDisplayMonitors(NULL, NULL, wxmswMonitorEnumProc, 0) ) { wxLogLastError(wxT("EnumDisplayMonitors")); @@ -303,6 +365,7 @@ static void InitDisplays() gs_displays = new wxDisplayInfoArray(); +#ifdef HAVE_DDRAW_H if ( !gs_useDirectX || !DoInitDirectX() ) { // either we were told not to try to use DirectX or fall back to std @@ -311,6 +374,9 @@ static void InitDisplays() DoInitStdWindows(); } +#else + DoInitStdWindows(); +#endif } // convert a DEVMODE to our wxVideoMode @@ -324,6 +390,7 @@ wxVideoMode ConvertToVideoMode(const DEVMODE& dm) dm.dmDisplayFrequency > 1 ? dm.dmDisplayFrequency : 0); } +#ifndef __WXWINCE__ // emulation of ChangeDisplaySettingsEx() for Win95 LONG WINAPI ChangeDisplaySettingsExForWin95(LPCTSTR WXUNUSED(lpszDeviceName), LPDEVMODE lpDevMode, @@ -333,6 +400,7 @@ LONG WINAPI ChangeDisplaySettingsExForWin95(LPCTSTR WXUNUSED(lpszDeviceName), { return ::ChangeDisplaySettings(lpDevMode, dwFlags); } +#endif // !__WXWINCE__ // ---------------------------------------------------------------------------- // wxDisplayModule @@ -352,10 +420,13 @@ void wxDisplay::UseDirectX(bool useDX) { wxCHECK_RET( !gs_displays, _T("it is too late to call UseDirectX") ); - gs_useDirectX = useDX; +#ifdef HAVE_DDRAW_H + // DirectDrawEnumerateEx requires Win98 or Win2k anyway. + if ( OsSupportsMultipleMonitors() ) gs_useDirectX = useDX; +#endif } -// helper of GetFromPoint() and GetFromWindow() +// helper for GetFromPoint() and GetFromWindow() static int DisplayFromHMONITOR(HMONITOR hmon) { if ( hmon ) @@ -375,12 +446,16 @@ static int DisplayFromHMONITOR(HMONITOR hmon) /* static */ size_t wxDisplayBase::GetCount() { + if ( !OsSupportsMultipleMonitors() ) return 1; + InitDisplays(); - // I'm not sure if they really always return the same thing and if this is - // not true I'd like to know in which situation does it happen - wxASSERT_MSG( gs_displays->GetCount() == (size_t)::GetSystemMetrics(SM_CMONITORS), - _T("So how many displays does this system have?") ); + //RN: FIXME: This is wrong - the display info array should reload after every call + //to GetCount() - otherwise it will not be accurate. + //The user can change the number of displays in display properties/settings + //after GetCount or similar is called and really mess this up... + //wxASSERT_MSG( gs_displays->GetCount() == (size_t)::GetSystemMetrics(SM_CMONITORS), + // _T("So how many displays does this system have?") ); return gs_displays->GetCount(); } @@ -388,19 +463,42 @@ size_t wxDisplayBase::GetCount() /* static */ int wxDisplayBase::GetFromPoint ( const wxPoint& pt ) { + if ( !OsSupportsMultipleMonitors() ) + { + const wxSize size = wxGetDisplaySize(); + if (pt.x >= 0 && pt.x < size.GetWidth() && + pt.y >= 0 && pt.y < size.GetHeight()) + { + return 0; + } + return wxNOT_FOUND; + } + POINT pt2; pt2.x = pt.x; pt2.y = pt.y; - return DisplayFromHMONITOR(::MonitorFromPoint(pt2, MONITOR_DEFAULTTONULL)); + return DisplayFromHMONITOR(gs_MonitorFromPoint(pt2, MONITOR_DEFAULTTONULL)); } /* static */ int wxDisplayBase::GetFromWindow(wxWindow *window) { + if ( !OsSupportsMultipleMonitors() ) + { + const wxRect r(window->GetRect()); + const wxSize size = wxGetDisplaySize(); + if (r.x < size.GetWidth() && r.x + r.width >= 0 && + r.y < size.GetHeight() && r.y + r.height >= 0) + { + return 0; + } + return wxNOT_FOUND; + } + return DisplayFromHMONITOR ( - ::MonitorFromWindow(GetHwndOf(window), MONITOR_DEFAULTTONULL) + gs_MonitorFromWindow(GetHwndOf(window), MONITOR_DEFAULTTONULL) ); } @@ -411,10 +509,13 @@ int wxDisplayBase::GetFromWindow(wxWindow *window) wxDisplay::wxDisplay ( size_t n ) : wxDisplayBase ( n ) { + if ( !OsSupportsMultipleMonitors() ) return; + // if we do this in ctor we won't have to call it from all the member // functions InitDisplays(); +#ifdef HAVE_DDRAW_H if ( gs_useDirectX ) { wxDisplayInfo& dpyInfo = (*gs_displays)[n]; @@ -456,10 +557,14 @@ wxDisplay::wxDisplay ( size_t n ) // all the time pDD2->AddRef(); } +#endif } wxDisplay::~wxDisplay() { +#ifdef HAVE_DDRAW_H + if ( !OsSupportsMultipleMonitors() ) return; + wxDisplayInfo& dpyInfo = (*gs_displays)[m_index]; LPDIRECTDRAW2& pDD2 = dpyInfo.m_pDD2; @@ -467,6 +572,7 @@ wxDisplay::~wxDisplay() { pDD2->Release(); } +#endif } // ---------------------------------------------------------------------------- @@ -475,12 +581,22 @@ wxDisplay::~wxDisplay() bool wxDisplay::IsOk() const { +#ifdef HAVE_DDRAW_H return m_index < GetCount() && (!gs_useDirectX || (*gs_displays)[m_index].m_pDD2); +#else + return m_index < GetCount(); +#endif } wxRect wxDisplay::GetGeometry() const { + if ( !OsSupportsMultipleMonitors() ) + { + wxSize size = wxGetDisplaySize(); + return wxRect(0, 0, size.GetWidth(), size.GetHeight()); + } + wxDisplayInfo& dpyInfo = (*gs_displays)[m_index]; wxRect& rect = dpyInfo.m_rect; if ( !rect.width ) @@ -489,7 +605,7 @@ wxRect wxDisplay::GetGeometry() const wxZeroMemory(monInfo); monInfo.cbSize = sizeof(monInfo); - if ( !::GetMonitorInfo(dpyInfo.m_hmon, &monInfo) ) + if ( !gs_GetMonitorInfo(dpyInfo.m_hmon, &monInfo) ) { wxLogLastError(_T("GetMonitorInfo")); } @@ -504,6 +620,8 @@ wxRect wxDisplay::GetGeometry() const wxString wxDisplay::GetName() const { + if ( !OsSupportsMultipleMonitors() ) return wxT(""); + wxDisplayInfo& dpyInfo = (*gs_displays)[m_index]; if ( dpyInfo.m_devName.empty() ) { @@ -515,7 +633,7 @@ wxString wxDisplay::GetName() const // Mingw headers - unlike the ones from Microsoft's Platform SDK - // don't derive the former from the latter in C++ mode and so // the pointer's type is not converted implicitly. - if ( !::GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) ) + if ( !gs_GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) ) { wxLogLastError(_T("GetMonitorInfo")); } @@ -528,28 +646,14 @@ wxString wxDisplay::GetName() const return dpyInfo.m_devName; } -wxString wxDisplay::GetNameForEnumSettings() const -{ - int major, minor; - const bool isWin95 = wxGetOsVersion(&major, &minor) == wxWIN95 && - major == 4 && minor == 0; - - // the first parameter of EnumDisplaySettings() must be NULL under Win95 - // according to MSDN but GetMonitorInfo() stub in multimon.h still returns - // something even in this case, so we have to correct this manually - wxString name; - if ( !isWin95 ) - name = GetName(); - - return name; -} - // ---------------------------------------------------------------------------- // determine if this is the primary display // ---------------------------------------------------------------------------- bool wxDisplay::IsPrimary() const { + if ( !OsSupportsMultipleMonitors() ) return true; + wxDisplayInfo& dpyInfo = (*gs_displays)[m_index]; MONITORINFOEX monInfo; @@ -560,7 +664,7 @@ bool wxDisplay::IsPrimary() const // Mingw headers - unlike the ones from Microsoft's Platform SDK - // don't derive the former from the latter in C++ mode and so // the pointer's type is not converted implicitly. - if ( !::GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) ) + if ( !gs_GetMonitorInfo(dpyInfo.m_hmon, (LPMONITORINFO)&monInfo) ) { wxLogLastError(_T("GetMonitorInfo")); } @@ -572,6 +676,7 @@ bool wxDisplay::IsPrimary() const // video modes enumeration // ---------------------------------------------------------------------------- +#ifdef HAVE_DDRAW_H wxArrayVideoModes wxDisplay::DoGetModesDirectX(const wxVideoMode& WXUNUSED(modeMatch)) const { @@ -597,17 +702,22 @@ wxDisplay::DoGetModesDirectX(const wxVideoMode& WXUNUSED(modeMatch)) const return modes; } +#endif wxArrayVideoModes wxDisplay::DoGetModesWindows(const wxVideoMode& modeMatch) const { wxArrayVideoModes modes; - const wxString name = GetNameForEnumSettings(); - + // The first parameter of EnumDisplaySettings() must be NULL under Win95 + // according to MSDN. The version of GetName() we implement for Win95 + // returns an empty string. + const wxString name = GetName(); const wxChar * const deviceName = name.empty() ? NULL : name.c_str(); DEVMODE dm; + dm.dmSize = sizeof(dm); + dm.dmDriverExtra = 0; for ( int iModeNum = 0; ::EnumDisplaySettings(deviceName, iModeNum, &dm); iModeNum++ ) @@ -624,20 +734,28 @@ wxDisplay::DoGetModesWindows(const wxVideoMode& modeMatch) const wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& modeMatch) const { +#ifdef HAVE_DDRAW_H return gs_useDirectX ? DoGetModesDirectX(modeMatch) : DoGetModesWindows(modeMatch); +#else + return DoGetModesWindows(modeMatch); +#endif } wxVideoMode wxDisplay::GetCurrentMode() const { wxVideoMode mode; - const wxString name = GetNameForEnumSettings(); + // The first parameter of EnumDisplaySettings() must be NULL under Win95 + // according to MSDN. The version of GetName() we implement for Win95 + // returns an empty string. + const wxString name = GetName(); + const wxChar * const deviceName = name.empty() ? NULL : name.c_str(); DEVMODE dm; - if ( !::EnumDisplaySettings(name.empty() ? NULL : name.c_str(), - ENUM_CURRENT_SETTINGS, - &dm) ) + dm.dmSize = sizeof(dm); + dm.dmDriverExtra = 0; + if ( !::EnumDisplaySettings(deviceName, ENUM_CURRENT_SETTINGS, &dm) ) { wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)")); } @@ -653,6 +771,7 @@ wxVideoMode wxDisplay::GetCurrentMode() const // video mode switching // ---------------------------------------------------------------------------- +#ifdef HAVE_DDRAW_H bool wxDisplay::DoChangeModeDirectX(const wxVideoMode& mode) { IDirectDraw2 *pDD = (*gs_displays)[m_index].m_pDD2; @@ -685,6 +804,7 @@ bool wxDisplay::DoChangeModeDirectX(const wxVideoMode& mode) return true; } +#endif bool wxDisplay::DoChangeModeWindows(const wxVideoMode& mode) { @@ -706,6 +826,7 @@ bool wxDisplay::DoChangeModeWindows(const wxVideoMode& mode) wxZeroMemory(dm); dm.dmSize = sizeof(dm); + dm.dmDriverExtra = 0; dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; dm.dmPelsWidth = mode.w; dm.dmPelsHeight = mode.h; @@ -724,7 +845,11 @@ bool wxDisplay::DoChangeModeWindows(const wxVideoMode& mode) pDevMode = &dm; +#ifdef __WXWINCE__ + flags = 0; +#else // !__WXWINCE__ flags = CDS_FULLSCREEN; +#endif // __WXWINCE__/!__WXWINCE__ } @@ -743,12 +868,14 @@ bool wxDisplay::DoChangeModeWindows(const wxVideoMode& mode) } //else: huh, no user32.dll?? +#ifndef __WXWINCE__ if ( !pfnChangeDisplaySettingsEx ) { // we must be under Win95 and so there is no multiple monitors // support anyhow pfnChangeDisplaySettingsEx = ChangeDisplaySettingsExForWin95; } +#endif // !__WXWINCE__ } // do change the mode @@ -790,8 +917,12 @@ bool wxDisplay::DoChangeModeWindows(const wxVideoMode& mode) bool wxDisplay::ChangeMode(const wxVideoMode& mode) { +#ifdef HAVE_DDRAW_H return gs_useDirectX ? DoChangeModeDirectX(mode) : DoChangeModeWindows(mode); +#else + return DoChangeModeWindows(mode); +#endif } #endif // wxUSE_DISPLAY