diff --git a/kitty/options/to-c.h b/kitty/options/to-c.h index aab7756f8..dc9f13d14 100644 --- a/kitty/options/to-c.h +++ b/kitty/options/to-c.h @@ -178,15 +178,25 @@ free_background_images(Options *opts) { static inline void background_images(PyObject *src, Options *opts) { - free_background_images(opts); static unsigned generation = 0; + size_t new_count = (PyTuple_Check(src) && PyTuple_GET_SIZE(src) > 0) ? (size_t)PyTuple_GET_SIZE(src) : 0; + if (new_count == opts->background_images.count && opts->background_images.paths) { + bool changed = false; + for (size_t i = 0; i < new_count; i++) { + const char *p = PyUnicode_AsUTF8(PyTuple_GET_ITEM(src, i)); + if (!p || !opts->background_images.paths[i] || strcmp(p, opts->background_images.paths[i]) != 0) { changed = true; break; } + } + if (!changed) return; + } + free_background_images(opts); opts->background_images.generation = ++generation; - if (!PyTuple_Check(src) || PyTuple_GET_SIZE(src) == 0) return; - opts->background_images.paths = calloc(PyTuple_GET_SIZE(src), sizeof(opts->background_images.paths[0])); + if (!new_count) return; + opts->background_images.paths = calloc(new_count, sizeof(opts->background_images.paths[0])); if (opts->background_images.paths) { - opts->background_images.count = PyTuple_GET_SIZE(src); - for (size_t i = 0; i < opts->background_images.count; i++) opts->background_images.paths[i] = strdup( - PyUnicode_AsUTF8(PyTuple_GET_ITEM(src, i))); + opts->background_images.count = new_count; + for (size_t i = 0; i < opts->background_images.count; i++) { + opts->background_images.paths[i] = strdup(PyUnicode_AsUTF8(PyTuple_GET_ITEM(src, i))); + } } } diff --git a/kitty/state.c b/kitty/state.c index f05d7565b..478173ca6 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -226,6 +226,7 @@ ensure_background_images_generation(bool release_texture) { if (global_state.background_images.generation == OPT(background_images).generation) return; free_global_background_images(release_texture); global_state.background_images.generation = OPT(background_images).generation; + global_state.background_images.entries_attempted = 0; if (OPT(background_images).count) { global_state.background_images.images = calloc( OPT(background_images).count, sizeof(global_state.background_images.images[0])); @@ -238,12 +239,11 @@ static unsigned bg_image_id_counter = 0; static BackgroundImage* global_background_image(size_t idx) { ensure_background_images_generation(true); - while (global_state.background_images.count <= idx && OPT(background_images).count) { - RAII_ALLOC(char, path, OPT(background_images).paths[0]); // transfer ownership - remove_i_from_array(OPT(background_images.paths), 0, OPT(background_images).count); + while (global_state.background_images.count <= idx && global_state.background_images.entries_attempted < OPT(background_images).count) { + size_t j = global_state.background_images.entries_attempted++; BackgroundImage *img = calloc(1, sizeof(BackgroundImage)); if (!img) fatal("Out of memory"); - if (image_path_to_bitmap(path, &img->bitmap, &img->width, &img->height, &img->mmap_size)) { + if (image_path_to_bitmap(OPT(background_images).paths[j], &img->bitmap, &img->width, &img->height, &img->mmap_size)) { if (send_bgimage_to_gpu(OPT(background_image_layout), img)) { img->refcnt++; img->id = ++bg_image_id_counter; @@ -273,7 +273,7 @@ increment_bg_image_idx(size_t idx, int delta) { } if ((unsigned)abs(delta) <= idx) return idx + delta; // wrap to last image, which means we need to load all - global_background_image(global_state.background_images.count + OPT(background_images).count + 1); + if (OPT(background_images).count > 0) global_background_image(OPT(background_images).count - 1); return global_state.background_images.count ? global_state.background_images.count - 1 : 0; } @@ -1417,6 +1417,12 @@ pyset_background_image(PyObject *self UNUSED, PyObject *args, PyObject *kw) { } global_state.background_images.images[0] = bgimage; bgimage->refcnt++; + if (OPT(background_images).count > 0) { + free(OPT(background_images).paths[0]); + char *new_path = strdup(path); + if (!new_path) fatal("Out of memory"); + OPT(background_images).paths[0] = new_path; + } } else free_global_background_images(true); OPT(background_image_layout) = layout; if (pylinear && pylinear != Py_None) convert_from_python_background_image_linear(pylinear, &global_state.opts); diff --git a/kitty/state.h b/kitty/state.h index 0f743864e..1564aca66 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -95,7 +95,8 @@ typedef struct Options { char *default_window_logo; struct { - char **paths; size_t count; + char **paths; + size_t count; unsigned generation; } background_images; BackgroundImageLayout background_image_layout; @@ -470,7 +471,7 @@ typedef struct GlobalState { PyObject *boss; struct { BackgroundImage **images; - size_t count; + size_t count, entries_attempted; unsigned generation; } background_images; OSWindow *os_windows;