#define _POSIX_C_SOURCE 200112L #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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[256]; uint32_t update_count; uint32_t registry_name; 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 remove_bar(Bar *bar); 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 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 register_bar(Bar *bar); 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 = remove_global, }; 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; int ready = 0; /* 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); } if (bar->clients & (1 << i)) draw_rect(canvas, x - padding + 2, 2, 5, 5, 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); if (ready) { register_bar(bar); } } } void remove_global(void *data, struct wl_registry *wl_registry, uint32_t name) { Bar *bar = bars; Bar *prev = 0; for (; bar; bar = bar->next) { if (bar->registry_name == name) { if (prev) { prev->next = bar->next; } else { bars = bar->next; } remove_bar(bar); break; } prev = bar; } } 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); } if (clients) { bar->clients |= 1 << tag; } else { bar->clients &= ~(1 << tag); } 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; strncpy(bar->progname, title, 256); } 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 remove_bar(Bar *bar) { wl_surface_destroy(bar->wl_surface); zwlr_layer_surface_v1_destroy(bar->zwlr_surface); wl_output_destroy(bar->wl_output); zdwl_output_v1_destroy(bar->dwl_output); free_drw(bar->canvas); free(bar); } void register_bar(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->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 setup() { Bar *bar; 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) { register_bar(bar); } ready = 1; } 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; }