kore / overlays / dwl / bar.patch1270 lines · 39218B · raw
1From 77b43f10b942abe9caab8a91d3a82923b1eb231c Mon Sep 17 00:00:00 2001
2From: sewn <[email protected]>
3Date: Mon, 5 Jan 2026 16:51:14 +0300
4Subject: [PATCH] Implement dwm bar clone
5
6---
7 Makefile | 2 +-
8 config.def.h | 33 ++--
9 drwl.h | 310 ++++++++++++++++++++++++++++++++++++
10 dwl.c | 441 +++++++++++++++++++++++++++++++++++++++++----------
11 4 files changed, 696 insertions(+), 90 deletions(-)
12 create mode 100644 drwl.h
13
14diff --git a/Makefile b/Makefile
15index 8304245..09ae285 100644
16--- a/Makefile
17+++ b/Makefile
18@@ -12,7 +12,7 @@ DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \
19 -Wfloat-conversion
20
21 # CFLAGS / LDFLAGS
22-PKGS = wayland-server xkbcommon libinput $(XLIBS)
23+PKGS = wayland-server xkbcommon libinput pixman-1 fcft $(XLIBS)
24 DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
25 LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
26
27diff --git a/config.def.h b/config.def.h
28index 13c5322..1fc6203 100644
29--- a/config.def.h
30+++ b/config.def.h
31@@ -8,15 +8,21 @@ static const int sloppyfocus = 1; /* focus follows mouse */
32 static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */
33 static const unsigned int borderpx = 1; /* border pixel of windows */
34 static const unsigned int snap = 32; /* snap pixel */
35-static const float rootcolor[] = COLOR(0x222222ff);
36-static const float bordercolor[] = COLOR(0x444444ff);
37-static const float focuscolor[] = COLOR(0x005577ff);
38-static const float urgentcolor[] = COLOR(0xff0000ff);
39+static const int showbar = 1; /* 0 means no bar */
40+static const int topbar = 1; /* 0 means bottom bar */
41+static const char *fonts[] = {"monospace:size=10"};
42+static const float rootcolor[] = COLOR(0x000000ff);
43 /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
44 static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
45+static uint32_t colors[][3] = {
46+ /* fg bg border */
47+ [SchemeNorm] = { 0xbbbbbbff, 0x222222ff, 0x444444ff },
48+ [SchemeSel] = { 0xeeeeeeff, 0x005577ff, 0x005577ff },
49+ [SchemeUrg] = { 0, 0, 0x770000ff },
50+};
51
52-/* tagging - TAGCOUNT must be no greater than 31 */
53-#define TAGCOUNT (9)
54+/* tagging */
55+static char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
56
57 /* logging */
58 static int log_level = WLR_ERROR;
59@@ -123,6 +129,7 @@ static const Key keys[] = {
60 /* modifier key function argument */
61 { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
62 { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
63+ { MODKEY, XKB_KEY_b, togglebar, {0} },
64 { MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
65 { MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
66 { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
67@@ -166,9 +173,17 @@ static const Key keys[] = {
68 };
69
70 static const Button buttons[] = {
71- { MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
72- { MODKEY, BTN_MIDDLE, togglefloating, {0} },
73- { MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
74+ { ClkLtSymbol, 0, BTN_LEFT, setlayout, {.v = &layouts[0]} },
75+ { ClkLtSymbol, 0, BTN_RIGHT, setlayout, {.v = &layouts[2]} },
76+ { ClkTitle, 0, BTN_MIDDLE, zoom, {0} },
77+ { ClkStatus, 0, BTN_MIDDLE, spawn, {.v = termcmd} },
78+ { ClkClient, MODKEY, BTN_LEFT, moveresize, {.ui = CurMove} },
79+ { ClkClient, MODKEY, BTN_MIDDLE, togglefloating, {0} },
80+ { ClkClient, MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
81+ { ClkTagBar, 0, BTN_LEFT, view, {0} },
82+ { ClkTagBar, 0, BTN_RIGHT, toggleview, {0} },
83+ { ClkTagBar, MODKEY, BTN_LEFT, tag, {0} },
84+ { ClkTagBar, MODKEY, BTN_RIGHT, toggletag, {0} },
85 };
86
87 static const Axis axes[] = {
88diff --git a/drwl.h b/drwl.h
89new file mode 100644
90index 0000000..21afd21
91--- /dev/null
92+++ b/drwl.h
93@@ -0,0 +1,310 @@
94+/*
95+ * drwl - https://codeberg.org/sewn/drwl
96+ *
97+ * Copyright (c) 2023-2025 sewn <[email protected]>
98+ * Copyright (c) 2024 notchoc <[email protected]>
99+ *
100+ * Permission is hereby granted, free of charge, to any person obtaining
101+ * a copy of this software and associated documentation files (the
102+ * "Software"), to deal in the Software without restriction, including
103+ * without limitation the rights to use, copy, modify, merge, publish,
104+ * distribute, sublicense, and/or sell copies of the Software, and to
105+ * permit persons to whom the Software is furnished to do so, subject to
106+ * the following conditions:
107+ *
108+ * The above copyright notice and this permission notice shall be
109+ * included in all copies or substantial portions of the Software.
110+ *
111+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
112+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
113+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
114+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
115+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
116+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
117+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
118+ *
119+ * The UTF-8 Decoder included is from Bjoern Hoehrmann:
120+ * Copyright (c) 2008-2010 Bjoern Hoehrmann <[email protected]>
121+ * See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
122+ */
123+#pragma once
124+
125+#include <stdlib.h>
126+#include <fcft/fcft.h>
127+#include <pixman-1/pixman.h>
128+
129+enum { ColFg, ColBg, ColBorder }; /* colorscheme index */
130+
131+typedef struct fcft_font Fnt;
132+typedef pixman_image_t Img;
133+
134+typedef struct {
135+ Img *image;
136+ Fnt *font;
137+ uint32_t *scheme;
138+} Drwl;
139+
140+#define UTF8_ACCEPT 0
141+#define UTF8_REJECT 12
142+#define UTF8_INVALID 0xFFFD
143+
144+static const uint8_t utf8d[] = {
145+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
146+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
147+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
148+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
149+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
150+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
151+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
152+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
153+
154+ 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
155+ 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
156+ 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
157+ 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
158+ 12,36,12,12,12,12,12,12,12,12,12,12,
159+};
160+
161+static inline uint32_t
162+utf8decode(uint32_t *state, uint32_t *codep, uint8_t byte)
163+{
164+ uint32_t type = utf8d[byte];
165+
166+ *codep = (*state != UTF8_ACCEPT) ?
167+ (byte & 0x3fu) | (*codep << 6) :
168+ (0xff >> type) & (byte);
169+
170+ *state = utf8d[256 + *state + type];
171+ return *state;
172+}
173+
174+static int
175+drwl_init(void)
176+{
177+ return fcft_init(FCFT_LOG_COLORIZE_AUTO, 0, FCFT_LOG_CLASS_ERROR);
178+}
179+
180+static Drwl *
181+drwl_create(void)
182+{
183+ Drwl *drwl;
184+
185+ if (!(drwl = calloc(1, sizeof(Drwl))))
186+ return NULL;
187+
188+ return drwl;
189+}
190+
191+static void
192+drwl_setfont(Drwl *drwl, Fnt *font)
193+{
194+ if (drwl)
195+ drwl->font = font;
196+}
197+
198+static void
199+drwl_setimage(Drwl *drwl, Img *image)
200+{
201+ if (drwl)
202+ drwl->image = image;
203+}
204+
205+static Fnt *
206+drwl_font_create(Drwl *drwl, size_t count,
207+ const char *names[static count], const char *attributes)
208+{
209+ Fnt *font = fcft_from_name(count, names, attributes);
210+ if (drwl)
211+ drwl_setfont(drwl, font);
212+ return font;
213+}
214+
215+static void
216+drwl_font_destroy(Fnt *font)
217+{
218+ fcft_destroy(font);
219+}
220+
221+static inline pixman_color_t
222+convert_color(uint32_t clr)
223+{
224+ return (pixman_color_t){
225+ ((clr >> 24) & 0xFF) * 0x101 * (clr & 0xFF) / 0xFF,
226+ ((clr >> 16) & 0xFF) * 0x101 * (clr & 0xFF) / 0xFF,
227+ ((clr >> 8) & 0xFF) * 0x101 * (clr & 0xFF) / 0xFF,
228+ (clr & 0xFF) * 0x101
229+ };
230+}
231+
232+static void
233+drwl_setscheme(Drwl *drwl, uint32_t *scm)
234+{
235+ if (drwl)
236+ drwl->scheme = scm;
237+}
238+
239+static Img *
240+drwl_image_create(Drwl *drwl, unsigned int w, unsigned int h, uint32_t *bits)
241+{
242+ Img *image;
243+ pixman_region32_t clip;
244+
245+ image = pixman_image_create_bits_no_clear(
246+ PIXMAN_a8r8g8b8, w, h, bits, w * 4);
247+ if (!image)
248+ return NULL;
249+ pixman_region32_init_rect(&clip, 0, 0, w, h);
250+ pixman_image_set_clip_region32(image, &clip);
251+ pixman_region32_fini(&clip);
252+
253+ if (drwl)
254+ drwl_setimage(drwl, image);
255+ return image;
256+}
257+
258+static void
259+drwl_rect(Drwl *drwl,
260+ int x, int y, unsigned int w, unsigned int h,
261+ int filled, int invert)
262+{
263+ pixman_color_t clr;
264+ if (!drwl || !drwl->scheme || !drwl->image)
265+ return;
266+
267+ clr = convert_color(drwl->scheme[invert ? ColBg : ColFg]);
268+ if (filled)
269+ pixman_image_fill_rectangles(PIXMAN_OP_SRC, drwl->image, &clr, 1,
270+ &(pixman_rectangle16_t){x, y, w, h});
271+ else
272+ pixman_image_fill_rectangles(PIXMAN_OP_SRC, drwl->image, &clr, 4,
273+ (pixman_rectangle16_t[4]){
274+ { x, y, w, 1 },
275+ { x, y + h - 1, w, 1 },
276+ { x, y, 1, h },
277+ { x + w - 1, y, 1, h }});
278+}
279+
280+static int
281+drwl_text(Drwl *drwl,
282+ int x, int y, unsigned int w, unsigned int h,
283+ unsigned int lpad, const char *text, int invert)
284+{
285+ int ty;
286+ int render = x || y || w || h;
287+ long x_kern;
288+ uint32_t cp = 0, last_cp = 0, state;
289+ pixman_color_t clr;
290+ pixman_image_t *fg_pix = NULL;
291+ int noellipsis = 0;
292+ const struct fcft_glyph *glyph, *eg = NULL;
293+ int fcft_subpixel_mode = FCFT_SUBPIXEL_DEFAULT;
294+
295+ if (!drwl || (render && (!drwl->scheme || !w || !drwl->image)) || !text || !drwl->font)
296+ return 0;
297+
298+ if (!render) {
299+ w = invert ? invert : ~invert;
300+ } else {
301+ clr = convert_color(drwl->scheme[invert ? ColBg : ColFg]);
302+ fg_pix = pixman_image_create_solid_fill(&clr);
303+
304+ drwl_rect(drwl, x, y, w, h, 1, !invert);
305+
306+ x += lpad;
307+ w -= lpad;
308+ }
309+
310+ if (render && (drwl->scheme[ColBg] & 0xFF) != 0xFF)
311+ fcft_subpixel_mode = FCFT_SUBPIXEL_NONE;
312+
313+ if (render)
314+ eg = fcft_rasterize_char_utf32(drwl->font, 0x2026 /* … */, fcft_subpixel_mode);
315+
316+ for (const char *p = text, *pp; pp = p, *p; p++) {
317+ for (state = UTF8_ACCEPT; *p &&
318+ utf8decode(&state, &cp, *p) > UTF8_REJECT; p++)
319+ ;
320+ if (!*p || state == UTF8_REJECT) {
321+ cp = UTF8_INVALID;
322+ if (p > pp)
323+ p--;
324+ }
325+
326+ glyph = fcft_rasterize_char_utf32(drwl->font, cp, fcft_subpixel_mode);
327+ if (!glyph)
328+ continue;
329+
330+ x_kern = 0;
331+ if (last_cp)
332+ fcft_kerning(drwl->font, last_cp, cp, &x_kern, NULL);
333+ last_cp = cp;
334+
335+ ty = y + (h - drwl->font->height) / 2 + drwl->font->ascent;
336+
337+ if (render && !noellipsis && x_kern + glyph->advance.x + eg->advance.x > w &&
338+ *(p + 1) != '\0') {
339+ /* cannot fit ellipsis after current codepoint */
340+ if (drwl_text(drwl, 0, 0, 0, 0, 0, pp, 0) + x_kern <= w) {
341+ noellipsis = 1;
342+ } else {
343+ w -= eg->advance.x;
344+ pixman_image_composite32(
345+ PIXMAN_OP_OVER, fg_pix, eg->pix, drwl->image, 0, 0, 0, 0,
346+ x + eg->x, ty - eg->y, eg->width, eg->height);
347+ }
348+ }
349+
350+ if ((x_kern + glyph->advance.x) > w)
351+ break;
352+
353+ x += x_kern;
354+
355+ if (render && pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8)
356+ /* pre-rendered glyphs (eg. emoji) */
357+ pixman_image_composite32(
358+ PIXMAN_OP_OVER, glyph->pix, NULL, drwl->image, 0, 0, 0, 0,
359+ x + glyph->x, ty - glyph->y, glyph->width, glyph->height);
360+ else if (render)
361+ pixman_image_composite32(
362+ PIXMAN_OP_OVER, fg_pix, glyph->pix, drwl->image, 0, 0, 0, 0,
363+ x + glyph->x, ty - glyph->y, glyph->width, glyph->height);
364+
365+ x += glyph->advance.x;
366+ w -= glyph->advance.x;
367+ }
368+
369+ if (render)
370+ pixman_image_unref(fg_pix);
371+
372+ return x + (render ? w : 0);
373+}
374+
375+static unsigned int
376+drwl_font_getwidth(Drwl *drwl, const char *text)
377+{
378+ if (!drwl || !drwl->font || !text)
379+ return 0;
380+ return drwl_text(drwl, 0, 0, 0, 0, 0, text, 0);
381+}
382+
383+static void
384+drwl_image_destroy(Img *image)
385+{
386+ pixman_image_unref(image);
387+}
388+
389+static void
390+drwl_destroy(Drwl *drwl)
391+{
392+ if (drwl->font)
393+ drwl_font_destroy(drwl->font);
394+ if (drwl->image)
395+ drwl_image_destroy(drwl->image);
396+ free(drwl);
397+}
398+
399+static void
400+drwl_fini(void)
401+{
402+ fcft_fini();
403+}
404diff --git a/dwl.c b/dwl.c
405index 4cfd0fd..751338b 100644
406--- a/dwl.c
407+++ b/dwl.c
408@@ -1,11 +1,13 @@
409 /*
410 * See LICENSE file for copyright and license details.
411 */
412+#include <fcntl.h>
413 #include <getopt.h>
414 #include <libinput.h>
415 #include <limits.h>
416 #include <linux/input-event-codes.h>
417 #include <math.h>
418+#include <libdrm/drm_fourcc.h>
419 #include <signal.h>
420 #include <stdio.h>
421 #include <stdlib.h>
422@@ -66,6 +68,7 @@
423 #include <wlr/types/wlr_xdg_decoration_v1.h>
424 #include <wlr/types/wlr_xdg_output_v1.h>
425 #include <wlr/types/wlr_xdg_shell.h>
426+#include <wlr/interfaces/wlr_buffer.h>
427 #include <wlr/util/log.h>
428 #include <wlr/util/region.h>
429 #include <xkbcommon/xkbcommon.h>
430@@ -77,20 +80,24 @@
431
432 #include "xdg-shell-protocol.h"
433 #include "util.h"
434+#include "drwl.h"
435
436 /* macros */
437 #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
438 #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
439-#define TAGMASK ((1u << TAGCOUNT) - 1)
440+#define TAGMASK ((1u << LENGTH(tags)) - 1)
441 #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L)))
442 #define LISTEN_STATIC(E, H) do { struct wl_listener *_l = ecalloc(1, sizeof(*_l)); _l->notify = (H); wl_signal_add((E), _l); } while (0)
443+#define TEXTW(mon, text) (drwl_font_getwidth(mon->drw, text) + mon->lrpad)
444
445 /* enums */
446+enum { SchemeNorm, SchemeSel, SchemeUrg }; /* color schemes */
447 enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
448 enum { XDGShell, LayerShell, X11 }; /* client types */
449 enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrUnmanaged, LyrOverlay,
450 LyrIMPopup, LyrBlock, NUM_LAYERS }; /* scene layers */
451 enum { AxisUp, AxisRight, AxisDown, AxisLeft };
452+enum { ClkTagBar, ClkLtSymbol, ClkStatus, ClkTitle, ClkClient, ClkRoot }; /* clicks */
453
454 typedef union {
455 int i;
456@@ -107,6 +114,7 @@ typedef struct {
457 } Axis;
458
459 typedef struct {
460+ unsigned int click;
461 unsigned int mod;
462 unsigned int button;
463 void (*func)(const Arg *);
464@@ -203,10 +211,19 @@ typedef struct {
465 void (*arrange)(Monitor *);
466 } Layout;
467
468+typedef struct {
469+ struct wlr_buffer base;
470+ struct wl_listener release;
471+ bool busy;
472+ Img *image;
473+ uint32_t data[];
474+} Buffer;
475+
476 struct Monitor {
477 struct wl_list link;
478 struct wlr_output *wlr_output;
479 struct wlr_scene_output *scene_output;
480+ struct wlr_scene_buffer *scene_buffer; /* bar buffer */
481 struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
482 struct wl_listener frame;
483 struct wl_listener destroy;
484@@ -214,6 +231,11 @@ struct Monitor {
485 struct wl_listener destroy_lock_surface;
486 struct wlr_session_lock_surface_v1 *lock_surface;
487 struct wlr_box m; /* monitor area, layout-relative */
488+ struct {
489+ int width, height;
490+ int real_width, real_height; /* non-scaled */
491+ float scale;
492+ } b; /* bar area */
493 struct wlr_box w; /* window area, layout-relative */
494 struct wl_list layers[4]; /* LayerSurface.link */
495 const Layout *lt[2];
496@@ -225,6 +247,9 @@ struct Monitor {
497 int nmaster;
498 char ltsymbol[16];
499 int asleep;
500+ Drwl *drw;
501+ Buffer *pool[2];
502+ int lrpad;
503 };
504
505 typedef struct {
506@@ -267,6 +292,13 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
507 struct wlr_box *usable_area, int exclusive);
508 static void arrangelayers(Monitor *m);
509 static void axisnotify(struct wl_listener *listener, void *data);
510+static bool baracceptsinput(struct wlr_scene_buffer *buffer, double *sx, double *sy);
511+static void bufdestroy(struct wlr_buffer *buffer);
512+static bool bufdatabegin(struct wlr_buffer *buffer, uint32_t flags,
513+ void **data, uint32_t *format, size_t *stride);
514+static void bufdataend(struct wlr_buffer *buffer);
515+static Buffer *bufmon(Monitor *m);
516+static void bufrelease(struct wl_listener *listener, void *data);
517 static void buttonpress(struct wl_listener *listener, void *data);
518 static void capturerequest(struct wl_listener *listener, void *data);
519 static void chvt(const Arg *arg);
520@@ -303,6 +335,8 @@ static void destroypointerconstraint(struct wl_listener *listener, void *data);
521 static void destroysessionlock(struct wl_listener *listener, void *data);
522 static void destroykeyboardgroup(struct wl_listener *listener, void *data);
523 static Monitor *dirtomon(enum wlr_direction dir);
524+static void drawbar(Monitor *m);
525+static void drawbars(void);
526 static void focusclient(Client *c, int lift);
527 static void focusmon(const Arg *arg);
528 static void focusstack(const Arg *arg);
529@@ -331,7 +365,6 @@ static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int
530 static void outputmgrtest(struct wl_listener *listener, void *data);
531 static void pointerfocus(Client *c, LayerSurface* l, struct wlr_surface *surface,
532 double sx, double sy, uint32_t time);
533-static void printstatus(void);
534 static void powermgrsetmode(struct wl_listener *listener, void *data);
535 static void quit(const Arg *arg);
536 static void rendermon(struct wl_listener *listener, void *data);
537@@ -352,9 +385,11 @@ static void setsel(struct wl_listener *listener, void *data);
538 static void setup(void);
539 static void spawn(const Arg *arg);
540 static void startdrag(struct wl_listener *listener, void *data);
541+static int statusin(int fd, unsigned int mask, void *data);
542 static void tag(const Arg *arg);
543 static void tagmon(const Arg *arg);
544 static void tile(Monitor *m);
545+static void togglebar(const Arg *arg);
546 static void togglefloating(const Arg *arg);
547 static void togglefullscreen(const Arg *arg);
548 static void toggletag(const Arg *arg);
549@@ -363,6 +398,7 @@ static void unlocksession(struct wl_listener *listener, void *data);
550 static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
551 static void unmapnotify(struct wl_listener *listener, void *data);
552 static void updatemons(struct wl_listener *listener, void *data);
553+static void updatebar(Monitor *m);
554 static void updatetitle(struct wl_listener *listener, void *data);
555 static void urgent(struct wl_listener *listener, void *data);
556 static void view(const Arg *arg);
557@@ -431,6 +467,15 @@ static struct wl_list mons;
558 static Monitor *selmon;
559 static int consumed[KEY_MAX + 1];
560
561+static char stext[256];
562+static struct wl_event_source *status_event_source;
563+
564+static const struct wlr_buffer_impl buffer_impl = {
565+ .destroy = bufdestroy,
566+ .begin_data_ptr_access = bufdatabegin,
567+ .end_data_ptr_access = bufdataend,
568+};
569+
570 /* global event handlers */
571 static struct wl_listener cursor_axis = {.notify = axisnotify};
572 static struct wl_listener cursor_button = {.notify = buttonpress};
573@@ -565,7 +610,7 @@ arrange(Monitor *m)
574 wlr_scene_node_set_enabled(&m->fullscreen_bg->node,
575 (c = focustop(m)) && c->isfullscreen);
576
577- strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
578+ strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof(m->ltsymbol));
579
580 /* We move all clients (except fullscreen and unmanaged) to LyrTile while
581 * in floating layout to avoid "real" floating clients be always on top */
582@@ -620,6 +665,11 @@ arrangelayers(Monitor *m)
583 if (!m->wlr_output->enabled)
584 return;
585
586+ if (m->scene_buffer->node.enabled) {
587+ usable_area.height -= m->b.real_height;
588+ usable_area.y += topbar ? m->b.real_height : 0;
589+ }
590+
591 /* Arrange exclusive surfaces from top->bottom */
592 for (i = 3; i >= 0; i--)
593 arrangelayer(m, &m->layers[i], &usable_area, 1);
594@@ -682,18 +732,103 @@ axisnotify(struct wl_listener *listener, void *data)
595 event->delta_discrete, event->source, event->relative_direction);
596 }
597
598+bool
599+baracceptsinput(struct wlr_scene_buffer *buffer, double *sx, double *sy)
600+{
601+ return true;
602+}
603+
604+void
605+bufdestroy(struct wlr_buffer *wlr_buffer)
606+{
607+ Buffer *buf = wl_container_of(wlr_buffer, buf, base);
608+ if (buf->busy)
609+ wl_list_remove(&buf->release.link);
610+ drwl_image_destroy(buf->image);
611+ free(buf);
612+}
613+
614+bool
615+bufdatabegin(struct wlr_buffer *wlr_buffer, uint32_t flags,
616+ void **data, uint32_t *format, size_t *stride)
617+{
618+ Buffer *buf = wl_container_of(wlr_buffer, buf, base);
619+
620+ if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE) return false;
621+
622+ *data = buf->data;
623+ *stride = wlr_buffer->width * 4;
624+ *format = DRM_FORMAT_ARGB8888;
625+
626+ return true;
627+}
628+
629+void
630+bufdataend(struct wlr_buffer *wlr_buffer)
631+{
632+}
633+
634+Buffer *
635+bufmon(Monitor *m)
636+{
637+ size_t i;
638+ Buffer *buf = NULL;
639+
640+ for (i = 0; i < LENGTH(m->pool); i++) {
641+ if (m->pool[i]) {
642+ if (m->pool[i]->busy)
643+ continue;
644+ buf = m->pool[i];
645+ break;
646+ }
647+
648+ buf = ecalloc(1, sizeof(Buffer) + (m->b.width * 4 * m->b.height));
649+ buf->image = drwl_image_create(NULL, m->b.width, m->b.height, buf->data);
650+ wlr_buffer_init(&buf->base, &buffer_impl, m->b.width, m->b.height);
651+ m->pool[i] = buf;
652+ break;
653+ }
654+ if (!buf)
655+ return NULL;
656+
657+ buf->busy = true;
658+ LISTEN(&buf->base.events.release, &buf->release, bufrelease);
659+ wlr_buffer_lock(&buf->base);
660+ drwl_setimage(m->drw, buf->image);
661+ return buf;
662+}
663+
664+void
665+bufrelease(struct wl_listener *listener, void *data)
666+{
667+ Buffer *buf = wl_container_of(listener, buf, release);
668+ buf->busy = false;
669+ wl_list_remove(&buf->release.link);
670+}
671+
672 void
673 buttonpress(struct wl_listener *listener, void *data)
674 {
675+ unsigned int i = 0, x = 0;
676+ double cx;
677+ unsigned int click;
678 struct wlr_pointer_button_event *event = data;
679 struct wlr_keyboard *keyboard;
680+ struct wlr_scene_node *node;
681+ struct wlr_scene_buffer *buffer;
682 uint32_t mods;
683+ Arg arg = {0};
684 Client *c = NULL;
685 LayerSurface *l = NULL;
686 const Button *b;
687
688 wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
689
690+ click = ClkRoot;
691+ xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL);
692+ if (c)
693+ click = ClkClient;
694+
695 switch (event->state) {
696 case WL_POINTER_BUTTON_STATE_PRESSED:
697 cursor_mode = CurPressed;
698@@ -701,10 +836,28 @@ buttonpress(struct wl_listener *listener, void *data)
699 if (locked)
700 break;
701
702+ if (!c && !exclusive_focus &&
703+ (node = wlr_scene_node_at(&layers[LyrBottom]->node, cursor->x, cursor->y, NULL, NULL)) &&
704+ (buffer = wlr_scene_buffer_from_node(node)) && buffer == selmon->scene_buffer) {
705+ cx = (cursor->x - selmon->m.x) * selmon->wlr_output->scale;
706+ do
707+ x += TEXTW(selmon, tags[i]);
708+ while (cx >= x && ++i < LENGTH(tags));
709+ if (i < LENGTH(tags)) {
710+ click = ClkTagBar;
711+ arg.ui = 1 << i;
712+ } else if (cx < x + TEXTW(selmon, selmon->ltsymbol))
713+ click = ClkLtSymbol;
714+ else if (cx > selmon->b.width - (TEXTW(selmon, stext) - selmon->lrpad + 2)) {
715+ click = ClkStatus;
716+ } else
717+ click = ClkTitle;
718+ }
719+
720 /* Change focus if the button was _pressed_ over a client
721 or a layer surface with on-demand keyboard interactivity */
722 xytonode(cursor->x, cursor->y, NULL, &c, &l, NULL, NULL);
723- if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) {
724+ if (click == ClkClient && c && (!client_is_unmanaged(c) || client_wants_focus(c))) {
725 focusclient(c, 1);
726 } else if (l && l->layer_surface->current.keyboard_interactive) {
727 focusclient(NULL, 0);
728@@ -714,9 +867,8 @@ buttonpress(struct wl_listener *listener, void *data)
729 keyboard = wlr_seat_get_keyboard(seat);
730 mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
731 for (b = buttons; b < END(buttons); b++) {
732- if (CLEANMASK(mods) == CLEANMASK(b->mod) &&
733- event->button == b->button && b->func) {
734- b->func(&b->arg);
735+ if (CLEANMASK(mods) == CLEANMASK(b->mod) && event->button == b->button && click == b->click && b->func) {
736+ b->func(click == ClkTagBar && b->arg.i == 0 ? &arg : &b->arg);
737 return;
738 }
739 }
740@@ -814,6 +966,8 @@ cleanup(void)
741 /* Destroy after the wayland display (when the monitors are already destroyed)
742 to avoid destroying them with an invalid scene output. */
743 wlr_scene_node_destroy(&scene->tree.node);
744+
745+ drwl_fini();
746 }
747
748 void
749@@ -829,6 +983,12 @@ cleanupmon(struct wl_listener *listener, void *data)
750 wlr_layer_surface_v1_destroy(l->layer_surface);
751 }
752
753+ for (i = 0; i < LENGTH(m->pool); i++)
754+ wlr_buffer_drop(&m->pool[i]->base);
755+
756+ drwl_setimage(m->drw, NULL);
757+ drwl_destroy(m->drw);
758+
759 wl_list_remove(&m->destroy.link);
760 wl_list_remove(&m->frame.link);
761 wl_list_remove(&m->link);
762@@ -841,6 +1001,7 @@ cleanupmon(struct wl_listener *listener, void *data)
763
764 closemon(m);
765 wlr_scene_node_destroy(&m->fullscreen_bg->node);
766+ wlr_scene_node_destroy(&m->scene_buffer->node);
767 free(m);
768 }
769
770@@ -908,7 +1069,7 @@ closemon(Monitor *m)
771 setmon(c, selmon, c->tags);
772 }
773 focusclient(focustop(selmon), 1);
774- printstatus();
775+ drawbars();
776 }
777
778 void
779@@ -1164,7 +1325,7 @@ createmon(struct wl_listener *listener, void *data)
780 m->nmaster = r->nmaster;
781 m->lt[0] = r->lt;
782 m->lt[1] = &layouts[LENGTH(layouts) > 1 && r->lt != &layouts[1]];
783- strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, LENGTH(m->ltsymbol));
784+ strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof(m->ltsymbol));
785 wlr_output_state_set_scale(&state, r->scale);
786 wlr_output_state_set_transform(&state, r->rr);
787 break;
788@@ -1186,8 +1347,15 @@ createmon(struct wl_listener *listener, void *data)
789 wlr_output_commit_state(wlr_output, &state);
790 wlr_output_state_finish(&state);
791
792+ if (!(m->drw = drwl_create()))
793+ die("failed to create drwl context");
794+
795+ m->scene_buffer = wlr_scene_buffer_create(layers[LyrBottom], NULL);
796+ m->scene_buffer->point_accepts_input = baracceptsinput;
797+ updatebar(m);
798+
799 wl_list_insert(&mons, &m->link);
800- printstatus();
801+ drawbars();
802
803 /* The xdg-protocol specifies:
804 *
805@@ -1504,6 +1672,80 @@ dirtomon(enum wlr_direction dir)
806 return selmon;
807 }
808
809+void
810+drawbar(Monitor *m)
811+{
812+ int x, w, tw = 0;
813+ int boxs = m->drw->font->height / 9;
814+ int boxw = m->drw->font->height / 6 + 2;
815+ uint32_t i, occ = 0, urg = 0;
816+ Client *c;
817+ Buffer *buf;
818+
819+ if (!m->scene_buffer->node.enabled)
820+ return;
821+ if (!(buf = bufmon(m)))
822+ return;
823+
824+ /* draw status first so it can be overdrawn by tags later */
825+ if (m == selmon) { /* status is only drawn on selected monitor */
826+ drwl_setscheme(m->drw, colors[SchemeNorm]);
827+ tw = TEXTW(m, stext) - m->lrpad + 2; /* 2px right padding */
828+ drwl_text(m->drw, m->b.width - tw, 0, tw, m->b.height, 0, stext, 0);
829+ }
830+
831+ wl_list_for_each(c, &clients, link) {
832+ if (c->mon != m)
833+ continue;
834+ occ |= c->tags;
835+ if (c->isurgent)
836+ urg |= c->tags;
837+ }
838+ x = 0;
839+ c = focustop(m);
840+ for (i = 0; i < LENGTH(tags); i++) {
841+ w = TEXTW(m, tags[i]);
842+ drwl_setscheme(m->drw, colors[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
843+ drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, tags[i], urg & 1 << i);
844+ if (occ & 1 << i)
845+ drwl_rect(m->drw, x + boxs, boxs, boxw, boxw,
846+ m == selmon && c && c->tags & 1 << i,
847+ urg & 1 << i);
848+ x += w;
849+ }
850+ w = TEXTW(m, m->ltsymbol);
851+ drwl_setscheme(m->drw, colors[SchemeNorm]);
852+ x = drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0);
853+
854+ if ((w = m->b.width - tw - x) > m->b.height) {
855+ if (c) {
856+ drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]);
857+ drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, client_get_title(c), 0);
858+ if (c && c->isfloating)
859+ drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0);
860+ } else {
861+ drwl_setscheme(m->drw, colors[SchemeNorm]);
862+ drwl_rect(m->drw, x, 0, w, m->b.height, 1, 1);
863+ }
864+ }
865+
866+ wlr_scene_buffer_set_dest_size(m->scene_buffer,
867+ m->b.real_width, m->b.real_height);
868+ wlr_scene_node_set_position(&m->scene_buffer->node, m->m.x,
869+ m->m.y + (topbar ? 0 : m->m.height - m->b.real_height));
870+ wlr_scene_buffer_set_buffer(m->scene_buffer, &buf->base);
871+ wlr_buffer_unlock(&buf->base);
872+}
873+
874+void
875+drawbars(void)
876+{
877+ Monitor *m = NULL;
878+
879+ wl_list_for_each(m, &mons, link)
880+ drawbar(m);
881+}
882+
883 void
884 focusclient(Client *c, int lift)
885 {
886@@ -1541,7 +1783,7 @@ focusclient(Client *c, int lift)
887 /* Don't change border color if there is an exclusive focus or we are
888 * handling a drag operation */
889 if (!exclusive_focus && !seat->drag)
890- client_set_border_color(c, focuscolor);
891+ client_set_border_color(c, (float[])COLOR(colors[SchemeSel][ColBorder]));
892 }
893
894 /* If an overlay is focused, don't focus or activate the client,
895@@ -1557,12 +1799,12 @@ focusclient(Client *c, int lift)
896 if (focused_client && focused_client != c && !(c && client_is_unmanaged(c))) {
897 struct wlr_surface *s = client_surface(focused_client);
898 if (c)
899- client_set_border_color(focused_client, bordercolor);
900+ client_set_border_color(focused_client, (float[])COLOR(colors[SchemeNorm][ColBorder]));
901 if (s && s->mapped)
902 client_activate_surface(s, 0);
903 focused_client = NULL;
904 }
905- printstatus();
906+ drawbars();
907
908 if (!c) {
909 /* With no client, all we have left is to clear focus */
910@@ -1898,7 +2140,7 @@ mapnotify(struct wl_listener *listener, void *data)
911
912 for (i = 0; i < 4; i++) {
913 c->border[i] = wlr_scene_rect_create(c->scene, 0, 0,
914- c->isurgent ? urgentcolor : bordercolor);
915+ (float[])COLOR(colors[c->isurgent ? SchemeUrg : SchemeNorm][ColBorder]));
916 c->border[i]->node.data = c;
917 }
918
919@@ -1932,7 +2174,7 @@ mapnotify(struct wl_listener *listener, void *data)
920 } else {
921 applyrules(c);
922 }
923- printstatus();
924+ drawbars();
925
926 unset_fullscreen:
927 m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y);
928@@ -2253,44 +2495,6 @@ pointerfocus(Client *c, LayerSurface *l, struct wlr_surface *surface, double sx,
929 wlr_seat_pointer_notify_motion(seat, time, sx, sy);
930 }
931
932-void
933-printstatus(void)
934-{
935- Monitor *m = NULL;
936- Client *c;
937- uint32_t occ, urg, sel;
938-
939- wl_list_for_each(m, &mons, link) {
940- occ = urg = 0;
941- wl_list_for_each(c, &clients, link) {
942- if (c->mon != m)
943- continue;
944- occ |= c->tags;
945- if (c->isurgent)
946- urg |= c->tags;
947- }
948- if ((c = focustop(m))) {
949- printf("%s title %s\n", m->wlr_output->name, client_get_title(c));
950- printf("%s appid %s\n", m->wlr_output->name, client_get_appid(c));
951- printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen);
952- printf("%s floating %d\n", m->wlr_output->name, c->isfloating);
953- sel = c->tags;
954- } else {
955- printf("%s title \n", m->wlr_output->name);
956- printf("%s appid \n", m->wlr_output->name);
957- printf("%s fullscreen \n", m->wlr_output->name);
958- printf("%s floating \n", m->wlr_output->name);
959- sel = 0;
960- }
961-
962- printf("%s selmon %u\n", m->wlr_output->name, m == selmon);
963- printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n",
964- m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg);
965- printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol);
966- }
967- fflush(stdout);
968-}
969-
970 void
971 powermgrsetmode(struct wl_listener *listener, void *data)
972 {
973@@ -2408,22 +2612,14 @@ run(char *startup_cmd)
974
975 /* Now that the socket exists and the backend is started, run the startup command */
976 if (startup_cmd) {
977- int piperw[2];
978- if (pipe(piperw) < 0)
979- die("startup: pipe:");
980 if ((child_pid = fork()) < 0)
981 die("startup: fork:");
982 if (child_pid == 0) {
983+ close(STDIN_FILENO);
984 setsid();
985- dup2(piperw[0], STDIN_FILENO);
986- close(piperw[0]);
987- close(piperw[1]);
988 execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);
989 die("startup: execl:");
990 }
991- dup2(piperw[1], STDOUT_FILENO);
992- close(piperw[1]);
993- close(piperw[0]);
994 }
995
996 /* Mark stdout as non-blocking to avoid the startup script
997@@ -2433,7 +2629,7 @@ run(char *startup_cmd)
998 if (fd_set_nonblock(STDOUT_FILENO) < 0)
999 close(STDOUT_FILENO);
1000
1001- printstatus();
1002+ drawbars();
1003
1004 /* At this point the outputs are initialized, choose initial selmon based on
1005 * cursor position, and set default cursor image */
1006@@ -2499,7 +2695,7 @@ setfloating(Client *c, int floating)
1007 (p && p->isfullscreen) ? LyrFS
1008 : c->isfloating ? LyrFloat : LyrTile]);
1009 arrange(c->mon);
1010- printstatus();
1011+ drawbars();
1012 }
1013
1014 void
1015@@ -2522,7 +2718,7 @@ setfullscreen(Client *c, int fullscreen)
1016 resize(c, c->prev, 0);
1017 }
1018 arrange(c->mon);
1019- printstatus();
1020+ drawbars();
1021 }
1022
1023 void
1024@@ -2534,9 +2730,9 @@ setlayout(const Arg *arg)
1025 selmon->sellt ^= 1;
1026 if (arg && arg->v)
1027 selmon->lt[selmon->sellt] = (Layout *)arg->v;
1028- strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol));
1029+ strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof(selmon->ltsymbol));
1030 arrange(selmon);
1031- printstatus();
1032+ drawbar(selmon);
1033 }
1034
1035 /* arg > 1.0 will set mfact absolutely */
1036@@ -2609,6 +2805,7 @@ setup(void)
1037 for (i = 0; i < (int)LENGTH(sig); i++)
1038 sigaction(sig[i], &sa, NULL);
1039
1040+
1041 wlr_log_init(log_level, NULL);
1042
1043 /* The Wayland display is managed by libwayland. It handles accepting
1044@@ -2816,6 +3013,11 @@ setup(void)
1045 text_input_manager = wlr_text_input_manager_v3_create(dpy);
1046 input_method_relay = input_method_relay_create();
1047
1048+ drwl_init();
1049+
1050+ status_event_source = wl_event_loop_add_fd(wl_display_get_event_loop(dpy),
1051+ STDIN_FILENO, WL_EVENT_READABLE, statusin, NULL);
1052+
1053 /* Make sure XWayland clients don't connect to the parent X server,
1054 * e.g when running in the x11 backend or the wayland backend and the
1055 * compositor has Xwayland support */
1056@@ -2840,6 +3042,8 @@ void
1057 spawn(const Arg *arg)
1058 {
1059 if (fork() == 0) {
1060+ close(STDIN_FILENO);
1061+ open("/dev/null", O_RDWR);
1062 dup2(STDERR_FILENO, STDOUT_FILENO);
1063 setsid();
1064 execvp(((char **)arg->v)[0], (char **)arg->v);
1065@@ -2858,6 +3062,30 @@ startdrag(struct wl_listener *listener, void *data)
1066 LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon);
1067 }
1068
1069+int
1070+statusin(int fd, unsigned int mask, void *data)
1071+{
1072+ char status[256];
1073+ ssize_t n;
1074+
1075+ if (mask & WL_EVENT_ERROR)
1076+ die("status in event error");
1077+ if (mask & WL_EVENT_HANGUP)
1078+ wl_event_source_remove(status_event_source);
1079+
1080+ n = read(fd, status, sizeof(status) - 1);
1081+ if (n < 0 && errno != EWOULDBLOCK)
1082+ die("read:");
1083+
1084+ status[n] = '\0';
1085+ status[strcspn(status, "\n")] = '\0';
1086+
1087+ strncpy(stext, status, sizeof(stext));
1088+ drawbars();
1089+
1090+ return 0;
1091+}
1092+
1093 void
1094 tag(const Arg *arg)
1095 {
1096@@ -2868,7 +3096,7 @@ tag(const Arg *arg)
1097 sel->tags = arg->ui & TAGMASK;
1098 focusclient(focustop(selmon), 1);
1099 arrange(selmon);
1100- printstatus();
1101+ drawbars();
1102 }
1103
1104 void
1105@@ -2913,6 +3141,15 @@ tile(Monitor *m)
1106 }
1107 }
1108
1109+void
1110+togglebar(const Arg *arg)
1111+{
1112+ wlr_scene_node_set_enabled(&selmon->scene_buffer->node,
1113+ !selmon->scene_buffer->node.enabled);
1114+ arrangelayers(selmon);
1115+ drawbars();
1116+}
1117+
1118 void
1119 togglefloating(const Arg *arg)
1120 {
1121@@ -2941,7 +3178,7 @@ toggletag(const Arg *arg)
1122 sel->tags = newtags;
1123 focusclient(focustop(selmon), 1);
1124 arrange(selmon);
1125- printstatus();
1126+ drawbars();
1127 }
1128
1129 void
1130@@ -2954,7 +3191,7 @@ toggleview(const Arg *arg)
1131 selmon->tagset[selmon->seltags] = newtagset;
1132 focusclient(focustop(selmon), 1);
1133 arrange(selmon);
1134- printstatus();
1135+ drawbars();
1136 }
1137
1138 void
1139@@ -3019,7 +3256,7 @@ unmapnotify(struct wl_listener *listener, void *data)
1140 c->image_capture_source = NULL;
1141 wlr_scene_node_destroy(&c->scene->node);
1142 client_surface(c)->data = NULL;
1143- printstatus();
1144+ drawbars();
1145 motionnotify(0, NULL, 0, 0, 0, 0);
1146 }
1147
1148@@ -3122,6 +3359,13 @@ updatemons(struct wl_listener *listener, void *data)
1149 }
1150 }
1151
1152+ if (stext[0] == '\0')
1153+ strncpy(stext, "dwl-"VERSION, sizeof(stext));
1154+ wl_list_for_each(m, &mons, link) {
1155+ updatebar(m);
1156+ drawbar(m);
1157+ }
1158+
1159 /* FIXME: figure out why the cursor image is at 0,0 after turning all
1160 * the monitors on.
1161 * Move the cursor image where it used to be. It does not generate a
1162@@ -3132,12 +3376,45 @@ updatemons(struct wl_listener *listener, void *data)
1163 wlr_output_manager_v1_set_configuration(output_mgr, config);
1164 }
1165
1166+void
1167+updatebar(Monitor *m)
1168+{
1169+ size_t i;
1170+ int rw, rh;
1171+ char fontattrs[12];
1172+
1173+ wlr_output_transformed_resolution(m->wlr_output, &rw, &rh);
1174+ m->b.width = rw;
1175+ m->b.real_width = (int)((float)m->b.width / m->wlr_output->scale);
1176+
1177+ wlr_scene_node_set_enabled(&m->scene_buffer->node, m->wlr_output->enabled ? showbar : 0);
1178+
1179+ for (i = 0; i < LENGTH(m->pool); i++)
1180+ if (m->pool[i]) {
1181+ wlr_buffer_drop(&m->pool[i]->base);
1182+ m->pool[i] = NULL;
1183+ }
1184+
1185+ if (m->b.scale == m->wlr_output->scale && m->drw)
1186+ return;
1187+
1188+ drwl_font_destroy(m->drw->font);
1189+ snprintf(fontattrs, sizeof(fontattrs), "dpi=%.2f", 96. * m->wlr_output->scale);
1190+ if (!(drwl_font_create(m->drw, LENGTH(fonts), fonts, fontattrs)))
1191+ die("Could not load font");
1192+
1193+ m->b.scale = m->wlr_output->scale;
1194+ m->lrpad = m->drw->font->height;
1195+ m->b.height = m->drw->font->height + 2;
1196+ m->b.real_height = (int)((float)m->b.height / m->wlr_output->scale);
1197+}
1198+
1199 void
1200 updatetitle(struct wl_listener *listener, void *data)
1201 {
1202 Client *c = wl_container_of(listener, c, set_title);
1203 if (c == focustop(c->mon))
1204- printstatus();
1205+ drawbars();
1206
1207 if (c->foreign_toplevel_handle) {
1208 struct wlr_ext_foreign_toplevel_handle_v1_state foreign_toplevel_state = {
1209@@ -3159,10 +3436,10 @@ urgent(struct wl_listener *listener, void *data)
1210 return;
1211
1212 c->isurgent = 1;
1213- printstatus();
1214+ drawbars();
1215
1216 if (client_surface(c)->mapped)
1217- client_set_border_color(c, urgentcolor);
1218+ client_set_border_color(c, (float[])COLOR(colors[SchemeUrg][ColBorder]));
1219 }
1220
1221 void
1222@@ -3175,7 +3452,7 @@ view(const Arg *arg)
1223 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
1224 focusclient(focustop(selmon), 1);
1225 arrange(selmon);
1226- printstatus();
1227+ drawbars();
1228 }
1229
1230 void
1231@@ -3219,6 +3496,7 @@ xytonode(double x, double y, struct wlr_surface **psurface,
1232 {
1233 struct wlr_scene_node *node;
1234 struct wlr_surface *surface = NULL;
1235+ struct wlr_scene_surface *scene_surface = NULL;
1236 int layer;
1237
1238 for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) {
1239@@ -3226,9 +3504,12 @@ xytonode(double x, double y, struct wlr_surface **psurface,
1240 !(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny)))
1241 continue;
1242
1243- if (node->type == WLR_SCENE_NODE_BUFFER)
1244- surface = wlr_scene_surface_try_from_buffer(
1245- wlr_scene_buffer_from_node(node))->surface;
1246+ if (node->type == WLR_SCENE_NODE_BUFFER) {
1247+ scene_surface = wlr_scene_surface_try_from_buffer(
1248+ wlr_scene_buffer_from_node(node));
1249+ if (!scene_surface) continue;
1250+ surface = scene_surface->surface;
1251+ }
1252 }
1253
1254 if (psurface) *psurface = surface;
1255@@ -3362,10 +3643,10 @@ sethints(struct wl_listener *listener, void *data)
1256 return;
1257
1258 c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);
1259- printstatus();
1260+ drawbars();
1261
1262 if (c->isurgent && surface && surface->mapped)
1263- client_set_border_color(c, urgentcolor);
1264+ client_set_border_color(c, (float[])COLOR(colors[SchemeUrg][ColBorder]));
1265 }
1266
1267 void
1268--
12692.55.0
1270