--- dwl.c +++ dwl.c @@ -1,10 +1,12 @@ /* * See LICENSE file for copyright and license details. */ +#include #include #include #include #include +#include #include #include #include @@ -79,14 +83,17 @@ #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) -#define TAGMASK ((1u << TAGCOUNT) - 1) +#define TAGMASK ((1u << LENGTH(tags)) - 1) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) #define LISTEN_STATIC(E, H) do { struct wl_listener *_l = ecalloc(1, sizeof(*_l)); _l->notify = (H); wl_signal_add((E), _l); } while (0) +#define TEXTW(mon, text) (drwl_font_getwidth(mon->drw, text) + mon->lrpad) /* enums */ +enum { SchemeNorm, SchemeSel, SchemeUrg }; /* color schemes */ enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ enum { XDGShell, LayerShell, X11 }; /* client types */ enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */ +enum { ClkTagBar, ClkLtSymbol, ClkStatus, ClkTitle, ClkClient, ClkRoot }; /* clicks */ typedef union { int i; @@ -309,6 +341,8 @@ static void destroypointerconstraint(struct wl_listener *listener, void *data); static void destroysessionlock(struct wl_listener *listener, void *data); static void destroykeyboardgroup(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); +static void drawbar(Monitor *m); +static void drawbars(void); static void focusclient(Client *c, int lift); static void focusmon(const Arg *arg); static void focusstack(const Arg *arg); @@ -661,17 +711,102 @@ axisnotify(struct wl_listener *listener, void *data) event->delta_discrete, event->source, event->relative_direction); } +bool +baracceptsinput(struct wlr_scene_buffer *buffer, double *sx, double *sy) +{ + return true; +} + +void +bufdestroy(struct wlr_buffer *wlr_buffer) +{ + Buffer *buf = wl_container_of(wlr_buffer, buf, base); + if (buf->busy) + wl_list_remove(&buf->release.link); + drwl_image_destroy(buf->image); + free(buf); +} + +bool +bufdatabegin(struct wlr_buffer *wlr_buffer, uint32_t flags, + void **data, uint32_t *format, size_t *stride) +{ + Buffer *buf = wl_container_of(wlr_buffer, buf, base); + + if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE) return false; + + *data = buf->data; + *stride = wlr_buffer->width * 4; + *format = DRM_FORMAT_ARGB8888; + + return true; +} + +void +bufdataend(struct wlr_buffer *wlr_buffer) +{ +} + +Buffer * +bufmon(Monitor *m) +{ + size_t i; + Buffer *buf = NULL; + + for (i = 0; i < LENGTH(m->pool); i++) { + if (m->pool[i]) { + if (m->pool[i]->busy) + continue; + buf = m->pool[i]; + break; + } + + buf = ecalloc(1, sizeof(Buffer) + (m->b.width * 4 * m->b.height)); + buf->image = drwl_image_create(NULL, m->b.width, m->b.height, buf->data); + wlr_buffer_init(&buf->base, &buffer_impl, m->b.width, m->b.height); + m->pool[i] = buf; + break; + } + if (!buf) + return NULL; + + buf->busy = true; + LISTEN(&buf->base.events.release, &buf->release, bufrelease); + wlr_buffer_lock(&buf->base); + drwl_setimage(m->drw, buf->image); + return buf; +} + +void +bufrelease(struct wl_listener *listener, void *data) +{ + Buffer *buf = wl_container_of(listener, buf, release); + buf->busy = false; + wl_list_remove(&buf->release.link); +} + void buttonpress(struct wl_listener *listener, void *data) { + unsigned int i = 0, x = 0; + double cx; + unsigned int click; struct wlr_pointer_button_event *event = data; struct wlr_keyboard *keyboard; + struct wlr_scene_node *node; + struct wlr_scene_buffer *buffer; uint32_t mods; + Arg arg = {0}; Client *c; const Button *b; wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + click = ClkRoot; + xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); + if (c) + click = ClkClient; + switch (event->state) { case WL_POINTER_BUTTON_STATE_PRESSED: cursor_mode = CurPressed; @@ -679,17 +814,34 @@ buttonpress(struct wl_listener *listener, void *data) if (locked) break; + if (!c && !exclusive_focus && + (node = wlr_scene_node_at(&layers[LyrBottom]->node, cursor->x, cursor->y, NULL, NULL)) && + (buffer = wlr_scene_buffer_from_node(node)) && buffer == selmon->scene_buffer) { + cx = (cursor->x - selmon->m.x) * selmon->wlr_output->scale; + do + x += TEXTW(selmon, tags[i]); + while (cx >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { + click = ClkTagBar; + arg.ui = 1 << i; + } else if (cx < x + TEXTW(selmon, selmon->ltsymbol)) + click = ClkLtSymbol; + else if (cx > selmon->b.width - (TEXTW(selmon, stext) - selmon->lrpad + 2)) { + click = ClkStatus; + } else + click = ClkTitle; + } + /* Change focus if the button was _pressed_ over a client */ xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL); - if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) + if (click == ClkClient && (!client_is_unmanaged(c) || client_wants_focus(c))) focusclient(c, 1); keyboard = wlr_seat_get_keyboard(seat); mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; for (b = buttons; b < END(buttons); b++) { - if (CLEANMASK(mods) == CLEANMASK(b->mod) && - event->button == b->button && b->func) { - b->func(&b->arg); + if (CLEANMASK(mods) == CLEANMASK(b->mod) && event->button == b->button && click == b->click && b->func) { + b->func(click == ClkTagBar && b->arg.i == 0 ? &arg : &b->arg); return; } } @@ -866,7 +1027,7 @@ closemon(Monitor *m) setmon(c, selmon, c->tags); } focusclient(focustop(selmon), 1); - printstatus(); + drawbars(); } void @@ -1566,13 +1808,13 @@ focusclient(Client *c, int lift) /* Don't change border color if there is an exclusive focus or we are * handling a drag operation */ if (!exclusive_focus && !seat->drag) - client_set_border_color(c, focuscolor); + client_set_border_color(c, (float[])COLOR(colors[SchemeSel][ColBorder])); } /* Deactivate old client if focus is changing */ if (old && (!c || client_surface(c) != old)) { /* If an overlay is focused, don't focus or activate the client, - * but only update its position in fstack to render its border with focuscolor + * but only update its position in fstack to render its border with its color * and focus it after the overlay is closed. */ if (old_client_type == LayerShell && wlr_scene_node_coords( &old_l->scene->node, &unused_lx, &unused_ly) @@ -1583,12 +1825,11 @@ focusclient(Client *c, int lift) /* Don't deactivate old client if the new one wants focus, as this causes issues with winecfg * and probably other clients */ } else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) { - client_set_border_color(old_c, bordercolor); - + client_set_border_color(old_c, (float[])COLOR(colors[SchemeNorm][ColBorder])); client_activate_surface(old, 0); } } - printstatus(); + drawbars(); if (!c) { /* With no client, all we have left is to clear focus */ @@ -2960,7 +3196,7 @@ unmapnotify(struct wl_listener *listener, void *data) } wlr_scene_node_destroy(&c->scene->node); - printstatus(); + drawbars(); motionnotify(0, NULL, 0, 0, 0, 0); } @@ -3077,12 +3320,45 @@ updatemons(struct wl_listener *listener, void *data) wlr_output_manager_v1_set_configuration(output_mgr, config); } +void +updatebar(Monitor *m) +{ + size_t i; + int rw, rh; + char fontattrs[12]; + + wlr_output_transformed_resolution(m->wlr_output, &rw, &rh); + m->b.width = rw; + m->b.real_width = (int)((float)m->b.width / m->wlr_output->scale); + + wlr_scene_node_set_enabled(&m->scene_buffer->node, m->wlr_output->enabled ? showbar : 0); + + for (i = 0; i < LENGTH(m->pool); i++) + if (m->pool[i]) { + wlr_buffer_drop(&m->pool[i]->base); + m->pool[i] = NULL; + } + + if (m->b.scale == m->wlr_output->scale && m->drw) + return; + + drwl_font_destroy(m->drw->font); + snprintf(fontattrs, sizeof(fontattrs), "dpi=%.2f", 96. * m->wlr_output->scale); + if (!(drwl_font_create(m->drw, LENGTH(fonts), fonts, fontattrs))) + die("Could not load font"); + + m->b.scale = m->wlr_output->scale; + m->lrpad = m->drw->font->height; + m->b.height = m->drw->font->height + 2; + m->b.real_height = (int)((float)m->b.height / m->wlr_output->scale); +} + void updatetitle(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, set_title); if (c == focustop(c->mon)) - printstatus(); + drawbars(); } void @@ -3152,6 +3428,7 @@ xytonode(double x, double y, struct wlr_surface **psurface, { struct wlr_scene_node *node, *pnode; struct wlr_surface *surface = NULL; + struct wlr_scene_surface *scene_surface = NULL; Client *c = NULL; LayerSurface *l = NULL; int layer; @@ -3160,9 +3437,12 @@ xytonode(double x, double y, struct wlr_surface **psurface, if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny))) continue; - if (node->type == WLR_SCENE_NODE_BUFFER) - surface = wlr_scene_surface_try_from_buffer( - wlr_scene_buffer_from_node(node))->surface; + if (node->type == WLR_SCENE_NODE_BUFFER) { + scene_surface = wlr_scene_surface_try_from_buffer( + wlr_scene_buffer_from_node(node)); + if (!scene_surface) continue; + surface = scene_surface->surface; + } /* Walk the tree to find a node that knows the client */ for (pnode = node; pnode && !c; pnode = &pnode->parent->node) c = pnode->data;