mirror of
https://github.com/yshui/picom.git
synced 2025-02-10 15:45:57 -05:00
wm/win: separate per-window options into their own struct
It's easier to just store them together, since the same group of information is needed for parsed window rules, and for window rendering. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
797e60f618
commit
cdf25b07dc
16 changed files with 407 additions and 372 deletions
|
@ -28,6 +28,19 @@ typedef enum {
|
|||
|
||||
enum tristate { TRI_FALSE = -1, TRI_UNKNOWN = 0, TRI_TRUE = 1 };
|
||||
|
||||
/// Return value if it's not TRI_UNKNOWN, otherwise return fallback.
|
||||
static inline enum tristate tri_or(enum tristate value, enum tristate fallback) {
|
||||
return value ?: fallback;
|
||||
}
|
||||
|
||||
static inline bool tri_or_bool(enum tristate value, bool fallback) {
|
||||
return value == TRI_UNKNOWN ? fallback : value == TRI_TRUE;
|
||||
}
|
||||
|
||||
static inline enum tristate tri_from_bool(bool value) {
|
||||
return value ? TRI_TRUE : TRI_FALSE;
|
||||
}
|
||||
|
||||
/// A structure representing margins around a rectangle.
|
||||
typedef struct {
|
||||
int top;
|
||||
|
|
|
@ -278,6 +278,8 @@ typedef struct session {
|
|||
|
||||
struct wm *wm;
|
||||
|
||||
struct window_options window_options_default;
|
||||
|
||||
// === Shadow/dimming related ===
|
||||
/// 1x1 black Picture.
|
||||
xcb_render_picture_t black_picture;
|
||||
|
|
|
@ -639,6 +639,8 @@ bool load_plugin(const char *name, const char *include_dir) {
|
|||
return handle != NULL;
|
||||
}
|
||||
|
||||
struct shader_info null_shader = {0};
|
||||
|
||||
bool parse_config(options_t *opt, const char *config_file) {
|
||||
// clang-format off
|
||||
*opt = (struct options){
|
||||
|
|
62
src/config.h
62
src/config.h
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <xcb/render.h> // for xcb_render_fixed_t, XXX
|
||||
|
@ -136,6 +137,67 @@ struct included_config_file {
|
|||
struct list_node siblings;
|
||||
};
|
||||
|
||||
struct window_maybe_options {
|
||||
/// Radius of rounded window corners, -1 means not set.
|
||||
int corner_radius;
|
||||
|
||||
/// Window opacity, NaN means not set.
|
||||
double opacity;
|
||||
|
||||
/// Name of the custom fragment shader for this window. NULL means not set.
|
||||
const struct shader_info *shader;
|
||||
|
||||
/// Whether transparent clipping is excluded by the rules.
|
||||
enum tristate transparent_clipping;
|
||||
/// Whether a window has shadow.
|
||||
enum tristate shadow;
|
||||
/// Whether to invert window color.
|
||||
enum tristate invert_color;
|
||||
/// Whether to blur window background.
|
||||
enum tristate blur_background;
|
||||
/// Whether the window is to be dimmed.
|
||||
enum tristate dim;
|
||||
/// Whether this window should fade.
|
||||
enum tristate fade;
|
||||
/// Do not paint shadow over this window.
|
||||
enum tristate clip_shadow_above;
|
||||
/// Whether the window is to be considered focused.
|
||||
enum tristate focused;
|
||||
/// Whether the window is painted.
|
||||
enum tristate paint;
|
||||
/// Whether this window should be considered for unredirect-if-possible.
|
||||
enum tristate unredir_ignore;
|
||||
};
|
||||
|
||||
/// Like `window_maybe_options`, but all fields are guaranteed to be set.
|
||||
struct window_options {
|
||||
double opacity;
|
||||
const struct shader_info *shader;
|
||||
unsigned int corner_radius;
|
||||
bool transparent_clipping;
|
||||
bool shadow;
|
||||
bool invert_color;
|
||||
bool blur_background;
|
||||
bool dim;
|
||||
bool fade;
|
||||
bool clip_shadow_above;
|
||||
bool focused;
|
||||
bool paint;
|
||||
bool unredir_ignore;
|
||||
|
||||
char padding[2];
|
||||
};
|
||||
|
||||
static inline bool
|
||||
win_options_eq(const struct window_options *a, const struct window_options *b) {
|
||||
return memcmp(a, b, offsetof(struct window_options, padding)) == 0;
|
||||
}
|
||||
|
||||
static_assert(offsetof(struct window_options, padding) == 30, "window_options has "
|
||||
"implicit padding");
|
||||
|
||||
extern struct shader_info null_shader;
|
||||
|
||||
/// Structure representing all options.
|
||||
typedef struct options {
|
||||
// === Config ===
|
||||
|
|
48
src/dbus.c
48
src/dbus.c
|
@ -20,6 +20,7 @@
|
|||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "utils/misc.h"
|
||||
#include "utils/str.h"
|
||||
#include "wm/defs.h"
|
||||
|
@ -652,6 +653,14 @@ static DBusHandlerResult cdbus_process_repaint(session_t *ps, DBusMessage *msg a
|
|||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
static inline cdbus_enum_t tristate_to_switch(enum tristate val) {
|
||||
switch (val) {
|
||||
case TRI_FALSE: return OFF;
|
||||
case TRI_TRUE: return ON;
|
||||
default: return UNSET;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a win_get D-Bus request.
|
||||
*/
|
||||
|
@ -703,6 +712,8 @@ cdbus_process_win_get(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBusE
|
|||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
auto w_opts = win_options(w);
|
||||
|
||||
append(id, wid, win_id(w));
|
||||
append(client_win, wid, win_client_id(w, /*fallback_to_self=*/true));
|
||||
append(map_state, boolean, w->a.map_state);
|
||||
|
@ -712,16 +723,20 @@ cdbus_process_win_get(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBusE
|
|||
append(right_width, int32, w->frame_extents.right);
|
||||
append(top_width, int32, w->frame_extents.top);
|
||||
append(bottom_width, int32, w->frame_extents.bottom);
|
||||
append(fade_force, enum, tristate_to_switch(w->options_override.fade));
|
||||
append(shadow_force, enum, tristate_to_switch(w->options_override.shadow));
|
||||
append(focused_force, enum, tristate_to_switch(w->options_override.focused));
|
||||
append(invert_color_force, enum, tristate_to_switch(w->options_override.invert_color));
|
||||
append(opacity_is_set, boolean, !safe_isnan(w->options.opacity));
|
||||
append(shadow, boolean, w_opts.shadow);
|
||||
append(fade, boolean, w_opts.fade);
|
||||
append(blur_background, boolean, w_opts.blur_background);
|
||||
|
||||
append_win_property(mode, enum);
|
||||
append_win_property(opacity, double);
|
||||
append_win_property(ever_damaged, boolean);
|
||||
append_win_property(window_type, enum);
|
||||
append_win_property(leader, wid);
|
||||
append_win_property(fade_force, enum);
|
||||
append_win_property(shadow_force, enum);
|
||||
append_win_property(focused_force, enum);
|
||||
append_win_property(invert_color_force, enum);
|
||||
append_win_property(name, string);
|
||||
append_win_property(class_instance, string);
|
||||
append_win_property(class_general, string);
|
||||
|
@ -729,12 +744,8 @@ cdbus_process_win_get(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBusE
|
|||
append_win_property(opacity, double);
|
||||
append_win_property(has_opacity_prop, boolean);
|
||||
append_win_property(opacity_prop, uint32);
|
||||
append_win_property(opacity_is_set, boolean);
|
||||
append_win_property(opacity_set, double);
|
||||
append_win_property(frame_opacity, double);
|
||||
append_win_property(shadow, boolean);
|
||||
append_win_property(invert_color, boolean);
|
||||
append_win_property(blur_background, boolean);
|
||||
|
||||
#undef append_win_property
|
||||
#undef append
|
||||
|
@ -778,19 +789,32 @@ cdbus_process_win_set(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBusE
|
|||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
if (!strcmp("shadow_force", target)) {
|
||||
win_set_shadow_force(ps, w, val);
|
||||
w->options_override.shadow =
|
||||
val == UNSET ? TRI_UNKNOWN : (val == ON ? TRI_TRUE : TRI_FALSE);
|
||||
changed = true;
|
||||
} else if (!strcmp("fade_force", target)) {
|
||||
win_set_fade_force(w, val);
|
||||
w->options_override.fade =
|
||||
val == UNSET ? TRI_UNKNOWN : (val == ON ? TRI_TRUE : TRI_FALSE);
|
||||
changed = true;
|
||||
} else if (!strcmp("focused_force", target)) {
|
||||
win_set_focused_force(ps, w, val);
|
||||
w->options_override.focused =
|
||||
val == UNSET ? TRI_UNKNOWN : (val == ON ? TRI_TRUE : TRI_FALSE);
|
||||
changed = true;
|
||||
} else if (!strcmp("invert_color_force", target)) {
|
||||
win_set_invert_color_force(ps, w, val);
|
||||
w->options_override.invert_color =
|
||||
val == UNSET ? TRI_UNKNOWN : (val == ON ? TRI_TRUE : TRI_FALSE);
|
||||
changed = true;
|
||||
} else {
|
||||
log_debug(CDBUS_ERROR_BADTGT_S, target);
|
||||
dbus_set_error(err, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
if (changed) {
|
||||
add_damage_from_win(ps, w);
|
||||
queue_redraw(ps);
|
||||
}
|
||||
|
||||
if (reply != NULL && !cdbus_append_boolean(reply, true)) {
|
||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||
|
|
|
@ -388,6 +388,7 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
|||
|
||||
auto w = wm_ref_deref(cursor);
|
||||
if (!w) {
|
||||
log_debug("Window %#010x is unmanaged.", ce->window);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ setup_window(struct x_connection *c, struct atom *atoms, struct options *options
|
|||
}
|
||||
}
|
||||
if (wid == win_id(w) || wid == win_client_id(w, /*fallback_to_self=*/false)) {
|
||||
w->focused = true;
|
||||
w->options.focused = TRI_TRUE;
|
||||
}
|
||||
|
||||
auto attributes_reply = XCB_AWAIT(xcb_get_window_attributes, c->c, win_id(w));
|
||||
|
|
46
src/picom.c
46
src/picom.c
|
@ -751,15 +751,6 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
|
|||
const winmode_t mode_old = w->mode;
|
||||
const bool was_painted = w->to_paint;
|
||||
|
||||
if (win_should_dim(ps, w) != w->dim) {
|
||||
w->dim = win_should_dim(ps, w);
|
||||
add_damage_from_win(ps, w);
|
||||
}
|
||||
|
||||
if (w->fg_shader && (w->fg_shader->attributes & SHADER_ATTRIBUTE_ANIMATED)) {
|
||||
add_damage_from_win(ps, w);
|
||||
*animation = true;
|
||||
}
|
||||
if (w->running_animation != NULL) {
|
||||
*animation = true;
|
||||
}
|
||||
|
@ -807,6 +798,11 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
|
|||
const bool was_painted = w->to_paint;
|
||||
const double window_opacity = win_animatable_get(w, WIN_SCRIPT_OPACITY);
|
||||
const double blur_opacity = win_animatable_get(w, WIN_SCRIPT_BLUR_OPACITY);
|
||||
auto window_options = win_options(w);
|
||||
if (window_options.shader->attributes & SHADER_ATTRIBUTE_ANIMATED) {
|
||||
add_damage_from_win(ps, w);
|
||||
*animation = true;
|
||||
}
|
||||
|
||||
// Destroy reg_ignore if some window above us invalidated it
|
||||
if (!reg_ignore_valid) {
|
||||
|
@ -837,13 +833,14 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
|
|||
log_trace("|- is positioned outside of the screen");
|
||||
to_paint = false;
|
||||
} else if (unlikely(window_opacity * MAX_ALPHA < 1 &&
|
||||
(!w->blur_background || blur_opacity * MAX_ALPHA < 1))) {
|
||||
(!window_options.blur_background ||
|
||||
blur_opacity * MAX_ALPHA < 1))) {
|
||||
// For consistency, even a window has 0 opacity, we would still
|
||||
// blur its background. (unless it's background is not blurred, or
|
||||
// the blur opacity is 0)
|
||||
log_trace("|- has 0 opacity");
|
||||
to_paint = false;
|
||||
} else if (w->paint_excluded) {
|
||||
} else if (!window_options.paint) {
|
||||
log_trace("|- is excluded from painting");
|
||||
to_paint = false;
|
||||
} else if (unlikely((w->flags & WIN_FLAGS_PIXMAP_ERROR) != 0)) {
|
||||
|
@ -878,7 +875,7 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
|
|||
// we add the window region to the ignored region
|
||||
// Otherwise last_reg_ignore shouldn't change
|
||||
if ((w->mode != WMODE_TRANS && !ps->o.force_win_blend) ||
|
||||
w->transparent_clipping) {
|
||||
window_options.transparent_clipping) {
|
||||
// w->mode == WMODE_SOLID or WMODE_FRAME_TRANS
|
||||
region_t *tmp = rc_region_new();
|
||||
if (w->mode == WMODE_SOLID) {
|
||||
|
@ -903,7 +900,7 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
|
|||
// is not correctly set.
|
||||
if (ps->o.unredir_if_possible && is_highest) {
|
||||
if (w->mode == WMODE_SOLID && !ps->o.force_win_blend &&
|
||||
w->is_fullscreen && !w->unredir_if_possible_excluded) {
|
||||
w->is_fullscreen && !window_options.unredir_ignore) {
|
||||
unredir_possible = true;
|
||||
}
|
||||
}
|
||||
|
@ -911,7 +908,7 @@ static bool paint_preprocess(session_t *ps, bool *animation, struct win **out_bo
|
|||
// Unredirect screen if some window is requesting compositor bypass, even
|
||||
// if that window is not on the top.
|
||||
if (ps->o.unredir_if_possible && win_is_bypassing_compositor(ps, w) &&
|
||||
!w->unredir_if_possible_excluded) {
|
||||
!window_options.unredir_ignore) {
|
||||
// Here we deviate from EWMH a bit. EWMH says we must not
|
||||
// unredirect the screen if the window requesting bypassing would
|
||||
// look different after unredirecting. Instead we always follow
|
||||
|
@ -1543,7 +1540,7 @@ static void handle_new_window_attributes_reply(struct x_connection * /*c*/,
|
|||
auto w = win_maybe_allocate(ps, toplevel,
|
||||
(xcb_get_window_attributes_reply_t *)reply_or_error);
|
||||
if (w != NULL && w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
||||
win_map_start(ps, w);
|
||||
win_set_flags(w, WIN_FLAGS_MAPPED);
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
}
|
||||
|
@ -1990,6 +1987,23 @@ static bool load_shader_source_for_condition(const c2_lptr_t *cond, void *data)
|
|||
return load_shader_source(data, c2_list_get_data(cond));
|
||||
}
|
||||
|
||||
static struct window_options win_options_from_config(const struct options *opts) {
|
||||
return (struct window_options){
|
||||
.blur_background = opts->blur_method != BLUR_METHOD_NONE,
|
||||
.shadow = opts->shadow_enable,
|
||||
.corner_radius = (unsigned)opts->corner_radius,
|
||||
.transparent_clipping = opts->transparent_clipping,
|
||||
.dim = opts->inactive_dim > 0,
|
||||
.fade = opts->fading_enable,
|
||||
.shader = &null_shader,
|
||||
.focused = false,
|
||||
.invert_color = false,
|
||||
.paint = true,
|
||||
.clip_shadow_above = false,
|
||||
.unredir_ignore = false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a session.
|
||||
*
|
||||
|
@ -2173,6 +2187,8 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ps->window_options_default = win_options_from_config(&ps->o);
|
||||
|
||||
if (ps->o.window_shader_fg) {
|
||||
log_debug("Default window shader: \"%s\"", ps->o.window_shader_fg);
|
||||
}
|
||||
|
|
67
src/render.c
67
src/render.c
|
@ -240,7 +240,7 @@ uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_
|
|||
}
|
||||
|
||||
void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int fullwid,
|
||||
int fullhei, double opacity, bool argb, bool neg, int cr,
|
||||
int fullhei, double opacity, bool argb, bool neg, unsigned int cr,
|
||||
xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint,
|
||||
const glx_prog_main_t *pprogram, clip_t *clip) {
|
||||
switch (ps->o.legacy_backend) {
|
||||
|
@ -266,7 +266,7 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, int f
|
|||
xcb_render_trapezoid_t traps[4 * max_ntraps + 3];
|
||||
|
||||
uint32_t n = make_rounded_window_shape(
|
||||
traps, max_ntraps, cr, fullwid, fullhei);
|
||||
traps, max_ntraps, (int)cr, fullwid, fullhei);
|
||||
|
||||
xcb_render_trapezoids(
|
||||
ps->c.c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp,
|
||||
|
@ -351,12 +351,16 @@ paint_region(session_t *ps, const struct win *w, int x, int y, int wid, int hei,
|
|||
const int dy = (w ? w->g.y : 0) + y;
|
||||
const int fullwid = w ? w->widthb : 0;
|
||||
const int fullhei = w ? w->heightb : 0;
|
||||
struct window_options w_opts = {};
|
||||
if (w) {
|
||||
w_opts = win_options(w);
|
||||
}
|
||||
const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend));
|
||||
const bool neg = (w && w->invert_color);
|
||||
const bool neg = (w && w_opts.invert_color);
|
||||
|
||||
render(ps, x, y, dx, dy, wid, hei, fullwid, fullhei, opacity, argb, neg,
|
||||
w ? w->corner_radius : 0, pict,
|
||||
(w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint,
|
||||
w_opts.corner_radius, pict, (w ? w->paint.ptex : ps->root_tile_paint.ptex),
|
||||
reg_paint,
|
||||
#ifdef CONFIG_OPENGL
|
||||
w ? &ps->glx_prog_win : NULL
|
||||
#else
|
||||
|
@ -392,7 +396,8 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) {
|
|||
/**
|
||||
* Paint a window itself and dim it if asked.
|
||||
*/
|
||||
void paint_one(session_t *ps, struct win *w, const region_t *reg_paint) {
|
||||
void paint_one(session_t *ps, struct win *w, const struct window_options *w_opts,
|
||||
const region_t *reg_paint) {
|
||||
// Fetch Pixmap
|
||||
if (!w->paint.pixmap) {
|
||||
w->paint.pixmap = x_new_id(&ps->c);
|
||||
|
@ -442,7 +447,7 @@ void paint_one(session_t *ps, struct win *w, const region_t *reg_paint) {
|
|||
xcb_render_picture_t pict = w->paint.pict;
|
||||
|
||||
// Invert window color, if required
|
||||
if (bkend_use_xrender(ps) && w->invert_color) {
|
||||
if (bkend_use_xrender(ps) && w_opts->invert_color) {
|
||||
xcb_render_picture_t newpict = x_create_picture_with_pictfmt(
|
||||
&ps->c, wid, hei, w->pictfmt->id, w->pictfmt->depth, 0, NULL);
|
||||
if (newpict) {
|
||||
|
@ -556,7 +561,7 @@ void paint_one(session_t *ps, struct win *w, const region_t *reg_paint) {
|
|||
}
|
||||
|
||||
// Dimming the window if needed
|
||||
if (w->dim) {
|
||||
if (w_opts->dim) {
|
||||
double dim_opacity = ps->o.inactive_dim;
|
||||
if (!ps->o.inactive_dim_fixed) {
|
||||
dim_opacity *= window_opacity;
|
||||
|
@ -761,7 +766,8 @@ shadow_picture_err:
|
|||
/**
|
||||
* Paint the shadow of a window.
|
||||
*/
|
||||
static inline void win_paint_shadow(session_t *ps, struct win *w, region_t *reg_paint) {
|
||||
static inline void win_paint_shadow(session_t *ps, struct win *w,
|
||||
const struct window_options *w_opts, region_t *reg_paint) {
|
||||
// Bind shadow pixmap to GLX texture if needed
|
||||
paint_bind_tex(ps, &w->shadow_paint, 0, 0, false, 32, 0, false);
|
||||
|
||||
|
@ -771,15 +777,16 @@ static inline void win_paint_shadow(session_t *ps, struct win *w, region_t *reg_
|
|||
}
|
||||
|
||||
xcb_render_picture_t td = XCB_NONE;
|
||||
bool should_clip =
|
||||
(w->corner_radius > 0) && (!ps->o.wintype_option[w->window_type].full_shadow);
|
||||
bool should_clip = (w_opts->corner_radius > 0) &&
|
||||
(!ps->o.wintype_option[w->window_type].full_shadow);
|
||||
if (should_clip) {
|
||||
if (ps->o.legacy_backend == BKEND_XRENDER ||
|
||||
ps->o.legacy_backend == BKEND_XR_GLX_HYBRID) {
|
||||
uint32_t max_ntraps = to_u32_checked(w->corner_radius);
|
||||
uint32_t max_ntraps = to_u32_checked(w_opts->corner_radius);
|
||||
xcb_render_trapezoid_t traps[4 * max_ntraps + 3];
|
||||
uint32_t n = make_rounded_window_shape(
|
||||
traps, max_ntraps, w->corner_radius, w->widthb, w->heightb);
|
||||
uint32_t n = make_rounded_window_shape(traps, max_ntraps,
|
||||
(int)w_opts->corner_radius,
|
||||
w->widthb, w->heightb);
|
||||
|
||||
td = x_create_picture_with_standard(
|
||||
&ps->c, w->widthb, w->heightb, XCB_PICT_STANDARD_ARGB_32, 0, 0);
|
||||
|
@ -896,13 +903,13 @@ xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y
|
|||
* Blur the background of a window.
|
||||
*/
|
||||
static inline void
|
||||
win_blur_background(session_t *ps, struct win *w, xcb_render_picture_t tgt_buffer,
|
||||
const region_t *reg_paint) {
|
||||
win_blur_background(session_t *ps, struct win *w, const struct window_options *w_opts,
|
||||
xcb_render_picture_t tgt_buffer, const region_t *reg_paint) {
|
||||
const int16_t x = w->g.x;
|
||||
const int16_t y = w->g.y;
|
||||
auto const wid = to_u16_checked(w->widthb);
|
||||
auto const hei = to_u16_checked(w->heightb);
|
||||
const int cr = w ? w->corner_radius : 0;
|
||||
const int cr = w_opts ? (int)w_opts->corner_radius : 0;
|
||||
const double window_opacity = win_animatable_get(w, WIN_SCRIPT_OPACITY);
|
||||
|
||||
double factor_center = 1.0;
|
||||
|
@ -1089,8 +1096,9 @@ void paint_all(session_t *ps, struct win *t) {
|
|||
region_t bshape_no_corners =
|
||||
win_get_bounding_shape_global_without_corners_by_val(w);
|
||||
region_t bshape_corners = win_get_bounding_shape_global_by_val(w);
|
||||
auto const w_opts = win_options(w);
|
||||
// Painting shadow
|
||||
if (w->shadow) {
|
||||
if (w_opts.shadow) {
|
||||
// Lazy shadow building
|
||||
if (!w->shadow_paint.pixmap) {
|
||||
if (!win_build_shadow(ps, w, 1)) {
|
||||
|
@ -1140,13 +1148,13 @@ void paint_all(session_t *ps, struct win *t) {
|
|||
// Detect if the region is empty before painting
|
||||
if (pixman_region32_not_empty(®_tmp)) {
|
||||
set_tgt_clip(ps, ®_tmp);
|
||||
win_paint_shadow(ps, w, ®_tmp);
|
||||
win_paint_shadow(ps, w, &w_opts, ®_tmp);
|
||||
}
|
||||
}
|
||||
|
||||
// Only clip shadows above visible windows
|
||||
if (win_animatable_get(w, WIN_SCRIPT_OPACITY) * MAX_ALPHA >= 1) {
|
||||
if (w->clip_shadow_above) {
|
||||
if (w_opts.clip_shadow_above) {
|
||||
// Add window bounds to shadow-clip region
|
||||
pixman_region32_union(®_shadow_clip, ®_shadow_clip,
|
||||
&bshape_corners);
|
||||
|
@ -1172,7 +1180,7 @@ void paint_all(session_t *ps, struct win *t) {
|
|||
|
||||
#ifdef CONFIG_OPENGL
|
||||
// If rounded corners backup the region first
|
||||
if (w->corner_radius > 0 && ps->o.legacy_backend == BKEND_GLX) {
|
||||
if (w_opts.corner_radius > 0 && ps->o.legacy_backend == BKEND_GLX) {
|
||||
const int16_t x = w->g.x;
|
||||
const int16_t y = w->g.y;
|
||||
auto const wid = to_u16_checked(w->widthb);
|
||||
|
@ -1182,26 +1190,27 @@ void paint_all(session_t *ps, struct win *t) {
|
|||
#endif
|
||||
|
||||
// Blur window background
|
||||
if (w->blur_background &&
|
||||
if (w_opts.blur_background &&
|
||||
(w->mode == WMODE_TRANS ||
|
||||
(ps->o.blur_background_frame && w->mode == WMODE_FRAME_TRANS) ||
|
||||
ps->o.force_win_blend)) {
|
||||
win_blur_background(ps, w, ps->tgt_buffer.pict, ®_tmp);
|
||||
win_blur_background(ps, w, &w_opts, ps->tgt_buffer.pict,
|
||||
®_tmp);
|
||||
}
|
||||
|
||||
// Painting the window
|
||||
paint_one(ps, w, ®_tmp);
|
||||
paint_one(ps, w, &w_opts, ®_tmp);
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
// Rounded corners for XRender is implemented inside render()
|
||||
// Round window corners
|
||||
if (w->corner_radius > 0 && ps->o.legacy_backend == BKEND_GLX) {
|
||||
if (w_opts.corner_radius > 0 && ps->o.legacy_backend == BKEND_GLX) {
|
||||
auto const wid = to_u16_checked(w->widthb);
|
||||
auto const hei = to_u16_checked(w->heightb);
|
||||
glx_round_corners_dst(ps, w, w->glx_texture_bg, w->g.x,
|
||||
w->g.y, wid, hei,
|
||||
(float)ps->psglx->z - 0.5F,
|
||||
(float)w->corner_radius, ®_tmp);
|
||||
glx_round_corners_dst(
|
||||
ps, w, w->glx_texture_bg, w->g.x, w->g.y, wid, hei,
|
||||
(float)ps->psglx->z - 0.5F,
|
||||
(float)w_opts.corner_radius, ®_tmp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -32,10 +32,9 @@ typedef struct clip {
|
|||
} clip_t;
|
||||
|
||||
void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, int fullw,
|
||||
int fullh, double opacity, bool argb, bool neg, int cr,
|
||||
int fullh, double opacity, bool argb, bool neg, unsigned int cr,
|
||||
xcb_render_picture_t pict, glx_texture_t *ptex, const region_t *reg_paint,
|
||||
const glx_prog_main_t *pprogram, clip_t *clip);
|
||||
void paint_one(session_t *ps, struct win *w, const region_t *reg_paint);
|
||||
|
||||
void paint_all(session_t *ps, struct win *const t);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ commands_for_window_body(struct layer *layer, struct backend_command *cmd,
|
|||
auto mode = win_calc_mode_raw(layer->win);
|
||||
int border_width = w->g.border_width;
|
||||
double dim = 0;
|
||||
if (w->dim) {
|
||||
if (layer->options.dim) {
|
||||
dim = inactive_dim;
|
||||
if (!inactive_dim_fixed) {
|
||||
dim *= layer->opacity;
|
||||
|
@ -48,7 +48,7 @@ commands_for_window_body(struct layer *layer, struct backend_command *cmd,
|
|||
frame_region);
|
||||
}
|
||||
}
|
||||
if (w->corner_radius > 0) {
|
||||
if (layer->options.corner_radius > 0) {
|
||||
win_region_remove_corners(w, layer->window.origin, &cmd->opaque_region);
|
||||
}
|
||||
region_scale(&cmd->target_mask, layer->window.origin, layer->scale);
|
||||
|
@ -61,15 +61,16 @@ commands_for_window_body(struct layer *layer, struct backend_command *cmd,
|
|||
cmd->blit = (struct backend_blit_args){
|
||||
.border_width = border_width,
|
||||
.target_mask = &cmd->target_mask,
|
||||
.corner_radius = w->corner_radius,
|
||||
.corner_radius = layer->options.corner_radius,
|
||||
.opacity = layer->opacity,
|
||||
.dim = dim,
|
||||
.scale = layer->scale,
|
||||
.effective_size = layer->window.size,
|
||||
.shader = w->fg_shader ? w->fg_shader->backend_shader : NULL,
|
||||
.color_inverted = w->invert_color,
|
||||
.shader = layer->options.shader->backend_shader,
|
||||
.color_inverted = layer->options.invert_color,
|
||||
.source_mask = NULL,
|
||||
.max_brightness = max_brightness};
|
||||
.max_brightness = max_brightness,
|
||||
};
|
||||
|
||||
if (w->frame_opacity == 1 || w->frame_opacity == 0) {
|
||||
return 1;
|
||||
|
@ -97,7 +98,7 @@ command_for_shadow(struct layer *layer, struct backend_command *cmd,
|
|||
const struct win_option *wintype_options,
|
||||
const struct x_monitors *monitors, const struct backend_command *end) {
|
||||
auto w = layer->win;
|
||||
if (!w->shadow) {
|
||||
if (!layer->options.shadow) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -143,8 +144,8 @@ command_for_shadow(struct layer *layer, struct backend_command *cmd,
|
|||
}
|
||||
}
|
||||
log_region(TRACE, &cmd->target_mask);
|
||||
if (w->corner_radius > 0) {
|
||||
cmd->source_mask.corner_radius = w->corner_radius;
|
||||
if (layer->options.corner_radius > 0) {
|
||||
cmd->source_mask.corner_radius = layer->options.corner_radius;
|
||||
cmd->source_mask.inverted = true;
|
||||
cmd->source_mask.origin =
|
||||
ivec2_sub(layer->window.origin, layer->shadow.origin);
|
||||
|
@ -156,7 +157,7 @@ command_for_shadow(struct layer *layer, struct backend_command *cmd,
|
|||
cmd->blit = (struct backend_blit_args){
|
||||
.opacity = layer->shadow_opacity,
|
||||
.max_brightness = 1,
|
||||
.source_mask = w->corner_radius > 0 ? &cmd->source_mask : NULL,
|
||||
.source_mask = layer->options.corner_radius > 0 ? &cmd->source_mask : NULL,
|
||||
.scale = layer->shadow_scale,
|
||||
.effective_size = layer->shadow.size,
|
||||
.target_mask = &cmd->target_mask,
|
||||
|
@ -170,7 +171,7 @@ command_for_blur(struct layer *layer, struct backend_command *cmd,
|
|||
const region_t *frame_region, bool force_blend, bool blur_frame) {
|
||||
auto w = layer->win;
|
||||
auto mode = win_calc_mode_raw(w);
|
||||
if (!w->blur_background || layer->blur_opacity == 0) {
|
||||
if (!layer->options.blur_background || layer->blur_opacity == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (force_blend || mode == WMODE_TRANS || layer->opacity < 1.0) {
|
||||
|
@ -189,15 +190,15 @@ command_for_blur(struct layer *layer, struct backend_command *cmd,
|
|||
|
||||
cmd->op = BACKEND_COMMAND_BLUR;
|
||||
cmd->origin = (ivec2){};
|
||||
if (w->corner_radius > 0) {
|
||||
if (layer->options.corner_radius > 0) {
|
||||
cmd->source_mask.origin = layer->window.origin;
|
||||
cmd->source_mask.corner_radius = w->corner_radius;
|
||||
cmd->source_mask.corner_radius = layer->options.corner_radius;
|
||||
cmd->source_mask.inverted = false;
|
||||
}
|
||||
cmd->blur = (struct backend_blur_args){
|
||||
.opacity = layer->blur_opacity,
|
||||
.target_mask = &cmd->target_mask,
|
||||
.source_mask = w->corner_radius > 0 ? &cmd->source_mask : NULL,
|
||||
.source_mask = layer->options.corner_radius > 0 ? &cmd->source_mask : NULL,
|
||||
};
|
||||
return 1;
|
||||
}
|
||||
|
@ -217,7 +218,7 @@ command_builder_apply_transparent_clipping(struct layout *layout, region_t *scra
|
|||
auto layer_start = end - layer->number_of_commands;
|
||||
for (auto i = end; i != begin; i--) {
|
||||
if (i == layer_start) {
|
||||
if (layer->win->transparent_clipping) {
|
||||
if (layer->options.transparent_clipping) {
|
||||
auto win = layer->win;
|
||||
auto mode = win_calc_mode_raw(layer->win);
|
||||
region_t tmp;
|
||||
|
@ -263,7 +264,7 @@ command_builder_apply_shadow_clipping(struct layout *layout, region_t *scratch_r
|
|||
if (i == layer_end) {
|
||||
layer += 1;
|
||||
layer_end += layer->number_of_commands;
|
||||
clip_shadow_above = layer->win->clip_shadow_above;
|
||||
clip_shadow_above = layer->options.clip_shadow_above;
|
||||
}
|
||||
|
||||
if (i->op == BACKEND_COMMAND_BLUR) {
|
||||
|
@ -370,13 +371,13 @@ void command_builder_build(struct command_builder *cb, struct layout *layout, bo
|
|||
unsigned ncmds = 1;
|
||||
dynarr_foreach(layout->layers, layer) {
|
||||
auto mode = win_calc_mode_raw(layer->win);
|
||||
if (layer->win->blur_background && layer->blur_opacity > 0 &&
|
||||
if (layer->options.blur_background && layer->blur_opacity > 0 &&
|
||||
(force_blend || mode == WMODE_TRANS || layer->opacity < 1.0 ||
|
||||
(blur_frame && mode == WMODE_FRAME_TRANS))) {
|
||||
// Needs blur
|
||||
ncmds += 1;
|
||||
}
|
||||
if (layer->win->shadow) {
|
||||
if (layer->options.shadow) {
|
||||
ncmds += 1;
|
||||
}
|
||||
if (layer->win->frame_opacity < 1 && layer->win->frame_opacity > 0) {
|
||||
|
|
|
@ -41,13 +41,15 @@ struct layout_manager {
|
|||
/// visible / should not be rendered. `out_layer` is modified either way.
|
||||
static bool layer_from_window(struct layer *out_layer, struct win *w, ivec2 size) {
|
||||
bool to_paint = false;
|
||||
if (!w->ever_damaged || w->paint_excluded) {
|
||||
auto w_opts = win_options(w);
|
||||
if (!w->ever_damaged || !w_opts.paint) {
|
||||
goto out;
|
||||
}
|
||||
if (w->win_image == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
out_layer->options = w_opts;
|
||||
out_layer->scale = (vec2){
|
||||
.x = win_animatable_get(w, WIN_SCRIPT_SCALE_X),
|
||||
.y = win_animatable_get(w, WIN_SCRIPT_SCALE_Y),
|
||||
|
@ -64,7 +66,7 @@ static bool layer_from_window(struct layer *out_layer, struct win *w, ivec2 size
|
|||
.x = win_animatable_get(w, WIN_SCRIPT_CROP_WIDTH),
|
||||
.y = win_animatable_get(w, WIN_SCRIPT_CROP_HEIGHT),
|
||||
});
|
||||
if (w->shadow) {
|
||||
if (w_opts.shadow) {
|
||||
out_layer->shadow_scale = (vec2){
|
||||
.x = win_animatable_get(w, WIN_SCRIPT_SHADOW_SCALE_X),
|
||||
.y = win_animatable_get(w, WIN_SCRIPT_SHADOW_SCALE_Y),
|
||||
|
@ -108,7 +110,6 @@ static bool layer_from_window(struct layer *out_layer, struct win *w, ivec2 size
|
|||
// their extent rectangle.
|
||||
out_layer->is_opaque =
|
||||
!win_has_alpha(w) && out_layer->opacity == 1.0F && !w->bounding_shaped;
|
||||
out_layer->is_clipping = w->transparent_clipping;
|
||||
out_layer->next_rank = -1;
|
||||
out_layer->prev_rank = -1;
|
||||
out_layer->key = wm_ref_treeid(w->tree_ref);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <picom/types.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "region.h"
|
||||
#include "wm/wm.h"
|
||||
|
||||
|
@ -18,6 +19,7 @@ struct layer {
|
|||
/// The window, this is only valid for the current layout. Once
|
||||
/// a frame has passed, windows could have been freed.
|
||||
struct win *win;
|
||||
struct window_options options;
|
||||
/// Damaged region of this layer, in screen coordinates
|
||||
region_t damaged;
|
||||
/// Window rectangle in screen coordinates, before it's scaled.
|
||||
|
@ -51,8 +53,6 @@ struct layer {
|
|||
|
||||
/// Is this window completely opaque?
|
||||
bool is_opaque;
|
||||
/// Is this window clipping the windows beneath it?
|
||||
bool is_clipping;
|
||||
|
||||
// TODO(yshui) make opaqueness/blur finer grained maybe? to support
|
||||
// things like blur-background-frame
|
||||
|
|
|
@ -210,8 +210,9 @@ err:
|
|||
return succeeded;
|
||||
}
|
||||
|
||||
image_handle renderer_shadow_from_mask(struct renderer *r, struct backend_base *backend,
|
||||
image_handle mask, int corner_radius, ivec2 mask_size) {
|
||||
image_handle
|
||||
renderer_shadow_from_mask(struct renderer *r, struct backend_base *backend,
|
||||
image_handle mask, unsigned int corner_radius, ivec2 mask_size) {
|
||||
image_handle normalized_mask_image = NULL, shadow_image = NULL,
|
||||
shadow_color_pixel = NULL;
|
||||
bool succeeded = false;
|
||||
|
@ -366,7 +367,7 @@ renderer_bind_shadow(struct renderer *r, struct backend_base *backend, struct wi
|
|||
return false;
|
||||
}
|
||||
w->shadow_image = renderer_shadow_from_mask(
|
||||
r, backend, w->mask_image, w->corner_radius,
|
||||
r, backend, w->mask_image, win_options(w).corner_radius,
|
||||
(ivec2){.width = w->widthb, .height = w->heightb});
|
||||
}
|
||||
if (!w->shadow_image) {
|
||||
|
|
346
src/wm/win.c
346
src/wm/win.c
|
@ -114,30 +114,24 @@ static inline struct wm_ref *win_get_leader(session_t *ps, struct win *w) {
|
|||
* Update focused state of a window.
|
||||
*/
|
||||
static void win_update_focused(session_t *ps, struct win *w) {
|
||||
if (w->focused_force != UNSET) {
|
||||
w->focused = w->focused_force;
|
||||
} else {
|
||||
bool is_wmwin = win_is_wmwin(w);
|
||||
w->focused = win_is_focused_raw(w);
|
||||
bool is_wmwin = win_is_wmwin(w);
|
||||
w->options.focused = win_is_focused_raw(w) ? TRI_TRUE : TRI_FALSE;
|
||||
|
||||
// Use wintype_focus, and treat WM windows and override-redirected
|
||||
// windows specially
|
||||
if (ps->o.wintype_option[w->window_type].focus ||
|
||||
(ps->o.mark_wmwin_focused && is_wmwin) ||
|
||||
(ps->o.mark_ovredir_focused &&
|
||||
wm_ref_client_of(w->tree_ref) == NULL && !is_wmwin) ||
|
||||
(w->a.map_state == XCB_MAP_STATE_VIEWABLE &&
|
||||
c2_match(ps->c2_state, w, ps->o.focus_blacklist, NULL))) {
|
||||
w->focused = true;
|
||||
}
|
||||
// Use wintype_focus, and treat WM windows and override-redirected
|
||||
// windows specially
|
||||
if (ps->o.wintype_option[w->window_type].focus ||
|
||||
(ps->o.mark_wmwin_focused && is_wmwin) ||
|
||||
(ps->o.mark_ovredir_focused && wm_ref_client_of(w->tree_ref) == NULL && !is_wmwin) ||
|
||||
(w->a.map_state == XCB_MAP_STATE_VIEWABLE &&
|
||||
c2_match(ps->c2_state, w, ps->o.focus_blacklist, NULL))) {
|
||||
w->options.focused = TRI_TRUE;
|
||||
}
|
||||
|
||||
// If window grouping detection is enabled, mark the window active if
|
||||
// its group is
|
||||
auto active_leader = wm_active_leader(ps->wm);
|
||||
if (ps->o.track_leader && active_leader &&
|
||||
win_get_leader(ps, w) == active_leader) {
|
||||
w->focused = true;
|
||||
}
|
||||
// If window grouping detection is enabled, mark the window active if
|
||||
// its group is
|
||||
auto active_leader = wm_active_leader(ps->wm);
|
||||
if (ps->o.track_leader && active_leader && win_get_leader(ps, w) == active_leader) {
|
||||
w->options.focused = TRI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,7 +317,6 @@ static inline void win_release_pixmap(backend_t *base, struct win *w) {
|
|||
static inline void win_release_shadow(backend_t *base, struct win *w) {
|
||||
log_debug("Releasing shadow of window %#010x (%s)", win_id(w), w->name);
|
||||
if (w->shadow_image) {
|
||||
assert(w->shadow);
|
||||
xcb_pixmap_t pixmap = XCB_NONE;
|
||||
pixmap = base->ops.release_image(base, w->shadow_image);
|
||||
w->shadow_image = NULL;
|
||||
|
@ -527,6 +520,14 @@ void win_process_secondary_flags(session_t *ps, struct win *w) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto old_options = win_options(w);
|
||||
region_t extents;
|
||||
pixman_region32_init(&extents);
|
||||
// Save old window extents. If window goes from having a shadow to not
|
||||
// having a shadow, we need to add the old, having-shadow extents to
|
||||
// damage.
|
||||
win_extents(w, &extents);
|
||||
|
||||
// Factor change flags could be set by previous stages, so must be handled
|
||||
// last
|
||||
if (win_check_flags_all(w, WIN_FLAGS_FACTOR_CHANGED)) {
|
||||
|
@ -539,6 +540,19 @@ void win_process_secondary_flags(session_t *ps, struct win *w) {
|
|||
add_damage_from_win(ps, w);
|
||||
win_clear_flags(w, WIN_FLAGS_DAMAGED);
|
||||
}
|
||||
|
||||
auto new_options = win_options(w);
|
||||
if (win_options_eq(&old_options, &new_options)) {
|
||||
pixman_region32_fini(&extents);
|
||||
return;
|
||||
}
|
||||
|
||||
add_damage_from_win(ps, w); // Only for legacy backends
|
||||
if (new_options.shadow != old_options.shadow && !new_options.shadow) {
|
||||
add_damage(ps, &extents);
|
||||
win_release_shadow(ps->backend_data, w);
|
||||
}
|
||||
pixman_region32_fini(&extents);
|
||||
}
|
||||
|
||||
void win_process_image_flags(session_t *ps, struct win *w) {
|
||||
|
@ -801,8 +815,8 @@ static double win_calc_opacity_target(session_t *ps, const struct win *w) {
|
|||
// Try obeying opacity property and window type opacity firstly
|
||||
if (w->has_opacity_prop) {
|
||||
opacity = ((double)w->opacity_prop) / OPAQUE;
|
||||
} else if (w->opacity_is_set) {
|
||||
opacity = w->opacity_set;
|
||||
} else if (!safe_isnan(w->options.opacity)) {
|
||||
opacity = w->options.opacity;
|
||||
} else if (!safe_isnan(ps->o.wintype_option[w->window_type].opacity)) {
|
||||
opacity = ps->o.wintype_option[w->window_type].opacity;
|
||||
} else {
|
||||
|
@ -810,14 +824,14 @@ static double win_calc_opacity_target(session_t *ps, const struct win *w) {
|
|||
// focused
|
||||
if (win_is_focused_raw(w)) {
|
||||
opacity = ps->o.active_opacity;
|
||||
} else if (!w->focused) {
|
||||
} else if (!win_options(w).focused) {
|
||||
// Respect inactive_opacity in some cases
|
||||
opacity = ps->o.inactive_opacity;
|
||||
}
|
||||
}
|
||||
|
||||
// respect inactive override
|
||||
if (ps->o.inactive_opacity_override && !w->focused) {
|
||||
if (ps->o.inactive_opacity_override && !win_options(w).focused) {
|
||||
opacity = ps->o.inactive_opacity;
|
||||
}
|
||||
|
||||
|
@ -852,16 +866,17 @@ void unmap_win_finish(session_t *ps, struct win *w) {
|
|||
/**
|
||||
* Determine whether a window is to be dimmed.
|
||||
*/
|
||||
bool win_should_dim(session_t *ps, const struct win *w) {
|
||||
static void win_update_dim(session_t *ps, struct win *w) {
|
||||
// Make sure we do nothing if the window is unmapped / being destroyed
|
||||
if (w->state == WSTATE_UNMAPPED) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ps->o.inactive_dim > 0 && !(w->focused)) {
|
||||
return true;
|
||||
if (ps->o.inactive_dim > 0 && !win_options(w).focused) {
|
||||
w->options.dim = TRI_TRUE;
|
||||
} else {
|
||||
w->options.dim = TRI_FALSE;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -882,82 +897,30 @@ void win_update_prop_shadow_raw(struct x_connection *c, struct atom *atoms, stru
|
|||
free_winprop(&prop);
|
||||
}
|
||||
|
||||
static void win_set_shadow(session_t *ps, struct win *w, bool shadow_new) {
|
||||
if (w->shadow == shadow_new) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_debug("Updating shadow property of window %#010x (%s) to %d", win_id(w),
|
||||
w->name, shadow_new);
|
||||
|
||||
// We don't handle property updates of non-visible windows until they are
|
||||
// mapped.
|
||||
assert(w->state == WSTATE_MAPPED);
|
||||
|
||||
// Keep a copy of window extent before the shadow change. Will be used for
|
||||
// calculation of damaged region
|
||||
region_t extents;
|
||||
pixman_region32_init(&extents);
|
||||
win_extents(w, &extents);
|
||||
|
||||
if (ps->redirected) {
|
||||
// Add damage for shadow change
|
||||
|
||||
// Window extents need update on shadow state change
|
||||
// Shadow geometry currently doesn't change on shadow state change
|
||||
// calc_shadow_geometry(ps, w);
|
||||
if (shadow_new) {
|
||||
// Mark the new extents as damaged if the shadow is added
|
||||
assert(!w->shadow_image);
|
||||
pixman_region32_clear(&extents);
|
||||
win_extents(w, &extents);
|
||||
add_damage_from_win(ps, w);
|
||||
} else {
|
||||
// Mark the old extents as damaged if the shadow is
|
||||
// removed
|
||||
add_damage(ps, &extents);
|
||||
win_release_shadow(ps->backend_data, w);
|
||||
}
|
||||
|
||||
// Only set pending_updates if we are redirected. Otherwise change
|
||||
// of a shadow won't have influence on whether we should redirect.
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
|
||||
w->shadow = shadow_new;
|
||||
|
||||
pixman_region32_fini(&extents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a window should have shadow, and update things depending
|
||||
* on shadow state.
|
||||
*/
|
||||
static void win_determine_shadow(session_t *ps, struct win *w) {
|
||||
log_debug("Determining shadow of window %#010x (%s)", win_id(w), w->name);
|
||||
bool shadow_new = w->shadow;
|
||||
w->options.shadow = TRI_UNKNOWN;
|
||||
|
||||
if (w->shadow_force != UNSET) {
|
||||
shadow_new = w->shadow_force;
|
||||
} else if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
||||
shadow_new = true;
|
||||
if (!ps->o.wintype_option[w->window_type].shadow) {
|
||||
log_debug("Shadow disabled by wintypes");
|
||||
shadow_new = false;
|
||||
} else if (c2_match(ps->c2_state, w, ps->o.shadow_blacklist, NULL)) {
|
||||
log_debug("Shadow disabled by shadow-exclude");
|
||||
shadow_new = false;
|
||||
} else if (ps->o.shadow_ignore_shaped && w->bounding_shaped &&
|
||||
!w->rounded_corners) {
|
||||
log_debug("Shadow disabled by shadow-ignore-shaped");
|
||||
shadow_new = false;
|
||||
} else if (w->prop_shadow == 0) {
|
||||
log_debug("Shadow disabled by shadow property");
|
||||
shadow_new = false;
|
||||
}
|
||||
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) {
|
||||
return;
|
||||
}
|
||||
if (!ps->o.wintype_option[w->window_type].shadow) {
|
||||
log_debug("Shadow disabled by wintypes");
|
||||
w->options.shadow = TRI_FALSE;
|
||||
} else if (c2_match(ps->c2_state, w, ps->o.shadow_blacklist, NULL)) {
|
||||
log_debug("Shadow disabled by shadow-exclude");
|
||||
w->options.shadow = TRI_FALSE;
|
||||
} else if (ps->o.shadow_ignore_shaped && w->bounding_shaped && !w->rounded_corners) {
|
||||
log_debug("Shadow disabled by shadow-ignore-shaped");
|
||||
w->options.shadow = TRI_FALSE;
|
||||
} else if (w->prop_shadow == 0) {
|
||||
log_debug("Shadow disabled by shadow property");
|
||||
w->options.shadow = TRI_FALSE;
|
||||
}
|
||||
|
||||
win_set_shadow(ps, w, shadow_new);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -994,99 +957,21 @@ bool win_update_prop_fullscreen(struct x_connection *c, const struct atom *atoms
|
|||
static void win_determine_clip_shadow_above(session_t *ps, struct win *w) {
|
||||
bool should_crop = (ps->o.wintype_option[w->window_type].clip_shadow_above ||
|
||||
c2_match(ps->c2_state, w, ps->o.shadow_clip_list, NULL));
|
||||
w->clip_shadow_above = should_crop;
|
||||
}
|
||||
|
||||
static void win_set_invert_color(session_t *ps, struct win *w, bool invert_color_new) {
|
||||
if (w->invert_color == invert_color_new) {
|
||||
return;
|
||||
}
|
||||
|
||||
w->invert_color = invert_color_new;
|
||||
|
||||
add_damage_from_win(ps, w);
|
||||
w->options.clip_shadow_above = should_crop ? TRI_TRUE : TRI_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a window should have color inverted.
|
||||
*/
|
||||
static void win_determine_invert_color(session_t *ps, struct win *w) {
|
||||
bool invert_color_new = w->invert_color;
|
||||
|
||||
if (UNSET != w->invert_color_force) {
|
||||
invert_color_new = w->invert_color_force;
|
||||
} else if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
||||
invert_color_new = c2_match(ps->c2_state, w, ps->o.invert_color_list, NULL);
|
||||
}
|
||||
|
||||
win_set_invert_color(ps, w, invert_color_new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set w->invert_color_force of a window.
|
||||
*/
|
||||
void win_set_invert_color_force(session_t *ps, struct win *w, switch_t val) {
|
||||
if (val != w->invert_color_force) {
|
||||
w->invert_color_force = val;
|
||||
win_determine_invert_color(ps, w);
|
||||
queue_redraw(ps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set w->fade_force of a window.
|
||||
*
|
||||
* Doesn't affect fading already in progress
|
||||
*/
|
||||
void win_set_fade_force(struct win *w, switch_t val) {
|
||||
w->fade_force = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set w->focused_force of a window.
|
||||
*/
|
||||
void win_set_focused_force(session_t *ps, struct win *w, switch_t val) {
|
||||
if (val != w->focused_force) {
|
||||
w->focused_force = val;
|
||||
win_on_factor_change(ps, w);
|
||||
queue_redraw(ps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set w->shadow_force of a window.
|
||||
*/
|
||||
void win_set_shadow_force(session_t *ps, struct win *w, switch_t val) {
|
||||
if (val != w->shadow_force) {
|
||||
w->shadow_force = val;
|
||||
win_determine_shadow(ps, w);
|
||||
queue_redraw(ps);
|
||||
}
|
||||
}
|
||||
|
||||
static void win_set_blur_background(session_t *ps, struct win *w, bool blur_background_new) {
|
||||
if (w->blur_background == blur_background_new) {
|
||||
w->options.invert_color = TRI_UNKNOWN;
|
||||
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
w->blur_background = blur_background_new;
|
||||
|
||||
// This damage might not be absolutely necessary (e.g. when the window is
|
||||
// opaque), but blur_background changes should be rare, so this should be
|
||||
// fine.
|
||||
add_damage_from_win(ps, w);
|
||||
}
|
||||
|
||||
static void win_set_fg_shader(session_t *ps, struct win *w, struct shader_info *shader_new) {
|
||||
if (w->fg_shader == shader_new) {
|
||||
return;
|
||||
if (c2_match(ps->c2_state, w, ps->o.invert_color_list, NULL)) {
|
||||
w->options.invert_color = TRI_TRUE;
|
||||
}
|
||||
|
||||
w->fg_shader = shader_new;
|
||||
|
||||
// A different shader might change how the window is drawn, these changes
|
||||
// should be rare however, so this should be fine.
|
||||
add_damage_from_win(ps, w);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1094,6 +979,7 @@ static void win_set_fg_shader(session_t *ps, struct win *w, struct shader_info *
|
|||
*/
|
||||
static void win_determine_blur_background(session_t *ps, struct win *w) {
|
||||
log_debug("Determining blur-background of window %#010x (%s)", win_id(w), w->name);
|
||||
w->options.blur_background = TRI_UNKNOWN;
|
||||
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) {
|
||||
return;
|
||||
}
|
||||
|
@ -1102,15 +988,12 @@ static void win_determine_blur_background(session_t *ps, struct win *w) {
|
|||
if (blur_background_new) {
|
||||
if (!ps->o.wintype_option[w->window_type].blur_background) {
|
||||
log_debug("Blur background disabled by wintypes");
|
||||
blur_background_new = false;
|
||||
w->options.blur_background = TRI_FALSE;
|
||||
} else if (c2_match(ps->c2_state, w, ps->o.blur_background_blacklist, NULL)) {
|
||||
log_debug("Blur background disabled by "
|
||||
"blur-background-exclude");
|
||||
blur_background_new = false;
|
||||
log_debug("Blur background disabled by blur-background-exclude");
|
||||
w->options.blur_background = TRI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
win_set_blur_background(ps, w, blur_background_new);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1118,27 +1001,28 @@ static void win_determine_blur_background(session_t *ps, struct win *w) {
|
|||
*/
|
||||
static void win_determine_rounded_corners(session_t *ps, struct win *w) {
|
||||
void *radius_override = NULL;
|
||||
if (c2_match(ps->c2_state, w, ps->o.corner_radius_rules, &radius_override)) {
|
||||
log_debug("Matched corner rule! %d", w->corner_radius);
|
||||
bool blacklisted = c2_match(ps->c2_state, w, ps->o.rounded_corners_blacklist, NULL);
|
||||
if (blacklisted) {
|
||||
w->options.corner_radius = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ps->o.corner_radius == 0 && !radius_override) {
|
||||
w->corner_radius = 0;
|
||||
return;
|
||||
bool matched = c2_match(ps->c2_state, w, ps->o.corner_radius_rules, &radius_override);
|
||||
if (matched) {
|
||||
log_debug("Window %#010x (%s) matched corner rule! %d", win_id(w),
|
||||
w->name, (int)(long)radius_override);
|
||||
}
|
||||
|
||||
// Don't round full screen windows & excluded windows,
|
||||
// unless we find a corner override in corner_radius_rules
|
||||
if (!radius_override &&
|
||||
((w && w->is_fullscreen) ||
|
||||
c2_match(ps->c2_state, w, ps->o.rounded_corners_blacklist, NULL))) {
|
||||
w->corner_radius = 0;
|
||||
if (!matched && w && w->is_fullscreen) {
|
||||
w->options.corner_radius = 0;
|
||||
log_debug("Not rounding corners for window %#010x", win_id(w));
|
||||
} else {
|
||||
if (radius_override) {
|
||||
w->corner_radius = (int)(long)radius_override;
|
||||
if (matched) {
|
||||
w->options.corner_radius = (int)(long)radius_override;
|
||||
} else {
|
||||
w->corner_radius = ps->o.corner_radius;
|
||||
w->options.corner_radius = -1;
|
||||
}
|
||||
|
||||
log_debug("Rounding corners for window %#010x", win_id(w));
|
||||
|
@ -1156,18 +1040,13 @@ static void win_determine_fg_shader(session_t *ps, struct win *w) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto shader_new = ps->o.window_shader_fg;
|
||||
void *val = NULL;
|
||||
w->options.shader = NULL;
|
||||
if (c2_match(ps->c2_state, w, ps->o.window_shader_fg_rules, &val)) {
|
||||
shader_new = val;
|
||||
struct shader_info *shader = NULL;
|
||||
HASH_FIND_STR(ps->shaders, val, shader);
|
||||
w->options.shader = shader;
|
||||
}
|
||||
|
||||
struct shader_info *shader = NULL;
|
||||
if (shader_new) {
|
||||
HASH_FIND_STR(ps->shaders, shader_new, shader);
|
||||
}
|
||||
|
||||
win_set_fg_shader(ps, w, shader);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1178,16 +1057,13 @@ void win_update_opacity_rule(session_t *ps, struct win *w) {
|
|||
return;
|
||||
}
|
||||
|
||||
double opacity = 1.0;
|
||||
bool is_set = false;
|
||||
double opacity = NAN;
|
||||
void *val = NULL;
|
||||
if (c2_match(ps->c2_state, w, ps->o.opacity_rules, &val)) {
|
||||
opacity = ((double)(long)val) / 100.0;
|
||||
is_set = true;
|
||||
}
|
||||
|
||||
w->opacity_set = opacity;
|
||||
w->opacity_is_set = is_set;
|
||||
w->options.opacity = opacity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1210,28 +1086,35 @@ void win_on_factor_change(session_t *ps, struct win *w) {
|
|||
win_determine_blur_background(ps, w);
|
||||
win_determine_rounded_corners(ps, w);
|
||||
win_determine_fg_shader(ps, w);
|
||||
win_update_dim(ps, w);
|
||||
w->mode = win_calc_mode(w);
|
||||
log_debug("Window mode changed to %d", w->mode);
|
||||
win_update_opacity_rule(ps, w);
|
||||
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
||||
w->paint_excluded = c2_match(ps->c2_state, w, ps->o.paint_blacklist, NULL);
|
||||
w->options.paint = c2_match(ps->c2_state, w, ps->o.paint_blacklist, NULL)
|
||||
? TRI_FALSE
|
||||
: TRI_UNKNOWN;
|
||||
}
|
||||
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
|
||||
w->unredir_if_possible_excluded =
|
||||
c2_match(ps->c2_state, w, ps->o.unredir_if_possible_blacklist, NULL);
|
||||
w->options.unredir_ignore =
|
||||
c2_match(ps->c2_state, w, ps->o.unredir_if_possible_blacklist, NULL)
|
||||
? TRI_TRUE
|
||||
: TRI_UNKNOWN;
|
||||
}
|
||||
|
||||
w->fade_excluded = c2_match(ps->c2_state, w, ps->o.fade_blacklist, NULL);
|
||||
w->options.fade =
|
||||
c2_match(ps->c2_state, w, ps->o.fade_blacklist, NULL) ? TRI_FALSE : TRI_UNKNOWN;
|
||||
|
||||
w->transparent_clipping =
|
||||
ps->o.transparent_clipping &&
|
||||
!c2_match(ps->c2_state, w, ps->o.transparent_clipping_blacklist, NULL);
|
||||
w->options.transparent_clipping =
|
||||
c2_match(ps->c2_state, w, ps->o.transparent_clipping_blacklist, NULL)
|
||||
? TRI_FALSE
|
||||
: TRI_UNKNOWN;
|
||||
|
||||
w->reg_ignore_valid = false;
|
||||
if (ps->debug_window != XCB_NONE &&
|
||||
(win_id(w) == ps->debug_window ||
|
||||
(win_client_id(w, /*fallback_to_self=*/false) == ps->debug_window))) {
|
||||
w->paint_excluded = true;
|
||||
w->options.paint = TRI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1378,12 +1261,6 @@ struct win *win_maybe_allocate(session_t *ps, struct wm_ref *cursor,
|
|||
// property/attributes/etc
|
||||
// change
|
||||
|
||||
// Runtime variables, updated by dbus
|
||||
.fade_force = UNSET,
|
||||
.shadow_force = UNSET,
|
||||
.focused_force = UNSET,
|
||||
.invert_color_force = UNSET,
|
||||
|
||||
.mode = WMODE_TRANS,
|
||||
.leader = XCB_NONE,
|
||||
.cache_leader = NULL,
|
||||
|
@ -1480,6 +1357,10 @@ struct win *win_maybe_allocate(session_t *ps, struct wm_ref *cursor,
|
|||
new->pictfmt = x_get_pictform_for_visual(&ps->c, new->a.visual);
|
||||
new->client_pictfmt = NULL;
|
||||
new->tree_ref = cursor;
|
||||
new->options = WIN_MAYBE_OPTIONS_DEFAULT;
|
||||
new->options_override = WIN_MAYBE_OPTIONS_DEFAULT;
|
||||
new->options_default = &ps->window_options_default;
|
||||
new->options.focused = TRI_FALSE;
|
||||
|
||||
// Set all the stale flags on this new window, so it's properties will get
|
||||
// updated when it's mapped
|
||||
|
@ -1691,9 +1572,12 @@ void win_set_focused(session_t *ps, struct win *w) {
|
|||
*/
|
||||
void win_extents(const struct win *w, region_t *res) {
|
||||
pixman_region32_clear(res);
|
||||
pixman_region32_union_rect(res, res, w->g.x, w->g.y, (uint)w->widthb, (uint)w->heightb);
|
||||
if (w->state != WSTATE_MAPPED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (w->shadow) {
|
||||
pixman_region32_union_rect(res, res, w->g.x, w->g.y, (uint)w->widthb, (uint)w->heightb);
|
||||
if (win_options(w).shadow) {
|
||||
assert(w->shadow_width >= 0 && w->shadow_height >= 0);
|
||||
pixman_region32_union_rect(res, res, w->g.x + w->shadow_dx,
|
||||
w->g.y + w->shadow_dy, (uint)w->shadow_width,
|
||||
|
|
132
src/wm/win.h
132
src/wm/win.h
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "c2.h"
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "defs.h"
|
||||
#include "region.h"
|
||||
#include "render.h"
|
||||
|
@ -159,10 +160,6 @@ struct win {
|
|||
bool rounded_corners;
|
||||
/// Whether this window is to be painted.
|
||||
bool to_paint;
|
||||
/// Whether the window is painting excluded.
|
||||
bool paint_excluded;
|
||||
/// Whether the window is unredirect-if-possible excluded.
|
||||
bool unredir_if_possible_excluded;
|
||||
/// Whether this window is in open/close state.
|
||||
bool in_openclose;
|
||||
|
||||
|
@ -174,12 +171,6 @@ struct win {
|
|||
/// Cached topmost window ID of the leader window.
|
||||
struct wm_ref *cache_leader;
|
||||
|
||||
// Focus-related members
|
||||
/// Whether the window is to be considered focused.
|
||||
bool focused;
|
||||
/// Override value of window focus state. Set by D-Bus method calls.
|
||||
switch_t focused_force;
|
||||
|
||||
// Blacklist related members
|
||||
/// Name of the window.
|
||||
char *name;
|
||||
|
@ -199,7 +190,7 @@ struct win {
|
|||
bool is_focused;
|
||||
|
||||
// Opacity-related members
|
||||
/// Window opacity
|
||||
/// The final window opacity if no animation is running
|
||||
double opacity;
|
||||
/// true if window (or client window, for broken window managers
|
||||
/// not transferring client window's _NET_WM_WINDOW_OPACITY value) has opacity
|
||||
|
@ -207,24 +198,11 @@ struct win {
|
|||
bool has_opacity_prop;
|
||||
/// Cached value of opacity window attribute.
|
||||
opacity_t opacity_prop;
|
||||
/// true if opacity is set by some rules
|
||||
bool opacity_is_set;
|
||||
/// Last window opacity value set by the rules.
|
||||
double opacity_set;
|
||||
|
||||
/// Radius of rounded window corners
|
||||
int corner_radius;
|
||||
float border_col[4];
|
||||
|
||||
// Fading-related members
|
||||
/// Override value of window fade state. Set by D-Bus method calls.
|
||||
switch_t fade_force;
|
||||
/// Whether fading is excluded by the rules. Calculated.
|
||||
bool fade_excluded;
|
||||
|
||||
/// Whether transparent clipping is excluded by the rules.
|
||||
bool transparent_clipping;
|
||||
|
||||
// Frame-opacity-related members
|
||||
/// Current window frame opacity. Affected by window opacity.
|
||||
double frame_opacity;
|
||||
|
@ -232,10 +210,6 @@ struct win {
|
|||
margin_t frame_extents;
|
||||
|
||||
// Shadow-related members
|
||||
/// Whether a window has shadow. Calculated.
|
||||
bool shadow;
|
||||
/// Override value of window shadow state. Set by D-Bus method calls.
|
||||
switch_t shadow_force;
|
||||
/// Window specific shadow factor. The final shadow opacity is a combination of
|
||||
/// this, the window opacity, and the window frame opacity.
|
||||
double shadow_opacity;
|
||||
|
@ -252,24 +226,6 @@ struct win {
|
|||
/// The value of _COMPTON_SHADOW attribute of the window. Below 0 for
|
||||
/// none.
|
||||
long long prop_shadow;
|
||||
/// Do not paint shadow over this window.
|
||||
bool clip_shadow_above;
|
||||
|
||||
// Dim-related members
|
||||
/// Whether the window is to be dimmed.
|
||||
bool dim;
|
||||
|
||||
/// Whether to invert window color.
|
||||
bool invert_color;
|
||||
/// Override value of window color inversion state. Set by D-Bus method
|
||||
/// calls.
|
||||
switch_t invert_color_force;
|
||||
|
||||
/// Whether to blur window background.
|
||||
bool blur_background;
|
||||
|
||||
/// The custom window shader to use when rendering.
|
||||
struct shader_info *fg_shader;
|
||||
|
||||
struct c2_window_state c2_state;
|
||||
|
||||
|
@ -285,6 +241,13 @@ struct win {
|
|||
/// The damaged region of the window, in window local coordinates.
|
||||
region_t damaged;
|
||||
|
||||
/// Per-window options coming from rules
|
||||
struct window_maybe_options options;
|
||||
/// Override of per-window options, used by dbus interface
|
||||
struct window_maybe_options options_override;
|
||||
/// Global per-window options default
|
||||
const struct window_options *options_default;
|
||||
|
||||
/// Previous state of the window before state changed. This is used
|
||||
/// by `win_process_animation_and_state_change` to trigger appropriate
|
||||
/// animations.
|
||||
|
@ -334,6 +297,68 @@ static const struct script_output_info win_script_outputs[] = {
|
|||
[NUM_OF_WIN_SCRIPT_OUTPUTS] = {NULL},
|
||||
};
|
||||
|
||||
static const struct window_maybe_options WIN_MAYBE_OPTIONS_DEFAULT = {
|
||||
.blur_background = TRI_UNKNOWN,
|
||||
.clip_shadow_above = TRI_UNKNOWN,
|
||||
.shadow = TRI_UNKNOWN,
|
||||
.fade = TRI_UNKNOWN,
|
||||
.invert_color = TRI_UNKNOWN,
|
||||
.paint = TRI_UNKNOWN,
|
||||
.dim = TRI_UNKNOWN,
|
||||
.opacity = NAN,
|
||||
.shader = NULL,
|
||||
.corner_radius = -1,
|
||||
.unredir_ignore = TRI_UNKNOWN,
|
||||
};
|
||||
|
||||
/// Combine two window options. The `upper` value has higher priority, the `lower` value
|
||||
/// will only be used if the corresponding value in `upper` is not set (e.g. it is
|
||||
/// TRI_UNKNOWN for tristate values, NaN for opacity, -1 for corner_radius).
|
||||
static inline struct window_maybe_options __attribute__((always_inline))
|
||||
win_maybe_options_fold(struct window_maybe_options upper, struct window_maybe_options lower) {
|
||||
return (struct window_maybe_options){
|
||||
.unredir_ignore = tri_or(upper.unredir_ignore, lower.unredir_ignore),
|
||||
.blur_background = tri_or(upper.blur_background, lower.blur_background),
|
||||
.clip_shadow_above = tri_or(upper.clip_shadow_above, lower.clip_shadow_above),
|
||||
.shadow = tri_or(upper.shadow, lower.shadow),
|
||||
.dim = tri_or(upper.dim, lower.dim),
|
||||
.fade = tri_or(upper.fade, lower.fade),
|
||||
.focused = tri_or(upper.focused, lower.focused),
|
||||
.invert_color = tri_or(upper.invert_color, lower.invert_color),
|
||||
.paint = tri_or(upper.paint, lower.paint),
|
||||
.opacity = !safe_isnan(upper.opacity) ? upper.opacity : lower.opacity,
|
||||
.shader = upper.shader ? upper.shader : lower.shader,
|
||||
.corner_radius = upper.corner_radius >= 0 ? upper.corner_radius : lower.corner_radius,
|
||||
};
|
||||
}
|
||||
|
||||
/// Unwrap a `window_maybe_options` to a `window_options`, using the default value for
|
||||
/// values that are not set in the `window_maybe_options`.
|
||||
static inline struct window_options __attribute__((always_inline))
|
||||
win_maybe_options_or(struct window_maybe_options maybe, struct window_options def) {
|
||||
return (struct window_options){
|
||||
.unredir_ignore = tri_or_bool(maybe.unredir_ignore, def.unredir_ignore),
|
||||
.blur_background = tri_or_bool(maybe.blur_background, def.blur_background),
|
||||
.clip_shadow_above = tri_or_bool(maybe.clip_shadow_above, def.clip_shadow_above),
|
||||
.shadow = tri_or_bool(maybe.shadow, def.shadow),
|
||||
.corner_radius = maybe.corner_radius >= 0 ? (unsigned int)maybe.corner_radius
|
||||
: def.corner_radius,
|
||||
.dim = tri_or_bool(maybe.dim, def.dim),
|
||||
.fade = tri_or_bool(maybe.fade, def.fade),
|
||||
.focused = tri_or_bool(maybe.focused, def.focused),
|
||||
.invert_color = tri_or_bool(maybe.invert_color, def.invert_color),
|
||||
.paint = tri_or_bool(maybe.paint, def.paint),
|
||||
.opacity = !safe_isnan(maybe.opacity) ? maybe.opacity : def.opacity,
|
||||
.shader = maybe.shader ? maybe.shader : def.shader,
|
||||
};
|
||||
}
|
||||
|
||||
static inline struct window_options __attribute__((always_inline))
|
||||
win_options(const struct win *w) {
|
||||
return win_maybe_options_or(
|
||||
win_maybe_options_fold(w->options_override, w->options), *w->options_default);
|
||||
}
|
||||
|
||||
/// Process pending updates/images flags on a window. Has to be called in X critical
|
||||
/// section. Returns true if the window had an animation running and it has just finished,
|
||||
/// or if the window's states just changed and there is no animation defined for this
|
||||
|
@ -358,10 +383,6 @@ void win_release_images(struct backend_base *backend, struct win *w);
|
|||
winmode_t attr_pure win_calc_mode_raw(const struct win *w);
|
||||
// TODO(yshui) `win_calc_mode` is only used by legacy backends
|
||||
winmode_t attr_pure win_calc_mode(const struct win *w);
|
||||
void win_set_shadow_force(session_t *ps, struct win *w, switch_t val);
|
||||
void win_set_fade_force(struct win *w, switch_t val);
|
||||
void win_set_focused_force(session_t *ps, struct win *w, switch_t val);
|
||||
void win_set_invert_color_force(session_t *ps, struct win *w, switch_t val);
|
||||
/**
|
||||
* Set real focused state of a window.
|
||||
*/
|
||||
|
@ -369,8 +390,6 @@ void win_set_focused(session_t *ps, struct win *w);
|
|||
void win_on_factor_change(session_t *ps, struct win *w);
|
||||
void win_on_client_update(session_t *ps, struct win *w);
|
||||
|
||||
bool attr_pure win_should_dim(session_t *ps, const struct win *w);
|
||||
|
||||
int attr_pure win_find_monitor(const struct x_monitors *monitors, const struct win *mw);
|
||||
|
||||
/// Recheck if a window is fullscreen
|
||||
|
@ -529,14 +548,15 @@ win_region_remove_corners(const struct win *w, ivec2 origin, region_t *res) {
|
|||
{1, 0},
|
||||
{1, 1},
|
||||
};
|
||||
int corner_radius = (int)win_options(w).corner_radius;
|
||||
rect_t rectangles[4];
|
||||
for (size_t i = 0; i < ARR_SIZE(corner_index); i++) {
|
||||
rectangles[i] = (rect_t){
|
||||
.x1 = origin.x + corner_index[i][0] * (w->widthb - w->corner_radius),
|
||||
.y1 = origin.y + corner_index[i][1] * (w->heightb - w->corner_radius),
|
||||
.x1 = origin.x + corner_index[i][0] * (w->widthb - corner_radius),
|
||||
.y1 = origin.y + corner_index[i][1] * (w->heightb - corner_radius),
|
||||
};
|
||||
rectangles[i].x2 = rectangles[i].x1 + w->corner_radius;
|
||||
rectangles[i].y2 = rectangles[i].y1 + w->corner_radius;
|
||||
rectangles[i].x2 = rectangles[i].x1 + corner_radius;
|
||||
rectangles[i].y2 = rectangles[i].y1 + corner_radius;
|
||||
}
|
||||
region_t corners;
|
||||
pixman_region32_init_rects(&corners, rectangles, 4);
|
||||
|
|
Loading…
Add table
Reference in a new issue