diff --git a/clients/simple-egl.c b/clients/simple-egl.c
index b94f31d2e..63b3aa122 100644
--- a/clients/simple-egl.c
+++ b/clients/simple-egl.c
@@ -264,13 +264,6 @@ init_gl(struct window *window)
glGetUniformLocation(program, "rotation");
}
-static void
-handle_surface_ping(void *data,
- struct xdg_surface *xdg_surface, uint32_t serial)
-{
- xdg_surface_pong(xdg_surface, serial);
-}
-
static void
handle_surface_configure(void *data, struct xdg_surface *surface,
int32_t width, int32_t height)
@@ -318,7 +311,6 @@ handle_surface_focused_unset(void *data, struct xdg_surface *xdg_surface)
}
static const struct xdg_surface_listener xdg_surface_listener = {
- handle_surface_ping,
handle_surface_configure,
handle_surface_request_set_maximized,
handle_surface_request_unset_maximized,
@@ -715,6 +707,16 @@ static const struct wl_seat_listener seat_listener = {
seat_handle_capabilities,
};
+static void
+xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial)
+{
+ xdg_shell_pong(shell, serial);
+}
+
+static const struct xdg_shell_listener xdg_shell_listener = {
+ xdg_shell_ping,
+};
+
static void
registry_handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
@@ -728,6 +730,7 @@ registry_handle_global(void *data, struct wl_registry *registry,
} else if (strcmp(interface, "xdg_shell") == 0) {
d->shell = wl_registry_bind(registry, name,
&xdg_shell_interface, 1);
+ xdg_shell_add_listener(d->shell, &xdg_shell_listener, d);
xdg_shell_use_unstable_version(d->shell, 1);
} else if (strcmp(interface, "wl_seat") == 0) {
d->seat = wl_registry_bind(registry, name,
diff --git a/clients/simple-shm.c b/clients/simple-shm.c
index 40f1633d0..820e8a2d9 100644
--- a/clients/simple-shm.c
+++ b/clients/simple-shm.c
@@ -111,12 +111,6 @@ create_shm_buffer(struct display *display, struct buffer *buffer,
return 0;
}
-static void
-handle_ping(void *data, struct xdg_surface *surface, uint32_t serial)
-{
- xdg_surface_pong(surface, serial);
-}
-
static void
handle_configure(void *data, struct xdg_surface *surface,
int32_t width, int32_t height)
@@ -154,7 +148,6 @@ handle_focused_unset(void *data, struct xdg_surface *xdg_surface)
}
static const struct xdg_surface_listener xdg_surface_listener = {
- handle_ping,
handle_configure,
handle_request_set_maximized,
handle_request_unset_maximized,
@@ -328,6 +321,16 @@ struct wl_shm_listener shm_listener = {
shm_format
};
+static void
+xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial)
+{
+ xdg_shell_pong(shell, serial);
+}
+
+static const struct xdg_shell_listener xdg_shell_listener = {
+ xdg_shell_ping,
+};
+
static void
registry_handle_global(void *data, struct wl_registry *registry,
uint32_t id, const char *interface, uint32_t version)
@@ -342,6 +345,7 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->shell = wl_registry_bind(registry,
id, &xdg_shell_interface, 1);
xdg_shell_use_unstable_version(d->shell, 1);
+ xdg_shell_add_listener(d->shell, &xdg_shell_listener, d);
} else if (strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry,
id, &wl_shm_interface, 1);
diff --git a/clients/window.c b/clients/window.c
index 91c1ea06d..93aa3680f 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -3843,12 +3843,6 @@ widget_schedule_resize(struct widget *widget, int32_t width, int32_t height)
window_schedule_resize(widget->window, width, height);
}
-static void
-handle_surface_ping(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
-{
- xdg_surface_pong(xdg_surface, serial);
-}
-
static void
handle_surface_configure(void *data, struct xdg_surface *xdg_surface,
int32_t width, int32_t height)
@@ -3910,7 +3904,6 @@ handle_surface_delete(void *data, struct xdg_surface *xdg_surface)
}
static const struct xdg_surface_listener xdg_surface_listener = {
- handle_surface_ping,
handle_surface_configure,
handle_surface_request_set_maximized,
handle_surface_request_unset_maximized,
@@ -4582,12 +4575,6 @@ menu_redraw_handler(struct widget *widget, void *data)
cairo_destroy(cr);
}
-static void
-handle_popup_ping(void *data, struct xdg_popup *xdg_popup, uint32_t serial)
-{
- xdg_popup_pong(xdg_popup, serial);
-}
-
static void
handle_popup_popup_done(void *data, struct xdg_popup *xdg_popup, uint32_t serial)
{
@@ -4599,7 +4586,6 @@ handle_popup_popup_done(void *data, struct xdg_popup *xdg_popup, uint32_t serial
}
static const struct xdg_popup_listener xdg_popup_listener = {
- handle_popup_ping,
handle_popup_popup_done,
};
@@ -5023,6 +5009,16 @@ struct wl_shm_listener shm_listener = {
shm_format
};
+static void
+xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial)
+{
+ xdg_shell_pong(shell, serial);
+}
+
+static const struct xdg_shell_listener xdg_shell_listener = {
+ xdg_shell_ping,
+};
+
static void
registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
const char *interface, uint32_t version)
@@ -5055,6 +5051,7 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
d->xdg_shell = wl_registry_bind(registry, id,
&xdg_shell_interface, 1);
xdg_shell_use_unstable_version(d->xdg_shell, XDG_SHELL_VERSION_CURRENT);
+ xdg_shell_add_listener(d->xdg_shell, &xdg_shell_listener, d);
} else if (strcmp(interface, "text_cursor_position") == 0) {
d->text_cursor_position =
wl_registry_bind(registry, id,
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index a73e8e026..2a82a1d38 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -227,6 +227,16 @@ struct shell_seat {
} popup_grab;
};
+struct shell_client {
+ struct wl_resource *resource;
+ struct wl_client *client;
+ struct desktop_shell *shell;
+ struct wl_listener destroy_listener;
+ struct wl_event_source *ping_timer;
+ uint32_t ping_serial;
+ int unresponsive;
+};
+
void
set_alpha_if_fullscreen(struct shell_surface *shsurf)
{
@@ -1733,9 +1743,6 @@ shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
common_surface_resize(resource, seat_resource, serial, edges);
}
-static void
-end_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer);
-
static void
busy_cursor_grab_focus(struct weston_pointer_grab *base)
{
@@ -1748,8 +1755,10 @@ busy_cursor_grab_focus(struct weston_pointer_grab *base)
pointer->x, pointer->y,
&sx, &sy);
- if (!grab->shsurf || grab->shsurf->surface != view->surface)
- end_busy_cursor(grab->shsurf, pointer);
+ if (!grab->shsurf || grab->shsurf->surface != view->surface) {
+ shell_grab_end(grab);
+ free(grab);
+ }
}
static void
@@ -1797,6 +1806,9 @@ set_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
{
struct shell_grab *grab;
+ if (pointer->grab->interface == &busy_cursor_grab_interface)
+ return;
+
grab = malloc(sizeof *grab);
if (!grab)
return;
@@ -1806,14 +1818,21 @@ set_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
}
static void
-end_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
+end_busy_cursor(struct weston_compositor *compositor, struct wl_client *client)
{
- struct shell_grab *grab = (struct shell_grab *) pointer->grab;
+ struct shell_grab *grab;
+ struct weston_seat *seat;
- if (grab->grab.interface == &busy_cursor_grab_interface &&
- grab->shsurf == shsurf) {
- shell_grab_end(grab);
- free(grab);
+ wl_list_for_each(seat, &compositor->seat_list, link) {
+ if (seat->pointer == NULL)
+ continue;
+
+ grab = (struct shell_grab *) seat->pointer->grab;
+ if (grab->grab.interface == &busy_cursor_grab_interface &&
+ wl_resource_get_client(grab->shsurf->resource) == client) {
+ shell_grab_end(grab);
+ free(grab);
+ }
}
}
@@ -1847,39 +1866,107 @@ ping_timeout_handler(void *data)
return 1;
}
+static const int ping_timeout = 200;
+
+static void
+handle_wl_shell_ping(struct shell_surface *shsurf, uint32_t serial)
+{
+ struct wl_event_loop *loop;
+ struct weston_compositor *compositor = shsurf->shell->compositor;
+
+ if (shsurf->ping_timer)
+ return;
+
+ shsurf->ping_timer = malloc(sizeof *shsurf->ping_timer);
+ if (!shsurf->ping_timer)
+ return;
+
+ shsurf->ping_timer->serial = serial;
+ loop = wl_display_get_event_loop(compositor->wl_display);
+ shsurf->ping_timer->source =
+ wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
+ wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
+
+ wl_shell_surface_send_ping(shsurf->resource, serial);
+}
+
+static void
+handle_shell_client_destroy(struct wl_listener *listener, void *data);
+
+static int
+xdg_ping_timeout_handler(void *data)
+{
+ struct shell_client *sc = data;
+ struct weston_seat *seat;
+ struct shell_surface *shsurf;
+
+ /* Client is not responding */
+ sc->unresponsive = 1;
+
+ wl_list_for_each(seat, &sc->shell->compositor->seat_list, link) {
+ if (seat->pointer == NULL || seat->pointer->focus == NULL)
+ continue;
+ if (seat->pointer->focus->surface->resource == NULL)
+ continue;
+
+ shsurf = get_shell_surface(seat->pointer->focus->surface);
+ if (shsurf &&
+ wl_resource_get_client(shsurf->resource) == sc->client)
+ set_busy_cursor(shsurf, seat->pointer);
+ }
+
+ return 1;
+}
+
+static void
+handle_xdg_ping(struct shell_surface *shsurf, uint32_t serial)
+{
+ struct weston_compositor *compositor = shsurf->shell->compositor;
+ struct wl_listener *listener;
+ struct wl_client *client = wl_resource_get_client(shsurf->resource);
+ struct shell_client *sc;
+ struct wl_event_loop *loop;
+
+ listener = wl_client_get_destroy_listener(client,
+ handle_shell_client_destroy);
+ sc = container_of(listener, struct shell_client, destroy_listener);
+
+ if (sc->unresponsive) {
+ xdg_ping_timeout_handler(sc);
+ return;
+ }
+
+ sc->ping_serial = serial;
+ loop = wl_display_get_event_loop(compositor->wl_display);
+ if (sc->ping_timer == NULL)
+ sc->ping_timer =
+ wl_event_loop_add_timer(loop,
+ xdg_ping_timeout_handler, sc);
+ if (sc->ping_timer == NULL)
+ return;
+
+ wl_event_source_timer_update(sc->ping_timer, ping_timeout);
+
+ xdg_shell_send_ping(sc->resource, serial);
+}
+
static void
ping_handler(struct weston_surface *surface, uint32_t serial)
{
struct shell_surface *shsurf = get_shell_surface(surface);
- struct wl_event_loop *loop;
- int ping_timeout = 200;
if (!shsurf)
return;
if (!shsurf->resource)
return;
-
if (shsurf->surface == shsurf->shell->grab_surface)
return;
- if (!shsurf->ping_timer) {
- shsurf->ping_timer = malloc(sizeof *shsurf->ping_timer);
- if (!shsurf->ping_timer)
- return;
-
- shsurf->ping_timer->serial = serial;
- loop = wl_display_get_event_loop(surface->compositor->wl_display);
- shsurf->ping_timer->source =
- wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
- wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
-
- if (shell_surface_is_wl_shell_surface(shsurf))
- wl_shell_surface_send_ping(shsurf->resource, serial);
- else if (shell_surface_is_xdg_surface(shsurf))
- xdg_surface_send_ping(shsurf->resource, serial);
- else if (shell_surface_is_xdg_popup(shsurf))
- xdg_popup_send_ping(shsurf->resource, serial);
- }
+ if (shell_surface_is_xdg_surface(shsurf) ||
+ shell_surface_is_xdg_popup(shsurf))
+ handle_xdg_ping(shsurf, serial);
+ else if (shell_surface_is_wl_shell_surface(shsurf))
+ handle_wl_shell_ping(shsurf, serial);
}
static void
@@ -1988,7 +2075,6 @@ static void
surface_pong(struct shell_surface *shsurf, uint32_t serial)
{
struct weston_compositor *ec = shsurf->surface->compositor;
- struct weston_seat *seat;
if (shsurf->ping_timer == NULL)
/* Just ignore unsolicited pong. */
@@ -1996,11 +2082,7 @@ surface_pong(struct shell_surface *shsurf, uint32_t serial)
if (shsurf->ping_timer->serial == serial) {
shsurf->unresponsive = 0;
- wl_list_for_each(seat, &ec->seat_list, link) {
- if(seat->pointer)
- end_busy_cursor(shsurf, seat->pointer);
- }
- ping_timer_destroy(shsurf);
+ end_busy_cursor(ec, wl_resource_get_client(shsurf->resource));
}
}
@@ -3161,16 +3243,6 @@ xdg_surface_destroy(struct wl_client *client,
wl_resource_destroy(resource);
}
-static void
-xdg_surface_pong(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t serial)
-{
- struct shell_surface *shsurf = wl_resource_get_user_data(resource);
-
- surface_pong(shsurf, serial);
-}
-
static void
xdg_surface_set_margin(struct wl_client *client,
struct wl_resource *resource,
@@ -3324,7 +3396,6 @@ static const struct xdg_surface_interface xdg_surface_implementation = {
xdg_surface_set_margin,
xdg_surface_set_title,
xdg_surface_set_app_id,
- xdg_surface_pong,
xdg_surface_move,
xdg_surface_resize,
xdg_surface_set_output,
@@ -3383,7 +3454,8 @@ xdg_get_xdg_surface(struct wl_client *client,
{
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
- struct desktop_shell *shell = wl_resource_get_user_data(resource);
+ struct shell_client *sc = wl_resource_get_user_data(resource);
+ struct desktop_shell *shell = sc->shell;
struct shell_surface *shsurf;
if (get_shell_surface(surface)) {
@@ -3427,19 +3499,8 @@ xdg_popup_destroy(struct wl_client *client,
wl_resource_destroy(resource);
}
-static void
-xdg_popup_pong(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t serial)
-{
- struct shell_surface *shsurf = wl_resource_get_user_data(resource);
-
- surface_pong(shsurf, serial);
-}
-
static const struct xdg_popup_interface xdg_popup_implementation = {
xdg_popup_destroy,
- xdg_popup_pong
};
static void
@@ -3485,7 +3546,8 @@ xdg_get_xdg_popup(struct wl_client *client,
{
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
- struct desktop_shell *shell = wl_resource_get_user_data(resource);
+ struct shell_client *sc = wl_resource_get_user_data(resource);
+ struct desktop_shell *shell = sc->shell;
struct shell_surface *shsurf;
struct weston_surface *parent;
struct shell_seat *seat;
@@ -3523,6 +3585,25 @@ xdg_get_xdg_popup(struct wl_client *client,
shsurf, shell_destroy_shell_surface);
}
+static void
+xdg_pong(struct wl_client *client,
+ struct wl_resource *resource, uint32_t serial)
+{
+ struct shell_client *sc = wl_resource_get_user_data(resource);
+ struct weston_compositor *ec = sc->shell->compositor;
+
+ if (sc->ping_serial != serial)
+ return;
+
+ sc->unresponsive = 0;
+ end_busy_cursor(ec, client);
+
+ if (sc->ping_timer) {
+ wl_event_source_remove(sc->ping_timer);
+ sc->ping_timer = NULL;
+ }
+}
+
static bool
shell_surface_is_xdg_popup(struct shell_surface *shsurf)
{
@@ -3534,7 +3615,8 @@ shell_surface_is_xdg_popup(struct shell_surface *shsurf)
static const struct xdg_shell_interface xdg_implementation = {
xdg_use_unstable_version,
xdg_get_xdg_surface,
- xdg_get_xdg_popup
+ xdg_get_xdg_popup,
+ xdg_pong
};
static int
@@ -3544,7 +3626,7 @@ xdg_shell_unversioned_dispatch(const void *implementation,
union wl_argument *args)
{
struct wl_resource *resource = _target;
- struct desktop_shell *shell = wl_resource_get_user_data(resource);
+ struct shell_client *sc = wl_resource_get_user_data(resource);
if (opcode != 0) {
wl_resource_post_error(resource,
@@ -3568,7 +3650,7 @@ xdg_shell_unversioned_dispatch(const void *implementation,
}
wl_resource_set_implementation(resource, &xdg_implementation,
- shell, NULL);
+ sc, NULL);
return 1;
}
@@ -4949,17 +5031,44 @@ bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
shell, NULL);
}
+static void
+handle_shell_client_destroy(struct wl_listener *listener, void *data)
+{
+ struct shell_client *sc =
+ container_of(listener, struct shell_client, destroy_listener);
+
+ if (sc->ping_timer)
+ wl_event_source_remove(sc->ping_timer);
+ free(sc);
+}
+
static void
bind_xdg_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
struct desktop_shell *shell = data;
- struct wl_resource *resource;
+ struct shell_client *sc;
- resource = wl_resource_create(client, &xdg_shell_interface, 1, id);
- if (resource)
- wl_resource_set_dispatcher(resource,
- xdg_shell_unversioned_dispatch,
- NULL, shell, NULL);
+ sc = zalloc(sizeof *sc);
+ if (sc == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ sc->resource = wl_resource_create(client, &xdg_shell_interface, 1, id);
+ if (sc->resource == NULL) {
+ free(sc);
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ sc->client = client;
+ sc->shell = shell;
+ sc->destroy_listener.notify = handle_shell_client_destroy;
+ wl_client_add_destroy_listener(client, &sc->destroy_listener);
+
+ wl_resource_set_dispatcher(sc->resource,
+ xdg_shell_unversioned_dispatch,
+ NULL, sc, NULL);
}
static void
diff --git a/protocol/xdg-shell.xml b/protocol/xdg-shell.xml
index f0d04aa34..d122ff5eb 100644
--- a/protocol/xdg-shell.xml
+++ b/protocol/xdg-shell.xml
@@ -84,6 +84,28 @@
+
+
+
+ The ping event asks the client if it's still alive. Pass the
+ serial specified in the event back to the compositor by sending
+ a "pong" request back with the specified serial.
+
+ Compositors can use this to determine if the client is still
+ alive. It's unspecified what will happen if the client doesn't
+ respond to the ping request, or in what timeframe. Clients should
+ try to respond in a reasonable amount of time.
+
+
+
+
+
+
+ A client must respond to a ping event with a pong request or
+ the client may be deemed unresponsive.
+
+
+
@@ -176,22 +198,6 @@
-
-
- A client must respond to a ping event with a pong request or
- the client may be deemed unresponsive.
-
-
-
-
-
-
- Ping a client to check if it is receiving events and sending
- requests. A client is expected to reply with a pong request.
-
-
-
-
Start a pointer-driven move of the surface.
@@ -447,22 +453,6 @@
-
-
- A client must respond to a ping event with a pong request or
- the client may be deemed unresponsive.
-
-
-
-
-
-
- Ping a client to check if it is receiving events and sending
- requests. A client is expected to reply with a pong request.
-
-
-
-
The popup_done event is sent out when a popup grab is broken,