diff options
-rw-r--r-- | include/swaylock/swaylock.h | 12 | ||||
-rw-r--r-- | meson.build | 2 | ||||
-rw-r--r-- | protocols/meson.build | 6 | ||||
-rw-r--r-- | swaylock/main.c | 155 | ||||
-rw-r--r-- | swaylock/render.c | 2 |
5 files changed, 153 insertions, 24 deletions
diff --git a/include/swaylock/swaylock.h b/include/swaylock/swaylock.h index 07b908d7..e161ada9 100644 --- a/include/swaylock/swaylock.h +++ b/include/swaylock/swaylock.h | |||
@@ -37,23 +37,35 @@ struct swaylock_state { | |||
37 | struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager; | 37 | struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager; |
38 | struct wl_shm *shm; | 38 | struct wl_shm *shm; |
39 | struct wl_list surfaces; | 39 | struct wl_list surfaces; |
40 | struct wl_list images; | ||
40 | struct swaylock_args args; | 41 | struct swaylock_args args; |
41 | struct swaylock_password password; | 42 | struct swaylock_password password; |
42 | struct swaylock_xkb xkb; | 43 | struct swaylock_xkb xkb; |
43 | enum auth_state auth_state; | 44 | enum auth_state auth_state; |
44 | bool run_display; | 45 | bool run_display; |
46 | struct zxdg_output_manager_v1 *zxdg_output_manager; | ||
45 | }; | 47 | }; |
46 | 48 | ||
47 | struct swaylock_surface { | 49 | struct swaylock_surface { |
48 | cairo_surface_t *image; | 50 | cairo_surface_t *image; |
49 | struct swaylock_state *state; | 51 | struct swaylock_state *state; |
50 | struct wl_output *output; | 52 | struct wl_output *output; |
53 | struct zxdg_output_v1 *xdg_output; | ||
51 | struct wl_surface *surface; | 54 | struct wl_surface *surface; |
52 | struct zwlr_layer_surface_v1 *layer_surface; | 55 | struct zwlr_layer_surface_v1 *layer_surface; |
53 | struct pool_buffer buffers[2]; | 56 | struct pool_buffer buffers[2]; |
54 | struct pool_buffer *current_buffer; | 57 | struct pool_buffer *current_buffer; |
55 | uint32_t width, height; | 58 | uint32_t width, height; |
56 | int32_t scale; | 59 | int32_t scale; |
60 | char *output_name; | ||
61 | struct wl_list link; | ||
62 | }; | ||
63 | |||
64 | // There is exactly one swaylock_image for each -i argument | ||
65 | struct swaylock_image { | ||
66 | char *path; | ||
67 | char *output_name; | ||
68 | cairo_surface_t *cairo_surface; | ||
57 | struct wl_list link; | 69 | struct wl_list link; |
58 | }; | 70 | }; |
59 | 71 | ||
diff --git a/meson.build b/meson.build index b943236f..d4ee1a11 100644 --- a/meson.build +++ b/meson.build | |||
@@ -29,7 +29,7 @@ wayland_server = dependency('wayland-server') | |||
29 | wayland_client = dependency('wayland-client') | 29 | wayland_client = dependency('wayland-client') |
30 | wayland_cursor = dependency('wayland-cursor') | 30 | wayland_cursor = dependency('wayland-cursor') |
31 | wayland_egl = dependency('wayland-egl') | 31 | wayland_egl = dependency('wayland-egl') |
32 | wayland_protos = dependency('wayland-protocols') | 32 | wayland_protos = dependency('wayland-protocols', version: '>=1.14') |
33 | xkbcommon = dependency('xkbcommon') | 33 | xkbcommon = dependency('xkbcommon') |
34 | cairo = dependency('cairo') | 34 | cairo = dependency('cairo') |
35 | pango = dependency('pango') | 35 | pango = dependency('pango') |
diff --git a/protocols/meson.build b/protocols/meson.build index 9966c02f..a031245c 100644 --- a/protocols/meson.build +++ b/protocols/meson.build | |||
@@ -29,16 +29,18 @@ wayland_scanner_server = generator( | |||
29 | 29 | ||
30 | client_protocols = [ | 30 | client_protocols = [ |
31 | [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], | 31 | [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], |
32 | [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], | ||
32 | ['wlr-layer-shell-unstable-v1.xml'], | 33 | ['wlr-layer-shell-unstable-v1.xml'], |
33 | ['idle.xml'], | 34 | ['idle.xml'], |
34 | ['wlr-input-inhibitor-unstable-v1.xml'] | 35 | ['wlr-input-inhibitor-unstable-v1.xml'], |
35 | ] | 36 | ] |
36 | 37 | ||
37 | server_protocols = [ | 38 | server_protocols = [ |
38 | [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], | 39 | [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], |
39 | [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], | 40 | [wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'], |
41 | [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], | ||
40 | ['wlr-layer-shell-unstable-v1.xml'], | 42 | ['wlr-layer-shell-unstable-v1.xml'], |
41 | ['wlr-input-inhibitor-unstable-v1.xml'] | 43 | ['wlr-input-inhibitor-unstable-v1.xml'], |
42 | ] | 44 | ] |
43 | 45 | ||
44 | client_protos_src = [] | 46 | client_protos_src = [] |
diff --git a/swaylock/main.c b/swaylock/main.c index 200c1b5f..11b5e8c8 100644 --- a/swaylock/main.c +++ b/swaylock/main.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <time.h> | 13 | #include <time.h> |
14 | #include <unistd.h> | 14 | #include <unistd.h> |
15 | #include <wayland-client.h> | 15 | #include <wayland-client.h> |
16 | #include <wordexp.h> | ||
16 | #include <wlr/util/log.h> | 17 | #include <wlr/util/log.h> |
17 | #include "swaylock/seat.h" | 18 | #include "swaylock/seat.h" |
18 | #include "swaylock/swaylock.h" | 19 | #include "swaylock/swaylock.h" |
@@ -20,9 +21,11 @@ | |||
20 | #include "pool-buffer.h" | 21 | #include "pool-buffer.h" |
21 | #include "cairo.h" | 22 | #include "cairo.h" |
22 | #include "log.h" | 23 | #include "log.h" |
24 | #include "stringop.h" | ||
23 | #include "util.h" | 25 | #include "util.h" |
24 | #include "wlr-input-inhibitor-unstable-v1-client-protocol.h" | 26 | #include "wlr-input-inhibitor-unstable-v1-client-protocol.h" |
25 | #include "wlr-layer-shell-unstable-v1-client-protocol.h" | 27 | #include "wlr-layer-shell-unstable-v1-client-protocol.h" |
28 | #include "xdg-output-unstable-v1-client-protocol.h" | ||
26 | 29 | ||
27 | void sway_terminate(int exit_code) { | 30 | void sway_terminate(int exit_code) { |
28 | exit(exit_code); | 31 | exit(exit_code); |
@@ -84,22 +87,23 @@ static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { | |||
84 | .closed = layer_surface_closed, | 87 | .closed = layer_surface_closed, |
85 | }; | 88 | }; |
86 | 89 | ||
87 | static void output_geometry(void *data, struct wl_output *output, int32_t x, | 90 | static void handle_wl_output_geometry(void *data, struct wl_output *output, int32_t x, |
88 | int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, | 91 | int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, |
89 | const char *make, const char *model, int32_t transform) { | 92 | const char *make, const char *model, int32_t transform) { |
90 | // Who cares | 93 | // Who cares |
91 | } | 94 | } |
92 | 95 | ||
93 | static void output_mode(void *data, struct wl_output *output, uint32_t flags, | 96 | static void handle_wl_output_mode(void *data, struct wl_output *output, uint32_t flags, |
94 | int32_t width, int32_t height, int32_t refresh) { | 97 | int32_t width, int32_t height, int32_t refresh) { |
95 | // Who cares | 98 | // Who cares |
96 | } | 99 | } |
97 | 100 | ||
98 | static void output_done(void *data, struct wl_output *output) { | 101 | static void handle_wl_output_done(void *data, struct wl_output *output) { |
99 | // Who cares | 102 | // Who cares |
100 | } | 103 | } |
101 | 104 | ||
102 | static void output_scale(void *data, struct wl_output *output, int32_t factor) { | 105 | static void handle_wl_output_scale(void *data, struct wl_output *output, |
106 | int32_t factor) { | ||
103 | struct swaylock_surface *surface = data; | 107 | struct swaylock_surface *surface = data; |
104 | surface->scale = factor; | 108 | surface->scale = factor; |
105 | if (surface->state->run_display) { | 109 | if (surface->state->run_display) { |
@@ -107,11 +111,46 @@ static void output_scale(void *data, struct wl_output *output, int32_t factor) { | |||
107 | } | 111 | } |
108 | } | 112 | } |
109 | 113 | ||
110 | struct wl_output_listener output_listener = { | 114 | struct wl_output_listener _wl_output_listener = { |
111 | .geometry = output_geometry, | 115 | .geometry = handle_wl_output_geometry, |
112 | .mode = output_mode, | 116 | .mode = handle_wl_output_mode, |
113 | .done = output_done, | 117 | .done = handle_wl_output_done, |
114 | .scale = output_scale, | 118 | .scale = handle_wl_output_scale, |
119 | }; | ||
120 | |||
121 | static void handle_xdg_output_logical_size(void *data, struct zxdg_output_v1 *output, | ||
122 | int width, int height) { | ||
123 | // Who cares | ||
124 | } | ||
125 | |||
126 | static void handle_xdg_output_logical_position(void *data, | ||
127 | struct zxdg_output_v1 *output, int x, int y) { | ||
128 | // Who cares | ||
129 | } | ||
130 | |||
131 | static void handle_xdg_output_name(void *data, struct zxdg_output_v1 *output, | ||
132 | const char *name) { | ||
133 | wlr_log(L_DEBUG, "output name is %s", name); | ||
134 | struct swaylock_surface *surface = data; | ||
135 | surface->xdg_output = output; | ||
136 | surface->output_name = strdup(name); | ||
137 | } | ||
138 | |||
139 | static void handle_xdg_output_description(void *data, struct zxdg_output_v1 *output, | ||
140 | const char *description) { | ||
141 | // Who cares | ||
142 | } | ||
143 | |||
144 | static void handle_xdg_output_done(void *data, struct zxdg_output_v1 *output) { | ||
145 | // Who cares | ||
146 | } | ||
147 | |||
148 | struct zxdg_output_v1_listener _xdg_output_listener = { | ||
149 | .logical_position = handle_xdg_output_logical_position, | ||
150 | .logical_size = handle_xdg_output_logical_size, | ||
151 | .done = handle_xdg_output_done, | ||
152 | .name = handle_xdg_output_name, | ||
153 | .description = handle_xdg_output_description, | ||
115 | }; | 154 | }; |
116 | 155 | ||
117 | static void handle_global(void *data, struct wl_registry *registry, | 156 | static void handle_global(void *data, struct wl_registry *registry, |
@@ -133,13 +172,16 @@ static void handle_global(void *data, struct wl_registry *registry, | |||
133 | } else if (strcmp(interface, zwlr_input_inhibit_manager_v1_interface.name) == 0) { | 172 | } else if (strcmp(interface, zwlr_input_inhibit_manager_v1_interface.name) == 0) { |
134 | state->input_inhibit_manager = wl_registry_bind( | 173 | state->input_inhibit_manager = wl_registry_bind( |
135 | registry, name, &zwlr_input_inhibit_manager_v1_interface, 1); | 174 | registry, name, &zwlr_input_inhibit_manager_v1_interface, 1); |
175 | } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) { | ||
176 | state->zxdg_output_manager = wl_registry_bind( | ||
177 | registry, name, &zxdg_output_manager_v1_interface, 2); | ||
136 | } else if (strcmp(interface, wl_output_interface.name) == 0) { | 178 | } else if (strcmp(interface, wl_output_interface.name) == 0) { |
137 | struct swaylock_surface *surface = | 179 | struct swaylock_surface *surface = |
138 | calloc(1, sizeof(struct swaylock_surface)); | 180 | calloc(1, sizeof(struct swaylock_surface)); |
139 | surface->state = state; | 181 | surface->state = state; |
140 | surface->output = wl_registry_bind(registry, name, | 182 | surface->output = wl_registry_bind(registry, name, |
141 | &wl_output_interface, 3); | 183 | &wl_output_interface, 3); |
142 | wl_output_add_listener(surface->output, &output_listener, surface); | 184 | wl_output_add_listener(surface->output, &_wl_output_listener, surface); |
143 | wl_list_insert(&state->surfaces, &surface->link); | 185 | wl_list_insert(&state->surfaces, &surface->link); |
144 | } | 186 | } |
145 | } | 187 | } |
@@ -154,6 +196,70 @@ static const struct wl_registry_listener registry_listener = { | |||
154 | .global_remove = handle_global_remove, | 196 | .global_remove = handle_global_remove, |
155 | }; | 197 | }; |
156 | 198 | ||
199 | static cairo_surface_t *select_image(struct swaylock_state *state, | ||
200 | struct swaylock_surface *surface) { | ||
201 | struct swaylock_image *image; | ||
202 | cairo_surface_t *default_image = NULL; | ||
203 | wl_list_for_each(image, &state->images, link) { | ||
204 | if (lenient_strcmp(image->output_name, surface->output_name) == 0) { | ||
205 | return image->cairo_surface; | ||
206 | } else if (!image->output_name) { | ||
207 | default_image = image->cairo_surface; | ||
208 | } | ||
209 | } | ||
210 | return default_image; | ||
211 | } | ||
212 | |||
213 | static void load_image(char *arg, struct swaylock_state *state) { | ||
214 | // [<output>:]<path> | ||
215 | struct swaylock_image *image = calloc(1, sizeof(struct swaylock_image)); | ||
216 | char *separator = strchr(arg, ':'); | ||
217 | if (separator) { | ||
218 | *separator = '\0'; | ||
219 | image->output_name = strdup(arg); | ||
220 | image->path = strdup(separator + 1); | ||
221 | } else { | ||
222 | image->output_name = NULL; | ||
223 | image->path = strdup(arg); | ||
224 | } | ||
225 | |||
226 | bool exists = false; | ||
227 | struct swaylock_image *iter_image; | ||
228 | wl_list_for_each(iter_image, &state->images, link) { | ||
229 | if (lenient_strcmp(iter_image->output_name, image->output_name) == 0) { | ||
230 | exists = true; | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | if (exists) { | ||
235 | if (image->output_name) { | ||
236 | wlr_log(L_ERROR, "Multiple images defined for output %s", | ||
237 | image->output_name); | ||
238 | } else { | ||
239 | wlr_log(L_ERROR, "Multiple default images defined"); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | // Bash doesn't replace the ~ with $HOME if the output name is supplied | ||
244 | wordexp_t p; | ||
245 | if (wordexp(image->path, &p, 0) == 0) { | ||
246 | free(image->path); | ||
247 | image->path = strdup(p.we_wordv[0]); | ||
248 | wordfree(&p); | ||
249 | } | ||
250 | |||
251 | // Load the actual image | ||
252 | image->cairo_surface = load_background_image(image->path); | ||
253 | if (!image->cairo_surface) { | ||
254 | free(image); | ||
255 | return; | ||
256 | } | ||
257 | wl_list_insert(&state->images, &image->link); | ||
258 | state->args.mode = BACKGROUND_MODE_FILL; | ||
259 | wlr_log(L_DEBUG, "Loaded image %s for output %s", | ||
260 | image->path, image->output_name ? image->output_name : "*"); | ||
261 | } | ||
262 | |||
157 | static struct swaylock_state state; | 263 | static struct swaylock_state state; |
158 | 264 | ||
159 | int main(int argc, char **argv) { | 265 | int main(int argc, char **argv) { |
@@ -180,16 +286,15 @@ int main(int argc, char **argv) { | |||
180 | " -v, --version Show the version number and quit.\n" | 286 | " -v, --version Show the version number and quit.\n" |
181 | " -i, --image [<output>:]<path> Display the given image.\n" | 287 | " -i, --image [<output>:]<path> Display the given image.\n" |
182 | " -u, --no-unlock-indicator Disable the unlock indicator.\n" | 288 | " -u, --no-unlock-indicator Disable the unlock indicator.\n" |
183 | " -f, --daemonize Detach from the controlling terminal.\n" | 289 | " -f, --daemonize Detach from the controlling terminal.\n"; |
184 | " --socket <socket> Use the specified socket.\n"; | ||
185 | 290 | ||
186 | struct swaylock_args args = { | 291 | struct swaylock_args args = { |
187 | .mode = BACKGROUND_MODE_SOLID_COLOR, | 292 | .mode = BACKGROUND_MODE_SOLID_COLOR, |
188 | .color = 0xFFFFFFFF, | 293 | .color = 0xFFFFFFFF, |
189 | .show_indicator = true, | 294 | .show_indicator = true, |
190 | }; | 295 | }; |
191 | cairo_surface_t *background_image = NULL; | ||
192 | state.args = args; | 296 | state.args = args; |
297 | wl_list_init(&state.images); | ||
193 | wlr_log_init(L_DEBUG, NULL); | 298 | wlr_log_init(L_DEBUG, NULL); |
194 | 299 | ||
195 | int c; | 300 | int c; |
@@ -206,12 +311,7 @@ int main(int argc, char **argv) { | |||
206 | break; | 311 | break; |
207 | } | 312 | } |
208 | case 'i': | 313 | case 'i': |
209 | // TODO: Multiple background images (bleh) | 314 | load_image(optarg, &state); |
210 | background_image = load_background_image(optarg); | ||
211 | if (!background_image) { | ||
212 | return 1; | ||
213 | } | ||
214 | state.args.mode = BACKGROUND_MODE_FILL; | ||
215 | break; | 315 | break; |
216 | case 's': | 316 | case 's': |
217 | state.args.mode = parse_background_mode(optarg); | 317 | state.args.mode = parse_background_mode(optarg); |
@@ -261,6 +361,7 @@ int main(int argc, char **argv) { | |||
261 | if (!state.input_inhibit_manager) { | 361 | if (!state.input_inhibit_manager) { |
262 | wlr_log(L_ERROR, "Compositor does not support the input inhibitor " | 362 | wlr_log(L_ERROR, "Compositor does not support the input inhibitor " |
263 | "protocol, refusing to run insecurely"); | 363 | "protocol, refusing to run insecurely"); |
364 | return 1; | ||
264 | } | 365 | } |
265 | 366 | ||
266 | if (wl_list_empty(&state.surfaces)) { | 367 | if (wl_list_empty(&state.surfaces)) { |
@@ -268,9 +369,23 @@ int main(int argc, char **argv) { | |||
268 | return 0; | 369 | return 0; |
269 | } | 370 | } |
270 | 371 | ||
372 | if (state.zxdg_output_manager) { | ||
373 | struct swaylock_surface *surface; | ||
374 | wl_list_for_each(surface, &state.surfaces, link) { | ||
375 | surface->xdg_output = zxdg_output_manager_v1_get_xdg_output( | ||
376 | state.zxdg_output_manager, surface->output); | ||
377 | zxdg_output_v1_add_listener( | ||
378 | surface->xdg_output, &_xdg_output_listener, surface); | ||
379 | } | ||
380 | wl_display_roundtrip(state.display); | ||
381 | } else { | ||
382 | wlr_log(L_INFO, "Compositor does not support zxdg output manager, " | ||
383 | "images assigned to named outputs will not work"); | ||
384 | } | ||
385 | |||
271 | struct swaylock_surface *surface; | 386 | struct swaylock_surface *surface; |
272 | wl_list_for_each(surface, &state.surfaces, link) { | 387 | wl_list_for_each(surface, &state.surfaces, link) { |
273 | surface->image = background_image; | 388 | surface->image = select_image(&state, surface); |
274 | 389 | ||
275 | surface->surface = wl_compositor_create_surface(state.compositor); | 390 | surface->surface = wl_compositor_create_surface(state.compositor); |
276 | assert(surface->surface); | 391 | assert(surface->surface); |
diff --git a/swaylock/render.c b/swaylock/render.c index 7d9d25a5..cc40f4e9 100644 --- a/swaylock/render.c +++ b/swaylock/render.c | |||
@@ -23,7 +23,7 @@ void render_frame(struct swaylock_surface *surface) { | |||
23 | cairo_t *cairo = surface->current_buffer->cairo; | 23 | cairo_t *cairo = surface->current_buffer->cairo; |
24 | cairo_identity_matrix(cairo); | 24 | cairo_identity_matrix(cairo); |
25 | 25 | ||
26 | if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR) { | 26 | if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR || !surface->image) { |
27 | cairo_set_source_u32(cairo, state->args.color); | 27 | cairo_set_source_u32(cairo, state->args.color); |
28 | cairo_paint(cairo); | 28 | cairo_paint(cairo); |
29 | } else { | 29 | } else { |