restore early-return from fixup_bundle_environment() on macOS if not running from...
[ardour.git] / gtk2_ardour / bundle_env_cocoa.cc
1 /*
2  * Copyright (C) 2014-2016 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2015-2018 Robin Gareus <robin@gareus.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include <unistd.h>
21
22 #include <string>
23 #include <vector>
24 #include <cerrno>
25 #include <cstdio>
26 #include <cstring>
27
28 #include <glib.h>
29 #include <glibmm/fileutils.h>
30 #include <glibmm/miscutils.h>
31
32 #include <fontconfig/fontconfig.h>
33
34 #include "ardour/ardour.h"
35 #include "ardour/filesystem_paths.h"
36
37 #include "pbd/epa.h"
38 #include "pbd/file_utils.h"
39 #include "pbd/search_path.h"
40 #include "pbd/pathexpand.h"
41
42 #include "bundle_env.h"
43
44 #include "pbd/i18n.h"
45
46 #include <asl.h>
47 #include <Carbon/Carbon.h>
48 #include <mach-o/dyld.h>
49 #include <sys/param.h>
50
51 using namespace PBD;
52 using namespace ARDOUR;
53 using namespace std;
54
55 extern void set_language_preference (); // cocoacarbon.mm
56 extern void no_app_nap (); // cocoacarbon.mm
57
58 static void
59 setup_logging (void)
60 {
61         char path[PATH_MAX+1];
62         snprintf (path, sizeof (path), "%s/stderr.log", user_config_directory().c_str());
63
64         int efd = ::open (path, O_CREAT|O_WRONLY|O_TRUNC, 0644);
65
66         if (efd >= 0) {
67                 if (dup2 (efd, STDERR_FILENO) < 0) {
68                         ::exit (12);
69                 }
70         } else {
71                 ::exit (11);
72         }
73
74         snprintf (path, sizeof (path), "%s/stdout.log", user_config_directory().c_str());
75
76         int ofd = ::open (path, O_CREAT|O_WRONLY|O_TRUNC, 0644);
77
78         if (ofd >= 0) {
79                 if (dup2 (ofd, STDOUT_FILENO) < 0) {
80                         ::exit (14);
81                 }
82         } else {
83                 ::exit (13);
84         }
85 }
86
87 void
88 fixup_bundle_environment (int argc, char* argv[], string & localedir)
89 {
90         /* if running from a bundle, stdout/stderr will be redirect to null by
91          * launchd. That's not useful for anyone, so fix that. Use the same
92          * mechanism is not running from a bundle, but ARDOUR_LOGGING is
93          * set. This allows us to test the stderr/stdout redirects directly
94          * from ./ardev.
95          */
96
97         if (g_getenv ("ARDOUR_BUNDLED") || g_getenv ("ARDOUR_LOGGING")) {
98                 setup_logging ();
99         }
100
101         no_app_nap ();
102
103         if (!g_getenv ("ARDOUR_BUNDLED")) {
104                 return;
105         }
106
107         if (g_getenv ("ARDOUR_SELF")) {
108                 g_setenv ("ARDOUR_SELF", argv[0], 1);
109         }
110         if (g_getenv ("PREBUNDLE_ENV")) {
111                 EnvironmentalProtectionAgency::set_global_epa (new EnvironmentalProtectionAgency (true, "PREBUNDLE_ENV"));
112         }
113
114         set_language_preference ();
115
116         char execpath[MAXPATHLEN+1];
117         uint32_t pathsz = sizeof (execpath);
118
119         _NSGetExecutablePath (execpath, &pathsz);
120
121         std::string path;
122         std::string exec_dir = Glib::path_get_dirname (execpath);
123         std::string bundle_dir;
124         std::string userconfigdir = user_config_directory();
125
126         bundle_dir = Glib::path_get_dirname (exec_dir);
127
128 #if ENABLE_NLS
129         if (!ARDOUR::translations_are_enabled ()) {
130                 localedir = "/this/cannot/exist";
131         } else {
132                 /* force localedir into the bundle */
133
134                 vector<string> lpath;
135                 lpath.push_back (bundle_dir);
136                 lpath.push_back ("Resources");
137                 lpath.push_back ("locale");
138                 localedir = Glib::build_filename (lpath).c_str();
139         }
140 #endif
141
142         export_search_path (bundle_dir, "ARDOUR_DLL_PATH", "/lib");
143
144         /* inside an OS X .app bundle, there is no difference
145            between DATA and CONFIG locations, since OS X doesn't
146            attempt to do anything to expose the notion of
147            machine-independent shared data.
148         */
149
150         export_search_path (bundle_dir, "ARDOUR_DATA_PATH", "/Resources");
151         export_search_path (bundle_dir, "ARDOUR_CONFIG_PATH", "/Resources");
152         export_search_path (bundle_dir, "ARDOUR_INSTANT_XML_PATH", "/Resources");
153         export_search_path (bundle_dir, "LADSPA_PATH", "/Plugins");
154         export_search_path (bundle_dir, "VAMP_PATH", "/lib");
155         export_search_path (bundle_dir, "GTK_PATH", "/lib/gtkengines");
156
157         g_setenv ("SUIL_MODULE_DIR", (bundle_dir + "/lib").c_str(), 1);
158         g_setenv ("PATH", (bundle_dir + "/MacOS:" + std::string(g_getenv ("PATH"))).c_str(), 1);
159
160         /* unset GTK2_RC_FILES so that we only load the RC files that we define
161          */
162
163         g_unsetenv ("GTK2_RC_FILES");
164         g_setenv ("CHARSETALIASDIR", bundle_dir.c_str(), 1);
165         g_setenv ("FONTCONFIG_FILE", Glib::build_filename (bundle_dir, "Resources/fonts.conf").c_str(), 1);
166 }
167
168 void load_custom_fonts()
169 {
170         /* this code will only compile on OS X 10.6 and above, and we currently do not
171          * need it for earlier versions since we fall back on a non-monospace,
172          * non-custom font.
173          */
174
175 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
176         std::string font_file;
177
178         if (!find_file (ardour_data_search_path(), "ArdourMono.ttf", font_file)) {
179                 cerr << _("Cannot find ArdourMono TrueType font") << endl;
180         } else {
181                 CFStringRef ttf;
182                 CFURLRef fontURL;
183                 CFErrorRef error;
184                 ttf = CFStringCreateWithBytes(
185                                 kCFAllocatorDefault, (const UInt8*) font_file.c_str(),
186                                 font_file.length(),
187                                 kCFStringEncodingUTF8, FALSE);
188                 fontURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, ttf, kCFURLPOSIXPathStyle, TRUE);
189                 if (CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error) != true) {
190                         cerr << _("Cannot load ArdourMono TrueType font.") << endl;
191                 }
192         }
193
194         if (!find_file (ardour_data_search_path(), "ArdourSans.ttf", font_file)) {
195                 cerr << _("Cannot find ArdourSans TrueType font") << endl;
196         } else {
197                 CFStringRef ttf;
198                 CFURLRef fontURL;
199                 CFErrorRef error;
200                 ttf = CFStringCreateWithBytes(
201                                 kCFAllocatorDefault, (const UInt8*) font_file.c_str(),
202                                 font_file.length(),
203                                 kCFStringEncodingUTF8, FALSE);
204                 fontURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, ttf, kCFURLPOSIXPathStyle, TRUE);
205                 if (CTFontManagerRegisterFontsForURL(fontURL, kCTFontManagerScopeProcess, &error) != true) {
206                         cerr << _("Cannot load ArdourSans TrueType font.") << endl;
207                 }
208         }
209 #endif
210 }