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