This repository has no description
11 kB
322 lines
1import subprocess
2import threading
3import json
4import os
5from typing import Callable
6from pathlib import Path
7
8from libqtile import bar, layout, widget, extension, hook
9from libqtile.config import Click, Drag, Group, Key, Match, Screen, ScratchPad, DropDown
10from libqtile.lazy import lazy
11from libqtile.utils import guess_terminal
12from libqtile.command.client import InteractiveCommandClient
13from libqtile.core.manager import Qtile
14from libqtile.backend.wayland import InputConfig
15
16prompt = widget.Prompt()
17state_file = "/home/lass/.local/share/qtile/state"
18
19
20def dmenu(candidates: list[str], callback: Callable) -> None:
21 def thread() -> None:
22 theme = Path("/var/theme/config/rofi-theme").read_text().strip()
23 dmenu = subprocess.Popen(
24 ["rofi", "-dmenu", "-theme", theme],
25 stdin=subprocess.PIPE,
26 stdout=subprocess.PIPE,
27 )
28 output = dmenu.communicate(input=("\n".join(candidates)).encode())
29 callback(output[0].decode().rstrip())
30
31 threading.Thread(target=thread).start()
32
33
34@lazy.function
35def goto_workspace(qtile: Qtile) -> None:
36 def callback(name: str) -> None:
37 if name:
38 c = InteractiveCommandClient()
39 c.group[name].toscreen()
40
41 dmenu(candidates=qtile.items("group")[1], callback=callback)
42
43
44@lazy.function
45def moveto_workspace(qtile: Qtile) -> None:
46 def callback(name: str) -> None:
47 if name:
48 c = InteractiveCommandClient()
49 c.window.togroup(name)
50
51 dmenu(candidates=qtile.items("group")[1], callback=callback)
52
53
54@lazy.function
55def add_group(qtile: Qtile) -> None:
56 def callback(name: str) -> None:
57 if name:
58 qtile.addgroup(name)
59
60 prompt.start_input("Add group: ", callback=callback)
61
62
63@lazy.function
64def del_group(qtile: Qtile) -> None:
65 qtile.delgroup(qtile.current_group.name)
66
67
68@lazy.function
69def reload_config(qtile: Qtile) -> None:
70 with open(state_file, "w") as f:
71 f.write(json.dumps(qtile.get_groups(), default=tuple))
72 qtile.reload_config()
73
74
75mod = "mod4"
76terminal = guess_terminal()
77
78if os.path.exists(state_file):
79 with open(state_file, "r") as f:
80 state = json.loads(f.read())
81 groups = [Group(name) for name, _ in state.items()]
82else:
83 groups = [
84 Group("dashboard"),
85 Group("ff"),
86 ]
87
88keys = [
89 # A list of available commands that can be bound to keys can be found
90 # at https://docs.qtile.org/en/latest/manual/config/lazy.html
91 # Switch between windows
92 Key([mod], "Tab", lazy.layout.next(), desc="Move window focus to other window"),
93 Key(
94 [mod, "shift"],
95 "Tab",
96 lazy.layout.previous(),
97 desc="Move window focus to other window",
98 ),
99 Key(
100 [mod], "Escape", lazy.screen.toggle_group(), desc="Switch to last active group"
101 ),
102 # Move windows between left/right columns or move up/down in current stack.
103 # Moving out of range in Columns layout will create new column.
104 Key([mod, "shift"], "a", add_group, desc="add group"),
105 Key([mod, "shift"], "backspace", del_group, desc="delete group"),
106 Key(
107 [mod, "shift"], "h", lazy.layout.shuffle_left(), desc="Move window to the left"
108 ),
109 Key(
110 [mod, "shift"],
111 "l",
112 lazy.layout.shuffle_right(),
113 desc="Move window to the right",
114 ),
115 Key([mod, "shift"], "j", lazy.layout.shuffle_down(), desc="Move window down"),
116 Key([mod, "shift"], "k", lazy.layout.shuffle_up(), desc="Move window up"),
117 # Grow windows. If current window is on the edge of screen and direction
118 # will be to screen edge - window would shrink.
119 Key([mod, "control"], "h", lazy.layout.grow_left(), desc="Grow window to the left"),
120 Key(
121 [mod, "control"], "l", lazy.layout.grow_right(), desc="Grow window to the right"
122 ),
123 Key([mod, "control"], "j", lazy.layout.grow_down(), desc="Grow window down"),
124 Key([mod, "control"], "k", lazy.layout.grow_up(), desc="Grow window up"),
125 Key(
126 [mod],
127 "f",
128 lazy.window.toggle_fullscreen(),
129 desc="Toggle fullscreen",
130 ),
131 Key([mod], "n", lazy.layout.normalize(), desc="Reset all window sizes"),
132 Key([mod], "d", lazy.spawn("copyq show")),
133 Key([mod, "shift"], "Return", lazy.spawn(terminal), desc="Launch terminal"),
134 # Toggle between different layouts as defined below
135 Key([mod], "Space", lazy.next_layout(), desc="Toggle between layouts"),
136 Key([mod, "shift"], "c", lazy.window.kill(), desc="Kill focused window"),
137 Key([mod], "F11", lazy.spawn("swaylock --image /var/lib/wallpaper/wallpaper")),
138 Key(
139 [mod],
140 "t",
141 lazy.window.toggle_floating(),
142 desc="Toggle floating on the focused window",
143 ),
144 Key([mod, "shift"], "r", reload_config, desc="Reload the config"),
145 Key([mod, "control"], "q", lazy.shutdown(), desc="Shutdown Qtile"),
146 Key([mod], "r", lazy.spawncmd(), desc="Spawn a command using a prompt widget"),
147 Key([mod], "F1", lazy.group["scratchpad"].dropdown_toggle("term")),
148 Key([mod], "i", lazy.spawn("screenshot")),
149 Key([mod], "p", lazy.spawn("passmenu")),
150 Key([mod], "Insert", lazy.spawn("type_paste")),
151 Key([mod], "v", goto_workspace, desc="Switch to group"),
152 Key([mod, "shift"], "v", moveto_workspace, desc="move window to group"),
153 Key(
154 [],
155 "XF86AudioRaiseVolume",
156 lazy.spawn("pactl set-sink-volume @DEFAULT_SINK@ +5%"),
157 ),
158 Key(
159 [],
160 "XF86AudioLowerVolume",
161 lazy.spawn("pactl set-sink-volume @DEFAULT_SINK@ -5%"),
162 ),
163 Key([], "XF86MonBrightnessUp", lazy.spawn("xbacklight -inc 2")),
164 Key([], "XF86MonBrightnessDown", lazy.spawn("xbacklight -dec 2")),
165 Key(["control", "mod1"], "F1", lazy.core.change_vt(1), desc="Switch to VT 1"),
166 Key(["control", "mod1"], "F2", lazy.core.change_vt(2), desc="Switch to VT 2"),
167 Key(["control", "mod1"], "F3", lazy.core.change_vt(3), desc="Switch to VT 3"),
168 Key(["control", "mod1"], "F4", lazy.core.change_vt(4), desc="Switch to VT 4"),
169 Key(["control", "mod1"], "F5", lazy.core.change_vt(5), desc="Switch to VT 5"),
170 Key(["control", "mod1"], "F6", lazy.core.change_vt(6), desc="Switch to VT 6"),
171]
172
173layouts = [
174 layout.Max(),
175 layout.Columns(border_focus_stack=["#d75f5f", "#8f3d3d"], border_width=4),
176 # Try more layouts by unleashing below layouts.
177 # layout.Stack(num_stacks=2),
178 # layout.Bsp(),
179 layout.Matrix(),
180 # layout.MonadTall(),
181 # layout.MonadWide(),
182 # layout.RatioTile(),
183 # layout.Tile(),
184 # layout.TreeTab(),
185 # layout.VerticalTile(),
186 # layout.Zoomy(),
187]
188
189widget_defaults = dict(
190 font="sans",
191 fontsize=12,
192 padding=3,
193)
194extension_defaults = widget_defaults.copy()
195
196screens = [
197 Screen(
198 bottom=bar.Bar(
199 [
200 widget.CurrentLayout(),
201 widget.GenPollUrl(
202 url="http://radio.r:8002/current",
203 parse=lambda r: "/".join(r["filename"].split("/")[-2:]),
204 update_interval=15,
205 ),
206 widget.Spacer(),
207 widget.Wlan(interface="wlp170s0"),
208 widget.HDDBusyGraph(device="nvme0n1", graph_color="#4fbe4f"),
209 widget.MemoryGraph(graph_color="#eed563"),
210 widget.CPUGraph(graph_color="#8575bf"),
211 widget.ThermalZone(
212 zone="/sys/class/thermal/thermal_zone1/temp", background="#440000"
213 ),
214 widget.PulseVolume(background="#009900"),
215 widget.Backlight(
216 background="#b18f00", backlight_name="intel_backlight"
217 ),
218 widget.Battery(background="#e52383"),
219 # widget.Clock(format="%Y-%m-%d %a %H:%M"), # doesn't support timezone updates without restart
220 widget.GenPollCommand(
221 cmd="date +'%Y-%m-%d %a %H:%M %:::z'",
222 shell=True,
223 update_interval=10,
224 ),
225 widget.StatusNotifier(),
226 ],
227 24,
228 # border_width=[2, 0, 2, 0], # Draw top and bottom borders
229 # border_color=["ff00ff", "000000", "ff00ff", "000000"] # Borders are magenta
230 ),
231 top=bar.Bar(
232 [
233 widget.GroupBox(),
234 prompt,
235 widget.WindowName(),
236 widget.Chord(
237 chords_colors={
238 "launch": ("#ff0000", "#ffffff"),
239 },
240 name_transform=lambda name: name.upper(),
241 ),
242 ],
243 24,
244 ),
245 # You can uncomment this variable if you see that on X11 floating resize/moving is laggy
246 # By default we handle these events delayed to already improve performance, however your system might still be struggling
247 # This variable is set to None (no cap) by default, but you can set it to 60 to indicate that you limit it to 60 events per second
248 # x11_drag_polling_rate = 60,
249 ),
250]
251
252# Drag floating layouts.
253mouse = [
254 Drag(
255 [mod],
256 "Button1",
257 lazy.window.set_position_floating(),
258 start=lazy.window.get_position(),
259 ),
260 Drag(
261 [mod], "Button3", lazy.window.set_size_floating(), start=lazy.window.get_size()
262 ),
263 Click([mod], "Button2", lazy.window.bring_to_front()),
264]
265
266dgroups_key_binder = None
267dgroups_app_rules = [] # type: list
268follow_mouse_focus = True
269bring_front_click = False
270floats_kept_above = True
271cursor_warp = False
272floating_layout = layout.Floating(
273 float_rules=[
274 # Run the utility of `xprop` to see the wm class and name of an X client.
275 *layout.Floating.default_float_rules,
276 Match(wm_class="confirmreset"), # gitk
277 Match(wm_class="makebranch"), # gitk
278 Match(wm_class="maketag"), # gitk
279 Match(wm_class="ssh-askpass"), # ssh-askpass
280 Match(title="branchdialog"), # gitk
281 Match(title="pinentry"), # GPG key password entry
282 ]
283)
284auto_fullscreen = True
285focus_on_window_activation = "smart"
286reconfigure_screens = True
287
288# If things like steam games want to auto-minimize themselves when losing
289# focus, should we respect this or not?
290auto_minimize = True
291
292# When using the Wayland backend, this can be used to configure input devices.
293wl_input_rules = {
294 "type:keyboard": InputConfig(
295 kb_options="ctrl:nocaps", kb_layout="us", kb_variant="altgr-intl"
296 ),
297 "*": InputConfig(click_method="clickfinger"),
298}
299
300
301@hook.subscribe.startup
302def autostart():
303 subprocess.run(
304 [
305 "systemctl",
306 "--user",
307 "import-environment",
308 "XDG_SESSION_PATH",
309 "WAYLAND_DISPLAY",
310 ]
311 )
312
313
314# XXX: Gasp! We're lying here. In fact, nobody really uses or cares about this
315# string besides java UI toolkits; you can see several discussions on the
316# mailing lists, GitHub issues, and other WM documentation that suggest setting
317# this string if your java app doesn't work correctly. We may as well just lie
318# and say that we're a working one by default.
319#
320# We choose LG3D to maximize irony: it is a 3D non-reparenting WM written in
321# java that happens to be on java's whitelist.
322wmname = "LG3D"