root/gui/main.c @ 354012f70727cdc93b1a464d0b59a18f0df31af1

Revision 354012f70727cdc93b1a464d0b59a18f0df31af1, 14.7 KB (checked in by Nedko Arnaudov <nedko@…>, 4 years ago)

Delete studio command. Closes #6

  • Property mode set to 100644
Line 
1/* -*- Mode: C ; c-basic-offset: 2 -*- */
2/*
3 * LADI Session Handler (ladish)
4 *
5 * Copyright (C) 2008, 2009 Nedko Arnaudov <nedko@arnaudov.name>
6 * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
7 *
8 **************************************************************************
9 * This file contains the code that implements main() and other top-level functionality
10 **************************************************************************
11 *
12 * LADI Session Handler is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * LADI Session Handler is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
24 * or write to the Free Software Foundation, Inc.,
25 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 */
27
28#include "common.h"
29
30#include <math.h>
31
32#include "glade.h"
33#include "canvas.h"
34#include "graph_canvas.h"
35#include "../jack_proxy.h"
36#include "dbus_helpers.h"
37#include "control_proxy.h"
38#include "../dbus_constants.h"
39#include "world_tree.h"
40#include "graph_view.h"
41#include "../catdup.h"
42#include "../studio_proxy.h"
43
44GtkWidget * g_main_win;
45
46GtkWidget * g_clear_load_button;
47GtkWidget * g_xrun_progress_bar;
48GtkWidget * g_buffer_size_combo;
49
50GtkWidget * g_menu_item_load_studio;
51GtkWidget * g_menu_item_save_studio;
52GtkWidget * g_menu_item_rename_studio;
53GtkWidget * g_menu_item_delete_studio;
54GtkWidget * g_menu_item_create_room;
55GtkWidget * g_menu_item_destroy_room;
56GtkWidget * g_menu_item_load_project;
57GtkWidget * g_menu_item_start_app;
58
59GtkWidget * g_rename_dialog;
60
61graph_view_handle g_jack_view = NULL;
62graph_view_handle g_studio_view = NULL;
63
64static guint g_jack_poll_source_tag;
65static double g_jack_max_dsp_load = 0.0;
66
67struct studio_list
68{
69  int count;
70  GtkWidget * menu_item;
71  GtkWidget * menu;
72  void (* item_activate_callback)(GtkWidget * item);
73  bool add_sensitive;
74};
75
76static struct studio_list g_load_studio_list;
77static struct studio_list g_delete_studio_list;
78
79#if 0
80static void
81gtkmm_get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
82             int& width,
83             int& height)
84{
85  Pango::Rectangle ink_rect = layout->get_ink_extents ();
86 
87  width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE;
88  height = (ink_rect.get_height() + PANGO_SCALE / 2) / PANGO_SCALE;
89}
90
91static void
92gtkmm_set_width_for_given_text (Gtk::Widget &w, const gchar *text,
93               gint hpadding/*, gint vpadding*/)
94 
95{
96  int old_width, old_height;
97  w.get_size_request(old_width, old_height);
98
99  int width, height;
100  w.ensure_style ();
101 
102  gtkmm_get_ink_pixel_size (w.create_pango_layout (text), width, height);
103  w.set_size_request(width + hpadding, old_height);//height + vpadding);
104}
105
106#endif
107
108static void set_buffer_size_combo_width(void)
109{
110  //gtkmm_set_width_for_given_text(*_buffer_size_combo, "4096 frames", 40);
111}
112
113static void buffer_size_clear()
114{
115  gtk_entry_set_text(GTK_ENTRY(get_glade_widget("comboboxentry")), "");
116}
117
118static void buffer_size_set(uint32_t size)
119{
120  gtk_combo_box_set_active(GTK_COMBO_BOX(g_buffer_size_combo), (int)log2f(size) - 5);
121}
122
123static void buffer_size_change_request(void)
124{
125  const int selected = gtk_combo_box_get_active(GTK_COMBO_BOX(g_buffer_size_combo));
126
127  if (selected < 0 || !jack_proxy_set_buffer_size(1 << (selected + 5)))
128  {
129    lash_error("cannot set JACK buffer size");
130    buffer_size_clear();
131  }
132}
133
134static void update_buffer_size(void)
135{
136  uint32_t size;
137
138  if (jack_proxy_get_buffer_size(&size))
139  {
140    buffer_size_set(size);
141  }
142  else
143  {
144    buffer_size_clear();
145  }
146}
147
148static void update_load(void)
149{
150  uint32_t xruns;
151  double load;
152  char tmp_buf[100];
153
154  if (!jack_proxy_get_xruns(&xruns) || !jack_proxy_get_dsp_load(&load))
155  {
156    gtk_progress_bar_set_text(GTK_PROGRESS_BAR(g_xrun_progress_bar), "error");
157    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(g_xrun_progress_bar), 0.0);
158  }
159
160  snprintf(tmp_buf, sizeof(tmp_buf), "%" PRIu32 " Dropouts", xruns);
161  gtk_progress_bar_set_text(GTK_PROGRESS_BAR(g_xrun_progress_bar), tmp_buf);
162
163  load /= 100.0;           // dbus returns it in percents, we use 0..1
164
165  if (load > g_jack_max_dsp_load)
166  {
167    g_jack_max_dsp_load = load;
168    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(g_xrun_progress_bar), load);
169  }
170}
171
172static void clear_load(void)
173{
174  jack_proxy_reset_xruns();
175  g_jack_max_dsp_load = 0.0;
176  gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(g_xrun_progress_bar), 0.0);
177}
178
179bool rename_dialog(const char * object, const char * old_name, char ** new_name)
180{
181  guint result;
182  bool renamed;
183  GtkEntry * entry = GTK_ENTRY(get_glade_widget("rename_entry"));
184
185  gtk_widget_show(g_rename_dialog);
186
187  gtk_label_set_text(GTK_LABEL(get_glade_widget("rename_label")), object);
188  gtk_entry_set_text(entry, old_name);
189  gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1);
190
191  result = gtk_dialog_run(GTK_DIALOG(g_rename_dialog));
192  renamed = result == 2;
193  if (renamed)
194  {
195    *new_name = strdup(gtk_entry_get_text(entry));
196    if (*new_name == NULL)
197    {
198      lash_error("strdup failed for new name (rename)");
199      renamed = false;
200    }
201  }
202
203  gtk_widget_hide(g_rename_dialog);
204
205  return renamed;
206}
207
208static void arrange(void)
209{
210  canvas_handle canvas;
211
212  lash_info("arrange request");
213
214  canvas = get_current_canvas();
215  if (canvas != NULL)
216  {
217    canvas_arrange(canvas);
218  }
219}
220
221static void on_load_studio(GtkWidget * item)
222{
223  const char * studio_name;
224
225  studio_name = gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))));
226  lash_info("Load studio \"%s\"", studio_name);
227
228  if (!control_proxy_load_studio(studio_name))
229  {
230    /* TODO: display error message */
231  }
232}
233
234static void on_delete_studio(GtkWidget * item)
235{
236  const char * studio_name;
237
238  studio_name = gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(item))));
239  lash_info("Delete studio \"%s\"", studio_name);
240
241  /* TODO: ask user for confirmation */
242
243  if (!control_proxy_delete_studio(studio_name))
244  {
245    /* TODO: display error message */
246  }
247}
248
249#define studio_list_ptr ((struct studio_list *)context)
250
251static void remove_studio_list_menu_entry(GtkWidget * item, gpointer context)
252{
253  GtkWidget * label;
254
255  label = gtk_bin_get_child(GTK_BIN(item));
256
257  //lash_debug("removing studio menu item \"%s\"", gtk_menu_item_get_label(GTK_MENU_ITEM(item));
258  // gtk_menu_item_get_label() requries gtk 2.16
259  lash_debug("removing studio menu item \"%s\"", gtk_label_get_text(GTK_LABEL(label)));
260
261  gtk_container_remove(GTK_CONTAINER(item), label); /* destroy the label and drop the item refcount by one */
262  //lash_info("refcount == %d", (unsigned int)G_OBJECT(item)->ref_count);
263  gtk_container_remove(GTK_CONTAINER(studio_list_ptr->menu), item); /* drop the refcount of item by one and thus destroy it */
264  studio_list_ptr->count--;
265}
266
267static void add_studio_list_menu_entry(void * context, const char * studio_name)
268{
269  GtkWidget * item;
270
271  item = gtk_menu_item_new_with_label(studio_name);
272  //lash_info("refcount == %d", (unsigned int)G_OBJECT(item)->ref_count); // refcount == 2 because of the label
273  gtk_widget_set_sensitive(item, studio_list_ptr->add_sensitive);
274  gtk_widget_show(item);
275  gtk_menu_shell_append(GTK_MENU_SHELL(studio_list_ptr->menu), item);
276  g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(studio_list_ptr->item_activate_callback), item);
277  studio_list_ptr->count++;
278}
279
280#undef studio_list_ptr
281
282static void menu_studio_list_clear(struct studio_list * studio_list_ptr)
283{
284  gtk_container_foreach(GTK_CONTAINER(studio_list_ptr->menu), remove_studio_list_menu_entry, studio_list_ptr);
285  assert(studio_list_ptr->count == 0);
286  studio_list_ptr->count = 0;
287}
288
289static void populate_studio_list_menu(GtkMenuItem * menu_item, struct studio_list * studio_list_ptr)
290{
291  menu_studio_list_clear(studio_list_ptr);
292  studio_list_ptr->add_sensitive = true;
293  if (!control_proxy_get_studio_list(add_studio_list_menu_entry, studio_list_ptr))
294  {
295    menu_studio_list_clear(studio_list_ptr);
296    studio_list_ptr->add_sensitive = true;
297    add_studio_list_menu_entry(studio_list_ptr, "Error obtaining studio list");
298  }
299  else if (studio_list_ptr->count == 0)
300  {
301    studio_list_ptr->add_sensitive = true;
302    add_studio_list_menu_entry(studio_list_ptr, "Empty studio list");
303  }
304}
305
306static void save_studio(void)
307{
308  lash_info("save studio request");
309  if (!studio_proxy_save())
310  {
311    lash_error("studio save failed");
312  }
313}
314
315static void rename_studio(void)
316{
317  char * new_name;
318
319  if (rename_dialog("Studio name", get_view_name(g_studio_view), &new_name))
320  {
321    if (!studio_proxy_rename(new_name))
322    {
323      lash_error("studio rename failed");
324    }
325
326    free(new_name);
327  }
328}
329
330static gboolean poll_jack(gpointer data)
331{
332  update_load();
333  update_buffer_size();
334
335  return TRUE;
336}
337
338void control_proxy_on_studio_appeared(void)
339{
340  char * name;
341
342  if (!studio_proxy_get_name(&name))
343  {
344    lash_error("failed to get studio name");
345    goto exit;
346  }
347
348  if (g_studio_view != NULL)
349  {
350    lash_error("studio appear signal received but studio already exists");
351    goto free_name;
352  }
353
354  if (!create_view(name, SERVICE_NAME, STUDIO_OBJECT_PATH, false, &g_studio_view))
355  {
356    lash_error("create_view() failed for studio");
357    goto free_name;
358  }
359
360  gtk_widget_set_sensitive(g_menu_item_save_studio, true);
361  gtk_widget_set_sensitive(g_menu_item_rename_studio, true);
362  gtk_widget_set_sensitive(g_menu_item_create_room, true);
363  gtk_widget_set_sensitive(g_menu_item_destroy_room, true);
364  gtk_widget_set_sensitive(g_menu_item_load_project, true);
365  gtk_widget_set_sensitive(g_menu_item_start_app, true);
366
367free_name:
368  free(name);
369
370exit:
371  return;
372}
373
374void control_proxy_on_studio_disappeared(void)
375{
376  if (g_studio_view == NULL)
377  {
378    lash_error("studio disappear signal received but studio does not exists");
379    return;
380  }
381
382  gtk_widget_set_sensitive(g_menu_item_save_studio, false);
383  gtk_widget_set_sensitive(g_menu_item_rename_studio, false);
384  gtk_widget_set_sensitive(g_menu_item_create_room, false);
385  gtk_widget_set_sensitive(g_menu_item_destroy_room, false);
386  gtk_widget_set_sensitive(g_menu_item_load_project, false);
387  gtk_widget_set_sensitive(g_menu_item_start_app, false);
388
389  if (g_studio_view != NULL)
390  {
391    destroy_view(g_studio_view);
392    g_studio_view = NULL;
393  }
394}
395
396static void on_studio_renamed(const char * new_studio_name)
397{
398  if (g_studio_view != NULL)
399  {
400    set_view_name(g_studio_view, new_studio_name);
401  }
402}
403
404void jack_started(void)
405{
406  lash_info("JACK started");
407
408  gtk_widget_set_sensitive(g_buffer_size_combo, true);
409  gtk_widget_set_sensitive(g_clear_load_button, true);
410
411  g_jack_poll_source_tag = g_timeout_add(100, poll_jack, NULL);
412}
413
414void jack_stopped(void)
415{
416  lash_info("JACK stopped");
417
418  g_source_remove(g_jack_poll_source_tag);
419
420  gtk_widget_set_sensitive(g_buffer_size_combo, false);
421  buffer_size_clear();
422  gtk_widget_set_sensitive(g_clear_load_button, false);
423  gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(g_xrun_progress_bar), 0.0);
424}
425
426void jack_appeared(void)
427{
428  lash_info("JACK appeared");
429
430  if (!create_view("Raw JACK", JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH, true, &g_jack_view))
431  {
432    lash_error("create_view() failed for jack");
433    return;
434  }
435}
436
437void jack_disappeared(void)
438{
439  lash_info("JACK disappeared");
440
441  if (g_jack_view != NULL)
442  {
443    destroy_view(g_jack_view);
444    g_jack_view = NULL;
445  }
446}
447
448void
449set_main_window_title(
450  graph_view_handle view)
451{
452  char * title = catdup(get_view_name(view), " - LADI Session Handler");
453  gtk_window_set_title(GTK_WINDOW(g_main_win), title);
454  free(title);
455}
456
457static
458void
459init_studio_list(
460  struct studio_list * studio_list_ptr,
461  const char * menu_item,
462  const char * menu,
463  void (* item_activate_callback)(GtkWidget * item))
464{
465  studio_list_ptr->count = 0;
466  studio_list_ptr->menu_item = get_glade_widget(menu_item);
467  studio_list_ptr->menu = get_glade_widget(menu);
468  studio_list_ptr->item_activate_callback = item_activate_callback;
469  gtk_menu_item_set_submenu(GTK_MENU_ITEM(studio_list_ptr->menu_item), studio_list_ptr->menu);
470  g_signal_connect(G_OBJECT(studio_list_ptr->menu_item), "activate", G_CALLBACK(populate_studio_list_menu), studio_list_ptr);
471
472  lash_info("studio_list_ptr = %p", studio_list_ptr);
473  lash_info("studio_list_ptr->menu = %p", studio_list_ptr->menu);
474}
475
476int main(int argc, char** argv)
477{
478  gtk_init(&argc, &argv);
479
480  if (!canvas_init())
481  {
482    lash_error("Canvas initialization failed.");
483    return 1;
484  }
485
486  if (!init_glade())
487  {
488    return 1;
489  }
490
491  g_main_win = get_glade_widget("main_win");
492  g_clear_load_button = get_glade_widget("clear_load_button");
493  g_xrun_progress_bar = get_glade_widget("xrun_progress_bar");
494  g_buffer_size_combo = get_glade_widget("buffer_size_combo");
495  g_menu_item_save_studio = get_glade_widget("menu_item_save_studio");
496  g_menu_item_rename_studio = get_glade_widget("menu_item_rename_studio");
497  g_menu_item_create_room = get_glade_widget("menu_item_create_room");
498  g_menu_item_destroy_room = get_glade_widget("menu_item_destroy_room");
499  g_menu_item_load_project = get_glade_widget("menu_item_load_project");
500  g_menu_item_start_app = get_glade_widget("menu_item_start_app");
501
502  g_rename_dialog = get_glade_widget("rename_dialog");
503
504  init_studio_list(&g_load_studio_list, "menu_item_load_studio", "load_studio_menu", on_load_studio);
505  init_studio_list(&g_delete_studio_list, "menu_item_delete_studio", "delete_studio_menu", on_delete_studio);
506
507  world_tree_init();
508  view_init();
509
510  patchage_dbus_init();
511
512  if (!jack_proxy_init(jack_started, jack_stopped, jack_appeared, jack_disappeared))
513  {
514    return 1;
515  }
516
517  if (!control_proxy_init())
518  {
519    return 1;
520  }
521
522  if (!studio_proxy_init())
523  {
524    return 1;
525  }
526
527  studio_proxy_set_renamed_callback(on_studio_renamed);
528
529  set_buffer_size_combo_width();
530
531  g_signal_connect(G_OBJECT(g_main_win), "destroy", G_CALLBACK(gtk_main_quit), NULL);
532  g_signal_connect(G_OBJECT(get_glade_widget("menu_item_quit")), "activate", G_CALLBACK(gtk_main_quit), NULL);
533  g_signal_connect(G_OBJECT(g_buffer_size_combo), "changed", G_CALLBACK(buffer_size_change_request), NULL);
534  g_signal_connect(G_OBJECT(g_clear_load_button), "clicked", G_CALLBACK(clear_load), NULL);
535  g_signal_connect(G_OBJECT(get_glade_widget("menu_item_view_arrange")), "activate", G_CALLBACK(arrange), NULL);
536  g_signal_connect(G_OBJECT(g_menu_item_save_studio), "activate", G_CALLBACK(save_studio), NULL);
537  g_signal_connect(G_OBJECT(g_menu_item_rename_studio), "activate", G_CALLBACK(rename_studio), NULL);
538
539  gtk_widget_show(g_main_win);
540
541  //_about_win->set_transient_for(*_main_win);
542
543  gtk_main();
544
545  studio_proxy_uninit();
546  control_proxy_uninit();
547  uninit_glade();
548
549  return 0;
550}
Note: See TracBrowser for help on using the browser.