Add wxDisplay::GetPPI() to use instead of wxGetDisplayPPI()

While this is not done for all the ports yet, the new API allows
returning different PPI values for different monitors, unlike the old
(and still existing, but implemented in terms of the new one) global
function.
This commit is contained in:
Vadim Zeitlin
2018-10-06 23:21:45 +02:00
parent e3e883bbd2
commit ded2894b78
24 changed files with 290 additions and 107 deletions

View File

@@ -127,6 +127,7 @@ All (GUI):
- Allow binding to events generated by their items in submenus too.
- Add wxGrid::SetCornerLabelValue() (Pavel Kalugin).
- Add strikethrough support for fonts defined in XRC.
- Add wxDisplay::GetPPI().
wxGTK:

View File

@@ -11,6 +11,7 @@
#define _WX_DISPLAY_H_BASE_
#include "wx/defs.h"
#include "wx/gdicmn.h" // wxSize
// NB: no #if wxUSE_DISPLAY here, the display geometry part of this class (but
// not the video mode stuff) is always available but if wxUSE_DISPLAY == 0
@@ -77,6 +78,9 @@ public:
// get the depth, i.e. number of bits per pixel (0 if unknown)
int GetDepth() const;
// get the resolution of this monitor in pixels per inch
wxSize GetPPI() const;
// name may be empty
wxString GetName() const;

View File

@@ -1080,6 +1080,9 @@ extern WXDLLIMPEXP_DATA_CORE(const wxPoint) wxDefaultPosition;
extern void WXDLLIMPEXP_CORE wxInitializeStockLists();
extern void WXDLLIMPEXP_CORE wxDeleteStockLists();
// Note: all the display-related functions here exist for compatibility only,
// please use wxDisplay class in the new code
// is the display colour (or monochrome)?
extern bool WXDLLIMPEXP_CORE wxColourDisplay();

View File

@@ -81,6 +81,15 @@ public:
// return the depth or 0 if unknown
virtual int GetDepth() const = 0;
// return the resolution of the display, uses GetSizeMM() by default but
// can be also overridden directly
virtual wxSize GetPPI() const;
// return the physical size of the display or (0, 0) if unknown: this is
// only used by GetPPI() implementation in the base class, so if GetPPI()
// is overridden, this one doesn't have to be implemented
virtual wxSize GetSizeMM() const { return wxSize(0, 0); }
// return the name (may be empty)
virtual wxString GetName() const { return wxString(); }

View File

@@ -12,8 +12,6 @@
@library{wxcore}
@category{cfg}
@see wxClientDisplayRect(), wxDisplaySize(), wxDisplaySizeMM()
*/
class wxDisplay
{
@@ -109,6 +107,19 @@ public:
*/
wxString GetName() const;
/**
Returns display resolution in pixels per inch.
Horizontal and vertical resolution are returned in @c x and @c y
components of the wxSize object respectively.
If the resolution information is not available, returns @code wxSize(0,
0) @endcode.
@since 3.1.2
*/
wxSize GetPPI() const;
/**
Returns @true if the display is the primary display. The primary
display is the one whose index is 0.

View File

@@ -1256,6 +1256,10 @@ wxRect wxGetClientDisplayRect();
The @c x component of the returned wxSize object contains the horizontal
resolution and the @c y one -- the vertical resolution.
@note Use of this function is not recommended in the new code as it only
works for the primary display. Use wxDisplay::GetPPI() to retrieve
the resolution of the appropriate display instead.
@header{wx/gdicmn.h}
@see wxDisplay

View File

@@ -15,8 +15,6 @@
@stdobjects
::wxDefaultVideoMode
@see wxClientDisplayRect(), wxDisplaySize(), wxDisplaySizeMM()
*/
struct wxVideoMode
{

View File

@@ -275,6 +275,11 @@ MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size,
rc.x, rc.y, rc.width, rc.height)
));
sizer->Add(new wxStaticText(page, wxID_ANY, "Resolution: "));
const wxSize ppi = display.GetPPI();
sizer->Add(new wxStaticText(page, wxID_ANY,
wxString::Format("%d*%d", ppi.x, ppi.y)));
sizer->Add(new wxStaticText(page, wxID_ANY, "Depth: "));
sizer->Add(new wxStaticText(page, wxID_ANY,
wxString::Format("%d", display.GetDepth())));

