ladishd: fix hidden connection save. Fix for #151
[ladish.git] / gui / graph_canvas.c
blob3fbd6922c1782d5ab38fa74ef0f94eefe1b79dfc
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 graph canvas 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 <locale.h>
29 #include "graph_canvas.h"
30 #include "../dbus_constants.h"
31 #include "../common/catdup.h"
33 struct graph_canvas
35 graph_proxy_handle graph;
36 canvas_handle canvas;
37 struct list_head clients;
40 struct client
42 struct list_head siblings;
43 uint64_t id;
44 canvas_module_handle canvas_module;
45 struct list_head ports;
46 struct graph_canvas * owner_ptr;
49 struct port
51 struct list_head siblings;
52 uint64_t id;
53 canvas_port_handle canvas_port;
54 struct graph_canvas * graph_canvas;
57 static
58 struct client *
59 find_client(
60 struct graph_canvas * graph_canvas_ptr,
61 uint64_t id)
63 struct list_head * node_ptr;
64 struct client * client_ptr;
66 list_for_each(node_ptr, &graph_canvas_ptr->clients)
68 client_ptr = list_entry(node_ptr, struct client, siblings);
69 if (client_ptr->id == id)
71 return client_ptr;
75 return NULL;
78 static
79 struct port *
80 find_port(
81 struct client * client_ptr,
82 uint64_t id)
84 struct list_head * node_ptr;
85 struct port * port_ptr;
87 list_for_each(node_ptr, &client_ptr->ports)
89 port_ptr = list_entry(node_ptr, struct port, siblings);
90 if (port_ptr->id == id)
92 return port_ptr;
96 return NULL;
99 #define port1_ptr ((struct port *)port1_context)
100 #define port2_ptr ((struct port *)port2_context)
102 static
103 void
104 connect_request(
105 void * port1_context,
106 void * port2_context)
108 log_info("connect request(%"PRIu64", %"PRIu64")", port1_ptr->id, port2_ptr->id);
110 ASSERT(port1_ptr->graph_canvas == port2_ptr->graph_canvas);
112 graph_proxy_connect_ports(port1_ptr->graph_canvas->graph, port1_ptr->id, port2_ptr->id);
115 void
116 disconnect_request(
117 void * port1_context,
118 void * port2_context)
120 log_info("disconnect request(%"PRIu64", %"PRIu64")", port1_ptr->id, port2_ptr->id);
122 ASSERT(port1_ptr->graph_canvas == port2_ptr->graph_canvas);
124 graph_proxy_disconnect_ports(port1_ptr->graph_canvas->graph, port1_ptr->id, port2_ptr->id);
127 #undef port1_ptr
128 #undef port2_ptr
130 #define client_ptr ((struct client *)module_context)
132 void
133 module_location_changed(
134 void * module_context,
135 double x,
136 double y)
138 char x_str[100];
139 char y_str[100];
140 char * locale;
142 log_info("module_location_changed(id = %3llu, x = %6.1f, y = %6.1f)", (unsigned long long)client_ptr->id, x, y);
144 locale = strdup(setlocale(LC_NUMERIC, NULL));
145 if (locale == NULL)
147 log_error("strdup() failed for locale string");
148 return;
151 setlocale(LC_NUMERIC, "POSIX");
152 sprintf(x_str, "%f", x);
153 sprintf(y_str, "%f", y);
154 setlocale(LC_NUMERIC, locale);
155 free(locale);
157 graph_proxy_dict_entry_set(
158 client_ptr->owner_ptr->graph,
159 GRAPH_DICT_OBJECT_TYPE_CLIENT,
160 client_ptr->id,
161 URI_CANVAS_X,
162 x_str);
164 graph_proxy_dict_entry_set(
165 client_ptr->owner_ptr->graph,
166 GRAPH_DICT_OBJECT_TYPE_CLIENT,
167 client_ptr->id,
168 URI_CANVAS_Y,
169 y_str);
172 #undef client_ptr
174 bool
175 graph_canvas_create(
176 int width,
177 int height,
178 void (* fill_canvas_menu)(GtkMenu * menu),
179 graph_canvas_handle * graph_canvas_handle_ptr)
181 struct graph_canvas * graph_canvas_ptr;
183 graph_canvas_ptr = malloc(sizeof(struct graph_canvas));
184 if (graph_canvas_ptr == NULL)
186 return false;
189 if (!canvas_create(
190 width,
191 height,
192 connect_request,
193 disconnect_request,
194 module_location_changed,
195 fill_canvas_menu,
196 NULL,
197 NULL,
198 &graph_canvas_ptr->canvas))
200 free(graph_canvas_ptr);
201 return false;
204 graph_canvas_ptr->graph = NULL;
205 INIT_LIST_HEAD(&graph_canvas_ptr->clients);
207 *graph_canvas_handle_ptr = (graph_canvas_handle)graph_canvas_ptr;
209 return true;
212 #define graph_canvas_ptr ((struct graph_canvas *)graph_canvas)
214 static
215 void
216 clear(
217 void * graph_canvas)
219 log_info("canvas::clear()");
220 canvas_clear(graph_canvas_ptr->canvas);
223 static
224 void
225 client_appeared(
226 void * graph_canvas,
227 uint64_t id,
228 const char * name)
230 struct client * client_ptr;
231 char * x_str;
232 char * y_str;
233 double x;
234 double y;
235 char * locale;
236 double width;
237 double height;
239 log_info("canvas::client_appeared(%"PRIu64", \"%s\")", id, name);
241 canvas_get_size(graph_canvas_ptr->canvas, &width, &height);
242 //log_debug("width %f, height %f", width, height);
244 client_ptr = malloc(sizeof(struct client));
245 if (client_ptr == NULL)
247 log_error("allocation of memory for struct client failed");
248 return;
251 client_ptr->id = id;
252 INIT_LIST_HEAD(&client_ptr->ports);
253 client_ptr->owner_ptr = graph_canvas_ptr;
255 x = 0;
256 y = 0;
258 if (!graph_proxy_dict_entry_get(
259 client_ptr->owner_ptr->graph,
260 GRAPH_DICT_OBJECT_TYPE_CLIENT,
262 URI_CANVAS_X,
263 &x_str))
265 x_str = NULL;
266 x = width / 2 - 200 + rand() % 300;
269 if (!graph_proxy_dict_entry_get(
270 client_ptr->owner_ptr->graph,
271 GRAPH_DICT_OBJECT_TYPE_CLIENT,
273 URI_CANVAS_Y,
274 &y_str))
276 y_str = NULL;
277 y = height / 2 - 200 + rand() % 300;
280 if (x_str != NULL || y_str != NULL)
282 locale = strdup(setlocale(LC_NUMERIC, NULL));
283 if (locale == NULL)
285 log_error("strdup() failed for locale string");
287 else
289 setlocale(LC_NUMERIC, "POSIX");
290 if (x_str != NULL)
292 //log_info("converting %s", x_str);
293 sscanf(x_str, "%lf", &x);
295 if (y_str != NULL)
297 //log_info("converting %s", y_str);
298 sscanf(y_str, "%lf", &y);
300 setlocale(LC_NUMERIC, locale);
301 free(locale);
304 if (x_str != NULL)
306 free(x_str);
309 if (y_str != NULL)
311 free(y_str);
315 if (!canvas_create_module(graph_canvas_ptr->canvas, name, x, y, true, true, client_ptr, &client_ptr->canvas_module))
317 log_error("canvas_create_module(\"%s\") failed", name);
318 free(client_ptr);
319 return;
322 if (x_str == NULL || y_str == NULL)
323 { /* we have generated random value, store it */
324 module_location_changed(client_ptr, x, y);
327 list_add_tail(&client_ptr->siblings, &graph_canvas_ptr->clients);
330 static
331 void
332 client_disappeared(
333 void * graph_canvas,
334 uint64_t id)
336 struct client * client_ptr;
338 log_info("canvas::client_disappeared(%"PRIu64")", id);
340 client_ptr = find_client(graph_canvas_ptr, id);
341 if (client_ptr == NULL)
343 log_error("cannot find disappearing client %"PRIu64"", id);
344 return;
347 list_del(&client_ptr->siblings);
348 canvas_destroy_module(graph_canvas_ptr->canvas, client_ptr->canvas_module);
349 free(client_ptr);
352 static void client_renamed(void * graph_canvas, uint64_t id, const char * old_name, const char * new_name)
354 struct client * client_ptr;
356 log_info("canvas::client_renamed(%"PRIu64", '%s', '%s')", id, old_name, new_name);
358 client_ptr = find_client(graph_canvas_ptr, id);
359 if (client_ptr == NULL)
361 log_error("cannot find renamed client %"PRIu64, id);
362 return;
365 canvas_set_module_name(client_ptr->canvas_module, new_name);
368 static
369 void
370 port_appeared(
371 void * graph_canvas,
372 uint64_t client_id,
373 uint64_t port_id,
374 const char * port_name,
375 bool is_input,
376 bool is_terminal,
377 bool is_midi)
379 int color;
380 struct client * client_ptr;
381 struct port * port_ptr;
382 char * value;
383 char * name_override;
385 log_info("canvas::port_appeared(%"PRIu64", %"PRIu64", \"%s\")", client_id, port_id, port_name);
387 client_ptr = find_client(graph_canvas_ptr, client_id);
388 if (client_ptr == NULL)
390 log_error("cannot find client %"PRIu64" of appearing port %"PRIu64" \"%s\"", client_id, port_id, port_name);
391 return;
394 port_ptr = malloc(sizeof(struct port));
395 if (port_ptr == NULL)
397 log_error("allocation of memory for struct port failed");
398 return;
401 port_ptr->id = port_id;
402 port_ptr->graph_canvas = graph_canvas_ptr;
404 // Darkest tango palette colour, with S -= 6, V -= 6, w/ transparency
405 if (is_midi)
407 color = 0x960909C0;
409 else
411 color = 0x244678C0;
414 if (!graph_proxy_dict_entry_get(
415 client_ptr->owner_ptr->graph,
416 GRAPH_DICT_OBJECT_TYPE_PORT,
417 port_id,
418 URI_A2J_PORT,
419 &value))
421 name_override = NULL;
423 else
425 if (strcmp(value, "yes") == 0)
427 name_override = catdup(port_name, " (a2j)");
428 if (name_override != NULL)
430 port_name = name_override;
433 else
435 name_override = NULL;
438 free(value);
441 if (!canvas_create_port(graph_canvas_ptr->canvas, client_ptr->canvas_module, port_name, is_input, color, port_ptr, &port_ptr->canvas_port))
443 log_error("canvas_create_port(\"%s\") failed", port_name);
444 free(port_ptr);
445 free(name_override);
446 return;
449 list_add_tail(&port_ptr->siblings, &client_ptr->ports);
451 free(name_override);
454 static
455 void
456 port_disappeared(
457 void * graph_canvas,
458 uint64_t client_id,
459 uint64_t port_id)
461 struct client * client_ptr;
462 struct port * port_ptr;
464 log_info("canvas::port_disappeared(%"PRIu64", %"PRIu64")", client_id, port_id);
466 client_ptr = find_client(graph_canvas_ptr, client_id);
467 if (client_ptr == NULL)
469 log_error("cannot find client %"PRIu64" of disappearing port %"PRIu64"", client_id, port_id);
470 return;
473 port_ptr = find_port(client_ptr, port_id);
474 if (client_ptr == NULL)
476 log_error("cannot find disappearing port %"PRIu64" of client %"PRIu64"", port_id, client_id);
477 return;
480 list_del(&port_ptr->siblings);
481 canvas_destroy_port(graph_canvas_ptr->canvas, port_ptr->canvas_port);
482 free(port_ptr);
485 static
486 void
487 port_renamed(
488 void * graph_canvas,
489 uint64_t client_id,
490 uint64_t port_id,
491 const char * old_port_name,
492 const char * new_port_name)
494 struct client * client_ptr;
495 struct port * port_ptr;
497 log_info("canvas::port_renamed(%"PRIu64", %"PRIu64", '%s', '%s')", client_id, port_id, old_port_name, new_port_name);
499 client_ptr = find_client(graph_canvas_ptr, client_id);
500 if (client_ptr == NULL)
502 log_error("cannot find client %"PRIu64" of renamed port %"PRIu64"", client_id, port_id);
503 return;
506 port_ptr = find_port(client_ptr, port_id);
507 if (client_ptr == NULL)
509 log_error("cannot find renamed port %"PRIu64" of client %"PRIu64"", port_id, client_id);
510 return;
513 canvas_set_port_name(port_ptr->canvas_port, new_port_name);
516 static
517 void
518 ports_connected(
519 void * graph_canvas,
520 uint64_t client1_id,
521 uint64_t port1_id,
522 uint64_t client2_id,
523 uint64_t port2_id)
525 struct client * client1_ptr;
526 struct port * port1_ptr;
527 struct client * client2_ptr;
528 struct port * port2_ptr;
530 log_info("canvas::ports_connected(%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64")", client1_id, port1_id, client2_id, port2_id);
532 client1_ptr = find_client(graph_canvas_ptr, client1_id);
533 if (client1_ptr == NULL)
535 log_error("cannot find client %"PRIu64" of connected port %"PRIu64"", client1_id, port1_id);
536 return;
539 port1_ptr = find_port(client1_ptr, port1_id);
540 if (client1_ptr == NULL)
542 log_error("cannot find connected port %"PRIu64" of client %"PRIu64"", port1_id, client1_id);
543 return;
546 client2_ptr = find_client(graph_canvas_ptr, client2_id);
547 if (client2_ptr == NULL)
549 log_error("cannot find client %"PRIu64" of connected port %"PRIu64"", client2_id, port2_id);
550 return;
553 port2_ptr = find_port(client2_ptr, port2_id);
554 if (client2_ptr == NULL)
556 log_error("cannot find connected port %"PRIu64" of client %"PRIu64"", port2_id, client2_id);
557 return;
560 canvas_add_connection(
561 graph_canvas_ptr->canvas,
562 port1_ptr->canvas_port,
563 port2_ptr->canvas_port,
564 canvas_get_port_color(port1_ptr->canvas_port) + 0x22222200);
567 static
568 void
569 ports_disconnected(
570 void * graph_canvas,
571 uint64_t client1_id,
572 uint64_t port1_id,
573 uint64_t client2_id,
574 uint64_t port2_id)
576 struct client * client1_ptr;
577 struct port * port1_ptr;
578 struct client * client2_ptr;
579 struct port * port2_ptr;
581 log_info("canvas::ports_disconnected(%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64")", client1_id, port1_id, client2_id, port2_id);
583 client1_ptr = find_client(graph_canvas_ptr, client1_id);
584 if (client1_ptr == NULL)
586 log_error("cannot find client %"PRIu64" of disconnected port %"PRIu64"", client1_id, port1_id);
587 return;
590 port1_ptr = find_port(client1_ptr, port1_id);
591 if (client1_ptr == NULL)
593 log_error("cannot find disconnected port %"PRIu64" of client %"PRIu64"", port1_id, client1_id);
594 return;
597 client2_ptr = find_client(graph_canvas_ptr, client2_id);
598 if (client2_ptr == NULL)
600 log_error("cannot find client %"PRIu64" of disconnected port %"PRIu64"", client2_id, port2_id);
601 return;
604 port2_ptr = find_port(client2_ptr, port2_id);
605 if (client2_ptr == NULL)
607 log_error("cannot find disconnected port %"PRIu64" of client %"PRIu64"", port2_id, client2_id);
608 return;
611 canvas_remove_connection(
612 graph_canvas_ptr->canvas,
613 port1_ptr->canvas_port,
614 port2_ptr->canvas_port);
617 void
618 graph_canvas_destroy(
619 graph_canvas_handle graph_canvas)
621 if (graph_canvas_ptr->graph != NULL)
623 graph_canvas_detach(graph_canvas);
626 free(graph_canvas_ptr);
629 bool
630 graph_canvas_attach(
631 graph_canvas_handle graph_canvas,
632 graph_proxy_handle graph)
634 ASSERT(graph_canvas_ptr->graph == NULL);
636 if (!graph_proxy_attach(
637 graph,
638 graph_canvas,
639 clear,
640 client_appeared,
641 client_renamed,
642 client_disappeared,
643 port_appeared,
644 port_renamed,
645 port_disappeared,
646 ports_connected,
647 ports_disconnected))
649 return false;
652 graph_canvas_ptr->graph = graph;
654 return true;
657 void
658 graph_canvas_detach(
659 graph_canvas_handle graph_canvas)
661 ASSERT(graph_canvas_ptr->graph != NULL);
662 graph_proxy_detach(graph_canvas_ptr->graph, graph_canvas);
663 graph_canvas_ptr->graph = NULL;
666 canvas_handle
667 graph_canvas_get_canvas(
668 graph_canvas_handle graph_canvas)
670 return graph_canvas_ptr->canvas;