[gtk+/wip/attente/popup-at: 1/5] gdkwindow: add gdk_window_move_to_rect ()
- From: William Hua <williamhua src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/attente/popup-at: 1/5] gdkwindow: add gdk_window_move_to_rect ()
- Date: Thu, 30 Jun 2016 17:25:34 +0000 (UTC)
commit 6edb6068d983ad24e9e16cc4258886266873e966
Author: William Hua <william hua canonical com>
Date: Wed Jun 15 11:00:38 2016 -0400
gdkwindow: add gdk_window_move_to_rect ()
gdk/gdk-private.c | 3 +-
gdk/gdk-private.h | 18 ++++
gdk/gdkmarshalers.list | 1 +
gdk/gdkwindow.c | 99 +++++++++++++++++++
gdk/gdkwindow.h | 37 +++++++
gdk/gdkwindowimpl.c | 252 ++++++++++++++++++++++++++++++++++++++++++++++++
gdk/gdkwindowimpl.h | 8 ++
7 files changed, 417 insertions(+), 1 deletions(-)
---
diff --git a/gdk/gdk-private.c b/gdk/gdk-private.c
index 7b62cc3..37a4ee6 100644
--- a/gdk/gdk-private.c
+++ b/gdk/gdk-private.c
@@ -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;
diff --git a/gdk/gdk-private.h b/gdk/gdk-private.h
index 474172d..32e3aaa 100644
--- a/gdk/gdk-private.h
+++ b/gdk/gdk-private.h
@@ -31,6 +31,15 @@ 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,
+ GdkWindow *transient_for,
+ 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 +65,15 @@ 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,
+ GdkWindow *transient_for,
+ 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
diff --git a/gdk/gdkmarshalers.list b/gdk/gdkmarshalers.list
index cb42499..adc37b9 100644
--- a/gdk/gdkmarshalers.list
+++ b/gdk/gdkmarshalers.list
@@ -5,3 +5,4 @@ OBJECT:VOID
OBJECT:DOUBLE,DOUBLE
BOXED:INT,INT
VOID:DOUBLE,DOUBLE,POINTER,POINTER
+VOID:POINTER,POINTER,BOOLEAN,BOOLEAN
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index d5ffc53..cd05ac0 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -148,6 +148,7 @@ enum {
TO_EMBEDDER,
FROM_EMBEDDER,
CREATE_SURFACE,
+ MOVED_TO_RECT,
LAST_SIGNAL
};
@@ -476,6 +477,43 @@ gdk_window_class_init (GdkWindowClass *klass)
2,
G_TYPE_INT,
G_TYPE_INT);
+
+ /**
+ * GdkWindow::moved-to-rect:
+ * @window: the #GdkWindow that moved
+ * @flipped_rect: the position of @window after any possible flipping
+ * @slid_rect: the position of @window after any possible sliding
+ * @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. @slid_rect is @flipped_rect,
+ * but possibly translated in the case that flipping is still ineffective in
+ * keeping @window on-screen.
+ *
+ * Since: 3.22
+ */
+ 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 +6175,67 @@ 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
+ * @transient_for: (not nullable): the #GdkWindow @rect is relative to
+ * @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 @rect's anchor point
+ * @rect_anchor_dy: vertical offset to shift @rect's anchor point
+ *
+ * Moves @window to @rect, aligning their anchor points.
+ *
+ * @rect is relative to the top-left corner of @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.
+ *
+ * @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.
+ *
+ * Since: 3.22
+ */
+void
+gdk_window_move_to_rect (GdkWindow *window,
+ GdkWindow *transient_for,
+ const GdkRectangle *rect,
+ GdkGravity rect_anchor,
+ GdkGravity window_anchor,
+ GdkAnchorHints anchor_hints,
+ gint rect_anchor_dx,
+ gint rect_anchor_dy)
+{
+ GdkWindowImplClass *impl_class;
+ GdkRectangle transformed_rect;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+ g_return_if_fail (GDK_IS_WINDOW (transient_for));
+ g_return_if_fail (rect);
+
+ transformed_rect = *rect;
+
+ while (!gdk_window_has_native (transient_for) && gdk_window_get_effective_parent (transient_for))
+ {
+ transformed_rect.x += transient_for->x;
+ transformed_rect.y += transient_for->y;
+ transient_for = gdk_window_get_effective_parent (transient_for);
+ }
+
+ impl_class = GDK_WINDOW_IMPL_GET_CLASS (window->impl);
+ impl_class->move_to_rect (window,
+ transient_for,
+ &transformed_rect,
+ rect_anchor,
+ window_anchor,
+ anchor_hints,
+ rect_anchor_dx,
+ rect_anchor_dy);
+}
/**
* gdk_window_scroll:
diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
index 4d98e07..8d6fdf8 100644
--- a/gdk/gdkwindow.h
+++ b/gdk/gdkwindow.h
@@ -245,6 +245,43 @@ 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. The
+ * default implementation first attempts to flip the anchors if allowed, then
+ * attempts to slide the window on-screen if allowed.
+ *
+ * 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.
+ *
+ * Since: 3.22
+ */
+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:
diff --git a/gdk/gdkwindowimpl.c b/gdk/gdkwindowimpl.c
index b7ec4ed..bdd96f5 100644
--- a/gdk/gdkwindowimpl.c
+++ b/gdk/gdkwindowimpl.c
@@ -39,6 +39,257 @@ 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;
+
+ 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 (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 (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
+choose_position (gint bounds_x,
+ gint bounds_width,
+ gint rect_x,
+ gint rect_width,
+ gint window_width,
+ gint rect_anchor,
+ gint window_anchor,
+ gint rect_anchor_dx,
+ gboolean flip,
+ gboolean *flipped)
+{
+ gint x;
+
+ *flipped = FALSE;
+ x = rect_x + (1 + rect_anchor) * rect_width / 2 + rect_anchor_dx - (1 + window_anchor) * window_width / 2;
+
+ if (!flip || (x >= bounds_x && x + window_width <= bounds_x + bounds_width))
+ return x;
+
+ *flipped = TRUE;
+ x = rect_x + (1 - rect_anchor) * rect_width / 2 - rect_anchor_dx - (1 - window_anchor) * window_width / 2;
+
+ if (x >= bounds_x && x + window_width <= bounds_x + bounds_width)
+ return x;
+
+ *flipped = FALSE;
+ return rect_x + (1 + rect_anchor) * rect_width / 2 + rect_anchor_dx - (1 + window_anchor) * window_width /
2;
+}
+
+static void
+gdk_window_impl_move_to_rect (GdkWindow *window,
+ GdkWindow *transient_for,
+ 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 slid_rect;
+ gboolean flipped_x;
+ gboolean flipped_y;
+
+ gdk_window_get_root_coords (transient_for,
+ root_rect.x,
+ root_rect.y,
+ &root_rect.x,
+ &root_rect.y);
+
+ display = get_display_for_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 = choose_position (bounds.x,
+ bounds.width,
+ root_rect.x,
+ root_rect.width,
+ flipped_rect.width,
+ get_anchor_x (rect_anchor),
+ get_anchor_x (window_anchor),
+ rect_anchor_dx,
+ anchor_hints & GDK_ANCHOR_FLIP_X,
+ &flipped_x);
+ flipped_rect.y = choose_position (bounds.y,
+ bounds.height,
+ root_rect.y,
+ root_rect.height,
+ flipped_rect.height,
+ get_anchor_y (rect_anchor),
+ get_anchor_y (window_anchor),
+ rect_anchor_dy,
+ anchor_hints & GDK_ANCHOR_FLIP_Y,
+ &flipped_y);
+
+ slid_rect = flipped_rect;
+
+ if (anchor_hints & GDK_ANCHOR_SLIDE_X)
+ {
+ if (slid_rect.x + slid_rect.width > bounds.x + bounds.width)
+ slid_rect.x = bounds.x + bounds.width - slid_rect.width;
+
+ if (slid_rect.x < bounds.x)
+ slid_rect.x = bounds.x;
+ }
+
+ if (anchor_hints & GDK_ANCHOR_SLIDE_Y)
+ {
+ if (slid_rect.y + slid_rect.height > bounds.y + bounds.height)
+ slid_rect.y = bounds.y + bounds.height - slid_rect.height;
+
+ if (slid_rect.y < bounds.y)
+ slid_rect.y = bounds.y;
+ }
+
+ if (anchor_hints & GDK_ANCHOR_RESIZE_X)
+ {
+ if (slid_rect.x < bounds.x)
+ {
+ slid_rect.width -= bounds.x - slid_rect.x;
+ slid_rect.x = bounds.x;
+ }
+
+ if (slid_rect.x + slid_rect.width > bounds.x + bounds.width)
+ slid_rect.width = bounds.x + bounds.width - slid_rect.x;
+ }
+
+ if (anchor_hints & GDK_ANCHOR_RESIZE_Y)
+ {
+ if (slid_rect.y < bounds.y)
+ {
+ slid_rect.height -= bounds.y - slid_rect.y;
+ slid_rect.y = bounds.y;
+ }
+
+ if (slid_rect.y + slid_rect.height > bounds.y + bounds.height)
+ slid_rect.height = bounds.y + bounds.height - slid_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;
+
+ slid_rect.x -= window->shadow_left;
+ slid_rect.y -= window->shadow_top;
+ slid_rect.width += window->shadow_left + window->shadow_right;
+ slid_rect.height += window->shadow_top + window->shadow_bottom;
+
+ if (slid_rect.width != window->width || slid_rect.height != window->height)
+ gdk_window_move_resize (window, slid_rect.x, slid_rect.y, slid_rect.width, slid_rect.height);
+ else
+ gdk_window_move (window, slid_rect.x, slid_rect.y);
+
+ g_signal_emit_by_name (window,
+ "moved-to-rect",
+ &flipped_rect,
+ &slid_rect,
+ flipped_x,
+ flipped_y);
+}
+
static void
gdk_window_impl_process_updates_recurse (GdkWindow *window,
cairo_region_t *region)
@@ -50,6 +301,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;
}
diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h
index 4ccdc67..61915e9 100644
--- a/gdk/gdkwindowimpl.h
+++ b/gdk/gdkwindowimpl.h
@@ -75,6 +75,14 @@ struct _GdkWindowImplClass
gint y,
gint width,
gint height);
+ void (* move_to_rect) (GdkWindow *window,
+ GdkWindow *transient_for,
+ 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);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]