diff options
Diffstat (limited to 'gtk/gtktooltip.c')
-rw-r--r-- | gtk/gtktooltip.c | 294 |
1 files changed, 74 insertions, 220 deletions
diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c index 706194a538..28e84f21bc 100644 --- a/gtk/gtktooltip.c +++ b/gtk/gtktooltip.c @@ -107,8 +107,6 @@ struct _GtkTooltip GtkWidget *tooltip_widget; - gdouble last_x; - gdouble last_y; GdkSurface *last_surface; guint timeout_id; @@ -601,245 +599,103 @@ gtk_tooltip_run_requery (GtkWidget **widget, } static void -get_bounding_box (GtkWidget *widget, - GdkRectangle *bounds) -{ - GtkWidget *toplevel; - GtkAllocation allocation; - GdkSurface *surface; - gint x, y; - gint w, h; - gint x1, y1; - gint x2, y2; - gint x3, y3; - gint x4, y4; - - surface = gtk_widget_get_parent_surface (widget); - if (surface == NULL) - surface = gtk_widget_get_surface (widget); - - gtk_widget_get_allocation (widget, &allocation); - - x = allocation.x; - y = allocation.y; - w = allocation.width; - h = allocation.height; - - toplevel = gtk_widget_get_toplevel (widget); - if (GTK_IS_WINDOW (toplevel) && !GTK_IS_WINDOW (widget)) - { - GtkWidget *parent = gtk_widget_get_parent (widget); - - gtk_widget_translate_coordinates (parent, toplevel, - x, y, - &x, &y); - } - - if (GTK_IS_WINDOW (widget)) - { - GtkBorder border = { 0, }; - - _gtk_window_get_shadow_width (GTK_WINDOW (widget), &border); - x += border.left; - y += border.right; - w -= border.left + border.right; - h -= border.top + border.bottom; - } - - gdk_surface_get_root_coords (surface, x, y, &x1, &y1); - gdk_surface_get_root_coords (surface, x + w, y, &x2, &y2); - gdk_surface_get_root_coords (surface, x, y + h, &x3, &y3); - gdk_surface_get_root_coords (surface, x + w, y + h, &x4, &y4); - -#define MIN4(a,b,c,d) MIN(MIN(a,b),MIN(c,d)) -#define MAX4(a,b,c,d) MAX(MAX(a,b),MAX(c,d)) - - bounds->x = floor (MIN4 (x1, x2, x3, x4)); - bounds->y = floor (MIN4 (y1, y2, y3, y4)); - bounds->width = ceil (MAX4 (x1, x2, x3, x4)) - bounds->x; - bounds->height = ceil (MAX4 (y1, y2, y3, y4)) - bounds->y; -} - -static void gtk_tooltip_position (GtkTooltip *tooltip, GdkDisplay *display, - GtkWidget *new_tooltip_widget) + GtkWidget *new_tooltip_widget, + GdkDevice *device) { - gint x, y, width, height; - GdkMonitor *monitor; - GdkRectangle workarea; - guint cursor_size; - GdkRectangle bounds; - GtkBorder border; - -#define MAX_DISTANCE 32 + GtkSettings *settings; + 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)); - gtk_widget_set_visible (GTK_WIDGET (tooltip->current_window), TRUE); + surface = _gtk_widget_get_surface (GTK_WIDGET (tooltip->current_window)); tooltip->tooltip_widget = new_tooltip_widget; - _gtk_window_get_shadow_width (GTK_WINDOW (tooltip->current_window), &border); + toplevel = _gtk_widget_get_toplevel (new_tooltip_widget); + gtk_widget_translate_coordinates (new_tooltip_widget, toplevel, + 0, 0, + &anchor_rect.x, &anchor_rect.y); - width = gtk_widget_get_allocated_width (GTK_WIDGET (tooltip->current_window)) - border.left - border.right; - height = gtk_widget_get_allocated_height (GTK_WIDGET (tooltip->current_window)) - border.top - border.bottom; + anchor_rect.width = gtk_widget_get_allocated_width (new_tooltip_widget); + anchor_rect.height = gtk_widget_get_allocated_height (new_tooltip_widget); - monitor = gdk_display_get_monitor_at_point (display, tooltip->last_x, tooltip->last_y); - gdk_monitor_get_workarea (monitor, &workarea); - - get_bounding_box (new_tooltip_widget, &bounds); - - /* Position the tooltip */ - - g_object_get (gtk_widget_get_settings (GTK_WIDGET (tooltip->current_window)), + settings = gtk_settings_get_for_display (display); + g_object_get (settings, "gtk-cursor-theme-size", &cursor_size, NULL); - /* Try below */ - x = bounds.x + bounds.width / 2 - width / 2; - y = bounds.y + bounds.height + 4; - - if (y + height <= workarea.y + workarea.height) - { - if (tooltip->keyboard_mode_enabled) - goto found; - - if (y <= tooltip->last_y + cursor_size + MAX_DISTANCE) - { - if (tooltip->last_x + cursor_size + MAX_DISTANCE < x) - x = tooltip->last_x + cursor_size + MAX_DISTANCE; - else if (x + width < tooltip->last_x - MAX_DISTANCE) - x = tooltip->last_x - MAX_DISTANCE - width; - - goto found; - } - } + if (device) + anchor_rect_padding = MAX (4, cursor_size - 32); + else + anchor_rect_padding = 4; - /* Try above */ - x = bounds.x + bounds.width / 2 - width / 2; - y = bounds.y - height - 4; + anchor_rect.x -= anchor_rect_padding; + anchor_rect.y -= anchor_rect_padding; + anchor_rect.width += anchor_rect_padding * 2; + anchor_rect.height += anchor_rect_padding * 2; - if (y >= workarea.y) + if (device) { - if (tooltip->keyboard_mode_enabled) - goto found; + const int max_x_distance = 32; + /* Max 48x48 icon + default padding */ + const int max_anchor_rect_height = 48 + 8; + int pointer_x, pointer_y; + + /* + * For pointer position triggered tooltips, implement the following + * semantics: + * + * If the anchor rectangle is too tall (meaning if we'd be constrained + * and flip, it'd flip too far away), rely only on the pointer position + * to position the tooltip. The approximate pointer cursorrectangle is + * used as a anchor rectantgle. + * + * If the anchor rectangle isn't to tall, make sure the tooltip isn't too + * far away from the pointer position. + */ + effective_toplevel = _gtk_widget_get_surface (new_tooltip_widget); + gdk_surface_get_device_position (effective_toplevel, + device, + &pointer_x, &pointer_y, NULL); - if (y + height >= tooltip->last_y - MAX_DISTANCE) + if (anchor_rect.height > max_anchor_rect_height) { - if (tooltip->last_x + cursor_size + MAX_DISTANCE < x) - x = tooltip->last_x + cursor_size + MAX_DISTANCE; - else if (x + width < tooltip->last_x - MAX_DISTANCE) - x = tooltip->last_x - MAX_DISTANCE - width; - - goto found; + anchor_rect.x = pointer_x - 4; + anchor_rect.y = pointer_y - 4; + anchor_rect.width = cursor_size; + anchor_rect.height = cursor_size; } - } - - /* Try right FIXME: flip on rtl ? */ - x = bounds.x + bounds.width + 4; - y = bounds.y + bounds.height / 2 - height / 2; - - if (x + width <= workarea.x + workarea.width) - { - if (tooltip->keyboard_mode_enabled) - goto found; - - if (x <= tooltip->last_x + cursor_size + MAX_DISTANCE) + else { - if (tooltip->last_y + cursor_size + MAX_DISTANCE < y) - y = tooltip->last_y + cursor_size + MAX_DISTANCE; - else if (y + height < tooltip->last_y - MAX_DISTANCE) - y = tooltip->last_y - MAX_DISTANCE - height; - - goto found; - } - } + int anchor_point_x; + int x_distance; - /* Try left FIXME: flip on rtl ? */ - x = bounds.x - width - 4; - y = bounds.y + bounds.height / 2 - height / 2; + anchor_point_x = anchor_rect.x + anchor_rect.width / 2; + x_distance = pointer_x - anchor_point_x; - if (x >= workarea.x) - { - if (tooltip->keyboard_mode_enabled) - goto found; - - 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 + height < tooltip->last_y - MAX_DISTANCE) - y = tooltip->last_y - MAX_DISTANCE - height; - - goto found; + if (x_distance > max_x_distance) + rect_anchor_dx = x_distance - max_x_distance; + else if (x_distance < -max_x_distance) + rect_anchor_dx = x_distance + max_x_distance; } } - /* Fallback */ - if (tooltip->keyboard_mode_enabled) - { - x = bounds.x + bounds.width / 2 - width / 2; - y = bounds.y + bounds.height + 4; - } - else - { - /* At cursor */ - x = tooltip->last_x + cursor_size * 3 / 4; - y = tooltip->last_y + cursor_size * 3 / 4; - } - -found: - /* Show it */ - if (x + width > workarea.x + workarea.width) - x -= x - (workarea.x + workarea.width) + width; - else if (x < workarea.x) - x = workarea.x; - - if (y + height > workarea.y + workarea.height) - y -= y - (workarea.y + workarea.height) + height; - else if (y < workarea.y) - y = workarea.y; - - if (!tooltip->keyboard_mode_enabled) - { - /* don't pop up under the pointer */ - 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; + gtk_window_set_transient_for (GTK_WINDOW (tooltip->current_window), + GTK_WINDOW (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 -#ifdef GDK_WINDOWING_MIR - /* Set the transient parent on the tooltip when running with the Mir - * backend to allow correct positioning of the tooltip windows */ - if (GDK_IS_MIR_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 - - x -= border.left; - y -= border.top; - - gtk_window_move (GTK_WINDOW (tooltip->current_window), x, y); + 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)); } @@ -849,6 +705,7 @@ gtk_tooltip_show_tooltip (GdkDisplay *display) gint x, y; GdkSurface *surface; GtkWidget *tooltip_widget; + GdkDevice *device; GtkTooltip *tooltip; gboolean return_value = FALSE; @@ -858,10 +715,10 @@ gtk_tooltip_show_tooltip (GdkDisplay *display) { x = y = -1; tooltip_widget = tooltip->keyboard_widget; + device = NULL; } else { - GdkDevice *device; gint tx, ty; surface = tooltip->last_surface; @@ -874,9 +731,6 @@ gtk_tooltip_show_tooltip (GdkDisplay *display) gdk_surface_get_device_position (surface, device, &x, &y, NULL); gdk_surface_get_root_coords (surface, x, y, &tx, &ty); - tooltip->last_x = tx; - tooltip->last_y = ty; - tooltip_widget = _gtk_widget_find_at_coords (surface, x, y, &x, &y); } @@ -908,7 +762,7 @@ gtk_tooltip_show_tooltip (GdkDisplay *display) G_CALLBACK (gtk_tooltip_display_closed), tooltip); } - gtk_tooltip_position (tooltip, display, tooltip_widget); + gtk_tooltip_position (tooltip, display, tooltip_widget, device); /* Now a tooltip is visible again on the display, make sure browse * mode is enabled. |