From bed4c68041fb77a683c29ec5a5e6ddddb441058c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 3 Mar 2019 19:40:32 +0100 Subject: [PATCH] widget: Fix gtk_widget_pick() on 3d-transformed widgets Picking is done by drawing a line along the parent's z axis and picking at the intersection with the child's z=0 plane. However, the previous code was casting a ray along the child's z axis. This patch actually transforms the line to pick into the target's coordinate system and then computes the corrrect intersection with the z=0 plane. Using graphene_point3d_interpolate() to compute the final intersection point is a bit of abuse of that function, but I found no better way in Graphene to achieve the same thing. --- gtk/gtkwidget.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 80f8dcc099..56f26387a9 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -822,13 +822,20 @@ gtk_widget_real_pick (GtkWidget *widget, GtkWidgetPrivate *priv = gtk_widget_get_instance_private (child); graphene_matrix_t inv; GtkWidget *picked; - graphene_point_t p; + graphene_point3d_t p0, p1, res; - graphene_matrix_inverse (&priv->transform, &inv); - graphene_point_init (&p, x, y); - graphene_matrix_transform_point (&inv, &p, &p); + if (!graphene_matrix_inverse (&priv->transform, &inv)) + continue; + graphene_point3d_init (&p0, x, y, 0); + graphene_point3d_init (&p1, x, y, 1); + graphene_matrix_transform_point3d (&inv, &p0, &p0); + graphene_matrix_transform_point3d (&inv, &p1, &p1); + if (fabs (p0.z - p1.z) < 1.f / 4096) + continue; - picked = gtk_widget_pick (child, p.x, p.y); + graphene_point3d_interpolate (&p0, &p1, p0.z / (p0.z - p1.z), &res); + + picked = gtk_widget_pick (child, res.x, res.y); if (picked) return picked; }