summaryrefslogtreecommitdiff
path: root/config/qtile.org
diff options
context:
space:
mode:
Diffstat (limited to 'config/qtile.org')
-rw-r--r--config/qtile.org422
1 files changed, 422 insertions, 0 deletions
diff --git a/config/qtile.org b/config/qtile.org
new file mode 100644
index 0000000..83d0c8d
--- /dev/null
+++ b/config/qtile.org
@@ -0,0 +1,422 @@
+#+title: QTile Configuration
+#+author: Preston Pan
+#+description: My personal qtile configuration to be used with NixOS
+#+date: [2026-03-25 Wed]
+#+language: en
+
+#+OPTIONS: broken-links:t
+#+PROPERTY: header-args :tangle yes :comments link
+
+* Introduction
+This is a QTile configuration meant to be a monolithic configuration of QTile along with widgets i.e. run launcher, bar, and notification panel.
+This enables the window manager to be integrated with these things entirely, making for a unified experience in terms of configuration, styling,
+and functionality.
+
+This configuration imports ~WALLPAPER~ and ~SOUND~ from my [[file:./nix.org][NixOS Configuration]], and therefore if you use this standalone you must replace those variables.
+* Imports
+We start with imports:
+#+begin_src python :tangle ../nix/qtile/config.py
+from paths import WALLPAPER, SOUND
+from libqtile import bar, layout, widget, qtile
+from libqtile.config import Key, Group, Screen, Click, Drag, Match
+from libqtile.lazy import lazy
+from libqtile.backend.wayland import InputConfig
+from qtile_extras.layout.decorations import RoundedCorners
+
+import re
+#+end_src
+We're using wayland because it's better.
+* Data
+#+begin_src python :tangle ../nix/qtile/config.py
+mod = "mod4"
+terminal = "kitty"
+wallpaper = WALLPAPER
+
+colors = {
+ "rosewater": "#f5e0dc",
+ "flamingo": "#f2cdcd",
+ "pink": "#f5c2e7",
+ "mauve": "#cba6f7",
+ "red": "#f38ba8",
+ "maroon": "#eba0ac",
+ "peach": "#fab387",
+ "yellow": "#f9e2af",
+ "green": "#a6e3a1",
+ "teal": "#94e2d5",
+ "sky": "#89dceb",
+ "sapphire": "#74c7ec",
+ "blue": "#89b4fa",
+ "lavender": "#b4befe",
+ "text": "#cdd6f4",
+ "subtext1": "#bac2de",
+ "subtext0": "#a6adc8",
+ "overlay2": "#9399b2",
+ "overlay1": "#7f849c",
+ "overlay0": "#6c7086",
+ "surface2": "#585b70",
+ "surface1": "#45475a",
+ "surface0": "#313244",
+ "base": "#1e1e2e",
+ "mantle": "#181825",
+ "crust": "#11111b",
+}
+
+workspace_keys = {
+ "1": "1",
+ "2": "2",
+ "3": "3",
+ "4": "4",
+ "5": "5",
+ "6": "6",
+ "7": "7",
+ "8": "8",
+ "9": "9",
+}
+#+end_src
+* Config
+#+begin_src python :tangle ../nix/qtile/config.py
+groups = [
+ Group("1", matches=[Match(wm_class=re.compile(r"^emacs$", re.IGNORECASE))]),
+ Group("2", matches=[Match(wm_class=re.compile(r"(qutebrowser|org\.qutebrowser\.qutebrowser)", re.IGNORECASE))]),
+ Group(
+ "3",
+ matches=[
+ Match(wm_class=re.compile(r"^signal.*", re.IGNORECASE)),
+ Match(wm_class=re.compile(r"^element.*", re.IGNORECASE)),
+ ],
+ ),
+ Group("4", matches=[Match(wm_class=re.compile(r"(pavucontrol|org\.pulseaudio\.pavucontrol)", re.IGNORECASE))]),
+ Group("5"),
+ Group("6"),
+ Group("7"),
+ Group("8"),
+ Group("9"),
+]
+
+wl_input_rules = {
+ "type:keyboard": InputConfig(
+ kb_options="caps:escape",
+ kb_repeat_rate=50,
+ kb_repeat_delay=250,
+ ),
+
+ "type:pointer": InputConfig(
+ scroll_method="on_button_down",
+ scroll_button=276, # Your exact trackball button code
+ ),
+}
+
+class QuietBattery(widget.Battery):
+ def poll(self):
+ try:
+ status = self._battery.update_status()
+ except RuntimeError:
+ return ""
+ return self.build_string(status)
+
+def logout():
+ qtile.stop()
+
+
+def reboot():
+ qtile.spawn("systemctl reboot")
+
+
+def shutdown():
+ qtile.spawn("systemctl poweroff")
+
+
+def workspace_bindings():
+ bindings = []
+ for group_name, key_name in workspace_keys.items():
+ bindings.append(Key([mod], key_name, lazy.group[group_name].toscreen()))
+ bindings.append(Key([mod, "shift"], key_name, lazy.window.togroup(group_name)))
+ return bindings
+
+
+keys = [
+ # apps / session
+ Key([mod], "Return", lazy.spawn(terminal)),
+ Key([mod], "d", lazy.spawncmd()),
+ Key([mod], "q", lazy.window.kill()),
+ Key([mod], "f", lazy.window.toggle_fullscreen()),
+ Key([mod], "Tab", lazy.next_layout()),
+ Key([mod, "control"], "r", lazy.reload_config()),
+ Key([mod], "t", lazy.window.toggle_floating()),
+
+ # focus
+ Key([mod], "h", lazy.layout.left()),
+ Key([mod], "j", lazy.layout.down()),
+ Key([mod], "k", lazy.layout.up()),
+ Key([mod], "l", lazy.layout.right()),
+
+ # move windows
+ Key([mod, "shift"], "h", lazy.layout.shuffle_left()),
+ Key([mod, "shift"], "j", lazy.layout.shuffle_down()),
+ Key([mod, "shift"], "k", lazy.layout.shuffle_up()),
+ Key([mod, "shift"], "l", lazy.layout.shuffle_right()),
+
+ # resize windows
+ Key([mod, "control"], "h", lazy.layout.grow_left()),
+ Key([mod, "control"], "j", lazy.layout.grow_down()),
+ Key([mod, "control"], "k", lazy.layout.grow_up()),
+ Key([mod, "control"], "l", lazy.layout.grow_right()),
+ Key([mod], "n", lazy.layout.normalize()),
+
+ # layout helpers
+ Key([mod], "space", lazy.layout.next()),
+ Key([mod, "shift"], "space", lazy.layout.toggle_split()),
+
+ # session shortcuts
+ Key([mod, "shift"], "q", lazy.shutdown()),
+ Key([mod, "control"], "Delete", lazy.spawn("systemctl reboot")),
+ Key([mod, "shift"], "Delete", lazy.spawn("systemctl poweroff")),
+
+ # app launchers
+ Key([mod], "e", lazy.spawn("emacs")),
+ Key([mod], "w", lazy.spawn("qutebrowser")),
+ Key([mod], "c", lazy.spawn("signal-desktop")),
+ Key([mod], "v", lazy.spawn("element-desktop")),
+ Key([mod], "s", lazy.spawn("pavucontrol")),
+
+ Key([], "XF86AudioPlay", lazy.spawn("mpc toggle")),
+ Key([], "XF86AudioNext", lazy.spawn("mpc next")),
+ Key([], "XF86AudioPrev", lazy.spawn("mpc prev")),
+ Key([], "XF86AudioStop", lazy.spawn("mpc stop")),
+
+ Key([], "XF86AudioRaiseVolume", lazy.spawn("wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 5%+")),
+ Key([], "XF86AudioLowerVolume", lazy.spawn("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-")),
+ Key([], "XF86AudioMute", lazy.spawn("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle")),
+ Key([], "Print", lazy.spawn("sh -c 'grim ~/screenshot-$(date +%Y%m%d-%H%M%S).png'")),
+] + workspace_bindings()
+
+layouts = [
+ layout.Columns(
+ border_focus=colors["blue"],
+ border_normal=colors["surface0"],
+
+ border_focus_stack=colors["mauve"],
+ border_normal_stack=colors["surface1"],
+
+ border_width=3,
+ margin=8,
+ insert_position=1,
+ ),
+ layout.Max(
+ border_focus=colors["blue"],
+ border_normal=colors["surface0"],
+ border_width=3,
+ margin=8,
+ ),
+]
+
+widget_defaults = {
+ "font": "Iosevka Nerd Font",
+ "fontsize": 13,
+ "padding": 6,
+ "background": colors["mantle"],
+ "foreground": colors["text"],
+}
+extension_defaults = widget_defaults.copy()
+
+mouse = [
+ Drag(
+ [mod],
+ "Button1",
+ lazy.window.set_position_floating(),
+ start=lazy.window.get_position(),
+ ),
+ Drag(
+ [mod],
+ "Button3",
+ lazy.window.set_size_floating(),
+ start=lazy.window.get_size(),
+ ),
+ Click(
+ [mod],
+ "Button2",
+ lazy.window.bring_to_front(),
+ ),
+]
+
+
+def segment_icon(text, color, background=None, padding=8, font=None, fontsize=None):
+ return widget.TextBox(
+ text=text,
+ foreground=color,
+ background=background or colors["surface0"],
+ padding=padding,
+ font=font or "Iosevka Nerd Font",
+ fontsize=fontsize,
+ )
+
+
+def segment_sep(padding=6):
+ return widget.Sep(
+ linewidth=0,
+ padding=padding,
+ background=colors["mantle"],
+ )
+
+
+power_widget = widget.WidgetBox(
+ text_closed="󰐥",
+ text_open="󰐥",
+ close_button_location="right",
+ background=colors["mantle"],
+ font="Iosevka Nerd Font",
+ widgets=[
+ widget.TextBox(
+ text=" 󰑐 ",
+ foreground=colors["blue"],
+ background=colors["surface0"],
+ padding=8,
+ font="Iosevka Nerd Font",
+ mouse_callbacks={"Button1": reboot},
+ ),
+ widget.TextBox(
+ text=" 󰍃 ",
+ foreground=colors["mauve"],
+ background=colors["surface0"],
+ padding=8,
+ font="Iosevka Nerd Font",
+ mouse_callbacks={"Button1": logout},
+ ),
+ widget.TextBox(
+ text=" 󰐥 ",
+ foreground=colors["red"],
+ background=colors["surface0"],
+ padding=8,
+ font="Iosevka Nerd Font",
+ mouse_callbacks={"Button1": shutdown},
+ ),
+ ],
+)
+
+screens = [
+ Screen(
+ wallpaper=wallpaper,
+ wallpaper_mode="fill",
+ top=bar.Bar(
+ [
+ widget.GroupBox(
+ font="Iosevka Nerd Font",
+ fontsize=13,
+ background=colors["mantle"],
+ active=colors["text"],
+ inactive=colors["overlay0"],
+ highlight_method="line",
+ highlight_color=[colors["mantle"], colors["mantle"]],
+ this_current_screen_border=colors["lavender"],
+ other_current_screen_border=colors["blue"],
+ this_screen_border=colors["surface2"],
+ other_screen_border=colors["surface1"],
+ urgent_border=colors["red"],
+ urgent_text=colors["red"],
+ borderwidth=2,
+ rounded=False,
+ disable_drag=True,
+ spacing=8,
+ padding_x=8,
+ padding_y=5,
+ margin_y=2,
+ margin_x=0,
+ ),
+ widget.Spacer(length=10),
+ widget.Prompt(
+ name="prompt",
+ prompt="❯ ",
+ cursor_color=colors["blue"],
+ foreground=colors["text"],
+ background=colors["surface0"],
+ padding=10,
+ font="Iosevka Nerd Font",
+ ),
+ widget.Spacer(),
+
+ segment_icon("󰖙", colors["blue"]),
+ widget.Wttr(
+ background=colors["surface0"],
+ format="%l: %t %C",
+ update_interval=1800,
+ font="Iosevka Nerd Font",
+ foreground=colors["teal"],
+ ),
+ segment_sep(),
+
+ segment_icon("󰎆", colors["green"]),
+ widget.Mpd2(
+ background=colors["surface0"],
+ foreground=colors["green"],
+ status_format="{play_status} {artist} - {title}",
+ idle_format=" idle",
+ idle_message="idle",
+ max_chars=40,
+ padding=10,
+ hide_crash=True,
+ font="Iosevka Nerd Font",
+ ),
+ segment_sep(),
+
+ segment_icon("󰂄", colors["yellow"]),
+ QuietBattery(
+ background=colors["surface0"],
+ foreground=colors["yellow"],
+ format="{percent:2.0%}",
+ charge_char="󰂄",
+ discharge_char="󰁹",
+ full_char="󰁹",
+ empty_char="󰂎",
+ update_interval=30,
+ padding=10,
+ font="Iosevka Nerd Font",
+ ),
+ segment_sep(),
+
+ segment_icon("󰂚", colors["peach"]),
+ widget.Notify(
+ foreground=colors["peach"],
+ background=colors["surface0"],
+ default_timeout=10,
+ audiofile=SOUND,
+ padding=10,
+ font="Iosevka Nerd Font",
+ ),
+ segment_sep(),
+
+ segment_icon("󰃭", colors["lavender"]),
+ widget.Clock(
+ format="%a %d %b",
+ foreground=colors["lavender"],
+ background=colors["surface0"],
+ padding=10,
+ font="Lora",
+ ),
+ segment_icon("󰥔", colors["blue"]),
+ widget.Clock(
+ format="%H:%M",
+ foreground=colors["blue"],
+ background=colors["surface0"],
+ padding=10,
+ font="Iosevka Nerd Font",
+ ),
+
+ widget.Spacer(length=10),
+ power_widget,
+ widget.Spacer(length=10),
+ ],
+ 30,
+ margin=[8, 10, 0, 10],
+ background=colors["mantle"],
+ opacity=0.97,
+ ),
+ ),
+]
+
+follow_mouse_focus = True
+bring_front_click = False
+cursor_warp = False
+auto_fullscreen = True
+auto_minimize = True
+wmname = "Qtile"
+#+end_src