[gtk: 2/7] wayland: Move popups with xdg_popup.reposition
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk: 2/7] wayland: Move popups with xdg_popup.reposition
- Date: Wed, 8 Apr 2020 23:59:40 +0000 (UTC)
commit 5425edff8282ac965888468aff31470d13ce8cd8
Author: Jonas Ã…dahl <jadahl gmail com>
Date: Sun Feb 16 20:09:42 2020 +0100
wayland: Move popups with xdg_popup.reposition
The third version of xdg-shell introduces support for explicit popup
repositioning. If available, make use of this to implement popup
repositioning.
Note that this does *NOT* include atomic parent-child state
synchronization. For that,
https://gitlab.freedesktop.org/wayland/wayland-protocols/issues/13 will
be needed.
This currently uses my own fork of wayland-protocols which adds meson
support, so that we can use it as a subproject. Eventually when
wayland-protocols' meson support lands upstream, we should change it to
point there.
Silence some meson warnings while at it to make CI happy.
This also bumps the glib requirement, since g_warning_once() is used.
gdk/wayland/gdkdisplay-wayland.c | 4 +-
gdk/wayland/gdkdisplay-wayland.h | 1 +
gdk/wayland/gdksurface-wayland.c | 122 ++++++++++++++++++++++++++++++++++++-
gdk/wayland/meson.build | 10 +--
gtk/meson.build | 4 +-
meson.build | 14 +++--
subprojects/wayland-protocols.wrap | 4 ++
7 files changed, 142 insertions(+), 17 deletions(-)
---
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 76596da719..dc8c52f305 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -431,6 +431,7 @@ gdk_registry_handle_global (void *data,
else if (strcmp (interface, "xdg_wm_base") == 0)
{
display_wayland->xdg_wm_base_id = id;
+ display_wayland->xdg_wm_base_version = version;
}
else if (strcmp (interface, "zxdg_shell_v6") == 0)
{
@@ -659,7 +660,8 @@ _gdk_wayland_display_open (const gchar *display_name)
display_wayland->xdg_wm_base =
wl_registry_bind (display_wayland->wl_registry,
display_wayland->xdg_wm_base_id,
- &xdg_wm_base_interface, 1);
+ &xdg_wm_base_interface,
+ MIN (display_wayland->xdg_wm_base_version, 3));
xdg_wm_base_add_listener (display_wayland->xdg_wm_base,
&xdg_wm_base_listener,
display_wayland);
diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h
index 4313ac3b17..db4b3efe41 100644
--- a/gdk/wayland/gdkdisplay-wayland.h
+++ b/gdk/wayland/gdkdisplay-wayland.h
@@ -86,6 +86,7 @@ struct _GdkWaylandDisplay
guint32 serial;
uint32_t xdg_wm_base_id;
+ int xdg_wm_base_version;
uint32_t zxdg_shell_v6_id;
GdkWaylandShellVariant shell_variant;
diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c
index 6947fe0b9e..5e734e6ecd 100644
--- a/gdk/wayland/gdksurface-wayland.c
+++ b/gdk/wayland/gdksurface-wayland.c
@@ -59,6 +59,7 @@ static guint signals[LAST_SIGNAL];
typedef enum _PopupState
{
POPUP_STATE_IDLE,
+ POPUP_STATE_WAITING_FOR_REPOSITIONED,
POPUP_STATE_WAITING_FOR_CONFIGURE,
POPUP_STATE_WAITING_FOR_FRAME,
} PopupState;
@@ -94,6 +95,9 @@ struct _GdkWaylandSurface
EGLSurface egl_surface;
EGLSurface dummy_egl_surface;
+ uint32_t reposition_token;
+ uint32_t received_reposition_token;
+
PopupState popup_state;
unsigned int initial_configure_received : 1;
@@ -167,12 +171,18 @@ struct _GdkWaylandSurface
int y;
int width;
int height;
+ uint32_t repositioned_token;
+ gboolean has_repositioned_token;
} popup;
+ gboolean is_initial_configure;
+
uint32_t serial;
gboolean is_dirty;
} pending;
+ uint32_t last_configure_serial;
+
int state_freeze_count;
struct {
@@ -438,6 +448,7 @@ frame_callback (void *data,
switch (impl->popup_state)
{
case POPUP_STATE_IDLE:
+ case POPUP_STATE_WAITING_FOR_REPOSITIONED:
case POPUP_STATE_WAITING_FOR_CONFIGURE:
break;
case POPUP_STATE_WAITING_FOR_FRAME:
@@ -1282,8 +1293,17 @@ gdk_wayland_surface_configure_popup (GdkSurface *surface)
impl->pending.serial);
}
+ if (impl->pending.popup.has_repositioned_token)
+ impl->received_reposition_token = impl->pending.popup.repositioned_token;
+
switch (impl->popup_state)
{
+ case POPUP_STATE_WAITING_FOR_REPOSITIONED:
+ if (impl->received_reposition_token != impl->reposition_token)
+ return;
+ else
+ gdk_surface_thaw_updates (surface);
+ G_GNUC_FALLTHROUGH;
case POPUP_STATE_WAITING_FOR_CONFIGURE:
impl->popup_state = POPUP_STATE_WAITING_FOR_FRAME;
break;
@@ -1306,6 +1326,10 @@ gdk_wayland_surface_configure_popup (GdkSurface *surface)
width, height,
impl->popup.layout);
+ if (!impl->pending.popup.has_repositioned_token &&
+ !impl->pending.is_initial_configure)
+ g_signal_emit_by_name (surface, "popup-layout-changed");
+
gdk_surface_invalidate_rect (surface, NULL);
}
@@ -1318,6 +1342,7 @@ gdk_wayland_surface_configure (GdkSurface *surface)
{
gdk_surface_thaw_updates (surface);
impl->initial_configure_received = TRUE;
+ impl->pending.is_initial_configure = TRUE;
}
if (is_realized_popup (surface))
@@ -1327,6 +1352,8 @@ gdk_wayland_surface_configure (GdkSurface *surface)
else
g_warn_if_reached ();
+ impl->last_configure_serial = impl->pending.serial;
+
memset (&impl->pending, 0, sizeof (impl->pending));
}
@@ -1663,9 +1690,31 @@ xdg_popup_done (void *data,
gdk_surface_hide (surface);
}
+static void
+xdg_popup_repositioned (void *data,
+ struct xdg_popup *xdg_popup,
+ uint32_t token)
+{
+ GdkSurface *surface = GDK_SURFACE (data);
+ GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+
+ GDK_DISPLAY_NOTE (gdk_surface_get_display (surface), EVENTS,
+ g_message ("repositioned %p", surface));
+
+ if (impl->popup_state != POPUP_STATE_WAITING_FOR_REPOSITIONED)
+ {
+ g_warning ("Unexpected xdg_popup.repositioned event, probably buggy compositor");
+ return;
+ }
+
+ impl->pending.popup.repositioned_token = token;
+ impl->pending.popup.has_repositioned_token = TRUE;
+}
+
static const struct xdg_popup_listener xdg_popup_listener = {
xdg_popup_configure,
xdg_popup_done,
+ xdg_popup_repositioned,
};
static void
@@ -2052,7 +2101,8 @@ static gpointer
create_dynamic_positioner (GdkSurface *surface,
int width,
int height,
- GdkPopupLayout *layout)
+ GdkPopupLayout *layout,
+ gboolean ack_parent_configure)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
GdkSurface *parent = surface->parent;
@@ -2129,6 +2179,30 @@ create_dynamic_positioner (GdkSurface *surface,
xdg_positioner_set_constraint_adjustment (positioner,
constraint_adjustment);
+ if (xdg_positioner_get_version (positioner) >=
+ XDG_POSITIONER_SET_REACTIVE_SINCE_VERSION)
+ xdg_positioner_set_reactive (positioner);
+
+ if (ack_parent_configure &&
+ xdg_positioner_get_version (positioner) >=
+ XDG_POSITIONER_SET_PARENT_CONFIGURE_SINCE_VERSION)
+ {
+ GdkWaylandSurface *parent_impl = GDK_WAYLAND_SURFACE (parent);
+ int parent_width;
+ int parent_height;
+
+ parent_width = parent->width - (parent_impl->margin_left +
+ parent_impl->margin_right);
+ parent_height = parent->height - (parent_impl->margin_top +
+ parent_impl->margin_bottom);
+
+ xdg_positioner_set_parent_size (positioner,
+ parent_width,
+ parent_height);
+ xdg_positioner_set_parent_configure (positioner,
+ parent_impl->last_configure_serial);
+ }
+
return positioner;
}
case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
@@ -2233,7 +2307,7 @@ gdk_wayland_surface_create_xdg_popup (GdkSurface *surface,
gdk_surface_freeze_updates (surface);
- positioner = create_dynamic_positioner (surface, width, height, layout);
+ positioner = create_dynamic_positioner (surface, width, height, layout, FALSE);
switch (display->shell_variant)
{
@@ -2501,6 +2575,9 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
{
switch (impl->popup_state)
{
+ case POPUP_STATE_WAITING_FOR_REPOSITIONED:
+ gdk_surface_thaw_updates (surface);
+ G_GNUC_FALLTHROUGH;
case POPUP_STATE_WAITING_FOR_CONFIGURE:
case POPUP_STATE_WAITING_FOR_FRAME:
thaw_popup_toplevel_state (surface);
@@ -2602,6 +2679,7 @@ do_queue_relayout (GdkSurface *surface,
GdkPopupLayout *layout)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+ struct xdg_positioner *positioner;
g_assert (is_realized_popup (surface));
g_assert (impl->popup_state == POPUP_STATE_IDLE ||
@@ -2612,7 +2690,41 @@ do_queue_relayout (GdkSurface *surface,
impl->popup.unconstrained_width = width;
impl->popup.unconstrained_height = height;
- queue_relayout_fallback (surface, layout);
+ if (!impl->display_server.xdg_popup ||
+ xdg_popup_get_version (impl->display_server.xdg_popup) <
+ XDG_POPUP_REPOSITION_SINCE_VERSION)
+ {
+ g_warning_once ("Compositor doesn't support moving popups, "
+ "relying on remapping");
+ queue_relayout_fallback (surface, layout);
+
+ return;
+ }
+
+ positioner = create_dynamic_positioner (surface,
+ width, height, layout,
+ TRUE);
+ xdg_popup_reposition (impl->display_server.xdg_popup,
+ positioner,
+ ++impl->reposition_token);
+ xdg_positioner_destroy (positioner);
+
+ gdk_surface_freeze_updates (surface);
+
+ switch (impl->popup_state)
+ {
+ case POPUP_STATE_IDLE:
+ freeze_popup_toplevel_state (surface);
+ break;
+ case POPUP_STATE_WAITING_FOR_FRAME:
+ break;
+ case POPUP_STATE_WAITING_FOR_CONFIGURE:
+ case POPUP_STATE_WAITING_FOR_REPOSITIONED:
+ default:
+ g_assert_not_reached ();
+ }
+
+ impl->popup_state = POPUP_STATE_WAITING_FOR_REPOSITIONED;
}
static gboolean
@@ -2623,6 +2735,9 @@ is_relayout_finished (GdkSurface *surface)
if (!impl->initial_configure_received)
return FALSE;
+ if (impl->reposition_token != impl->received_reposition_token)
+ return FALSE;
+
return TRUE;
}
@@ -2707,6 +2822,7 @@ reposition_popup (GdkSurface *surface,
case POPUP_STATE_WAITING_FOR_FRAME:
do_queue_relayout (surface, width, height, layout);
break;
+ case POPUP_STATE_WAITING_FOR_REPOSITIONED:
case POPUP_STATE_WAITING_FOR_CONFIGURE:
g_warn_if_reached ();
break;
diff --git a/gdk/wayland/meson.build b/gdk/wayland/meson.build
index b6592064fb..14267f4ccc 100644
--- a/gdk/wayland/meson.build
+++ b/gdk/wayland/meson.build
@@ -37,10 +37,6 @@ gdk_wayland_deps = [
wlegldep,
]
-# wayland protocols
-proto_dir = dependency('wayland-protocols').get_pkgconfig_variable('pkgdatadir')
-assert(proto_dir != '', 'Could not get pkgdatadir from wayland-protocols.pc')
-
wayland_scanner = find_program('wayland-scanner')
# Format:
@@ -68,14 +64,14 @@ foreach p: proto_sources
if proto_stability == 'stable'
output_base = proto_name
- input = join_paths(proto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name, output_base))
+ input = files(join_paths(wlproto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name,
output_base)))
elif proto_stability == 'private'
output_base = proto_name
- input = 'protocol/@0@.xml'.format(proto_name)
+ input = files('protocol/@0@.xml'.format(proto_name))
else
proto_version = p.get(2)
output_base = '@0@-@1@-@2@'.format(proto_name, proto_stability, proto_version)
- input = join_paths(proto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name, output_base))
+ input = files(join_paths(wlproto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name,
output_base)))
endif
gdk_wayland_gen_headers += custom_target('@0@ client header'.format(output_base),
diff --git a/gtk/meson.build b/gtk/meson.build
index c7627af5f0..28e23b6781 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -644,11 +644,11 @@ foreach p: proto_sources
if wayland_enabled
if proto_stability == 'stable'
output_base = proto_name
- input = '@0@.xml'.format(proto_name)
+ input = files('@0@.xml'.format(proto_name))
else
proto_version = p.get(2)
output_base = '@0@-@1@-@2@'.format(proto_name, proto_stability, proto_version)
- input = join_paths(proto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name, output_base))
+ input = files(join_paths(wlproto_dir, '@0@/@1@/@2@.xml'.format(proto_stability, proto_name,
output_base)))
endif
# wayland_scanner is defined in gdk/wayland/meson.build
diff --git a/meson.build b/meson.build
index d3b94574ab..ecf4228b40 100644
--- a/meson.build
+++ b/meson.build
@@ -11,8 +11,8 @@ project('gtk', 'c',
license: 'LGPLv2.1+')
glib_major_req = 2
-glib_minor_req = 59
-glib_micro_req = 0
+glib_minor_req = 63
+glib_micro_req = 1
if glib_minor_req.is_odd()
glib_min_required = 'GLIB_VERSION_@0@_@1@'.format(glib_major_req, glib_minor_req - 1)
@@ -33,7 +33,7 @@ atk_req = '>= 2.15.1'
cairo_req = '>= 1.14.0'
gdk_pixbuf_req = '>= 2.30.0'
introspection_req = '>= 1.39.0'
-wayland_proto_req = '>= 1.14'
+wayland_proto_req = '>= 1.20'
wayland_req = '>= 1.14.91'
graphene_req = '>= 1.9.1'
epoxy_req = '>= 1.4'
@@ -469,10 +469,16 @@ atk_pkgs = ['atk']
wayland_pkgs = []
if wayland_enabled
wlclientdep = dependency('wayland-client', version: wayland_req)
- wlprotocolsdep = dependency('wayland-protocols', version: wayland_proto_req)
+ wlprotocolsdep = dependency('wayland-protocols', version: wayland_proto_req, required: false)
wlegldep = dependency('wayland-egl')
backend_immodules += ['wayland']
+ if not wlprotocolsdep.found()
+ wlproto_dir = subproject('wayland-protocols').get_variable('wayland_protocols_srcdir')
+ else
+ wlproto_dir = wlprotocolsdep.get_pkgconfig_variable('pkgdatadir')
+ endif
+
wayland_pkgs = [
'wayland-client', wayland_req,
'wayland-protocols', wayland_proto_req,
diff --git a/subprojects/wayland-protocols.wrap b/subprojects/wayland-protocols.wrap
new file mode 100644
index 0000000000..bb9619cbc9
--- /dev/null
+++ b/subprojects/wayland-protocols.wrap
@@ -0,0 +1,4 @@
+[wrap-git]
+directory=wayland-protocols
+url=https://gitlab.freedesktop.org/jadahl/wayland-protocols.git
+revision=wip/meson-meson-0.53
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]