[gtk/popup-shadow-width: 72/78] popover: Support shadows




commit f1db2060c82ca40d0d539ffee2555178c1c3055a
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Jan 31 19:26:33 2021 -0500

    popover: Support shadows
    
    Use gdk_popup_layout_set_shadow_width to take shadows into
    account when positioning popovers, and set the input region
    to exclude the shadow, since we aren't doing interactive
    resizing and the like.
    
    When the popover has a beak, we make the surface size be
    content size + shadow + tail, and then position the content
    according to the final position inside this slightly too large
    surface. The surface being too large doesn't matter, since we
    set up an input region.

 gtk/gtkpopover.c | 128 ++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 103 insertions(+), 25 deletions(-)
---
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index 6d10169073..217c2f30a2 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -126,6 +126,7 @@
 #include "gtkstylecontextprivate.h"
 #include "gtkroundedboxprivate.h"
 #include "gsk/gskroundedrectprivate.h"
+#include "gtkcssshadowvalueprivate.h"
 
 #define MNEMONICS_DELAY 300 /* ms */
 
@@ -436,6 +437,8 @@ create_popup_layout (GtkPopover *popover)
   GdkAnchorHints anchor_hints;
   GdkPopupLayout *layout;
   GtkWidget *parent;
+  GtkCssStyle *style;
+  GtkBorder shadow_width;
 
   parent = gtk_widget_get_parent (GTK_WIDGET (popover));
   gtk_widget_get_surface_allocation (parent, &rect);
@@ -447,6 +450,9 @@ create_popup_layout (GtkPopover *popover)
       rect.height = priv->pointing_to.height;
     }
 
+  style = gtk_css_node_get_style (gtk_widget_get_css_node (GTK_WIDGET (priv->contents_widget)));
+  gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width);
+
   switch (priv->position)
     {
     case GTK_POS_LEFT:
@@ -553,6 +559,11 @@ create_popup_layout (GtkPopover *popover)
 
   layout = gdk_popup_layout_new (&rect, parent_anchor, surface_anchor);
   gdk_popup_layout_set_anchor_hints (layout, anchor_hints);
+  gdk_popup_layout_set_shadow_width (layout,
+                                     shadow_width.left,
+                                     shadow_width.right,
+                                     shadow_width.top,
+                                     shadow_width.bottom);
 
   if (priv->x_offset || priv->y_offset)
     gdk_popup_layout_set_offset (layout, priv->x_offset, priv->y_offset);
@@ -570,9 +581,7 @@ present_popup (GtkPopover *popover)
   layout = create_popup_layout (popover);
   gtk_widget_get_preferred_size (GTK_WIDGET (popover), NULL, &nat);
 
-  if (gdk_popup_present (GDK_POPUP (priv->surface),
-                         nat.width, nat.height,
-                         layout))
+  if (gdk_popup_present (GDK_POPUP (priv->surface), nat.width, nat.height, layout))
     {
       update_popover_layout (popover, layout, nat.width, nat.height);
       return TRUE;
@@ -1107,6 +1116,7 @@ gtk_popover_get_gap_coords (GtkPopover *popover,
   int popover_width, popover_height;
   GtkCssStyle *style;
   GtkWidget *parent;
+  GtkBorder shadow_width;
 
   popover_width = gtk_widget_get_allocated_width (widget);
   popover_height = gtk_widget_get_allocated_height (widget);
@@ -1132,20 +1142,27 @@ gtk_popover_get_gap_coords (GtkPopover *popover,
   border_right = _gtk_css_number_value_get (style->border->border_right_width, 100);
   border_bottom = _gtk_css_number_value_get (style->border->border_bottom_width, 100);
 
-  if (pos == GTK_POS_BOTTOM || pos == GTK_POS_RIGHT)
+  gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width);
+
+  if (pos == GTK_POS_BOTTOM)
     {
-      tip = 0;
-      base = TAIL_HEIGHT + border_top;
+      tip = shadow_width.top;
+      base = tip + TAIL_HEIGHT + border_top;
+    }
+  else if (pos == GTK_POS_RIGHT)
+    {
+      tip = shadow_width.left;
+      base = tip + TAIL_HEIGHT + border_top;
     }
   else if (pos == GTK_POS_TOP)
     {
-      base = popover_height - border_bottom - TAIL_HEIGHT;
-      tip = popover_height;
+      tip = popover_height - shadow_width.bottom;
+      base = tip - border_bottom - TAIL_HEIGHT;
     }
   else if (pos == GTK_POS_LEFT)
     {
-      base = popover_width - border_right - TAIL_HEIGHT;
-      tip = popover_width;
+      tip = popover_width - shadow_width.right;
+      base = tip - border_right - TAIL_HEIGHT;
     }
   else
     g_assert_not_reached ();
@@ -1286,7 +1303,31 @@ gtk_popover_update_shape (GtkPopover *popover)
       cairo_region_destroy (region);
     }
   else
-    gdk_surface_set_input_region (priv->surface, NULL);
+    {
+      GtkCssNode *content_css_node;
+      GtkCssStyle *style;
+      GtkBorder shadow_width;
+      cairo_rectangle_int_t input_rect;
+      cairo_region_t *region;
+
+      content_css_node =
+        gtk_widget_get_css_node (GTK_WIDGET (priv->contents_widget));
+      style = gtk_css_node_get_style (content_css_node);
+      gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width);
+
+      input_rect.x = shadow_width.left;
+      input_rect.y = shadow_width.top;
+      input_rect.width =
+        gdk_surface_get_width (priv->surface) -
+        (shadow_width.left + shadow_width.right);
+      input_rect.height =
+        gdk_surface_get_height (priv->surface) -
+        (shadow_width.top + shadow_width.bottom);
+
+      region = cairo_region_create_rectangle (&input_rect);
+      gdk_surface_set_input_region (priv->surface, region);
+      cairo_region_destroy (region);
+    }
 }
 
 static int
