diff --git a/src/backend/backend.c b/src/backend/backend.c index db0bb2c9..7d40e1cb 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -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); } diff --git a/src/win.c b/src/win.c index 3f376a77..d97597e3 100644 --- a/src/win.c +++ b/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; diff --git a/src/win.h b/src/win.h index fb5137c0..8b79cb14 100644 --- a/src/win.h +++ b/src/win.h @@ -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);