compositor: extend applyrules, guard toggles, gate effects at render time only
This commit is contained in:
@@ -19,6 +19,17 @@ struct wlr_scene_shadow;
|
|||||||
/* Client types */
|
/* Client types */
|
||||||
enum { XDGShell, LayerShell, X11 };
|
enum { XDGShell, LayerShell, X11 };
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool rounding;
|
||||||
|
bool shadows;
|
||||||
|
bool transparency;
|
||||||
|
bool blur;
|
||||||
|
bool gaps;
|
||||||
|
bool smartgaps;
|
||||||
|
bool border;
|
||||||
|
bool sloppy_focus;
|
||||||
|
} ClientRuleEffects;
|
||||||
|
|
||||||
typedef struct Client {
|
typedef struct Client {
|
||||||
/* Must keep this field first — union-cast discriminant */
|
/* Must keep this field first — union-cast discriminant */
|
||||||
unsigned int type; /* XDGShell or X11 */
|
unsigned int type; /* XDGShell or X11 */
|
||||||
@@ -50,6 +61,11 @@ typedef struct Client {
|
|||||||
struct wlr_scene_tree *scene_surface;
|
struct wlr_scene_tree *scene_surface;
|
||||||
struct wlr_xdg_toplevel_decoration_v1 *decoration;
|
struct wlr_xdg_toplevel_decoration_v1 *decoration;
|
||||||
|
|
||||||
|
/* Per-rule constraints and effects */
|
||||||
|
bool can_float;
|
||||||
|
bool can_fullscreen;
|
||||||
|
ClientRuleEffects rule_effects;
|
||||||
|
|
||||||
/* COLD — wl_listeners (set up once, rarely touched after) */
|
/* COLD — wl_listeners (set up once, rarely touched after) */
|
||||||
struct wl_listener commit;
|
struct wl_listener commit;
|
||||||
struct wl_listener map;
|
struct wl_listener map;
|
||||||
|
|||||||
+35
-15
@@ -469,11 +469,20 @@ static void applyrules(Client *c) {
|
|||||||
appid = client_get_appid(c);
|
appid = client_get_appid(c);
|
||||||
title = client_get_title(c);
|
title = client_get_title(c);
|
||||||
|
|
||||||
|
/* Initialize rule-controlled defaults */
|
||||||
|
c->can_float = true;
|
||||||
|
c->can_fullscreen = true;
|
||||||
|
memset(&c->rule_effects, 0xFF, sizeof(c->rule_effects));
|
||||||
|
|
||||||
for (ri = 0; ri < cfg.nrules; ri++) {
|
for (ri = 0; ri < cfg.nrules; ri++) {
|
||||||
const CfgRule *r = &cfg.rules[ri];
|
const CfgRule *r = &cfg.rules[ri];
|
||||||
if ((!r->title[0] || strstr(title, r->title)) &&
|
if ((!r->title[0] || strstr(title, r->title)) &&
|
||||||
(!r->app_id[0] || strstr(appid, r->app_id))) {
|
(!r->app_id[0] || strstr(appid, r->app_id))) {
|
||||||
c->isfloating = r->floating;
|
c->isfloating = r->floating;
|
||||||
|
c->isfullscreen = r->fullscreen;
|
||||||
|
c->can_float = r->can_float;
|
||||||
|
c->can_fullscreen = r->can_fullscreen;
|
||||||
|
memcpy(&c->rule_effects, &r->apply_effects, sizeof(c->rule_effects));
|
||||||
newtags |= r->tags;
|
newtags |= r->tags;
|
||||||
i = 0;
|
i = 0;
|
||||||
wl_list_for_each(m, &mons, link) {
|
wl_list_for_each(m, &mons, link) {
|
||||||
@@ -1595,7 +1604,7 @@ void focusclient(Client *c, int lift) {
|
|||||||
/* Activate the new client */
|
/* Activate the new client */
|
||||||
client_activate_surface(client_surface(c), 1);
|
client_activate_surface(client_surface(c), 1);
|
||||||
|
|
||||||
if (cfg.sloppyfocus && warp_focus)
|
if (cfg.sloppyfocus && c->rule_effects.sloppy_focus && warp_focus)
|
||||||
wlr_cursor_warp(cursor, nullptr, c->geom.x + c->geom.width / 2,
|
wlr_cursor_warp(cursor, nullptr, c->geom.x + c->geom.width / 2,
|
||||||
c->geom.y + c->geom.height / 2);
|
c->geom.y + c->geom.height / 2);
|
||||||
}
|
}
|
||||||
@@ -2575,7 +2584,7 @@ static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, doub
|
|||||||
struct timespec now;
|
struct timespec now;
|
||||||
|
|
||||||
if (surface != seat->pointer_state.focused_surface && cfg.sloppyfocus &&
|
if (surface != seat->pointer_state.focused_surface && cfg.sloppyfocus &&
|
||||||
time && c && !client_is_unmanaged(c)) {
|
c->rule_effects.sloppy_focus && time && c && !client_is_unmanaged(c)) {
|
||||||
warp_focus = false;
|
warp_focus = false;
|
||||||
focusclient(c, 0);
|
focusclient(c, 0);
|
||||||
warp_focus = true;
|
warp_focus = true;
|
||||||
@@ -2677,7 +2686,7 @@ static void rendermon(struct wl_listener *listener, void *data) {
|
|||||||
{
|
{
|
||||||
Client *c;
|
Client *c;
|
||||||
wl_list_for_each(c, &clients, link) {
|
wl_list_for_each(c, &clients, link) {
|
||||||
if (c->mon == m && c->scene_surface && c->corner_radius > 0 && !c->isfullscreen) {
|
if (c->mon == m && c->scene_surface && c->corner_radius > 0 && !c->isfullscreen && c->rule_effects.rounding) {
|
||||||
apply_surface_corners(&c->scene_surface->node, c->corner_radius);
|
apply_surface_corners(&c->scene_surface->node, c->corner_radius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2689,7 +2698,7 @@ static void rendermon(struct wl_listener *listener, void *data) {
|
|||||||
wl_list_for_each(c, &clients, link) {
|
wl_list_for_each(c, &clients, link) {
|
||||||
if (c->mon != m)
|
if (c->mon != m)
|
||||||
continue;
|
continue;
|
||||||
if (!cfg.effects.windows.transparency.enabled)
|
if (!cfg.effects.windows.transparency.enabled || !c->rule_effects.transparency)
|
||||||
continue;
|
continue;
|
||||||
if (!VISIBLEON(c, m))
|
if (!VISIBLEON(c, m))
|
||||||
continue;
|
continue;
|
||||||
@@ -2789,7 +2798,7 @@ void resize(Client *c, struct wlr_box geo, int interact) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update single border rect with clipped region hole */
|
/* Update single border rect with clipped region hole */
|
||||||
if (c->border_bg) {
|
if (c->border_bg && c->rule_effects.border) {
|
||||||
int bw_i = (int)c->bw;
|
int bw_i = (int)c->bw;
|
||||||
int cw = (int)c->geom.width;
|
int cw = (int)c->geom.width;
|
||||||
int ch = (int)c->geom.height;
|
int ch = (int)c->geom.height;
|
||||||
@@ -2823,7 +2832,8 @@ void resize(Client *c, struct wlr_box geo, int interact) {
|
|||||||
if (c->shadow) {
|
if (c->shadow) {
|
||||||
bool shadow_visible = cfg.effects.windows.shadows.shadows
|
bool shadow_visible = cfg.effects.windows.shadows.shadows
|
||||||
&& (cfg.effects.windows.shadows.fullscreen_shadows || !c->isfullscreen)
|
&& (cfg.effects.windows.shadows.fullscreen_shadows || !c->isfullscreen)
|
||||||
&& (!cfg.effects.windows.shadows.only_floating || c->isfloating);
|
&& (!cfg.effects.windows.shadows.only_floating || c->isfloating)
|
||||||
|
&& c->rule_effects.shadows;
|
||||||
if (!cfg.effects.windows.shadows.nogaps_shadows && !c->mon->gaps)
|
if (!cfg.effects.windows.shadows.nogaps_shadows && !c->mon->gaps)
|
||||||
shadow_visible = false;
|
shadow_visible = false;
|
||||||
else if (!cfg.effects.windows.shadows.nogaps_shadows
|
else if (!cfg.effects.windows.shadows.nogaps_shadows
|
||||||
@@ -2887,7 +2897,8 @@ void resize(Client *c, struct wlr_box geo, int interact) {
|
|||||||
wlr_scene_blur_set_clipped_region(c->blur, cr);
|
wlr_scene_blur_set_clipped_region(c->blur, cr);
|
||||||
|
|
||||||
/* Evaluate blur visibility */
|
/* Evaluate blur visibility */
|
||||||
bool blur_enabled = cfg.effects.windows.transparency.blur.enabled;
|
bool blur_enabled = cfg.effects.windows.transparency.blur.enabled
|
||||||
|
&& c->rule_effects.blur;
|
||||||
if (!cfg.effects.windows.transparency.blur.nogaps_blur && !c->mon->gaps)
|
if (!cfg.effects.windows.transparency.blur.nogaps_blur && !c->mon->gaps)
|
||||||
blur_enabled = false;
|
blur_enabled = false;
|
||||||
/* smart_gaps edge case */
|
/* smart_gaps edge case */
|
||||||
@@ -3042,8 +3053,8 @@ static void setfullscreen(Client *c, int fullscreen) {
|
|||||||
if (c->blur)
|
if (c->blur)
|
||||||
wlr_scene_node_set_enabled(&c->blur->node, false);
|
wlr_scene_node_set_enabled(&c->blur->node, false);
|
||||||
} else {
|
} else {
|
||||||
c->corner_radius = config_get_corner_radius();
|
c->corner_radius = c->rule_effects.rounding ? config_get_corner_radius() : 0;
|
||||||
if (c->border_bg) {
|
if (c->border_bg && c->rule_effects.border) {
|
||||||
wlr_scene_node_set_enabled(&c->border_bg->node, true);
|
wlr_scene_node_set_enabled(&c->border_bg->node, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3286,7 +3297,7 @@ reapply_client_appearance(void)
|
|||||||
wl_list_for_each(c, &clients, link) {
|
wl_list_for_each(c, &clients, link) {
|
||||||
c->bw = !c->isfullscreen ? cfg.appearance.border_px : 0;
|
c->bw = !c->isfullscreen ? cfg.appearance.border_px : 0;
|
||||||
if (!client_is_unmanaged(c)) {
|
if (!client_is_unmanaged(c)) {
|
||||||
int r = c->isfullscreen ? 0 : config_get_corner_radius();
|
int r = c->isfullscreen ? 0 : (c->rule_effects.rounding ? config_get_corner_radius() : 0);
|
||||||
c->corner_radius = r;
|
c->corner_radius = r;
|
||||||
if (c->border_bg) {
|
if (c->border_bg) {
|
||||||
if (r > 0 && !c->isfullscreen) {
|
if (r > 0 && !c->isfullscreen) {
|
||||||
@@ -3300,7 +3311,7 @@ reapply_client_appearance(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Shadow re-apply on config reload */
|
/* Shadow re-apply on config reload */
|
||||||
if (cfg.effects.windows.shadows.shadows) {
|
if (cfg.effects.windows.shadows.shadows && c->rule_effects.shadows) {
|
||||||
if (!c->shadow) {
|
if (!c->shadow) {
|
||||||
float sc[4];
|
float sc[4];
|
||||||
parse_color_hex(cfg.effects.windows.shadows.shadow_color, sc);
|
parse_color_hex(cfg.effects.windows.shadows.shadow_color, sc);
|
||||||
@@ -3329,7 +3340,7 @@ reapply_client_appearance(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Blur re-apply on config reload */
|
/* Blur re-apply on config reload */
|
||||||
if (cfg.effects.windows.transparency.blur.enabled) {
|
if (cfg.effects.windows.transparency.blur.enabled && c->rule_effects.blur) {
|
||||||
if (!c->blur) {
|
if (!c->blur) {
|
||||||
c->blur = wlr_scene_blur_create(c->scene,
|
c->blur = wlr_scene_blur_create(c->scene,
|
||||||
(int)(c->geom.width - 2 * (int)c->bw),
|
(int)(c->geom.width - 2 * (int)c->bw),
|
||||||
@@ -3380,6 +3391,12 @@ reapply_client_rules(void)
|
|||||||
wl_list_for_each(c, &clients, link) {
|
wl_list_for_each(c, &clients, link) {
|
||||||
if (client_is_unmanaged(c))
|
if (client_is_unmanaged(c))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Reset rule-controlled defaults */
|
||||||
|
c->can_float = true;
|
||||||
|
c->can_fullscreen = true;
|
||||||
|
memset(&c->rule_effects, 0xFF, sizeof(c->rule_effects));
|
||||||
|
|
||||||
const char *appid = client_get_appid(c);
|
const char *appid = client_get_appid(c);
|
||||||
const char *title = client_get_title(c);
|
const char *title = client_get_title(c);
|
||||||
for (int ri = 0; ri < cfg.nrules; ri++) {
|
for (int ri = 0; ri < cfg.nrules; ri++) {
|
||||||
@@ -3387,6 +3404,10 @@ reapply_client_rules(void)
|
|||||||
if ((!r->title[0] || strstr(title, r->title)) &&
|
if ((!r->title[0] || strstr(title, r->title)) &&
|
||||||
(!r->app_id[0] || strstr(appid, r->app_id))) {
|
(!r->app_id[0] || strstr(appid, r->app_id))) {
|
||||||
c->isfloating = r->floating | client_is_float_type(c);
|
c->isfloating = r->floating | client_is_float_type(c);
|
||||||
|
c->isfullscreen = r->fullscreen;
|
||||||
|
c->can_float = r->can_float;
|
||||||
|
c->can_fullscreen = r->can_fullscreen;
|
||||||
|
memcpy(&c->rule_effects, &r->apply_effects, sizeof(c->rule_effects));
|
||||||
if (r->tags) {
|
if (r->tags) {
|
||||||
dwindle_remove_client(c);
|
dwindle_remove_client(c);
|
||||||
master_remove_client(c);
|
master_remove_client(c);
|
||||||
@@ -3805,14 +3826,13 @@ static void tagmon(const Arg *arg) {
|
|||||||
|
|
||||||
void togglefloating(const Arg *arg) {
|
void togglefloating(const Arg *arg) {
|
||||||
Client *sel = focustop(selmon);
|
Client *sel = focustop(selmon);
|
||||||
/* return if fullscreen or scratchpad (strictly floating) */
|
if (sel && !sel->isfullscreen && !sel->isscratchpad && sel->can_float)
|
||||||
if (sel && !sel->isfullscreen && !sel->isscratchpad)
|
|
||||||
setfloating(sel, !sel->isfloating);
|
setfloating(sel, !sel->isfloating);
|
||||||
}
|
}
|
||||||
|
|
||||||
void togglefullscreen(const Arg *arg) {
|
void togglefullscreen(const Arg *arg) {
|
||||||
Client *sel = focustop(selmon);
|
Client *sel = focustop(selmon);
|
||||||
if (sel)
|
if (sel && sel->can_fullscreen)
|
||||||
setfullscreen(sel, !sel->isfullscreen);
|
setfullscreen(sel, !sel->isfullscreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user