64 lines
2.3 KiB
Python
Executable file
64 lines
2.3 KiB
Python
Executable file
#!/bin/env python
|
|
from argparse import ArgumentParser
|
|
import subprocess
|
|
import json
|
|
|
|
# JSON object to represent a window in Niri
|
|
type WindowJson = dict[str, int | str | bool]
|
|
|
|
# Get a list of open windows from Niri
|
|
def get_windows():
|
|
command = "niri msg -j windows"
|
|
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
data: list[WindowJson] = json.loads(process.communicate()[0])
|
|
|
|
return data
|
|
|
|
# Generate a string representation for each window.
|
|
# Map the string to its Niri window ID
|
|
def get_string_id_mapping(window_list: list[WindowJson]):
|
|
mapping: dict[str, int] = {}
|
|
for idx, window in enumerate(window_list):
|
|
s = f"{idx}: {window.get("app_id")}: {window.get("title")}"
|
|
id = window.get("id")
|
|
assert type(id) == int
|
|
mapping[s] = id
|
|
return mapping
|
|
|
|
# Generate the string to be sent to fuzzel
|
|
def get_input_string(mapping: dict[str, int]):
|
|
m = max([len(s) for s in mapping.keys()])
|
|
return "\n".join(mapping.keys()), m
|
|
|
|
def spawn_picker(cmd, input_string, m):
|
|
# cmd = "fuzzel --dmenu -I --placeholder=Select a window:"
|
|
cmd = f"{cmd} --width {min(m, 120) + 1}"
|
|
process = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
|
selection = process.communicate(input=input_string.encode("UTF-8"))
|
|
if process.returncode != 2:
|
|
return selection[0].decode("UTF-8").strip("\n")
|
|
else:
|
|
return None
|
|
|
|
def switch_window(id: int):
|
|
cmd = f"niri msg action focus-window --id {id}"
|
|
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
|
|
process.communicate()
|
|
|
|
if __name__ == "__main__":
|
|
parser = ArgumentParser()
|
|
parser.add_argument("-p", "--picker", required=False, help="Set a picker command. Must take a newline delimited string on stdin and return the selection on stdout (default: %(default)s)", default="fuzzel --dmenu --placeholder=Select a window:", type=str, metavar="COMMAND")
|
|
args = parser.parse_args()
|
|
picker_cmd = args.picker
|
|
# print("picker:", picker_cmd)
|
|
wl = get_windows()
|
|
mapping = get_string_id_mapping(wl)
|
|
input_string, m= get_input_string(mapping)
|
|
selection = spawn_picker(picker_cmd, input_string, m)
|
|
if selection is None:
|
|
exit(1)
|
|
try:
|
|
id = mapping[selection]
|
|
except KeyError:
|
|
exit(1)
|
|
switch_window(id)
|