2009/02/04

ボリュームコントロールアプリ完成

あまり美しくないコードですが公開します
適当なところが多い、、(エラー処理とかないし
トレイに出るアイコンを右クリックとか左クリックとかしてください
そのうちFedoracubeに入れる予定

#!/usr/bin/python
# -*- encoding: utf-8 -*-

import sys, pygtk, gtk, subprocess

class PopupMenu(gtk.Menu):
def __init__(self, icon):
gtk.Menu.__init__(self)

self.icon = icon

# コントロール
controls = []
group = None
for i in self.GetControls():
controls.append(gtk.RadioMenuItem(group, i))
control = controls[-1]
control.connect("activate", self.activate_ChangeControl, i)
group = control
self.append(control)
controls[0].set_active(True)

# 区切り線
self.append(gtk.SeparatorMenuItem())

# PulseAudio Volume Control
self.pavucontrol = gtk.ImageMenuItem("PulseAudio Volume Control")
self.pavucontrol.set_image(gtk.image_new_from_icon_name("multimedia-volume-control", gtk.ICON_SIZE_MENU))
self.pavucontrol.connect("activate", self.activate_RunPavucontrol)
self.append(self.pavucontrol)

# 終了
self.exit = gtk.ImageMenuItem(stock_id = gtk.STOCK_QUIT)
self.exit.connect("activate", gtk.main_quit)
self.append(self.exit)

self.show_all()

def GetControls(self):
amixer = subprocess.Popen(["/usr/bin/amixer", "scontrols"], stdout = subprocess.PIPE).communicate()[0]

controls = []
for control in amixer.rstrip().split("\n"):
controls.append(control.split(" ")[3])

return controls

def activate_RunPavucontrol(self, widget):
subprocess.Popen(["/usr/bin/pavucontrol"])

def activate_ChangeControl(self, widget, control):
if widget.get_active() == True:
self.icon.active_control = control

class VolumeControl(gtk.Window):
def __init__(self, icon):
gtk.Window.__init__(self)

self.icon = icon
self.vbox = gtk.VBox(False, 0)
self.plus = gtk.Button()
self.scale = gtk.VScale(gtk.Adjustment(50, 0, 101, 1, 1, 1))
self.minus = gtk.Button()
self.mute = gtk.Button()

self.plus.set_relief(gtk.RELIEF_NONE)
self.plus.set_image(gtk.image_new_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_MENU))
self.plus.connect("clicked", self.clicked_ChangeVolume, 5)

self.minus.set_relief(gtk.RELIEF_NONE)
self.minus.set_image(gtk.image_new_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_MENU))
self.minus.connect("clicked", self.clicked_ChangeVolume, -5)

self.mute.set_relief(gtk.RELIEF_NONE)
self.mute.connect("clicked", self.clicked_ToggleMute)

self.scale.set_size_request(28, 128)
self.scale.set_draw_value(False)
self.scale.set_inverted(True)
self.scale.connect("adjust-bounds", self.adjust_bounds_ChangeVolume)

self.vbox.pack_start(self.plus, False, True, 0)
self.vbox.pack_start(self.scale, False, True, 0)
self.vbox.pack_start(self.minus, False, True, 0)
self.vbox.pack_start(self.mute, False, True, 0)

self.set_skip_pager_hint(True)
self.set_skip_taskbar_hint(True)
self.set_decorated(False)
self.resize(28, 212)
self.add(self.vbox)
self.connect("show", self.show_ShowWindow)
self.connect("focus-out-event", self.focus_out_event_CloseWindow)

def GetMuteStatus(self):
amixer = subprocess.Popen(["/usr/bin/amixer", "sget", self.icon.active_control], stdout = subprocess.PIPE)
grep = subprocess.Popen(["/bin/grep", "-e", "\[on\]$"], stdin = amixer.stdout, stdout = subprocess.PIPE).communicate()[0]

if grep == "":
ret = gtk.STOCK_MEDIA_PLAY
else:
ret = gtk.STOCK_MEDIA_STOP

return ret

def GetVolume(self):
amixer = subprocess.Popen(["/usr/bin/amixer", "sget", self.icon.active_control], stdout = subprocess.PIPE)
grep = subprocess.Popen(["/bin/grep", "-oe", "[0-9]*%"], stdin = amixer.stdout, stdout = subprocess.PIPE).communicate()[0]
ret = int(grep.split("%")[0])

return ret

def ChangeVolume(self, adjust):
value = adjust.value

if value > adjust.upper:
value = adjust.upper
elif value < adjust.lower:
value = adjust.lower

subprocess.Popen(["/usr/bin/amixer", "sset", self.icon.active_control, str(int(value)) + "%"], stdout = subprocess.PIPE).communicate()[0]

def show_ShowWindow(self, widget):
self.scale.grab_focus()
self.scale.set_value(self.GetVolume())
self.mute.set_image(gtk.image_new_from_stock(self.GetMuteStatus(), gtk.ICON_SIZE_MENU))

def focus_out_event_CloseWindow(self, widget, event):
self.hide_all()

def clicked_ChangeVolume(self, button, value):
self.scale.set_value(self.scale.get_value() + value)
self.ChangeVolume(self.scale.get_adjustment())

def clicked_ToggleMute(self, button):
subprocess.Popen(["/usr/bin/amixer", "sset", self.icon.active_control, "toggle"], stdout = subprocess.PIPE).communicate()[0]
self.hide_all()

def adjust_bounds_ChangeVolume(self, range, value):
self.ChangeVolume(self.scale.get_adjustment())

class StatusIconVolumeControl(gtk.StatusIcon):
def __init__(self):
gtk.StatusIcon.__init__(self)

self.menu = PopupMenu(self)
self.control = VolumeControl(self)

self.set_from_icon_name("multimedia-volume-control")
self.connect("activate", self.activate_VolumeControl)
self.connect("popup-menu", self.popup_menu_PopupMenu)

def activate_VolumeControl(self, widget):
if self.control.is_active() == True:
self.control.hide_all()
else:
(screen, rectangle, orientation) = self.get_geometry()

if (screen.get_width() / rectangle.x) > 2:
x = rectangle.x + rectangle.width
else:
x = rectangle.x - self.control.get_size()[0]

if (screen.get_height() / rectangle.y) > 2:
y = rectangle.y + rectangle.height
else:
y = rectangle.y - self.control.get_size()[1]

self.control.move(x, y)
self.control.show_all()

def popup_menu_PopupMenu(self, widget, button, time):
self.menu.popup(None, None, gtk.status_icon_position_menu, button, time, self)

if __name__ == '__main__':
StatusIconVolumeControl()
gtk.main()

0 件のコメント:

コメントを投稿