win: delayed handling of configure notify

Part of the configure notify handling which requires querying the X
server, has been moved into the X critical section.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2020-10-23 01:27:55 +01:00
parent f447e51380
commit a099678664
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
4 changed files with 110 additions and 90 deletions

View File

@ -189,8 +189,6 @@ static inline void ev_create_notify(session_t *ps, xcb_create_notify_event_t *ev
/// Handle configure event of a regular window
static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
auto w = find_win(ps, ce->window);
region_t damage;
pixman_region32_init(&damage);
if (!w) {
return;
@ -210,44 +208,47 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
restack_above(ps, w, ce->above_sibling);
} else {
restack_above(ps, w, ce->above_sibling);
bool factor_change = false;
win_extents(mw, &damage);
// If window geometry change, free old extents
if (mw->g.x != ce->x || mw->g.y != ce->y || mw->g.width != ce->width ||
mw->g.height != ce->height || mw->g.border_width != ce->border_width) {
factor_change = true;
}
region_t damage, new_extents;
pixman_region32_init(&damage);
pixman_region32_init(&new_extents);
mw->g.x = ce->x;
mw->g.y = ce->y;
// Get the old window extents
win_extents(mw, &damage);
if (mw->g.width != ce->width || mw->g.height != ce->height ||
mw->g.border_width != ce->border_width) {
log_trace("Window size changed, %dx%d -> %dx%d", mw->g.width,
mw->g.height, ce->width, ce->height);
mw->g.width = ce->width;
mw->g.height = ce->height;
mw->g.border_width = ce->border_width;
win_on_win_size_change(ps, mw);
win_update_bounding_shape(ps, mw);
}
// Queue pending updates
win_set_flags(mw, WIN_FLAGS_FACTOR_CHANGED);
ps->pending_updates = true;
region_t new_extents;
pixman_region32_init(&new_extents);
win_extents(mw, &new_extents);
pixman_region32_union(&damage, &damage, &new_extents);
pixman_region32_fini(&new_extents);
mw->g.x = ce->x;
mw->g.y = ce->y;
if (factor_change) {
win_on_factor_change(ps, mw);
if (mw->g.width != ce->width || mw->g.height != ce->height ||
mw->g.border_width != ce->border_width) {
log_trace("Window size changed, %dx%d -> %dx%d",
mw->g.width, mw->g.height, ce->width, ce->height);
mw->g.width = ce->width;
mw->g.height = ce->height;
mw->g.border_width = ce->border_width;
win_set_flags(mw, WIN_FLAGS_SIZE_STALE);
}
win_extents(mw, &new_extents);
// Mark the union of the old and new extents as damaged
pixman_region32_union(&damage, &damage, &new_extents);
add_damage(ps, &damage);
win_update_screen(ps, mw);
pixman_region32_fini(&damage);
pixman_region32_fini(&new_extents);
// Recalculate which screen this window is on
win_update_screen(ps->xinerama_nscrs, ps->xinerama_scr_regs, mw);
}
}
pixman_region32_fini(&damage);
// override_redirect flag cannot be changed after window creation, as far
// as I know, so there's no point to re-match windows here.
mw->a.override_redirect = ce->override_redirect;

137
src/win.c
View File

@ -350,6 +350,60 @@ static bool win_fetch_and_unset_property_stale(struct managed_win *w, xcb_atom_t
/// 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);
/// Fetch new window properties from the X server, and run appropriate updates. Might set
/// WIN_FLAGS_FACTOR_CHANGED
static void win_update_properties(session_t *ps, struct managed_win *w) {
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) {
win_set_flags(w, WIN_FLAGS_FACTOR_CHANGED);
}
}
if (win_fetch_and_unset_property_stale(w, ps->atoms->aWM_CLASS)) {
if (win_update_class(ps, w)) {
win_set_flags(w, WIN_FLAGS_FACTOR_CHANGED);
}
}
if (win_fetch_and_unset_property_stale(w, ps->atoms->aWM_WINDOW_ROLE)) {
if (win_update_role(ps, w) == 1) {
win_set_flags(w, WIN_FLAGS_FACTOR_CHANGED);
}
}
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
win_set_flags(w, WIN_FLAGS_FACTOR_CHANGED);
}
}
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);
@ -363,62 +417,21 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) {
win_clear_flags(w, WIN_FLAGS_CLIENT_STALE);
}
if (win_check_flags_all(w, WIN_FLAGS_SIZE_STALE)) {
win_on_win_size_change(ps, w);
win_update_bounding_shape(ps, w);
win_clear_flags(w, WIN_FLAGS_SIZE_STALE);
}
if (win_check_flags_all(w, WIN_FLAGS_PROPERTY_STALE)) {
bool factor_change = false;
win_update_properties(ps, w);
win_clear_flags(w, WIN_FLAGS_PROPERTY_STALE);
}
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);
}
// Factor change flags could be set by previous stages, so must be handled last
if (win_check_flags_all(w, WIN_FLAGS_FACTOR_CHANGED)) {
win_on_factor_change(ps, w);
win_clear_flags(w, WIN_FLAGS_FACTOR_CHANGED);
}
}
@ -884,8 +897,9 @@ void win_update_prop_shadow(session_t *ps, struct managed_win *w) {
}
static void win_set_invert_color(session_t *ps, struct managed_win *w, bool invert_color_new) {
if (w->invert_color == invert_color_new)
if (w->invert_color == invert_color_new) {
return;
}
w->invert_color = invert_color_new;
@ -898,10 +912,11 @@ static void win_set_invert_color(session_t *ps, struct managed_win *w, bool inve
static void win_determine_invert_color(session_t *ps, struct managed_win *w) {
bool invert_color_new = w->invert_color;
if (UNSET != w->invert_color_force)
if (UNSET != w->invert_color_force) {
invert_color_new = w->invert_color_force;
else if (w->a.map_state == XCB_MAP_STATE_VIEWABLE)
} else if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
invert_color_new = c2_match(ps, w, ps->o.invert_color_list, NULL);
}
win_set_invert_color(ps, w, invert_color_new);
}
@ -2118,11 +2133,11 @@ bool win_skip_fading(session_t *ps, struct managed_win *w) {
* TODO(yshui) move to x.c
* TODO(yshui) use xrandr
*/
void win_update_screen(session_t *ps, struct managed_win *w) {
void win_update_screen(int nscreens, region_t *screens, struct managed_win *w) {
w->xinerama_scr = -1;
for (int i = 0; i < ps->xinerama_nscrs; i++) {
auto e = pixman_region32_extents(&ps->xinerama_scr_regs[i]);
for (int i = 0; i < nscreens; i++) {
auto e = pixman_region32_extents(&screens[i]);
if (e->x1 <= w->g.x && e->y1 <= w->g.y && e->x2 >= w->g.x + w->widthb &&
e->y2 >= w->g.y + w->heightb) {
w->xinerama_scr = i;
@ -2190,7 +2205,7 @@ void map_win_start(session_t *ps, struct managed_win *w) {
// XXX Can we assume map_state is always viewable?
w->a.map_state = XCB_MAP_STATE_VIEWABLE;
win_update_screen(ps, w);
win_update_screen(ps->xinerama_nscrs, ps->xinerama_scr_regs, w);
// Set window event mask before reading properties so that no property
// changes are lost

View File

@ -314,7 +314,7 @@ void win_recheck_client(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 *);
void win_update_screen(int nscreens, region_t *screens, struct managed_win *w);
/**
* Retrieve the bounding shape of a window.
*/

View File

@ -87,6 +87,10 @@ enum win_flags {
WIN_FLAGS_MAPPED = 64,
/// this window has properties which needs to be updated
WIN_FLAGS_PROPERTY_STALE = 128,
/// this window has an unhandled size/shape change
WIN_FLAGS_SIZE_STALE = 256,
/// need better name for this, is set when some aspects of the window changed
WIN_FLAGS_FACTOR_CHANGED = 512,
};
static const uint64_t WIN_FLAGS_IMAGES_STALE =