diff --git a/docs/changelog.rst b/docs/changelog.rst index 44acf30d9..051307a7e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -83,6 +83,9 @@ To update |kitty|, :doc:`follow the instructions `. - hints kitten: When using the linenumber action with a background action, preserve the working directory (:iss:`3352`) +- Graphics protocol: Fix suppression of responses not working for chunked + transmission (:iss:`3375`) + 0.19.3 [2020-12-19] ------------------- diff --git a/docs/graphics-protocol.rst b/docs/graphics-protocol.rst index 8f7d489bf..1939e2e59 100644 --- a/docs/graphics-protocol.rst +++ b/docs/graphics-protocol.rst @@ -269,7 +269,7 @@ sequence of escape codes to the terminal emulator:: _Gm=0;\ Note that only the first escape code needs to have the full set of control -codes such as width, height, format etc. Subsequent chunks must have +codes such as width, height, format etc. Subsequent chunks **must** have only the ``m`` key. The client **must** finish sending all chunks for a single image before sending any other graphics related escape codes. Note that the cursor position used to display the image **must** be the position when the final chunk is diff --git a/kitty/graphics.c b/kitty/graphics.c index c8f595042..b3a9d687a 100644 --- a/kitty/graphics.c +++ b/kitty/graphics.c @@ -1508,7 +1508,7 @@ grman_handle_command(GraphicsManager *self, const GraphicsCommand *g, const uint Image *image = handle_add_command(self, g, payload, is_dirty, iid); if (!self->currently_loading.loading_for.image_id) free_load_data(&self->currently_loading); GraphicsCommand *lg = &self->currently_loading.start_command; - lg->quiet = g->quiet; + if (g->quiet) lg->quiet = g->quiet; if (is_query) ret = finish_command_response(&(const GraphicsCommand){.id=q_iid, .quiet=g->quiet}, image != NULL); else ret = finish_command_response(lg, image != NULL); if (lg->action == 'T' && image && image->root_frame_data_loaded) handle_put_command(self, lg, c, is_dirty, image, cell); @@ -1534,7 +1534,8 @@ grman_handle_command(GraphicsManager *self, const GraphicsCommand *g, const uint if (ag.action == 'f') { img = handle_animation_frame_load_command(self, &ag, img, payload, is_dirty); if (!self->currently_loading.loading_for.image_id) free_load_data(&self->currently_loading); - ag.quiet = g->quiet; + if (g->quiet) ag.quiet = g->quiet; + else ag.quiet = self->currently_loading.start_command.quiet; ret = finish_command_response(&ag, img != NULL); } else if (ag.action == 'a') { handle_animation_control_command(self, is_dirty, &ag, img); diff --git a/kitty_tests/graphics.py b/kitty_tests/graphics.py index 79efb306f..5b258a18c 100644 --- a/kitty_tests/graphics.py +++ b/kitty_tests/graphics.py @@ -286,13 +286,43 @@ class TestGraphics(BaseTest): dc.remove_from_ram(clear_predicate) self.assertEqual(dc.num_cached_in_ram(), 0) + def test_suppressing_gr_command_responses(self): + s, g, l, sl = load_helpers(self) + self.ae(l('abcd', s=10, v=10, q=1), 'ENODATA:Insufficient image data: 4 < 400') + self.ae(l('abcd', s=10, v=10, q=2), None) + self.assertIsNone(l('abcd', s=1, v=1, a='q', q=1)) + # Test chunked load + self.assertIsNone(l('abcd', s=2, v=2, m=1, q=1)) + self.assertIsNone(l('efgh', m=1)) + self.assertIsNone(l('ijkl', m=1)) + self.assertIsNone(l('mnop', m=0)) + + # errors + self.assertIsNone(l('abcd', s=2, v=2, m=1, q=1)) + self.ae(l('mnop', m=0), 'ENODATA:Insufficient image data: 8 < 16') + self.assertIsNone(l('abcd', s=2, v=2, m=1, q=2)) + self.assertIsNone(l('mnop', m=0)) + + # frames + s = self.create_screen() + li = make_send_command(s) + self.assertEqual(li().code, 'ENOENT') + self.assertIsNone(li(q=2)) + self.assertIsNone(li(a='t', q=1)) + self.assertIsNone(li(payload='2' * 12, z=77, m=1, q=1)) + self.assertIsNone(li(payload='2' * 12, m=1)) + self.assertIsNone(li(payload='2' * 12)) + self.assertIsNone(li(payload='2' * 12, z=77, m=1, q=1)) + self.ae(li(payload='2' * 12).code, 'ENODATA') + self.assertIsNone(li(payload='2' * 12, z=77, m=1, q=2)) + self.assertIsNone(li(payload='2' * 12)) + def test_load_images(self): s, g, l, sl = load_helpers(self) self.assertEqual(g.disk_cache.total_size, 0) # Test load query self.ae(l('abcd', s=1, v=1, a='q'), 'OK') - self.assertIsNone(l('abcd', s=1, v=1, a='q', q=1)) self.ae(g.image_count, 0) # Test simple load @@ -308,8 +338,6 @@ class TestGraphics(BaseTest): self.ae(l('mnop', m=0), 'OK') img = g.image_for_client_id(1) self.ae(img['data'], b'abcdefghijklmnop') - self.ae(l('abcd', s=10, v=10, q=1), 'ENODATA:Insufficient image data: 4 < 400') - self.ae(l('abcd', s=10, v=10, q=2), None) # Test compression random_data = byte_block(3 * 1024)