@@ -1306,14 +1347,22 @@ get_minimal_size (GtkPopover     *popover,
   GtkPositionType pos;
   int minimal_size;
   int tail_gap_width = priv->has_arrow ? TAIL_GAP_WIDTH : 0;
+  int min_width, min_height;
 
-  minimal_size = 2 * get_border_radius (GTK_WIDGET (popover));
+  minimal_size = 2 * get_border_radius (GTK_WIDGET (priv->contents_widget));
   pos = priv->position;
 
   if ((orientation == GTK_ORIENTATION_HORIZONTAL && POS_IS_VERTICAL (pos)) ||
       (orientation == GTK_ORIENTATION_VERTICAL && !POS_IS_VERTICAL (pos)))
     minimal_size += tail_gap_width;
 
+  gtk_widget_get_size_request (GTK_WIDGET (popover), &min_width, &min_height);
+
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    minimal_size = MAX (minimal_size, min_width);
+  else
+    minimal_size = MAX (minimal_size, min_height);
+
   return minimal_size;
 }
 
@@ -1330,10 +1379,15 @@ gtk_popover_measure (GtkWidget      *widget,
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
   int minimal_size;
   int tail_height = priv->has_arrow ? TAIL_HEIGHT : 0;
+  GtkCssStyle *style;
+  GtkBorder shadow_width;
 
   if (for_size >= 0)
     for_size -= tail_height;
 
+  style = gtk_css_node_get_style (gtk_widget_get_css_node (GTK_WIDGET (priv->contents_widget)));
+  gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width);
+
   gtk_widget_measure (priv->contents_widget,
                       orientation, for_size,
                       minimum, natural,
@@ -1343,8 +1397,22 @@ gtk_popover_measure (GtkWidget      *widget,
   *minimum = MAX (*minimum, minimal_size);
   *natural = MAX (*natural, minimal_size);
 
-  *minimum += tail_height;
-  *natural += tail_height;
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      *minimum += shadow_width.left + shadow_width.right;
+      *natural += shadow_width.left + shadow_width.right;
+    }
+  else
+    {
+      *minimum += shadow_width.top + shadow_width.bottom;
+      *natural += shadow_width.top + shadow_width.bottom;
+    }
+
+  if (POS_IS_VERTICAL (priv->position) == (orientation == GTK_ORIENTATION_VERTICAL))
+    {
+      *minimum += tail_height;
+      *natural += tail_height;
+    }
 }
 
 static void
@@ -1357,32 +1425,42 @@ gtk_popover_size_allocate (GtkWidget *widget,
   GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
   GtkAllocation child_alloc;
   int tail_height = priv->has_arrow ? TAIL_HEIGHT : 0;
+  GtkCssStyle *style;
+  GtkBorder shadow_width;
+
+  style = gtk_css_node_get_style (gtk_widget_get_css_node (GTK_WIDGET (priv->contents_widget)));
+  gtk_css_shadow_value_get_extents (style->background->box_shadow, &shadow_width);
 
   switch (priv->final_position)
     {
     case GTK_POS_TOP:
-      child_alloc.x = tail_height / 2;
-      child_alloc.y = 0;
+      child_alloc.x = shadow_width.left;
+      child_alloc.y = shadow_width.top;
+      child_alloc.width = width - (shadow_width.left + shadow_width.right);
+      child_alloc.height = height - (shadow_width.top + shadow_width.bottom + tail_height);
       break;
     case GTK_POS_BOTTOM:
-      child_alloc.x = tail_height / 2;
-      child_alloc.y = tail_height;
+      child_alloc.x = shadow_width.left;
+      child_alloc.y = shadow_width.top + tail_height;
+      child_alloc.width = width - (shadow_width.left + shadow_width.right);
+      child_alloc.height = height - (shadow_width.top + shadow_width.bottom + tail_height);
       break;
     case GTK_POS_LEFT:
-      child_alloc.x = 0;
-      child_alloc.y = tail_height / 2;
+      child_alloc.x = shadow_width.left;
+      child_alloc.y = shadow_width.top;
+      child_alloc.width = width - (shadow_width.left + shadow_width.right + tail_height);
+      child_alloc.height = height - (shadow_width.top + shadow_width.bottom);
       break;
     case GTK_POS_RIGHT:
-      child_alloc.x = tail_height;
-      child_alloc.y = tail_height / 2;
+      child_alloc.x = shadow_width.left + tail_height;
+      child_alloc.y = shadow_width.top;
+      child_alloc.width = width - (shadow_width.left + shadow_width.right + tail_height);
+      child_alloc.height = height - (shadow_width.top + shadow_width.bottom);
       break;
     default:
       break;
     }
 
-  child_alloc.width = width - tail_height;
-  child_alloc.height = height - tail_height;
-
   gtk_widget_size_allocate (priv->contents_widget, &child_alloc, baseline);
 
   if (priv->surface)


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