# -*- 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 = "alacritty" 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='Qutebrowser'), 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'), ] groups = [Group("CHT", matches=[Match(wm_class=('microsoft teams - preview'))]), Group("WWW", matches=[Match(wm_class=['Firefox', 'firefox', 'firefox-bin', 'Chromium', 'Google-chrome', 'google-chrome'])]), Group("DEV"), Group("SYS"), Group("REF"), Group("DOC", matches=[Match(wm_class=['obsidian'])]), Group("DMP")] # 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=u'\ue73c', foreground=Colors.fg, fontsize=22, padding=12, # mouse_callbacks={'Button1': lambda: qtile.cmd_spawn(myTerm)} ), widget.GroupBox( 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, 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_screen1 = init_widgets_list() del widgets_screen1[7:8] # Slicing removes (systray) on Monitors 1,3 del widgets_screen1[4:5] # Slicing removes (prompt) on Monitors 1,3 return widgets_screen1 def init_widgets_screen_main(): widgets_screen2 = init_widgets_list() return widgets_screen2 # 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(1, 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.