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 ]) 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()), # 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'))), # 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("")) 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(), 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), kuro.utils.widgets.BatteryInfoWidget(fontsize_left=16, fontsize_right=11), kuro.utils.widgets.VolumeInfoWidget( pulse_sink=Config.get('volume_pulse_sink', None), fontsize_left=18, fontsize_right=11, ), kuro.utils.widgets.TextSpacerWidget(fontsize=14), kuro.utils.widgets.NetworkInfoWidget(fontsize_left=16, fontsize_right=14), 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, ), 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"]) #mode_out = utils.call_process(["optimus-manager", "--print-mode"]) 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 # 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 self.qtile.screens: for widget in screen.top.widgets: if isinstance(widget, kuro.utils.widgets.AudioVisualizerWidget): if widget.client == client: screen_index = self.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 = os.listdir(wallpaper_dir) 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']) )