Fix #9993: Handle DPI changes on macOS and Windows

This commit is contained in:
Bouke Haarsma 2022-09-07 22:17:10 +02:00 committed by Michael Lutz
parent bda602f4b0
commit 45d98f689a
7 changed files with 86 additions and 2 deletions

View File

@ -10,6 +10,7 @@
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness>
</windowsSettings>
</application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">

View File

@ -17,10 +17,12 @@
#include "settings_type.h"
#include "network/network.h"
#include "network/network_func.h"
#include "window_gui.h"
#include "window_func.h"
#include "newgrf_debug.h"
#include "thread.h"
#include "core/backup_type.hpp"
#include "viewport_func.h"
#include "table/palettes.h"
#include "table/string_colours.h"
@ -2042,6 +2044,38 @@ void UpdateGUIZoom()
}
}
/**
* Resolve GUI zoom level and adjust GUI to new zoom, if auto-suggestion is requested.
* @returns true when the zoom level has changed, caller must call ReInitAllWindows(true)
* after resizing the application's window/buffer.
*/
bool AdjustGUIZoom()
{
auto old_zoom = _gui_zoom;
UpdateGUIZoom();
if (old_zoom == _gui_zoom) return false;
GfxClearSpriteCache();
VideoDriver::GetInstance()->ClearSystemSprites();
ClearFontCache();
GfxClearSpriteCache();
UpdateAllVirtCoords();
/* Adjust all window sizes to match the new zoom level, so that they don't appear
to move around when the application is moved to a screen with different DPI. */
auto zoom_shift = old_zoom - _gui_zoom;
for (Window *w : Window::Iterate()) {
w->left = AdjustByZoom(w->left, zoom_shift);
w->top = AdjustByZoom(w->top, zoom_shift);
w->width = AdjustByZoom(w->width, zoom_shift);
w->height = AdjustByZoom(w->height, zoom_shift);
if (w->viewport != nullptr) {
w->viewport->zoom = Clamp(ZoomLevel(w->viewport->zoom - zoom_shift), _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
}
}
return true;
}
void ChangeGameSpeed(bool enable_fast_forward)
{
if (enable_fast_forward) {

View File

@ -80,6 +80,7 @@ void DrawMouseCursor();
void ScreenSizeChanged();
void GameSizeChanged();
void UpdateGUIZoom();
bool AdjustGUIZoom();
void UndrawMouseCursor();
/** Size of the buffer used for drawing strings. */

View File

@ -1269,8 +1269,12 @@ void CocoaDialog(const char *title, const char *message, const char *buttonLabel
/** Screen the window is on changed. */
- (void)windowDidChangeBackingProperties:(NSNotification *)notification
{
bool did_adjust = AdjustGUIZoom();
/* Reallocate screen buffer if necessary. */
driver->AllocateBackingStore();
if (did_adjust) ReInitAllWindows(true);
}
/** Presentation options to use for full screen mode. */

View File

@ -38,6 +38,10 @@
#define PM_QS_INPUT 0x20000
#endif
#ifndef WM_DPICHANGED
#define WM_DPICHANGED 0x02E0
#endif
bool _window_maximize;
static Dimension _bck_resolution;
DWORD _imm_props;
@ -670,6 +674,24 @@ LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
return TRUE;
}
case WM_DPICHANGED: {
auto did_adjust = AdjustGUIZoom();
/* Resize the window to match the new DPI setting. */
RECT *prcNewWindow = (RECT *)lParam;
SetWindowPos(hwnd,
NULL,
prcNewWindow->left,
prcNewWindow->top,
prcNewWindow->right - prcNewWindow->left,
prcNewWindow->bottom - prcNewWindow->top,
SWP_NOZORDER | SWP_NOACTIVATE);
if (did_adjust) ReInitAllWindows(true);
return 0;
}
/* needed for wheel */
#if !defined(WM_MOUSEWHEEL)
# define WM_MOUSEWHEEL 0x020A

View File

@ -3343,6 +3343,13 @@ void HideVitalWindows()
CloseWindowById(WC_STATUS_BAR, 0);
}
void ReInitWindow(Window *w, bool zoom_changed)
{
if (w == nullptr) return;
if (zoom_changed) w->nested_root->AdjustPaddingForZoom();
w->ReInit();
}
/** Re-initialize all windows. */
void ReInitAllWindows(bool zoom_changed)
{
@ -3352,9 +3359,13 @@ void ReInitAllWindows(bool zoom_changed)
extern void InitDepotWindowBlockSizes();
InitDepotWindowBlockSizes();
/* When _gui_zoom has changed, we need to resize toolbar and statusbar first,
* so EnsureVisibleCaption uses the updated size information. */
ReInitWindow(FindWindowById(WC_MAIN_TOOLBAR, 0), zoom_changed);
ReInitWindow(FindWindowById(WC_STATUS_BAR, 0), zoom_changed);
for (Window *w : Window::Iterate()) {
if (zoom_changed) w->nested_root->AdjustPaddingForZoom();
w->ReInit();
if (w->window_class == WC_MAIN_TOOLBAR || w->window_class == WC_STATUS_BAR) continue;
ReInitWindow(w, zoom_changed);
}
void NetworkReInitChatBoxSize();

View File

@ -36,6 +36,17 @@ static inline int UnScaleByZoom(int value, ZoomLevel zoom)
return (value + (1 << zoom) - 1) >> zoom;
}
/**
* Adjust by zoom level; zoom < 0 shifts right, zoom >= 0 shifts left
* @param value value to shift
* @param zoom zoom level to shift to
* @return shifted value
*/
static inline int AdjustByZoom(int value, int zoom)
{
return zoom < 0 ? UnScaleByZoom(value, ZoomLevel(-zoom)) : ScaleByZoom(value, ZoomLevel(zoom));
}
/**
* Scale by zoom level, usually shift left (when zoom > ZOOM_LVL_NORMAL)
* @param value value to shift