#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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); if (bg->canvas != 0) { free_drw(bg->canvas); } 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; }