Merge pull request #521 from yshui/more-delayed-handling

More delayed event handlings
This commit is contained in:
yshui 2020-10-23 07:50:54 +01:00 committed by GitHub
commit b675e3f19d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 198 additions and 139 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,53 @@ 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;
}
// We don't mark the old region as damaged if we have stale
// shape/size/position information. The old region should have
// already been add to damage when the information became stale.
if (!win_check_flags_any(
mw, WIN_FLAGS_SIZE_STALE | WIN_FLAGS_POSITION_STALE)) {
// Mark the old extents as damaged.
// The new extents will be marked damaged when processing
// window flags.
region_t damage;
pixman_region32_init(&damage);
win_extents(mw, &damage);
add_damage(ps, &damage);
pixman_region32_fini(&damage);
}
mw->g.x = ce->x;
mw->g.y = ce->y;
// Queue pending updates
win_set_flags(mw, WIN_FLAGS_FACTOR_CHANGED);
ps->pending_updates = true;
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);
}
// At least one of the following if's is true
if (mw->g.x != ce->x || mw->g.y != ce->y) {
log_trace("Window position changed, %dx%d -> %dx%d",
mw->g.x, mw->g.y, ce->x, ce->y);
mw->g.x = ce->x;
mw->g.y = ce->y;
win_set_flags(mw, WIN_FLAGS_POSITION_STALE);
}
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);
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);
}
if (factor_change) {
win_on_factor_change(ps, mw);
add_damage(ps, &damage);
win_update_screen(ps, mw);
// 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;
@ -569,7 +576,11 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
w = find_toplevel(ps, ev->window);
}
if (w) {
win_set_property_stale(w, ev->atom);
// Set FACTOR_CHANGED so rules based on properties will be
// re-evaluated.
// Don't need to set property stale here, since that only
// concerns properties we explicitly check.
win_set_flags(w, WIN_FLAGS_FACTOR_CHANGED);
}
break;
}
@ -606,8 +617,9 @@ static inline void repair_win(session_t *ps, struct managed_win *w) {
}
// Remove the part in the damage area that could be ignored
if (w->reg_ignore && win_is_region_ignore_valid(ps, w))
if (w->reg_ignore && win_is_region_ignore_valid(ps, w)) {
pixman_region32_subtract(&parts, &parts, w->reg_ignore);
}
add_damage(ps, &parts);
pixman_region32_fini(&parts);
@ -641,19 +653,16 @@ static inline void ev_shape_notify(session_t *ps, xcb_shape_notify_event_t *ev)
* seemingly BadRegion errors would be triggered
* if we attempt to rebuild border_size
*/
// Mark the old border_size as damaged
region_t tmp = win_get_bounding_shape_global_by_val(w);
add_damage(ps, &tmp);
pixman_region32_fini(&tmp);
win_update_bounding_shape(ps, w);
// Mark the new border_size as damaged
tmp = win_get_bounding_shape_global_by_val(w);
add_damage(ps, &tmp);
pixman_region32_fini(&tmp);
// Mark the old bounding shape as damaged
if (!win_check_flags_any(w, WIN_FLAGS_SIZE_STALE | WIN_FLAGS_POSITION_STALE)) {
region_t tmp = win_get_bounding_shape_global_by_val(w);
add_damage(ps, &tmp);
pixman_region32_fini(&tmp);
}
w->reg_ignore_valid = false;
win_set_flags(w, WIN_FLAGS_SIZE_STALE);
ps->pending_updates = true;
}
static inline void

225
src/win.c
View File

