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 from libqtile.command import lazy from libqtile import layout, bar, widget 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=[ {'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 ]) def set_debug_text(self, text): for field in self.debug_textfields: field.text = text for bar in self.debug_bars: if self.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], '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'))), # 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"), layout='verticaltile', layouts=[ layout.VerticalTile( border_focus=Config.get('colour_border_focus', "#ffffff"), border_normal=Config.get('colour_border_normal', "#777777"), border_width=Config.get('width_border', "1"), margin=Config.get('margin_layout', "0"), ) ])) 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), **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, qtile=None): if Config.get("show_audio_visualizer", False): logger.warning("Reinitializing visualizers...") for screen in self.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(qtile=qtile) def update_visualizers(self, qtile=None): if Config.get("show_audio_visualizer", False): logger.warning("Updating visualizers..") for screen in self.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): self.update_wallpaper(self.qtile) # Setup audio # p = utils.execute_once(["qjackctl"]) # p.wait() def callback_startup(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(self.qtile, wallpaper) else: p = utils.execute_once("nitrogen --restore") p.wait() self.log_info("Starting compositor...") utils.execute_once("compton -b") self.log_info("Starting clipboard manager...") utils.execute_once("xfce4-clipman") # 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): # Only run on first startup if not self.qtile.no_spawn: dg = self.qtile.dgroups for r in dg.rules: pid = -1 # noinspection PyProtectedMember for r2 in r.match._rules: if r2[0] == "net_wm_pid": pid = r2[1] 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 self.qtile.no_spawn: for app in Config.get("apps_audio_afterstart", []): utils.execute_once(app) # Update color scheme Kuro.update_colorscheme(self.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 self.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 = self.qtile.dgroups.rules_map.copy() for rid, r in c.items(): if r.matches(window): self.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(self.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 self.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 = self.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.set_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 {}".format(colors['color15'], colors['color1'][1:])) qtile.theme_instance.reinitialize_visualizers() utils.notify( "Updated colorscheme!", "active: {}, inactive: {}".format(colors['color15'], colors['color1']) )