aboutsummaryrefslogtreecommitdiffstats
path: root/sway/desktop/output.c
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-08-30 21:00:10 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-09-05 18:01:43 +1000
commit7586f150c058997d9dde387ea7c091ffa7a3c3c7 (patch)
tree63d19027974c1db62ce3a74ca1d2314eb6d5049b /sway/desktop/output.c
parentMerge pull request #2569 from RyanDwyer/deny-reload-repeat (diff)
downloadsway-7586f150c058997d9dde387ea7c091ffa7a3c3c7.tar.gz
sway-7586f150c058997d9dde387ea7c091ffa7a3c3c7.tar.zst
sway-7586f150c058997d9dde387ea7c091ffa7a3c3c7.zip
Implement type safe arguments and demote sway_container
This commit changes the meaning of sway_container so that it only refers to layout containers and view containers. Workspaces, outputs and the root are no longer known as containers. Instead, root, outputs, workspaces and containers are all a type of node, and containers come in two types: layout containers and view containers. In addition to the above, this implements type safe variables. This means we use specific types such as sway_output and sway_workspace instead of generic containers or nodes. However, it's worth noting that in a few places places (eg. seat focus and transactions) referring to them in a generic way is unavoidable which is why we still use nodes in some places. If you want a TL;DR, look at node.h, as well as the struct definitions for root, output, workspace and container. Note that sway_output now contains a workspaces list, and workspaces now contain a tiling and floating list, and containers now contain a pointer back to the workspace. There are now functions for seat_get_focused_workspace and seat_get_focused_container. The latter will return NULL if a workspace itself is focused. Most other seat functions like seat_get_focus and seat_set_focus now accept and return nodes. In the config->handler_context struct, current_container has been replaced with three pointers: node, container and workspace. node is the same as what current_container was, while workspace is the workspace that the node resides on and container is the actual container, which may be NULL if a workspace itself is focused. The global root_container variable has been replaced with one simply called root, which is a pointer to the sway_root instance. The way outputs are created, enabled, disabled and destroyed has changed. Previously we'd wrap the sway_output in a container when it is enabled, but as we don't have containers any more it needs a different approach. The output_create and output_destroy functions previously created/destroyed the container, but now they create/destroy the sway_output. There is a new function output_disable to disable an output without destroying it. Containers have a new view property. If this is populated then the container is a view container, otherwise it's a layout container. Like before, this property is immutable for the life of the container. Containers have both a `sway_container *parent` and `sway_workspace *workspace`. As we use specific types now, parent cannot point to a workspace so it'll be NULL for containers which are direct children of the workspace. The workspace property is set for all containers, except those which are hidden in the scratchpad as they have no workspace. In some cases we need to refer to workspaces in a container-like way. For example, workspaces have layout and children, but when using specific types this makes it difficult. Likewise, it's difficult for a container to get its parent's layout when the parent could be another container or a workspace. To make it easier, some helper functions have been created: container_parent_layout and container_get_siblings. container_remove_child has been renamed to container_detach and container_replace_child has been renamed to container_replace. `container_handle_fullscreen_reparent(con, old_parent)` has had the old_parent removed. We now unfullscreen the workspace when detaching the container, so this function is simplified and only needs one argument now. container_notify_subtree_changed has been renamed to container_update_representation. This is more descriptive of its purpose. I also wanted to be able to call it with whatever container was changed rather than the container's parent, which makes bubbling up to the workspace easier. There are now state structs per node thing. ie. sway_output_state, sway_workspace_state and sway_container_state. The focus, move and layout commands have been completely refactored to work with the specific types. I considered making these a separate PR, but I'd be backporting my changes only to replace them again, and it's easier just to test everything at once.
Diffstat (limited to 'sway/desktop/output.c')
-rw-r--r--sway/desktop/output.c182
1 files changed, 72 insertions, 110 deletions
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index c30e52a1..c182bad6 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -28,10 +28,10 @@
28#include "sway/tree/view.h" 28#include "sway/tree/view.h"
29#include "sway/tree/workspace.h" 29#include "sway/tree/workspace.h"
30 30
31struct sway_container *output_by_name(const char *name) { 31struct sway_output *output_by_name(const char *name) {
32 for (int i = 0; i < root_container.children->length; ++i) { 32 for (int i = 0; i < root->outputs->length; ++i) {
33 struct sway_container *output = root_container.children->items[i]; 33 struct sway_output *output = root->outputs->items[i];
34 if (strcasecmp(output->name, name) == 0) { 34 if (strcasecmp(output->wlr_output->name, name) == 0) {
35 return output; 35 return output;
36 } 36 }
37 } 37 }
@@ -98,8 +98,8 @@ static bool get_surface_box(struct surface_iterator_data *data,
98 wlr_box_rotated_bounds(&box, data->rotation, &rotated_box); 98 wlr_box_rotated_bounds(&box, data->rotation, &rotated_box);
99 99
100 struct wlr_box output_box = { 100 struct wlr_box output_box = {
101 .width = output->swayc->current.swayc_width, 101 .width = output->wlr_output->width,
102 .height = output->swayc->current.swayc_height, 102 .height = output->wlr_output->height,
103 }; 103 };
104 104
105 struct wlr_box intersection; 105 struct wlr_box intersection;
@@ -145,12 +145,12 @@ void output_view_for_each_surface(struct sway_output *output,
145 .user_iterator = iterator, 145 .user_iterator = iterator,
146 .user_data = user_data, 146 .user_data = user_data,
147 .output = output, 147 .output = output,
148 .ox = view->swayc->current.view_x - output->swayc->current.swayc_x 148 .ox = view->container->current.view_x - output->wlr_output->lx
149 - view->geometry.x, 149 - view->geometry.x,
150 .oy = view->swayc->current.view_y - output->swayc->current.swayc_y 150 .oy = view->container->current.view_y - output->wlr_output->ly
151 - view->geometry.y, 151 - view->geometry.y,
152 .width = view->swayc->current.view_width, 152 .width = view->container->current.view_width,
153 .height = view->swayc->current.view_height, 153 .height = view->container->current.view_height,
154 .rotation = 0, // TODO 154 .rotation = 0, // TODO
155 }; 155 };
156 156
@@ -164,12 +164,12 @@ void output_view_for_each_popup(struct sway_output *output,
164 .user_iterator = iterator, 164 .user_iterator = iterator,
165 .user_data = user_data, 165 .user_data = user_data,
166 .output = output, 166 .output = output,
167 .ox = view->swayc->current.view_x - output->swayc->current.swayc_x 167 .ox = view->container->current.view_x - output->wlr_output->lx
168 - view->geometry.x, 168 - view->geometry.x,
169 .oy = view->swayc->current.view_y - output->swayc->current.swayc_y 169 .oy = view->container->current.view_y - output->wlr_output->ly
170 - view->geometry.y, 170 - view->geometry.y,
171 .width = view->swayc->current.view_width, 171 .width = view->container->current.view_width,
172 .height = view->swayc->current.view_height, 172 .height = view->container->current.view_height,
173 .rotation = 0, // TODO 173 .rotation = 0, // TODO
174 }; 174 };
175 175
@@ -197,8 +197,8 @@ void output_unmanaged_for_each_surface(struct sway_output *output,
197 wl_list_for_each(unmanaged_surface, unmanaged, link) { 197 wl_list_for_each(unmanaged_surface, unmanaged, link) {
198 struct wlr_xwayland_surface *xsurface = 198 struct wlr_xwayland_surface *xsurface =
199 unmanaged_surface->wlr_xwayland_surface; 199 unmanaged_surface->wlr_xwayland_surface;
200 double ox = unmanaged_surface->lx - output->swayc->current.swayc_x; 200 double ox = unmanaged_surface->lx - output->wlr_output->lx;
201 double oy = unmanaged_surface->ly - output->swayc->current.swayc_y; 201 double oy = unmanaged_surface->ly - output->wlr_output->ly;
202 202
203 output_surface_for_each_surface(output, xsurface->surface, ox, oy, 203 output_surface_for_each_surface(output, xsurface->surface, ox, oy,
204 iterator, user_data); 204 iterator, user_data);
@@ -211,8 +211,8 @@ void output_drag_icons_for_each_surface(struct sway_output *output,
211 void *user_data) { 211 void *user_data) {
212 struct sway_drag_icon *drag_icon; 212 struct sway_drag_icon *drag_icon;
213 wl_list_for_each(drag_icon, drag_icons, link) { 213 wl_list_for_each(drag_icon, drag_icons, link) {
214 double ox = drag_icon->x - output->swayc->x; 214 double ox = drag_icon->x - output->wlr_output->lx;
215 double oy = drag_icon->y - output->swayc->y; 215 double oy = drag_icon->y - output->wlr_output->ly;
216 216
217 if (drag_icon->wlr_drag_icon->mapped) { 217 if (drag_icon->wlr_drag_icon->mapped) {
218 output_surface_for_each_surface(output, 218 output_surface_for_each_surface(output,
@@ -229,19 +229,13 @@ static void scale_box(struct wlr_box *box, float scale) {
229 box->height *= scale; 229 box->height *= scale;
230} 230}
231 231
232struct sway_container *output_get_active_workspace(struct sway_output *output) { 232struct sway_workspace *output_get_active_workspace(struct sway_output *output) {
233 struct sway_seat *seat = input_manager_current_seat(input_manager); 233 struct sway_seat *seat = input_manager_current_seat(input_manager);
234 struct sway_container *focus = 234 struct sway_node *focus = seat_get_active_child(seat, &output->node);
235 seat_get_focus_inactive(seat, output->swayc);
236 if (!focus) { 235 if (!focus) {
237 // We've never been to this output before 236 return output->workspaces->items[0];
238 focus = output->swayc->current.children->items[0];
239 } 237 }
240 struct sway_container *workspace = focus; 238 return focus->sway_workspace;
241 if (workspace->type != C_WORKSPACE) {
242 workspace = container_parent(workspace, C_WORKSPACE);
243 }
244 return workspace;
245} 239}
246 240
247bool output_has_opaque_overlay_layer_surface(struct sway_output *output) { 241bool output_has_opaque_overlay_layer_surface(struct sway_output *output) {
@@ -255,8 +249,8 @@ bool output_has_opaque_overlay_layer_surface(struct sway_output *output) {
255 struct sway_layer_surface *sway_layer_surface = 249 struct sway_layer_surface *sway_layer_surface =
256 layer_from_wlr_layer_surface(wlr_layer_surface); 250 layer_from_wlr_layer_surface(wlr_layer_surface);
257 pixman_box32_t output_box = { 251 pixman_box32_t output_box = {
258 .x2 = output->swayc->current.swayc_width, 252 .x2 = output->wlr_output->width,
259 .y2 = output->swayc->current.swayc_height, 253 .y2 = output->wlr_output->height,
260 }; 254 };
261 pixman_region32_t surface_opaque_box; 255 pixman_region32_t surface_opaque_box;
262 pixman_region32_init(&surface_opaque_box); 256 pixman_region32_init(&surface_opaque_box);
@@ -307,15 +301,15 @@ struct send_frame_done_data {
307 301
308static void send_frame_done_container_iterator(struct sway_container *con, 302static void send_frame_done_container_iterator(struct sway_container *con,
309 void *_data) { 303 void *_data) {
310 if (con->type != C_VIEW) { 304 if (!con->view) {
311 return; 305 return;
312 } 306 }
313 if (!view_is_visible(con->sway_view)) { 307 if (!view_is_visible(con->view)) {
314 return; 308 return;
315 } 309 }
316 310
317 struct send_frame_done_data *data = _data; 311 struct send_frame_done_data *data = _data;
318 output_view_for_each_surface(data->output, con->sway_view, 312 output_view_for_each_surface(data->output, con->view,
319 send_frame_done_iterator, data->when); 313 send_frame_done_iterator, data->when);
320} 314}
321 315
@@ -328,15 +322,14 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) {
328 .output = output, 322 .output = output,
329 .when = when, 323 .when = when,
330 }; 324 };
331 struct sway_container *workspace = output_get_active_workspace(output); 325 struct sway_workspace *workspace = output_get_active_workspace(output);
332 if (workspace->current.ws_fullscreen) { 326 if (workspace->current.fullscreen) {
333 send_frame_done_container_iterator( 327 send_frame_done_container_iterator(
334 workspace->current.ws_fullscreen, &data); 328 workspace->current.fullscreen, &data);
335 container_for_each_child(workspace->current.ws_fullscreen, 329 container_for_each_child(workspace->current.fullscreen,
336 send_frame_done_container_iterator, &data); 330 send_frame_done_container_iterator, &data);
337#ifdef HAVE_XWAYLAND 331#ifdef HAVE_XWAYLAND
338 send_frame_done_unmanaged(output, 332 send_frame_done_unmanaged(output, &root->xwayland_unmanaged, when);
339 &root_container.sway_root->xwayland_unmanaged, when);
340#endif 333#endif
341 } else { 334 } else {
342 send_frame_done_layer(output, 335 send_frame_done_layer(output,
@@ -348,8 +341,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) {
348 send_frame_done_container_iterator, &data); 341 send_frame_done_container_iterator, &data);
349 342
350#ifdef HAVE_XWAYLAND 343#ifdef HAVE_XWAYLAND
351 send_frame_done_unmanaged(output, 344 send_frame_done_unmanaged(output, &root->xwayland_unmanaged, when);
352 &root_container.sway_root->xwayland_unmanaged, when);
353#endif 345#endif
354 send_frame_done_layer(output, 346 send_frame_done_layer(output,
355 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], when); 347 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], when);
@@ -358,8 +350,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) {
358send_frame_overlay: 350send_frame_overlay:
359 send_frame_done_layer(output, 351 send_frame_done_layer(output,
360 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], when); 352 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], when);
361 send_frame_done_drag_icons(output, &root_container.sway_root->drag_icons, 353 send_frame_done_drag_icons(output, &root->drag_icons, when);
362 when);
363} 354}
364 355
365static void damage_handle_frame(struct wl_listener *listener, void *data) { 356static void damage_handle_frame(struct wl_listener *listener, void *data) {
@@ -391,7 +382,11 @@ static void damage_handle_frame(struct wl_listener *listener, void *data) {
391} 382}
392 383
393void output_damage_whole(struct sway_output *output) { 384void output_damage_whole(struct sway_output *output) {
394 wlr_output_damage_add_whole(output->damage); 385 // The output can exist with no wlr_output if it's just been disconnected
386 // and the transaction to evacuate it has't completed yet.
387 if (output && output->wlr_output) {
388 wlr_output_damage_add_whole(output->damage);
389 }
395} 390}
396 391
397static void damage_surface_iterator(struct sway_output *output, 392static void damage_surface_iterator(struct sway_output *output,
@@ -446,14 +441,9 @@ void output_damage_surface(struct sway_output *output, double ox, double oy,
446 441
447static void output_damage_view(struct sway_output *output, 442static void output_damage_view(struct sway_output *output,
448 struct sway_view *view, bool whole) { 443 struct sway_view *view, bool whole) {
449 if (!sway_assert(view->swayc != NULL, "expected a view in the tree")) {
450 return;
451 }
452
453 if (!view_is_visible(view)) { 444 if (!view_is_visible(view)) {
454 return; 445 return;
455 } 446 }
456
457 output_view_for_each_surface(output, view, damage_surface_iterator, &whole); 447 output_view_for_each_surface(output, view, damage_surface_iterator, &whole);
458} 448}
459 449
@@ -466,31 +456,29 @@ void output_damage_from_view(struct sway_output *output,
466void output_damage_box(struct sway_output *output, struct wlr_box *_box) { 456void output_damage_box(struct sway_output *output, struct wlr_box *_box) {
467 struct wlr_box box; 457 struct wlr_box box;
468 memcpy(&box, _box, sizeof(struct wlr_box)); 458 memcpy(&box, _box, sizeof(struct wlr_box));
469 box.x -= output->swayc->current.swayc_x; 459 box.x -= output->wlr_output->lx;
470 box.y -= output->swayc->current.swayc_y; 460 box.y -= output->wlr_output->ly;
471 scale_box(&box, output->wlr_output->scale); 461 scale_box(&box, output->wlr_output->scale);
472 wlr_output_damage_add_box(output->damage, &box); 462 wlr_output_damage_add_box(output->damage, &box);
473} 463}
474 464
475static void output_damage_whole_container_iterator(struct sway_container *con, 465static void output_damage_whole_container_iterator(struct sway_container *con,
476 void *data) { 466 void *data) {
477 struct sway_output *output = data; 467 if (!sway_assert(con->view, "expected a view")) {
478
479 if (!sway_assert(con->type == C_VIEW, "expected a view")) {
480 return; 468 return;
481 } 469 }
482 470 struct sway_output *output = data;
483 output_damage_view(output, con->sway_view, true); 471 output_damage_view(output, con->view, true);
484} 472}
485 473
486void output_damage_whole_container(struct sway_output *output, 474void output_damage_whole_container(struct sway_output *output,
487 struct sway_container *con) { 475 struct sway_container *con) {
488 // Pad the box by 1px, because the width is a double and might be a fraction 476 // Pad the box by 1px, because the width is a double and might be a fraction
489 struct wlr_box box = { 477 struct wlr_box box = {
490 .x = con->current.swayc_x - output->wlr_output->lx - 1, 478 .x = con->current.con_x - output->wlr_output->lx - 1,
491 .y = con->current.swayc_y - output->wlr_output->ly - 1, 479 .y = con->current.con_y - output->wlr_output->ly - 1,
492 .width = con->current.swayc_width + 2, 480 .width = con->current.con_width + 2,
493 .height = con->current.swayc_height + 2, 481 .height = con->current.con_height + 2,
494 }; 482 };
495 scale_box(&box, output->wlr_output->scale); 483 scale_box(&box, output->wlr_output->scale);
496 wlr_output_damage_add_box(output->damage, &box); 484 wlr_output_damage_add_box(output->damage, &box);
@@ -499,44 +487,48 @@ void output_damage_whole_container(struct sway_output *output,
499static void damage_handle_destroy(struct wl_listener *listener, void *data) { 487static void damage_handle_destroy(struct wl_listener *listener, void *data) {
500 struct sway_output *output = 488 struct sway_output *output =
501 wl_container_of(listener, output, damage_destroy); 489 wl_container_of(listener, output, damage_destroy);
502 output_begin_destroy(output->swayc); 490 output_disable(output);
491 transaction_commit_dirty();
503} 492}
504 493
505static void handle_destroy(struct wl_listener *listener, void *data) { 494static void handle_destroy(struct wl_listener *listener, void *data) {
506 struct sway_output *output = wl_container_of(listener, output, destroy); 495 struct sway_output *output = wl_container_of(listener, output, destroy);
507 wl_signal_emit(&output->events.destroy, output); 496 wl_signal_emit(&output->events.destroy, output);
508 497
509 if (output->swayc) { 498 if (output->enabled) {
510 output_begin_destroy(output->swayc); 499 output_disable(output);
511 } 500 }
501 output_begin_destroy(output);
512 502
513 wl_list_remove(&output->link); 503 transaction_commit_dirty();
514 wl_list_remove(&output->destroy.link);
515 output->wlr_output->data = NULL;
516 free(output);
517
518 arrange_windows(&root_container);
519} 504}
520 505
521static void handle_mode(struct wl_listener *listener, void *data) { 506static void handle_mode(struct wl_listener *listener, void *data) {
522 struct sway_output *output = wl_container_of(listener, output, mode); 507 struct sway_output *output = wl_container_of(listener, output, mode);
523 arrange_layers(output); 508 arrange_layers(output);
524 arrange_windows(output->swayc); 509 arrange_output(output);
525 transaction_commit_dirty(); 510 transaction_commit_dirty();
526} 511}
527 512
528static void handle_transform(struct wl_listener *listener, void *data) { 513static void handle_transform(struct wl_listener *listener, void *data) {
529 struct sway_output *output = wl_container_of(listener, output, transform); 514 struct sway_output *output = wl_container_of(listener, output, transform);
530 arrange_layers(output); 515 arrange_layers(output);
531 arrange_windows(output->swayc); 516 arrange_output(output);
532 transaction_commit_dirty(); 517 transaction_commit_dirty();
533} 518}
534 519
520static void update_textures(struct sway_container *con, void *data) {
521 container_update_title_textures(con);
522 if (con->view) {
523 view_update_marks_textures(con->view);
524 }
525}
526
535static void handle_scale(struct wl_listener *listener, void *data) { 527static void handle_scale(struct wl_listener *listener, void *data) {
536 struct sway_output *output = wl_container_of(listener, output, scale); 528 struct sway_output *output = wl_container_of(listener, output, scale);
537 arrange_layers(output); 529 arrange_layers(output);
538 container_update_textures_recursive(output->swayc); 530 output_for_each_container(output, update_textures, NULL);
539 arrange_windows(output->swayc); 531 arrange_output(output);
540 transaction_commit_dirty(); 532 transaction_commit_dirty();
541} 533}
542 534
@@ -545,57 +537,27 @@ void handle_new_output(struct wl_listener *listener, void *data) {
545 struct wlr_output *wlr_output = data; 537 struct wlr_output *wlr_output = data;
546 wlr_log(WLR_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); 538 wlr_log(WLR_DEBUG, "New output %p: %s", wlr_output, wlr_output->name);
547 539
548 struct sway_output *output = calloc(1, sizeof(struct sway_output)); 540 struct sway_output *output = output_create(wlr_output);
549 if (!output) { 541 if (!output) {
550 return; 542 return;
551 } 543 }
552 output->wlr_output = wlr_output;
553 wlr_output->data = output;
554 output->server = server; 544 output->server = server;
555 output->damage = wlr_output_damage_create(wlr_output); 545 output->damage = wlr_output_damage_create(wlr_output);
556
557 wl_signal_add(&wlr_output->events.destroy, &output->destroy);
558 output->destroy.notify = handle_destroy; 546 output->destroy.notify = handle_destroy;
559 547
560 wl_list_insert(&root_container.sway_root->all_outputs, &output->link); 548 struct output_config *oc = output_find_config(output);
561
562 output_enable(output);
563}
564
565void output_enable(struct sway_output *output) {
566 struct wlr_output *wlr_output = output->wlr_output;
567
568 if (!sway_assert(output->swayc == NULL, "output is already enabled")) {
569 return;
570 }
571
572 output->swayc = output_create(output);
573 if (!output->swayc) {
574 // Output is disabled
575 return;
576 }
577 549
578 size_t len = sizeof(output->layers) / sizeof(output->layers[0]); 550 if (oc && oc->enabled) {
579 for (size_t i = 0; i < len; ++i) { 551 output_enable(output, oc);
580 wl_list_init(&output->layers[i]);
581 } 552 }
582 wl_signal_init(&output->events.destroy);
583 553
584 input_manager_configure_xcursor(input_manager); 554 transaction_commit_dirty();
555}
585 556
586 wl_signal_add(&wlr_output->events.mode, &output->mode); 557void output_add_listeners(struct sway_output *output) {
587 output->mode.notify = handle_mode; 558 output->mode.notify = handle_mode;
588 wl_signal_add(&wlr_output->events.transform, &output->transform);
589 output->transform.notify = handle_transform; 559 output->transform.notify = handle_transform;
590 wl_signal_add(&wlr_output->events.scale, &output->scale);
591 output->scale.notify = handle_scale; 560 output->scale.notify = handle_scale;
592
593 wl_signal_add(&output->damage->events.frame, &output->damage_frame);
594 output->damage_frame.notify = damage_handle_frame; 561 output->damage_frame.notify = damage_handle_frame;
595 wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
596 output->damage_destroy.notify = damage_handle_destroy; 562 output->damage_destroy.notify = damage_handle_destroy;
597
598 arrange_layers(output);
599 arrange_windows(&root_container);
600 transaction_commit_dirty();
601} 563}