From fc02b3e1f6bba31a32ed86904218d9333e4a72b4 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Sun, 12 Apr 2020 13:40:41 +0200 Subject: [PATCH 1/4] Implement basic restacking support The compositor now allows to restack surfaces into arbitrary locations in the z-order. As a first application, these functions are used to implement functions to raise a window to the top or drop them to the bottom of the z-order, which are used to fix the behaviour of floating windows. Windows now restack to the top of the z-order whenever they become floating or when they are moved, which is the same behaviour as dwm. When a window becomes tiled it gets dropped to the bottom of the z-order, thus ensuring that floating windows are always above tiled windows. --- libswc/compositor.c | 25 +++++++++++++++++++++++++ libswc/compositor.h | 5 +++++ libswc/window.c | 21 +++++++++++++++++++++ libswc/window.h | 2 ++ 4 files changed, 53 insertions(+) diff --git a/libswc/compositor.c b/libswc/compositor.c index 23f0155..4fa0e60 100644 --- a/libswc/compositor.c +++ b/libswc/compositor.c @@ -836,3 +836,28 @@ compositor_finalize(void) pixman_region32_fini(&compositor.opaque); wl_global_destroy(compositor.global); } + +void compositor_view_restack_above(struct compositor_view *view, struct wl_list *link) +{ + wl_list_remove(&view->link); + wl_list_insert(link, &view->link); + damage_view(view); + update(&view->base); +} + +void compositor_view_restack_below(struct compositor_view* view, struct wl_list *link) +{ + compositor_view_restack_above(view, link->next); +} + +void +compositor_view_restack_at_head(struct compositor_view* view) +{ + compositor_view_restack_above(view, &compositor.views); +} + +void +compositor_view_restack_at_tail(struct compositor_view* view) +{ + compositor_view_restack_above(view, compositor.views.prev); +} diff --git a/libswc/compositor.h b/libswc/compositor.h index 5fdd9aa..11c4786 100644 --- a/libswc/compositor.h +++ b/libswc/compositor.h @@ -81,4 +81,9 @@ void compositor_view_hide(struct compositor_view *view); void compositor_view_set_border_color(struct compositor_view *view, uint32_t color); void compositor_view_set_border_width(struct compositor_view *view, uint32_t width); +void compositor_view_restack_above(struct compositor_view *view, struct wl_list *link); +void compositor_view_restack_below(struct compositor_view *view, struct wl_list *link); +void compositor_view_restack_at_head(struct compositor_view *view); +void compositor_view_restack_at_tail(struct compositor_view *view); + #endif diff --git a/libswc/window.c b/libswc/window.c index 7f7255e..ac84080 100644 --- a/libswc/window.c +++ b/libswc/window.c @@ -174,6 +174,8 @@ swc_window_set_stacked(struct swc_window *base) if (window->impl->set_mode) window->impl->set_mode(window, WINDOW_MODE_STACKED); window->mode = WINDOW_MODE_STACKED; + + window_raise(window); } EXPORT void @@ -186,6 +188,8 @@ swc_window_set_tiled(struct swc_window *base) if (window->impl->set_mode) window->impl->set_mode(window, WINDOW_MODE_TILED); window->mode = WINDOW_MODE_TILED; + + window_drop(window); } EXPORT void @@ -479,6 +483,8 @@ window_begin_move(struct window *window, struct button *button) begin_interaction(&window->move.interaction, button); window->move.offset.x = geometry->x - px; window->move.offset.y = geometry->y - py; + + window_raise(window); } void @@ -505,3 +511,18 @@ window_begin_resize(struct window *window, uint32_t edges, struct button *button window->resize.offset.y = geometry->y - py + ((edges & SWC_WINDOW_EDGE_BOTTOM) ? geometry->height : 0); window->resize.edges = edges; } + +void +window_raise(struct window *window) +{ + /* TODO: recursively raise other windows in the same tree */ + compositor_view_restack_at_head(window->view); +} + +void +window_drop(struct window *window) +{ + /* TODO: recursively drop other windows in the same tree */ + compositor_view_restack_at_tail(window->view); +} + diff --git a/libswc/window.h b/libswc/window.h index 08c9d36..40bd26d 100644 --- a/libswc/window.h +++ b/libswc/window.h @@ -97,5 +97,7 @@ void window_set_app_id(struct window *window, const char *app_id); void window_set_parent(struct window *window, struct window *parent); void window_begin_move(struct window *window, struct button *button); void window_begin_resize(struct window *window, uint32_t edges, struct button *button); +void window_raise(struct window *window); +void window_drop(struct window *window); #endif From 86be336e59c9adc3771fb15bd590d39469d52d05 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Tue, 14 Apr 2020 00:59:42 +0200 Subject: [PATCH 2/4] Implement xdg shell popup support Menu bars and other popups in graphical applications should now work properly. The implementation is very rough and still requires a lot of polishing, but it works for now. --- libswc/xdg_shell.c | 245 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 240 insertions(+), 5 deletions(-) diff --git a/libswc/xdg_shell.c b/libswc/xdg_shell.c index 6ee4f73..9236b48 100644 --- a/libswc/xdg_shell.c +++ b/libswc/xdg_shell.c @@ -22,8 +22,10 @@ */ #include "xdg_shell.h" +#include "compositor.h" #include "internal.h" #include "seat.h" +#include "keyboard.h" #include "surface.h" #include "util.h" #include "window.h" @@ -33,15 +35,43 @@ #include #include "xdg-shell-server-protocol.h" +enum xdg_surface_role { + XDG_SURFACE_ROLE_NONE, + XDG_SURFACE_ROLE_TOPLEVEL, + XDG_SURFACE_ROLE_POPUP, +}; + struct xdg_surface { struct wl_resource *resource, *role; struct surface *surface; struct wl_listener surface_destroy_listener, role_destroy_listener; uint32_t configure_serial; + enum xdg_surface_role surface_role; }; struct xdg_positioner { struct wl_resource *resource; + + struct { + uint32_t width; + uint32_t height; + } size; + + struct { + int32_t x; + int32_t y; + uint32_t width; + uint32_t height; + } anchor_rect; + + uint32_t anchor; + uint32_t gravity; + uint32_t constraint_adjustment; + + struct { + int32_t x; + int32_t y; + } offset; }; struct xdg_toplevel { @@ -51,7 +81,87 @@ struct xdg_toplevel { struct xdg_surface *xdg_surface; }; +struct xdg_popup { + struct compositor_view* view; + struct wl_resource *resource; + struct xdg_surface *xdg_surface; + struct xdg_surface *parent; +}; + /* xdg_positioner */ +static struct swc_rectangle +xdg_positioner_get_geometry(struct xdg_positioner *positioner) +{ + struct swc_rectangle geometry = { + .x = positioner->offset.x, + .y = positioner->offset.y, + .width = positioner->size.width, + .height = positioner->size.height, + }; + + switch (positioner->anchor) { + case XDG_POSITIONER_ANCHOR_TOP: + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + geometry.y += positioner->anchor_rect.y; + break; + case XDG_POSITIONER_ANCHOR_BOTTOM: + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height; + break; + default: + geometry.y += positioner->anchor_rect.y + positioner->anchor_rect.height / 2; + } + + switch (positioner->anchor) { + case XDG_POSITIONER_ANCHOR_LEFT: + case XDG_POSITIONER_ANCHOR_TOP_LEFT: + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: + geometry.x += positioner->anchor_rect.x; + break; + case XDG_POSITIONER_ANCHOR_RIGHT: + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: + geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width; + break; + default: + geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width / 2; + } + + switch (positioner->gravity) { + case XDG_POSITIONER_GRAVITY_TOP: + case XDG_POSITIONER_GRAVITY_TOP_LEFT: + case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + geometry.y -= geometry.height; + break; + case XDG_POSITIONER_GRAVITY_BOTTOM: + case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + geometry.y = geometry.y; + break; + default: + geometry.y -= geometry.height / 2; + } + + switch (positioner->gravity) { + case XDG_POSITIONER_GRAVITY_LEFT: + case XDG_POSITIONER_GRAVITY_TOP_LEFT: + case XDG_POSITIONER_GRAVITY_BOTTOM_LEFT: + geometry.x -= geometry.width; + break; + case XDG_POSITIONER_GRAVITY_RIGHT: + case XDG_POSITIONER_GRAVITY_TOP_RIGHT: + case XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT: + geometry.x = geometry.x; + break; + default: + geometry.x -= geometry.width / 2; + } + + return geometry; +} + static void destroy_positioner(struct wl_resource *resource) { @@ -63,31 +173,65 @@ destroy_positioner(struct wl_resource *resource) static void set_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height) { + struct xdg_positioner *positioner = wl_resource_get_user_data(resource); + + if (width < 1 || height < 1) { + wl_resource_post_error(resource, + XDG_POSITIONER_ERROR_INVALID_INPUT, + "width and height must be positives and non-zero"); + return; + } + + positioner->size.width = width; + positioner->size.height = height; } static void set_anchor_rect(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { + struct xdg_positioner *positioner = wl_resource_get_user_data(resource); + + if (width < 0 || height < 0) { + wl_resource_post_error(resource, + XDG_POSITIONER_ERROR_INVALID_INPUT, + "width and height must be non-negative"); + return; + } + + positioner->anchor_rect.x = x; + positioner->anchor_rect.y = y; + positioner->anchor_rect.width = width; + positioner->anchor_rect.height = height; } static void set_anchor(struct wl_client *client, struct wl_resource *resource, uint32_t anchor) { + struct xdg_positioner *positioner = wl_resource_get_user_data(resource); + positioner->anchor = anchor; } static void set_gravity(struct wl_client *client, struct wl_resource *resource, uint32_t gravity) { + struct xdg_positioner *positioner = wl_resource_get_user_data(resource); + positioner->gravity = gravity; } static void set_constraint_adjustment(struct wl_client *client, struct wl_resource *resource, uint32_t adjustment) { + struct xdg_positioner *positioner = wl_resource_get_user_data(resource); + positioner->constraint_adjustment = adjustment; } static void set_offset(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) { + struct xdg_positioner *positioner = wl_resource_get_user_data(resource); + + positioner->offset.x = x; + positioner->offset.y = y; } static const struct xdg_positioner_interface positioner_impl = { @@ -100,6 +244,42 @@ static const struct xdg_positioner_interface positioner_impl = { .set_offset = set_offset, }; +/* xdg_popup */ +static void +destroy_popup(struct wl_resource *resource) +{ + struct xdg_popup *popup = wl_resource_get_user_data(resource); + + compositor_view_destroy(popup->view); + free(popup); +} + +static uint32_t +popup_send_configure(struct xdg_popup *popup, int32_t x, int32_t y, int32_t width, int32_t height) { + uint32_t serial = wl_display_next_serial(swc.display); + + xdg_popup_send_configure(popup->resource, x, y, width, height); + xdg_surface_send_configure(popup->xdg_surface->resource, serial); + + return serial; +} + +static void +grab(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial) +{ +} + +static void +reposition(struct wl_client *client, struct wl_resource *resource, struct wl_resource *positioner, uint32_t token) +{ +} + +static const struct xdg_popup_interface popup_impl = { + .destroy = destroy_resource, + .grab = grab, + .reposition = reposition, +}; + /* xdg_toplevel */ static void destroy_toplevel(struct wl_resource *resource) @@ -356,6 +536,31 @@ xdg_toplevel_new(struct wl_client *client, uint32_t version, uint32_t id, struct return NULL; } +static struct xdg_popup * +xdg_popup_new(struct wl_client *client, uint32_t version, uint32_t id, struct xdg_surface *xdg_surface, struct xdg_surface *parent) +{ + struct xdg_popup *popup; + + popup = malloc(sizeof(*popup)); + if (!popup) + goto error0; + popup->xdg_surface = xdg_surface; + popup->parent = parent; + popup->resource = wl_resource_create(client, &xdg_popup_interface, version, id); + if (!popup->resource) + goto error1; + + popup->view = compositor_create_view(popup->xdg_surface->surface); + wl_resource_set_implementation(popup->resource, &popup_impl, popup, &destroy_popup); + + return popup; + +error1: + free(popup); +error0: + return NULL; +} + /* xdg_surface */ static void get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id) @@ -373,25 +578,55 @@ get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id return; } xdg_surface->role = toplevel->resource; + xdg_surface->surface_role = XDG_SURFACE_ROLE_TOPLEVEL; wl_resource_add_destroy_listener(xdg_surface->role, &xdg_surface->role_destroy_listener); } static void -get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent, struct wl_resource *positioner) +get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent, struct wl_resource *positioner_resource) { + + struct xdg_surface *popup_surface = wl_resource_get_user_data(resource); + struct xdg_surface *parent_surface = wl_resource_get_user_data(parent); + struct xdg_popup *popup; + + popup = xdg_popup_new(client, wl_resource_get_version(resource), id, popup_surface, parent_surface); + if (!popup) { + wl_client_post_no_memory(client); + return; + } + + popup_surface->role = popup->resource; + popup_surface->surface_role = XDG_SURFACE_ROLE_POPUP; + wl_resource_add_destroy_listener(popup_surface->role, &popup_surface->role_destroy_listener); + + struct compositor_view *parent_view = compositor_view(parent_surface->surface->view); + compositor_view_set_parent(popup->view, parent_view); + + struct xdg_positioner *positioner = wl_resource_get_user_data(positioner_resource); + struct swc_rectangle geometry = xdg_positioner_get_geometry(positioner); + view_set_size(&popup->view->base, geometry.width, geometry.height); + view_move(&popup->view->base, parent_view->base.geometry.x + geometry.x, parent_view->base.geometry.y + geometry.y); + + popup->xdg_surface->configure_serial = popup_send_configure(popup, parent_view->base.geometry.x + geometry.x, parent_view->base.geometry.y + geometry.y, geometry.width, geometry.height); } static void ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial) { struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource); - struct window *window; - if (!xdg_surface->role) - return; + switch (xdg_surface->surface_role) { + case XDG_SURFACE_ROLE_NONE: + return; + case XDG_SURFACE_ROLE_POPUP: + return; + } + + struct window *window; window = wl_resource_get_user_data(xdg_surface->role); if (window && serial == xdg_surface->configure_serial) - window->configure.acknowledged = true; + window->configure.acknowledged = true; } static void From f7a97664194da119e2171656bd9eb79379fa5436 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Sat, 18 Apr 2020 20:11:28 +0200 Subject: [PATCH 3/4] Implement basic subsurface support Functionality is for now limited to creation, initial rendering and destruction. --- libswc/subcompositor.c | 7 ++-- libswc/subsurface.c | 94 +++++++++++++++++++++++++++++++++++++----- libswc/subsurface.h | 20 ++++++++- libswc/surface.c | 6 ++- libswc/surface.h | 3 ++ 5 files changed, 115 insertions(+), 15 deletions(-) diff --git a/libswc/subcompositor.c b/libswc/subcompositor.c index 5d1da45..10d50c3 100644 --- a/libswc/subcompositor.c +++ b/libswc/subcompositor.c @@ -31,10 +31,11 @@ static void get_subsurface(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource, struct wl_resource *parent_resource) { - struct subsurface *subsurface; - - subsurface = subsurface_new(client, wl_resource_get_version(resource), id); + struct surface *surface = wl_resource_get_user_data(surface_resource); + struct surface *parent = wl_resource_get_user_data(parent_resource); + struct subsurface *subsurface; + subsurface = subsurface_new(client, wl_resource_get_version(resource), id, surface, parent); if (!subsurface) { wl_resource_post_no_memory(resource); return; diff --git a/libswc/subsurface.c b/libswc/subsurface.c index 6f68b2c..c8aaca0 100644 --- a/libswc/subsurface.c +++ b/libswc/subsurface.c @@ -21,40 +21,53 @@ * SOFTWARE. */ +#include "compositor.h" #include "subsurface.h" #include "util.h" #include +#include #include static void set_position(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y) { - /* TODO: Implement. */ + struct subsurface *subsurface = wl_resource_get_user_data(resource); + + subsurface->position.x = x; + subsurface->position.y = y; + subsurface->position.set = true; + + view_move(subsurface->surface->view, subsurface->parent->view->geometry.x + x, subsurface->parent->view->geometry.y + y); + view_update(subsurface->surface->view); + + struct compositor_view *comp_view = compositor_view(subsurface->surface->view); + if (comp_view) + compositor_view_show(comp_view); } static void place_above(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource) { - /* TODO: Implement. */ + DEBUG("subsurface::place_above\n"); } static void place_below(struct wl_client *client, struct wl_resource *resource, struct wl_resource *sibling_resource) { - /* TODO: Implement. */ + DEBUG("subsurface::place_below\n"); } static void set_sync(struct wl_client *client, struct wl_resource *resource) { - /* TODO: Implement. */ + DEBUG("subsurface::set_sync\n"); } static void set_desync(struct wl_client *client, struct wl_resource *resource) { - /* TODO: Implement. */ + DEBUG("subsurface::set_desync\n"); } static const struct wl_subsurface_interface subsurface_impl = { @@ -67,14 +80,63 @@ static const struct wl_subsurface_interface subsurface_impl = { }; static void -subsurface_destroy(struct wl_resource *resource) +unlink_from_parent(struct subsurface* subsurface) { - struct subsurface *subsurface = wl_resource_get_user_data(resource); + wl_list_remove(&subsurface->parent_link); + wl_list_remove(&subsurface->parent_destroy_listener.link); + subsurface->parent = NULL; +} + +static void +subsurface_destroy(struct subsurface *subsurface) +{ + if (subsurface->parent) + unlink_from_parent(subsurface); + + struct compositor_view *comp_view = compositor_view(subsurface->surface->view); + if (comp_view) + compositor_view_destroy(comp_view); + + wl_list_remove(&subsurface->surface_destroy_listener.link); + free(subsurface); } +static void +subsurface_destroy_handler(struct wl_resource *resource) +{ + struct subsurface *subsurface = wl_resource_get_user_data(resource); + if (subsurface) + subsurface_destroy(subsurface); +} + +static void +subsurface_handle_surface_destroy(struct wl_listener *listener, void *data) +{ + struct subsurface *subsurface; + subsurface = wl_container_of(listener, subsurface, surface_destroy_listener); + + if (subsurface->resource) + wl_resource_set_user_data(subsurface->resource, NULL); + + subsurface_destroy(subsurface); +} + +static void +subsurface_handle_parent_destroy(struct wl_listener *listener, void *data) +{ + struct subsurface *subsurface; + subsurface = wl_container_of(listener, subsurface, parent_destroy_listener); + + struct compositor_view *comp_view = compositor_view(subsurface->surface->view); + if (comp_view) + compositor_view_hide(comp_view); + + unlink_from_parent(subsurface); +} + struct subsurface * -subsurface_new(struct wl_client *client, uint32_t version, uint32_t id) +subsurface_new(struct wl_client *client, uint32_t version, uint32_t id, struct surface *surface, struct surface *parent) { struct subsurface *subsurface; @@ -82,11 +144,23 @@ subsurface_new(struct wl_client *client, uint32_t version, uint32_t id) goto error0; subsurface->resource = wl_resource_create(client, &wl_subsurface_interface, version, id); - if (!subsurface->resource) goto error1; + wl_resource_set_implementation(subsurface->resource, &subsurface_impl, subsurface, &subsurface_destroy_handler); + + subsurface->surface = surface; + subsurface->parent = parent; + + subsurface->surface_destroy_listener.notify = subsurface_handle_surface_destroy; + subsurface->parent_destroy_listener.notify = subsurface_handle_parent_destroy; + wl_signal_add(&surface->destroy_signal, &subsurface->surface_destroy_listener); + wl_signal_add(&parent->destroy_signal, &subsurface->parent_destroy_listener); + + wl_list_insert(&parent->subsurface_list, &subsurface->parent_link); + + subsurface->synchronized = true; - wl_resource_set_implementation(subsurface->resource, &subsurface_impl, subsurface, &subsurface_destroy); + compositor_create_view(subsurface->surface); return subsurface; diff --git a/libswc/subsurface.h b/libswc/subsurface.h index a78ed69..2bfd578 100644 --- a/libswc/subsurface.h +++ b/libswc/subsurface.h @@ -24,14 +24,32 @@ #ifndef SWC_SUBSURFACE_H #define SWC_SUBSURFACE_H +#include "surface.h" + +#include #include struct wl_client; struct subsurface { struct wl_resource *resource; + + struct surface *surface; + struct wl_listener surface_destroy_listener; + + struct surface *parent; + struct wl_listener parent_destroy_listener; + struct wl_list parent_link; + + struct { + int32_t x; + int32_t y; + bool set; + } position; + + bool synchronized; }; -struct subsurface *subsurface_new(struct wl_client *client, uint32_t version, uint32_t id); +struct subsurface *subsurface_new(struct wl_client *client, uint32_t version, uint32_t id, struct surface *surface, struct surface *parent); #endif diff --git a/libswc/surface.c b/libswc/surface.c index 19a36ec..f6809d8 100644 --- a/libswc/surface.c +++ b/libswc/surface.c @@ -305,6 +305,8 @@ surface_destroy(struct wl_resource *resource) { struct surface *surface = wl_resource_get_user_data(resource); + wl_signal_emit(&surface->destroy_signal, surface); + state_finalize(&surface->state); state_finalize(&surface->pending.state); @@ -339,10 +341,13 @@ surface_new(struct wl_client *client, uint32_t version, uint32_t id) surface->pending.commit = 0; surface->view = NULL; surface->view_handler.impl = &view_handler_impl; + wl_list_init(&surface->subsurface_list); state_initialize(&surface->state); state_initialize(&surface->pending.state); + wl_signal_init(&surface->destroy_signal); + return surface; error1: @@ -361,7 +366,6 @@ surface_set_view(struct surface *surface, struct view *view) wl_list_remove(&surface->view_handler.link); surface->view = view; - if (view) { wl_list_insert(&view->handlers, &surface->view_handler.link); view_attach(view, surface->state.buffer); diff --git a/libswc/surface.h b/libswc/surface.h index 039ed4c..28d810b 100644 --- a/libswc/surface.h +++ b/libswc/surface.h @@ -67,6 +67,9 @@ struct surface { struct view *view; struct view_handler view_handler; + + struct wl_signal destroy_signal; + struct wl_list subsurface_list; }; struct surface *surface_new(struct wl_client *client, uint32_t version, uint32_t id); From e05969b0ac0009dba18e430596c1888ae4cc9136 Mon Sep 17 00:00:00 2001 From: ian <42294085+ianbeyst@users.noreply.github.com> Date: Sat, 18 Apr 2020 22:55:23 +0200 Subject: [PATCH 4/4] defer setting subsurface geometry until after parent commit --- libswc/subsurface.c | 30 +++++++++++++++++++++--------- libswc/subsurface.h | 1 + libswc/surface.c | 6 ++++++ 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/libswc/subsurface.c b/libswc/subsurface.c index c8aaca0..dc4232c 100644 --- a/libswc/subsurface.c +++ b/libswc/subsurface.c @@ -37,13 +37,6 @@ set_position(struct wl_client *client, struct wl_resource *resource, int32_t x, subsurface->position.x = x; subsurface->position.y = y; subsurface->position.set = true; - - view_move(subsurface->surface->view, subsurface->parent->view->geometry.x + x, subsurface->parent->view->geometry.y + y); - view_update(subsurface->surface->view); - - struct compositor_view *comp_view = compositor_view(subsurface->surface->view); - if (comp_view) - compositor_view_show(comp_view); } static void @@ -160,12 +153,31 @@ subsurface_new(struct wl_client *client, uint32_t version, uint32_t id, struct s subsurface->synchronized = true; - compositor_create_view(subsurface->surface); + struct compositor_view *comp_view = compositor_create_view(subsurface->surface); + compositor_view_show(comp_view); - return subsurface; + return subsurface; error1: free(subsurface); error0: return NULL; } + +void +subsurface_parent_commit(struct subsurface *subsurface, bool is_parent_synchronized) +{ + if (subsurface->position.set) { + int32_t oldx = subsurface->parent->view->geometry.x; + int32_t oldy = subsurface->parent->view->geometry.y; + int32_t newx = oldx + subsurface->position.x; + int32_t newy = oldy + subsurface->position.y; + view_move(subsurface->surface->view, newx, newy); + + subsurface->position.set = false; + } + + if (is_parent_synchronized || subsurface->synchronized) { + // TODO: handle this + } +} diff --git a/libswc/subsurface.h b/libswc/subsurface.h index 2bfd578..43369d9 100644 --- a/libswc/subsurface.h +++ b/libswc/subsurface.h @@ -51,5 +51,6 @@ struct subsurface { }; struct subsurface *subsurface_new(struct wl_client *client, uint32_t version, uint32_t id, struct surface *surface, struct surface *parent); +void subsurface_parent_commit(struct subsurface *subsurface, bool is_parent_synchronized); #endif diff --git a/libswc/surface.c b/libswc/surface.c index f6809d8..a6f3c9e 100644 --- a/libswc/surface.c +++ b/libswc/surface.c @@ -22,6 +22,7 @@ */ #include "surface.h" +#include "subsurface.h" #include "event.h" #include "internal.h" #include "output.h" @@ -263,6 +264,11 @@ commit(struct wl_client *client, struct wl_resource *resource) } surface->pending.commit = 0; + + struct subsurface *sub; + wl_list_for_each(sub, &surface->subsurface_list, parent_link) { + subsurface_parent_commit(sub, false); + } } static void