Merge branch 'per-monitor-dpi-aware-framework' of https://github.com/MaartenBent/wxWidgets

Add preliminary support for per-monitor DPI awareness to wxMSW.

Individual controls still need to be fixed, so this support is still
experimental/unfinished for now.

See https://github.com/wxWidgets/wxWidgets/pull/1499
This commit is contained in:
Vadim Zeitlin
2019-08-27 12:59:56 +02:00
18 changed files with 335 additions and 28 deletions

View File

@@ -2830,6 +2830,7 @@ WX_MSW_DECLARE_HANDLE(HBITMAP);
WX_MSW_DECLARE_HANDLE(HIMAGELIST); WX_MSW_DECLARE_HANDLE(HIMAGELIST);
WX_MSW_DECLARE_HANDLE(HGLOBAL); WX_MSW_DECLARE_HANDLE(HGLOBAL);
WX_MSW_DECLARE_HANDLE(HDC); WX_MSW_DECLARE_HANDLE(HDC);
WX_MSW_DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
typedef WXHINSTANCE WXHMODULE; typedef WXHINSTANCE WXHMODULE;
#undef WX_MSW_DECLARE_HANDLE #undef WX_MSW_DECLARE_HANDLE

View File

@@ -641,6 +641,7 @@ class WXDLLIMPEXP_FWD_CORE wxMenuEvent;
class WXDLLIMPEXP_FWD_CORE wxContextMenuEvent; class WXDLLIMPEXP_FWD_CORE wxContextMenuEvent;
class WXDLLIMPEXP_FWD_CORE wxSysColourChangedEvent; class WXDLLIMPEXP_FWD_CORE wxSysColourChangedEvent;
class WXDLLIMPEXP_FWD_CORE wxDisplayChangedEvent; class WXDLLIMPEXP_FWD_CORE wxDisplayChangedEvent;
class WXDLLIMPEXP_FWD_CORE wxDPIChangedEvent;
class WXDLLIMPEXP_FWD_CORE wxQueryNewPaletteEvent; class WXDLLIMPEXP_FWD_CORE wxQueryNewPaletteEvent;
class WXDLLIMPEXP_FWD_CORE wxPaletteChangedEvent; class WXDLLIMPEXP_FWD_CORE wxPaletteChangedEvent;
class WXDLLIMPEXP_FWD_CORE wxJoystickEvent; class WXDLLIMPEXP_FWD_CORE wxJoystickEvent;
@@ -793,6 +794,7 @@ wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_MENU_HIGHLIGHT, wxMenuEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_CONTEXT_MENU, wxContextMenuEvent); wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_CONTEXT_MENU, wxContextMenuEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEvent); wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_DISPLAY_CHANGED, wxDisplayChangedEvent); wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_DISPLAY_CHANGED, wxDisplayChangedEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_DPI_CHANGED, wxDPIChangedEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_QUERY_NEW_PALETTE, wxQueryNewPaletteEvent); wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_QUERY_NEW_PALETTE, wxQueryNewPaletteEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_PALETTE_CHANGED, wxPaletteChangedEvent); wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_PALETTE_CHANGED, wxPaletteChangedEvent);
wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_JOY_BUTTON_DOWN, wxJoystickEvent); wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_JOY_BUTTON_DOWN, wxJoystickEvent);
@@ -3031,6 +3033,32 @@ public:
virtual wxEvent *Clone() const wxOVERRIDE { return new wxDisplayChangedEvent(*this); } virtual wxEvent *Clone() const wxOVERRIDE { return new wxDisplayChangedEvent(*this); }
}; };
/*
wxEVT_DPI_CHANGED
*/
class WXDLLIMPEXP_CORE wxDPIChangedEvent : public wxEvent
{
public:
explicit
wxDPIChangedEvent(const wxSize& oldDPI = wxDefaultSize,
const wxSize& newDPI = wxDefaultSize)
: wxEvent(0, wxEVT_DPI_CHANGED),
m_oldDPI(oldDPI),
m_newDPI(newDPI)
{ }
wxSize GetOldDPI() const { return m_oldDPI; }
wxSize GetNewDPI() const { return m_newDPI; }
virtual wxEvent *Clone() const wxOVERRIDE { return new wxDPIChangedEvent(*this); }
private:
wxSize m_oldDPI;
wxSize m_newDPI;
wxDECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxDPIChangedEvent);
};
/* /*
wxEVT_PALETTE_CHANGED wxEVT_PALETTE_CHANGED
*/ */
@@ -4108,6 +4136,7 @@ typedef void (wxEvtHandler::*wxDropFilesEventFunction)(wxDropFilesEvent&);
typedef void (wxEvtHandler::*wxInitDialogEventFunction)(wxInitDialogEvent&); typedef void (wxEvtHandler::*wxInitDialogEventFunction)(wxInitDialogEvent&);
typedef void (wxEvtHandler::*wxSysColourChangedEventFunction)(wxSysColourChangedEvent&); typedef void (wxEvtHandler::*wxSysColourChangedEventFunction)(wxSysColourChangedEvent&);
typedef void (wxEvtHandler::*wxDisplayChangedEventFunction)(wxDisplayChangedEvent&); typedef void (wxEvtHandler::*wxDisplayChangedEventFunction)(wxDisplayChangedEvent&);
typedef void (wxEvtHandler::*wxDPIChangedEventFunction)(wxDPIChangedEvent&);
typedef void (wxEvtHandler::*wxUpdateUIEventFunction)(wxUpdateUIEvent&); typedef void (wxEvtHandler::*wxUpdateUIEventFunction)(wxUpdateUIEvent&);
typedef void (wxEvtHandler::*wxCloseEventFunction)(wxCloseEvent&); typedef void (wxEvtHandler::*wxCloseEventFunction)(wxCloseEvent&);
typedef void (wxEvtHandler::*wxShowEventFunction)(wxShowEvent&); typedef void (wxEvtHandler::*wxShowEventFunction)(wxShowEvent&);
@@ -4171,6 +4200,8 @@ typedef void (wxEvtHandler::*wxPressAndTapEventFunction)(wxPressAndTapEvent&);
wxEVENT_HANDLER_CAST(wxSysColourChangedEventFunction, func) wxEVENT_HANDLER_CAST(wxSysColourChangedEventFunction, func)
#define wxDisplayChangedEventHandler(func) \ #define wxDisplayChangedEventHandler(func) \
wxEVENT_HANDLER_CAST(wxDisplayChangedEventFunction, func) wxEVENT_HANDLER_CAST(wxDisplayChangedEventFunction, func)
#define wxDPIChangedEventHandler(func) \
wxEVENT_HANDLER_CAST(wxDPIChangedEventFunction, func)
#define wxUpdateUIEventHandler(func) \ #define wxUpdateUIEventHandler(func) \
wxEVENT_HANDLER_CAST(wxUpdateUIEventFunction, func) wxEVENT_HANDLER_CAST(wxUpdateUIEventFunction, func)
#define wxCloseEventHandler(func) \ #define wxCloseEventHandler(func) \
@@ -4430,6 +4461,7 @@ typedef void (wxEvtHandler::*wxPressAndTapEventFunction)(wxPressAndTapEvent&);
#define EVT_INIT_DIALOG(func) wx__DECLARE_EVT0(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(func)) #define EVT_INIT_DIALOG(func) wx__DECLARE_EVT0(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(func))
#define EVT_SYS_COLOUR_CHANGED(func) wx__DECLARE_EVT0(wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEventHandler(func)) #define EVT_SYS_COLOUR_CHANGED(func) wx__DECLARE_EVT0(wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEventHandler(func))
#define EVT_DISPLAY_CHANGED(func) wx__DECLARE_EVT0(wxEVT_DISPLAY_CHANGED, wxDisplayChangedEventHandler(func)) #define EVT_DISPLAY_CHANGED(func) wx__DECLARE_EVT0(wxEVT_DISPLAY_CHANGED, wxDisplayChangedEventHandler(func))
#define EVT_DPI_CHANGED(func) wx__DECLARE_EVT0(wxEVT_DPI_CHANGED, wxDPIChangedEventHandler(func))
#define EVT_SHOW(func) wx__DECLARE_EVT0(wxEVT_SHOW, wxShowEventHandler(func)) #define EVT_SHOW(func) wx__DECLARE_EVT0(wxEVT_SHOW, wxShowEventHandler(func))
#define EVT_MAXIMIZE(func) wx__DECLARE_EVT0(wxEVT_MAXIMIZE, wxMaximizeEventHandler(func)) #define EVT_MAXIMIZE(func) wx__DECLARE_EVT0(wxEVT_MAXIMIZE, wxMaximizeEventHandler(func))
#define EVT_ICONIZE(func) wx__DECLARE_EVT0(wxEVT_ICONIZE, wxIconizeEventHandler(func)) #define EVT_ICONIZE(func) wx__DECLARE_EVT0(wxEVT_ICONIZE, wxIconizeEventHandler(func))

