Created
March 23, 2023 09:14
-
-
Save crazygolem/b3021cd834f013145afa54805ef330b4 to your computer and use it in GitHub Desktop.
Launch an application with KDocker from its desktop file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import argparse | |
import os | |
import re | |
import shlex | |
import shutil | |
import subprocess | |
# pyxdg; https://freedesktop.org/wiki/Software/pyxdg/ | |
from xdg.DesktopEntry import DesktopEntry | |
from xdg import IconTheme | |
for bin in ['kdocker', 'xdotool']: | |
if not shutil.which(bin): | |
raise Exception(f"Missing dependency, could not find executable: {bin}") | |
def file(path): | |
if os.path.isfile(path): | |
return path | |
else: | |
raise Exception('Could not find specified desktop file') | |
parser = argparse.ArgumentParser( | |
description='Launch an application with KDocker from its desktop file.') | |
parser.add_argument('-d', '--avoid-launch', action='store_true', | |
help="dock an existing window if possible") | |
parser.add_argument('-D', '--dock-only', action='store_true', | |
help="dock an existing window instead of launching the app") | |
parser.add_argument('-c', '--click', action='store_true', | |
help="select the window to dock by clicking on it") | |
parser.add_argument('-n', '--name', action='store_true', | |
help="use the name/title instead of WMClass to match the window") | |
parser.add_argument('path', type=file, help='Path to a desktop file') | |
args = parser.parse_args() | |
def find_window(de, wait=True): | |
# I could not make KDocker match the windows' title with '-n', and I'm not | |
# sure why... | |
# So instead the matching is done manually and the result is fed to KDocker. | |
# This adds a dependency to an external program, but also allows matching on | |
# other attributes, like the WMClass which seems to be more robust. | |
wmclass = de.getStartupWMClass() | |
appname = de.getName() | |
cmd = ['xdotool', 'search', '--onlyvisible', '--limit', '1'] | |
if wait: | |
cmd += ['--sync'] | |
if wmclass and not args.name: | |
cmd += ['--classname', re.escape(wmclass)] | |
else: | |
cmd += ['--name', re.escape(appname)] | |
return subprocess.run( | |
cmd, | |
check=wait, timeout=5, | |
capture_output=True, text=True | |
).stdout.strip() | |
de = DesktopEntry() | |
de.parse(args.path) | |
kdargs = [] | |
if icon := de.getIcon(): | |
# The Icon value can be either already an absolute path, or a name which | |
# needs to be looked up. | |
icon = IconTheme.getIconPath(icon) | |
kdargs += ['-i', icon] | |
if not (args.dock_only or (args.avoid_launch and find_window(de, wait=False))): | |
# KDocker is not able to target correctly windows of apps that launch | |
# separate processes, or processes that own multiple windows that should be | |
# docked independently. | |
# PWAs installed with Chrome can fall into both categories, as chrome reuses | |
# the first process that was launched for subsequent windows, leading to a | |
# confusing situation where the first PWA to launch is correctly docked as | |
# long as there is no existing Chrome window, but the following PWAs aren't. | |
# To work around this, the app is first launched "in the background", then | |
# KDocker is called separately to dock the window. | |
subprocess.Popen(shlex.split(de.getExec())) | |
if not args.click: | |
kdargs += ['-w', find_window(de)] | |
try: | |
subprocess.run(['kdocker', *kdargs], check=True) | |
except KeyboardInterrupt: | |
pass |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment