diff options
author | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-06-03 16:35:06 +1000 |
---|---|---|
committer | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-06-09 10:08:43 +1000 |
commit | 59c94887018bdfa578c4371c4275061ca6e71b3e (patch) | |
tree | 62bdaa6ac4777d1fcb292013bddd2043dad7765a /sway/desktop/transaction.c | |
parent | Merge pull request #2115 from RedSoxFan/restore-workspaces (diff) | |
download | sway-59c94887018bdfa578c4371c4275061ca6e71b3e.tar.gz sway-59c94887018bdfa578c4371c4275061ca6e71b3e.tar.zst sway-59c94887018bdfa578c4371c4275061ca6e71b3e.zip |
WIP: Atomic layout updates ground work
Diffstat (limited to 'sway/desktop/transaction.c')
-rw-r--r-- | sway/desktop/transaction.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c new file mode 100644 index 00000000..69f97e3d --- /dev/null +++ b/sway/desktop/transaction.c | |||
@@ -0,0 +1,214 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include <stdbool.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <string.h> | ||
5 | #include <wlr/types/wlr_linux_dmabuf.h> | ||
6 | #include "sway/debug.h" | ||
7 | #include "sway/desktop/transaction.h" | ||
8 | #include "sway/output.h" | ||
9 | #include "sway/tree/container.h" | ||
10 | #include "sway/tree/view.h" | ||
11 | #include "list.h" | ||
12 | #include "log.h" | ||
13 | |||
14 | /** | ||
15 | * How long we should wait for views to respond to the configure before giving | ||
16 | * up and applying the transaction anyway. | ||
17 | */ | ||
18 | #define TIMEOUT_MS 200 | ||
19 | |||
20 | struct sway_transaction_instruction { | ||
21 | struct sway_transaction *transaction; | ||
22 | struct sway_container *container; | ||
23 | struct sway_container_state state; | ||
24 | uint32_t serial; | ||
25 | }; | ||
26 | |||
27 | struct sway_transaction *transaction_create() { | ||
28 | struct sway_transaction *transaction = | ||
29 | calloc(1, sizeof(struct sway_transaction)); | ||
30 | transaction->instructions = create_list(); | ||
31 | transaction->damage = create_list(); | ||
32 | return transaction; | ||
33 | } | ||
34 | |||
35 | static void transaction_destroy(struct sway_transaction *transaction) { | ||
36 | int i; | ||
37 | // Free instructions | ||
38 | for (i = 0; i < transaction->instructions->length; ++i) { | ||
39 | struct sway_transaction_instruction *instruction = | ||
40 | transaction->instructions->items[i]; | ||
41 | if (instruction->container->type == C_VIEW) { | ||
42 | struct sway_view *view = instruction->container->sway_view; | ||
43 | for (int j = 0; j < view->instructions->length; ++j) { | ||
44 | if (view->instructions->items[j] == instruction) { | ||
45 | list_del(view->instructions, j); | ||
46 | break; | ||
47 | } | ||
48 | } | ||
49 | } | ||
50 | free(instruction); | ||
51 | } | ||
52 | list_free(transaction->instructions); | ||
53 | |||
54 | // Free damage | ||
55 | for (i = 0; i < transaction->damage->length; ++i) { | ||
56 | struct wlr_box *box = transaction->damage->items[i]; | ||
57 | free(box); | ||
58 | } | ||
59 | list_free(transaction->damage); | ||
60 | |||
61 | free(transaction); | ||
62 | } | ||
63 | |||
64 | void transaction_add_container(struct sway_transaction *transaction, | ||
65 | struct sway_container *container) { | ||
66 | struct sway_transaction_instruction *instruction = | ||
67 | calloc(1, sizeof(struct sway_transaction_instruction)); | ||
68 | instruction->transaction = transaction; | ||
69 | instruction->container = container; | ||
70 | memcpy(&instruction->state, &container->pending, | ||
71 | sizeof(struct sway_container_state)); | ||
72 | list_add(transaction->instructions, instruction); | ||
73 | } | ||
74 | |||
75 | void transaction_add_damage(struct sway_transaction *transaction, | ||
76 | struct wlr_box *_box) { | ||
77 | struct wlr_box *box = calloc(1, sizeof(struct wlr_box)); | ||
78 | memcpy(box, _box, sizeof(struct wlr_box)); | ||
79 | list_add(transaction->damage, box); | ||
80 | } | ||
81 | |||
82 | static void save_view_texture(struct sway_view *view) { | ||
83 | wlr_texture_destroy(view->saved_texture); | ||
84 | view->saved_texture = NULL; | ||
85 | |||
86 | // TODO: Copy the texture and store it in view->saved_texture. | ||
87 | } | ||
88 | |||
89 | static void remove_saved_view_texture(struct sway_view *view) { | ||
90 | wlr_texture_destroy(view->saved_texture); | ||
91 | view->saved_texture = NULL; | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * Apply a transaction to the "current" state of the tree. | ||
96 | * | ||
97 | * This is mostly copying stuff from the pending state into the main swayc | ||
98 | * properties, but also includes reparenting and deleting containers. | ||
99 | */ | ||
100 | static void transaction_apply(struct sway_transaction *transaction) { | ||
101 | int i; | ||
102 | for (i = 0; i < transaction->instructions->length; ++i) { | ||
103 | struct sway_transaction_instruction *instruction = | ||
104 | transaction->instructions->items[i]; | ||
105 | struct sway_container_state *state = &instruction->state; | ||
106 | struct sway_container *container = instruction->container; | ||
107 | |||
108 | container->layout = state->layout; | ||
109 | container->x = state->swayc_x; | ||
110 | container->y = state->swayc_y; | ||
111 | container->width = state->swayc_width; | ||
112 | container->height = state->swayc_height; | ||
113 | |||
114 | if (container->type == C_VIEW) { | ||
115 | struct sway_view *view = container->sway_view; | ||
116 | view->x = state->view_x; | ||
117 | view->y = state->view_y; | ||
118 | view->width = state->view_width; | ||
119 | view->height = state->view_height; | ||
120 | view->is_fullscreen = state->is_fullscreen; | ||
121 | view->border = state->border; | ||
122 | view->border_thickness = state->border_thickness; | ||
123 | view->border_top = state->border_top; | ||
124 | view->border_left = state->border_left; | ||
125 | view->border_right = state->border_right; | ||
126 | view->border_bottom = state->border_bottom; | ||
127 | |||
128 | remove_saved_view_texture(view); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | // Damage | ||
133 | for (i = 0; i < transaction->damage->length; ++i) { | ||
134 | struct wlr_box *box = transaction->damage->items[i]; | ||
135 | for (int j = 0; j < root_container.children->length; ++j) { | ||
136 | struct sway_container *output = root_container.children->items[j]; | ||
137 | output_damage_box(output->sway_output, box); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | update_debug_tree(); | ||
142 | } | ||
143 | |||
144 | static int handle_timeout(void *data) { | ||
145 | struct sway_transaction *transaction = data; | ||
146 | wlr_log(L_DEBUG, "Transaction %p timed out (%li waiting), applying anyway", | ||
147 | transaction, transaction->num_waiting); | ||
148 | transaction_apply(transaction); | ||
149 | transaction_destroy(transaction); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | void transaction_commit(struct sway_transaction *transaction) { | ||
154 | wlr_log(L_DEBUG, "Transaction %p committing with %i instructions", | ||
155 | transaction, transaction->instructions->length); | ||
156 | transaction->num_waiting = 0; | ||
157 | for (int i = 0; i < transaction->instructions->length; ++i) { | ||
158 | struct sway_transaction_instruction *instruction = | ||
159 | transaction->instructions->items[i]; | ||
160 | if (instruction->container->type == C_VIEW) { | ||
161 | struct sway_view *view = instruction->container->sway_view; | ||
162 | instruction->serial = view_configure(view, | ||
163 | instruction->state.view_x, | ||
164 | instruction->state.view_y, | ||
165 | instruction->state.view_width, | ||
166 | instruction->state.view_height); | ||
167 | if (instruction->serial) { | ||
168 | save_view_texture(view); | ||
169 | list_add(view->instructions, instruction); | ||
170 | ++transaction->num_waiting; | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | if (!transaction->num_waiting) { | ||
175 | // This can happen if the transaction only contains xwayland views | ||
176 | wlr_log(L_DEBUG, "Transaction %p has nothing to wait for, applying", | ||
177 | transaction); | ||
178 | transaction_apply(transaction); | ||
179 | transaction_destroy(transaction); | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | // Set up a timer which the views must respond within | ||
184 | transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, | ||
185 | handle_timeout, transaction); | ||
186 | wl_event_source_timer_update(transaction->timer, TIMEOUT_MS); | ||
187 | } | ||
188 | |||
189 | void transaction_notify_view_ready(struct sway_view *view, uint32_t serial) { | ||
190 | // Find the instruction | ||
191 | struct sway_transaction_instruction *instruction = NULL; | ||
192 | for (int i = 0; i < view->instructions->length; ++i) { | ||
193 | struct sway_transaction_instruction *tmp_instruction = | ||
194 | view->instructions->items[i]; | ||
195 | if (tmp_instruction->serial == serial) { | ||
196 | instruction = tmp_instruction; | ||
197 | list_del(view->instructions, i); | ||
198 | break; | ||
199 | } | ||
200 | } | ||
201 | if (!instruction) { | ||
202 | // This can happen if the view acknowledges the configure after the | ||
203 | // transaction has timed out and applied. | ||
204 | return; | ||
205 | } | ||
206 | // If all views are ready, apply the transaction | ||
207 | struct sway_transaction *transaction = instruction->transaction; | ||
208 | if (--transaction->num_waiting == 0) { | ||
209 | wlr_log(L_DEBUG, "Transaction %p is ready, applying", transaction); | ||
210 | wl_event_source_timer_update(transaction->timer, 0); | ||
211 | transaction_apply(transaction); | ||
212 | transaction_destroy(transaction); | ||
213 | } | ||
214 | } | ||