gladish: canvas zoom functionality. Fixes #66
[ladish.git] / daemon / save.c
bloba3f73c140a617c4a9a7afb203b6968b41a2004dd
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2010 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation save releated helper functions
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 <unistd.h>
29 #include "save.h"
30 #include "escape.h"
31 #include "studio.h"
33 bool ladish_write_string(int fd, const char * string)
35 size_t len;
36 ssize_t ret;
38 len = strlen(string);
40 ret = write(fd, string, len);
41 if (ret == -1)
43 log_error("write(%d, \"%s\", %zu) failed to write config file: %d (%s)", fd, string, len, errno, strerror(errno));
44 return false;
46 if ((size_t)ret != len)
48 log_error("write() wrote wrong byte count to config file (%zd != %zu).", ret, len);
49 return false;
52 return true;
55 bool ladish_write_indented_string(int fd, int indent, const char * string)
57 ASSERT(indent >= 0);
58 while (indent--)
60 if (!ladish_write_string(fd, LADISH_XML_BASE_INDENT))
62 return false;
66 if (!ladish_write_string(fd, string))
68 return false;
71 return true;
74 #define fd (((struct ladish_write_context *)context)->fd)
75 #define indent (((struct ladish_write_context *)context)->indent)
77 static
78 bool
79 write_dict_entry(
80 void * context,
81 const char * key,
82 const char * value)
84 if (!ladish_write_indented_string(fd, indent, "<key name=\""))
86 return false;
89 if (!ladish_write_string(fd, key))
91 return false;
94 if (!ladish_write_string(fd, "\">"))
96 return false;
99 if (!ladish_write_string(fd, value))
101 return false;
104 if (!ladish_write_string(fd, "</key>\n"))
106 return false;
109 return true;
112 static
113 bool
114 ladish_save_vgraph_client_begin(
115 void * context,
116 ladish_graph_handle graph,
117 ladish_client_handle client_handle,
118 const char * client_name,
119 void ** client_iteration_context_ptr_ptr)
121 uuid_t uuid;
122 char str[37];
124 ladish_client_get_uuid(client_handle, uuid);
125 uuid_unparse(uuid, str);
127 log_info("saving vgraph client '%s' (%s)", client_name, str);
129 if (!ladish_write_indented_string(fd, indent, "<client name=\""))
131 return false;
134 if (!ladish_write_string(fd, client_name))
136 return false;
139 if (!ladish_write_string(fd, "\" uuid=\""))
141 return false;
144 if (!ladish_write_string(fd, str))
146 return false;
149 if (!ladish_write_string(fd, "\">\n"))
151 return false;
154 if (!ladish_write_indented_string(fd, indent + 1, "<ports>\n"))
156 return false;
159 return true;
162 static
163 bool
164 ladish_save_vgraph_client_end(
165 void * context,
166 ladish_graph_handle graph,
167 ladish_client_handle client_handle,
168 const char * client_name,
169 void * client_iteration_context_ptr)
171 if (!ladish_write_indented_string(fd, indent + 1, "</ports>\n"))
173 return false;
176 if (!ladish_write_dict(fd, indent + 1, ladish_client_get_dict(client_handle)))
178 return false;
181 if (!ladish_write_indented_string(fd, indent, "</client>\n"))
183 return false;
186 return true;
189 static bool ladish_get_vgraph_port_uuids(ladish_graph_handle vgraph, ladish_port_handle port, uuid_t uuid, uuid_t link_uuid)
191 bool link;
193 if (vgraph != ladish_studio_get_studio_graph())
195 link = false; /* room ports are saved using their fixed uuids */
197 else
199 link = ladish_port_is_link(port);
200 if (link)
202 /* get the generated port uuid that is used for identification in the virtual graph */
203 ladish_graph_get_port_uuid(vgraph, port, uuid);
207 if (!link || link_uuid != NULL)
209 /* get the real port uuid that is same in both room and studio graphs */
210 ladish_port_get_uuid(port, link ? link_uuid : uuid);
213 return link;
216 static
217 bool
218 ladish_save_vgraph_port(
219 void * context,
220 ladish_graph_handle graph,
221 void * client_iteration_context_ptr,
222 ladish_client_handle client_handle,
223 const char * client_name,
224 ladish_port_handle port_handle,
225 const char * port_name,
226 uint32_t port_type,
227 uint32_t port_flags)
229 uuid_t uuid;
230 bool link;
231 uuid_t link_uuid;
232 char str[37];
233 char link_str[37];
234 ladish_dict_handle dict;
236 link = ladish_get_vgraph_port_uuids(graph, port_handle, uuid, link_uuid);
237 uuid_unparse(uuid, str);
238 if (link)
240 uuid_unparse(link_uuid, link_str);
241 log_info("saving vgraph link port '%s':'%s' (%s link=%s)", client_name, port_name, str, link_str);
243 else
245 log_info("saving vgraph port '%s':'%s' (%s)", client_name, port_name, str);
248 if (!ladish_write_indented_string(fd, indent + 2, "<port name=\""))
250 return false;
253 if (!ladish_write_string(fd, port_name))
255 return false;
258 if (!ladish_write_string(fd, "\" uuid=\""))
260 return false;
263 if (!ladish_write_string(fd, str))
265 return false;
268 if (link)
270 if (!ladish_write_string(fd, "\" link_uuid=\""))
272 return false;
275 if (!ladish_write_string(fd, link_str))
277 return false;
281 dict = ladish_port_get_dict(port_handle);
282 if (ladish_dict_is_empty(dict))
284 if (!ladish_write_string(fd, "\" />\n"))
286 return false;
289 else
291 if (!ladish_write_string(fd, "\">\n"))
293 return false;
296 if (!ladish_write_dict(fd, indent + 3, dict))
298 return false;
301 if (!ladish_write_indented_string(fd, indent + 2, "</port>\n"))
303 return false;
307 return true;
310 static
311 bool
312 ladish_save_vgraph_connection(
313 void * context,
314 ladish_graph_handle graph,
315 ladish_port_handle port1_handle,
316 ladish_port_handle port2_handle,
317 ladish_dict_handle dict)
319 uuid_t uuid;
320 char str[37];
322 log_info("saving vgraph connection");
324 if (!ladish_write_indented_string(fd, indent, "<connection port1=\""))
326 return false;
329 ladish_get_vgraph_port_uuids(graph, port1_handle, uuid, NULL);
330 uuid_unparse(uuid, str);
332 if (!ladish_write_string(fd, str))
334 return false;
337 if (!ladish_write_string(fd, "\" port2=\""))
339 return false;
342 ladish_get_vgraph_port_uuids(graph, port2_handle, uuid, NULL);
343 uuid_unparse(uuid, str);
345 if (!ladish_write_string(fd, str))
347 return false;
350 if (ladish_dict_is_empty(dict))
352 if (!ladish_write_string(fd, "\" />\n"))
354 return false;
357 else
359 if (!ladish_write_string(fd, "\">\n"))
361 return false;
364 if (!ladish_write_dict(fd, indent + 1, dict))
366 return false;
369 if (!ladish_write_indented_string(fd, indent, "</connection>\n"))
371 return false;
375 return true;
378 static
379 bool
380 ladish_save_app(
381 void * context,
382 const char * name,
383 bool running,
384 const char * command,
385 bool terminal,
386 uint8_t level,
387 pid_t pid,
388 const uuid_t uuid)
390 char buf[100];
391 const char * unescaped_string;
392 char * escaped_string;
393 char * escaped_buffer;
394 bool ret;
396 log_info("saving app: name='%s', %srunning, %s, level %u, commandline='%s'", name, running ? "" : "not ", terminal ? "terminal" : "shell", (unsigned int)level, command);
398 ret = false;
400 escaped_buffer = malloc(ladish_max(strlen(name), strlen(command)) * 3 + 1); /* encode each char in three bytes (percent encoding) */
401 if (escaped_buffer == NULL)
403 log_error("malloc() failed.");
404 goto exit;
407 if (!ladish_write_indented_string(fd, indent, "<application name=\""))
409 goto free_buffer;
412 unescaped_string = name;
413 escaped_string = escaped_buffer;
414 escape(&unescaped_string, &escaped_string);
415 *escaped_string = 0;
416 if (!ladish_write_string(fd, escaped_buffer))
418 goto free_buffer;
421 if (!ladish_write_string(fd, "\" terminal=\""))
423 goto free_buffer;
426 if (!ladish_write_string(fd, terminal ? "true" : "false"))
428 goto free_buffer;
431 if (!ladish_write_string(fd, "\" level=\""))
433 goto free_buffer;
436 sprintf(buf, "%u", (unsigned int)level);
438 if (!ladish_write_string(fd, buf))
440 goto free_buffer;
443 if (!ladish_write_string(fd, "\" autorun=\""))
445 goto free_buffer;
448 if (!ladish_write_string(fd, running ? "true" : "false"))
450 goto free_buffer;
453 if (!ladish_write_string(fd, "\">"))
455 goto free_buffer;
458 unescaped_string = command;
459 escaped_string = escaped_buffer;
460 escape(&unescaped_string, &escaped_string);
461 *escaped_string = 0;
462 if (!ladish_write_string(fd, escaped_buffer))
464 goto free_buffer;
467 if (!ladish_write_string(fd, "</application>\n"))
469 goto free_buffer;
472 ret = true;
474 free_buffer:
475 free(escaped_buffer);
477 exit:
478 return ret;
481 static
482 bool
483 ladish_write_room_port(
484 void * context,
485 ladish_port_handle port,
486 const char * name,
487 uint32_t type,
488 uint32_t flags)
490 uuid_t uuid;
491 char str[37];
492 bool midi;
493 const char * type_str;
494 bool playback;
495 const char * direction_str;
496 ladish_dict_handle dict;
498 ladish_port_get_uuid(port, uuid);
499 uuid_unparse(uuid, str);
501 playback = (flags & JACKDBUS_PORT_FLAG_INPUT) != 0;
502 ASSERT(playback || (flags & JACKDBUS_PORT_FLAG_OUTPUT) != 0); /* playback or capture */
503 ASSERT(!(playback && (flags & JACKDBUS_PORT_FLAG_OUTPUT) != 0)); /* but not both */
504 direction_str = playback ? "playback" : "capture";
506 midi = type == JACKDBUS_PORT_TYPE_MIDI;
507 ASSERT(midi || type == JACKDBUS_PORT_TYPE_AUDIO); /* midi or audio */
508 ASSERT(!(midi && type == JACKDBUS_PORT_TYPE_AUDIO)); /* but not both */
509 type_str = midi ? "midi" : "audio";
511 log_info("saving room %s %s port '%s' (%s)", direction_str, type_str, name, str);
513 if (!ladish_write_indented_string(fd, indent, "<port name=\""))
515 return false;
518 if (!ladish_write_string(fd, name))
520 return false;
523 if (!ladish_write_string(fd, "\" uuid=\""))
525 return false;
528 if (!ladish_write_string(fd, str))
530 return false;
533 if (!ladish_write_string(fd, "\" type=\""))
535 return false;
538 if (!ladish_write_string(fd, type_str))
540 return false;
543 if (!ladish_write_string(fd, "\" direction=\""))
545 return false;
548 if (!ladish_write_string(fd, direction_str))
550 return false;
553 dict = ladish_port_get_dict(port);
554 if (ladish_dict_is_empty(dict))
556 if (!ladish_write_string(fd, "\" />\n"))
558 return false;
561 else
563 if (!ladish_write_string(fd, "\">\n"))
565 return false;
568 if (!ladish_write_dict(fd, indent + 1, dict))
570 return false;
573 if (!ladish_write_indented_string(fd, indent, "</port>\n"))
575 return false;
579 return true;
582 static
583 bool
584 ladish_save_jack_client_begin(
585 void * context,
586 ladish_graph_handle graph_handle,
587 ladish_client_handle client_handle,
588 const char * client_name,
589 void ** client_iteration_context_ptr_ptr)
591 uuid_t uuid;
592 char str[37];
594 ladish_client_get_uuid(client_handle, uuid);
595 uuid_unparse(uuid, str);
597 log_info("saving jack client '%s' (%s)", client_name, str);
599 if (!ladish_write_indented_string(fd, indent, "<client name=\""))
601 return false;
604 if (!ladish_write_string(fd, client_name))
606 return false;
609 if (!ladish_write_string(fd, "\" uuid=\""))
611 return false;
614 if (!ladish_write_string(fd, str))
616 return false;
619 if (!ladish_write_string(fd, "\">\n"))
621 return false;
624 if (!ladish_write_indented_string(fd, indent + 1, "<ports>\n"))
626 return false;
629 return true;
632 static
633 bool
634 ladish_save_jack_client_end(
635 void * context,
636 ladish_graph_handle graph_handle,
637 ladish_client_handle client_handle,
638 const char * client_name,
639 void * client_iteration_context_ptr)
641 if (!ladish_write_indented_string(fd, indent + 1, "</ports>\n"))
643 return false;
646 if (!ladish_write_indented_string(fd, indent, "</client>\n"))
648 return false;
651 return true;
654 static
655 bool
656 ladish_save_jack_port(
657 void * context,
658 ladish_graph_handle graph_handle,
659 void * client_iteration_context_ptr,
660 ladish_client_handle client_handle,
661 const char * client_name,
662 ladish_port_handle port_handle,
663 const char * port_name,
664 uint32_t port_type,
665 uint32_t port_flags)
667 uuid_t uuid;
668 char str[37];
670 ladish_port_get_uuid(port_handle, uuid);
671 uuid_unparse(uuid, str);
673 log_info("saving jack port '%s':'%s' (%s)", client_name, port_name, str);
675 if (!ladish_write_indented_string(fd, indent + 2, "<port name=\""))
677 return false;
680 if (!ladish_write_string(fd, port_name))
682 return false;
685 if (!ladish_write_string(fd, "\" uuid=\""))
687 return false;
690 if (!ladish_write_string(fd, str))
692 return false;
695 if (!ladish_write_string(fd, "\" />\n"))
697 return false;
700 return true;
703 #undef indent
704 #undef fd
706 bool ladish_write_dict(int fd, int indent, ladish_dict_handle dict)
708 struct ladish_write_context context;
710 if (ladish_dict_is_empty(dict))
712 return true;
715 context.fd = fd;
716 context.indent = indent + 1;
718 if (!ladish_write_indented_string(fd, indent, "<dict>\n"))
720 return false;
723 if (!ladish_dict_iterate(dict, &context, write_dict_entry))
725 return false;
728 if (!ladish_write_indented_string(fd, indent, "</dict>\n"))
730 return false;
733 return true;
736 bool ladish_write_vgraph(int fd, int indent, ladish_graph_handle vgraph, ladish_app_supervisor_handle app_supervisor)
738 struct ladish_write_context context;
740 context.fd = fd;
741 context.indent = indent + 1;
743 if (!ladish_write_indented_string(fd, indent, "<clients>\n"))
745 return false;
748 if (!ladish_graph_iterate_nodes(
749 vgraph,
750 true,
751 NULL,
752 &context,
753 ladish_save_vgraph_client_begin,
754 ladish_save_vgraph_port,
755 ladish_save_vgraph_client_end))
757 log_error("ladish_graph_iterate_nodes() failed");
758 return false;
761 if (!ladish_write_indented_string(fd, indent, "</clients>\n"))
763 return false;
766 if (!ladish_write_indented_string(fd, indent, "<connections>\n"))
768 return false;
771 if (!ladish_graph_iterate_connections(vgraph, true, &context, ladish_save_vgraph_connection))
773 log_error("ladish_graph_iterate_connections() failed");
774 return false;
777 if (!ladish_write_indented_string(fd, indent, "</connections>\n"))
779 return false;
782 if (!ladish_write_indented_string(fd, indent, "<applications>\n"))
784 return false;
787 if (!ladish_app_supervisor_enum(app_supervisor, &context, ladish_save_app))
789 return false;
792 if (!ladish_write_indented_string(fd, indent, "</applications>\n"))
794 return false;
797 return true;
800 bool ladish_write_room_link_ports(int fd, int indent, ladish_room_handle room)
802 struct ladish_write_context context;
804 context.fd = fd;
805 context.indent = indent;
807 if (!ladish_room_iterate_link_ports(room, &context, ladish_write_room_port))
809 log_error("ladish_room_iterate_link_ports() failed");
810 return false;
813 return true;
816 bool ladish_write_jgraph(int fd, int indent, ladish_graph_handle vgraph)
818 struct ladish_write_context context;
820 if (!ladish_write_indented_string(fd, indent, "<clients>\n"))
822 return false;
825 context.fd = fd;
826 context.indent = indent + 1;
828 if (!ladish_graph_iterate_nodes(
829 ladish_studio_get_jack_graph(),
830 true,
831 vgraph,
832 &context,
833 ladish_save_jack_client_begin,
834 ladish_save_jack_port,
835 ladish_save_jack_client_end))
837 log_error("ladish_graph_iterate_nodes() failed");
838 return false;
841 if (!ladish_write_indented_string(fd, indent, "</clients>\n"))
843 return false;
846 return true;