diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-07-23 20:27:56 -0400 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2018-07-23 20:31:11 -0400 |
commit | f4b882475eee7a81c206c7825616cc4656b2f60b (patch) | |
tree | 38e6ebf81b235424f105dcbcbb194e5e9eac70c0 /swaylock/main.c | |
parent | acd79e1505c06089e4fb9fb6c0c6e1d351ba9176 (diff) | |
parent | 224ade138208e9aa525423cbfbd643aa9d9b63c3 (diff) |
Merge branch 'master' into pid-workspaces
Diffstat (limited to 'swaylock/main.c')
-rw-r--r-- | swaylock/main.c | 568 |
1 files changed, 510 insertions, 58 deletions
diff --git a/swaylock/main.c b/swaylock/main.c index 591df7b4..668a8742 100644 --- a/swaylock/main.c +++ b/swaylock/main.c @@ -21,6 +21,7 @@ #include "pool-buffer.h" #include "cairo.h" #include "log.h" +#include "readline.h" #include "stringop.h" #include "util.h" #include "wlr-input-inhibitor-unstable-v1-client-protocol.h" @@ -34,14 +35,16 @@ void sway_terminate(int exit_code) { static void daemonize() { int fds[2]; if (pipe(fds) != 0) { - wlr_log(L_ERROR, "Failed to pipe"); + wlr_log(WLR_ERROR, "Failed to pipe"); exit(1); } if (fork() == 0) { + setsid(); close(fds[0]); int devnull = open("/dev/null", O_RDWR); dup2(STDOUT_FILENO, devnull); dup2(STDERR_FILENO, devnull); + close(devnull); uint8_t success = 0; if (chdir("/") != 0) { write(fds[1], &success, 1); @@ -56,7 +59,7 @@ static void daemonize() { close(fds[1]); uint8_t success; if (read(fds[0], &success, 1) != 1 || !success) { - wlr_log(L_ERROR, "Failed to daemonize"); + wlr_log(WLR_ERROR, "Failed to daemonize"); exit(1); } close(fds[0]); @@ -83,6 +86,13 @@ static const struct zwlr_layer_surface_v1_listener layer_surface_listener; static cairo_surface_t *select_image(struct swaylock_state *state, struct swaylock_surface *surface); +static bool surface_is_opaque(struct swaylock_surface *surface) { + if (surface->image) { + return cairo_surface_get_content(surface->image) == CAIRO_CONTENT_COLOR; + } + return (surface->state->args.colors.background & 0xff) == 0xff; +} + static void create_layer_surface(struct swaylock_surface *surface) { struct swaylock_state *state = surface->state; @@ -107,6 +117,17 @@ static void create_layer_surface(struct swaylock_surface *surface) { surface->layer_surface, true); zwlr_layer_surface_v1_add_listener(surface->layer_surface, &layer_surface_listener, surface); + + if (surface_is_opaque(surface) && + surface->state->args.mode != BACKGROUND_MODE_CENTER && + surface->state->args.mode != BACKGROUND_MODE_FIT) { + struct wl_region *region = + wl_compositor_create_region(surface->state->compositor); + wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX); + wl_surface_set_opaque_region(surface->surface, region); + wl_region_destroy(region); + } + wl_surface_commit(surface->surface); } @@ -218,7 +239,7 @@ static void handle_xdg_output_logical_position(void *data, static void handle_xdg_output_name(void *data, struct zxdg_output_v1 *output, const char *name) { - wlr_log(L_DEBUG, "output name is %s", name); + wlr_log(WLR_DEBUG, "output name is %s", name); struct swaylock_surface *surface = data; surface->xdg_output = output; surface->output_name = strdup(name); @@ -324,22 +345,25 @@ static void load_image(char *arg, struct swaylock_state *state) { image->path = strdup(arg); } - bool exists = false; - struct swaylock_image *iter_image; - wl_list_for_each(iter_image, &state->images, link) { + struct swaylock_image *iter_image, *temp; + wl_list_for_each_safe(iter_image, temp, &state->images, link) { if (lenient_strcmp(iter_image->output_name, image->output_name) == 0) { - exists = true; + if (image->output_name) { + wlr_log(WLR_DEBUG, + "Replacing image defined for output %s with %s", + image->output_name, image->path); + } else { + wlr_log(WLR_DEBUG, "Replacing default image with %s", + image->path); + } + wl_list_remove(&iter_image->link); + free(iter_image->cairo_surface); + free(iter_image->output_name); + free(iter_image->path); + free(iter_image); break; } } - if (exists) { - if (image->output_name) { - wlr_log(L_ERROR, "Multiple images defined for output %s", - image->output_name); - } else { - wlr_log(L_ERROR, "Multiple default images defined"); - } - } // Bash doesn't replace the ~ with $HOME if the output name is supplied wordexp_t p; @@ -357,71 +381,252 @@ static void load_image(char *arg, struct swaylock_state *state) { } wl_list_insert(&state->images, &image->link); state->args.mode = BACKGROUND_MODE_FILL; - wlr_log(L_DEBUG, "Loaded image %s for output %s", + wlr_log(WLR_DEBUG, "Loaded image %s for output %s", image->path, image->output_name ? image->output_name : "*"); } -static struct swaylock_state state; +static void set_default_colors(struct swaylock_colors *colors) { + colors->background = 0xFFFFFFFF; + colors->bs_highlight = 0xDB3300FF; + colors->key_highlight = 0x33DB00FF; + colors->separator = 0x000000FF; + colors->inside = (struct swaylock_colorset){ + .input = 0x000000C0, + .cleared = 0xE5A445C0, + .verifying = 0x0072FFC0, + .wrong = 0xFA0000C0, + }; + colors->line = (struct swaylock_colorset){ + .input = 0x000000FF, + .cleared = 0x000000FF, + .verifying = 0x000000FF, + .wrong = 0x000000FF, + }; + colors->ring = (struct swaylock_colorset){ + .input = 0x337D00FF, + .cleared = 0xE5A445FF, + .verifying = 0x3300FFFF, + .wrong = 0x7D3300FF, + }; + colors->text = (struct swaylock_colorset){ + .input = 0xE5A445FF, + .cleared = 0x000000FF, + .verifying = 0x000000FF, + .wrong = 0x000000FF, + }; +} + +enum line_mode { + LM_LINE, + LM_INSIDE, + LM_RING, +}; + +static int parse_options(int argc, char **argv, struct swaylock_state *state, + enum line_mode *line_mode, char **config_path) { + enum long_option_codes { + LO_BS_HL_COLOR = 256, + LO_FONT, + LO_IND_RADIUS, + LO_IND_THICKNESS, + LO_INSIDE_COLOR, + LO_INSIDE_CLEAR_COLOR, + LO_INSIDE_VER_COLOR, + LO_INSIDE_WRONG_COLOR, + LO_KEY_HL_COLOR, + LO_LINE_COLOR, + LO_LINE_CLEAR_COLOR, + LO_LINE_VER_COLOR, + LO_LINE_WRONG_COLOR, + LO_RING_COLOR, + LO_RING_CLEAR_COLOR, + LO_RING_VER_COLOR, + LO_RING_WRONG_COLOR, + LO_SEP_COLOR, + LO_TEXT_COLOR, + LO_TEXT_CLEAR_COLOR, + LO_TEXT_VER_COLOR, + LO_TEXT_WRONG_COLOR, + }; -int main(int argc, char **argv) { static struct option long_options[] = { - {"help", no_argument, NULL, 'h'}, + {"config", required_argument, NULL, 'C'}, {"color", required_argument, NULL, 'c'}, + {"ignore-empty-password", no_argument, NULL, 'e'}, + {"daemonize", no_argument, NULL, 'f'}, + {"help", no_argument, NULL, 'h'}, {"image", required_argument, NULL, 'i'}, + {"line-uses-inside", no_argument, NULL, 'n'}, + {"socket", required_argument, NULL, 'p'}, + {"line-uses-ring", no_argument, NULL, 'r'}, {"scaling", required_argument, NULL, 's'}, {"tiling", no_argument, NULL, 't'}, - {"version", no_argument, NULL, 'v'}, - {"socket", required_argument, NULL, 'p'}, {"no-unlock-indicator", no_argument, NULL, 'u'}, - {"daemonize", no_argument, NULL, 'f'}, + {"version", no_argument, NULL, 'v'}, + {"bs-hl-color", required_argument, NULL, LO_BS_HL_COLOR}, + {"font", required_argument, NULL, LO_FONT}, + {"indicator-radius", required_argument, NULL, LO_IND_RADIUS}, + {"indicator-thickness", required_argument, NULL, LO_IND_THICKNESS}, + {"inside-color", required_argument, NULL, LO_INSIDE_COLOR}, + {"inside-clear-color", required_argument, NULL, LO_INSIDE_CLEAR_COLOR}, + {"inside-ver-color", required_argument, NULL, LO_INSIDE_VER_COLOR}, + {"inside-wrong-color", required_argument, NULL, LO_INSIDE_WRONG_COLOR}, + {"key-hl-color", required_argument, NULL, LO_KEY_HL_COLOR}, + {"line-color", required_argument, NULL, LO_LINE_COLOR}, + {"line-clear-color", required_argument, NULL, LO_LINE_CLEAR_COLOR}, + {"line-ver-color", required_argument, NULL, LO_LINE_VER_COLOR}, + {"line-wrong-color", required_argument, NULL, LO_LINE_WRONG_COLOR}, + {"ring-color", required_argument, NULL, LO_RING_COLOR}, + {"ring-clear-color", required_argument, NULL, LO_RING_CLEAR_COLOR}, + {"ring-ver-color", required_argument, NULL, LO_RING_VER_COLOR}, + {"ring-wrong-color", required_argument, NULL, LO_RING_WRONG_COLOR}, + {"separator-color", required_argument, NULL, LO_SEP_COLOR}, + {"text-color", required_argument, NULL, LO_TEXT_COLOR}, + {"text-clear-color", required_argument, NULL, LO_TEXT_CLEAR_COLOR}, + {"text-ver-color", required_argument, NULL, LO_TEXT_VER_COLOR}, + {"text-wrong-color", required_argument, NULL, LO_TEXT_WRONG_COLOR}, {0, 0, 0, 0} }; const char usage[] = "Usage: swaylock [options...]\n" "\n" - " -h, --help Show help message and quit.\n" - " -c, --color <rrggbb[aa]> Turn the screen into the given color instead of white.\n" - " -s, --scaling Scaling mode: stretch, fill, fit, center, tile.\n" - " -t, --tiling Same as --scaling=tile.\n" - " -v, --version Show the version number and quit.\n" - " -i, --image [<output>:]<path> Display the given image.\n" - " -u, --no-unlock-indicator Disable the unlock indicator.\n" - " -f, --daemonize Detach from the controlling terminal.\n"; - - state.args = (struct swaylock_args){ - .mode = BACKGROUND_MODE_SOLID_COLOR, - .color = 0xFFFFFFFF, - .show_indicator = true, - }; - wl_list_init(&state.images); - - wlr_log_init(L_DEBUG, NULL); + " -C, --config <config_file> " + "Path to the config file.\n" + " -c, --color <color> " + "Turn the screen into the given color instead of white.\n" + " -e, --ignore-empty-password " + "When an empty password is provided, do not validate it.\n" + " -f, --daemonize " + "Detach from the controlling terminal after locking.\n" + " -h, --help " + "Show help message and quit.\n" + " -i, --image [<output>:]<path> " + "Display the given image.\n" + " -s, --scaling <mode> " + "Scaling mode: stretch, fill, fit, center, tile.\n" + " -t, --tiling " + "Same as --scaling=tile.\n" + " -u, --no-unlock-indicator " + "Disable the unlock indicator.\n" + " -v, --version " + "Show the version number and quit.\n" + " --bs-hl-color <color> " + "Sets the color of backspace highlight segments.\n" + " --font <font> " + "Sets the font of the text.\n" + " --indicator-radius <radius> " + "Sets the indicator radius.\n" + " --indicator-thickness <thick> " + "Sets the indicator thickness.\n" + " --inside-color <color> " + "Sets the color of the inside of the indicator.\n" + " --inside-clear-color <color> " + "Sets the color of the inside of the indicator when cleared.\n" + " --inside-ver-color <color> " + "Sets the color of the inside of the indicator when verifying.\n" + " --inside-wrong-color <color> " + "Sets the color of the inside of the indicator when invalid.\n" + " --key-hl-color <color> " + "Sets the color of the key press highlight segments.\n" + " --line-color <color> " + "Sets the color of the line between the inside and ring.\n" + " --line-clear-color <color> " + "Sets the color of the line between the inside and ring when " + "cleared.\n" + " --line-ver-color <color> " + "Sets the color of the line between the inside and ring when " + "verifying.\n" + " --line-wrong-color <color> " + "Sets the color of the line between the inside and ring when " + "invalid.\n" + " -n, --line-uses-inside " + "Use the inside color for the line between the inside and ring.\n" + " -r, --line-uses-ring " + "Use the ring color for the line between the inside and ring.\n" + " --ring-color <color> " + "Sets the color of the ring of the indicator.\n" + " --ring-clear-color <color> " + "Sets the color of the ring of the indicator when cleared.\n" + " --ring-ver-color <color> " + "Sets the color of the ring of the indicator when verifying.\n" + " --ring-wrong-color <color> " + "Sets the color of the ring of the indicator when invalid.\n" + " --separator-color <color> " + "Sets the color of the lines that separate highlight segments.\n" + " --text-color <color> " + "Sets the color of the text.\n" + " --text-clear-color <color> " + "Sets the color of the text when cleared.\n" + " --text-ver-color <color> " + "Sets the color of the text when verifying.\n" + " --text-wrong-color <color> " + "Sets the color of the text when invalid.\n" + "\n" + "All <color> options are of the form <rrggbb[aa]>.\n"; int c; + optind = 1; while (1) { - int option_index = 0; - c = getopt_long(argc, argv, "hc:i:s:tvuf", long_options, &option_index); + int opt_idx = 0; + c = getopt_long(argc, argv, "c:efhi:nrs:tuvC:", long_options, &opt_idx); if (c == -1) { break; } switch (c) { - case 'c': { - state.args.color = parse_color(optarg); - state.args.mode = BACKGROUND_MODE_SOLID_COLOR; + case 'C': + if (config_path) { + *config_path = strdup(optarg); + } + break; + case 'c': + if (state) { + state->args.colors.background = parse_color(optarg); + state->args.mode = BACKGROUND_MODE_SOLID_COLOR; + } + break; + case 'e': + if (state) { + state->args.ignore_empty = true; + } + break; + case 'f': + if (state) { + state->args.daemonize = true; + } break; - } case 'i': - load_image(optarg, &state); + if (state) { + load_image(optarg, state); + } + break; + case 'n': + if (line_mode) { + *line_mode = LM_INSIDE; + } + break; + case 'r': + if (line_mode) { + *line_mode = LM_RING; + } break; case 's': - state.args.mode = parse_background_mode(optarg); - if (state.args.mode == BACKGROUND_MODE_INVALID) { - return 1; + if (state) { + state->args.mode = parse_background_mode(optarg); + if (state->args.mode == BACKGROUND_MODE_INVALID) { + return 1; + } } break; case 't': - state.args.mode = BACKGROUND_MODE_TILE; + if (state) { + state->args.mode = BACKGROUND_MODE_TILE; + } + break; + case 'u': + if (state) { + state->args.show_indicator = false; + } break; case 'v': #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE @@ -430,12 +635,117 @@ int main(int argc, char **argv) { #else fprintf(stdout, "version unknown\n"); #endif - return 0; - case 'u': - state.args.show_indicator = false; + return 1; + case LO_BS_HL_COLOR: + if (state) { + state->args.colors.bs_highlight = parse_color(optarg); + } break; - case 'f': - daemonize(); + case LO_FONT: + if (state) { + free(state->args.font); + state->args.font = strdup(optarg); + } + break; + case LO_IND_RADIUS: + if (state) { + state->args.radius = strtol(optarg, NULL, 0); + } + break; + case LO_IND_THICKNESS: + if (state) { + state->args.thickness = strtol(optarg, NULL, 0); + } + break; + case LO_INSIDE_COLOR: + if (state) { + state->args.colors.inside.input = parse_color(optarg); + } + break; + case LO_INSIDE_CLEAR_COLOR: + if (state) { + state->args.colors.inside.cleared = parse_color(optarg); + } + break; + case LO_INSIDE_VER_COLOR: + if (state) { + state->args.colors.inside.verifying = parse_color(optarg); + } + break; + case LO_INSIDE_WRONG_COLOR: + if (state) { + state->args.colors.inside.wrong = parse_color(optarg); + } + break; + case LO_KEY_HL_COLOR: + if (state) { + state->args.colors.key_highlight = parse_color(optarg); + } + break; + case LO_LINE_COLOR: + if (state) { + state->args.colors.line.input = parse_color(optarg); + } + break; + case LO_LINE_CLEAR_COLOR: + if (state) { + state->args.colors.line.cleared = parse_color(optarg); + } + break; + case LO_LINE_VER_COLOR: + if (state) { + state->args.colors.line.verifying = parse_color(optarg); + } + break; + case LO_LINE_WRONG_COLOR: + if (state) { + state->args.colors.line.wrong = parse_color(optarg); + } + break; + case LO_RING_COLOR: + if (state) { + state->args.colors.ring.input = parse_color(optarg); + } + break; + case LO_RING_CLEAR_COLOR: + if (state) { + state->args.colors.ring.cleared = parse_color(optarg); + } + break; + case LO_RING_VER_COLOR: + if (state) { + state->args.colors.ring.verifying = parse_color(optarg); + } + break; + case LO_RING_WRONG_COLOR: + if (state) { + state->args.colors.ring.wrong = parse_color(optarg); + } + break; + case LO_SEP_COLOR: + if (state) { + state->args.colors.separator = parse_color(optarg); + } + break; + case LO_TEXT_COLOR: + if (state) { + state->args.colors.text.input = parse_color(optarg); + } + break; + case LO_TEXT_CLEAR_COLOR: + if (state) { + state->args.colors.text.cleared = parse_color(optarg); + } + break; + case LO_TEXT_VER_COLOR: + if (state) { + state->args.colors.text.verifying = parse_color(optarg); + } + break; + case LO_TEXT_WRONG_COLOR: + if (state) { + state->args.colors.text.wrong = parse_color(optarg); + } break; default: fprintf(stderr, "%s", usage); @@ -443,6 +753,141 @@ int main(int argc, char **argv) { } } + 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/.swaylock/config", + "$XDG_CONFIG_HOME/swaylock/config", + SYSCONFDIR "/swaylock/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 swaylock_state *state, + enum line_mode *line_mode) { + FILE *config = fopen(path, "r"); + if (!config) { + wlr_log(WLR_ERROR, "Failed to read config. Running without it."); + return 0; + } + 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; + } + + wlr_log(WLR_DEBUG, "Config Line #%d: %s", line_number, line); + char flag[strlen(line) + 3]; + sprintf(flag, "--%s", line); + char *argv[] = {"swaylock", flag}; + int result = parse_options(2, argv, state, line_mode, NULL); + if (result != 0) { + free(line); + fclose(config); + return result; + } + free(line); + } + fclose(config); + return 0; +} + +static struct swaylock_state state; + +int main(int argc, char **argv) { + enum line_mode line_mode = LM_LINE; + state.args = (struct swaylock_args){ + .mode = BACKGROUND_MODE_SOLID_COLOR, + .font = strdup("sans-serif"), + .radius = 50, + .thickness = 10, + .ignore_empty = false, + .show_indicator = true, + }; + wl_list_init(&state.images); + set_default_colors(&state.args.colors); + + wlr_log_init(WLR_DEBUG, NULL); + + char *config_path = NULL; + int result = parse_options(argc, argv, NULL, NULL, &config_path); + if (result != 0) { + free(config_path); + return result; + } + if (!config_path) { + config_path = get_config_path(); + } + + if (config_path) { + wlr_log(WLR_DEBUG, "Found config at %s", config_path); + int config_status = load_config(config_path, &state, &line_mode); + free(config_path); + if (config_status != 0) { + return config_status; + } + } + + if (argc > 1) { + wlr_log(WLR_DEBUG, "Parsing CLI Args"); + int result = parse_options(argc, argv, &state, &line_mode, NULL); + if (result != 0) { + return result; + } + } + + if (line_mode == LM_INSIDE) { + state.args.colors.line = state.args.colors.inside; + } else if (line_mode == LM_RING) { + state.args.colors.line = state.args.colors.ring; + } + #ifdef __linux__ // Most non-linux platforms require root to mlock() if (mlock(state.password.buffer, sizeof(state.password.buffer)) != 0) { @@ -460,13 +905,13 @@ int main(int argc, char **argv) { wl_display_roundtrip(state.display); assert(state.compositor && state.layer_shell && state.shm); if (!state.input_inhibit_manager) { - wlr_log(L_ERROR, "Compositor does not support the input inhibitor " + wlr_log(WLR_ERROR, "Compositor does not support the input inhibitor " "protocol, refusing to run insecurely"); return 1; } if (wl_list_empty(&state.surfaces)) { - wlr_log(L_DEBUG, "Exiting - no outputs to show on."); + wlr_log(WLR_DEBUG, "Exiting - no outputs to show on."); return 0; } @@ -482,7 +927,7 @@ int main(int argc, char **argv) { } wl_display_roundtrip(state.display); } else { - wlr_log(L_INFO, "Compositor does not support zxdg output manager, " + wlr_log(WLR_INFO, "Compositor does not support zxdg output manager, " "images assigned to named outputs will not work"); } @@ -491,9 +936,16 @@ int main(int argc, char **argv) { create_layer_surface(surface); } + if (state.args.daemonize) { + wl_display_roundtrip(state.display); + daemonize(); + } + state.run_display = true; while (wl_display_dispatch(state.display) != -1 && state.run_display) { // This space intentionally left blank } + + free(state.args.font); return 0; } |