From ca5d5a528be41f94996c30cb57422fdd2da52069 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 15 May 2023 15:57:00 +0900 Subject: [PATCH] xdg_toplevel_v6: Implement remaining part of xdg_toplevel_v6 This makes xdg_shell_v6 work properly. Change-Id: I33ff81c5870aaf101471a7d68666e61d11d708be --- include/libds/xdg_shell_v6.h | 37 ++++++ src/xdg_shell_v6/xdg_shell_v6.h | 14 ++- src/xdg_shell_v6/xdg_surface_v6.c | 78 ++++++------- src/xdg_shell_v6/xdg_toplevel_v6.c | 225 ++++++++++++++++++++++++++++++++++--- 4 files changed, 288 insertions(+), 66 deletions(-) diff --git a/include/libds/xdg_shell_v6.h b/include/libds/xdg_shell_v6.h index 35a2d42..34916f6 100644 --- a/include/libds/xdg_shell_v6.h +++ b/include/libds/xdg_shell_v6.h @@ -16,6 +16,19 @@ struct ds_xdg_surface_v6; struct ds_xdg_toplevel_v6; +struct ds_xdg_toplevel_v6_event_request_move { + struct ds_xdg_toplevel_v6 *toplevel; + struct wl_resource *seat_resource; + uint32_t serial; +}; + +struct ds_xdg_toplevel_v6_event_request_resize { + struct ds_xdg_toplevel_v6 *toplevel; + struct wl_resource *seat_resource; + uint32_t serial; + uint32_t edges; +}; + struct ds_xdg_shell_v6 * ds_xdg_shell_v6_create(struct wl_display *display); @@ -45,6 +58,30 @@ ds_xdg_surface_v6_ping(struct ds_xdg_surface_v6 *surface); struct ds_surface * ds_xdg_surface_v6_get_surface(struct ds_xdg_surface_v6 *surface); +void +ds_xdg_toplevel_v6_add_set_parent_listener(struct ds_xdg_toplevel_v6 *toplevel, + struct wl_listener *listener); + +void +ds_xdg_toplevel_v6_add_request_move_listener(struct ds_xdg_toplevel_v6 *toplevel, + struct wl_listener *listener); + +void +ds_xdg_toplevel_v6_add_request_resize_listener(struct ds_xdg_toplevel_v6 *toplevel, + struct wl_listener *listener); + +void +ds_xdg_toplevel_v6_add_request_maximize_listener(struct ds_xdg_toplevel_v6 *toplevel, + struct wl_listener *listener); + +void +ds_xdg_toplevel_v6_add_request_fullscreen_listener(struct ds_xdg_toplevel_v6 *toplevel, + struct wl_listener *listener); + +void +ds_xdg_toplevel_v6_add_request_minimize_listener(struct ds_xdg_toplevel_v6 *toplevel, + struct wl_listener *listener); + uint32_t ds_xdg_toplevel_v6_set_size(struct ds_xdg_toplevel_v6 *toplevel, int32_t width, int32_t height); diff --git a/src/xdg_shell_v6/xdg_shell_v6.h b/src/xdg_shell_v6/xdg_shell_v6.h index 5bd7615..0e2ff52 100644 --- a/src/xdg_shell_v6/xdg_shell_v6.h +++ b/src/xdg_shell_v6/xdg_shell_v6.h @@ -5,6 +5,7 @@ #include #include "libds/output.h" +#include "libds/xdg_shell_v6.h" #include "surface.h" @@ -71,9 +72,8 @@ struct ds_xdg_toplevel_v6 { struct wl_resource *resource; struct ds_xdg_surface_v6 *base; - bool added; - struct ds_xdg_surface_v6 *parent; + struct ds_xdg_toplevel_v6 *parent; struct wl_listener parent_unmap; struct ds_xdg_toplevel_v6_state current, pending; @@ -94,6 +94,8 @@ struct ds_xdg_toplevel_v6 struct wl_signal set_title; struct wl_signal set_app_id; } events; + + bool sent_initial_configure; }; struct ds_xdg_popup @@ -174,14 +176,20 @@ reset_xdg_surface_v6(struct ds_xdg_surface_v6 *surface); void create_xdg_toplevel_v6(struct ds_xdg_surface_v6 *surface, uint32_t id); +void destroy_xdg_surface_v6_role(struct ds_xdg_surface_v6 *surface); + void handle_xdg_surface_v6_commit(struct ds_surface *ds_surface); void -handle_xdg_surface_v6_toplevel_committed(struct ds_xdg_surface_v6 *surface); +handle_xdg_toplevel_v6_committed(struct ds_xdg_toplevel_v6 *toplevel); void send_xdg_toplevel_v6_configure(struct ds_xdg_surface_v6 *surface, struct ds_xdg_surface_v6_configure *configure); +void reset_xdg_toplevel_v6(struct ds_xdg_toplevel_v6 *toplevel); + +void destroy_xdg_toplevel_v6(struct ds_xdg_toplevel_v6 *toplevel); + #endif diff --git a/src/xdg_shell_v6/xdg_surface_v6.c b/src/xdg_shell_v6/xdg_surface_v6.c index 37e7015..51742ed 100644 --- a/src/xdg_shell_v6/xdg_surface_v6.c +++ b/src/xdg_shell_v6/xdg_surface_v6.c @@ -108,51 +108,60 @@ create_xdg_surface_v6(struct ds_xdg_client_v6 *client, struct ds_surface *ds_sur void unmap_xdg_surface_v6(struct ds_xdg_surface_v6 *surface) { - struct ds_xdg_surface_v6_configure *configure, *tmp; + surface->mapped = false; + + wl_signal_emit_mutable(&surface->events.unmap, surface); +} - // TODO handle popup +void +reset_xdg_surface_v6(struct ds_xdg_surface_v6 *surface) +{ + struct ds_xdg_surface_v6_configure *configure, *tmp; - if (surface->mapped) - wl_signal_emit_mutable(&surface->events.unmap, surface); + surface->configured = false; switch (surface->role) { case DS_XDG_SURFACE_V6_ROLE_TOPLEVEL: - if (surface->toplevel->parent) { - wl_list_remove(&surface->toplevel->parent_unmap.link); - surface->toplevel->parent = NULL; - } - free(surface->toplevel->title); - surface->toplevel->title = NULL; - free(surface->toplevel->app_id); - surface->toplevel->app_id = NULL; + reset_xdg_toplevel_v6(surface->toplevel); break; case DS_XDG_SURFACE_V6_ROLE_POPUP: // TODO break; case DS_XDG_SURFACE_V6_ROLE_NONE: - DS_ASSERT_NOT_REACHED(); + break; } - wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) + wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) { xdg_surface_v6_configure_destroy(configure); + } if (surface->configure_idle) { wl_event_source_remove(surface->configure_idle); surface->configure_idle = NULL; } - - surface->configured = false; - surface->mapped = false; } void -reset_xdg_surface_v6(struct ds_xdg_surface_v6 *surface) +destroy_xdg_surface_v6(struct ds_xdg_surface_v6 *surface) { - struct ds_xdg_toplevel_v6_requested *req; + destroy_xdg_surface_v6_role(surface); + + wl_list_remove(&surface->link); + wl_list_remove(&surface->listener.surface_destroy.link); + wl_list_remove(&surface->listener.surface_commit.link); + + wl_resource_set_user_data(surface->resource, NULL); + free(surface); +} - if (surface->role != DS_XDG_SURFACE_V6_ROLE_NONE) +void +destroy_xdg_surface_v6_role(struct ds_xdg_surface_v6 *surface) +{ + if (surface->configured && surface->mapped) unmap_xdg_surface_v6(surface); + reset_xdg_surface_v6(surface); + if (surface->added) { wl_signal_emit_mutable(&surface->events.destroy, surface); surface->added = false; @@ -160,19 +169,13 @@ reset_xdg_surface_v6(struct ds_xdg_surface_v6 *surface) switch (surface->role) { case DS_XDG_SURFACE_V6_ROLE_TOPLEVEL: - wl_resource_set_user_data(surface->toplevel->resource, NULL); - surface->toplevel->resource = NULL; - req = &surface->toplevel->requested; - if (req->fullscreen_output) - wl_list_remove(&req->fullscreen_output_destroy.link); - free(surface->toplevel); + destroy_xdg_toplevel_v6(surface->toplevel); surface->toplevel = NULL; break; case DS_XDG_SURFACE_V6_ROLE_POPUP: // TODO break; - case DS_XDG_SURFACE_V6_ROLE_NONE: - // This space is intentionally left blank + default: break; } @@ -180,22 +183,6 @@ reset_xdg_surface_v6(struct ds_xdg_surface_v6 *surface) } void -destroy_xdg_surface_v6(struct ds_xdg_surface_v6 *surface) -{ - reset_xdg_surface_v6(surface); - - wl_resource_set_user_data(surface->resource, NULL); - - ds_surface_reset_role_data(surface->ds_surface); - - wl_list_remove(&surface->link); - wl_list_remove(&surface->listener.surface_destroy.link); - wl_list_remove(&surface->listener.surface_commit.link); - - free(surface); -} - -void handle_xdg_surface_v6_commit(struct ds_surface *ds_surface) { struct ds_xdg_surface_v6 *surface; @@ -208,8 +195,7 @@ handle_xdg_surface_v6_commit(struct ds_surface *ds_surface) // inert toplevel or popup break; case DS_XDG_SURFACE_V6_ROLE_TOPLEVEL: - handle_xdg_surface_v6_toplevel_committed(surface); - // TODO + handle_xdg_toplevel_v6_committed(surface->toplevel); break; case DS_XDG_SURFACE_V6_ROLE_POPUP: // TODO diff --git a/src/xdg_shell_v6/xdg_toplevel_v6.c b/src/xdg_shell_v6/xdg_toplevel_v6.c index 7e5426a..d15eee1 100644 --- a/src/xdg_shell_v6/xdg_toplevel_v6.c +++ b/src/xdg_shell_v6/xdg_toplevel_v6.c @@ -13,6 +13,53 @@ static const struct ds_surface_role xdg_toplevel_v6_surface_role = static const struct zxdg_toplevel_v6_interface xdg_toplevel_v6_impl; static void xdg_toplevel_v6_handle_resource_destroy(struct wl_resource *resource); +static void xdg_toplevel_v6_set_parent(struct ds_xdg_toplevel_v6 *toplevel, + struct ds_xdg_toplevel_v6 *parent); + +WL_EXPORT void +ds_xdg_toplevel_v6_add_set_parent_listener(struct ds_xdg_toplevel_v6 *toplevel, + struct wl_listener *listener) +{ + wl_signal_add(&toplevel->events.set_parent, listener); +} + +WL_EXPORT void +ds_xdg_toplevel_v6_add_request_move_listener(struct ds_xdg_toplevel_v6 *toplevel, + struct wl_listener *listener) +{ + wl_signal_add(&toplevel->events.request_move, listener); +} + +WL_EXPORT void +ds_xdg_toplevel_v6_add_request_resize_listener(struct ds_xdg_toplevel_v6 *toplevel, + struct wl_listener *listener) +{ + wl_signal_add(&toplevel->events.request_resize, listener); +} + +WL_EXPORT void +ds_xdg_toplevel_v6_add_request_maximize_listener( + struct ds_xdg_toplevel_v6 *toplevel, + struct wl_listener *listener) +{ + wl_signal_add(&toplevel->events.request_maximize, listener); +} + +WL_EXPORT void +ds_xdg_toplevel_v6_add_request_fullscreen_listener( + struct ds_xdg_toplevel_v6 *toplevel, + struct wl_listener *listener) +{ + wl_signal_add(&toplevel->events.request_fullscreen, listener); +} + +WL_EXPORT void +ds_xdg_toplevel_v6_add_request_minimize_listener( + struct ds_xdg_toplevel_v6 *toplevel, + struct wl_listener *listener) +{ + wl_signal_add(&toplevel->events.request_minimize, listener); +} WL_EXPORT uint32_t ds_xdg_toplevel_v6_set_size(struct ds_xdg_toplevel_v6 *toplevel, @@ -106,15 +153,14 @@ create_xdg_toplevel_v6(struct ds_xdg_surface_v6 *surface, uint32_t id) } void -handle_xdg_surface_v6_toplevel_committed(struct ds_xdg_surface_v6 *surface) +handle_xdg_toplevel_v6_committed(struct ds_xdg_toplevel_v6 *toplevel) { - if (!surface->toplevel->added) { - ds_xdg_surface_v6_schedule_configure(surface); - surface->toplevel->added = true; - return; - } + toplevel->current = toplevel->pending; - surface->toplevel->current = surface->toplevel->pending; + if (!toplevel->sent_initial_configure) { + ds_xdg_surface_v6_schedule_configure(toplevel->base); + toplevel->sent_initial_configure = true; + } } void @@ -177,9 +223,36 @@ error_out: } void -destroy_xdg_toplevel_v6(struct ds_xdg_surface_v6 *xdg_surface_v6) +destroy_xdg_toplevel_v6(struct ds_xdg_toplevel_v6 *toplevel) { - reset_xdg_surface_v6(xdg_surface_v6); + wl_resource_set_user_data(toplevel->resource, NULL); + free(toplevel); +} + +void +reset_xdg_toplevel_v6(struct ds_xdg_toplevel_v6 *toplevel) +{ + if (toplevel->parent) { + wl_list_remove(&toplevel->parent_unmap.link); + toplevel->parent = NULL; + } + + free(toplevel->title); + toplevel->title = NULL; + + free(toplevel->app_id); + toplevel->app_id = NULL; + + if (toplevel->requested.fullscreen_output) { + wl_list_remove(&toplevel->requested.fullscreen_output_destroy.link); + toplevel->requested.fullscreen_output = NULL; + } + + toplevel->requested.fullscreen = false; + toplevel->requested.maximized = false; + toplevel->requested.minimized = false; + + toplevel->sent_initial_configure = false; } static void @@ -193,7 +266,16 @@ static void xdg_toplevel_v6_handle_set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource) { - // TODO + struct ds_xdg_toplevel_v6 *toplevel, *parent = NULL; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + return; + + if (parent_resource) + parent = wl_resource_get_user_data(parent_resource); + + xdg_toplevel_v6_set_parent(toplevel, parent); } static void @@ -204,6 +286,9 @@ xdg_toplevel_v6_handle_set_title(struct wl_client *client, char *tmp; toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + return; + tmp = strdup(title); if (!tmp) { wl_resource_post_no_memory(resource); @@ -225,6 +310,9 @@ xdg_toplevel_v6_handle_set_app_id(struct wl_client *client, char *tmp; toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + return; + tmp = strdup(app_id); if (!tmp) { wl_resource_post_no_memory(resource); @@ -251,7 +339,25 @@ xdg_toplevel_v6_handle_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { - // TODO + struct ds_xdg_toplevel_v6 *toplevel; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + return; + + if (!toplevel->base->configured) { + wl_resource_post_error(toplevel->base->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + + struct ds_xdg_toplevel_v6_event_request_move event = { + .toplevel = toplevel, + .seat_resource = seat_resource, + .serial = serial, + }; + wl_signal_emit_mutable(&toplevel->events.request_move, &event); } static void @@ -259,7 +365,26 @@ xdg_toplevel_v6_handle_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, uint32_t edges) { - // TODO + struct ds_xdg_toplevel_v6 *toplevel; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + return; + + if (!toplevel->base->configured) { + wl_resource_post_error(toplevel->base->resource, + ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED, + "surface has not been configured yet"); + return; + } + + struct ds_xdg_toplevel_v6_event_request_resize event = { + .toplevel = toplevel, + .seat_resource = seat_resource, + .serial = serial, + .edges = edges, + }; + wl_signal_emit_mutable(&toplevel->events.request_resize, &event); } static void @@ -269,6 +394,9 @@ xdg_toplevel_v6_handle_set_max_size(struct wl_client *client, struct ds_xdg_toplevel_v6 *toplevel; toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + return; + toplevel->pending.max_width = width; toplevel->pending.max_height = height; } @@ -280,6 +408,9 @@ xdg_toplevel_v6_handle_set_min_size(struct wl_client *client, struct ds_xdg_toplevel_v6 *toplevel; toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + return; + toplevel->pending.min_width = width; toplevel->pending.min_height = height; } @@ -291,9 +422,11 @@ xdg_toplevel_v6_handle_set_maximized(struct wl_client *client, struct ds_xdg_toplevel_v6 *toplevel; toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + return; + toplevel->requested.maximized = true; wl_signal_emit_mutable(&toplevel->events.request_maximize, toplevel); - ds_xdg_surface_v6_schedule_configure(toplevel->base); } static void @@ -303,23 +436,41 @@ xdg_toplevel_v6_handle_unset_maximized(struct wl_client *client, struct ds_xdg_toplevel_v6 *toplevel; toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + return; + toplevel->requested.maximized = false; wl_signal_emit_mutable(&toplevel->events.request_maximize, toplevel); - ds_xdg_surface_v6_schedule_configure(toplevel->base); } static void xdg_toplevel_v6_handle_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { - // TODO + struct ds_xdg_toplevel_v6 *toplevel; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + return; + + // TODO get a ds_output from an output_resource + + toplevel->requested.fullscreen = true; + wl_signal_emit_mutable(&toplevel->events.request_fullscreen, toplevel); } static void xdg_toplevel_v6_handle_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { - // TODO + struct ds_xdg_toplevel_v6 *toplevel; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + return; + + toplevel->requested.fullscreen = false; + wl_signal_emit_mutable(&toplevel->events.request_fullscreen, toplevel); } static void @@ -329,6 +480,9 @@ xdg_toplevel_v6_handle_set_minimized(struct wl_client *client, struct ds_xdg_toplevel_v6 *toplevel; toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + return; + toplevel->requested.minimized = true; wl_signal_emit_mutable(&toplevel->events.request_maximize, toplevel); } @@ -360,5 +514,42 @@ xdg_toplevel_v6_handle_resource_destroy(struct wl_resource *resource) if (!toplevel) return; - destroy_xdg_toplevel_v6(toplevel->base); + destroy_xdg_surface_v6_role(toplevel->base); +} + +static void +xdg_toplevel_v6_handle_parent_unmap(struct wl_listener *listener, void *data) +{ + struct ds_xdg_toplevel_v6 *toplevel; + + toplevel = wl_container_of(listener, toplevel, parent_unmap); + xdg_toplevel_v6_set_parent(toplevel, toplevel->parent->parent); +} + +static void +xdg_toplevel_v6_set_parent(struct ds_xdg_toplevel_v6 *toplevel, + struct ds_xdg_toplevel_v6 *parent) +{ + struct ds_xdg_toplevel_v6 *iter = parent; + + while (iter) { + if (iter == toplevel) + return; + iter = iter->parent; + } + + if (toplevel->parent) + wl_list_remove(&toplevel->parent_unmap.link); + + if (parent && parent->base->mapped) { + toplevel->parent = parent; + toplevel->parent_unmap.notify = xdg_toplevel_v6_handle_parent_unmap; + wl_signal_add(&toplevel->parent->base->events.unmap, + &toplevel->parent_unmap); + } + else { + toplevel->parent = NULL; + } + + wl_signal_emit_mutable(&toplevel->events.set_parent, NULL); } -- 2.7.4