aboutsummaryrefslogtreecommitdiffstats
path: root/sway/desktop/transaction.c
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-06-24 12:33:23 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-06-24 12:33:23 +1000
commitf08a30d6d04b5f986ea1e66a017e81bcd7c77e39 (patch)
treea252ff8805495230ad7ac6ecdc81ac664649f6e0 /sway/desktop/transaction.c
parentFix crash when deleting last child in a tabbed or stacked container (diff)
downloadsway-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.
Diffstat (limited to 'sway/desktop/transaction.c')
-rw-r--r--sway/desktop/transaction.c90
1 files changed, 72 insertions, 18 deletions
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
36struct sway_transaction_instruction { 37struct 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 */
177static void transaction_apply(struct sway_transaction *transaction) { 178static 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
208static 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
206static int handle_timeout(void *data) { 220static 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
229static 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
215void transaction_commit(struct sway_transaction *transaction) { 256void 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}