|
|
@ -20,11 +20,12 @@ |
|
|
|
|
|
|
|
#include "xcb.h" |
|
|
|
#include "unlock_indicator.h" |
|
|
|
#include "xinerama.h" |
|
|
|
|
|
|
|
#define BUTTON_RADIUS 90 |
|
|
|
#define BUTTON_SPACE (BUTTON_RADIUS + 5) |
|
|
|
#define BUTTON_CENTER (BUTTON_RADIUS + 5) |
|
|
|
#define BUTTON_DIAMETER (5 * BUTTON_SPACE) |
|
|
|
#define BUTTON_DIAMETER (2 * BUTTON_SPACE) |
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* Variables defined in i3lock.c. |
|
|
@ -79,51 +80,47 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { |
|
|
|
if (!vistype) |
|
|
|
vistype = get_root_visual_type(screen); |
|
|
|
bg_pixmap = create_bg_pixmap(conn, screen, resolution, color); |
|
|
|
/* Initialize cairo */ |
|
|
|
cairo_surface_t *output; |
|
|
|
output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, |
|
|
|
resolution[0], resolution[1]); |
|
|
|
/* Initialize cairo: Create one in-memory surface to render the unlock
|
|
|
|
* indicator on, create one XCB surface to actually draw (one or more, |
|
|
|
* depending on the amount of screens) unlock indicators on. */ |
|
|
|
cairo_surface_t *output = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, BUTTON_DIAMETER, BUTTON_DIAMETER); |
|
|
|
cairo_t *ctx = cairo_create(output); |
|
|
|
|
|
|
|
cairo_surface_t *xcb_output = cairo_xcb_surface_create(conn, bg_pixmap, vistype, resolution[0], resolution[1]); |
|
|
|
cairo_t *xcb_ctx = cairo_create(xcb_output); |
|
|
|
|
|
|
|
if (img) { |
|
|
|
if (!tile) { |
|
|
|
cairo_set_source_surface(ctx, img, 0, 0); |
|
|
|
cairo_paint(ctx); |
|
|
|
cairo_set_source_surface(xcb_ctx, img, 0, 0); |
|
|
|
cairo_paint(xcb_ctx); |
|
|
|
} else { |
|
|
|
/* create a pattern and fill a rectangle as big as the screen */ |
|
|
|
cairo_pattern_t *pattern; |
|
|
|
pattern = cairo_pattern_create_for_surface(img); |
|
|
|
cairo_set_source(ctx, pattern); |
|
|
|
cairo_set_source(xcb_ctx, pattern); |
|
|
|
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); |
|
|
|
cairo_rectangle(ctx, 0, 0, resolution[0], resolution[1]); |
|
|
|
cairo_fill(ctx); |
|
|
|
cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); |
|
|
|
cairo_fill(xcb_ctx); |
|
|
|
cairo_pattern_destroy(pattern); |
|
|
|
} |
|
|
|
} else { |
|
|
|
char strgroups[3][3] = {{color[0], color[1], '\0'}, |
|
|
|
{color[2], color[3], '\0'}, |
|
|
|
{color[4], color[5], '\0'}}; |
|
|
|
uint32_t rgb16[3] = {(strtol(strgroups[0], NULL, 16)), |
|
|
|
(strtol(strgroups[1], NULL, 16)), |
|
|
|
(strtol(strgroups[2], NULL, 16))}; |
|
|
|
cairo_set_source_rgb(xcb_ctx, rgb16[0], rgb16[1], rgb16[2]); |
|
|
|
cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); |
|
|
|
cairo_fill(xcb_ctx); |
|
|
|
} |
|
|
|
|
|
|
|
if (unlock_state >= STATE_KEY_PRESSED && unlock_indicator) { |
|
|
|
cairo_pattern_t *outer_pat = NULL; |
|
|
|
|
|
|
|
outer_pat = cairo_pattern_create_linear(0, 0, 0, BUTTON_DIAMETER); |
|
|
|
switch (pam_state) { |
|
|
|
case STATE_PAM_VERIFY: |
|
|
|
cairo_pattern_add_color_stop_rgb(outer_pat, 0, 139.0/255, 0, 250.0/255); |
|
|
|
cairo_pattern_add_color_stop_rgb(outer_pat, 1, 51.0/255, 0, 250.0/255); |
|
|
|
break; |
|
|
|
case STATE_PAM_WRONG: |
|
|
|
cairo_pattern_add_color_stop_rgb(outer_pat, 0, 255.0/250, 139.0/255, 0); |
|
|
|
cairo_pattern_add_color_stop_rgb(outer_pat, 1, 125.0/255, 51.0/255, 0); |
|
|
|
break; |
|
|
|
case STATE_PAM_IDLE: |
|
|
|
cairo_pattern_add_color_stop_rgb(outer_pat, 0, 139.0/255, 125.0/255, 0); |
|
|
|
cairo_pattern_add_color_stop_rgb(outer_pat, 1, 51.0/255, 125.0/255, 0); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
/* Draw a (centered) circle with transparent background. */ |
|
|
|
cairo_set_line_width(ctx, 10.0); |
|
|
|
cairo_arc(ctx, |
|
|
|
(resolution[0] / 2) /* x */, |
|
|
|
(resolution[1] / 2) /* y */, |
|
|
|
BUTTON_CENTER /* x */, |
|
|
|
BUTTON_CENTER /* y */, |
|
|
|
BUTTON_RADIUS /* radius */, |
|
|
|
0 /* start */, |
|
|
|
2 * M_PI /* end */); |
|
|
@ -142,17 +139,26 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { |
|
|
|
break; |
|
|
|
} |
|
|
|
cairo_fill_preserve(ctx); |
|
|
|
cairo_set_source(ctx, outer_pat); |
|
|
|
cairo_stroke(ctx); |
|
|
|
|
|
|
|
cairo_pattern_destroy(outer_pat); |
|
|
|
switch (pam_state) { |
|
|
|
case STATE_PAM_VERIFY: |
|
|
|
cairo_set_source_rgb(ctx, 51.0/255, 0, 250.0/255); |
|
|
|
break; |
|
|
|
case STATE_PAM_WRONG: |
|
|
|
cairo_set_source_rgb(ctx, 125.0/255, 51.0/255, 0); |
|
|
|
break; |
|
|
|
case STATE_PAM_IDLE: |
|
|
|
cairo_set_source_rgb(ctx, 51.0/255, 125.0/255, 0); |
|
|
|
break; |
|
|
|
} |
|
|
|
cairo_stroke(ctx); |
|
|
|
|
|
|
|
/* Draw an inner seperator line. */ |
|
|
|
cairo_set_source_rgb(ctx, 0, 0, 0); |
|
|
|
cairo_set_line_width(ctx, 2.0); |
|
|
|
cairo_arc(ctx, |
|
|
|
(resolution[0] / 2) /* x */, |
|
|
|
(resolution[1] / 2) /* y */, |
|
|
|
BUTTON_CENTER /* x */, |
|
|
|
BUTTON_CENTER /* y */, |
|
|
|
BUTTON_RADIUS - 5 /* radius */, |
|
|
|
0, |
|
|
|
2 * M_PI); |
|
|
@ -181,8 +187,8 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { |
|
|
|
cairo_set_font_size(ctx, 28.0); |
|
|
|
|
|
|
|
cairo_text_extents(ctx, text, &extents); |
|
|
|
x = (resolution[0] / 2.0) - ((extents.width / 2) + extents.x_bearing); |
|
|
|
y = (resolution[1] / 2.0) - ((extents.height / 2) + extents.y_bearing); |
|
|
|
x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing); |
|
|
|
y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing); |
|
|
|
|
|
|
|
cairo_move_to(ctx, x, y); |
|
|
|
cairo_show_text(ctx, text); |
|
|
@ -196,46 +202,65 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { |
|
|
|
unlock_state == STATE_BACKSPACE_ACTIVE) { |
|
|
|
cairo_new_sub_path(ctx); |
|
|
|
double highlight_start = (rand() % (int)(2 * M_PI * 100)) / 100.0; |
|
|
|
cairo_arc(ctx, resolution[0] / 2 /* x */, resolution[1] / 2 /* y */, |
|
|
|
BUTTON_RADIUS /* radius */, highlight_start, |
|
|
|
cairo_arc(ctx, |
|
|
|
BUTTON_CENTER /* x */, |
|
|
|
BUTTON_CENTER /* y */, |
|
|
|
BUTTON_RADIUS /* radius */, |
|
|
|
highlight_start, |
|
|
|
highlight_start + (M_PI / 3.0)); |
|
|
|
if (unlock_state == STATE_KEY_ACTIVE) { |
|
|
|
/* For normal keys, we use a lighter green. */ |
|
|
|
outer_pat = cairo_pattern_create_linear(0, 0, 0, BUTTON_DIAMETER); |
|
|
|
cairo_pattern_add_color_stop_rgb(outer_pat, 0, 139.0/255, 219.0/255, 0); |
|
|
|
cairo_pattern_add_color_stop_rgb(outer_pat, 1, 51.0/255, 219.0/255, 0); |
|
|
|
cairo_set_source_rgb(ctx, 51.0/255, 219.0/255, 0); |
|
|
|
} else { |
|
|
|
/* For backspace, we use red. */ |
|
|
|
outer_pat = cairo_pattern_create_linear(0, 0, 0, BUTTON_DIAMETER); |
|
|
|
cairo_pattern_add_color_stop_rgb(outer_pat, 0, 219.0/255, 139.0/255, 0); |
|
|
|
cairo_pattern_add_color_stop_rgb(outer_pat, 1, 219.0/255, 51.0/255, 0); |
|
|
|
cairo_set_source_rgb(ctx, 219.0/255, 51.0/255, 0); |
|
|
|
} |
|
|
|
cairo_set_source(ctx, outer_pat); |
|
|
|
cairo_stroke(ctx); |
|
|
|
|
|
|
|
/* Draw two little separators for the highlighted part of the
|
|
|
|
* unlock indicator. */ |
|
|
|
cairo_set_source_rgb(ctx, 0, 0, 0); |
|
|
|
cairo_arc(ctx, |
|
|
|
(resolution[0] / 2) /* x */, |
|
|
|
(resolution[1] / 2) /* y */, |
|
|
|
BUTTON_CENTER /* x */, |
|
|
|
BUTTON_CENTER /* y */, |
|
|
|
BUTTON_RADIUS /* radius */, |
|
|
|
highlight_start /* start */, |
|
|
|
highlight_start + (M_PI / 128.0) /* end */); |
|
|
|
cairo_stroke(ctx); |
|
|
|
cairo_arc(ctx, |
|
|
|
(resolution[0] / 2) /* x */, |
|
|
|
(resolution[1] / 2) /* y */, |
|
|
|
BUTTON_CENTER /* x */, |
|
|
|
BUTTON_CENTER /* y */, |
|
|
|
BUTTON_RADIUS /* radius */, |
|
|
|
highlight_start + (M_PI / 3.0) /* start */, |
|
|
|
(highlight_start + (M_PI / 3.0)) + (M_PI / 128.0) /* end */); |
|
|
|
cairo_stroke(ctx); |
|
|
|
cairo_pattern_destroy(outer_pat); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (xr_screens > 0) { |
|
|
|
/* Composite the unlock indicator in the middle of each screen. */ |
|
|
|
for (int screen = 0; screen < xr_screens; screen++) { |
|
|
|
int x = (xr_resolutions[screen].x + ((xr_resolutions[screen].width / 2) - (BUTTON_DIAMETER / 2))); |
|
|
|
int y = (xr_resolutions[screen].y + ((xr_resolutions[screen].height / 2) - (BUTTON_DIAMETER / 2))); |
|
|
|
cairo_set_source_surface(xcb_ctx, output, x, y); |
|
|
|
cairo_rectangle(xcb_ctx, x, y, BUTTON_DIAMETER, BUTTON_DIAMETER); |
|
|
|
cairo_fill(xcb_ctx); |
|
|
|
} |
|
|
|
} else { |
|
|
|
/* We have no information about the screen sizes/positions, so we just
|
|
|
|
* place the unlock indicator in the middle of the X root window and |
|
|
|
* hope for the best. */ |
|
|
|
int x = (last_resolution[0] / 2); |
|
|
|
int y = (last_resolution[1] / 2); |
|
|
|
cairo_set_source_surface(xcb_ctx, output, x, y); |
|
|
|
cairo_rectangle(xcb_ctx, x, y, BUTTON_DIAMETER, BUTTON_DIAMETER); |
|
|
|
cairo_fill(xcb_ctx); |
|
|
|
} |
|
|
|
|
|
|
|
cairo_surface_destroy(xcb_output); |
|
|
|
cairo_surface_destroy(output); |
|
|
|
cairo_destroy(ctx); |
|
|
|
cairo_destroy(xcb_ctx); |
|
|
|
#endif |
|
|
|
return bg_pixmap; |
|
|
|
} |
|
|
|