dolphin/Externals/wxWidgets/src/msw/display.cpp

1041 lines
33 KiB
C++
Raw Normal View History

/////////////////////////////////////////////////////////////////////////////
// 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