diff options
Diffstat (limited to 'sway/config.c')
-rw-r--r-- | sway/config.c | 1449 |
1 files changed, 0 insertions, 1449 deletions
diff --git a/sway/config.c b/sway/config.c deleted file mode 100644 index aa40c49a..00000000 --- a/sway/config.c +++ /dev/null | |||
@@ -1,1449 +0,0 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #define _XOPEN_SOURCE 700 | ||
3 | #include <stdio.h> | ||
4 | #include <stdbool.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <unistd.h> | ||
7 | #include <libgen.h> | ||
8 | #include <wordexp.h> | ||
9 | #include <sys/types.h> | ||
10 | #include <sys/wait.h> | ||
11 | #include <sys/stat.h> | ||
12 | #include <signal.h> | ||
13 | #include <libinput.h> | ||
14 | #include <limits.h> | ||
15 | #include <float.h> | ||
16 | #include <dirent.h> | ||
17 | #include <strings.h> | ||
18 | #include <wlr/types/wlr_output.h> | ||
19 | #include "wayland-desktop-shell-server-protocol.h" | ||
20 | #include "sway/commands.h" | ||
21 | #include "sway/config.h" | ||
22 | #include "sway/layout.h" | ||
23 | #include "sway/input_state.h" | ||
24 | #include "sway/criteria.h" | ||
25 | #include "sway/input.h" | ||
26 | #include "sway/border.h" | ||
27 | #include "readline.h" | ||
28 | #include "stringop.h" | ||
29 | #include "list.h" | ||
30 | #include "log.h" | ||
31 | |||
32 | struct sway_config *config = NULL; | ||
33 | |||
34 | static void terminate_swaybar(pid_t pid); | ||
35 | |||
36 | static void free_variable(struct sway_variable *var) { | ||
37 | if (!var) { | ||
38 | return; | ||
39 | } | ||
40 | free(var->name); | ||
41 | free(var->value); | ||
42 | free(var); | ||
43 | } | ||
44 | |||
45 | static void free_binding(struct sway_binding *bind) { | ||
46 | if (!bind) { | ||
47 | return; | ||
48 | } | ||
49 | free_flat_list(bind->keys); | ||
50 | free(bind->command); | ||
51 | free(bind); | ||
52 | } | ||
53 | |||
54 | static void free_mode(struct sway_mode *mode) { | ||
55 | if (!mode) { | ||
56 | return; | ||
57 | } | ||
58 | free(mode->name); | ||
59 | int i; | ||
60 | for (i = 0; mode->bindings && i < mode->bindings->length; ++i) { | ||
61 | free_binding(mode->bindings->items[i]); | ||
62 | } | ||
63 | list_free(mode->bindings); | ||
64 | free(mode); | ||
65 | } | ||
66 | |||
67 | static void free_bar(struct bar_config *bar) { | ||
68 | if (!bar) { | ||
69 | return; | ||
70 | } | ||
71 | free(bar->mode); | ||
72 | free(bar->hidden_state); | ||
73 | #ifdef ENABLE_TRAY | ||
74 | free(bar->tray_output); | ||
75 | free(bar->icon_theme); | ||
76 | #endif | ||
77 | free(bar->status_command); | ||
78 | free(bar->font); | ||
79 | free(bar->separator_symbol); | ||
80 | int i; | ||
81 | for (i = 0; bar->bindings && i < bar->bindings->length; ++i) { | ||
82 | free_sway_mouse_binding(bar->bindings->items[i]); | ||
83 | } | ||
84 | list_free(bar->bindings); | ||
85 | |||
86 | if (bar->outputs) { | ||
87 | free_flat_list(bar->outputs); | ||
88 | } | ||
89 | |||
90 | if (bar->pid != 0) { | ||
91 | terminate_swaybar(bar->pid); | ||
92 | } | ||
93 | |||
94 | free(bar->colors.background); | ||
95 | free(bar->colors.statusline); | ||
96 | free(bar->colors.separator); | ||
97 | free(bar->colors.focused_background); | ||
98 | free(bar->colors.focused_statusline); | ||
99 | free(bar->colors.focused_separator); | ||
100 | free(bar->colors.focused_workspace_border); | ||
101 | free(bar->colors.focused_workspace_bg); | ||
102 | free(bar->colors.focused_workspace_text); | ||
103 | free(bar->colors.active_workspace_border); | ||
104 | free(bar->colors.active_workspace_bg); | ||
105 | free(bar->colors.active_workspace_text); | ||
106 | free(bar->colors.inactive_workspace_border); | ||
107 | free(bar->colors.inactive_workspace_bg); | ||
108 | free(bar->colors.inactive_workspace_text); | ||
109 | free(bar->colors.urgent_workspace_border); | ||
110 | free(bar->colors.urgent_workspace_bg); | ||
111 | free(bar->colors.urgent_workspace_text); | ||
112 | free(bar->colors.binding_mode_border); | ||
113 | free(bar->colors.binding_mode_bg); | ||
114 | free(bar->colors.binding_mode_text); | ||
115 | |||
116 | free(bar); | ||
117 | } | ||
118 | |||
119 | void free_input_config(struct input_config *ic) { | ||
120 | if (!ic) { | ||
121 | return; | ||
122 | } | ||
123 | free(ic->identifier); | ||
124 | free(ic); | ||
125 | } | ||
126 | |||
127 | void free_output_config(struct output_config *oc) { | ||
128 | if (!oc) { | ||
129 | return; | ||
130 | } | ||
131 | free(oc->name); | ||
132 | free(oc->background); | ||
133 | free(oc->background_option); | ||
134 | free(oc); | ||
135 | } | ||
136 | |||
137 | static void free_workspace_output(struct workspace_output *wo) { | ||
138 | if (!wo) { | ||
139 | return; | ||
140 | } | ||
141 | free(wo->output); | ||
142 | free(wo->workspace); | ||
143 | free(wo); | ||
144 | } | ||
145 | |||
146 | static void pid_workspace_cleanup() { | ||
147 | struct timespec ts; | ||
148 | struct pid_workspace *pw = NULL; | ||
149 | |||
150 | clock_gettime(CLOCK_MONOTONIC, &ts); | ||
151 | |||
152 | // work backwards through list and remove any entries | ||
153 | // older than PID_WORKSPACE_TIMEOUT | ||
154 | for (int i = config->pid_workspaces->length - 1; i > -1; i--) { | ||
155 | pw = config->pid_workspaces->items[i]; | ||
156 | |||
157 | if (difftime(ts.tv_sec, *pw->time_added) >= PID_WORKSPACE_TIMEOUT) { | ||
158 | free_pid_workspace(config->pid_workspaces->items[i]); | ||
159 | list_del(config->pid_workspaces, i); | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | |||
164 | // de-dupe pid_workspaces to ensure pid uniqueness | ||
165 | void pid_workspace_add(struct pid_workspace *pw) { | ||
166 | struct pid_workspace *list_pw = NULL; | ||
167 | struct timespec ts; | ||
168 | time_t *now = malloc(sizeof(time_t)); | ||
169 | if (!now) { | ||
170 | sway_log(L_ERROR, "Allocating time for pid_workspace failed"); | ||
171 | return; | ||
172 | } | ||
173 | |||
174 | pid_workspace_cleanup(); | ||
175 | |||
176 | // add current time to pw | ||
177 | clock_gettime(CLOCK_MONOTONIC, &ts); | ||
178 | *now = ts.tv_sec; | ||
179 | |||
180 | pw->time_added = now; | ||
181 | |||
182 | // work backwards through list and delete any entries that | ||
183 | // have the same pid as that in our new pid_workspace | ||
184 | for (int i = config->pid_workspaces->length - 1; i > -1; i--) { | ||
185 | list_pw = config->pid_workspaces->items[i]; | ||
186 | |||
187 | if (pw->pid == list_pw->pid) { | ||
188 | free_pid_workspace(config->pid_workspaces->items[i]); | ||
189 | list_del(config->pid_workspaces, i); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | list_add(config->pid_workspaces, pw); | ||
194 | } | ||
195 | |||
196 | void free_pid_workspace(struct pid_workspace *pw) { | ||
197 | if (!pw) { | ||
198 | return; | ||
199 | } | ||
200 | free(pw->pid); | ||
201 | free(pw->workspace); | ||
202 | free(pw->time_added); | ||
203 | free(pw); | ||
204 | } | ||
205 | |||
206 | void free_command_policy(struct command_policy *policy) { | ||
207 | if (!policy) { | ||
208 | return; | ||
209 | } | ||
210 | free(policy->command); | ||
211 | free(policy); | ||
212 | } | ||
213 | |||
214 | void free_feature_policy(struct feature_policy *policy) { | ||
215 | if (!policy) { | ||
216 | return; | ||
217 | } | ||
218 | free(policy->program); | ||
219 | free(policy); | ||
220 | } | ||
221 | |||
222 | void free_config(struct sway_config *config) { | ||
223 | if (!config) { | ||
224 | return; | ||
225 | } | ||
226 | int i; | ||
227 | for (i = 0; config->symbols && i < config->symbols->length; ++i) { | ||
228 | free_variable(config->symbols->items[i]); | ||
229 | } | ||
230 | list_free(config->symbols); | ||
231 | |||
232 | for (i = 0; config->modes && i < config->modes->length; ++i) { | ||
233 | free_mode(config->modes->items[i]); | ||
234 | } | ||
235 | list_free(config->modes); | ||
236 | |||
237 | for (i = 0; config->bars && i < config->bars->length; ++i) { | ||
238 | free_bar(config->bars->items[i]); | ||
239 | } | ||
240 | list_free(config->bars); | ||
241 | |||
242 | free_flat_list(config->cmd_queue); | ||
243 | |||
244 | for (i = 0; config->workspace_outputs && i < config->workspace_outputs->length; ++i) { | ||
245 | free_workspace_output(config->workspace_outputs->items[i]); | ||
246 | } | ||
247 | list_free(config->workspace_outputs); | ||
248 | |||
249 | for (i = 0; config->pid_workspaces && i < config->pid_workspaces->length; ++i) { | ||
250 | free_pid_workspace(config->pid_workspaces->items[i]); | ||
251 | } | ||
252 | list_free(config->pid_workspaces); | ||
253 | |||
254 | for (i = 0; config->criteria && i < config->criteria->length; ++i) { | ||
255 | free_criteria(config->criteria->items[i]); | ||
256 | } | ||
257 | list_free(config->criteria); | ||
258 | |||
259 | for (i = 0; config->no_focus && i < config->no_focus->length; ++i) { | ||
260 | free_criteria(config->no_focus->items[i]); | ||
261 | } | ||
262 | list_free(config->no_focus); | ||
263 | |||
264 | for (i = 0; config->input_configs && i < config->input_configs->length; ++i) { | ||
265 | free_input_config(config->input_configs->items[i]); | ||
266 | } | ||
267 | list_free(config->input_configs); | ||
268 | |||
269 | for (i = 0; config->output_configs && i < config->output_configs->length; ++i) { | ||
270 | free_output_config(config->output_configs->items[i]); | ||
271 | } | ||
272 | list_free(config->output_configs); | ||
273 | |||
274 | for (i = 0; config->command_policies && i < config->command_policies->length; ++i) { | ||
275 | free_command_policy(config->command_policies->items[i]); | ||
276 | } | ||
277 | list_free(config->command_policies); | ||
278 | |||
279 | for (i = 0; config->feature_policies && i < config->feature_policies->length; ++i) { | ||
280 | free_feature_policy(config->feature_policies->items[i]); | ||
281 | } | ||
282 | list_free(config->feature_policies); | ||
283 | |||
284 | list_free(config->active_bar_modifiers); | ||
285 | free_flat_list(config->config_chain); | ||
286 | free(config->font); | ||
287 | free(config->floating_scroll_up_cmd); | ||
288 | free(config->floating_scroll_down_cmd); | ||
289 | free(config->floating_scroll_left_cmd); | ||
290 | free(config->floating_scroll_right_cmd); | ||
291 | free(config); | ||
292 | } | ||
293 | |||
294 | |||
295 | static bool file_exists(const char *path) { | ||
296 | return path && access(path, R_OK) != -1; | ||
297 | } | ||
298 | |||
299 | static void config_defaults(struct sway_config *config) { | ||
300 | if (!(config->symbols = create_list())) goto cleanup; | ||
301 | if (!(config->modes = create_list())) goto cleanup; | ||
302 | if (!(config->bars = create_list())) goto cleanup; | ||
303 | if (!(config->workspace_outputs = create_list())) goto cleanup; | ||
304 | if (!(config->pid_workspaces = create_list())) goto cleanup; | ||
305 | if (!(config->criteria = create_list())) goto cleanup; | ||
306 | if (!(config->no_focus = create_list())) goto cleanup; | ||
307 | if (!(config->input_configs = create_list())) goto cleanup; | ||
308 | if (!(config->output_configs = create_list())) goto cleanup; | ||
309 | |||
310 | if (!(config->cmd_queue = create_list())) goto cleanup; | ||
311 | |||
312 | if (!(config->current_mode = malloc(sizeof(struct sway_mode)))) goto cleanup; | ||
313 | if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup; | ||
314 | strcpy(config->current_mode->name, "default"); | ||
315 | if (!(config->current_mode->bindings = create_list())) goto cleanup; | ||
316 | list_add(config->modes, config->current_mode); | ||
317 | |||
318 | config->floating_mod = 0; | ||
319 | config->dragging_key = M_LEFT_CLICK; | ||
320 | config->resizing_key = M_RIGHT_CLICK; | ||
321 | if (!(config->floating_scroll_up_cmd = strdup(""))) goto cleanup; | ||
322 | if (!(config->floating_scroll_down_cmd = strdup(""))) goto cleanup; | ||
323 | if (!(config->floating_scroll_left_cmd = strdup(""))) goto cleanup; | ||
324 | if (!(config->floating_scroll_right_cmd = strdup(""))) goto cleanup; | ||
325 | config->default_layout = L_NONE; | ||
326 | config->default_orientation = L_NONE; | ||
327 | if (!(config->font = strdup("monospace 10"))) goto cleanup; | ||
328 | config->font_height = get_font_text_height(config->font); | ||
329 | |||
330 | // floating view | ||
331 | config->floating_maximum_width = 0; | ||
332 | config->floating_maximum_height = 0; | ||
333 | config->floating_minimum_width = 75; | ||
334 | config->floating_minimum_height = 50; | ||
335 | |||
336 | // Flags | ||
337 | config->focus_follows_mouse = true; | ||
338 | config->mouse_warping = true; | ||
339 | config->reloading = false; | ||
340 | config->active = false; | ||
341 | config->failed = false; | ||
342 | config->auto_back_and_forth = false; | ||
343 | config->seamless_mouse = true; | ||
344 | config->reading = false; | ||
345 | config->show_marks = true; | ||
346 | |||
347 | config->edge_gaps = true; | ||
348 | config->smart_gaps = false; | ||
349 | config->gaps_inner = 0; | ||
350 | config->gaps_outer = 0; | ||
351 | |||
352 | if (!(config->active_bar_modifiers = create_list())) goto cleanup; | ||
353 | |||
354 | if (!(config->config_chain = create_list())) goto cleanup; | ||
355 | config->current_config = NULL; | ||
356 | |||
357 | // borders | ||
358 | config->border = B_NORMAL; | ||
359 | config->floating_border = B_NORMAL; | ||
360 | config->border_thickness = 2; | ||
361 | config->floating_border_thickness = 2; | ||
362 | config->hide_edge_borders = E_NONE; | ||
363 | |||
364 | // border colors | ||
365 | config->border_colors.focused.border = 0x4C7899FF; | ||
366 | config->border_colors.focused.background = 0x285577FF; | ||
367 | config->border_colors.focused.text = 0xFFFFFFFF; | ||
368 | config->border_colors.focused.indicator = 0x2E9EF4FF; | ||
369 | config->border_colors.focused.child_border = 0x285577FF; | ||
370 | |||
371 | config->border_colors.focused_inactive.border = 0x333333FF; | ||
372 | config->border_colors.focused_inactive.background = 0x5F676AFF; | ||
373 | config->border_colors.focused_inactive.text = 0xFFFFFFFF; | ||
374 | config->border_colors.focused_inactive.indicator = 0x484E50FF; | ||
375 | config->border_colors.focused_inactive.child_border = 0x5F676AFF; | ||
376 | |||
377 | config->border_colors.unfocused.border = 0x333333FF; | ||
378 | config->border_colors.unfocused.background = 0x222222FF; | ||
379 | config->border_colors.unfocused.text = 0x888888FF; | ||
380 | config->border_colors.unfocused.indicator = 0x292D2EFF; | ||
381 | config->border_colors.unfocused.child_border = 0x222222FF; | ||
382 | |||
383 | config->border_colors.urgent.border = 0x2F343AFF; | ||
384 | config->border_colors.urgent.background = 0x900000FF; | ||
385 | config->border_colors.urgent.text = 0xFFFFFFFF; | ||
386 | config->border_colors.urgent.indicator = 0x900000FF; | ||
387 | config->border_colors.urgent.child_border = 0x900000FF; | ||
388 | |||
389 | config->border_colors.placeholder.border = 0x000000FF; | ||
390 | config->border_colors.placeholder.background = 0x0C0C0CFF; | ||
391 | config->border_colors.placeholder.text = 0xFFFFFFFF; | ||
392 | config->border_colors.placeholder.indicator = 0x000000FF; | ||
393 | config->border_colors.placeholder.child_border = 0x0C0C0CFF; | ||
394 | |||
395 | config->border_colors.background = 0xFFFFFFFF; | ||
396 | |||
397 | // Security | ||
398 | if (!(config->command_policies = create_list())) goto cleanup; | ||
399 | if (!(config->feature_policies = create_list())) goto cleanup; | ||
400 | if (!(config->ipc_policies = create_list())) goto cleanup; | ||
401 | |||
402 | return; | ||
403 | cleanup: | ||
404 | sway_abort("Unable to allocate config structures"); | ||
405 | } | ||
406 | |||
407 | static int compare_modifiers(const void *left, const void *right) { | ||
408 | uint32_t a = *(uint32_t *)left; | ||
409 | uint32_t b = *(uint32_t *)right; | ||
410 | |||
411 | return a - b; | ||
412 | } | ||
413 | |||
414 | void update_active_bar_modifiers() { | ||
415 | if (config->active_bar_modifiers->length > 0) { | ||
416 | list_free(config->active_bar_modifiers); | ||
417 | config->active_bar_modifiers = create_list(); | ||
418 | } | ||
419 | |||
420 | struct bar_config *bar; | ||
421 | int i; | ||
422 | for (i = 0; i < config->bars->length; ++i) { | ||
423 | bar = config->bars->items[i]; | ||
424 | if (strcmp(bar->mode, "hide") == 0 && strcmp(bar->hidden_state, "hide") == 0) { | ||
425 | if (list_seq_find(config->active_bar_modifiers, compare_modifiers, &bar->modifier) < 0) { | ||
426 | list_add(config->active_bar_modifiers, &bar->modifier); | ||
427 | } | ||
428 | } | ||
429 | } | ||
430 | } | ||
431 | |||
432 | static char *get_config_path(void) { | ||
433 | static const char *config_paths[] = { | ||
434 | "$HOME/.sway/config", | ||
435 | "$XDG_CONFIG_HOME/sway/config", | ||
436 | "$HOME/.i3/config", | ||
437 | "$XDG_CONFIG_HOME/i3/config", | ||
438 | SYSCONFDIR "/sway/config", | ||
439 | SYSCONFDIR "/i3/config", | ||
440 | }; | ||
441 | |||
442 | if (!getenv("XDG_CONFIG_HOME")) { | ||
443 | char *home = getenv("HOME"); | ||
444 | char *config_home = malloc(strlen(home) + strlen("/.config") + 1); | ||
445 | if (!config_home) { | ||
446 | sway_log(L_ERROR, "Unable to allocate $HOME/.config"); | ||
447 | } else { | ||
448 | strcpy(config_home, home); | ||
449 | strcat(config_home, "/.config"); | ||
450 | setenv("XDG_CONFIG_HOME", config_home, 1); | ||
451 | sway_log(L_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home); | ||
452 | free(config_home); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | wordexp_t p; | ||
457 | char *path; | ||
458 | |||
459 | int i; | ||
460 | for (i = 0; i < (int)(sizeof(config_paths) / sizeof(char *)); ++i) { | ||
461 | if (wordexp(config_paths[i], &p, 0) == 0) { | ||
462 | path = strdup(p.we_wordv[0]); | ||
463 | wordfree(&p); | ||
464 | if (file_exists(path)) { | ||
465 | return path; | ||
466 | } | ||
467 | } | ||
468 | } | ||
469 | |||
470 | return NULL; // Not reached | ||
471 | } | ||
472 | |||
473 | const char *current_config_path; | ||
474 | |||
475 | static bool load_config(const char *path, struct sway_config *config) { | ||
476 | sway_log(L_INFO, "Loading config from %s", path); | ||
477 | current_config_path = path; | ||
478 | |||
479 | struct stat sb; | ||
480 | if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { | ||
481 | return false; | ||
482 | } | ||
483 | |||
484 | if (path == NULL) { | ||
485 | sway_log(L_ERROR, "Unable to find a config file!"); | ||
486 | return false; | ||
487 | } | ||
488 | |||
489 | FILE *f = fopen(path, "r"); | ||
490 | if (!f) { | ||
491 | sway_log(L_ERROR, "Unable to open %s for reading", path); | ||
492 | return false; | ||
493 | } | ||
494 | |||
495 | bool config_load_success = read_config(f, config); | ||
496 | fclose(f); | ||
497 | |||
498 | if (!config_load_success) { | ||
499 | sway_log(L_ERROR, "Error(s) loading config!"); | ||
500 | } | ||
501 | |||
502 | current_config_path = NULL; | ||
503 | return true; | ||
504 | } | ||
505 | |||
506 | static int qstrcmp(const void* a, const void* b) { | ||
507 | return strcmp(*((char**) a), *((char**) b)); | ||
508 | } | ||
509 | |||
510 | bool load_main_config(const char *file, bool is_active) { | ||
511 | input_init(); | ||
512 | |||
513 | char *path; | ||
514 | if (file != NULL) { | ||
515 | path = strdup(file); | ||
516 | } else { | ||
517 | path = get_config_path(); | ||
518 | } | ||
519 | |||
520 | struct sway_config *old_config = config; | ||
521 | config = calloc(1, sizeof(struct sway_config)); | ||
522 | if (!config) { | ||
523 | sway_abort("Unable to allocate config"); | ||
524 | } | ||
525 | |||
526 | config_defaults(config); | ||
527 | if (is_active) { | ||
528 | sway_log(L_DEBUG, "Performing configuration file reload"); | ||
529 | config->reloading = true; | ||
530 | config->active = true; | ||
531 | } | ||
532 | |||
533 | config->current_config = path; | ||
534 | list_add(config->config_chain, path); | ||
535 | |||
536 | config->reading = true; | ||
537 | |||
538 | // Read security configs | ||
539 | bool success = true; | ||
540 | DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); | ||
541 | if (!dir) { | ||
542 | sway_log(L_ERROR, "%s does not exist, sway will have no security configuration" | ||
543 | " and will probably be broken", SYSCONFDIR "/sway/security.d"); | ||
544 | } else { | ||
545 | list_t *secconfigs = create_list(); | ||
546 | char *base = SYSCONFDIR "/sway/security.d/"; | ||
547 | struct dirent *ent = readdir(dir); | ||
548 | struct stat s; | ||
549 | while (ent != NULL) { | ||
550 | char *_path = malloc(strlen(ent->d_name) + strlen(base) + 1); | ||
551 | strcpy(_path, base); | ||
552 | strcat(_path, ent->d_name); | ||
553 | lstat(_path, &s); | ||
554 | if (S_ISREG(s.st_mode) && ent->d_name[0] != '.') { | ||
555 | list_add(secconfigs, _path); | ||
556 | } | ||
557 | else { | ||
558 | free(_path); | ||
559 | } | ||
560 | ent = readdir(dir); | ||
561 | } | ||
562 | closedir(dir); | ||
563 | |||
564 | list_qsort(secconfigs, qstrcmp); | ||
565 | for (int i = 0; i < secconfigs->length; ++i) { | ||
566 | char *_path = secconfigs->items[i]; | ||
567 | if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || (((s.st_mode & 0777) != 0644) && (s.st_mode & 0777) != 0444)) { | ||
568 | sway_log(L_ERROR, "Refusing to load %s - it must be owned by root and mode 644 or 444", _path); | ||
569 | success = false; | ||
570 | } else { | ||
571 | success = success && load_config(_path, config); | ||
572 | } | ||
573 | } | ||
574 | |||
575 | free_flat_list(secconfigs); | ||
576 | } | ||
577 | |||
578 | success = success && load_config(path, config); | ||
579 | |||
580 | if (is_active) { | ||
581 | config->reloading = false; | ||
582 | } | ||
583 | |||
584 | if (old_config) { | ||
585 | free_config(old_config); | ||
586 | } | ||
587 | config->reading = false; | ||
588 | |||
589 | if (success) { | ||
590 | update_active_bar_modifiers(); | ||
591 | } | ||
592 | |||
593 | return success; | ||
594 | } | ||
595 | |||
596 | static bool load_include_config(const char *path, const char *parent_dir, struct sway_config *config) { | ||
597 | // save parent config | ||
598 | const char *parent_config = config->current_config; | ||
599 | |||
600 | char *full_path = strdup(path); | ||
601 | int len = strlen(path); | ||
602 | if (len >= 1 && path[0] != '/') { | ||
603 | len = len + strlen(parent_dir) + 2; | ||
604 | full_path = malloc(len * sizeof(char)); | ||
605 | if (!full_path) { | ||
606 | sway_log(L_ERROR, "Unable to allocate full path to included config"); | ||
607 | return false; | ||
608 | } | ||
609 | snprintf(full_path, len, "%s/%s", parent_dir, path); | ||
610 | } | ||
611 | |||
612 | char *real_path = realpath(full_path, NULL); | ||
613 | free(full_path); | ||
614 | |||
615 | if (real_path == NULL) { | ||
616 | sway_log(L_DEBUG, "%s not found.", path); | ||
617 | return false; | ||
618 | } | ||
619 | |||
620 | // check if config has already been included | ||
621 | int j; | ||
622 | for (j = 0; j < config->config_chain->length; ++j) { | ||
623 | char *old_path = config->config_chain->items[j]; | ||
624 | if (strcmp(real_path, old_path) == 0) { | ||
625 | sway_log(L_DEBUG, "%s already included once, won't be included again.", real_path); | ||
626 | free(real_path); | ||
627 | return false; | ||
628 | } | ||
629 | } | ||
630 | |||
631 | config->current_config = real_path; | ||
632 | list_add(config->config_chain, real_path); | ||
633 | int index = config->config_chain->length - 1; | ||
634 | |||
635 | if (!load_config(real_path, config)) { | ||
636 | free(real_path); | ||
637 | config->current_config = parent_config; | ||
638 | list_del(config->config_chain, index); | ||
639 | return false; | ||
640 | } | ||
641 | |||
642 | // restore current_config | ||
643 | config->current_config = parent_config; | ||
644 | return true; | ||
645 | } | ||
646 | |||
647 | bool load_include_configs(const char *path, struct sway_config *config) { | ||
648 | char *wd = getcwd(NULL, 0); | ||
649 | char *parent_path = strdup(config->current_config); | ||
650 | const char *parent_dir = dirname(parent_path); | ||
651 | |||
652 | if (chdir(parent_dir) < 0) { | ||
653 | free(parent_path); | ||
654 | free(wd); | ||
655 | return false; | ||
656 | } | ||
657 | |||
658 | wordexp_t p; | ||
659 | |||
660 | if (wordexp(path, &p, 0) < 0) { | ||
661 | free(parent_path); | ||
662 | free(wd); | ||
663 | return false; | ||
664 | } | ||
665 | |||
666 | char **w = p.we_wordv; | ||
667 | size_t i; | ||
668 | for (i = 0; i < p.we_wordc; ++i) { | ||
669 | load_include_config(w[i], parent_dir, config); | ||
670 | } | ||
671 | free(parent_path); | ||
672 | wordfree(&p); | ||
673 | |||
674 | // restore wd | ||
675 | if (chdir(wd) < 0) { | ||
676 | free(wd); | ||
677 | sway_log(L_ERROR, "failed to restore working directory"); | ||
678 | return false; | ||
679 | } | ||
680 | |||
681 | free(wd); | ||
682 | return true; | ||
683 | } | ||
684 | |||
685 | struct cmd_results *check_security_config() { | ||
686 | if (!current_config_path || strncmp(SYSCONFDIR "/sway/security.d/", current_config_path, | ||
687 | strlen(SYSCONFDIR "/sway/security.d/")) != 0) { | ||
688 | return cmd_results_new(CMD_INVALID, "permit", | ||
689 | "This command is only permitted to run from " SYSCONFDIR "/sway/security.d/*"); | ||
690 | } | ||
691 | return NULL; | ||
692 | } | ||
693 | |||
694 | bool read_config(FILE *file, struct sway_config *config) { | ||
695 | bool success = true; | ||
696 | enum cmd_status block = CMD_BLOCK_END; | ||
697 | |||
698 | int line_number = 0; | ||
699 | char *line; | ||
700 | while (!feof(file)) { | ||
701 | line = read_line(file); | ||
702 | if (!line) { | ||
703 | continue; | ||
704 | } | ||
705 | line_number++; | ||
706 | line = strip_whitespace(line); | ||
707 | if (line[0] == '#') { | ||
708 | free(line); | ||
709 | continue; | ||
710 | } | ||
711 | struct cmd_results *res; | ||
712 | if (block == CMD_BLOCK_COMMANDS) { | ||
713 | // Special case | ||
714 | res = config_commands_command(line); | ||
715 | } else { | ||
716 | res = config_command(line, block); | ||
717 | } | ||
718 | switch(res->status) { | ||
719 | case CMD_FAILURE: | ||
720 | case CMD_INVALID: | ||
721 | sway_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number, line, | ||
722 | res->error, config->current_config); | ||
723 | success = false; | ||
724 | break; | ||
725 | |||
726 | case CMD_DEFER: | ||
727 | sway_log(L_DEBUG, "Defferring command `%s'", line); | ||
728 | list_add(config->cmd_queue, strdup(line)); | ||
729 | break; | ||
730 | |||
731 | case CMD_BLOCK_MODE: | ||
732 | if (block == CMD_BLOCK_END) { | ||
733 | block = CMD_BLOCK_MODE; | ||
734 | } else { | ||
735 | sway_log(L_ERROR, "Invalid block '%s'", line); | ||
736 | } | ||
737 | break; | ||
738 | |||
739 | case CMD_BLOCK_INPUT: | ||
740 | if (block == CMD_BLOCK_END) { | ||
741 | block = CMD_BLOCK_INPUT; | ||
742 | } else { | ||
743 | sway_log(L_ERROR, "Invalid block '%s'", line); | ||
744 | } | ||
745 | break; | ||
746 | |||
747 | case CMD_BLOCK_BAR: | ||
748 | if (block == CMD_BLOCK_END) { | ||
749 | block = CMD_BLOCK_BAR; | ||
750 | } else { | ||
751 | sway_log(L_ERROR, "Invalid block '%s'", line); | ||
752 | } | ||
753 | break; | ||
754 | |||
755 | case CMD_BLOCK_BAR_COLORS: | ||
756 | if (block == CMD_BLOCK_BAR) { | ||
757 | block = CMD_BLOCK_BAR_COLORS; | ||
758 | } else { | ||
759 | sway_log(L_ERROR, "Invalid block '%s'", line); | ||
760 | } | ||
761 | break; | ||
762 | |||
763 | case CMD_BLOCK_COMMANDS: | ||
764 | if (block == CMD_BLOCK_END) { | ||
765 | block = CMD_BLOCK_COMMANDS; | ||
766 | } else { | ||
767 | sway_log(L_ERROR, "Invalid block '%s'", line); | ||
768 | } | ||
769 | break; | ||
770 | |||
771 | case CMD_BLOCK_IPC: | ||
772 | if (block == CMD_BLOCK_END) { | ||
773 | block = CMD_BLOCK_IPC; | ||
774 | } else { | ||
775 | sway_log(L_ERROR, "Invalid block '%s'", line); | ||
776 | } | ||
777 | break; | ||
778 | |||
779 | case CMD_BLOCK_IPC_EVENTS: | ||
780 | if (block == CMD_BLOCK_IPC) { | ||
781 | block = CMD_BLOCK_IPC_EVENTS; | ||
782 | } else { | ||
783 | sway_log(L_ERROR, "Invalid block '%s'", line); | ||
784 | } | ||
785 | break; | ||
786 | |||
787 | case CMD_BLOCK_END: | ||
788 | switch(block) { | ||
789 | case CMD_BLOCK_MODE: | ||
790 | sway_log(L_DEBUG, "End of mode block"); | ||
791 | config->current_mode = config->modes->items[0]; | ||
792 | block = CMD_BLOCK_END; | ||
793 | break; | ||
794 | |||
795 | case CMD_BLOCK_INPUT: | ||
796 | sway_log(L_DEBUG, "End of input block"); | ||
797 | current_input_config = NULL; | ||
798 | block = CMD_BLOCK_END; | ||
799 | break; | ||
800 | |||
801 | case CMD_BLOCK_BAR: | ||
802 | sway_log(L_DEBUG, "End of bar block"); | ||
803 | config->current_bar = NULL; | ||
804 | block = CMD_BLOCK_END; | ||
805 | break; | ||
806 | |||
807 | case CMD_BLOCK_BAR_COLORS: | ||
808 | sway_log(L_DEBUG, "End of bar colors block"); | ||
809 | block = CMD_BLOCK_BAR; | ||
810 | break; | ||
811 | |||
812 | case CMD_BLOCK_COMMANDS: | ||
813 | sway_log(L_DEBUG, "End of commands block"); | ||
814 | block = CMD_BLOCK_END; | ||
815 | break; | ||
816 | |||
817 | case CMD_BLOCK_IPC: | ||
818 | sway_log(L_DEBUG, "End of IPC block"); | ||
819 | block = CMD_BLOCK_END; | ||
820 | break; | ||
821 | |||
822 | case CMD_BLOCK_IPC_EVENTS: | ||
823 | sway_log(L_DEBUG, "End of IPC events block"); | ||
824 | block = CMD_BLOCK_IPC; | ||
825 | break; | ||
826 | |||
827 | case CMD_BLOCK_END: | ||
828 | sway_log(L_ERROR, "Unmatched }"); | ||
829 | break; | ||
830 | |||
831 | default:; | ||
832 | } | ||
833 | default:; | ||
834 | } | ||
835 | free(line); | ||
836 | free_cmd_results(res); | ||
837 | } | ||
838 | |||
839 | return success; | ||
840 | } | ||
841 | |||
842 | int input_identifier_cmp(const void *item, const void *data) { | ||
843 | const struct input_config *ic = item; | ||
844 | const char *identifier = data; | ||
845 | return strcmp(ic->identifier, identifier); | ||
846 | } | ||
847 | |||
848 | int output_name_cmp(const void *item, const void *data) { | ||
849 | const struct output_config *output = item; | ||
850 | const char *name = data; | ||
851 | |||
852 | return strcmp(output->name, name); | ||
853 | } | ||
854 | |||
855 | void merge_input_config(struct input_config *dst, struct input_config *src) { | ||
856 | if (src->identifier) { | ||
857 | if (dst->identifier) { | ||
858 | free(dst->identifier); | ||
859 | } | ||
860 | dst->identifier = strdup(src->identifier); | ||
861 | } | ||
862 | if (src->accel_profile != INT_MIN) { | ||
863 | dst->accel_profile = src->accel_profile; | ||
864 | } | ||
865 | if (src->click_method != INT_MIN) { | ||
866 | dst->click_method = src->click_method; | ||
867 | } | ||
868 | if (src->drag_lock != INT_MIN) { | ||
869 | dst->drag_lock = src->drag_lock; | ||
870 | } | ||
871 | if (src->dwt != INT_MIN) { | ||
872 | dst->dwt = src->dwt; | ||
873 | } | ||
874 | if (src->middle_emulation != INT_MIN) { | ||
875 | dst->middle_emulation = src->middle_emulation; | ||
876 | } | ||
877 | if (src->natural_scroll != INT_MIN) { | ||
878 | dst->natural_scroll = src->natural_scroll; | ||
879 | } | ||
880 | if (src->pointer_accel != FLT_MIN) { | ||
881 | dst->pointer_accel = src->pointer_accel; | ||
882 | } | ||
883 | if (src->scroll_method != INT_MIN) { | ||
884 | dst->scroll_method = src->scroll_method; | ||
885 | } | ||
886 | if (src->send_events != INT_MIN) { | ||
887 | dst->send_events = src->send_events; | ||
888 | } | ||
889 | if (src->tap != INT_MIN) { | ||
890 | dst->tap = src->tap; | ||
891 | } | ||
892 | } | ||
893 | |||
894 | void merge_output_config(struct output_config *dst, struct output_config *src) { | ||
895 | if (src->name) { | ||
896 | if (dst->name) { | ||
897 | free(dst->name); | ||
898 | } | ||
899 | dst->name = strdup(src->name); | ||
900 | } | ||
901 | if (src->enabled != -1) { | ||
902 | dst->enabled = src->enabled; | ||
903 | } | ||
904 | if (src->width != -1) { | ||
905 | dst->width = src->width; | ||
906 | } | ||
907 | if (src->height != -1) { | ||
908 | dst->height = src->height; | ||
909 | } | ||
910 | if (src->x != -1) { | ||
911 | dst->x = src->x; | ||
912 | } | ||
913 | if (src->y != -1) { | ||
914 | dst->y = src->y; | ||
915 | } | ||
916 | if (src->scale != -1) { | ||
917 | dst->scale = src->scale; | ||
918 | } | ||
919 | if (src->background) { | ||
920 | if (dst->background) { | ||
921 | free(dst->background); | ||
922 | } | ||
923 | dst->background = strdup(src->background); | ||
924 | } | ||
925 | if (src->background_option) { | ||
926 | if (dst->background_option) { | ||
927 | free(dst->background_option); | ||
928 | } | ||
929 | dst->background_option = strdup(src->background_option); | ||
930 | } | ||
931 | } | ||
932 | |||
933 | static void invoke_swaybar(struct bar_config *bar) { | ||
934 | return; // TODO WLR | ||
935 | sway_log(L_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); | ||
936 | // Pipe to communicate errors | ||
937 | int filedes[2]; | ||
938 | if (pipe(filedes) == -1) { | ||
939 | sway_log(L_ERROR, "Pipe setup failed! Cannot fork into bar"); | ||
940 | return; | ||
941 | } | ||
942 | |||
943 | bar->pid = fork(); | ||
944 | if (bar->pid == 0) { | ||
945 | close(filedes[0]); | ||
946 | if (!bar->swaybar_command) { | ||
947 | char *const cmd[] = { | ||
948 | "swaybar", | ||
949 | "-b", | ||
950 | bar->id, | ||
951 | NULL, | ||
952 | }; | ||
953 | |||
954 | close(filedes[1]); | ||
955 | execvp(cmd[0], cmd); | ||
956 | _exit(EXIT_SUCCESS); | ||
957 | } else { | ||
958 | // run custom swaybar | ||
959 | int len = strlen(bar->swaybar_command) + strlen(bar->id) + 5; | ||
960 | char *command = malloc(len * sizeof(char)); | ||
961 | if (!command) { | ||
962 | const char msg[] = "Unable to allocate swaybar command string"; | ||
963 | int len = sizeof(msg); | ||
964 | if (write(filedes[1], &len, sizeof(int))) {}; | ||
965 | if (write(filedes[1], msg, len)) {}; | ||
966 | close(filedes[1]); | ||
967 | _exit(EXIT_FAILURE); | ||
968 | } | ||
969 | snprintf(command, len, "%s -b %s", bar->swaybar_command, bar->id); | ||
970 | |||
971 | char *const cmd[] = { | ||
972 | "sh", | ||
973 | "-c", | ||
974 | command, | ||
975 | NULL, | ||
976 | }; | ||
977 | |||
978 | close(filedes[1]); | ||
979 | execvp(cmd[0], cmd); | ||
980 | free(command); | ||
981 | _exit(EXIT_SUCCESS); | ||
982 | } | ||
983 | } | ||
984 | close(filedes[0]); | ||
985 | int len; | ||
986 | if(read(filedes[1], &len, sizeof(int)) == sizeof(int)) { | ||
987 | char *buf = malloc(len); | ||
988 | if(!buf) { | ||
989 | sway_log(L_ERROR, "Cannot allocate error string"); | ||
990 | return; | ||
991 | } | ||
992 | if(read(filedes[1], buf, len)) { | ||
993 | sway_log(L_ERROR, "%s", buf); | ||
994 | } | ||
995 | free(buf); | ||
996 | } | ||
997 | close(filedes[1]); | ||
998 | } | ||
999 | |||
1000 | static void terminate_swaybar(pid_t pid) { | ||
1001 | int ret = kill(pid, SIGTERM); | ||
1002 | if (ret != 0) { | ||
1003 | sway_log(L_ERROR, "Unable to terminate swaybar [pid: %d]", pid); | ||
1004 | } else { | ||
1005 | int status; | ||
1006 | waitpid(pid, &status, 0); | ||
1007 | } | ||
1008 | } | ||
1009 | |||
1010 | void terminate_swaybg(pid_t pid) { | ||
1011 | int ret = kill(pid, SIGTERM); | ||
1012 | if (ret != 0) { | ||
1013 | sway_log(L_ERROR, "Unable to terminate swaybg [pid: %d]", pid); | ||
1014 | } else { | ||
1015 | int status; | ||
1016 | waitpid(pid, &status, 0); | ||
1017 | } | ||
1018 | } | ||
1019 | |||
1020 | static bool active_output(const char *name) { | ||
1021 | int i; | ||
1022 | swayc_t *cont = NULL; | ||
1023 | for (i = 0; i < root_container.children->length; ++i) { | ||
1024 | cont = root_container.children->items[i]; | ||
1025 | if (cont->type == C_OUTPUT && strcasecmp(name, cont->name) == 0) { | ||
1026 | return true; | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | return false; | ||
1031 | } | ||
1032 | |||
1033 | void load_swaybars() { | ||
1034 | // Check for bars | ||
1035 | list_t *bars = create_list(); | ||
1036 | struct bar_config *bar = NULL; | ||
1037 | int i; | ||
1038 | for (i = 0; i < config->bars->length; ++i) { | ||
1039 | bar = config->bars->items[i]; | ||
1040 | bool apply = false; | ||
1041 | if (bar->outputs) { | ||
1042 | int j; | ||
1043 | for (j = 0; j < bar->outputs->length; ++j) { | ||
1044 | char *o = bar->outputs->items[j]; | ||
1045 | if (!strcmp(o, "*") || active_output(o)) { | ||
1046 | apply = true; | ||
1047 | break; | ||
1048 | } | ||
1049 | } | ||
1050 | } else { | ||
1051 | apply = true; | ||
1052 | } | ||
1053 | if (apply) { | ||
1054 | list_add(bars, bar); | ||
1055 | } | ||
1056 | } | ||
1057 | |||
1058 | for (i = 0; i < bars->length; ++i) { | ||
1059 | bar = bars->items[i]; | ||
1060 | if (bar->pid != 0) { | ||
1061 | terminate_swaybar(bar->pid); | ||
1062 | } | ||
1063 | invoke_swaybar(bar); | ||
1064 | } | ||
1065 | |||
1066 | list_free(bars); | ||
1067 | } | ||
1068 | |||
1069 | void apply_input_config(struct input_config *ic, struct libinput_device *dev) { | ||
1070 | if (!ic) { | ||
1071 | return; | ||
1072 | } | ||
1073 | |||
1074 | sway_log(L_DEBUG, "apply_input_config(%s)", ic->identifier); | ||
1075 | |||
1076 | if (ic->accel_profile != INT_MIN) { | ||
1077 | sway_log(L_DEBUG, "apply_input_config(%s) accel_set_profile(%d)", ic->identifier, ic->accel_profile); | ||
1078 | libinput_device_config_accel_set_profile(dev, ic->accel_profile); | ||
1079 | } | ||
1080 | if (ic->click_method != INT_MIN) { | ||
1081 | sway_log(L_DEBUG, "apply_input_config(%s) click_set_method(%d)", ic->identifier, ic->click_method); | ||
1082 | libinput_device_config_click_set_method(dev, ic->click_method); | ||
1083 | } | ||
1084 | if (ic->drag_lock != INT_MIN) { | ||
1085 | sway_log(L_DEBUG, "apply_input_config(%s) tap_set_drag_lock_enabled(%d)", ic->identifier, ic->click_method); | ||
1086 | libinput_device_config_tap_set_drag_lock_enabled(dev, ic->drag_lock); | ||
1087 | } | ||
1088 | if (ic->dwt != INT_MIN) { | ||
1089 | sway_log(L_DEBUG, "apply_input_config(%s) dwt_set_enabled(%d)", ic->identifier, ic->dwt); | ||
1090 | libinput_device_config_dwt_set_enabled(dev, ic->dwt); | ||
1091 | } | ||
1092 | if (ic->left_handed != INT_MIN) { | ||
1093 | sway_log(L_DEBUG, "apply_input_config(%s) left_handed_set_enabled(%d)", ic->identifier, ic->left_handed); | ||
1094 | libinput_device_config_left_handed_set(dev, ic->left_handed); | ||
1095 | } | ||
1096 | if (ic->middle_emulation != INT_MIN) { | ||
1097 | sway_log(L_DEBUG, "apply_input_config(%s) middle_emulation_set_enabled(%d)", ic->identifier, ic->middle_emulation); | ||
1098 | libinput_device_config_middle_emulation_set_enabled(dev, ic->middle_emulation); | ||
1099 | } | ||
1100 | if (ic->natural_scroll != INT_MIN) { | ||
1101 | sway_log(L_DEBUG, "apply_input_config(%s) natural_scroll_set_enabled(%d)", ic->identifier, ic->natural_scroll); | ||
1102 | libinput_device_config_scroll_set_natural_scroll_enabled(dev, ic->natural_scroll); | ||
1103 | } | ||
1104 | if (ic->pointer_accel != FLT_MIN) { | ||
1105 | sway_log(L_DEBUG, "apply_input_config(%s) accel_set_speed(%f)", ic->identifier, ic->pointer_accel); | ||
1106 | libinput_device_config_accel_set_speed(dev, ic->pointer_accel); | ||
1107 | } | ||
1108 | if (ic->scroll_method != INT_MIN) { | ||
1109 | sway_log(L_DEBUG, "apply_input_config(%s) scroll_set_method(%d)", ic->identifier, ic->scroll_method); | ||
1110 | libinput_device_config_scroll_set_method(dev, ic->scroll_method); | ||
1111 | } | ||
1112 | if (ic->send_events != INT_MIN) { | ||
1113 | sway_log(L_DEBUG, "apply_input_config(%s) send_events_set_mode(%d)", ic->identifier, ic->send_events); | ||
1114 | libinput_device_config_send_events_set_mode(dev, ic->send_events); | ||
1115 | } | ||
1116 | if (ic->tap != INT_MIN) { | ||
1117 | sway_log(L_DEBUG, "apply_input_config(%s) tap_set_enabled(%d)", ic->identifier, ic->tap); | ||
1118 | libinput_device_config_tap_set_enabled(dev, ic->tap); | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | void apply_output_config(struct output_config *oc, swayc_t *output) { | ||
1123 | if (oc && oc->enabled == 0) { | ||
1124 | destroy_output(output); | ||
1125 | return; | ||
1126 | } | ||
1127 | |||
1128 | if (oc && oc->width > 0 && oc->height > 0) { | ||
1129 | output->width = oc->width; | ||
1130 | output->height = oc->height; | ||
1131 | |||
1132 | sway_log(L_DEBUG, "Set %s size to %ix%i (%d)", oc->name, oc->width, oc->height, oc->scale); | ||
1133 | // TODO WLR: modes | ||
1134 | //struct wlc_size new_size = { .w = oc->width, .h = oc->height }; | ||
1135 | //wlc_output_set_resolution(output->handle, &new_size, (uint32_t)oc->scale); | ||
1136 | } else if (oc) { | ||
1137 | //const struct wlc_size *new_size = wlc_output_get_resolution(output->handle); | ||
1138 | //wlc_output_set_resolution(output->handle, new_size, (uint32_t)oc->scale); | ||
1139 | } | ||
1140 | |||
1141 | // TODO WLR: wlr_output_layout | ||
1142 | // Find position for it | ||
1143 | if (oc && oc->x != -1 && oc->y != -1) { | ||
1144 | sway_log(L_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y); | ||
1145 | output->x = oc->x; | ||
1146 | output->y = oc->y; | ||
1147 | } else { | ||
1148 | int x = 0; | ||
1149 | for (int i = 0; i < root_container.children->length; ++i) { | ||
1150 | swayc_t *c = root_container.children->items[i]; | ||
1151 | if (c->type == C_OUTPUT) { | ||
1152 | if (c->width + c->x > x) { | ||
1153 | x = c->width + c->x; | ||
1154 | } | ||
1155 | } | ||
1156 | } | ||
1157 | output->x = x; | ||
1158 | } | ||
1159 | |||
1160 | if (!oc || !oc->background) { | ||
1161 | // Look for a * config for background | ||
1162 | int i = list_seq_find(config->output_configs, output_name_cmp, "*"); | ||
1163 | if (i >= 0) { | ||
1164 | oc = config->output_configs->items[i]; | ||
1165 | } else { | ||
1166 | oc = NULL; | ||
1167 | } | ||
1168 | } | ||
1169 | |||
1170 | int output_i; | ||
1171 | for (output_i = 0; output_i < root_container.children->length; ++output_i) { | ||
1172 | if (root_container.children->items[output_i] == output) { | ||
1173 | break; | ||
1174 | } | ||
1175 | } | ||
1176 | |||
1177 | /* TODO WLR | ||
1178 | if (oc && oc->background) { | ||
1179 | if (output->bg_pid != 0) { | ||
1180 | terminate_swaybg(output->bg_pid); | ||
1181 | } | ||
1182 | |||
1183 | sway_log(L_DEBUG, "Setting background for output %d to %s", output_i, oc->background); | ||
1184 | |||
1185 | size_t bufsize = 12; | ||
1186 | char output_id[bufsize]; | ||
1187 | snprintf(output_id, bufsize, "%d", output_i); | ||
1188 | output_id[bufsize-1] = 0; | ||
1189 | |||
1190 | char *const cmd[] = { | ||
1191 | "swaybg", | ||
1192 | output_id, | ||
1193 | oc->background, | ||
1194 | oc->background_option, | ||
1195 | NULL, | ||
1196 | }; | ||
1197 | |||
1198 | output->bg_pid = fork(); | ||
1199 | if (output->bg_pid == 0) { | ||
1200 | execvp(cmd[0], cmd); | ||
1201 | } | ||
1202 | } | ||
1203 | */ | ||
1204 | } | ||
1205 | |||
1206 | char *do_var_replacement(char *str) { | ||
1207 | int i; | ||
1208 | char *find = str; | ||
1209 | while ((find = strchr(find, '$'))) { | ||
1210 | // Skip if escaped. | ||
1211 | if (find > str && find[-1] == '\\') { | ||
1212 | if (find == str + 1 || !(find > str + 1 && find[-2] == '\\')) { | ||
1213 | ++find; | ||
1214 | continue; | ||
1215 | } | ||
1216 | } | ||
1217 | // Find matching variable | ||
1218 | for (i = 0; i < config->symbols->length; ++i) { | ||
1219 | struct sway_variable *var = config->symbols->items[i]; | ||
1220 | int vnlen = strlen(var->name); | ||
1221 | if (strncmp(find, var->name, vnlen) == 0) { | ||
1222 | int vvlen = strlen(var->value); | ||
1223 | char *newstr = malloc(strlen(str) - vnlen + vvlen + 1); | ||
1224 | if (!newstr) { | ||
1225 | sway_log(L_ERROR, | ||
1226 | "Unable to allocate replacement during variable expansion"); | ||
1227 | break; | ||
1228 | } | ||
1229 | char *newptr = newstr; | ||
1230 | int offset = find - str; | ||
1231 | strncpy(newptr, str, offset); | ||
1232 | newptr += offset; | ||
1233 | strncpy(newptr, var->value, vvlen); | ||
1234 | newptr += vvlen; | ||
1235 | strcpy(newptr, find + vnlen); | ||
1236 | free(str); | ||
1237 | str = newstr; | ||
1238 | find = str + offset + vvlen; | ||
1239 | break; | ||
1240 | } | ||
1241 | } | ||
1242 | if (i == config->symbols->length) { | ||
1243 | ++find; | ||
1244 | } | ||
1245 | } | ||
1246 | return str; | ||
1247 | } | ||
1248 | |||
1249 | // the naming is intentional (albeit long): a workspace_output_cmp function | ||
1250 | // would compare two structs in full, while this method only compares the | ||
1251 | // workspace. | ||
1252 | int workspace_output_cmp_workspace(const void *a, const void *b) { | ||
1253 | const struct workspace_output *wsa = a, *wsb = b; | ||
1254 | return lenient_strcmp(wsa->workspace, wsb->workspace); | ||
1255 | } | ||
1256 | |||
1257 | int sway_binding_cmp_keys(const void *a, const void *b) { | ||
1258 | const struct sway_binding *binda = a, *bindb = b; | ||
1259 | |||
1260 | // Count keys pressed for this binding. important so we check long before | ||
1261 | // short ones. for example mod+a+b before mod+a | ||
1262 | unsigned int moda = 0, modb = 0, i; | ||
1263 | |||
1264 | // Count how any modifiers are pressed | ||
1265 | for (i = 0; i < 8 * sizeof(binda->modifiers); ++i) { | ||
1266 | moda += (binda->modifiers & 1 << i) != 0; | ||
1267 | modb += (bindb->modifiers & 1 << i) != 0; | ||
1268 | } | ||
1269 | if (bindb->keys->length + modb != binda->keys->length + moda) { | ||
1270 | return (bindb->keys->length + modb) - (binda->keys->length + moda); | ||
1271 | } | ||
1272 | |||
1273 | // Otherwise compare keys | ||
1274 | if (binda->modifiers > bindb->modifiers) { | ||
1275 | return 1; | ||
1276 | } else if (binda->modifiers < bindb->modifiers) { | ||
1277 | return -1; | ||
1278 | } | ||
1279 | struct wlc_modifiers no_mods = { 0, 0 }; | ||
1280 | for (int i = 0; i < binda->keys->length; i++) { | ||
1281 | xkb_keysym_t ka = *(xkb_keysym_t *)binda->keys->items[i], | ||
1282 | kb = *(xkb_keysym_t *)bindb->keys->items[i]; | ||
1283 | if (binda->bindcode) { | ||
1284 | uint32_t *keycode = binda->keys->items[i]; | ||
1285 | ka = wlc_keyboard_get_keysym_for_key(*keycode, &no_mods); | ||
1286 | } | ||
1287 | |||
1288 | if (bindb->bindcode) { | ||
1289 | uint32_t *keycode = bindb->keys->items[i]; | ||
1290 | kb = wlc_keyboard_get_keysym_for_key(*keycode, &no_mods); | ||
1291 | } | ||
1292 | |||
1293 | if (ka > kb) { | ||
1294 | return 1; | ||
1295 | } else if (ka < kb) { | ||
1296 | return -1; | ||
1297 | } | ||
1298 | } | ||
1299 | |||
1300 | return 0; | ||
1301 | } | ||
1302 | |||
1303 | int sway_binding_cmp(const void *a, const void *b) { | ||
1304 | int cmp = 0; | ||
1305 | if ((cmp = sway_binding_cmp_keys(a, b)) != 0) { | ||
1306 | return cmp; | ||
1307 | } | ||
1308 | const struct sway_binding *binda = a, *bindb = b; | ||
1309 | return lenient_strcmp(binda->command, bindb->command); | ||
1310 | } | ||
1311 | |||
1312 | int sway_binding_cmp_qsort(const void *a, const void *b) { | ||
1313 | return sway_binding_cmp(*(void **)a, *(void **)b); | ||
1314 | } | ||
1315 | |||
1316 | void free_sway_binding(struct sway_binding *binding) { | ||
1317 | if (binding->keys) { | ||
1318 | for (int i = 0; i < binding->keys->length; i++) { | ||
1319 | free(binding->keys->items[i]); | ||
1320 | } | ||
1321 | list_free(binding->keys); | ||
1322 | } | ||
1323 | if (binding->command) { | ||
1324 | free(binding->command); | ||
1325 | } | ||
1326 | free(binding); | ||
1327 | } | ||
1328 | |||
1329 | int sway_mouse_binding_cmp_buttons(const void *a, const void *b) { | ||
1330 | const struct sway_mouse_binding *binda = a, *bindb = b; | ||
1331 | if (binda->button > bindb->button) { | ||
1332 | return 1; | ||
1333 | } | ||
1334 | if (binda->button < bindb->button) { | ||
1335 | return -1; | ||
1336 | } | ||
1337 | return 0; | ||
1338 | } | ||
1339 | |||
1340 | int sway_mouse_binding_cmp(const void *a, const void *b) { | ||
1341 | int cmp = 0; | ||
1342 | if ((cmp = sway_binding_cmp_keys(a, b)) != 0) { | ||
1343 | return cmp; | ||
1344 | } | ||
1345 | const struct sway_mouse_binding *binda = a, *bindb = b; | ||
1346 | return lenient_strcmp(binda->command, bindb->command); | ||
1347 | } | ||
1348 | |||
1349 | int sway_mouse_binding_cmp_qsort(const void *a, const void *b) { | ||
1350 | return sway_mouse_binding_cmp(*(void **)a, *(void **)b); | ||
1351 | } | ||
1352 | |||
1353 | void free_sway_mouse_binding(struct sway_mouse_binding *binding) { | ||
1354 | if (binding->command) { | ||
1355 | free(binding->command); | ||
1356 | } | ||
1357 | free(binding); | ||
1358 | } | ||
1359 | |||
1360 | struct sway_binding *sway_binding_dup(struct sway_binding *sb) { | ||
1361 | struct sway_binding *new_sb = malloc(sizeof(struct sway_binding)); | ||
1362 | if (!new_sb) { | ||
1363 | return NULL; | ||
1364 | } | ||
1365 | |||
1366 | new_sb->order = sb->order; | ||
1367 | new_sb->modifiers = sb->modifiers; | ||
1368 | new_sb->command = strdup(sb->command); | ||
1369 | |||
1370 | new_sb->keys = create_list(); | ||
1371 | int i; | ||
1372 | for (i = 0; i < sb->keys->length; ++i) { | ||
1373 | xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); | ||
1374 | if (!key) { | ||
1375 | free_sway_binding(new_sb); | ||
1376 | return NULL; | ||
1377 | } | ||
1378 | *key = *(xkb_keysym_t *)sb->keys->items[i]; | ||
1379 | list_add(new_sb->keys, key); | ||
1380 | } | ||
1381 | |||
1382 | return new_sb; | ||
1383 | } | ||
1384 | |||
1385 | struct bar_config *default_bar_config(void) { | ||
1386 | struct bar_config *bar = NULL; | ||
1387 | bar = malloc(sizeof(struct bar_config)); | ||
1388 | if (!bar) { | ||
1389 | return NULL; | ||
1390 | } | ||
1391 | if (!(bar->mode = strdup("dock"))) goto cleanup; | ||
1392 | if (!(bar->hidden_state = strdup("hide"))) goto cleanup; | ||
1393 | bar->modifier = WLC_BIT_MOD_LOGO; | ||
1394 | bar->outputs = NULL; | ||
1395 | bar->position = DESKTOP_SHELL_PANEL_POSITION_BOTTOM; | ||
1396 | if (!(bar->bindings = create_list())) goto cleanup; | ||
1397 | if (!(bar->status_command = strdup("while :; do date +'%Y-%m-%d %l:%M:%S %p'; sleep 1; done"))) goto cleanup; | ||
1398 | bar->pango_markup = false; | ||
1399 | bar->swaybar_command = NULL; | ||
1400 | bar->font = NULL; | ||
1401 | bar->height = -1; | ||
1402 | bar->workspace_buttons = true; | ||
1403 | bar->wrap_scroll = false; | ||
1404 | bar->separator_symbol = NULL; | ||
1405 | bar->strip_workspace_numbers = false; | ||
1406 | bar->binding_mode_indicator = true; | ||
1407 | #ifdef ENABLE_TRAY | ||
1408 | bar->tray_output = NULL; | ||
1409 | bar->icon_theme = NULL; | ||
1410 | bar->tray_padding = 2; | ||
1411 | bar->activate_button = 0x110; /* BTN_LEFT */ | ||
1412 | bar->context_button = 0x111; /* BTN_RIGHT */ | ||
1413 | bar->secondary_button = 0x112; /* BTN_MIDDLE */ | ||
1414 | #endif | ||
1415 | bar->verbose = false; | ||
1416 | bar->pid = 0; | ||
1417 | // set default colors | ||
1418 | if (!(bar->colors.background = strndup("#000000ff", 9))) goto cleanup; | ||
1419 | if (!(bar->colors.statusline = strndup("#ffffffff", 9))) goto cleanup; | ||
1420 | if (!(bar->colors.separator = strndup("#666666ff", 9))) goto cleanup; | ||
1421 | if (!(bar->colors.focused_workspace_border = strndup("#4c7899ff", 9))) goto cleanup; | ||
1422 | if (!(bar->colors.focused_workspace_bg = strndup("#285577ff", 9))) goto cleanup; | ||
1423 | if (!(bar->colors.focused_workspace_text = strndup("#ffffffff", 9))) goto cleanup; | ||
1424 | if (!(bar->colors.active_workspace_border = strndup("#333333ff", 9))) goto cleanup; | ||
1425 | if (!(bar->colors.active_workspace_bg = strndup("#5f676aff", 9))) goto cleanup; | ||
1426 | if (!(bar->colors.active_workspace_text = strndup("#ffffffff", 9))) goto cleanup; | ||
1427 | if (!(bar->colors.inactive_workspace_border = strndup("#333333ff", 9))) goto cleanup; | ||
1428 | if (!(bar->colors.inactive_workspace_bg = strndup("#222222ff", 9))) goto cleanup; | ||
1429 | if (!(bar->colors.inactive_workspace_text = strndup("#888888ff", 9))) goto cleanup; | ||
1430 | if (!(bar->colors.urgent_workspace_border = strndup("#2f343aff", 9))) goto cleanup; | ||
1431 | if (!(bar->colors.urgent_workspace_bg = strndup("#900000ff", 9))) goto cleanup; | ||
1432 | if (!(bar->colors.urgent_workspace_text = strndup("#ffffffff", 9))) goto cleanup; | ||
1433 | // if the following colors stay undefined, they fall back to background, | ||
1434 | // statusline, separator and urgent_workspace_*. | ||
1435 | bar->colors.focused_background = NULL; | ||
1436 | bar->colors.focused_statusline = NULL; | ||
1437 | bar->colors.focused_separator = NULL; | ||
1438 | bar->colors.binding_mode_border = NULL; | ||
1439 | bar->colors.binding_mode_bg = NULL; | ||
1440 | bar->colors.binding_mode_text = NULL; | ||
1441 | |||
1442 | list_add(config->bars, bar); | ||
1443 | |||
1444 | return bar; | ||
1445 | |||
1446 | cleanup: | ||
1447 | free_bar(bar); | ||
1448 | return NULL; | ||
1449 | } | ||