From cf2d549e922b51e7c4c790c04531be0cfb6ddd63 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 5 Nov 2017 00:49:18 +0100 Subject: [PATCH] widget: Implement gtk_widget_pick() ... and use it. --- docs/reference/gtk/gtk4-sections.txt | 1 + gtk/gtkmain.c | 31 ++++------------ gtk/gtkpointerfocus.c | 5 +-- gtk/gtkwidget.c | 53 ++++++++++++++++++++++------ gtk/gtkwidget.h | 8 +++-- gtk/gtkwindow.c | 36 ++++++------------- gtk/inspector/inspect-button.c | 14 ++------ 7 files changed, 70 insertions(+), 78 deletions(-) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 0c5003ccf2..27c8de3280 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -4592,6 +4592,7 @@ gtk_widget_get_width gtk_widget_get_height gtk_widget_get_clip gtk_widget_contains +gtk_widget_pick gtk_widget_get_can_default gtk_widget_set_can_default gtk_widget_get_can_focus diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index 198bd91373..5837f7ceb5 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -1509,7 +1509,9 @@ handle_pointing_event (GdkEvent *event) case GDK_TOUCH_BEGIN: case GDK_TOUCH_UPDATE: case GDK_MOTION_NOTIFY: - target = _gtk_toplevel_pick (toplevel, x, y, NULL, NULL); + target = gtk_widget_pick (GTK_WIDGET (toplevel), x, y); + if (target == NULL) + target = GTK_WIDGET (toplevel); old_target = update_pointer_focus_state (toplevel, event, target); if (event->type == GDK_MOTION_NOTIFY || event->type == GDK_ENTER_NOTIFY) @@ -1544,7 +1546,9 @@ handle_pointing_event (GdkEvent *event) if (event->type == GDK_BUTTON_RELEASE) { old_target = target; - target = _gtk_toplevel_pick (toplevel, x, y, NULL, NULL); + target = gtk_widget_pick (GTK_WIDGET (toplevel), x, y); + if (target == NULL) + target = GTK_WIDGET (toplevel); gtk_synthesize_crossing_events (toplevel, old_target, target, event, GDK_CROSSING_UNGRAB); gtk_window_maybe_update_cursor (toplevel, NULL, device); @@ -2617,26 +2621,3 @@ gtk_propagate_event (GtkWidget *widget, gtk_propagate_event_internal (widget, event, topmost); } - -GtkWidget * -_gtk_toplevel_pick (GtkWindow *toplevel, - gdouble x, - gdouble y, - gdouble *x_out, - gdouble *y_out) -{ - GtkWidget *target = NULL, *widget = GTK_WIDGET (toplevel); - - while (widget) - { - target = widget; - widget = GTK_WIDGET_GET_CLASS (target)->pick (widget, x, y, &x, &y); - } - - if (x_out) - *x_out = x; - if (y_out) - *y_out = y; - - return target; -} diff --git a/gtk/gtkpointerfocus.c b/gtk/gtkpointerfocus.c index cb484b8d34..5229e39e12 100644 --- a/gtk/gtkpointerfocus.c +++ b/gtk/gtkpointerfocus.c @@ -133,7 +133,8 @@ gtk_pointer_focus_repick_target (GtkPointerFocus *focus) { GtkWidget *target; - target = _gtk_toplevel_pick (focus->toplevel, focus->x, focus->y, - NULL, NULL); + target = gtk_widget_pick (GTK_WIDGET (focus->toplevel), focus->x, focus->y); + if (target == NULL) + target = GTK_WIDGET (focus->toplevel); gtk_pointer_focus_set_target (focus, target); } diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 70152b9d4e..69dfe6d8ae 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -951,29 +951,28 @@ gtk_widget_real_contains (GtkWidget *widget, static GtkWidget * gtk_widget_real_pick (GtkWidget *widget, gdouble x, - gdouble y, - gdouble *x_out, - gdouble *y_out) + gdouble y) { GtkWidget *child; + if (!gtk_widget_contains (widget, x, y)) + return NULL; + for (child = _gtk_widget_get_last_child (widget); child; child = _gtk_widget_get_prev_sibling (child)) { + GtkWidget *picked; int dx, dy; gtk_widget_get_origin_relative_to_parent (child, &dx, &dy); - if (gtk_widget_contains (child, x - dx, y - dy)) - { - *x_out = x - dx; - *y_out = y - dy; - return child; - } + picked = gtk_widget_pick (child, x - dx, y - dy); + if (picked) + return picked; } - return NULL; + return widget; } static void @@ -13156,6 +13155,40 @@ gtk_widget_contains (GtkWidget *widget, return GTK_WIDGET_GET_CLASS (widget)->contains (widget, x, y); } +/** + * gtk_widget_pick: + * @widget: the widget to query + * @x: X coordinate to test, relative to @widget's origin + * @y: Y coordinate to test, relative to @widget's origin + * + * Finds the descendant of widget (including widget itself) closest + * to the screen at the point (@x, @y). The point must be given in + * widget coordinates, so (0, 0) is assumed to be the top left of + * @widget's content area. + * + * Usually widgets will return %NULL if the given coordinate is not + * contained in @widget checked via gtk_widget_contains(). Otherwise + * they will recursively try to find a child that does not return %NULL. + * Widgets are however free to customize their picking algorithm. + * + * This function is used on the toplevel to determine the widget below + * the mouse cursor for purposes of hover hilighting and delivering events. + * + * Returns: (nullable) (transfer none): The widget descendant at the given + * coordinate or %NULL if none. + * + * Since: 3.94 + **/ +GtkWidget * +gtk_widget_pick (GtkWidget *widget, + gdouble x, + gdouble y) +{ + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); + + return GTK_WIDGET_GET_CLASS (widget)->pick (widget, x, y); +} + void gtk_widget_get_outer_allocation (GtkWidget *widget, GdkRectangle *allocation) diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 0f4a785c17..3568d87362 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -472,9 +472,7 @@ struct _GtkWidgetClass gdouble y); GtkWidget * (* pick) (GtkWidget *widget, gdouble x, - gdouble y, - gdouble *x_out, - gdouble *y_out); + gdouble y); /*< private >*/ @@ -894,6 +892,10 @@ GDK_AVAILABLE_IN_3_94 gboolean gtk_widget_contains (GtkWidget *widget, gdouble x, gdouble y); +GDK_AVAILABLE_IN_3_94 +GtkWidget * gtk_widget_pick (GtkWidget *widget, + gdouble x, + gdouble y); /* Hide widget and return TRUE. */ GDK_AVAILABLE_IN_ALL diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index ed60d5cf05..6a806357b0 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -742,9 +742,7 @@ static void popover_get_rect (GtkWindowPopover *popover, static GtkWidget * gtk_window_pick (GtkWidget *widget, gdouble x, - gdouble y, - gdouble *x_out, - gdouble *y_out) + gdouble y) { GtkWindow *window = GTK_WINDOW (widget); GList *popovers; @@ -752,33 +750,19 @@ gtk_window_pick (GtkWidget *widget, for (popovers = window->priv->popovers.tail; popovers; popovers = popovers->prev) { GtkWindowPopover *popover = popovers->data; - cairo_rectangle_int_t rect; - - if (!gtk_widget_is_sensitive (popover->widget) || - !gtk_widget_is_drawable (popover->widget)) - continue; + int dest_x, dest_y; + GtkWidget *picked; - gtk_widget_get_outer_allocation (popover->widget, &rect); + gtk_widget_translate_coordinates (widget, popover->widget, + x, y, + &dest_x, &dest_y); - if (gdk_rectangle_contains_point (&rect, x, y)) - { - if (x_out && y_out) - { - int dest_x, dest_y; - gtk_widget_translate_coordinates (widget, popover->widget, - x, y, - &dest_x, &dest_y); - - *x_out = dest_x; - *y_out = dest_y; - } - - return popover->widget; - } + picked = gtk_widget_pick (popover->widget, dest_x, dest_y); + if (picked) + return picked; } - return GTK_WIDGET_CLASS (gtk_window_parent_class)->pick (widget, x, y, - x_out, y_out); + return GTK_WIDGET_CLASS (gtk_window_parent_class)->pick (widget, x, y); } static void diff --git a/gtk/inspector/inspect-button.c b/gtk/inspector/inspect-button.c index 8c5ecdc0d3..517e716c0f 100644 --- a/gtk/inspector/inspect-button.c +++ b/gtk/inspector/inspect-button.c @@ -73,20 +73,10 @@ find_widget_at_pointer (GdkDevice *device) gdk_window_get_device_position_double (gtk_widget_get_window (widget), device, &x, &y, NULL); - while (widget) - { - GtkWidget *w; - - w = GTK_WIDGET_GET_CLASS (widget)->pick (widget, x, y, &x, &y); - - if (!w) - return widget; - - widget = w; - } + widget = gtk_widget_pick (widget, x, y); } - return NULL; + return widget; } static gboolean draw_flash (GtkWidget *widget, -- 2.30.2