aboutsummaryrefslogtreecommitdiff
path: root/ffbg.c
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2023-04-22 18:40:22 +0200
committerNathan Reiner <nathan@nathanreiner.xyz>2023-04-22 18:40:22 +0200
commitf14acf7306b022c1d0dd98f5fd654dbdc38e64e5 (patch)
tree562e30fdad694f11fc1075b353be6d22d9094171 /ffbg.c
create ffbg
Diffstat (limited to 'ffbg.c')
-rw-r--r--ffbg.c357
1 files changed, 357 insertions, 0 deletions
diff --git a/ffbg.c b/ffbg.c
new file mode 100644
index 0000000..4fd5e25
--- /dev/null
+++ b/ffbg.c
@@ -0,0 +1,357 @@
+#include <wayland-client-protocol.h>
+#include <assert.h>
+#include <string.h>
+#include <wayland-client.h>
+#include <xkbcommon/xkbcommon.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <malloc.h>
+#include <arpa/inet.h>
+
+#include "drw.h"
+#include "util.h"
+#include "wayland.h"
+
+/* type definitions */
+typedef struct BG BG;
+struct BG {
+ unsigned width;
+ unsigned height;
+ uint32_t registry_name;
+ Canvas *canvas;
+ struct wl_output *wl_output;
+ struct wl_surface *wl_surface;
+ struct zwlr_layer_surface_v1 *zwlr_surface;
+ BG *next;
+};
+
+typedef struct {
+ uint32_t width;
+ uint32_t height;
+ uint32_t *buffer;
+} Image;
+
+/* function declarations */
+static void update_bg(BG *bg);
+static void wl_buffer_release(void *data, struct wl_buffer *wl_buffer);
+static void remove_bg(BG *bg);
+static void registry_global(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version);
+static void remove_global(void *data, struct wl_registry *wl_registry, uint32_t name);
+static void layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t w, uint32_t h);
+static void layer_surface_closed(void *data, struct zwlr_layer_surface_v1 *surface);
+static void dummy();
+static void wayland_flush();
+static void register_bg(BG *bg);
+static void readimage();
+static void setup();
+struct wl_buffer *draw_frame(BG *bg);
+static BG *add_bg();
+
+
+/* global variables */
+static const struct wl_buffer_listener wl_buffer_listener = {
+ .release = wl_buffer_release,
+};
+
+static const struct wl_registry_listener wl_registry_listener = {
+ .global = registry_global,
+ .global_remove = remove_global,
+};
+
+static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
+ .configure = layer_surface_configure,
+ .closed = layer_surface_closed
+};
+
+static BG *bgs = NULL;
+static char statusline[1024] = "";
+struct client_state bg_state = { 0 };
+struct pollfd pollfds[2];
+int displayfd;
+int ready = 0;
+Image img;
+
+/* configuration */
+#include "config.h"
+
+/* function implementations */
+void
+wl_buffer_release(void *data, struct wl_buffer *wl_buffer)
+{
+ wl_buffer_destroy(wl_buffer);
+}
+
+
+struct wl_buffer *
+draw_frame(BG *bg)
+{
+
+ Canvas *canvas = bg->canvas;
+ unsigned tx;
+ unsigned ty;
+ unsigned x;
+ unsigned y;
+ Color c;
+ Color colbg = to_color(background);
+ double strength;
+
+ if (canvas == 0)
+ return 0;
+
+ draw_rect(canvas, 0, 0, bg->width, bg->height, background);
+
+ tx = (bg->width - img.width) / 2;
+ ty = (bg->height - img.height) / 2;
+
+ for (x = 0; x < img.width; ++x) {
+ for (y = 0; y < img.height; ++y) {
+ c = to_color(img.buffer[x + img.width * y]);
+ strength = (double)(c.a) / 255;
+
+ c.r = (strength * c.r) + ((1 - strength) * colbg.r);
+ c.g = (strength * c.g) + ((1 - strength) * colbg.g);
+ c.b = (strength * c.b) + ((1 - strength) * colbg.b);
+ c.a = 0xff;
+
+ draw_point(canvas, x + tx, y + ty, to_uint32_t(c));
+ }
+ }
+
+ return canvas->buffer;
+}
+
+void
+update_bg(BG *bg)
+{
+ struct wl_buffer *buffer = draw_frame(bg);
+
+ if (!buffer)
+ return;
+
+ wl_surface_attach(bg->wl_surface, buffer, 0, 0);
+ wl_surface_damage_buffer(bg->wl_surface, 0, 0, bg->width, bg->height);
+ wl_surface_commit(bg->wl_surface);
+}
+
+
+void
+registry_global(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version)
+{
+ struct client_state *state = data;
+ BG *bg;
+
+ if (strcmp(interface, wl_shm_interface.name) == 0) {
+ state->wl_shm = wl_registry_bind(
+ wl_registry, name, &wl_shm_interface, 1);
+ } else if (strcmp(interface, wl_compositor_interface.name) == 0) {
+ state->wl_compositor = wl_registry_bind(
+ wl_registry, name, &wl_compositor_interface, 4);
+ } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
+ state->zwlr_layer = wl_registry_bind(wl_registry, name, &zwlr_layer_shell_v1_interface, 1);
+ } else if (strcmp(interface, wl_output_interface.name) == 0) {
+ bg = add_bg();
+ bg->wl_output = wl_registry_bind(wl_registry, name, &wl_output_interface, 1);
+ bg->registry_name = name;
+
+ if (ready) {
+ register_bg(bg);
+ }
+ }
+}
+
+
+void
+remove_global(void *data, struct wl_registry *wl_registry, uint32_t name)
+{
+ BG *bg = bgs;
+ BG *prev = 0;
+
+ for (; bg; bg = bg->next) {
+ if (bg->registry_name == name) {
+ if (prev) {
+ prev->next = bg->next;
+ } else {
+ bgs = bg->next;
+ }
+
+ remove_bg(bg);
+ break;
+ }
+
+ prev = bg;
+ }
+}
+
+
+void
+layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t w, uint32_t h)
+{
+ BG *bg = data;
+
+ bg->width = w;
+ bg->height = h;
+
+ zwlr_layer_surface_v1_set_exclusive_zone(surface, -1);
+ zwlr_layer_surface_v1_ack_configure(surface, serial);
+
+ bg->canvas = create_drw(bg_state.wl_shm, bg->width, bg->height);
+
+ update_bg(bg);
+}
+
+
+void
+layer_surface_closed(void *data, struct zwlr_layer_surface_v1 *surface)
+{
+ BG *bg = data;
+ zwlr_layer_surface_v1_destroy(surface);
+ wl_surface_destroy(bg->wl_surface);
+}
+
+
+void
+dummy()
+{
+ /* Who cares */
+}
+
+
+BG *
+add_bg()
+{
+ BG *bg = bgs;
+
+ if (!bg) {
+ bgs = malloc(sizeof(BG));
+ memset(bgs, 0, sizeof(BG));
+ return bgs;
+ }
+
+ for (; bg->next; bg = bg->next);
+
+ bg->next = malloc(sizeof(BG));
+ memset(bg->next, 0, sizeof(BG));
+
+ return bg->next;
+}
+
+
+void
+remove_bg(BG *bg)
+{
+ wl_surface_destroy(bg->wl_surface);
+ zwlr_layer_surface_v1_destroy(bg->zwlr_surface);
+ wl_output_destroy(bg->wl_output);
+ free_drw(bg->canvas);
+ free(bg);
+}
+
+
+void
+register_bg(BG *bg)
+{
+ char *namespace = "dbg";
+ uint32_t layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND;
+ uint32_t anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
+
+ bg->wl_surface = wl_compositor_create_surface(bg_state.wl_compositor);
+ bg->zwlr_surface = zwlr_layer_shell_v1_get_layer_surface(bg_state.zwlr_layer, bg->wl_surface, bg->wl_output, layer, namespace);
+
+ zwlr_layer_surface_v1_add_listener(bg->zwlr_surface, &layer_surface_listener, bg);
+
+ zwlr_layer_surface_v1_set_size(bg->zwlr_surface, bg->width, bg->height);
+ zwlr_layer_surface_v1_set_anchor(bg->zwlr_surface, anchor);
+
+ wl_surface_commit(bg->wl_surface);
+ wl_display_roundtrip(bg_state.wl_display);
+}
+
+void
+readimage()
+{
+ uint32_t buf[4];
+ size_t i;
+ size_t s = 0;
+ uint8_t r, g, b, a;
+ uint64_t *tmpbuf;
+ uint64_t color;
+ read(STDIN_FILENO, buf, sizeof(buf));
+
+ if (memcmp(buf, "farbfeld", sizeof("farbfeld") - 1)) {
+ die("input not farbfeld image");
+ }
+
+ img.width = ntohl(buf[2]);
+ img.height = ntohl(buf[3]);
+ img.buffer = malloc(img.width * img.height * sizeof(uint32_t));
+ tmpbuf = malloc(img.width * img.height * sizeof(uint64_t));
+
+ for (i = 0; i < ((size_t)img.width * img.height * sizeof(uint64_t));) {
+ i += read(STDIN_FILENO, (char*)(tmpbuf) + i, 1);
+ }
+
+ for (i = 0; i < img.width * img.height; ++i) {
+ color = tmpbuf[i];
+ a = ((color & (0xffffl << 48)) >> 48) / 257;
+ b = ((color & (0xffffl << 32)) >> 32) / 257;
+ g = ((color & (0xffffl << 16)) >> 16) / 257;
+ r = (color & 0xffffl) / 257;
+ img.buffer[i] = (a << 24) | (r << 16) | (g << 8) | b;
+ }
+
+ free(tmpbuf);
+}
+
+
+void
+setup()
+{
+ BG *bg;
+
+ bg_state.wl_display = wl_display_connect(NULL);
+ bg_state.wl_registry = wl_display_get_registry(bg_state.wl_display);
+ wl_registry_add_listener(bg_state.wl_registry, &wl_registry_listener, &bg_state);
+ wl_display_roundtrip(bg_state.wl_display);
+
+ for (bg = bgs; bg; bg = bg->next) {
+ register_bg(bg);
+ }
+
+ ready = 1;
+}
+
+
+void
+wayland_flush()
+{
+ int i;
+
+ wl_display_dispatch_pending(bg_state.wl_display);
+
+ if (wl_display_flush(bg_state.wl_display) < 0 && errno == EAGAIN) {
+ for (i = 0; i < 2; ++i) {
+ if (pollfds[i].fd == displayfd) {
+ pollfds[i].events |= POLLOUT;
+ }
+ }
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ readimage();
+ setup();
+
+ while (wl_display_dispatch(bg_state.wl_display)) {
+ }
+
+ return 0;
+}