Skip to content
This repository was archived by the owner on Oct 15, 2025. It is now read-only.

Commit 9b696d4

Browse files
nopsqiManuelSchneid3r
authored andcommitted
[x_window_switcher] 0.6.0
1 parent 8df351d commit 9b696d4

1 file changed

Lines changed: 71 additions & 0 deletions

File tree

x_window_switcher/__init__.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import subprocess
4+
from collections import namedtuple
5+
from albert import *
6+
7+
md_iid = "3.0"
8+
md_version = "0.6.0"
9+
md_name = "X Window Switcher"
10+
md_description = "Switch X11 Windows"
11+
md_license = "MIT"
12+
md_url = "https://github.com/albertlauncher/python/tree/main/x_window_switcher"
13+
md_bin_dependencies = "wmctrl"
14+
md_authors = ["Ed Perez", "Manuel S.", "dshoreman", "nopsqi"]
15+
16+
Window = namedtuple("Window", ["wid", "desktop", "wm_class", "host", "wm_name"])
17+
18+
19+
class Plugin(PluginInstance, TriggerQueryHandler):
20+
def __init__(self):
21+
PluginInstance.__init__(self)
22+
TriggerQueryHandler.__init__(self)
23+
24+
# Check for X session and wmctrl availability
25+
try:
26+
subprocess.check_call(["wmctrl", "-m"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
27+
except FileNotFoundError:
28+
raise Exception("wmctrl not found. Please install wmctrl.")
29+
except subprocess.CalledProcessError:
30+
raise Exception("Unable to communicate with X11 window manager. This plugin requires a running X session.")
31+
32+
def defaultTrigger(self):
33+
return 'w '
34+
35+
def handleTriggerQuery(self, query):
36+
try:
37+
for line in subprocess.check_output(['wmctrl', '-l', '-x']).splitlines():
38+
win = Window(*parseWindow(line))
39+
40+
if win.desktop == "-1":
41+
continue
42+
43+
win_instance, win_class = win.wm_class.replace(' ', '-').split('.', 1)
44+
45+
m = Matcher(query.string)
46+
if not query.string or m.match(win_instance + ' ' + win_class + ' ' + win.wm_name):
47+
query.add(StandardItem(
48+
id="%s%s" % (md_name, win.wm_class),
49+
iconUrls=["xdg:%s" % win_instance],
50+
text="%s - Desktop %s" % (win_class.replace('-', ' '), win.desktop),
51+
subtext=win.wm_name,
52+
actions=[Action("switch",
53+
"Switch Window",
54+
lambda w=win: runDetachedProcess(["wmctrl", '-i', '-a', w.wid])),
55+
Action("move",
56+
"Move window to this desktop",
57+
lambda w=win: runDetachedProcess(["wmctrl", '-i', '-R', w.wid])),
58+
Action("close",
59+
"Close the window gracefully.",
60+
lambda w=win: runDetachedProcess(["wmctrl", '-c', w.wid]))]
61+
))
62+
except subprocess.CalledProcessError as e:
63+
warning(f"Error executing wmctrl: {str(e)}")
64+
65+
66+
def parseWindow(line):
67+
win_id, desktop, rest = line.decode().split(None, 2)
68+
win_class, rest = rest.split(' ', 1)
69+
host, title = rest.strip().split(None, 1)
70+
71+
return [win_id, desktop, win_class, host, title]

0 commit comments

Comments
 (0)