diff options
author | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-06-24 12:33:23 +1000 |
---|---|---|
committer | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-06-24 12:33:23 +1000 |
commit | f08a30d6d04b5f986ea1e66a017e81bcd7c77e39 (patch) | |
tree | a252ff8805495230ad7ac6ecdc81ac664649f6e0 | |
parent | Fix crash when deleting last child in a tabbed or stacked container (diff) | |
download | sway-f08a30d6d04b5f986ea1e66a017e81bcd7c77e39.tar.gz sway-f08a30d6d04b5f986ea1e66a017e81bcd7c77e39.tar.zst sway-f08a30d6d04b5f986ea1e66a017e81bcd7c77e39.zip |
Force transactions to complete in order
This forces transactions to complete in order by using a singly linked
list stored in the sway server.
-rw-r--r-- | include/sway/server.h | 2 | ||||
-rw-r--r-- | sway/desktop/transaction.c | 90 |
2 files changed, 74 insertions, 18 deletions
diff --git a/include/sway/server.h b/include/sway/server.h index b07e86a7..2aa7b7fe 100644 --- a/include/sway/server.h +++ b/include/sway/server.h | |||
@@ -47,6 +47,8 @@ struct sway_server { | |||
47 | 47 | ||
48 | bool terminating; | 48 | bool terminating; |
49 | 49 | ||
50 | struct sway_transaction *head_transaction; // singly linked list | ||
51 | |||
50 | // When a view is being destroyed and is waiting for a transaction to | 52 | // When a view is being destroyed and is waiting for a transaction to |
51 | // complete it will be stored here. | 53 | // complete it will be stored here. |
52 | list_t *destroying_containers; | 54 | list_t *destroying_containers; |
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 6e09537a..04142bcc 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -31,6 +31,7 @@ struct sway_transaction { | |||
31 | list_t *instructions; // struct sway_transaction_instruction * | 31 | list_t *instructions; // struct sway_transaction_instruction * |
32 | list_t *damage; // struct wlr_box * | 32 | list_t *damage; // struct wlr_box * |
33 | size_t num_waiting; | 33 | size_t num_waiting; |
34 | struct sway_transaction *next; | ||
34 | }; | 35 | }; |
35 | 36 | ||
36 | struct sway_transaction_instruction { | 37 | struct sway_transaction_instruction { |
@@ -175,6 +176,7 @@ void transaction_add_damage(struct sway_transaction *transaction, | |||
175 | * Apply a transaction to the "current" state of the tree. | 176 | * Apply a transaction to the "current" state of the tree. |
176 | */ | 177 | */ |
177 | static void transaction_apply(struct sway_transaction *transaction) { | 178 | static void transaction_apply(struct sway_transaction *transaction) { |
179 | wlr_log(L_DEBUG, "Applying transaction %p", transaction); | ||
178 | int i; | 180 | int i; |
179 | // Apply the instruction state to the container's current state | 181 | // Apply the instruction state to the container's current state |
180 | for (i = 0; i < transaction->instructions->length; ++i) { | 182 | for (i = 0; i < transaction->instructions->length; ++i) { |
@@ -203,15 +205,54 @@ static void transaction_apply(struct sway_transaction *transaction) { | |||
203 | } | 205 | } |
204 | } | 206 | } |
205 | 207 | ||
208 | static void progress_queue() { | ||
209 | struct sway_transaction *transaction = server.head_transaction; | ||
210 | struct sway_transaction *next = NULL; | ||
211 | while (transaction && !transaction->num_waiting) { | ||
212 | next = transaction->next; | ||
213 | transaction_apply(transaction); | ||
214 | transaction_destroy(transaction); | ||
215 | transaction = next; | ||
216 | } | ||
217 | server.head_transaction = transaction; | ||
218 | } | ||
219 | |||
206 | static int handle_timeout(void *data) { | 220 | static int handle_timeout(void *data) { |
207 | struct sway_transaction *transaction = data; | 221 | struct sway_transaction *transaction = data; |
208 | wlr_log(L_DEBUG, "Transaction %p timed out (%li waiting), applying anyway", | 222 | wlr_log(L_DEBUG, "Transaction %p timed out (%li waiting)", |
209 | transaction, transaction->num_waiting); | 223 | transaction, transaction->num_waiting); |
210 | transaction_apply(transaction); | 224 | transaction->num_waiting = 0; |
211 | transaction_destroy(transaction); | 225 | progress_queue(); |
212 | return 0; | 226 | return 0; |
213 | } | 227 | } |
214 | 228 | ||
229 | static bool should_configure(struct sway_container *con, | ||
230 | struct sway_transaction_instruction *instruction) { | ||
231 | if (con->type != C_VIEW) { | ||
232 | return false; | ||
233 | } | ||
234 | if (con->destroying) { | ||
235 | return false; | ||
236 | } | ||
237 | // The settled dimensions are what size the view will be once any pending | ||
238 | // configures have applied (excluding the one we might be configuring now). | ||
239 | // If these match the dimensions that this transaction wants then we don't | ||
240 | // need to configure it. | ||
241 | int settled_width = con->current.view_width; | ||
242 | int settled_height = con->current.view_height; | ||
243 | if (con->instructions->length) { | ||
244 | struct sway_transaction_instruction *last_instruction = | ||
245 | con->instructions->items[con->instructions->length - 1]; | ||
246 | settled_width = last_instruction->state.view_width; | ||
247 | settled_height = last_instruction->state.view_height; | ||
248 | } | ||
249 | if (settled_width == instruction->state.view_width && | ||
250 | settled_height == instruction->state.view_height) { | ||
251 | return false; | ||
252 | } | ||
253 | return true; | ||
254 | } | ||
255 | |||
215 | void transaction_commit(struct sway_transaction *transaction) { | 256 | void transaction_commit(struct sway_transaction *transaction) { |
216 | wlr_log(L_DEBUG, "Transaction %p committing with %i instructions", | 257 | wlr_log(L_DEBUG, "Transaction %p committing with %i instructions", |
217 | transaction, transaction->instructions->length); | 258 | transaction, transaction->instructions->length); |
@@ -220,9 +261,7 @@ void transaction_commit(struct sway_transaction *transaction) { | |||
220 | struct sway_transaction_instruction *instruction = | 261 | struct sway_transaction_instruction *instruction = |
221 | transaction->instructions->items[i]; | 262 | transaction->instructions->items[i]; |
222 | struct sway_container *con = instruction->container; | 263 | struct sway_container *con = instruction->container; |
223 | if (con->type == C_VIEW && !con->destroying && | 264 | if (should_configure(con, instruction)) { |
224 | (con->current.view_width != instruction->state.view_width || | ||
225 | con->current.view_height != instruction->state.view_height)) { | ||
226 | instruction->serial = view_configure(con->sway_view, | 265 | instruction->serial = view_configure(con->sway_view, |
227 | instruction->state.view_x, | 266 | instruction->state.view_x, |
228 | instruction->state.view_y, | 267 | instruction->state.view_y, |
@@ -234,18 +273,33 @@ void transaction_commit(struct sway_transaction *transaction) { | |||
234 | } | 273 | } |
235 | list_add(con->instructions, instruction); | 274 | list_add(con->instructions, instruction); |
236 | } | 275 | } |
237 | if (!transaction->num_waiting) { | 276 | if (server.head_transaction) { |
238 | wlr_log(L_DEBUG, "Transaction %p has nothing to wait for, applying", | 277 | // There is another transaction in progress - we must add this one to |
239 | transaction); | 278 | // the queue so we complete after it. |
279 | struct sway_transaction *tail = server.head_transaction; | ||
280 | while (tail->next) { | ||
281 | tail = tail->next; | ||
282 | } | ||
283 | tail->next = transaction; | ||
284 | } else if (transaction->num_waiting) { | ||
285 | // There are no other transactions, but we're not applying immediately | ||
286 | // so we must jump in the queue so others will queue behind us. | ||
287 | server.head_transaction = transaction; | ||
288 | } else { | ||
289 | // There are no other transactions in progress, and this one has nothing | ||
290 | // to wait for, so we can skip the queue. | ||
291 | wlr_log(L_DEBUG, "Transaction %p has nothing to wait for", transaction); | ||
240 | transaction_apply(transaction); | 292 | transaction_apply(transaction); |
241 | transaction_destroy(transaction); | 293 | transaction_destroy(transaction); |
242 | return; | 294 | return; |
243 | } | 295 | } |
244 | 296 | ||
245 | // Set up a timer which the views must respond within | 297 | if (transaction->num_waiting) { |
246 | transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, | 298 | // Set up a timer which the views must respond within |
247 | handle_timeout, transaction); | 299 | transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, |
248 | wl_event_source_timer_update(transaction->timer, TIMEOUT_MS); | 300 | handle_timeout, transaction); |
301 | wl_event_source_timer_update(transaction->timer, TIMEOUT_MS); | ||
302 | } | ||
249 | 303 | ||
250 | // The debug tree shows the pending/live tree. Here is a good place to | 304 | // The debug tree shows the pending/live tree. Here is a good place to |
251 | // update it, because we make a transaction every time we change the pending | 305 | // update it, because we make a transaction every time we change the pending |
@@ -269,14 +323,14 @@ void transaction_notify_view_ready(struct sway_view *view, uint32_t serial) { | |||
269 | } | 323 | } |
270 | instruction->ready = true; | 324 | instruction->ready = true; |
271 | 325 | ||
272 | // If all views are ready, apply the transaction | 326 | // If all views are ready, apply the transaction. |
327 | // If the transaction has timed out then its num_waiting will be 0 already. | ||
273 | struct sway_transaction *transaction = instruction->transaction; | 328 | struct sway_transaction *transaction = instruction->transaction; |
274 | if (--transaction->num_waiting == 0) { | 329 | if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { |
275 | #if !TRANSACTION_DEBUG | 330 | #if !TRANSACTION_DEBUG |
276 | wlr_log(L_DEBUG, "Transaction %p is ready, applying", transaction); | 331 | wlr_log(L_DEBUG, "Transaction %p is ready", transaction); |
277 | wl_event_source_timer_update(transaction->timer, 0); | 332 | wl_event_source_timer_update(transaction->timer, 0); |
278 | transaction_apply(transaction); | 333 | progress_queue(); |
279 | transaction_destroy(transaction); | ||
280 | #endif | 334 | #endif |
281 | } | 335 | } |
282 | } | 336 | } |