75e54cd5ef
This part of GIO library isn't suitable for short-lived processes (the call is done asynchronously and may not reach the application before qubes-desktop-run process is terminated). To fix this, implement dbus activation manually, synchronously. While at it, implement waiting for application to terminate (useful in DispVM), by waiting for its dbus name to disappear. dbus-python API isn't particularly nice, but don't switch to completely different library as a stable update. Fixes QubesOS/qubes-issues#2449
70 lines
2.5 KiB
Python
Executable File
70 lines
2.5 KiB
Python
Executable File
import functools
|
|
|
|
from gi.repository import Gio # pylint: disable=import-error
|
|
from gi.repository import GLib # pylint: disable=import-error
|
|
import sys
|
|
import os
|
|
|
|
def pid_callback(launcher, pid, pid_list):
|
|
pid_list.append(pid)
|
|
|
|
def dbus_name_change(loop, name, old_owner, new_owner):
|
|
if not new_owner:
|
|
loop.quit()
|
|
|
|
def launch(desktop, *files, **kwargs):
|
|
wait = kwargs.pop('wait', True)
|
|
launcher = Gio.DesktopAppInfo.new_from_filename(desktop)
|
|
try:
|
|
import dbus
|
|
from dbus.mainloop.glib import DBusGMainLoop
|
|
if hasattr(launcher, 'get_boolean'):
|
|
activatable = launcher.get_boolean('DBusActivatable')
|
|
if activatable:
|
|
loop = GLib.MainLoop()
|
|
DBusGMainLoop(set_as_default=True)
|
|
bus = dbus.SessionBus()
|
|
service_id = launcher.get_id()
|
|
# cut the .desktop suffix
|
|
service_id = service_id[:-len('.desktop')]
|
|
# see D-Bus Activation Desktop entry specification
|
|
object_path = '/' + service_id.replace('.', '/').\
|
|
replace('-', '_')
|
|
try:
|
|
proxy = bus.get_object(service_id, object_path)
|
|
match = bus.add_signal_receiver(
|
|
functools.partial(dbus_name_change, loop),
|
|
'NameOwnerChanged',
|
|
dbus.BUS_DAEMON_IFACE,
|
|
dbus.BUS_DAEMON_NAME,
|
|
dbus.BUS_DAEMON_PATH)
|
|
if files:
|
|
proxy.Open(files, {},
|
|
dbus_interface='org.freedesktop.Application')
|
|
else:
|
|
proxy.Activate({},
|
|
dbus_interface='org.freedesktop.Application')
|
|
except dbus.DBusException as e:
|
|
print(e)
|
|
# fallback to non-dbus version
|
|
pass
|
|
else:
|
|
if wait:
|
|
loop.run()
|
|
match.remove()
|
|
return
|
|
except ImportError:
|
|
pass
|
|
if wait:
|
|
pid_list = []
|
|
flags = GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD
|
|
launcher.launch_uris_as_manager(files, None, flags, None, None,
|
|
pid_callback, pid_list)
|
|
for pid in pid_list:
|
|
os.waitpid(pid, 0)
|
|
else:
|
|
launcher.launch(files, None)
|
|
|
|
if __name__ == "__main__":
|
|
launch(*sys.argv[1:])
|