aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/output.c
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-09-05 09:33:27 -0400
committerLibravatar GitHub <noreply@github.com>2018-09-05 09:33:27 -0400
commit610eb946171f782165a20614b2d3318b89273990 (patch)
tree05eec1df1ef48e05b23d273d31143ad32e7632d2 /sway/tree/output.c
parentMerge pull request #2574 from ammgws/block-bg-fix (diff)
parentAllow marked containers to be moved out of the scratchpad via move command (diff)
downloadsway-610eb946171f782165a20614b2d3318b89273990.tar.gz
sway-610eb946171f782165a20614b2d3318b89273990.tar.zst
sway-610eb946171f782165a20614b2d3318b89273990.zip
Merge pull request #2540 from RyanDwyer/typesafety
Implement type safe arguments and demote sway_container
Diffstat (limited to 'sway/tree/output.c')
-rw-r--r--sway/tree/output.c348
1 files changed, 209 insertions, 139 deletions
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 6601220b..35589032 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -2,28 +2,31 @@
2#include <ctype.h> 2#include <ctype.h>
3#include <string.h> 3#include <string.h>
4#include <strings.h> 4#include <strings.h>
5#include <wlr/types/wlr_output_damage.h>
5#include "sway/ipc-server.h" 6#include "sway/ipc-server.h"
7#include "sway/layers.h"
6#include "sway/output.h" 8#include "sway/output.h"
7#include "sway/tree/arrange.h" 9#include "sway/tree/arrange.h"
8#include "sway/tree/output.h" 10#include "sway/tree/output.h"
9#include "sway/tree/workspace.h" 11#include "sway/tree/workspace.h"
10#include "log.h" 12#include "log.h"
13#include "util.h"
11 14
12static void restore_workspaces(struct sway_container *output) { 15static void restore_workspaces(struct sway_output *output) {
13 // Workspace output priority 16 // Workspace output priority
14 for (int i = 0; i < root_container.children->length; i++) { 17 for (int i = 0; i < root->outputs->length; i++) {
15 struct sway_container *other = root_container.children->items[i]; 18 struct sway_output *other = root->outputs->items[i];
16 if (other == output) { 19 if (other == output) {
17 continue; 20 continue;
18 } 21 }
19 22
20 for (int j = 0; j < other->children->length; j++) { 23 for (int j = 0; j < other->workspaces->length; j++) {
21 struct sway_container *ws = other->children->items[j]; 24 struct sway_workspace *ws = other->workspaces->items[j];
22 struct sway_container *highest = 25 struct sway_output *highest =
23 workspace_output_get_highest_available(ws, NULL); 26 workspace_output_get_highest_available(ws, NULL);
24 if (highest == output) { 27 if (highest == output) {
25 container_remove_child(ws); 28 workspace_detach(ws);
26 container_add_child(output, ws); 29 output_add_workspace(output, ws);
27 ipc_event_workspace(NULL, ws, "move"); 30 ipc_event_workspace(NULL, ws, "move");
28 j--; 31 j--;
29 } 32 }
@@ -31,111 +34,116 @@ static void restore_workspaces(struct sway_container *output) {
31 } 34 }
32 35
33 // Saved workspaces 36 // Saved workspaces
34 list_t *saved = root_container.sway_root->saved_workspaces; 37 for (int i = 0; i < root->saved_workspaces->length; ++i) {
35 for (int i = 0; i < saved->length; ++i) { 38 struct sway_workspace *ws = root->saved_workspaces->items[i];
36 struct sway_container *ws = saved->items[i]; 39 output_add_workspace(output, ws);
37 container_add_child(output, ws);
38 ipc_event_workspace(NULL, ws, "move"); 40 ipc_event_workspace(NULL, ws, "move");
39 } 41 }
40 saved->length = 0; 42 root->saved_workspaces->length = 0;
41 43
42 output_sort_workspaces(output); 44 output_sort_workspaces(output);
43} 45}
44 46
45struct sway_container *output_create( 47struct sway_output *output_create(struct wlr_output *wlr_output) {
46 struct sway_output *sway_output) { 48 struct sway_output *output = calloc(1, sizeof(struct sway_output));
47 const char *name = sway_output->wlr_output->name; 49 node_init(&output->node, N_OUTPUT, output);
48 char identifier[128]; 50 output->wlr_output = wlr_output;
49 output_get_identifier(identifier, sizeof(identifier), sway_output); 51 wlr_output->data = output;
50 52
51 struct output_config *oc = NULL, *all = NULL; 53 wl_signal_add(&wlr_output->events.destroy, &output->destroy);
52 for (int i = 0; i < config->output_configs->length; ++i) {
53 struct output_config *cur = config->output_configs->items[i];
54 54
55 if (strcasecmp(name, cur->name) == 0 || 55 wl_list_insert(&root->all_outputs, &output->link);
56 strcasecmp(identifier, cur->name) == 0) {
57 wlr_log(WLR_DEBUG, "Matched output config for %s", name);
58 oc = cur;
59 }
60 if (strcasecmp("*", cur->name) == 0) {
61 wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name);
62 all = cur;
63 }
64 56
65 if (oc && all) { 57 if (!wl_list_empty(&wlr_output->modes)) {
66 break; 58 struct wlr_output_mode *mode =
67 } 59 wl_container_of(wlr_output->modes.prev, mode, link);
68 } 60 wlr_output_set_mode(wlr_output, mode);
69 if (!oc) {
70 oc = all;
71 } 61 }
72 62
73 if (oc && !oc->enabled) { 63 output->workspaces = create_list();
74 return NULL; 64 output->current.workspaces = create_list();
75 }
76 65
77 struct sway_container *output = container_create(C_OUTPUT); 66 return output;
78 output->sway_output = sway_output; 67}
79 output->name = strdup(name);
80 if (output->name == NULL) {
81 output_begin_destroy(output);
82 return NULL;
83 }
84 68
69void output_enable(struct sway_output *output, struct output_config *oc) {
70 if (!sway_assert(!output->enabled, "output is already enabled")) {
71 return;
72 }
73 struct wlr_output *wlr_output = output->wlr_output;
74 output->enabled = true;
85 apply_output_config(oc, output); 75 apply_output_config(oc, output);
86 container_add_child(&root_container, output); 76 list_add(root->outputs, output);
87 load_swaybars();
88 77
89 struct wlr_box size; 78 output->lx = wlr_output->lx;
90 wlr_output_effective_resolution(sway_output->wlr_output, &size.width, 79 output->ly = wlr_output->ly;
91 &size.height); 80 wlr_output_transformed_resolution(wlr_output,
92 output->width = size.width; 81 &output->width, &output->height);
93 output->height = size.height;
94 82
95 restore_workspaces(output); 83 restore_workspaces(output);
96 84
97 if (!output->children->length) { 85 if (!output->workspaces->length) {
98 // Create workspace 86 // Create workspace
99 char *ws_name = workspace_next_name(output->name); 87 char *ws_name = workspace_next_name(wlr_output->name);
100 wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name); 88 wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name);
101 struct sway_container *ws = workspace_create(output, ws_name); 89 struct sway_workspace *ws = workspace_create(output, ws_name);
102 // Set each seat's focus if not already set 90 // Set each seat's focus if not already set
103 struct sway_seat *seat = NULL; 91 struct sway_seat *seat = NULL;
104 wl_list_for_each(seat, &input_manager->seats, link) { 92 wl_list_for_each(seat, &input_manager->seats, link) {
105 if (!seat->has_focus) { 93 if (!seat->has_focus) {
106 seat_set_focus(seat, ws); 94 seat_set_focus(seat, &ws->node);
107 } 95 }
108 } 96 }
109 free(ws_name); 97 free(ws_name);
110 } 98 }
111 99
112 container_create_notify(output); 100 size_t len = sizeof(output->layers) / sizeof(output->layers[0]);
113 return output; 101 for (size_t i = 0; i < len; ++i) {
102 wl_list_init(&output->layers[i]);
103 }
104 wl_signal_init(&output->events.destroy);
105
106 input_manager_configure_xcursor(input_manager);
107
108 wl_signal_add(&wlr_output->events.mode, &output->mode);
109 wl_signal_add(&wlr_output->events.transform, &output->transform);
110 wl_signal_add(&wlr_output->events.scale, &output->scale);
111 wl_signal_add(&output->damage->events.frame, &output->damage_frame);
112 wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
113
114 output_add_listeners(output);
115
116 wl_signal_emit(&root->events.new_node, &output->node);
117
118 load_swaybars();
119
120 arrange_layers(output);
121 arrange_root();
114} 122}
115 123
116static void output_evacuate(struct sway_container *output) { 124static void output_evacuate(struct sway_output *output) {
117 if (!output->children->length) { 125 if (!output->workspaces->length) {
118 return; 126 return;
119 } 127 }
120 struct sway_container *fallback_output = NULL; 128 struct sway_output *fallback_output = NULL;
121 if (root_container.children->length > 1) { 129 if (root->outputs->length > 1) {
122 fallback_output = root_container.children->items[0]; 130 fallback_output = root->outputs->items[0];
123 if (fallback_output == output) { 131 if (fallback_output == output) {
124 fallback_output = root_container.children->items[1]; 132 fallback_output = root->outputs->items[1];
125 } 133 }
126 } 134 }
127 135
128 while (output->children->length) { 136 while (output->workspaces->length) {
129 struct sway_container *workspace = output->children->items[0]; 137 struct sway_workspace *workspace = output->workspaces->items[0];
130 138
131 container_remove_child(workspace); 139 workspace_detach(workspace);
132 140
133 if (workspace_is_empty(workspace)) { 141 if (workspace_is_empty(workspace)) {
134 workspace_begin_destroy(workspace); 142 workspace_begin_destroy(workspace);
135 continue; 143 continue;
136 } 144 }
137 145
138 struct sway_container *new_output = 146 struct sway_output *new_output =
139 workspace_output_get_highest_available(workspace, output); 147 workspace_output_get_highest_available(workspace, output);
140 if (!new_output) { 148 if (!new_output) {
141 new_output = fallback_output; 149 new_output = fallback_output;
@@ -143,39 +151,31 @@ static void output_evacuate(struct sway_container *output) {
143 151
144 if (new_output) { 152 if (new_output) {
145 workspace_output_add_priority(workspace, new_output); 153 workspace_output_add_priority(workspace, new_output);
146 container_add_child(new_output, workspace); 154 output_add_workspace(new_output, workspace);
147 output_sort_workspaces(new_output); 155 output_sort_workspaces(new_output);
148 ipc_event_workspace(NULL, workspace, "move"); 156 ipc_event_workspace(NULL, workspace, "move");
149 } else { 157 } else {
150 list_add(root_container.sway_root->saved_workspaces, workspace); 158 list_add(root->saved_workspaces, workspace);
151 } 159 }
152 } 160 }
153} 161}
154 162
155void output_destroy(struct sway_container *output) { 163void output_destroy(struct sway_output *output) {
156 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { 164 if (!sway_assert(output->node.destroying,
165 "Tried to free output which wasn't marked as destroying")) {
157 return; 166 return;
158 } 167 }
159 if (!sway_assert(output->destroying, 168 if (!sway_assert(output->wlr_output == NULL,
160 "Tried to free output which wasn't marked as destroying")) { 169 "Tried to free output which still had a wlr_output")) {
161 return; 170 return;
162 } 171 }
163 if (!sway_assert(output->ntxnrefs == 0, "Tried to free output " 172 if (!sway_assert(output->node.ntxnrefs == 0, "Tried to free output "
164 "which is still referenced by transactions")) { 173 "which is still referenced by transactions")) {
165 return; 174 return;
166 } 175 }
167 free(output->name); 176 list_free(output->workspaces);
168 free(output->formatted_title); 177 list_free(output->current.workspaces);
169 wlr_texture_destroy(output->title_focused);
170 wlr_texture_destroy(output->title_focused_inactive);
171 wlr_texture_destroy(output->title_unfocused);
172 wlr_texture_destroy(output->title_urgent);
173 list_free(output->children);
174 list_free(output->current.children);
175 list_free(output->outputs);
176 free(output); 178 free(output);
177
178 // NOTE: We don't actually destroy the sway_output here
179} 179}
180 180
181static void untrack_output(struct sway_container *con, void *data) { 181static void untrack_output(struct sway_container *con, void *data) {
@@ -186,76 +186,128 @@ static void untrack_output(struct sway_container *con, void *data) {
186 } 186 }
187} 187}
188 188
189void output_begin_destroy(struct sway_container *output) { 189void output_disable(struct sway_output *output) {
190 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { 190 if (!sway_assert(output->enabled, "Expected an enabled output")) {
191 return; 191 return;
192 } 192 }
193 wlr_log(WLR_DEBUG, "OUTPUT: Destroying output '%s'", output->name); 193 wlr_log(WLR_DEBUG, "Disabling output '%s'", output->wlr_output->name);
194 wl_signal_emit(&output->events.destroy, output); 194 wl_signal_emit(&output->events.destroy, output);
195 195
196 output_evacuate(output); 196 output_evacuate(output);
197 197
198 output->destroying = true; 198 root_for_each_container(untrack_output, output);
199 container_set_dirty(output); 199
200 int index = list_find(root->outputs, output);
201 list_del(root->outputs, index);
202
203 wl_list_remove(&output->mode.link);
204 wl_list_remove(&output->transform.link);
205 wl_list_remove(&output->scale.link);
206 wl_list_remove(&output->damage_destroy.link);
207 wl_list_remove(&output->damage_frame.link);
208
209 output->enabled = false;
210
211 arrange_root();
212}
213
214void output_begin_destroy(struct sway_output *output) {
215 if (!sway_assert(!output->enabled, "Expected a disabled output")) {
216 return;
217 }
218 wlr_log(WLR_DEBUG, "Destroying output '%s'", output->wlr_output->name);
219
220 output->node.destroying = true;
221 node_set_dirty(&output->node);
222
223 wl_list_remove(&output->link);
224 wl_list_remove(&output->destroy.link);
225 output->wlr_output->data = NULL;
226 output->wlr_output = NULL;
227}
200 228
201 root_for_each_container(untrack_output, output->sway_output); 229struct output_config *output_find_config(struct sway_output *output) {
230 const char *name = output->wlr_output->name;
231 char identifier[128];
232 output_get_identifier(identifier, sizeof(identifier), output);
202 233
203 wl_list_remove(&output->sway_output->mode.link); 234 struct output_config *oc = NULL, *all = NULL;
204 wl_list_remove(&output->sway_output->transform.link); 235 for (int i = 0; i < config->output_configs->length; ++i) {
205 wl_list_remove(&output->sway_output->scale.link); 236 struct output_config *cur = config->output_configs->items[i];
206 wl_list_remove(&output->sway_output->damage_destroy.link);
207 wl_list_remove(&output->sway_output->damage_frame.link);
208 237
209 output->sway_output->swayc = NULL; 238 if (strcasecmp(name, cur->name) == 0 ||
210 output->sway_output = NULL; 239 strcasecmp(identifier, cur->name) == 0) {
240 wlr_log(WLR_DEBUG, "Matched output config for %s", name);
241 oc = cur;
242 }
243 if (strcasecmp("*", cur->name) == 0) {
244 wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name);
245 all = cur;
246 }
211 247
212 if (output->parent) { 248 if (oc && all) {
213 container_remove_child(output); 249 break;
250 }
251 }
252 if (!oc) {
253 oc = all;
214 } 254 }
255
256 return oc;
215} 257}
216 258
217struct sway_container *output_from_wlr_output(struct wlr_output *output) { 259struct sway_output *output_from_wlr_output(struct wlr_output *output) {
218 if (output == NULL) { 260 return output->data;
261}
262
263struct sway_output *output_get_in_direction(struct sway_output *reference,
264 enum movement_direction direction) {
265 enum wlr_direction wlr_dir = 0;
266 if (!sway_assert(sway_dir_to_wlr(direction, &wlr_dir),
267 "got invalid direction: %d", direction)) {
219 return NULL; 268 return NULL;
220 } 269 }
221 for (int i = 0; i < root_container.children->length; ++i) { 270 int lx = reference->wlr_output->lx + reference->width / 2;
222 struct sway_container *o = root_container.children->items[i]; 271 int ly = reference->wlr_output->ly + reference->height / 2;
223 if (o->type == C_OUTPUT && o->sway_output->wlr_output == output) { 272 struct wlr_output *wlr_adjacent = wlr_output_layout_adjacent_output(
224 return o; 273 root->output_layout, wlr_dir, reference->wlr_output, lx, ly);
225 } 274 if (!wlr_adjacent) {
275 return NULL;
226 } 276 }
227 return NULL; 277 return output_from_wlr_output(wlr_adjacent);
228} 278}
229 279
230void output_for_each_workspace(struct sway_container *output, 280void output_add_workspace(struct sway_output *output,
231 void (*f)(struct sway_container *con, void *data), void *data) { 281 struct sway_workspace *workspace) {
232 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { 282 if (workspace->output) {
233 return; 283 workspace_detach(workspace);
234 } 284 }
235 for (int i = 0; i < output->children->length; ++i) { 285 list_add(output->workspaces, workspace);
236 struct sway_container *workspace = output->children->items[i]; 286 workspace->output = output;
287 node_set_dirty(&output->node);
288 node_set_dirty(&workspace->node);
289}
290
291void output_for_each_workspace(struct sway_output *output,
292 void (*f)(struct sway_workspace *ws, void *data), void *data) {
293 for (int i = 0; i < output->workspaces->length; ++i) {
294 struct sway_workspace *workspace = output->workspaces->items[i];
237 f(workspace, data); 295 f(workspace, data);
238 } 296 }
239} 297}
240 298
241void output_for_each_container(struct sway_container *output, 299void output_for_each_container(struct sway_output *output,
242 void (*f)(struct sway_container *con, void *data), void *data) { 300 void (*f)(struct sway_container *con, void *data), void *data) {
243 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { 301 for (int i = 0; i < output->workspaces->length; ++i) {
244 return; 302 struct sway_workspace *workspace = output->workspaces->items[i];
245 }
246 for (int i = 0; i < output->children->length; ++i) {
247 struct sway_container *workspace = output->children->items[i];
248 workspace_for_each_container(workspace, f, data); 303 workspace_for_each_container(workspace, f, data);
249 } 304 }
250} 305}
251 306
252struct sway_container *output_find_workspace(struct sway_container *output, 307struct sway_workspace *output_find_workspace(struct sway_output *output,
253 bool (*test)(struct sway_container *con, void *data), void *data) { 308 bool (*test)(struct sway_workspace *ws, void *data), void *data) {
254 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { 309 for (int i = 0; i < output->workspaces->length; ++i) {
255 return NULL; 310 struct sway_workspace *workspace = output->workspaces->items[i];
256 }
257 for (int i = 0; i < output->children->length; ++i) {
258 struct sway_container *workspace = output->children->items[i];
259 if (test(workspace, data)) { 311 if (test(workspace, data)) {
260 return workspace; 312 return workspace;
261 } 313 }
@@ -263,14 +315,11 @@ struct sway_container *output_find_workspace(struct sway_container *output,
263 return NULL; 315 return NULL;
264} 316}
265 317
266struct sway_container *output_find_container(struct sway_container *output, 318struct sway_container *output_find_container(struct sway_output *output,
267 bool (*test)(struct sway_container *con, void *data), void *data) { 319 bool (*test)(struct sway_container *con, void *data), void *data) {
268 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) {
269 return NULL;
270 }
271 struct sway_container *result = NULL; 320 struct sway_container *result = NULL;
272 for (int i = 0; i < output->children->length; ++i) { 321 for (int i = 0; i < output->workspaces->length; ++i) {
273 struct sway_container *workspace = output->children->items[i]; 322 struct sway_workspace *workspace = output->workspaces->items[i];
274 if ((result = workspace_find_container(workspace, test, data))) { 323 if ((result = workspace_find_container(workspace, test, data))) {
275 return result; 324 return result;
276 } 325 }
@@ -279,8 +328,8 @@ struct sway_container *output_find_container(struct sway_container *output,
279} 328}
280 329
281static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { 330static int sort_workspace_cmp_qsort(const void *_a, const void *_b) {
282 struct sway_container *a = *(void **)_a; 331 struct sway_workspace *a = *(void **)_a;
283 struct sway_container *b = *(void **)_b; 332 struct sway_workspace *b = *(void **)_b;
284 333
285 if (isdigit(a->name[0]) && isdigit(b->name[0])) { 334 if (isdigit(a->name[0]) && isdigit(b->name[0])) {
286 int a_num = strtol(a->name, NULL, 10); 335 int a_num = strtol(a->name, NULL, 10);
@@ -294,6 +343,27 @@ static int sort_workspace_cmp_qsort(const void *_a, const void *_b) {
294 return 0; 343 return 0;
295} 344}
296 345
297void output_sort_workspaces(struct sway_container *output) { 346void output_sort_workspaces(struct sway_output *output) {
298 list_stable_sort(output->children, sort_workspace_cmp_qsort); 347 list_stable_sort(output->workspaces, sort_workspace_cmp_qsort);
348}
349
350void output_get_box(struct sway_output *output, struct wlr_box *box) {
351 box->x = output->lx;
352 box->y = output->ly;
353 box->width = output->width;
354 box->height = output->height;
355}
356
357enum sway_container_layout output_get_default_layout(
358 struct sway_output *output) {
359 if (config->default_layout != L_NONE) {
360 return config->default_layout;
361 }
362 if (config->default_orientation != L_NONE) {
363 return config->default_orientation;
364 }
365 if (output->height > output->width) {
366 return L_VERT;
367 }
368 return L_HORIZ;
299} 369}