View File

@@ -501,6 +501,13 @@ public:
// account as well. // account as well.
static int GetNumericWeightOf(wxFontWeight weight); static int GetNumericWeightOf(wxFontWeight weight);
// Some ports need to modify the font object when the DPI of the window it
// is used with changes, this function can be used to do it.
//
// Currently it is only used in wxMSW and is not considered to be part of
// wxWidgets public API.
virtual void WXAdjustToPPI(const wxSize& WXUNUSED(ppi)) { }
// this doesn't do anything and is kept for compatibility only // this doesn't do anything and is kept for compatibility only
#if WXWIN_COMPATIBILITY_2_8 #if WXWIN_COMPATIBILITY_2_8
wxDEPRECATED_INLINE(void SetNoAntiAliasing(bool no = true), wxUnusedVar(no);) wxDEPRECATED_INLINE(void SetNoAntiAliasing(bool no = true), wxUnusedVar(no);)

View File

@@ -120,25 +120,17 @@ public:
#elif defined(__WXMSW__) #elif defined(__WXMSW__)
wxNativeFontInfo(const LOGFONT& lf_) wxNativeFontInfo(const LOGFONT& lf_)
: lf(lf_), : lf(lf_),
pointSize(GetPointSizeFromLogFontHeight(lf.lfHeight)) pointSize(GetPointSizeAtPPI(lf.lfHeight))
{ {
} }
// MSW-specific: get point size from LOGFONT height using the default DPI. // MSW-specific: get point size from LOGFONT height using specified DPI,
static float GetPointSizeFromLogFontHeight(int height); // or screen DPI when 0.
static float GetPointSizeAtPPI(int lfHeight, int ppi = 0);
// MSW-specific: get the height value in pixels using LOGFONT convention // MSW-specific: get the height value in pixels using LOGFONT convention
// (i.e. negative) corresponding to the given size in points and DPI. // (i.e. negative) corresponding to the given size in points and DPI.
static int GetLogFontHeightAtPPI(float size, int ppi) static int GetLogFontHeightAtPPI(float size, int ppi);
{
return -wxRound(size * ppi / 72.0);
}
// And the same thing for the size of this font.
int GetLogFontHeightAtPPI(int ppi) const
{
return GetLogFontHeightAtPPI(pointSize, ppi);
}
LOGFONT lf; LOGFONT lf;

View File

@@ -120,6 +120,8 @@ public:
virtual bool IsFixedWidth() const wxOVERRIDE; virtual bool IsFixedWidth() const wxOVERRIDE;
virtual void WXAdjustToPPI(const wxSize& ppi) wxOVERRIDE;
wxDEPRECATED_MSG("use wxFONT{FAMILY,STYLE,WEIGHT}_XXX constants ie: wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD") wxDEPRECATED_MSG("use wxFONT{FAMILY,STYLE,WEIGHT}_XXX constants ie: wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD")
wxFont(int size, wxFont(int size,
int family, int family,

View File

@@ -23,7 +23,11 @@
#endif #endif
#ifndef WM_PRINTCLIENT #ifndef WM_PRINTCLIENT
#define WM_PRINTCLIENT 0x318 #define WM_PRINTCLIENT 0x0318
#endif
#ifndef WM_DPICHANGED
#define WM_DPICHANGED 0x02E0
#endif #endif
#ifndef DT_HIDEPREFIX #ifndef DT_HIDEPREFIX

View File

@@ -165,6 +165,9 @@ protected:
int& x, int& y, int& x, int& y,
int& w, int& h) const wxOVERRIDE; int& w, int& h) const wxOVERRIDE;
// WM_DPICHANGED handler.
bool HandleDPIChange(const wxSize& newDPI, const wxRect& newRect);
// This field contains the show command to use when showing the window the // This field contains the show command to use when showing the window the
// next time and also indicates whether the window should be considered // next time and also indicates whether the window should be considered
// being iconized or maximized (which may be different from whether it's // being iconized or maximized (which may be different from whether it's
@@ -191,6 +194,14 @@ protected:
wxWindowRef m_winLastFocused; wxWindowRef m_winLastFocused;
private: private:
// Keep track of the DPI used in this window. So when per-monitor dpi
// awareness is enabled, both old and new DPI are known for
// wxDPIChangedEvent and wxWindow::MSWUpdateOnDPIChange.
wxSize m_activeDPI;
// This window supports handling per-monitor DPI awareness when the
// application manifest contains <dpiAwareness>PerMonitorV2</dpiAwareness>.
bool m_perMonitorDPIaware;
// The system menu: initially NULL but can be set (once) by // The system menu: initially NULL but can be set (once) by
// MSWGetSystemMenu(). Owned by this window. // MSWGetSystemMenu(). Owned by this window.

View File

@@ -586,7 +586,17 @@ public:
// Should be overridden by all classes storing the "last focused" window. // Should be overridden by all classes storing the "last focused" window.
virtual void WXDoUpdatePendingFocus(wxWindow* WXUNUSED(win)) {} virtual void WXDoUpdatePendingFocus(wxWindow* WXUNUSED(win)) {}
// Called from WM_DPICHANGED handler for all windows to let them update
// any sizes and fonts used internally when the DPI changes and generate
// wxDPIChangedEvent to let the user code do the same thing as well.
void MSWUpdateOnDPIChange(const wxSize& oldDPI, const wxSize& newDPI);
protected: protected:
// Called from MSWUpdateOnDPIChange() specifically to update the control
// font, as this may need to be done differently for some specific native
// controls. The default version updates m_font of this window.
virtual void MSWUpdateFontOnDPIChange(const wxSize& newDPI);
// this allows you to implement standard control borders without // this allows you to implement standard control borders without
// repeating the code in different classes that are not derived from // repeating the code in different classes that are not derived from
// wxControl // wxControl

View File

@@ -3318,6 +3318,62 @@ public:
}; };
/**
@class wxDPIChangedEvent
Event sent when the resolution (measured in dots-per-inch, or DPI) of the
monitor a window is on changes.
The event is sent to each wxTopLevelWindow affected by the change, and all
its children recursively. For example, this event is sent to the window
when it is moved, by the user, from a display using some DPI value to
another display using a different DPI value. It also sent to all program
windows on the given display if its DPI changes due to a change in the
system settings.
Currently this event is generated by wxMSW port if only and only if the
MSW application runs under Windows 10 Creators Update (v1703) or later and
is marked as being "per-monitor DPI aware", i.e. contains a @c dpiAwareness
tag with the value "PerMonitorV2" in its manifest (see Microsoft
<a href="https://docs.microsoft.com/en-us/windows/desktop/sbscs/application-manifests">"Application Manifests" documentation</a>
for more details).
@note Per-monitor DPI support is an experimental feature that is still in
development. It might not work correctly for some controls.
@beginEventTable{wxDPIChangedEvent}
@event{EVT_DPI_CHANGED(func)}
Process a @c wxEVT_DPI_CHANGED event.
@endEventTable
@since 3.1.3
@library{wxcore}
@category{events}
@see @ref overview_events
*/
class wxDPIChangedEvent : public wxEvent
{
public:
/**
Returns the old DPI.
@since 3.1.3
*/
wxSize GetOldDPI() const;
/**
Returns the new DPI.
@since 3.1.3
*/
wxSize GetNewDPI() const;
};
class wxPaletteChangedEvent : public wxEvent class wxPaletteChangedEvent : public wxEvent
{ {
public: public:

View File

@@ -2044,7 +2044,7 @@ public:
If the DPI is not available, returns @c wxSize(0,0) object. If the DPI is not available, returns @c wxSize(0,0) object.
@see wxDisplay::GetPPI() @see wxDisplay::GetPPI(), wxDPIChangedEvent
@since 3.1.3 @since 3.1.3
*/ */

View File

@@ -92,6 +92,7 @@
wxIMPLEMENT_DYNAMIC_CLASS(wxSetCursorEvent, wxEvent); wxIMPLEMENT_DYNAMIC_CLASS(wxSetCursorEvent, wxEvent);
wxIMPLEMENT_DYNAMIC_CLASS(wxSysColourChangedEvent, wxEvent); wxIMPLEMENT_DYNAMIC_CLASS(wxSysColourChangedEvent, wxEvent);
wxIMPLEMENT_DYNAMIC_CLASS(wxDisplayChangedEvent, wxEvent); wxIMPLEMENT_DYNAMIC_CLASS(wxDisplayChangedEvent, wxEvent);
wxIMPLEMENT_DYNAMIC_CLASS(wxDPIChangedEvent, wxEvent);
wxIMPLEMENT_DYNAMIC_CLASS(wxUpdateUIEvent, wxCommandEvent); wxIMPLEMENT_DYNAMIC_CLASS(wxUpdateUIEvent, wxCommandEvent);
wxIMPLEMENT_DYNAMIC_CLASS(wxNavigationKeyEvent, wxEvent); wxIMPLEMENT_DYNAMIC_CLASS(wxNavigationKeyEvent, wxEvent);
wxIMPLEMENT_DYNAMIC_CLASS(wxPaletteChangedEvent, wxEvent); wxIMPLEMENT_DYNAMIC_CLASS(wxPaletteChangedEvent, wxEvent);
@@ -302,6 +303,7 @@ wxDEFINE_EVENT( wxEVT_MENU_HIGHLIGHT, wxMenuEvent );
wxDEFINE_EVENT( wxEVT_CONTEXT_MENU, wxContextMenuEvent ); wxDEFINE_EVENT( wxEVT_CONTEXT_MENU, wxContextMenuEvent );
wxDEFINE_EVENT( wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEvent ); wxDEFINE_EVENT( wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEvent );
wxDEFINE_EVENT( wxEVT_DISPLAY_CHANGED, wxDisplayChangedEvent ); wxDEFINE_EVENT( wxEVT_DISPLAY_CHANGED, wxDisplayChangedEvent );
wxDEFINE_EVENT( wxEVT_DPI_CHANGED, wxDPIChangedEvent );
wxDEFINE_EVENT( wxEVT_QUERY_NEW_PALETTE, wxQueryNewPaletteEvent ); wxDEFINE_EVENT( wxEVT_QUERY_NEW_PALETTE, wxQueryNewPaletteEvent );
wxDEFINE_EVENT( wxEVT_PALETTE_CHANGED, wxPaletteChangedEvent ); wxDEFINE_EVENT( wxEVT_PALETTE_CHANGED, wxPaletteChangedEvent );
wxDEFINE_EVENT( wxEVT_JOY_BUTTON_DOWN, wxJoystickEvent ); wxDEFINE_EVENT( wxEVT_JOY_BUTTON_DOWN, wxJoystickEvent );

View File

@@ -1726,6 +1726,8 @@ wxFont wxWindowBase::GetFont() const
if ( !font.IsOk() ) if ( !font.IsOk() )
font = GetClassDefaultAttributes().font; font = GetClassDefaultAttributes().font;
font.WXAdjustToPPI(GetDPI());
return font; return font;
} }
else else
@@ -1744,6 +1746,9 @@ bool wxWindowBase::SetFont(const wxFont& font)
m_hasFont = font.IsOk(); m_hasFont = font.IsOk();
m_inheritFont = m_hasFont; m_inheritFont = m_hasFont;
if ( m_hasFont )
m_font.WXAdjustToPPI(GetDPI());
InvalidateBestSize(); InvalidateBestSize();
return true; return true;

View File

@@ -159,7 +159,8 @@ public:
int GetLogFontHeightAtPPI(int ppi) const int GetLogFontHeightAtPPI(int ppi) const
{ {
return m_nativeFontInfo.GetLogFontHeightAtPPI(ppi); return m_nativeFontInfo.GetLogFontHeightAtPPI(
m_nativeFontInfo.pointSize, ppi);
} }
// ... and setters: notice that all of them invalidate the currently // ... and setters: notice that all of them invalidate the currently
@@ -403,12 +404,18 @@ void wxFontRefData::Free()
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/* static */ /* static */
float wxNativeFontInfo::GetPointSizeFromLogFontHeight(int height) float wxNativeFontInfo::GetPointSizeAtPPI(int lfHeight, int ppi)
{ {
// Determine the size in points using the primary screen DPI as we don't if ( ppi == 0 )
// have anything else here. ppi = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY);
const float ppi = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY);
return 72.0f * abs(height) / ppi; return abs(lfHeight) * 72.0f / ppi;
}
/* static */
int wxNativeFontInfo::GetLogFontHeightAtPPI(float size, int ppi)
{
return -wxRound(size * ppi / 72.0f);
} }
void wxNativeFontInfo::Init() void wxNativeFontInfo::Init()
@@ -512,7 +519,8 @@ wxFontEncoding wxNativeFontInfo::GetEncoding() const
void wxNativeFontInfo::SetFractionalPointSize(float pointSizeNew) void wxNativeFontInfo::SetFractionalPointSize(float pointSizeNew)
{ {
// We don't have the correct DPI to use here, so use that of the // We don't have the correct DPI to use here, so use that of the
// primary screen. // primary screen and rely on WXAdjustToPPI() changing it later if
// necessary.
const int ppi = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY); const int ppi = ::GetDeviceCaps(ScreenHDC(), LOGPIXELSY);
lf.lfHeight = GetLogFontHeightAtPPI(pointSizeNew, ppi); lf.lfHeight = GetLogFontHeightAtPPI(pointSizeNew, ppi);
@@ -535,7 +543,7 @@ void wxNativeFontInfo::SetPixelSize(const wxSize& pixelSize)
// We don't have the right DPI to use here neither, but we need to update // We don't have the right DPI to use here neither, but we need to update
// the point size too, so fall back to the default. // the point size too, so fall back to the default.
pointSize = GetPointSizeFromLogFontHeight(lf.lfHeight); pointSize = GetPointSizeAtPPI(lf.lfHeight);
} }
void wxNativeFontInfo::SetStyle(wxFontStyle style) void wxNativeFontInfo::SetStyle(wxFontStyle style)
@@ -698,7 +706,7 @@ bool wxNativeFontInfo::FromString(const wxString& s)
return false; return false;
lf.lfHeight = l; lf.lfHeight = l;
if ( setPointSizeFromHeight ) if ( setPointSizeFromHeight )
pointSize = GetPointSizeFromLogFontHeight(l); pointSize = GetPointSizeAtPPI(l);
token = tokenizer.GetNextToken(); token = tokenizer.GetNextToken();
if ( !token.ToLong(&l) ) if ( !token.ToLong(&l) )
@@ -899,6 +907,19 @@ void wxFont::SetPixelSize(const wxSize& pixelSize)
M_FONTDATA->SetPixelSize(pixelSize); M_FONTDATA->SetPixelSize(pixelSize);
} }
void wxFont::WXAdjustToPPI(const wxSize& ppi)
{
// We only use vertical component here as we only adjust LOGFONT::lfHeight.
const int heightNew = M_FONTDATA->GetLogFontHeightAtPPI(ppi.y);
if ( heightNew != M_FONTDATA->GetLogFontHeight() )
{
AllocExclusive();
M_FONTDATA->SetLogFontHeight(heightNew);
}
}
void wxFont::SetFamily(wxFontFamily family) void wxFont::SetFamily(wxFontFamily family)
{ {
AllocExclusive(); AllocExclusive();

View File

@@ -392,7 +392,15 @@ void MenuDrawData::Init()
Offset = -12; Offset = -12;
Font = wxFont(wxNativeFontInfo(metrics.lfMenuFont)); wxNativeFontInfo info(metrics.lfMenuFont);
// wxNativeFontInfo constructor calculates the pointSize using the
// main screen DPI. But lfHeight is based on the window DPI.
if ( window )
{
info.pointSize = wxNativeFontInfo::GetPointSizeAtPPI(
info.lf.lfHeight, window->GetDPI().y);
}
Font = wxFont(info);
Theme = false; Theme = false;
} }

View File

@@ -397,8 +397,17 @@ void wxMessageDialog::AdjustButtonLabels()
wxFont wxMessageDialog::GetMessageFont() wxFont wxMessageDialog::GetMessageFont()
{ {
const wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL; const wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL;
const NONCLIENTMETRICS& ncm = wxMSWImpl::GetNonClientMetrics(win); wxNativeFontInfo info(wxMSWImpl::GetNonClientMetrics(win).lfMessageFont);
return wxNativeFontInfo(ncm.lfMessageFont);
// wxNativeFontInfo constructor calculates the pointSize using the
// main screen DPI. But lfHeight is based on the window DPI.
if ( win )
{
info.pointSize = wxNativeFontInfo::GetPointSizeAtPPI(
info.lf.lfHeight, win->GetDPI().y);
}
return info;
} }
int wxMessageDialog::ShowMessageBox() int wxMessageDialog::ShowMessageBox()

View File

@@ -183,8 +183,17 @@ wxFont wxSystemSettingsNative::GetFont(wxSystemFont index)
// controls may prefer to use lfStatusFont or lfCaptionFont if it // controls may prefer to use lfStatusFont or lfCaptionFont if it
// is more appropriate for them // is more appropriate for them
const wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL; const wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL;
const wxNativeFontInfo wxNativeFontInfo
info(wxMSWImpl::GetNonClientMetrics(win).lfMessageFont); info(wxMSWImpl::GetNonClientMetrics(win).lfMessageFont);
// wxNativeFontInfo constructor calculates the pointSize using the
// main screen DPI. But lfHeight is based on the window DPI.
if ( win )
{
info.pointSize = wxNativeFontInfo::GetPointSizeAtPPI(
info.lf.lfHeight, win->GetDPI().y);
}
gs_fontDefault = new wxFont(info); gs_fontDefault = new wxFont(info);
} }

