Merge branch 'surface.compute.win32' into 'master'

Fix surface and geometry computation for Windows (Win32)

Closes #3480

See merge request GNOME/gtk!3067
This commit is contained in:
Matthias Clasen
2021-01-11 11:56:42 +00:00
3 changed files with 237 additions and 132 deletions

View File

@@ -1721,8 +1721,8 @@ _gdk_win32_surface_fill_min_max_info (GdkSurface *window,
mmi->ptMaxSize.y = nearest_info.rcWork.bottom - nearest_info.rcWork.top;
}
mmi->ptMaxTrackSize.x = GetSystemMetrics (SM_CXVIRTUALSCREEN) + impl->margins_x * impl->surface_scale;
mmi->ptMaxTrackSize.y = GetSystemMetrics (SM_CYVIRTUALSCREEN) + impl->margins_y * impl->surface_scale;
mmi->ptMaxTrackSize.x = GetSystemMetrics (SM_CXVIRTUALSCREEN) + impl->shadow_x * impl->surface_scale;
mmi->ptMaxTrackSize.y = GetSystemMetrics (SM_CYVIRTUALSCREEN) + impl->shadow_y * impl->surface_scale;
}
return TRUE;
@@ -2354,9 +2354,7 @@ gdk_event_translate (MSG *msg,
if (impl->drag_move_resize_context.op != GDK_WIN32_DRAGOP_NONE)
{
gdk_win32_surface_do_move_resize_drag (window, current_root_x, current_root_y);
}
gdk_win32_surface_do_move_resize_drag (window, current_root_x, current_root_y);
else if (_gdk_input_ignore_core == 0)
{
current_x = (gint16) GET_X_LPARAM (msg->lParam) / impl->surface_scale;
@@ -2835,6 +2833,16 @@ gdk_event_translate (MSG *msg,
else
unset_bits |= GDK_TOPLEVEL_STATE_MAXIMIZED;
/*
* If we are minizing, pause all surface layout computations, and re-start the
* computation once we are coming out of a minimized state
*/
if (!(old_state & GDK_TOPLEVEL_STATE_MINIMIZED) && set_bits & GDK_TOPLEVEL_STATE_MINIMIZED)
gdk_surface_freeze_updates (window);
if (old_state & GDK_TOPLEVEL_STATE_MINIMIZED && unset_bits & GDK_TOPLEVEL_STATE_MINIMIZED)
gdk_surface_thaw_updates (window);
gdk_surface_set_is_mapped (window, !!IsWindowVisible (msg->hwnd));
gdk_synthesize_surface_state (window, unset_bits, set_bits);

View File

@@ -53,6 +53,10 @@
#include <math.h>
static void gdk_surface_win32_finalize (GObject *object);
static void compute_toplevel_size (GdkSurface *surface,
gboolean update_geometry,
int *width,
int *height);
static gpointer parent_class = NULL;
static GSList *modal_window_stack = NULL;
@@ -1100,6 +1104,8 @@ gdk_win32_surface_resize (GdkSurface *window,
outer_rect.bottom - outer_rect.top,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER));
window->resize_count += 1;
gdk_surface_request_layout (window);
}
static void
@@ -1160,8 +1166,6 @@ gdk_win32_surface_move_resize_internal (GdkSurface *window,
{
GdkWin32Surface *surface = GDK_WIN32_SURFACE (window);
surface->inhibit_configure = TRUE;
/* We ignore changes to the window being moved or resized by the
user, as we don't want to fight the user */
if (GDK_SURFACE_HWND (window) == _modal_move_resize_window)
@@ -1186,8 +1190,6 @@ gdk_win32_surface_move_resize_internal (GdkSurface *window,
}
out:
surface->inhibit_configure = FALSE;
gdk_surface_request_layout (window);
}
@@ -1228,10 +1230,10 @@ gdk_win32_surface_layout_popup (GdkSurface *surface,
gdk_surface_layout_popup_helper (surface,
width,
height,
impl->margins.left,
impl->margins.right,
impl->margins.top,
impl->margins.bottom,
impl->shadow.left,
impl->shadow.right,
impl->shadow.top,
impl->shadow.bottom,
monitor,
&bounds,
layout,
@@ -1256,11 +1258,24 @@ gdk_win32_surface_layout_popup (GdkSurface *surface,
}
}
static void
maybe_notify_mapped (GdkSurface *surface)
{
if (surface->destroyed)
return;
if (!GDK_SURFACE_IS_MAPPED (surface))
{
gdk_surface_set_is_mapped (surface, TRUE);
gdk_surface_invalidate_rect (surface, NULL);
}
}
static void
show_popup (GdkSurface *surface)
{
gdk_win32_surface_raise (surface);
gdk_surface_set_is_mapped (surface, TRUE);
maybe_notify_mapped (surface);
show_window_internal (surface, FALSE, FALSE);
gdk_surface_invalidate_rect (surface, NULL);
}
@@ -2294,6 +2309,7 @@ snap_up (GdkSurface *window)
impl = GDK_WIN32_SURFACE (window);
impl->snap_state = GDK_WIN32_AEROSNAP_STATE_FULLUP;
impl->resized = FALSE;
stash_window (window, impl);
@@ -2304,10 +2320,18 @@ snap_up (GdkSurface *window)
y = 0;
height = maxysize;
x = x - impl->margins.left;
y = y - impl->margins.top;
width += impl->margins_x;
height += impl->margins_y;
x = x - impl->shadow.left;
y = y - impl->shadow.top;
width += impl->shadow_x;
height += impl->shadow_y;
/* XXX: FIXME, AeroSnap snap_up() not really working well,
*
* * The snap_up() puts the window at the top left corner.
* * Without the following call, the height maximizes but we see a spew of
* "GdkToplevelSize: geometry size (x,y) exceeds bounds" warnings
*/
compute_toplevel_size (window, TRUE, &width, &height);
gdk_win32_surface_move_resize (window, x, y, width, height);
}
@@ -2323,6 +2347,7 @@ snap_left (GdkSurface *window,
impl = GDK_WIN32_SURFACE (window);
impl->snap_state = GDK_WIN32_AEROSNAP_STATE_HALFLEFT;
impl->resized = FALSE;
gdk_win32_monitor_get_workarea (snap_monitor, &rect);
@@ -2330,10 +2355,10 @@ snap_left (GdkSurface *window,
rect.width = rect.width / 2;
rect.x = rect.x - impl->margins.left;
rect.y = rect.y - impl->margins.top;
rect.width = rect.width + impl->margins_x;
rect.height = rect.height + impl->margins_y;
rect.x = rect.x - impl->shadow.left;
rect.y = rect.y - impl->shadow.top;
rect.width = rect.width + impl->shadow_x;
rect.height = rect.height + impl->shadow_y;
gdk_win32_surface_move_resize (window,
rect.x, rect.y,
@@ -2351,6 +2376,7 @@ snap_right (GdkSurface *window,
impl = GDK_WIN32_SURFACE (window);
impl->snap_state = GDK_WIN32_AEROSNAP_STATE_HALFRIGHT;
impl->resized = FALSE;
gdk_win32_monitor_get_workarea (snap_monitor, &rect);
@@ -2359,10 +2385,10 @@ snap_right (GdkSurface *window,
rect.width = rect.width / 2;
rect.x += rect.width;
rect.x = rect.x - impl->margins.left;
rect.y = rect.y - impl->margins.top;
rect.width = rect.width + impl->margins_x;
rect.height = rect.height + impl->margins_y;
rect.x = rect.x - impl->shadow.left;
rect.y = rect.y - impl->shadow.top;
rect.width = rect.width + impl->shadow_x;
rect.height = rect.height + impl->shadow_y;
gdk_win32_surface_move_resize (window,
rect.x, rect.y,
@@ -3502,10 +3528,10 @@ setup_drag_move_resize_context (GdkSurface *window,
*/
if (op == GDK_WIN32_DRAGOP_MOVE && !maximized)
{
swx += impl->margins.left / impl->surface_scale;
swy += impl->margins.top / impl->surface_scale;
swwidth -= impl->margins_x;
swheight -= impl->margins_y;
swx += impl->shadow.left / impl->surface_scale;
swy += impl->shadow.top / impl->surface_scale;
swwidth -= impl->shadow_x;
swheight -= impl->shadow_y;
}
pointer_outside_of_window = root_x < swx || root_x > swx + swwidth ||
@@ -3555,23 +3581,23 @@ setup_drag_move_resize_context (GdkSurface *window,
unmax_width = placement.rcNormalPosition.right - placement.rcNormalPosition.left;
unmax_height = placement.rcNormalPosition.bottom - placement.rcNormalPosition.top;
shadow_unmax_width = unmax_width - impl->margins_x * impl->surface_scale;
shadow_unmax_height = unmax_height - impl->margins_y * impl->surface_scale;
shadow_unmax_width = unmax_width - impl->shadow_x * impl->surface_scale;
shadow_unmax_height = unmax_height - impl->shadow_y * impl->surface_scale;
if (offsetx * impl->surface_scale < (shadow_unmax_width / 2) &&
offsety * impl->surface_scale < (shadow_unmax_height / 2))
{
placement.rcNormalPosition.top = (root_y - offsety + impl->margins.top - _gdk_offset_y) * impl->surface_scale;
placement.rcNormalPosition.top = (root_y - offsety + impl->shadow.top - _gdk_offset_y) * impl->surface_scale;
placement.rcNormalPosition.bottom = placement.rcNormalPosition.top + unmax_height;
if (left_half)
{
placement.rcNormalPosition.left = (root_x - offsetx + impl->margins.left - _gdk_offset_x) * impl->surface_scale;
placement.rcNormalPosition.left = (root_x - offsetx + impl->shadow.left - _gdk_offset_x) * impl->surface_scale;
placement.rcNormalPosition.right = placement.rcNormalPosition.left + unmax_width;
}
else
{
placement.rcNormalPosition.right = (root_x + offsetx + impl->margins.right - _gdk_offset_x) * impl->surface_scale;
placement.rcNormalPosition.right = (root_x + offsetx + impl->shadow.right - _gdk_offset_x) * impl->surface_scale;
placement.rcNormalPosition.left = placement.rcNormalPosition.right - unmax_width;
}
}
@@ -3582,7 +3608,7 @@ setup_drag_move_resize_context (GdkSurface *window,
(_gdk_offset_x * impl->surface_scale);
if (offsety * impl->surface_scale < shadow_unmax_height / 2)
placement.rcNormalPosition.top = (root_y - offsety + impl->margins.top - _gdk_offset_y) * impl->surface_scale;
placement.rcNormalPosition.top = (root_y - offsety + impl->shadow.top - _gdk_offset_y) * impl->surface_scale;
else
placement.rcNormalPosition.top = (root_y * impl->surface_scale) -
(unmax_height / 2) -
@@ -3609,18 +3635,18 @@ setup_drag_move_resize_context (GdkSurface *window,
if (op == GDK_WIN32_DRAGOP_MOVE)
{
snew_pos.width -= impl->margins_x;
snew_pos.height -= impl->margins_y;
snew_pos.width -= impl->shadow_x;
snew_pos.height -= impl->shadow_y;
}
if (offsetx < snew_pos.width / 2 && offsety < snew_pos.height / 2)
{
new_pos.y = root_y - offsety + impl->margins.top / impl->surface_scale;
new_pos.y = root_y - offsety + impl->shadow.top / impl->surface_scale;
if (left_half)
new_pos.x = root_x - offsetx + impl->margins.left / impl->surface_scale;
new_pos.x = root_x - offsetx + impl->shadow.left / impl->surface_scale;
else
new_pos.x = root_x + offsetx + impl->margins.left / impl->surface_scale - new_pos.width;
new_pos.x = root_x + offsetx + impl->shadow.left / impl->surface_scale - new_pos.width;
}
else
{
@@ -4015,8 +4041,18 @@ gdk_win32_surface_do_move_resize_drag (GdkSurface *window,
rect.top != new_rect.top ||
rect.bottom != new_rect.bottom))
{
if (GDK_IS_TOPLEVEL (window))
{
int scale = impl->surface_scale;
impl->unscaled_width = new_rect.right - new_rect.left;
impl->unscaled_height = new_rect.bottom - new_rect.top;
impl->next_layout.configured_width = (impl->unscaled_width + scale - 1) / scale;
impl->next_layout.configured_height = (impl->unscaled_height + scale - 1) / scale;
impl->resized = TRUE;
}
context->native_move_resize_pending = TRUE;
gdk_surface_request_layout (window);
}
else if (context->op == GDK_WIN32_DRAGOP_MOVE &&
(rect.left != new_rect.left ||
@@ -4051,6 +4087,8 @@ gdk_win32_surface_do_move_resize_drag (GdkSurface *window,
if (context->op == GDK_WIN32_DRAGOP_RESIZE ||
context->op == GDK_WIN32_DRAGOP_MOVE)
handle_aerosnap_move_resize (window, context, x, y);
gdk_surface_request_layout (window);
}
static void
@@ -4159,6 +4197,7 @@ gdk_win32_surface_minimize (GdkSurface *window)
static void
gdk_win32_surface_maximize (GdkSurface *window)
{
GdkWin32Surface *impl;
g_return_if_fail (GDK_IS_SURFACE (window));
@@ -4169,6 +4208,9 @@ gdk_win32_surface_maximize (GdkSurface *window)
GDK_SURFACE_HWND (window),
_gdk_win32_surface_state_to_string (window->state)));
impl = GDK_WIN32_SURFACE (window);
impl->resized = FALSE;
if (GDK_SURFACE_IS_MAPPED (window))
GtkShowWindow (window, SW_MAXIMIZE);
else
@@ -4514,17 +4556,17 @@ gdk_win32_surface_set_shadow_width (GdkSurface *window,
"left %d, top %d, right %d, bottom %d\n",
window, left, top, right, bottom));
impl->zero_margins = left == 0 && right == 0 && top == 0 && bottom == 0;
impl->zero_shadow = left == 0 && right == 0 && top == 0 && bottom == 0;
if (impl->zero_margins)
if (impl->zero_shadow)
return;
impl->margins.left = left;
impl->margins.right = right * impl->surface_scale;
impl->margins.top = top;
impl->margins.bottom = bottom * impl->surface_scale;
impl->margins_x = left + right;
impl->margins_y = top + bottom;
impl->shadow.left = left;
impl->shadow.right = right * impl->surface_scale;
impl->shadow.top = top;
impl->shadow.bottom = bottom * impl->surface_scale;
impl->shadow_x = left + right;
impl->shadow_y = top + bottom;
}
@@ -4597,6 +4639,118 @@ gdk_win32_surface_set_input_region (GdkSurface *window,
*/
}
static void
compute_toplevel_size (GdkSurface *surface,
gboolean update_geometry,
int *width,
int *height)
{
GdkDisplay *display = gdk_surface_get_display (surface);
GdkMonitor *monitor;
GdkToplevelSize size;
int bounds_width, bounds_height;
GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
monitor = gdk_display_get_monitor_at_surface (display, surface);
if (monitor)
{
GdkRectangle workarea;
gdk_win32_monitor_get_workarea (monitor, &workarea);
bounds_width = workarea.width;
bounds_height = workarea.height;
}
else
{
bounds_width = G_MAXINT;
bounds_height = G_MAXINT;
}
gdk_toplevel_size_init (&size, bounds_width, bounds_height);
gdk_toplevel_notify_compute_size (GDK_TOPLEVEL (surface), &size);
g_warn_if_fail (size.width > 0);
g_warn_if_fail (size.height > 0);
*width = size.width;
*height = size.height;
if (size.shadow.is_valid)
{
gdk_win32_surface_set_shadow_width (surface,
size.shadow.left,
size.shadow.right,
size.shadow.top,
size.shadow.bottom);
}
if (update_geometry)
{
GdkGeometry geometry;
GdkSurfaceHints mask;
GdkToplevelLayout *layout = impl->toplevel_layout;
if (gdk_toplevel_layout_get_resizable (layout))
{
geometry.min_width = size.min_width;
geometry.min_height = size.min_height;
mask = GDK_HINT_MIN_SIZE;
}
else
{
geometry.max_width = geometry.min_width = *width;
geometry.max_height = geometry.min_height = *height;
mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
}
gdk_win32_surface_set_geometry_hints (surface, &geometry, mask);
gdk_surface_constrain_size (&geometry, mask, *width, *height, width, height);
}
}
static void
_gdk_win32_surface_request_layout (GdkSurface *surface)
{
GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
int scale = impl->surface_scale;
RECT rect;
if (GDK_IS_TOPLEVEL (surface) && impl->resized)
{
surface->width = impl->next_layout.configured_width;
surface->height = impl->next_layout.configured_height;
}
else
{
_gdk_win32_get_window_rect (surface, &rect);
impl->unscaled_width = rect.right - rect.left;
impl->unscaled_height = rect.bottom - rect.top;
impl->next_layout.configured_width = (impl->unscaled_width + scale - 1) / scale;
impl->next_layout.configured_height = (impl->unscaled_height + scale - 1) / scale;
surface->x = rect.left / scale;
surface->y = rect.top / scale;
}
}
static gboolean
_gdk_win32_surface_compute_size (GdkSurface *surface)
{
GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
int width, height;
if (GDK_IS_TOPLEVEL (surface))
compute_toplevel_size (surface, TRUE, &width, &height);
if (!impl->resized)
{
surface->width = impl->next_layout.configured_width;
surface->height = impl->next_layout.configured_height;
_gdk_surface_update_size (surface);
}
return FALSE;
}
static void
gdk_win32_surface_class_init (GdkWin32SurfaceClass *klass)
{
@@ -4623,6 +4777,8 @@ gdk_win32_surface_class_init (GdkWin32SurfaceClass *klass)
impl_class->create_gl_context = _gdk_win32_surface_create_gl_context;
impl_class->get_scale_factor = _gdk_win32_surface_get_scale_factor;
impl_class->get_unscaled_size = _gdk_win32_surface_get_unscaled_size;
impl_class->request_layout = _gdk_win32_surface_request_layout;
impl_class->compute_size = _gdk_win32_surface_compute_size;
}
HGDIOBJ
@@ -4912,75 +5068,18 @@ gdk_win32_toplevel_class_init (GdkWin32ToplevelClass *class)
}
static void
show_surface (GdkSurface *surface)
{
gboolean was_mapped;
if (surface->destroyed)
return;
was_mapped = GDK_SURFACE_IS_MAPPED (surface);
if (!was_mapped)
gdk_surface_set_is_mapped (surface, TRUE);
gdk_win32_surface_show (surface, FALSE);
if (!was_mapped)
gdk_surface_invalidate_rect (surface, NULL);
}
static gboolean
gdk_win32_toplevel_present (GdkToplevel *toplevel,
GdkToplevelLayout *layout)
{
GdkSurface *surface = GDK_SURFACE (toplevel);
GdkDisplay *display = gdk_surface_get_display (surface);
GdkMonitor *monitor;
GdkToplevelSize size;
int bounds_width, bounds_height;
GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
int width, height;
GdkGeometry geometry;
GdkSurfaceHints mask;
gboolean maximize;
gboolean fullscreen;
monitor = gdk_display_get_monitor_at_surface (display, surface);
if (monitor)
{
GdkRectangle workarea;
gdk_win32_monitor_get_workarea (monitor, &workarea);
bounds_width = workarea.width;
bounds_height = workarea.height;
}
else
{
bounds_width = G_MAXINT;
bounds_height = G_MAXINT;
}
gdk_toplevel_size_init (&size, bounds_width, bounds_height);
gdk_toplevel_notify_compute_size (toplevel, &size);
g_warn_if_fail (size.width > 0);
g_warn_if_fail (size.height > 0);
width = size.width;
height = size.height;
if (gdk_toplevel_layout_get_resizable (layout))
{
geometry.min_width = size.min_width;
geometry.min_height = size.min_height;
mask = GDK_HINT_MIN_SIZE;
}
else
{
geometry.max_width = geometry.min_width = width;
geometry.max_height = geometry.min_height = height;
mask = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
}
gdk_win32_surface_set_geometry_hints (surface, &geometry, mask);
gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height);
g_clear_pointer (&impl->toplevel_layout, gdk_toplevel_layout_unref);
impl->toplevel_layout = gdk_toplevel_layout_copy (layout);
compute_toplevel_size (surface, FALSE, &width, &height);
gdk_win32_surface_resize (surface, width, height);
if (gdk_toplevel_layout_get_maximized (layout, &maximize))
@@ -4999,18 +5098,8 @@ gdk_win32_toplevel_present (GdkToplevel *toplevel,
gdk_win32_surface_unfullscreen (surface);
}
show_surface (surface);
if (size.shadow.is_valid)
{
gdk_win32_surface_set_shadow_width (surface,
size.shadow.left,
size.shadow.right,
size.shadow.top,
size.shadow.bottom);
}
return TRUE;
gdk_win32_surface_show (surface, FALSE);
maybe_notify_mapped (surface);
}
static gboolean
@@ -5093,8 +5182,9 @@ gdk_win32_drag_surface_present (GdkDragSurface *drag_surface,
{
GdkSurface *surface = GDK_SURFACE (drag_surface);
gdk_win32_surface_resize (surface, width, height);
show_surface (surface);
gdk_win32_surface_resize (surface, width, height);
gdk_win32_surface_show (surface, FALSE);
maybe_notify_mapped (surface);
return TRUE;
}

View File

@@ -265,16 +265,16 @@ struct _GdkWin32Surface
int initial_y;
/* left/right/top/bottom width of the shadow/resize-grip around the window */
RECT margins;
RECT shadow;
/* left+right and top+bottom from @margins */
int margins_x;
int margins_y;
/* left+right and top+bottom from @shadow */
int shadow_x;
int shadow_y;
/* Set to TRUE when GTK tells us that margins are 0 everywhere.
* We don't actually set margins to 0, we just set this bit.
/* Set to TRUE when GTK tells us that shadow are 0 everywhere.
* We don't actually set shadow to 0, we just set this bit.
*/
guint zero_margins : 1;
guint zero_shadow : 1;
guint inhibit_configure : 1;
/* Set to TRUE if window is using true layered mode adjustments
@@ -354,6 +354,13 @@ struct _GdkWin32Surface
int unscaled_width;
int unscaled_height;
GdkToplevelLayout *toplevel_layout;
struct {
int configured_width;
int configured_height;
} next_layout;
gboolean resized;
#ifdef GDK_WIN32_ENABLE_EGL
EGLSurface egl_surface;
EGLSurface egl_dummy_surface;