diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h index 922d7c0f..816ff713 100644 --- a/include/wlr/types/wlr_compositor.h +++ b/include/wlr/types/wlr_compositor.h @@ -6,12 +6,19 @@ struct wlr_surface; +struct wlr_subcompositor { + struct wl_global *wl_global; + struct wl_list wl_resources; +}; + struct wlr_compositor { struct wl_global *wl_global; struct wl_list wl_resources; struct wlr_renderer *renderer; struct wl_list surfaces; + struct wlr_subcompositor subcompositor; + struct wl_listener display_destroy; struct { diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 62f03e37..35d47926 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -56,7 +56,8 @@ struct wlr_subsurface { struct wl_list parent_link; struct wl_list parent_pending_link; - struct wl_listener parent_destroy_listener; + struct wl_listener surface_destroy; + struct wl_listener parent_destroy; struct { struct wl_signal destroy; @@ -87,9 +88,7 @@ struct wlr_surface { void (*role_committed)(struct wlr_surface *surface, void *role_data); void *role_data; - // subsurface properties - struct wlr_subsurface *subsurface; - struct wl_list subsurface_list; // wlr_subsurface::parent_link + struct wl_list subsurfaces; // wlr_subsurface::parent_link // wlr_subsurface::parent_pending_link struct wl_list subsurface_pending_list; diff --git a/rootston/desktop.c b/rootston/desktop.c index 4edcb5e3..6ddf56b8 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -459,7 +459,7 @@ void view_map(struct roots_view *view, struct wlr_surface *surface) { view->wlr_surface = surface; struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &view->wlr_surface->subsurface_list, + wl_list_for_each(subsurface, &view->wlr_surface->subsurfaces, parent_link) { subsurface_create(view, subsurface); } diff --git a/rootston/output.c b/rootston/output.c index 75bbd928..791b2819 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -318,7 +318,7 @@ static void render_view(struct roots_view *view, struct render_data *data) { } static bool has_standalone_surface(struct roots_view *view) { - if (!wl_list_empty(&view->wlr_surface->subsurface_list)) { + if (!wl_list_empty(&view->wlr_surface->subsurfaces)) { return false; } diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index 2f9d12c9..57f3bd91 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -10,7 +10,8 @@ static const char *subsurface_role = "wl_subsurface"; bool wlr_surface_is_subsurface(struct wlr_surface *surface) { - return strcmp(surface->role, subsurface_role) == 0; + return surface->role != NULL && + strcmp(surface->role, subsurface_role) == 0; } struct wlr_subsurface *wlr_subsurface_from_surface( @@ -19,9 +20,96 @@ struct wlr_subsurface *wlr_subsurface_from_surface( return (struct wlr_subsurface *)surface->role_data; } +static void subcompositor_handle_destroy(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static void subcompositor_handle_get_subsurface(struct wl_client *client, + struct wl_resource *resource, uint32_t id, + struct wl_resource *surface_resource, + struct wl_resource *parent_resource) { + struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); + struct wlr_surface *parent = wlr_surface_from_resource(parent_resource); + + static const char msg[] = "get_subsurface: wl_subsurface@"; + + if (surface == parent) { + wl_resource_post_error(resource, + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, + "%s%d: wl_surface@%d cannot be its own parent", + msg, id, wl_resource_get_id(surface_resource)); + return; + } + + if (wlr_surface_is_subsurface(surface)) { + wl_resource_post_error(resource, + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, + "%s%d: wl_surface@%d is already a sub-surface", + msg, id, wl_resource_get_id(surface_resource)); + return; + } + + if (wlr_surface_get_root_surface(parent) == surface) { + wl_resource_post_error(resource, + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, + "%s%d: wl_surface@%d is an ancestor of parent", + msg, id, wl_resource_get_id(surface_resource)); + return; + } + + if (wlr_surface_set_role(surface, subsurface_role, resource, + WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE) < 0) { + return; + } + + wlr_surface_make_subsurface(surface, parent, id); +} + +static const struct wl_subcompositor_interface subcompositor_interface = { + .destroy = subcompositor_handle_destroy, + .get_subsurface = subcompositor_handle_get_subsurface, +}; + +static void subcompositor_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) { + struct wlr_subcompositor *subcompositor = data; + struct wl_resource *resource = + wl_resource_create(client, &wl_subcompositor_interface, 1, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &subcompositor_interface, + subcompositor, NULL); + wl_list_insert(&subcompositor->wl_resources, wl_resource_get_link(resource)); +} + +static void subcompositor_init(struct wlr_subcompositor *subcompositor, + struct wl_display *display) { + subcompositor->wl_global = wl_global_create(display, + &wl_subcompositor_interface, 1, subcompositor, subcompositor_bind); + if (subcompositor->wl_global == NULL) { + wlr_log_errno(L_ERROR, "Could not allocate subcompositor global"); + return; + } + wl_list_init(&subcompositor->wl_resources); +} + +static void subcompositor_finish(struct wlr_subcompositor *subcompositor) { + wl_global_destroy(subcompositor->wl_global); +} + + + + + + + static const struct wl_compositor_interface wl_compositor_impl; -static struct wlr_compositor *compositor_from_resource(struct wl_resource *resource) { +static struct wlr_compositor *compositor_from_resource( + struct wl_resource *resource) { assert(wl_resource_instance_of(resource, &wl_compositor_interface, &wl_compositor_impl)); return wl_resource_get_user_data(resource); @@ -86,16 +174,15 @@ static void wl_compositor_bind(struct wl_client *wl_client, void *data, struct wlr_compositor *compositor = data; assert(wl_client && compositor); - struct wl_resource *wl_resource = + struct wl_resource *resource = wl_resource_create(wl_client, &wl_compositor_interface, version, id); - if (wl_resource == NULL) { + if (resource == NULL) { wl_client_post_no_memory(wl_client); return; } - wl_resource_set_implementation(wl_resource, &wl_compositor_impl, + wl_resource_set_implementation(resource, &wl_compositor_impl, compositor, wl_compositor_destroy); - wl_list_insert(&compositor->wl_resources, - wl_resource_get_link(wl_resource)); + wl_list_insert(&compositor->wl_resources, wl_resource_get_link(resource)); } void wlr_compositor_destroy(struct wlr_compositor *compositor) { @@ -103,82 +190,12 @@ void wlr_compositor_destroy(struct wlr_compositor *compositor) { return; } wlr_signal_emit_safe(&compositor->events.destroy, compositor); + subcompositor_finish(&compositor->subcompositor); wl_list_remove(&compositor->display_destroy.link); wl_global_destroy(compositor->wl_global); free(compositor); } -static void subcompositor_destroy(struct wl_client *client, - struct wl_resource *resource) { - wl_resource_destroy(resource); -} - -static void subcompositor_get_subsurface(struct wl_client *client, - struct wl_resource *resource, uint32_t id, - struct wl_resource *surface_resource, - struct wl_resource *parent_resource) { - struct wlr_surface *surface = wlr_surface_from_resource(surface_resource); - struct wlr_surface *parent = wlr_surface_from_resource(parent_resource); - - static const char msg[] = "get_subsurface: wl_subsurface@"; - - if (surface == parent) { - wl_resource_post_error(resource, - WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, - "%s%d: wl_surface@%d cannot be its own parent", - msg, id, wl_resource_get_id(surface_resource)); - return; - } - - if (surface->subsurface) { - wl_resource_post_error(resource, - WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, - "%s%d: wl_surface@%d is already a sub-surface", - msg, id, wl_resource_get_id(surface_resource)); - return; - } - - if (wlr_surface_get_root_surface(parent) == surface) { - wl_resource_post_error(resource, - WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, - "%s%d: wl_surface@%d is an ancestor of parent", - msg, id, wl_resource_get_id(surface_resource)); - return; - } - - if (wlr_surface_set_role(surface, subsurface_role, resource, - WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE) < 0) { - return; - } - - wlr_surface_make_subsurface(surface, parent, id); - if (!surface->subsurface) { - wl_resource_post_no_memory(resource); - return; - } - - surface->role_data = surface->subsurface; -} - - -static const struct wl_subcompositor_interface subcompositor_interface = { - .destroy = subcompositor_destroy, - .get_subsurface = subcompositor_get_subsurface, -}; - -static void subcompositor_bind(struct wl_client *client, void *data, - uint32_t version, uint32_t id) { - struct wlr_compositor *compositor = data; - struct wl_resource *resource = - wl_resource_create(client, &wl_subcompositor_interface, 1, id); - if (resource == NULL) { - wl_client_post_no_memory(client); - return; - } - wl_resource_set_implementation(resource, &subcompositor_interface, - compositor, NULL); -} - static void handle_display_destroy(struct wl_listener *listener, void *data) { struct wlr_compositor *compositor = wl_container_of(listener, compositor, display_destroy); @@ -204,14 +221,13 @@ struct wlr_compositor *wlr_compositor_create(struct wl_display *display, compositor->wl_global = compositor_global; compositor->renderer = renderer; - wl_global_create(display, &wl_subcompositor_interface, 1, compositor, - subcompositor_bind); - wl_list_init(&compositor->wl_resources); wl_list_init(&compositor->surfaces); wl_signal_init(&compositor->events.new_surface); wl_signal_init(&compositor->events.destroy); + subcompositor_init(&compositor->subcompositor, display); + compositor->display_destroy.notify = handle_display_destroy; wl_display_add_destroy_listener(display, &compositor->display_destroy); diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 320e2421..9c0324a0 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -129,8 +130,7 @@ static void surface_set_opaque_region(struct wl_client *client, } static void surface_set_input_region(struct wl_client *client, - struct wl_resource *resource, - struct wl_resource *region_resource) { + struct wl_resource *resource, struct wl_resource *region_resource) { struct wlr_surface *surface = wlr_surface_from_resource(resource); surface->pending->invalid |= WLR_SURFACE_INVALID_INPUT_REGION; if (region_resource) { @@ -326,7 +326,7 @@ static void wlr_surface_damage_subsurfaces(struct wlr_subsurface *subsurface) { subsurface->reordered = false; struct wlr_subsurface *child; - wl_list_for_each(child, &subsurface->surface->subsurface_list, parent_link) { + wl_list_for_each(child, &subsurface->surface->subsurfaces, parent_link) { wlr_surface_damage_subsurfaces(child); } } @@ -418,7 +418,7 @@ static void wlr_surface_commit_pending(struct wlr_surface *surface) { wl_list_for_each_reverse(subsurface, &surface->subsurface_pending_list, parent_pending_link) { wl_list_remove(&subsurface->parent_link); - wl_list_insert(&surface->subsurface_list, &subsurface->parent_link); + wl_list_insert(&surface->subsurfaces, &subsurface->parent_link); if (subsurface->reordered) { // TODO: damage all the subsurfaces @@ -438,7 +438,7 @@ static void wlr_surface_commit_pending(struct wlr_surface *surface) { } static bool wlr_subsurface_is_synchronized(struct wlr_subsurface *subsurface) { - while (subsurface) { + while (1) { if (subsurface->synchronized) { return true; } @@ -447,7 +447,10 @@ static bool wlr_subsurface_is_synchronized(struct wlr_subsurface *subsurface) { return false; } - subsurface = subsurface->parent->subsurface; + if (!wlr_surface_is_subsurface(subsurface->parent)) { + break; + } + subsurface = wlr_subsurface_from_surface(subsurface->parent); } return false; @@ -468,7 +471,7 @@ static void wlr_subsurface_parent_commit(struct wlr_subsurface *subsurface, } struct wlr_subsurface *tmp; - wl_list_for_each(tmp, &surface->subsurface_list, parent_link) { + wl_list_for_each(tmp, &surface->subsurfaces, parent_link) { wlr_subsurface_parent_commit(tmp, true); } } @@ -491,19 +494,19 @@ static void wlr_subsurface_commit(struct wlr_subsurface *subsurface) { } struct wlr_subsurface *tmp; - wl_list_for_each(tmp, &surface->subsurface_list, parent_link) { + wl_list_for_each(tmp, &surface->subsurfaces, parent_link) { wlr_subsurface_parent_commit(tmp, false); } } - } static void surface_commit(struct wl_client *client, struct wl_resource *resource) { struct wlr_surface *surface = wlr_surface_from_resource(resource); - struct wlr_subsurface *subsurface = surface->subsurface; - if (subsurface) { + if (wlr_surface_is_subsurface(surface)) { + struct wlr_subsurface *subsurface = + wlr_subsurface_from_surface(surface); wlr_subsurface_commit(subsurface); return; } @@ -511,7 +514,7 @@ static void surface_commit(struct wl_client *client, wlr_surface_commit_pending(surface); struct wlr_subsurface *tmp; - wl_list_for_each(tmp, &surface->subsurface_list, parent_link) { + wl_list_for_each(tmp, &surface->subsurfaces, parent_link) { wlr_subsurface_parent_commit(tmp, false); } } @@ -603,28 +606,26 @@ static void wlr_surface_state_destroy(struct wlr_surface_state *state) { void wlr_subsurface_destroy(struct wlr_subsurface *subsurface) { wlr_signal_emit_safe(&subsurface->events.destroy, subsurface); + wl_list_remove(&subsurface->surface_destroy.link); wlr_surface_state_destroy(subsurface->cached); if (subsurface->parent) { wl_list_remove(&subsurface->parent_link); wl_list_remove(&subsurface->parent_pending_link); - wl_list_remove(&subsurface->parent_destroy_listener.link); + wl_list_remove(&subsurface->parent_destroy.link); } wl_resource_set_user_data(subsurface->resource, NULL); if (subsurface->surface) { - subsurface->surface->subsurface = NULL; + subsurface->surface->role_data = NULL; } free(subsurface); } static void destroy_surface(struct wl_resource *resource) { struct wlr_surface *surface = wlr_surface_from_resource(resource); - wlr_signal_emit_safe(&surface->events.destroy, surface); - if (surface->subsurface) { - wlr_subsurface_destroy(surface->subsurface); - } + wlr_signal_emit_safe(&surface->events.destroy, surface); wlr_texture_destroy(surface->texture); wlr_surface_state_destroy(surface->pending); @@ -650,7 +651,7 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res, wl_signal_init(&surface->events.commit); wl_signal_init(&surface->events.destroy); wl_signal_init(&surface->events.new_subsurface); - wl_list_init(&surface->subsurface_list); + wl_list_init(&surface->subsurfaces); wl_list_init(&surface->subsurface_pending_list); wl_resource_set_implementation(res, &surface_interface, surface, destroy_surface); @@ -720,7 +721,7 @@ static struct wlr_subsurface *subsurface_find_sibling( struct wlr_surface *parent = subsurface->parent; struct wlr_subsurface *sibling; - wl_list_for_each(sibling, &parent->subsurface_list, parent_link) { + wl_list_for_each(sibling, &parent->subsurfaces, parent_link) { if (sibling->surface == surface && sibling != subsurface) { return sibling; } @@ -812,17 +813,23 @@ static const struct wl_subsurface_interface subsurface_implementation = { static void subsurface_handle_parent_destroy(struct wl_listener *listener, void *data) { struct wlr_subsurface *subsurface = - wl_container_of(listener, subsurface, parent_destroy_listener); + wl_container_of(listener, subsurface, parent_destroy); wl_list_remove(&subsurface->parent_link); wl_list_remove(&subsurface->parent_pending_link); - wl_list_remove(&subsurface->parent_destroy_listener.link); + wl_list_remove(&subsurface->parent_destroy.link); subsurface->parent = NULL; } +static void subsurface_handle_surface_destroy(struct wl_listener *listener, + void *data) { + struct wlr_subsurface *subsurface = + wl_container_of(listener, subsurface, surface_destroy); + wlr_subsurface_destroy(subsurface); +} + void wlr_surface_make_subsurface(struct wlr_surface *surface, struct wlr_surface *parent, uint32_t id) { struct wl_client *client = wl_resource_get_client(surface->resource); - assert(surface->subsurface == NULL); struct wlr_subsurface *subsurface = calloc(1, sizeof(struct wlr_subsurface)); @@ -839,14 +846,14 @@ void wlr_surface_make_subsurface(struct wlr_surface *surface, subsurface->synchronized = true; subsurface->surface = surface; wl_signal_init(&subsurface->events.destroy); + wl_signal_add(&surface->events.destroy, &subsurface->surface_destroy); + subsurface->surface_destroy.notify = subsurface_handle_surface_destroy; // link parent subsurface->parent = parent; - wl_signal_add(&parent->events.destroy, - &subsurface->parent_destroy_listener); - subsurface->parent_destroy_listener.notify = - subsurface_handle_parent_destroy; - wl_list_insert(&parent->subsurface_list, &subsurface->parent_link); + wl_signal_add(&parent->events.destroy, &subsurface->parent_destroy); + subsurface->parent_destroy.notify = subsurface_handle_parent_destroy; + wl_list_insert(&parent->subsurfaces, &subsurface->parent_link); wl_list_insert(&parent->subsurface_pending_list, &subsurface->parent_pending_link); @@ -863,21 +870,19 @@ void wlr_surface_make_subsurface(struct wlr_surface *surface, &subsurface_implementation, subsurface, subsurface_resource_destroy); - surface->subsurface = subsurface; + surface->role_data = subsurface; wlr_signal_emit_safe(&parent->events.new_subsurface, subsurface); } struct wlr_surface *wlr_surface_get_root_surface(struct wlr_surface *surface) { - while (surface != NULL) { - struct wlr_subsurface *sub = surface->subsurface; - if (sub == NULL) { - return surface; - } - surface = sub->parent; + while (wlr_surface_is_subsurface(surface)) { + struct wlr_subsurface *subsurface = + wlr_subsurface_from_surface(surface); + surface = subsurface->surface; } - return NULL; + return surface; } bool wlr_surface_point_accepts_input(struct wlr_surface *surface, @@ -890,7 +895,7 @@ bool wlr_surface_point_accepts_input(struct wlr_surface *surface, struct wlr_surface *wlr_surface_surface_at(struct wlr_surface *surface, double sx, double sy, double *sub_x, double *sub_y) { struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { + wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) { double _sub_x = subsurface->surface->current->subsurface_position.x; double _sub_y = subsurface->surface->current->subsurface_position.y; struct wlr_surface *sub = wlr_surface_surface_at(subsurface->surface, @@ -957,7 +962,7 @@ static void surface_for_each_surface(struct wlr_surface *surface, int x, int y, iterator(surface, x, y, user_data); struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { + wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) { struct wlr_surface_state *state = subsurface->surface->current; int sx = state->subsurface_position.x; int sy = state->subsurface_position.y; diff --git a/types/wlr_wl_shell.c b/types/wlr_wl_shell.c index 45a80221..5e4c24e7 100644 --- a/types/wlr_wl_shell.c +++ b/types/wlr_wl_shell.c @@ -13,7 +13,8 @@ static const char *wlr_wl_shell_surface_role = "wl-shell-surface"; bool wlr_surface_is_wl_shell_surface(struct wlr_surface *surface) { - return strcmp(surface->role, wlr_wl_shell_surface_role) == 0; + return surface->role != NULL && + strcmp(surface->role, wlr_wl_shell_surface_role) == 0; } struct wlr_wl_surface *wlr_wl_shell_surface_from_wlr_surface( diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index 1aa964a6..8d424f3b 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -17,8 +17,9 @@ static const char *wlr_desktop_xdg_toplevel_role = "xdg_toplevel"; static const char *wlr_desktop_xdg_popup_role = "xdg_popup"; bool wlr_surface_is_xdg_surface(struct wlr_surface *surface) { - return strcmp(surface->role, wlr_desktop_xdg_toplevel_role) == 0 || - strcmp(surface->role, wlr_desktop_xdg_popup_role) == 0; + return surface->role != NULL && + (strcmp(surface->role, wlr_desktop_xdg_toplevel_role) == 0 || + strcmp(surface->role, wlr_desktop_xdg_popup_role) == 0); } struct wlr_xdg_surface *wlr_xdg_surface_from_wlr_surface( diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 3bd845d3..22b387f1 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -17,8 +17,9 @@ static const char *wlr_desktop_xdg_toplevel_role = "xdg_toplevel_v6"; static const char *wlr_desktop_xdg_popup_role = "xdg_popup_v6"; bool wlr_surface_is_xdg_surface_v6(struct wlr_surface *surface) { - return strcmp(surface->role, wlr_desktop_xdg_toplevel_role) == 0 || - strcmp(surface->role, wlr_desktop_xdg_popup_role) == 0; + return surface->role != NULL && + (strcmp(surface->role, wlr_desktop_xdg_toplevel_role) == 0 || + strcmp(surface->role, wlr_desktop_xdg_popup_role) == 0); } struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_surface( diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 77dc0797..599006ae 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -80,7 +80,8 @@ const char *atom_map[ATOM_LAST] = { const char *wlr_xwayland_surface_role = "wlr_xwayland_surface"; bool wlr_surface_is_xwayland_surface(struct wlr_surface *surface) { - return strcmp(surface->role, wlr_xwayland_surface_role) == 0; + return surface->role != NULL && + strcmp(surface->role, wlr_xwayland_surface_role) == 0; } struct wlr_xwayland_surface *wlr_xwayland_surface_from_wlr_surface(