[gtk: 15/16] gdk/surface: Replace move_to_rect() with GdkPopupLayout based API
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk: 15/16] gdk/surface: Replace move_to_rect() with GdkPopupLayout based API
- Date: Wed, 19 Feb 2020 18:59:18 +0000 (UTC)
commit ca71119a40ac9b196700855dac6484f4e198bdb1
Author: Jonas Ådahl <jadahl gmail com>
Date: Sun Feb 16 12:59:24 2020 +0100
gdk/surface: Replace move_to_rect() with GdkPopupLayout based API
Replace the gdk_surface_move_to_rect() API with a new GdkSurface
method called gdk_surface_present_popup() taking a new GdkPopupLayout
object describing how they should be laid out on screen.
The layout properties provided are the same as the ones used with
gdk_surface_move_to_rect(), except they are now set up using
GdkPopupLayout.
Calling gdk_surface_present_popup() will either show the popup at the
position described using the popup layout object and a new unconstrained
size, or reposition it accordingly.
In some situations, such as when a popup is set to autohide, presenting
may immediately fail, in case the grab was not granted by the display
server.
After a successful present, the result of the layout can be queried
using the following methods:
* gdk_surface_get_position() - to get the position relative to its
parent
* gdk_surface_get_width() - to get the current width
* gdk_surface_get_height() - to get the current height
* gdk_surface_get_rect_anchor() - to get the anchor point on the anchor
rectangle the popup was effectively positioned against given
constraints defined by the environment and the layout rules provided
via GdkPopupLayout.
* gdk_surface_get_surface_anchor() - the same as the one above but for
the surface anchor.
A new signal replaces the old "moved-to-rect" one -
"popup-layout-changed". However, it is only intended to be emitted when
the layout changes implicitly by the windowing system, for example if
the monitor resolution changed, or the parent window moved.
docs/reference/gdk/gdk4-sections.txt | 4 +-
gdk/broadway/gdksurface-broadway.c | 86 ++--
gdk/gdk-autocleanup.h | 1 +
gdk/gdkpopuplayout.c | 281 +++++++++++++
gdk/gdkpopuplayout.h | 136 ++++++
gdk/gdksurface.c | 295 ++++++-------
gdk/gdksurface.h | 57 +--
gdk/gdksurfaceprivate.h | 93 +++-
gdk/meson.build | 2 +
gdk/quartz/gdksurface-quartz.c | 90 ++--
gdk/wayland/gdkdevice-wayland.c | 2 -
gdk/wayland/gdksurface-wayland.c | 794 ++++++++++++++++++++++-------------
gdk/win32/gdksurface-win32.c | 84 ++--
gdk/x11/gdksurface-x11.c | 86 ++--
gtk/gtkpopover.c | 299 ++++++++++---
gtk/gtktooltipwindow.c | 62 +--
16 files changed, 1648 insertions(+), 724 deletions(-)
---
diff --git a/docs/reference/gdk/gdk4-sections.txt b/docs/reference/gdk/gdk4-sections.txt
index 48eadea63b..9e9cb5bb24 100644
--- a/docs/reference/gdk/gdk4-sections.txt
+++ b/docs/reference/gdk/gdk4-sections.txt
@@ -205,7 +205,9 @@ gdk_surface_set_keep_above
gdk_surface_set_keep_below
gdk_surface_set_opacity
gdk_surface_resize
-gdk_surface_move_to_rect
+gdk_surface_present_popup
+gdk_surface_get_popup_rect_anchor
+gdk_surface_get_popup_surface_anchor
gdk_surface_raise
gdk_surface_lower
gdk_surface_restack
diff --git a/gdk/broadway/gdksurface-broadway.c b/gdk/broadway/gdksurface-broadway.c
index 0f2411f63a..af946eef71 100644
--- a/gdk/broadway/gdksurface-broadway.c
+++ b/gdk/broadway/gdksurface-broadway.c
@@ -455,18 +455,21 @@ gdk_broadway_surface_move (GdkSurface *surface,
}
static void
-gdk_broadway_surface_moved_to_rect (GdkSurface *surface,
- GdkRectangle final_rect)
+gdk_broadway_surface_layout_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
{
- GdkSurface *toplevel;
+ GdkRectangle final_rect;
int x, y;
- if (surface->surface_type == GDK_SURFACE_POPUP)
- toplevel = surface->parent;
- else
- toplevel = surface->transient_for;
+ gdk_surface_layout_popup_helper (surface,
+ width,
+ height,
+ layout,
+ &final_rect);
- gdk_surface_get_origin (toplevel, &x, &y);
+ gdk_surface_get_origin (surface->parent, &x, &y);
x += final_rect.x;
y += final_rect.y;
@@ -474,8 +477,10 @@ gdk_broadway_surface_moved_to_rect (GdkSurface *surface,
final_rect.height != surface->height)
{
gdk_broadway_surface_move_resize (surface,
- x, y,
- final_rect.width, final_rect.height);
+ x,
+ y,
+ final_rect.width,
+ final_rect.height);
}
else
{
@@ -484,22 +489,49 @@ gdk_broadway_surface_moved_to_rect (GdkSurface *surface,
}
static void
-gdk_broadway_surface_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)
-{
- gdk_surface_move_to_rect_helper (surface,
- rect,
- rect_anchor,
- surface_anchor,
- anchor_hints,
- rect_anchor_dx,
- rect_anchor_dy,
- gdk_broadway_surface_moved_to_rect);
+show_popup (GdkSurface *surface)
+{
+ gdk_surface_raise (surface);
+ gdk_synthesize_surface_state (surface, GDK_SURFACE_STATE_WITHDRAWN, 0);
+ _gdk_surface_update_viewable (surface);
+ gdk_broadway_surface_show (surface, FALSE);
+ gdk_surface_invalidate_rect (surface, NULL);
+}
+
+static void
+show_grabbing_popup (GdkSeat *seat,
+ GdkSurface *surface,
+ gpointer user_data)
+{
+ show_popup (surface);
+}
+
+static gboolean
+gdk_broadway_surface_present_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
+{
+ gdk_broadway_surface_layout_popup (surface, width, height, layout);
+
+ if (GDK_SURFACE_IS_MAPPED (surface))
+ return TRUE;
+
+ if (surface->autohide)
+ {
+ gdk_seat_grab (gdk_display_get_default_seat (surface->display),
+ surface,
+ GDK_SEAT_CAPABILITY_ALL,
+ TRUE,
+ NULL, NULL,
+ show_grabbing_popup, NULL);
+ }
+ else
+ {
+ show_popup (surface);
+ }
+
+ return GDK_SURFACE_IS_MAPPED (surface);
}
static void
@@ -1393,7 +1425,7 @@ gdk_broadway_surface_class_init (GdkBroadwaySurfaceClass *klass)
impl_class->lower = gdk_broadway_surface_lower;
impl_class->restack_toplevel = gdk_broadway_surface_restack_toplevel;
impl_class->toplevel_resize = gdk_broadway_surface_toplevel_resize;
- impl_class->move_to_rect = gdk_broadway_surface_move_to_rect;
+ impl_class->present_popup = gdk_broadway_surface_present_popup;
impl_class->get_geometry = gdk_broadway_surface_get_geometry;
impl_class->get_root_coords = gdk_broadway_surface_get_root_coords;
impl_class->get_device_state = gdk_broadway_surface_get_device_state;
diff --git a/gdk/gdk-autocleanup.h b/gdk/gdk-autocleanup.h
index 513725620a..0086e21794 100644
--- a/gdk/gdk-autocleanup.h
+++ b/gdk/gdk-autocleanup.h
@@ -35,6 +35,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkGLContext, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkKeymap, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkMonitor, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkSeat, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkPopupLayout, gdk_popup_layout_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkVulkanContext, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkSurface, g_object_unref)
diff --git a/gdk/gdkpopuplayout.c b/gdk/gdkpopuplayout.c
new file mode 100644
index 0000000000..7bc7704c64
--- /dev/null
+++ b/gdk/gdkpopuplayout.c
@@ -0,0 +1,281 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2020 Red Hat
+ *
+ * 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/>.
+ *
+ */
+
+#include "config.h"
+
+#include "gdkpopuplayout.h"
+
+#include "gdksurface.h"
+
+struct _GdkPopupLayout
+{
+ /* < private >*/
+ grefcount ref_count;
+
+ GdkRectangle anchor_rect;
+ GdkGravity rect_anchor;
+ GdkGravity surface_anchor;
+ GdkAnchorHints anchor_hints;
+ int dx;
+ int dy;
+
+ gboolean is_sealed;
+};
+
+G_DEFINE_BOXED_TYPE (GdkPopupLayout, gdk_popup_layout,
+ gdk_popup_layout_ref,
+ gdk_popup_layout_unref)
+
+/**
+ * gdk_popup_layout_new: (constructor)
+ * @anchor_rect: (not nullable): the anchor #GdkRectangle to align @surface with
+ * @rect_anchor: the point on @anchor_rect to align with @surface's anchor point
+ * @surface_anchor: the point on @surface to align with @rect's anchor point
+ *
+ * Create a popup layout description. Used together with
+ * gdk_surface_present_popup() to describe how a popup surface should be placed
+ * and behave on-screen.
+ *
+ * @anchor_rect is relative to the top-left corner of the surface's parent.
+ * @rect_anchor and @surface_anchor determine anchor points on @anchor_rect and
+ * surface to pin together.
+ *
+ * The position of @anchor_rect's anchor point can optionally be offset using
+ * gdk_popup_layout_set_offset(), which is equivalent to offsetting the
+ * position of surface.
+ *
+ * Returns: (transfer full): newly created instance of #GdkPopupLayout
+ */
+GdkPopupLayout *
+gdk_popup_layout_new (const GdkRectangle *anchor_rect,
+ GdkGravity rect_anchor,
+ GdkGravity surface_anchor)
+{
+ GdkPopupLayout *layout;
+
+ layout = g_new0 (GdkPopupLayout, 1);
+ g_ref_count_init (&layout->ref_count);
+ layout->anchor_rect = *anchor_rect;
+ layout->rect_anchor = rect_anchor;
+ layout->surface_anchor = surface_anchor;
+
+ return layout;
+}
+
+/**
+ * gdk_popup_layout_ref:
+ * @layout: a #GdkPopupLayout
+ *
+ * Increases the reference count of @value.
+ *
+ * Returns: the same @layout
+ */
+GdkPopupLayout *
+gdk_popup_layout_ref (GdkPopupLayout *layout)
+{
+ g_ref_count_inc (&layout->ref_count);
+ return layout;
+}
+
+/**
+ * gdk_popup_layout_unref:
+ * @layout: a #GdkPopupLayout
+ *
+ * Decreases the reference count of @value.
+ */
+void
+gdk_popup_layout_unref (GdkPopupLayout *layout)
+{
+ if (g_ref_count_dec (&layout->ref_count))
+ g_free (layout);
+}
+
+/**
+ * gdk_popup_layout_copy:
+ * @layout: a #GdkPopupLayout
+ *
+ * Create a new #GdkPopupLayout and copy the contents of @layout into it.
+ *
+ * Returns: (transfer full): a copy of @layout.
+ */
+GdkPopupLayout *
+gdk_popup_layout_copy (GdkPopupLayout *layout)
+{
+ GdkPopupLayout *new_layout;
+
+ new_layout = g_new0 (GdkPopupLayout, 1);
+ g_ref_count_init (&new_layout->ref_count);
+
+ new_layout->anchor_rect = layout->anchor_rect;
+ new_layout->rect_anchor = layout->rect_anchor;
+ new_layout->surface_anchor = layout->surface_anchor;
+ new_layout->anchor_hints = layout->anchor_hints;
+ new_layout->dx = layout->dx;
+ new_layout->dy = layout->dy;
+
+ return new_layout;
+}
+
+/**
+ * gdk_popup_layout_set_anchor_rect:
+ * @layout: a #GdkPopupLayout
+ * @anchor_rect: the new anchor rectangle
+ *
+ * Set the anchor rectangle.
+ */
+void
+gdk_popup_layout_set_anchor_rect (GdkPopupLayout *layout,
+ const GdkRectangle *anchor_rect)
+{
+ layout->anchor_rect = *anchor_rect;
+}
+
+/**
+ * gdk_popup_layout_get_anchor_rect:
+ * @layout: a #GdkPopupLayout
+ *
+ * Get the anchor rectangle.
+ *
+ * Returns: The anchor rectangle.
+ */
+const GdkRectangle *
+gdk_popup_layout_get_anchor_rect (GdkPopupLayout *layout)
+{
+ return &layout->anchor_rect;
+}
+
+/**
+ * gdk_popup_layout_set_rect_anchor:
+ * @layout: a #GdkPopupLayout
+ * @anchor: the new rect anchor
+ *
+ * Set the anchor on the anchor rectangle.
+ */
+void
+gdk_popup_layout_set_rect_anchor (GdkPopupLayout *layout,
+ GdkGravity anchor)
+{
+ layout->rect_anchor = anchor;
+}
+
+/**
+ * gdk_popup_layout_get_rect_anchor:
+ * @layout: a #GdkPopupLayout
+ *
+ * Returns: the anchor on the anchor rectangle.
+ */
+GdkGravity
+gdk_popup_layout_get_rect_anchor (GdkPopupLayout *layout)
+{
+ return layout->rect_anchor;
+}
+
+/**
+ * gdk_popup_layout_set_surface_anchor:
+ * @layout: a #GdkPopupLayout
+ * @anchor: the new popup surface anchor
+ *
+ * Set the anchor on the popup surface.
+ */
+void
+gdk_popup_layout_set_surface_anchor (GdkPopupLayout *layout,
+ GdkGravity anchor)
+{
+ layout->surface_anchor = anchor;
+}
+
+/**
+ * gdk_popup_layout_get_surface_anchor:
+ * @layout: a #GdkPopupLayout
+ *
+ * Returns: the anchor on the popup surface.
+ */
+GdkGravity
+gdk_popup_layout_get_surface_anchor (GdkPopupLayout *layout)
+{
+ return layout->surface_anchor;
+}
+
+/**
+ * gdk_popup_layout_set_anchor_hints:
+ * @layout: a #GdkPopupLayout
+ * @anchor_hints: the new #GdkAnchorHints
+ *
+ * Set new anchor hints.
+ *
+ * The set @anchor_hints determines how @surface 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 @surface extends beyond the left or right edges of the monitor.
+ */
+void
+gdk_popup_layout_set_anchor_hints (GdkPopupLayout *layout,
+ GdkAnchorHints anchor_hints)
+{
+ layout->anchor_hints = anchor_hints;
+}
+
+/**
+ * gdk_popup_layout_get_anchor_hints:
+ * @layout: a #GdkPopupLayout
+ *
+ * Get the #GdkAnchorHints.
+ *
+ * Returns: the #GdkAnchorHints.
+ */
+GdkAnchorHints
+gdk_popup_layout_get_anchor_hints (GdkPopupLayout *layout)
+{
+ return layout->anchor_hints;
+}
+
+/**
+ * gdk_popup_layout_set_offset:
+ * @layout: a #GdkPopupLayout
+ * @dx: x delta to offset the anchor rectangle with
+ * @dy: y delta to offset the anchor rectangle with
+ *
+ * Offset the position of the anchor rectangle with the given delta.
+ */
+void
+gdk_popup_layout_set_offset (GdkPopupLayout *layout,
+ int dx,
+ int dy)
+{
+ layout->dx = dx;
+ layout->dy = dy;
+}
+
+/**
+ * gdk_popup_layout_get_offset:
+ * @layout: a #GdkPopupLayout
+ * @dx: a pointer to where to store the delta x coordinate
+ * @dy: a pointer to where to store the delta y coordinate
+ *
+ * Get the delta the anchor rectangle is offset with
+ */
+void
+gdk_popup_layout_get_offset (GdkPopupLayout *layout,
+ int *dx,
+ int *dy)
+{
+ if (dx)
+ *dx = layout->dx;
+ if (dy)
+ *dy = layout->dy;
+}
diff --git a/gdk/gdkpopuplayout.h b/gdk/gdkpopuplayout.h
new file mode 100644
index 0000000000..9a07c0aeea
--- /dev/null
+++ b/gdk/gdkpopuplayout.h
@@ -0,0 +1,136 @@
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2020 Red Hat
+ *
+ * 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/>.
+ *
+ */
+
+#ifndef __GDK_POPUP_LAYOUT_H__
+#define __GDK_POPUP_LAYOUT_H__
+
+#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#include <gdk/gdkversionmacros.h>
+#include <gdk/gdktypes.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GdkAnchorHints:
+ * @GDK_ANCHOR_FLIP_X: allow flipping anchors horizontally
+ * @GDK_ANCHOR_FLIP_Y: allow flipping anchors vertically
+ * @GDK_ANCHOR_SLIDE_X: allow sliding surface horizontally
+ * @GDK_ANCHOR_SLIDE_Y: allow sliding surface vertically
+ * @GDK_ANCHOR_RESIZE_X: allow resizing surface horizontally
+ * @GDK_ANCHOR_RESIZE_Y: allow resizing surface vertically
+ * @GDK_ANCHOR_FLIP: allow flipping anchors on both axes
+ * @GDK_ANCHOR_SLIDE: allow sliding surface on both axes
+ * @GDK_ANCHOR_RESIZE: allow resizing surface on both axes
+ *
+ * Positioning hints for aligning a surface relative to a rectangle.
+ *
+ * These hints determine how the surface should be positioned in the case that
+ * the surface 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 surface extends beyond the left
+ * or right edges of the monitor.
+ *
+ * If %GDK_ANCHOR_SLIDE_X is set, the surface can be shifted horizontally to fit
+ * on-screen. If %GDK_ANCHOR_RESIZE_X is set, the surface 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.
+ */
+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;
+
+/**
+ * GdkPopupLayout:
+ */
+typedef struct _GdkPopupLayout GdkPopupLayout;
+
+#define GDK_TYPE_POPUP_LAYOUT (gdk_popup_layout_get_type ())
+
+GDK_AVAILABLE_IN_ALL
+GType gdk_popup_layout_get_type (void);
+
+GDK_AVAILABLE_IN_ALL
+GdkPopupLayout * gdk_popup_layout_new (const GdkRectangle *anchor_rect,
+ GdkGravity rect_anchor,
+ GdkGravity surface_anchor);
+
+GDK_AVAILABLE_IN_ALL
+GdkPopupLayout * gdk_popup_layout_ref (GdkPopupLayout *layout);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_popup_layout_unref (GdkPopupLayout *layout);
+
+GDK_AVAILABLE_IN_ALL
+GdkPopupLayout * gdk_popup_layout_copy (GdkPopupLayout *layout);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_popup_layout_set_anchor_rect (GdkPopupLayout *layout,
+ const GdkRectangle *anchor_rect);
+
+GDK_AVAILABLE_IN_ALL
+const GdkRectangle * gdk_popup_layout_get_anchor_rect (GdkPopupLayout *layout);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_popup_layout_set_rect_anchor (GdkPopupLayout *layout,
+ GdkGravity anchor);
+
+GDK_AVAILABLE_IN_ALL
+GdkGravity gdk_popup_layout_get_rect_anchor (GdkPopupLayout *layout);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_popup_layout_set_surface_anchor (GdkPopupLayout *layout,
+ GdkGravity anchor);
+
+GDK_AVAILABLE_IN_ALL
+GdkGravity gdk_popup_layout_get_surface_anchor (GdkPopupLayout *layout);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_popup_layout_set_anchor_hints (GdkPopupLayout *layout,
+ GdkAnchorHints anchor_hints);
+
+GDK_AVAILABLE_IN_ALL
+GdkAnchorHints gdk_popup_layout_get_anchor_hints (GdkPopupLayout *layout);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_popup_layout_set_offset (GdkPopupLayout *layout,
+ int dx,
+ int dy);
+
+GDK_AVAILABLE_IN_ALL
+void gdk_popup_layout_get_offset (GdkPopupLayout *layout,
+ int *dx,
+ int *dy);
+
+G_END_DECLS
+
+#endif /* __GDK_POPUP_LAYOUT_H__ */
diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c
index 9790be98a3..dbda1833bc 100644
--- a/gdk/gdksurface.c
+++ b/gdk/gdksurface.c
@@ -69,7 +69,7 @@
*/
enum {
- MOVED_TO_RECT,
+ POPUP_LAYOUT_CHANGED,
SIZE_CHANGED,
RENDER,
EVENT,
@@ -247,36 +247,30 @@ maybe_flip_position (gint bounds_pos,
}
void
-gdk_surface_move_to_rect_helper (GdkSurface *surface,
- const GdkRectangle *rect,
- GdkGravity rect_anchor,
- GdkGravity surface_anchor,
- GdkAnchorHints anchor_hints,
- gint rect_anchor_dx,
- gint rect_anchor_dy,
- GdkSurfaceMovedToRect moved_to_rect)
-{
- GdkSurface *toplevel;
+gdk_surface_layout_popup_helper (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout,
+ GdkRectangle *out_final_rect)
+{
GdkDisplay *display;
GdkMonitor *monitor;
GdkRectangle bounds;
- GdkRectangle root_rect = *rect;
- GdkRectangle flipped_rect;
+ GdkRectangle root_rect;
+ GdkGravity rect_anchor;
+ GdkGravity surface_anchor;
+ int rect_anchor_dx;
+ int rect_anchor_dy;
+ GdkAnchorHints anchor_hints;
GdkRectangle final_rect;
gboolean flipped_x;
gboolean flipped_y;
int x, y;
- /* This implementation only works for backends that
- * can provide root coordinates via get_root_coords.
- * Other backends need to implement move_to_rect.
- */
- if (surface->surface_type == GDK_SURFACE_POPUP)
- toplevel = surface->parent;
- else
- toplevel = surface->transient_for;
+ g_return_if_fail (surface->surface_type == GDK_SURFACE_POPUP);
- gdk_surface_get_root_coords (toplevel,
+ root_rect = *gdk_popup_layout_get_anchor_rect (layout);
+ gdk_surface_get_root_coords (surface->parent,
root_rect.x,
root_rect.y,
&root_rect.x,
@@ -286,30 +280,33 @@ gdk_surface_move_to_rect_helper (GdkSurface *surface,
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;
+ rect_anchor = gdk_popup_layout_get_rect_anchor (layout);
+ surface_anchor = gdk_popup_layout_get_surface_anchor (layout);
+ gdk_popup_layout_get_offset (layout, &rect_anchor_dx, &rect_anchor_dy);
+ anchor_hints = gdk_popup_layout_get_anchor_hints (layout);
+
+ final_rect.width = width - surface->shadow_left - surface->shadow_right;
+ final_rect.height = height - surface->shadow_top - surface->shadow_bottom;
+ final_rect.x = maybe_flip_position (bounds.x,
+ bounds.width,
+ root_rect.x,
+ root_rect.width,
+ final_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);
+ final_rect.y = maybe_flip_position (bounds.y,
+ bounds.height,
+ root_rect.y,
+ root_rect.height,
+ final_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);
if (anchor_hints & GDK_ANCHOR_SLIDE_X)
{
@@ -353,30 +350,30 @@ gdk_surface_move_to_rect_helper (GdkSurface *surface,
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;
- gdk_surface_get_origin (toplevel, &x, &y);
+ gdk_surface_get_origin (surface->parent, &x, &y);
final_rect.x -= x;
final_rect.y -= y;
- flipped_rect.x -= x;
- flipped_rect.y -= y;
- moved_to_rect (surface, final_rect);
+ if (flipped_x)
+ {
+ rect_anchor = gdk_gravity_flip_horizontally (rect_anchor);
+ surface_anchor = gdk_gravity_flip_horizontally (surface_anchor);
+ }
+ if (flipped_y)
+ {
+ rect_anchor = gdk_gravity_flip_vertically (rect_anchor);
+ surface_anchor = gdk_gravity_flip_vertically (surface_anchor);
+ }
+
+ surface->popup.rect_anchor = rect_anchor;
+ surface->popup.surface_anchor = surface_anchor;
- g_signal_emit_by_name (surface,
- "moved-to-rect",
- &flipped_rect,
- &final_rect,
- flipped_x,
- flipped_y);
+ *out_final_rect = final_rect;
}
static void
@@ -481,42 +478,24 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
g_object_class_install_properties (object_class, LAST_PROP, properties);
/**
- * GdkSurface::moved-to-rect:
- * @surface: the #GdkSurface that moved
- * @flipped_rect: (nullable): the position of @surface after any possible
- * flipping or %NULL if the backend can't obtain it
- * @final_rect: (nullable): the final position of @surface 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 @surface is finalized after being moved to a
- * destination rectangle.
+ * GdkSurface::popup-layout-changed
+ * @surface: the #GdkSurface that was laid out
*
- * @surface 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.
+ * Emitted when the layout of a popup @surface has changed, e.g. if the popup
+ * layout was reactive and after the parent moved causing the popover to end
+ * up partially off-screen.
*
- * @flipped_rect is the ideal position of @surface 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 @surface on-screen.
- * Stability: Private
*/
- signals[MOVED_TO_RECT] =
- g_signal_new (g_intern_static_string ("moved-to-rect"),
+ signals[POPUP_LAYOUT_CHANGED] =
+ g_signal_new (g_intern_static_string ("popup-layout-changed"),
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL,
NULL,
- _gdk_marshal_VOID__POINTER_POINTER_BOOLEAN_BOOLEAN,
+ NULL,
G_TYPE_NONE,
- 4,
- G_TYPE_POINTER,
- G_TYPE_POINTER,
- G_TYPE_BOOLEAN,
- G_TYPE_BOOLEAN);
+ 0);
/**
* GdkSurface::size-changed:
@@ -805,9 +784,8 @@ gdk_surface_new_temp (GdkDisplay *display,
*
* Create a new popup surface.
*
- * The surface will be attached to @parent and can
- * be positioned relative to it using
- * gdk_surface_move_to_rect().
+ * The surface will be attached to @parent and can be positioned relative to it
+ * using gdk_surface_show_popup() or later using gdk_surface_layout_popup().
*
* Returns: (transfer full): a new #GdkSurface
*/
@@ -1985,14 +1963,6 @@ gdk_surface_restack (GdkSurface *surface,
GDK_SURFACE_GET_CLASS (surface)->restack_toplevel (surface, sibling, above);
}
-static void
-grab_prepare_func (GdkSeat *seat,
- GdkSurface *surface,
- gpointer data)
-{
- gdk_surface_show_internal (surface, TRUE);
-}
-
/**
* gdk_surface_show:
* @surface: a #GdkSurface
@@ -2004,25 +1974,18 @@ grab_prepare_func (GdkSeat *seat,
* This function maps a surface so it’s visible onscreen. Its opposite
* is gdk_surface_hide().
*
+ * This function may not be used on a #GdkSurface with the surface type
+ * GTK_SURFACE_POPUP.
+ *
* When implementing a #GtkWidget, you should call this function on the widget's
* #GdkSurface as part of the “map” method.
*/
void
gdk_surface_show (GdkSurface *surface)
{
- if (surface->autohide)
- {
- gdk_seat_grab (gdk_display_get_default_seat (surface->display),
- surface,
- GDK_SEAT_CAPABILITY_ALL,
- TRUE,
- NULL, NULL,
- grab_prepare_func, NULL);
- }
- else
- {
- gdk_surface_show_internal (surface, TRUE);
- }
+ g_return_if_fail (surface->surface_type != GDK_SURFACE_POPUP);
+
+ gdk_surface_show_internal (surface, TRUE);
}
/**
@@ -2084,6 +2047,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS
GDK_SURFACE_GET_CLASS (surface)->hide (surface);
+ surface->popup.rect_anchor = 0;
+ surface->popup.surface_anchor = 0;
surface->x = 0;
surface->y = 0;
}
@@ -2109,52 +2074,70 @@ gdk_surface_resize (GdkSurface *surface,
}
/**
- * gdk_surface_move_to_rect:
- * @surface: the #GdkSurface to move
- * @rect: (not nullable): the destination #GdkRectangle to align @surface with
- * @rect_anchor: the point on @rect to align with @surface's anchor point
- * @surface_anchor: the point on @surface to align with @rect's anchor point
- * @anchor_hints: positioning hints to use when limited on space
- * @rect_anchor_dx: horizontal offset to shift @surface, i.e. @rect's anchor
- * point
- * @rect_anchor_dy: vertical offset to shift @surface, i.e. @rect's anchor point
- *
- * Moves @surface to @rect, aligning their anchor points.
- *
- * @rect is relative to the top-left corner of the surface that @surface is
- * transient for. @rect_anchor and @surface_anchor determine anchor points on
- * @rect and @surface 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 @surface.
- *
- * @anchor_hints determines how @surface 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
- * @surface extends beyond the left or right edges of the monitor.
- *
- * Connect to the #GdkSurface::moved-to-rect signal to find out how it was
- * actually positioned.
+ * gdk_surface_present_popup:
+ * @surface: the popup #GdkSurface to show
+ * @width: the unconstrained popup width to layout
+ * @height: the unconstrained popup height to layout
+ * @layout: the #GdkPopupLayout object used to layout
+ *
+ * Present @surface after having processed the #GdkPopupLayout rules. If the
+ * popup was previously now showing, it will be showed, otherwise it will
+ * change position according to @layout.
+ *
+ * After calling this function, the result of the layout can be queried
+ * using gdk_surface_get_position(), gdk_surface_get_width(),
+ * gdk_surface_get_height(), gdk_surface_get_popup_rect_anchor() and
+ * gdk_surface_get_popup_surface_anchor().
+ *
+ * Presenting may have fail, for example if it was immediately hidden if the
+ * @surface was set to autohide.
+ *
+ * Returns: %FALSE if it failed to be presented, otherwise %TRUE.
*/
-void
-gdk_surface_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)
+gboolean
+gdk_surface_present_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
{
- g_return_if_fail (GDK_IS_SURFACE (surface));
- g_return_if_fail (surface->parent || surface->transient_for);
- g_return_if_fail (rect);
-
- GDK_SURFACE_GET_CLASS (surface)->move_to_rect (surface,
- rect,
- rect_anchor,
- surface_anchor,
- anchor_hints,
- rect_anchor_dx,
- rect_anchor_dy);
+ g_return_val_if_fail (GDK_IS_SURFACE (surface), FALSE);
+ g_return_val_if_fail (surface->parent, FALSE);
+ g_return_val_if_fail (layout, FALSE);
+ g_return_val_if_fail (!GDK_SURFACE_DESTROYED (surface), FALSE);
+ g_return_val_if_fail (width > 0 && height > 0, FALSE);
+
+ return GDK_SURFACE_GET_CLASS (surface)->present_popup (surface,
+ width,
+ height,
+ layout);
+}
+
+/**
+ * gdk_surface_get_popup_surface_anchor:
+ * @surface: a #GdkSurface
+ *
+ * Get the current popup surface anchor. The value returned may chage after
+ * calling gdk_surface_show_popup(), gdk_surface_layout_popup() or after the
+ * "popup-layout-changed" is emitted.
+ */
+GdkGravity
+gdk_surface_get_popup_surface_anchor (GdkSurface *surface)
+{
+ return surface->popup.surface_anchor;
+}
+
+/**
+ * gdk_surface_get_popup_rect_anchor:
+ * @surface: a #GdkSurface
+ *
+ * Get the current popup anchor rectangle anchor. The value
+ * returned may chage after calling gdk_surface_show_popup(),
+ * gdk_surface_layout_popup() or after the "popup-layout-changed" is emitted.
+ */
+GdkGravity
+gdk_surface_get_popup_rect_anchor (GdkSurface *surface)
+{
+ return surface->popup.rect_anchor;
}
static void
diff --git a/gdk/gdksurface.h b/gdk/gdksurface.h
index 2d8c3d0b5f..6f50e66b7b 100644
--- a/gdk/gdksurface.h
+++ b/gdk/gdksurface.h
@@ -34,6 +34,7 @@
#include <gdk/gdkevents.h>
#include <gdk/gdkframeclock.h>
#include <gdk/gdkmonitor.h>
+#include <gdk/gdkpopuplayout.h>
G_BEGIN_DECLS
@@ -143,47 +144,6 @@ typedef enum
GDK_FUNC_CLOSE = 1 << 5
} GdkWMFunction;
-/**
- * GdkAnchorHints:
- * @GDK_ANCHOR_FLIP_X: allow flipping anchors horizontally
- * @GDK_ANCHOR_FLIP_Y: allow flipping anchors vertically
- * @GDK_ANCHOR_SLIDE_X: allow sliding surface horizontally
- * @GDK_ANCHOR_SLIDE_Y: allow sliding surface vertically
- * @GDK_ANCHOR_RESIZE_X: allow resizing surface horizontally
- * @GDK_ANCHOR_RESIZE_Y: allow resizing surface vertically
- * @GDK_ANCHOR_FLIP: allow flipping anchors on both axes
- * @GDK_ANCHOR_SLIDE: allow sliding surface on both axes
- * @GDK_ANCHOR_RESIZE: allow resizing surface on both axes
- *
- * Positioning hints for aligning a surface relative to a rectangle.
- *
- * These hints determine how the surface should be positioned in the case that
- * the surface 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 surface extends beyond the left
- * or right edges of the monitor.
- *
- * If %GDK_ANCHOR_SLIDE_X is set, the surface can be shifted horizontally to fit
- * on-screen. If %GDK_ANCHOR_RESIZE_X is set, the surface 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.
- */
-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;
-
/**
* GdkSurfaceEdge:
* @GDK_SURFACE_EDGE_NORTH_WEST: the top left corner.
@@ -407,13 +367,14 @@ void gdk_surface_resize (GdkSurface *surface,
gint width,
gint height);
GDK_AVAILABLE_IN_ALL
-void gdk_surface_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);
+gboolean gdk_surface_present_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout);
+GDK_AVAILABLE_IN_ALL
+GdkGravity gdk_surface_get_popup_surface_anchor (GdkSurface *surface);
+GDK_AVAILABLE_IN_ALL
+GdkGravity gdk_surface_get_popup_rect_anchor (GdkSurface *surface);
GDK_AVAILABLE_IN_ALL
void gdk_surface_raise (GdkSurface *surface);
diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h
index eafdb78c19..fa9674451d 100644
--- a/gdk/gdksurfaceprivate.h
+++ b/gdk/gdksurfaceprivate.h
@@ -73,6 +73,11 @@ struct _GdkSurface
guint frame_clock_events_paused : 1;
guint autohide : 1;
+ struct {
+ GdkGravity surface_anchor;
+ GdkGravity rect_anchor;
+ } popup;
+
guint update_and_descendants_freeze_count;
gint width, height;
@@ -116,13 +121,10 @@ struct _GdkSurfaceClass
void (* toplevel_resize) (GdkSurface *surface,
gint width,
gint height);
- void (* 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);
+ gboolean (* present_popup) (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout);
void (* get_geometry) (GdkSurface *surface,
gint *x,
@@ -255,18 +257,71 @@ struct _GdkSurfaceClass
void gdk_surface_set_state (GdkSurface *surface,
GdkSurfaceState new_state);
-typedef void (* GdkSurfaceMovedToRect) (GdkSurface *surface,
- GdkRectangle final_rect);
-
-void
-gdk_surface_move_to_rect_helper (GdkSurface *surface,
- const GdkRectangle *rect,
- GdkGravity rect_anchor,
- GdkGravity surface_anchor,
- GdkAnchorHints anchor_hints,
- gint rect_anchor_dx,
- gint rect_anchor_dy,
- GdkSurfaceMovedToRect moved_to_rect);
+void gdk_surface_layout_popup_helper (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout,
+ GdkRectangle *out_final_rect);
+
+static inline GdkGravity
+gdk_gravity_flip_horizontally (GdkGravity anchor)
+{
+ switch (anchor)
+ {
+ default:
+ case GDK_GRAVITY_STATIC:
+ case GDK_GRAVITY_NORTH_WEST:
+ return GDK_GRAVITY_NORTH_EAST;
+ case GDK_GRAVITY_NORTH:
+ return GDK_GRAVITY_NORTH;
+ case GDK_GRAVITY_NORTH_EAST:
+ return GDK_GRAVITY_NORTH_WEST;
+ case GDK_GRAVITY_WEST:
+ return GDK_GRAVITY_EAST;
+ case GDK_GRAVITY_CENTER:
+ return GDK_GRAVITY_CENTER;
+ case GDK_GRAVITY_EAST:
+ return GDK_GRAVITY_WEST;
+ case GDK_GRAVITY_SOUTH_WEST:
+ return GDK_GRAVITY_SOUTH_EAST;
+ case GDK_GRAVITY_SOUTH:
+ return GDK_GRAVITY_SOUTH;
+ case GDK_GRAVITY_SOUTH_EAST:
+ return GDK_GRAVITY_SOUTH_WEST;
+ }
+
+ g_assert_not_reached ();
+}
+
+static inline GdkGravity
+gdk_gravity_flip_vertically (GdkGravity anchor)
+{
+ switch (anchor)
+ {
+ default:
+ case GDK_GRAVITY_STATIC:
+ case GDK_GRAVITY_NORTH_WEST:
+ return GDK_GRAVITY_SOUTH_WEST;
+ case GDK_GRAVITY_NORTH:
+ return GDK_GRAVITY_SOUTH;
+ case GDK_GRAVITY_NORTH_EAST:
+ return GDK_GRAVITY_SOUTH_EAST;
+ case GDK_GRAVITY_WEST:
+ return GDK_GRAVITY_WEST;
+ case GDK_GRAVITY_CENTER:
+ return GDK_GRAVITY_CENTER;
+ case GDK_GRAVITY_EAST:
+ return GDK_GRAVITY_EAST;
+ case GDK_GRAVITY_SOUTH_WEST:
+ return GDK_GRAVITY_NORTH_WEST;
+ case GDK_GRAVITY_SOUTH:
+ return GDK_GRAVITY_NORTH;
+ case GDK_GRAVITY_SOUTH_EAST:
+ return GDK_GRAVITY_NORTH_EAST;
+ }
+
+ g_assert_not_reached ();
+}
G_END_DECLS
diff --git a/gdk/meson.build b/gdk/meson.build
index ed41b126ea..af04354d88 100644
--- a/gdk/meson.build
+++ b/gdk/meson.build
@@ -45,6 +45,7 @@ gdk_public_sources = files([
'gdktexture.c',
'gdkvulkancontext.c',
'gdksurface.c',
+ 'gdkpopuplayout.c',
'gdkprofiler.c'
])
@@ -90,6 +91,7 @@ gdk_public_headers = files([
'gdktypes.h',
'gdkvulkancontext.h',
'gdksurface.h',
+ 'gdkpopuplayout.h',
])
install_headers(gdk_public_headers, subdir: 'gtk-4.0/gdk/')
diff --git a/gdk/quartz/gdksurface-quartz.c b/gdk/quartz/gdksurface-quartz.c
index cd8599e281..ae259e7d42 100644
--- a/gdk/quartz/gdksurface-quartz.c
+++ b/gdk/quartz/gdksurface-quartz.c
@@ -1245,51 +1245,83 @@ gdk_surface_quartz_toplevel_resize (GdkSurface *surface,
}
static void
-gdk_quartz_surface_moved_to_rect (GdkSurface *surface,
- GdkRectangle final_rect)
+gdk_quartz_surface_layout_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
{
- GdkSurface *toplevel;
+ GdkRectangle final_rect;
int x, y;
- if (surface->surface_type == GDK_SURFACE_POPUP)
- toplevel = surface->parent;
- else
- toplevel = surface->transient_for;
+ gdk_surface_layout_popup_helper (surface,
+ width,
+ height,
+ layout,
+ &final_rect);
- gdk_surface_get_origin (toplevel, &x, &y);
+ gdk_surface_get_origin (surface->parent, &x, &y);
x += final_rect.x;
y += final_rect.y;
if (final_rect.width != surface->width ||
final_rect.height != surface->height)
{
- window_quartz_move_resize (surface,
- x, y,
- final_rect.width, final_rect.height);
+ move_resize_window_internal (surface,
+ x,
+ y,
+ final_rect.width,
+ final_rect.height);
}
else
{
- window_quartz_resize (surface, final_rect.width, final_rect.height);
+ window_quartz_move (surface, x, y);
}
}
static void
-gdk_quartz_surface_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)
-{
- gdk_surface_move_to_rect_helper (surface,
- rect,
- rect_anchor,
- surface_anchor,
- anchor_hints,
- rect_anchor_dx,
- rect_anchor_dy,
- gdk_quartz_surface_moved_to_rect);
+show_popup (GdkSurface *surface)
+{
+ gdk_surface_raise (surface);
+ gdk_synthesize_surface_state (surface, GDK_SURFACE_STATE_WITHDRAWN, 0);
+ _gdk_surface_update_viewable (surface);
+ gdk_quartz_surface_show (surface, FALSE);
+ gdk_surface_invalidate_rect (surface, NULL);
+}
+
+static void
+show_grabbing_popup (GdkSeat *seat,
+ GdkSurface *surface,
+ gpointer user_data)
+{
+ show_popup (surface);
+}
+
+static gboolean
+gdk_quartz_surface_present_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
+{
+ gdk_quartz_surface_layout_popup (surface, width, height, layout);
+
+ if (GDK_SURFACE_IS_MAPPED (surface))
+ return TRUE;
+
+ if (surface->autohide)
+ {
+ gdk_seat_grab (gdk_display_get_default_seat (surface->display),
+ surface,
+ GDK_SEAT_CAPABILITY_ALL,
+ TRUE,
+ NULL, NULL,
+ show_grabbing_popup, NULL);
+ }
+ else
+ {
+ show_popup (surface);
+ }
+
+ return GDK_SURFACE_IS_MAPPED (surface);
}
/* Get the toplevel ordering from NSApp and update our own list. We do
@@ -2675,7 +2707,7 @@ gdk_surface_impl_quartz_class_init (GdkSurfaceImplQuartzClass *klass)
impl_class->lower = gdk_surface_quartz_lower;
impl_class->restack_toplevel = gdk_surface_quartz_restack_toplevel;
impl_class->toplevel_resize = gdk_surface_quartz_toplevel_resize;
- impl_class->move_to_rect = gdk_surface_quartz_move_to_rect;
+ impl_class->present_popup = gdk_quartz_surface_present_popup;
impl_class->get_geometry = gdk_surface_quartz_get_geometry;
impl_class->get_root_coords = gdk_surface_quartz_get_root_coords;
impl_class->get_device_state = gdk_surface_quartz_get_device_state;
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index 8ef0a3ae03..814c180386 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -4593,8 +4593,6 @@ gdk_wayland_seat_grab (GdkSeat *seat,
if (!gdk_surface_is_visible (surface))
{
gdk_wayland_seat_set_grab_surface (wayland_seat, NULL);
- g_critical ("Surface %p has not been made visible in GdkSeatGrabPrepareFunc",
- surface);
return GDK_GRAB_NOT_VIEWABLE;
}
diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c
index d9302c75e8..5a1b767089 100644
--- a/gdk/wayland/gdksurface-wayland.c
+++ b/gdk/wayland/gdksurface-wayland.c
@@ -52,6 +52,13 @@ static guint signals[LAST_SIGNAL];
#define MAX_WL_BUFFER_SIZE (4083) /* 4096 minus header, string argument length and NUL byte */
+typedef enum _PopupState
+{
+ POPUP_STATE_IDLE,
+ POPUP_STATE_WAITING_FOR_CONFIGURE,
+ POPUP_STATE_WAITING_FOR_FRAME,
+} PopupState;
+
struct _GdkWaylandSurface
{
GdkSurface parent_instance;
@@ -83,6 +90,8 @@ struct _GdkWaylandSurface
EGLSurface egl_surface;
EGLSurface dummy_egl_surface;
+ PopupState popup_state;
+
unsigned int initial_configure_received : 1;
unsigned int mapped : 1;
unsigned int pending_commit : 1;
@@ -91,7 +100,6 @@ struct _GdkWaylandSurface
GdkSurfaceTypeHint hint;
GdkSurface *transient_for;
GdkSurface *popup_parent;
- gboolean has_layout_data;
int pending_buffer_offset_x;
int pending_buffer_offset_y;
@@ -137,13 +145,10 @@ struct _GdkWaylandSurface
gulong parent_surface_committed_handler;
struct {
- GdkRectangle rect;
- GdkGravity rect_anchor;
- GdkGravity surface_anchor;
- GdkAnchorHints anchor_hints;
- gint rect_anchor_dx;
- gint rect_anchor_dy;
- } pending_move_to_rect;
+ GdkPopupLayout *layout;
+ int unconstrained_width;
+ int unconstrained_height;
+ } popup;
struct {
struct {
@@ -160,8 +165,11 @@ struct _GdkWaylandSurface
} popup;
uint32_t serial;
+ gboolean is_dirty;
} pending;
+ int state_freeze_count;
+
struct {
GdkWaylandSurfaceExported callback;
gpointer user_data;
@@ -199,15 +207,12 @@ static void gdk_wayland_surface_move_resize (GdkSurface *surface,
gint width,
gint height);
-static void calculate_moved_to_rect_result (GdkSurface *surface,
- int x,
- int y,
- int width,
- int height,
- GdkRectangle *flipped_rect,
- GdkRectangle *final_rect,
- gboolean *flipped_x,
- gboolean *flipped_y);
+static void update_popup_layout_state (GdkSurface *surface,
+ int x,
+ int y,
+ int width,
+ int height,
+ GdkPopupLayout *layout);
static gboolean gdk_wayland_surface_is_exported (GdkSurface *surface);
@@ -223,6 +228,32 @@ gdk_wayland_surface_init (GdkWaylandSurface *impl)
impl->shortcuts_inhibitors = g_hash_table_new (NULL, NULL);
}
+static void
+gdk_wayland_surface_freeze_state (GdkSurface *surface)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+
+ impl->state_freeze_count++;
+}
+
+static void
+gdk_wayland_surface_thaw_state (GdkSurface *surface)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+
+ g_assert (impl->state_freeze_count > 0);
+
+ impl->state_freeze_count--;
+
+ if (impl->state_freeze_count > 0)
+ return;
+
+ if (impl->pending.is_dirty)
+ gdk_wayland_surface_configure (surface);
+
+ g_assert (!impl->display_server.xdg_popup);
+}
+
static void
_gdk_wayland_screen_add_orphan_dialog (GdkSurface *surface)
{
@@ -341,6 +372,44 @@ fill_presentation_time_from_frame_time (GdkFrameTimings *timings,
}
}
+static GdkSurface *
+get_popup_toplevel (GdkSurface *surface)
+{
+ if (surface->parent)
+ return get_popup_toplevel (surface->parent);
+ else
+ return surface;
+}
+
+static void
+freeze_popup_toplevel_state (GdkSurface *surface)
+{
+ GdkSurface *toplevel;
+
+ toplevel = get_popup_toplevel (surface);
+ gdk_wayland_surface_freeze_state (toplevel);
+}
+
+static void
+thaw_popup_toplevel_state (GdkSurface *surface)
+{
+ GdkSurface *toplevel;
+
+ toplevel = get_popup_toplevel (surface);
+ gdk_wayland_surface_thaw_state (toplevel);
+}
+
+static void
+finish_pending_relayout (GdkSurface *surface)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+
+ g_assert (impl->popup_state == POPUP_STATE_WAITING_FOR_FRAME);
+ impl->popup_state = POPUP_STATE_IDLE;
+
+ thaw_popup_toplevel_state (surface);
+}
+
static void
frame_callback (void *data,
struct wl_callback *callback,
@@ -364,6 +433,18 @@ frame_callback (void *data,
if (!impl->awaiting_frame)
return;
+ switch (impl->popup_state)
+ {
+ case POPUP_STATE_IDLE:
+ case POPUP_STATE_WAITING_FOR_CONFIGURE:
+ break;
+ case POPUP_STATE_WAITING_FOR_FRAME:
+ finish_pending_relayout (surface);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
impl->awaiting_frame = FALSE;
if (impl->awaiting_frame_frozen)
{
@@ -464,11 +545,8 @@ on_frame_clock_after_paint (GdkFrameClock *clock,
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- if (impl->pending_commit)
+ if (impl->pending_commit && surface->update_freeze_count == 0)
{
- if (surface->update_freeze_count > 0)
- return;
-
gdk_wayland_surface_request_frame (surface);
/* From this commit forward, we can't write to the buffer,
@@ -671,6 +749,8 @@ gdk_wayland_surface_dispose (GObject *object)
impl = GDK_WAYLAND_SURFACE (surface);
+ g_clear_object (&impl->popup_parent);
+
if (impl->event_queue)
{
GdkWaylandDisplay *display_wayland =
@@ -1202,12 +1282,6 @@ gdk_wayland_surface_configure_popup (GdkSurface *surface)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
int x, y, width, height;
- GdkRectangle flipped_rect;
- GdkRectangle final_rect;
- gboolean flipped_x;
- gboolean flipped_y;
-
- g_return_if_fail (impl->transient_for);
if (impl->display_server.xdg_popup)
{
@@ -1220,6 +1294,18 @@ gdk_wayland_surface_configure_popup (GdkSurface *surface)
impl->pending.serial);
}
+ switch (impl->popup_state)
+ {
+ case POPUP_STATE_WAITING_FOR_CONFIGURE:
+ impl->popup_state = POPUP_STATE_WAITING_FOR_FRAME;
+ break;
+ case POPUP_STATE_IDLE:
+ case POPUP_STATE_WAITING_FOR_FRAME:
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
x = impl->pending.popup.x;
y = impl->pending.popup.y;
width = impl->pending.popup.width;
@@ -1227,20 +1313,12 @@ gdk_wayland_surface_configure_popup (GdkSurface *surface)
gdk_wayland_surface_resize (surface, width, height, impl->scale);
- calculate_moved_to_rect_result (surface,
- x, y,
- width, height,
- &flipped_rect,
- &final_rect,
- &flipped_x,
- &flipped_y);
+ update_popup_layout_state (surface,
+ x, y,
+ width, height,
+ impl->popup.layout);
- g_signal_emit_by_name (surface,
- "moved-to-rect",
- &flipped_rect,
- &final_rect,
- flipped_x,
- flipped_y);
+ gdk_surface_invalidate_rect (surface, NULL);
}
static void
@@ -1260,6 +1338,8 @@ gdk_wayland_surface_configure (GdkSurface *surface)
gdk_wayland_surface_configure_toplevel (surface);
else
g_warn_if_reached ();
+
+ memset (&impl->pending, 0, sizeof (impl->pending));
}
static void
@@ -1268,8 +1348,12 @@ gdk_wayland_surface_handle_configure (GdkSurface *surface,
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+ impl->pending.is_dirty = TRUE;
impl->pending.serial = serial;
+ if (impl->state_freeze_count > 0)
+ return;
+
gdk_wayland_surface_configure (surface);
}
@@ -1776,70 +1860,28 @@ gdk_wayland_surface_announce_csd (GdkSurface *surface)
ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_CLIENT);
}
-static GdkSurface *
-get_real_parent_and_translate (GdkSurface *surface,
- gint *x,
- gint *y)
-{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- GdkSurface *parent = impl->transient_for;
-
- return parent;
-}
-
-static void
-translate_to_real_parent_surface_geometry (GdkSurface *surface,
- gint *x,
- gint *y)
-{
- GdkSurface *parent;
-
- parent = get_real_parent_and_translate (surface, x, y);
-
- *x -= parent->shadow_left;
- *y -= parent->shadow_top;
-}
-
-static GdkSurface *
-translate_from_real_parent_surface_geometry (GdkSurface *surface,
- gint *x,
- gint *y)
-{
- GdkSurface *parent;
- gint dx = 0;
- gint dy = 0;
-
- parent = get_real_parent_and_translate (surface, &dx, &dy);
-
- *x -= dx - parent->shadow_left;
- *y -= dy - parent->shadow_top;
-
- return parent;
-}
-
static void
-calculate_popup_rect (GdkSurface *surface,
- GdkGravity rect_anchor,
- GdkGravity surface_anchor,
- GdkRectangle *out_rect)
+calculate_popup_rect (GdkSurface *surface,
+ GdkPopupLayout *layout,
+ GdkRectangle *out_rect)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- GdkRectangle geometry;
+ int width, height;
GdkRectangle anchor_rect;
+ int dx, dy;
int x = 0, y = 0;
- gdk_wayland_surface_get_window_geometry (surface, &geometry);
+ width = (impl->popup.unconstrained_width -
+ (impl->margin_left + impl->margin_right));
+ height = (impl->popup.unconstrained_height -
+ (impl->margin_top + impl->margin_bottom));
- anchor_rect = (GdkRectangle) {
- .x = (impl->pending_move_to_rect.rect.x +
- impl->pending_move_to_rect.rect_anchor_dx),
- .y = (impl->pending_move_to_rect.rect.y +
- impl->pending_move_to_rect.rect_anchor_dy),
- .width = impl->pending_move_to_rect.rect.width,
- .height = impl->pending_move_to_rect.rect.height
- };
+ anchor_rect = *gdk_popup_layout_get_anchor_rect (layout);
+ gdk_popup_layout_get_offset (layout, &dx, &dy);
+ anchor_rect.x += dx;
+ anchor_rect.y += dy;
- switch (rect_anchor)
+ switch (gdk_popup_layout_get_rect_anchor (layout))
{
default:
case GDK_GRAVITY_STATIC:
@@ -1881,137 +1923,71 @@ calculate_popup_rect (GdkSurface *surface,
break;
}
- switch (surface_anchor)
+ switch (gdk_popup_layout_get_surface_anchor (layout))
{
default:
case GDK_GRAVITY_STATIC:
case GDK_GRAVITY_NORTH_WEST:
break;
case GDK_GRAVITY_NORTH:
- x -= geometry.width / 2;
+ x -= width / 2;
break;
case GDK_GRAVITY_NORTH_EAST:
- x -= geometry.width;
+ x -= width;
break;
case GDK_GRAVITY_WEST:
- y -= geometry.height / 2;
+ y -= height / 2;
break;
case GDK_GRAVITY_CENTER:
- x -= geometry.width / 2;
- y -= geometry.height / 2;
+ x -= width / 2;
+ y -= height / 2;
break;
case GDK_GRAVITY_EAST:
- x -= geometry.width;
- y -= geometry.height / 2;
+ x -= width;
+ y -= height / 2;
break;
case GDK_GRAVITY_SOUTH_WEST:
- y -= geometry.height;
+ y -= height;
break;
case GDK_GRAVITY_SOUTH:
- x -= geometry.width / 2;
- y -= geometry.height;
+ x -= width / 2;
+ y -= height;
break;
case GDK_GRAVITY_SOUTH_EAST:
- x -= geometry.width;
- y -= geometry.height;
+ x -= width;
+ y -= height;
break;
}
*out_rect = (GdkRectangle) {
.x = x,
.y = y,
- .width = geometry.width,
- .height = geometry.height
+ .width = width,
+ .height = height
};
}
-static GdkGravity
-flip_anchor_horizontally (GdkGravity anchor)
-{
- switch (anchor)
- {
- default:
- case GDK_GRAVITY_STATIC:
- case GDK_GRAVITY_NORTH_WEST:
- return GDK_GRAVITY_NORTH_EAST;
- case GDK_GRAVITY_NORTH:
- return GDK_GRAVITY_NORTH;
- case GDK_GRAVITY_NORTH_EAST:
- return GDK_GRAVITY_NORTH_WEST;
- case GDK_GRAVITY_WEST:
- return GDK_GRAVITY_EAST;
- case GDK_GRAVITY_CENTER:
- return GDK_GRAVITY_CENTER;
- case GDK_GRAVITY_EAST:
- return GDK_GRAVITY_WEST;
- case GDK_GRAVITY_SOUTH_WEST:
- return GDK_GRAVITY_SOUTH_EAST;
- case GDK_GRAVITY_SOUTH:
- return GDK_GRAVITY_SOUTH;
- case GDK_GRAVITY_SOUTH_EAST:
- return GDK_GRAVITY_SOUTH_WEST;
- }
-
- g_assert_not_reached ();
-}
-
-static GdkGravity
-flip_anchor_vertically (GdkGravity anchor)
-{
- switch (anchor)
- {
- default:
- case GDK_GRAVITY_STATIC:
- case GDK_GRAVITY_NORTH_WEST:
- return GDK_GRAVITY_SOUTH_WEST;
- case GDK_GRAVITY_NORTH:
- return GDK_GRAVITY_SOUTH;
- case GDK_GRAVITY_NORTH_EAST:
- return GDK_GRAVITY_SOUTH_EAST;
- case GDK_GRAVITY_WEST:
- return GDK_GRAVITY_WEST;
- case GDK_GRAVITY_CENTER:
- return GDK_GRAVITY_CENTER;
- case GDK_GRAVITY_EAST:
- return GDK_GRAVITY_EAST;
- case GDK_GRAVITY_SOUTH_WEST:
- return GDK_GRAVITY_NORTH_WEST;
- case GDK_GRAVITY_SOUTH:
- return GDK_GRAVITY_NORTH;
- case GDK_GRAVITY_SOUTH_EAST:
- return GDK_GRAVITY_NORTH_EAST;
- }
-
- g_assert_not_reached ();
-}
-
static void
-calculate_moved_to_rect_result (GdkSurface *surface,
- int x,
- int y,
- int width,
- int height,
- GdkRectangle *flipped_rect,
- GdkRectangle *final_rect,
- gboolean *flipped_x,
- gboolean *flipped_y)
+update_popup_layout_state (GdkSurface *surface,
+ int x,
+ int y,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
{
- GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- GdkSurface *parent;
gint surface_x, surface_y;
gint surface_width, surface_height;
GdkRectangle best_rect;
+ GdkRectangle flipped_rect;
+ GdkGravity rect_anchor;
+ GdkGravity surface_anchor;
+ GdkAnchorHints anchor_hints;
- parent = translate_from_real_parent_surface_geometry (surface, &x, &y);
- *final_rect = (GdkRectangle) {
- .x = x,
- .y = y,
- .width = width,
- .height = height,
- };
+ x += surface->parent->shadow_left;
+ y += surface->parent->shadow_top;
- surface_x = parent->x + x;
- surface_y = parent->y + y;
+ surface_x = x;
+ surface_y = y;
surface_width = width + surface->shadow_left + surface->shadow_right;
surface_height = height + surface->shadow_top + surface->shadow_bottom;
@@ -2019,79 +1995,117 @@ calculate_moved_to_rect_result (GdkSurface *surface,
surface_x, surface_y,
surface_width, surface_height);
- calculate_popup_rect (surface,
- impl->pending_move_to_rect.rect_anchor,
- impl->pending_move_to_rect.surface_anchor,
- &best_rect);
+ rect_anchor = gdk_popup_layout_get_rect_anchor (layout);
+ surface_anchor = gdk_popup_layout_get_surface_anchor (layout);
+ anchor_hints = gdk_popup_layout_get_anchor_hints (layout);
- *flipped_rect = best_rect;
+ calculate_popup_rect (surface, layout, &best_rect);
+
+ flipped_rect = best_rect;
if (x != best_rect.x &&
- impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_X)
+ anchor_hints & GDK_ANCHOR_FLIP_X)
{
GdkRectangle flipped_x_rect;
GdkGravity flipped_rect_anchor;
GdkGravity flipped_surface_anchor;
-
- flipped_rect_anchor =
- flip_anchor_horizontally (impl->pending_move_to_rect.rect_anchor);
- flipped_surface_anchor =
- flip_anchor_horizontally (impl->pending_move_to_rect.surface_anchor),
+ GdkPopupLayout *flipped_layout;
+
+ flipped_rect_anchor = gdk_gravity_flip_horizontally (rect_anchor);
+ flipped_surface_anchor = gdk_gravity_flip_horizontally (surface_anchor);
+ flipped_layout = gdk_popup_layout_copy (layout);
+ gdk_popup_layout_set_rect_anchor (flipped_layout,
+ flipped_rect_anchor);
+ gdk_popup_layout_set_surface_anchor (flipped_layout,
+ flipped_surface_anchor);
calculate_popup_rect (surface,
- flipped_rect_anchor,
- flipped_surface_anchor,
+ flipped_layout,
&flipped_x_rect);
+ gdk_popup_layout_unref (flipped_layout);
if (flipped_x_rect.x == x)
- flipped_rect->x = x;
+ flipped_rect.x = x;
}
if (y != best_rect.y &&
- impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_Y)
+ anchor_hints & GDK_ANCHOR_FLIP_Y)
{
GdkRectangle flipped_y_rect;
GdkGravity flipped_rect_anchor;
GdkGravity flipped_surface_anchor;
-
- flipped_rect_anchor =
- flip_anchor_vertically (impl->pending_move_to_rect.rect_anchor);
- flipped_surface_anchor =
- flip_anchor_vertically (impl->pending_move_to_rect.surface_anchor),
+ GdkPopupLayout *flipped_layout;
+
+ flipped_rect_anchor = gdk_gravity_flip_vertically (rect_anchor);
+ flipped_surface_anchor = gdk_gravity_flip_vertically (surface_anchor);
+ flipped_layout = gdk_popup_layout_copy (layout);
+ gdk_popup_layout_set_rect_anchor (flipped_layout,
+ flipped_rect_anchor);
+ gdk_popup_layout_set_surface_anchor (flipped_layout,
+ flipped_surface_anchor);
calculate_popup_rect (surface,
- flipped_rect_anchor,
- flipped_surface_anchor,
+ flipped_layout,
&flipped_y_rect);
+ gdk_popup_layout_unref (flipped_layout);
if (flipped_y_rect.y == y)
- flipped_rect->y = y;
+ flipped_rect.y = y;
}
- *flipped_x = flipped_rect->x != best_rect.x;
- *flipped_y = flipped_rect->y != best_rect.y;
+ if (flipped_rect.x != best_rect.x)
+ {
+ rect_anchor = gdk_gravity_flip_horizontally (rect_anchor);
+ surface_anchor = gdk_gravity_flip_horizontally (surface_anchor);
+ }
+ if (flipped_rect.y != best_rect.y)
+ {
+ rect_anchor = gdk_gravity_flip_vertically (rect_anchor);
+ surface_anchor = gdk_gravity_flip_vertically (surface_anchor);
+ }
+
+ surface->popup.rect_anchor = rect_anchor;
+ surface->popup.surface_anchor = surface_anchor;
}
static gpointer
-create_dynamic_positioner (GdkSurface *surface)
+create_dynamic_positioner (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+ GdkSurface *parent = surface->parent;
GdkWaylandDisplay *display =
GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
GdkRectangle geometry;
uint32_t constraint_adjustment = ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE;
+ const GdkRectangle *anchor_rect;
gint real_anchor_rect_x, real_anchor_rect_y;
gint anchor_rect_width, anchor_rect_height;
+ int rect_anchor_dx;
+ int rect_anchor_dy;
+ GdkGravity rect_anchor;
+ GdkGravity surface_anchor;
+ GdkAnchorHints anchor_hints;
- g_warn_if_fail (impl->has_layout_data);
+ geometry = (GdkRectangle) {
+ .x = impl->margin_left,
+ .y = impl->margin_top,
+ .width = width - (impl->margin_left + impl->margin_right),
+ .height = height - (impl->margin_top + impl->margin_bottom),
+ };
- gdk_wayland_surface_get_window_geometry (surface, &geometry);
+ anchor_rect = gdk_popup_layout_get_anchor_rect (layout);
+ real_anchor_rect_x = anchor_rect->x - parent->shadow_left;
+ real_anchor_rect_y = anchor_rect->y - parent->shadow_top;
+
+ anchor_rect_width = anchor_rect->width;
+ anchor_rect_height = anchor_rect->height;
- real_anchor_rect_x = impl->pending_move_to_rect.rect.x;
- real_anchor_rect_y = impl->pending_move_to_rect.rect.y;
- translate_to_real_parent_surface_geometry (surface,
- &real_anchor_rect_x,
- &real_anchor_rect_y);
+ gdk_popup_layout_get_offset (layout, &rect_anchor_dx, &rect_anchor_dy);
- anchor_rect_width = impl->pending_move_to_rect.rect.width;
- anchor_rect_height = impl->pending_move_to_rect.rect.height;
+ rect_anchor = gdk_popup_layout_get_rect_anchor (layout);
+ surface_anchor = gdk_popup_layout_get_surface_anchor (layout);
+
+ anchor_hints = gdk_popup_layout_get_anchor_hints (layout);
switch (display->shell_variant)
{
@@ -2109,27 +2123,25 @@ create_dynamic_positioner (GdkSurface *surface)
real_anchor_rect_y,
anchor_rect_width,
anchor_rect_height);
- xdg_positioner_set_offset (positioner,
- impl->pending_move_to_rect.rect_anchor_dx,
- impl->pending_move_to_rect.rect_anchor_dy);
+ xdg_positioner_set_offset (positioner, rect_anchor_dx, rect_anchor_dy);
- anchor = rect_anchor_to_anchor (impl->pending_move_to_rect.rect_anchor);
+ anchor = rect_anchor_to_anchor (rect_anchor);
xdg_positioner_set_anchor (positioner, anchor);
- gravity = surface_anchor_to_gravity (impl->pending_move_to_rect.surface_anchor);
+ gravity = surface_anchor_to_gravity (surface_anchor);
xdg_positioner_set_gravity (positioner, gravity);
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_X)
+ if (anchor_hints & GDK_ANCHOR_FLIP_X)
constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_Y)
+ if (anchor_hints & GDK_ANCHOR_FLIP_Y)
constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_SLIDE_X)
+ if (anchor_hints & GDK_ANCHOR_SLIDE_X)
constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_SLIDE_Y)
+ if (anchor_hints & GDK_ANCHOR_SLIDE_Y)
constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_RESIZE_X)
+ if (anchor_hints & GDK_ANCHOR_RESIZE_X)
constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_RESIZE_Y)
+ if (anchor_hints & GDK_ANCHOR_RESIZE_Y)
constraint_adjustment |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
xdg_positioner_set_constraint_adjustment (positioner,
constraint_adjustment);
@@ -2151,26 +2163,26 @@ create_dynamic_positioner (GdkSurface *surface)
anchor_rect_width,
anchor_rect_height);
zxdg_positioner_v6_set_offset (positioner,
- impl->pending_move_to_rect.rect_anchor_dx,
- impl->pending_move_to_rect.rect_anchor_dy);
+ rect_anchor_dx,
+ rect_anchor_dy);
- anchor = rect_anchor_to_anchor_legacy (impl->pending_move_to_rect.rect_anchor);
+ anchor = rect_anchor_to_anchor_legacy (rect_anchor);
zxdg_positioner_v6_set_anchor (positioner, anchor);
- gravity = surface_anchor_to_gravity_legacy (impl->pending_move_to_rect.surface_anchor);
+ gravity = surface_anchor_to_gravity_legacy (surface_anchor);
zxdg_positioner_v6_set_gravity (positioner, gravity);
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_X)
+ if (anchor_hints & GDK_ANCHOR_FLIP_X)
constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_FLIP_Y)
+ if (anchor_hints & GDK_ANCHOR_FLIP_Y)
constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_SLIDE_X)
+ if (anchor_hints & GDK_ANCHOR_SLIDE_X)
constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_SLIDE_Y)
+ if (anchor_hints & GDK_ANCHOR_SLIDE_Y)
constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_RESIZE_X)
+ if (anchor_hints & GDK_ANCHOR_RESIZE_X)
constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X;
- if (impl->pending_move_to_rect.anchor_hints & GDK_ANCHOR_RESIZE_Y)
+ if (anchor_hints & GDK_ANCHOR_RESIZE_Y)
constraint_adjustment |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
zxdg_positioner_v6_set_constraint_adjustment (positioner,
constraint_adjustment);
@@ -2202,7 +2214,10 @@ can_map_grabbing_popup (GdkSurface *surface,
static void
gdk_wayland_surface_create_xdg_popup (GdkSurface *surface,
GdkSurface *parent,
- GdkWaylandSeat *grab_input_seat)
+ GdkWaylandSeat *grab_input_seat,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
{
GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
@@ -2235,7 +2250,7 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface,
gdk_surface_freeze_updates (surface);
- positioner = create_dynamic_positioner (surface);
+ positioner = create_dynamic_positioner (surface, width, height, layout);
switch (display->shell_variant)
{
@@ -2302,7 +2317,14 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface,
gdk_profiler_add_mark (g_get_monotonic_time (), 0, "wayland", "surface commit");
wl_surface_commit (impl->display_server.wl_surface);
- impl->popup_parent = parent;
+ if (surface->surface_type == GDK_SURFACE_POPUP)
+ {
+ g_assert (impl->popup_state == POPUP_STATE_IDLE);
+ impl->popup_state = POPUP_STATE_WAITING_FOR_CONFIGURE;
+ freeze_popup_toplevel_state (surface);
+ }
+
+ g_set_object (&impl->popup_parent, parent);
display->current_popups = g_list_append (display->current_popups, surface);
if (grab_input_seat)
{
@@ -2360,10 +2382,9 @@ should_map_as_popup (GdkSurface *surface)
}
static void
-gdk_wayland_surface_map (GdkSurface *surface)
+gdk_wayland_surface_map_toplevel (GdkSurface *surface)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- GdkSurface *parent = NULL;
if (!should_be_mapped (surface))
return;
@@ -2371,25 +2392,7 @@ gdk_wayland_surface_map (GdkSurface *surface)
if (impl->mapped)
return;
- if (should_map_as_popup (surface))
- {
- GdkWaylandSeat *grab_input_seat;
-
- parent = surface->parent;
- if (!parent)
- {
- g_warning ("Couldn't map as surface %p as popup because it doesn't have a parent",
- surface);
- return;
- }
-
- grab_input_seat = find_grab_input_seat (surface, parent);
- gdk_wayland_surface_create_xdg_popup (surface, parent, grab_input_seat);
- }
- else
- {
- gdk_wayland_surface_create_xdg_toplevel (surface);
- }
+ gdk_wayland_surface_create_xdg_toplevel (surface);
impl->mapped = TRUE;
}
@@ -2400,10 +2403,12 @@ gdk_wayland_surface_show (GdkSurface *surface,
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+ g_return_if_fail (!should_map_as_popup (surface));
+
if (!impl->display_server.wl_surface)
gdk_wayland_surface_create_surface (surface);
- gdk_wayland_surface_map (surface);
+ gdk_wayland_surface_map_toplevel (surface);
}
static void
@@ -2517,6 +2522,23 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
gdk_surface_thaw_updates (surface);
}
+ if (surface->surface_type == GDK_SURFACE_POPUP)
+ {
+ switch (impl->popup_state)
+ {
+ case POPUP_STATE_WAITING_FOR_CONFIGURE:
+ case POPUP_STATE_WAITING_FOR_FRAME:
+ thaw_popup_toplevel_state (surface);
+ break;
+ case POPUP_STATE_IDLE:
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ impl->popup_state = POPUP_STATE_IDLE;
+ }
+
if (impl->display_server.gtk_surface)
{
gtk_surface1_destroy (impl->display_server.gtk_surface);
@@ -2533,6 +2555,8 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
if (impl->hint == GDK_SURFACE_TYPE_HINT_DIALOG && !impl->transient_for)
display_wayland->orphan_dialogs =
g_list_remove (display_wayland->orphan_dialogs, surface);
+
+ g_clear_pointer (&impl->popup.layout, gdk_popup_layout_unref);
}
unset_transient_for_exported (surface);
@@ -2606,41 +2630,217 @@ gdk_wayland_surface_toplevel_resize (GdkSurface *surface,
impl->scale);
}
-/* Avoid zero width/height as this is a protocol error */
+static gboolean
+is_fallback_relayout_possible (GdkSurface *surface)
+{
+ GList *l;
+
+ for (l = surface->children; l; l = l->next)
+ {
+ GdkSurface *child = l->data;
+
+ if (GDK_WAYLAND_SURFACE (child)->mapped)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+queue_relayout_fallback (GdkSurface *surface,
+ GdkPopupLayout *layout)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+
+ if (!is_fallback_relayout_possible (surface))
+ return;
+
+ gdk_wayland_surface_hide_surface (surface);
+ gdk_surface_present_popup (surface,
+ impl->popup.unconstrained_width,
+ impl->popup.unconstrained_height,
+ layout);
+}
+
+static void
+do_queue_relayout (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+
+ g_assert (is_realized_popup (surface));
+ g_assert (impl->popup_state == POPUP_STATE_IDLE ||
+ impl->popup_state == POPUP_STATE_WAITING_FOR_FRAME);
+
+ g_clear_pointer (&impl->popup.layout, gdk_popup_layout_unref);
+ impl->popup.layout = gdk_popup_layout_copy (layout);
+ impl->popup.unconstrained_width = width;
+ impl->popup.unconstrained_height = height;
+
+ queue_relayout_fallback (surface, layout);
+}
+
+static gboolean
+is_relayout_finished (GdkSurface *surface)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+
+ if (!impl->initial_configure_received)
+ return FALSE;
+
+ return TRUE;
+}
+
static void
-sanitize_anchor_rect (GdkSurface *surface,
- GdkRectangle *rect)
+gdk_wayland_surface_map_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
{
- gint original_width = rect->width;
- gint original_height = rect->height;
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+ GdkSurface *parent;
+ GdkWaylandSeat *grab_input_seat;
+
+ if (!should_be_mapped (surface))
+ return;
- rect->width = MAX (1, rect->width);
- rect->height = MAX (1, rect->height);
- rect->x = MAX (rect->x + original_width - rect->width, 0);
- rect->y = MAX (rect->y + original_height - rect->height, 0);
+ if (impl->mapped)
+ return;
+
+ parent = surface->parent;
+ if (!parent)
+ {
+ g_warning ("Couldn't map as surface %p as popup because it doesn't have a parent",
+ surface);
+ return;
+ }
+
+ if (surface->autohide)
+ grab_input_seat = find_grab_input_seat (surface, parent);
+ else
+ grab_input_seat = NULL;
+ gdk_wayland_surface_create_xdg_popup (surface,
+ parent,
+ grab_input_seat,
+ width, height,
+ layout);
+
+ impl->popup.layout = gdk_popup_layout_copy (layout);
+ impl->popup.unconstrained_width = width;
+ impl->popup.unconstrained_height = height;
+ impl->mapped = TRUE;
}
static void
-gdk_wayland_surface_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)
+show_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
- impl->pending_move_to_rect.rect = *rect;
- sanitize_anchor_rect (surface, &impl->pending_move_to_rect.rect);
+ if (!impl->display_server.wl_surface)
+ gdk_wayland_surface_create_surface (surface);
+
+ gdk_wayland_surface_map_popup (surface, width, height, layout);
+}
- impl->pending_move_to_rect.rect_anchor = rect_anchor;
- impl->pending_move_to_rect.surface_anchor = surface_anchor;
- impl->pending_move_to_rect.anchor_hints = anchor_hints;
- impl->pending_move_to_rect.rect_anchor_dx = rect_anchor_dx;
- impl->pending_move_to_rect.rect_anchor_dy = rect_anchor_dy;
+typedef struct
+{
+ int width;
+ int height;
+ GdkPopupLayout *layout;
+} GrabPrepareData;
+
+static void
+show_grabbing_popup (GdkSeat *seat,
+ GdkSurface *surface,
+ gpointer user_data)
+{
+ GrabPrepareData *data = user_data;
- impl->has_layout_data = TRUE;
+ show_popup (surface, data->width, data->height, data->layout);
+}
+
+static void
+reposition_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
+{
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+
+ switch (impl->popup_state)
+ {
+ case POPUP_STATE_IDLE:
+ case POPUP_STATE_WAITING_FOR_FRAME:
+ do_queue_relayout (surface, width, height, layout);
+ break;
+ case POPUP_STATE_WAITING_FOR_CONFIGURE:
+ g_warn_if_reached ();
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static gboolean
+gdk_wayland_surface_present_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
+{
+ GdkWaylandDisplay *display_wayland =
+ GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+ GdkWaylandSurface *impl;
+
+ g_return_val_if_fail (should_map_as_popup (surface), FALSE);
+
+ impl = GDK_WAYLAND_SURFACE (surface);
+
+ if (!impl->mapped)
+ {
+ if (surface->autohide)
+ {
+ GrabPrepareData data;
+
+ data = (GrabPrepareData) {
+ .width = width,
+ .height = height,
+ .layout = layout,
+ };
+ gdk_seat_grab (gdk_display_get_default_seat (surface->display),
+ surface,
+ GDK_SEAT_CAPABILITY_ALL,
+ TRUE,
+ NULL, NULL,
+ show_grabbing_popup, &data);
+ }
+ else
+ {
+ show_popup (surface, width, height, layout);
+ }
+ }
+ else
+ {
+ reposition_popup (surface, width, height, layout);
+ }
+
+ while (impl->display_server.xdg_popup && !is_relayout_finished (surface))
+ wl_display_dispatch_queue (display_wayland->wl_display, impl->event_queue);
+
+ if (impl->display_server.xdg_popup)
+ {
+ gdk_synthesize_surface_state (surface, GDK_SURFACE_STATE_WITHDRAWN, 0);
+ gdk_surface_invalidate_rect (surface, NULL);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
}
static void
@@ -3697,7 +3897,7 @@ gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *klass)
impl_class->lower = gdk_wayland_surface_lower;
impl_class->restack_toplevel = gdk_wayland_surface_restack_toplevel;
impl_class->toplevel_resize = gdk_wayland_surface_toplevel_resize;
- impl_class->move_to_rect = gdk_wayland_surface_move_to_rect;
+ impl_class->present_popup = gdk_wayland_surface_present_popup;
impl_class->get_geometry = gdk_wayland_surface_get_geometry;
impl_class->get_root_coords = gdk_wayland_surface_get_root_coords;
impl_class->get_device_state = gdk_wayland_surface_get_device_state;
diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c
index eda9325bd5..d662b1059e 100644
--- a/gdk/win32/gdksurface-win32.c
+++ b/gdk/win32/gdksurface-win32.c
@@ -1289,18 +1289,21 @@ gdk_win32_surface_move (GdkSurface *surface,
}
static void
-gdk_win32_surface_moved_to_rect (GdkSurface *surface,
- GdkRectangle final_rect)
+gdk_win32_surface_layout_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
{
- GdkSurface *toplevel;
+ GdkRectangle final_rect;
int x, y;
- if (surface->surface_type == GDK_SURFACE_POPUP)
- toplevel = surface->parent;
- else
- toplevel = surface->transient_for;
+ gdk_surface_layout_popup_helper (surface,
+ width,
+ height,
+ layout,
+ &final_rect);
- gdk_surface_get_origin (toplevel, &x, &y);
+ gdk_surface_get_origin (surface->parent, &x, &y);
x += final_rect.x;
y += final_rect.y;
@@ -1308,8 +1311,10 @@ gdk_win32_surface_moved_to_rect (GdkSurface *surface,
final_rect.height != surface->height)
{
gdk_win32_surface_move_resize (surface,
- x, y,
- final_rect.width, final_rect.height);
+ x,
+ y,
+ final_rect.width,
+ final_rect.height);
}
else
{
@@ -1318,22 +1323,49 @@ gdk_win32_surface_moved_to_rect (GdkSurface *surface,
}
static void
-gdk_win32_surface_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)
+show_popup (GdkSurface *surface)
+{
+ gdk_surface_raise (surface);
+ gdk_synthesize_surface_state (surface, GDK_SURFACE_STATE_WITHDRAWN, 0);
+ _gdk_surface_update_viewable (surface);
+ show_window_internal (surface, FALSE, FALSE);
+ gdk_surface_invalidate_rect (surface, NULL);
+}
+
+static void
+show_grabbing_popup (GdkSeat *seat,
+ GdkSurface *surface,
+ gpointer user_data)
+{
+ show_popup (surface);
+}
+
+static gboolean
+gdk_win32_surface_present_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
{
- gdk_surface_move_to_rect_helper (surface,
- rect,
- rect_anchor,
- surface_anchor,
- anchor_hints,
- rect_anchor_dx,
- rect_anchor_dy,
- gdk_win32_surface_moved_to_rect);
+ gdk_win32_surface_layout_popup (surface, width, height, layout);
+
+ if (GDK_SURFACE_IS_MAPPED (surface))
+ return TRUE;
+
+ if (surface->autohide)
+ {
+ gdk_seat_grab (gdk_display_get_default_seat (surface->display),
+ surface,
+ GDK_SEAT_CAPABILITY_ALL,
+ TRUE,
+ NULL, NULL,
+ show_grabbing_popup, NULL);
+ }
+ else
+ {
+ show_popup (surface);
+ }
+
+ return GDK_SURFACE_IS_MAPPED (surface);
}
static void
@@ -5161,7 +5193,7 @@ gdk_win32_surface_class_init (GdkWin32SurfaceClass *klass)
impl_class->lower = gdk_win32_surface_lower;
impl_class->restack_toplevel = gdk_win32_surface_restack_toplevel;
impl_class->toplevel_resize = gdk_win32_surface_toplevel_resize;
- impl_class->move_to_rect = gdk_win32_surface_move_to_rect;
+ impl_class->present_popup = gdk_win32_surface_present_popup;
impl_class->get_geometry = gdk_win32_surface_get_geometry;
impl_class->get_device_state = gdk_surface_win32_get_device_state;
impl_class->get_root_coords = gdk_win32_surface_get_root_coords;
diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c
index b9e122a91a..3ddad661f6 100644
--- a/gdk/x11/gdksurface-x11.c
+++ b/gdk/x11/gdksurface-x11.c
@@ -1416,18 +1416,21 @@ gdk_x11_surface_move (GdkSurface *surface,
}
static void
-gdk_x11_surface_moved_to_rect (GdkSurface *surface,
- GdkRectangle final_rect)
+gdk_x11_surface_layout_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
{
- GdkSurface *toplevel;
+ GdkRectangle final_rect;
int x, y;
- if (surface->surface_type == GDK_SURFACE_POPUP)
- toplevel = surface->parent;
- else
- toplevel = surface->transient_for;
+ gdk_surface_layout_popup_helper (surface,
+ width,
+ height,
+ layout,
+ &final_rect);
- gdk_surface_get_origin (toplevel, &x, &y);
+ gdk_surface_get_origin (surface->parent, &x, &y);
x += final_rect.x;
y += final_rect.y;
@@ -1436,8 +1439,10 @@ gdk_x11_surface_moved_to_rect (GdkSurface *surface,
{
gdk_x11_surface_move_resize (surface,
TRUE,
- x, y,
- final_rect.width, final_rect.height);
+ x,
+ y,
+ final_rect.width,
+ final_rect.height);
}
else
{
@@ -1446,22 +1451,49 @@ gdk_x11_surface_moved_to_rect (GdkSurface *surface,
}
static void
-gdk_x11_surface_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)
-{
- gdk_surface_move_to_rect_helper (surface,
- rect,
- rect_anchor,
- surface_anchor,
- anchor_hints,
- rect_anchor_dx,
- rect_anchor_dy,
- gdk_x11_surface_moved_to_rect);
+show_popup (GdkSurface *surface)
+{
+ gdk_surface_raise (surface);
+ gdk_synthesize_surface_state (surface, GDK_SURFACE_STATE_WITHDRAWN, 0);
+ _gdk_surface_update_viewable (surface);
+ gdk_x11_surface_show (surface, FALSE);
+ gdk_surface_invalidate_rect (surface, NULL);
+}
+
+static void
+show_grabbing_popup (GdkSeat *seat,
+ GdkSurface *surface,
+ gpointer user_data)
+{
+ show_popup (surface);
+}
+
+static gboolean
+gdk_x11_surface_present_popup (GdkSurface *surface,
+ int width,
+ int height,
+ GdkPopupLayout *layout)
+{
+ gdk_x11_surface_layout_popup (surface, width, height, layout);
+
+ if (GDK_SURFACE_IS_MAPPED (surface))
+ return TRUE;
+
+ if (surface->autohide)
+ {
+ gdk_seat_grab (gdk_display_get_default_seat (surface->display),
+ surface,
+ GDK_SEAT_CAPABILITY_ALL,
+ TRUE,
+ NULL, NULL,
+ show_grabbing_popup, NULL);
+ }
+ else
+ {
+ show_popup (surface);
+ }
+
+ return GDK_SURFACE_IS_MAPPED (surface);
}
static void gdk_x11_surface_restack_toplevel (GdkSurface *surface,
@@ -4659,7 +4691,7 @@ gdk_x11_surface_class_init (GdkX11SurfaceClass *klass)
impl_class->lower = gdk_x11_surface_lower;
impl_class->restack_toplevel = gdk_x11_surface_restack_toplevel;
impl_class->toplevel_resize = gdk_x11_surface_toplevel_resize;
- impl_class->move_to_rect = gdk_x11_surface_move_to_rect;
+ impl_class->present_popup = gdk_x11_surface_present_popup;
impl_class->get_geometry = gdk_x11_surface_get_geometry;
impl_class->get_root_coords = gdk_x11_surface_get_root_coords;
impl_class->get_device_state = gdk_x11_surface_get_device_state;
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index b626a3fbd6..a5285a2766 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -155,6 +155,7 @@ typedef struct {
GtkCssNode *arrow_node;
GskRenderNode *arrow_render_node;
+ GdkPopupLayout *layout;
GdkRectangle final_rect;
GtkPositionType final_position;
} GtkPopoverPrivate;
@@ -221,14 +222,200 @@ gtk_popover_native_get_surface_transform (GtkNative *native,
_gtk_css_number_value_get (style->size->padding_top, 100);
}
+static gboolean
+is_gravity_facing_north (GdkGravity gravity)
+{
+ switch (gravity)
+ {
+ case GDK_GRAVITY_NORTH_EAST:
+ case GDK_GRAVITY_NORTH:
+ case GDK_GRAVITY_NORTH_WEST:
+ case GDK_GRAVITY_STATIC:
+ return TRUE;
+ case GDK_GRAVITY_SOUTH_WEST:
+ case GDK_GRAVITY_WEST:
+ case GDK_GRAVITY_SOUTH_EAST:
+ case GDK_GRAVITY_EAST:
+ case GDK_GRAVITY_CENTER:
+ case GDK_GRAVITY_SOUTH:
+ return FALSE;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static gboolean
+is_gravity_facing_south (GdkGravity gravity)
+{
+ switch (gravity)
+ {
+ case GDK_GRAVITY_SOUTH_WEST:
+ case GDK_GRAVITY_SOUTH_EAST:
+ case GDK_GRAVITY_SOUTH:
+ return TRUE;
+ case GDK_GRAVITY_NORTH_EAST:
+ case GDK_GRAVITY_NORTH:
+ case GDK_GRAVITY_NORTH_WEST:
+ case GDK_GRAVITY_STATIC:
+ case GDK_GRAVITY_WEST:
+ case GDK_GRAVITY_EAST:
+ case GDK_GRAVITY_CENTER:
+ return FALSE;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static gboolean
+is_gravity_facing_west (GdkGravity gravity)
+{
+ switch (gravity)
+ {
+ case GDK_GRAVITY_NORTH_WEST:
+ case GDK_GRAVITY_STATIC:
+ case GDK_GRAVITY_SOUTH_WEST:
+ case GDK_GRAVITY_WEST:
+ return TRUE;
+ case GDK_GRAVITY_NORTH_EAST:
+ case GDK_GRAVITY_SOUTH_EAST:
+ case GDK_GRAVITY_EAST:
+ case GDK_GRAVITY_NORTH:
+ case GDK_GRAVITY_CENTER:
+ case GDK_GRAVITY_SOUTH:
+ return FALSE;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static gboolean
+is_gravity_facing_east (GdkGravity gravity)
+{
+ switch (gravity)
+ {
+ case GDK_GRAVITY_NORTH_EAST:
+ case GDK_GRAVITY_SOUTH_EAST:
+ case GDK_GRAVITY_EAST:
+ return TRUE;
+ case GDK_GRAVITY_NORTH_WEST:
+ case GDK_GRAVITY_STATIC:
+ case GDK_GRAVITY_SOUTH_WEST:
+ case GDK_GRAVITY_WEST:
+ case GDK_GRAVITY_NORTH:
+ case GDK_GRAVITY_CENTER:
+ case GDK_GRAVITY_SOUTH:
+ return FALSE;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static gboolean
+did_flip_horizontally (GdkGravity original_gravity,
+ GdkGravity final_gravity)
+{
+ g_return_val_if_fail (original_gravity, FALSE);
+ g_return_val_if_fail (final_gravity, FALSE);
+
+ if (is_gravity_facing_east (original_gravity) &&
+ is_gravity_facing_west (final_gravity))
+ return TRUE;
+
+ if (is_gravity_facing_west (original_gravity) &&
+ is_gravity_facing_east (final_gravity))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+did_flip_vertically (GdkGravity original_gravity,
+ GdkGravity final_gravity)
+{
+ g_return_val_if_fail (original_gravity, FALSE);
+ g_return_val_if_fail (final_gravity, FALSE);
+
+ if (is_gravity_facing_north (original_gravity) &&
+ is_gravity_facing_south (final_gravity))
+ return TRUE;
+
+ if (is_gravity_facing_south (original_gravity) &&
+ is_gravity_facing_north (final_gravity))
+ return TRUE;
+
+ return FALSE;
+}
+
static void
-move_to_rect (GtkPopover *popover)
+update_popover_layout (GtkPopover *popover,
+ GdkPopupLayout *layout)
+{
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+ GdkRectangle final_rect;
+ gboolean flipped_x;
+ gboolean flipped_y;
+
+ g_clear_pointer (&priv->layout, gdk_popup_layout_unref);
+ priv->layout = layout;
+
+ final_rect = (GdkRectangle) {
+ .width = gdk_surface_get_width (priv->surface),
+ .height = gdk_surface_get_height (priv->surface),
+ };
+ gdk_surface_get_position (priv->surface,
+ &final_rect.x,
+ &final_rect.y);
+
+ flipped_x =
+ did_flip_horizontally (gdk_popup_layout_get_rect_anchor (layout),
+ gdk_surface_get_popup_rect_anchor (priv->surface)) &&
+ did_flip_horizontally (gdk_popup_layout_get_surface_anchor (layout),
+ gdk_surface_get_popup_surface_anchor (priv->surface));
+ flipped_y =
+ did_flip_vertically (gdk_popup_layout_get_rect_anchor (layout),
+ gdk_surface_get_popup_rect_anchor (priv->surface)) &&
+ did_flip_vertically (gdk_popup_layout_get_surface_anchor (layout),
+ gdk_surface_get_popup_surface_anchor (priv->surface));
+
+ gtk_widget_allocate (GTK_WIDGET (popover),
+ gdk_surface_get_width (priv->surface),
+ gdk_surface_get_height (priv->surface),
+ -1, NULL);
+
+ priv->final_rect = final_rect;
+
+ switch (priv->position)
+ {
+ case GTK_POS_LEFT:
+ priv->final_position = flipped_x ? GTK_POS_RIGHT : GTK_POS_LEFT;
+ break;
+ case GTK_POS_RIGHT:
+ priv->final_position = flipped_x ? GTK_POS_LEFT : GTK_POS_RIGHT;
+ break;
+ case GTK_POS_TOP:
+ priv->final_position = flipped_y ? GTK_POS_BOTTOM : GTK_POS_TOP;
+ break;
+ case GTK_POS_BOTTOM:
+ priv->final_position = flipped_y ? GTK_POS_TOP : GTK_POS_BOTTOM;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ g_clear_pointer (&priv->arrow_render_node, gsk_render_node_unref);
+ gtk_widget_queue_draw (GTK_WIDGET (popover));
+}
+
+static GdkPopupLayout *
+create_popup_layout (GtkPopover *popover)
{
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
GdkRectangle rect;
GdkGravity parent_anchor;
GdkGravity surface_anchor;
GdkAnchorHints anchor_hints;
+ GdkPopupLayout *layout;
gtk_widget_get_surface_allocation (priv->relative_to, &rect);
if (priv->has_pointing_to)
@@ -341,46 +528,39 @@ move_to_rect (GtkPopover *popover)
g_assert_not_reached ();
}
- gdk_surface_move_to_rect (priv->surface,
- &rect,
- parent_anchor,
- surface_anchor,
- anchor_hints,
- 0, 0);
+ layout = gdk_popup_layout_new (&rect,
+ parent_anchor,
+ surface_anchor);
+ gdk_popup_layout_set_anchor_hints (layout, anchor_hints);
+
+ return layout;
}
static void
-gtk_popover_move_resize (GtkPopover *popover)
+present_popup (GtkPopover *popover)
{
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
GtkRequisition req;
+ GdkPopupLayout *layout;
- if (priv->surface)
- {
- gtk_widget_get_preferred_size (GTK_WIDGET (popover), NULL, &req);
- gdk_surface_resize (priv->surface, req.width, req.height);
- move_to_rect (popover);
- }
+ layout = create_popup_layout (popover);
+ gtk_widget_get_preferred_size (GTK_WIDGET (popover), NULL, &req);
+ if (gdk_surface_present_popup (priv->surface,
+ req.width, req.height,
+ layout))
+ update_popover_layout (popover, layout);
}
static void
gtk_popover_native_check_resize (GtkNative *native)
{
GtkPopover *popover = GTK_POPOVER (native);
- GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
GtkWidget *widget = GTK_WIDGET (popover);
if (!_gtk_widget_get_alloc_needed (widget))
gtk_widget_ensure_allocate (widget);
else if (gtk_widget_get_visible (widget))
- {
- gtk_popover_move_resize (popover);
- if (priv->surface)
- gtk_widget_allocate (GTK_WIDGET (popover),
- gdk_surface_get_width (priv->surface),
- gdk_surface_get_height (priv->surface),
- -1, NULL);
- }
+ present_popup (popover);
}
@@ -436,7 +616,8 @@ surface_state_changed (GtkWidget *widget)
if (changed_mask & GDK_SURFACE_STATE_WITHDRAWN)
{
- if (priv->state & GDK_SURFACE_STATE_WITHDRAWN)
+ if (priv->state & GDK_SURFACE_STATE_WITHDRAWN &&
+ gtk_widget_is_visible (widget))
gtk_widget_hide (widget);
}
}
@@ -467,36 +648,13 @@ surface_event (GdkSurface *surface,
}
static void
-surface_moved_to_rect (GdkSurface *surface,
- GdkRectangle *flipped_rect,
- GdkRectangle *final_rect,
- gboolean flipped_x,
- gboolean flipped_y,
- GtkWidget *widget)
+popup_layout_changed (GdkSurface *surface,
+ GtkWidget *widget)
{
GtkPopover *popover = GTK_POPOVER (widget);
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- priv->final_rect = *final_rect;
-
- switch (priv->position)
- {
- case GTK_POS_LEFT:
- priv->final_position = flipped_x ? GTK_POS_RIGHT : GTK_POS_LEFT;
- break;
- case GTK_POS_RIGHT:
- priv->final_position = flipped_x ? GTK_POS_LEFT : GTK_POS_RIGHT;
- break;
- case GTK_POS_TOP:
- priv->final_position = flipped_y ? GTK_POS_BOTTOM : GTK_POS_TOP;
- break;
- case GTK_POS_BOTTOM:
- priv->final_position = flipped_y ? GTK_POS_TOP : GTK_POS_BOTTOM;
- break;
- default:
- g_assert_not_reached ();
- break;
- }
+ update_popover_layout (popover, gdk_popup_layout_ref (priv->layout));
}
static void
@@ -612,7 +770,7 @@ gtk_popover_realize (GtkWidget *widget)
g_signal_connect_swapped (priv->surface, "size-changed", G_CALLBACK (surface_size_changed), widget);
g_signal_connect (priv->surface, "render", G_CALLBACK (surface_render), widget);
g_signal_connect (priv->surface, "event", G_CALLBACK (surface_event), widget);
- g_signal_connect (priv->surface, "moved-to-rect", G_CALLBACK (surface_moved_to_rect), widget);
+ g_signal_connect (priv->surface, "popup-layout-changed", G_CALLBACK (popup_layout_changed), widget);
GTK_WIDGET_CLASS (gtk_popover_parent_class)->realize (widget);
@@ -634,7 +792,7 @@ gtk_popover_unrealize (GtkWidget *widget)
g_signal_handlers_disconnect_by_func (priv->surface, surface_size_changed, widget);
g_signal_handlers_disconnect_by_func (priv->surface, surface_render, widget);
g_signal_handlers_disconnect_by_func (priv->surface, surface_event, widget);
- g_signal_handlers_disconnect_by_func (priv->surface, surface_moved_to_rect, widget);
+ g_signal_handlers_disconnect_by_func (priv->surface, popup_layout_changed, widget);
gdk_surface_set_widget (priv->surface, NULL);
gdk_surface_destroy (priv->surface);
g_clear_object (&priv->surface);
@@ -648,7 +806,7 @@ gtk_popover_show (GtkWidget *widget)
_gtk_widget_set_visible_flag (widget, TRUE);
gtk_widget_realize (widget);
- gtk_popover_native_check_resize (GTK_NATIVE (widget));
+ present_popup (popover);
gtk_widget_map (widget);
if (priv->autohide)
@@ -683,8 +841,8 @@ surface_transform_changed_cb (GtkWidget *widget,
GtkPopover *popover = user_data;
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
- move_to_rect (popover);
- g_clear_pointer (&priv->arrow_render_node, gsk_render_node_unref);
+ if (priv->surface && gdk_surface_is_visible (priv->surface))
+ present_popup (popover);
return G_SOURCE_CONTINUE;
}
@@ -696,8 +854,7 @@ gtk_popover_map (GtkWidget *widget)
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
GtkWidget *child;
- gdk_surface_show (priv->surface);
- move_to_rect (popover);
+ present_popup (popover);
priv->surface_transform_changed_cb =
gtk_widget_add_surface_transform_changed_callback (priv->relative_to,
@@ -755,6 +912,11 @@ gtk_popover_dispose (GObject *object)
static void
gtk_popover_finalize (GObject *object)
{
+ GtkPopover *popover = GTK_POPOVER (object);
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
+ g_clear_pointer (&priv->layout, gdk_popup_layout_unref);
+
G_OBJECT_CLASS (gtk_popover_parent_class)->finalize (object);
}
@@ -1096,8 +1258,6 @@ gtk_popover_size_allocate (GtkWidget *widget,
GtkAllocation child_alloc;
int tail_height = priv->has_arrow ? TAIL_HEIGHT : 0;
- gtk_popover_move_resize (popover);
-
switch (priv->final_position)
{
case GTK_POS_TOP:
@@ -1414,13 +1574,16 @@ gtk_popover_new (GtkWidget *relative_to)
}
static void
-size_changed (GtkWidget *widget,
- int width,
- int height,
- int baseline,
- GtkPopover *popover)
+relative_to_size_changed (GtkWidget *widget,
+ int width,
+ int height,
+ int baseline,
+ GtkPopover *popover)
{
- gtk_popover_move_resize (popover);
+ GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+
+ if (priv->surface && gdk_surface_is_visible (priv->surface))
+ present_popup (popover);
}
void
@@ -1487,7 +1650,9 @@ gtk_popover_set_relative_to (GtkPopover *popover,
if (priv->relative_to)
{
- g_signal_handlers_disconnect_by_func (priv->relative_to, size_changed, popover);
+ g_signal_handlers_disconnect_by_func (priv->relative_to,
+ relative_to_size_changed,
+ popover);
gtk_widget_unparent (GTK_WIDGET (popover));
}
@@ -1496,7 +1661,7 @@ gtk_popover_set_relative_to (GtkPopover *popover,
if (priv->relative_to)
{
g_signal_connect_object (priv->relative_to, "size-allocate",
- G_CALLBACK (size_changed), popover, 0);
+ G_CALLBACK (relative_to_size_changed), popover, 0);
gtk_css_node_set_parent (gtk_widget_get_css_node (GTK_WIDGET (popover)),
gtk_widget_get_css_node (relative_to));
gtk_widget_set_parent (GTK_WIDGET (popover), relative_to);
diff --git a/gtk/gtktooltipwindow.c b/gtk/gtktooltipwindow.c
index a80c8034c5..73fc24e625 100644
--- a/gtk/gtktooltipwindow.c
+++ b/gtk/gtktooltipwindow.c
@@ -110,16 +110,34 @@ gtk_tooltip_window_native_get_surface_transform (GtkNative *native,
*y = margin.top + border.top + padding.top;
}
+static GdkPopupLayout *
+create_popup_layout (GtkTooltipWindow *window)
+{
+ GdkPopupLayout *layout;
+
+ layout = gdk_popup_layout_new (&window->rect,
+ window->rect_anchor,
+ window->surface_anchor);
+ gdk_popup_layout_set_anchor_hints (layout, window->anchor_hints);
+ gdk_popup_layout_set_offset (layout, window->dx, window->dy);
+
+ return layout;
+}
+
static void
-move_to_rect (GtkTooltipWindow *window)
+relayout_popup (GtkTooltipWindow *window)
{
- gdk_surface_move_to_rect (window->surface,
- &window->rect,
- window->rect_anchor,
- window->surface_anchor,
- window->anchor_hints,
- window->dx,
- window->dy);
+ GdkPopupLayout *layout;
+
+ if (!gtk_widget_get_visible (GTK_WIDGET (window)))
+ return;
+
+ layout = create_popup_layout (window);
+ gdk_surface_present_popup (window->surface,
+ gdk_surface_get_width (window->surface),
+ gdk_surface_get_height (window->surface),
+ layout);
+ gdk_popup_layout_unref (layout);
}
static void
@@ -131,7 +149,8 @@ gtk_tooltip_window_move_resize (GtkTooltipWindow *window)
{
gtk_widget_get_preferred_size (GTK_WIDGET (window), NULL, &req);
gdk_surface_resize (window->surface, req.width, req.height);
- move_to_rect (window);
+
+ relayout_popup (window);
}
}
@@ -206,16 +225,6 @@ surface_event (GdkSurface *surface,
return TRUE;
}
-static void
-surface_moved_to_rect (GdkSurface *surface,
- GdkRectangle *flipped_rect,
- GdkRectangle *final_rect,
- gboolean flipped_x,
- gboolean flipped_y,
- GtkWidget *widget)
-{
-}
-
static void
gtk_tooltip_window_realize (GtkWidget *widget)
{
@@ -234,7 +243,6 @@ gtk_tooltip_window_realize (GtkWidget *widget)
g_signal_connect_swapped (window->surface, "size-changed", G_CALLBACK (surface_size_changed), widget);
g_signal_connect (window->surface, "render", G_CALLBACK (surface_render), widget);
g_signal_connect (window->surface, "event", G_CALLBACK (surface_event), widget);
- g_signal_connect (window->surface, "moved-to-rect", G_CALLBACK (surface_moved_to_rect), widget);
GTK_WIDGET_CLASS (gtk_tooltip_window_parent_class)->realize (widget);
@@ -255,7 +263,6 @@ gtk_tooltip_window_unrealize (GtkWidget *widget)
g_signal_handlers_disconnect_by_func (window->surface, surface_size_changed, widget);
g_signal_handlers_disconnect_by_func (window->surface, surface_render, widget);
g_signal_handlers_disconnect_by_func (window->surface, surface_event, widget);
- g_signal_handlers_disconnect_by_func (window->surface, surface_moved_to_rect, widget);
gdk_surface_set_widget (window->surface, NULL);
gdk_surface_destroy (window->surface);
g_clear_object (&window->surface);
@@ -277,7 +284,7 @@ surface_transform_changed_cb (GtkWidget *widget,
{
GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget);
- move_to_rect (window);
+ relayout_popup (window);
return G_SOURCE_CONTINUE;
}
@@ -287,10 +294,15 @@ static void
gtk_tooltip_window_map (GtkWidget *widget)
{
GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget);
+ GdkPopupLayout *layout;
GtkWidget *child;
- gdk_surface_show (window->surface);
- move_to_rect (window);
+ layout = create_popup_layout (window);
+ gdk_surface_present_popup (window->surface,
+ gdk_surface_get_width (window->surface),
+ gdk_surface_get_height (window->surface),
+ layout);
+ gdk_popup_layout_unref (layout);
window->surface_transform_changed_cb =
gtk_widget_add_surface_transform_changed_callback (window->relative_to,
@@ -599,6 +611,6 @@ gtk_tooltip_window_position (GtkTooltipWindow *window,
window->dx = dx;
window->dy = dy;
- move_to_rect (window);
+ relayout_popup (window);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]