swaynag: implement config file support

This commit is contained in:
Brian Ashworth 2018-07-28 09:34:25 -04:00
parent a4f7bf23b2
commit 8463a2896a
10 changed files with 499 additions and 137 deletions

View file

@ -1,8 +1,9 @@
#ifndef _SWAY_NAGBAR_NAGBAR_H #ifndef _SWAY_NAGBAR_NAGBAR_H
#define _SWAY_NAGBAR_NAGNAR_H #define _SWAY_NAGBAR_NAGBAR_H
#include <stdint.h> #include <stdint.h>
#include "list.h" #include "list.h"
#include "pool-buffer.h" #include "pool-buffer.h"
#include "swaynag/types.h"
#include "xdg-output-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h"
#define NAGBAR_BAR_BORDER_THICKNESS 2 #define NAGBAR_BAR_BORDER_THICKNESS 2
@ -16,25 +17,12 @@
#define NAGBAR_MAX_HEIGHT 500 #define NAGBAR_MAX_HEIGHT 500
enum sway_nagbar_type {
NAGBAR_ERROR,
NAGBAR_WARNING,
};
enum sway_nagbar_action_type { enum sway_nagbar_action_type {
NAGBAR_ACTION_DISMISS, NAGBAR_ACTION_DISMISS,
NAGBAR_ACTION_EXPAND, NAGBAR_ACTION_EXPAND,
NAGBAR_ACTION_COMMAND, NAGBAR_ACTION_COMMAND,
}; };
struct sway_nagbar_colors {
uint32_t button_background;
uint32_t background;
uint32_t text;
uint32_t border;
uint32_t border_bottom;
};
struct sway_nagbar_pointer { struct sway_nagbar_pointer {
struct wl_pointer *pointer; struct wl_pointer *pointer;
struct wl_cursor_theme *cursor_theme; struct wl_cursor_theme *cursor_theme;
@ -72,6 +60,7 @@ struct sway_nagbar_details {
int offset; int offset;
int visible_lines; int visible_lines;
int total_lines; int total_lines;
struct sway_nagbar_button button_details;
struct sway_nagbar_button button_up; struct sway_nagbar_button button_up;
struct sway_nagbar_button button_down; struct sway_nagbar_button button_down;
}; };
@ -97,8 +86,7 @@ struct sway_nagbar {
struct pool_buffer buffers[2]; struct pool_buffer buffers[2];
struct pool_buffer *current_buffer; struct pool_buffer *current_buffer;
enum sway_nagbar_type type; struct sway_nagbar_type *type;
struct sway_nagbar_colors colors;
uint32_t anchors; uint32_t anchors;
char *message; char *message;
char *font; char *font;

25
include/swaynag/types.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef _SWAY_NAGBAR_TYPES_H
#define _SWAY_NAGBAR_TYPES_H
struct sway_nagbar_type {
char *name;
uint32_t button_background;
uint32_t background;
uint32_t text;
uint32_t border;
uint32_t border_bottom;
};
void nagbar_types_add_default(list_t *types);
struct sway_nagbar_type *nagbar_type_get(list_t *types, char *name);
struct sway_nagbar_type *nagbar_type_clone(struct sway_nagbar_type *type);
void nagbar_type_free(struct sway_nagbar_type *type);
void nagbar_types_free(list_t *types);
int nagbar_parse_type(int argc, char **argv, struct sway_nagbar_type *type);
#endif

View file

@ -83,6 +83,7 @@ if scdoc.found()
'swaymsg/swaymsg.1.scd', 'swaymsg/swaymsg.1.scd',
'swayidle/swayidle.1.scd', 'swayidle/swayidle.1.scd',
'swaynag/swaynag.1.scd', 'swaynag/swaynag.1.scd',
'swaynag/swaynag.5.scd',
] ]
foreach filename : man_files foreach filename : man_files
topic = filename.split('.')[-3].split('/')[-1] topic = filename.split('.')[-3].split('/')[-1]

View file

@ -1,10 +1,14 @@
#define _XOPEN_SOURCE 500 #define _XOPEN_SOURCE 700
#define _POSIX_C_SOURCE 200112L
#include <getopt.h> #include <getopt.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h>
#include <wordexp.h>
#include "log.h" #include "log.h"
#include "list.h" #include "list.h"
#include "readline.h" #include "readline.h"
#include "swaynag/nagbar.h" #include "swaynag/nagbar.h"
#include "swaynag/types.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h"
static struct sway_nagbar nagbar; static struct sway_nagbar nagbar;
@ -19,22 +23,6 @@ void sway_terminate(int code) {
exit(code); exit(code);
} }
static void set_nagbar_colors() {
if (nagbar.type == NAGBAR_ERROR) {
nagbar.colors.button_background = 0x680A0AFF;
nagbar.colors.background = 0x900000FF;
nagbar.colors.text = 0xFFFFFFFF;
nagbar.colors.border = 0xD92424FF;
nagbar.colors.border_bottom = 0x470909FF;
} else if (nagbar.type == NAGBAR_WARNING) {
nagbar.colors.button_background = 0xFFC100FF;
nagbar.colors.background = 0xFFA800FF;
nagbar.colors.text = 0x000000FF;
nagbar.colors.border = 0xAB7100FF;
nagbar.colors.border_bottom = 0xAB7100FF;
}
}
static char *read_from_stdin() { static char *read_from_stdin() {
char *buffer = NULL; char *buffer = NULL;
while (!feof(stdin)) { while (!feof(stdin)) {
@ -61,32 +49,11 @@ static char *read_from_stdin() {
return buffer; return buffer;
} }
int main(int argc, char **argv) { static int parse_options(int argc, char **argv, struct sway_nagbar *nagbar,
int exit_code = EXIT_SUCCESS; list_t *types, char **config, bool *debug) {
bool debug = false;
memset(&nagbar, 0, sizeof(nagbar));
nagbar.anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
| ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
nagbar.type = NAGBAR_ERROR;
set_nagbar_colors();
nagbar.font = strdup("pango:monospace 10");
nagbar.buttons = create_list();
struct sway_nagbar_button *button_close =
calloc(sizeof(struct sway_nagbar_button), 1);
button_close->text = strdup("X");
button_close->type = NAGBAR_ACTION_DISMISS;
list_add(nagbar.buttons, button_close);
struct sway_nagbar_button *button_details =
calloc(sizeof(struct sway_nagbar_button), 1);
button_details->text = strdup("Toggle Details");
button_details->type = NAGBAR_ACTION_EXPAND;
static struct option opts[] = { static struct option opts[] = {
{"button", required_argument, NULL, 'b'}, {"button", required_argument, NULL, 'b'},
{"config", required_argument, NULL, 'c'},
{"debug", no_argument, NULL, 'd'}, {"debug", no_argument, NULL, 'd'},
{"edge", required_argument, NULL, 'e'}, {"edge", required_argument, NULL, 'e'},
{"font", required_argument, NULL, 'f'}, {"font", required_argument, NULL, 'f'},
@ -106,6 +73,7 @@ int main(int argc, char **argv) {
"\n" "\n"
" -b, --button <text> <action> Create a button with text that " " -b, --button <text> <action> Create a button with text that "
"executes action when pressed. Multiple buttons can be defined.\n" "executes action when pressed. Multiple buttons can be defined.\n"
" -c, --config <path> Path to config file.\n"
" -d, --debug Enable debugging.\n" " -d, --debug Enable debugging.\n"
" -e, --edge top|bottom Set the edge to use.\n" " -e, --edge top|bottom Set the edge to use.\n"
" -f, --font <font> Set the font to use.\n" " -f, --font <font> Set the font to use.\n"
@ -115,97 +83,278 @@ int main(int argc, char **argv) {
" -m, --message <msg> Set the message text.\n" " -m, --message <msg> Set the message text.\n"
" -o, --output <output> Set the output to use.\n" " -o, --output <output> Set the output to use.\n"
" -s, --dismiss-button <text> Set the dismiss button text.\n" " -s, --dismiss-button <text> Set the dismiss button text.\n"
" -t, --type error|warning Set the message type.\n" " -t, --type <type> Set the message type.\n"
" -v, --version Show the version number and quit.\n"; " -v, --version Show the version number and quit.\n";
optind = 1;
while (1) { while (1) {
int c = getopt_long(argc, argv, "b:de:f:hlL:m:o:s:t:v", opts, NULL); int c = getopt_long(argc, argv, "b:c:de:f:hlL:m:o:s:t:v", opts, NULL);
if (c == -1) { if (c == -1) {
break; break;
} }
switch (c) { switch (c) {
case 'b': // Button case 'b': // Button
if (optind >= argc) { if (nagbar) {
fprintf(stderr, "Missing action for button %s\n", optarg); if (optind >= argc) {
exit_code = EXIT_FAILURE; fprintf(stderr, "Missing action for button %s\n", optarg);
goto cleanup; return EXIT_FAILURE;
}
struct sway_nagbar_button *button;
button = calloc(sizeof(struct sway_nagbar_button), 1);
button->text = strdup(optarg);
button->type = NAGBAR_ACTION_COMMAND;
button->action = strdup(argv[optind]);
optind++;
list_add(nagbar->buttons, button);
}
break;
case 'c': // Config
if (config) {
*config = strdup(optarg);
} }
struct sway_nagbar_button *button;
button = calloc(sizeof(struct sway_nagbar_button), 1);
button->text = strdup(optarg);
button->type = NAGBAR_ACTION_COMMAND;
button->action = strdup(argv[optind]);
optind++;
list_add(nagbar.buttons, button);
break; break;
case 'd': // Debug case 'd': // Debug
debug = true; if (debug) {
*debug = true;
}
break; break;
case 'e': // Edge case 'e': // Edge
if (strcmp(optarg, "top") == 0) { if (nagbar) {
nagbar.anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP if (strcmp(optarg, "top") == 0) {
| ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT nagbar->anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
} else if (strcmp(optarg, "bottom") == 0) { | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
nagbar.anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM } else if (strcmp(optarg, "bottom") == 0) {
| ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT nagbar->anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
} else { | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
fprintf(stderr, "Invalid edge: %s\n", optarg); } else {
exit_code = EXIT_FAILURE; fprintf(stderr, "Invalid edge: %s\n", optarg);
goto cleanup; return EXIT_FAILURE;
}
} }
break; break;
case 'f': // Font case 'f': // Font
free(nagbar.font); if (nagbar) {
nagbar.font = strdup(optarg); free(nagbar->font);
nagbar->font = strdup(optarg);
}
break; break;
case 'l': // Detailed Message case 'l': // Detailed Message
free(nagbar.details.message); if (nagbar) {
nagbar.details.message = read_from_stdin(); free(nagbar->details.message);
nagbar.details.button_up.text = strdup(""); nagbar->details.message = read_from_stdin();
nagbar.details.button_down.text = strdup(""); nagbar->details.button_up.text = strdup("");
nagbar->details.button_down.text = strdup("");
}
break; break;
case 'L': // Detailed Button Text case 'L': // Detailed Button Text
free(button_details->text); if (nagbar) {
button_details->text = strdup(optarg); free(nagbar->details.button_details.text);
nagbar->details.button_details.text = strdup(optarg);
}
break; break;
case 'm': // Message case 'm': // Message
free(nagbar.message); if (nagbar) {
nagbar.message = strdup(optarg); free(nagbar->message);
nagbar->message = strdup(optarg);
}
break; break;
case 'o': // Output case 'o': // Output
free(nagbar.output.name); if (nagbar) {
nagbar.output.name = strdup(optarg); free(nagbar->output.name);
nagbar->output.name = strdup(optarg);
}
break; break;
case 's': // Dismiss Button Text case 's': // Dismiss Button Text
free(button_close->text); if (nagbar) {
button_close->text = strdup(optarg); struct sway_nagbar_button *button_close;
button_close = nagbar->buttons->items[0];
free(button_close->text);
button_close->text = strdup(optarg);
}
break; break;
case 't': // Type case 't': // Type
if (strcmp(optarg, "error") == 0) { if (nagbar) {
nagbar.type = NAGBAR_ERROR; nagbar->type = nagbar_type_get(types, optarg);
} else if (strcmp(optarg, "warning") == 0) { if (!nagbar->type) {
nagbar.type = NAGBAR_WARNING; fprintf(stderr, "Unknown type %s\n", optarg);
} else { return EXIT_FAILURE;
fprintf(stderr, "Type must be either 'error' or 'warning'\n"); }
exit_code = EXIT_FAILURE;
goto cleanup;
} }
set_nagbar_colors();
break; break;
case 'v': // Version case 'v': // Version
fprintf(stdout, "swaynag version " SWAY_VERSION "\n"); fprintf(stdout, "swaynag version " SWAY_VERSION "\n");
exit_code = EXIT_SUCCESS; return -1;
goto cleanup;
default: // Help or unknown flag default: // Help or unknown flag
fprintf(c == 'h' ? stdout : stderr, "%s", usage); fprintf(c == 'h' ? stdout : stderr, "%s", usage);
exit_code = c == 'h' ? EXIT_SUCCESS : EXIT_FAILURE; return -1;
}
}
return 0;
}
static bool file_exists(const char *path) {
return path && access(path, R_OK) != -1;
}
static char *get_config_path(void) {
static const char *config_paths[] = {
"$HOME/.swaynag/config",
"$XDG_CONFIG_HOME/swaynag/config",
SYSCONFDIR "/swaynag/config",
};
if (!getenv("XDG_CONFIG_HOME")) {
char *home = getenv("HOME");
char *config_home = malloc(strlen(home) + strlen("/.config") + 1);
if (!config_home) {
wlr_log(WLR_ERROR, "Unable to allocate $HOME/.config");
} else {
strcpy(config_home, home);
strcat(config_home, "/.config");
setenv("XDG_CONFIG_HOME", config_home, 1);
wlr_log(WLR_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home);
free(config_home);
}
}
wordexp_t p;
char *path;
for (size_t i = 0; i < sizeof(config_paths) / sizeof(char *); ++i) {
if (wordexp(config_paths[i], &p, 0) == 0) {
path = strdup(p.we_wordv[0]);
wordfree(&p);
if (file_exists(path)) {
return path;
}
free(path);
}
}
return NULL;
}
static int load_config(char *path, struct sway_nagbar *nagbar, list_t *types) {
FILE *config = fopen(path, "r");
if (!config) {
fprintf(stderr, "Failed to read config. Running without it.\n");
return 0;
}
struct sway_nagbar_type *type = NULL;
char *line;
int line_number = 0;
while (!feof(config)) {
line = read_line(config);
if (!line) {
continue;
}
line_number++;
if (line[0] == '#') {
free(line);
continue;
}
if (strlen(line) == 0) {
free(line);
continue;
}
if (line[0] == '[') {
char *close = strchr(line, ']');
if (!close) {
free(line);
fclose(config);
fprintf(stderr, "Closing bracket not found on line %d\n",
line_number);
return 1;
}
char *name = calloc(1, close - line);
strncat(name, line + 1, close - line - 1);
type = nagbar_type_get(types, name);
if (!type) {
type = calloc(1, sizeof(struct sway_nagbar_type));
type->name = strdup(name);
list_add(types, type);
}
free(name);
} else {
char flag[strlen(line) + 3];
sprintf(flag, "--%s", line);
char *argv[] = {"swaynag", flag};
int result;
if (type) {
result = nagbar_parse_type(2, argv, type);
} else {
result = parse_options(2, argv, nagbar, types, NULL, NULL);
}
if (result != 0) {
free(line);
fclose(config);
return result;
}
}
free(line);
}
fclose(config);
return 0;
}
int main(int argc, char **argv) {
int exit_code = EXIT_SUCCESS;
list_t *types = create_list();
nagbar_types_add_default(types);
memset(&nagbar, 0, sizeof(nagbar));
nagbar.anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
| ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
nagbar.font = strdup("pango:monospace 10");
nagbar.buttons = create_list();
struct sway_nagbar_button *button_close =
calloc(sizeof(struct sway_nagbar_button), 1);
button_close->text = strdup("X");
button_close->type = NAGBAR_ACTION_DISMISS;
list_add(nagbar.buttons, button_close);
nagbar.details.button_details.text = strdup("Toggle Details");
nagbar.details.button_details.type = NAGBAR_ACTION_EXPAND;
char *config_path = NULL;
bool debug = false;
int launch_status = parse_options(argc, argv, NULL, NULL,
&config_path, &debug);
if (launch_status != 0) {
exit_code = launch_status;
goto cleanup;
}
wlr_log_init(debug ? WLR_DEBUG : WLR_ERROR, NULL);
if (!config_path) {
config_path = get_config_path();
}
if (config_path) {
wlr_log(WLR_DEBUG, "Loading config file: %s", config_path);
int config_status = load_config(config_path, &nagbar, types);
free(config_path);
if (config_status != 0) {
exit_code = config_status;
goto cleanup; goto cleanup;
} }
} }
wlr_log_init(debug ? WLR_DEBUG : WLR_ERROR, NULL); if (argc > 1) {
int result = parse_options(argc, argv, &nagbar, types, NULL, NULL);
if (result != 0) {
exit_code = result;
goto cleanup;
}
}
if (!nagbar.message) { if (!nagbar.message) {
wlr_log(WLR_ERROR, "No message passed. Please provide --message/-m"); wlr_log(WLR_ERROR, "No message passed. Please provide --message/-m");
@ -213,16 +362,22 @@ int main(int argc, char **argv) {
goto cleanup; goto cleanup;
} }
if (!nagbar.type) {
nagbar.type = nagbar_type_get(types, "error");
}
nagbar.type = nagbar_type_clone(nagbar.type);
nagbar_types_free(types);
if (nagbar.details.message) { if (nagbar.details.message) {
list_add(nagbar.buttons, button_details); list_add(nagbar.buttons, &nagbar.details.button_details);
} else { } else {
free(button_details->text); free(nagbar.details.button_details.text);
free(button_details);
} }
wlr_log(WLR_DEBUG, "Output: %s", nagbar.output.name); wlr_log(WLR_DEBUG, "Output: %s", nagbar.output.name);
wlr_log(WLR_DEBUG, "Anchors: %d", nagbar.anchors); wlr_log(WLR_DEBUG, "Anchors: %d", nagbar.anchors);
wlr_log(WLR_DEBUG, "Type: %d", nagbar.type); wlr_log(WLR_DEBUG, "Type: %s", nagbar.type->name);
wlr_log(WLR_DEBUG, "Message: %s", nagbar.message); wlr_log(WLR_DEBUG, "Message: %s", nagbar.message);
wlr_log(WLR_DEBUG, "Font: %s", nagbar.font); wlr_log(WLR_DEBUG, "Font: %s", nagbar.font);
wlr_log(WLR_DEBUG, "Buttons"); wlr_log(WLR_DEBUG, "Buttons");
@ -238,8 +393,8 @@ int main(int argc, char **argv) {
return exit_code; return exit_code;
cleanup: cleanup:
free(button_details->text); nagbar_types_free(types);
free(button_details); free(nagbar.details.button_details.text);
nagbar_destroy(&nagbar); nagbar_destroy(&nagbar);
return exit_code; return exit_code;
} }

View file

@ -3,6 +3,7 @@ executable(
'main.c', 'main.c',
'nagbar.c', 'nagbar.c',
'render.c', 'render.c',
'types.c',
], ],
include_directories: [sway_inc], include_directories: [sway_inc],
dependencies: [ dependencies: [

View file

@ -8,6 +8,7 @@
#include "list.h" #include "list.h"
#include "swaynag/nagbar.h" #include "swaynag/nagbar.h"
#include "swaynag/render.h" #include "swaynag/render.h"
#include "swaynag/types.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h"
static void nop() { static void nop() {
@ -386,6 +387,10 @@ void nagbar_destroy(struct sway_nagbar *nagbar) {
free(nagbar->details.button_up.text); free(nagbar->details.button_up.text);
free(nagbar->details.button_down.text); free(nagbar->details.button_down.text);
if (nagbar->type) {
nagbar_type_free(nagbar->type);
}
if (nagbar->layer_surface) { if (nagbar->layer_surface) {
zwlr_layer_surface_v1_destroy(nagbar->layer_surface); zwlr_layer_surface_v1_destroy(nagbar->layer_surface);
} }

View file

@ -4,6 +4,7 @@
#include "pango.h" #include "pango.h"
#include "pool-buffer.h" #include "pool-buffer.h"
#include "swaynag/nagbar.h" #include "swaynag/nagbar.h"
#include "swaynag/types.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h"
static uint32_t render_message(cairo_t *cairo, struct sway_nagbar *nagbar) { 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) {
return ideal_surface_height; return ideal_surface_height;
} }
cairo_set_source_u32(cairo, nagbar->colors.text); cairo_set_source_u32(cairo, nagbar->type->text);
cairo_move_to(cairo, padding, (int)(ideal_height - text_height) / 2); cairo_move_to(cairo, padding, (int)(ideal_height - text_height) / 2);
pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s", pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s",
nagbar->message); nagbar->message);
@ -39,17 +40,17 @@ static void render_details_scroll_button(cairo_t *cairo,
int border = NAGBAR_BUTTON_BORDER_THICKNESS * nagbar->scale; int border = NAGBAR_BUTTON_BORDER_THICKNESS * nagbar->scale;
int padding = NAGBAR_BUTTON_PADDING * nagbar->scale; int padding = NAGBAR_BUTTON_PADDING * nagbar->scale;
cairo_set_source_u32(cairo, nagbar->colors.border); cairo_set_source_u32(cairo, nagbar->type->border);
cairo_rectangle(cairo, button->x, button->y, cairo_rectangle(cairo, button->x, button->y,
button->width, button->height); button->width, button->height);
cairo_fill(cairo); cairo_fill(cairo);
cairo_set_source_u32(cairo, nagbar->colors.button_background); cairo_set_source_u32(cairo, nagbar->type->button_background);
cairo_rectangle(cairo, button->x + border, button->y + border, cairo_rectangle(cairo, button->x + border, button->y + border,
button->width - (border * 2), button->height - (border * 2)); button->width - (border * 2), button->height - (border * 2));
cairo_fill(cairo); cairo_fill(cairo);
cairo_set_source_u32(cairo, nagbar->colors.text); cairo_set_source_u32(cairo, nagbar->type->text);
cairo_move_to(cairo, button->x + border + padding, cairo_move_to(cairo, button->x + border + padding,
button->y + border + (button->height - text_height) / 2); button->y + border + (button->height - text_height) / 2);
pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s", button->text); 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,
&nagbar->details.button_down); &nagbar->details.button_down);
} }
cairo_set_source_u32(cairo, nagbar->colors.border); cairo_set_source_u32(cairo, nagbar->type->border);
cairo_rectangle(cairo, nagbar->details.x, nagbar->details.y, cairo_rectangle(cairo, nagbar->details.x, nagbar->details.y,
nagbar->details.width, nagbar->details.height); nagbar->details.width, nagbar->details.height);
cairo_fill(cairo); cairo_fill(cairo);
cairo_move_to(cairo, nagbar->details.x + padding, cairo_move_to(cairo, nagbar->details.x + padding,
nagbar->details.y + padding); nagbar->details.y + padding);
cairo_set_source_u32(cairo, nagbar->colors.text); cairo_set_source_u32(cairo, nagbar->type->text);
pango_cairo_show_layout(cairo, layout); pango_cairo_show_layout(cairo, layout);
g_object_unref(layout); g_object_unref(layout);
@ -192,17 +193,17 @@ static uint32_t render_button(cairo_t *cairo, struct sway_nagbar *nagbar,
button->width = text_width + padding * 2; button->width = text_width + padding * 2;
button->height = text_height + padding * 2; button->height = text_height + padding * 2;
cairo_set_source_u32(cairo, nagbar->colors.border); cairo_set_source_u32(cairo, nagbar->type->border);
cairo_rectangle(cairo, button->x - border, button->y - border, cairo_rectangle(cairo, button->x - border, button->y - border,
button->width + border * 2, button->height + border * 2); button->width + border * 2, button->height + border * 2);
cairo_fill(cairo); cairo_fill(cairo);
cairo_set_source_u32(cairo, nagbar->colors.button_background); cairo_set_source_u32(cairo, nagbar->type->button_background);
cairo_rectangle(cairo, button->x, button->y, cairo_rectangle(cairo, button->x, button->y,
button->width, button->height); button->width, button->height);
cairo_fill(cairo); cairo_fill(cairo);
cairo_set_source_u32(cairo, nagbar->colors.text); cairo_set_source_u32(cairo, nagbar->type->text);
cairo_move_to(cairo, button->x + padding, button->y + padding); cairo_move_to(cairo, button->x + padding, button->y + padding);
pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s", button->text); pango_printf(cairo, nagbar->font, nagbar->scale, true, "%s", button->text);
@ -215,7 +216,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct sway_nagbar *nagbar) {
uint32_t max_height = 0; uint32_t max_height = 0;
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
cairo_set_source_u32(cairo, nagbar->colors.background); cairo_set_source_u32(cairo, nagbar->type->background);
cairo_paint(cairo); cairo_paint(cairo);
uint32_t h = render_message(cairo, nagbar); uint32_t h = render_message(cairo, nagbar);
@ -240,7 +241,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct sway_nagbar *nagbar) {
if (max_height > nagbar->height) { if (max_height > nagbar->height) {
max_height += border; max_height += border;
} }
cairo_set_source_u32(cairo, nagbar->colors.border_bottom); cairo_set_source_u32(cairo, nagbar->type->border_bottom);
cairo_rectangle(cairo, 0, nagbar->height * nagbar->scale - border, cairo_rectangle(cairo, 0, nagbar->height * nagbar->scale - border,
nagbar->width * nagbar->scale, border); nagbar->width * nagbar->scale, border);
cairo_fill(cairo); cairo_fill(cairo);

View file

@ -1,4 +1,4 @@
swaynagbar(1) swaynag(1)
# NAME # NAME
@ -13,13 +13,21 @@ _swaynag_ [options...]
Create a button with the text _text_ that executes _action_ when pressed. Create a button with the text _text_ that executes _action_ when pressed.
Multiple buttons can be defined by providing the flag multiple times. Multiple buttons can be defined by providing the flag multiple times.
*-c, --config* <path>
The config file to use. By default, the following paths are checked:
_$HOME/.swaynag/config_, _$XDG\_CONFIG\_HOME/swaynag/config_, and
_SYSCONFDIR/swaynag/config_. All flags aside from this one and _debug_ are
valid options in the configuration file using the format
_long-option=value_. All leading dashes should be omitted and the equals
sign is required. See swaynag(5) for more information.
*-d, --debug* *-d, --debug*
Enable debugging. Enable debugging.
*-e, --edge top|bottom* *-e, --edge* top|bottom
Set the edge to use. Set the edge to use.
*-f, --font <font>* *-f, --font* <font>
Set the font to use. Set the font to use.
*-h, --help* *-h, --help*
@ -29,24 +37,29 @@ _swaynag_ [options...]
Read a detailed message from stdin. A button to toggle details will be Read a detailed message from stdin. A button to toggle details will be
added. Details are shown in a scrollable multi-line text area. added. Details are shown in a scrollable multi-line text area.
*-L, --detailed-button <text>* *-L, --detailed-button* <text>
Set the text for the button that toggles details. This has no effect if Set the text for the button that toggles details. This has no effect if
there is not a detailed message. The default is _Toggle Details_. there is not a detailed message. The default is _Toggle Details_.
*-m, --message <msg>* *-m, --message* <msg>
Set the message text. Set the message text.
*-o, --output <output>* *-o, --output* <output>
Set the output to use. This should be the name of a _xdg\_output_. If Set the output to use. This should be the name of a _xdg\_output_. If
_xdg\_output\_manager_ is not supported, then the first detected output _xdg\_output\_manager_ is not supported, then the first detected output
will be used will be used
*-s, --dismiss-button <text>* *-s, --dismiss-button* <text>
Sets the text for the dismiss nagbar button. The default is _X_. Sets the text for the dismiss nagbar button. The default is _X_.
*-t, --type error|warning* *-t, --type*
Set the message type. Set the message type. Two types are created by default _error_ and
_warning_. Custom types can be defined in the config file. See
_--config_ and swaynag(5) for details. Both of the default types can be
overridden in the config file as well.
*-v, --version *-v, --version*
Show the version number and quit. Show the version number and quit.
# SEE
swaynag(5)

57
swaynag/swaynag.5.scd Normal file
View file

@ -0,0 +1,57 @@
swaynag(5)
# NAME
swaynag - swaynag configuration file
# SYNOPSIS
$HOME/.swaynag/config, $XDG\_CONFIG\_HOME/swaynag/config,
SYSCONFDIR/swaynag/config
# CONFIG FILE
At the top of the config file, _swaynag_ options can be set using the format
_long-option=value_. These will be used as default values if _swaynag_ is not
given the option. This can be useful for setting a preferred font, output, and
edge.
Below the options, custom types may be defined. To define a type, use the
following format:
```
[name-of-type]
color=RRGGBB[AA]
```
All colors may be given in the form _RRGGBB_ or _RRGGBBAA_. The following
colors can be set:
*background*
The background color for _swaynag_.
*border*
The color to use for borders of buttons.
*border-bottom*
The color of the border line at the bottom of _swaynag_.
*button-background*
The background color for the buttons.
*text*
The color of the text.
# EXAMPLE
```
font=Monospace 12
[green]
background=00AA00
border=006600
border-bottom=004400
text=FFFFFF
button-background=00CC00
```
# SEE
swaynag(1)

116
swaynag/types.c Normal file
View file

@ -0,0 +1,116 @@
#define _XOPEN_SOURCE 500
#include <getopt.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include "list.h"
#include "swaynag/types.h"
#include "util.h"
void nagbar_types_add_default(list_t *types) {
struct sway_nagbar_type *type_error;
type_error = calloc(1, sizeof(struct sway_nagbar_type));
type_error->name = strdup("error");
type_error->button_background = 0x680A0AFF;
type_error->background = 0x900000FF;
type_error->text = 0xFFFFFFFF;
type_error->border = 0xD92424FF;
type_error->border_bottom = 0x470909FF;
list_add(types, type_error);
struct sway_nagbar_type *type_warning;
type_warning = calloc(1, sizeof(struct sway_nagbar_type));
type_warning->name = strdup("warning");
type_warning->button_background = 0xFFC100FF;
type_warning->background = 0xFFA800FF;
type_warning->text = 0x000000FF;
type_warning->border = 0xAB7100FF;
type_warning->border_bottom = 0xAB7100FF;
list_add(types, type_warning);
}
struct sway_nagbar_type *nagbar_type_get(list_t *types, char *name) {
for (int i = 0; i < types->length; i++) {
struct sway_nagbar_type *type = types->items[i];
if (strcasecmp(type->name, name) == 0) {
return type;
}
}
return NULL;
}
struct sway_nagbar_type *nagbar_type_clone(struct sway_nagbar_type *type) {
struct sway_nagbar_type *clone;
clone = calloc(1, sizeof(struct sway_nagbar_type));
clone->name = strdup(type->name);
clone->button_background = type->button_background;
clone->background = type->background;
clone->text = type->text;
clone->border = type->border;
clone->border_bottom = type->border_bottom;
return clone;
}
void nagbar_type_free(struct sway_nagbar_type *type) {
free(type->name);
free(type);
}
void nagbar_types_free(list_t *types) {
while (types->length) {
struct sway_nagbar_type *type = types->items[0];
nagbar_type_free(type);
list_del(types, 0);
}
list_free(types);
}
int nagbar_parse_type(int argc, char **argv, struct sway_nagbar_type *type) {
enum color_option {
COLOR_BACKGROUND,
COLOR_BORDER,
COLOR_BORDER_BOTTOM,
COLOR_BUTTON,
COLOR_TEXT,
};
static struct option opts[] = {
{"background", required_argument, NULL, COLOR_BACKGROUND},
{"border", required_argument, NULL, COLOR_BORDER},
{"border-bottom", required_argument, NULL, COLOR_BORDER_BOTTOM},
{"button-background", required_argument, NULL, COLOR_BUTTON},
{"text", required_argument, NULL, COLOR_TEXT},
{0, 0, 0, 0}
};
optind = 1;
while (1) {
int c = getopt_long(argc, argv, "", opts, NULL);
if (c == -1) {
break;
}
switch (c) {
case COLOR_BACKGROUND:
type->background = parse_color(optarg);
break;
case COLOR_BORDER:
type->border = parse_color(optarg);
break;
case COLOR_BORDER_BOTTOM:
type->border_bottom = parse_color(optarg);
break;
case COLOR_BUTTON:
type->button_background = parse_color(optarg);
break;
case COLOR_TEXT:
type->text = parse_color(optarg);
break;
default:
break;
}
}
return 0;
}