From f4c6430eb41db08622c98076d01bfca929e38be3 Mon Sep 17 00:00:00 2001 From: Kevin Alberts <kevin@kevinalberts.nl> Date: Wed, 14 Oct 2020 18:59:03 +0200 Subject: [PATCH 1/7] Changes on Celestia --- kuro/config.py | 4 +++- kuro/theme.py | 11 ++++++++++- required_packages.txt | 3 ++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/kuro/config.py b/kuro/config.py index 05f2f87..aba2092 100644 --- a/kuro/config.py +++ b/kuro/config.py @@ -16,7 +16,9 @@ class Config(BaseConfig): # Default Applications app_terminal = "terminator" - app_launcher = "/home/kevin/bin/dmenu_wal.sh" + #app_launcher = "/home/kevin/bin/dmenu_wal.sh" + app_launcher = "dmenu_run -i -p '»' -nb '" + background + "' -fn 'Noto Sans-11' -nf '" + inactive_light + \ + "' -sb '" + highlight + "' -sf '" + foreground + "'" web_browser = "firefox-developer-edition" file_manager = "thunar" app_chat = "/home/kevin/bin/ramboxpro" diff --git a/kuro/theme.py b/kuro/theme.py index ac322df..30472b3 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -149,6 +149,9 @@ class Kuro(BaseTheme): # 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 @@ -180,7 +183,7 @@ class Kuro(BaseTheme): # Screenshot key Key([], "Print", lazy.spawn(Config.get('cmd_screenshot', 'xfce4-screenshooter'))), - # Alt Screenshot + # Alt screenshot Key([self.mod], "Print", lazy.spawn(Config.get('cmd_alt_screenshot', 'xfce4-screenshooter'))), # Toggle between different layouts as defined below @@ -564,6 +567,12 @@ class Kuro(BaseTheme): 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) diff --git a/required_packages.txt b/required_packages.txt index 8b3391e..ff3bd88 100644 --- a/required_packages.txt +++ b/required_packages.txt @@ -8,4 +8,5 @@ python-osc playerctl xfce4-screenshooter -xfce4-clipman-plugin \ No newline at end of file +xfce4-clipman-plugin +wireless_tools From a033bde573fee44f09fb9de5045b378e55406cdc Mon Sep 17 00:00:00 2001 From: Kevin Alberts <kevin@kevinalberts.nl> Date: Thu, 15 Apr 2021 17:11:48 +0200 Subject: [PATCH 2/7] Changes to Celestia --- kuro/base.py | 24 +++++------- kuro/config.py | 13 +++++-- kuro/theme.py | 73 ++++++++++++++++++++----------------- kuro/utils/general.py | 9 ++++- kuro/utils/layouts.py | 85 ++++++++++++++++++------------------------- 5 files changed, 101 insertions(+), 103 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/config.py b/kuro/config.py index aba2092..b986e53 100644 --- a/kuro/config.py +++ b/kuro/config.py @@ -122,7 +122,8 @@ class Config(BaseConfig): volume_font = "Noto Sans" volume_fontsize = 11 volume_theme_path = "/home/kevin/.config/qtile/kuro/resources/volume" - volume_pulse_sink = "alsa_output.pci-0000_00_1f.3.analog-stereo" + volume_pulse_sink = "alsa_output.pci-0000_04_00.0.pro-output-0" + volume_pulse_sink2 = "alsa_output.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.pro-output-0" volume_is_bluetooth_icon = False volume_update_interval = 0.2 @@ -151,12 +152,18 @@ 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 show_temperature = True + # Show GPU widget + show_gpu_widget = False + + # Show battery widget + show_battery_widget = False + # Audio control applications # apps_audio = ["pavucontrol"] - apps_audio_afterstart = "/home/kevin/bin/start_jack_audio_chain.sh" + apps_audio_afterstart = [] diff --git a/kuro/theme.py b/kuro/theme.py index 30472b3..27012d6 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): @@ -245,14 +239,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", @@ -360,19 +347,34 @@ class Kuro(BaseTheme): 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), + ]) + if Config.get('show_battery_widget', False): + widgets.extend([ + kuro.utils.widgets.BatteryInfoWidget(fontsize_left=16, fontsize_right=11), + ]) + widgets.extend([ kuro.utils.widgets.VolumeInfoWidget( pulse_sink=Config.get('volume_pulse_sink', None), fontsize_left=18, fontsize_right=11, ), + kuro.utils.widgets.VolumeInfoWidget( + pulse_sink=Config.get('volume_pulse_sink2', 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, - ), + ]) + if Config.get('show_gpu_widget', False): + widgets.extend([ + kuro.utils.widgets.GPUStatusWidget( + theme_path=Config.get('gpu_theme_path', '/home/docs/checkouts/readthedocs.org/user_builds/qtile' + '/checkouts/latest/libqtile/resources/battery-icons'), + padding=0, + ) + ]) + widgets.extend([ kuro.utils.widgets.TextSpacerWidget(fontsize=14), ]) @@ -388,6 +390,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), @@ -481,7 +484,6 @@ class Kuro(BaseTheme): @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" @@ -600,11 +602,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() @@ -636,9 +641,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..bfa32fc 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 6a265ea3b617aa9dc9be34aa302862b1130732fb Mon Sep 17 00:00:00 2001 From: Kevin Alberts <kevin@kevinalberts.nl> Date: Mon, 22 Nov 2021 19:42:03 +0100 Subject: [PATCH 3/7] Compatibility with latest qtile, fixes to widgets, etc... --- config.py | 3 --- kuro/config.py | 16 +++++------ kuro/theme.py | 63 ++++++++++++++++++++++++++----------------- kuro/utils/general.py | 2 +- kuro/utils/widgets.py | 41 ++++++++++++++++++++-------- kuro/utils/windows.py | 3 +-- 6 files changed, 78 insertions(+), 50 deletions(-) diff --git a/config.py b/config.py index c3abfcd..7d5f49f 100644 --- a/config.py +++ b/config.py @@ -121,8 +121,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 b986e53..480de2c 100644 --- a/kuro/config.py +++ b/kuro/config.py @@ -16,12 +16,10 @@ class Config(BaseConfig): # Default Applications app_terminal = "terminator" - #app_launcher = "/home/kevin/bin/dmenu_wal.sh" - app_launcher = "dmenu_run -i -p '»' -nb '" + background + "' -fn 'Noto Sans-11' -nf '" + inactive_light + \ - "' -sb '" + highlight + "' -sf '" + foreground + "'" + app_launcher = "/home/kevin/bin/dmenu_wal.sh" web_browser = "firefox-developer-edition" file_manager = "thunar" - app_chat = "/home/kevin/bin/ramboxpro" + app_chat = "/usr/bin/ramboxpro" app_irc = "quasselclient" app_mail = "thunderbird" cmd_brightness_up = "sudo /usr/bin/xbacklight -inc 10" @@ -94,8 +92,8 @@ class Config(BaseConfig): # Thermal indicator variables thermal_threshold = 75 - thermal_sensor = "Package id 0" - thermal_chip = "coretemp-isa-0000" + thermal_sensor = "Tdie" + thermal_chip = "zenpower-pci-00c3" # CPU graph variables cpu_graph_colour = '#ff0000' @@ -122,8 +120,8 @@ class Config(BaseConfig): volume_font = "Noto Sans" volume_fontsize = 11 volume_theme_path = "/home/kevin/.config/qtile/kuro/resources/volume" - volume_pulse_sink = "alsa_output.pci-0000_04_00.0.pro-output-0" - volume_pulse_sink2 = "alsa_output.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.pro-output-0" + volume_pulse_sink = "alsa_output.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo" + volume_pulse_sink2 = "alsa_output.pci-0000_0e_00.4.analog-stereo" volume_is_bluetooth_icon = False volume_update_interval = 0.2 @@ -152,7 +150,7 @@ class Config(BaseConfig): do_keyboard_updates = False # Show audio visualizer - show_audio_visualizer = False + show_audio_visualizer = True kill_unnecessary_glava_processes = True # Show thermal widget diff --git a/kuro/theme.py b/kuro/theme.py index 27012d6..aebeb85 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...") @@ -83,13 +83,14 @@ 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 ]) 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: + if qtile is not None: bar.draw() def log_debug(self, text): @@ -144,7 +145,7 @@ class Kuro(BaseTheme): Key([self.mod, "shift"], 'f', lazy.window.toggle_floating()), # Pinned toggle - Key([self.mod], 'p', lazy.function(self.toggle_pinned)), + Key([self.mod, "shift"], 'p', lazy.function(self.toggle_pinned)), # Toggle between split and unsplit sides of stack. # Split = all windows displayed @@ -513,22 +514,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: @@ -577,13 +578,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() @@ -596,7 +604,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() @@ -610,6 +618,9 @@ class Kuro(BaseTheme): self.log_info("Starting notification daemon...") utils.execute_once("dunst") + self.log_info("Starting xiccd color profile manager...") + utils.execute_once("xiccd") + # Update color scheme self.initialize_colorscheme() @@ -635,9 +646,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 @@ -651,12 +666,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 @@ -664,27 +679,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: @@ -693,10 +708,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: @@ -722,11 +737,11 @@ class Kuro(BaseTheme): # Detach visualizer from widget if it was a visualizer window if isinstance(client, KuroStatic): - 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 == client: - screen_index = self.qtile.screens.index(screen) + screen_index = qtile.screens.index(screen) logger.warning("Detaching {} {} from widget {} on screen {}".format(client, client.window.wid, type(widget).__name__, screen_index)) widget.client = None widget.screen = None @@ -876,7 +891,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/general.py b/kuro/utils/general.py index bfa32fc..92551f7 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 a122a50..7620d1a 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 @@ -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() + 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 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 cdf5996c4031fef4897366838d9ee7886f902d91 Mon Sep 17 00:00:00 2001 From: Kevin Alberts <kevin@kevinalberts.nl> Date: Sat, 28 May 2022 13:57:05 +0200 Subject: [PATCH 4/7] Updates over time --- kuro/config.py | 2 +- kuro/theme.py | 6 ++++++ kuro/utils/general.py | 2 +- kuro/utils/widgets.py | 2 ++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/kuro/config.py b/kuro/config.py index 480de2c..3e05df9 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/theme.py b/kuro/theme.py index aebeb85..40915d4 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -621,6 +621,12 @@ 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 indicator...") + utils.execute_once("/usr/bin/kdeconnect-indicator") + # Update color scheme self.initialize_colorscheme() diff --git a/kuro/utils/general.py b/kuro/utils/general.py index 92551f7..76a1f0a 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 7620d1a..b665507 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 9976e7f14423f35aaf63c7969b48937eda3e1825 Mon Sep 17 00:00:00 2001 From: Kevin Alberts <kevin@kevinalberts.nl> Date: Mon, 15 May 2023 11:41:58 +0200 Subject: [PATCH 5/7] various small changes --- kuro/config.py | 8 ++++++-- kuro/theme.py | 4 ++-- kuro/utils/widgets.py | 13 +++++++------ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/kuro/config.py b/kuro/config.py index 3e05df9..e82690b 100644 --- a/kuro/config.py +++ b/kuro/config.py @@ -17,11 +17,12 @@ 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" app_mail = "thunderbird" + app_music = "spotify" cmd_brightness_up = "sudo /usr/bin/xbacklight -inc 10" cmd_brightness_down = "sudo /usr/bin/xbacklight -dec 10" lock_command = "bash /home/kevin/bin/lock.sh" @@ -150,7 +151,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 @@ -165,3 +166,6 @@ class Config(BaseConfig): # Audio control applications # apps_audio = ["pavucontrol"] apps_audio_afterstart = [] + + # Comma-separated list of ignored players in the media widget + media_ignore_players = "kdeconnect" diff --git a/kuro/theme.py b/kuro/theme.py index 40915d4..f3d44d6 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -238,7 +238,7 @@ class Kuro(BaseTheme): 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("", spawn=Config.get('app_music', "true"))) groups.append(Group("")) groups.append(Group("", spawn=Config.get('apps_audio', "true"))) groups.append(Group("", layout='floating', layouts=[ @@ -325,7 +325,7 @@ class Kuro(BaseTheme): widgets.append(kuro.utils.widgets.AudioVisualizerWidget(margin_x=0, margin_y=0)) widgets.extend([ - kuro.utils.widgets.MediaWidget(), + kuro.utils.widgets.MediaWidget(ignore_players=Config.get('media_ignore_players', '')), kuro.utils.widgets.TextSpacerWidget(fontsize=14), ]) diff --git a/kuro/utils/widgets.py b/kuro/utils/widgets.py index b665507..43b31ed 100644 --- a/kuro/utils/widgets.py +++ b/kuro/utils/widgets.py @@ -262,6 +262,7 @@ class MediaWidget(base.InLoopPollText): ('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.'), + ('ignore_players', '', 'Comma-separated list of players to ignore.') ] player_icons = { @@ -319,13 +320,13 @@ class MediaWidget(base.InLoopPollText): if button == BUTTON_LEFT: player = self._player_to_control() if player is not None: - command = ["playerctl", "-p", player, "play-pause"] + command = ["playerctl", "-i", self.ignore_players, "-p", player, "play-pause"] _ = self.call_process(command) notify("MediaWidget", "Toggled {}".format(player)) if button == BUTTON_RIGHT: player = self._player_to_control() if player is not None: - command = ["playerctl", "-p", player, "next"] + command = ["playerctl", "-i", self.ignore_players, "-p", player, "next"] _ = self.call_process(command) if button == BUTTON_MIDDLE: # Jump to the screen that the player is on @@ -358,7 +359,7 @@ class MediaWidget(base.InLoopPollText): # Playerctl players try: - result = self.call_process(["playerctl", "-l"]) + result = self.call_process(["playerctl", "-i", self.ignore_players, "-l"]) except subprocess.CalledProcessError: result = None @@ -398,17 +399,17 @@ class MediaWidget(base.InLoopPollText): else: # PlayerCtl player - command = ["playerctl", "-p", player, "status"] + command = ["playerctl", "-i", self.ignore_players, "-p", player, "status"] cmd_result = self.call_process(command).strip() text = "Unknown" if cmd_result in ["Playing", "Paused"]: try: - artist = self.call_process(['playerctl', '-p', player, 'metadata', 'artist']).strip() + artist = self.call_process(['playerctl', "-i", self.ignore_players, '-p', player, 'metadata', 'artist']).strip() except subprocess.CalledProcessError: artist = None try: - title = self.call_process(['playerctl', '-p', player, 'metadata', 'title']).strip() + title = self.call_process(['playerctl', "-i", self.ignore_players, '-p', player, 'metadata', 'title']).strip() except subprocess.CalledProcessError: title = None From b279b258462f92ce7dcd45c9e281597f78a81f1f Mon Sep 17 00:00:00 2001 From: Kevin Alberts <kevin@kevinalberts.nl> Date: Sat, 28 Oct 2023 10:16:10 +0200 Subject: [PATCH 6/7] Updates on Violet --- kuro/config.py | 18 ++++++++++++++++-- kuro/theme.py | 19 +++++++++++++++++++ kuro/utils/general.py | 18 ++++++++++-------- kuro/utils/widgets.py | 22 +++++++++++++++++++++- 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/kuro/config.py b/kuro/config.py index e82690b..6761564 100644 --- a/kuro/config.py +++ b/kuro/config.py @@ -30,6 +30,20 @@ class Config(BaseConfig): cmd_screenshot = "xfce4-screenshooter -r -c -d 1" cmd_alt_screenshot = "xfce4-screenshooter -w -c -d 0" + # Keyboard commands + cmd_media_play = "playerctl -i kdeconnect play-pause" + cmd_media_next = "playerctl -i kdeconnect next" + cmd_media_mute = "pamixer -t" + cmd_media_volume_down = "pamixer -i 2" + 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" + # Commands wallpaper_config_command = "/home/kevin/bin/wal-nitrogen-noupdate" @@ -121,8 +135,8 @@ class Config(BaseConfig): volume_font = "Noto Sans" volume_fontsize = 11 volume_theme_path = "/home/kevin/.config/qtile/kuro/resources/volume" - volume_pulse_sink = "alsa_output.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo" - volume_pulse_sink2 = "alsa_output.pci-0000_0e_00.4.analog-stereo" + volume_pulse_sink = "alsa_output.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo-output" + volume_pulse_sink2 = "alsa_output.pci-0000_0d_00.4.analog-stereo" volume_is_bluetooth_icon = False volume_update_interval = 0.2 diff --git a/kuro/theme.py b/kuro/theme.py index f3d44d6..f6f0946 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -175,6 +175,23 @@ class Kuro(BaseTheme): Key([], "XF86MonBrightnessUp", lazy.spawn(Config.get('cmd_brightness_up', 'xbacklight -inc 10'))), Key([], "XF86MonBrightnessDown", lazy.spawn(Config.get('cmd_brightness_down', 'xbacklight -dec 10'))), + # Display modes + Key([self.mod], "Prior", lazy.spawn(Config.get('cmd_monitor_mode_3s144', 'true'))), + Key([self.mod], "Next", lazy.spawn(Config.get('cmd_monitor_mode_3s60', 'true'))), + Key([self.mod], "Home", lazy.spawn(Config.get('cmd_monitor_mode_day', 'true'))), + Key([self.mod], "End", lazy.spawn(Config.get('cmd_monitor_mode_night', 'true'))), + Key([self.mod], "Insert", lazy.spawn(Config.get('cmd_monitor_mode_alt', 'true'))), + + # Media keys + Key([], "XF86AudioPlay", lazy.spawn(Config.get('cmd_media_play', 'true'))), + Key([], "XF86AudioNext", lazy.spawn(Config.get('cmd_media_next', 'true'))), + Key([], "XF86AudioMute", lazy.spawn(Config.get('cmd_media_mute', 'true'))), + Key([], "XF86AudioRaiseVolume", lazy.spawn(Config.get('cmd_media_volume_up', 'true'))), + Key([], "XF86AudioLowerVolume", lazy.spawn(Config.get('cmd_media_volume_down', 'true'))), + + # Sleep key + Key([], "XF86Sleep", lazy.spawn(Config.get('cmd_sleep', 'true'))), + # Screenshot key Key([], "Print", lazy.spawn(Config.get('cmd_screenshot', 'xfce4-screenshooter'))), @@ -358,11 +375,13 @@ class Kuro(BaseTheme): pulse_sink=Config.get('volume_pulse_sink', None), fontsize_left=18, fontsize_right=11, + font_left=Config.get('font_groupbox', None), ), kuro.utils.widgets.VolumeInfoWidget( pulse_sink=Config.get('volume_pulse_sink2', None), fontsize_left=18, fontsize_right=11, + font_left=Config.get('font_groupbox', None), ), kuro.utils.widgets.TextSpacerWidget(fontsize=14), kuro.utils.widgets.NetworkInfoWidget(fontsize_left=16, fontsize_right=14), diff --git a/kuro/utils/general.py b/kuro/utils/general.py index 76a1f0a..f63e1ad 100644 --- a/kuro/utils/general.py +++ b/kuro/utils/general.py @@ -204,22 +204,24 @@ class KuroTopBar(Bar): self.window.update_name() def draw(self): - if self.queued_draws == 0: - self.qtile.call_soon(self._actual_draw) - self.queued_draws += 1 + if not self.widgets: + return + if not self._draw_queued: + self.future = self.qtile.call_soon(self._actual_draw) + self._draw_queued = True def _actual_draw(self): - self.queued_draws = 0 - self._resize(self.length, self.widgets) + self._draw_queued = False + self._resize(self._length, self.widgets) for i in self.widgets: i.draw() if self.widgets: end = i.offset + i.length - if end < self.length: + if end < self._length: if self.horizontal: - self.drawer.draw(offsetx=end, width=self.length - end) + self.drawer.draw(offsetx=end, width=self._length - end) else: - self.drawer.draw(offsety=end, height=self.length - end) + self.drawer.draw(offsety=end, height=self._length - end) self.theme.update_visualizers() diff --git a/kuro/utils/widgets.py b/kuro/utils/widgets.py index 43b31ed..d03c0da 100644 --- a/kuro/utils/widgets.py +++ b/kuro/utils/widgets.py @@ -139,6 +139,26 @@ class DualPaneTextboxBase(base._Widget): if self.layout_right: self.layout_right.font = value + @property + def font_left(self): + return self._font_left + + @font_left.setter + def font_left(self, value): + self._font_left = value + if self.layout_left: + self.layout_left.font = value + + @property + def font_right(self): + return self._font_right + + @font_right.setter + def font_right(self, value): + self._font_right = value + if self.layout_right: + self.layout_right.font = value + @property def fontshadow(self): return self._fontshadow @@ -1197,7 +1217,7 @@ class VolumeInfoWidget(DualPaneTextboxBase): """Displays information about the volume""" orientations = base.ORIENTATION_HORIZONTAL defaults = [ - ('update_interval', 10, 'The update interval in seconds.'), + ('update_interval', 5, 'The update interval in seconds.'), ('text_pattern', "{percentage}%", 'The pattern for the text that is displayed.'), ('charging_color', "#ffffff", "Color when battery is charging"), ('normal_color', "#ffffff", "Color when value is normal"), From 1e650250450bfae59b049b655a24ea5a27fe9bd3 Mon Sep 17 00:00:00 2001 From: Kevin Alberts <kevin@kevinalberts.nl> Date: Mon, 5 Feb 2024 20:19:39 +0100 Subject: [PATCH 7/7] Filter vertical walls, add vorta --- kuro/theme.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kuro/theme.py b/kuro/theme.py index f6f0946..f85eb9e 100644 --- a/kuro/theme.py +++ b/kuro/theme.py @@ -646,6 +646,9 @@ class Kuro(BaseTheme): self.log_info("Starting KDE connect indicator...") utils.execute_once("/usr/bin/kdeconnect-indicator") + self.log_info("Starting automatic backup scheduler...") + utils.execute_once("/usr/bin/vorta") + # Update color scheme self.initialize_colorscheme() @@ -782,7 +785,7 @@ class Kuro(BaseTheme): wallpapers = [] wallpaper_dir = Config.get("desktop_bg_folder", "") try: - wallpapers = os.listdir(wallpaper_dir) + 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))