[gtk/wip/baedert/for-master] window: Make decoration a widget



commit 3e95116a368395da95e7c17fcccd4a52f455b534
Author: Timm Bäder <mail baedert org>
Date:   Wed Feb 5 14:57:34 2020 +0100

    window: Make decoration a widget
    
    Instead of having a decoration node and adding the .background style
    class to the window, have a decoration widget that draws its own shadow,
    etc. and add .background to that widget.
    
    We place the decoration widget below all other child widgets and give it
    the same size.

 gtk/gtkwindow.c                | 297 ++++++++++++-----------------------------
 gtk/theme/Adwaita/_common.scss |  23 ++--
 2 files changed, 96 insertions(+), 224 deletions(-)
---
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index ea16143bfb..9df2254d08 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -69,6 +69,7 @@
 #include "gtkwindowgroup.h"
 #include "gtkpopovermenubarprivate.h"
 #include "gtkcssboxesimplprivate.h"
+#include "gtkgizmoprivate.h"
 
 #include "a11y/gtkwindowaccessibleprivate.h"
 #include "a11y/gtkcontaineraccessibleprivate.h"
@@ -160,7 +161,7 @@
  */
 
 #define MENU_BAR_ACCEL "F10"
-#define RESIZE_HANDLE_SIZE 20
+#define RESIZE_HANDLE_SIZE 10
 #define MNEMONICS_DELAY 300 /* ms */
 #define NO_CONTENT_CHILD_NAT 200
 /* In case the content (excluding header bar and shadows) of the window
@@ -268,7 +269,7 @@ typedef struct
   GtkGesture *bubble_drag_gesture;
   GtkEventController *key_controller;
 
-  GtkCssNode *decoration_node;
+  GtkWidget *decoration_widget;
 
   GdkSurface  *surface;
   GskRenderer *renderer;
@@ -437,8 +438,6 @@ static void gtk_window_real_activate_focus   (GtkWindow         *window);
 static void gtk_window_keys_changed          (GtkWindow         *window);
 static gboolean gtk_window_enable_debugging  (GtkWindow         *window,
                                               gboolean           toggle);
-static void gtk_window_snapshot                    (GtkWidget   *widget,
-                                                    GtkSnapshot *snapshot);
 static void gtk_window_unset_transient_for         (GtkWindow  *window);
 static void gtk_window_transient_parent_realized   (GtkWidget  *parent,
                                                    GtkWidget  *window);
@@ -503,8 +502,6 @@ static void gtk_window_activate_default_activate (GtkWidget *widget,
 static void        gtk_window_do_popup         (GtkWindow      *window,
                                                 GdkEventButton *event);
 static void gtk_window_style_updated (GtkWidget     *widget);
-static void gtk_window_state_flags_changed (GtkWidget     *widget,
-                                            GtkStateFlags  previous_state);
 static void _gtk_window_set_is_active (GtkWindow *window,
                                       gboolean   is_active);
 
@@ -656,6 +653,7 @@ gtk_window_measure (GtkWidget      *widget,
   int title_nat_size = 0;
   int child_min_size = 0;
   int child_nat_size = 0;
+  int min_decoration;
   GtkBorder window_border = { 0 };
 
 
@@ -686,6 +684,7 @@ gtk_window_measure (GtkWidget      *widget,
                               &title_min_size, &title_nat_size,
                               NULL, NULL);
         }
+
     }
 
   if (child != NULL && gtk_widget_get_visible (child))
@@ -704,6 +703,10 @@ gtk_window_measure (GtkWidget      *widget,
       child_nat_size = NO_CONTENT_CHILD_NAT;
     }
 
+  gtk_widget_measure (priv->decoration_widget, orientation, -1,
+                      &min_decoration, NULL, NULL, NULL);
+  child_min_size = MAX (child_min_size, min_decoration);
+
   if (orientation == GTK_ORIENTATION_HORIZONTAL)
     {
       title_min_size += window_border.left + window_border.right;
@@ -724,12 +727,27 @@ static void
 gtk_window_add (GtkContainer *container,
                 GtkWidget    *child)
 {
-  /* Insert the child's css node now at the end so the order wrt. decoration_node is correct */
-  gtk_css_node_insert_before (gtk_widget_get_css_node (GTK_WIDGET (container)),
-                              gtk_widget_get_css_node (child),
-                              NULL);
+  gtk_widget_set_parent (child, GTK_WIDGET (container));
+  _gtk_bin_set_child (GTK_BIN (container), child);
+}
+
+static void
+get_resize_handle_size (GtkWindow *window,
+                        GtkBorder *out_size)
+{
+  GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
 
-  GTK_CONTAINER_CLASS (gtk_window_parent_class)->add (container, child);
+  if (priv->use_client_shadow)
+    {
+      out_size->left = RESIZE_HANDLE_SIZE;
+      out_size->top = RESIZE_HANDLE_SIZE;
+      out_size->right = RESIZE_HANDLE_SIZE;
+      out_size->bottom = RESIZE_HANDLE_SIZE;
+    }
+  else
+    {
+      gtk_style_context_get_border (gtk_widget_get_style_context (priv->decoration_widget), out_size);
+    }
 }
 
 static void popover_get_rect (GtkWindowPopover      *popover,
@@ -799,9 +817,7 @@ gtk_window_class_init (GtkWindowClass *klass)
   widget_class->focus = gtk_window_focus;
   widget_class->move_focus = gtk_window_move_focus;
   widget_class->measure = gtk_window_measure;
-  widget_class->state_flags_changed = gtk_window_state_flags_changed;
   widget_class->style_updated = gtk_window_style_updated;
-  widget_class->snapshot = gtk_window_snapshot;
 
   container_class->add = gtk_window_add;
   container_class->remove = gtk_window_remove;
@@ -1554,17 +1570,6 @@ drag_gesture_update_cb (GtkGestureDrag *gesture,
     }
 }
 
