| @@ -0,0 +1,57 @@ |
| 1 | + | #!/usr/bin/env python3 |
| 2 | + | # org.freedesktop.FileManager1 for lf: browsers' "Show in Folder", Electron apps, portals... call |
| 3 | + | # ShowItems/ShowFolders over D-Bus. Each opens lf in foot (a file = its folder with the file selected). |
| 4 | + | # D-Bus activated via ~/.local/share/dbus-1/services/org.freedesktop.FileManager1.service. |
| 5 | + | import os |
| 6 | + | import subprocess |
| 7 | + | from urllib.parse import unquote, urlparse |
| 8 | + | |
| 9 | + | from gi.repository import Gio, GLib |
| 10 | + | |
| 11 | + | XML = """ |
| 12 | + | <node> |
| 13 | + | <interface name="org.freedesktop.FileManager1"> |
| 14 | + | <method name="ShowFolders"><arg type="as" name="URIs" direction="in"/><arg type="s" name="StartupId" direction="in"/></method> |
| 15 | + | <method name="ShowItems"><arg type="as" name="URIs" direction="in"/><arg type="s" name="StartupId" direction="in"/></method> |
| 16 | + | <method name="ShowItemProperties"><arg type="as" name="URIs" direction="in"/><arg type="s" name="StartupId" direction="in"/></method> |
| 17 | + | </interface> |
| 18 | + | </node> |
| 19 | + | """ |
| 20 | + | |
| 21 | + | |
| 22 | + | def path_of(uri): |
| 23 | + | if uri.startswith("file://"): |
| 24 | + | return unquote(urlparse(uri).path) |
| 25 | + | return uri if uri.startswith("/") else None |
| 26 | + | |
| 27 | + | |
| 28 | + | def lf(path): |
| 29 | + | subprocess.Popen(["foot", "-e", "lf", path], start_new_session=True, |
| 30 | + | stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) |
| 31 | + | |
| 32 | + | |
| 33 | + | def call(conn, sender, obj, iface, method, params, inv): |
| 34 | + | uris, _startup = params.unpack() |
| 35 | + | # one window per folder: ShowItems of several files in the same folder opens it once |
| 36 | + | seen = set() |
| 37 | + | for uri in uris: |
| 38 | + | p = path_of(uri) |
| 39 | + | if not p or not os.path.exists(p): |
| 40 | + | continue |
| 41 | + | key = p if method == "ShowFolders" else os.path.dirname(p) |
| 42 | + | if key in seen: |
| 43 | + | continue |
| 44 | + | seen.add(key) |
| 45 | + | lf(p) |
| 46 | + | inv.return_value(None) |
| 47 | + | |
| 48 | + | |
| 49 | + | def acquired(conn, name): |
| 50 | + | node = Gio.DBusNodeInfo.new_for_xml(XML) |
| 51 | + | conn.register_object("/org/freedesktop/FileManager1", node.interfaces[0], call, None, None) |
| 52 | + | |
| 53 | + | |
| 54 | + | loop = GLib.MainLoop() |
| 55 | + | Gio.bus_own_name(Gio.BusType.SESSION, "org.freedesktop.FileManager1", Gio.BusNameOwnerFlags.NONE, |
| 56 | + | acquired, None, lambda *a: loop.quit()) |
| 57 | + | loop.run() |