# -*- coding: utf-8 -*- import os import re import socket import subprocess from libqtile import qtile from libqtile.config import ( Click, Drag, Group, KeyChord, Key, Match, Screen, ScratchPad, DropDown, ) # from libqtile.command import lazy from libqtile import layout, bar, hook # ,widget from libqtile.lazy import lazy # from libqtile.utils import guess_terminal from libqtile.dgroups import simple_key_binder # from typing import List from qtile_extras import widget from qtile_extras.widget import UPowerWidget from qtile_extras.widget.decorations import PowerLineDecoration from qutils import get_num_screens, get_network_interface, get_batteries, Colors mod = "mod4" # Sets mod key to SUPER/WINDOWS myTerm = "wezterm" myBrowser = "firefox" myExplorer = "thunar" sound_ctrl = "pavucontrol" update_distro_key = "Ubuntu" bt_ctrl = "blueman-manager" keys = [ # ## The essentials Key([mod], "Return", lazy.spawn(myTerm), desc="Launches My Terminal"), Key([mod], "space", lazy.spawn("rofi -show run"), desc="Run Launcher"), Key([mod], "b", lazy.spawn(myBrowser), desc="Web Browser"), Key([mod], "e", lazy.spawn(myExplorer), desc="File Explorer"), Key([mod], "l", lazy.spawn("xflock4"), desc="Screen Lock"), Key([mod], "Tab", lazy.next_layout(), desc="Toggle through layouts"), Key([mod, "shift"], "c", lazy.window.kill(), desc="Kill active window"), Key([mod, "shift"], "r", lazy.restart(), desc="Restart Qtile"), Key([mod, "shift"], "q", lazy.shutdown(), desc="Shutdown Qtile"), Key( [mod, "shift"], "p", lazy.spawn( """rofi -show p -modi p:'rofi-power-menu \\ --symbols-font \"Symbols Nerd Font Mono\" \\ --choices=shutdown/reboot/suspend/logout' \\ -theme-str 'window {width: 12em;} listview {lines: 4;}'""" ), desc="Run Shutdown Menu", ), Key([mod], "period", lazy.spawn("rofimoji"), desc="Emoji Picker"), Key( [mod], "Print", lazy.spawn("flameshot gui"), desc="Summon the screenshot tool." ), # ## Switch focus of monitors Key( [mod, "control"], "Right", lazy.next_screen(), desc="Move focus to next monitor" ), Key( [mod, "control"], "Left", lazy.prev_screen(), desc="Move focus to prev monitor" ), # ## Window controls Key([mod], "Up", lazy.layout.up(), desc="Move focus up"), Key([mod], "Down", lazy.layout.down(), desc="Move focus down"), Key([mod], "Left", lazy.layout.left(), desc="Move focus left"), Key([mod], "Right", lazy.layout.right(), desc="Move focus right"), Key( [mod, "shift"], "Up", lazy.layout.shuffle_up(), lazy.layout.section_up(), desc="Move windows up in current stack", ), Key( [mod, "shift"], "Down", lazy.layout.shuffle_down(), lazy.layout.section_down(), desc="Move windows down in current stack", ), Key([mod, "shift"], "Left", lazy.layout.shuffle_left(), desc="Move windows left"), Key( [mod, "shift"], "Right", lazy.layout.shuffle_right(), desc="Move windows right" ), Key( [mod], "minus", lazy.layout.shrink(), lazy.layout.decrease_nmaster(), desc="Shrink window (MonadTall), decrease number in master pane (Tile)", ), Key( [mod], "equal", lazy.layout.grow(), lazy.layout.increase_nmaster(), desc="Expand window (MonadTall), increase number in master pane (Tile)", ), # Grow windows. If current window is on the edge of screen and direction # will be to screen edge - window would shrink. # Key([mod, "control"], "Up", lazy.layout.grow_up(), desc="Grow window up"), # Key([mod, "control"], "Down", lazy.layout.grow_down(), desc="Grow window down"), # Key([mod, "control"], "Left", lazy.layout.grow_left(), desc="Grow window to the left"), # Key([mod, "control"], "Right", lazy.layout.grow_right(), desc="Grow window to the right"), Key([mod], "n", lazy.layout.normalize(), desc="normalize window size ratios"), Key( [mod], "m", lazy.layout.maximize(), desc="toggle window between minimum and maximum sizes", ), Key([mod, "shift"], "f", lazy.window.toggle_floating(), desc="toggle floating"), Key([mod], "f", lazy.window.toggle_fullscreen(), desc="toggle fullscreen"), # ## Stack controls Key( [mod, "shift"], "Tab", lazy.layout.rotate(), lazy.layout.flip(), desc="Switch which side main pane occupies (XmonadTall)", ), # Key([mod], "space", lazy.layout.next(), desc='Switch window focus to other pane(s) of stack'), # Key([mod, "shift"], "space", lazy.layout.toggle_split(), # desc='Toggle between split and unsplit sides of stack'), ] matchers = { "browser": Match( wm_class=re.compile( r"^(Firefox|firefox|firefox\-bin|Chromium|Google\-chrome|google\-chrome)$" ) ), "pkm": Match(wm_class=re.compile(r"^(obsidian)$")), } groups = [ Group("CHT"), Group("WWW", matches=[matchers["browser"]]), Group("DEV"), Group("SYS"), Group("REF"), Group("DOC", matches=[matchers["pkm"]]), Group("-7-"), Group("-8-"), Group("-9-"), Group("-0-"), ] # Allow MODKEY+[0 through 9] to bind to groups, see https://docs.qtile.org/en/stable/manual/config/groups.html # MOD4 + index Number : Switch to Group[index] # MOD4 + shift + index Number : Send active window to another Group dgroups_key_binder = simple_key_binder("mod4") groups.append( ScratchPad( "scratch", [ DropDown("term", myTerm, height=0.66, width=0.66, x=0.166, y=0.166), DropDown( "qalc", myTerm + " -e qalc", height=0.66, width=0.33, x=0.33, y=0.166 ), # DropDown('file', myExplorer, height=0.66, width=0.66, x=0.166, y=0.166), DropDown("sound", sound_ctrl, height=0.66, width=0.50, x=0.25, y=0.166), DropDown("bluetooth", bt_ctrl, height=0.66, width=0.50, x=0.25, y=0.166), ], ), ) keys.extend( [ Key([mod], "q", lazy.group["scratch"].dropdown_toggle("qalc")), Key([mod], "w", lazy.group["scratch"].dropdown_toggle("term")), # Key([mod], 'e', lazy.group['scratch'].dropdown_toggle('file')), Key([mod], "s", lazy.group["scratch"].dropdown_toggle("sound")), Key([mod], "d", lazy.group["scratch"].dropdown_toggle("bluetooth")), ] ) layout_theme = { "border_width": 2, "margin": 8, "border_focus": Colors.green, "border_normal": Colors.grey, "ratio": 0.6180469715698392, "new_client_position": "bottom", } layouts = [ layout.MonadTall(**layout_theme), layout.MonadWide(**layout_theme), layout.Max(**layout_theme), # layout.MonadThreeCol(main_centered=False, **layout_theme), # layout.RatioTile(**layout_theme), # layout.TreeTab( # font = "Ubuntu", # fontsize = 10, # # sections = ["FIRST", "SECOND", "THIRD", "FOURTH"], # section_fontsize = 10, # border_width = 2, # bg_color = Colors.bg, # active_bg = Colors.green, # active_fg = Colors.bg, # inactive_bg = Colors.grey, # inactive_fg = Colors.bg, # padding_left = 0, # padding_x = 0, # padding_y = 5, # section_top = 10, # section_bottom = 20, # level_shift = 8, # vspace = 3, # panel_width = 150 # ), # layout.Floating(**layout_theme) ] prompt = "{0}@{1}: ".format(os.environ["USER"], socket.gethostname()) # #### DEFAULT WIDGET SETTINGS ##### widget_defaults = dict( font="FiraCode Nerd Font Bold", fontsize=11, padding=0, background=Colors.bg ) extension_defaults = widget_defaults.copy() def init_widgets_list(): powerline = {"decorations": [PowerLineDecoration(path="back_slash")]} widgets_list = [ # widget.Image(filename = "~/.config/qtile/icons/python-white.png"), widget.TextBox( text="\ue73c", foreground=Colors.fg, fontsize=22, padding=12, # mouse_callbacks={'Button1': lambda: qtile.cmd_spawn(myTerm)} ), widget.GroupBox( disable_drag=True, font="Ubuntu Bold", fontsize=9, margin_y=3, margin_x=0, padding_y=5, padding_x=3, borderwidth=3, active=Colors.fg, inactive=Colors.grey, rounded=False, hide_unused=True, highlight_color=Colors.orange, highlight_method="line", this_current_screen_border=Colors.blue, other_screen_border=Colors.grey, this_screen_border=Colors.blue, other_current_screen_border=Colors.grey, foreground=Colors.fg, background=Colors.bg, ), widget.Sep(foreground=Colors.red, padding=8), widget.CurrentLayoutIcon( # custom_icon_paths=[os.path.expanduser("~/.config/qtile/icons")], foreground=Colors.red, background=Colors.bg, padding=0, scale=0.7, ), widget.Prompt(), widget.Sep(foreground=Colors.red, padding=8), widget.WindowName( fontsize=10, foreground=Colors.yellow, background=Colors.bg, padding=0, **powerline, ), widget.Systray( background=Colors.bg1, padding=5, **powerline, ), widget.ThermalSensor( foreground=Colors.bg, background=Colors.orange, threshold=90, fmt="T {}", **powerline, ), widget.CheckUpdates( update_interval=1800, distro=update_distro_key, markup=False, display_format="apt {updates}", foreground=Colors.bg, colour_have_updates=Colors.bg, colour_no_updates=Colors.bg, background=Colors.red, **powerline, ), widget.Memory( foreground=Colors.bg, background=Colors.purple, mouse_callbacks={"Button1": lambda: qtile.cmd_spawn(myTerm + " -e htop")}, fmt="{}", format="M {MemPercent:5.1f}%", **powerline, ), widget.CPU( foreground=Colors.bg, background=Colors.blue, fmt="{}", format="C {load_percent:5.1f}", **powerline, ), widget.Net( interface=get_network_interface(), format="{down:6.2f} ↓↑ {up:6.2f}", prefix="M", foreground=Colors.bg, background=Colors.aqua, **powerline, ), widget.Clock( foreground=Colors.bg, background=Colors.green, format="%Y-%m-%d %a %H:%M ", padding=5, ), ] upw_kwargs = { "background": Colors.yellow, "foreground": Colors.bg, "border_colour": Colors.bg, "border_critical_colour": Colors.red, "border_charge_colour": Colors.blue, "fill_critical": Colors.red, "fill_low": Colors.red, "fill_normal": Colors.bg2, "text_charging": "({percentage:.0f}%) {ttf}", "text_discharging": "({percentage:.0f}%) {tte}", "spacing": 10, } upw_kwargs.update(powerline) widgets_list[8:8] = [ UPowerWidget(battery_name=battery, **upw_kwargs) for battery in get_batteries() ] return widgets_list def init_widgets_screen_aux(): widgets_screen = init_widgets_list() del widgets_screen[7:8] # Slicing removes (systray) on Monitors 1,3 del widgets_screen[4:5] # Slicing removes (prompt) on Monitors 1,3 return widgets_screen def init_widgets_screen_main(): widgets_screen = init_widgets_list() return widgets_screen # display all widgets in widgets_list def init_screens(): num_screens = get_num_screens() main = Screen(top=bar.Bar(widgets=init_widgets_screen_main(), opacity=1.0, size=20)) if num_screens <= 1: screens = [main] else: screens = [ Screen(top=bar.Bar(widgets=init_widgets_screen_aux(), opacity=1.0, size=20)) for _ in range(num_screens - 1) ] screens.insert(0, main) return screens if __name__ in ["config", "__main__"]: screens = init_screens() widgets_list = init_widgets_list() widgets_screen1 = init_widgets_screen_aux() widgets_screen2 = init_widgets_screen_main() def window_to_prev_group(qtile): if qtile.currentWindow is not None: i = qtile.groups.index(qtile.currentGroup) qtile.currentWindow.togroup(qtile.groups[i - 1].name) def window_to_next_group(qtile): if qtile.currentWindow is not None: i = qtile.groups.index(qtile.currentGroup) qtile.currentWindow.togroup(qtile.groups[i + 1].name) def window_to_previous_screen(qtile): i = qtile.screens.index(qtile.current_screen) if i != 0: group = qtile.screens[i - 1].group.name qtile.current_window.togroup(group) def window_to_next_screen(qtile): i = qtile.screens.index(qtile.current_screen) if i + 1 != len(qtile.screens): group = qtile.screens[i + 1].group.name qtile.current_window.togroup(group) def switch_screens(qtile): i = qtile.screens.index(qtile.current_screen) group = qtile.screens[i - 1].group qtile.current_screen.set_group(group) 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()), ] dgroups_app_rules = [] # type: List follow_mouse_focus = True bring_front_click = False cursor_warp = False floating_layout = layout.Floating( float_rules=[ # Run the utility of `xprop` to see the wm class and name of an X client. # default_float_rules include: utility, notification, toolbar, splash, dialog, # file_progress, confirm, download and error. *layout.Floating.default_float_rules, Match(title="Confirmation"), # tastyworks exit box Match(title="Qalculate!"), # qalculate-gtk Match(wm_class="kdenlive"), # kdenlive Match(wm_class="pinentry-gtk-2"), # GPG key password entry ] ) auto_fullscreen = True focus_on_window_activation = "smart" reconfigure_screens = True # If things like steam games want to auto-minimize themselves when losing # focus, should we respect this or not? auto_minimize = True @hook.subscribe.startup_once def start_once(): home = os.path.expanduser("~") subprocess.call([home + "/.config/qtile/up.sh"]) wmname = "LG3D" # XXX: Gasp! We're lying here. In fact, nobody really uses or cares about this # string besides java UI toolkits; you can see several discussions on the # mailing lists, GitHub issues, and other WM documentation that suggest setting # this string if your java app doesn't work correctly. We may as well just lie # and say that we're a working one by default. # # We choose LG3D to maximize irony: it is a 3D non-reparenting WM written in # java that happens to be on java's whitelist.