From 9d99e5c2e72a464554b034c014437a495bb7b409 Mon Sep 17 00:00:00 2001
From: Ryan Dwyer <ryandwyer1@gmail.com>
Date: Sat, 19 May 2018 08:47:47 +1000
Subject: Swaylock: Allow per-output images

---
 swaylock/main.c   | 138 ++++++++++++++++++++++++++++++++++++++++++++++--------
 swaylock/render.c |   2 +-
 2 files changed, 119 insertions(+), 21 deletions(-)

(limited to 'swaylock')

diff --git a/swaylock/main.c b/swaylock/main.c
index 200c1b5f..91c28bd2 100644
--- a/swaylock/main.c
+++ b/swaylock/main.c
@@ -13,6 +13,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <wayland-client.h>
+#include <wordexp.h>
 #include <wlr/util/log.h>
 #include "swaylock/seat.h"
 #include "swaylock/swaylock.h"
@@ -20,9 +21,11 @@
 #include "pool-buffer.h"
 #include "cairo.h"
 #include "log.h"
+#include "stringop.h"
 #include "util.h"
 #include "wlr-input-inhibitor-unstable-v1-client-protocol.h"
 #include "wlr-layer-shell-unstable-v1-client-protocol.h"
+#include "xdg-output-unstable-v1-client-protocol.h"
 
 void sway_terminate(int exit_code) {
 	exit(exit_code);
@@ -84,22 +87,23 @@ static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
 	.closed = layer_surface_closed,
 };
 
