mirror of https://github.com/yshui/picom.git
event: delayed handling of window property changes
Move handling window property changes into the X critical section. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
8f78b9b631
commit
f3ff7eff8c
42
src/event.c
42
src/event.c
|
@ -472,6 +472,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
return;
|
||||
}
|
||||
|
||||
ps->pending_updates = true;
|
||||
// If WM_STATE changes
|
||||
if (ev->atom == ps->atoms->aWM_STATE) {
|
||||
// Check whether it could be a client window
|
||||
|
@ -486,17 +487,18 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
// would be NULL.
|
||||
if (w_top) {
|
||||
win_set_flags(w_top, WIN_FLAGS_CLIENT_STALE);
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If _NET_WM_WINDOW_TYPE changes... God knows why this would happen, but
|
||||
// there are always some stupid applications. (#144)
|
||||
if (ev->atom == ps->atoms->a_NET_WM_WINDOW_TYPE) {
|
||||
struct managed_win *w = NULL;
|
||||
if ((w = find_toplevel(ps, ev->window)))
|
||||
win_update_wintype(ps, w);
|
||||
if ((w = find_toplevel(ps, ev->window))) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
if (ev->atom == ps->atoms->a_NET_WM_BYPASS_COMPOSITOR) {
|
||||
|
@ -507,29 +509,22 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
// If _NET_WM_OPACITY changes
|
||||
if (ev->atom == ps->atoms->a_NET_WM_WINDOW_OPACITY) {
|
||||
auto w = find_managed_win(ps, ev->window) ?: find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_update_opacity_prop(ps, w);
|
||||
// we cannot receive OPACITY change when window is destroyed
|
||||
assert(w->state != WSTATE_DESTROYING);
|
||||
win_update_opacity_target(ps, w);
|
||||
}
|
||||
win_set_property_stale(w, ps->atoms->a_NET_WM_WINDOW_OPACITY);
|
||||
}
|
||||
|
||||
// If frame extents property changes
|
||||
if (ps->o.frame_opacity > 0 && ev->atom == ps->atoms->a_NET_FRAME_EXTENTS) {
|
||||
auto w = find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_update_frame_extents(ps, w, ev->window);
|
||||
// If frame extents change, the window needs repaint
|
||||
add_damage_from_win(ps, w);
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
// If name changes
|
||||
if (ps->atoms->aWM_NAME == ev->atom || ps->atoms->a_NET_WM_NAME == ev->atom) {
|
||||
auto w = find_toplevel(ps, ev->window);
|
||||
if (w && win_update_name(ps, w) == 1) {
|
||||
win_on_factor_change(ps, w);
|
||||
if (w) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -537,16 +532,15 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
if (ps->atoms->aWM_CLASS == ev->atom) {
|
||||
auto w = find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_get_class(ps, w);
|
||||
win_on_factor_change(ps, w);
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
// If role changes
|
||||
if (ps->atoms->aWM_WINDOW_ROLE == ev->atom) {
|
||||
auto w = find_toplevel(ps, ev->window);
|
||||
if (w && 1 == win_get_role(ps, w)) {
|
||||
win_on_factor_change(ps, w);
|
||||
if (w) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,7 +548,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
if (ps->atoms->a_COMPTON_SHADOW == ev->atom) {
|
||||
auto w = find_managed_win(ps, ev->window);
|
||||
if (w) {
|
||||
win_update_prop_shadow(ps, w);
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,7 +557,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
(ps->o.detect_client_leader && ps->atoms->aWM_CLIENT_LEADER == ev->atom)) {
|
||||
auto w = find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_update_leader(ps, w);
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -571,10 +565,12 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
for (latom_t *platom = ps->track_atom_lst; platom; platom = platom->next) {
|
||||
if (platom->atom == ev->atom) {
|
||||
auto w = find_managed_win(ps, ev->window);
|
||||
if (!w)
|
||||
if (!w) {
|
||||
w = find_toplevel(ps, ev->window);
|
||||
if (w)
|
||||
win_on_factor_change(ps, w);
|
||||
}
|
||||
if (w) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
155
src/win.c
155
src/win.c
|
@ -53,6 +53,31 @@ static const int WIN_GET_LEADER_MAX_RECURSION = 20;
|
|||
static const int ROUNDED_PIXELS = 1;
|
||||
static const double ROUNDED_PERCENT = 0.05;
|
||||
|
||||
/**
|
||||
* Retrieve the <code>WM_CLASS</code> of a window and update its
|
||||
* <code>win</code> structure.
|
||||
*/
|
||||
static bool win_update_class(session_t *ps, struct managed_win *w);
|
||||
static int win_update_role(session_t *ps, struct managed_win *w);
|
||||
static void win_update_wintype(session_t *ps, struct managed_win *w);
|
||||
static int win_update_name(session_t *ps, struct managed_win *w);
|
||||
/**
|
||||
* Reread opacity property of a window.
|
||||
*/
|
||||
static void win_update_opacity_prop(session_t *ps, struct managed_win *w);
|
||||
static void win_update_opacity_target(session_t *ps, struct managed_win *w);
|
||||
/**
|
||||
* Retrieve frame extents from a window.
|
||||
*/
|
||||
static void
|
||||
win_update_frame_extents(session_t *ps, struct managed_win *w, xcb_window_t client);
|
||||
static void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w);
|
||||
static void win_update_prop_shadow(session_t *ps, struct managed_win *w);
|
||||
/**
|
||||
* Update leader of a window.
|
||||
*/
|
||||
static void win_update_leader(session_t *ps, struct managed_win *w);
|
||||
|
||||
/// Generate a "return by value" function, from a function that returns the
|
||||
/// region via a region_t pointer argument.
|
||||
/// Function signature has to be (win *, region_t *)
|
||||
|
@ -320,11 +345,81 @@ void win_release_images(struct backend_base *backend, struct managed_win *w) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns true if the `prop` property is stale, as well as clears the stale flag.
|
||||
static bool win_fetch_and_unset_property_stale(struct managed_win *w, xcb_atom_t prop);
|
||||
/// Returns true if any of the properties are stale, as well as clear all the stale flags.
|
||||
static bool win_check_and_clear_all_properties_stale(struct managed_win *w);
|
||||
|
||||
void win_process_update_flags(session_t *ps, struct managed_win *w) {
|
||||
if (win_check_flags_all(w, WIN_FLAGS_MAPPED)) {
|
||||
map_win_start(ps, w);
|
||||
win_clear_flags(w, WIN_FLAGS_MAPPED);
|
||||
}
|
||||
|
||||
// Check client first, because later property updates need accurate client window
|
||||
// information
|
||||
if (win_check_flags_all(w, WIN_FLAGS_CLIENT_STALE)) {
|
||||
win_recheck_client(ps, w);
|
||||
win_clear_flags(w, WIN_FLAGS_CLIENT_STALE);
|
||||
}
|
||||
|
||||
if (win_check_flags_all(w, WIN_FLAGS_PROPERTY_STALE)) {
|
||||
bool factor_change = false;
|
||||
|
||||
if (win_fetch_and_unset_property_stale(w, ps->atoms->a_NET_WM_WINDOW_TYPE)) {
|
||||
win_update_wintype(ps, w);
|
||||
}
|
||||
|
||||
if (win_fetch_and_unset_property_stale(w, ps->atoms->a_NET_WM_WINDOW_OPACITY)) {
|
||||
win_update_opacity_prop(ps, w);
|
||||
// we cannot receive OPACITY change when window has been destroyed
|
||||
assert(w->state != WSTATE_DESTROYING);
|
||||
win_update_opacity_target(ps, w);
|
||||
}
|
||||
|
||||
if (win_fetch_and_unset_property_stale(w, ps->atoms->a_NET_FRAME_EXTENTS)) {
|
||||
win_update_frame_extents(ps, w, w->client_win);
|
||||
add_damage_from_win(ps, w);
|
||||
}
|
||||
|
||||
if (win_fetch_and_unset_property_stale(w, ps->atoms->aWM_NAME) ||
|
||||
win_fetch_and_unset_property_stale(w, ps->atoms->a_NET_WM_NAME)) {
|
||||
if (win_update_name(ps, w) == 1) {
|
||||
factor_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (win_fetch_and_unset_property_stale(w, ps->atoms->aWM_CLASS)) {
|
||||
if (win_update_class(ps, w)) {
|
||||
factor_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (win_fetch_and_unset_property_stale(w, ps->atoms->aWM_WINDOW_ROLE)) {
|
||||
if (win_update_role(ps, w) == 1) {
|
||||
factor_change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (win_fetch_and_unset_property_stale(w, ps->atoms->a_COMPTON_SHADOW)) {
|
||||
win_update_prop_shadow(ps, w);
|
||||
}
|
||||
|
||||
if (win_fetch_and_unset_property_stale(w, ps->atoms->aWM_CLIENT_LEADER) ||
|
||||
win_fetch_and_unset_property_stale(w, ps->atoms->aWM_TRANSIENT_FOR)) {
|
||||
win_update_leader(ps, w);
|
||||
}
|
||||
|
||||
if (win_check_and_clear_all_properties_stale(w)) {
|
||||
// Some other flags we didn't explicitly check has changed, must
|
||||
// have been a tracked atom for the custom rules
|
||||
factor_change = true;
|
||||
}
|
||||
|
||||
if (factor_change) {
|
||||
win_on_factor_change(ps, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void win_process_image_flags(session_t *ps, struct managed_win *w) {
|
||||
|
@ -374,11 +469,6 @@ void win_process_image_flags(session_t *ps, struct managed_win *w) {
|
|||
if (win_check_flags_any(w, WIN_FLAGS_IMAGES_STALE)) {
|
||||
win_clear_flags(w, WIN_FLAGS_IMAGES_STALE);
|
||||
}
|
||||
|
||||
if (win_check_flags_all(w, WIN_FLAGS_CLIENT_STALE)) {
|
||||
win_recheck_client(ps, w);
|
||||
win_clear_flags(w, WIN_FLAGS_CLIENT_STALE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -458,7 +548,7 @@ int win_update_name(session_t *ps, struct managed_win *w) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
int win_get_role(session_t *ps, struct managed_win *w) {
|
||||
static int win_update_role(session_t *ps, struct managed_win *w) {
|
||||
char **strlst = NULL;
|
||||
int nstr = 0;
|
||||
|
||||
|
@ -788,8 +878,9 @@ void win_update_prop_shadow(session_t *ps, struct managed_win *w) {
|
|||
|
||||
win_update_prop_shadow_raw(ps, w);
|
||||
|
||||
if (w->prop_shadow != attr_shadow_old)
|
||||
if (w->prop_shadow != attr_shadow_old) {
|
||||
win_determine_shadow(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
static void win_set_invert_color(session_t *ps, struct managed_win *w, bool invert_color_new) {
|
||||
|
@ -1020,8 +1111,8 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client)
|
|||
|
||||
// Get window name and class if we are tracking them
|
||||
win_update_name(ps, w);
|
||||
win_get_class(ps, w);
|
||||
win_get_role(ps, w);
|
||||
win_update_class(ps, w);
|
||||
win_update_role(ps, w);
|
||||
|
||||
// Update everything related to conditions
|
||||
win_on_factor_change(ps, w);
|
||||
|
@ -1142,6 +1233,10 @@ void free_win_res(session_t *ps, struct managed_win *w) {
|
|||
free(w->class_instance);
|
||||
free(w->class_general);
|
||||
free(w->role);
|
||||
|
||||
free(w->stale_props);
|
||||
w->stale_props = NULL;
|
||||
w->stale_props_capacity = 0;
|
||||
}
|
||||
|
||||
/// Insert a new window after list_node `prev`
|
||||
|
@ -1212,6 +1307,8 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
|||
.reg_ignore_valid = false, // set to true when damaged
|
||||
.flags = WIN_FLAGS_IMAGES_NONE, // updated by property/attributes/etc
|
||||
// change
|
||||
.stale_props = NULL,
|
||||
.stale_props_capacity = 0,
|
||||
|
||||
// Runtime variables, updated by dbus
|
||||
.fade_force = UNSET,
|
||||
|
@ -1431,7 +1528,7 @@ static xcb_window_t win_get_leader_raw(session_t *ps, struct managed_win *w, int
|
|||
* Retrieve the <code>WM_CLASS</code> of a window and update its
|
||||
* <code>win</code> structure.
|
||||
*/
|
||||
bool win_get_class(session_t *ps, struct managed_win *w) {
|
||||
bool win_update_class(session_t *ps, struct managed_win *w) {
|
||||
char **strlst = NULL;
|
||||
int nstr = 0;
|
||||
|
||||
|
@ -2374,6 +2471,44 @@ void win_clear_flags(struct managed_win *w, uint64_t flags) {
|
|||
w->flags = w->flags & (~flags);
|
||||
}
|
||||
|
||||
void win_set_property_stale(struct managed_win *w, xcb_atom_t prop) {
|
||||
const auto bits_per_element = sizeof(*w->stale_props) * 8;
|
||||
if (prop >= w->stale_props_capacity * bits_per_element) {
|
||||
const auto new_size = prop / bits_per_element + 1;
|
||||
w->stale_props = realloc(w->stale_props, new_size * sizeof(*w->stale_props));
|
||||
|
||||
// Clear the content of the newly allocated bytes
|
||||
memset(w->stale_props + w->stale_props_capacity, 0,
|
||||
(new_size - w->stale_props_capacity) * sizeof(*w->stale_props));
|
||||
w->stale_props_capacity = new_size;
|
||||
}
|
||||
|
||||
w->stale_props[prop / bits_per_element] |= 1UL << (prop % bits_per_element);
|
||||
win_set_flags(w, WIN_FLAGS_PROPERTY_STALE);
|
||||
}
|
||||
|
||||
static bool win_check_and_clear_all_properties_stale(struct managed_win *w) {
|
||||
bool ret = false;
|
||||
for (size_t i = 0; i < w->stale_props_capacity; i++) {
|
||||
ret = ret || (w->stale_props[i] != 0);
|
||||
w->stale_props[i] = 0;
|
||||
}
|
||||
win_clear_flags(w, WIN_FLAGS_PROPERTY_STALE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool win_fetch_and_unset_property_stale(struct managed_win *w, xcb_atom_t prop) {
|
||||
const auto bits_per_element = sizeof(*w->stale_props) * 8;
|
||||
if (prop >= w->stale_props_capacity * bits_per_element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto mask = 1UL << (prop % bits_per_element);
|
||||
bool ret = w->stale_props[prop / bits_per_element] & mask;
|
||||
w->stale_props[prop / bits_per_element] &= ~mask;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool win_check_flags_any(struct managed_win *w, uint64_t flags) {
|
||||
return (w->flags & flags) != 0;
|
||||
}
|
||||
|
|
26
src/win.h
26
src/win.h
|
@ -126,6 +126,10 @@ struct managed_win {
|
|||
xcb_damage_damage_t damage;
|
||||
/// Paint info of the window.
|
||||
paint_t paint;
|
||||
/// bitmap for properties which needs to be updated
|
||||
uint64_t *stale_props;
|
||||
/// number of uint64_ts that has been allocated for stale_props
|
||||
uint64_t stale_props_capacity;
|
||||
|
||||
/// Bounding shape of the window. In local coordinates.
|
||||
/// See above about coordinate systems.
|
||||
|
@ -277,8 +281,6 @@ bool must_use destroy_win_start(session_t *ps, struct win *w);
|
|||
/// Release images bound with a window, set the *_NONE flags on the window. Only to be
|
||||
/// used when de-initializing the backend outside of win.c
|
||||
void win_release_images(struct backend_base *base, struct managed_win *w);
|
||||
int win_update_name(session_t *ps, struct managed_win *w);
|
||||
int win_get_role(session_t *ps, struct managed_win *w);
|
||||
winmode_t attr_pure win_calc_mode(const struct managed_win *w);
|
||||
void win_set_shadow_force(session_t *ps, struct managed_win *w, switch_t val);
|
||||
void win_set_fade_force(struct managed_win *w, switch_t val);
|
||||
|
@ -289,19 +291,13 @@ void win_set_invert_color_force(session_t *ps, struct managed_win *w, switch_t v
|
|||
*/
|
||||
void win_set_focused(session_t *ps, struct managed_win *w);
|
||||
bool attr_pure win_should_fade(session_t *ps, const struct managed_win *w);
|
||||
void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w);
|
||||
void win_update_prop_shadow(session_t *ps, struct managed_win *w);
|
||||
void win_update_opacity_target(session_t *ps, struct managed_win *w);
|
||||
void win_on_factor_change(session_t *ps, struct managed_win *w);
|
||||
/**
|
||||
* Update cache data in struct _win that depends on window size.
|
||||
*/
|
||||
void win_on_win_size_change(session_t *ps, struct managed_win *w);
|
||||
void win_update_wintype(session_t *ps, struct managed_win *w);
|
||||
void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client);
|
||||
void win_unmark_client(session_t *ps, struct managed_win *w);
|
||||
void win_recheck_client(session_t *ps, struct managed_win *w);
|
||||
bool win_get_class(session_t *ps, struct managed_win *w);
|
||||
|
||||
/**
|
||||
* Calculate and return the opacity target of a window.
|
||||
|
@ -319,14 +315,6 @@ bool win_get_class(session_t *ps, struct managed_win *w);
|
|||
double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w);
|
||||
bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w);
|
||||
void win_update_screen(session_t *, struct managed_win *);
|
||||
/**
|
||||
* Reread opacity property of a window.
|
||||
*/
|
||||
void win_update_opacity_prop(session_t *ps, struct managed_win *w);
|
||||
/**
|
||||
* Update leader of a window.
|
||||
*/
|
||||
void win_update_leader(session_t *ps, struct managed_win *w);
|
||||
/**
|
||||
* Retrieve the bounding shape of a window.
|
||||
*/
|
||||
|
@ -363,10 +351,6 @@ void win_get_region_noframe_local(const struct managed_win *w, region_t *);
|
|||
void win_get_region_frame_local(const struct managed_win *w, region_t *res);
|
||||
/// Get the region for the frame of the window, by value
|
||||
region_t win_get_region_frame_local_by_val(const struct managed_win *w);
|
||||
/**
|
||||
* Retrieve frame extents from a window.
|
||||
*/
|
||||
void win_update_frame_extents(session_t *ps, struct managed_win *w, xcb_window_t client);
|
||||
/// Insert a new window above window with id `below`, if there is no window, add to top
|
||||
/// New window will be in unmapped state
|
||||
struct win *add_win_above(session_t *ps, xcb_window_t id, xcb_window_t below);
|
||||
|
@ -442,6 +426,8 @@ void win_clear_flags(struct managed_win *w, uint64_t flags);
|
|||
bool win_check_flags_any(struct managed_win *w, uint64_t flags);
|
||||
/// Returns true if all of the flags in `flags` are set
|
||||
bool win_check_flags_all(struct managed_win *w, uint64_t flags);
|
||||
/// Mark a property as stale for a window
|
||||
void win_set_property_stale(struct managed_win *w, xcb_atom_t prop);
|
||||
|
||||
/// Free all resources in a struct win
|
||||
void free_win_res(session_t *ps, struct managed_win *w);
|
||||
|
|
|
@ -85,6 +85,8 @@ enum win_flags {
|
|||
WIN_FLAGS_CLIENT_STALE = 32,
|
||||
/// the window is mapped by X, we need to call map_win_start for it
|
||||
WIN_FLAGS_MAPPED = 64,
|
||||
/// this window has properties which needs to be updated
|
||||
WIN_FLAGS_PROPERTY_STALE = 128,
|
||||
};
|
||||
|
||||
static const uint64_t WIN_FLAGS_IMAGES_STALE =
|
||||
|
|
Loading…
Reference in New Issue