aboutsummaryrefslogtreecommitdiffstats
path: root/swaynag/main.c
diff options
context:
space:
mode:
authorLibravatar Brian Ashworth <bosrsf04@gmail.com>2018-07-28 09:34:25 -0400
committerLibravatar Brian Ashworth <bosrsf04@gmail.com>2018-08-01 22:47:54 -0400
commit8463a2896a932cd99f3dc93608b03cb4aba93293 (patch)
treeb8c4ba994cf4d9ca7510d0f80a1864cce144092a /swaynag/main.c
parentAddress first round review for swaynag (diff)
downloadsway-8463a2896a932cd99f3dc93608b03cb4aba93293.tar.gz
sway-8463a2896a932cd99f3dc93608b03cb4aba93293.tar.zst
sway-8463a2896a932cd99f3dc93608b03cb4aba93293.zip
swaynag: implement config file support
Diffstat (limited to 'swaynag/main.c')
-rw-r--r--swaynag/main.c357
1 files changed, 256 insertions, 101 deletions
diff --git a/swaynag/main.c b/swaynag/main.c
index 60560c72..b199fac4 100644
--- a/swaynag/main.c
+++ b/swaynag/main.c
@@ -1,10 +1,14 @@
1#define _XOPEN_SOURCE 500 1#define _XOPEN_SOURCE 700
2#define _POSIX_C_SOURCE 200112L
2#include <getopt.h> 3#include <getopt.h>
3#include <signal.h> 4#include <signal.h>
5#include <stdlib.h>
6#include <wordexp.h>
4#include "log.h" 7#include "log.h"
5#include "list.h" 8#include "list.h"
6#include "readline.h" 9#include "readline.h"
7#include "swaynag/nagbar.h" 10#include "swaynag/nagbar.h"
11#include "swaynag/types.h"
8#include "wlr-layer-shell-unstable-v1-client-protocol.h" 12#include "wlr-layer-shell-unstable-v1-client-protocol.h"
9 13
10static struct sway_nagbar nagbar; 14static struct sway_nagbar nagbar;
@@ -19,22 +23,6 @@ void sway_terminate(int code) {
19 exit(code); 23 exit(code);
20} 24}
21 25
22static void set_nagbar_colors() {
23 if (nagbar.type == NAGBAR_ERROR) {
24 nagbar.colors.button_background = 0x680A0AFF;
25 nagbar.colors.background = 0x900000FF;
26 nagbar.colors.text = 0xFFFFFFFF;
27 nagbar.colors.border = 0xD92424FF;
28 nagbar.colors.border_bottom = 0x470909FF;
29 } else if (nagbar.type == NAGBAR_WARNING) {
30 nagbar.colors.button_background = 0xFFC100FF;
31 nagbar.colors.background = 0xFFA800FF;
32 nagbar.colors.text = 0x000000FF;
33 nagbar.colors.border = 0xAB7100FF;
34 nagbar.colors.border_bottom = 0xAB7100FF;
35 }
36}
37
38static char *read_from_stdin() { 26static char *read_from_stdin() {
39 char *buffer = NULL; 27 char *buffer = NULL;
40 while (!feof(stdin)) { 28 while (!feof(stdin)) {
@@ -61,32 +49,11 @@ static char *read_from_stdin() {
61 return buffer; 49 return buffer;
62} 50}
63 51
64int main(int argc, char **argv) { 52static int parse_options(int argc, char **argv, struct sway_nagbar *nagbar,
65 int exit_code = EXIT_SUCCESS; 53 list_t *types, char **config, bool *debug) {
66 bool debug = false;
67
68 memset(&nagbar, 0, sizeof(nagbar));
69 nagbar.anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
70 | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
71 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
72 nagbar.type = NAGBAR_ERROR;
73 set_nagbar_colors();
74 nagbar.font = strdup("pango:monospace 10");
75 nagbar.buttons = create_list();
76
77 struct sway_nagbar_button *button_close =
78 calloc(sizeof(struct sway_nagbar_button), 1);
79 button_close->text = strdup("X");
80 button_close->type = NAGBAR_ACTION_DISMISS;
81 list_add(nagbar.buttons, button_close);
82
83 struct sway_nagbar_button *button_details =
84 calloc(sizeof(struct sway_nagbar_button), 1);
85 button_details->text = strdup("Toggle Details");
86 button_details->type = NAGBAR_ACTION_EXPAND;
87
88 static struct option opts[] = { 54 static struct option opts[] = {
89 {"button", required_argument, NULL, 'b'}, 55 {"button", required_argument, NULL, 'b'},
56 {"config", required_argument, NULL, 'c'},
90 {"debug", no_argument, NULL, 'd'}, 57 {"debug", no_argument, NULL, 'd'},
91 {"edge", required_argument, NULL, 'e'}, 58 {"edge", required_argument, NULL, 'e'},
92 {"font", required_argument, NULL, 'f'}, 59 {"font", required_argument, NULL, 'f'},
@@ -106,6 +73,7 @@ int main(int argc, char **argv) {
106 "\n" 73 "\n"
107 " -b, --button <text> <action> Create a button with text that " 74 " -b, --button <text> <action> Create a button with text that "
108 "executes action when pressed. Multiple buttons can be defined.\n" 75 "executes action when pressed. Multiple buttons can be defined.\n"
76 " -c, --config <path> Path to config file.\n"
109 " -d, --debug Enable debugging.\n" 77 " -d, --debug Enable debugging.\n"
110 " -e, --edge top|bottom Set the edge to use.\n" 78 " -e, --edge top|bottom Set the edge to use.\n"
111 " -f, --font <font> Set the font to use.\n" 79 " -f, --font <font> Set the font to use.\n"
@@ -115,114 +83,301 @@ int main(int argc, char **argv) {
115 " -m, --message <msg> Set the message text.\n" 83 " -m, --message <msg> Set the message text.\n"
116 " -o, --output <output> Set the output to use.\n" 84 " -o, --output <output> Set the output to use.\n"
117 " -s, --dismiss-button <text> Set the dismiss button text.\n" 85 " -s, --dismiss-button <text> Set the dismiss button text.\n"
118 " -t, --type error|warning Set the message type.\n" 86 " -t, --type <type> Set the message type.\n"
119 " -v, --version Show the version number and quit.\n"; 87 " -v, --version Show the version number and quit.\n";
120 88
89 optind = 1;
121 while (1) { 90 while (1) {
122 int c = getopt_long(argc, argv, "b:de:f:hlL:m:o:s:t:v", opts, NULL); 91 int c = getopt_long(argc, argv, "b:c:de:f:hlL:m:o:s:t:v", opts, NULL);
123 if (c == -1) { 92 if (c == -1) {
124 break; 93 break;
125 } 94 }
126 switch (c) { 95 switch (c) {
127 case 'b': // Button 96 case 'b': // Button
128 if (optind >= argc) { 97 if (nagbar) {
129 fprintf(stderr, "Missing action for button %s\n", optarg); 98 if (optind >= argc) {
130 exit_code = EXIT_FAILURE; 99 fprintf(stderr, "Missing action for button %s\n", optarg);
131 goto cleanup; 100 return EXIT_FAILURE;
132 } 101 }
133 struct sway_nagbar_button *button; 102 struct sway_nagbar_button *button;
134 button = calloc(sizeof(struct sway_nagbar_button), 1); 103 button = calloc(sizeof(struct sway_nagbar_button), 1);
135 button->text = strdup(optarg); 104 button->text = strdup(optarg);
136 button->type = NAGBAR_ACTION_COMMAND; 105 button->type = NAGBAR_ACTION_COMMAND;
137 button->action = strdup(argv[optind]); 106 button->action = strdup(argv[optind]);
138 optind++; 107 optind++;
139 list_add(nagbar.buttons, button); 108 list_add(nagbar->buttons, button);
109 }
110 break;
111 case 'c': // Config
112 if (config) {
113 *config = strdup(optarg);
114 }
140 break; 115 break;
141 case 'd': // Debug 116 case 'd': // Debug
142 debug = true; 117 if (debug) {
118 *debug = true;
119 }
143 break; 120 break;
144 case 'e': // Edge 121 case 'e': // Edge
145 if (strcmp(optarg, "top") == 0) { 122 if (nagbar) {
146 nagbar.anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP 123 if (strcmp(optarg, "top") == 0) {
147 | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT 124 nagbar->anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
148 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; 125 | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
149 } else if (strcmp(optarg, "bottom") == 0) { 126 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
150 nagbar.anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM 127 } else if (strcmp(optarg, "bottom") == 0) {
151 | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT 128 nagbar->anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
152 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; 129 | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
153 } else { 130 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
154 fprintf(stderr, "Invalid edge: %s\n", optarg); 131 } else {
155 exit_code = EXIT_FAILURE; 132 fprintf(stderr, "Invalid edge: %s\n", optarg);
156 goto cleanup; 133 return EXIT_FAILURE;
134 }
157 } 135 }
158 break; 136 break;
159 case 'f': // Font 137 case 'f': // Font
160 free(nagbar.font); 138 if (nagbar) {
161 nagbar.font = strdup(optarg); 139 free(nagbar->font);
140 nagbar->font = strdup(optarg);
141 }
162 break; 142 break;
163 case 'l': // Detailed Message 143 case 'l': // Detailed Message
164 free(nagbar.details.message); 144 if (nagbar) {
165 nagbar.details.message = read_from_stdin(); 145 free(nagbar->details.message);
166 nagbar.details.button_up.text = strdup("▲"); 146 nagbar->details.message = read_from_stdin();
167 nagbar.details.button_down.text = strdup("▼"); 147 nagbar->details.button_up.text = strdup("▲");
148 nagbar->details.button_down.text = strdup("▼");
149 }
168 break; 150 break;
169 case 'L': // Detailed Button Text 151 case 'L': // Detailed Button Text
170 free(button_details->text); 152 if (nagbar) {
171 button_details->text = strdup(optarg); 153 free(nagbar->details.button_details.text);
154 nagbar->details.button_details.text = strdup(optarg);
155 }
172 break; 156 break;
173 case 'm': // Message 157 case 'm': // Message
174 free(nagbar.message); 158 if (nagbar) {
175 nagbar.message = strdup(optarg); 159 free(nagbar->message);
160 nagbar->message = strdup(optarg);
161 }
176 break; 162 break;
177 case 'o': // Output 163 case 'o': // Output
178 free(nagbar.output.name); 164 if (nagbar) {
179 nagbar.output.name = strdup(optarg); 165 free(nagbar->output.name);
166 nagbar->output.name = strdup(optarg);
167 }
180 break; 168 break;
181 case 's': // Dismiss Button Text 169 case 's': // Dismiss Button Text
182 free(button_close->text); 170 if (nagbar) {
183 button_close->text = strdup(optarg); 171 struct sway_nagbar_button *button_close;
172 button_close = nagbar->buttons->items[0];
173 free(button_close->text);
174 button_close->text = strdup(optarg);
175 }
184 break; 176 break;
185 case 't': // Type 177 case 't': // Type
186 if (strcmp(optarg, "error") == 0) { 178 if (nagbar) {
187 nagbar.type = NAGBAR_ERROR; 179 nagbar->type = nagbar_type_get(types, optarg);
188 } else if (strcmp(optarg, "warning") == 0) { 180 if (!nagbar->type) {
189 nagbar.type = NAGBAR_WARNING; 181 fprintf(stderr, "Unknown type %s\n", optarg);
190 } else { 182 return EXIT_FAILURE;
191 fprintf(stderr, "Type must be either 'error' or 'warning'\n"); 183 }
192 exit_code = EXIT_FAILURE;
193 goto cleanup;
194 } 184 }
195 set_nagbar_colors();
196 break; 185 break;
197 case 'v': // Version 186 case 'v': // Version
198 fprintf(stdout, "swaynag version " SWAY_VERSION "\n"); 187 fprintf(stdout, "swaynag version " SWAY_VERSION "\n");
199 exit_code = EXIT_SUCCESS; 188 return -1;
200 goto cleanup;
201 default: // Help or unknown flag 189 default: // Help or unknown flag
202 fprintf(c == 'h' ? stdout : stderr, "%s", usage); 190 fprintf(c == 'h' ? stdout : stderr, "%s", usage);
203 exit_code = c == 'h' ? EXIT_SUCCESS : EXIT_FAILURE; 191 return -1;
204 goto cleanup; 192 }
193 }
194
195 return 0;
196}
197
198static bool file_exists(const char *path) {
199 return path && access(path, R_OK) != -1;
200}
201
202static char *get_config_path(void) {
203 static const char *config_paths[] = {
204 "$HOME/.swaynag/config",
205 "$XDG_CONFIG_HOME/swaynag/config",
206 SYSCONFDIR "/swaynag/config",
207 };
208
209 if (!getenv("XDG_CONFIG_HOME")) {
210 char *home = getenv("HOME");
211 char *config_home = malloc(strlen(home) + strlen("/.config") + 1);
212 if (!config_home) {
213 wlr_log(WLR_ERROR, "Unable to allocate $HOME/.config");
214 } else {
215 strcpy(config_home, home);
216 strcat(config_home, "/.config");
217 setenv("XDG_CONFIG_HOME", config_home, 1);
218 wlr_log(WLR_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home);
219 free(config_home);
220 }
221 }
222
223 wordexp_t p;
224 char *path;
225 for (size_t i = 0; i < sizeof(config_paths) / sizeof(char *); ++i) {
226 if (wordexp(config_paths[i], &p, 0) == 0) {
227 path = strdup(p.we_wordv[0]);
228 wordfree(&p);
229 if (file_exists(path)) {
230 return path;
231 }
232 free(path);
233 }
234 }
235
236 return NULL;
237}
238
239static int load_config(char *path, struct sway_nagbar *nagbar, list_t *types) {
240 FILE *config = fopen(path, "r");
241 if (!config) {
242 fprintf(stderr, "Failed to read config. Running without it.\n");
243 return 0;
244 }
245 struct sway_nagbar_type *type = NULL;
246 char *line;
247 int line_number = 0;
248 while (!feof(config)) {
249 line = read_line(config);
250 if (!line) {
251 continue;
252 }
253
254 line_number++;
255 if (line[0] == '#') {
256 free(line);
257 continue;
205 } 258 }
259 if (strlen(line) == 0) {
260 free(line);
261 continue;
262 }
263
264 if (line[0] == '[') {
265 char *close = strchr(line, ']');
266 if (!close) {
267 free(line);
268 fclose(config);
269 fprintf(stderr, "Closing bracket not found on line %d\n",
270 line_number);
271 return 1;
272 }
273 char *name = calloc(1, close - line);
274 strncat(name, line + 1, close - line - 1);
275 type = nagbar_type_get(types, name);
276 if (!type) {
277 type = calloc(1, sizeof(struct sway_nagbar_type));
278 type->name = strdup(name);
279 list_add(types, type);
280 }
281 free(name);
282 } else {
283 char flag[strlen(line) + 3];
284 sprintf(flag, "--%s", line);
285 char *argv[] = {"swaynag", flag};
286 int result;
287 if (type) {
288 result = nagbar_parse_type(2, argv, type);
289 } else {
290 result = parse_options(2, argv, nagbar, types, NULL, NULL);
291 }
292 if (result != 0) {
293 free(line);
294 fclose(config);
295 return result;
296 }
297 }
298
299 free(line);
206 } 300 }
301 fclose(config);
302 return 0;
303}
304
305int main(int argc, char **argv) {
306 int exit_code = EXIT_SUCCESS;
307
308 list_t *types = create_list();
309 nagbar_types_add_default(types);
310
311 memset(&nagbar, 0, sizeof(nagbar));
312 nagbar.anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
313 | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
314 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
315 nagbar.font = strdup("pango:monospace 10");
316 nagbar.buttons = create_list();
317
318 struct sway_nagbar_button *button_close =
319 calloc(sizeof(struct sway_nagbar_button), 1);
320 button_close->text = strdup("X");
321 button_close->type = NAGBAR_ACTION_DISMISS;
322 list_add(nagbar.buttons, button_close);
323
324 nagbar.details.button_details.text = strdup("Toggle Details");
325 nagbar.details.button_details.type = NAGBAR_ACTION_EXPAND;
207 326
327
328 char *config_path = NULL;
329 bool debug = false;
330 int launch_status = parse_options(argc, argv, NULL, NULL,
331 &config_path, &debug);
332 if (launch_status != 0) {
333 exit_code = launch_status;
334 goto cleanup;
335 }
208 wlr_log_init(debug ? WLR_DEBUG : WLR_ERROR, NULL); 336 wlr_log_init(debug ? WLR_DEBUG : WLR_ERROR, NULL);
209 337
338 if (!config_path) {
339 config_path = get_config_path();
340 }
341 if (config_path) {
342 wlr_log(WLR_DEBUG, "Loading config file: %s", config_path);
343 int config_status = load_config(config_path, &nagbar, types);
344 free(config_path);
345 if (config_status != 0) {
346 exit_code = config_status;
347 goto cleanup;
348 }
349 }
350
351 if (argc > 1) {
352 int result = parse_options(argc, argv, &nagbar, types, NULL, NULL);
353 if (result != 0) {
354 exit_code = result;
355 goto cleanup;
356 }
357 }
358
210 if (!nagbar.message) { 359 if (!nagbar.message) {
211 wlr_log(WLR_ERROR, "No message passed. Please provide --message/-m"); 360 wlr_log(WLR_ERROR, "No message passed. Please provide --message/-m");
212 exit_code = EXIT_FAILURE; 361 exit_code = EXIT_FAILURE;
213 goto cleanup; 362 goto cleanup;
214 } 363 }
215 364
365 if (!nagbar.type) {
366 nagbar.type = nagbar_type_get(types, "error");
367 }
368
369 nagbar.type = nagbar_type_clone(nagbar.type);
370 nagbar_types_free(types);
371
216 if (nagbar.details.message) { 372 if (nagbar.details.message) {
217 list_add(nagbar.buttons, button_details); 373 list_add(nagbar.buttons, &nagbar.details.button_details);
218 } else { 374 } else {
219 free(button_details->text); 375 free(nagbar.details.button_details.text);
220 free(button_details);
221 } 376 }
222 377
223 wlr_log(WLR_DEBUG, "Output: %s", nagbar.output.name); 378 wlr_log(WLR_DEBUG, "Output: %s", nagbar.output.name);
224 wlr_log(WLR_DEBUG, "Anchors: %d", nagbar.anchors); 379 wlr_log(WLR_DEBUG, "Anchors: %d", nagbar.anchors);
225 wlr_log(WLR_DEBUG, "Type: %d", nagbar.type); 380 wlr_log(WLR_DEBUG, "Type: %s", nagbar.type->name);
226 wlr_log(WLR_DEBUG, "Message: %s", nagbar.message); 381 wlr_log(WLR_DEBUG, "Message: %s", nagbar.message);
227 wlr_log(WLR_DEBUG, "Font: %s", nagbar.font); 382 wlr_log(WLR_DEBUG, "Font: %s", nagbar.font);
228 wlr_log(WLR_DEBUG, "Buttons"); 383 wlr_log(WLR_DEBUG, "Buttons");
@@ -238,8 +393,8 @@ int main(int argc, char **argv) {
238 return exit_code; 393 return exit_code;
239 394
240cleanup: 395cleanup:
241 free(button_details->text); 396 nagbar_types_free(types);
242 free(button_details); 397 free(nagbar.details.button_details.text);
243 nagbar_destroy(&nagbar); 398 nagbar_destroy(&nagbar);
244 return exit_code; 399 return exit_code;
245} 400}