From c7b60140603021de3dc247cf36af4c7a0242072b Mon Sep 17 00:00:00 2001 From: Zach Anderson Date: Sat, 26 Mar 2022 23:55:00 -0500 Subject: [PATCH 1/2] Add options to draw indicator as polygon --- i3lock-bash | 4 ++++ i3lock-zsh | 4 ++++ i3lock.1 | 15 +++++++++++++ i3lock.c | 32 ++++++++++++++++++++++++++++ unlock_indicator.c | 52 +++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 102 insertions(+), 5 deletions(-) diff --git a/i3lock-bash b/i3lock-bash index ce440740..3bd0e955 100644 --- a/i3lock-bash +++ b/i3lock-bash @@ -93,6 +93,10 @@ _i3lock() { "--bar-pos" "--bar-count" "--bar-total-width" + # Polygon indicator + "--polygon-sides" + "--polygon-offset" + "--polygon-highlight" # Extra configs "--redraw-thread" "--refresh-rate" diff --git a/i3lock-zsh b/i3lock-zsh index 14327765..dde6a6ab 100644 --- a/i3lock-zsh +++ b/i3lock-zsh @@ -93,6 +93,10 @@ _i3lock() { "--bar-pos[Sets the bar position]:pos:->bar_pos" "--bar-count[Sets the number of minibars to draw on each screen]:int:" "--bar-total-width[The total width of the bar]:float:" + # Polygon indicator + "--polygon-sides[Draws the indicator as a regular polygon]:int:" + "--polygon-offset[Rotates the indicator polygon]:float:" + "--polygon-highlight[Sets the polygon highlight mode]:mode:((0\:'random' 1\:'clockwise' 2\:'counterclockwise'))" # Extra configs "--redraw-thread[Starts a separate thread for redrawing the screen]" "--refresh-rate[The refresh rate of the indicator]:double:" diff --git a/i3lock.1 b/i3lock.1 index 2ef335d6..22805c29 100644 --- a/i3lock.1 +++ b/i3lock.1 @@ -444,6 +444,21 @@ Sets the number of minibars to draw on each screen. .B \-\-bar\-total\-width The total width of the bar. Can be an expression. +.TP +.B \-\-polygon\-sides=0 +If set to an integer greater then 2, draw the indicator as a regular polygon +instead of a circle. + +.TP +.B \-\-polygon\-offset=degrees\-as\-double +The angle to rotate the indicator polygon by. + +.TP +.B \-\-polygon\-highlight={0, 1, 2} +Sets the highlight mode when drawing the indicator as a polygon. 0 highlights a +random edge on each keypress, 1 highlights consecutive edges clockwise, 2 highlights +counterclockwise. Highlights reverse direction while backspacing. + .TP .B \-\-redraw\-thread Starts a separate thread for redrawing the screen. Potentially worse from a diff --git a/i3lock.c b/i3lock.c index b7c320a7..aad32e9d 100644 --- a/i3lock.c +++ b/i3lock.c @@ -294,6 +294,11 @@ char bar_width_expr[32] = ""; // empty string means full width based on bar orie bool bar_bidirectional = false; bool bar_reversed = false; +// Polygon indicator +int polygon_sides = 0; +double polygon_offset = 0; +int polygon_highlight = 0; + /* isutf, u8_dec © 2005 Jeff Bezanson, public domain */ #define isutf(c) (((c)&0xC0) != 0x80) @@ -1493,6 +1498,9 @@ int main(int argc, char *argv[]) { {"indicator", no_argument, NULL, 401}, {"radius", required_argument, NULL, 402}, {"ring-width", required_argument, NULL, 403}, + {"polygon-sides", required_argument, NULL, 404}, + {"polygon-offset", required_argument, NULL, 405}, + {"polygon-highlight", required_argument, NULL, 406}, // alignment {"time-align", required_argument, NULL, 500}, @@ -1810,6 +1818,30 @@ int main(int argc, char *argv[]) { fprintf(stderr, "ring-width must be a positive float; ignoring...\n"); ring_width = 7.0; } + break; + case 404: + arg = optarg; + if (sscanf(arg, "%d", &polygon_sides) != 1) + errx(1, "polygon-sides must be a number\n"); + if (polygon_sides < 3 && polygon_sides != 0) { + fprintf(stderr, "polygon-sides must be greater then 2 or 0; ignoring...\n"); + polygon_sides = 0; + } + break; + case 405: + arg = optarg; + if (sscanf(arg, "%lf", &polygon_offset) != 1) + errx(1, "polygon-offset must be a number\n"); + polygon_offset = polygon_offset * (M_PI / 180); + break; + case 406: + arg = optarg; + if (sscanf(arg, "%d", &polygon_highlight) != 1) + errx(1, "polygon-highlight must be a number\n"); + if (polygon_highlight < 0 || polygon_highlight > 2) { + fprintf(stderr, "polygon-highlight must be between 0 and 2; ignoring...\n"); + polygon_highlight = 0; + } break; // Alignment stuff diff --git a/unlock_indicator.c b/unlock_indicator.c index e10984a6..8c61eca2 100644 --- a/unlock_indicator.c +++ b/unlock_indicator.c @@ -247,6 +247,11 @@ extern char bar_width_expr[32]; extern bool bar_bidirectional; extern bool bar_reversed; +// Polygon indicator +extern int polygon_sides; +extern double polygon_offset; +extern int polygon_highlight; + static cairo_font_face_t *font_faces[6] = { NULL, NULL, @@ -518,12 +523,31 @@ static void draw_bar(cairo_t *ctx, double bar_x, double bar_y, double bar_width, cairo_restore(ctx); } +void draw_polygon(cairo_t *ctx, double center_x, double center_y, double radius, int points, int start, int end, double offset) { + int count = end - start; + + for (int v = 0; v < count + 1; v++) { + double theta = (start + v) * ((M_PI * 2) / points) + offset; + + int x = radius * cos(theta); + int y = radius * sin(theta); + + if (v == 0) + cairo_move_to(ctx, center_x + x, center_y + y); + else + cairo_line_to(ctx, center_x + x, center_y + y); + } +} + static void draw_indic(cairo_t *ctx, double ind_x, double ind_y) { if (unlock_indicator && (unlock_state >= STATE_KEY_PRESSED || auth_state > STATE_AUTH_IDLE || show_indicator)) { /* Draw a (centered) circle with transparent background. */ cairo_set_line_width(ctx, RING_WIDTH); - cairo_arc(ctx, ind_x, ind_y, BUTTON_RADIUS, 0, 2 * M_PI); + if (polygon_sides > 0) + draw_polygon(ctx, ind_x, ind_y, BUTTON_RADIUS, polygon_sides, 0, polygon_sides, polygon_offset); + else + cairo_arc(ctx, ind_x, ind_y, BUTTON_RADIUS, 0, 2 * M_PI); /* Use the appropriate color for the different PAM states * (currently verifying, wrong password, or default) */ @@ -593,15 +617,16 @@ static void draw_indic(cairo_t *ctx, double ind_x, double ind_y) { if (internal_line_source != 2) { //pretty sure this only needs drawn if it's being drawn over the inside? cairo_set_source_rgba(ctx, line16.red, line16.green, line16.blue, line16.alpha); cairo_set_line_width(ctx, 2.0); - cairo_arc(ctx, ind_x, ind_y, BUTTON_RADIUS - 5, 0, 2 * M_PI); + if (polygon_sides > 0) + draw_polygon(ctx, ind_x, ind_y, BUTTON_RADIUS - 5, polygon_sides, 0, polygon_sides, polygon_offset); + else + cairo_arc(ctx, ind_x, ind_y, BUTTON_RADIUS - 5, 0, 2 * M_PI); cairo_stroke(ctx); } if (unlock_state == STATE_KEY_ACTIVE || unlock_state == STATE_BACKSPACE_ACTIVE) { cairo_set_line_width(ctx, RING_WIDTH); cairo_new_sub_path(ctx); - double highlight_start = (rand() % (int)(2 * M_PI * 100)) / 100.0; - cairo_arc(ctx, ind_x, ind_y, BUTTON_RADIUS, - highlight_start, highlight_start + (M_PI / 3.0)); + if (unlock_state == STATE_KEY_ACTIVE) { /* For normal keys, we use a lighter green. */ cairo_set_source_rgba(ctx, keyhl16.red, keyhl16.green, keyhl16.blue, keyhl16.alpha); @@ -610,6 +635,23 @@ static void draw_indic(cairo_t *ctx, double ind_x, double ind_y) { cairo_set_source_rgba(ctx, bshl16.red, bshl16.green, bshl16.blue, bshl16.alpha); } + if (polygon_sides > 0) { + int highlight_start = 0; + if (polygon_highlight == 0) + highlight_start = rand() % polygon_sides; + else if(polygon_highlight == 1) + highlight_start = input_position % polygon_sides; + else if(polygon_highlight == 2) + highlight_start = -input_position % polygon_sides; + draw_polygon(ctx, ind_x, ind_y, BUTTON_RADIUS, polygon_sides, highlight_start, highlight_start+1, polygon_offset); + cairo_stroke(ctx); + return; + } + + double highlight_start = (rand() % (int)(2 * M_PI * 100)) / 100.0; + cairo_arc(ctx, ind_x, ind_y, BUTTON_RADIUS, + highlight_start, highlight_start + (M_PI / 3.0)); + cairo_stroke(ctx); /* Draw two little separators for the highlighted part of the From 4920faf7068e475128f16ac5cdfe4d42b218bb0f Mon Sep 17 00:00:00 2001 From: Zach Anderson Date: Sat, 6 Aug 2022 02:04:24 -0500 Subject: [PATCH 2/2] s/offset/rotation/g --- i3lock-zsh | 2 +- i3lock.1 | 7 +++---- i3lock.c | 18 ++++++++---------- unlock_indicator.c | 22 ++++++++++++++++------ 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/i3lock-zsh b/i3lock-zsh index dde6a6ab..4d045a18 100644 --- a/i3lock-zsh +++ b/i3lock-zsh @@ -95,7 +95,7 @@ _i3lock() { "--bar-total-width[The total width of the bar]:float:" # Polygon indicator "--polygon-sides[Draws the indicator as a regular polygon]:int:" - "--polygon-offset[Rotates the indicator polygon]:float:" + "--polygon-rotation[Rotates the indicator polygon]:float:" "--polygon-highlight[Sets the polygon highlight mode]:mode:((0\:'random' 1\:'clockwise' 2\:'counterclockwise'))" # Extra configs "--redraw-thread[Starts a separate thread for redrawing the screen]" diff --git a/i3lock.1 b/i3lock.1 index 22805c29..d869a839 100644 --- a/i3lock.1 +++ b/i3lock.1 @@ -445,12 +445,11 @@ Sets the number of minibars to draw on each screen. The total width of the bar. Can be an expression. .TP -.B \-\-polygon\-sides=0 -If set to an integer greater then 2, draw the indicator as a regular polygon -instead of a circle. +.B \-\-polygon\-sides +Draw the indicator as a regular polygon instead of a circle. .TP -.B \-\-polygon\-offset=degrees\-as\-double +.B \-\-polygon\-rotation=degrees\-as\-double The angle to rotate the indicator polygon by. .TP diff --git a/i3lock.c b/i3lock.c index aad32e9d..94b211e6 100644 --- a/i3lock.c +++ b/i3lock.c @@ -296,7 +296,7 @@ bool bar_reversed = false; // Polygon indicator int polygon_sides = 0; -double polygon_offset = 0; +double polygon_rotation = 0; int polygon_highlight = 0; /* isutf, u8_dec © 2005 Jeff Bezanson, public domain */ @@ -1499,7 +1499,7 @@ int main(int argc, char *argv[]) { {"radius", required_argument, NULL, 402}, {"ring-width", required_argument, NULL, 403}, {"polygon-sides", required_argument, NULL, 404}, - {"polygon-offset", required_argument, NULL, 405}, + {"polygon-rotation", required_argument, NULL, 405}, {"polygon-highlight", required_argument, NULL, 406}, // alignment @@ -1822,17 +1822,15 @@ int main(int argc, char *argv[]) { case 404: arg = optarg; if (sscanf(arg, "%d", &polygon_sides) != 1) - errx(1, "polygon-sides must be a number\n"); - if (polygon_sides < 3 && polygon_sides != 0) { - fprintf(stderr, "polygon-sides must be greater then 2 or 0; ignoring...\n"); - polygon_sides = 0; - } + errx(EXIT_FAILURE, "polygon-sides must be a number\n"); + if (polygon_sides < 3) + errx(EXIT_FAILURE, "polygon-sides must be greater then 2 or 0\n"); break; case 405: arg = optarg; - if (sscanf(arg, "%lf", &polygon_offset) != 1) - errx(1, "polygon-offset must be a number\n"); - polygon_offset = polygon_offset * (M_PI / 180); + if (sscanf(arg, "%lf", &polygon_rotation) != 1) + errx(1, "polygon-rotation must be a number\n"); + polygon_rotation = polygon_rotation * (M_PI / 180); break; case 406: arg = optarg; diff --git a/unlock_indicator.c b/unlock_indicator.c index 8c61eca2..e9333713 100644 --- a/unlock_indicator.c +++ b/unlock_indicator.c @@ -249,7 +249,7 @@ extern bool bar_reversed; // Polygon indicator extern int polygon_sides; -extern double polygon_offset; +extern double polygon_rotation; extern int polygon_highlight; static cairo_font_face_t *font_faces[6] = { @@ -523,11 +523,21 @@ static void draw_bar(cairo_t *ctx, double bar_x, double bar_y, double bar_width, cairo_restore(ctx); } -void draw_polygon(cairo_t *ctx, double center_x, double center_y, double radius, int points, int start, int end, double offset) { +/* Draw some number of edges of a polygon + * center_x/center_y: The center of the polygon + * radius: The distance from the center to the vertices + * points: The number of verticies + * start/end: The index of the edges to draw. Settings start to 0 and end to + * points will draw the entire polygon. Edges are indexed counter + * clockwise around the polygon. + * angle_offset: How far offset clockwise the first vertex is from the positive + * x axis (radians). + */ +void draw_polygon(cairo_t *ctx, double center_x, double center_y, double radius, int points, int start, int end, double angle_offset) { int count = end - start; for (int v = 0; v < count + 1; v++) { - double theta = (start + v) * ((M_PI * 2) / points) + offset; + double theta = (start + v) * ((M_PI * 2) / points) + angle_offset; int x = radius * cos(theta); int y = radius * sin(theta); @@ -545,7 +555,7 @@ static void draw_indic(cairo_t *ctx, double ind_x, double ind_y) { /* Draw a (centered) circle with transparent background. */ cairo_set_line_width(ctx, RING_WIDTH); if (polygon_sides > 0) - draw_polygon(ctx, ind_x, ind_y, BUTTON_RADIUS, polygon_sides, 0, polygon_sides, polygon_offset); + draw_polygon(ctx, ind_x, ind_y, BUTTON_RADIUS, polygon_sides, 0, polygon_sides, polygon_rotation); else cairo_arc(ctx, ind_x, ind_y, BUTTON_RADIUS, 0, 2 * M_PI); @@ -618,7 +628,7 @@ static void draw_indic(cairo_t *ctx, double ind_x, double ind_y) { cairo_set_source_rgba(ctx, line16.red, line16.green, line16.blue, line16.alpha); cairo_set_line_width(ctx, 2.0); if (polygon_sides > 0) - draw_polygon(ctx, ind_x, ind_y, BUTTON_RADIUS - 5, polygon_sides, 0, polygon_sides, polygon_offset); + draw_polygon(ctx, ind_x, ind_y, BUTTON_RADIUS - 5, polygon_sides, 0, polygon_sides, polygon_rotation); else cairo_arc(ctx, ind_x, ind_y, BUTTON_RADIUS - 5, 0, 2 * M_PI); cairo_stroke(ctx); @@ -643,7 +653,7 @@ static void draw_indic(cairo_t *ctx, double ind_x, double ind_y) { highlight_start = input_position % polygon_sides; else if(polygon_highlight == 2) highlight_start = -input_position % polygon_sides; - draw_polygon(ctx, ind_x, ind_y, BUTTON_RADIUS, polygon_sides, highlight_start, highlight_start+1, polygon_offset); + draw_polygon(ctx, ind_x, ind_y, BUTTON_RADIUS, polygon_sides, highlight_start, highlight_start+1, polygon_rotation); cairo_stroke(ctx); return; }