-static void output_geometry(void *data, struct wl_output *output, int32_t x,
+static void handle_wl_output_geometry(void *data, struct wl_output *output, int32_t x,
 		int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel,
 		const char *make, const char *model, int32_t transform) {
 	// Who cares
 }
 
-static void output_mode(void *data, struct wl_output *output, uint32_t flags,
+static void handle_wl_output_mode(void *data, struct wl_output *output, uint32_t flags,
 		int32_t width, int32_t height, int32_t refresh) {
 	// Who cares
 }
 
-static void output_done(void *data, struct wl_output *output) {
+static void handle_wl_output_done(void *data, struct wl_output *output) {
 	// Who cares
 }
 
-static void output_scale(void *data, struct wl_output *output, int32_t factor) {
+static void handle_wl_output_scale(void *data, struct wl_output *output,
+		int32_t factor) {
 	struct swaylock_surface *surface = data;
 	surface->scale = factor;
 	if (surface->state->run_display) {
@@ -107,11 +111,46 @@ static void output_scale(void *data, struct wl_output *output, int32_t factor) {
 	}
 }
 
-struct wl_output_listener output_listener = {
-	.geometry = output_geometry,
-	.mode = output_mode,
-	.done = output_done,
-	.scale = output_scale,
+struct wl_output_listener _wl_output_listener = {
+	.geometry = handle_wl_output_geometry,
+	.mode = handle_wl_output_mode,
+	.done = handle_wl_output_done,
+	.scale = handle_wl_output_scale,
+};
+
+static void handle_xdg_output_logical_size(void *data, struct zxdg_output_v1 *output,
+		int width, int height) {
+	// Who cares
+}
+
+static void handle_xdg_output_logical_position(void *data,
+		struct zxdg_output_v1 *output, int x, int y) {
+	// Who cares
+}
+
+static void handle_xdg_output_name(void *data, struct zxdg_output_v1 *output,
+		const char *name) {
+	wlr_log(L_DEBUG, "output name is %s", name);
+	struct swaylock_surface *surface = data;
+	surface->xdg_output = output;
+	surface->output_name = strdup(name);
+}
+
+static void handle_xdg_output_description(void *data, struct zxdg_output_v1 *output,
+		const char *description) {
+	// Who cares
+}
+
+static void handle_xdg_output_done(void *data, struct zxdg_output_v1 *output) {
+	// Who cares
+}
+
+struct zxdg_output_v1_listener _xdg_output_listener = {
+	.logical_position = handle_xdg_output_logical_position,
+	.logical_size = handle_xdg_output_logical_size,
+	.done = handle_xdg_output_done,
+	.name = handle_xdg_output_name,
+	.description = handle_xdg_output_description,
 };
 
 static void handle_global(void *data, struct wl_registry *registry,
@@ -133,13 +172,16 @@ static void handle_global(void *data, struct wl_registry *registry,
 	} else if (strcmp(interface, zwlr_input_inhibit_manager_v1_interface.name) == 0) {
 		state->input_inhibit_manager = wl_registry_bind(
 				registry, name, &zwlr_input_inhibit_manager_v1_interface, 1);
+	} else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
+		state->zxdg_output_manager = wl_registry_bind(
+				registry, name, &zxdg_output_manager_v1_interface, 2);
 	} else if (strcmp(interface, wl_output_interface.name) == 0) {
 		struct swaylock_surface *surface =
 			calloc(1, sizeof(struct swaylock_surface));
 		surface->state = state;
 		surface->output = wl_registry_bind(registry, name,
 				&wl_output_interface, 3);
-		wl_output_add_listener(surface->output, &output_listener, surface);
+		wl_output_add_listener(surface->output, &_wl_output_listener, surface);
 		wl_list_insert(&state->surfaces, &surface->link);
 	}
 }
@@ -154,6 +196,53 @@ static const struct wl_registry_listener registry_listener = {
 	.global_remove = handle_global_remove,
 };
 
+static cairo_surface_t *select_image(struct swaylock_state *state,
+		struct swaylock_surface *surface) {
+	struct swaylock_image *image;
+	cairo_surface_t *default_image = NULL;
+	wl_list_for_each(image, &state->images, link) {
+		if (lenient_strcmp(image->output_name, surface->output_name) == 0) {
+			return image->cairo_surface;
+		} else if (!image->output_name) {
+			default_image = image->cairo_surface;
+		}
+	}
+	return default_image;
+}
+
+static void load_image(char *arg, struct swaylock_state *state) {
+	// [<output>:]<path>
+	struct swaylock_image *image = malloc(sizeof(struct swaylock_image));
+	char *separator = strchr(arg, ':');
+	if (separator) {
+		*separator = '\0';
+		image->output_name = strdup(arg);
+		image->path = strdup(separator + 1);
+	} else {
+		image->output_name = NULL;
+		image->path = strdup(arg);
+	}
+
+	// Bash doesn't replace the ~ with $HOME if the output name is supplied
+	wordexp_t p;
+	if (wordexp(image->path, &p, 0) == 0) {
+		free(image->path);
+		image->path = strdup(p.we_wordv[0]);
+		wordfree(&p);
+	}
+
+	// Load the actual image
+	image->cairo_surface = load_background_image(image->path);
+	if (!image->cairo_surface) {
+		free(image);
+		return;
+	}
+	wl_list_insert(&state->images, &image->link);
+	state->args.mode = BACKGROUND_MODE_FILL;
+	wlr_log(L_DEBUG, "Loaded image %s for output %s",
+			image->path, image->output_name ? image->output_name : "*");
+}
+
 static struct swaylock_state state;
 
 int main(int argc, char **argv) {
@@ -180,16 +269,15 @@ int main(int argc, char **argv) {
 		"  -v, --version                  Show the version number and quit.\n"
 		"  -i, --image [<output>:]<path>  Display the given image.\n"
 		"  -u, --no-unlock-indicator      Disable the unlock indicator.\n"
-		"  -f, --daemonize                Detach from the controlling terminal.\n" 
-		"  --socket <socket>              Use the specified socket.\n";
+		"  -f, --daemonize                Detach from the controlling terminal.\n";
 
 	struct swaylock_args args = {
 		.mode = BACKGROUND_MODE_SOLID_COLOR,
 		.color = 0xFFFFFFFF,
 		.show_indicator = true,
 	};
-	cairo_surface_t *background_image = NULL;
 	state.args = args;
+	wl_list_init(&state.images);
 	wlr_log_init(L_DEBUG, NULL);
 
 	int c;
@@ -206,12 +294,7 @@ int main(int argc, char **argv) {
 			break;
 		}
 		case 'i':
-			// TODO: Multiple background images (bleh)
-			background_image = load_background_image(optarg);
-			if (!background_image) {
-				return 1;
-			}
-			state.args.mode = BACKGROUND_MODE_FILL;
+			load_image(optarg, &state);
 			break;
 		case 's':
 			state.args.mode = parse_background_mode(optarg);
@@ -261,6 +344,7 @@ int main(int argc, char **argv) {
 	if (!state.input_inhibit_manager) {
 		wlr_log(L_ERROR, "Compositor does not support the input inhibitor "
 				"protocol, refusing to run insecurely");
+		return 1;
 	}
 
 	if (wl_list_empty(&state.surfaces)) {
@@ -268,9 +352,23 @@ int main(int argc, char **argv) {
 		return 0;
 	}
 
+	if (state.zxdg_output_manager) {
+		struct swaylock_surface *surface;
+		wl_list_for_each(surface, &state.surfaces, link) {
+			surface->xdg_output = zxdg_output_manager_v1_get_xdg_output(
+						state.zxdg_output_manager, surface->output);
+			zxdg_output_v1_add_listener(
+					surface->xdg_output, &_xdg_output_listener, surface);
+		}
+		wl_display_roundtrip(state.display);
+	} else {
+		wlr_log(L_INFO, "Compositor does not support zxdg output manager, "
+				"images assigned to named outputs will not work");
+	}
+
 	struct swaylock_surface *surface;
 	wl_list_for_each(surface, &state.surfaces, link) {
-		surface->image = background_image;
+		surface->image = select_image(&state, surface);
 
 		surface->surface = wl_compositor_create_surface(state.compositor);
 		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) {
 	cairo_t *cairo = surface->current_buffer->cairo;
 	cairo_identity_matrix(cairo);
 
-	if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR) {
+	if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR || !surface->image) {
 		cairo_set_source_u32(cairo, state->args.color);
 		cairo_paint(cairo);
 	} else {
-- 
cgit v1.2.3


From bde9711f3cea13a0283f7c2b5b5aa1deb91edf41 Mon Sep 17 00:00:00 2001
From: Ryan Dwyer <ryandwyer1@gmail.com>
Date: Sun, 20 May 2018 22:39:08 +1000
Subject: Swaylock: Log error if multiple images are defined for the same
 output

---
 swaylock/main.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

(limited to 'swaylock')

diff --git a/swaylock/main.c b/swaylock/main.c
index 91c28bd2..74a00a35 100644
--- a/swaylock/main.c
+++ b/swaylock/main.c
@@ -223,6 +223,23 @@ static void load_image(char *arg, struct swaylock_state *state) {
 		image->path = strdup(arg);
 	}
 
+	bool exists = false;
+	struct swaylock_image *iter_image;
+	wl_list_for_each(iter_image, &state->images, link) {
+		if (lenient_strcmp(iter_image->output_name, image->output_name) == 0) {
+			exists = true;
+			break;
+		}
+	}
+	if (exists) {
+		if (image->output_name) {
+			wlr_log(L_ERROR, "Multiple images defined for output %s",
+				image->output_name);
+		} else {
+			wlr_log(L_ERROR, "Multiple default images defined");
+		}
+	}
+
 	// Bash doesn't replace the ~ with $HOME if the output name is supplied
 	wordexp_t p;
 	if (wordexp(image->path, &p, 0) == 0) {
-- 
cgit v1.2.3


From 836123329504af8b4fd735063eb44690a23e626e Mon Sep 17 00:00:00 2001
From: Ryan Dwyer <ryandwyer1@gmail.com>
Date: Sun, 20 May 2018 22:47:07 +1000
Subject: Swaylock: Use calloc instead of malloc

---
 swaylock/main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'swaylock')

diff --git a/swaylock/main.c b/swaylock/main.c
index 74a00a35..11b5e8c8 100644
--- a/swaylock/main.c
+++ b/swaylock/main.c
@@ -212,7 +212,7 @@ static cairo_surface_t *select_image(struct swaylock_state *state,
 
 static void load_image(char *arg, struct swaylock_state *state) {
 	// [<output>:]<path>
-	struct swaylock_image *image = malloc(sizeof(struct swaylock_image));
+	struct swaylock_image *image = calloc(1, sizeof(struct swaylock_image));
 	char *separator = strchr(arg, ':');
 	if (separator) {
 		*separator = '\0';
-- 
cgit v1.2.3