summaryrefslogtreecommitdiffstats
path: root/swaylock
diff options
context:
space:
mode:
Diffstat (limited to 'swaylock')
-rw-r--r--swaylock/main.c568
-rw-r--r--swaylock/password.c25
-rw-r--r--swaylock/render.c77
-rw-r--r--swaylock/seat.c4
-rw-r--r--swaylock/swaylock.1.scd92
5 files changed, 632 insertions, 134 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 @@
21#include "pool-buffer.h" 21#include "pool-buffer.h"
22#include "cairo.h" 22#include "cairo.h"
23#include "log.h" 23#include "log.h"
24#include "readline.h"
24#include "stringop.h" 25#include "stringop.h"
25#include "util.h" 26#include "util.h"
26#include "wlr-input-inhibitor-unstable-v1-client-protocol.h" 27#include "wlr-input-inhibitor-unstable-v1-client-protocol.h"
@@ -34,14 +35,16 @@ void sway_terminate(int exit_code) {
34static void daemonize() { 35static void daemonize() {
35 int fds[2]; 36 int fds[2];
36 if (pipe(fds) != 0) { 37 if (pipe(fds) != 0) {
37 wlr_log(L_ERROR, "Failed to pipe"); 38 wlr_log(WLR_ERROR, "Failed to pipe");
38 exit(1); 39 exit(1);
39 } 40 }
40 if (fork() == 0) { 41 if (fork() == 0) {
42 setsid();
41 close(fds[0]); 43 close(fds[0]);
42 int devnull = open("/dev/null", O_RDWR); 44 int devnull = open("/dev/null", O_RDWR);
43 dup2(STDOUT_FILENO, devnull); 45 dup2(STDOUT_FILENO, devnull);
44 dup2(STDERR_FILENO, devnull); 46 dup2(STDERR_FILENO, devnull);
47 close(devnull);
45 uint8_t success = 0; 48 uint8_t success = 0;
46 if (chdir("/") != 0) { 49 if (chdir("/") != 0) {
47 write(fds[1], &success, 1); 50 write(fds[1], &success, 1);
@@ -56,7 +59,7 @@ static void daemonize() {
56 close(fds[1]); 59 close(fds[1]);
57 uint8_t success; 60 uint8_t success;
58 if (read(fds[0], &success, 1) != 1 || !success) { 61 if (read(fds[0], &success, 1) != 1 || !success) {
59 wlr_log(L_ERROR, "Failed to daemonize"); 62 wlr_log(WLR_ERROR, "Failed to daemonize");
60 exit(1); 63 exit(1);
61 } 64 }
62 close(fds[0]); 65 close(fds[0]);
@@ -83,6 +86,13 @@ static const struct zwlr_layer_surface_v1_listener layer_surface_listener;
83static cairo_surface_t *select_image(struct swaylock_state *state, 86static cairo_surface_t *select_image(struct swaylock_state *state,
84 struct swaylock_surface *surface); 87 struct swaylock_surface *surface);
85 88
89static bool surface_is_opaque(struct swaylock_surface *surface) {
90 if (surface->image) {
91 return cairo_surface_get_content(surface->image) == CAIRO_CONTENT_COLOR;
92 }
93 return (surface->state->args.colors.background & 0xff) == 0xff;
94}
95
86static void create_layer_surface(struct swaylock_surface *surface) { 96static void create_layer_surface(struct swaylock_surface *surface) {
87 struct swaylock_state *state = surface->state; 97 struct swaylock_state *state = surface->state;
88 98
@@ -107,6 +117,17 @@ static void create_layer_surface(struct swaylock_surface *surface) {
107 surface->layer_surface, true); 117 surface->layer_surface, true);
108 zwlr_layer_surface_v1_add_listener(surface->layer_surface, 118 zwlr_layer_surface_v1_add_listener(surface->layer_surface,
109 &layer_surface_listener, surface); 119 &layer_surface_listener, surface);
120
121 if (surface_is_opaque(surface) &&
122 surface->state->args.mode != BACKGROUND_MODE_CENTER &&
123 surface->state->args.mode != BACKGROUND_MODE_FIT) {
124 struct wl_region *region =
125 wl_compositor_create_region(surface->state->compositor);
126 wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX);
127 wl_surface_set_opaque_region(surface->surface, region);
128 wl_region_destroy(region);
129 }
130
110 wl_surface_commit(surface->surface); 131 wl_surface_commit(surface->surface);
111} 132}
112 133
@@ -218,7 +239,7 @@ static void handle_xdg_output_logical_position(void *data,
218 239
219static void handle_xdg_output_name(void *data, struct zxdg_output_v1 *output, 240static void handle_xdg_output_name(void *data, struct zxdg_output_v1 *output,
220 const char *name) { 241 const char *name) {
221 wlr_log(L_DEBUG, "output name is %s", name); 242 wlr_log(WLR_DEBUG, "output name is %s", name);
222 struct swaylock_surface *surface = data; 243 struct swaylock_surface *surface = data;
223 surface->xdg_output = output; 244 surface->xdg_output = output;
224 surface->output_name = strdup(name); 245 surface->output_name = strdup(name);
@@ -324,22 +345,25 @@ static void load_image(char *arg, struct swaylock_state *state) {
324 image->path = strdup(arg); 345 image->path = strdup(arg);
325 } 346 }
326 347
327 bool exists = false; 348 struct swaylock_image *iter_image, *temp;
328 struct swaylock_image *iter_image; 349 wl_list_for_each_safe(iter_image, temp, &state->images, link) {
329 wl_list_for_each(iter_image, &state->images, link) {
330 if (lenient_strcmp(iter_image->output_name, image->output_name) == 0) { 350 if (lenient_strcmp(iter_image->output_name, image->output_name) == 0) {
331 exists = true; 351 if (image->output_name) {
352 wlr_log(WLR_DEBUG,
353 "Replacing image defined for output %s with %s",
354 image->output_name, image->path);
355 } else {
356 wlr_log(WLR_DEBUG, "Replacing default image with %s",
357 image->path);
358 }
359 wl_list_remove(&iter_image->link);
360 free(iter_image->cairo_surface);
361 free(iter_image->output_name);
362 free(iter_image->path);
363 free(iter_image);
332 break; 364 break;
333 } 365 }
334 } 366 }
335 if (exists) {
336 if (image->output_name) {
337 wlr_log(L_ERROR, "Multiple images defined for output %s",
338 image->output_name);
339 } else {
340 wlr_log(L_ERROR, "Multiple default images defined");
341 }
342 }
343 367
344 // Bash doesn't replace the ~ with $HOME if the output name is supplied 368 // Bash doesn't replace the ~ with $HOME if the output name is supplied
345 wordexp_t p; 369 wordexp_t p;
@@ -357,71 +381,252 @@ static void load_image(char *arg, struct swaylock_state *state) {
357 } 381 }
358 wl_list_insert(&state->images, &image->link); 382 wl_list_insert(&state->images, &image->link);
359 state->args.mode = BACKGROUND_MODE_FILL; 383 state->args.mode = BACKGROUND_MODE_FILL;
360 wlr_log(L_DEBUG, "Loaded image %s for output %s", 384 wlr_log(WLR_DEBUG, "Loaded image %s for output %s",
361 image->path, image->output_name ? image->output_name : "*"); 385 image->path, image->output_name ? image->output_name : "*");
362} 386}
363 387
364static struct swaylock_state state; 388static void set_default_colors(struct swaylock_colors *colors) {
389 colors->background = 0xFFFFFFFF;
390 colors->bs_highlight = 0xDB3300FF;
391 colors->key_highlight = 0x33DB00FF;
392 colors->separator = 0x000000FF;
393 colors->inside = (struct swaylock_colorset){
394 .input = 0x000000C0,
395 .cleared = 0xE5A445C0,
396 .verifying = 0x0072FFC0,
397 .wrong = 0xFA0000C0,
398 };
399 colors->line = (struct swaylock_colorset){
400 .input = 0x000000FF,
401 .cleared = 0x000000FF,
402 .verifying = 0x000000FF,
403 .wrong = 0x000000FF,
404 };
405 colors->ring = (struct swaylock_colorset){
406 .input = 0x337D00FF,
407 .cleared = 0xE5A445FF,
408 .verifying = 0x3300FFFF,
409 .wrong = 0x7D3300FF,
410 };
411 colors->text = (struct swaylock_colorset){
412 .input = 0xE5A445FF,
413 .cleared = 0x000000FF,
414 .verifying = 0x000000FF,
415 .wrong = 0x000000FF,
416 };
417}
418
419enum line_mode {
420 LM_LINE,
421 LM_INSIDE,
422 LM_RING,
423};
424
425static int parse_options(int argc, char **argv, struct swaylock_state *state,
426 enum line_mode *line_mode, char **config_path) {
427 enum long_option_codes {
428 LO_BS_HL_COLOR = 256,
429 LO_FONT,
430 LO_IND_RADIUS,
431 LO_IND_THICKNESS,
432 LO_INSIDE_COLOR,
433 LO_INSIDE_CLEAR_COLOR,
434 LO_INSIDE_VER_COLOR,
435 LO_INSIDE_WRONG_COLOR,
436 LO_KEY_HL_COLOR,
437 LO_LINE_COLOR,
438 LO_LINE_CLEAR_COLOR,
439 LO_LINE_VER_COLOR,
440 LO_LINE_WRONG_COLOR,
441 LO_RING_COLOR,
442 LO_RING_CLEAR_COLOR,
443 LO_RING_VER_COLOR,
444 LO_RING_WRONG_COLOR,
445 LO_SEP_COLOR,
446 LO_TEXT_COLOR,
447 LO_TEXT_CLEAR_COLOR,
448 LO_TEXT_VER_COLOR,
449 LO_TEXT_WRONG_COLOR,
450 };
365 451
366int main(int argc, char **argv) {
367 static struct option long_options[] = { 452 static struct option long_options[] = {
368 {"help", no_argument, NULL, 'h'}, 453 {"config", required_argument, NULL, 'C'},
369 {"color", required_argument, NULL, 'c'}, 454 {"color", required_argument, NULL, 'c'},
455 {"ignore-empty-password", no_argument, NULL, 'e'},
456 {"daemonize", no_argument, NULL, 'f'},
457 {"help", no_argument, NULL, 'h'},
370 {"image", required_argument, NULL, 'i'}, 458 {"image", required_argument, NULL, 'i'},
459 {"line-uses-inside", no_argument, NULL, 'n'},
460 {"socket", required_argument, NULL, 'p'},
461 {"line-uses-ring", no_argument, NULL, 'r'},
371 {"scaling", required_argument, NULL, 's'}, 462 {"scaling", required_argument, NULL, 's'},
372 {"tiling", no_argument, NULL, 't'}, 463 {"tiling", no_argument, NULL, 't'},
373 {"version", no_argument, NULL, 'v'},
374 {"socket", required_argument, NULL, 'p'},
375 {"no-unlock-indicator", no_argument, NULL, 'u'}, 464 {"no-unlock-indicator", no_argument, NULL, 'u'},
376 {"daemonize", no_argument, NULL, 'f'}, 465 {"version", no_argument, NULL, 'v'},
466 {"bs-hl-color", required_argument, NULL, LO_BS_HL_COLOR},
467 {"font", required_argument, NULL, LO_FONT},
468 {"indicator-radius", required_argument, NULL, LO_IND_RADIUS},
469 {"indicator-thickness", required_argument, NULL, LO_IND_THICKNESS},
470 {"inside-color", required_argument, NULL, LO_INSIDE_COLOR},
471 {"inside-clear-color", required_argument, NULL, LO_INSIDE_CLEAR_COLOR},
472 {"inside-ver-color", required_argument, NULL, LO_INSIDE_VER_COLOR},
473 {"inside-wrong-color", required_argument, NULL, LO_INSIDE_WRONG_COLOR},
474 {"key-hl-color", required_argument, NULL, LO_KEY_HL_COLOR},
475 {"line-color", required_argument, NULL, LO_LINE_COLOR},
476 {"line-clear-color", required_argument, NULL, LO_LINE_CLEAR_COLOR},
477 {"line-ver-color", required_argument, NULL, LO_LINE_VER_COLOR},
478 {"line-wrong-color", required_argument, NULL, LO_LINE_WRONG_COLOR},
479 {"ring-color", required_argument, NULL, LO_RING_COLOR},
480 {"ring-clear-color", required_argument, NULL, LO_RING_CLEAR_COLOR},
481 {"ring-ver-color", required_argument, NULL, LO_RING_VER_COLOR},
482 {"ring-wrong-color", required_argument, NULL, LO_RING_WRONG_COLOR},
483 {"separator-color", required_argument, NULL, LO_SEP_COLOR},
484 {"text-color", required_argument, NULL, LO_TEXT_COLOR},
485 {"text-clear-color", required_argument, NULL, LO_TEXT_CLEAR_COLOR},
486 {"text-ver-color", required_argument, NULL, LO_TEXT_VER_COLOR},
487 {"text-wrong-color", required_argument, NULL, LO_TEXT_WRONG_COLOR},
377 {0, 0, 0, 0} 488 {0, 0, 0, 0}
378 }; 489 };
379 490
380 const char usage[] = 491 const char usage[] =
381 "Usage: swaylock [options...]\n" 492 "Usage: swaylock [options...]\n"
382 "\n" 493 "\n"
383 " -h, --help Show help message and quit.\n" 494 " -C, --config <config_file> "
384 " -c, --color <rrggbb[aa]> Turn the screen into the given color instead of white.\n" 495 "Path to the config file.\n"
385 " -s, --scaling Scaling mode: stretch, fill, fit, center, tile.\n" 496 " -c, --color <color> "
386 " -t, --tiling Same as --scaling=tile.\n" 497 "Turn the screen into the given color instead of white.\n"
387 " -v, --version Show the version number and quit.\n" 498 " -e, --ignore-empty-password "
388 " -i, --image [<output>:]<path> Display the given image.\n" 499 "When an empty password is provided, do not validate it.\n"
389 " -u, --no-unlock-indicator Disable the unlock indicator.\n" 500 " -f, --daemonize "
390 " -f, --daemonize Detach from the controlling terminal.\n"; 501 "Detach from the controlling terminal after locking.\n"
391 502 " -h, --help "
392 state.args = (struct swaylock_args){ 503 "Show help message and quit.\n"
393 .mode = BACKGROUND_MODE_SOLID_COLOR, 504 " -i, --image [<output>:]<path> "
394 .color = 0xFFFFFFFF, 505 "Display the given image.\n"
395 .show_indicator = true, 506 " -s, --scaling <mode> "
396 }; 507 "Scaling mode: stretch, fill, fit, center, tile.\n"
397 wl_list_init(&state.images); 508 " -t, --tiling "
398 509 "Same as --scaling=tile.\n"
399 wlr_log_init(L_DEBUG, NULL); 510 " -u, --no-unlock-indicator "
511 "Disable the unlock indicator.\n"
512 " -v, --version "
513 "Show the version number and quit.\n"
514 " --bs-hl-color <color> "
515 "Sets the color of backspace highlight segments.\n"
516 " --font <font> "
517 "Sets the font of the text.\n"
518 " --indicator-radius <radius> "
519 "Sets the indicator radius.\n"
520 " --indicator-thickness <thick> "
521 "Sets the indicator thickness.\n"
522 " --inside-color <color> "
523 "Sets the color of the inside of the indicator.\n"
524 " --inside-clear-color <color> "
525 "Sets the color of the inside of the indicator when cleared.\n"
526 " --inside-ver-color <color> "
527 "Sets the color of the inside of the indicator when verifying.\n"
528 " --inside-wrong-color <color> "
529 "Sets the color of the inside of the indicator when invalid.\n"
530 " --key-hl-color <color> "
531 "Sets the color of the key press highlight segments.\n"
532 " --line-color <color> "
533 "Sets the color of the line between the inside and ring.\n"
534 " --line-clear-color <color> "
535 "Sets the color of the line between the inside and ring when "
536 "cleared.\n"
537 " --line-ver-color <color> "
538 "Sets the color of the line between the inside and ring when "
539 "verifying.\n"
540 " --line-wrong-color <color> "
541 "Sets the color of the line between the inside and ring when "
542 "invalid.\n"
543 " -n, --line-uses-inside "
544 "Use the inside color for the line between the inside and ring.\n"
545 " -r, --line-uses-ring "
546 "Use the ring color for the line between the inside and ring.\n"
547 " --ring-color <color> "
548 "Sets the color of the ring of the indicator.\n"
549 " --ring-clear-color <color> "
550 "Sets the color of the ring of the indicator when cleared.\n"
551 " --ring-ver-color <color> "
552 "Sets the color of the ring of the indicator when verifying.\n"
553 " --ring-wrong-color <color> "
554 "Sets the color of the ring of the indicator when invalid.\n"
555 " --separator-color <color> "
556 "Sets the color of the lines that separate highlight segments.\n"
557 " --text-color <color> "
558 "Sets the color of the text.\n"
559 " --text-clear-color <color> "
560 "Sets the color of the text when cleared.\n"
561 " --text-ver-color <color> "
562 "Sets the color of the text when verifying.\n"
563 " --text-wrong-color <color> "
564 "Sets the color of the text when invalid.\n"
565 "\n"
566 "All <color> options are of the form <rrggbb[aa]>.\n";
400 567
401 int c; 568 int c;
569 optind = 1;
402 while (1) { 570 while (1) {
403 int option_index = 0; 571 int opt_idx = 0;
404 c = getopt_long(argc, argv, "hc:i:s:tvuf", long_options, &option_index); 572 c = getopt_long(argc, argv, "c:efhi:nrs:tuvC:", long_options, &opt_idx);
405 if (c == -1) { 573 if (c == -1) {
406 break; 574 break;
407 } 575 }
408 switch (c) { 576 switch (c) {
409 case 'c': { 577 case 'C':
410 state.args.color = parse_color(optarg); 578 if (config_path) {
411 state.args.mode = BACKGROUND_MODE_SOLID_COLOR; 579 *config_path = strdup(optarg);
580 }
581 break;
582 case 'c':
583 if (state) {
584 state->args.colors.background = parse_color(optarg);
585 state->args.mode = BACKGROUND_MODE_SOLID_COLOR;
586 }
587 break;
588 case 'e':
589 if (state) {
590 state->args.ignore_empty = true;
591 }
592 break;
593 case 'f':
594 if (state) {
595 state->args.daemonize = true;
596 }
412 break; 597 break;
413 }
414 case 'i': 598 case 'i':
415 load_image(optarg, &state); 599 if (state) {
600 load_image(optarg, state);
601 }
602 break;
603 case 'n':
604 if (line_mode) {
605 *line_mode = LM_INSIDE;
606 }
607 break;
608 case 'r':
609 if (line_mode) {
610 *line_mode = LM_RING;
611 }
416 break; 612 break;
417 case 's': 613 case 's':
418 state.args.mode = parse_background_mode(optarg); 614 if (state) {
419 if (state.args.mode == BACKGROUND_MODE_INVALID) { 615 state->args.mode = parse_background_mode(optarg);
420 return 1; 616 if (state->args.mode == BACKGROUND_MODE_INVALID) {
617 return 1;
618 }
421 } 619 }
422 break; 620 break;
423 case 't': 621 case 't':
424 state.args.mode = BACKGROUND_MODE_TILE; 622 if (state) {
623 state->args.mode = BACKGROUND_MODE_TILE;
624 }
625 break;
626 case 'u':
627 if (state) {
628 state->args.show_indicator = false;
629 }
425 break; 630 break;
426 case 'v': 631 case 'v':
427#if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE 632#if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE
@@ -430,12 +635,117 @@ int main(int argc, char **argv) {
430#else 635#else
431 fprintf(stdout, "version unknown\n"); 636 fprintf(stdout, "version unknown\n");
432#endif 637#endif
433 return 0; 638 return 1;
434 case 'u': 639 case LO_BS_HL_COLOR:
435 state.args.show_indicator = false; 640 if (state) {
641 state->args.colors.bs_highlight = parse_color(optarg);
642 }
436 break; 643 break;
437 case 'f': 644 case LO_FONT:
438 daemonize(); 645 if (state) {
646 free(state->args.font);
647 state->args.font = strdup(optarg);
648 }
649 break;
650 case LO_IND_RADIUS:
651 if (state) {
652 state->args.radius = strtol(optarg, NULL, 0);
653 }
654 break;
655 case LO_IND_THICKNESS:
656 if (state) {
657 state->args.thickness = strtol(optarg, NULL, 0);
658 }
659 break;
660 case LO_INSIDE_COLOR:
661 if (state) {
662 state->args.colors.inside.input = parse_color(optarg);
663 }
664 break;
665 case LO_INSIDE_CLEAR_COLOR:
666 if (state) {
667 state->args.colors.inside.cleared = parse_color(optarg);
668 }
669 break;
670 case LO_INSIDE_VER_COLOR:
671 if (state) {
672 state->args.colors.inside.verifying = parse_color(optarg);
673 }
674 break;
675 case LO_INSIDE_WRONG_COLOR:
676 if (state) {
677 state->args.colors.inside.wrong = parse_color(optarg);
678 }
679 break;
680 case LO_KEY_HL_COLOR:
681 if (state) {
682 state->args.colors.key_highlight = parse_color(optarg);
683 }
684 break;
685 case LO_LINE_COLOR:
686 if (state) {
687 state->args.colors.line.input = parse_color(optarg);
688 }
689 break;
690 case LO_LINE_CLEAR_COLOR:
691 if (state) {
692 state->args.colors.line.cleared = parse_color(optarg);
693 }
694 break;
695 case LO_LINE_VER_COLOR:
696 if (state) {
697 state->args.colors.line.verifying = parse_color(optarg);
698 }
699 break;
700 case LO_LINE_WRONG_COLOR:
701 if (state) {
702 state->args.colors.line.wrong = parse_color(optarg);
703 }
704 break;
705 case LO_RING_COLOR:
706 if (state) {
707 state->args.colors.ring.input = parse_color(optarg);
708 }
709 break;
710 case LO_RING_CLEAR_COLOR:
711 if (state) {
712 state->args.colors.ring.cleared = parse_color(optarg);
713 }
714 break;
715 case LO_RING_VER_COLOR:
716 if (state) {
717 state->args.colors.ring.verifying = parse_color(optarg);
718 }
719 break;
720 case LO_RING_WRONG_COLOR:
721 if (state) {
722 state->args.colors.ring.wrong = parse_color(optarg);
723 }
724 break;
725 case LO_SEP_COLOR:
726 if (state) {
727 state->args.colors.separator = parse_color(optarg);
728 }
729 break;
730 case LO_TEXT_COLOR:
731 if (state) {
732 state->args.colors.text.input = parse_color(optarg);
733 }
734 break;
735 case LO_TEXT_CLEAR_COLOR:
736 if (state) {
737 state->args.colors.text.cleared = parse_color(optarg);
738 }
739 break;
740 case LO_TEXT_VER_COLOR:
741 if (state) {
742 state->args.colors.text.verifying = parse_color(optarg);
743 }
744 break;
745 case LO_TEXT_WRONG_COLOR:
746 if (state) {
747 state->args.colors.text.wrong = parse_color(optarg);
748 }
439 break; 749 break;
440 default: 750 default:
441 fprintf(stderr, "%s", usage); 751 fprintf(stderr, "%s", usage);
@@ -443,6 +753,141 @@ int main(int argc, char **argv) {
443 } 753 }
444 } 754 }
445 755
756 return 0;
757}
758
759static bool file_exists(const char *path) {
760 return path && access(path, R_OK) != -1;
761}
762
763static char *get_config_path(void) {
764 static const char *config_paths[] = {
765 "$HOME/.swaylock/config",
766 "$XDG_CONFIG_HOME/swaylock/config",
767 SYSCONFDIR "/swaylock/config",
768 };
769
770 if (!getenv("XDG_CONFIG_HOME")) {
771 char *home = getenv("HOME");
772 char *config_home = malloc(strlen(home) + strlen("/.config") + 1);
773 if (!config_home) {
774 wlr_log(WLR_ERROR, "Unable to allocate $HOME/.config");
775 } else {
776 strcpy(config_home, home);
777 strcat(config_home, "/.config");
778 setenv("XDG_CONFIG_HOME", config_home, 1);
779 wlr_log(WLR_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home);
780 free(config_home);
781 }
782 }
783
784 wordexp_t p;
785 char *path;
786 for (size_t i = 0; i < sizeof(config_paths) / sizeof(char *); ++i) {
787 if (wordexp(config_paths[i], &p, 0) == 0) {
788 path = strdup(p.we_wordv[0]);
789 wordfree(&p);
790 if (file_exists(path)) {
791 return path;
792 }
793 free(path);
794 }
795 }
796
797 return NULL;
798}
799
800static int load_config(char *path, struct swaylock_state *state,
801 enum line_mode *line_mode) {
802 FILE *config = fopen(path, "r");
803 if (!config) {
804 wlr_log(WLR_ERROR, "Failed to read config. Running without it.");
805 return 0;
806 }
807 char *line;
808 int line_number = 0;
809 while (!feof(config)) {
810 line = read_line(config);
811 if (!line) {
812 continue;
813 }
814
815 line_number++;
816 if (line[0] == '#') {
817 free(line);
818 continue;
819 }
820 if (strlen(line) == 0) {
821 free(line);
822 continue;
823 }
824
825 wlr_log(WLR_DEBUG, "Config Line #%d: %s", line_number, line);
826 char flag[strlen(line) + 3];
827 sprintf(flag, "--%s", line);
828 char *argv[] = {"swaylock", flag};
829 int result = parse_options(2, argv, state, line_mode, NULL);
830 if (result != 0) {
831 free(line);
832 fclose(config);
833 return result;
834 }
835 free(line);
836 }
837 fclose(config);
838 return 0;
839}
840
841static struct swaylock_state state;
842
843int main(int argc, char **argv) {
844 enum line_mode line_mode = LM_LINE;
845 state.args = (struct swaylock_args){
846 .mode = BACKGROUND_MODE_SOLID_COLOR,
847 .font = strdup("sans-serif"),
848 .radius = 50,
849 .thickness = 10,
850 .ignore_empty = false,
851 .show_indicator = true,
852 };
853 wl_list_init(&state.images);
854 set_default_colors(&state.args.colors);
855
856 wlr_log_init(WLR_DEBUG, NULL);
857
858 char *config_path = NULL;
859 int result = parse_options(argc, argv, NULL, NULL, &config_path);
860 if (result != 0) {
861 free(config_path);
862 return result;
863 }
864 if (!config_path) {
865 config_path = get_config_path();
866 }
867
868 if (config_path) {
869 wlr_log(WLR_DEBUG, "Found config at %s", config_path);
870 int config_status = load_config(config_path, &state, &line_mode);
871 free(config_path);
872 if (config_status != 0) {
873 return config_status;
874 }
875 }
876
877 if (argc > 1) {
878 wlr_log(WLR_DEBUG, "Parsing CLI Args");
879 int result = parse_options(argc, argv, &state, &line_mode, NULL);
880 if (result != 0) {
881 return result;
882 }
883 }
884
885 if (line_mode == LM_INSIDE) {
886 state.args.colors.line = state.args.colors.inside;
887 } else if (line_mode == LM_RING) {
888 state.args.colors.line = state.args.colors.ring;
889 }
890
446#ifdef __linux__ 891#ifdef __linux__
447 // Most non-linux platforms require root to mlock() 892 // Most non-linux platforms require root to mlock()
448 if (mlock(state.password.buffer, sizeof(state.password.buffer)) != 0) { 893 if (mlock(state.password.buffer, sizeof(state.password.buffer)) != 0) {
@@ -460,13 +905,13 @@ int main(int argc, char **argv) {
460 wl_display_roundtrip(state.display); 905 wl_display_roundtrip(state.display);
461 assert(state.compositor && state.layer_shell && state.shm); 906 assert(state.compositor && state.layer_shell && state.shm);
462 if (!state.input_inhibit_manager) { 907 if (!state.input_inhibit_manager) {
463 wlr_log(L_ERROR, "Compositor does not support the input inhibitor " 908 wlr_log(WLR_ERROR, "Compositor does not support the input inhibitor "
464 "protocol, refusing to run insecurely"); 909 "protocol, refusing to run insecurely");
465 return 1; 910 return 1;
466 } 911 }
467 912
468 if (wl_list_empty(&state.surfaces)) { 913 if (wl_list_empty(&state.surfaces)) {
469 wlr_log(L_DEBUG, "Exiting - no outputs to show on."); 914 wlr_log(WLR_DEBUG, "Exiting - no outputs to show on.");
470 return 0; 915 return 0;
471 } 916 }
472 917
@@ -482,7 +927,7 @@ int main(int argc, char **argv) {
482 } 927 }
483 wl_display_roundtrip(state.display); 928 wl_display_roundtrip(state.display);
484 } else { 929 } else {
485 wlr_log(L_INFO, "Compositor does not support zxdg output manager, " 930 wlr_log(WLR_INFO, "Compositor does not support zxdg output manager, "
486 "images assigned to named outputs will not work"); 931 "images assigned to named outputs will not work");
487 } 932 }
488 933
@@ -491,9 +936,16 @@ int main(int argc, char **argv) {
491 create_layer_surface(surface); 936 create_layer_surface(surface);
492 } 937 }
493 938
939 if (state.args.daemonize) {
940 wl_display_roundtrip(state.display);
941 daemonize();
942 }
943
494 state.run_display = true; 944 state.run_display = true;
495 while (wl_display_dispatch(state.display) != -1 && state.run_display) { 945 while (wl_display_dispatch(state.display) != -1 && state.run_display) {
496 // This space intentionally left blank 946 // This space intentionally left blank
497 } 947 }
948
949 free(state.args.font);
498 return 0; 950 return 0;
499} 951}
diff --git a/swaylock/password.c b/swaylock/password.c
index bb32286e..7c686b34 100644
--- a/swaylock/password.c
+++ b/swaylock/password.c
@@ -53,15 +53,15 @@ static bool attempt_password(struct swaylock_password *pw) {
53 // TODO: only call pam_start once. keep the same handle the whole time 53 // TODO: only call pam_start once. keep the same handle the whole time
54 if ((pam_err = pam_start("swaylock", username, 54 if ((pam_err = pam_start("swaylock", username,
55 &local_conversation, &local_auth_handle)) != PAM_SUCCESS) { 55 &local_conversation, &local_auth_handle)) != PAM_SUCCESS) {
56 wlr_log(L_ERROR, "PAM returned error %d", pam_err); 56 wlr_log(WLR_ERROR, "PAM returned error %d", pam_err);
57 } 57 }
58 if ((pam_err = pam_authenticate(local_auth_handle, 0)) != PAM_SUCCESS) { 58 if ((pam_err = pam_authenticate(local_auth_handle, 0)) != PAM_SUCCESS) {
59 wlr_log(L_ERROR, "pam_authenticate failed"); 59 wlr_log(WLR_ERROR, "pam_authenticate failed");
60 goto fail; 60 goto fail;
61 } 61 }
62 // TODO: only call pam_end once we succeed at authing. refresh tokens beforehand 62 // TODO: only call pam_end once we succeed at authing. refresh tokens beforehand
63 if ((pam_err = pam_end(local_auth_handle, pam_err)) != PAM_SUCCESS) { 63 if ((pam_err = pam_end(local_auth_handle, pam_err)) != PAM_SUCCESS) {
64 wlr_log(L_ERROR, "pam_end failed"); 64 wlr_log(WLR_ERROR, "pam_end failed");
65 goto fail; 65 goto fail;
66 } 66 }
67 clear_password_buffer(pw); 67 clear_password_buffer(pw);
@@ -95,9 +95,26 @@ void swaylock_handle_key(struct swaylock_state *state,
95 switch (keysym) { 95 switch (keysym) {
96 case XKB_KEY_KP_Enter: /* fallthrough */ 96 case XKB_KEY_KP_Enter: /* fallthrough */
97 case XKB_KEY_Return: 97 case XKB_KEY_Return:
98 if (state->args.ignore_empty && state->password.len == 0) {
99 break;
100 }
101
98 state->auth_state = AUTH_STATE_VALIDATING; 102 state->auth_state = AUTH_STATE_VALIDATING;
99 damage_state(state); 103 damage_state(state);
100 wl_display_roundtrip(state->display); 104 while (wl_display_dispatch(state->display) != -1 && state->run_display) {
105 bool ok = 1;
106 struct swaylock_surface *surface;
107 wl_list_for_each(surface, &state->surfaces, link) {
108 if (surface->dirty) {
109 ok = 0;
110 }
111 }
112 if (ok) {
113 break;
114 }
115 }
116 wl_display_flush(state->display);
117
101 if (attempt_password(&state->password)) { 118 if (attempt_password(&state->password)) {
102 state->run_display = false; 119 state->run_display = false;
103 break; 120 break;
diff --git a/swaylock/render.c b/swaylock/render.c
index 2032ddcf..66c55965 100644
--- a/swaylock/render.c
+++ b/swaylock/render.c
@@ -7,11 +7,22 @@
7#include "swaylock/swaylock.h" 7#include "swaylock/swaylock.h"
8 8
9#define M_PI 3.14159265358979323846 9#define M_PI 3.14159265358979323846
10const int ARC_RADIUS = 50;
11const int ARC_THICKNESS = 10;
12const float TYPE_INDICATOR_RANGE = M_PI / 3.0f; 10const float TYPE_INDICATOR_RANGE = M_PI / 3.0f;
13const float TYPE_INDICATOR_BORDER_THICKNESS = M_PI / 128.0f; 11const float TYPE_INDICATOR_BORDER_THICKNESS = M_PI / 128.0f;
14 12
13static void set_color_for_state(cairo_t *cairo, struct swaylock_state *state,
14 struct swaylock_colorset *colorset) {
15 if (state->auth_state == AUTH_STATE_VALIDATING) {
16 cairo_set_source_u32(cairo, colorset->verifying);
17 } else if (state->auth_state == AUTH_STATE_INVALID) {
18 cairo_set_source_u32(cairo, colorset->wrong);
19 } else if (state->auth_state == AUTH_STATE_CLEAR) {
20 cairo_set_source_u32(cairo, colorset->cleared);
21 } else {
22 cairo_set_source_u32(cairo, colorset->input);
23 }
24}
25
15void render_frame(struct swaylock_surface *surface) { 26void render_frame(struct swaylock_surface *surface) {
16 struct swaylock_state *state = surface->state; 27 struct swaylock_state *state = surface->state;
17 28
@@ -30,58 +41,37 @@ void render_frame(struct swaylock_surface *surface) {
30 cairo_t *cairo = surface->current_buffer->cairo; 41 cairo_t *cairo = surface->current_buffer->cairo;
31 cairo_identity_matrix(cairo); 42 cairo_identity_matrix(cairo);
32 43
44 cairo_save(cairo);
45 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
33 if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR || !surface->image) { 46 if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR || !surface->image) {
34 cairo_set_source_u32(cairo, state->args.color); 47 cairo_set_source_u32(cairo, state->args.colors.background);
35 cairo_paint(cairo); 48 cairo_paint(cairo);
36 } else { 49 } else {
37 render_background_image(cairo, surface->image, 50 render_background_image(cairo, surface->image,
38 state->args.mode, buffer_width, buffer_height); 51 state->args.mode, buffer_width, buffer_height);
39 } 52 }
53 cairo_restore(cairo);
40 cairo_identity_matrix(cairo); 54 cairo_identity_matrix(cairo);
41 55
42 int arc_radius = ARC_RADIUS * surface->scale; 56 int arc_radius = state->args.radius * surface->scale;
43 int arc_thickness = ARC_THICKNESS * surface->scale; 57 int arc_thickness = state->args.thickness * surface->scale;
44 float type_indicator_border_thickness = 58 float type_indicator_border_thickness =
45 TYPE_INDICATOR_BORDER_THICKNESS * surface->scale; 59 TYPE_INDICATOR_BORDER_THICKNESS * surface->scale;
46 60
47 if (state->args.show_indicator && state->auth_state != AUTH_STATE_IDLE) { 61 if (state->args.show_indicator && state->auth_state != AUTH_STATE_IDLE) {
48 // Draw circle 62 // Draw circle
49 cairo_set_line_width(cairo, arc_thickness); 63 cairo_set_line_width(cairo, arc_thickness);
50 cairo_arc(cairo, buffer_width / 2, buffer_height / 2, arc_radius, 0, 2 * M_PI); 64 cairo_arc(cairo, buffer_width / 2, buffer_height / 2, arc_radius,
51 switch (state->auth_state) { 65 0, 2 * M_PI);
52 case AUTH_STATE_INPUT: 66 set_color_for_state(cairo, state, &state->args.colors.inside);
53 case AUTH_STATE_INPUT_NOP: 67 cairo_fill_preserve(cairo);
54 case AUTH_STATE_BACKSPACE: { 68 set_color_for_state(cairo, state, &state->args.colors.ring);
55 cairo_set_source_rgba(cairo, 0, 0, 0, 0.75); 69 cairo_stroke(cairo);
56 cairo_fill_preserve(cairo);
57 cairo_set_source_rgb(cairo, 51.0 / 255, 125.0 / 255, 0);
58 cairo_stroke(cairo);
59 } break;
60 case AUTH_STATE_VALIDATING: {
61 cairo_set_source_rgba(cairo, 0, 114.0 / 255, 255.0 / 255, 0.75);
62 cairo_fill_preserve(cairo);
63 cairo_set_source_rgb(cairo, 51.0 / 255, 0, 250.0 / 255);
64 cairo_stroke(cairo);
65 } break;
66 case AUTH_STATE_INVALID: {
67 cairo_set_source_rgba(cairo, 250.0 / 255, 0, 0, 0.75);
68 cairo_fill_preserve(cairo);
69 cairo_set_source_rgb(cairo, 125.0 / 255, 51.0 / 255, 0);
70 cairo_stroke(cairo);
71 } break;
72 case AUTH_STATE_CLEAR: {
73 cairo_set_source_rgba(cairo, 229.0/255, 164.0/255, 69.0/255, 0.75);
74 cairo_fill_preserve(cairo);
75 cairo_set_source_rgb(cairo, 229.0/255, 164.0/255, 69.0/255);
76 cairo_stroke(cairo);
77 } break;
78 default: break;
79 }
80 70
81 // Draw a message 71 // Draw a message
82 char *text = NULL; 72 char *text = NULL;
83 cairo_set_source_rgb(cairo, 0, 0, 0); 73 set_color_for_state(cairo, state, &state->args.colors.text);
84 cairo_select_font_face(cairo, "sans-serif", 74 cairo_select_font_face(cairo, state->args.font,
85 CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); 75 CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
86 cairo_set_font_size(cairo, arc_radius / 3.0f); 76 cairo_set_font_size(cairo, arc_radius / 3.0f);
87 switch (state->auth_state) { 77 switch (state->auth_state) {
@@ -98,9 +88,10 @@ void render_frame(struct swaylock_surface *surface) {
98 case AUTH_STATE_INPUT_NOP: 88 case AUTH_STATE_INPUT_NOP:
99 if (state->xkb.caps_lock) { 89 if (state->xkb.caps_lock) {
100 text = "Caps Lock"; 90 text = "Caps Lock";
101 cairo_set_source_rgb(cairo, 229.0/255, 164.0/255, 69.0/255);
102 } 91 }
103 default: break; 92 break;
93 default:
94 break;
104 } 95 }
105 96
106 if (text) { 97 if (text) {
@@ -128,14 +119,14 @@ void render_frame(struct swaylock_surface *surface) {
128 arc_radius, highlight_start, 119 arc_radius, highlight_start,
129 highlight_start + TYPE_INDICATOR_RANGE); 120 highlight_start + TYPE_INDICATOR_RANGE);
130 if (state->auth_state == AUTH_STATE_INPUT) { 121 if (state->auth_state == AUTH_STATE_INPUT) {
131 cairo_set_source_rgb(cairo, 51.0 / 255, 219.0 / 255, 0); 122 cairo_set_source_u32(cairo, state->args.colors.key_highlight);
132 } else { 123 } else {
133 cairo_set_source_rgb(cairo, 219.0 / 255, 51.0 / 255, 0); 124 cairo_set_source_u32(cairo, state->args.colors.bs_highlight);
134 } 125 }
135 cairo_stroke(cairo); 126 cairo_stroke(cairo);
136 127
137 // Draw borders 128 // Draw borders
138 cairo_set_source_rgb(cairo, 0, 0, 0); 129 cairo_set_source_u32(cairo, state->args.colors.separator);
139 cairo_arc(cairo, buffer_width / 2, buffer_height / 2, 130 cairo_arc(cairo, buffer_width / 2, buffer_height / 2,
140 arc_radius, highlight_start, 131 arc_radius, highlight_start,
141 highlight_start + type_indicator_border_thickness); 132 highlight_start + type_indicator_border_thickness);
@@ -149,7 +140,7 @@ void render_frame(struct swaylock_surface *surface) {
149 } 140 }
150 141
151 // Draw inner + outer border of the circle 142 // Draw inner + outer border of the circle
152 cairo_set_source_rgb(cairo, 0, 0, 0); 143 set_color_for_state(cairo, state, &state->args.colors.line);
153 cairo_set_line_width(cairo, 2.0 * surface->scale); 144 cairo_set_line_width(cairo, 2.0 * surface->scale);
154 cairo_arc(cairo, buffer_width / 2, buffer_height / 2, 145 cairo_arc(cairo, buffer_width / 2, buffer_height / 2,
155 arc_radius - arc_thickness / 2, 0, 2 * M_PI); 146 arc_radius - arc_thickness / 2, 0, 2 * M_PI);
diff --git a/swaylock/seat.c b/swaylock/seat.c
index 6c66d220..c2630d87 100644
--- a/swaylock/seat.c
+++ b/swaylock/seat.c
@@ -12,13 +12,13 @@ static void keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
12 struct swaylock_state *state = data; 12 struct swaylock_state *state = data;
13 if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { 13 if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
14 close(fd); 14 close(fd);
15 wlr_log(L_ERROR, "Unknown keymap format %d, aborting", format); 15 wlr_log(WLR_ERROR, "Unknown keymap format %d, aborting", format);
16 exit(1); 16 exit(1);
17 } 17 }
18 char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); 18 char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
19 if (map_shm == MAP_FAILED) { 19 if (map_shm == MAP_FAILED) {
20 close(fd); 20 close(fd);
21 wlr_log(L_ERROR, "Unable to initialize keymap shm, aborting"); 21 wlr_log(WLR_ERROR, "Unable to initialize keymap shm, aborting");
22 exit(1); 22 exit(1);
23 } 23 }
24 struct xkb_keymap *keymap = xkb_keymap_new_from_string( 24 struct xkb_keymap *keymap = xkb_keymap_new_from_string(
diff --git a/swaylock/swaylock.1.scd b/swaylock/swaylock.1.scd
index 35d6444c..3107124f 100644
--- a/swaylock/swaylock.1.scd
+++ b/swaylock/swaylock.1.scd
@@ -12,23 +12,34 @@ Locks your Wayland session.
12 12
13# OPTIONS 13# OPTIONS
14 14
15*-h, --help* 15*-C, --config* <path>
16 Show help message and quit. 16 The config file to use. By default, the following paths are checked:
17 _$HOME/.swaylock/config_, _$XDG\_CONFIG\_HOME/swaylock/config_, and
18 _SYSCONFDIR/swaylock/config_. All flags aside from this one are valid
19 options in the configuration file using the format _long-option=value_.
20 For options such as _ignore-empty-password_, just supply the _long-option_.
21 All leading dashes should be omitted and the equals sign is required for
22 flags that take an argument.
17 23
18*-c, --color* <rrggbb[aa]> 24*-c, --color* <rrggbb[aa]>
19 Turn the screen into the given color. If -i is used, this sets the 25 Turn the screen into the given color. If -i is used, this sets the
20 background of the image to the given color. Defaults to white (FFFFFF), or 26 background of the image to the given color. Defaults to white (FFFFFF), or
21 transparent (00000000) if an image is in use. 27 transparent (00000000) if an image is in use.
22 28
29*-e, --ignore-empty-password*
30 When an empty password is provided by the user, do not validate it.
31
23*-f, --daemonize* 32*-f, --daemonize*
24 Fork into the background after spawning. Note: this is the default behavior 33 Detach from the controlling terminal after locking.
25 of i3lock. 34
35*-h, --help*
36 Show help message and quit.
26 37
27*-i, --image* [<output>:]<path> 38*-i, --image* [<output>:]<path>
28 Display the given image, optionally only on the given output. Use -c to set 39 Display the given image, optionally only on the given output. Use -c to set
29 a background color. 40 a background color.
30 41
31*--scaling* 42*-s, --scaling*
32 Scaling mode for images: _stretch_, _fill_, _fit_, _center_, or _tile_. 43 Scaling mode for images: _stretch_, _fill_, _fit_, _center_, or _tile_.
33 44
34*-t, --tiling* 45*-t, --tiling*
@@ -42,29 +53,52 @@ Locks your Wayland session.
42 53
43# APPEARANCE 54# APPEARANCE
44 55
45*--bshlcolor* <rrggbb[aa]> 56*--bs-hl-color* <rrggbb[aa]>
46 Sets the color of backspace highlight segments. 57 Sets the color of backspace highlight segments.
47 58
48*--font* <font> 59*--font* <font>
49 Sets the font of the text inside the indicator. 60 Sets the font of the text inside the indicator.
50 61
51*--insidecolor* <rrggbb[aa]> 62*--indicator-radius* <radius>
63 Sets the radius of the indicator to _radius_ pixels. The default value is
64 50.
65
66*--indicator-thickness* <thickness>
67 Sets the thickness of the indicator to _thickness_ pixels. The default value
68 is 10.
69
70*--inside-color* <rrggbb[aa]>
52 Sets the color of the inside of the indicator when typing or idle. 71 Sets the color of the inside of the indicator when typing or idle.
53 72
54*--insidevercolor* <rrggbb[aa]> 73*--inside-clear-color* <rrggbb[aa]>
74 Sets the color of the inside of the indicator when cleared.
75
76*--inside-ver-color* <rrggbb[aa]>
55 Sets the color of the inside of the indicator when verifying. 77 Sets the color of the inside of the indicator when verifying.
56 78
57*--insidewrongcolor* <rrggbb[aa]> 79*--inside-wrong-color* <rrggbb[aa]>
58 Sets the color of the inside of the indicator when invalid. 80 Sets the color of the inside of the indicator when invalid.
59 81
60*--keyhlcolor* <rrggbb[aa]> 82*--key-hl-color* <rrggbb[aa]>
61 Sets the color of keypress highlight segments. 83 Sets the color of key press highlight segments.
62 84
63*--linecolor* <rrggbb[aa]> 85*--line-color* <rrggbb[aa]>
64 Sets the color of the lines that separate the inside and outside of the 86 Sets the color of the lines that separate the inside and outside of the
65 indicator. 87 indicator when typing or idle.
66 88
67*-s, --line-uses-inside* 89*--line-clear-color* <rrggbb[aa]>
90 Sets the color of the lines that separate the inside and outside of the
91 indicator when cleared.
92
93*--line-ver-color* <rrggbb[aa]>
94 Sets the color of the lines that separate the inside and outside of the
95 indicator when verifying.
96
97*--line-wrong-color* <rrggbb[aa]>
98 Sets the color of the lines that separate the inside and outside of the
99 indicator when invalid.
100
101*-n, --line-uses-inside*
68 Use the color of the inside of the indicator for the line separating the 102 Use the color of the inside of the indicator for the line separating the
69 inside and outside of the indicator. 103 inside and outside of the indicator.
70 104
@@ -72,28 +106,32 @@ Locks your Wayland session.
72 Use the outer ring's color for the line separating the inside and outside of 106 Use the outer ring's color for the line separating the inside and outside of
73 the indicator. 107 the indicator.
74 108
75*--ringcolor* <rrggbb[aa]> 109*--ring-color* <rrggbb[aa]>
76 Sets the color of the outside of the indicator when typing or idle. 110 Sets the color of the outside of the indicator when typing or idle.
77 111
78*--ringvercolor* <rrggbb[aa]> 112*--ring-clear-color* <rrggbb[aa]>
113 Sets the color of the outside of the indicator when cleared.
114
115*--ring-ver-color* <rrggbb[aa]>
79 Sets the color of the outside of the indicator when verifying. 116 Sets the color of the outside of the indicator when verifying.
80 117
81*--ringwrongcolor* <rrggbb[aa]> 118*--ring-wrong-color* <rrggbb[aa]>
82 Sets the color of the outside of the indicator when invalid. 119 Sets the color of the outside of the indicator when invalid.
83 120
84*--separatorcolor* <rrggbb[aa]> 121*--separator-color* <rrggbb[aa]>
85 Sets the color of the lines that seperate highlight segments. 122 Sets the color of the lines that separate highlight segments.
86 123
87*--textcolor* <rrggbb[aa]> 124*--text-color* <rrggbb[aa]>
88 Sets the color of the text inside the indicator. 125 Sets the color of the text inside the indicator when typing or idle.
89 126
90*--indicator-radius* <radius> 127*--text-clear-color* <rrggbb[aa]>
91 Sets the radius of the indicator to _radius_ pixels. The default value is 128 Sets the color of the text inside the indicator when cleared.
92 50.
93 129
94*--indicator-thickness* <thickness> 130*--text-ver-color* <rrggbb[aa]>
95 Sets the thickness of the indicator to _thickness_ pixels. The default value 131 Sets the color of the text inside the indicator when verifying.
96 is 10. 132
133*--text-wrong-color* <rrggbb[aa]>
134 Sets the color of the text inside the indicator when invalid.
97 135
98# AUTHORS 136# AUTHORS
99 137