View File

@@ -104,6 +104,9 @@ void wxTopLevelWindowMSW::Init()
m_fsIsShowing = false; m_fsIsShowing = false;
m_menuSystem = NULL; m_menuSystem = NULL;
m_activeDPI = wxDefaultSize;
m_perMonitorDPIaware = false;
} }
WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const WXDWORD wxTopLevelWindowMSW::MSWGetStyle(long style, WXDWORD *exflags) const
@@ -246,6 +249,26 @@ WXHWND wxTopLevelWindowMSW::MSWGetParent() const
return (WXHWND)hwndParent; return (WXHWND)hwndParent;
} }
bool wxTopLevelWindowMSW::HandleDPIChange(const wxSize& newDPI, const wxRect& newRect)
{
if ( !m_perMonitorDPIaware )
{
return false;
}
if ( newDPI != m_activeDPI )
{
MSWUpdateOnDPIChange(m_activeDPI, newDPI);
m_activeDPI = newDPI;
}
SetSize(newRect);
Refresh();
return true;
}
WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
{ {
WXLRESULT rc = 0; WXLRESULT rc = 0;
@@ -306,6 +329,17 @@ WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WX
#endif // #ifndef __WXUNIVERSAL__ #endif // #ifndef __WXUNIVERSAL__
} }
break; break;
case WM_DPICHANGED:
{
const RECT* const prcNewWindow =
reinterpret_cast<const RECT*>(lParam);
processed = HandleDPIChange(wxSize(LOWORD(wParam),
HIWORD(wParam)),
wxRectFromRECT(*prcNewWindow));
}
break;
} }
if ( !processed ) if ( !processed )
@@ -314,6 +348,47 @@ WXLRESULT wxTopLevelWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WX
return rc; return rc;
} }
namespace
{
static bool IsPerMonitorDPIAware(HWND hwnd)
{
bool dpiAware = false;
// Determine if 'Per Monitor v2' DPI awareness is enabled in the
// applications manifest.
#if wxUSE_DYNLIB_CLASS
#define WXDPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((WXDPI_AWARENESS_CONTEXT)-4)
typedef WXDPI_AWARENESS_CONTEXT(WINAPI * GetWindowDpiAwarenessContext_t)(HWND hwnd);
typedef BOOL(WINAPI * AreDpiAwarenessContextsEqual_t)(WXDPI_AWARENESS_CONTEXT dpiContextA, WXDPI_AWARENESS_CONTEXT dpiContextB);
static GetWindowDpiAwarenessContext_t s_pfnGetWindowDpiAwarenessContext = NULL;
static AreDpiAwarenessContextsEqual_t s_pfnAreDpiAwarenessContextsEqual = NULL;
static bool s_initDone = false;
if ( !s_initDone )
{
wxLoadedDLL dllUser32("user32.dll");
wxDL_INIT_FUNC(s_pfn, GetWindowDpiAwarenessContext, dllUser32);
wxDL_INIT_FUNC(s_pfn, AreDpiAwarenessContextsEqual, dllUser32);
s_initDone = true;
}
if ( s_pfnGetWindowDpiAwarenessContext && s_pfnAreDpiAwarenessContextsEqual )
{
WXDPI_AWARENESS_CONTEXT dpiAwarenessContext = s_pfnGetWindowDpiAwarenessContext(hwnd);
if ( s_pfnAreDpiAwarenessContextsEqual(dpiAwarenessContext, WXDPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) == TRUE )
{
dpiAware = true;
}
}
#endif // wxUSE_DYNLIB_CLASS
return dpiAware;
}
}
bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate, bool wxTopLevelWindowMSW::CreateDialog(const void *dlgTemplate,
const wxString& title, const wxString& title,
const wxPoint& pos, const wxPoint& pos,
@@ -484,6 +559,10 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent,
EnableCloseButton(false); EnableCloseButton(false);
} }
m_activeDPI = GetDPI();
m_perMonitorDPIaware = IsPerMonitorDPIAware(GetHwnd());
// for standard dialogs the dialog manager generates WM_CHANGEUISTATE // for standard dialogs the dialog manager generates WM_CHANGEUISTATE
// itself but for custom windows we have to do it ourselves in order to // itself but for custom windows we have to do it ourselves in order to
// make the keyboard indicators (such as underlines for accelerators and // make the keyboard indicators (such as underlines for accelerators and

