diff options
Diffstat (limited to 'swaylock')
-rw-r--r-- | swaylock/main.c | 14 | ||||
-rw-r--r-- | swaylock/password.c | 20 | ||||
-rw-r--r-- | swaylock/render.c | 121 |
3 files changed, 147 insertions, 8 deletions
diff --git a/swaylock/main.c b/swaylock/main.c index c8fdc2f4..ce337e24 100644 --- a/swaylock/main.c +++ b/swaylock/main.c | |||
@@ -133,6 +133,7 @@ int main(int argc, char **argv) { | |||
133 | .color = 0xFFFFFFFF, | 133 | .color = 0xFFFFFFFF, |
134 | .show_indicator = true, | 134 | .show_indicator = true, |
135 | }; | 135 | }; |
136 | cairo_surface_t *background_image = NULL; | ||
136 | state.args = args; | 137 | state.args = args; |
137 | wlr_log_init(L_DEBUG, NULL); | 138 | wlr_log_init(L_DEBUG, NULL); |
138 | 139 | ||
@@ -150,8 +151,13 @@ int main(int argc, char **argv) { | |||
150 | break; | 151 | break; |
151 | } | 152 | } |
152 | case 'i': | 153 | case 'i': |
153 | // TODO | 154 | // TODO: Multiple background images (bleh) |
154 | return 1; | 155 | background_image = load_background_image(optarg); |
156 | if (!background_image) { | ||
157 | return 1; | ||
158 | } | ||
159 | state.args.mode = BACKGROUND_MODE_FILL; | ||
160 | break; | ||
155 | case 's': | 161 | case 's': |
156 | state.args.mode = parse_background_mode(optarg); | 162 | state.args.mode = parse_background_mode(optarg); |
157 | if (state.args.mode == BACKGROUND_MODE_INVALID) { | 163 | if (state.args.mode == BACKGROUND_MODE_INVALID) { |
@@ -159,7 +165,7 @@ int main(int argc, char **argv) { | |||
159 | } | 165 | } |
160 | break; | 166 | break; |
161 | case 't': | 167 | case 't': |
162 | // TODO | 168 | state.args.mode = BACKGROUND_MODE_TILE; |
163 | break; | 169 | break; |
164 | case 'v': | 170 | case 'v': |
165 | #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE | 171 | #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE |
@@ -197,6 +203,8 @@ int main(int argc, char **argv) { | |||
197 | 203 | ||
198 | struct swaylock_surface *surface; | 204 | struct swaylock_surface *surface; |
199 | wl_list_for_each(surface, &state.surfaces, link) { | 205 | wl_list_for_each(surface, &state.surfaces, link) { |
206 | surface->image = background_image; | ||
207 | |||
200 | assert(surface->surface = | 208 | assert(surface->surface = |
201 | wl_compositor_create_surface(state.compositor)); | 209 | wl_compositor_create_surface(state.compositor)); |
202 | 210 | ||
diff --git a/swaylock/password.c b/swaylock/password.c index 9af7fe16..2bdf151f 100644 --- a/swaylock/password.c +++ b/swaylock/password.c | |||
@@ -50,21 +50,23 @@ static bool attempt_password(struct swaylock_password *pw) { | |||
50 | wlr_log(L_ERROR, "pam_end failed"); | 50 | wlr_log(L_ERROR, "pam_end failed"); |
51 | goto fail; | 51 | goto fail; |
52 | } | 52 | } |
53 | // PAM freed this | 53 | // PAM frees this |
54 | pw->buffer = NULL; | 54 | pw->buffer = NULL; |
55 | pw->len = pw->size = 0; | 55 | pw->len = pw->size = 0; |
56 | return true; | 56 | return true; |
57 | fail: | 57 | fail: |
58 | // PAM freed this | 58 | // PAM frees this |
59 | pw->buffer = NULL; | 59 | pw->buffer = NULL; |
60 | pw->len = pw->size = 0; | 60 | pw->len = pw->size = 0; |
61 | return false; | 61 | return false; |
62 | } | 62 | } |
63 | 63 | ||
64 | static void backspace(struct swaylock_password *pw) { | 64 | static bool backspace(struct swaylock_password *pw) { |
65 | if (pw->len != 0) { | 65 | if (pw->len != 0) { |
66 | pw->buffer[--pw->len] = 0; | 66 | pw->buffer[--pw->len] = 0; |
67 | return true; | ||
67 | } | 68 | } |
69 | return false; | ||
68 | } | 70 | } |
69 | 71 | ||
70 | static void append_ch(struct swaylock_password *pw, uint32_t codepoint) { | 72 | static void append_ch(struct swaylock_password *pw, uint32_t codepoint) { |
@@ -97,17 +99,27 @@ void swaylock_handle_key(struct swaylock_state *state, | |||
97 | switch (keysym) { | 99 | switch (keysym) { |
98 | case XKB_KEY_KP_Enter: /* fallthrough */ | 100 | case XKB_KEY_KP_Enter: /* fallthrough */ |
99 | case XKB_KEY_Return: | 101 | case XKB_KEY_Return: |
102 | state->auth_state = AUTH_STATE_VALIDATING; | ||
103 | render_frames(state); | ||
100 | if (attempt_password(&state->password)) { | 104 | if (attempt_password(&state->password)) { |
101 | exit(0); | 105 | exit(0); |
102 | } | 106 | } |
107 | state->auth_state = AUTH_STATE_INVALID; | ||
108 | render_frames(state); | ||
103 | break; | 109 | break; |
104 | case XKB_KEY_BackSpace: | 110 | case XKB_KEY_BackSpace: |
105 | backspace(&state->password); | 111 | if (backspace(&state->password)) { |
112 | state->auth_state = AUTH_STATE_BACKSPACE; | ||
113 | render_frames(state); | ||
114 | } | ||
106 | break; | 115 | break; |
107 | default: | 116 | default: |
108 | if (codepoint) { | 117 | if (codepoint) { |
109 | append_ch(&state->password, codepoint); | 118 | append_ch(&state->password, codepoint); |
119 | state->auth_state = AUTH_STATE_INPUT; | ||
120 | render_frames(state); | ||
110 | } | 121 | } |
111 | break; | 122 | break; |
112 | } | 123 | } |
124 | // TODO: Expire state in a few seconds | ||
113 | } | 125 | } |
diff --git a/swaylock/render.c b/swaylock/render.c index 8fc47281..90db71e3 100644 --- a/swaylock/render.c +++ b/swaylock/render.c | |||
@@ -1,21 +1,140 @@ | |||
1 | #include <wayland-client.h> | 1 | #include <wayland-client.h> |
2 | #include <math.h> | ||
2 | #include "cairo.h" | 3 | #include "cairo.h" |
3 | #include "background-image.h" | 4 | #include "background-image.h" |
4 | #include "swaylock/swaylock.h" | 5 | #include "swaylock/swaylock.h" |
5 | 6 | ||
7 | #define M_PI 3.14159265358979323846 | ||
8 | |||
6 | void render_frame(struct swaylock_surface *surface) { | 9 | void render_frame(struct swaylock_surface *surface) { |
7 | struct swaylock_state *state = surface->state; | 10 | struct swaylock_state *state = surface->state; |
8 | surface->current_buffer = get_next_buffer(state->shm, | 11 | surface->current_buffer = get_next_buffer(state->shm, |
9 | surface->buffers, surface->width, surface->height); | 12 | surface->buffers, surface->width, surface->height); |
10 | cairo_t *cairo = surface->current_buffer->cairo; | 13 | cairo_t *cairo = surface->current_buffer->cairo; |
14 | cairo_identity_matrix(cairo); | ||
11 | if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR) { | 15 | if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR) { |
12 | cairo_set_source_u32(cairo, state->args.color); | 16 | cairo_set_source_u32(cairo, state->args.color); |
13 | cairo_paint(cairo); | 17 | cairo_paint(cairo); |
14 | } else { | 18 | } else { |
19 | // TODO: hidpi | ||
15 | render_background_image(cairo, surface->image, | 20 | render_background_image(cairo, surface->image, |
16 | state->args.mode, surface->width, surface->height); | 21 | state->args.mode, surface->width, surface->height, 1); |
22 | } | ||
23 | cairo_identity_matrix(cairo); | ||
24 | |||
25 | const int ARC_RADIUS = 50; | ||
26 | const int ARC_THICKNESS = 10; | ||
27 | const float TYPE_INDICATOR_RANGE = M_PI / 3.0f; | ||
28 | const float TYPE_INDICATOR_BORDER_THICKNESS = M_PI / 128.0f; | ||
29 | if (state->args.show_indicator && state->auth_state != AUTH_STATE_IDLE) { | ||
30 | // Draw circle | ||
31 | cairo_set_line_width(cairo, ARC_THICKNESS); | ||
32 | cairo_arc(cairo, surface->width / 2, surface->height / 2, | ||
33 | ARC_RADIUS, 0, 2 * M_PI); | ||
34 | switch (state->auth_state) { | ||
35 | case AUTH_STATE_INPUT: | ||
36 | case AUTH_STATE_BACKSPACE: { | ||
37 | cairo_set_source_rgba(cairo, 0, 0, 0, 0.75); | ||
38 | cairo_fill_preserve(cairo); | ||
39 | cairo_set_source_rgb(cairo, 51.0 / 255, 125.0 / 255, 0); | ||
40 | cairo_stroke(cairo); | ||
41 | } break; | ||
42 | case AUTH_STATE_VALIDATING: { | ||
43 | cairo_set_source_rgba(cairo, 0, 114.0 / 255, 255.0 / 255, 0.75); | ||
44 | cairo_fill_preserve(cairo); | ||
45 | cairo_set_source_rgb(cairo, 51.0 / 255, 0, 250.0 / 255); | ||
46 | cairo_stroke(cairo); | ||
47 | } break; | ||
48 | case AUTH_STATE_INVALID: { | ||
49 | cairo_set_source_rgba(cairo, 250.0 / 255, 0, 0, 0.75); | ||
50 | cairo_fill_preserve(cairo); | ||
51 | cairo_set_source_rgb(cairo, 125.0 / 255, 51.0 / 255, 0); | ||
52 | cairo_stroke(cairo); | ||
53 | } break; | ||
54 | default: break; | ||
55 | } | ||
56 | |||
57 | // Draw a message | ||
58 | char *text = NULL; | ||
59 | cairo_set_source_rgb(cairo, 0, 0, 0); | ||
60 | cairo_select_font_face(cairo, "sans-serif", | ||
61 | CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); | ||
62 | cairo_set_font_size(cairo, ARC_RADIUS / 3.0f); | ||
63 | switch (state->auth_state) { | ||
64 | case AUTH_STATE_VALIDATING: | ||
65 | text = "verifying"; | ||
66 | break; | ||
67 | case AUTH_STATE_INVALID: | ||
68 | text = "wrong"; | ||
69 | break; | ||
70 | default: break; | ||
71 | } | ||
72 | |||
73 | if (text) { | ||
74 | cairo_text_extents_t extents; | ||
75 | double x, y; | ||
76 | cairo_text_extents(cairo, text, &extents); | ||
77 | x = (surface->width / 2) - | ||
78 | (extents.width / 2 + extents.x_bearing); | ||
79 | y = (surface->height / 2) - | ||
80 | (extents.height / 2 + extents.y_bearing); | ||
81 | |||
82 | cairo_move_to(cairo, x, y); | ||
83 | cairo_show_text(cairo, text); | ||
84 | cairo_close_path(cairo); | ||
85 | cairo_new_sub_path(cairo); | ||
86 | } | ||
87 | |||
88 | // Typing indicator: Highlight random part on keypress | ||
89 | if (state->auth_state == AUTH_STATE_INPUT | ||
90 | || state->auth_state == AUTH_STATE_BACKSPACE) { | ||
91 | static double highlight_start = 0; | ||
92 | highlight_start += | ||
93 | (rand() % (int)(M_PI * 100)) / 100.0 + M_PI * 0.5; | ||
94 | cairo_arc(cairo, surface->width / 2, surface->height / 2, | ||
95 | ARC_RADIUS, highlight_start, | ||
96 | highlight_start + TYPE_INDICATOR_RANGE); | ||
97 | if (state->auth_state == AUTH_STATE_INPUT) { | ||
98 | cairo_set_source_rgb(cairo, 51.0 / 255, 219.0 / 255, 0); | ||
99 | } else { | ||
100 | cairo_set_source_rgb(cairo, 219.0 / 255, 51.0 / 255, 0); | ||
101 | } | ||
102 | cairo_stroke(cairo); | ||
103 | |||
104 | // Draw borders | ||
105 | cairo_set_source_rgb(cairo, 0, 0, 0); | ||
106 | cairo_arc(cairo, surface->width / 2, surface->height / 2, | ||
107 | ARC_RADIUS, highlight_start, | ||
108 | highlight_start + TYPE_INDICATOR_BORDER_THICKNESS); | ||
109 | cairo_stroke(cairo); | ||
110 | |||
111 | cairo_arc(cairo, surface->width / 2, surface->height / 2, | ||
112 | ARC_RADIUS, highlight_start + TYPE_INDICATOR_RANGE, | ||
113 | highlight_start + TYPE_INDICATOR_RANGE + | ||
114 | TYPE_INDICATOR_BORDER_THICKNESS); | ||
115 | cairo_stroke(cairo); | ||
116 | } | ||
117 | |||
118 | // Draw inner + outer border of the circle | ||
119 | cairo_set_source_rgb(cairo, 0, 0, 0); | ||
120 | cairo_set_line_width(cairo, 2.0); | ||
121 | cairo_arc(cairo, surface->width / 2, surface->height / 2, | ||
122 | ARC_RADIUS - ARC_THICKNESS / 2, 0, 2 * M_PI); | ||
123 | cairo_stroke(cairo); | ||
124 | cairo_arc(cairo, surface->width / 2, surface->height / 2, | ||
125 | ARC_RADIUS + ARC_THICKNESS / 2, 0, 2 * M_PI); | ||
126 | cairo_stroke(cairo); | ||
17 | } | 127 | } |
128 | |||
18 | wl_surface_attach(surface->surface, surface->current_buffer->buffer, 0, 0); | 129 | wl_surface_attach(surface->surface, surface->current_buffer->buffer, 0, 0); |
19 | wl_surface_damage(surface->surface, 0, 0, surface->width, surface->height); | 130 | wl_surface_damage(surface->surface, 0, 0, surface->width, surface->height); |
20 | wl_surface_commit(surface->surface); | 131 | wl_surface_commit(surface->surface); |
132 | wl_display_roundtrip(state->display); | ||
133 | } | ||
134 | |||
135 | void render_frames(struct swaylock_state *state) { | ||
136 | struct swaylock_surface *surface; | ||
137 | wl_list_for_each(surface, &state->surfaces, link) { | ||
138 | render_frame(surface); | ||
139 | } | ||
21 | } | 140 | } |