kuro-qtile-theme/kuro/theme.py

916 lines
37 KiB
Python

import json
import os
import random
# Initialize logging
from libqtile.log_utils import logger
logger.error("Importing qtile theme requirements...")
from libqtile.config import Key, Screen, Group, Drag, Click, Match
from libqtile.command import lazy
from libqtile import layout, bar, widget, qtile
logger.error("Importing theme util functions...")
# Import theme util functions
from xcffib.xproto import WindowError
logger.error("Importing kuro utils...")
import kuro.utils.widgets
from kuro.utils import general as utils
logger.error("Importing variables and other utils...")
# Import variables
from kuro.base import BaseTheme
from kuro.utils.general import display_wm_class, test_popups
from kuro.utils.kb_backlight import handle_focus_change as kb_handle_focus_change
from kuro.utils import layouts as kuro_layouts
from kuro.utils.windows import KuroStatic
logger.error("Importing configuration...")
try:
from kuro.config import Config
except ImportError:
try:
from kuro.baseconfig import BaseConfig as Config
except ImportError:
Config = None
raise ImportError("Could not load theme Config or BaseConfig!")
logger.error("Imports done")
class Kuro(BaseTheme):
# Shorthand for modifier key
mod = Config.get("modifier", "mod4")
# Show debug messages
debug = Config.get('debug', False)
debug_textfields = []
debug_bars = []
# Screen count
num_screens = 0
# Top bars
topbars = []
# Visualizers
audio_visualizers = []
# Static windows
static_windows = []
# Current wallpaper path
current_wallpaper = None
# Whether or not to perform keyboard backlight updates
do_keyboard_updates = True
# Window manager name
wmname = "qtile"
# Floating layout override
floating_layout = kuro_layouts.KuroFloating(float_rules=[
# Run the utility of `xprop` to see the wm class and name of an X client.
*layout.Floating.default_float_rules,
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
Match(title='origin.exe', wm_class='Wine'), # Wine Origin game launcher
])
def set_debug_text(self, text):
for field in self.debug_textfields:
field.text = text
for bar in self.debug_bars:
if qtile is not None:
bar.draw()
def log_debug(self, text):
if Config.get('verbose', False):
self.set_debug_text(text)
logger.debug(text)
def log_info(self, text):
self.set_debug_text(text)
logger.info(text)
def initialize(self):
logger.error("Initializing Kuro theme...")
self.log_debug("Initializing Kuro Theme...")
# Update color scheme
self.initialize_colorscheme()
# Set settings
self.do_keyboard_updates = Config.get("do_keyboard_updates", True)
super(Kuro, self).initialize()
self.update()
def update(self):
# Update keys with keys for groups and layouts
self.update_keys()
def init_keys(self):
self.log_debug("Initializing keys")
return [
# Switch between windows in current stack pane
Key([self.mod], "k", lazy.layout.down()),
Key([self.mod], "j", lazy.layout.up()),
# Move windows up or down in current stack
Key([self.mod, "control"], "k", lazy.layout.shuffle_down()),
Key([self.mod, "control"], "j", lazy.layout.shuffle_up()),
# Switch window focus to other pane(s) of stack
Key([self.mod], "space", lazy.layout.next()),
# Swap panes of split stack
Key([self.mod, "shift"], "space", lazy.layout.rotate()),
# Fullscreen toggle
Key([self.mod], 'f', lazy.window.toggle_fullscreen()),
# Floating toggle
Key([self.mod, "shift"], 'f', lazy.window.toggle_floating()),
# Pinned toggle
Key([self.mod, "shift"], 'p', lazy.function(self.toggle_pinned)),
# 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([self.mod, "shift"], "Return", lazy.layout.toggle_split()),
# Super-Enter to start terminal
Key([self.mod], "Return", lazy.spawn(Config.get('app_terminal', "xterm"))),
# Super-R to start dmenu_run
Key([self.mod], "r", lazy.spawn(Config.get('app_launcher', "dmenu_run"))),
# Super-B to start webbrowser
Key([self.mod], "b", lazy.spawn(Config.get('web_browser', "xterm links"))),
# Super-F to start file manager
# Key([self.mod], "f", lazy.spawn(Config.get('file_m4anager', "thunar"))),
# Super-Shift-R to start spawncmd
Key([self.mod, "shift"], "r", lazy.spawncmd()),
# Lock shortcut
Key([self.mod], "l", lazy.spawn(Config.get('lock_command', "i3lock"))),
# Backlight keys
Key([], "XF86MonBrightnessUp", lazy.spawn(Config.get('cmd_brightness_up', 'xbacklight -inc 10'))),
Key([], "XF86MonBrightnessDown", lazy.spawn(Config.get('cmd_brightness_down', 'xbacklight -dec 10'))),
# Display modes
Key([self.mod], "Prior", lazy.spawn(Config.get('cmd_monitor_mode_3s144', 'true'))),
Key([self.mod], "Next", lazy.spawn(Config.get('cmd_monitor_mode_3s60', 'true'))),
Key([self.mod], "Home", lazy.spawn(Config.get('cmd_monitor_mode_day', 'true'))),
Key([self.mod], "End", lazy.spawn(Config.get('cmd_monitor_mode_night', 'true'))),
Key([self.mod], "Insert", lazy.spawn(Config.get('cmd_monitor_mode_alt', 'true'))),
# Media keys
Key([], "XF86AudioPlay", lazy.spawn(Config.get('cmd_media_play', 'true'))),
Key([], "XF86AudioNext", lazy.spawn(Config.get('cmd_media_next', 'true'))),
Key([], "XF86AudioMute", lazy.spawn(Config.get('cmd_media_mute', 'true'))),
Key([], "XF86AudioRaiseVolume", lazy.spawn(Config.get('cmd_media_volume_up', 'true'))),
Key([], "XF86AudioLowerVolume", lazy.spawn(Config.get('cmd_media_volume_down', 'true'))),
# Sleep key
Key([], "XF86Sleep", lazy.spawn(Config.get('cmd_sleep', 'true'))),
# Screenshot key
Key([], "Print", lazy.spawn(Config.get('cmd_screenshot', 'xfce4-screenshooter'))),
# Alt screenshot
Key([self.mod], "Print", lazy.spawn(Config.get('cmd_alt_screenshot', 'xfce4-screenshooter'))),
# Toggle between different layouts as defined below
Key([self.mod], "Tab", lazy.next_layout()),
# Kill the current window
Key([self.mod], "w", lazy.window.kill()),
# Restart QTile
Key([self.mod, "control"], "r", lazy.restart()),
# Shutdown QTile
Key([self.mod, "control"], "q", lazy.shutdown()),
# Update wallpaper
Key([self.mod, "control"], "w", lazy.function(self.update_wallpaper)),
# Reload colorscheme
Key([self.mod, "control"], "t", lazy.function(self.update_colorscheme)),
# Reorganize screens
Key([self.mod, "control"], "s", lazy.function(self.update_screens)),
# Toggle static windows
Key([self.mod], "p", lazy.function(self.toggle_window_static)),
##
# Debug keyboard shortcuts
##
Key([self.mod, "control"], "c", lazy.function(display_wm_class)),
# Redraw the top bar
Key([self.mod, "shift", "control"], "r", lazy.function(self.redraw_bar)),
# Update visualizer widgets
Key([self.mod, "shift", "control"], "v", lazy.function(self.reinitialize_visualizers)),
# Show extensive window info
Key([self.mod, "shift", "control"], "i", lazy.function(self.show_window_info)),
# Spawn a popup, and despawn it after 3 seconds
Key([self.mod, "control"], "p", lazy.function(test_popups)),
]
def init_groups(self):
self.log_debug("Initializing groups")
groups = []
# http://fontawesome.io/cheatsheet
groups.append(Group("", spawn=Config.get('web_browser', "true")))
groups.append(Group("", spawn=Config.get('app_terminal', "true")))
groups.append(Group(""))
groups.append(Group("", spawn=Config.get('app_chat', "true")))
groups.append(Group("", spawn=Config.get('app_irc', "true")))
groups.append(Group("", spawn=Config.get('file_manager', "true")))
groups.append(Group("", spawn=Config.get('app_mail', "true")))
groups.append(Group(""))
groups.append(Group("", spawn=Config.get('app_music', "true")))
groups.append(Group(""))
groups.append(Group("", spawn=Config.get('apps_audio', "true")))
groups.append(Group("", layout='floating', layouts=[
layout.Floating(
border_focus="#990000",
border_normal="#440000"
)
]))
return groups
def init_layouts(self):
self.log_debug("Initializing layouts")
return [
kuro_layouts.KuroWmii(
theme=self,
border_focus=Config.get('colour_border_focus', "#ffffff"),
border_focus_stack=Config.get('colour_border_normal', "#777777"),
border_normal=Config.get('colour_border_normal', "#777777"),
border_normal_stack=Config.get('colour_border_normal', "#777777"),
border_width=Config.get('width_border', "1"),
grow_amount=Config.get('grow_amount', "5"),
margin=Config.get('margin_layout', "0"),
),
layout.Max(),
layout.Zoomy(
columnwidth=Config.get('width_zoomy_column', 150),
margin=Config.get('margin_layout', "0"),
)
]
def init_widget_defaults(self):
self.log_debug("Initializing widget_defaults")
return {
"font": Config.get('font_topbar', "Sans"),
"fontsize": Config.get('fontsize_topbar', 16),
"padding": 3,
}
def init_screens(self):
self.log_debug("Initializing screens")
self.num_screens = utils.get_screen_count()
if self.num_screens <= 0:
self.num_screens = 1
screens = []
for x in range(self.num_screens):
self.log_info("Initializing bars for screen {}".format(x))
widgets = []
widgets.extend([
widget.GroupBox(
active=Config.get('colour_groupbox_icon_active', '#ffffff'),
borderwidth=Config.get('width_groupbox_border', 1),
disable_drag=Config.get('bool_groupbox_disable_drag', False),
font=Config.get('font_groupbox', 'Arial'),
fontsize=Config.get('fontsize_groupbox', 15),
highlight_color=Config.get("colour_groupbox_border_normal", '#444444'),
inactive=Config.get('colour_groupbox_icon_inactive', '#444444'),
rounded=Config.get('bool_groupbox_rounded_borders', True),
this_current_screen_border=Config.get('colour_groupbox_border_focus', '#ffffff'),
this_screen_border=Config.get('colour_groupbox_border_focus', '#ffffff'),
margin=Config.get('margin_groupbox', 0)
),
widget.Prompt(**self.widget_defaults),
kuro.utils.widgets.KuroTaskList(
border=Config.get('tasklist_border', '#ffffff'),
borderwidth=Config.get('tasklist_borderwidth', 1),
font=Config.get('tasklist_font', 'Arial'),
fontsize=Config.get('tasklist_fontsize', 15),
highlight_method=Config.get('tasklist_highlight_method', 'border'),
max_title_width=Config.get('tasklist_max_title_width', 200),
rounded=Config.get('tasklist_rounded', True),
urgent_alert_method=Config.get('tasklist_urgent_alert_method', 'border'),
urgent_border=Config.get('tasklist_urgent_border', '#ff0000'),
margin=Config.get('margin_groupbox', 0)
)
])
if Config.get('show_audio_visualizer', False):
widgets.append(kuro.utils.widgets.AudioVisualizerWidget(margin_x=0, margin_y=0))
widgets.extend([
kuro.utils.widgets.MediaWidget(ignore_players=Config.get('media_ignore_players', '')),
kuro.utils.widgets.TextSpacerWidget(fontsize=14),
])
if Config.get('show_temperature', False):
widgets.extend([
kuro.utils.widgets.ThermalSensorWidget(
font=Config.get('font_topbar', 'Arial'),
fontsize=Config.get('fontsize_topbar', 16),
foreground=Config.get('thermal_colour', '#ffffff'),
foreground_alert=Config.get('thermal_colour_alert', '#ff0000'),
tag_sensor=Config.get('thermal_sensor', 'temp1'),
chip=Config.get('thermal_chip', None),
threshold=Config.get('thermal_threshold', 70),
update_interval=5,
fontsize_left=18, fontsize_right=11
),
])
widgets.extend([
kuro.utils.widgets.CPUInfoWidget(fontsize_left=16, fontsize_right=11),
kuro.utils.widgets.MemoryInfoWidget(fontsize_left=18, fontsize_right=11),
kuro.utils.widgets.DiskIOInfoWidget(fontsize_left=16, fontsize_right=11),
])
if Config.get('show_battery_widget', False):
widgets.extend([
kuro.utils.widgets.BatteryInfoWidget(fontsize_left=16, fontsize_right=11),
])
widgets.extend([
kuro.utils.widgets.VolumeInfoWidget(
pulse_sink=Config.get('volume_pulse_sink', None),
fontsize_left=18,
fontsize_right=11,
font_left=Config.get('font_groupbox', None),
),
kuro.utils.widgets.VolumeInfoWidget(
pulse_sink=Config.get('volume_pulse_sink2', None),
fontsize_left=18,
fontsize_right=11,
font_left=Config.get('font_groupbox', None),
),
kuro.utils.widgets.TextSpacerWidget(fontsize=14),
kuro.utils.widgets.NetworkInfoWidget(fontsize_left=16, fontsize_right=14),
])
if Config.get('show_gpu_widget', False):
widgets.extend([
kuro.utils.widgets.GPUStatusWidget(
theme_path=Config.get('gpu_theme_path', '/home/docs/checkouts/readthedocs.org/user_builds/qtile'
'/checkouts/latest/libqtile/resources/battery-icons'),
padding=0,
)
])
widgets.extend([
kuro.utils.widgets.TextSpacerWidget(fontsize=14),
])
# Systray can only be on one screen, so put it on the first
if x == 0:
widgets.append(widget.Systray(**self.widget_defaults))
widgets.extend([
kuro.utils.widgets.KuroCurrentLayoutIcon(custom_icon_paths=Config.get('custom_layout_icon_paths', [])),
widget.Clock(format="%a %d %b, %H:%M", **self.widget_defaults),
kuro.utils.widgets.CheckUpdatesYay(
colour_no_updates=Config.get('updates_colour_none', '#ffffff'),
colour_have_updates=Config.get('updates_colour_available', '#ff0000'),
display_format=Config.get('updates_display_format', 'Updates: {updates}'),
execute=Config.get('updates_execute_command', None),
update_interval=Config.get('updates_interval', 600),
**self.widget_defaults
),
widget.TextBox("#{}".format(x), name="default", **self.widget_defaults),
])
topbar = utils.KuroTopBar(
theme=self,
background=Config.get('bar_background', '#000000'),
opacity=Config.get('bar_opacity', 1.0),
widgets=widgets,
size=Config.get('height_groupbox', 30)
)
self.topbars.append(topbar)
screens.append(Screen(top=topbar))
# Add debug bars on each window if debugging is enabled
if Config.get('debug', False):
self.debug_textfields = []
for x in range(self.num_screens):
textfield = widget.TextBox("...", name="debugtext", **self.widget_defaults)
self.debug_textfields.append(textfield)
widgets = []
widgets.extend([
widget.TextBox(" Debugging bar ", name="default", **self.widget_defaults),
textfield,
])
screens[x].bottom = bar.Bar(
widgets=widgets,
size=Config.get('height_debugbar', 30)
)
self.debug_bars.append(screens[x].bottom)
return screens
def init_mouse(self):
self.log_debug("Initializing mouse")
# Drag floating layouts.
mouse = [
Drag([self.mod], "Button1", lazy.window.set_position_floating(),
start=lazy.window.get_position()),
Drag([self.mod], "Button3", lazy.window.set_size_floating(),
start=lazy.window.get_size()),
Click([self.mod], "Button2", lazy.window.bring_to_front())
]
return mouse
def update_keys(self):
self.log_debug("Updating keys")
for i, g in enumerate(self.groups):
if i == 9:
i = -1
elif i > 9:
continue
# mod1 + number = switch to group
self.keys.append(
Key([self.mod], str(i + 1), lazy.group[g.name].toscreen())
)
# mod1 + shift + number = switch to & move focused window to group
self.keys.append(
Key([self.mod, "shift"], str(i + 1), lazy.window.togroup(g.name))
)
# Keys for the Wmii layout
self.keys.extend([
Key([self.mod, "shift"], "j", lazy.layout.shuffle_down()),
Key([self.mod, "shift"], "k", lazy.layout.shuffle_up()),
Key([self.mod, "shift"], "h", lazy.layout.shuffle_left()),
Key([self.mod, "shift"], "l", lazy.layout.shuffle_right()),
Key([self.mod, "shift", "control"], "j", lazy.layout.grow_down()),
Key([self.mod, "shift", "control"], "k", lazy.layout.grow_up()),
Key([self.mod, "shift", "control"], "h", lazy.layout.grow_left()),
Key([self.mod, "shift", "control"], "l", lazy.layout.grow_right()),
Key([self.mod], "s", lazy.layout.toggle_split()),
Key([self.mod], "n", lazy.layout.normalize()),
])
# Util functions
@staticmethod
def redraw_bar(qtile):
for s in qtile.screens:
s.top.draw()
@staticmethod
def update_screens(qtile):
out = utils.call_process(["xrandr", "--current"])
video_mode = "nvidia"
#if "nvidia" in mode_out:
# video_mode = "nvidia"
#elif "intel" in mode_out:
# video_mode = "intel"
laptop_screen = None
screens = []
for x in out.split("\n"):
if " connected " in x:
if Config.get("laptop_screen_nvidia", None) is not None \
and Config.get("laptop_screen_intel", None) is not None:
if video_mode == "nvidia" and Config.get("laptop_screen_nvidia", None) in x:
laptop_screen = x
elif video_mode == "intel" and Config.get("laptop_screen_intel", None) in x:
laptop_screen = x
else:
screens.append(x)
else:
screens.append(x)
# Only configure two screens. Open arandr if more screens are present.
if laptop_screen is not None and len(screens) == 1:
laptop = laptop_screen.split()[0]
other = screens[0].split()[0]
utils.call_process(["xrandr", "--output", laptop, "--below", other])
qtile.cmd_restart()
else:
utils.execute("arandr")
def reinitialize_visualizers(self):
if Config.get("show_audio_visualizer", False):
logger.warning("Reinitializing visualizers...")
for screen in qtile.screens:
for widget in screen.top.widgets:
if isinstance(widget, kuro.utils.widgets.AudioVisualizerWidget):
if widget.client is not None:
widget.client.kill()
widget.client = None
widget.screen = None
self.update_visualizers()
def update_visualizers(self):
if Config.get("show_audio_visualizer", False):
logger.warning("Updating visualizers..")
for screen in qtile.screens:
for widget in screen.top.widgets:
if isinstance(widget, kuro.utils.widgets.AudioVisualizerWidget):
if widget.client is None:
logger.warning("Spawning for screen {}".format(screen))
utils.execute(Config.get('visualizer_app', "glava"))
else:
widget.update_graph()
def show_window_info(self, qtile):
window = qtile.current_window if qtile else None
import pprint
if window:
info = window.cmd_inspect() or None
name = window.name
utils.notify(title="Window properties {}".format(name),
content="{}".format(pprint.pformat(vars(window))))
logger.warning("{}".format(pprint.pformat(vars(window))))
if info:
info = pprint.pformat(info)
utils.notify(title="Window info of {}".format(name),
content="{}".format(info))
logger.warning("{}".format(info))
# @staticmethod
def toggle_window_static(self, qtile):
window = qtile.current_window
if window in self.static_windows:
utils.notify("Unpinned {}".format(window.name), "{} has been unpinned".format(window.name))
self.static_windows.remove(window)
del window.is_static_window
else:
utils.notify("Pinned {}".format(window.name), "{} has been pinned".format(window.name))
self.static_windows.append(window)
window.is_static_window = True
window.floating = True
# Pinned toggle function
@staticmethod
def toggle_pinned(qtile):
windows = qtile.cmd_windows()
print(windows)
# QTile base callbacks
def callback_startup_once(self, *args, **kwargs):
if not hasattr(qtile, 'theme_instance'):
# Save theme instance in qtile
qtile.theme_instance = self
self.update_wallpaper(qtile)
# Setup audio
# p = utils.execute_once(["qjackctl"])
# p.wait()
def callback_startup(self):
if not hasattr(qtile, 'theme_instance'):
# Save theme instance in qtile
qtile.theme_instance = self
if self.current_wallpaper:
p = utils.execute_once(["wal", "-n", "-i", "{}".format(self.current_wallpaper)])
p.wait()
else:
wallpaper = None
if os.path.isfile("/home/kevin/.cache/wal/colors.json"):
with open("/home/kevin/.cache/wal/colors.json", 'r') as f:
try:
wallpaper = json.load(f)['wallpaper']
except KeyError:
wallpaper = None
if wallpaper:
Kuro.set_wallpaper(qtile, wallpaper)
else:
p = utils.execute_once("nitrogen --restore")
p.wait()
self.log_info("Starting compositor...")
utils.execute_once("picom -b")
self.log_info("Starting clipboard manager...")
utils.execute_once("xfce4-clipman")
self.log_info("Starting notification daemon...")
utils.execute_once("dunst")
# Update color scheme
self.initialize_colorscheme()
# def callback_screen_change(self, *args, **kwargs):
# for window in self.static_windows:
# window.togroup()
def callback_setgroup(self, *args, **kwargs):
for window in self.static_windows:
# Only move if the window is not currently on any screen.
if window.group.screen is None:
try:
window.togroup()
except WindowError as e:
logger.warning("Could not move static window {}, removing from list: {}".format(window.name, e))
del window.is_static_window
self.static_windows.remove(window)
def callback_focus_change(self, *args, **kwargs):
if self.do_keyboard_updates:
kb_handle_focus_change(self)
initial_windows = []
def callback_startup_complete(self, *args, **kwargs):
if not hasattr(qtile, 'theme_instance'):
# Save theme instance in qtile
qtile.theme_instance = self
# Only run on first startup
if not qtile.no_spawn:
dg = qtile.dgroups
for r in dg.rules:
pid = -1
# noinspection PyProtectedMember
for m in r.matchlist:
if m._rules.get('net_wm_pid', None) is not None:
pid = m._rules.get('net_wm_pid')
break
if pid != -1:
self.initial_windows.append((pid, r.group))
self.callback_client_new()
# After first startup is complete, start the audio apps that can only be started after boot is complete
if not qtile.no_spawn:
for app in Config.get("apps_audio_afterstart", []):
utils.execute_once(app)
# Update color scheme
Kuro.update_colorscheme(qtile)
def callback_client_new(self, *args, **kwargs):
client = args[0] if len(args) > 0 else None
if len(self.initial_windows) > 0:
init = self.initial_windows.copy()
for pid, gname in init:
for group in qtile.groups:
if len(group.windows) > 0:
for window in group.windows:
w_pid = window.window.get_net_wm_pid()
self.log_info("Comparing pid {} with window PID {}, window {}".format(pid, w_pid,
window.name))
if pid == w_pid:
c = qtile.dgroups.rules_map.copy()
for rid, r in c.items():
if r.matches(window):
qtile.dgroups.remove_rule(rid)
self.initial_windows.remove((pid, gname))
self.log_info("Removed group rule for PID {}, window {}".format(pid,
window.name))
self.log_info(str(qtile.dgroups.rules_map))
# Check if it is a visualizer
if Config.get("show_audio_visualizer", False):
if client is not None and client.window.get_name() == "GLava":
placed = False
for screen in qtile.screens:
for widget in screen.top.widgets:
if not placed and isinstance(widget, kuro.utils.widgets.AudioVisualizerWidget):
if widget.client is None:
viz_info = widget.info()
pos_x = viz_info['offset'] + widget.margin_x
pos_y = 0 + widget.margin_y
width = viz_info['width'] - (2 * widget.margin_x)
height = viz_info['height'] - (2 * widget.margin_y)
screen_index = qtile.screens.index(screen)
logger.warning("Attaching {} {} to {} on screen {}".format(client, client.window.wid, type(widget).__name__, screen_index))
c = KuroStatic.create(client, screen, x=pos_x, y=pos_y, width=width, height=height)
c.opacity = Config.get("bar_opacity", 1.0)
widget.set_client(c, screen)
placed = True
if not placed:
if Config.get("kill_unnecessary_glava_processes", False):
logger.warning("Killing GLava {} because there is no widget where it can fit".format(client))
utils.notify("Glava", "Killing new GLava process because there is no screen without a visualizer")
client.kill()
else:
logger.warning("Not repositioning GLava {} because there is no widget where it can fit".format(client))
utils.notify("Glava", "Not repisitioning new GLava process because there is no screen without a visualizer")
# If this is Non-Mixer, move it to the audio group
logger.warning("Processing window {}".format(client))
if client is not None and client.window.get_wm_class() == ('Non-Mixer', 'Non-Mixer'):
logger.warning("Moving to correct group!")
client.window.togroup("")
def callback_client_killed(self, *args, **kwargs):
client = args[0]
logger.warning("Client {} Killed".format(client))
# Detach visualizer from widget if it was a visualizer window
if isinstance(client, KuroStatic):
for screen in qtile.screens:
for widget in screen.top.widgets:
if isinstance(widget, kuro.utils.widgets.AudioVisualizerWidget):
if widget.client == client:
screen_index = qtile.screens.index(screen)
logger.warning("Detaching {} {} from widget {} on screen {}".format(client, client.window.wid, type(widget).__name__, screen_index))
widget.client = None
widget.screen = None
# If this window was static, remove it from the static window list
if hasattr(client, "is_static_window") and client.is_static_window:
logger.warning("Removing static window {}".format(client.name))
del client.is_static_window
self.static_windows.remove(client)
@staticmethod
def update_wallpaper(qtile):
wallpapers = []
wallpaper_dir = Config.get("desktop_bg_folder", "")
try:
wallpapers = [x for x in os.listdir(wallpaper_dir) if ".vertical." not in x]
except os.error as e:
logger.warning("Could not load wallpapers from directory: {}".format(e))
if wallpapers:
if Config.get("desktop_bg_override", False):
qtile.theme_instance.current_wallpaper = Config.get("desktop_bg_override", "")
else:
qtile.theme_instance.current_wallpaper = os.path.join(wallpaper_dir, random.choice(wallpapers))
Kuro.set_wallpaper(qtile, qtile.theme_instance.current_wallpaper)
else:
utils.execute_once("nitrogen --restore")
@staticmethod
def set_wallpaper(qtile, filename):
p = utils.execute_once("{} {}".format(Config.get('wallpaper_config_command', 'wal-nitrogen-noupdate'),
filename))
p.wait()
qtile.theme_instance.current_wallpaper = filename
Kuro.update_colorscheme(qtile)
@staticmethod
def update_mediaclients(*args, **kwargs):
return str(str(args) + " " + str(kwargs))
@staticmethod
def initialize_colorscheme():
colors = None
if os.path.isfile("/home/kevin/.cache/wal/colors.json"):
with open("/home/kevin/.cache/wal/colors.json", 'r') as f:
try:
colors = json.load(f)['colors']
except KeyError:
colors = None
if colors:
# Update Config
Config.foreground = colors['color15']
Config.background = colors['color0']
Config.highlight = colors['color3']
Config.inactive_light = colors['color4']
Config.inactive_dark = colors['color5']
Config.bar_background = colors['color1']
@staticmethod
def update_colorscheme(qtile):
"""
:type qtile: libqtile.manager.Qtile
"""
if qtile.theme_instance.current_wallpaper:
p = utils.execute(["wal", "-n", "-i", "{}".format(qtile.theme_instance.current_wallpaper)])
p.wait()
colors = None
if os.path.isfile("/home/kevin/.cache/wal/colors.json"):
with open("/home/kevin/.cache/wal/colors.json", 'r') as f:
try:
colors = json.load(f)['colors']
except KeyError:
colors = None
if colors:
# Update Config
Config.foreground = colors['color15']
Config.background = colors['color0']
Config.highlight = colors['color3']
Config.inactive_light = colors['color4']
Config.inactive_dark = colors['color5']
Config.bar_background = colors['color1']
# Update border colors in layouts
for group in qtile.groups:
for layout in group.layouts:
if isinstance(layout, kuro_layouts.KuroWmii):
layout.border_focus = colors['color15']
layout.border_focus_stack = colors['color1']
layout.border_normal = colors['color1']
layout.border_normal_stack = colors['color1']
for screen in qtile.screens:
bar = screen.top
bar.background = colors['color1']
bar.drawer.clear(bar.background)
for w in bar.widgets:
if hasattr(w, '_update_drawer'):
try:
w._update_drawer()
except Exception as e:
logger.error("Error while updating drawer for widget {}: {}".format(w, e))
if hasattr(w, 'foreground'):
w.foreground = colors['color15']
if hasattr(w, 'foreground_normal'):
w.foreground_normal = colors['color15']
if hasattr(w, 'foreground_alert'):
w.foreground_alert = colors['color3']
if hasattr(w, 'border'):
w.border = colors['color15']
if hasattr(w, 'active'):
w.active = colors['color15']
if hasattr(w, 'highlight_color'):
w.highlight_color = colors['color3']
if hasattr(w, 'inactive'):
w.inactive = colors['color8']
if hasattr(w, 'this_current_screen_border'):
w.this_current_screen_border = colors['color15']
if hasattr(w, 'this_screen_border'):
w.this_screen_border = colors['color15']
if hasattr(w, 'other_current_screen_border'):
w.other_current_screen_border = colors['color8']
if hasattr(w, 'other_screen_border'):
w.other_screen_border = colors['color8']
if isinstance(w, kuro.utils.widgets.AudioVisualizerWidget):
w.graph_color = colors['color15']
w.fill_color = colors['color8']
bar.draw()
# Update colors in visualizers and restart visualizers
with open(Config.get("glava_color_file_path", "~/.config/glava/kurobars_color.glsl"), 'w') as f:
f.write("#define COLOR {}\n#request setbg {}00".format(colors['color15'], colors['color1'][1:]))
qtile.theme_instance.reinitialize_visualizers()
utils.notify(
"Updated colorscheme!",
"active: {}, inactive: {}".format(colors['color15'], colors['color1'])
)