diff --git a/quickshell/services/python/launch_app.py b/quickshell/services/python/launch_app.py index d999a6b..a6306a7 100755 --- a/quickshell/services/python/launch_app.py +++ b/quickshell/services/python/launch_app.py @@ -5,16 +5,32 @@ import subprocess import shutil import re +def get_installed_flatpaks(): + """Returns a list of installed Flatpak application IDs.""" + try: + res = subprocess.run(["flatpak", "list", "--app", "--columns=application"], capture_output=True, text=True) + if res.returncode == 0: + return [line.strip() for line in res.stdout.splitlines() if line.strip()] + except Exception: + pass + return [] + def launch(): if len(sys.argv) < 2: return - cmd = sys.argv[1].strip() - if not cmd: + raw_cmd = sys.argv[1].strip() + if not raw_cmd: return - # Strip desktop field codes (%u, %U, %f, %F, etc.) - clean_cmd = re.sub(r'%[a-zA-Z]', '', cmd).strip() + # Strip desktop field codes (%u, %U, %f, %F, %i, %c, %k, etc.) + clean_cmd = re.sub(r'%[a-zA-Z]', '', raw_cmd).strip() + + # Extract desktop ID and base name + # e.g. "/usr/bin/equibop" -> "equibop", "org.equicord.equibop.desktop" -> "org.equicord.equibop" base_name = clean_cmd.replace('.desktop', '').strip() + if '/' in base_name: + base_name = os.path.basename(base_name.split()[0]).replace('.desktop', '').strip() + lower_name = base_name.lower() flatpak_mappings = { @@ -23,6 +39,9 @@ def launch(): "zen": "io.github.zen_browser.zen", "zen-browser": "io.github.zen_browser.zen", "vesktop": "dev.vencord.Vesktop", + "equibop": "org.equicord.equibop", + "equicord": "org.equicord.equibop", + "vencord": "dev.vencord.Vesktop", "discord": "com.discordapp.Discord", "code": "com.visualstudio.code", "vscodium": "com.vscodium.codium", @@ -31,24 +50,36 @@ def launch(): "heroic": "com.heroicgameslauncher.hgl" } - # 1. Flatpak launch check (launch exactly once if Flatpak ID is installed) + installed_flatpaks = get_installed_flatpaks() + + # 1. Flatpak launch check candidates_flatpak = [] - if base_name in flatpak_mappings: - candidates_flatpak.append(flatpak_mappings[base_name]) if lower_name in flatpak_mappings: candidates_flatpak.append(flatpak_mappings[lower_name]) - if base_name.startswith(("org.", "io.", "com.", "app.")): - candidates_flatpak.append(base_name) + + # Match any installed flatpak containing lower_name (e.g. 'equibop' -> 'org.equicord.equibop') + for fp in installed_flatpaks: + fp_lower = fp.lower() + if lower_name in fp_lower or fp_lower.endswith(lower_name): + if fp not in candidates_flatpak: + candidates_flatpak.append(fp) + + if lower_name.startswith(("org.", "io.", "com.", "app.", "dev.")): + candidates_flatpak.append(lower_name) for fp_id in candidates_flatpak: + if fp_id in installed_flatpaks: + subprocess.Popen(["flatpak", "run", fp_id], start_new_session=True) + return + # Fallback check via flatpak info check = subprocess.run(["flatpak", "info", fp_id], capture_output=True, text=True) if check.returncode == 0: subprocess.Popen(["flatpak", "run", fp_id], start_new_session=True) return - # 2. GTK Desktop launcher check + # 2. GTK Desktop launcher check (using clean desktop ID without paths) if shutil.which("gtk-launch"): - for gtk_id in [base_name, f"{base_name}.desktop"]: + for gtk_id in [base_name, f"{base_name}.desktop", lower_name]: res = subprocess.run(["gtk-launch", gtk_id], capture_output=True, text=True) if res.returncode == 0: return