mirror of
https://github.com/yshui/picom.git
synced 2024-11-25 14:06:08 -05:00
win: process window flags in two stages
Previously a window's leader changing will trigger factor change on all windows in the same window group. However, if a window in this group has already been iterated over in the foreach loop in `refresh_windows`, their flags will not be processed again in the same loop. This will cause those windows to have outdated per-window options. This commit split flag handling in two stages, factor changes are only processed after other flags of ALL windows have been processed. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
c7fc8784d5
commit
76af408a64
4 changed files with 58 additions and 28 deletions
12
src/picom.c
12
src/picom.c
|
@ -1601,9 +1601,17 @@ static void handle_new_windows(session_t *ps) {
|
||||||
static void refresh_windows(session_t *ps) {
|
static void refresh_windows(session_t *ps) {
|
||||||
wm_stack_foreach(ps->wm, cursor) {
|
wm_stack_foreach(ps->wm, cursor) {
|
||||||
auto w = wm_ref_deref(cursor);
|
auto w = wm_ref_deref(cursor);
|
||||||
if (w != NULL) {
|
if (w == NULL) {
|
||||||
win_process_update_flags(ps, w);
|
continue;
|
||||||
}
|
}
|
||||||
|
win_process_primary_flags(ps, w);
|
||||||
|
}
|
||||||
|
wm_stack_foreach(ps->wm, cursor) {
|
||||||
|
auto w = wm_ref_deref(cursor);
|
||||||
|
if (w == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
win_process_secondary_flags(ps, w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,9 @@ enum win_flags {
|
||||||
WIN_FLAGS_PIXMAP_STALE = 1,
|
WIN_FLAGS_PIXMAP_STALE = 1,
|
||||||
/// there was an error binding the window pixmap
|
/// there was an error binding the window pixmap
|
||||||
WIN_FLAGS_PIXMAP_ERROR = 4,
|
WIN_FLAGS_PIXMAP_ERROR = 4,
|
||||||
|
/// Window is damaged, and should be added to the damage region
|
||||||
|
/// (only used by the legacy backends, remove)
|
||||||
|
WIN_FLAGS_DAMAGED = 8,
|
||||||
/// the client window needs to be updated
|
/// the client window needs to be updated
|
||||||
WIN_FLAGS_CLIENT_STALE = 32,
|
WIN_FLAGS_CLIENT_STALE = 32,
|
||||||
/// the window is mapped by X, we need to call map_win_start for it
|
/// the window is mapped by X, we need to call map_win_start for it
|
||||||
|
|
62
src/wm/win.c
62
src/wm/win.c
|
@ -103,11 +103,9 @@ win_get_leader_property(struct x_connection *c, struct atom *atoms, xcb_window_t
|
||||||
|
|
||||||
static struct wm_ref *win_get_leader_raw(session_t *ps, struct win *w, int recursions);
|
static struct wm_ref *win_get_leader_raw(session_t *ps, struct win *w, int recursions);
|
||||||
|
|
||||||
/**
|
/// Get the leader of a window.
|
||||||
* Get the leader of a window.
|
///
|
||||||
*
|
/// This function updates w->cache_leader if necessary.
|
||||||
* This function updates w->cache_leader if necessary.
|
|
||||||
*/
|
|
||||||
static inline struct wm_ref *win_get_leader(session_t *ps, struct win *w) {
|
static inline struct wm_ref *win_get_leader(session_t *ps, struct win *w) {
|
||||||
return win_get_leader_raw(ps, w, 0);
|
return win_get_leader_raw(ps, w, 0);
|
||||||
}
|
}
|
||||||
|
@ -172,13 +170,7 @@ static inline void group_on_factor_change(session_t *ps, struct wm_ref *leader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static inline bool win_is_group_focused_inner(session_t *ps, struct wm_ref *leader) {
|
||||||
* Return whether a window group is really focused.
|
|
||||||
*
|
|
||||||
* @param leader leader window ID
|
|
||||||
* @return true if the window group is focused, false otherwise
|
|
||||||
*/
|
|
||||||
static inline bool group_is_focused(session_t *ps, struct wm_ref *leader) {
|
|
||||||
if (!leader) {
|
if (!leader) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -198,6 +190,15 @@ static inline bool group_is_focused(session_t *ps, struct wm_ref *leader) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool win_is_group_focused(session_t *ps, struct win *w) {
|
||||||
|
if (w->state != WSTATE_MAPPED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto leader = win_get_leader(ps, w);
|
||||||
|
return win_is_group_focused_inner(ps, leader);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set leader of a window.
|
* Set leader of a window.
|
||||||
*/
|
*/
|
||||||
|
@ -214,7 +215,7 @@ static inline void win_set_leader(session_t *ps, struct win *w, xcb_window_t nle
|
||||||
}
|
}
|
||||||
auto i = wm_ref_deref(cursor);
|
auto i = wm_ref_deref(cursor);
|
||||||
if (i != NULL) {
|
if (i != NULL) {
|
||||||
i->cache_leader = XCB_NONE;
|
i->cache_leader = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,8 +435,9 @@ static void win_update_properties(session_t *ps, struct win *w) {
|
||||||
win_clear_all_properties_stale(w);
|
win_clear_all_properties_stale(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle non-image flags. This phase might set IMAGES_STALE flags
|
/// Handle primary flags. These flags are set as direct results of raw X11 window data
|
||||||
void win_process_update_flags(session_t *ps, struct win *w) {
|
/// changes.
|
||||||
|
void win_process_primary_flags(session_t *ps, struct win *w) {
|
||||||
log_trace("Processing flags for window %#010x (%s), was rendered: %d, flags: "
|
log_trace("Processing flags for window %#010x (%s), was rendered: %d, flags: "
|
||||||
"%#" PRIx64,
|
"%#" PRIx64,
|
||||||
win_id(w), w->name, w->to_paint, w->flags);
|
win_id(w), w->name, w->to_paint, w->flags);
|
||||||
|
@ -451,7 +453,6 @@ void win_process_update_flags(session_t *ps, struct win *w) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool damaged = false;
|
|
||||||
if (win_check_flags_all(w, WIN_FLAGS_CLIENT_STALE)) {
|
if (win_check_flags_all(w, WIN_FLAGS_CLIENT_STALE)) {
|
||||||
win_on_client_update(ps, w);
|
win_on_client_update(ps, w);
|
||||||
win_clear_flags(w, WIN_FLAGS_CLIENT_STALE);
|
win_clear_flags(w, WIN_FLAGS_CLIENT_STALE);
|
||||||
|
@ -490,12 +491,12 @@ void win_process_update_flags(session_t *ps, struct win *w) {
|
||||||
ps->o.shadow_offset_y, ps->o.shadow_radius);
|
ps->o.shadow_offset_y, ps->o.shadow_radius);
|
||||||
win_update_bounding_shape(&ps->c, w, ps->shape_exists,
|
win_update_bounding_shape(&ps->c, w, ps->shape_exists,
|
||||||
ps->o.detect_rounded_corners);
|
ps->o.detect_rounded_corners);
|
||||||
damaged = true;
|
|
||||||
win_clear_flags(w, WIN_FLAGS_SIZE_STALE);
|
win_clear_flags(w, WIN_FLAGS_SIZE_STALE);
|
||||||
|
|
||||||
// Window shape/size changed, invalidate the images we built
|
// Window shape/size changed, invalidate the images we built
|
||||||
// log_trace("free out dated pict");
|
// log_trace("free out dated pict");
|
||||||
win_set_flags(w, WIN_FLAGS_PIXMAP_STALE | WIN_FLAGS_FACTOR_CHANGED);
|
win_set_flags(w, WIN_FLAGS_PIXMAP_STALE |
|
||||||
|
WIN_FLAGS_FACTOR_CHANGED | WIN_FLAGS_DAMAGED);
|
||||||
|
|
||||||
win_release_mask(ps->backend_data, w);
|
win_release_mask(ps->backend_data, w);
|
||||||
win_release_shadow(ps->backend_data, w);
|
win_release_shadow(ps->backend_data, w);
|
||||||
|
@ -505,8 +506,8 @@ void win_process_update_flags(session_t *ps, struct win *w) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (win_check_flags_all(w, WIN_FLAGS_POSITION_STALE)) {
|
if (win_check_flags_all(w, WIN_FLAGS_POSITION_STALE)) {
|
||||||
damaged = true;
|
|
||||||
win_clear_flags(w, WIN_FLAGS_POSITION_STALE);
|
win_clear_flags(w, WIN_FLAGS_POSITION_STALE);
|
||||||
|
win_set_flags(w, WIN_FLAGS_DAMAGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,6 +515,17 @@ void win_process_update_flags(session_t *ps, struct win *w) {
|
||||||
win_update_properties(ps, w);
|
win_update_properties(ps, w);
|
||||||
win_clear_flags(w, WIN_FLAGS_PROPERTY_STALE);
|
win_clear_flags(w, WIN_FLAGS_PROPERTY_STALE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle secondary flags. These flags are set during the processing of primary flags.
|
||||||
|
/// Flags are separated into primaries and secondaries because processing of secondary
|
||||||
|
/// flags must happen after primary flags of ALL windows are processed, to make sure some
|
||||||
|
/// global states (e.g. active window group) are consistent because they will be used in
|
||||||
|
/// the processing of secondary flags.
|
||||||
|
void win_process_secondary_flags(session_t *ps, struct win *w) {
|
||||||
|
if (w->flags == 0 || w->state != WSTATE_MAPPED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Factor change flags could be set by previous stages, so must be handled
|
// Factor change flags could be set by previous stages, so must be handled
|
||||||
// last
|
// last
|
||||||
|
@ -521,11 +533,11 @@ void win_process_update_flags(session_t *ps, struct win *w) {
|
||||||
win_on_factor_change(ps, w);
|
win_on_factor_change(ps, w);
|
||||||
win_clear_flags(w, WIN_FLAGS_FACTOR_CHANGED);
|
win_clear_flags(w, WIN_FLAGS_FACTOR_CHANGED);
|
||||||
}
|
}
|
||||||
|
if (win_check_flags_all(w, WIN_FLAGS_DAMAGED)) {
|
||||||
// Add damage, has to be done last so the window has the latest geometry
|
// Add damage, has to be done last so the window has the latest geometry
|
||||||
// information.
|
// information.
|
||||||
if (damaged) {
|
|
||||||
add_damage_from_win(ps, w);
|
add_damage_from_win(ps, w);
|
||||||
|
win_clear_flags(w, WIN_FLAGS_DAMAGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1376,7 +1388,7 @@ struct win *win_maybe_allocate(session_t *ps, struct wm_ref *cursor,
|
||||||
|
|
||||||
.mode = WMODE_TRANS,
|
.mode = WMODE_TRANS,
|
||||||
.leader = XCB_NONE,
|
.leader = XCB_NONE,
|
||||||
.cache_leader = XCB_NONE,
|
.cache_leader = NULL,
|
||||||
.window_type = WINTYPE_UNKNOWN,
|
.window_type = WINTYPE_UNKNOWN,
|
||||||
.opacity_prop = OPAQUE,
|
.opacity_prop = OPAQUE,
|
||||||
.opacity_set = 1,
|
.opacity_set = 1,
|
||||||
|
@ -1628,7 +1640,7 @@ static void win_on_focus_change(session_t *ps, struct win *w) {
|
||||||
}
|
}
|
||||||
// If the group get unfocused, remove it from active_leader
|
// If the group get unfocused, remove it from active_leader
|
||||||
else if (!win_is_focused_raw(w) && leader && leader == active_leader &&
|
else if (!win_is_focused_raw(w) && leader && leader == active_leader &&
|
||||||
!group_is_focused(ps, leader)) {
|
!win_is_group_focused_inner(ps, leader)) {
|
||||||
wm_set_active_leader(ps->wm, XCB_NONE);
|
wm_set_active_leader(ps->wm, XCB_NONE);
|
||||||
group_on_factor_change(ps, leader);
|
group_on_factor_change(ps, leader);
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,7 +340,8 @@ static const struct script_output_info win_script_outputs[] = {
|
||||||
/// state change.
|
/// state change.
|
||||||
bool win_process_animation_and_state_change(struct session *ps, struct win *w, double delta_t);
|
bool win_process_animation_and_state_change(struct session *ps, struct win *w, double delta_t);
|
||||||
double win_animatable_get(const struct win *w, enum win_script_output output);
|
double win_animatable_get(const struct win *w, enum win_script_output output);
|
||||||
void win_process_update_flags(session_t *ps, struct win *w);
|
void win_process_primary_flags(session_t *ps, struct win *w);
|
||||||
|
void win_process_secondary_flags(session_t *ps, struct win *w);
|
||||||
void win_process_image_flags(session_t *ps, struct win *w);
|
void win_process_image_flags(session_t *ps, struct win *w);
|
||||||
|
|
||||||
/// Start the unmap of a window. We cannot unmap immediately since we might need to fade
|
/// Start the unmap of a window. We cannot unmap immediately since we might need to fade
|
||||||
|
@ -421,6 +422,12 @@ void win_destroy_finish(session_t *ps, struct win *w);
|
||||||
*/
|
*/
|
||||||
bool attr_pure win_is_focused_raw(const struct win *w);
|
bool attr_pure win_is_focused_raw(const struct win *w);
|
||||||
|
|
||||||
|
/// Return whether the group a window belongs to is really focused.
|
||||||
|
///
|
||||||
|
/// @param leader leader window ID
|
||||||
|
/// @return true if the window group is focused, false otherwise
|
||||||
|
bool win_is_group_focused(session_t *ps, struct win *w);
|
||||||
|
|
||||||
/// check if window has ARGB visual
|
/// check if window has ARGB visual
|
||||||
bool attr_pure win_has_alpha(const struct win *w);
|
bool attr_pure win_has_alpha(const struct win *w);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue