diff options
| author | allusive-dev <[email protected]> | 2023-10-30 15:12:21 +1100 |
|---|---|---|
| committer | allusive-dev <[email protected]> | 2023-10-30 15:12:21 +1100 |
| commit | ac33357e7ce7c474aeaffc92e381020289d767a2 (patch) | |
| tree | 7f05fa79b3ccd7834f85cc65a07fbd4f8030eb94 /src/win.c | |
| parent | Create FUNDING.yml (diff) | |
| download | compfy-ac33357e7ce7c474aeaffc92e381020289d767a2.tar.xz compfy-ac33357e7ce7c474aeaffc92e381020289d767a2.zip | |
Version 1.01.0.0
Diffstat (limited to 'src/win.c')
| -rw-r--r-- | src/win.c | 412 |
1 files changed, 260 insertions, 152 deletions
@@ -322,6 +322,13 @@ static inline void win_release_shadow(backend_t *base, struct managed_win *w) { } } +static inline void win_release_mask(backend_t *base, struct managed_win *w) { + if (w->mask_image) { + base->ops->release_image(base, w->mask_image); + w->mask_image = NULL; + } +} + static inline bool win_bind_pixmap(struct backend_base *b, struct managed_win *w) { assert(!w->win_image); auto pixmap = x_new_id(b->c); @@ -346,14 +353,36 @@ 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) { + assert(!w->mask_image); + 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->widthb, .height = w->heightb}, ®_bound_local); + pixman_region32_fini(®_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 conv *kernel) { + struct backend_shadow_context *sctx) { assert(!w->shadow_image); assert(w->shadow); - w->shadow_image = b->ops->render_shadow(b, w->widthb, w->heightb, kernel, c.red, - c.green, c.blue, c.alpha); + 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); @@ -367,10 +396,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)); @@ -382,15 +410,19 @@ void win_release_images(struct backend_base *backend, struct managed_win *w) { assert(!win_check_flags_all(w, WIN_FLAGS_SHADOW_STALE)); win_release_shadow(backend, 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); @@ -576,10 +608,6 @@ static void init_animation_unmap(session_t *ps, struct managed_win *w) { animation = ps->o.wintype_option[w->window_type].animation_unmap; } - if (c2_match(ps, w, ps->o.animation_unmap_blacklist, NULL)) { - animation = OPEN_WINDOW_ANIMATION_NONE; - } - if (ps->root_desktop_switch_direction != 0) { if (ps->o.animation_for_workspace_switch_out == OPEN_WINDOW_ANIMATION_AUTO) animation = OPEN_WINDOW_ANIMATION_SLIDE_OUT; @@ -587,6 +615,10 @@ static void init_animation_unmap(session_t *ps, struct managed_win *w) { animation = ps->o.animation_for_workspace_switch_out; } + if (c2_match(ps, w, ps->o.animation_unmap_blacklist, NULL)) { + animation = OPEN_WINDOW_ANIMATION_NONE; + } + switch (animation) { case OPEN_WINDOW_ANIMATION_AUTO: case OPEN_WINDOW_ANIMATION_NONE: { // No animation @@ -672,8 +704,8 @@ static void init_animation_unmap(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); @@ -688,8 +720,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); @@ -698,15 +730,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); } @@ -800,7 +832,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); @@ -832,9 +865,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 @@ -854,7 +888,7 @@ void win_process_image_flags(session_t *ps, struct managed_win *w) { .green = ps->o.shadow_green, .blue = ps->o.shadow_blue, .alpha = ps->o.shadow_opacity}, - ps->gaussian_map); + ps->shadow_context); } } @@ -914,7 +948,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)) { @@ -1036,8 +1071,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 @@ -1047,12 +1082,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)) { @@ -1068,8 +1103,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 @@ -1097,7 +1133,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) @@ -1133,7 +1170,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; } @@ -1177,7 +1215,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); @@ -1199,33 +1238,35 @@ 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 || win_check_flags_all(w, WIN_FLAGS_SHADOW_STALE) || - !ps->o.experimental_backends); + ps->o.legacy_backends); pixman_region32_clear(&extents); 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.experimental_backends); + ps->o.legacy_backends); add_damage(ps, &extents); } // 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; } @@ -1268,7 +1309,7 @@ static void win_determine_shadow(session_t *ps, struct managed_win *w) { * things. */ void win_update_prop_shadow(session_t *ps, struct managed_win *w) { - long attr_shadow_old = w->prop_shadow; + long long attr_shadow_old = w->prop_shadow; win_update_prop_shadow_raw(ps, w); @@ -1357,8 +1398,22 @@ 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); +} + +static void +win_set_fg_shader(session_t *ps, struct managed_win *w, struct shader_info *shader_new) { + if (w->fg_shader == shader_new) { + return; + } + + 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. add_damage_from_win(ps, w); } @@ -1377,7 +1432,12 @@ 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; + } else if (c2_match(ps, w, ps->o.blur_rules, NULL)) { + blur_background_new = true; + } else { blur_background_new = false; } } @@ -1393,7 +1453,7 @@ static void win_determine_rounded_corners(session_t *ps, struct managed_win *w) w->corner_radius = 0; return; } - + void *val = NULL; // Don't round full screen windows & excluded windows @@ -1413,6 +1473,28 @@ static void win_determine_rounded_corners(session_t *ps, struct managed_win *w) } /** + * Determine custom window shader to use for a window. + */ +static void win_determine_fg_shader(session_t *ps, struct managed_win *w) { + if (w->a.map_state != XCB_MAP_STATE_VIEWABLE) { + return; + } + + auto shader_new = ps->o.window_shader_fg; + void *val = NULL; + if (c2_match(ps, w, ps->o.window_shader_fg_rules, &val)) { + shader_new = val; + } + + struct shader_info *shader = NULL; + if (shader_new) { + HASH_FIND_STR(ps->shaders, shader_new, shader); + } + + win_set_fg_shader(ps, w, shader); +} + +/** * Update window opacity according to opacity rules. */ void win_update_opacity_rule(session_t *ps, struct managed_win *w) { @@ -1439,8 +1521,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); @@ -1448,6 +1530,7 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) { win_determine_invert_color(ps, w); win_determine_blur_background(ps, w); win_determine_rounded_corners(ps, w); + win_determine_fg_shader(ps, w); w->mode = win_calc_mode(w); log_debug("Window mode changed to %d", w->mode); win_update_opacity_rule(ps, w); @@ -1461,6 +1544,9 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) { w->fade_excluded = c2_match(ps, w, ps->o.fade_blacklist, NULL); + w->transparent_clipping_excluded = + c2_match(ps, w, ps->o.transparent_clipping_blacklist, NULL); + win_update_opacity_target(ps, w); w->reg_ignore_valid = false; @@ -1477,14 +1563,14 @@ 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); // Invalidate the shadow we built - if (w->state != WSTATE_DESTROYING) - win_set_flags(w, WIN_FLAGS_IMAGES_STALE); - + win_set_flags(w, WIN_FLAGS_IMAGES_STALE); + win_release_mask(ps->backend_data, w); ps->pending_updates = true; free_paint(ps, &w->shadow_paint); } @@ -1707,21 +1793,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); } @@ -1743,19 +1829,20 @@ struct win *fill_win(session_t *ps, struct win *w) { .blur_background = false, .reg_ignore = NULL, // The following ones are updated for other reasons - .pixmap_damaged = false, // updated by damage events - .state = WSTATE_UNMAPPED, // updated by window state changes - .in_openclose = true, // set to false after first map is done, - // true here because window is just created + .pixmap_damaged = false, // updated by damage events + .state = WSTATE_UNMAPPED, // updated by window state changes + .in_openclose = true, // set to false after first map is done, + // true here because window is just created .animation_velocity_x = 0.0, // updated by window geometry changes .animation_velocity_y = 0.0, // updated by window geometry changes .animation_velocity_w = 0.0, // updated by window geometry changes .animation_velocity_h = 0.0, // updated by window geometry changes .animation_progress = 1.0, // updated by window geometry changes .animation_inv_og_distance = NAN, // updated by window geometry changes - .reg_ignore_valid = false, // set to true when damaged - .flags = WIN_FLAGS_IMAGES_NONE, // updated by property/attributes/etc - // change + .reg_ignore_valid = false, // set to true when damaged + .flags = WIN_FLAGS_IMAGES_NONE, // updated by + // property/attributes/etc + // change .stale_props = NULL, .stale_props_capacity = 0, @@ -1783,9 +1870,11 @@ struct win *fill_win(session_t *ps, struct win *w) { .win_image = NULL, .old_win_image = NULL, .shadow_image = NULL, + .mask_image = NULL, .prev_trans = NULL, .shadow = false, .clip_shadow_above = false, + .fg_shader = NULL, .xinerama_scr = -1, .mode = WMODE_TRANS, .ever_damaged = false, @@ -1807,6 +1896,7 @@ struct win *fill_win(session_t *ps, struct win *w) { .rounded_corners = false, .paint_excluded = false, .fade_excluded = false, + .transparent_clipping_excluded = false, .unredir_if_possible_excluded = false, .prop_shadow = -1, // following 4 are set in win_mark_client @@ -1834,8 +1924,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; } @@ -1847,14 +1938,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; @@ -1924,8 +2016,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); @@ -1961,8 +2053,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; @@ -2009,7 +2101,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) { @@ -2157,7 +2250,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); @@ -2198,8 +2292,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); @@ -2213,6 +2307,7 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) { // Window shape changed, we should free old wpaint and shadow pict // log_trace("free out dated pict"); win_set_flags(w, WIN_FLAGS_IMAGES_STALE); + win_release_mask(ps->backend_data, w); ps->pending_updates = true; free_paint(ps, &w->paint); @@ -2255,7 +2350,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; @@ -2369,11 +2465,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); } @@ -2382,6 +2479,7 @@ static void destroy_win_finish(session_t *ps, struct win *w) { assert(mw->shadow_image != NULL); win_release_shadow(ps->backend_data, mw); } + win_release_mask(ps->backend_data, mw); // Invalidate reg_ignore of windows below this one // TODO(yshui) what if next_w is not mapped?? @@ -2396,11 +2494,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; } @@ -2433,11 +2532,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; @@ -2519,39 +2620,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); @@ -2598,7 +2702,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); @@ -2648,10 +2753,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)); } } @@ -2667,7 +2772,6 @@ bool win_check_fade_finished(session_t *ps, struct managed_win *w) { assert(w->opacity_target == w->opacity); return false; } - if (w->opacity == w->opacity_target) { switch (w->state) { case WSTATE_UNMAPPING: unmap_win_finish(ps, w); return false; @@ -2720,14 +2824,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); } @@ -2752,23 +2858,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; @@ -2788,9 +2895,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 @@ -2925,17 +3032,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) { @@ -3101,7 +3208,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; |