Forgot to delete the actual pngs
[rox-volume.git] / volume.py
blob07b0b73796713baee1c439455ca71dfedf3ed1ac
1 """
2 volume.py (a volume control applet for the ROX Panel)
4 Copyright 2004 Kenneth Hayber <khayber@socal.rr.com>
5 All rights reserved.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License.
11 This program is distributed in the hope that it will be useful
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 """
21 import rox, sys, gtk
22 from rox import app_options, applet, Menu, InfoWin
23 from rox.options import Option
24 from volumecontrol import VolumeControl
26 try:
27 import ossaudiodev
28 except:
29 rox.croak(_("You need python 2.3 for ossaudiodev support"))
31 APP_NAME = 'Volume'
32 APP_DIR = rox.app_dir
33 APP_SIZE = [28, 150]
35 #Options.xml processing
36 from rox import choices
37 choices.migrate(APP_NAME, 'hayber.us')
38 rox.setup_app_options(APP_NAME, site='hayber.us')
39 Menu.set_save_name(APP_NAME, site='hayber.us')
41 MIXER_DEVICE = Option('mixer_device', '/dev/mixer')
42 VOLUME_CONTROL = Option('volume_control', 'VOLUME')
43 SHOW_ICON = Option('show_icon', True)
44 SHOW_BAR = Option('show_bar', False)
46 rox.app_options.notify()
48 MIXER_CONTROLS = {
49 'VOLUME':ossaudiodev.SOUND_MIXER_VOLUME,
50 'PCM':ossaudiodev.SOUND_MIXER_PCM,
51 'Other':ossaudiodev.SOUND_MIXER_ALTPCM
54 class Volume(applet.Applet):
55 """An applet to control a sound card Master or PCM volume"""
56 def __init__(self, filename):
57 applet.Applet.__init__(self, filename)
59 self.vertical = self.get_panel_orientation() in ('Right', 'Left')
60 if self.vertical:
61 self.set_size_request(8, -1)
62 self.box = gtk.VBox()
63 bar_orient = gtk.PROGRESS_LEFT_TO_RIGHT
64 else:
65 self.set_size_request(-1, 8)
66 self.box = gtk.HBox()
67 bar_orient = gtk.PROGRESS_BOTTOM_TO_TOP
69 self.add(self.box)
71 self.image = gtk.Image()
72 self.pixbuf = gtk.gdk.pixbuf_new_from_file(APP_DIR+'/images/volume.svg')
73 self.image.set_from_pixbuf(self.pixbuf)
74 self.size = 0
75 self.box.pack_start(self.image)
77 self.bar = gtk.ProgressBar()
78 self.bar.set_orientation(bar_orient)
79 self.bar.set_size_request(12,12)
80 self.box.pack_end(self.bar)
82 tooltips = gtk.Tooltips()
83 tooltips.set_tip(self, _('Volume control'), tip_private=None)
85 rox.app_options.add_notify(self.get_options)
86 self.connect('size-allocate', self.event_callback)
87 self.connect('scroll_event', self.button_scroll)
89 self.add_events(gtk.gdk.BUTTON_PRESS_MASK)
90 self.connect('button-press-event', self.button_press)
91 self.menu = Menu.Menu('main', [
92 Menu.Action(_('Mixer'), 'run_mixer', ''),
93 Menu.Separator(),
94 Menu.Action(_('Options'), 'show_options', '', gtk.STOCK_PREFERENCES),
95 Menu.Action(_('Info'), 'get_info', '', gtk.STOCK_DIALOG_INFO),
96 Menu.Action(_('Close'), 'quit', '', gtk.STOCK_CLOSE),
98 self.menu.attach(self, self)
100 self.thing = None
101 self.mixer = ossaudiodev.openmixer(MIXER_DEVICE.value)
102 self.get_volume(MIXER_CONTROLS[VOLUME_CONTROL.value])
104 self.show_all()
105 self.show()
106 if not SHOW_ICON.int_value:
107 self.image.hide()
108 if not SHOW_BAR.int_value:
109 self.bar.hide()
113 def button_scroll(self, window, event):
114 channel = MIXER_CONTROLS[VOLUME_CONTROL.value]
115 current_volume = self.get_volume(channel)
116 if event.direction == 0:
117 self.set_volume((current_volume[0]+2, current_volume[1]+2), channel)
118 elif event.direction == 1:
119 self.set_volume((current_volume[0]-2, current_volume[1]-2), channel)
121 def event_callback(self, widget, rectangle):
122 """Called when the panel sends a size."""
123 if self.vertical:
124 size = rectangle[2]
125 else:
126 size = rectangle[3]
127 if size != self.size:
128 self.resize_image(size)
130 def resize_image(self, size):
131 """Called to resize the image."""
132 #I like the look better with the -4, there is no technical reason for it.
133 scaled_pixbuf = self.pixbuf.scale_simple(size-4, size-4, gtk.gdk.INTERP_BILINEAR)
134 self.image.set_from_pixbuf(scaled_pixbuf)
135 self.size = size
137 def button_press(self, window, event):
138 """Show/Hide the volume control on button 1 and the menu on button 3"""
139 if event.button == 1:
140 if not self.hide_volume():
141 self.show_volume(event)
142 elif event.button == 3:
143 self.hide_volume()
144 self.menu.popup(self, event, self.position_menu)
146 def hide_volume(self, event=None):
147 """Destroy the popup volume control"""
148 if self.thing:
149 # self.mixer = None
150 self.thing.destroy()
151 self.thing = None
152 return True
153 return False
155 def get_panel_orientation(self):
156 """Return the panel orientation ('Top', 'Bottom', 'Left', 'Right')
157 and the margin for displaying a popup menu"""
158 pos = self.socket.property_get('_ROX_PANEL_MENU_POS', 'STRING', gtk.FALSE)
159 if pos: pos = pos[2]
160 if pos:
161 side, margin = pos.split(',')
162 margin = int(margin)
163 else:
164 side, margin = None, 2
165 return side
167 def set_position(self):
168 """Set the position of the popup"""
169 side = self.get_panel_orientation()
171 # widget (x, y, w, h, bits)
172 geometry = self.socket.get_geometry()
174 if side == 'Bottom':
175 vertical = True
176 self.thing.set_size_request(APP_SIZE[0], APP_SIZE[1])
177 self.thing.move(self.socket.get_origin()[0],
178 self.socket.get_origin()[1]-APP_SIZE[1])
179 elif side == 'Top':
180 vertical = True
181 self.thing.set_size_request(APP_SIZE[0], APP_SIZE[1])
182 self.thing.move(self.socket.get_origin()[0],
183 self.socket.get_origin()[1]+geometry[3])
184 elif side == 'Left':
185 vertical = False
186 self.thing.set_size_request(APP_SIZE[1], APP_SIZE[0])
187 self.thing.move(self.socket.get_origin()[0]+geometry[2],
188 self.socket.get_origin()[1])
189 elif side == 'Right':
190 vertical = False
191 self.thing.set_size_request(APP_SIZE[1], APP_SIZE[0])
192 self.thing.move(self.socket.get_origin()[0]-APP_SIZE[1],
193 self.socket.get_origin()[1])
194 return vertical
196 def show_volume(self, event):
197 """Display the popup volume control"""
198 # self.mixer = ossaudiodev.openmixer(MIXER_DEVICE.value)
200 self.thing = gtk.Window(type=gtk.WINDOW_POPUP)
201 self.thing.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_MENU)
202 self.thing.set_decorated(False)
204 vertical = self.set_position()
205 self.volume = VolumeControl(MIXER_CONTROLS[VOLUME_CONTROL.value],
206 0, 0, True, None, vertical)
207 self.volume.set_level(self.get_volume(MIXER_CONTROLS[VOLUME_CONTROL.value]))
208 self.volume.connect("volume_changed", self.adjust_volume)
210 self.thing.add(self.volume)
211 self.thing.show_all()
212 self.thing.show()
214 def adjust_volume(self, vol, channel, vol_left, vol_right):
215 """Set the playback volume"""
216 self.set_volume((vol_left, vol_right), channel)
218 def set_volume(self, volume, channel):
219 """Send the volume setting(s) to the mixer """
220 self.mixer.set(channel, volume)
221 self.bar.set_fraction(max(volume[0], volume[1])/100.0)
223 def get_volume(self, channel):
224 """Get the volume settings from the mixer"""
225 vol = self.mixer.get(channel)
226 self.bar.set_fraction(max(vol[0], vol[1])/100.0)
227 return (vol[0], vol[1])
229 def get_options(self):
230 """Used as the notify callback when options change"""
231 if VOLUME_CONTROL.has_changed:
232 self.get_volume(MIXER_CONTROLS[VOLUME_CONTROL.value])
234 if SHOW_BAR.has_changed:
235 if SHOW_BAR.int_value:
236 self.bar.show()
237 else:
238 self.bar.hide()
240 if SHOW_ICON.has_changed:
241 if SHOW_ICON.int_value:
242 self.image.show()
243 else:
244 self.image.hide()
246 def show_options(self, button=None):
247 """Options edit dialog"""
248 rox.edit_options()
250 def get_info(self):
251 """Display an InfoWin box"""
252 InfoWin.infowin(APP_NAME)
254 def run_mixer(self, button=None):
255 from rox import filer
256 filer.spawn_rox((APP_DIR,))
258 def quit(self):
259 """Quit"""
260 self.destroy()