diff options
Diffstat (limited to 'sway/config/bar.c')
-rw-r--r-- | sway/config/bar.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/sway/config/bar.c b/sway/config/bar.c new file mode 100644 index 00000000..2913f059 --- /dev/null +++ b/sway/config/bar.c | |||
@@ -0,0 +1,240 @@ | |||
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 <wordexp.h> | ||
8 | #include <sys/types.h> | ||
9 | #include <sys/wait.h> | ||
10 | #include <sys/stat.h> | ||
11 | #include <signal.h> | ||
12 | #include <strings.h> | ||
13 | #include "sway/config.h" | ||
14 | #include "stringop.h" | ||
15 | #include "list.h" | ||
16 | #include "log.h" | ||
17 | |||
18 | static void terminate_swaybar(pid_t pid) { | ||
19 | wlr_log(L_DEBUG, "Terminating swaybar %d", pid); | ||
20 | int ret = kill(pid, SIGTERM); | ||
21 | if (ret != 0) { | ||
22 | wlr_log_errno(L_ERROR, "Unable to terminate swaybar %d", pid); | ||
23 | } else { | ||
24 | int status; | ||
25 | waitpid(pid, &status, 0); | ||
26 | } | ||
27 | } | ||
28 | |||
29 | void free_bar_config(struct bar_config *bar) { | ||
30 | if (!bar) { | ||
31 | return; | ||
32 | } | ||
33 | free(bar->mode); | ||
34 | free(bar->position); | ||
35 | free(bar->hidden_state); | ||
36 | free(bar->status_command); | ||
37 | free(bar->font); | ||
38 | free(bar->separator_symbol); | ||
39 | // TODO: Free mouse bindings | ||
40 | list_free(bar->bindings); | ||
41 | if (bar->outputs) { | ||
42 | free_flat_list(bar->outputs); | ||
43 | } | ||
44 | if (bar->pid != 0) { | ||
45 | terminate_swaybar(bar->pid); | ||
46 | } | ||
47 | free(bar->colors.background); | ||
48 | free(bar->colors.statusline); | ||
49 | free(bar->colors.separator); | ||
50 | free(bar->colors.focused_background); | ||
51 | free(bar->colors.focused_statusline); | ||
52 | free(bar->colors.focused_separator); | ||
53 | free(bar->colors.focused_workspace_border); | ||
54 | free(bar->colors.focused_workspace_bg); | ||
55 | free(bar->colors.focused_workspace_text); | ||
56 | free(bar->colors.active_workspace_border); | ||
57 | free(bar->colors.active_workspace_bg); | ||
58 | free(bar->colors.active_workspace_text); | ||
59 | free(bar->colors.inactive_workspace_border); | ||
60 | free(bar->colors.inactive_workspace_bg); | ||
61 | free(bar->colors.inactive_workspace_text); | ||
62 | free(bar->colors.urgent_workspace_border); | ||
63 | free(bar->colors.urgent_workspace_bg); | ||
64 | free(bar->colors.urgent_workspace_text); | ||
65 | free(bar->colors.binding_mode_border); | ||
66 | free(bar->colors.binding_mode_bg); | ||
67 | free(bar->colors.binding_mode_text); | ||
68 | free(bar); | ||
69 | } | ||
70 | |||
71 | struct bar_config *default_bar_config(void) { | ||
72 | struct bar_config *bar = NULL; | ||
73 | bar = malloc(sizeof(struct bar_config)); | ||
74 | if (!bar) { | ||
75 | return NULL; | ||
76 | } | ||
77 | if (!(bar->mode = strdup("dock"))) goto cleanup; | ||
78 | if (!(bar->hidden_state = strdup("hide"))) goto cleanup; | ||
79 | bar->outputs = NULL; | ||
80 | bar->position = strdup("bottom"); | ||
81 | if (!(bar->bindings = create_list())) goto cleanup; | ||
82 | if (!(bar->status_command = strdup("while :; do date +'%Y-%m-%d %l:%M:%S %p'; sleep 1; done"))) goto cleanup; | ||
83 | bar->pango_markup = false; | ||
84 | bar->swaybar_command = NULL; | ||
85 | bar->font = NULL; | ||
86 | bar->height = -1; | ||
87 | bar->workspace_buttons = true; | ||
88 | bar->wrap_scroll = false; | ||
89 | bar->separator_symbol = NULL; | ||
90 | bar->strip_workspace_numbers = false; | ||
91 | bar->binding_mode_indicator = true; | ||
92 | bar->verbose = false; | ||
93 | bar->pid = 0; | ||
94 | // set default colors | ||
95 | if (!(bar->colors.background = strndup("#000000ff", 9))) { | ||
96 | goto cleanup; | ||
97 | } | ||
98 | if (!(bar->colors.statusline = strndup("#ffffffff", 9))) { | ||
99 | goto cleanup; | ||
100 | } | ||
101 | if (!(bar->colors.separator = strndup("#666666ff", 9))) { | ||
102 | goto cleanup; | ||
103 | } | ||
104 | if (!(bar->colors.focused_workspace_border = strndup("#4c7899ff", 9))) { | ||
105 | goto cleanup; | ||
106 | } | ||
107 | if (!(bar->colors.focused_workspace_bg = strndup("#285577ff", 9))) { | ||
108 | goto cleanup; | ||
109 | } | ||
110 | if (!(bar->colors.focused_workspace_text = strndup("#ffffffff", 9))) { | ||
111 | goto cleanup; | ||
112 | } | ||
113 | if (!(bar->colors.active_workspace_border = strndup("#333333ff", 9))) { | ||
114 | goto cleanup; | ||
115 | } | ||
116 | if (!(bar->colors.active_workspace_bg = strndup("#5f676aff", 9))) { | ||
117 | goto cleanup; | ||
118 | } | ||
119 | if (!(bar->colors.active_workspace_text = strndup("#ffffffff", 9))) { | ||
120 | goto cleanup; | ||
121 | } | ||
122 | if (!(bar->colors.inactive_workspace_border = strndup("#333333ff", 9))) { | ||
123 | goto cleanup; | ||
124 | } | ||
125 | if (!(bar->colors.inactive_workspace_bg = strndup("#222222ff", 9))) { | ||
126 | goto cleanup; | ||
127 | } | ||
128 | if (!(bar->colors.inactive_workspace_text = strndup("#888888ff", 9))) { | ||
129 | goto cleanup; | ||
130 | } | ||
131 | if (!(bar->colors.urgent_workspace_border = strndup("#2f343aff", 9))) { | ||
132 | goto cleanup; | ||
133 | } | ||
134 | if (!(bar->colors.urgent_workspace_bg = strndup("#900000ff", 9))) { | ||
135 | goto cleanup; | ||
136 | } | ||
137 | if (!(bar->colors.urgent_workspace_text = strndup("#ffffffff", 9))) { | ||
138 | goto cleanup; | ||
139 | } | ||
140 | // if the following colors stay undefined, they fall back to background, | ||
141 | // statusline, separator and urgent_workspace_*. | ||
142 | bar->colors.focused_background = NULL; | ||
143 | bar->colors.focused_statusline = NULL; | ||
144 | bar->colors.focused_separator = NULL; | ||
145 | bar->colors.binding_mode_border = NULL; | ||
146 | bar->colors.binding_mode_bg = NULL; | ||
147 | bar->colors.binding_mode_text = NULL; | ||
148 | |||
149 | list_add(config->bars, bar); | ||
150 | return bar; | ||
151 | cleanup: | ||
152 | free_bar_config(bar); | ||
153 | return NULL; | ||
154 | } | ||
155 | |||
156 | void invoke_swaybar(struct bar_config *bar) { | ||
157 | // Pipe to communicate errors | ||
158 | int filedes[2]; | ||
159 | if (pipe(filedes) == -1) { | ||
160 | wlr_log(L_ERROR, "Pipe setup failed! Cannot fork into bar"); | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | bar->pid = fork(); | ||
165 | if (bar->pid == 0) { | ||
166 | close(filedes[0]); | ||
167 | |||
168 | // run custom swaybar | ||
169 | size_t len = snprintf(NULL, 0, "%s -b %s", | ||
170 | bar->swaybar_command ? bar->swaybar_command : "swaybar", | ||
171 | bar->id); | ||
172 | char *command = malloc(len + 1); | ||
173 | if (!command) { | ||
174 | const char msg[] = "Unable to allocate swaybar command string"; | ||
175 | size_t len = sizeof(msg); | ||
176 | if (write(filedes[1], &len, sizeof(int))) {}; | ||
177 | if (write(filedes[1], msg, len)) {}; | ||
178 | close(filedes[1]); | ||
179 | exit(1); | ||
180 | } | ||
181 | snprintf(command, len + 1, "%s -b %s", | ||
182 | bar->swaybar_command ? bar->swaybar_command : "swaybar", | ||
183 | bar->id); | ||
184 | char *const cmd[] = { "sh", "-c", command, NULL, }; | ||
185 | close(filedes[1]); | ||
186 | execvp(cmd[0], cmd); | ||
187 | exit(1); | ||
188 | } | ||
189 | wlr_log(L_DEBUG, "Spawned swaybar %d", bar->pid); | ||
190 | close(filedes[0]); | ||
191 | ssize_t len; | ||
192 | if (read(filedes[1], &len, sizeof(int)) == sizeof(int)) { | ||
193 | char *buf = malloc(len); | ||
194 | if(!buf) { | ||
195 | wlr_log(L_ERROR, "Cannot allocate error string"); | ||
196 | return; | ||
197 | } | ||
198 | if (read(filedes[1], buf, len)) { | ||
199 | wlr_log(L_ERROR, "%s", buf); | ||
200 | } | ||
201 | free(buf); | ||
202 | } | ||
203 | close(filedes[1]); | ||
204 | } | ||
205 | |||
206 | static bool active_output(const char *name) { | ||
207 | struct sway_container *cont = NULL; | ||
208 | for (int i = 0; i < root_container.children->length; ++i) { | ||
209 | cont = root_container.children->items[i]; | ||
210 | if (cont->type == C_OUTPUT && strcasecmp(name, cont->name) == 0) { | ||
211 | return true; | ||
212 | } | ||
213 | } | ||
214 | return false; | ||
215 | } | ||
216 | |||
217 | void load_swaybars() { | ||
218 | for (int i = 0; i < config->bars->length; ++i) { | ||
219 | struct bar_config *bar = config->bars->items[i]; | ||
220 | bool apply = false; | ||
221 | if (bar->outputs) { | ||
222 | for (int j = 0; j < bar->outputs->length; ++j) { | ||
223 | char *o = bar->outputs->items[j]; | ||
224 | if (!strcmp(o, "*") || active_output(o)) { | ||
225 | apply = true; | ||
226 | break; | ||
227 | } | ||
228 | } | ||
229 | } else { | ||
230 | apply = true; | ||
231 | } | ||
232 | if (apply) { | ||
233 | if (bar->pid != 0) { | ||
234 | terminate_swaybar(bar->pid); | ||
235 | } | ||
236 | wlr_log(L_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); | ||
237 | invoke_swaybar(bar); | ||
238 | } | ||
239 | } | ||
240 | } | ||