diff options
| author | Preston Pan <ret2pop@nullring.xyz> | 2026-03-25 20:06:26 -0700 |
|---|---|---|
| committer | Preston Pan <ret2pop@nullring.xyz> | 2026-03-25 20:06:26 -0700 |
| commit | d79e97256cb01e33c47822859e171161352fb7c9 (patch) | |
| tree | c7c03b4eae03d52923a21833920e1b1523a35af4 /config/qtile.org | |
| parent | 42656b6d8e9d433ee9a032605755679157980365 (diff) | |
add qtile configuration
Diffstat (limited to 'config/qtile.org')
| -rw-r--r-- | config/qtile.org | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/config/qtile.org b/config/qtile.org new file mode 100644 index 0000000..0f5c847 --- /dev/null +++ b/config/qtile.org @@ -0,0 +1,421 @@ +#+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. +* Config +#+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", +} + +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 |
