Browse Source

Win32 Shell: Support Per Monitor DPI awareness on Windows 10. Change 'dp'-ratio with ctrl +/-/0 keys.

Michael Ragazzon 5 years ago
parent
commit
b0fbb7fa04

+ 3 - 0
Samples/shell/include/Shell.h

@@ -92,6 +92,9 @@ public:
 	
 	
 	/// Sets the RmlUi context to send window resized events to.
 	/// Sets the RmlUi context to send window resized events to.
 	static void SetContext(Rml::Context* context);
 	static void SetContext(Rml::Context* context);
+
+	/// Sets the RmlUi context to send window resized events to.
+	static float GetDensityIndependentPixelRatio();
 };
 };
 
 
 #include "ShellSystemInterface.h"
 #include "ShellSystemInterface.h"

+ 5 - 3
Samples/shell/include/win32/IncludeWindows.h

@@ -29,10 +29,12 @@
 #ifndef RMLUI_SHELL_WIN32_INCLUDEWINDOWS_H
 #ifndef RMLUI_SHELL_WIN32_INCLUDEWINDOWS_H
 #define RMLUI_SHELL_WIN32_INCLUDEWINDOWS_H
 #define RMLUI_SHELL_WIN32_INCLUDEWINDOWS_H
 
 
-#if !defined _WIN32_WINNT || _WIN32_WINNT < 0x0501
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
+#if !defined _WIN32_WINNT || _WIN32_WINNT < 0x0601
+	#undef _WIN32_WINNT
+	// Target Windows 7
+	#define _WIN32_WINNT 0x0601
 #endif
 #endif
+
 #define UNICODE
 #define UNICODE
 #define _UNICODE
 #define _UNICODE
 #define WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN

+ 20 - 4
Samples/shell/src/win32/InputWin32.cpp

@@ -29,6 +29,7 @@
 #include <win32/InputWin32.h>
 #include <win32/InputWin32.h>
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Context.h>
 #include <RmlUi/Core/Input.h>
 #include <RmlUi/Core/Input.h>
+#include <RmlUi/Core/Math.h>
 #include <RmlUi/Core/StringUtilities.h>
 #include <RmlUi/Core/StringUtilities.h>
 #include <RmlUi/Debugger.h>
 #include <RmlUi/Debugger.h>
 #include <Shell.h>
 #include <Shell.h>
@@ -97,14 +98,29 @@ void InputWin32::ProcessWindowsEvent(HWND window, UINT message, WPARAM w_param,
 			Rml::Input::KeyIdentifier key_identifier = key_identifier_map[w_param];
 			Rml::Input::KeyIdentifier key_identifier = key_identifier_map[w_param];
 			int key_modifier_state = GetKeyModifierState();
 			int key_modifier_state = GetKeyModifierState();
 
 
-			// Check for F8 to toggle the debugger.
+			// Toggle debugger and set 'dp'-ratio ctrl +/-/0 keys
 			if (key_identifier == Rml::Input::KI_F8)
 			if (key_identifier == Rml::Input::KI_F8)
 			{
 			{
 				Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible());
 				Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible());
-				break;
 			}
 			}
-
-			context->ProcessKeyDown(key_identifier, key_modifier_state);
+			else if (key_identifier == Rml::Input::KI_0 && key_modifier_state & Rml::Input::KM_CTRL)
+			{
+				context->SetDensityIndependentPixelRatio(key_modifier_state == Rml::Input::KM_SHIFT ? 1.f : Shell::GetDensityIndependentPixelRatio());
+			}
+			else if (key_identifier == Rml::Input::KI_OEM_MINUS && key_modifier_state & Rml::Input::KM_CTRL)
+			{
+				const float new_dp_ratio = Rml::Math::Max(context->GetDensityIndependentPixelRatio() / 1.2f, 0.5f);
+				context->SetDensityIndependentPixelRatio(new_dp_ratio);
+			}
+			else if (key_identifier == Rml::Input::KI_OEM_PLUS && key_modifier_state & Rml::Input::KM_CTRL)
+			{
+				const float new_dp_ratio = Rml::Math::Min(context->GetDensityIndependentPixelRatio() * 1.2f, 2.5f);
+				context->SetDensityIndependentPixelRatio(new_dp_ratio);
+			}
+			else
+			{
+				context->ProcessKeyDown(key_identifier, key_modifier_state);
+			}
 		}
 		}
 		break;
 		break;
 
 