View File

@@ -29,6 +29,8 @@
#include "wx/module.h"
#endif //WX_PRECOMP
#include "wx/math.h"
#include "wx/private/display.h"
#if wxUSE_DISPLAY
@@ -122,6 +124,13 @@ wxRect wxDisplay::GetClientArea() const
return m_impl->GetClientArea();
}
wxSize wxDisplay::GetPPI() const
{
wxCHECK_MSG( IsOk(), wxSize(), wxT("invalid wxDisplay object") );
return m_impl->GetPPI();
}
int wxDisplay::GetDepth() const
{
wxCHECK_MSG( IsOk(), 0, wxT("invalid wxDisplay object") );
@@ -180,6 +189,26 @@ bool wxDisplay::ChangeMode(const wxVideoMode& mode)
return *gs_factory;
}
// ============================================================================
// wxDisplayImpl implementation
// ============================================================================
wxSize wxDisplayImpl::GetPPI() const
{
const wxSize pixels = GetGeometry().GetSize();
const wxSize mm = GetSizeMM();
if ( !mm.x || !mm.y )
{
// Physical size is unknown, return a special value indicating that we
// can't compute the resolution -- what else can we do?
return wxSize(0, 0);
}
return wxSize(wxRound((pixels.x * inches2mm) / mm.x),
wxRound((pixels.y * inches2mm) / mm.y));
}
// ============================================================================
// wxDisplayFactory implementation
// ============================================================================

View File

@@ -889,20 +889,29 @@ wxRect wxGetClientDisplayRect()
return wxDisplay().GetClientArea();
}
void wxDisplaySizeMM(int *width, int *height)
{
const wxSize size = wxGetDisplaySizeMM();
if ( width )
*width = size.x;
if ( height )
*height = size.y;
}
wxSize wxGetDisplaySizeMM()
{
int x, y;
wxDisplaySizeMM(& x, & y);
return wxSize(x, y);
const wxSize ppi = wxGetDisplayPPI();
if ( !ppi.x || !ppi.y )
return wxSize(0, 0);
const wxSize pixels = wxGetDisplaySize();
return wxSize(wxRound(pixels.x * inches2mm / ppi.x),
wxRound(pixels.y * inches2mm / ppi.y));
}
wxSize wxGetDisplayPPI()
{
const wxSize pixels = wxGetDisplaySize();
const wxSize mm = wxGetDisplaySizeMM();
return wxSize((int)((pixels.x * inches2mm) / mm.x),
(int)((pixels.y * inches2mm) / mm.y));
return wxDisplay().GetPPI();
}
wxResourceCache::~wxResourceCache ()

View File

@@ -73,6 +73,13 @@ public:
{
return wxTheApp->GetDisplayMode().bpp;
}
virtual wxSize GetPPI() const wxOVERRIDE
{
// FIXME: there's no way to get physical resolution using the DirectDB
// API, we hardcode a commonly used value of 72dpi
return wxSize(72, 72);
}
};
class wxDisplayFactorySingleDFB : public wxDisplayFactorySingle
@@ -89,21 +96,6 @@ wxDisplayFactory* wxDisplay::CreateFactory()
return new wxDisplayFactorySingleDFB;
}
void wxDisplaySizeMM(int *width, int *height)
{
// FIXME: there's no way to get physical resolution using the DirectDB
// API, we hardcode a commonly used value of 72dpi
#define DPI 72.0
#define PX_TO_MM(x) (int(((x) / DPI) * inches2mm))
wxDisplaySize(width, height);
if ( width ) *width = PX_TO_MM(*width);
if ( height ) *height = PX_TO_MM(*height);
#undef DPI
#undef PX_TO_MM
}
//-----------------------------------------------------------------------------
// mouse
//-----------------------------------------------------------------------------

