[mutter] wayland: add min/max size from xdg-shell v6



commit 4f58a4621725ac657dcfa1e232af4e0d063b8f76
Author: Olivier Fourdan <ofourdan redhat com>
Date:   Wed Apr 6 14:07:08 2016 +0200

    wayland: add min/max size from xdg-shell v6
    
    Implement min/max size request from xdg-shell-v6 and plug it into the
    existing code so that windows with fixed size cannot be tiled/maximized
    in Wayland just like in X11.
    
    Bugzilla: https://bugzilla.gnome.org/show_bug.cgi?id=770226

 src/wayland/meta-wayland-surface.c   |    8 ++
 src/wayland/meta-wayland-surface.h   |    8 ++
 src/wayland/meta-wayland-xdg-shell.c |   83 +++++++++++++++++-
 src/wayland/meta-window-wayland.c    |  163 +++++++++++++++++++++++++++++++++-
 src/wayland/meta-window-wayland.h    |   18 ++++
 5 files changed, 275 insertions(+), 5 deletions(-)
---
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index ffa6e2e..bfddef7 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -479,6 +479,8 @@ pending_state_init (MetaWaylandPendingState *state)
   wl_list_init (&state->frame_callback_list);
 
   state->has_new_geometry = FALSE;
+  state->has_new_min_size = FALSE;
+  state->has_new_max_size = FALSE;
 }
 
 static void
@@ -523,6 +525,12 @@ move_pending_state (MetaWaylandPendingState *from,
   to->opaque_region_set = from->opaque_region_set;
   to->new_geometry = from->new_geometry;
   to->has_new_geometry = from->has_new_geometry;
+  to->has_new_min_size = from->has_new_min_size;
+  to->new_min_width = from->new_min_width;
+  to->new_min_height = from->new_min_height;
+  to->has_new_max_size = from->has_new_max_size;
+  to->new_max_width = from->new_max_width;
+  to->new_max_height = from->new_max_height;
 
   wl_list_init (&to->frame_callback_list);
   wl_list_insert_list (&to->frame_callback_list, &from->frame_callback_list);
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index 6c892de..1682fb6 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -142,6 +142,14 @@ struct _MetaWaylandPendingState
 
   MetaRectangle new_geometry;
   gboolean has_new_geometry;
+
+  /* pending min/max size in window geometry coordinates */
+  gboolean has_new_min_size;
+  int new_min_width;
+  int new_min_height;
+  gboolean has_new_max_size;
+  int new_max_width;
+  int new_max_height;
 };
 
 struct _MetaWaylandDragDestFuncs
diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c
index f2d8572..8831f8b 100644
--- a/src/wayland/meta-wayland-xdg-shell.c
+++ b/src/wayland/meta-wayland-xdg-shell.c
@@ -295,7 +295,20 @@ xdg_toplevel_set_max_size (struct wl_client   *client,
                            int32_t             width,
                            int32_t             height)
 {
-  /* TODO */
+  MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource);
+
+  if (width < 0 || height < 0)
+    {
+      wl_resource_post_error (resource,
+                              ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
+                              "invalid negative max size requested %i x %i",
+                              width, height);
+      return;
+    }
+
+  surface->pending->has_new_max_size = TRUE;
+  surface->pending->new_max_width = width;
+  surface->pending->new_max_height = height;
 }
 
 static void
@@ -304,7 +317,20 @@ xdg_toplevel_set_min_size (struct wl_client   *client,
                            int32_t             width,
                            int32_t             height)
 {
-  /* TODO */
+  MetaWaylandSurface *surface = surface_from_xdg_toplevel_resource (resource);
+
+  if (width < 0 || height < 0)
+    {
+      wl_resource_post_error (resource,
+                              ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
+                              "invalid negative min size requested %i x %i",
+                              width, height);
+      return;
+    }
+
+  surface->pending->has_new_min_size = TRUE;
+  surface->pending->new_min_width = width;
+  surface->pending->new_min_height = height;
 }
 
 static void
@@ -520,6 +546,37 @@ meta_wayland_xdg_toplevel_send_configure (MetaWaylandXdgToplevel *xdg_toplevel,
     }
 }
 
