| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- #!/usr/bin/env python3
- """
- Launch an application or focus it if already running in i3.
- Usage: i3-launch-or-focus --class CLASS <command> [args...]
- Examples:
- i3-launch-or-focus --class sdm-connect alacritty -e ~/.local/bin/sdm-ui.sh
- i3-launch-or-focus --class dropdown alacritty
- """
- import argparse
- import json
- import subprocess
- import sys
- def find_window(tree, instance=None, title=None):
- """Recursively search the i3 tree for a window matching criteria."""
- props = tree.get("window_properties", {})
- if instance and props.get("instance", "").lower() == instance.lower():
- return tree.get("id")
- if title and tree.get("name", "") == title:
- return tree.get("id")
- for node in tree.get("nodes", []) + tree.get("floating_nodes", []):
- result = find_window(node, instance=instance, title=title)
- if result:
- return result
- return None
- def focus_window(instance=None, title=None):
- """Focus a window using i3-msg criteria."""
- if instance:
- criteria = f'[instance="{instance}"]'
- elif title:
- criteria = f'[title="{title}"]'
- else:
- return
- subprocess.run(
- ["i3-msg", f"{criteria} focus"],
- stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- )
- def launch_command(command, args):
- """Launch a command, replacing this process."""
- import os
- os.execvp(command, [command] + args)
- def main():
- parser = argparse.ArgumentParser(
- description="Launch an application or focus it if already running in i3"
- )
- parser.add_argument("command", help="Command to run")
- parser.add_argument("--class", dest="class_name", help="Window instance name")
- parser.add_argument("--title", help="Window title")
- parser.add_argument(
- "args", nargs=argparse.REMAINDER, help="Additional arguments for command"
- )
- args = parser.parse_args()
- try:
- result = subprocess.run(
- ["i3-msg", "-t", "get_tree"],
- capture_output=True,
- text=True,
- check=False,
- )
- tree = json.loads(result.stdout)
- except (json.JSONDecodeError, subprocess.SubprocessError):
- tree = {}
- window_id = find_window(tree, instance=args.class_name, title=args.title)
- if window_id:
- focus_window(instance=args.class_name, title=args.title)
- else:
- 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)
- launch_command(args.command, cmd_args)
- if __name__ == "__main__":
- main()
|