From c4e522f17a3f504de2981c7600443449e08b0607 Mon Sep 17 00:00:00 2001 From: Makesesama Date: Mon, 29 Sep 2025 11:36:33 +0200 Subject: [PATCH] fix battery usage --- bar/modules/bar.py | 16 ++++---- bar/modules/battery.py | 55 +++++++-------------------- bar/modules/player.py | 19 ++++++++++ bar/services/battery.py | 72 ++++++++++++++++++++++++++++++++++++ bar/services/system_stats.py | 65 ++++++++++++++++++++++++++++++++ 5 files changed, 177 insertions(+), 50 deletions(-) create mode 100644 bar/services/battery.py create mode 100644 bar/services/system_stats.py diff --git a/bar/modules/bar.py b/bar/modules/bar.py index f7acf92..ea71070 100644 --- a/bar/modules/bar.py +++ b/bar/modules/bar.py @@ -15,10 +15,8 @@ from fabric.river.widgets import ( RiverActiveWindow, get_river_connection, ) -from fabric.utils import ( - invoke_repeater, -) from fabric.widgets.circularprogressbar import CircularProgressBar +from bar.services.system_stats import SystemStatsService from bar.config import VINYL, BATTERY, BAR_HEIGHT, WINDOW_TITLE @@ -134,14 +132,16 @@ class StatusBar(Window): ), ) - invoke_repeater(1000, self.update_progress_bars) + # Create system stats service with signal-based updates + self.system_stats_service = SystemStatsService(update_interval=3000) + self.system_stats_service.connect("stats-changed", self.update_progress_bars) # Set the bar height self.set_size_request(-1, BAR_HEIGHT) self.show_all() - def update_progress_bars(self): - self.ram_progress_bar.value = psutil.virtual_memory().percent / 100 - self.cpu_progress_bar.value = psutil.cpu_percent() / 100 - return True + def update_progress_bars(self, service, cpu_percent, memory_percent): + """Update progress bars when system stats change""" + self.cpu_progress_bar.value = cpu_percent + self.ram_progress_bar.value = memory_percent diff --git a/bar/modules/battery.py b/bar/modules/battery.py index 2cbe7a5..c12d92e 100644 --- a/bar/modules/battery.py +++ b/bar/modules/battery.py @@ -1,38 +1,13 @@ -import psutil from gi.repository import GLib from fabric.widgets.box import Box from fabric.widgets.label import Label from fabric.widgets.image import Image -from fabric import Fabricator - - -class BatteryProvider: - def __init__(self): - self.bat_percent = 0.0 - self.bat_charging = None - - self._update() - GLib.timeout_add_seconds(1, self._update) - - def _update(self): - battery = psutil.sensors_battery() - if battery is None: - self.bat_percent = 0.0 - self.bat_charging = None - else: - self.bat_percent = battery.percent - self.bat_charging = battery.power_plugged - - return True - - def get_battery(self): - return (self.bat_percent, self.bat_charging) +from bar.services.battery import BatteryService class Battery(Box): def __init__(self, **kwargs): super().__init__(name="battery-widget", orientation="h", spacing=4, **kwargs) - self.bat_provider = BatteryProvider() self.bat_icon = Image( name="bat-icon", icon_name="battery-full-symbolic", icon_size=16 @@ -40,18 +15,17 @@ class Battery(Box): self.bat_label = Label(name="bat-label", label="100%") - self.bat_fabricator = Fabricator( - poll_from=lambda *_: self.bat_provider.get_battery(), - on_changed=self.update_battery, - interval=1000, - stream=False, - default_value=(100, False), - ) + # Create battery service with signal-based updates + self.battery_service = BatteryService(update_interval=10000) # Check every 10 seconds + self.battery_service.connect("battery-changed", self.update_battery) self.children = [self.bat_icon, self.bat_label] self.show_all() - GLib.idle_add(self.update_battery, None, self.bat_provider.get_battery()) + # Initialize with current battery status + initial_percent = self.battery_service.percent + initial_charging = self.battery_service.charging + GLib.idle_add(self.update_battery, None, initial_percent, initial_charging) def _icon_lookup(self, bat, charging): # Round to nearest 10 for level-based icons @@ -62,19 +36,16 @@ class Battery(Box): else: return f"battery-level-{level}-symbolic" - def update_battery(self, sender, battery_data): - value, charging = battery_data - - icon_name = self._icon_lookup(value, charging) + def update_battery(self, service, percent, charging): + """Update battery display when battery status changes""" + icon_name = self._icon_lookup(percent, charging) self.bat_icon.set_property("icon-name", icon_name) - self.bat_label.set_text(f"{int(value)}%") + self.bat_label.set_text(f"{int(percent)}%") - if value < 20 and not charging: + if percent < 20 and not charging: self.bat_label.add_style_class("battery-low") self.bat_icon.add_style_class("battery-low") else: self.bat_label.remove_style_class("battery-low") self.bat_icon.remove_style_class("battery-low") - - return True diff --git a/bar/modules/player.py b/bar/modules/player.py index 9ec1345..d3a7fde 100644 --- a/bar/modules/player.py +++ b/bar/modules/player.py @@ -13,10 +13,29 @@ from fabric.widgets.stack import Stack from ..widgets.circle_image import CircleImage import bar.modules.icons as icons from bar.services.mpris import MprisPlayerManager, MprisPlayer +from fabric import Fabricator # from bar.modules.cavalcade import SpectrumRender +def get_player_progress(fabricator, mpris_player): + """Get player progress for Fabricator""" + if not mpris_player: + return (0, 0, 0.0) + + try: + current = mpris_player.position + except Exception: + current = 0 + try: + total = int(mpris_player.length or 0) + except Exception: + total = 0 + + progress = current / total if total > 0 else 0.0 + return (current, total, progress) + + def get_player_icon_markup_by_name(player_name): if player_name: pn = player_name.lower() diff --git a/bar/services/battery.py b/bar/services/battery.py new file mode 100644 index 0000000..740ba54 --- /dev/null +++ b/bar/services/battery.py @@ -0,0 +1,72 @@ +import psutil +from fabric.core.service import Service, Signal +from fabric.utils import invoke_repeater + + +class BatteryService(Service): + @Signal + def battery_changed(self, percent: float, charging: bool) -> None: + """Signal emitted when battery status changes""" + pass + + def __init__(self, update_interval=10000, **kwargs): # Check every 10 seconds + super().__init__(**kwargs) + self._percent = 0.0 + self._charging = False + self._update_interval = update_interval + self._timer_id = None + + # Start periodic updates + self.start_monitoring() + + def start_monitoring(self): + """Start monitoring battery status""" + if self._timer_id is None: + # Get initial values + self._update_battery() + # Set up periodic updates + self._timer_id = invoke_repeater(self._update_interval, self._update_battery) + + def stop_monitoring(self): + """Stop monitoring battery status""" + if self._timer_id is not None: + from gi.repository import GLib + GLib.source_remove(self._timer_id) + self._timer_id = None + + def _update_battery(self): + """Update battery status and emit signal if changed""" + try: + # Use the same pattern as the example + bat_sen = psutil.sensors_battery() + if not bat_sen: + # No battery sensor available (desktop systems) + new_percent = 100.0 # Assume plugged in + new_charging = True + else: + new_percent = bat_sen.percent + new_charging = bat_sen.power_plugged + + # Only emit signal if values changed + percent_changed = abs(new_percent - self._percent) > 0.5 + charging_changed = new_charging != self._charging + + if percent_changed or charging_changed: + self._percent = new_percent + self._charging = new_charging + self.battery_changed(new_percent, new_charging) + + except Exception as e: + print(f"Error updating battery status: {e}") + + return True # Keep the timer running + + @property + def percent(self): + """Get current battery percentage""" + return self._percent + + @property + def charging(self): + """Get current charging status""" + return self._charging \ No newline at end of file diff --git a/bar/services/system_stats.py b/bar/services/system_stats.py new file mode 100644 index 0000000..d50662f --- /dev/null +++ b/bar/services/system_stats.py @@ -0,0 +1,65 @@ +import psutil +from fabric.core.service import Service, Signal +from fabric.utils import invoke_repeater + + +class SystemStatsService(Service): + @Signal + def stats_changed(self, cpu_percent: float, memory_percent: float) -> None: + """Signal emitted when system stats change""" + pass + + def __init__(self, update_interval=3000, **kwargs): + super().__init__(**kwargs) + self._cpu_percent = 0.0 + self._memory_percent = 0.0 + self._update_interval = update_interval + self._timer_id = None + + # Start periodic updates + self.start_monitoring() + + def start_monitoring(self): + """Start monitoring system stats""" + if self._timer_id is None: + # Get initial values + self._update_stats() + # Set up periodic updates + self._timer_id = invoke_repeater(self._update_interval, self._update_stats) + + def stop_monitoring(self): + """Stop monitoring system stats""" + if self._timer_id is not None: + from gi.repository import GLib + GLib.source_remove(self._timer_id) + self._timer_id = None + + def _update_stats(self): + """Update system stats and emit signal if changed""" + try: + new_cpu = psutil.cpu_percent() + new_memory = psutil.virtual_memory().percent + + # Only emit signal if values changed significantly (reduce noise) + cpu_changed = abs(new_cpu - self._cpu_percent) > 1.0 + memory_changed = abs(new_memory - self._memory_percent) > 1.0 + + if cpu_changed or memory_changed: + self._cpu_percent = new_cpu + self._memory_percent = new_memory + self.stats_changed(new_cpu / 100, new_memory / 100) + + except Exception as e: + print(f"Error updating system stats: {e}") + + return True # Keep the timer running + + @property + def cpu_percent(self): + """Get current CPU percentage""" + return self._cpu_percent / 100 + + @property + def memory_percent(self): + """Get current memory percentage""" + return self._memory_percent / 100 \ No newline at end of file