mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-10-01 16:52:15 +02:00
1041 lines
33 KiB
C++
1041 lines
33 KiB
C++
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Name: src/msw/display.cpp
|
||
|
// Purpose: MSW Implementation of wxDisplay class
|
||
|
// Author: Royce Mitchell III, Vadim Zeitlin
|
||
|
// Modified by: Ryan Norton (IsPrimary override)
|
||
|
// Created: 06/21/02
|
||
|
// RCS-ID: $Id: display.cpp 42813 2006-10-31 08:45:16Z VZ $
|
||
|
// Copyright: (c) wxWidgets team
|
||
|
// Copyright: (c) 2002-2006 wxWidgets team
|
||
|
// Licence: wxWindows licence
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// ===========================================================================
|
||
|
// declarations
|
||
|
// ===========================================================================
|
||
|
|
||
|
// ---------------------------------------------------------------------------
|
||
|
// headers
|
||
|
// ---------------------------------------------------------------------------
|
||
|
|
||
|
// For compilers that support precompilation, includes "wx.h".
|
||
|
#include "wx/wxprec.h"
|
||
|
|
||
|
#ifdef __BORLANDC__
|
||
|
#pragma hdrstop
|
||
|
#endif
|
||
|
|
||
|
#if wxUSE_DISPLAY
|
||
|
|
||
|
#include "wx/display.h"
|
||
|
|
||
|
#ifndef WX_PRECOMP
|
||
|
#include "wx/dynarray.h"
|
||
|
#include "wx/app.h"
|
||
|
#include "wx/frame.h"
|
||
|
#endif
|
||
|
|
||
|
#include "wx/dynload.h"
|
||
|
#include "wx/sysopt.h"
|
||
|
|
||
|
#include "wx/display_impl.h"
|
||
|
#include "wx/msw/wrapwin.h"
|
||
|
#include "wx/msw/missing.h"
|
||
|
|
||
|
// define this to use DirectDraw for display mode switching: this is disabled
|
||
|
// by default because ddraw.h is now always available and also it's not really
|
||
|
// clear what are the benefits of using DirectDraw compared to the standard API
|
||
|
|
||
|
#if !defined(wxUSE_DIRECTDRAW)
|
||
|
#define wxUSE_DIRECTDRAW 0
|
||
|
#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);
|
||
|
typedef BOOL(CALLBACK * MONITORENUMPROC )(HMONITOR, HDC, LPRECT, LPARAM);
|
||
|
typedef struct tagMONITORINFO
|
||
|
{
|
||
|
DWORD cbSize;
|
||
|
RECT rcMonitor;
|
||
|
RECT rcWork;
|
||
|
DWORD dwFlags;
|
||
|
} MONITORINFO, *LPMONITORINFO;
|
||
|
typedef struct tagMONITORINFOEX : public tagMONITORINFO
|
||
|
{
|
||
|
TCHAR szDevice[CCHDEVICENAME];
|
||
|
} MONITORINFOEX, *LPMONITORINFOEX;
|
||
|
#define MONITOR_DEFAULTTONULL 0x00000000
|
||
|
#define MONITOR_DEFAULTTOPRIMARY 0x00000001
|
||
|
#define MONITOR_DEFAULTTONEAREST 0x00000002
|
||
|
#define MONITORINFOF_PRIMARY 0x00000001
|
||
|
#define HMONITOR_DECLARED
|
||
|
#endif
|
||
|
#endif // !__WXWINCE__
|
||
|
|
||
|
#if wxUSE_DIRECTDRAW
|
||
|
#include <ddraw.h>
|
||
|
|
||
|
// 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 // wxUSE_DIRECTDRAW
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// typedefs for dynamically loaded Windows functions
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName,
|
||
|
LPDEVMODE lpDevMode,
|
||
|
HWND hwnd,
|
||
|
DWORD dwFlags,
|
||
|
LPVOID lParam);
|
||
|
|
||
|
#if wxUSE_DIRECTDRAW
|
||
|
typedef BOOL (PASCAL *DDEnumExCallback_t)(GUID *pGuid,
|
||
|
LPTSTR driverDescription,
|
||
|
LPTSTR driverName,
|
||
|
LPVOID lpContext,
|
||
|
HMONITOR hmon);
|
||
|
|
||
|
typedef HRESULT (WINAPI *DirectDrawEnumerateEx_t)(DDEnumExCallback_t lpCallback,
|
||
|
LPVOID lpContext,
|
||
|
DWORD dwFlags);
|
||
|
|
||
|
typedef HRESULT (WINAPI *DirectDrawCreate_t)(GUID *lpGUID,
|
||
|
LPDIRECTDRAW *lplpDD,
|
||
|
IUnknown *pUnkOuter);
|
||
|
#endif // wxUSE_DIRECTDRAW
|
||
|
|
||
|
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);
|
||
|
|
||
|
#ifndef __WXWINCE__
|
||
|
// emulation of ChangeDisplaySettingsEx() for Win95
|
||
|
LONG WINAPI ChangeDisplaySettingsExForWin95(LPCTSTR WXUNUSED(lpszDeviceName),
|
||
|
LPDEVMODE lpDevMode,
|
||
|
HWND WXUNUSED(hwnd),
|
||
|
DWORD dwFlags,
|
||
|
LPVOID WXUNUSED(lParam))
|
||
|
{
|
||
|
return ::ChangeDisplaySettings(lpDevMode, dwFlags);
|
||
|
}
|
||
|
#endif // !__WXWINCE__
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// display information classes
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
struct wxDisplayInfo
|
||
|
{
|
||
|
wxDisplayInfo(HMONITOR hmon = NULL)
|
||
|
{
|
||
|
m_hmon = hmon;
|
||
|
m_flags = (DWORD)-1;
|
||
|
}
|
||
|
|
||
|
virtual ~wxDisplayInfo() { }
|
||
|
|
||
|
|
||
|
// use GetMonitorInfo() to fill in all of our fields if needed (i.e. if it
|
||
|
// hadn't been done before)
|
||
|
void Initialize();
|
||
|
|
||
|
|
||
|
// handle of this monitor used by MonitorXXX() functions, never NULL
|
||
|
HMONITOR m_hmon;
|
||
|
|
||
|
// the entire area of this monitor in virtual screen coordinates
|
||
|
wxRect m_rect;
|
||
|
|
||
|
// the work or client area, i.e. the area available for the normal windows
|
||
|
wxRect m_rectClient;
|
||
|
|
||
|
// the display device name for this monitor, empty initially and retrieved
|
||
|
// on demand by DoGetName()
|
||
|
wxString m_devName;
|
||
|
|
||
|
// the flags of this monitor, also used as initialization marker: if this
|
||
|
// is -1, GetMonitorInfo() hadn't been called yet
|
||
|
DWORD m_flags;
|
||
|
};
|
||
|
|
||
|
WX_DEFINE_ARRAY_PTR(wxDisplayInfo *, wxDisplayInfoArray);
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// common base class for all Win32 wxDisplayImpl versions
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
class wxDisplayImplWin32Base : public wxDisplayImpl
|
||
|
{
|
||
|
public:
|
||
|
wxDisplayImplWin32Base(unsigned n, wxDisplayInfo& info)
|
||
|
: wxDisplayImpl(n),
|
||
|
m_info(info)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
virtual wxRect GetGeometry() const;
|
||
|
virtual wxRect GetClientArea() const;
|
||
|
virtual wxString GetName() const;
|
||
|
virtual bool IsPrimary() const;
|
||
|
|
||
|
virtual wxVideoMode GetCurrentMode() const;
|
||
|
|
||
|
protected:
|
||
|
// convert a DEVMODE to our wxVideoMode
|
||
|
static wxVideoMode ConvertToVideoMode(const DEVMODE& dm)
|
||
|
{
|
||
|
// note that dmDisplayFrequency may be 0 or 1 meaning "standard one"
|
||
|
// and although 0 is ok for us we don't want to return modes with 1hz
|
||
|
// refresh
|
||
|
return wxVideoMode(dm.dmPelsWidth,
|
||
|
dm.dmPelsHeight,
|
||
|
dm.dmBitsPerPel,
|
||
|
dm.dmDisplayFrequency > 1 ? dm.dmDisplayFrequency : 0);
|
||
|
}
|
||
|
|
||
|
wxDisplayInfo& m_info;
|
||
|
};
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// common base class for all Win32 wxDisplayFactory versions
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
// functions dynamically bound by wxDisplayFactoryWin32Base::Initialize()
|
||
|
static MonitorFromPoint_t gs_MonitorFromPoint = NULL;
|
||
|
static MonitorFromWindow_t gs_MonitorFromWindow = NULL;
|
||
|
static GetMonitorInfo_t gs_GetMonitorInfo = NULL;
|
||
|
|
||
|
class wxDisplayFactoryWin32Base : public wxDisplayFactory
|
||
|
{
|
||
|
public:
|
||
|
virtual ~wxDisplayFactoryWin32Base();
|
||
|
|
||
|
bool IsOk() const { return !m_displays.empty(); }
|
||
|
|
||
|
virtual unsigned GetCount() { return unsigned(m_displays.size()); }
|
||
|
virtual int GetFromPoint(const wxPoint& pt);
|
||
|
virtual int GetFromWindow(wxWindow *window);
|
||
|
|
||
|
protected:
|
||
|
// ctor checks if the current system supports multimon API and dynamically
|
||
|
// bind the functions we need if this is the case and sets
|
||
|
// ms_supportsMultimon if they're available
|
||
|
wxDisplayFactoryWin32Base();
|
||
|
|
||
|
// delete all m_displays elements: can be called from the derived class
|
||
|
// dtor if it is important to do this before destroying it (as in
|
||
|
// wxDisplayFactoryDirectDraw case), otherwise will be done by our dtor
|
||
|
void Clear();
|
||
|
|
||
|
// find the monitor corresponding to the given handle, return wxNOT_FOUND
|
||
|
// if not found
|
||
|
int FindDisplayFromHMONITOR(HMONITOR hmon) const;
|
||
|
|
||
|
|
||
|
// flag indicating whether gs_MonitorXXX functions are available
|
||
|
static int ms_supportsMultimon;
|
||
|
|
||
|
// the array containing information about all available displays, should be
|
||
|
// filled by the derived class ctors
|
||
|
wxDisplayInfoArray m_displays;
|
||
|
|
||
|
|
||
|
DECLARE_NO_COPY_CLASS(wxDisplayFactoryWin32Base)
|
||
|
};
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplay implementation using Windows multi-monitor support functions
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
class wxDisplayImplMultimon : public wxDisplayImplWin32Base
|
||
|
{
|
||
|
public:
|
||
|
wxDisplayImplMultimon(unsigned n, wxDisplayInfo& info)
|
||
|
: wxDisplayImplWin32Base(n, info)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
|
||
|
virtual bool ChangeMode(const wxVideoMode& mode);
|
||
|
|
||
|
private:
|
||
|
DECLARE_NO_COPY_CLASS(wxDisplayImplMultimon)
|
||
|
};
|
||
|
|
||
|
class wxDisplayFactoryMultimon : public wxDisplayFactoryWin32Base
|
||
|
{
|
||
|
public:
|
||
|
wxDisplayFactoryMultimon();
|
||
|
|
||
|
virtual wxDisplayImpl *CreateDisplay(unsigned n);
|
||
|
|
||
|
private:
|
||
|
// EnumDisplayMonitors() callback
|
||
|
static BOOL CALLBACK MultimonEnumProc(HMONITOR hMonitor,
|
||
|
HDC hdcMonitor,
|
||
|
LPRECT lprcMonitor,
|
||
|
LPARAM dwData);
|
||
|
|
||
|
|
||
|
// add a monitor description to m_displays array
|
||
|
void AddDisplay(HMONITOR hMonitor, LPRECT lprcMonitor);
|
||
|
};
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplay implementation using DirectDraw
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
#if wxUSE_DIRECTDRAW
|
||
|
|
||
|
struct wxDisplayInfoDirectDraw : wxDisplayInfo
|
||
|
{
|
||
|
wxDisplayInfoDirectDraw(const GUID& guid, HMONITOR hmon, LPTSTR name)
|
||
|
: wxDisplayInfo(hmon),
|
||
|
m_guid(guid)
|
||
|
{
|
||
|
m_pDD2 = NULL;
|
||
|
m_devName = name;
|
||
|
}
|
||
|
|
||
|
virtual ~wxDisplayInfoDirectDraw()
|
||
|
{
|
||
|
if ( m_pDD2 )
|
||
|
m_pDD2->Release();
|
||
|
}
|
||
|
|
||
|
|
||
|
// IDirectDraw object used to control this display, may be NULL
|
||
|
IDirectDraw2 *m_pDD2;
|
||
|
|
||
|
// DirectDraw GUID for this display, only valid when using DirectDraw
|
||
|
const GUID m_guid;
|
||
|
|
||
|
|
||
|
DECLARE_NO_COPY_CLASS(wxDisplayInfoDirectDraw)
|
||
|
};
|
||
|
|
||
|
class wxDisplayImplDirectDraw : public wxDisplayImplWin32Base
|
||
|
{
|
||
|
public:
|
||
|
wxDisplayImplDirectDraw(unsigned n, wxDisplayInfo& info, IDirectDraw2 *pDD2)
|
||
|
: wxDisplayImplWin32Base(n, info),
|
||
|
m_pDD2(pDD2)
|
||
|
{
|
||
|
m_pDD2->AddRef();
|
||
|
}
|
||
|
|
||
|
virtual ~wxDisplayImplDirectDraw()
|
||
|
{
|
||
|
m_pDD2->Release();
|
||
|
}
|
||
|
|
||
|
virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const;
|
||
|
virtual bool ChangeMode(const wxVideoMode& mode);
|
||
|
|
||
|
private:
|
||
|
IDirectDraw2 *m_pDD2;
|
||
|
|
||
|
DECLARE_NO_COPY_CLASS(wxDisplayImplDirectDraw)
|
||
|
};
|
||
|
|
||
|
class wxDisplayFactoryDirectDraw : public wxDisplayFactoryWin32Base
|
||
|
{
|
||
|
public:
|
||
|
wxDisplayFactoryDirectDraw();
|
||
|
virtual ~wxDisplayFactoryDirectDraw();
|
||
|
|
||
|
virtual wxDisplayImpl *CreateDisplay(unsigned n);
|
||
|
|
||
|
private:
|
||
|
// callback used with DirectDrawEnumerateEx()
|
||
|
static BOOL WINAPI DDEnumExCallback(GUID *pGuid,
|
||
|
LPTSTR driverDescription,
|
||
|
LPTSTR driverName,
|
||
|
LPVOID lpContext,
|
||
|
HMONITOR hmon);
|
||
|
|
||
|
// add a monitor description to m_displays array
|
||
|
void AddDisplay(const GUID& guid, HMONITOR hmon, LPTSTR name);
|
||
|
|
||
|
|
||
|
// ddraw.dll
|
||
|
wxDynamicLibrary m_dllDDraw;
|
||
|
|
||
|
// dynamically resolved DirectDrawCreate()
|
||
|
DirectDrawCreate_t m_pfnDirectDrawCreate;
|
||
|
|
||
|
DECLARE_NO_COPY_CLASS(wxDisplayFactoryDirectDraw)
|
||
|
};
|
||
|
|
||
|
#endif // wxUSE_DIRECTDRAW
|
||
|
|
||
|
|
||
|
// ============================================================================
|
||
|
// common classes implementation
|
||
|
// ============================================================================
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplay
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
/* static */ wxDisplayFactory *wxDisplay::CreateFactory()
|
||
|
{
|
||
|
// we have 2 implementations for modern Windows: one using standard Win32
|
||
|
// and another using DirectDraw, the choice between them is done using a
|
||
|
// system option
|
||
|
|
||
|
#if wxUSE_DIRECTDRAW
|
||
|
if ( wxSystemOptions::GetOptionInt(_T("msw.display.directdraw")) )
|
||
|
{
|
||
|
wxDisplayFactoryDirectDraw *factoryDD = new wxDisplayFactoryDirectDraw;
|
||
|
if ( factoryDD->IsOk() )
|
||
|
return factoryDD;
|
||
|
|
||
|
delete factoryDD;
|
||
|
}
|
||
|
#endif // wxUSE_DIRECTDRAW
|
||
|
|
||
|
wxDisplayFactoryMultimon *factoryMM = new wxDisplayFactoryMultimon;
|
||
|
if ( factoryMM->IsOk() )
|
||
|
return factoryMM;
|
||
|
|
||
|
delete factoryMM;
|
||
|
|
||
|
|
||
|
// finally fall back to a stub implementation if all else failed (Win95?)
|
||
|
return new wxDisplayFactorySingle;
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplayInfo
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
void wxDisplayInfo::Initialize()
|
||
|
{
|
||
|
if ( m_flags == (DWORD)-1 )
|
||
|
{
|
||
|
WinStruct<MONITORINFOEX> monInfo;
|
||
|
if ( !gs_GetMonitorInfo(m_hmon, (LPMONITORINFO)&monInfo) )
|
||
|
{
|
||
|
wxLogLastError(_T("GetMonitorInfo"));
|
||
|
m_flags = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
wxCopyRECTToRect(monInfo.rcMonitor, m_rect);
|
||
|
wxCopyRECTToRect(monInfo.rcWork, m_rectClient);
|
||
|
m_devName = monInfo.szDevice;
|
||
|
m_flags = monInfo.dwFlags;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplayImplWin32Base
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
wxRect wxDisplayImplWin32Base::GetGeometry() const
|
||
|
{
|
||
|
if ( m_info.m_rect.IsEmpty() )
|
||
|
m_info.Initialize();
|
||
|
|
||
|
return m_info.m_rect;
|
||
|
}
|
||
|
|
||
|
wxRect wxDisplayImplWin32Base::GetClientArea() const
|
||
|
{
|
||
|
if ( m_info.m_rectClient.IsEmpty() )
|
||
|
m_info.Initialize();
|
||
|
|
||
|
return m_info.m_rectClient;
|
||
|
}
|
||
|
|
||
|
wxString wxDisplayImplWin32Base::GetName() const
|
||
|
{
|
||
|
if ( m_info.m_devName.empty() )
|
||
|
m_info.Initialize();
|
||
|
|
||
|
return m_info.m_devName;
|
||
|
}
|
||
|
|
||
|
bool wxDisplayImplWin32Base::IsPrimary() const
|
||
|
{
|
||
|
if ( m_info.m_flags == (DWORD)-1 )
|
||
|
m_info.Initialize();
|
||
|
|
||
|
return (m_info.m_flags & MONITORINFOF_PRIMARY) != 0;
|
||
|
}
|
||
|
|
||
|
wxVideoMode wxDisplayImplWin32Base::GetCurrentMode() const
|
||
|
{
|
||
|
wxVideoMode mode;
|
||
|
|
||
|
// 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;
|
||
|
if ( !::EnumDisplaySettings(deviceName, ENUM_CURRENT_SETTINGS, &dm) )
|
||
|
{
|
||
|
wxLogLastError(_T("EnumDisplaySettings(ENUM_CURRENT_SETTINGS)"));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mode = ConvertToVideoMode(dm);
|
||
|
}
|
||
|
|
||
|
return mode;
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplayFactoryWin32Base
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
int wxDisplayFactoryWin32Base::ms_supportsMultimon = -1;
|
||
|
|
||
|
wxDisplayFactoryWin32Base::wxDisplayFactoryWin32Base()
|
||
|
{
|
||
|
if ( ms_supportsMultimon == -1 )
|
||
|
{
|
||
|
ms_supportsMultimon = 0;
|
||
|
|
||
|
wxDynamicLibrary dllUser32(_T("user32.dll"));
|
||
|
|
||
|
wxLogNull noLog;
|
||
|
|
||
|
gs_MonitorFromPoint = (MonitorFromPoint_t)
|
||
|
dllUser32.GetSymbol(wxT("MonitorFromPoint"));
|
||
|
if ( !gs_MonitorFromPoint )
|
||
|
return;
|
||
|
|
||
|
gs_MonitorFromWindow = (MonitorFromWindow_t)
|
||
|
dllUser32.GetSymbol(wxT("MonitorFromWindow"));
|
||
|
if ( !gs_MonitorFromWindow )
|
||
|
return;
|
||
|
|
||
|
gs_GetMonitorInfo = (GetMonitorInfo_t)
|
||
|
dllUser32.GetSymbolAorW(wxT("GetMonitorInfo"));
|
||
|
if ( !gs_GetMonitorInfo )
|
||
|
return;
|
||
|
|
||
|
ms_supportsMultimon = 1;
|
||
|
|
||
|
// we can safely let dllUser32 go out of scope, the DLL itself will
|
||
|
// still remain loaded as all Win32 programs use it
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void wxDisplayFactoryWin32Base::Clear()
|
||
|
{
|
||
|
WX_CLEAR_ARRAY(m_displays);
|
||
|
}
|
||
|
|
||
|
wxDisplayFactoryWin32Base::~wxDisplayFactoryWin32Base()
|
||
|
{
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
// helper for GetFromPoint() and GetFromWindow()
|
||
|
int wxDisplayFactoryWin32Base::FindDisplayFromHMONITOR(HMONITOR hmon) const
|
||
|
{
|
||
|
if ( hmon )
|
||
|
{
|
||
|
const size_t count = m_displays.size();
|
||
|
for ( size_t n = 0; n < count; n++ )
|
||
|
{
|
||
|
if ( hmon == m_displays[n]->m_hmon )
|
||
|
return n;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return wxNOT_FOUND;
|
||
|
}
|
||
|
|
||
|
int wxDisplayFactoryWin32Base::GetFromPoint(const wxPoint& pt)
|
||
|
{
|
||
|
POINT pt2;
|
||
|
pt2.x = pt.x;
|
||
|
pt2.y = pt.y;
|
||
|
|
||
|
return FindDisplayFromHMONITOR(gs_MonitorFromPoint(pt2,
|
||
|
MONITOR_DEFAULTTONULL));
|
||
|
}
|
||
|
|
||
|
int wxDisplayFactoryWin32Base::GetFromWindow(wxWindow *window)
|
||
|
{
|
||
|
return FindDisplayFromHMONITOR(gs_MonitorFromWindow(GetHwndOf(window),
|
||
|
MONITOR_DEFAULTTONULL));
|
||
|
}
|
||
|
|
||
|
// ============================================================================
|
||
|
// wxDisplay implementation using Win32 multimon API
|
||
|
// ============================================================================
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplayFactoryMultimon initialization
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
wxDisplayFactoryMultimon::wxDisplayFactoryMultimon()
|
||
|
{
|
||
|
if ( !ms_supportsMultimon )
|
||
|
return;
|
||
|
|
||
|
// look up EnumDisplayMonitors() which we don't need with DirectDraw
|
||
|
// implementation
|
||
|
EnumDisplayMonitors_t pfnEnumDisplayMonitors;
|
||
|
{
|
||
|
wxLogNull noLog;
|
||
|
|
||
|
wxDynamicLibrary dllUser32(_T("user32.dll"));
|
||
|
pfnEnumDisplayMonitors = (EnumDisplayMonitors_t)
|
||
|
dllUser32.GetSymbol(wxT("EnumDisplayMonitors"));
|
||
|
if ( !pfnEnumDisplayMonitors )
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// enumerate all displays
|
||
|
if ( !pfnEnumDisplayMonitors(NULL, NULL, MultimonEnumProc, (LPARAM)this) )
|
||
|
{
|
||
|
wxLogLastError(wxT("EnumDisplayMonitors"));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* static */
|
||
|
BOOL CALLBACK
|
||
|
wxDisplayFactoryMultimon::MultimonEnumProc(
|
||
|
HMONITOR hMonitor, // handle to display monitor
|
||
|
HDC WXUNUSED(hdcMonitor), // handle to monitor-appropriate device context
|
||
|
LPRECT lprcMonitor, // pointer to monitor intersection rectangle
|
||
|
LPARAM dwData // data passed from EnumDisplayMonitors (this)
|
||
|
)
|
||
|
{
|
||
|
wxDisplayFactoryMultimon *const self = (wxDisplayFactoryMultimon *)dwData;
|
||
|
self->AddDisplay(hMonitor, lprcMonitor);
|
||
|
|
||
|
// continue the enumeration
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplayFactoryMultimon helper functions
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
void wxDisplayFactoryMultimon::AddDisplay(HMONITOR hMonitor, LPRECT lprcMonitor)
|
||
|
{
|
||
|
wxDisplayInfo *info = new wxDisplayInfo(hMonitor);
|
||
|
|
||
|
// we also store the display geometry
|
||
|
info->m_rect = wxRect(lprcMonitor->left, lprcMonitor->top,
|
||
|
lprcMonitor->right - lprcMonitor->left,
|
||
|
lprcMonitor->bottom - lprcMonitor->top);
|
||
|
|
||
|
// now add this monitor to the array
|
||
|
m_displays.Add(info);
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplayFactoryMultimon inherited pure virtuals implementation
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
wxDisplayImpl *wxDisplayFactoryMultimon::CreateDisplay(unsigned n)
|
||
|
{
|
||
|
wxCHECK_MSG( n < m_displays.size(), NULL, _T("invalid display index") );
|
||
|
|
||
|
return new wxDisplayImplMultimon(n, *(m_displays[n]));
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplayImplMultimon implementation
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
wxArrayVideoModes
|
||
|
wxDisplayImplMultimon::GetModes(const wxVideoMode& modeMatch) const
|
||
|
{
|
||
|
wxArrayVideoModes modes;
|
||
|
|
||
|
// 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++ )
|
||
|
{
|
||
|
const wxVideoMode mode = ConvertToVideoMode(dm);
|
||
|
if ( mode.Matches(modeMatch) )
|
||
|
{
|
||
|
modes.Add(mode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return modes;
|
||
|
}
|
||
|
|
||
|
bool wxDisplayImplMultimon::ChangeMode(const wxVideoMode& mode)
|
||
|
{
|
||
|
// prepare ChangeDisplaySettingsEx() parameters
|
||
|
DEVMODE dm;
|
||
|
DEVMODE *pDevMode;
|
||
|
|
||
|
int flags;
|
||
|
|
||
|
if ( mode == wxDefaultVideoMode )
|
||
|
{
|
||
|
// reset the video mode to default
|
||
|
pDevMode = NULL;
|
||
|
flags = 0;
|
||
|
}
|
||
|
else // change to the given mode
|
||
|
{
|
||
|
wxCHECK_MSG( mode.w && mode.h, false,
|
||
|
_T("at least the width and height must be specified") );
|
||
|
|
||
|
wxZeroMemory(dm);
|
||
|
dm.dmSize = sizeof(dm);
|
||
|
dm.dmDriverExtra = 0;
|
||
|
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
|
||
|
dm.dmPelsWidth = mode.w;
|
||
|
dm.dmPelsHeight = mode.h;
|
||
|
|
||
|
if ( mode.bpp )
|
||
|
{
|
||
|
dm.dmFields |= DM_BITSPERPEL;
|
||
|
dm.dmBitsPerPel = mode.bpp;
|
||
|
}
|
||
|
|
||
|
if ( mode.refresh )
|
||
|
{
|
||
|
dm.dmFields |= DM_DISPLAYFREQUENCY;
|
||
|
dm.dmDisplayFrequency = mode.refresh;
|
||
|
}
|
||
|
|
||
|
pDevMode = &dm;
|
||
|
|
||
|
#ifdef __WXWINCE__
|
||
|
flags = 0;
|
||
|
#else // !__WXWINCE__
|
||
|
flags = CDS_FULLSCREEN;
|
||
|
#endif // __WXWINCE__/!__WXWINCE__
|
||
|
}
|
||
|
|
||
|
|
||
|
// get pointer to the function dynamically
|
||
|
//
|
||
|
// we're only called from the main thread, so it's ok to use static
|
||
|
// variable
|
||
|
static ChangeDisplaySettingsEx_t pfnChangeDisplaySettingsEx = NULL;
|
||
|
if ( !pfnChangeDisplaySettingsEx )
|
||
|
{
|
||
|
wxDynamicLibrary dllUser32(_T("user32.dll"));
|
||
|
if ( dllUser32.IsLoaded() )
|
||
|
{
|
||
|
pfnChangeDisplaySettingsEx = (ChangeDisplaySettingsEx_t)
|
||
|
dllUser32.GetSymbolAorW(_T("ChangeDisplaySettingsEx"));
|
||
|
}
|
||
|
//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
|
||
|
switch ( pfnChangeDisplaySettingsEx
|
||
|
(
|
||
|
GetName(), // display name
|
||
|
pDevMode, // dev mode or NULL to reset
|
||
|
NULL, // reserved
|
||
|
flags,
|
||
|
NULL // pointer to video parameters (not used)
|
||
|
) )
|
||
|
{
|
||
|
case DISP_CHANGE_SUCCESSFUL:
|
||
|
// ok
|
||
|
{
|
||
|
// If we have a top-level, full-screen frame, emulate
|
||
|
// the DirectX behavior and resize it. This makes this
|
||
|
// API quite a bit easier to use.
|
||
|
wxWindow *winTop = wxTheApp->GetTopWindow();
|
||
|
wxFrame *frameTop = wxDynamicCast(winTop, wxFrame);
|
||
|
if (frameTop && frameTop->IsFullScreen())
|
||
|
{
|
||
|
wxVideoMode current = GetCurrentMode();
|
||
|
frameTop->SetClientSize(current.w, current.h);
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
|
||
|
case DISP_CHANGE_BADMODE:
|
||
|
// don't complain about this, this is the only "expected" error
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
wxFAIL_MSG( _T("unexpected ChangeDisplaySettingsEx() return value") );
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ============================================================================
|
||
|
// DirectDraw-based wxDisplay implementation
|
||
|
// ============================================================================
|
||
|
|
||
|
#if wxUSE_DIRECTDRAW
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplayFactoryDirectDraw initialization
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
wxDisplayFactoryDirectDraw::wxDisplayFactoryDirectDraw()
|
||
|
{
|
||
|
if ( !ms_supportsMultimon )
|
||
|
return;
|
||
|
|
||
|
#if wxUSE_LOG
|
||
|
// suppress the errors if ddraw.dll is not found, we're prepared to handle
|
||
|
// this
|
||
|
wxLogNull noLog;
|
||
|
#endif
|
||
|
|
||
|
m_dllDDraw.Load(_T("ddraw.dll"));
|
||
|
|
||
|
if ( !m_dllDDraw.IsLoaded() )
|
||
|
return;
|
||
|
|
||
|
DirectDrawEnumerateEx_t pDDEnumEx = (DirectDrawEnumerateEx_t)
|
||
|
m_dllDDraw.GetSymbolAorW(_T("DirectDrawEnumerateEx"));
|
||
|
if ( !pDDEnumEx )
|
||
|
return;
|
||
|
|
||
|
// we can't continue without DirectDrawCreate() later, so resolve it right
|
||
|
// now and fail the initialization if it's not available
|
||
|
m_pfnDirectDrawCreate = (DirectDrawCreate_t)
|
||
|
m_dllDDraw.GetSymbol(_T("DirectDrawCreate"));
|
||
|
if ( !m_pfnDirectDrawCreate )
|
||
|
return;
|
||
|
|
||
|
if ( (*pDDEnumEx)(DDEnumExCallback,
|
||
|
this,
|
||
|
DDENUM_ATTACHEDSECONDARYDEVICES) != DD_OK )
|
||
|
{
|
||
|
wxLogLastError(_T("DirectDrawEnumerateEx"));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
wxDisplayFactoryDirectDraw::~wxDisplayFactoryDirectDraw()
|
||
|
{
|
||
|
// we must clear m_displays now, before m_dllDDraw is unloaded as otherwise
|
||
|
// calling m_pDD2->Release() later would crash
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// callbacks for monitor/modes enumeration stuff
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL WINAPI
|
||
|
wxDisplayFactoryDirectDraw::DDEnumExCallback(GUID *pGuid,
|
||
|
LPTSTR WXUNUSED(driverDescription),
|
||
|
LPTSTR driverName,
|
||
|
LPVOID lpContext,
|
||
|
HMONITOR hmon)
|
||
|
{
|
||
|
if ( pGuid )
|
||
|
{
|
||
|
wxDisplayFactoryDirectDraw * self =
|
||
|
wx_static_cast(wxDisplayFactoryDirectDraw *, lpContext);
|
||
|
self->AddDisplay(*pGuid, hmon, driverName);
|
||
|
}
|
||
|
//else: we're called for the primary monitor, skip it
|
||
|
|
||
|
// continue the enumeration
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplayFactoryDirectDraw helpers
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
void wxDisplayFactoryDirectDraw::AddDisplay(const GUID& guid,
|
||
|
HMONITOR hmon,
|
||
|
LPTSTR name)
|
||
|
{
|
||
|
m_displays.Add(new wxDisplayInfoDirectDraw(guid, hmon, name));
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// wxDisplayFactoryDirectDraw inherited pure virtuals implementation
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
wxDisplayImpl *wxDisplayFactoryDirectDraw::CreateDisplay(unsigned n)
|
||
|
{
|
||
|
wxCHECK_MSG( n < m_displays.size(), NULL, _T("invalid display index") );
|
||
|
|
||
|
wxDisplayInfoDirectDraw *
|
||
|
info = wx_static_cast(wxDisplayInfoDirectDraw *, m_displays[n]);
|
||
|
|
||
|
if ( !info->m_pDD2 )
|
||
|
{
|
||
|
IDirectDraw *pDD;
|
||
|
GUID guid(info->m_guid);
|
||
|
HRESULT hr = (*m_pfnDirectDrawCreate)(&guid, &pDD, NULL);
|
||
|
|
||
|
if ( FAILED(hr) || !pDD )
|
||
|
{
|
||
|
// what to do??
|
||
|
wxLogApiError(_T("DirectDrawCreate"), hr);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// we got IDirectDraw, but we need IDirectDraw2
|
||
|
hr = pDD->QueryInterface(wxIID_IDirectDraw2, (void **)&info->m_pDD2);
|
||
|
pDD->Release();
|
||
|
|
||
|
if ( FAILED(hr) || !info->m_pDD2 )
|
||
|
{
|
||
|
wxLogApiError(_T("IDirectDraw::QueryInterface(IDD2)"), hr);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// NB: m_pDD2 will now be only destroyed when m_displays is destroyed
|
||
|
// which is ok as we don't want to recreate DD objects all the time
|
||
|
}
|
||
|
//else: DirectDraw object corresponding to our display already exists
|
||
|
|
||
|
return new wxDisplayImplDirectDraw(n, *info, info->m_pDD2);
|
||
|
}
|
||
|
|
||
|
// ============================================================================
|
||
|
// wxDisplayImplDirectDraw
|
||
|
// ============================================================================
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// video modes enumeration
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
// tiny helper class used to pass information from GetModes() to
|
||
|
// wxDDEnumModesCallback
|
||
|
class wxDDVideoModesAdder
|
||
|
{
|
||
|
public:
|
||
|
// our Add() method will add modes matching modeMatch to modes array
|
||
|
wxDDVideoModesAdder(wxArrayVideoModes& modes, const wxVideoMode& modeMatch)
|
||
|
: m_modes(modes),
|
||
|
m_modeMatch(modeMatch)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void Add(const wxVideoMode& mode)
|
||
|
{
|
||
|
if ( mode.Matches(m_modeMatch) )
|
||
|
m_modes.Add(mode);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
wxArrayVideoModes& m_modes;
|
||
|
const wxVideoMode& m_modeMatch;
|
||
|
|
||
|
DECLARE_NO_COPY_CLASS(wxDDVideoModesAdder)
|
||
|
};
|
||
|
|
||
|
HRESULT WINAPI wxDDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc,
|
||
|
LPVOID lpContext)
|
||
|
{
|
||
|
// we need at least the mode size
|
||
|
static const DWORD FLAGS_REQUIRED = DDSD_HEIGHT | DDSD_WIDTH;
|
||
|
if ( (lpDDSurfaceDesc->dwFlags & FLAGS_REQUIRED) == FLAGS_REQUIRED )
|
||
|
{
|
||
|
wxDDVideoModesAdder * const vmodes =
|
||
|
wx_static_cast(wxDDVideoModesAdder *, lpContext);
|
||
|
|
||
|
vmodes->Add(wxVideoMode(lpDDSurfaceDesc->dwWidth,
|
||
|
lpDDSurfaceDesc->dwHeight,
|
||
|
lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
|
||
|
lpDDSurfaceDesc->dwRefreshRate));
|
||
|
}
|
||
|
|
||
|
// continue the enumeration
|
||
|
return DDENUMRET_OK;
|
||
|
}
|
||
|
|
||
|
wxArrayVideoModes
|
||
|
wxDisplayImplDirectDraw::GetModes(const wxVideoMode& modeMatch) const
|
||
|
{
|
||
|
wxArrayVideoModes modes;
|
||
|
wxDDVideoModesAdder modesAdder(modes, modeMatch);
|
||
|
|
||
|
HRESULT hr = m_pDD2->EnumDisplayModes
|
||
|
(
|
||
|
DDEDM_REFRESHRATES,
|
||
|
NULL, // all modes
|
||
|
&modesAdder, // callback parameter
|
||
|
wxDDEnumModesCallback
|
||
|
);
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
wxLogApiError(_T("IDirectDraw::EnumDisplayModes"), hr);
|
||
|
}
|
||
|
|
||
|
return modes;
|
||
|
}
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
// video mode switching
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
bool wxDisplayImplDirectDraw::ChangeMode(const wxVideoMode& mode)
|
||
|
{
|
||
|
wxWindow *winTop = wxTheApp->GetTopWindow();
|
||
|
wxCHECK_MSG( winTop, false, _T("top level window required for DirectX") );
|
||
|
|
||
|
HRESULT hr = m_pDD2->SetCooperativeLevel
|
||
|
(
|
||
|
GetHwndOf(winTop),
|
||
|
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN
|
||
|
);
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
wxLogApiError(_T("IDirectDraw2::SetCooperativeLevel"), hr);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
hr = m_pDD2->SetDisplayMode(mode.w, mode.h, mode.bpp, mode.refresh, 0);
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
wxLogApiError(_T("IDirectDraw2::SetDisplayMode"), hr);
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
#endif // wxUSE_DIRECTDRAW
|
||
|
|
||
|
#endif // wxUSE_DISPLAY
|