| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- #!/usr/bin/env python3
- """
- Simple script to launch an application or focus it if already running in niri
- Usage: niri-launch-or-focus <command> [--class CLASS] [--title TITLE] [args...]
- Examples:
- niri-launch-or-focus firefox
- niri-launch-or-focus code --class Code --title "My Project"
- niri-launch-or-focus kitty --class kitty
- """
- import argparse
- import json
- import subprocess
- import sys
- def find_window(class_name=None, title=None, app_name=None):
- """Find window by app_id (class), title, or app name."""
- try:
- result = subprocess.run(
- ["niri", "msg", "--json", "windows"],
- capture_output=True,
- text=True,
- check=False,
- )
- windows_json = result.stdout.strip()
-
- if not windows_json or windows_json == "[]":
- return None
-
- windows = json.loads(windows_json)
-
- for window in windows:
- app_id = window.get("app_id", "").lower()
-
- if class_name:
- if app_id == class_name.lower():
- return window.get("id")
- elif title:
- if window.get("title") == title:
- return window.get("id")
- elif app_name:
- if app_id == app_name.lower():
- return window.get("id")
-
- return None
- except (json.JSONDecodeError, subprocess.SubprocessError, KeyError):
- return None
- def focus_window(window_id):
- """Focus a window by ID."""
- subprocess.run(
- ["niri", "msg", "action", "focus-window", "--id", str(window_id)],
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- )
- def launch_command(command, args):
- """Launch a command in the background."""
- subprocess.Popen(
- [command] + args,
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- start_new_session=True,
- )
- def main():
- parser = argparse.ArgumentParser(
- description="Launch an application or focus it if already running in niri"
- )
- parser.add_argument("command", help="Command to run")
- parser.add_argument("--class", dest="class_name", help="Window class (app_id)")
- parser.add_argument("--title", help="Window title")
- parser.add_argument("args", nargs=argparse.REMAINDER, help="Additional arguments for command")
-
- args = parser.parse_args()
-
- # Extract app name from command (basename)
- app_name = args.command.split("/")[-1]
-
- # Try to find existing window
- window_id = find_window(
- class_name=args.class_name,
- title=args.title,
- app_name=app_name if not args.class_name and not args.title else None,
- )
-
- # Build command arguments
- cmd_args = []
- if args.class_name:
- cmd_args.append(f"--class={args.class_name}")
- if args.title:
- cmd_args.append(f"--title={args.title}")
- cmd_args.extend(args.args)
-
- # Focus if found, otherwise launch
- if window_id:
- focus_window(window_id)
- else:
- launch_command(args.command, cmd_args)
- if __name__ == "__main__":
- main()
|