summaryrefslogtreecommitdiff
path: root/gtk2_ardour/cocoacarbon.mm
blob: 6d646c763ef8ff28e8b3f4216be1c55d6415e4ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
 * Copyright (C) 2008-2016 Paul Davis <paul@linuxaudiosystems.com>
 * Copyright (C) 2008 David Robillard <d@drobilla.net>
 * Copyright (C) 2014-2016 Robin Gareus <robin@gareus.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <string>
#include <ctype.h>
#include <stdlib.h>
#include <sys/utsname.h>
#include <sys/sysctl.h>

#include <pbd/error.h>
#include <gtkmm2ext/gtkapplication.h>
#include <gdk/gdkquartz.h>

#undef check
#undef YES
#undef NO
#ifdef verify
#undef verify
#endif

#include "ardour_ui.h"
#include "actions.h"
#include "opts.h"

#include <CoreFoundation/CFLocale.h>
#import <CoreFoundation/CFString.h>
#import <Foundation/NSString.h>
#import <Foundation/NSAutoreleasePool.h>

using namespace std;
using namespace PBD;

bool
cocoa_open_url (const char* uri)
{
	NSString* struri = [[NSString alloc] initWithUTF8String:uri];
	NSURL* nsurl = [[NSURL alloc] initWithString:struri];

	bool ret = [[NSWorkspace sharedWorkspace] openURL:nsurl];

	[struri release];
	[nsurl release];

	return ret;
}

void
set_language_preference ()
{
	gtk_disable_setlocale ();

	/* the gettext manual is potentially misleading about the utility of
	   LANGUAGE.  It notes that if LANGUAGE is set to include a dialect/region-free
	   language code, like "it", it will assume that you mean the main
	   dialect (e.g. "it_IT"). But in reality, it doesn't bother looking for
	   locale dirs with the full name, only the short code (it doesn't
	   know any better).
	*/

	/* how to get language preferences with CoreFoundation
	 */

	NSArray* languages = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"];
	
	/* push into LANGUAGE */

	if (languages && [languages count] > 0) {

		int i, count = [languages count];
		bool have_translatable_languages = true;

		for (i = 0; i < count; ++i) {
			if (i == 0 && [[languages objectAtIndex:i] isEqualToString:@"en-US"]) {
				/* primary language choice is english (US). Stop looking, and do not set
				   LANGUAGE. gettext needs to just skip translation entirely.
				*/
				have_translatable_languages = false;
				cout << "User has en_US as primary language choice. " << PROGRAM_NAME << " will not be translated\n";
				break;
			}
		}

		if (have_translatable_languages) {

			NSRange r = { 0, static_cast<NSUInteger> (count) };

			std::string stupid_apple_string = [[[languages subarrayWithRange:r] componentsJoinedByString:@":"] UTF8String];

			/* Apple's language preference tokens use "-" to separate the two letter ISO language code from the two-letter
			   ISO region code. So for a German speaker in Germany whose macOS system settings reflect these realities the user
			   language preference will be "de-DE".

			   Why Apple did this when the standard everywhere else is to use an underscore is unclear. However, we do know that
			   neither gettext not setlocale(2) will work with these hyphen separated tokens, so fix them.
			*/

			for (std::string::iterator s = stupid_apple_string.begin(); s != stupid_apple_string.end(); ++s) {
				if (*s == '-') {
					*s = '_';
				}
			}

			setenv ("LANGUAGE", stupid_apple_string.c_str(), 0);
			cout << "LANGUAGE set to " << getenv ("LANGUAGE") << endl;
		}
	}

	/* now get AppleLocale value and use that to set LC_ALL because Launchd-started processes (i.e. GUI apps)
	   do not have this environment variable set, and without it, setlocale (LC_ALL, "") will fail.

	   Note that it doesn't matter much what we set LC_ALL to for gettext's purposes, but other aspects of the
	   locale system do need a value that mostly/sort-of/kind-of represents the user's own preferences. So, get
	   that from CoreFoundation APIs.
	 */

	CFLocaleRef cflocale = CFLocaleCopyCurrent();
	NSString* nslocale = (NSString*) CFLocaleGetValue (cflocale, kCFLocaleIdentifier);

	cout << "Apple's CoreFoundation API says that this user's locale is " << [nslocale UTF8String] << endl;
	setenv ("LC_ALL", [nslocale UTF8String], 0);
	CFRelease (cflocale);
}

	/* Prevent "App Nap" */

void
no_app_nap ()
{

#ifndef NSActivityLatencyCritical
#define NSActivityLatencyCritical 0xFF00000000ULL
#endif

	if ( [ [ NSProcessInfo processInfo ] respondsToSelector:@selector(beginActivityWithOptions:reason:) ] ) {
		cout << "Disabling MacOS AppNap\n";
		[ [ NSProcessInfo processInfo] beginActivityWithOptions:NSActivityLatencyCritical reason:@"realtime audio" ];
	}
}

/** Query Darwin kernel version.
 * @return major kernel version or -1 on failure
 *
 * kernel version is 4 ahead of OS X release
 * 19.x.x - OS 10.15 (Catalina)
 * 18.x.x - OS 10.14 (Mojave)
 * 17.x.x - OS 10.13 (High Sierra)
 * 16.x.x - OS 10.12 (Sierra)
 * ...
 * 10.x.x - OS 10.6  (Snow Leopard)
 */
int
query_darwin_version ()
{
	char str[256] = {0};
	size_t size = sizeof(str);

	if (0 == sysctlbyname ("kern.osrelease", str, &size, NULL, 0)) {
		short int v[3];
		if (3 == sscanf (str, "%hd.%hd.%hd", &v[0], &v[1], &v[2])) {
			return v[0]; // major version only
		}
	} else {
		struct utsname name;
		uname (&name);
		int v[3];
		if (3 == sscanf (name.release, "%d.%d.%d", &v[0], &v[1], &v[2])) {
			return v[0]; // major version only
		}
		if (2 == sscanf (name.release, "%d.%d", &v[0], &v[1])) {
			return v[0]; // major version only
		}
	}
	return -1;
}