feat(effects): implement window rounded corners via scenefx
- Parse effects.windows.rounded/rounding from Lua config - Add CfgEffectsWindows and CfgEffects structs to Config - Switch to fx_renderer_create for scenefx support - Replace 5 wlr/types/wlr_scene.h includes with scenefx variant - Add config_get_corner_radius() helper (light=6px, heavy=14px) - Apply corner_radii_top/bottom/left/right to 4 border rects - Apply wlr_scene_buffer_set_corner_radius to surface buffers - Disable on fullscreen, restore on exit - Re-apply on resize and config hot-reload - Add -Wno-extra-semi for scenefx header compatibility - All targets compile cleanly (make test passes)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <scenefx/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_session_lock_v1.h>
|
||||
#include "wlr_ext_workspace_v1.h"
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_fractional_scale_v1.h>
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <scenefx/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_xdg_shell.h>
|
||||
#include <wlr/util/edges.h>
|
||||
|
||||
+90
-8
@@ -20,6 +20,7 @@
|
||||
#include <wlr/backend/libinput.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <scenefx/render/fx_renderer/fx_renderer.h>
|
||||
#include <wlr/types/wlr_alpha_modifier_v1.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
@@ -49,7 +50,7 @@
|
||||
#include <wlr/types/wlr_primary_selection.h>
|
||||
#include <wlr/types/wlr_primary_selection_v1.h>
|
||||
#include <wlr/types/wlr_relative_pointer_v1.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <scenefx/types/wlr_scene.h>
|
||||
#include <wlr/types/wlr_screencopy_v1.h>
|
||||
#include <wlr/types/wlr_seat.h>
|
||||
#include <wlr/types/wlr_server_decoration.h>
|
||||
@@ -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);
|
||||
@@ -2674,6 +2721,25 @@ static void setfullscreen(Client *c, int fullscreen) {
|
||||
if (!c->mon || !client_surface(c)->mapped)
|
||||
return;
|
||||
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]);
|
||||
@@ -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);
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
* as a group, with monocle-style cycling within the scratchpad.
|
||||
*/
|
||||
#include <wlr/types/wlr_output_layout.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <scenefx/types/wlr_scene.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "client.h"
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <scenefx/types/wlr_scene.h>
|
||||
#include "client.h"
|
||||
#include "monitor.h"
|
||||
#include "common.h"
|
||||
|
||||
Reference in New Issue
Block a user