1 | /* GTK - The GIMP Toolkit |
2 | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | /* |
19 | * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS |
20 | * file for a list of people on the GTK+ Team. See the ChangeLog |
21 | * files for a list of changes. These files are distributed with |
22 | * GTK+ at ftp://ftp.gtk.org/pub/gtk/. |
23 | */ |
24 | |
25 | #include "config.h" |
26 | |
27 | #include <locale.h> |
28 | #include <stdlib.h> |
29 | |
30 | #include "gdk/gdk.h" |
31 | |
32 | #include "gtkprivate.h" |
33 | #include "gtkresources.h" |
34 | |
35 | |
36 | #if !defined G_OS_WIN32 && !(defined GDK_WINDOWING_MACOS && defined QUARTZ_RELOCATION) |
37 | |
38 | const char * |
39 | _gtk_get_datadir (void) |
40 | { |
41 | return GTK_DATADIR; |
42 | } |
43 | |
44 | const char * |
45 | _gtk_get_libdir (void) |
46 | { |
47 | return GTK_LIBDIR; |
48 | } |
49 | |
50 | const char * |
51 | _gtk_get_sysconfdir (void) |
52 | { |
53 | return GTK_SYSCONFDIR; |
54 | } |
55 | |
56 | const char * |
57 | _gtk_get_localedir (void) |
58 | { |
59 | return GTK_LOCALEDIR; |
60 | } |
61 | |
62 | const char * |
63 | _gtk_get_data_prefix (void) |
64 | { |
65 | return GTK_DATA_PREFIX; |
66 | } |
67 | |
68 | #endif |
69 | |
70 | /* _gtk_get_lc_ctype: |
71 | * |
72 | * Return the Unix-style locale string for the language currently in |
73 | * effect. On Unix systems, this is the return value from |
74 | * `setlocale(LC_CTYPE, NULL)`, and the user can |
75 | * affect this through the environment variables LC_ALL, LC_CTYPE or |
76 | * LANG (checked in that order). The locale strings typically is in |
77 | * the form lang_COUNTRY, where lang is an ISO-639 language code, and |
78 | * COUNTRY is an ISO-3166 country code. For instance, sv_FI for |
79 | * Swedish as written in Finland or pt_BR for Portuguese as written in |
80 | * Brazil. |
81 | * |
82 | * On Windows, the C library doesn’t use any such environment |
83 | * variables, and setting them won’t affect the behaviour of functions |
84 | * like ctime(). The user sets the locale through the Regional Options |
85 | * in the Control Panel. The C library (in the setlocale() function) |
86 | * does not use country and language codes, but country and language |
87 | * names spelled out in English. |
88 | * However, this function does check the above environment |
89 | * variables, and does return a Unix-style locale string based on |
90 | * either said environment variables or the thread’s current locale. |
91 | * |
92 | * Returns: a dynamically allocated string, free with g_free(). |
93 | */ |
94 | |
95 | char * |
96 | _gtk_get_lc_ctype (void) |
97 | { |
98 | #ifdef G_OS_WIN32 |
99 | /* Somebody might try to set the locale for this process using the |
100 | * LANG or LC_ environment variables. The Microsoft C library |
101 | * doesn't know anything about them. You set the locale in the |
102 | * Control Panel. Setting these env vars won't have any affect on |
103 | * locale-dependent C library functions like ctime(). But just for |
104 | * kicks, do obey LC_ALL, LC_CTYPE and LANG in GTK. (This also makes |
105 | * it easier to test GTK and Pango in various default languages, you |
106 | * don't have to clickety-click in the Control Panel, you can simply |
107 | * start the program with LC_ALL=something on the command line.) |
108 | */ |
109 | char *p; |
110 | |
111 | p = getenv ("LC_ALL" ); |
112 | if (p != NULL) |
113 | return g_strdup (p); |
114 | |
115 | p = getenv ("LC_CTYPE" ); |
116 | if (p != NULL) |
117 | return g_strdup (p); |
118 | |
119 | p = getenv ("LANG" ); |
120 | if (p != NULL) |
121 | return g_strdup (p); |
122 | |
123 | return g_win32_getlocale (); |
124 | #else |
125 | return g_strdup (str: setlocale (LC_CTYPE, NULL)); |
126 | #endif |
127 | } |
128 | |
129 | gboolean |
130 | _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint, |
131 | GValue *return_accu, |
132 | const GValue *handler_return, |
133 | gpointer dummy) |
134 | { |
135 | gboolean continue_emission; |
136 | gboolean signal_handled; |
137 | |
138 | signal_handled = g_value_get_boolean (value: handler_return); |
139 | g_value_set_boolean (value: return_accu, v_boolean: signal_handled); |
140 | continue_emission = !signal_handled; |
141 | |
142 | return continue_emission; |
143 | } |
144 | |
145 | gboolean |
146 | _gtk_single_string_accumulator (GSignalInvocationHint *ihint, |
147 | GValue *return_accu, |
148 | const GValue *handler_return, |
149 | gpointer dummy) |
150 | { |
151 | gboolean continue_emission; |
152 | const char *str; |
153 | |
154 | str = g_value_get_string (value: handler_return); |
155 | g_value_set_string (value: return_accu, v_string: str); |
156 | continue_emission = str == NULL; |
157 | |
158 | return continue_emission; |
159 | } |
160 | |
161 | static gpointer |
162 | register_resources (gpointer data) |
163 | { |
164 | _gtk_register_resource (); |
165 | return NULL; |
166 | } |
167 | |
168 | void |
169 | _gtk_ensure_resources (void) |
170 | { |
171 | static GOnce register_resources_once = G_ONCE_INIT; |
172 | |
173 | g_once (®ister_resources_once, register_resources, NULL); |
174 | } |
175 | |
176 | /* |
177 | * gtk_get_portal_interface_version: |
178 | * @connection: a session `GDBusConnection` |
179 | * @interface_name: the interface name for the portal interface |
180 | * we're interested in. |
181 | * |
182 | * Returns: the version number of the portal, or 0 on error. |
183 | */ |
184 | guint |
185 | gtk_get_portal_interface_version (GDBusConnection *connection, |
186 | const char *interface_name) |
187 | { |
188 | GDBusProxy *proxy = NULL; |
189 | GError *error = NULL; |
190 | GVariant *ret = NULL; |
191 | char *owner = NULL; |
192 | guint version = 0; |
193 | |
194 | proxy = g_dbus_proxy_new_sync (connection, |
195 | flags: 0, |
196 | NULL, |
197 | name: "org.freedesktop.portal.Desktop" , |
198 | object_path: "/org/freedesktop/portal/desktop" , |
199 | interface_name, |
200 | NULL, |
201 | error: &error); |
202 | if (!proxy) |
203 | { |
204 | if (!g_error_matches (error, G_IO_ERROR, code: G_IO_ERROR_CANCELLED)) |
205 | g_warning ("Could not query portal version on interface '%s': %s" , |
206 | interface_name, error->message); |
207 | goto out; |
208 | } |
209 | |
210 | owner = g_dbus_proxy_get_name_owner (proxy); |
211 | if (owner == NULL) |
212 | { |
213 | g_debug ("%s not provided by any service" , interface_name); |
214 | goto out; |
215 | } |
216 | |
217 | ret = g_dbus_proxy_get_cached_property (proxy, property_name: "version" ); |
218 | if (ret) |
219 | version = g_variant_get_uint32 (value: ret); |
220 | |
221 | g_debug ("Got version %u for portal interface '%s'" , |
222 | version, interface_name); |
223 | |
224 | out: |
225 | g_clear_object (&proxy); |
226 | g_clear_error (err: &error); |
227 | g_clear_pointer (&ret, g_variant_unref); |
228 | g_clear_pointer (&owner, g_free); |
229 | |
230 | return version; |
231 | } |
232 | |
233 | static char * |
234 | get_portal_path (GDBusConnection *connection, |
235 | const char *kind, |
236 | char **token) |
237 | { |
238 | char *sender; |
239 | int i; |
240 | char *path; |
241 | |
242 | *token = g_strdup_printf (format: "gtk%d" , g_random_int_range (begin: 0, G_MAXINT)); |
243 | /* +1 to skip the leading : */ |
244 | sender = g_strdup (str: g_dbus_connection_get_unique_name (connection) + 1); |
245 | for (i = 0; sender[i]; i++) |
246 | if (sender[i] == '.') |
247 | sender[i] = '_'; |
248 | |
249 | path = g_strconcat (PORTAL_OBJECT_PATH, "/" , kind, "/" , sender, "/" , *token, NULL); |
250 | |
251 | g_free (mem: sender); |
252 | |
253 | return path; |
254 | } |
255 | |
256 | char * |
257 | gtk_get_portal_request_path (GDBusConnection *connection, |
258 | char **token) |
259 | { |
260 | return get_portal_path (connection, kind: "request" , token); |
261 | } |
262 | |
263 | char * |
264 | gtk_get_portal_session_path (GDBusConnection *connection, |
265 | char **token) |
266 | { |
267 | return get_portal_path (connection, kind: "session" , token); |
268 | } |
269 | |
270 | char * |
271 | _gtk_elide_underscores (const char *original) |
272 | { |
273 | char *q, *result; |
274 | const char *p, *end; |
275 | gsize len; |
276 | gboolean last_underscore; |
277 | |
278 | if (!original) |
279 | return NULL; |
280 | |
281 | len = strlen (s: original); |
282 | q = result = g_malloc (n_bytes: len + 1); |
283 | last_underscore = FALSE; |
284 | |
285 | end = original + len; |
286 | for (p = original; p < end; p++) |
287 | { |
288 | if (!last_underscore && *p == '_') |
289 | last_underscore = TRUE; |
290 | else |
291 | { |
292 | last_underscore = FALSE; |
293 | if (original + 2 <= p && p + 1 <= end && |
294 | p[-2] == '(' && p[-1] == '_' && p[0] != '_' && p[1] == ')') |
295 | { |
296 | q--; |
297 | *q = '\0'; |
298 | p++; |
299 | } |
300 | else |
301 | *q++ = *p; |
302 | } |
303 | } |
304 | |
305 | if (last_underscore) |
306 | *q++ = '_'; |
307 | |
308 | *q = '\0'; |
309 | |
310 | return result; |
311 | } |
312 | |