View File

@@ -46,6 +46,7 @@ public:
virtual wxRect GetGeometry() const wxOVERRIDE;
virtual wxRect GetClientArea() const wxOVERRIDE;
virtual int GetDepth() const wxOVERRIDE;
virtual wxSize GetSizeMM() const wxOVERRIDE;
#if wxUSE_DISPLAY
virtual bool IsPrimary() const wxOVERRIDE;
@@ -120,6 +121,15 @@ int wxDisplayImplGTK::GetDepth() const
return 24;
}
wxSize wxDisplayImplGTK::GetSizeMM() const
{
return wxSize
(
gdk_monitor_get_width_mm(m_monitor),
gdk_monitor_get_height_mm(m_monitor)
);
}
#if wxUSE_DISPLAY
bool wxDisplayImplGTK::IsPrimary() const
{
@@ -212,6 +222,7 @@ public:
virtual wxRect GetGeometry() const wxOVERRIDE;
virtual wxRect GetClientArea() const wxOVERRIDE;
virtual int GetDepth() const wxOVERRIDE;
virtual wxSize GetSizeMM() const wxOVERRIDE;
#if wxUSE_DISPLAY
virtual bool IsPrimary() const wxOVERRIDE;
@@ -282,6 +293,34 @@ int wxDisplayImplGTK::GetDepth() const
return gdk_visual_get_depth(gdk_window_get_visual(wxGetTopLevelGDK()));
}
wxSize wxDisplayImplGTK::GetSizeMM() const
{
// At least in some configurations, gdk_screen_xxx_mm() functions return
// valid values when gdk_screen_get_monitor_xxx_mm() only return -1, so
// handle this case specially.
if ( IsPrimary() )
{
return wxSize(gdk_screen_width_mm(), gdk_screen_height_mm());
}
wxSize sizeMM;
#if GTK_CHECK_VERSION(2,14,0)
if ( wx_is_at_least_gtk2(14) )
{
// Take care not to return (-1, -1) from here, the caller expects us to
// return (0, 0) if we can't retrieve this information.
int rc = gdk_screen_get_monitor_width_mm(m_screen, m_index);
if ( rc != -1 )
sizeMM.x = rc;
rc = gdk_screen_get_monitor_height_mm(m_screen, m_index);
if ( rc != -1 )
sizeMM.y = rc;
}
#endif // GTK+ 2.14
return sizeMM;
}
#if wxUSE_DISPLAY
bool wxDisplayImplGTK::IsPrimary() const
{

View File

@@ -76,20 +76,6 @@ void *wxGetDisplay()
}
#endif
void wxDisplaySizeMM( int *width, int *height )
{
#ifdef __WXGTK4__
GdkMonitor* monitor = gdk_display_get_primary_monitor(gdk_display_get_default());
if (width) *width = gdk_monitor_get_width_mm(monitor);
if (height) *height = gdk_monitor_get_height_mm(monitor);
#else
wxGCC_WARNING_SUPPRESS(deprecated-declarations)
if (width) *width = gdk_screen_width_mm();
if (height) *height = gdk_screen_height_mm();
wxGCC_WARNING_RESTORE()
#endif
}
wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
{
return wxGenericFindWindowAtPoint(pt);

View File

@@ -86,12 +86,6 @@ void *wxGetDisplay()
return GDK_DISPLAY();
}
void wxDisplaySizeMM( int *width, int *height )
{
if (width) *width = gdk_screen_width_mm();
if (height) *height = gdk_screen_height_mm();
}
void wxGetMousePosition( int* x, int* y )
{
gdk_window_get_pointer( NULL, x, y, NULL );

View File

@@ -225,16 +225,6 @@ void wxGetMousePosition( int* x, int* y )
#endif
}
void wxDisplaySizeMM(int *width, int *height)
{
Display *dpy = wxGlobalDisplay();
if ( width )
*width = DisplayWidthMM(dpy, DefaultScreen (dpy));
if ( height )
*height = DisplayHeightMM(dpy, DefaultScreen (dpy));
}
// Configurable display in wxX11 and wxMotif
static WXDisplay *gs_currentDisplay = NULL;
static wxString gs_displayName;

