aboutsummaryrefslogtreecommitdiff
path: root/sway/desktop/transaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/desktop/transaction.c')
-rw-r--r--sway/desktop/transaction.c374
1 files changed, 235 insertions, 139 deletions
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index 145c5f92..b4eec933 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -12,6 +12,7 @@
#include "sway/desktop/transaction.h"
#include "sway/output.h"
#include "sway/tree/container.h"
+#include "sway/tree/node.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
#include "list.h"
@@ -27,8 +28,12 @@ struct sway_transaction {
struct sway_transaction_instruction {
struct sway_transaction *transaction;
- struct sway_container *container;
- struct sway_container_state state;
+ struct sway_node *node;
+ union {
+ struct sway_output_state *output_state;
+ struct sway_workspace_state *workspace_state;
+ struct sway_container_state *container_state;
+ };
uint32_t serial;
};
@@ -47,26 +52,24 @@ static void transaction_destroy(struct sway_transaction *transaction) {
for (int i = 0; i < transaction->instructions->length; ++i) {
struct sway_transaction_instruction *instruction =
transaction->instructions->items[i];
- struct sway_container *con = instruction->container;
- con->ntxnrefs--;
- if (con->instruction == instruction) {
- con->instruction = NULL;
+ struct sway_node *node = instruction->node;
+ node->ntxnrefs--;
+ if (node->instruction == instruction) {
+ node->instruction = NULL;
}
- if (con->destroying && con->ntxnrefs == 0) {
- switch (con->type) {
- case C_ROOT:
+ if (node->destroying && node->ntxnrefs == 0) {
+ switch (node->type) {
+ case N_ROOT:
+ sway_assert(false, "Never reached");
break;
- case C_OUTPUT:
- output_destroy(con);
+ case N_OUTPUT:
+ output_destroy(node->sway_output);
break;
- case C_WORKSPACE:
- workspace_destroy(con);
+ case N_WORKSPACE:
+ workspace_destroy(node->sway_workspace);
break;
- case C_CONTAINER:
- case C_VIEW:
- container_destroy(con);
- break;
- case C_TYPES:
+ case N_CONTAINER:
+ container_destroy(node->sway_container);
break;
}
}
@@ -80,22 +83,79 @@ static void transaction_destroy(struct sway_transaction *transaction) {
free(transaction);
}
-static void copy_pending_state(struct sway_container *container,
- struct sway_container_state *state) {
+static void copy_output_state(struct sway_output *output,
+ struct sway_transaction_instruction *instruction) {
+ struct sway_output_state *state =
+ calloc(1, sizeof(struct sway_output_state));
+ if (!state) {
+ wlr_log(WLR_ERROR, "Could not allocate output state");
+ return;
+ }
+ instruction->output_state = state;
+
+ state->workspaces = create_list();
+ list_cat(state->workspaces, output->workspaces);
+
+ state->active_workspace = output_get_active_workspace(output);
+}
+
+static void copy_workspace_state(struct sway_workspace *ws,
+ struct sway_transaction_instruction *instruction) {
+ struct sway_workspace_state *state =
+ calloc(1, sizeof(struct sway_workspace_state));
+ if (!state) {
+ wlr_log(WLR_ERROR, "Could not allocate workspace state");
+ return;
+ }
+ instruction->workspace_state = state;
+
+ state->fullscreen = ws->fullscreen;
+ state->x = ws->x;
+ state->y = ws->y;
+ state->width = ws->width;
+ state->height = ws->height;
+ state->layout = ws->layout;
+
+ state->output = ws->output;
+ state->floating = create_list();
+ state->tiling = create_list();
+ list_cat(state->floating, ws->floating);
+ list_cat(state->tiling, ws->tiling);
+
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ state->focused = seat_get_focus(seat) == &ws->node;
+
+ // Set focused_inactive_child to the direct tiling child
+ struct sway_container *focus = seat_get_focus_inactive_tiling(seat, ws);
+ if (focus) {
+ while (focus->parent) {
+ focus = focus->parent;
+ }
+ }
+ state->focused_inactive_child = focus;
+}
+
+static void copy_container_state(struct sway_container *container,
+ struct sway_transaction_instruction *instruction) {
+ struct sway_container_state *state =
+ calloc(1, sizeof(struct sway_container_state));
+ if (!state) {
+ wlr_log(WLR_ERROR, "Could not allocate container state");
+ return;
+ }
+ instruction->container_state = 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;
+ state->con_x = container->x;
+ state->con_y = container->y;
+ state->con_width = container->width;
+ state->con_height = container->height;
state->is_fullscreen = container->is_fullscreen;
- state->has_gaps = container->has_gaps;
- state->current_gaps = container->current_gaps;
- state->gaps_inner = container->gaps_inner;
- state->gaps_outer = container->gaps_outer;
state->parent = container->parent;
+ state->workspace = container->workspace;
- if (container->type == C_VIEW) {
- struct sway_view *view = container->sway_view;
+ if (container->view) {
+ struct sway_view *view = container->view;
state->view_x = view->x;
state->view_y = view->y;
state->view_width = view->width;
@@ -107,50 +167,111 @@ static void copy_pending_state(struct sway_container *container,
state->border_right = view->border_right;
state->border_bottom = view->border_bottom;
state->using_csd = view->using_csd;
- } else if (container->type == C_WORKSPACE) {
- state->ws_fullscreen = container->sway_workspace->fullscreen;
- state->ws_floating = create_list();
- state->children = create_list();
- list_cat(state->ws_floating, container->sway_workspace->floating);
- list_cat(state->children, container->children);
} else {
state->children = create_list();
list_cat(state->children, container->children);
}
struct sway_seat *seat = input_manager_current_seat(input_manager);
- state->focused = seat_get_focus(seat) == container;
-
- if (container->type == C_WORKSPACE) {
- // Set focused_inactive_child to the direct tiling child
- struct sway_container *focus =
- seat_get_focus_inactive_tiling(seat, container);
- if (focus && focus->type > C_WORKSPACE) {
- while (focus->parent->type != C_WORKSPACE) {
- focus = focus->parent;
- }
- }
- state->focused_inactive_child = focus;
- } else if (container->type != C_VIEW) {
- state->focused_inactive_child =
- seat_get_active_child(seat, container);
+ state->focused = seat_get_focus(seat) == &container->node;
+
+ if (!container->view) {
+ struct sway_node *focus = seat_get_active_child(seat, &container->node);
+ state->focused_inactive_child = focus ? focus->sway_container : NULL;
}
}
-static void transaction_add_container(struct sway_transaction *transaction,
- struct sway_container *container) {
+static void transaction_add_node(struct sway_transaction *transaction,
+ struct sway_node *node) {
struct sway_transaction_instruction *instruction =
calloc(1, sizeof(struct sway_transaction_instruction));
if (!sway_assert(instruction, "Unable to allocate instruction")) {
return;
}
instruction->transaction = transaction;
- instruction->container = container;
-
- copy_pending_state(container, &instruction->state);
+ instruction->node = node;
+
+ switch (node->type) {
+ case N_ROOT:
+ break;
+ case N_OUTPUT:
+ copy_output_state(node->sway_output, instruction);
+ break;
+ case N_WORKSPACE:
+ copy_workspace_state(node->sway_workspace, instruction);
+ break;
+ case N_CONTAINER:
+ copy_container_state(node->sway_container, instruction);
+ break;
+ }
list_add(transaction->instructions, instruction);
- container->ntxnrefs++;
+ node->ntxnrefs++;
+}
+
+static void apply_output_state(struct sway_output *output,
+ struct sway_output_state *state) {
+ output_damage_whole(output);
+ list_free(output->current.workspaces);
+ memcpy(&output->current, state, sizeof(struct sway_output_state));
+ output_damage_whole(output);
+}
+
+static void apply_workspace_state(struct sway_workspace *ws,
+ struct sway_workspace_state *state) {
+ output_damage_whole(ws->current.output);
+ list_free(ws->current.floating);
+ list_free(ws->current.tiling);
+ memcpy(&ws->current, state, sizeof(struct sway_workspace_state));
+ output_damage_whole(ws->current.output);
+}
+
+static void apply_container_state(struct sway_container *container,
+ struct sway_container_state *state) {
+ struct sway_view *view = container->view;
+ // Damage the old location
+ desktop_damage_whole_container(container);
+ if (view && view->saved_buffer) {
+ struct wlr_box box = {
+ .x = container->current.view_x - view->saved_geometry.x,
+ .y = container->current.view_y - view->saved_geometry.y,
+ .width = view->saved_buffer_width,
+ .height = view->saved_buffer_height,
+ };
+ desktop_damage_box(&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.
+ // Any child containers which are being deleted will be cleaned up in
+ // transaction_destroy().
+ list_free(container->current.children);
+
+ memcpy(&container->current, state, sizeof(struct sway_container_state));
+
+ if (view && view->saved_buffer) {
+ if (!container->node.destroying || container->node.ntxnrefs == 1) {
+ view_remove_saved_buffer(view);
+ }
+ }
+
+ // Damage the new location
+ desktop_damage_whole_container(container);
+ if (view && view->surface) {
+ struct wlr_surface *surface = view->surface;
+ struct wlr_box box = {
+ .x = container->current.view_x - view->geometry.x,
+ .y = container->current.view_y - view->geometry.y,
+ .width = surface->current.width,
+ .height = surface->current.height,
+ };
+ desktop_damage_box(&box);
+ }
+
+ if (!container->node.destroying) {
+ container_discover_outputs(container);
+ }
}
/**
@@ -168,67 +289,36 @@ static void transaction_apply(struct sway_transaction *transaction) {
"(%.1f frames if 60Hz)", transaction, ms, ms / (1000.0f / 60));
}
- // Apply the instruction state to the container's current state
+ // Apply the instruction state to the node'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 location
- desktop_damage_whole_container(container);
- if (container->type == C_VIEW && container->sway_view->saved_buffer) {
- struct sway_view *view = container->sway_view;
- struct wlr_box box = {
- .x = container->current.view_x - view->saved_geometry.x,
- .y = container->current.view_y - view->saved_geometry.y,
- .width = view->saved_buffer_width,
- .height = view->saved_buffer_height,
- };
- desktop_damage_box(&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.
- // Any child containers which are being deleted will be cleaned up in
- // transaction_destroy().
- list_free(container->current.children);
- list_free(container->current.ws_floating);
-
- memcpy(&container->current, &instruction->state,
- sizeof(struct sway_container_state));
-
- if (container->type == C_VIEW && container->sway_view->saved_buffer) {
- if (!container->destroying || container->ntxnrefs == 1) {
- view_remove_saved_buffer(container->sway_view);
- }
- }
+ struct sway_node *node = instruction->node;
- // Damage the new location
- desktop_damage_whole_container(container);
- if (container->type == C_VIEW && container->sway_view->surface) {
- struct sway_view *view = container->sway_view;
- struct wlr_surface *surface = view->surface;
- struct wlr_box box = {
- .x = container->current.view_x - view->geometry.x,
- .y = container->current.view_y - view->geometry.y,
- .width = surface->current.width,
- .height = surface->current.height,
- };
- desktop_damage_box(&box);
+ switch (node->type) {
+ case N_ROOT:
+ break;
+ case N_OUTPUT:
+ apply_output_state(node->sway_output, instruction->output_state);
+ break;
+ case N_WORKSPACE:
+ apply_workspace_state(node->sway_workspace,
+ instruction->workspace_state);
+ break;
+ case N_CONTAINER:
+ apply_container_state(node->sway_container,
+ instruction->container_state);
+ break;
}
- container->instruction = NULL;
- if (container->type == C_CONTAINER || container->type == C_VIEW) {
- container_discover_outputs(container);
- }
+ node->instruction = NULL;
}
}
static void transaction_commit(struct sway_transaction *transaction);
-// Return true if both transactions operate on the same containers
-static bool transaction_same_containers(struct sway_transaction *a,
+// Return true if both transactions operate on the same nodes
+static bool transaction_same_nodes(struct sway_transaction *a,
struct sway_transaction *b) {
if (a->instructions->length != b->instructions->length) {
return false;
@@ -236,7 +326,7 @@ static bool transaction_same_containers(struct sway_transaction *a,
for (int i = 0; i < a->instructions->length; ++i) {
struct sway_transaction_instruction *a_inst = a->instructions->items[i];
struct sway_transaction_instruction *b_inst = b->instructions->items[i];
- if (a_inst->container != b_inst->container) {
+ if (a_inst->node != b_inst->node) {
return false;
}
}
@@ -267,7 +357,7 @@ static void transaction_progress_queue() {
while (server.transactions->length >= 2) {
struct sway_transaction *a = server.transactions->items[0];
struct sway_transaction *b = server.transactions->items[1];
- if (transaction_same_containers(a, b)) {
+ if (transaction_same_nodes(a, b)) {
list_del(server.transactions, 0);
transaction_destroy(a);
} else {
@@ -289,16 +379,18 @@ static int handle_timeout(void *data) {
return 0;
}
-static bool should_configure(struct sway_container *con,
+static bool should_configure(struct sway_node *node,
struct sway_transaction_instruction *instruction) {
- if (con->type != C_VIEW) {
+ if (!node_is_view(node)) {
return false;
}
- if (con->destroying) {
+ if (node->destroying) {
return false;
}
- if (con->current.view_width == instruction->state.view_width &&
- con->current.view_height == instruction->state.view_height) {
+ struct sway_container_state *cstate = &node->sway_container->current;
+ struct sway_container_state *istate = instruction->container_state;
+ if (cstate->view_width == istate->view_width &&
+ cstate->view_height == istate->view_height) {
return false;
}
return true;
@@ -311,13 +403,13 @@ static 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];
- struct sway_container *con = instruction->container;
- if (should_configure(con, instruction)) {
- instruction->serial = view_configure(con->sway_view,
- instruction->state.view_x,
- instruction->state.view_y,
- instruction->state.view_width,
- instruction->state.view_height);
+ struct sway_node *node = instruction->node;
+ if (should_configure(node, instruction)) {
+ instruction->serial = view_configure(node->sway_container->view,
+ instruction->container_state->view_x,
+ instruction->container_state->view_y,
+ instruction->container_state->view_width,
+ instruction->container_state->view_height);
++transaction->num_waiting;
// From here on we are rendering a saved buffer of the view, which
@@ -325,14 +417,16 @@ static void transaction_commit(struct sway_transaction *transaction) {
// 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);
+ wlr_surface_send_frame_done(
+ node->sway_container->view->surface, &when);
}
- if (con->type == C_VIEW && !con->sway_view->saved_buffer) {
- view_save_buffer(con->sway_view);
- memcpy(&con->sway_view->saved_geometry, &con->sway_view->geometry,
+ if (node_is_view(node) && !node->sway_container->view->saved_buffer) {
+ view_save_buffer(node->sway_container->view);
+ memcpy(&node->sway_container->view->saved_geometry,
+ &node->sway_container->view->geometry,
sizeof(struct wlr_box));
}
- con->instruction = instruction;
+ node->instruction = instruction;
}
transaction->num_configures = transaction->num_waiting;
if (debug.txn_timings) {
@@ -381,7 +475,7 @@ static void set_instruction_ready(
transaction,
transaction->num_configures - transaction->num_waiting + 1,
transaction->num_configures, ms,
- instruction->container->name);
+ instruction->node->sway_container->title);
}
// If the transaction has timed out then its num_waiting will be 0 already.
@@ -390,41 +484,43 @@ static void set_instruction_ready(
wl_event_source_timer_update(transaction->timer, 0);
}
- instruction->container->instruction = NULL;
+ instruction->node->instruction = NULL;
transaction_progress_queue();
}
void transaction_notify_view_ready_by_serial(struct sway_view *view,
uint32_t serial) {
- struct sway_transaction_instruction *instruction = view->swayc->instruction;
- if (view->swayc->instruction->serial == serial) {
+ struct sway_transaction_instruction *instruction =
+ view->container->node.instruction;
+ if (instruction->serial == serial) {
set_instruction_ready(instruction);
}
}
void transaction_notify_view_ready_by_size(struct sway_view *view,
int width, int height) {
- struct sway_transaction_instruction *instruction = view->swayc->instruction;
- if (instruction->state.view_width == width &&
- instruction->state.view_height == height) {
+ struct sway_transaction_instruction *instruction =
+ view->container->node.instruction;
+ if (instruction->container_state->view_width == width &&
+ instruction->container_state->view_height == height) {
set_instruction_ready(instruction);
}
}
void transaction_commit_dirty(void) {
- if (!server.dirty_containers->length) {
+ if (!server.dirty_nodes->length) {
return;
}
struct sway_transaction *transaction = transaction_create();
if (!transaction) {
return;
}
- for (int i = 0; i < server.dirty_containers->length; ++i) {
- struct sway_container *container = server.dirty_containers->items[i];
- transaction_add_container(transaction, container);
- container->dirty = false;
+ for (int i = 0; i < server.dirty_nodes->length; ++i) {
+ struct sway_node *node = server.dirty_nodes->items[i];
+ transaction_add_node(transaction, node);
+ node->dirty = false;
}
- server.dirty_containers->length = 0;
+ server.dirty_nodes->length = 0;
list_add(server.transactions, transaction);