mirror of https://github.com/yshui/picom.git
win: rework how events for unmapped windows are handled
Make unmapped window events work mostly like a mapped window, except flags set on unmapped windows aren't processed until the window is mapped. Hopefully this unifies some of the code paths and reduce corner cases. Should fix #525 Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
bf5a9ca154
commit
a56d66b4f3
85
src/event.c
85
src/event.c
|
@ -201,58 +201,55 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
|||
|
||||
auto mw = (struct managed_win *)w;
|
||||
|
||||
if (mw->state == WSTATE_UNMAPPED || mw->state == WSTATE_UNMAPPING ||
|
||||
mw->state == WSTATE_DESTROYING) {
|
||||
// Only restack the window to make sure we can handle future restack
|
||||
// notification correctly
|
||||
restack_above(ps, w, ce->above_sibling);
|
||||
} else {
|
||||
restack_above(ps, w, ce->above_sibling);
|
||||
restack_above(ps, w, ce->above_sibling);
|
||||
|
||||
// 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) {
|
||||
// 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.
|
||||
// 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) {
|
||||
// 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)) {
|
||||
if (mw->state != WSTATE_UNMAPPED && mw->state != WSTATE_UNMAPPING &&
|
||||
mw->state != WSTATE_DESTROYING) {
|
||||
// Mark the old extents as damaged. The new extents will
|
||||
// be marked damaged when processing window flags.
|
||||
// If the window is not mapped, we don't care
|
||||
region_t damage;
|
||||
pixman_region32_init(&damage);
|
||||
win_extents(mw, &damage);
|
||||
add_damage(ps, &damage);
|
||||
pixman_region32_fini(&damage);
|
||||
}
|
||||
|
||||
// Queue pending updates
|
||||
win_set_flags(mw, WIN_FLAGS_FACTOR_CHANGED);
|
||||
ps->pending_updates = true;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Recalculate which screen this window is on
|
||||
win_update_screen(ps->xinerama_nscrs, ps->xinerama_scr_regs, mw);
|
||||
}
|
||||
|
||||
// Queue pending updates
|
||||
win_set_flags(mw, WIN_FLAGS_FACTOR_CHANGED);
|
||||
// TODO(yshui) don't set pending_updates if the window is not
|
||||
// visible/mapped
|
||||
ps->pending_updates = true;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Recalculate which screen this window is on
|
||||
win_update_screen(ps->xinerama_nscrs, ps->xinerama_scr_regs, mw);
|
||||
}
|
||||
|
||||
// override_redirect flag cannot be changed after window creation, as far
|
||||
|
|
31
src/picom.c
31
src/picom.c
|
@ -405,8 +405,12 @@ static void destroy_backend(session_t *ps) {
|
|||
if (w->state == WSTATE_MAPPED) {
|
||||
win_release_images(ps->backend_data, w);
|
||||
} else {
|
||||
// Unmapped windows could still have shadow images.
|
||||
// And they might have image stale flags set by events.
|
||||
assert(!w->win_image);
|
||||
assert(!w->shadow_image);
|
||||
win_clear_flags(
|
||||
w, WIN_FLAGS_PIXMAP_STALE | WIN_FLAGS_SHADOW_STALE);
|
||||
win_release_images(ps->backend_data, w);
|
||||
}
|
||||
}
|
||||
free_paint(ps, &w->paint);
|
||||
|
@ -495,25 +499,12 @@ static bool initialize_backend(session_t *ps) {
|
|||
}
|
||||
auto w = (struct managed_win *)_w;
|
||||
assert(w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED);
|
||||
if (w->state == WSTATE_MAPPED) {
|
||||
// We need to reacquire image
|
||||
log_debug("Marking window %#010x (%s) for update after "
|
||||
"redirection",
|
||||
w->base.id, w->name);
|
||||
if (w->shadow) {
|
||||
struct color c = {
|
||||
.red = ps->o.shadow_red,
|
||||
.green = ps->o.shadow_green,
|
||||
.blue = ps->o.shadow_blue,
|
||||
.alpha = ps->o.shadow_opacity,
|
||||
};
|
||||
win_bind_shadow(ps->backend_data, w, c,
|
||||
ps->gaussian_map);
|
||||
}
|
||||
|
||||
w->flags |= WIN_FLAGS_PIXMAP_STALE;
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
// We need to reacquire image
|
||||
log_debug("Marking window %#010x (%s) for update after "
|
||||
"redirection",
|
||||
w->base.id, w->name);
|
||||
win_set_flags(w, WIN_FLAGS_IMAGES_STALE);
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
205
src/win.c
205
src/win.c
|
@ -125,8 +125,9 @@ static void win_update_focused(session_t *ps, struct managed_win *w) {
|
|||
(ps->o.mark_wmwin_focused && w->wmwin) ||
|
||||
(ps->o.mark_ovredir_focused && w->base.id == w->client_win && !w->wmwin) ||
|
||||
(w->a.map_state == XCB_MAP_STATE_VIEWABLE &&
|
||||
c2_match(ps, w, ps->o.focus_blacklist, NULL)))
|
||||
c2_match(ps, w, ps->o.focus_blacklist, NULL))) {
|
||||
w->focused = true;
|
||||
}
|
||||
|
||||
// If window grouping detection is enabled, mark the window active if
|
||||
// its group is
|
||||
|
@ -411,6 +412,12 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) {
|
|||
win_clear_flags(w, WIN_FLAGS_MAPPED);
|
||||
}
|
||||
|
||||
if (w->state == WSTATE_UNMAPPED || w->state == WSTATE_DESTROYING ||
|
||||
w->state == WSTATE_UNMAPPING) {
|
||||
// Flags of invisible windows are processed when they are mapped
|
||||
return;
|
||||
}
|
||||
|
||||
// Check client first, because later property updates need accurate client window
|
||||
// information
|
||||
if (win_check_flags_all(w, WIN_FLAGS_CLIENT_STALE)) {
|
||||
|
@ -452,6 +459,12 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) {
|
|||
void win_process_image_flags(session_t *ps, struct managed_win *w) {
|
||||
assert(!win_check_flags_all(w, WIN_FLAGS_MAPPED));
|
||||
|
||||
if (w->state == WSTATE_UNMAPPED || w->state == WSTATE_DESTROYING ||
|
||||
w->state == WSTATE_UNMAPPING) {
|
||||
// Flags of invisible windows are processed when they are mapped
|
||||
return;
|
||||
}
|
||||
|
||||
// Not a loop
|
||||
while (win_check_flags_any(w, WIN_FLAGS_IMAGES_STALE) &&
|
||||
!win_check_flags_all(w, WIN_FLAGS_IMAGE_ERROR)) {
|
||||
|
@ -804,15 +817,9 @@ static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new
|
|||
log_debug("Updating shadow property of window %#010x (%s) to %d", w->base.id,
|
||||
w->name, shadow_new);
|
||||
|
||||
if (w->state == WSTATE_UNMAPPED) {
|
||||
// No need to add damage or update shadow
|
||||
// Unmapped window shouldn't have any images
|
||||
w->shadow = shadow_new;
|
||||
assert(!w->shadow_image);
|
||||
assert(!w->win_image);
|
||||
assert(win_check_flags_all(w, WIN_FLAGS_IMAGES_NONE));
|
||||
return;
|
||||
}
|
||||
// We don't handle property updates of non-visible windows until they are mapped.
|
||||
assert(w->state != WSTATE_UNMAPPED && w->state != WSTATE_DESTROYING &&
|
||||
w->state != WSTATE_UNMAPPING);
|
||||
|
||||
// Keep a copy of window extent before the shadow change. Will be used for
|
||||
// calculation of damaged region
|
||||
|
@ -856,6 +863,9 @@ static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new
|
|||
// By setting WIN_FLAGS_SHADOW_STALE, we ask win_process_flags to
|
||||
// re-create or release the shaodw in based on whether w->shadow is set.
|
||||
win_set_flags(w, WIN_FLAGS_SHADOW_STALE);
|
||||
|
||||
// Only set pending_updates if we are redirected. Otherwise change of a
|
||||
// shadow won't have influence on whether we should redirect.
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
|
||||
|
@ -991,8 +1001,9 @@ win_set_blur_background(session_t *ps, struct managed_win *w, bool blur_backgrou
|
|||
*/
|
||||
static void win_determine_blur_background(session_t *ps, struct managed_win *w) {
|
||||
log_debug("Determining blur-background of window %#010x (%s)", w->base.id, w->name);
|
||||
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE)
|
||||
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool blur_background_new = ps->o.blur_method != BLUR_METHOD_NONE;
|
||||
if (blur_background_new) {
|
||||
|
@ -1190,8 +1201,9 @@ static xcb_window_t find_client_win(session_t *ps, xcb_window_t w) {
|
|||
|
||||
xcb_query_tree_reply_t *reply =
|
||||
xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, w), NULL);
|
||||
if (!reply)
|
||||
if (!reply) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
xcb_window_t *children = xcb_query_tree_children(reply);
|
||||
int nchildren = xcb_query_tree_children_length(reply);
|
||||
|
@ -1199,8 +1211,9 @@ static xcb_window_t find_client_win(session_t *ps, xcb_window_t w) {
|
|||
xcb_window_t ret = 0;
|
||||
|
||||
for (i = 0; i < nchildren; ++i) {
|
||||
if ((ret = find_client_win(ps, children[i])))
|
||||
if ((ret = find_client_win(ps, children[i]))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(reply);
|
||||
|
@ -1237,8 +1250,9 @@ void win_recheck_client(session_t *ps, struct managed_win *w) {
|
|||
}
|
||||
|
||||
// Unmark the old one
|
||||
if (w->client_win && w->client_win != cw)
|
||||
if (w->client_win && w->client_win != cw) {
|
||||
win_unmark_client(ps, w);
|
||||
}
|
||||
|
||||
// Mark the new one
|
||||
win_mark_client(ps, w, cw);
|
||||
|
@ -1455,16 +1469,40 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
|||
|
||||
free(a);
|
||||
|
||||
// Create Damage for window (if not Input Only)
|
||||
new->damage = x_new_id(ps->c);
|
||||
xcb_generic_error_t *e = xcb_request_check(
|
||||
ps->c, xcb_damage_create_checked(ps->c, new->damage, w->id,
|
||||
XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY));
|
||||
if (e) {
|
||||
xcb_generic_error_t *e;
|
||||
auto g = xcb_get_geometry_reply(ps->c, xcb_get_geometry(ps->c, w->id), &e);
|
||||
if (!g) {
|
||||
log_error_x_error(e, "Failed to get geometry of window %#010x", w->id);
|
||||
free(e);
|
||||
free(new);
|
||||
return w;
|
||||
}
|
||||
new->g = *g;
|
||||
free(g);
|
||||
|
||||
win_update_screen(ps->xinerama_nscrs, ps->xinerama_scr_regs, new);
|
||||
|
||||
// Create Damage for window (if not Input Only)
|
||||
new->damage = x_new_id(ps->c);
|
||||
e = xcb_request_check(
|
||||
ps->c, xcb_damage_create_checked(ps->c, new->damage, w->id,
|
||||
XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY));
|
||||
if (e) {
|
||||
log_error_x_error(e, "Failed to create damage");
|
||||
free(e);
|
||||
free(new);
|
||||
return w;
|
||||
}
|
||||
|
||||
// Set window event mask
|
||||
xcb_change_window_attributes(
|
||||
ps->c, new->base.id, XCB_CW_EVENT_MASK,
|
||||
(const uint32_t[]){determine_evmask(ps, new->base.id, WIN_EVMODE_FRAME)});
|
||||
|
||||
// Get notification when the shape of a window changes
|
||||
if (ps->shape_exists) {
|
||||
xcb_shape_select_input(ps->c, new->base.id, 1);
|
||||
}
|
||||
|
||||
new->pictfmt = x_get_pictform_for_visual(ps->c, new->a.visual);
|
||||
new->client_pictfmt = NULL;
|
||||
|
@ -1475,6 +1513,20 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
|||
assert(replaced == w);
|
||||
free(w);
|
||||
|
||||
// Set all the stale flags on this new window, so it's properties will get updated
|
||||
// when it's mapped
|
||||
win_set_flags(new, WIN_FLAGS_CLIENT_STALE | WIN_FLAGS_SIZE_STALE |
|
||||
WIN_FLAGS_POSITION_STALE | WIN_FLAGS_PROPERTY_STALE |
|
||||
WIN_FLAGS_FACTOR_CHANGED);
|
||||
xcb_atom_t init_stale_props[] = {
|
||||
ps->atoms->a_NET_WM_WINDOW_TYPE, ps->atoms->a_NET_WM_WINDOW_OPACITY,
|
||||
ps->atoms->a_NET_FRAME_EXTENTS, ps->atoms->aWM_NAME,
|
||||
ps->atoms->a_NET_WM_NAME, ps->atoms->aWM_CLASS,
|
||||
ps->atoms->aWM_WINDOW_ROLE, ps->atoms->a_COMPTON_SHADOW,
|
||||
ps->atoms->aWM_CLIENT_LEADER, ps->atoms->aWM_TRANSIENT_FOR,
|
||||
};
|
||||
win_set_properties_stale(new, init_stale_props, ARR_SIZE(init_stale_props));
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
if (ps->o.dbus) {
|
||||
|
@ -1856,7 +1908,11 @@ static void unmap_win_finish(session_t *ps, struct managed_win *w) {
|
|||
|
||||
// We are in unmap_win, this window definitely was viewable
|
||||
if (ps->backend_data) {
|
||||
win_release_images(ps->backend_data, w);
|
||||
// Only the pixmap needs to be freed and reacquired when mapping.
|
||||
// Shadow image can be preserved.
|
||||
if (!win_check_flags_all(w, WIN_FLAGS_PIXMAP_NONE)) {
|
||||
win_release_pixmap(ps->backend_data, w);
|
||||
}
|
||||
} else {
|
||||
assert(!w->win_image);
|
||||
assert(!w->shadow_image);
|
||||
|
@ -1889,6 +1945,12 @@ static void destroy_win_finish(session_t *ps, struct win *w) {
|
|||
unmap_win_finish(ps, mw);
|
||||
}
|
||||
|
||||
// Unmapping preserves the shadow image, so free it here
|
||||
if (!win_check_flags_all(mw, WIN_FLAGS_SHADOW_NONE)) {
|
||||
assert(mw->shadow_image != NULL);
|
||||
win_release_shadow(ps->backend_data, mw);
|
||||
}
|
||||
|
||||
// Invalidate reg_ignore of windows below this one
|
||||
// TODO(yshui) what if next_w is not mapped??
|
||||
/* TODO(yshui) seriously figure out how reg_ignore behaves.
|
||||
|
@ -2117,13 +2179,6 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
|
|||
w->opacity_target_old = fmax(w->opacity_target, w->opacity_target_old);
|
||||
w->opacity_target = win_calc_opacity_target(ps, w);
|
||||
|
||||
// Clear PIXMAP_STALE flag, since the window is unmapped there is no pixmap
|
||||
// available so STALE doesn't make sense.
|
||||
win_clear_flags(w, WIN_FLAGS_PIXMAP_STALE);
|
||||
|
||||
// don't care about properties anymore
|
||||
win_ev_stop(ps, &w->base);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
if (ps->o.dbus) {
|
||||
|
@ -2226,23 +2281,6 @@ void map_win_start(session_t *ps, struct managed_win *w) {
|
|||
}
|
||||
|
||||
assert(w->state == WSTATE_UNMAPPED);
|
||||
assert(win_check_flags_all(w, WIN_FLAGS_IMAGES_NONE) || !ps->o.experimental_backends);
|
||||
|
||||
// We stopped processing window size change when we were unmapped, refresh the
|
||||
// size of the window
|
||||
xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(ps->c, w->base.id);
|
||||
xcb_get_geometry_reply_t *g = xcb_get_geometry_reply(ps->c, gcookie, NULL);
|
||||
|
||||
if (!g) {
|
||||
log_error("Failed to get the geometry of window %#010x", w->base.id);
|
||||
return;
|
||||
}
|
||||
|
||||
w->g = *g;
|
||||
free(g);
|
||||
|
||||
win_on_win_size_change(ps, w);
|
||||
log_trace("Window size: %dx%d", w->g.width, w->g.height);
|
||||
|
||||
// Rant: window size could change after we queried its geometry here and before
|
||||
// we get its pixmap. Later, when we get back to the event processing loop, we
|
||||
|
@ -2254,48 +2292,11 @@ 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->xinerama_nscrs, ps->xinerama_scr_regs, w);
|
||||
|
||||
// Set window event mask before reading properties so that no property
|
||||
// changes are lost
|
||||
xcb_change_window_attributes(
|
||||
ps->c, w->base.id, XCB_CW_EVENT_MASK,
|
||||
(const uint32_t[]){determine_evmask(ps, w->base.id, WIN_EVMODE_FRAME)});
|
||||
|
||||
// Get notification when the shape of a window changes
|
||||
if (ps->shape_exists) {
|
||||
xcb_shape_select_input(ps->c, w->base.id, 1);
|
||||
}
|
||||
|
||||
// Update window mode here to check for ARGB windows
|
||||
w->mode = win_calc_mode(w);
|
||||
|
||||
// Detect client window here instead of in add_win() as the client
|
||||
// window should have been prepared at this point
|
||||
if (!w->client_win) {
|
||||
win_recheck_client(ps, w);
|
||||
} else {
|
||||
// Re-mark client window here
|
||||
win_mark_client(ps, w, w->client_win);
|
||||
}
|
||||
assert(w->client_win);
|
||||
|
||||
log_debug("Window (%#010x) has type %s", w->base.id, WINTYPES[w->window_type]);
|
||||
|
||||
// TODO(yshui) can we just replace calls below with win_on_factor_change?
|
||||
|
||||
// Update window focus state
|
||||
win_update_focused(ps, w);
|
||||
|
||||
// Update opacity and dim state
|
||||
win_update_opacity_prop(ps, w);
|
||||
|
||||
// Check for _COMPTON_SHADOW
|
||||
win_update_prop_shadow_raw(ps, w);
|
||||
|
||||
// Many things above could affect shadow
|
||||
win_determine_shadow(ps, w);
|
||||
|
||||
// XXX We need to make sure that win_data is available
|
||||
// iff `state` is MAPPED
|
||||
w->state = WSTATE_MAPPING;
|
||||
|
@ -2305,23 +2306,15 @@ void map_win_start(session_t *ps, struct managed_win *w) {
|
|||
log_debug("Window %#010x has opacity %f, opacity target is %f", w->base.id,
|
||||
w->opacity, w->opacity_target);
|
||||
|
||||
win_determine_blur_background(ps, w);
|
||||
|
||||
// Cannot set w->ever_damaged = false here, since window mapping could be
|
||||
// delayed, so a damage event might have already arrived before this function
|
||||
// is called. But this should be unnecessary in the first place, since
|
||||
// ever_damaged is set to false in unmap_win_finish anyway.
|
||||
|
||||
// We stopped listening on ShapeNotify events
|
||||
// when the window is unmapped (XXX we shouldn't),
|
||||
// so the shape of the window might have changed,
|
||||
// update. (Issue #35)
|
||||
//
|
||||
// Also this sets the WIN_FLAGS_IMAGES_STALE flag so later in the critical section
|
||||
// Sets the WIN_FLAGS_IMAGES_STALE flag so later in the critical section
|
||||
// the window's image will be bound
|
||||
win_update_bounding_shape(ps, w);
|
||||
|
||||
assert(win_check_flags_all(w, WIN_FLAGS_IMAGES_STALE));
|
||||
win_set_flags(w, WIN_FLAGS_PIXMAP_STALE);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
|
@ -2538,19 +2531,33 @@ 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) {
|
||||
void win_set_properties_stale(struct managed_win *w, const xcb_atom_t *props, int nprops) {
|
||||
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));
|
||||
size_t new_capacity = w->stale_props_capacity;
|
||||
|
||||
// Calculate the new capacity of the properties array
|
||||
for (int i = 0; i < nprops; i++) {
|
||||
if (props[i] >= new_capacity * bits_per_element) {
|
||||
new_capacity = props[i] / bits_per_element + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Reallocate if necessary
|
||||
if (new_capacity > w->stale_props_capacity) {
|
||||
w->stale_props =
|
||||
realloc(w->stale_props, new_capacity * 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;
|
||||
(new_capacity - w->stale_props_capacity) * sizeof(*w->stale_props));
|
||||
w->stale_props_capacity = new_capacity;
|
||||
}
|
||||
|
||||
w->stale_props[prop / bits_per_element] |= 1UL << (prop % bits_per_element);
|
||||
// Set the property bits
|
||||
for (int i = 0; i < nprops; i++) {
|
||||
w->stale_props[props[i] / bits_per_element] |=
|
||||
1UL << (props[i] % bits_per_element);
|
||||
}
|
||||
win_set_flags(w, WIN_FLAGS_PROPERTY_STALE);
|
||||
}
|
||||
|
||||
|
|
|
@ -428,8 +428,12 @@ 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);
|
||||
/// Mark properties as stale for a window
|
||||
void win_set_properties_stale(struct managed_win *w, const xcb_atom_t *prop, int nprops);
|
||||
|
||||
static inline attr_unused void win_set_property_stale(struct managed_win *w, xcb_atom_t prop) {
|
||||
return win_set_properties_stale(w, (xcb_atom_t[]){prop}, 1);
|
||||
}
|
||||
|
||||
/// Free all resources in a struct win
|
||||
void free_win_res(session_t *ps, struct managed_win *w);
|
||||
|
|
Loading…
Reference in New Issue