View File

@@ -26,9 +26,14 @@
#include "wx/private/display.h"
#include "wx/dynlib.h"
#include "wx/msw/private.h"
#include "wx/msw/wrapwin.h"
namespace
{
int wxGetHDCDepth(HDC hdc)
{
return ::GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
@@ -62,6 +67,13 @@ public:
{
return wxGetHDCDepth(ScreenHDC());
}
virtual wxSize GetSizeMM() const wxOVERRIDE
{
ScreenHDC dc;
return wxSize(::GetDeviceCaps(dc, HORZSIZE), ::GetDeviceCaps(dc, VERTSIZE));
}
};
class wxDisplayFactorySingleMSW : public wxDisplayFactorySingle
@@ -73,6 +85,8 @@ protected:
}
};
} // anonymous namespace
#if wxUSE_DISPLAY
#ifndef WX_PRECOMP
@@ -87,6 +101,10 @@ protected:
#include "wx/msw/missing.h"
#include "wx/msw/private/hiddenwin.h"
#ifndef DPI_ENUMS_DECLARED
#define MDT_EFFECTIVE_DPI 0
#endif
static const wxChar displayDllName[] = wxT("user32.dll");
namespace
@@ -119,6 +137,8 @@ public:
virtual wxRect GetGeometry() const wxOVERRIDE;
virtual wxRect GetClientArea() const wxOVERRIDE;
virtual int GetDepth() const wxOVERRIDE;
virtual wxSize GetPPI() const wxOVERRIDE;
virtual wxString GetName() const wxOVERRIDE;
virtual bool IsPrimary() const wxOVERRIDE;
@@ -176,6 +196,13 @@ public:
// handles.
static void RefreshMonitors() { ms_factory->DoRefreshMonitors(); }
// Declare the second argument as int to avoid problems with older SDKs not
// declaring MONITOR_DPI_TYPE enum.
typedef HRESULT (WINAPI *GetDpiForMonitor_t)(HMONITOR, int, UINT*, UINT*);
// Return the pointer to GetDpiForMonitor() function which may be null if
// not running under new enough Windows version.
static GetDpiForMonitor_t GetDpiForMonitorPtr();
private:
// EnumDisplayMonitors() callback
@@ -197,6 +224,48 @@ private:
// variable (also making it of correct type for us) here).
static wxDisplayFactoryMSW* ms_factory;
// The pointer to GetDpiForMonitorPtr(), retrieved on demand, and the
// related data, including the DLL containing the function that we must
// keep loaded.
struct GetDpiForMonitorData
{
GetDpiForMonitorData()
{
m_pfnGetDpiForMonitor = NULL;
m_initialized = false;
}
bool TryLoad()
{
if ( !m_dllShcore.Load("shcore.dll", wxDL_VERBATIM | wxDL_QUIET) )
return false;
wxDL_INIT_FUNC(m_pfn, GetDpiForMonitor, m_dllShcore);
if ( !m_pfnGetDpiForMonitor )
{
m_dllShcore.Unload();
return false;
}
return true;
}
void UnloadIfNecessary()
{
if ( m_dllShcore.IsLoaded() )
{
m_dllShcore.Unload();
m_pfnGetDpiForMonitor = NULL;
}
}
wxDynamicLibrary m_dllShcore;
GetDpiForMonitor_t m_pfnGetDpiForMonitor;
bool m_initialized;
};
static GetDpiForMonitorData ms_getDpiForMonitorData;
// the array containing information about all available displays, filled by
// MultimonEnumProc()
@@ -211,6 +280,8 @@ private:
};
wxDisplayFactoryMSW* wxDisplayFactoryMSW::ms_factory = NULL;
wxDisplayFactoryMSW::GetDpiForMonitorData
wxDisplayFactoryMSW::ms_getDpiForMonitorData;
// ----------------------------------------------------------------------------
// wxDisplay implementation
@@ -272,6 +343,24 @@ int wxDisplayMSW::GetDepth() const
return m_info.depth;
}
wxSize wxDisplayMSW::GetPPI() const
{
if ( const wxDisplayFactoryMSW::GetDpiForMonitor_t
getFunc = wxDisplayFactoryMSW::GetDpiForMonitorPtr() )
{
UINT dpiX = 0,
dpiY = 0;
const HRESULT
hr = (*getFunc)(m_info.hmon, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
if ( SUCCEEDED(hr) )
return wxSize(dpiX, dpiY);
wxLogApiError("GetDpiForMonitor", hr);
}
return IsPrimary() ? wxDisplayImplSingleMSW().GetPPI() : wxSize(0, 0);
}
wxString wxDisplayMSW::GetName() const
{
WinStruct<MONITORINFOEX> monInfo;
@@ -492,9 +581,28 @@ wxDisplayFactoryMSW::~wxDisplayFactoryMSW()
}
}
if ( ms_getDpiForMonitorData.m_initialized )
{
ms_getDpiForMonitorData.UnloadIfNecessary();
ms_getDpiForMonitorData.m_initialized = false;
}
ms_factory = NULL;
}
/* static */
wxDisplayFactoryMSW::GetDpiForMonitor_t
wxDisplayFactoryMSW::GetDpiForMonitorPtr()
{
if ( !ms_getDpiForMonitorData.m_initialized )
{
ms_getDpiForMonitorData.m_initialized = true;
ms_getDpiForMonitorData.TryLoad();
}
return ms_getDpiForMonitorData.m_pfnGetDpiForMonitor;
}
void wxDisplayFactoryMSW::DoRefreshMonitors()
{
m_displays.clear();

View File

@@ -117,16 +117,6 @@ void wxGetMousePosition( int* x, int* y )
if ( y ) *y = pt.y;
}
void wxDisplaySizeMM(int *width, int *height)
{
ScreenHDC dc;
if ( width )
*width = ::GetDeviceCaps(dc, HORZSIZE);
if ( height )
*height = ::GetDeviceCaps(dc, VERTSIZE);
}
// ---------------------------------------------------------------------------
// window information functions
// ---------------------------------------------------------------------------

