diff --git a/src/event.c b/src/event.c index d12d76e..8e88542 100644 --- a/src/event.c +++ b/src/event.c @@ -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; diff --git a/src/win.c b/src/win.c index 15fb602..0d4e08d 100644 --- a/src/win.c +++ b/src/win.c @@ -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 diff --git a/src/win.h b/src/win.h index 0b70c4c..6d94573 100644 --- a/src/win.h +++ b/src/win.h @@ -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. */ diff --git a/src/win_defs.h b/src/win_defs.h index 278ccc0..48ed651 100644 --- a/src/win_defs.h +++ b/src/win_defs.h @@ -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 =