You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
7.5 KiB

#!/usr/bin/python3
import os
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib
import glib
import pulsectl
pulse = pulsectl.Pulse("PiPulse")
import threading
class CannotFindError ( Exception ):
pass
class MainWindow ( object ):
def __init__ ( self, gladeFile ):
self.builder = Gtk.Builder()
self.builder.add_from_file ( gladeFile );
self.alive = True
self.sources = []
self.sinks = []
self.default_sink = ""
self.default_source = ""
self.actions = []
self.MainWindow = self.builder.get_object ( "MainWindow" );
self.SourceImg = self.builder.get_object ( "InputImg" )
self.SinkImg = self.builder.get_object ( "OutputImg" )
self.SourceComboBox = self.builder.get_object ( "InputComboBox" );
self.SinkComboBox = self.builder.get_object ( "OutputComboBox" );
self.SourceComboBox.set_wrap_width(1)
self.SinkComboBox.set_wrap_width(1)
self.SourceDefault = self.builder.get_object ("InputDefault" )
self.SinkDefault = self.builder.get_object ("OutputDefault" )
self.SinkToggle = self.builder.get_object ( "OutputToggle" )
self.SourceToggle = self.builder.get_object ( "InputToggle" )
self.MainWindow.connect ("destroy", self.Destroy )
self.MainWindow.connect ("window-state-event", self.WindowStateTrigger )
self.SinkToggleSignal = self.SinkToggle.connect ("clicked", self.Mute, "sink" )
self.SourceToggleSignal = self.SourceToggle.connect ("clicked", self.Mute, "source" )
self.SinkChangedSignal = self.SinkComboBox.connect ("changed", self.SetDefaultThing, "sink" )
self.SourceChangedSignal = self.SourceComboBox.connect ("changed", self.SetDefaultThing, "source" )
self.waiter = threading.Thread ( target = self.WaitForEvents )
self.waiter.start()
self.MainWindow.set_title ( "PiPulse" )
def Mute ( self, w, d=None ):
if d == "sink":
self.actions += ["mute_sink"]
elif d=="source":
self.actions += ["mute_source"]
else:
return
pulse.event_listen_stop();
def SetDefaultThing ( self, w, d=None ):
if d == "sink":
self.actions += ["default_sink"]
elif d == "source":
self.actions += ["default_source"]
else:
return
print ("DefaultTrigger")
pulse.event_listen_stop()
def WaitForEvents ( self ):
while self.alive:
self.UpdateInternal ()
pulse.event_mask_set('sink','source')
pulse.event_callback_set( self.EvalEvents )
pulse.event_listen(timeout=10)
def Default ( self, l, default, attr="name" ):
for li in l:
if getattr(li, attr) == default:
return li
raise CannotFindError
def UpdateInternal ( self ):
self.sources = pulse.source_list()
self.sinks = pulse.sink_list()
self.default_source = pulse.server_info().default_source_name
self.default_sink = pulse.server_info().default_sink_name
actions = self.actions
for action in actions:
if action == "mute_sink":
try:
d = self.Default ( self.sinks, self.default_sink );
if d.mute == 0:
pulse.mute ( d, True );
else:
pulse.mute ( d, False );
except CannotFindError:
print ( "was not able to find default sink")
elif action == "mute_source":
try:
d = self.Default ( self.sources, self.default_source );
if d.mute == 0:
pulse.mute ( d, True );
else:
pulse.mute ( d, False );
except CannotFindError:
print ( "was not able to find default source")
elif action == "default_sink":
x = self.SinkComboBox.get_active_text()
try:
d = self.Default ( self.sinks, x, "description" )
pulse.default_set ( d )
except CannotFindError:
print ("was not able to find the selected sink")
elif action == "default_source":
x = self.SourceComboBox.get_active_text()
try:
d = self.Default ( self.sources, x, "description" )
pulse.default_set ( d )
except CannotFindError:
print ("was not able to find the selected sink")
self.actions.clear()
self.sources = pulse.source_list()
self.sinks = pulse.sink_list()
self.default_source = pulse.server_info().default_source_name
self.default_sink = pulse.server_info().default_sink_name
GLib.idle_add ( self.Update );
def EvalEvents ( self, ev ):
self.cs = True
raise pulsectl.PulseLoopStop
def Update ( self, w=None, d=None ):
self.UpdateSinks()
self.UpdateSources()
def SetMute ( self, img, mute, mode, toggle ):
if mode != "sink" and mode != "source":
return
if mode == "sink":
toggle.disconnect ( self.SinkToggleSignal )
else:
toggle.disconnect ( self.SourceToggleSignal )
muted = "muted"
if mute == 0:
muted = "unmuted"
toggle.set_active(False)
else:
muted = "muted"
toggle.set_active(True)
if mode == "sink":
self.SinkToggleSignal = toggle.connect ( "clicked", self.Mute, mode )
else:
self.SourceToggleSignal = toggle.connect ( "clicked", self.Mute, mode )
pic = os.path.dirname(__file__) + "/symbol-" + mode + "-" + muted + ".svg"
img.set_from_file ( pic );
def UpdateSinks ( self ):
self.SinkComboBox.disconnect ( self.SinkChangedSignal )
self.SinkComboBox.remove_all()
i = 0
index = 0
for sink in self.sinks:
if sink.name == self.default_sink:
self.SinkDefault.set_text ( sink.description )
self.SetMute ( self.SinkImg, sink.mute, "sink", self.SinkToggle )
index = i
i+=1
self.SinkComboBox.append_text ( sink.description )
self.SinkComboBox.set_active(index)
self.SinkChangedSignal = self.SinkComboBox.connect ( "changed", self.SetDefaultThing, "sink" )
def UpdateSources ( self ):
self.SourceComboBox.disconnect ( self.SourceChangedSignal )
self.SourceComboBox.remove_all()
i = 0
index = 0
for source in self.sources:
if source.name == self.default_source:
self.SourceDefault.set_text ( source.description )
self.SetMute ( self.SourceImg, source.mute, "source", self.SourceToggle )
index = i
i+=1
self.SourceComboBox.append_text ( source.description )
self.SourceComboBox.set_active(index)
self.SourceChangedSignal = self.SourceComboBox.connect ( "changed", self.SetDefaultThing, "source" )
## show the window
def Show ( self ):
self.MainWindow.show_all ()
def Destroy ( self, w, d=None ):
pulse.close()
Gtk.main_quit()
def WindowStateTrigger ( self, w, d=None ):
pass
gladefile = os.path.dirname(__file__) + "/view.glade"
hwnd = MainWindow ( gladefile )
hwnd.Show()
Gtk.main()