aboutsummaryrefslogtreecommitdiff
path: root/dbar.c
diff options
context:
space:
mode:
Diffstat (limited to 'dbar.c')
-rw-r--r--dbar.c494
1 files changed, 494 insertions, 0 deletions
diff --git a/dbar.c b/dbar.c
new file mode 100644
index 0000000..80eaeaa
--- /dev/null
+++ b/dbar.c
@@ -0,0 +1,494 @@
+#define _POSIX_C_SOURCE 200112L
+#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 <sys/inotify.h>
+
+#include "drw.h"
+#include "util.h"
+
+/* type definitions */
+typedef struct Bar Bar;
+struct Bar {
+ unsigned width;
+ uint32_t seltag;
+ uint32_t urgtag;
+ uint32_t clients;
+ uint32_t active;
+ uint32_t layout;
+ char *progname;
+ uint32_t update_count;
+ Canvas *canvas;
+ struct zdwl_output_v1 *dwl_output;
+ struct wl_output *wl_output;
+ struct wl_surface *wl_surface;
+ struct zwlr_layer_surface_v1 *zwlr_surface;
+ Bar *next;
+};
+
+/* function declarations */
+static void update_bar(Bar *bar);
+static void wl_buffer_release(void *data, struct wl_buffer *wl_buffer);
+static void registry_global(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version);
+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 dwl_manager_tag(void *data, struct zdwl_manager_v1 *zdwl_manager_v1, const char *name);
+static void dwl_manager_layout(void *data, struct zdwl_manager_v1 *zdwl_manager_v1, const char *name);
+static void dwl_output_active(void *data, struct zdwl_output_v1 *zdwl_output_v1, uint32_t active);
+static void dwl_output_tag(void *data, struct zdwl_output_v1 *zdwl_output_v1, uint32_t tag, uint32_t state, uint32_t clients, uint32_t focused);
+static void dwl_output_title(void *data, struct zdwl_output_v1 *zdwl_output_v1, const char *title);
+static void dwl_output_layout(void *data, struct zdwl_output_v1 *zdwl_output_v1, uint32_t layout);
+static void dummy();
+static void wayland_flush();
+static void setup();
+struct wl_buffer *draw_frame(Bar *bar);
+static Bar *add_bar();
+
+
+/* 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 = dummy,
+};
+
+static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
+ .configure = layer_surface_configure,
+ .closed = layer_surface_closed
+};
+
+static const struct zdwl_manager_v1_listener dwl_manager_listener = {
+ .tag = dwl_manager_tag,
+ .layout = dwl_manager_layout,
+};
+
+static const struct zdwl_output_v1_listener dwl_output_listener = {
+ .toggle_visibility = dummy,
+ .active = dwl_output_active,
+ .tag = dwl_output_tag,
+ .layout = dwl_output_layout,
+ .title = dwl_output_title,
+ .appid = dummy,
+ .frame = dummy,
+};
+
+static Bar *bars = NULL;
+static char statusline[1024] = "";
+struct client_state bar_state = { 0 };
+struct pollfd pollfds[2];
+int displayfd;
+
+/* configuration */
+#include "config.h"
+
+/* function implementations */
+void
+wl_buffer_release(void *data, struct wl_buffer *wl_buffer)
+{
+ fprintf(stderr, "Buffer Release\n");
+ wl_buffer_destroy(wl_buffer);
+}
+
+
+struct wl_buffer *
+draw_frame(Bar *bar)
+{
+
+ Canvas *canvas = bar->canvas;
+
+ if (canvas == 0)
+ return 0;
+
+ struct wl_buffer *buffer = canvas->buffer;
+ Font *font = create_font(fontpath, (height - padding * 2) * 1.5);
+ unsigned w;
+ unsigned x = 0;
+ unsigned i = 0;
+ ListElement *tag;
+ ListElement *layout;
+
+ draw_rect(canvas, 0, 0, bar->width, height, background);
+
+ for (tag = bar_state.tags.first; tag; tag = tag->next) {
+ x += padding;
+
+ w = font_width(font, tag->name);
+
+ if (bar->urgtag & (1 << i)) {
+ draw_rect(canvas, x - padding, 0, w + 2 * padding, height, foreground);
+ draw_font(canvas, font, tag->name, x, height - padding, background);
+ } else {
+ if (bar->seltag & (1 << i)) {
+ draw_rect(canvas, x - padding, 0, w + 2 * padding, height, highlight);
+ }
+ draw_font(canvas, font, tag->name, x, height - padding, foreground);
+ }
+
+
+ x += padding + w;
+ ++i;
+ }
+
+ i = 0;
+ for (layout = bar_state.layouts.first; layout; layout = layout->next) {
+ if (i++ == bar->layout)
+ break;
+ }
+
+ x = draw_font(canvas, font, layout->name, x + padding, height - padding, foreground);
+
+ w = font_width(font, statusline);
+
+ x += 3 * padding;
+ x = draw_font(canvas, font, bar->progname, x, height - padding, foreground);
+
+ if (bar->active) {
+ draw_rect(canvas, bar->width - 2 * padding - w, 0, bar->width, height, highlight);
+ draw_font(canvas, font, statusline, bar->width - padding - w, height - padding, foreground);
+ }
+
+
+ free_font(font);
+ return buffer;
+}
+
+void
+update_bar(Bar *bar)
+{
+ struct wl_buffer *buffer = draw_frame(bar);
+
+ if (!buffer)
+ return;
+
+ wl_surface_attach(bar->wl_surface, buffer, 0, 0);
+ wl_surface_damage_buffer(bar->wl_surface, 0, 0, bar->width, height);
+ wl_surface_commit(bar->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;
+ Bar *bar;
+
+ 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, zdwl_manager_v1_interface.name) == 0) {
+ state->dwl_manager = wl_registry_bind(wl_registry, name, &zdwl_manager_v1_interface, 1);
+ } else if (strcmp(interface, wl_output_interface.name) == 0) {
+ bar = add_bar();
+ bar->wl_output = wl_registry_bind(wl_registry, name, &wl_output_interface, 1);
+ }
+}
+
+
+void
+layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface, uint32_t serial, uint32_t w, uint32_t h)
+{
+ Bar *bar = data;
+
+ bar->width = w;
+ height = h;
+
+ zwlr_layer_surface_v1_set_exclusive_zone(surface, height);
+ zwlr_layer_surface_v1_ack_configure(surface, serial);
+
+ bar->canvas = create_drw(bar_state.wl_shm, bar->width, height);
+
+ update_bar(bar);
+}
+
+
+void
+layer_surface_closed(void *data, struct zwlr_layer_surface_v1 *surface)
+{
+ Bar *bar = data;
+ zwlr_layer_surface_v1_destroy(surface);
+ wl_surface_destroy(bar->wl_surface);
+}
+
+void
+dwl_manager_tag(void *data, struct zdwl_manager_v1 *zdwl_manager_v1, const char *name)
+{
+ struct client_state *state = data;
+ ListElement *tag = state->tags.first;
+
+ ++state->tags.size;
+
+ if (state->tags.first == 0) {
+ state->tags.first = malloc(sizeof(ListElement));
+ state->tags.last = state->tags.first;
+ state->tags.first->name = malloc(strlen(name));
+ strcpy((char *)state->tags.first->name, name);
+ state->tags.first->next = 0;
+ state->tags.first->previous = 0;
+ return;
+ }
+
+ for (; tag->next; tag = tag->next);
+
+ tag->next = malloc(sizeof(ListElement));
+ tag->next->previous = tag;
+ tag = tag->next;
+ tag->name = malloc(strlen(name));
+ strcpy((char *)tag->name, name);
+ tag->next = 0;
+
+ state->tags.last = tag;
+}
+
+
+void
+dwl_manager_layout(void *data, struct zdwl_manager_v1 *zdwl_manager_v1, const char *name)
+{
+ struct client_state *state = data;
+ ListElement *layout = state->layouts.first;
+
+ ++state->layouts.size;
+
+ if (state->layouts.first == 0) {
+ state->layouts.first = malloc(sizeof(ListElement));
+ state->layouts.last = state->layouts.first;
+ state->layouts.first->name = malloc(strlen(name));
+ strcpy((char *)state->layouts.first->name, name);
+ state->layouts.first->next = 0;
+ state->layouts.first->previous = 0;
+ return;
+ }
+
+ for (; layout->next; layout = layout->next);
+
+ layout->next = malloc(sizeof(ListElement));
+ layout->next->previous = layout;
+ layout = layout->next;
+ layout->name = malloc(strlen(name));
+ strcpy((char *)layout->name, name);
+ layout->next = 0;
+
+ state->layouts.last = layout;
+}
+
+
+void
+dwl_output_active(void *data, struct zdwl_output_v1* zdwl_output_v1, uint32_t active)
+{
+ Bar *bar = data;
+ bar->active = active;
+ update_bar(bar);
+}
+
+
+void
+dwl_output_tag(void *data, struct zdwl_output_v1 *zdwl_output_v1, uint32_t tag, uint32_t state, uint32_t clients, uint32_t focused)
+{
+ Bar *bar = data;
+
+ if (state == ZDWL_OUTPUT_V1_TAG_STATE_ACTIVE) {
+ bar->seltag |= 1 << tag;
+ bar->urgtag &= ~(1 << tag);
+ } else if (state == ZDWL_OUTPUT_V1_TAG_STATE_URGENT) {
+ bar->urgtag |= 1 << tag;
+ bar->seltag &= ~(1 << tag);
+ } else {
+ bar->seltag &= ~(1 << tag);
+ bar->urgtag &= ~(1 << tag);
+ }
+
+ bar->clients = clients;
+
+ if (++bar->update_count == bar_state.tags.size) {
+ update_bar(bar);
+ }
+}
+
+
+void
+dwl_output_title(void *data, struct zdwl_output_v1 *zdwl_output_v1, const char *title)
+{
+ Bar *bar = data;
+
+ if (bar->progname)
+ free(bar->progname);
+
+ bar->progname = malloc(strlen(title));
+ strcpy(bar->progname, title);
+}
+
+
+void
+dwl_output_layout(void *data, struct zdwl_output_v1 *zdwl_output_v1, uint32_t layout)
+{
+ Bar *bar = data;
+ bar->layout = layout;
+ update_bar(bar);
+}
+
+
+void
+dummy()
+{
+ /* Who cares */
+}
+
+
+Bar *
+add_bar()
+{
+ Bar *bar = bars;
+
+ if (!bar) {
+ bars = malloc(sizeof(Bar));
+ memset(bars, 0, sizeof(Bar));
+ return bars;
+ }
+
+ for (; bar->next; bar = bar->next);
+
+ bar->next = malloc(sizeof(Bar));
+ memset(bar->next, 0, sizeof(Bar));
+
+ return bar->next;
+}
+
+
+void
+setup()
+{
+ Bar *bar;
+ char *namespace = "dbar";
+ uint32_t layer = ZWLR_LAYER_SHELL_V1_LAYER_TOP;
+ uint32_t anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
+
+ bar_state.wl_display = wl_display_connect(NULL);
+ bar_state.wl_registry = wl_display_get_registry(bar_state.wl_display);
+ wl_registry_add_listener(bar_state.wl_registry, &wl_registry_listener, &bar_state);
+ wl_display_roundtrip(bar_state.wl_display);
+
+ zdwl_manager_v1_add_listener(bar_state.dwl_manager, &dwl_manager_listener, &bar_state);
+ wl_display_roundtrip(bar_state.wl_display);
+
+ for (bar = bars; bar; bar = bar->next) {
+ bar->dwl_output = zdwl_manager_v1_get_output(bar_state.dwl_manager, bar->wl_output);
+ zdwl_output_v1_add_listener(bar->dwl_output, &dwl_output_listener, bar);
+
+ bar->wl_surface = wl_compositor_create_surface(bar_state.wl_compositor);
+ bar->zwlr_surface = zwlr_layer_shell_v1_get_layer_surface(bar_state.zwlr_layer, bar->wl_surface, bar->wl_output, layer, namespace);
+
+ zwlr_layer_surface_v1_add_listener(bar->zwlr_surface, &layer_surface_listener, bar);
+
+ zwlr_layer_surface_v1_set_size(bar->zwlr_surface, bar->width, height);
+ zwlr_layer_surface_v1_set_anchor(bar->zwlr_surface, anchor);
+
+ wl_surface_commit(bar->wl_surface);
+ wl_display_roundtrip(bar_state.wl_display);
+ }
+
+}
+
+
+void
+wayland_flush()
+{
+ int i;
+
+ wl_display_dispatch_pending(bar_state.wl_display);
+
+ if (wl_display_flush(bar_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[])
+{
+ Bar *bar;
+ int status;
+ struct inotify_event event;
+ char laststat[1024];
+ int s;
+ int i;
+ int inotify_fd = inotify_init1(IN_NONBLOCK);
+ int running = 1;
+
+ setup();
+
+ status = open(statusfile, O_CREAT, 0600);
+ close(status);
+
+ inotify_add_watch(inotify_fd, statusfile, IN_MODIFY);
+
+ displayfd = wl_display_get_fd(bar_state.wl_display);
+
+ pollfds[0].fd = inotify_fd;
+ pollfds[0].events = POLLIN;
+ pollfds[1].fd = displayfd;
+ pollfds[1].events = POLLIN;
+
+ status = open(statusfile, O_RDONLY);
+
+
+ while (running) {
+
+ wayland_flush();
+
+ if (poll(pollfds, 2, -1) > 0) {
+ for (i = 0; i < 2; ++i) {
+ if (pollfds[i].fd == inotify_fd && (pollfds[i].revents & POLLIN)) {
+ read(pollfds[i].fd, &event, sizeof(struct inotify_event));
+
+ if (event.mask & IN_MODIFY) {
+ lseek(status, 0, SEEK_SET);
+ s = read(status, statusline, 1024);
+ statusline[s - 1] = 0;
+
+ if (strcmp(laststat, statusline) != 0) {
+ for (bar = bars; bar; bar = bar->next)
+ update_bar(bar);
+ }
+
+ strcpy(laststat, statusline);
+ }
+
+ } else if (pollfds[i].fd == displayfd) {
+ if (pollfds[i].revents & POLLIN) {
+ if (wl_display_dispatch(bar_state.wl_display) < 0)
+ running = 0;
+ }
+
+ if (pollfds[i].revents & POLLOUT) {
+ pollfds[i].events = POLLIN;
+ wayland_flush();
+ }
+ }
+ }
+ }
+ }
+
+ close(status);
+
+ return 0;
+}