#!/usr/bin/env python3 import dbus from gi.repository import AppIndicator3 from gi.repository import Gtk, GLib import subprocess import threading import pulsectl # Asegúrate de tener pulsectl instalado class VolumeApplet: def __init__(self): self.app = 'volume-applet' # Define el icono inicial self.indicator = AppIndicator3.Indicator.new( self.app, "audio-volume-medium", # Icono predeterminado AppIndicator3.IndicatorCategory.APPLICATION_STATUS ) self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE) self.indicator.set_menu(self.create_menu()) # Icono inicial basado en el volumen actual current_volume = self.get_current_volume() self.update_icon(current_volume) self.window = None # Ventana de la barra de volumen # Iniciar el monitoreo de cambios de volumen en un hilo separado self.pulse = pulsectl.Pulse('volume-applet') self.pulse.event_mask_set('sink') # Monitorea cambios en los sinks self.pulse.event_callback_set(self.on_pulse_event) self.monitor_thread = threading.Thread( target=self.pulse_event_listener, daemon=True) self.monitor_thread.start() def create_menu(self): menu = Gtk.Menu() # Agregar opción para abrir la barra de volumen vertical volume_item = Gtk.MenuItem(label="Ajustar Volumen") volume_item.connect("activate", self.show_volume_control) menu.append(volume_item) # Agregar opción para salir quit_item = Gtk.MenuItem(label="Salir") quit_item.connect("activate", Gtk.main_quit) menu.append(quit_item) menu.show_all() return menu def show_volume_control(self, source=None): if self.window: self.window.destroy() self.window = Gtk.Window(title="Control de Volumen") self.window.set_default_size(50, 200) # Barra vertical self.window.set_border_width(10) # Configurar la barra de volumen en orientación vertical volume_scale = Gtk.Scale.new_with_range( Gtk.Orientation.VERTICAL, 0, 100, 1) volume_scale.set_value(self.get_current_volume()) volume_scale.connect("value-changed", self.on_volume_changed) self.window.add(volume_scale) self.window.show_all() def on_volume_changed(self, scale): volume = int(scale.get_value()) subprocess.run(["pamixer", "--set-volume", str(volume)]) # Actualizar el icono y el tooltip en función del nuevo volumen self.update_icon(volume) def get_current_volume(self): try: result = subprocess.check_output(["pamixer", "--get-volume"]) return int(result.strip()) except subprocess.CalledProcessError: return 50 # Valor por defecto si pamixer falla def update_icon(self, volume): """Actualiza el icono y el tooltip basado en el nivel de volumen.""" if volume == 0: icon_name = "volume-0.png" elif 1 <= volume <= 33: icon_name = "volume-1.png" elif 34 <= volume <= 66: icon_name = "volume-2.png" elif 67 <= volume <= 75: icon_name = "volume-3.png" else: icon_name = "volume-4.png" # Ruta completa del icono icon_path = f"/home/teraflops/Icons/{icon_name}" tooltip = f"Volumen Actual: {volume}%" self.indicator.set_icon_full(icon_path, tooltip) # Establecer el tooltip explícitamente self.indicator.set_title(tooltip) def pulse_event_listener(self): """Escucha eventos de PulseAudio en un hilo separado.""" try: self.pulse.event_listen() except Exception as e: print(f"Error al escuchar eventos de PulseAudio: {e}") def on_pulse_event(self, event): """Callback para manejar eventos de PulseAudio.""" if event.t == 'change': # Verifica si el cambio es relevante para el volumen if event.facility == 'sink': # Obtén el volumen actual current_volume = self.get_current_volume() # Actualiza el icono y el tooltip en el hilo principal GLib.idle_add(self.update_icon, current_volume) def __del__(self): if hasattr(self, 'pulse'): self.pulse.close() def main(): app = VolumeApplet() Gtk.main() if __name__ == "__main__": main()