diff options
Diffstat (limited to 'dbar.c')
| -rw-r--r-- | dbar.c | 494 |
1 files changed, 494 insertions, 0 deletions
@@ -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; +} |