mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-10 02:40:11 +00:00
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.
This commit is contained in:
parent
213c471bb7
commit
5425edff82
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
14
meson.build
14
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,
|
||||
|
4
subprojects/wayland-protocols.wrap
Normal file
4
subprojects/wayland-protocols.wrap
Normal file
@ -0,0 +1,4 @@
|
||||
[wrap-git]
|
||||
directory=wayland-protocols
|
||||
url=https://gitlab.freedesktop.org/jadahl/wayland-protocols.git
|
||||
revision=wip/meson-meson-0.53
|
Loading…
Reference in New Issue
Block a user