diff options
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 @@ | |||
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) { | |||
34 | static void daemonize() { | 35 | static 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; | |||
83 | static cairo_surface_t *select_image(struct swaylock_state *state, | 86 | static cairo_surface_t *select_image(struct swaylock_state *state, |
84 | struct swaylock_surface *surface); | 87 | struct swaylock_surface *surface); |
85 | 88 | ||
89 | static 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 | |||
86 | static void create_layer_surface(struct swaylock_surface *surface) { | 96 | static 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 | ||
219 | static void handle_xdg_output_name(void *data, struct zxdg_output_v1 *output, | 240 | static 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 | ||
364 | static struct swaylock_state state; | 388 | static 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 | |||
419 | enum line_mode { | ||
420 | LM_LINE, | ||
421 | LM_INSIDE, | ||
422 | LM_RING, | ||
423 | }; | ||
424 | |||
425 | static 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 | ||
366 | int 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 | |||
759 | static bool file_exists(const char *path) { | ||
760 | return path && access(path, R_OK) != -1; | ||
761 | } | ||
762 | |||
763 | static 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 | |||
800 | static 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 | |||
841 | static struct swaylock_state state; | ||
842 | |||
843 | int 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 | } |