aboutsummaryrefslogtreecommitdiffstats
path: root/sway/tree/output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/tree/output.c')
-rw-r--r--sway/tree/output.c348
1 files changed, 208 insertions, 140 deletions
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 6601220b..d72eb1a1 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,111 @@ 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
89 struct wlr_box size;
90 wlr_output_effective_resolution(sway_output->wlr_output, &size.width,
91 &size.height);
92 output->width = size.width;
93 output->height = size.height;
94 77
95 restore_workspaces(output); 78 restore_workspaces(output);
96 79
97 if (!output->children->length) { 80 if (!output->workspaces->length) {
98 // Create workspace 81 // Create workspace
99 char *ws_name = workspace_next_name(output->name); 82 char *ws_name = workspace_next_name(wlr_output->name);
100 wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name); 83 wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name);
101 struct sway_container *ws = workspace_create(output, ws_name); 84 struct sway_workspace *ws = workspace_create(output, ws_name);
102 // Set each seat's focus if not already set 85 // Set each seat's focus if not already set
103 struct sway_seat *seat = NULL; 86 struct sway_seat *seat = NULL;
104 wl_list_for_each(seat, &input_manager->seats, link) { 87 wl_list_for_each(seat, &input_manager->seats, link) {
105 if (!seat->has_focus) { 88 if (!seat->has_focus) {
106 seat_set_focus(seat, ws); 89 seat_set_focus(seat, &ws->node);
107 } 90 }
108 } 91 }
109 free(ws_name); 92 free(ws_name);
110 } 93 }
111 94
112 container_create_notify(output); 95 size_t len = sizeof(output->layers) / sizeof(output->layers[0]);
113 return output; 96 for (size_t i = 0; i < len; ++i) {
97 wl_list_init(&output->layers[i]);
98 }
99 wl_signal_init(&output->events.destroy);
100
101 input_manager_configure_xcursor(input_manager);
102
103 wl_signal_add(&wlr_output->events.mode, &output->mode);
104 wl_signal_add(&wlr_output->events.transform, &output->transform);
105 wl_signal_add(&wlr_output->events.scale, &output->scale);
106 wl_signal_add(&output->damage->events.frame, &output->damage_frame);
107 wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
108
109 output_add_listeners(output);
110
111 wl_signal_emit(&root->events.new_node, &output->node);
112
113 load_swaybars();
114
115 arrange_layers(output);
116 arrange_root();
114} 117}
115 118
116static void output_evacuate(struct sway_container *output) { 119static void output_evacuate(struct sway_output *output) {
117 if (!output->children->length) { 120 if (!output->workspaces->length) {
118 return; 121 return;
119 } 122 }
120 struct sway_container *fallback_output = NULL; 123 struct sway_output *fallback_output = NULL;
121 if (root_container.children->length > 1) { 124 if (root->outputs->length > 1) {
122 fallback_output = root_container.children->items[0]; 125 fallback_output = root->outputs->items[0];
123 if (fallback_output == output) { 126 if (fallback_output == output) {
124 fallback_output = root_container.children->items[1]; 127 fallback_output = root->outputs->items[1];
125 } 128 }
126 } 129 }
127 130
128 while (output->children->length) { 131 while (output->workspaces->length) {
129 struct sway_container *workspace = output->children->items[0]; 132 struct sway_workspace *workspace = output->workspaces->items[0];
130 133
131 container_remove_child(workspace); 134 workspace_detach(workspace);
132 135
133 if (workspace_is_empty(workspace)) { 136 if (workspace_is_empty(workspace)) {
134 workspace_begin_destroy(workspace); 137 workspace_begin_destroy(workspace);
135 continue; 138 continue;
136 } 139 }
137 140
138 struct sway_container *new_output = 141 struct sway_output *new_output =
139 workspace_output_get_highest_available(workspace, output); 142 workspace_output_get_highest_available(workspace, output);
140 if (!new_output) { 143 if (!new_output) {
141 new_output = fallback_output; 144 new_output = fallback_output;
@@ -143,39 +146,31 @@ static void output_evacuate(struct sway_container *output) {
143 146
144 if (new_output) { 147 if (new_output) {
145 workspace_output_add_priority(workspace, new_output); 148 workspace_output_add_priority(workspace, new_output);
146 container_add_child(new_output, workspace); 149 output_add_workspace(new_output, workspace);
147 output_sort_workspaces(new_output); 150 output_sort_workspaces(new_output);
148 ipc_event_workspace(NULL, workspace, "move"); 151 ipc_event_workspace(NULL, workspace, "move");
149 } else { 152 } else {
150 list_add(root_container.sway_root->saved_workspaces, workspace); 153 list_add(root->saved_workspaces, workspace);
151 } 154 }
152 } 155 }
153} 156}
154 157
155void output_destroy(struct sway_container *output) { 158void output_destroy(struct sway_output *output) {
156 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { 159 if (!sway_assert(output->node.destroying,
160 "Tried to free output which wasn't marked as destroying")) {
157 return; 161 return;
158 } 162 }
159 if (!sway_assert(output->destroying, 163 if (!sway_assert(output->wlr_output == NULL,
160 "Tried to free output which wasn't marked as destroying")) { 164 "Tried to free output which still had a wlr_output")) {
161 return; 165 return;
162 } 166 }
163 if (!sway_assert(output->ntxnrefs == 0, "Tried to free output " 167 if (!sway_assert(output->node.ntxnrefs == 0, "Tried to free output "
164 "which is still referenced by transactions")) { 168 "which is still referenced by transactions")) {
165 return; 169 return;
166 } 170 }
167 free(output->name); 171 list_free(output->workspaces);
168 free(output->formatted_title); 172 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); 173 free(output);
177
178 // NOTE: We don't actually destroy the sway_output here
179} 174}
180 175
181static void untrack_output(struct sway_container *con, void *data) { 176static void untrack_output(struct sway_container *con, void *data) {
@@ -186,76 +181,131 @@ static void untrack_output(struct sway_container *con, void *data) {
186 } 181 }
187} 182}
188 183
189void output_begin_destroy(struct sway_container *output) { 184void output_disable(struct sway_output *output) {
190 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { 185 if (!sway_assert(output->enabled, "Expected an enabled output")) {
191 return; 186 return;
192 } 187 }
193 wlr_log(WLR_DEBUG, "OUTPUT: Destroying output '%s'", output->name); 188 wlr_log(WLR_DEBUG, "Disabling output '%s'", output->wlr_output->name);
194 wl_signal_emit(&output->events.destroy, output); 189 wl_signal_emit(&output->events.destroy, output);
195 190
196 output_evacuate(output); 191 output_evacuate(output);
197 192
198 output->destroying = true; 193 root_for_each_container(untrack_output, output);
199 container_set_dirty(output); 194
195 int index = list_find(root->outputs, output);
196 list_del(root->outputs, index);
200 197
201 root_for_each_container(untrack_output, output->sway_output); 198 wl_list_remove(&output->mode.link);
199 wl_list_remove(&output->transform.link);
200 wl_list_remove(&output->scale.link);
201 wl_list_remove(&output->damage_destroy.link);
202 wl_list_remove(&output->damage_frame.link);
202 203
203 wl_list_remove(&output->sway_output->mode.link); 204 output->enabled = false;
204 wl_list_remove(&output->sway_output->transform.link);
205 wl_list_remove(&output->sway_output->scale.link);
206 wl_list_remove(&output->sway_output->damage_destroy.link);
207 wl_list_remove(&output->sway_output->damage_frame.link);
208 205
209 output->sway_output->swayc = NULL; 206 arrange_root();
210 output->sway_output = NULL; 207}
211 208
212 if (output->parent) { 209void output_begin_destroy(struct sway_output *output) {
213 container_remove_child(output); 210 if (!sway_assert(!output->enabled, "Expected a disabled output")) {
211 return;
214 } 212 }
213 wlr_log(WLR_DEBUG, "Destroying output '%s'", output->wlr_output->name);
214
215 output->node.destroying = true;
216 node_set_dirty(&output->node);
217
218 wl_list_remove(&output->link);
219 wl_list_remove(&output->destroy.link);
220 output->wlr_output->data = NULL;
221 output->wlr_output = NULL;
215} 222}
216 223
217struct sway_container *output_from_wlr_output(struct wlr_output *output) { 224struct output_config *output_find_config(struct sway_output *output) {
218 if (output == NULL) { 225 const char *name = output->wlr_output->name;
226 char identifier[128];
227 output_get_identifier(identifier, sizeof(identifier), output);
228
229 struct output_config *oc = NULL, *all = NULL;
230 for (int i = 0; i < config->output_configs->length; ++i) {
231 struct output_config *cur = config->output_configs->items[i];
232
233 if (strcasecmp(name, cur->name) == 0 ||
234 strcasecmp(identifier, cur->name) == 0) {
235 wlr_log(WLR_DEBUG, "Matched output config for %s", name);
236 oc = cur;
237 }
238 if (strcasecmp("*", cur->name) == 0) {
239 wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name);
240 all = cur;
241 }
242
243 if (oc && all) {
244 break;
245 }
246 }
247 if (!oc) {
248 oc = all;
249 }
250
251 if (oc && !oc->enabled) {
219 return NULL; 252 return NULL;
220 } 253 }
221 for (int i = 0; i < root_container.children->length; ++i) { 254 return oc;
222 struct sway_container *o = root_container.children->items[i]; 255}
223 if (o->type == C_OUTPUT && o->sway_output->wlr_output == output) { 256
224 return o; 257struct sway_output *output_from_wlr_output(struct wlr_output *output) {
225 } 258 return output->data;
259}
260
261struct sway_output *output_get_in_direction(struct sway_output *reference,
262 enum movement_direction direction) {
263 enum wlr_direction wlr_dir = 0;
264 if (!sway_assert(sway_dir_to_wlr(direction, &wlr_dir),
265 "got invalid direction: %d", direction)) {
266 return NULL;
226 } 267 }
227 return NULL; 268 int lx = reference->wlr_output->lx + reference->wlr_output->width / 2;
269 int ly = reference->wlr_output->ly + reference->wlr_output->height / 2;
270 struct wlr_output *wlr_adjacent = wlr_output_layout_adjacent_output(
271 root->output_layout, wlr_dir, reference->wlr_output, lx, ly);
272 if (!wlr_adjacent) {
273 return NULL;
274 }
275 return output_from_wlr_output(wlr_adjacent);
228} 276}
229 277
230void output_for_each_workspace(struct sway_container *output, 278void output_add_workspace(struct sway_output *output,
231 void (*f)(struct sway_container *con, void *data), void *data) { 279 struct sway_workspace *workspace) {
232 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { 280 if (workspace->output) {
233 return; 281 workspace_detach(workspace);
234 } 282 }
235 for (int i = 0; i < output->children->length; ++i) { 283 list_add(output->workspaces, workspace);
236 struct sway_container *workspace = output->children->items[i]; 284 workspace->output = output;
285 node_set_dirty(&output->node);
286 node_set_dirty(&workspace->node);
287}
288
289void output_for_each_workspace(struct sway_output *output,
290 void (*f)(struct sway_workspace *ws, void *data), void *data) {
291 for (int i = 0; i < output->workspaces->length; ++i) {
292 struct sway_workspace *workspace = output->workspaces->items[i];
237 f(workspace, data); 293 f(workspace, data);
238 } 294 }
239} 295}
240 296
241void output_for_each_container(struct sway_container *output, 297void output_for_each_container(struct sway_output *output,
242 void (*f)(struct sway_container *con, void *data), void *data) { 298 void (*f)(struct sway_container *con, void *data), void *data) {
243 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { 299 for (int i = 0; i < output->workspaces->length; ++i) {
244 return; 300 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); 301 workspace_for_each_container(workspace, f, data);
249 } 302 }
250} 303}
251 304
252struct sway_container *output_find_workspace(struct sway_container *output, 305struct sway_workspace *output_find_workspace(struct sway_output *output,
253 bool (*test)(struct sway_container *con, void *data), void *data) { 306 bool (*test)(struct sway_workspace *ws, void *data), void *data) {
254 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { 307 for (int i = 0; i < output->workspaces->length; ++i) {
255 return NULL; 308 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)) { 309 if (test(workspace, data)) {
260 return workspace; 310 return workspace;
261 } 311 }
@@ -263,14 +313,11 @@ struct sway_container *output_find_workspace(struct sway_container *output,
263 return NULL; 313 return NULL;
264} 314}
265 315
266struct sway_container *output_find_container(struct sway_container *output, 316struct sway_container *output_find_container(struct sway_output *output,
267 bool (*test)(struct sway_container *con, void *data), void *data) { 317 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; 318 struct sway_container *result = NULL;
272 for (int i = 0; i < output->children->length; ++i) { 319 for (int i = 0; i < output->workspaces->length; ++i) {
273 struct sway_container *workspace = output->children->items[i]; 320 struct sway_workspace *workspace = output->workspaces->items[i];
274 if ((result = workspace_find_container(workspace, test, data))) { 321 if ((result = workspace_find_container(workspace, test, data))) {
275 return result; 322 return result;
276 } 323 }
@@ -279,8 +326,8 @@ struct sway_container *output_find_container(struct sway_container *output,
279} 326}
280 327
281static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { 328static int sort_workspace_cmp_qsort(const void *_a, const void *_b) {
282 struct sway_container *a = *(void **)_a; 329 struct sway_workspace *a = *(void **)_a;
283 struct sway_container *b = *(void **)_b; 330 struct sway_workspace *b = *(void **)_b;
284 331
285 if (isdigit(a->name[0]) && isdigit(b->name[0])) { 332 if (isdigit(a->name[0]) && isdigit(b->name[0])) {
286 int a_num = strtol(a->name, NULL, 10); 333 int a_num = strtol(a->name, NULL, 10);
@@ -294,6 +341,27 @@ static int sort_workspace_cmp_qsort(const void *_a, const void *_b) {
294 return 0; 341 return 0;
295} 342}
296 343
297void output_sort_workspaces(struct sway_container *output) { 344void output_sort_workspaces(struct sway_output *output) {
298 list_stable_sort(output->children, sort_workspace_cmp_qsort); 345 list_stable_sort(output->workspaces, sort_workspace_cmp_qsort);
346}
347
348void output_get_box(struct sway_output *output, struct wlr_box *box) {
349 box->x = output->wlr_output->lx;
350 box->y = output->wlr_output->ly;
351 box->width = output->wlr_output->width;
352 box->height = output->wlr_output->height;
353}
354
355enum sway_container_layout output_get_default_layout(
356 struct sway_output *output) {
357 if (config->default_layout != L_NONE) {
358 return config->default_layout;
359 }
360 if (config->default_orientation != L_NONE) {
361 return config->default_orientation;
362 }
363 if (output->wlr_output->height > output->wlr_output->width) {
364 return L_VERT;
365 }
366 return L_HORIZ;
299} 367}