From 3f0ecbb2410e7ab50d2487c39ac052a4e7ff5450 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 5 Dec 2021 18:02:09 +0530 Subject: [PATCH] Use the new async response framework when setting background/logo images via RC. Avoids having to use --no-response --- kitty/rc/set_background_image.py | 29 +++++++++++++++-------------- kitty/rc/set_window_logo.py | 24 +++++++++++------------- kitty/remote_control.py | 2 +- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/kitty/rc/set_background_image.py b/kitty/rc/set_background_image.py index bd17bd59a..c6c7f360c 100644 --- a/kitty/rc/set_background_image.py +++ b/kitty/rc/set_background_image.py @@ -5,9 +5,11 @@ import imghdr import os import tempfile from base64 import standard_b64decode, standard_b64encode -from typing import IO, TYPE_CHECKING, Optional +from typing import IO, TYPE_CHECKING, Dict, Optional from uuid import uuid4 +from kitty.types import AsyncResponse + from .base import ( MATCH_WINDOW_OPTION, ArgsType, Boss, CmdGenerator, PayloadGetType, PayloadType, RCOptions, RemoteCommand, ResponseType, Window @@ -22,7 +24,6 @@ class SetBackgroundImage(RemoteCommand): ''' data+: Chunk of at most 512 bytes of PNG data, base64 encoded. Must send an empty chunk to indicate end of image. \ Or the special value - to indicate image must be removed. - img_id+: Unique uuid (as string) used for chunking match: Window to change opacity in layout: The image layout all: Boolean indicating operate on all windows @@ -62,8 +63,8 @@ failed, the command will exit with a success code. argspec = 'PATH_TO_PNG_IMAGE' args_count = 1 args_completion = {'files': ('PNG Images', ('*.png',))} - current_img_id: Optional[str] = None - current_file_obj: Optional[IO[bytes]] = None + images_in_flight: Dict[str, IO[bytes]] = {} + is_asynchronous = True def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: if len(args) != 1: @@ -96,15 +97,13 @@ failed, the command will exit with a success code. def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType: data = payload_get('data') + img_id = payload_get('async_id') if data != '-': - img_id = payload_get('img_id') - if img_id != set_background_image.current_img_id: - set_background_image.current_img_id = img_id - set_background_image.current_file_obj = tempfile.NamedTemporaryFile() + if img_id not in self.images_in_flight: + self.images_in_flight[img_id] = tempfile.NamedTemporaryFile() if data: - assert set_background_image.current_file_obj is not None - set_background_image.current_file_obj.write(standard_b64decode(data)) - return None + self.images_in_flight[img_id].write(standard_b64decode(data)) + return AsyncResponse() windows = self.windows_for_payload(boss, window, payload_get) os_windows = tuple({w.os_window_id for w in windows}) @@ -112,10 +111,8 @@ failed, the command will exit with a success code. if data == '-': path = None else: - assert set_background_image.current_file_obj is not None - f = set_background_image.current_file_obj + f = self.images_in_flight.pop(img_id) path = f.name - set_background_image.current_file_obj = None f.flush() try: @@ -125,5 +122,9 @@ failed, the command will exit with a success code. raise return None + def cancel_async_request(self, boss: 'Boss', window: Optional['Window'], payload_get: PayloadGetType) -> None: + async_id = payload_get('async_id') + self.images_in_flight.pop(async_id, None) + set_background_image = SetBackgroundImage() diff --git a/kitty/rc/set_window_logo.py b/kitty/rc/set_window_logo.py index e2a349a2c..46c92a108 100644 --- a/kitty/rc/set_window_logo.py +++ b/kitty/rc/set_window_logo.py @@ -6,9 +6,11 @@ import imghdr import os import tempfile from base64 import standard_b64decode, standard_b64encode -from typing import IO, TYPE_CHECKING, Optional +from typing import IO, TYPE_CHECKING, Dict, Optional from uuid import uuid4 +from kitty.types import AsyncResponse + from .base import ( MATCH_WINDOW_OPTION, ArgsType, Boss, CmdGenerator, PayloadGetType, PayloadType, RCOptions, RemoteCommand, ResponseType, Window @@ -62,8 +64,8 @@ failed, the command will exit with a success code. argspec = 'PATH_TO_PNG_IMAGE' args_count = 1 args_completion = {'files': ('PNG Images', ('*.png',))} - current_img_id: Optional[str] = None - current_file_obj: Optional[IO[bytes]] = None + images_in_flight: Dict[str, IO[bytes]] = {} + is_asynchronous = True def message_to_kitty(self, global_opts: RCOptions, opts: 'CLIOptions', args: ArgsType) -> PayloadType: if len(args) != 1: @@ -96,23 +98,19 @@ failed, the command will exit with a success code. def response_from_kitty(self, boss: Boss, window: Optional[Window], payload_get: PayloadGetType) -> ResponseType: data = payload_get('data') + img_id = payload_get('async_id') if data != '-': - img_id = payload_get('img_id') - if img_id != self.current_img_id: - self.current_img_id = img_id - self.current_file_obj = tempfile.NamedTemporaryFile(suffix='.png') + if img_id not in self.images_in_flight: + self.images_in_flight[img_id] = tempfile.NamedTemporaryFile() if data: - assert self.current_file_obj is not None - self.current_file_obj.write(standard_b64decode(data)) - return None + self.images_in_flight[img_id].write(standard_b64decode(data)) + return AsyncResponse() if data == '-': path = '' else: - assert self.current_file_obj is not None - f = self.current_file_obj + f = self.images_in_flight.pop(img_id) path = f.name - self.current_file_obj = None f.flush() alpha = float(payload_get('alpha', '-1')) diff --git a/kitty/remote_control.py b/kitty/remote_control.py index 5b59e4513..77a47dc3c 100644 --- a/kitty/remote_control.py +++ b/kitty/remote_control.py @@ -45,12 +45,12 @@ def handle_cmd(boss: BossType, window: Optional[WindowType], serialized_cmd: str payload['peer_id'] = peer_id async_id = str(cmd.get('async', '')) if async_id: + payload['async_id'] = async_id if 'cancel_async' in cmd: active_async_requests.pop(async_id, None) c.cancel_async_request(boss, window, PayloadGetter(c, payload)) return None active_async_requests[async_id] = monotonic() - payload['async_id'] = async_id if len(active_async_requests) > 32: oldest = next(iter(active_async_requests)) del active_async_requests[oldest]