From 2dfb5381ae390b82d671de724357343ecb0901bb Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Thu, 15 Apr 2021 17:18:04 +0200 Subject: [PATCH 01/17] Changes to Aria --- kuro/utils/widgets.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kuro/utils/widgets.py b/kuro/utils/widgets.py index a122a50..a32d571 100644 --- a/kuro/utils/widgets.py +++ b/kuro/utils/widgets.py @@ -337,19 +337,19 @@ class MediaWidget(base.InLoopPollText): if data['playing'] and data['muted']: self.custom_player_data['firefox']['showing'] = True self.custom_player_data['firefox']['state'] = MediaWidget.Status.PAUSED - self.custom_player_data['firefox']['title'] = data['title'] + self.custom_player_data['firefox']['title'] = data['title'][:50] elif data['playing'] and not data['muted']: self.custom_player_data['firefox']['showing'] = True self.custom_player_data['firefox']['state'] = MediaWidget.Status.PLAYING - self.custom_player_data['firefox']['title'] = data['title'] + self.custom_player_data['firefox']['title'] = data['title'][:50] elif not data['playing'] and data['muted']: self.custom_player_data['firefox']['showing'] = True self.custom_player_data['firefox']['state'] = MediaWidget.Status.STOPPED - self.custom_player_data['firefox']['title'] = data['title'] + self.custom_player_data['firefox']['title'] = data['title'][:50] elif not data['playing'] and not data['muted']: self.custom_player_data['firefox']['showing'] = False self.custom_player_data['firefox']['state'] = MediaWidget.Status.OFFLINE - self.custom_player_data['firefox']['title'] = data['title'] + self.custom_player_data['firefox']['title'] = data['title'][:50] def _get_players(self): players = [] @@ -399,7 +399,7 @@ class MediaWidget(base.InLoopPollText): text = "Unknown" if cmd_result in ["Playing", "Paused"]: artist = self.call_process(['playerctl', '-p', player, 'metadata', 'artist']).strip() - title = self.call_process(['playerctl', '-p', player, 'metadata', 'title']).strip() + title = self.call_process(['playerctl', '-p', player, 'metadata', 'title']).strip()[:50] if artist and title: text = "{} - {}".format(artist, title) From f775ce8b03267643866a363eac1758bf597c9749 Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Thu, 15 Apr 2021 17:35:02 +0200 Subject: [PATCH 02/17] Update Aria config to latest qtile version --- kuro/base.py | 24 +++++------- kuro/theme.py | 45 +++++++++-------------- kuro/utils/general.py | 9 ++++- kuro/utils/layouts.py | 85 ++++++++++++++++++------------------------- 4 files changed, 70 insertions(+), 93 deletions(-) diff --git a/kuro/base.py b/kuro/base.py index fd7bc84..370c02f 100644 --- a/kuro/base.py +++ b/kuro/base.py @@ -1,6 +1,6 @@ from libqtile import layout as libqtile_layout, layout, bar, widget from libqtile.command import lazy -from libqtile.config import Key, Group, Screen, Drag, Click +from libqtile.config import Key, Group, Screen, Drag, Click, Match class BaseConfig: @@ -29,20 +29,14 @@ class BaseTheme: bring_front_click = False cursor_warp = False floating_layout = libqtile_layout.Floating(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 + # 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 ]) auto_fullscreen = True focus_on_window_activation = "smart" diff --git a/kuro/theme.py b/kuro/theme.py index ac322df..9e14eaa 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -7,7 +7,7 @@ from libqtile.log_utils import logger logger.error("Importing qtile theme requirements...") -from libqtile.config import Key, Screen, Group, Drag, Click +from libqtile.config import Key, Screen, Group, Drag, Click, Match from libqtile.command import lazy from libqtile import layout, bar, widget @@ -75,20 +75,14 @@ class Kuro(BaseTheme): # 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 + # 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): @@ -242,14 +236,7 @@ class Kuro(BaseTheme): 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("", spawn=Config.get('apps_audio', "true"))) groups.append(Group("", layout='floating', layouts=[ layout.Floating( border_focus="#990000", @@ -385,6 +372,7 @@ class Kuro(BaseTheme): 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), @@ -591,11 +579,14 @@ class Kuro(BaseTheme): p.wait() self.log_info("Starting compositor...") - utils.execute_once("compton -b") + 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() @@ -627,9 +618,9 @@ class Kuro(BaseTheme): for r in dg.rules: pid = -1 # noinspection PyProtectedMember - for r2 in r.match._rules: - if r2[0] == "net_wm_pid": - pid = r2[1] + 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)) diff --git a/kuro/utils/general.py b/kuro/utils/general.py index da8d96b..ff5893f 100644 --- a/kuro/utils/general.py +++ b/kuro/utils/general.py @@ -12,7 +12,10 @@ from libqtile.bar import Bar from notify2 import Notification, URGENCY_NORMAL from libqtile.log_utils import logger -notify2.init("QTileWM") +try: + notify2.init("QTileWM") +except DBusException as e: + logger.error("Could not initialize notify2: {}".format(e)) BUTTON_LEFT = 1 BUTTON_MIDDLE = 2 @@ -100,6 +103,10 @@ def notify(title, content, urgency=URGENCY_NORMAL, timeout=5000, image=None): try: return notification.show() + except notify2.UninittedError: + logger.warning("Notify2 was uninitialized, initializing...") + notify2.init("qtile") + return notification.show() except DBusException as e: logger.warning("Showing notification failed: {}".format(e)) logger.warning(traceback.format_exc()) diff --git a/kuro/utils/layouts.py b/kuro/utils/layouts.py index c12007c..e74dee6 100644 --- a/kuro/utils/layouts.py +++ b/kuro/utils/layouts.py @@ -15,68 +15,53 @@ class KuroFloating(Floating): super(KuroFloating, self).__init__(*args, **kwargs) self.add_defaults(KuroFloating.defaults) - def configure(self, client, screen): - # 'sun-awt-X11-XWindowPeer' is a dropdown used in Java application, - # don't reposition it anywhere, let Java app to control it - cls = client.window.get_wm_class() or '' - is_java_dropdown = 'sun-awt-X11-XWindowPeer' in cls - if is_java_dropdown: - return - + def configure(self, client, screen_rect): if hasattr(client, "is_static_window") and client.is_static_window: - bc = client.group.qtile.color_pixel(self.border_static) + bc = self.border_static elif client.has_focus: - bc = client.group.qtile.color_pixel(self.border_focus) + bc = self.border_focus else: - bc = client.group.qtile.color_pixel(self.border_normal) + bc = self.border_normal + if client.maximized: bw = self.max_border_width elif client.fullscreen: bw = self.fullscreen_border_width else: bw = self.border_width - above = False - # We definitely have a screen here, so let's be sure we'll float on screen - try: - client.float_x - client.float_y - except AttributeError: - # this window hasn't been placed before, let's put it in a sensible spot - transient_for = client.window.get_wm_transient_for() - win = client.group.qtile.windows_map.get(transient_for) - if win is not None: - # if transient for a window, place in the center of the window - center_x = win.x + win.width / 2 - center_y = win.y + win.height / 2 - else: - center_x = screen.x + screen.width / 2 - center_y = screen.y + screen.height / 2 - above = True + # 'sun-awt-X11-XWindowPeer' is a dropdown used in Java application, + # don't reposition it anywhere, let Java app to control it + cls = client.window.get_wm_class() or '' + is_java_dropdown = 'sun-awt-X11-XWindowPeer' in cls + if is_java_dropdown: + client.paint_borders(bc, bw) + client.cmd_bring_to_front() - x = center_x - client.width / 2 - y = center_y - client.height / 2 + # alternatively, users may have asked us explicitly to leave the client alone + elif any(m.compare(client) for m in self.no_reposition_rules): + client.paint_borders(bc, bw) + client.cmd_bring_to_front() - # don't go off the right... - x = min(x, screen.x + screen.width) - # or left... - x = max(x, screen.x) - # or bottom... - y = min(y, screen.y + screen.height) - # or top - y = max(y, screen.y) + else: + above = False - if not (self.no_reposition_match and self.no_reposition_match.compare(client)): - client.x = int(round(x)) - client.y = int(round(y)) + # We definitely have a screen here, so let's be sure we'll float on screen + try: + client.float_x + client.float_y + except AttributeError: + # this window hasn't been placed before, let's put it in a sensible spot + above = self.compute_client_position(client, screen_rect) - client.place( - client.x, - client.y, - client.width, - client.height, - bw, - bc, - above, - ) + + client.place( + client.x, + client.y, + client.width, + client.height, + bw, + bc, + above, + ) client.unhide() From 8f4f08e3bf058844ae56c4722ff9c1ca3fbb991e Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Mon, 13 Sep 2021 19:56:40 +0200 Subject: [PATCH 03/17] Update Aria config to latest qtile version and newest config --- config.py | 6 ++++++ kuro/config.py | 2 +- kuro/utils/general.py | 2 +- kuro/utils/widgets.py | 2 +- kuro/utils/windows.py | 3 +-- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/config.py b/config.py index c3abfcd..46c84be 100644 --- a/config.py +++ b/config.py @@ -27,28 +27,33 @@ # Import Theme from libqtile import hook from libqtile.log_utils import logger +import traceback try: from kuro.theme import Kuro Theme = Kuro() except ImportError as e: + logger.error(traceback.format_exc()) logger.error("Could not load Kuro Theme. Trying to load BaseTheme. Error: {}".format(e)) try: from kuro.base import BaseTheme as Kuro Theme = Kuro() except ImportError as e: Kuro = None + logger.error(traceback.format_exc()) raise ImportError("Could not load theme Config or BaseTheme! Error: {}".format(e)) # Import theme configuration try: from kuro.config import Config except ImportError as e: + logger.error(traceback.format_exc()) logger.error("Could not load Kuro Config. Trying to load BaseConfig. Error: {}".format(e)) try: from kuro.base import BaseConfig as Config except ImportError as e: Config = None + logger.error(traceback.format_exc()) raise ImportError("Could not load theme Config or BaseConfig! Error: {}".format(e)) @@ -108,6 +113,7 @@ try: except Exception as e: Theme = None Config = None + logger.error(traceback.format_exc()) raise AttributeError("Could not configure theme! Error: {}".format(e)) diff --git a/kuro/config.py b/kuro/config.py index 05f2f87..e178ee6 100644 --- a/kuro/config.py +++ b/kuro/config.py @@ -19,7 +19,7 @@ class Config(BaseConfig): app_launcher = "/home/kevin/bin/dmenu_wal.sh" web_browser = "firefox-developer-edition" file_manager = "thunar" - app_chat = "/home/kevin/bin/ramboxpro" + app_chat = "ramboxpro" app_irc = "quasselclient" app_mail = "thunderbird" cmd_brightness_up = "sudo /usr/bin/xbacklight -inc 10" diff --git a/kuro/utils/general.py b/kuro/utils/general.py index ff5893f..8a432b0 100644 --- a/kuro/utils/general.py +++ b/kuro/utils/general.py @@ -7,7 +7,7 @@ import notify2 import six from dbus import DBusException from libqtile import widget -from libqtile.window import Internal +from libqtile.backend.x11.window import Internal from libqtile.bar import Bar from notify2 import Notification, URGENCY_NORMAL from libqtile.log_utils import logger diff --git a/kuro/utils/widgets.py b/kuro/utils/widgets.py index a32d571..7473717 100644 --- a/kuro/utils/widgets.py +++ b/kuro/utils/widgets.py @@ -18,7 +18,7 @@ from libqtile.widget.currentlayout import CurrentLayoutIcon from libqtile.widget.graph import _Graph from libqtile.widget.tasklist import TaskList from libqtile.widget.wlan import get_status -from libqtile.window import Window +from libqtile.backend.x11.window import Window from kuro.utils.general import notify, BUTTON_LEFT, BUTTON_MIDDLE, BUTTON_RIGHT, BUTTON_DOWN, BUTTON_UP, BUTTON_MUTE, \ call_process diff --git a/kuro/utils/windows.py b/kuro/utils/windows.py index edaf7ac..6bfd997 100644 --- a/kuro/utils/windows.py +++ b/kuro/utils/windows.py @@ -1,7 +1,6 @@ from cairocffi.test_xcb import xcffib from libqtile import hook -from libqtile.window import Window, Static - +from libqtile.backend.x11.window import Window, Static class KuroStatic(Static): From 0f4ef9190a657e8a060c660dd85d0e04cb46164a Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Mon, 22 Nov 2021 20:47:16 +0100 Subject: [PATCH 04/17] Refactor usage of qtile object and improvements to media widget --- config.py | 3 --- kuro/config.py | 2 +- kuro/theme.py | 54 +++++++++++++++++++++++++------------------ kuro/utils/widgets.py | 39 +++++++++++++++++++++++-------- 4 files changed, 62 insertions(+), 36 deletions(-) diff --git a/config.py b/config.py index 46c84be..75af0da 100644 --- a/config.py +++ b/config.py @@ -127,8 +127,5 @@ def main(qtile): else: qtile.cmd_warning() - # Save qtile instance in theme - Theme.qtile = qtile - # Save theme instance in qtile qtile.theme_instance = Theme diff --git a/kuro/config.py b/kuro/config.py index e178ee6..5d06eb3 100644 --- a/kuro/config.py +++ b/kuro/config.py @@ -19,7 +19,7 @@ class Config(BaseConfig): app_launcher = "/home/kevin/bin/dmenu_wal.sh" web_browser = "firefox-developer-edition" file_manager = "thunar" - app_chat = "ramboxpro" + app_chat = "/usr/bin/ramboxpro" app_irc = "quasselclient" app_mail = "thunderbird" cmd_brightness_up = "sudo /usr/bin/xbacklight -inc 10" diff --git a/kuro/theme.py b/kuro/theme.py index 9e14eaa..2226c5e 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -9,7 +9,7 @@ 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 +from libqtile import layout, bar, widget, qtile logger.error("Importing theme util functions...") @@ -89,7 +89,7 @@ class Kuro(BaseTheme): for field in self.debug_textfields: field.text = text for bar in self.debug_bars: - if self.qtile is not None: + if qtile is not None: bar.draw() def log_debug(self, text): @@ -496,22 +496,22 @@ class Kuro(BaseTheme): else: utils.execute("arandr") - def reinitialize_visualizers(self, qtile=None): + def reinitialize_visualizers(self): if Config.get("show_audio_visualizer", False): logger.warning("Reinitializing visualizers...") - for screen in self.qtile.screens: + 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(qtile=qtile) + self.update_visualizers() - def update_visualizers(self, qtile=None): + def update_visualizers(self): if Config.get("show_audio_visualizer", False): logger.warning("Updating visualizers..") - for screen in self.qtile.screens: + for screen in qtile.screens: for widget in screen.top.widgets: if isinstance(widget, kuro.utils.widgets.AudioVisualizerWidget): if widget.client is None: @@ -554,13 +554,20 @@ class Kuro(BaseTheme): # QTile base callbacks def callback_startup_once(self, *args, **kwargs): - self.update_wallpaper(self.qtile) + 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() @@ -573,7 +580,7 @@ class Kuro(BaseTheme): except KeyError: wallpaper = None if wallpaper: - Kuro.set_wallpaper(self.qtile, wallpaper) + Kuro.set_wallpaper(qtile, wallpaper) else: p = utils.execute_once("nitrogen --restore") p.wait() @@ -612,9 +619,13 @@ class Kuro(BaseTheme): 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 self.qtile.no_spawn: - dg = self.qtile.dgroups + if not qtile.no_spawn: + dg = qtile.dgroups for r in dg.rules: pid = -1 # noinspection PyProtectedMember @@ -628,12 +639,12 @@ class Kuro(BaseTheme): 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: + if not qtile.no_spawn: for app in Config.get("apps_audio_afterstart", []): utils.execute_once(app) # Update color scheme - Kuro.update_colorscheme(self.qtile) + Kuro.update_colorscheme(qtile) def callback_client_new(self, *args, **kwargs): client = args[0] if len(args) > 0 else None @@ -641,27 +652,27 @@ class Kuro(BaseTheme): if len(self.initial_windows) > 0: init = self.initial_windows.copy() for pid, gname in init: - for group in self.qtile.groups: + 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 = self.qtile.dgroups.rules_map.copy() + c = qtile.dgroups.rules_map.copy() for rid, r in c.items(): if r.matches(window): - self.qtile.dgroups.remove_rule(rid) + 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)) + 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 self.qtile.screens: + 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: @@ -670,10 +681,10 @@ class Kuro(BaseTheme): 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) + 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.set_opacity(Config.get("bar_opacity", 1.0)) + c.opacity = Config.get("bar_opacity", 1.0) widget.set_client(c, screen) placed = True if not placed: @@ -692,7 +703,6 @@ class Kuro(BaseTheme): client.window.togroup("") - def callback_client_killed(self, *args, **kwargs): client = args[0] logger.warning("Client {} Killed".format(client)) @@ -853,7 +863,7 @@ class Kuro(BaseTheme): # 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:])) + f.write("#define COLOR {}\n#request setbg {}00".format(colors['color15'], colors['color1'][1:])) qtile.theme_instance.reinitialize_visualizers() utils.notify( diff --git a/kuro/utils/widgets.py b/kuro/utils/widgets.py index 7473717..c32532c 100644 --- a/kuro/utils/widgets.py +++ b/kuro/utils/widgets.py @@ -260,6 +260,7 @@ class MediaWidget(base.InLoopPollText): ('on_text_pause', ' {}', 'The pattern for the text if music is paused.'), ('on_text_stop', ' {}', 'The pattern for the text if music is stopped.'), ('update_interval', 1, 'The update interval.'), + ('max_chars_per_player', 50, 'Maximum characters of text per player.'), ] player_icons = { @@ -333,7 +334,7 @@ class MediaWidget(base.InLoopPollText): def cmd_update_custom_player(self, player_name, data): # Update firefox player - if player_name == "firefox": + if player_name.startswith("firefox"): if data['playing'] and data['muted']: self.custom_player_data['firefox']['showing'] = True self.custom_player_data['firefox']['state'] = MediaWidget.Status.PAUSED @@ -355,8 +356,11 @@ class MediaWidget(base.InLoopPollText): players = [] # Playerctl players - command = ["playerctl", "-l"] - result = self.call_process(command) + try: + result = self.call_process(["playerctl", "-l"]) + except subprocess.CalledProcessError: + result = None + if result: players.extend([x for x in result.split("\n") if x]) @@ -398,8 +402,14 @@ class MediaWidget(base.InLoopPollText): text = "Unknown" if cmd_result in ["Playing", "Paused"]: - artist = self.call_process(['playerctl', '-p', player, 'metadata', 'artist']).strip() - title = self.call_process(['playerctl', '-p', player, 'metadata', 'title']).strip()[:50] + try: + artist = self.call_process(['playerctl', '-p', player, 'metadata', 'artist']).strip() + except subprocess.CalledProcessError: + artist = None + try: + title = self.call_process(['playerctl', '-p', player, 'metadata', 'title']).strip() + except subprocess.CalledProcessError: + title = None if artist and title: text = "{} - {}".format(artist, title) @@ -419,13 +429,17 @@ class MediaWidget(base.InLoopPollText): def _get_formatted_text(self, status): if status[0] == MediaWidget.Status.PLAYING: - return self.on_text_play.format(status[1]) + res = self.on_text_play.format(status[1]) elif status[0] == MediaWidget.Status.PAUSED: - return self.on_text_pause.format(status[1]) + res = self.on_text_pause.format(status[1]) elif status[0] == MediaWidget.Status.STOPPED: - return self.on_text_stop.format(status[1]) + res = self.on_text_stop.format(status[1]) else: - return "Unknown" + res = "Unknown" + res = pangocffi.markup_escape_text(res) + if len(res) > self.max_chars_per_player: + res = res[:self.max_chars_per_player] + "..." + return res def draw(self): super(MediaWidget, self).draw() @@ -437,7 +451,12 @@ class MediaWidget(base.InLoopPollText): return self.off_text else: for player in status.keys(): - icon = self.player_icons.get(player, player) + # Shorten firefox.instance[0-9]+ to just firefox for icon finding + if player.startswith("firefox"): + player_icon = "firefox" + else: + player_icon = player + icon = self.player_icons.get(player_icon, player_icon) text.append("{} {}".format(icon, self._get_formatted_text(status[player]))) return " | ".join(text) if text else self.off_text From 3b6ee3d20ddeb51457424cbeffc570569b61e5b4 Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Sat, 28 May 2022 14:01:07 +0200 Subject: [PATCH 05/17] Fixes for crash and updates --- kuro/config.py | 2 +- kuro/utils/general.py | 2 +- kuro/utils/widgets.py | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/kuro/config.py b/kuro/config.py index 5d06eb3..b942998 100644 --- a/kuro/config.py +++ b/kuro/config.py @@ -19,7 +19,7 @@ class Config(BaseConfig): app_launcher = "/home/kevin/bin/dmenu_wal.sh" web_browser = "firefox-developer-edition" file_manager = "thunar" - app_chat = "/usr/bin/ramboxpro" + app_chat = "/usr/bin/rambox" app_irc = "quasselclient" app_mail = "thunderbird" cmd_brightness_up = "sudo /usr/bin/xbacklight -inc 10" diff --git a/kuro/utils/general.py b/kuro/utils/general.py index 8a432b0..5bc12bc 100644 --- a/kuro/utils/general.py +++ b/kuro/utils/general.py @@ -196,7 +196,7 @@ class KuroTopBar(Bar): self.theme = theme super(KuroTopBar, self).__init__(widgets, size, **config) - def _configure(self, qtile, screen): + def _configure(self, qtile, screen, *args, **kwargs): super(KuroTopBar, self)._configure(qtile, screen) self.window.handle_EnterNotify = self.handle_enter_notify self.window.handle_LeaveNotify = self.handle_leave_notify diff --git a/kuro/utils/widgets.py b/kuro/utils/widgets.py index c32532c..36e1283 100644 --- a/kuro/utils/widgets.py +++ b/kuro/utils/widgets.py @@ -8,6 +8,7 @@ import iwlib import netifaces import psutil import six +import unicodedata from libqtile import bar, pangocffi from libqtile.log_utils import logger from libqtile.widget import base @@ -437,6 +438,7 @@ class MediaWidget(base.InLoopPollText): else: res = "Unknown" res = pangocffi.markup_escape_text(res) + res = unicodedata.normalize("NFKD", res) if len(res) > self.max_chars_per_player: res = res[:self.max_chars_per_player] + "..." return res From a043d8d452df81d6e3d90ab55cd266b8a75015fc Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Mon, 4 Mar 2024 14:44:38 +0100 Subject: [PATCH 06/17] Default apps changes --- kuro/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kuro/config.py b/kuro/config.py index b942998..dc21c57 100644 --- a/kuro/config.py +++ b/kuro/config.py @@ -17,7 +17,7 @@ class Config(BaseConfig): # Default Applications app_terminal = "terminator" app_launcher = "/home/kevin/bin/dmenu_wal.sh" - web_browser = "firefox-developer-edition" + web_browser = "firefox" file_manager = "thunar" app_chat = "/usr/bin/rambox" app_irc = "quasselclient" @@ -149,7 +149,7 @@ class Config(BaseConfig): do_keyboard_updates = False # Show audio visualizer - show_audio_visualizer = True + show_audio_visualizer = False kill_unnecessary_glava_processes = True # Show thermal widget From 12238c2b6c83bb1d05095cf2e5c5410d67811cfe Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Mon, 21 Jul 2025 00:54:30 +0200 Subject: [PATCH 07/17] General updates and fixes, ghostty terminal emulator, wallust colors, different wallpaper set at night --- config_debug.py | 2 +- kuro/base.py | 2 +- kuro/config.py | 8 +++++--- kuro/theme.py | 26 ++++++++++++++++++++------ kuro/utils/widgets.py | 31 +++++++++++++++++++------------ 5 files changed, 46 insertions(+), 23 deletions(-) diff --git a/config_debug.py b/config_debug.py index 8dbfaff..3aa6617 100644 --- a/config_debug.py +++ b/config_debug.py @@ -25,7 +25,7 @@ # SOFTWARE. from libqtile.config import Key, Screen, Group, Drag, Click -from libqtile.command import lazy +from libqtile.lazy import lazy from libqtile import layout, bar, widget diff --git a/kuro/base.py b/kuro/base.py index 370c02f..221d1fd 100644 --- a/kuro/base.py +++ b/kuro/base.py @@ -1,5 +1,5 @@ from libqtile import layout as libqtile_layout, layout, bar, widget -from libqtile.command import lazy +from libqtile.lazy import lazy from libqtile.config import Key, Group, Screen, Drag, Click, Match diff --git a/kuro/config.py b/kuro/config.py index 6761564..5bc2ce7 100644 --- a/kuro/config.py +++ b/kuro/config.py @@ -15,12 +15,13 @@ class Config(BaseConfig): inactive_dark = "#333333" # Default Applications - app_terminal = "terminator" + app_terminal = "ghostty" + app_terminal_init = "ghostty --gtk-single-instance=true --quit-after-last-window-close=false --initial-window=true" app_launcher = "/home/kevin/bin/dmenu_wal.sh" web_browser = "firefox" file_manager = "thunar" app_chat = "/usr/bin/rambox" - app_irc = "quasselclient" + app_irc = "" app_mail = "thunderbird" app_music = "spotify" cmd_brightness_up = "sudo /usr/bin/xbacklight -inc 10" @@ -49,7 +50,8 @@ class Config(BaseConfig): # Images desktop_bg = "/home/kevin/Pictures/wallpapers/desktop.png" - desktop_bg_folder = "/home/kevin/Pictures/wallpapers/desktop_rotation" + desktop_bg_folder = "/home/kevin/Pictures/wallpapers/desktop_rotation/day" + desktop_bg_night_folder = "/home/kevin/Pictures/wallpapers/desktop_rotation/night" # desktop_bg_override = "/home/kevin/Pictures/safe_wallpaper.jpg" applauncher_image = "/home/kevin/.config/qtile/kuro/resources/arch.png" custom_layout_icon_paths = ['/home/kevin/.config/qtile/kuro/resources/layout_icons/'] diff --git a/kuro/theme.py b/kuro/theme.py index f85eb9e..b83e0d6 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -1,6 +1,7 @@ import json import os import random +import datetime # Initialize logging from libqtile.log_utils import logger @@ -8,7 +9,8 @@ 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.command.base import expose_command +from libqtile.lazy import lazy from libqtile import layout, bar, widget, qtile logger.error("Importing theme util functions...") @@ -248,7 +250,7 @@ class Kuro(BaseTheme): # 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("", spawn=Config.get('app_terminal_init', "true"))) groups.append(Group("")) groups.append(Group("", spawn=Config.get('app_chat', "true"))) groups.append(Group("", spawn=Config.get('app_irc', "true"))) @@ -612,7 +614,8 @@ class Kuro(BaseTheme): qtile.theme_instance = self if self.current_wallpaper: - p = utils.execute_once(["wal", "-n", "-i", "{}".format(self.current_wallpaper)]) + #p = utils.execute_once(["wal", "-n", "-i", "{}".format(self.current_wallpaper)]) + p = utils.execute_once(["wallust", "run", "{}".format(self.current_wallpaper)]) p.wait() else: wallpaper = None @@ -640,8 +643,8 @@ class Kuro(BaseTheme): self.log_info("Starting xiccd color profile manager...") utils.execute_once("xiccd") - self.log_info("Starting KDE connect daemon...") - utils.execute_once("/usr/lib/kdeconnectd") + #self.log_info("Starting KDE connect daemon...") + #utils.execute_once("/usr/lib/kdeconnectd") self.log_info("Starting KDE connect indicator...") utils.execute_once("/usr/bin/kdeconnect-indicator") @@ -784,16 +787,26 @@ class Kuro(BaseTheme): def update_wallpaper(qtile): wallpapers = [] wallpaper_dir = Config.get("desktop_bg_folder", "") + + # Use a wallpaper from the night folder after 9PM and before 6AM + wallpaper_night_dir = Config.get("desktop_bg_night_folder", "") + if wallpaper_night_dir and os.path.isdir(wallpaper_night_dir): + cur_time = datetime.datetime.now() + if cur_time.hour > 21 or cur_time.hour < 6: + wallpaper_dir = wallpaper_night_dir + 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)) + logger.warning("Selected new wallpaper: {}".format(qtile.theme_instance.current_wallpaper)) Kuro.set_wallpaper(qtile, qtile.theme_instance.current_wallpaper) else: utils.execute_once("nitrogen --restore") @@ -838,7 +851,8 @@ class Kuro(BaseTheme): :type qtile: libqtile.manager.Qtile """ if qtile.theme_instance.current_wallpaper: - p = utils.execute(["wal", "-n", "-i", "{}".format(qtile.theme_instance.current_wallpaper)]) + #p = utils.execute(["wal", "-n", "-i", "{}".format(qtile.theme_instance.current_wallpaper)]) + p = utils.execute(["wallust", "run", "{}".format(qtile.theme_instance.current_wallpaper)]) p.wait() colors = None diff --git a/kuro/utils/widgets.py b/kuro/utils/widgets.py index d03c0da..442595c 100644 --- a/kuro/utils/widgets.py +++ b/kuro/utils/widgets.py @@ -11,6 +11,7 @@ import six import unicodedata from libqtile import bar, pangocffi from libqtile.log_utils import logger +from libqtile.command.base import expose_command from libqtile.widget import base from libqtile.widget.base import ORIENTATION_HORIZONTAL from libqtile.widget.battery import default_icon_path, load_battery, BatteryState @@ -242,18 +243,19 @@ class DualPaneTextboxBase(base._Widget): self.bar.draw() self.changed = False - def cmd_set_font(self, font=base.UNSPECIFIED, fontsize_left=base.UNSPECIFIED, fontsize_right=base.UNSPECIFIED, fontshadow=base.UNSPECIFIED): + @expose_command() + def set_font(self, font=None, fontsize_left=None, fontsize_right=None, fontshadow=None): """ Change the font used by this widget. If font is None, the current font is used. """ - if font is not base.UNSPECIFIED: + if font is not None: self.font = font - if fontsize_left is not base.UNSPECIFIED: + if fontsize_left is not None: self.fontsize_left = fontsize_left - if fontsize_right is not base.UNSPECIFIED: + if fontsize_right is not None: self.fontsize_right = fontsize_right - if fontshadow is not base.UNSPECIFIED: + if fontshadow is not None: self.fontshadow = fontshadow self.bar.draw() @@ -354,7 +356,8 @@ class MediaWidget(base.InLoopPollText): # logger.warning("{}") pass - def cmd_update_custom_player(self, player_name, data): + @expose_command() + def update_custom_player(self, player_name, data): # Update firefox player if player_name.startswith("firefox"): if data['playing'] and data['muted']: @@ -538,7 +541,7 @@ class AudioVisualizerWidget(_Graph): class KuroCurrentLayoutIcon(CurrentLayoutIcon): def _get_layout_names(self): - names = super(KuroCurrentLayoutIcon, self)._get_layout_names() + names = list(super(KuroCurrentLayoutIcon, self)._get_layout_names()) from kuro.utils import layouts as kuro_layouts from libqtile.layout.base import Layout @@ -550,7 +553,7 @@ class KuroCurrentLayoutIcon(CurrentLayoutIcon): ] names.extend(klayouts) - return list(set(names)) + return set(names) class KuroTaskList(TaskList): @@ -1321,18 +1324,22 @@ class VolumeInfoWidget(DualPaneTextboxBase): self.update() - def cmd_increase_vol(self): + @expose_command() + def increase_vol(self): # Emulate button press. self.button_press(0, 0, BUTTON_UP) - def cmd_decrease_vol(self): + @expose_command() + def decrease_vol(self): # Emulate button press. self.button_press(0, 0, BUTTON_DOWN) - def cmd_mute(self): + @expose_command() + def mute(self): # Emulate button press. self.button_press(0, 0, BUTTON_MUTE) - def cmd_run_app(self): + @expose_command() + def run_app(self): # Emulate button press. self.button_press(0, 0, BUTTON_RIGHT) From 6dd362247e0b7337278598d27f8129efc710857e Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Fri, 25 Jul 2025 17:39:36 +0200 Subject: [PATCH 08/17] Unify configs so we can get rid of all those branches per machine. Also Wayland changes for Violet --- config.py | 18 +++-- kuro/base.py | 17 ++++- kuro/{config.py => config/__init__.py} | 53 +++++++++----- kuro/config/aria.py | 45 ++++++++++++ kuro/config/meconopsis.py | 22 ++++++ kuro/config/violet.py | 26 +++++++ kuro/theme.py | 70 ++++++++++--------- kuro/utils/__init__.py | 30 ++++++++ kuro/utils/widgets.py | 96 ++++++++++++++------------ required_packages.txt | 2 + 10 files changed, 274 insertions(+), 105 deletions(-) rename kuro/{config.py => config/__init__.py} (81%) create mode 100644 kuro/config/aria.py create mode 100644 kuro/config/meconopsis.py create mode 100644 kuro/config/violet.py diff --git a/config.py b/config.py index 2959508..2749ee2 100644 --- a/config.py +++ b/config.py @@ -27,6 +27,7 @@ # Import Theme from libqtile import hook from libqtile.log_utils import logger +from kuro.utils import load_config_class try: from kuro.theme import Kuro @@ -40,20 +41,15 @@ except ImportError as e: Kuro = None raise ImportError("Could not load theme Config or BaseTheme! Error: {}".format(e)) -# Import theme configuration -try: - from kuro.config import Config -except ImportError as e: - logger.error("Could not load Kuro Config. Trying to load BaseConfig. Error: {}".format(e)) - try: - from kuro.base import BaseConfig as Config - except ImportError as e: - Config = None - raise ImportError("Could not load theme Config or BaseConfig! Error: {}".format(e)) +# Import theme configuration +Config = load_config_class() +if Config is None: + raise ImportError("Could not load theme Config or BaseConfig! Error: {}".format(e)) try: logger.warning("Initializing theme...") + logger.warning(f"Using config variables for '{Config.get('config_name', '????')}'") # Initialize the Theme Theme.initialize() logger.warning("Initialize done") @@ -114,6 +110,8 @@ except Exception as e: def main(qtile): + Config.initialize(qtile) + # set logging level if Config.get('debug', False): if Config.get('verbose', False): diff --git a/kuro/base.py b/kuro/base.py index 15ce41d..8f02d65 100644 --- a/kuro/base.py +++ b/kuro/base.py @@ -1,3 +1,5 @@ +import time + from libqtile import layout as libqtile_layout, layout, bar, widget from libqtile.lazy import lazy from libqtile.config import Key, Group, Screen, Drag, Click, Match @@ -7,13 +9,21 @@ from libqtile.log_utils import logger class BaseConfig: + config_name = "KuroBase" + @classmethod def get(cls, key, default): if hasattr(cls, key): - return cls.__dict__[key] + return getattr(cls, key) + #return cls.__dict__[key] else: return default + @classmethod + def initialize(cls, qtile): + # Can do extra initialization based on qtile instance here + pass + class BaseTheme: # Changing variables initialized by function @@ -45,7 +55,7 @@ class BaseTheme: auto_fullscreen = True focus_on_window_activation = "smart" extensions = [] - reconfigure_screens = True + reconfigure_screens = False # 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 @@ -60,6 +70,9 @@ class BaseTheme: # 'export _JAVA_AWT_WM_NONREPARENTING=1' wmname = "LG3D" + def __init__(self): + self.startup_time = time.time() + def initialize(self): logger.info("Initializing widget defaults...") self.widget_defaults = self.init_widget_defaults() diff --git a/kuro/config.py b/kuro/config/__init__.py similarity index 81% rename from kuro/config.py rename to kuro/config/__init__.py index 43ff6e5..00ff7ea 100644 --- a/kuro/config.py +++ b/kuro/config/__init__.py @@ -1,8 +1,11 @@ from kuro.base import BaseConfig +from libqtile.log_utils import logger # Config variables used in the main configuration class Config(BaseConfig): + config_name = "KuroGeneral" + # Show debug bar and messages debug = False verbose = False @@ -24,7 +27,7 @@ class Config(BaseConfig): # Default Applications app_terminal = "ghostty" - app_launcher = "wofi --show drun,run" + app_launcher = "wofi --show run,drun" file_manager = "thunar" visualizer_app = "glava" web_browser = "firefox" @@ -38,15 +41,24 @@ class Config(BaseConfig): {'group': "", 'command': ["thunderbird"]}, {'group': "", 'command': ["spotify"]}, ] - apps_autostart = [ - # ["ulauncher", "--hide-window", "--no-window-shadow"], # App launcher background daemon - ["mako"], # Notification daemon - ["kanshi"], # Display hotplug - ["wl-paste", "--watch", "cliphist", "store"], # Clipboard manager - ["/usr/lib/kdeconnectd"], # KDE Connect daemon - ["kdeconnect-indicator"], # KDE Connect tray - ["vorta"], # Vorta backup scheduler - ] + apps_autostart = { + 'common': [ + ["/usr/lib/kdeconnectd"], # KDE Connect daemon + ["kdeconnect-indicator"], # KDE Connect tray + ["vorta"], # Vorta backup scheduler + ], + 'x11': [ + ["dunst"], # Notification daemon + ["picom", "-b"], # Compositor + ["xfce4-clipman"], # Clipboard manager + ["xiccd"], # Color profile manager + ], + 'wayland': [ + ["mako"], # Notification daemon + ["wl-paste", "--watch", "cliphist", "store"], # Clipboard manager + ["kanshi"], # Display hotplugging + ] + } # Keyboard commands cmd_media_play = "playerctl -i kdeconnect play-pause" @@ -129,8 +141,8 @@ class Config(BaseConfig): # Thermal indicator variables thermal_threshold = 75 - thermal_sensor = "Tdie" - thermal_chip = "zenpower-pci-00c3" + thermal_sensor = "Package id 0" + thermal_chip = "coretemp-isa-0000" # CPU graph variables cpu_graph_colour = '#ff0000' @@ -149,7 +161,7 @@ class Config(BaseConfig): wifi_interface = "wifi0" wifi_theme_path = "/home/kevin/.config/qtile/kuro/resources/wifi" wifi_update_interval = 5 - wired_interface = "br1" + wired_interface = "eth0" # GPU variables gpu_theme_path = "/home/kevin/.config/qtile/kuro/resources/gpu" @@ -158,10 +170,7 @@ class Config(BaseConfig): volume_font = "Noto Sans" volume_fontsize = 11 volume_theme_path = "/home/kevin/.config/qtile/kuro/resources/volume" - volume_pulse_sinks = [ - "alsa_output.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo-output", - "alsa_output.pci-0000_0d_00.4.analog-stereo", - ] + volume_pulse_sinks = [] volume_is_bluetooth_icon = False volume_update_interval = 0.2 @@ -200,3 +209,13 @@ class Config(BaseConfig): # Comma-separated list of ignored players in the media widget media_ignore_players = "kdeconnect" + + @classmethod + def initialize(cls, qtile): + # Can do extra initialization based on qtile instance here + super(Config, cls).initialize(qtile=qtile) + + # Replace some apps if launched in X11 mode + if qtile.core.name == "x11": + logger.warning("Launched in X11 mode, overriding some apps in Config to xorg-variants.") + cls.app_launcher = "/home/kevin/bin/dmenu_wal.sh" diff --git a/kuro/config/aria.py b/kuro/config/aria.py new file mode 100644 index 0000000..ebb87bf --- /dev/null +++ b/kuro/config/aria.py @@ -0,0 +1,45 @@ +from kuro.config import Config as GeneralConfig + + +class Config(GeneralConfig): + """ + Kuro QTile configuration overrides for Aria + """ + config_name = "Aria" + + # Default Applications + app_terminal = "terminator" + app_launcher = "/home/kevin/bin/dmenu_wal.sh" + cmd_brightness_up = "true" + cmd_brightness_down = "true" + cmd_screenshot = "xfce4-screenshooter -r -c -d 1" + cmd_alt_screenshot = "xfce4-screenshooter -w -c -d 0" + lock_command = "bash /home/kevin/bin/lock.sh" + cliphistory_command = "true" + + # Autostart applications + apps_autostart_group = [ + {'group': "", 'command': ["firefox"]}, + {'group': "", 'command': ["terminator"]}, + {'group': "", 'command': ["/usr/bin/rambox"]}, + {'group': "", 'command': ["thunar"]}, + {'group': "", 'command': ["thunderbird"]}, + {'group': "", 'command': ["spotify"]}, + ] + + # Thermal indicator variables + thermal_sensor = "Package id 0" + thermal_chip = "coretemp-isa-0000" + + # Network variables + wifi_interface = "wifi0" + wired_interface = "enp7s0" + + # Volume widget variables + volume_pulse_sinks = [ + "alsa_output.pci-0000_00_1f.3.analog-stereo", + ] + + # Screen organization + laptop_screen_nvidia = "eDP-1-1" + laptop_screen_intel = "eDP1" diff --git a/kuro/config/meconopsis.py b/kuro/config/meconopsis.py new file mode 100644 index 0000000..e580c92 --- /dev/null +++ b/kuro/config/meconopsis.py @@ -0,0 +1,22 @@ +from kuro.config import Config as GeneralConfig + + +class Config(GeneralConfig): + """ + Kuro QTile configuration overrides for Meconopsis + """ + config_name = "Meconopsis" + + # Thermal indicator variables + thermal_sensor = "Package id 0" + thermal_chip = "coretemp-isa-0000" + + # Network variables + wifi_interface = "wlp3s0" + wired_interface = "enp4s0" + + # Volume widget variables + volume_pulse_sinks = [ + # Analog jack + "alsa_output.usb-CSCTEK_USB_Audio_and_HID_A34004801402-00.analog-stereo", + ] diff --git a/kuro/config/violet.py b/kuro/config/violet.py new file mode 100644 index 0000000..e6dd5a6 --- /dev/null +++ b/kuro/config/violet.py @@ -0,0 +1,26 @@ +from kuro.config import Config as GeneralConfig + + +class Config(GeneralConfig): + """ + Kuro QTile configuration overrides for Violet + """ + config_name = "Violet" + + # Thermal indicator variables + thermal_sensor = "Tdie" + thermal_chip = "zenpower-pci-00c3" + + # Network variables + wifi_interface = None + wired_interface = "br1" + + # Volume widget variables + volume_pulse_sinks = [ + # Behringer USB mixer + "alsa_output.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo-output", + # Motherboard output (Starship/Matisse) + "alsa_output.pci-0000_0e_00.4.iec958-stereo", + # PCIe card output (CMI8738/CMI8768 PCI Audio) + "alsa_output.pci-0000_08_00.0.analog-stereo", + ] diff --git a/kuro/theme.py b/kuro/theme.py index 8bafb1d..7311976 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -1,6 +1,7 @@ import json import os import random +import time import datetime import socket import subprocess @@ -39,14 +40,11 @@ from kuro.utils import layouts as kuro_layouts logger.warning("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!") +from kuro.utils import load_config_class +Config = load_config_class() +if Config is None: + raise ImportError("Could not load theme Config or BaseConfig! Error: {}".format(e)) +Config.initialize(qtile) logger.warning("Imports done") @@ -58,9 +56,6 @@ class Kuro(BaseTheme): # Screen count num_screens = 0 - # Top bars - topbars = [] - # Static windows static_windows = [] @@ -310,9 +305,6 @@ class Kuro(BaseTheme): Config.bar_background = colors['color1'] def reinit_screens(self): - # Re-initalize bars - self.topbars.clear() - # TODO: Move backend check into utils method if qtile.core.name == "x11": self.num_screens = max(1, utils.get_screen_count()) @@ -320,18 +312,19 @@ class Kuro(BaseTheme): self.num_screens = max(1, len(qtile.core.get_screen_info())) logger.warning(f"Detected {self.num_screens} screens.") - # TODO: If i get the double topbar issue, this might be the - # cause; creating new screens on reinit... - screens = [] for x in range(self.num_screens): - logger.warning("Initializing bars for screen {}".format(x)) - topbar = self.build_bar_for_screen(x) - self.topbars.append(topbar) - screens.append(Screen(top=topbar)) + logger.warning("Reconfiguring bars for screen {}".format(x)) - self.screens.clear() - for s in screens: - self.screens.append(s) + try: + screen = self.screens[x] + except IndexError: + screen = Screen() + + if screen.top is None: + screen.top = self.build_bar_for_screen(x) + topbar = screen.top + + self.screens.append(Screen(top=topbar)) def update_keys(self): logger.warning("Updating keys") @@ -606,7 +599,6 @@ class Kuro(BaseTheme): # Update color scheme self.update_colorscheme() - self.startup_completed = True def callback_startup_complete(self, *args, **kwargs): logger.warning("Callback Startup Complete") @@ -617,14 +609,20 @@ class Kuro(BaseTheme): # Update color scheme self.update_colorscheme() - # Setup XDG Desktop Portal - self.setup_xdg_desktop_portal() + # Setup XDG Desktop Portal on Wayland + if qtile.core.name == "wayland": + self.setup_xdg_desktop_portal() # After first startup is complete, autostart configured apps logger.warning("Autostarting apps...") - for app in Config.get("apps_autostart", []): - logger.warning(f"Starting '{app}'...") - utils.execute_once(app) + for category in Config.get("apps_autostart", {}).keys(): + if qtile.core.name == category or category == "common": + logger.warning(f"Autostarting apps for {category}...") + for app in Config.get("apps_autostart", {}).get(category, []): + logger.warning(f"Starting '{app}'...") + utils.execute_once(app) + else: + logger.warning(f"Skipping autostart apps for {category}, because core is {qtile.core.name}...") for app in Config.get("apps_autostart_group", []): if all(x in app.keys() for x in ["group", "command"]): @@ -634,6 +632,9 @@ class Kuro(BaseTheme): logger.warning(f"Invalid app in 'apps_autostart_group', " f"must have 'group' and 'command' keys: {app}...") logger.warning("Autostart complete") + cur_time = time.time() + logger.warning(f"QTile startup completed! Started up in {(cur_time - self.startup_time):.1f} seconds!") + self.startup_completed = True def callback_client_managed(self, *args, **kwargs): client: Optional[Window] = args[0] if len(args) > 0 else None @@ -667,9 +668,14 @@ class Kuro(BaseTheme): del client.is_static_window self.static_windows.remove(client) - def callback_screens_reconfigured(self, *args, **kwargs): - logger.warning(f"Re-configuring screens!") + def callback_screen_change(self, *args, **kwargs): + logger.warning(f"Screen configuration changed, reinitializing screens") self.reinit_screens() + qtile.reconfigure_screens() + #qtile.reconfigure_screens() # Twice, see: https://github.com/qtile/qtile/issues/4673#issuecomment-2196459114 + + #def callback_screens_reconfigured(self, *args, **kwargs): + logger.warning(f"Screens were reconfgured, updating wallpapers and color scheme") self.set_wallpaper(self.current_wallpaper) self.update_colorscheme() diff --git a/kuro/utils/__init__.py b/kuro/utils/__init__.py index e69de29..758cba3 100644 --- a/kuro/utils/__init__.py +++ b/kuro/utils/__init__.py @@ -0,0 +1,30 @@ +import socket +import importlib +from libqtile.log_utils import logger + +def load_config_class(): + # Try to import host-specific configuration first + hostname = socket.gethostname().lower() + if hostname: + try: + host_module = importlib.import_module(f"kuro.config.{hostname}") + return getattr(host_module, "Config") + except ImportError: + pass + logger.warning(f"No host-specific configuration available for {hostname}. Loading general config...") + + # If no config yet, load general Kuro Config object + try: + conf_module = importlib.import_module("kuro.config") + return getattr(conf_module, "Config") + except ImportError as e: + pass + logger.error("Could not load Kuro Config. Trying to load BaseConfig. Error: {}".format(e)) + + # If no config yet, load fallback BaseConfig + try: + base_module = importlib.import_module("kuro.base") + return getattr(base_module, "BaseConfig") + except ImportError as e: + pass + return None diff --git a/kuro/utils/widgets.py b/kuro/utils/widgets.py index ff95975..aff7f56 100644 --- a/kuro/utils/widgets.py +++ b/kuro/utils/widgets.py @@ -649,62 +649,70 @@ class NetworkInfoWidget(DualPaneTextboxBase): def _update_values(self): # Wifi - try: - essid, quality = get_status(self.wireless_interface) - status = iwlib.get_iwconfig(self.wireless_interface) - self.wireless_ips = netifaces.ifaddresses(self.wireless_interface) - disconnected = essid is None - percent = math.ceil(((quality or 0) / 70) * 100) - self.wireless_quality = quality - self.wireless_signal = percent - self.wireless_name = essid - self.wireless_connected = not disconnected - self.wireless_accesspoint = status.get('Access Point', b'Unknown').decode() - self.wireless_frequency = status.get('Frequency', b'Unknown').decode() - self.wireless_ipv4 = self.wireless_ips.get(netifaces.AF_INET, [{'addr': ""}])[0]['addr'] - self.wireless_ipv6 = self.wireless_ips.get(netifaces.AF_INET6, [{'addr': ""}])[0]['addr'] - self.wireless_mac = self.wireless_ips.get(netifaces.AF_LINK, [{'addr': ""}])[0]['addr'] - except EnvironmentError: - pass + if self.wireless_interface: + try: + essid, quality = get_status(self.wireless_interface) + status = iwlib.get_iwconfig(self.wireless_interface) + self.wireless_ips = netifaces.ifaddresses(self.wireless_interface) + disconnected = essid is None + percent = math.ceil(((quality or 0) / 70) * 100) + self.wireless_quality = quality + self.wireless_signal = percent + self.wireless_name = essid + self.wireless_connected = not disconnected + self.wireless_accesspoint = status.get('Access Point', b'Unknown').decode() + self.wireless_frequency = status.get('Frequency', b'Unknown').decode() + self.wireless_ipv4 = self.wireless_ips.get(netifaces.AF_INET, [{'addr': ""}])[0]['addr'] + self.wireless_ipv6 = self.wireless_ips.get(netifaces.AF_INET6, [{'addr': ""}])[0]['addr'] + self.wireless_mac = self.wireless_ips.get(netifaces.AF_LINK, [{'addr': ""}])[0]['addr'] + except EnvironmentError: + pass # Wired - try: - self.wired_ips = netifaces.ifaddresses(self.wired_interface) - self.wired_ipv4 = self.wired_ips.get(netifaces.AF_INET, [{'addr': ""}])[0]['addr'] - self.wired_ipv6 = self.wired_ips.get(netifaces.AF_INET6, [{'addr': ""}])[0]['addr'] - self.wired_mac = self.wired_ips.get(netifaces.AF_LINK, [{'addr': ""}])[0]['addr'] - command = ["ip", "link", "show", "{}".format(self.wired_interface)] + if self.wired_interface: try: - eth_status = call_process(command) - except subprocess.CalledProcessError as e: - logger.error(f"Error while calling {command} - {e}") - return - m = self.wired_up_regex.search(eth_status) - if m: - self.wired_connected = "UP" in m.group(1) - else: - self.wired_connected = False + self.wired_ips = netifaces.ifaddresses(self.wired_interface) + self.wired_ipv4 = self.wired_ips.get(netifaces.AF_INET, [{'addr': ""}])[0]['addr'] + self.wired_ipv6 = self.wired_ips.get(netifaces.AF_INET6, [{'addr': ""}])[0]['addr'] + self.wired_mac = self.wired_ips.get(netifaces.AF_LINK, [{'addr': ""}])[0]['addr'] + command = ["ip", "link", "show", "{}".format(self.wired_interface)] + try: + eth_status = call_process(command) + except subprocess.CalledProcessError as e: + logger.error(f"Error while calling {command} - {e}") + return + m = self.wired_up_regex.search(eth_status) + if m: + self.wired_connected = "UP" in m.group(1) + else: + self.wired_connected = False - except (EnvironmentError, ValueError): - pass + except (EnvironmentError, ValueError): + pass def update(self): self._update_values() self.draw() def draw(self): - if self.wireless_connected: - strength = "" - if self.wireless_signal < 66: - strength = "" - if self.wireless_signal < 33: - strength = "" - self.text_left = strength + if self.wireless_interface: + if self.wireless_connected: + strength = "" + if self.wireless_signal < 66: + strength = "" + if self.wireless_signal < 33: + strength = "" + self.text_left = strength + else: + self.text_left = "" else: - self.text_left = "" + self.text_left = "" - if self.wired_connected: - self.text_right = "" + if self.wired_interface: + if self.wired_connected: + self.text_right = "" + else: + self.text_right = "" else: self.text_right = "" diff --git a/required_packages.txt b/required_packages.txt index cf0478e..3462d93 100644 --- a/required_packages.txt +++ b/required_packages.txt @@ -4,6 +4,8 @@ notification-daemon otf-font-awesome python-osc +qtile-extras + # /optional/ playerctl From befd2eb0fb8bc8c186823c742a862824c67cfdf2 Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Sat, 9 Aug 2025 12:25:51 +0200 Subject: [PATCH 09/17] Updates for qtile 0.33.x --- kuro/theme.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kuro/theme.py b/kuro/theme.py index 7311976..a7b785a 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -537,7 +537,7 @@ class Kuro(BaseTheme): # Layout switcher, clock and Screen ID widgets.extend([ - widget.CurrentLayoutIcon(custom_icon_paths=Config.get('custom_layout_icon_paths', [])), + widget.CurrentLayout(mode="icon", custom_icon_paths=Config.get('custom_layout_icon_paths', [])), widget.Clock(format="%a %d %b ", **self.widget_defaults), widget.Clock( format="%H:%M", From b5a3d3f5778a800a1a2145884d61d204f7363390 Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Mon, 11 Aug 2025 17:17:08 +0200 Subject: [PATCH 10/17] Set x11 wallpaper update command --- kuro/config/__init__.py | 2 +- kuro/theme.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kuro/config/__init__.py b/kuro/config/__init__.py index 00ff7ea..7c6a25a 100644 --- a/kuro/config/__init__.py +++ b/kuro/config/__init__.py @@ -76,7 +76,7 @@ class Config(BaseConfig): cmd_reconfigure_screens = "kanshictl reload" # Commands - wallpaper_config_command = "/bin/true" # TODO: Remove + x11_wallpaper_config_command = "/home/kevin/bin/wal-nitrogen-noupdate" # TODO: Remove # Images desktop_bg = "/home/kevin/Pictures/wallpapers/desktop.png" diff --git a/kuro/theme.py b/kuro/theme.py index a7b785a..d46ce20 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -739,7 +739,7 @@ class Kuro(BaseTheme): def set_wallpaper(self, filename): if qtile.core.name == "x11": - p = utils.execute_once(f"{Config.get('wallpaper_config_command', 'wal-nitrogen-noupdate')} {filename}") + p = utils.execute_once(f"{Config.get('x11_wallpaper_config_command', 'wal-nitrogen-noupdate')} {filename}") p.wait() else: # Wayland can set wallpaper in qtile directly per screen From a68f516f333f2dc49837a6108a754785e35c5980 Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Mon, 11 Aug 2025 17:18:03 +0200 Subject: [PATCH 11/17] Add Temari config, always try to launch dbus because qtile.theme_instance is broken since latest qtile update --- kuro/config/temari.py | 35 +++++++++++++++++++++++++++++++++++ kuro/utils/general.py | 22 +++++++++++----------- 2 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 kuro/config/temari.py diff --git a/kuro/config/temari.py b/kuro/config/temari.py new file mode 100644 index 0000000..c3b1476 --- /dev/null +++ b/kuro/config/temari.py @@ -0,0 +1,35 @@ +from kuro.config import Config as GeneralConfig + + +class Config(GeneralConfig): + """ + Kuro QTile configuration overrides for Meconopsis + """ + config_name = "Temari" + + # Default Applications + #app_terminal = "terminator" + cmd_brightness_up = "brightnessctl -d intel_backlight set +5%" + cmd_brightness_down = "brightnessctl -d intel_backlight set 5%-" + #lock_command = "bash /home/kevin/bin/lock.sh" + + # Thermal indicator variables + thermal_sensor = "Package id 0" + thermal_chip = "coretemp-isa-0000" + + # Network variables + wifi_interface = "wlp0s20f3" + wired_interface = "enp7s0" + + # Volume widget variables + volume_pulse_sinks = [ + # Analog jack + "alsa_output.pci-0000_00_1f.3.analog-stereo", + ] + + # Screen organization + laptop_screen_nvidia = "eDP-1-1" + laptop_screen_intel = "eDP1" + + # Show battery widget + show_battery_widget = True diff --git a/kuro/utils/general.py b/kuro/utils/general.py index c8d6a8c..0fb66e9 100644 --- a/kuro/utils/general.py +++ b/kuro/utils/general.py @@ -110,17 +110,17 @@ def bar_separator(config): ) def init_notify(qtile): - if qtile and qtile.theme_instance and qtile.theme_instance.startup_completed: - try: - if not notify2.is_initted(): - logger.warning("Initializing Notify2") - notify2.init("QTileWM") - except DBusException: - logger.error(f"Failed to initialize Notify2 (DBus error), retrying later.") - except Exception: - logger.error(f"Failed to initialize Notify2 (Generic error), retrying later.") - else: - logger.warning(f"Not initializing Notify2 yet, QTile startup not completed.") + #if qtile and qtile.theme_instance and qtile.theme_instance.startup_completed: + try: + if not notify2.is_initted(): + logger.warning("Initializing Notify2") + notify2.init("QTileWM") + except DBusException: + logger.error(f"Failed to initialize Notify2 (DBus error), retrying later.") + except Exception: + logger.error(f"Failed to initialize Notify2 (Generic error), retrying later.") + #else: + # logger.warning(f"Not initializing Notify2 yet, QTile startup not completed.") def notify(qtile, title, content, urgency=URGENCY_NORMAL, timeout=5000, image=None): From 812eb28abc31a4fe6698e24aac900582057418b4 Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Mon, 11 Aug 2025 17:29:06 +0200 Subject: [PATCH 12/17] Add option to launch network config app when right/middle clicking network widget --- kuro/config/__init__.py | 1 + kuro/config/temari.py | 1 + kuro/utils/widgets.py | 6 +++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/kuro/config/__init__.py b/kuro/config/__init__.py index 7c6a25a..56f4cb4 100644 --- a/kuro/config/__init__.py +++ b/kuro/config/__init__.py @@ -31,6 +31,7 @@ class Config(BaseConfig): file_manager = "thunar" visualizer_app = "glava" web_browser = "firefox" + network_config = "true" # Autostart applications apps_autostart_group = [ diff --git a/kuro/config/temari.py b/kuro/config/temari.py index c3b1476..5dca927 100644 --- a/kuro/config/temari.py +++ b/kuro/config/temari.py @@ -11,6 +11,7 @@ class Config(GeneralConfig): #app_terminal = "terminator" cmd_brightness_up = "brightnessctl -d intel_backlight set +5%" cmd_brightness_down = "brightnessctl -d intel_backlight set 5%-" + network_config = "nm-applet" #lock_command = "bash /home/kevin/bin/lock.sh" # Thermal indicator variables diff --git a/kuro/utils/widgets.py b/kuro/utils/widgets.py index aff7f56..3c10903 100644 --- a/kuro/utils/widgets.py +++ b/kuro/utils/widgets.py @@ -17,7 +17,7 @@ from libqtile.widget.groupbox import GroupBox from libqtile.command.base import expose_command from kuro.utils.general import notify, BUTTON_LEFT, BUTTON_MIDDLE, BUTTON_RIGHT, BUTTON_DOWN, BUTTON_UP, BUTTON_MUTE, \ - call_process + call_process, execute class DualPaneTextboxBase(base._Widget): @@ -621,6 +621,7 @@ class NetworkInfoWidget(DualPaneTextboxBase): ('critical_color', "#ffffff", "Color when value is critical"), ('wireless_interface', "wifi0", "Wireless interface device name"), ('wired_interface', "enp7s0", "Wired interface device name"), + ('config_application', "true", "Application to launch when right/middle clicking"), ] def __init__(self, **config): @@ -747,6 +748,9 @@ class NetworkInfoWidget(DualPaneTextboxBase): notify(None, title, "{}\n\n{}".format(wifi_text, wired_text)) else: notify(None, title, "\n{}".format(wired_text)) + if button == BUTTON_LEFT or button == BUTTON_MIDDLE: + if self.config_application: + execute(self.config_application) class BatteryInfoWidget(DualPaneTextboxBase): From 86e4404660c93abbc4efe70a710260deeffa0430 Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Mon, 11 Aug 2025 17:50:31 +0200 Subject: [PATCH 13/17] Fix right/middle click network icon to configure --- kuro/config/__init__.py | 2 +- kuro/config/temari.py | 2 +- kuro/theme.py | 3 ++- kuro/utils/widgets.py | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/kuro/config/__init__.py b/kuro/config/__init__.py index 56f4cb4..a9a9aca 100644 --- a/kuro/config/__init__.py +++ b/kuro/config/__init__.py @@ -31,7 +31,7 @@ class Config(BaseConfig): file_manager = "thunar" visualizer_app = "glava" web_browser = "firefox" - network_config = "true" + network_config = None # Autostart applications apps_autostart_group = [ diff --git a/kuro/config/temari.py b/kuro/config/temari.py index 5dca927..59f4dff 100644 --- a/kuro/config/temari.py +++ b/kuro/config/temari.py @@ -11,7 +11,7 @@ class Config(GeneralConfig): #app_terminal = "terminator" cmd_brightness_up = "brightnessctl -d intel_backlight set +5%" cmd_brightness_down = "brightnessctl -d intel_backlight set 5%-" - network_config = "nm-applet" + network_config = "nm-connection-editor" #lock_command = "bash /home/kevin/bin/lock.sh" # Thermal indicator variables diff --git a/kuro/theme.py b/kuro/theme.py index d46ce20..d643aa9 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -512,7 +512,8 @@ class Kuro(BaseTheme): kuro.utils.widgets.NetworkInfoWidget( fontsize_left=16, fontsize_right=14, wireless_interface=Config.get('wifi_interface', None), - wired_interface=Config.get('wired_interface', None) + wired_interface=Config.get('wired_interface', None), + config_application=Config.get('network_config', None), ), ]) diff --git a/kuro/utils/widgets.py b/kuro/utils/widgets.py index 3c10903..3a30e23 100644 --- a/kuro/utils/widgets.py +++ b/kuro/utils/widgets.py @@ -621,7 +621,7 @@ class NetworkInfoWidget(DualPaneTextboxBase): ('critical_color', "#ffffff", "Color when value is critical"), ('wireless_interface', "wifi0", "Wireless interface device name"), ('wired_interface', "enp7s0", "Wired interface device name"), - ('config_application', "true", "Application to launch when right/middle clicking"), + ('config_application', None, "Application to launch when right/middle clicking"), ] def __init__(self, **config): @@ -748,7 +748,7 @@ class NetworkInfoWidget(DualPaneTextboxBase): notify(None, title, "{}\n\n{}".format(wifi_text, wired_text)) else: notify(None, title, "\n{}".format(wired_text)) - if button == BUTTON_LEFT or button == BUTTON_MIDDLE: + if button == BUTTON_RIGHT or button == BUTTON_MIDDLE: if self.config_application: execute(self.config_application) From 3c72148fcd7cd3371f91ad74af24dafade493192 Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Tue, 19 Aug 2025 08:21:05 +0200 Subject: [PATCH 14/17] Make Terminator default terminal again --- kuro/config/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kuro/config/__init__.py b/kuro/config/__init__.py index a9a9aca..ffdf584 100644 --- a/kuro/config/__init__.py +++ b/kuro/config/__init__.py @@ -26,7 +26,7 @@ class Config(BaseConfig): cliphistory_command = "/home/kevin/bin/cliphistory.sh" # Default Applications - app_terminal = "ghostty" + app_terminal = "terminator" app_launcher = "wofi --show run,drun" file_manager = "thunar" visualizer_app = "glava" @@ -36,7 +36,7 @@ class Config(BaseConfig): # Autostart applications apps_autostart_group = [ {'group': "", 'command': ["firefox"]}, - {'group': "", 'command': ["ghostty", "--gtk-single-instance=true", "--quit-after-last-window-close=false", "--initial-window=true"]}, + {'group': "", 'command': ["terminator"]}, {'group': "", 'command': ["/usr/bin/rambox"]}, {'group': "", 'command': ["thunar"]}, {'group': "", 'command': ["thunderbird"]}, From 8f5e1e282a80f4ebe978eb789e2701140b5b1a6a Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Mon, 1 Sep 2025 09:29:32 +0200 Subject: [PATCH 15/17] Load more config from host-specific files, add host-config for work DBO, allow using 'fake-screens', various bugfixes --- config.py | 6 +- kuro/config/__init__.py | 62 +++++++++-- kuro/config/ppc1006083.py | 133 +++++++++++++++++++++++ kuro/theme.py | 221 +++++++++++++++++++------------------- kuro/utils/general.py | 15 +-- 5 files changed, 308 insertions(+), 129 deletions(-) create mode 100644 kuro/config/ppc1006083.py diff --git a/config.py b/config.py index e4e63a5..c530902 100644 --- a/config.py +++ b/config.py @@ -91,7 +91,11 @@ try: groups = Theme.groups layouts = Theme.layouts widget_defaults = Theme.widget_defaults - screens = Theme.screens + if Config.get("use_fake_screens", False): + logger.warning(f"This host uses fake screens!") + fake_screens = Theme.screens + else: + screens = Theme.screens dgroups_key_binder = Theme.dgroups_key_binder dgroups_app_rules = Theme.dgroups_app_rules main = Theme.main diff --git a/kuro/config/__init__.py b/kuro/config/__init__.py index ffdf584..85c1bff 100644 --- a/kuro/config/__init__.py +++ b/kuro/config/__init__.py @@ -1,5 +1,6 @@ from kuro.base import BaseConfig from libqtile.log_utils import logger +from libqtile.lazy import lazy # Config variables used in the main configuration @@ -10,6 +11,13 @@ class Config(BaseConfig): debug = False verbose = False + # General variables + homedir = "/home/kevin" + use_fake_screens = False + + # Screen configs (empty = autoconfig, otherwise list of Screen() kwarg dicts) + screen_kwargs = [] + # Colors foreground = "#ffffff" background = "#000000" @@ -18,8 +26,6 @@ class Config(BaseConfig): inactive_dark = "#333333" # Predefined commands - cmd_brightness_up = "sudo /usr/bin/xbacklight -inc 10" - cmd_brightness_down = "sudo /usr/bin/xbacklight -dec 10" cmd_screenshot = "/home/kevin/bin/screenshot.sh" cmd_alt_screenshot = "/home/kevin/bin/screenshot.sh" lock_command = "bash /home/kevin/bin/lock.sh" @@ -28,11 +34,52 @@ class Config(BaseConfig): # Default Applications app_terminal = "terminator" app_launcher = "wofi --show run,drun" + app_launcer_x11 = "/home/kevin/bin/dmenu_wal.sh" file_manager = "thunar" visualizer_app = "glava" web_browser = "firefox" network_config = None + # Group definitions + groups = [ + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': '', 'layout': 'floating', 'options': {'border_focus': '#990000', 'border_normal': '#440000'}} + ] + + # Extra keybind definitions + extra_keys = [ + # Display modes + {'modifiers': ['mod'], 'key': "Prior", 'action': lazy.spawn("bash /home/kevin/.screenlayout/3scrns_144_rrot.sh")}, + {'modifiers': ['mod'], 'key': "Next", 'action': lazy.spawn("bash /home/kevin/.screenlayout/3scrns_60_rrot.sh")}, + {'modifiers': ['mod'], 'key': "Home", 'action': lazy.spawn("bash /home/kevin/bin/monitor_day.sh")}, + {'modifiers': ['mod'], 'key': "End", 'action': lazy.spawn("bash /home/kevin/bin/monitor_night.sh")}, + {'modifiers': ['mod'], 'key': "Insert", 'action': lazy.spawn("bash /home/kevin/bin/monitor_gamenight.sh")}, + + # Backlight keys + {'modifiers': [], 'key': "XF86MonBrightnessUp", 'action': lazy.spawn("sudo /usr/bin/xbacklight -inc 10")}, + {'modifiers': [], 'key': "XF86MonBrightnessDown", 'action': lazy.spawn("sudo /usr/bin/xbacklight -dec 10")}, + ] + + # Extra floating window rules + extra_float_rules = [ + # Wine Origin game launcher + {'title': 'origin.exe', 'wm_class': 'Wine'}, + # Homebank popups + {'title': 'Add transaction', 'wm_class': 'homebank'}, + {'title': 'Edit transaction', 'wm_class': 'homebank'}, + {'title': 'Inherit transaction', 'wm_class': 'homebank'}, + {'title': 'Multiple edit transactions', 'wm_class': 'homebank'}, + {'title': 'Transaction splits', 'wm_class': 'homebank'}, + ] + # Autostart applications apps_autostart_group = [ {'group': "", 'command': ["firefox"]}, @@ -69,12 +116,8 @@ class Config(BaseConfig): cmd_media_volume_up = "pamixer -d 2" # Display mode commands - cmd_monitor_mode_3s144 = "bash /home/kevin/.screenlayout/3scrns_144_rrot.sh" - cmd_monitor_mode_3s60 = "bash /home/kevin/.screenlayout/3scrns_60_rrot.sh" - cmd_monitor_mode_day = "bash /home/kevin/bin/monitor_day.sh" - cmd_monitor_mode_night = "bash /home/kevin/bin/monitor_night.sh" - cmd_monitor_mode_alt = "bash /home/kevin/bin/monitor_gamenight.sh" cmd_reconfigure_screens = "kanshictl reload" + cmd_wal = ["wallust", "run"] # Commands x11_wallpaper_config_command = "/home/kevin/bin/wal-nitrogen-noupdate" # TODO: Remove @@ -208,6 +251,9 @@ class Config(BaseConfig): # Show battery widget show_battery_widget = False + # Show media widget + show_media_widget = True + # Comma-separated list of ignored players in the media widget media_ignore_players = "kdeconnect" @@ -219,4 +265,4 @@ class Config(BaseConfig): # Replace some apps if launched in X11 mode if qtile.core.name == "x11": logger.warning("Launched in X11 mode, overriding some apps in Config to xorg-variants.") - cls.app_launcher = "/home/kevin/bin/dmenu_wal.sh" + cls.app_launcher = cls.app_launcer_x11 diff --git a/kuro/config/ppc1006083.py b/kuro/config/ppc1006083.py new file mode 100644 index 0000000..ceb9eae --- /dev/null +++ b/kuro/config/ppc1006083.py @@ -0,0 +1,133 @@ +from kuro.config import Config as GeneralConfig +import os +from libqtile.log_utils import logger + + +class Config(GeneralConfig): + """ + Kuro QTile configuration overrides for Work DBO laptop + """ + config_name = "DBO Power" + homedir = "/home/albek00" + #modifier = "mod1" # Non-existing F13 key used by AutoHotKey script + use_fake_screens = True + fake_screen_count = 2 + + # Default Applications + app_terminal = "terminator" + app_launcher = "/home/albek00/bin/dmenu_wal.sh" + app_launcer_x11 = "/home/albek00/bin/dmenu_wal.sh" + cmd_brightness_up = "true" + cmd_brightness_down = "true" + cmd_screenshot = "xfce4-screenshooter -r -c -d 1" + cmd_alt_screenshot = "xfce4-screenshooter -w -c -d 0" + lock_command = "true" + cliphistory_command = "true" + cmd_wal = ["wal", "-n", "-s", "-t", "-i"] + + # Screen configs (empty = autoconfig, otherwise list of Screen() kwarg dicts) + screen_kwargs = [ + {'x': 0, 'y': 0, 'width': int(os.getenv("QTILE_WIDTH", "3840"))//2, 'height': int(os.getenv("QTILE_HEIGHT", "1080"))}, + {'x': int(os.getenv("QTILE_WIDTH", "3840"))//2, 'y': 0, 'width': int(os.getenv("QTILE_WIDTH", "3840"))//2, 'height': int(os.getenv("QTILE_HEIGHT", "1080"))}, + ] + margin_layout = [8, 8, 2, 8] + + # Group definitions + groups = [ + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': ''}, + {'name': ''}, + ] + + # Extra keybind definitions + extra_keys = [] + + # Extra floating window rules + extra_float_rules = [] + + # Autostart applications + apps_autostart_group = [ + {'group': "", 'command': ["firefox"]}, + {'group': "", 'command': ["terminator"]}, + {'group': "", 'command': ["subl"]}, + {'group': "", 'command': ["smerge"]}, + {'group': "", 'command': ["thunar"]}, + ] + + # Hide unnecessary widgets + show_temperature = False + show_media_widget = False + + # Network variables + wifi_interface = None + wired_interface = "enP20755p0s0" + + # Volume widget variables + volume_pulse_sinks = [ + "RDPSink", + ] + + # Override directories to proper homedir. Half of these are probably not even used but meh + x11_wallpaper_config_command = "/home/albek00/bin/wal-nitrogen-noupdate" + desktop_bg = "/home/albek00/Pictures/wallpapers/desktop.png" + desktop_bg_folder = "/home/albek00/Pictures/wallpapers/desktop_rotation/day" + desktop_bg_night_folder = "/home/albek00/Pictures/wallpapers/desktop_rotation/night" + # desktop_bg_override = "/home/albek00/Pictures/safe_wallpaper.jpg" + applauncher_image = "/home/albek00/.config/qtile/kuro/resources/arch.png" + custom_layout_icon_paths = ['/home/albek00/.config/qtile/kuro/resources/layout_icons/'] + glava_color_file_path = "/home/albek00/.config/glava/kurobars_color.glsl" + battery_theme_path = "/home/albek00/.config/qtile/kuro/resources/battery" + wifi_theme_path = "/home/albek00/.config/qtile/kuro/resources/wifi" + gpu_theme_path = "/home/albek00/.config/qtile/kuro/resources/gpu" + volume_theme_path = "/home/albek00/.config/qtile/kuro/resources/volume" + bluevol_theme_path = "/home/albek00/.config/qtile/kuro/resources/bluetooth_volume" + + @classmethod + def initialize(cls, qtile): + super(Config, cls).initialize(qtile=qtile) + # Add keyboard remapping to autostart apps + cls.apps_autostart['common'].append(["xmodmap", "-e", "keycode 191 = Super_L"]) + + # Determine screens programatically + qtile_width = int(os.getenv("QTILE_WIDTH", "3840")) + qtile_height = int(os.getenv("QTILE_HEIGHT", "1080")) + logger.warning(f"Determining screens for size {qtile_width}x{qtile_height}...") + + # Home office, 1920x1080 horizontal right and 1080x1920 vertical left + if qtile_width == 3000 and (qtile_height > 1912 and qtile_height <= 1920): + cls.screen_kwargs = [ + {'x': 0, 'y': 840, 'width': 1920, 'height': qtile_height-840}, + {'x': 1920, 'y': 0, 'width': 1080, 'height': qtile_height}, + ] + # Dual 1680x1050 + elif qtile_width == 3360 and qtile_height == 1050: + cls.screen_kwargs = [ + {'x': 0, 'y': 0, 'width': 1680, 'height': 1050}, + {'x': 1680, 'y': 0, 'width': 1680, 'height': 1050}, + ] + # Dual 1920x1080 + elif qtile_width == 3840 and qtile_height == 1080: + cls.screen_kwargs = [ + {'x': 0, 'y': 0, 'width': 1920, 'height': 1080}, + {'x': 1920, 'y': 0, 'width': 1920, 'height': 1080}, + ] + # Single 1920x1080 + elif qtile_width == 1920 and qtile_height == 1080: + cls.screen_kwargs = [{'x': 0, 'y': 0, 'width': 1920, 'height': 1080}] + # Single 1680x1050 + elif qtile_width == 1680 and qtile_height == 1050: + cls.screen_kwargs = [{'x': 0, 'y': 0, 'width': 1680, 'height': 1050}] + # Else, set to autoconfigure + else: + cls.screen_kwargs = [] + # {'x': 0, 'y': 0, 'width': int(os.getenv("QTILE_WIDTH", "3840"))//2, 'height': int(os.getenv("QTILE_HEIGHT", "1080"))}, + # {'x': int(os.getenv("QTILE_WIDTH", "3840"))//2, 'y': 0, 'width': int(os.getenv("QTILE_WIDTH", "3840"))//2, 'height': int(os.getenv("QTILE_HEIGHT", "1080"))}, + + logger.warning(f"Kwargs: {cls.screen_kwargs}") + diff --git a/kuro/theme.py b/kuro/theme.py index d643aa9..3f554a6 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -82,14 +82,8 @@ class Kuro(BaseTheme): 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 - - # Homebank popups - Match(title='Add transaction', wm_class='homebank'), - Match(title='Edit transaction', wm_class='homebank'), - Match(title='Inherit transaction', wm_class='homebank'), - Match(title='Multiple edit transactions', wm_class='homebank'), - Match(title='Transaction splits', wm_class='homebank'), + # Extra rules from host-specific Config + *[Match(**rule) for rule in Config.get('extra_float_rules', [])] ] ) @@ -106,7 +100,7 @@ class Kuro(BaseTheme): def init_keys(self): logger.warning("Initializing keys") - return [ + keys = [ # Switch between windows in current stack pane Key([self.mod], "k", lazy.layout.down()), Key([self.mod], "j", lazy.layout.up()), @@ -151,17 +145,6 @@ class Kuro(BaseTheme): # Lock shortcut Key([self.mod], "l", lazy.spawn(Config.get('lock_command', "i3lock"))), - # 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'))), - - # 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'))), - # Media keys Key([], "XF86AudioPlay", lazy.spawn(Config.get('cmd_media_play', 'true'))), Key([], "XF86AudioNext", lazy.spawn(Config.get('cmd_media_next', 'true'))), @@ -218,27 +201,32 @@ class Kuro(BaseTheme): # Spawn a popup, and despawn it after 3 seconds Key([self.mod, "control"], "p", lazy.function(test_popups)), ] + # Extra keybinds from host-specific Config + keys.extend([ + Key([(self.mod if m == 'mod' else m) for m in key['modifiers']], key['key'], key['action']) + for key in Config.get('extra_keys', []) + ]) + return keys def init_groups(self): logger.warning("Initializing groups") # http://fontawesome.io/cheatsheet - groups = [ - Group(""), - Group(""), - Group(""), - Group(""), - Group(""), - Group(""), - Group(""), - Group(""), - Group(""), - Group("", layout='floating', layouts=[ - layout.Floating( - border_focus="#990000", - border_normal="#440000" - ) - ]) - ] + groups = [] + + for group in Config.get('groups', [{'name': '1'}]): + if 'layout' in group: + if group['layout'] == "floating": + groups.append(Group( + group['name'], + layout="floating", + layouts=[ + layout.Floating(**group.get('options', {})) + ] + )) + else: + logger.warning(f"Unknown group layout for group '{group['name']}': {group['layout']}") + else: + groups.append(Group(group['name'])) return groups def init_layouts(self): @@ -288,8 +276,8 @@ class Kuro(BaseTheme): def initialize_colorscheme(self): colors = None - if os.path.isfile("/home/kevin/.cache/wal/colors.json"): - with open("/home/kevin/.cache/wal/colors.json", 'r') as f: + if os.path.isfile(f"{Config.get('homedir', '~')}/.cache/wal/colors.json"): + with open(f"{Config.get('homedir', '~')}/.cache/wal/colors.json", 'r') as f: try: colors = json.load(f)['colors'] except KeyError: @@ -305,26 +293,34 @@ class Kuro(BaseTheme): Config.bar_background = colors['color1'] def reinit_screens(self): - # TODO: Move backend check into utils method - if qtile.core.name == "x11": - self.num_screens = max(1, utils.get_screen_count()) + if Config.get("use_fake_screens", False): + logger.warning(f"Using fake screens!") + self.num_screens = Config.get("fake_screen_count", 1) else: - self.num_screens = max(1, len(qtile.core.get_screen_info())) + self.num_screens = max(1, utils.get_screen_count()) logger.warning(f"Detected {self.num_screens} screens.") + screen_kwargs = Config.get("screen_kwargs", []) + for x in range(self.num_screens): - logger.warning("Reconfiguring bars for screen {}".format(x)) + logger.warning(f"Reconfiguring bars for screen {x}") try: screen = self.screens[x] except IndexError: - screen = Screen() + try: + kwargs = screen_kwargs[x] + logger.warning(f"Config for screen {x}: {kwargs}") + except IndexError: + logger.warning(f"No kwarg config for screen {x}") + kwargs = {} + screen = Screen(**kwargs) if screen.top is None: screen.top = self.build_bar_for_screen(x) topbar = screen.top - self.screens.append(Screen(top=topbar)) + self.screens.append(screen) def update_keys(self): logger.warning("Updating keys") @@ -399,60 +395,61 @@ class Kuro(BaseTheme): ] # Media widget(s) - widgets.extend([ - # An MPRIS widget that shows the media play status as an icon. - widget.Mpris2( - font=Config.get('font_groupbox', 'Arial'), - fontsize=Config.get('fontsize_groupbox', 15), - format="", - scroll=False, - playing_text="", - paused_text="", - stopped_text="", - no_metadata_text="", - name=f"media_icon{screen_num}", - mouse_callbacks={ - "Button1": lazy.widget[f"media_icon{screen_num}"].play_pause(), - "Button3": lazy.widget[f"media_icon{screen_num}"].next(), - "Button4": lambda: None, - "Button5": lambda: None, - } - ), - # An MPRIS widget that shows the currently playing song information in a nice format. - widget.Mpris2( - font=Config.get('font_topbar', 'Arial'), - fontsize=Config.get('fontsize_topbar', 15), - format="{xesam:title} - {xesam:artist} - {xesam:album}", - scroll=True, - width=300, # Maximum width before widget starts scrolling - playing_text="{track}", - paused_text="{track}", - stopped_text="", - no_metadata_text="No metadata available", - name=f"media_text{screen_num}", - mouse_callbacks={ - "Button1": lazy.widget[f"media_icon{screen_num}"].play_pause(), - "Button3": lazy.widget[f"media_icon{screen_num}"].next(), - "Button4": lambda: None, - "Button5": lambda: None, - } - ), - # An MPRIS widget masquerading as a text widget, that only shows "|" when media is playing or paused. - widget.Mpris2( - fontsize=14, - format="", - scroll=False, - playing_text="|", - paused_text="|", - stopped_text="", - no_metadata_text="", - mouse_callbacks={ - "Button1": lambda: None, - "Button4": lambda: None, - "Button5": lambda: None, - } - ) - ]) + if Config.get('show_media_widget', False): + widgets.extend([ + # An MPRIS widget that shows the media play status as an icon. + widget.Mpris2( + font=Config.get('font_groupbox', 'Arial'), + fontsize=Config.get('fontsize_groupbox', 15), + format="", + scroll=False, + playing_text="", + paused_text="", + stopped_text="", + no_metadata_text="", + name=f"media_icon{screen_num}", + mouse_callbacks={ + "Button1": lazy.widget[f"media_icon{screen_num}"].play_pause(), + "Button3": lazy.widget[f"media_icon{screen_num}"].next(), + "Button4": lambda: None, + "Button5": lambda: None, + } + ), + # An MPRIS widget that shows the currently playing song information in a nice format. + widget.Mpris2( + font=Config.get('font_topbar', 'Arial'), + fontsize=Config.get('fontsize_topbar', 15), + format="{xesam:title} - {xesam:artist} - {xesam:album}", + scroll=True, + width=300, # Maximum width before widget starts scrolling + playing_text="{track}", + paused_text="{track}", + stopped_text="", + no_metadata_text="No metadata available", + name=f"media_text{screen_num}", + mouse_callbacks={ + "Button1": lazy.widget[f"media_icon{screen_num}"].play_pause(), + "Button3": lazy.widget[f"media_icon{screen_num}"].next(), + "Button4": lambda: None, + "Button5": lambda: None, + } + ), + # An MPRIS widget masquerading as a text widget, that only shows "|" when media is playing or paused. + widget.Mpris2( + fontsize=14, + format="", + scroll=False, + playing_text="|", + paused_text="|", + stopped_text="", + no_metadata_text="", + mouse_callbacks={ + "Button1": lambda: None, + "Button4": lambda: None, + "Button5": lambda: None, + } + ) + ]) # Sensor widgets sensor_widgets = [] @@ -583,12 +580,13 @@ class Kuro(BaseTheme): logger.warning("Restoring wallpaper...") if self.current_wallpaper: - p = utils.execute_once(["wallust", "run", "{}".format(self.current_wallpaper)]) - p.wait() + p = utils.execute_once([*Config.get('cmd_wal', ['wallust', 'run']), "{}".format(self.current_wallpaper)]) + if p: + 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: + if os.path.isfile(f"{Config.get('homedir', '~')}/.cache/wal/colors.json"): + with open(f"{Config.get('homedir', '~')}/.cache/wal/colors.json", 'r') as f: try: wallpaper = json.load(f)['wallpaper'] except KeyError: @@ -741,7 +739,8 @@ class Kuro(BaseTheme): def set_wallpaper(self, filename): if qtile.core.name == "x11": p = utils.execute_once(f"{Config.get('x11_wallpaper_config_command', 'wal-nitrogen-noupdate')} {filename}") - p.wait() + if p: + p.wait() else: # Wayland can set wallpaper in qtile directly per screen for screen_i, screen in enumerate(qtile.screens): @@ -760,12 +759,13 @@ class Kuro(BaseTheme): def update_colorscheme(self, *args, **kwargs): if self.current_wallpaper: logger.warning(f"Updating wal colors for wallpaper {self.current_wallpaper}") - p = utils.execute_once(["wallust", "run", "{}".format(self.current_wallpaper)]) - p.wait() + p = utils.execute_once([*Config.get('cmd_wal', ['wallust', 'run']), "{}".format(self.current_wallpaper)]) + if p: + 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: + if os.path.isfile(f"{Config.get('homedir', '~')}/.cache/wal/colors.json"): + with open(f"{Config.get('homedir', '~')}/.cache/wal/colors.json", 'r') as f: try: colors = json.load(f)['colors'] except KeyError: @@ -851,7 +851,8 @@ class Kuro(BaseTheme): try: logger.warning(f"Calling 'pywalfox update'...") p = utils.execute(["pywalfox", "update"]) - p.wait() + if p: + p.wait() except subprocess.SubprocessError as e: logger.error(f"Error running 'pywalfox update': {e}") diff --git a/kuro/utils/general.py b/kuro/utils/general.py index 0fb66e9..35944f2 100644 --- a/kuro/utils/general.py +++ b/kuro/utils/general.py @@ -65,7 +65,7 @@ def start_in_group(theme, qtile, group: str, command: List[str], floating: bool theme.autostart_app_rules[proc.pid] = rule_id return proc except FileNotFoundError as e: - logger.error(f"Could not execute {process}, FileNotFoundError - {e}") + logger.error(f"Could not execute {command}, FileNotFoundError - {e}") def start_in_group_once(theme, qtile, group: str, command: List[str], floating: bool = False, @@ -90,17 +90,12 @@ def get_screen_count(): logger.info("Using xrandr to detect screen count") output = subprocess.check_output("xrandr -q".split()).decode('utf-8') output = [x for x in output.split("\n") if " connected" in x] + return max(1, len(output)) else: - logger.info("Using lsmon (wallutils) to detect screen count") - output = subprocess.check_output(["lsmon"]).decode('utf-8') - output = output.split("\n") + return max(1, len(qtile.core.get_screen_info())) except subprocess.CalledProcessError: - return 1 - - if output: - return len(output) - else: - return 1 + pass + return 1 def bar_separator(config): From c58e1d4e5c9c80588173ddc69844592f00342c9c Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Fri, 5 Sep 2025 11:26:08 +0200 Subject: [PATCH 16/17] Fix screen resolution detection in-office --- kuro/config/ppc1006083.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kuro/config/ppc1006083.py b/kuro/config/ppc1006083.py index ceb9eae..8797168 100644 --- a/kuro/config/ppc1006083.py +++ b/kuro/config/ppc1006083.py @@ -106,7 +106,7 @@ class Config(GeneralConfig): {'x': 1920, 'y': 0, 'width': 1080, 'height': qtile_height}, ] # Dual 1680x1050 - elif qtile_width == 3360 and qtile_height == 1050: + elif qtile_width == 3360 and (qtile_height > 1040 and qtile_height <= 1050): cls.screen_kwargs = [ {'x': 0, 'y': 0, 'width': 1680, 'height': 1050}, {'x': 1680, 'y': 0, 'width': 1680, 'height': 1050}, From ee311b12bed7562a447307f35f4acce7883cf1dd Mon Sep 17 00:00:00 2001 From: Kevin Alberts Date: Fri, 5 Sep 2025 11:59:38 +0200 Subject: [PATCH 17/17] More screen resolution detection fixes --- kuro/config/ppc1006083.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/kuro/config/ppc1006083.py b/kuro/config/ppc1006083.py index 8797168..06f171a 100644 --- a/kuro/config/ppc1006083.py +++ b/kuro/config/ppc1006083.py @@ -102,7 +102,7 @@ class Config(GeneralConfig): # Home office, 1920x1080 horizontal right and 1080x1920 vertical left if qtile_width == 3000 and (qtile_height > 1912 and qtile_height <= 1920): cls.screen_kwargs = [ - {'x': 0, 'y': 840, 'width': 1920, 'height': qtile_height-840}, + {'x': 0, 'y': 839, 'width': 1920, 'height': qtile_height-839}, {'x': 1920, 'y': 0, 'width': 1080, 'height': qtile_height}, ] # Dual 1680x1050 @@ -112,22 +112,20 @@ class Config(GeneralConfig): {'x': 1680, 'y': 0, 'width': 1680, 'height': 1050}, ] # Dual 1920x1080 - elif qtile_width == 3840 and qtile_height == 1080: + elif qtile_width == 3840 and (qtile_height > 1070 and qtile_height <= 1080): cls.screen_kwargs = [ {'x': 0, 'y': 0, 'width': 1920, 'height': 1080}, {'x': 1920, 'y': 0, 'width': 1920, 'height': 1080}, ] # Single 1920x1080 - elif qtile_width == 1920 and qtile_height == 1080: + elif qtile_width == 1920 and (qtile_height > 1070 and qtile_height <= 1080): cls.screen_kwargs = [{'x': 0, 'y': 0, 'width': 1920, 'height': 1080}] # Single 1680x1050 - elif qtile_width == 1680 and qtile_height == 1050: + elif qtile_width == 1680 and (qtile_height > 1040 and qtile_height <= 1050): cls.screen_kwargs = [{'x': 0, 'y': 0, 'width': 1680, 'height': 1050}] - # Else, set to autoconfigure + # Else, configure for 1 large screen else: - cls.screen_kwargs = [] - # {'x': 0, 'y': 0, 'width': int(os.getenv("QTILE_WIDTH", "3840"))//2, 'height': int(os.getenv("QTILE_HEIGHT", "1080"))}, - # {'x': int(os.getenv("QTILE_WIDTH", "3840"))//2, 'y': 0, 'width': int(os.getenv("QTILE_WIDTH", "3840"))//2, 'height': int(os.getenv("QTILE_HEIGHT", "1080"))}, + cls.screen_kwargs = [{'x': 0, 'y': 0, 'width': qtile_width, 'height': qtile_height}] logger.warning(f"Kwargs: {cls.screen_kwargs}")