static void gtk_application_window_real_get_preferred_width_for_height (GtkWidget *widget, gint height, gint *minimum_width, gint *natural_width) { GtkApplicationWindow *window = GTK_APPLICATION_WINDOW (widget); gint menubar_height; if (window->priv->menubar != NULL) gtk_widget_get_preferred_height (window->priv->menubar, &menubar_height, NULL); else menubar_height = 0; GTK_WIDGET_CLASS (gtk_application_window_parent_class) ->get_preferred_width_for_height (widget, height - menubar_height, minimum_width, natural_width); if (window->priv->menubar != NULL) { gint menubar_min_width, menubar_nat_width; gint border_width; GtkBorder border = { 0 }; gtk_widget_get_preferred_width_for_height (window->priv->menubar, menubar_height, &menubar_min_width, &menubar_nat_width); border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); _gtk_window_get_shadow_width (GTK_WINDOW (widget), &border); menubar_min_width += 2 * border_width + border.left + border.right; menubar_nat_width += 2 * border_width + border.left + border.right; *minimum_width = MAX (*minimum_width, menubar_min_width); *natural_width = MAX (*natural_width, menubar_nat_width); } }
/* Ignores (x, y) on input, translates event coordinates to * allocation relative (x, y) of the returned widget. */ static GtkWidget * find_topmost_widget_coords_from_event (GdkEvent *event, gint *x, gint *y) { GtkAllocation allocation; gint tx, ty; gdouble dx, dy; GtkWidget *tmp; gdk_event_get_coords (event, &dx, &dy); /* Returns coordinates relative to tmp's allocation. */ tmp = _gtk_widget_find_at_coords (event->any.window, dx, dy, &tx, &ty); if (!tmp) return NULL; /* Make sure the pointer can actually be on the widget returned. */ gtk_widget_get_allocation (tmp, &allocation); allocation.x = 0; allocation.y = 0; if (GTK_IS_WINDOW (tmp)) { GtkBorder border; _gtk_window_get_shadow_width (GTK_WINDOW (tmp), &border); allocation.x = border.left; allocation.y = border.top; allocation.width -= border.left + border.right; allocation.height -= border.top + border.bottom; } if (tx < allocation.x || tx >= allocation.width || ty < allocation.y || ty >= allocation.height) return NULL; if (x) *x = tx; if (y) *y = ty; return tmp; }
static void get_bounding_box (GtkWidget *widget, GdkRectangle *bounds) { GtkAllocation allocation; GtkBorder border = { 0, }; GdkWindow *window; gint x, y; gint w, h; gint x1, y1; gint x2, y2; gint x3, y3; gint x4, y4; window = gtk_widget_get_parent_window (widget); if (window == NULL) window = gtk_widget_get_window (widget); gtk_widget_get_allocation (widget, &allocation); if (GTK_IS_WINDOW (widget)) _gtk_window_get_shadow_width (GTK_WINDOW (widget), &border); x = allocation.x + border.left; y = allocation.y + border.right; w = allocation.width - border.left - border.right; h = allocation.height - border.top - border.bottom; gdk_window_get_root_coords (window, x, y, &x1, &y1); gdk_window_get_root_coords (window, x + w, y, &x2, &y2); gdk_window_get_root_coords (window, x, y + h, &x3, &y3); gdk_window_get_root_coords (window, 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) { gint x, y, width, height; GdkScreen *screen; gint monitor_num; GdkRectangle monitor; guint cursor_size; GdkRectangle bounds; GtkBorder border; #define MAX_DISTANCE 32 gtk_widget_realize (GTK_WIDGET (tooltip->current_window)); gtk_widget_set_visible (GTK_WIDGET (tooltip->current_window), TRUE); tooltip->tooltip_widget = new_tooltip_widget; screen = gtk_widget_get_screen (new_tooltip_widget); _gtk_window_get_shadow_width (GTK_WINDOW (tooltip->current_window), &border); 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; monitor_num = gdk_screen_get_monitor_at_point (screen, tooltip->last_x, tooltip->last_y); gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor); get_bounding_box (new_tooltip_widget, &bounds); /* Position the tooltip */ cursor_size = gdk_display_get_default_cursor_size (display); /* Try below */ x = bounds.x + bounds.width / 2 - width / 2; y = bounds.y + bounds.height + 4; if (y + height <= monitor.y + monitor.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; } } /* Try above */ 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 + 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 + width < tooltip->last_x - MAX_DISTANCE) x = tooltip->last_x - MAX_DISTANCE - width; goto found; } } /* Try right FIXME: flip on rtl ? */ x = bounds.x + bounds.width + 4; y = bounds.y + bounds.height / 2 - height / 2; if (x + width <= monitor.x + monitor.width) { if (tooltip->keyboard_mode_enabled) goto found; if (x <= tooltip->last_x + cursor_size + 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; } } /* Try left FIXME: flip on rtl ? */ 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 + 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; } } /* 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 (tooltip->current_window) { if (x + width > monitor.x + monitor.width) x -= x - (monitor.x + monitor.width) + width; else if (x < monitor.x) x = monitor.x; 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 + 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 x -= border.left; y -= border.top; gtk_window_move (GTK_WINDOW (tooltip->current_window), x, y); gtk_widget_show (GTK_WIDGET (tooltip->current_window)); } }