129 lines
4.9 KiB
Python
129 lines
4.9 KiB
Python
import typing
|
|
import os
|
|
|
|
from dasbus.connection import SessionMessageBus
|
|
from dasbus.loop import EventLoop
|
|
from dasbus.client.observer import DBusObserver
|
|
from dasbus.client.proxy import disconnect_proxy
|
|
|
|
from .watcher import WATCHER_SERVICE_NAME, WATCHER_OBJECT_PATH
|
|
from .tray import Tray
|
|
from .item import StatusNotifierItem
|
|
|
|
HOST_SERVICE_NAME_TEMPLATE = "org.kde.StatusNotifierHost-{}-{}"
|
|
HOST_OBJECT_PATH_TEMPLATE = "/StatusNotifierHost/{}"
|
|
|
|
dasbus_event_loop: typing.Union[EventLoop, None] = None
|
|
|
|
|
|
def get_service_name_and_object_path(service: str) -> (str, str):
|
|
index = service.find("/")
|
|
if index != len(service):
|
|
return service[0:index], service[index:]
|
|
return service, "/StatusNotifierItem"
|
|
|
|
|
|
class StatusNotifierHostInterface(object):
|
|
def __init__(self, host_id, trays: typing.List[Tray]):
|
|
self.host_id = host_id
|
|
self.trays = trays
|
|
|
|
self._statusNotifierItems = []
|
|
self.watcher_proxy = None
|
|
self.session_bus = SessionMessageBus()
|
|
|
|
self.host_service_name = HOST_SERVICE_NAME_TEMPLATE.format(os.getpid(), self.host_id)
|
|
self.host_object_path = HOST_OBJECT_PATH_TEMPLATE.format(self.host_id)
|
|
self.session_bus.register_service(self.host_service_name)
|
|
|
|
self.watcher_service_observer = DBusObserver(
|
|
message_bus=self.session_bus,
|
|
service_name=WATCHER_SERVICE_NAME
|
|
)
|
|
self.watcher_service_observer.service_available.connect(
|
|
self.watcher_available_handler
|
|
)
|
|
self.watcher_service_observer.service_unavailable.connect(
|
|
self.watcher_unavailable_handler
|
|
)
|
|
self.watcher_service_observer.connect_once_available()
|
|
|
|
def __del__(self):
|
|
if self.watcher_proxy is not None:
|
|
disconnect_proxy(self.watcher_proxy)
|
|
self.watcher_service_observer.disconnect()
|
|
self.session_bus.disconnect()
|
|
|
|
def watcher_available_handler(self, _observer):
|
|
print("StatusNotifierHostInterface -> watcher_available_handler")
|
|
self.watcher_proxy = self.session_bus.get_proxy(WATCHER_SERVICE_NAME, WATCHER_OBJECT_PATH)
|
|
self.watcher_proxy.StatusNotifierItemRegistered.connect(self.item_registered_handler)
|
|
self.watcher_proxy.StatusNotifierItemUnregistered.connect(self.item_unregistered_handler)
|
|
self.watcher_proxy.RegisterStatusNotifierHost(self.host_object_path, callback=lambda _: None)
|
|
|
|
def watcher_unavailable_handler(self, _observer):
|
|
print("StatusNotifierHostInterface -> watcher_unavailable_handler")
|
|
self._statusNotifierItems.clear()
|
|
disconnect_proxy(self.watcher_proxy)
|
|
self.watcher_proxy = None
|
|
|
|
def item_registered_handler(self, full_service_service):
|
|
print(
|
|
"StatusNotifierHostInterface -> item_registered_handler\n full_service_name: {}".format(
|
|
full_service_service
|
|
)
|
|
)
|
|
service_name, object_path = get_service_name_and_object_path(full_service_service)
|
|
if self.find_item(service_name, object_path) is None:
|
|
item = StatusNotifierItem(service_name, object_path)
|
|
item.set_on_loaded_callback(self.item_loaded_handler)
|
|
item.set_on_updated_callback(self.item_updated_handler)
|
|
self._statusNotifierItems.append(item)
|
|
|
|
def item_unregistered_handler(self, full_service_service):
|
|
print(
|
|
"StatusNotifierHostInterface -> item_unregistered_handler\n full_service_name: {}".format(
|
|
full_service_service
|
|
)
|
|
)
|
|
service_name, object_path = get_service_name_and_object_path(full_service_service)
|
|
item = self.find_item(service_name, object_path)
|
|
if item is not None:
|
|
self._statusNotifierItems.remove(item)
|
|
for tray in self.trays:
|
|
tray.remove_item(item)
|
|
|
|
def find_item(self, service_name, object_path) -> typing.Union[StatusNotifierItem, None]:
|
|
for item in self._statusNotifierItems:
|
|
if item.service_name == service_name and item.object_path == object_path:
|
|
return item
|
|
else:
|
|
return None
|
|
|
|
def item_loaded_handler(self, item):
|
|
for tray in self.trays:
|
|
tray.add_item(item)
|
|
|
|
def item_updated_handler(self, item, changed_properties):
|
|
for tray in self.trays:
|
|
tray.update_item(item, changed_properties)
|
|
|
|
|
|
def init(host_id, trays: typing.List[Tray]):
|
|
_status_notifier_host_interface = StatusNotifierHostInterface(host_id, trays)
|
|
|
|
global dasbus_event_loop
|
|
if dasbus_event_loop is None:
|
|
print("host.init(): running dasbus.EventLoop")
|
|
dasbus_event_loop = EventLoop()
|
|
dasbus_event_loop.run()
|
|
|
|
|
|
def deinit():
|
|
global dasbus_event_loop
|
|
if dasbus_event_loop is not None:
|
|
print("host.deinit(): quitting dasbus.EventLoop")
|
|
dasbus_event_loop.quit()
|
|
if dasbus_event_loop is not None:
|
|
dasbus_event_loop = None
|