Files
.dotfiles/qtile/.config/qtile/config.py
T
2021-01-26 15:09:08 +01:00

608 lines
20 KiB
Python

import re
import os
import subprocess
import psutil
from PIL import Image, ImageDraw, ImageFont
from libqtile import layout, bar, widget
from libqtile.config import Key, Drag, Click, Group, Screen, ScratchPad, DropDown
from libqtile.command import lazy
#region defines
term = 'termite'
focus_color = '#bd93f9'
border_width = 2
mod = 'mod4'
hotkey_file='/home/paul/Hotkeys'
#region colors
light_foreground_color = ['#f8f8f2','#f8f8f2']
dark_foreground_color = ['#282a36','#282a36']
background_color0 = ['#000000','#000000']
background_color8 = ['#4d4d4d','#4d4d4d']
base_color = ['#101010','#101010']
# red
red_color = ['#df253f','#df253f']
light_red_color = ['#ff5555','#ff5555']
# green
green_color = ['#53a93f','#53a93f']
light_green_color = ['#50fa7b','#50fa7b']
#orange
orange_color = ['#f57900','#f57900']
# yellow
yellow_color = ['#f1fa8c','#f1fa8c']
#blue
blue_color = ['#7197e7','#7197e7']
# purple
purple_color = ['#bd93f9','#bd93f9']
light_purple_color = ['#caa9fa','#caa9fa']
# magenta
magenta_color = ['#ff79c6','#ff79c6']
# cyan
cyan_color = ['#8be9fd','#8be9fd']
#endregion
#endregion
#region Keys
keys = [
#moving focus aroung
Key([mod], "h", lazy.layout.left(),desc="move focus left"),
Key([mod], "l", lazy.layout.right(),desc="move focus right"),
Key([mod], "j", lazy.layout.down(),desc="move focus down"),
Key([mod], "k", lazy.layout.up(),desc="move focus up"),
Key([mod,"mod1"], "k", lazy.to_screen(0),desc="move focus to top screen"),
Key([mod,"mod1"], "j", lazy.to_screen(2),desc="move focus to main screen"),
Key([mod,"mod1"], "l", lazy.to_screen(2),desc="move focus to main screen"),
Key([mod,"mod1"], "h", lazy.to_screen(1),desc="move focus to left screen"),
# moving windows around
Key([mod, "shift"], "h", lazy.layout.swap_left(),desc="move focused window left"),
Key([mod, "shift"], "l", lazy.layout.swap_right(),desc="move focused window right"),
Key([mod, "shift"], "j", lazy.layout.shuffle_down(),desc="move focused window down"),
Key([mod, "shift"], "k", lazy.layout.shuffle_up(),desc="move focused window up"),
# resize windows
Key([mod], "plus", lazy.layout.grow(),desc="increase window size"),
Key([mod], "minus", lazy.layout.shrink(),desc="decrease window size"),
Key([mod], "n", lazy.layout.normalize(),desc="normalize windows"),
Key([mod], "o", lazy.layout.maximize(),desc="maximize current window"),
Key([mod], "space", lazy.window.toggle_fullscreen(),desc="make current window fullscreen"),
# app hotkeys
Key([mod],"t", lazy.spawn(term), desc="Launch terminal"),
Key([mod],"f", lazy.spawn("firefox"),desc="Launch firefox"),
Key([mod],"e", lazy.spawn("pcmanfm"),desc="Launch pcmanfm"),
Key([mod],"c", lazy.spawn("code"),desc="Launch visual studio code"),
Key([mod, "shift"],"s", lazy.spawn('gscreenshot -s -o -f /tmp/screenshots'),desc="take a screenshot"),
# Toggle between different layouts as defined below
Key([mod], "Tab", lazy.next_layout(), desc="Toggle between layouts"),
Key([mod], "BackSpace", lazy.window.kill(), desc="Kill focused window"),
# qtile hotkeys
Key([mod, "control"], "r", lazy.restart(), desc="Restart qtile"),
Key([mod, "control"], "q", lazy.shutdown(), desc="Shutdown qtile"),
#rofi
Key([mod],'Return',lazy.spawn("rofi -show drun -show-icons -modi drun,calc,ssh"),desc="launch rofi (drun)"),
Key([mod],'p',lazy.spawn("bwmenu --auto-lock -1"),desc="launch bwmenu"),
# audio hotkeys
Key([], 'XF86AudioRaiseVolume', lazy.spawn('pulseaudio-ctl up 1'), desc="increase speaker volume"),
Key([], 'XF86AudioLowerVolume', lazy.spawn('pulseaudio-ctl down 1'), desc="decrease speaker volume"),
Key([], 'XF86AudioMute', lazy.spawn('pulseaudio-ctl mute'), desc="toggle speaker mute"),
Key(['control'], 'XF86AudioRaiseVolume', lazy.spawn('amixer set Capture 1%+'), desc="increase mic volume"),
Key(['control'], 'XF86AudioLowerVolume', lazy.spawn('amixer set Capture 1%-'), desc="decrease mic volume"),
Key(['control'], 'XF86AudioMute', lazy.spawn('amixer set Capture toggle'), desc="toggle mic mute"),
# Media hotkeys
Key([], 'XF86AudioNext', lazy.spawn('playerctl next')),
Key([], 'XF86AudioPrev', lazy.spawn('playerctl previous')),
Key([], 'XF86AudioPlay', lazy.spawn('playerctl play-pause')),
]
# 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())
]
#endregion
#region Groups
group_names = [("","Home", 'h',{'layout': 'monadtall'}),
("","Coding", 'c',{'layout': 'monadtall'}),
("","Browser", 'f',{'layout': 'monadtall'}),
("","Mail", 'm',{'layout': 'monadtall'}),
("","Music", 's',{'layout': 'monadtall'}),
("","Chat", 'w',{'layout': 'monadtall'}),
("","Video", 'v',{'layout': 'monadtall'}),
("","Documents", 'l',{'layout': 'monadtall'}),
("","Discord", 'd',{'layout': 'monadtall'}),
("","VM's", 'o',{'layout': 'monadtall'}),
("","Gaming", 'g',{'layout': 'monadtall'})]
groups = [Group(icon, **kwargs) for icon, name, key, kwargs in group_names]
groups.extend([ScratchPad("scratchpad",[DropDown("term",term,opacity=0.8)])])
for (icon,name,key, kwargs) in group_names:
keys.extend([
Key(["mod1","control"], str(key), lazy.group[icon].toscreen(),
desc="Switch to group {}".format(name)),
Key(['mod1','control', "shift"], str(key), lazy.window.togroup(icon),
desc="move focused window to group {}".format(name)),
])
keys.extend([
Key(['mod1','control'],'space',lazy.group['scratchpad'].dropdown_toggle('term'),
desc="open the dropdown terminal"),
])
#endregion
#region Layouts
layouts = [
layout.MonadTall(
align=1,
border_focus = focus_color,
border_width = border_width,
new_at_current = True,
),
layout.Floating(
border_focus = focus_color,
border_width = border_width,
),
layout.Max(),
layout.MonadWide(
border_focus = focus_color,
border_width = border_width,
new_at_current = True,
),
]
floating_layout = layout.Floating(
border_focus = focus_color,
border_width = border_width,
float_rules=[
# Run the utility of `xprop` to see the wm class and name of an X client.
{'wmclass': 'confirm'},
{'wmclass': 'dialog'},
{'wmclass': 'download'},
{'wmclass': 'error'},
{'wmclass': 'file_progress'},
{'wmclass': 'notification'},
{'wmclass': 'splash'},
{'wmclass': 'toolbar'},
{'wmclass': 'confirmreset'}, # gitk
{'wmclass': 'makebranch'}, # gitk
{'wmclass': 'maketag'}, # gitk
{'wname': 'branchdialog'}, # gitk
{'wname': 'pinentry'}, # GPG key password entry
{'wmclass': 'ssh-askpass'}, # ssh-askpass
])
#endregion
#region Custom_Widgets
#region Custom_Memory
class MemoryC(widget.base.ThreadedPollText):
orientations = widget.base.ORIENTATION_HORIZONTAL
defaults = [
("format", "{MemUsed}GB/{MemTotal}GB", "Formatting for field names."),
("update_interval", 1.0, "Update interval for the Memory"),
]
def __init__(self, **config):
super().__init__(**config)
self.add_defaults(MemoryC.defaults)
def tick(self):
self.update(self.poll())
return self.update_interval
def poll(self):
mem = psutil.virtual_memory()
swap = psutil.swap_memory()
val = {}
val["MemUsed"] = mem.used // 1024 // 1024 // 102.4 / 10
val["MemTotal"] = mem.total // 1024 // 1024 // 102.4 / 10
val["MemPercent"] = mem.percent
val["MemFree"] = mem.free // 1024 // 1024 // 102.4 / 10
val["Buffers"] = mem.buffers // 1024 // 1024 // 102.4 / 10
val["Active"] = mem.active // 1024 // 1024 // 102.4 / 10
val["Inactive"] = mem.inactive // 1024 // 1024 // 102.4 / 10
val["Shmem"] = mem.shared // 1024 // 1024 // 102.4 / 10
val["SwapTotal"] = swap.total // 1024 // 1024 // 102.4 / 10
val["Swapfree"] = swap.free // 1024 // 1024 // 102.4 / 10
val["SwapUsed"] = swap.used // 1024 // 1024 // 102.4 / 10
val["SwapPercent"] = swap.percent
return self.format.format(**val)
#endregion
#region Microphone_Widget
re_vol = re.compile(r'\[(\d?\d?\d?)%\]')
BUTTON_MUTE = 1
class Mic(widget.base._TextBox):
"""
Custom Microphone widget
"""
orientations = widget.base.ORIENTATION_HORIZONTAL
defaults = [
("cardid", None, "Card Id"),
("device", "default", "Device Name"),
("channel", "Capture", "Channel"),
("padding", 3, "Padding left and right. Calculated if None."),
("update_interval", 0.2, "Update time in seconds."),
("theme_path", None, "Path of the icons"),
("emoji", False, "Use emoji to display volume states, only if ``theme_path`` is not set."
"The specified font needs to contain the correct unicode characters."),
("mute_command", None, "Mute command"),
("volume_app", None, "App to control volume"),
("volume_up_command", None, "Volume up command"),
("volume_down_command", None, "Volume down command"),
("get_volume_command", None, "Command to get the current volume"),
("step", 2, "Volume change for up an down commands in percentage."
"Only used if ``volume_up_command`` and ``volume_down_command`` are not set.")
]
def __init__(self, **config):
widget.base._TextBox.__init__(self, '0', width=bar.CALCULATED, **config)
self.add_defaults(Mic.defaults)
if self.theme_path:
self.length_type = bar.STATIC
self.length = 0
self.surfaces = {}
self.volume = None
def timer_setup(self):
self.timeout_add(self.update_interval, self.update)
if self.theme_path:
self.setup_images()
def create_amixer_command(self, *args):
cmd = ['amixer']
cmd.extend([x for x in args])
return cmd
def button_press(self, x, y, button):
if button == BUTTON_MUTE:
if self.mute_command is not None:
subprocess.call(self.mute_command, shell=True)
else:
subprocess.call(self.create_amixer_command('-q',
'sset',
self.channel,
'toggle'))
self.draw()
def update(self):
vol = self.get_volume()
if vol != self.volume:
self.volume = vol
# Update the underlying canvas size before actually attempting
# to figure out how big it is and draw it.
self._update_drawer()
self.bar.draw()
self.timeout_add(self.update_interval, self.update)
def _update_drawer(self):
if self.emoji:
if self.volume > 0:
self.text = ''
elif self.volume <= 0:
self.text = ''
else:
if self.volume == -1:
self.text = 'M'
else:
self.text = '{}%'.format(self.volume)
def get_volume(self):
try:
get_volume_cmd = self.create_amixer_command('sget',
self.channel)
if self.get_volume_command:
get_volume_cmd = self.get_volume_command
mixer_out = self.call_process(get_volume_cmd)
except subprocess.CalledProcessError:
return -1
if '[off]' in mixer_out:
return -1
volgroups = re_vol.search(mixer_out)
if volgroups:
return int(volgroups.groups()[0])
else:
# this shouldn't happen
return -1
def draw(self):
if self.theme_path:
self.drawer.draw(offsetx=self.offset, width=self.length)
else:
widget.base._TextBox.draw(self)
def cmd_mute(self):
# Emulate button press.
self.button_press(0, 0, BUTTON_MUTE)
#endregion
#endregion
#region widgets
#region Powerline
def powerline_arrow(direction, color1, color2,size):
if direction == "r":
return [
widget.TextBox(
text=u"\ue0b0",
foreground=color1,
background=color2,
fontsize=size,
borderwidth=0,
padding=0
),
widget.Sep(padding=5, linewidth=0, background=color2),
]
else:
return [
widget.TextBox(
text=u"\ue0b2",
foreground=color2,
background=color1,
fontsize=size,
borderwidth=0,
padding=0
),
]
#endregion
#region Left_widgets
def Left_widgets(size,fontsize,prompt=False):
return [
widget.CurrentLayoutIcon(),
*powerline_arrow('r',base_color,blue_color,size),
widget.Image(
filename='~/.config/qtile/icons/archlinux-logo-small.png',
margin=5,
background=blue_color
),
*powerline_arrow('r',blue_color,base_color,size),
widget.GroupBox(
fontsize=fontsize,
rounded=False,
active=light_foreground_color,
inactive=dark_foreground_color,
highlight_method='block',
highlight_color=red_color,
other_screen_border = light_purple_color,
other_current_screen_border = purple_color,
this_current_screen_border = blue_color,
this_screen_border = blue_color,
urgent_alert_method='block',
urgent_border = red_color,
),
widget.WindowName(fontsize=fontsize-2),
]
#endregion
#region Volume_widget
def vloume_widget(prev_color,color,size,fontsize):
return[
*powerline_arrow('l',prev_color,color,size),
widget.Volume(
foreground=dark_foreground_color,
background=color,
emoji=True,
fontsize=fontsize,
),
widget.Volume(
foreground=dark_foreground_color,
background=color,
fontsize=fontsize,
padding=0
),
Mic(
foreground=dark_foreground_color,
background=color,
emoji=True,
fontsize=fontsize,
),
Mic(
foreground=dark_foreground_color,
background=color,
fontsize=fontsize,
padding=0
),
widget.TextBox(" ",background=color),
]
#endregion
#region System_widgets
launch_htop= {'Button1': lambda qtile: qtile.cmd_spawn(term + ' -e htop')}
def System_widgets(prev_color,last_color,size,fontsize):
return [
*powerline_arrow('l',prev_color,red_color,size),
widget.Image(
filename='~/.config/qtile/icons/temp.png',
margin=5,
background=red_color,
mouse_callbacks = launch_htop,
),
widget.ThermalSensor(
foreground=dark_foreground_color,
background=red_color,
fontsize=fontsize,
tag_sensor='Tctl',
mouse_callbacks = launch_htop,
),
*powerline_arrow('l',red_color,green_color,size),
widget.Image(
filename='~/.config/qtile/icons/cpu.png',
margin=5,
background=green_color,
mouse_callbacks = launch_htop,
),
widget.CPU(
foreground=dark_foreground_color,
background=green_color,
fontsize=fontsize,
format='{load_percent}% @ {freq_current}GHz',
mouse_callbacks = launch_htop,
),
*powerline_arrow('l',green_color,orange_color,size),
widget.Image(
filename='~/.config/qtile/icons/ram.png',
background=orange_color,
margin=-10,
mouse_callbacks = launch_htop,
),
MemoryC(
foreground=dark_foreground_color,
background=orange_color,
fontsize=fontsize,
format=" {MemUsed}GB({MemPercent}%) | {SwapUsed}GB({SwapPercent}%)",
mouse_callbacks = launch_htop,
),
*powerline_arrow('l',orange_color,last_color,size),
widget.Image(
filename='~/.config/qtile/icons/network.png',
background=blue_color,
margin=5,
mouse_callbacks = launch_htop,
),
widget.Net(
background=last_color,
foreground=dark_foreground_color,
fontsize=fontsize,
fmt='{:.9}',
format='{down}',
mouse_callbacks = launch_htop,
),
widget.Net(
background=last_color,
foreground=dark_foreground_color,
fontsize=fontsize,
fmt='{:.9}',
format='{up}',
mouse_callbacks = launch_htop,
),
]
#endregion
#region End_widgets
def end_widgets(prev_color,size,fontsize):
return [
*powerline_arrow('l',prev_color,magenta_color,size),
widget.Image(
filename='~/.config/qtile/icons/calendar.png',
margin=5,
background=magenta_color,
),
widget.Clock(
foreground=dark_foreground_color,
background=magenta_color,
fontsize=fontsize,
format='%Y-%m-%d'
),
*powerline_arrow('l',magenta_color,base_color,size),
widget.Clock(
font='dseg7 classic bold',
fontsize=16,
format='%H:%M'
),
]
#endregion
#endregion
#region Bars
widget_defaults = dict(
background=base_color,
font='Ubuntu Mono',
fontsize=18,
padding=3,
)
extension_defaults = widget_defaults.copy()
main_bar_fontsize=22
main_bar_height=28
secondary_bar_height=24
secondary_bar_fontsize=18
main_bar = bar.Bar([
*Left_widgets(main_bar_height,main_bar_fontsize,True),
widget.Systray(fontsize=main_bar_fontsize),
*vloume_widget(base_color,blue_color,main_bar_height,main_bar_fontsize),
*System_widgets(blue_color,blue_color,main_bar_height,main_bar_fontsize),
*end_widgets(blue_color,main_bar_height,main_bar_fontsize),
],main_bar_height)
#left bar
left_bar = bar.Bar([
*Left_widgets(secondary_bar_height,secondary_bar_fontsize),
*vloume_widget(base_color,blue_color,secondary_bar_height,secondary_bar_fontsize),
*end_widgets(blue_color,secondary_bar_height,secondary_bar_fontsize)
],secondary_bar_height)
top_bar = bar.Bar([
*Left_widgets(secondary_bar_height,secondary_bar_fontsize),
*vloume_widget(base_color,blue_color,secondary_bar_height,secondary_bar_fontsize),
*end_widgets(blue_color,secondary_bar_height,secondary_bar_fontsize)
],secondary_bar_height)
#endregion
#region Screens
screens = [
Screen(bottom=top_bar),
Screen(top=left_bar),
Screen(top=main_bar),
]
#endregion
#region miscelanious
dgroups_key_binder = None
dgroups_app_rules = [] # type: List
main = None # WARNING: this is deprecated and will be removed soon
follow_mouse_focus = True
bring_front_click = True
cursor_warp = False
auto_fullscreen = True
focus_on_window_activation = "smart"
#region Hotkey_Wallpaper
#create hotkey textfile
if os.path.isfile(hotkey_file):
os.remove(hotkey_file)
with open(hotkey_file,'w') as file:
for key in keys:
if not str(key.key).startswith("XF86"):
modifiers=""
for modifier in key.modifiers:
modifiers += '{:^7}'.format(
str(modifier).replace("mod1","Alt").replace("mod4","Super").replace("shift","Shift").replace("control","Ctrl")
) + "+"
file.write('{:30}'.format(modifiers+' '+str(key.key).upper())+"=> "+key.desc)
file.write('\n')
#endregion
# 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"
#endregion