View File

@@ -4837,6 +4837,65 @@ wxSize wxWindowMSW::GetDPI() const
return dpi; return dpi;
} }
void wxWindowMSW::MSWUpdateFontOnDPIChange(const wxSize& newDPI)
{
if ( m_font.IsOk() )
{
m_font.WXAdjustToPPI(newDPI);
// WXAdjustToPPI() changes the HFONT, so reassociate it with the window.
wxSetWindowFont(GetHwnd(), m_font);
}
}
// Helper function to update the given coordinate by the scaling factor if it
// is set, i.e. different from wxDefaultCoord.
static void ScaleCoordIfSet(int& coord, float scaleFactor)
{
if ( coord != wxDefaultCoord )
{
const float coordScaled = coord * scaleFactor;
coord = scaleFactor > 1.0 ? ceil(coordScaled) : floor(coordScaled);
}
}
void
wxWindowMSW::MSWUpdateOnDPIChange(const wxSize& oldDPI, const wxSize& newDPI)
{
// update min and max size if necessary
const float scaleFactor = (float)newDPI.y / oldDPI.y;
ScaleCoordIfSet(m_minHeight, scaleFactor);
ScaleCoordIfSet(m_minWidth, scaleFactor);
ScaleCoordIfSet(m_maxHeight, scaleFactor);
ScaleCoordIfSet(m_maxWidth, scaleFactor);
InvalidateBestSize();
// update font if necessary
MSWUpdateFontOnDPIChange(newDPI);
// update children
wxWindowList::compatibility_iterator current = GetChildren().GetFirst();
while ( current )
{
wxWindow *childWin = current->GetData();
// Update all children, except other top-level windows.
// These could be on a different monitor and will get their own
// dpi-changed event.
if ( childWin && !childWin->IsTopLevel() )
{
childWin->MSWUpdateOnDPIChange(oldDPI, newDPI);
}
current = current->GetNext();
}
wxDPIChangedEvent event(oldDPI, newDPI);
event.SetEventObject(this);
HandleWindowEvent(event);
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// colours and palettes // colours and palettes
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------