diff options
Diffstat (limited to 'swaynag')
-rw-r--r-- | swaynag/main.c | 357 | ||||
-rw-r--r-- | swaynag/meson.build | 1 | ||||
-rw-r--r-- | swaynag/nagbar.c | 5 | ||||
-rw-r--r-- | swaynag/render.c | 23 | ||||
-rw-r--r-- | swaynag/swaynag.1.scd | 33 | ||||
-rw-r--r-- | swaynag/swaynag.5.scd | 57 | ||||
-rw-r--r-- | swaynag/types.c | 116 |
7 files changed, 470 insertions, 122 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 | ||
10 | static struct sway_nagbar nagbar; | 14 | static struct sway_nagbar nagbar; |
@@ -19,22 +23,6 @@ void sway_terminate(int code) { | |||
19 | exit(code); | 23 | exit(code); |
20 | } | 24 | } |
21 | 25 | ||
22 | static 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 | |||
38 | static char *read_from_stdin() { | 26 | static 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 | ||
64 | int main(int argc, char **argv) { | 52 | static 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 | |||
198 | static bool file_exists(const char *path) { | ||
199 | return path && access(path, R_OK) != -1; | ||
200 | } | ||
201 | |||
202 | static 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 | |||
239 | static 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 | |||
305 | int 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 | ||
240 | cleanup: | 395 | cleanup: |
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 | } |
diff --git a/swaynag/meson.build b/swaynag/meson.build index 6492e4dc..6a9df984 100644 --- a/swaynag/meson.build +++ b/swaynag/meson.build | |||
@@ -3,6 +3,7 @@ executable( | |||
3 | 'main.c', | 3 | 'main.c', |
4 | 'nagbar.c', | 4 | 'nagbar.c', |
5 | 'render.c', | 5 | 'render.c', |
6 | 'types.c', | ||
6 | ], | 7 | ], |
7 | include_directories: [sway_inc], | 8 | include_directories: [sway_inc], |
8 | dependencies: [ | 9 | dependencies: [ |
diff --git a/swaynag/nagbar.c b/swaynag/nagbar.c index 6647e8c2..a20a9095 100644 --- a/swaynag/nagbar.c +++ b/swaynag/nagbar.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include "list.h" | 8 | #include "list.h" |
9 | #include "swaynag/nagbar.h" | 9 | #include "swaynag/nagbar.h" |
10 | #include "swaynag/render.h" | 10 | #include "swaynag/render.h" |
11 | #include "swaynag/types.h" | ||
11 | #include "wlr-layer-shell-unstable-v1-client-protocol.h" | 12 | #include "wlr-layer-shell-unstable-v1-client-protocol.h" |
12 | 13 | ||
13 | static void nop() { | 14 | static void nop() { |
@@ -386,6 +387,10 @@ void nagbar_destroy(struct sway_nagbar *nagbar) { | |||
386 | free(nagbar->details.button_up.text); | 387 | free(nagbar->details.button_up.text); |
387 | free(nagbar->details.button_down.text); | 388 | free(nagbar->details.button_down.text); |
388 | 389 | ||
390 | if (nagbar->type) { | ||
391 | nagbar_type_free(nagbar->type); | ||
392 | } | ||
393 | |||
389 | if (nagbar->layer_surface) { | 394 | if (nagbar->layer_surface) { |
390 | zwlr_layer_surface_v1_destroy(nagbar->layer_surface); | 395 | zwlr_layer_surface_v1_destroy(nagbar->layer_surface); |
391 | } | 396 | } |
diff --git a/swaynag/render.c b/swaynag/render.c index 150ae3f2..134c247e 100644 --- a/swaynag/render.c +++ b/swaynag/render.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "pango.h" | 4 | #include "pango.h" |
5 | #include "pool-buffer.h" | 5 | #include "pool-buffer.h" |
6 | #include "swaynag/nagbar.h" | 6 | #include "swaynag/nagbar.h" |
7 | #include "swaynag/types.h" | ||
7 | #include "wlr-layer-shell-unstable-v1-client-protocol.h" | 8 | #include "wlr-layer-shell-unstable-v1-client-protocol.h" |
8 | 9 | ||
9 | static uint32_t render_message(cairo_t *cairo, struct sway_nagbar *nagbar) { | 10 | static uint32_t render_message(cairo_t *cairo, struct sway_nagbar *nagbar) { |
@@ -22,7 +23,7 @@ static uint32_t render_message(cairo_t *cairo, struct sway_nagbar *nagbar) { | |||
22 | return ideal_surface_height; | 23 | return ideal_surface_height; |
23 | } | 24 | } |
24 | 25 | ||
25 | cairo_set_source_u32(cairo, nagbar->colors.text); | 26 | cairo_set_source_u32(cairo, nagbar->type->text); |
26 | cairo_move_to(cairo, padding, (int)(ideal_height - text_height) / 2); | 27 | cairo_move_to(cairo, padding, (int)(ideal_height - text_height) / 2); |
27 | pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s", | 28 | pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s", |
28 | nagbar->message); | 29 | nagbar->message); |
@@ -39,17 +40,17 @@ static void render_details_scroll_button(cairo_t *cairo, | |||
39 | int border = NAGBAR_BUTTON_BORDER_THICKNESS * nagbar->scale; | 40 | int border = NAGBAR_BUTTON_BORDER_THICKNESS * nagbar->scale; |
40 | int padding = NAGBAR_BUTTON_PADDING * nagbar->scale; | 41 | int padding = NAGBAR_BUTTON_PADDING * nagbar->scale; |
41 | 42 | ||
42 | cairo_set_source_u32(cairo, nagbar->colors.border); | 43 | cairo_set_source_u32(cairo, nagbar->type->border); |
43 | cairo_rectangle(cairo, button->x, button->y, | 44 | cairo_rectangle(cairo, button->x, button->y, |
44 | button->width, button->height); | 45 | button->width, button->height); |
45 | cairo_fill(cairo); | 46 | cairo_fill(cairo); |
46 | 47 | ||
47 | cairo_set_source_u32(cairo, nagbar->colors.button_background); | 48 | cairo_set_source_u32(cairo, nagbar->type->button_background); |
48 | cairo_rectangle(cairo, button->x + border, button->y + border, | 49 | cairo_rectangle(cairo, button->x + border, button->y + border, |
49 | button->width - (border * 2), button->height - (border * 2)); | 50 | button->width - (border * 2), button->height - (border * 2)); |
50 | cairo_fill(cairo); | 51 | cairo_fill(cairo); |
51 | 52 | ||
52 | cairo_set_source_u32(cairo, nagbar->colors.text); | 53 | cairo_set_source_u32(cairo, nagbar->type->text); |
53 | cairo_move_to(cairo, button->x + border + padding, | 54 | cairo_move_to(cairo, button->x + border + padding, |
54 | button->y + border + (button->height - text_height) / 2); | 55 | button->y + border + (button->height - text_height) / 2); |
55 | pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s", button->text); | 56 | pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s", button->text); |
@@ -154,14 +155,14 @@ static uint32_t render_detailed(cairo_t *cairo, struct sway_nagbar *nagbar, | |||
154 | &nagbar->details.button_down); | 155 | &nagbar->details.button_down); |
155 | } | 156 | } |
156 | 157 | ||
157 | cairo_set_source_u32(cairo, nagbar->colors.border); | 158 | cairo_set_source_u32(cairo, nagbar->type->border); |
158 | cairo_rectangle(cairo, nagbar->details.x, nagbar->details.y, | 159 | cairo_rectangle(cairo, nagbar->details.x, nagbar->details.y, |
159 | nagbar->details.width, nagbar->details.height); | 160 | nagbar->details.width, nagbar->details.height); |
160 | cairo_fill(cairo); | 161 | cairo_fill(cairo); |
161 | 162 | ||
162 | cairo_move_to(cairo, nagbar->details.x + padding, | 163 | cairo_move_to(cairo, nagbar->details.x + padding, |
163 | nagbar->details.y + padding); | 164 | nagbar->details.y + padding); |
164 | cairo_set_source_u32(cairo, nagbar->colors.text); | 165 | cairo_set_source_u32(cairo, nagbar->type->text); |
165 | pango_cairo_show_layout(cairo, layout); | 166 | pango_cairo_show_layout(cairo, layout); |
166 | g_object_unref(layout); | 167 | g_object_unref(layout); |
167 | 168 | ||
@@ -192,17 +193,17 @@ static uint32_t render_button(cairo_t *cairo, struct sway_nagbar *nagbar, | |||
192 | button->width = text_width + padding * 2; | 193 | button->width = text_width + padding * 2; |
193 | button->height = text_height + padding * 2; | 194 | button->height = text_height + padding * 2; |
194 | 195 | ||
195 | cairo_set_source_u32(cairo, nagbar->colors.border); | 196 | cairo_set_source_u32(cairo, nagbar->type->border); |
196 | cairo_rectangle(cairo, button->x - border, button->y - border, | 197 | cairo_rectangle(cairo, button->x - border, button->y - border, |
197 | button->width + border * 2, button->height + border * 2); | 198 | button->width + border * 2, button->height + border * 2); |
198 | cairo_fill(cairo); | 199 | cairo_fill(cairo); |
199 | 200 | ||
200 | cairo_set_source_u32(cairo, nagbar->colors.button_background); | 201 | cairo_set_source_u32(cairo, nagbar->type->button_background); |
201 | cairo_rectangle(cairo, button->x, button->y, | 202 | cairo_rectangle(cairo, button->x, button->y, |
202 | button->width, button->height); | 203 | button->width, button->height); |
203 | cairo_fill(cairo); | 204 | cairo_fill(cairo); |
204 | 205 | ||
205 | cairo_set_source_u32(cairo, nagbar->colors.text); | 206 | cairo_set_source_u32(cairo, nagbar->type->text); |
206 | cairo_move_to(cairo, button->x + padding, button->y + padding); | 207 | cairo_move_to(cairo, button->x + padding, button->y + padding); |
207 | pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s", button->text); | 208 | pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s", button->text); |
208 | 209 | ||
@@ -215,7 +216,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct sway_nagbar *nagbar) { | |||
215 | uint32_t max_height = 0; | 216 | uint32_t max_height = 0; |
216 | 217 | ||
217 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | 218 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); |
218 | cairo_set_source_u32(cairo, nagbar->colors.background); | 219 | cairo_set_source_u32(cairo, nagbar->type->background); |
219 | cairo_paint(cairo); | 220 | cairo_paint(cairo); |
220 | 221 | ||
221 | uint32_t h = render_message(cairo, nagbar); | 222 | uint32_t h = render_message(cairo, nagbar); |
@@ -240,7 +241,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct sway_nagbar *nagbar) { | |||
240 | if (max_height > nagbar->height) { | 241 | if (max_height > nagbar->height) { |
241 | max_height += border; | 242 | max_height += border; |
242 | } | 243 | } |
243 | cairo_set_source_u32(cairo, nagbar->colors.border_bottom); | 244 | cairo_set_source_u32(cairo, nagbar->type->border_bottom); |
244 | cairo_rectangle(cairo, 0, nagbar->height * nagbar->scale - border, | 245 | cairo_rectangle(cairo, 0, nagbar->height * nagbar->scale - border, |
245 | nagbar->width * nagbar->scale, border); | 246 | nagbar->width * nagbar->scale, border); |
246 | cairo_fill(cairo); | 247 | cairo_fill(cairo); |
diff --git a/swaynag/swaynag.1.scd b/swaynag/swaynag.1.scd index 879aaf2e..7d250a45 100644 --- a/swaynag/swaynag.1.scd +++ b/swaynag/swaynag.1.scd | |||
@@ -1,4 +1,4 @@ | |||
1 | swaynagbar(1) | 1 | swaynag(1) |
2 | 2 | ||
3 | # NAME | 3 | # NAME |
4 | 4 | ||
@@ -13,13 +13,21 @@ _swaynag_ [options...] | |||
13 | Create a button with the text _text_ that executes _action_ when pressed. | 13 | Create a button with the text _text_ that executes _action_ when pressed. |
14 | Multiple buttons can be defined by providing the flag multiple times. | 14 | Multiple buttons can be defined by providing the flag multiple times. |
15 | 15 | ||
16 | *-c, --config* <path> | ||
17 | The config file to use. By default, the following paths are checked: | ||
18 | _$HOME/.swaynag/config_, _$XDG\_CONFIG\_HOME/swaynag/config_, and | ||
19 | _SYSCONFDIR/swaynag/config_. All flags aside from this one and _debug_ are | ||
20 | valid options in the configuration file using the format | ||
21 | _long-option=value_. All leading dashes should be omitted and the equals | ||
22 | sign is required. See swaynag(5) for more information. | ||
23 | |||
16 | *-d, --debug* | 24 | *-d, --debug* |
17 | Enable debugging. | 25 | Enable debugging. |
18 | 26 | ||
19 | *-e, --edge top|bottom* | 27 | *-e, --edge* top|bottom |
20 | Set the edge to use. | 28 | Set the edge to use. |
21 | 29 | ||
22 | *-f, --font <font>* | 30 | *-f, --font* <font> |
23 | Set the font to use. | 31 | Set the font to use. |
24 | 32 | ||
25 | *-h, --help* | 33 | *-h, --help* |
@@ -29,24 +37,29 @@ _swaynag_ [options...] | |||
29 | Read a detailed message from stdin. A button to toggle details will be | 37 | Read a detailed message from stdin. A button to toggle details will be |
30 | added. Details are shown in a scrollable multi-line text area. | 38 | added. Details are shown in a scrollable multi-line text area. |
31 | 39 | ||
32 | *-L, --detailed-button <text>* | 40 | *-L, --detailed-button* <text> |
33 | Set the text for the button that toggles details. This has no effect if | 41 | Set the text for the button that toggles details. This has no effect if |
34 | there is not a detailed message. The default is _Toggle Details_. | 42 | there is not a detailed message. The default is _Toggle Details_. |
35 | 43 | ||
36 | *-m, --message <msg>* | 44 | *-m, --message* <msg> |
37 | Set the message text. | 45 | Set the message text. |
38 | 46 | ||
39 | *-o, --output <output>* | 47 | *-o, --output* <output> |
40 | Set the output to use. This should be the name of a _xdg\_output_. If | 48 | Set the output to use. This should be the name of a _xdg\_output_. If |
41 | _xdg\_output\_manager_ is not supported, then the first detected output | 49 | _xdg\_output\_manager_ is not supported, then the first detected output |
42 | will be used | 50 | will be used |
43 | 51 | ||
44 | *-s, --dismiss-button <text>* | 52 | *-s, --dismiss-button* <text> |
45 | Sets the text for the dismiss nagbar button. The default is _X_. | 53 | Sets the text for the dismiss nagbar button. The default is _X_. |
46 | 54 | ||
47 | *-t, --type error|warning* | 55 | *-t, --type* |
48 | Set the message type. | 56 | Set the message type. Two types are created by default _error_ and |
57 | _warning_. Custom types can be defined in the config file. See | ||
58 | _--config_ and swaynag(5) for details. Both of the default types can be | ||
59 | overridden in the config file as well. | ||
49 | 60 | ||
50 | *-v, --version | 61 | *-v, --version* |
51 | Show the version number and quit. | 62 | Show the version number and quit. |
52 | 63 | ||
64 | # SEE | ||
65 | swaynag(5) | ||
diff --git a/swaynag/swaynag.5.scd b/swaynag/swaynag.5.scd new file mode 100644 index 00000000..a4e05e3a --- /dev/null +++ b/swaynag/swaynag.5.scd | |||
@@ -0,0 +1,57 @@ | |||
1 | swaynag(5) | ||
2 | |||
3 | # NAME | ||
4 | |||
5 | swaynag - swaynag configuration file | ||
6 | |||
7 | # SYNOPSIS | ||
8 | |||
9 | $HOME/.swaynag/config, $XDG\_CONFIG\_HOME/swaynag/config, | ||
10 | SYSCONFDIR/swaynag/config | ||
11 | |||
12 | # CONFIG FILE | ||
13 | At the top of the config file, _swaynag_ options can be set using the format | ||
14 | _long-option=value_. These will be used as default values if _swaynag_ is not | ||
15 | given the option. This can be useful for setting a preferred font, output, and | ||
16 | edge. | ||
17 | |||
18 | Below the options, custom types may be defined. To define a type, use the | ||
19 | following format: | ||
20 | |||
21 | ``` | ||
22 | [name-of-type] | ||
23 | color=RRGGBB[AA] | ||
24 | ``` | ||
25 | |||
26 | All colors may be given in the form _RRGGBB_ or _RRGGBBAA_. The following | ||
27 | colors can be set: | ||
28 | |||
29 | *background* | ||
30 | The background color for _swaynag_. | ||
31 | |||
32 | *border* | ||
33 | The color to use for borders of buttons. | ||
34 | |||
35 | *border-bottom* | ||
36 | The color of the border line at the bottom of _swaynag_. | ||
37 | |||
38 | *button-background* | ||
39 | The background color for the buttons. | ||
40 | |||
41 | *text* | ||
42 | The color of the text. | ||
43 | |||
44 | # EXAMPLE | ||
45 | ``` | ||
46 | font=Monospace 12 | ||
47 | |||
48 | [green] | ||
49 | background=00AA00 | ||
50 | border=006600 | ||
51 | border-bottom=004400 | ||
52 | text=FFFFFF | ||
53 | button-background=00CC00 | ||
54 | ``` | ||
55 | |||
56 | # SEE | ||
57 | swaynag(1) | ||
diff --git a/swaynag/types.c b/swaynag/types.c new file mode 100644 index 00000000..8dd99d2a --- /dev/null +++ b/swaynag/types.c | |||
@@ -0,0 +1,116 @@ | |||
1 | #define _XOPEN_SOURCE 500 | ||
2 | #include <getopt.h> | ||
3 | #include <stdbool.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <stdint.h> | ||
6 | #include <string.h> | ||
7 | #include <strings.h> | ||
8 | #include "list.h" | ||
9 | #include "swaynag/types.h" | ||
10 | #include "util.h" | ||
11 | |||
12 | void nagbar_types_add_default(list_t *types) { | ||
13 | struct sway_nagbar_type *type_error; | ||
14 | type_error = calloc(1, sizeof(struct sway_nagbar_type)); | ||
15 | type_error->name = strdup("error"); | ||
16 | type_error->button_background = 0x680A0AFF; | ||
17 | type_error->background = 0x900000FF; | ||
18 | type_error->text = 0xFFFFFFFF; | ||
19 | type_error->border = 0xD92424FF; | ||
20 | type_error->border_bottom = 0x470909FF; | ||
21 | list_add(types, type_error); | ||
22 | |||
23 | struct sway_nagbar_type *type_warning; | ||
24 | type_warning = calloc(1, sizeof(struct sway_nagbar_type)); | ||
25 | type_warning->name = strdup("warning"); | ||
26 | type_warning->button_background = 0xFFC100FF; | ||
27 | type_warning->background = 0xFFA800FF; | ||
28 | type_warning->text = 0x000000FF; | ||
29 | type_warning->border = 0xAB7100FF; | ||
30 | type_warning->border_bottom = 0xAB7100FF; | ||
31 | list_add(types, type_warning); | ||
32 | } | ||
33 | |||
34 | struct sway_nagbar_type *nagbar_type_get(list_t *types, char *name) { | ||
35 | for (int i = 0; i < types->length; i++) { | ||
36 | struct sway_nagbar_type *type = types->items[i]; | ||
37 | if (strcasecmp(type->name, name) == 0) { | ||
38 | return type; | ||
39 | } | ||
40 | } | ||
41 | return NULL; | ||
42 | } | ||
43 | |||
44 | struct sway_nagbar_type *nagbar_type_clone(struct sway_nagbar_type *type) { | ||
45 | struct sway_nagbar_type *clone; | ||
46 | clone = calloc(1, sizeof(struct sway_nagbar_type)); | ||
47 | clone->name = strdup(type->name); | ||
48 | clone->button_background = type->button_background; | ||
49 | clone->background = type->background; | ||
50 | clone->text = type->text; | ||
51 | clone->border = type->border; | ||
52 | clone->border_bottom = type->border_bottom; | ||
53 | return clone; | ||
54 | } | ||
55 | |||
56 | void nagbar_type_free(struct sway_nagbar_type *type) { | ||
57 | free(type->name); | ||
58 | free(type); | ||
59 | } | ||
60 | |||
61 | void nagbar_types_free(list_t *types) { | ||
62 | while (types->length) { | ||
63 | struct sway_nagbar_type *type = types->items[0]; | ||
64 | nagbar_type_free(type); | ||
65 | list_del(types, 0); | ||
66 | } | ||
67 | list_free(types); | ||
68 | } | ||
69 | |||
70 | int nagbar_parse_type(int argc, char **argv, struct sway_nagbar_type *type) { | ||
71 | enum color_option { | ||
72 | COLOR_BACKGROUND, | ||
73 | COLOR_BORDER, | ||
74 | COLOR_BORDER_BOTTOM, | ||
75 | COLOR_BUTTON, | ||
76 | COLOR_TEXT, | ||
77 | }; | ||
78 | |||
79 | static struct option opts[] = { | ||
80 | {"background", required_argument, NULL, COLOR_BACKGROUND}, | ||
81 | {"border", required_argument, NULL, COLOR_BORDER}, | ||
82 | {"border-bottom", required_argument, NULL, COLOR_BORDER_BOTTOM}, | ||
83 | {"button-background", required_argument, NULL, COLOR_BUTTON}, | ||
84 | {"text", required_argument, NULL, COLOR_TEXT}, | ||
85 | {0, 0, 0, 0} | ||
86 | }; | ||
87 | |||
88 | optind = 1; | ||
89 | while (1) { | ||
90 | int c = getopt_long(argc, argv, "", opts, NULL); | ||
91 | if (c == -1) { | ||
92 | break; | ||
93 | } | ||
94 | switch (c) { | ||
95 | case COLOR_BACKGROUND: | ||
96 | type->background = parse_color(optarg); | ||
97 | break; | ||
98 | case COLOR_BORDER: | ||
99 | type->border = parse_color(optarg); | ||
100 | break; | ||
101 | case COLOR_BORDER_BOTTOM: | ||
102 | type->border_bottom = parse_color(optarg); | ||
103 | break; | ||
104 | case COLOR_BUTTON: | ||
105 | type->button_background = parse_color(optarg); | ||
106 | break; | ||
107 | case COLOR_TEXT: | ||
108 | type->text = parse_color(optarg); | ||
109 | break; | ||
110 | default: | ||
111 | break; | ||
112 | } | ||
113 | } | ||
114 | return 0; | ||
115 | } | ||
116 | |||