from libqtile.config import Key, Screen, Group, Drag, Click, Match from libqtile.command import lazy from libqtile import layout, bar, widget, hook import logging import os import re import subprocess from libqtile.log_utils import logger # import psutil # import getpass mod = "mod4" alt = "mod1" home = os.path.expanduser("~") hostname = os.uname().nodename display = os.environ['DISPLAY'] terminal = "termite" drun_launcher = "rofi -show drun" run_launcher = "rofi -show run" lock = home+"/bin/xorg_lock" brightness_step = "2" brightness_up = "backlight -i "+brightness_step brightness_down = "backlight -i -"+brightness_step volume_up = home+"/bin/set_volume increase" volume_down = home+"/bin/set_volume decrease" volume_toggle = home+"/bin/set_volume toggle" audio_prev = home+"/bin/notify_mpd prev" audio_next = home+"/bin/notify_mpd next" audio_toggle = home+"/bin/notify_mpd toggle" audio_stop = home+"/bin/notify_mpd stop" conky_network = ['/usr/bin/conky', '-X', display, '-c', home+'/.config/conky/'+hostname+'-network.conf'] conky_general = ['/usr/bin/conky', '-X', display, '-c', home+'/.config/conky/'+hostname+'-general.conf'] background = ['feh', '--randomize', '--recursive', '--bg-fill', home+'/cloud/photos/desktop/'] compton = ['/usr/bin/compton', '-CGb', '-d', display] colors = { "grey": "#555555", "red": "#DD1144", "blue": "#445588", "lgrey": "#b8b6b1", "green": "#008080", } # kick a window to another screen (handy during presentations) def move_to_other_screen(qtile, direction=1): other_scr_index = (qtile.screens.index(qtile.currentScreen) + direction) \ % len(qtile.screens) othergroup = None for group in qtile.cmd_groups().values(): if group['screen'] == other_scr_index: othergroup = group['name'] break if othergroup: qtile.moveToGroup(othergroup) keys = [ # base commands # restart qtile Key([mod, "control"], "r", lazy.restart()), # close qtile Key([mod, "control"], "q", lazy.shutdown()), # start run launcher Key([mod], "r", lazy.spawn(run_launcher)), # start drun launcher Key([mod], "p", lazy.spawn(drun_launcher)), # lock screen Key([mod, "control"], "s", lazy.spawn(lock)), # launch terminal Key([mod], "Return", lazy.spawn(terminal)), # multimedia Key([], "XF86AudioRaiseVolume", lazy.spawn(volume_up)), Key([], "XF86AudioLowerVolume", lazy.spawn(volume_down)), Key([], "XF86AudioMute", lazy.spawn(volume_toggle)), Key([], "XF86AudioPrev", lazy.spawn(audio_prev)), Key([], "XF86AudioNext", lazy.spawn(audio_next)), Key([], "XF86AudioPlay", lazy.spawn(audio_toggle)), Key([], "XF86AudioStop", lazy.spawn(audio_stop)), # brightness settings Key([], "XF86MonBrightnessUp", lazy.spawn(brightness_up)), Key([], "XF86MonBrightnessDown", lazy.spawn(brightness_down)), # cycle to previous and next group Key(["control", alt], "Left", lazy.screen.prev_group(skip_managed=True)), Key(["control", alt], "Right", lazy.screen.next_group(skip_managed=True)), Key(["control", mod, alt], "Left", lazy.screen.prev_group()), Key(["control", mod, alt], "Right", lazy.screen.next_group()), # Switch between windows in current stack pane Key([mod], "comma", lazy.layout.up()), Key([mod], "period", lazy.layout.down()), Key([mod], "Tab", lazy.layout.previous()), Key([mod, "shift"], "Tab", lazy.layout.next()), # toggle between different layouts Key([mod], "space", lazy.next_layout()), # close window Key([mod], "q", lazy.window.kill()), # toggle fullscreen Key([mod, "control"], "f", lazy.window.toggle_fullscreen()), # toggle maximized Key([mod], "m", lazy.window.toggle_maximize()), # toggle floating Key([mod], "f", lazy.window.toggle_floating()), Key([mod, alt], "space", lazy.layout.rotate()), # flip sides # Multihead magic Key([mod, "control"], "comma", lazy.prev_screen()), Key([mod, "control"], "period", lazy.next_screen()), Key([mod], "o", lazy.function(move_to_other_screen)), # columns layout # move selection around in current group Key([mod], "j", lazy.layout.down()), Key([mod], "k", lazy.layout.up()), Key([mod], "h", lazy.layout.left()), Key([mod], "l", lazy.layout.right()), # move current window around in the current layout Key([mod, "shift"], "j", lazy.layout.shuffle_down()), Key([mod, "shift"], "k", lazy.layout.shuffle_up()), Key([mod, "shift"], "h", lazy.layout.shuffle_left()), Key([mod, "shift"], "l", lazy.layout.shuffle_right()), # grow current window into some direction Key([mod, "control"], "j", lazy.layout.grow_down()), Key([mod, "control"], "k", lazy.layout.grow_up()), Key([mod, "control"], "h", lazy.layout.grow_left()), Key([mod, "control"], "l", lazy.layout.grow_right()), # toggle current window to be splitting current group in half Key([mod], "s", lazy.layout.toggle_split()), # normalize the layout Key([mod], "n", lazy.layout.normalize()), ] matchers = { 'web': [ Match(wm_class=[ re.compile('Chromium$'), re.compile('Firefox$'), re.compile('.*qutebrowser$'), re.compile('TorLauncher'), re.compile('Tor Browser'), ]), ], 'dev': [ Match(wm_class=[ re.compile('Processing'), re.compile('processing-app-Base'), ]), Match(title=[ re.compile("SuperCollider\sIDE$"), re.compile("^SuperCollider"), re.compile("^Loading"), re.compile("Pd$"), ]), ], 'games': [ Match(wm_class=[ re.compile('Minecraft'), re.compile('Minetest'), re.compile('MediaElch'), "pyrogenesis", "spring", "angband", "scummvm", "widelands", ]), Match(title=[ re.compile('ScummVM'), re.compile('Widelands'), re.compile('Minecraft'), re.compile('Minetest'), "OpenRA", "0 A.D.", "Angband", "Alien Arena", ]), ], 'audio': [ Match(wm_class=[ re.compile('Ardour'), re.compile('Audacity'), re.compile('Calfjackhost'), re.compile('Carla'), re.compile('Cadence'), re.compile('Ffado-mixer'), re.compile('Guitarix'), re.compile('Session Setup'), ]), Match(title=[ re.compile('^JACK'), re.compile("^Calf\sJACK\sHost"), re.compile("^Patchage"), re.compile("^Instrument Tuner"), ]), ], 'spat': [ Match(title=[ re.compile('.*Renderer'), re.compile('Controls'), ]), ], 'photo': [ Match(wm_class=[ re.compile('Shotwell'), re.compile('Gimp'), re.compile('Inkscape'), re.compile('Darktable'), re.compile('Converseen'), re.compile('Ufraw'), ]) ], 'office': [ Match(wm_class=[ re.compile('Scribus'), ]), Match(title=[ re.compile('^calibre'), re.compile('^JabRef'), re.compile("Libreoffice\sWriter$"), ]), ], 'admin': [ Match(wm_class=[ re.compile('virt-manager'), re.compile('Virt-manager'), ]), ], } workspaces = [ {"key": "1", "name": "shell"}, {"key": "2", "name": "web", "matches": matchers["web"]}, {"key": "3", "name": "dev", "matches": matchers["dev"]}, {"key": "4", "name": "games", "matches": matchers["games"]}, {"key": "5", "name": "audio", "matches": matchers["audio"]}, {"key": "6", "name": "spat", "matches": matchers["spat"]}, {"key": "7", "name": "photo", "matches": matchers["photo"]}, {"key": "8", "name": "office", "matches": matchers["office"]}, {"key": "9", "name": "admin", "matches": matchers["admin"]}, {"key": "0", "name": "0"}, ] groups = [] for workspace in workspaces: matches = workspace["matches"] if "matches" in workspace else None groups.append(Group(workspace["name"], matches=matches)) keys.append( Key([mod], workspace["key"], lazy.group[workspace["name"]].toscreen()) ) keys.append(Key( [mod, alt], workspace["key"], lazy.window.togroup(workspace["name"]), )) layouts = [ layout.Columns( border_focus=colors["red"][1:], border_normal=colors["green"][1:], margin=1, ), layout.TreeTab( active_bg=colors["red"][1:], # active_fg=colors["grey"][1:], active_fg='ffffff', inactive_bg=colors["green"][1:], # inactive_fg=colors["lgrey"][1:], inactive_fg='ffffff', border_focus=colors["red"][1:], border_normal=colors["green"][1:], font='Monospace', fontsize=14, margin_left=0, padding_left=0, panel_width=100, previous_on_rm=True, ), layout.Max(), layout.VerticalTile( border_focus=colors["red"][1:], border_normal=colors["green"][1:], margin=1, ), ] widget_defaults = dict( font='Monospace', fontsize=11, padding=3, ) screens = [ Screen( top=bar.Bar([ widget.CurrentScreen(), widget.Sep(), widget.GroupBox( active="fff0f0", inactive="808080", highlight_method="block", this_current_screen_border="c22b25", this_screen_border="619a75", other_current_screen_border="ba9998", other_screen_border="26914c", urgent_alert_method="block", urget_border="a528d2", disable_drag=True, use_mouse_wheel=False ), widget.Sep(), widget.Notify( foreground_low=colors["red"][1:], foreground_urgent=colors["red"][1:] ), widget.CurrentLayout(), widget.Spacer(), widget.Sep(), widget.Mpd( host="127.0.0.1", port=6600, reconnect=True, fmt_playing="%a [%A] %t [%v%%]", ), widget.Sep(), widget.HDDGraph( graph_color=colors["blue"], border_width=0, samples=10, frequency=5, type="box", ), widget.Wlan( interface="wlp3s0"), widget.MemoryGraph( graph_color=colors["green"], border_width=0, samples=10, frequency=2, type="box", ), widget.CPUGraph( graph_color=colors["red"], border_width=0, samples=10, frequency=2, type="box", ), widget.Battery(), widget.Sep(), widget.Systray(), widget.Sep(), widget.Clock( timezone="Europe/Berlin", format="%Y%m%d %a %H:%M:%S" ), ], 20 ), ), Screen( top=bar.Bar([ widget.CurrentScreen(), widget.Sep(), widget.GroupBox( active="fff0f0", inactive="808080", highlight_method="block", this_current_screen_border="c22b25", this_screen_border="619a75", other_current_screen_border="ba9998", other_screen_border="26914c", urgent_alert_method="block", urget_border="a528d2", disable_drag=True, use_mouse_wheel=False ), widget.Sep(), widget.CurrentLayout(), widget.Sep(), widget.Notify( foreground_low=colors["red"][1:], foreground_urgent=colors["red"][1:] ), widget.Spacer(), widget.Clock( timezone="Europe/Berlin", format="%Y%m%d %a %H:%M:%S" ), ], 20 ), ), ] # Drag floating layouts. mouse = [ Click([mod], "Button2", lazy.window.bring_to_front() ), 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() ) ] floating_clients = [ re.compile('^JACK'), re.compile('^Controls'), re.compile('^ssr-.*'), re.compile('^Help Browser'), re.compile('^Find externals'), re.compile('^Audio Settings'), re.compile('^MIDI Settings'), re.compile('^Find'), re.compile('^Pd search path'), re.compile('^Send a Pd message'), re.compile('^Instrument Tuner'), ] dgroups_key_binder = None dgroups_app_rules = [] follow_mouse_focus = True bring_front_click = False cursor_warp = False floating_layout = layout.Floating() auto_fullscreen = True wmname = "LG3D" def main(qtile): qtile.cmd_warning() @hook.subscribe.screen_change def restart_on_randr(qtile, ev): subprocess.run(['/usr/bin/killall', 'compton']) qtile.cmd_restart() @hook.subscribe.client_new def floating_dialogs(client): # wm_class = client.window.get_wm_class() # logger.setLevel(logging.INFO) # logger.info('New client window name: %s' % client.name) # logger.info('New client window class: %c' % wm_class) logger.setLevel(logging.WARNING) for client_regex in floating_clients: match = client_regex.match(client.name) if match: client.floating = True transient = client.window.get_wm_transient_for() if transient: client.floating = True @hook.subscribe.startup def autostart_background(): subprocess.run(['/usr/bin/killall', 'compton']) subprocess.call(background) @hook.subscribe.startup_once def autostart_conky(): subprocess.call(conky_network) subprocess.call(conky_general) @hook.subscribe.startup_complete def autostart_compton(): subprocess.call(compton) # get_user_processes('compton') # def get_user_processes(process_name): # for process in psutil.process_iter(attrs=['name', 'username']): # if process.info['username'] == getpass.getuser() and \ # process.info['name'] == process_name: # logger.setLevel(logging.INFO) # logger.info(process.pid) # logger.info(process.info['name']) # logger.setLevel(logging.WARNING)