diff --git a/Makefile b/Makefile index 3a48dd4..0549796 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ XLIBS = xcb xcb-icccm DISTRO = LUA_PKG = lua5.4 -PKGS = wayland-server xkbcommon libinput $(LUA_PKG) $(XLIBS) +PKGS = wayland-server xkbcommon libinput $(LUA_PKG) $(XLIBS) scenefx-0.5 CFLAGS = `$(PKG_CONFIG) --cflags $(PKGS) wlroots-0.20` \ -I. -Iinclude -Isrc -Iparser -Iprotocols \ @@ -59,9 +59,11 @@ release: CFLAGS += -Werror -Wpedantic -Wmissing-prototypes -Wstrict-prototypes \ -Wold-style-definition -Wmissing-declarations -Wimplicit-fallthrough \ -Wno-gnu-zero-variadic-macro-arguments \ -Wno-c23-extensions \ + -Wno-extra-semi \ -march=native release: peachwm peachmsg/peachmsg +debug: CC = clang debug: CC = clang debug: CFLAGS += -Werror -Weverything \ -Wno-padded -Wno-unsafe-buffer-usage \ @@ -80,6 +82,7 @@ debug: CFLAGS += -Werror -Weverything \ -Wno-tentative-definition-compat -Wno-missing-variable-declarations \ -Wno-gnu-zero-variadic-macro-arguments \ -Wno-c23-extensions \ + -Wno-extra-semi \ -g3 -fno-omit-frame-pointer -fsanitize=address,undefined,leak \ -fsanitize-trap=all debug: LDLIBS += -fsanitize=address,undefined,leak diff --git a/include/client.h b/include/client.h index 0e327be..f378059 100644 --- a/include/client.h +++ b/include/client.h @@ -53,6 +53,7 @@ typedef struct Client { struct wl_listener set_hints; #endif unsigned int bw; + int corner_radius; uint32_t tags; int isfloating, isurgent, isfullscreen, isscratchpad; uint32_t resize; /* configure serial of a pending resize */ diff --git a/include/monitor.h b/include/monitor.h index 70420a6..c00e327 100644 --- a/include/monitor.h +++ b/include/monitor.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include "wlr_ext_workspace_v1.h" diff --git a/parser/parser.c b/parser/parser.c index c6c7b23..bb49f25 100644 --- a/parser/parser.c +++ b/parser/parser.c @@ -618,6 +618,37 @@ parse_autostart(lua_State *L, Config *cfg) lua_pop(L, 1); } +static void +parse_effects(lua_State *L, CfgEffects *e) +{ + /* Defaults */ + e->windows.rounded = false; + strcpy(e->windows.rounding, "off"); + + lua_getglobal(L, "effects"); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + return; + } + + lua_getfield(L, -1, "windows"); + if (!lua_istable(L, -1)) { + lua_pop(L, 2); /* pop windows + effects */ + return; + } + + e->windows.rounded = lua_get_bool(L, "rounded", false); + + char scratch[CFG_MAX_STRLEN] = {0}; + lua_get_string(L, "rounding", scratch, sizeof(scratch)); + if (!strcmp(scratch, "light") || !strcmp(scratch, "heavy")) + strncpy(e->windows.rounding, scratch, CFG_MAX_STRLEN - 1); + else + strcpy(e->windows.rounding, "off"); + + lua_pop(L, 2); /* pop windows + effects */ +} + /* Public API */ char * @@ -686,6 +717,7 @@ config_load(const char *path, Config *cfg) parse_buttons (L, cfg); parse_scrolls (L, cfg); parse_autostart (L, cfg); + parse_effects (L, &cfg->effects); lua_close(L); return 0; diff --git a/parser/parser.h b/parser/parser.h index 4e0e5ad..c272e71 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -104,6 +104,17 @@ typedef struct { char cmd[CFG_MAX_AUTOSTART_CMD]; } CfgAutostart; +/* Effects */ + +typedef struct { + bool rounded; + char rounding[CFG_MAX_STRLEN]; +} CfgEffectsWindows; + +typedef struct { + CfgEffectsWindows windows; +} CfgEffects; + /* the whole shebang */ typedef struct { @@ -135,6 +146,8 @@ typedef struct { /* Per-workspace (tag) default layouts, indexed by tag index 0-8 */ char workspace_layouts[9][CFG_MAX_STRLEN]; + + CfgEffects effects; } Config; /* Public API */ diff --git a/src/client.c b/src/client.c index 5cad9f2..d6de92d 100644 --- a/src/client.c +++ b/src/client.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/peachwm.c b/src/peachwm.c index 201cff6..2b49e8f 100644 --- a/src/peachwm.c +++ b/src/peachwm.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +50,7 @@ #include #include #include -#include +#include #include #include #include @@ -385,6 +386,18 @@ static char config_path[1024]; /* function implementations */ +static int +config_get_corner_radius(void) +{ + if (!cfg.effects.windows.rounded) + return 0; + if (strcmp(cfg.effects.windows.rounding, "light") == 0) + return 6; + if (strcmp(cfg.effects.windows.rounding, "heavy") == 0) + return 14; + return 0; /* "off" or unknown */ +} + /* Apply a workspace default layout for the given tag index (0-based) on monitor * m */ static void apply_workspace_layout(Monitor *m, int tag_idx) { @@ -1664,7 +1677,7 @@ static void gpureset(struct wl_listener *listener, void *data) { struct wlr_renderer *old_drw = drw; struct wlr_allocator *old_alloc = alloc; struct Monitor *m; - if (!(drw = wlr_renderer_autocreate(backend))) + if (!(drw = fx_renderer_create(backend))) die("couldn't recreate renderer"); if (!(alloc = wlr_allocator_autocreate(backend, drw))) @@ -2059,6 +2072,14 @@ static void locksession(struct wl_listener *listener, void *data) { wlr_session_lock_v1_send_locked(session_lock); } +static void +set_buffer_corner_radius(struct wlr_scene_buffer *buffer, + int sx, int sy, void *user_data) +{ + int radius = *(int *)user_data; + wlr_scene_buffer_set_corner_radius(buffer, radius); +} + static void mapnotify(struct wl_listener *listener, void *data) { /* Called when the surface is mapped, or ready to display on-screen. */ Client *p = nullptr; @@ -2070,11 +2091,7 @@ static void mapnotify(struct wl_listener *listener, void *data) { c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]); /* Enabled later by a call to arrange() */ wlr_scene_node_set_enabled(&c->scene->node, client_is_unmanaged(c)); - c->scene_surface = - c->type == XDGShell - ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) - : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); - c->scene->node.data = c->scene_surface->node.data = c; + c->scene->node.data = c; client_get_geometry(c, &c->geom); @@ -2099,6 +2116,28 @@ static void mapnotify(struct wl_listener *listener, void *data) { c->border[i]->node.data = c; } + { + int r = config_get_corner_radius(); + c->corner_radius = r; + if (r > 0) { + wlr_scene_rect_set_corner_radii(c->border[0], corner_radii_top(r)); + wlr_scene_rect_set_corner_radii(c->border[1], corner_radii_bottom(r)); + wlr_scene_rect_set_corner_radii(c->border[2], corner_radii_left(r)); + wlr_scene_rect_set_corner_radii(c->border[3], corner_radii_right(r)); + } + } + + c->scene_surface = + c->type == XDGShell + ? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg) + : wlr_scene_subsurface_tree_create(c->scene, client_surface(c)); + c->scene_surface->node.data = c; + + if (c->corner_radius > 0) { + wlr_scene_node_for_each_buffer(&c->scene_surface->node, + set_buffer_corner_radius, &c->corner_radius); + } + /* Initialize client geometry with room for border */ client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); @@ -2552,6 +2591,14 @@ void resize(Client *c, struct wlr_box geo, int interact) { wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw); + if (c->corner_radius > 0 && !c->isfullscreen) { + int r = c->corner_radius; + wlr_scene_rect_set_corner_radii(c->border[0], corner_radii_top(r)); + wlr_scene_rect_set_corner_radii(c->border[1], corner_radii_bottom(r)); + wlr_scene_rect_set_corner_radii(c->border[2], corner_radii_left(r)); + wlr_scene_rect_set_corner_radii(c->border[3], corner_radii_right(r)); + } + /* this is a no-op if size hasn't changed */ c->resize = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); @@ -2673,8 +2720,27 @@ static void setfullscreen(Client *c, int fullscreen) { c->isfullscreen = fullscreen; if (!c->mon || !client_surface(c)->mapped) return; - c->bw = fullscreen ? 0 : cfg.appearance.border_px; - client_set_fullscreen(c, fullscreen); + c->bw = fullscreen ? 0 : cfg.appearance.border_px; + if (fullscreen) { + c->corner_radius = 0; + int zero = 0; + wlr_scene_node_for_each_buffer(&c->scene_surface->node, + set_buffer_corner_radius, &zero); + for (int i = 0; i < 4; i++) + wlr_scene_rect_set_corner_radius(c->border[i], 0); + } else { + int r = config_get_corner_radius(); + c->corner_radius = r; + if (r > 0) { + wlr_scene_rect_set_corner_radii(c->border[0], corner_radii_top(r)); + wlr_scene_rect_set_corner_radii(c->border[1], corner_radii_bottom(r)); + wlr_scene_rect_set_corner_radii(c->border[2], corner_radii_left(r)); + wlr_scene_rect_set_corner_radii(c->border[3], corner_radii_right(r)); + wlr_scene_node_for_each_buffer(&c->scene_surface->node, + set_buffer_corner_radius, &r); + } + } + client_set_fullscreen(c, fullscreen); if (c->isscratchpad) { wlr_scene_node_reparent(&c->scene->node, layers[LyrScratch]); } else { @@ -2910,6 +2976,22 @@ reapply_client_appearance(void) } wl_list_for_each(c, &clients, link) { c->bw = !c->isfullscreen ? cfg.appearance.border_px : 0; + if (!client_is_unmanaged(c)) { + int r = c->isfullscreen ? 0 : config_get_corner_radius(); + c->corner_radius = r; + if (r > 0 && !c->isfullscreen) { + wlr_scene_rect_set_corner_radii(c->border[0], corner_radii_top(r)); + wlr_scene_rect_set_corner_radii(c->border[1], corner_radii_bottom(r)); + wlr_scene_rect_set_corner_radii(c->border[2], corner_radii_left(r)); + wlr_scene_rect_set_corner_radii(c->border[3], corner_radii_right(r)); + } else { + for (int i = 0; i < 4; i++) + wlr_scene_rect_set_corner_radius(c->border[i], 0); + } + int radius = r; + wlr_scene_node_for_each_buffer(&c->scene_surface->node, + set_buffer_corner_radius, &radius); + } if (!client_is_unmanaged(c)) { float *color = c->isurgent ? cfg.appearance.urgent_color : c == focustop(c->mon) ? cfg.appearance.focus_color @@ -3064,7 +3146,7 @@ static void setup(void) { * can also specify a renderer using the WLR_RENDERER env var. * The renderer is responsible for defining the various pixel formats it * supports for shared memory, this configures that for clients. */ - if (!(drw = wlr_renderer_autocreate(backend))) + if (!(drw = fx_renderer_create(backend))) die("couldn't create renderer"); wl_signal_add(&drw->events.lost, &gpu_reset); diff --git a/src/scratchpad.c b/src/scratchpad.c index 74c2246..b89c308 100644 --- a/src/scratchpad.c +++ b/src/scratchpad.c @@ -6,7 +6,7 @@ * as a group, with monocle-style cycling within the scratchpad. */ #include -#include +#include #include #include "client.h" diff --git a/src/scratchpad.h b/src/scratchpad.h index 343b2c6..ecc52df 100644 --- a/src/scratchpad.h +++ b/src/scratchpad.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "client.h" #include "monitor.h" #include "common.h"