aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/layout.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree/layout.c')
-rw-r--r--sway/tree/layout.c285
1 files changed, 276 insertions, 9 deletions
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index 41ff81b2..3d04a1a7 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -10,6 +10,7 @@
10#include "sway/layout.h" 10#include "sway/layout.h"
11#include "sway/output.h" 11#include "sway/output.h"
12#include "sway/view.h" 12#include "sway/view.h"
13#include "sway/input/seat.h"
13#include "list.h" 14#include "list.h"
14#include "log.h" 15#include "log.h"
15 16
@@ -48,10 +49,12 @@ void init_layout(void) {
48 root_container.layout = L_NONE; 49 root_container.layout = L_NONE;
49 root_container.name = strdup("root"); 50 root_container.name = strdup("root");
50 root_container.children = create_list(); 51 root_container.children = create_list();
52 wl_signal_init(&root_container.events.destroy);
51 53
52 root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); 54 root_container.sway_root = calloc(1, sizeof(*root_container.sway_root));
53 root_container.sway_root->output_layout = wlr_output_layout_create(); 55 root_container.sway_root->output_layout = wlr_output_layout_create();
54 wl_list_init(&root_container.sway_root->unmanaged_views); 56 wl_list_init(&root_container.sway_root->unmanaged_views);
57 wl_signal_init(&root_container.sway_root->events.new_container);
55 58
56 root_container.sway_root->output_layout_change.notify = 59 root_container.sway_root->output_layout_change.notify =
57 output_layout_change_notify; 60 output_layout_change_notify;
@@ -59,6 +62,32 @@ void init_layout(void) {
59 &root_container.sway_root->output_layout_change); 62 &root_container.sway_root->output_layout_change);
60} 63}
61 64
65static int index_child(const swayc_t *child) {
66 // TODO handle floating
67 swayc_t *parent = child->parent;
68 int i, len;
69 len = parent->children->length;
70 for (i = 0; i < len; ++i) {
71 if (parent->children->items[i] == child) {
72 break;
73 }
74 }
75
76 if (!sway_assert(i < len, "Stray container")) {
77 return -1;
78 }
79 return i;
80}
81
82swayc_t *add_sibling(swayc_t *fixed, swayc_t *active) {
83 // TODO handle floating
84 swayc_t *parent = fixed->parent;
85 int i = index_child(fixed);
86 list_insert(parent->children, i + 1, active);
87 active->parent = parent;
88 return active->parent;
89}
90
62void add_child(swayc_t *parent, swayc_t *child) { 91void add_child(swayc_t *parent, swayc_t *child) {
63 wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", 92 wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)",
64 child, child->type, child->width, child->height, 93 child, child->type, child->width, child->height,
@@ -66,9 +95,6 @@ void add_child(swayc_t *parent, swayc_t *child) {
66 list_add(parent->children, child); 95 list_add(parent->children, child);
67 child->parent = parent; 96 child->parent = parent;
68 // set focus for this container 97 // set focus for this container
69 if (!parent->focused) {
70 parent->focused = child;
71 }
72 /* TODO WLR 98 /* TODO WLR
73 if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) { 99 if (parent->type == C_WORKSPACE && child->type == C_VIEW && (parent->workspace_layout == L_TABBED || parent->workspace_layout == L_STACKED)) {
74 child = new_container(child, parent->workspace_layout); 100 child = new_container(child, parent->workspace_layout);
@@ -147,8 +173,8 @@ void arrange_windows(swayc_t *container, double width, double height) {
147 height = floor(height); 173 height = floor(height);
148 174
149 wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", container, 175 wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", container,
150 container->name, container->width, container->height, container->x, 176 container->name, container->width, container->height, container->x,
151 container->y); 177 container->y);
152 178
153 double x = 0, y = 0; 179 double x = 0, y = 0;
154 switch (container->type) { 180 switch (container->type) {
@@ -249,8 +275,8 @@ static void apply_horiz_layout(swayc_t *container,
249 for (int i = start; i < end; ++i) { 275 for (int i = start; i < end; ++i) {
250 swayc_t *child = container->children->items[i]; 276 swayc_t *child = container->children->items[i];
251 wlr_log(L_DEBUG, 277 wlr_log(L_DEBUG,
252 "Calculating arrangement for %p:%d (will scale %f by %f)", 278 "Calculating arrangement for %p:%d (will scale %f by %f)",
253 child, child->type, width, scale); 279 child, child->type, width, scale);
254 view_set_position(child->sway_view, child_x, y); 280 view_set_position(child->sway_view, child_x, y);
255 281
256 if (i == end - 1) { 282 if (i == end - 1) {
@@ -299,8 +325,8 @@ void apply_vert_layout(swayc_t *container,
299 for (i = start; i < end; ++i) { 325 for (i = start; i < end; ++i) {
300 swayc_t *child = container->children->items[i]; 326 swayc_t *child = container->children->items[i];
301 wlr_log(L_DEBUG, 327 wlr_log(L_DEBUG,
302 "Calculating arrangement for %p:%d (will scale %f by %f)", 328 "Calculating arrangement for %p:%d (will scale %f by %f)",
303 child, child->type, height, scale); 329 child, child->type, height, scale);
304 view_set_position(child->sway_view, x, child_y); 330 view_set_position(child->sway_view, x, child_y);
305 331
306 if (i == end - 1) { 332 if (i == end - 1) {
@@ -321,3 +347,244 @@ void apply_vert_layout(swayc_t *container,
321 */ 347 */
322 } 348 }
323} 349}
350
351/**
352 * Get swayc in the direction of newly entered output.
353 */
354static swayc_t *get_swayc_in_output_direction(swayc_t *output,
355 enum movement_direction dir, struct sway_seat *seat) {
356 if (!output) {
357 return NULL;
358 }
359
360 swayc_t *ws = sway_seat_get_focus_inactive(seat, output);
361 if (ws->type != C_WORKSPACE) {
362 ws = swayc_parent_by_type(ws, C_WORKSPACE);
363 }
364
365 if (ws == NULL) {
366 wlr_log(L_ERROR, "got an output without a workspace");
367 return NULL;
368 }
369
370 if (ws->children->length > 0) {
371 switch (dir) {
372 case MOVE_LEFT:
373 // get most right child of new output
374 return ws->children->items[ws->children->length-1];
375 case MOVE_RIGHT:
376 // get most left child of new output
377 return ws->children->items[0];
378 case MOVE_UP:
379 case MOVE_DOWN: {
380 swayc_t *focused = sway_seat_get_focus_inactive(seat, ws);
381 if (focused && focused->parent) {
382 swayc_t *parent = focused->parent;
383 if (parent->layout == L_VERT) {
384 if (dir == MOVE_UP) {
385 // get child furthest down on new output
386 return parent->children->items[parent->children->length-1];
387 } else if (dir == MOVE_DOWN) {
388 // get child furthest up on new output
389 return parent->children->items[0];
390 }
391 }
392 return focused;
393 }
394 break;
395 }
396 default:
397 break;
398 }
399 }
400
401 return ws;
402}
403
404static void get_layout_center_position(swayc_t *container, int *x, int *y) {
405 // FIXME view coords are inconsistently referred to in layout/output systems
406 if (container->type == C_OUTPUT) {
407 *x = container->x + container->width/2;
408 *y = container->y + container->height/2;
409 } else {
410 swayc_t *output = swayc_parent_by_type(container, C_OUTPUT);
411 if (container->type == C_WORKSPACE) {
412 // Workspace coordinates are actually wrong/arbitrary, but should
413 // be same as output.
414 *x = output->x;
415 *y = output->y;
416 } else {
417 *x = output->x + container->x;
418 *y = output->y + container->y;
419 }
420 }
421}
422
423static bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out) {
424 switch (dir) {
425 case MOVE_UP:
426 *out = WLR_DIRECTION_UP;
427 break;
428 case MOVE_DOWN:
429 *out = WLR_DIRECTION_DOWN;
430 break;
431 case MOVE_LEFT:
432 *out = WLR_DIRECTION_LEFT;
433 break;
434 case MOVE_RIGHT:
435 *out = WLR_DIRECTION_RIGHT;
436 break;
437 default:
438 return false;
439 }
440
441 return true;
442}
443
444static swayc_t *sway_output_from_wlr(struct wlr_output *output) {
445 if (output == NULL) {
446 return NULL;
447 }
448 for (int i = 0; i < root_container.children->length; ++i) {
449 swayc_t *o = root_container.children->items[i];
450 if (o->type == C_OUTPUT && o->sway_output->wlr_output == output) {
451 return o;
452 }
453 }
454 return NULL;
455}
456
457static swayc_t *get_swayc_in_direction_under(swayc_t *container,
458 enum movement_direction dir, struct sway_seat *seat, swayc_t *limit) {
459 if (dir == MOVE_CHILD) {
460 return sway_seat_get_focus_inactive(seat, container);
461 }
462
463 swayc_t *parent = container->parent;
464 if (dir == MOVE_PARENT) {
465 if (parent->type == C_OUTPUT) {
466 return NULL;
467 } else {
468 return parent;
469 }
470 }
471
472 if (dir == MOVE_PREV || dir == MOVE_NEXT) {
473 int focused_idx = index_child(container);
474 if (focused_idx == -1) {
475 return NULL;
476 } else {
477 int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) %
478 parent->children->length;
479 if (desired < 0) {
480 desired += parent->children->length;
481 }
482 return parent->children->items[desired];
483 }
484 }
485
486 // If moving to an adjacent output we need a starting position (since this
487 // output might border to multiple outputs).
488 //struct wlc_point abs_pos;
489 //get_layout_center_position(container, &abs_pos);
490
491
492 // TODO WLR fullscreen
493 /*
494 if (container->type == C_VIEW && swayc_is_fullscreen(container)) {
495 wlr_log(L_DEBUG, "Moving from fullscreen view, skipping to output");
496 container = swayc_parent_by_type(container, C_OUTPUT);
497 get_layout_center_position(container, &abs_pos);
498 swayc_t *output = swayc_adjacent_output(container, dir, &abs_pos, true);
499 return get_swayc_in_output_direction(output, dir);
500 }
501 if (container->type == C_WORKSPACE && container->fullscreen) {
502 sway_log(L_DEBUG, "Moving to fullscreen view");
503 return container->fullscreen;
504 }
505 */
506
507 swayc_t *wrap_candidate = NULL;
508 while (true) {
509 // Test if we can even make a difference here
510 bool can_move = false;
511 int desired;
512 int idx = index_child(container);
513 if (parent->type == C_ROOT) {
514 enum wlr_direction wlr_dir = 0;
515 if (!sway_assert(sway_dir_to_wlr(dir, &wlr_dir),
516 "got invalid direction: %d", dir)) {
517 return NULL;
518 }
519 int lx, ly;
520 get_layout_center_position(container, &lx, &ly);
521 struct wlr_output_layout *layout = root_container.sway_root->output_layout;
522 struct wlr_output *wlr_adjacent =
523 wlr_output_layout_adjacent_output(layout, wlr_dir,
524 container->sway_output->wlr_output, lx, ly);
525 swayc_t *adjacent = sway_output_from_wlr(wlr_adjacent);
526
527 if (!adjacent || adjacent == container) {
528 return wrap_candidate;
529 }
530 swayc_t *next = get_swayc_in_output_direction(adjacent, dir, seat);
531 if (next == NULL) {
532 return NULL;
533 }
534 if (next->children && next->children->length) {
535 // TODO consider floating children as well
536 return sway_seat_get_focus_inactive(seat, next);
537 } else {
538 return next;
539 }
540 } else {
541 if (dir == MOVE_LEFT || dir == MOVE_RIGHT) {
542 if (parent->layout == L_HORIZ || parent->layout == L_TABBED) {
543 can_move = true;
544 desired = idx + (dir == MOVE_LEFT ? -1 : 1);
545 }
546 } else {
547 if (parent->layout == L_VERT || parent->layout == L_STACKED) {
548 can_move = true;
549 desired = idx + (dir == MOVE_UP ? -1 : 1);
550 }
551 }
552 }
553
554 if (can_move) {
555 // TODO handle floating
556 if (desired < 0 || desired >= parent->children->length) {
557 can_move = false;
558 int len = parent->children->length;
559 if (!wrap_candidate && len > 1) {
560 if (desired < 0) {
561 wrap_candidate = parent->children->items[len-1];
562 } else {
563 wrap_candidate = parent->children->items[0];
564 }
565 if (config->force_focus_wrapping) {
566 return wrap_candidate;
567 }
568 }
569 } else {
570 wlr_log(L_DEBUG, "%s cont %d-%p dir %i sibling %d: %p", __func__,
571 idx, container, dir, desired, parent->children->items[desired]);
572 return parent->children->items[desired];
573 }
574 }
575
576 if (!can_move) {
577 container = parent;
578 parent = parent->parent;
579 if (!parent || container == limit) {
580 // wrapping is the last chance
581 return wrap_candidate;
582 }
583 }
584 }
585}
586
587swayc_t *get_swayc_in_direction(swayc_t *container, struct sway_seat *seat,
588 enum movement_direction dir) {
589 return get_swayc_in_direction_under(container, dir, seat, NULL);
590}