move catdup to common/
[ladish.git] / gui / graph_view.c
blobb616d2e044f935efa452596e601d2313fe856c1d
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009, 2010 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of the graph view object
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "common.h"
28 #include "graph_view.h"
29 #include "gtk_builder.h"
30 #include "world_tree.h"
31 #include "menu.h"
32 #include "../proxies/room_proxy.h"
33 #include "../common/catdup.h"
35 struct graph_view
37 struct list_head siblings;
38 char * view_name;
39 char * project_name;
40 char * full_name;
41 graph_canvas_handle graph_canvas;
42 graph_proxy_handle graph;
43 GtkWidget * canvas_widget;
44 ladish_app_supervisor_proxy_handle app_supervisor;
45 ladish_room_proxy_handle room;
48 struct list_head g_views;
50 GtkScrolledWindow * g_main_scrolledwin;
51 static struct graph_view * g_current_view;
52 GtkWidget * g_view_label;
54 const char * g_view_label_text =
55 "If you've started ladish for the first time, you should:\n\n"
56 " 1. Create a new studio (in the menu, Studio -> New Studio)\n"
57 " 2. Configure JACK (in the menu, Tools -> Configure JACK)\n"
58 " 3. Start the studio (in the menu, Studio -> Start Studio)\n"
59 " 4. Start apps (in the menu, Application -> Run)\n"
60 " 5. Connect their ports by click & drag on canvas\n"
61 " 6. Save the studio (in the menu, Studio -> Save Studio)\n";
63 void view_init(void)
65 g_main_scrolledwin = GTK_SCROLLED_WINDOW(get_gtk_builder_widget("main_scrolledwin"));
66 INIT_LIST_HEAD(&g_views);
68 g_view_label = gtk_label_new(g_view_label_text);
69 g_object_ref(g_view_label);
70 gtk_widget_show(g_view_label);
72 g_current_view = NULL;
73 gtk_scrolled_window_add_with_viewport(g_main_scrolledwin, g_view_label);
76 void announce_view_name_change(struct graph_view * view_ptr)
78 world_tree_name_changed((graph_view_handle)view_ptr);
80 if (g_current_view == view_ptr)
82 set_main_window_title((graph_view_handle)view_ptr);
86 static void detach_canvas(struct graph_view * view_ptr)
88 GtkWidget * child;
90 child = gtk_bin_get_child(GTK_BIN(g_main_scrolledwin));
91 if (child == view_ptr->canvas_widget)
93 gtk_container_remove(GTK_CONTAINER(g_main_scrolledwin), view_ptr->canvas_widget);
94 g_current_view = NULL;
95 gtk_widget_show(g_view_label);
96 gtk_scrolled_window_add_with_viewport(g_main_scrolledwin, g_view_label);
100 #define view_ptr ((struct graph_view *)context)
102 static void app_added(void * context, uint64_t id, const char * name, bool running, bool terminal, uint8_t level)
104 //log_info("app added. id=%"PRIu64", name='%s', %srunning, %s, level %u", id, name, running ? "" : "not ", terminal ? "terminal" : "shell", (unsigned int)level);
105 world_tree_add_app(context, id, name, running, terminal, level);
108 static void app_state_changed(void * context, uint64_t id, const char * name, bool running, bool terminal, uint8_t level)
110 //log_info("app state changed. id=%"PRIu64", name='%s', %srunning, %s, level %u", id, name, running ? "" : "not ", terminal ? "terminal" : "shell", (unsigned int)level);
111 world_tree_app_state_changed(context, id, name, running, terminal, level);
114 static void app_removed(void * context, uint64_t id)
116 //log_info("app removed. id=%"PRIu64, id);
117 world_tree_remove_app(context, id);
120 static void project_properties_changed(void * context, const char * project_dir, const char * project_name)
122 bool empty;
123 char * project_name_buffer;
124 char * full_name_buffer;
126 log_info("Room '%s' project properties changed. name='%s', dir='%s'", view_ptr->view_name, project_name, project_dir);
128 empty = strlen(project_name) == 0;
130 if (!empty)
132 project_name_buffer = strdup(project_name);
133 if (project_name_buffer == NULL)
135 return;
138 full_name_buffer = catdup4(view_ptr->view_name, " (", project_name, ")");
139 if (full_name_buffer == NULL)
141 free(project_name_buffer);
142 return;
145 if (view_ptr->full_name != NULL && view_ptr->full_name != view_ptr->view_name)
147 free(view_ptr->full_name);
150 if (view_ptr->project_name != NULL)
152 free(view_ptr->project_name);
155 view_ptr->full_name = full_name_buffer;
156 view_ptr->project_name = project_name_buffer;
158 else
160 if (view_ptr->full_name != NULL && view_ptr->full_name != view_ptr->view_name)
162 free(view_ptr->full_name);
165 if (view_ptr->project_name != NULL)
167 free(view_ptr->project_name);
170 view_ptr->full_name = view_ptr->view_name;
171 view_ptr->project_name = NULL;
174 announce_view_name_change(view_ptr);
177 #undef view_ptr
179 static void fill_canvas_menu(GtkMenu * menu)
181 fill_view_popup_menu(menu, (graph_view_handle)g_current_view);
184 bool
185 create_view(
186 const char * name,
187 const char * service,
188 const char * object,
189 bool graph_dict_supported,
190 bool app_supervisor_supported,
191 bool force_activate,
192 graph_view_handle * handle_ptr)
194 struct graph_view * view_ptr;
196 view_ptr = malloc(sizeof(struct graph_view));
197 if (view_ptr == NULL)
199 log_error("malloc() failed for struct graph_view");
200 goto fail;
203 view_ptr->view_name = strdup(name);
204 if (view_ptr->view_name == NULL)
206 log_error("strdup() failed for \"%s\"", name);
207 goto free_view;
210 view_ptr->app_supervisor = NULL;
211 view_ptr->room = NULL;
212 view_ptr->full_name = view_ptr->view_name;
213 view_ptr->project_name = NULL;
215 if (!graph_proxy_create(service, object, graph_dict_supported, &view_ptr->graph))
217 goto free_name;
220 if (!graph_canvas_create(1600 * 2, 1200 * 2, fill_canvas_menu, &view_ptr->graph_canvas))
222 goto destroy_graph;
225 if (!graph_canvas_attach(view_ptr->graph_canvas, view_ptr->graph))
227 goto destroy_graph_canvas;
230 view_ptr->canvas_widget = canvas_get_widget(graph_canvas_get_canvas(view_ptr->graph_canvas));
232 list_add_tail(&view_ptr->siblings, &g_views);
234 gtk_widget_show(view_ptr->canvas_widget);
236 world_tree_add((graph_view_handle)view_ptr, force_activate);
238 if (app_supervisor_supported)
240 if (!ladish_app_supervisor_proxy_create(service, object, view_ptr, app_added, app_state_changed, app_removed, &view_ptr->app_supervisor))
242 goto remove_from_world_tree;
246 if (strcmp(object, STUDIO_OBJECT_PATH) != 0 && strcmp(object, JACKDBUS_OBJECT_PATH) != 0) /* TODO: this is a quite lame way to detect room views */
248 if (!ladish_room_proxy_create(service, object, view_ptr, project_properties_changed, &view_ptr->room))
250 goto free_app_supervisor;
254 if (!graph_proxy_activate(view_ptr->graph))
256 goto free_room_proxy;
259 *handle_ptr = (graph_view_handle)view_ptr;
261 return true;
263 free_room_proxy:
264 if (view_ptr->room != NULL)
266 ladish_room_proxy_destroy(view_ptr->room);
268 free_app_supervisor:
269 if (view_ptr->app_supervisor != NULL)
271 ladish_app_supervisor_proxy_destroy(view_ptr->app_supervisor);
273 remove_from_world_tree:
274 list_del(&view_ptr->siblings);
275 if (!list_empty(&g_views))
277 world_tree_activate((graph_view_handle)list_entry(g_views.next, struct graph_view, siblings));
279 else
281 set_main_window_title(NULL);
284 detach_canvas(view_ptr);
286 world_tree_remove((graph_view_handle)view_ptr);
287 destroy_graph_canvas:
288 graph_canvas_destroy(view_ptr->graph_canvas);
289 destroy_graph:
290 graph_proxy_destroy(view_ptr->graph);
291 free_name:
292 if (view_ptr->full_name != NULL && view_ptr->full_name != view_ptr->view_name)
294 free(view_ptr->full_name);
296 if (view_ptr->project_name != NULL)
298 free(view_ptr->project_name);
300 free(view_ptr->view_name);
301 free_view:
302 free(view_ptr);
303 fail:
304 return false;
307 static void attach_canvas(struct graph_view * view_ptr)
309 GtkWidget * child;
311 child = gtk_bin_get_child(GTK_BIN(g_main_scrolledwin));
313 if (child == view_ptr->canvas_widget)
315 return;
318 if (child != NULL)
320 gtk_container_remove(GTK_CONTAINER(g_main_scrolledwin), child);
323 g_current_view = view_ptr;
324 gtk_container_add(GTK_CONTAINER(g_main_scrolledwin), view_ptr->canvas_widget);
326 //_main_scrolledwin->property_hadjustment().get_value()->set_step_increment(10);
327 //_main_scrolledwin->property_vadjustment().get_value()->set_step_increment(10);
330 #define view_ptr ((struct graph_view *)view)
332 void destroy_view(graph_view_handle view)
334 list_del(&view_ptr->siblings);
335 if (!list_empty(&g_views))
337 world_tree_activate((graph_view_handle)list_entry(g_views.next, struct graph_view, siblings));
339 else
341 set_main_window_title(NULL);
344 detach_canvas(view_ptr);
346 world_tree_remove(view);
348 graph_canvas_detach(view_ptr->graph_canvas);
349 graph_canvas_destroy(view_ptr->graph_canvas);
350 graph_proxy_destroy(view_ptr->graph);
352 if (view_ptr->app_supervisor != NULL)
354 ladish_app_supervisor_proxy_destroy(view_ptr->app_supervisor);
357 if (view_ptr->room != NULL)
359 ladish_room_proxy_destroy(view_ptr->room);
362 if (view_ptr->full_name != NULL && view_ptr->full_name != view_ptr->view_name)
364 free(view_ptr->full_name);
366 if (view_ptr->project_name != NULL)
368 free(view_ptr->project_name);
370 free(view_ptr->view_name);
372 free(view_ptr);
375 void activate_view(graph_view_handle view)
377 attach_canvas(view_ptr);
378 set_main_window_title(view);
379 menu_view_activated(is_room_view(view));
382 const char * get_view_name(graph_view_handle view)
384 return view_ptr->full_name;
387 const char * get_view_opath(graph_view_handle view)
389 return graph_proxy_get_object(view_ptr->graph);
392 bool set_view_name(graph_view_handle view, const char * name)
394 char * view_name_buffer;
395 char * full_name_buffer;
397 view_name_buffer = strdup(name);
398 if (view_name_buffer == NULL)
400 log_error("strdup() failed for \"%s\"", name);
401 return false;
404 if (view_ptr->project_name != NULL)
406 full_name_buffer = catdup4(view_name_buffer, " (", view_ptr->project_name, ")");
407 if (full_name_buffer == NULL)
409 free(view_name_buffer);
410 return false;
413 else
415 full_name_buffer = view_name_buffer;
418 if (view_ptr->full_name != NULL && view_ptr->full_name != view_ptr->view_name)
420 free(view_ptr->full_name);
423 free(view_ptr->view_name);
425 view_ptr->view_name = view_name_buffer;
426 view_ptr->full_name = full_name_buffer;
428 announce_view_name_change(view_ptr);
430 return true;
433 canvas_handle get_current_canvas(void)
435 if (g_current_view == NULL)
437 return NULL;
440 return graph_canvas_get_canvas(g_current_view->graph_canvas);
443 const char * get_current_view_room_name(void)
445 if (g_current_view == NULL || !is_room_view((graph_view_handle)g_current_view))
447 return NULL;
450 return g_current_view->view_name;
453 graph_view_handle get_current_view(void)
455 return (graph_view_handle)g_current_view;
458 bool is_room_view(graph_view_handle view)
460 return view_ptr->room != NULL;
463 bool app_run_custom(graph_view_handle view, const char * command, const char * name, bool run_in_terminal, uint8_t level)
465 return ladish_app_supervisor_proxy_run_custom(view_ptr->app_supervisor, command, name, run_in_terminal, level);
468 ladish_app_supervisor_proxy_handle graph_view_get_app_supervisor(graph_view_handle view)
470 return view_ptr->app_supervisor;
473 ladish_room_proxy_handle graph_view_get_room(graph_view_handle view)
475 return view_ptr->room;