mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 06:21:14 +00:00
339 lines
10 KiB
C
339 lines
10 KiB
C
/* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
}
|