Commit 5c8bb51a authored by Matthias Clasen's avatar Matthias Clasen

Merge branch 'wip/xdg-shell-gtk-3-22' into 'gtk-3-22'

xdg shell (stable; gtk 3 22)

See merge request !36
parents 68fce76f 0454a1ca
......@@ -60,7 +60,7 @@ m4_define([cairo_required_version], [1.14.0])
m4_define([gdk_pixbuf_required_version], [2.30.0])
m4_define([introspection_required_version], [1.39.0])
m4_define([wayland_required_version], [1.9.91])
m4_define([wayland_protocols_required_version], [1.9])
m4_define([wayland_protocols_required_version], [1.12])
m4_define([mirclient_required_version], [0.22.0])
m4_define([mircookie_required_version], [0.17.0])
m4_define([epoxy_required_version], [1.0])
......
......@@ -23,6 +23,8 @@ noinst_LTLIBRARIES = \
BUILT_SOURCES = \
pointer-gestures-unstable-v1-client-protocol.h \
pointer-gestures-unstable-v1-protocol.c \
xdg-shell-client-protocol.h \
xdg-shell-protocol.c \
xdg-shell-unstable-v6-client-protocol.h \
xdg-shell-unstable-v6-protocol.c \
xdg-foreign-unstable-v1-client-protocol.h \
......@@ -80,7 +82,7 @@ libgdkwaylandinclude_HEADERS = \
.SECONDEXPANSION:
define protostability
$(shell echo $1 | sed 's/.*-\(\(un\)\{0,1\}stable\)-.*/\1/')
$(if $(findstring unstable,$1),unstable,stable)
endef
define protoname
......
......@@ -119,9 +119,28 @@ _gdk_wayland_display_async_roundtrip (GdkWaylandDisplay *display_wayland)
}
static void
xdg_shell_ping (void *data,
struct zxdg_shell_v6 *xdg_shell,
uint32_t serial)
xdg_wm_base_ping (void *data,
struct xdg_wm_base *xdg_wm_base,
uint32_t serial)
{
GdkWaylandDisplay *display_wayland = data;
_gdk_wayland_display_update_serial (display_wayland, serial);
GDK_NOTE (EVENTS,
g_message ("ping, shell %p, serial %u\n", xdg_wm_base, serial));
xdg_wm_base_pong (xdg_wm_base, serial);
}
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
xdg_wm_base_ping,
};
static void
zxdg_shell_v6_ping (void *data,
struct zxdg_shell_v6 *xdg_shell,
uint32_t serial)
{
GdkWaylandDisplay *display_wayland = data;
......@@ -133,8 +152,8 @@ xdg_shell_ping (void *data,
zxdg_shell_v6_pong (xdg_shell, serial);
}
static const struct zxdg_shell_v6_listener xdg_shell_listener = {
xdg_shell_ping,
static const struct zxdg_shell_v6_listener zxdg_shell_v6_listener = {
zxdg_shell_v6_ping,
};
static gboolean
......@@ -388,14 +407,13 @@ gdk_registry_handle_global (void *data,
wl_registry_bind (display_wayland->wl_registry, id, &wl_shm_interface, 1);
wl_shm_add_listener (display_wayland->shm, &wl_shm_listener, display_wayland);
}
else if (strcmp (interface, "xdg_wm_base") == 0)
{
display_wayland->xdg_wm_base_id = id;
}
else if (strcmp (interface, "zxdg_shell_v6") == 0)
{
display_wayland->xdg_shell =
wl_registry_bind (display_wayland->wl_registry, id,
&zxdg_shell_v6_interface, 1);
zxdg_shell_v6_add_listener (display_wayland->xdg_shell,
&xdg_shell_listener,
display_wayland);
display_wayland->zxdg_shell_v6_id = id;
}
else if (strcmp (interface, "gtk_shell1") == 0)
{
......@@ -603,11 +621,32 @@ _gdk_wayland_display_open (const gchar *display_name)
}
}
/* Make sure we have xdg_shell at least */
if (display_wayland->xdg_shell == NULL)
if (display_wayland->xdg_wm_base_id)
{
display_wayland->shell_variant = GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL;
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_add_listener (display_wayland->xdg_wm_base,
&xdg_wm_base_listener,
display_wayland);
}
else if (display_wayland->zxdg_shell_v6_id)
{
display_wayland->shell_variant = GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6;
display_wayland->zxdg_shell_v6 =
wl_registry_bind (display_wayland->wl_registry,
display_wayland->zxdg_shell_v6_id,
&zxdg_shell_v6_interface, 1);
zxdg_shell_v6_add_listener (display_wayland->zxdg_shell_v6,
&zxdg_shell_v6_listener,
display_wayland);
}
else
{
g_warning ("Wayland compositor does not support xdg_shell interface,"
" not using Wayland display");
g_warning ("The Wayland compositor does not provide any supported shell interface, "
"not using Wayland display");
g_object_unref (display);
return NULL;
......
......@@ -29,6 +29,7 @@
#include <wayland-egl.h>
#include <gdk/wayland/tablet-unstable-v2-client-protocol.h>
#include <gdk/wayland/gtk-shell-client-protocol.h>
#include <gdk/wayland/xdg-shell-client-protocol.h>
#include <gdk/wayland/xdg-shell-unstable-v6-client-protocol.h>
#include <gdk/wayland/xdg-foreign-unstable-v1-client-protocol.h>
#include <gdk/wayland/keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h>
......@@ -53,6 +54,12 @@ G_BEGIN_DECLS
typedef struct _GdkWaylandSelection GdkWaylandSelection;
typedef enum _GdkWaylandShellVariant
{
GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL,
GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6,
} GdkWaylandShellVariant;
struct _GdkWaylandDisplay
{
GdkDisplay parent_instance;
......@@ -64,12 +71,17 @@ struct _GdkWaylandDisplay
/* Most recent serial */
guint32 serial;
uint32_t xdg_wm_base_id;
uint32_t zxdg_shell_v6_id;
GdkWaylandShellVariant shell_variant;
/* Wayland fields below */
struct wl_display *wl_display;
struct wl_registry *wl_registry;
struct wl_compositor *compositor;
struct wl_shm *shm;
struct zxdg_shell_v6 *xdg_shell;
struct xdg_wm_base *xdg_wm_base;
struct zxdg_shell_v6 *zxdg_shell_v6;
struct gtk_shell1 *gtk_shell;
struct wl_input_device *input_device;
struct wl_data_device_manager *data_device_manager;
......
......@@ -118,9 +118,16 @@ struct _GdkWindowImplWayland
GSList *outputs;
struct wl_surface *wl_surface;
struct zxdg_surface_v6 *xdg_surface;
struct zxdg_toplevel_v6 *xdg_toplevel;
struct zxdg_popup_v6 *xdg_popup;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct xdg_popup *xdg_popup;
/* Legacy xdg-shell unstable v6 fallback support */
struct zxdg_surface_v6 *zxdg_surface_v6;
struct zxdg_toplevel_v6 *zxdg_toplevel_v6;
struct zxdg_popup_v6 *zxdg_popup_v6;
struct gtk_surface1 *gtk_surface;
struct wl_subsurface *wl_subsurface;
struct wl_egl_window *egl_window;
......@@ -1019,6 +1026,33 @@ gdk_wayland_window_configure (GdkWindow *window,
_gdk_wayland_display_deliver_event (display, event);
}
static gboolean
is_realized_shell_surface (GdkWindow *window)
{
GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
return (impl->display_server.xdg_surface ||
impl->display_server.zxdg_surface_v6);
}
static gboolean
is_realized_toplevel (GdkWindow *window)
{
GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
return (impl->display_server.xdg_toplevel ||
impl->display_server.zxdg_toplevel_v6);
}
static gboolean
is_realized_popup (GdkWindow *window)
{
GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
return (impl->display_server.xdg_popup ||
impl->display_server.zxdg_popup_v6);
}
static void
gdk_wayland_window_maybe_configure (GdkWindow *window,
int width,
......@@ -1040,7 +1074,7 @@ gdk_wayland_window_maybe_configure (GdkWindow *window,
* force the new size onto the compositor. See bug #772505.
*/
is_xdg_popup = (impl->display_server.xdg_popup != NULL);
is_xdg_popup = is_realized_popup (window);
is_visible = gdk_window_is_visible (window);
if (is_xdg_popup && is_visible && !impl->initial_configure_received)
......@@ -1056,14 +1090,15 @@ static void
gdk_wayland_window_sync_parent (GdkWindow *window,
GdkWindow *parent)
{
GdkWaylandDisplay *display_wayland =
GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
GdkWindowImplWayland *impl_parent = NULL;
struct zxdg_toplevel_v6 *parent_toplevel;
g_assert (parent == NULL ||
gdk_window_get_display (window) == gdk_window_get_display (parent));
if (!impl->display_server.xdg_toplevel)
if (!is_realized_toplevel (window))
return;
if (impl->transient_for)
......@@ -1071,19 +1106,40 @@ gdk_wayland_window_sync_parent (GdkWindow *window,
else if (parent)
impl_parent = GDK_WINDOW_IMPL_WAYLAND (parent->impl);
if (impl_parent)
/* XXX: Is this correct? */
if (impl_parent && !impl_parent->display_server.wl_surface)
return;
switch (display_wayland->shell_variant)
{
/* XXX: Is this correct? */
if (!impl_parent->display_server.wl_surface)
return;
case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
{
struct xdg_toplevel *parent_toplevel;
parent_toplevel = impl_parent->display_server.xdg_toplevel;
}
else
parent_toplevel = NULL;
if (impl_parent)
parent_toplevel = impl_parent->display_server.xdg_toplevel;
else
parent_toplevel = NULL;
xdg_toplevel_set_parent (impl->display_server.xdg_toplevel,
parent_toplevel);
break;
}
break;
case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
{
struct zxdg_toplevel_v6 *parent_toplevel;
zxdg_toplevel_v6_set_parent (impl->display_server.xdg_toplevel,
parent_toplevel);
if (impl_parent)
parent_toplevel = impl_parent->display_server.zxdg_toplevel_v6;
else
parent_toplevel = NULL;
zxdg_toplevel_v6_set_parent (impl->display_server.zxdg_toplevel_v6,
parent_toplevel);
break;
}
}
}
static void
......@@ -1097,7 +1153,7 @@ gdk_wayland_window_sync_parent_of_imported (GdkWindow *window)
if (!impl->imported_transient_for)
return;
if (!impl->display_server.xdg_toplevel)
if (!is_realized_toplevel (window))
return;
zxdg_imported_v1_set_parent_of (impl->imported_transient_for,
......@@ -1139,14 +1195,26 @@ static void
gdk_wayland_window_sync_title (GdkWindow *window)
{
GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
GdkWaylandDisplay *display_wayland =
GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
if (!impl->display_server.xdg_toplevel)
if (!is_realized_toplevel (window))
return;
if (!impl->title)
return;
zxdg_toplevel_v6_set_title (impl->display_server.xdg_toplevel, impl->title);
switch (display_wayland->shell_variant)
{
case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
xdg_toplevel_set_title (impl->display_server.xdg_toplevel,
impl->title);
break;
case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
zxdg_toplevel_v6_set_title (impl->display_server.zxdg_toplevel_v6,
impl->title);
break;
}
}
static void
......@@ -1167,20 +1235,35 @@ static void
gdk_wayland_window_sync_margin (GdkWindow *window)
{
GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
GdkWaylandDisplay *display_wayland =
GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
GdkRectangle geometry;
if (!impl->display_server.xdg_surface)
if (!is_realized_shell_surface (window))
return;
gdk_wayland_window_get_window_geometry (window, &geometry);
gdk_window_set_geometry_hints (window,
&impl->geometry_hints,
impl->geometry_mask);
zxdg_surface_v6_set_window_geometry (impl->display_server.xdg_surface,
switch (display_wayland->shell_variant)
{
case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
xdg_surface_set_window_geometry (impl->display_server.xdg_surface,
geometry.x,
geometry.y,
geometry.width,
geometry.height);
break;
case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
zxdg_surface_v6_set_window_geometry (impl->display_server.zxdg_surface_v6,
geometry.x,
geometry.y,
geometry.width,
geometry.height);
break;
}
}
static struct wl_region *
......@@ -1382,12 +1465,12 @@ gdk_wayland_window_create_surface (GdkWindow *window)
}
static void
xdg_surface_configure (void *data,
struct zxdg_surface_v6 *xdg_surface,
uint32_t serial)
gdk_wayland_window_handle_configure (GdkWindow *window,
uint32_t serial)
{
GdkWindow *window = GDK_WINDOW (data);
GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
GdkWaylandDisplay *display_wayland =
GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
GdkWindowState new_state;
int width = impl->pending.width;
int height = impl->pending.height;
......@@ -1402,7 +1485,13 @@ xdg_surface_configure (void *data,
if (impl->display_server.xdg_popup)
{
zxdg_surface_v6_ack_configure (xdg_surface, serial);
xdg_surface_ack_configure (impl->display_server.xdg_surface, serial);
return;
}
else if (impl->display_server.zxdg_popup_v6)
{
zxdg_surface_v6_ack_configure (impl->display_server.zxdg_surface_v6,
serial);
return;
}
......@@ -1410,7 +1499,9 @@ xdg_surface_configure (void *data,
impl->pending.state = 0;
fixed_size =
new_state & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN | GDK_WINDOW_STATE_TILED);
new_state & (GDK_WINDOW_STATE_MAXIMIZED |
GDK_WINDOW_STATE_FULLSCREEN |
GDK_WINDOW_STATE_TILED);
saved_size = (width == 0 && height == 0);
/* According to xdg_shell, an xdg_surface.configure with size 0x0
......@@ -1460,40 +1551,179 @@ xdg_surface_configure (void *data,
(new_state & GDK_WINDOW_STATE_TILED) ? " tiled" : ""));
_gdk_set_window_state (window, new_state);
zxdg_surface_v6_ack_configure (xdg_surface, serial);
switch (display_wayland->shell_variant)
{
case GDK_WAYLAND_SHELL_VARIANT_XDG_SHELL:
xdg_surface_ack_configure (impl->display_server.xdg_surface, serial);
break;
case GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6:
zxdg_surface_v6_ack_configure (impl->display_server.zxdg_surface_v6,
serial);
break;
}
if (impl->hint != GDK_WINDOW_TYPE_HINT_DIALOG &&
new_state & GDK_WINDOW_STATE_FOCUSED)
gdk_wayland_window_update_dialogs (window);
}
static const struct zxdg_surface_v6_listener xdg_surface_listener = {
static void
gdk_wayland_window_handle_configure_toplevel (GdkWindow *window,
int32_t width,
int32_t height,
GdkWindowState state)
{
GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
impl->pending.state |= state;
impl->pending.width = width;
impl->pending.height = height;
}
static void
gdk_wayland_window_handle_close (GdkWindow *window)
{
GdkDisplay *display;
GdkEvent *event;
GDK_NOTE (EVENTS,
g_message ("close %p", window));
event = gdk_event_new (GDK_DELETE);
event->any.window = g_object_ref (window);
event->any.send_event = TRUE;
display = gdk_window_get_display (window);
_gdk_wayland_display_deliver_event (display, event);
}
static void
xdg_surface_configure (void *data,
struct xdg_surface *xdg_surface,
uint32_t serial)
{
GdkWindow *window = GDK_WINDOW (data);
gdk_wayland_window_handle_configure (window, serial);
}
static const struct xdg_surface_listener xdg_surface_listener = {
xdg_surface_configure,
};
static void
xdg_toplevel_configure (void *data,
struct zxdg_toplevel_v6 *xdg_toplevel,
int32_t width,
int32_t height,
struct wl_array *states)
xdg_toplevel_configure (void *data,
struct xdg_toplevel *xdg_toplevel,
int32_t width,
int32_t height,
struct wl_array *states)
{
GdkWindow *window = GDK_WINDOW (data);
uint32_t *p;
GdkWindowState pending_state = 0;
wl_array_for_each (p, states)
{
uint32_t state = *p;
switch (state)
{
case XDG_TOPLEVEL_STATE_FULLSCREEN:
pending_state |= GDK_WINDOW_STATE_FULLSCREEN;
break;
case XDG_TOPLEVEL_STATE_MAXIMIZED:
pending_state |= GDK_WINDOW_STATE_MAXIMIZED;
break;
case XDG_TOPLEVEL_STATE_ACTIVATED:
pending_state |= GDK_WINDOW_STATE_FOCUSED;
break;
case XDG_TOPLEVEL_STATE_RESIZING:
break;
default:
/* Unknown state */
break;
}
}
gdk_wayland_window_handle_configure_toplevel (window, width, height,
pending_state);
}
static void
xdg_toplevel_close (void *data,
struct xdg_toplevel *xdg_toplevel)
{
GdkWindow *window = GDK_WINDOW (data);
gdk_wayland_window_handle_close (window);
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
xdg_toplevel_configure,
xdg_toplevel_close,
};
static void
create_xdg_toplevel_resources (GdkWindow *window)
{
GdkWaylandDisplay *display_wayland =
GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
impl->display_server.xdg_surface =
xdg_wm_base_get_xdg_surface (display_wayland->xdg_wm_base,
impl->display_server.wl_surface);
xdg_surface_add_listener (impl->display_server.xdg_surface,
&xdg_surface_listener,
window);
impl->display_server.xdg_toplevel =
xdg_surface_get_toplevel (impl->display_server.xdg_surface);
xdg_toplevel_add_listener (impl->display_server.xdg_toplevel,
&xdg_toplevel_listener,
window);
}
static void
zxdg_surface_v6_configure (void *data,
struct zxdg_surface_v6 *xdg_surface,
uint32_t serial)
{
GdkWindow *window = GDK_WINDOW (data);
gdk_wayland_window_handle_configure (window, serial);
}
static const struct zxdg_surface_v6_listener zxdg_surface_v6_listener = {
zxdg_surface_v6_configure,
};
static void
zxdg_toplevel_v6_configure (void *data,
struct zxdg_toplevel_v6 *xdg_toplevel,
int32_t width,
int32_t height,
struct wl_array *states)
{
GdkWindow *window = GDK_WINDOW (data);
uint32_t *p;
GdkWindowState pending_state = 0;
wl_array_for_each (p, states)
{
uint32_t state = *p;
switch (state)
{
case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
impl->pending.state |= GDK_WINDOW_STATE_FULLSCREEN;
pending_state |= GDK_WINDOW_STATE_FULLSCREEN;
break;
case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED:
impl->pending.state |= GDK_WINDOW_STATE_MAXIMIZED;
pending_state |= GDK_WINDOW_STATE_MAXIMIZED;
break;
case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED:
impl->pending.state |= GDK_WINDOW_STATE_FOCUSED;
pending_state |= GDK_WINDOW_STATE_FOCUSED;
break;
case ZXDG_TOPLEVEL_V6_STATE_RESIZING:
break;
......@@ -1503,34 +1733,45 @@ xdg_toplevel_configure (void *data,
}
}
impl->pending.width = width;
impl->pending.height = height;
gdk_wayland_window_handle_configure_toplevel (window, width, height,
pending_state);
}
static void
xdg_toplevel_close (void *data,
struct zxdg_toplevel_v6 *xdg_toplevel)
zxdg_toplevel_v6_close (void *data,
struct zxdg_toplevel_v6 *xdg_toplevel)
{
GdkWindow *window = GDK_WINDOW (data);
GdkDisplay *display;
GdkEvent *event;
GDK_NOTE (EVENTS,
g_message ("close %p", window));
event = gdk_event_new (GDK_DELETE);
event->any.window = g_object_ref (window);
event->any.send_event = TRUE;
display = gdk_window_get_display (window);
_gdk_wayland_display_deliver_event (display, event);
gdk_wayland_window_handle_close (window);
}
static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
xdg_toplevel_configure,
xdg_toplevel_close,
static const struct zxdg_toplevel_v6_listener zxdg_toplevel_v6_listener = {
zxdg_toplevel_v6_configure,
zxdg_toplevel_v6_close,
};
static void
create_zxdg_toplevel_v6_resources (GdkWindow *window)
{