diff options
Diffstat (limited to 'src/picom.c')
| -rw-r--r-- | src/picom.c | 449 |
1 files changed, 233 insertions, 216 deletions
diff --git a/src/picom.c b/src/picom.c index 24d5ece..980655d 100644 --- a/src/picom.c +++ b/src/picom.c @@ -69,8 +69,6 @@ (session_t *)((char *)__mptr - offsetof(session_t, member)); \ }) -static const long SWOPTI_TOLERANCE = 3000; - static bool must_use redirect_start(session_t *ps); static void unredirect(session_t *ps); @@ -90,6 +88,7 @@ const char *const BACKEND_STRS[] = {[BKEND_XRENDER] = "xrender", [BKEND_GLX] = "glx", [BKEND_XR_GLX_HYBRID] = "xr_glx_hybrid", [BKEND_DUMMY] = "dummy", + [BKEND_EGL] = "egl", NULL}; // clang-format on @@ -433,6 +432,14 @@ static void destroy_backend(session_t *ps) { free_paint(ps, &w->paint); } + HASH_ITER2(ps->shaders, shader) { + if (shader->backend_shader != NULL) { + ps->backend_data->ops->destroy_shader(ps->backend_data, + shader->backend_shader); + shader->backend_shader = NULL; + } + } + if (ps->backend_data && ps->root_image) { ps->backend_data->ops->release_image(ps->backend_data, ps->root_image); ps->root_image = NULL; @@ -445,6 +452,11 @@ static void destroy_backend(session_t *ps) { ps->backend_data, ps->backend_blur_context); ps->backend_blur_context = NULL; } + if (ps->shadow_context) { + ps->backend_data->ops->destroy_shadow_context(ps->backend_data, + ps->shadow_context); + ps->shadow_context = NULL; + } ps->backend_data->ops->deinit(ps->backend_data); ps->backend_data = NULL; } @@ -487,7 +499,7 @@ static bool initialize_blur(session_t *ps) { /// Init the backend and bind all the window pixmap to backend images static bool initialize_backend(session_t *ps) { - if (ps->o.experimental_backends) { + if (!ps->o.legacy_backends) { assert(!ps->backend_data); // Reinitialize win_data assert(backend_list[ps->o.backend]); @@ -498,13 +510,38 @@ static bool initialize_backend(session_t *ps) { return false; } ps->backend_data->ops = backend_list[ps->o.backend]; + ps->shadow_context = ps->backend_data->ops->create_shadow_context( + ps->backend_data, ps->o.shadow_radius); + if (!ps->shadow_context) { + log_fatal("Failed to initialize shadow context, aborting..."); + goto err; + } if (!initialize_blur(ps)) { log_fatal("Failed to prepare for background blur, aborting..."); - ps->backend_data->ops->deinit(ps->backend_data); - ps->backend_data = NULL; - quit(ps); - return false; + goto err; + } + + // Create shaders + HASH_ITER2(ps->shaders, shader) { + assert(shader->backend_shader == NULL); + shader->backend_shader = ps->backend_data->ops->create_shader( + ps->backend_data, shader->source); + if (shader->backend_shader == NULL) { + log_warn("Failed to create shader for shader file %s, " + "this shader will not be used", + shader->key); + } else { + if (ps->backend_data->ops->get_shader_attributes) { + shader->attributes = + ps->backend_data->ops->get_shader_attributes( + ps->backend_data, shader->backend_shader); + } else { + shader->attributes = 0; + } + log_debug("Shader %s has attributes %" PRIu64, + shader->key, shader->attributes); + } } // window_stack shouldn't include window that's @@ -527,6 +564,16 @@ static bool initialize_backend(session_t *ps) { // The old backends binds pixmap lazily, nothing to do here return true; +err: + if (ps->shadow_context) { + ps->backend_data->ops->destroy_shadow_context(ps->backend_data, + ps->shadow_context); + ps->shadow_context = NULL; + } + ps->backend_data->ops->deinit(ps->backend_data); + ps->backend_data = NULL; + quit(ps); + return false; } /// Handle configure event of the root window @@ -541,7 +588,7 @@ static void configure_root(session_t *ps) { bool has_root_change = false; if (ps->redirected) { // On root window changes - if (ps->o.experimental_backends) { + if (!ps->o.legacy_backends) { assert(ps->backend_data); has_root_change = ps->backend_data->ops->root_change != NULL; } else { @@ -585,7 +632,7 @@ static void configure_root(session_t *ps) { ps->damage = ps->damage_ring + ps->ndamage - 1; #ifdef CONFIG_OPENGL // GLX root change callback - if (BKEND_GLX == ps->o.backend && !ps->o.experimental_backends) { + if (BKEND_GLX == ps->o.backend && ps->o.legacy_backends) { glx_on_root_change(ps); } #endif @@ -619,14 +666,6 @@ static void handle_root_flags(session_t *ps) { if (ps->o.xinerama_shadow_crop) { cxinerama_upd_scrs(ps); } - - if (ps->o.sw_opti && !ps->o.refresh_rate) { - update_refresh_rate(ps); - if (!ps->refresh_rate) { - log_warn("Refresh rate detection failed. swopti will be " - "temporarily disabled"); - } - } ps->root_flags &= ~(uint64_t)ROOT_FLAGS_SCREEN_CHANGE; } @@ -639,8 +678,7 @@ static void handle_root_flags(session_t *ps) { static struct managed_win * paint_preprocess(session_t *ps, bool *fade_running, bool *animation_running) { // XXX need better, more general name for `fade_running`. It really - // means if fade is still ongoing after the current frame is rendered. - // Same goes for `animation_running`. + // means if fade is still ongoing after the current frame is rendered struct managed_win *bottom = NULL; *fade_running = false; *animation_running = false; @@ -670,7 +708,9 @@ paint_preprocess(session_t *ps, bool *fade_running, bool *animation_running) { animation_delta = min2(animation_delta, ps->o.animation_delta/1000); } - // First, let's process fading + // First, let's process fading, and animated shaders + // TODO(yshui) check if a window is fully obscured, and if we don't need to + // process fading or animation for it. win_stack_foreach_managed_safe(w, &ps->window_stack) { const winmode_t mode_old = w->mode; const bool was_painted = w->to_paint; @@ -850,39 +890,42 @@ paint_preprocess(session_t *ps, bool *fade_running, bool *animation_running) { add_damage_from_win(ps, w); } - if (w->opacity != w->opacity_target) { - // Run fading - if (run_fade(ps, &w, steps)) { - *fade_running = true; - } + if (w->fg_shader && (w->fg_shader->attributes & SHADER_ATTRIBUTE_ANIMATED)) { + add_damage_from_win(ps, w); + *animation_running = true; + } - // Add window to damaged area if its opacity changes - // If was_painted == false, and to_paint is also false, we don't care - // If was_painted == false, but to_paint is true, damage will be added in - // the loop below - if (was_painted && w->opacity != opacity_old) { - add_damage_from_win(ps, w); - } + // Run fading + if (run_fade(ps, &w, steps)) { + *fade_running = true; + } - if (win_check_fade_finished(ps, w)) { - // the window has been destroyed because fading finished - continue; - } + // Add window to damaged area if its opacity changes + // If was_painted == false, and to_paint is also false, we don't care + // If was_painted == false, but to_paint is true, damage will be added in + // the loop below + if (was_painted && w->opacity != opacity_old) { + add_damage_from_win(ps, w); + } - if (win_has_frame(w)) { - w->frame_opacity = ps->o.frame_opacity; - } else { - w->frame_opacity = 1.0; - } + if (win_check_fade_finished(ps, w)) { + // the window has been destroyed because fading finished + continue; + } - // Update window mode - w->mode = win_calc_mode(w); + if (win_has_frame(w)) { + w->frame_opacity = ps->o.frame_opacity; + } else { + w->frame_opacity = 1.0; + } - // Destroy all reg_ignore above when frame opaque state changes on - // SOLID mode - if (was_painted && w->mode != mode_old) { - w->reg_ignore_valid = false; - } + // Update window mode + w->mode = win_calc_mode(w); + + // Destroy all reg_ignore above when frame opaque state changes on + // SOLID mode + if (was_painted && w->mode != mode_old) { + w->reg_ignore_valid = false; } } @@ -983,7 +1026,7 @@ paint_preprocess(session_t *ps, bool *fade_running, bool *animation_running) { // we add the window region to the ignored region // Otherwise last_reg_ignore shouldn't change if ((w->mode != WMODE_TRANS && !ps->o.force_win_blend) || - ps->o.transparent_clipping) { + (ps->o.transparent_clipping && !w->transparent_clipping_excluded)) { // w->mode == WMODE_SOLID or WMODE_FRAME_TRANS region_t *tmp = rc_region_new(); if (w->mode == WMODE_SOLID) { @@ -1098,9 +1141,13 @@ void root_damaged(session_t *ps) { if (pixmap != XCB_NONE) { ps->root_image = ps->backend_data->ops->bind_pixmap( ps->backend_data, pixmap, x_get_visual_info(ps->c, ps->vis), false); - ps->backend_data->ops->set_image_property( - ps->backend_data, IMAGE_PROPERTY_EFFECTIVE_SIZE, - ps->root_image, (int[]){ps->root_width, ps->root_height}); + if (ps->root_image) { + ps->backend_data->ops->set_image_property( + ps->backend_data, IMAGE_PROPERTY_EFFECTIVE_SIZE, + ps->root_image, (int[]){ps->root_width, ps->root_height}); + } else { + log_error("Failed to bind root back pixmap"); + } } } @@ -1240,7 +1287,7 @@ static int register_cm(session_t *ps) { ps->c, xcb_change_property_checked( ps->c, XCB_PROP_MODE_REPLACE, ps->reg_win, get_atom(ps->atoms, "COMPTON_VERSION"), XCB_ATOM_STRING, 8, - (uint32_t)strlen(COMPTON_VERSION), COMPTON_VERSION)); + (uint32_t)strlen(PICOM_VERSION), PICOM_VERSION)); if (e) { log_error_x_error(e, "Failed to set COMPTON_VERSION."); free(e); @@ -1295,77 +1342,6 @@ static inline bool write_pid(session_t *ps) { } /** - * Update refresh rate info with X Randr extension. - */ -void update_refresh_rate(session_t *ps) { - xcb_randr_get_screen_info_reply_t *randr_info = xcb_randr_get_screen_info_reply( - ps->c, xcb_randr_get_screen_info(ps->c, ps->root), NULL); - - if (!randr_info) - return; - ps->refresh_rate = randr_info->rate; - free(randr_info); - - if (ps->refresh_rate) - ps->refresh_intv = US_PER_SEC / ps->refresh_rate; - else - ps->refresh_intv = 0; -} - -/** - * Initialize refresh-rated based software optimization. - * - * @return true for success, false otherwise - */ -static bool swopti_init(session_t *ps) { - log_warn("--sw-opti is going to be deprecated. If you get real benefits from " - "using " - "this option, please open an issue to let us know."); - // Prepare refresh rate - // Check if user provides one - ps->refresh_rate = ps->o.refresh_rate; - if (ps->refresh_rate) - ps->refresh_intv = US_PER_SEC / ps->refresh_rate; - - // Auto-detect refresh rate otherwise - if (!ps->refresh_rate && ps->randr_exists) { - update_refresh_rate(ps); - } - - // Turn off vsync_sw if we can't get the refresh rate - if (!ps->refresh_rate) - return false; - - return true; -} - -/** - * Modify a struct timeval timeout value to render at a fixed pace. - * - * @param ps current session - * @param[in,out] ptv pointer to the timeout - */ -static double swopti_handle_timeout(session_t *ps) { - if (!ps->refresh_intv) - return 0; - - // Get the microsecond offset of the time when the we reach the timeout - // I don't think a 32-bit long could overflow here. - long offset = (get_time_timeval().tv_usec - ps->paint_tm_offset) % ps->refresh_intv; - // XXX this formula dones't work if refresh rate is not a whole number - if (offset < 0) - offset += ps->refresh_intv; - - // If the target time is sufficiently close to a refresh time, don't add - // an offset, to avoid certain blocking conditions. - if (offset < SWOPTI_TOLERANCE || offset > ps->refresh_intv - SWOPTI_TOLERANCE) - return 0; - - // Add an offset so we wait until the next refresh after timeout - return (double)(ps->refresh_intv - offset) / 1e6; -} - -/** * Initialize X composite overlay window. */ static bool init_overlay(session_t *ps) { @@ -1456,10 +1432,10 @@ uint8_t session_redirection_mode(session_t *ps) { if (ps->o.debug_mode) { // If the backend is not rendering to the screen, we don't need to // take over the screen. - assert(ps->o.experimental_backends); + assert(!ps->o.legacy_backends); return XCB_COMPOSITE_REDIRECT_AUTOMATIC; } - if (ps->o.experimental_backends && !backend_list[ps->o.backend]->present) { + if (!ps->o.legacy_backends && !backend_list[ps->o.backend]->present) { // if the backend doesn't render anything, we don't need to take over the // screen. return XCB_COMPOSITE_REDIRECT_AUTOMATIC; @@ -1496,7 +1472,7 @@ static bool redirect_start(session_t *ps) { return false; } - if (ps->o.experimental_backends) { + if (!ps->o.legacy_backends) { assert(ps->backend_data); ps->ndamage = ps->backend_data->ops->max_buffer_age; } else { @@ -1738,6 +1714,7 @@ static void draw_callback_impl(EV_P_ session_t *ps, int revents attr_unused) { ev_timer_set(&ps->fade_timer, fade_timeout(ps), 0); ev_timer_start(EV_A_ & ps->fade_timer); } + // Start/stop animation timer depends on whether windows are animating if (!animation_running && ev_is_active(&ps->animation_timer)) { ev_timer_stop(EV_A_ & ps->animation_timer); @@ -1751,7 +1728,7 @@ static void draw_callback_impl(EV_P_ session_t *ps, int revents attr_unused) { static int paint = 0; log_trace("Render start, frame %d", paint); - if (ps->o.experimental_backends) { + if (!ps->o.legacy_backends) { paint_all_new(ps, bottom, false); } else { paint_all(ps, bottom, false); @@ -1780,57 +1757,17 @@ static void draw_callback_impl(EV_P_ session_t *ps, int revents attr_unused) { } static void draw_callback(EV_P_ ev_idle *w, int revents) { - // This function is not used if we are using --swopti session_t *ps = session_ptr(w, draw_idle); draw_callback_impl(EV_A_ ps, revents); - // Don't do painting non-stop unless we are in benchmark mode - if (!ps->o.benchmark) { + // Don't do painting non-stop unless we are in benchmark mode, or if + // draw_callback_impl thinks we should continue painting. + if (!ps->o.benchmark && !ps->redraw_needed) { ev_idle_stop(EV_A_ & ps->draw_idle); } } -static void delayed_draw_timer_callback(EV_P_ ev_timer *w, int revents) { - session_t *ps = session_ptr(w, delayed_draw_timer); - draw_callback_impl(EV_A_ ps, revents); - - // We might have stopped the ev_idle in delayed_draw_callback, - // so we restart it if we are in benchmark mode - if (ps->o.benchmark) - ev_idle_start(EV_A_ & ps->draw_idle); -} - -static void delayed_draw_callback(EV_P_ ev_idle *w, int revents) { - // This function is only used if we are using --swopti - session_t *ps = session_ptr(w, draw_idle); - assert(ps->redraw_needed); - assert(!ev_is_active(&ps->delayed_draw_timer)); - - double delay = swopti_handle_timeout(ps); - if (delay < 1e-6) { - if (!ps->o.benchmark) { - ev_idle_stop(EV_A_ & ps->draw_idle); - } - return draw_callback_impl(EV_A_ ps, revents); - } - - // This is a little bit hacky. When we get to this point in code, we need - // to update the screen , but we will only be updating after a delay, So - // we want to stop the ev_idle, so this callback doesn't get call repeatedly - // during the delay, we also want queue_redraw to not restart the ev_idle. - // So we stop ev_idle and leave ps->redraw_needed to be true. (effectively, - // ps->redraw_needed means if redraw is needed or if draw is in progress). - // - // We do this anyway even if we are in benchmark mode. That means we will - // have to restart draw_idle after the draw actually happened when we are in - // benchmark mode. - ev_idle_stop(EV_A_ & ps->draw_idle); - - ev_timer_set(&ps->delayed_draw_timer, delay, 0); - ev_timer_start(EV_A_ & ps->delayed_draw_timer); -} - static void x_event_callback(EV_P attr_unused, ev_io *w, int revents attr_unused) { session_t *ps = (session_t *)w; xcb_generic_event_t *ev = xcb_poll_for_event(ps->c); @@ -1861,6 +1798,62 @@ static void config_file_change_cb(void *_ps) { reset_enable(ps->loop, NULL, 0); } +static bool load_shader_source(session_t *ps, const char *path) { + if (!path) { + // Using the default shader. + return false; + } + + log_info("Loading shader source from %s", path); + + struct shader_info *shader = NULL; + HASH_FIND_STR(ps->shaders, path, shader); + if (shader) { + log_debug("Shader already loaded, reusing"); + return false; + } + + shader = ccalloc(1, struct shader_info); + shader->key = strdup(path); + HASH_ADD_KEYPTR(hh, ps->shaders, shader->key, strlen(shader->key), shader); + + FILE *f = fopen(path, "r"); + if (!f) { + log_error("Failed to open custom shader file: %s", path); + goto err; + } + struct stat statbuf; + if (fstat(fileno(f), &statbuf) < 0) { + log_error("Failed to access custom shader file: %s", path); + goto err; + } + + auto num_bytes = (size_t)statbuf.st_size; + shader->source = ccalloc(num_bytes + 1, char); + auto read_bytes = fread(shader->source, sizeof(char), num_bytes, f); + if (read_bytes < num_bytes || ferror(f)) { + // This is a difficult to hit error case, review thoroughly. + log_error("Failed to read custom shader at %s. (read %lu bytes, expected " + "%lu bytes)", + path, read_bytes, num_bytes); + goto err; + } + return false; +err: + HASH_DEL(ps->shaders, shader); + if (f) { + fclose(f); + } + free(shader->source); + free(shader->key); + free(shader); + return true; +} + +static bool load_shader_source_for_condition(const c2_lptr_t *cond, void *data) { + return load_shader_source(data, c2_list_get_data(cond)); +} + /** * Initialize a session. * @@ -1912,11 +1905,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, .black_picture = XCB_NONE, .cshadow_picture = XCB_NONE, .white_picture = XCB_NONE, - .gaussian_map = NULL, - - .refresh_rate = 0, - .refresh_intv = 0UL, - .paint_tm_offset = 0L, + .shadow_context = NULL, #ifdef CONFIG_VSYNC_DRM .drm_fd = -1, @@ -2093,6 +2082,10 @@ static session_t *session_init(int argc, char **argv, Display *dpy, return NULL; } + if (ps->o.window_shader_fg) { + log_debug("Default window shader: \"%s\"", ps->o.window_shader_fg); + } + if (ps->o.logpath) { auto l = file_logger_new(ps->o.logpath); if (l) { @@ -2142,9 +2135,11 @@ static session_t *session_init(int argc, char **argv, Display *dpy, c2_list_postprocess(ps, ps->o.fade_blacklist) && c2_list_postprocess(ps, ps->o.blur_background_blacklist) && c2_list_postprocess(ps, ps->o.invert_color_list) && + c2_list_postprocess(ps, ps->o.window_shader_fg_rules) && c2_list_postprocess(ps, ps->o.opacity_rules) && - c2_list_postprocess(ps, ps->o.corner_rules) && c2_list_postprocess(ps, ps->o.rounded_corners_blacklist) && + c2_list_postprocess(ps, ps->o.corner_rules) && + c2_list_postprocess(ps, ps->o.blur_rules) && c2_list_postprocess(ps, ps->o.animation_open_blacklist) && c2_list_postprocess(ps, ps->o.animation_unmap_blacklist) && c2_list_postprocess(ps, ps->o.focus_blacklist))) { @@ -2152,8 +2147,27 @@ static session_t *session_init(int argc, char **argv, Display *dpy, "might not work"); } - ps->gaussian_map = gaussian_kernel_autodetect_deviation(ps->o.shadow_radius); - sum_kernel_preprocess(ps->gaussian_map); + // Load shader source file specified in the shader rules + if (c2_list_foreach(ps->o.window_shader_fg_rules, load_shader_source_for_condition, ps)) { + log_error("Failed to load shader source file for some of the window " + "shader rules"); + } + if (load_shader_source(ps, ps->o.window_shader_fg)) { + log_error("Failed to load window shader source file"); + } + + if (log_get_level_tls() <= LOG_LEVEL_DEBUG) { + HASH_ITER2(ps->shaders, shader) { + log_debug("Shader %s:", shader->key); + log_debug("%s", shader->source); + } + } + + if (ps->o.legacy_backends) { + ps->shadow_context = + (void *)gaussian_kernel_autodetect_deviation(ps->o.shadow_radius); + sum_kernel_preprocess((conv *)ps->shadow_context); + } rebuild_shadow_exclude_reg(ps); @@ -2224,11 +2238,10 @@ static session_t *session_init(int argc, char **argv, Display *dpy, } // Query X RandR - if ((ps->o.sw_opti && !ps->o.refresh_rate) || ps->o.xinerama_shadow_crop) { + if (ps->o.xinerama_shadow_crop) { if (!ps->randr_exists) { - log_fatal("No XRandR extension. sw-opti, refresh-rate or " - "xinerama-shadow-crop " - "cannot be enabled."); + log_fatal("No XRandR extension. xinerama-shadow-crop cannot be " + "enabled."); goto err; } } @@ -2280,7 +2293,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, // The old backends doesn't have a automatic redirection mode log_info("The compositor is started in automatic redirection mode."); - assert(ps->o.experimental_backends); + assert(!ps->o.legacy_backends); if (backend_list[ps->o.backend]->present) { // If the backend has `present`, we couldn't be in automatic @@ -2296,7 +2309,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, apply_driver_workarounds(ps, ps->drivers); // Initialize filters, must be preceded by OpenGL context creation - if (!ps->o.experimental_backends && !init_render(ps)) { + if (ps->o.legacy_backends && !init_render(ps)) { log_fatal("Failed to initialize the backend"); exit(1); } @@ -2314,7 +2327,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, free(config_file_to_free); - if (bkend_use_glx(ps) && !ps->o.experimental_backends) { + if (bkend_use_glx(ps) && ps->o.legacy_backends) { auto gl_logger = gl_string_marker_logger_new(); if (gl_logger) { log_info("Enabling gl string marker"); @@ -2322,7 +2335,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy, } } - if (ps->o.experimental_backends) { + if (!ps->o.legacy_backends) { if (ps->o.monitor_repaint && !backend_list[ps->o.backend]->fill) { log_warn("--monitor-repaint is not supported by the backend, " "disabling"); @@ -2330,15 +2343,11 @@ static session_t *session_init(int argc, char **argv, Display *dpy, } } - // Initialize software optimization - if (ps->o.sw_opti) - ps->o.sw_opti = swopti_init(ps); - // Monitor screen changes if vsync_sw is enabled and we are using // an auto-detected refresh rate, or when Xinerama features are enabled - if (ps->randr_exists && - ((ps->o.sw_opti && !ps->o.refresh_rate) || ps->o.xinerama_shadow_crop)) + if (ps->randr_exists && ps->o.xinerama_shadow_crop) { xcb_randr_select_input(ps->c, ps->root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE); + } cxinerama_upd_scrs(ps); @@ -2359,14 +2368,10 @@ static session_t *session_init(int argc, char **argv, Display *dpy, ev_io_init(&ps->xiow, x_event_callback, ConnectionNumber(ps->dpy), EV_READ); ev_io_start(ps->loop, &ps->xiow); ev_init(&ps->unredir_timer, tmout_unredir_callback); - if (ps->o.sw_opti) - ev_idle_init(&ps->draw_idle, delayed_draw_callback); - else - ev_idle_init(&ps->draw_idle, draw_callback); + ev_idle_init(&ps->draw_idle, draw_callback); ev_init(&ps->fade_timer, fade_timer_callback); ev_init(&ps->animation_timer, animation_timer_callback); - ev_init(&ps->delayed_draw_timer, delayed_draw_timer_callback); // Set up SIGUSR1 signal handler to reset program ev_signal_init(&ps->usr1_signal, reset_enable, SIGUSR1); @@ -2517,19 +2522,21 @@ static void session_destroy(session_t *ps) { list_init_head(&ps->window_stack); // Free blacklists - free_wincondlst(&ps->o.shadow_blacklist); - free_wincondlst(&ps->o.shadow_clip_list); - free_wincondlst(&ps->o.fade_blacklist); - free_wincondlst(&ps->o.focus_blacklist); - free_wincondlst(&ps->o.invert_color_list); - free_wincondlst(&ps->o.blur_background_blacklist); - free_wincondlst(&ps->o.opacity_rules); - free_wincondlst(&ps->o.corner_rules); - free_wincondlst(&ps->o.paint_blacklist); - free_wincondlst(&ps->o.unredir_if_possible_blacklist); - free_wincondlst(&ps->o.rounded_corners_blacklist); - free_wincondlst(&ps->o.animation_open_blacklist); - free_wincondlst(&ps->o.animation_unmap_blacklist); + c2_list_free(&ps->o.shadow_blacklist, NULL); + c2_list_free(&ps->o.shadow_clip_list, NULL); + c2_list_free(&ps->o.fade_blacklist, NULL); + c2_list_free(&ps->o.focus_blacklist, NULL); + c2_list_free(&ps->o.invert_color_list, NULL); + c2_list_free(&ps->o.blur_background_blacklist, NULL); + c2_list_free(&ps->o.opacity_rules, NULL); + c2_list_free(&ps->o.paint_blacklist, NULL); + c2_list_free(&ps->o.unredir_if_possible_blacklist, NULL); + c2_list_free(&ps->o.rounded_corners_blacklist, NULL); + c2_list_free(&ps->o.corner_rules, NULL); + c2_list_free(&ps->o.blur_rules, NULL); + c2_list_free(&ps->o.animation_open_blacklist, NULL); + c2_list_free(&ps->o.animation_unmap_blacklist, NULL); + c2_list_free(&ps->o.window_shader_fg_rules, free); // Free tracked atom list { @@ -2580,6 +2587,17 @@ static void session_destroy(session_t *ps) { free(ps->o.glx_fshader_win_str); free_xinerama_info(ps); + // Release custom window shaders + free(ps->o.window_shader_fg); + struct shader_info *shader, *tmp; + HASH_ITER(hh, ps->shaders, shader, tmp) { + HASH_DEL(ps->shaders, shader); + assert(shader->backend_shader == NULL); + free(shader->source); + free(shader->key); + free(shader); + } + #ifdef CONFIG_VSYNC_DRM // Close file opened for DRM VSync if (ps->drm_fd >= 0) { @@ -2615,7 +2633,7 @@ static void session_destroy(session_t *ps) { ps->damaged_region = XCB_NONE; } - if (ps->o.experimental_backends) { + if (!ps->o.legacy_backends) { // backend is deinitialized in unredirect() assert(ps->backend_data == NULL); } else { @@ -2632,7 +2650,9 @@ static void session_destroy(session_t *ps) { // Flush all events x_sync(ps->c); ev_io_stop(ps->loop, &ps->xiow); - free_conv(ps->gaussian_map); + if (ps->o.legacy_backends) { + free_conv((conv *)ps->shadow_context); + } destroy_atoms(ps->atoms); #ifdef DEBUG_XRC @@ -2658,9 +2678,6 @@ static void session_destroy(session_t *ps) { * @param ps current session */ static void session_run(session_t *ps) { - if (ps->o.sw_opti) - ps->paint_tm_offset = get_time_timeval().tv_usec; - // In benchmark mode, we want draw_idle handler to always be active if (ps->o.benchmark) { ev_idle_start(ps->loop, &ps->draw_idle); |