1 /*
2 * Copyright (C) 2018-2021 Alexandros Theodotou <alex at zrythm dot org>
3 *
4 * This file is part of Zrythm
5 *
6 * Zrythm is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero 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.
10 *
11 * Zrythm 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 Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "zrythm-config.h"
21
22 #ifndef _WOE32
23 #include <sys/mman.h>
24 #endif
25 #include <stdlib.h>
26
27 #include "actions/actions.h"
28 #include "actions/undo_manager.h"
29 #include "audio/engine.h"
30 #include "audio/router.h"
31 #include "audio/quantize_options.h"
32 #include "audio/recording_manager.h"
33 #include "audio/track.h"
34 #include "audio/tracklist.h"
35 #include "gui/accel.h"
36 #include "gui/backend/event_manager.h"
37 #include "gui/backend/file_manager.h"
38 #include "gui/backend/piano_roll.h"
39 #include "gui/widgets/main_window.h"
40 #include "gui/widgets/splash.h"
41 #include "plugins/plugin_manager.h"
42 #include "project.h"
43 #include "settings/settings.h"
44 #include "utils/arrays.h"
45 #include "utils/cairo.h"
46 #include "utils/curl.h"
47 #include "utils/env.h"
48 #include "utils/gtk.h"
49 #include "utils/localization.h"
50 #include "utils/log.h"
51 #include "utils/object_pool.h"
52 #include "utils/object_utils.h"
53 #include "utils/objects.h"
54 #include "utils/io.h"
55 #include "utils/pcg_rand.h"
56 #include "utils/string.h"
57 #include "utils/symap.h"
58 #include "utils/ui.h"
59 #include "zrythm.h"
60 #include "zrythm_app.h"
61
62 #include "Wrapper.h"
63
64 #include <gdk-pixbuf/gdk-pixbuf.h>
65 #include <glib/gi18n.h>
66 #include <gtk/gtk.h>
67
68 typedef enum
69 {
70 Z_ZRYTHM_ERROR_CANNOT_GET_LATEST_RELEASE,
71 } ZZrythmError;
72
73 #define Z_ZRYTHM_ERROR \
74 z_zrythm_error_quark ()
75 GQuark z_zrythm_error_quark (void);
76 G_DEFINE_QUARK (
77 z-zrythm-error-quark, z_zrythm_error)
78
79 /** This is declared extern in zrythm.h. */
80 Zrythm * zrythm = NULL;
81
82 /**
83 * FIXME move somewhere else.
84 */
85 void
zrythm_add_to_recent_projects(Zrythm * self,const char * _filepath)86 zrythm_add_to_recent_projects (
87 Zrythm * self,
88 const char * _filepath)
89 {
90 /* if we are at max
91 * projects */
92 if (ZRYTHM->num_recent_projects ==
93 MAX_RECENT_PROJECTS)
94 {
95 /* free the last one and delete it */
96 g_free (ZRYTHM->recent_projects[
97 MAX_RECENT_PROJECTS - 1]);
98 array_delete (
99 ZRYTHM->recent_projects,
100 ZRYTHM->num_recent_projects,
101 ZRYTHM->recent_projects[
102 ZRYTHM->num_recent_projects - 1]);
103 }
104
105 char * filepath =
106 g_strdup (_filepath);
107
108 array_insert (
109 ZRYTHM->recent_projects,
110 ZRYTHM->num_recent_projects,
111 0,
112 filepath);
113
114 /* set last element to NULL because the call
115 * takes a NULL terminated array */
116 ZRYTHM->recent_projects[
117 ZRYTHM->num_recent_projects] = NULL;
118
119 g_settings_set_strv (
120 S_GENERAL, "recent-projects",
121 (const char * const *) ZRYTHM->recent_projects);
122 }
123
124 void
zrythm_remove_recent_project(char * filepath)125 zrythm_remove_recent_project (
126 char * filepath)
127 {
128 /* FIXME use GStrvBuilder */
129 for (int i = 0; i < ZRYTHM->num_recent_projects;
130 i++)
131 {
132 const char * recent_project =
133 ZRYTHM->recent_projects[i];
134 g_return_if_fail (recent_project);
135 if (string_is_equal (filepath, recent_project))
136 {
137 array_delete (ZRYTHM->recent_projects,
138 ZRYTHM->num_recent_projects,
139 ZRYTHM->recent_projects[i]);
140
141 ZRYTHM->recent_projects[
142 ZRYTHM->num_recent_projects] = NULL;
143
144 g_settings_set_strv (
145 S_GENERAL, "recent-projects",
146 (const char * const *)
147 ZRYTHM->recent_projects);
148 }
149
150 }
151 }
152
153 /**
154 * Returns the version string.
155 *
156 * Must be g_free()'d.
157 *
158 * @param with_v Include a starting "v".
159 */
160 char *
zrythm_get_version(bool with_v)161 zrythm_get_version (
162 bool with_v)
163 {
164 const char * ver = PACKAGE_VERSION;
165
166 if (with_v)
167 {
168 if (ver[0] == 'v')
169 return g_strdup (ver);
170 else
171 return
172 g_strdup_printf ("v%s", ver);
173 }
174 else
175 {
176 if (ver[0] == 'v')
177 return g_strdup (ver + 1);
178 else
179 return g_strdup (ver);
180 }
181 }
182
183 /**
184 * Returns the veresion and the capabilities.
185 */
186 void
zrythm_get_version_with_capabilities(char * str)187 zrythm_get_version_with_capabilities (
188 char * str)
189 {
190 char * ver = zrythm_get_version (0);
191
192 sprintf (
193 str,
194 "%s %s%s (%s)\n"
195 " built with %s %s for %s%s\n"
196 #ifdef HAVE_CARLA
197 " +carla\n"
198 #endif
199
200 #ifdef HAVE_JACK2
201 " +jack2\n"
202 #elif defined (HAVE_JACK)
203 " +jack1\n"
204 #endif
205
206 #ifdef MANUAL_PATH
207 " +manual\n"
208 #endif
209 #ifdef HAVE_PULSEAUDIO
210 " +pulse\n"
211 #endif
212 #ifdef HAVE_RTMIDI
213 " +rtmidi\n"
214 #endif
215 #ifdef HAVE_RTAUDIO
216 " +rtaudio\n"
217 #endif
218 #ifdef HAVE_SDL
219 " +sdl2\n"
220 #endif
221
222 #ifdef HAVE_GTK_SOURCE_VIEW_4
223 " +gtksourceview4\n"
224 #elif defined (HAVE_GTK_SOURCE_VIEW_3)
225 " +gtksourceview3\n"
226 #endif
227
228 #ifdef HAVE_GUILE
229 " +guile\n"
230 #endif
231
232 #ifdef HAVE_LSP_DSP
233 " +lsp-dsp-lib\n"
234 #endif
235
236 "",
237 PROGRAM_NAME,
238
239 #ifdef TRIAL_VER
240 "(trial) ",
241 #else
242 "",
243 #endif
244
245 ver,
246
247 #if 0
248 "optimization " OPTIMIZATION
249 #ifdef IS_DEBUG_BUILD
250 " - debug"
251 #endif
252 #endif
253 BUILD_TYPE
254 ,
255
256 COMPILER, COMPILER_VERSION, HOST_MACHINE_SYSTEM,
257
258 #ifdef APPIMAGE_BUILD
259 " (appimage)"
260 #elif defined (INSTALLER_VER)
261 " (installer)"
262 #else
263 ""
264 #endif
265
266 );
267
268 g_free (ver);
269 }
270
271 /**
272 * Returns whether the current Zrythm version is a
273 * release version.
274 *
275 * @note This only does regex checking.
276 */
277 bool
zrythm_is_release(bool official)278 zrythm_is_release (
279 bool official)
280 {
281 #ifndef INSTALLER_VER
282 if (official)
283 {
284 return false;
285 }
286 #endif
287
288 return
289 !string_contains_substr (PACKAGE_VERSION, "g");
290 }
291
292 /**
293 * Returns the latest release version.
294 */
295 char *
zrythm_fetch_latest_release_ver(void)296 zrythm_fetch_latest_release_ver (void)
297 {
298 static char * ver = NULL;
299 static bool called = false;
300
301 if (called && ver)
302 {
303 return g_strdup (ver);
304 }
305
306 char * page =
307 z_curl_get_page_contents_default (
308 "https://www.zrythm.org/releases/?C=M;O=D");
309 if (!page)
310 {
311 g_warning ("failed to get page");
312 return NULL;
313 }
314
315 ver =
316 string_get_regex_group (
317 page, "title=\"zrythm-(.+).tar.xz\"", 1);
318 g_free (page);
319
320 if (!ver)
321 {
322 g_warning ("failed to parse version");
323 return NULL;
324 }
325
326 g_debug ("latest release: %s", ver);
327 called = true;
328
329 return g_strdup (ver);
330 }
331
332 /**
333 * Returns whether this is the latest release.
334 *
335 * @p error will be set if an error occured and the
336 * return value should be ignored.
337 */
338 bool
zrythm_is_latest_release(GError ** error)339 zrythm_is_latest_release (
340 GError ** error)
341 {
342 g_return_val_if_fail (
343 *error == NULL, false);
344
345 char * latest_release =
346 zrythm_fetch_latest_release_ver ();
347 if (!latest_release)
348 {
349 g_set_error_literal (
350 error, Z_ZRYTHM_ERROR,
351 Z_ZRYTHM_ERROR_CANNOT_GET_LATEST_RELEASE,
352 "Error getting latest release");
353 return false;
354 }
355
356 bool ret = false;
357 if (string_is_equal (
358 latest_release, PACKAGE_VERSION))
359 {
360 ret = true;
361 }
362 g_free (latest_release);
363
364 return ret;
365 }
366
367 /**
368 * Returns the prefix or in the case of windows
369 * the root dir (C/program files/zrythm) or in the
370 * case of macos the bundle path.
371 *
372 * In all cases, "share" is expected to be found
373 * in this dir.
374 *
375 * @return A newly allocated string.
376 */
377 char *
zrythm_get_prefix(void)378 zrythm_get_prefix (void)
379 {
380 #if defined (_WOE32) && defined (INSTALLER_VER)
381 return
382 io_get_registry_string_val ("InstallPath");
383 #elif defined (__APPLE__) && defined (INSTALLER_VER)
384 char bundle_path[PATH_MAX];
385 int ret = io_get_bundle_path (bundle_path);
386 g_return_val_if_fail (ret == 0, NULL);
387 return io_path_get_parent_dir (bundle_path);
388 #elif defined (APPIMAGE_BUILD)
389 g_return_val_if_fail (
390 zrythm_app->appimage_runtime_path, NULL);
391 return
392 g_build_filename (
393 zrythm_app->appimage_runtime_path, "usr",
394 NULL);
395 #else
396 return g_strdup (PREFIX);
397 #endif
398 }
399
400 /**
401 * Gets the zrythm directory, either from the
402 * settings if non-empty, or the default
403 * ($XDG_DATA_DIR/zrythm).
404 *
405 * @param force_default Ignore the settings and get
406 * the default dir.
407 *
408 * Must be free'd by caler.
409 */
410 char *
zrythm_get_user_dir(bool force_default)411 zrythm_get_user_dir (
412 bool force_default)
413 {
414 if (ZRYTHM_TESTING)
415 {
416 if (!ZRYTHM->testing_dir)
417 {
418 ZRYTHM->testing_dir =
419 g_dir_make_tmp (
420 "zrythm_test_dir_XXXXXX", NULL);
421 }
422 g_debug (
423 "returning user dir: %s",
424 ZRYTHM->testing_dir);
425 return g_strdup (ZRYTHM->testing_dir);
426 }
427
428 char * dir = NULL;
429 if (SETTINGS && S_P_GENERAL_PATHS)
430 {
431 dir =
432 g_settings_get_string (
433 S_P_GENERAL_PATHS, "zrythm-dir");
434 }
435 else
436 {
437 GSettings * settings =
438 g_settings_new (
439 GSETTINGS_ZRYTHM_PREFIX
440 ".preferences.general.paths");
441 g_return_val_if_fail (settings, NULL);
442
443 dir =
444 g_settings_get_string (
445 settings, "zrythm-dir");
446
447 g_object_unref (settings);
448 }
449
450 if (force_default || strlen (dir) == 0)
451 {
452 g_free (dir);
453 dir =
454 g_build_filename (
455 g_get_user_data_dir (), "zrythm", NULL);
456 }
457
458 return dir;
459 }
460
461 /**
462 * Returns the default user "zrythm" dir.
463 *
464 * This is used when resetting or when the
465 * dir is not selected by the user yet.
466 */
467 char *
zrythm_get_default_user_dir(void)468 zrythm_get_default_user_dir (void)
469 {
470 return zrythm_get_user_dir (true);
471 }
472
473 /**
474 * Returns a Zrythm directory specified by
475 * \ref type.
476 *
477 * @return A newly allocated string.
478 */
479 char *
zrythm_get_dir(ZrythmDirType type)480 zrythm_get_dir (
481 ZrythmDirType type)
482 {
483 char * res = NULL;
484
485 /* handle system dirs */
486 if (type < ZRYTHM_DIR_USER_TOP)
487 {
488 char * prefix = zrythm_get_prefix ();
489
490 switch (type)
491 {
492 case ZRYTHM_DIR_SYSTEM_PREFIX:
493 res = g_strdup (prefix);
494 break;
495 case ZRYTHM_DIR_SYSTEM_BINDIR:
496 res =
497 g_build_filename (
498 prefix, "bin", NULL);
499 break;
500 case ZRYTHM_DIR_SYSTEM_PARENT_DATADIR:
501 res =
502 g_build_filename (
503 prefix, "share", NULL);
504 break;
505 case ZRYTHM_DIR_SYSTEM_PARENT_LIBDIR:
506 res =
507 g_build_filename (
508 prefix, "lib", NULL);
509 break;
510 case ZRYTHM_DIR_SYSTEM_ZRYTHM_LIBDIR:
511 res =
512 g_build_filename (
513 prefix, "lib", "zrythm", NULL);
514 break;
515 case ZRYTHM_DIR_SYSTEM_LOCALEDIR:
516 res =
517 g_build_filename (
518 prefix, "share", "locale", NULL);
519 break;
520 case ZRYTHM_DIR_SYSTEM_SOURCEVIEW_LANGUAGE_SPECS_DIR:
521 res =
522 g_build_filename (
523 prefix, "share",
524 #ifdef HAVE_GTK_SOURCE_VIEW_4
525 "gtksourceview-4",
526 #else
527 "gtksourceview-3.0",
528 #endif
529 "language-specs", NULL);
530 break;
531 case ZRYTHM_DIR_SYSTEM_ZRYTHM_DATADIR:
532 res =
533 g_build_filename (
534 prefix, "share", "zrythm", NULL);
535 break;
536 case ZRYTHM_DIR_SYSTEM_SAMPLESDIR:
537 res =
538 g_build_filename (
539 prefix, "share", "zrythm",
540 "samples", NULL);
541 break;
542 case ZRYTHM_DIR_SYSTEM_SCRIPTSDIR:
543 res =
544 g_build_filename (
545 prefix, "share", "zrythm",
546 "scripts", NULL);
547 break;
548 case ZRYTHM_DIR_SYSTEM_THEMESDIR:
549 res =
550 g_build_filename (
551 prefix, "share", "zrythm",
552 "themes", NULL);
553 break;
554 case ZRYTHM_DIR_SYSTEM_THEMES_CSS_DIR:
555 res =
556 g_build_filename (
557 prefix, "share", "zrythm",
558 "themes", "css", NULL);
559 break;
560 case ZRYTHM_DIR_SYSTEM_LV2_PLUGINS_DIR:
561 res =
562 g_build_filename (
563 prefix, "share", "zrythm",
564 "lv2", NULL);
565 break;
566 default:
567 break;
568 }
569
570 g_free (prefix);
571 }
572 /* handle user dirs */
573 else
574 {
575 char * user_dir = zrythm_get_user_dir (false);
576
577 switch (type)
578 {
579 case ZRYTHM_DIR_USER_TOP:
580 res = g_strdup (user_dir);
581 break;
582 case ZRYTHM_DIR_USER_PROJECTS:
583 res =
584 g_build_filename (
585 user_dir, ZRYTHM_PROJECTS_DIR, NULL);
586 break;
587 case ZRYTHM_DIR_USER_TEMPLATES:
588 res =
589 g_build_filename (
590 user_dir, "templates", NULL);
591 break;
592 case ZRYTHM_DIR_USER_LOG:
593 res =
594 g_build_filename (
595 user_dir, "log", NULL);
596 break;
597 case ZRYTHM_DIR_USER_SCRIPTS:
598 res =
599 g_build_filename (
600 user_dir, "scripts", NULL);
601 break;
602 case ZRYTHM_DIR_USER_THEMES:
603 res =
604 g_build_filename (
605 user_dir, "themes", NULL);
606 break;
607 case ZRYTHM_DIR_USER_THEMES_CSS:
608 res =
609 g_build_filename (
610 user_dir, "themes", "css", NULL);
611 break;
612 case ZRYTHM_DIR_USER_PROFILING:
613 res =
614 g_build_filename (
615 user_dir, "profiling", NULL);
616 break;
617 case ZRYTHM_DIR_USER_GDB:
618 res =
619 g_build_filename (
620 user_dir, "gdb", NULL);
621 break;
622 case ZRYTHM_DIR_USER_BACKTRACE:
623 res =
624 g_build_filename (
625 user_dir, "backtraces", NULL);
626 break;
627 default:
628 break;
629 }
630
631 g_free (user_dir);
632 }
633
634 return res;
635 }
636
637 /**
638 * Initializes/creates the default dirs/files in
639 * the user directory.
640 */
641 NONNULL
642 void
zrythm_init_user_dirs_and_files(Zrythm * self)643 zrythm_init_user_dirs_and_files (
644 Zrythm * self)
645 {
646 g_message ("initing dirs and files");
647 char * dir;
648
649 #define MK_USER_DIR(x) \
650 dir = zrythm_get_dir (ZRYTHM_DIR_USER_##x); \
651 io_mkdir (dir); \
652 g_free (dir)
653
654 MK_USER_DIR (TOP);
655 MK_USER_DIR (PROJECTS);
656 MK_USER_DIR (TEMPLATES);
657 MK_USER_DIR (LOG);
658 MK_USER_DIR (THEMES);
659 MK_USER_DIR (THEMES_CSS);
660 MK_USER_DIR (PROFILING);
661 MK_USER_DIR (GDB);
662
663 #undef MK_USER_DIR
664 }
665
666 /**
667 * Initializes the array of project templates.
668 */
669 void
zrythm_init_templates(Zrythm * self)670 zrythm_init_templates (
671 Zrythm * self)
672 {
673 g_message ("Initializing templates...");
674
675 char * user_templates_dir =
676 zrythm_get_dir (ZRYTHM_DIR_USER_TEMPLATES);
677 ZRYTHM->templates =
678 io_get_files_in_dir (user_templates_dir, true);
679 g_return_if_fail (ZRYTHM->templates);
680 g_free (user_templates_dir);
681
682 g_message ("done");
683 }
684
685 /**
686 * Frees the instance and any unfreed members.
687 */
688 void
zrythm_free(Zrythm * self)689 zrythm_free (
690 Zrythm * self)
691 {
692 g_message (
693 "%s: deleting Zrythm instance...",
694 __func__);
695
696 object_free_w_func_and_null (
697 project_free, self->project);
698
699 self->have_ui = false;
700
701 object_free_w_func_and_null (
702 z_cairo_caches_free, self->cairo_caches);
703 object_free_w_func_and_null (
704 recording_manager_free,
705 self->recording_manager);
706 object_free_w_func_and_null (
707 plugin_manager_free,
708 self->plugin_manager);
709 object_free_w_func_and_null (
710 event_manager_free, self->event_manager);
711 object_free_w_func_and_null (
712 file_manager_free, self->file_manager);
713
714 /* free object utils around last */
715 object_free_w_func_and_null (
716 object_utils_free, self->object_utils);
717
718 object_free_w_func_and_null (
719 symap_free, self->symap);
720 object_free_w_func_and_null (
721 symap_free, self->error_domain_symap);
722
723 if (ZRYTHM == self)
724 {
725 ZRYTHM = NULL;
726 }
727
728 object_zero_and_free (self);
729
730 g_message ("%s: done", __func__);
731 }
732
733 /**
734 * Creates a new Zrythm instance.
735 *
736 * @param have_ui Whether Zrythm is instantiated
737 * with a UI (false if headless).
738 * @param testing Whether this is a unit test.
739 */
740 Zrythm *
zrythm_new(const char * exe_path,bool have_ui,bool testing,bool optimized_dsp)741 zrythm_new (
742 const char * exe_path,
743 bool have_ui,
744 bool testing,
745 bool optimized_dsp)
746 {
747 Zrythm * self = object_new (Zrythm);
748 ZRYTHM = self;
749
750 self->rand = pcg_rand_new ();
751
752 self->exe_path = g_strdup (exe_path);
753
754 self->version = zrythm_get_version (false);
755 self->have_ui = have_ui;
756 self->testing = testing;
757 self->use_optimized_dsp = optimized_dsp;
758 self->settings = settings_new ();
759 self->object_utils = object_utils_new ();
760 self->recording_manager =
761 recording_manager_new ();
762 self->plugin_manager = plugin_manager_new ();
763 self->symap = symap_new ();
764 self->error_domain_symap = symap_new ();
765 self->file_manager = file_manager_new ();
766 self->cairo_caches = z_cairo_caches_new ();
767
768 if (have_ui)
769 {
770 self->event_manager =
771 event_manager_new ();
772 }
773
774 return self;
775 }
776