aboutsummaryrefslogtreecommitdiff
path: root/swaybg/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'swaybg/main.c')
-rw-r--r--swaybg/main.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/swaybg/main.c b/swaybg/main.c
index 94e98228..4473869b 100644
--- a/swaybg/main.c
+++ b/swaybg/main.c
@@ -6,6 +6,10 @@
#include <time.h>
#include <wayland-client.h>
#include <wlr/util/log.h>
+#include "buffer_pool.h"
+#include "cairo.h"
+#include "util.h"
+#include "wlr-layer-shell-unstable-v1-client-protocol.h"
enum scaling_mode {
SCALING_MODE_STRETCH,
@@ -13,6 +17,31 @@ enum scaling_mode {
SCALING_MODE_FIT,
SCALING_MODE_CENTER,
SCALING_MODE_TILE,
+ SCALING_MODE_SOLID_COLOR,
+};
+
+struct swaybg_args {
+ int output_idx;
+ const char *path;
+ enum scaling_mode mode;
+};
+
+struct swaybg_state {
+ const struct swaybg_args *args;
+
+ struct wl_display *display;
+ struct wl_compositor *compositor;
+ struct zwlr_layer_shell_v1 *layer_shell;
+ struct wl_shm *shm;
+
+ struct wl_output *output;
+ struct wl_surface *surface;
+ struct zwlr_layer_surface_v1 *layer_surface;
+
+ bool run_display;
+ uint32_t width, height;
+ struct pool_buffer buffers[2];
+ struct pool_buffer *current_buffer;
};
bool is_valid_color(const char *color) {
@@ -33,7 +62,165 @@ bool is_valid_color(const char *color) {
return true;
}
+static void render_frame(struct swaybg_state *state) {
+ if (!state->run_display) {
+ return;
+ }
+
+ state->current_buffer = get_next_buffer(state->shm,
+ state->buffers, state->width, state->height);
+ cairo_t *cairo = state->current_buffer->cairo;
+
+ switch (state->args->mode) {
+ case SCALING_MODE_SOLID_COLOR:
+ cairo_set_source_u32(cairo, parse_color(state->args->path));
+ cairo_paint(cairo);
+ break;
+ default:
+ exit(1);
+ break;
+ }
+
+ wl_surface_attach(state->surface, state->current_buffer->buffer, 0, 0);
+ wl_surface_damage(state->surface, 0, 0, state->width, state->height);
+ wl_surface_commit(state->surface);
+}
+
+static void layer_surface_configure(void *data,
+ struct zwlr_layer_surface_v1 *surface,
+ uint32_t serial, uint32_t width, uint32_t height) {
+ struct swaybg_state *state = data;
+ state->width = width;
+ state->height = height;
+ render_frame(state);
+ zwlr_layer_surface_v1_ack_configure(surface, serial);
+}
+
+static void layer_surface_closed(void *data,
+ struct zwlr_layer_surface_v1 *surface) {
+ struct swaybg_state *state = data;
+ zwlr_layer_surface_v1_destroy(state->layer_surface);
+ wl_surface_destroy(state->surface);
+ state->run_display = false;
+}
+
+struct zwlr_layer_surface_v1_listener layer_surface_listener = {
+ .configure = layer_surface_configure,
+ .closed = layer_surface_closed,
+};
+
+static void handle_global(void *data, struct wl_registry *registry,
+ uint32_t name, const char *interface, uint32_t version) {
+ struct swaybg_state *state = data;
+ if (strcmp(interface, wl_compositor_interface.name) == 0) {
+ state->compositor = wl_registry_bind(registry, name,
+ &wl_compositor_interface, 1);
+ } else if (strcmp(interface, wl_shm_interface.name) == 0) {
+ state->shm = wl_registry_bind(registry, name,
+ &wl_shm_interface, 1);
+ } else if (strcmp(interface, wl_output_interface.name) == 0) {
+ static int output_idx = 0;
+ if (output_idx == state->args->output_idx) {
+ state->output = wl_registry_bind(registry, name,
+ &wl_output_interface, 1);
+ }
+ output_idx++;
+ } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
+ state->layer_shell = wl_registry_bind(
+ registry, name, &zwlr_layer_shell_v1_interface, 1);
+ }
+}
+
+static void handle_global_remove(void *data, struct wl_registry *registry,
+ uint32_t name) {
+ // who cares
+}
+
+static const struct wl_registry_listener registry_listener = {
+ .global = handle_global,
+ .global_remove = handle_global_remove,
+};
+
int main(int argc, const char **argv) {
+ struct swaybg_args args = {0};
+ struct swaybg_state state = {0};
+ state.args = &args;
wlr_log_init(L_DEBUG, NULL);
+
+ if (argc != 4) {
+ wlr_log(L_ERROR, "Do not run this program manually. "
+ "See man 5 sway and look for output options.");
+ return 1;
+ }
+ args.output_idx = atoi(argv[1]);
+ args.path = argv[2];
+ args.mode = atoi(argv[3]);
+
+ args.mode = SCALING_MODE_STRETCH;
+ if (strcmp(argv[3], "stretch") == 0) {
+ args.mode = SCALING_MODE_STRETCH;
+ } else if (strcmp(argv[3], "fill") == 0) {
+ args.mode = SCALING_MODE_FILL;
+ } else if (strcmp(argv[3], "fit") == 0) {
+ args.mode = SCALING_MODE_FIT;
+ } else if (strcmp(argv[3], "center") == 0) {
+ args.mode = SCALING_MODE_CENTER;
+ } else if (strcmp(argv[3], "tile") == 0) {
+ args.mode = SCALING_MODE_TILE;
+ } else if (strcmp(argv[3], "solid_color") == 0) {
+ args.mode = SCALING_MODE_SOLID_COLOR;
+ } else {
+ wlr_log(L_ERROR, "Unsupported scaling mode: %s", argv[3]);
+ return 1;
+ }
+
+ state.display = wl_display_connect(NULL);
+ if (!state.display) {
+ wlr_log(L_ERROR, "Failed to create display\n");
+ return 1;
+ }
+
+ struct wl_registry *registry = wl_display_get_registry(state.display);
+ wl_registry_add_listener(registry, &registry_listener, &state);
+ wl_display_roundtrip(state.display);
+
+ if (!state.compositor) {
+ wlr_log(L_DEBUG, "wl-compositor not available");
+ return 1;
+ }
+ if (!state.layer_shell) {
+ wlr_log(L_ERROR, "layer-shell not available");
+ return 1;
+ }
+
+ state.surface = wl_compositor_create_surface(state.compositor);
+ if (!state.surface) {
+ wlr_log(L_ERROR, "failed to create wl_surface");
+ return 1;
+ }
+
+ state.layer_surface = zwlr_layer_shell_v1_get_layer_surface(
+ state.layer_shell, state.surface, state.output,
+ ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "wallpaper");
+ if (!state.layer_surface) {
+ wlr_log(L_ERROR, "failed to create zwlr_layer_surface");
+ return 1;
+ }
+ zwlr_layer_surface_v1_set_size(state.layer_surface, 0, 0);
+ zwlr_layer_surface_v1_set_anchor(state.layer_surface,
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
+ ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
+ zwlr_layer_surface_v1_add_listener(state.layer_surface,
+ &layer_surface_listener, &state);
+ wl_surface_commit(state.surface);
+ wl_display_roundtrip(state.display);
+
+ state.run_display = true;
+ render_frame(&state);
+ while (wl_display_dispatch(state.display) != -1 && state.run_display) {
+ // This space intentionally left blank
+ }
return 0;
}