/* GDK - The GIMP Drawing Kit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ /* * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ #include "config.h" #include "gdksurfaceimpl.h" #include "gdkinternals.h" G_DEFINE_TYPE (GdkSurfaceImpl, gdk_surface_impl, G_TYPE_OBJECT); static gboolean gdk_surface_impl_beep (GdkSurface *surface) { /* FALSE means surfaces can't beep, so the display will be * made to beep instead. */ return FALSE; } static GdkDisplay * get_display_for_surface (GdkSurface *primary, GdkSurface *secondary) { GdkDisplay *display = gdk_surface_get_display (primary); if (display) return display; display = gdk_surface_get_display (secondary); if (display) return display; g_warning ("no display for surface, using default"); return gdk_display_get_default (); } static GdkMonitor * get_monitor_for_rect (GdkDisplay *display, const GdkRectangle *rect) { gint biggest_area = G_MININT; GdkMonitor *best_monitor = NULL; GdkMonitor *monitor; GdkRectangle workarea; GdkRectangle intersection; gint x; gint y; gint i; for (i = 0; i < gdk_display_get_n_monitors (display); i++) { monitor = gdk_display_get_monitor (display, i); gdk_monitor_get_workarea (monitor, &workarea); if (gdk_rectangle_intersect (&workarea, rect, &intersection)) { if (intersection.width * intersection.height > biggest_area) { biggest_area = intersection.width * intersection.height; best_monitor = monitor; } } } if (best_monitor) return best_monitor; x = rect->x + rect->width / 2; y = rect->y + rect->height / 2; return gdk_display_get_monitor_at_point (display, x, y); } static gint get_anchor_x_sign (GdkGravity anchor) { switch (anchor) { case GDK_GRAVITY_STATIC: case GDK_GRAVITY_NORTH_WEST: case GDK_GRAVITY_WEST: case GDK_GRAVITY_SOUTH_WEST: return -1; default: case GDK_GRAVITY_NORTH: case GDK_GRAVITY_CENTER: case GDK_GRAVITY_SOUTH: return 0; case GDK_GRAVITY_NORTH_EAST: case GDK_GRAVITY_EAST: case GDK_GRAVITY_SOUTH_EAST: return 1; } } static gint get_anchor_y_sign (GdkGravity anchor) { switch (anchor) { case GDK_GRAVITY_STATIC: case GDK_GRAVITY_NORTH_WEST: case GDK_GRAVITY_NORTH: case GDK_GRAVITY_NORTH_EAST: return -1; default: case GDK_GRAVITY_WEST: case GDK_GRAVITY_CENTER: case GDK_GRAVITY_EAST: return 0; case GDK_GRAVITY_SOUTH_WEST: case GDK_GRAVITY_SOUTH: case GDK_GRAVITY_SOUTH_EAST: return 1; } } static gint maybe_flip_position (gint bounds_pos, gint bounds_size, gint rect_pos, gint rect_size, gint surface_size, gint rect_sign, gint surface_sign, gint offset, gboolean flip, gboolean *flipped) { gint primary; gint secondary; *flipped = FALSE; primary = rect_pos + (1 + rect_sign) * rect_size / 2 + offset - (1 + surface_sign) * surface_size / 2; if (!flip || (primary >= bounds_pos && primary + surface_size <= bounds_pos + bounds_size)) return primary; *flipped = TRUE; secondary = rect_pos + (1 - rect_sign) * rect_size / 2 - offset - (1 - surface_sign) * surface_size / 2; if (secondary >= bounds_pos && secondary + surface_size <= bounds_pos + bounds_size) return secondary; *flipped = FALSE; return primary; } static GdkSurface * traverse_to_toplevel (GdkSurface *surface, gint x, gint y, gint *toplevel_x, gint *toplevel_y) { GdkSurface *parent; gdouble xf = x; gdouble yf = y; while ((parent = surface->parent) != NULL) { gdk_surface_coords_to_parent (surface, xf, yf, &xf, &yf); surface = parent; } *toplevel_x = (gint) xf; *toplevel_y = (gint) yf; return surface; } static void gdk_surface_impl_move_to_rect (GdkSurface *surface, const GdkRectangle *rect, GdkGravity rect_anchor, GdkGravity surface_anchor, GdkAnchorHints anchor_hints, gint rect_anchor_dx, gint rect_anchor_dy) { GdkSurface *transient_for_toplevel; GdkDisplay *display; GdkMonitor *monitor; GdkRectangle bounds; GdkRectangle root_rect = *rect; GdkRectangle flipped_rect; GdkRectangle final_rect; gboolean flipped_x; gboolean flipped_y; /* * First translate the anchor rect to toplevel coordinates. This is needed * because not all backends will be able to get root coordinates for * non-toplevel surfaces. */ transient_for_toplevel = traverse_to_toplevel (surface->transient_for, root_rect.x, root_rect.y, &root_rect.x, &root_rect.y); gdk_surface_get_root_coords (transient_for_toplevel, root_rect.x, root_rect.y, &root_rect.x, &root_rect.y); display = get_display_for_surface (surface, surface->transient_for); monitor = get_monitor_for_rect (display, &root_rect); gdk_monitor_get_workarea (monitor, &bounds); flipped_rect.width = surface->width - surface->shadow_left - surface->shadow_right; flipped_rect.height = surface->height - surface->shadow_top - surface->shadow_bottom; flipped_rect.x = maybe_flip_position (bounds.x, bounds.width, root_rect.x, root_rect.width, flipped_rect.width, get_anchor_x_sign (rect_anchor), get_anchor_x_sign (surface_anchor), rect_anchor_dx, anchor_hints & GDK_ANCHOR_FLIP_X, &flipped_x); flipped_rect.y = maybe_flip_position (bounds.y, bounds.height, root_rect.y, root_rect.height, flipped_rect.height, get_anchor_y_sign (rect_anchor), get_anchor_y_sign (surface_anchor), rect_anchor_dy, anchor_hints & GDK_ANCHOR_FLIP_Y, &flipped_y); final_rect = flipped_rect; if (anchor_hints & GDK_ANCHOR_SLIDE_X) { if (final_rect.x + final_rect.width > bounds.x + bounds.width) final_rect.x = bounds.x + bounds.width - final_rect.width; if (final_rect.x < bounds.x) final_rect.x = bounds.x; } if (anchor_hints & GDK_ANCHOR_SLIDE_Y) { if (final_rect.y + final_rect.height > bounds.y + bounds.height) final_rect.y = bounds.y + bounds.height - final_rect.height; if (final_rect.y < bounds.y) final_rect.y = bounds.y; } if (anchor_hints & GDK_ANCHOR_RESIZE_X) { if (final_rect.x < bounds.x) { final_rect.width -= bounds.x - final_rect.x; final_rect.x = bounds.x; } if (final_rect.x + final_rect.width > bounds.x + bounds.width) final_rect.width = bounds.x + bounds.width - final_rect.x; } if (anchor_hints & GDK_ANCHOR_RESIZE_Y) { if (final_rect.y < bounds.y) { final_rect.height -= bounds.y - final_rect.y; final_rect.y = bounds.y; } if (final_rect.y + final_rect.height > bounds.y + bounds.height) final_rect.height = bounds.y + bounds.height - final_rect.y; } flipped_rect.x -= surface->shadow_left; flipped_rect.y -= surface->shadow_top; flipped_rect.width += surface->shadow_left + surface->shadow_right; flipped_rect.height += surface->shadow_top + surface->shadow_bottom; final_rect.x -= surface->shadow_left; final_rect.y -= surface->shadow_top; final_rect.width += surface->shadow_left + surface->shadow_right; final_rect.height += surface->shadow_top + surface->shadow_bottom; if (final_rect.width != surface->width || final_rect.height != surface->height) gdk_surface_move_resize (surface, final_rect.x, final_rect.y, final_rect.width, final_rect.height); else gdk_surface_move (surface, final_rect.x, final_rect.y); g_signal_emit_by_name (surface, "moved-to-rect", &flipped_rect, &final_rect, flipped_x, flipped_y); } static void gdk_surface_impl_class_init (GdkSurfaceImplClass *impl_class) { impl_class->beep = gdk_surface_impl_beep; impl_class->move_to_rect = gdk_surface_impl_move_to_rect; } static void gdk_surface_impl_init (GdkSurfaceImpl *impl) { }