popover: Correct placement of popovers
authorMatthias Clasen <mclasen@redhat.com>
Fri, 24 Mar 2023 18:47:27 +0000 (14:47 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Fri, 21 Apr 2023 06:38:12 +0000 (08:38 +0200)
When we don't have a pointing-to rectangle, we want to place
the popover wrt to the parents bounds. But if we have a
pointing-to rectangle, it is relative to the widgets allocation,
which is different from the bounds.

We were not handling the second case correctly, leading to context
menus in the text view being mispositioned by the widgets CSS padding.

While we are touching this code, rewrite it to handle transforms.

Fixes: #5695
gtk/gtkpopover.c

index 78dc4034c26eb743a17fcd27e834898223c48ac1..e60f9ea4df3efe22df774dd12d37f10f176f4902 100644 (file)
@@ -443,17 +443,39 @@ create_popup_layout (GtkPopover *popover)
   GtkWidget *parent;
   GtkCssStyle *style;
   GtkBorder shadow_width;
+  GtkNative *native;
+  double nx, ny;
+  graphene_rect_t bounds;
 
   parent = gtk_widget_get_parent (GTK_WIDGET (popover));
-  gtk_widget_get_surface_allocation (parent, &rect);
+  native = gtk_widget_get_native (parent);
+
   if (priv->has_pointing_to)
     {
-      rect.x += priv->pointing_to.x;
-      rect.y += priv->pointing_to.y;
-      rect.width = priv->pointing_to.width;
-      rect.height = priv->pointing_to.height;
+      graphene_matrix_t transform;
+      graphene_rect_t pointing_to = GRAPHENE_RECT_INIT (priv->pointing_to.x,
+                                                        priv->pointing_to.y,
+                                                        priv->pointing_to.width,
+                                                        priv->pointing_to.height);
+
+      if (!gtk_widget_compute_transform (parent, GTK_WIDGET (native), &transform))
+        graphene_matrix_init_identity (&transform);
+
+      graphene_matrix_transform_bounds (&transform, &pointing_to, &bounds);
+    }
+  else
+    {
+      if (!gtk_widget_compute_bounds (parent, GTK_WIDGET (native), &bounds))
+        g_warning ("Failed to compute bounds");
     }
 
+  gtk_native_get_surface_transform (native, &nx, &ny);
+
+  rect.x = (int) floor (bounds.origin.x + nx);
+  rect.y = (int) floor (bounds.origin.y + ny);
+  rect.width = (int) ceilf (bounds.size.width);
+  rect.width = (int) ceilf (bounds.size.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);