# -*- 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, widget, hook from libqtile.lazy import lazy from libqtile.utils import guess_terminal from typing import List # noqa: F401from typing import List # noqa: F401 from qtile_extras import widget from qtile_extras.widget.decorations import PowerLineDecoration from qutils import get_num_screens, get_network_interface, Colors mod = "mod4" # Sets mod key to SUPER/WINDOWS myTerm = "alacritty" # My terminal of choice myBrowser = "firefox" # My browser of choice keys = [ ### The essentials Key([mod], "Return", lazy.spawn(myTerm), desc='Launches My Terminal'), Key([mod, "shift"], "Return", lazy.spawn("rofi -show run"), desc='Run Launcher'), Key([mod], "b", lazy.spawn(myBrowser),desc='Qutebrowser'), Key([mod], "l", lazy.spawn("cinnamon-screensaver-command -a"), desc='Qutebrowser'), 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'), ### Switch focus of monitors Key([mod], "period", lazy.next_screen(), desc='Move focus to next monitor'), Key([mod], "comma", 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", layout='max', matches=[Match(wm_class=('microsoft teams - preview'))]), Group("WWW", layout='monadtall', matches=[Match(wm_class=['Firefox','firefox','firefox-bin','Chromium','Google-chrome','google-chrome'])]), Group("DEV", layout='max'), Group("SYS", layout='monadtall'), Group("REF", layout='monadtall'), Group("DOC", layout='monadtall', matches=[Match(wm_class=['obsidian'])]), Group("DMP", layout='monadtall')] # 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 from libqtile.dgroups import simple_key_binder 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('nnn', myTerm+' -e nnn -d', height=0.66, width=0.66, x=0.166, y=0.166), DropDown('sound', 'cinnamon-settings sound', 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('nnn')), Key([mod], 's', lazy.group['scratch'].dropdown_toggle('sound')), ]) layout_theme = {"border_width": 2, "margin": 8, "border_focus": Colors.green, "border_normal": Colors.grey } layouts = [ layout.MonadTall(**layout_theme), layout.MonadWide(**layout_theme), layout.Max(**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", # scale = "False", # mouse_callbacks = {'Button1': lambda: qtile.cmd_spawn(myTerm)} # ), 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, ), # UPowerWidget( # background = Colors.yellow, # foreground = Colors.fg, # **powerline, # ), widget.Battery( battery = 0, fmt = ' {}', charge_char = u'\uf583', discharge_char = u'\uf57d', empty_char = u'\uf582', full_char = u'\uf578', unknown_char = u'\uf590', format = '{char} {percent:2.0%} {hour:d}:{min:02d}', background = Colors.yellow, foreground = Colors.bg, **powerline, ), # widget.Battery( # battery = 1, # fmt = ' {}', # charge_char = u'\uf583', # discharge_char = u'\uf57d', # empty_char = u'\uf582', # full_char = u'\uf578', # unknown_char = u'\uf590', # format = '{char} {percent:2.0%} {hour:d}:{min:02d}', # background = Colors.yellow, # foreground = Colors.bg, # ), widget.ThermalSensor( foreground = Colors.bg, background = Colors.orange, threshold = 90, fmt = '\uf8c7 {}', **powerline, ), widget.CheckUpdates( update_interval = 1800, distro = "Mint", custom_command = "aptitude search '~U'", markup = False, display_format = "\uf546 {updates}", foreground = Colors.bg, colour_have_updates = Colors.bg, colour_no_updates = Colors.bg, # mouse_callbacks = {'Button1': lambda: qtile.cmd_spawn(myTerm + ' -e sudo apt upgrade')}, background = Colors.red, **powerline, ), widget.Memory( foreground = Colors.bg, background = Colors.purple, mouse_callbacks = {'Button1': lambda: qtile.cmd_spawn(myTerm + ' -e htop')}, fmt = '{}', format = '\uf85a{MemPercent:5.1f} %', **powerline, ), widget.CPU( foreground = Colors.bg, background = Colors.blue, fmt = '{}', format = '\ufb19{load_percent:5.1f}%', **powerline, ), widget.Net( # bash script to get the active network interface: ip interface = get_network_interface(), format = '{down} ↓↑ {up}', 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 ), ] return widgets_list def init_widgets_screen1(): widgets_screen1 = init_widgets_list() del widgets_screen1[7:8] # Slicing removes unwanted widgets (systray) on Monitors 1,3 del widgets_screen1[4:5] # Slicing removes unwanted widgets (prompt) on Monitors 1,3 return widgets_screen1 def init_widgets_screen2(): widgets_screen2 = init_widgets_list() return widgets_screen2 # Monitor 2 will display all widgets in widgets_list def init_screens(): num_screens = get_num_screens() if num_screens <= 1: return [Screen(top=bar.Bar(widgets=init_widgets_screen2(), opacity=1.0, size=20))] elif num_screens == 2: return [ Screen(top=bar.Bar(widgets=init_widgets_screen1(), opacity=1.0, size=20)), Screen(top=bar.Bar(widgets=init_widgets_screen2(), opacity=1.0, size=20)), ] else: return [ Screen(top=bar.Bar(widgets=init_widgets_screen1(), opacity=1.0, size=20)), Screen(top=bar.Bar(widgets=init_widgets_screen2(), opacity=1.0, size=20)), Screen(top=bar.Bar(widgets=init_widgets_screen1(), opacity=1.0, size=20)), ] if __name__ in ["config", "__main__"]: screens = init_screens() widgets_list = init_widgets_list() widgets_screen1 = init_widgets_screen1() widgets_screen2 = init_widgets_screen2() 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']) # 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. wmname = "LG3D"