1 /* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /* mate-desktop-utils.c - Utilities for the MATE Desktop
3
4 Copyright (C) 1998 Tom Tromey
5 All rights reserved.
6
7 This file is part of the Mate Library.
8
9 The Mate Library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
13
14 The Mate Library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
18
19 You should have received a copy of the GNU Library General Public
20 License along with the Mate Library; see the file COPYING.LIB. If not,
21 write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 Boston, MA 02110-1301, USA. */
23 /*
24 @NOTATION@
25 */
26
27 #include <config.h>
28 #include <glib.h>
29 #include <gio/gio.h>
30 #include <glib/gi18n-lib.h>
31 #include <gdk/gdk.h>
32 #include <gtk/gtk.h>
33
34 #define MATE_DESKTOP_USE_UNSTABLE_API
35 #include <mate-desktop-utils.h>
36
37 #include "private.h"
38
39 static void
40 gtk_style_shade (GdkRGBA *a,
41 GdkRGBA *b,
42 gdouble k);
43
44 static void
45 rgb_to_hls (gdouble *r,
46 gdouble *g,
47 gdouble *b);
48
49 static void
50 hls_to_rgb (gdouble *h,
51 gdouble *l,
52 gdouble *s);
53
54 /**
55 * mate_desktop_prepend_terminal_to_vector:
56 * @argc: a pointer to the vector size
57 * @argv: a pointer to the vector
58 *
59 * Prepends a terminal (either the one configured as default in the user's
60 * MATE setup, or one of the common xterm emulators) to the passed in vector,
61 * modifying it in the process. The vector should be allocated with #g_malloc,
62 * as this will #g_free the original vector. Also all elements must have been
63 * allocated separately. That is the standard glib/MATE way of doing vectors
64 * however. If the integer that @argc points to is negative, the size will
65 * first be computed. Also note that passing in pointers to a vector that is
66 * empty, will just create a new vector for you.
67 **/
68 void
mate_desktop_prepend_terminal_to_vector(int * argc,char *** argv)69 mate_desktop_prepend_terminal_to_vector (int *argc, char ***argv)
70 {
71 char **real_argv;
72 int real_argc;
73 int i, j;
74 char **term_argv = NULL;
75 int term_argc = 0;
76 GSettings *settings;
77
78 gchar *terminal;
79
80 char **the_argv;
81
82 g_return_if_fail (argc != NULL);
83 g_return_if_fail (argv != NULL);
84
85 _mate_desktop_init_i18n ();
86
87 /* sanity */
88 if(*argv == NULL)
89 *argc = 0;
90
91 the_argv = *argv;
92
93 /* compute size if not given */
94 if (*argc < 0) {
95 for (i = 0; the_argv[i] != NULL; i++)
96 ;
97 *argc = i;
98 }
99
100 settings = g_settings_new ("org.mate.applications-terminal");
101 terminal = g_settings_get_string (settings, "exec");
102
103 if (terminal && *terminal != '\0') {
104 gchar *command_line;
105 gchar *exec_flag;
106
107 exec_flag = g_settings_get_string (settings, "exec-arg");
108
109 if (!exec_flag || *exec_flag == '\0')
110 command_line = g_strdup (terminal);
111 else
112 command_line = g_strdup_printf ("%s %s", terminal,
113 exec_flag);
114
115 g_shell_parse_argv (command_line,
116 &term_argc,
117 &term_argv,
118 NULL /* error */);
119
120 g_free (command_line);
121 g_free (exec_flag);
122 }
123 g_free (terminal);
124 g_object_unref (settings);
125
126 if (term_argv == NULL) {
127 char *check;
128
129 term_argc = 2;
130 term_argv = g_new0 (char *, 3);
131
132 check = g_find_program_in_path ("mate-terminal");
133 if (check != NULL) {
134 term_argv[0] = check;
135 /* Note that mate-terminal takes -x and
136 * as -e in mate-terminal is broken we use that. */
137 term_argv[1] = g_strdup ("-x");
138 } else {
139 if (check == NULL)
140 check = g_find_program_in_path ("nxterm");
141 if (check == NULL)
142 check = g_find_program_in_path ("color-xterm");
143 if (check == NULL)
144 check = g_find_program_in_path ("rxvt");
145 if (check == NULL)
146 check = g_find_program_in_path ("xterm");
147 if (check == NULL)
148 check = g_find_program_in_path ("dtterm");
149 if (check == NULL) {
150 g_warning (_("Cannot find a terminal, using "
151 "xterm, even if it may not work"));
152 check = g_strdup ("xterm");
153 }
154 term_argv[0] = check;
155 term_argv[1] = g_strdup ("-e");
156 }
157 }
158
159 real_argc = term_argc + *argc;
160 real_argv = g_new (char *, real_argc + 1);
161
162 for (i = 0; i < term_argc; i++)
163 real_argv[i] = term_argv[i];
164
165 for (j = 0; j < *argc; j++, i++)
166 real_argv[i] = (char *)the_argv[j];
167
168 real_argv[i] = NULL;
169
170 g_free (*argv);
171 *argv = real_argv;
172 *argc = real_argc;
173
174 /* we use g_free here as we sucked all the inner strings
175 * out from it into real_argv */
176 g_free (term_argv);
177 }
178
179 /**
180 * mate_gdk_spawn_command_line_on_screen:
181 * @screen: a GdkScreen
182 * @command: a command line
183 * @error: return location for errors
184 *
185 * This is a replacement for gdk_spawn_command_line_on_screen, deprecated
186 * in GDK 2.24 and removed in GDK 3.0.
187 *
188 * gdk_spawn_command_line_on_screen is like g_spawn_command_line_async(),
189 * except the child process is spawned in such an environment that on
190 * calling gdk_display_open() it would be returned a GdkDisplay with
191 * screen as the default screen.
192 *
193 * This is useful for applications which wish to launch an application
194 * on a specific screen.
195 *
196 * Returns: TRUE on success, FALSE if error is set.
197 *
198 * Since: 1.7.1
199 **/
200 gboolean
mate_gdk_spawn_command_line_on_screen(GdkScreen * screen,const gchar * command,GError ** error)201 mate_gdk_spawn_command_line_on_screen (GdkScreen *screen, const gchar *command, GError **error)
202 {
203 GAppInfo *appinfo = NULL;
204 GdkAppLaunchContext *context = NULL;
205 gboolean res = FALSE;
206
207 appinfo = g_app_info_create_from_commandline (command, NULL, G_APP_INFO_CREATE_NONE, error);
208
209 if (appinfo) {
210 context = gdk_display_get_app_launch_context (gdk_screen_get_display (screen));
211 res = g_app_info_launch (appinfo, NULL, G_APP_LAUNCH_CONTEXT (context), error);
212 g_object_unref (context);
213 g_object_unref (appinfo);
214 }
215
216 return res;
217 }
218
219 void
_mate_desktop_init_i18n(void)220 _mate_desktop_init_i18n (void) {
221 static gboolean initialized = FALSE;
222
223 if (!initialized) {
224 bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR);
225 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
226 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
227 #endif
228 initialized = TRUE;
229 }
230 }
231
232 /**
233 * gtk_style_shade:
234 * @a: the starting colour
235 * @b: [out] the resulting colour
236 * @k: amount to scale lightness and saturation by
237 *
238 * Takes a colour "a", scales the lightness and saturation by a certain amount,
239 * and sets "b" to the resulting colour.
240 * gtkstyle.c cut-and-pastage.
241 */
242 static void
gtk_style_shade(GdkRGBA * a,GdkRGBA * b,gdouble k)243 gtk_style_shade (GdkRGBA *a,
244 GdkRGBA *b,
245 gdouble k)
246 {
247 gdouble red;
248 gdouble green;
249 gdouble blue;
250
251 red = a->red;
252 green = a->green;
253 blue = a->blue;
254
255 rgb_to_hls (&red, &green, &blue);
256
257 green *= k;
258 if (green > 1.0)
259 green = 1.0;
260 else if (green < 0.0)
261 green = 0.0;
262
263 blue *= k;
264 if (blue > 1.0)
265 blue = 1.0;
266 else if (blue < 0.0)
267 blue = 0.0;
268
269 hls_to_rgb (&red, &green, &blue);
270
271 b->red = red;
272 b->green = green;
273 b->blue = blue;
274 }
275
276 /**
277 * rgb_to_hls:
278 * @r: on input, red; on output, hue
279 * @g: on input, green; on output, lightness
280 * @b: on input, blue; on output, saturation
281 *
282 * Converts a red/green/blue triplet to a hue/lightness/saturation triplet.
283 */
284 static void
rgb_to_hls(gdouble * r,gdouble * g,gdouble * b)285 rgb_to_hls (gdouble *r,
286 gdouble *g,
287 gdouble *b)
288 {
289 gdouble min;
290 gdouble max;
291 gdouble red;
292 gdouble green;
293 gdouble blue;
294 gdouble h, l, s;
295 gdouble delta;
296
297 red = *r;
298 green = *g;
299 blue = *b;
300
301 if (red > green)
302 {
303 if (red > blue)
304 max = red;
305 else
306 max = blue;
307
308 if (green < blue)
309 min = green;
310 else
311 min = blue;
312 }
313 else
314 {
315 if (green > blue)
316 max = green;
317 else
318 max = blue;
319
320 if (red < blue)
321 min = red;
322 else
323 min = blue;
324 }
325
326 l = (max + min) / 2;
327 s = 0;
328 h = 0;
329
330 if (max != min)
331 {
332 if (l <= 0.5)
333 s = (max - min) / (max + min);
334 else
335 s = (max - min) / (2 - max - min);
336
337 delta = max -min;
338 if (red == max)
339 h = (green - blue) / delta;
340 else if (green == max)
341 h = 2 + (blue - red) / delta;
342 else if (blue == max)
343 h = 4 + (red - green) / delta;
344
345 h *= 60;
346 if (h < 0.0)
347 h += 360;
348 }
349
350 *r = h;
351 *g = l;
352 *b = s;
353 }
354
355 /**
356 * hls_to_rgb:
357 * @h: on input, hue; on output, red
358 * @l: on input, lightness; on output, green
359 * @s on input, saturation; on output, blue
360 *
361 * Converts a hue/lightness/saturation triplet to a red/green/blue triplet.
362 */
363 static void
hls_to_rgb(gdouble * h,gdouble * l,gdouble * s)364 hls_to_rgb (gdouble *h,
365 gdouble *l,
366 gdouble *s)
367 {
368 gdouble hue;
369 gdouble lightness;
370 gdouble saturation;
371 gdouble m1, m2;
372 gdouble r, g, b;
373
374 lightness = *l;
375 saturation = *s;
376
377 if (lightness <= 0.5)
378 m2 = lightness * (1 + saturation);
379 else
380 m2 = lightness + saturation - lightness * saturation;
381 m1 = 2 * lightness - m2;
382
383 if (saturation == 0)
384 {
385 *h = lightness;
386 *l = lightness;
387 *s = lightness;
388 }
389 else
390 {
391 hue = *h + 120;
392 while (hue > 360)
393 hue -= 360;
394 while (hue < 0)
395 hue += 360;
396
397 if (hue < 60)
398 r = m1 + (m2 - m1) * hue / 60;
399 else if (hue < 180)
400 r = m2;
401 else if (hue < 240)
402 r = m1 + (m2 - m1) * (240 - hue) / 60;
403 else
404 r = m1;
405
406 hue = *h;
407 while (hue > 360)
408 hue -= 360;
409 while (hue < 0)
410 hue += 360;
411
412 if (hue < 60)
413 g = m1 + (m2 - m1) * hue / 60;
414 else if (hue < 180)
415 g = m2;
416 else if (hue < 240)
417 g = m1 + (m2 - m1) * (240 - hue) / 60;
418 else
419 g = m1;
420
421 hue = *h - 120;
422 while (hue > 360)
423 hue -= 360;
424 while (hue < 0)
425 hue += 360;
426
427 if (hue < 60)
428 b = m1 + (m2 - m1) * hue / 60;
429 else if (hue < 180)
430 b = m2;
431 else if (hue < 240)
432 b = m1 + (m2 - m1) * (240 - hue) / 60;
433 else
434 b = m1;
435
436 *h = r;
437 *l = g;
438 *s = b;
439 }
440 }
441
442 /* Based on set_color() in gtkstyle.c */
443 #define LIGHTNESS_MULT 1.3
444 #define DARKNESS_MULT 0.7
445 void
mate_desktop_gtk_style_get_light_color(GtkStyleContext * style,GtkStateFlags state,GdkRGBA * color)446 mate_desktop_gtk_style_get_light_color (GtkStyleContext *style,
447 GtkStateFlags state,
448 GdkRGBA *color)
449 {
450 gtk_style_context_get_background_color (style, state, color);
451 gtk_style_shade (color, color, LIGHTNESS_MULT);
452 }
453
454 void
mate_desktop_gtk_style_get_dark_color(GtkStyleContext * style,GtkStateFlags state,GdkRGBA * color)455 mate_desktop_gtk_style_get_dark_color (GtkStyleContext *style,
456 GtkStateFlags state,
457 GdkRGBA *color)
458 {
459 gtk_style_context_get_background_color (style, state, color);
460 gtk_style_shade (color, color, DARKNESS_MULT);
461 }
462