X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtktooltip.c;h=aba9ffb38a173b8be9a9a377bc19c76c4c9f05d2;hb=fd51c8f5e9d6fb68c8e81b9b1e2ab80931f963f0;hp=8ef7754ddee20a44fc647c3447a0e3a43efa12cf;hpb=ccaf8429198d0ab329a202979973e4bf71aafb78;p=~andy%2Fgtk diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c index 8ef7754dd..aba9ffb38 100644 --- a/gtk/gtktooltip.c +++ b/gtk/gtktooltip.c @@ -14,9 +14,7 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ #include "config.h" @@ -31,9 +29,16 @@ #include "gtkmain.h" #include "gtklabel.h" #include "gtkimage.h" -#include "gtkhbox.h" -#include "gtkalignment.h" +#include "gtkbox.h" +#include "gtksettings.h" #include "gtksizerequest.h" +#include "gtkstylecontext.h" +#include "gtkwindowprivate.h" + + +#ifdef GDK_WINDOWING_WAYLAND +#include "wayland/gdkwayland.h" +#endif /** @@ -116,7 +121,6 @@ struct _GtkTooltip GObject parent_instance; GtkWidget *window; - GtkWidget *alignment; GtkWidget *box; GtkWidget *image; GtkWidget *label; @@ -155,9 +159,12 @@ static void gtk_tooltip_class_init (GtkTooltipClass *klass); static void gtk_tooltip_init (GtkTooltip *tooltip); static void gtk_tooltip_dispose (GObject *object); -static void gtk_tooltip_window_style_set (GtkTooltip *tooltip); static gboolean gtk_tooltip_paint_window (GtkTooltip *tooltip, cairo_t *cr); +static void gtk_tooltip_realize_window (GtkTooltip *tooltip, + GtkWidget *widget); +static void gtk_tooltip_composited_changed (GtkTooltip *tooltip, + GtkWidget *widget); static void gtk_tooltip_window_hide (GtkWidget *widget, gpointer user_data); static void gtk_tooltip_display_closed (GdkDisplay *display, @@ -182,7 +189,13 @@ gtk_tooltip_class_init (GtkTooltipClass *klass) static void gtk_tooltip_init (GtkTooltip *tooltip) { - GtkStyle *style; + GtkStyleContext *context; + GtkWidget *window; + GtkWidget *box; + GtkWidget *image; + GtkWidget *label; + GdkScreen *screen; + GdkVisual *visual; tooltip->timeout_id = 0; tooltip->browse_mode_timeout_id = 0; @@ -198,42 +211,50 @@ gtk_tooltip_init (GtkTooltip *tooltip) tooltip->last_window = NULL; - tooltip->window = g_object_ref (gtk_window_new (GTK_WINDOW_POPUP)); - gtk_window_set_type_hint (GTK_WINDOW (tooltip->window), - GDK_WINDOW_TYPE_HINT_TOOLTIP); - gtk_widget_set_app_paintable (tooltip->window, TRUE); - gtk_window_set_resizable (GTK_WINDOW (tooltip->window), FALSE); - gtk_widget_set_name (tooltip->window, "gtk-tooltip"); - g_signal_connect (tooltip->window, "hide", - G_CALLBACK (gtk_tooltip_window_hide), tooltip); - - style = gtk_widget_get_style (tooltip->window); - - tooltip->alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0); - gtk_alignment_set_padding (GTK_ALIGNMENT (tooltip->alignment), - style->ythickness, style->ythickness, - style->xthickness, style->xthickness); - gtk_container_add (GTK_CONTAINER (tooltip->window), tooltip->alignment); - gtk_widget_show (tooltip->alignment); - - g_signal_connect_swapped (tooltip->window, "style-set", - G_CALLBACK (gtk_tooltip_window_style_set), tooltip); - g_signal_connect_swapped (tooltip->window, "draw", - G_CALLBACK (gtk_tooltip_paint_window), tooltip); - - tooltip->box = gtk_hbox_new (FALSE, style->xthickness); - gtk_container_add (GTK_CONTAINER (tooltip->alignment), tooltip->box); - gtk_widget_show (tooltip->box); - - tooltip->image = gtk_image_new (); - gtk_box_pack_start (GTK_BOX (tooltip->box), tooltip->image, - FALSE, FALSE, 0); - - tooltip->label = gtk_label_new (""); - gtk_label_set_line_wrap (GTK_LABEL (tooltip->label), TRUE); - gtk_box_pack_start (GTK_BOX (tooltip->box), tooltip->label, - FALSE, FALSE, 0); - + window = 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); + gtk_widget_set_name (window, "gtk-tooltip"); + g_signal_connect (window, "hide", + G_CALLBACK (gtk_tooltip_window_hide), tooltip); + + context = gtk_widget_get_style_context (window); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_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 (gtk_tooltip_composited_changed), tooltip); + + /* FIXME: don't hardcode the padding */ + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); + gtk_widget_set_margin_left (box, 6); + gtk_widget_set_margin_right (box, 6); + gtk_widget_set_margin_top (box, 6); + gtk_widget_set_margin_bottom (box, 6); + gtk_container_add (GTK_CONTAINER (window), box); + gtk_widget_show (box); + + image = gtk_image_new (); + gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0); + + label = gtk_label_new (""); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0); + + tooltip->window = window; + tooltip->box = box; + tooltip->image = image; + tooltip->label = label; tooltip->custom_widget = NULL; } @@ -532,9 +553,11 @@ gtk_tooltip_trigger_tooltip_query (GdkDisplay *display) gint x, y; GdkWindow *window; GdkEvent event; + GdkDevice *device; /* Trigger logic as if the mouse moved */ - window = gdk_display_get_window_at_pointer (display, &x, &y); + device = gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (display)); + window = gdk_device_get_window_at_position (device, &x, &y); if (!window) return; @@ -567,35 +590,83 @@ gtk_tooltip_reset (GtkTooltip *tooltip) } static void -gtk_tooltip_window_style_set (GtkTooltip *tooltip) +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) { - GtkStyle *style; + cairo_t *cr; + cairo_surface_t *surface; + cairo_region_t *region; + + /* fallback to XShape only for non-composited clients */ + if (gtk_widget_is_composited (tooltip->window)) + { + gtk_widget_shape_combine_region (tooltip->window, NULL); + return; + } - style = gtk_widget_get_style (tooltip->window); + 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)); - gtk_alignment_set_padding (GTK_ALIGNMENT (tooltip->alignment), - style->ythickness, style->ythickness, - style->xthickness, style->xthickness); + cr = cairo_create (surface); + paint_background_and_frame (tooltip, cr); + cairo_destroy (cr); - gtk_box_set_spacing (GTK_BOX (tooltip->box), - style->xthickness); + 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_composited_changed (GtkTooltip *tooltip, + GtkWidget *widget) +{ + if (gtk_widget_get_realized (tooltip->window)) + maybe_update_shape (tooltip); +} - gtk_widget_queue_draw (tooltip->window); +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) { - gtk_paint_flat_box (gtk_widget_get_style (tooltip->window), - cr, - GTK_STATE_NORMAL, - GTK_SHADOW_OUT, - tooltip->window, - "tooltip", - 0, 0, - gtk_widget_get_allocated_width (tooltip->window), - gtk_widget_get_allocated_height (tooltip->window)); + 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); + } + + maybe_update_shape (tooltip); + paint_background_and_frame (tooltip, cr); return FALSE; } @@ -990,27 +1061,28 @@ gtk_tooltip_position (GtkTooltip *tooltip, GdkDisplay *display, GtkWidget *new_tooltip_widget) { - gint x, y; + gint x, y, width, height; GdkScreen *screen; gint monitor_num; GdkRectangle monitor; - GtkRequisition requisition; guint cursor_size; GdkRectangle bounds; #define MAX_DISTANCE 32 + gtk_widget_realize (GTK_WIDGET (tooltip->current_window)); + tooltip->tooltip_widget = new_tooltip_widget; screen = gtk_widget_get_screen (new_tooltip_widget); - gtk_widget_get_preferred_size (GTK_WIDGET (tooltip->current_window), - &requisition, NULL); + width = gtk_widget_get_allocated_width (GTK_WIDGET (tooltip->current_window)); + height = gtk_widget_get_allocated_height (GTK_WIDGET (tooltip->current_window)); monitor_num = gdk_screen_get_monitor_at_point (screen, tooltip->last_x, tooltip->last_y); - gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); + gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor); get_bounding_box (new_tooltip_widget, &bounds); @@ -1019,10 +1091,10 @@ gtk_tooltip_position (GtkTooltip *tooltip, cursor_size = gdk_display_get_default_cursor_size (display); /* Try below */ - x = bounds.x + bounds.width / 2 - requisition.width / 2; + x = bounds.x + bounds.width / 2 - width / 2; y = bounds.y + bounds.height + 4; - if (y + requisition.height <= monitor.y + monitor.height) + if (y + height <= monitor.y + monitor.height) { if (tooltip->keyboard_mode_enabled) goto found; @@ -1031,28 +1103,28 @@ gtk_tooltip_position (GtkTooltip *tooltip, { if (tooltip->last_x + cursor_size + MAX_DISTANCE < x) x = tooltip->last_x + cursor_size + MAX_DISTANCE; - else if (x + requisition.width < tooltip->last_x - MAX_DISTANCE) - x = tooltip->last_x - MAX_DISTANCE - requisition.width; + else if (x + width < tooltip->last_x - MAX_DISTANCE) + x = tooltip->last_x - MAX_DISTANCE - width; goto found; } } /* Try above */ - x = bounds.x + bounds.width / 2 - requisition.width / 2; - y = bounds.y - requisition.height - 4; + x = bounds.x + bounds.width / 2 - width / 2; + y = bounds.y - height - 4; if (y >= monitor.y) { if (tooltip->keyboard_mode_enabled) goto found; - if (y + requisition.height >= tooltip->last_y - MAX_DISTANCE) + if (y + height >= tooltip->last_y - MAX_DISTANCE) { if (tooltip->last_x + cursor_size + MAX_DISTANCE < x) x = tooltip->last_x + cursor_size + MAX_DISTANCE; - else if (x + requisition.width < tooltip->last_x - MAX_DISTANCE) - x = tooltip->last_x - MAX_DISTANCE - requisition.width; + else if (x + width < tooltip->last_x - MAX_DISTANCE) + x = tooltip->last_x - MAX_DISTANCE - width; goto found; } @@ -1060,9 +1132,9 @@ gtk_tooltip_position (GtkTooltip *tooltip, /* Try right FIXME: flip on rtl ? */ x = bounds.x + bounds.width + 4; - y = bounds.y + bounds.height / 2 - requisition.height / 2; + y = bounds.y + bounds.height / 2 - height / 2; - if (x + requisition.width <= monitor.x + monitor.width) + if (x + width <= monitor.x + monitor.width) { if (tooltip->keyboard_mode_enabled) goto found; @@ -1071,28 +1143,28 @@ gtk_tooltip_position (GtkTooltip *tooltip, { if (tooltip->last_y + cursor_size + MAX_DISTANCE < y) y = tooltip->last_y + cursor_size + MAX_DISTANCE; - else if (y + requisition.height < tooltip->last_y - MAX_DISTANCE) - y = tooltip->last_y - MAX_DISTANCE - requisition.height; + else if (y + height < tooltip->last_y - MAX_DISTANCE) + y = tooltip->last_y - MAX_DISTANCE - height; goto found; } } /* Try left FIXME: flip on rtl ? */ - x = bounds.x - requisition.width - 4; - y = bounds.y + bounds.height / 2 - requisition.height / 2; + x = bounds.x - width - 4; + y = bounds.y + bounds.height / 2 - height / 2; if (x >= monitor.x) { if (tooltip->keyboard_mode_enabled) goto found; - if (x + requisition.width >= tooltip->last_x - MAX_DISTANCE) + if (x + width >= tooltip->last_x - MAX_DISTANCE) { if (tooltip->last_y + cursor_size + MAX_DISTANCE < y) y = tooltip->last_y + cursor_size + MAX_DISTANCE; - else if (y + requisition.height < tooltip->last_y - MAX_DISTANCE) - y = tooltip->last_y - MAX_DISTANCE - requisition.height; + else if (y + height < tooltip->last_y - MAX_DISTANCE) + y = tooltip->last_y - MAX_DISTANCE - height; goto found; } @@ -1101,7 +1173,7 @@ gtk_tooltip_position (GtkTooltip *tooltip, /* Fallback */ if (tooltip->keyboard_mode_enabled) { - x = bounds.x + bounds.width / 2 - requisition.width / 2; + x = bounds.x + bounds.width / 2 - width / 2; y = bounds.y + bounds.height + 4; } else @@ -1115,24 +1187,38 @@ found: /* Show it */ if (tooltip->current_window) { - if (x + requisition.width > monitor.x + monitor.width) - x -= x - (monitor.x + monitor.width) + requisition.width; + if (x + width > monitor.x + monitor.width) + x -= x - (monitor.x + monitor.width) + width; else if (x < monitor.x) x = monitor.x; - if (y + requisition.height > monitor.y + monitor.height) - y -= y - (monitor.y + monitor.height) + requisition.height; + if (y + height > monitor.y + monitor.height) + y -= y - (monitor.y + monitor.height) + height; else if (y < monitor.y) y = monitor.y; if (!tooltip->keyboard_mode_enabled) { /* don't pop up under the pointer */ - if (x <= tooltip->last_x && tooltip->last_x < x + requisition.width && - y <= tooltip->last_y && tooltip->last_y < y + requisition.height) - y = tooltip->last_y - requisition.height - 2; + if (x <= tooltip->last_x && tooltip->last_x < x + width && + y <= tooltip->last_y && tooltip->last_y < y + height) + y = tooltip->last_y - height - 2; } +#ifdef GDK_WINDOWING_WAYLAND + /* set the transient parent on the tooltip when running with the Wayland + * backend to allow correct positioning of the tooltip windows */ + if (GDK_IS_WAYLAND_DISPLAY (display)) + { + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (tooltip->tooltip_widget); + if (GTK_IS_WINDOW (toplevel)) + gtk_window_set_transient_for (GTK_WINDOW (tooltip->current_window), + GTK_WINDOW (toplevel)); + } +#endif + gtk_window_move (GTK_WINDOW (tooltip->current_window), x, y); gtk_widget_show (GTK_WIDGET (tooltip->current_window)); } @@ -1146,37 +1232,37 @@ gtk_tooltip_show_tooltip (GdkDisplay *display) GdkWindow *window; GtkWidget *tooltip_widget; - GtkWidget *pointer_widget; GtkTooltip *tooltip; gboolean has_tooltip; gboolean return_value = FALSE; tooltip = g_object_get_data (G_OBJECT (display), - "gdk-display-current-tooltip"); + "gdk-display-current-tooltip"); if (tooltip->keyboard_mode_enabled) { x = y = -1; - pointer_widget = tooltip_widget = tooltip->keyboard_widget; + tooltip_widget = tooltip->keyboard_widget; } else { + GdkDevice *device; gint tx, ty; window = tooltip->last_window; if (!GDK_IS_WINDOW (window)) - return; + return; + + device = gdk_device_manager_get_client_pointer (gdk_display_get_device_manager (display)); - gdk_window_get_pointer (window, &x, &y, NULL); + gdk_window_get_device_position (window, device, &x, &y, NULL); gdk_window_get_root_coords (window, x, y, &tx, &ty); tooltip->last_x = tx; tooltip->last_y = ty; - pointer_widget = tooltip_widget = _gtk_widget_find_at_coords (window, - x, y, - &x, &y); + tooltip_widget = _gtk_widget_find_at_coords (window, x, y, &x, &y); } if (!tooltip_widget) @@ -1191,9 +1277,9 @@ gtk_tooltip_show_tooltip (GdkDisplay *display) if (!tooltip->current_window) { if (gtk_widget_get_tooltip_window (tooltip_widget)) - tooltip->current_window = gtk_widget_get_tooltip_window (tooltip_widget); + tooltip->current_window = gtk_widget_get_tooltip_window (tooltip_widget); else - tooltip->current_window = GTK_WINDOW (GTK_TOOLTIP (tooltip)->window); + tooltip->current_window = GTK_WINDOW (GTK_TOOLTIP (tooltip)->window); } screen = gtk_widget_get_screen (tooltip_widget); @@ -1202,13 +1288,13 @@ gtk_tooltip_show_tooltip (GdkDisplay *display) if (screen != gtk_widget_get_screen (tooltip->window)) { g_signal_handlers_disconnect_by_func (display, - gtk_tooltip_display_closed, - tooltip); + gtk_tooltip_display_closed, + tooltip); gtk_window_set_screen (GTK_WINDOW (tooltip->window), screen); g_signal_connect (display, "closed", - G_CALLBACK (gtk_tooltip_display_closed), tooltip); + G_CALLBACK (gtk_tooltip_display_closed), tooltip); } gtk_tooltip_position (tooltip, display, tooltip_widget); @@ -1284,7 +1370,7 @@ tooltip_popup_timeout (gpointer data) GdkDisplay *display; GtkTooltip *tooltip; - display = GDK_DISPLAY_OBJECT (data); + display = GDK_DISPLAY (data); tooltip = g_object_get_data (G_OBJECT (display), "gdk-display-current-tooltip"); @@ -1350,7 +1436,7 @@ _gtk_tooltip_focus_in (GtkWidget *widget) device = gtk_get_current_event_device (); - if (device && device->source == GDK_SOURCE_KEYBOARD) + if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) device = gdk_device_get_associated_device (device); /* This function should be called by either a focus in event, @@ -1470,22 +1556,33 @@ _gtk_tooltip_hide (GtkWidget *widget) } static gboolean -tooltips_enabled (GdkWindow *window) +tooltips_enabled (GdkEvent *event) { + GdkDevice *source_device; + GdkInputSource source; + GdkWindow *window; gboolean enabled; - gboolean touchscreen; GdkScreen *screen; GtkSettings *settings; + window = event->any.window; + source_device = gdk_event_get_source_device (event); + + if (!source_device) + return FALSE; + + source = gdk_device_get_source (source_device); screen = gdk_window_get_screen (window); settings = gtk_settings_get_for_screen (screen); g_object_get (settings, - "gtk-touchscreen-mode", &touchscreen, "gtk-enable-tooltips", &enabled, NULL); - return (!touchscreen && enabled); + if (enabled && source != GDK_SOURCE_TOUCHSCREEN) + return TRUE; + + return FALSE; } void @@ -1497,7 +1594,7 @@ _gtk_tooltip_handle_event (GdkEvent *event) GdkDisplay *display; GtkTooltip *current_tooltip; - if (!tooltips_enabled (event->any.window)) + if (!tooltips_enabled (event)) return; /* Returns coordinates relative to has_tooltip_widget's allocation. */ @@ -1560,13 +1657,13 @@ _gtk_tooltip_handle_event (GdkEvent *event) case GDK_KEY_PRESS: case GDK_DRAG_ENTER: case GDK_GRAB_BROKEN: + case GDK_SCROLL: gtk_tooltip_hide_tooltip (current_tooltip); break; case GDK_MOTION_NOTIFY: case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: - case GDK_SCROLL: if (current_tooltip) { gboolean tip_area_set;