-static void
-node_style_changed_cb (GtkCssNode        *node,
-                       GtkCssStyleChange *change,
-                       GtkWidget         *widget)
-{
-  if (gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_SIZE))
-    gtk_widget_queue_resize (widget);
-  else
-    gtk_widget_queue_draw (widget);
-}
-
 static void
 device_removed_cb (GdkSeat   *seat,
                    GdkDevice *device,
@@ -1625,10 +1630,11 @@ edge_under_coordinates (GtkWindow     *window,
                         GdkSurfaceEdge  edge)
 {
   GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
-  GtkAllocation allocation;
-  GtkStyleContext *context;
-  gint handle_v, handle_h;
+  GtkCssBoxes css_boxes;
+  graphene_rect_t border_rect;
+  gint handle_v = 0, handle_h = 0;
   GtkBorder border;
+  GtkAllocation allocation;
   gboolean supports_edge_constraints;
   guint constraints;
 
@@ -1649,24 +1655,19 @@ edge_under_coordinates (GtkWindow     *window,
       (priv->edge_constraints & constraints) != constraints)
     return FALSE;
 
-  gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
-  context = _gtk_widget_get_style_context (GTK_WIDGET (window));
-  gtk_style_context_save_to_node (context, priv->decoration_node);
+  gtk_css_boxes_init (&css_boxes, priv->decoration_widget);
+  border_rect = *gtk_css_boxes_get_border_rect (&css_boxes);
 
-  if (priv->use_client_shadow)
-    {
-      handle_h = MIN (RESIZE_HANDLE_SIZE, allocation.width / 2);
-      handle_v = MIN (RESIZE_HANDLE_SIZE, allocation.height / 2);
-      get_shadow_width (window, &border);
-    }
-  else
-    {
-      handle_h = 0;
-      handle_v = 0;
-      gtk_style_context_get_padding (context, &border);
-    }
+  if (!gtk_widget_compute_point (priv->decoration_widget, GTK_WIDGET (window),
+                                 &border_rect.origin, &border_rect.origin))
+    return FALSE;
 
-  gtk_style_context_restore (context);
+  get_resize_handle_size (window, &border);
+
+  allocation.x = border_rect.origin.x - border.left;
+  allocation.y = border_rect.origin.y - border.top;
+  allocation.width = border_rect.size.width + border.left + border.top;
+  allocation.height = border_rect.size.height + border.top + border.bottom;
 
   /* Check whether the click falls outside the handle area */
   if (x >= allocation.x + border.left &&
@@ -1781,7 +1782,6 @@ gtk_window_init (GtkWindow *window)
 {
   GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
   GtkWidget *widget;
-  GtkCssNode *widget_node;
   GdkSeat *seat;
   GtkEventController *motion_controller;
 #ifdef GDK_WINDOWING_X11
@@ -1827,15 +1827,11 @@ gtk_window_init (GtkWindow *window)
                     G_CALLBACK (gtk_window_on_theme_variant_changed), window);
 #endif
 
-  widget_node = gtk_widget_get_css_node (GTK_WIDGET (window));
-  priv->decoration_node = gtk_css_node_new ();
-  gtk_css_node_set_name (priv->decoration_node, g_quark_from_static_string ("decoration"));
-  gtk_css_node_set_parent (priv->decoration_node, widget_node);
-  gtk_css_node_set_state (priv->decoration_node, gtk_css_node_get_state (widget_node));
-  g_signal_connect_object (priv->decoration_node, "style-changed", G_CALLBACK (node_style_changed_cb), 
window, 0);
-  g_object_unref (priv->decoration_node);
-
-  gtk_css_node_add_class (widget_node, g_quark_from_static_string (GTK_STYLE_CLASS_BACKGROUND));
+  priv->decoration_widget = g_object_new (GTK_TYPE_GIZMO,
+                                          "css-name", "decoration",
+                                          NULL);
+  gtk_widget_add_style_class (priv->decoration_widget, "background");
+  gtk_widget_set_parent (priv->decoration_widget, GTK_WIDGET (window));
 
   priv->scale = gtk_widget_get_scale_factor (widget);
 
@@ -3008,6 +3004,8 @@ gtk_window_dispose (GObject *object)
   gtk_window_set_default_widget (window, NULL);
   remove_attach_widget (window);
 
+  g_clear_pointer (&priv->decoration_widget, gtk_widget_unparent);
+
   G_OBJECT_CLASS (gtk_window_parent_class)->dispose (object);
   unset_titlebar (window);
 
@@ -3759,12 +3757,9 @@ gtk_window_set_titlebar (GtkWindow *window,
 
   gtk_window_enable_csd (window);
   priv->title_box = titlebar;
-  /* Same reason as in gtk_window_add */
-  gtk_css_node_insert_before (gtk_widget_get_css_node (GTK_WIDGET (window)),
-                              gtk_widget_get_css_node (titlebar),
-                              NULL);
+  gtk_widget_insert_before (titlebar, GTK_WIDGET (window),
+                            gtk_bin_get_child (GTK_BIN (widget)));
 
-  gtk_widget_set_parent (priv->title_box, widget);
   if (GTK_IS_HEADER_BAR (titlebar))
     {
       g_signal_connect (titlebar, "notify::title",
@@ -5267,16 +5262,6 @@ max_borders (GtkBorder *one,
   one->left = MAX (one->left, two->left);
 }
 
-static void
-subtract_borders (GtkBorder *one,
-                  GtkBorder *two)
-{
-  one->top -= two->top;
-  one->right -= two->right;
-  one->bottom -= two->bottom;
-  one->left -= two->left;
-}
-
 static void
 get_shadow_width (GtkWindow *window,
                   GtkBorder *shadow_width)
@@ -5302,9 +5287,9 @@ get_shadow_width (GtkWindow *window,
       priv->fullscreen)
     return;
 
-  context = _gtk_widget_get_style_context (GTK_WIDGET (window));
+  context = _gtk_widget_get_style_context (priv->decoration_widget);
 
-  gtk_style_context_save_to_node (context, priv->decoration_node);
+  gtk_style_context_save (context);
 
   /* Always sum border + padding */
   gtk_style_context_get_border (context, &border);
@@ -5331,42 +5316,41 @@ get_shadow_width (GtkWindow *window,
 static void
 update_csd_shape (GtkWindow *window)
 {
-  GtkWidget *widget = (GtkWidget *)window;
   GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
-  cairo_rectangle_int_t rect;
-  GtkBorder border, tmp;
-  GtkBorder window_border;
-  GtkStyleContext *context;
+  GtkWidget *widget = (GtkWidget *)window;
+  GtkCssBoxes css_boxes;
+  graphene_rect_t border_box;
+  GtkBorder handle_size;
 
   if (!priv->client_decorated)
     return;
 
-  context = _gtk_widget_get_style_context (widget);
+  gtk_css_boxes_init (&css_boxes, priv->decoration_widget);
+  border_box = *gtk_css_boxes_get_border_rect (&css_boxes);
 
-  gtk_style_context_save_to_node (context, priv->decoration_node);
-  gtk_style_context_get_margin (context, &border);
-  gtk_style_context_get_border (context, &tmp);
-  sum_borders (&border, &tmp);
-  gtk_style_context_get_padding (context, &tmp);
-  sum_borders (&border, &tmp);
-  gtk_style_context_restore (context);
-  get_shadow_width (window, &window_border);
+  /* Move into window coords */
+  if (!gtk_widget_compute_point (priv->decoration_widget, widget,
+                                 &border_box.origin, &border_box.origin))
+    return;
 
-  /* update the input shape, which makes it so that clicks
-   * outside the border windows go through.
-   */
+  get_resize_handle_size (window, &handle_size);
 
   if (priv->type != GTK_WINDOW_POPUP)
-    subtract_borders (&window_border, &border);
-
-  rect.x = window_border.left;
-  rect.y = window_border.top;
-  rect.width = gtk_widget_get_allocated_width (widget) - window_border.left - window_border.right;
-  rect.height = gtk_widget_get_allocated_height (widget) - window_border.top - window_border.bottom;
+    {
+      border_box.origin.x -= handle_size.left;
+      border_box.origin.y -= handle_size.top;
+      border_box.size.width += handle_size.left + handle_size.right;
+      border_box.size.height += handle_size.top + handle_size.bottom;
+    }
 
-  if (rect.width > 0 && rect.height > 0)
+  if (border_box.size.width > 0 && border_box.size.height > 0)
     {
-      cairo_region_t *region = cairo_region_create_rectangle (&rect);
+      cairo_region_t *region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
+                                                                border_box.origin.x,
+                                                                border_box.origin.y,
+                                                                border_box.size.width,
+                                                                border_box.size.height
+                                                              });
       gtk_widget_set_csd_input_shape (widget, region);
       cairo_region_destroy (region);
     }
@@ -5409,8 +5393,6 @@ subtract_decoration_corners_from_region (cairo_region_t        *region,
       priv->maximized)
     return;
 
-  gtk_style_context_save_to_node (context, priv->decoration_node);
-
   corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS));
   rect.x = extents->x;
   rect.y = extents->y;
@@ -5430,8 +5412,6 @@ subtract_decoration_corners_from_region (cairo_region_t        *region,
   rect.x = extents->x + extents->width - rect.width;
   rect.y = extents->y + extents->height - rect.height;
   cairo_region_subtract_rectangle (region, &rect);
-
-  gtk_style_context_restore (context);
 }
 
 static void
@@ -5448,7 +5428,7 @@ update_opaque_region (GtkWindow           *window,
   if (!_gtk_widget_get_realized (widget))
       return;
 
-  context = gtk_widget_get_style_context (widget);
+  context = gtk_widget_get_style_context (priv->decoration_widget);
 
   is_opaque = gdk_rgba_is_opaque (gtk_css_color_value_get_rgba (_gtk_style_context_peek_property (context, 
GTK_CSS_PROPERTY_BACKGROUND_COLOR)));
 
@@ -5837,6 +5817,10 @@ _gtk_window_set_allocation (GtkWindow           *window,
 
   *allocation_out = child_allocation;
 
+  child_allocation.y -= priv->title_height;
+  child_allocation.height += priv->title_height;
+  gtk_widget_size_allocate (priv->decoration_widget, &child_allocation, -1);
+
   for (link = priv->popovers.head; link; link = link->next)
     {
       GtkWindowPopover *popover = link->data;
@@ -6462,20 +6446,6 @@ gtk_window_set_focus (GtkWindow *window,
   g_object_notify (G_OBJECT (window), "focus-widget");
 }
 
-static void
-gtk_window_state_flags_changed (GtkWidget     *widget,
-                                GtkStateFlags  previous_state)
-{
-  GtkWindow *window = GTK_WINDOW (widget);
-  GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
-  GtkStateFlags state;
-
-  state = gtk_widget_get_state_flags (widget);
-  gtk_css_node_set_state (priv->decoration_node, state);
-
-  GTK_WIDGET_CLASS (gtk_window_parent_class)->state_flags_changed (widget, previous_state);
-}
-
 static void
 gtk_window_style_updated (GtkWidget *widget)
 {
@@ -7394,105 +7364,6 @@ gtk_window_compute_hints (GtkWindow   *window,
 #undef INCLUDE_CSD_SIZE
 #undef EXCLUDE_CSD_SIZE
 
-/***********************
- * Redrawing functions *
- ***********************/
-
-static void
-gtk_window_snapshot (GtkWidget   *widget,
-                     GtkSnapshot *snapshot)
-{
-  GtkWindowPrivate *priv = gtk_window_get_instance_private (GTK_WINDOW (widget));
-  GtkStyleContext *context;
-  GtkBorder window_border;
-  gint title_height;
-  GList *l;
-  int width, height;
-  GtkWidget *child;
-
-  context = gtk_widget_get_style_context (widget);
-
-  get_shadow_width (GTK_WINDOW (widget), &window_border);
-  width = gtk_widget_get_width (widget);
-  height = gtk_widget_get_height (widget);
-
-  if (priv->client_decorated &&
-      priv->decorated &&
-      !priv->fullscreen &&
-      !priv->maximized)
-    {
-      gtk_style_context_save_to_node (context, priv->decoration_node);
-
-      if (priv->use_client_shadow)
-        {
-          GtkBorder padding, border;
-
-          gtk_style_context_get_padding (context, &padding);
-          gtk_style_context_get_border (context, &border);
-          sum_borders (&border, &padding);
-
-          gtk_snapshot_render_background (snapshot, context,
-                                          window_border.left - border.left, window_border.top - border.top,
-                                          width -
-                                            (window_border.left + window_border.right - border.left - 
border.right),
-                                          height -
-                                            (window_border.top + window_border.bottom - border.top - 
border.bottom));
-          gtk_snapshot_render_frame (snapshot, context,
-                                     window_border.left - border.left, window_border.top - border.top,
-                                     width -
-                                       (window_border.left + window_border.right - border.left - 
border.right),
-                                     height -
-                                       (window_border.top + window_border.bottom - border.top - 
border.bottom));
-        }
-      else
-        {
-          gtk_snapshot_render_background (snapshot, context, 0, 0,
-                                          width, height);
-
-          gtk_snapshot_render_frame (snapshot, context, 0, 0,
-                                     width, height);
-        }
-      gtk_style_context_restore (context);
-    }
-
-  if (priv->title_box &&
-      gtk_widget_get_visible (priv->title_box) &&
-      gtk_widget_get_child_visible (priv->title_box))
-    title_height = priv->title_height;
-  else
-    title_height = 0;
-
-  gtk_snapshot_render_background (snapshot, context,
-                                  window_border.left,
-                                  window_border.top + title_height,
-                                  width -
-                                    (window_border.left + window_border.right),
-                                  height -
-                                    (window_border.top + window_border.bottom + title_height));
-  gtk_snapshot_render_frame (snapshot, context,
-                             window_border.left,
-                             window_border.top + title_height,
-                             width -
-                               (window_border.left + window_border.right),
-                             height -
-                               (window_border.top + window_border.bottom + title_height));
-
-  for (child = _gtk_widget_get_first_child (widget);
-       child != NULL;
-       child = _gtk_widget_get_next_sibling (child))
-    {
-      /* Handle popovers separately until their stacking order is fixed */
-      if (!GTK_IS_POPOVER (child))
-        gtk_widget_snapshot_child (widget, child, snapshot);
-    }
-
-  for (l = priv->popovers.head; l; l = l->next)
-    {
-      GtkWindowPopover *data = l->data;
-      gtk_widget_snapshot_child (widget, data->widget, snapshot);
-    }
-}
-
 /**
  * gtk_window_present:
  * @window: a #GtkWindow
diff --git a/gtk/theme/Adwaita/_common.scss b/gtk/theme/Adwaita/_common.scss
index 5296a9b261..71d2e0a31b 100644
--- a/gtk/theme/Adwaita/_common.scss
+++ b/gtk/theme/Adwaita/_common.scss
@@ -34,18 +34,25 @@ flowboxchild:focus(visible) {
 /***************
  * Base States *
  ***************/
-.background {
+window,
+dialog{
   color: $fg_color;
-  background-color: $bg_color;
 
   &:backdrop {
     color: $backdrop_fg_color;
-    background-color: $backdrop_bg_color;
     text-shadow: none;
     -gtk-icon-shadow: none;
   }
 }
 
+.background {
+  background-color: $bg_color;
+
+  &:backdrop {
+    background-color: $backdrop_bg_color;
+  }
+}
+
 .normal-icons {
   -gtk-icon-size: 16px;
 }
@@ -1444,7 +1451,7 @@ headerbar {
   border-width: 0 0 1px;
   border-style: solid;
   border-color: $alt_borders_color;
-  border-radius: 0;
+  border-radius: $window_radius $window_radius 0 0;
 
   @include headerbar_fill(darken($bg_color, 10%));
 
@@ -4100,11 +4107,6 @@ decoration {
   box-shadow: 0 3px 9px 1px transparentize(black, 0.5),
               0 0 0 1px $_wm_border; //doing borders with box-shadow
 
-  // FIXME rationalize shadows
-
-  // this is used for the resize cursor area
-  margin: 10px;
-
   &:backdrop {
     // the transparent shadow here is to enforce that the shadow extents don't
     // change when we go to backdrop, to prevent jumping windows.
@@ -4148,10 +4150,9 @@ decoration {
 
   .solid-csd > & {
     margin: 0;
-    padding: 4px;
-    background-color: $borders_color;
     border: solid 1px $borders_color;
     border-radius: 0;
+    border-width: 4px;
     box-shadow: inset 0 0 0 3px $headerbar_color, inset 0 1px $top_hilight;
 
     &:backdrop { box-shadow: inset 0 0 0 3px $backdrop_bg_color, inset 0 1px $top_hilight; }


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