Feature for #1078: Configurable swaylock colors

Colors are configured through the command line so that swaylock conforms
to the i3lock fork 'github.com/chrjguill/i3lock-color'. Differences from
it are that one letter options '-r' and '-s' are not implimentend because
'-s' is already used by '--scaling' in swaylock.
This commit also fixed whitespace in 'include/swaylock/swaylock.h' and
changed `parse_color` in 'common/util.h' so that it can accept colors
that do not start with a hash. This was done to keep compatability with
the i3lock fork.
master
Calvin Lee 8 years ago
parent 76614efb16
commit 34e2c70abc

@ -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,54 @@
#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,
}; };
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;
}; };
void render(struct render_data* render_data); 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, 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;
int line_source = 0;
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;
@ -335,21 +368,47 @@ int main(int argc, char **argv) {
{"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, 0},
{"line-uses-inside", no_argument, NULL, 0},
{"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}
}; };
const char *usage = const char *usage =
"Usage: swaylock [options...]\n" "Usage: swaylock [options...]\n"
"\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" " -s, --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"
" --font <font> Use the specified font instead of sans-serif.\n"
" --textcolor <rrggbb[aa]> Sets the color of the text.\n"
" --insidevercolor <rrggbb[aa]> Sets the color of the verifying indicator circle.\n"
" --insidewrongcolor <rrggbb[aa]> Sets the color of the invalid indicator circle.\n"
" --insidecolor <rrggbb[aa]> Sets the color of the typing or idle indicator circle.\n"
" --ringvercolor <rrggbb[aa]> Sets the color of the verifying indicator ring.\n"
" --ringwrongcolor <rrggbb[aa]> Sets the color of the invalid indicator ring.\n"
" --ringcolor <rrggbb[aa]> Sets the color of the typing or idle indicator ring.\n"
" --linecolor <rrggbb[aa]> Sets the color of the line that separates the indicator.\n"
" --separatorcolor <rrggbb[aa]> Sets the color of the line that separates highlight segments.\n"
" --keyhlcolor <rrggbb[aa]> Sets the color of keypress highlight segments.\n"
" --bshlcolor <rrggbb[aa]> Sets the color of keypress highlight segments.\n";
registry = registry_poll(); registry = registry_poll();
@ -364,18 +423,8 @@ int main(int argc, char **argv) {
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':
@ -431,6 +480,59 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
break; 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, "line-uses-ring") == 0) {
if (line_source != 0) {
sway_log(L_ERROR, "Line source options conflict");
exit(EXIT_FAILURE);
}
line_source = 1;
}
else if (strcmp(long_options[option_index].name, "line-uses-inside") == 0) {
if (line_source != 0) {
sway_log(L_ERROR, "Line source options conflict");
exit(EXIT_FAILURE);
}
line_source = 2;
}
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 +626,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 +658,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 +713,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 +735,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 +768,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 +783,41 @@ void render(struct render_data *render_data) {
cairo_stroke(window->cairo); cairo_stroke(window->cairo);
} }
if (line_source == 1) {
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);
}
}
}
else if (line_source == 2) {
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;
}
}
}
else {
cairo_set_source_u32(window->cairo, config->colors.line);
}
// 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);

@ -45,6 +45,43 @@ 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).
*--font* <font>::
Sets the font of the text inside the indicator.
*--textcolor* <rrggbb[aa]>::
Sets the color of the text inside the indicator.
*--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.
*--insidecolor* <rrggbb[aa]>::
Sets the color of the inside 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.
*--ringcolor* <rrggbb[aa]>::
Sets the color of the outside of the indicator when typing or idle.
*--linecolor* <rrggbb[aa]>::
Sets the color of the lines that separate the inside and outside of the
indicator.
*--separatorcolor* <rrggbb[aa]>::
Sets the color of the lines that seperate highlight segments.
*--keyhlcolor* <rrggbb[aa]>::
Sets the color of keypress highlight segments.
*--bshlcolor* <rrggbb[aa]>::
Sets the color of backspace highlight segments.
Authors Authors
------- -------

Loading…
Cancel
Save