summaryrefslogtreecommitdiff
path: root/gtk/gtktooltip.c
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2019-12-28 21:04:19 -0500
committerMatthias Clasen <mclasen@redhat.com>2019-12-29 22:09:13 -0500
commitf31a016efb3674ac5c660f66475f44a2075c44df (patch)
tree28ce3ad0d9be51fefa56dd0e6ae07fa75582f405 /gtk/gtktooltip.c
parente56eb7b17b40ee4a1e16a3964b72feddbecea032 (diff)
downloadgtk+-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.c185
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);
}