From 59c94887018bdfa578c4371c4275061ca6e71b3e Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 3 Jun 2018 16:35:06 +1000 Subject: WIP: Atomic layout updates ground work --- sway/desktop/xwayland.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'sway/desktop/xwayland.c') diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 6447b711..6a3c1b66 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -167,19 +167,18 @@ static uint32_t get_int_prop(struct sway_view *view, enum sway_view_prop prop) { } } -static void configure(struct sway_view *view, double lx, double ly, int width, +static uint32_t configure(struct sway_view *view, double lx, double ly, int width, int height) { struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); if (xwayland_view == NULL) { - return; + return 0; } struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - xwayland_view->pending_lx = lx; - xwayland_view->pending_ly = ly; - xwayland_view->pending_width = width; - xwayland_view->pending_height = height; wlr_xwayland_surface_configure(xsurface, lx, ly, width, height); + + // xwayland doesn't give us a serial for the configure + return 0; } static void set_activated(struct sway_view *view, bool activated) { @@ -250,15 +249,21 @@ static void handle_commit(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, commit); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (view->swayc && container_is_floating(view->swayc)) { - view_update_size(view, xsurface->width, xsurface->height); - } else { - view_update_size(view, xwayland_view->pending_width, - xwayland_view->pending_height); + + // Don't allow xwayland views to do resize or reposition themselves if + // they're involved in a transaction. Once the transaction has finished + // they'll apply the next time a commit happens. + if (view->instructions->length) { + if (view->swayc && container_is_floating(view->swayc)) { + view_update_size(view, xsurface->width, xsurface->height); + } else { + view_update_size(view, view->swayc->pending.swayc_width, + view->swayc->pending.swayc_height); + } + view_update_position(view, + view->swayc->pending.view_x, view->swayc->pending.view_y); + view_damage_from(view); } - view_update_position(view, - xwayland_view->pending_lx, xwayland_view->pending_ly); - view_damage_from(view); } static void handle_unmap(struct wl_listener *listener, void *data) { -- cgit v1.2.3 From f9e6d703d298dbdee0770fd9e0c64ab2d7ac7deb Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 6 Jun 2018 19:19:30 +1000 Subject: Make main properties be the pending state --- include/sway/tree/container.h | 4 +- sway/desktop/desktop.c | 3 +- sway/desktop/output.c | 28 ++++++----- sway/desktop/transaction.c | 49 ++++++++++--------- sway/desktop/xwayland.c | 9 ++-- sway/tree/arrange.c | 107 +++++++++++++++++++----------------------- sway/tree/layout.c | 4 +- sway/tree/view.c | 90 +++++++++++++++++------------------ sway/tree/workspace.c | 6 --- 9 files changed, 143 insertions(+), 157 deletions(-) (limited to 'sway/desktop/xwayland.c') diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index dd5bd47c..a8efd893 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -91,7 +91,9 @@ struct sway_container { */ size_t id; - struct sway_container_state pending; + // The pending state is the main container properties, and the current state is in the below struct. + // This means most places of the code can refer to the main variables (pending state) and it'll just work. + struct sway_container_state current; char *name; // The view's title (unformatted) char *formatted_title; // The title displayed in the title bar diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c index 66f33151..e495790c 100644 --- a/sway/desktop/desktop.c +++ b/sway/desktop/desktop.c @@ -7,7 +7,8 @@ void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, for (int i = 0; i < root_container.children->length; ++i) { struct sway_container *cont = root_container.children->items[i]; if (cont->type == C_OUTPUT) { - output_damage_surface(cont->sway_output, lx - cont->x, ly - cont->y, + output_damage_surface(cont->sway_output, + lx - cont->current.swayc_x, ly - cont->current.swayc_y, surface, whole); } } diff --git a/sway/desktop/output.c b/sway/desktop/output.c index c5d445a6..8af05bc3 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -774,9 +774,10 @@ static void render_container_stacked(struct sway_output *output, marks_texture = view ? view->marks_unfocused : NULL; } - int y = con->y + container_titlebar_height() * i; - render_titlebar(output, damage, child, child->x, y, child->width, - colors, title_texture, marks_texture); + int y = con->current.swayc_y + container_titlebar_height() * i; + render_titlebar(output, damage, child, child->current.swayc_x, y, + child->current.swayc_width, colors, + title_texture, marks_texture); if (child == current) { current_colors = colors; @@ -795,7 +796,7 @@ static void render_container_stacked(struct sway_output *output, static void render_container(struct sway_output *output, pixman_region32_t *damage, struct sway_container *con, bool parent_focused) { - switch (con->layout) { + switch (con->current.layout) { case L_NONE: case L_HORIZ: case L_VERT: @@ -832,9 +833,10 @@ static void render_floating_container(struct sway_output *soutput, marks_texture = view->marks_unfocused; } - if (con->sway_view->border == B_NORMAL) { - render_titlebar(soutput, damage, con, con->x, con->y, con->width, - colors, title_texture, marks_texture); + if (con->current.border == B_NORMAL) { + render_titlebar(soutput, damage, con, con->current.swayc_x, + con->current.swayc_y, con->current.swayc_width, colors, + title_texture, marks_texture); } else { render_top_border(soutput, damage, con, colors); } @@ -1184,8 +1186,8 @@ void output_damage_from_view(struct sway_output *output, void output_damage_box(struct sway_output *output, struct wlr_box *_box) { struct wlr_box box; memcpy(&box, _box, sizeof(struct wlr_box)); - box.x -= output->swayc->x; - box.y -= output->swayc->y; + box.x -= output->swayc->current.swayc_x; + box.y -= output->swayc->current.swayc_y; scale_box(&box, output->wlr_output->scale); wlr_output_damage_add_box(output->damage, &box); } @@ -1204,10 +1206,10 @@ static void output_damage_whole_container_iterator(struct sway_container *con, void output_damage_whole_container(struct sway_output *output, struct sway_container *con) { struct wlr_box box = { - .x = con->x - output->wlr_output->lx, - .y = con->y - output->wlr_output->ly, - .width = con->width, - .height = con->height, + .x = con->current.swayc_x - output->wlr_output->lx, + .y = con->current.swayc_y - output->wlr_output->ly, + .width = con->current.swayc_width, + .height = con->current.swayc_height, }; scale_box(&box, output->wlr_output->scale); wlr_output_damage_add_box(output->damage, &box); diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 69f97e3d..313e707b 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -67,8 +67,30 @@ void transaction_add_container(struct sway_transaction *transaction, calloc(1, sizeof(struct sway_transaction_instruction)); instruction->transaction = transaction; instruction->container = container; - memcpy(&instruction->state, &container->pending, - sizeof(struct sway_container_state)); + + // Copy the container's main (pending) properties into the instruction state + struct sway_container_state *state = &instruction->state; + state->layout = container->layout; + state->swayc_x = container->x; + state->swayc_y = container->y; + state->swayc_width = container->width; + state->swayc_height = container->height; + + if (container->type == C_VIEW) { + struct sway_view *view = container->sway_view; + state->view_x = view->x; + state->view_y = view->y; + state->view_width = view->width; + state->view_height = view->height; + state->is_fullscreen = view->is_fullscreen; + state->border = view->border; + state->border_thickness = view->border_thickness; + state->border_top = view->border_top; + state->border_left = view->border_left; + state->border_right = view->border_right; + state->border_bottom = view->border_bottom; + } + list_add(transaction->instructions, instruction); } @@ -102,30 +124,13 @@ static void transaction_apply(struct sway_transaction *transaction) { for (i = 0; i < transaction->instructions->length; ++i) { struct sway_transaction_instruction *instruction = transaction->instructions->items[i]; - struct sway_container_state *state = &instruction->state; struct sway_container *container = instruction->container; - container->layout = state->layout; - container->x = state->swayc_x; - container->y = state->swayc_y; - container->width = state->swayc_width; - container->height = state->swayc_height; + memcpy(&instruction->container->current, &instruction->state, + sizeof(struct sway_container_state)); if (container->type == C_VIEW) { - struct sway_view *view = container->sway_view; - view->x = state->view_x; - view->y = state->view_y; - view->width = state->view_width; - view->height = state->view_height; - view->is_fullscreen = state->is_fullscreen; - view->border = state->border; - view->border_thickness = state->border_thickness; - view->border_top = state->border_top; - view->border_left = state->border_left; - view->border_right = state->border_right; - view->border_bottom = state->border_bottom; - - remove_saved_view_texture(view); + remove_saved_view_texture(container->sway_view); } } diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 6a3c1b66..d8442530 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -257,11 +257,9 @@ static void handle_commit(struct wl_listener *listener, void *data) { if (view->swayc && container_is_floating(view->swayc)) { view_update_size(view, xsurface->width, xsurface->height); } else { - view_update_size(view, view->swayc->pending.swayc_width, - view->swayc->pending.swayc_height); + view_update_size(view, view->swayc->width, view->swayc->height); } - view_update_position(view, - view->swayc->pending.view_x, view->swayc->pending.view_y); + view_update_position(view, view->x, view->y); view_damage_from(view); } } @@ -314,7 +312,8 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { return; } // TODO: Let floating views do whatever - configure(view, view->swayc->x, view->swayc->y, view->width, view->height); + configure(view, view->swayc->current.view_x, view->swayc->current.view_y, + view->swayc->current.view_width, view->swayc->current.view_height); } static void handle_request_fullscreen(struct wl_listener *listener, void *data) { diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index d8b3aec1..cf7ce61c 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -22,48 +22,46 @@ static void apply_horiz_layout(struct sway_container *parent) { return; } size_t parent_offset = 0; - if (parent->parent->pending.layout == L_TABBED) { + if (parent->parent->layout == L_TABBED) { parent_offset = container_titlebar_height(); - } else if (parent->parent->pending.layout == L_STACKED) { + } else if (parent->parent->layout == L_STACKED) { parent_offset = container_titlebar_height() * parent->parent->children->length; } - size_t parent_height = parent->pending.swayc_height - parent_offset; + size_t parent_height = parent->height - parent_offset; // Calculate total width of children double total_width = 0; for (size_t i = 0; i < num_children; ++i) { struct sway_container *child = parent->children->items[i]; - if (child->pending.swayc_width <= 0) { + if (child->width <= 0) { if (num_children > 1) { - child->pending.swayc_width = - parent->pending.swayc_width / (num_children - 1); + child->width = parent->width / (num_children - 1); } else { - child->pending.swayc_width = parent->pending.swayc_width; + child->width = parent->width; } } - total_width += child->pending.swayc_width; + total_width += child->width; } - double scale = parent->pending.swayc_width / total_width; + double scale = parent->width / total_width; // Resize windows wlr_log(L_DEBUG, "Arranging %p horizontally", parent); - double child_x = parent->pending.swayc_x; + double child_x = parent->x; for (size_t i = 0; i < num_children; ++i) { struct sway_container *child = parent->children->items[i]; wlr_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", - child, child->type, child->pending.swayc_width, scale); - child->pending.swayc_x = child_x; - child->pending.swayc_y = parent->pending.swayc_y + parent_offset; - child->pending.swayc_width = floor(child->pending.swayc_width * scale); - child->pending.swayc_height = parent_height; - child_x += child->pending.swayc_width; + child, child->type, child->width, scale); + child->x = child_x; + child->y = parent->y + parent_offset; + child->width = floor(child->width * scale); + child->height = parent_height; + child_x += child->width; // Make last child use remaining width of parent if (i == num_children - 1) { - child->pending.swayc_width = parent->pending.swayc_x + - parent->pending.swayc_width - child->pending.swayc_x; + child->width = parent->x + parent->width - child->x; } } } @@ -74,49 +72,47 @@ static void apply_vert_layout(struct sway_container *parent) { return; } size_t parent_offset = 0; - if (parent->parent->pending.layout == L_TABBED) { + if (parent->parent->layout == L_TABBED) { parent_offset = container_titlebar_height(); - } else if (parent->parent->pending.layout == L_STACKED) { + } else if (parent->parent->layout == L_STACKED) { parent_offset = container_titlebar_height() * parent->parent->children->length; } - size_t parent_height = parent->pending.swayc_height - parent_offset; + size_t parent_height = parent->height - parent_offset; // Calculate total height of children double total_height = 0; for (size_t i = 0; i < num_children; ++i) { struct sway_container *child = parent->children->items[i]; - if (child->pending.swayc_height <= 0) { + if (child->height <= 0) { if (num_children > 1) { - child->pending.swayc_height = - parent_height / (num_children - 1); + child->height = parent_height / (num_children - 1); } else { - child->pending.swayc_height = parent_height; + child->height = parent_height; } } - total_height += child->pending.swayc_height; + total_height += child->height; } double scale = parent_height / total_height; // Resize wlr_log(L_DEBUG, "Arranging %p vertically", parent); - double child_y = parent->pending.swayc_y + parent_offset; + double child_y = parent->y + parent_offset; for (size_t i = 0; i < num_children; ++i) { struct sway_container *child = parent->children->items[i]; wlr_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", - child, child->type, child->pending.swayc_height, scale); - child->pending.swayc_x = parent->pending.swayc_x; - child->pending.swayc_y = child_y; - child->pending.swayc_width = parent->pending.swayc_width; - child->pending.swayc_height = - floor(child->pending.swayc_height * scale); - child_y += child->pending.swayc_height; + child, child->type, child->height, scale); + child->x = parent->x; + child->y = child_y; + child->width = parent->width; + child->height = floor(child->height * scale); + child_y += child->height; // Make last child use remaining height of parent if (i == num_children - 1) { - child->pending.swayc_height = parent->pending.swayc_y + - parent_offset + parent_height - child->pending.swayc_y; + child->height = + parent->y + parent_offset + parent_height - child->y; } } } @@ -126,19 +122,19 @@ static void apply_tabbed_or_stacked_layout(struct sway_container *parent) { return; } size_t parent_offset = 0; - if (parent->parent->pending.layout == L_TABBED) { + if (parent->parent->layout == L_TABBED) { parent_offset = container_titlebar_height(); - } else if (parent->parent->pending.layout == L_STACKED) { + } else if (parent->parent->layout == L_STACKED) { parent_offset = container_titlebar_height() * parent->parent->children->length; } - size_t parent_height = parent->pending.swayc_height - parent_offset; + size_t parent_height = parent->height - parent_offset; for (int i = 0; i < parent->children->length; ++i) { struct sway_container *child = parent->children->items[i]; - child->pending.swayc_x = parent->pending.swayc_x; - child->pending.swayc_y = parent->pending.swayc_y + parent_offset; - child->pending.swayc_width = parent->pending.swayc_width; - child->pending.swayc_height = parent_height; + child->x = parent->x; + child->y = parent->y + parent_offset; + child->width = parent->width; + child->height = parent_height; } } @@ -148,11 +144,10 @@ static void _arrange_children_of(struct sway_container *parent, return; } wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent, - parent->name, parent->pending.swayc_width, parent->pending.swayc_height, - parent->pending.swayc_x, parent->pending.swayc_y); + parent->name, parent->width, parent->height, parent->x, parent->y); // Calculate x, y, width and height of children - switch (parent->pending.layout) { + switch (parent->layout) { case L_HORIZ: apply_horiz_layout(parent); break; @@ -191,13 +186,13 @@ static void _arrange_workspace(struct sway_container *workspace, struct wlr_box *area = &output->sway_output->usable_area; wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d", area->width, area->height, area->x, area->y); - workspace->pending.swayc_width = area->width; - workspace->pending.swayc_height = area->height; - workspace->pending.swayc_x = output->x + area->x; - workspace->pending.swayc_y = output->y + area->y; + workspace->width = area->width; + workspace->height = area->height; + workspace->x = output->x + area->x; + workspace->y = output->y + area->y; transaction_add_container(transaction, workspace); wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, - workspace->pending.swayc_x, workspace->pending.swayc_y); + workspace->x, workspace->y); _arrange_children_of(workspace, transaction); } @@ -213,13 +208,9 @@ static void _arrange_output(struct sway_container *output, output->y = output_box->y; output->width = output_box->width; output->height = output_box->height; - output->pending.swayc_x = output_box->x; - output->pending.swayc_y = output_box->y; - output->pending.swayc_width = output_box->width; - output->pending.swayc_height = output_box->height; transaction_add_container(transaction, output); wlr_log(L_DEBUG, "Arranging output '%s' at %f,%f", - output->name, output->pending.swayc_x, output->pending.swayc_y); + output->name, output->x, output->y); for (int i = 0; i < output->children->length; ++i) { struct sway_container *workspace = output->children->items[i]; _arrange_workspace(workspace, transaction); @@ -238,10 +229,6 @@ static void _arrange_root(struct sway_transaction *transaction) { root_container.y = layout_box->y; root_container.width = layout_box->width; root_container.height = layout_box->height; - root_container.pending.swayc_x = layout_box->x; - root_container.pending.swayc_y = layout_box->y; - root_container.pending.swayc_width = layout_box->width; - root_container.pending.swayc_height = layout_box->height; transaction_add_container(transaction, &root_container); for (int i = 0; i < root_container.children->length; ++i) { struct sway_container *output = root_container.children->items[i]; diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 3bba049a..6d4cd088 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -915,10 +915,10 @@ void container_recursive_resize(struct sway_container *container, bool layout_match = true; wlr_log(L_DEBUG, "Resizing %p with amount: %f", container, amount); if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) { - container->pending.swayc_width += amount; + container->width += amount; layout_match = container->layout == L_HORIZ; } else if (edge == RESIZE_EDGE_TOP || edge == RESIZE_EDGE_BOTTOM) { - container->pending.swayc_height += amount; + container->height += amount; layout_match = container->layout == L_VERT; } if (container->children) { diff --git a/sway/tree/view.c b/sway/tree/view.c index 40fe2740..dbf803c6 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -187,23 +187,23 @@ void view_autoconfigure(struct sway_view *view) { } } - struct sway_container_state *state = &view->swayc->pending; + struct sway_container *con = view->swayc; - state->border_top = state->border_bottom = true; - state->border_left = state->border_right = true; + view->border_top = view->border_bottom = true; + view->border_left = view->border_right = true; if (config->hide_edge_borders == E_BOTH || config->hide_edge_borders == E_VERTICAL || (config->hide_edge_borders == E_SMART && !other_views)) { - state->border_left = state->swayc_x != ws->x; - int right_x = state->swayc_x + state->swayc_width; - state->border_right = right_x != ws->x + ws->width; + view->border_left = con->x != ws->x; + int right_x = con->x + con->width; + view->border_right = right_x != ws->x + ws->width; } if (config->hide_edge_borders == E_BOTH || config->hide_edge_borders == E_HORIZONTAL || (config->hide_edge_borders == E_SMART && !other_views)) { - state->border_top = state->swayc_y != ws->y; - int bottom_y = state->swayc_y + state->swayc_height; - state->border_bottom = bottom_y != ws->y + ws->height; + view->border_top = con->y != ws->y; + int bottom_y = con->y + con->height; + view->border_bottom = bottom_y != ws->y + ws->height; } double x, y, width, height; @@ -213,54 +213,53 @@ void view_autoconfigure(struct sway_view *view) { // In a tabbed or stacked container, the swayc's y is the top of the title // area. We have to offset the surface y by the height of the title bar, and // disable any top border because we'll always have the title bar. - if (view->swayc->parent->pending.layout == L_TABBED) { + if (con->parent->layout == L_TABBED) { y_offset = container_titlebar_height(); - state->border_top = false; - } else if (view->swayc->parent->pending.layout == L_STACKED) { - y_offset = container_titlebar_height() - * view->swayc->parent->children->length; + view->border_top = false; + } else if (con->parent->layout == L_STACKED) { + y_offset = container_titlebar_height() * con->parent->children->length; view->border_top = false; } - switch (state->border) { + switch (view->border) { case B_NONE: - x = state->swayc_x; - y = state->swayc_y + y_offset; - width = state->swayc_width; - height = state->swayc_height - y_offset; + x = con->x; + y = con->y + y_offset; + width = con->width; + height = con->height - y_offset; break; case B_PIXEL: - x = state->swayc_x + state->border_thickness * state->border_left; - y = state->swayc_y + state->border_thickness * state->border_top + y_offset; - width = state->swayc_width - - state->border_thickness * state->border_left - - state->border_thickness * state->border_right; - height = state->swayc_height - y_offset - - state->border_thickness * state->border_top - - state->border_thickness * state->border_bottom; + x = con->x + view->border_thickness * view->border_left; + y = con->y + view->border_thickness * view->border_top + y_offset; + width = con->width + - view->border_thickness * view->border_left + - view->border_thickness * view->border_right; + height = con->height - y_offset + - view->border_thickness * view->border_top + - view->border_thickness * view->border_bottom; break; case B_NORMAL: // Height is: 1px border + 3px pad + title height + 3px pad + 1px border - x = state->swayc_x + state->border_thickness * state->border_left; - width = state->swayc_width - - state->border_thickness * state->border_left - - state->border_thickness * state->border_right; + x = con->x + view->border_thickness * view->border_left; + width = con->width + - view->border_thickness * view->border_left + - view->border_thickness * view->border_right; if (y_offset) { - y = state->swayc_y + y_offset; - height = state->swayc_height - y_offset - - state->border_thickness * state->border_bottom; + y = con->y + y_offset; + height = con->height - y_offset + - view->border_thickness * view->border_bottom; } else { - y = state->swayc_y + container_titlebar_height(); - height = state->swayc_height - container_titlebar_height() - - state->border_thickness * state->border_bottom; + y = con->y + container_titlebar_height(); + height = con->height - container_titlebar_height() + - view->border_thickness * view->border_bottom; } break; } - state->view_x = x; - state->view_y = y; - state->view_width = width; - state->view_height = height; + view->x = x; + view->y = y; + view->width = width; + view->height = height; } void view_set_activated(struct sway_view *view, bool activated) { @@ -319,9 +318,8 @@ void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen) { view_configure(view, view->saved_x, view->saved_y, view->saved_width, view->saved_height); } else { - view->swayc->width = view->swayc->saved_width; - view->swayc->height = view->swayc->saved_height; - view_autoconfigure(view); + view->swayc->width = view->swayc->saved_width; + view->swayc->height = view->swayc->saved_height; } } } @@ -508,8 +506,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { view->swayc = cont; view->border = config->border; view->border_thickness = config->border_thickness; - view->swayc->pending.border = config->border; - view->swayc->pending.border_thickness = config->border_thickness; view_init_subsurfaces(view, wlr_surface); wl_signal_add(&wlr_surface->events.new_subsurface, @@ -977,7 +973,7 @@ bool view_is_visible(struct sway_view *view) { } // Check the workspace is visible if (!is_sticky) { - return workspace_is_visible(workspace); + return workspace_is_visible(workspace); } return true; } diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index ad581a96..9ba210fd 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -60,12 +60,6 @@ struct sway_container *workspace_create(struct sway_container *output, workspace->prev_layout = L_NONE; workspace->layout = container_get_default_layout(output); - workspace->pending.swayc_x = workspace->x; - workspace->pending.swayc_y = workspace->y; - workspace->pending.swayc_width = workspace->width; - workspace->pending.swayc_height = workspace->height; - workspace->pending.layout = workspace->layout; - struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace)); if (!swayws) { return NULL; -- cgit v1.2.3 From bb66e6d578fdc68fb33d0fde921390d74f20bb31 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 6 Jun 2018 22:57:34 +1000 Subject: Refactor everything that needs to arrange windows * The arrange_foo functions are now replaced with arrange_and_commit, or with manually created transactions and arrange_windows x2. * The arrange functions are now only called from the highest level functions rather than from both high level and low level functions. * Due to the previous point, view_set_fullscreen_raw and view_set_fullscreen are both merged into one function again. * Floating and fullscreen are now working with transactions. --- include/sway/desktop/transaction.h | 7 +--- include/sway/tree/arrange.h | 7 ---- include/sway/tree/view.h | 5 +++ sway/commands/border.c | 7 ++-- sway/commands/floating.c | 3 ++ sway/commands/fullscreen.c | 4 +++ sway/commands/layout.c | 2 +- sway/commands/move.c | 41 +++++++++++++++++++--- sway/commands/reload.c | 2 +- sway/commands/resize.c | 2 +- sway/commands/split.c | 2 +- sway/commands/swap.c | 12 +++++++ sway/config.c | 4 +-- sway/desktop/layer_shell.c | 2 +- sway/desktop/output.c | 8 ++--- sway/desktop/transaction.c | 19 +++++++--- sway/desktop/xdg_shell.c | 18 ++++++---- sway/desktop/xdg_shell_v6.c | 20 +++++++---- sway/desktop/xwayland.c | 3 ++ sway/tree/arrange.c | 63 +++++++++++++++++---------------- sway/tree/container.c | 10 +++--- sway/tree/layout.c | 71 ++++++++++---------------------------- sway/tree/view.c | 49 +++++++++----------------- sway/tree/workspace.c | 2 +- 24 files changed, 192 insertions(+), 171 deletions(-) (limited to 'sway/desktop/xwayland.c') diff --git a/include/sway/desktop/transaction.h b/include/sway/desktop/transaction.h index 575d28c8..5aff28e9 100644 --- a/include/sway/desktop/transaction.h +++ b/include/sway/desktop/transaction.h @@ -16,12 +16,7 @@ * the updates all at the same time. */ -struct sway_transaction { - struct wl_event_source *timer; - list_t *instructions; // struct sway_transaction_instruction * - list_t *damage; // struct wlr_box * - size_t num_waiting; -}; +struct sway_transaction; /** * Create a new transaction. diff --git a/include/sway/tree/arrange.h b/include/sway/tree/arrange.h index 23cd66dc..897a9392 100644 --- a/include/sway/tree/arrange.h +++ b/include/sway/tree/arrange.h @@ -23,11 +23,4 @@ void arrange_windows(struct sway_container *container, */ void arrange_and_commit(struct sway_container *container); -// These functions are temporary and are only here to make everything compile. -// They are wrappers around arrange_and_commit. -void arrange_root(void); -void arrange_output(struct sway_container *container); -void arrange_workspace(struct sway_container *container); -void arrange_children_of(struct sway_container *container); - #endif diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index f47db567..d0093db5 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -214,6 +214,11 @@ const char *view_get_shell(struct sway_view *view); uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, int height); +/** + * Center the view in its workspace and build the swayc decorations around it. + */ +void view_init_floating(struct sway_view *view); + /** * Configure the view's position and size based on the swayc's position and * size, taking borders into consideration. diff --git a/sway/commands/border.c b/sway/commands/border.c index 0b059562..6db85395 100644 --- a/sway/commands/border.c +++ b/sway/commands/border.c @@ -3,6 +3,7 @@ #include "sway/config.h" #include "sway/input/cursor.h" #include "sway/input/input-manager.h" +#include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/view.h" @@ -38,13 +39,11 @@ struct cmd_results *cmd_border(int argc, char **argv) { } if (container_is_floating(view->swayc)) { - container_damage_whole(view->swayc); container_set_geometry_from_floating_view(view->swayc); - container_damage_whole(view->swayc); - } else { - view_autoconfigure(view); } + arrange_and_commit(view->swayc); + struct sway_seat *seat = input_manager_current_seat(input_manager); if (seat->cursor) { cursor_send_pointer_motion(seat->cursor, 0, false); diff --git a/sway/commands/floating.c b/sway/commands/floating.c index 46b761da..e6003521 100644 --- a/sway/commands/floating.c +++ b/sway/commands/floating.c @@ -36,5 +36,8 @@ struct cmd_results *cmd_floating(int argc, char **argv) { container_set_floating(container, wants_floating); + struct sway_container *workspace = container_parent(container, C_WORKSPACE); + arrange_and_commit(workspace); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index ec9ec276..1a4d8b41 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c @@ -1,6 +1,7 @@ #include "log.h" #include "sway/commands.h" #include "sway/config.h" +#include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/view.h" #include "sway/tree/layout.h" @@ -32,5 +33,8 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { view_set_fullscreen(view, wants_fullscreen); + struct sway_container *workspace = container_parent(container, C_WORKSPACE); + arrange_and_commit(workspace->parent); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/layout.c b/sway/commands/layout.c index a009e38f..9945fa5c 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c @@ -49,7 +49,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) { } container_notify_subtree_changed(parent); - arrange_children_of(parent); + arrange_and_commit(parent); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/move.c b/sway/commands/move.c index dc9a6f6f..2c9fb77a 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -5,8 +5,10 @@ #include #include #include "sway/commands.h" +#include "sway/desktop/transaction.h" #include "sway/input/seat.h" #include "sway/output.h" +#include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/layout.h" #include "sway/tree/workspace.h" @@ -96,6 +98,12 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, seat_set_focus(config->handler_context.seat, focus); container_reap_empty(old_parent); container_reap_empty(destination->parent); + + struct sway_transaction *txn = transaction_create(); + arrange_windows(old_parent, txn); + arrange_windows(destination->parent, txn); + transaction_commit(txn); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } else if (strcasecmp(argv[1], "to") == 0 && strcasecmp(argv[2], "output") == 0) { @@ -125,6 +133,12 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, seat_set_focus(config->handler_context.seat, old_parent); container_reap_empty(old_parent); container_reap_empty(focus->parent); + + struct sway_transaction *txn = transaction_create(); + arrange_windows(old_parent, txn); + arrange_windows(focus->parent, txn); + transaction_commit(txn); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } return cmd_results_new(CMD_INVALID, "move", expected_syntax); @@ -152,9 +166,28 @@ static struct cmd_results *cmd_move_workspace(struct sway_container *current, current = container_parent(current, C_WORKSPACE); } container_move_to(current, destination); + + struct sway_transaction *txn = transaction_create(); + arrange_windows(source, txn); + arrange_windows(destination, txn); + transaction_commit(txn); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } +static void move_in_direction(struct sway_container *container, + enum wlr_direction direction, int move_amt) { + struct sway_container *old_parent = container->parent; + container_move(container, direction, move_amt); + + struct sway_transaction *txn = transaction_create(); + arrange_windows(old_parent, txn); + if (container->parent != old_parent) { + arrange_windows(container->parent, txn); + } + transaction_commit(txn); +} + struct cmd_results *cmd_move(int argc, char **argv) { struct cmd_results *error = NULL; int move_amt = 10; @@ -173,13 +206,13 @@ struct cmd_results *cmd_move(int argc, char **argv) { } if (strcasecmp(argv[0], "left") == 0) { - container_move(current, MOVE_LEFT, move_amt); + move_in_direction(current, MOVE_LEFT, move_amt); } else if (strcasecmp(argv[0], "right") == 0) { - container_move(current, MOVE_RIGHT, move_amt); + move_in_direction(current, MOVE_RIGHT, move_amt); } else if (strcasecmp(argv[0], "up") == 0) { - container_move(current, MOVE_UP, move_amt); + move_in_direction(current, MOVE_UP, move_amt); } else if (strcasecmp(argv[0], "down") == 0) { - container_move(current, MOVE_DOWN, move_amt); + move_in_direction(current, MOVE_DOWN, move_amt); } else if (strcasecmp(argv[0], "container") == 0 || strcasecmp(argv[0], "window") == 0) { return cmd_move_container(current, argc, argv); diff --git a/sway/commands/reload.c b/sway/commands/reload.c index 092dd46f..9fc213c4 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c @@ -12,6 +12,6 @@ struct cmd_results *cmd_reload(int argc, char **argv) { } load_swaybars(); - arrange_root(); + arrange_and_commit(&root_container); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/resize.c b/sway/commands/resize.c index 29637953..6357343e 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c @@ -182,7 +182,7 @@ static void resize_tiled(int amount, enum resize_axis axis) { } } - arrange_children_of(parent->parent); + arrange_and_commit(parent->parent); } static void resize(int amount, enum resize_axis axis, enum resize_unit unit) { diff --git a/sway/commands/split.c b/sway/commands/split.c index 57e42a5a..7ea14953 100644 --- a/sway/commands/split.c +++ b/sway/commands/split.c @@ -16,7 +16,7 @@ static struct cmd_results *do_split(int layout) { } struct sway_container *parent = container_split(con, layout); container_create_notify(parent); - arrange_children_of(parent); + arrange_and_commit(parent); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/swap.c b/sway/commands/swap.c index e8dfc57f..e052058f 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c @@ -1,6 +1,8 @@ #include #include #include "sway/commands.h" +#include "sway/desktop/transaction.h" +#include "sway/tree/arrange.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" #include "stringop.h" @@ -76,5 +78,15 @@ struct cmd_results *cmd_swap(int argc, char **argv) { } container_swap(current, other); + + struct sway_transaction *txn = transaction_create(); + arrange_windows(current->parent, txn); + + if (other->parent != current->parent) { + arrange_windows(other->parent, txn); + } + + transaction_commit(txn); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/config.c b/sway/config.c index 949c5cd3..12a02163 100644 --- a/sway/config.c +++ b/sway/config.c @@ -531,7 +531,7 @@ static int detect_brace_on_following_line(FILE *file, char *line, } while (peeked && strlen(peeked) == 0); if (peeked && strlen(peeked) == 1 && peeked[0] == '{') { - fseek(file, position, SEEK_SET); + fseek(file, position, SEEK_SET); } else { lines = 0; } @@ -735,6 +735,6 @@ void config_update_font_height(bool recalculate) { } if (config->font_height != prev_max_height) { - arrange_root(); + arrange_and_commit(&root_container); } } diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 3accdefb..fe5fc316 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -176,7 +176,7 @@ void arrange_layers(struct sway_output *output) { sizeof(struct wlr_box)) != 0) { wlr_log(L_DEBUG, "Usable area changed, rearranging output"); memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); - arrange_output(output->swayc); + arrange_and_commit(output->swayc); } // Arrange non-exlusive surfaces from top->bottom diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 8af05bc3..29efdd50 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -1238,13 +1238,13 @@ static void handle_destroy(struct wl_listener *listener, void *data) { static void handle_mode(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, mode); arrange_layers(output); - arrange_output(output->swayc); + arrange_and_commit(output->swayc); } static void handle_transform(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, transform); arrange_layers(output); - arrange_output(output->swayc); + arrange_and_commit(output->swayc); } static void handle_scale_iterator(struct sway_container *view, void *data) { @@ -1254,8 +1254,8 @@ static void handle_scale_iterator(struct sway_container *view, void *data) { static void handle_scale(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, scale); arrange_layers(output); - arrange_output(output->swayc); container_descendants(output->swayc, C_VIEW, handle_scale_iterator, NULL); + arrange_and_commit(output->swayc); } void handle_new_output(struct wl_listener *listener, void *data) { @@ -1314,5 +1314,5 @@ void output_enable(struct sway_output *output) { output->damage_destroy.notify = damage_handle_destroy; arrange_layers(output); - arrange_root(); + arrange_and_commit(&root_container); } diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 313e707b..ee9883e2 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -17,6 +17,13 @@ */ #define TIMEOUT_MS 200 +struct sway_transaction { + struct wl_event_source *timer; + list_t *instructions; // struct sway_transaction_instruction * + list_t *damage; // struct wlr_box * + size_t num_waiting; +}; + struct sway_transaction_instruction { struct sway_transaction *transaction; struct sway_container *container; @@ -162,16 +169,18 @@ void transaction_commit(struct sway_transaction *transaction) { for (int i = 0; i < transaction->instructions->length; ++i) { struct sway_transaction_instruction *instruction = transaction->instructions->items[i]; - if (instruction->container->type == C_VIEW) { - struct sway_view *view = instruction->container->sway_view; - instruction->serial = view_configure(view, + struct sway_container *con = instruction->container; + if (con->type == C_VIEW && + (con->current.view_width != instruction->state.view_width || + con->current.view_height != instruction->state.view_height)) { + instruction->serial = view_configure(con->sway_view, instruction->state.view_x, instruction->state.view_y, instruction->state.view_width, instruction->state.view_height); if (instruction->serial) { - save_view_texture(view); - list_add(view->instructions, instruction); + save_view_texture(con->sway_view); + list_add(con->sway_view->instructions, instruction); ++transaction->num_waiting; } } diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index f43a0a1b..d22c967c 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -5,10 +5,10 @@ #include #include #include "log.h" -#include "sway/desktop/transaction.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/server.h" +#include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" @@ -210,8 +210,14 @@ static void handle_map(struct wl_listener *listener, void *data) { view->natural_width = view->wlr_xdg_surface->surface->current->width; view->natural_height = view->wlr_xdg_surface->surface->current->height; } + view_map(view, view->wlr_xdg_surface->surface); + if (xdg_surface->toplevel->client_pending.fullscreen) { + view_set_fullscreen(view, true); + } + arrange_and_commit(view->swayc->parent); + xdg_shell_view->commit.notify = handle_commit; wl_signal_add(&xdg_surface->surface->events.commit, &xdg_shell_view->commit); @@ -219,10 +225,6 @@ static void handle_map(struct wl_listener *listener, void *data) { xdg_shell_view->new_popup.notify = handle_new_popup; wl_signal_add(&xdg_surface->events.new_popup, &xdg_shell_view->new_popup); - - if (xdg_surface->toplevel->client_pending.fullscreen) { - view_set_fullscreen(view, true); - } } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -237,6 +239,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) struct wlr_xdg_toplevel_set_fullscreen_event *e = data; struct wlr_xdg_surface *xdg_surface = xdg_shell_view->view.wlr_xdg_surface; + struct sway_view *view = &xdg_shell_view->view; if (!sway_assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL, "xdg_shell requested fullscreen of surface with role %i", @@ -247,7 +250,10 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) return; } - view_set_fullscreen(&xdg_shell_view->view, e->fullscreen); + view_set_fullscreen(view, e->fullscreen); + + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + arrange_and_commit(ws); } void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index bce59174..7ec9e6cb 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -3,10 +3,10 @@ #include #include #include -#include "sway/desktop/transaction.h" +#include "sway/server.h" +#include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/layout.h" -#include "sway/server.h" #include "sway/tree/view.h" #include "sway/input/seat.h" #include "sway/input/input-manager.h" @@ -210,8 +210,14 @@ static void handle_map(struct wl_listener *listener, void *data) { view->natural_width = view->wlr_xdg_surface_v6->surface->current->width; view->natural_height = view->wlr_xdg_surface_v6->surface->current->height; } + view_map(view, view->wlr_xdg_surface_v6->surface); + if (xdg_surface->toplevel->client_pending.fullscreen) { + view_set_fullscreen(view, true); + } + arrange_and_commit(view->swayc->parent); + xdg_shell_v6_view->commit.notify = handle_commit; wl_signal_add(&xdg_surface->surface->events.commit, &xdg_shell_v6_view->commit); @@ -219,10 +225,6 @@ static void handle_map(struct wl_listener *listener, void *data) { xdg_shell_v6_view->new_popup.notify = handle_new_popup; wl_signal_add(&xdg_surface->events.new_popup, &xdg_shell_v6_view->new_popup); - - if (xdg_surface->toplevel->client_pending.fullscreen) { - view_set_fullscreen(view, true); - } } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -237,6 +239,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) struct wlr_xdg_toplevel_v6_set_fullscreen_event *e = data; struct wlr_xdg_surface_v6 *xdg_surface = xdg_shell_v6_view->view.wlr_xdg_surface_v6; + struct sway_view *view = &xdg_shell_v6_view->view; if (!sway_assert(xdg_surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL, "xdg_shell_v6 requested fullscreen of surface with role %i", @@ -247,7 +250,10 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) return; } - view_set_fullscreen(&xdg_shell_v6_view->view, e->fullscreen); + view_set_fullscreen(view, e->fullscreen); + + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + arrange_and_commit(ws); } void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index d8442530..70929d48 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -11,6 +11,7 @@ #include "sway/input/seat.h" #include "sway/output.h" #include "sway/server.h" +#include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" @@ -292,6 +293,7 @@ static void handle_map(struct wl_listener *listener, void *data) { if (xsurface->fullscreen) { view_set_fullscreen(view, true); } + arrange_and_commit(view->swayc); } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -325,6 +327,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) return; } view_set_fullscreen(view, xsurface->fullscreen); + arrange_and_commit(view->swayc); } static void handle_set_title(struct wl_listener *listener, void *data) { diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index cf7ce61c..e138410d 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -138,7 +138,23 @@ static void apply_tabbed_or_stacked_layout(struct sway_container *parent) { } } -static void _arrange_children_of(struct sway_container *parent, +static void arrange_children_of(struct sway_container *parent, + struct sway_transaction *transaction); + +static void arrange_floating(struct sway_container *floating, + struct sway_transaction *transaction) { + for (int i = 0; i < floating->children->length; ++i) { + struct sway_container *floater = floating->children->items[i]; + if (floater->type == C_VIEW) { + view_autoconfigure(floater->sway_view); + } else { + arrange_children_of(floater, transaction); + } + transaction_add_container(transaction, floater); + } +} + +static void arrange_children_of(struct sway_container *parent, struct sway_transaction *transaction) { if (config->reloading) { return; @@ -162,7 +178,8 @@ static void _arrange_children_of(struct sway_container *parent, apply_horiz_layout(parent); break; case L_FLOATING: - sway_assert(false, "Didn't expect to see floating here"); + arrange_floating(parent, transaction); + break; } // Recurse into child containers @@ -171,13 +188,13 @@ static void _arrange_children_of(struct sway_container *parent, if (child->type == C_VIEW) { view_autoconfigure(child->sway_view); } else { - _arrange_children_of(child, transaction); + arrange_children_of(child, transaction); } transaction_add_container(transaction, child); } } -static void _arrange_workspace(struct sway_container *workspace, +static void arrange_workspace(struct sway_container *workspace, struct sway_transaction *transaction) { if (config->reloading) { return; @@ -193,10 +210,11 @@ static void _arrange_workspace(struct sway_container *workspace, transaction_add_container(transaction, workspace); wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, workspace->x, workspace->y); - _arrange_children_of(workspace, transaction); + arrange_floating(workspace->sway_workspace->floating, transaction); + arrange_children_of(workspace, transaction); } -static void _arrange_output(struct sway_container *output, +static void arrange_output(struct sway_container *output, struct sway_transaction *transaction) { if (config->reloading) { return; @@ -213,11 +231,11 @@ static void _arrange_output(struct sway_container *output, output->name, output->x, output->y); for (int i = 0; i < output->children->length; ++i) { struct sway_container *workspace = output->children->items[i]; - _arrange_workspace(workspace, transaction); + arrange_workspace(workspace, transaction); } } -static void _arrange_root(struct sway_transaction *transaction) { +static void arrange_root(struct sway_transaction *transaction) { if (config->reloading) { return; } @@ -232,7 +250,7 @@ static void _arrange_root(struct sway_transaction *transaction) { transaction_add_container(transaction, &root_container); for (int i = 0; i < root_container.children->length; ++i) { struct sway_container *output = root_container.children->items[i]; - _arrange_output(output, transaction); + arrange_output(output, transaction); } } @@ -240,19 +258,21 @@ void arrange_windows(struct sway_container *container, struct sway_transaction *transaction) { switch (container->type) { case C_ROOT: - _arrange_root(transaction); + arrange_root(transaction); break; case C_OUTPUT: - _arrange_output(container, transaction); + arrange_output(container, transaction); break; case C_WORKSPACE: - _arrange_workspace(container, transaction); + arrange_workspace(container, transaction); break; case C_CONTAINER: - _arrange_children_of(container, transaction); + arrange_children_of(container, transaction); transaction_add_container(transaction, container); break; case C_VIEW: + view_autoconfigure(container->sway_view); + transaction_add_container(transaction, container); break; case C_TYPES: break; @@ -265,20 +285,3 @@ void arrange_and_commit(struct sway_container *container) { arrange_windows(container, transaction); transaction_commit(transaction); } - -// These functions are only temporary -void arrange_root() { - arrange_and_commit(&root_container); -} - -void arrange_output(struct sway_container *container) { - arrange_and_commit(container); -} - -void arrange_workspace(struct sway_container *container) { - arrange_and_commit(container); -} - -void arrange_children_of(struct sway_container *container) { - arrange_and_commit(container); -} diff --git a/sway/tree/container.c b/sway/tree/container.c index e6956f5c..d312eb60 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -204,6 +204,7 @@ static struct sway_container *container_workspace_destroy( container_move_to(floating->children->items[i], new_workspace->sway_workspace->floating); } + arrange_and_commit(new_workspace); } struct sway_workspace *sway_workspace = workspace->sway_workspace; @@ -264,10 +265,10 @@ static struct sway_container *container_output_destroy( } container_sort_workspaces(new_output); - arrange_output(new_output); } } } + arrange_and_commit(&root_container); wl_list_remove(&output->sway_output->mode.link); wl_list_remove(&output->sway_output->transform.link); @@ -924,13 +925,12 @@ void container_set_floating(struct sway_container *container, bool enable) { struct sway_container *workspace = container_parent(container, C_WORKSPACE); struct sway_seat *seat = input_manager_current_seat(input_manager); - container_damage_whole(container); if (enable) { container_remove_child(container); container_add_child(workspace->sway_workspace->floating, container); if (container->type == C_VIEW) { - view_autoconfigure(container->sway_view); + view_init_floating(container->sway_view); } seat_set_focus(seat, seat_get_focus_inactive(seat, container)); container_reap_empty_recursive(workspace); @@ -943,8 +943,8 @@ void container_set_floating(struct sway_container *container, bool enable) { container->is_sticky = false; container_reap_empty_recursive(workspace->sway_workspace->floating); } - arrange_workspace(workspace); - container_damage_whole(container); + + ipc_event_window(container, "floating"); } void container_set_geometry_from_floating_view(struct sway_container *con) { diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 6d4cd088..65b61495 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -22,7 +22,7 @@ struct sway_container root_container; static void output_layout_handle_change(struct wl_listener *listener, void *data) { - arrange_root(); + arrange_and_commit(&root_container); } void layout_init(void) { @@ -56,18 +56,17 @@ static int index_child(const struct sway_container *child) { return -1; } -static void container_handle_fullscreen_reparent(struct sway_container *viewcon, +static void container_handle_fullscreen_reparent(struct sway_container *con, struct sway_container *old_parent) { - if (viewcon->type != C_VIEW || !viewcon->sway_view->is_fullscreen) { + if (con->type != C_VIEW || !con->sway_view->is_fullscreen) { return; } - struct sway_view *view = viewcon->sway_view; + struct sway_view *view = con->sway_view; struct sway_container *old_workspace = old_parent; if (old_workspace && old_workspace->type != C_WORKSPACE) { old_workspace = container_parent(old_workspace, C_WORKSPACE); } - struct sway_container *new_workspace = container_parent(view->swayc, - C_WORKSPACE); + struct sway_container *new_workspace = container_parent(con, C_WORKSPACE); if (old_workspace == new_workspace) { return; } @@ -78,15 +77,19 @@ static void container_handle_fullscreen_reparent(struct sway_container *viewcon, // Mark the new workspace as fullscreen if (new_workspace->sway_workspace->fullscreen) { - view_set_fullscreen_raw( - new_workspace->sway_workspace->fullscreen, false); + view_set_fullscreen(new_workspace->sway_workspace->fullscreen, false); } new_workspace->sway_workspace->fullscreen = view; // Resize view to new output dimensions struct sway_container *output = new_workspace->parent; - view_configure(view, 0, 0, output->width, output->height); - view->swayc->width = output->width; - view->swayc->height = output->height; + view->x = output->x; + view->y = output->y; + view->width = output->width; + view->height = output->height; + con->x = output->x; + con->y = output->y; + con->width = output->width; + con->height = output->height; } void container_insert_child(struct sway_container *parent, @@ -188,18 +191,7 @@ void container_move_to(struct sway_container *container, } container_notify_subtree_changed(old_parent); container_notify_subtree_changed(new_parent); - if (old_parent) { - if (old_parent->type == C_OUTPUT) { - arrange_output(old_parent); - } else { - arrange_children_of(old_parent); - } - } - if (new_parent->type == C_OUTPUT) { - arrange_output(new_parent); - } else { - arrange_children_of(new_parent); - } + // If view was moved to a fullscreen workspace, refocus the fullscreen view struct sway_container *new_workspace = container; if (new_workspace->type != C_WORKSPACE) { @@ -214,7 +206,8 @@ void container_move_to(struct sway_container *container, if (focus_ws->type != C_WORKSPACE) { focus_ws = container_parent(focus_ws, C_WORKSPACE); } - seat_set_focus(seat, new_workspace->sway_workspace->fullscreen->swayc); + seat_set_focus(seat, + new_workspace->sway_workspace->fullscreen->swayc); if (focus_ws != new_workspace) { seat_set_focus(seat, focus); } @@ -308,7 +301,6 @@ static void workspace_rejigger(struct sway_container *ws, container_reap_empty_recursive(original_parent); wl_signal_emit(&child->events.reparent, original_parent); container_create_notify(new_parent); - arrange_workspace(ws); } static void move_out_of_tabs_stacks(struct sway_container *container, @@ -319,11 +311,6 @@ static void move_out_of_tabs_stacks(struct sway_container *container, wlr_log(L_DEBUG, "Changing layout of %zd", current->parent->id); current->parent->layout = move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; - if (current->parent->type == C_WORKSPACE) { - arrange_workspace(current->parent); - } else { - arrange_children_of(current->parent); - } return; } @@ -339,11 +326,6 @@ static void move_out_of_tabs_stacks(struct sway_container *container, container_flatten(new_parent->parent); } container_create_notify(new_parent); - if (is_workspace) { - arrange_workspace(new_parent->parent); - } else { - arrange_children_of(new_parent); - } container_notify_subtree_changed(new_parent); } @@ -367,10 +349,7 @@ void container_move(struct sway_container *container, struct sway_container *new_parent = container_flatten(parent); if (new_parent != parent) { - // Special case: we were the last one in this container, so flatten it - // and leave - arrange_children_of(new_parent); - update_debug_tree(); + // Special case: we were the last one in this container, so leave return; } @@ -452,12 +431,9 @@ void container_move(struct sway_container *container, wlr_log(L_DEBUG, "Hit limit, " "promoting descendant to sibling"); // Special case - struct sway_container *old_parent = container->parent; container_insert_child(current->parent, container, index + (offs < 0 ? 0 : 1)); container->width = container->height = 0; - arrange_children_of(current->parent); - arrange_children_of(old_parent); return; } } else { @@ -491,14 +467,11 @@ void container_move(struct sway_container *container, wlr_log(L_DEBUG, "Swapping siblings"); sibling->parent->children->items[index + offs] = container; sibling->parent->children->items[index] = sibling; - arrange_children_of(sibling->parent); } else { wlr_log(L_DEBUG, "Promoting to sibling of cousin"); container_insert_child(sibling->parent, container, index_child(sibling) + (offs > 0 ? 0 : 1)); container->width = container->height = 0; - arrange_children_of(sibling->parent); - arrange_children_of(old_parent); } sibling = NULL; break; @@ -512,8 +485,6 @@ void container_move(struct sway_container *container, "(move dir: %d)", limit, move_dir); container_insert_child(sibling, container, limit); container->width = container->height = 0; - arrange_children_of(sibling); - arrange_children_of(old_parent); sibling = NULL; } else { wlr_log(L_DEBUG, "Reparenting container (perpendicular)"); @@ -537,8 +508,6 @@ void container_move(struct sway_container *container, container_add_child(sibling, container); } container->width = container->height = 0; - arrange_children_of(sibling); - arrange_children_of(old_parent); sibling = NULL; } break; @@ -863,7 +832,6 @@ struct sway_container *container_split(struct sway_container *child, // Special case: this just behaves like splitt child->prev_layout = child->layout; child->layout = layout; - arrange_children_of(child); return child; } @@ -1044,9 +1012,6 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) { prev_workspace_name = stored_prev_name; } - arrange_children_of(con1->parent); - arrange_children_of(con2->parent); - if (fs1 && con2->type == C_VIEW) { view_set_fullscreen(con2->sway_view, true); } diff --git a/sway/tree/view.c b/sway/tree/view.c index dbf803c6..658a94e8 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -135,22 +135,22 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, return 0; } -static void view_autoconfigure_floating(struct sway_view *view) { +void view_init_floating(struct sway_view *view) { struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); int max_width = ws->width * 0.6666; int max_height = ws->height * 0.6666; - int width = + view->width = view->natural_width > max_width ? max_width : view->natural_width; - int height = + view->height = view->natural_height > max_height ? max_height : view->natural_height; - int lx = ws->x + (ws->width - width) / 2; - int ly = ws->y + (ws->height - height) / 2; + view->x = ws->x + (ws->width - view->width) / 2; + view->y = ws->y + (ws->height - view->height) / 2; // If the view's border is B_NONE then these properties are ignored. view->border_top = view->border_bottom = true; view->border_left = view->border_right = true; - view_configure(view, lx, ly, width, height); + container_set_geometry_from_floating_view(view->swayc); } void view_autoconfigure(struct sway_view *view) { @@ -162,12 +162,14 @@ void view_autoconfigure(struct sway_view *view) { struct sway_container *output = container_parent(view->swayc, C_OUTPUT); if (view->is_fullscreen) { - view_configure(view, output->x, output->y, output->width, output->height); + view->x = output->x; + view->y = output->y; + view->width = output->width; + view->height = output->height; return; } if (container_is_floating(view->swayc)) { - view_autoconfigure_floating(view); return; } @@ -268,8 +270,7 @@ void view_set_activated(struct sway_view *view, bool activated) { } } -// Set fullscreen, but without IPC events or arranging windows. -void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen) { +void view_set_fullscreen(struct sway_view *view, bool fullscreen) { if (view->is_fullscreen == fullscreen) { return; } @@ -315,26 +316,17 @@ void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen) { } else { workspace->sway_workspace->fullscreen = NULL; if (container_is_floating(view->swayc)) { - view_configure(view, view->saved_x, view->saved_y, - view->saved_width, view->saved_height); + view->x = view->saved_x; + view->y = view->saved_y; + view->width = view->saved_width; + view->height = view->saved_height; + container_set_geometry_from_floating_view(view->swayc); } else { view->swayc->width = view->swayc->saved_width; view->swayc->height = view->swayc->saved_height; } } -} - -void view_set_fullscreen(struct sway_view *view, bool fullscreen) { - if (view->is_fullscreen == fullscreen) { - return; - } - view_set_fullscreen_raw(view, fullscreen); - - struct sway_container *workspace = - container_parent(view->swayc, C_WORKSPACE); - arrange_workspace(workspace); - output_damage_whole(workspace->parent->sway_output); ipc_event_window(view->swayc, "fullscreen_mode"); } @@ -517,8 +509,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { if (view->impl->wants_floating && view->impl->wants_floating(view)) { container_set_floating(view->swayc, true); - } else { - arrange_children_of(cont->parent); } input_manager_set_focus(input_manager, cont); @@ -530,7 +520,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { container_notify_subtree_changed(view->swayc->parent); view_execute_criteria(view); - container_damage_whole(cont); view_handle_container_reparent(&view->container_reparent, NULL); } @@ -561,11 +550,7 @@ void view_unmap(struct sway_view *view) { view->title_format = NULL; } - if (parent->type == C_OUTPUT) { - arrange_output(parent); - } else { - arrange_children_of(parent); - } + arrange_and_commit(parent); } void view_update_position(struct sway_view *view, double lx, double ly) { diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 9ba210fd..ead752ad 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -425,7 +425,7 @@ bool workspace_switch(struct sway_container *workspace) { } seat_set_focus(seat, next); struct sway_container *output = container_parent(workspace, C_OUTPUT); - arrange_output(output); + arrange_and_commit(output); return true; } -- cgit v1.2.3 From 1c89f32533534f6e78c81c95578f40df45bb9016 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 18 Jun 2018 20:42:12 +1000 Subject: Preserve buffers during transactions * Also fix parts of the rendering where it was rendering the pending state instead of current. --- include/sway/tree/view.h | 9 ++-- sway/desktop/output.c | 101 +++++++++++++++++++++++---------------------- sway/desktop/transaction.c | 28 ++++++++----- sway/desktop/xwayland.c | 2 +- sway/tree/container.c | 3 -- 5 files changed, 76 insertions(+), 67 deletions(-) (limited to 'sway/desktop/xwayland.c') diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index d0093db5..fc4c8df9 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -72,10 +72,11 @@ struct sway_view { list_t *marks; // char * list_t *instructions; // struct sway_transaction_instruction * - // If saved_texture is set, the main surface of the view will render this - // texture instead of its own. This is used while waiting for transactions - // to complete. - struct wlr_texture *saved_texture; + // If saved_buffer is set, the main surface of the view will render this + // buffer/texture instead of its own. This is used while waiting for + // transactions to complete. + struct wlr_buffer *saved_buffer; + int saved_surface_width, saved_surface_height; struct wlr_texture *marks_focused; struct wlr_texture *marks_focused_inactive; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 37528cac..a485cb10 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -112,8 +113,8 @@ static bool get_surface_box(struct root_geometry *geo, static bool get_view_box(struct root_geometry *geo, struct sway_output *output, struct sway_view *view, int sx, int sy, struct wlr_box *surface_box) { - int sw = view->width; - int sh = view->height; + int sw = view->saved_surface_width; + int sh = view->saved_surface_height; double _sx = sx, _sy = sy; rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height, @@ -157,10 +158,10 @@ static void output_view_for_each_surface(struct sway_view *view, struct root_geometry *geo, wlr_surface_iterator_func_t iterator, void *user_data) { struct render_data *data = user_data; - geo->x = view->x - data->output->swayc->x; - geo->y = view->y - data->output->swayc->y; - geo->width = view->surface->current->width; - geo->height = view->surface->current->height; + geo->x = view->swayc->current.view_x - data->output->swayc->x; + geo->y = view->swayc->current.view_y - data->output->swayc->y; + geo->width = view->swayc->current.view_width; + geo->height = view->swayc->current.view_height; geo->rotation = 0; // TODO view_for_each_surface(view, iterator, user_data); @@ -277,11 +278,11 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, struct wlr_box box; bool intersects; - // If this is the main surface of a view, render the saved_texture instead + // If this is the main surface of a view, render the saved_buffer instead // if it exists. It exists when we are mid-transaction. - if (data->view && data->view->saved_texture && + if (data->view && data->view->saved_buffer && data->view->surface == surface) { - texture = data->view->saved_texture; + texture = data->view->saved_buffer->texture; intersects = get_view_box(&data->root_geo, data->output, data->view, sx, sy, &box); } else { @@ -405,46 +406,46 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, float output_scale = output->wlr_output->scale; float color[4]; - if (view->border != B_NONE) { - if (view->border_left) { + if (con->current.border != B_NONE) { + if (con->current.border_left) { memcpy(&color, colors->child_border, sizeof(float) * 4); premultiply_alpha(color, con->alpha); - box.x = con->x; - box.y = view->y; - box.width = view->border_thickness; - box.height = view->height; + box.x = con->current.swayc_x; + box.y = con->current.view_y; + box.width = con->current.border_thickness; + box.height = con->current.view_height; scale_box(&box, output_scale); render_rect(output->wlr_output, damage, &box, color); } - if (view->border_right) { + if (con->current.border_right) { if (con->parent->children->length == 1 - && con->parent->layout == L_HORIZ) { + && con->parent->current.layout == L_HORIZ) { memcpy(&color, colors->indicator, sizeof(float) * 4); } else { memcpy(&color, colors->child_border, sizeof(float) * 4); } premultiply_alpha(color, con->alpha); - box.x = view->x + view->width; - box.y = view->y; - box.width = view->border_thickness; - box.height = view->height; + box.x = con->current.view_x + con->current.view_width; + box.y = con->current.view_y; + box.width = con->current.border_thickness; + box.height = con->current.view_height; scale_box(&box, output_scale); render_rect(output->wlr_output, damage, &box, color); } - if (view->border_bottom) { + if (con->current.border_bottom) { if (con->parent->children->length == 1 - && con->parent->layout == L_VERT) { + && con->parent->current.layout == L_VERT) { memcpy(&color, colors->indicator, sizeof(float) * 4); } else { memcpy(&color, colors->child_border, sizeof(float) * 4); } premultiply_alpha(color, con->alpha); - box.x = con->x; - box.y = view->y + view->height; - box.width = con->width; - box.height = view->border_thickness; + box.x = con->current.swayc_x; + box.y = con->current.view_y + con->current.view_height; + box.width = con->current.swayc_width; + box.height = con->current.border_thickness; scale_box(&box, output_scale); render_rect(output->wlr_output, damage, &box, color); } @@ -468,9 +469,8 @@ static void render_titlebar(struct sway_output *output, struct wlr_texture *marks_texture) { struct wlr_box box; float color[4]; - struct sway_view *view = con->type == C_VIEW ? con->sway_view : NULL; float output_scale = output->wlr_output->scale; - enum sway_container_layout layout = con->parent->layout; + enum sway_container_layout layout = con->parent->current.layout; bool is_last_child = con->parent->children->items[con->parent->children->length - 1] == con; @@ -489,9 +489,11 @@ static void render_titlebar(struct sway_output *output, bool connects_sides = false; if (layout == L_HORIZ || layout == L_VERT || (layout == L_STACKED && is_last_child)) { - if (view) { - left_offset = view->border_left * view->border_thickness; - right_offset = view->border_right * view->border_thickness; + if (con->type == C_VIEW) { + left_offset = + con->current.border_left * con->current.border_thickness; + right_offset = + con->current.border_right * con->current.border_thickness; connects_sides = true; } } @@ -612,15 +614,16 @@ static void render_titlebar(struct sway_output *output, // Left pixel in line with bottom bar box.x = x; box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; - box.width = view->border_thickness * view->border_left; + box.width = con->current.border_thickness * con->current.border_left; box.height = TITLEBAR_BORDER_THICKNESS; scale_box(&box, output_scale); render_rect(output->wlr_output, output_damage, &box, color); // Right pixel in line with bottom bar - box.x = x + width - view->border_thickness * view->border_right; + box.x = x + width - + con->current.border_thickness * con->current.border_right; box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; - box.width = view->border_thickness * view->border_right; + box.width = con->current.border_thickness * con->current.border_right; box.height = TITLEBAR_BORDER_THICKNESS; scale_box(&box, output_scale); render_rect(output->wlr_output, output_damage, &box, color); @@ -633,8 +636,7 @@ static void render_titlebar(struct sway_output *output, static void render_top_border(struct sway_output *output, pixman_region32_t *output_damage, struct sway_container *con, struct border_colors *colors) { - struct sway_view *view = con->sway_view; - if (!view->border_top) { + if (!con->current.border_top) { return; } struct wlr_box box; @@ -644,10 +646,10 @@ static void render_top_border(struct sway_output *output, // Child border - top edge memcpy(&color, colors->child_border, sizeof(float) * 4); premultiply_alpha(color, con->alpha); - box.x = con->x; - box.y = con->y; - box.width = con->width; - box.height = view->border_thickness; + box.x = con->current.swayc_x; + box.y = con->current.swayc_y; + box.width = con->current.swayc_width; + box.height = con->current.border_thickness; scale_box(&box, output_scale); render_rect(output->wlr_output, output_damage, &box, color); } @@ -688,9 +690,10 @@ static void render_container_simple(struct sway_output *output, marks_texture = child->sway_view->marks_unfocused; } - if (child->sway_view->border == B_NORMAL) { - render_titlebar(output, damage, child, child->x, child->y, - child->width, colors, title_texture, marks_texture); + if (child->current.border == B_NORMAL) { + render_titlebar(output, damage, child, child->current.swayc_x, + child->current.swayc_y, child->current.swayc_width, + colors, title_texture, marks_texture); } else { render_top_border(output, damage, child, colors); } @@ -739,15 +742,15 @@ static void render_container_tabbed(struct sway_output *output, marks_texture = view ? view->marks_unfocused : NULL; } - int tab_width = con->width / con->children->length; - int x = con->x + tab_width * i; + int tab_width = con->current.swayc_width / con->children->length; + int x = con->current.swayc_x + tab_width * i; // Make last tab use the remaining width of the parent if (i == con->children->length - 1) { - tab_width = con->width - tab_width * i; + tab_width = con->current.swayc_width - tab_width * i; } - render_titlebar(output, damage, child, x, child->y, tab_width, colors, - title_texture, marks_texture); + render_titlebar(output, damage, child, x, child->current.swayc_y, + tab_width, colors, title_texture, marks_texture); if (child == current) { current_colors = colors; diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 07bfbf7a..77377a18 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "sway/debug.h" #include "sway/desktop/transaction.h" @@ -112,16 +113,23 @@ void transaction_add_damage(struct sway_transaction *transaction, list_add(transaction->damage, box); } -static void save_view_texture(struct sway_view *view) { - wlr_texture_destroy(view->saved_texture); - view->saved_texture = NULL; - - // TODO: Copy the texture and store it in view->saved_texture. +static void save_view_buffer(struct sway_view *view) { + if (view->saved_buffer) { + wlr_buffer_unref(view->saved_buffer); + } + wlr_buffer_ref(view->surface->buffer); + view->saved_buffer = view->surface->buffer; + view->saved_surface_width = view->surface->current->width; + view->saved_surface_height = view->surface->current->height; } -static void remove_saved_view_texture(struct sway_view *view) { - wlr_texture_destroy(view->saved_texture); - view->saved_texture = NULL; +static void remove_saved_view_buffer(struct sway_view *view) { + if (view->saved_buffer) { + wlr_buffer_unref(view->saved_buffer); + view->saved_buffer = NULL; + view->saved_surface_width = 0; + view->saved_surface_height = 0; + } } /** @@ -141,7 +149,7 @@ static void transaction_apply(struct sway_transaction *transaction) { sizeof(struct sway_container_state)); if (container->type == C_VIEW) { - remove_saved_view_texture(container->sway_view); + remove_saved_view_buffer(container->sway_view); } } @@ -183,7 +191,7 @@ void transaction_commit(struct sway_transaction *transaction) { instruction->state.view_width, instruction->state.view_height); if (instruction->serial) { - save_view_texture(con->sway_view); + save_view_buffer(con->sway_view); list_add(con->sway_view->instructions, instruction); ++transaction->num_waiting; } diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 70929d48..55917bf6 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -261,8 +261,8 @@ static void handle_commit(struct wl_listener *listener, void *data) { view_update_size(view, view->swayc->width, view->swayc->height); } view_update_position(view, view->x, view->y); - view_damage_from(view); } + view_damage_from(view); } static void handle_unmap(struct wl_listener *listener, void *data) { diff --git a/sway/tree/container.c b/sway/tree/container.c index f8620b72..b071f394 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -766,9 +766,6 @@ static void update_title_texture(struct sway_container *con, "Unexpected type %s", container_type_to_str(con->type))) { return; } - if (!con->width) { - return; - } struct sway_container *output = container_parent(con, C_OUTPUT); if (!output) { return; -- cgit v1.2.3 From 38398e2d77d57dc06b67ec88a54091c897915602 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 23 Jun 2018 16:24:11 +1000 Subject: Implement atomic layout updates for tree operations This implements atomic layout updates for when views map, reparent or unmap. --- include/sway/desktop/transaction.h | 9 ++ include/sway/server.h | 7 + include/sway/tree/container.h | 16 +- include/sway/tree/view.h | 18 +-- sway/commands/split.c | 2 +- sway/desktop/output.c | 293 ++++++++++++++++++------------------- sway/desktop/transaction.c | 176 ++++++++++++++-------- sway/desktop/xdg_shell.c | 35 +++-- sway/desktop/xdg_shell_v6.c | 30 ++-- sway/desktop/xwayland.c | 45 ++++-- sway/main.c | 1 + sway/server.c | 4 + sway/tree/arrange.c | 25 +++- sway/tree/container.c | 184 +++++++++++------------ sway/tree/layout.c | 2 + sway/tree/output.c | 2 - sway/tree/view.c | 76 +++++----- sway/tree/workspace.c | 3 + 18 files changed, 542 insertions(+), 386 deletions(-) (limited to 'sway/desktop/xwayland.c') diff --git a/include/sway/desktop/transaction.h b/include/sway/desktop/transaction.h index 5aff28e9..d6adc609 100644 --- a/include/sway/desktop/transaction.h +++ b/include/sway/desktop/transaction.h @@ -1,5 +1,6 @@ #ifndef _SWAY_TRANSACTION_H #define _SWAY_TRANSACTION_H +#include #include "sway/tree/container.h" /** @@ -48,4 +49,12 @@ void transaction_commit(struct sway_transaction *transaction); */ void transaction_notify_view_ready(struct sway_view *view, uint32_t serial); +/** + * Get the texture that should be rendered for a view. + * + * In most cases this will return the normal live texture for a view, but if the + * view is in a transaction then it'll return a saved texture. + */ +struct wlr_texture *transaction_get_texture(struct sway_view *view); + #endif diff --git a/include/sway/server.h b/include/sway/server.h index 65d96e7a..f5f88a5a 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -12,6 +12,7 @@ #include // TODO WLR: make Xwayland optional #include +#include "list.h" struct sway_server { struct wl_display *wl_display; @@ -43,6 +44,12 @@ struct sway_server { struct wlr_wl_shell *wl_shell; struct wl_listener wl_shell_surface; + + bool terminating; + + // When a view is being destroyed and is waiting for a transaction to + // complete it will be stored here. + list_t *destroying_containers; }; struct sway_server server; diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index f4e978ea..7e78cbef 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -65,8 +65,8 @@ struct sway_container_state { double gaps_inner; double gaps_outer; - //struct sway_container *parent; - //list_t *children; + struct sway_container *parent; + list_t *children; // View properties double view_x, view_y; @@ -79,6 +79,10 @@ struct sway_container_state { bool border_bottom; bool border_left; bool border_right; + + // Workspace properties + struct sway_view *ws_fullscreen; + struct sway_container *ws_floating; }; struct sway_container { @@ -128,8 +132,6 @@ struct sway_container { struct sway_container *parent; - list_t *marks; // list of char* - float alpha; struct wlr_texture *title_focused; @@ -138,6 +140,10 @@ struct sway_container { struct wlr_texture *title_urgent; size_t title_height; + list_t *instructions; // struct sway_transaction_instruction * + + bool destroying; + struct { struct wl_signal destroy; // Raised after the tree updates, but before arrange_windows @@ -181,6 +187,8 @@ struct sway_container *workspace_create(struct sway_container *output, struct sway_container *container_view_create( struct sway_container *sibling, struct sway_view *sway_view); +void container_free(struct sway_container *cont); + struct sway_container *container_destroy(struct sway_container *container); struct sway_container *container_close(struct sway_container *container); diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index fc4c8df9..5a615b43 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -37,7 +37,7 @@ struct sway_view_impl { void (*for_each_surface)(struct sway_view *view, wlr_surface_iterator_func_t iterator, void *user_data); void (*close)(struct sway_view *view); - void (*destroy)(struct sway_view *view); + void (*free)(struct sway_view *view); }; struct sway_view { @@ -68,15 +68,10 @@ struct sway_view { bool border_left; bool border_right; + bool destroying; + list_t *executed_criteria; // struct criteria * list_t *marks; // char * - list_t *instructions; // struct sway_transaction_instruction * - - // If saved_buffer is set, the main surface of the view will render this - // buffer/texture instead of its own. This is used while waiting for - // transactions to complete. - struct wlr_buffer *saved_buffer; - int saved_surface_width, saved_surface_height; struct wlr_texture *marks_focused; struct wlr_texture *marks_focused_inactive; @@ -244,11 +239,16 @@ void view_for_each_surface(struct sway_view *view, void view_init(struct sway_view *view, enum sway_view_type type, const struct sway_view_impl *impl); +void view_free(struct sway_view *view); + void view_destroy(struct sway_view *view); void view_map(struct sway_view *view, struct wlr_surface *wlr_surface); -void view_unmap(struct sway_view *view); +/** + * Unmap the view and return the surviving parent (after reaping). + */ +struct sway_container *view_unmap(struct sway_view *view); void view_update_position(struct sway_view *view, double lx, double ly); diff --git a/sway/commands/split.c b/sway/commands/split.c index 7ea14953..c40f4d9f 100644 --- a/sway/commands/split.c +++ b/sway/commands/split.c @@ -16,7 +16,7 @@ static struct cmd_results *do_split(int layout) { } struct sway_container *parent = container_split(con, layout); container_create_notify(parent); - arrange_and_commit(parent); + arrange_and_commit(parent->parent); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a485cb10..9db95ef5 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -102,40 +102,8 @@ static bool get_surface_box(struct root_geometry *geo, wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box); struct wlr_box output_box = { - .width = output->swayc->width, - .height = output->swayc->height, - }; - - struct wlr_box intersection; - return wlr_box_intersection(&output_box, &rotated_box, &intersection); -} - -static bool get_view_box(struct root_geometry *geo, - struct sway_output *output, struct sway_view *view, int sx, int sy, - struct wlr_box *surface_box) { - int sw = view->saved_surface_width; - int sh = view->saved_surface_height; - - double _sx = sx, _sy = sy; - rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height, - geo->rotation); - - struct wlr_box box = { - .x = geo->x + _sx, - .y = geo->y + _sy, - .width = sw, - .height = sh, - }; - if (surface_box != NULL) { - memcpy(surface_box, &box, sizeof(struct wlr_box)); - } - - struct wlr_box rotated_box; - wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box); - - struct wlr_box output_box = { - .width = output->swayc->width, - .height = output->swayc->height, + .width = output->swayc->current.swayc_width, + .height = output->swayc->current.swayc_height, }; struct wlr_box intersection; @@ -158,8 +126,8 @@ static void output_view_for_each_surface(struct sway_view *view, struct root_geometry *geo, wlr_surface_iterator_func_t iterator, void *user_data) { struct render_data *data = user_data; - geo->x = view->swayc->current.view_x - data->output->swayc->x; - geo->y = view->swayc->current.view_y - data->output->swayc->y; + geo->x = view->swayc->current.view_x - data->output->swayc->current.swayc_x; + geo->y = view->swayc->current.view_y - data->output->swayc->current.swayc_y; geo->width = view->swayc->current.view_width; geo->height = view->swayc->current.view_height; geo->rotation = 0; // TODO @@ -187,8 +155,8 @@ static void unmanaged_for_each_surface(struct wl_list *unmanaged, wl_list_for_each(unmanaged_surface, unmanaged, link) { struct wlr_xwayland_surface *xsurface = unmanaged_surface->wlr_xwayland_surface; - double ox = unmanaged_surface->lx - output->swayc->x; - double oy = unmanaged_surface->ly - output->swayc->y; + double ox = unmanaged_surface->lx - output->swayc->current.swayc_x; + double oy = unmanaged_surface->ly - output->swayc->current.swayc_y; surface_for_each_surface(xsurface->surface, ox, oy, geo, iterator, user_data); @@ -274,26 +242,14 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, pixman_region32_t *output_damage = data->damage; float alpha = data->alpha; - struct wlr_texture *texture = NULL; - struct wlr_box box; - bool intersects; - - // If this is the main surface of a view, render the saved_buffer instead - // if it exists. It exists when we are mid-transaction. - if (data->view && data->view->saved_buffer && - data->view->surface == surface) { - texture = data->view->saved_buffer->texture; - intersects = get_view_box(&data->root_geo, data->output, data->view, - sx, sy, &box); - } else { - texture = wlr_surface_get_texture(surface); - if (texture == NULL) { - return; - } - intersects = get_surface_box(&data->root_geo, data->output, surface, - sx, sy, &box); + struct wlr_texture *texture = wlr_surface_get_texture(surface); + if (!texture) { + return; } + struct wlr_box box; + bool intersects = get_surface_box(&data->root_geo, data->output, surface, + sx, sy, &box); if (!intersects) { return; } @@ -394,58 +350,98 @@ static void render_view_surfaces(struct sway_view *view, view, &data.root_geo, render_surface_iterator, &data); } +static void render_saved_view(struct sway_view *view, + struct sway_output *output, pixman_region32_t *damage, float alpha) { + struct wlr_output *wlr_output = output->wlr_output; + + struct wlr_texture *texture = transaction_get_texture(view); + if (!texture) { + return; + } + struct wlr_box box = { + .x = view->swayc->current.view_x - output->swayc->current.swayc_x, + .y = view->swayc->current.view_y - output->swayc->current.swayc_y, + .width = view->swayc->current.view_width, + .height = view->swayc->current.view_height, + }; + + struct wlr_box output_box = { + .width = output->swayc->current.swayc_width, + .height = output->swayc->current.swayc_height, + }; + + struct wlr_box intersection; + bool intersects = wlr_box_intersection(&output_box, &box, &intersection); + if (!intersects) { + return; + } + + scale_box(&box, wlr_output->scale); + + float matrix[9]; + wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, + wlr_output->transform_matrix); + + render_texture(wlr_output, damage, texture, &box, matrix, alpha); +} + /** * Render a view's surface and left/bottom/right borders. */ static void render_view(struct sway_output *output, pixman_region32_t *damage, struct sway_container *con, struct border_colors *colors) { struct sway_view *view = con->sway_view; - render_view_surfaces(view, output, damage, view->swayc->alpha); + if (view->swayc->instructions->length) { + render_saved_view(view, output, damage, view->swayc->alpha); + } else { + render_view_surfaces(view, output, damage, view->swayc->alpha); + } struct wlr_box box; float output_scale = output->wlr_output->scale; float color[4]; + struct sway_container_state *state = &con->current; - if (con->current.border != B_NONE) { - if (con->current.border_left) { + if (state->border != B_NONE) { + if (state->border_left) { memcpy(&color, colors->child_border, sizeof(float) * 4); premultiply_alpha(color, con->alpha); - box.x = con->current.swayc_x; - box.y = con->current.view_y; - box.width = con->current.border_thickness; - box.height = con->current.view_height; + box.x = state->swayc_x; + box.y = state->view_y; + box.width = state->border_thickness; + box.height = state->view_height; scale_box(&box, output_scale); render_rect(output->wlr_output, damage, &box, color); } - if (con->current.border_right) { - if (con->parent->children->length == 1 - && con->parent->current.layout == L_HORIZ) { + if (state->border_right) { + if (state->parent->current.children->length == 1 + && state->parent->current.layout == L_HORIZ) { memcpy(&color, colors->indicator, sizeof(float) * 4); } else { memcpy(&color, colors->child_border, sizeof(float) * 4); } premultiply_alpha(color, con->alpha); - box.x = con->current.view_x + con->current.view_width; - box.y = con->current.view_y; - box.width = con->current.border_thickness; - box.height = con->current.view_height; + box.x = state->view_x + state->view_width; + box.y = state->view_y; + box.width = state->border_thickness; + box.height = state->view_height; scale_box(&box, output_scale); render_rect(output->wlr_output, damage, &box, color); } - if (con->current.border_bottom) { - if (con->parent->children->length == 1 - && con->parent->current.layout == L_VERT) { + if (state->border_bottom) { + if (state->parent->current.children->length == 1 + && con->current.parent->current.layout == L_VERT) { memcpy(&color, colors->indicator, sizeof(float) * 4); } else { memcpy(&color, colors->child_border, sizeof(float) * 4); } premultiply_alpha(color, con->alpha); - box.x = con->current.swayc_x; - box.y = con->current.view_y + con->current.view_height; - box.width = con->current.swayc_width; - box.height = con->current.border_thickness; + box.x = state->swayc_x; + box.y = state->view_y + state->view_height; + box.width = state->swayc_width; + box.height = state->border_thickness; scale_box(&box, output_scale); render_rect(output->wlr_output, damage, &box, color); } @@ -469,10 +465,13 @@ static void render_titlebar(struct sway_output *output, struct wlr_texture *marks_texture) { struct wlr_box box; float color[4]; + struct sway_container_state *state = &con->current; float output_scale = output->wlr_output->scale; - enum sway_container_layout layout = con->parent->current.layout; - bool is_last_child = - con->parent->children->items[con->parent->children->length - 1] == con; + enum sway_container_layout layout = state->parent->current.layout; + list_t *children = state->parent->current.children; + bool is_last_child = children->items[children->length - 1] == con; + double output_x = output->swayc->current.swayc_x; + double output_y = output->swayc->current.swayc_y; // Single pixel bar above title memcpy(&color, colors->border, sizeof(float) * 4); @@ -490,10 +489,8 @@ static void render_titlebar(struct sway_output *output, if (layout == L_HORIZ || layout == L_VERT || (layout == L_STACKED && is_last_child)) { if (con->type == C_VIEW) { - left_offset = - con->current.border_left * con->current.border_thickness; - right_offset = - con->current.border_right * con->current.border_thickness; + left_offset = state->border_left * state->border_thickness; + right_offset = state->border_right * state->border_thickness; connects_sides = true; } } @@ -527,10 +524,9 @@ static void render_titlebar(struct sway_output *output, struct wlr_box texture_box; wlr_texture_get_size(marks_texture, &texture_box.width, &texture_box.height); - texture_box.x = (x - output->swayc->x + width - TITLEBAR_H_PADDING) + texture_box.x = (x - output_x + width - TITLEBAR_H_PADDING) * output_scale - texture_box.width; - texture_box.y = (y - output->swayc->y + TITLEBAR_V_PADDING) - * output_scale; + texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; float matrix[9]; wlr_matrix_project_box(matrix, &texture_box, @@ -551,10 +547,8 @@ static void render_titlebar(struct sway_output *output, struct wlr_box texture_box; wlr_texture_get_size(title_texture, &texture_box.width, &texture_box.height); - texture_box.x = (x - output->swayc->x + TITLEBAR_H_PADDING) - * output_scale; - texture_box.y = (y - output->swayc->y + TITLEBAR_V_PADDING) - * output_scale; + texture_box.x = (x - output_x + TITLEBAR_H_PADDING) * output_scale; + texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; float matrix[9]; wlr_matrix_project_box(matrix, &texture_box, @@ -614,16 +608,15 @@ static void render_titlebar(struct sway_output *output, // Left pixel in line with bottom bar box.x = x; box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; - box.width = con->current.border_thickness * con->current.border_left; + box.width = state->border_thickness * state->border_left; box.height = TITLEBAR_BORDER_THICKNESS; scale_box(&box, output_scale); render_rect(output->wlr_output, output_damage, &box, color); // Right pixel in line with bottom bar - box.x = x + width - - con->current.border_thickness * con->current.border_right; + box.x = x + width - state->border_thickness * state->border_right; box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; - box.width = con->current.border_thickness * con->current.border_right; + box.width = state->border_thickness * state->border_right; box.height = TITLEBAR_BORDER_THICKNESS; scale_box(&box, output_scale); render_rect(output->wlr_output, output_damage, &box, color); @@ -636,7 +629,8 @@ static void render_titlebar(struct sway_output *output, static void render_top_border(struct sway_output *output, pixman_region32_t *output_damage, struct sway_container *con, struct border_colors *colors) { - if (!con->current.border_top) { + struct sway_container_state *state = &con->current; + if (!state->border_top) { return; } struct wlr_box box; @@ -646,10 +640,10 @@ static void render_top_border(struct sway_output *output, // Child border - top edge memcpy(&color, colors->child_border, sizeof(float) * 4); premultiply_alpha(color, con->alpha); - box.x = con->current.swayc_x; - box.y = con->current.swayc_y; - box.width = con->current.swayc_width; - box.height = con->current.border_thickness; + box.x = state->swayc_x; + box.y = state->swayc_y; + box.width = state->swayc_width; + box.height = state->border_thickness; scale_box(&box, output_scale); render_rect(output->wlr_output, output_damage, &box, color); } @@ -669,31 +663,34 @@ static void render_container_simple(struct sway_output *output, struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = seat_get_focus(seat); - for (int i = 0; i < con->children->length; ++i) { - struct sway_container *child = con->children->items[i]; + for (int i = 0; i < con->current.children->length; ++i) { + struct sway_container *child = con->current.children->items[i]; if (child->type == C_VIEW) { + struct sway_view *view = child->sway_view; struct border_colors *colors; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; + struct sway_container_state *state = &child->current; + if (focus == child || parent_focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; - marks_texture = child->sway_view->marks_focused; + marks_texture = view->marks_focused; } else if (seat_get_focus_inactive(seat, con) == child) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; - marks_texture = child->sway_view->marks_focused_inactive; + marks_texture = view->marks_focused_inactive; } else { colors = &config->border_colors.unfocused; title_texture = child->title_unfocused; - marks_texture = child->sway_view->marks_unfocused; + marks_texture = view->marks_unfocused; } - if (child->current.border == B_NORMAL) { - render_titlebar(output, damage, child, child->current.swayc_x, - child->current.swayc_y, child->current.swayc_width, - colors, title_texture, marks_texture); + if (state->border == B_NORMAL) { + render_titlebar(output, damage, child, state->swayc_x, + state->swayc_y, state->swayc_width, colors, + title_texture, marks_texture); } else { render_top_border(output, damage, child, colors); } @@ -711,22 +708,23 @@ static void render_container_simple(struct sway_output *output, static void render_container_tabbed(struct sway_output *output, pixman_region32_t *damage, struct sway_container *con, bool parent_focused) { - if (!con->children->length) { + if (!con->current.children->length) { return; } struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = seat_get_focus(seat); struct sway_container *current = seat_get_active_child(seat, con); struct border_colors *current_colors = NULL; + struct sway_container_state *pstate = &con->current; // Render tabs - for (int i = 0; i < con->children->length; ++i) { - struct sway_container *child = con->children->items[i]; + for (int i = 0; i < con->current.children->length; ++i) { + struct sway_container *child = con->current.children->items[i]; + struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; + struct sway_container_state *cstate = &child->current; struct border_colors *colors; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; - struct sway_view *view = - child->type == C_VIEW ? child->sway_view : NULL; if (focus == child || parent_focused) { colors = &config->border_colors.focused; @@ -735,22 +733,22 @@ static void render_container_tabbed(struct sway_output *output, } else if (child == current) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; - marks_texture = view ? view->marks_focused : NULL; + marks_texture = view ? view->marks_focused_inactive : NULL; } else { colors = &config->border_colors.unfocused; title_texture = child->title_unfocused; marks_texture = view ? view->marks_unfocused : NULL; } - int tab_width = con->current.swayc_width / con->children->length; - int x = con->current.swayc_x + tab_width * i; + int tab_width = pstate->swayc_width / pstate->children->length; + int x = pstate->swayc_x + tab_width * i; // Make last tab use the remaining width of the parent - if (i == con->children->length - 1) { - tab_width = con->current.swayc_width - tab_width * i; + if (i == pstate->children->length - 1) { + tab_width = pstate->swayc_width - tab_width * i; } - render_titlebar(output, damage, child, x, child->current.swayc_y, - tab_width, colors, title_texture, marks_texture); + render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width, + colors, title_texture, marks_texture); if (child == current) { current_colors = colors; @@ -772,22 +770,23 @@ static void render_container_tabbed(struct sway_output *output, static void render_container_stacked(struct sway_output *output, pixman_region32_t *damage, struct sway_container *con, bool parent_focused) { - if (!con->children->length) { + if (!con->current.children->length) { return; } struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = seat_get_focus(seat); struct sway_container *current = seat_get_active_child(seat, con); struct border_colors *current_colors = NULL; + struct sway_container_state *pstate = &con->current; // Render titles - for (int i = 0; i < con->children->length; ++i) { - struct sway_container *child = con->children->items[i]; + for (int i = 0; i < con->current.children->length; ++i) { + struct sway_container *child = con->current.children->items[i]; + struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; + struct sway_container_state *cstate = &child->current; struct border_colors *colors; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; - struct sway_view *view = - child->type == C_VIEW ? child->sway_view : NULL; if (focus == child || parent_focused) { colors = &config->border_colors.focused; @@ -803,10 +802,9 @@ static void render_container_stacked(struct sway_output *output, marks_texture = view ? view->marks_unfocused : NULL; } - int y = con->current.swayc_y + container_titlebar_height() * i; - render_titlebar(output, damage, child, child->current.swayc_x, y, - child->current.swayc_width, colors, - title_texture, marks_texture); + int y = pstate->swayc_y + container_titlebar_height() * i; + render_titlebar(output, damage, child, cstate->swayc_x, y, + cstate->swayc_width, colors, title_texture, marks_texture); if (child == current) { current_colors = colors; @@ -877,17 +875,18 @@ static void render_floating_container(struct sway_output *soutput, static void render_floating(struct sway_output *soutput, pixman_region32_t *damage) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; - for (int j = 0; j < output->children->length; ++j) { - struct sway_container *workspace = output->children->items[j]; - struct sway_workspace *ws = workspace->sway_workspace; - if (!workspace_is_visible(workspace)) { + for (int i = 0; i < root_container.current.children->length; ++i) { + struct sway_container *output = + root_container.current.children->items[i]; + for (int j = 0; j < output->current.children->length; ++j) { + struct sway_container *ws = output->current.children->items[j]; + if (!workspace_is_visible(ws)) { continue; } - for (int k = 0; k < ws->floating->children->length; ++k) { - struct sway_container *floater = - ws->floating->children->items[k]; + list_t *floating = + ws->current.ws_floating->current.children; + for (int k = 0; k < floating->length; ++k) { + struct sway_container *floater = floating->items[k]; render_floating_container(soutput, damage, floater); } } @@ -901,7 +900,7 @@ static struct sway_container *output_get_active_workspace( seat_get_focus_inactive(seat, output->swayc); if (!focus) { // We've never been to this output before - focus = output->swayc->children->items[0]; + focus = output->swayc->current.children->items[0]; } struct sway_container *workspace = focus; if (workspace->type != C_WORKSPACE) { @@ -942,8 +941,9 @@ static void render_output(struct sway_output *output, struct timespec *when, } struct sway_container *workspace = output_get_active_workspace(output); + struct sway_view *fullscreen_view = workspace->current.ws_fullscreen; - if (workspace->sway_workspace->fullscreen) { + if (fullscreen_view) { float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; int nrects; @@ -954,10 +954,9 @@ static void render_output(struct sway_output *output, struct timespec *when, } // TODO: handle views smaller than the output - render_view_surfaces( - workspace->sway_workspace->fullscreen, output, damage, 1.0f); + render_view_surfaces(fullscreen_view, output, damage, 1.0f); - if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) { + if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) { render_unmanaged(output, damage, &root_container.sway_root->xwayland_unmanaged); } @@ -1073,11 +1072,11 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { }; struct sway_container *workspace = output_get_active_workspace(output); - if (workspace->sway_workspace->fullscreen) { + if (workspace->current.ws_fullscreen) { send_frame_done_container_iterator( - workspace->sway_workspace->fullscreen->swayc, &data); + workspace->current.ws_fullscreen->swayc, &data); - if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) { + if (workspace->current.ws_fullscreen->type == SWAY_VIEW_XWAYLAND) { send_frame_done_unmanaged(&data, &root_container.sway_root->xwayland_unmanaged); } diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 77377a18..6e09537a 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -9,6 +9,7 @@ #include "sway/output.h" #include "sway/tree/container.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" #include "list.h" #include "log.h" @@ -18,6 +19,13 @@ */ #define TIMEOUT_MS 200 +/** + * If enabled, sway will always wait for the transaction timeout before + * applying it, rather than applying it when the views are ready. This allows us + * to observe the rendered state while a transaction is in progress. + */ +#define TRANSACTION_DEBUG false + struct sway_transaction { struct wl_event_source *timer; list_t *instructions; // struct sway_transaction_instruction * @@ -29,7 +37,9 @@ struct sway_transaction_instruction { struct sway_transaction *transaction; struct sway_container *container; struct sway_container_state state; + struct wlr_buffer *saved_buffer; uint32_t serial; + bool ready; }; struct sway_transaction *transaction_create() { @@ -40,44 +50,55 @@ struct sway_transaction *transaction_create() { return transaction; } +static void remove_saved_view_buffer( + struct sway_transaction_instruction *instruction) { + if (instruction->saved_buffer) { + wlr_buffer_unref(instruction->saved_buffer); + instruction->saved_buffer = NULL; + } +} + +static void save_view_buffer(struct sway_view *view, + struct sway_transaction_instruction *instruction) { + if (!sway_assert(instruction->saved_buffer == NULL, + "Didn't expect instruction to have a saved buffer already")) { + remove_saved_view_buffer(instruction); + } + if (view->surface && wlr_surface_has_buffer(view->surface)) { + wlr_buffer_ref(view->surface->buffer); + instruction->saved_buffer = view->surface->buffer; + } +} + static void transaction_destroy(struct sway_transaction *transaction) { - int i; // Free instructions - for (i = 0; i < transaction->instructions->length; ++i) { + for (int i = 0; i < transaction->instructions->length; ++i) { struct sway_transaction_instruction *instruction = transaction->instructions->items[i]; - if (instruction->container->type == C_VIEW) { - struct sway_view *view = instruction->container->sway_view; - for (int j = 0; j < view->instructions->length; ++j) { - if (view->instructions->items[j] == instruction) { - list_del(view->instructions, j); - break; - } + struct sway_container *con = instruction->container; + for (int j = 0; j < con->instructions->length; ++j) { + if (con->instructions->items[j] == instruction) { + list_del(con->instructions, j); + break; } } + if (con->destroying && !con->instructions->length) { + container_free(con); + } + remove_saved_view_buffer(instruction); free(instruction); } list_free(transaction->instructions); // Free damage - for (i = 0; i < transaction->damage->length; ++i) { - struct wlr_box *box = transaction->damage->items[i]; - free(box); - } + list_foreach(transaction->damage, free); list_free(transaction->damage); free(transaction); } -void transaction_add_container(struct sway_transaction *transaction, - struct sway_container *container) { - struct sway_transaction_instruction *instruction = - calloc(1, sizeof(struct sway_transaction_instruction)); - instruction->transaction = transaction; - instruction->container = container; - - // Copy the container's main (pending) properties into the instruction state - struct sway_container_state *state = &instruction->state; +static void copy_pending_state(struct sway_container *container, + struct sway_container_state *state) { state->layout = container->layout; state->swayc_x = container->x; state->swayc_y = container->y; @@ -87,6 +108,7 @@ void transaction_add_container(struct sway_transaction *transaction, state->current_gaps = container->current_gaps; state->gaps_inner = container->gaps_inner; state->gaps_outer = container->gaps_outer; + state->parent = container->parent; if (container->type == C_VIEW) { struct sway_view *view = container->sway_view; @@ -101,8 +123,44 @@ void transaction_add_container(struct sway_transaction *transaction, state->border_left = view->border_left; state->border_right = view->border_right; state->border_bottom = view->border_bottom; + } else if (container->type == C_WORKSPACE) { + state->ws_fullscreen = container->sway_workspace->fullscreen; + state->ws_floating = container->sway_workspace->floating; + state->children = create_list(); + list_cat(state->children, container->children); + } else { + state->children = create_list(); + list_cat(state->children, container->children); + } +} + +static bool transaction_has_container(struct sway_transaction *transaction, + struct sway_container *container) { + for (int i = 0; i < transaction->instructions->length; ++i) { + struct sway_transaction_instruction *instruction = + transaction->instructions->items[i]; + if (instruction->container == container) { + return true; + } + } + return false; +} + +void transaction_add_container(struct sway_transaction *transaction, + struct sway_container *container) { + if (transaction_has_container(transaction, container)) { + return; } + struct sway_transaction_instruction *instruction = + calloc(1, sizeof(struct sway_transaction_instruction)); + instruction->transaction = transaction; + instruction->container = container; + + copy_pending_state(container, &instruction->state); + if (container->type == C_VIEW) { + save_view_buffer(container->sway_view, instruction); + } list_add(transaction->instructions, instruction); } @@ -113,47 +171,29 @@ void transaction_add_damage(struct sway_transaction *transaction, list_add(transaction->damage, box); } -static void save_view_buffer(struct sway_view *view) { - if (view->saved_buffer) { - wlr_buffer_unref(view->saved_buffer); - } - wlr_buffer_ref(view->surface->buffer); - view->saved_buffer = view->surface->buffer; - view->saved_surface_width = view->surface->current->width; - view->saved_surface_height = view->surface->current->height; -} - -static void remove_saved_view_buffer(struct sway_view *view) { - if (view->saved_buffer) { - wlr_buffer_unref(view->saved_buffer); - view->saved_buffer = NULL; - view->saved_surface_width = 0; - view->saved_surface_height = 0; - } -} - /** * Apply a transaction to the "current" state of the tree. - * - * This is mostly copying stuff from the pending state into the main swayc - * properties, but also includes reparenting and deleting containers. */ static void transaction_apply(struct sway_transaction *transaction) { int i; + // Apply the instruction state to the container's current state for (i = 0; i < transaction->instructions->length; ++i) { struct sway_transaction_instruction *instruction = transaction->instructions->items[i]; struct sway_container *container = instruction->container; - memcpy(&instruction->container->current, &instruction->state, - sizeof(struct sway_container_state)); + // There are separate children lists for each instruction state, the + // container's current state and the container's pending state + // (ie. con->children). The list itself needs to be freed here. + // Any child containers which are being deleted will be cleaned up in + // transaction_destroy(). + list_free(container->current.children); - if (container->type == C_VIEW) { - remove_saved_view_buffer(container->sway_view); - } + memcpy(&container->current, &instruction->state, + sizeof(struct sway_container_state)); } - // Damage + // Apply damage for (i = 0; i < transaction->damage->length; ++i) { struct wlr_box *box = transaction->damage->items[i]; for (int j = 0; j < root_container.children->length; ++j) { @@ -161,8 +201,6 @@ static void transaction_apply(struct sway_transaction *transaction) { output_damage_box(output->sway_output, box); } } - - update_debug_tree(); } static int handle_timeout(void *data) { @@ -182,7 +220,7 @@ void transaction_commit(struct sway_transaction *transaction) { struct sway_transaction_instruction *instruction = transaction->instructions->items[i]; struct sway_container *con = instruction->container; - if (con->type == C_VIEW && + if (con->type == C_VIEW && !con->destroying && (con->current.view_width != instruction->state.view_width || con->current.view_height != instruction->state.view_height)) { instruction->serial = view_configure(con->sway_view, @@ -191,14 +229,12 @@ void transaction_commit(struct sway_transaction *transaction) { instruction->state.view_width, instruction->state.view_height); if (instruction->serial) { - save_view_buffer(con->sway_view); - list_add(con->sway_view->instructions, instruction); ++transaction->num_waiting; } } + list_add(con->instructions, instruction); } if (!transaction->num_waiting) { - // This can happen if the transaction only contains xwayland views wlr_log(L_DEBUG, "Transaction %p has nothing to wait for, applying", transaction); transaction_apply(transaction); @@ -210,31 +246,47 @@ void transaction_commit(struct sway_transaction *transaction) { transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, handle_timeout, transaction); wl_event_source_timer_update(transaction->timer, TIMEOUT_MS); + + // The debug tree shows the pending/live tree. Here is a good place to + // update it, because we make a transaction every time we change the pending + // tree. + update_debug_tree(); } void transaction_notify_view_ready(struct sway_view *view, uint32_t serial) { // Find the instruction struct sway_transaction_instruction *instruction = NULL; - for (int i = 0; i < view->instructions->length; ++i) { + for (int i = 0; i < view->swayc->instructions->length; ++i) { struct sway_transaction_instruction *tmp_instruction = - view->instructions->items[i]; - if (tmp_instruction->serial == serial) { + view->swayc->instructions->items[i]; + if (tmp_instruction->serial == serial && !tmp_instruction->ready) { instruction = tmp_instruction; - list_del(view->instructions, i); break; } } if (!instruction) { - // This can happen if the view acknowledges the configure after the - // transaction has timed out and applied. return; } + instruction->ready = true; + // If all views are ready, apply the transaction struct sway_transaction *transaction = instruction->transaction; if (--transaction->num_waiting == 0) { +#if !TRANSACTION_DEBUG wlr_log(L_DEBUG, "Transaction %p is ready, applying", transaction); wl_event_source_timer_update(transaction->timer, 0); transaction_apply(transaction); transaction_destroy(transaction); +#endif } } + +struct wlr_texture *transaction_get_texture(struct sway_view *view) { + if (!view->swayc || !view->swayc->instructions->length) { + return view->surface->buffer->texture; + } + struct sway_transaction_instruction *instruction = + view->swayc->instructions->items[0]; + return instruction->saved_buffer ? + instruction->saved_buffer->texture : NULL; +} diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index d22c967c..ab35b98f 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -143,16 +143,12 @@ static void _close(struct sway_view *view) { } } -static void destroy(struct sway_view *view) { +static void _free(struct sway_view *view) { struct sway_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); if (xdg_shell_view == NULL) { return; } - wl_list_remove(&xdg_shell_view->destroy.link); - wl_list_remove(&xdg_shell_view->map.link); - wl_list_remove(&xdg_shell_view->unmap.link); - wl_list_remove(&xdg_shell_view->request_fullscreen.link); free(xdg_shell_view); } @@ -164,7 +160,7 @@ static const struct sway_view_impl view_impl = { .wants_floating = wants_floating, .for_each_surface = for_each_surface, .close = _close, - .destroy = destroy, + .free = _free, }; static void handle_commit(struct wl_listener *listener, void *data) { @@ -173,7 +169,11 @@ static void handle_commit(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_view->view; struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface; - if (view->instructions->length) { + if (!view->swayc) { + return; + } + + if (view->swayc->instructions->length) { transaction_notify_view_ready(view, xdg_surface->configure_serial); } @@ -191,11 +191,18 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, unmap); + struct sway_view *view = &xdg_shell_view->view; + + if (!sway_assert(view->surface, "Cannot unmap unmapped view")) { + return; + } - view_unmap(&xdg_shell_view->view); + struct sway_container *parent = view_unmap(view); + arrange_and_commit(parent); wl_list_remove(&xdg_shell_view->commit.link); wl_list_remove(&xdg_shell_view->new_popup.link); + view->surface = NULL; } static void handle_map(struct wl_listener *listener, void *data) { @@ -230,7 +237,17 @@ static void handle_map(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, destroy); - view_destroy(&xdg_shell_view->view); + struct sway_view *view = &xdg_shell_view->view; + if (!sway_assert(view->swayc == NULL || view->swayc->destroying, + "Tried to destroy a mapped view")) { + return; + } + wl_list_remove(&xdg_shell_view->destroy.link); + wl_list_remove(&xdg_shell_view->map.link); + wl_list_remove(&xdg_shell_view->unmap.link); + wl_list_remove(&xdg_shell_view->request_fullscreen.link); + view->wlr_xdg_surface = NULL; + view_destroy(view); } static void handle_request_fullscreen(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 7ec9e6cb..76c1fa24 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -143,16 +143,12 @@ static void _close(struct sway_view *view) { } } -static void destroy(struct sway_view *view) { +static void _free(struct sway_view *view) { struct sway_xdg_shell_v6_view *xdg_shell_v6_view = xdg_shell_v6_view_from_view(view); if (xdg_shell_v6_view == NULL) { return; } - wl_list_remove(&xdg_shell_v6_view->destroy.link); - wl_list_remove(&xdg_shell_v6_view->map.link); - wl_list_remove(&xdg_shell_v6_view->unmap.link); - wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link); free(xdg_shell_v6_view); } @@ -164,7 +160,7 @@ static const struct sway_view_impl view_impl = { .wants_floating = wants_floating, .for_each_surface = for_each_surface, .close = _close, - .destroy = destroy, + .free = _free, }; static void handle_commit(struct wl_listener *listener, void *data) { @@ -173,7 +169,10 @@ static void handle_commit(struct wl_listener *listener, void *data) { struct sway_view *view = &xdg_shell_v6_view->view; struct wlr_xdg_surface_v6 *xdg_surface_v6 = view->wlr_xdg_surface_v6; - if (view->instructions->length) { + if (!view->swayc) { + return; + } + if (view->swayc->instructions->length) { transaction_notify_view_ready(view, xdg_surface_v6->configure_serial); } @@ -191,11 +190,18 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_xdg_shell_v6_view *xdg_shell_v6_view = wl_container_of(listener, xdg_shell_v6_view, unmap); + struct sway_view *view = &xdg_shell_v6_view->view; - view_unmap(&xdg_shell_v6_view->view); + if (!sway_assert(view->surface, "Cannot unmap unmapped view")) { + return; + } + + struct sway_container *parent = view_unmap(view); + arrange_and_commit(parent); wl_list_remove(&xdg_shell_v6_view->commit.link); wl_list_remove(&xdg_shell_v6_view->new_popup.link); + view->surface = NULL; } static void handle_map(struct wl_listener *listener, void *data) { @@ -230,7 +236,13 @@ static void handle_map(struct wl_listener *listener, void *data) { static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_xdg_shell_v6_view *xdg_shell_v6_view = wl_container_of(listener, xdg_shell_v6_view, destroy); - view_destroy(&xdg_shell_v6_view->view); + struct sway_view *view = &xdg_shell_v6_view->view; + wl_list_remove(&xdg_shell_v6_view->destroy.link); + wl_list_remove(&xdg_shell_v6_view->map.link); + wl_list_remove(&xdg_shell_v6_view->unmap.link); + wl_list_remove(&xdg_shell_v6_view->request_fullscreen.link); + view->wlr_xdg_surface_v6 = NULL; + view_destroy(view); } static void handle_request_fullscreen(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 55917bf6..a1837420 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -218,19 +218,11 @@ static void _close(struct sway_view *view) { wlr_xwayland_surface_close(view->wlr_xwayland_surface); } -static void destroy(struct sway_view *view) { +static void _free(struct sway_view *view) { struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); if (xwayland_view == NULL) { return; } - wl_list_remove(&xwayland_view->destroy.link); - wl_list_remove(&xwayland_view->request_configure.link); - wl_list_remove(&xwayland_view->request_fullscreen.link); - wl_list_remove(&xwayland_view->set_title.link); - wl_list_remove(&xwayland_view->set_class.link); - wl_list_remove(&xwayland_view->set_window_type.link); - wl_list_remove(&xwayland_view->map.link); - wl_list_remove(&xwayland_view->unmap.link); free(xwayland_view); } @@ -242,7 +234,7 @@ static const struct sway_view_impl view_impl = { .set_fullscreen = set_fullscreen, .wants_floating = wants_floating, .close = _close, - .destroy = destroy, + .free = _free, }; static void handle_commit(struct wl_listener *listener, void *data) { @@ -254,7 +246,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { // Don't allow xwayland views to do resize or reposition themselves if // they're involved in a transaction. Once the transaction has finished // they'll apply the next time a commit happens. - if (view->instructions->length) { + if (view->swayc && view->swayc->instructions->length) { if (view->swayc && container_is_floating(view->swayc)) { view_update_size(view, xsurface->width, xsurface->height); } else { @@ -268,8 +260,17 @@ static void handle_commit(struct wl_listener *listener, void *data) { static void handle_unmap(struct wl_listener *listener, void *data) { struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, unmap); + struct sway_view *view = &xwayland_view->view; + + if (!sway_assert(view->surface, "Cannot unmap unmapped view")) { + return; + } + + struct sway_container *parent = view_unmap(view); + arrange_and_commit(parent); + wl_list_remove(&xwayland_view->commit.link); - view_unmap(&xwayland_view->view); + view->surface = NULL; } static void handle_map(struct wl_listener *listener, void *data) { @@ -293,12 +294,30 @@ static void handle_map(struct wl_listener *listener, void *data) { if (xsurface->fullscreen) { view_set_fullscreen(view, true); } - arrange_and_commit(view->swayc); + arrange_and_commit(view->swayc->parent); } static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, destroy); + struct sway_view *view = &xwayland_view->view; + + if (view->surface) { + struct sway_container *parent = view_unmap(view); + arrange_and_commit(parent); + + wl_list_remove(&xwayland_view->commit.link); + view->surface = NULL; + } + + wl_list_remove(&xwayland_view->destroy.link); + wl_list_remove(&xwayland_view->request_configure.link); + wl_list_remove(&xwayland_view->request_fullscreen.link); + wl_list_remove(&xwayland_view->set_title.link); + wl_list_remove(&xwayland_view->set_class.link); + wl_list_remove(&xwayland_view->set_window_type.link); + wl_list_remove(&xwayland_view->map.link); + wl_list_remove(&xwayland_view->unmap.link); view_destroy(&xwayland_view->view); } diff --git a/sway/main.c b/sway/main.c index a7e808ad..a83660d5 100644 --- a/sway/main.c +++ b/sway/main.c @@ -34,6 +34,7 @@ struct sway_server server; void sway_terminate(int exit_code) { terminate_request = true; exit_value = exit_code; + server.terminating = true; wl_display_terminate(server.wl_display); } diff --git a/sway/server.c b/sway/server.c index 824b1d8e..a13f2c3a 100644 --- a/sway/server.c +++ b/sway/server.c @@ -19,6 +19,7 @@ #include // TODO WLR: make Xwayland optional #include +#include "list.h" #include "sway/config.h" #include "sway/input/input-manager.h" #include "sway/server.h" @@ -105,6 +106,8 @@ bool server_init(struct sway_server *server) { return false; } + server->destroying_containers = create_list(); + input_manager = input_manager_create(server); return true; } @@ -112,6 +115,7 @@ bool server_init(struct sway_server *server) { void server_fini(struct sway_server *server) { // TODO: free sway-specific resources wl_display_destroy(server->wl_display); + list_free(server->destroying_containers); } void server_run(struct sway_server *server) { diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index ac99c5df..cb3f8ba2 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -144,6 +144,19 @@ static void apply_tabbed_or_stacked_layout(struct sway_container *parent) { } } +/** + * If a container has been deleted from the pending tree state, we must add it + * to the transaction so it can be freed afterwards. To do this, we iterate the + * server's destroying_containers list and add all of them. We may add more than + * what we need to, but this is easy and has no negative consequences. + */ +static void add_deleted_containers(struct sway_transaction *transaction) { + for (int i = 0; i < server.destroying_containers->length; ++i) { + struct sway_container *child = server.destroying_containers->items[i]; + transaction_add_container(transaction, child); + } +} + static void arrange_children_of(struct sway_container *parent, struct sway_transaction *transaction); @@ -158,6 +171,7 @@ static void arrange_floating(struct sway_container *floating, } transaction_add_container(transaction, floater); } + transaction_add_container(transaction, floating); } static void arrange_children_of(struct sway_container *parent, @@ -290,7 +304,16 @@ void arrange_windows(struct sway_container *container, case C_TYPES: break; } - transaction_add_damage(transaction, container_get_box(container)); + // Add damage for whatever container arrange_windows() was called with, + // unless it was called with the special floating container, in which case + // we'll damage the entire output. + if (container->type == C_CONTAINER && container->layout == L_FLOATING) { + struct sway_container *output = container_parent(container, C_OUTPUT); + transaction_add_damage(transaction, container_get_box(output)); + } else { + transaction_add_damage(transaction, container_get_box(container)); + } + add_deleted_containers(transaction); } void arrange_and_commit(struct sway_container *container) { diff --git a/sway/tree/container.c b/sway/tree/container.c index b071f394..484d26a5 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -16,7 +16,6 @@ #include "sway/ipc-server.h" #include "sway/output.h" #include "sway/server.h" -#include "sway/tree/arrange.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" @@ -113,10 +112,11 @@ struct sway_container *container_create(enum sway_container_type type) { c->layout = L_NONE; c->type = type; c->alpha = 1.0f; + c->instructions = create_list(); if (type != C_VIEW) { c->children = create_list(); - //c->pending.children = create_list(); + c->current.children = create_list(); } wl_signal_init(&c->events.destroy); @@ -133,43 +133,68 @@ struct sway_container *container_create(enum sway_container_type type) { return c; } -static void _container_destroy(struct sway_container *cont) { - if (cont == NULL) { - return; - } - - wl_signal_emit(&cont->events.destroy, cont); +static void container_workspace_free(struct sway_workspace *ws) { + list_foreach(ws->output_priority, free); + list_free(ws->output_priority); + ws->floating->destroying = true; + container_free(ws->floating); + free(ws); +} - struct sway_container *parent = cont->parent; - if (cont->children != NULL && cont->children->length) { - // remove children until there are no more, container_destroy calls - // container_remove_child, which removes child from this container - while (cont->children != NULL && cont->children->length > 0) { - struct sway_container *child = cont->children->items[0]; - ipc_event_window(child, "close"); - container_remove_child(child); - _container_destroy(child); - } - } - if (cont->marks) { - list_foreach(cont->marks, free); - list_free(cont->marks); - } - if (parent) { - parent = container_remove_child(cont); +void container_free(struct sway_container *cont) { + if (!sway_assert(cont->destroying, + "Tried to free container which wasn't marked as destroying")) { + return; } - if (cont->name) { - free(cont->name); + if (!sway_assert(cont->instructions->length == 0, + "Tried to free container with pending instructions")) { + return; } - + free(cont->name); wlr_texture_destroy(cont->title_focused); wlr_texture_destroy(cont->title_focused_inactive); wlr_texture_destroy(cont->title_unfocused); wlr_texture_destroy(cont->title_urgent); + for (int i = 0; i < server.destroying_containers->length; ++i) { + if (server.destroying_containers->items[i] == cont) { + list_del(server.destroying_containers, i); + break; + } + } + + list_free(cont->instructions); list_free(cont->children); - //list_free(cont->pending.children); - cont->children = NULL; + list_free(cont->current.children); + + switch (cont->type) { + case C_ROOT: + break; + case C_OUTPUT: + cont->sway_output->swayc = NULL; + break; + case C_WORKSPACE: + container_workspace_free(cont->sway_workspace); + break; + case C_CONTAINER: + break; + case C_VIEW: + { + struct sway_view *view = cont->sway_view; + view->swayc = NULL; + free(view->title_format); + view->title_format = NULL; + + if (view->destroying) { + view_free(view); + } + } + break; + case C_TYPES: + sway_assert(false, "Didn't expect to see C_TYPES here"); + break; + } + free(cont); } @@ -186,7 +211,6 @@ static struct sway_container *container_workspace_destroy( } wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); - ipc_event_window(workspace, "close"); struct sway_container *parent = workspace->parent; if (!workspace_is_empty(workspace) && output) { @@ -209,25 +233,6 @@ static struct sway_container *container_workspace_destroy( container_move_to(floating->children->items[i], new_workspace->sway_workspace->floating); } - arrange_and_commit(new_workspace); - } - - struct sway_workspace *sway_workspace = workspace->sway_workspace; - - // This emits the destroy event and also destroys the swayc. - _container_destroy(workspace); - - // Clean up the floating container - sway_workspace->floating->parent = NULL; - _container_destroy(sway_workspace->floating); - - list_foreach(sway_workspace->output_priority, free); - list_free(sway_workspace->output_priority); - - free(sway_workspace); - - if (output) { - output_damage_whole(output->sway_output); } return parent; @@ -266,14 +271,13 @@ static struct sway_container *container_output_destroy( container_add_child(new_output, workspace); ipc_event_workspace(workspace, NULL, "move"); } else { - container_workspace_destroy(workspace); + container_destroy(workspace); } container_sort_workspaces(new_output); } } } - arrange_and_commit(&root_container); wl_list_remove(&output->sway_output->mode.link); wl_list_remove(&output->sway_output->transform.link); @@ -285,12 +289,8 @@ static struct sway_container *container_output_destroy( output->sway_output->swayc = NULL; wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); - _container_destroy(output); - return &root_container; -} -static void container_root_finish(struct sway_container *con) { - wlr_log(L_ERROR, "TODO: destroy the root container"); + return &root_container; } bool container_reap_empty(struct sway_container *con) { @@ -306,13 +306,13 @@ bool container_reap_empty(struct sway_container *con) { case C_WORKSPACE: if (!workspace_is_visible(con) && workspace_is_empty(con)) { wlr_log(L_DEBUG, "Destroying workspace via reaper"); - container_workspace_destroy(con); + container_destroy(con); return true; } break; case C_CONTAINER: if (con->children->length == 0) { - _container_destroy(con); + container_destroy(con); return true; } case C_VIEW: @@ -349,46 +349,48 @@ struct sway_container *container_flatten(struct sway_container *container) { return container; } +/** + * container_destroy() is the first step in destroying a container. We'll emit + * events, detach it from the tree and mark it as destroying. The container will + * remain in memory until it's no longer used by a transaction, then it will be + * freed via container_free(). + */ struct sway_container *container_destroy(struct sway_container *con) { if (con == NULL) { return NULL; } + if (con->destroying) { + return NULL; + } - struct sway_container *parent = con->parent; + // The below functions move their children to somewhere else. + if (con->type == C_OUTPUT) { + container_output_destroy(con); + } else if (con->type == C_WORKSPACE) { + // Workspaces will refuse to be destroyed if they're the last workspace + // on their output. + if (!container_workspace_destroy(con)) { + return NULL; + } + } - switch (con->type) { - case C_ROOT: - container_root_finish(con); - break; - case C_OUTPUT: - // dont try to reap the root after this - container_output_destroy(con); - break; - case C_WORKSPACE: - // dont try to reap the output after this - container_workspace_destroy(con); - break; - case C_CONTAINER: - if (con->children->length) { - for (int i = 0; i < con->children->length; ++i) { - struct sway_container *child = con->children->items[0]; - ipc_event_window(child, "close"); - container_remove_child(child); - container_add_child(parent, child); - } - } - ipc_event_window(con, "close"); - _container_destroy(con); - break; - case C_VIEW: - _container_destroy(con); - break; - case C_TYPES: - wlr_log(L_ERROR, "container_destroy called on an invalid " - "container"); - break; + // At this point the container being destroyed shouldn't have any children + // unless sway is terminating. + if (!server.terminating) { + if (!sway_assert(!con->children || con->children->length == 0, + "Didn't expect to see children here")) { + return NULL; + } } + wl_signal_emit(&con->events.destroy, con); + ipc_event_window(con, "close"); + + struct sway_container *parent = container_remove_child(con); + + con->destroying = true; + list_add(server.destroying_containers, con); + return container_reap_empty_recursive(parent); } diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 3724361d..14631ad4 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -30,7 +30,9 @@ void layout_init(void) { root_container.type = C_ROOT; root_container.layout = L_NONE; root_container.name = strdup("root"); + root_container.instructions = create_list(); root_container.children = create_list(); + root_container.current.children = create_list(); wl_signal_init(&root_container.events.destroy); root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); diff --git a/sway/tree/output.c b/sway/tree/output.c index 8af319d5..e2927cdb 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -29,7 +29,6 @@ static void restore_workspaces(struct sway_container *output) { } container_sort_workspaces(output); - arrange_and_commit(&root_container); } struct sway_container *output_create( @@ -66,7 +65,6 @@ struct sway_container *output_create( struct sway_container *output = container_create(C_OUTPUT); output->sway_output = sway_output; - sway_output->swayc = output; output->name = strdup(name); if (output->name == NULL) { container_destroy(output); diff --git a/sway/tree/view.c b/sway/tree/view.c index 658a94e8..cb36f123 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -25,47 +25,60 @@ void view_init(struct sway_view *view, enum sway_view_type type, view->impl = impl; view->executed_criteria = create_list(); view->marks = create_list(); - view->instructions = create_list(); wl_signal_init(&view->events.unmap); } -void view_destroy(struct sway_view *view) { - if (view == NULL) { +void view_free(struct sway_view *view) { + if (!sway_assert(view->surface == NULL, "Tried to free mapped view")) { return; } - - if (view->surface != NULL) { - view_unmap(view); + if (!sway_assert(view->destroying, + "Tried to free view which wasn't marked as destroying")) { + return; } - - if (!sway_assert(view->instructions->length == 0, - "Tried to destroy view with pending instructions")) { + if (!sway_assert(view->swayc == NULL, + "Tried to free view which still has a swayc " + "(might have a pending transaction?)")) { return; } - list_free(view->executed_criteria); - for (int i = 0; i < view->marks->length; ++i) { - free(view->marks->items[i]); - } + list_foreach(view->marks, free); list_free(view->marks); - list_free(view->instructions); - wlr_texture_destroy(view->marks_focused); wlr_texture_destroy(view->marks_focused_inactive); wlr_texture_destroy(view->marks_unfocused); wlr_texture_destroy(view->marks_urgent); - container_destroy(view->swayc); - - if (view->impl->destroy) { - view->impl->destroy(view); + if (view->impl->free) { + view->impl->free(view); } else { free(view); } } +/** + * The view may or may not be involved in a transaction. For example, a view may + * unmap then attempt to destroy itself before we've applied the new layout. If + * an unmapping view is still involved in a transaction then it'll still have a + * swayc. + * + * If there's no transaction we can simply free the view. Otherwise the + * destroying flag will make the view get freed when the transaction is + * finished. + */ +void view_destroy(struct sway_view *view) { + if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) { + return; + } + view->destroying = true; + + if (!view->swayc) { + view_free(view); + } +} + const char *view_get_title(struct sway_view *view) { if (view->impl->get_string_prop) { return view->impl->get_string_prop(view, VIEW_PROP_TITLE); @@ -356,6 +369,9 @@ static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) { void view_for_each_surface(struct sway_view *view, wlr_surface_iterator_func_t iterator, void *user_data) { + if (!view->surface) { + return; + } if (view->impl->for_each_surface) { view->impl->for_each_surface(view, iterator, user_data); } else { @@ -523,11 +539,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { view_handle_container_reparent(&view->container_reparent, NULL); } -void view_unmap(struct sway_view *view) { - if (!sway_assert(view->surface != NULL, "cannot unmap unmapped view")) { - return; - } - +struct sway_container *view_unmap(struct sway_view *view) { wl_signal_emit(&view->events.unmap, view); if (view->is_fullscreen) { @@ -535,22 +547,10 @@ void view_unmap(struct sway_view *view) { ws->sway_workspace->fullscreen = NULL; } - container_damage_whole(view->swayc); - wl_list_remove(&view->surface_new_subsurface.link); wl_list_remove(&view->container_reparent.link); - struct sway_container *parent = container_destroy(view->swayc); - - view->swayc = NULL; - view->surface = NULL; - - if (view->title_format) { - free(view->title_format); - view->title_format = NULL; - } - - arrange_and_commit(parent); + return container_destroy(view->swayc); } void view_update_position(struct sway_view *view, double lx, double ly) { @@ -924,7 +924,7 @@ void view_update_marks_textures(struct sway_view *view) { } bool view_is_visible(struct sway_view *view) { - if (!view->swayc) { + if (!view->swayc || view->swayc->destroying) { return false; } struct sway_container *workspace = diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index ead752ad..5eb4be0f 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -430,6 +430,9 @@ bool workspace_switch(struct sway_container *workspace) { } bool workspace_is_visible(struct sway_container *ws) { + if (ws->destroying) { + return false; + } struct sway_container *output = container_parent(ws, C_OUTPUT); struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = seat_get_focus_inactive(seat, output); -- cgit v1.2.3 From 1549fb719ae75a498bf319db45281464e72c759e Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 24 Jun 2018 23:01:09 +1000 Subject: Implement atomic layout updates for xwayland views --- include/sway/desktop/transaction.h | 9 ++++++++ sway/desktop/transaction.c | 44 +++++++++++++++++++++++--------------- sway/desktop/xwayland.c | 14 ++++-------- 3 files changed, 40 insertions(+), 27 deletions(-) (limited to 'sway/desktop/xwayland.c') diff --git a/include/sway/desktop/transaction.h b/include/sway/desktop/transaction.h index d6adc609..b1da86f1 100644 --- a/include/sway/desktop/transaction.h +++ b/include/sway/desktop/transaction.h @@ -49,6 +49,15 @@ void transaction_commit(struct sway_transaction *transaction); */ void transaction_notify_view_ready(struct sway_view *view, uint32_t serial); +/** + * Notify the transaction system that a view is ready for the new layout, but + * identifying the instruction by width and height rather than by serial. + * + * This is used by xwayland views, as they don't have serials. + */ +void transaction_notify_view_ready_by_size(struct sway_view *view, + int width, int height); + /** * Get the texture that should be rendered for a view. * diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 04142bcc..08678b5b 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -267,9 +267,7 @@ void transaction_commit(struct sway_transaction *transaction) { instruction->state.view_y, instruction->state.view_width, instruction->state.view_height); - if (instruction->serial) { - ++transaction->num_waiting; - } + ++transaction->num_waiting; } list_add(con->instructions, instruction); } @@ -307,20 +305,8 @@ void transaction_commit(struct sway_transaction *transaction) { update_debug_tree(); } -void transaction_notify_view_ready(struct sway_view *view, uint32_t serial) { - // Find the instruction - struct sway_transaction_instruction *instruction = NULL; - for (int i = 0; i < view->swayc->instructions->length; ++i) { - struct sway_transaction_instruction *tmp_instruction = - view->swayc->instructions->items[i]; - if (tmp_instruction->serial == serial && !tmp_instruction->ready) { - instruction = tmp_instruction; - break; - } - } - if (!instruction) { - return; - } +static void set_instruction_ready( + struct sway_transaction_instruction *instruction) { instruction->ready = true; // If all views are ready, apply the transaction. @@ -335,6 +321,30 @@ void transaction_notify_view_ready(struct sway_view *view, uint32_t serial) { } } +void transaction_notify_view_ready(struct sway_view *view, uint32_t serial) { + for (int i = 0; i < view->swayc->instructions->length; ++i) { + struct sway_transaction_instruction *instruction = + view->swayc->instructions->items[i]; + if (instruction->serial == serial && !instruction->ready) { + set_instruction_ready(instruction); + return; + } + } +} + +void transaction_notify_view_ready_by_size(struct sway_view *view, + int width, int height) { + for (int i = 0; i < view->swayc->instructions->length; ++i) { + struct sway_transaction_instruction *instruction = + view->swayc->instructions->items[i]; + if (!instruction->ready && instruction->state.view_width == width && + instruction->state.view_height == height) { + set_instruction_ready(instruction); + return; + } + } +} + struct wlr_texture *transaction_get_texture(struct sway_view *view) { if (!view->swayc || !view->swayc->instructions->length) { return view->surface->buffer->texture; diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index a1837420..7e78ef32 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -7,6 +7,7 @@ #include #include "log.h" #include "sway/desktop.h" +#include "sway/desktop/transaction.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/output.h" @@ -243,16 +244,9 @@ static void handle_commit(struct wl_listener *listener, void *data) { struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - // Don't allow xwayland views to do resize or reposition themselves if - // they're involved in a transaction. Once the transaction has finished - // they'll apply the next time a commit happens. - if (view->swayc && view->swayc->instructions->length) { - if (view->swayc && container_is_floating(view->swayc)) { - view_update_size(view, xsurface->width, xsurface->height); - } else { - view_update_size(view, view->swayc->width, view->swayc->height); - } - view_update_position(view, view->x, view->y); + if (view->swayc->instructions->length) { + transaction_notify_view_ready_by_size(view, + xsurface->width, xsurface->height); } view_damage_from(view); } -- cgit v1.2.3 From 7a922c65aab27c5f4282cf15de52d240e5ac8052 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 26 Jun 2018 13:15:45 +1000 Subject: Damage output when a fullscreen view unmaps Also moved the arranging into view_unmap to avoid excessive code duplication. --- include/sway/tree/view.h | 5 +---- sway/desktop/xdg_shell.c | 3 +-- sway/desktop/xdg_shell_v6.c | 3 +-- sway/desktop/xwayland.c | 7 ++----- sway/tree/view.c | 14 ++++++++++---- 5 files changed, 15 insertions(+), 17 deletions(-) (limited to 'sway/desktop/xwayland.c') diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 5a615b43..0e6f5292 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -245,10 +245,7 @@ void view_destroy(struct sway_view *view); void view_map(struct sway_view *view, struct wlr_surface *wlr_surface); -/** - * Unmap the view and return the surviving parent (after reaping). - */ -struct sway_container *view_unmap(struct sway_view *view); +void view_unmap(struct sway_view *view); void view_update_position(struct sway_view *view, double lx, double ly); diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index ab35b98f..a06c3bd2 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -197,8 +197,7 @@ static void handle_unmap(struct wl_listener *listener, void *data) { return; } - struct sway_container *parent = view_unmap(view); - arrange_and_commit(parent); + view_unmap(view); wl_list_remove(&xdg_shell_view->commit.link); wl_list_remove(&xdg_shell_view->new_popup.link); diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 76c1fa24..424bca7b 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -196,8 +196,7 @@ static void handle_unmap(struct wl_listener *listener, void *data) { return; } - struct sway_container *parent = view_unmap(view); - arrange_and_commit(parent); + view_unmap(view); wl_list_remove(&xdg_shell_v6_view->commit.link); wl_list_remove(&xdg_shell_v6_view->new_popup.link); diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 7e78ef32..53fa42cc 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -260,8 +260,7 @@ static void handle_unmap(struct wl_listener *listener, void *data) { return; } - struct sway_container *parent = view_unmap(view); - arrange_and_commit(parent); + view_unmap(view); wl_list_remove(&xwayland_view->commit.link); view->surface = NULL; @@ -297,9 +296,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_view *view = &xwayland_view->view; if (view->surface) { - struct sway_container *parent = view_unmap(view); - arrange_and_commit(parent); - + view_unmap(view); wl_list_remove(&xwayland_view->commit.link); view->surface = NULL; } diff --git a/sway/tree/view.c b/sway/tree/view.c index 2ca0dbbb..5a78112a 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -539,7 +539,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { view_handle_container_reparent(&view->container_reparent, NULL); } -struct sway_container *view_unmap(struct sway_view *view) { +void view_unmap(struct sway_view *view) { wl_signal_emit(&view->events.unmap, view); wl_list_remove(&view->surface_new_subsurface.link); @@ -549,10 +549,16 @@ struct sway_container *view_unmap(struct sway_view *view) { struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); ws->sway_workspace->fullscreen = NULL; container_destroy(view->swayc); - return ws; - } - return container_destroy(view->swayc); + struct sway_container *output = ws->parent; + struct sway_transaction *transaction = transaction_create(); + arrange_windows(output, transaction); + transaction_add_damage(transaction, container_get_box(output)); + transaction_commit(transaction); + } else { + struct sway_container *parent = container_destroy(view->swayc); + arrange_and_commit(parent); + } } void view_update_position(struct sway_view *view, double lx, double ly) { -- cgit v1.2.3 From 50190bc7609d981c45d26cd0b7d6d0fbf66feb05 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 26 Jun 2018 13:18:33 +1000 Subject: Rename view's free callback to destroy --- include/sway/tree/view.h | 2 +- sway/desktop/xdg_shell.c | 4 ++-- sway/desktop/xdg_shell_v6.c | 4 ++-- sway/desktop/xwayland.c | 4 ++-- sway/tree/view.c | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) (limited to 'sway/desktop/xwayland.c') diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 0e6f5292..1bcb0582 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -37,7 +37,7 @@ struct sway_view_impl { void (*for_each_surface)(struct sway_view *view, wlr_surface_iterator_func_t iterator, void *user_data); void (*close)(struct sway_view *view); - void (*free)(struct sway_view *view); + void (*destroy)(struct sway_view *view); }; struct sway_view { diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index a06c3bd2..105e77ae 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -143,7 +143,7 @@ static void _close(struct sway_view *view) { } } -static void _free(struct sway_view *view) { +static void destroy(struct sway_view *view) { struct sway_xdg_shell_view *xdg_shell_view = xdg_shell_view_from_view(view); if (xdg_shell_view == NULL) { @@ -160,7 +160,7 @@ static const struct sway_view_impl view_impl = { .wants_floating = wants_floating, .for_each_surface = for_each_surface, .close = _close, - .free = _free, + .destroy = destroy, }; static void handle_commit(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 424bca7b..19b30604 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -143,7 +143,7 @@ static void _close(struct sway_view *view) { } } -static void _free(struct sway_view *view) { +static void destroy(struct sway_view *view) { struct sway_xdg_shell_v6_view *xdg_shell_v6_view = xdg_shell_v6_view_from_view(view); if (xdg_shell_v6_view == NULL) { @@ -160,7 +160,7 @@ static const struct sway_view_impl view_impl = { .wants_floating = wants_floating, .for_each_surface = for_each_surface, .close = _close, - .free = _free, + .destroy = destroy, }; static void handle_commit(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 53fa42cc..eea8420d 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -219,7 +219,7 @@ static void _close(struct sway_view *view) { wlr_xwayland_surface_close(view->wlr_xwayland_surface); } -static void _free(struct sway_view *view) { +static void destroy(struct sway_view *view) { struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); if (xwayland_view == NULL) { return; @@ -235,7 +235,7 @@ static const struct sway_view_impl view_impl = { .set_fullscreen = set_fullscreen, .wants_floating = wants_floating, .close = _close, - .free = _free, + .destroy = destroy, }; static void handle_commit(struct wl_listener *listener, void *data) { diff --git a/sway/tree/view.c b/sway/tree/view.c index 5a78112a..a616af03 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -51,8 +51,8 @@ void view_free(struct sway_view *view) { wlr_texture_destroy(view->marks_unfocused); wlr_texture_destroy(view->marks_urgent); - if (view->impl->free) { - view->impl->free(view); + if (view->impl->destroy) { + view->impl->destroy(view); } else { free(view); } -- cgit v1.2.3 From e8001e6fbe827f6ae6842cf9f221edb322bb570e Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 26 Jun 2018 14:24:15 +1000 Subject: Damage output when views toggle fullscreen Also add workspace to the transaction when a view maps in fullscreen mode. --- sway/desktop/xdg_shell.c | 10 ++++++++-- sway/desktop/xdg_shell_v6.c | 10 ++++++++-- sway/desktop/xwayland.c | 12 ++++++++++-- 3 files changed, 26 insertions(+), 6 deletions(-) (limited to 'sway/desktop/xwayland.c') diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 105e77ae..484afd0c 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -221,8 +221,11 @@ static void handle_map(struct wl_listener *listener, void *data) { if (xdg_surface->toplevel->client_pending.fullscreen) { view_set_fullscreen(view, true); + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + arrange_and_commit(ws); + } else { + arrange_and_commit(view->swayc->parent); } - arrange_and_commit(view->swayc->parent); xdg_shell_view->commit.notify = handle_commit; wl_signal_add(&xdg_surface->surface->events.commit, @@ -269,7 +272,10 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, e->fullscreen); struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_and_commit(ws); + struct sway_transaction *transaction = transaction_create(); + arrange_windows(ws, transaction); + transaction_add_damage(transaction, container_get_box(ws->parent)); + transaction_commit(transaction); } void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 19b30604..da2eda7a 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -220,8 +220,11 @@ static void handle_map(struct wl_listener *listener, void *data) { if (xdg_surface->toplevel->client_pending.fullscreen) { view_set_fullscreen(view, true); + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + arrange_and_commit(ws); + } else { + arrange_and_commit(view->swayc->parent); } - arrange_and_commit(view->swayc->parent); xdg_shell_v6_view->commit.notify = handle_commit; wl_signal_add(&xdg_surface->surface->events.commit, @@ -264,7 +267,10 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, e->fullscreen); struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_and_commit(ws); + struct sway_transaction *transaction = transaction_create(); + arrange_windows(ws, transaction); + transaction_add_damage(transaction, container_get_box(ws->parent)); + transaction_commit(transaction); } void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index eea8420d..720ea2fd 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -286,8 +286,11 @@ static void handle_map(struct wl_listener *listener, void *data) { if (xsurface->fullscreen) { view_set_fullscreen(view, true); + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + arrange_and_commit(ws); + } else { + arrange_and_commit(view->swayc->parent); } - arrange_and_commit(view->swayc->parent); } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -337,7 +340,12 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) return; } view_set_fullscreen(view, xsurface->fullscreen); - arrange_and_commit(view->swayc); + + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + struct sway_transaction *transaction = transaction_create(); + arrange_windows(ws, transaction); + transaction_add_damage(transaction, container_get_box(ws->parent)); + transaction_commit(transaction); } static void handle_set_title(struct wl_listener *listener, void *data) { -- cgit v1.2.3 From be86d3aba602fef7b51fafa8a6e7a39d1e49817f Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 27 Jun 2018 17:46:03 +1000 Subject: Remove transaction_add_damage Instead, damage each container when applying the transaction. --- include/sway/desktop/transaction.h | 7 ------- sway/desktop/transaction.c | 42 ++++++++++++++++++-------------------- sway/desktop/xdg_shell.c | 5 +---- sway/desktop/xdg_shell_v6.c | 5 +---- sway/desktop/xwayland.c | 5 +---- sway/tree/arrange.c | 9 -------- sway/tree/view.c | 6 +----- 7 files changed, 24 insertions(+), 55 deletions(-) (limited to 'sway/desktop/xwayland.c') diff --git a/include/sway/desktop/transaction.h b/include/sway/desktop/transaction.h index b1da86f1..fcfed297 100644 --- a/include/sway/desktop/transaction.h +++ b/include/sway/desktop/transaction.h @@ -30,13 +30,6 @@ struct sway_transaction *transaction_create(void); void transaction_add_container(struct sway_transaction *transaction, struct sway_container *container); -/** - * Add a box to be damaged when the transaction is applied. - * The box should be in layout coordinates. - */ -void transaction_add_damage(struct sway_transaction *transaction, - struct wlr_box *box); - /** * Submit a transaction to the client views for configuration. */ diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 98cde889..c29b6661 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -30,7 +30,6 @@ struct sway_transaction { struct wl_event_source *timer; list_t *instructions; // struct sway_transaction_instruction * - list_t *damage; // struct wlr_box * size_t num_waiting; size_t num_configures; struct sway_transaction *next; @@ -51,7 +50,6 @@ struct sway_transaction *transaction_create() { struct sway_transaction *transaction = calloc(1, sizeof(struct sway_transaction)); transaction->instructions = create_list(); - transaction->damage = create_list(); if (server.debug_txn_timings) { clock_gettime(CLOCK_MONOTONIC, &transaction->create_time); } @@ -97,10 +95,6 @@ static void transaction_destroy(struct sway_transaction *transaction) { } list_free(transaction->instructions); - // Free damage - list_foreach(transaction->damage, free); - list_free(transaction->damage); - if (transaction->timer) { wl_event_source_remove(transaction->timer); } @@ -174,13 +168,6 @@ void transaction_add_container(struct sway_transaction *transaction, list_add(transaction->instructions, instruction); } -void transaction_add_damage(struct sway_transaction *transaction, - struct wlr_box *_box) { - struct wlr_box *box = calloc(1, sizeof(struct wlr_box)); - memcpy(box, _box, sizeof(struct wlr_box)); - list_add(transaction->damage, box); -} - /** * Apply a transaction to the "current" state of the tree. */ @@ -200,12 +187,32 @@ static void transaction_apply(struct sway_transaction *transaction) { "%.1fms total (%.1f frames if 60Hz)", transaction, ms_arranging, ms_waiting, ms_total, ms_total / (1000 / 60)); } + // Apply the instruction state to the container's current state for (int i = 0; i < transaction->instructions->length; ++i) { struct sway_transaction_instruction *instruction = transaction->instructions->items[i]; struct sway_container *container = instruction->container; + // Damage the old and new locations + struct wlr_box old_box = { + .x = container->current.swayc_x, + .y = container->current.swayc_y, + .width = container->current.swayc_width, + .height = container->current.swayc_height, + }; + struct wlr_box new_box = { + .x = instruction->state.swayc_x, + .y = instruction->state.swayc_y, + .width = instruction->state.swayc_width, + .height = instruction->state.swayc_height, + }; + for (int j = 0; j < root_container.children->length; ++j) { + struct sway_container *output = root_container.children->items[j]; + output_damage_box(output->sway_output, &old_box); + output_damage_box(output->sway_output, &new_box); + } + // There are separate children lists for each instruction state, the // container's current state and the container's pending state // (ie. con->children). The list itself needs to be freed here. @@ -216,15 +223,6 @@ static void transaction_apply(struct sway_transaction *transaction) { memcpy(&container->current, &instruction->state, sizeof(struct sway_container_state)); } - - // Apply damage - for (int i = 0; i < transaction->damage->length; ++i) { - struct wlr_box *box = transaction->damage->items[i]; - for (int j = 0; j < root_container.children->length; ++j) { - struct sway_container *output = root_container.children->items[j]; - output_damage_box(output->sway_output, box); - } - } } static void transaction_progress_queue() { diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 484afd0c..b6fa9525 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -272,10 +272,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, e->fullscreen); struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - struct sway_transaction *transaction = transaction_create(); - arrange_windows(ws, transaction); - transaction_add_damage(transaction, container_get_box(ws->parent)); - transaction_commit(transaction); + arrange_and_commit(ws); } void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index da2eda7a..6042a806 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -267,10 +267,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, e->fullscreen); struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - struct sway_transaction *transaction = transaction_create(); - arrange_windows(ws, transaction); - transaction_add_damage(transaction, container_get_box(ws->parent)); - transaction_commit(transaction); + arrange_and_commit(ws); } void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 720ea2fd..1d5dab70 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -342,10 +342,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, xsurface->fullscreen); struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - struct sway_transaction *transaction = transaction_create(); - arrange_windows(ws, transaction); - transaction_add_damage(transaction, container_get_box(ws->parent)); - transaction_commit(transaction); + arrange_and_commit(ws); } static void handle_set_title(struct wl_listener *listener, void *data) { diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index cb3f8ba2..582b2891 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -304,15 +304,6 @@ void arrange_windows(struct sway_container *container, case C_TYPES: break; } - // Add damage for whatever container arrange_windows() was called with, - // unless it was called with the special floating container, in which case - // we'll damage the entire output. - if (container->type == C_CONTAINER && container->layout == L_FLOATING) { - struct sway_container *output = container_parent(container, C_OUTPUT); - transaction_add_damage(transaction, container_get_box(output)); - } else { - transaction_add_damage(transaction, container_get_box(container)); - } add_deleted_containers(transaction); } diff --git a/sway/tree/view.c b/sway/tree/view.c index a616af03..68d2a029 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -550,11 +550,7 @@ void view_unmap(struct sway_view *view) { ws->sway_workspace->fullscreen = NULL; container_destroy(view->swayc); - struct sway_container *output = ws->parent; - struct sway_transaction *transaction = transaction_create(); - arrange_windows(output, transaction); - transaction_add_damage(transaction, container_get_box(output)); - transaction_commit(transaction); + arrange_and_commit(ws->parent); } else { struct sway_container *parent = container_destroy(view->swayc); arrange_and_commit(parent); -- cgit v1.2.3 From e6829c5991cac1bd164f800c14fccd522d702783 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 27 Jun 2018 17:54:57 +1000 Subject: Move unsetting of view->surface into view_unmap --- sway/desktop/xdg_shell.c | 1 - sway/desktop/xdg_shell_v6.c | 1 - sway/desktop/xwayland.c | 2 -- sway/tree/view.c | 1 + 4 files changed, 1 insertion(+), 4 deletions(-) (limited to 'sway/desktop/xwayland.c') diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index b6fa9525..b076d772 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -201,7 +201,6 @@ static void handle_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&xdg_shell_view->commit.link); wl_list_remove(&xdg_shell_view->new_popup.link); - view->surface = NULL; } static void handle_map(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 6042a806..7320e629 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -200,7 +200,6 @@ static void handle_unmap(struct wl_listener *listener, void *data) { wl_list_remove(&xdg_shell_v6_view->commit.link); wl_list_remove(&xdg_shell_v6_view->new_popup.link); - view->surface = NULL; } static void handle_map(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 1d5dab70..854da006 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -263,7 +263,6 @@ static void handle_unmap(struct wl_listener *listener, void *data) { view_unmap(view); wl_list_remove(&xwayland_view->commit.link); - view->surface = NULL; } static void handle_map(struct wl_listener *listener, void *data) { @@ -301,7 +300,6 @@ static void handle_destroy(struct wl_listener *listener, void *data) { if (view->surface) { view_unmap(view); wl_list_remove(&xwayland_view->commit.link); - view->surface = NULL; } wl_list_remove(&xwayland_view->destroy.link); diff --git a/sway/tree/view.c b/sway/tree/view.c index 68d2a029..9f85bac0 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -555,6 +555,7 @@ void view_unmap(struct sway_view *view) { struct sway_container *parent = container_destroy(view->swayc); arrange_and_commit(parent); } + view->surface = NULL; } void view_update_position(struct sway_view *view, double lx, double ly) { -- cgit v1.2.3 From 96c8c024830f13a27790d4ea36b640df383a7f49 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 30 Jun 2018 14:30:14 +1000 Subject: Fix flash of background when xwayland views are mapped A flash of background was happening for two reasons: 1) We were using the xsurface's dimensions to check if the surface is ready, but these are pending dimensions. 2) In my particular setup, the default geometry of the xsurface does not intersect any output, which prevented it from receiving a frame done event. This made the transaction time out and the client would only redraw once it's been rendered. --- sway/desktop/transaction.c | 7 +++++++ sway/desktop/xwayland.c | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'sway/desktop/xwayland.c') diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 7c5a9b8f..d2932c87 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -298,6 +298,13 @@ void transaction_commit(struct sway_transaction *transaction) { instruction->state.view_width, instruction->state.view_height); ++transaction->num_waiting; + + // From here on we are rendering a saved buffer of the view, which + // means we can send a frame done event to make the client redraw it + // as soon as possible. Additionally, this is required if a view is + // mapping and its default geometry doesn't intersect an output. + struct timespec when; + wlr_surface_send_frame_done(con->sway_view->surface, &when); } list_add(con->instructions, instruction); } diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 023fb2a7..ad893248 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -269,10 +269,11 @@ static void handle_commit(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, commit); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; + struct wlr_surface_state *surface_state = xsurface->surface->current; if (view->swayc->instructions->length) { transaction_notify_view_ready_by_size(view, - xsurface->width, xsurface->height); + surface_state->width, surface_state->height); } view_damage_from(view); } -- cgit v1.2.3