From: Matthias Clasen Date: Sun, 29 Dec 2019 02:04:19 +0000 (-0500) Subject: tooltips: Stop using GTK_WINDOW_POPUP X-Git-Tag: archive/raspbian/4.4.1+ds1-2+rpi1^2~18^2~20^2~485^2~1 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=f31a016efb3674ac5c660f66475f44a2075c44df;p=gtk4.git tooltips: Stop using GTK_WINDOW_POPUP Make GtkTooltipWindow a GtkNative implementation, instead of using a GTK_WINDOW_POPUP window. --- 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); } diff --git a/gtk/gtktooltipwindow.c b/gtk/gtktooltipwindow.c index f614acb60e..d4615647c7 100644 --- a/gtk/gtktooltipwindow.c +++ b/gtk/gtktooltipwindow.c @@ -38,11 +38,27 @@ #include "gtksizerequest.h" #include "gtkwindowprivate.h" #include "gtkwidgetprivate.h" +#include "gtknative.h" +#include "gtkstylecontext.h" +#include "gtkcssnodeprivate.h" struct _GtkTooltipWindow { GtkWindow parent_type; + GdkSurface *surface; + GskRenderer *renderer; + + GdkSurfaceState state; + GtkWidget *relative_to; + GdkRectangle rect; + GdkGravity rect_anchor; + GdkGravity surface_anchor; + GdkAnchorHints anchor_hints; + int dx; + int dy; + guint surface_transform_changed_cb; + GtkWidget *box; GtkWidget *image; GtkWidget *label; @@ -54,13 +70,349 @@ struct _GtkTooltipWindowClass GtkWindowClass parent_class; }; -G_DEFINE_TYPE (GtkTooltipWindow, gtk_tooltip_window, GTK_TYPE_WINDOW) +static void gtk_tooltip_window_native_init (GtkNativeInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GtkTooltipWindow, gtk_tooltip_window, GTK_TYPE_BIN, + G_IMPLEMENT_INTERFACE (GTK_TYPE_NATIVE, + gtk_tooltip_window_native_init)) + + +static GdkSurface * +gtk_tooltip_window_native_get_surface (GtkNative *native) +{ + GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (native); + + return window->surface; +} + +static GskRenderer * +gtk_tooltip_window_native_get_renderer (GtkNative *native) +{ + GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (native); + + return window->renderer; +} + +static void +gtk_tooltip_window_native_get_surface_transform (GtkNative *native, + int *x, + int *y) +{ + GtkStyleContext *context; + GtkBorder margin, border, padding; + + context = gtk_widget_get_style_context (GTK_WIDGET (native)); + gtk_style_context_get_margin (context, &margin); + gtk_style_context_get_border (context, &border); + gtk_style_context_get_padding (context, &padding); + + *x = margin.left + border.left + padding.left; + *y = margin.top + border.top + padding.top; +} + +static void +move_to_rect (GtkTooltipWindow *window) +{ + gdk_surface_move_to_rect (window->surface, + &window->rect, + window->rect_anchor, + window->surface_anchor, + window->anchor_hints, + window->dx, + window->dy); +} + +static void +gtk_tooltip_window_move_resize (GtkTooltipWindow *window) +{ + GtkRequisition req; + + if (window->surface) + { + gtk_widget_get_preferred_size (GTK_WIDGET (window), NULL, &req); + gdk_surface_resize (window->surface, req.width, req.height); + move_to_rect (window); + } +} + +static void +gtk_tooltip_window_native_check_resize (GtkNative *native) +{ + GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (native); + GtkWidget *widget = GTK_WIDGET (native); + + if (!_gtk_widget_get_alloc_needed (widget)) + gtk_widget_ensure_allocate (widget); + else if (gtk_widget_get_visible (widget)) + { + gtk_tooltip_window_move_resize (window); + if (window->surface) + gtk_widget_allocate (GTK_WIDGET (window), + gdk_surface_get_width (window->surface), + gdk_surface_get_height (window->surface), + -1, NULL); + } +} + +static void +gtk_tooltip_window_native_init (GtkNativeInterface *iface) +{ + iface->get_surface = gtk_tooltip_window_native_get_surface; + iface->get_renderer = gtk_tooltip_window_native_get_renderer; + iface->get_surface_transform = gtk_tooltip_window_native_get_surface_transform; + iface->check_resize = gtk_tooltip_window_native_check_resize; +} + +static void +surface_state_changed (GtkWidget *widget) +{ + GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget); + GdkSurfaceState new_surface_state; + GdkSurfaceState changed_mask; + + new_surface_state = gdk_surface_get_state (window->surface); + changed_mask = new_surface_state ^ window->state; + window->state = new_surface_state; + + if (changed_mask & GDK_SURFACE_STATE_WITHDRAWN) + { + if (window->state & GDK_SURFACE_STATE_WITHDRAWN) + gtk_widget_hide (widget); + } +} + +static void +surface_size_changed (GtkWidget *widget, + guint width, + guint height) +{ +} + +static gboolean +surface_render (GdkSurface *surface, + cairo_region_t *region, + GtkWidget *widget) +{ + gtk_widget_render (widget, surface, region); + return TRUE; +} + +static gboolean +surface_event (GdkSurface *surface, + GdkEvent *event, + GtkWidget *widget) +{ + gtk_main_do_event (event); + return TRUE; +} + +static void +surface_moved_to_rect (GdkSurface *surface, + GdkRectangle *flipped_rect, + GdkRectangle *final_rect, + gboolean flipped_x, + gboolean flipped_y, + GtkWidget *widget) +{ +} + +static void +gtk_tooltip_window_realize (GtkWidget *widget) +{ + GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget); + GdkDisplay *display; + GdkSurface *parent; + + display = gtk_widget_get_display (window->relative_to); + + parent = gtk_native_get_surface (gtk_widget_get_native (window->relative_to)); + window->surface = gdk_surface_new_popup (display, parent, FALSE); + + gdk_surface_set_widget (window->surface, widget); + + g_signal_connect_swapped (window->surface, "notify::state", G_CALLBACK (surface_state_changed), widget); + g_signal_connect_swapped (window->surface, "size-changed", G_CALLBACK (surface_size_changed), widget); + g_signal_connect (window->surface, "render", G_CALLBACK (surface_render), widget); + g_signal_connect (window->surface, "event", G_CALLBACK (surface_event), widget); + g_signal_connect (window->surface, "moved-to-rect", G_CALLBACK (surface_moved_to_rect), widget); + + GTK_WIDGET_CLASS (gtk_tooltip_window_parent_class)->realize (widget); + + window->renderer = gsk_renderer_new_for_surface (window->surface); +} + +static void +gtk_tooltip_window_unrealize (GtkWidget *widget) +{ + GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget); + + GTK_WIDGET_CLASS (gtk_tooltip_window_parent_class)->unrealize (widget); + + gsk_renderer_unrealize (window->renderer); + g_clear_object (&window->renderer); + + g_signal_handlers_disconnect_by_func (window->surface, surface_state_changed, widget); + g_signal_handlers_disconnect_by_func (window->surface, surface_size_changed, widget); + g_signal_handlers_disconnect_by_func (window->surface, surface_render, widget); + g_signal_handlers_disconnect_by_func (window->surface, surface_event, widget); + g_signal_handlers_disconnect_by_func (window->surface, surface_moved_to_rect, widget); + gdk_surface_set_widget (window->surface, NULL); + gdk_surface_destroy (window->surface); + g_clear_object (&window->surface); +} + + +static void +unset_surface_transform_changed_cb (gpointer data) +{ + GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (data); + + window->surface_transform_changed_cb = 0; +} + +static gboolean +surface_transform_changed_cb (GtkWidget *widget, + const graphene_matrix_t *transform, + gpointer user_data) +{ + GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget); + + move_to_rect (window); + + return G_SOURCE_CONTINUE; +} + + +static void +gtk_tooltip_window_map (GtkWidget *widget) +{ + GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget); + GtkWidget *child; + + gdk_surface_show (window->surface); + move_to_rect (window); + + window->surface_transform_changed_cb = + gtk_widget_add_surface_transform_changed_callback (window->relative_to, + surface_transform_changed_cb, + window, + unset_surface_transform_changed_cb); + + GTK_WIDGET_CLASS (gtk_tooltip_window_parent_class)->map (widget); + + child = gtk_bin_get_child (GTK_BIN (widget)); + if (child != NULL && gtk_widget_get_visible (child)) + gtk_widget_map (child); +} + +static void +gtk_tooltip_window_unmap (GtkWidget *widget) +{ + GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget); + GtkWidget *child; + + gtk_widget_remove_surface_transform_changed_callback (window->relative_to, + window->surface_transform_changed_cb); + window->surface_transform_changed_cb = 0; + + GTK_WIDGET_CLASS (gtk_tooltip_window_parent_class)->unmap (widget); + gdk_surface_hide (window->surface); + + child = gtk_bin_get_child (GTK_BIN (widget)); + if (child != NULL) + gtk_widget_unmap (child); +} + +static void +gtk_tooltip_window_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkWidget *child; + + child = gtk_bin_get_child (GTK_BIN (widget)); + + if (child) + gtk_widget_measure (child, + orientation, for_size, + minimum, natural, + minimum_baseline, natural_baseline); +} + +static void +gtk_tooltip_window_size_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ + GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget); + GtkWidget *child; + + gtk_tooltip_window_move_resize (window); + + child = gtk_bin_get_child (GTK_BIN (window)); + + if (child) + gtk_widget_allocate (child, width, height, baseline, NULL); +} + +static void +gtk_tooltip_window_show (GtkWidget *widget) +{ + _gtk_widget_set_visible_flag (widget, TRUE); + gtk_css_node_validate (gtk_widget_get_css_node (widget)); + gtk_widget_realize (widget); + gtk_tooltip_window_native_check_resize (GTK_NATIVE (widget)); + gtk_widget_map (widget); +} + +static void +gtk_tooltip_window_hide (GtkWidget *widget) +{ + _gtk_widget_set_visible_flag (widget, FALSE); + gtk_widget_unmap (widget); +} + +static void size_changed (GtkWidget *widget, + int width, + int height, + int baseline, + GtkTooltipWindow *window); + +static void +gtk_tooltip_window_dispose (GObject *object) +{ + GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (object); + + if (window->relative_to) + { + g_signal_handlers_disconnect_by_func (window->relative_to, size_changed, window); + gtk_widget_unparent (GTK_WIDGET (window)); + } + + G_OBJECT_CLASS (gtk_tooltip_window_parent_class)->dispose (object); +} static void gtk_tooltip_window_class_init (GtkTooltipWindowClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + object_class->dispose = gtk_tooltip_window_dispose; + widget_class->realize = gtk_tooltip_window_realize; + widget_class->unrealize = gtk_tooltip_window_unrealize; + widget_class->map = gtk_tooltip_window_map; + widget_class->unmap = gtk_tooltip_window_unmap; + widget_class->measure = gtk_tooltip_window_measure; + widget_class->size_allocate = gtk_tooltip_window_size_allocate; + widget_class->show = gtk_tooltip_window_show; + widget_class->hide = gtk_tooltip_window_hide; + gtk_widget_class_set_css_name (widget_class, I_("tooltip")); gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_TOOL_TIP); gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtktooltipwindow.ui"); @@ -68,24 +420,20 @@ gtk_tooltip_window_class_init (GtkTooltipWindowClass *klass) gtk_widget_class_bind_template_child (widget_class, GtkTooltipWindow, box); gtk_widget_class_bind_template_child (widget_class, GtkTooltipWindow, image); gtk_widget_class_bind_template_child (widget_class, GtkTooltipWindow, label); + + gtk_widget_class_set_css_name (widget_class, "tooltip"); } static void gtk_tooltip_window_init (GtkTooltipWindow *self) { - GtkWindow *window = GTK_WINDOW (self); - gtk_widget_init_template (GTK_WIDGET (self)); - - _gtk_window_request_csd (window); } GtkWidget * gtk_tooltip_window_new (void) { - return g_object_new (GTK_TYPE_TOOLTIP_WINDOW, - "type", GTK_WINDOW_POPUP, - NULL); + return g_object_new (GTK_TYPE_TOOLTIP_WINDOW, NULL); } void @@ -191,5 +539,65 @@ gtk_tooltip_window_set_custom_widget (GtkTooltipWindow *window, gtk_container_add (GTK_CONTAINER (window->box), custom_widget); gtk_widget_show (custom_widget); + gtk_widget_hide (window->image); + gtk_widget_hide (window->label); } } + +static void +size_changed (GtkWidget *widget, + int width, + int height, + int baseline, + GtkTooltipWindow *window) +{ + gtk_native_check_resize (GTK_NATIVE (window)); +} + +void +gtk_tooltip_window_set_relative_to (GtkTooltipWindow *window, + GtkWidget *relative_to) +{ + if (window->relative_to == relative_to) + return; + + g_object_ref (window); + + if (window->relative_to) + { + g_signal_handlers_disconnect_by_func (window->relative_to, size_changed, window); + gtk_widget_unparent (GTK_WIDGET (window)); + } + + window->relative_to = relative_to; + + if (window->relative_to) + { + g_signal_connect (window->relative_to, "size-allocate", G_CALLBACK (size_changed), window); + gtk_css_node_set_parent (gtk_widget_get_css_node (GTK_WIDGET (window)), + gtk_widget_get_css_node (relative_to)); + gtk_widget_set_parent (GTK_WIDGET (window), relative_to); + } + + g_object_unref (window); +} + +void +gtk_tooltip_window_position (GtkTooltipWindow *window, + GdkRectangle *rect, + GdkGravity rect_anchor, + GdkGravity surface_anchor, + GdkAnchorHints anchor_hints, + int dx, + int dy) +{ + window->rect = *rect; + window->rect_anchor = rect_anchor; + window->surface_anchor = surface_anchor; + window->anchor_hints = anchor_hints; + window->dx = dx; + window->dy = dy; + + move_to_rect (window); +} + diff --git a/gtk/gtktooltipwindowprivate.h b/gtk/gtktooltipwindowprivate.h index ad26f8dd92..13556d41e3 100644 --- a/gtk/gtktooltipwindowprivate.h +++ b/gtk/gtktooltipwindowprivate.h @@ -49,6 +49,15 @@ void gtk_tooltip_window_set_image_icon_from_gicon (GtkTooltipWindo GIcon *gicon); void gtk_tooltip_window_set_custom_widget (GtkTooltipWindow *window, GtkWidget *custom_widget); +void gtk_tooltip_window_set_relative_to (GtkTooltipWindow *window, + GtkWidget *relative_to); +void gtk_tooltip_window_position (GtkTooltipWindow *window, + GdkRectangle *rect, + GdkGravity rect_anchor, + GdkGravity surface_anchor, + GdkAnchorHints anchor_hints, + int dx, + int dy); G_END_DECLS diff --git a/gtk/ui/gtktooltipwindow.ui b/gtk/ui/gtktooltipwindow.ui index bb4329f18b..2dd5584646 100644 --- a/gtk/ui/gtktooltipwindow.ui +++ b/gtk/ui/gtktooltipwindow.ui @@ -1,8 +1,9 @@ -