From febc29852b5feec2071b92bdd8d088c23a5affb0 Mon Sep 17 00:00:00 2001 From: Cosimo Cecchi Date: Thu, 6 Oct 2011 17:06:57 -0400 Subject: [PATCH] tooltip: add support for opacity and rounded corners for tooltips Rounded corners now will always work, using XShape in case we're not running a composite manager. Also, setting an RGBA visual (if available) on the tooltip toplevel enables them to be transparent if the theme specifies so. https://bugzilla.gnome.org/show_bug.cgi?id=599617 --- gtk/gtktooltip.c | 90 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 9 deletions(-) diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c index f65e08df4c..29f4630d42 100644 --- a/gtk/gtktooltip.c +++ b/gtk/gtktooltip.c @@ -157,6 +157,9 @@ static void gtk_tooltip_dispose (GObject *object); static gboolean gtk_tooltip_paint_window (GtkTooltip *tooltip, cairo_t *cr); +static void gtk_tooltip_realize_window (GtkTooltip *tooltip, + GtkWidget *widget); +static void maybe_update_shape (GtkTooltip *tooltip); static void gtk_tooltip_window_hide (GtkWidget *widget, gpointer user_data); static void gtk_tooltip_display_closed (GdkDisplay *display, @@ -186,6 +189,8 @@ gtk_tooltip_init (GtkTooltip *tooltip) GtkWidget *box; GtkWidget *image; GtkWidget *label; + GdkScreen *screen; + GdkVisual *visual; tooltip->timeout_id = 0; tooltip->browse_mode_timeout_id = 0; @@ -202,6 +207,12 @@ gtk_tooltip_init (GtkTooltip *tooltip) tooltip->last_window = NULL; window = g_object_ref (gtk_window_new (GTK_WINDOW_POPUP)); + screen = gtk_widget_get_screen (window); + visual = gdk_screen_get_rgba_visual (screen); + + if (visual != NULL) + gtk_widget_set_visual (window, visual); + gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_TOOLTIP); gtk_widget_set_app_paintable (window, TRUE); gtk_window_set_resizable (GTK_WINDOW (window), FALSE); @@ -214,6 +225,10 @@ gtk_tooltip_init (GtkTooltip *tooltip) g_signal_connect_swapped (window, "draw", G_CALLBACK (gtk_tooltip_paint_window), tooltip); + g_signal_connect_swapped (window, "realize", + G_CALLBACK (gtk_tooltip_realize_window), tooltip); + g_signal_connect_swapped (window, "composited-changed", + G_CALLBACK (maybe_update_shape), tooltip); /* FIXME: don't hardcode the padding */ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); @@ -569,20 +584,77 @@ gtk_tooltip_reset (GtkTooltip *tooltip) tooltip->custom_was_reset = FALSE; } +static void +paint_background_and_frame (GtkTooltip *tooltip, + cairo_t *cr) +{ + GtkStyleContext *context; + gint width, height; + + width = gtk_widget_get_allocated_width (tooltip->window); + height = gtk_widget_get_allocated_height (tooltip->window); + context = gtk_widget_get_style_context (tooltip->window); + + gtk_render_background (context, cr, + 0, 0, width, height); + gtk_render_frame (context, cr, + 0, 0, width, height); +} + +static void +maybe_update_shape (GtkTooltip *tooltip) +{ + cairo_t *cr; + cairo_surface_t *surface; + cairo_region_t *region; + gint width, height; + + /* fallback to XShape only for non-composited clients */ + if (gtk_widget_is_composited (tooltip->window)) + { + gtk_widget_shape_combine_region (tooltip->window, NULL); + return; + } + + surface = gdk_window_create_similar_surface (gtk_widget_get_window (tooltip->window), + CAIRO_CONTENT_COLOR_ALPHA, + gtk_widget_get_allocated_width (tooltip->window), + gtk_widget_get_allocated_height (tooltip->window)); + + cr = cairo_create (surface); + paint_background_and_frame (tooltip, cr); + cairo_destroy (cr); + + region = gdk_cairo_region_create_from_surface (surface); + gtk_widget_shape_combine_region (tooltip->window, region); + + cairo_surface_destroy (surface); + cairo_region_destroy (region); +} + +static void +gtk_tooltip_realize_window (GtkTooltip *tooltip, + GtkWidget *widget) +{ + maybe_update_shape (tooltip); +} + static gboolean gtk_tooltip_paint_window (GtkTooltip *tooltip, cairo_t *cr) { - GtkStyleContext *context; + if (gtk_widget_is_composited (tooltip->window)) + { + /* clear any background */ + cairo_save (cr); + cairo_set_source_rgba (cr, 0, 0, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + cairo_restore (cr); + } - context = gtk_widget_get_style_context (tooltip->window); - - gtk_render_background (context, cr, 0, 0, - gtk_widget_get_allocated_width (tooltip->window), - gtk_widget_get_allocated_height (tooltip->window)); - gtk_render_frame (context, cr, 0, 0, - gtk_widget_get_allocated_width (tooltip->window), - gtk_widget_get_allocated_height (tooltip->window)); + maybe_update_shape (tooltip); + paint_background_and_frame (tooltip, cr); return FALSE; }