Merge lp:~mbudde/earcandy/reorganization into lp:earcandy

Proposed by Michael Budde
Status: Merged
Merge reported by: KillerKiwi
Merged at revision: not available
Proposed branch: lp:~mbudde/earcandy/reorganization
Merge into: lp:earcandy
Diff against target: None lines
To merge this branch: bzr merge lp:~mbudde/earcandy/reorganization
Reviewer Review Type Date Requested Status
KillerKiwi Approve
Review via email: mp+6748@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Michael Budde (mbudde) wrote :

In this branch the tree has been reorganized to make the application a package (earcandylib). ear_candy.py has been moved to earcandylib/EarCandy.py and a earcandy script for running the application has been created. Data files have been moved to data/.

A distutils script (setup.py) has also been added. A tar ball can now be created with ./setup.py sdist.

A .desktop file has been added for easily running the application when it has been installed.

Revision history for this message
David D Lowe (flimm) wrote :

Hello Michael Budde! It seems like we were working on the same bug #379266 in parallel, so a lot of our work is similar, if not identical (earcandy.desktop has the exact same comment!).
So I'm going to comment on the changes you've made versus what's now in the trunk (lp:earcandy revision 50).

I find your approach to the runnable script earcandy interesting. You basically moved the code under if __name__ == "__main__" from the EarCandy.py to the script. Theoretically, this is the best method, practically, I've found from my personal experience with Epidermis that it makes namespaces rather confusing. The other approach which I took calls the script by running subprocess.call(['python', ear_candy.py']), creating two python processes one depending on the other, which is a bit of a waste but makes the result in System Monitor prettier. The final approach (that I can think of) is to launch it by running subprocess.Popen(['earcandy.py']) which is lighter on resources but less pretty in System Monitor.

Since you're using distutils, the data files will be separated from the .py files, so you created a function called find_data_file, similar to my find_program_file. You check to see in which directory of /usr/ or /usr/local/ the files are installed. This actually superfluous, they're always going to be under sys.prefix, according to the distutils documentation.

Having a seperate EarCandyInfo.py file for the application's metadata is certainly interesting. Having one place to modify the program's version number is nice, but do you really need it for things like APPNAME?

I'm going to go ahead and comment on your Ubuntu packaging branch too, lp:~mbudde/earcandy/ubuntu revision 59 if you don't mind. You included a dependency which I somehow forgot: pulseaudio, well done! Having the Ubuntu packaging in a separate branch from the trunk is an interesting idea, and one which a lot of projects go by. I personally prefer having the debian/ folder in the original source, keeps the developers responsible for the packaging and things like dependencies.

Obviously, I'm not the developer of EarCandy, it'll be up to KillerKiwi to decide what to take and what to keep. Thanks for contributing!

Revision history for this message
Michael Budde (mbudde) wrote :
Download full text (3.9 KiB)

> Hello Michael Budde! It seems like we were working on the same bug #379266 in
> parallel, so a lot of our work is similar, if not identical (earcandy.desktop
> has the exact same comment!).
> So I'm going to comment on the changes you've made versus what's now in the
> trunk (lp:earcandy revision 50).
>

Yeah, I noticed your branch the day after I started my branch. I've certainly
got some inspiration from your branch, hope you don't mind that ;)

