forked from AuroraMiddleware/gtk
gdkwindow: add gdk_window_move_to_rect ()
https://bugzilla.gnome.org/show_bug.cgi?id=756579
This commit is contained in:
parent
48108c401e
commit
b3a530cb72
@ -341,6 +341,7 @@ GdkWindowWindowClass
|
||||
GdkWindowHints
|
||||
GdkGeometry
|
||||
GdkGravity
|
||||
GdkAnchorHints
|
||||
GdkWindowEdge
|
||||
GdkWindowTypeHint
|
||||
GdkWindowAttr
|
||||
|
@ -16,7 +16,8 @@ gdk__private__ (void)
|
||||
gdk_display_get_rendering_mode,
|
||||
gdk_display_set_rendering_mode,
|
||||
gdk_display_get_debug_updates,
|
||||
gdk_display_set_debug_updates
|
||||
gdk_display_set_debug_updates,
|
||||
gdk_window_move_to_rect
|
||||
};
|
||||
|
||||
return &table;
|
||||
|
@ -31,6 +31,14 @@ gboolean gdk_display_get_debug_updates (GdkDisplay *display);
|
||||
void gdk_display_set_debug_updates (GdkDisplay *display,
|
||||
gboolean debug_updates);
|
||||
|
||||
void gdk_window_move_to_rect (GdkWindow *window,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity window_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy);
|
||||
|
||||
typedef struct {
|
||||
/* add all private functions here, initialize them in gdk-private.c */
|
||||
gboolean (* gdk_device_grab_info) (GdkDisplay *display,
|
||||
@ -56,6 +64,14 @@ typedef struct {
|
||||
gboolean (* gdk_display_get_debug_updates) (GdkDisplay *display);
|
||||
void (* gdk_display_set_debug_updates) (GdkDisplay *display,
|
||||
gboolean debug_updates);
|
||||
|
||||
void (* gdk_window_move_to_rect) (GdkWindow *window,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity window_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy);
|
||||
} GdkPrivateVTable;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
|
@ -5,3 +5,4 @@ OBJECT:VOID
|
||||
OBJECT:DOUBLE,DOUBLE
|
||||
BOXED:INT,INT
|
||||
VOID:DOUBLE,DOUBLE,POINTER,POINTER
|
||||
VOID:POINTER,POINTER,BOOLEAN,BOOLEAN
|
||||
|
@ -148,6 +148,7 @@ enum {
|
||||
TO_EMBEDDER,
|
||||
FROM_EMBEDDER,
|
||||
CREATE_SURFACE,
|
||||
MOVED_TO_RECT,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@ -476,6 +477,46 @@ gdk_window_class_init (GdkWindowClass *klass)
|
||||
2,
|
||||
G_TYPE_INT,
|
||||
G_TYPE_INT);
|
||||
|
||||
/**
|
||||
* GdkWindow::moved-to-rect:
|
||||
* @window: the #GdkWindow that moved
|
||||
* @flipped_rect: (nullable): the position of @window after any possible
|
||||
* flipping or %NULL if the backend can't obtain it
|
||||
* @final_rect: (nullable): the final position of @window or %NULL if the
|
||||
* backend can't obtain it
|
||||
* @flipped_x: %TRUE if the anchors were flipped horizontally
|
||||
* @flipped_y: %TRUE if the anchors were flipped vertically
|
||||
*
|
||||
* Emitted when the position of @window is finalized after being moved to a
|
||||
* destination rectangle.
|
||||
*
|
||||
* @window might be flipped over the destination rectangle in order to keep
|
||||
* it on-screen, in which case @flipped_x and @flipped_y will be set to %TRUE
|
||||
* accordingly.
|
||||
*
|
||||
* @flipped_rect is the ideal position of @window after any possible
|
||||
* flipping, but before any possible sliding. @final_rect is @flipped_rect,
|
||||
* but possibly translated in the case that flipping is still ineffective in
|
||||
* keeping @window on-screen.
|
||||
*
|
||||
* Since: 3.22
|
||||
* Stability: Private
|
||||
*/
|
||||
signals[MOVED_TO_RECT] =
|
||||
g_signal_new (g_intern_static_string ("moved-to-rect"),
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
_gdk_marshal_VOID__POINTER_POINTER_BOOLEAN_BOOLEAN,
|
||||
G_TYPE_NONE,
|
||||
4,
|
||||
G_TYPE_POINTER,
|
||||
G_TYPE_POINTER,
|
||||
G_TYPE_BOOLEAN,
|
||||
G_TYPE_BOOLEAN);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -6137,6 +6178,60 @@ gdk_window_move_resize (GdkWindow *window,
|
||||
gdk_window_move_resize_internal (window, TRUE, x, y, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_window_move_to_rect:
|
||||
* @window: the #GdkWindow to move
|
||||
* @rect: (not nullable): the destination #GdkRectangle to align @window with
|
||||
* @rect_anchor: the point on @rect to align with @window's anchor point
|
||||
* @window_anchor: the point on @window to align with @rect's anchor point
|
||||
* @anchor_hints: positioning hints to use when limited on space
|
||||
* @rect_anchor_dx: horizontal offset to shift @window, i.e. @rect's anchor
|
||||
* point
|
||||
* @rect_anchor_dy: vertical offset to shift @window, i.e. @rect's anchor point
|
||||
*
|
||||
* Moves @window to @rect, aligning their anchor points.
|
||||
*
|
||||
* @rect is relative to the top-left corner of the window that @window is
|
||||
* transient for. @rect_anchor and @window_anchor determine anchor points on
|
||||
* @rect and @window to pin together. @rect's anchor point can optionally be
|
||||
* offset by @rect_anchor_dx and @rect_anchor_dy, which is equivalent to
|
||||
* offsetting the position of @window.
|
||||
*
|
||||
* @anchor_hints determines how @window will be moved if the anchor points cause
|
||||
* it to move off-screen. For example, %GDK_ANCHOR_FLIP_X will replace
|
||||
* %GDK_GRAVITY_NORTH_WEST with %GDK_GRAVITY_NORTH_EAST and vice versa if
|
||||
* @window extends beyond the left or right edges of the monitor.
|
||||
*
|
||||
* Connect to the #GdkWindow::moved-to-rect signal to find out how it was
|
||||
* actually positioned.
|
||||
*
|
||||
* Since: 3.22
|
||||
* Stability: Private
|
||||
*/
|
||||
void
|
||||
gdk_window_move_to_rect (GdkWindow *window,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity window_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy)
|
||||
{
|
||||
GdkWindowImplClass *impl_class;
|
||||
|
||||
g_return_if_fail (GDK_IS_WINDOW (window));
|
||||
g_return_if_fail (window->transient_for);
|
||||
g_return_if_fail (rect);
|
||||
|
||||
impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
|
||||
impl_class->move_to_rect (window,
|
||||
rect,
|
||||
rect_anchor,
|
||||
window_anchor,
|
||||
anchor_hints,
|
||||
rect_anchor_dx,
|
||||
rect_anchor_dy);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_window_scroll:
|
||||
|
@ -245,6 +245,49 @@ typedef enum
|
||||
GDK_GRAVITY_STATIC
|
||||
} GdkGravity;
|
||||
|
||||
/**
|
||||
* GdkAnchorHints:
|
||||
* @GDK_ANCHOR_FLIP_X: allow flipping anchors horizontally
|
||||
* @GDK_ANCHOR_FLIP_Y: allow flipping anchors vertically
|
||||
* @GDK_ANCHOR_SLIDE_X: allow sliding window horizontally
|
||||
* @GDK_ANCHOR_SLIDE_Y: allow sliding window vertically
|
||||
* @GDK_ANCHOR_RESIZE_X: allow resizing window horizontally
|
||||
* @GDK_ANCHOR_RESIZE_Y: allow resizing window vertically
|
||||
* @GDK_ANCHOR_FLIP: allow flipping anchors on both axes
|
||||
* @GDK_ANCHOR_SLIDE: allow sliding window on both axes
|
||||
* @GDK_ANCHOR_RESIZE: allow resizing window on both axes
|
||||
*
|
||||
* Positioning hints for aligning a window relative to a rectangle.
|
||||
*
|
||||
* These hints determine how the window should be positioned in the case that
|
||||
* the window would fall off-screen if placed in its ideal position.
|
||||
*
|
||||
* For example, %GDK_ANCHOR_FLIP_X will replace %GDK_GRAVITY_NORTH_WEST with
|
||||
* %GDK_GRAVITY_NORTH_EAST and vice versa if the window extends beyond the left
|
||||
* or right edges of the monitor.
|
||||
*
|
||||
* If %GDK_ANCHOR_SLIDE_X is set, the window can be shifted horizontally to fit
|
||||
* on-screen. If %GDK_ANCHOR_RESIZE_X is set, the window can be shrunken
|
||||
* horizontally to fit.
|
||||
*
|
||||
* In general, when multiple flags are set, flipping should take precedence over
|
||||
* sliding, which should take precedence over resizing.
|
||||
*
|
||||
* Since: 3.22
|
||||
* Stability: Unstable
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GDK_ANCHOR_FLIP_X = 1 << 0,
|
||||
GDK_ANCHOR_FLIP_Y = 1 << 1,
|
||||
GDK_ANCHOR_SLIDE_X = 1 << 2,
|
||||
GDK_ANCHOR_SLIDE_Y = 1 << 3,
|
||||
GDK_ANCHOR_RESIZE_X = 1 << 4,
|
||||
GDK_ANCHOR_RESIZE_Y = 1 << 5,
|
||||
GDK_ANCHOR_FLIP = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_FLIP_Y,
|
||||
GDK_ANCHOR_SLIDE = GDK_ANCHOR_SLIDE_X | GDK_ANCHOR_SLIDE_Y,
|
||||
GDK_ANCHOR_RESIZE = GDK_ANCHOR_RESIZE_X | GDK_ANCHOR_RESIZE_Y
|
||||
} GdkAnchorHints;
|
||||
|
||||
/**
|
||||
* GdkWindowEdge:
|
||||
|
@ -39,6 +39,258 @@ gdk_window_impl_beep (GdkWindow *window)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GdkDisplay *
|
||||
get_display_for_window (GdkWindow *primary,
|
||||
GdkWindow *secondary)
|
||||
{
|
||||
GdkDisplay *display = gdk_window_get_display (primary);
|
||||
|
||||
if (display)
|
||||
return display;
|
||||
|
||||
display = gdk_window_get_display (secondary);
|
||||
|
||||
if (display)
|
||||
return display;
|
||||
|
||||
g_warning ("no display for window, 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 window_size,
|
||||
gint rect_sign,
|
||||
gint window_sign,
|
||||
gint offset,
|
||||
gboolean flip,
|
||||
gboolean *flipped)
|
||||
{
|
||||
gint primary;
|
||||
gint secondary;
|
||||
|
||||
*flipped = FALSE;
|
||||
primary = rect_pos + (1 + rect_sign) * rect_size / 2 + offset - (1 + window_sign) * window_size / 2;
|
||||
|
||||
if (!flip || (primary >= bounds_pos && primary + window_size <= bounds_pos + bounds_size))
|
||||
return primary;
|
||||
|
||||
*flipped = TRUE;
|
||||
secondary = rect_pos + (1 - rect_sign) * rect_size / 2 - offset - (1 - window_sign) * window_size / 2;
|
||||
|
||||
if (secondary >= bounds_pos && secondary + window_size <= bounds_pos + bounds_size)
|
||||
return secondary;
|
||||
|
||||
*flipped = FALSE;
|
||||
return primary;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_window_impl_move_to_rect (GdkWindow *window,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity window_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy)
|
||||
{
|
||||
GdkDisplay *display;
|
||||
GdkMonitor *monitor;
|
||||
GdkRectangle bounds;
|
||||
GdkRectangle root_rect = *rect;
|
||||
GdkRectangle flipped_rect;
|
||||
GdkRectangle final_rect;
|
||||
gboolean flipped_x;
|
||||
gboolean flipped_y;
|
||||
|
||||
gdk_window_get_root_coords (window->transient_for,
|
||||
root_rect.x,
|
||||
root_rect.y,
|
||||
&root_rect.x,
|
||||
&root_rect.y);
|
||||
|
||||
display = get_display_for_window (window, window->transient_for);
|
||||
monitor = get_monitor_for_rect (display, &root_rect);
|
||||
gdk_monitor_get_workarea (monitor, &bounds);
|
||||
|
||||
flipped_rect.width = window->width - window->shadow_left - window->shadow_right;
|
||||
flipped_rect.height = window->height - window->shadow_top - window->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 (window_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 (window_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 -= window->shadow_left;
|
||||
flipped_rect.y -= window->shadow_top;
|
||||
flipped_rect.width += window->shadow_left + window->shadow_right;
|
||||
flipped_rect.height += window->shadow_top + window->shadow_bottom;
|
||||
|
||||
final_rect.x -= window->shadow_left;
|
||||
final_rect.y -= window->shadow_top;
|
||||
final_rect.width += window->shadow_left + window->shadow_right;
|
||||
final_rect.height += window->shadow_top + window->shadow_bottom;
|
||||
|
||||
if (final_rect.width != window->width || final_rect.height != window->height)
|
||||
gdk_window_move_resize (window, final_rect.x, final_rect.y, final_rect.width, final_rect.height);
|
||||
else
|
||||
gdk_window_move (window, final_rect.x, final_rect.y);
|
||||
|
||||
g_signal_emit_by_name (window,
|
||||
"moved-to-rect",
|
||||
&flipped_rect,
|
||||
&final_rect,
|
||||
flipped_x,
|
||||
flipped_y);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_window_impl_process_updates_recurse (GdkWindow *window,
|
||||
cairo_region_t *region)
|
||||
@ -50,6 +302,7 @@ static void
|
||||
gdk_window_impl_class_init (GdkWindowImplClass *impl_class)
|
||||
{
|
||||
impl_class->beep = gdk_window_impl_beep;
|
||||
impl_class->move_to_rect = gdk_window_impl_move_to_rect;
|
||||
impl_class->process_updates_recurse = gdk_window_impl_process_updates_recurse;
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,13 @@ struct _GdkWindowImplClass
|
||||
gint y,
|
||||
gint width,
|
||||
gint height);
|
||||
void (* move_to_rect) (GdkWindow *window,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity window_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy);
|
||||
void (* set_background) (GdkWindow *window,
|
||||
cairo_pattern_t *pattern);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user