+ 91 - 4
Samples/shell/src/win32/ShellWin32.cpp

@@ -46,6 +46,8 @@ static Rml::U16String instance_name;
 static HWND window_handle = nullptr;
 static HWND window_handle = nullptr;
 static HINSTANCE instance_handle = nullptr;
 static HINSTANCE instance_handle = nullptr;
 
 
+static bool has_dpi_support = false;
+static UINT window_dpi = USER_DEFAULT_SCREEN_DPI;
 static int window_width = 0;
 static int window_width = 0;
 static int window_height = 0;
 static int window_height = 0;
 
 
@@ -63,6 +65,37 @@ static HCURSOR cursor_text = nullptr;
 static HCURSOR cursor_unavailable = nullptr;
 static HCURSOR cursor_unavailable = nullptr;
 
 
 
 
+#ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
+#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE)-4)
+#endif
+#ifndef WM_DPICHANGED
+#define WM_DPICHANGED 0x02E0
+#endif
+
+// Declare pointers to the DPI aware Windows API functions.
+using ProcSetProcessDpiAwarenessContext = BOOL(WINAPI*)(HANDLE value);
+using ProcGetDpiForWindow = UINT(WINAPI*)(HWND hwnd);
+using ProcAdjustWindowRectExForDpi = BOOL(WINAPI*)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);
+
+static ProcSetProcessDpiAwarenessContext procSetProcessDpiAwarenessContext = NULL;
+static ProcGetDpiForWindow procGetDpiForWindow = NULL;
+static ProcAdjustWindowRectExForDpi procAdjustWindowRectExForDpi = NULL;
+
+
+static void UpdateDpi()
+{
+	if (has_dpi_support)
+	{
+		UINT dpi = procGetDpiForWindow(window_handle);
+		if (dpi != 0)
+		{
+			window_dpi = dpi;
+			if (context)
+				context->SetDensityIndependentPixelRatio(Shell::GetDensityIndependentPixelRatio());
+		}
+	}
+}
+
 static void UpdateWindowDimensions(int width = 0, int height = 0)
 static void UpdateWindowDimensions(int width = 0, int height = 0)
 {
 {
 	if (width > 0)
 	if (width > 0)
@@ -101,6 +134,23 @@ bool Shell::Initialise()
 	file_interface = Rml::MakeUnique<ShellFileInterface>(root);
 	file_interface = Rml::MakeUnique<ShellFileInterface>(root);
 	Rml::SetFileInterface(file_interface.get());
 	Rml::SetFileInterface(file_interface.get());
 
 
+	// See if we have Per Monitor V2 DPI awareness. Requires Windows 10, version 1703.
+	// Cast function pointers to void* first for MinGW not to emit errors.
+	procSetProcessDpiAwarenessContext = (ProcSetProcessDpiAwarenessContext)(void*)GetProcAddress(
+		GetModuleHandle(TEXT("User32.dll")),
+		"SetProcessDpiAwarenessContext"
+	);
+	procGetDpiForWindow = (ProcGetDpiForWindow)(void*)GetProcAddress(
+		GetModuleHandle(TEXT("User32.dll")),
+		"GetDpiForWindow"
+	);
+	procAdjustWindowRectExForDpi = (ProcAdjustWindowRectExForDpi)(void*)GetProcAddress(
+		GetModuleHandle(TEXT("User32.dll")),
+		"AdjustWindowRectExForDpi"
+	);
+
+	has_dpi_support = (procSetProcessDpiAwarenessContext != NULL && procGetDpiForWindow != NULL && procAdjustWindowRectExForDpi != NULL);
+
 	return result;
 	return result;
 }
 }
 
 
@@ -146,8 +196,15 @@ Rml::String Shell::FindSamplesRoot()
 	return Rml::String();
 	return Rml::String();
 }
 }
 
 
