[gtk/surface.compute.win32: 4/4] gdk/win32: Fix window display and resizing




commit d7d4fed0f3ca6e620b7b8391ca63187473f71dea
Author: Chun-wei Fan <fanchunwei src gnome org>
Date:   Thu Dec 31 16:36:41 2020 +0800

    gdk/win32: Fix window display and resizing
    
    Have an implementation of ->request_layout() and ->compute_size() for the Win32
    surface backend so that we can properly display and move and resize the
    windows, as we request from the Win32 APIs.
    
    Hxndling Aerosnap properly is mostly done except for snap_up(), which needs to
    to be looked at later.

 gdk/win32/gdkevents-win32.c  |  14 ++-
 gdk/win32/gdksurface-win32.c | 208 +++++++++++++++++++++++++++++++------------
 gdk/win32/gdksurface-win32.h |   7 ++
 3 files changed, 170 insertions(+), 59 deletions(-)
---
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index 286aa923e8..bb847b5ebd 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -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);
 
diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c
index d0ddf83d10..2722bb32cc 100644
--- a/gdk/win32/gdksurface-win32.c
+++ b/gdk/win32/gdksurface-win32.c
@@ -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);
 }
 
@@ -2307,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);
 
@@ -2322,6 +2325,14 @@ snap_up (GdkSurface *window)
   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);
 }
 
@@ -2336,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);
 
@@ -2364,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);
 
@@ -4028,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 ||
@@ -4064,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
@@ -4172,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));
 
@@ -4182,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
@@ -4610,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)
 {
@@ -4636,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
@@ -4929,52 +5072,14 @@ 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))
@@ -4995,15 +5100,6 @@ gdk_win32_toplevel_present (GdkToplevel       *toplevel,
 
   gdk_win32_surface_show (surface, FALSE);
   maybe_notify_mapped (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);
-    }
 }
 
 static gboolean
diff --git a/gdk/win32/gdksurface-win32.h b/gdk/win32/gdksurface-win32.h
index a60e67e574..08d8bf9d73 100644
--- a/gdk/win32/gdksurface-win32.h
+++ b/gdk/win32/gdksurface-win32.h
@@ -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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]