Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
[[ Bug 21305 ]] Cache often used Win32 metrics
This patch caches the screen dpi and non-client metrics in the MCScreenDC
class on open, with them being updated whenever a WM_SETTINGCHANGE or
WM_DISPLAYCHANGE message is received. This metrics are used frequently,
especially when serializing fields, and caching vastly improves the speed
of the operations using them.

To facilitate the caching and update of the metrics, a new method
`updatemetrics()` has been added to MCScreenDC, which is called when opened
and during `processdesktopchanged()`.
  • Loading branch information
runrevmark committed Apr 30, 2020
commit 99d27f7a20811d79100b65a64fc41da74b65654f
58 changes: 35 additions & 23 deletions engine/src/w32dc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ MCScreenDC::MCScreenDC()
m_printer_dc = NULL;
m_printer_dc_locked = false;
m_printer_dc_changed = false;

/* Initialize metrics with sensible defaults. */
m_metrics_x_dpi = 96;
m_metrics_y_dpi = 96;
memset(&m_metrics_non_client, 0, sizeof(m_metrics_non_client));
}

MCScreenDC::~MCScreenDC()
Expand Down Expand Up @@ -289,28 +294,38 @@ MCStack *MCScreenDC::platform_getstackatpoint(int32_t x, int32_t y)

///////////////////////////////////////////////////////////////////////////////

void *MCScreenDC::GetNativeWindowHandle(Window p_win)
{
return p_win != nil ? p_win->handle.window : nil;
}

///////////////////////////////////////////////////////////////////////////////

// IM-2014-01-28: [[ HiDPI ]] Return the x & y dpi of the main screen
bool MCWin32GetScreenDPI(uint32_t &r_xdpi, uint32_t &r_ydpi)
void MCScreenDC::updatemetrics(void)
{
/* Get the DC representing the whole 'screen' so we can get default dpi
* metrics from it. */
HDC t_dc;
t_dc = GetDC(NULL);
if (t_dc != NULL)
{
m_metrics_x_dpi = GetDeviceCaps(t_dc, LOGPIXELSX);
m_metrics_y_dpi = GetDeviceCaps(t_dc, LOGPIXELSY);
ReleaseDC(NULL, t_dc);
}
else
{
m_metrics_x_dpi = 96;
m_metrics_y_dpi = 96;
}

if (t_dc == NULL)
return false;

r_xdpi = GetDeviceCaps(t_dc, LOGPIXELSX);
r_ydpi = GetDeviceCaps(t_dc, LOGPIXELSY);
/* Fetch the 'non-client-metrics' which contains the names of fonts to use
* which match the current system settings. */
m_metrics_non_client.cbSize = sizeof(m_metrics_non_client);
if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(m_metrics_non_client), &m_metrics_non_client, 0))
{
memset(&m_metrics_non_client, 0, sizeof(m_metrics_non_client));
}
}

ReleaseDC(NULL, t_dc);
///////////////////////////////////////////////////////////////////////////////

return true;
void *MCScreenDC::GetNativeWindowHandle(Window p_win)
{
return p_win != nil ? p_win->handle.window : nil;
}

///////////////////////////////////////////////////////////////////////////////
Expand All @@ -329,7 +344,8 @@ MCGFloat MCWin32GetLogicalToScreenScale(void)
return 1.0;

uint32_t t_x, t_y;
/* UNCHECKED */ MCWin32GetScreenDPI(t_x, t_y);
t_x = ((MCScreenDC *)MCscreen)->getscreenxdpi();
t_y = ((MCScreenDC *)MCscreen)->getscreenydpi();

return (MCGFloat) MCMax(t_x, t_y) / NORMAL_DENSITY;
}
Expand All @@ -348,12 +364,8 @@ bool MCWin32GetMonitorPixelScale(HMONITOR p_monitor, MCGFloat &r_pixel_scale)
if (!MCWin32GetDpiForMonitor(t_result, p_monitor, kMCWin32MDTDefault, &t_xdpi, &t_ydpi) ||
t_result != S_OK)
{
// fallback to the global system DPI setting
uint32_t t_screen_xdpi, t_screen_ydpi;
if (!MCWin32GetScreenDPI(t_screen_xdpi, t_screen_ydpi))
return false;
t_xdpi = t_screen_xdpi;
t_ydpi = t_screen_ydpi;
t_xdpi = ((MCScreenDC *)MCscreen)->getscreenxdpi();
t_ydpi = ((MCScreenDC *)MCscreen)->getscreenydpi();
}

r_pixel_scale = (MCGFloat)MCMax(t_xdpi, t_ydpi) / NORMAL_DENSITY;
Expand Down
12 changes: 12 additions & 0 deletions engine/src/w32dc.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ class MCScreenDC : public MCUIDC
int m_main_window_depth = 0;
HWND m_main_window_current = nullptr;

uint32_t m_metrics_x_dpi;
uint32_t m_metrics_y_dpi;
NONCLIENTMETRICSW m_metrics_non_client;

