diff options
Diffstat (limited to 'sway/desktop/transaction.c')
-rw-r--r-- | sway/desktop/transaction.c | 107 |
1 files changed, 56 insertions, 51 deletions
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index d2932c87..2a89880a 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -4,8 +4,8 @@ | |||
4 | #include <string.h> | 4 | #include <string.h> |
5 | #include <time.h> | 5 | #include <time.h> |
6 | #include <wlr/types/wlr_buffer.h> | 6 | #include <wlr/types/wlr_buffer.h> |
7 | #include <wlr/types/wlr_linux_dmabuf.h> | ||
8 | #include "sway/debug.h" | 7 | #include "sway/debug.h" |
8 | #include "sway/desktop/idle_inhibit_v1.h" | ||
9 | #include "sway/desktop/transaction.h" | 9 | #include "sway/desktop/transaction.h" |
10 | #include "sway/output.h" | 10 | #include "sway/output.h" |
11 | #include "sway/tree/container.h" | 11 | #include "sway/tree/container.h" |
@@ -18,14 +18,14 @@ | |||
18 | * How long we should wait for views to respond to the configure before giving | 18 | * How long we should wait for views to respond to the configure before giving |
19 | * up and applying the transaction anyway. | 19 | * up and applying the transaction anyway. |
20 | */ | 20 | */ |
21 | #define TIMEOUT_MS 200 | 21 | int txn_timeout_ms = 200; |
22 | 22 | ||
23 | /** | 23 | /** |
24 | * If enabled, sway will always wait for the transaction timeout before | 24 | * If enabled, sway will always wait for the transaction timeout before |
25 | * applying it, rather than applying it when the views are ready. This allows us | 25 | * applying it, rather than applying it when the views are ready. This allows us |
26 | * to observe the rendered state while a transaction is in progress. | 26 | * to observe the rendered state while a transaction is in progress. |
27 | */ | 27 | */ |
28 | #define TRANSACTION_DEBUG false | 28 | bool txn_debug = false; |
29 | 29 | ||
30 | struct sway_transaction { | 30 | struct sway_transaction { |
31 | struct wl_event_source *timer; | 31 | struct wl_event_source *timer; |
@@ -46,7 +46,7 @@ struct sway_transaction_instruction { | |||
46 | bool ready; | 46 | bool ready; |
47 | }; | 47 | }; |
48 | 48 | ||
49 | struct sway_transaction *transaction_create() { | 49 | static struct sway_transaction *transaction_create() { |
50 | struct sway_transaction *transaction = | 50 | struct sway_transaction *transaction = |
51 | calloc(1, sizeof(struct sway_transaction)); | 51 | calloc(1, sizeof(struct sway_transaction)); |
52 | transaction->instructions = create_list(); | 52 | transaction->instructions = create_list(); |
@@ -72,8 +72,8 @@ static void save_view_buffer(struct sway_view *view, | |||
72 | } | 72 | } |
73 | if (view->surface && wlr_surface_has_buffer(view->surface)) { | 73 | if (view->surface && wlr_surface_has_buffer(view->surface)) { |
74 | instruction->saved_buffer = wlr_buffer_ref(view->surface->buffer); | 74 | instruction->saved_buffer = wlr_buffer_ref(view->surface->buffer); |
75 | instruction->saved_buffer_width = view->surface->current->width; | 75 | instruction->saved_buffer_width = view->surface->current.width; |
76 | instruction->saved_buffer_height = view->surface->current->height; | 76 | instruction->saved_buffer_height = view->surface->current.height; |
77 | } | 77 | } |
78 | } | 78 | } |
79 | 79 | ||
@@ -138,25 +138,18 @@ static void copy_pending_state(struct sway_container *container, | |||
138 | state->children = create_list(); | 138 | state->children = create_list(); |
139 | list_cat(state->children, container->children); | 139 | list_cat(state->children, container->children); |
140 | } | 140 | } |
141 | } | ||
142 | 141 | ||
143 | static bool transaction_has_container(struct sway_transaction *transaction, | 142 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
144 | struct sway_container *container) { | 143 | state->focused = seat_get_focus(seat) == container; |
145 | for (int i = 0; i < transaction->instructions->length; ++i) { | 144 | |
146 | struct sway_transaction_instruction *instruction = | 145 | if (container->type != C_VIEW) { |
147 | transaction->instructions->items[i]; | 146 | state->focused_inactive_child = |
148 | if (instruction->container == container) { | 147 | seat_get_active_child(seat, container); |
149 | return true; | ||
150 | } | ||
151 | } | 148 | } |
152 | return false; | ||
153 | } | 149 | } |
154 | 150 | ||
155 | void transaction_add_container(struct sway_transaction *transaction, | 151 | static void transaction_add_container(struct sway_transaction *transaction, |
156 | struct sway_container *container) { | 152 | struct sway_container *container) { |
157 | if (transaction_has_container(transaction, container)) { | ||
158 | return; | ||
159 | } | ||
160 | struct sway_transaction_instruction *instruction = | 153 | struct sway_transaction_instruction *instruction = |
161 | calloc(1, sizeof(struct sway_transaction_instruction)); | 154 | calloc(1, sizeof(struct sway_transaction_instruction)); |
162 | instruction->transaction = transaction; | 155 | instruction->transaction = transaction; |
@@ -174,7 +167,7 @@ void transaction_add_container(struct sway_transaction *transaction, | |||
174 | * Apply a transaction to the "current" state of the tree. | 167 | * Apply a transaction to the "current" state of the tree. |
175 | */ | 168 | */ |
176 | static void transaction_apply(struct sway_transaction *transaction) { | 169 | static void transaction_apply(struct sway_transaction *transaction) { |
177 | wlr_log(L_DEBUG, "Applying transaction %p", transaction); | 170 | wlr_log(WLR_DEBUG, "Applying transaction %p", transaction); |
178 | if (server.debug_txn_timings) { | 171 | if (server.debug_txn_timings) { |
179 | struct timespec now; | 172 | struct timespec now; |
180 | clock_gettime(CLOCK_MONOTONIC, &now); | 173 | clock_gettime(CLOCK_MONOTONIC, &now); |
@@ -185,9 +178,9 @@ static void transaction_apply(struct sway_transaction *transaction) { | |||
185 | float ms_waiting = (now.tv_sec - commit->tv_sec) * 1000 + | 178 | float ms_waiting = (now.tv_sec - commit->tv_sec) * 1000 + |
186 | (now.tv_nsec - commit->tv_nsec) / 1000000.0; | 179 | (now.tv_nsec - commit->tv_nsec) / 1000000.0; |
187 | float ms_total = ms_arranging + ms_waiting; | 180 | float ms_total = ms_arranging + ms_waiting; |
188 | wlr_log(L_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, " | 181 | wlr_log(WLR_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, " |
189 | "%.1fms total (%.1f frames if 60Hz)", transaction, | 182 | "%.1fms total (%.1f frames if 60Hz)", transaction, |
190 | ms_arranging, ms_waiting, ms_total, ms_total / (1000 / 60)); | 183 | ms_arranging, ms_waiting, ms_total, ms_total / (1000.0f / 60)); |
191 | } | 184 | } |
192 | 185 | ||
193 | // Apply the instruction state to the container's current state | 186 | // Apply the instruction state to the container's current state |
@@ -209,10 +202,12 @@ static void transaction_apply(struct sway_transaction *transaction) { | |||
209 | .width = instruction->state.swayc_width, | 202 | .width = instruction->state.swayc_width, |
210 | .height = instruction->state.swayc_height, | 203 | .height = instruction->state.swayc_height, |
211 | }; | 204 | }; |
212 | for (int j = 0; j < root_container.children->length; ++j) { | 205 | for (int j = 0; j < root_container.current.children->length; ++j) { |
213 | struct sway_container *output = root_container.children->items[j]; | 206 | struct sway_container *output = root_container.current.children->items[j]; |
214 | output_damage_box(output->sway_output, &old_box); | 207 | if (output->sway_output) { |
215 | output_damage_box(output->sway_output, &new_box); | 208 | output_damage_box(output->sway_output, &old_box); |
209 | output_damage_box(output->sway_output, &new_box); | ||
210 | } | ||
216 | } | 211 | } |
217 | 212 | ||
218 | // There are separate children lists for each instruction state, the | 213 | // There are separate children lists for each instruction state, the |
@@ -227,29 +222,22 @@ static void transaction_apply(struct sway_transaction *transaction) { | |||
227 | } | 222 | } |
228 | } | 223 | } |
229 | 224 | ||
230 | /** | ||
231 | * For simplicity, we only progress the queue if it can be completely flushed. | ||
232 | */ | ||
233 | static void transaction_progress_queue() { | 225 | static void transaction_progress_queue() { |
234 | // We iterate this list in reverse because we're more likely to find a | 226 | while (server.transactions->length) { |
235 | // waiting transactions at the end of the list. | 227 | struct sway_transaction *transaction = server.transactions->items[0]; |
236 | for (int i = server.transactions->length - 1; i >= 0; --i) { | ||
237 | struct sway_transaction *transaction = server.transactions->items[i]; | ||
238 | if (transaction->num_waiting) { | 228 | if (transaction->num_waiting) { |
239 | return; | 229 | return; |
240 | } | 230 | } |
241 | } | ||
242 | for (int i = 0; i < server.transactions->length; ++i) { | ||
243 | struct sway_transaction *transaction = server.transactions->items[i]; | ||
244 | transaction_apply(transaction); | 231 | transaction_apply(transaction); |
245 | transaction_destroy(transaction); | 232 | transaction_destroy(transaction); |
233 | list_del(server.transactions, 0); | ||
246 | } | 234 | } |
247 | server.transactions->length = 0; | 235 | idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); |
248 | } | 236 | } |
249 | 237 | ||
250 | static int handle_timeout(void *data) { | 238 | static int handle_timeout(void *data) { |
251 | struct sway_transaction *transaction = data; | 239 | struct sway_transaction *transaction = data; |
252 | wlr_log(L_DEBUG, "Transaction %p timed out (%li waiting)", | 240 | wlr_log(WLR_DEBUG, "Transaction %p timed out (%li waiting)", |
253 | transaction, transaction->num_waiting); | 241 | transaction, transaction->num_waiting); |
254 | transaction->num_waiting = 0; | 242 | transaction->num_waiting = 0; |
255 | transaction_progress_queue(); | 243 | transaction_progress_queue(); |
@@ -283,8 +271,8 @@ static bool should_configure(struct sway_container *con, | |||
283 | return true; | 271 | return true; |
284 | } | 272 | } |
285 | 273 | ||
286 | void transaction_commit(struct sway_transaction *transaction) { | 274 | static void transaction_commit(struct sway_transaction *transaction) { |
287 | wlr_log(L_DEBUG, "Transaction %p committing with %i instructions", | 275 | wlr_log(WLR_DEBUG, "Transaction %p committing with %i instructions", |
288 | transaction, transaction->instructions->length); | 276 | transaction, transaction->instructions->length); |
289 | transaction->num_waiting = 0; | 277 | transaction->num_waiting = 0; |
290 | for (int i = 0; i < transaction->instructions->length; ++i) { | 278 | for (int i = 0; i < transaction->instructions->length; ++i) { |
@@ -317,9 +305,10 @@ void transaction_commit(struct sway_transaction *transaction) { | |||
317 | } else { | 305 | } else { |
318 | // There are no other transactions in progress, and this one has nothing | 306 | // There are no other transactions in progress, and this one has nothing |
319 | // to wait for, so we can skip the queue. | 307 | // to wait for, so we can skip the queue. |
320 | wlr_log(L_DEBUG, "Transaction %p has nothing to wait for", transaction); | 308 | wlr_log(WLR_DEBUG, "Transaction %p has nothing to wait for", transaction); |
321 | transaction_apply(transaction); | 309 | transaction_apply(transaction); |
322 | transaction_destroy(transaction); | 310 | transaction_destroy(transaction); |
311 | idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); | ||
323 | return; | 312 | return; |
324 | } | 313 | } |
325 | 314 | ||
@@ -327,7 +316,7 @@ void transaction_commit(struct sway_transaction *transaction) { | |||
327 | // Set up a timer which the views must respond within | 316 | // Set up a timer which the views must respond within |
328 | transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, | 317 | transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, |
329 | handle_timeout, transaction); | 318 | handle_timeout, transaction); |
330 | wl_event_source_timer_update(transaction->timer, TIMEOUT_MS); | 319 | wl_event_source_timer_update(transaction->timer, txn_timeout_ms); |
331 | } | 320 | } |
332 | 321 | ||
333 | // The debug tree shows the pending/live tree. Here is a good place to | 322 | // The debug tree shows the pending/live tree. Here is a good place to |
@@ -347,7 +336,7 @@ static void set_instruction_ready( | |||
347 | struct timespec *start = &transaction->commit_time; | 336 | struct timespec *start = &transaction->commit_time; |
348 | float ms = (now.tv_sec - start->tv_sec) * 1000 + | 337 | float ms = (now.tv_sec - start->tv_sec) * 1000 + |
349 | (now.tv_nsec - start->tv_nsec) / 1000000.0; | 338 | (now.tv_nsec - start->tv_nsec) / 1000000.0; |
350 | wlr_log(L_DEBUG, "Transaction %p: %li/%li ready in %.1fms (%s)", | 339 | wlr_log(WLR_DEBUG, "Transaction %p: %li/%li ready in %.1fms (%s)", |
351 | transaction, | 340 | transaction, |
352 | transaction->num_configures - transaction->num_waiting + 1, | 341 | transaction->num_configures - transaction->num_waiting + 1, |
353 | transaction->num_configures, ms, | 342 | transaction->num_configures, ms, |
@@ -358,11 +347,11 @@ static void set_instruction_ready( | |||
358 | // If all views are ready, apply the transaction. | 347 | // If all views are ready, apply the transaction. |
359 | // If the transaction has timed out then its num_waiting will be 0 already. | 348 | // If the transaction has timed out then its num_waiting will be 0 already. |
360 | if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { | 349 | if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { |
361 | #if !TRANSACTION_DEBUG | 350 | if (!txn_debug) { |
362 | wlr_log(L_DEBUG, "Transaction %p is ready", transaction); | 351 | wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction); |
363 | wl_event_source_timer_update(transaction->timer, 0); | 352 | wl_event_source_timer_update(transaction->timer, 0); |
364 | transaction_progress_queue(); | 353 | transaction_progress_queue(); |
365 | #endif | 354 | } |
366 | } | 355 | } |
367 | } | 356 | } |
368 | 357 | ||
@@ -374,7 +363,9 @@ static void set_instructions_ready(struct sway_view *view, int index) { | |||
374 | for (int i = 0; i <= index; ++i) { | 363 | for (int i = 0; i <= index; ++i) { |
375 | struct sway_transaction_instruction *instruction = | 364 | struct sway_transaction_instruction *instruction = |
376 | view->swayc->instructions->items[i]; | 365 | view->swayc->instructions->items[i]; |
377 | set_instruction_ready(instruction); | 366 | if (!instruction->ready) { |
367 | set_instruction_ready(instruction); | ||
368 | } | ||
378 | } | 369 | } |
379 | } | 370 | } |
380 | 371 | ||
@@ -413,3 +404,17 @@ struct wlr_texture *transaction_get_saved_texture(struct sway_view *view, | |||
413 | *height = instruction->saved_buffer_height; | 404 | *height = instruction->saved_buffer_height; |
414 | return instruction->saved_buffer->texture; | 405 | return instruction->saved_buffer->texture; |
415 | } | 406 | } |
407 | |||
408 | void transaction_commit_dirty(void) { | ||
409 | if (!server.dirty_containers->length) { | ||
410 | return; | ||
411 | } | ||
412 | struct sway_transaction *transaction = transaction_create(); | ||
413 | for (int i = 0; i < server.dirty_containers->length; ++i) { | ||
414 | struct sway_container *container = server.dirty_containers->items[i]; | ||
415 | transaction_add_container(transaction, container); | ||
416 | container->dirty = false; | ||
417 | } | ||
418 | server.dirty_containers->length = 0; | ||
419 | transaction_commit(transaction); | ||
420 | } | ||