diff options
-rw-r--r-- | swaylock/CMakeLists.txt | 2 | ||||
-rw-r--r-- | swaylock/main.c | 156 | ||||
-rw-r--r-- | swaylock/swaylock.1.txt | 12 |
3 files changed, 132 insertions, 38 deletions
diff --git a/swaylock/CMakeLists.txt b/swaylock/CMakeLists.txt index 08c893ca..b290cd2f 100644 --- a/swaylock/CMakeLists.txt +++ b/swaylock/CMakeLists.txt | |||
@@ -4,6 +4,7 @@ include_directories( | |||
4 | ${CAIRO_INCLUDE_DIRS} | 4 | ${CAIRO_INCLUDE_DIRS} |
5 | ${PANGO_INCLUDE_DIRS} | 5 | ${PANGO_INCLUDE_DIRS} |
6 | ${PAM_INCLUDE_DIRS} | 6 | ${PAM_INCLUDE_DIRS} |
7 | ${JSONC_INCLUDE_DIRS} | ||
7 | ) | 8 | ) |
8 | 9 | ||
9 | add_executable(swaylock | 10 | add_executable(swaylock |
@@ -18,6 +19,7 @@ target_link_libraries(swaylock | |||
18 | ${CAIRO_LIBRARIES} | 19 | ${CAIRO_LIBRARIES} |
19 | ${PANGO_LIBRARIES} | 20 | ${PANGO_LIBRARIES} |
20 | ${PAM_LIBRARIES} | 21 | ${PAM_LIBRARIES} |
22 | ${JSONC_LIBRARIES} | ||
21 | m | 23 | m |
22 | ) | 24 | ) |
23 | 25 | ||
diff --git a/swaylock/main.c b/swaylock/main.c index feb64975..8f0eddb3 100644 --- a/swaylock/main.c +++ b/swaylock/main.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <xkbcommon/xkbcommon.h> | 2 | #include <xkbcommon/xkbcommon.h> |
3 | #include <xkbcommon/xkbcommon-names.h> | 3 | #include <xkbcommon/xkbcommon-names.h> |
4 | #include <security/pam_appl.h> | 4 | #include <security/pam_appl.h> |
5 | #include <json-c/json.h> | ||
5 | #include <stdio.h> | 6 | #include <stdio.h> |
6 | #include <stdlib.h> | 7 | #include <stdlib.h> |
7 | #include <string.h> | 8 | #include <string.h> |
@@ -11,6 +12,7 @@ | |||
11 | #include "client/window.h" | 12 | #include "client/window.h" |
12 | #include "client/registry.h" | 13 | #include "client/registry.h" |
13 | #include "client/cairo.h" | 14 | #include "client/cairo.h" |
15 | #include "ipc-client.h" | ||
14 | #include "log.h" | 16 | #include "log.h" |
15 | 17 | ||
16 | list_t *surfaces; | 18 | list_t *surfaces; |
@@ -134,7 +136,6 @@ void notify_key(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t cod | |||
134 | void render_color(struct window *window, uint32_t color) { | 136 | void render_color(struct window *window, uint32_t color) { |
135 | cairo_set_source_u32(window->cairo, color); | 137 | cairo_set_source_u32(window->cairo, color); |
136 | cairo_paint(window->cairo); | 138 | cairo_paint(window->cairo); |
137 | window_render(window); | ||
138 | } | 139 | } |
139 | 140 | ||
140 | void render_image(struct window *window, cairo_surface_t *image, enum scaling_mode scaling_mode) { | 141 | void render_image(struct window *window, cairo_surface_t *image, enum scaling_mode scaling_mode) { |
@@ -203,14 +204,34 @@ void render_image(struct window *window, cairo_surface_t *image, enum scaling_mo | |||
203 | } | 204 | } |
204 | 205 | ||
205 | cairo_paint(window->cairo); | 206 | cairo_paint(window->cairo); |
207 | } | ||
208 | |||
209 | cairo_surface_t *load_image(char *image_path) { | ||
210 | cairo_surface_t *image = NULL; | ||
211 | |||
212 | #ifdef WITH_GDK_PIXBUF | ||
213 | GError *err = NULL; | ||
214 | GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(image_path, &err); | ||
215 | if (!pixbuf) { | ||
216 | sway_abort("Failed to load background image: %s", err->message); | ||
217 | } | ||
218 | image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); | ||
219 | g_object_unref(pixbuf); | ||
220 | #else | ||
221 | image = cairo_image_surface_create_from_png(image_path); | ||
222 | #endif //WITH_GDK_PIXBUF | ||
223 | if (!image) { | ||
224 | sway_abort("Failed to read background image."); | ||
225 | } | ||
206 | 226 | ||
207 | window_render(window); | 227 | return image; |
208 | } | 228 | } |
209 | 229 | ||
210 | int main(int argc, char **argv) { | 230 | int main(int argc, char **argv) { |
211 | char *image_path = NULL; | 231 | char *scaling_mode_str = "fit", *socket_path = NULL; |
212 | char *scaling_mode_str = "fit"; | 232 | int i, num_images = 0, color_set = 0; |
213 | uint32_t color = 0xFFFFFFFF; | 233 | uint32_t color = 0xFFFFFFFF; |
234 | void *images; | ||
214 | 235 | ||
215 | init_log(L_INFO); | 236 | init_log(L_INFO); |
216 | 237 | ||
@@ -221,18 +242,22 @@ int main(int argc, char **argv) { | |||
221 | {"scaling", required_argument, NULL, 's'}, | 242 | {"scaling", required_argument, NULL, 's'}, |
222 | {"tiling", no_argument, NULL, 't'}, | 243 | {"tiling", no_argument, NULL, 't'}, |
223 | {"version", no_argument, NULL, 'v'}, | 244 | {"version", no_argument, NULL, 'v'}, |
245 | {"socket", required_argument, NULL, 'p'}, | ||
224 | {0, 0, 0, 0} | 246 | {0, 0, 0, 0} |
225 | }; | 247 | }; |
226 | 248 | ||
227 | const char *usage = | 249 | const char *usage = |
228 | "Usage: swaylock [options...]\n" | 250 | "Usage: swaylock [options...]\n" |
229 | "\n" | 251 | "\n" |
230 | " -h, --help Show help message and quit.\n" | 252 | " -h, --help Show help message and quit.\n" |
231 | " -c, --color <rrggbb[aa]> Turn the screen into the given color instead of white.\n" | 253 | " -c, --color <rrggbb[aa]> Turn the screen into the given color instead of white.\n" |
232 | " -s, --scaling Scaling mode: stretch, fill, fit, center, tile.\n" | 254 | " -s, --scaling Scaling mode: stretch, fill, fit, center, tile.\n" |
233 | " -t, --tiling Same as --scaling=tile.\n" | 255 | " -t, --tiling Same as --scaling=tile.\n" |
234 | " -v, --version Show the version number and quit.\n" | 256 | " -v, --version Show the version number and quit.\n" |
235 | " -i, --image <path> Display the given image.\n"; | 257 | " -i, --image [<output>:]<path> Display the given image.\n" |
258 | " --socket <socket> Use the specified socket.\n"; | ||
259 | |||
260 | registry = registry_poll(); | ||
236 | 261 | ||
237 | int c; | 262 | int c; |
238 | while (1) { | 263 | while (1) { |
@@ -246,10 +271,11 @@ int main(int argc, char **argv) { | |||
246 | { | 271 | { |
247 | int colorlen = strlen(optarg); | 272 | int colorlen = strlen(optarg); |
248 | if (colorlen < 6 || colorlen == 7 || colorlen > 8) { | 273 | if (colorlen < 6 || colorlen == 7 || colorlen > 8) { |
249 | fprintf(stderr, "color must be specified in 3 or 4 byte format, e.g. ff0000 or ff0000ff\n"); | 274 | sway_log(L_ERROR, "color must be specified in 3 or 4 byte format, e.g. ff0000 or ff0000ff"); |
250 | exit(EXIT_FAILURE); | 275 | exit(EXIT_FAILURE); |
251 | } | 276 | } |
252 | color = strtol(optarg, NULL, 16); | 277 | color = strtol(optarg, NULL, 16); |
278 | color_set = 1; | ||
253 | 279 | ||
254 | if (colorlen == 6) { | 280 | if (colorlen == 6) { |
255 | color <<= 8; | 281 | color <<= 8; |
@@ -259,14 +285,39 @@ int main(int argc, char **argv) { | |||
259 | break; | 285 | break; |
260 | } | 286 | } |
261 | case 'i': | 287 | case 'i': |
262 | image_path = optarg; | 288 | { |
289 | char *image_path = strchr(optarg, ':'); | ||
290 | if (image_path == NULL) { | ||
291 | if (num_images == 0) { | ||
292 | images = load_image(optarg); | ||
293 | num_images = -1; | ||
294 | } else { | ||
295 | sway_log(L_ERROR, "output must be defined for all --images or no --images"); | ||
296 | exit(EXIT_FAILURE); | ||
297 | } | ||
298 | } else { | ||
299 | if (num_images == 0) { | ||
300 | images = calloc(registry->outputs->length, sizeof(char*) * 2); | ||
301 | } else if (num_images == -1) { | ||
302 | sway_log(L_ERROR, "output must be defined for all --images or no --images"); | ||
303 | exit(EXIT_FAILURE); | ||
304 | } | ||
305 | |||
306 | image_path[0] = '\0'; | ||
307 | ((char**) images)[num_images * 2] = optarg; | ||
308 | ((char**) images)[num_images++ * 2 + 1] = ++image_path; | ||
309 | } | ||
263 | break; | 310 | break; |
311 | } | ||
264 | case 's': | 312 | case 's': |
265 | scaling_mode_str = optarg; | 313 | scaling_mode_str = optarg; |
266 | break; | 314 | break; |
267 | case 't': | 315 | case 't': |
268 | scaling_mode_str = "tile"; | 316 | scaling_mode_str = "tile"; |
269 | break; | 317 | break; |
318 | case 'p': | ||
319 | socket_path = optarg; | ||
320 | break; | ||
270 | case 'v': | 321 | case 'v': |
271 | #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE | 322 | #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE |
272 | fprintf(stdout, "swaylock version %s (%s, branch \"%s\")\n", SWAY_GIT_VERSION, SWAY_VERSION_DATE, SWAY_GIT_BRANCH); | 323 | fprintf(stdout, "swaylock version %s (%s, branch \"%s\")\n", SWAY_GIT_VERSION, SWAY_VERSION_DATE, SWAY_GIT_BRANCH); |
@@ -300,7 +351,12 @@ int main(int argc, char **argv) { | |||
300 | password = malloc(password_size); | 351 | password = malloc(password_size); |
301 | password[0] = '\0'; | 352 | password[0] = '\0'; |
302 | surfaces = create_list(); | 353 | surfaces = create_list(); |
303 | registry = registry_poll(); | 354 | if (!socket_path) { |
355 | socket_path = get_socketpath(); | ||
356 | if (!socket_path) { | ||
357 | sway_abort("Unable to retrieve socket path"); | ||
358 | } | ||
359 | } | ||
304 | 360 | ||
305 | if (!registry) { | 361 | if (!registry) { |
306 | sway_abort("Unable to connect to wayland compositor"); | 362 | sway_abort("Unable to connect to wayland compositor"); |
@@ -316,7 +372,6 @@ int main(int argc, char **argv) { | |||
316 | registry->pointer = NULL; | 372 | registry->pointer = NULL; |
317 | } | 373 | } |
318 | 374 | ||
319 | int i; | ||
320 | for (i = 0; i < registry->outputs->length; ++i) { | 375 | for (i = 0; i < registry->outputs->length; ++i) { |
321 | struct output_state *output = registry->outputs->items[i]; | 376 | struct output_state *output = registry->outputs->items[i]; |
322 | struct window *window = window_setup(registry, output->width, output->height, true); | 377 | struct window *window = window_setup(registry, output->width, output->height, true); |
@@ -328,23 +383,38 @@ int main(int argc, char **argv) { | |||
328 | 383 | ||
329 | registry->input->notify = notify_key; | 384 | registry->input->notify = notify_key; |
330 | 385 | ||
331 | cairo_surface_t *image = NULL; | 386 | if (num_images >= 1) { |
332 | 387 | char **displays_paths = images; | |
333 | if (image_path) { | 388 | images = calloc(registry->outputs->length, sizeof(cairo_surface_t*)); |
334 | #ifdef WITH_GDK_PIXBUF | 389 | |
335 | GError *err = NULL; | 390 | int socketfd = ipc_open_socket(socket_path); |
336 | GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(image_path, &err); | 391 | uint32_t len = 0; |
337 | if (!pixbuf) { | 392 | char *outputs = ipc_single_command(socketfd, IPC_GET_OUTPUTS, "", &len); |
338 | sway_abort("Failed to load background image."); | 393 | struct json_object *json_outputs = json_tokener_parse(outputs); |
339 | } | 394 | |
340 | image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf); | 395 | for (i = 0; i < registry->outputs->length; ++i) { |
341 | g_object_unref(pixbuf); | 396 | if (displays_paths[i * 2] != NULL) { |
342 | #else | 397 | for (int j = 0;; ++j) { |
343 | cairo_surface_t *image = cairo_image_surface_create_from_png(argv[1]); | 398 | if (j >= json_object_array_length(json_outputs)) { |
344 | #endif //WITH_GDK_PIXBUF | 399 | sway_log(L_ERROR, "%s is not an extant output", displays_paths[i * 2]); |
345 | if (!image) { | 400 | exit(EXIT_FAILURE); |
346 | sway_abort("Failed to read background image."); | 401 | } |
402 | |||
403 | struct json_object *dsp_name, *at_j = json_object_array_get_idx(json_outputs, j); | ||
404 | if (!json_object_object_get_ex(at_j, "name", &dsp_name)) { | ||
405 | sway_abort("output doesn't have a name field"); | ||
406 | } | ||
407 | if (!strcmp(displays_paths[i * 2], json_object_get_string(dsp_name))) { | ||
408 | ((cairo_surface_t**) images)[j] = load_image(displays_paths[i * 2 + 1]); | ||
409 | break; | ||
410 | } | ||
411 | } | ||
412 | } | ||
347 | } | 413 | } |
414 | |||
415 | json_object_put(json_outputs); | ||
416 | close(socketfd); | ||
417 | free(displays_paths); | ||
348 | } | 418 | } |
349 | 419 | ||
350 | for (i = 0; i < surfaces->length; ++i) { | 420 | for (i = 0; i < surfaces->length; ++i) { |
@@ -352,15 +422,31 @@ int main(int argc, char **argv) { | |||
352 | if (!window_prerender(window) || !window->cairo) { | 422 | if (!window_prerender(window) || !window->cairo) { |
353 | continue; | 423 | continue; |
354 | } | 424 | } |
355 | if (image) { | 425 | |
356 | render_image(window, image, scaling_mode); | 426 | if (num_images == 0 || color_set) { |
357 | } else { | ||
358 | render_color(window, color); | 427 | render_color(window, color); |
359 | } | 428 | } |
429 | |||
430 | if (num_images == -1) { | ||
431 | render_image(window, images, scaling_mode); | ||
432 | } else if (num_images >= 1) { | ||
433 | if (((cairo_surface_t**) images)[i] != NULL) { | ||
434 | render_image(window, ((cairo_surface_t**) images)[i], scaling_mode); | ||
435 | } | ||
436 | } | ||
437 | |||
438 | window_render(window); | ||
360 | } | 439 | } |
361 | 440 | ||
362 | if (image) { | 441 | if (num_images == -1) { |
363 | cairo_surface_destroy(image); | 442 | cairo_surface_destroy((cairo_surface_t*) images); |
443 | } else if (num_images >= 1) { | ||
444 | for (i = 0; i < registry->outputs->length; ++i) { | ||
445 | if (((cairo_surface_t**) images)[i] != NULL) { | ||
446 | cairo_surface_destroy(((cairo_surface_t**) images)[i]); | ||
447 | } | ||
448 | } | ||
449 | free(images); | ||
364 | } | 450 | } |
365 | 451 | ||
366 | bool locked = false; | 452 | bool locked = false; |
diff --git a/swaylock/swaylock.1.txt b/swaylock/swaylock.1.txt index 04594fd0..c30e8d3d 100644 --- a/swaylock/swaylock.1.txt +++ b/swaylock/swaylock.1.txt | |||
@@ -23,10 +23,11 @@ Options | |||
23 | Show help message and quit. | 23 | Show help message and quit. |
24 | 24 | ||
25 | *-c, \--color* <rrggbb[aa]>:: | 25 | *-c, \--color* <rrggbb[aa]>:: |
26 | Turn the screen into the given color instead of white. | 26 | Turn the screen into the given color instead of white. If an image is in use, |
27 | also enables color display. | ||
27 | 28 | ||
28 | *-i, \--image* <path>:: | 29 | *-i, \--image* [<output>:]<path>:: |
29 | Display the given image. | 30 | Display the given image, optionally only on the given output. |
30 | 31 | ||
31 | *-s, \--scaling*:: | 32 | *-s, \--scaling*:: |
32 | Scaling mode for images: stretch, fill, fit, center, or tile. | 33 | Scaling mode for images: stretch, fill, fit, center, or tile. |
@@ -37,6 +38,11 @@ Options | |||
37 | *-v, \--version*:: | 38 | *-v, \--version*:: |
38 | Show the version number and quit. | 39 | Show the version number and quit. |
39 | 40 | ||
41 | *--socket <path>*:: | ||
42 | Use the specified socket path. Otherwise, swaymsg will ask sway where the | ||
43 | socket is (which is the value of $SWAYSOCK, then of $I3SOCK). | ||
44 | |||
45 | |||
40 | Authors | 46 | Authors |
41 | ------- | 47 | ------- |
42 | 48 | ||