xdg.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import functools
  2. from gi.repository import Gio # pylint: disable=import-error
  3. from gi.repository import GLib # pylint: disable=import-error
  4. import sys
  5. import os
  6. def pid_callback(launcher, pid, pid_list):
  7. pid_list.append(pid)
  8. def dbus_name_change(loop, name, old_owner, new_owner):
  9. if not new_owner:
  10. loop.quit()
  11. def launch(desktop, *files, **kwargs):
  12. wait = kwargs.pop('wait', True)
  13. launcher = Gio.DesktopAppInfo.new_from_filename(desktop)
  14. try:
  15. import dbus
  16. from dbus.mainloop.glib import DBusGMainLoop
  17. if hasattr(launcher, 'get_boolean'):
  18. activatable = launcher.get_boolean('DBusActivatable')
  19. if activatable:
  20. loop = GLib.MainLoop()
  21. DBusGMainLoop(set_as_default=True)
  22. bus = dbus.SessionBus()
  23. service_id = launcher.get_id()
  24. # cut the .desktop suffix
  25. service_id = service_id[:-len('.desktop')]
  26. # see D-Bus Activation Desktop entry specification
  27. object_path = '/' + service_id.replace('.', '/').\
  28. replace('-', '_')
  29. try:
  30. proxy = bus.get_object(service_id, object_path)
  31. match = bus.add_signal_receiver(
  32. functools.partial(dbus_name_change, loop),
  33. 'NameOwnerChanged',
  34. dbus.BUS_DAEMON_IFACE,
  35. dbus.BUS_DAEMON_NAME,
  36. dbus.BUS_DAEMON_PATH)
  37. if files:
  38. proxy.Open(files, {},
  39. dbus_interface='org.freedesktop.Application')
  40. else:
  41. proxy.Activate({},
  42. dbus_interface='org.freedesktop.Application')
  43. except dbus.DBusException as e:
  44. print(e)
  45. # fallback to non-dbus version
  46. pass
  47. else:
  48. if wait:
  49. loop.run()
  50. match.remove()
  51. return
  52. except ImportError:
  53. pass
  54. if wait:
  55. pid_list = []
  56. flags = GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD
  57. launcher.launch_uris_as_manager(files, None, flags, None, None,
  58. pid_callback, pid_list)
  59. for pid in pid_list:
  60. os.waitpid(pid, 0)
  61. else:
  62. launcher.launch(files, None)
  63. if __name__ == "__main__":
  64. launch(*sys.argv[1:])