diff options
author | Matthias Clasen <mclasen@redhat.com> | 2019-12-28 21:04:19 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2019-12-29 22:09:13 -0500 |
commit | f31a016efb3674ac5c660f66475f44a2075c44df (patch) | |
tree | 28ce3ad0d9be51fefa56dd0e6ae07fa75582f405 /gtk/gtktooltip.c | |
parent | e56eb7b17b40ee4a1e16a3964b72feddbecea032 (diff) | |
download | gtk+-f31a016efb3674ac5c660f66475f44a2075c44df.tar.gz |
tooltips: Stop using GTK_WINDOW_POPUP
Make GtkTooltipWindow a GtkNative implementation,
instead of using a GTK_WINDOW_POPUP window.
Diffstat (limited to 'gtk/gtktooltip.c')
-rw-r--r-- | gtk/gtktooltip.c | 185 |
1 files changed, 84 insertions, 101 deletions
diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c index 9b1ef188c3..88cf89651d 100644 --- a/gtk/gtktooltip.c +++ b/gtk/gtktooltip.c @@ -87,6 +87,13 @@ #define GTK_IS_TOOLTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_TOOLTIP)) #define GTK_TOOLTIP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TOOLTIP, GtkTooltipClass)) +/* We keep a single GtkTooltip object per display. The tooltip object + * owns a GtkTooltipWindow widget, which is using a popup surface, similar + * to what a GtkPopover does. It gets reparented to the right native widget + * whenever a tooltip is to be shown. The tooltip object keeps a weak + * ref on the native in order to remove the tooltip window when the + * native goes away. + */ typedef struct _GtkTooltipClass GtkTooltipClass; struct _GtkTooltip @@ -95,11 +102,9 @@ struct _GtkTooltip GtkWidget *window; - GtkWindow *current_window; - GtkWidget *tooltip_widget; - GdkSurface *last_surface; + GtkWidget *native; guint timeout_id; guint browse_mode_timeout_id; @@ -116,7 +121,7 @@ struct _GtkTooltipClass GObjectClass parent_class; }; -#define GTK_TOOLTIP_VISIBLE(tooltip) ((tooltip)->current_window && gtk_widget_get_visible (GTK_WIDGET((tooltip)->current_window))) +#define GTK_TOOLTIP_VISIBLE(tooltip) ((tooltip)->window && gtk_widget_get_visible (GTK_WIDGET((tooltip)->window))) static void gtk_tooltip_dispose (GObject *object); @@ -125,7 +130,7 @@ static void gtk_tooltip_window_hide (GtkWidget *widget, static void gtk_tooltip_display_closed (GdkDisplay *display, gboolean was_error, GtkTooltip *tooltip); -static void gtk_tooltip_set_last_surface (GtkTooltip *tooltip, +static void gtk_tooltip_set_surface (GtkTooltip *tooltip, GdkSurface *surface); static void gtk_tooltip_handle_event_internal (GdkEventType event_type, @@ -134,16 +139,7 @@ static void gtk_tooltip_handle_event_internal (GdkEventType event_type, gdouble dx, gdouble dy); -static inline GQuark tooltip_quark (void) -{ - static GQuark quark; - - if G_UNLIKELY (quark == 0) - quark = g_quark_from_static_string ("gdk-display-current-tooltip"); - return quark; -} - -#define quark_current_tooltip tooltip_quark() +static GQuark quark_current_tooltip; G_DEFINE_TYPE (GtkTooltip, gtk_tooltip, G_TYPE_OBJECT); @@ -152,6 +148,8 @@ gtk_tooltip_class_init (GtkTooltipClass *klass) { GObjectClass *object_class; + quark_current_tooltip = g_quark_from_static_string ("gdk-display-current-tooltip"); + object_class = G_OBJECT_CLASS (klass); object_class->dispose = gtk_tooltip_dispose; @@ -165,13 +163,12 @@ gtk_tooltip_init (GtkTooltip *tooltip) tooltip->browse_mode_enabled = FALSE; - tooltip->current_window = NULL; - tooltip->tooltip_widget = NULL; - tooltip->last_surface = NULL; + tooltip->native = NULL; tooltip->window = gtk_tooltip_window_new (); + g_object_ref_sink (tooltip->window); g_signal_connect (tooltip->window, "hide", G_CALLBACK (gtk_tooltip_window_hide), tooltip); @@ -195,7 +192,7 @@ gtk_tooltip_dispose (GObject *object) } gtk_tooltip_set_custom (tooltip, NULL); - gtk_tooltip_set_last_surface (tooltip, NULL); + gtk_tooltip_set_surface (tooltip, NULL); if (tooltip->window) { @@ -205,8 +202,8 @@ gtk_tooltip_dispose (GObject *object) g_signal_handlers_disconnect_by_func (display, gtk_tooltip_display_closed, tooltip); - gtk_widget_destroy (tooltip->window); - tooltip->window = NULL; + gtk_tooltip_window_set_relative_to (GTK_TOOLTIP_WINDOW (tooltip->window), NULL); + g_clear_object (&tooltip->window); } G_OBJECT_CLASS (gtk_tooltip_parent_class)->dispose (object); @@ -476,37 +473,40 @@ gtk_tooltip_display_closed (GdkDisplay *display, } static void -gtk_tooltip_set_last_surface (GtkTooltip *tooltip, - GdkSurface *surface) +native_weak_notify (gpointer data, GObject *former_object) { - GtkWidget *window_widget = NULL; + GtkTooltip *tooltip = data; - if (tooltip->last_surface == surface) - return; + gtk_tooltip_window_set_relative_to (GTK_TOOLTIP_WINDOW (tooltip->window), NULL); + tooltip->native = NULL; +} - if (tooltip->last_surface) - g_object_remove_weak_pointer (G_OBJECT (tooltip->last_surface), - (gpointer *) &tooltip->last_surface); +static void +gtk_tooltip_set_surface (GtkTooltip *tooltip, + GdkSurface *surface) +{ + GtkWidget *native; - tooltip->last_surface = surface; + if (surface) + native = gtk_native_get_for_surface (surface); + else + native = NULL; - if (tooltip->last_surface) - g_object_add_weak_pointer (G_OBJECT (tooltip->last_surface), - (gpointer *) &tooltip->last_surface); + if (tooltip->native == native) + return; - if (surface) - window_widget = gtk_native_get_for_surface (surface); + if (tooltip->native) + g_object_weak_unref (G_OBJECT (tooltip->native), native_weak_notify, tooltip); + + tooltip->native = native; - if (window_widget) - window_widget = GTK_WIDGET (gtk_widget_get_root (window_widget)); + if (tooltip->native) + g_object_weak_ref (G_OBJECT (tooltip->native), native_weak_notify, tooltip); - if (window_widget && - window_widget != tooltip->window && - GTK_IS_WINDOW (window_widget)) - gtk_window_set_transient_for (GTK_WINDOW (tooltip->window), - GTK_WINDOW (window_widget)); + if (native) + gtk_tooltip_window_set_relative_to (GTK_TOOLTIP_WINDOW (tooltip->window), native); else - gtk_window_set_transient_for (GTK_WINDOW (tooltip->window), NULL); + gtk_tooltip_window_set_relative_to (GTK_TOOLTIP_WINDOW (tooltip->window), NULL); } static gboolean @@ -567,19 +567,17 @@ gtk_tooltip_position (GtkTooltip *tooltip, GtkSettings *settings; graphene_rect_t anchor_bounds; GdkRectangle anchor_rect; - GdkSurface *surface; GdkSurface *effective_toplevel; GtkWidget *toplevel; int rect_anchor_dx = 0; int cursor_size; int anchor_rect_padding; - gtk_widget_realize (GTK_WIDGET (tooltip->current_window)); - surface = gtk_native_get_surface (GTK_NATIVE (tooltip->current_window)); + gtk_widget_realize (GTK_WIDGET (tooltip->window)); tooltip->tooltip_widget = new_tooltip_widget; - toplevel = GTK_WIDGET (gtk_widget_get_root (new_tooltip_widget)); + toplevel = GTK_WIDGET (gtk_widget_get_native (new_tooltip_widget)); if (gtk_widget_compute_bounds (new_tooltip_widget, toplevel, &anchor_bounds)) { anchor_rect = (GdkRectangle) { @@ -657,16 +655,12 @@ gtk_tooltip_position (GtkTooltip *tooltip, } } - gtk_window_set_transient_for (GTK_WINDOW (tooltip->current_window), - GTK_WINDOW (toplevel)); - - gdk_surface_move_to_rect (surface, - &anchor_rect, - GDK_GRAVITY_SOUTH, - GDK_GRAVITY_NORTH, - GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE_X, - rect_anchor_dx, 0); - gtk_widget_show (GTK_WIDGET (tooltip->current_window)); + gtk_tooltip_window_position (GTK_TOOLTIP_WINDOW (tooltip->window), + &anchor_rect, + GDK_GRAVITY_SOUTH, + GDK_GRAVITY_NORTH, + GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE_X, + rect_anchor_dx, 0); } static void @@ -682,20 +676,18 @@ gtk_tooltip_show_tooltip (GdkDisplay *display) tooltip = g_object_get_qdata (G_OBJECT (display), quark_current_tooltip); - { - surface = tooltip->last_surface; + if (!tooltip->native) + return; - if (!GDK_IS_SURFACE (surface)) - return; + surface = gtk_native_get_surface (GTK_NATIVE (tooltip->native)); - device = gdk_seat_get_pointer (gdk_display_get_default_seat (display)); + device = gdk_seat_get_pointer (gdk_display_get_default_seat (display)); - gdk_surface_get_device_position (surface, device, &px, &py, NULL); - x = round (px); - y = round (py); + gdk_surface_get_device_position (surface, device, &px, &py, NULL); + x = round (px); + y = round (py); - tooltip_widget = _gtk_widget_find_at_coords (surface, x, y, &x, &y); - } + tooltip_widget = _gtk_widget_find_at_coords (surface, x, y, &x, &y); if (!tooltip_widget) return; @@ -704,10 +696,7 @@ gtk_tooltip_show_tooltip (GdkDisplay *display) if (!return_value) return; - if (!tooltip->current_window) - tooltip->current_window = GTK_WINDOW (GTK_TOOLTIP (tooltip)->window); - - /* FIXME: should use tooltip->current_window iso tooltip->window */ + /* FIXME: should use tooltip->window iso tooltip->window */ if (display != gtk_widget_get_display (tooltip->window)) { g_signal_handlers_disconnect_by_func (display, @@ -722,6 +711,8 @@ gtk_tooltip_show_tooltip (GdkDisplay *display) gtk_tooltip_position (tooltip, display, tooltip_widget, device); + gtk_widget_show (GTK_WIDGET (tooltip->window)); + /* Now a tooltip is visible again on the display, make sure browse * mode is enabled. */ @@ -765,11 +756,8 @@ gtk_tooltip_hide_tooltip (GtkTooltip *tooltip) g_source_set_name_by_id (tooltip->browse_mode_timeout_id, "[gtk] tooltip_browse_mode_expired"); } - if (tooltip->current_window) - { - gtk_widget_hide (GTK_WIDGET (tooltip->current_window)); - tooltip->current_window = NULL; - } + if (tooltip->window) + gtk_widget_hide (tooltip->window); } static gint @@ -829,7 +817,7 @@ _gtk_tooltip_hide (GtkWidget *widget) display = gtk_widget_get_display (widget); tooltip = g_object_get_qdata (G_OBJECT (display), quark_current_tooltip); - if (!tooltip || !GTK_TOOLTIP_VISIBLE (tooltip) || !tooltip->tooltip_widget) + if (!tooltip || !tooltip->window || !tooltip->tooltip_widget) return; if (widget == tooltip->tooltip_widget) @@ -911,19 +899,19 @@ gtk_tooltip_handle_event_internal (GdkEventType event_type, { int x = dx, y = dy; GdkDisplay *display; - GtkTooltip *current_tooltip; + GtkTooltip *tooltip; display = gdk_surface_get_display (surface); - current_tooltip = g_object_get_qdata (G_OBJECT (display), quark_current_tooltip); + tooltip = g_object_get_qdata (G_OBJECT (display), quark_current_tooltip); - if (current_tooltip) - gtk_tooltip_set_last_surface (current_tooltip, surface); + if (tooltip) + gtk_tooltip_set_surface (tooltip, surface); /* Hide the tooltip when there's no new tooltip widget */ if (!target_widget) { - if (current_tooltip) - gtk_tooltip_hide_tooltip (current_tooltip); + if (tooltip) + gtk_tooltip_hide_tooltip (tooltip); return; } @@ -935,54 +923,49 @@ gtk_tooltip_handle_event_internal (GdkEventType event_type, case GDK_DRAG_ENTER: case GDK_GRAB_BROKEN: case GDK_SCROLL: - gtk_tooltip_hide_tooltip (current_tooltip); + gtk_tooltip_hide_tooltip (tooltip); break; case GDK_MOTION_NOTIFY: case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: - if (current_tooltip) + if (tooltip) { gboolean tip_area_set; GdkRectangle tip_area; gboolean hide_tooltip; - tip_area_set = current_tooltip->tip_area_set; - tip_area = current_tooltip->tip_area; + tip_area_set = tooltip->tip_area_set; + tip_area = tooltip->tip_area; - gtk_tooltip_run_requery (&target_widget, - current_tooltip, - &x, &y); + gtk_tooltip_run_requery (&target_widget, tooltip, &x, &y); /* Leave notify should override the query function */ hide_tooltip = (event_type == GDK_LEAVE_NOTIFY); /* Is the pointer above another widget now? */ - if (GTK_TOOLTIP_VISIBLE (current_tooltip)) - hide_tooltip |= target_widget != current_tooltip->tooltip_widget; + if (GTK_TOOLTIP_VISIBLE (tooltip)) + hide_tooltip |= target_widget != tooltip->tooltip_widget; /* Did the pointer move out of the previous "context area"? */ if (tip_area_set) hide_tooltip |= !gdk_rectangle_contains_point (&tip_area, x, y); if (hide_tooltip) - gtk_tooltip_hide_tooltip (current_tooltip); + gtk_tooltip_hide_tooltip (tooltip); else gtk_tooltip_start_delay (display); } else { /* Need a new tooltip for this display */ - current_tooltip = g_object_new (GTK_TYPE_TOOLTIP, NULL); - g_object_set_qdata_full (G_OBJECT (display), - quark_current_tooltip, - current_tooltip, - g_object_unref); + tooltip = g_object_new (GTK_TYPE_TOOLTIP, NULL); + g_object_set_qdata_full (G_OBJECT (display), quark_current_tooltip, + tooltip, g_object_unref); g_signal_connect (display, "closed", - G_CALLBACK (gtk_tooltip_display_closed), - current_tooltip); + G_CALLBACK (gtk_tooltip_display_closed), tooltip); - gtk_tooltip_set_last_surface (current_tooltip, surface); + gtk_tooltip_set_surface (tooltip, surface); gtk_tooltip_start_delay (display); } |