diff --git a/docs/changelog.rst b/docs/changelog.rst index 2e6093cdc..5cf312777 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -97,6 +97,8 @@ Detailed list of changes - Wayland: Fix an abort when a client program tries to set an invalid title containing interleaved escape codes and UTF-8 multi-byte characters (:iss:`8067`) +- Graphics protocol: Fix delete by number not deleting newest image with the specified number (:iss:`8071`) + 0.37.0 [2024-10-30] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/graphics.c b/kitty/graphics.c index 57e53fb59..562baea86 100644 --- a/kitty/graphics.c +++ b/kitty/graphics.c @@ -2051,14 +2051,6 @@ id_range_filter_func(const ImageRef *ref UNUSED, Image *img, const void *data, C } -static bool -number_filter_func(const ImageRef *ref, Image *img, const void *data, CellPixelSize cell UNUSED) { - const GraphicsCommand *g = data; - if (g->image_number && img->client_number == g->image_number) return !g->placement_id || ref->client_id == g->placement_id; - return false; -} - - static bool x_filter_func(const ImageRef *ref, Image UNUSED *img, const void *data, CellPixelSize cell UNUSED) { if (ref->is_virtual_ref || is_cell_image(ref)) return false; @@ -2098,9 +2090,8 @@ static void handle_delete_command(GraphicsManager *self, const GraphicsCommand *g, Cursor *c, bool *is_dirty, CellPixelSize cell) { if (self->currently_loading.loading_for.image_id) free_load_data(&self->currently_loading); GraphicsCommand d; - bool only_first_image = false; switch (g->delete_action) { -#define I(u, data, func) filter_refs(self, data, g->delete_action == u, func, cell, only_first_image); *is_dirty = true; break +#define I(u, data, func) filter_refs(self, data, g->delete_action == u, func, cell, false); *is_dirty = true; break #define D(l, u, data, func) case l: case u: I(u, data, func) #define G(l, u, func) D(l, u, g, func) case 0: @@ -2117,9 +2108,18 @@ handle_delete_command(GraphicsManager *self, const GraphicsCommand *g, Cursor *c d.x_offset = c->x + 1; d.y_offset = c->y + 1; I('C', &d, point_filter_func); case 'n': - case 'N': - only_first_image = true; - I('N', g, number_filter_func); + case 'N': { + Image *img = img_by_client_number(self, g->image_number); + if (img) { + for (ref_map_itr ri = vt_first(&img->refs_by_internal_id); !vt_is_end(ri); ) { ImageRef *ref = ri.data->val; + if (!g->placement_id || g->placement_id == ref->client_id) { + ri = remove_ref_itr(img, ri); + self->layers_dirty = true; + } else ri = vt_next(ri); + } + if (!vt_size(&img->refs_by_internal_id) && (g->delete_action == 'N' || img->client_id == 0)) remove_image(self, img); + } + } break; case 'f': case 'F': if (handle_delete_frame_command(self, g, is_dirty) != NULL) { diff --git a/kitty_tests/graphics.py b/kitty_tests/graphics.py index 9ad79d64f..dfd88c6f9 100644 --- a/kitty_tests/graphics.py +++ b/kitty_tests/graphics.py @@ -582,6 +582,16 @@ def delete(ac='N', **kw): self.ae(s.grman.image_count, count - 1) delete(I=1) self.ae(s.grman.image_count, count - 2) + cn = 1117 + li('abc', s=1, v=1, f=24, I=cn) + first_id = g.image_for_client_number(cn)['internal_id'] + li('abc', s=1, v=1, f=24, I=cn) + second_id = g.image_for_client_number(cn)['internal_id'] + self.assertNotEqual(first_id, second_id) + count = s.grman.image_count + delete(I=cn) + self.ae(g.image_for_client_number(cn)['internal_id'], first_id) + self.ae(s.grman.image_count, count - 1) s.reset() self.assertEqual(g.disk_cache.total_size, 0)