GDK-Win32: Enable HiDPI support for Windows

This enables HiDPI support for GTK+ on Windows, so that the
fonts and window look better on HiDPI displays.  Notes for the current
work:

-The DPI awareness enabling can be disabled if and only if an application
 manifest is not embedded in the app to enable DPI awareness AND a user
 compatibility setting is not set to limit DPI awareness for the app, via
 the envvar GDK_WIN32_DISABLE_HIDPI.  The app manifest/user setting for
 DPI awareness will always win against the envvar, and so the HiDPI items
 will be always setup in such scenarios, unless DPI awareness is disabled.

-Both automatic detection for the scaling factor and setting the scale
 factor using the GDK_SCALE envvar are supported, where the envvar takes
 precedence, which will therefore disable automatic scaling when
 resolution changes.

-I am unable to test the wintab items because I don't have such devices
 around.

https://bugzilla.gnome.org/show_bug.cgi?id=768081
This commit is contained in:
Chun-wei Fan
2016-06-27 13:16:43 +08:00
parent a64a0bc617
commit 4add92a431
13 changed files with 953 additions and 322 deletions

View File

@ -44,15 +44,18 @@
#include "gdkprivate-win32.h"
#include <glib/gprintf.h>
#include <cairo-win32.h>
#include "gdk.h"
#include "gdkdisplayprivate.h"
#include "gdkmonitorprivate.h"
#include "gdkwin32.h"
#include "gdkkeysyms.h"
#include "gdkdevicemanager-win32.h"
#include "gdkdeviceprivate.h"
#include "gdkdevice-wintab.h"
#include "gdkwin32dnd.h"
#include "gdkdisplay-win32.h"
#include "gdkdndprivate.h"
#include <windowsx.h>
@ -1059,17 +1062,17 @@ show_window_recurse (GdkWindow *window, gboolean hide_window)
{
if (gdk_window_get_state (window) & GDK_WINDOW_STATE_MAXIMIZED)
{
GtkShowWindow (GDK_WINDOW_HWND (window), SW_SHOWMAXIMIZED);
GtkShowWindow (window, SW_SHOWMAXIMIZED);
}
else
{
GtkShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
GtkShowWindow (window, SW_RESTORE);
}
}
}
else
{
GtkShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE);
GtkShowWindow (window, SW_MINIMIZE);
}
}
@ -1121,6 +1124,7 @@ send_crossing_event (GdkDisplay *display,
GdkDeviceGrabInfo *grab;
GdkDeviceManagerWin32 *device_manager;
POINT pt;
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
device_manager = GDK_DEVICE_MANAGER_WIN32 (gdk_display_get_device_manager (display));
@ -1142,10 +1146,10 @@ send_crossing_event (GdkDisplay *display,
event->crossing.window = window;
event->crossing.subwindow = subwindow;
event->crossing.time = _gdk_win32_get_next_tick (time_);
event->crossing.x = pt.x;
event->crossing.y = pt.y;
event->crossing.x_root = screen_pt->x + _gdk_offset_x;
event->crossing.y_root = screen_pt->y + _gdk_offset_y;
event->crossing.x = pt.x / impl->window_scale;
event->crossing.y = pt.y / impl->window_scale;
event->crossing.x_root = (screen_pt->x + _gdk_offset_x) / impl->window_scale;
event->crossing.y_root = (screen_pt->y + _gdk_offset_y) / impl->window_scale;
event->crossing.mode = mode;
event->crossing.detail = notify_type;
event->crossing.mode = mode;
@ -1449,8 +1453,8 @@ _gdk_win32_get_window_rect (GdkWindow *window,
if (gdk_window_get_parent (window) == gdk_get_default_root_window ())
{
ClientToScreen (hwnd, &point);
point.x += _gdk_offset_x;
point.y += _gdk_offset_y;
point.x += _gdk_offset_x * window_impl->window_scale;
point.y += _gdk_offset_y * window_impl->window_scale;
}
rect->left = point.x;
@ -1465,9 +1469,12 @@ void
_gdk_win32_do_emit_configure_event (GdkWindow *window,
RECT rect)
{
window->width = rect.right - rect.left;
window->height = rect.bottom - rect.top;
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
impl->unscaled_width = rect.right - rect.left;
impl->unscaled_height = rect.bottom - rect.top;
window->width = (impl->unscaled_width + impl->window_scale - 1) / impl->window_scale;
window->height = (impl->unscaled_height + impl->window_scale - 1) / impl->window_scale;
window->x = rect.left;
window->y = rect.top;
@ -1479,11 +1486,11 @@ _gdk_win32_do_emit_configure_event (GdkWindow *window,
event->configure.window = window;
event->configure.width = rect.right - rect.left;
event->configure.height = rect.bottom - rect.top;
event->configure.width = window->width;
event->configure.height = window->height;
event->configure.x = rect.left;
event->configure.y = rect.top;
event->configure.x = window->x;
event->configure.y = window->y;
_gdk_win32_append_event (event);
}
@ -1501,7 +1508,8 @@ _gdk_win32_emit_configure_event (GdkWindow *window)
}
cairo_region_t *
_gdk_win32_hrgn_to_region (HRGN hrgn)
_gdk_win32_hrgn_to_region (HRGN hrgn,
guint scale)
{
RGNDATA *rgndata;
RECT *rects;
@ -1532,8 +1540,8 @@ _gdk_win32_hrgn_to_region (HRGN hrgn)
r.x = rects[i].left;
r.y = rects[i].top;
r.width = rects[i].right - r.x;
r.height = rects[i].bottom - r.y;
r.width = (rects[i].right - r.x) / scale;
r.height = (rects[i].bottom - r.y) / scale;
cairo_region_union_rectangle (result, &r);
}
@ -1562,6 +1570,7 @@ handle_wm_paint (MSG *msg,
HDC hdc;
PAINTSTRUCT paintstruct;
cairo_region_t *update_region;
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
if (GetUpdateRgn (msg->hwnd, hrgn, FALSE) == ERROR)
{
@ -1587,7 +1596,7 @@ handle_wm_paint (MSG *msg,
return;
}
update_region = _gdk_win32_hrgn_to_region (hrgn);
update_region = _gdk_win32_hrgn_to_region (hrgn, impl->window_scale);
if (!cairo_region_is_empty (update_region))
_gdk_window_invalidate_for_expose (window, update_region);
cairo_region_destroy (update_region);
@ -1660,6 +1669,7 @@ handle_nchittest (HWND hwnd,
gint *ret_valp)
{
RECT rect;
GdkWindowImplWin32 *impl;
if (window == NULL || window->input_shape == NULL)
return FALSE;
@ -1673,11 +1683,14 @@ handle_nchittest (HWND hwnd,
if (!GetWindowRect (hwnd, &rect))
return FALSE;
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
rect.left = screen_x - rect.left;
rect.top = screen_y - rect.top;
/* If it's inside the rect, return FALSE and let DefWindowProc() handle it */
if (cairo_region_contains_point (window->input_shape, rect.left, rect.top))
if (cairo_region_contains_point (window->input_shape,
rect.left / impl->window_scale,
rect.top / impl->window_scale))
return FALSE;
/* Otherwise override DefWindowProc() and tell WM that the point is not
@ -1695,6 +1708,7 @@ generate_button_event (GdkEventType type,
{
GdkEvent *event = gdk_event_new (type);
GdkDeviceManagerWin32 *device_manager;
GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
if (_gdk_input_ignore_core)
return;
@ -1703,10 +1717,10 @@ generate_button_event (GdkEventType type,
event->button.window = window;
event->button.time = _gdk_win32_get_next_tick (msg->time);
event->button.x = current_x = (gint16) GET_X_LPARAM (msg->lParam);
event->button.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam);
event->button.x_root = msg->pt.x + _gdk_offset_x;
event->button.y_root = msg->pt.y + _gdk_offset_y;
event->button.x = current_x = (gint16) GET_X_LPARAM (msg->lParam) / impl->window_scale;
event->button.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam) / impl->window_scale;
event->button.x_root = (msg->pt.x + _gdk_offset_x) / impl->window_scale;
event->button.y_root = (msg->pt.y + _gdk_offset_y) / impl->window_scale;
event->button.axes = NULL;
event->button.state = build_pointer_event_state (msg);
event->button.button = button;
@ -1999,8 +2013,8 @@ _gdk_win32_window_fill_min_max_info (GdkWindow *window,
if (impl->hint_flags & GDK_HINT_MIN_SIZE)
{
rect.left = rect.top = 0;
rect.right = impl->hints.min_width;
rect.bottom = impl->hints.min_height;
rect.right = impl->hints.min_width * impl->window_scale;
rect.bottom = impl->hints.min_height * impl->window_scale;
_gdk_win32_adjust_client_rect (window, &rect);
@ -2013,8 +2027,8 @@ _gdk_win32_window_fill_min_max_info (GdkWindow *window,
int maxw, maxh;
rect.left = rect.top = 0;
rect.right = impl->hints.max_width;
rect.bottom = impl->hints.max_height;
rect.right = impl->hints.max_width * impl->window_scale;
rect.bottom = impl->hints.max_height * impl->window_scale;
_gdk_win32_adjust_client_rect (window, &rect);
@ -2047,8 +2061,8 @@ _gdk_win32_window_fill_min_max_info (GdkWindow *window,
mmi->ptMaxSize.y = nearest_info.rcWork.bottom - nearest_info.rcWork.top;
}
mmi->ptMaxTrackSize.x = GetSystemMetrics (SM_CXVIRTUALSCREEN) + impl->margins_x;
mmi->ptMaxTrackSize.y = GetSystemMetrics (SM_CYVIRTUALSCREEN) + impl->margins_y;
mmi->ptMaxTrackSize.x = GetSystemMetrics (SM_CXVIRTUALSCREEN) + impl->margins_x * impl->window_scale;
mmi->ptMaxTrackSize.y = GetSystemMetrics (SM_CYVIRTUALSCREEN) + impl->margins_y * impl->window_scale;
}
return TRUE;
@ -2755,19 +2769,19 @@ gdk_event_translate (MSG *msg,
}
g_set_object (&window, find_window_for_mouse_event (window, msg));
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
/* If we haven't moved, don't create any GDK event. Windows
* sends WM_MOUSEMOVE messages after a new window is shows under
* the mouse, even if the mouse hasn't moved. This disturbs gtk.
*/
if (msg->pt.x + _gdk_offset_x == current_root_x &&
msg->pt.y + _gdk_offset_y == current_root_y)
if ((msg->pt.x + _gdk_offset_x) / impl->window_scale == current_root_x &&
(msg->pt.y + _gdk_offset_y) / impl->window_scale == current_root_y)
break;
current_root_x = msg->pt.x + _gdk_offset_x;
current_root_y = msg->pt.y + _gdk_offset_y;
current_root_x = (msg->pt.x + _gdk_offset_x) / impl->window_scale;
current_root_y = (msg->pt.y + _gdk_offset_y) / impl->window_scale;
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
{
@ -2778,8 +2792,8 @@ gdk_event_translate (MSG *msg,
event = gdk_event_new (GDK_MOTION_NOTIFY);
event->motion.window = window;
event->motion.time = _gdk_win32_get_next_tick (msg->time);
event->motion.x = current_x = (gint16) GET_X_LPARAM (msg->lParam);
event->motion.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam);
event->motion.x = current_x = (gint16) GET_X_LPARAM (msg->lParam) / impl->window_scale;
event->motion.y = current_y = (gint16) GET_Y_LPARAM (msg->lParam) / impl->window_scale;
event->motion.x_root = current_root_x;
event->motion.y_root = current_root_y;
event->motion.axes = NULL;
@ -2891,6 +2905,7 @@ gdk_event_translate (MSG *msg,
g_set_object (&window, new_window);
}
impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
ScreenToClient (msg->hwnd, &point);
event = gdk_event_new (GDK_SCROLL);
@ -2903,10 +2918,10 @@ gdk_event_translate (MSG *msg,
event->scroll.direction = (((short) HIWORD (msg->wParam)) > 0) ?
GDK_SCROLL_RIGHT : GDK_SCROLL_LEFT;
event->scroll.time = _gdk_win32_get_next_tick (msg->time);
event->scroll.x = (gint16) point.x;
event->scroll.y = (gint16) point.y;
event->scroll.x_root = (gint16) GET_X_LPARAM (msg->lParam) + _gdk_offset_x;
event->scroll.y_root = (gint16) GET_Y_LPARAM (msg->lParam) + _gdk_offset_y;
event->scroll.x = (gint16) point.x / impl->window_scale;
event->scroll.y = (gint16) point.y / impl->window_scale;
event->scroll.x_root = ((gint16) GET_X_LPARAM (msg->lParam) + _gdk_offset_x) / impl->window_scale;
event->scroll.y_root = ((gint16) GET_Y_LPARAM (msg->lParam) + _gdk_offset_y) / impl->window_scale;
event->scroll.state = build_pointer_event_state (msg);
gdk_event_set_device (event, device_manager_win32->core_pointer);
gdk_event_set_source_device (event, device_manager_win32->system_pointer);
@ -3272,8 +3287,8 @@ gdk_event_translate (MSG *msg,
{
/* Resize in increments relative to the base size */
rect.left = rect.top = 0;
rect.right = impl->hints.base_width;
rect.bottom = impl->hints.base_height;
rect.right = impl->hints.base_width * impl->window_scale;
rect.bottom = impl->hints.base_height * impl->window_scale;
_gdk_win32_adjust_client_rect (window, &rect);
point.x = rect.left;
point.y = rect.top;
@ -3295,53 +3310,53 @@ gdk_event_translate (MSG *msg,
case WMSZ_BOTTOM:
if (drag->bottom == rect.bottom)
break;
adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc);
adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc * impl->window_scale);
break;
case WMSZ_BOTTOMLEFT:
if (drag->bottom == rect.bottom && drag->left == rect.left)
break;
adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc);
adjust_drag (&drag->left, rect.left, impl->hints.width_inc);
adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc * impl->window_scale);
adjust_drag (&drag->left, rect.left, impl->hints.width_inc * impl->window_scale);
break;
case WMSZ_LEFT:
if (drag->left == rect.left)
break;
adjust_drag (&drag->left, rect.left, impl->hints.width_inc);
adjust_drag (&drag->left, rect.left, impl->hints.width_inc * impl->window_scale);
break;
case WMSZ_TOPLEFT:
if (drag->top == rect.top && drag->left == rect.left)
break;
adjust_drag (&drag->top, rect.top, impl->hints.height_inc);
adjust_drag (&drag->left, rect.left, impl->hints.width_inc);
adjust_drag (&drag->top, rect.top, impl->hints.height_inc * impl->window_scale);
adjust_drag (&drag->left, rect.left, impl->hints.width_inc * impl->window_scale);
break;
case WMSZ_TOP:
if (drag->top == rect.top)
break;
adjust_drag (&drag->top, rect.top, impl->hints.height_inc);
adjust_drag (&drag->top, rect.top, impl->hints.height_inc * impl->window_scale);
break;
case WMSZ_TOPRIGHT:
if (drag->top == rect.top && drag->right == rect.right)
break;
adjust_drag (&drag->top, rect.top, impl->hints.height_inc);
adjust_drag (&drag->right, rect.right, impl->hints.width_inc);
adjust_drag (&drag->top, rect.top, impl->hints.height_inc * impl->window_scale);
adjust_drag (&drag->right, rect.right, impl->hints.width_inc * impl->window_scale);
break;
case WMSZ_RIGHT:
if (drag->right == rect.right)
break;
adjust_drag (&drag->right, rect.right, impl->hints.width_inc);
adjust_drag (&drag->right, rect.right, impl->hints.width_inc * impl->window_scale);
break;
case WMSZ_BOTTOMRIGHT:
if (drag->bottom == rect.bottom && drag->right == rect.right)
break;
adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc);
adjust_drag (&drag->right, rect.right, impl->hints.width_inc);
adjust_drag (&drag->bottom, rect.bottom, impl->hints.height_inc * impl->window_scale);
adjust_drag (&drag->right, rect.right, impl->hints.width_inc * impl->window_scale);
break;
}