+
 bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize)
 bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_shell_renderer, unsigned int width, unsigned int height, bool allow_resize)
 {
 {
+	// Activate Per Monitor V2.
+	if (has_dpi_support && !procSetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
+	{
+		has_dpi_support = false;
+	}
+
 	WNDCLASSW window_class;
 	WNDCLASSW window_class;
 
 
 	Rml::U16String name = Rml::StringUtilities::ToUTF16(Rml::String(in_name));
 	Rml::U16String name = Rml::StringUtilities::ToUTF16(Rml::String(in_name));
@@ -177,7 +234,7 @@ bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_she
 								   (LPCWSTR)name.data(),
 								   (LPCWSTR)name.data(),
 								   WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
 								   WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
 								   0, 0,	// Window position.
 								   0, 0,	// Window position.
-								   width, height,// Window size.
+								   0, 0,// Window size.
 								   nullptr,
 								   nullptr,
 								   nullptr,
 								   nullptr,
 								   instance_handle,
 								   instance_handle,
@@ -193,6 +250,10 @@ bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_she
 	window_width = width;
 	window_width = width;
 	window_height = height;
 	window_height = height;
 
 
+	UpdateDpi();
+	window_width = (width * window_dpi) / USER_DEFAULT_SCREEN_DPI;
+	window_height = (height * window_dpi) / USER_DEFAULT_SCREEN_DPI;
+
 	instance_name = name;
 	instance_name = name;
 
 
 	DWORD style = (allow_resize ? WS_OVERLAPPEDWINDOW : (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX));
 	DWORD style = (allow_resize ? WS_OVERLAPPEDWINDOW : (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX));
@@ -202,9 +263,12 @@ bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_she
 	RECT window_rect;
 	RECT window_rect;
 	window_rect.top = 0;
 	window_rect.top = 0;
 	window_rect.left = 0;
 	window_rect.left = 0;
-	window_rect.right = width;
-	window_rect.bottom = height;
-	AdjustWindowRectEx(&window_rect, style, FALSE, extended_style);
+	window_rect.right = window_width;
+	window_rect.bottom = window_height;
+	if (has_dpi_support)
+		procAdjustWindowRectExForDpi(&window_rect, style, FALSE, extended_style, window_dpi);
+	else
+		AdjustWindowRectEx(&window_rect, style, FALSE, extended_style);
 
 
 	SetWindowLong(window_handle, GWL_EXSTYLE, extended_style);
 	SetWindowLong(window_handle, GWL_EXSTYLE, extended_style);
 	SetWindowLong(window_handle, GWL_STYLE, style);
 	SetWindowLong(window_handle, GWL_STYLE, style);
@@ -219,6 +283,8 @@ bool Shell::OpenWindow(const char* in_name, ShellRenderInterfaceExtensions *_she
 		}
 		}
 	}
 	}
 
 
+	UpdateWindowDimensions();
+
 	// Resize the window.
 	// Resize the window.
 	SetWindowPos(window_handle, HWND_TOP, 0, 0, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top, SWP_NOACTIVATE);
 	SetWindowPos(window_handle, HWND_TOP, 0, 0, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top, SWP_NOACTIVATE);
 
 
@@ -399,9 +465,15 @@ void Shell::GetClipboardText(Rml::String& text)
 void Shell::SetContext(Rml::Context* new_context)
 void Shell::SetContext(Rml::Context* new_context)
 {
 {
 	context = new_context;
 	context = new_context;
+	UpdateDpi();
 	UpdateWindowDimensions();
 	UpdateWindowDimensions();
 }
 }
 
 
+float Shell::GetDensityIndependentPixelRatio()
+{
+	return float(window_dpi) / float(USER_DEFAULT_SCREEN_DPI);
+}
+
 static LRESULT CALLBACK WindowProcedure(HWND local_window_handle, UINT message, WPARAM w_param, LPARAM l_param)
 static LRESULT CALLBACK WindowProcedure(HWND local_window_handle, UINT message, WPARAM w_param, LPARAM l_param)
 {
 {
 	// See what kind of message we've got.
 	// See what kind of message we've got.
@@ -436,6 +508,21 @@ static LRESULT CALLBACK WindowProcedure(HWND local_window_handle, UINT message,
 		}
 		}
 		break;
 		break;
 
 
+		case WM_DPICHANGED:
+		{
+			UpdateDpi();
+
+			RECT* const new_pos = (RECT*)l_param;
+			SetWindowPos(window_handle,
+				NULL,
+				new_pos->left,
+				new_pos->top,
+				new_pos->right - new_pos->left,
+				new_pos->bottom - new_pos->top,
+				SWP_NOZORDER | SWP_NOACTIVATE);
+		}
+		break;
+
 		default:
 		default:
 		{
 		{
 			InputWin32::ProcessWindowsEvent(local_window_handle, message, w_param, l_param);
 			InputWin32::ProcessWindowsEvent(local_window_handle, message, w_param, l_param);