aboutsummaryrefslogtreecommitdiff
path: root/swaybg
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2018-04-12 20:19:54 -0400
committerDrew DeVault <sir@cmpwn.com>2018-04-12 20:19:54 -0400
commitcd1b32453a9296c18b28bff71607aeb22987b5cd (patch)
treec653c6d525b471914c01a9d7ae543f521b6138ed /swaybg
parent8e06985cc1b479724446fba752e0fecfb998e87b (diff)
parent5785170421dc38437acde8bb61068cd16fda716c (diff)
Merge branch 'wlroots'
Diffstat (limited to 'swaybg')
-rw-r--r--swaybg/CMakeLists.txt37
-rw-r--r--swaybg/main.c377
-rw-r--r--swaybg/meson.build18
3 files changed, 221 insertions, 211 deletions
diff --git a/swaybg/CMakeLists.txt b/swaybg/CMakeLists.txt
deleted file mode 100644
index f8cad404..00000000
--- a/swaybg/CMakeLists.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-include_directories(
- ${PROTOCOLS_INCLUDE_DIRS}
- ${WAYLAND_INCLUDE_DIR}
- ${CAIRO_INCLUDE_DIRS}
- ${PANGO_INCLUDE_DIRS}
- ${XKBCOMMON_INCLUDE_DIRS}
-)
-
-add_executable(swaybg
- main.c
-)
-
-target_link_libraries(swaybg
- sway-common
- sway-wayland
- ${WAYLAND_CLIENT_LIBRARIES}
- ${WAYLAND_CURSOR_LIBRARIES}
- ${CAIRO_LIBRARIES}
- ${PANGO_LIBRARIES}
- m
-)
-
-if (WITH_GDK_PIXBUF)
- include_directories(
- ${GDK_PIXBUF_INCLUDE_DIRS}
- )
- target_link_libraries(swaybg
- ${GDK_PIXBUF_LIBRARIES}
- )
-endif()
-
-install(
- TARGETS swaybg
- RUNTIME
- DESTINATION bin
- COMPONENT runtime
-)
diff --git a/swaybg/main.c b/swaybg/main.c
index 2fdd4220..679b8c20 100644
--- a/swaybg/main.c
+++ b/swaybg/main.c
@@ -1,44 +1,55 @@
-#include "wayland-desktop-shell-client-protocol.h"
+#include <assert.h>
+#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
-#include <ctype.h>
-#include <wayland-client.h>
-#include <time.h>
#include <string.h>
-#include "client/window.h"
-#include "client/registry.h"
-#include "client/cairo.h"
-#include "log.h"
-#include "list.h"
+#include <time.h>
+#include <wayland-client.h>
+#include <wlr/util/log.h>
+#include "background-image.h"
+#include "pool-buffer.h"
+#include "cairo.h"
#include "util.h"
+#include "wlr-layer-shell-unstable-v1-client-protocol.h"
-list_t *surfaces;
-struct registry *registry;
+struct swaybg_args {
+ int output_idx;
+ const char *path;
+ enum background_mode mode;
+};
-enum scaling_mode {
- SCALING_MODE_STRETCH,
- SCALING_MODE_FILL,
- SCALING_MODE_FIT,
- SCALING_MODE_CENTER,
- SCALING_MODE_TILE,
+struct swaybg_context {
+ uint32_t color;
+ cairo_surface_t *image;
};
-void sway_terminate(int exit_code) {
- int i;
- for (i = 0; i < surfaces->length; ++i) {
- struct window *window = surfaces->items[i];
- window_teardown(window);
- }
- list_free(surfaces);
- registry_teardown(registry);
- exit(exit_code);
-}
+struct swaybg_state {
+ const struct swaybg_args *args;
+ struct swaybg_context context;
+
+ 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 wl_region *input_region;
+ struct zwlr_layer_surface_v1 *layer_surface;
+
+ bool run_display;
+ uint32_t width, height;
+ int32_t scale;
+ struct pool_buffer buffers[2];
+ struct pool_buffer *current_buffer;
+};
bool is_valid_color(const char *color) {
int len = strlen(color);
if (len != 7 || color[0] != '#') {
- sway_log(L_ERROR, "%s is not a valid color for swaybg. Color should be specified as #rrggbb (no alpha).", color);
+ wlr_log(L_ERROR, "%s is not a valid color for swaybg. "
+ "Color should be specified as #rrggbb (no alpha).", color);
return false;
}
@@ -52,163 +63,181 @@ bool is_valid_color(const char *color) {
return true;
}
-int main(int argc, const char **argv) {
- init_log(L_INFO);
- surfaces = create_list();
- registry = registry_poll();
-
- if (argc != 4) {
- sway_abort("Do not run this program manually. See man 5 sway and look for output options.");
+static void render_frame(struct swaybg_state *state) {
+ int buffer_width = state->width * state->scale,
+ buffer_height = state->height * state->scale;
+ state->current_buffer = get_next_buffer(state->shm,
+ state->buffers, buffer_width, buffer_height);
+ cairo_t *cairo = state->current_buffer->cairo;
+ if (state->args->mode == BACKGROUND_MODE_SOLID_COLOR) {
+ cairo_set_source_u32(cairo, state->context.color);
+ cairo_paint(cairo);
+ } else {
+ render_background_image(cairo, state->context.image,
+ state->args->mode, buffer_width, buffer_height);
}
- if (!registry->desktop_shell) {
- sway_abort("swaybg requires the compositor to support the desktop-shell extension.");
+ wl_surface_set_buffer_scale(state->surface, state->scale);
+ 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 bool prepare_context(struct swaybg_state *state) {
+ if (state->args->mode == BACKGROUND_MODE_SOLID_COLOR) {
+ state->context.color = parse_color(state->args->path);
+ return is_valid_color(state->args->path);
}
+ if (!(state->context.image = load_background_image(state->args->path))) {
+ return false;
+ }
+ return true;
+}
- int desired_output = atoi(argv[1]);
- sway_log(L_INFO, "Using output %d of %d", desired_output, registry->outputs->length);
- int i;
- struct output_state *output = registry->outputs->items[desired_output];
- struct window *window = window_setup(registry,
- output->width, output->height, output->scale, false);
- if (!window) {
- sway_abort("Failed to create surfaces.");
+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;
+ zwlr_layer_surface_v1_ack_configure(surface, serial);
+ render_frame(state);
+}
+
+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);
+ wl_region_destroy(state->input_region);
+ state->run_display = false;
+}
+
+struct zwlr_layer_surface_v1_listener layer_surface_listener = {
+ .configure = layer_surface_configure,
+ .closed = layer_surface_closed,
+};
+
+static void 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,
+ int32_t width, int32_t height, int32_t refresh) {
+ // Who cares
+}
+
+static void output_done(void *data, struct wl_output *output) {
+ // Who cares
+}
+
+static void output_scale(void *data, struct wl_output *output, int32_t factor) {
+ struct swaybg_state *state = data;
+ state->scale = factor;
+ if (state->run_display) {
+ render_frame(state);
}
- desktop_shell_set_background(registry->desktop_shell, output->output, window->surface);
- window_make_shell(window);
- list_add(surfaces, window);
-
- if (strcmp(argv[3], "solid_color") == 0 && is_valid_color(argv[2])) {
- cairo_set_source_u32(window->cairo, parse_color(argv[2]));
- cairo_paint(window->cairo);
- window_render(window);
- } else {
-#ifdef WITH_GDK_PIXBUF
- GError *err = NULL;
- GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(argv[2], &err);
- if (!pixbuf) {
- sway_abort("Failed to load background image.");
- }
- cairo_surface_t *image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf);
- g_object_unref(pixbuf);
-#else
- cairo_surface_t *image = cairo_image_surface_create_from_png(argv[2]);
-#endif //WITH_GDK_PIXBUF
- if (!image) {
- sway_abort("Failed to read background image.");
- }
- if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) {
- sway_abort("Failed to read background image: %s."
-#ifndef WITH_GDK_PIXBUF
- "\nSway was compiled without gdk_pixbuf support, so only"
- "\nPNG images can be loaded. This is the likely cause."
-#endif //WITH_GDK_PIXBUF
- , cairo_status_to_string(cairo_surface_status(image)));
- }
- double width = cairo_image_surface_get_width(image);
- double height = cairo_image_surface_get_height(image);
-
- const char *scaling_mode_str = argv[3];
- enum scaling_mode scaling_mode = SCALING_MODE_STRETCH;
- if (strcmp(scaling_mode_str, "stretch") == 0) {
- scaling_mode = SCALING_MODE_STRETCH;
- } else if (strcmp(scaling_mode_str, "fill") == 0) {
- scaling_mode = SCALING_MODE_FILL;
- } else if (strcmp(scaling_mode_str, "fit") == 0) {
- scaling_mode = SCALING_MODE_FIT;
- } else if (strcmp(scaling_mode_str, "center") == 0) {
- scaling_mode = SCALING_MODE_CENTER;
- } else if (strcmp(scaling_mode_str, "tile") == 0) {
- scaling_mode = SCALING_MODE_TILE;
- } else {
- sway_abort("Unsupported scaling mode: %s", scaling_mode_str);
- }
+}
- int wwidth = window->width * window->scale;
- int wheight = window->height * window->scale;
-
- for (i = 0; i < surfaces->length; ++i) {
- struct window *window = surfaces->items[i];
- if (window_prerender(window) && window->cairo) {
- switch (scaling_mode) {
- case SCALING_MODE_STRETCH:
- cairo_scale(window->cairo,
- (double) wwidth / width,
- (double) wheight / height);
- cairo_set_source_surface(window->cairo, image, 0, 0);
- break;
- case SCALING_MODE_FILL:
- {
- double window_ratio = (double) wwidth / wheight;
- double bg_ratio = width / height;
-
- if (window_ratio > bg_ratio) {
- double scale = (double) wwidth / width;
- cairo_scale(window->cairo, scale, scale);
- cairo_set_source_surface(window->cairo, image,
- 0,
- (double) wheight/2 / scale - height/2);
- } else {
- double scale = (double) wheight / height;
- cairo_scale(window->cairo, scale, scale);
- cairo_set_source_surface(window->cairo, image,
- (double) wwidth/2 / scale - width/2,
- 0);
- }
- break;
- }
- case SCALING_MODE_FIT:
- {
- double window_ratio = (double) wwidth / wheight;
- double bg_ratio = width / height;
-
- if (window_ratio > bg_ratio) {
- double scale = (double) wheight / height;
- cairo_scale(window->cairo, scale, scale);
- cairo_set_source_surface(window->cairo, image,
- (double) wwidth/2 / scale - width/2,
- 0);
- } else {
- double scale = (double) wwidth / width;
- cairo_scale(window->cairo, scale, scale);
- cairo_set_source_surface(window->cairo, image,
- 0,
- (double) wheight/2 / scale - height/2);
- }
- break;
- }
- case SCALING_MODE_CENTER:
- cairo_set_source_surface(window->cairo, image,
- (double) wwidth/2 - width/2,
- (double) wheight/2 - height/2);
- break;
- case SCALING_MODE_TILE:
- {
- cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image);
- cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
- cairo_set_source(window->cairo, pattern);
- break;
- }
- default:
- sway_abort("Scaling mode '%s' not implemented yet!", scaling_mode_str);
- }
-
- cairo_paint(window->cairo);
-
- window_render(window);
- }
+struct wl_output_listener output_listener = {
+ .geometry = output_geometry,
+ .mode = output_mode,
+ .done = output_done,
+ .scale = output_scale,
+};
+
+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, 3);
+ } 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, 3);
+ wl_output_add_listener(state->output, &output_listener, state);
}
+ 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);
+ }
+}
- cairo_surface_destroy(image);
+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];
- while (wl_display_dispatch(registry->display) != -1);
+ args.mode = parse_background_mode(argv[3]);
+ if (args.mode == BACKGROUND_MODE_INVALID) {
+ return 1;
+ }
+ if (!prepare_context(&state)) {
+ return 1;
+ }
- for (i = 0; i < surfaces->length; ++i) {
- struct window *window = surfaces->items[i];
- window_teardown(window);
+ assert(state.display = wl_display_connect(NULL));
+
+ struct wl_registry *registry = wl_display_get_registry(state.display);
+ wl_registry_add_listener(registry, &registry_listener, &state);
+ wl_display_roundtrip(state.display);
+ assert(state.compositor && state.layer_shell && state.output && state.shm);
+
+ // Second roundtrip to get output properties
+ wl_display_roundtrip(state.display);
+
+ assert(state.surface = wl_compositor_create_surface(state.compositor));
+
+ assert(state.input_region = wl_compositor_create_region(state.compositor));
+ wl_surface_set_input_region(state.surface, state.input_region);
+
+ state.layer_surface = zwlr_layer_shell_v1_get_layer_surface(
+ state.layer_shell, state.surface, state.output,
+ ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND, "wallpaper");
+ assert(state.layer_surface);
+
+ 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_set_exclusive_zone(state.layer_surface, -1);
+ 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;
+ while (wl_display_dispatch(state.display) != -1 && state.run_display) {
+ // This space intentionally left blank
}
- list_free(surfaces);
- registry_teardown(registry);
return 0;
}
diff --git a/swaybg/meson.build b/swaybg/meson.build
new file mode 100644
index 00000000..8704de6d
--- /dev/null
+++ b/swaybg/meson.build
@@ -0,0 +1,18 @@
+executable(
+ 'swaybg',
+ 'main.c',
+ include_directories: [sway_inc],
+ dependencies: [
+ cairo,
+ client_protos,
+ gdk_pixbuf,
+ jsonc,
+ math,
+ pango,
+ pangocairo,
+ wayland_client,
+ wlroots,
+ ],
+ link_with: [lib_sway_common, lib_sway_client],
+ install: true
+)