From 632bb948b7ffbb08a6e965dabf88347afd0a1fa8 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Tue, 27 Mar 2018 15:25:25 -0400 Subject: Add solid-color rendering to swaybg --- swaybg/main.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++++ swaybg/meson.build | 18 +++++- 2 files changed, 203 insertions(+), 2 deletions(-) (limited to 'swaybg') 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 #include #include +#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, ®istry_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; } diff --git a/swaybg/meson.build b/swaybg/meson.build index 47315023..7f5d6bd1 100644 --- a/swaybg/meson.build +++ b/swaybg/meson.build @@ -1,8 +1,22 @@ +deps = [ + cairo, + jsonc, + math, + pango, + pangocairo, + sway_protos, + wayland_client, +] + +if gdk_pixbuf.found() + deps += [gdk_pixbuf] +endif + executable( 'swaybg', 'main.c', include_directories: [sway_inc], - dependencies: [wayland_client, sway_protos, jsonc, wlroots], - link_with: [lib_sway_common], + dependencies: deps, + link_with: [lib_sway_common, lib_sway_client], install: true ) -- cgit v1.2.3-54-g00ecf