+static gboolean
+is_new_size_hints_valid (MetaWindow              *window,
+                         MetaWaylandPendingState *pending)
+{
+  int new_min_width, new_min_height;
+  int new_max_width, new_max_height;
+
+  if (pending->has_new_min_size)
+    {
+      new_min_width = pending->new_min_width;
+      new_min_height = pending->new_min_height;
+    }
+  else
+    {
+      meta_window_wayland_get_min_size (window, &new_min_width, &new_min_height);
+    }
+
+  if (pending->has_new_max_size)
+    {
+      new_max_width = pending->new_max_width;
+      new_max_height = pending->new_max_height;
+    }
+  else
+    {
+      meta_window_wayland_get_max_size (window, &new_max_width, &new_max_height);
+    }
+  /* Zero means unlimited */
+  return ((new_max_width == 0 || new_min_width <= new_max_width) &&
+          (new_max_height == 0 || new_min_height <= new_max_height));
+}
+
 static void
 xdg_toplevel_role_commit (MetaWaylandSurfaceRole  *surface_role,
                           MetaWaylandPendingState *pending)
@@ -560,6 +617,28 @@ xdg_toplevel_role_commit (MetaWaylandSurfaceRole  *surface_role,
       return;
     }
 
+  /* When we get to this point, we ought to have valid size hints */
+  if (pending->has_new_min_size || pending->has_new_max_size)
+    {
+      if (is_new_size_hints_valid (window, pending))
+        {
+          if (pending->has_new_min_size)
+            meta_window_wayland_set_min_size (window, pending->new_min_width, pending->new_min_height);
+
+          if (pending->has_new_max_size)
+            meta_window_wayland_set_max_size (window, pending->new_max_width, pending->new_max_height);
+
+          meta_window_recalc_features (window);
+        }
+      else
+        {
+          wl_resource_post_error (surface->resource,
+                                  ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
+                                  "Invalid min/max size");
+
+        }
+    }
+
   window_geometry = meta_wayland_xdg_surface_get_window_geometry (xdg_surface);
   meta_window_wayland_move_resize (window,
                                    &xdg_surface_priv->acked_configure_serial,
diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c
index 85c4296..7dd6f42 100644
--- a/src/wayland/meta-window-wayland.c
+++ b/src/wayland/meta-window-wayland.c
@@ -325,10 +325,28 @@ meta_window_wayland_move_resize_internal (MetaWindow                *window,
 }
 
 static void
-scale_rect_size (MetaRectangle *rect, float scale)
+scale_size (int  *width,
+            int  *height,
+            float scale)
 {
-  rect->width = (int)(rect->width * scale);
-  rect->height = (int)(rect->height * scale);
+  if (*width < G_MAXINT)
+    {
+      float new_width = (*width * scale);
+      *width = (int) MIN (new_width, G_MAXINT);
+    }
+
+  if (*height < G_MAXINT)
+    {
+      float new_height = (*height * scale);
+      *height = (int) MIN (new_height, G_MAXINT);
+    }
+}
+
+static void
+scale_rect_size (MetaRectangle *rect,
+                 float          scale)
+{
+  scale_size (&rect->width, &rect->height, scale);
 }
 
 static void
@@ -399,6 +417,9 @@ meta_window_wayland_main_monitor_changed (MetaWindow *window,
   scale_rect_size (&window->rect, scale_factor);
   scale_rect_size (&window->unconstrained_rect, scale_factor);
   scale_rect_size (&window->saved_rect, scale_factor);
+  scale_size (&window->size_hints.min_width, &window->size_hints.min_height, scale_factor);
+  scale_size (&window->size_hints.max_width, &window->size_hints.max_height, scale_factor);
+
 
   /* Window geometry offset (XXX: Need a better place, see
    * meta_window_wayland_move_resize). */
@@ -650,3 +671,139 @@ meta_window_place_with_placement_rule (MetaWindow        *window,
   window->unconstrained_rect.height = placement_rule->height;
   meta_window_force_placement (window);
 }
+
+void
+meta_window_wayland_set_min_size (MetaWindow *window,
+                                  int         width,
+                                  int         height)
+{
+  gint64 new_width, new_height;
+  float scale;
+
+  meta_topic (META_DEBUG_GEOMETRY, "Window %s sets min size %d x %d\n",
+              window->desc, width, height);
+
+  if (width == 0 && height == 0)
+    {
+      window->size_hints.min_width = 0;
+      window->size_hints.min_height = 0;
+      window->size_hints.flags &= ~PMinSize;
+
+      return;
+    }
+
+  scale = (float) meta_window_wayland_get_main_monitor_scale (window);
+  scale_size (&width, &height, scale);
+
+  new_width = width + (window->custom_frame_extents.left +
+                       window->custom_frame_extents.right);
+  new_height = height + (window->custom_frame_extents.top +
+                         window->custom_frame_extents.bottom);
+
+  window->size_hints.min_width = (int) MIN (new_width, G_MAXINT);
+  window->size_hints.min_height = (int) MIN (new_height, G_MAXINT);
+  window->size_hints.flags |= PMinSize;
+}
+
+void
+meta_window_wayland_set_max_size (MetaWindow *window,
+                                  int         width,
+                                  int         height)
+
+{
+  gint64 new_width, new_height;
+  float scale;
+
+  meta_topic (META_DEBUG_GEOMETRY, "Window %s sets max size %d x %d\n",
+              window->desc, width, height);
+
+  if (width == 0 && height == 0)
+    {
+      window->size_hints.max_width = G_MAXINT;
+      window->size_hints.max_height = G_MAXINT;
+      window->size_hints.flags &= ~PMaxSize;
+
+      return;
+    }
+
+  scale = (float) meta_window_wayland_get_main_monitor_scale (window);
+  scale_size (&width, &height, scale);
+
+  new_width = width + (window->custom_frame_extents.left +
+                       window->custom_frame_extents.right);
+  new_height = height + (window->custom_frame_extents.top +
+                         window->custom_frame_extents.bottom);
+
+  window->size_hints.max_width = (int) ((new_width > 0 && new_width < G_MAXINT) ?
+                                        new_width : G_MAXINT);
+  window->size_hints.max_height = (int)  ((new_height > 0 && new_height < G_MAXINT) ?
+                                          new_height : G_MAXINT);
+  window->size_hints.flags |= PMaxSize;
+}
+
+void
+meta_window_wayland_get_min_size (MetaWindow *window,
+                                  int        *width,
+                                  int        *height)
+{
+  gint64 current_width, current_height;
+  float scale;
+
+  if (!(window->size_hints.flags & PMinSize))
+    {
+      /* Zero means unlimited */
+      *width = 0;
+      *height = 0;
+
+      return;
+    }
+
+  current_width = window->size_hints.min_width -
+                  (window->custom_frame_extents.left +
+                   window->custom_frame_extents.right);
+  current_height = window->size_hints.min_height -
+                   (window->custom_frame_extents.top +
+                    window->custom_frame_extents.bottom);
+
+  *width = MAX (current_width, 0);
+  *height = MAX (current_height, 0);
+
+  scale = 1.0 / (float) meta_window_wayland_get_main_monitor_scale (window);
+  scale_size (width, height, scale);
+}
+
+void
+meta_window_wayland_get_max_size (MetaWindow *window,
+                                  int        *width,
+                                  int        *height)
+{
+  gint64 current_width = 0;
+  gint64 current_height = 0;
+  float scale;
+
+  if (!(window->size_hints.flags & PMaxSize))
+    {
+      /* Zero means unlimited */
+      *width = 0;
+      *height = 0;
+
+      return;
+    }
+
+  if (window->size_hints.max_width < G_MAXINT)
+    current_width = window->size_hints.max_width -
+                    (window->custom_frame_extents.left +
+                     window->custom_frame_extents.right);
+
+  if (window->size_hints.max_height < G_MAXINT)
+    current_height = window->size_hints.max_height -
+                     (window->custom_frame_extents.top +
+                      window->custom_frame_extents.bottom);
+
+  *width = CLAMP (current_width, 0, G_MAXINT);
+  *height = CLAMP (current_height, 0, G_MAXINT);
+
+  scale = 1.0 / (float) meta_window_wayland_get_main_monitor_scale (window);
+  scale_size (width, height, scale);
+}
+
diff --git a/src/wayland/meta-window-wayland.h b/src/wayland/meta-window-wayland.h
index 1847f70..b7d7b20 100644
--- a/src/wayland/meta-window-wayland.h
+++ b/src/wayland/meta-window-wayland.h
@@ -61,4 +61,22 @@ void meta_window_wayland_place_relative_to (MetaWindow *window,
 void meta_window_place_with_placement_rule (MetaWindow        *window,
                                             MetaPlacementRule *placement_rule);
 
+void meta_window_wayland_set_min_size (MetaWindow *window,
+                                       int         width,
+                                       int         height);
+
+void meta_window_wayland_set_max_size (MetaWindow *window,
+                                       int         width,
+                                       int         height);
+
+void meta_window_wayland_get_min_size (MetaWindow *window,
+                                       int        *width,
+                                       int        *height);
+
+
+void meta_window_wayland_get_max_size (MetaWindow *window,
+                                       int        *width,
+                                       int        *height);
+
+
 #endif


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