mirror of
https://github.com/yshui/picom.git
synced 2025-02-17 15:56:21 -05:00
backend, win: create shadows with shadow_from_mask
Do this for shaped, and rounded windows. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
a9ec614286
commit
9ac046c2ba
3 changed files with 191 additions and 145 deletions
|
@ -206,21 +206,11 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
|||
auto reg_bound = win_get_bounding_shape_global_by_val(w);
|
||||
auto reg_bound_no_corner =
|
||||
win_get_bounding_shape_global_without_corners_by_val(w);
|
||||
region_t reg_bound_local;
|
||||
pixman_region32_init(®_bound_local);
|
||||
pixman_region32_copy(®_bound_local, ®_bound);
|
||||
pixman_region32_translate(®_bound_local, -w->g.x, -w->g.y);
|
||||
|
||||
if (!w->mask_image) {
|
||||
// TODO(yshui) only allocate a mask if the window is shaped or has
|
||||
// rounded corners.
|
||||
w->mask_image = ps->backend_data->ops->make_mask(
|
||||
ps->backend_data,
|
||||
(geometry_t){.width = w->g.width, .height = w->g.height},
|
||||
®_bound_local);
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_CORNER_RADIUS, w->mask_image,
|
||||
(double[]){w->corner_radius});
|
||||
win_bind_mask(ps->backend_data, w);
|
||||
}
|
||||
|
||||
// The clip region for the current window, in global/target coordinates
|
||||
|
@ -455,8 +445,12 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
|||
// reg_visible as a hint. Since window image data outside of the
|
||||
// damage region won't be painted onto target
|
||||
region_t reg_visible_local;
|
||||
region_t reg_bound_local;
|
||||
{
|
||||
// The bounding shape, in window local coordinates
|
||||
pixman_region32_init(®_bound_local);
|
||||
pixman_region32_copy(®_bound_local, ®_bound);
|
||||
pixman_region32_translate(®_bound_local, -w->g.x, -w->g.y);
|
||||
|
||||
pixman_region32_init(®_visible_local);
|
||||
pixman_region32_intersect(®_visible_local,
|
||||
|
@ -483,10 +477,10 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
|||
®_paint_in_bound, ®_visible);
|
||||
ps->backend_data->ops->release_image(ps->backend_data, new_img);
|
||||
pixman_region32_fini(®_visible_local);
|
||||
pixman_region32_fini(®_bound_local);
|
||||
}
|
||||
skip:
|
||||
pixman_region32_fini(®_bound);
|
||||
pixman_region32_fini(®_bound_local);
|
||||
pixman_region32_fini(®_bound_no_corner);
|
||||
pixman_region32_fini(®_paint_in_bound);
|
||||
}
|
||||
|
|
317
src/win.c
317
src/win.c
|
@ -345,13 +345,33 @@ static inline bool win_bind_pixmap(struct backend_base *b, struct managed_win *w
|
|||
return true;
|
||||
}
|
||||
|
||||
bool win_bind_mask(struct backend_base *b, struct managed_win *w) {
|
||||
auto reg_bound_local = win_get_bounding_shape_global_by_val(w);
|
||||
pixman_region32_translate(®_bound_local, -w->g.x, -w->g.y);
|
||||
w->mask_image = b->ops->make_mask(
|
||||
b, (geometry_t){.width = w->g.width, .height = w->g.height}, ®_bound_local);
|
||||
if (!w->mask_image) {
|
||||
return false;
|
||||
}
|
||||
b->ops->set_image_property(b, IMAGE_PROPERTY_CORNER_RADIUS, w->mask_image,
|
||||
(double[]){w->corner_radius});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool win_bind_shadow(struct backend_base *b, struct managed_win *w, struct color c,
|
||||
struct backend_shadow_context *sctx) {
|
||||
assert(!w->shadow_image);
|
||||
assert(w->shadow);
|
||||
w->shadow_image = b->ops->render_shadow(b, w->widthb, w->heightb, sctx, c);
|
||||
if ((w->corner_radius == 0 && w->bounding_shaped == false) ||
|
||||
b->ops->shadow_from_mask == NULL) {
|
||||
w->shadow_image = b->ops->render_shadow(b, w->widthb, w->heightb, sctx, c);
|
||||
} else {
|
||||
win_bind_mask(b, w);
|
||||
w->shadow_image = b->ops->shadow_from_mask(b, w->mask_image, sctx, c);
|
||||
}
|
||||
if (!w->shadow_image) {
|
||||
log_error("Failed to bind shadow image, shadow will be disabled for "
|
||||
log_error("Failed to bind shadow image, shadow will be disabled "
|
||||
"for "
|
||||
"%#010x (%s)",
|
||||
w->base.id, w->name);
|
||||
win_set_flags(w, WIN_FLAGS_SHADOW_NONE);
|
||||
|
@ -365,10 +385,9 @@ bool win_bind_shadow(struct backend_base *b, struct managed_win *w, struct color
|
|||
}
|
||||
|
||||
void win_release_images(struct backend_base *backend, struct managed_win *w) {
|
||||
// We don't want to decide what we should do if the image we want to release is
|
||||
// stale (do we clear the stale flags or not?)
|
||||
// But if we are not releasing any images anyway, we don't care about the stale
|
||||
// flags.
|
||||
// We don't want to decide what we should do if the image we want to
|
||||
// release is stale (do we clear the stale flags or not?) But if we are
|
||||
// not releasing any images anyway, we don't care about the stale flags.
|
||||
|
||||
if (!win_check_flags_all(w, WIN_FLAGS_PIXMAP_NONE)) {
|
||||
assert(!win_check_flags_all(w, WIN_FLAGS_PIXMAP_STALE));
|
||||
|
@ -383,13 +402,15 @@ void win_release_images(struct backend_base *backend, struct managed_win *w) {
|
|||
win_release_mask(backend, w);
|
||||
}
|
||||
|
||||
/// Returns true if the `prop` property is stale, as well as clears the stale flag.
|
||||
/// 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.
|
||||
/// Returns true if any of the properties are stale, as well as clear all the
|
||||
/// stale flags.
|
||||
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
|
||||
/// 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);
|
||||
|
@ -440,8 +461,8 @@ static void win_update_properties(session_t *ps, struct managed_win *w) {
|
|||
|
||||
/// Handle non-image flags. This phase might set IMAGES_STALE flags
|
||||
void win_process_update_flags(session_t *ps, struct managed_win *w) {
|
||||
// Whether the window was visible before we process the mapped flag. i.e. is the
|
||||
// window just mapped.
|
||||
// Whether the window was visible before we process the mapped flag. i.e.
|
||||
// is the window just mapped.
|
||||
bool was_visible = win_is_real_visible(w);
|
||||
log_trace("Processing flags for window %#010x (%s), was visible: %d", w->base.id,
|
||||
w->name, was_visible);
|
||||
|
@ -456,8 +477,8 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Check client first, because later property updates need accurate client window
|
||||
// information
|
||||
// Check client first, because later property updates need accurate client
|
||||
// window information
|
||||
if (win_check_flags_all(w, WIN_FLAGS_CLIENT_STALE)) {
|
||||
win_recheck_client(ps, w);
|
||||
win_clear_flags(w, WIN_FLAGS_CLIENT_STALE);
|
||||
|
@ -466,15 +487,15 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) {
|
|||
bool damaged = false;
|
||||
if (win_check_flags_any(w, WIN_FLAGS_SIZE_STALE | WIN_FLAGS_POSITION_STALE)) {
|
||||
if (was_visible) {
|
||||
// Mark the old extents of this window as damaged. The new extents
|
||||
// will be marked damaged below, after the window extents are
|
||||
// updated.
|
||||
// Mark the old extents of this window as damaged. The new
|
||||
// extents will be marked damaged below, after the window
|
||||
// extents are updated.
|
||||
//
|
||||
// If the window is just mapped, we don't need to mark the old
|
||||
// extent as damaged. (It's possible that the window was in fading
|
||||
// and is interrupted by being mapped. In that case, the fading
|
||||
// window will be added to damage by map_win_start, so we don't
|
||||
// need to do it here)
|
||||
// If the window is just mapped, we don't need to mark the
|
||||
// old extent as damaged. (It's possible that the window
|
||||
// was in fading and is interrupted by being mapped. In
|
||||
// that case, the fading window will be added to damage by
|
||||
// map_win_start, so we don't need to do it here)
|
||||
add_damage_from_win(ps, w);
|
||||
}
|
||||
|
||||
|
@ -501,7 +522,8 @@ void win_process_update_flags(session_t *ps, struct managed_win *w) {
|
|||
win_clear_flags(w, WIN_FLAGS_PROPERTY_STALE);
|
||||
}
|
||||
|
||||
// Factor change flags could be set by previous stages, so must be handled last
|
||||
// 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);
|
||||
|
@ -533,9 +555,10 @@ void win_process_image_flags(session_t *ps, struct managed_win *w) {
|
|||
}
|
||||
|
||||
if (win_check_flags_all(w, WIN_FLAGS_PIXMAP_STALE)) {
|
||||
// Check to make sure the window is still mapped, otherwise we
|
||||
// won't be able to rebind pixmap after releasing it, yet we might
|
||||
// still need the pixmap for rendering.
|
||||
// Check to make sure the window is still mapped,
|
||||
// otherwise we won't be able to rebind pixmap after
|
||||
// releasing it, yet we might still need the pixmap for
|
||||
// rendering.
|
||||
assert(w->state != WSTATE_UNMAPPING && w->state != WSTATE_DESTROYING);
|
||||
if (!win_check_flags_all(w, WIN_FLAGS_PIXMAP_NONE)) {
|
||||
// Must release images first, otherwise breaks
|
||||
|
@ -615,7 +638,8 @@ int win_update_name(session_t *ps, struct managed_win *w) {
|
|||
}
|
||||
|
||||
if (!(wid_get_text_prop(ps, w->client_win, ps->atoms->a_NET_WM_NAME, &strlst, &nstr))) {
|
||||
log_debug("(%#010x): _NET_WM_NAME unset, falling back to WM_NAME.",
|
||||
log_debug("(%#010x): _NET_WM_NAME unset, falling back to "
|
||||
"WM_NAME.",
|
||||
w->client_win);
|
||||
|
||||
if (!wid_get_text_prop(ps, w->client_win, ps->atoms->aWM_NAME, &strlst, &nstr)) {
|
||||
|
@ -737,8 +761,8 @@ winmode_t win_calc_mode(const struct managed_win *w) {
|
|||
|
||||
if (win_has_alpha(w)) {
|
||||
if (w->client_win == XCB_NONE) {
|
||||
// This is a window not managed by the WM, and it has alpha,
|
||||
// so it's transparent. No need to check WM frame.
|
||||
// This is a window not managed by the WM, and it has
|
||||
// alpha, so it's transparent. No need to check WM frame.
|
||||
return WMODE_TRANS;
|
||||
}
|
||||
// The WM window has alpha
|
||||
|
@ -748,12 +772,12 @@ winmode_t win_calc_mode(const struct managed_win *w) {
|
|||
return WMODE_TRANS;
|
||||
}
|
||||
if (win_has_frame(w)) {
|
||||
// The client window doesn't have alpha, but we have a WM frame
|
||||
// window, which has alpha.
|
||||
// The client window doesn't have alpha, but we have a WM
|
||||
// frame window, which has alpha.
|
||||
return WMODE_FRAME_TRANS;
|
||||
}
|
||||
// Although the WM window has alpha, the frame window has 0 size, so
|
||||
// consider the window solid
|
||||
// Although the WM window has alpha, the frame window has 0 size,
|
||||
// so consider the window solid
|
||||
}
|
||||
|
||||
if (w->frame_opacity != 1.0 && win_has_frame(w)) {
|
||||
|
@ -769,8 +793,9 @@ winmode_t win_calc_mode(const struct managed_win *w) {
|
|||
*
|
||||
* The priority of opacity settings are:
|
||||
*
|
||||
* inactive_opacity_override (if set, and unfocused) > _NET_WM_WINDOW_OPACITY (if set) >
|
||||
* opacity-rules (if matched) > window type default opacity > active/inactive opacity
|
||||
* inactive_opacity_override (if set, and unfocused) > _NET_WM_WINDOW_OPACITY (if
|
||||
* set) > opacity-rules (if matched) > window type default opacity >
|
||||
* active/inactive opacity
|
||||
*
|
||||
* @param ps current session
|
||||
* @param w struct _win object representing the window
|
||||
|
@ -795,7 +820,8 @@ double win_calc_opacity_target(session_t *ps, const struct managed_win *w) {
|
|||
} else if (!safe_isnan(ps->o.wintype_option[w->window_type].opacity)) {
|
||||
opacity = ps->o.wintype_option[w->window_type].opacity;
|
||||
} else {
|
||||
// Respect active_opacity only when the window is physically focused
|
||||
// Respect active_opacity only when the window is physically
|
||||
// focused
|
||||
if (win_is_focused_raw(ps, w))
|
||||
opacity = ps->o.active_opacity;
|
||||
else if (!w->focused)
|
||||
|
@ -831,7 +857,8 @@ bool win_should_dim(session_t *ps, const struct managed_win *w) {
|
|||
* Determine if a window should fade on opacity change.
|
||||
*/
|
||||
bool win_should_fade(session_t *ps, const struct managed_win *w) {
|
||||
// To prevent it from being overwritten by last-paint value if the window is
|
||||
// To prevent it from being overwritten by last-paint value if the window
|
||||
// is
|
||||
if (w->fade_force != UNSET) {
|
||||
return w->fade_force;
|
||||
}
|
||||
|
@ -875,7 +902,8 @@ 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);
|
||||
|
||||
// We don't handle property updates of non-visible windows until they are mapped.
|
||||
// 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);
|
||||
|
||||
|
@ -897,10 +925,10 @@ static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new
|
|||
|
||||
// Note: because the release and creation of the shadow images are
|
||||
// delayed. When multiple shadow changes happen in a row, without
|
||||
// rendering phase between them, there could be a stale shadow image
|
||||
// attached to the window even if w->shadow was previously false. And vice
|
||||
// versa. So we check the STALE flag before asserting the existence of the
|
||||
// shadow image.
|
||||
// rendering phase between them, there could be a stale shadow
|
||||
// image attached to the window even if w->shadow was previously
|
||||
// false. And vice versa. So we check the STALE flag before
|
||||
// asserting the existence of the shadow image.
|
||||
if (w->shadow) {
|
||||
// Mark the new extents as damaged if the shadow is added
|
||||
assert(!w->shadow_image ||
|
||||
|
@ -910,7 +938,8 @@ static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new
|
|||
win_extents(w, &extents);
|
||||
add_damage_from_win(ps, w);
|
||||
} else {
|
||||
// Mark the old extents as damaged if the shadow is removed
|
||||
// Mark the old extents as damaged if the shadow is
|
||||
// removed
|
||||
assert(w->shadow_image ||
|
||||
win_check_flags_all(w, WIN_FLAGS_SHADOW_STALE) ||
|
||||
ps->o.legacy_backends);
|
||||
|
@ -919,11 +948,12 @@ static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new
|
|||
|
||||
// Delayed update of shadow image
|
||||
// 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.
|
||||
// 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.
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -1055,8 +1085,9 @@ win_set_blur_background(session_t *ps, struct managed_win *w, bool blur_backgrou
|
|||
|
||||
w->blur_background = blur_background_new;
|
||||
|
||||
// This damage might not be absolutely necessary (e.g. when the window is opaque),
|
||||
// but blur_background changes should be rare, so this should be fine.
|
||||
// This damage might not be absolutely necessary (e.g. when the window is
|
||||
// opaque), but blur_background changes should be rare, so this should be
|
||||
// fine.
|
||||
add_damage_from_win(ps, w);
|
||||
}
|
||||
|
||||
|
@ -1068,8 +1099,8 @@ win_set_fg_shader(session_t *ps, struct managed_win *w, struct shader_info *shad
|
|||
|
||||
w->fg_shader = shader_new;
|
||||
|
||||
// A different shader might change how the window is drawn, these changes should
|
||||
// be rare however, so this should be fine.
|
||||
// A different shader might change how the window is drawn, these changes
|
||||
// should be rare however, so this should be fine.
|
||||
add_damage_from_win(ps, w);
|
||||
}
|
||||
|
||||
|
@ -1088,7 +1119,8 @@ static void win_determine_blur_background(session_t *ps, struct managed_win *w)
|
|||
log_debug("Blur background disabled by wintypes");
|
||||
blur_background_new = false;
|
||||
} else if (c2_match(ps, w, ps->o.blur_background_blacklist, NULL)) {
|
||||
log_debug("Blur background disabled by blur-background-exclude");
|
||||
log_debug("Blur background disabled by "
|
||||
"blur-background-exclude");
|
||||
blur_background_new = false;
|
||||
}
|
||||
}
|
||||
|
@ -1168,8 +1200,8 @@ void win_update_opacity_rule(session_t *ps, struct managed_win *w) {
|
|||
*/
|
||||
void win_on_factor_change(session_t *ps, struct managed_win *w) {
|
||||
log_debug("Window %#010x (%s) factor change", w->base.id, w->name);
|
||||
// Focus needs to be updated first, as other rules might depend on the focused
|
||||
// state of the window
|
||||
// Focus needs to be updated first, as other rules might depend on the
|
||||
// focused state of the window
|
||||
win_update_focused(ps, w);
|
||||
|
||||
win_determine_shadow(ps, w);
|
||||
|
@ -1207,7 +1239,8 @@ void win_on_win_size_change(session_t *ps, struct managed_win *w) {
|
|||
w->shadow_width = w->widthb + ps->o.shadow_radius * 2;
|
||||
w->shadow_height = w->heightb + ps->o.shadow_radius * 2;
|
||||
|
||||
// We don't handle property updates of non-visible windows until they are mapped.
|
||||
// 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);
|
||||
|
||||
|
@ -1436,21 +1469,21 @@ struct win *add_win_top(session_t *ps, xcb_window_t id) {
|
|||
return add_win(ps, id, &ps->window_stack);
|
||||
}
|
||||
|
||||
/// Insert a new window above window with id `below`, if there is no window, add to top
|
||||
/// New window will be in unmapped state
|
||||
/// Insert a new window above window with id `below`, if there is no window, add
|
||||
/// to top New window will be in unmapped state
|
||||
struct win *add_win_above(session_t *ps, xcb_window_t id, xcb_window_t below) {
|
||||
struct win *w = NULL;
|
||||
HASH_FIND_INT(ps->windows, &below, w);
|
||||
if (!w) {
|
||||
if (!list_is_empty(&ps->window_stack)) {
|
||||
// `below` window is not found even if the window stack is not
|
||||
// empty
|
||||
// `below` window is not found even if the window stack is
|
||||
// not empty
|
||||
return NULL;
|
||||
}
|
||||
return add_win_top(ps, id);
|
||||
} else {
|
||||
// we found something from the hash table, so if the stack is empty,
|
||||
// we are in an inconsistent state.
|
||||
// we found something from the hash table, so if the stack is
|
||||
// empty, we are in an inconsistent state.
|
||||
assert(!list_is_empty(&ps->window_stack));
|
||||
return add_win(ps, id, w->stack_neighbour.prev);
|
||||
}
|
||||
|
@ -1477,7 +1510,8 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
|||
.in_openclose = true, // set to false after first map is done,
|
||||
// true here because window is just created
|
||||
.reg_ignore_valid = false, // set to true when damaged
|
||||
.flags = WIN_FLAGS_IMAGES_NONE, // updated by property/attributes/etc
|
||||
.flags = WIN_FLAGS_IMAGES_NONE, // updated by
|
||||
// property/attributes/etc
|
||||
// change
|
||||
.stale_props = NULL,
|
||||
.stale_props_capacity = 0,
|
||||
|
@ -1558,8 +1592,9 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
|||
|
||||
auto duplicated_win = find_managed_win(ps, w->id);
|
||||
if (duplicated_win) {
|
||||
log_debug("Window %#010x (recorded name: %s) added multiple times", w->id,
|
||||
duplicated_win->name);
|
||||
log_debug("Window %#010x (recorded name: %s) added multiple "
|
||||
"times",
|
||||
w->id, duplicated_win->name);
|
||||
return &duplicated_win->base;
|
||||
}
|
||||
|
||||
|
@ -1571,14 +1606,15 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
|||
// Failed to get window attributes or geometry probably means
|
||||
// the window is gone already. Unviewable means the window is
|
||||
// already reparented elsewhere.
|
||||
// BTW, we don't care about Input Only windows, except for stacking
|
||||
// proposes, so we need to keep track of them still.
|
||||
// BTW, we don't care about Input Only windows, except for
|
||||
// stacking proposes, so we need to keep track of them still.
|
||||
free(a);
|
||||
return w;
|
||||
}
|
||||
|
||||
if (a->_class == XCB_WINDOW_CLASS_INPUT_ONLY) {
|
||||
// No need to manage this window, but we still keep it on the window stack
|
||||
// No need to manage this window, but we still keep it on the
|
||||
// window stack
|
||||
w->managed = false;
|
||||
free(a);
|
||||
return w;
|
||||
|
@ -1648,8 +1684,8 @@ 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
|
||||
// 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);
|
||||
|
@ -1685,8 +1721,8 @@ static inline void win_set_leader(session_t *ps, struct managed_win *w, xcb_wind
|
|||
// gets mapped before parent, or when the window is a waypoint
|
||||
clear_cache_win_leaders(ps);
|
||||
|
||||
// Update the old and new window group and active_leader if the window
|
||||
// could affect their state.
|
||||
// Update the old and new window group and active_leader if the
|
||||
// window could affect their state.
|
||||
xcb_window_t cache_leader = win_get_leader(ps, w);
|
||||
if (win_is_focused_raw(ps, w) && cache_leader_old != cache_leader) {
|
||||
ps->active_leader = cache_leader;
|
||||
|
@ -1733,7 +1769,8 @@ static xcb_window_t win_get_leader_raw(session_t *ps, struct managed_win *w, int
|
|||
if (!(w->cache_leader = w->leader))
|
||||
w->cache_leader = w->client_win;
|
||||
|
||||
// If the leader of this window isn't itself, look for its ancestors
|
||||
// If the leader of this window isn't itself, look for its
|
||||
// ancestors
|
||||
if (w->cache_leader && w->cache_leader != w->client_win) {
|
||||
auto wp = find_toplevel(ps, w->cache_leader);
|
||||
if (wp) {
|
||||
|
@ -1881,7 +1918,8 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) {
|
|||
w->bounding_shaped = win_bounding_shaped(ps, w->base.id);
|
||||
}
|
||||
|
||||
// We don't handle property updates of non-visible windows until they are mapped.
|
||||
// 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);
|
||||
|
||||
|
@ -1922,8 +1960,8 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) {
|
|||
// We think the top left of the border is the origin
|
||||
pixman_region32_translate(&br, w->g.border_width, w->g.border_width);
|
||||
|
||||
// Intersect the bounding region we got with the window rectangle, to
|
||||
// make sure the bounding region is not bigger than the window
|
||||
// Intersect the bounding region we got with the window rectangle,
|
||||
// to make sure the bounding region is not bigger than the window
|
||||
// rectangle
|
||||
pixman_region32_intersect(&w->bounding_shape, &w->bounding_shape, &br);
|
||||
pixman_region32_fini(&br);
|
||||
|
@ -1980,7 +2018,8 @@ void win_update_frame_extents(session_t *ps, struct managed_win *w, xcb_window_t
|
|||
for (int i = 0; i < 4; i++) {
|
||||
if (prop.c32[i] > (uint32_t)INT_MAX) {
|
||||
log_warn("Your window manager sets a absurd "
|
||||
"_NET_FRAME_EXTENTS value (%u), ignoring it.",
|
||||
"_NET_FRAME_EXTENTS value (%u), "
|
||||
"ignoring it.",
|
||||
prop.c32[i]);
|
||||
memset(extents, 0, sizeof(extents));
|
||||
break;
|
||||
|
@ -2080,11 +2119,12 @@ static void destroy_win_finish(session_t *ps, struct win *w) {
|
|||
auto mw = (struct managed_win *)w;
|
||||
|
||||
if (mw->state != WSTATE_UNMAPPED) {
|
||||
// Only UNMAPPED state has window resources freed, otherwise
|
||||
// we need to call unmap_win_finish to free them.
|
||||
// XXX actually we unmap_win_finish only frees the rendering
|
||||
// resources, we still need to call free_win_res. will fix
|
||||
// later.
|
||||
// Only UNMAPPED state has window resources freed,
|
||||
// otherwise we need to call unmap_win_finish to free
|
||||
// them.
|
||||
// XXX actually we unmap_win_finish only frees the
|
||||
// rendering resources, we still need to call free_win_res.
|
||||
// will fix later.
|
||||
unmap_win_finish(ps, mw);
|
||||
}
|
||||
|
||||
|
@ -2107,11 +2147,12 @@ static void destroy_win_finish(session_t *ps, struct win *w) {
|
|||
}
|
||||
|
||||
if (mw == ps->active_win) {
|
||||
// Usually, the window cannot be the focused at destruction.
|
||||
// FocusOut should be generated before the window is destroyed. We
|
||||
// do this check just to be completely sure we don't have dangling
|
||||
// references.
|
||||
log_debug("window %#010x (%s) is destroyed while being focused",
|
||||
// Usually, the window cannot be the focused at
|
||||
// destruction. FocusOut should be generated before the
|
||||
// window is destroyed. We do this check just to be
|
||||
// completely sure we don't have dangling references.
|
||||
log_debug("window %#010x (%s) is destroyed while being "
|
||||
"focused",
|
||||
w->id, mw->name);
|
||||
ps->active_win = NULL;
|
||||
}
|
||||
|
@ -2144,11 +2185,13 @@ static inline void restack_win(session_t *ps, struct win *w, struct list_node *n
|
|||
}
|
||||
|
||||
if (mw) {
|
||||
// This invalidates all reg_ignore below the new stack position of `w`
|
||||
// This invalidates all reg_ignore below the new stack position of
|
||||
// `w`
|
||||
mw->reg_ignore_valid = false;
|
||||
rc_region_unref(&mw->reg_ignore);
|
||||
|
||||
// This invalidates all reg_ignore below the old stack position of `w`
|
||||
// This invalidates all reg_ignore below the old stack position of
|
||||
// `w`
|
||||
auto next_w = win_stack_find_next_managed(ps, &w->stack_neighbour);
|
||||
if (next_w) {
|
||||
next_w->reg_ignore_valid = false;
|
||||
|
@ -2230,39 +2273,42 @@ bool destroy_win_start(session_t *ps, struct win *w) {
|
|||
log_debug("Destroying %#010x \"%s\", managed = %d", w->id,
|
||||
(w->managed ? mw->name : NULL), w->managed);
|
||||
|
||||
// Delete destroyed window from the hash table, even though the window might still
|
||||
// be rendered for a while. We need to make sure future window with the same
|
||||
// window id won't confuse us. Keep the window in the window stack if it's managed
|
||||
// and mapped, since we might still need to render it (e.g. fading out). Window
|
||||
// will be removed from the stack when it finishes destroying.
|
||||
// Delete destroyed window from the hash table, even though the window
|
||||
// might still be rendered for a while. We need to make sure future window
|
||||
// with the same window id won't confuse us. Keep the window in the window
|
||||
// stack if it's managed and mapped, since we might still need to render
|
||||
// it (e.g. fading out). Window will be removed from the stack when it
|
||||
// finishes destroying.
|
||||
HASH_DEL(ps->windows, w);
|
||||
|
||||
if (!w->managed || mw->state == WSTATE_UNMAPPED) {
|
||||
// Window is already unmapped, or is an unmanged window, just destroy it
|
||||
// Window is already unmapped, or is an unmanged window, just
|
||||
// destroy it
|
||||
destroy_win_finish(ps, w);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (w->managed) {
|
||||
// Clear IMAGES_STALE flags since the window is destroyed: Clear
|
||||
// PIXMAP_STALE as there is no pixmap available anymore, so STALE doesn't
|
||||
// make sense.
|
||||
// XXX Clear SHADOW_STALE as setting/clearing flags on a destroyed window
|
||||
// doesn't work leading to an inconsistent state where the shadow is
|
||||
// refreshed but the flags are stuck in STALE.
|
||||
// Do this before changing the window state to destroying
|
||||
// PIXMAP_STALE as there is no pixmap available anymore, so STALE
|
||||
// doesn't make sense.
|
||||
// XXX Clear SHADOW_STALE as setting/clearing flags on a destroyed
|
||||
// window doesn't work leading to an inconsistent state where the
|
||||
// shadow is refreshed but the flags are stuck in STALE. Do this
|
||||
// before changing the window state to destroying
|
||||
win_clear_flags(mw, WIN_FLAGS_IMAGES_STALE);
|
||||
|
||||
// If size/shape/position information is stale, win_process_update_flags
|
||||
// will update them and add the new window extents to damage. Since the
|
||||
// window has been destroyed, we cannot get the complete information at
|
||||
// this point, so we just add what we currently have to the damage.
|
||||
// If size/shape/position information is stale,
|
||||
// win_process_update_flags will update them and add the new
|
||||
// window extents to damage. Since the window has been destroyed,
|
||||
// we cannot get the complete information at this point, so we
|
||||
// just add what we currently have to the damage.
|
||||
if (win_check_flags_any(mw, WIN_FLAGS_SIZE_STALE | WIN_FLAGS_POSITION_STALE)) {
|
||||
add_damage_from_win(ps, mw);
|
||||
}
|
||||
|
||||
// Clear some flags about stale window information. Because now the window
|
||||
// is destroyed, we can't update them anyway.
|
||||
// Clear some flags about stale window information. Because now
|
||||
// the window is destroyed, we can't update them anyway.
|
||||
win_clear_flags(mw, WIN_FLAGS_SIZE_STALE | WIN_FLAGS_POSITION_STALE |
|
||||
WIN_FLAGS_PROPERTY_STALE |
|
||||
WIN_FLAGS_FACTOR_CHANGED | WIN_FLAGS_CLIENT_STALE);
|
||||
|
@ -2309,7 +2355,8 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
|
|||
// Clear the pending map as this window is now unmapped
|
||||
win_clear_flags(w, WIN_FLAGS_MAPPED);
|
||||
} else {
|
||||
log_warn("Trying to unmapping an already unmapped window %#010x "
|
||||
log_warn("Trying to unmapping an already unmapped window "
|
||||
"%#010x "
|
||||
"\"%s\"",
|
||||
w->base.id, w->name);
|
||||
assert(false);
|
||||
|
@ -2333,10 +2380,10 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
|
|||
#endif
|
||||
|
||||
if (!ps->redirected || !was_damaged) {
|
||||
// If we are not redirected, we skip fading because we aren't rendering
|
||||
// anything anyway.
|
||||
// If the window wasn't ever damaged, it shouldn't be painted either. But
|
||||
// a fading out window is always painted, so we have to skip fading here.
|
||||
// If we are not redirected, we skip fading because we aren't
|
||||
// rendering anything anyway. If the window wasn't ever damaged,
|
||||
// it shouldn't be painted either. But a fading out window is
|
||||
// always painted, so we have to skip fading here.
|
||||
CHECK(!win_skip_fading(ps, w));
|
||||
}
|
||||
}
|
||||
|
@ -2395,14 +2442,16 @@ void win_update_screen(int nscreens, region_t *screens, struct managed_win *w) {
|
|||
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;
|
||||
log_debug("Window %#010x (%s), %dx%d+%dx%d, is on screen %d "
|
||||
log_debug("Window %#010x (%s), %dx%d+%dx%d, is on screen "
|
||||
"%d "
|
||||
"(%dx%d+%dx%d)",
|
||||
w->base.id, w->name, w->g.x, w->g.y, w->widthb, w->heightb,
|
||||
i, e->x1, e->y1, e->x2 - e->x1, e->y2 - e->y1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
log_debug("Window %#010x (%s), %dx%d+%dx%d, is not contained by any screen",
|
||||
log_debug("Window %#010x (%s), %dx%d+%dx%d, is not contained by any "
|
||||
"screen",
|
||||
w->base.id, w->name, w->g.x, w->g.y, w->g.width, w->g.height);
|
||||
}
|
||||
|
||||
|
@ -2427,23 +2476,24 @@ void map_win_start(session_t *ps, struct managed_win *w) {
|
|||
|
||||
if (w->state == WSTATE_UNMAPPING) {
|
||||
CHECK(!win_skip_fading(ps, w));
|
||||
// We skipped the unmapping process, the window was rendered, now it is
|
||||
// not anymore. So we need to mark the then unmapping window as damaged.
|
||||
// We skipped the unmapping process, the window was rendered, now
|
||||
// it is not anymore. So we need to mark the then unmapping window
|
||||
// as damaged.
|
||||
//
|
||||
// Solves problem when, for example, a window is unmapped then mapped in a
|
||||
// different location
|
||||
// Solves problem when, for example, a window is unmapped then
|
||||
// mapped in a different location
|
||||
add_damage_from_win(ps, w);
|
||||
assert(w);
|
||||
}
|
||||
|
||||
assert(w->state == WSTATE_UNMAPPED);
|
||||
|
||||
// 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
|
||||
// will get the notification about size change from Xserver and try to refresh the
|
||||
// pixmap, while the pixmap is actually already up-to-date (i.e. the notification
|
||||
// is stale). There is basically no real way to prevent this, aside from grabbing
|
||||
// the server.
|
||||
// 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 will get the notification about size change from
|
||||
// Xserver and try to refresh the pixmap, while the pixmap is actually
|
||||
// already up-to-date (i.e. the notification is stale). There is basically
|
||||
// no real way to prevent this, aside from grabbing the server.
|
||||
|
||||
// XXX Can we assume map_state is always viewable?
|
||||
w->a.map_state = XCB_MAP_STATE_VIEWABLE;
|
||||
|
@ -2463,9 +2513,9 @@ void map_win_start(session_t *ps, struct managed_win *w) {
|
|||
w->opacity, w->opacity_target);
|
||||
|
||||
// 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.
|
||||
// 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.
|
||||
|
||||
// Sets the WIN_FLAGS_IMAGES_STALE flag so later in the critical section
|
||||
// the window's image will be bound
|
||||
|
@ -2600,17 +2650,17 @@ struct managed_win *find_toplevel(session_t *ps, xcb_window_t id) {
|
|||
* @return struct _win object of the found window, NULL if not found
|
||||
*/
|
||||
struct managed_win *find_managed_window_or_parent(session_t *ps, xcb_window_t wid) {
|
||||
// TODO(yshui) this should probably be an "update tree", then find_toplevel.
|
||||
// current approach is a bit more "racy", as the server state might be ahead of
|
||||
// our state
|
||||
// TODO(yshui) this should probably be an "update tree", then
|
||||
// find_toplevel. current approach is a bit more "racy", as the server
|
||||
// state might be ahead of our state
|
||||
struct win *w = NULL;
|
||||
|
||||
// We traverse through its ancestors to find out the frame
|
||||
// Using find_win here because if we found a unmanaged window we know about, we
|
||||
// can stop early.
|
||||
// Using find_win here because if we found a unmanaged window we know
|
||||
// about, we can stop early.
|
||||
while (wid && wid != ps->root && !(w = find_win(ps, wid))) {
|
||||
// xcb_query_tree probably fails if you run picom when X is somehow
|
||||
// initializing (like add it in .xinitrc). In this case
|
||||
// xcb_query_tree probably fails if you run picom when X is
|
||||
// somehow initializing (like add it in .xinitrc). In this case
|
||||
// just leave it alone.
|
||||
auto reply = xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, wid), NULL);
|
||||
if (reply == NULL) {
|
||||
|
@ -2776,7 +2826,8 @@ bool win_is_bypassing_compositor(const session_t *ps, const struct managed_win *
|
|||
}
|
||||
|
||||
/**
|
||||
* Check if a window is focused, without using any focus rules or forced focus settings
|
||||
* Check if a window is focused, without using any focus rules or forced focus
|
||||
* settings
|
||||
*/
|
||||
bool win_is_focused_raw(const session_t *ps, const struct managed_win *w) {
|
||||
return w->a.map_state == XCB_MAP_STATE_VIEWABLE && ps->active_win == w;
|
||||
|
|
|
@ -289,6 +289,7 @@ struct managed_win {
|
|||
/// section
|
||||
void win_process_update_flags(session_t *ps, struct managed_win *w);
|
||||
void win_process_image_flags(session_t *ps, struct managed_win *w);
|
||||
bool win_bind_mask(struct backend_base *b, struct managed_win *w);
|
||||
/// Bind a shadow to the window, with color `c` and shadow kernel `kernel`
|
||||
bool win_bind_shadow(struct backend_base *b, struct managed_win *w, struct color c,
|
||||
struct backend_shadow_context *kernel);
|
||||
|
|
Loading…
Add table
Reference in a new issue