Let application decides on how to handle signals.
[laditools.git] / ladi-player
blob76fad141e2ddb6e846f0aa463fb4a3ab2b0781fd
1 #!/usr/bin/python
2 # LADITools - Linux Audio Desktop Integration Tools
3 # laditray - System tray integration for LADI
4 # Copyright (C) 2012 Alessio Treglia <quadrispro@ubuntu.com>
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
19 import os
20 import sys
21 import time
22 import signal
23 import gettext
24 import argparse
26 from laditools import _gettext_domain
27 gettext.install(_gettext_domain)
29 from laditools import get_version_string
30 from laditools import LadiConfiguration
31 from laditools import LadiApp
33 from gi.repository import Gtk
34 from gi.repository import GObject
35 from laditools import LadiManager
36 from laditools.gtk import LadiManagerGtk
37 from laditools.gtk import find_data_file
39 timeout_add = GObject.timeout_add
41 class LadiPlayer(LadiManagerGtk, LadiApp):
43 _appname = 'ladi-player'
44 _appname_long = _("LADI Player")
45 _appid = 'org.linuxaudio.ladi.player'
47 # Default configuration
48 _default_config = {
49 'autostart' : False,
52 def on_about(self, *args):
53 LadiManagerGtk.on_about(self, parent=self.window_main, version=get_version_string())
55 def quit(self, *args):
56 self.global_config.set_config_section (self.appname,
57 self.config_dict)
58 self.global_config.save()
59 Gtk.main_quit()
61 def on_quit(self, *args, **kwargs):
62 self.quit()
64 def _run_select_studio_dialog(self, title, *args):
65 studio_list = self.get_ladish_controller().studio_list()
66 if not studio_list:
67 dlg = Gtk.MessageDialog(None,Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
68 Gtk.MessageType.INFO,
69 Gtk.ButtonsType.CLOSE,
70 _('No studio is available.'))
71 dlg.set_transient_for(self.window_main)
72 dlg.set_title(title)
73 dlg.run()
74 dlg.destroy()
75 return None
77 dlg = Gtk.Dialog()
78 treeview = Gtk.TreeView()
79 model = Gtk.ListStore(GObject.TYPE_STRING)
80 renderer = Gtk.CellRendererText()
81 column = Gtk.TreeViewColumn('Available studios', renderer, text=0)
83 treeview.set_model(model)
84 treeview.append_column(column)
85 treeview.set_cursor(Gtk.TreePath(path=0),
86 focus_column=column,
87 start_editing=False)
89 for studio in studio_list:
90 model.append((studio,))
92 dlg.set_transient_for(self.window_main)
93 dlg.set_modal(True)
94 dlg.set_destroy_with_parent(True)
95 dlg.set_title(title)
96 dlg.get_content_area().pack_start(child=treeview,
97 expand=True,
98 fill=True,
99 padding=10)
100 dlg.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK)
101 dlg.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
102 dlg.show_all()
104 response = dlg.run()
105 ret = None
106 if response == Gtk.ResponseType.OK:
107 path, column = treeview.get_cursor()
108 ret = model[path][0]
109 dlg.hide()
110 return ret
112 def _toolbuttons_set_active(self, group, **kwargs):
113 buttons = getattr(self, "%s_status_buttons" % group)
114 if 'all' in kwargs:
115 status = kwargs['all']
116 for button in buttons:
117 buttons[button].set_sensitive(status)
118 else:
119 for button in kwargs:
120 buttons[button].set_sensitive(kwargs[button])
122 def jack_is_started(self, *args, **kwargs):
123 while True:
124 try:
125 return LadiManagerGtk.jack_is_started(self, *args, **kwargs)
126 except:
127 time.sleep(0.5)
128 continue
130 def ladish_toolbuttons_set_active(self, **kwargs): self._toolbuttons_set_active('ladish', **kwargs)
131 def jack_toolbuttons_set_active(self, **kwargs): self._toolbuttons_set_active('jack', **kwargs)
132 def a2j_toolbuttons_set_active(self, **kwargs): self._toolbuttons_set_active('a2j', **kwargs)
134 def ladish_status_buttons_update(self):
135 buttons = self.ladish_status_buttons
137 # Setup ladish controls
138 if self.ladish_is_available():
139 # Buttons "rename" and "unload"
140 if self.studio_is_loaded():
141 self.ladish_toolbuttons_set_active(unload=True, rename=True)
142 # Buttons "start" and "stop"
143 if self.studio_is_started():
144 self.ladish_toolbuttons_set_active(start=False, stop=True, save=True)
145 else:
146 self.ladish_toolbuttons_set_active(start=True, stop=False, save=False)
147 else:
148 self.ladish_toolbuttons_set_active(start=True,
149 stop=False,
150 save=False,
151 unload=False,
152 rename=False)
153 else:
154 self.ladish_toolbuttons_set_active(all=False)
156 def jack_status_buttons_update(self):
157 if not self.jack_is_available():
158 return
160 buttons = self.jack_status_buttons
161 ladish_available = self.ladish_is_available()
162 jack_started = self.jack_is_started()
164 if jack_started:
165 self.jack_toolbuttons_set_active(jack_start=False,
166 jack_stop=(not ladish_available),
167 jack_reset_xruns=True,
168 jack_reactivate=True)
169 else:
170 self.jack_toolbuttons_set_active(jack_start=True,
171 jack_stop=False,
172 jack_reset_xruns=False,
173 jack_reactivate=True)
176 def a2j_status_buttons_update(self):
177 if not self.a2j_is_available():
178 self.a2j_toolbuttons_set_active(all=False)
179 return
181 buttons = self.a2j_status_buttons
182 ladish_available = self.ladish_is_available()
183 a2j_started = self.a2j_is_started()
185 if not ladish_available:
186 if a2j_started:
187 self.a2j_toolbuttons_set_active(a2j_start=False,
188 a2j_stop=True,
189 a2j_reactivate=True)
190 else:
191 self.a2j_toolbuttons_set_active(a2j_start=True,
192 a2j_stop=False,
193 a2j_reactivate=True)
194 else:
195 self.a2j_toolbuttons_set_active(a2j_start=False,
196 a2j_stop=False,
197 a2j_reactivate=True)
199 def update_status_buttons(self):
201 # Update widgets
202 self.ladish_status_buttons_update()
203 self.jack_status_buttons_update()
204 self.a2j_status_buttons_update()
206 # Update status label and window icon
207 if self.jack_is_started():
208 self.window_main.set_icon_name("ladi-started")
209 if self.jack_is_realtime():
210 status_text = "RT | "
211 else:
212 status_text = ""
213 # Get DSP Load
214 status_text += str (round (float (self.jack_get_load()),1)) + "% | "
215 # Get Xruns
216 status_text += str (self.jack_get_xruns())
217 # Set a started status
218 self.status_label.set_label (status_text)
219 else:
220 self.window_main.set_icon_name("ladi-stopped")
221 self.status_label.set_label(_('<i>Stopped</i>'))
223 def update(self, *args, **kwargs):
224 self.update_status_buttons()
225 LadiManagerGtk.update(self, *args, **kwargs)
226 return True
228 def _set_starting_status(self):
229 self.window_main.set_icon_name("ladi-starting")
231 def action_ladish_new(self, action, *args):
232 self.studio_new()
234 def action_ladish_start(self, action, *args):
235 if self.studio_is_loaded():
236 if not self.studio_is_started():
237 self._set_starting_status()
238 self.studio_start()
239 self.update_status_buttons()
240 else:
241 self._set_starting_status()
242 self.jack_start()
243 self.update_status_buttons()
245 def action_ladish_save(self, action, *args):
246 self.studio_save()
248 def action_ladish_stop(self, action, *args):
249 if self.jack_is_started() and self.studio_is_started():
250 self.studio_stop()
251 self.update_status_buttons()
253 def action_ladish_rename(self, action, *args):
254 self.studio_rename()
255 self.update_status_buttons()
257 def action_ladish_load(self, action, *args):
258 selection = self._run_select_studio_dialog(_('Load studio'))
259 if selection:
260 self.studio_load(studio=selection)
261 return selection
263 def action_ladish_delete(self, action, *args):
264 selection = self._run_select_studio_dialog(_('Delete studio'))
265 if selection:
266 LadiManager.studio_delete(self, studio=selection)
267 return selection
269 def action_ladish_unload(self, action, *args):
270 while True:
271 try:
272 if self.studio_is_loaded():
273 self.studio_unload()
274 self.update_status_buttons()
275 break
276 except:
277 time.sleep(0.5)
278 continue
280 def action_ladish_reactivate(self, action, *args):
281 self.ladish_reactivate()
283 def action_jack_start(self, action, *args):
284 self._set_starting_status()
285 self.jack_start()
286 def action_jack_stop(self, action, *args):
287 self.jack_stop()
288 def action_jack_reset_xruns(self, action, *args):
289 self.jack_reset_xruns()
290 def action_jack_reactivate(self, action, *args):
291 self.jack_reactivate()
293 def action_a2j_start(self, action, *args):
294 self.a2j_start()
295 def action_a2j_stop(self, action, *args):
296 self.a2j_stop()
297 def action_a2j_reactivate(self, action, *args):
298 self.a2j_reactivate()
300 def action_launcher_launch(self, action, *args):
301 self.launcher_exec(command=self._launcher_which(action.get_name()))
303 def __init__(self):
304 # Initialize app
305 LadiApp.__init__(self)
306 # Handle the configuration
307 self.global_config = LadiConfiguration(self.appname, self._default_config)
308 self.config_dict = self.global_config.get_config_section (self.appname)
309 autostart = bool(eval(self.config_dict['autostart']))
311 LadiManagerGtk.__init__(self, autostart)
313 # Handle signals
314 signal.signal(signal.SIGTERM, self.quit)
315 signal.signal(signal.SIGINT, self.quit)
317 # Build the UI
318 builder = Gtk.Builder()
319 ui_path = find_data_file("ladi-player.ui")
320 builder.add_from_file(ui_path)
321 sys.stderr.write( _("Loading interface from %s\n") % ui_path)
322 sys.stderr.flush()
324 # Retrieve objects
325 self.window_main = builder.get_object("window_main")
326 actiongroup_ladish = builder.get_object("actiongroup_ladish")
327 actiongroup_jack = builder.get_object("actiongroup_jack")
328 actiongroup_a2j = builder.get_object("actiongroup_a2j")
329 actiongroup_launcher = builder.get_object("actiongroup_launcher")
330 self.status_label = builder.get_object('toolbutton_label_status')
332 # Setup status buttons
333 self.ladish_status_buttons = ladish_status_buttons = {}
334 self.jack_status_buttons = jack_status_buttons = {}
335 self.a2j_status_buttons = a2j_status_buttons = {}
336 self.launcher_status_buttons = launcher_status_buttons = {}
338 for action in actiongroup_ladish.list_actions():
339 ladish_status_buttons[action.get_name()] = action
340 for action in actiongroup_jack.list_actions():
341 jack_status_buttons[action.get_name()] = action
342 for action in actiongroup_a2j.list_actions():
343 a2j_status_buttons[action.get_name()] = action
344 for action in actiongroup_launcher.list_actions():
345 launcher_status_buttons[action.get_name()] = action
347 # Remove launchers for unavailable commands
348 for command in launcher_status_buttons:
349 if not self._launcher_which(command):
350 launcher_status_buttons[command].set_active(False)
352 # Accelerators
353 # accelgroup = builder.get_object("accelgroup1")
354 # action = actiongroup_launcher.get_action("gladish")
355 # action.set_accel_group(accelgroup)
356 # action.set_accel_path("menu_studio")
358 # Get the initial status
359 self.update ()
360 # Add the auto update callback
361 self.auto_updater = timeout_add (250, self.update, None)
363 builder.connect_signals(self)
365 def run(self):
366 self.window_main.show_all()
368 if __name__ == "__main__":
369 parser = argparse.ArgumentParser(description=_('graphical front-end that allows users to start, stop and'
370 'monitor JACK, as well as start some JACK related applications'),
371 epilog=_('This program is part of the LADITools suite.'))
372 parser.add_argument('--version', action='version', version="%(prog)s " + get_version_string())
374 parser.parse_args()
375 GObject.threads_init()
377 Gtk.init(None)
378 LadiPlayer().run()
379 Gtk.main()
380 sys.exit(0)