Created
March 21, 2022 19:49
-
-
Save xtalax/bd2d1a4237fb2181f436e41467c9f358 to your computer and use it in GitHub Desktop.
qtile config
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright (c) 2010 Aldo Cortesi | |
# Copyright (c) 2010, 2014 dequis | |
# Copyright (c) 2012 Randall Ma | |
# Copyright (c) 2012-2014 Tycho Andersen | |
# Copyright (c) 2012 Craig Barnes | |
# Copyright (c) 2013 horsik | |
# Copyright (c) 2013 Tao Sauvage | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining a copy | |
# of this software and associated documentation files (the "Software"), to deal | |
# in the Software without restriction, including without limitation the rights | |
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
# copies of the Software, and to permit persons to whom the Software is | |
# furnished to do so, subject to the following conditions: | |
# | |
# The above copyright notice and this permission notice shall be included in | |
# all copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
# SOFTWARE. | |
from typing import List # noqa: F401 | |
from libqtile import qtile | |
from libqtile import bar, layout, widget | |
from libqtile.config import Click, Drag, Group, Key, Match, Screen, DropDown, ScratchPad | |
from libqtile.layout.floating import Floating | |
from libqtile.lazy import lazy | |
# from libqtile.utils import guess_terminal | |
from libqtile import hook | |
# from libqtile.command import lazy | |
from datetime import datetime as dt | |
import os | |
import subprocess | |
import time | |
# from libqtile.utils import send_notification | |
from libqtile.log_utils import logger | |
# Get the number of connected screens | |
def get_monitors(): | |
xr = subprocess.check_output('xrandr --query | grep " connected"', shell=True).decode().split('\n') | |
monitors = len(xr) - 1 if len(xr) > 2 else len(xr) | |
return monitors | |
monitors = get_monitors() | |
# Run autorandr --change and restart Qtile on screen change | |
@hook.subscribe.startup_once | |
def autostart(): | |
# home = os.path.expanduser('~') | |
subprocess.Popen([home + '/.config/qtile/autostart.sh']) | |
# Add th, nd or st to the date - use custom_date in text box | |
def suffix(d): | |
return 'th' if 11 <= d <= 13 else {1: 'st', 2: 'nd', 3: 'rd'}.get(d % 10, 'th') | |
def custom_strftime(format, t): | |
return t.strftime(format).replace('{S}', str(t.day) + suffix(t.day)) | |
def custom_date(): | |
return custom_strftime('%A {S} %B %Y - %H:%M', dt.now()) | |
mod = "mod4" | |
terminal = 'alacritty' | |
home = os.path.expanduser('~') | |
MYCOLORS = [ | |
'#073642', | |
'#dc322f', | |
'#00ff2a', | |
'#b58900', | |
'#268bd2', | |
'#d33682', | |
'#2aa198', | |
'#eee8d5' | |
] | |
BLACK = MYCOLORS[0] | |
RED = MYCOLORS[1] | |
GREEN = MYCOLORS[2] | |
YELLOW = MYCOLORS[3] | |
BLUE = MYCOLORS[4] | |
MAGENTA = MYCOLORS[5] | |
CYAN = MYCOLORS[6] | |
WHITE = MYCOLORS[7] | |
keys = [ | |
Key([mod], "g", | |
lazy.screen.next_group(skip_empty=True), | |
desc="Move to next active group" | |
), | |
Key([mod, "shift"], "g", | |
lazy.screen.prev_group(skip_empty=True), | |
desc="Move to previous active group" | |
), | |
# Switch between windows in current stack pane | |
Key([mod], "k", | |
lazy.layout.down(), | |
desc="Move focus down in stack pane" | |
), | |
Key([mod], "j", | |
lazy.layout.up(), | |
desc="Move focus up in stack pane" | |
), | |
Key([mod, "shift"], "k", | |
lazy.layout.shuffle_down(), | |
desc='Shuffle down' | |
), | |
Key([mod, "shift"], "j", | |
lazy.layout.shuffle_up(), | |
desc='Shuffle up' | |
), | |
Key([mod, "shift"], "h", | |
lazy.layout.shuffle_left(), | |
desc='Shuffle left' | |
), | |
Key([mod, "shift"], "l", | |
lazy.layout.shuffle_right(), | |
desc='Shuffle right' | |
), | |
Key([mod, "mod1"], "j", | |
lazy.layout.flip_down(), | |
desc='Flip down' | |
), | |
Key([mod, "mod1"], "k", | |
lazy.layout.flip_up(), | |
desc='Flip up' | |
), | |
Key([mod, "mod1"], "h", | |
lazy.layout.flip_left(), | |
desc='Flip left' | |
), | |
Key([mod, "mod1"], "l", | |
lazy.layout.flip_right(), | |
desc='Flip right' | |
), | |
Key([mod, "control"], "j", | |
lazy.layout.grow_down(), | |
desc='Grow down' | |
), | |
Key([mod, "control"], "k", | |
lazy.layout.grow_up(), | |
desc='Grow up' | |
), | |
Key([mod, "control"], "h", | |
lazy.layout.grow_left(), | |
desc='Grow left' | |
), | |
Key([mod, "control"], "l", | |
lazy.layout.grow_right(), | |
desc='Grow 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], "h", | |
lazy.layout.grow(), | |
lazy.layout.increase_nmaster(), | |
desc='Expand window (MonadTall), increase number in master pane (Tile)' | |
), | |
Key([mod], "l", | |
lazy.layout.shrink(), | |
lazy.layout.decrease_nmaster(), | |
desc='Shrink window (MonadTall), decrease number in master pane (Tile)' | |
), | |
# Toggle floating | |
Key([mod, "shift"], "f", lazy.window.toggle_floating(), | |
desc="Toggle floating" | |
), | |
# Toggle Fullscreen | |
Key([mod], "f", | |
lazy.window.toggle_fullscreen(), | |
lazy.hide_show_bar(position='all'), | |
desc='Toggle fullscreen and the bars' | |
), | |
# Switch window focus to other pane(s) of stack | |
Key([mod], "space", lazy.layout.next(), | |
desc="Switch window focus to other pane(s) of stack" | |
), | |
# Swap panes of split stack | |
Key([mod, "shift"], "space", | |
lazy.layout.rotate(), | |
desc="Swap panes of split stack" | |
), | |
# Toggle between split and unsplit sides of stack. | |
# Split = all windows displayed | |
# Unsplit = 1 window displayed, like Max layout, but still with | |
# multiple stack panes | |
Key([mod, "shift"], "Return", | |
lazy.layout.toggle_split(), | |
desc="Toggle between split and unsplit sides of stack" | |
), | |
# Launch programs | |
Key([mod], "t", | |
lazy.spawn(terminal), | |
desc="Launch terminal" | |
), | |
Key([mod], "c", | |
lazy.spawn("code"), | |
desc="Launch vscode" | |
), | |
Key([mod], "b", | |
lazy.spawn("vivaldi-stable"), | |
desc="Launch vivaldi" | |
), | |
# Toggle between different layouts as defined below | |
Key([mod], "Tab", | |
lazy.next_layout(), | |
desc="Toggle between layouts" | |
), | |
Key([mod], "w", | |
lazy.window.kill(), | |
desc="Kill focused window" | |
), | |
# Toggle bars | |
Key([mod], p, | |
lazy.hide_show_bar(position='all'), | |
desc="Toggle bars" | |
), | |
# Qtile system keys | |
Key([mod, "control"], "l", | |
lazy.spawn("betterlockscreen -l"), | |
desc="Lock screen" | |
), | |
Key([mod, "control"], "r", | |
lazy.restart(), | |
desc="Restart qtile" | |
), | |
Key([mod, "control"], "q", | |
lazy.shutdown(), | |
desc="Shutdown qtile" | |
), | |
Key([mod], "r", | |
lazy.spawncmd(), | |
desc="Spawn a command using a prompt widget" | |
), | |
Key([mod, "control"], "p", | |
lazy.spawn("" + home + "/.local/bin/powermenu"), | |
desc="Launch Power menu" | |
), | |
# Rofi | |
Key([mod], "Return", | |
lazy.spawn("rofi -show drun"), | |
desc="Launch Rofi menu" | |
), | |
# Cycle through windows in the floating layout | |
Key([mod, "shift"], "i", | |
lazy.window.toggle_minimize(), | |
lazy.group.next_window(), | |
lazy.window.bring_to_front() | |
), | |
# ------------ Hardware Configs ------------ | |
# Volume | |
Key([], "XF86AudioMute", | |
lazy.spawn(home + "/.local/bin/statusbar/volumecontrol mute"), | |
desc='Mute audio' | |
), | |
Key([], "XF86AudioLowerVolume", | |
lazy.spawn(home + "/.local/bin/statusbar/volumecontrol down"), | |
desc='Volume down' | |
), | |
Key([], "XF86AudioRaiseVolume", | |
lazy.spawn(home + "/.local/bin/statusbar/volumecontrol up"), | |
desc='Volume up' | |
), | |
# Media keys | |
Key([], "XF86AudioPlay", | |
lazy.spawn("dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify " "/org/mpris/MediaPlayer2 " "org.mpris.MediaPlayer2.Player.PlayPause"), | |
desc='Audio play' | |
), | |
Key([], "XF86AudioNext", | |
lazy.spawn("dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify " "/org/mpris/MediaPlayer2 " "org.mpris.MediaPlayer2.Player.Next"), | |
desc='Audio next' | |
), | |
Key([], "XF86AudioPrev", | |
lazy.spawn("dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify " "/org/mpris/MediaPlayer2 " "org.mpris.MediaPlayer2.Player.Previous"), | |
desc='Audio previous' | |
), | |
# Brightness | |
Key([], "XF86MonBrightnessDown", | |
lazy.spawn(home + "/.local/bin/statusbar/brightnesscontrol down"), | |
desc='Brightness down' | |
), | |
Key([], "XF86MonBrightnessUp", | |
lazy.spawn(home + "/.local/bin/statusbar/brightnesscontrol up"), | |
desc='Brightness up' | |
), | |
# Screenshots | |
# Save screen to clipboard | |
Key([], "Print", | |
lazy.spawn("/usr/bin/escrotum -C"), | |
desc='Save screen to clipboard' | |
), | |
# Save screen to screenshots folder | |
Key([mod], "Print", | |
lazy.spawn("/usr/bin/escrotum " + home + "/Pictures/Screenshots/screenshot_%d_%m_%Y_%H_%M_%S.png"), | |
desc='Save screen to screenshots folder' | |
), | |
# Capture region of screen to clipboard | |
Key([mod, "shift"], "s", | |
lazy.spawn("/usr/bin/escrotum -Cs"), | |
desc='Capture region of screen to clipboard' | |
), | |
] | |
# Groups with matches | |
workspaces = [ | |
{"name": " ₁", "key": "1", "matches": [Match(wm_class='firefox')], "layout": "columns"}, | |
{"name": " ₂", "key": "2", "matches": [Match(wm_class='alacritty'), Match(wm_class='ranger')], "layout": "columns"}, | |
{"name": " ₃", "key": "3", "matches": [Match(wm_class='vim')], "layout": "columns"}, | |
{"name": " ₄", "key": "4", "matches": [Match(wm_class='telegram-desktop'), Match(wm_class='weechat')], "layout": "columns"}, | |
{"name": " ₅", "key": "5", "matches": [Match(wm_class='gimp-2.10')], "layout": "columns"}, | |
{"name": "阮 ₆", "key": "6", "matches": [Match(wm_class='spotify')], "layout": "columns"}, | |
{"name": " ₇", "key": "7", "matches": [Match(wm_class='libreoffice')], "layout": "columns"}, | |
{"name": " ₈", "key": "8", "matches": [Match(wm_class='newsboat')], "layout": "columns"}, | |
{"name": " ₉", "key": "9", "matches": [Match(wm_class='neomutt')], "layout": "columns"}, | |
] | |
groups = [] | |
for workspace in workspaces: | |
matches = workspace["matches"] if "matches" in workspace else None | |
layouts = workspace["layout"] if "layout" in workspace else None | |
groups.append(Group(workspace["name"], matches=matches, layout=layouts)) | |
keys.append(Key([mod], workspace["key"], lazy.group[workspace["name"]].toscreen())) | |
keys.append(Key([mod, "control"], workspace["key"], lazy.window.togroup(workspace["name"]))) | |
# Dropdowns | |
#groups.append(DropDown("term", "alacritty", opacity=0.8)) | |
#keys.extend([ | |
# Key([], 'F12', lazy.group['scratchpad'].dropdown_toggle('term')) | |
#]) | |
# Move window to screen with Mod, Alt and number | |
for i in range(monitors): | |
keys.extend([Key([mod, "mod1"], str(i), lazy.window.toscreen(i))]) | |
# DEFAULT THEME SETTINGS FOR LAYOUTS # | |
layout_theme = {"border_width": 3, | |
"margin": 16, | |
"border_focus": BLUE, | |
"border_normal": BLACK | |
} | |
layouts = [ | |
layout.Columns(**layout_theme, num_columns=3), | |
layout.MonadTall(**layout_theme, single_border_width=0), | |
layout.Stack(num_stacks=2, **layout_theme), | |
# layout.Max(), | |
# Try more layouts by unleashing below layouts. | |
layout.Bsp(**layout_theme), | |
layout.Floating(**layout_theme), | |
# layout.Matrix(), | |
# layout.MonadWide(), | |
# layout.RatioTile(), | |
# layout.Tile(), | |
# layout.TreeTab(), | |
# layout.VerticalTile(), | |
# layout.Zoomy(), | |
] | |
widget_defaults = dict( | |
font='FiraCode Nerd Font Regular', | |
fontsize='12', | |
padding=2, | |
) | |
extension_defaults = widget_defaults.copy() | |
screens = [] | |
for monitor in range(monitors): | |
if monitor == 0: | |
screens.append( | |
Screen( | |
top=bar.Bar( | |
[ | |
widget.Spacer(length=10), | |
widget.GroupBox(borderwidth=2, inactive='969696', this_current_screen_border='eee8d5', this_screen_border='eee8d5', font='FiraCode Nerd Font', fontsize=18, highlight_method='line', highlight_color=['00000000', '00000000']), | |
widget.CurrentLayoutIcon(scale=0.7), | |
widget.CurrentLayout(**widget_defaults), | |
widget.Prompt(**widget_defaults), | |
widget.Spacer(), | |
widget.GenPollText(func=custom_date, update_interval=1, **widget_defaults, mouse_callbacks={'Button1': lambda: qtile.cmd_spawn(os.path.expanduser("~/.local/bin/statusbar/calendar.sh show"), shell=True), 'Button3': lambda: qtile.cmd_spawn(os.path.expanduser("~/.local/bin/statusbar/calendar.sh edit"), shell=True)}), | |
widget.Spacer(), | |
widget.CheckUpdates( | |
**widget_defaults, | |
update_interval=1800, | |
distro='Arch_yay', | |
custom_command='checkupdates;paru -Qum', | |
display_format=' {updates}', | |
colour_have_updates=GREEN, | |
execute='alacritty -e paru', | |
), | |
widget.Mpris2( | |
name='spotify', | |
objname="org.mpris.MediaPlayer2.spotify", | |
display_metadata=['xesam:title', 'xesam:artist'], | |
scroll_chars=None, | |
stop_pause_text='', | |
**widget_defaults | |
), | |
widget.Systray(), | |
widget.CheckUpdates( | |
**widget_defaults, | |
no_update_string='0', | |
display_format='{updates}', | |
update_interval=600, | |
custom_command='checkupdates', | |
), | |
widget.Spacer(length=5), | |
widget.Memory( | |
**widget_defaults, | |
mouse_callbacks={'Button1': lambda qtile: qtile.cmd_spawn( | |
self.termite + ' -e htop')}, | |
), | |
widget.Spacer(length=5), | |
widget.GenPollText(update_interval=1, **widget_defaults, func=lambda: subprocess.check_output(os.path.expanduser("~/.local/bin/statusbar/brightnesscontrol")).decode(), mouse_callbacks={'Button1': lambda: qtile.cmd_spawn(os.path.expanduser("~/.local/bin/statusbar/brightnesscontrol down"), shell=True), 'Button3': lambda: qtile.cmd_spawn(os.path.expanduser("~/.local/bin/statusbar/brightnesscontrol up"), shell=True)}), | |
widget.Spacer(length=5), | |
widget.GenPollText(update_interval=1, **widget_defaults, func=lambda: subprocess.check_output(os.path.expanduser("~/.local/bin/statusbar/volumecontrol")).decode(), mouse_callbacks={'Button1': lambda: qtile.cmd_spawn(os.path.expanduser("~/.local/bin/statusbar/volumecontrol down"), shell=True), 'Button2': lambda: qtile.cmd_spawn(os.path.expanduser("~/.local/bin/statusbar/volumecontrol mute"), shell=True), 'Button3': lambda: qtile.cmd_spawn(os.path.expanduser("~/.local/bin/statusbar/volumecontrol up"), shell=True)}), | |
widget.Spacer(length=5), | |
widget.GenPollText(update_interval=1, **widget_defaults, func=lambda: subprocess.check_output(os.path.expanduser("~/.local/bin/statusbar/network.sh")).decode(), mouse_callbacks={'Button1': lambda: qtile.cmd_spawn(os.path.expanduser("~/.local/bin/statusbar/network.sh ShowInfo"), shell=True), 'Button3': lambda: qtile.cmd_spawn(terminal + ' -e nmtui', shell=True)}), | |
widget.Spacer(length=10), | |
], | |
28, background="#000000AA", margin=[10, 16, 0, 16] # N E S W | |
), | |
) | |
) | |
else: | |
screens.append( | |
Screen( | |
top=bar.Bar( | |
[ | |
widget.Spacer(), | |
widget.GenPollText(func=custom_date, update_interval=1, **widget_defaults, mouse_callbacks={'Button1': lambda: qtile.cmd_spawn(os.path.expanduser("~/.local/bin/statusbar/calendar.sh show"), shell=True), 'Bu tton3': lambda: qtile.cmd_spawn(os.path.expanduser("~/.local/bin/statusbar/calendar.sh edit"), shell=True)}), | |
widget.Spacer(), | |
], | |
28, background="000000AA", margin=[10, 16, 0, 16] # N E S W | |
), | |
) | |
) | |
def window_to_previous_screen(qtile, switch_group=False, switch_screen=False): | |
i = qtile.screens.index(qtile.current_screen) | |
if i != 0: | |
group = qtile.screens[i - 1].group.name | |
qtile.current_window.togroup(group, switch_group=switch_group) | |
if switch_screen == True: | |
qtile.cmd_to_screen(i - 1) | |
def window_to_next_screen(qtile, switch_group=False, switch_screen=False): | |
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, switch_group=switch_group) | |
if switch_screen == True: | |
qtile.cmd_to_screen(i + 1) | |
keys.extend([ | |
Key([mod,"control"], "comma", lazy.function(window_to_next_screen)), | |
Key([mod,"control"], "period", lazy.function(window_to_previous_screen)), | |
Key([mod],"comma", lazy.function(window_to_next_screen, switch_screen=True)), | |
Key([mod],"period", lazy.function(window_to_previous_screen, switch_screen=True)), | |
]) | |
# Drag floating layouts. | |
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_key_binder = None | |
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. | |
# *layout.Floating.default_float_rules, | |
Match(title='Quit and close tabs?'), | |
Match(wm_type='utility'), | |
Match(wm_type='notification'), | |
Match(wm_type='toolbar'), | |
Match(wm_type='splash'), | |
Match(wm_type='dialog'), | |
Match(wm_class='Conky'), | |
Match(wm_class='Firefox'), | |
Match(wm_class='file_progress'), | |
Match(wm_class='confirm'), | |
Match(wm_class='dialog'), | |
Match(wm_class='download'), | |
Match(wm_class='error'), | |
Match(wm_class='notification'), | |
Match(wm_class='splash'), | |
Match(wm_class='toolbar'), | |
Match(wm_class='confirmreset'), # gitk | |
Match(wm_class='makebranch'), # gitk | |
Match(wm_class='maketag'), # gitk | |
Match(wm_class='ssh-askpass'), # ssh-askpass | |
Match(title='branchdialog'), # gitk | |
Match(title='pinentry'), # GPG key password entry | |
]) | |
auto_fullscreen = True | |
focus_on_window_activation = "smart" | |
# When application launched automatically focus it's group | |
@hook.subscribe.client_new | |
def modify_window(client): | |
for group in groups: # follow on auto-move | |
match = next((m for m in group.matches if m.compare(client)), None) | |
if match: | |
targetgroup = client.qtile.groups_map[group.name] # there can be multiple instances of a group | |
targetgroup.cmd_toscreen(toggle=False) | |
break | |
# Hook to fallback to the first group with windows when last window of group is killed | |
@hook.subscribe.client_killed | |
def fallback(window): | |
if window.group.windows != [window]: | |
return | |
idx = qtile.groups.index(window.group) | |
for group in qtile.groups[idx - 1::-1]: | |
if group.windows: | |
qtile.current_screen.toggle_group(group) | |
return | |
qtile.current_screen.toggle_group(qtile.groups[0]) | |
# Work around for matching Spotify | |
@hook.subscribe.client_new | |
def slight_delay(window): | |
time.sleep(0.04) | |
# 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 = "Qtile" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment