#!/usr/bin/env python
# asoundconf-gtk - GTK GUI to select the default sound card
#
# (C) 2006 Toby Smithe
# asoundconf parts (C) 2005 Canonical Ltd.
# gourmet parts (C) 2005 Thomas Hinkle (and any other gourmet developers)
# Both the asoundconf and gourmet projects are also licenced under the 
# GPLv2 or any later version in exactly the same way as this project.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

import sys, re, os, pygtk, gtk, string

######################################
#START small block of asoundconf code#
######################################

def getcards():
	cardspath = '/proc/asound/cards'
	if not os.path.exists(cardspath):
		return False
	procfile = open(cardspath, 'rb')
	cardline = re.compile('^\s*\d+\s*\[')
	card_lines = []
	lines = procfile.readlines()
	for l in lines:
		if cardline.match(l):
			card_lines.append(re.sub(r'^\s*\d+\s*\[(\w+)\s*\].+','\\1',l))
	return card_lines # Snipped here

####################################
#END small block of asoundconf code#
####################################

###################################
#START small block of gourmet code#
###################################

def cb_set_active_text (combobox, text, col=0):
    """Set the active text of combobox to text. We fail
    if the text is not already in the model. Column is the column
    of the model from which text is drawn."""
    model = combobox.get_model()
    n = 0
    for rw in model:
        if rw[col]==text:
            combobox.set_active(n)
            return n
       	n += 1
    return None

#################################
#END small block of gourmet code#
#################################

asoundconf = "/usr/bin/asoundconf"

def die_on_error():
	'''Kill the application if it cannot run'''
	if not os.path.exists("/proc/asound/cards"):
		print "You need at least one ALSA sound card for this to work!"
		sys.exit(-1)
	if os.system(asoundconf + " is-active"):
		print "You need to make sure asoundconf is active!"
		print "By default, asoundconf's configuration file is ~/.asoundrc.asoundconf"
		print "and must be included in ~/.asoundrc. Open this file to make sure it is!"
		sys.exit(-2)

def get(setting):
	'''Get an asoundconf setting'''
	cmd = asoundconf + " get " + setting
	output = os.popen(cmd).readlines()
	return output

def get_default_card():
	'''# Get the default PCM card (but assume this is the default card for everything)
	This is just a very simple wrapper for get(...) as otherwise I'd have to repeat
	a load (well, two lines) of code.'''
	value_raw = get("defaults.pcm.card")
	if not value_raw:
		return 0
	value = string.strip(value_raw[0])
	return value

def set_default_card(card):
	'''Set the default card using asoundconf'''
	call = asoundconf + " set-default-card " + card
	return os.system(call)

def set_pulseaudio():
	call = asoundconf + " set-pulseaudio"
	return os.system(call)

def unset_pulseaudio():
	call = asoundconf + " unset-pulseaudio"
	return os.system(call)
	
class asoundconf_gtk:
	def destroy(self, widget, data=None):
		'''This is a stub function to allow for stuff to be done on close'''
		gtk.main_quit()

	def delete_event(self, widget, event, data=None):
		'''Again, a stub to allow stuff to happen when widgets are deleted'''
		return False

	def choose(self, widget, data=None):
		'''Function to set thde default card on choice'''
		card = widget.get_active_text()
		if card == "PulseAudio":
			set_pulseaudio()
		else:
			unset_pulseaudio()
			set_default_card(card)

	def pulse(self, widget, data=None):
		'''Enables/Disables PulseAudio support'''
		active = widget.get_active()
		if active:
			value = set_pulseaudio()
		else:
			value = unset_pulseaudio()
		return value

	def reset(self, widget, data=None):
		'''Reset the default card to the current default'''
		if self.combo.get_active_text() == "PulseAudio":
			set_pulseaudio()
		else:
			unset_pulseaudio()			
			set_default_card(get_default_card())
	
	def __init__(self):
		# Initiate the window
		self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
		self.window.set_title("Default Sound Card")
		# Create an HBox box
		self.selectionbox = gtk.HBox(False, 0)
		# Create a button
		self.button = gtk.Button("Quit")
		self.button.connect("clicked", self.reset, None)
		self.button.connect_object("clicked", gtk.Widget.destroy, self.window)
		# Create combobox
		self.combo = gtk.combo_box_new_text()
		self.liststore = self.combo.get_model()
		# Add cards to combobox liststore
		cards = getcards()
		if not cards:
			return False
		for card in cards:
			self.combo.append_text(card.strip())
		self.combo.connect("changed", self.choose, None)
		# Create a label
		self.label = gtk.Label("Select default card: ")
		# Add contents to HBox "selectionbox"
		self.selectionbox.pack_start(self.combo, True, True, 0)		
		self.selectionbox.pack_start(self.button, True, True, 0)
		# Create a VBox
		self.vbox = gtk.VBox(False, 0)
		self.window.add(self.vbox)
		self.vbox.pack_start(self.label, True, True, 0)
		self.vbox.pack_start(self.selectionbox, True, True, 0)
		# Create PulseAudio checkbox if ALSA PulseAudio plugin installed
		if os.path.exists("/usr/lib/alsa-lib/libasound_module_pcm_pulse.so") and os.path.exists("/usr/lib/alsa-lib/libasound_module_ctl_pulse.so"):
			#self.pulsecheck = gtk.CheckButton("Use _PulseAudio?")
			self.combo.append_text("PulseAudio")
			try: pcmDefault = get("pcm.!default")[0]
			except: pcmDefault = ""
			if pcmDefault == "{ type pulse }\n":
				#self.pulsecheck.set_active(True)
				cb_set_active_text(self.combo, "PulseAudio")
			else:
				# Select current default 
				cb_set_active_text(self.combo, get_default_card())
			#self.pulsecheck.connect("toggled", self.pulse, None)
			#self.vbox.pack_start(self.pulsecheck, True, True, 0)
		# Connect up window events
		self.window.connect("destroy",self.destroy)
		self.window.connect("delete_event",self.delete_event)
		# Show window and contents
		self.window.show_all()

	def main(self):
		'''Do the stuffs'''
		gtk.main()

if __name__ == "__main__":
	die_on_error()
	aconf = asoundconf_gtk()
	sys.exit(aconf.main())
