From 74e95788892b906008e289747912353a1c1166f8 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 11 Sep 2017 13:01:53 -0400 Subject: [PATCH 01/20] add surface destroy signal --- include/wlr/types/wlr_surface.h | 1 + types/wlr_surface.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index f0765160..0a802ea3 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -42,6 +42,7 @@ struct wlr_surface { struct { struct wl_signal commit; + struct wl_signal destroy; } signals; struct wl_list frame_callback_list; // wl_surface.frame diff --git a/types/wlr_surface.c b/types/wlr_surface.c index e733c544..9f329b7d 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -365,6 +365,7 @@ const struct wl_surface_interface surface_interface = { static void destroy_surface(struct wl_resource *resource) { struct wlr_surface *surface = wl_resource_get_user_data(resource); + wl_signal_emit(&surface->signals.destroy, surface); wlr_texture_destroy(surface->texture); struct wlr_frame_callback *cb, *next; @@ -399,6 +400,7 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, pixman_region32_init(&surface->pending.opaque); pixman_region32_init(&surface->pending.input); wl_signal_init(&surface->signals.commit); + wl_signal_init(&surface->signals.destroy); wl_list_init(&surface->frame_callback_list); wl_resource_set_implementation(res, &surface_interface, surface, destroy_surface); From 4752b84f4e4c12b5a7b16f414af30e62134117b0 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 11 Sep 2017 16:26:51 -0400 Subject: [PATCH 02/20] wlr_xdg_shell_v6.c: fix formatting --- types/wlr_xdg_shell_v6.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index b5df9bd8..abe718a0 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -5,7 +5,8 @@ #include #include "xdg-shell-unstable-v6-protocol.h" -static void resource_destroy(struct wl_client *client, struct wl_resource *resource) { +static void resource_destroy(struct wl_client *client, + struct wl_resource *resource) { // TODO: we probably need to do more than this wl_resource_destroy(resource); } @@ -58,23 +59,28 @@ static void xdg_toplevel_set_maximized(struct wl_client *client, wlr_log(L_DEBUG, "TODO: toplevel set maximized"); } -static void xdg_toplevel_unset_maximized(struct wl_client *client, struct wl_resource *resource) { +static void xdg_toplevel_unset_maximized(struct wl_client *client, + struct wl_resource *resource) { wlr_log(L_DEBUG, "TODO: toplevel unset maximized"); } -static void xdg_toplevel_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { +static void xdg_toplevel_set_fullscreen(struct wl_client *client, + struct wl_resource *resource, struct wl_resource *output_resource) { wlr_log(L_DEBUG, "TODO: toplevel set fullscreen"); } -static void xdg_toplevel_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { +static void xdg_toplevel_unset_fullscreen(struct wl_client *client, + struct wl_resource *resource) { wlr_log(L_DEBUG, "TODO: toplevel unset fullscreen"); } -static void xdg_toplevel_set_minimized(struct wl_client *client, struct wl_resource *resource) { +static void xdg_toplevel_set_minimized(struct wl_client *client, + struct wl_resource *resource) { wlr_log(L_DEBUG, "TODO: toplevel set minimized"); } -static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = { +static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = +{ .destroy = resource_destroy, .set_parent = xdg_toplevel_set_parent, .set_title = xdg_toplevel_set_title, @@ -118,7 +124,7 @@ static void xdg_surface_ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { wlr_log(L_DEBUG, "TODO xdg surface ack configure"); } - + static void xdg_surface_set_window_geometry(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { @@ -175,13 +181,15 @@ static void xdg_shell_bind(struct wl_client *wl_client, void *_xdg_shell, struct wlr_xdg_shell_v6 *xdg_shell = _xdg_shell; assert(wl_client && xdg_shell); if (version > 1) { - wlr_log(L_ERROR, "Client requested unsupported xdg_shell_v6 version, disconnecting"); + wlr_log(L_ERROR, + "Client requested unsupported xdg_shell_v6 version, disconnecting"); wl_client_destroy(wl_client); return; } - struct wl_resource *wl_resource = wl_resource_create( - wl_client, &zxdg_shell_v6_interface, version, id); - wl_resource_set_implementation(wl_resource, &xdg_shell_impl, xdg_shell, xdg_shell_destroy); + struct wl_resource *wl_resource = + wl_resource_create( wl_client, &zxdg_shell_v6_interface, version, id); + wl_resource_set_implementation(wl_resource, &xdg_shell_impl, xdg_shell, + xdg_shell_destroy); wl_list_insert(&xdg_shell->wl_resources, wl_resource_get_link(wl_resource)); } From c5f8f81e58feb13aeadb4f27ee3e4e2a1eb2b8a8 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 11 Sep 2017 17:24:55 -0400 Subject: [PATCH 03/20] xdg_surface: handle wlr_surface destroy --- include/wlr/types/wlr_xdg_shell_v6.h | 2 ++ types/wlr_xdg_shell_v6.c | 26 +++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 41cf483a..500dae87 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -15,6 +15,8 @@ struct wlr_xdg_surface_v6 { struct wl_resource *surface; struct wl_list link; + struct wl_listener surface_destroy_listener; + void *data; }; diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index abe718a0..46416c4e 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -97,12 +97,20 @@ static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = .set_minimized = xdg_toplevel_set_minimized }; -static void xdg_surface_destroy(struct wl_resource *resource) { - struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); +static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { + wl_resource_set_user_data(surface->resource, NULL); wl_list_remove(&surface->link); + wl_list_remove(&surface->surface_destroy_listener.link); free(surface); } +static void xdg_surface_resource_destroy(struct wl_resource *resource) { + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + if (surface != NULL) { + xdg_surface_destroy(surface); + } +} + static void xdg_surface_get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id) { // TODO: Flesh out @@ -144,6 +152,13 @@ static void xdg_shell_create_positioner(struct wl_client *client, wlr_log(L_DEBUG, "TODO: xdg shell create positioner"); } +static void handle_wlr_surface_destroyed(struct wl_listener *listener, + void *data) { + struct wlr_xdg_surface_v6 *xdg_surface = + wl_container_of(listener, xdg_surface, surface_destroy_listener); + xdg_surface_destroy(xdg_surface); +} + static void xdg_shell_get_xdg_surface(struct wl_client *client, struct wl_resource *_xdg_shell, uint32_t id, struct wl_resource *_surface) { @@ -155,9 +170,14 @@ static void xdg_shell_get_xdg_surface(struct wl_client *client, surface->surface = _surface; surface->resource = wl_resource_create(client, &zxdg_surface_v6_interface, wl_resource_get_version(_xdg_shell), id); + + wl_signal_add(&_surface->destroy_signal, + &surface->surface_destroy_listener); + surface->surface_destroy_listener.notify = handle_wlr_surface_destroyed; + wlr_log(L_DEBUG, "new xdg_surface %p (res %p)", surface, surface->resource); wl_resource_set_implementation(surface->resource, - &zxdg_surface_v6_implementation, surface, xdg_surface_destroy); + &zxdg_surface_v6_implementation, surface, xdg_surface_resource_destroy); wl_list_insert(&xdg_shell->surfaces, &surface->link); } From b2c71287f29cec22217177d11e8692e73b805b66 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 11 Sep 2017 18:06:19 -0400 Subject: [PATCH 04/20] set toplevel role on wlr_surface --- include/wlr/types/wlr_surface.h | 8 ++++++++ include/wlr/types/wlr_xdg_shell_v6.h | 7 +++++++ types/wlr_surface.c | 21 +++++++++++++++++++++ types/wlr_xdg_shell_v6.c | 15 +++++++++++++++ 4 files changed, 51 insertions(+) diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 0a802ea3..d76fff16 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -70,4 +70,12 @@ void wlr_surface_get_matrix(struct wlr_surface *surface, const float (*projection)[16], const float (*transform)[16]); + +/** + * Set the lifetime role for this surface. Returns 0 on success or -1 if the + * role cannot be set. + */ +int wlr_surface_set_role(struct wlr_surface *surface, const char *role, + struct wl_resource *error_resource, uint32_t error_code); + #endif diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 500dae87..6bc37940 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -10,10 +10,17 @@ struct wlr_xdg_shell_v6 { void *data; }; +enum wlr_xdg_surface_v6_role { + WLR_XDG_SURFACE_V6_ROLE_NONE, + WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL, + WLR_XDG_SURFACE_V6_ROLE_POPUP, +}; + struct wlr_xdg_surface_v6 { struct wl_resource *resource; struct wl_resource *surface; struct wl_list link; + enum wlr_xdg_surface_v6_role role; struct wl_listener surface_destroy_listener; diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 9f329b7d..a9a54abe 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -422,3 +422,24 @@ void wlr_surface_get_matrix(struct wlr_surface *surface, wlr_matrix_mul(matrix, &scale, matrix); wlr_matrix_mul(projection, matrix, matrix); } + +int wlr_surface_set_role(struct wlr_surface *surface, const char *role, + struct wl_resource *error_resource, uint32_t error_code) { + assert(role); + + if (surface->role == NULL || + surface->role == role || + strcmp(surface->role, role) == 0) { + surface->role = role; + + return 0; + } + + wl_resource_post_error(error_resource, error_code, + "Cannot assign role %s to wl_surface@%d, already has role %s\n", + role, + wl_resource_get_id(surface->resource), + surface->role); + + return -1; +} diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 46416c4e..2fff054d 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -2,9 +2,12 @@ #include #include #include +#include #include #include "xdg-shell-unstable-v6-protocol.h" +static const char *wlr_desktop_xdg_toplevel_role = "xdg_toplevel"; + static void resource_destroy(struct wl_client *client, struct wl_resource *resource) { // TODO: we probably need to do more than this @@ -114,8 +117,19 @@ static void xdg_surface_resource_destroy(struct wl_resource *resource) { static void xdg_surface_get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id) { // TODO: Flesh out + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_surface *wsurface = wl_resource_get_user_data(surface->surface); + + if (wlr_surface_set_role(wsurface, wlr_desktop_xdg_toplevel_role, + resource, ZXDG_SHELL_V6_ERROR_ROLE)) { + return; + } + + surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; + struct wl_resource *toplevel_resource = wl_resource_create(client, &zxdg_toplevel_v6_interface, wl_resource_get_version(resource), id); + wl_resource_set_implementation(toplevel_resource, &zxdg_toplevel_v6_implementation, NULL, NULL); struct wl_display *display = wl_client_get_display(client); @@ -167,6 +181,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *client, if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface_v6)))) { return; } + surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; surface->surface = _surface; surface->resource = wl_resource_create(client, &zxdg_surface_v6_interface, wl_resource_get_version(_xdg_shell), id); From 9d2dc8447a64d0f402b309af5a655ce374dad808 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 12 Sep 2017 06:18:52 -0400 Subject: [PATCH 05/20] use wlr_surface on shell struct and listen to events --- examples/compositor.c | 2 +- include/wlr/types/wlr_xdg_shell_v6.h | 3 ++- types/wlr_xdg_shell_v6.c | 17 +++++++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/examples/compositor.c b/examples/compositor.c index 995c1b7d..9d96b053 100644 --- a/examples/compositor.c +++ b/examples/compositor.c @@ -102,7 +102,7 @@ static void handle_output_frame(struct output_state *output, struct wlr_xdg_surface_v6 *xdg_surface; wl_list_for_each(xdg_surface, &sample->xdg_shell->surfaces, link) { output_frame_handle_surface(sample, wlr_output, ts, - xdg_surface->surface); + xdg_surface->surface->resource); } struct wlr_x11_window *x11_window; wl_list_for_each(x11_window, &sample->xwayland->displayable_windows, link) { diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 6bc37940..27fafd2d 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -18,11 +18,12 @@ enum wlr_xdg_surface_v6_role { struct wlr_xdg_surface_v6 { struct wl_resource *resource; - struct wl_resource *surface; + struct wlr_surface *surface; struct wl_list link; enum wlr_xdg_surface_v6_role role; struct wl_listener surface_destroy_listener; + struct wl_listener surface_commit_listener; void *data; }; diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 2fff054d..70f22197 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -104,6 +104,7 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { wl_resource_set_user_data(surface->resource, NULL); wl_list_remove(&surface->link); wl_list_remove(&surface->surface_destroy_listener.link); + wl_list_remove(&surface->surface_commit_listener.link); free(surface); } @@ -118,9 +119,8 @@ static void xdg_surface_get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id) { // TODO: Flesh out struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - struct wlr_surface *wsurface = wl_resource_get_user_data(surface->surface); - if (wlr_surface_set_role(wsurface, wlr_desktop_xdg_toplevel_role, + if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_toplevel_role, resource, ZXDG_SHELL_V6_ERROR_ROLE)) { return; } @@ -173,6 +173,11 @@ static void handle_wlr_surface_destroyed(struct wl_listener *listener, xdg_surface_destroy(xdg_surface); } +static void handle_wlr_surface_committed(struct wl_listener *listener, + void *data) { + wlr_log(L_DEBUG, "TODO: handle wlr surface committed"); +} + static void xdg_shell_get_xdg_surface(struct wl_client *client, struct wl_resource *_xdg_shell, uint32_t id, struct wl_resource *_surface) { @@ -182,14 +187,18 @@ static void xdg_shell_get_xdg_surface(struct wl_client *client, return; } surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; - surface->surface = _surface; + surface->surface = wl_resource_get_user_data(_surface); surface->resource = wl_resource_create(client, &zxdg_surface_v6_interface, wl_resource_get_version(_xdg_shell), id); - wl_signal_add(&_surface->destroy_signal, + wl_signal_add(&surface->surface->signals.destroy, &surface->surface_destroy_listener); surface->surface_destroy_listener.notify = handle_wlr_surface_destroyed; + wl_signal_add(&surface->surface->signals.commit, + &surface->surface_commit_listener); + surface->surface_commit_listener.notify = handle_wlr_surface_committed; + wlr_log(L_DEBUG, "new xdg_surface %p (res %p)", surface, surface->resource); wl_resource_set_implementation(surface->resource, &zxdg_surface_v6_implementation, surface, xdg_surface_resource_destroy); From 2fd5c7999b1ecb93700ab6e61ae54f65e147518b Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 12 Sep 2017 06:36:16 -0400 Subject: [PATCH 06/20] set title and app_id --- include/wlr/types/wlr_xdg_shell_v6.h | 3 +++ types/wlr_xdg_shell_v6.c | 28 +++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 27fafd2d..a6e62628 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -22,6 +22,9 @@ struct wlr_xdg_surface_v6 { struct wl_list link; enum wlr_xdg_surface_v6_role role; + char *title; + char *app_id; + struct wl_listener surface_destroy_listener; struct wl_listener surface_commit_listener; diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 70f22197..3ed41ff3 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -1,5 +1,9 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif #include #include +#include #include #include #include @@ -21,12 +25,30 @@ static void xdg_toplevel_set_parent(struct wl_client *client, static void xdg_toplevel_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { - wlr_log(L_DEBUG, "TODO: toplevel set title"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + char *tmp; + + tmp = strdup(title); + if (tmp == NULL) { + return; + } + + free(surface->title); + surface->title = tmp; } static void xdg_toplevel_set_app_id(struct wl_client *client, struct wl_resource *resource, const char *app_id) { - wlr_log(L_DEBUG, "TODO: toplevel set app id"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + char *tmp; + + tmp = strdup(app_id); + if (tmp == NULL) { + return; + } + + free(surface->app_id); + surface->app_id = tmp; } static void xdg_toplevel_show_window_menu(struct wl_client *client, @@ -131,7 +153,7 @@ static void xdg_surface_get_toplevel(struct wl_client *client, &zxdg_toplevel_v6_interface, wl_resource_get_version(resource), id); wl_resource_set_implementation(toplevel_resource, - &zxdg_toplevel_v6_implementation, NULL, NULL); + &zxdg_toplevel_v6_implementation, surface, NULL); struct wl_display *display = wl_client_get_display(client); zxdg_surface_v6_send_configure(resource, wl_display_next_serial(display)); } From 353629b034654c686d0bf28c765a9e0160672310 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 13 Sep 2017 08:44:32 -0400 Subject: [PATCH 07/20] xdg-surface geometry --- include/wlr/types/wlr_xdg_shell_v6.h | 5 +++++ types/wlr_xdg_shell_v6.c | 33 ++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index a6e62628..0a060444 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -1,5 +1,6 @@ #ifndef _WLR_XDG_SHELL_V6_H #define _WLR_XDG_SHELL_V6_H +#include #include struct wlr_xdg_shell_v6 { @@ -25,6 +26,10 @@ struct wlr_xdg_surface_v6 { char *title; char *app_id; + bool has_next_geometry; + struct wlr_box *next_geometry; + struct wlr_box *geometry; + struct wl_listener surface_destroy_listener; struct wl_listener surface_commit_listener; diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 3ed41ff3..487ede3d 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -127,6 +127,8 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { wl_list_remove(&surface->link); wl_list_remove(&surface->surface_destroy_listener.link); wl_list_remove(&surface->surface_commit_listener.link); + free(surface->geometry); + free(surface->next_geometry); free(surface); } @@ -172,7 +174,12 @@ static void xdg_surface_ack_configure(struct wl_client *client, static void xdg_surface_set_window_geometry(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - wlr_log(L_DEBUG, "TODO xdg surface set window geometry"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->has_next_geometry = true; + surface->next_geometry->height = height; + surface->next_geometry->width = width; + surface->next_geometry->x = x; + surface->next_geometry->y = y; } static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation = { @@ -197,7 +204,17 @@ static void handle_wlr_surface_destroyed(struct wl_listener *listener, static void handle_wlr_surface_committed(struct wl_listener *listener, void *data) { - wlr_log(L_DEBUG, "TODO: handle wlr surface committed"); + + struct wlr_xdg_surface_v6 *surface = + wl_container_of(listener, surface, surface_commit_listener); + + if (surface->has_next_geometry) { + surface->has_next_geometry = false; + surface->geometry->x = surface->next_geometry->x; + surface->geometry->y = surface->next_geometry->y; + surface->geometry->width = surface->next_geometry->width; + surface->geometry->height = surface->next_geometry->height; + } } static void xdg_shell_get_xdg_surface(struct wl_client *client, @@ -208,6 +225,18 @@ static void xdg_shell_get_xdg_surface(struct wl_client *client, if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface_v6)))) { return; } + + if (!(surface->geometry = calloc(1, sizeof(struct wlr_box)))) { + free(surface); + return; + } + + if (!(surface->next_geometry = calloc(1, sizeof(struct wlr_box)))) { + free(surface->geometry); + free(surface); + return; + } + surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; surface->surface = wl_resource_get_user_data(_surface); surface->resource = wl_resource_create(client, From 50f4275298f2ece3de2a0de77b86414b4a0c5c91 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Wed, 13 Sep 2017 09:19:10 -0400 Subject: [PATCH 08/20] implement xdg-toplevel state properties --- include/wlr/types/wlr_xdg_shell_v6.h | 19 ++++++++++ types/wlr_xdg_shell_v6.c | 55 ++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 0a060444..890f404f 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -17,11 +17,30 @@ enum wlr_xdg_surface_v6_role { WLR_XDG_SURFACE_V6_ROLE_POPUP, }; +struct wlr_xdg_toplevel_v6_state { + bool maximized; + bool fullscreen; + bool resizing; + bool activated; + + uint32_t max_width; + uint32_t max_height; + + uint32_t min_width; + uint32_t min_height; +}; + +struct wlr_xdg_toplevel_v6 { + struct wlr_xdg_toplevel_v6_state next; + struct wlr_xdg_toplevel_v6_state current; +}; + struct wlr_xdg_surface_v6 { struct wl_resource *resource; struct wlr_surface *surface; struct wl_list link; enum wlr_xdg_surface_v6_role role; + struct wlr_xdg_toplevel_v6 *toplevel_state; char *title; char *app_id; diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 487ede3d..cc940997 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -71,37 +71,46 @@ static void xdg_toplevel_resize(struct wl_client *client, static void xdg_toplevel_set_max_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - wlr_log(L_DEBUG, "TODO: toplevel set max size"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.max_width = width; + surface->toplevel_state->next.max_height = height; } static void xdg_toplevel_set_min_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { - wlr_log(L_DEBUG, "TODO: toplevel set min size"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.min_width = width; + surface->toplevel_state->next.min_height = height; } static void xdg_toplevel_set_maximized(struct wl_client *client, struct wl_resource *resource) { - wlr_log(L_DEBUG, "TODO: toplevel set maximized"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.maximized = true; } static void xdg_toplevel_unset_maximized(struct wl_client *client, struct wl_resource *resource) { - wlr_log(L_DEBUG, "TODO: toplevel unset maximized"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.maximized = false; } static void xdg_toplevel_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { - wlr_log(L_DEBUG, "TODO: toplevel set fullscreen"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.fullscreen = true; } static void xdg_toplevel_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { - wlr_log(L_DEBUG, "TODO: toplevel unset fullscreen"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + surface->toplevel_state->next.fullscreen = false; } static void xdg_toplevel_set_minimized(struct wl_client *client, struct wl_resource *resource) { - wlr_log(L_DEBUG, "TODO: toplevel set minimized"); + // TODO event for minimization request + wlr_log(L_DEBUG, "TODO: xdg toplevel set minimized"); } static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = @@ -141,7 +150,6 @@ static void xdg_surface_resource_destroy(struct wl_resource *resource) { static void xdg_surface_get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id) { - // TODO: Flesh out struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); if (wlr_surface_set_role(surface->surface, wlr_desktop_xdg_toplevel_role, @@ -149,6 +157,11 @@ static void xdg_surface_get_toplevel(struct wl_client *client, return; } + if (!(surface->toplevel_state = + calloc(1, sizeof(struct wlr_xdg_toplevel_v6)))) { + return; + } + surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; struct wl_resource *toplevel_resource = wl_resource_create(client, @@ -202,6 +215,28 @@ static void handle_wlr_surface_destroyed(struct wl_listener *listener, xdg_surface_destroy(xdg_surface); } +static void wlr_xdg_surface_v6_toplevel_committed( + struct wlr_xdg_surface_v6 *surface) { + surface->toplevel_state->current.maximized = + surface->toplevel_state->next.maximized; + surface->toplevel_state->current.fullscreen = + surface->toplevel_state->next.fullscreen; + surface->toplevel_state->current.resizing = + surface->toplevel_state->next.resizing; + surface->toplevel_state->current.activated = + surface->toplevel_state->next.activated; + + surface->toplevel_state->current.max_width = + surface->toplevel_state->next.max_width; + surface->toplevel_state->current.max_height = + surface->toplevel_state->next.max_height; + + surface->toplevel_state->current.min_width = + surface->toplevel_state->next.min_width; + surface->toplevel_state->current.min_height = + surface->toplevel_state->next.min_height; +} + static void handle_wlr_surface_committed(struct wl_listener *listener, void *data) { @@ -215,6 +250,10 @@ static void handle_wlr_surface_committed(struct wl_listener *listener, surface->geometry->width = surface->next_geometry->width; surface->geometry->height = surface->next_geometry->height; } + + if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + wlr_xdg_surface_v6_toplevel_committed(surface); + } } static void xdg_shell_get_xdg_surface(struct wl_client *client, From 45a3b761a6058bb83f1a5ebfc18b517a680be659 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 14 Sep 2017 08:39:57 -0400 Subject: [PATCH 09/20] xdg-surface-v6: add events --- include/wlr/types/wlr_xdg_shell_v6.h | 6 ++++++ types/wlr_xdg_shell_v6.c | 11 +++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 890f404f..6e2f43c4 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -52,6 +52,12 @@ struct wlr_xdg_surface_v6 { struct wl_listener surface_destroy_listener; struct wl_listener surface_commit_listener; + struct { + struct wl_signal request_minimize; + struct wl_signal commit; + struct wl_signal destroy; + } events; + void *data; }; diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index cc940997..df01730f 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -109,8 +109,8 @@ static void xdg_toplevel_unset_fullscreen(struct wl_client *client, static void xdg_toplevel_set_minimized(struct wl_client *client, struct wl_resource *resource) { - // TODO event for minimization request - wlr_log(L_DEBUG, "TODO: xdg toplevel set minimized"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + wl_signal_emit(&surface->events.request_minimize, surface); } static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = @@ -132,6 +132,7 @@ static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = }; static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { + wl_signal_emit(&surface->events.destroy, surface); wl_resource_set_user_data(surface->resource, NULL); wl_list_remove(&surface->link); wl_list_remove(&surface->surface_destroy_listener.link); @@ -254,6 +255,8 @@ static void handle_wlr_surface_committed(struct wl_listener *listener, if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { wlr_xdg_surface_v6_toplevel_committed(surface); } + + wl_signal_emit(&surface->events.commit, surface); } static void xdg_shell_get_xdg_surface(struct wl_client *client, @@ -281,6 +284,10 @@ static void xdg_shell_get_xdg_surface(struct wl_client *client, surface->resource = wl_resource_create(client, &zxdg_surface_v6_interface, wl_resource_get_version(_xdg_shell), id); + wl_signal_init(&surface->events.request_minimize); + wl_signal_init(&surface->events.commit); + wl_signal_init(&surface->events.destroy); + wl_signal_add(&surface->surface->signals.destroy, &surface->surface_destroy_listener); surface->surface_destroy_listener.notify = handle_wlr_surface_destroyed; From a0bdbc92ba7059d3abaa69d170bf9ce5165d1795 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 14 Sep 2017 16:27:14 -0400 Subject: [PATCH 10/20] xdg-shell-toplevel configure requests --- include/wlr/types/wlr_xdg_shell_v6.h | 53 ++++- types/wlr_xdg_shell_v6.c | 294 ++++++++++++++++++++++----- 2 files changed, 299 insertions(+), 48 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 6e2f43c4..e13af137 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -23,6 +23,9 @@ struct wlr_xdg_toplevel_v6_state { bool resizing; bool activated; + uint32_t width; + uint32_t height; + uint32_t max_width; uint32_t max_height; @@ -31,17 +34,31 @@ struct wlr_xdg_toplevel_v6_state { }; struct wlr_xdg_toplevel_v6 { - struct wlr_xdg_toplevel_v6_state next; + struct wl_resource *resource; + struct wlr_xdg_surface_v6 *base; + struct wlr_xdg_toplevel_v6_state next; // client protocol requests + struct wlr_xdg_toplevel_v6_state pending; // user configure requests struct wlr_xdg_toplevel_v6_state current; }; +// TODO split up into toplevel and popup configure +struct wlr_xdg_surface_v6_configure { + struct wl_list link; // wlr_xdg_surface_v6::configure_list + uint32_t serial; + struct wlr_xdg_toplevel_v6_state *state; +}; + struct wlr_xdg_surface_v6 { + struct wl_client *client; struct wl_resource *resource; struct wlr_surface *surface; struct wl_list link; enum wlr_xdg_surface_v6_role role; struct wlr_xdg_toplevel_v6 *toplevel_state; + struct wl_event_source *configure_idle; + struct wl_list configure_list; + char *title; char *app_id; @@ -64,4 +81,38 @@ struct wlr_xdg_surface_v6 { struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display); void wlr_xdg_shell_v6_destroy(struct wlr_xdg_shell_v6 *xdg_shell); +/** + * Request that this toplevel surface be the given size. + */ +void wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, + uint32_t width, uint32_t height); + +/** + * Request that this toplevel surface show itself in an activated or deactivated + * state. + */ +void wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, + bool activated); + +/** + * Request that this toplevel surface consider itself maximized or not + * maximized. + */ +void wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, + bool maximized); + +/** + * Request that this toplevel surface consider itself fullscreen or not + * fullscreen. + */ +void wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, + bool fullscreen); + +/** + * Request that this toplevel surface consider itself to be resizing or not + * resizing. + */ +void wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, + bool resizing); + #endif diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index df01730f..71c5fb0a 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -18,12 +18,12 @@ static void resource_destroy(struct wl_client *client, wl_resource_destroy(resource); } -static void xdg_toplevel_set_parent(struct wl_client *client, +static void xdg_toplevel_protocol_set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource) { wlr_log(L_DEBUG, "TODO: toplevel set parent"); } -static void xdg_toplevel_set_title(struct wl_client *client, +static void xdg_toplevel_protocol_set_title(struct wl_client *client, struct wl_resource *resource, const char *title) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); char *tmp; @@ -37,7 +37,7 @@ static void xdg_toplevel_set_title(struct wl_client *client, surface->title = tmp; } -static void xdg_toplevel_set_app_id(struct wl_client *client, +static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, struct wl_resource *resource, const char *app_id) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); char *tmp; @@ -51,63 +51,63 @@ static void xdg_toplevel_set_app_id(struct wl_client *client, surface->app_id = tmp; } -static void xdg_toplevel_show_window_menu(struct wl_client *client, +static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, int32_t x, int32_t y) { wlr_log(L_DEBUG, "TODO: toplevel show window menu"); } -static void xdg_toplevel_move(struct wl_client *client, +static void xdg_toplevel_protocol_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { wlr_log(L_DEBUG, "TODO: toplevel move"); } -static void xdg_toplevel_resize(struct wl_client *client, +static void xdg_toplevel_protocol_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, uint32_t edges) { wlr_log(L_DEBUG, "TODO: toplevel resize"); } -static void xdg_toplevel_set_max_size(struct wl_client *client, +static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); surface->toplevel_state->next.max_width = width; surface->toplevel_state->next.max_height = height; } -static void xdg_toplevel_set_min_size(struct wl_client *client, +static void xdg_toplevel_protocol_set_min_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); surface->toplevel_state->next.min_width = width; surface->toplevel_state->next.min_height = height; } -static void xdg_toplevel_set_maximized(struct wl_client *client, +static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); surface->toplevel_state->next.maximized = true; } -static void xdg_toplevel_unset_maximized(struct wl_client *client, +static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); surface->toplevel_state->next.maximized = false; } -static void xdg_toplevel_set_fullscreen(struct wl_client *client, +static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); surface->toplevel_state->next.fullscreen = true; } -static void xdg_toplevel_unset_fullscreen(struct wl_client *client, +static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); surface->toplevel_state->next.fullscreen = false; } -static void xdg_toplevel_set_minimized(struct wl_client *client, +static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); wl_signal_emit(&surface->events.request_minimize, surface); @@ -116,19 +116,19 @@ static void xdg_toplevel_set_minimized(struct wl_client *client, static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation = { .destroy = resource_destroy, - .set_parent = xdg_toplevel_set_parent, - .set_title = xdg_toplevel_set_title, - .set_app_id = xdg_toplevel_set_app_id, - .show_window_menu = xdg_toplevel_show_window_menu, - .move = xdg_toplevel_move, - .resize = xdg_toplevel_resize, - .set_max_size = xdg_toplevel_set_max_size, - .set_min_size = xdg_toplevel_set_min_size, - .set_maximized = xdg_toplevel_set_maximized, - .unset_maximized = xdg_toplevel_unset_maximized, - .set_fullscreen = xdg_toplevel_set_fullscreen, - .unset_fullscreen = xdg_toplevel_unset_fullscreen, - .set_minimized = xdg_toplevel_set_minimized + .set_parent = xdg_toplevel_protocol_set_parent, + .set_title = xdg_toplevel_protocol_set_title, + .set_app_id = xdg_toplevel_protocol_set_app_id, + .show_window_menu = xdg_toplevel_protocol_show_window_menu, + .move = xdg_toplevel_protocol_move, + .resize = xdg_toplevel_protocol_resize, + .set_max_size = xdg_toplevel_protocol_set_max_size, + .set_min_size = xdg_toplevel_protocol_set_min_size, + .set_maximized = xdg_toplevel_protocol_set_maximized, + .unset_maximized = xdg_toplevel_protocol_unset_maximized, + .set_fullscreen = xdg_toplevel_protocol_set_fullscreen, + .unset_fullscreen = xdg_toplevel_protocol_unset_fullscreen, + .set_minimized = xdg_toplevel_protocol_set_minimized }; static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { @@ -164,14 +164,15 @@ static void xdg_surface_get_toplevel(struct wl_client *client, } surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; + surface->toplevel_state->base = surface; struct wl_resource *toplevel_resource = wl_resource_create(client, &zxdg_toplevel_v6_interface, wl_resource_get_version(resource), id); + surface->toplevel_state->resource = toplevel_resource; + wl_resource_set_implementation(toplevel_resource, &zxdg_toplevel_v6_implementation, surface, NULL); - struct wl_display *display = wl_client_get_display(client); - zxdg_surface_v6_send_configure(resource, wl_display_next_serial(display)); } static void xdg_surface_get_popup(struct wl_client *client, @@ -180,9 +181,64 @@ static void xdg_surface_get_popup(struct wl_client *client, wlr_log(L_DEBUG, "TODO xdg surface get popup"); } +static void copy_toplevel_state(struct wlr_xdg_toplevel_v6_state *src, + struct wlr_xdg_toplevel_v6_state *dest) { + dest->width = src->width; + dest->height = src->height; + dest->max_width = src->max_width; + dest->max_height = src->max_height; + dest->min_width = src->min_width; + dest->min_height = src->min_height; + + dest->fullscreen = src->fullscreen; + dest->resizing = src->resizing; + dest->activated = src->activated; + dest->maximized = src->maximized; +} + +static void wlr_xdg_toplevel_v6_ack_configure( + struct wlr_xdg_surface_v6 *surface, + struct wlr_xdg_surface_v6_configure *configure) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + copy_toplevel_state(configure->state, &surface->toplevel_state->next); +} + static void xdg_surface_ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { wlr_log(L_DEBUG, "TODO xdg surface ack configure"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + + // TODO handle popups + if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + return; + } + + bool found = false; + struct wlr_xdg_surface_v6_configure *configure, *tmp; + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { + if (configure->serial < serial) { + wl_list_remove(&configure->link); + free(configure); + } else if (configure->serial == serial) { + wl_list_remove(&configure->link); + found = true; + break; + } else { + break; + } + } + if (!found) { + // TODO post error on the client resource + return; + } + + // TODO handle popups + if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + wlr_xdg_toplevel_v6_ack_configure(surface, configure); + } + + // TODO send ack_configure event? + free(configure); } static void xdg_surface_set_window_geometry(struct wl_client *client, @@ -218,29 +274,12 @@ static void handle_wlr_surface_destroyed(struct wl_listener *listener, static void wlr_xdg_surface_v6_toplevel_committed( struct wlr_xdg_surface_v6 *surface) { - surface->toplevel_state->current.maximized = - surface->toplevel_state->next.maximized; - surface->toplevel_state->current.fullscreen = - surface->toplevel_state->next.fullscreen; - surface->toplevel_state->current.resizing = - surface->toplevel_state->next.resizing; - surface->toplevel_state->current.activated = - surface->toplevel_state->next.activated; - - surface->toplevel_state->current.max_width = - surface->toplevel_state->next.max_width; - surface->toplevel_state->current.max_height = - surface->toplevel_state->next.max_height; - - surface->toplevel_state->current.min_width = - surface->toplevel_state->next.min_width; - surface->toplevel_state->current.min_height = - surface->toplevel_state->next.min_height; + copy_toplevel_state(&surface->toplevel_state->next, + &surface->toplevel_state->current); } static void handle_wlr_surface_committed(struct wl_listener *listener, void *data) { - struct wlr_xdg_surface_v6 *surface = wl_container_of(listener, surface, surface_commit_listener); @@ -279,11 +318,14 @@ static void xdg_shell_get_xdg_surface(struct wl_client *client, return; } + surface->client = client; surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; surface->surface = wl_resource_get_user_data(_surface); surface->resource = wl_resource_create(client, &zxdg_surface_v6_interface, wl_resource_get_version(_xdg_shell), id); + wl_list_init(&surface->configure_list); + wl_signal_init(&surface->events.request_minimize); wl_signal_init(&surface->events.commit); wl_signal_init(&surface->events.destroy); @@ -366,3 +408,161 @@ void wlr_xdg_shell_v6_destroy(struct wlr_xdg_shell_v6 *xdg_shell) { // wl_global_destroy(xdg_shell->wl_global); free(xdg_shell); } + +static bool wlr_xdg_surface_v6_toplevel_state_compare( + struct wlr_xdg_toplevel_v6 *state) { + // is pending state different from current state? + if (state->pending.activated != state->current.activated) { + return false; + } + if (state->pending.fullscreen != state->current.fullscreen) { + return false; + } + if (state->pending.maximized != state->current.maximized) { + return false; + } + if (state->pending.resizing != state->current.resizing) { + return false; + } + + if ((uint32_t)state->base->geometry->width == state->pending.width && + (uint32_t)state->base->geometry->height == state->pending.height) { + return true; + } + + if (state->pending.width == 0 && state->pending.height == 0) { + return true; + } + + return false; +} + +static void wlr_xdg_toplevel_v6_send_configure( + struct wlr_xdg_surface_v6 *surface, + struct wlr_xdg_surface_v6_configure *configure) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + uint32_t *s; + struct wl_array states; + + configure->state = &surface->toplevel_state->pending; + + wl_array_init(&states); + if (surface->toplevel_state->pending.maximized) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; + } + if (surface->toplevel_state->pending.fullscreen) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; + } + if (surface->toplevel_state->pending.resizing) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; + } + if (surface->toplevel_state->pending.activated) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; + } + + zxdg_toplevel_v6_send_configure(surface->toplevel_state->resource, + surface->toplevel_state->pending.width, + surface->toplevel_state->pending.height, + &states); + + wl_array_release(&states); +} + +static void wlr_xdg_surface_send_configure(void *user_data) { + struct wlr_xdg_surface_v6 *surface = user_data; + struct wl_display *display = wl_client_get_display(surface->client); + + // TODO handle popups + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + + surface->configure_idle = NULL; + + // TODO handle no memory + struct wlr_xdg_surface_v6_configure *configure = + calloc(1, sizeof(struct wlr_xdg_surface_v6_configure)); + wl_list_insert(surface->configure_list.prev, &configure->link); + configure->serial = wl_display_next_serial(display); + + wlr_xdg_toplevel_v6_send_configure(surface, configure); + + zxdg_surface_v6_send_configure(surface->resource, configure->serial); +} + +static void wlr_xdg_surface_v6_schedule_configure( + struct wlr_xdg_surface_v6 *surface) { + // TODO handle popups + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + + struct wl_display *display = wl_client_get_display(surface->client); + struct wl_event_loop *loop = wl_display_get_event_loop(display); + + bool pending_same = + wlr_xdg_surface_v6_toplevel_state_compare(surface->toplevel_state); + + if (surface->configure_idle != NULL) { + if (!pending_same) { + // configure request already scheduled + return; + } + + // configure request not necessary anymore + wl_event_source_remove(surface->configure_idle); + surface->configure_idle = NULL; + } else { + if (pending_same) { + // configure request not necessary + return; + } + + surface->configure_idle = + wl_event_loop_add_idle( + loop, + wlr_xdg_surface_send_configure, + surface); + } +} + +void wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, + uint32_t width, uint32_t height) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + surface->toplevel_state->pending.width = width; + surface->toplevel_state->pending.height = height; + + wlr_xdg_surface_v6_schedule_configure(surface); +} + +void wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, + bool activated) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + surface->toplevel_state->pending.activated = activated; + + wlr_xdg_surface_v6_schedule_configure(surface); +} + +void wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, + bool maximized) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + surface->toplevel_state->pending.maximized = maximized; + + wlr_xdg_surface_v6_schedule_configure(surface); +} + +void wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, + bool fullscreen) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + surface->toplevel_state->pending.fullscreen = fullscreen; + + wlr_xdg_surface_v6_schedule_configure(surface); +} + +void wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, + bool resizing) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + surface->toplevel_state->pending.fullscreen = resizing; + + wlr_xdg_surface_v6_schedule_configure(surface); +} From 569b147bba41d009a95c1e80c7dbb342f25bf9af Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 15 Sep 2017 07:50:13 -0400 Subject: [PATCH 11/20] schedule configure request on toplevel first commit --- include/wlr/types/wlr_xdg_shell_v6.h | 1 + types/wlr_xdg_shell_v6.c | 252 ++++++++++++++------------- 2 files changed, 131 insertions(+), 122 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index e13af137..a4afaf3b 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -36,6 +36,7 @@ struct wlr_xdg_toplevel_v6_state { struct wlr_xdg_toplevel_v6 { struct wl_resource *resource; struct wlr_xdg_surface_v6 *base; + bool added; struct wlr_xdg_toplevel_v6_state next; // client protocol requests struct wlr_xdg_toplevel_v6_state pending; // user configure requests struct wlr_xdg_toplevel_v6_state current; diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 71c5fb0a..11b44d6d 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -265,6 +265,123 @@ static void xdg_shell_create_positioner(struct wl_client *client, wlr_log(L_DEBUG, "TODO: xdg shell create positioner"); } +static bool wlr_xdg_surface_v6_toplevel_state_compare( + struct wlr_xdg_toplevel_v6 *state) { + // is pending state different from current state? + if (state->pending.activated != state->current.activated) { + return false; + } + if (state->pending.fullscreen != state->current.fullscreen) { + return false; + } + if (state->pending.maximized != state->current.maximized) { + return false; + } + if (state->pending.resizing != state->current.resizing) { + return false; + } + + if ((uint32_t)state->base->geometry->width == state->pending.width && + (uint32_t)state->base->geometry->height == state->pending.height) { + return true; + } + + if (state->pending.width == 0 && state->pending.height == 0) { + return true; + } + + return false; +} + +static void wlr_xdg_toplevel_v6_send_configure( + struct wlr_xdg_surface_v6 *surface, + struct wlr_xdg_surface_v6_configure *configure) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + uint32_t *s; + struct wl_array states; + + configure->state = &surface->toplevel_state->pending; + + wl_array_init(&states); + if (surface->toplevel_state->pending.maximized) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; + } + if (surface->toplevel_state->pending.fullscreen) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; + } + if (surface->toplevel_state->pending.resizing) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; + } + if (surface->toplevel_state->pending.activated) { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; + } + + zxdg_toplevel_v6_send_configure(surface->toplevel_state->resource, + surface->toplevel_state->pending.width, + surface->toplevel_state->pending.height, + &states); + + wl_array_release(&states); +} + +static void wlr_xdg_surface_send_configure(void *user_data) { + struct wlr_xdg_surface_v6 *surface = user_data; + struct wl_display *display = wl_client_get_display(surface->client); + + // TODO handle popups + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + + surface->configure_idle = NULL; + + // TODO handle no memory + struct wlr_xdg_surface_v6_configure *configure = + calloc(1, sizeof(struct wlr_xdg_surface_v6_configure)); + wl_list_insert(surface->configure_list.prev, &configure->link); + configure->serial = wl_display_next_serial(display); + + wlr_xdg_toplevel_v6_send_configure(surface, configure); + + zxdg_surface_v6_send_configure(surface->resource, configure->serial); +} + +static void wlr_xdg_surface_v6_schedule_configure( + struct wlr_xdg_surface_v6 *surface, bool force) { + // TODO handle popups + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + + struct wl_display *display = wl_client_get_display(surface->client); + struct wl_event_loop *loop = wl_display_get_event_loop(display); + + bool pending_same = !force && + wlr_xdg_surface_v6_toplevel_state_compare(surface->toplevel_state); + + if (surface->configure_idle != NULL) { + if (!pending_same) { + // configure request already scheduled + return; + } + + // configure request not necessary anymore + wl_event_source_remove(surface->configure_idle); + surface->configure_idle = NULL; + } else { + if (pending_same) { + // configure request not necessary + return; + } + + surface->configure_idle = + wl_event_loop_add_idle( + loop, + wlr_xdg_surface_send_configure, + surface); + } +} + static void handle_wlr_surface_destroyed(struct wl_listener *listener, void *data) { struct wlr_xdg_surface_v6 *xdg_surface = @@ -274,6 +391,14 @@ static void handle_wlr_surface_destroyed(struct wl_listener *listener, static void wlr_xdg_surface_v6_toplevel_committed( struct wlr_xdg_surface_v6 *surface) { + if (!surface->toplevel_state->added) { + // on the first commit, send a configure request to tell the client it + // is added + wlr_xdg_surface_v6_schedule_configure(surface, true); + surface->toplevel_state->added = true; + return; + } + copy_toplevel_state(&surface->toplevel_state->next, &surface->toplevel_state->current); } @@ -409,130 +534,13 @@ void wlr_xdg_shell_v6_destroy(struct wlr_xdg_shell_v6 *xdg_shell) { free(xdg_shell); } -static bool wlr_xdg_surface_v6_toplevel_state_compare( - struct wlr_xdg_toplevel_v6 *state) { - // is pending state different from current state? - if (state->pending.activated != state->current.activated) { - return false; - } - if (state->pending.fullscreen != state->current.fullscreen) { - return false; - } - if (state->pending.maximized != state->current.maximized) { - return false; - } - if (state->pending.resizing != state->current.resizing) { - return false; - } - - if ((uint32_t)state->base->geometry->width == state->pending.width && - (uint32_t)state->base->geometry->height == state->pending.height) { - return true; - } - - if (state->pending.width == 0 && state->pending.height == 0) { - return true; - } - - return false; -} - -static void wlr_xdg_toplevel_v6_send_configure( - struct wlr_xdg_surface_v6 *surface, - struct wlr_xdg_surface_v6_configure *configure) { - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - uint32_t *s; - struct wl_array states; - - configure->state = &surface->toplevel_state->pending; - - wl_array_init(&states); - if (surface->toplevel_state->pending.maximized) { - s = wl_array_add(&states, sizeof(uint32_t)); - *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; - } - if (surface->toplevel_state->pending.fullscreen) { - s = wl_array_add(&states, sizeof(uint32_t)); - *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; - } - if (surface->toplevel_state->pending.resizing) { - s = wl_array_add(&states, sizeof(uint32_t)); - *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; - } - if (surface->toplevel_state->pending.activated) { - s = wl_array_add(&states, sizeof(uint32_t)); - *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; - } - - zxdg_toplevel_v6_send_configure(surface->toplevel_state->resource, - surface->toplevel_state->pending.width, - surface->toplevel_state->pending.height, - &states); - - wl_array_release(&states); -} - -static void wlr_xdg_surface_send_configure(void *user_data) { - struct wlr_xdg_surface_v6 *surface = user_data; - struct wl_display *display = wl_client_get_display(surface->client); - - // TODO handle popups - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - - surface->configure_idle = NULL; - - // TODO handle no memory - struct wlr_xdg_surface_v6_configure *configure = - calloc(1, sizeof(struct wlr_xdg_surface_v6_configure)); - wl_list_insert(surface->configure_list.prev, &configure->link); - configure->serial = wl_display_next_serial(display); - - wlr_xdg_toplevel_v6_send_configure(surface, configure); - - zxdg_surface_v6_send_configure(surface->resource, configure->serial); -} - -static void wlr_xdg_surface_v6_schedule_configure( - struct wlr_xdg_surface_v6 *surface) { - // TODO handle popups - assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - - struct wl_display *display = wl_client_get_display(surface->client); - struct wl_event_loop *loop = wl_display_get_event_loop(display); - - bool pending_same = - wlr_xdg_surface_v6_toplevel_state_compare(surface->toplevel_state); - - if (surface->configure_idle != NULL) { - if (!pending_same) { - // configure request already scheduled - return; - } - - // configure request not necessary anymore - wl_event_source_remove(surface->configure_idle); - surface->configure_idle = NULL; - } else { - if (pending_same) { - // configure request not necessary - return; - } - - surface->configure_idle = - wl_event_loop_add_idle( - loop, - wlr_xdg_surface_send_configure, - surface); - } -} - void wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, uint32_t width, uint32_t height) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); surface->toplevel_state->pending.width = width; surface->toplevel_state->pending.height = height; - wlr_xdg_surface_v6_schedule_configure(surface); + wlr_xdg_surface_v6_schedule_configure(surface, false); } void wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, @@ -540,7 +548,7 @@ void wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface, assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); surface->toplevel_state->pending.activated = activated; - wlr_xdg_surface_v6_schedule_configure(surface); + wlr_xdg_surface_v6_schedule_configure(surface, false); } void wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, @@ -548,7 +556,7 @@ void wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface, assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); surface->toplevel_state->pending.maximized = maximized; - wlr_xdg_surface_v6_schedule_configure(surface); + wlr_xdg_surface_v6_schedule_configure(surface, false); } void wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, @@ -556,7 +564,7 @@ void wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface, assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); surface->toplevel_state->pending.fullscreen = fullscreen; - wlr_xdg_surface_v6_schedule_configure(surface); + wlr_xdg_surface_v6_schedule_configure(surface, false); } void wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, @@ -564,5 +572,5 @@ void wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); surface->toplevel_state->pending.fullscreen = resizing; - wlr_xdg_surface_v6_schedule_configure(surface); + wlr_xdg_surface_v6_schedule_configure(surface, false); } From 27161a673f2b4bcc6db47759d035881985758001 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 15 Sep 2017 08:53:08 -0400 Subject: [PATCH 12/20] xdg-shell new surface and ack configure events --- examples/compositor.c | 19 +++++++++++++++++++ include/wlr/types/wlr_xdg_shell_v6.h | 7 +++++++ types/wlr_xdg_shell_v6.c | 15 +++++++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/examples/compositor.c b/examples/compositor.c index 9d96b053..841407bf 100644 --- a/examples/compositor.c +++ b/examples/compositor.c @@ -56,6 +56,8 @@ struct sample_state { struct wl_listener cursor_motion_absolute; struct wl_listener cursor_button; struct wl_listener cursor_axis; + + struct wl_listener new_xdg_surface_v6; }; /* @@ -85,6 +87,15 @@ static void output_frame_handle_surface(struct sample_state *sample, } } } + +static void handle_new_xdg_surface_v6(struct wl_listener *listener, + void *data) { + struct wlr_xdg_surface_v6 *surface = data; + wlr_log(L_DEBUG, "new xdg surface: title=%s, app_id=%s", + surface->title, surface->app_id); + // configure the surface and add it to data structures here +} + static void handle_output_frame(struct output_state *output, struct timespec *ts) { struct compositor_state *state = output->compositor; @@ -309,6 +320,12 @@ int main(int argc, char *argv[]) { state.wl_shell = wlr_wl_shell_create(compositor.display); state.xdg_shell = wlr_xdg_shell_v6_create(compositor.display); + // shell events + wl_signal_add(&state.xdg_shell->events.new_surface, + &state.new_xdg_surface_v6); + state.new_xdg_surface_v6.notify = handle_new_xdg_surface_v6; + + state.data_device_manager = wlr_data_device_manager_create(compositor.display); @@ -341,6 +358,8 @@ int main(int argc, char *argv[]) { wl_display_run(compositor.display); + wl_list_remove(&state.new_xdg_surface_v6.link); + wlr_xwayland_destroy(state.xwayland); close(state.keymap_fd); wlr_seat_destroy(state.wl_seat); diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index a4afaf3b..7c912370 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -8,6 +8,10 @@ struct wlr_xdg_shell_v6 { struct wl_list wl_resources; struct wl_list surfaces; + struct { + struct wl_signal new_surface; + } events; + void *data; }; @@ -53,10 +57,12 @@ struct wlr_xdg_surface_v6 { struct wl_client *client; struct wl_resource *resource; struct wlr_surface *surface; + struct wlr_xdg_shell_v6 *shell; struct wl_list link; enum wlr_xdg_surface_v6_role role; struct wlr_xdg_toplevel_v6 *toplevel_state; + bool configured; struct wl_event_source *configure_idle; struct wl_list configure_list; @@ -74,6 +80,7 @@ struct wlr_xdg_surface_v6 { struct wl_signal request_minimize; struct wl_signal commit; struct wl_signal destroy; + struct wl_signal ack_configure; } events; void *data; diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 11b44d6d..d32990db 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -205,7 +205,6 @@ static void wlr_xdg_toplevel_v6_ack_configure( static void xdg_surface_ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { - wlr_log(L_DEBUG, "TODO xdg surface ack configure"); struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); // TODO handle popups @@ -237,7 +236,13 @@ static void xdg_surface_ack_configure(struct wl_client *client, wlr_xdg_toplevel_v6_ack_configure(surface, configure); } - // TODO send ack_configure event? + if (!surface->configured) { + surface->configured = true; + wl_signal_emit(&surface->shell->events.new_surface, surface); + } + + wl_signal_emit(&surface->events.ack_configure, surface); + free(configure); } @@ -444,6 +449,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *client, } surface->client = client; + surface->shell = xdg_shell; surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; surface->surface = wl_resource_get_user_data(_surface); surface->resource = wl_resource_create(client, @@ -454,6 +460,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *client, wl_signal_init(&surface->events.request_minimize); wl_signal_init(&surface->events.commit); wl_signal_init(&surface->events.destroy); + wl_signal_init(&surface->events.ack_configure); wl_signal_add(&surface->surface->signals.destroy, &surface->surface_destroy_listener); @@ -514,8 +521,12 @@ struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) { return NULL; } xdg_shell->wl_global = wl_global; + + wl_signal_init(&xdg_shell->events.new_surface); + wl_list_init(&xdg_shell->wl_resources); wl_list_init(&xdg_shell->surfaces); + return xdg_shell; } From 0f865c547aa619dcab2ceb591b8d2b3d94832846 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 16 Sep 2017 08:31:08 -0400 Subject: [PATCH 13/20] xdg-toplevel-v6: seat events --- include/wlr/types/wlr_xdg_shell_v6.h | 30 +++++++++++- types/wlr_xdg_shell_v6.c | 71 ++++++++++++++++++++++++++-- 2 files changed, 95 insertions(+), 6 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 7c912370..3e404b6d 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -77,15 +77,43 @@ struct wlr_xdg_surface_v6 { struct wl_listener surface_commit_listener; struct { - struct wl_signal request_minimize; struct wl_signal commit; struct wl_signal destroy; struct wl_signal ack_configure; + + struct wl_signal request_minimize; + struct wl_signal request_move; + struct wl_signal request_resize; + struct wl_signal request_show_window_menu; } events; void *data; }; +struct wlr_xdg_toplevel_v6_move_event { + struct wl_client *client; + struct wlr_xdg_surface_v6 *surface; + struct wlr_seat_handle *seat_handle; + uint32_t serial; +}; + +struct wlr_xdg_toplevel_v6_resize_event { + struct wl_client *client; + struct wlr_xdg_surface_v6 *surface; + struct wlr_seat_handle *seat_handle; + uint32_t serial; + uint32_t edges; +}; + +struct wlr_xdg_toplevel_v6_show_window_menu_event { + struct wl_client *client; + struct wlr_xdg_surface_v6 *surface; + struct wlr_seat_handle *seat_handle; + uint32_t serial; + uint32_t x; + uint32_t y; +}; + struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display); void wlr_xdg_shell_v6_destroy(struct wlr_xdg_shell_v6 *xdg_shell); diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index d32990db..8c101020 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "xdg-shell-unstable-v6-protocol.h" @@ -52,21 +53,78 @@ static void xdg_toplevel_protocol_set_app_id(struct wl_client *client, } static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, - struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, - int32_t x, int32_t y) { - wlr_log(L_DEBUG, "TODO: toplevel show window menu"); + struct wl_resource *resource, struct wl_resource *seat_resource, + uint32_t serial, int32_t x, int32_t y) { + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_seat_handle *seat_handle = + wl_resource_get_user_data(seat_resource); + + struct wlr_xdg_toplevel_v6_show_window_menu_event *event = + calloc(1, sizeof(struct wlr_xdg_toplevel_v6_show_window_menu_event)); + if (event == NULL) { + wl_client_post_no_memory(client); + return; + } + + event->client = client; + event->surface = surface; + event->seat_handle = seat_handle; + event->serial = serial; + event->x = x; + event->y = y; + + wl_signal_emit(&surface->events.request_show_window_menu, event); + + free(event); } static void xdg_toplevel_protocol_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { - wlr_log(L_DEBUG, "TODO: toplevel move"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_seat_handle *seat_handle = + wl_resource_get_user_data(seat_resource); + + struct wlr_xdg_toplevel_v6_move_event *event = + calloc(1, sizeof(struct wlr_xdg_toplevel_v6_move_event)); + if (event == NULL) { + wl_client_post_no_memory(client); + return; + } + + event->client = client; + event->surface = surface; + event->seat_handle = seat_handle; + event->serial = serial; + + wl_signal_emit(&surface->events.request_move, event); + + free(event); } static void xdg_toplevel_protocol_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, uint32_t edges) { - wlr_log(L_DEBUG, "TODO: toplevel resize"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_seat_handle *seat_handle = + wl_resource_get_user_data(seat_resource); + + struct wlr_xdg_toplevel_v6_resize_event *event = + calloc(1, sizeof(struct wlr_xdg_toplevel_v6_resize_event)); + if (event == NULL) { + wl_client_post_no_memory(client); + return; + } + + event->client = client; + event->surface = surface; + event->seat_handle = seat_handle; + event->serial = serial; + event->edges = edges; + + wl_signal_emit(&surface->events.request_resize, event); + + free(event); } static void xdg_toplevel_protocol_set_max_size(struct wl_client *client, @@ -458,6 +516,9 @@ static void xdg_shell_get_xdg_surface(struct wl_client *client, wl_list_init(&surface->configure_list); wl_signal_init(&surface->events.request_minimize); + wl_signal_init(&surface->events.request_move); + wl_signal_init(&surface->events.request_resize); + wl_signal_init(&surface->events.request_show_window_menu); wl_signal_init(&surface->events.commit); wl_signal_init(&surface->events.destroy); wl_signal_init(&surface->events.ack_configure); From c912de6390299aeadb871b52bd3ee8ae984d91ca Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 16 Sep 2017 09:13:00 -0400 Subject: [PATCH 14/20] compositor.c: implement xdg-toplevel-v6 request events --- examples/compositor.c | 87 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/examples/compositor.c b/examples/compositor.c index 841407bf..4ddb6565 100644 --- a/examples/compositor.c +++ b/examples/compositor.c @@ -60,6 +60,16 @@ struct sample_state { struct wl_listener new_xdg_surface_v6; }; +struct example_xdg_surface_v6 { + struct wlr_xdg_surface_v6 *surface; + + struct wl_listener destroy_listener; + struct wl_listener request_minimize_listener; + struct wl_listener request_move_listener; + struct wl_listener request_resize_listener; + struct wl_listener request_show_window_menu_listener; +}; + /* * Convert timespec to milliseconds */ @@ -88,12 +98,87 @@ static void output_frame_handle_surface(struct sample_state *sample, } } +static void handle_xdg_surface_v6_destroy(struct wl_listener *listener, + void *data) { + struct example_xdg_surface_v6 *example_surface = + wl_container_of(listener, example_surface, destroy_listener); + wl_list_remove(&example_surface->destroy_listener.link); + wl_list_remove(&example_surface->request_move_listener.link); + wl_list_remove(&example_surface->request_resize_listener.link); + wl_list_remove(&example_surface->request_show_window_menu_listener.link); + wl_list_remove(&example_surface->request_minimize_listener.link); + free(example_surface); +} + +static void handle_xdg_surface_v6_request_move(struct wl_listener *listener, + void *data) { + struct example_xdg_surface_v6 *example_surface = + wl_container_of(listener, example_surface, request_move_listener); + struct wlr_xdg_toplevel_v6_move_event *e = data; + wlr_log(L_DEBUG, "TODO: surface requested move: %s", e->surface->title); +} + +static void handle_xdg_surface_v6_request_resize(struct wl_listener *listener, + void *data) { + struct example_xdg_surface_v6 *example_surface = + wl_container_of(listener, example_surface, request_resize_listener); + struct wlr_xdg_toplevel_v6_resize_event *e = data; + wlr_log(L_DEBUG, "TODO: surface requested resize: %s", e->surface->title); +} + +static void handle_xdg_surface_v6_request_show_window_menu( + struct wl_listener *listener, void *data) { + struct example_xdg_surface_v6 *example_surface = + wl_container_of(listener, example_surface, + request_show_window_menu_listener); + struct wlr_xdg_toplevel_v6_show_window_menu_event *e = data; + wlr_log(L_DEBUG, "TODO: surface requested to show window menu: %s", + e->surface->title); +} + +static void handle_xdg_surface_v6_request_minimize( + struct wl_listener *listener, void *data) { + struct example_xdg_surface_v6 *example_surface = + wl_container_of(listener, example_surface, request_minimize_listener); + wlr_log(L_DEBUG, "TODO: surface requested to be minimized: %s", + example_surface->surface->title); +} + static void handle_new_xdg_surface_v6(struct wl_listener *listener, void *data) { struct wlr_xdg_surface_v6 *surface = data; wlr_log(L_DEBUG, "new xdg surface: title=%s, app_id=%s", surface->title, surface->app_id); - // configure the surface and add it to data structures here + + struct example_xdg_surface_v6 *esurface = + calloc(1, sizeof(struct example_xdg_surface_v6)); + if (esurface == NULL) { + return; + } + + esurface->surface = surface; + + wl_signal_add(&surface->events.destroy, &esurface->destroy_listener); + esurface->destroy_listener.notify = handle_xdg_surface_v6_destroy; + + wl_signal_add(&surface->events.request_move, + &esurface->request_move_listener); + esurface->request_move_listener.notify = handle_xdg_surface_v6_request_move; + + wl_signal_add(&surface->events.request_resize, + &esurface->request_resize_listener); + esurface->request_resize_listener.notify = + handle_xdg_surface_v6_request_resize; + + wl_signal_add(&surface->events.request_show_window_menu, + &esurface->request_show_window_menu_listener); + esurface->request_show_window_menu_listener.notify = + handle_xdg_surface_v6_request_show_window_menu; + + wl_signal_add(&surface->events.request_minimize, + &esurface->request_minimize_listener); + esurface->request_minimize_listener.notify = + handle_xdg_surface_v6_request_minimize; } static void handle_output_frame(struct output_state *output, From 94f4f1878dd035ba1be6bf49ce7c41e45581ea94 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 16 Sep 2017 12:35:49 -0400 Subject: [PATCH 15/20] xdg-surface-v6: implement ping --- examples/compositor.c | 23 ++++- include/wlr/types/wlr_xdg_shell_v6.h | 29 +++++- types/wlr_xdg_shell_v6.c | 132 +++++++++++++++++++++------ 3 files changed, 146 insertions(+), 38 deletions(-) diff --git a/examples/compositor.c b/examples/compositor.c index 4ddb6565..fb5d8dfd 100644 --- a/examples/compositor.c +++ b/examples/compositor.c @@ -64,6 +64,7 @@ struct example_xdg_surface_v6 { struct wlr_xdg_surface_v6 *surface; struct wl_listener destroy_listener; + struct wl_listener ping_timeout_listener; struct wl_listener request_minimize_listener; struct wl_listener request_move_listener; struct wl_listener request_resize_listener; @@ -98,11 +99,18 @@ static void output_frame_handle_surface(struct sample_state *sample, } } +static void handle_xdg_surface_v6_ping_timeout(struct wl_listener *listener, + void *data) { + struct wlr_xdg_surface_v6 *surface = data; + wlr_log(L_DEBUG, "got ping timeout for surface: %s", surface->title); +} + static void handle_xdg_surface_v6_destroy(struct wl_listener *listener, void *data) { struct example_xdg_surface_v6 *example_surface = wl_container_of(listener, example_surface, destroy_listener); wl_list_remove(&example_surface->destroy_listener.link); + wl_list_remove(&example_surface->ping_timeout_listener.link); wl_list_remove(&example_surface->request_move_listener.link); wl_list_remove(&example_surface->request_resize_listener.link); wl_list_remove(&example_surface->request_show_window_menu_listener.link); @@ -150,6 +158,8 @@ static void handle_new_xdg_surface_v6(struct wl_listener *listener, wlr_log(L_DEBUG, "new xdg surface: title=%s, app_id=%s", surface->title, surface->app_id); + wlr_xdg_surface_v6_ping(surface); + struct example_xdg_surface_v6 *esurface = calloc(1, sizeof(struct example_xdg_surface_v6)); if (esurface == NULL) { @@ -161,6 +171,10 @@ static void handle_new_xdg_surface_v6(struct wl_listener *listener, wl_signal_add(&surface->events.destroy, &esurface->destroy_listener); esurface->destroy_listener.notify = handle_xdg_surface_v6_destroy; + wl_signal_add(&surface->events.ping_timeout, + &esurface->ping_timeout_listener); + esurface->ping_timeout_listener.notify = handle_xdg_surface_v6_ping_timeout; + wl_signal_add(&surface->events.request_move, &esurface->request_move_listener); esurface->request_move_listener.notify = handle_xdg_surface_v6_request_move; @@ -196,9 +210,12 @@ static void handle_output_frame(struct output_state *output, wl_shell_surface->surface); } struct wlr_xdg_surface_v6 *xdg_surface; - wl_list_for_each(xdg_surface, &sample->xdg_shell->surfaces, link) { - output_frame_handle_surface(sample, wlr_output, ts, - xdg_surface->surface->resource); + struct wlr_xdg_client_v6 *xdg_client; + wl_list_for_each(xdg_client, &sample->xdg_shell->clients, link) { + wl_list_for_each(xdg_surface, &xdg_client->surfaces, link) { + output_frame_handle_surface(sample, wlr_output, ts, + xdg_surface->surface->resource); + } } struct wlr_x11_window *x11_window; wl_list_for_each(x11_window, &sample->xwayland->displayable_windows, link) { diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 3e404b6d..f57dde10 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -5,8 +5,8 @@ struct wlr_xdg_shell_v6 { struct wl_global *wl_global; - struct wl_list wl_resources; - struct wl_list surfaces; + struct wl_list clients; + uint32_t ping_timeout; struct { struct wl_signal new_surface; @@ -15,6 +15,19 @@ struct wlr_xdg_shell_v6 { void *data; }; +struct wlr_xdg_client_v6 { + struct wlr_xdg_shell_v6 *shell; + struct wl_resource *resource; + struct wl_client *client; + struct wl_list surfaces; + + struct wl_list link; // wlr_xdg_shell_v6::clients + + uint32_t ping_serial; + struct wl_event_source *ping_timer; +}; + + enum wlr_xdg_surface_v6_role { WLR_XDG_SURFACE_V6_ROLE_NONE, WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL, @@ -54,11 +67,10 @@ struct wlr_xdg_surface_v6_configure { }; struct wlr_xdg_surface_v6 { - struct wl_client *client; + struct wlr_xdg_client_v6 *client; struct wl_resource *resource; struct wlr_surface *surface; - struct wlr_xdg_shell_v6 *shell; - struct wl_list link; + struct wl_list link; // wlr_xdg_client_v6::surfaces enum wlr_xdg_surface_v6_role role; struct wlr_xdg_toplevel_v6 *toplevel_state; @@ -80,6 +92,7 @@ struct wlr_xdg_surface_v6 { struct wl_signal commit; struct wl_signal destroy; struct wl_signal ack_configure; + struct wl_signal ping_timeout; struct wl_signal request_minimize; struct wl_signal request_move; @@ -117,6 +130,12 @@ struct wlr_xdg_toplevel_v6_show_window_menu_event { struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display); void wlr_xdg_shell_v6_destroy(struct wlr_xdg_shell_v6 *xdg_shell); +/** + * Send a ping to the surface. If the surface does not respond in a reasonable + * amount of time, the ping_timeout event will be emitted. + */ +void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface); + /** * Request that this toplevel surface be the given size. */ diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 8c101020..a8d8c93a 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -296,7 +296,7 @@ static void xdg_surface_ack_configure(struct wl_client *client, if (!surface->configured) { surface->configured = true; - wl_signal_emit(&surface->shell->events.new_surface, surface); + wl_signal_emit(&surface->client->shell->events.new_surface, surface); } wl_signal_emit(&surface->events.ack_configure, surface); @@ -393,7 +393,7 @@ static void wlr_xdg_toplevel_v6_send_configure( static void wlr_xdg_surface_send_configure(void *user_data) { struct wlr_xdg_surface_v6 *surface = user_data; - struct wl_display *display = wl_client_get_display(surface->client); + struct wl_display *display = wl_client_get_display(surface->client->client); // TODO handle popups assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); @@ -416,7 +416,7 @@ static void wlr_xdg_surface_v6_schedule_configure( // TODO handle popups assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - struct wl_display *display = wl_client_get_display(surface->client); + struct wl_display *display = wl_client_get_display(surface->client->client); struct wl_event_loop *loop = wl_display_get_event_loop(display); bool pending_same = !force && @@ -486,32 +486,36 @@ static void handle_wlr_surface_committed(struct wl_listener *listener, wl_signal_emit(&surface->events.commit, surface); } -static void xdg_shell_get_xdg_surface(struct wl_client *client, - struct wl_resource *_xdg_shell, uint32_t id, - struct wl_resource *_surface) { - struct wlr_xdg_shell_v6 *xdg_shell = wl_resource_get_user_data(_xdg_shell); +static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, + struct wl_resource *client_resource, uint32_t id, + struct wl_resource *surface_resource) { + struct wlr_xdg_client_v6 *client = + wl_resource_get_user_data(client_resource); struct wlr_xdg_surface_v6 *surface; if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface_v6)))) { + wl_client_post_no_memory(wl_client); return; } if (!(surface->geometry = calloc(1, sizeof(struct wlr_box)))) { free(surface); + wl_client_post_no_memory(wl_client); return; } if (!(surface->next_geometry = calloc(1, sizeof(struct wlr_box)))) { free(surface->geometry); free(surface); + wl_client_post_no_memory(wl_client); return; } surface->client = client; - surface->shell = xdg_shell; surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE; - surface->surface = wl_resource_get_user_data(_surface); - surface->resource = wl_resource_create(client, - &zxdg_surface_v6_interface, wl_resource_get_version(_xdg_shell), id); + surface->surface = wl_resource_get_user_data(surface_resource); + surface->resource = wl_resource_create(wl_client, + &zxdg_surface_v6_interface, wl_resource_get_version(client_resource), + id); wl_list_init(&surface->configure_list); @@ -522,6 +526,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *client, wl_signal_init(&surface->events.commit); wl_signal_init(&surface->events.destroy); wl_signal_init(&surface->events.ack_configure); + wl_signal_init(&surface->events.ping_timeout); wl_signal_add(&surface->surface->signals.destroy, &surface->surface_destroy_listener); @@ -534,12 +539,19 @@ static void xdg_shell_get_xdg_surface(struct wl_client *client, wlr_log(L_DEBUG, "new xdg_surface %p (res %p)", surface, surface->resource); wl_resource_set_implementation(surface->resource, &zxdg_surface_v6_implementation, surface, xdg_surface_resource_destroy); - wl_list_insert(&xdg_shell->surfaces, &surface->link); + wl_list_insert(&client->surfaces, &surface->link); } -static void xdg_shell_pong(struct wl_client *client, +static void xdg_shell_pong(struct wl_client *wl_client, struct wl_resource *resource, uint32_t serial) { - wlr_log(L_DEBUG, "TODO xdg shell pong"); + struct wlr_xdg_client_v6 *client = wl_resource_get_user_data(resource); + + if (client->ping_serial != serial) { + return; + } + + wl_event_source_timer_update(client->ping_timer, 0); + client->ping_serial = 0; } static struct zxdg_shell_v6_interface xdg_shell_impl = { @@ -548,8 +560,36 @@ static struct zxdg_shell_v6_interface xdg_shell_impl = { .pong = xdg_shell_pong, }; -static void xdg_shell_destroy(struct wl_resource *resource) { - wl_list_remove(wl_resource_get_link(resource)); +static void wlr_xdg_client_v6_destroy(struct wl_resource *resource) { + struct wlr_xdg_client_v6 *client = wl_resource_get_user_data(resource); + struct wl_list *list = &client->surfaces; + struct wl_list *link, *tmp; + + for (link = list->next, tmp = link->next; + link != list; + link = tmp, tmp = link->next) { + wl_list_remove(link); + wl_list_init(link); + } + + if (client->ping_timer != NULL) { + wl_event_source_remove(client->ping_timer); + } + + wl_list_remove(&client->link); + free(client); +} + +static int wlr_xdg_client_v6_ping_timeout(void *user_data) { + struct wlr_xdg_client_v6 *client = user_data; + + struct wlr_xdg_surface_v6 *surface; + wl_list_for_each(surface, &client->surfaces, link) { + wl_signal_emit(&surface->events.ping_timeout, surface); + } + + client->ping_serial = 0; + return 1; } static void xdg_shell_bind(struct wl_client *wl_client, void *_xdg_shell, @@ -562,11 +602,31 @@ static void xdg_shell_bind(struct wl_client *wl_client, void *_xdg_shell, wl_client_destroy(wl_client); return; } - struct wl_resource *wl_resource = - wl_resource_create( wl_client, &zxdg_shell_v6_interface, version, id); - wl_resource_set_implementation(wl_resource, &xdg_shell_impl, xdg_shell, - xdg_shell_destroy); - wl_list_insert(&xdg_shell->wl_resources, wl_resource_get_link(wl_resource)); + struct wlr_xdg_client_v6 *client = + calloc(1, sizeof(struct wlr_xdg_client_v6)); + if (client == NULL) { + wl_client_post_no_memory(wl_client); + return; + } + + wl_list_init(&client->surfaces); + + client->resource = + wl_resource_create(wl_client, &zxdg_shell_v6_interface, version, id); + client->client = wl_client; + client->shell = xdg_shell; + + wl_resource_set_implementation(client->resource, &xdg_shell_impl, client, + wlr_xdg_client_v6_destroy); + wl_list_insert(&xdg_shell->clients, &client->link); + + struct wl_display *display = wl_client_get_display(client->client); + struct wl_event_loop *loop = wl_display_get_event_loop(display); + client->ping_timer = wl_event_loop_add_timer(loop, + wlr_xdg_client_v6_ping_timeout, client); + if (client->ping_timer == NULL) { + wl_client_post_no_memory(client->client); + } } struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) { @@ -575,6 +635,11 @@ struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) { if (!xdg_shell) { return NULL; } + + xdg_shell->ping_timeout = 10000; + + wl_list_init(&xdg_shell->clients); + struct wl_global *wl_global = wl_global_create(display, &zxdg_shell_v6_interface, 1, xdg_shell, xdg_shell_bind); if (!wl_global) { @@ -585,9 +650,6 @@ struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) { wl_signal_init(&xdg_shell->events.new_surface); - wl_list_init(&xdg_shell->wl_resources); - wl_list_init(&xdg_shell->surfaces); - return xdg_shell; } @@ -595,17 +657,27 @@ void wlr_xdg_shell_v6_destroy(struct wlr_xdg_shell_v6 *xdg_shell) { if (!xdg_shell) { return; } - struct wl_resource *resource = NULL, *temp = NULL; - wl_resource_for_each_safe(resource, temp, &xdg_shell->wl_resources) { - struct wl_list *link = wl_resource_get_link(resource); - wl_list_remove(link); - } - // TODO: destroy surfaces + // TODO: disconnect clients and destroy surfaces + // TODO: this segfault (wl_display->registry_resource_list is not init) // wl_global_destroy(xdg_shell->wl_global); free(xdg_shell); } +void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface) { + if (surface->client->ping_serial != 0) { + // already pinged + return; + } + + surface->client->ping_serial = + wl_display_next_serial(wl_client_get_display(surface->client->client)); + wl_event_source_timer_update(surface->client->ping_timer, + surface->client->shell->ping_timeout); + zxdg_shell_v6_send_ping(surface->client->resource, + surface->client->ping_serial); +} + void wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface, uint32_t width, uint32_t height) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); From 49a24225a269f3266d8a11aae265a34d7d384efb Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 16 Sep 2017 14:33:07 -0400 Subject: [PATCH 16/20] toplevel protocol errors --- types/wlr_xdg_shell_v6.c | 81 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index a8d8c93a..3e0aeac4 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -59,6 +59,13 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, struct wlr_seat_handle *seat_handle = wl_resource_get_user_data(seat_resource); + if (!surface->configured) { + wl_resource_post_error(surface->toplevel_state->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + struct wlr_xdg_toplevel_v6_show_window_menu_event *event = calloc(1, sizeof(struct wlr_xdg_toplevel_v6_show_window_menu_event)); if (event == NULL) { @@ -85,6 +92,13 @@ static void xdg_toplevel_protocol_move(struct wl_client *client, struct wlr_seat_handle *seat_handle = wl_resource_get_user_data(seat_resource); + if (!surface->configured) { + wl_resource_post_error(surface->toplevel_state->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + struct wlr_xdg_toplevel_v6_move_event *event = calloc(1, sizeof(struct wlr_xdg_toplevel_v6_move_event)); if (event == NULL) { @@ -109,6 +123,13 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client, struct wlr_seat_handle *seat_handle = wl_resource_get_user_data(seat_resource); + if (!surface->configured) { + wl_resource_post_error(surface->toplevel_state->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + struct wlr_xdg_toplevel_v6_resize_event *event = calloc(1, sizeof(struct wlr_xdg_toplevel_v6_resize_event)); if (event == NULL) { @@ -243,6 +264,7 @@ static void copy_toplevel_state(struct wlr_xdg_toplevel_v6_state *src, struct wlr_xdg_toplevel_v6_state *dest) { dest->width = src->width; dest->height = src->height; + dest->max_width = src->max_width; dest->max_height = src->max_height; dest->min_width = src->min_width; @@ -265,8 +287,10 @@ static void xdg_surface_ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - // TODO handle popups - if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); return; } @@ -285,7 +309,9 @@ static void xdg_surface_ack_configure(struct wl_client *client, } } if (!found) { - // TODO post error on the client resource + wl_resource_post_error(surface->client->resource, + ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE, + "wrong configure serial: %u", serial); return; } @@ -308,6 +334,14 @@ static void xdg_surface_set_window_geometry(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + + if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) { + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + return; + } + surface->has_next_geometry = true; surface->next_geometry->height = height; surface->next_geometry->width = width; @@ -400,9 +434,13 @@ static void wlr_xdg_surface_send_configure(void *user_data) { surface->configure_idle = NULL; - // TODO handle no memory struct wlr_xdg_surface_v6_configure *configure = calloc(1, sizeof(struct wlr_xdg_surface_v6_configure)); + if (configure == NULL) { + wl_client_post_no_memory(surface->client->client); + return; + } + wl_list_insert(surface->configure_list.prev, &configure->link); configure->serial = wl_display_next_serial(display); @@ -454,7 +492,7 @@ static void handle_wlr_surface_destroyed(struct wl_listener *listener, static void wlr_xdg_surface_v6_toplevel_committed( struct wlr_xdg_surface_v6 *surface) { - if (!surface->toplevel_state->added) { + if (!surface->surface->current.buffer && !surface->toplevel_state->added) { // on the first commit, send a configure request to tell the client it // is added wlr_xdg_surface_v6_schedule_configure(surface, true); @@ -462,6 +500,12 @@ static void wlr_xdg_surface_v6_toplevel_committed( return; } + if (!surface->surface->current.buffer) { + return; + } + + // TODO: error if they try to resize a maximized or fullscreen window + copy_toplevel_state(&surface->toplevel_state->next, &surface->toplevel_state->current); } @@ -471,6 +515,13 @@ static void handle_wlr_surface_committed(struct wl_listener *listener, struct wlr_xdg_surface_v6 *surface = wl_container_of(listener, surface, surface_commit_listener); + if (surface->surface->current.buffer && !surface->configured) { + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, + "xdg_surface has never been configured"); + return; + } + if (surface->has_next_geometry) { surface->has_next_geometry = false; surface->geometry->x = surface->next_geometry->x; @@ -479,8 +530,18 @@ static void handle_wlr_surface_committed(struct wl_listener *listener, surface->geometry->height = surface->next_geometry->height; } - if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + switch (surface->role) { + case WLR_XDG_SURFACE_V6_ROLE_NONE: + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "xdg_surface must have a role"); + break; + case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL: wlr_xdg_surface_v6_toplevel_committed(surface); + break; + case WLR_XDG_SURFACE_V6_ROLE_POPUP: + wlr_log(L_DEBUG, "TODO: popup surface committed"); + break; } wl_signal_emit(&surface->events.commit, surface); @@ -491,6 +552,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, struct wl_resource *surface_resource) { struct wlr_xdg_client_v6 *client = wl_resource_get_user_data(client_resource); + struct wlr_xdg_surface_v6 *surface; if (!(surface = calloc(1, sizeof(struct wlr_xdg_surface_v6)))) { wl_client_post_no_memory(wl_client); @@ -517,6 +579,13 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, &zxdg_surface_v6_interface, wl_resource_get_version(client_resource), id); + if (surface->surface->current.buffer != NULL) { + wl_resource_post_error(surface->resource, + ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, + "xdg_surface must not have a buffer at creation"); + return; + } + wl_list_init(&surface->configure_list); wl_signal_init(&surface->events.request_minimize); From 2573c429ee62d875ad2480fd29bef775cb33fa32 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 16 Sep 2017 19:32:23 -0400 Subject: [PATCH 17/20] reset pending geometry on ack configure --- include/wlr/types/wlr_xdg_shell_v6.h | 2 +- types/wlr_xdg_shell_v6.c | 40 +++++++++++----------------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index f57dde10..5183abd5 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -63,7 +63,7 @@ struct wlr_xdg_toplevel_v6 { struct wlr_xdg_surface_v6_configure { struct wl_list link; // wlr_xdg_surface_v6::configure_list uint32_t serial; - struct wlr_xdg_toplevel_v6_state *state; + struct wlr_xdg_toplevel_v6_state state; }; struct wlr_xdg_surface_v6 { diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 3e0aeac4..f09cba8f 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -260,27 +260,13 @@ static void xdg_surface_get_popup(struct wl_client *client, wlr_log(L_DEBUG, "TODO xdg surface get popup"); } -static void copy_toplevel_state(struct wlr_xdg_toplevel_v6_state *src, - struct wlr_xdg_toplevel_v6_state *dest) { - dest->width = src->width; - dest->height = src->height; - - dest->max_width = src->max_width; - dest->max_height = src->max_height; - dest->min_width = src->min_width; - dest->min_height = src->min_height; - - dest->fullscreen = src->fullscreen; - dest->resizing = src->resizing; - dest->activated = src->activated; - dest->maximized = src->maximized; -} - static void wlr_xdg_toplevel_v6_ack_configure( struct wlr_xdg_surface_v6 *surface, struct wlr_xdg_surface_v6_configure *configure) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); - copy_toplevel_state(configure->state, &surface->toplevel_state->next); + surface->toplevel_state->next = configure->state; + surface->toplevel_state->pending.width = 0; + surface->toplevel_state->pending.height = 0; } static void xdg_surface_ack_configure(struct wl_client *client, @@ -347,6 +333,7 @@ static void xdg_surface_set_window_geometry(struct wl_client *client, surface->next_geometry->width = width; surface->next_geometry->x = x; surface->next_geometry->y = y; + } static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation = { @@ -397,7 +384,7 @@ static void wlr_xdg_toplevel_v6_send_configure( uint32_t *s; struct wl_array states; - configure->state = &surface->toplevel_state->pending; + configure->state = surface->toplevel_state->pending; wl_array_init(&states); if (surface->toplevel_state->pending.maximized) { @@ -417,10 +404,16 @@ static void wlr_xdg_toplevel_v6_send_configure( *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; } - zxdg_toplevel_v6_send_configure(surface->toplevel_state->resource, - surface->toplevel_state->pending.width, - surface->toplevel_state->pending.height, - &states); + uint32_t width = surface->toplevel_state->pending.width; + uint32_t height = surface->toplevel_state->pending.height; + + if (width == 0 || height == 0) { + width = surface->geometry->width; + height = surface->geometry->height; + } + + zxdg_toplevel_v6_send_configure(surface->toplevel_state->resource, width, + height, &states); wl_array_release(&states); } @@ -506,8 +499,7 @@ static void wlr_xdg_surface_v6_toplevel_committed( // TODO: error if they try to resize a maximized or fullscreen window - copy_toplevel_state(&surface->toplevel_state->next, - &surface->toplevel_state->current); + surface->toplevel_state->current = surface->toplevel_state->next; } static void handle_wlr_surface_committed(struct wl_listener *listener, From 5b9373a7913d956b6e1aca8370b66d9d59a83351 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 16 Sep 2017 20:07:19 -0400 Subject: [PATCH 18/20] xdg-toplevel-v6 set parent --- include/wlr/types/wlr_xdg_shell_v6.h | 1 + types/wlr_xdg_shell_v6.c | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 5183abd5..786bf4e6 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -53,6 +53,7 @@ struct wlr_xdg_toplevel_v6_state { struct wlr_xdg_toplevel_v6 { struct wl_resource *resource; struct wlr_xdg_surface_v6 *base; + struct wlr_xdg_surface_v6 *parent; bool added; struct wlr_xdg_toplevel_v6_state next; // client protocol requests struct wlr_xdg_toplevel_v6_state pending; // user configure requests diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index f09cba8f..9f503b1f 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -21,7 +21,14 @@ static void resource_destroy(struct wl_client *client, static void xdg_toplevel_protocol_set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource) { - wlr_log(L_DEBUG, "TODO: toplevel set parent"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_xdg_surface_v6 *parent = NULL; + + if (parent_resource != NULL) { + parent = wl_resource_get_user_data(parent_resource); + } + + surface->toplevel_state->parent = parent; } static void xdg_toplevel_protocol_set_title(struct wl_client *client, From 94d4b9249cd0702c26bd9d87dcfbea57569c6382 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 16 Sep 2017 20:31:34 -0400 Subject: [PATCH 19/20] xdg-shell-v6 misc cleanup --- types/wlr_xdg_shell_v6.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 9f503b1f..827f3491 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -15,7 +15,6 @@ static const char *wlr_desktop_xdg_toplevel_role = "xdg_toplevel"; static void resource_destroy(struct wl_client *client, struct wl_resource *resource) { - // TODO: we probably need to do more than this wl_resource_destroy(resource); } @@ -225,6 +224,8 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { wl_list_remove(&surface->surface_commit_listener.link); free(surface->geometry); free(surface->next_geometry); + free(surface->title); + free(surface->app_id); free(surface); } @@ -244,8 +245,9 @@ static void xdg_surface_get_toplevel(struct wl_client *client, return; } - if (!(surface->toplevel_state = - calloc(1, sizeof(struct wlr_xdg_toplevel_v6)))) { + surface->toplevel_state = calloc(1, sizeof(struct wlr_xdg_toplevel_v6)); + if (surface->toplevel_state == NULL) { + wl_client_post_no_memory(client); return; } @@ -492,6 +494,8 @@ static void handle_wlr_surface_destroyed(struct wl_listener *listener, static void wlr_xdg_surface_v6_toplevel_committed( struct wlr_xdg_surface_v6 *surface) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); + if (!surface->surface->current.buffer && !surface->toplevel_state->added) { // on the first commit, send a configure request to tell the client it // is added @@ -504,8 +508,6 @@ static void wlr_xdg_surface_v6_toplevel_committed( return; } - // TODO: error if they try to resize a maximized or fullscreen window - surface->toplevel_state->current = surface->toplevel_state->next; } @@ -601,7 +603,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, surface->surface_destroy_listener.notify = handle_wlr_surface_destroyed; wl_signal_add(&surface->surface->signals.commit, - &surface->surface_commit_listener); + &surface->surface_commit_listener); surface->surface_commit_listener.notify = handle_wlr_surface_committed; wlr_log(L_DEBUG, "new xdg_surface %p (res %p)", surface, surface->resource); @@ -725,8 +727,6 @@ void wlr_xdg_shell_v6_destroy(struct wlr_xdg_shell_v6 *xdg_shell) { if (!xdg_shell) { return; } - // TODO: disconnect clients and destroy surfaces - // TODO: this segfault (wl_display->registry_resource_list is not init) // wl_global_destroy(xdg_shell->wl_global); free(xdg_shell); From f46befec7c9c1561d2325df2325008a8a4e36328 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 17 Sep 2017 09:42:27 -0400 Subject: [PATCH 20/20] use wl_list_for_each_safe() to unlink client surfaces --- types/wlr_xdg_shell_v6.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 827f3491..a7450add 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -632,14 +632,11 @@ static struct zxdg_shell_v6_interface xdg_shell_impl = { static void wlr_xdg_client_v6_destroy(struct wl_resource *resource) { struct wlr_xdg_client_v6 *client = wl_resource_get_user_data(resource); - struct wl_list *list = &client->surfaces; - struct wl_list *link, *tmp; - for (link = list->next, tmp = link->next; - link != list; - link = tmp, tmp = link->next) { - wl_list_remove(link); - wl_list_init(link); + struct wlr_xdg_surface_v6 *surface, *tmp = NULL; + wl_list_for_each_safe(surface, tmp, &client->surfaces, link) { + wl_list_remove(&surface->link); + wl_list_init(&surface->link); } if (client->ping_timer != NULL) {