display.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 806 行 · 第 1/2 页
CPP
806 行
/////////////////////////////////////////////////////////////////////////////
// Name: display.cpp
// Purpose: MSW Implementation of wxDisplay class
// Author: Royce Mitchell III
// Modified by: VZ (resolutions enumeration/change support, DirectDraw, ...)
// Ryan Norton (IsPrimary override)
// Created: 06/21/02
// RCS-ID: $Id: display.cpp,v 1.16 2005/02/28 02:00:12 RN Exp $
// Copyright: (c) wxWidgets team
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ===========================================================================
// declarations
// ===========================================================================
// ---------------------------------------------------------------------------
// 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"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_DISPLAY
#ifndef WX_PRECOMP
#include "wx/app.h"
#include "wx/dynarray.h"
#include "wx/frame.h"
#endif
#include "wx/dynload.h"
#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 <sigh>
#pragma warning(disable:4706)
#endif
// with mingw32, we must include windows.h first and it doesn't hurt with other
// compilers
#include <windows.h>
#include <multimon.h>
#ifdef _MSC_VER
#pragma warning(default:4706)
#endif
#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 } };
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
#ifdef _UNICODE
#define WINFUNC(x) _T(#x) L"W"
#else
#define WINFUNC(x) #x "A"
#endif
// ----------------------------------------------------------------------------
// typedefs for dynamically loaded Windows functions
// ----------------------------------------------------------------------------
typedef LONG (WINAPI *ChangeDisplaySettingsEx_t)(LPCTSTR lpszDeviceName,
LPDEVMODE lpDevMode,
HWND hwnd,
DWORD dwFlags,
LPVOID lParam);
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);
// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------
class wxDisplayInfo
{
public:
// handle of this monitor used by MonitorXXX() functions, never NULL
HMONITOR m_hmon;
// IDirectDraw object used to control this display, may be NULL
IDirectDraw2 *m_pDD2;
// DirectDraw GUID for this display, only valid when using DirectDraw
GUID m_guid;
// the entire area of this monitor in virtual screen coordinates
wxRect m_rect;
// the display device name for this monitor, empty initially and retrieved
// on demand by DoGetName()
wxString m_devName;
wxDisplayInfo() { m_hmon = NULL; m_pDD2 = NULL; }
~wxDisplayInfo() { if ( m_pDD2 ) m_pDD2->Release(); }
};
WX_DECLARE_OBJARRAY(wxDisplayInfo, wxDisplayInfoArray);
#include "wx/arrimpl.cpp"
WX_DEFINE_OBJARRAY(wxDisplayInfoArray);
// this module is used to cleanup gs_displays array
class wxDisplayModule : public wxModule
{
public:
virtual bool OnInit() { return true; }
virtual void OnExit();
DECLARE_DYNAMIC_CLASS(wxDisplayModule)
};
IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule)
// ----------------------------------------------------------------------------
// globals
// ----------------------------------------------------------------------------
// do we use DirectX?
static bool gs_useDirectX = false;
// dynamically resolved DirectDrawCreate()
static DirectDrawCreate_t gs_DirectDrawCreate = NULL;
// 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
static wxDisplayInfoArray *gs_displays = NULL;
// ===========================================================================
// implementation
// ===========================================================================
// ----------------------------------------------------------------------------
// callbacks for monitor/modes enumeration stuff
// ----------------------------------------------------------------------------
static BOOL CALLBACK wxmswMonitorEnumProc (
HMONITOR hMonitor, // handle to display monitor
HDC WXUNUSED(hdcMonitor), // handle to monitor-appropriate device context
LPRECT lprcMonitor, // pointer to monitor intersection rectangle
LPARAM WXUNUSED(dwData) // data passed from EnumDisplayMonitors (unused)
)
{
wxDisplayInfo *info = new wxDisplayInfo();
// we need hMonitor to be able to map display id to it which is needed for
// MonitorXXX() functions, in particular MonitorFromPoint()
info->m_hmon = hMonitor;
// we also store the display geometry
info->m_rect.SetX ( lprcMonitor->left );
info->m_rect.SetY ( lprcMonitor->top );
info->m_rect.SetWidth ( lprcMonitor->right - lprcMonitor->left );
info->m_rect.SetHeight ( lprcMonitor->bottom - lprcMonitor->top );
// now add this monitor to the array
gs_displays->Add(info);
// continue the enumeration
return true;
}
BOOL PASCAL
wxDDEnumExCallback(GUID *pGuid,
LPTSTR WXUNUSED(driverDescription),
LPTSTR driverName,
LPVOID WXUNUSED(lpContext),
HMONITOR hmon)
{
if ( pGuid )
{
wxDisplayInfo *info = new wxDisplayInfo();
info->m_hmon = hmon;
info->m_guid = *pGuid;
info->m_devName = driverName;
gs_displays->Add(info);
}
//else: we're called for the primary monitor, skip it
// continue the enumeration
return true;
}
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 )
{
wxArrayVideoModes * const modes = (wxArrayVideoModes *)lpContext;
modes->Add(wxVideoMode(lpDDSurfaceDesc->dwWidth,
lpDDSurfaceDesc->dwHeight,
lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
lpDDSurfaceDesc->dwRefreshRate));
}
// continue the enumeration
return DDENUMRET_OK;
}
// ----------------------------------------------------------------------------
// local functions
// ----------------------------------------------------------------------------
// initialize gs_displays using DirectX functions
static bool DoInitDirectX()
{
#if wxUSE_LOG
// suppress the errors if ddraw.dll is not found
wxLog::EnableLogging(false);
#endif
wxDynamicLibrary dllDX(_T("ddraw.dll"));
#if wxUSE_LOG
wxLog::EnableLogging();
#endif
if ( !dllDX.IsLoaded() )
return false;
DirectDrawEnumerateEx_t pDDEnumEx = (DirectDrawEnumerateEx_t)
dllDX.GetSymbol(WINFUNC(DirectDrawEnumerateEx));
if ( !pDDEnumEx )
return false;
// we'll also need DirectDrawCreate() later, resolve it right now
gs_DirectDrawCreate = (DirectDrawCreate_t)
dllDX.GetSymbol(_T("DirectDrawCreate"));
if ( !gs_DirectDrawCreate )
return false;
if ( (*pDDEnumEx)(wxDDEnumExCallback,
NULL,
DDENUM_ATTACHEDSECONDARYDEVICES) != DD_OK )
{
return false;
}
// ok, it seems like we're going to use DirectDraw and so we're going to
// need ddraw.dll all the time, don't unload it
dllDX.Detach();
return true;
}
// initialize gs_displays using the standard Windows functions
static void DoInitStdWindows()
{
// enumerate all displays
if ( !::EnumDisplayMonitors(NULL, NULL, wxmswMonitorEnumProc, 0) )
{
wxLogLastError(wxT("EnumDisplayMonitors"));
// TODO: still create at least one (valid) entry in gs_displays for the
// primary display!
}
}
// this function must be called before accessing gs_displays array as it
// creates and initializes it
static void InitDisplays()
{
if ( gs_displays )
return;
gs_displays = new wxDisplayInfoArray();
if ( !gs_useDirectX || !DoInitDirectX() )
{
// either we were told not to try to use DirectX or fall back to std
// functions if DirectX method failed
gs_useDirectX = false;
DoInitStdWindows();
}
}
// convert a DEVMODE to our wxVideoMode
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);
}
// 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);
}
// ----------------------------------------------------------------------------
// wxDisplayModule
// ----------------------------------------------------------------------------
void wxDisplayModule::OnExit()
{
delete gs_displays;
}
// ---------------------------------------------------------------------------
// wxDisplay
// ---------------------------------------------------------------------------
/* static */
void wxDisplay::UseDirectX(bool useDX)
{
wxCHECK_RET( !gs_displays, _T("it is too late to call UseDirectX") );
gs_useDirectX = useDX;
}
// helper of GetFromPoint() and GetFromWindow()
static int DisplayFromHMONITOR(HMONITOR hmon)
{
if ( hmon )
{
const size_t count = wxDisplay::GetCount();
for ( size_t n = 0; n < count; n++ )
{
if ( hmon == (*gs_displays)[n].m_hmon )
return n;
}
}
return wxNOT_FOUND;
}
/* static */
size_t wxDisplayBase::GetCount()
{
InitDisplays();
//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();
}
/* static */
int wxDisplayBase::GetFromPoint ( const wxPoint& pt )
{
POINT pt2;
pt2.x = pt.x;
pt2.y = pt.y;
return DisplayFromHMONITOR(::MonitorFromPoint(pt2, MONITOR_DEFAULTTONULL));
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?