aboutsummaryrefslogtreecommitdiffstats
path: root/sway/container.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/container.c')
-rw-r--r--sway/container.c415
1 files changed, 266 insertions, 149 deletions
diff --git a/sway/container.c b/sway/container.c
index ef0e6c55..baf84378 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -1,6 +1,7 @@
1#include <stdlib.h> 1#include <stdlib.h>
2#include <stdbool.h> 2#include <stdbool.h>
3#include <strings.h> 3#include <strings.h>
4#include <pcre.h>
4#include "config.h" 5#include "config.h"
5#include "container.h" 6#include "container.h"
6#include "workspace.h" 7#include "workspace.h"
@@ -53,26 +54,30 @@ static void free_swayc(swayc_t *cont) {
53// New containers 54// New containers
54 55
55swayc_t *new_output(wlc_handle handle) { 56swayc_t *new_output(wlc_handle handle) {
56 const struct wlc_size *size = wlc_output_get_resolution(handle);
57 const char *name = wlc_output_get_name(handle); 57 const char *name = wlc_output_get_name(handle);
58 int i, len;
59
58 // Find current outputs to see if this already exists 60 // Find current outputs to see if this already exists
59 { 61 if (name) {
60 int i, len = root_container.children->length; 62 len = root_container.children->length;
61 for (i = 0; i < len; ++i) { 63 for (i = 0; i < len; ++i) {
62 swayc_t *op = root_container.children->items[i]; 64 swayc_t *op = root_container.children->items[i];
63 const char *op_name = op->name; 65 if (strcmp(op->name, name) == 0) {
64 if (op_name && name && strcmp(op_name, name) == 0) { 66 sway_log(L_DEBUG, "restoring output %lu:%s", handle, op->name);
65 sway_log(L_DEBUG, "restoring output %lu:%s", handle, op_name);
66 return op; 67 return op;
67 } 68 }
68 } 69 }
70 } else {
71 sway_log(L_ERROR, "Output has no given name");
72 return NULL;
69 } 73 }
70 74
71 sway_log(L_DEBUG, "Added output %lu:%s", handle, name); 75 sway_log(L_DEBUG, "Adding output %lu:%s", handle, name);
72 76
77 // Find output config
73 struct output_config *oc = NULL; 78 struct output_config *oc = NULL;
74 int i; 79 len = config->output_configs->length;
75 for (i = 0; i < config->output_configs->length; ++i) { 80 for (i = 0; i < len; ++i) {
76 oc = config->output_configs->items[i]; 81 oc = config->output_configs->items[i];
77 if (strcasecmp(name, oc->name) == 0) { 82 if (strcasecmp(name, oc->name) == 0) {
78 sway_log(L_DEBUG, "Matched output config for %s", name); 83 sway_log(L_DEBUG, "Matched output config for %s", name);
@@ -86,77 +91,88 @@ swayc_t *new_output(wlc_handle handle) {
86 } 91 }
87 92
88 swayc_t *output = new_swayc(C_OUTPUT); 93 swayc_t *output = new_swayc(C_OUTPUT);
89 if (oc && oc->width != -1 && oc->height != -1) {
90 output->width = oc->width;
91 output->height = oc->height;
92 struct wlc_size new_size = { .w = oc->width, .h = oc->height };
93 wlc_output_set_resolution(handle, &new_size);
94 } else {
95 output->width = size->w;
96 output->height = size->h;
97 }
98 output->handle = handle; 94 output->handle = handle;
99 output->name = name ? strdup(name) : NULL; 95 output->name = name ? strdup(name) : NULL;
100
101 // Find position for it
102 if (oc && oc->x != -1 && oc->y != -1) {
103 sway_log(L_DEBUG, "Set %s position to %d, %d", name, oc->x, oc->y);
104 output->x = oc->x;
105 output->y = oc->y;
106 } else {
107 int x = 0;
108 for (i = 0; i < root_container.children->length; ++i) {
109 swayc_t *c = root_container.children->items[i];
110 if (c->type == C_OUTPUT) {
111 if (c->width + c->x > x) {
112 x = c->width + c->x;
113 }
114 }
115 }
116 output->x = x;
117 }
118 96
119 add_child(&root_container, output); 97 if (oc) {
120 98 // Set output width/height
121 // Create workspace 99 if (oc->width > 0 && oc->height > 0) {
122 char *ws_name = NULL; 100 output->width = oc->width;
123 if (name) { 101 output->height = oc->height;
124 for (i = 0; i < config->workspace_outputs->length; ++i) { 102 struct wlc_size geo = { .w = oc->width, .h = oc->height};
125 struct workspace_output *wso = config->workspace_outputs->items[i]; 103 wlc_output_set_resolution(handle, &geo);
126 if (strcasecmp(wso->output, name) == 0) { 104 } else {
127 sway_log(L_DEBUG, "Matched workspace to output: %s for %s", wso->workspace, wso->output); 105 struct wlc_size geo = *wlc_output_get_resolution(handle);
128 // Check if any other workspaces are using this name 106 output->width = geo.w;
129 if (workspace_by_name(wso->workspace)) { 107 output->height = geo.h;
130 sway_log(L_DEBUG, "But it's already taken"); 108 }
131 break; 109 // find position in config or find where it should go
110 // TODO more intelligent method
111 if (oc->x > 0 && oc->y > 0) {
112 output->x = oc->x;
113 output->y = oc->y;
114 } else {
115 unsigned int x = 0;
116 len = root_container.children->length;
117 for (i = 0; i < len; ++i) {
118 swayc_t *c = root_container.children->items[i];
119 if (c->type == C_OUTPUT) {
120 unsigned int cx = c->width + c->x;
121 if (cx > x) {
122 x = cx;
123 }
132 } 124 }
133 sway_log(L_DEBUG, "So we're going to use it");
134 ws_name = strdup(wso->workspace);
135 break;
136 } 125 }
126 output->x = x;
137 } 127 }
138 } 128 }
139 if (!ws_name) { 129 // Add as child to root
140 ws_name = workspace_next_name(); 130 add_child(&root_container, output);
141 }
142 131
143 // create and initilize default workspace 132 // create and initilize default workspace
144 swayc_t *ws = new_workspace(output, ws_name); 133 swayc_t *ws = new_workspace(output, NULL);
145 ws->is_focused = true; 134 ws->is_focused = true;
146 135
147 free(ws_name);
148
149 return output; 136 return output;
150} 137}
151 138
152swayc_t *new_workspace(swayc_t *output, const char *name) { 139swayc_t *new_workspace(swayc_t *output, const char *name) {
153 if (!ASSERT_NONNULL(output)) { 140 swayc_t *ws = NULL;
154 return NULL; 141 struct workspace_output *wsop;
142 if (name) {
143 // Find existing workspace with same name.
144 // or workspace found by special name
145 if ((ws = workspace_by_name(name))) {
146 return ws;
147 }
148 // Find matching output from config
149 if (!output) {
150 if ((wsop = wsop_find_workspace(name))) {
151 int i, len = root_container.children->length;
152 for (i = 0; i < len; ++i) {
153 swayc_t *op = root_container.children->items[i];
154 if (strcasecmp(op->name, wsop->output) == 0) {
155 output = op;
156 goto find_wsop_end;
157 }
158 }
159 }
160 // Set output to active_output if there is no output.
161 output = swayc_active_output();
162 find_wsop_end:;
163 }
164 } else {
165 // No name or output, use active_output
166 if (!output) {
167 output = swayc_active_output();
168 }
169 // search for available output name
170 if (!(name = workspace_output_open_name(output))) {
171 // otherwise just use simple next name
172 name = workspace_next_name();
173 }
155 } 174 }
156 sway_log(L_DEBUG, "Added workspace %s for output %u", name, (unsigned int)output->handle);
157 swayc_t *workspace = new_swayc(C_WORKSPACE); 175 swayc_t *workspace = new_swayc(C_WORKSPACE);
158
159 // TODO: default_layout
160 if (config->default_layout != L_NONE) { 176 if (config->default_layout != L_NONE) {
161 workspace->layout = config->default_layout; 177 workspace->layout = config->default_layout;
162 } else if (config->default_orientation != L_NONE) { 178 } else if (config->default_orientation != L_NONE) {
@@ -374,7 +390,7 @@ swayc_t *destroy_view(swayc_t *view) {
374// Container lookup 390// Container lookup
375 391
376 392
377swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { 393swayc_t *swayc_by_test_r(swayc_t *container, swayc_test_func test, void *data) {
378 if (!container->children) { 394 if (!container->children) {
379 return NULL; 395 return NULL;
380 } 396 }
@@ -393,7 +409,7 @@ swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *dat
393 if (test(child, data)) { 409 if (test(child, data)) {
394 return child; 410 return child;
395 } else { 411 } else {
396 swayc_t *res = swayc_by_test(child, test, data); 412 swayc_t *res = swayc_by_test_r(child, test, data);
397 if (res) { 413 if (res) {
398 return res; 414 return res;
399 } 415 }
@@ -401,18 +417,193 @@ swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *dat
401 } 417 }
402 return NULL; 418 return NULL;
403} 419}
420swayc_t *swayc_by_test(swayc_test_func test, void *data) {
421 return swayc_by_test_r(&root_container, test, data);
422}
423
424void swayc_map_r(swayc_t *container, swayc_map_func f, void *data) {
425 if (container) {
426 f(container, data);
427 int i;
428 if (container->children) {
429 for (i = 0; i < container->children->length; ++i) {
430 swayc_t *child = container->children->items[i];
431 swayc_map_r(child, f, data);
432 }
433 }
434 if (container->floating) {
435 for (i = 0; i < container->floating->length; ++i) {
436 swayc_t *child = container->floating->items[i];
437 swayc_map_r(child, f, data);
438 }
439 }
440 }
441}
442void swayc_map(swayc_map_func f, void *data) {
443 swayc_map_r(&root_container, f, data);
444}
445
446void swayc_map_by_test_r(swayc_t *container,
447 swayc_map_func func, swayc_test_func test,
448 void *funcdata, void *testdata) {
449 if (container) {
450 if (test(container, testdata)) {
451 func(container, funcdata);
452 }
453 int i;
454 if (container->children) {
455 for (i = 0; i < container->children->length; ++i) {
456 swayc_t *child = container->children->items[i];
457 swayc_map_by_test_r(child, func, test, funcdata, testdata);
458 }
459 }
460 if (container->floating) {
461 for (i = 0; i < container->floating->length; ++i) {
462 swayc_t *child = container->floating->items[i];
463 swayc_map_by_test_r(child, func, test, funcdata, testdata);
464 }
465 }
466 }
467}
468void swayc_map_by_test(
469 swayc_map_func func, swayc_test_func test,
470 void *funcdata, void *testdata) {
471 swayc_map_by_test_r(&root_container, func, test, funcdata, testdata);
472}
473
474
475
476// Map functions
477void set_gaps(swayc_t *view, void *_data) {
478 int *data = _data;
479 if (view->type == C_WORKSPACE || view->type == C_VIEW) {
480 view->gaps = *data;
481 }
482}
404 483
405static bool test_name(swayc_t *view, void *data) { 484void add_gaps(swayc_t *view, void *_data) {
406 if (!view && !view->name) { 485 int *data = _data;
407 return false; 486 if (view->type == C_WORKSPACE || view->type == C_VIEW) {
487 if ((view->gaps += *data) < 0) {
488 view->gaps = 0;
489 }
408 } 490 }
409 return strcmp(view->name, data) == 0;
410} 491}
411 492
412swayc_t *swayc_by_name(const char *name) { 493// Test functions
413 return swayc_by_test(&root_container, test_name, (void *)name); 494bool test_name(swayc_t *view, void *data) {
495 return view->name && strcmp(view->name, data) == 0;
414} 496}
415 497
498// test_name_regex
499struct test_name_regex {
500 pcre *reg;
501 pcre_extra *regext;
502};
503
504void *compile_regex(const char *pattern) {
505 struct test_name_regex *regex = malloc(sizeof *regex);
506 const char *error;
507 int erroffset;
508 if (!(regex->reg = pcre_compile(pattern, 0, &error, &erroffset, NULL))) {
509 sway_log(L_ERROR, "Regex compilation failed:%s:%s", pattern, error);
510 free(regex);
511 return NULL;
512 }
513 regex->regext = pcre_study(regex->reg, 0, &error);
514 if (error) {
515 sway_log(L_DEBUG, "Regex study failed:%s:%s", pattern, error);
516 }
517 return regex;
518}
519
520void free_regex(void *_regex) {
521 struct test_name_regex *regex = _regex;
522 pcre_free(regex->reg);
523 pcre_free_study(regex->regext);
524 free(regex);
525}
526
527static bool exec_regex(const char *pattern, struct test_name_regex *regex) {
528 int ovector[300];
529 return 0 < pcre_exec(regex->reg, regex->regext, pattern,
530 strlen(pattern), 0, 0, ovector, 300);
531}
532
533bool test_name_regex(swayc_t *view, void *data) {
534 return view->name && exec_regex(view->name, data);
535}
536bool test_layout(swayc_t *view, void *data) {
537 return view->layout & *(enum swayc_layouts *)data;
538}
539bool test_type(swayc_t *view, void *data) {
540 return view->layout & *(enum swayc_types *)data;
541}
542bool test_visibility(swayc_t *view, void *data) {
543 return view->visible == *(bool *)data;
544}
545bool test_handle(swayc_t *view, void *data) {
546 return view->handle == *(wlc_handle *)data;
547}
548
549// C_VIEW tests
550bool test_view_state(swayc_t *view, void *data) {
551 return view->type == C_VIEW
552 && wlc_view_get_state(view->handle) & *(int *)data;
553}
554bool test_view_type(swayc_t *view, void *data) {
555 return view->type == C_VIEW
556 && wlc_view_get_type(view->handle) & *(int *)data;
557}
558bool test_view_title(swayc_t *view, void *data) {
559 return view->type == C_VIEW
560 && strcmp(view->name, data) == 0;
561}
562bool test_view_class(swayc_t *view, void *data) {
563 return view->type == C_VIEW
564 && strcmp(wlc_view_get_class(view->handle), data) == 0;
565}
566bool test_view_appid(swayc_t *view, void *data) {
567 return view->type == C_VIEW
568 && strcmp(wlc_view_get_app_id(view->handle), data) == 0;
569}
570bool test_view_title_regex(swayc_t *view, void *data) {
571 return view->type == C_VIEW
572 && exec_regex(view->name, data);
573}
574bool test_view_class_regex(swayc_t *view, void *data) {
575 return view->type == C_VIEW
576 && exec_regex(wlc_view_get_class(view->handle), data);
577}
578bool test_view_appid_regex(swayc_t *view, void *data) {
579 return view->type == C_VIEW
580 && exec_regex(wlc_view_get_app_id(view->handle), data);
581}
582
583// Fancy test combiners
584bool test_and(swayc_t *view, void *data) {
585 struct test_list *list = data;
586 while (list->test) {
587 if (!list->test(view, list->data)) {
588 return false;
589 }
590 ++list;
591 }
592 return true;
593}
594bool test_or(swayc_t *view, void *data) {
595 struct test_list *list = data;
596 while (list->test) {
597 if (list->test(view, list->data)) {
598 return true;
599 }
600 ++list;
601 }
602 return false;
603}
604
605// Focus|parent lookup
606
416swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) { 607swayc_t *swayc_parent_by_type(swayc_t *container, enum swayc_types type) {
417 if (!ASSERT_NONNULL(container)) { 608 if (!ASSERT_NONNULL(container)) {
418 return NULL; 609 return NULL;
@@ -465,42 +656,6 @@ swayc_t *swayc_focus_by_layout(swayc_t *container, enum swayc_layouts layout) {
465 return container; 656 return container;
466} 657}
467 658
468
469static swayc_t *_swayc_by_handle_helper(wlc_handle handle, swayc_t *parent) {
470 if (!parent || !parent->children) {
471 return NULL;
472 }
473 int i, len;
474 swayc_t **child;
475 if (parent->type == C_WORKSPACE) {
476 len = parent->floating->length;
477 child = (swayc_t **)parent->floating->items;
478 for (i = 0; i < len; ++i, ++child) {
479 if ((*child)->handle == handle) {
480 return *child;
481 }
482 }
483 }
484
485 len = parent->children->length;
486 child = (swayc_t**)parent->children->items;
487 for (i = 0; i < len; ++i, ++child) {
488 if ((*child)->handle == handle) {
489 return *child;
490 } else {
491 swayc_t *res;
492 if ((res = _swayc_by_handle_helper(handle, *child))) {
493 return res;
494 }
495 }
496 }
497 return NULL;
498}
499
500swayc_t *swayc_by_handle(wlc_handle handle) {
501 return _swayc_by_handle_helper(handle, &root_container);
502}
503
504swayc_t *swayc_active_output(void) { 659swayc_t *swayc_active_output(void) {
505 return root_container.focused; 660 return root_container.focused;
506} 661}
@@ -533,11 +688,13 @@ swayc_t *swayc_active_workspace_for(swayc_t *cont) {
533// Container information 688// Container information
534 689
535bool swayc_is_fullscreen(swayc_t *view) { 690bool swayc_is_fullscreen(swayc_t *view) {
536 return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN); 691 return view && view->type == C_VIEW
692 && wlc_view_get_state(view->handle) & WLC_BIT_FULLSCREEN;
537} 693}
538 694
539bool swayc_is_active(swayc_t *view) { 695bool swayc_is_active(swayc_t *view) {
540 return view && view->type == C_VIEW && (wlc_view_get_state(view->handle) & WLC_BIT_ACTIVATED); 696 return view && view->type == C_VIEW
697 && wlc_view_get_state(view->handle) & WLC_BIT_ACTIVATED;
541} 698}
542 699
543bool swayc_is_parent_of(swayc_t *parent, swayc_t *child) { 700bool swayc_is_parent_of(swayc_t *parent, swayc_t *child) {
@@ -566,25 +723,6 @@ int swayc_gap(swayc_t *container) {
566 723
567// Mapping 724// Mapping
568 725
569void container_map(swayc_t *container, void (*f)(swayc_t *view, void *data), void *data) {
570 if (container) {
571 f(container, data);
572 int i;
573 if (container->children) {
574 for (i = 0; i < container->children->length; ++i) {
575 swayc_t *child = container->children->items[i];
576 container_map(child, f, data);
577 }
578 }
579 if (container->floating) {
580 for (i = 0; i < container->floating->length; ++i) {
581 swayc_t *child = container->floating->items[i];
582 container_map(child, f, data);
583 }
584 }
585 }
586}
587
588void update_visibility_output(swayc_t *container, wlc_handle output) { 726void update_visibility_output(swayc_t *container, wlc_handle output) {
589 // Inherit visibility 727 // Inherit visibility
590 swayc_t *parent = container->parent; 728 swayc_t *parent = container->parent;
@@ -653,24 +791,3 @@ void update_visibility(swayc_t *container) {
653 } 791 }
654} 792}
655 793
656void set_gaps(swayc_t *view, void *_data) {
657 int *data = _data;
658 if (!ASSERT_NONNULL(view)) {
659 return;
660 }
661 if (view->type == C_WORKSPACE || view->type == C_VIEW) {
662 view->gaps = *data;
663 }
664}
665
666void add_gaps(swayc_t *view, void *_data) {
667 int *data = _data;
668 if (!ASSERT_NONNULL(view)) {
669 return;
670 }
671 if (view->type == C_WORKSPACE || view->type == C_VIEW) {
672 if ((view->gaps += *data) < 0) {
673 view->gaps = 0;
674 }
675 }
676}