Merge pull request #1081 from 4e554c4c/swaylock_colors

Feature for #1078: Configurable swaylock colors
master
Drew DeVault 8 years ago committed by GitHub
commit 7f58ea5ec2

@ -102,13 +102,17 @@ pid_t get_parent_pid(pid_t child) {
} }
uint32_t parse_color(const char *color) { uint32_t parse_color(const char *color) {
if (color[0] == '#') {
++color;
}
int len = strlen(color); int len = strlen(color);
if (color[0] != '#' || (len != 7 && len != 9)) { if (len != 6 && len != 8) {
sway_log(L_DEBUG, "Invalid color %s, defaulting to color 0xFFFFFFFF", color); sway_log(L_DEBUG, "Invalid color %s, defaulting to color 0xFFFFFFFF", color);
return 0xFFFFFFFF; return 0xFFFFFFFF;
} }
uint32_t res = (uint32_t)strtoul(color + 1, NULL, 16); uint32_t res = (uint32_t)strtoul(color, NULL, 16);
if (strlen(color) == 7) { if (strlen(color) == 6) {
res = (res << 8) | 0xFF; res = (res << 8) | 0xFF;
} }
return res; return res;

@ -4,34 +4,60 @@
#include "client/cairo.h" #include "client/cairo.h"
enum scaling_mode { enum scaling_mode {
SCALING_MODE_STRETCH, SCALING_MODE_STRETCH,
SCALING_MODE_FILL, SCALING_MODE_FILL,
SCALING_MODE_FIT, SCALING_MODE_FIT,
SCALING_MODE_CENTER, SCALING_MODE_CENTER,
SCALING_MODE_TILE, SCALING_MODE_TILE,
}; };
enum auth_state { enum auth_state {
AUTH_STATE_IDLE, AUTH_STATE_IDLE,
AUTH_STATE_INPUT, AUTH_STATE_INPUT,
AUTH_STATE_BACKSPACE, AUTH_STATE_BACKSPACE,
AUTH_STATE_VALIDATING, AUTH_STATE_VALIDATING,
AUTH_STATE_INVALID, AUTH_STATE_INVALID,
};
enum line_source {
LINE_SOURCE_DEFAULT,
LINE_SOURCE_RING,
LINE_SOURCE_INSIDE,
}; };
struct render_data { struct render_data {
list_t *surfaces; list_t *surfaces;
// Output specific images // Output specific images
cairo_surface_t **images; cairo_surface_t **images;
// OR one image for all outputs: // OR one image for all outputs:
cairo_surface_t *image; cairo_surface_t *image;
int num_images; int num_images;
int color_set; int color_set;
uint32_t color; uint32_t color;
enum scaling_mode scaling_mode; enum scaling_mode scaling_mode;
enum auth_state auth_state; enum auth_state auth_state;
};
struct lock_colors {
uint32_t inner_ring;
uint32_t outer_ring;
};
struct lock_config {
char *font;
struct {
uint32_t text;
uint32_t line;
uint32_t separator;
uint32_t input_cursor;
uint32_t backspace_cursor;
struct lock_colors normal;
struct lock_colors validating;
struct lock_colors invalid;
} colors;
}; };
void render(struct render_data* render_data); void render(struct render_data* render_data, struct lock_config *config);
#endif #endif

@ -18,9 +18,11 @@
#include "swaylock/swaylock.h" #include "swaylock/swaylock.h"
#include "ipc-client.h" #include "ipc-client.h"
#include "log.h" #include "log.h"
#include "util.h"
struct registry *registry; struct registry *registry;
struct render_data render_data; struct render_data render_data;
struct lock_config *config;
bool show_indicator = true; bool show_indicator = true;
void wl_dispatch_events() { void wl_dispatch_events() {
@ -35,7 +37,7 @@ void sigalarm_handler(int sig) {
signal(SIGALRM, SIG_IGN); signal(SIGALRM, SIG_IGN);
// Hide typing indicator // Hide typing indicator
render_data.auth_state = AUTH_STATE_IDLE; render_data.auth_state = AUTH_STATE_IDLE;
render(&render_data); render(&render_data, config);
wl_display_flush(registry->display); wl_display_flush(registry->display);
signal(SIGALRM, sigalarm_handler); signal(SIGALRM, sigalarm_handler);
} }
@ -55,6 +57,36 @@ void sway_terminate(int exit_code) {
char *password; char *password;
int password_size; int password_size;
enum line_source line_source = LINE_SOURCE_DEFAULT;
struct lock_config *init_config() {
struct lock_config *config = calloc(1, sizeof(struct lock_config));
config->font = strdup("sans-serif");
config->colors.text = 0x000000FF;
config->colors.line = 0x000000FF;
config->colors.separator = 0x000000FF;
config->colors.input_cursor = 0x33DB00FF;
config->colors.backspace_cursor = 0xDB3300FF;
config->colors.normal.inner_ring = 0x000000BF;
config->colors.normal.outer_ring = 0x337D00FF;
config->colors.validating.inner_ring = 0x0072FFBF;
config->colors.validating.outer_ring = 0x3300FAFF;
config->colors.invalid.inner_ring = 0xFA0000BF;
config->colors.invalid.outer_ring = 0x7D3300FF;
return config;
}
void free_config(struct lock_config *config) {
free(config->font);
free(config);
}
int function_conversation(int num_msg, const struct pam_message **msg, int function_conversation(int num_msg, const struct pam_message **msg,
struct pam_response **resp, void *appdata_ptr) { struct pam_response **resp, void *appdata_ptr) {
@ -123,7 +155,7 @@ void notify_key(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t cod
case XKB_KEY_Return: case XKB_KEY_Return:
render_data.auth_state = AUTH_STATE_VALIDATING; render_data.auth_state = AUTH_STATE_VALIDATING;
render(&render_data); render(&render_data, config);
// Make sure our render call will actually be displayed on the screen // Make sure our render call will actually be displayed on the screen
wl_dispatch_events(); wl_dispatch_events();
@ -207,7 +239,7 @@ void notify_key(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t cod
} }
} }
if (redraw_screen) { if (redraw_screen) {
render(&render_data); render(&render_data, config);
wl_dispatch_events(); wl_dispatch_events();
// Hide the indicator after a couple of seconds // Hide the indicator after a couple of seconds
alarm(5); alarm(5);
@ -315,6 +347,7 @@ int main(int argc, char **argv) {
const char *scaling_mode_str = "fit", *socket_path = NULL; const char *scaling_mode_str = "fit", *socket_path = NULL;
int i; int i;
void *images = NULL; void *images = NULL;
config = init_config();
render_data.num_images = 0; render_data.num_images = 0;
render_data.color_set = 0; render_data.color_set = 0;
@ -329,12 +362,26 @@ int main(int argc, char **argv) {
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
{"color", required_argument, NULL, 'c'}, {"color", required_argument, NULL, 'c'},
{"image", required_argument, NULL, 'i'}, {"image", required_argument, NULL, 'i'},
{"scaling", required_argument, NULL, 's'}, {"scaling", required_argument, NULL, 0},
{"tiling", no_argument, NULL, 't'}, {"tiling", no_argument, NULL, 't'},
{"version", no_argument, NULL, 'v'}, {"version", no_argument, NULL, 'v'},
{"socket", required_argument, NULL, 'p'}, {"socket", required_argument, NULL, 'p'},
{"no-unlock-indicator", no_argument, NULL, 'u'}, {"no-unlock-indicator", no_argument, NULL, 'u'},
{"daemonize", no_argument, NULL, 'f'}, {"daemonize", no_argument, NULL, 'f'},
{"font", required_argument, NULL, 0},
{"line-uses-ring", no_argument, NULL, 'r'},
{"line-uses-inside", no_argument, NULL, 's'},
{"textcolor", required_argument, NULL, 0},
{"insidevercolor", required_argument, NULL, 0},
{"insidewrongcolor", required_argument, NULL, 0},
{"insidecolor", required_argument, NULL, 0},
{"ringvercolor", required_argument, NULL, 0},
{"ringwrongcolor", required_argument, NULL, 0},
{"ringcolor", required_argument, NULL, 0},
{"linecolor", required_argument, NULL, 0},
{"separatorcolor", required_argument, NULL, 0},
{"keyhlcolor", required_argument, NULL, 0},
{"bshlcolor", required_argument, NULL, 0},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
@ -343,13 +390,14 @@ int main(int argc, char **argv) {
"\n" "\n"
" -h, --help Show help message and quit.\n" " -h, --help Show help message and quit.\n"
" -c, --color <rrggbb[aa]> Turn the screen into the given color instead of white.\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" " --scaling Scaling mode: stretch, fill, fit, center, tile.\n"
" -t, --tiling Same as --scaling=tile.\n" " -t, --tiling Same as --scaling=tile.\n"
" -v, --version Show the version number and quit.\n" " -v, --version Show the version number and quit.\n"
" -i, --image [<output>:]<path> Display the given image.\n" " -i, --image [<output>:]<path> Display the given image.\n"
" -u, --no-unlock-indicator Disable the unlock indicator.\n" " -u, --no-unlock-indicator Disable the unlock indicator.\n"
" -f, --daemonize Detach from the controlling terminal.\n" " -f, --daemonize Detach from the controlling terminal.\n"
" --socket <socket> Use the specified socket.\n"; " --socket <socket> Use the specified socket.\n"
" For more information see `man swaylock`\n";
registry = registry_poll(); registry = registry_poll();
@ -357,25 +405,15 @@ int main(int argc, char **argv) {
int c; int c;
while (1) { while (1) {
int option_index = 0; int option_index = 0;
c = getopt_long(argc, argv, "hc:i:s:tvuf", long_options, &option_index); c = getopt_long(argc, argv, "hc:i:srtvuf", long_options, &option_index);
if (c == -1) { if (c == -1) {
break; break;
} }
switch (c) { switch (c) {
case 'c': case 'c':
{ {
int colorlen = strlen(optarg); render_data.color = parse_color(optarg);
if (colorlen < 6 || colorlen == 7 || colorlen > 8) {
sway_log(L_ERROR, "color must be specified in 3 or 4 byte format, i.e. rrggbb or rrggbbaa");
exit(EXIT_FAILURE);
}
render_data.color = strtol(optarg, NULL, 16);
render_data.color_set = 1; render_data.color_set = 1;
if (colorlen == 6) {
render_data.color <<= 8;
render_data.color |= 0xFF;
}
break; break;
} }
case 'i': case 'i':
@ -405,9 +443,6 @@ int main(int argc, char **argv) {
} }
break; break;
} }
case 's':
scaling_mode_str = optarg;
break;
case 't': case 't':
scaling_mode_str = "tile"; scaling_mode_str = "tile";
break; break;
@ -431,6 +466,50 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
break; break;
case 'r':
if (line_source != LINE_SOURCE_DEFAULT) {
sway_log(L_ERROR, "line source options conflict");
exit(EXIT_FAILURE);
}
line_source = LINE_SOURCE_RING;
break;
case 's':
if (line_source != LINE_SOURCE_DEFAULT) {
sway_log(L_ERROR, "line source options conflict");
exit(EXIT_FAILURE);
}
line_source = LINE_SOURCE_INSIDE;
break;
case 0:
if (strcmp(long_options[option_index].name, "font") == 0) {
free(config->font);
config->font = strdup(optarg);
} else if (strcmp(long_options[option_index].name, "scaling") == 0) {
scaling_mode_str = optarg;
} else if (strcmp(long_options[option_index].name, "textcolor") == 0) {
config->colors.text = parse_color(optarg);
} else if (strcmp(long_options[option_index].name, "insidevercolor") == 0) {
config->colors.validating.inner_ring = parse_color(optarg);
} else if (strcmp(long_options[option_index].name, "insidewrongcolor") == 0) {
config->colors.invalid.inner_ring = parse_color(optarg);
} else if (strcmp(long_options[option_index].name, "insidecolor") == 0) {
config->colors.normal.inner_ring = parse_color(optarg);
} else if (strcmp(long_options[option_index].name, "ringvercolor") == 0) {
config->colors.validating.outer_ring = parse_color(optarg);
} else if (strcmp(long_options[option_index].name, "ringwrongcolor") == 0) {
config->colors.invalid.outer_ring = parse_color(optarg);
} else if (strcmp(long_options[option_index].name, "ringcolor") == 0) {
config->colors.normal.outer_ring = parse_color(optarg);
} else if (strcmp(long_options[option_index].name, "linecolor") == 0) {
config->colors.line = parse_color(optarg);
} else if (strcmp(long_options[option_index].name, "separatorcolor") == 0) {
config->colors.separator = parse_color(optarg);
} else if (strcmp(long_options[option_index].name, "keyhlcolor") == 0) {
config->colors.input_cursor = parse_color(optarg);
} else if (strcmp(long_options[option_index].name, "bshlcolor") == 0) {
config->colors.backspace_cursor = parse_color(optarg);
}
break;
default: default:
fprintf(stderr, "%s", usage); fprintf(stderr, "%s", usage);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -524,7 +603,7 @@ int main(int argc, char **argv) {
free(displays_paths); free(displays_paths);
} }
render(&render_data); render(&render_data, config);
bool locked = false; bool locked = false;
while (wl_display_dispatch(registry->display) != -1) { while (wl_display_dispatch(registry->display) != -1) {
if (!locked) { if (!locked) {
@ -556,10 +635,12 @@ int main(int argc, char **argv) {
list_free(render_data.surfaces); list_free(render_data.surfaces);
registry_teardown(registry); registry_teardown(registry);
free_config(config);
return 0; return 0;
} }
void render(struct render_data *render_data) { void render(struct render_data *render_data, struct lock_config *config) {
int i; int i;
for (i = 0; i < render_data->surfaces->length; ++i) { for (i = 0; i < render_data->surfaces->length; ++i) {
sway_log(L_DEBUG, "Render surface %d of %d", i, render_data->surfaces->length); sway_log(L_DEBUG, "Render surface %d of %d", i, render_data->surfaces->length);
@ -609,21 +690,21 @@ void render(struct render_data *render_data) {
switch (render_data->auth_state) { switch (render_data->auth_state) {
case AUTH_STATE_INPUT: case AUTH_STATE_INPUT:
case AUTH_STATE_BACKSPACE: { case AUTH_STATE_BACKSPACE: {
cairo_set_source_rgba(window->cairo, 0, 0, 0, 0.75); cairo_set_source_u32(window->cairo, config->colors.normal.inner_ring);
cairo_fill_preserve(window->cairo); cairo_fill_preserve(window->cairo);
cairo_set_source_rgb(window->cairo, 51.0 / 255, 125.0 / 255, 0); cairo_set_source_u32(window->cairo, config->colors.normal.outer_ring);
cairo_stroke(window->cairo); cairo_stroke(window->cairo);
} break; } break;
case AUTH_STATE_VALIDATING: { case AUTH_STATE_VALIDATING: {
cairo_set_source_rgba(window->cairo, 0, 114.0 / 255, 255.0 / 255, 0.75); cairo_set_source_u32(window->cairo, config->colors.validating.inner_ring);
cairo_fill_preserve(window->cairo); cairo_fill_preserve(window->cairo);
cairo_set_source_rgb(window->cairo, 51.0 / 255, 0, 250.0 / 255); cairo_set_source_u32(window->cairo, config->colors.validating.outer_ring);
cairo_stroke(window->cairo); cairo_stroke(window->cairo);
} break; } break;
case AUTH_STATE_INVALID: { case AUTH_STATE_INVALID: {
cairo_set_source_rgba(window->cairo, 250.0 / 255, 0, 0, 0.75); cairo_set_source_u32(window->cairo, config->colors.invalid.inner_ring);
cairo_fill_preserve(window->cairo); cairo_fill_preserve(window->cairo);
cairo_set_source_rgb(window->cairo, 125.0 / 255, 51.0 / 255, 0); cairo_set_source_u32(window->cairo, config->colors.invalid.outer_ring);
cairo_stroke(window->cairo); cairo_stroke(window->cairo);
} break; } break;
default: break; default: break;
@ -631,8 +712,8 @@ void render(struct render_data *render_data) {
// Draw a message // Draw a message
char *text = NULL; char *text = NULL;
cairo_set_source_rgb(window->cairo, 0, 0, 0); cairo_set_source_u32(window->cairo, config->colors.text);
cairo_select_font_face(window->cairo, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_select_font_face(window->cairo, config->font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(window->cairo, ARC_RADIUS/3.0f); cairo_set_font_size(window->cairo, ARC_RADIUS/3.0f);
switch (render_data->auth_state) { switch (render_data->auth_state) {
case AUTH_STATE_VALIDATING: case AUTH_STATE_VALIDATING:
@ -664,14 +745,14 @@ void render(struct render_data *render_data) {
highlight_start += (rand() % (int)(M_PI * 100)) / 100.0 + M_PI * 0.5; highlight_start += (rand() % (int)(M_PI * 100)) / 100.0 + M_PI * 0.5;
cairo_arc(window->cairo, wwidth/2, wheight/2, ARC_RADIUS, highlight_start, highlight_start + TYPE_INDICATOR_RANGE); cairo_arc(window->cairo, wwidth/2, wheight/2, ARC_RADIUS, highlight_start, highlight_start + TYPE_INDICATOR_RANGE);
if (render_data->auth_state == AUTH_STATE_INPUT) { if (render_data->auth_state == AUTH_STATE_INPUT) {
cairo_set_source_rgb(window->cairo, 51.0 / 255, 219.0 / 255, 0); cairo_set_source_u32(window->cairo, config->colors.input_cursor);
} else { } else {
cairo_set_source_rgb(window->cairo, 219.0 / 255, 51.0 / 255, 0); cairo_set_source_u32(window->cairo, config->colors.backspace_cursor);
} }
cairo_stroke(window->cairo); cairo_stroke(window->cairo);
// Draw borders // Draw borders
cairo_set_source_rgb(window->cairo, 0, 0, 0); cairo_set_source_u32(window->cairo, config->colors.separator);
cairo_arc(window->cairo, wwidth/2, wheight/2, ARC_RADIUS, highlight_start, highlight_start + TYPE_INDICATOR_BORDER_THICKNESS); cairo_arc(window->cairo, wwidth/2, wheight/2, ARC_RADIUS, highlight_start, highlight_start + TYPE_INDICATOR_BORDER_THICKNESS);
cairo_stroke(window->cairo); cairo_stroke(window->cairo);
@ -679,8 +760,37 @@ void render(struct render_data *render_data) {
cairo_stroke(window->cairo); cairo_stroke(window->cairo);
} }
switch(line_source) {
case LINE_SOURCE_RING:
switch(render_data->auth_state) {
case AUTH_STATE_VALIDATING:
cairo_set_source_u32(window->cairo, config->colors.validating.outer_ring);
break;
case AUTH_STATE_INVALID:
cairo_set_source_u32(window->cairo, config->colors.invalid.outer_ring);
break;
default:
cairo_set_source_u32(window->cairo, config->colors.normal.outer_ring);
}
break;
case LINE_SOURCE_INSIDE:
switch(render_data->auth_state) {
case AUTH_STATE_VALIDATING:
cairo_set_source_u32(window->cairo, config->colors.validating.inner_ring);
break;
case AUTH_STATE_INVALID:
cairo_set_source_u32(window->cairo, config->colors.invalid.inner_ring);
break;
default:
cairo_set_source_u32(window->cairo, config->colors.normal.inner_ring);
break;
}
break;
default:
cairo_set_source_u32(window->cairo, config->colors.line);
break;
}
// Draw inner + outer border of the circle // Draw inner + outer border of the circle
cairo_set_source_rgb(window->cairo, 0, 0, 0);
cairo_set_line_width(window->cairo, 2.0); cairo_set_line_width(window->cairo, 2.0);
cairo_arc(window->cairo, wwidth/2, wheight/2, ARC_RADIUS - ARC_THICKNESS/2, 0, 2*M_PI); cairo_arc(window->cairo, wwidth/2, wheight/2, ARC_RADIUS - ARC_THICKNESS/2, 0, 2*M_PI);
cairo_stroke(window->cairo); cairo_stroke(window->cairo);

@ -29,7 +29,7 @@ Options
*-i, \--image* [<output>:]<path>:: *-i, \--image* [<output>:]<path>::
Display the given image, optionally only on the given output. Display the given image, optionally only on the given output.
*-s, \--scaling*:: *--scaling*::
Scaling mode for images: stretch, fill, fit, center, or tile. Scaling mode for images: stretch, fill, fit, center, or tile.
*-t, --tiling*:: *-t, --tiling*::
@ -45,6 +45,53 @@ Options
Use the specified socket path. Otherwise, swaymsg will ask sway where the Use the specified socket path. Otherwise, swaymsg will ask sway where the
socket is (which is the value of $SWAYSOCK, then of $I3SOCK). socket is (which is the value of $SWAYSOCK, then of $I3SOCK).
Appearance
----------
*--bshlcolor* <rrggbb[aa]>::
Sets the color of backspace highlight segments.
*--font* <font>::
Sets the font of the text inside the indicator.
*--insidecolor* <rrggbb[aa]>::
Sets the color of the inside of the indicator when typing or idle.
*--insidevercolor* <rrggbb[aa]>::
Sets the color of the inside of the indicator when verifying.
*--insidewrongcolor* <rrggbb[aa]>::
Sets the color of the inside of the indicator when invalid.
*--keyhlcolor* <rrggbb[aa]>::
Sets the color of keypress highlight segments.
*--linecolor* <rrggbb[aa]>::
Sets the color of the lines that separate the inside and outside of the
indicator.
*-s, \--line-uses-inside*::
Use the color of the inside of the indicator for the line separating the
inside and outside of the indicator.
*-r, \--line-uses-ring*::
Use the outer ring's color for the line separating the inside and outside of
the indicator.
*--ringcolor* <rrggbb[aa]>::
Sets the color of the outside of the indicator when typing or idle.
*--ringvercolor* <rrggbb[aa]>::
Sets the color of the outside of the indicator when verifying.
*--ringwrongcolor* <rrggbb[aa]>::
Sets the color of the outside of the indicator when invalid.
*--separatorcolor* <rrggbb[aa]>::
Sets the color of the lines that seperate highlight segments.
*--textcolor* <rrggbb[aa]>::
Sets the color of the text inside the indicator.
Authors Authors
------- -------

Loading…
Cancel
Save