protected:
static uint4 pen_inks[];
static uint4 image_inks[];
Expand Down Expand Up @@ -355,13 +359,21 @@ class MCScreenDC : public MCUIDC
void processdesktopchanged(bool p_notify = true, bool p_update_fonts = true);
void processtaskbarnotify(HWND hwnd, WPARAM wparam, LPARAM lparam);

uint32_t getscreenxdpi(void) const { return m_metrics_x_dpi; }
uint32_t getscreenydpi(void) const { return m_metrics_y_dpi; }
const NONCLIENTMETRICSW& getnonclientmetrics(void) const { return m_metrics_non_client; }

// These rountines convert a UTF-8 string into with a 'WIDE' or 'ANSI'
// string suitable for passing to a windows API W or A function. The
// caller is reponsible for freeing the returned string.
static LPWSTR convertutf8towide(const char *p_utf8_string);
static LPCSTR convertutf8toansi(const char *p_utf8_string);

private:
/* Refetch any system metric information that may be changed by either a
* WM_SETTINGCHANGE or WM_DISPALYCHANGE message. */
void updatemetrics(void);

bool initialisebackdrop(void);
void finalisebackdrop(void);
};
Expand Down
7 changes: 7 additions & 0 deletions engine/src/w32dcs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,10 @@ Boolean MCScreenDC::open()
MCdoubletime = GetDoubleClickTime();
opened++;

/* Fetch any system metrics we need which are updated on WM_SETTINGCHANGE or
* WM_DISPLAYCHANGE. */
updatemetrics();

MCDisplay const *t_displays;
getdisplays(t_displays, false);
MCwbr = t_displays[0] . workarea;
Expand Down Expand Up @@ -1128,6 +1132,9 @@ void MCScreenDC::processdesktopchanged(bool p_notify, bool p_update_fonts)
bool t_changed;
t_changed = false;

/* Update any system metrics which are used often and are cached. */
updatemetrics();

updatedisplayinfo(t_changed);

if (t_changed && (backdrop_active || backdrop_hard))
Expand Down
33 changes: 19 additions & 14 deletions engine/src/windows-theme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,35 +30,36 @@
#include "stack.h"
#include "font.h"

#ifndef _SERVER
#include "w32dc.h"
#endif

static bool logfont_for_control(MCPlatformControlType p_type, LOGFONTW& r_lf)
{
#ifndef _SERVER
// Get the font used for the non-client areas of Windows. This font
// gets used throughout the Windows UI.
bool t_found;
NONCLIENTMETRICSW ncm;
ncm.cbSize = sizeof(ncm);
t_found = SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
if (t_found)
const NONCLIENTMETRICSW& t_ncm = ((MCScreenDC *)MCscreen)->getnonclientmetrics();
if (t_ncm.cbSize != 0)
{
// Which LOGFONT structure contains the info for this control?
LOGFONTW* lf = NULL;
const LOGFONTW* lf = NULL;
switch (p_type)
{
case kMCPlatformControlTypeTooltip:
lf = &ncm.lfStatusFont;
lf = &t_ncm.lfStatusFont;
break;

case kMCPlatformControlTypeMenu:
case kMCPlatformControlTypeMenuItem:
case kMCPlatformControlTypeOptionMenu:
case kMCPlatformControlTypePulldownMenu:
case kMCPlatformControlTypePopupMenu:
lf = &ncm.lfMenuFont;
lf = &t_ncm.lfMenuFont;
break;

default:
lf = &ncm.lfMessageFont;
lf = &t_ncm.lfMessageFont;
break;
}

Expand All @@ -71,15 +72,16 @@ static bool logfont_for_control(MCPlatformControlType p_type, LOGFONTW& r_lf)
}

return false;
#else
return false;
#endif
}

bool MCPlatformGetControlThemePropBool(MCPlatformControlType, MCPlatformControlPart, MCPlatformControlState, MCPlatformThemeProperty, bool&)
{
return false;
}

extern bool MCWin32GetScreenDPI(uint32_t&, uint32_t&);

// Density used by default for the Win32 UI
#define NORMAL_DENSITY 96

Expand All @@ -99,11 +101,14 @@ bool MCPlatformGetControlThemePropInteger(MCPlatformControlType p_type, MCPlatfo
{
// Scale compared to the "normal" windows scale
uint32_t t_x_dpi, t_y_dpi;

#ifndef _SERVER
if (!MCWin32GetScreenDPI(t_x_dpi, t_y_dpi))
t_x_dpi = ((MCScreenDC *)MCscreen)->getscreenxdpi();
t_y_dpi = ((MCScreenDC *)MCscreen)->getscreenydpi();
#else
t_x_dpi = t_y_dpi = NORMAL_DENSITY;
#endif
t_x_dpi = t_y_dpi = NORMAL_DENSITY;


// Get the size from the LOGFONT structure
r_int = MCGFloat(-lf.lfHeight) / (MCGFloat(MCMax(t_x_dpi, t_y_dpi)) / NORMAL_DENSITY);
}
Expand Down