diff --git a/linux/keyman-config/keyman_config/dbus_util.py b/linux/keyman-config/keyman_config/dbus_util.py new file mode 100644 index 0000000000..e960e322d9 --- /dev/null +++ b/linux/keyman-config/keyman_config/dbus_util.py @@ -0,0 +1,88 @@ +#!/usr/bin/python3 +import logging +import os + +import dbus +import dbus.bus +import dbus.mainloop.glib +import dbus.service + +BUS_NAME = 'com.Keyman.Config' +OBJECT_PATH = '/com/Keyman/Config' + + +__keyman_config_service = None + + +class KeymanConfigService(dbus.service.Object): + def __init__(self, bus, handler) -> None: + self.__keyboard_list_changed_handler = handler + self.__bus = bus + bus_name = dbus.service.BusName(BUS_NAME, bus=self.__bus, do_not_queue=True) + dbus.service.Object.__init__(self, bus_name, OBJECT_PATH) + + @dbus.service.signal(BUS_NAME) + def KeyboardListChangedSignal(self): + pass + + @dbus.service.method(BUS_NAME) + def keyboard_list_changed(self): + logging.debug("%s: -------------keyboard_list_changed--------------------" % os.getpid()) + if self.__keyboard_list_changed_handler: + self.__keyboard_list_changed_handler() + self.KeyboardListChangedSignal() + + +class KeymanConfigServiceManager: + def __init__(self, handler): + self.__name_owner_watch = None + self.__signal_receiver = None + self.__service = None + self.__keyboard_list_changed_handler = handler + loop = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + self.__bus = dbus.SessionBus(loop) + self.__name_owner_watch = self.__bus.watch_name_owner(BUS_NAME, self.__name_owner_changed) + + def __is_name_owner(self) -> bool: + retval = self.__bus.request_name(BUS_NAME, dbus.bus.NAME_FLAG_DO_NOT_QUEUE) + return ( + retval == dbus.bus.REQUEST_NAME_REPLY_ALREADY_OWNER or + retval == dbus.bus.REQUEST_NAME_REPLY_PRIMARY_OWNER) + + def __create_service(self) -> None: + if self.__signal_receiver: + self.__signal_receiver.remove() + self.__signal_receiver = None + if self.__is_name_owner(): + logging.debug('%s: I am now owner (%s)' % (os.getpid(), self.__bus.get_name_owner(BUS_NAME))) + if self.__name_owner_watch: + self.__name_owner_watch.cancel() + self.__name_owner_watch = None + self.__service = KeymanConfigService(self.__bus, self.__keyboard_list_changed_handler) + else: + logging.debug('%s: Not owner. Owner is %s. Connecting signal' % + (os.getpid(), self.__bus.get_name_owner(BUS_NAME))) + self.__service = self.__bus.get_object(BUS_NAME, OBJECT_PATH, introspect=False) + if self.__keyboard_list_changed_handler: + self.__signal_receiver = self.__service.connect_to_signal( + 'KeyboardListChangedSignal', self.__keyboard_list_changed_handler, dbus_interface=BUS_NAME) + + def __name_owner_changed(self, new_owner) -> None: + logging.debug('%s: Owner changed. Recreating service.' % os.getpid()) + self.__create_service() + + def __verify_service_exists(self) -> None: + if not self.__service: + self.__create_service() + + def keyboard_list_changed(self) -> None: + self.__verify_service_exists() + if self.__service: + self.__service.keyboard_list_changed() + + +def get_keyman_config_service(handler=None) -> KeymanConfigServiceManager: + global __keyman_config_service + if not __keyman_config_service: + __keyman_config_service = KeymanConfigServiceManager(handler) + return __keyman_config_service diff --git a/linux/keyman-config/keyman_config/install_kmp.py b/linux/keyman-config/keyman_config/install_kmp.py index 38ced061ea..17c40e117b 100755 --- a/linux/keyman-config/keyman_config/install_kmp.py +++ b/linux/keyman-config/keyman_config/install_kmp.py @@ -11,6 +11,7 @@ from shutil import rmtree from keyman_config import _, __version__, secure_lookup from keyman_config.canonical_language_code_utils import CanonicalLanguageCodeUtils from keyman_config.convertico import checkandsaveico, extractico +from keyman_config.dbus_util import get_keyman_config_service from keyman_config.fcitx_util import is_fcitx_running, restart_fcitx from keyman_config.get_kmp import (InstallLocation, get_keyboard_data, get_keyboard_dir, get_keyman_doc_dir, @@ -320,6 +321,9 @@ def install_kmp(inputfile, online=False, sharedarea=False, language=None): has_ui(bool, default=True): whether we're displaying a window or running UI less from the command line """ if sharedarea: - return InstallKmp().install_kmp_shared(inputfile, online, language) + return_value = InstallKmp().install_kmp_shared(inputfile, online, language) else: - return InstallKmp().install_kmp_user(inputfile, online, language) + return_value = InstallKmp().install_kmp_user(inputfile, online, language) + + get_keyman_config_service().keyboard_list_changed() + return return_value diff --git a/linux/keyman-config/keyman_config/uninstall_kmp.py b/linux/keyman-config/keyman_config/uninstall_kmp.py index c7408b097d..fe8931dbe3 100755 --- a/linux/keyman-config/keyman_config/uninstall_kmp.py +++ b/linux/keyman-config/keyman_config/uninstall_kmp.py @@ -5,6 +5,7 @@ import os from shutil import rmtree from keyman_config import _ +from keyman_config.dbus_util import get_keyman_config_service from keyman_config.fcitx_util import is_fcitx_running from keyman_config.get_kmp import (InstallLocation, get_keyboard_dir, get_keyman_doc_dir, get_keyman_font_dir) @@ -163,3 +164,5 @@ def uninstall_kmp(packageID, sharedarea=False): uninstall_kmp_shared(packageID) else: uninstall_kmp_user(packageID) + + get_keyman_config_service().keyboard_list_changed() diff --git a/linux/keyman-config/keyman_config/view_installed.py b/linux/keyman-config/keyman_config/view_installed.py index 93d5721c23..959c0196d9 100755 --- a/linux/keyman-config/keyman_config/view_installed.py +++ b/linux/keyman-config/keyman_config/view_installed.py @@ -16,6 +16,7 @@ from gi.repository import GdkPixbuf, Gtk from keyman_config import _ from keyman_config.accelerators import bind_accelerator, init_accel +from keyman_config.dbus_util import get_keyman_config_service from keyman_config.downloadkeyboard import DownloadKmpWindow from keyman_config.get_kmp import (InstallLocation, get_keyboard_dir, get_keyman_dir) @@ -32,6 +33,7 @@ class ViewInstalledWindowBase(Gtk.Window): self.accelerators = None Gtk.Window.__init__(self, title=_("Keyman Configuration")) init_accel(self) + self._config_service = get_keyman_config_service(self.refresh_installed_kmp) def refresh_installed_kmp(self): pass