> I find your approach to the runnable script earcandy interesting. You
> basically moved the code under if __name__ == "__main__" from the EarCandy.py
> to the script. Theoretically, this is the best method, practically, I've found
> from my personal experience with Epidermis that it makes namespaces rather
> confusing. The other approach which I took calls the script by running
> subprocess.call(['python', ear_candy.py']), creating two python processes one
> depending on the other, which is a bit of a waste but makes the result in
> System Monitor prettier. The final approach (that I can think of) is to launch
> it by running subprocess.Popen(['earcandy.py']) which is lighter on resources
> but less pretty in System Monitor.

I'm not sure what you mean when you say that it "makes namespaces rather confusing".
Do you have any examples where your method would be prefered to mine?

> Since you're using distutils, the data files will be separated from the .py
> files, so you created a function called find_data_file, similar to my
> find_program_file. You check to see in which directory of /usr/ or /usr/local/
> the files are installed. This actually superfluous, they're always going to be
> under sys.prefix, according to the distutils documentation.

Running setup.py in the source tree gives me this:
$ ./setup.py -n install
running install
[..snip..]
running install_data
creating /usr/local/share/earcandy
copying data/earsLabel.png -> /usr/local/share/earcandy
copying data/pulseoptions.glade -> /usr/local/share/earcandy
copying data/settings.xml -> /usr/local/share/earcandy
copying data/earsLabelOff.png -> /usr/local/share/earcandy
copying earcandy.desktop -> /usr/local/share/applications
creating /usr/local/share/pixmaps
copying data/earsLabel.png -> /usr/local/share/pixmaps
running install_egg_info
Writing /usr/local/lib/python2.6/dist-packages/earcandy-0.5.egg-info

Also I don't quite like how you've copied find_program_file() to every source file
that needs it. Right now it's a pain to edit that function as you have to do it in three
places. Why not put it in a separate file and import it?

> Having a seperate EarCandyInfo.py file for the application's metadata is
> certainly interesting. Having one place to modify the program's version number
> is nice, but do you really need it for things like APPNAME?

You're right. That probably is overkill.

> I'm going to go ahead and comment on your Ubuntu packaging branch too,
> lp:~mbudde/earcandy/ubuntu revision 59 if you don't mind. You included a
> dependency which I somehow forgot: pulseaudio, well done! Having the Ubuntu
> packaging in a separate branch from the trunk is an interesting idea, and one
> which a lot of projects go by. I personally ...

Read more...

Revision history for this message
KillerKiwi (killerkiwi2005) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'MANIFEST.in'
--- MANIFEST.in 1970-01-01 00:00:00 +0000
+++ MANIFEST.in 2009-05-23 12:12:46 +0000
@@ -0,0 +1,2 @@
1include earcandy earcandy.desktop MANIFEST.in
2recursive-include data *
03
=== added directory 'data'
=== renamed file 'earsLabel.png' => 'data/earsLabel.png'
=== renamed file 'earsLabelOff.png' => 'data/earsLabelOff.png'
=== renamed file 'pulseoptions.glade' => 'data/pulseoptions.glade'
=== renamed file 'settings.xml' => 'data/settings.xml'
=== added file 'earcandy'
--- earcandy 1970-01-01 00:00:00 +0000
+++ earcandy 2009-05-22 14:09:54 +0000
@@ -0,0 +1,8 @@
1#!/usr/bin/env python
2
3from earcandylib.EarCandy import EarCandy
4
5if __name__ == '__main__':
6 ec = EarCandy()
7 ec.run()
8 ec.save()
09
=== added file 'earcandy.desktop'
--- earcandy.desktop 1970-01-01 00:00:00 +0000
+++ earcandy.desktop 2009-05-23 12:12:46 +0000
@@ -0,0 +1,12 @@
1[Desktop Entry]
2Version=1.0
3Encoding=UTF-8
4Name=Ear Candy
5Comment=Gracefully fade applications' volume in and out
6Generic Name=Sound level manager
7Terminal=false
8Icon=earsLabel
9Type=Application
10Exec=earcandy
11Categories=Utility;
12StartupNotify=True
013
=== added directory 'earcandylib'
=== renamed file 'Client.py' => 'earcandylib/Client.py'
--- Client.py 2009-05-21 19:43:15 +0000
+++ earcandylib/Client.py 2009-05-22 15:58:21 +0000
@@ -17,7 +17,7 @@
17 self.category = "" # music | video | phone17 self.category = "" # music | video | phone
18 self.window_position_fade = False18 self.window_position_fade = False
1919
20 self.volume_step = 2 20 self.volume_step = 2
21 self.has_focus = False21 self.has_focus = False
22 self.fullscreen = False22 self.fullscreen = False
23 self.icon = None23 self.icon = None
@@ -60,7 +60,7 @@
60 # check meter levels on others60 # check meter levels on others
61 for sink in self.sinks.values():61 for sink in self.sinks.values():
62 if sink.volume_meter > 0: return True62 if sink.volume_meter > 0: return True
63 63
64 # HACK: Check how long its been inactive... and if more than a second count as expired64 # HACK: Check how long its been inactive... and if more than a second count as expired
65 if timestamp - sink.volume_meter_last_non_zero < 1:65 if timestamp - sink.volume_meter_last_non_zero < 1:
66 return True66 return True
@@ -107,7 +107,7 @@
107107
108 def __fade_mute(self):108 def __fade_mute(self):
109 self.volume_target = self.volume_step # if we goto 0 than our volume meter will never register a value109 self.volume_target = self.volume_step # if we goto 0 than our volume meter will never register a value
110 110
111 def set_primary(self, value):111 def set_primary(self, value):
112 if value or self.category == "default":112 if value or self.category == "default":
113 self.__fade_in()113 self.__fade_in()
@@ -127,7 +127,7 @@
127 el.setAttribute("category",self.category)127 el.setAttribute("category",self.category)
128 el.setAttribute("window_position_fade", str(self.window_position_fade))128 el.setAttribute("window_position_fade", str(self.window_position_fade))
129 el.setAttribute("icon_name", str(self.icon_name))129 el.setAttribute("icon_name", str(self.icon_name))
130 130
131 def from_xml(self, el):131 def from_xml(self, el):
132132
133 self.name = el.getAttribute("name")133 self.name = el.getAttribute("name")
134134
=== renamed file 'DesktopFiles.py' => 'earcandylib/DesktopFiles.py'
=== renamed file 'ear_candy' => 'earcandylib/EarCandy.py' (properties changed: +x to -x)
--- ear_candy 2009-05-21 19:43:15 +0000
+++ earcandylib/EarCandy.py 2009-05-22 15:58:21 +0000
@@ -16,19 +16,20 @@
16from xml.dom.minidom import *16from xml.dom.minidom import *
1717
18from window.WindowWatcher import WindowWatcher18from window.WindowWatcher import WindowWatcher
19from pulseaudio.PulseAudio import PulseAudio 19from pulseaudio.PulseAudio import PulseAudio
20from Client import Client20from Client import Client
21from Sink import Sink21from Sink import Sink
22from Threads import threaded22from Threads import threaded
23from TrayIcon import EarCandyStatusIcon23from TrayIcon import EarCandyStatusIcon
24from EarCandyPrefs import EarCandayPref 24from EarCandyPrefs import EarCandayPref
25from VolumeSlider import EarCandyVolumeSlider 25from VolumeSlider import EarCandyVolumeSlider
26from EarCandyDBus import EarCandyDBusClient26from EarCandyDBus import EarCandyDBusClient
27from Paths import get_data_path
2728
28# Turn on gtk threading29# Turn on gtk threading
29gtk.gdk.threads_init()30gtk.gdk.threads_init()
3031
31gtk.window_set_default_icon_from_file(os.path.join(os.path.dirname(__file__), "earsLabel.png"))32gtk.window_set_default_icon_from_file(get_data_path("earsLabel.png"))
3233
33# hack to get around 0.2 not have alsaaudio.cards()34# hack to get around 0.2 not have alsaaudio.cards()
34def reset_alsa_volumes(value=100):35def reset_alsa_volumes(value=100):
@@ -50,7 +51,7 @@
5051
5152
52 for track in mixer.list_tracks():53 for track in mixer.list_tracks():
53 54
54 if track.flags & gst.interfaces.MIXER_TRACK_OUTPUT and track.num_channels > 0:55 if track.flags & gst.interfaces.MIXER_TRACK_OUTPUT and track.num_channels > 0:
55 print "|", track.label56 print "|", track.label
5657
@@ -85,7 +86,7 @@
85 rules.appendChild(el)86 rules.appendChild(el)
86 client.to_xml(el)87 client.to_xml(el)
87 skip.append(client.name)88 skip.append(client.name)
88 89
8990
90 doc.documentElement.setAttribute("fade_timer_speed", str(self.fade_timer_speed))91 doc.documentElement.setAttribute("fade_timer_speed", str(self.fade_timer_speed))
91 doc.documentElement.setAttribute("mute_level", str(self.mute_level))92 doc.documentElement.setAttribute("mute_level", str(self.mute_level))
@@ -146,8 +147,8 @@
146 self.active = True147 self.active = True
147 self.display = {"": "[ unknown ]", "phone" : "Phone (VoIP)", "video" : "Video Player", "music" : "Music Player", "default" : "Notification" }148 self.display = {"": "[ unknown ]", "phone" : "Phone (VoIP)", "video" : "Video Player", "music" : "Music Player", "default" : "Notification" }
148 self.ignore = ["EsounD client (UNIX socket client)", "ear-candy", "Native client (UNIX socket client)"]149 self.ignore = ["EsounD client (UNIX socket client)", "ear-candy", "Native client (UNIX socket client)"]
149 self.config_file = os.path.expanduser("~/.config/Ear Candy/settings.xml") 150 self.config_file = os.path.expanduser("~/.config/Ear Candy/settings.xml")
150 self.default_config_file = os.path.join(os.path.dirname(__file__),"settings.xml")151 self.default_config_file = get_data_path("settings.xml")
151152
152 self.pa_clients = {} # clients by name153 self.pa_clients = {} # clients by name
153 self.pa_clients_by_id = {} # clients by id154 self.pa_clients_by_id = {} # clients by id
@@ -161,13 +162,11 @@
161162
162 self.pref = None163 self.pref = None
163164
164 self.fade_timer_speed = 0.1 165 self.fade_timer_speed = 0.1
165 self.mute_level = 20166 self.mute_level = 20
166 self.follow_new_outputs = True167 self.follow_new_outputs = True
167168
168 self.priority = { "" : [], "phone" : [], "video" : [], "music" : [] } 169 self.priority = { "" : [], "phone" : [], "video" : [], "music" : [] }
169
170 pass
171170
172 def run(self):171 def run(self):
173 self.ecb = EarCandyDBusClient(self)172 self.ecb = EarCandyDBusClient(self)
@@ -179,7 +178,7 @@
179 else:178 else:
180179
181 self.tray = EarCandyStatusIcon(self)180 self.tray = EarCandyStatusIcon(self)
182 181
183 self.slider = EarCandyVolumeSlider(self)182 self.slider = EarCandyVolumeSlider(self)
184183
185 self.ecb.start_service()184 self.ecb.start_service()
@@ -187,7 +186,7 @@
187 self.pa = PulseAudio( self.on_new_pa_client, self.on_remove_pa_client, self.on_new_pa_sink, self.on_remove_pa_sink, self.on_new_pa_output, self.on_remove_pa_output, self.on_volume_change, self.pa_volume_meter)186 self.pa = PulseAudio( self.on_new_pa_client, self.on_remove_pa_client, self.on_new_pa_sink, self.on_remove_pa_sink, self.on_new_pa_output, self.on_remove_pa_output, self.on_volume_change, self.pa_volume_meter)
188 self.ww = WindowWatcher(self.on_active_window_change)187 self.ww = WindowWatcher(self.on_active_window_change)
189 self.fade_timer()188 self.fade_timer()
190 189
191 gtk.main()190 gtk.main()
192191
193192
@@ -207,7 +206,7 @@
207 def fade_timer(self):206 def fade_timer(self):
208 while True:207 while True:
209 time.sleep(self.fade_timer_speed)208 time.sleep(self.fade_timer_speed)
210 gobject.idle_add(self.adjust_volumes) 209 gobject.idle_add(self.adjust_volumes)
211210
212 def adjust_volumes(self):211 def adjust_volumes(self):
213212
@@ -217,11 +216,11 @@
217 for sink in self.pa_sinks.values():216 for sink in self.pa_sinks.values():
218 if sink.set_volume():217 if sink.set_volume():
219 # set pa volume218 # set pa volume
220 self.pa.set_sink_volume(sink.index, sink.volume, sink.channels) 219 self.pa.set_sink_volume(sink.index, sink.volume, sink.channels)
221220
222 def __set_primary_client(self):221 def __set_primary_client(self):
223 # Apply fade rules222 # Apply fade rules
224 223
225 if self.active:224 if self.active:
226 for client in self.pa_clients.values():225 for client in self.pa_clients.values():
227 # self.pref.update_client( client )226 # self.pref.update_client( client )
@@ -256,7 +255,7 @@
256 flagFound = False255 flagFound = False
257 for key in self.priority.keys():256 for key in self.priority.keys():
258 if key:257 if key:
259 for client in self.priority[key]: 258 for client in self.priority[key]:
260259
261 if not flagFound and self.active and client.is_active():260 if not flagFound and self.active and client.is_active():
262 # Toggle old client to inactive261 # Toggle old client to inactive
@@ -271,7 +270,7 @@
271 # all clients with no category should be treated as active for volume270 # all clients with no category should be treated as active for volume
272 for client in self.priority[key]:271 for client in self.priority[key]:
273 client.set_primary(True)272 client.set_primary(True)
274 273
275274
276 def on_volume_change(self, level):275 def on_volume_change(self, level):
277 self.slider.set_volume( level )276 self.slider.set_volume( level )
@@ -281,7 +280,7 @@
281 # /desktop/gnome/sound/default_mixer_device280 # /desktop/gnome/sound/default_mixer_device
282281
283 del( self.pa_outputs[index] )282 del( self.pa_outputs[index] )
284 283
285 # fall back to previous value...284 # fall back to previous value...
286 for value in self.pa_outputs.values():285 for value in self.pa_outputs.values():
287 self.set_last_output(value)286 self.set_last_output(value)
@@ -289,7 +288,7 @@
289288
290 def set_last_output(self, name):289 def set_last_output(self, name):
291 self.last_output_name = name290 self.last_output_name = name
292 291
293 # Update gconf key that governs multimedia key controls292 # Update gconf key that governs multimedia key controls
294 gconf_key = "/desktop/gnome/sound/default_mixer_device"293 gconf_key = "/desktop/gnome/sound/default_mixer_device"
295 prefix = "pulsemixer:"294 prefix = "pulsemixer:"
@@ -299,12 +298,12 @@
299 print298 print
300 print "== Change gnome default sound device =="299 print "== Change gnome default sound device =="
301 client.set_string(gconf_key, prefix + name)300 client.set_string(gconf_key, prefix + name)
302 301
303302
304 def on_new_pa_output(self, index, output_name, startup):303 def on_new_pa_output(self, index, output_name, startup):
305 self.pa_outputs[index] = output_name304 self.pa_outputs[index] = output_name
306 self.save()305 self.save()
307 306
308 if self.follow_new_outputs and (self.last_output_name == "" or output_name.lower().count("usb") > 0):307 if self.follow_new_outputs and (self.last_output_name == "" or output_name.lower().count("usb") > 0):
309 self.set_last_output(output_name)308 self.set_last_output(output_name)
310 # Move all streams to the new output ;)309 # Move all streams to the new output ;)
@@ -318,7 +317,7 @@
318 def on_new_pa_sink(self, index, name, client_index, volume, sink, channels):317 def on_new_pa_sink(self, index, name, client_index, volume, sink, channels):
319318
320 if not self.pa_sinks.has_key(index):319 if not self.pa_sinks.has_key(index):
321 print 320 print
322 print "== pa sink input =="321 print "== pa sink input =="
323 print "sink:", index, name322 print "sink:", index, name
324 if self.pa_clients_by_id.has_key(client_index):323 if self.pa_clients_by_id.has_key(client_index):
@@ -329,13 +328,13 @@
329 client.sinks[index] = sink328 client.sinks[index] = sink
330 self.pa_sinks[index] = sink329 self.pa_sinks[index] = sink
331 # insure the sink input is on the correct output..330 # insure the sink input is on the correct output..
332 if self.follow_new_outputs and self.last_output_name: 331 if self.follow_new_outputs and self.last_output_name:
333 self.pa.move_sink(sink.index, self.last_output_name)332 self.pa.move_sink(sink.index, self.last_output_name)
334 else:333 else:
335 return334 return
336 else:335 else:
337 self.pa_sinks[index].volume = volume336 self.pa_sinks[index].volume = volume
338 337
339 if self.pref:338 if self.pref:
340 self.pref.update_client( self.pa_clients_by_id[client_index] )339 self.pref.update_client( self.pa_clients_by_id[client_index] )
341 self.on_active_window_change( self.last_application, "pa")340 self.on_active_window_change( self.last_application, "pa")
@@ -344,10 +343,11 @@
344 if self.pa_sinks.has_key(index):343 if self.pa_sinks.has_key(index):
345 sink = self.pa_sinks[index]344 sink = self.pa_sinks[index]
346 sink.volume_meter = level345 sink.volume_meter = level
347 if(level > sink.client.volume_step): sink.volume_meter_last_non_zero = time.mktime(datetime.datetime.now().timetuple())346 if (level > sink.client.volume_step):
347 sink.volume_meter_last_non_zero = time.mktime(datetime.datetime.now().timetuple())
348348
349 def on_remove_pa_sink(self, index):349 def on_remove_pa_sink(self, index):
350 print 350 print
351 print "== pa remove sink input =="351 print "== pa remove sink input =="
352 print index352 print index
353 if self.pa_sinks.has_key(index):353 if self.pa_sinks.has_key(index):
@@ -357,7 +357,7 @@
357 if self.pref:357 if self.pref:
358 self.pref.update_client( client )358 self.pref.update_client( client )
359 self.on_active_window_change( self.last_application, "pa")359 self.on_active_window_change( self.last_application, "pa")
360 360
361361
362 def get_unregistered_clients(self):362 def get_unregistered_clients(self):
363 clients = []363 clients = []
@@ -371,11 +371,11 @@
371 return clients371 return clients
372372
373 def on_new_pa_client(self, index, name):373 def on_new_pa_client(self, index, name):
374 print 374 print
375 print "== pa sink client =="375 print "== pa sink client =="
376 print name376 print name
377 # Link all clients with same name into same object377 # Link all clients with same name into same object
378 if not self.pa_clients.has_key(index) or not self.pa_clients[index].name == name: 378 if not self.pa_clients.has_key(index) or not self.pa_clients[index].name == name:
379 if not self.pa_clients.has_key(name):379 if not self.pa_clients.has_key(name):
380 client = Client(self, name)380 client = Client(self, name)
381 self.pa_clients[name] = client381 self.pa_clients[name] = client
@@ -419,10 +419,10 @@
419 self.last_application = application419 self.last_application = application
420420
421 def match_client_to_application(self, client, application, index=0):421 def match_client_to_application(self, client, application, index=0):
422 if client.test_focus_window(application.window_name, application.command, application.name): 422 if client.test_focus_window(application.window_name, application.command, application.name):
423 #print "MATCH pa client:", client.name, index423 #print "MATCH pa client:", client.name, index
424424
425 client.fullscreen = application.fullscreen 425 client.fullscreen = application.fullscreen
426 client.icon = application.icon426 client.icon = application.icon
427 client.icon_name = application.icon_name427 client.icon_name = application.icon_name
428 client.description = application.description428 client.description = application.description
@@ -447,13 +447,3 @@
447 if name.startswith(alsa_plugin):447 if name.startswith(alsa_plugin):
448 name = name[len(alsa_plugin): -1]448 name = name[len(alsa_plugin): -1]
449 return name449 return name
450
451
452if __name__ == '__main__':
453
454 os.chdir(os.path.dirname(sys.argv[0]))
455
456 ec = EarCandy()
457 ec.run()
458 ec.save()
459
460450
=== renamed file 'EarCandyAppSelect.py' => 'earcandylib/EarCandyAppSelect.py'
--- EarCandyAppSelect.py 2009-02-20 02:08:20 +0000
+++ earcandylib/EarCandyAppSelect.py 2009-05-22 15:58:21 +0000
@@ -16,14 +16,15 @@
16from glade_window import GladeWindow16from glade_window import GladeWindow
17from window.WindowWatcher import WindowWatcher17from window.WindowWatcher import WindowWatcher
18from Client import Client18from Client import Client
19from Paths import get_data_path
1920
20class EarCandyAppSelect(GladeWindow):21class EarCandyAppSelect(GladeWindow):
21 def __init__(self, core):22 def __init__(self, core):
22 23
23 self.core = core24 self.core = core
24 25
25 GladeWindow.__init__(self, "pulseoptions.glade", "dialog_select")26 GladeWindow.__init__(self, get_data_path("pulseoptions.glade"), "dialog_select")
26 27
27 self.combobox_clients = self.wtree.get_widget("combobox_clients")28 self.combobox_clients = self.wtree.get_widget("combobox_clients")
28 self.treeview_applications = self.wtree.get_widget("treeview_applications")29 self.treeview_applications = self.wtree.get_widget("treeview_applications")
29 self.combobox_category = self.wtree.get_widget("combobox_category")30 self.combobox_category = self.wtree.get_widget("combobox_category")
@@ -33,7 +34,7 @@
33 "on_button_cancel_clicked" : self.on_button_cancel_clicked34 "on_button_cancel_clicked" : self.on_button_cancel_clicked
34 }35 }
35 self.wtree.signal_autoconnect(signals)36 self.wtree.signal_autoconnect(signals)
36 37
37 # Setup tree38 # Setup tree
38 column = gtk.TreeViewColumn((''))39 column = gtk.TreeViewColumn((''))
39 column.set_spacing(4)40 column.set_spacing(4)
@@ -48,8 +49,8 @@
48 column.set_attributes(cell, markup=1)49 column.set_attributes(cell, markup=1)
49 self.treeview_applications.append_column(column)50 self.treeview_applications.append_column(column)
50 self.store = gtk.ListStore(gtk.gdk.Pixbuf, str, object)51 self.store = gtk.ListStore(gtk.gdk.Pixbuf, str, object)
51 self.treeview_applications.set_model(self.store) 52 self.treeview_applications.set_model(self.store)
52 self.store.set_sort_column_id(1, gtk.SORT_ASCENDING) 53 self.store.set_sort_column_id(1, gtk.SORT_ASCENDING)
5354
54 self.update()55 self.update()
5556
@@ -65,8 +66,8 @@
65 if self.store.get_value(iter, 1) == app_name: return66 if self.store.get_value(iter, 1) == app_name: return
66 iter = self.store.iter_next(iter)67 iter = self.store.iter_next(iter)
6768
68 self.store.append(([icon, app_name, client])) 69 self.store.append(([icon, app_name, client]))
69 70
70 def update(self):71 def update(self):
7172
72 icon_theme = gtk.icon_theme_get_default()73 icon_theme = gtk.icon_theme_get_default()
@@ -76,7 +77,7 @@
76 self.combobox_clients.append_text(client.name)77 self.combobox_clients.append_text(client.name)
7778
78 for app in self.core.ww.applications.values():79 for app in self.core.ww.applications.values():
79 self.store.append(([app.icon, app.name, app])) 80 self.store.append(([app.icon, app.name, app]))
8081
81 self.combobox_clients.set_active(0)82 self.combobox_clients.set_active(0)
8283
@@ -88,7 +89,7 @@
88 def on_button_add_clicked(self, widget):89 def on_button_add_clicked(self, widget):
8990
90 client = self.core.pa_clients[self.combobox_clients.get_active_text()]91 client = self.core.pa_clients[self.combobox_clients.get_active_text()]
91 92
9293
93 # override with selected app94 # override with selected app
94 model, iter = self.treeview_applications.get_selection().get_selected()95 model, iter = self.treeview_applications.get_selection().get_selected()
@@ -107,6 +108,6 @@
107108
108 self.core.pref.update_client( client )109 self.core.pref.update_client( client )
109 self.stop()110 self.stop()
110 111
111 def on_button_cancel_clicked(self, widget):112 def on_button_cancel_clicked(self, widget):
112 self.stop()113 self.stop()
113114
=== renamed file 'EarCandyDBus.py' => 'earcandylib/EarCandyDBus.py'
--- EarCandyDBus.py 2009-05-19 04:28:48 +0000
+++ earcandylib/EarCandyDBus.py 2009-05-22 15:58:21 +0000
@@ -6,10 +6,9 @@
6DBUS_KEY = "org.earCandy.EarCandyDBus2"6DBUS_KEY = "org.earCandy.EarCandyDBus2"
77
8class EarCandyDBusClient(dbus.service.Object):8class EarCandyDBusClient(dbus.service.Object):
9 9
10 def __init__(self, core):10 def __init__(self, core):
11 self.core = core11 self.core = core
12
1312
14 def is_running(self):13 def is_running(self):
15 dbus.mainloop.glib.DBusGMainLoop (set_as_default=True)14 dbus.mainloop.glib.DBusGMainLoop (set_as_default=True)
@@ -34,7 +33,7 @@
34 dbus.mainloop.glib.DBusGMainLoop (set_as_default=True)33 dbus.mainloop.glib.DBusGMainLoop (set_as_default=True)
35 bus = dbus.SessionBus ()34 bus = dbus.SessionBus ()
36 dbus.service.Object.__init__(self, bus, "/", DBUS_KEY)35 dbus.service.Object.__init__(self, bus, "/", DBUS_KEY)
37 print 36 print
38 print "registered as dbus service..."37 print "registered as dbus service..."
39 print38 print
4039
4140
=== added file 'earcandylib/EarCandyInfo.py'
--- earcandylib/EarCandyInfo.py 1970-01-01 00:00:00 +0000
+++ earcandylib/EarCandyInfo.py 2009-05-23 11:53:46 +0000
@@ -0,0 +1,8 @@
1NAME = "Ear Candy"
2APPNAME = "earcandy"
3VERSION = "0.5"
4DESC = "A PulseAudio volume manager"
5WEBSITE = "http://edge.launchpad.net/earcandy"
6AUTHOR = "Jason Taylor"
7AUTHOR_EMAIL = "killerkiwi2005@gmail.com"
8LICENSE = "GNU GPL v2"
09
=== renamed file 'EarCandyPrefs.py' => 'earcandylib/EarCandyPrefs.py'
--- EarCandyPrefs.py 2009-05-19 04:28:48 +0000
+++ earcandylib/EarCandyPrefs.py 2009-05-22 15:58:21 +0000
@@ -17,15 +17,16 @@
17from Threads import threaded17from Threads import threaded
18from glade_window import GladeWindow18from glade_window import GladeWindow
19from EarCandyAppSelect import EarCandyAppSelect19from EarCandyAppSelect import EarCandyAppSelect
20from Paths import get_data_path
2021
21class EarCandayPref(GladeWindow):22class EarCandayPref(GladeWindow):
22 def __init__(self, core):23 def __init__(self, core):
23 24
24 self.core = core25 self.core = core
2526
26 self.vals = {"" : 0, "music" : 1, "video" : 2, "phone": 3}27 self.vals = {"" : 0, "music" : 1, "video" : 2, "phone": 3}
2728
28 GladeWindow.__init__(self, "pulseoptions.glade", "dialog_options")29 GladeWindow.__init__(self, get_data_path("pulseoptions.glade"), "dialog_options")
2930
30 self.treeview_pulse_clients = self.wtree.get_widget("treeview_pulse_clients")31 self.treeview_pulse_clients = self.wtree.get_widget("treeview_pulse_clients")
31 self.label_pulse_client = self.wtree.get_widget("label_pulse_client")32 self.label_pulse_client = self.wtree.get_widget("label_pulse_client")
@@ -63,9 +64,9 @@
63 "on_comboboxentry_window_match_changed" : self.on_comboboxentry_window_match_changed,64 "on_comboboxentry_window_match_changed" : self.on_comboboxentry_window_match_changed,
64 "on_entry_pulse_client_description_changed" : self.on_entry_pulse_client_description_changed,65 "on_entry_pulse_client_description_changed" : self.on_entry_pulse_client_description_changed,
65 "on_toolbutton_delete_clicked" : self.on_toolbutton_delete_clicked,66 "on_toolbutton_delete_clicked" : self.on_toolbutton_delete_clicked,
66 67
67 "on_hscale_mute_level_value_changed" : self.on_hscale_mute_level_value_changed, 68 "on_hscale_mute_level_value_changed" : self.on_hscale_mute_level_value_changed,
68 "on_hscale_fade_value_changed" : self.on_hscale_fade_value_changed, 69 "on_hscale_fade_value_changed" : self.on_hscale_fade_value_changed,
6970
70 "on_close_button_clicked" : self.on_close_button_clicked,71 "on_close_button_clicked" : self.on_close_button_clicked,
71 "on_button_add_new_clicked" : self.on_button_add_new_clicked,72 "on_button_add_new_clicked" : self.on_button_add_new_clicked,
@@ -74,7 +75,7 @@
74 "on_checkbutton_output_toggled" : self.on_checkbutton_output_toggled75 "on_checkbutton_output_toggled" : self.on_checkbutton_output_toggled
75 }76 }
76 self.wtree.signal_autoconnect(signals)77 self.wtree.signal_autoconnect(signals)
77 78
78 # Setup tree79 # Setup tree
79 #column = gtk.TreeViewColumn('Target', gtk.CellRendererProgress(), value=4)80 #column = gtk.TreeViewColumn('Target', gtk.CellRendererProgress(), value=4)
80 #self.treeview_pulse_clients.append_column(column)81 #self.treeview_pulse_clients.append_column(column)
@@ -145,7 +146,7 @@
145146
146 self.selected_client = model.get_value(iter, 5)147 self.selected_client = model.get_value(iter, 5)
147 self.selected_client.window_position_fade = model[path][3]148 self.selected_client.window_position_fade = model[path][3]
148 149
149 def on_hscale_mute_level_value_changed(self, widget):150 def on_hscale_mute_level_value_changed(self, widget):
150 self.core.mute_level = self.hscale_mute_level.get_value()151 self.core.mute_level = self.hscale_mute_level.get_value()
151 print "Mute Level ", self.core.mute_level152 print "Mute Level ", self.core.mute_level
@@ -170,7 +171,8 @@
170 model, iter = self.treeview_pulse_clients.get_selection().get_selected()171 model, iter = self.treeview_pulse_clients.get_selection().get_selected()
171 if not iter: return172 if not iter: return
172 self.selected_client = model.get_value(iter, 2)173 self.selected_client = model.get_value(iter, 2)
173 md = gtk.MessageDialog(None, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format="Are you sure you want to delete this rule?") 174 md = gtk.MessageDialog(None, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO,
175 message_format="Are you sure you want to delete this rule?")
174 result = md.run()176 result = md.run()
175 md.destroy()177 md.destroy()
176 if result == gtk.RESPONSE_YES:178 if result == gtk.RESPONSE_YES:
@@ -179,17 +181,20 @@
179 del self.core.pa_clients[ key ]181 del self.core.pa_clients[ key ]
180 self.store.remove(iter)182 self.store.remove(iter)
181 self.core.save()183 self.core.save()
182 184
183 def on_button_add_new_clicked(self, widget):185 def on_button_add_new_clicked(self, widget):
184 186
185 if len(self.core.get_unregistered_clients()) > 0:187 if len(self.core.get_unregistered_clients()) > 0:
186 188
187 ecas = EarCandyAppSelect(self.core)189 ecas = EarCandyAppSelect(self.core)
188 client = ecas.run()190 client = ecas.run()
189 if client:191 if client:
190 self.update_client( client )192 self.update_client( client )
191 else:193 else:
192 md = gtk.MessageDialog(self.window, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_OK, message_format="There are currently no pulseaudio streams unassigned,\n\nYou will need to start your sound application playing first") 194 md = gtk.MessageDialog(self.window, flags=0,
195 type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_OK,
196 message_format="There are currently no PulseAudio streams assigned.\n\n"
197 "You will need to start your sound application playing first")
193 result = md.run()198 result = md.run()
194 md.destroy()199 md.destroy()
195200
@@ -201,9 +206,9 @@
201206
202 def on_entry_command_changed(self, widget):207 def on_entry_command_changed(self, widget):
203 self.current_client.rule_re_command = re.compile(widget.get_text(), re.IGNORECASE)208 self.current_client.rule_re_command = re.compile(widget.get_text(), re.IGNORECASE)
204 209
205 def on_entry_window_title_changed(self, widget):210 def on_entry_window_title_changed(self, widget):
206 self.current_client.rule_re_window_title = re.compile(widget.get_text(), re.IGNORECASE) 211 self.current_client.rule_re_window_title = re.compile(widget.get_text(), re.IGNORECASE)
207212
208 def on_combobox_profile_changed(self, widget):213 def on_combobox_profile_changed(self, widget):
209 for key in self.vals.keys():214 for key in self.vals.keys():
@@ -213,7 +218,7 @@
213218
214 def on_vscale_volume_change_value(self, widget, a, b):219 def on_vscale_volume_change_value(self, widget, a, b):
215 self.current_client.volume_default = self.vscale_volume.get_value()220 self.current_client.volume_default = self.vscale_volume.get_value()
216 221
217 def on_vscale_mute_change_value(self, widget, a, b):222 def on_vscale_mute_change_value(self, widget, a, b):
218 self.current_client.volume_mute = self.vscale_mute.get_value()223 self.current_client.volume_mute = self.vscale_mute.get_value()
219224
@@ -222,24 +227,24 @@
222 if cvh.description:227 if cvh.description:
223 text = cvh.description228 text = cvh.description
224 model.set_value(iter,1, text)229 model.set_value(iter,1, text)
225 230
226 def on_entry_pulse_client_description_changed(self, widget): 231 def on_entry_pulse_client_description_changed(self, widget):
227 model, iter = self.treeview_pulse_clients.get_selection().get_selected()232 model, iter = self.treeview_pulse_clients.get_selection().get_selected()
228 cvh = model.get_value(iter, 5) 233 cvh = model.get_value(iter, 5)
229 #cvh.description = self.entry_pulse_client_description.get_text()234 #cvh.description = self.entry_pulse_client_description.get_text()
230 self.update_label(cvh, model, iter)235 self.update_label(cvh, model, iter)
231 236
232 def on_comboboxentry_window_match_changed(self, widget):237 def on_comboboxentry_window_match_changed(self, widget):
233 model, iter = self.treeview_pulse_clients.get_selection().get_selected()238 model, iter = self.treeview_pulse_clients.get_selection().get_selected()
234 cvh = model.get_value(iter, 5) 239 cvh = model.get_value(iter, 5)
235 cvh.window_name_rule = self.comboboxentry_window_match.get_text()240 cvh.window_name_rule = self.comboboxentry_window_match.get_text()
236 241
237 def on_treeview_pulse_clients_cursor_changed(self, widget):242 def on_treeview_pulse_clients_cursor_changed(self, widget):
238 model, iter = self.treeview_pulse_clients.get_selection().get_selected()243 model, iter = self.treeview_pulse_clients.get_selection().get_selected()
239 if not iter: return244 if not iter: return
240 self.selected_client = model.get_value(iter, 5)245 self.selected_client = model.get_value(iter, 5)
241 self.__update_detail( self.selected_client)246 self.__update_detail( self.selected_client)
242 247
243 def on_checkbutton_channel_window_toggled(self, widget):248 def on_checkbutton_channel_window_toggled(self, widget):
244 self.current_client.window_position_fade = self.checkbutton_channel_window.get_active()249 self.current_client.window_position_fade = self.checkbutton_channel_window.get_active()
245250
@@ -249,7 +254,6 @@
249254
250 def on_close_button_clicked(self,widget=None):255 def on_close_button_clicked(self,widget=None):
251 self.stop()256 self.stop()
252
253257
254 def __get_title(self, client):258 def __get_title(self, client):
255 text = client.name259 text = client.name
@@ -262,15 +266,17 @@
262 client.iter = None266 client.iter = None
263267
264 self.store = gtk.ListStore(gtk.gdk.Pixbuf, str, str, bool, int, object)268 self.store = gtk.ListStore(gtk.gdk.Pixbuf, str, str, bool, int, object)
265 self.treeview_pulse_clients.set_model(self.store) 269 self.treeview_pulse_clients.set_model(self.store)
266270
267 icon_theme = gtk.icon_theme_get_default()271 icon_theme = gtk.icon_theme_get_default()
268 icon = icon_theme.lookup_icon("audio-volume-medium", 32, 0).load_icon()272 icon = icon_theme.lookup_icon("audio-volume-medium", 32, 0).load_icon()
269 for client in self.core.pa_clients.values() :273 for client in self.core.pa_clients.values() :
270 if client.category and client.is_active() and not (client.name in self.core.ignore):274 if client.category and client.is_active() and not (client.name in self.core.ignore):
271 client.iter = self.store.append(([client.icon or icon, self.__get_title(client), self.core.display[client.category], client.window_position_fade, 50, client])) 275 client.iter = self.store.append(([client.icon or icon, self.__get_title(client),
276 self.core.display[client.category],
277 client.window_position_fade, 50, client]))
272278
273 self.store.set_sort_column_id(1, gtk.SORT_ASCENDING) 279 self.store.set_sort_column_id(1, gtk.SORT_ASCENDING)
274280
275 def update_client(self, client):281 def update_client(self, client):
276282
@@ -303,12 +309,15 @@
303 if client.has_rule() and not client.name in self.core.ignore:309 if client.has_rule() and not client.name in self.core.ignore:
304 icon_theme = gtk.icon_theme_get_default()310 icon_theme = gtk.icon_theme_get_default()
305 icon = icon_theme.lookup_icon("audio-volume-medium", 32, 0).load_icon()311 icon = icon_theme.lookup_icon("audio-volume-medium", 32, 0).load_icon()
306 client.iter = self.store.append(([client.icon or icon, self.__get_title(client), self.core.display[client.category], client.window_position_fade, client.get_volume(), client])) 312 client.iter = self.store.append(([client.icon or icon, self.__get_title(client),
313 self.core.display[client.category],
314 client.window_position_fade, client.get_volume(),
315 client]))
307316
308 self.store.set_sort_column_id(1,gtk.SORT_ASCENDING)317 self.store.set_sort_column_id(1,gtk.SORT_ASCENDING)
309318
310 def run(self):319 def run(self):
311 self.window.show() 320 self.window.show()
312 self.hscale_mute_level.set_value(self.core.mute_level)321 self.hscale_mute_level.set_value(self.core.mute_level)
313 self.hscale_fade.set_value(self.core.fade_timer_speed)322 self.hscale_fade.set_value(self.core.fade_timer_speed)
314 self.checkbutton_tray.set_active( self.core.tray.get_visible() )323 self.checkbutton_tray.set_active( self.core.tray.get_visible() )
@@ -320,19 +329,14 @@
320 self.core.save()329 self.core.save()
321 self.core.close_preferances()330 self.core.close_preferances()
322 self.window.destroy()331 self.window.destroy()
323 332
324 @threaded333 @threaded
325 def remove_client_on_timer(self, client):334 def remove_client_on_timer(self, client):
326 #time.sleep(60)335 #time.sleep(60)
327 #gobject.idle_add(self.remove_client, client) 336 #gobject.idle_add(self.remove_client, client)
328 return337 return
329 338
330 def remove_client(self, client):339 def remove_client(self, client):
331 if not client.is_active() and client.iter :340 if not client.is_active() and client.iter :
332 self.store.remove(client.iter)341 self.store.remove(client.iter)
333 client.iter = None342 client.iter = None
334
335
336
337
338
339343
=== renamed file 'Freedesktop.py' => 'earcandylib/Freedesktop.py'
--- Freedesktop.py 2009-02-06 10:31:04 +0000
+++ earcandylib/Freedesktop.py 2009-05-22 15:58:21 +0000
@@ -81,7 +81,7 @@
81 items.sort()81 items.sort()
82 for item in items:82 for item in items:
83 file_object.write(item[0] + '=' + item[1] + '\n')83 file_object.write(item[0] + '=' + item[1] + '\n')
84 84
85 # turn command into an array85 # turn command into an array
86 def get_exec_array(self):86 def get_exec_array(self):
87 command = []87 command = []
@@ -89,4 +89,3 @@
89 for r in re.finditer(p, self.get("Exec")):89 for r in re.finditer(p, self.get("Exec")):
90 command.append( str(r.group(0)) )90 command.append( str(r.group(0)) )
91 return command91 return command
92
9392
=== added file 'earcandylib/Paths.py'
--- earcandylib/Paths.py 1970-01-01 00:00:00 +0000
+++ earcandylib/Paths.py 2009-05-23 12:53:07 +0000
@@ -0,0 +1,27 @@
1
2from os.path import isdir, isfile, join, dirname, abspath
3
4
5DATA_DIR = None
6
7
8_path = abspath(join(dirname(__file__), '..', 'data'))
9if isdir(_path):
10 DATA_DIR = _path
11else:
12 # We are installed on the system
13 for prefix in ["/usr", "/usr/local"]:
14 _path = join(prefix, "share", "earcandy")
15 if isdir(_path):
16 DATA_DIR = _path
17
18if DATA_DIR == None:
19 raise IOError, "cannot find data directory"
20
21
22def get_data_path(filename):
23 path = join(DATA_DIR, filename)
24 if isfile(path):
25 return path
26 else:
27 raise IOError, "file not found"
028
=== renamed file 'Sink.py' => 'earcandylib/Sink.py'
--- Sink.py 2009-05-19 04:28:48 +0000
+++ earcandylib/Sink.py 2009-05-22 15:58:21 +0000
@@ -1,6 +1,6 @@
1import math 1import math
2import time2import time
3 3
4class Sink():4class Sink():
5 def __init__(self, index, name, volume, client, channels=1):5 def __init__(self, index, name, volume, client, channels=1):
66
@@ -15,7 +15,7 @@
1515
16 self.__previous_left = 016 self.__previous_left = 0
17 self.__previous_right = 017 self.__previous_right = 0
18 18
19 def set_volume(self):19 def set_volume(self):
2020
21 if len(self.volume) > 2:21 if len(self.volume) > 2:
@@ -26,9 +26,9 @@
26 # Mono channel26 # Mono channel
27 target_volume = round(self.volume[1])27 target_volume = round(self.volume[1])
2828
29 if target_volume < self.client.volume_target: 29 if target_volume < self.client.volume_target:
30 target_volume = round(target_volume + self.client.volume_step)30 target_volume = round(target_volume + self.client.volume_step)
31 elif target_volume > self.client.volume_target: 31 elif target_volume > self.client.volume_target:
32 target_volume = round(target_volume - self.client.volume_step)32 target_volume = round(target_volume - self.client.volume_step)
3333
34 if len(self.volume) > 2:34 if len(self.volume) > 2:
@@ -38,7 +38,7 @@
38 if len(self.volume) > 2:38 if len(self.volume) > 2:
39 if self.client.balance < 0: left = math.fabs(target_volume - (target_volume / 100 * self.client.balance))39 if self.client.balance < 0: left = math.fabs(target_volume - (target_volume / 100 * self.client.balance))
40 if self.client.balance > 0: right = math.fabs(target_volume - (target_volume / 100 * self.client.balance))40 if self.client.balance > 0: right = math.fabs(target_volume - (target_volume / 100 * self.client.balance))
41 41
42 if self.volume[1] < left:42 if self.volume[1] < left:
43 self.volume[1] = round(self.volume[1]) + self.client.volume_step43 self.volume[1] = round(self.volume[1]) + self.client.volume_step
44 if self.volume[1] > left:44 if self.volume[1] > left:
@@ -57,20 +57,20 @@
57 else:57 else:
58 self.volume[1] = round(target_volume)58 self.volume[1] = round(target_volume)
59 self.volume.append(target_volume) #FIXME: remove second channel volume59 self.volume.append(target_volume) #FIXME: remove second channel volume
60 60
61 # we dont want to get stuck in a loop because volumes arn't exactly the same 61 # we dont want to get stuck in a loop because volumes arn't exactly the same
62 result = math.fabs(self.volume[1] - self.__previous_left) > self.client.volume_step / 262 result = math.fabs(self.volume[1] - self.__previous_left) > self.client.volume_step / 2
63 result = result and (math.fabs(self.volume[2] - self.__previous_right) > self.client.volume_step /2)63 result = result and (math.fabs(self.volume[2] - self.__previous_right) > self.client.volume_step /2)
64 64
65 # We never want a zero volume as we cant read meter levels from zero volume65 # We never want a zero volume as we cant read meter levels from zero volume
66 result = result and not self.volume[1] == self.client.volume_step66 result = result and not self.volume[1] == self.client.volume_step
67 result = result and not self.volume[2] == self.client.volume_step 67 result = result and not self.volume[2] == self.client.volume_step
68 if result:68 if result:
69 print69 print
70 print "Adjust Volume", self.client.name, self.volume[1] , self.__previous_left70 print "Adjust Volume", self.client.name, self.volume[1] , self.__previous_left
7171
72 self.__previous_left = self.volume[1]72 self.__previous_left = self.volume[1]
73 self.__previous_right = self.volume[2]73 self.__previous_right = self.volume[2]
74 74
75 return result75 return result
7676
7777
=== renamed file 'Threads.py' => 'earcandylib/Threads.py'
=== renamed file 'TrayIcon.py' => 'earcandylib/TrayIcon.py'
--- TrayIcon.py 2009-05-19 04:28:48 +0000
+++ earcandylib/TrayIcon.py 2009-05-22 15:58:21 +0000
@@ -1,15 +1,17 @@
1#!/usr/bin/env python1#!/usr/bin/env python
22
3import os
4import sys3import sys
5import gtk4import gtk
65
6import EarCandyInfo
7from Paths import get_data_path
8
79
8class EarCandyStatusIcon(gtk.StatusIcon):10class EarCandyStatusIcon(gtk.StatusIcon):
9 def __init__(self, core):11 def __init__(self, core):
10 gtk.StatusIcon.__init__(self)12 gtk.StatusIcon.__init__(self)
11 self.core = core13 self.core = core
12 14
13 menu = '''15 menu = '''
14 <ui>16 <ui>
15 <menubar name="Menubar">17 <menubar name="Menubar">
@@ -44,7 +46,7 @@
44 #46 #
45 #self.core.slider.window.present()47 #self.core.slider.window.present()
46 self.core.slider.window.set_position(gtk.WIN_POS_MOUSE)48 self.core.slider.window.set_position(gtk.WIN_POS_MOUSE)
47 screen, rect, orin = self.get_geometry() 49 screen, rect, orin = self.get_geometry()
48 x, y = self.core.slider.window.get_position()50 x, y = self.core.slider.window.get_position()
49 if rect.y - rect.height/2 > y - rect.height:51 if rect.y - rect.height/2 > y - rect.height:
50 self.core.slider.window.move(x, y + rect.height)52 self.core.slider.window.move(x, y + rect.height)
@@ -58,24 +60,24 @@
5860
59 def on_about(self, data):61 def on_about(self, data):
60 dialog = gtk.AboutDialog()62 dialog = gtk.AboutDialog()
61 dialog.set_name('Ear Candy')63 dialog.set_name(EarCandyInfo.NAME)
62 dialog.set_version('0.4')64 dialog.set_version(EarCandyInfo.VERSION)
63 dialog.set_comments('A pulse audio ear candy manager')65 dialog.set_comments(EarCandyInfo.DESC)
64 dialog.set_website('http://edge.launchpad.net/eyecandy')66 dialog.set_website(EarCandyInfo.WEBSITE)
65 dialog.run()67 dialog.run()
66 dialog.destroy()68 dialog.destroy()
67 69
6870
69 def set_icon(self):71 def set_icon(self):
70 if self.core.active:72 if self.core.active:
71 icon_path = os.path.join(os.path.dirname(__file__),"earsLabel.png")73 icon_path = get_data_path("earsLabel.png")
72 else:74 else:
73 icon_path = os.path.join(os.path.dirname(__file__),"earsLabelOff.png")75 icon_path = get_data_path("earsLabelOff.png")
74 self.set_from_file( icon_path )76 self.set_from_file( icon_path )
7577
76 def stop(self, data=None):78 def stop(self, data=None):
77 gtk.main_quit()79 gtk.main_quit()
78 80
79if __name__ == '__main__':81if __name__ == '__main__':
80 ts = TrackerStatusIcon()82 ts = TrackerStatusIcon()
81 ts.run()83 ts.run()
8284
=== renamed file 'VolumeSlider.py' => 'earcandylib/VolumeSlider.py'
--- VolumeSlider.py 2009-05-19 04:28:48 +0000
+++ earcandylib/VolumeSlider.py 2009-05-22 15:58:21 +0000
@@ -16,13 +16,14 @@
16from glade_window import GladeWindow16from glade_window import GladeWindow
17from window.WindowWatcher import WindowWatcher17from window.WindowWatcher import WindowWatcher
18from Client import Client18from Client import Client
19from Paths import get_data_path
1920
20class EarCandyVolumeSlider(GladeWindow):21class EarCandyVolumeSlider(GladeWindow):
21 def __init__(self, core):22 def __init__(self, core):
22 self.core = core23 self.core = core
23 24
24 GladeWindow.__init__(self, "pulseoptions.glade", "popup_volume_control")25 GladeWindow.__init__(self, get_data_path("pulseoptions.glade"), "popup_volume_control")
25 26
26 self.vscale_volume = self.wtree.get_widget("vscale_volume")27 self.vscale_volume = self.wtree.get_widget("vscale_volume")
27 self.image_status = self.wtree.get_widget("image_status")28 self.image_status = self.wtree.get_widget("image_status")
2829
@@ -48,7 +49,7 @@
48 self.image_status.set_from_stock("gtk-media-pause", 4)49 self.image_status.set_from_stock("gtk-media-pause", 4)
49 else:50 else:
50 self.image_status.set_from_stock("gtk-media-play", 4)51 self.image_status.set_from_stock("gtk-media-play", 4)
51 52
52 self.core.tray.set_icon()53 self.core.tray.set_icon()
53 self.stop()54 self.stop()
5455
5556
=== added file 'earcandylib/__init__.py'
=== renamed file 'glade_window.py' => 'earcandylib/glade_window.py'
--- glade_window.py 2008-10-09 20:37:12 +0000
+++ earcandylib/glade_window.py 2009-05-22 15:58:21 +0000
@@ -18,9 +18,9 @@
18 self.wtree = gtk.glade.XML(glade_file)18 self.wtree = gtk.glade.XML(glade_file)
19 self.window = self.wtree.get_widget(window_name)19 self.window = self.wtree.get_widget(window_name)
20 self.window.connect("destroy", self.on_destroy)20 self.window.connect("destroy", self.on_destroy)
21 21
22 def run(self):22 def run(self):
23 self.window.show() 23 self.window.show()
24 gtk.main()24 gtk.main()
25 return self.return_value25 return self.return_value
2626
2727
=== renamed directory 'pulseaudio' => 'earcandylib/pulseaudio'
=== renamed directory 'window' => 'earcandylib/window'
=== modified file 'earcandylib/window/WindowWatcher.py'
--- window/WindowWatcher.py 2009-05-11 22:27:41 +0000
+++ earcandylib/window/WindowWatcher.py 2009-05-22 14:14:10 +0000
@@ -6,7 +6,7 @@
6import wnck6import wnck
7import gobject7import gobject
8import os8import os
9from DesktopFiles import DesktopFiles9from earcandylib.DesktopFiles import DesktopFiles
1010
11class Application():11class Application():
12 def __init__(self, command, name, desktop_files, icon):12 def __init__(self, command, name, desktop_files, icon):
1313
=== added file 'setup.py'
--- setup.py 1970-01-01 00:00:00 +0000
+++ setup.py 2009-05-23 12:26:12 +0000
@@ -0,0 +1,21 @@
1#!/usr/bin/env python
2
3from distutils.core import setup
4from glob import glob
5
6from earcandylib.EarCandyInfo import *
7
8DATA_FILES = [('share/earcandy', glob('data/*'))]
9DATA_FILES += [('share/applications', ['earcandy.desktop'])]
10DATA_FILES += [('share/pixmaps', ['data/earsLabel.png'])]
11
12setup(name = APPNAME,
13 version = VERSION,
14 description = DESC,
15 author = AUTHOR,
16 author_email = AUTHOR_EMAIL,
17 url = WEBSITE,
18 license = LICENSE,
19 packages = ['earcandylib', 'earcandylib.pulseaudio', 'earcandylib.window'],
20 data_files = DATA_FILES,
21 scripts = ['earcandy'])

Subscribers

People subscribed via source and target branches

to all changes:
to status/vote changes: