From 85bf7f823e97af154ce8b13de2367ce4d7a0d525 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 17 Nov 2020 18:06:36 +0530 Subject: [PATCH] Workaround for SSIPClient using non-daemonic thread and therefore hanging interpreter shutdown --- src/calibre/gui2/tts/implementation.py | 4 +-- src/calibre/gui2/tts/linux.py | 43 +++++++++++++------------- src/calibre/gui2/viewer/ui.py | 1 + src/calibre/gui2/viewer/web_view.py | 14 +++++++-- 4 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/calibre/gui2/tts/implementation.py b/src/calibre/gui2/tts/implementation.py index cbd2844e11..23de156f74 100644 --- a/src/calibre/gui2/tts/implementation.py +++ b/src/calibre/gui2/tts/implementation.py @@ -9,5 +9,5 @@ if iswindows: elif ismacos: pass else: - from .linux import speak_simple_text - speak_simple_text + from .linux import Client + Client diff --git a/src/calibre/gui2/tts/linux.py b/src/calibre/gui2/tts/linux.py index 81d99d6846..46ba56d5a3 100644 --- a/src/calibre/gui2/tts/linux.py +++ b/src/calibre/gui2/tts/linux.py @@ -2,29 +2,30 @@ # vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2020, Kovid Goyal -import atexit from .errors import TTSSystemUnavailable -def get_client(): - client = getattr(get_client, 'ans', None) - if client is not None: - return client - from speechd.client import SSIPClient, SpawnError - try: - client = get_client.ans = SSIPClient('calibre') - except SpawnError as err: - raise TTSSystemUnavailable(_('Could not find speech-dispatcher on your system. Please install it.'), str(err)) - atexit.register(client.close) - return client +class Client: + def __init__(self): + self.create_ssip_client() -def speak_simple_text(text): - client = get_client() - from speechd.client import SSIPCommunicationError - try: - client.speak(text) - except SSIPCommunicationError: - get_client.ans = None - client = get_client() - client.speak(text) + def create_ssip_client(self): + from speechd.client import SSIPClient, SpawnError + try: + self.ssip_client = SSIPClient('calibre') + except SpawnError as err: + raise TTSSystemUnavailable(_('Could not find speech-dispatcher on your system. Please install it.'), str(err)) + + def __del__(self): + self.ssip_client.close() + del self.ssip_client + + def speak_simple_text(self, text): + from speechd.client import SSIPCommunicationError + try: + self.ssip_client.speak(text) + except SSIPCommunicationError: + self.ssip_client.close() + self.create_ssip_client() + self.ssip_client.speak(text) diff --git a/src/calibre/gui2/viewer/ui.py b/src/calibre/gui2/viewer/ui.py index 52c1fc5b34..9fd0e31e2c 100644 --- a/src/calibre/gui2/viewer/ui.py +++ b/src/calibre/gui2/viewer/ui.py @@ -674,6 +674,7 @@ class EbookViewer(MainWindow): return self.shutting_down = True self.search_widget.shutdown() + self.web_view.shutdown() try: self.save_state() self.save_annotations() diff --git a/src/calibre/gui2/viewer/web_view.py b/src/calibre/gui2/viewer/web_view.py index 9ee6bc9d1b..c7189a3e8b 100644 --- a/src/calibre/gui2/viewer/web_view.py +++ b/src/calibre/gui2/viewer/web_view.py @@ -467,6 +467,7 @@ class WebView(RestartingWebEngineView): def __init__(self, parent=None): self._host_widget = None + self._tts_client = None self.callback_id_counter = count() self.callback_map = {} self.current_cfi = self.current_content_file = None @@ -529,9 +530,18 @@ class WebView(RestartingWebEngineView): self.inspector = Inspector(parent.inspector_dock.toggleViewAction(), self) parent.inspector_dock.setWidget(self.inspector) + @property + def tts_client(self): + if self._tts_client is None: + from calibre.gui2.tts.implementation import Client + self._tts_client = Client() + return self._tts_client + def speak_simple_text(self, text): - from calibre.gui2.tts.implementation import speak_simple_text - speak_simple_text(text) + self.tts_client.speak_simple_text(text) + + def shutdown(self): + self._tts_client = None def set_shortcut_map(self, smap): self.shortcut_map = smap