@ -255,6 +255,9 @@ gen_by_val(win_get_region_frame_local);
void add_damage_from_win(session_t *ps, const struct managed_win *w) {
// XXX there was a cached extents region, investigate
// if that's better
// TODO(yshui) use the bounding shape when the window is shaped, otherwise the
// damage would be excessive
region_t extents;
pixman_region32_init(&extents);
win_extents(w, &extents);
@ -348,8 +351,59 @@ 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);
static void win_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);
}
win_clear_all_properties_stale(w);
}
/// Handle non-image flags. This phase might set IMAGES_STALE flags
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,34 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) {
win_clear_flags(w, WIN_FLAGS_CLIENT_STALE);
}
bool damaged = false;
if (win_check_flags_all(w, WIN_FLAGS_SIZE_STALE)) {
win_on_win_size_change(ps, w);
win_update_bounding_shape(ps, w);
damaged = true;
win_clear_flags(w, WIN_FLAGS_SIZE_STALE);
}
if (win_check_flags_all(w, WIN_FLAGS_POSITION_STALE)) {
damaged = true;
win_clear_flags(w, WIN_FLAGS_POSITION_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);
}
// 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);
}
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);
}
// Add damage, has to be done last so the window has the latest geometry
// information.
if (damaged) {
add_damage_from_win(ps, w);
}
}
@ -749,11 +775,7 @@ bool win_should_fade(session_t *ps, const struct managed_win *w) {
// deprecated
return false;
}
// Ignore other possible causes of fading state changes after window
// gets unmapped
// if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) {
//}
if (c2_match(ps, w, ps->o.fade_blacklist, NULL)) {
if (w->fade_excluded) {
return false;
}
return ps->o.wintype_option[w->window_type].fade;
@ -884,8 +906,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 +921,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);
}
@ -1019,11 +1043,15 @@ void win_on_factor_change(session_t *ps, struct managed_win *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)
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
w->paint_excluded = c2_match(ps, w, ps->o.paint_blacklist, NULL);
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE)
}
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE) {
w->unredir_if_possible_excluded =
c2_match(ps, w, ps->o.unredir_if_possible_blacklist, NULL);
}
w->fade_excluded = c2_match(ps, w, ps->o.fade_blacklist, NULL);
win_update_opacity_target(ps, w);
@ -1072,8 +1100,9 @@ void win_update_wintype(session_t *ps, struct managed_win *w) {
w->window_type = WINTYPE_DIALOG;
}
if (w->window_type != wtype_old)
if (w->window_type != wtype_old) {
win_on_factor_change(ps, w);
}
}
/**
@ -1088,8 +1117,9 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client)
// If the window isn't mapped yet, stop here, as the function will be
// called in map_win()
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE)
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) {
return;
}
auto e = xcb_request_check(
ps->c, xcb_change_window_attributes(
@ -1106,8 +1136,9 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client)
win_update_frame_extents(ps, w, client);
// Get window group
if (ps->o.track_leader)
if (ps->o.track_leader) {
win_update_leader(ps, w);
}
// Get window name and class if we are tracking them
win_update_name(ps, w);
@ -1355,6 +1386,7 @@ struct win *fill_win(session_t *ps, struct win *w) {
.bounding_shape = {0},
.rounded_corners = false,
.paint_excluded = false,
.fade_excluded = false,
.unredir_if_possible_excluded = false,
.prop_shadow = -1,
// following 4 are set in win_mark_client
@ -1486,11 +1518,13 @@ void win_update_leader(session_t *ps, struct managed_win *w) {
xcb_window_t leader = XCB_NONE;
// Read the leader properties
if (ps->o.detect_transient && !leader)
if (ps->o.detect_transient && !leader) {
leader = wid_get_prop_window(ps, w->client_win, ps->atoms->aWM_TRANSIENT_FOR);
}
if (ps->o.detect_client_leader && !leader)
if (ps->o.detect_client_leader && !leader) {
leader = wid_get_prop_window(ps, w->client_win, ps->atoms->aWM_CLIENT_LEADER);
}
win_set_leader(ps, w, leader);
@ -1592,10 +1626,11 @@ static void win_on_focus_change(session_t *ps, struct managed_win *w) {
#ifdef CONFIG_DBUS
// Send D-Bus signal
if (ps->o.dbus) {
if (win_is_focused_raw(ps, w))
if (win_is_focused_raw(ps, w)) {
cdbus_ev_win_focusin(ps, &w->base);
else
} else {
cdbus_ev_win_focusout(ps, &w->base);
}
}
#endif
}
@ -1649,8 +1684,9 @@ gen_by_val(win_extents);
* Mark the window shape as updated
*/
void win_update_bounding_shape(session_t *ps, struct managed_win *w) {
if (ps->shape_exists)
if (ps->shape_exists) {
w->bounding_shaped = win_bounding_shaped(ps, w->base.id);
}
pixman_region32_clear(&w->bounding_shape);
// Start with the window rectangular region
@ -1668,8 +1704,9 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) {
ps->c,
xcb_shape_get_rectangles(ps->c, w->base.id, XCB_SHAPE_SK_BOUNDING), NULL);
if (!r)
if (!r) {
break;
}
xcb_rectangle_t *xrects = xcb_shape_get_rectangles_rectangles(r);
int nrects = xcb_shape_get_rectangles_rectangles_length(r);
@ -1722,13 +1759,15 @@ void win_update_opacity_prop(session_t *ps, struct managed_win *w) {
// get frame opacity first
w->has_opacity_prop = wid_get_opacity_prop(ps, w->base.id, OPAQUE, &w->opacity_prop);
if (w->has_opacity_prop)
if (w->has_opacity_prop) {
// opacity found
return;
}
if (ps->o.detect_client_opacity && w->client_win && w->base.id == w->client_win)
if (ps->o.detect_client_opacity && w->client_win && w->base.id == w->client_win) {
// checking client opacity not allowed
return;
}
// get client opacity
w->has_opacity_prop =
@ -1760,8 +1799,9 @@ void win_update_frame_extents(session_t *ps, struct managed_win *w, xcb_window_t
// If frame_opacity != 1, then frame of this window
// is not included in reg_ignore of underneath windows
if (ps->o.frame_opacity == 1 && changed)
if (ps->o.frame_opacity == 1 && changed) {
w->reg_ignore_valid = false;
}
}
log_trace("(%#010x): %d, %d, %d, %d", w->base.id, w->frame_extents.left,
@ -1772,10 +1812,12 @@ void win_update_frame_extents(session_t *ps, struct managed_win *w, xcb_window_t
bool win_is_region_ignore_valid(session_t *ps, const struct managed_win *w) {
win_stack_foreach_managed(i, &ps->window_stack) {
if (i == w)
if (i == w) {
break;
if (!i->reg_ignore_valid)
}
if (!i->reg_ignore_valid) {
return false;
}
}
return true;
}
@ -2118,11 +2160,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 +2232,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
@ -2432,14 +2474,16 @@ win_is_fullscreen_xcb(xcb_connection_t *c, const struct atom *a, const xcb_windo
xcb_get_property_cookie_t prop =
xcb_get_property(c, 0, w, a->a_NET_WM_STATE, XCB_ATOM_ATOM, 0, 12);
xcb_get_property_reply_t *reply = xcb_get_property_reply(c, prop, NULL);
if (!reply)
if (!reply) {
return false;
}
if (reply->length) {
xcb_atom_t *val = xcb_get_property_value(reply);
for (uint32_t i = 0; i < reply->length; i++) {
if (val[i] != a->a_NET_WM_STATE_FULLSCREEN)
if (val[i] != a->a_NET_WM_STATE_FULLSCREEN) {
continue;
}
free(reply);
return true;
}
@ -2487,14 +2531,9 @@ void win_set_property_stale(struct managed_win *w, xcb_atom_t prop) {
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;
}
static void win_clear_all_properties_stale(struct managed_win *w) {
memset(w->stale_props, 0, w->stale_props_capacity * sizeof(*w->stale_props));
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) {
@ -2523,8 +2562,10 @@ bool win_check_flags_all(struct managed_win *w, uint64_t flags) {
* It's not using w->border_size for performance measures.
*/
bool win_is_fullscreen(const session_t *ps, const struct managed_win *w) {
if (!ps->o.no_ewmh_fullscreen && win_is_fullscreen_xcb(ps->c, ps->atoms, w->client_win))
if (!ps->o.no_ewmh_fullscreen &&
win_is_fullscreen_xcb(ps->c, ps->atoms, w->client_win)) {
return true;
}
return rect_is_fullscreen(ps, w->g.x, w->g.y, w->widthb, w->heightb) &&
(!w->bounding_shaped || w->rounded_corners);
}

View File

@ -211,6 +211,8 @@ struct managed_win {
// 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;
// Frame-opacity-related members
/// Current window frame opacity. Affected by window opacity.
@ -314,7 +316,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.
*/
@ -432,7 +434,7 @@ 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);
static inline region_t win_get_bounding_shape_global_by_val(struct managed_win *w) {
static inline region_t attr_unused win_get_bounding_shape_global_by_val(struct managed_win *w) {
region_t ret;
pixman_region32_init(&ret);
pixman_region32_copy(&ret, &w->bounding_shape);
@ -444,7 +446,7 @@ static inline region_t win_get_bounding_shape_global_by_val(struct managed_win *
* Calculate the extents of the frame of the given window based on EWMH
* _NET_FRAME_EXTENTS and the X window border width.
*/
static inline margin_t attr_pure win_calc_frame_extents(const struct managed_win *w) {
static inline margin_t attr_pure attr_unused win_calc_frame_extents(const struct managed_win *w) {
margin_t result = w->frame_extents;
result.top = max2(result.top, w->g.border_width);
result.left = max2(result.left, w->g.border_width);
@ -456,7 +458,7 @@ static inline margin_t attr_pure win_calc_frame_extents(const struct managed_win
/**
* Check whether a window has WM frames.
*/
static inline bool attr_pure win_has_frame(const struct managed_win *w) {
static inline bool attr_pure attr_unused win_has_frame(const struct managed_win *w) {
return w->g.border_width || w->frame_extents.top || w->frame_extents.left ||
w->frame_extents.right || w->frame_extents.bottom;
}

View File

@ -87,6 +87,13 @@ enum win_flags {
WIN_FLAGS_MAPPED = 64,
/// this window has properties which needs to be updated
WIN_FLAGS_PROPERTY_STALE = 128,
// TODO(yshui) _maybe_ split SIZE_STALE into SIZE_STALE and SHAPE_STALE
/// this window has an unhandled size/shape change
WIN_FLAGS_SIZE_STALE = 256,
/// this window has an unhandled position (i.e. x and y) change
WIN_FLAGS_POSITION_STALE = 512,
/// need better name for this, is set when some aspects of the window changed
WIN_FLAGS_FACTOR_CHANGED = 1024,
};
static const uint64_t WIN_FLAGS_IMAGES_STALE =