View File

@@ -75,6 +75,12 @@ int wxGetDisplayDepth(CGDirectDisplayID id)
return theDepth;
}
wxSize wxGetDisplaySizeMM(CGDirectDisplayID id)
{
const CGSize size = CGDisplayScreenSize(id);
return wxSize(wxRound(size.width), wxRound(size.height));
}
} // anonymous namespace
#if wxUSE_DISPLAY
@@ -97,6 +103,7 @@ public:
virtual wxRect GetGeometry() const wxOVERRIDE;
virtual wxRect GetClientArea() const wxOVERRIDE;
virtual int GetDepth() const wxOVERRIDE;
virtual wxSize GetSizeMM() const wxOVERRIDE;
virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const wxOVERRIDE;
virtual wxVideoMode GetCurrentMode() const wxOVERRIDE;
@@ -258,6 +265,11 @@ int wxDisplayImplMacOSX::GetDepth() const
return wxGetDisplayDepth(m_id);
}
wxSize wxDisplayImplMacOSX::GetSizeMM() const
{
return wxGetDisplaySizeMM(m_id);
}
static int wxOSXCGDisplayModeGetBitsPerPixel( CGDisplayModeRef theValue )
{
wxCFRef<CFStringRef> pixelEncoding( CGDisplayModeCopyPixelEncoding(theValue) );
@@ -373,6 +385,11 @@ public:
{
return wxGetDisplayDepth(CGMainDisplayID());
}
virtual wxSize GetSizeMM() const wxOVERRIDE
{
return wxGetDisplaySizeMM(CGMainDisplayID());
}
};
class wxDisplayFactorySingleMacOSX : public wxDisplayFactorySingle

View File

@@ -160,6 +160,11 @@ public:
{
return 32; // TODO can we determine this ?
}
virtual wxSize GetPPI() const wxOVERRIDE
{
return wxSize(72, 72);
}
};
class wxDisplayFactorySingleiOS : public wxDisplayFactorySingle

View File

@@ -106,28 +106,6 @@ bool wxDoLaunchDefaultBrowser(const wxLaunchBrowserParams& params)
#endif
void wxDisplaySizeMM(int *width, int *height)
{
#if wxOSX_USE_IPHONE
wxDisplaySize(width, height);
// on mac 72 is fixed (at least now;-)
double cvPt2Mm = 25.4 / 72;
if (width != NULL)
*width = int( *width * cvPt2Mm );
if (height != NULL)
*height = int( *height * cvPt2Mm );
#else
CGSize size = CGDisplayScreenSize(CGMainDisplayID());
if ( width )
*width = (int)size.width ;
if ( height )
*height = (int)size.height;
#endif
}
wxPortId wxGUIAppTraits::GetToolkitVersion(int *verMaj,
int *verMin,
int *verMicro) const

View File

@@ -22,6 +22,7 @@ public:
virtual wxRect GetGeometry() const wxOVERRIDE;
virtual wxRect GetClientArea() const wxOVERRIDE;
virtual int GetDepth() const wxOVERRIDE;
virtual wxSize GetSizeMM() const wxOVERRIDE;
#if wxUSE_DISPLAY
virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const wxOVERRIDE;
@@ -50,6 +51,13 @@ int wxDisplayImplQt::GetDepth() const
return IsPrimary() ? QApplication::desktop()->depth() : 0;
}
wxSize wxDisplayImplQt::GetSizeMM() const
{
return IsPrimary() ? wxSize(QApplication::desktop()->widthMM(),
QApplication::desktop()->heightMM())
: wxSize(0, 0);
}
#if wxUSE_DISPLAY
wxArrayVideoModes wxDisplayImplQt::GetModes(const wxVideoMode& WXUNUSED(mode)) const
{

View File

@@ -110,14 +110,6 @@ bool wxGetKeyState(wxKeyCode key)
}
}
void wxDisplaySizeMM(int *width, int *height)
{
if ( width != NULL )
*width = QApplication::desktop()->widthMM();
if ( height != NULL )
*height = QApplication::desktop()->heightMM();
}
void wxBell()
{
QApplication::beep();

View File

@@ -44,6 +44,17 @@ inline int wxGetMainScreenDepth()
return DefaultDepth(dpy, DefaultScreen (dpy));
}
inline wxSize wxGetMainScreenSizeMM()
{
Display* const dpy = wxGetX11Display();
return wxSize
(
DisplayWidthMM(dpy, DefaultScreen(dpy)),
DisplayHeightMM(dpy, DefaultScreen(dpy))
);
}
class wxDisplayImplSingleX11 : public wxDisplayImplSingle
{
public:
@@ -65,6 +76,11 @@ public:
{
return wxGetMainScreenDepth();
}
virtual wxSize GetSizeMM() const wxOVERRIDE
{
return wxGetMainScreenSizeMM();
}
};
class wxDisplayFactorySingleX11 : public wxDisplayFactorySingle
@@ -143,6 +159,11 @@ public:
return wxGetMainScreenDepth();
}
virtual wxSize GetSizeMM() const wxOVERRIDE
{
// TODO: how to get physical size or resolution of the other monitors?
return IsPrimary() ? wxGetMainScreenSizeMM() : wxSize(0, 0);
}
virtual wxArrayVideoModes GetModes(const wxVideoMode& mode) const wxOVERRIDE;
virtual wxVideoMode GetCurrentMode() const wxOVERRIDE;

View File

@@ -148,16 +148,6 @@ void wxGetMousePosition( int* x, int* y )
#endif
};
void wxDisplaySizeMM(int *width, int *height)
{
Display *dpy = (Display*) wxGetDisplay();
if ( width )
*width = DisplayWidthMM(dpy, DefaultScreen (dpy));
if ( height )
*height = DisplayHeightMM(dpy, DefaultScreen (dpy));
}
wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
{
return wxGenericFindWindowAtPoint(pt);