From 4988f6f941cfa6d538e9112d6dba2418e8c9c74d Mon Sep 17 00:00:00 2001 From: "raveit65 (via Travis CI)" Date: Tue, 30 Jul 2024 21:03:41 +0000 Subject: Deploy mate-desktop/mate-desktop to github.com/mate-desktop/mate-desktop.git:gh-pages --- .../index.html | 146 + .../report-25ea44.html | 1920 ++++++++ .../report-2f348d.html | 3591 +++++++++++++++ .../report-30e8a4.html | 4660 +++++++++++++++++++ .../report-413fe6.html | 2115 +++++++++ .../report-425c9c.html | 4660 +++++++++++++++++++ .../report-4a69b4.html | 2115 +++++++++ .../report-563e6a.html | 2013 +++++++++ .../report-689d47.html | 4660 +++++++++++++++++++ .../report-6a2986.html | 4711 ++++++++++++++++++++ .../report-6e323f.html | 2013 +++++++++ .../report-8fac16.html | 4693 +++++++++++++++++++ .../report-a7ec2e.html | 2013 +++++++++ .../report-d0e85f.html | 4650 +++++++++++++++++++ .../report-f1d0a2.html | 4154 +++++++++++++++++ .../report-f4adeb.html | 2013 +++++++++ .../report-fb6164.html | 1437 ++++++ .../scanview.css | 62 + .../sorttable.js | 492 ++ 19 files changed, 52118 insertions(+) create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/index.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-25ea44.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-2f348d.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-30e8a4.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-413fe6.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-425c9c.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-4a69b4.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-563e6a.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-689d47.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-6a2986.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-6e323f.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-8fac16.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-a7ec2e.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-d0e85f.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-f1d0a2.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-f4adeb.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-fb6164.html create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/scanview.css create mode 100644 2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/sorttable.js (limited to '2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail') diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/index.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/index.html new file mode 100644 index 0000000..3affa56 --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/index.html @@ -0,0 +1,146 @@ + + +rootdir - scan-build results + + + + + + +

rootdir - scan-build results

+ + + + + + + +
User:root@7204d9fef646
Working Directory:/rootdir
Command Line:make -j 2
Clang Version:clang version 17.0.6 (Fedora 17.0.6-2.fc39) +
Date:Thu Apr 4 05:37:07 2024
+

Bug Summary

+ + + + + + + + + + + +
Bug TypeQuantityDisplay?
All Bugs16
Logic error
Garbage return value1
Out-of-bound access5
Uninitialized argument value1
Memory error
Use-after-free1
Unused code
Dead nested assignment1
Unreachable code7
+

Reports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Unused codeDead nested assignmentdocs/reference/mate-desktop/mate-desktop-scan.coutput_object_signal1881View Report
Logic errorGarbage return valuelibmate-desktop/mate-desktop-item.cditem_execute203753View Report
Logic errorOut-of-bound accesslibmate-desktop/mate-desktop-item.cescape_string_and_dup312127View Report
Logic errorOut-of-bound accesslibmate-desktop/mate-desktop-item.cescape_string_and_dup312927View Report
Logic errorOut-of-bound accesslibmate-desktop/mate-desktop-item.cescape_string_and_dup312527View Report
Logic errorOut-of-bound accesslibmate-desktop/mate-desktop-item.cescape_string_and_dup312037View Report
Logic errorOut-of-bound accesslibmate-desktop/mate-desktop-item.cescape_string_and_dup313624View Report
Logic errorUninitialized argument valuelibmate-desktop/mate-bg.ccreate_img_thumbnail227676View Report
Unused codeUnreachable codelibmate-desktop/mate-hsv.cmate_hsv_button_press6701View Report
Unused codeUnreachable codelibmate-desktop/mate-hsv.cmate_hsv_button_press6521View Report
Unused codeUnreachable codelibmate-desktop/mate-languages.cmate_get_language_from_locale11631View Report
Unused codeUnreachable codelibmate-desktop/mate-languages.cmate_get_country_from_locale12181View Report
Unused codeUnreachable codelibmate-desktop/mate-languages.cmate_get_language_from_locale11371View Report
Unused codeUnreachable codelibmate-desktop/mate-languages.cmate_get_country_from_locale12441View Report
Unused codeUnreachable codelibmate-desktop/tmp-introspectv9kvk83f/MateDesktop-2.0.cvalue_to_string1811View Report
Memory errorUse-after-freelibmate-desktop/mate-colorsel.chex_changed187613View Report
+ + diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-25ea44.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-25ea44.html new file mode 100644 index 0000000..6f0e588 --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-25ea44.html @@ -0,0 +1,1920 @@ + + + +mate-desktop-scan.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:docs/reference/mate-desktop/mate-desktop-scan.c
Warning:line 188, column 16
Although the value stored to 'event_num' is used in the enclosing expression, the value is never actually read from 'event_num'
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-desktop-scan.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/docs/reference/mate-desktop -resource-dir /usr/bin/../lib/clang/17 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I ../../../libmate-desktop -D MATE_DESKTOP_USE_UNSTABLE_API -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/docs/reference/mate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-desktop-scan.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1
2#include <string.h>
3#include <stdlib.h>
4#include <stdio.h>
5#include <errno(*__errno_location ()).h>
6#include <glib-object.h>
7
8#ifndef G_GNUC_BEGIN_IGNORE_DEPRECATIONSclang diagnostic push + clang diagnostic ignored "-Wdeprecated-declarations"
+
9# define G_GNUC_BEGIN_IGNORE_DEPRECATIONSclang diagnostic push + clang diagnostic ignored "-Wdeprecated-declarations"
+
10# define G_GNUC_END_IGNORE_DEPRECATIONSclang diagnostic pop +
11#endif
12
13#include <mate-desktop-item.h>
14#include <mate-bg.h>
15#include <mate-desktop-thumbnail.h>
16#include <mate-rr-labeler.h>
17
18
19#ifdef GTK_IS_WIDGET_CLASS
20#include <gtk/gtk.h>
21#endif
22static GType object_types[5];
23
24static GType *
25get_object_types (void)
26{
27 gpointer g_object_class;
28 gint i = 0;
29
30G_GNUC_BEGIN_IGNORE_DEPRECATIONSclang diagnostic push + clang diagnostic ignored "-Wdeprecated-declarations"
+
31
32 object_types[i++] = mate_desktop_item_get_type ();
33 object_types[i++] = mate_bg_get_type ();
34 object_types[i++] = mate_desktop_thumbnail_factory_get_type ();
35 object_types[i++] = mate_rr_labeler_get_type ();
36
37 object_types[i] = G_TYPE_INVALID((GType) ((0) << (2)));
38
39 /* reference the GObjectClass to initialize the param spec pool
40 * potentially needed by interfaces. See http://bugs.gnome.org/571820 */
41 g_object_class = g_type_class_ref (G_TYPE_OBJECT((GType) ((20) << (2))));
42
43 /* Need to make sure all the types are loaded in and initialize
44 * their signals and properties.
45 */
46 for (i=0; object_types[i]; i++) {
47 if (G_TYPE_IS_CLASSED (object_types[i])(g_type_test_flags ((object_types[i]), G_TYPE_FLAG_CLASSED)))
48 g_type_class_ref (object_types[i]);
49 if (G_TYPE_IS_INTERFACE (object_types[i])((g_type_fundamental (object_types[i])) == ((GType) ((2) <<
(2))))
)
50 g_type_default_interface_ref (object_types[i]);
51 }
52
53 g_type_class_unref (g_object_class);
54
55G_GNUC_END_IGNORE_DEPRECATIONSclang diagnostic pop +
56
57 return object_types;
58}
59
60/*
61 * This uses GObject type functions to output signal prototypes and the object
62 * hierarchy.
63 */
64
65/* The output files */
66const gchar *signals_filename = "./mate-desktop.signals.new";
67const gchar *hierarchy_filename = "./mate-desktop.hierarchy.new";
68const gchar *interfaces_filename = "./mate-desktop.interfaces.new";
69const gchar *prerequisites_filename = "./mate-desktop.prerequisites.new";
70const gchar *args_filename = "./mate-desktop.args.new";
71const gchar *actions_filename = "./mate-desktop.actions.new";
72
73static void output_signals (void);
74static void output_object_signals (FILE *fp,
75 GType object_type);
76static void output_object_signal (FILE *fp,
77 const gchar *object_class_name,
78 guint signal_id);
79static const gchar * get_type_name (GType type,
80 gboolean * is_pointer);
81static void output_object_hierarchy (void);
82static void output_hierarchy (FILE *fp,
83 GType type,
84 guint level);
85
86static void output_object_interfaces (void);
87static void output_interfaces (FILE *fp,
88 GType type);
89
90static void output_interface_prerequisites (void);
91static void output_prerequisites (FILE *fp,
92 GType type);
93
94static void output_args (void);
95static void output_object_args (FILE *fp, GType object_type);
96
97static void output_actions (void);
98static void output_object_actions (FILE *fp, GType object_type);
99
100int
101main (void)
102{
103 ;
104
105 get_object_types ();
106
107 output_signals ();
108 output_object_hierarchy ();
109 output_object_interfaces ();
110 output_interface_prerequisites ();
111 output_args ();
112 output_actions ();
113
114 return 0;
115}
116
117static void
118output_signals (void)
119{
120 FILE *fp;
121 gint i;
122
123 fp = fopen (signals_filename, "w");
124 if (fp == NULL((void*)0)) {
125 g_warning ("Couldn't open output file: %s : %s", signals_filename, g_strerror(errno(*__errno_location ())));
126 return;
127 }
128
129 for (i = 0; object_types[i]; i++)
130 output_object_signals (fp, object_types[i]);
131
132 fclose (fp);
133}
134
135static gint
136compare_signals (const void *a, const void *b)
137{
138 const guint *signal_a = a;
139 const guint *signal_b = b;
140
141 return strcmp (g_signal_name (*signal_a), g_signal_name (*signal_b));
142}
143
144/* This outputs all the signals of one object. */
145static void
146output_object_signals (FILE *fp, GType object_type)
147{
148 const gchar *object_class_name;
149 guint *signals, n_signals;
150 guint sig;
151
152 if (G_TYPE_IS_INSTANTIATABLE (object_type)(g_type_test_flags ((object_type), G_TYPE_FLAG_INSTANTIATABLE
))
||
153 G_TYPE_IS_INTERFACE (object_type)((g_type_fundamental (object_type)) == ((GType) ((2) <<
(2))))
) {
154
155 object_class_name = g_type_name (object_type);
156
157 signals = g_signal_list_ids (object_type, &n_signals);
158 if (n_signals > 0)
159 qsort (signals, n_signals, sizeof (guint), compare_signals);
160
161 for (sig = 0; sig < n_signals; sig++) {
162 output_object_signal (fp, object_class_name, signals[sig]);
163 }
164 g_free (signals);
165 }
166}
167
168/* This outputs one signal. */
169static void
170output_object_signal (FILE *fp,
171 const gchar *object_name,
172 guint signal_id)
173{
174 GSignalQuery query_info;
175 const gchar *type_name, *ret_type, *object_arg, *arg_name;
176 gchar *pos, *object_arg_lower;
177 gboolean is_pointer;
178 gchar buffer[1024];
179 guint i, param;
180 gint param_num, widget_num, event_num, callback_num;
181 gint *arg_num;
182 gchar signal_name[128];
183 gchar flags[16];
184
185 /* g_print ("Object: %s Signal: %u\n", object_name, signal_id);*/
186
187 param_num = 1;
188 widget_num = event_num = callback_num = 0;
Although the value stored to 'event_num' is used in the enclosing expression, the value is never actually read from 'event_num'
189
190 g_signal_query (signal_id, &query_info);
191
192 /* Output the signal object type and the argument name. We assume the
193 * type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
194 * convert to lower case for the argument name. */
195 pos = buffer;
196 sprintf (pos, "%s ", object_name);
197 pos += strlen (pos);
198
199 /* Try to come up with a sensible variable name for the first arg
200 * It chops off 2 know prefixes :/ and makes the name lowercase
201 * It should replace lowercase -> uppercase with '_'
202 * GFileMonitor -> file_monitor
203 * GIOExtensionPoint -> extension_point
204 * GtkTreeView -> tree_view
205 * if 2nd char is upper case too
206 * search for first lower case and go back one char
207 * else
208 * search for next upper case
209 */
210 if (!strncmp (object_name, "Gtk", 3))
211 object_arg = object_name + 3;
212 else if (!strncmp (object_name, "Gnome", 5))
213 object_arg = object_name + 5;
214 else
215 object_arg = object_name;
216
217 object_arg_lower = g_ascii_strdown (object_arg, -1);
218 sprintf (pos, "*%s\n", object_arg_lower);
219 pos += strlen (pos);
220 if (!strncmp (object_arg_lower, "widget", 6))
221 widget_num = 2;
222 g_free(object_arg_lower);
223
224 /* Convert signal name to use underscores rather than dashes '-'. */
225 strncpy (signal_name, query_info.signal_name, 127);
226 signal_name[127] = '\0';
227 for (i = 0; signal_name[i]; i++) {
228 if (signal_name[i] == '-')
229 signal_name[i] = '_';
230 }
231
232 /* Output the signal parameters. */
233 for (param = 0; param < query_info.n_params; param++) {
234 type_name = get_type_name (query_info.param_types[param] & ~G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0))), &is_pointer);
235
236 /* Most arguments to the callback are called "arg1", "arg2", etc.
237 GtkWidgets are called "widget", "widget2", ...
238 GtkCallbacks are called "callback", "callback2", ... */
239 if (!strcmp (type_name, "GtkWidget")) {
240 arg_name = "widget";
241 arg_num = &widget_num;
242 }
243 else if (!strcmp (type_name, "GtkCallback")
244 || !strcmp (type_name, "GtkCCallback")) {
245 arg_name = "callback";
246 arg_num = &callback_num;
247 }
248 else {
249 arg_name = "arg";
250 arg_num = &param_num;
251 }
252 sprintf (pos, "%s ", type_name);
253 pos += strlen (pos);
254
255 if (!arg_num || *arg_num == 0)
256 sprintf (pos, "%s%s\n", is_pointer ? "*" : " ", arg_name);
257 else
258 sprintf (pos, "%s%s%i\n", is_pointer ? "*" : " ", arg_name,
259 *arg_num);
260 pos += strlen (pos);
261
262 if (arg_num) {
263 if (*arg_num == 0)
264 *arg_num = 2;
265 else
266 *arg_num += 1;
267 }
268 }
269
270 pos = flags;
271 /* We use one-character flags for simplicity. */
272 if (query_info.signal_flags & G_SIGNAL_RUN_FIRST)
273 *pos++ = 'f';
274 if (query_info.signal_flags & G_SIGNAL_RUN_LAST)
275 *pos++ = 'l';
276 if (query_info.signal_flags & G_SIGNAL_RUN_CLEANUP)
277 *pos++ = 'c';
278 if (query_info.signal_flags & G_SIGNAL_NO_RECURSE)
279 *pos++ = 'r';
280 if (query_info.signal_flags & G_SIGNAL_DETAILED)
281 *pos++ = 'd';
282 if (query_info.signal_flags & G_SIGNAL_ACTION)
283 *pos++ = 'a';
284 if (query_info.signal_flags & G_SIGNAL_NO_HOOKS)
285 *pos++ = 'h';
286 *pos = 0;
287
288 /* Output the return type and function name. */
289 ret_type = get_type_name (query_info.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE(((GType) (1 << 0))), &is_pointer);
290
291 fprintf (fp,
292 "<SIGNAL>\n<NAME>%s::%s</NAME>\n<RETURNS>%s%s</RETURNS>\n<FLAGS>%s</FLAGS>\n%s</SIGNAL>\n\n",
293 object_name, query_info.signal_name, ret_type, is_pointer ? "*" : "", flags, buffer);
294}
295
296
297/* Returns the type name to use for a signal argument or return value, given
298 the GtkType from the signal info. It also sets is_pointer to TRUE if the
299 argument needs a '*' since it is a pointer. */
300static const gchar *
301get_type_name (GType type, gboolean * is_pointer)
302{
303 const gchar *type_name;
304
305 *is_pointer = FALSE(0);
306 type_name = g_type_name (type);
307
308 switch (type) {
309 case G_TYPE_NONE((GType) ((1) << (2))):
310 case G_TYPE_UCHAR((GType) ((4) << (2))):
311 case G_TYPE_BOOLEAN((GType) ((5) << (2))):
312 case G_TYPE_UINT((GType) ((7) << (2))):
313 case G_TYPE_LONG((GType) ((8) << (2))):
314 case G_TYPE_ULONG((GType) ((9) << (2))):
315 case G_TYPE_POINTER((GType) ((17) << (2))):
316 /* These all have normal C type names so they are OK. */
317 return type_name;
318
319 case G_TYPE_CHAR((GType) ((3) << (2))):
320 return "char";
321
322 case G_TYPE_INT((GType) ((6) << (2))):
323 return "int";
324
325 case G_TYPE_FLOAT((GType) ((14) << (2))):
326 return "float";
327
328 case G_TYPE_DOUBLE((GType) ((15) << (2))):
329 return "double";
330
331 case G_TYPE_STRING((GType) ((16) << (2))):
332 /* A GtkString is really a gchar*. */
333 *is_pointer = TRUE(!(0));
334 return "char";
335
336 case G_TYPE_ENUM((GType) ((12) << (2))):
337 case G_TYPE_FLAGS((GType) ((13) << (2))):
338 /* We use a gint for both of these. Hopefully a subtype with a decent
339 name will be registered and used instead, as GTK+ does itself. */
340 return "int";
341
342 case G_TYPE_BOXED((GType) ((18) << (2))):
343 /* The boxed type shouldn't be used itself, only subtypes. Though we
344 return 'gpointer' just in case. */
345 return "gpointer";
346
347 case G_TYPE_PARAM((GType) ((19) << (2))):
348 /* A GParam is really a GParamSpec*. */
349 *is_pointer = TRUE(!(0));
350 return "GParamSpec";
351
352#if GLIB_CHECK_VERSION (2, 25, 9)(2 > (2) || (2 == (2) && 78 > (25)) || (2 == (2
) && 78 == (25) && 3 >= (9)))
353 case G_TYPE_VARIANT((GType) ((21) << (2))):
354 *is_pointer = TRUE(!(0));
355 return "GVariant";
356#endif
357
358default:
359 break;
360 }
361
362 /* For all GObject subclasses we can use the class name with a "*",
363 e.g. 'GtkWidget *'. */
364 if (g_type_is_a (type, G_TYPE_OBJECT)((type) == (((GType) ((20) << (2)))) || (g_type_is_a) (
(type), (((GType) ((20) << (2))))))
)
365 *is_pointer = TRUE(!(0));
366
367 /* Also catch non GObject root types */
368 if (G_TYPE_IS_CLASSED (type)(g_type_test_flags ((type), G_TYPE_FLAG_CLASSED)))
369 *is_pointer = TRUE(!(0));
370
371 /* All boxed subtypes will be pointers as well. */
372 /* Exception: GStrv */
373 if (g_type_is_a (type, G_TYPE_BOXED)((type) == (((GType) ((18) << (2)))) || (g_type_is_a) (
(type), (((GType) ((18) << (2))))))
&&
374 !g_type_is_a (type, G_TYPE_STRV)((type) == ((g_strv_get_type ())) || (g_type_is_a) ((type), (
(g_strv_get_type ()))))
)
375 *is_pointer = TRUE(!(0));
376
377 /* All pointer subtypes will be pointers as well. */
378 if (g_type_is_a (type, G_TYPE_POINTER)((type) == (((GType) ((17) << (2)))) || (g_type_is_a) (
(type), (((GType) ((17) << (2))))))
)
379 *is_pointer = TRUE(!(0));
380
381 /* But enums are not */
382 if (g_type_is_a (type, G_TYPE_ENUM)((type) == (((GType) ((12) << (2)))) || (g_type_is_a) (
(type), (((GType) ((12) << (2))))))
||
383 g_type_is_a (type, G_TYPE_FLAGS)((type) == (((GType) ((13) << (2)))) || (g_type_is_a) (
(type), (((GType) ((13) << (2))))))
)
384 *is_pointer = FALSE(0);
385
386 return type_name;
387}
388
389
390/* This outputs the hierarchy of all objects which have been initialized,
391 i.e. by calling their XXX_get_type() initialization function. */
392static void
393output_object_hierarchy (void)
394{
395 FILE *fp;
396 gint i,j;
397 GType root, type;
398 GType root_types[5] = { G_TYPE_INVALID((GType) ((0) << (2))), };
399
400 fp = fopen (hierarchy_filename, "w");
401 if (fp == NULL((void*)0)) {
402 g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, g_strerror(errno(*__errno_location ())));
403 return;
404 }
405 output_hierarchy (fp, G_TYPE_OBJECT((GType) ((20) << (2))), 0);
406 output_hierarchy (fp, G_TYPE_INTERFACE((GType) ((2) << (2))), 0);
407
408 for (i=0; object_types[i]; i++) {
409 root = object_types[i];
410 while ((type = g_type_parent (root))) {
411 root = type;
412 }
413 if ((root != G_TYPE_OBJECT((GType) ((20) << (2)))) && (root != G_TYPE_INTERFACE((GType) ((2) << (2))))) {
414 for (j=0; root_types[j]; j++) {
415 if (root == root_types[j]) {
416 root = G_TYPE_INVALID((GType) ((0) << (2))); break;
417 }
418 }
419 if(root) {
420 root_types[j] = root;
421 output_hierarchy (fp, root, 0);
422 }
423 }
424 }
425
426 fclose (fp);
427}
428
429/* This is called recursively to output the hierarchy of a object. */
430static void
431output_hierarchy (FILE *fp,
432 GType type,
433 guint level)
434{
435 guint i;
436 GType *children;
437 guint n_children;
438
439 if (!type)
440 return;
441
442 for (i = 0; i < level; i++)
443 fprintf (fp, " ");
444 fprintf (fp, "%s\n", g_type_name (type));
445
446 children = g_type_children (type, &n_children);
447
448 for (i=0; i < n_children; i++)
449 output_hierarchy (fp, children[i], level + 1);
450
451 g_free (children);
452}
453
454static void output_object_interfaces (void)
455{
456 guint i;
457 FILE *fp;
458
459 fp = fopen (interfaces_filename, "w");
460 if (fp == NULL((void*)0)) {
461 g_warning ("Couldn't open output file: %s : %s", interfaces_filename, g_strerror(errno(*__errno_location ())));
462 return;
463 }
464 output_interfaces (fp, G_TYPE_OBJECT((GType) ((20) << (2))));
465
466 for (i = 0; object_types[i]; i++) {
467 if (!g_type_parent (object_types[i]) &&
468 (object_types[i] != G_TYPE_OBJECT((GType) ((20) << (2)))) &&
469 G_TYPE_IS_INSTANTIATABLE (object_types[i])(g_type_test_flags ((object_types[i]), G_TYPE_FLAG_INSTANTIATABLE
))
) {
470 output_interfaces (fp, object_types[i]);
471 }
472 }
473 fclose (fp);
474}
475
476static void
477output_interfaces (FILE *fp,
478 GType type)
479{
480 guint i;
481 GType *children, *interfaces;
482 guint n_children, n_interfaces;
483
484 if (!type)
485 return;
486
487 interfaces = g_type_interfaces (type, &n_interfaces);
488
489 if (n_interfaces > 0) {
490 fprintf (fp, "%s", g_type_name (type));
491 for (i=0; i < n_interfaces; i++)
492 fprintf (fp, " %s", g_type_name (interfaces[i]));
493 fprintf (fp, "\n");
494 }
495 g_free (interfaces);
496
497 children = g_type_children (type, &n_children);
498
499 for (i=0; i < n_children; i++)
500 output_interfaces (fp, children[i]);
501
502 g_free (children);
503}
504
505static void output_interface_prerequisites (void)
506{
507 FILE *fp;
508
509 fp = fopen (prerequisites_filename, "w");
510 if (fp == NULL((void*)0)) {
511 g_warning ("Couldn't open output file: %s : %s", prerequisites_filename, g_strerror(errno(*__errno_location ())));
512 return;
513 }
514 output_prerequisites (fp, G_TYPE_INTERFACE((GType) ((2) << (2))));
515 fclose (fp);
516}
517
518static void
519output_prerequisites (FILE *fp,
520 GType type)
521{
522#if GLIB_CHECK_VERSION(2,1,0)(2 > (2) || (2 == (2) && 78 > (1)) || (2 == (2)
&& 78 == (1) && 3 >= (0)))
523 guint i;
524 GType *children, *prerequisites;
525 guint n_children, n_prerequisites;
526
527 if (!type)
528 return;
529
530 prerequisites = g_type_interface_prerequisites (type, &n_prerequisites);
531
532 if (n_prerequisites > 0) {
533 fprintf (fp, "%s", g_type_name (type));
534 for (i=0; i < n_prerequisites; i++)
535 fprintf (fp, " %s", g_type_name (prerequisites[i]));
536 fprintf (fp, "\n");
537 }
538 g_free (prerequisites);
539
540 children = g_type_children (type, &n_children);
541
542 for (i=0; i < n_children; i++)
543 output_prerequisites (fp, children[i]);
544
545 g_free (children);
546#endif
547}
548
549static void
550output_actions (void)
551{
552 FILE *fp;
553 gint i;
554
555 fp = fopen (actions_filename, "w");
556 if (fp == NULL((void*)0)) {
557 g_warning ("Couldn't open output file: %s : %s", actions_filename, g_strerror(errno(*__errno_location ())));
558 return;
559 }
560
561 for (i = 0; object_types[i]; i++) {
562 output_object_actions (fp, object_types[i]);
563 }
564
565 fclose (fp);
566}
567
568static void
569output_object_actions (FILE *fp, GType object_type)
570{
571 gpointer class;
572
573 if (!G_TYPE_IS_OBJECT (object_type)((g_type_fundamental (object_type)) == ((GType) ((20) <<
(2))))
)
574 return;
575
576 class = g_type_class_peek (object_type);
577 if (!class)
578 return;
579
580#ifdef GTK_IS_WIDGET_CLASS
581#if GTK_CHECK_VERSION(3,96,0)((3) > (3) || ((3) == (3) && (24) > (96)) || ((
3) == (3) && (24) == (96) && (41) >= (0)))
582 if (GTK_IS_WIDGET_CLASS (class)(((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((class
)); GType __t = ((gtk_widget_get_type ())); gboolean __r; if (
!__class) __r = (0); else if (__class->g_type == __t) __r =
(!(0)); else __r = g_type_check_class_is_a (__class, __t); __r
; }))))
) {
583 guint i = 0;
584 const char *action_name;
585 GType owner;
586 const GVariantType *parameter_type;
587 const char *property_name;
588 const gchar *object_class_name;
589
590 object_class_name = g_type_name (object_type);
591 while (gtk_widget_class_query_action (GTK_WIDGET_CLASS (class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), ((gtk_widget_get_type ()))))))
,
592 i,
593 &owner,
594 &action_name,
595 &parameter_type,
596 &property_name)) {
597 i++;
598 if (owner == G_TYPE_FROM_CLASS (class)(((GTypeClass*) (class))->g_type))
599 fprintf (fp, "<ACTION>\n"
600 "<NAME>%s:::%s</NAME>\n"
601 "<PARAMETER>%s</PARAMETER>\n"
602 "<PROPERTY>%s</PROPERTY>\n"
603 "</ACTION>\n\n",
604 object_class_name,
605 action_name,
606 parameter_type ? g_variant_type_peek_string (parameter_type) : "",
607 property_name ? property_name : "");
608 }
609 }
610#endif
611#endif
612}
613
614static void
615output_args (void)
616{
617 FILE *fp;
618 gint i;
619
620 fp = fopen (args_filename, "w");
621 if (fp == NULL((void*)0)) {
622 g_warning ("Couldn't open output file: %s : %s", args_filename, g_strerror(errno(*__errno_location ())));
623 return;
624 }
625
626 for (i = 0; object_types[i]; i++) {
627 output_object_args (fp, object_types[i]);
628 }
629
630 fclose (fp);
631}
632
633static gint
634compare_param_specs (const void *a, const void *b)
635{
636 GParamSpec *spec_a = *(GParamSpec **)a;
637 GParamSpec *spec_b = *(GParamSpec **)b;
638
639 return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b));
640}
641
642/* Its common to have unsigned properties restricted
643 * to the signed range. Therefore we make this look
644 * a bit nicer by spelling out the max constants.
645 */
646
647/* Don't use "==" with floats, it might trigger a gcc warning. */
648#define GTKDOC_COMPARE_FLOAT(x, y)(x <= y && x >= y) (x <= y && x >= y)
649
650static gchar*
651describe_double_constant (gdouble value)
652{
653 gchar *desc;
654
655 if (GTKDOC_COMPARE_FLOAT (value, G_MAXDOUBLE)(value <= 1.7976931348623157e+308 && value >= 1.7976931348623157e+308
)
)
656 desc = g_strdup ("G_MAXDOUBLE")g_strdup_inline ("G_MAXDOUBLE");
657 else if (GTKDOC_COMPARE_FLOAT (value, G_MINDOUBLE)(value <= 2.2250738585072014e-308 && value >= 2.2250738585072014e-308
)
)
658 desc = g_strdup ("G_MINDOUBLE")g_strdup_inline ("G_MINDOUBLE");
659 else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXDOUBLE)(value <= -1.7976931348623157e+308 && value >= -
1.7976931348623157e+308)
)
660 desc = g_strdup ("-G_MAXDOUBLE")g_strdup_inline ("-G_MAXDOUBLE");
661 else if (GTKDOC_COMPARE_FLOAT (value, (gdouble)G_MAXFLOAT)(value <= (gdouble)3.40282347e+38F && value >= (
gdouble)3.40282347e+38F)
)
662 desc = g_strdup ("G_MAXFLOAT")g_strdup_inline ("G_MAXFLOAT");
663 else if (GTKDOC_COMPARE_FLOAT (value, (gdouble)G_MINFLOAT)(value <= (gdouble)1.17549435e-38F && value >= (
gdouble)1.17549435e-38F)
)
664 desc = g_strdup ("G_MINFLOAT")g_strdup_inline ("G_MINFLOAT");
665 else if (GTKDOC_COMPARE_FLOAT (value, (gdouble)-G_MAXFLOAT)(value <= (gdouble)-3.40282347e+38F && value >=
(gdouble)-3.40282347e+38F)
)
666 desc = g_strdup ("-G_MAXFLOAT")g_strdup_inline ("-G_MAXFLOAT");
667 else{
668 /* make sure floats are output with a decimal dot irrespective of
669 * current locale. Use formatd since we want human-readable numbers
670 * and do not need the exact same bit representation when deserialising */
671 desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE(29 + 10));
672 g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE(29 + 10), "%g", value);
673 }
674
675 return desc;
676}
677
678static gchar*
679describe_signed_constant (gsize size, gint64 value)
680{
681 gchar *desc = NULL((void*)0);
682
683 switch (size) {
684 case 2:
685 if (sizeof (int) == 2) {
686 if (value == G_MAXINT2147483647)
687 desc = g_strdup ("G_MAXINT")g_strdup_inline ("G_MAXINT");
688 else if (value == G_MININT(-2147483647 -1))
689 desc = g_strdup ("G_MININT")g_strdup_inline ("G_MININT");
690 }
691 break;
692 case 4:
693 if (sizeof (int) == 4) {
694 if (value == G_MAXINT2147483647)
695 desc = g_strdup ("G_MAXINT")g_strdup_inline ("G_MAXINT");
696 else if (value == G_MININT(-2147483647 -1))
697 desc = g_strdup ("G_MININT")g_strdup_inline ("G_MININT");
698 }
699 if (value == G_MAXLONG9223372036854775807L)
700 desc = g_strdup ("G_MAXLONG")g_strdup_inline ("G_MAXLONG");
701 else if (value == G_MINLONG(-9223372036854775807L -1L))
702 desc = g_strdup ("G_MINLONG")g_strdup_inline ("G_MINLONG");
703 break;
704 case 8:
705 if (value == G_MAXINT64(0x7fffffffffffffffL))
706 desc = g_strdup ("G_MAXINT64")g_strdup_inline ("G_MAXINT64");
707 else if (value == G_MININT64((gint64) (-(0x7fffffffffffffffL) - (1L))))
708 desc = g_strdup ("G_MININT64")g_strdup_inline ("G_MININT64");
709 break;
710 default:
711 break;
712 }
713 if (!desc)
714 desc = g_strdup_printf ("%" G_GINT64_FORMAT"li", value);
715
716 return desc;
717}
718
719static gchar*
720describe_unsigned_constant (gsize size, guint64 value)
721{
722 gchar *desc = NULL((void*)0);
723
724 switch (size) {
725 case 2:
726 if (sizeof (int) == 2) {
727 if (value == (guint64)G_MAXINT2147483647)
728 desc = g_strdup ("G_MAXINT")g_strdup_inline ("G_MAXINT");
729 else if (value == G_MAXUINT(2147483647 *2U +1U))
730 desc = g_strdup ("G_MAXUINT")g_strdup_inline ("G_MAXUINT");
731 }
732 break;
733 case 4:
734 if (sizeof (int) == 4) {
735 if (value == (guint64)G_MAXINT2147483647)
736 desc = g_strdup ("G_MAXINT")g_strdup_inline ("G_MAXINT");
737 else if (value == G_MAXUINT(2147483647 *2U +1U))
738 desc = g_strdup ("G_MAXUINT")g_strdup_inline ("G_MAXUINT");
739 }
740 if (desc == NULL((void*)0)) {
741 if (value == (guint64)G_MAXLONG9223372036854775807L)
742 desc = g_strdup ("G_MAXLONG")g_strdup_inline ("G_MAXLONG");
743 else if (value == G_MAXULONG(9223372036854775807L *2UL+1UL))
744 desc = g_strdup ("G_MAXULONG")g_strdup_inline ("G_MAXULONG");
745 }
746 break;
747 case 8:
748 if (value == G_MAXINT64(0x7fffffffffffffffL))
749 desc = g_strdup ("G_MAXINT64")g_strdup_inline ("G_MAXINT64");
750 else if (value == G_MAXUINT64(0xffffffffffffffffUL))
751 desc = g_strdup ("G_MAXUINT64")g_strdup_inline ("G_MAXUINT64");
752 break;
753 default:
754 break;
755 }
756 if (!desc)
757 desc = g_strdup_printf ("%" G_GUINT64_FORMAT"lu", value);
758
759 return desc;
760}
761
762static gchar*
763describe_type (GParamSpec *spec)
764{
765 gchar *desc;
766 gchar *lower;
767 gchar *upper;
768
769 if (G_IS_PARAM_SPEC_CHAR (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[0])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
770 GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec)((((GParamSpecChar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[0]))))))
;
771
772 lower = describe_signed_constant (sizeof(gchar), pspec->minimum);
773 upper = describe_signed_constant (sizeof(gchar), pspec->maximum);
774 if (pspec->minimum == G_MININT8((gint8) (-((gint8) 0x7f) - 1)) && pspec->maximum == G_MAXINT8((gint8) 0x7f))
775 desc = g_strdup ("")g_strdup_inline ("");
776 else if (pspec->minimum == G_MININT8((gint8) (-((gint8) 0x7f) - 1)))
777 desc = g_strdup_printf ("<= %s", upper);
778 else if (pspec->maximum == G_MAXINT8((gint8) 0x7f))
779 desc = g_strdup_printf (">= %s", lower);
780 else
781 desc = g_strdup_printf ("[%s,%s]", lower, upper);
782 g_free (lower);
783 g_free (upper);
784 }
785 else if (G_IS_PARAM_SPEC_UCHAR (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[1])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
786 GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec)((((GParamSpecUChar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[1]))))))
;
787
788 lower = describe_unsigned_constant (sizeof(guchar), pspec->minimum);
789 upper = describe_unsigned_constant (sizeof(guchar), pspec->maximum);
790 if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8((guint8) 0xff))
791 desc = g_strdup ("")g_strdup_inline ("");
792 else if (pspec->minimum == 0)
793 desc = g_strdup_printf ("<= %s", upper);
794 else if (pspec->maximum == G_MAXUINT8((guint8) 0xff))
795 desc = g_strdup_printf (">= %s", lower);
796 else
797 desc = g_strdup_printf ("[%s,%s]", lower, upper);
798 g_free (lower);
799 g_free (upper);
800 }
801 else if (G_IS_PARAM_SPEC_INT (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[3])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
802 GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec)((((GParamSpecInt*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[3]))))))
;
803
804 lower = describe_signed_constant (sizeof(gint), pspec->minimum);
805 upper = describe_signed_constant (sizeof(gint), pspec->maximum);
806 if (pspec->minimum == G_MININT(-2147483647 -1) && pspec->maximum == G_MAXINT2147483647)
807 desc = g_strdup ("")g_strdup_inline ("");
808 else if (pspec->minimum == G_MININT(-2147483647 -1))
809 desc = g_strdup_printf ("<= %s", upper);
810 else if (pspec->maximum == G_MAXINT2147483647)
811 desc = g_strdup_printf (">= %s", lower);
812 else
813 desc = g_strdup_printf ("[%s,%s]", lower, upper);
814 g_free (lower);
815 g_free (upper);
816 }
817 else if (G_IS_PARAM_SPEC_UINT (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[4])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
818 GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec)((((GParamSpecUInt*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[4]))))))
;
819
820 lower = describe_unsigned_constant (sizeof(guint), pspec->minimum);
821 upper = describe_unsigned_constant (sizeof(guint), pspec->maximum);
822 if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT(2147483647 *2U +1U))
823 desc = g_strdup ("")g_strdup_inline ("");
824 else if (pspec->minimum == 0)
825 desc = g_strdup_printf ("<= %s", upper);
826 else if (pspec->maximum == G_MAXUINT(2147483647 *2U +1U))
827 desc = g_strdup_printf (">= %s", lower);
828 else
829 desc = g_strdup_printf ("[%s,%s]", lower, upper);
830 g_free (lower);
831 g_free (upper);
832 }
833 else if (G_IS_PARAM_SPEC_LONG (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[5])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
834 GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec)((((GParamSpecLong*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[5]))))))
;
835
836 lower = describe_signed_constant (sizeof(glong), pspec->minimum);
837 upper = describe_signed_constant (sizeof(glong), pspec->maximum);
838 if (pspec->minimum == G_MINLONG(-9223372036854775807L -1L) && pspec->maximum == G_MAXLONG9223372036854775807L)
839 desc = g_strdup ("")g_strdup_inline ("");
840 else if (pspec->minimum == G_MINLONG(-9223372036854775807L -1L))
841 desc = g_strdup_printf ("<= %s", upper);
842 else if (pspec->maximum == G_MAXLONG9223372036854775807L)
843 desc = g_strdup_printf (">= %s", lower);
844 else
845 desc = g_strdup_printf ("[%s,%s]", lower, upper);
846 g_free (lower);
847 g_free (upper);
848 }
849 else if (G_IS_PARAM_SPEC_ULONG (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[6])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
850 GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec)((((GParamSpecULong*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[6]))))))
;
851
852 lower = describe_unsigned_constant (sizeof(gulong), pspec->minimum);
853 upper = describe_unsigned_constant (sizeof(gulong), pspec->maximum);
854 if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG(9223372036854775807L *2UL+1UL))
855 desc = g_strdup ("")g_strdup_inline ("");
856 else if (pspec->minimum == 0)
857 desc = g_strdup_printf ("<= %s", upper);
858 else if (pspec->maximum == G_MAXULONG(9223372036854775807L *2UL+1UL))
859 desc = g_strdup_printf (">= %s", lower);
860 else
861 desc = g_strdup_printf ("[%s,%s]", lower, upper);
862 g_free (lower);
863 g_free (upper);
864 }
865 else if (G_IS_PARAM_SPEC_INT64 (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[7])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
866 GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec)((((GParamSpecInt64*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[7]))))))
;
867
868 lower = describe_signed_constant (sizeof(gint64), pspec->minimum);
869 upper = describe_signed_constant (sizeof(gint64), pspec->maximum);
870 if (pspec->minimum == G_MININT64((gint64) (-(0x7fffffffffffffffL) - (1L))) && pspec->maximum == G_MAXINT64(0x7fffffffffffffffL))
871 desc = g_strdup ("")g_strdup_inline ("");
872 else if (pspec->minimum == G_MININT64((gint64) (-(0x7fffffffffffffffL) - (1L))))
873 desc = g_strdup_printf ("<= %s", upper);
874 else if (pspec->maximum == G_MAXINT64(0x7fffffffffffffffL))
875 desc = g_strdup_printf (">= %s", lower);
876 else
877 desc = g_strdup_printf ("[%s,%s]", lower, upper);
878 g_free (lower);
879 g_free (upper);
880 }
881 else if (G_IS_PARAM_SPEC_UINT64 (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[8])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
882 GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec)((((GParamSpecUInt64*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((spec)), ((g_param_spec_types[8]))))))
;
883
884 lower = describe_unsigned_constant (sizeof(guint64), pspec->minimum);
885 upper = describe_unsigned_constant (sizeof(guint64), pspec->maximum);
886 if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64(0xffffffffffffffffUL))
887 desc = g_strdup ("")g_strdup_inline ("");
888 else if (pspec->minimum == 0)
889 desc = g_strdup_printf ("<= %s", upper);
890 else if (pspec->maximum == G_MAXUINT64(0xffffffffffffffffUL))
891 desc = g_strdup_printf (">= %s", lower);
892 else
893 desc = g_strdup_printf ("[%s,%s]", lower, upper);
894 g_free (lower);
895 g_free (upper);
896 }
897 else if (G_IS_PARAM_SPEC_FLOAT (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[12])); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
898 GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec)((((GParamSpecFloat*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[12]))))))
;
899
900 lower = describe_double_constant (pspec->minimum);
901 upper = describe_double_constant (pspec->maximum);
902 if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXFLOAT)(pspec->minimum <= -3.40282347e+38F && pspec->
minimum >= -3.40282347e+38F)
) {
903 if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT)(pspec->maximum <= 3.40282347e+38F && pspec->
maximum >= 3.40282347e+38F)
)
904 desc = g_strdup ("")g_strdup_inline ("");
905 else
906 desc = g_strdup_printf ("<= %s", upper);
907 }
908 else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT)(pspec->maximum <= 3.40282347e+38F && pspec->
maximum >= 3.40282347e+38F)
)
909 desc = g_strdup_printf (">= %s", lower);
910 else
911 desc = g_strdup_printf ("[%s,%s]", lower, upper);
912 g_free (lower);
913 g_free (upper);
914 }
915 else if (G_IS_PARAM_SPEC_DOUBLE (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[13])); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
916 GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec)((((GParamSpecDouble*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((spec)), ((g_param_spec_types[13]))))))
;
917
918 lower = describe_double_constant (pspec->minimum);
919 upper = describe_double_constant (pspec->maximum);
920 if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXDOUBLE)(pspec->minimum <= -1.7976931348623157e+308 && pspec
->minimum >= -1.7976931348623157e+308)
) {
921 if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE)(pspec->maximum <= 1.7976931348623157e+308 && pspec
->maximum >= 1.7976931348623157e+308)
)
922 desc = g_strdup ("")g_strdup_inline ("");
923 else
924 desc = g_strdup_printf ("<= %s", upper);
925 }
926 else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE)(pspec->maximum <= 1.7976931348623157e+308 && pspec
->maximum >= 1.7976931348623157e+308)
)
927 desc = g_strdup_printf (">= %s", lower);
928 else
929 desc = g_strdup_printf ("[%s,%s]", lower, upper);
930 g_free (lower);
931 g_free (upper);
932 }
933#if GLIB_CHECK_VERSION (2, 12, 0)(2 > (2) || (2 == (2) && 78 > (12)) || (2 == (2
) && 78 == (12) && 3 >= (0)))
934 else if (G_IS_PARAM_SPEC_GTYPE (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[21])); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
935 GParamSpecGType *pspec = G_PARAM_SPEC_GTYPE (spec)((((GParamSpecGType*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[21]))))))
;
936 gboolean is_pointer;
937
938 desc = g_strdup (get_type_name (pspec->is_a_type, &is_pointer))g_strdup_inline (get_type_name (pspec->is_a_type, &is_pointer
))
;
939 }
940#endif
941#if GLIB_CHECK_VERSION (2, 25, 9)(2 > (2) || (2 == (2) && 78 > (25)) || (2 == (2
) && 78 == (25) && 3 >= (9)))
942 else if (G_IS_PARAM_SPEC_VARIANT (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[22])); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
943 GParamSpecVariant *pspec = G_PARAM_SPEC_VARIANT (spec)((((GParamSpecVariant*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((spec)), ((g_param_spec_types[22]))))))
;
944 gchar *variant_type;
945
946 variant_type = g_variant_type_dup_string (pspec->type);
947 desc = g_strdup_printf ("GVariant<%s>", variant_type);
948 g_free (variant_type);
949 }
950#endif
951 else {
952 desc = g_strdup ("")g_strdup_inline ("");
953 }
954
955 return desc;
956}
957
958static gchar*
959describe_default (GParamSpec *spec)
960{
961 gchar *desc;
962
963 if (G_IS_PARAM_SPEC_CHAR (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[0])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
964 GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec)((((GParamSpecChar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[0]))))))
;
965
966 desc = g_strdup_printf ("%d", pspec->default_value);
967 }
968 else if (G_IS_PARAM_SPEC_UCHAR (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[1])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
969 GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec)((((GParamSpecUChar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[1]))))))
;
970
971 desc = g_strdup_printf ("%u", pspec->default_value);
972 }
973 else if (G_IS_PARAM_SPEC_BOOLEAN (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[2])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
974 GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec)((((GParamSpecBoolean*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((spec)), ((g_param_spec_types[2]))))))
;
975
976 desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE");
977 }
978 else if (G_IS_PARAM_SPEC_INT (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[3])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
979 GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec)((((GParamSpecInt*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[3]))))))
;
980
981 desc = g_strdup_printf ("%d", pspec->default_value);
982 }
983 else if (G_IS_PARAM_SPEC_UINT (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[4])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
984 GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec)((((GParamSpecUInt*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[4]))))))
;
985
986 desc = g_strdup_printf ("%u", pspec->default_value);
987 }
988 else if (G_IS_PARAM_SPEC_LONG (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[5])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
989 GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec)((((GParamSpecLong*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[5]))))))
;
990
991 desc = g_strdup_printf ("%ld", pspec->default_value);
992 }
993 else if (G_IS_PARAM_SPEC_LONG (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[5])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
994 GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec)((((GParamSpecULong*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[6]))))))
;
995
996 desc = g_strdup_printf ("%lu", pspec->default_value);
997 }
998 else if (G_IS_PARAM_SPEC_INT64 (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[7])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
999 GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec)((((GParamSpecInt64*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[7]))))))
;
1000
1001 desc = g_strdup_printf ("%" G_GINT64_FORMAT"li", pspec->default_value);
1002 }
1003 else if (G_IS_PARAM_SPEC_UINT64 (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[8])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1004 {
1005 GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec)((((GParamSpecUInt64*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((spec)), ((g_param_spec_types[8]))))))
;
1006
1007 desc = g_strdup_printf ("%" G_GUINT64_FORMAT"lu", pspec->default_value);
1008 }
1009 else if (G_IS_PARAM_SPEC_UNICHAR (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[9])); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
1010 GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec)((((GParamSpecUnichar*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((spec)), ((g_param_spec_types[9]))))))
;
1011
1012 if (g_unichar_isprint (pspec->default_value))
1013 desc = g_strdup_printf ("'%c'", pspec->default_value);
1014 else
1015 desc = g_strdup_printf ("%u", pspec->default_value);
1016 }
1017 else if (G_IS_PARAM_SPEC_ENUM (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[10])); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
1018 GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec)((((GParamSpecEnum*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[10]))))))
;
1019
1020 GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value);
1021 if (value)
1022 desc = g_strdup_printf ("%s", value->value_name);
1023 else
1024 desc = g_strdup_printf ("%d", pspec->default_value);
1025 }
1026 else if (G_IS_PARAM_SPEC_FLAGS (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[11])); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
1027 GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec)((((GParamSpecFlags*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[11]))))))
;
1028 guint default_value;
1029 GString *acc;
1030
1031 default_value = pspec->default_value;
1032 acc = g_string_new ("");
1033
1034 while (default_value) {
1035 GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value);
1036
1037 if (!value)
1038 break;
1039
1040 if (acc->len > 0)
1041 g_string_append (acc, " | ")(__builtin_constant_p (" | ") ? __extension__ ({ const char *
const __val = (" | "); g_string_append_len_inline (acc, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (acc, " | "
, (gssize) -1))
;
1042 g_string_append (acc, value->value_name)(__builtin_constant_p (value->value_name) ? __extension__ (
{ const char * const __val = (value->value_name); g_string_append_len_inline
(acc, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(acc, value->value_name, (gssize) -1))
;
1043
1044 default_value &= ~value->value;
1045 }
1046
1047 if (default_value == 0)
1048 desc = g_string_free (acc, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((acc)
, ((0))) : g_string_free_and_steal (acc)) : (g_string_free) (
(acc), ((0))))
;
1049 else {
1050 desc = g_strdup_printf ("%d", pspec->default_value);
1051 g_string_free (acc, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(acc), ((!(0)))) : g_string_free_and_steal (acc)) : (g_string_free
) ((acc), ((!(0)))))
;
1052 }
1053 }
1054 else if (G_IS_PARAM_SPEC_FLOAT (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[12])); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
1055 GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec)((((GParamSpecFloat*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((spec)), ((g_param_spec_types[12]))))))
;
1056
1057 /* make sure floats are output with a decimal dot irrespective of
1058 * current locale. Use formatd since we want human-readable numbers
1059 * and do not need the exact same bit representation when deserialising */
1060 desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE(29 + 10));
1061 g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE(29 + 10), "%g",
1062 pspec->default_value);
1063 }
1064 else if (G_IS_PARAM_SPEC_DOUBLE (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[13])); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
1065 GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec)((((GParamSpecDouble*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((spec)), ((g_param_spec_types[13]))))))
;
1066
1067 /* make sure floats are output with a decimal dot irrespective of
1068 * current locale. Use formatd since we want human-readable numbers
1069 * and do not need the exact same bit representation when deserialising */
1070 desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE(29 + 10));
1071 g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE(29 + 10), "%g",
1072 pspec->default_value);
1073 }
1074 else if (G_IS_PARAM_SPEC_STRING (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[14])); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
1075 GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec)((((GParamSpecString*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((spec)), ((g_param_spec_types[14]))))))
;
1076
1077 if (pspec->default_value) {
1078 gchar *esc = g_strescape (pspec->default_value, NULL((void*)0));
1079 desc = g_strdup_printf ("\"%s\"", esc);
1080 g_free (esc);
1081 }
1082 else
1083 desc = g_strdup_printf ("NULL");
1084 }
1085#if GLIB_CHECK_VERSION (2, 25, 9)(2 > (2) || (2 == (2) && 78 > (25)) || (2 == (2
) && 78 == (25) && 3 >= (9)))
1086 else if (G_IS_PARAM_SPEC_VARIANT (spec)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(spec)); GType __t = ((g_param_spec_types[22])); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) {
1087 GParamSpecVariant *pspec = G_PARAM_SPEC_VARIANT (spec)((((GParamSpecVariant*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((spec)), ((g_param_spec_types[22]))))))
;
1088
1089 if (pspec->default_value)
1090 desc = g_variant_print (pspec->default_value, TRUE(!(0)));
1091 else
1092 desc = g_strdup ("NULL")g_strdup_inline ("NULL");
1093 }
1094#endif
1095 else {
1096 desc = g_strdup ("")g_strdup_inline ("");
1097 }
1098
1099 return desc;
1100}
1101
1102
1103static void
1104output_object_args (FILE *fp, GType object_type)
1105{
1106 gpointer class;
1107 const gchar *object_class_name;
1108 guint arg;
1109 gchar flags[16], *pos;
1110 GParamSpec **properties;
1111 guint n_properties;
1112 gboolean child_prop;
1113 gboolean style_prop;
1114 gboolean is_pointer;
1115 const gchar *type_name;
1116 gchar *type_desc;
1117 gchar *default_value;
1118
1119 if (G_TYPE_IS_OBJECT (object_type)((g_type_fundamental (object_type)) == ((GType) ((20) <<
(2))))
) {
1120 class = g_type_class_peek (object_type);
1121 if (!class)
1122 return;
1123
1124 properties = g_object_class_list_properties (class, &n_properties);
1125 }
1126#if GLIB_MAJOR_VERSION2 > 2 || (GLIB_MAJOR_VERSION2 == 2 && GLIB_MINOR_VERSION78 >= 3)
1127 else if (G_TYPE_IS_INTERFACE (object_type)((g_type_fundamental (object_type)) == ((GType) ((2) <<
(2))))
) {
1128 class = g_type_default_interface_ref (object_type);
1129
1130 if (!class)
1131 return;
1132
1133 properties = g_object_interface_list_properties (class, &n_properties);
1134 }
1135#endif
1136 else
1137 return;
1138
1139 object_class_name = g_type_name (object_type);
1140
1141 child_prop = FALSE(0);
1142 style_prop = FALSE(0);
1143
1144 while (TRUE(!(0))) {
1145 if (n_properties > 0)
1146 qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
1147 for (arg = 0; arg < n_properties; arg++) {
1148 GParamSpec *spec = properties[arg];
1149 const gchar *nick, *blurb, *dot;
1150
1151 if (spec->owner_type != object_type)
1152 continue;
1153
1154 pos = flags;
1155 /* We use one-character flags for simplicity. */
1156 if (child_prop && !style_prop)
1157 *pos++ = 'c';
1158 if (style_prop)
1159 *pos++ = 's';
1160 if (spec->flags & G_PARAM_READABLE)
1161 *pos++ = 'r';
1162 if (spec->flags & G_PARAM_WRITABLE)
1163 *pos++ = 'w';
1164 if (spec->flags & G_PARAM_CONSTRUCT)
1165 *pos++ = 'x';
1166 if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
1167 *pos++ = 'X';
1168 *pos = 0;
1169
1170 nick = g_param_spec_get_nick (spec);
1171 blurb = g_param_spec_get_blurb (spec);
1172
1173 dot = "";
1174 if (blurb) {
1175 int str_len = strlen (blurb);
1176 if (str_len > 0 && blurb[str_len - 1] != '.')
1177 dot = ".";
1178 }
1179
1180 type_desc = describe_type (spec);
1181 default_value = describe_default (spec);
1182 type_name = get_type_name (spec->value_type, &is_pointer);
1183 fprintf (fp, "<ARG>\n"
1184 "<NAME>%s::%s</NAME>\n"
1185 "<TYPE>%s%s</TYPE>\n"
1186 "<RANGE>%s</RANGE>\n"
1187 "<FLAGS>%s</FLAGS>\n"
1188 "<NICK>%s</NICK>\n"
1189 "<BLURB>%s%s</BLURB>\n"
1190 "<DEFAULT>%s</DEFAULT>\n"
1191 "</ARG>\n\n",
1192 object_class_name, g_param_spec_get_name (spec), type_name,
1193 is_pointer ? "*" : "", type_desc, flags, nick ? nick : "(null)",
1194 blurb ? blurb : "(null)", dot, default_value);
1195 g_free (type_desc);
1196 g_free (default_value);
1197 }
1198
1199 g_free (properties);
1200
1201#ifdef GTK_IS_CONTAINER_CLASS
1202#if !GTK_CHECK_VERSION(3,96,0)((3) > (3) || ((3) == (3) && (24) > (96)) || ((
3) == (3) && (24) == (96) && (41) >= (0)))
1203 if (!child_prop && GTK_IS_CONTAINER_CLASS (class)(((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((class
)); GType __t = ((gtk_container_get_type ())); gboolean __r; if
(!__class) __r = (0); else if (__class->g_type == __t) __r
= (!(0)); else __r = g_type_check_class_is_a (__class, __t);
__r; }))))
) {
1204 properties = gtk_container_class_list_child_properties (class, &n_properties);
1205 child_prop = TRUE(!(0));
1206 continue;
1207 }
1208#endif
1209#endif
1210
1211#ifdef GTK_IS_CELL_AREA_CLASS
1212 if (!child_prop && GTK_IS_CELL_AREA_CLASS (class)(((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((class
)); GType __t = ((gtk_cell_area_get_type ())); gboolean __r; if
(!__class) __r = (0); else if (__class->g_type == __t) __r
= (!(0)); else __r = g_type_check_class_is_a (__class, __t);
__r; }))))
) {
1213 properties = gtk_cell_area_class_list_cell_properties (class, &n_properties);
1214 child_prop = TRUE(!(0));
1215 continue;
1216 }
1217#endif
1218
1219#ifdef GTK_IS_WIDGET_CLASS
1220#if GTK_CHECK_VERSION(2,1,0)((3) > (2) || ((3) == (2) && (24) > (1)) || ((3
) == (2) && (24) == (1) && (41) >= (0)))
&& !GTK_CHECK_VERSION(3,89,2)((3) > (3) || ((3) == (3) && (24) > (89)) || ((
3) == (3) && (24) == (89) && (41) >= (2)))
1221 if (!style_prop && GTK_IS_WIDGET_CLASS (class)(((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((class
)); GType __t = ((gtk_widget_get_type ())); gboolean __r; if (
!__class) __r = (0); else if (__class->g_type == __t) __r =
(!(0)); else __r = g_type_check_class_is_a (__class, __t); __r
; }))))
) {
1222 properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), ((gtk_widget_get_type ()))))))
, &n_properties);
1223 style_prop = TRUE(!(0));
1224 continue;
1225 }
1226#endif
1227#endif
1228
1229
1230 break;
1231 }
1232}
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-2f348d.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-2f348d.html new file mode 100644 index 0000000..da1dfda --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-2f348d.html @@ -0,0 +1,3591 @@ + + + +mate-colorsel.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-colorsel.c
Warning:line 1876, column 20
Use of memory after it is freed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-colorsel.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-colorsel.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* GTK - The GIMP Toolkit
2 * Copyright (C) 2000 Red Hat, Inc.
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library 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 GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20
21/*
22 * Modified by the GTK+ Team and others 1997-2001. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
26 */
27
28#include "config.h"
29#include "private.h"
30#include <math.h>
31#include <string.h>
32
33#include <gdk/gdkx.h>
34#include <gdk/gdkkeysyms.h>
35#include <gtk/gtk.h>
36#include <glib/gi18n-lib.h>
37#include "mate-colorsel.h"
38#include "mate-hsv.h"
39
40#define DEFAULT_COLOR_PALETTE"#ef2929:#fcaf3e:#fce94f:#8ae234:#729fcf:#ad7fa8:#e9b96e:#888a85:#eeeeec:#cc0000:#f57900:#edd400:#73d216:#3465a4:#75507b:#c17d11:#555753:#d3d7cf:#a40000:#ce5c00:#c4a000:#4e9a06:#204a87:#5c3566:#8f5902:#2e3436:#babdb6:#000000:#2e3436:#555753:#888a85:#babdb6:#d3d7cf:#eeeeec:#f3f3f3:#ffffff" "#ef2929:#fcaf3e:#fce94f:#8ae234:#729fcf:#ad7fa8:#e9b96e:#888a85:#eeeeec:#cc0000:#f57900:#edd400:#73d216:#3465a4:#75507b:#c17d11:#555753:#d3d7cf:#a40000:#ce5c00:#c4a000:#4e9a06:#204a87:#5c3566:#8f5902:#2e3436:#babdb6:#000000:#2e3436:#555753:#888a85:#babdb6:#d3d7cf:#eeeeec:#f3f3f3:#ffffff"
41
42/* Number of elements in the custom palatte */
43#define GTK_CUSTOM_PALETTE_WIDTH9 9
44#define GTK_CUSTOM_PALETTE_HEIGHT4 4
45
46#define CUSTOM_PALETTE_ENTRY_WIDTH20 20
47#define CUSTOM_PALETTE_ENTRY_HEIGHT20 20
48
49/* The cursor for the dropper */
50#define DROPPER_WIDTH16 16
51#define DROPPER_HEIGHT16 16
52#define DROPPER_STRIDE64 64
53#define DROPPER_X_HOT2 2
54#define DROPPER_Y_HOT16 16
55
56#define CHECK_SIZE16 16
57#define BIG_STEP20 20
58
59/* Conversion between 0->1 double and and guint16. See
60 * scale_round() below for more general conversions
61 */
62#define SCALE(i)(i / 65535.) (i / 65535.)
63#define UNSCALE(d)((guint16)(d * 65535 + 0.5)) ((guint16)(d * 65535 + 0.5))
64#define INTENSITY(r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
65
66enum {
67 COLOR_CHANGED,
68 LAST_SIGNAL
69};
70
71enum {
72 PROP_0,
73 PROP_HAS_PALETTE,
74 PROP_HAS_OPACITY_CONTROL,
75 PROP_CURRENT_RGBA,
76 PROP_CURRENT_ALPHA,
77 PROP_HEX_STRING
78};
79
80enum {
81 COLORSEL_RED = 0,
82 COLORSEL_GREEN = 1,
83 COLORSEL_BLUE = 2,
84 COLORSEL_OPACITY = 3,
85 COLORSEL_HUE,
86 COLORSEL_SATURATION,
87 COLORSEL_VALUE,
88 COLORSEL_NUM_CHANNELS
89};
90
91struct _MateColorSelectionPrivate
92{
93 guint has_opacity : 1;
94 guint has_palette : 1;
95 guint changing : 1;
96 guint default_set : 1;
97 guint default_alpha_set : 1;
98 guint has_grab : 1;
99
100 gdouble color[COLORSEL_NUM_CHANNELS];
101 gdouble old_color[COLORSEL_NUM_CHANNELS];
102
103 GtkWidget *triangle_colorsel;
104 GtkWidget *hue_spinbutton;
105 GtkWidget *sat_spinbutton;
106 GtkWidget *val_spinbutton;
107 GtkWidget *red_spinbutton;
108 GtkWidget *green_spinbutton;
109 GtkWidget *blue_spinbutton;
110 GtkWidget *opacity_slider;
111 GtkWidget *opacity_label;
112 GtkWidget *opacity_entry;
113 GtkWidget *palette_frame;
114 GtkWidget *hex_entry;
115
116 /* The Palette code */
117 GtkWidget *custom_palette [GTK_CUSTOM_PALETTE_WIDTH9][GTK_CUSTOM_PALETTE_HEIGHT4];
118
119 /* The color_sample stuff */
120 GtkWidget *sample_area;
121 GtkWidget *old_sample;
122 GtkWidget *cur_sample;
123 GtkWidget *colorsel;
124
125 /* Window for grabbing on */
126 GtkWidget *dropper_grab_widget;
127 guint32 grab_time;
128
129 /* Connection to settings */
130 gulong settings_connection;
131};
132
133static void mate_color_selection_dispose (GObject *object);
134static void mate_color_selection_finalize (GObject *object);
135static void update_color (MateColorSelection *colorsel);
136static void mate_color_selection_set_property (GObject *object,
137 guint prop_id,
138 const GValue *value,
139 GParamSpec *pspec);
140static void mate_color_selection_get_property (GObject *object,
141 guint prop_id,
142 GValue *value,
143 GParamSpec *pspec);
144
145static void mate_color_selection_realize (GtkWidget *widget);
146static void mate_color_selection_unrealize (GtkWidget *widget);
147static void mate_color_selection_show_all (GtkWidget *widget);
148static gboolean mate_color_selection_grab_broken (GtkWidget *widget,
149 GdkEventGrabBroken *event);
150
151static void mate_color_selection_set_palette_color (MateColorSelection *colorsel,
152 gint index,
153 GdkRGBA *color);
154static void default_noscreen_change_palette_func (const GdkRGBA *colors,
155 gint n_colors);
156static void default_change_palette_func (GdkScreen *screen,
157 const GdkRGBA *colors,
158 gint n_colors);
159static void make_control_relations (AtkObject *atk_obj,
160 GtkWidget *widget);
161static void make_all_relations (AtkObject *atk_obj,
162 MateColorSelectionPrivate *priv);
163
164static void hsv_changed (GtkWidget *hsv,
165 gpointer data);
166static void get_screen_color (GtkWidget *button);
167static void adjustment_changed (GtkAdjustment *adjustment,
168 gpointer data);
169static void opacity_entry_changed (GtkWidget *opacity_entry,
170 gpointer data);
171static void hex_changed (GtkWidget *hex_entry,
172 gpointer data);
173static gboolean hex_focus_out (GtkWidget *hex_entry,
174 GdkEventFocus *event,
175 gpointer data);
176static void color_sample_new (MateColorSelection *colorsel);
177static void make_label_spinbutton (MateColorSelection *colorsel,
178 GtkWidget **spinbutton,
179 gchar *text,
180 GtkWidget *grid,
181 gint i,
182 gint j,
183 gint channel_type,
184 const gchar *tooltip);
185static void make_palette_frame (MateColorSelection *colorsel,
186 GtkWidget *grid,
187 gint i,
188 gint j);
189static void set_selected_palette (MateColorSelection *colorsel,
190 int x,
191 int y);
192static void set_focus_line_attributes (GtkWidget *drawing_area,
193 cairo_t *cr,
194 gint *focus_width);
195static gboolean mouse_press (GtkWidget *invisible,
196 GdkEventButton *event,
197 gpointer data);
198static void palette_change_notify_instance (GObject *object,
199 GParamSpec *pspec,
200 gpointer data);
201static void update_palette (MateColorSelection *colorsel);
202static void shutdown_eyedropper (GtkWidget *widget);
203
204static guint color_selection_signals[LAST_SIGNAL] = { 0 };
205
206static MateColorSelectionChangePaletteFunc noscreen_change_palette_hook = default_noscreen_change_palette_func;
207static MateColorSelectionChangePaletteWithScreenFunc change_palette_hook = default_change_palette_func;
208
209static const guchar dropper_bits[] = {
210"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
211 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
212 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
213 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
214 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
215 "\0U\35\35\35\373\40\40\40\350\0\0\0""6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
216 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\"\0\0\0\265"
217 "\0\0\0\373\233\233\233\377\233\233\233\377\0\0\0\351\0\0\0\0\0\0\0\0"
218 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
219 "\0y\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\375\0\0\0\0\0\0\0\0"
220 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
221 "\0U555\374\0\0\0\377\0\0\0\377\0\0\0\366\0\0\0t\0\0\0\15\0\0\0\0\0\0"
222 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0=EEE\377\362"
223 "\362\362\377HHH\377\0\0\0\377\0\0\0\332\0\0\0.\0\0\0\6\0\0\0\0\0\0\0"
224 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0=ddd\370\352\352\352"
225 "\377xxx\377\5\5\5\305\0\0\0\256\0\0\0q\0\0\0\15\0\0\0\0\0\0\0\0\0\0\0"
226 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0=EEE\377\353\353\353\377\206"
227 "\206\206\377\2\2\2\311\1\1\1=\0\0\0@\0\0\0-\0\0\0\4\0\0\0\0\0\0\0\0\0"
228 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0=ddd\370\354\354\354\377xxx\377\2"
229 "\2\2\311\0\0\0\77\0\0\0\21\0\0\0\14\0\0\0\10\0\0\0\0\0\0\0\0\0\0\0\0"
230 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<EEE\377\354\354\354\377\206\206\206\377"
231 "\2\2\2\311\2\2\2""6\0\0\0\20\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
232 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\316\374\374\374\377yyy\377\2\2"
233 "\2\311\0\0\0\77\0\0\0\20\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
234 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\32)))\351111\362\0\0\0\306\2\2\2""6"
235 "\0\0\0\20\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
236 "\0\0\0\0\0\0\0\0\0\0\0\0\0\21\0\0\0j\0\0\0g\0\0\0<\0\0\0\20\0\0\0\1\0"
237 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
238 "\0\0\0\0\0\0\0\0\11\0\0\0(\0\0\0\40\0\0\0\14\0\0\0\1\0\0\0\0\0\0\0\0"
239 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
240 "\0\0\0\0\0\0\0\0\0\3\0\0\0\2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
241 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"};
242
243G_DEFINE_TYPE_WITH_PRIVATE (MateColorSelection, mate_color_selection, GTK_TYPE_BOX)static void mate_color_selection_init (MateColorSelection *self
); static void mate_color_selection_class_init (MateColorSelectionClass
*klass); static GType mate_color_selection_get_type_once (void
); static gpointer mate_color_selection_parent_class = ((void
*)0); static gint MateColorSelection_private_offset; static void
mate_color_selection_class_intern_init (gpointer klass) { mate_color_selection_parent_class
= g_type_class_peek_parent (klass); if (MateColorSelection_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &MateColorSelection_private_offset
); mate_color_selection_class_init ((MateColorSelectionClass*
) klass); } __attribute__ ((__unused__)) static inline gpointer
mate_color_selection_get_instance_private (MateColorSelection
*self) { return (((gpointer) ((guint8*) (self) + (glong) (MateColorSelection_private_offset
)))); } GType mate_color_selection_get_type (void) { static gsize
static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); (void) (0 ? (gpointer) *(
&static_g_define_type_id) : ((void*)0)); (!(__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = mate_color_selection_get_type_once
(); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType mate_color_selection_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((gtk_box_get_type ()), g_intern_static_string ("MateColorSelection"
), sizeof (MateColorSelectionClass), (GClassInitFunc)(void (*
)(void)) mate_color_selection_class_intern_init, sizeof (MateColorSelection
), (GInstanceInitFunc)(void (*)(void)) mate_color_selection_init
, (GTypeFlags) 0); { {{ MateColorSelection_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (MateColorSelectionPrivate)); };} }
return g_define_type_id; }
244
245static void
246mate_color_selection_class_init (MateColorSelectionClass *klass)
247{
248 GObjectClass *gobject_class;
249 GtkWidgetClass *widget_class;
250
251 gobject_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
252 gobject_class->finalize = mate_color_selection_finalize;
253 gobject_class->set_property = mate_color_selection_set_property;
254 gobject_class->get_property = mate_color_selection_get_property;
255
256 gobject_class->dispose = mate_color_selection_dispose;
257
258 widget_class = GTK_WIDGET_CLASS (klass)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((gtk_widget_get_type ()))))))
;
259 widget_class->realize = mate_color_selection_realize;
260 widget_class->unrealize = mate_color_selection_unrealize;
261 widget_class->show_all = mate_color_selection_show_all;
262 widget_class->grab_broken_event = mate_color_selection_grab_broken;
263
264 g_object_class_install_property (gobject_class,
265 PROP_HAS_OPACITY_CONTROL,
266 g_param_spec_boolean ("has-opacity-control",
267 _("Has Opacity Control")((char *) g_dgettext ("mate-desktop", "Has Opacity Control")),
268 _("Whether the color selector should allow setting opacity")((char *) g_dgettext ("mate-desktop", "Whether the color selector should allow setting opacity"
))
,
269 FALSE(0),
270 G_PARAM_READWRITE));
271 g_object_class_install_property (gobject_class,
272 PROP_HAS_PALETTE,
273 g_param_spec_boolean ("has-palette",
274 _("Has palette")((char *) g_dgettext ("mate-desktop", "Has palette")),
275 _("Whether a palette should be used")((char *) g_dgettext ("mate-desktop", "Whether a palette should be used"
))
,
276 FALSE(0),
277 G_PARAM_READWRITE));
278 g_object_class_install_property (gobject_class,
279 PROP_CURRENT_RGBA,
280 g_param_spec_boxed ("current-rgba",
281 _("Current RGBA")((char *) g_dgettext ("mate-desktop", "Current RGBA")),
282 _("The current RGBA color")((char *) g_dgettext ("mate-desktop", "The current RGBA color"
))
,
283 GDK_TYPE_RGBA(gdk_rgba_get_type ()),
284 G_PARAM_READWRITE|
285 G_PARAM_STATIC_NAME|
286 G_PARAM_STATIC_NICK|
287 G_PARAM_STATIC_BLURB));
288 g_object_class_install_property (gobject_class,
289 PROP_CURRENT_ALPHA,
290 g_param_spec_uint ("current-alpha",
291 _("Current Alpha")((char *) g_dgettext ("mate-desktop", "Current Alpha")),
292 _("The current opacity value (0 fully transparent, 65535 fully opaque)")((char *) g_dgettext ("mate-desktop", "The current opacity value (0 fully transparent, 65535 fully opaque)"
))
,
293 0, 65535, 65535,
294 G_PARAM_READWRITE));
295 g_object_class_install_property (gobject_class,
296 PROP_HEX_STRING,
297 g_param_spec_string ("hex-string",
298 _("HEX String")((char *) g_dgettext ("mate-desktop", "HEX String")),
299 _("The hexadecimal string of current color")((char *) g_dgettext ("mate-desktop", "The hexadecimal string of current color"
))
,
300 "",
301 G_PARAM_READABLE));
302
303 color_selection_signals[COLOR_CHANGED] =
304 g_signal_new ("color-changed",
305 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
306 G_SIGNAL_RUN_FIRST,
307 G_STRUCT_OFFSET (MateColorSelectionClass, color_changed)((glong) __builtin_offsetof(MateColorSelectionClass, color_changed
))
,
308 NULL((void*)0), NULL((void*)0),
309 g_cclosure_marshal_VOID__VOID,
310 G_TYPE_NONE((GType) ((1) << (2))), 0);
311}
312
313static void
314mate_color_selection_init (MateColorSelection *colorsel)
315{
316 GtkWidget *top_hbox;
317 GtkWidget *top_right_vbox;
318 GtkWidget *grid, *label, *hbox, *frame, *vbox, *button;
319 GtkAdjustment *adjust;
320 GtkWidget *picker_image;
321 gint i, j;
322 MateColorSelectionPrivate *priv;
323 AtkObject *atk_obj;
324 GList *focus_chain = NULL((void*)0);
325
326 _mate_desktop_init_i18n ();
327
328 priv = colorsel->private_data = mate_color_selection_get_instance_private (colorsel);
329 priv->changing = FALSE(0);
330 priv->default_set = FALSE(0);
331 priv->default_alpha_set = FALSE(0);
332
333 top_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
334 gtk_box_pack_start (GTK_BOX (colorsel)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((colorsel)), ((gtk_box_get_type ()))))))
, top_hbox, FALSE(0), FALSE(0), 0);
335
336 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
337 priv->triangle_colorsel = mate_hsv_new ();
338 g_signal_connect (priv->triangle_colorsel, "changed",g_signal_connect_data ((priv->triangle_colorsel), ("changed"
), (((GCallback) (hsv_changed))), (colorsel), ((void*)0), (GConnectFlags
) 0)
339 G_CALLBACK (hsv_changed), colorsel)g_signal_connect_data ((priv->triangle_colorsel), ("changed"
), (((GCallback) (hsv_changed))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
340 mate_hsv_set_metrics (MATE_HSV (priv->triangle_colorsel)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->triangle_colorsel)), ((mate_hsv_get_type ()))))
))
, 174, 15);
341 gtk_box_pack_start (GTK_BOX (top_hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((top_hbox)), ((gtk_box_get_type ()))))))
, vbox, FALSE(0), FALSE(0), 0);
342 gtk_box_pack_start (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, priv->triangle_colorsel, FALSE(0), FALSE(0), 0);
343 gtk_widget_set_tooltip_text (priv->triangle_colorsel,
344 _("Select the color you want from the outer ring. Select the darkness or lightness of that color using the inner triangle.")((char *) g_dgettext ("mate-desktop", "Select the color you want from the outer ring. Select the darkness or lightness of that color using the inner triangle."
))
);
345
346 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
347 gtk_box_pack_end (GTK_BOX (vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((vbox)), ((gtk_box_get_type ()))))))
, hbox, FALSE(0), FALSE(0), 0);
348
349 frame = gtk_frame_new (NULL((void*)0));
350 gtk_widget_set_size_request (frame, -1, 30);
351 gtk_frame_set_shadow_type (GTK_FRAME (frame)((((GtkFrame*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame)), ((gtk_frame_get_type ()))))))
, GTK_SHADOW_IN);
352 color_sample_new (colorsel);
353 gtk_container_add (GTK_CONTAINER (frame)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame)), ((gtk_container_get_type ()))))))
, priv->sample_area);
354 gtk_box_pack_start (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, frame, TRUE(!(0)), TRUE(!(0)), 0);
355
356 button = gtk_button_new ();
357
358 gtk_widget_set_events (button, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
359 g_object_set_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "COLORSEL", colorsel);
360 g_signal_connect (button, "clicked",g_signal_connect_data ((button), ("clicked"), (((GCallback) (
get_screen_color))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
361 G_CALLBACK (get_screen_color), NULL)g_signal_connect_data ((button), ("clicked"), (((GCallback) (
get_screen_color))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
362 picker_image = gtk_image_new_from_icon_name ("gtk-color-picker", GTK_ICON_SIZE_BUTTON);
363 gtk_container_add (GTK_CONTAINER (button)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((gtk_container_get_type ()))))))
, picker_image);
364 gtk_widget_show (GTK_WIDGET (picker_image)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((picker_image)), ((gtk_widget_get_type ()))))))
);
365 gtk_box_pack_end (GTK_BOX (hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hbox)), ((gtk_box_get_type ()))))))
, button, FALSE(0), FALSE(0), 0);
366
367 gtk_widget_set_tooltip_text (button,
368 _("Click the eyedropper, then click a color anywhere on your screen to select that color.")((char *) g_dgettext ("mate-desktop", "Click the eyedropper, then click a color anywhere on your screen to select that color."
))
);
369
370 top_right_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
371 gtk_box_pack_start (GTK_BOX (top_hbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((top_hbox)), ((gtk_box_get_type ()))))))
, top_right_vbox, FALSE(0), FALSE(0), 0);
372 grid = gtk_grid_new ();
373 gtk_box_pack_start (GTK_BOX (top_right_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((top_right_vbox)), ((gtk_box_get_type ()))))))
, grid, FALSE(0), FALSE(0), 0);
374 gtk_grid_set_row_spacing (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, 6);
375 gtk_grid_set_column_spacing (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, 12);
376
377 make_label_spinbutton (colorsel, &priv->hue_spinbutton, _("_Hue:")((char *) g_dgettext ("mate-desktop", "_Hue:")), grid, 0, 0, COLORSEL_HUE,
378 _("Position on the color wheel.")((char *) g_dgettext ("mate-desktop", "Position on the color wheel."
))
);
379 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (priv->hue_spinbutton)((((GtkSpinButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->hue_spinbutton)), ((gtk_spin_button_get_type ()
))))))
, TRUE(!(0)));
380 make_label_spinbutton (colorsel, &priv->sat_spinbutton, _("_Saturation:")((char *) g_dgettext ("mate-desktop", "_Saturation:")), grid, 0, 1, COLORSEL_SATURATION,
381 _("\"Deepness\" of the color.")((char *) g_dgettext ("mate-desktop", "\"Deepness\" of the color."
))
);
382 make_label_spinbutton (colorsel, &priv->val_spinbutton, _("_Value:")((char *) g_dgettext ("mate-desktop", "_Value:")), grid, 0, 2, COLORSEL_VALUE,
383 _("Brightness of the color.")((char *) g_dgettext ("mate-desktop", "Brightness of the color."
))
);
384 make_label_spinbutton (colorsel, &priv->red_spinbutton, _("_Red:")((char *) g_dgettext ("mate-desktop", "_Red:")), grid, 6, 0, COLORSEL_RED,
385 _("Amount of red light in the color.")((char *) g_dgettext ("mate-desktop", "Amount of red light in the color."
))
);
386 make_label_spinbutton (colorsel, &priv->green_spinbutton, _("_Green:")((char *) g_dgettext ("mate-desktop", "_Green:")), grid, 6, 1, COLORSEL_GREEN,
387 _("Amount of green light in the color.")((char *) g_dgettext ("mate-desktop", "Amount of green light in the color."
))
);
388 make_label_spinbutton (colorsel, &priv->blue_spinbutton, _("_Blue:")((char *) g_dgettext ("mate-desktop", "_Blue:")), grid, 6, 2, COLORSEL_BLUE,
389 _("Amount of blue light in the color.")((char *) g_dgettext ("mate-desktop", "Amount of blue light in the color."
))
);
390 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, gtk_separator_new (GTK_ORIENTATION_HORIZONTAL), 0, 3, 8, 1);
391
392 priv->opacity_label = gtk_label_new_with_mnemonic (_("Op_acity:")((char *) g_dgettext ("mate-desktop", "Op_acity:")));
393 gtk_label_set_xalign (GTK_LABEL (priv->opacity_label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->opacity_label)), ((gtk_label_get_type ()))))))
, 0.0);
394 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, priv->opacity_label, 0, 4, 1, 1);
395 adjust = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 1.0, 0.0))((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 1.0, 0.0))), (
(gtk_adjustment_get_type ()))))))
;
396 g_object_set_data (G_OBJECT (adjust)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((adjust)), (((GType) ((20) << (2))))))))
, "COLORSEL", colorsel);
397 priv->opacity_slider = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adjust);
398 gtk_widget_set_tooltip_text (priv->opacity_slider,
399 _("Transparency of the color.")((char *) g_dgettext ("mate-desktop", "Transparency of the color."
))
);
400 gtk_label_set_mnemonic_widget (GTK_LABEL (priv->opacity_label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->opacity_label)), ((gtk_label_get_type ()))))))
,
401 priv->opacity_slider);
402 gtk_scale_set_draw_value (GTK_SCALE (priv->opacity_slider)((((GtkScale*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->opacity_slider)), ((gtk_scale_get_type ()))))))
, FALSE(0));
403 g_signal_connect (adjust, "value-changed",g_signal_connect_data ((adjust), ("value-changed"), (((GCallback
) (adjustment_changed))), (((gpointer) (glong) (COLORSEL_OPACITY
))), ((void*)0), (GConnectFlags) 0)
404 G_CALLBACK (adjustment_changed),g_signal_connect_data ((adjust), ("value-changed"), (((GCallback
) (adjustment_changed))), (((gpointer) (glong) (COLORSEL_OPACITY
))), ((void*)0), (GConnectFlags) 0)
405 GINT_TO_POINTER (COLORSEL_OPACITY))g_signal_connect_data ((adjust), ("value-changed"), (((GCallback
) (adjustment_changed))), (((gpointer) (glong) (COLORSEL_OPACITY
))), ((void*)0), (GConnectFlags) 0)
;
406 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, priv->opacity_slider, 1, 4, 6, 1);
407 priv->opacity_entry = gtk_entry_new ();
408 gtk_widget_set_tooltip_text (priv->opacity_entry,
409 _("Transparency of the color.")((char *) g_dgettext ("mate-desktop", "Transparency of the color."
))
);
410 gtk_widget_set_size_request (priv->opacity_entry, 40, -1);
411
412 g_signal_connect (priv->opacity_entry, "activate",g_signal_connect_data ((priv->opacity_entry), ("activate")
, (((GCallback) (opacity_entry_changed))), (colorsel), ((void
*)0), (GConnectFlags) 0)
413 G_CALLBACK (opacity_entry_changed), colorsel)g_signal_connect_data ((priv->opacity_entry), ("activate")
, (((GCallback) (opacity_entry_changed))), (colorsel), ((void
*)0), (GConnectFlags) 0)
;
414 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, priv->opacity_entry, 7, 4, 1, 1);
415
416 label = gtk_label_new_with_mnemonic (_("Color _name:")((char *) g_dgettext ("mate-desktop", "Color _name:")));
417 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, label, 0, 5, 1, 1);
418 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
419 priv->hex_entry = gtk_entry_new ();
420
421 gtk_label_set_mnemonic_widget (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, priv->hex_entry);
422
423 g_signal_connect (priv->hex_entry, "activate",g_signal_connect_data ((priv->hex_entry), ("activate"), ((
(GCallback) (hex_changed))), (colorsel), ((void*)0), (GConnectFlags
) 0)
424 G_CALLBACK (hex_changed), colorsel)g_signal_connect_data ((priv->hex_entry), ("activate"), ((
(GCallback) (hex_changed))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
425
426 g_signal_connect (priv->hex_entry, "focus-out-event",g_signal_connect_data ((priv->hex_entry), ("focus-out-event"
), (((GCallback) (hex_focus_out))), (colorsel), ((void*)0), (
GConnectFlags) 0)
427 G_CALLBACK (hex_focus_out), colorsel)g_signal_connect_data ((priv->hex_entry), ("focus-out-event"
), (((GCallback) (hex_focus_out))), (colorsel), ((void*)0), (
GConnectFlags) 0)
;
428
429 gtk_widget_set_tooltip_text (priv->hex_entry,
430 _("You can enter an HTML-style hexadecimal color value, or simply a color name such as 'orange' in this entry.")((char *) g_dgettext ("mate-desktop", "You can enter an HTML-style hexadecimal color value, or simply a color name such as 'orange' in this entry."
))
);
431
432 gtk_entry_set_width_chars (GTK_ENTRY (priv->hex_entry)((((GtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->hex_entry)), ((gtk_entry_get_type ()))))))
, 7);
433 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, priv->hex_entry, 1, 5, 4, 1);
434
435 focus_chain = g_list_append (focus_chain, priv->hue_spinbutton);
436 focus_chain = g_list_append (focus_chain, priv->sat_spinbutton);
437 focus_chain = g_list_append (focus_chain, priv->val_spinbutton);
438 focus_chain = g_list_append (focus_chain, priv->red_spinbutton);
439 focus_chain = g_list_append (focus_chain, priv->green_spinbutton);
440 focus_chain = g_list_append (focus_chain, priv->blue_spinbutton);
441 focus_chain = g_list_append (focus_chain, priv->opacity_slider);
442 focus_chain = g_list_append (focus_chain, priv->opacity_entry);
443 focus_chain = g_list_append (focus_chain, priv->hex_entry);
444 gtk_container_set_focus_chain (GTK_CONTAINER (grid)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_container_get_type ()))))))
, focus_chain);
445 g_list_free (focus_chain);
446
447 /* Set up the palette */
448 grid = gtk_grid_new ();
449 gtk_grid_set_row_spacing (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, 1);
450 gtk_grid_set_column_spacing (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, 1);
451 for (i = 0; i < GTK_CUSTOM_PALETTE_WIDTH9; i++)
452 {
453 for (j = 0; j < GTK_CUSTOM_PALETTE_HEIGHT4; j++)
454 {
455 make_palette_frame (colorsel, grid, i, j);
456 }
457 }
458 set_selected_palette (colorsel, 0, 0);
459 priv->palette_frame = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
460 label = gtk_label_new_with_mnemonic (_("_Palette:")((char *) g_dgettext ("mate-desktop", "_Palette:")));
461
462 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
463 gtk_box_pack_start (GTK_BOX (priv->palette_frame)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->palette_frame)), ((gtk_box_get_type ()))))))
, label, FALSE(0), FALSE(0), 0);
464
465 gtk_label_set_mnemonic_widget (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
,
466 priv->custom_palette[0][0]);
467
468 gtk_box_pack_end (GTK_BOX (top_right_vbox)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((top_right_vbox)), ((gtk_box_get_type ()))))))
, priv->palette_frame, FALSE(0), FALSE(0), 0);
469 gtk_box_pack_start (GTK_BOX (priv->palette_frame)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->palette_frame)), ((gtk_box_get_type ()))))))
, grid, FALSE(0), FALSE(0), 0);
470
471 gtk_widget_show_all (top_hbox);
472
473 /* hide unused stuff */
474
475 if (priv->has_opacity == FALSE(0))
476 {
477 gtk_widget_hide (priv->opacity_label);
478 gtk_widget_hide (priv->opacity_slider);
479 gtk_widget_hide (priv->opacity_entry);
480 }
481
482 if (priv->has_palette == FALSE(0))
483 {
484 gtk_widget_hide (priv->palette_frame);
485 }
486
487 atk_obj = gtk_widget_get_accessible (priv->triangle_colorsel);
488 if (GTK_IS_ACCESSIBLE (atk_obj)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(atk_obj)); GType __t = ((gtk_accessible_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
489 {
490 atk_object_set_name (atk_obj, _("Color Wheel")((char *) g_dgettext ("mate-desktop", "Color Wheel")));
491 atk_object_set_role (gtk_widget_get_accessible (GTK_WIDGET (colorsel)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((colorsel)), ((gtk_widget_get_type ()))))))
), ATK_ROLE_COLOR_CHOOSER);
492 make_all_relations (atk_obj, priv);
493 }
494}
495
496/* GObject methods */
497static void
498mate_color_selection_finalize (GObject *object)
499{
500 G_OBJECT_CLASS (mate_color_selection_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((mate_color_selection_parent_class)), (((GType) ((20) <<
(2))))))))
->finalize (object);
501}
502
503static void
504mate_color_selection_set_property (GObject *object,
505 guint prop_id,
506 const GValue *value,
507 GParamSpec *pspec)
508{
509 MateColorSelection *colorsel = MATE_COLOR_SELECTION (object)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((object)), ((mate_color_selection_get_type (
)))))))
;
510
511 switch (prop_id)
512 {
513 case PROP_HAS_OPACITY_CONTROL:
514 mate_color_selection_set_has_opacity_control (colorsel,
515 g_value_get_boolean (value));
516 break;
517 case PROP_HAS_PALETTE:
518 mate_color_selection_set_has_palette (colorsel,
519 g_value_get_boolean (value));
520 break;
521 case PROP_CURRENT_RGBA:
522 mate_color_selection_set_current_rgba (colorsel, g_value_get_boxed (value));
523 break;
524 case PROP_CURRENT_ALPHA:
525 mate_color_selection_set_current_alpha (colorsel, g_value_get_uint (value));
526 break;
527 default:
528 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "mate-colorsel.c", 528, ("property"), _glib__property_id, _glib__pspec
->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) (
_glib__pspec))->g_class))->g_type)))), (g_type_name (((
(((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
529 break;
530 }
531
532}
533
534static void
535mate_color_selection_get_property (GObject *object,
536 guint prop_id,
537 GValue *value,
538 GParamSpec *pspec)
539{
540 GdkRGBA rgba;
541 MateColorSelection *colorsel = MATE_COLOR_SELECTION (object)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((object)), ((mate_color_selection_get_type (
)))))))
;
542 MateColorSelectionPrivate *priv = colorsel->private_data;
543
544 switch (prop_id)
545 {
546 case PROP_HAS_OPACITY_CONTROL:
547 g_value_set_boolean (value, mate_color_selection_get_has_opacity_control (colorsel));
548 break;
549 case PROP_HAS_PALETTE:
550 g_value_set_boolean (value, mate_color_selection_get_has_palette (colorsel));
551 break;
552 case PROP_CURRENT_RGBA:
553 mate_color_selection_get_current_rgba (colorsel, &rgba);
554 g_value_set_boxed (value, &rgba);
555 break;
556 case PROP_CURRENT_ALPHA:
557 g_value_set_uint (value, mate_color_selection_get_current_alpha (colorsel));
558 break;
559 case PROP_HEX_STRING:
560 g_value_set_string (value, gtk_editable_get_chars (GTK_EDITABLE (priv->hex_entry)((((GtkEditable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->hex_entry)), ((gtk_editable_get_type ()))))))
, 0, -1));
561 break;
562 default:
563 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "mate-colorsel.c", 563, ("property"), _glib__property_id, _glib__pspec
->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) (
_glib__pspec))->g_class))->g_type)))), (g_type_name (((
(((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
564 break;
565 }
566}
567
568static void
569mate_color_selection_dispose (GObject *object)
570{
571 MateColorSelection *cselection = MATE_COLOR_SELECTION (object)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((object)), ((mate_color_selection_get_type (
)))))))
;
572 MateColorSelectionPrivate *priv = cselection->private_data;
573
574 if (priv->dropper_grab_widget)
575 {
576 gtk_widget_destroy (priv->dropper_grab_widget);
577 priv->dropper_grab_widget = NULL((void*)0);
578 }
579
580 G_OBJECT_CLASS (mate_color_selection_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((mate_color_selection_parent_class)), (((GType) ((20) <<
(2))))))))
->dispose (object);
581}
582
583/* GtkWidget methods */
584
585static void
586mate_color_selection_realize (GtkWidget *widget)
587{
588 MateColorSelection *colorsel = MATE_COLOR_SELECTION (widget)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), ((mate_color_selection_get_type (
)))))))
;
589 MateColorSelectionPrivate *priv = colorsel->private_data;
590 GtkSettings *settings = gtk_widget_get_settings (widget);
591
592 priv->settings_connection = g_signal_connect (settings,g_signal_connect_data ((settings), ("notify::gtk-color-palette"
), (((GCallback) (palette_change_notify_instance))), (widget)
, ((void*)0), (GConnectFlags) 0)
593 "notify::gtk-color-palette",g_signal_connect_data ((settings), ("notify::gtk-color-palette"
), (((GCallback) (palette_change_notify_instance))), (widget)
, ((void*)0), (GConnectFlags) 0)
594 G_CALLBACK (palette_change_notify_instance),g_signal_connect_data ((settings), ("notify::gtk-color-palette"
), (((GCallback) (palette_change_notify_instance))), (widget)
, ((void*)0), (GConnectFlags) 0)
595 widget)g_signal_connect_data ((settings), ("notify::gtk-color-palette"
), (((GCallback) (palette_change_notify_instance))), (widget)
, ((void*)0), (GConnectFlags) 0)
;
596 update_palette (colorsel);
597
598 GTK_WIDGET_CLASS (mate_color_selection_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((mate_color_selection_parent_class)), ((gtk_widget_get_type
()))))))
->realize (widget);
599}
600
601static void
602mate_color_selection_unrealize (GtkWidget *widget)
603{
604 MateColorSelection *colorsel = MATE_COLOR_SELECTION (widget)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), ((mate_color_selection_get_type (
)))))))
;
605 MateColorSelectionPrivate *priv = colorsel->private_data;
606 GtkSettings *settings = gtk_widget_get_settings (widget);
607
608 g_signal_handler_disconnect (settings, priv->settings_connection);
609
610 GTK_WIDGET_CLASS (mate_color_selection_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((mate_color_selection_parent_class)), ((gtk_widget_get_type
()))))))
->unrealize (widget);
611}
612
613/* We override show-all since we have internal widgets that
614 * shouldn't be shown when you call show_all(), like the
615 * palette and opacity sliders.
616 */
617static void
618mate_color_selection_show_all (GtkWidget *widget)
619{
620 gtk_widget_show (widget);
621}
622
623static gboolean
624mate_color_selection_grab_broken (GtkWidget *widget,
625 GdkEventGrabBroken *event)
626{
627 shutdown_eyedropper (widget);
628
629 return TRUE(!(0));
630}
631
632/*
633 *
634 * The Sample Color
635 *
636 */
637
638static void color_sample_draw_sample (MateColorSelection *colorsel, cairo_t *cr, int which);
639static void color_sample_update_samples (MateColorSelection *colorsel);
640
641static void
642set_color_internal (MateColorSelection *colorsel,
643 gdouble *color)
644{
645 MateColorSelectionPrivate *priv;
646 gint i;
647
648 priv = colorsel->private_data;
649 priv->changing = TRUE(!(0));
650 priv->color[COLORSEL_RED] = color[0];
651 priv->color[COLORSEL_GREEN] = color[1];
652 priv->color[COLORSEL_BLUE] = color[2];
653 priv->color[COLORSEL_OPACITY] = color[3];
654 gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
655 priv->color[COLORSEL_GREEN],
656 priv->color[COLORSEL_BLUE],
657 &priv->color[COLORSEL_HUE],
658 &priv->color[COLORSEL_SATURATION],
659 &priv->color[COLORSEL_VALUE]);
660 if (priv->default_set == FALSE(0))
661 {
662 for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
663 priv->old_color[i] = priv->color[i];
664 }
665 priv->default_set = TRUE(!(0));
666 priv->default_alpha_set = TRUE(!(0));
667 update_color (colorsel);
668}
669
670static void
671set_color_icon (GdkDragContext *context,
672 gdouble *colors)
673{
674 GdkPixbuf *pixbuf;
675 guint32 pixel;
676
677 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE(0),
678 8, 48, 32);
679
680 pixel = (((UNSCALE (colors[COLORSEL_RED])((guint16)(colors[COLORSEL_RED] * 65535 + 0.5)) & 0xff00) << 16) |
681 ((UNSCALE (colors[COLORSEL_GREEN])((guint16)(colors[COLORSEL_GREEN] * 65535 + 0.5)) & 0xff00) << 8) |
682 ((UNSCALE (colors[COLORSEL_BLUE])((guint16)(colors[COLORSEL_BLUE] * 65535 + 0.5)) & 0xff00)));
683
684 gdk_pixbuf_fill (pixbuf, pixel);
685
686 gtk_drag_set_icon_pixbuf (context, pixbuf, -2, -2);
687 g_object_unref (pixbuf);
688}
689
690static void
691color_sample_drag_begin (GtkWidget *widget,
692 GdkDragContext *context,
693 gpointer data)
694{
695 MateColorSelection *colorsel = data;
696 MateColorSelectionPrivate *priv;
697 gdouble *colsrc;
698
699 priv = colorsel->private_data;
700
701 if (widget == priv->old_sample)
702 colsrc = priv->old_color;
703 else
704 colsrc = priv->color;
705
706 set_color_icon (context, colsrc);
707}
708
709static void
710color_sample_drag_end (GtkWidget *widget,
711 GdkDragContext *context,
712 gpointer data)
713{
714 g_object_set_data (G_OBJECT (widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), (((GType) ((20) << (2))))))))
, "gtk-color-selection-drag-window", NULL((void*)0));
715}
716
717static void
718color_sample_drop_handle (GtkWidget *widget,
719 GdkDragContext *context,
720 gint x,
721 gint y,
722 GtkSelectionData *selection_data,
723 guint info,
724 guint time,
725 gpointer data)
726{
727 MateColorSelection *colorsel = data;
728 MateColorSelectionPrivate *priv;
729 guint16 *vals;
730 gdouble color[4];
731 priv = colorsel->private_data;
732
733 /* This is currently a guint16 array of the format:
734 * R
735 * G
736 * B
737 * opacity
738 */
739
740 if (gtk_selection_data_get_length (selection_data) < 0)
741 return;
742
743 /* We accept drops with the wrong format, since the KDE color
744 * chooser incorrectly drops application/x-color with format 8.
745 */
746 if (gtk_selection_data_get_length (selection_data) != 8)
747 {
748 g_warning ("Received invalid color data\n");
749 return;
750 }
751
752 vals = (guint16 *) gtk_selection_data_get_data (selection_data);
753
754 if (widget == priv->cur_sample)
755 {
756 color[0] = (gdouble)vals[0] / 0xffff;
757 color[1] = (gdouble)vals[1] / 0xffff;
758 color[2] = (gdouble)vals[2] / 0xffff;
759 color[3] = (gdouble)vals[3] / 0xffff;
760
761 set_color_internal (colorsel, color);
762 }
763}
764
765static void
766color_sample_drag_handle (GtkWidget *widget,
767 GdkDragContext *context,
768 GtkSelectionData *selection_data,
769 guint info,
770 guint time,
771 gpointer data)
772{
773 MateColorSelection *colorsel = data;
774 MateColorSelectionPrivate *priv;
775 guint16 vals[4];
776 gdouble *colsrc;
777
778 priv = colorsel->private_data;
779
780 if (widget == priv->old_sample)
781 colsrc = priv->old_color;
782 else
783 colsrc = priv->color;
784
785 vals[0] = colsrc[COLORSEL_RED] * 0xffff;
786 vals[1] = colsrc[COLORSEL_GREEN] * 0xffff;
787 vals[2] = colsrc[COLORSEL_BLUE] * 0xffff;
788 vals[3] = priv->has_opacity ? colsrc[COLORSEL_OPACITY] * 0xffff : 0xffff;
789
790 gtk_selection_data_set (selection_data,
791 gdk_atom_intern_static_string ("application/x-color"),
792 16, (guchar *)vals, 8);
793}
794
795/* which = 0 means draw old sample, which = 1 means draw new */
796static void
797color_sample_draw_sample (MateColorSelection *colorsel, cairo_t *cr, int which)
798{
799 GtkWidget *da;
800 gint x, y, wid, heig, goff;
801 MateColorSelectionPrivate *priv;
802 GtkAllocation allocation;
803
804 g_return_if_fail (colorsel != NULL)do { if ((colorsel != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "colorsel != NULL"
); return; } } while (0)
;
805 priv = colorsel->private_data;
806
807 g_return_if_fail (priv->sample_area != NULL)do { if ((priv->sample_area != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "priv->sample_area != NULL"
); return; } } while (0)
;
808 if (!gtk_widget_is_drawable (priv->sample_area))
809 return;
810
811 if (which == 0)
812 {
813 da = priv->old_sample;
814 goff = 0;
815 }
816 else
817 {
818 da = priv->cur_sample;
819 gtk_widget_get_allocation (priv->old_sample, &allocation);
820 goff = allocation.width % 32;
821 }
822
823 gtk_widget_get_allocation (da, &allocation);
824 wid = allocation.width;
825 heig = allocation.height;
826
827 /* Below needs tweaking for non-power-of-two */
828
829 if (priv->has_opacity)
830 {
831 /* Draw checks in background */
832
833 cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
834 cairo_rectangle (cr, 0, 0, wid, heig);
835 cairo_fill (cr);
836
837 cairo_set_source_rgb (cr, 0.75, 0.75, 0.75);
838 for (x = goff & -CHECK_SIZE16; x < goff + wid; x += CHECK_SIZE16)
839 for (y = 0; y < heig; y += CHECK_SIZE16)
840 if ((x / CHECK_SIZE16 + y / CHECK_SIZE16) % 2 == 0)
841 cairo_rectangle (cr, x - goff, y, CHECK_SIZE16, CHECK_SIZE16);
842 cairo_fill (cr);
843 }
844
845 if (which == 0)
846 {
847 cairo_set_source_rgba (cr,
848 priv->old_color[COLORSEL_RED],
849 priv->old_color[COLORSEL_GREEN],
850 priv->old_color[COLORSEL_BLUE],
851 priv->has_opacity ?
852 priv->old_color[COLORSEL_OPACITY] : 1.0);
853 }
854 else
855 {
856 cairo_set_source_rgba (cr,
857 priv->color[COLORSEL_RED],
858 priv->color[COLORSEL_GREEN],
859 priv->color[COLORSEL_BLUE],
860 priv->has_opacity ?
861 priv->color[COLORSEL_OPACITY] : 1.0);
862 }
863
864 cairo_rectangle (cr, 0, 0, wid, heig);
865 cairo_fill (cr);
866}
867
868static void
869color_sample_update_samples (MateColorSelection *colorsel)
870{
871 MateColorSelectionPrivate *priv = colorsel->private_data;
872 gtk_widget_queue_draw (priv->old_sample);
873 gtk_widget_queue_draw (priv->cur_sample);
874}
875
876static gboolean
877color_old_sample_draw (GtkWidget *da,
878 cairo_t *cr,
879 MateColorSelection *colorsel)
880{
881 color_sample_draw_sample (colorsel, cr, 0);
882 return FALSE(0);
883}
884
885static gboolean
886color_cur_sample_draw (GtkWidget *da,
887 cairo_t *cr,
888 MateColorSelection *colorsel)
889{
890 color_sample_draw_sample (colorsel, cr, 1);
891 return FALSE(0);
892}
893
894static void
895color_sample_setup_dnd (MateColorSelection *colorsel, GtkWidget *sample)
896{
897 static const GtkTargetEntry targets[] = {
898 { .target = "application/x-color", .flags = 0, .info = 0 }
899 };
900 MateColorSelectionPrivate *priv;
901 priv = colorsel->private_data;
902
903 gtk_drag_source_set (sample,
904 GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
905 targets, 1,
906 GDK_ACTION_COPY | GDK_ACTION_MOVE);
907
908 g_signal_connect (sample, "drag-begin",g_signal_connect_data ((sample), ("drag-begin"), (((GCallback
) (color_sample_drag_begin))), (colorsel), ((void*)0), (GConnectFlags
) 0)
909 G_CALLBACK (color_sample_drag_begin),g_signal_connect_data ((sample), ("drag-begin"), (((GCallback
) (color_sample_drag_begin))), (colorsel), ((void*)0), (GConnectFlags
) 0)
910 colorsel)g_signal_connect_data ((sample), ("drag-begin"), (((GCallback
) (color_sample_drag_begin))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
911 if (sample == priv->cur_sample)
912 {
913
914 gtk_drag_dest_set (sample,
915 GTK_DEST_DEFAULT_HIGHLIGHT |
916 GTK_DEST_DEFAULT_MOTION |
917 GTK_DEST_DEFAULT_DROP,
918 targets, 1,
919 GDK_ACTION_COPY);
920
921 g_signal_connect (sample, "drag-end",g_signal_connect_data ((sample), ("drag-end"), (((GCallback) (
color_sample_drag_end))), (colorsel), ((void*)0), (GConnectFlags
) 0)
922 G_CALLBACK (color_sample_drag_end),g_signal_connect_data ((sample), ("drag-end"), (((GCallback) (
color_sample_drag_end))), (colorsel), ((void*)0), (GConnectFlags
) 0)
923 colorsel)g_signal_connect_data ((sample), ("drag-end"), (((GCallback) (
color_sample_drag_end))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
924 }
925
926 g_signal_connect (sample, "drag-data-get",g_signal_connect_data ((sample), ("drag-data-get"), (((GCallback
) (color_sample_drag_handle))), (colorsel), ((void*)0), (GConnectFlags
) 0)
927 G_CALLBACK (color_sample_drag_handle),g_signal_connect_data ((sample), ("drag-data-get"), (((GCallback
) (color_sample_drag_handle))), (colorsel), ((void*)0), (GConnectFlags
) 0)
928 colorsel)g_signal_connect_data ((sample), ("drag-data-get"), (((GCallback
) (color_sample_drag_handle))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
929 g_signal_connect (sample, "drag-data-received",g_signal_connect_data ((sample), ("drag-data-received"), (((GCallback
) (color_sample_drop_handle))), (colorsel), ((void*)0), (GConnectFlags
) 0)
930 G_CALLBACK (color_sample_drop_handle),g_signal_connect_data ((sample), ("drag-data-received"), (((GCallback
) (color_sample_drop_handle))), (colorsel), ((void*)0), (GConnectFlags
) 0)
931 colorsel)g_signal_connect_data ((sample), ("drag-data-received"), (((GCallback
) (color_sample_drop_handle))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
932
933}
934
935static void
936update_tooltips (MateColorSelection *colorsel)
937{
938 MateColorSelectionPrivate *priv;
939
940 priv = colorsel->private_data;
941
942 if (priv->has_palette == TRUE(!(0)))
943 {
944 gtk_widget_set_tooltip_text (priv->old_sample,
945 _("The previously-selected color, for comparison to the color you're selecting now. You can drag this color to a palette entry, or select this color as current by dragging it to the other color swatch alongside.")((char *) g_dgettext ("mate-desktop", "The previously-selected color, for comparison to the color you're selecting now. You can drag this color to a palette entry, or select this color as current by dragging it to the other color swatch alongside."
))
);
946
947 gtk_widget_set_tooltip_text (priv->cur_sample,
948 _("The color you've chosen. You can drag this color to a palette entry to save it for use in the future.")((char *) g_dgettext ("mate-desktop", "The color you've chosen. You can drag this color to a palette entry to save it for use in the future."
))
);
949 }
950 else
951 {
952 gtk_widget_set_tooltip_text (priv->old_sample,
953 _("The previously-selected color, for comparison to the color you're selecting now.")((char *) g_dgettext ("mate-desktop", "The previously-selected color, for comparison to the color you're selecting now."
))
);
954
955 gtk_widget_set_tooltip_text (priv->cur_sample,
956 _("The color you've chosen.")((char *) g_dgettext ("mate-desktop", "The color you've chosen."
))
);
957 }
958}
959
960static void
961color_sample_new (MateColorSelection *colorsel)
962{
963 MateColorSelectionPrivate *priv;
964
965 priv = colorsel->private_data;
966
967 priv->sample_area = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
968 priv->old_sample = gtk_drawing_area_new ();
969 priv->cur_sample = gtk_drawing_area_new ();
970
971 gtk_box_pack_start (GTK_BOX (priv->sample_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->sample_area)), ((gtk_box_get_type ()))))))
, priv->old_sample,
972 TRUE(!(0)), TRUE(!(0)), 0);
973 gtk_box_pack_start (GTK_BOX (priv->sample_area)((((GtkBox*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->sample_area)), ((gtk_box_get_type ()))))))
, priv->cur_sample,
974 TRUE(!(0)), TRUE(!(0)), 0);
975
976 g_signal_connect (priv->old_sample, "draw",g_signal_connect_data ((priv->old_sample), ("draw"), (((GCallback
) (color_old_sample_draw))), (colorsel), ((void*)0), (GConnectFlags
) 0)
977 G_CALLBACK (color_old_sample_draw),g_signal_connect_data ((priv->old_sample), ("draw"), (((GCallback
) (color_old_sample_draw))), (colorsel), ((void*)0), (GConnectFlags
) 0)
978 colorsel)g_signal_connect_data ((priv->old_sample), ("draw"), (((GCallback
) (color_old_sample_draw))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
979 g_signal_connect (priv->cur_sample, "draw",g_signal_connect_data ((priv->cur_sample), ("draw"), (((GCallback
) (color_cur_sample_draw))), (colorsel), ((void*)0), (GConnectFlags
) 0)
980 G_CALLBACK (color_cur_sample_draw),g_signal_connect_data ((priv->cur_sample), ("draw"), (((GCallback
) (color_cur_sample_draw))), (colorsel), ((void*)0), (GConnectFlags
) 0)
981 colorsel)g_signal_connect_data ((priv->cur_sample), ("draw"), (((GCallback
) (color_cur_sample_draw))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
982
983 color_sample_setup_dnd (colorsel, priv->old_sample);
984 color_sample_setup_dnd (colorsel, priv->cur_sample);
985
986 update_tooltips (colorsel);
987
988 gtk_widget_show_all (priv->sample_area);
989}
990
991/*
992 *
993 * The palette area code
994 *
995 */
996
997static void
998palette_get_color (GtkWidget *drawing_area, gdouble *color)
999{
1000 gdouble *color_val;
1001
1002 g_return_if_fail (color != NULL)do { if ((color != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "color != NULL")
; return; } } while (0)
;
1003
1004 color_val = g_object_get_data (G_OBJECT (drawing_area)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((drawing_area)), (((GType) ((20) << (2))))))))
, "color_val");
1005 if (color_val == NULL((void*)0))
1006 {
1007 /* Default to white for no good reason */
1008 color[0] = 1.0;
1009 color[1] = 1.0;
1010 color[2] = 1.0;
1011 color[3] = 1.0;
1012 return;
1013 }
1014
1015 color[0] = color_val[0];
1016 color[1] = color_val[1];
1017 color[2] = color_val[2];
1018 color[3] = 1.0;
1019}
1020
1021static void
1022palette_paint (GtkWidget *drawing_area,
1023 cairo_t *cr,
1024 gpointer data)
1025{
1026 gint focus_width;
1027 GtkAllocation allocation;
1028 gdouble color[4];
1029
1030 if (gtk_widget_get_window (drawing_area) == NULL((void*)0))
1031 return;
1032
1033 gtk_widget_get_allocation (drawing_area, &allocation);
1034
1035 palette_get_color (drawing_area, color);
1036 cairo_set_source_rgba (cr, color[0], color[1], color[2], color[3]);
1037 cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
1038 cairo_fill (cr);
1039
1040 if (gtk_widget_has_focus (drawing_area))
1041 {
1042 set_focus_line_attributes (drawing_area, cr, &focus_width);
1043
1044 cairo_rectangle (cr,
1045 focus_width / 2., focus_width / 2.,
1046 allocation.width - focus_width,
1047 allocation.height - focus_width);
1048 cairo_stroke (cr);
1049 }
1050}
1051
1052static void
1053set_focus_line_attributes (GtkWidget *drawing_area,
1054 cairo_t *cr,
1055 gint *focus_width)
1056{
1057 gdouble color[4];
1058 gint8 *dash_list;
1059
1060 gtk_widget_style_get (drawing_area,
1061 "focus-line-width", focus_width,
1062 "focus-line-pattern", (gchar *)&dash_list,
1063 NULL((void*)0));
1064
1065 palette_get_color (drawing_area, color);
1066
1067 if (INTENSITY (color[0], color[1], color[2])((color[0]) * 0.30 + (color[1]) * 0.59 + (color[2]) * 0.11) > 0.5)
1068 cairo_set_source_rgb (cr, 0., 0., 0.);
1069 else
1070 cairo_set_source_rgb (cr, 1., 1., 1.);
1071
1072 cairo_set_line_width (cr, *focus_width);
1073
1074 if (dash_list[0])
1075 {
1076 gint n_dashes = strlen ((gchar *)dash_list);
1077 gdouble *dashes = g_new (gdouble, n_dashes)((gdouble *) g_malloc_n ((n_dashes), sizeof (gdouble)));
1078 gdouble total_length = 0;
1079 gdouble dash_offset;
1080 gint i;
1081
1082 for (i = 0; i < n_dashes; i++)
1083 {
1084 dashes[i] = dash_list[i];
1085 total_length += dash_list[i];
1086 }
1087
1088 /* The dash offset here aligns the pattern to integer pixels
1089 * by starting the dash at the right side of the left border
1090 * Negative dash offsets in cairo don't work
1091 * (https://bugs.freedesktop.org/show_bug.cgi?id=2729)
1092 */
1093 dash_offset = - *focus_width / 2.;
1094 while (dash_offset < 0)
1095 dash_offset += total_length;
1096
1097 cairo_set_dash (cr, dashes, n_dashes, dash_offset);
1098 g_free (dashes);
1099 }
1100
1101 g_free (dash_list);
1102}
1103
1104static void
1105palette_drag_begin (GtkWidget *widget,
1106 GdkDragContext *context,
1107 gpointer data)
1108{
1109 gdouble colors[4];
1110
1111 palette_get_color (widget, colors);
1112 set_color_icon (context, colors);
1113}
1114
1115static void
1116palette_drag_handle (GtkWidget *widget,
1117 GdkDragContext *context,
1118 GtkSelectionData *selection_data,
1119 guint info,
1120 guint time,
1121 gpointer data)
1122{
1123 guint16 vals[4];
1124 gdouble colsrc[4];
1125
1126 palette_get_color (widget, colsrc);
1127
1128 vals[0] = colsrc[COLORSEL_RED] * 0xffff;
1129 vals[1] = colsrc[COLORSEL_GREEN] * 0xffff;
1130 vals[2] = colsrc[COLORSEL_BLUE] * 0xffff;
1131 vals[3] = 0xffff;
1132
1133 gtk_selection_data_set (selection_data,
1134 gdk_atom_intern_static_string ("application/x-color"),
1135 16, (guchar *)vals, 8);
1136}
1137
1138static void
1139palette_drag_end (GtkWidget *widget,
1140 GdkDragContext *context,
1141 gpointer data)
1142{
1143 g_object_set_data (G_OBJECT (widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), (((GType) ((20) << (2))))))))
, "gtk-color-selection-drag-window", NULL((void*)0));
1144}
1145
1146static GdkRGBA *
1147get_current_colors (MateColorSelection *colorsel)
1148{
1149 GdkRGBA *colors = NULL((void*)0);
1150 gint n_colors = 0;
1151
1152 mate_color_selection_palette_from_string (DEFAULT_COLOR_PALETTE"#ef2929:#fcaf3e:#fce94f:#8ae234:#729fcf:#ad7fa8:#e9b96e:#888a85:#eeeeec:#cc0000:#f57900:#edd400:#73d216:#3465a4:#75507b:#c17d11:#555753:#d3d7cf:#a40000:#ce5c00:#c4a000:#4e9a06:#204a87:#5c3566:#8f5902:#2e3436:#babdb6:#000000:#2e3436:#555753:#888a85:#babdb6:#d3d7cf:#eeeeec:#f3f3f3:#ffffff",
1153 &colors,
1154 &n_colors);
1155
1156 /* make sure that we fill every slot */
1157 g_assert (n_colors == GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT)do { if (n_colors == 9 * 4) ; else g_assertion_message_expr (
"MateDesktop", "mate-colorsel.c", 1157, ((const char*) (__func__
)), "n_colors == GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT"
); } while (0)
;
1158
1159 return colors;
1160}
1161
1162/* Changes the model color */
1163static void
1164palette_change_color (GtkWidget *drawing_area,
1165 MateColorSelection *colorsel,
1166 gdouble *color)
1167{
1168 gint x, y;
1169 MateColorSelectionPrivate *priv;
1170 GdkRGBA gdk_color;
1171 GdkRGBA *current_colors;
1172 GdkScreen *screen;
1173
1174 g_return_if_fail (MATE_IS_COLOR_SELECTION (colorsel))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return; } } while (0)
;
1175 g_return_if_fail (GTK_IS_DRAWING_AREA (drawing_area))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((drawing_area)); GType __t = ((gtk_drawing_area_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "GTK_IS_DRAWING_AREA (drawing_area)"
); return; } } while (0)
;
1176
1177 priv = colorsel->private_data;
1178
1179 gdk_color.red = color[0];
1180 gdk_color.green = color[1];
1181 gdk_color.blue = color[2];
1182
1183 x = 0;
1184 y = 0; /* Quiet GCC */
1185 while (x < GTK_CUSTOM_PALETTE_WIDTH9)
1186 {
1187 y = 0;
1188 while (y < GTK_CUSTOM_PALETTE_HEIGHT4)
1189 {
1190 if (priv->custom_palette[x][y] == drawing_area)
1191 goto out;
1192
1193 ++y;
1194 }
1195
1196 ++x;
1197 }
1198
1199 out:
1200
1201 g_assert (x < GTK_CUSTOM_PALETTE_WIDTH || y < GTK_CUSTOM_PALETTE_HEIGHT)do { if (x < 9 || y < 4) ; else g_assertion_message_expr
("MateDesktop", "mate-colorsel.c", 1201, ((const char*) (__func__
)), "x < GTK_CUSTOM_PALETTE_WIDTH || y < GTK_CUSTOM_PALETTE_HEIGHT"
); } while (0)
;
1202
1203 current_colors = get_current_colors (colorsel);
1204 current_colors[y * GTK_CUSTOM_PALETTE_WIDTH9 + x] = gdk_color;
1205
1206 screen = gtk_widget_get_screen (GTK_WIDGET (colorsel)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((colorsel)), ((gtk_widget_get_type ()))))))
);
1207 if (change_palette_hook != default_change_palette_func)
1208 (* change_palette_hook) (screen, current_colors,
1209 GTK_CUSTOM_PALETTE_WIDTH9 * GTK_CUSTOM_PALETTE_HEIGHT4);
1210 else if (noscreen_change_palette_hook != default_noscreen_change_palette_func)
1211 {
1212 if (screen != gdk_screen_get_default ())
1213 g_warning ("mate_color_selection_set_change_palette_hook used by widget is not on the default screen.");
1214 (* noscreen_change_palette_hook) (current_colors,
1215 GTK_CUSTOM_PALETTE_WIDTH9 * GTK_CUSTOM_PALETTE_HEIGHT4);
1216 }
1217 else
1218 (* change_palette_hook) (screen, current_colors,
1219 GTK_CUSTOM_PALETTE_WIDTH9 * GTK_CUSTOM_PALETTE_HEIGHT4);
1220
1221 g_free (current_colors);
1222}
1223
1224/* Changes the view color */
1225static void
1226palette_set_color (GtkWidget *drawing_area,
1227 MateColorSelection *colorsel,
1228 gdouble *color)
1229{
1230 gpointer pointer;
1231 gdouble *new_color = g_new (double, 4)((double *) g_malloc_n ((4), sizeof (double)));
1232
1233 pointer = g_object_get_data (G_OBJECT (drawing_area)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((drawing_area)), (((GType) ((20) << (2))))))))
, "color_set");
1234 if (!pointer || GPOINTER_TO_INT (pointer)((gint) (glong) (pointer)) == 0)
1235 {
1236 static const GtkTargetEntry targets[] = {
1237 { .target = "application/x-color", .flags = 0, .info = 0 }
1238 };
1239 gtk_drag_source_set (drawing_area,
1240 GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
1241 targets, 1,
1242 GDK_ACTION_COPY | GDK_ACTION_MOVE);
1243
1244 g_signal_connect (drawing_area, "drag-begin",g_signal_connect_data ((drawing_area), ("drag-begin"), (((GCallback
) (palette_drag_begin))), (colorsel), ((void*)0), (GConnectFlags
) 0)
1245 G_CALLBACK (palette_drag_begin),g_signal_connect_data ((drawing_area), ("drag-begin"), (((GCallback
) (palette_drag_begin))), (colorsel), ((void*)0), (GConnectFlags
) 0)
1246 colorsel)g_signal_connect_data ((drawing_area), ("drag-begin"), (((GCallback
) (palette_drag_begin))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
1247 g_signal_connect (drawing_area, "drag-data-get",g_signal_connect_data ((drawing_area), ("drag-data-get"), (((
GCallback) (palette_drag_handle))), (colorsel), ((void*)0), (
GConnectFlags) 0)
1248 G_CALLBACK (palette_drag_handle),g_signal_connect_data ((drawing_area), ("drag-data-get"), (((
GCallback) (palette_drag_handle))), (colorsel), ((void*)0), (
GConnectFlags) 0)
1249 colorsel)g_signal_connect_data ((drawing_area), ("drag-data-get"), (((
GCallback) (palette_drag_handle))), (colorsel), ((void*)0), (
GConnectFlags) 0)
;
1250
1251 g_object_set_data (G_OBJECT (drawing_area)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((drawing_area)), (((GType) ((20) << (2))))))))
, "color_set",
1252 GINT_TO_POINTER (1)((gpointer) (glong) (1)));
1253 }
1254
1255 new_color[0] = color[0];
1256 new_color[1] = color[1];
1257 new_color[2] = color[2];
1258 new_color[3] = 1.0;
1259
1260 g_object_set_data_full (G_OBJECT (drawing_area)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((drawing_area)), (((GType) ((20) << (2))))))))
, "color_val", new_color, (GDestroyNotify)g_free);
1261}
1262
1263static gboolean
1264palette_draw (GtkWidget *drawing_area,
1265 cairo_t *cr,
1266 gpointer data)
1267{
1268 if (gtk_widget_get_window (drawing_area) == NULL((void*)0))
1269 return FALSE(0);
1270
1271 palette_paint (drawing_area, cr, data);
1272
1273 return FALSE(0);
1274}
1275
1276static void
1277save_color_selected (GtkWidget *menuitem,
1278 gpointer data)
1279{
1280 MateColorSelection *colorsel;
1281 GtkWidget *drawing_area;
1282 MateColorSelectionPrivate *priv;
1283
1284 drawing_area = GTK_WIDGET (data)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((gtk_widget_get_type ()))))))
;
1285
1286 colorsel = MATE_COLOR_SELECTION (g_object_get_data (G_OBJECT (drawing_area),((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((g_object_get_data (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((drawing_area)), (((GType) ((20) <<
(2)))))))), "gtk-color-sel"))), ((mate_color_selection_get_type
()))))))
1287 "gtk-color-sel"))((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((g_object_get_data (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((drawing_area)), (((GType) ((20) <<
(2)))))))), "gtk-color-sel"))), ((mate_color_selection_get_type
()))))))
;
1288
1289 priv = colorsel->private_data;
1290
1291 palette_change_color (drawing_area, colorsel, priv->color);
1292}
1293
1294static void
1295do_popup (MateColorSelection *colorsel,
1296 GtkWidget *drawing_area,
1297 const GdkEvent *trigger_event)
1298{
1299 GtkWidget *menu;
1300 GtkWidget *mi;
1301
1302 g_object_set_data (G_OBJECT (drawing_area)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((drawing_area)), (((GType) ((20) << (2))))))))
,
1303 _("gtk-color-sel")((char *) g_dgettext ("mate-desktop", "gtk-color-sel")),
1304 colorsel);
1305
1306 menu = gtk_menu_new ();
1307
1308 mi = gtk_menu_item_new_with_mnemonic (_("_Save color here")((char *) g_dgettext ("mate-desktop", "_Save color here")));
1309
1310 g_signal_connect (mi, "activate",g_signal_connect_data ((mi), ("activate"), (((GCallback) (save_color_selected
))), (drawing_area), ((void*)0), (GConnectFlags) 0)
1311 G_CALLBACK (save_color_selected),g_signal_connect_data ((mi), ("activate"), (((GCallback) (save_color_selected
))), (drawing_area), ((void*)0), (GConnectFlags) 0)
1312 drawing_area)g_signal_connect_data ((mi), ("activate"), (((GCallback) (save_color_selected
))), (drawing_area), ((void*)0), (GConnectFlags) 0)
;
1313
1314 gtk_menu_shell_append (GTK_MENU_SHELL (menu)((((GtkMenuShell*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((gtk_menu_shell_get_type ()))))))
, mi);
1315
1316 gtk_widget_show_all (mi);
1317
1318 if (trigger_event && gdk_event_triggers_context_menu (trigger_event))
1319 gtk_menu_popup_at_pointer (GTK_MENU (menu)((((GtkMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((gtk_menu_get_type ()))))))
, trigger_event);
1320 else
1321 /* We use the drawing area's parent to anchor the menu because of GTK bug
1322 * https://gitlab.gnome.org/GNOME/gtk/-/issues/6166 that leads to
1323 * misplacement of the popup if the anchor widget has its own window.
1324 * The drawing area ought to have its own window though, as it is mandatory
1325 * for setting it up as a drag source.
1326 * Using the parent is OK in our case because the drawing area's parent is
1327 * a frame that has it as its only child, and thus size and placement is
1328 * appropriate for placing the menu. */
1329 gtk_menu_popup_at_widget (GTK_MENU (menu)((((GtkMenu*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((menu)), ((gtk_menu_get_type ()))))))
,
1330 gtk_widget_get_parent (drawing_area),
1331 GDK_GRAVITY_CENTER,
1332 GDK_GRAVITY_NORTH_WEST,
1333 trigger_event);
1334}
1335
1336static gboolean
1337palette_enter (GtkWidget *drawing_area,
1338 GdkEventCrossing *event,
1339 gpointer data)
1340{
1341 g_object_set_data (G_OBJECT (drawing_area)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((drawing_area)), (((GType) ((20) << (2))))))))
,
1342 "gtk-colorsel-have-pointer",
1343 GUINT_TO_POINTER (TRUE)((gpointer) (gulong) ((!(0)))));
1344
1345 return FALSE(0);
1346}
1347
1348static gboolean
1349palette_leave (GtkWidget *drawing_area,
1350 GdkEventCrossing *event,
1351 gpointer data)
1352{
1353 g_object_set_data (G_OBJECT (drawing_area)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((drawing_area)), (((GType) ((20) << (2))))))))
,
1354 "gtk-colorsel-have-pointer",
1355 NULL((void*)0));
1356
1357 return FALSE(0);
1358}
1359
1360/* private function copied from gtk2/gtkmain.c */
1361static gboolean
1362_gtk_button_event_triggers_context_menu (GdkEventButton *event)
1363{
1364 if (event->type == GDK_BUTTON_PRESS)
1365 {
1366 if (event->button == 3 &&
1367 ! (event->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK)))
1368 return TRUE(!(0));
1369
1370#ifdef GDK_WINDOWING_QUARTZ
1371 if (event->button == 1 &&
1372 ! (event->state & (GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) &&
1373 (event->state & GDK_CONTROL_MASK))
1374 return TRUE(!(0));
1375#endif
1376 }
1377
1378 return FALSE(0);
1379}
1380
1381static gboolean
1382palette_press (GtkWidget *drawing_area,
1383 GdkEventButton *event,
1384 gpointer data)
1385{
1386 MateColorSelection *colorsel = MATE_COLOR_SELECTION (data)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((data)), ((mate_color_selection_get_type ()
))))))
;
1387
1388 gtk_widget_grab_focus (drawing_area);
1389
1390 if (_gtk_button_event_triggers_context_menu (event))
1391 {
1392 do_popup (colorsel, drawing_area, (GdkEvent *) event);
1393 return TRUE(!(0));
1394 }
1395
1396 return FALSE(0);
1397}
1398
1399static gboolean
1400palette_release (GtkWidget *drawing_area,
1401 GdkEventButton *event,
1402 gpointer data)
1403{
1404 MateColorSelection *colorsel = MATE_COLOR_SELECTION (data)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((data)), ((mate_color_selection_get_type ()
))))))
;
1405
1406 gtk_widget_grab_focus (drawing_area);
1407
1408 if (event->button == 1 &&
1409 g_object_get_data (G_OBJECT (drawing_area)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((drawing_area)), (((GType) ((20) << (2))))))))
,
1410 "gtk-colorsel-have-pointer") != NULL((void*)0))
1411 {
1412 gpointer pointer = g_object_get_data (G_OBJECT (drawing_area)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((drawing_area)), (((GType) ((20) << (2))))))))
, "color_set");
1413 if (pointer && GPOINTER_TO_INT (pointer)((gint) (glong) (pointer)) != 0)
1414 {
1415 gdouble color[4];
1416 palette_get_color (drawing_area, color);
1417 set_color_internal (colorsel, color);
1418 }
1419 }
1420
1421 return FALSE(0);
1422}
1423
1424static void
1425palette_drop_handle (GtkWidget *widget,
1426 GdkDragContext *context,
1427 gint x,
1428 gint y,
1429 GtkSelectionData *selection_data,
1430 guint info,
1431 guint time,
1432 gpointer data)
1433{
1434 MateColorSelection *colorsel = MATE_COLOR_SELECTION (data)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((data)), ((mate_color_selection_get_type ()
))))))
;
1435 guint16 *vals;
1436 gdouble color[4];
1437
1438 if (gtk_selection_data_get_length (selection_data) < 0)
1439 return;
1440
1441 /* We accept drops with the wrong format, since the KDE color
1442 * chooser incorrectly drops application/x-color with format 8.
1443 */
1444 if (gtk_selection_data_get_length (selection_data) != 8)
1445 {
1446 g_warning ("Received invalid color data\n");
1447 return;
1448 }
1449
1450 vals = (guint16 *) gtk_selection_data_get_data (selection_data);
1451
1452 color[0] = (gdouble)vals[0] / 0xffff;
1453 color[1] = (gdouble)vals[1] / 0xffff;
1454 color[2] = (gdouble)vals[2] / 0xffff;
1455 color[3] = (gdouble)vals[3] / 0xffff;
1456 palette_change_color (widget, colorsel, color);
1457 set_color_internal (colorsel, color);
1458}
1459
1460static gint
1461palette_activate (GtkWidget *widget,
1462 GdkEventKey *event,
1463 gpointer data)
1464{
1465 /* should have a drawing area subclass with an activate signal */
1466 if ((event->keyval == GDK_KEY_space0x020) ||
1467 (event->keyval == GDK_KEY_Return0xff0d) ||
1468 (event->keyval == GDK_KEY_ISO_Enter0xfe34) ||
1469 (event->keyval == GDK_KEY_KP_Enter0xff8d) ||
1470 (event->keyval == GDK_KEY_KP_Space0xff80))
1471 {
1472 gpointer pointer = g_object_get_data (G_OBJECT (widget)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), (((GType) ((20) << (2))))))))
, "color_set");
1473 if (pointer && GPOINTER_TO_INT (pointer)((gint) (glong) (pointer)) != 0)
1474 {
1475 gdouble color[4];
1476 palette_get_color (widget, color);
1477 set_color_internal (MATE_COLOR_SELECTION (data)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((data)), ((mate_color_selection_get_type ()
))))))
, color);
1478 }
1479 return TRUE(!(0));
1480 }
1481
1482 return FALSE(0);
1483}
1484
1485static gboolean
1486palette_popup (GtkWidget *widget,
1487 gpointer data)
1488{
1489 MateColorSelection *colorsel = MATE_COLOR_SELECTION (data)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((data)), ((mate_color_selection_get_type ()
))))))
;
1490
1491 do_popup (colorsel, widget, NULL((void*)0));
1492 return TRUE(!(0));
1493}
1494
1495static GtkWidget*
1496palette_new (MateColorSelection *colorsel)
1497{
1498 static const GtkTargetEntry targets[] = {
1499 { .target = "application/x-color", .flags = 0, .info = 0 }
1500 };
1501
1502 GtkWidget *retval = gtk_drawing_area_new ();
1503
1504 gtk_widget_set_can_focus (retval, TRUE(!(0)));
1505
1506 g_object_set_data (G_OBJECT (retval)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((retval)), (((GType) ((20) << (2))))))))
, "color_set", GINT_TO_POINTER (0)((gpointer) (glong) (0)));
1507 gtk_widget_set_events (retval, GDK_BUTTON_PRESS_MASK
1508 | GDK_BUTTON_RELEASE_MASK
1509 | GDK_EXPOSURE_MASK
1510 | GDK_ENTER_NOTIFY_MASK
1511 | GDK_LEAVE_NOTIFY_MASK);
1512
1513 g_signal_connect (retval, "draw",g_signal_connect_data ((retval), ("draw"), (((GCallback) (palette_draw
))), (colorsel), ((void*)0), (GConnectFlags) 0)
1514 G_CALLBACK (palette_draw), colorsel)g_signal_connect_data ((retval), ("draw"), (((GCallback) (palette_draw
))), (colorsel), ((void*)0), (GConnectFlags) 0)
;
1515 g_signal_connect (retval, "button-press-event",g_signal_connect_data ((retval), ("button-press-event"), (((GCallback
) (palette_press))), (colorsel), ((void*)0), (GConnectFlags) 0
)
1516 G_CALLBACK (palette_press), colorsel)g_signal_connect_data ((retval), ("button-press-event"), (((GCallback
) (palette_press))), (colorsel), ((void*)0), (GConnectFlags) 0
)
;
1517 g_signal_connect (retval, "button-release-event",g_signal_connect_data ((retval), ("button-release-event"), ((
(GCallback) (palette_release))), (colorsel), ((void*)0), (GConnectFlags
) 0)
1518 G_CALLBACK (palette_release), colorsel)g_signal_connect_data ((retval), ("button-release-event"), ((
(GCallback) (palette_release))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
1519 g_signal_connect (retval, "enter-notify-event",g_signal_connect_data ((retval), ("enter-notify-event"), (((GCallback
) (palette_enter))), (colorsel), ((void*)0), (GConnectFlags) 0
)
1520 G_CALLBACK (palette_enter), colorsel)g_signal_connect_data ((retval), ("enter-notify-event"), (((GCallback
) (palette_enter))), (colorsel), ((void*)0), (GConnectFlags) 0
)
;
1521 g_signal_connect (retval, "leave-notify-event",g_signal_connect_data ((retval), ("leave-notify-event"), (((GCallback
) (palette_leave))), (colorsel), ((void*)0), (GConnectFlags) 0
)
1522 G_CALLBACK (palette_leave), colorsel)g_signal_connect_data ((retval), ("leave-notify-event"), (((GCallback
) (palette_leave))), (colorsel), ((void*)0), (GConnectFlags) 0
)
;
1523 g_signal_connect (retval, "key-press-event",g_signal_connect_data ((retval), ("key-press-event"), (((GCallback
) (palette_activate))), (colorsel), ((void*)0), (GConnectFlags
) 0)
1524 G_CALLBACK (palette_activate), colorsel)g_signal_connect_data ((retval), ("key-press-event"), (((GCallback
) (palette_activate))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
1525 g_signal_connect (retval, "popup-menu",g_signal_connect_data ((retval), ("popup-menu"), (((GCallback
) (palette_popup))), (colorsel), ((void*)0), (GConnectFlags) 0
)
1526 G_CALLBACK (palette_popup), colorsel)g_signal_connect_data ((retval), ("popup-menu"), (((GCallback
) (palette_popup))), (colorsel), ((void*)0), (GConnectFlags) 0
)
;
1527
1528 gtk_drag_dest_set (retval,
1529 GTK_DEST_DEFAULT_HIGHLIGHT |
1530 GTK_DEST_DEFAULT_MOTION |
1531 GTK_DEST_DEFAULT_DROP,
1532 targets, 1,
1533 GDK_ACTION_COPY);
1534
1535 g_signal_connect (retval, "drag-end",g_signal_connect_data ((retval), ("drag-end"), (((GCallback) (
palette_drag_end))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
1536 G_CALLBACK (palette_drag_end), NULL)g_signal_connect_data ((retval), ("drag-end"), (((GCallback) (
palette_drag_end))), (((void*)0)), ((void*)0), (GConnectFlags
) 0)
;
1537 g_signal_connect (retval, "drag-data-received",g_signal_connect_data ((retval), ("drag-data-received"), (((GCallback
) (palette_drop_handle))), (colorsel), ((void*)0), (GConnectFlags
) 0)
1538 G_CALLBACK (palette_drop_handle), colorsel)g_signal_connect_data ((retval), ("drag-data-received"), (((GCallback
) (palette_drop_handle))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
1539
1540 gtk_widget_set_tooltip_text (retval,
1541 _("Click this palette entry to make it the current color. To change this entry, drag a color swatch here or right-click it and select \"Save color here.\"")((char *) g_dgettext ("mate-desktop", "Click this palette entry to make it the current color. To change this entry, drag a color swatch here or right-click it and select \"Save color here.\""
))
);
1542 return retval;
1543}
1544
1545/*
1546 *
1547 * The actual MateColorSelection widget
1548 *
1549 */
1550
1551static GdkCursor *
1552make_picker_cursor (GdkScreen *screen)
1553{
1554 GdkCursor *cursor;
1555
1556 cursor = gdk_cursor_new_from_name (gdk_screen_get_display (screen),
1557 "color-picker");
1558
1559 if (!cursor)
1560 {
1561 GdkPixbuf *pixbuf;
1562
1563 pixbuf = gdk_pixbuf_new_from_data (dropper_bits,
1564 GDK_COLORSPACE_RGB, TRUE(!(0)), 8,
1565 DROPPER_WIDTH16, DROPPER_HEIGHT16,
1566 DROPPER_STRIDE64,
1567 NULL((void*)0), NULL((void*)0));
1568
1569 cursor = gdk_cursor_new_from_pixbuf (gdk_screen_get_display (screen),
1570 pixbuf,
1571 DROPPER_X_HOT2, DROPPER_Y_HOT16);
1572 g_object_unref (pixbuf);
1573 }
1574
1575 return cursor;
1576}
1577
1578static void
1579grab_color_at_mouse (GdkScreen *screen,
1580 GdkDevice *device,
1581 gint x_root,
1582 gint y_root,
1583 gpointer data)
1584{
1585 GdkPixbuf *pixbuf;
1586 guchar *pixels;
1587 MateColorSelection *colorsel = data;
1588 MateColorSelectionPrivate *priv;
1589 GdkWindow *root_window = gdk_screen_get_root_window (screen);
1590
1591 priv = colorsel->private_data;
1592
1593 pixbuf = gdk_pixbuf_get_from_window (root_window,
1594 x_root, y_root,
1595 1, 1);
1596 if (!pixbuf)
1597 {
1598 gint x, y;
1599 GdkWindow *window = gdk_device_get_window_at_position (device, &x, &y);
1600 if (!window)
1601 return;
1602 pixbuf = gdk_pixbuf_get_from_window (window,
1603 x, y,
1604 1, 1);
1605 if (!pixbuf)
1606 return;
1607 }
1608 pixels = gdk_pixbuf_get_pixels (pixbuf);
1609 priv->color[COLORSEL_RED] = SCALE(pixels[0] * 0x101)(pixels[0] * 0x101 / 65535.);
1610 priv->color[COLORSEL_GREEN] = SCALE(pixels[1] * 0x101)(pixels[1] * 0x101 / 65535.);
1611 priv->color[COLORSEL_BLUE] = SCALE(pixels[2] * 0x101)(pixels[2] * 0x101 / 65535.);
1612 g_object_unref (pixbuf);
1613
1614 gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
1615 priv->color[COLORSEL_GREEN],
1616 priv->color[COLORSEL_BLUE],
1617 &priv->color[COLORSEL_HUE],
1618 &priv->color[COLORSEL_SATURATION],
1619 &priv->color[COLORSEL_VALUE]);
1620
1621 update_color (colorsel);
1622}
1623
1624static void
1625shutdown_eyedropper (GtkWidget *widget)
1626{
1627 MateColorSelection *colorsel;
1628 MateColorSelectionPrivate *priv;
1629 GdkDisplay *display = gtk_widget_get_display (widget);
1630 GdkSeat *seat = gdk_display_get_default_seat (display);
1631
1632 colorsel = MATE_COLOR_SELECTION (widget)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((widget)), ((mate_color_selection_get_type (
)))))))
;
1633 priv = colorsel->private_data;
1634
1635 if (priv->has_grab)
1636 {
1637 gdk_seat_ungrab (seat);
1638 gtk_grab_remove (priv->dropper_grab_widget);
1639
1640 priv->has_grab = FALSE(0);
1641 }
1642}
1643
1644static void
1645mouse_motion (GtkWidget *invisible,
1646 GdkEventMotion *event,
1647 gpointer data)
1648{
1649 grab_color_at_mouse (gdk_event_get_screen ((GdkEvent *)event),
1650 gdk_event_get_device ((GdkEvent *) event),
1651 event->x_root, event->y_root, data);
1652}
1653
1654static gboolean
1655mouse_release (GtkWidget *invisible,
1656 GdkEventButton *event,
1657 gpointer data)
1658{
1659 /* MateColorSelection *colorsel = data; */
1660
1661 if (event->button != 1)
1662 return FALSE(0);
1663
1664 grab_color_at_mouse (gdk_event_get_screen ((GdkEvent *)event),
1665 gdk_event_get_device ((GdkEvent *) event),
1666 event->x_root, event->y_root, data);
1667
1668 shutdown_eyedropper (GTK_WIDGET (data)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((gtk_widget_get_type ()))))))
);
1669
1670 g_signal_handlers_disconnect_by_func (invisible,g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (mouse_motion), (data))
1671 mouse_motion,g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (mouse_motion), (data))
1672 data)g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (mouse_motion), (data))
;
1673 g_signal_handlers_disconnect_by_func (invisible,g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (mouse_release), (data))
1674 mouse_release,g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (mouse_release), (data))
1675 data)g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (mouse_release), (data))
;
1676
1677 return TRUE(!(0));
1678}
1679
1680/* Helper Functions */
1681
1682static gboolean
1683key_press (GtkWidget *invisible,
1684 GdkEventKey *event,
1685 gpointer data)
1686{
1687 GdkDevice *device, *pointer_device;
1688 GdkScreen *screen = gdk_event_get_screen ((GdkEvent *)event);
1689 guint state = event->state & gtk_accelerator_get_default_mod_mask ();
1690 gint x, y;
1691 gint dx, dy;
1692
1693 device = gdk_event_get_device ((GdkEvent *) event);
1694 pointer_device = gdk_device_get_associated_device (device);
1695 gdk_device_get_position (pointer_device, NULL((void*)0), &x, &y);
1696
1697 dx = 0;
1698 dy = 0;
1699
1700 switch (event->keyval)
1701 {
1702 case GDK_KEY_space0x020:
1703 case GDK_KEY_Return0xff0d:
1704 case GDK_KEY_ISO_Enter0xfe34:
1705 case GDK_KEY_KP_Enter0xff8d:
1706 case GDK_KEY_KP_Space0xff80:
1707 grab_color_at_mouse (screen, pointer_device, x, y, data);
1708 /* fall through */
1709
1710 case GDK_KEY_Escape0xff1b:
1711 shutdown_eyedropper (data);
1712
1713 g_signal_handlers_disconnect_by_func (invisible,g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (mouse_press), (data))
1714 mouse_press,g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (mouse_press), (data))
1715 data)g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (mouse_press), (data))
;
1716 g_signal_handlers_disconnect_by_func (invisible,g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (key_press), (data))
1717 key_press,g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (key_press), (data))
1718 data)g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (key_press), (data))
;
1719
1720 return TRUE(!(0));
1721
1722#if defined GDK_WINDOWING_X11
1723 case GDK_KEY_Up0xff52:
1724 case GDK_KEY_KP_Up0xff97:
1725 dy = state == GDK_MOD1_MASK ? -BIG_STEP20 : -1;
1726 break;
1727
1728 case GDK_KEY_Down0xff54:
1729 case GDK_KEY_KP_Down0xff99:
1730 dy = state == GDK_MOD1_MASK ? BIG_STEP20 : 1;
1731 break;
1732
1733 case GDK_KEY_Left0xff51:
1734 case GDK_KEY_KP_Left0xff96:
1735 dx = state == GDK_MOD1_MASK ? -BIG_STEP20 : -1;
1736 break;
1737
1738 case GDK_KEY_Right0xff53:
1739 case GDK_KEY_KP_Right0xff98:
1740 dx = state == GDK_MOD1_MASK ? BIG_STEP20 : 1;
1741 break;
1742#endif
1743
1744 default:
1745 return FALSE(0);
1746 }
1747
1748 gdk_device_warp (pointer_device, screen, x + dx, y + dy);
1749
1750 return TRUE(!(0));
1751
1752}
1753
1754static gboolean
1755mouse_press (GtkWidget *invisible,
1756 GdkEventButton *event,
1757 gpointer data)
1758{
1759 /* MateColorSelection *colorsel = data; */
1760
1761 if (event->type == GDK_BUTTON_PRESS &&
1762 event->button == 1)
1763 {
1764 g_signal_connect (invisible, "motion-notify-event",g_signal_connect_data ((invisible), ("motion-notify-event"), (
((GCallback) (mouse_motion))), (data), ((void*)0), (GConnectFlags
) 0)
1765 G_CALLBACK (mouse_motion),g_signal_connect_data ((invisible), ("motion-notify-event"), (
((GCallback) (mouse_motion))), (data), ((void*)0), (GConnectFlags
) 0)
1766 data)g_signal_connect_data ((invisible), ("motion-notify-event"), (
((GCallback) (mouse_motion))), (data), ((void*)0), (GConnectFlags
) 0)
;
1767 g_signal_connect (invisible, "button-release-event",g_signal_connect_data ((invisible), ("button-release-event"),
(((GCallback) (mouse_release))), (data), ((void*)0), (GConnectFlags
) 0)
1768 G_CALLBACK (mouse_release),g_signal_connect_data ((invisible), ("button-release-event"),
(((GCallback) (mouse_release))), (data), ((void*)0), (GConnectFlags
) 0)
1769 data)g_signal_connect_data ((invisible), ("button-release-event"),
(((GCallback) (mouse_release))), (data), ((void*)0), (GConnectFlags
) 0)
;
1770 g_signal_handlers_disconnect_by_func (invisible,g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (mouse_press), (data))
1771 mouse_press,g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (mouse_press), (data))
1772 data)g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (mouse_press), (data))
;
1773 g_signal_handlers_disconnect_by_func (invisible,g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (key_press), (data))
1774 key_press,g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (key_press), (data))
1775 data)g_signal_handlers_disconnect_matched ((invisible), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, ((void*)
0), (key_press), (data))
;
1776 return TRUE(!(0));
1777 }
1778
1779 return FALSE(0);
1780}
1781
1782/* when the button is clicked */
1783static void
1784get_screen_color (GtkWidget *button)
1785{
1786 MateColorSelection *colorsel = g_object_get_data (G_OBJECT (button)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), (((GType) ((20) << (2))))))))
, "COLORSEL");
1787 MateColorSelectionPrivate *priv = colorsel->private_data;
1788 GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (button)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((gtk_widget_get_type ()))))))
);
1789 GdkCursor *picker_cursor;
1790 GdkGrabStatus grab_status;
1791 GtkWidget *grab_widget, *toplevel;
1792 GdkDisplay *display;
1793 GdkEvent *event;
1794 GdkSeat *seat;
1795
1796 guint32 time = gtk_get_current_event_time ();
1797 event = gtk_get_current_event ();
1798 if (priv->dropper_grab_widget == NULL((void*)0))
1799 {
1800 grab_widget = gtk_window_new (GTK_WINDOW_POPUP);
1801 gtk_window_set_screen (GTK_WINDOW (grab_widget)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grab_widget)), ((gtk_window_get_type ()))))))
, screen);
1802 gtk_window_resize (GTK_WINDOW (grab_widget)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grab_widget)), ((gtk_window_get_type ()))))))
, 1, 1);
1803 gtk_window_move (GTK_WINDOW (grab_widget)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grab_widget)), ((gtk_window_get_type ()))))))
, -100, -100);
1804 gtk_widget_show (grab_widget);
1805
1806 gtk_widget_add_events (grab_widget,
1807 GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
1808
1809 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (colorsel)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((colorsel)), ((gtk_widget_get_type ()))))))
);
1810
1811 if (GTK_IS_WINDOW (toplevel)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(toplevel)); GType __t = ((gtk_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1812 {
1813 if (gtk_window_get_group (GTK_WINDOW (toplevel)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((gtk_window_get_type ()))))))
))
1814 gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((gtk_window_get_type ()))))))
),
1815 GTK_WINDOW (grab_widget)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grab_widget)), ((gtk_window_get_type ()))))))
);
1816 }
1817
1818 priv->dropper_grab_widget = grab_widget;
1819 }
1820
1821 display = gtk_widget_get_display (priv->dropper_grab_widget);
1822 seat = gdk_display_get_default_seat (display);
1823
1824 if (gdk_seat_grab (seat, gtk_widget_get_window (priv->dropper_grab_widget),
1825 GDK_SEAT_CAPABILITY_KEYBOARD, FALSE(0), NULL((void*)0),
1826 event,
1827 NULL((void*)0), NULL((void*)0)) != GDK_GRAB_SUCCESS)
1828 {
1829 gdk_event_free (event);
1830 return;
1831 }
1832
1833 picker_cursor = make_picker_cursor (screen);
1834 grab_status = gdk_seat_grab (seat, gtk_widget_get_window (priv->dropper_grab_widget),
1835 GDK_SEAT_CAPABILITY_POINTER, FALSE(0), picker_cursor,
1836 event,
1837 NULL((void*)0), NULL((void*)0));
1838 gdk_event_free (event);
1839 g_object_unref (picker_cursor);
1840
1841 if (grab_status != GDK_GRAB_SUCCESS)
1842 {
1843 gdk_seat_ungrab (seat);
1844 return;
1845 }
1846
1847 gtk_grab_add (priv->dropper_grab_widget);
1848 priv->grab_time = time;
1849 priv->has_grab = TRUE(!(0));
1850
1851 g_signal_connect (priv->dropper_grab_widget, "button-press-event",g_signal_connect_data ((priv->dropper_grab_widget), ("button-press-event"
), (((GCallback) (mouse_press))), (colorsel), ((void*)0), (GConnectFlags
) 0)
1852 G_CALLBACK (mouse_press), colorsel)g_signal_connect_data ((priv->dropper_grab_widget), ("button-press-event"
), (((GCallback) (mouse_press))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
1853 g_signal_connect (priv->dropper_grab_widget, "key-press-event",g_signal_connect_data ((priv->dropper_grab_widget), ("key-press-event"
), (((GCallback) (key_press))), (colorsel), ((void*)0), (GConnectFlags
) 0)
1854 G_CALLBACK (key_press), colorsel)g_signal_connect_data ((priv->dropper_grab_widget), ("key-press-event"
), (((GCallback) (key_press))), (colorsel), ((void*)0), (GConnectFlags
) 0)
;
1855}
1856
1857static void
1858hex_changed (GtkWidget *hex_entry,
1859 gpointer data)
1860{
1861 MateColorSelection *colorsel;
1862 MateColorSelectionPrivate *priv;
1863 GdkRGBA color;
1864 gchar *text;
1865
1866 colorsel = MATE_COLOR_SELECTION (data)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((data)), ((mate_color_selection_get_type ()
))))))
;
1867 priv = colorsel->private_data;
1868
1869 if (priv->changing)
2
Assuming field 'changing' is 0
3
Taking false branch
1870 return;
1871
1872 text = gtk_editable_get_chars (GTK_EDITABLE (priv->hex_entry)((((GtkEditable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->hex_entry)), ((gtk_editable_get_type ()))))))
, 0, -1);
1873 if (!g_str_has_prefix (text, "#")(__builtin_constant_p ("#")? __extension__ ({ const char * const
__str = (text); const char * const __prefix = ("#"); gboolean
__result = (0); if (__str == ((void*)0) || __prefix == ((void
*)0)) __result = (g_str_has_prefix) (__str, __prefix); else {
const size_t __str_len = strlen (((__str) + !(__str))); const
size_t __prefix_len = strlen (((__prefix) + !(__prefix))); if
(__str_len >= __prefix_len) __result = memcmp (((__str) +
!(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0; }
__result; }) : (g_str_has_prefix) (text, "#") )
)
4
'?' condition is true
5
Assuming '__str' is not equal to null
6
Taking false branch
7
Assuming '__str_len' is < '__prefix_len'
8
Taking false branch
9
Taking true branch
1874 {
1875 g_free (text);
10
Memory is released
1876 gchar *tmp = g_strconcat ("#", text, NULL((void*)0));
11
Use of memory after it is freed
1877 text = tmp;
1878 }
1879
1880 if (gdk_rgba_parse (&color, text))
1881 {
1882 priv->color[COLORSEL_RED] = color.red;
1883 priv->color[COLORSEL_GREEN] = color.green;
1884 priv->color[COLORSEL_BLUE] = color.blue;
1885 gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
1886 priv->color[COLORSEL_GREEN],
1887 priv->color[COLORSEL_BLUE],
1888 &priv->color[COLORSEL_HUE],
1889 &priv->color[COLORSEL_SATURATION],
1890 &priv->color[COLORSEL_VALUE]);
1891 update_color (colorsel);
1892 }
1893 g_free (text);
1894}
1895
1896static gboolean
1897hex_focus_out (GtkWidget *hex_entry,
1898 GdkEventFocus *event,
1899 gpointer data)
1900{
1901 hex_changed (hex_entry, data);
1
Calling 'hex_changed'
1902
1903 return FALSE(0);
1904}
1905
1906static void
1907hsv_changed (GtkWidget *hsv,
1908 gpointer data)
1909{
1910 MateColorSelection *colorsel;
1911 MateColorSelectionPrivate *priv;
1912
1913 colorsel = MATE_COLOR_SELECTION (data)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((data)), ((mate_color_selection_get_type ()
))))))
;
1914 priv = colorsel->private_data;
1915
1916 if (priv->changing)
1917 return;
1918
1919 mate_hsv_get_color (MATE_HSV (hsv)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((mate_hsv_get_type ()))))))
,
1920 &priv->color[COLORSEL_HUE],
1921 &priv->color[COLORSEL_SATURATION],
1922 &priv->color[COLORSEL_VALUE]);
1923 gtk_hsv_to_rgb (priv->color[COLORSEL_HUE],
1924 priv->color[COLORSEL_SATURATION],
1925 priv->color[COLORSEL_VALUE],
1926 &priv->color[COLORSEL_RED],
1927 &priv->color[COLORSEL_GREEN],
1928 &priv->color[COLORSEL_BLUE]);
1929 update_color (colorsel);
1930}
1931
1932static void
1933adjustment_changed (GtkAdjustment *adjustment,
1934 gpointer data)
1935{
1936 MateColorSelection *colorsel;
1937 MateColorSelectionPrivate *priv;
1938 gdouble value;
1939
1940 colorsel = MATE_COLOR_SELECTION (g_object_get_data (G_OBJECT (adjustment), "COLORSEL"))((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((g_object_get_data (((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((adjustment)), (((GType) ((20) << (
2)))))))), "COLORSEL"))), ((mate_color_selection_get_type ())
)))))
;
1941 priv = colorsel->private_data;
1942 value = gtk_adjustment_get_value (adjustment);
1943
1944 if (priv->changing)
1945 return;
1946
1947 switch (GPOINTER_TO_INT (data)((gint) (glong) (data)))
1948 {
1949 case COLORSEL_SATURATION:
1950 case COLORSEL_VALUE:
1951 priv->color[GPOINTER_TO_INT (data)((gint) (glong) (data))] = value / 100;
1952 gtk_hsv_to_rgb (priv->color[COLORSEL_HUE],
1953 priv->color[COLORSEL_SATURATION],
1954 priv->color[COLORSEL_VALUE],
1955 &priv->color[COLORSEL_RED],
1956 &priv->color[COLORSEL_GREEN],
1957 &priv->color[COLORSEL_BLUE]);
1958 break;
1959 case COLORSEL_HUE:
1960 priv->color[GPOINTER_TO_INT (data)((gint) (glong) (data))] = value / 360;
1961 gtk_hsv_to_rgb (priv->color[COLORSEL_HUE],
1962 priv->color[COLORSEL_SATURATION],
1963 priv->color[COLORSEL_VALUE],
1964 &priv->color[COLORSEL_RED],
1965 &priv->color[COLORSEL_GREEN],
1966 &priv->color[COLORSEL_BLUE]);
1967 break;
1968 case COLORSEL_RED:
1969 case COLORSEL_GREEN:
1970 case COLORSEL_BLUE:
1971 priv->color[GPOINTER_TO_INT (data)((gint) (glong) (data))] = value / 255;
1972
1973 gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
1974 priv->color[COLORSEL_GREEN],
1975 priv->color[COLORSEL_BLUE],
1976 &priv->color[COLORSEL_HUE],
1977 &priv->color[COLORSEL_SATURATION],
1978 &priv->color[COLORSEL_VALUE]);
1979 break;
1980 default:
1981 priv->color[GPOINTER_TO_INT (data)((gint) (glong) (data))] = value / 255;
1982 break;
1983 }
1984 update_color (colorsel);
1985}
1986
1987static void
1988opacity_entry_changed (GtkWidget *opacity_entry,
1989 gpointer data)
1990{
1991 MateColorSelection *colorsel;
1992 MateColorSelectionPrivate *priv;
1993 GtkAdjustment *adj;
1994 gchar *text;
1995
1996 colorsel = MATE_COLOR_SELECTION (data)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((data)), ((mate_color_selection_get_type ()
))))))
;
1997 priv = colorsel->private_data;
1998
1999 if (priv->changing)
2000 return;
2001
2002 text = gtk_editable_get_chars (GTK_EDITABLE (priv->opacity_entry)((((GtkEditable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->opacity_entry)), ((gtk_editable_get_type ()))))
))
, 0, -1);
2003 adj = gtk_range_get_adjustment (GTK_RANGE (priv->opacity_slider)((((GtkRange*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->opacity_slider)), ((gtk_range_get_type ()))))))
);
2004 gtk_adjustment_set_value (adj, g_strtod (text, NULL((void*)0)));
2005
2006 update_color (colorsel);
2007
2008 g_free (text);
2009}
2010
2011static void
2012make_label_spinbutton (MateColorSelection *colorsel,
2013 GtkWidget **spinbutton,
2014 gchar *text,
2015 GtkWidget *grid,
2016 gint i,
2017 gint j,
2018 gint channel_type,
2019 const gchar *tooltip)
2020{
2021 GtkWidget *label;
2022 GtkAdjustment *adjust;
2023
2024 if (channel_type == COLORSEL_HUE)
2025 {
2026 adjust = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 360.0, 1.0, 1.0, 0.0))((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new (0.0, 0.0, 360.0, 1.0, 1.0, 0.0))), (
(gtk_adjustment_get_type ()))))))
;
2027 }
2028 else if (channel_type == COLORSEL_SATURATION ||
2029 channel_type == COLORSEL_VALUE)
2030 {
2031 adjust = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 1.0, 0.0))((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 1.0, 0.0))), (
(gtk_adjustment_get_type ()))))))
;
2032 }
2033 else
2034 {
2035 adjust = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 1.0, 0.0))((((GtkAdjustment*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 1.0, 0.0))), (
(gtk_adjustment_get_type ()))))))
;
2036 }
2037 g_object_set_data (G_OBJECT (adjust)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((adjust)), (((GType) ((20) << (2))))))))
, "COLORSEL", colorsel);
2038 *spinbutton = gtk_spin_button_new (adjust, 10.0, 0);
2039
2040 gtk_widget_set_tooltip_text (*spinbutton, tooltip);
2041
2042 g_signal_connect (adjust, "value-changed",g_signal_connect_data ((adjust), ("value-changed"), (((GCallback
) (adjustment_changed))), (((gpointer) (glong) (channel_type)
)), ((void*)0), (GConnectFlags) 0)
2043 G_CALLBACK (adjustment_changed),g_signal_connect_data ((adjust), ("value-changed"), (((GCallback
) (adjustment_changed))), (((gpointer) (glong) (channel_type)
)), ((void*)0), (GConnectFlags) 0)
2044 GINT_TO_POINTER (channel_type))g_signal_connect_data ((adjust), ("value-changed"), (((GCallback
) (adjustment_changed))), (((gpointer) (glong) (channel_type)
)), ((void*)0), (GConnectFlags) 0)
;
2045 label = gtk_label_new_with_mnemonic (text);
2046 gtk_label_set_mnemonic_widget (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, *spinbutton);
2047
2048 gtk_label_set_xalign (GTK_LABEL (label)((((GtkLabel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((label)), ((gtk_label_get_type ()))))))
, 0.0);
2049 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, label, i, j, 1, 1);
2050 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, *spinbutton, i+1, j, 1, 1);
2051}
2052
2053static void
2054make_palette_frame (MateColorSelection *colorsel,
2055 GtkWidget *grid,
2056 gint i,
2057 gint j)
2058{
2059 GtkWidget *frame;
2060 MateColorSelectionPrivate *priv;
2061
2062 priv = colorsel->private_data;
2063 frame = gtk_frame_new (NULL((void*)0));
2064 gtk_frame_set_shadow_type (GTK_FRAME (frame)((((GtkFrame*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame)), ((gtk_frame_get_type ()))))))
, GTK_SHADOW_IN);
2065 priv->custom_palette[i][j] = palette_new (colorsel);
2066 gtk_widget_set_size_request (priv->custom_palette[i][j], CUSTOM_PALETTE_ENTRY_WIDTH20, CUSTOM_PALETTE_ENTRY_HEIGHT20);
2067 gtk_container_add (GTK_CONTAINER (frame)((((GtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame)), ((gtk_container_get_type ()))))))
, priv->custom_palette[i][j]);
2068 gtk_widget_set_hexpand (frame, TRUE(!(0)));
2069 gtk_grid_attach (GTK_GRID (grid)((((GtkGrid*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((grid)), ((gtk_grid_get_type ()))))))
, frame, i, j, 1, 1);
2070}
2071
2072/* Set the palette entry [x][y] to be the currently selected one. */
2073static void
2074set_selected_palette (MateColorSelection *colorsel, int x, int y)
2075{
2076 MateColorSelectionPrivate *priv = colorsel->private_data;
2077
2078 gtk_widget_grab_focus (priv->custom_palette[x][y]);
2079}
2080
2081static double
2082scale_round (double val, double factor)
2083{
2084 val = floor (val * factor + 0.5);
2085 val = MAX (val, 0)(((val) > (0)) ? (val) : (0));
2086 val = MIN (val, factor)(((val) < (factor)) ? (val) : (factor));
2087 return val;
2088}
2089
2090static void
2091update_color (MateColorSelection *colorsel)
2092{
2093 MateColorSelectionPrivate *priv = colorsel->private_data;
2094 gchar entryval[12];
2095 gchar opacity_text[32];
2096 gchar *ptr;
2097 double r;
2098 double g;
2099 double b;
2100
2101 priv->changing = TRUE(!(0));
2102 color_sample_update_samples (colorsel);
2103
2104 mate_hsv_set_color (MATE_HSV (priv->triangle_colorsel)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->triangle_colorsel)), ((mate_hsv_get_type ()))))
))
,
2105 priv->color[COLORSEL_HUE],
2106 priv->color[COLORSEL_SATURATION],
2107 priv->color[COLORSEL_VALUE]);
2108 gtk_adjustment_set_value (gtk_spin_button_get_adjustment
2109 (GTK_SPIN_BUTTON (priv->hue_spinbutton)((((GtkSpinButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->hue_spinbutton)), ((gtk_spin_button_get_type ()
))))))
),
2110 scale_round (priv->color[COLORSEL_HUE], 360));
2111 gtk_adjustment_set_value (gtk_spin_button_get_adjustment
2112 (GTK_SPIN_BUTTON (priv->sat_spinbutton)((((GtkSpinButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->sat_spinbutton)), ((gtk_spin_button_get_type ()
))))))
),
2113 scale_round (priv->color[COLORSEL_SATURATION], 100));
2114 gtk_adjustment_set_value (gtk_spin_button_get_adjustment
2115 (GTK_SPIN_BUTTON (priv->val_spinbutton)((((GtkSpinButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->val_spinbutton)), ((gtk_spin_button_get_type ()
))))))
),
2116 scale_round (priv->color[COLORSEL_VALUE], 100));
2117 gtk_adjustment_set_value (gtk_spin_button_get_adjustment
2118 (GTK_SPIN_BUTTON (priv->red_spinbutton)((((GtkSpinButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->red_spinbutton)), ((gtk_spin_button_get_type ()
))))))
),
2119 scale_round (priv->color[COLORSEL_RED], 255));
2120 gtk_adjustment_set_value (gtk_spin_button_get_adjustment
2121 (GTK_SPIN_BUTTON (priv->green_spinbutton)((((GtkSpinButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->green_spinbutton)), ((gtk_spin_button_get_type (
)))))))
),
2122 scale_round (priv->color[COLORSEL_GREEN], 255));
2123 gtk_adjustment_set_value (gtk_spin_button_get_adjustment
2124 (GTK_SPIN_BUTTON (priv->blue_spinbutton)((((GtkSpinButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->blue_spinbutton)), ((gtk_spin_button_get_type (
)))))))
),
2125 scale_round (priv->color[COLORSEL_BLUE], 255));
2126 gtk_adjustment_set_value (gtk_range_get_adjustment
2127 (GTK_RANGE (priv->opacity_slider)((((GtkRange*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->opacity_slider)), ((gtk_range_get_type ()))))))
),
2128 scale_round (priv->color[COLORSEL_OPACITY], 255));
2129
2130 g_snprintf (opacity_text, 32, "%.0f", scale_round (priv->color[COLORSEL_OPACITY], 255));
2131 gtk_entry_set_text (GTK_ENTRY (priv->opacity_entry)((((GtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->opacity_entry)), ((gtk_entry_get_type ()))))))
, opacity_text);
2132
2133 r = scale_round (priv->color[COLORSEL_RED], 255);
2134 g = scale_round (priv->color[COLORSEL_GREEN], 255);
2135 b = scale_round (priv->color[COLORSEL_BLUE], 255);
2136 g_snprintf (entryval, 11, "#%2X%2X%2X", (guint) r, (guint) g, (guint) b);
2137
2138 for (ptr = entryval; *ptr; ptr++)
2139 if (*ptr == ' ')
2140 *ptr = '0';
2141 gtk_entry_set_text (GTK_ENTRY (priv->hex_entry)((((GtkEntry*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->hex_entry)), ((gtk_entry_get_type ()))))))
, entryval);
2142 priv->changing = FALSE(0);
2143
2144 g_object_ref (colorsel)((__typeof__ (colorsel)) (g_object_ref) (colorsel));
2145
2146 g_signal_emit (colorsel, color_selection_signals[COLOR_CHANGED], 0);
2147
2148 g_object_freeze_notify (G_OBJECT (colorsel)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((colorsel)), (((GType) ((20) << (2))))))))
);
2149 g_object_notify (G_OBJECT (colorsel)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((colorsel)), (((GType) ((20) << (2))))))))
, "current-rgba");
2150 g_object_notify (G_OBJECT (colorsel)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((colorsel)), (((GType) ((20) << (2))))))))
, "current-alpha");
2151 g_object_thaw_notify (G_OBJECT (colorsel)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((colorsel)), (((GType) ((20) << (2))))))))
);
2152
2153 g_object_unref (colorsel);
2154}
2155
2156static void
2157update_palette (MateColorSelection *colorsel)
2158{
2159 GdkRGBA *current_colors;
2160 gint i, j;
2161
2162 current_colors = get_current_colors (colorsel);
2163
2164 for (i = 0; i < GTK_CUSTOM_PALETTE_HEIGHT4; i++)
2165 {
2166 for (j = 0; j < GTK_CUSTOM_PALETTE_WIDTH9; j++)
2167 {
2168 gint index;
2169
2170 index = i * GTK_CUSTOM_PALETTE_WIDTH9 + j;
2171
2172 mate_color_selection_set_palette_color (colorsel,
2173 index,
2174 &current_colors[index]);
2175 }
2176 }
2177
2178 g_free (current_colors);
2179}
2180
2181static void
2182palette_change_notify_instance (GObject *object,
2183 GParamSpec *pspec,
2184 gpointer data)
2185{
2186 update_palette (MATE_COLOR_SELECTION (data)((((MateColorSelection*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((data)), ((mate_color_selection_get_type ()
))))))
);
2187}
2188
2189static void
2190default_noscreen_change_palette_func (const GdkRGBA *colors,
2191 gint n_colors)
2192{
2193 default_change_palette_func (gdk_screen_get_default (), colors, n_colors);
2194}
2195
2196static void
2197default_change_palette_func (GdkScreen *screen,
2198 const GdkRGBA *colors,
2199 gint n_colors)
2200{
2201 gchar *str;
2202
2203 str = mate_color_selection_palette_to_string (colors, n_colors);
2204
2205 g_object_set (G_OBJECT (gtk_settings_get_for_screen (screen))((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_settings_get_for_screen (screen))), (((GType) ((20) <<
(2))))))))
,
2206 "gtk-color-palette",
2207 str,
2208 NULL((void*)0));
2209
2210 g_free (str);
2211}
2212
2213/**
2214 * mate_color_selection_new:
2215 *
2216 * Creates a new MateColorSelection.
2217 *
2218 * Return value: a new #MateColorSelection
2219 **/
2220GtkWidget *
2221mate_color_selection_new (void)
2222{
2223 MateColorSelection *colorsel;
2224 MateColorSelectionPrivate *priv;
2225 gdouble color[4];
2226 color[0] = 1.0;
2227 color[1] = 1.0;
2228 color[2] = 1.0;
2229 color[3] = 1.0;
2230
2231 colorsel = g_object_new (MATE_TYPE_COLOR_SELECTION(mate_color_selection_get_type ()), "orientation", GTK_ORIENTATION_VERTICAL, NULL((void*)0));
2232 priv = colorsel->private_data;
2233 set_color_internal (colorsel, color);
2234 mate_color_selection_set_has_opacity_control (colorsel, TRUE(!(0)));
2235
2236 /* We want to make sure that default_set is FALSE */
2237 /* This way the user can still set it */
2238 priv->default_set = FALSE(0);
2239 priv->default_alpha_set = FALSE(0);
2240
2241 return GTK_WIDGET (colorsel)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((colorsel)), ((gtk_widget_get_type ()))))))
;
2242}
2243
2244/**
2245 * mate_color_selection_get_has_opacity_control:
2246 * @colorsel: a #MateColorSelection.
2247 *
2248 * Determines whether the colorsel has an opacity control.
2249 *
2250 * Return value: %TRUE if the @colorsel has an opacity control. %FALSE if it does't.
2251 **/
2252gboolean
2253mate_color_selection_get_has_opacity_control (MateColorSelection *colorsel)
2254{
2255 MateColorSelectionPrivate *priv;
2256
2257 g_return_val_if_fail (MATE_IS_COLOR_SELECTION (colorsel), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return ((0)); } } while (0)
;
2258
2259 priv = colorsel->private_data;
2260
2261 return priv->has_opacity;
2262}
2263
2264/**
2265 * mate_color_selection_set_has_opacity_control:
2266 * @colorsel: a #MateColorSelection.
2267 * @has_opacity: %TRUE if @colorsel can set the opacity, %FALSE otherwise.
2268 *
2269 * Sets the @colorsel to use or not use opacity.
2270 *
2271 **/
2272void
2273mate_color_selection_set_has_opacity_control (MateColorSelection *colorsel,
2274 gboolean has_opacity)
2275{
2276 MateColorSelectionPrivate *priv;
2277
2278 g_return_if_fail (MATE_IS_COLOR_SELECTION (colorsel))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return; } } while (0)
;
2279
2280 priv = colorsel->private_data;
2281 has_opacity = has_opacity != FALSE(0);
2282
2283 if (priv->has_opacity != has_opacity)
2284 {
2285 priv->has_opacity = (has_opacity != FALSE(0));
2286 if (has_opacity)
2287 {
2288 gtk_widget_show (priv->opacity_slider);
2289 gtk_widget_show (priv->opacity_label);
2290 gtk_widget_show (priv->opacity_entry);
2291 }
2292 else
2293 {
2294 gtk_widget_hide (priv->opacity_slider);
2295 gtk_widget_hide (priv->opacity_label);
2296 gtk_widget_hide (priv->opacity_entry);
2297 }
2298 color_sample_update_samples (colorsel);
2299
2300 g_object_notify (G_OBJECT (colorsel)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((colorsel)), (((GType) ((20) << (2))))))))
, "has-opacity-control");
2301 }
2302}
2303
2304/**
2305 * mate_color_selection_get_has_palette:
2306 * @colorsel: a #MateColorSelection.
2307 *
2308 * Determines whether the color selector has a color palette.
2309 *
2310 * Return value: %TRUE if the selector has a palette. %FALSE if it hasn't.
2311 **/
2312gboolean
2313mate_color_selection_get_has_palette (MateColorSelection *colorsel)
2314{
2315 MateColorSelectionPrivate *priv;
2316
2317 g_return_val_if_fail (MATE_IS_COLOR_SELECTION (colorsel), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return ((0)); } } while (0)
;
2318
2319 priv = colorsel->private_data;
2320
2321 return priv->has_palette;
2322}
2323
2324/**
2325 * mate_color_selection_set_has_palette:
2326 * @colorsel: a #MateColorSelection.
2327 * @has_palette: %TRUE if palette is to be visible, %FALSE otherwise.
2328 *
2329 * Shows and hides the palette based upon the value of @has_palette.
2330 *
2331 **/
2332void
2333mate_color_selection_set_has_palette (MateColorSelection *colorsel,
2334 gboolean has_palette)
2335{
2336 MateColorSelectionPrivate *priv;
2337 g_return_if_fail (MATE_IS_COLOR_SELECTION (colorsel))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return; } } while (0)
;
2338
2339 priv = colorsel->private_data;
2340 has_palette = has_palette != FALSE(0);
2341
2342 if (priv->has_palette != has_palette)
2343 {
2344 priv->has_palette = (has_palette != FALSE(0));
2345 if (has_palette)
2346 gtk_widget_show (priv->palette_frame);
2347 else
2348 gtk_widget_hide (priv->palette_frame);
2349
2350 update_tooltips (colorsel);
2351
2352 g_object_notify (G_OBJECT (colorsel)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((colorsel)), (((GType) ((20) << (2))))))))
, "has-palette");
2353 }
2354}
2355
2356/**
2357 * mate_color_selection_set_current_rgba:
2358 * @colorsel: a #MateColorSelection.
2359 * @color: A #GdkRGBA to set the current color with.
2360 *
2361 * Sets the current color to be @color. The first time this is called, it will
2362 * also set the original color to be @color too.
2363 **/
2364void
2365mate_color_selection_set_current_rgba (MateColorSelection *colorsel,
2366 const GdkRGBA *rgba)
2367{
2368 MateColorSelectionPrivate *priv;
2369 gint i;
2370
2371 g_return_if_fail (MATE_IS_COLOR_SELECTION (colorsel))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return; } } while (0)
;
2372 g_return_if_fail (rgba != NULL)do { if ((rgba != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "rgba != NULL");
return; } } while (0)
;
2373
2374 priv = colorsel->private_data;
2375 priv->changing = TRUE(!(0));
2376
2377 priv->color[COLORSEL_RED] = CLAMP (rgba->red, 0, 1)(((rgba->red) > (1)) ? (1) : (((rgba->red) < (0))
? (0) : (rgba->red)))
;
2378 priv->color[COLORSEL_GREEN] = CLAMP (rgba->green, 0, 1)(((rgba->green) > (1)) ? (1) : (((rgba->green) < (
0)) ? (0) : (rgba->green)))
;
2379 priv->color[COLORSEL_BLUE] = CLAMP (rgba->blue, 0, 1)(((rgba->blue) > (1)) ? (1) : (((rgba->blue) < (0
)) ? (0) : (rgba->blue)))
;
2380 priv->color[COLORSEL_OPACITY] = CLAMP (rgba->alpha, 0, 1)(((rgba->alpha) > (1)) ? (1) : (((rgba->alpha) < (
0)) ? (0) : (rgba->alpha)))
;
2381
2382 gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
2383 priv->color[COLORSEL_GREEN],
2384 priv->color[COLORSEL_BLUE],
2385 &priv->color[COLORSEL_HUE],
2386 &priv->color[COLORSEL_SATURATION],
2387 &priv->color[COLORSEL_VALUE]);
2388
2389 if (priv->default_set == FALSE(0))
2390 {
2391 for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
2392 priv->old_color[i] = priv->color[i];
2393 }
2394
2395 priv->default_set = TRUE(!(0));
2396 update_color (colorsel);
2397}
2398
2399/**
2400 * mate_color_selection_set_current_alpha:
2401 * @colorsel: a #MateColorSelection.
2402 * @alpha: an integer between 0 and 65535.
2403 *
2404 * Sets the current opacity to be @alpha. The first time this is called, it will
2405 * also set the original opacity to be @alpha too.
2406 **/
2407void
2408mate_color_selection_set_current_alpha (MateColorSelection *colorsel,
2409 guint16 alpha)
2410{
2411 MateColorSelectionPrivate *priv;
2412 gint i;
2413
2414 g_return_if_fail (MATE_IS_COLOR_SELECTION (colorsel))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return; } } while (0)
;
2415
2416 priv = colorsel->private_data;
2417 priv->changing = TRUE(!(0));
2418 priv->color[COLORSEL_OPACITY] = SCALE (alpha)(alpha / 65535.);
2419 if (priv->default_alpha_set == FALSE(0))
2420 {
2421 for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
2422 priv->old_color[i] = priv->color[i];
2423 }
2424 priv->default_alpha_set = TRUE(!(0));
2425 update_color (colorsel);
2426}
2427
2428/**
2429 * mate_color_selection_set_color:
2430 * @colorsel: a #MateColorSelection.
2431 * @color: an array of 4 doubles specifying the red, green, blue and opacity
2432 * to set the current color to.
2433 *
2434 * Sets the current color to be @color. The first time this is called, it will
2435 * also set the original color to be @color too.
2436 *
2437 * Deprecated: 2.0: Use mate_color_selection_set_current_color() instead.
2438 **/
2439void
2440mate_color_selection_set_color (MateColorSelection *colorsel,
2441 gdouble *color)
2442{
2443 g_return_if_fail (MATE_IS_COLOR_SELECTION (colorsel))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return; } } while (0)
;
2444
2445 set_color_internal (colorsel, color);
2446}
2447
2448/**
2449 * mate_color_selection_get_current_rgba:
2450 * @colorsel: a #MateColorSelection.
2451 * @color: (out): a #GdkRGBA to fill in with the current color.
2452 *
2453 * Sets @color to be the current color in the MateColorSelection widget.
2454 **/
2455void
2456mate_color_selection_get_current_rgba (MateColorSelection *colorsel,
2457 GdkRGBA *color)
2458{
2459 MateColorSelectionPrivate *priv;
2460
2461 g_return_if_fail (MATE_IS_COLOR_SELECTION (colorsel))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return; } } while (0)
;
2462 g_return_if_fail (color != NULL)do { if ((color != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "color != NULL")
; return; } } while (0)
;
2463
2464 priv = colorsel->private_data;
2465 color->red = priv->color[COLORSEL_RED];
2466 color->green = priv->color[COLORSEL_GREEN];
2467 color->blue = priv->color[COLORSEL_BLUE];
2468}
2469
2470/**
2471 * mate_color_selection_get_current_alpha:
2472 * @colorsel: a #MateColorSelection.
2473 *
2474 * Returns the current alpha value.
2475 *
2476 * Return value: an integer between 0 and 65535.
2477 **/
2478guint16
2479mate_color_selection_get_current_alpha (MateColorSelection *colorsel)
2480{
2481 MateColorSelectionPrivate *priv;
2482
2483 g_return_val_if_fail (MATE_IS_COLOR_SELECTION (colorsel), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return (0); } } while (0)
;
2484
2485 priv = colorsel->private_data;
2486 return priv->has_opacity ? UNSCALE (priv->color[COLORSEL_OPACITY])((guint16)(priv->color[COLORSEL_OPACITY] * 65535 + 0.5)) : 65535;
2487}
2488
2489/**
2490 * mate_color_selection_get_color:
2491 * @colorsel: a #MateColorSelection.
2492 * @color: an array of 4 #gdouble to fill in with the current color.
2493 *
2494 * Sets @color to be the current color in the MateColorSelection widget.
2495 *
2496 * Deprecated: 2.0: Use mate_color_selection_get_current_color() instead.
2497 **/
2498void
2499mate_color_selection_get_color (MateColorSelection *colorsel,
2500 gdouble *color)
2501{
2502 MateColorSelectionPrivate *priv;
2503
2504 g_return_if_fail (MATE_IS_COLOR_SELECTION (colorsel))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return; } } while (0)
;
2505
2506 priv = colorsel->private_data;
2507 color[0] = priv->color[COLORSEL_RED];
2508 color[1] = priv->color[COLORSEL_GREEN];
2509 color[2] = priv->color[COLORSEL_BLUE];
2510 color[3] = priv->has_opacity ? priv->color[COLORSEL_OPACITY] : 65535;
2511}
2512
2513/**
2514 * mate_color_selection_set_previous_color:
2515 * @colorsel: a #MateColorSelection.
2516 * @color: a #GdkRGBA to set the previous color with.
2517 *
2518 * Sets the 'previous' color to be @color. This function should be called with
2519 * some hesitations, as it might seem confusing to have that color change.
2520 * Calling mate_color_selection_set_current_color() will also set this color the first
2521 * time it is called.
2522 **/
2523void
2524mate_color_selection_set_previous_color (MateColorSelection *colorsel,
2525 const GdkRGBA *color)
2526{
2527 MateColorSelectionPrivate *priv;
2528
2529 g_return_if_fail (MATE_IS_COLOR_SELECTION (colorsel))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return; } } while (0)
;
2530 g_return_if_fail (color != NULL)do { if ((color != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "color != NULL")
; return; } } while (0)
;
2531
2532 priv = colorsel->private_data;
2533 priv->changing = TRUE(!(0));
2534 priv->old_color[COLORSEL_RED] = color->red;
2535 priv->old_color[COLORSEL_GREEN] = color->green;
2536 priv->old_color[COLORSEL_BLUE] = color->blue;
2537 gtk_rgb_to_hsv (priv->old_color[COLORSEL_RED],
2538 priv->old_color[COLORSEL_GREEN],
2539 priv->old_color[COLORSEL_BLUE],
2540 &priv->old_color[COLORSEL_HUE],
2541 &priv->old_color[COLORSEL_SATURATION],
2542 &priv->old_color[COLORSEL_VALUE]);
2543 color_sample_update_samples (colorsel);
2544 priv->default_set = TRUE(!(0));
2545 priv->changing = FALSE(0);
2546}
2547
2548/**
2549 * mate_color_selection_set_previous_alpha:
2550 * @colorsel: a #MateColorSelection.
2551 * @alpha: an integer between 0 and 65535.
2552 *
2553 * Sets the 'previous' alpha to be @alpha. This function should be called with
2554 * some hesitations, as it might seem confusing to have that alpha change.
2555 **/
2556void
2557mate_color_selection_set_previous_alpha (MateColorSelection *colorsel,
2558 guint16 alpha)
2559{
2560 MateColorSelectionPrivate *priv;
2561
2562 g_return_if_fail (MATE_IS_COLOR_SELECTION (colorsel))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return; } } while (0)
;
2563
2564 priv = colorsel->private_data;
2565 priv->changing = TRUE(!(0));
2566 priv->old_color[COLORSEL_OPACITY] = SCALE (alpha)(alpha / 65535.);
2567 color_sample_update_samples (colorsel);
2568 priv->default_alpha_set = TRUE(!(0));
2569 priv->changing = FALSE(0);
2570}
2571
2572/**
2573 * mate_color_selection_get_previous_color:
2574 * @colorsel: a #MateColorSelection.
2575 * @color: (out): a #GdkRGBA to fill in with the original color value.
2576 *
2577 * Fills @color in with the original color value.
2578 **/
2579void
2580mate_color_selection_get_previous_color (MateColorSelection *colorsel,
2581 GdkRGBA *color)
2582{
2583 MateColorSelectionPrivate *priv;
2584
2585 g_return_if_fail (MATE_IS_COLOR_SELECTION (colorsel))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return; } } while (0)
;
2586 g_return_if_fail (color != NULL)do { if ((color != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "color != NULL")
; return; } } while (0)
;
2587
2588 priv = colorsel->private_data;
2589 color->red = priv->old_color[COLORSEL_RED];
2590 color->green = priv->old_color[COLORSEL_GREEN];
2591 color->blue = priv->old_color[COLORSEL_BLUE];
2592}
2593
2594/**
2595 * mate_color_selection_get_previous_alpha:
2596 * @colorsel: a #MateColorSelection.
2597 *
2598 * Returns the previous alpha value.
2599 *
2600 * Return value: an integer between 0 and 65535.
2601 **/
2602guint16
2603mate_color_selection_get_previous_alpha (MateColorSelection *colorsel)
2604{
2605 MateColorSelectionPrivate *priv;
2606
2607 g_return_val_if_fail (MATE_IS_COLOR_SELECTION (colorsel), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return (0); } } while (0)
;
2608
2609 priv = colorsel->private_data;
2610 return priv->has_opacity ? UNSCALE (priv->old_color[COLORSEL_OPACITY])((guint16)(priv->old_color[COLORSEL_OPACITY] * 65535 + 0.5
))
: 65535;
2611}
2612
2613/**
2614 * mate_color_selection_set_palette_color:
2615 * @colorsel: a #MateColorSelection.
2616 * @index: the color index of the palette.
2617 * @color: A #GdkRGBA to set the palette with.
2618 *
2619 * Sets the palette located at @index to have @color as its color.
2620 *
2621 **/
2622static void
2623mate_color_selection_set_palette_color (MateColorSelection *colorsel,
2624 gint index,
2625 GdkRGBA *color)
2626{
2627 MateColorSelectionPrivate *priv;
2628 gint x, y;
2629 gdouble col[3];
2630
2631 g_return_if_fail (MATE_IS_COLOR_SELECTION (colorsel))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return; } } while (0)
;
2632 g_return_if_fail (index >= 0 && index < GTK_CUSTOM_PALETTE_WIDTH*GTK_CUSTOM_PALETTE_HEIGHT)do { if ((index >= 0 && index < 9*4)) { } else {
g_return_if_fail_warning ("MateDesktop", ((const char*) (__func__
)), "index >= 0 && index < GTK_CUSTOM_PALETTE_WIDTH*GTK_CUSTOM_PALETTE_HEIGHT"
); return; } } while (0)
;
2633
2634 x = index % GTK_CUSTOM_PALETTE_WIDTH9;
2635 y = index / GTK_CUSTOM_PALETTE_WIDTH9;
2636
2637 priv = colorsel->private_data;
2638 col[0] = color->red;
2639 col[1] = color->green;
2640 col[2] = color->blue;
2641
2642 palette_set_color (priv->custom_palette[x][y], colorsel, col);
2643}
2644
2645/**
2646 * mate_color_selection_is_adjusting:
2647 * @colorsel: a #MateColorSelection.
2648 *
2649 * Gets the current state of the @colorsel.
2650 *
2651 * Return value: %TRUE if the user is currently dragging a color around, and %FALSE
2652 * if the selection has stopped.
2653 **/
2654gboolean
2655mate_color_selection_is_adjusting (MateColorSelection *colorsel)
2656{
2657 MateColorSelectionPrivate *priv;
2658
2659 g_return_val_if_fail (MATE_IS_COLOR_SELECTION (colorsel), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((colorsel)); GType __t = ((mate_color_selection_get_type (
))); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "MATE_IS_COLOR_SELECTION (colorsel)"
); return ((0)); } } while (0)
;
2660
2661 priv = colorsel->private_data;
2662
2663 return (mate_hsv_is_adjusting (MATE_HSV (priv->triangle_colorsel)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((priv->triangle_colorsel)), ((mate_hsv_get_type ()))))
))
));
2664}
2665
2666/**
2667 * mate_color_selection_palette_from_string:
2668 * @str: a string encoding a color palette.
2669 * @colors: (out) (array length=n_colors): return location for allocated
2670 * array of #GdkRGBA.
2671 * @n_colors: return location for length of array.
2672 *
2673 * Parses a color palette string; the string is a colon-separated
2674 * list of color names readable by gdk_color_parse().
2675 *
2676 * Return value: %TRUE if a palette was successfully parsed.
2677 **/
2678gboolean
2679mate_color_selection_palette_from_string (const gchar *str,
2680 GdkRGBA **colors,
2681 gint *n_colors)
2682{
2683 GdkRGBA *retval;
2684 gint count;
2685 gchar *p;
2686 gchar *start;
2687 gchar *copy;
2688
2689 count = 0;
2690 retval = NULL((void*)0);
2691 copy = g_strdup (str)g_strdup_inline (str);
2692
2693 start = copy;
2694 p = copy;
2695 while (TRUE(!(0)))
2696 {
2697 if (*p == ':' || *p == '\0')
2698 {
2699 gboolean done = TRUE(!(0));
2700
2701 if (start == p)
2702 {
2703 goto failed; /* empty entry */
2704 }
2705
2706 if (*p)
2707 {
2708 *p = '\0';
2709 done = FALSE(0);
2710 }
2711
2712 retval = g_renew (GdkRGBA, retval, count + 1)((GdkRGBA *) g_realloc_n (retval, (count + 1), sizeof (GdkRGBA
)))
;
2713 if (!gdk_rgba_parse (retval + count, start))
2714 {
2715 goto failed;
2716 }
2717
2718 ++count;
2719
2720 if (done)
2721 break;
2722 else
2723 start = p + 1;
2724 }
2725
2726 ++p;
2727 }
2728
2729 g_free (copy);
2730
2731 if (colors)
2732 *colors = retval;
2733 else
2734 g_free (retval);
2735
2736 if (n_colors)
2737 *n_colors = count;
2738
2739 return TRUE(!(0));
2740
2741 failed:
2742 g_free (copy);
2743 g_free (retval);
2744
2745 if (colors)
2746 *colors = NULL((void*)0);
2747 if (n_colors)
2748 *n_colors = 0;
2749
2750 return FALSE(0);
2751}
2752
2753/**
2754 * mate_color_selection_palette_to_string:
2755 * @colors: (array length=n_colors): an array of colors.
2756 * @n_colors: length of the array.
2757 *
2758 * Encodes a palette as a string, useful for persistent storage.
2759 *
2760 * Return value: allocated string encoding the palette.
2761 **/
2762gchar*
2763mate_color_selection_palette_to_string (const GdkRGBA *colors,
2764 gint n_colors)
2765{
2766 gint i;
2767 gchar **strs = NULL((void*)0);
2768 gchar *retval;
2769
2770 if (n_colors == 0)
2771 return g_strdup ("")g_strdup_inline ("");
2772
2773 strs = g_new0 (gchar*, n_colors + 1)((gchar* *) g_malloc0_n ((n_colors + 1), sizeof (gchar*)));
2774
2775 i = 0;
2776 while (i < n_colors)
2777 {
2778 gchar *ptr;
2779
2780 strs[i] =
2781 g_strdup_printf ("#%2X%2X%2X",
2782 (unsigned int)colors[i].red * 255,
2783 (unsigned int)colors[i].green * 255,
2784 (unsigned int)colors[i].blue * 255);
2785
2786 for (ptr = strs[i]; *ptr; ptr++)
2787 if (*ptr == ' ')
2788 *ptr = '0';
2789
2790 ++i;
2791 }
2792
2793 retval = g_strjoinv (":", strs);
2794
2795 g_strfreev (strs);
2796
2797 return retval;
2798}
2799
2800/**
2801 * mate_color_selection_set_change_palette_hook:
2802 * @func: a function to call when the custom palette needs saving.
2803 *
2804 * Installs a global function to be called whenever the user tries to
2805 * modify the palette in a color selection. This function should save
2806 * the new palette contents, and update the GtkSettings property
2807 * "gtk-color-palette" so all MateColorSelection widgets will be modified.
2808 *
2809 * Return value: the previous change palette hook (that was replaced).
2810 *
2811 * Deprecated: 2.4: This function does not work in multihead environments.
2812 * Use mate_color_selection_set_change_palette_with_screen_hook() instead.
2813 *
2814 **/
2815MateColorSelectionChangePaletteFunc
2816mate_color_selection_set_change_palette_hook (MateColorSelectionChangePaletteFunc func)
2817{
2818 MateColorSelectionChangePaletteFunc old;
2819
2820 old = noscreen_change_palette_hook;
2821
2822 noscreen_change_palette_hook = func;
2823
2824 return old;
2825}
2826
2827/**
2828 * mate_color_selection_set_change_palette_with_screen_hook:
2829 * @func: a function to call when the custom palette needs saving.
2830 *
2831 * Installs a global function to be called whenever the user tries to
2832 * modify the palette in a color selection. This function should save
2833 * the new palette contents, and update the GtkSettings property
2834 * "gtk-color-palette" so all MateColorSelection widgets will be modified.
2835 *
2836 * Return value: the previous change palette hook (that was replaced).
2837 *
2838 * Since: 1.9.1
2839 **/
2840MateColorSelectionChangePaletteWithScreenFunc
2841mate_color_selection_set_change_palette_with_screen_hook (MateColorSelectionChangePaletteWithScreenFunc func)
2842{
2843 MateColorSelectionChangePaletteWithScreenFunc old;
2844
2845 old = change_palette_hook;
2846
2847 change_palette_hook = func;
2848
2849 return old;
2850}
2851
2852static void
2853make_control_relations (AtkObject *atk_obj,
2854 GtkWidget *widget)
2855{
2856 AtkObject *obj;
2857
2858 obj = gtk_widget_get_accessible (widget);
2859 atk_object_add_relationship (atk_obj, ATK_RELATION_CONTROLLED_BY, obj);
2860 atk_object_add_relationship (obj, ATK_RELATION_CONTROLLER_FOR, atk_obj);
2861}
2862
2863static void
2864make_all_relations (AtkObject *atk_obj,
2865 MateColorSelectionPrivate *priv)
2866{
2867 make_control_relations (atk_obj, priv->hue_spinbutton);
2868 make_control_relations (atk_obj, priv->sat_spinbutton);
2869 make_control_relations (atk_obj, priv->val_spinbutton);
2870 make_control_relations (atk_obj, priv->red_spinbutton);
2871 make_control_relations (atk_obj, priv->green_spinbutton);
2872 make_control_relations (atk_obj, priv->blue_spinbutton);
2873}
2874
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-30e8a4.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-30e8a4.html new file mode 100644 index 0000000..99eb01b --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-30e8a4.html @@ -0,0 +1,4660 @@ + + + +mate-desktop-item.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-desktop-item.c
Warning:line 3121, column 9
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-desktop-item.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-desktop-item.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* mate-desktop-item.c - MATE Desktop File Representation
3
4 Copyright (C) 1999, 2000 Red Hat Inc.
5 Copyright (C) 2001 Sid Vicious
6 All rights reserved.
7
8 This file is part of the Mate Library.
9
10 Developed by Elliot Lee <sopwith@redhat.com> and Sid Vicious
11
12 The Mate Library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Library General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
16
17 The Mate Library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Library General Public License for more details.
21
22 You should have received a copy of the GNU Library General Public
23 License along with the Mate Library; see the file COPYING.LIB. If not,
24 write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 Boston, MA 02110-1301, USA. */
26/*
27 @NOTATION@
28 */
29
30#include "config.h"
31
32#include <limits.h>
33#include <ctype.h>
34#include <stdio.h>
35#include <glib.h>
36#include <sys/types.h>
37#include <dirent.h>
38#include <unistd.h>
39#include <time.h>
40#include <string.h>
41#include <glib/gi18n-lib.h>
42#include <locale.h>
43#include <stdlib.h>
44
45#include <gio/gio.h>
46
47#ifdef HAVE_STARTUP_NOTIFICATION
48#define SN_API_NOT_YET_FROZEN
49#include <libsn/sn.h>
50#include <gdk/gdk.h>
51#include <gdk/gdkx.h>
52#include <gtk/gtk.h>
53#endif
54
55#define MATE_DESKTOP_USE_UNSTABLE_API
56#undef MATE_DISABLE_DEPRECATED
57#include <mate-desktop-item.h>
58#include <mate-desktop-utils.h>
59
60#include "private.h"
61
62struct _MateDesktopItem {
63 int refcount;
64
65 /* all languages used */
66 GList *languages;
67
68 MateDesktopItemType type;
69
70 /* `modified' means that the ditem has been
71 * modified since the last save. */
72 gboolean modified;
73
74 /* Keys of the main section only */
75 GList *keys;
76
77 GList *sections;
78
79 /* This includes ALL keys, including
80 * other sections, separated by '/' */
81 GHashTable *main_hash;
82
83 char *location;
84
85 gint64 mtime;
86
87 guint32 launch_time;
88};
89
90/* If mtime is set to this, set_location won't update mtime,
91 * this is to be used internally only. */
92#define DONT_UPDATE_MTIME((gint64)-2) ((gint64)-2)
93
94typedef struct {
95 char *name;
96 GList *keys;
97} Section;
98
99typedef enum {
100 ENCODING_UNKNOWN,
101 ENCODING_UTF8,
102 ENCODING_LEGACY_MIXED
103} Encoding;
104
105/*
106 * IO reading utils, that look like the libc buffered io stuff
107 */
108
109#define READ_BUF_SIZE(32 * 1024) (32 * 1024)
110
111typedef struct {
112 GFile *file;
113 GFileInputStream *stream;
114 char *uri;
115 char *buf;
116 gboolean buf_needs_free;
117 gboolean past_first_read;
118 gboolean eof;
119 guint64 size;
120 gsize pos;
121} ReadBuf;
122
123static MateDesktopItem *ditem_load (ReadBuf *rb,
124 gboolean no_translations,
125 GError **error);
126static gboolean ditem_save (MateDesktopItem *item,
127 const char *uri,
128 GError **error);
129
130static void mate_desktop_item_set_location_gfile (MateDesktopItem *item,
131 GFile *file);
132
133static MateDesktopItem *mate_desktop_item_new_from_gfile (GFile *file,
134 MateDesktopItemLoadFlags flags,
135 GError **error);
136
137static int
138readbuf_getc (ReadBuf *rb)
139{
140 if (rb->eof)
141 return EOF(-1);
142
143 if (rb->size == 0 ||
144 rb->pos == rb->size) {
145 gssize bytes_read;
146
147 if (rb->stream == NULL((void*)0))
148 bytes_read = 0;
149 else
150 bytes_read = g_input_stream_read (G_INPUT_STREAM (rb->stream)((((GInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((rb->stream)), ((g_input_stream_get_type ()))))))
,
151 rb->buf,
152 READ_BUF_SIZE(32 * 1024),
153 NULL((void*)0), NULL((void*)0));
154
155 /* FIXME: handle errors other than EOF */
156 if (bytes_read <= 0) {
157 rb->eof = TRUE(!(0));
158 return EOF(-1);
159 }
160
161 if (rb->size != 0)
162 rb->past_first_read = TRUE(!(0));
163 rb->size = bytes_read;
164 rb->pos = 0;
165
166 }
167
168 return (guchar) rb->buf[rb->pos++];
169}
170
171/* Note, does not include the trailing \n */
172static char *
173readbuf_gets (char *buf, gsize bufsize, ReadBuf *rb)
174{
175 int c;
176 gsize pos;
177
178 g_return_val_if_fail (buf != NULL, NULL)do { if ((buf != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "buf != NULL"); return
(((void*)0)); } } while (0)
;
179 g_return_val_if_fail (rb != NULL, NULL)do { if ((rb != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "rb != NULL"); return
(((void*)0)); } } while (0)
;
180
181 pos = 0;
182 buf[0] = '\0';
183
184 do {
185 c = readbuf_getc (rb);
186 if (c == EOF(-1) || c == '\n')
187 break;
188 buf[pos++] = c;
189 } while (pos < bufsize-1);
190
191 if (c == EOF(-1) && pos == 0)
192 return NULL((void*)0);
193
194 buf[pos++] = '\0';
195
196 return buf;
197}
198
199static ReadBuf *
200readbuf_open (GFile *file, GError **error)
201{
202 GError *local_error;
203 GFileInputStream *stream;
204 char *uri;
205 ReadBuf *rb;
206
207 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
208
209 uri = g_file_get_uri (file);
210 local_error = NULL((void*)0);
211 stream = g_file_read (file, NULL((void*)0), &local_error);
212
213 if (stream == NULL((void*)0)) {
214 g_set_error (error,
215 /* FIXME: better errors */
216 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
217 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
218 _("Error reading file '%s': %s")((char *) g_dgettext ("mate-desktop", "Error reading file '%s': %s"
))
,
219 uri, local_error->message);
220 g_error_free (local_error);
221 g_free (uri);
222 return NULL((void*)0);
223 }
224
225 rb = g_new0 (ReadBuf, 1)((ReadBuf *) g_malloc0_n ((1), sizeof (ReadBuf)));
226 rb->stream = stream;
227 rb->file = g_file_dup (file);
228 rb->uri = uri;
229 rb->buf = g_malloc (READ_BUF_SIZE(32 * 1024));
230 rb->buf_needs_free = TRUE(!(0));
231 /* rb->past_first_read = FALSE; */
232 /* rb->eof = FALSE; */
233 /* rb->size = 0; */
234 /* rb->pos = 0; */
235
236 return rb;
237}
238
239static ReadBuf *
240readbuf_new_from_string (const char *uri, const char *string, gssize length)
241{
242 ReadBuf *rb;
243
244 g_return_val_if_fail (string != NULL, NULL)do { if ((string != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "string != NULL"
); return (((void*)0)); } } while (0)
;
245 g_return_val_if_fail (length >= 0, NULL)do { if ((length >= 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "length >= 0"
); return (((void*)0)); } } while (0)
;
246
247 rb = g_new0 (ReadBuf, 1)((ReadBuf *) g_malloc0_n ((1), sizeof (ReadBuf)));
248 /* rb->file = NULL; */
249 /* rb->stream = NULL; */
250 rb->uri = g_strdup (uri)g_strdup_inline (uri);
251 rb->buf = (char *) string;
252 /* rb->buf_needs_free = FALSE; */
253 /* rb->past_first_read = FALSE; */
254 /* rb->eof = FALSE; */
255 rb->size = length;
256 /* rb->pos = 0; */
257
258 return rb;
259}
260
261static gboolean
262readbuf_rewind (ReadBuf *rb, GError **error)
263{
264 GError *local_error;
265
266 rb->eof = FALSE(0);
267 rb->pos = 0;
268
269 if (!rb->past_first_read)
270 return TRUE(!(0));
271
272 rb->size = 0;
273
274 if (g_seekable_seek (G_SEEKABLE (rb->stream)((((GSeekable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((rb->stream)), ((g_seekable_get_type ()))))))
,
275 0, G_SEEK_SET, NULL((void*)0), NULL((void*)0)))
276 return TRUE(!(0));
277
278 g_object_unref (rb->stream);
279 local_error = NULL((void*)0);
280 rb->stream = g_file_read (rb->file, NULL((void*)0), &local_error);
281
282 if (rb->stream == NULL((void*)0)) {
283 g_set_error (
284 error, MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
285 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
286 _("Error rewinding file '%s': %s")((char *) g_dgettext ("mate-desktop", "Error rewinding file '%s': %s"
))
,
287 rb->uri, local_error->message);
288 g_error_free (local_error);
289
290 return FALSE(0);
291 }
292
293 return TRUE(!(0));
294}
295
296static void
297readbuf_close (ReadBuf *rb)
298{
299 if (rb->stream != NULL((void*)0))
300 g_object_unref (rb->stream);
301 if (rb->file != NULL((void*)0))
302 g_object_unref (rb->file);
303 g_free (rb->uri);
304 if (rb->buf_needs_free)
305 g_free (rb->buf);
306 g_free (rb);
307}
308
309static MateDesktopItemType
310type_from_string (const char *type)
311{
312 if (!type)
313 return MATE_DESKTOP_ITEM_TYPE_NULL;
314
315 switch (type [0]) {
316 case 'A':
317 if (!strcmp (type, "Application"))
318 return MATE_DESKTOP_ITEM_TYPE_APPLICATION;
319 break;
320 case 'L':
321 if (!strcmp (type, "Link"))
322 return MATE_DESKTOP_ITEM_TYPE_LINK;
323 break;
324 case 'F':
325 if (!strcmp (type, "FSDevice"))
326 return MATE_DESKTOP_ITEM_TYPE_FSDEVICE;
327 break;
328 case 'M':
329 if (!strcmp (type, "MimeType"))
330 return MATE_DESKTOP_ITEM_TYPE_MIME_TYPE;
331 break;
332 case 'D':
333 if (!strcmp (type, "Directory"))
334 return MATE_DESKTOP_ITEM_TYPE_DIRECTORY;
335 break;
336 case 'S':
337 if (!strcmp (type, "Service"))
338 return MATE_DESKTOP_ITEM_TYPE_SERVICE;
339
340 else if (!strcmp (type, "ServiceType"))
341 return MATE_DESKTOP_ITEM_TYPE_SERVICE_TYPE;
342 break;
343 default:
344 break;
345 }
346
347 return MATE_DESKTOP_ITEM_TYPE_OTHER;
348}
349
350/**
351 * mate_desktop_item_new:
352 *
353 * Creates a MateDesktopItem object. The reference count on the returned value is set to '1'.
354 *
355 * Returns: The new MateDesktopItem
356 */
357MateDesktopItem *
358mate_desktop_item_new (void)
359{
360 MateDesktopItem *retval;
361
362 _mate_desktop_init_i18n ();
363
364 retval = g_new0 (MateDesktopItem, 1)((MateDesktopItem *) g_malloc0_n ((1), sizeof (MateDesktopItem
)))
;
365
366 retval->refcount++;
367
368 retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
369 (GDestroyNotify) g_free,
370 (GDestroyNotify) g_free);
371
372 /* These are guaranteed to be set */
373 mate_desktop_item_set_string (retval,
374 MATE_DESKTOP_ITEM_NAME"Name",
375 /* Translators: the "name" mentioned
376 * here is the name of an application or
377 * a document */
378 _("No name")((char *) g_dgettext ("mate-desktop", "No name")));
379 mate_desktop_item_set_string (retval,
380 MATE_DESKTOP_ITEM_ENCODING"Encoding",
381 "UTF-8");
382 mate_desktop_item_set_string (retval,
383 MATE_DESKTOP_ITEM_VERSION"Version",
384 "1.0");
385
386 retval->launch_time = 0;
387
388 return retval;
389}
390
391static Section *
392dup_section (Section *sec)
393{
394 GList *li;
395 Section *retval = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
396
397 retval->name = g_strdup (sec->name)g_strdup_inline (sec->name);
398
399 retval->keys = g_list_copy (sec->keys);
400 for (li = retval->keys; li != NULL((void*)0); li = li->next)
401 li->data = g_strdup (li->data)g_strdup_inline (li->data);
402
403 return retval;
404}
405
406static void
407copy_string_hash (gpointer key, gpointer value, gpointer user_data)
408{
409 GHashTable *copy = user_data;
410 g_hash_table_replace (copy,
411 g_strdup (key)g_strdup_inline (key),
412 g_strdup (value)g_strdup_inline (value));
413}
414
415/**
416 * mate_desktop_item_copy:
417 * @item: The item to be copied
418 *
419 * Creates a copy of a MateDesktopItem. The new copy has a refcount of 1.
420 * Note: Section stack is NOT copied.
421 *
422 * Returns: The new copy
423 */
424MateDesktopItem *
425mate_desktop_item_copy (const MateDesktopItem *item)
426{
427 GList *li;
428 MateDesktopItem *retval;
429
430 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
431 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
432
433 retval = mate_desktop_item_new ();
434
435 retval->type = item->type;
436 retval->modified = item->modified;
437 retval->location = g_strdup (item->location)g_strdup_inline (item->location);
438 retval->mtime = item->mtime;
439 retval->launch_time = item->launch_time;
440
441 /* Languages */
442 retval->languages = g_list_copy (item->languages);
443 for (li = retval->languages; li != NULL((void*)0); li = li->next)
444 li->data = g_strdup (li->data)g_strdup_inline (li->data);
445
446 /* Keys */
447 retval->keys = g_list_copy (item->keys);
448 for (li = retval->keys; li != NULL((void*)0); li = li->next)
449 li->data = g_strdup (li->data)g_strdup_inline (li->data);
450
451 /* Sections */
452 retval->sections = g_list_copy (item->sections);
453 for (li = retval->sections; li != NULL((void*)0); li = li->next)
454 li->data = dup_section (li->data);
455
456 retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
457 (GDestroyNotify) g_free,
458 (GDestroyNotify) g_free);
459
460 g_hash_table_foreach (item->main_hash,
461 copy_string_hash,
462 retval->main_hash);
463
464 return retval;
465}
466
467static void
468read_sort_order (MateDesktopItem *item, GFile *dir)
469{
470 GFile *child;
471 char buf[BUFSIZ8192];
472 GString *str;
473 ReadBuf *rb;
474
475 child = g_file_get_child (dir, ".order");
476
477 rb = readbuf_open (child, NULL((void*)0));
478 g_object_unref (child);
479
480 if (rb == NULL((void*)0))
481 return;
482
483 str = NULL((void*)0);
484 while (readbuf_gets (buf, sizeof (buf), rb) != NULL((void*)0)) {
485 if (str == NULL((void*)0))
486 str = g_string_new (buf);
487 else
488 g_string_append (str, buf)(__builtin_constant_p (buf) ? __extension__ ({ const char * const
__val = (buf); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, buf, (gssize) -1
))
;
489 g_string_append_c (str, ';')g_string_append_c_inline (str, ';');
490 }
491 readbuf_close (rb);
492 if (str != NULL((void*)0)) {
493 mate_desktop_item_set_string (item, MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder",
494 str->str);
495 g_string_free (str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(str), ((!(0)))) : g_string_free_and_steal (str)) : (g_string_free
) ((str), ((!(0)))))
;
496 }
497}
498
499static MateDesktopItem *
500make_fake_directory (GFile *dir)
501{
502 MateDesktopItem *item;
503 GFile *child;
504
505 item = mate_desktop_item_new ();
506 mate_desktop_item_set_entry_type (item,
507 MATE_DESKTOP_ITEM_TYPE_DIRECTORY);
508
509 item->mtime = DONT_UPDATE_MTIME((gint64)-2); /* it doesn't exist, we know that */
510 child = g_file_get_child (dir, ".directory");
511 mate_desktop_item_set_location_gfile (item, child);
512 item->mtime = 0;
513 g_object_unref (child);
514
515 read_sort_order (item, dir);
516
517 return item;
518}
519
520/**
521 * mate_desktop_item_new_from_file:
522 * @file: The filename or directory path to load the MateDesktopItem from
523 * @flags: Flags to influence the loading process
524 *
525 * This function loads 'file' and turns it into a MateDesktopItem.
526 *
527 * Returns: The newly loaded item.
528 */
529MateDesktopItem *
530mate_desktop_item_new_from_file (const char *file,
531 MateDesktopItemLoadFlags flags,
532 GError **error)
533{
534 MateDesktopItem *retval;
535 GFile *gfile;
536
537 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
538
539 gfile = g_file_new_for_path (file);
540 retval = mate_desktop_item_new_from_gfile (gfile, flags, error);
541 g_object_unref (gfile);
542
543 return retval;
544}
545
546/**
547 * mate_desktop_item_new_from_uri:
548 * @uri: URI to load the MateDesktopItem from
549 * @flags: Flags to influence the loading process
550 *
551 * This function loads 'uri' and turns it into a MateDesktopItem.
552 *
553 * Returns: The newly loaded item.
554 */
555MateDesktopItem *
556mate_desktop_item_new_from_uri (const char *uri,
557 MateDesktopItemLoadFlags flags,
558 GError **error)
559{
560 MateDesktopItem *retval;
561 GFile *file;
562
563 g_return_val_if_fail (uri != NULL, NULL)do { if ((uri != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "uri != NULL"); return
(((void*)0)); } } while (0)
;
564
565 file = g_file_new_for_uri (uri);
566 retval = mate_desktop_item_new_from_gfile (file, flags, error);
567 g_object_unref (file);
568
569 return retval;
570}
571
572static MateDesktopItem *
573mate_desktop_item_new_from_gfile (GFile *file,
574 MateDesktopItemLoadFlags flags,
575 GError **error)
576{
577 MateDesktopItem *retval;
578 GFile *subfn;
579 GFileInfo *info;
580 GFileType type;
581 GFile *parent;
582 gint64 mtime = 0;
583 ReadBuf *rb;
584
585 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
586
587 info = g_file_query_info (file,
588 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type"","G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
589 G_FILE_QUERY_INFO_NONE, NULL((void*)0), error);
590 if (info == NULL((void*)0))
591 return NULL((void*)0);
592
593 type = g_file_info_get_file_type (info);
594
595 if (type != G_FILE_TYPE_REGULAR && type != G_FILE_TYPE_DIRECTORY) {
596 char *uri;
597
598 uri = g_file_get_uri (file);
599 g_set_error (error,
600 /* FIXME: better errors */
601 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
602 MATE_DESKTOP_ITEM_ERROR_INVALID_TYPE,
603 _("File '%s' is not a regular file or directory.")((char *) g_dgettext ("mate-desktop", "File '%s' is not a regular file or directory."
))
,
604 uri);
605
606 g_free (uri);
607 g_object_unref (info);
608
609 return NULL((void*)0);
610 }
611
612 mtime = g_file_info_get_attribute_uint64 (info,
613 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
614
615 g_object_unref (info);
616
617 if (type == G_FILE_TYPE_DIRECTORY) {
618 GFile *child;
619 GFileInfo *child_info;
620
621 child = g_file_get_child (file, ".directory");
622 child_info = g_file_query_info (child,
623 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
624 G_FILE_QUERY_INFO_NONE,
625 NULL((void*)0), NULL((void*)0));
626
627 if (child_info == NULL((void*)0)) {
628 g_object_unref (child);
629
630 if (flags & MATE_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS) {
631 return NULL((void*)0);
632 } else {
633 return make_fake_directory (file);
634 }
635 }
636
637 mtime = g_file_info_get_attribute_uint64 (child_info,
638 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
639 g_object_unref (child_info);
640
641 subfn = child;
642 } else {
643 subfn = g_file_dup (file);
644 }
645
646 rb = readbuf_open (subfn, error);
647
648 if (rb == NULL((void*)0)) {
649 g_object_unref (subfn);
650 return NULL((void*)0);
651 }
652
653 retval = ditem_load (rb,
654 (flags & MATE_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS) != 0,
655 error);
656
657 if (retval == NULL((void*)0)) {
658 g_object_unref (subfn);
659 return NULL((void*)0);
660 }
661
662 if (flags & MATE_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS &&
663 ! mate_desktop_item_exists (retval)) {
664 mate_desktop_item_unref (retval);
665 g_object_unref (subfn);
666 return NULL((void*)0);
667 }
668
669 retval->mtime = DONT_UPDATE_MTIME((gint64)-2);
670 mate_desktop_item_set_location_gfile (retval, subfn);
671 retval->mtime = mtime;
672
673 parent = g_file_get_parent (file);
674 if (parent != NULL((void*)0)) {
675 read_sort_order (retval, parent);
676 g_object_unref (parent);
677 }
678
679 g_object_unref (subfn);
680
681 return retval;
682}
683
684/**
685 * mate_desktop_item_new_from_string:
686 * @string: string to load the MateDesktopItem from
687 * @length: length of string, or -1 to use strlen
688 * @flags: Flags to influence the loading process
689 * @error: place to put errors
690 *
691 * This function turns the contents of the string into a MateDesktopItem.
692 *
693 * Returns: The newly loaded item.
694 */
695MateDesktopItem *
696mate_desktop_item_new_from_string (const char *uri,
697 const char *string,
698 gssize length,
699 MateDesktopItemLoadFlags flags,
700 GError **error)
701{
702 MateDesktopItem *retval;
703 ReadBuf *rb;
704
705 g_return_val_if_fail (string != NULL, NULL)do { if ((string != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "string != NULL"
); return (((void*)0)); } } while (0)
;
706 g_return_val_if_fail (length >= -1, NULL)do { if ((length >= -1)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "length >= -1"
); return (((void*)0)); } } while (0)
;
707
708 if (length == -1) {
709 length = strlen (string);
710 }
711
712 rb = readbuf_new_from_string (uri, string, length);
713
714 retval = ditem_load (rb,
715 (flags & MATE_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS) != 0,
716 error);
717
718 if (retval == NULL((void*)0)) {
719 return NULL((void*)0);
720 }
721
722 /* FIXME: Sort order? */
723
724 return retval;
725}
726
727static char *
728lookup_desktop_file_in_data_dir (const char *desktop_file,
729 const char *data_dir)
730{
731 char *path;
732
733 path = g_build_filename (data_dir, "applications", desktop_file, NULL((void*)0));
734 if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
735 g_free (path);
736 return NULL((void*)0);
737 }
738 return path;
739}
740
741static char *
742file_from_basename (const char *basename)
743{
744 const char * const *system_data_dirs;
745 const char *user_data_dir;
746 char *retval;
747 int i;
748
749 user_data_dir = g_get_user_data_dir ();
750 system_data_dirs = g_get_system_data_dirs ();
751
752 if ((retval = lookup_desktop_file_in_data_dir (basename, user_data_dir))) {
753 return retval;
754 }
755 for (i = 0; system_data_dirs[i]; i++) {
756 if ((retval = lookup_desktop_file_in_data_dir (basename, system_data_dirs[i]))) {
757 return retval;
758 }
759 }
760 return NULL((void*)0);
761}
762
763/**
764 * mate_desktop_item_new_from_basename:
765 * @basename: The basename of the MateDesktopItem to load.
766 * @flags: Flags to influence the loading process
767 *
768 * This function loads 'basename' from a system data directory and
769 * returns its MateDesktopItem.
770 *
771 * Returns: The newly loaded item.
772 */
773MateDesktopItem *
774mate_desktop_item_new_from_basename (const char *basename,
775 MateDesktopItemLoadFlags flags,
776 GError **error)
777{
778 MateDesktopItem *retval;
779 char *file;
780
781 g_return_val_if_fail (basename != NULL, NULL)do { if ((basename != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "basename != NULL"
); return (((void*)0)); } } while (0)
;
782
783 if (!(file = file_from_basename (basename))) {
784 g_set_error (error,
785 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
786 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
787 _("Cannot find file '%s'")((char *) g_dgettext ("mate-desktop", "Cannot find file '%s'"
))
,
788 basename);
789 return NULL((void*)0);
790 }
791
792 retval = mate_desktop_item_new_from_file (file, flags, error);
793 g_free (file);
794
795 return retval;
796}
797
798/**
799 * mate_desktop_item_save:
800 * @item: A desktop item
801 * @under: A new uri (location) for this #MateDesktopItem
802 * @force: Save even if it wasn't modified
803 * @error: #GError return
804 *
805 * Writes the specified item to disk. If the 'under' is NULL, the original
806 * location is used. It sets the location of this entry to point to the
807 * new location.
808 *
809 * Returns: boolean. %TRUE if the file was saved, %FALSE otherwise
810 */
811gboolean
812mate_desktop_item_save (MateDesktopItem *item,
813 const char *under,
814 gboolean force,
815 GError **error)
816{
817 const char *uri;
818
819 if (under == NULL((void*)0) &&
1
Assuming 'under' is not equal to NULL
820 ! force &&
821 ! item->modified)
822 return TRUE(!(0));
823
824 if (under
1.1
'under' is not equal to NULL
== NULL((void*)0))
2
Taking false branch
825 uri = item->location;
826 else
827 uri = under;
828
829 if (uri
2.1
'uri' is not equal to NULL
== NULL((void*)0)) {
3
Taking false branch
830 g_set_error (error,
831 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
832 MATE_DESKTOP_ITEM_ERROR_NO_FILENAME,
833 _("No filename to save to")((char *) g_dgettext ("mate-desktop", "No filename to save to"
))
);
834 return FALSE(0);
835 }
836
837 if ( ! ditem_save (item, uri, error))
4
Calling 'ditem_save'
838 return FALSE(0);
839
840 item->modified = FALSE(0);
841 item->mtime = g_get_real_time () / G_USEC_PER_SEC1000000;
842
843 return TRUE(!(0));
844}
845
846/**
847 * mate_desktop_item_ref:
848 * @item: A desktop item
849 *
850 * Description: Increases the reference count of the specified item.
851 *
852 * Returns: the newly referenced @item
853 */
854MateDesktopItem *
855mate_desktop_item_ref (MateDesktopItem *item)
856{
857 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
858
859 item->refcount++;
860
861 return item;
862}
863
864static void
865free_section (gpointer data)
866{
867 Section *section = data;
868
869 g_free (section->name);
870 section->name = NULL((void*)0);
871
872 g_list_free_full (section->keys, g_free);
873 section->keys = NULL((void*)0);
874
875 g_free (section);
876}
877
878/**
879 * mate_desktop_item_unref:
880 * @item: A desktop item
881 *
882 * Decreases the reference count of the specified item, and destroys the item if there are no more references left.
883 */
884void
885mate_desktop_item_unref (MateDesktopItem *item)
886{
887 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
888 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
889
890 item->refcount--;
891
892 if(item->refcount != 0)
893 return;
894
895 g_list_free_full (item->languages, g_free);
896 item->languages = NULL((void*)0);
897
898 g_list_free_full (item->keys, g_free);
899 item->keys = NULL((void*)0);
900
901 g_list_free_full (item->sections, (GDestroyNotify) free_section);
902 item->sections = NULL((void*)0);
903
904 g_hash_table_destroy (item->main_hash);
905 item->main_hash = NULL((void*)0);
906
907 g_free (item->location);
908 item->location = NULL((void*)0);
909
910 g_free (item);
911}
912
913static Section *
914find_section (MateDesktopItem *item, const char *section)
915{
916 GList *li;
917 Section *sec;
918
919 if (section == NULL((void*)0))
920 return NULL((void*)0);
921 if (strcmp (section, "Desktop Entry") == 0)
922 return NULL((void*)0);
923
924 for (li = item->sections; li != NULL((void*)0); li = li->next) {
925 sec = li->data;
926 if (strcmp (sec->name, section) == 0)
927 return sec;
928 }
929
930 sec = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
931 sec->name = g_strdup (section)g_strdup_inline (section);
932 sec->keys = NULL((void*)0);
933
934 item->sections = g_list_append (item->sections, sec);
935
936 /* Don't mark the item modified, this is just an empty section,
937 * it won't be saved even */
938
939 return sec;
940}
941
942static Section *
943section_from_key (MateDesktopItem *item, const char *key)
944{
945 char *p;
946 char *name;
947 Section *sec;
948
949 if (key == NULL((void*)0))
950 return NULL((void*)0);
951
952 p = strchr (key, '/');
953 if (p == NULL((void*)0))
954 return NULL((void*)0);
955
956 name = g_strndup (key, p - key);
957
958 sec = find_section (item, name);
959
960 g_free (name);
961
962 return sec;
963}
964
965static const char *
966key_basename (const char *key)
967{
968 char *p = strrchr (key, '/');
969 if (p != NULL((void*)0))
970 return p+1;
971 else
972 return key;
973}
974
975static const char *
976lookup (const MateDesktopItem *item, const char *key)
977{
978 return g_hash_table_lookup (item->main_hash, key);
979}
980
981static const char *
982lookup_locale (const MateDesktopItem *item, const char *key, const char *locale)
983{
984 if (locale == NULL((void*)0) ||
985 strcmp (locale, "C") == 0) {
986 return lookup (item, key);
987 } else {
988 const char *ret;
989 char *full = g_strdup_printf ("%s[%s]", key, locale);
990 ret = lookup (item, full);
991 g_free (full);
992 return ret;
993 }
994}
995
996static const char *
997lookup_best_locale (const MateDesktopItem *item, const char *key)
998{
999 const char * const *langs_pointer;
1000 int i;
1001
1002 langs_pointer = g_get_language_names ();
1003 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
1004 const char *ret = NULL((void*)0);
1005
1006 ret = lookup_locale (item, key, langs_pointer[i]);
1007 if (ret != NULL((void*)0))
1008 return ret;
1009 }
1010
1011 return NULL((void*)0);
1012}
1013
1014static void
1015set (MateDesktopItem *item, const char *key, const char *value)
1016{
1017 Section *sec = section_from_key (item, key);
1018
1019 if (sec != NULL((void*)0)) {
1020 if (value != NULL((void*)0)) {
1021 if (g_hash_table_lookup (item->main_hash, key) == NULL((void*)0))
1022 sec->keys = g_list_append
1023 (sec->keys,
1024 g_strdup (key_basename (key))g_strdup_inline (key_basename (key)));
1025
1026 g_hash_table_replace (item->main_hash,
1027 g_strdup (key)g_strdup_inline (key),
1028 g_strdup (value)g_strdup_inline (value));
1029 } else {
1030 GList *list = g_list_find_custom
1031 (sec->keys, key_basename (key),
1032 (GCompareFunc)strcmp);
1033 if (list != NULL((void*)0)) {
1034 g_free (list->data);
1035 sec->keys =
1036 g_list_delete_link (sec->keys, list);
1037 }
1038 g_hash_table_remove (item->main_hash, key);
1039 }
1040 } else {
1041 if (value != NULL((void*)0)) {
1042 if (g_hash_table_lookup (item->main_hash, key) == NULL((void*)0))
1043 item->keys = g_list_append (item->keys,
1044 g_strdup (key)g_strdup_inline (key));
1045
1046 g_hash_table_replace (item->main_hash,
1047 g_strdup (key)g_strdup_inline (key),
1048 g_strdup (value)g_strdup_inline (value));
1049 } else {
1050 GList *list = g_list_find_custom
1051 (item->keys, key, (GCompareFunc)strcmp);
1052 if (list != NULL((void*)0)) {
1053 g_free (list->data);
1054 item->keys =
1055 g_list_delete_link (item->keys, list);
1056 }
1057 g_hash_table_remove (item->main_hash, key);
1058 }
1059 }
1060 item->modified = TRUE(!(0));
1061}
1062
1063static void
1064set_locale (MateDesktopItem *item, const char *key,
1065 const char *locale, const char *value)
1066{
1067 if (locale == NULL((void*)0) ||
1068 strcmp (locale, "C") == 0) {
1069 set (item, key, value);
1070 } else {
1071 char *full = g_strdup_printf ("%s[%s]", key, locale);
1072 set (item, full, value);
1073 g_free (full);
1074
1075 /* add the locale to the list of languages if it wasn't there
1076 * before */
1077 if (g_list_find_custom (item->languages, locale,
1078 (GCompareFunc)strcmp) == NULL((void*)0))
1079 item->languages = g_list_prepend (item->languages,
1080 g_strdup (locale)g_strdup_inline (locale));
1081 }
1082}
1083
1084static char **
1085list_to_vector (GSList *list)
1086{
1087 int len = g_slist_length (list);
1088 char **argv;
1089 int i;
1090 GSList *li;
1091
1092 argv = g_new0 (char *, len+1)((char * *) g_malloc0_n ((len+1), sizeof (char *)));
1093
1094 for (i = 0, li = list;
1095 li != NULL((void*)0);
1096 li = li->next, i++) {
1097 argv[i] = g_strdup (li->data)g_strdup_inline (li->data);
1098 }
1099 argv[i] = NULL((void*)0);
1100
1101 return argv;
1102}
1103
1104static GSList *
1105make_args (GList *files)
1106{
1107 GSList *list = NULL((void*)0);
1108 GList *li;
1109
1110 for (li = files; li != NULL((void*)0); li = li->next) {
1111 GFile *gfile;
1112 const char *file = li->data;
1113 if (file == NULL((void*)0))
1114 continue;
1115 gfile = g_file_new_for_uri (file);
1116 list = g_slist_prepend (list, gfile);
1117 }
1118
1119 return g_slist_reverse (list);
1120}
1121
1122static void
1123free_args (GSList *list)
1124{
1125 GSList *li;
1126
1127 for (li = list; li != NULL((void*)0); li = li->next) {
1128 g_object_unref (G_FILE (li->data)((((GFile*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((li->data)), ((g_file_get_type ()))))))
);
1129 li->data = NULL((void*)0);
1130 }
1131 g_slist_free (list);
1132}
1133
1134static char *
1135escape_single_quotes (const char *s,
1136 gboolean in_single_quotes,
1137 gboolean in_double_quotes)
1138{
1139 const char *p;
1140 GString *gs;
1141 const char *pre = "";
1142 const char *post = "";
1143
1144 if ( ! in_single_quotes && ! in_double_quotes) {
1145 pre = "'";
1146 post = "'";
1147 } else if ( ! in_single_quotes && in_double_quotes) {
1148 pre = "\"'";
1149 post = "'\"";
1150 }
1151
1152 if (strchr (s, '\'') == NULL((void*)0)) {
1153 return g_strconcat (pre, s, post, NULL((void*)0));
1154 }
1155
1156 gs = g_string_new (pre);
1157
1158 for (p = s; *p != '\0'; p++) {
1159 if (*p == '\'')
1160 g_string_append (gs, "'\\''")(__builtin_constant_p ("'\\''") ? __extension__ ({ const char
* const __val = ("'\\''"); g_string_append_len_inline (gs, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (gs, "'\\''"
, (gssize) -1))
;
1161 else
1162 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1163 }
1164
1165 g_string_append (gs, post)(__builtin_constant_p (post) ? __extension__ ({ const char * const
__val = (post); g_string_append_len_inline (gs, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (gs, post, (gssize) -1
))
;
1166
1167 return g_string_free (gs, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((gs),
((0))) : g_string_free_and_steal (gs)) : (g_string_free) ((gs
), ((0))))
;
1168}
1169
1170typedef enum {
1171 URI_TO_STRING,
1172 URI_TO_LOCAL_PATH,
1173 URI_TO_LOCAL_DIRNAME,
1174 URI_TO_LOCAL_BASENAME
1175} ConversionType;
1176
1177static char *
1178convert_uri (GFile *file,
1179 ConversionType conversion)
1180{
1181 char *retval = NULL((void*)0);
1182
1183 switch (conversion) {
1184 case URI_TO_STRING:
1185 retval = g_file_get_uri (file);
1186 break;
1187 case URI_TO_LOCAL_PATH:
1188 retval = g_file_get_path (file);
1189 break;
1190 case URI_TO_LOCAL_DIRNAME:
1191 {
1192 char *local_path;
1193
1194 local_path = g_file_get_path (file);
1195 retval = g_path_get_dirname (local_path);
1196 g_free (local_path);
1197 }
1198 break;
1199 case URI_TO_LOCAL_BASENAME:
1200 retval = g_file_get_basename (file);
1201 break;
1202 default:
1203 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-desktop-item.c"
, 1203, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1204 }
1205
1206 return retval;
1207}
1208
1209typedef enum {
1210 ADDED_NONE = 0,
1211 ADDED_SINGLE,
1212 ADDED_ALL
1213} AddedStatus;
1214
1215static AddedStatus
1216append_all_converted (GString *str,
1217 ConversionType conversion,
1218 GSList *args,
1219 gboolean in_single_quotes,
1220 gboolean in_double_quotes,
1221 AddedStatus added_status)
1222{
1223 GSList *l;
1224
1225 for (l = args; l; l = l->next) {
1226 char *converted;
1227 char *escaped;
1228
1229 if (!(converted = convert_uri (l->data, conversion)))
1230 continue;
1231
1232 g_string_append (str, " ")(__builtin_constant_p (" ") ? __extension__ ({ const char * const
__val = (" "); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, " ", (gssize) -1
))
;
1233
1234 escaped = escape_single_quotes (converted,
1235 in_single_quotes,
1236 in_double_quotes);
1237 g_string_append (str, escaped)(__builtin_constant_p (escaped) ? __extension__ ({ const char
* const __val = (escaped); g_string_append_len_inline (str, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (str, escaped
, (gssize) -1))
;
1238
1239 g_free (escaped);
1240 g_free (converted);
1241 }
1242
1243 return ADDED_ALL;
1244}
1245
1246static AddedStatus
1247append_first_converted (GString *str,
1248 ConversionType conversion,
1249 GSList **arg_ptr,
1250 gboolean in_single_quotes,
1251 gboolean in_double_quotes,
1252 AddedStatus added_status)
1253{
1254 GSList *l;
1255 char *converted = NULL((void*)0);
1256 char *escaped;
1257
1258 for (l = *arg_ptr; l; l = l->next) {
1259 if ((converted = convert_uri (l->data, conversion)))
1260 break;
1261
1262 *arg_ptr = l->next;
1263 }
1264
1265 if (!converted)
1266 return added_status;
1267
1268 escaped = escape_single_quotes (converted, in_single_quotes, in_double_quotes);
1269 g_string_append (str, escaped)(__builtin_constant_p (escaped) ? __extension__ ({ const char
* const __val = (escaped); g_string_append_len_inline (str, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (str, escaped
, (gssize) -1))
;
1270 g_free (escaped);
1271 g_free (converted);
1272
1273 return added_status != ADDED_ALL ? ADDED_SINGLE : added_status;
1274}
1275
1276static gboolean
1277do_percent_subst (const MateDesktopItem *item,
1278 const char *arg,
1279 GString *str,
1280 gboolean in_single_quotes,
1281 gboolean in_double_quotes,
1282 GSList *args,
1283 GSList **arg_ptr,
1284 AddedStatus *added_status)
1285{
1286 char *esc;
1287 const char *cs;
1288
1289 if (arg[0] != '%' || arg[1] == '\0') {
1290 return FALSE(0);
1291 }
1292
1293 switch (arg[1]) {
1294 case '%':
1295 g_string_append_c (str, '%')g_string_append_c_inline (str, '%');
1296 break;
1297 case 'U':
1298 *added_status = append_all_converted (str,
1299 URI_TO_STRING,
1300 args,
1301 in_single_quotes,
1302 in_double_quotes,
1303 *added_status);
1304 break;
1305 case 'F':
1306 *added_status = append_all_converted (str,
1307 URI_TO_LOCAL_PATH,
1308 args,
1309 in_single_quotes,
1310 in_double_quotes,
1311 *added_status);
1312 break;
1313 case 'N':
1314 *added_status = append_all_converted (str,
1315 URI_TO_LOCAL_BASENAME,
1316 args,
1317 in_single_quotes,
1318 in_double_quotes,
1319 *added_status);
1320 break;
1321 case 'D':
1322 *added_status = append_all_converted (str,
1323 URI_TO_LOCAL_DIRNAME,
1324 args,
1325 in_single_quotes,
1326 in_double_quotes,
1327 *added_status);
1328 break;
1329 case 'f':
1330 *added_status = append_first_converted (str,
1331 URI_TO_LOCAL_PATH,
1332 arg_ptr,
1333 in_single_quotes,
1334 in_double_quotes,
1335 *added_status);
1336 break;
1337 case 'u':
1338 *added_status = append_first_converted (str,
1339 URI_TO_STRING,
1340 arg_ptr,
1341 in_single_quotes,
1342 in_double_quotes,
1343 *added_status);
1344 break;
1345 case 'd':
1346 *added_status = append_first_converted (str,
1347 URI_TO_LOCAL_DIRNAME,
1348 arg_ptr,
1349 in_single_quotes,
1350 in_double_quotes,
1351 *added_status);
1352 break;
1353 case 'n':
1354 *added_status = append_first_converted (str,
1355 URI_TO_LOCAL_BASENAME,
1356 arg_ptr,
1357 in_single_quotes,
1358 in_double_quotes,
1359 *added_status);
1360 break;
1361 case 'm':
1362 /* Note: v0.9.4 of the spec says this is deprecated
1363 * and replace with --miniicon iconname */
1364 cs = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_MINI_ICON"MiniIcon");
1365 if (cs != NULL((void*)0)) {
1366 g_string_append (str, "--miniicon=")(__builtin_constant_p ("--miniicon=") ? __extension__ ({ const
char * const __val = ("--miniicon="); g_string_append_len_inline
(str, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(str, "--miniicon=", (gssize) -1))
;
1367 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1368 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1369 }
1370 break;
1371 case 'i':
1372 /* Note: v0.9.4 of the spec says replace with --icon iconname */
1373 cs = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_ICON"Icon");
1374 if (cs != NULL((void*)0)) {
1375 g_string_append (str, "--icon=")(__builtin_constant_p ("--icon=") ? __extension__ ({ const char
* const __val = ("--icon="); g_string_append_len_inline (str
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (str
, "--icon=", (gssize) -1))
;
1376 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1377 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1378 }
1379 break;
1380 case 'c':
1381 cs = mate_desktop_item_get_localestring (item, MATE_DESKTOP_ITEM_NAME"Name");
1382 if (cs != NULL((void*)0)) {
1383 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1384 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1385 g_free (esc);
1386 }
1387 break;
1388 case 'k':
1389 if (item->location != NULL((void*)0)) {
1390 esc = escape_single_quotes (item->location, in_single_quotes, in_double_quotes);
1391 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1392 g_free (esc);
1393 }
1394 break;
1395 case 'v':
1396 cs = mate_desktop_item_get_localestring (item, MATE_DESKTOP_ITEM_DEV"Dev");
1397 if (cs != NULL((void*)0)) {
1398 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1399 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1400 g_free (esc);
1401 }
1402 break;
1403 default:
1404 /* Maintain special characters - e.g. "%20" */
1405 if (g_ascii_isdigit (arg [1])((g_ascii_table[(guchar) (arg [1])] & G_ASCII_DIGIT) != 0
)
)
1406 g_string_append_c (str, '%')g_string_append_c_inline (str, '%');
1407 return FALSE(0);
1408 }
1409
1410 return TRUE(!(0));
1411}
1412
1413static char *
1414expand_string (const MateDesktopItem *item,
1415 const char *s,
1416 GSList *args,
1417 GSList **arg_ptr,
1418 AddedStatus *added_status)
1419{
1420 const char *p;
1421 gboolean escape = FALSE(0);
1422 gboolean single_quot = FALSE(0);
1423 gboolean double_quot = FALSE(0);
1424 GString *gs = g_string_new (NULL((void*)0));
1425
1426 for (p = s; *p != '\0'; p++) {
1427 if (escape) {
1428 escape = FALSE(0);
1429 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1430 } else if (*p == '\\') {
1431 if ( ! single_quot)
1432 escape = TRUE(!(0));
1433 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1434 } else if (*p == '\'') {
1435 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1436 if ( ! single_quot && ! double_quot) {
1437 single_quot = TRUE(!(0));
1438 } else if (single_quot) {
1439 single_quot = FALSE(0);
1440 }
1441 } else if (*p == '"') {
1442 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1443 if ( ! single_quot && ! double_quot) {
1444 double_quot = TRUE(!(0));
1445 } else if (double_quot) {
1446 double_quot = FALSE(0);
1447 }
1448 } else if (*p == '%') {
1449 if (do_percent_subst (item, p, gs,
1450 single_quot, double_quot,
1451 args, arg_ptr,
1452 added_status)) {
1453 p++;
1454 }
1455 } else {
1456 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1457 }
1458 }
1459 return g_string_free (gs, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((gs),
((0))) : g_string_free_and_steal (gs)) : (g_string_free) ((gs
), ((0))))
;
1460}
1461
1462/*Functions in this code block should only ever be reached in x11*/
1463#ifdef HAVE_STARTUP_NOTIFICATION
1464static void
1465sn_error_trap_push (SnDisplay *display,
1466 Display *xdisplay)
1467{
1468 GdkDisplay *gdkdisplay;
1469
1470 gdkdisplay = gdk_display_get_default ();
1471 gdk_x11_display_error_trap_push (gdkdisplay);
1472}
1473
1474static void
1475sn_error_trap_pop (SnDisplay *display,
1476 Display *xdisplay)
1477{
1478 GdkDisplay *gdkdisplay;
1479
1480 gdkdisplay = gdk_display_get_default ();
1481 gdk_x11_display_error_trap_pop_ignored (gdkdisplay);
1482}
1483
1484static char **
1485make_spawn_environment_for_sn_context (SnLauncherContext *sn_context,
1486 char **envp)
1487{
1488 char **retval;
1489 char **freeme;
1490 int i, j;
1491 int desktop_startup_id_len;
1492
1493 retval = freeme = NULL((void*)0);
1494
1495 if (envp == NULL((void*)0)) {
1496 envp = freeme = g_listenv ();
1497 for (i = 0; envp[i]; i++) {
1498 char *name = envp[i];
1499
1500 envp[i] = g_strjoin ("=", name, g_getenv (name), NULL((void*)0));
1501 g_free (name);
1502 }
1503 } else {
1504 for (i = 0; envp[i]; i++)
1505 ;
1506 }
1507
1508 retval = g_new (char *, i + 2)((char * *) g_malloc_n ((i + 2), sizeof (char *)));
1509
1510 desktop_startup_id_len = strlen ("DESKTOP_STARTUP_ID");
1511
1512 for (i = 0, j = 0; envp[i]; i++) {
1513 if (strncmp (envp[i], "DESKTOP_STARTUP_ID", desktop_startup_id_len) != 0) {
1514 retval[j] = g_strdup (envp[i])g_strdup_inline (envp[i]);
1515 ++j;
1516 }
1517 }
1518
1519 retval[j] = g_strdup_printf ("DESKTOP_STARTUP_ID=%s",
1520 sn_launcher_context_get_startup_id (sn_context));
1521 ++j;
1522 retval[j] = NULL((void*)0);
1523
1524 g_strfreev (freeme);
1525
1526 return retval;
1527}
1528
1529/* This should be fairly long, as it's confusing to users if a startup
1530 * ends when it shouldn't (it appears that the startup failed, and
1531 * they have to relaunch the app). Also the timeout only matters when
1532 * there are bugs and apps don't end their own startup sequence.
1533 *
1534 * This timeout is a "last resort" timeout that ignores whether the
1535 * startup sequence has shown activity or not. Marco and the
1536 * tasklist have smarter, and correspondingly able-to-be-shorter
1537 * timeouts. The reason our timeout is dumb is that we don't monitor
1538 * the sequence (don't use an SnMonitorContext)
1539 */
1540#define STARTUP_TIMEOUT_LENGTH_SEC30 30 /* seconds */
1541#define STARTUP_TIMEOUT_LENGTH(30 * 1000) (STARTUP_TIMEOUT_LENGTH_SEC30 * 1000)
1542
1543typedef struct
1544{
1545 GdkScreen *screen;
1546 GSList *contexts;
1547 guint timeout_id;
1548} StartupTimeoutData;
1549
1550static void
1551free_startup_timeout (void *data)
1552{
1553 StartupTimeoutData *std = data;
1554
1555 g_slist_free_full (std->contexts, (GDestroyNotify) sn_launcher_context_unref);
1556
1557 if (std->timeout_id != 0) {
1558 g_source_remove (std->timeout_id);
1559 std->timeout_id = 0;
1560 }
1561
1562 g_free (std);
1563}
1564
1565static gboolean
1566startup_timeout (void *data)
1567{
1568 StartupTimeoutData *std = data;
1569 GSList *tmp;
1570 int min_timeout;
1571
1572 min_timeout = STARTUP_TIMEOUT_LENGTH(30 * 1000);
1573
1574#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1575 gint64 now = g_get_real_time ();
1576#else
1577 GTimeVal now;
1578 g_get_current_time (&now);
1579#endif
1580
1581 tmp = std->contexts;
1582 while (tmp != NULL((void*)0)) {
1583 SnLauncherContext *sn_context = tmp->data;
1584 GSList *next = tmp->next;
1585 double elapsed;
1586
1587#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1588 time_t tv_sec;
1589 suseconds_t tv_usec;
1590 gint64 tv;
1591
1592 sn_launcher_context_get_last_active_time (sn_context, &tv_sec, &tv_usec);
1593 tv = (tv_sec * G_USEC_PER_SEC1000000) + tv_usec;
1594 elapsed = (double) (now - tv) / 1000.0;
1595#else
1596 long tv_sec, tv_usec;
1597
1598 sn_launcher_context_get_last_active_time (sn_context,
1599 &tv_sec, &tv_usec);
1600
1601 elapsed =
1602 ((((double)now.tv_sec - tv_sec) * G_USEC_PER_SEC1000000 +
1603 (now.tv_usec - tv_usec))) / 1000.0;
1604#endif
1605
1606 if (elapsed >= STARTUP_TIMEOUT_LENGTH(30 * 1000)) {
1607 std->contexts = g_slist_remove (std->contexts,
1608 sn_context);
1609 sn_launcher_context_complete (sn_context);
1610 sn_launcher_context_unref (sn_context);
1611 } else {
1612 min_timeout = MIN (min_timeout, (STARTUP_TIMEOUT_LENGTH - elapsed))(((min_timeout) < (((30 * 1000) - elapsed))) ? (min_timeout
) : (((30 * 1000) - elapsed)))
;
1613 }
1614
1615 tmp = next;
1616 }
1617
1618 /* we'll use seconds for the timeout */
1619 if (min_timeout < 1000)
1620 min_timeout = 1000;
1621
1622 if (std->contexts == NULL((void*)0)) {
1623 std->timeout_id = 0;
1624 } else {
1625 std->timeout_id = g_timeout_add_seconds (min_timeout / 1000,
1626 startup_timeout,
1627 std);
1628 }
1629
1630 /* always remove this one, but we may have reinstalled another one. */
1631 return FALSE(0);
1632}
1633
1634static void
1635add_startup_timeout (GdkScreen *screen,
1636 SnLauncherContext *sn_context)
1637{
1638 StartupTimeoutData *data;
1639
1640 data = g_object_get_data (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "mate-startup-data");
1641 if (data == NULL((void*)0)) {
1642 data = g_new (StartupTimeoutData, 1)((StartupTimeoutData *) g_malloc_n ((1), sizeof (StartupTimeoutData
)))
;
1643 data->screen = screen;
1644 data->contexts = NULL((void*)0);
1645 data->timeout_id = 0;
1646
1647 g_object_set_data_full (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "mate-startup-data",
1648 data, free_startup_timeout);
1649 }
1650
1651 sn_launcher_context_ref (sn_context);
1652 data->contexts = g_slist_prepend (data->contexts, sn_context);
1653
1654 if (data->timeout_id == 0) {
1655 data->timeout_id = g_timeout_add_seconds (
1656 STARTUP_TIMEOUT_LENGTH_SEC30,
1657 startup_timeout,
1658 data);
1659 }
1660}
1661#endif /* HAVE_STARTUP_NOTIFICATION - functions should only be reached in x11*/
1662
1663static inline char *
1664stringify_uris (GSList *args)
1665{
1666 GString *str;
1667
1668 str = g_string_new (NULL((void*)0));
1669
1670 append_all_converted (str, URI_TO_STRING, args, FALSE(0), FALSE(0), ADDED_NONE);
1671
1672 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1673}
1674
1675static inline char *
1676stringify_files (GSList *args)
1677{
1678 GString *str;
1679
1680 str = g_string_new (NULL((void*)0));
1681
1682 append_all_converted (str, URI_TO_LOCAL_PATH, args, FALSE(0), FALSE(0), ADDED_NONE);
1683
1684 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1685}
1686
1687static char **
1688make_environment_for_screen (GdkScreen *screen,
1689 char **envp)
1690{
1691 GdkDisplay *display;
1692 char **retval;
1693 char **freeme;
1694 char *display_name;
1695 int display_index = -1;
1696 int i, env_len;
1697
1698 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((screen)); GType __t = ((gdk_screen_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "GDK_IS_SCREEN (screen)"); return (((void*)0)
); } } while (0)
;
1699
1700 retval = freeme = NULL((void*)0);
1701
1702 if (envp == NULL((void*)0)) {
1703 envp = freeme = g_listenv ();
1704 for (i = 0; envp [i]; i++) {
1705 char *name = envp[i];
1706
1707 envp[i] = g_strjoin ("=", name, g_getenv (name), NULL((void*)0));
1708 g_free (name);
1709 }
1710 }
1711
1712 for (env_len = 0; envp [env_len]; env_len++)
1713 if (strncmp (envp [env_len], "DISPLAY", strlen ("DISPLAY")) == 0)
1714 display_index = env_len;
1715
1716 retval = g_new (char *, env_len + 1)((char * *) g_malloc_n ((env_len + 1), sizeof (char *)));
1717 retval [env_len] = NULL((void*)0);
1718
1719 display = gdk_screen_get_display (screen);
1720 display_name = g_strdup (gdk_display_get_name (display))g_strdup_inline (gdk_display_get_name (display));
1721
1722 for (i = 0; i < env_len; i++)
1723 if (i == display_index)
1724 retval [i] = g_strconcat ("DISPLAY=", display_name, NULL((void*)0));
1725 else
1726 retval [i] = g_strdup (envp[i])g_strdup_inline (envp[i]);
1727
1728 g_assert (i == env_len)do { if (i == env_len) ; else g_assertion_message_expr ("MateDesktop"
, "mate-desktop-item.c", 1728, ((const char*) (__func__)), "i == env_len"
); } while (0)
;
1729
1730 g_free (display_name);
1731 g_strfreev (freeme);
1732
1733 return retval;
1734}
1735
1736static void
1737dummy_child_watch (GPid pid,
1738 gint status,
1739 gpointer user_data)
1740{
1741 /* Nothing, this is just to ensure we don't double fork
1742 * and break pkexec:
1743 * https://bugzilla.gnome.org/show_bug.cgi?id=675789
1744 */
1745}
1746
1747static int
1748ditem_execute (const MateDesktopItem *item,
1749 const char *exec,
1750 GList *file_list,
1751 GdkScreen *screen,
1752 int workspace,
1753 char **envp,
1754 gboolean launch_only_one,
1755 gboolean use_current_dir,
1756 gboolean append_uris,
1757 gboolean append_paths,
1758 gboolean do_not_reap_child,
1759 GError **error)
1760{
1761 char **free_me = NULL((void*)0);
1762 char **real_argv;
1763 int i, ret;
1764 char **term_argv = NULL((void*)0);
1765 int term_argc = 0;
1766 GSList *vector_list;
1767 GSList *args, *arg_ptr;
1768 AddedStatus added_status;
1769 const char *working_dir = NULL((void*)0);
1770 char **temp_argv = NULL((void*)0);
1771 int temp_argc = 0;
1772 char *new_exec, *uris, *temp;
1773 char *exec_locale;
1774 int launched = 0;
1775 GPid pid;
1776#ifdef HAVE_STARTUP_NOTIFICATION
1777 GdkDisplay *gdkdisplay;
1778 SnLauncherContext *sn_context;
1779 SnDisplay *sn_display;
1780 const char *startup_class;
1781#endif
1782
1783 g_return_val_if_fail (item, -1)do { if ((item)) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "item"); return (-1); } } while
(0)
;
1784
1785 if (item->type == MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
1786 working_dir = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_PATH"Path");
1787 if (working_dir &&
1788 !g_file_test (working_dir, G_FILE_TEST_IS_DIR))
1789 working_dir = NULL((void*)0);
1790 }
1791
1792 if (working_dir == NULL((void*)0) && !use_current_dir)
1793 working_dir = g_get_home_dir ();
1794
1795 if (mate_desktop_item_get_boolean (item, MATE_DESKTOP_ITEM_TERMINAL"Terminal")) {
1796 const char *options =
1797 mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_TERMINAL_OPTIONS"TerminalOptions");
1798
1799 if (options != NULL((void*)0)) {
1800 g_shell_parse_argv (options,
1801 &term_argc,
1802 &term_argv,
1803 NULL((void*)0) /* error */);
1804 /* ignore errors */
1805 }
1806
1807 mate_desktop_prepend_terminal_to_vector (&term_argc, &term_argv);
1808 }
1809
1810 args = make_args (file_list);
1811 arg_ptr = make_args (file_list);
1812
1813#ifdef HAVE_STARTUP_NOTIFICATION
1814 GdkDisplay *display = gdk_screen_get_display (gdk_screen_get_default());
1815 if (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1816 {
1817 if (screen)
1818 gdkdisplay = gdk_screen_get_display (screen);
1819 else
1820 gdkdisplay = gdk_display_get_default ();
1821
1822 sn_display = sn_display_new (GDK_DISPLAY_XDISPLAY (gdkdisplay)(gdk_x11_display_get_xdisplay (gdkdisplay)),
1823 sn_error_trap_push,
1824 sn_error_trap_pop);
1825
1826 /* Only initiate notification if desktop file supports it.
1827 * (we could avoid setting up the SnLauncherContext if we aren't going
1828 * to initiate, but why bother)
1829 */
1830
1831 startup_class = mate_desktop_item_get_string (item,
1832 "StartupWMClass");
1833 if (startup_class ||
1834 mate_desktop_item_get_boolean (item, "StartupNotify")) {
1835 const char *name;
1836 const char *icon;
1837
1838 sn_context = sn_launcher_context_new (sn_display,
1839 screen ? gdk_x11_screen_get_screen_number (screen) :
1840 DefaultScreen (GDK_DISPLAY_XDISPLAY (gdkdisplay))(((_XPrivDisplay)((gdk_x11_display_get_xdisplay (gdkdisplay))
))->default_screen)
);
1841
1842 name = mate_desktop_item_get_localestring (item,
1843 MATE_DESKTOP_ITEM_NAME"Name");
1844
1845 if (name == NULL((void*)0))
1846 name = mate_desktop_item_get_localestring (item,
1847 MATE_DESKTOP_ITEM_GENERIC_NAME"GenericName");
1848
1849 if (name != NULL((void*)0)) {
1850 char *description;
1851
1852 sn_launcher_context_set_name (sn_context, name);
1853
1854 description = g_strdup_printf (_("Starting %s")((char *) g_dgettext ("mate-desktop", "Starting %s")), name);
1855
1856 sn_launcher_context_set_description (sn_context, description);
1857
1858 g_free (description);
1859 }
1860
1861 icon = mate_desktop_item_get_string (item,
1862 MATE_DESKTOP_ITEM_ICON"Icon");
1863
1864 if (icon != NULL((void*)0))
1865 sn_launcher_context_set_icon_name (sn_context, icon);
1866
1867 sn_launcher_context_set_workspace (sn_context, workspace);
1868
1869 if (startup_class != NULL((void*)0))
1870 sn_launcher_context_set_wmclass (sn_context,
1871 startup_class);
1872 } else {
1873 sn_context = NULL((void*)0);
1874 }
1875 }
1876 else {
1877 sn_context = NULL((void*)0);
1878 sn_display = NULL((void*)0);
1879 }
1880#endif
1881
1882 if (screen) {
1883 envp = make_environment_for_screen (screen, envp);
1884 if (free_me)
1885 g_strfreev (free_me);
1886 free_me = envp;
1887 }
1888
1889 exec_locale = g_filename_from_utf8 (exec, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
1890
1891 if (exec_locale == NULL((void*)0)) {
1892 exec_locale = g_strdup ("")g_strdup_inline ("");
1893 }
1894
1895 do {
1896 added_status = ADDED_NONE;
1897 new_exec = expand_string (item,
1898 exec_locale,
1899 args, &arg_ptr, &added_status);
1900
1901 if (launched == 0 && added_status == ADDED_NONE && append_uris) {
1902 uris = stringify_uris (args);
1903 temp = g_strconcat (new_exec, " ", uris, NULL((void*)0));
1904 g_free (uris);
1905 g_free (new_exec);
1906 new_exec = temp;
1907 added_status = ADDED_ALL;
1908 }
1909
1910 /* append_uris and append_paths are mutually exlusive */
1911 if (launched == 0 && added_status == ADDED_NONE && append_paths) {
1912 uris = stringify_files (args);
1913 temp = g_strconcat (new_exec, " ", uris, NULL((void*)0));
1914 g_free (uris);
1915 g_free (new_exec);
1916 new_exec = temp;
1917 added_status = ADDED_ALL;
1918 }
1919
1920 if (launched > 0 && added_status == ADDED_NONE) {
1921 g_free (new_exec);
1922 break;
1923 }
1924
1925 if ( ! g_shell_parse_argv (new_exec,
1926 &temp_argc, &temp_argv, error)) {
1927 /* The error now comes from g_shell_parse_argv */
1928 g_free (new_exec);
1929 ret = -1;
1930 break;
1931 }
1932 g_free (new_exec);
1933
1934 vector_list = NULL((void*)0);
1935 for(i = 0; i < term_argc; i++)
1936 vector_list = g_slist_append (vector_list,
1937 g_strdup (term_argv[i])g_strdup_inline (term_argv[i]));
1938
1939 for(i = 0; i < temp_argc; i++)
1940 vector_list = g_slist_append (vector_list,
1941 g_strdup (temp_argv[i])g_strdup_inline (temp_argv[i]));
1942
1943 g_strfreev (temp_argv);
1944
1945 real_argv = list_to_vector (vector_list);
1946 g_slist_free_full (vector_list, g_free);
1947
1948#ifdef HAVE_STARTUP_NOTIFICATION
1949 if (sn_context != NULL((void*)0) && (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) &&
1950 !sn_launcher_context_get_initiated (sn_context)) {
1951 guint32 launch_time;
1952
1953 /* This means that we always use the first real_argv[0]
1954 * we select for the "binary name", but it's probably
1955 * OK to do that. Binary name isn't super-important
1956 * anyway, and we can't initiate twice, and we
1957 * must initiate prior to fork/exec.
1958 */
1959
1960 sn_launcher_context_set_binary_name (sn_context,
1961 real_argv[0]);
1962
1963 if (item->launch_time > 0)
1964 launch_time = item->launch_time;
1965 else
1966 launch_time = gdk_x11_display_get_user_time (gdkdisplay);
1967
1968 sn_launcher_context_initiate (sn_context,
1969 g_get_prgname () ? g_get_prgname () : "unknown",
1970 real_argv[0],
1971 launch_time);
1972
1973 /* Don't allow accidental reuse of same timestamp */
1974 ((MateDesktopItem *)item)->launch_time = 0;
1975
1976 envp = make_spawn_environment_for_sn_context (sn_context, envp);
1977 if (free_me)
1978 g_strfreev (free_me);
1979 free_me = envp;
1980 }
1981#endif
1982
1983 if ( ! g_spawn_async (working_dir,
1984 real_argv,
1985 envp,
1986 (do_not_reap_child ? G_SPAWN_DO_NOT_REAP_CHILD : 0) | G_SPAWN_SEARCH_PATH /* flags */,
1987 NULL((void*)0), /* child_setup_func */
1988 NULL((void*)0), /* child_setup_func_data */
1989 (do_not_reap_child ? &pid : NULL((void*)0)) /* child_pid */,
1990 error)) {
1991 /* The error was set for us,
1992 * we just can't launch this thingie */
1993 ret = -1;
1994 g_strfreev (real_argv);
1995 break;
1996 } else if (do_not_reap_child) {
1997 g_child_watch_add (pid, dummy_child_watch, NULL((void*)0));
1998 }
1999
2000 launched ++;
2001
2002 g_strfreev (real_argv);
2003
2004 if (arg_ptr != NULL((void*)0))
2005 arg_ptr = arg_ptr->next;
2006
2007 /* rinse, repeat until we run out of arguments (That
2008 * is if we were adding singles anyway) */
2009 } while (added_status == ADDED_SINGLE &&
2010 arg_ptr != NULL((void*)0) &&
2011 ! launch_only_one);
2012
2013 g_free (exec_locale);
2014#ifdef HAVE_STARTUP_NOTIFICATION
2015 if ((sn_context != NULL((void*)0)) && (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)){
2016 if (ret < 0)
2017 sn_launcher_context_complete (sn_context); /* end sequence */
2018 else
2019 add_startup_timeout (screen ? screen :
2020 gdk_display_get_default_screen (gdk_display_get_default ()),
2021 sn_context);
2022 sn_launcher_context_unref (sn_context);
2023 }
2024 if (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2025 sn_display_unref (sn_display);
2026
2027#endif /* HAVE_STARTUP_NOTIFICATION */
2028
2029 free_args (args);
2030
2031 if (term_argv)
2032 g_strfreev (term_argv);
2033
2034 if (free_me)
2035 g_strfreev (free_me);
2036
2037 return ret;
2038}
2039
2040/* strip any trailing &, return FALSE if bad things happen and
2041 we end up with an empty string */
2042static gboolean
2043strip_the_amp (char *exec)
2044{
2045 size_t exec_len;
2046
2047 g_strstrip (exec)g_strchomp (g_strchug (exec));
2048 if (*exec == '\0')
2049 return FALSE(0);
2050
2051 exec_len = strlen (exec);
2052 /* kill any trailing '&' */
2053 if (exec[exec_len-1] == '&') {
2054 exec[exec_len-1] = '\0';
2055 g_strchomp (exec);
2056 }
2057
2058 /* can't exactly launch an empty thing */
2059 if (*exec == '\0')
2060 return FALSE(0);
2061
2062 return TRUE(!(0));
2063}
2064
2065static int
2066mate_desktop_item_launch_on_screen_with_env (
2067 const MateDesktopItem *item,
2068 GList *file_list,
2069 MateDesktopItemLaunchFlags flags,
2070 GdkScreen *screen,
2071 int workspace,
2072 char **envp,
2073 GError **error)
2074{
2075 const char *exec;
2076 char *the_exec;
2077 int ret;
2078
2079 exec = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_EXEC"Exec");
2080 /* This is a URL, so launch it as a url */
2081 if (item->type == MATE_DESKTOP_ITEM_TYPE_LINK) {
2082 const char *url;
2083 gboolean retval;
2084
2085 url = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_URL"URL");
2086 /* Mate panel used to put this in Exec */
2087 if (!(url && url[0] != '\0'))
2088 url = exec;
2089
2090 if (!(url && url[0] != '\0')) {
2091 g_set_error (error,
2092 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2093 MATE_DESKTOP_ITEM_ERROR_NO_URL,
2094 _("No URL to launch")((char *) g_dgettext ("mate-desktop", "No URL to launch")));
2095 return -1;
2096 }
2097
2098 retval = gtk_show_uri_on_window (NULL((void*)0),
2099 url,
2100 GDK_CURRENT_TIME0L,
2101 error);
2102 return retval ? 0 : -1;
2103 }
2104
2105 /* check the type, if there is one set */
2106 if (item->type != MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
2107 g_set_error (error,
2108 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2109 MATE_DESKTOP_ITEM_ERROR_NOT_LAUNCHABLE,
2110 _("Not a launchable item")((char *) g_dgettext ("mate-desktop", "Not a launchable item"
))
);
2111 return -1;
2112 }
2113
2114 if (exec == NULL((void*)0) ||
2115 exec[0] == '\0') {
2116 g_set_error (error,
2117 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2118 MATE_DESKTOP_ITEM_ERROR_NO_EXEC_STRING,
2119 _("No command (Exec) to launch")((char *) g_dgettext ("mate-desktop", "No command (Exec) to launch"
))
);
2120 return -1;
2121 }
2122
2123 /* make a new copy and get rid of spaces */
2124 the_exec = g_alloca (strlen (exec) + 1)__builtin_alloca (strlen (exec) + 1);
2125 g_strlcpy (the_exec, exec, strlen (exec) + 1);
2126
2127 if ( ! strip_the_amp (the_exec)) {
2128 g_set_error (error,
2129 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2130 MATE_DESKTOP_ITEM_ERROR_BAD_EXEC_STRING,
2131 _("Bad command (Exec) to launch")((char *) g_dgettext ("mate-desktop", "Bad command (Exec) to launch"
))
);
2132 return -1;
2133 }
2134
2135 ret = ditem_execute (item, the_exec, file_list, screen, workspace, envp,
2136 (flags & MATE_DESKTOP_ITEM_LAUNCH_ONLY_ONE),
2137 (flags & MATE_DESKTOP_ITEM_LAUNCH_USE_CURRENT_DIR),
2138 (flags & MATE_DESKTOP_ITEM_LAUNCH_APPEND_URIS),
2139 (flags & MATE_DESKTOP_ITEM_LAUNCH_APPEND_PATHS),
2140 (flags & MATE_DESKTOP_ITEM_LAUNCH_DO_NOT_REAP_CHILD),
2141 error);
2142
2143 return ret;
2144}
2145
2146/**
2147 * mate_desktop_item_launch:
2148 * @item: A desktop item
2149 * @file_list: Files/URIs to launch this item with, can be %NULL
2150 * @flags: FIXME
2151 * @error: FIXME
2152 *
2153 * This function runs the program listed in the specified 'item',
2154 * optionally appending additional arguments to its command line. It uses
2155 * #g_shell_parse_argv to parse the the exec string into a vector which is
2156 * then passed to #g_spawn_async for execution. This can return all
2157 * the errors from MateURL, #g_shell_parse_argv and #g_spawn_async,
2158 * in addition to it's own. The files are
2159 * only added if the entry defines one of the standard % strings in it's
2160 * Exec field.
2161 *
2162 * Returns: The the pid of the process spawned. If more then one
2163 * process was spawned the last pid is returned. On error -1
2164 * is returned and @error is set.
2165 */
2166int
2167mate_desktop_item_launch (const MateDesktopItem *item,
2168 GList *file_list,
2169 MateDesktopItemLaunchFlags flags,
2170 GError **error)
2171{
2172 return mate_desktop_item_launch_on_screen_with_env (
2173 item, file_list, flags, NULL((void*)0), -1, NULL((void*)0), error);
2174}
2175
2176/**
2177 * mate_desktop_item_launch_with_env:
2178 * @item: A desktop item
2179 * @file_list: Files/URIs to launch this item with, can be %NULL
2180 * @flags: FIXME
2181 * @envp: child's environment, or %NULL to inherit parent's
2182 * @error: FIXME
2183 *
2184 * See mate_desktop_item_launch for a full description. This function
2185 * additionally passes an environment vector for the child process
2186 * which is to be launched.
2187 *
2188 * Returns: The the pid of the process spawned. If more then one
2189 * process was spawned the last pid is returned. On error -1
2190 * is returned and @error is set.
2191 */
2192int
2193mate_desktop_item_launch_with_env (const MateDesktopItem *item,
2194 GList *file_list,
2195 MateDesktopItemLaunchFlags flags,
2196 char **envp,
2197 GError **error)
2198{
2199 return mate_desktop_item_launch_on_screen_with_env (
2200 item, file_list, flags,
2201 NULL((void*)0), -1, envp, error);
2202}
2203
2204/**
2205 * mate_desktop_item_launch_on_screen:
2206 * @item: A desktop item
2207 * @file_list: Files/URIs to launch this item with, can be %NULL
2208 * @flags: FIXME
2209 * @screen: the %GdkScreen on which the application should be launched
2210 * @workspace: the workspace on which the app should be launched (-1 for current)
2211 * @error: FIXME
2212 *
2213 * See mate_desktop_item_launch for a full description. This function
2214 * additionally attempts to launch the application on a given screen
2215 * and workspace.
2216 *
2217 * Returns: The the pid of the process spawned. If more then one
2218 * process was spawned the last pid is returned. On error -1
2219 * is returned and @error is set.
2220 */
2221int
2222mate_desktop_item_launch_on_screen (const MateDesktopItem *item,
2223 GList *file_list,
2224 MateDesktopItemLaunchFlags flags,
2225 GdkScreen *screen,
2226 int workspace,
2227 GError **error)
2228{
2229 return mate_desktop_item_launch_on_screen_with_env (
2230 item, file_list, flags,
2231 screen, workspace, NULL((void*)0), error);
2232}
2233
2234/**
2235 * mate_desktop_item_drop_uri_list:
2236 * @item: A desktop item
2237 * @uri_list: text as gotten from a text/uri-list
2238 * @flags: FIXME
2239 * @error: FIXME
2240 *
2241 * A list of files or urls dropped onto an icon, the proper (Url or File)
2242 * exec is run you can pass directly string that you got as the
2243 * text/uri-list. This just parses the list and calls
2244 *
2245 * Returns: The value returned by #mate_execute_async() upon execution of
2246 * the specified item or -1 on error. If multiple instances are run, the
2247 * return of the last one is returned.
2248 */
2249int
2250mate_desktop_item_drop_uri_list (const MateDesktopItem *item,
2251 const char *uri_list,
2252 MateDesktopItemLaunchFlags flags,
2253 GError **error)
2254{
2255 return mate_desktop_item_drop_uri_list_with_env (item, uri_list,
2256 flags, NULL((void*)0), error);
2257}
2258
2259/**
2260* mate_desktop_item_drop_uri_list_with_env:
2261* @item: A desktop item
2262* @uri_list: text as gotten from a text/uri-list
2263* @flags: FIXME
2264* @envp: child's environment
2265* @error: FIXME
2266*
2267* See mate_desktop_item_drop_uri_list for a full description. This function
2268* additionally passes an environment vector for the child process
2269* which is to be launched.
2270*
2271* Returns: The value returned by #mate_execute_async() upon execution of
2272* the specified item or -1 on error. If multiple instances are run, the
2273* return of the last one is returned.
2274*/
2275int
2276mate_desktop_item_drop_uri_list_with_env (const MateDesktopItem *item,
2277 const char *uri_list,
2278 MateDesktopItemLaunchFlags flags,
2279 char **envp,
2280 GError **error)
2281{
2282 int ret;
2283 char *uri;
2284 char **uris;
2285 GList *list = NULL((void*)0);
2286
2287 uris = g_uri_list_extract_uris (uri_list);
2288
2289 for (uri = uris[0]; uri != NULL((void*)0); uri++) {
2290 list = g_list_prepend (list, uri);
2291 }
2292 list = g_list_reverse (list);
2293
2294 ret = mate_desktop_item_launch_with_env (
2295 item, list, flags, envp, error);
2296
2297 g_strfreev (uris);
2298 g_list_free (list);
2299
2300 return ret;
2301}
2302
2303static gboolean
2304exec_exists (const char *exec)
2305{
2306 if (g_path_is_absolute (exec)) {
2307 if (access (exec, X_OK1) == 0)
2308 return TRUE(!(0));
2309 else
2310 return FALSE(0);
2311 } else {
2312 char *tryme;
2313
2314 tryme = g_find_program_in_path (exec);
2315 if (tryme != NULL((void*)0)) {
2316 g_free (tryme);
2317 return TRUE(!(0));
2318 }
2319 return FALSE(0);
2320 }
2321}
2322
2323/**
2324 * mate_desktop_item_exists:
2325 * @item: A desktop item
2326 *
2327 * Attempt to figure out if the program that can be executed by this item
2328 * actually exists. First it tries the TryExec attribute to see if that
2329 * contains a program that is in the path. Then if there is no such
2330 * attribute, it tries the first word of the Exec attribute.
2331 *
2332 * Returns: A boolean, %TRUE if it exists, %FALSE otherwise.
2333 */
2334gboolean
2335mate_desktop_item_exists (const MateDesktopItem *item)
2336{
2337 const char *try_exec;
2338 const char *exec;
2339
2340 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2341
2342 try_exec = lookup (item, MATE_DESKTOP_ITEM_TRY_EXEC"TryExec");
2343
2344 if (try_exec != NULL((void*)0) &&
2345 ! exec_exists (try_exec)) {
2346 return FALSE(0);
2347 }
2348
2349 if (item->type == MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
2350 int argc;
2351 char **argv;
2352 const char *exe;
2353
2354 exec = lookup (item, MATE_DESKTOP_ITEM_EXEC"Exec");
2355 if (exec == NULL((void*)0))
2356 return FALSE(0);
2357
2358 if ( ! g_shell_parse_argv (exec, &argc, &argv, NULL((void*)0)))
2359 return FALSE(0);
2360
2361 if (argc < 1) {
2362 g_strfreev (argv);
2363 return FALSE(0);
2364 }
2365
2366 exe = argv[0];
2367
2368 if ( ! exec_exists (exe)) {
2369 g_strfreev (argv);
2370 return FALSE(0);
2371 }
2372 g_strfreev (argv);
2373 }
2374
2375 return TRUE(!(0));
2376}
2377
2378/**
2379 * mate_desktop_item_get_entry_type:
2380 * @item: A desktop item
2381 *
2382 * Gets the type attribute (the 'Type' field) of the item. This should
2383 * usually be 'Application' for an application, but it can be 'Directory'
2384 * for a directory description. There are other types available as well.
2385 * The type usually indicates how the desktop item should be handeled and
2386 * how the 'Exec' field should be handeled.
2387 *
2388 * Returns: The type of the specified 'item'. The returned
2389 * memory remains owned by the MateDesktopItem and should not be freed.
2390 */
2391MateDesktopItemType
2392mate_desktop_item_get_entry_type (const MateDesktopItem *item)
2393{
2394 g_return_val_if_fail (item != NULL, 0)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (0); } } while (0)
;
2395 g_return_val_if_fail (item->refcount > 0, 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (0); } } while (0)
;
2396
2397 return item->type;
2398}
2399
2400void
2401mate_desktop_item_set_entry_type (MateDesktopItem *item,
2402 MateDesktopItemType type)
2403{
2404 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2405 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2406
2407 item->type = type;
2408
2409 switch (type) {
2410 case MATE_DESKTOP_ITEM_TYPE_NULL:
2411 set (item, MATE_DESKTOP_ITEM_TYPE"Type", NULL((void*)0));
2412 break;
2413 case MATE_DESKTOP_ITEM_TYPE_APPLICATION:
2414 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Application");
2415 break;
2416 case MATE_DESKTOP_ITEM_TYPE_LINK:
2417 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Link");
2418 break;
2419 case MATE_DESKTOP_ITEM_TYPE_FSDEVICE:
2420 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "FSDevice");
2421 break;
2422 case MATE_DESKTOP_ITEM_TYPE_MIME_TYPE:
2423 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "MimeType");
2424 break;
2425 case MATE_DESKTOP_ITEM_TYPE_DIRECTORY:
2426 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Directory");
2427 break;
2428 case MATE_DESKTOP_ITEM_TYPE_SERVICE:
2429 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Service");
2430 break;
2431 case MATE_DESKTOP_ITEM_TYPE_SERVICE_TYPE:
2432 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "ServiceType");
2433 break;
2434 default:
2435 break;
2436 }
2437}
2438
2439/**
2440 * mate_desktop_item_get_file_status:
2441 * @item: A desktop item
2442 *
2443 * This function checks the modification time of the on-disk file to
2444 * see if it is more recent than the in-memory data.
2445 *
2446 * Returns: An enum value that specifies whether the item has changed since being loaded.
2447 */
2448MateDesktopItemStatus
2449mate_desktop_item_get_file_status (const MateDesktopItem *item)
2450{
2451 MateDesktopItemStatus retval;
2452 GFile *file;
2453 GFileInfo *info;
2454
2455 g_return_val_if_fail (item != NULL, MATE_DESKTOP_ITEM_DISAPPEARED)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (MATE_DESKTOP_ITEM_DISAPPEARED); } } while (0)
;
2456 g_return_val_if_fail (item->refcount > 0, MATE_DESKTOP_ITEM_DISAPPEARED)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (MATE_DESKTOP_ITEM_DISAPPEARED); } } while (0)
;
2457
2458 if (item->location == NULL((void*)0))
2459 return MATE_DESKTOP_ITEM_DISAPPEARED;
2460
2461 file = g_file_new_for_uri (item->location);
2462 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2463 G_FILE_QUERY_INFO_NONE, NULL((void*)0), NULL((void*)0));
2464
2465 retval = MATE_DESKTOP_ITEM_UNCHANGED;
2466
2467 if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2468 retval = MATE_DESKTOP_ITEM_DISAPPEARED;
2469 else if (((guint64) item->mtime) < g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2470 retval = MATE_DESKTOP_ITEM_CHANGED;
2471
2472 g_object_unref (info);
2473 g_object_unref (file);
2474
2475 return retval;
2476}
2477
2478/**
2479 * mate_desktop_item_find_icon:
2480 * @icon_theme: a #GtkIconTheme
2481 * @icon: icon name, something you'd get out of the Icon key
2482 * @desired_size: FIXME
2483 * @flags: FIXME
2484 *
2485 * Description: This function goes and looks for the icon file. If the icon
2486 * is not an absolute filename, this will look for it in the standard places.
2487 * If it can't find the icon, it will return %NULL
2488 *
2489 * Returns: A newly allocated string
2490 */
2491char *
2492mate_desktop_item_find_icon (GtkIconTheme *icon_theme,
2493 const char *icon,
2494 int desired_size,
2495 int flags)
2496{
2497 GtkIconInfo *info;
2498 char *full = NULL((void*)0);
2499
2500 g_return_val_if_fail (icon_theme == NULL ||do { if ((icon_theme == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((icon_theme)); GType __t = ((gtk_icon_theme_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "icon_theme == NULL || GTK_IS_ICON_THEME (icon_theme)"
); return (((void*)0)); } } while (0)
2501 GTK_IS_ICON_THEME (icon_theme), NULL)do { if ((icon_theme == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((icon_theme)); GType __t = ((gtk_icon_theme_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "icon_theme == NULL || GTK_IS_ICON_THEME (icon_theme)"
); return (((void*)0)); } } while (0)
;
2502
2503 if (icon == NULL((void*)0) || strcmp(icon,"") == 0) {
2504 return NULL((void*)0);
2505 } else if (g_path_is_absolute (icon)) {
2506 if (g_file_test (icon, G_FILE_TEST_EXISTS)) {
2507 return g_strdup (icon)g_strdup_inline (icon);
2508 } else {
2509 return NULL((void*)0);
2510 }
2511 } else {
2512 char *icon_no_extension;
2513 char *p;
2514
2515 if (icon_theme == NULL((void*)0))
2516 icon_theme = gtk_icon_theme_get_default ();
2517
2518 icon_no_extension = g_strdup (icon)g_strdup_inline (icon);
2519 p = strrchr (icon_no_extension, '.');
2520 if (p &&
2521 (strcmp (p, ".png") == 0 ||
2522 strcmp (p, ".xpm") == 0 ||
2523 strcmp (p, ".svg") == 0)) {
2524 *p = 0;
2525 }
2526
2527 info = gtk_icon_theme_lookup_icon (icon_theme,
2528 icon_no_extension,
2529 desired_size,
2530 0);
2531
2532 full = NULL((void*)0);
2533 if (info) {
2534 full = g_strdup (gtk_icon_info_get_filename (info))g_strdup_inline (gtk_icon_info_get_filename (info));
2535 g_object_unref (info);
2536 }
2537 g_free (icon_no_extension);
2538 }
2539
2540 return full;
2541
2542}
2543
2544/**
2545 * mate_desktop_item_get_icon:
2546 * @icon_theme: a #GtkIconTheme
2547 * @item: A desktop item
2548 *
2549 * Description: This function goes and looks for the icon file. If the icon
2550 * is not set as an absolute filename, this will look for it in the standard places.
2551 * If it can't find the icon, it will return %NULL
2552 *
2553 * Returns: A newly allocated string
2554 */
2555char *
2556mate_desktop_item_get_icon (const MateDesktopItem *item,
2557 GtkIconTheme *icon_theme)
2558{
2559 /* maybe this function should be deprecated in favour of find icon
2560 * -George */
2561 const char *icon;
2562
2563 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2564 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2565
2566 icon = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_ICON"Icon");
2567
2568 return mate_desktop_item_find_icon (icon_theme, icon,
2569 48 /* desired_size */,
2570 0 /* flags */);
2571}
2572
2573/**
2574 * mate_desktop_item_get_location:
2575 * @item: A desktop item
2576 *
2577 * Returns: The file location associated with 'item'.
2578 *
2579 */
2580const char *
2581mate_desktop_item_get_location (const MateDesktopItem *item)
2582{
2583 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2584 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2585
2586 return item->location;
2587}
2588
2589/**
2590 * mate_desktop_item_set_location:
2591 * @item: A desktop item
2592 * @location: A uri string specifying the file location of this particular item.
2593 *
2594 * Set's the 'location' uri of this item.
2595 */
2596void
2597mate_desktop_item_set_location (MateDesktopItem *item, const char *location)
2598{
2599 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2600 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2601
2602 if (item->location != NULL((void*)0) &&
2603 location != NULL((void*)0) &&
2604 strcmp (item->location, location) == 0)
2605 return;
2606
2607 g_free (item->location);
2608 item->location = g_strdup (location)g_strdup_inline (location);
2609
2610 /* This is ugly, but useful internally */
2611 if (item->mtime != DONT_UPDATE_MTIME((gint64)-2)) {
2612 item->mtime = 0;
2613
2614 if (item->location) {
2615 GFile *file;
2616 GFileInfo *info;
2617
2618 file = g_file_new_for_uri (item->location);
2619
2620 info = g_file_query_info (file,
2621 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2622 G_FILE_QUERY_INFO_NONE,
2623 NULL((void*)0), NULL((void*)0));
2624 if (info) {
2625 if (g_file_info_has_attribute (info,
2626 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2627 item->mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
2628 g_object_unref (info);
2629 }
2630
2631 g_object_unref (file);
2632 }
2633 }
2634
2635 /* Make sure that save actually saves */
2636 item->modified = TRUE(!(0));
2637}
2638
2639/**
2640 * mate_desktop_item_set_location_file:
2641 * @item: A desktop item
2642 * @file: A local filename specifying the file location of this particular item.
2643 *
2644 * Set's the 'location' uri of this item to the given @file.
2645 */
2646void
2647mate_desktop_item_set_location_file (MateDesktopItem *item, const char *file)
2648{
2649 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2650 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2651
2652 if (file != NULL((void*)0)) {
2653 GFile *gfile;
2654
2655 gfile = g_file_new_for_path (file);
2656 mate_desktop_item_set_location_gfile (item, gfile);
2657 g_object_unref (gfile);
2658 } else {
2659 mate_desktop_item_set_location (item, NULL((void*)0));
2660 }
2661}
2662
2663static void
2664mate_desktop_item_set_location_gfile (MateDesktopItem *item, GFile *file)
2665{
2666 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2667 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2668
2669 if (file != NULL((void*)0)) {
2670 char *uri;
2671
2672 uri = g_file_get_uri (file);
2673 mate_desktop_item_set_location (item, uri);
2674 g_free (uri);
2675 } else {
2676 mate_desktop_item_set_location (item, NULL((void*)0));
2677 }
2678}
2679
2680/*
2681 * Reading/Writing different sections, NULL is the standard section
2682 */
2683
2684gboolean
2685mate_desktop_item_attr_exists (const MateDesktopItem *item,
2686 const char *attr)
2687{
2688 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2689 g_return_val_if_fail (item->refcount > 0, FALSE)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return ((0)); } } while (0)
;
2690 g_return_val_if_fail (attr != NULL, FALSE)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return ((0)); } } while (0)
;
2691
2692 return lookup (item, attr) != NULL((void*)0);
2693}
2694
2695/*
2696 * String type
2697 */
2698const char *
2699mate_desktop_item_get_string (const MateDesktopItem *item,
2700 const char *attr)
2701{
2702 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2703 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2704 g_return_val_if_fail (attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2705
2706 return lookup (item, attr);
2707}
2708
2709void
2710mate_desktop_item_set_string (MateDesktopItem *item,
2711 const char *attr,
2712 const char *value)
2713{
2714 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2715 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2716 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2717
2718 set (item, attr, value);
2719
2720 if (strcmp (attr, MATE_DESKTOP_ITEM_TYPE"Type") == 0)
2721 item->type = type_from_string (value);
2722}
2723
2724/*
2725 * LocaleString type
2726 */
2727const char* mate_desktop_item_get_localestring(const MateDesktopItem* item, const char* attr)
2728{
2729 g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2730 g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2731 g_return_val_if_fail(attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2732
2733 return lookup_best_locale(item, attr);
2734}
2735
2736const char* mate_desktop_item_get_localestring_lang(const MateDesktopItem* item, const char* attr, const char* language)
2737{
2738 g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2739 g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2740 g_return_val_if_fail(attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2741
2742 return lookup_locale(item, attr, language);
2743}
2744
2745/**
2746 * mate_desktop_item_get_string_locale:
2747 * @item: A desktop item
2748 * @attr: An attribute name
2749 *
2750 * Returns the current locale that is used for the given attribute.
2751 * This might not be the same for all attributes. For example, if your
2752 * locale is "en_US.ISO8859-1" but attribute FOO only has "en_US" then
2753 * that would be returned for attr = "FOO". If attribute BAR has
2754 * "en_US.ISO8859-1" then that would be returned for "BAR".
2755 *
2756 * Returns: a string equal to the current locale or NULL
2757 * if the attribute is invalid or there is no matching locale.
2758 */
2759const char *
2760mate_desktop_item_get_attr_locale (const MateDesktopItem *item,
2761 const char *attr)
2762{
2763 const char * const *langs_pointer;
2764 int i;
2765
2766 langs_pointer = g_get_language_names ();
2767 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
2768 const char *value = NULL((void*)0);
2769
2770 value = lookup_locale (item, attr, langs_pointer[i]);
2771 if (value)
2772 return langs_pointer[i];
2773 }
2774
2775 return NULL((void*)0);
2776}
2777
2778GList *
2779mate_desktop_item_get_languages (const MateDesktopItem *item,
2780 const char *attr)
2781{
2782 GList *li;
2783 GList *list = NULL((void*)0);
2784
2785 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2786 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2787
2788 for (li = item->languages; li != NULL((void*)0); li = li->next) {
2789 char *language = li->data;
2790 if (attr == NULL((void*)0) ||
2791 lookup_locale (item, attr, language) != NULL((void*)0)) {
2792 list = g_list_prepend (list, language);
2793 }
2794 }
2795
2796 return g_list_reverse (list);
2797}
2798
2799static const char *
2800get_language (void)
2801{
2802 const char * const *langs_pointer;
2803 int i;
2804
2805 langs_pointer = g_get_language_names ();
2806 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
2807 /* find first without encoding */
2808 if (strchr (langs_pointer[i], '.') == NULL((void*)0)) {
2809 return langs_pointer[i];
2810 }
2811 }
2812 return NULL((void*)0);
2813}
2814
2815void
2816mate_desktop_item_set_localestring (MateDesktopItem *item,
2817 const char *attr,
2818 const char *value)
2819{
2820 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2821 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2822 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2823
2824 set_locale (item, attr, get_language (), value);
2825}
2826
2827void
2828mate_desktop_item_set_localestring_lang (MateDesktopItem *item,
2829 const char *attr,
2830 const char *language,
2831 const char *value)
2832{
2833 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2834 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2835 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2836
2837 set_locale (item, attr, language, value);
2838}
2839
2840void
2841mate_desktop_item_clear_localestring (MateDesktopItem *item,
2842 const char *attr)
2843{
2844 GList *l;
2845
2846 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2847 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2848 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2849
2850 for (l = item->languages; l != NULL((void*)0); l = l->next)
2851 set_locale (item, attr, l->data, NULL((void*)0));
2852
2853 set (item, attr, NULL((void*)0));
2854}
2855
2856/*
2857 * Strings, Regexps types
2858 */
2859
2860char **
2861mate_desktop_item_get_strings (const MateDesktopItem *item,
2862 const char *attr)
2863{
2864 const char *value;
2865
2866 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2867 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2868 g_return_val_if_fail (attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2869
2870 value = lookup (item, attr);
2871 if (value == NULL((void*)0))
2872 return NULL((void*)0);
2873
2874 /* FIXME: there's no way to escape semicolons apparently */
2875 return g_strsplit (value, ";", -1);
2876}
2877
2878void
2879mate_desktop_item_set_strings (MateDesktopItem *item,
2880 const char *attr,
2881 char **strings)
2882{
2883 char *str, *str2;
2884
2885 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2886 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2887 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2888
2889 str = g_strjoinv (";", strings);
2890 str2 = g_strconcat (str, ";", NULL((void*)0));
2891 /* FIXME: there's no way to escape semicolons apparently */
2892 set (item, attr, str2);
2893 g_free (str);
2894 g_free (str2);
2895}
2896
2897/*
2898 * Boolean type
2899 */
2900gboolean
2901mate_desktop_item_get_boolean (const MateDesktopItem *item,
2902 const char *attr)
2903{
2904 const char *value;
2905
2906 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2907 g_return_val_if_fail (item->refcount > 0, FALSE)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return ((0)); } } while (0)
;
2908 g_return_val_if_fail (attr != NULL, FALSE)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return ((0)); } } while (0)
;
2909
2910 value = lookup (item, attr);
2911 if (value == NULL((void*)0))
2912 return FALSE(0);
2913
2914 return (value[0] == 'T' ||
2915 value[0] == 't' ||
2916 value[0] == 'Y' ||
2917 value[0] == 'y' ||
2918 atoi (value) != 0);
2919}
2920
2921void
2922mate_desktop_item_set_boolean (MateDesktopItem *item,
2923 const char *attr,
2924 gboolean value)
2925{
2926 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2927 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2928 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2929
2930 set (item, attr, value ? "true" : "false");
2931}
2932
2933void
2934mate_desktop_item_set_launch_time (MateDesktopItem *item,
2935 guint32 timestamp)
2936{
2937 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2938
2939 item->launch_time = timestamp;
2940}
2941
2942/*
2943 * Clearing attributes
2944 */
2945void
2946mate_desktop_item_clear_section (MateDesktopItem *item,
2947 const char *section)
2948{
2949 Section *sec;
2950 GList *li;
2951
2952 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2953 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2954
2955 sec = find_section (item, section);
2956
2957 if (sec == NULL((void*)0)) {
2958 for (li = item->keys; li != NULL((void*)0); li = li->next) {
2959 g_hash_table_remove (item->main_hash, li->data);
2960 g_free (li->data);
2961 li->data = NULL((void*)0);
2962 }
2963 g_list_free (item->keys);
2964 item->keys = NULL((void*)0);
2965 } else {
2966 for (li = sec->keys; li != NULL((void*)0); li = li->next) {
2967 char *key = li->data;
2968 char *full = g_strdup_printf ("%s/%s",
2969 sec->name, key);
2970 g_hash_table_remove (item->main_hash, full);
2971 g_free (full);
2972 g_free (key);
2973 li->data = NULL((void*)0);
2974 }
2975 g_list_free (sec->keys);
2976 sec->keys = NULL((void*)0);
2977 }
2978 item->modified = TRUE(!(0));
2979}
2980
2981/************************************************************
2982 * Parser: *
2983 ************************************************************/
2984
2985static gboolean G_GNUC_CONST__attribute__ ((__const__))
2986standard_is_boolean (const char * key)
2987{
2988 static GHashTable *bools = NULL((void*)0);
2989
2990 if (bools == NULL((void*)0)) {
2991 bools = g_hash_table_new (g_str_hash, g_str_equal);
2992 g_hash_table_insert (bools,
2993 MATE_DESKTOP_ITEM_NO_DISPLAY"NoDisplay",
2994 MATE_DESKTOP_ITEM_NO_DISPLAY"NoDisplay");
2995 g_hash_table_insert (bools,
2996 MATE_DESKTOP_ITEM_HIDDEN"Hidden",
2997 MATE_DESKTOP_ITEM_HIDDEN"Hidden");
2998 g_hash_table_insert (bools,
2999 MATE_DESKTOP_ITEM_TERMINAL"Terminal",
3000 MATE_DESKTOP_ITEM_TERMINAL"Terminal");
3001 g_hash_table_insert (bools,
3002 MATE_DESKTOP_ITEM_READ_ONLY"ReadOnly",
3003 MATE_DESKTOP_ITEM_READ_ONLY"ReadOnly");
3004 }
3005
3006 return g_hash_table_lookup (bools, key) != NULL((void*)0);
3007}
3008
3009static gboolean G_GNUC_CONST__attribute__ ((__const__))
3010standard_is_strings (const char *key)
3011{
3012 static GHashTable *strings = NULL((void*)0);
3013
3014 if (strings == NULL((void*)0)) {
3015 strings = g_hash_table_new (g_str_hash, g_str_equal);
3016 g_hash_table_insert (strings,
3017 MATE_DESKTOP_ITEM_FILE_PATTERN"FilePattern",
3018 MATE_DESKTOP_ITEM_FILE_PATTERN"FilePattern");
3019 g_hash_table_insert (strings,
3020 MATE_DESKTOP_ITEM_ACTIONS"Actions",
3021 MATE_DESKTOP_ITEM_ACTIONS"Actions");
3022 g_hash_table_insert (strings,
3023 MATE_DESKTOP_ITEM_MIME_TYPE"MimeType",
3024 MATE_DESKTOP_ITEM_MIME_TYPE"MimeType");
3025 g_hash_table_insert (strings,
3026 MATE_DESKTOP_ITEM_PATTERNS"Patterns",
3027 MATE_DESKTOP_ITEM_PATTERNS"Patterns");
3028 g_hash_table_insert (strings,
3029 MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder",
3030 MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder");
3031 }
3032
3033 return g_hash_table_lookup (strings, key) != NULL((void*)0);
3034}
3035
3036/* If no need to cannonize, returns NULL */
3037static char *
3038cannonize (const char *key, const char *value)
3039{
3040 if (standard_is_boolean (key)) {
3041 if (value[0] == 'T' ||
3042 value[0] == 't' ||
3043 value[0] == 'Y' ||
3044 value[0] == 'y' ||
3045 atoi (value) != 0) {
3046 return g_strdup ("true")g_strdup_inline ("true");
3047 } else {
3048 return g_strdup ("false")g_strdup_inline ("false");
3049 }
3050 } else if (standard_is_strings (key)) {
3051 int len = strlen (value);
3052 if (len == 0 || value[len-1] != ';') {
3053 return g_strconcat (value, ";", NULL((void*)0));
3054 }
3055 }
3056 /* XXX: Perhaps we should canonize numeric values as well, but this
3057 * has caused some subtle problems before so it needs to be done
3058 * carefully if at all */
3059 return NULL((void*)0);
3060}
3061
3062static char *
3063decode_string_and_dup (const char *s)
3064{
3065 char *p = g_malloc (strlen (s) + 1);
3066 char *q = p;
3067
3068 do {
3069 if (*s == '\\'){
3070 switch (*(++s)){
3071 case 's':
3072 *p++ = ' ';
3073 break;
3074 case 't':
3075 *p++ = '\t';
3076 break;
3077 case 'n':
3078 *p++ = '\n';
3079 break;
3080 case '\\':
3081 *p++ = '\\';
3082 break;
3083 case 'r':
3084 *p++ = '\r';
3085 break;
3086 default:
3087 *p++ = '\\';
3088 *p++ = *s;
3089 break;
3090 }
3091 } else {
3092 *p++ = *s;
3093 }
3094 } while (*s++);
3095
3096 return q;
3097}
3098
3099static char *
3100escape_string_and_dup (const char *s)
3101{
3102 char *return_value, *p;
3103 const char *q;
3104 int len = 0;
3105
3106 if (s
11.1
's' is not equal to NULL
== NULL((void*)0))
12
Taking false branch
3107 return g_strdup("")g_strdup_inline ("");
3108
3109 q = s;
3110 while (*q){
13
Loop condition is true. Entering loop body
16
Loop condition is true. Entering loop body
19
Loop condition is false. Execution continues on line 3116
3111 len++;
3112 if (strchr ("\n\r\t\\", *q) != NULL((void*)0))
14
Assuming the condition is false
15
Taking false branch
17
Assuming the condition is false
18
Taking false branch
3113 len++;
3114 q++;
3115 }
3116 return_value = p = (char *) g_malloc (len + 1);
3117 do {
22
Loop condition is true. Execution continues on line 3118
3118 switch (*s){
20
Control jumps to 'case 92:' at line 3131
23
Control jumps to 'case 9:' at line 3119
3119 case '\t':
3120 *p++ = '\\';
3121 *p++ = 't';
24
Out of bound memory access (access exceeds upper limit of memory block)
3122 break;
3123 case '\n':
3124 *p++ = '\\';
3125 *p++ = 'n';
3126 break;
3127 case '\r':
3128 *p++ = '\\';
3129 *p++ = 'r';
3130 break;
3131 case '\\':
3132 *p++ = '\\';
3133 *p++ = '\\';
3134 break;
21
Execution continues on line 3138
3135 default:
3136 *p++ = *s;
3137 }
3138 } while (*s++);
3139 return return_value;
3140}
3141
3142static gboolean
3143check_locale (const char *locale)
3144{
3145 GIConv cd = g_iconv_open ("UTF-8", locale);
3146 if ((GIConv)-1 == cd)
3147 return FALSE(0);
3148 g_iconv_close (cd);
3149 return TRUE(!(0));
3150}
3151
3152static void
3153insert_locales (GHashTable *encodings, char *enc, ...)
3154{
3155 va_list args;
3156 char *s;
3157
3158 va_start (args, enc)__builtin_va_start(args, enc);
3159 for (;;) {
3160 s = va_arg (args, char *)__builtin_va_arg(args, char *);
3161 if (s == NULL((void*)0))
3162 break;
3163 g_hash_table_insert (encodings, s, enc);
3164 }
3165 va_end (args)__builtin_va_end(args);
3166}
3167
3168/* make a standard conversion table from the desktop standard spec */
3169static GHashTable *
3170init_encodings (void)
3171{
3172 GHashTable *encodings = g_hash_table_new (g_str_hash, g_str_equal);
3173
3174 /* "C" is plain ascii */
3175 insert_locales (encodings, "ASCII", "C", NULL((void*)0));
3176
3177 insert_locales (encodings, "ARMSCII-8", "by", NULL((void*)0));
3178 insert_locales (encodings, "BIG5", "zh_TW", NULL((void*)0));
3179 insert_locales (encodings, "CP1251", "be", "bg", NULL((void*)0));
3180 if (check_locale ("EUC-CN")) {
3181 insert_locales (encodings, "EUC-CN", "zh_CN", NULL((void*)0));
3182 } else {
3183 insert_locales (encodings, "GB2312", "zh_CN", NULL((void*)0));
3184 }
3185 insert_locales (encodings, "EUC-JP", "ja", NULL((void*)0));
3186 insert_locales (encodings, "EUC-KR", "ko", NULL((void*)0));
3187 /*insert_locales (encodings, "GEORGIAN-ACADEMY", NULL);*/
3188 insert_locales (encodings, "GEORGIAN-PS", "ka", NULL((void*)0));
3189 insert_locales (encodings, "ISO-8859-1", "br", "ca", "da", "de", "en", "es", "eu", "fi", "fr", "gl", "it", "nl", "wa", "no", "pt", "pt", "sv", NULL((void*)0));
3190 insert_locales (encodings, "ISO-8859-2", "cs", "hr", "hu", "pl", "ro", "sk", "sl", "sq", "sr", NULL((void*)0));
3191 insert_locales (encodings, "ISO-8859-3", "eo", NULL((void*)0));
3192 insert_locales (encodings, "ISO-8859-5", "mk", "sp", NULL((void*)0));
3193 insert_locales (encodings, "ISO-8859-7", "el", NULL((void*)0));
3194 insert_locales (encodings, "ISO-8859-9", "tr", NULL((void*)0));
3195 insert_locales (encodings, "ISO-8859-13", "lt", "lv", "mi", NULL((void*)0));
3196 insert_locales (encodings, "ISO-8859-14", "ga", "cy", NULL((void*)0));
3197 insert_locales (encodings, "ISO-8859-15", "et", NULL((void*)0));
3198 insert_locales (encodings, "KOI8-R", "ru", NULL((void*)0));
3199 insert_locales (encodings, "KOI8-U", "uk", NULL((void*)0));
3200 if (check_locale ("TCVN-5712")) {
3201 insert_locales (encodings, "TCVN-5712", "vi", NULL((void*)0));
3202 } else {
3203 insert_locales (encodings, "TCVN", "vi", NULL((void*)0));
3204 }
3205 insert_locales (encodings, "TIS-620", "th", NULL((void*)0));
3206 /*insert_locales (encodings, "VISCII", NULL);*/
3207
3208 return encodings;
3209}
3210
3211static const char *
3212get_encoding_from_locale (const char *locale)
3213{
3214 char lang[3];
3215 const char *encoding;
3216 static GHashTable *encodings = NULL((void*)0);
3217
3218 if (locale == NULL((void*)0))
3219 return NULL((void*)0);
3220
3221 /* if locale includes encoding, use it */
3222 encoding = strchr (locale, '.');
3223 if (encoding != NULL((void*)0)) {
3224 return encoding+1;
3225 }
3226
3227 if (encodings == NULL((void*)0))
3228 encodings = init_encodings ();
3229
3230 /* first try the entire locale (at this point ll_CC) */
3231 encoding = g_hash_table_lookup (encodings, locale);
3232 if (encoding != NULL((void*)0))
3233 return encoding;
3234
3235 /* Try just the language */
3236 strncpy (lang, locale, 2);
3237 lang[2] = '\0';
3238 return g_hash_table_lookup (encodings, lang);
3239}
3240
3241static Encoding
3242get_encoding (ReadBuf *rb)
3243{
3244 gboolean old_kde = FALSE(0);
3245 char buf [BUFSIZ8192];
3246 gboolean all_valid_utf8 = TRUE(!(0));
3247
3248 while (readbuf_gets (buf, sizeof (buf), rb) != NULL((void*)0)) {
3249 if (strncmp (MATE_DESKTOP_ITEM_ENCODING"Encoding",
3250 buf,
3251 strlen (MATE_DESKTOP_ITEM_ENCODING"Encoding")) == 0) {
3252 char *p = &buf[strlen (MATE_DESKTOP_ITEM_ENCODING"Encoding")];
3253 if (*p == ' ')
3254 p++;
3255 if (*p != '=')
3256 continue;
3257 p++;
3258 if (*p == ' ')
3259 p++;
3260 if (strcmp (p, "UTF-8") == 0) {
3261 return ENCODING_UTF8;
3262 } else if (strcmp (p, "Legacy-Mixed") == 0) {
3263 return ENCODING_LEGACY_MIXED;
3264 } else {
3265 /* According to the spec we're not supposed
3266 * to read a file like this */
3267 return ENCODING_UNKNOWN;
3268 }
3269 } else if (strcmp ("[KDE Desktop Entry]", buf) == 0) {
3270 old_kde = TRUE(!(0));
3271 /* don't break yet, we still want to support
3272 * Encoding even here */
3273 }
3274 if (all_valid_utf8 && ! g_utf8_validate (buf, -1, NULL((void*)0)))
3275 all_valid_utf8 = FALSE(0);
3276 }
3277
3278 if (old_kde)
3279 return ENCODING_LEGACY_MIXED;
3280
3281 /* try to guess by location */
3282 if (rb->uri != NULL((void*)0) && strstr (rb->uri, "mate/apps/") != NULL((void*)0)) {
3283 /* old mate */
3284 return ENCODING_LEGACY_MIXED;
3285 }
3286
3287 /* A dilemma, new KDE files are in UTF-8 but have no Encoding
3288 * info, at this time we really can't tell. The best thing to
3289 * do right now is to just assume UTF-8 if the whole file
3290 * validates as utf8 I suppose */
3291
3292 if (all_valid_utf8)
3293 return ENCODING_UTF8;
3294 else
3295 return ENCODING_LEGACY_MIXED;
3296}
3297
3298static char *
3299decode_string (const char *value, Encoding encoding, const char *locale)
3300{
3301 char *retval = NULL((void*)0);
3302
3303 /* if legacy mixed, then convert */
3304 if (locale != NULL((void*)0) && encoding == ENCODING_LEGACY_MIXED) {
3305 const char *char_encoding = get_encoding_from_locale (locale);
3306 char *utf8_string;
3307 if (char_encoding == NULL((void*)0))
3308 return NULL((void*)0);
3309 if (strcmp (char_encoding, "ASCII") == 0) {
3310 return decode_string_and_dup (value);
3311 }
3312 utf8_string = g_convert (value, -1, "UTF-8", char_encoding,
3313 NULL((void*)0), NULL((void*)0), NULL((void*)0));
3314 if (utf8_string == NULL((void*)0))
3315 return NULL((void*)0);
3316 retval = decode_string_and_dup (utf8_string);
3317 g_free (utf8_string);
3318 return retval;
3319 /* if utf8, then validate */
3320 } else if (locale != NULL((void*)0) && encoding == ENCODING_UTF8) {
3321 if ( ! g_utf8_validate (value, -1, NULL((void*)0)))
3322 /* invalid utf8, ignore this key */
3323 return NULL((void*)0);
3324 return decode_string_and_dup (value);
3325 } else {
3326 /* Meaning this is not a localized string */
3327 return decode_string_and_dup (value);
3328 }
3329}
3330
3331static char *
3332snarf_locale_from_key (const char *key)
3333{
3334 const char *brace;
3335 char *locale, *p;
3336
3337 brace = strchr (key, '[');
3338 if (brace == NULL((void*)0))
3339 return NULL((void*)0);
3340
3341 locale = g_strdup (brace + 1)g_strdup_inline (brace + 1);
3342 if (*locale == '\0') {
3343 g_free (locale);
3344 return NULL((void*)0);
3345 }
3346 p = strchr (locale, ']');
3347 if (p == NULL((void*)0)) {
3348 g_free (locale);
3349 return NULL((void*)0);
3350 }
3351 *p = '\0';
3352 return locale;
3353}
3354
3355static void
3356insert_key (MateDesktopItem *item,
3357 Section *cur_section,
3358 Encoding encoding,
3359 const char *key,
3360 const char *value,
3361 gboolean old_kde,
3362 gboolean no_translations)
3363{
3364 char *k;
3365 char *val;
3366 /* we always store everything in UTF-8 */
3367 if (cur_section == NULL((void*)0) &&
3368 strcmp (key, MATE_DESKTOP_ITEM_ENCODING"Encoding") == 0) {
3369 k = g_strdup (key)g_strdup_inline (key);
3370 val = g_strdup ("UTF-8")g_strdup_inline ("UTF-8");
3371 } else {
3372 char *locale = snarf_locale_from_key (key);
3373 /* If we're ignoring translations */
3374 if (no_translations && locale != NULL((void*)0)) {
3375 g_free (locale);
3376 return;
3377 }
3378 val = decode_string (value, encoding, locale);
3379
3380 /* Ignore this key, it's whacked */
3381 if (val == NULL((void*)0)) {
3382 g_free (locale);
3383 return;
3384 }
3385
3386 g_strchomp (val);
3387
3388 /* For old KDE entries, we can also split by a comma
3389 * on sort order, so convert to semicolons */
3390 if (old_kde &&
3391 cur_section == NULL((void*)0) &&
3392 strcmp (key, MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder") == 0 &&
3393 strchr (val, ';') == NULL((void*)0)) {
3394 int i;
3395 for (i = 0; val[i] != '\0'; i++) {
3396 if (val[i] == ',')
3397 val[i] = ';';
3398 }
3399 }
3400
3401 /* Check some types, not perfect, but catches a lot
3402 * of things */
3403 if (cur_section == NULL((void*)0)) {
3404 char *cannon = cannonize (key, val);
3405 if (cannon != NULL((void*)0)) {
3406 g_free (val);
3407 val = cannon;
3408 }
3409 }
3410
3411 k = g_strdup (key)g_strdup_inline (key);
3412
3413 /* Take care of the language part */
3414 if (locale != NULL((void*)0) &&
3415 strcmp (locale, "C") == 0) {
3416 char *p;
3417 /* Whack C locale */
3418 p = strchr (k, '[');
3419 *p = '\0';
3420 g_free (locale);
3421 } else if (locale != NULL((void*)0)) {
3422 char *p, *brace;
3423
3424 /* Whack the encoding part */
3425 p = strchr (locale, '.');
3426 if (p != NULL((void*)0))
3427 *p = '\0';
3428
3429 if (g_list_find_custom (item->languages, locale,
3430 (GCompareFunc)strcmp) == NULL((void*)0)) {
3431 item->languages = g_list_prepend
3432 (item->languages, locale);
3433 } else {
3434 g_free (locale);
3435 }
3436
3437 /* Whack encoding from encoding in the key */
3438 brace = strchr (k, '[');
3439 p = strchr (brace, '.');
3440 if (p != NULL((void*)0)) {
3441 *p = ']';
3442 *(p+1) = '\0';
3443 }
3444 }
3445 }
3446
3447 if (cur_section == NULL((void*)0)) {
3448 /* only add to list if we haven't seen it before */
3449 if (g_hash_table_lookup (item->main_hash, k) == NULL((void*)0)) {
3450 item->keys = g_list_prepend (item->keys,
3451 g_strdup (k)g_strdup_inline (k));
3452 }
3453 /* later duplicates override earlier ones */
3454 g_hash_table_replace (item->main_hash, k, val);
3455 } else {
3456 char *full = g_strdup_printf
3457 ("%s/%s",
3458 cur_section->name, k);
3459 /* only add to list if we haven't seen it before */
3460 if (g_hash_table_lookup (item->main_hash, full) == NULL((void*)0)) {
3461 cur_section->keys =
3462 g_list_prepend (cur_section->keys, k);
3463 }
3464 /* later duplicates override earlier ones */
3465 g_hash_table_replace (item->main_hash,
3466 full, val);
3467 }
3468}
3469
3470static void
3471setup_type (MateDesktopItem *item, const char *uri)
3472{
3473 const char *type = g_hash_table_lookup (item->main_hash,
3474 MATE_DESKTOP_ITEM_TYPE"Type");
3475 if (type == NULL((void*)0) && uri != NULL((void*)0)) {
3476 char *base = g_path_get_basename (uri);
3477 if (base != NULL((void*)0) &&
3478 strcmp (base, ".directory") == 0) {
3479 /* This gotta be a directory */
3480 g_hash_table_replace (item->main_hash,
3481 g_strdup (MATE_DESKTOP_ITEM_TYPE)g_strdup_inline ("Type"),
3482 g_strdup ("Directory")g_strdup_inline ("Directory"));
3483 item->keys = g_list_prepend
3484 (item->keys, g_strdup (MATE_DESKTOP_ITEM_TYPE)g_strdup_inline ("Type"));
3485 item->type = MATE_DESKTOP_ITEM_TYPE_DIRECTORY;
3486 } else {
3487 item->type = MATE_DESKTOP_ITEM_TYPE_NULL;
3488 }
3489 g_free (base);
3490 } else {
3491 item->type = type_from_string (type);
3492 }
3493}
3494
3495/* fallback to find something suitable for C locale */
3496static char *
3497try_english_key (MateDesktopItem *item, const char *key)
3498{
3499 char *str;
3500 char *locales[] = { "en_US", "en_GB", "en_AU", "en", NULL((void*)0) };
3501 int i;
3502
3503 str = NULL((void*)0);
3504 for (i = 0; locales[i] != NULL((void*)0) && str == NULL((void*)0); i++) {
3505 str = g_strdup (lookup_locale (item, key, locales[i]))g_strdup_inline (lookup_locale (item, key, locales[i]));
3506 }
3507 if (str != NULL((void*)0)) {
3508 /* We need a 7-bit ascii string, so whack all
3509 * above 127 chars */
3510 guchar *p;
3511 for (p = (guchar *)str; *p != '\0'; p++) {
3512 if (*p > 127)
3513 *p = '?';
3514 }
3515 }
3516 return str;
3517}
3518
3519static void
3520sanitize (MateDesktopItem *item, const char *uri)
3521{
3522 const char *type;
3523
3524 type = lookup (item, MATE_DESKTOP_ITEM_TYPE"Type");
3525
3526 /* understand old mate style url exec thingies */
3527 if (type != NULL((void*)0) && strcmp (type, "URL") == 0) {
3528 const char *exec = lookup (item, MATE_DESKTOP_ITEM_EXEC"Exec");
3529 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Link");
3530 if (exec != NULL((void*)0)) {
3531 /* Note, this must be in this order */
3532 set (item, MATE_DESKTOP_ITEM_URL"URL", exec);
3533 set (item, MATE_DESKTOP_ITEM_EXEC"Exec", NULL((void*)0));
3534 }
3535 }
3536
3537 /* we make sure we have Name, Encoding and Version */
3538 if (lookup (item, MATE_DESKTOP_ITEM_NAME"Name") == NULL((void*)0)) {
3539 char *name = try_english_key (item, MATE_DESKTOP_ITEM_NAME"Name");
3540 /* If no name, use the basename */
3541 if (name == NULL((void*)0) && uri != NULL((void*)0))
3542 name = g_path_get_basename (uri);
3543 /* If no uri either, use same default as mate_desktop_item_new */
3544 if (name == NULL((void*)0)) {
3545 /* Translators: the "name" mentioned here is the name of
3546 * an application or a document */
3547 name = g_strdup (_("No name"))g_strdup_inline (((char *) g_dgettext ("mate-desktop", "No name"
)))
;
3548 }
3549 g_hash_table_replace (item->main_hash,
3550 g_strdup (MATE_DESKTOP_ITEM_NAME)g_strdup_inline ("Name"),
3551 name);
3552 item->keys = g_list_prepend
3553 (item->keys, g_strdup (MATE_DESKTOP_ITEM_NAME)g_strdup_inline ("Name"));
3554 }
3555 if (lookup (item, MATE_DESKTOP_ITEM_ENCODING"Encoding") == NULL((void*)0)) {
3556 /* We store everything in UTF-8 so write that down */
3557 g_hash_table_replace (item->main_hash,
3558 g_strdup (MATE_DESKTOP_ITEM_ENCODING)g_strdup_inline ("Encoding"),
3559 g_strdup ("UTF-8")g_strdup_inline ("UTF-8"));
3560 item->keys = g_list_prepend
3561 (item->keys, g_strdup (MATE_DESKTOP_ITEM_ENCODING)g_strdup_inline ("Encoding"));
3562 }
3563 if (lookup (item, MATE_DESKTOP_ITEM_VERSION"Version") == NULL((void*)0)) {
3564 /* this is the version that we follow, so write it down */
3565 g_hash_table_replace (item->main_hash,
3566 g_strdup (MATE_DESKTOP_ITEM_VERSION)g_strdup_inline ("Version"),
3567 g_strdup ("1.0")g_strdup_inline ("1.0"));
3568 item->keys = g_list_prepend
3569 (item->keys, g_strdup (MATE_DESKTOP_ITEM_VERSION)g_strdup_inline ("Version"));
3570 }
3571}
3572
3573enum {
3574 FirstBrace,
3575 OnSecHeader,
3576 IgnoreToEOL,
3577 IgnoreToEOLFirst,
3578 KeyDef,
3579 KeyDefOnKey,
3580 KeyValue
3581};
3582
3583static MateDesktopItem *
3584ditem_load (ReadBuf *rb,
3585 gboolean no_translations,
3586 GError **error)
3587{
3588 int state;
3589 char CharBuffer [1024];
3590 char *next = CharBuffer;
3591 int c;
3592 Encoding encoding;
3593 MateDesktopItem *item;
3594 Section *cur_section = NULL((void*)0);
3595 char *key = NULL((void*)0);
3596 gboolean old_kde = FALSE(0);
3597
3598 encoding = get_encoding (rb);
3599 if (encoding == ENCODING_UNKNOWN) {
3600 /* spec says, don't read this file */
3601 g_set_error (error,
3602 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
3603 MATE_DESKTOP_ITEM_ERROR_UNKNOWN_ENCODING,
3604 _("Unknown encoding of: %s")((char *) g_dgettext ("mate-desktop", "Unknown encoding of: %s"
))
,
3605 rb->uri);
3606 readbuf_close (rb);
3607 return NULL((void*)0);
3608 }
3609
3610 /* Rewind since get_encoding goes through the file */
3611 if (! readbuf_rewind (rb, error)) {
3612 readbuf_close (rb);
3613 /* spec says, don't read this file */
3614 return NULL((void*)0);
3615 }
3616
3617 item = mate_desktop_item_new ();
3618 item->modified = FALSE(0);
3619
3620 /* Note: location and mtime are filled in by the new_from_file
3621 * function since it has those values */
3622
3623#define OVERFLOW (next == &CharBuffer [sizeof(CharBuffer)-1])
3624
3625 state = FirstBrace;
3626 while ((c = readbuf_getc (rb)) != EOF(-1)) {
3627 if (c == '\r') /* Ignore Carriage Return */
3628 continue;
3629
3630 switch (state) {
3631
3632 case OnSecHeader:
3633 if (c == ']' || OVERFLOW) {
3634 *next = '\0';
3635 next = CharBuffer;
3636
3637 /* keys were inserted in reverse */
3638 if (cur_section != NULL((void*)0) &&
3639 cur_section->keys != NULL((void*)0)) {
3640 cur_section->keys = g_list_reverse
3641 (cur_section->keys);
3642 }
3643 if (strcmp (CharBuffer,
3644 "KDE Desktop Entry") == 0) {
3645 /* Main section */
3646 cur_section = NULL((void*)0);
3647 old_kde = TRUE(!(0));
3648 } else if (strcmp (CharBuffer,
3649 "Desktop Entry") == 0) {
3650 /* Main section */
3651 cur_section = NULL((void*)0);
3652 } else {
3653 cur_section = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
3654 cur_section->name =
3655 g_strdup (CharBuffer)g_strdup_inline (CharBuffer);
3656 cur_section->keys = NULL((void*)0);
3657 item->sections = g_list_prepend
3658 (item->sections, cur_section);
3659 }
3660 state = IgnoreToEOL;
3661 } else if (c == '[') {
3662 /* FIXME: probably error out instead of ignoring this */
3663 } else {
3664 *next++ = c;
3665 }
3666 break;
3667
3668 case IgnoreToEOL:
3669 case IgnoreToEOLFirst:
3670 if (c == '\n'){
3671 if (state == IgnoreToEOLFirst)
3672 state = FirstBrace;
3673 else
3674 state = KeyDef;
3675 next = CharBuffer;
3676 }
3677 break;
3678
3679 case FirstBrace:
3680 case KeyDef:
3681 case KeyDefOnKey:
3682 if (c == '#') {
3683 if (state == FirstBrace)
3684 state = IgnoreToEOLFirst;
3685 else
3686 state = IgnoreToEOL;
3687 break;
3688 }
3689
3690 if (c == '[' && state != KeyDefOnKey){
3691 state = OnSecHeader;
3692 next = CharBuffer;
3693 g_free (key);
3694 key = NULL((void*)0);
3695 break;
3696 }
3697 /* On first pass, don't allow dangling keys */
3698 if (state == FirstBrace)
3699 break;
3700
3701 if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
3702 break;
3703
3704 if (c == '\n' || OVERFLOW) { /* Abort Definition */
3705 next = CharBuffer;
3706 state = KeyDef;
3707 break;
3708 }
3709
3710 if (c == '=' || OVERFLOW){
3711 *next = '\0';
3712
3713 g_free (key);
3714 key = g_strdup (CharBuffer)g_strdup_inline (CharBuffer);
3715 state = KeyValue;
3716 next = CharBuffer;
3717 } else {
3718 *next++ = c;
3719 state = KeyDefOnKey;
3720 }
3721 break;
3722
3723 case KeyValue:
3724 if (OVERFLOW || c == '\n'){
3725 *next = '\0';
3726
3727 insert_key (item, cur_section, encoding,
3728 key, CharBuffer, old_kde,
3729 no_translations);
3730
3731 g_free (key);
3732 key = NULL((void*)0);
3733
3734 state = (c == '\n') ? KeyDef : IgnoreToEOL;
3735 next = CharBuffer;
3736 } else {
3737 *next++ = c;
3738 }
3739 break;
3740
3741 } /* switch */
3742
3743 } /* while ((c = getc_unlocked (f)) != EOF) */
3744 if (c == EOF(-1) && state == KeyValue) {
3745 *next = '\0';
3746
3747 insert_key (item, cur_section, encoding,
3748 key, CharBuffer, old_kde,
3749 no_translations);
3750
3751 g_free (key);
3752 key = NULL((void*)0);
3753 }
3754
3755#undef OVERFLOW
3756
3757 /* keys were inserted in reverse */
3758 if (cur_section != NULL((void*)0) &&
3759 cur_section->keys != NULL((void*)0)) {
3760 cur_section->keys = g_list_reverse (cur_section->keys);
3761 }
3762 /* keys were inserted in reverse */
3763 item->keys = g_list_reverse (item->keys);
3764 /* sections were inserted in reverse */
3765 item->sections = g_list_reverse (item->sections);
3766
3767 /* sanitize some things */
3768 sanitize (item, rb->uri);
3769
3770 /* make sure that we set up the type */
3771 setup_type (item, rb->uri);
3772
3773 readbuf_close (rb);
3774
3775 return item;
3776}
3777
3778static void stream_printf (GFileOutputStream *stream,
3779 const char *format, ...) G_GNUC_PRINTF (2, 3)__attribute__((__format__ (__printf__, 2, 3)));
3780
3781static void
3782stream_printf (GFileOutputStream *stream, const char *format, ...)
3783{
3784 va_list args;
3785 gchar *s;
3786
3787 va_start (args, format)__builtin_va_start(args, format);
3788 s = g_strdup_vprintf (format, args);
3789 va_end (args)__builtin_va_end(args);
3790
3791 /* FIXME: what about errors */
3792 g_output_stream_write (G_OUTPUT_STREAM (stream)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((stream)), ((g_output_stream_get_type ()))))))
, s, strlen (s),
3793 NULL((void*)0), NULL((void*)0));
3794 g_free (s);
3795}
3796
3797static void
3798dump_section (MateDesktopItem *item, GFileOutputStream *stream, Section *section)
3799{
3800 GList *li;
3801
3802 stream_printf (stream, "[%s]\n", section->name);
3803 for (li = section->keys; li != NULL((void*)0); li = li->next) {
3804 const char *key = li->data;
3805 char *full = g_strdup_printf ("%s/%s", section->name, key);
3806 const char *value = g_hash_table_lookup (item->main_hash, full);
3807 if (value != NULL((void*)0)) {
3808 char *val = escape_string_and_dup (value);
3809 stream_printf (stream, "%s=%s\n", key, val);
3810 g_free (val);
3811 }
3812 g_free (full);
3813 }
3814}
3815
3816static gboolean
3817ditem_save (MateDesktopItem *item, const char *uri, GError **error)
3818{
3819 GList *li;
3820 GFile *file;
3821 GFileOutputStream *stream;
3822
3823 file = g_file_new_for_uri (uri);
3824 stream = g_file_replace (file, NULL((void*)0), FALSE(0), G_FILE_CREATE_NONE,
3825 NULL((void*)0), error);
3826 if (stream == NULL((void*)0))
5
Assuming 'stream' is not equal to NULL
6
Taking false branch
3827 return FALSE(0);
3828
3829 stream_printf (stream, "[Desktop Entry]\n");
3830 for (li = item->keys; li != NULL((void*)0); li = li->next) {
7
Assuming 'li' is not equal to NULL
8
Loop condition is true. Entering loop body
3831 const char *key = li->data;
3832 const char *value = g_hash_table_lookup (item->main_hash, key);
3833 if (value != NULL((void*)0)) {
9
Assuming 'value' is not equal to NULL
10
Taking true branch
3834 char *val = escape_string_and_dup (value);
11
Calling 'escape_string_and_dup'
3835 stream_printf (stream, "%s=%s\n", key, val);
3836 g_free (val);
3837 }
3838 }
3839
3840 if (item->sections != NULL((void*)0))
3841 stream_printf (stream, "\n");
3842
3843 for (li = item->sections; li != NULL((void*)0); li = li->next) {
3844 Section *section = li->data;
3845
3846 /* Don't write empty sections */
3847 if (section->keys == NULL((void*)0))
3848 continue;
3849
3850 dump_section (item, stream, section);
3851
3852 if (li->next != NULL((void*)0))
3853 stream_printf (stream, "\n");
3854 }
3855
3856 g_object_unref (stream);
3857 g_object_unref (file);
3858
3859 return TRUE(!(0));
3860}
3861
3862static gpointer
3863_mate_desktop_item_copy (gpointer boxed)
3864{
3865 return mate_desktop_item_copy (boxed);
3866}
3867
3868static void
3869_mate_desktop_item_free (gpointer boxed)
3870{
3871 mate_desktop_item_unref (boxed);
3872}
3873
3874GType
3875mate_desktop_item_get_type (void)
3876{
3877 static GType type = 0;
3878
3879 if (type == 0) {
3880 type = g_boxed_type_register_static ("MateDesktopItem",
3881 _mate_desktop_item_copy,
3882 _mate_desktop_item_free);
3883 }
3884
3885 return type;
3886}
3887
3888GQuark
3889mate_desktop_item_error_quark (void)
3890{
3891 static GQuark q = 0;
3892 if (q == 0)
3893 q = g_quark_from_static_string ("mate-desktop-item-error-quark");
3894
3895 return q;
3896}
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-413fe6.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-413fe6.html new file mode 100644 index 0000000..e30a673 --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-413fe6.html @@ -0,0 +1,2115 @@ + + + +mate-hsv.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-hsv.c
Warning:line 670, column 20
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-hsv.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-hsv.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* HSV color selector for GTK+
2 *
3 * Copyright (C) 1999 The Free Software Foundation
4 * Copyright (C) 2019-2021 MATE Developers
5 *
6 * Authors: Simon Budig <Simon.Budig@unix-ag.org> (original code)
7 * Federico Mena-Quintero <federico@gimp.org> (cleanup for GTK+)
8 * Jonathan Blandford <jrb@redhat.com> (cleanup for GTK+)
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
26 * file for a list of people on the GTK+ Team. See the ChangeLog
27 * files for a list of changes. These files are distributed with
28 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29 *
30 * Modified to work internally in mate-desktop by Pablo Barciela 2019
31 */
32
33#ifdef HAVE_CONFIG_H1
34#include "config.h"
35#endif
36
37#include "mate-hsv.h"
38
39#include <math.h>
40#include <string.h>
41
42#include <gtk/gtk.h>
43
44#define I_(string)g_intern_static_string (string) g_intern_static_string (string)
45
46/**
47 * SECTION:mate-hsv
48 * @Short_description: A “color wheel” widget
49 * @Title: MateHSV
50 *
51 * #MateHSV is the “color wheel” part of a complete color selector widget.
52 * It allows to select a color by determining its HSV components in an
53 * intuitive way. Moving the selection around the outer ring changes the hue,
54 * and moving the selection point inside the inner triangle changes value and
55 * saturation.
56 */
57
58/* Default width/height */
59#define DEFAULT_SIZE100 100
60
61/* Default ring width */
62#define DEFAULT_RING_WIDTH10 10
63
64/* Dragging modes */
65typedef enum {
66 DRAG_NONE,
67 DRAG_H,
68 DRAG_SV
69} DragMode;
70
71/* Private part of the MateHSV structure */
72struct _MateHSVPrivate
73{
74 /* Color value */
75 double h;
76 double s;
77 double v;
78
79 /* Size and ring width */
80 int size;
81 int ring_width;
82
83 /* Window for capturing events */
84 GdkWindow *window;
85
86 /* Dragging mode */
87 DragMode mode;
88
89 guint focus_on_ring : 1;
90};
91
92/* Signal IDs */
93
94enum {
95 CHANGED,
96 MOVE,
97 LAST_SIGNAL
98};
99
100static void mate_hsv_destroy (GtkWidget *widget);
101static void mate_hsv_realize (GtkWidget *widget);
102static void mate_hsv_unrealize (GtkWidget *widget);
103static void mate_hsv_get_preferred_width (GtkWidget *widget,
104 gint *minimum,
105 gint *natural);
106static void mate_hsv_get_preferred_height (GtkWidget *widget,
107 gint *minimum,
108 gint *natural);
109static void mate_hsv_size_allocate (GtkWidget *widget,
110 GtkAllocation *allocation);
111static gboolean mate_hsv_button_press (GtkWidget *widget,
112 GdkEventButton *event);
113static gboolean mate_hsv_button_release (GtkWidget *widget,
114 GdkEventButton *event);
115static gboolean mate_hsv_motion (GtkWidget *widget,
116 GdkEventMotion *event);
117static gboolean mate_hsv_draw (GtkWidget *widget,
118 cairo_t *cr);
119static gboolean mate_hsv_grab_broken (GtkWidget *widget,
120 GdkEventGrabBroken *event);
121static gboolean mate_hsv_focus (GtkWidget *widget,
122 GtkDirectionType direction);
123static void mate_hsv_move (MateHSV *hsv,
124 GtkDirectionType dir);
125
126static guint hsv_signals[LAST_SIGNAL];
127
128G_DEFINE_TYPE_WITH_PRIVATE (MateHSV, mate_hsv, GTK_TYPE_WIDGET)static void mate_hsv_init (MateHSV *self); static void mate_hsv_class_init
(MateHSVClass *klass); static GType mate_hsv_get_type_once (
void); static gpointer mate_hsv_parent_class = ((void*)0); static
gint MateHSV_private_offset; static void mate_hsv_class_intern_init
(gpointer klass) { mate_hsv_parent_class = g_type_class_peek_parent
(klass); if (MateHSV_private_offset != 0) g_type_class_adjust_private_offset
(klass, &MateHSV_private_offset); mate_hsv_class_init ((
MateHSVClass*) klass); } __attribute__ ((__unused__)) static inline
gpointer mate_hsv_get_instance_private (MateHSV *self) { return
(((gpointer) ((guint8*) (self) + (glong) (MateHSV_private_offset
)))); } GType mate_hsv_get_type (void) { static gsize static_g_define_type_id
= 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&static_g_define_type_id) : ((void*)0
)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = mate_hsv_get_type_once ()
; (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType mate_hsv_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((gtk_widget_get_type ()), g_intern_static_string ("MateHSV"
), sizeof (MateHSVClass), (GClassInitFunc)(void (*)(void)) mate_hsv_class_intern_init
, sizeof (MateHSV), (GInstanceInitFunc)(void (*)(void)) mate_hsv_init
, (GTypeFlags) 0); { {{ MateHSV_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (MateHSVPrivate)); };} } return g_define_type_id
; }
129
130/* Class initialization function for the HSV color selector */
131static void
132mate_hsv_class_init (MateHSVClass *class)
133{
134 GObjectClass *gobject_class;
135 GtkWidgetClass *widget_class;
136 MateHSVClass *hsv_class;
137 GtkBindingSet *binding_set;
138
139 gobject_class = (GObjectClass *) class;
140 widget_class = (GtkWidgetClass *) class;
141 hsv_class = MATE_HSV_CLASS (class)((((MateHSVClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), ((mate_hsv_get_type ()))))))
;
142
143 widget_class->destroy = mate_hsv_destroy;
144 widget_class->realize = mate_hsv_realize;
145 widget_class->unrealize = mate_hsv_unrealize;
146 widget_class->get_preferred_width = mate_hsv_get_preferred_width;
147 widget_class->get_preferred_height = mate_hsv_get_preferred_height;
148 widget_class->size_allocate = mate_hsv_size_allocate;
149 widget_class->button_press_event = mate_hsv_button_press;
150 widget_class->button_release_event = mate_hsv_button_release;
151 widget_class->motion_notify_event = mate_hsv_motion;
152 widget_class->draw = mate_hsv_draw;
153 widget_class->focus = mate_hsv_focus;
154 widget_class->grab_broken_event = mate_hsv_grab_broken;
155
156 gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_COLOR_CHOOSER);
157
158 hsv_class->move = mate_hsv_move;
159
160 hsv_signals[CHANGED] =
161 g_signal_new (I_("changed")g_intern_static_string ("changed"),
162 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
163 G_SIGNAL_RUN_FIRST,
164 G_STRUCT_OFFSET (MateHSVClass, changed)((glong) __builtin_offsetof(MateHSVClass, changed)),
165 NULL((void*)0), NULL((void*)0),
166 NULL((void*)0),
167 G_TYPE_NONE((GType) ((1) << (2))), 0);
168
169 hsv_signals[MOVE] =
170 g_signal_new (I_("move")g_intern_static_string ("move"),
171 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
172 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
173 G_STRUCT_OFFSET (MateHSVClass, move)((glong) __builtin_offsetof(MateHSVClass, move)),
174 NULL((void*)0), NULL((void*)0),
175 NULL((void*)0),
176 G_TYPE_NONE((GType) ((1) << (2))), 1,
177 GTK_TYPE_DIRECTION_TYPE(gtk_direction_type_get_type ()));
178
179 binding_set = gtk_binding_set_by_class (class);
180
181 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Up0xff52, 0,
182 "move", 1,
183 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_UP);
184 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Up0xff97, 0,
185 "move", 1,
186 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_UP);
187 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Down0xff54, 0,
188 "move", 1,
189 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_DOWN);
190 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Down0xff99, 0,
191 "move", 1,
192 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_DOWN);
193 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right0xff53, 0,
194 "move", 1,
195 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_RIGHT);
196 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right0xff98, 0,
197 "move", 1,
198 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_RIGHT);
199 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left0xff51, 0,
200 "move", 1,
201 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_LEFT);
202 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left0xff96, 0,
203 "move", 1,
204 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_LEFT);
205}
206
207static void
208mate_hsv_init (MateHSV *hsv)
209{
210 MateHSVPrivate *priv;
211
212 priv = mate_hsv_get_instance_private (hsv);
213 hsv->priv = priv;
214
215 gtk_widget_set_has_window (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
, FALSE(0));
216 gtk_widget_set_can_focus (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
, TRUE(!(0)));
217
218 priv->h = 0.0;
219 priv->s = 0.0;
220 priv->v = 0.0;
221
222 priv->size = DEFAULT_SIZE100;
223 priv->ring_width = DEFAULT_RING_WIDTH10;
224}
225
226static void
227mate_hsv_destroy (GtkWidget *widget)
228{
229 GTK_WIDGET_CLASS (mate_hsv_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((mate_hsv_parent_class)), ((gtk_widget_get_type ()))))))
->destroy (widget);
230}
231
232static void
233mate_hsv_realize (GtkWidget *widget)
234{
235 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
236 MateHSVPrivate *priv = hsv->priv;
237 GtkAllocation allocation;
238 GdkWindow *parent_window;
239 GdkWindowAttr attr;
240 int attr_mask;
241
242 gtk_widget_set_realized (widget, TRUE(!(0)));
243
244 gtk_widget_get_allocation (widget, &allocation);
245
246 attr.window_type = GDK_WINDOW_CHILD;
247 attr.x = allocation.x;
248 attr.y = allocation.y;
249 attr.width = allocation.width;
250 attr.height = allocation.height;
251 attr.wclass = GDK_INPUT_ONLY;
252 attr.event_mask = gtk_widget_get_events (widget);
253 attr.event_mask |= (GDK_KEY_PRESS_MASK
254 | GDK_BUTTON_PRESS_MASK
255 | GDK_BUTTON_RELEASE_MASK
256 | GDK_POINTER_MOTION_MASK
257 | GDK_ENTER_NOTIFY_MASK
258 | GDK_LEAVE_NOTIFY_MASK);
259 attr_mask = GDK_WA_X | GDK_WA_Y;
260
261 parent_window = gtk_widget_get_parent_window (widget);
262 gtk_widget_set_window (widget, parent_window);
263 g_object_ref (parent_window)((__typeof__ (parent_window)) (g_object_ref) (parent_window));
264
265 priv->window = gdk_window_new (parent_window, &attr, attr_mask);
266 gdk_window_set_user_data (priv->window, hsv);
267 gdk_window_show (priv->window);
268}
269
270static void
271mate_hsv_unrealize (GtkWidget *widget)
272{
273 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
274 MateHSVPrivate *priv = hsv->priv;
275
276 gdk_window_set_user_data (priv->window, NULL((void*)0));
277 gdk_window_destroy (priv->window);
278 priv->window = NULL((void*)0);
279
280 GTK_WIDGET_CLASS (mate_hsv_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((mate_hsv_parent_class)), ((gtk_widget_get_type ()))))))
->unrealize (widget);
281}
282
283static void
284mate_hsv_get_preferred_width (GtkWidget *widget,
285 gint *minimum,
286 gint *natural)
287{
288 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
289 MateHSVPrivate *priv = hsv->priv;
290 gint focus_width;
291 gint focus_pad;
292
293 gtk_widget_style_get (widget,
294 "focus-line-width", &focus_width,
295 "focus-padding", &focus_pad,
296 NULL((void*)0));
297
298 *minimum = priv->size + 2 * (focus_width + focus_pad);
299 *natural = priv->size + 2 * (focus_width + focus_pad);
300}
301
302static void
303mate_hsv_get_preferred_height (GtkWidget *widget,
304 gint *minimum,
305 gint *natural)
306{
307 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
308 MateHSVPrivate *priv = hsv->priv;
309 gint focus_width;
310 gint focus_pad;
311
312 gtk_widget_style_get (widget,
313 "focus-line-width", &focus_width,
314 "focus-padding", &focus_pad,
315 NULL((void*)0));
316
317 *minimum = priv->size + 2 * (focus_width + focus_pad);
318 *natural = priv->size + 2 * (focus_width + focus_pad);
319}
320
321static void
322mate_hsv_size_allocate (GtkWidget *widget,
323 GtkAllocation *allocation)
324{
325 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
326 MateHSVPrivate *priv = hsv->priv;
327
328 gtk_widget_set_allocation (widget, allocation);
329
330 if (gtk_widget_get_realized (widget))
331 gdk_window_move_resize (priv->window,
332 allocation->x,
333 allocation->y,
334 allocation->width,
335 allocation->height);
336}
337
338/* Utility functions */
339
340#define INTENSITY(r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
341
342/* Converts from HSV to RGB */
343static void
344hsv_to_rgb (gdouble *h,
345 gdouble *s,
346 gdouble *v)
347{
348 gdouble hue, saturation, value;
349 gdouble f, p, q, t;
350
351 if (*s == 0.0)
352 {
353 *h = *v;
354 *s = *v;
355 *v = *v; /* heh */
356 }
357 else
358 {
359 hue = *h * 6.0;
360 saturation = *s;
361 value = *v;
362
363 if (hue == 6.0)
364 hue = 0.0;
365
366 f = hue - (int) hue;
367 p = value * (1.0 - saturation);
368 q = value * (1.0 - saturation * f);
369 t = value * (1.0 - saturation * (1.0 - f));
370
371 switch ((int) hue)
372 {
373 case 0:
374 *h = value;
375 *s = t;
376 *v = p;
377 break;
378
379 case 1:
380 *h = q;
381 *s = value;
382 *v = p;
383 break;
384
385 case 2:
386 *h = p;
387 *s = value;
388 *v = t;
389 break;
390
391 case 3:
392 *h = p;
393 *s = q;
394 *v = value;
395 break;
396
397 case 4:
398 *h = t;
399 *s = p;
400 *v = value;
401 break;
402
403 case 5:
404 *h = value;
405 *s = p;
406 *v = q;
407 break;
408
409 default:
410 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-hsv.c", 410
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
411 }
412 }
413}
414
415/* Computes the vertices of the saturation/value triangle */
416static void
417compute_triangle (MateHSV *hsv,
418 gint *hx,
419 gint *hy,
420 gint *sx,
421 gint *sy,
422 gint *vx,
423 gint *vy)
424{
425 MateHSVPrivate *priv = hsv->priv;
426 GtkWidget *widget = GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
;
427 gdouble center_x;
428 gdouble center_y;
429 gdouble inner, outer;
430 gdouble angle;
431
432 center_x = gtk_widget_get_allocated_width (widget) / 2.0;
433 center_y = gtk_widget_get_allocated_height (widget) / 2.0;
434 outer = priv->size / 2.0;
435 inner = outer - priv->ring_width;
436 angle = priv->h * 2.0 * G_PI3.1415926535897932384626433832795028841971693993751;
437
438 *hx = floor (center_x + cos (angle) * inner + 0.5);
439 *hy = floor (center_y - sin (angle) * inner + 0.5);
440 *sx = floor (center_x + cos (angle + 2.0 * G_PI3.1415926535897932384626433832795028841971693993751 / 3.0) * inner + 0.5);
441 *sy = floor (center_y - sin (angle + 2.0 * G_PI3.1415926535897932384626433832795028841971693993751 / 3.0) * inner + 0.5);
442 *vx = floor (center_x + cos (angle + 4.0 * G_PI3.1415926535897932384626433832795028841971693993751 / 3.0) * inner + 0.5);
443 *vy = floor (center_y - sin (angle + 4.0 * G_PI3.1415926535897932384626433832795028841971693993751 / 3.0) * inner + 0.5);
444}
445
446/* Computes whether a point is inside the hue ring */
447static gboolean
448is_in_ring (MateHSV *hsv,
449 gdouble x,
450 gdouble y)
451{
452 MateHSVPrivate *priv = hsv->priv;
453 GtkWidget *widget = GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
;
454 gdouble dx, dy, dist;
455 gdouble center_x;
456 gdouble center_y;
457 gdouble inner, outer;
458
459 center_x = gtk_widget_get_allocated_width (widget) / 2.0;
460 center_y = gtk_widget_get_allocated_height (widget) / 2.0;
461 outer = priv->size / 2.0;
462 inner = outer - priv->ring_width;
463
464 dx = x - center_x;
465 dy = center_y - y;
466 dist = dx * dx + dy * dy;
467
468 return (dist >= inner * inner && dist <= outer * outer);
469}
470
471/* Computes a saturation/value pair based on the mouse coordinates */
472static void
473compute_sv (MateHSV *hsv,
474 gdouble x,
475 gdouble y,
476 gdouble *s,
477 gdouble *v)
478{
479 GtkWidget *widget = GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
;
480 int ihx, ihy, isx, isy, ivx, ivy;
481 double hx, hy, sx, sy, vx, vy;
482 double center_x;
483 double center_y;
484
485 compute_triangle (hsv, &ihx, &ihy, &isx, &isy, &ivx, &ivy);
486 center_x = gtk_widget_get_allocated_width (widget) / 2.0;
487 center_y = gtk_widget_get_allocated_height (widget) / 2.0;
488 hx = ihx - center_x;
489 hy = center_y - ihy;
490 sx = isx - center_x;
491 sy = center_y - isy;
492 vx = ivx - center_x;
493 vy = center_y - ivy;
494 x -= center_x;
495 y = center_y - y;
496
497 if (vx * (x - sx) + vy * (y - sy) < 0.0)
498 {
499 *s = 1.0;
500 *v = (((x - sx) * (hx - sx) + (y - sy) * (hy-sy))
501 / ((hx - sx) * (hx - sx) + (hy - sy) * (hy - sy)));
502
503 if (*v < 0.0)
504 *v = 0.0;
505 else if (*v > 1.0)
506 *v = 1.0;
507 }
508 else if (hx * (x - sx) + hy * (y - sy) < 0.0)
509 {
510 *s = 0.0;
511 *v = (((x - sx) * (vx - sx) + (y - sy) * (vy - sy))
512 / ((vx - sx) * (vx - sx) + (vy - sy) * (vy - sy)));
513
514 if (*v < 0.0)
515 *v = 0.0;
516 else if (*v > 1.0)
517 *v = 1.0;
518 }
519 else if (sx * (x - hx) + sy * (y - hy) < 0.0)
520 {
521 *v = 1.0;
522 *s = (((x - vx) * (hx - vx) + (y - vy) * (hy - vy)) /
523 ((hx - vx) * (hx - vx) + (hy - vy) * (hy - vy)));
524
525 if (*s < 0.0)
526 *s = 0.0;
527 else if (*s > 1.0)
528 *s = 1.0;
529 }
530 else
531 {
532 *v = (((x - sx) * (hy - vy) - (y - sy) * (hx - vx))
533 / ((vx - sx) * (hy - vy) - (vy - sy) * (hx - vx)));
534
535 if (*v<= 0.0)
536 {
537 *v = 0.0;
538 *s = 0.0;
539 }
540 else
541 {
542 if (*v > 1.0)
543 *v = 1.0;
544
545 if (fabs (hy - vy) < fabs (hx - vx))
546 *s = (x - sx - *v * (vx - sx)) / (*v * (hx - vx));
547 else
548 *s = (y - sy - *v * (vy - sy)) / (*v * (hy - vy));
549
550 if (*s < 0.0)
551 *s = 0.0;
552 else if (*s > 1.0)
553 *s = 1.0;
554 }
555 }
556}
557
558/* Computes whether a point is inside the saturation/value triangle */
559static gboolean
560is_in_triangle (MateHSV *hsv,
561 gdouble x,
562 gdouble y)
563{
564 int hx, hy, sx, sy, vx, vy;
565 double det, s, v;
566
567 compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
568
569 det = (vx - sx) * (hy - sy) - (vy - sy) * (hx - sx);
570
571 s = ((x - sx) * (hy - sy) - (y - sy) * (hx - sx)) / det;
572 v = ((vx - sx) * (y - sy) - (vy - sy) * (x - sx)) / det;
573
574 return (s >= 0.0 && v >= 0.0 && s + v <= 1.0);
575}
576
577/* Computes a value based on the mouse coordinates */
578static double
579compute_v (MateHSV *hsv,
580 gdouble x,
581 gdouble y)
582{
583 GtkWidget *widget = GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
;
584 double center_x;
585 double center_y;
586 double dx, dy;
587 double angle;
588
589 center_x = gtk_widget_get_allocated_width (widget) / 2.0;
590 center_y = gtk_widget_get_allocated_height (widget) / 2.0;
591 dx = x - center_x;
592 dy = center_y - y;
593
594 angle = atan2 (dy, dx);
595 if (angle < 0.0)
596 angle += 2.0 * G_PI3.1415926535897932384626433832795028841971693993751;
597
598 return angle / (2.0 * G_PI3.1415926535897932384626433832795028841971693993751);
599}
600
601/* Event handlers */
602
603static void
604set_cross_grab (MateHSV *hsv,
605 GdkDevice *device,
606 guint32 time)
607{
608 MateHSVPrivate *priv = hsv->priv;
609 GdkCursor *cursor;
610
611 cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
),
612 GDK_CROSSHAIR);
613 gdk_seat_grab (gdk_device_get_seat (device),
614 priv->window,
615 GDK_SEAT_CAPABILITY_ALL_POINTING,
616 FALSE(0),
617 cursor,
618 NULL((void*)0),
619 NULL((void*)0),
620 NULL((void*)0));
621 g_object_unref (cursor);
622}
623
624static gboolean
625mate_hsv_grab_broken (GtkWidget *widget,
626 GdkEventGrabBroken *event)
627{
628 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
629 MateHSVPrivate *priv = hsv->priv;
630
631 priv->mode = DRAG_NONE;
632
633 return TRUE(!(0));
634}
635
636static gint
637mate_hsv_button_press (GtkWidget *widget,
638 GdkEventButton *event)
639{
640 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
641 MateHSVPrivate *priv = hsv->priv;
642 double x, y;
643
644 if (priv->mode != DRAG_NONE || event->button != GDK_BUTTON_PRIMARY(1))
645 return FALSE(0);
646
647 x = event->x;
648 y = event->y;
649
650 if (is_in_ring (hsv, x, y))
651 {
652 priv->mode = DRAG_H;
653 set_cross_grab (hsv, gdk_event_get_device ((GdkEvent *) event), event->time);
654
655 mate_hsv_set_color (hsv,
656 compute_v (hsv, x, y),
657 priv->s,
658 priv->v);
659
660 gtk_widget_grab_focus (widget);
661 priv->focus_on_ring = TRUE(!(0));
662
663 return TRUE(!(0));
664 }
665
666 if (is_in_triangle (hsv, x, y))
667 {
668 gdouble s, v;
669
670 priv->mode = DRAG_SV;
This statement is never executed
671 set_cross_grab (hsv, gdk_event_get_device ((GdkEvent *) event), event->time);
672
673 compute_sv (hsv, x, y, &s, &v);
674 mate_hsv_set_color (hsv, priv->h, s, v);
675
676 gtk_widget_grab_focus (widget);
677 priv->focus_on_ring = FALSE(0);
678
679 return TRUE(!(0));
680 }
681
682 return FALSE(0);
683}
684
685static gint
686mate_hsv_button_release (GtkWidget *widget,
687 GdkEventButton *event)
688{
689 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
690 MateHSVPrivate *priv = hsv->priv;
691 DragMode mode;
692 gdouble x, y;
693
694 if (priv->mode == DRAG_NONE || event->button != GDK_BUTTON_PRIMARY(1))
695 return FALSE(0);
696
697 /* Set the drag mode to DRAG_NONE so that signal handlers for "catched"
698 * can see that this is the final color state.
699 */
700 mode = priv->mode;
701 priv->mode = DRAG_NONE;
702
703 x = event->x;
704 y = event->y;
705
706 if (mode == DRAG_H)
707 {
708 mate_hsv_set_color (hsv, compute_v (hsv, x, y), priv->s, priv->v);
709 }
710 else if (mode == DRAG_SV)
711 {
712 gdouble s, v;
713
714 compute_sv (hsv, x, y, &s, &v);
715 mate_hsv_set_color (hsv, priv->h, s, v);
716 }
717 else
718 {
719 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-hsv.c", 719
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
720 }
721
722 gdk_seat_ungrab (gdk_device_get_seat (gdk_event_get_device ((GdkEvent *) event)));
723
724 return TRUE(!(0));
725}
726
727static gint
728mate_hsv_motion (GtkWidget *widget,
729 GdkEventMotion *event)
730{
731 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
732 MateHSVPrivate *priv = hsv->priv;
733 gdouble x, y;
734
735 if (priv->mode == DRAG_NONE)
736 return FALSE(0);
737
738 gdk_event_request_motions (event);
739 x = event->x;
740 y = event->y;
741
742 if (priv->mode == DRAG_H)
743 {
744 mate_hsv_set_color (hsv, compute_v (hsv, x, y), priv->s, priv->v);
745 return TRUE(!(0));
746 }
747 else if (priv->mode == DRAG_SV)
748 {
749 gdouble s, v;
750
751 compute_sv (hsv, x, y, &s, &v);
752 mate_hsv_set_color (hsv, priv->h, s, v);
753 return TRUE(!(0));
754 }
755
756 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-hsv.c", 756
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
757
758 return FALSE(0);
759}
760
761/* Redrawing */
762
763/* Paints the hue ring */
764static void
765paint_ring (MateHSV *hsv,
766 cairo_t *cr)
767{
768 MateHSVPrivate *priv = hsv->priv;
769 GtkWidget *widget = GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
;
770 int xx, yy, width, height;
771 gdouble dx, dy, dist;
772 gdouble center_x;
773 gdouble center_y;
774 gdouble inner, outer;
775 guint32 *buf, *p;
776 gdouble angle;
777 gdouble hue;
778 gdouble r, g, b;
779 cairo_surface_t *source;
780 cairo_t *source_cr;
781 gint stride;
782
783 width = gtk_widget_get_allocated_width (widget);
784 height = gtk_widget_get_allocated_height (widget);
785
786 center_x = width / 2.0;
787 center_y = height / 2.0;
788
789 outer = priv->size / 2.0;
790 inner = outer - priv->ring_width;
791
792 /* Create an image initialized with the ring colors */
793
794 stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
795 buf = g_new (guint32, height * stride / 4)((guint32 *) g_malloc_n ((height * stride / 4), sizeof (guint32
)))
;
796
797 for (yy = 0; yy < height; yy++)
798 {
799 p = buf + yy * width;
800
801 dy = -(yy - center_y);
802
803 for (xx = 0; xx < width; xx++)
804 {
805 dx = xx - center_x;
806
807 dist = dx * dx + dy * dy;
808 if (dist < ((inner-1) * (inner-1)) || dist > ((outer+1) * (outer+1)))
809 {
810 *p++ = 0;
811 continue;
812 }
813
814 angle = atan2 (dy, dx);
815 if (angle < 0.0)
816 angle += 2.0 * G_PI3.1415926535897932384626433832795028841971693993751;
817
818 hue = angle / (2.0 * G_PI3.1415926535897932384626433832795028841971693993751);
819
820 r = hue;
821 g = 1.0;
822 b = 1.0;
823 hsv_to_rgb (&r, &g, &b);
824
825 *p++ = (((int)(r * 255.0) << 16) |
826 ((int)(g * 255.0) << 8) |
827 (int)(b * 255.0));
828 }
829 }
830
831 source = cairo_image_surface_create_for_data ((unsigned char *)buf,
832 CAIRO_FORMAT_RGB24,
833 width, height, stride);
834
835 /* Now draw the value marker onto the source image, so that it
836 * will get properly clipped at the edges of the ring
837 */
838 source_cr = cairo_create (source);
839
840 r = priv->h;
841 g = 1.0;
842 b = 1.0;
843 hsv_to_rgb (&r, &g, &b);
844
845 if (INTENSITY (r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) > 0.5)
846 cairo_set_source_rgb (source_cr, 0., 0., 0.);
847 else
848 cairo_set_source_rgb (source_cr, 1., 1., 1.);
849
850 cairo_move_to (source_cr, center_x, center_y);
851 cairo_line_to (source_cr,
852 center_x + cos (priv->h * 2.0 * G_PI3.1415926535897932384626433832795028841971693993751) * priv->size / 2,
853 center_y - sin (priv->h * 2.0 * G_PI3.1415926535897932384626433832795028841971693993751) * priv->size / 2);
854 cairo_stroke (source_cr);
855 cairo_destroy (source_cr);
856
857 /* Draw the ring using the source image */
858
859 cairo_save (cr);
860
861 cairo_set_source_surface (cr, source, 0, 0);
862 cairo_surface_destroy (source);
863
864 cairo_set_line_width (cr, priv->ring_width);
865 cairo_new_path (cr);
866 cairo_arc (cr,
867 center_x, center_y,
868 priv->size / 2. - priv->ring_width / 2.,
869 0, 2 * G_PI3.1415926535897932384626433832795028841971693993751);
870 cairo_stroke (cr);
871
872 cairo_restore (cr);
873
874 g_free (buf);
875}
876
877/* Converts an HSV triplet to an integer RGB triplet */
878static void
879get_color (gdouble h,
880 gdouble s,
881 gdouble v,
882 gint *r,
883 gint *g,
884 gint *b)
885{
886 hsv_to_rgb (&h, &s, &v);
887
888 *r = floor (h * 255 + 0.5);
889 *g = floor (s * 255 + 0.5);
890 *b = floor (v * 255 + 0.5);
891}
892
893#define SWAP(a, b, t)((t) = (a), (a) = (b), (b) = (t)) ((t) = (a), (a) = (b), (b) = (t))
894
895#define LERP(a, b, v1, v2, i)(((v2) - (v1) != 0) ? ((a) + ((b) - (a)) * ((i) - (v1)) / ((v2
) - (v1))) : (a))
(((v2) - (v1) != 0) \
896 ? ((a) + ((b) - (a)) * ((i) - (v1)) / ((v2) - (v1))) \
897 : (a))
898
899/* Number of pixels we extend out from the edges when creating
900 * color source to avoid artifacts
901 */
902#define PAD3 3
903
904/* Paints the HSV triangle */
905static void
906paint_triangle (MateHSV *hsv,
907 cairo_t *cr,
908 gboolean draw_focus)
909{
910 MateHSVPrivate *priv = hsv->priv;
911 GtkWidget *widget = GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
;
912 gint hx, hy, sx, sy, vx, vy; /* HSV vertices */
913 gint x1, y1, r1, g1, b1; /* First vertex in scanline order */
914 gint x2, y2, r2, g2, b2; /* Second vertex */
915 gint x3, y3, r3, g3, b3; /* Third vertex */
916 gint t;
917 guint32 *buf, *p, c;
918 gint xl, xr, rl, rr, gl, gr, bl, br; /* Scanline data */
919 gint xx, yy;
920 gint x_interp, y_interp;
921 gint x_start, x_end;
922 cairo_surface_t *source;
923 gdouble r, g, b;
924 gint stride;
925 int width, height;
926 GtkStyleContext *context;
927
928 width = gtk_widget_get_allocated_width (widget);
929 height = gtk_widget_get_allocated_height (widget);
930 /* Compute triangle's vertices */
931
932 compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
933
934 x1 = hx;
935 y1 = hy;
936 get_color (priv->h, 1.0, 1.0, &r1, &g1, &b1);
937
938 x2 = sx;
939 y2 = sy;
940 get_color (priv->h, 1.0, 0.0, &r2, &g2, &b2);
941
942 x3 = vx;
943 y3 = vy;
944 get_color (priv->h, 0.0, 1.0, &r3, &g3, &b3);
945
946 if (y2 > y3)
947 {
948 SWAP (x2, x3, t)((t) = (x2), (x2) = (x3), (x3) = (t));
949 SWAP (y2, y3, t)((t) = (y2), (y2) = (y3), (y3) = (t));
950 SWAP (r2, r3, t)((t) = (r2), (r2) = (r3), (r3) = (t));
951 SWAP (g2, g3, t)((t) = (g2), (g2) = (g3), (g3) = (t));
952 SWAP (b2, b3, t)((t) = (b2), (b2) = (b3), (b3) = (t));
953 }
954
955 if (y1 > y3)
956 {
957 SWAP (x1, x3, t)((t) = (x1), (x1) = (x3), (x3) = (t));
958 SWAP (y1, y3, t)((t) = (y1), (y1) = (y3), (y3) = (t));
959 SWAP (r1, r3, t)((t) = (r1), (r1) = (r3), (r3) = (t));
960 SWAP (g1, g3, t)((t) = (g1), (g1) = (g3), (g3) = (t));
961 SWAP (b1, b3, t)((t) = (b1), (b1) = (b3), (b3) = (t));
962 }
963
964 if (y1 > y2)
965 {
966 SWAP (x1, x2, t)((t) = (x1), (x1) = (x2), (x2) = (t));
967 SWAP (y1, y2, t)((t) = (y1), (y1) = (y2), (y2) = (t));
968 SWAP (r1, r2, t)((t) = (r1), (r1) = (r2), (r2) = (t));
969 SWAP (g1, g2, t)((t) = (g1), (g1) = (g2), (g2) = (t));
970 SWAP (b1, b2, t)((t) = (b1), (b1) = (b2), (b2) = (t));
971 }
972
973 /* Shade the triangle */
974
975 stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
976 buf = g_new (guint32, height * stride / 4)((guint32 *) g_malloc_n ((height * stride / 4), sizeof (guint32
)))
;
977
978 for (yy = 0; yy < height; yy++)
979 {
980 p = buf + yy * width;
981
982 if (yy >= y1 - PAD3 && yy < y3 + PAD3) {
983 y_interp = CLAMP (yy, y1, y3)(((yy) > (y3)) ? (y3) : (((yy) < (y1)) ? (y1) : (yy)));
984
985 if (y_interp < y2)
986 {
987 xl = LERP (x1, x2, y1, y2, y_interp)(((y2) - (y1) != 0) ? ((x1) + ((x2) - (x1)) * ((y_interp) - (
y1)) / ((y2) - (y1))) : (x1))
;
988
989 rl = LERP (r1, r2, y1, y2, y_interp)(((y2) - (y1) != 0) ? ((r1) + ((r2) - (r1)) * ((y_interp) - (
y1)) / ((y2) - (y1))) : (r1))
;
990 gl = LERP (g1, g2, y1, y2, y_interp)(((y2) - (y1) != 0) ? ((g1) + ((g2) - (g1)) * ((y_interp) - (
y1)) / ((y2) - (y1))) : (g1))
;
991 bl = LERP (b1, b2, y1, y2, y_interp)(((y2) - (y1) != 0) ? ((b1) + ((b2) - (b1)) * ((y_interp) - (
y1)) / ((y2) - (y1))) : (b1))
;
992 }
993 else
994 {
995 xl = LERP (x2, x3, y2, y3, y_interp)(((y3) - (y2) != 0) ? ((x2) + ((x3) - (x2)) * ((y_interp) - (
y2)) / ((y3) - (y2))) : (x2))
;
996
997 rl = LERP (r2, r3, y2, y3, y_interp)(((y3) - (y2) != 0) ? ((r2) + ((r3) - (r2)) * ((y_interp) - (
y2)) / ((y3) - (y2))) : (r2))
;
998 gl = LERP (g2, g3, y2, y3, y_interp)(((y3) - (y2) != 0) ? ((g2) + ((g3) - (g2)) * ((y_interp) - (
y2)) / ((y3) - (y2))) : (g2))
;
999 bl = LERP (b2, b3, y2, y3, y_interp)(((y3) - (y2) != 0) ? ((b2) + ((b3) - (b2)) * ((y_interp) - (
y2)) / ((y3) - (y2))) : (b2))
;
1000 }
1001
1002 xr = LERP (x1, x3, y1, y3, y_interp)(((y3) - (y1) != 0) ? ((x1) + ((x3) - (x1)) * ((y_interp) - (
y1)) / ((y3) - (y1))) : (x1))
;
1003
1004 rr = LERP (r1, r3, y1, y3, y_interp)(((y3) - (y1) != 0) ? ((r1) + ((r3) - (r1)) * ((y_interp) - (
y1)) / ((y3) - (y1))) : (r1))
;
1005 gr = LERP (g1, g3, y1, y3, y_interp)(((y3) - (y1) != 0) ? ((g1) + ((g3) - (g1)) * ((y_interp) - (
y1)) / ((y3) - (y1))) : (g1))
;
1006 br = LERP (b1, b3, y1, y3, y_interp)(((y3) - (y1) != 0) ? ((b1) + ((b3) - (b1)) * ((y_interp) - (
y1)) / ((y3) - (y1))) : (b1))
;
1007
1008 if (xl > xr)
1009 {
1010 SWAP (xl, xr, t)((t) = (xl), (xl) = (xr), (xr) = (t));
1011 SWAP (rl, rr, t)((t) = (rl), (rl) = (rr), (rr) = (t));
1012 SWAP (gl, gr, t)((t) = (gl), (gl) = (gr), (gr) = (t));
1013 SWAP (bl, br, t)((t) = (bl), (bl) = (br), (br) = (t));
1014 }
1015
1016 x_start = MAX (xl - PAD, 0)(((xl - 3) > (0)) ? (xl - 3) : (0));
1017 x_end = MIN (xr + PAD, width)(((xr + 3) < (width)) ? (xr + 3) : (width));
1018 x_start = MIN (x_start, x_end)(((x_start) < (x_end)) ? (x_start) : (x_end));
1019
1020 c = (rl << 16) | (gl << 8) | bl;
1021
1022 for (xx = 0; xx < x_start; xx++)
1023 *p++ = c;
1024
1025 for (; xx < x_end; xx++)
1026 {
1027 x_interp = CLAMP (xx, xl, xr)(((xx) > (xr)) ? (xr) : (((xx) < (xl)) ? (xl) : (xx)));
1028
1029 *p++ = ((LERP (rl, rr, xl, xr, x_interp)(((xr) - (xl) != 0) ? ((rl) + ((rr) - (rl)) * ((x_interp) - (
xl)) / ((xr) - (xl))) : (rl))
<< 16) |
1030 (LERP (gl, gr, xl, xr, x_interp)(((xr) - (xl) != 0) ? ((gl) + ((gr) - (gl)) * ((x_interp) - (
xl)) / ((xr) - (xl))) : (gl))
<< 8) |
1031 LERP (bl, br, xl, xr, x_interp)(((xr) - (xl) != 0) ? ((bl) + ((br) - (bl)) * ((x_interp) - (
xl)) / ((xr) - (xl))) : (bl))
);
1032 }
1033
1034 c = (rr << 16) | (gr << 8) | br;
1035
1036 for (; xx < width; xx++)
1037 *p++ = c;
1038 }
1039 }
1040
1041 source = cairo_image_surface_create_for_data ((unsigned char *)buf,
1042 CAIRO_FORMAT_RGB24,
1043 width, height, stride);
1044
1045 /* Draw a triangle with the image as a source */
1046
1047 cairo_set_source_surface (cr, source, 0, 0);
1048 cairo_surface_destroy (source);
1049
1050 cairo_move_to (cr, x1, y1);
1051 cairo_line_to (cr, x2, y2);
1052 cairo_line_to (cr, x3, y3);
1053 cairo_close_path (cr);
1054 cairo_fill (cr);
1055
1056 g_free (buf);
1057
1058 /* Draw value marker */
1059
1060 xx = floor (sx + (vx - sx) * priv->v + (hx - vx) * priv->s * priv->v + 0.5);
1061 yy = floor (sy + (vy - sy) * priv->v + (hy - vy) * priv->s * priv->v + 0.5);
1062
1063 r = priv->h;
1064 g = priv->s;
1065 b = priv->v;
1066 hsv_to_rgb (&r, &g, &b);
1067
1068 context = gtk_widget_get_style_context (widget);
1069
1070 gtk_style_context_save (context);
1071
1072 if (INTENSITY (r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) > 0.5)
1073 {
1074 gtk_style_context_add_class (context, "light-area-focus");
1075 cairo_set_source_rgb (cr, 0., 0., 0.);
1076 }
1077 else
1078 {
1079 gtk_style_context_add_class (context, "dark-area-focus");
1080 cairo_set_source_rgb (cr, 1., 1., 1.);
1081 }
1082
1083#define RADIUS4 4
1084#define FOCUS_RADIUS6 6
1085
1086 cairo_new_path (cr);
1087 cairo_arc (cr, xx, yy, RADIUS4, 0, 2 * G_PI3.1415926535897932384626433832795028841971693993751);
1088 cairo_stroke (cr);
1089
1090 /* Draw focus outline */
1091
1092 if (draw_focus && !priv->focus_on_ring)
1093 {
1094 gint focus_width;
1095 gint focus_pad;
1096
1097 gtk_widget_style_get (widget,
1098 "focus-line-width", &focus_width,
1099 "focus-padding", &focus_pad,
1100 NULL((void*)0));
1101
1102 gtk_render_focus (context, cr,
1103 xx - FOCUS_RADIUS6 - focus_width - focus_pad,
1104 yy - FOCUS_RADIUS6 - focus_width - focus_pad,
1105 2 * (FOCUS_RADIUS6 + focus_width + focus_pad),
1106 2 * (FOCUS_RADIUS6 + focus_width + focus_pad));
1107 }
1108
1109 gtk_style_context_restore (context);
1110}
1111
1112/* Paints the contents of the HSV color selector */
1113static gboolean
1114mate_hsv_draw (GtkWidget *widget,
1115 cairo_t *cr)
1116{
1117 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
1118 MateHSVPrivate *priv = hsv->priv;
1119 gboolean draw_focus;
1120
1121 draw_focus = gtk_widget_has_visible_focus (widget);
1122
1123 paint_ring (hsv, cr);
1124 paint_triangle (hsv, cr, draw_focus);
1125
1126 if (draw_focus && priv->focus_on_ring)
1127 {
1128 GtkStyleContext *context;
1129
1130 context = gtk_widget_get_style_context (widget);
1131
1132 gtk_render_focus (context, cr, 0, 0,
1133 gtk_widget_get_allocated_width (widget),
1134 gtk_widget_get_allocated_height (widget));
1135 }
1136
1137 return FALSE(0);
1138}
1139
1140static gboolean
1141mate_hsv_focus (GtkWidget *widget,
1142 GtkDirectionType dir)
1143{
1144 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
1145 MateHSVPrivate *priv = hsv->priv;
1146
1147 if (!gtk_widget_has_focus (widget))
1148 {
1149 if (dir == GTK_DIR_TAB_BACKWARD)
1150 priv->focus_on_ring = FALSE(0);
1151 else
1152 priv->focus_on_ring = TRUE(!(0));
1153
1154 gtk_widget_grab_focus (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
);
1155 return TRUE(!(0));
1156 }
1157
1158 switch (dir)
1159 {
1160 case GTK_DIR_UP:
1161 if (priv->focus_on_ring)
1162 return FALSE(0);
1163 else
1164 priv->focus_on_ring = TRUE(!(0));
1165 break;
1166
1167 case GTK_DIR_DOWN:
1168 if (priv->focus_on_ring)
1169 priv->focus_on_ring = FALSE(0);
1170 else
1171 return FALSE(0);
1172 break;
1173
1174 case GTK_DIR_LEFT:
1175 case GTK_DIR_TAB_BACKWARD:
1176 if (priv->focus_on_ring)
1177 return FALSE(0);
1178 else
1179 priv->focus_on_ring = TRUE(!(0));
1180 break;
1181
1182 case GTK_DIR_RIGHT:
1183 case GTK_DIR_TAB_FORWARD:
1184 if (priv->focus_on_ring)
1185 priv->focus_on_ring = FALSE(0);
1186 else
1187 return FALSE(0);
1188 break;
1189 }
1190
1191 gtk_widget_queue_draw (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
);
1192
1193 return TRUE(!(0));
1194}
1195
1196/**
1197 * mate_hsv_new:
1198 *
1199 * Creates a new HSV color selector.
1200 *
1201 * Returns: A newly-created HSV color selector.
1202 */
1203GtkWidget*
1204mate_hsv_new (void)
1205{
1206 return g_object_new (MATE_TYPE_HSV(mate_hsv_get_type ()), NULL((void*)0));
1207}
1208
1209/**
1210 * mate_hsv_set_color:
1211 * @hsv: An HSV color selector
1212 * @h: Hue
1213 * @s: Saturation
1214 * @v: Value
1215 *
1216 * Sets the current color in an HSV color selector.
1217 * Color component values must be in the [0.0, 1.0] range.
1218 */
1219void
1220mate_hsv_set_color (MateHSV *hsv,
1221 gdouble h,
1222 gdouble s,
1223 gdouble v)
1224{
1225 MateHSVPrivate *priv;
1226
1227 g_return_if_fail (MATE_IS_HSV (hsv))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((mate_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_HSV (hsv)"); return; } } while (0)
;
1228 g_return_if_fail (h >= 0.0 && h <= 1.0)do { if ((h >= 0.0 && h <= 1.0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "h >= 0.0 && h <= 1.0"
); return; } } while (0)
;
1229 g_return_if_fail (s >= 0.0 && s <= 1.0)do { if ((s >= 0.0 && s <= 1.0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "s >= 0.0 && s <= 1.0"
); return; } } while (0)
;
1230 g_return_if_fail (v >= 0.0 && v <= 1.0)do { if ((v >= 0.0 && v <= 1.0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "v >= 0.0 && v <= 1.0"
); return; } } while (0)
;
1231
1232 priv = hsv->priv;
1233
1234 priv->h = h;
1235 priv->s = s;
1236 priv->v = v;
1237
1238 g_signal_emit (hsv, hsv_signals[CHANGED], 0);
1239
1240 gtk_widget_queue_draw (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
);
1241}
1242
1243/**
1244 * mate_hsv_get_color:
1245 * @hsv: An HSV color selector
1246 * @h: (out): Return value for the hue
1247 * @s: (out): Return value for the saturation
1248 * @v: (out): Return value for the value
1249 *
1250 * Queries the current color in an HSV color selector.
1251 * Returned values will be in the [0.0, 1.0] range.
1252 */
1253void
1254mate_hsv_get_color (MateHSV *hsv,
1255 double *h,
1256 double *s,
1257 double *v)
1258{
1259 MateHSVPrivate *priv;
1260
1261 g_return_if_fail (MATE_IS_HSV (hsv))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((mate_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_HSV (hsv)"); return; } } while (0)
;
1262
1263 priv = hsv->priv;
1264
1265 if (h)
1266 *h = priv->h;
1267
1268 if (s)
1269 *s = priv->s;
1270
1271 if (v)
1272 *v = priv->v;
1273}
1274
1275/**
1276 * mate_hsv_set_metrics:
1277 * @hsv: An HSV color selector
1278 * @size: Diameter for the hue ring
1279 * @ring_width: Width of the hue ring
1280 *
1281 * Sets the size and ring width of an HSV color selector.
1282 */
1283void
1284mate_hsv_set_metrics (MateHSV *hsv,
1285 gint size,
1286 gint ring_width)
1287{
1288 MateHSVPrivate *priv;
1289 int same_size;
1290
1291 g_return_if_fail (MATE_IS_HSV (hsv))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((mate_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_HSV (hsv)"); return; } } while (0)
;
1292 g_return_if_fail (size > 0)do { if ((size > 0)) { } else { g_return_if_fail_warning (
"MateDesktop", ((const char*) (__func__)), "size > 0"); return
; } } while (0)
;
1293 g_return_if_fail (ring_width > 0)do { if ((ring_width > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "ring_width > 0"
); return; } } while (0)
;
1294 g_return_if_fail (2 * ring_width + 1 <= size)do { if ((2 * ring_width + 1 <= size)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "2 * ring_width + 1 <= size"
); return; } } while (0)
;
1295
1296 priv = hsv->priv;
1297
1298 same_size = (priv->size == size);
1299
1300 priv->size = size;
1301 priv->ring_width = ring_width;
1302
1303 if (same_size)
1304 gtk_widget_queue_draw (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
);
1305 else
1306 gtk_widget_queue_resize (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
);
1307}
1308
1309/**
1310 * mate_hsv_get_metrics:
1311 * @hsv: An HSV color selector
1312 * @size: (out): Return value for the diameter of the hue ring
1313 * @ring_width: (out): Return value for the width of the hue ring
1314 *
1315 * Queries the size and ring width of an HSV color selector.
1316 */
1317void
1318mate_hsv_get_metrics (MateHSV *hsv,
1319 gint *size,
1320 gint *ring_width)
1321{
1322 MateHSVPrivate *priv;
1323
1324 g_return_if_fail (MATE_IS_HSV (hsv))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((mate_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_HSV (hsv)"); return; } } while (0)
;
1325
1326 priv = hsv->priv;
1327
1328 if (size)
1329 *size = priv->size;
1330
1331 if (ring_width)
1332 *ring_width = priv->ring_width;
1333}
1334
1335/**
1336 * mate_hsv_is_adjusting:
1337 * @hsv: A #MateHSV
1338 *
1339 * An HSV color selector can be said to be adjusting if multiple rapid
1340 * changes are being made to its value, for example, when the user is
1341 * adjusting the value with the mouse. This function queries whether
1342 * the HSV color selector is being adjusted or not.
1343 *
1344 * Returns: %TRUE if clients can ignore changes to the color value,
1345 * since they may be transitory, or %FALSE if they should consider
1346 * the color value status to be final.
1347 */
1348gboolean
1349mate_hsv_is_adjusting (MateHSV *hsv)
1350{
1351 MateHSVPrivate *priv;
1352
1353 g_return_val_if_fail (MATE_IS_HSV (hsv), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((mate_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_HSV (hsv)"); return ((0)); } } while
(0)
;
1354
1355 priv = hsv->priv;
1356
1357 return priv->mode != DRAG_NONE;
1358}
1359
1360static void
1361mate_hsv_move (MateHSV *hsv,
1362 GtkDirectionType dir)
1363{
1364 MateHSVPrivate *priv = hsv->priv;
1365 gdouble hue, sat, val;
1366 gint hx, hy, sx, sy, vx, vy; /* HSV vertices */
1367 gint x, y; /* position in triangle */
1368
1369 hue = priv->h;
1370 sat = priv->s;
1371 val = priv->v;
1372
1373 compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
1374
1375 x = floor (sx + (vx - sx) * priv->v + (hx - vx) * priv->s * priv->v + 0.5);
1376 y = floor (sy + (vy - sy) * priv->v + (hy - vy) * priv->s * priv->v + 0.5);
1377
1378#define HUE_DELTA0.002 0.002
1379 switch (dir)
1380 {
1381 case GTK_DIR_UP:
1382 if (priv->focus_on_ring)
1383 hue += HUE_DELTA0.002;
1384 else
1385 {
1386 y -= 1;
1387 compute_sv (hsv, x, y, &sat, &val);
1388 }
1389 break;
1390
1391 case GTK_DIR_DOWN:
1392 if (priv->focus_on_ring)
1393 hue -= HUE_DELTA0.002;
1394 else
1395 {
1396 y += 1;
1397 compute_sv (hsv, x, y, &sat, &val);
1398 }
1399 break;
1400
1401 case GTK_DIR_LEFT:
1402 if (priv->focus_on_ring)
1403 hue += HUE_DELTA0.002;
1404 else
1405 {
1406 x -= 1;
1407 compute_sv (hsv, x, y, &sat, &val);
1408 }
1409 break;
1410
1411 case GTK_DIR_RIGHT:
1412 if (priv->focus_on_ring)
1413 hue -= HUE_DELTA0.002
1414 ;
1415 else
1416 {
1417 x += 1;
1418 compute_sv (hsv, x, y, &sat, &val);
1419 }
1420 break;
1421
1422 default:
1423 /* we don't care about the tab directions */
1424 break;
1425 }
1426
1427 /* Wrap */
1428 if (hue < 0.0)
1429 hue = 1.0;
1430 else if (hue > 1.0)
1431 hue = 0.0;
1432
1433 mate_hsv_set_color (hsv, hue, sat, val);
1434}
1435
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-425c9c.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-425c9c.html new file mode 100644 index 0000000..eac5c9c --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-425c9c.html @@ -0,0 +1,4660 @@ + + + +mate-desktop-item.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-desktop-item.c
Warning:line 3129, column 9
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-desktop-item.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-desktop-item.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* mate-desktop-item.c - MATE Desktop File Representation
3
4 Copyright (C) 1999, 2000 Red Hat Inc.
5 Copyright (C) 2001 Sid Vicious
6 All rights reserved.
7
8 This file is part of the Mate Library.
9
10 Developed by Elliot Lee <sopwith@redhat.com> and Sid Vicious
11
12 The Mate Library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Library General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
16
17 The Mate Library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Library General Public License for more details.
21
22 You should have received a copy of the GNU Library General Public
23 License along with the Mate Library; see the file COPYING.LIB. If not,
24 write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 Boston, MA 02110-1301, USA. */
26/*
27 @NOTATION@
28 */
29
30#include "config.h"
31
32#include <limits.h>
33#include <ctype.h>
34#include <stdio.h>
35#include <glib.h>
36#include <sys/types.h>
37#include <dirent.h>
38#include <unistd.h>
39#include <time.h>
40#include <string.h>
41#include <glib/gi18n-lib.h>
42#include <locale.h>
43#include <stdlib.h>
44
45#include <gio/gio.h>
46
47#ifdef HAVE_STARTUP_NOTIFICATION
48#define SN_API_NOT_YET_FROZEN
49#include <libsn/sn.h>
50#include <gdk/gdk.h>
51#include <gdk/gdkx.h>
52#include <gtk/gtk.h>
53#endif
54
55#define MATE_DESKTOP_USE_UNSTABLE_API
56#undef MATE_DISABLE_DEPRECATED
57#include <mate-desktop-item.h>
58#include <mate-desktop-utils.h>
59
60#include "private.h"
61
62struct _MateDesktopItem {
63 int refcount;
64
65 /* all languages used */
66 GList *languages;
67
68 MateDesktopItemType type;
69
70 /* `modified' means that the ditem has been
71 * modified since the last save. */
72 gboolean modified;
73
74 /* Keys of the main section only */
75 GList *keys;
76
77 GList *sections;
78
79 /* This includes ALL keys, including
80 * other sections, separated by '/' */
81 GHashTable *main_hash;
82
83 char *location;
84
85 gint64 mtime;
86
87 guint32 launch_time;
88};
89
90/* If mtime is set to this, set_location won't update mtime,
91 * this is to be used internally only. */
92#define DONT_UPDATE_MTIME((gint64)-2) ((gint64)-2)
93
94typedef struct {
95 char *name;
96 GList *keys;
97} Section;
98
99typedef enum {
100 ENCODING_UNKNOWN,
101 ENCODING_UTF8,
102 ENCODING_LEGACY_MIXED
103} Encoding;
104
105/*
106 * IO reading utils, that look like the libc buffered io stuff
107 */
108
109#define READ_BUF_SIZE(32 * 1024) (32 * 1024)
110
111typedef struct {
112 GFile *file;
113 GFileInputStream *stream;
114 char *uri;
115 char *buf;
116 gboolean buf_needs_free;
117 gboolean past_first_read;
118 gboolean eof;
119 guint64 size;
120 gsize pos;
121} ReadBuf;
122
123static MateDesktopItem *ditem_load (ReadBuf *rb,
124 gboolean no_translations,
125 GError **error);
126static gboolean ditem_save (MateDesktopItem *item,
127 const char *uri,
128 GError **error);
129
130static void mate_desktop_item_set_location_gfile (MateDesktopItem *item,
131 GFile *file);
132
133static MateDesktopItem *mate_desktop_item_new_from_gfile (GFile *file,
134 MateDesktopItemLoadFlags flags,
135 GError **error);
136
137static int
138readbuf_getc (ReadBuf *rb)
139{
140 if (rb->eof)
141 return EOF(-1);
142
143 if (rb->size == 0 ||
144 rb->pos == rb->size) {
145 gssize bytes_read;
146
147 if (rb->stream == NULL((void*)0))
148 bytes_read = 0;
149 else
150 bytes_read = g_input_stream_read (G_INPUT_STREAM (rb->stream)((((GInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((rb->stream)), ((g_input_stream_get_type ()))))))
,
151 rb->buf,
152 READ_BUF_SIZE(32 * 1024),
153 NULL((void*)0), NULL((void*)0));
154
155 /* FIXME: handle errors other than EOF */
156 if (bytes_read <= 0) {
157 rb->eof = TRUE(!(0));
158 return EOF(-1);
159 }
160
161 if (rb->size != 0)
162 rb->past_first_read = TRUE(!(0));
163 rb->size = bytes_read;
164 rb->pos = 0;
165
166 }
167
168 return (guchar) rb->buf[rb->pos++];
169}
170
171/* Note, does not include the trailing \n */
172static char *
173readbuf_gets (char *buf, gsize bufsize, ReadBuf *rb)
174{
175 int c;
176 gsize pos;
177
178 g_return_val_if_fail (buf != NULL, NULL)do { if ((buf != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "buf != NULL"); return
(((void*)0)); } } while (0)
;
179 g_return_val_if_fail (rb != NULL, NULL)do { if ((rb != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "rb != NULL"); return
(((void*)0)); } } while (0)
;
180
181 pos = 0;
182 buf[0] = '\0';
183
184 do {
185 c = readbuf_getc (rb);
186 if (c == EOF(-1) || c == '\n')
187 break;
188 buf[pos++] = c;
189 } while (pos < bufsize-1);
190
191 if (c == EOF(-1) && pos == 0)
192 return NULL((void*)0);
193
194 buf[pos++] = '\0';
195
196 return buf;
197}
198
199static ReadBuf *
200readbuf_open (GFile *file, GError **error)
201{
202 GError *local_error;
203 GFileInputStream *stream;
204 char *uri;
205 ReadBuf *rb;
206
207 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
208
209 uri = g_file_get_uri (file);
210 local_error = NULL((void*)0);
211 stream = g_file_read (file, NULL((void*)0), &local_error);
212
213 if (stream == NULL((void*)0)) {
214 g_set_error (error,
215 /* FIXME: better errors */
216 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
217 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
218 _("Error reading file '%s': %s")((char *) g_dgettext ("mate-desktop", "Error reading file '%s': %s"
))
,
219 uri, local_error->message);
220 g_error_free (local_error);
221 g_free (uri);
222 return NULL((void*)0);
223 }
224
225 rb = g_new0 (ReadBuf, 1)((ReadBuf *) g_malloc0_n ((1), sizeof (ReadBuf)));
226 rb->stream = stream;
227 rb->file = g_file_dup (file);
228 rb->uri = uri;
229 rb->buf = g_malloc (READ_BUF_SIZE(32 * 1024));
230 rb->buf_needs_free = TRUE(!(0));
231 /* rb->past_first_read = FALSE; */
232 /* rb->eof = FALSE; */
233 /* rb->size = 0; */
234 /* rb->pos = 0; */
235
236 return rb;
237}
238
239static ReadBuf *
240readbuf_new_from_string (const char *uri, const char *string, gssize length)
241{
242 ReadBuf *rb;
243
244 g_return_val_if_fail (string != NULL, NULL)do { if ((string != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "string != NULL"
); return (((void*)0)); } } while (0)
;
245 g_return_val_if_fail (length >= 0, NULL)do { if ((length >= 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "length >= 0"
); return (((void*)0)); } } while (0)
;
246
247 rb = g_new0 (ReadBuf, 1)((ReadBuf *) g_malloc0_n ((1), sizeof (ReadBuf)));
248 /* rb->file = NULL; */
249 /* rb->stream = NULL; */
250 rb->uri = g_strdup (uri)g_strdup_inline (uri);
251 rb->buf = (char *) string;
252 /* rb->buf_needs_free = FALSE; */
253 /* rb->past_first_read = FALSE; */
254 /* rb->eof = FALSE; */
255 rb->size = length;
256 /* rb->pos = 0; */
257
258 return rb;
259}
260
261static gboolean
262readbuf_rewind (ReadBuf *rb, GError **error)
263{
264 GError *local_error;
265
266 rb->eof = FALSE(0);
267 rb->pos = 0;
268
269 if (!rb->past_first_read)
270 return TRUE(!(0));
271
272 rb->size = 0;
273
274 if (g_seekable_seek (G_SEEKABLE (rb->stream)((((GSeekable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((rb->stream)), ((g_seekable_get_type ()))))))
,
275 0, G_SEEK_SET, NULL((void*)0), NULL((void*)0)))
276 return TRUE(!(0));
277
278 g_object_unref (rb->stream);
279 local_error = NULL((void*)0);
280 rb->stream = g_file_read (rb->file, NULL((void*)0), &local_error);
281
282 if (rb->stream == NULL((void*)0)) {
283 g_set_error (
284 error, MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
285 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
286 _("Error rewinding file '%s': %s")((char *) g_dgettext ("mate-desktop", "Error rewinding file '%s': %s"
))
,
287 rb->uri, local_error->message);
288 g_error_free (local_error);
289
290 return FALSE(0);
291 }
292
293 return TRUE(!(0));
294}
295
296static void
297readbuf_close (ReadBuf *rb)
298{
299 if (rb->stream != NULL((void*)0))
300 g_object_unref (rb->stream);
301 if (rb->file != NULL((void*)0))
302 g_object_unref (rb->file);
303 g_free (rb->uri);
304 if (rb->buf_needs_free)
305 g_free (rb->buf);
306 g_free (rb);
307}
308
309static MateDesktopItemType
310type_from_string (const char *type)
311{
312 if (!type)
313 return MATE_DESKTOP_ITEM_TYPE_NULL;
314
315 switch (type [0]) {
316 case 'A':
317 if (!strcmp (type, "Application"))
318 return MATE_DESKTOP_ITEM_TYPE_APPLICATION;
319 break;
320 case 'L':
321 if (!strcmp (type, "Link"))
322 return MATE_DESKTOP_ITEM_TYPE_LINK;
323 break;
324 case 'F':
325 if (!strcmp (type, "FSDevice"))
326 return MATE_DESKTOP_ITEM_TYPE_FSDEVICE;
327 break;
328 case 'M':
329 if (!strcmp (type, "MimeType"))
330 return MATE_DESKTOP_ITEM_TYPE_MIME_TYPE;
331 break;
332 case 'D':
333 if (!strcmp (type, "Directory"))
334 return MATE_DESKTOP_ITEM_TYPE_DIRECTORY;
335 break;
336 case 'S':
337 if (!strcmp (type, "Service"))
338 return MATE_DESKTOP_ITEM_TYPE_SERVICE;
339
340 else if (!strcmp (type, "ServiceType"))
341 return MATE_DESKTOP_ITEM_TYPE_SERVICE_TYPE;
342 break;
343 default:
344 break;
345 }
346
347 return MATE_DESKTOP_ITEM_TYPE_OTHER;
348}
349
350/**
351 * mate_desktop_item_new:
352 *
353 * Creates a MateDesktopItem object. The reference count on the returned value is set to '1'.
354 *
355 * Returns: The new MateDesktopItem
356 */
357MateDesktopItem *
358mate_desktop_item_new (void)
359{
360 MateDesktopItem *retval;
361
362 _mate_desktop_init_i18n ();
363
364 retval = g_new0 (MateDesktopItem, 1)((MateDesktopItem *) g_malloc0_n ((1), sizeof (MateDesktopItem
)))
;
365
366 retval->refcount++;
367
368 retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
369 (GDestroyNotify) g_free,
370 (GDestroyNotify) g_free);
371
372 /* These are guaranteed to be set */
373 mate_desktop_item_set_string (retval,
374 MATE_DESKTOP_ITEM_NAME"Name",
375 /* Translators: the "name" mentioned
376 * here is the name of an application or
377 * a document */
378 _("No name")((char *) g_dgettext ("mate-desktop", "No name")));
379 mate_desktop_item_set_string (retval,
380 MATE_DESKTOP_ITEM_ENCODING"Encoding",
381 "UTF-8");
382 mate_desktop_item_set_string (retval,
383 MATE_DESKTOP_ITEM_VERSION"Version",
384 "1.0");
385
386 retval->launch_time = 0;
387
388 return retval;
389}
390
391static Section *
392dup_section (Section *sec)
393{
394 GList *li;
395 Section *retval = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
396
397 retval->name = g_strdup (sec->name)g_strdup_inline (sec->name);
398
399 retval->keys = g_list_copy (sec->keys);
400 for (li = retval->keys; li != NULL((void*)0); li = li->next)
401 li->data = g_strdup (li->data)g_strdup_inline (li->data);
402
403 return retval;
404}
405
406static void
407copy_string_hash (gpointer key, gpointer value, gpointer user_data)
408{
409 GHashTable *copy = user_data;
410 g_hash_table_replace (copy,
411 g_strdup (key)g_strdup_inline (key),
412 g_strdup (value)g_strdup_inline (value));
413}
414
415/**
416 * mate_desktop_item_copy:
417 * @item: The item to be copied
418 *
419 * Creates a copy of a MateDesktopItem. The new copy has a refcount of 1.
420 * Note: Section stack is NOT copied.
421 *
422 * Returns: The new copy
423 */
424MateDesktopItem *
425mate_desktop_item_copy (const MateDesktopItem *item)
426{
427 GList *li;
428 MateDesktopItem *retval;
429
430 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
431 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
432
433 retval = mate_desktop_item_new ();
434
435 retval->type = item->type;
436 retval->modified = item->modified;
437 retval->location = g_strdup (item->location)g_strdup_inline (item->location);
438 retval->mtime = item->mtime;
439 retval->launch_time = item->launch_time;
440
441 /* Languages */
442 retval->languages = g_list_copy (item->languages);
443 for (li = retval->languages; li != NULL((void*)0); li = li->next)
444 li->data = g_strdup (li->data)g_strdup_inline (li->data);
445
446 /* Keys */
447 retval->keys = g_list_copy (item->keys);
448 for (li = retval->keys; li != NULL((void*)0); li = li->next)
449 li->data = g_strdup (li->data)g_strdup_inline (li->data);
450
451 /* Sections */
452 retval->sections = g_list_copy (item->sections);
453 for (li = retval->sections; li != NULL((void*)0); li = li->next)
454 li->data = dup_section (li->data);
455
456 retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
457 (GDestroyNotify) g_free,
458 (GDestroyNotify) g_free);
459
460 g_hash_table_foreach (item->main_hash,
461 copy_string_hash,
462 retval->main_hash);
463
464 return retval;
465}
466
467static void
468read_sort_order (MateDesktopItem *item, GFile *dir)
469{
470 GFile *child;
471 char buf[BUFSIZ8192];
472 GString *str;
473 ReadBuf *rb;
474
475 child = g_file_get_child (dir, ".order");
476
477 rb = readbuf_open (child, NULL((void*)0));
478 g_object_unref (child);
479
480 if (rb == NULL((void*)0))
481 return;
482
483 str = NULL((void*)0);
484 while (readbuf_gets (buf, sizeof (buf), rb) != NULL((void*)0)) {
485 if (str == NULL((void*)0))
486 str = g_string_new (buf);
487 else
488 g_string_append (str, buf)(__builtin_constant_p (buf) ? __extension__ ({ const char * const
__val = (buf); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, buf, (gssize) -1
))
;
489 g_string_append_c (str, ';')g_string_append_c_inline (str, ';');
490 }
491 readbuf_close (rb);
492 if (str != NULL((void*)0)) {
493 mate_desktop_item_set_string (item, MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder",
494 str->str);
495 g_string_free (str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(str), ((!(0)))) : g_string_free_and_steal (str)) : (g_string_free
) ((str), ((!(0)))))
;
496 }
497}
498
499static MateDesktopItem *
500make_fake_directory (GFile *dir)
501{
502 MateDesktopItem *item;
503 GFile *child;
504
505 item = mate_desktop_item_new ();
506 mate_desktop_item_set_entry_type (item,
507 MATE_DESKTOP_ITEM_TYPE_DIRECTORY);
508
509 item->mtime = DONT_UPDATE_MTIME((gint64)-2); /* it doesn't exist, we know that */
510 child = g_file_get_child (dir, ".directory");
511 mate_desktop_item_set_location_gfile (item, child);
512 item->mtime = 0;
513 g_object_unref (child);
514
515 read_sort_order (item, dir);
516
517 return item;
518}
519
520/**
521 * mate_desktop_item_new_from_file:
522 * @file: The filename or directory path to load the MateDesktopItem from
523 * @flags: Flags to influence the loading process
524 *
525 * This function loads 'file' and turns it into a MateDesktopItem.
526 *
527 * Returns: The newly loaded item.
528 */
529MateDesktopItem *
530mate_desktop_item_new_from_file (const char *file,
531 MateDesktopItemLoadFlags flags,
532 GError **error)
533{
534 MateDesktopItem *retval;
535 GFile *gfile;
536
537 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
538
539 gfile = g_file_new_for_path (file);
540 retval = mate_desktop_item_new_from_gfile (gfile, flags, error);
541 g_object_unref (gfile);
542
543 return retval;
544}
545
546/**
547 * mate_desktop_item_new_from_uri:
548 * @uri: URI to load the MateDesktopItem from
549 * @flags: Flags to influence the loading process
550 *
551 * This function loads 'uri' and turns it into a MateDesktopItem.
552 *
553 * Returns: The newly loaded item.
554 */
555MateDesktopItem *
556mate_desktop_item_new_from_uri (const char *uri,
557 MateDesktopItemLoadFlags flags,
558 GError **error)
559{
560 MateDesktopItem *retval;
561 GFile *file;
562
563 g_return_val_if_fail (uri != NULL, NULL)do { if ((uri != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "uri != NULL"); return
(((void*)0)); } } while (0)
;
564
565 file = g_file_new_for_uri (uri);
566 retval = mate_desktop_item_new_from_gfile (file, flags, error);
567 g_object_unref (file);
568
569 return retval;
570}
571
572static MateDesktopItem *
573mate_desktop_item_new_from_gfile (GFile *file,
574 MateDesktopItemLoadFlags flags,
575 GError **error)
576{
577 MateDesktopItem *retval;
578 GFile *subfn;
579 GFileInfo *info;
580 GFileType type;
581 GFile *parent;
582 gint64 mtime = 0;
583 ReadBuf *rb;
584
585 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
586
587 info = g_file_query_info (file,
588 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type"","G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
589 G_FILE_QUERY_INFO_NONE, NULL((void*)0), error);
590 if (info == NULL((void*)0))
591 return NULL((void*)0);
592
593 type = g_file_info_get_file_type (info);
594
595 if (type != G_FILE_TYPE_REGULAR && type != G_FILE_TYPE_DIRECTORY) {
596 char *uri;
597
598 uri = g_file_get_uri (file);
599 g_set_error (error,
600 /* FIXME: better errors */
601 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
602 MATE_DESKTOP_ITEM_ERROR_INVALID_TYPE,
603 _("File '%s' is not a regular file or directory.")((char *) g_dgettext ("mate-desktop", "File '%s' is not a regular file or directory."
))
,
604 uri);
605
606 g_free (uri);
607 g_object_unref (info);
608
609 return NULL((void*)0);
610 }
611
612 mtime = g_file_info_get_attribute_uint64 (info,
613 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
614
615 g_object_unref (info);
616
617 if (type == G_FILE_TYPE_DIRECTORY) {
618 GFile *child;
619 GFileInfo *child_info;
620
621 child = g_file_get_child (file, ".directory");
622 child_info = g_file_query_info (child,
623 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
624 G_FILE_QUERY_INFO_NONE,
625 NULL((void*)0), NULL((void*)0));
626
627 if (child_info == NULL((void*)0)) {
628 g_object_unref (child);
629
630 if (flags & MATE_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS) {
631 return NULL((void*)0);
632 } else {
633 return make_fake_directory (file);
634 }
635 }
636
637 mtime = g_file_info_get_attribute_uint64 (child_info,
638 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
639 g_object_unref (child_info);
640
641 subfn = child;
642 } else {
643 subfn = g_file_dup (file);
644 }
645
646 rb = readbuf_open (subfn, error);
647
648 if (rb == NULL((void*)0)) {
649 g_object_unref (subfn);
650 return NULL((void*)0);
651 }
652
653 retval = ditem_load (rb,
654 (flags & MATE_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS) != 0,
655 error);
656
657 if (retval == NULL((void*)0)) {
658 g_object_unref (subfn);
659 return NULL((void*)0);
660 }
661
662 if (flags & MATE_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS &&
663 ! mate_desktop_item_exists (retval)) {
664 mate_desktop_item_unref (retval);
665 g_object_unref (subfn);
666 return NULL((void*)0);
667 }
668
669 retval->mtime = DONT_UPDATE_MTIME((gint64)-2);
670 mate_desktop_item_set_location_gfile (retval, subfn);
671 retval->mtime = mtime;
672
673 parent = g_file_get_parent (file);
674 if (parent != NULL((void*)0)) {
675 read_sort_order (retval, parent);
676 g_object_unref (parent);
677 }
678
679 g_object_unref (subfn);
680
681 return retval;
682}
683
684/**
685 * mate_desktop_item_new_from_string:
686 * @string: string to load the MateDesktopItem from
687 * @length: length of string, or -1 to use strlen
688 * @flags: Flags to influence the loading process
689 * @error: place to put errors
690 *
691 * This function turns the contents of the string into a MateDesktopItem.
692 *
693 * Returns: The newly loaded item.
694 */
695MateDesktopItem *
696mate_desktop_item_new_from_string (const char *uri,
697 const char *string,
698 gssize length,
699 MateDesktopItemLoadFlags flags,
700 GError **error)
701{
702 MateDesktopItem *retval;
703 ReadBuf *rb;
704
705 g_return_val_if_fail (string != NULL, NULL)do { if ((string != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "string != NULL"
); return (((void*)0)); } } while (0)
;
706 g_return_val_if_fail (length >= -1, NULL)do { if ((length >= -1)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "length >= -1"
); return (((void*)0)); } } while (0)
;
707
708 if (length == -1) {
709 length = strlen (string);
710 }
711
712 rb = readbuf_new_from_string (uri, string, length);
713
714 retval = ditem_load (rb,
715 (flags & MATE_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS) != 0,
716 error);
717
718 if (retval == NULL((void*)0)) {
719 return NULL((void*)0);
720 }
721
722 /* FIXME: Sort order? */
723
724 return retval;
725}
726
727static char *
728lookup_desktop_file_in_data_dir (const char *desktop_file,
729 const char *data_dir)
730{
731 char *path;
732
733 path = g_build_filename (data_dir, "applications", desktop_file, NULL((void*)0));
734 if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
735 g_free (path);
736 return NULL((void*)0);
737 }
738 return path;
739}
740
741static char *
742file_from_basename (const char *basename)
743{
744 const char * const *system_data_dirs;
745 const char *user_data_dir;
746 char *retval;
747 int i;
748
749 user_data_dir = g_get_user_data_dir ();
750 system_data_dirs = g_get_system_data_dirs ();
751
752 if ((retval = lookup_desktop_file_in_data_dir (basename, user_data_dir))) {
753 return retval;
754 }
755 for (i = 0; system_data_dirs[i]; i++) {
756 if ((retval = lookup_desktop_file_in_data_dir (basename, system_data_dirs[i]))) {
757 return retval;
758 }
759 }
760 return NULL((void*)0);
761}
762
763/**
764 * mate_desktop_item_new_from_basename:
765 * @basename: The basename of the MateDesktopItem to load.
766 * @flags: Flags to influence the loading process
767 *
768 * This function loads 'basename' from a system data directory and
769 * returns its MateDesktopItem.
770 *
771 * Returns: The newly loaded item.
772 */
773MateDesktopItem *
774mate_desktop_item_new_from_basename (const char *basename,
775 MateDesktopItemLoadFlags flags,
776 GError **error)
777{
778 MateDesktopItem *retval;
779 char *file;
780
781 g_return_val_if_fail (basename != NULL, NULL)do { if ((basename != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "basename != NULL"
); return (((void*)0)); } } while (0)
;
782
783 if (!(file = file_from_basename (basename))) {
784 g_set_error (error,
785 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
786 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
787 _("Cannot find file '%s'")((char *) g_dgettext ("mate-desktop", "Cannot find file '%s'"
))
,
788 basename);
789 return NULL((void*)0);
790 }
791
792 retval = mate_desktop_item_new_from_file (file, flags, error);
793 g_free (file);
794
795 return retval;
796}
797
798/**
799 * mate_desktop_item_save:
800 * @item: A desktop item
801 * @under: A new uri (location) for this #MateDesktopItem
802 * @force: Save even if it wasn't modified
803 * @error: #GError return
804 *
805 * Writes the specified item to disk. If the 'under' is NULL, the original
806 * location is used. It sets the location of this entry to point to the
807 * new location.
808 *
809 * Returns: boolean. %TRUE if the file was saved, %FALSE otherwise
810 */
811gboolean
812mate_desktop_item_save (MateDesktopItem *item,
813 const char *under,
814 gboolean force,
815 GError **error)
816{
817 const char *uri;
818
819 if (under == NULL((void*)0) &&
1
Assuming 'under' is not equal to NULL
820 ! force &&
821 ! item->modified)
822 return TRUE(!(0));
823
824 if (under
1.1
'under' is not equal to NULL
== NULL((void*)0))
2
Taking false branch
825 uri = item->location;
826 else
827 uri = under;
828
829 if (uri
2.1
'uri' is not equal to NULL
== NULL((void*)0)) {
3
Taking false branch
830 g_set_error (error,
831 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
832 MATE_DESKTOP_ITEM_ERROR_NO_FILENAME,
833 _("No filename to save to")((char *) g_dgettext ("mate-desktop", "No filename to save to"
))
);
834 return FALSE(0);
835 }
836
837 if ( ! ditem_save (item, uri, error))
4
Calling 'ditem_save'
838 return FALSE(0);
839
840 item->modified = FALSE(0);
841 item->mtime = g_get_real_time () / G_USEC_PER_SEC1000000;
842
843 return TRUE(!(0));
844}
845
846/**
847 * mate_desktop_item_ref:
848 * @item: A desktop item
849 *
850 * Description: Increases the reference count of the specified item.
851 *
852 * Returns: the newly referenced @item
853 */
854MateDesktopItem *
855mate_desktop_item_ref (MateDesktopItem *item)
856{
857 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
858
859 item->refcount++;
860
861 return item;
862}
863
864static void
865free_section (gpointer data)
866{
867 Section *section = data;
868
869 g_free (section->name);
870 section->name = NULL((void*)0);
871
872 g_list_free_full (section->keys, g_free);
873 section->keys = NULL((void*)0);
874
875 g_free (section);
876}
877
878/**
879 * mate_desktop_item_unref:
880 * @item: A desktop item
881 *
882 * Decreases the reference count of the specified item, and destroys the item if there are no more references left.
883 */
884void
885mate_desktop_item_unref (MateDesktopItem *item)
886{
887 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
888 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
889
890 item->refcount--;
891
892 if(item->refcount != 0)
893 return;
894
895 g_list_free_full (item->languages, g_free);
896 item->languages = NULL((void*)0);
897
898 g_list_free_full (item->keys, g_free);
899 item->keys = NULL((void*)0);
900
901 g_list_free_full (item->sections, (GDestroyNotify) free_section);
902 item->sections = NULL((void*)0);
903
904 g_hash_table_destroy (item->main_hash);
905 item->main_hash = NULL((void*)0);
906
907 g_free (item->location);
908 item->location = NULL((void*)0);
909
910 g_free (item);
911}
912
913static Section *
914find_section (MateDesktopItem *item, const char *section)
915{
916 GList *li;
917 Section *sec;
918
919 if (section == NULL((void*)0))
920 return NULL((void*)0);
921 if (strcmp (section, "Desktop Entry") == 0)
922 return NULL((void*)0);
923
924 for (li = item->sections; li != NULL((void*)0); li = li->next) {
925 sec = li->data;
926 if (strcmp (sec->name, section) == 0)
927 return sec;
928 }
929
930 sec = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
931 sec->name = g_strdup (section)g_strdup_inline (section);
932 sec->keys = NULL((void*)0);
933
934 item->sections = g_list_append (item->sections, sec);
935
936 /* Don't mark the item modified, this is just an empty section,
937 * it won't be saved even */
938
939 return sec;
940}
941
942static Section *
943section_from_key (MateDesktopItem *item, const char *key)
944{
945 char *p;
946 char *name;
947 Section *sec;
948
949 if (key == NULL((void*)0))
950 return NULL((void*)0);
951
952 p = strchr (key, '/');
953 if (p == NULL((void*)0))
954 return NULL((void*)0);
955
956 name = g_strndup (key, p - key);
957
958 sec = find_section (item, name);
959
960 g_free (name);
961
962 return sec;
963}
964
965static const char *
966key_basename (const char *key)
967{
968 char *p = strrchr (key, '/');
969 if (p != NULL((void*)0))
970 return p+1;
971 else
972 return key;
973}
974
975static const char *
976lookup (const MateDesktopItem *item, const char *key)
977{
978 return g_hash_table_lookup (item->main_hash, key);
979}
980
981static const char *
982lookup_locale (const MateDesktopItem *item, const char *key, const char *locale)
983{
984 if (locale == NULL((void*)0) ||
985 strcmp (locale, "C") == 0) {
986 return lookup (item, key);
987 } else {
988 const char *ret;
989 char *full = g_strdup_printf ("%s[%s]", key, locale);
990 ret = lookup (item, full);
991 g_free (full);
992 return ret;
993 }
994}
995
996static const char *
997lookup_best_locale (const MateDesktopItem *item, const char *key)
998{
999 const char * const *langs_pointer;
1000 int i;
1001
1002 langs_pointer = g_get_language_names ();
1003 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
1004 const char *ret = NULL((void*)0);
1005
1006 ret = lookup_locale (item, key, langs_pointer[i]);
1007 if (ret != NULL((void*)0))
1008 return ret;
1009 }
1010
1011 return NULL((void*)0);
1012}
1013
1014static void
1015set (MateDesktopItem *item, const char *key, const char *value)
1016{
1017 Section *sec = section_from_key (item, key);
1018
1019 if (sec != NULL((void*)0)) {
1020 if (value != NULL((void*)0)) {
1021 if (g_hash_table_lookup (item->main_hash, key) == NULL((void*)0))
1022 sec->keys = g_list_append
1023 (sec->keys,
1024 g_strdup (key_basename (key))g_strdup_inline (key_basename (key)));
1025
1026 g_hash_table_replace (item->main_hash,
1027 g_strdup (key)g_strdup_inline (key),
1028 g_strdup (value)g_strdup_inline (value));
1029 } else {
1030 GList *list = g_list_find_custom
1031 (sec->keys, key_basename (key),
1032 (GCompareFunc)strcmp);
1033 if (list != NULL((void*)0)) {
1034 g_free (list->data);
1035 sec->keys =
1036 g_list_delete_link (sec->keys, list);
1037 }
1038 g_hash_table_remove (item->main_hash, key);
1039 }
1040 } else {
1041 if (value != NULL((void*)0)) {
1042 if (g_hash_table_lookup (item->main_hash, key) == NULL((void*)0))
1043 item->keys = g_list_append (item->keys,
1044 g_strdup (key)g_strdup_inline (key));
1045
1046 g_hash_table_replace (item->main_hash,
1047 g_strdup (key)g_strdup_inline (key),
1048 g_strdup (value)g_strdup_inline (value));
1049 } else {
1050 GList *list = g_list_find_custom
1051 (item->keys, key, (GCompareFunc)strcmp);
1052 if (list != NULL((void*)0)) {
1053 g_free (list->data);
1054 item->keys =
1055 g_list_delete_link (item->keys, list);
1056 }
1057 g_hash_table_remove (item->main_hash, key);
1058 }
1059 }
1060 item->modified = TRUE(!(0));
1061}
1062
1063static void
1064set_locale (MateDesktopItem *item, const char *key,
1065 const char *locale, const char *value)
1066{
1067 if (locale == NULL((void*)0) ||
1068 strcmp (locale, "C") == 0) {
1069 set (item, key, value);
1070 } else {
1071 char *full = g_strdup_printf ("%s[%s]", key, locale);
1072 set (item, full, value);
1073 g_free (full);
1074
1075 /* add the locale to the list of languages if it wasn't there
1076 * before */
1077 if (g_list_find_custom (item->languages, locale,
1078 (GCompareFunc)strcmp) == NULL((void*)0))
1079 item->languages = g_list_prepend (item->languages,
1080 g_strdup (locale)g_strdup_inline (locale));
1081 }
1082}
1083
1084static char **
1085list_to_vector (GSList *list)
1086{
1087 int len = g_slist_length (list);
1088 char **argv;
1089 int i;
1090 GSList *li;
1091
1092 argv = g_new0 (char *, len+1)((char * *) g_malloc0_n ((len+1), sizeof (char *)));
1093
1094 for (i = 0, li = list;
1095 li != NULL((void*)0);
1096 li = li->next, i++) {
1097 argv[i] = g_strdup (li->data)g_strdup_inline (li->data);
1098 }
1099 argv[i] = NULL((void*)0);
1100
1101 return argv;
1102}
1103
1104static GSList *
1105make_args (GList *files)
1106{
1107 GSList *list = NULL((void*)0);
1108 GList *li;
1109
1110 for (li = files; li != NULL((void*)0); li = li->next) {
1111 GFile *gfile;
1112 const char *file = li->data;
1113 if (file == NULL((void*)0))
1114 continue;
1115 gfile = g_file_new_for_uri (file);
1116 list = g_slist_prepend (list, gfile);
1117 }
1118
1119 return g_slist_reverse (list);
1120}
1121
1122static void
1123free_args (GSList *list)
1124{
1125 GSList *li;
1126
1127 for (li = list; li != NULL((void*)0); li = li->next) {
1128 g_object_unref (G_FILE (li->data)((((GFile*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((li->data)), ((g_file_get_type ()))))))
);
1129 li->data = NULL((void*)0);
1130 }
1131 g_slist_free (list);
1132}
1133
1134static char *
1135escape_single_quotes (const char *s,
1136 gboolean in_single_quotes,
1137 gboolean in_double_quotes)
1138{
1139 const char *p;
1140 GString *gs;
1141 const char *pre = "";
1142 const char *post = "";
1143
1144 if ( ! in_single_quotes && ! in_double_quotes) {
1145 pre = "'";
1146 post = "'";
1147 } else if ( ! in_single_quotes && in_double_quotes) {
1148 pre = "\"'";
1149 post = "'\"";
1150 }
1151
1152 if (strchr (s, '\'') == NULL((void*)0)) {
1153 return g_strconcat (pre, s, post, NULL((void*)0));
1154 }
1155
1156 gs = g_string_new (pre);
1157
1158 for (p = s; *p != '\0'; p++) {
1159 if (*p == '\'')
1160 g_string_append (gs, "'\\''")(__builtin_constant_p ("'\\''") ? __extension__ ({ const char
* const __val = ("'\\''"); g_string_append_len_inline (gs, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (gs, "'\\''"
, (gssize) -1))
;
1161 else
1162 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1163 }
1164
1165 g_string_append (gs, post)(__builtin_constant_p (post) ? __extension__ ({ const char * const
__val = (post); g_string_append_len_inline (gs, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (gs, post, (gssize) -1
))
;
1166
1167 return g_string_free (gs, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((gs),
((0))) : g_string_free_and_steal (gs)) : (g_string_free) ((gs
), ((0))))
;
1168}
1169
1170typedef enum {
1171 URI_TO_STRING,
1172 URI_TO_LOCAL_PATH,
1173 URI_TO_LOCAL_DIRNAME,
1174 URI_TO_LOCAL_BASENAME
1175} ConversionType;
1176
1177static char *
1178convert_uri (GFile *file,
1179 ConversionType conversion)
1180{
1181 char *retval = NULL((void*)0);
1182
1183 switch (conversion) {
1184 case URI_TO_STRING:
1185 retval = g_file_get_uri (file);
1186 break;
1187 case URI_TO_LOCAL_PATH:
1188 retval = g_file_get_path (file);
1189 break;
1190 case URI_TO_LOCAL_DIRNAME:
1191 {
1192 char *local_path;
1193
1194 local_path = g_file_get_path (file);
1195 retval = g_path_get_dirname (local_path);
1196 g_free (local_path);
1197 }
1198 break;
1199 case URI_TO_LOCAL_BASENAME:
1200 retval = g_file_get_basename (file);
1201 break;
1202 default:
1203 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-desktop-item.c"
, 1203, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1204 }
1205
1206 return retval;
1207}
1208
1209typedef enum {
1210 ADDED_NONE = 0,
1211 ADDED_SINGLE,
1212 ADDED_ALL
1213} AddedStatus;
1214
1215static AddedStatus
1216append_all_converted (GString *str,
1217 ConversionType conversion,
1218 GSList *args,
1219 gboolean in_single_quotes,
1220 gboolean in_double_quotes,
1221 AddedStatus added_status)
1222{
1223 GSList *l;
1224
1225 for (l = args; l; l = l->next) {
1226 char *converted;
1227 char *escaped;
1228
1229 if (!(converted = convert_uri (l->data, conversion)))
1230 continue;
1231
1232 g_string_append (str, " ")(__builtin_constant_p (" ") ? __extension__ ({ const char * const
__val = (" "); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, " ", (gssize) -1
))
;
1233
1234 escaped = escape_single_quotes (converted,
1235 in_single_quotes,
1236 in_double_quotes);
1237 g_string_append (str, escaped)(__builtin_constant_p (escaped) ? __extension__ ({ const char
* const __val = (escaped); g_string_append_len_inline (str, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (str, escaped
, (gssize) -1))
;
1238
1239 g_free (escaped);
1240 g_free (converted);
1241 }
1242
1243 return ADDED_ALL;
1244}
1245
1246static AddedStatus
1247append_first_converted (GString *str,
1248 ConversionType conversion,
1249 GSList **arg_ptr,
1250 gboolean in_single_quotes,
1251 gboolean in_double_quotes,
1252 AddedStatus added_status)
1253{
1254 GSList *l;
1255 char *converted = NULL((void*)0);
1256 char *escaped;
1257
1258 for (l = *arg_ptr; l; l = l->next) {
1259 if ((converted = convert_uri (l->data, conversion)))
1260 break;
1261
1262 *arg_ptr = l->next;
1263 }
1264
1265 if (!converted)
1266 return added_status;
1267
1268 escaped = escape_single_quotes (converted, in_single_quotes, in_double_quotes);
1269 g_string_append (str, escaped)(__builtin_constant_p (escaped) ? __extension__ ({ const char
* const __val = (escaped); g_string_append_len_inline (str, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (str, escaped
, (gssize) -1))
;
1270 g_free (escaped);
1271 g_free (converted);
1272
1273 return added_status != ADDED_ALL ? ADDED_SINGLE : added_status;
1274}
1275
1276static gboolean
1277do_percent_subst (const MateDesktopItem *item,
1278 const char *arg,
1279 GString *str,
1280 gboolean in_single_quotes,
1281 gboolean in_double_quotes,
1282 GSList *args,
1283 GSList **arg_ptr,
1284 AddedStatus *added_status)
1285{
1286 char *esc;
1287 const char *cs;
1288
1289 if (arg[0] != '%' || arg[1] == '\0') {
1290 return FALSE(0);
1291 }
1292
1293 switch (arg[1]) {
1294 case '%':
1295 g_string_append_c (str, '%')g_string_append_c_inline (str, '%');
1296 break;
1297 case 'U':
1298 *added_status = append_all_converted (str,
1299 URI_TO_STRING,
1300 args,
1301 in_single_quotes,
1302 in_double_quotes,
1303 *added_status);
1304 break;
1305 case 'F':
1306 *added_status = append_all_converted (str,
1307 URI_TO_LOCAL_PATH,
1308 args,
1309 in_single_quotes,
1310 in_double_quotes,
1311 *added_status);
1312 break;
1313 case 'N':
1314 *added_status = append_all_converted (str,
1315 URI_TO_LOCAL_BASENAME,
1316 args,
1317 in_single_quotes,
1318 in_double_quotes,
1319 *added_status);
1320 break;
1321 case 'D':
1322 *added_status = append_all_converted (str,
1323 URI_TO_LOCAL_DIRNAME,
1324 args,
1325 in_single_quotes,
1326 in_double_quotes,
1327 *added_status);
1328 break;
1329 case 'f':
1330 *added_status = append_first_converted (str,
1331 URI_TO_LOCAL_PATH,
1332 arg_ptr,
1333 in_single_quotes,
1334 in_double_quotes,
1335 *added_status);
1336 break;
1337 case 'u':
1338 *added_status = append_first_converted (str,
1339 URI_TO_STRING,
1340 arg_ptr,
1341 in_single_quotes,
1342 in_double_quotes,
1343 *added_status);
1344 break;
1345 case 'd':
1346 *added_status = append_first_converted (str,
1347 URI_TO_LOCAL_DIRNAME,
1348 arg_ptr,
1349 in_single_quotes,
1350 in_double_quotes,
1351 *added_status);
1352 break;
1353 case 'n':
1354 *added_status = append_first_converted (str,
1355 URI_TO_LOCAL_BASENAME,
1356 arg_ptr,
1357 in_single_quotes,
1358 in_double_quotes,
1359 *added_status);
1360 break;
1361 case 'm':
1362 /* Note: v0.9.4 of the spec says this is deprecated
1363 * and replace with --miniicon iconname */
1364 cs = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_MINI_ICON"MiniIcon");
1365 if (cs != NULL((void*)0)) {
1366 g_string_append (str, "--miniicon=")(__builtin_constant_p ("--miniicon=") ? __extension__ ({ const
char * const __val = ("--miniicon="); g_string_append_len_inline
(str, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(str, "--miniicon=", (gssize) -1))
;
1367 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1368 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1369 }
1370 break;
1371 case 'i':
1372 /* Note: v0.9.4 of the spec says replace with --icon iconname */
1373 cs = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_ICON"Icon");
1374 if (cs != NULL((void*)0)) {
1375 g_string_append (str, "--icon=")(__builtin_constant_p ("--icon=") ? __extension__ ({ const char
* const __val = ("--icon="); g_string_append_len_inline (str
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (str
, "--icon=", (gssize) -1))
;
1376 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1377 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1378 }
1379 break;
1380 case 'c':
1381 cs = mate_desktop_item_get_localestring (item, MATE_DESKTOP_ITEM_NAME"Name");
1382 if (cs != NULL((void*)0)) {
1383 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1384 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1385 g_free (esc);
1386 }
1387 break;
1388 case 'k':
1389 if (item->location != NULL((void*)0)) {
1390 esc = escape_single_quotes (item->location, in_single_quotes, in_double_quotes);
1391 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1392 g_free (esc);
1393 }
1394 break;
1395 case 'v':
1396 cs = mate_desktop_item_get_localestring (item, MATE_DESKTOP_ITEM_DEV"Dev");
1397 if (cs != NULL((void*)0)) {
1398 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1399 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1400 g_free (esc);
1401 }
1402 break;
1403 default:
1404 /* Maintain special characters - e.g. "%20" */
1405 if (g_ascii_isdigit (arg [1])((g_ascii_table[(guchar) (arg [1])] & G_ASCII_DIGIT) != 0
)
)
1406 g_string_append_c (str, '%')g_string_append_c_inline (str, '%');
1407 return FALSE(0);
1408 }
1409
1410 return TRUE(!(0));
1411}
1412
1413static char *
1414expand_string (const MateDesktopItem *item,
1415 const char *s,
1416 GSList *args,
1417 GSList **arg_ptr,
1418 AddedStatus *added_status)
1419{
1420 const char *p;
1421 gboolean escape = FALSE(0);
1422 gboolean single_quot = FALSE(0);
1423 gboolean double_quot = FALSE(0);
1424 GString *gs = g_string_new (NULL((void*)0));
1425
1426 for (p = s; *p != '\0'; p++) {
1427 if (escape) {
1428 escape = FALSE(0);
1429 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1430 } else if (*p == '\\') {
1431 if ( ! single_quot)
1432 escape = TRUE(!(0));
1433 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1434 } else if (*p == '\'') {
1435 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1436 if ( ! single_quot && ! double_quot) {
1437 single_quot = TRUE(!(0));
1438 } else if (single_quot) {
1439 single_quot = FALSE(0);
1440 }
1441 } else if (*p == '"') {
1442 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1443 if ( ! single_quot && ! double_quot) {
1444 double_quot = TRUE(!(0));
1445 } else if (double_quot) {
1446 double_quot = FALSE(0);
1447 }
1448 } else if (*p == '%') {
1449 if (do_percent_subst (item, p, gs,
1450 single_quot, double_quot,
1451 args, arg_ptr,
1452 added_status)) {
1453 p++;
1454 }
1455 } else {
1456 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1457 }
1458 }
1459 return g_string_free (gs, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((gs),
((0))) : g_string_free_and_steal (gs)) : (g_string_free) ((gs
), ((0))))
;
1460}
1461
1462/*Functions in this code block should only ever be reached in x11*/
1463#ifdef HAVE_STARTUP_NOTIFICATION
1464static void
1465sn_error_trap_push (SnDisplay *display,
1466 Display *xdisplay)
1467{
1468 GdkDisplay *gdkdisplay;
1469
1470 gdkdisplay = gdk_display_get_default ();
1471 gdk_x11_display_error_trap_push (gdkdisplay);
1472}
1473
1474static void
1475sn_error_trap_pop (SnDisplay *display,
1476 Display *xdisplay)
1477{
1478 GdkDisplay *gdkdisplay;
1479
1480 gdkdisplay = gdk_display_get_default ();
1481 gdk_x11_display_error_trap_pop_ignored (gdkdisplay);
1482}
1483
1484static char **
1485make_spawn_environment_for_sn_context (SnLauncherContext *sn_context,
1486 char **envp)
1487{
1488 char **retval;
1489 char **freeme;
1490 int i, j;
1491 int desktop_startup_id_len;
1492
1493 retval = freeme = NULL((void*)0);
1494
1495 if (envp == NULL((void*)0)) {
1496 envp = freeme = g_listenv ();
1497 for (i = 0; envp[i]; i++) {
1498 char *name = envp[i];
1499
1500 envp[i] = g_strjoin ("=", name, g_getenv (name), NULL((void*)0));
1501 g_free (name);
1502 }
1503 } else {
1504 for (i = 0; envp[i]; i++)
1505 ;
1506 }
1507
1508 retval = g_new (char *, i + 2)((char * *) g_malloc_n ((i + 2), sizeof (char *)));
1509
1510 desktop_startup_id_len = strlen ("DESKTOP_STARTUP_ID");
1511
1512 for (i = 0, j = 0; envp[i]; i++) {
1513 if (strncmp (envp[i], "DESKTOP_STARTUP_ID", desktop_startup_id_len) != 0) {
1514 retval[j] = g_strdup (envp[i])g_strdup_inline (envp[i]);
1515 ++j;
1516 }
1517 }
1518
1519 retval[j] = g_strdup_printf ("DESKTOP_STARTUP_ID=%s",
1520 sn_launcher_context_get_startup_id (sn_context));
1521 ++j;
1522 retval[j] = NULL((void*)0);
1523
1524 g_strfreev (freeme);
1525
1526 return retval;
1527}
1528
1529/* This should be fairly long, as it's confusing to users if a startup
1530 * ends when it shouldn't (it appears that the startup failed, and
1531 * they have to relaunch the app). Also the timeout only matters when
1532 * there are bugs and apps don't end their own startup sequence.
1533 *
1534 * This timeout is a "last resort" timeout that ignores whether the
1535 * startup sequence has shown activity or not. Marco and the
1536 * tasklist have smarter, and correspondingly able-to-be-shorter
1537 * timeouts. The reason our timeout is dumb is that we don't monitor
1538 * the sequence (don't use an SnMonitorContext)
1539 */
1540#define STARTUP_TIMEOUT_LENGTH_SEC30 30 /* seconds */
1541#define STARTUP_TIMEOUT_LENGTH(30 * 1000) (STARTUP_TIMEOUT_LENGTH_SEC30 * 1000)
1542
1543typedef struct
1544{
1545 GdkScreen *screen;
1546 GSList *contexts;
1547 guint timeout_id;
1548} StartupTimeoutData;
1549
1550static void
1551free_startup_timeout (void *data)
1552{
1553 StartupTimeoutData *std = data;
1554
1555 g_slist_free_full (std->contexts, (GDestroyNotify) sn_launcher_context_unref);
1556
1557 if (std->timeout_id != 0) {
1558 g_source_remove (std->timeout_id);
1559 std->timeout_id = 0;
1560 }
1561
1562 g_free (std);
1563}
1564
1565static gboolean
1566startup_timeout (void *data)
1567{
1568 StartupTimeoutData *std = data;
1569 GSList *tmp;
1570 int min_timeout;
1571
1572 min_timeout = STARTUP_TIMEOUT_LENGTH(30 * 1000);
1573
1574#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1575 gint64 now = g_get_real_time ();
1576#else
1577 GTimeVal now;
1578 g_get_current_time (&now);
1579#endif
1580
1581 tmp = std->contexts;
1582 while (tmp != NULL((void*)0)) {
1583 SnLauncherContext *sn_context = tmp->data;
1584 GSList *next = tmp->next;
1585 double elapsed;
1586
1587#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1588 time_t tv_sec;
1589 suseconds_t tv_usec;
1590 gint64 tv;
1591
1592 sn_launcher_context_get_last_active_time (sn_context, &tv_sec, &tv_usec);
1593 tv = (tv_sec * G_USEC_PER_SEC1000000) + tv_usec;
1594 elapsed = (double) (now - tv) / 1000.0;
1595#else
1596 long tv_sec, tv_usec;
1597
1598 sn_launcher_context_get_last_active_time (sn_context,
1599 &tv_sec, &tv_usec);
1600
1601 elapsed =
1602 ((((double)now.tv_sec - tv_sec) * G_USEC_PER_SEC1000000 +
1603 (now.tv_usec - tv_usec))) / 1000.0;
1604#endif
1605
1606 if (elapsed >= STARTUP_TIMEOUT_LENGTH(30 * 1000)) {
1607 std->contexts = g_slist_remove (std->contexts,
1608 sn_context);
1609 sn_launcher_context_complete (sn_context);
1610 sn_launcher_context_unref (sn_context);
1611 } else {
1612 min_timeout = MIN (min_timeout, (STARTUP_TIMEOUT_LENGTH - elapsed))(((min_timeout) < (((30 * 1000) - elapsed))) ? (min_timeout
) : (((30 * 1000) - elapsed)))
;
1613 }
1614
1615 tmp = next;
1616 }
1617
1618 /* we'll use seconds for the timeout */
1619 if (min_timeout < 1000)
1620 min_timeout = 1000;
1621
1622 if (std->contexts == NULL((void*)0)) {
1623 std->timeout_id = 0;
1624 } else {
1625 std->timeout_id = g_timeout_add_seconds (min_timeout / 1000,
1626 startup_timeout,
1627 std);
1628 }
1629
1630 /* always remove this one, but we may have reinstalled another one. */
1631 return FALSE(0);
1632}
1633
1634static void
1635add_startup_timeout (GdkScreen *screen,
1636 SnLauncherContext *sn_context)
1637{
1638 StartupTimeoutData *data;
1639
1640 data = g_object_get_data (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "mate-startup-data");
1641 if (data == NULL((void*)0)) {
1642 data = g_new (StartupTimeoutData, 1)((StartupTimeoutData *) g_malloc_n ((1), sizeof (StartupTimeoutData
)))
;
1643 data->screen = screen;
1644 data->contexts = NULL((void*)0);
1645 data->timeout_id = 0;
1646
1647 g_object_set_data_full (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "mate-startup-data",
1648 data, free_startup_timeout);
1649 }
1650
1651 sn_launcher_context_ref (sn_context);
1652 data->contexts = g_slist_prepend (data->contexts, sn_context);
1653
1654 if (data->timeout_id == 0) {
1655 data->timeout_id = g_timeout_add_seconds (
1656 STARTUP_TIMEOUT_LENGTH_SEC30,
1657 startup_timeout,
1658 data);
1659 }
1660}
1661#endif /* HAVE_STARTUP_NOTIFICATION - functions should only be reached in x11*/
1662
1663static inline char *
1664stringify_uris (GSList *args)
1665{
1666 GString *str;
1667
1668 str = g_string_new (NULL((void*)0));
1669
1670 append_all_converted (str, URI_TO_STRING, args, FALSE(0), FALSE(0), ADDED_NONE);
1671
1672 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1673}
1674
1675static inline char *
1676stringify_files (GSList *args)
1677{
1678 GString *str;
1679
1680 str = g_string_new (NULL((void*)0));
1681
1682 append_all_converted (str, URI_TO_LOCAL_PATH, args, FALSE(0), FALSE(0), ADDED_NONE);
1683
1684 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1685}
1686
1687static char **
1688make_environment_for_screen (GdkScreen *screen,
1689 char **envp)
1690{
1691 GdkDisplay *display;
1692 char **retval;
1693 char **freeme;
1694 char *display_name;
1695 int display_index = -1;
1696 int i, env_len;
1697
1698 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((screen)); GType __t = ((gdk_screen_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "GDK_IS_SCREEN (screen)"); return (((void*)0)
); } } while (0)
;
1699
1700 retval = freeme = NULL((void*)0);
1701
1702 if (envp == NULL((void*)0)) {
1703 envp = freeme = g_listenv ();
1704 for (i = 0; envp [i]; i++) {
1705 char *name = envp[i];
1706
1707 envp[i] = g_strjoin ("=", name, g_getenv (name), NULL((void*)0));
1708 g_free (name);
1709 }
1710 }
1711
1712 for (env_len = 0; envp [env_len]; env_len++)
1713 if (strncmp (envp [env_len], "DISPLAY", strlen ("DISPLAY")) == 0)
1714 display_index = env_len;
1715
1716 retval = g_new (char *, env_len + 1)((char * *) g_malloc_n ((env_len + 1), sizeof (char *)));
1717 retval [env_len] = NULL((void*)0);
1718
1719 display = gdk_screen_get_display (screen);
1720 display_name = g_strdup (gdk_display_get_name (display))g_strdup_inline (gdk_display_get_name (display));
1721
1722 for (i = 0; i < env_len; i++)
1723 if (i == display_index)
1724 retval [i] = g_strconcat ("DISPLAY=", display_name, NULL((void*)0));
1725 else
1726 retval [i] = g_strdup (envp[i])g_strdup_inline (envp[i]);
1727
1728 g_assert (i == env_len)do { if (i == env_len) ; else g_assertion_message_expr ("MateDesktop"
, "mate-desktop-item.c", 1728, ((const char*) (__func__)), "i == env_len"
); } while (0)
;
1729
1730 g_free (display_name);
1731 g_strfreev (freeme);
1732
1733 return retval;
1734}
1735
1736static void
1737dummy_child_watch (GPid pid,
1738 gint status,
1739 gpointer user_data)
1740{
1741 /* Nothing, this is just to ensure we don't double fork
1742 * and break pkexec:
1743 * https://bugzilla.gnome.org/show_bug.cgi?id=675789
1744 */
1745}
1746
1747static int
1748ditem_execute (const MateDesktopItem *item,
1749 const char *exec,
1750 GList *file_list,
1751 GdkScreen *screen,
1752 int workspace,
1753 char **envp,
1754 gboolean launch_only_one,
1755 gboolean use_current_dir,
1756 gboolean append_uris,
1757 gboolean append_paths,
1758 gboolean do_not_reap_child,
1759 GError **error)
1760{
1761 char **free_me = NULL((void*)0);
1762 char **real_argv;
1763 int i, ret;
1764 char **term_argv = NULL((void*)0);
1765 int term_argc = 0;
1766 GSList *vector_list;
1767 GSList *args, *arg_ptr;
1768 AddedStatus added_status;
1769 const char *working_dir = NULL((void*)0);
1770 char **temp_argv = NULL((void*)0);
1771 int temp_argc = 0;
1772 char *new_exec, *uris, *temp;
1773 char *exec_locale;
1774 int launched = 0;
1775 GPid pid;
1776#ifdef HAVE_STARTUP_NOTIFICATION
1777 GdkDisplay *gdkdisplay;
1778 SnLauncherContext *sn_context;
1779 SnDisplay *sn_display;
1780 const char *startup_class;
1781#endif
1782
1783 g_return_val_if_fail (item, -1)do { if ((item)) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "item"); return (-1); } } while
(0)
;
1784
1785 if (item->type == MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
1786 working_dir = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_PATH"Path");
1787 if (working_dir &&
1788 !g_file_test (working_dir, G_FILE_TEST_IS_DIR))
1789 working_dir = NULL((void*)0);
1790 }
1791
1792 if (working_dir == NULL((void*)0) && !use_current_dir)
1793 working_dir = g_get_home_dir ();
1794
1795 if (mate_desktop_item_get_boolean (item, MATE_DESKTOP_ITEM_TERMINAL"Terminal")) {
1796 const char *options =
1797 mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_TERMINAL_OPTIONS"TerminalOptions");
1798
1799 if (options != NULL((void*)0)) {
1800 g_shell_parse_argv (options,
1801 &term_argc,
1802 &term_argv,
1803 NULL((void*)0) /* error */);
1804 /* ignore errors */
1805 }
1806
1807 mate_desktop_prepend_terminal_to_vector (&term_argc, &term_argv);
1808 }
1809
1810 args = make_args (file_list);
1811 arg_ptr = make_args (file_list);
1812
1813#ifdef HAVE_STARTUP_NOTIFICATION
1814 GdkDisplay *display = gdk_screen_get_display (gdk_screen_get_default());
1815 if (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1816 {
1817 if (screen)
1818 gdkdisplay = gdk_screen_get_display (screen);
1819 else
1820 gdkdisplay = gdk_display_get_default ();
1821
1822 sn_display = sn_display_new (GDK_DISPLAY_XDISPLAY (gdkdisplay)(gdk_x11_display_get_xdisplay (gdkdisplay)),
1823 sn_error_trap_push,
1824 sn_error_trap_pop);
1825
1826 /* Only initiate notification if desktop file supports it.
1827 * (we could avoid setting up the SnLauncherContext if we aren't going
1828 * to initiate, but why bother)
1829 */
1830
1831 startup_class = mate_desktop_item_get_string (item,
1832 "StartupWMClass");
1833 if (startup_class ||
1834 mate_desktop_item_get_boolean (item, "StartupNotify")) {
1835 const char *name;
1836 const char *icon;
1837
1838 sn_context = sn_launcher_context_new (sn_display,
1839 screen ? gdk_x11_screen_get_screen_number (screen) :
1840 DefaultScreen (GDK_DISPLAY_XDISPLAY (gdkdisplay))(((_XPrivDisplay)((gdk_x11_display_get_xdisplay (gdkdisplay))
))->default_screen)
);
1841
1842 name = mate_desktop_item_get_localestring (item,
1843 MATE_DESKTOP_ITEM_NAME"Name");
1844
1845 if (name == NULL((void*)0))
1846 name = mate_desktop_item_get_localestring (item,
1847 MATE_DESKTOP_ITEM_GENERIC_NAME"GenericName");
1848
1849 if (name != NULL((void*)0)) {
1850 char *description;
1851
1852 sn_launcher_context_set_name (sn_context, name);
1853
1854 description = g_strdup_printf (_("Starting %s")((char *) g_dgettext ("mate-desktop", "Starting %s")), name);
1855
1856 sn_launcher_context_set_description (sn_context, description);
1857
1858 g_free (description);
1859 }
1860
1861 icon = mate_desktop_item_get_string (item,
1862 MATE_DESKTOP_ITEM_ICON"Icon");
1863
1864 if (icon != NULL((void*)0))
1865 sn_launcher_context_set_icon_name (sn_context, icon);
1866
1867 sn_launcher_context_set_workspace (sn_context, workspace);
1868
1869 if (startup_class != NULL((void*)0))
1870 sn_launcher_context_set_wmclass (sn_context,
1871 startup_class);
1872 } else {
1873 sn_context = NULL((void*)0);
1874 }
1875 }
1876 else {
1877 sn_context = NULL((void*)0);
1878 sn_display = NULL((void*)0);
1879 }
1880#endif
1881
1882 if (screen) {
1883 envp = make_environment_for_screen (screen, envp);
1884 if (free_me)
1885 g_strfreev (free_me);
1886 free_me = envp;
1887 }
1888
1889 exec_locale = g_filename_from_utf8 (exec, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
1890
1891 if (exec_locale == NULL((void*)0)) {
1892 exec_locale = g_strdup ("")g_strdup_inline ("");
1893 }
1894
1895 do {
1896 added_status = ADDED_NONE;
1897 new_exec = expand_string (item,
1898 exec_locale,
1899 args, &arg_ptr, &added_status);
1900
1901 if (launched == 0 && added_status == ADDED_NONE && append_uris) {
1902 uris = stringify_uris (args);
1903 temp = g_strconcat (new_exec, " ", uris, NULL((void*)0));
1904 g_free (uris);
1905 g_free (new_exec);
1906 new_exec = temp;
1907 added_status = ADDED_ALL;
1908 }
1909
1910 /* append_uris and append_paths are mutually exlusive */
1911 if (launched == 0 && added_status == ADDED_NONE && append_paths) {
1912 uris = stringify_files (args);
1913 temp = g_strconcat (new_exec, " ", uris, NULL((void*)0));
1914 g_free (uris);
1915 g_free (new_exec);
1916 new_exec = temp;
1917 added_status = ADDED_ALL;
1918 }
1919
1920 if (launched > 0 && added_status == ADDED_NONE) {
1921 g_free (new_exec);
1922 break;
1923 }
1924
1925 if ( ! g_shell_parse_argv (new_exec,
1926 &temp_argc, &temp_argv, error)) {
1927 /* The error now comes from g_shell_parse_argv */
1928 g_free (new_exec);
1929 ret = -1;
1930 break;
1931 }
1932 g_free (new_exec);
1933
1934 vector_list = NULL((void*)0);
1935 for(i = 0; i < term_argc; i++)
1936 vector_list = g_slist_append (vector_list,
1937 g_strdup (term_argv[i])g_strdup_inline (term_argv[i]));
1938
1939 for(i = 0; i < temp_argc; i++)
1940 vector_list = g_slist_append (vector_list,
1941 g_strdup (temp_argv[i])g_strdup_inline (temp_argv[i]));
1942
1943 g_strfreev (temp_argv);
1944
1945 real_argv = list_to_vector (vector_list);
1946 g_slist_free_full (vector_list, g_free);
1947
1948#ifdef HAVE_STARTUP_NOTIFICATION
1949 if (sn_context != NULL((void*)0) && (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) &&
1950 !sn_launcher_context_get_initiated (sn_context)) {
1951 guint32 launch_time;
1952
1953 /* This means that we always use the first real_argv[0]
1954 * we select for the "binary name", but it's probably
1955 * OK to do that. Binary name isn't super-important
1956 * anyway, and we can't initiate twice, and we
1957 * must initiate prior to fork/exec.
1958 */
1959
1960 sn_launcher_context_set_binary_name (sn_context,
1961 real_argv[0]);
1962
1963 if (item->launch_time > 0)
1964 launch_time = item->launch_time;
1965 else
1966 launch_time = gdk_x11_display_get_user_time (gdkdisplay);
1967
1968 sn_launcher_context_initiate (sn_context,
1969 g_get_prgname () ? g_get_prgname () : "unknown",
1970 real_argv[0],
1971 launch_time);
1972
1973 /* Don't allow accidental reuse of same timestamp */
1974 ((MateDesktopItem *)item)->launch_time = 0;
1975
1976 envp = make_spawn_environment_for_sn_context (sn_context, envp);
1977 if (free_me)
1978 g_strfreev (free_me);
1979 free_me = envp;
1980 }
1981#endif
1982
1983 if ( ! g_spawn_async (working_dir,
1984 real_argv,
1985 envp,
1986 (do_not_reap_child ? G_SPAWN_DO_NOT_REAP_CHILD : 0) | G_SPAWN_SEARCH_PATH /* flags */,
1987 NULL((void*)0), /* child_setup_func */
1988 NULL((void*)0), /* child_setup_func_data */
1989 (do_not_reap_child ? &pid : NULL((void*)0)) /* child_pid */,
1990 error)) {
1991 /* The error was set for us,
1992 * we just can't launch this thingie */
1993 ret = -1;
1994 g_strfreev (real_argv);
1995 break;
1996 } else if (do_not_reap_child) {
1997 g_child_watch_add (pid, dummy_child_watch, NULL((void*)0));
1998 }
1999
2000 launched ++;
2001
2002 g_strfreev (real_argv);
2003
2004 if (arg_ptr != NULL((void*)0))
2005 arg_ptr = arg_ptr->next;
2006
2007 /* rinse, repeat until we run out of arguments (That
2008 * is if we were adding singles anyway) */
2009 } while (added_status == ADDED_SINGLE &&
2010 arg_ptr != NULL((void*)0) &&
2011 ! launch_only_one);
2012
2013 g_free (exec_locale);
2014#ifdef HAVE_STARTUP_NOTIFICATION
2015 if ((sn_context != NULL((void*)0)) && (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)){
2016 if (ret < 0)
2017 sn_launcher_context_complete (sn_context); /* end sequence */
2018 else
2019 add_startup_timeout (screen ? screen :
2020 gdk_display_get_default_screen (gdk_display_get_default ()),
2021 sn_context);
2022 sn_launcher_context_unref (sn_context);
2023 }
2024 if (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2025 sn_display_unref (sn_display);
2026
2027#endif /* HAVE_STARTUP_NOTIFICATION */
2028
2029 free_args (args);
2030
2031 if (term_argv)
2032 g_strfreev (term_argv);
2033
2034 if (free_me)
2035 g_strfreev (free_me);
2036
2037 return ret;
2038}
2039
2040/* strip any trailing &, return FALSE if bad things happen and
2041 we end up with an empty string */
2042static gboolean
2043strip_the_amp (char *exec)
2044{
2045 size_t exec_len;
2046
2047 g_strstrip (exec)g_strchomp (g_strchug (exec));
2048 if (*exec == '\0')
2049 return FALSE(0);
2050
2051 exec_len = strlen (exec);
2052 /* kill any trailing '&' */
2053 if (exec[exec_len-1] == '&') {
2054 exec[exec_len-1] = '\0';
2055 g_strchomp (exec);
2056 }
2057
2058 /* can't exactly launch an empty thing */
2059 if (*exec == '\0')
2060 return FALSE(0);
2061
2062 return TRUE(!(0));
2063}
2064
2065static int
2066mate_desktop_item_launch_on_screen_with_env (
2067 const MateDesktopItem *item,
2068 GList *file_list,
2069 MateDesktopItemLaunchFlags flags,
2070 GdkScreen *screen,
2071 int workspace,
2072 char **envp,
2073 GError **error)
2074{
2075 const char *exec;
2076 char *the_exec;
2077 int ret;
2078
2079 exec = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_EXEC"Exec");
2080 /* This is a URL, so launch it as a url */
2081 if (item->type == MATE_DESKTOP_ITEM_TYPE_LINK) {
2082 const char *url;
2083 gboolean retval;
2084
2085 url = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_URL"URL");
2086 /* Mate panel used to put this in Exec */
2087 if (!(url && url[0] != '\0'))
2088 url = exec;
2089
2090 if (!(url && url[0] != '\0')) {
2091 g_set_error (error,
2092 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2093 MATE_DESKTOP_ITEM_ERROR_NO_URL,
2094 _("No URL to launch")((char *) g_dgettext ("mate-desktop", "No URL to launch")));
2095 return -1;
2096 }
2097
2098 retval = gtk_show_uri_on_window (NULL((void*)0),
2099 url,
2100 GDK_CURRENT_TIME0L,
2101 error);
2102 return retval ? 0 : -1;
2103 }
2104
2105 /* check the type, if there is one set */
2106 if (item->type != MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
2107 g_set_error (error,
2108 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2109 MATE_DESKTOP_ITEM_ERROR_NOT_LAUNCHABLE,
2110 _("Not a launchable item")((char *) g_dgettext ("mate-desktop", "Not a launchable item"
))
);
2111 return -1;
2112 }
2113
2114 if (exec == NULL((void*)0) ||
2115 exec[0] == '\0') {
2116 g_set_error (error,
2117 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2118 MATE_DESKTOP_ITEM_ERROR_NO_EXEC_STRING,
2119 _("No command (Exec) to launch")((char *) g_dgettext ("mate-desktop", "No command (Exec) to launch"
))
);
2120 return -1;
2121 }
2122
2123 /* make a new copy and get rid of spaces */
2124 the_exec = g_alloca (strlen (exec) + 1)__builtin_alloca (strlen (exec) + 1);
2125 g_strlcpy (the_exec, exec, strlen (exec) + 1);
2126
2127 if ( ! strip_the_amp (the_exec)) {
2128 g_set_error (error,
2129 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2130 MATE_DESKTOP_ITEM_ERROR_BAD_EXEC_STRING,
2131 _("Bad command (Exec) to launch")((char *) g_dgettext ("mate-desktop", "Bad command (Exec) to launch"
))
);
2132 return -1;
2133 }
2134
2135 ret = ditem_execute (item, the_exec, file_list, screen, workspace, envp,
2136 (flags & MATE_DESKTOP_ITEM_LAUNCH_ONLY_ONE),
2137 (flags & MATE_DESKTOP_ITEM_LAUNCH_USE_CURRENT_DIR),
2138 (flags & MATE_DESKTOP_ITEM_LAUNCH_APPEND_URIS),
2139 (flags & MATE_DESKTOP_ITEM_LAUNCH_APPEND_PATHS),
2140 (flags & MATE_DESKTOP_ITEM_LAUNCH_DO_NOT_REAP_CHILD),
2141 error);
2142
2143 return ret;
2144}
2145
2146/**
2147 * mate_desktop_item_launch:
2148 * @item: A desktop item
2149 * @file_list: Files/URIs to launch this item with, can be %NULL
2150 * @flags: FIXME
2151 * @error: FIXME
2152 *
2153 * This function runs the program listed in the specified 'item',
2154 * optionally appending additional arguments to its command line. It uses
2155 * #g_shell_parse_argv to parse the the exec string into a vector which is
2156 * then passed to #g_spawn_async for execution. This can return all
2157 * the errors from MateURL, #g_shell_parse_argv and #g_spawn_async,
2158 * in addition to it's own. The files are
2159 * only added if the entry defines one of the standard % strings in it's
2160 * Exec field.
2161 *
2162 * Returns: The the pid of the process spawned. If more then one
2163 * process was spawned the last pid is returned. On error -1
2164 * is returned and @error is set.
2165 */
2166int
2167mate_desktop_item_launch (const MateDesktopItem *item,
2168 GList *file_list,
2169 MateDesktopItemLaunchFlags flags,
2170 GError **error)
2171{
2172 return mate_desktop_item_launch_on_screen_with_env (
2173 item, file_list, flags, NULL((void*)0), -1, NULL((void*)0), error);
2174}
2175
2176/**
2177 * mate_desktop_item_launch_with_env:
2178 * @item: A desktop item
2179 * @file_list: Files/URIs to launch this item with, can be %NULL
2180 * @flags: FIXME
2181 * @envp: child's environment, or %NULL to inherit parent's
2182 * @error: FIXME
2183 *
2184 * See mate_desktop_item_launch for a full description. This function
2185 * additionally passes an environment vector for the child process
2186 * which is to be launched.
2187 *
2188 * Returns: The the pid of the process spawned. If more then one
2189 * process was spawned the last pid is returned. On error -1
2190 * is returned and @error is set.
2191 */
2192int
2193mate_desktop_item_launch_with_env (const MateDesktopItem *item,
2194 GList *file_list,
2195 MateDesktopItemLaunchFlags flags,
2196 char **envp,
2197 GError **error)
2198{
2199 return mate_desktop_item_launch_on_screen_with_env (
2200 item, file_list, flags,
2201 NULL((void*)0), -1, envp, error);
2202}
2203
2204/**
2205 * mate_desktop_item_launch_on_screen:
2206 * @item: A desktop item
2207 * @file_list: Files/URIs to launch this item with, can be %NULL
2208 * @flags: FIXME
2209 * @screen: the %GdkScreen on which the application should be launched
2210 * @workspace: the workspace on which the app should be launched (-1 for current)
2211 * @error: FIXME
2212 *
2213 * See mate_desktop_item_launch for a full description. This function
2214 * additionally attempts to launch the application on a given screen
2215 * and workspace.
2216 *
2217 * Returns: The the pid of the process spawned. If more then one
2218 * process was spawned the last pid is returned. On error -1
2219 * is returned and @error is set.
2220 */
2221int
2222mate_desktop_item_launch_on_screen (const MateDesktopItem *item,
2223 GList *file_list,
2224 MateDesktopItemLaunchFlags flags,
2225 GdkScreen *screen,
2226 int workspace,
2227 GError **error)
2228{
2229 return mate_desktop_item_launch_on_screen_with_env (
2230 item, file_list, flags,
2231 screen, workspace, NULL((void*)0), error);
2232}
2233
2234/**
2235 * mate_desktop_item_drop_uri_list:
2236 * @item: A desktop item
2237 * @uri_list: text as gotten from a text/uri-list
2238 * @flags: FIXME
2239 * @error: FIXME
2240 *
2241 * A list of files or urls dropped onto an icon, the proper (Url or File)
2242 * exec is run you can pass directly string that you got as the
2243 * text/uri-list. This just parses the list and calls
2244 *
2245 * Returns: The value returned by #mate_execute_async() upon execution of
2246 * the specified item or -1 on error. If multiple instances are run, the
2247 * return of the last one is returned.
2248 */
2249int
2250mate_desktop_item_drop_uri_list (const MateDesktopItem *item,
2251 const char *uri_list,
2252 MateDesktopItemLaunchFlags flags,
2253 GError **error)
2254{
2255 return mate_desktop_item_drop_uri_list_with_env (item, uri_list,
2256 flags, NULL((void*)0), error);
2257}
2258
2259/**
2260* mate_desktop_item_drop_uri_list_with_env:
2261* @item: A desktop item
2262* @uri_list: text as gotten from a text/uri-list
2263* @flags: FIXME
2264* @envp: child's environment
2265* @error: FIXME
2266*
2267* See mate_desktop_item_drop_uri_list for a full description. This function
2268* additionally passes an environment vector for the child process
2269* which is to be launched.
2270*
2271* Returns: The value returned by #mate_execute_async() upon execution of
2272* the specified item or -1 on error. If multiple instances are run, the
2273* return of the last one is returned.
2274*/
2275int
2276mate_desktop_item_drop_uri_list_with_env (const MateDesktopItem *item,
2277 const char *uri_list,
2278 MateDesktopItemLaunchFlags flags,
2279 char **envp,
2280 GError **error)
2281{
2282 int ret;
2283 char *uri;
2284 char **uris;
2285 GList *list = NULL((void*)0);
2286
2287 uris = g_uri_list_extract_uris (uri_list);
2288
2289 for (uri = uris[0]; uri != NULL((void*)0); uri++) {
2290 list = g_list_prepend (list, uri);
2291 }
2292 list = g_list_reverse (list);
2293
2294 ret = mate_desktop_item_launch_with_env (
2295 item, list, flags, envp, error);
2296
2297 g_strfreev (uris);
2298 g_list_free (list);
2299
2300 return ret;
2301}
2302
2303static gboolean
2304exec_exists (const char *exec)
2305{
2306 if (g_path_is_absolute (exec)) {
2307 if (access (exec, X_OK1) == 0)
2308 return TRUE(!(0));
2309 else
2310 return FALSE(0);
2311 } else {
2312 char *tryme;
2313
2314 tryme = g_find_program_in_path (exec);
2315 if (tryme != NULL((void*)0)) {
2316 g_free (tryme);
2317 return TRUE(!(0));
2318 }
2319 return FALSE(0);
2320 }
2321}
2322
2323/**
2324 * mate_desktop_item_exists:
2325 * @item: A desktop item
2326 *
2327 * Attempt to figure out if the program that can be executed by this item
2328 * actually exists. First it tries the TryExec attribute to see if that
2329 * contains a program that is in the path. Then if there is no such
2330 * attribute, it tries the first word of the Exec attribute.
2331 *
2332 * Returns: A boolean, %TRUE if it exists, %FALSE otherwise.
2333 */
2334gboolean
2335mate_desktop_item_exists (const MateDesktopItem *item)
2336{
2337 const char *try_exec;
2338 const char *exec;
2339
2340 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2341
2342 try_exec = lookup (item, MATE_DESKTOP_ITEM_TRY_EXEC"TryExec");
2343
2344 if (try_exec != NULL((void*)0) &&
2345 ! exec_exists (try_exec)) {
2346 return FALSE(0);
2347 }
2348
2349 if (item->type == MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
2350 int argc;
2351 char **argv;
2352 const char *exe;
2353
2354 exec = lookup (item, MATE_DESKTOP_ITEM_EXEC"Exec");
2355 if (exec == NULL((void*)0))
2356 return FALSE(0);
2357
2358 if ( ! g_shell_parse_argv (exec, &argc, &argv, NULL((void*)0)))
2359 return FALSE(0);
2360
2361 if (argc < 1) {
2362 g_strfreev (argv);
2363 return FALSE(0);
2364 }
2365
2366 exe = argv[0];
2367
2368 if ( ! exec_exists (exe)) {
2369 g_strfreev (argv);
2370 return FALSE(0);
2371 }
2372 g_strfreev (argv);
2373 }
2374
2375 return TRUE(!(0));
2376}
2377
2378/**
2379 * mate_desktop_item_get_entry_type:
2380 * @item: A desktop item
2381 *
2382 * Gets the type attribute (the 'Type' field) of the item. This should
2383 * usually be 'Application' for an application, but it can be 'Directory'
2384 * for a directory description. There are other types available as well.
2385 * The type usually indicates how the desktop item should be handeled and
2386 * how the 'Exec' field should be handeled.
2387 *
2388 * Returns: The type of the specified 'item'. The returned
2389 * memory remains owned by the MateDesktopItem and should not be freed.
2390 */
2391MateDesktopItemType
2392mate_desktop_item_get_entry_type (const MateDesktopItem *item)
2393{
2394 g_return_val_if_fail (item != NULL, 0)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (0); } } while (0)
;
2395 g_return_val_if_fail (item->refcount > 0, 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (0); } } while (0)
;
2396
2397 return item->type;
2398}
2399
2400void
2401mate_desktop_item_set_entry_type (MateDesktopItem *item,
2402 MateDesktopItemType type)
2403{
2404 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2405 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2406
2407 item->type = type;
2408
2409 switch (type) {
2410 case MATE_DESKTOP_ITEM_TYPE_NULL:
2411 set (item, MATE_DESKTOP_ITEM_TYPE"Type", NULL((void*)0));
2412 break;
2413 case MATE_DESKTOP_ITEM_TYPE_APPLICATION:
2414 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Application");
2415 break;
2416 case MATE_DESKTOP_ITEM_TYPE_LINK:
2417 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Link");
2418 break;
2419 case MATE_DESKTOP_ITEM_TYPE_FSDEVICE:
2420 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "FSDevice");
2421 break;
2422 case MATE_DESKTOP_ITEM_TYPE_MIME_TYPE:
2423 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "MimeType");
2424 break;
2425 case MATE_DESKTOP_ITEM_TYPE_DIRECTORY:
2426 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Directory");
2427 break;
2428 case MATE_DESKTOP_ITEM_TYPE_SERVICE:
2429 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Service");
2430 break;
2431 case MATE_DESKTOP_ITEM_TYPE_SERVICE_TYPE:
2432 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "ServiceType");
2433 break;
2434 default:
2435 break;
2436 }
2437}
2438
2439/**
2440 * mate_desktop_item_get_file_status:
2441 * @item: A desktop item
2442 *
2443 * This function checks the modification time of the on-disk file to
2444 * see if it is more recent than the in-memory data.
2445 *
2446 * Returns: An enum value that specifies whether the item has changed since being loaded.
2447 */
2448MateDesktopItemStatus
2449mate_desktop_item_get_file_status (const MateDesktopItem *item)
2450{
2451 MateDesktopItemStatus retval;
2452 GFile *file;
2453 GFileInfo *info;
2454
2455 g_return_val_if_fail (item != NULL, MATE_DESKTOP_ITEM_DISAPPEARED)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (MATE_DESKTOP_ITEM_DISAPPEARED); } } while (0)
;
2456 g_return_val_if_fail (item->refcount > 0, MATE_DESKTOP_ITEM_DISAPPEARED)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (MATE_DESKTOP_ITEM_DISAPPEARED); } } while (0)
;
2457
2458 if (item->location == NULL((void*)0))
2459 return MATE_DESKTOP_ITEM_DISAPPEARED;
2460
2461 file = g_file_new_for_uri (item->location);
2462 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2463 G_FILE_QUERY_INFO_NONE, NULL((void*)0), NULL((void*)0));
2464
2465 retval = MATE_DESKTOP_ITEM_UNCHANGED;
2466
2467 if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2468 retval = MATE_DESKTOP_ITEM_DISAPPEARED;
2469 else if (((guint64) item->mtime) < g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2470 retval = MATE_DESKTOP_ITEM_CHANGED;
2471
2472 g_object_unref (info);
2473 g_object_unref (file);
2474
2475 return retval;
2476}
2477
2478/**
2479 * mate_desktop_item_find_icon:
2480 * @icon_theme: a #GtkIconTheme
2481 * @icon: icon name, something you'd get out of the Icon key
2482 * @desired_size: FIXME
2483 * @flags: FIXME
2484 *
2485 * Description: This function goes and looks for the icon file. If the icon
2486 * is not an absolute filename, this will look for it in the standard places.
2487 * If it can't find the icon, it will return %NULL
2488 *
2489 * Returns: A newly allocated string
2490 */
2491char *
2492mate_desktop_item_find_icon (GtkIconTheme *icon_theme,
2493 const char *icon,
2494 int desired_size,
2495 int flags)
2496{
2497 GtkIconInfo *info;
2498 char *full = NULL((void*)0);
2499
2500 g_return_val_if_fail (icon_theme == NULL ||do { if ((icon_theme == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((icon_theme)); GType __t = ((gtk_icon_theme_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "icon_theme == NULL || GTK_IS_ICON_THEME (icon_theme)"
); return (((void*)0)); } } while (0)
2501 GTK_IS_ICON_THEME (icon_theme), NULL)do { if ((icon_theme == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((icon_theme)); GType __t = ((gtk_icon_theme_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "icon_theme == NULL || GTK_IS_ICON_THEME (icon_theme)"
); return (((void*)0)); } } while (0)
;
2502
2503 if (icon == NULL((void*)0) || strcmp(icon,"") == 0) {
2504 return NULL((void*)0);
2505 } else if (g_path_is_absolute (icon)) {
2506 if (g_file_test (icon, G_FILE_TEST_EXISTS)) {
2507 return g_strdup (icon)g_strdup_inline (icon);
2508 } else {
2509 return NULL((void*)0);
2510 }
2511 } else {
2512 char *icon_no_extension;
2513 char *p;
2514
2515 if (icon_theme == NULL((void*)0))
2516 icon_theme = gtk_icon_theme_get_default ();
2517
2518 icon_no_extension = g_strdup (icon)g_strdup_inline (icon);
2519 p = strrchr (icon_no_extension, '.');
2520 if (p &&
2521 (strcmp (p, ".png") == 0 ||
2522 strcmp (p, ".xpm") == 0 ||
2523 strcmp (p, ".svg") == 0)) {
2524 *p = 0;
2525 }
2526
2527 info = gtk_icon_theme_lookup_icon (icon_theme,
2528 icon_no_extension,
2529 desired_size,
2530 0);
2531
2532 full = NULL((void*)0);
2533 if (info) {
2534 full = g_strdup (gtk_icon_info_get_filename (info))g_strdup_inline (gtk_icon_info_get_filename (info));
2535 g_object_unref (info);
2536 }
2537 g_free (icon_no_extension);
2538 }
2539
2540 return full;
2541
2542}
2543
2544/**
2545 * mate_desktop_item_get_icon:
2546 * @icon_theme: a #GtkIconTheme
2547 * @item: A desktop item
2548 *
2549 * Description: This function goes and looks for the icon file. If the icon
2550 * is not set as an absolute filename, this will look for it in the standard places.
2551 * If it can't find the icon, it will return %NULL
2552 *
2553 * Returns: A newly allocated string
2554 */
2555char *
2556mate_desktop_item_get_icon (const MateDesktopItem *item,
2557 GtkIconTheme *icon_theme)
2558{
2559 /* maybe this function should be deprecated in favour of find icon
2560 * -George */
2561 const char *icon;
2562
2563 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2564 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2565
2566 icon = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_ICON"Icon");
2567
2568 return mate_desktop_item_find_icon (icon_theme, icon,
2569 48 /* desired_size */,
2570 0 /* flags */);
2571}
2572
2573/**
2574 * mate_desktop_item_get_location:
2575 * @item: A desktop item
2576 *
2577 * Returns: The file location associated with 'item'.
2578 *
2579 */
2580const char *
2581mate_desktop_item_get_location (const MateDesktopItem *item)
2582{
2583 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2584 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2585
2586 return item->location;
2587}
2588
2589/**
2590 * mate_desktop_item_set_location:
2591 * @item: A desktop item
2592 * @location: A uri string specifying the file location of this particular item.
2593 *
2594 * Set's the 'location' uri of this item.
2595 */
2596void
2597mate_desktop_item_set_location (MateDesktopItem *item, const char *location)
2598{
2599 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2600 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2601
2602 if (item->location != NULL((void*)0) &&
2603 location != NULL((void*)0) &&
2604 strcmp (item->location, location) == 0)
2605 return;
2606
2607 g_free (item->location);
2608 item->location = g_strdup (location)g_strdup_inline (location);
2609
2610 /* This is ugly, but useful internally */
2611 if (item->mtime != DONT_UPDATE_MTIME((gint64)-2)) {
2612 item->mtime = 0;
2613
2614 if (item->location) {
2615 GFile *file;
2616 GFileInfo *info;
2617
2618 file = g_file_new_for_uri (item->location);
2619
2620 info = g_file_query_info (file,
2621 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2622 G_FILE_QUERY_INFO_NONE,
2623 NULL((void*)0), NULL((void*)0));
2624 if (info) {
2625 if (g_file_info_has_attribute (info,
2626 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2627 item->mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
2628 g_object_unref (info);
2629 }
2630
2631 g_object_unref (file);
2632 }
2633 }
2634
2635 /* Make sure that save actually saves */
2636 item->modified = TRUE(!(0));
2637}
2638
2639/**
2640 * mate_desktop_item_set_location_file:
2641 * @item: A desktop item
2642 * @file: A local filename specifying the file location of this particular item.
2643 *
2644 * Set's the 'location' uri of this item to the given @file.
2645 */
2646void
2647mate_desktop_item_set_location_file (MateDesktopItem *item, const char *file)
2648{
2649 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2650 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2651
2652 if (file != NULL((void*)0)) {
2653 GFile *gfile;
2654
2655 gfile = g_file_new_for_path (file);
2656 mate_desktop_item_set_location_gfile (item, gfile);
2657 g_object_unref (gfile);
2658 } else {
2659 mate_desktop_item_set_location (item, NULL((void*)0));
2660 }
2661}
2662
2663static void
2664mate_desktop_item_set_location_gfile (MateDesktopItem *item, GFile *file)
2665{
2666 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2667 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2668
2669 if (file != NULL((void*)0)) {
2670 char *uri;
2671
2672 uri = g_file_get_uri (file);
2673 mate_desktop_item_set_location (item, uri);
2674 g_free (uri);
2675 } else {
2676 mate_desktop_item_set_location (item, NULL((void*)0));
2677 }
2678}
2679
2680/*
2681 * Reading/Writing different sections, NULL is the standard section
2682 */
2683
2684gboolean
2685mate_desktop_item_attr_exists (const MateDesktopItem *item,
2686 const char *attr)
2687{
2688 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2689 g_return_val_if_fail (item->refcount > 0, FALSE)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return ((0)); } } while (0)
;
2690 g_return_val_if_fail (attr != NULL, FALSE)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return ((0)); } } while (0)
;
2691
2692 return lookup (item, attr) != NULL((void*)0);
2693}
2694
2695/*
2696 * String type
2697 */
2698const char *
2699mate_desktop_item_get_string (const MateDesktopItem *item,
2700 const char *attr)
2701{
2702 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2703 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2704 g_return_val_if_fail (attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2705
2706 return lookup (item, attr);
2707}
2708
2709void
2710mate_desktop_item_set_string (MateDesktopItem *item,
2711 const char *attr,
2712 const char *value)
2713{
2714 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2715 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2716 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2717
2718 set (item, attr, value);
2719
2720 if (strcmp (attr, MATE_DESKTOP_ITEM_TYPE"Type") == 0)
2721 item->type = type_from_string (value);
2722}
2723
2724/*
2725 * LocaleString type
2726 */
2727const char* mate_desktop_item_get_localestring(const MateDesktopItem* item, const char* attr)
2728{
2729 g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2730 g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2731 g_return_val_if_fail(attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2732
2733 return lookup_best_locale(item, attr);
2734}
2735
2736const char* mate_desktop_item_get_localestring_lang(const MateDesktopItem* item, const char* attr, const char* language)
2737{
2738 g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2739 g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2740 g_return_val_if_fail(attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2741
2742 return lookup_locale(item, attr, language);
2743}
2744
2745/**
2746 * mate_desktop_item_get_string_locale:
2747 * @item: A desktop item
2748 * @attr: An attribute name
2749 *
2750 * Returns the current locale that is used for the given attribute.
2751 * This might not be the same for all attributes. For example, if your
2752 * locale is "en_US.ISO8859-1" but attribute FOO only has "en_US" then
2753 * that would be returned for attr = "FOO". If attribute BAR has
2754 * "en_US.ISO8859-1" then that would be returned for "BAR".
2755 *
2756 * Returns: a string equal to the current locale or NULL
2757 * if the attribute is invalid or there is no matching locale.
2758 */
2759const char *
2760mate_desktop_item_get_attr_locale (const MateDesktopItem *item,
2761 const char *attr)
2762{
2763 const char * const *langs_pointer;
2764 int i;
2765
2766 langs_pointer = g_get_language_names ();
2767 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
2768 const char *value = NULL((void*)0);
2769
2770 value = lookup_locale (item, attr, langs_pointer[i]);
2771 if (value)
2772 return langs_pointer[i];
2773 }
2774
2775 return NULL((void*)0);
2776}
2777
2778GList *
2779mate_desktop_item_get_languages (const MateDesktopItem *item,
2780 const char *attr)
2781{
2782 GList *li;
2783 GList *list = NULL((void*)0);
2784
2785 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2786 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2787
2788 for (li = item->languages; li != NULL((void*)0); li = li->next) {
2789 char *language = li->data;
2790 if (attr == NULL((void*)0) ||
2791 lookup_locale (item, attr, language) != NULL((void*)0)) {
2792 list = g_list_prepend (list, language);
2793 }
2794 }
2795
2796 return g_list_reverse (list);
2797}
2798
2799static const char *
2800get_language (void)
2801{
2802 const char * const *langs_pointer;
2803 int i;
2804
2805 langs_pointer = g_get_language_names ();
2806 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
2807 /* find first without encoding */
2808 if (strchr (langs_pointer[i], '.') == NULL((void*)0)) {
2809 return langs_pointer[i];
2810 }
2811 }
2812 return NULL((void*)0);
2813}
2814
2815void
2816mate_desktop_item_set_localestring (MateDesktopItem *item,
2817 const char *attr,
2818 const char *value)
2819{
2820 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2821 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2822 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2823
2824 set_locale (item, attr, get_language (), value);
2825}
2826
2827void
2828mate_desktop_item_set_localestring_lang (MateDesktopItem *item,
2829 const char *attr,
2830 const char *language,
2831 const char *value)
2832{
2833 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2834 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2835 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2836
2837 set_locale (item, attr, language, value);
2838}
2839
2840void
2841mate_desktop_item_clear_localestring (MateDesktopItem *item,
2842 const char *attr)
2843{
2844 GList *l;
2845
2846 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2847 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2848 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2849
2850 for (l = item->languages; l != NULL((void*)0); l = l->next)
2851 set_locale (item, attr, l->data, NULL((void*)0));
2852
2853 set (item, attr, NULL((void*)0));
2854}
2855
2856/*
2857 * Strings, Regexps types
2858 */
2859
2860char **
2861mate_desktop_item_get_strings (const MateDesktopItem *item,
2862 const char *attr)
2863{
2864 const char *value;
2865
2866 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2867 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2868 g_return_val_if_fail (attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2869
2870 value = lookup (item, attr);
2871 if (value == NULL((void*)0))
2872 return NULL((void*)0);
2873
2874 /* FIXME: there's no way to escape semicolons apparently */
2875 return g_strsplit (value, ";", -1);
2876}
2877
2878void
2879mate_desktop_item_set_strings (MateDesktopItem *item,
2880 const char *attr,
2881 char **strings)
2882{
2883 char *str, *str2;
2884
2885 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2886 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2887 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2888
2889 str = g_strjoinv (";", strings);
2890 str2 = g_strconcat (str, ";", NULL((void*)0));
2891 /* FIXME: there's no way to escape semicolons apparently */
2892 set (item, attr, str2);
2893 g_free (str);
2894 g_free (str2);
2895}
2896
2897/*
2898 * Boolean type
2899 */
2900gboolean
2901mate_desktop_item_get_boolean (const MateDesktopItem *item,
2902 const char *attr)
2903{
2904 const char *value;
2905
2906 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2907 g_return_val_if_fail (item->refcount > 0, FALSE)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return ((0)); } } while (0)
;
2908 g_return_val_if_fail (attr != NULL, FALSE)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return ((0)); } } while (0)
;
2909
2910 value = lookup (item, attr);
2911 if (value == NULL((void*)0))
2912 return FALSE(0);
2913
2914 return (value[0] == 'T' ||
2915 value[0] == 't' ||
2916 value[0] == 'Y' ||
2917 value[0] == 'y' ||
2918 atoi (value) != 0);
2919}
2920
2921void
2922mate_desktop_item_set_boolean (MateDesktopItem *item,
2923 const char *attr,
2924 gboolean value)
2925{
2926 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2927 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2928 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2929
2930 set (item, attr, value ? "true" : "false");
2931}
2932
2933void
2934mate_desktop_item_set_launch_time (MateDesktopItem *item,
2935 guint32 timestamp)
2936{
2937 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2938
2939 item->launch_time = timestamp;
2940}
2941
2942/*
2943 * Clearing attributes
2944 */
2945void
2946mate_desktop_item_clear_section (MateDesktopItem *item,
2947 const char *section)
2948{
2949 Section *sec;
2950 GList *li;
2951
2952 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2953 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2954
2955 sec = find_section (item, section);
2956
2957 if (sec == NULL((void*)0)) {
2958 for (li = item->keys; li != NULL((void*)0); li = li->next) {
2959 g_hash_table_remove (item->main_hash, li->data);
2960 g_free (li->data);
2961 li->data = NULL((void*)0);
2962 }
2963 g_list_free (item->keys);
2964 item->keys = NULL((void*)0);
2965 } else {
2966 for (li = sec->keys; li != NULL((void*)0); li = li->next) {
2967 char *key = li->data;
2968 char *full = g_strdup_printf ("%s/%s",
2969 sec->name, key);
2970 g_hash_table_remove (item->main_hash, full);
2971 g_free (full);
2972 g_free (key);
2973 li->data = NULL((void*)0);
2974 }
2975 g_list_free (sec->keys);
2976 sec->keys = NULL((void*)0);
2977 }
2978 item->modified = TRUE(!(0));
2979}
2980
2981/************************************************************
2982 * Parser: *
2983 ************************************************************/
2984
2985static gboolean G_GNUC_CONST__attribute__ ((__const__))
2986standard_is_boolean (const char * key)
2987{
2988 static GHashTable *bools = NULL((void*)0);
2989
2990 if (bools == NULL((void*)0)) {
2991 bools = g_hash_table_new (g_str_hash, g_str_equal);
2992 g_hash_table_insert (bools,
2993 MATE_DESKTOP_ITEM_NO_DISPLAY"NoDisplay",
2994 MATE_DESKTOP_ITEM_NO_DISPLAY"NoDisplay");
2995 g_hash_table_insert (bools,
2996 MATE_DESKTOP_ITEM_HIDDEN"Hidden",
2997 MATE_DESKTOP_ITEM_HIDDEN"Hidden");
2998 g_hash_table_insert (bools,
2999 MATE_DESKTOP_ITEM_TERMINAL"Terminal",
3000 MATE_DESKTOP_ITEM_TERMINAL"Terminal");
3001 g_hash_table_insert (bools,
3002 MATE_DESKTOP_ITEM_READ_ONLY"ReadOnly",
3003 MATE_DESKTOP_ITEM_READ_ONLY"ReadOnly");
3004 }
3005
3006 return g_hash_table_lookup (bools, key) != NULL((void*)0);
3007}
3008
3009static gboolean G_GNUC_CONST__attribute__ ((__const__))
3010standard_is_strings (const char *key)
3011{
3012 static GHashTable *strings = NULL((void*)0);
3013
3014 if (strings == NULL((void*)0)) {
3015 strings = g_hash_table_new (g_str_hash, g_str_equal);
3016 g_hash_table_insert (strings,
3017 MATE_DESKTOP_ITEM_FILE_PATTERN"FilePattern",
3018 MATE_DESKTOP_ITEM_FILE_PATTERN"FilePattern");
3019 g_hash_table_insert (strings,
3020 MATE_DESKTOP_ITEM_ACTIONS"Actions",
3021 MATE_DESKTOP_ITEM_ACTIONS"Actions");
3022 g_hash_table_insert (strings,
3023 MATE_DESKTOP_ITEM_MIME_TYPE"MimeType",
3024 MATE_DESKTOP_ITEM_MIME_TYPE"MimeType");
3025 g_hash_table_insert (strings,
3026 MATE_DESKTOP_ITEM_PATTERNS"Patterns",
3027 MATE_DESKTOP_ITEM_PATTERNS"Patterns");
3028 g_hash_table_insert (strings,
3029 MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder",
3030 MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder");
3031 }
3032
3033 return g_hash_table_lookup (strings, key) != NULL((void*)0);
3034}
3035
3036/* If no need to cannonize, returns NULL */
3037static char *
3038cannonize (const char *key, const char *value)
3039{
3040 if (standard_is_boolean (key)) {
3041 if (value[0] == 'T' ||
3042 value[0] == 't' ||
3043 value[0] == 'Y' ||
3044 value[0] == 'y' ||
3045 atoi (value) != 0) {
3046 return g_strdup ("true")g_strdup_inline ("true");
3047 } else {
3048 return g_strdup ("false")g_strdup_inline ("false");
3049 }
3050 } else if (standard_is_strings (key)) {
3051 int len = strlen (value);
3052 if (len == 0 || value[len-1] != ';') {
3053 return g_strconcat (value, ";", NULL((void*)0));
3054 }
3055 }
3056 /* XXX: Perhaps we should canonize numeric values as well, but this
3057 * has caused some subtle problems before so it needs to be done
3058 * carefully if at all */
3059 return NULL((void*)0);
3060}
3061
3062static char *
3063decode_string_and_dup (const char *s)
3064{
3065 char *p = g_malloc (strlen (s) + 1);
3066 char *q = p;
3067
3068 do {
3069 if (*s == '\\'){
3070 switch (*(++s)){
3071 case 's':
3072 *p++ = ' ';
3073 break;
3074 case 't':
3075 *p++ = '\t';
3076 break;
3077 case 'n':
3078 *p++ = '\n';
3079 break;
3080 case '\\':
3081 *p++ = '\\';
3082 break;
3083 case 'r':
3084 *p++ = '\r';
3085 break;
3086 default:
3087 *p++ = '\\';
3088 *p++ = *s;
3089 break;
3090 }
3091 } else {
3092 *p++ = *s;
3093 }
3094 } while (*s++);
3095
3096 return q;
3097}
3098
3099static char *
3100escape_string_and_dup (const char *s)
3101{
3102 char *return_value, *p;
3103 const char *q;
3104 int len = 0;
3105
3106 if (s
11.1
's' is not equal to NULL
== NULL((void*)0))
12
Taking false branch
3107 return g_strdup("")g_strdup_inline ("");
3108
3109 q = s;
3110 while (*q){
13
Loop condition is true. Entering loop body
16
Loop condition is true. Entering loop body
19
Loop condition is false. Execution continues on line 3116
3111 len++;
3112 if (strchr ("\n\r\t\\", *q) != NULL((void*)0))
14
Assuming the condition is false
15
Taking false branch
17
Assuming the condition is false
18
Taking false branch
3113 len++;
3114 q++;
3115 }
3116 return_value = p = (char *) g_malloc (len + 1);
3117 do {
22
Loop condition is true. Execution continues on line 3118
3118 switch (*s){
20
Control jumps to 'case 92:' at line 3131
23
Control jumps to 'case 13:' at line 3127
3119 case '\t':
3120 *p++ = '\\';
3121 *p++ = 't';
3122 break;
3123 case '\n':
3124 *p++ = '\\';
3125 *p++ = 'n';
3126 break;
3127 case '\r':
3128 *p++ = '\\';
3129 *p++ = 'r';
24
Out of bound memory access (access exceeds upper limit of memory block)
3130 break;
3131 case '\\':
3132 *p++ = '\\';
3133 *p++ = '\\';
3134 break;
21
Execution continues on line 3138
3135 default:
3136 *p++ = *s;
3137 }
3138 } while (*s++);
3139 return return_value;
3140}
3141
3142static gboolean
3143check_locale (const char *locale)
3144{
3145 GIConv cd = g_iconv_open ("UTF-8", locale);
3146 if ((GIConv)-1 == cd)
3147 return FALSE(0);
3148 g_iconv_close (cd);
3149 return TRUE(!(0));
3150}
3151
3152static void
3153insert_locales (GHashTable *encodings, char *enc, ...)
3154{
3155 va_list args;
3156 char *s;
3157
3158 va_start (args, enc)__builtin_va_start(args, enc);
3159 for (;;) {
3160 s = va_arg (args, char *)__builtin_va_arg(args, char *);
3161 if (s == NULL((void*)0))
3162 break;
3163 g_hash_table_insert (encodings, s, enc);
3164 }
3165 va_end (args)__builtin_va_end(args);
3166}
3167
3168/* make a standard conversion table from the desktop standard spec */
3169static GHashTable *
3170init_encodings (void)
3171{
3172 GHashTable *encodings = g_hash_table_new (g_str_hash, g_str_equal);
3173
3174 /* "C" is plain ascii */
3175 insert_locales (encodings, "ASCII", "C", NULL((void*)0));
3176
3177 insert_locales (encodings, "ARMSCII-8", "by", NULL((void*)0));
3178 insert_locales (encodings, "BIG5", "zh_TW", NULL((void*)0));
3179 insert_locales (encodings, "CP1251", "be", "bg", NULL((void*)0));
3180 if (check_locale ("EUC-CN")) {
3181 insert_locales (encodings, "EUC-CN", "zh_CN", NULL((void*)0));
3182 } else {
3183 insert_locales (encodings, "GB2312", "zh_CN", NULL((void*)0));
3184 }
3185 insert_locales (encodings, "EUC-JP", "ja", NULL((void*)0));
3186 insert_locales (encodings, "EUC-KR", "ko", NULL((void*)0));
3187 /*insert_locales (encodings, "GEORGIAN-ACADEMY", NULL);*/
3188 insert_locales (encodings, "GEORGIAN-PS", "ka", NULL((void*)0));
3189 insert_locales (encodings, "ISO-8859-1", "br", "ca", "da", "de", "en", "es", "eu", "fi", "fr", "gl", "it", "nl", "wa", "no", "pt", "pt", "sv", NULL((void*)0));
3190 insert_locales (encodings, "ISO-8859-2", "cs", "hr", "hu", "pl", "ro", "sk", "sl", "sq", "sr", NULL((void*)0));
3191 insert_locales (encodings, "ISO-8859-3", "eo", NULL((void*)0));
3192 insert_locales (encodings, "ISO-8859-5", "mk", "sp", NULL((void*)0));
3193 insert_locales (encodings, "ISO-8859-7", "el", NULL((void*)0));
3194 insert_locales (encodings, "ISO-8859-9", "tr", NULL((void*)0));
3195 insert_locales (encodings, "ISO-8859-13", "lt", "lv", "mi", NULL((void*)0));
3196 insert_locales (encodings, "ISO-8859-14", "ga", "cy", NULL((void*)0));
3197 insert_locales (encodings, "ISO-8859-15", "et", NULL((void*)0));
3198 insert_locales (encodings, "KOI8-R", "ru", NULL((void*)0));
3199 insert_locales (encodings, "KOI8-U", "uk", NULL((void*)0));
3200 if (check_locale ("TCVN-5712")) {
3201 insert_locales (encodings, "TCVN-5712", "vi", NULL((void*)0));
3202 } else {
3203 insert_locales (encodings, "TCVN", "vi", NULL((void*)0));
3204 }
3205 insert_locales (encodings, "TIS-620", "th", NULL((void*)0));
3206 /*insert_locales (encodings, "VISCII", NULL);*/
3207
3208 return encodings;
3209}
3210
3211static const char *
3212get_encoding_from_locale (const char *locale)
3213{
3214 char lang[3];
3215 const char *encoding;
3216 static GHashTable *encodings = NULL((void*)0);
3217
3218 if (locale == NULL((void*)0))
3219 return NULL((void*)0);
3220
3221 /* if locale includes encoding, use it */
3222 encoding = strchr (locale, '.');
3223 if (encoding != NULL((void*)0)) {
3224 return encoding+1;
3225 }
3226
3227 if (encodings == NULL((void*)0))
3228 encodings = init_encodings ();
3229
3230 /* first try the entire locale (at this point ll_CC) */
3231 encoding = g_hash_table_lookup (encodings, locale);
3232 if (encoding != NULL((void*)0))
3233 return encoding;
3234
3235 /* Try just the language */
3236 strncpy (lang, locale, 2);
3237 lang[2] = '\0';
3238 return g_hash_table_lookup (encodings, lang);
3239}
3240
3241static Encoding
3242get_encoding (ReadBuf *rb)
3243{
3244 gboolean old_kde = FALSE(0);
3245 char buf [BUFSIZ8192];
3246 gboolean all_valid_utf8 = TRUE(!(0));
3247
3248 while (readbuf_gets (buf, sizeof (buf), rb) != NULL((void*)0)) {
3249 if (strncmp (MATE_DESKTOP_ITEM_ENCODING"Encoding",
3250 buf,
3251 strlen (MATE_DESKTOP_ITEM_ENCODING"Encoding")) == 0) {
3252 char *p = &buf[strlen (MATE_DESKTOP_ITEM_ENCODING"Encoding")];
3253 if (*p == ' ')
3254 p++;
3255 if (*p != '=')
3256 continue;
3257 p++;
3258 if (*p == ' ')
3259 p++;
3260 if (strcmp (p, "UTF-8") == 0) {
3261 return ENCODING_UTF8;
3262 } else if (strcmp (p, "Legacy-Mixed") == 0) {
3263 return ENCODING_LEGACY_MIXED;
3264 } else {
3265 /* According to the spec we're not supposed
3266 * to read a file like this */
3267 return ENCODING_UNKNOWN;
3268 }
3269 } else if (strcmp ("[KDE Desktop Entry]", buf) == 0) {
3270 old_kde = TRUE(!(0));
3271 /* don't break yet, we still want to support
3272 * Encoding even here */
3273 }
3274 if (all_valid_utf8 && ! g_utf8_validate (buf, -1, NULL((void*)0)))
3275 all_valid_utf8 = FALSE(0);
3276 }
3277
3278 if (old_kde)
3279 return ENCODING_LEGACY_MIXED;
3280
3281 /* try to guess by location */
3282 if (rb->uri != NULL((void*)0) && strstr (rb->uri, "mate/apps/") != NULL((void*)0)) {
3283 /* old mate */
3284 return ENCODING_LEGACY_MIXED;
3285 }
3286
3287 /* A dilemma, new KDE files are in UTF-8 but have no Encoding
3288 * info, at this time we really can't tell. The best thing to
3289 * do right now is to just assume UTF-8 if the whole file
3290 * validates as utf8 I suppose */
3291
3292 if (all_valid_utf8)
3293 return ENCODING_UTF8;
3294 else
3295 return ENCODING_LEGACY_MIXED;
3296}
3297
3298static char *
3299decode_string (const char *value, Encoding encoding, const char *locale)
3300{
3301 char *retval = NULL((void*)0);
3302
3303 /* if legacy mixed, then convert */
3304 if (locale != NULL((void*)0) && encoding == ENCODING_LEGACY_MIXED) {
3305 const char *char_encoding = get_encoding_from_locale (locale);
3306 char *utf8_string;
3307 if (char_encoding == NULL((void*)0))
3308 return NULL((void*)0);
3309 if (strcmp (char_encoding, "ASCII") == 0) {
3310 return decode_string_and_dup (value);
3311 }
3312 utf8_string = g_convert (value, -1, "UTF-8", char_encoding,
3313 NULL((void*)0), NULL((void*)0), NULL((void*)0));
3314 if (utf8_string == NULL((void*)0))
3315 return NULL((void*)0);
3316 retval = decode_string_and_dup (utf8_string);
3317 g_free (utf8_string);
3318 return retval;
3319 /* if utf8, then validate */
3320 } else if (locale != NULL((void*)0) && encoding == ENCODING_UTF8) {
3321 if ( ! g_utf8_validate (value, -1, NULL((void*)0)))
3322 /* invalid utf8, ignore this key */
3323 return NULL((void*)0);
3324 return decode_string_and_dup (value);
3325 } else {
3326 /* Meaning this is not a localized string */
3327 return decode_string_and_dup (value);
3328 }
3329}
3330
3331static char *
3332snarf_locale_from_key (const char *key)
3333{
3334 const char *brace;
3335 char *locale, *p;
3336
3337 brace = strchr (key, '[');
3338 if (brace == NULL((void*)0))
3339 return NULL((void*)0);
3340
3341 locale = g_strdup (brace + 1)g_strdup_inline (brace + 1);
3342 if (*locale == '\0') {
3343 g_free (locale);
3344 return NULL((void*)0);
3345 }
3346 p = strchr (locale, ']');
3347 if (p == NULL((void*)0)) {
3348 g_free (locale);
3349 return NULL((void*)0);
3350 }
3351 *p = '\0';
3352 return locale;
3353}
3354
3355static void
3356insert_key (MateDesktopItem *item,
3357 Section *cur_section,
3358 Encoding encoding,
3359 const char *key,
3360 const char *value,
3361 gboolean old_kde,
3362 gboolean no_translations)
3363{
3364 char *k;
3365 char *val;
3366 /* we always store everything in UTF-8 */
3367 if (cur_section == NULL((void*)0) &&
3368 strcmp (key, MATE_DESKTOP_ITEM_ENCODING"Encoding") == 0) {
3369 k = g_strdup (key)g_strdup_inline (key);
3370 val = g_strdup ("UTF-8")g_strdup_inline ("UTF-8");
3371 } else {
3372 char *locale = snarf_locale_from_key (key);
3373 /* If we're ignoring translations */
3374 if (no_translations && locale != NULL((void*)0)) {
3375 g_free (locale);
3376 return;
3377 }
3378 val = decode_string (value, encoding, locale);
3379
3380 /* Ignore this key, it's whacked */
3381 if (val == NULL((void*)0)) {
3382 g_free (locale);
3383 return;
3384 }
3385
3386 g_strchomp (val);
3387
3388 /* For old KDE entries, we can also split by a comma
3389 * on sort order, so convert to semicolons */
3390 if (old_kde &&
3391 cur_section == NULL((void*)0) &&
3392 strcmp (key, MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder") == 0 &&
3393 strchr (val, ';') == NULL((void*)0)) {
3394 int i;
3395 for (i = 0; val[i] != '\0'; i++) {
3396 if (val[i] == ',')
3397 val[i] = ';';
3398 }
3399 }
3400
3401 /* Check some types, not perfect, but catches a lot
3402 * of things */
3403 if (cur_section == NULL((void*)0)) {
3404 char *cannon = cannonize (key, val);
3405 if (cannon != NULL((void*)0)) {
3406 g_free (val);
3407 val = cannon;
3408 }
3409 }
3410
3411 k = g_strdup (key)g_strdup_inline (key);
3412
3413 /* Take care of the language part */
3414 if (locale != NULL((void*)0) &&
3415 strcmp (locale, "C") == 0) {
3416 char *p;
3417 /* Whack C locale */
3418 p = strchr (k, '[');
3419 *p = '\0';
3420 g_free (locale);
3421 } else if (locale != NULL((void*)0)) {
3422 char *p, *brace;
3423
3424 /* Whack the encoding part */
3425 p = strchr (locale, '.');
3426 if (p != NULL((void*)0))
3427 *p = '\0';
3428
3429 if (g_list_find_custom (item->languages, locale,
3430 (GCompareFunc)strcmp) == NULL((void*)0)) {
3431 item->languages = g_list_prepend
3432 (item->languages, locale);
3433 } else {
3434 g_free (locale);
3435 }
3436
3437 /* Whack encoding from encoding in the key */
3438 brace = strchr (k, '[');
3439 p = strchr (brace, '.');
3440 if (p != NULL((void*)0)) {
3441 *p = ']';
3442 *(p+1) = '\0';
3443 }
3444 }
3445 }
3446
3447 if (cur_section == NULL((void*)0)) {
3448 /* only add to list if we haven't seen it before */
3449 if (g_hash_table_lookup (item->main_hash, k) == NULL((void*)0)) {
3450 item->keys = g_list_prepend (item->keys,
3451 g_strdup (k)g_strdup_inline (k));
3452 }
3453 /* later duplicates override earlier ones */
3454 g_hash_table_replace (item->main_hash, k, val);
3455 } else {
3456 char *full = g_strdup_printf
3457 ("%s/%s",
3458 cur_section->name, k);
3459 /* only add to list if we haven't seen it before */
3460 if (g_hash_table_lookup (item->main_hash, full) == NULL((void*)0)) {
3461 cur_section->keys =
3462 g_list_prepend (cur_section->keys, k);
3463 }
3464 /* later duplicates override earlier ones */
3465 g_hash_table_replace (item->main_hash,
3466 full, val);
3467 }
3468}
3469
3470static void
3471setup_type (MateDesktopItem *item, const char *uri)
3472{
3473 const char *type = g_hash_table_lookup (item->main_hash,
3474 MATE_DESKTOP_ITEM_TYPE"Type");
3475 if (type == NULL((void*)0) && uri != NULL((void*)0)) {
3476 char *base = g_path_get_basename (uri);
3477 if (base != NULL((void*)0) &&
3478 strcmp (base, ".directory") == 0) {
3479 /* This gotta be a directory */
3480 g_hash_table_replace (item->main_hash,
3481 g_strdup (MATE_DESKTOP_ITEM_TYPE)g_strdup_inline ("Type"),
3482 g_strdup ("Directory")g_strdup_inline ("Directory"));
3483 item->keys = g_list_prepend
3484 (item->keys, g_strdup (MATE_DESKTOP_ITEM_TYPE)g_strdup_inline ("Type"));
3485 item->type = MATE_DESKTOP_ITEM_TYPE_DIRECTORY;
3486 } else {
3487 item->type = MATE_DESKTOP_ITEM_TYPE_NULL;
3488 }
3489 g_free (base);
3490 } else {
3491 item->type = type_from_string (type);
3492 }
3493}
3494
3495/* fallback to find something suitable for C locale */
3496static char *
3497try_english_key (MateDesktopItem *item, const char *key)
3498{
3499 char *str;
3500 char *locales[] = { "en_US", "en_GB", "en_AU", "en", NULL((void*)0) };
3501 int i;
3502
3503 str = NULL((void*)0);
3504 for (i = 0; locales[i] != NULL((void*)0) && str == NULL((void*)0); i++) {
3505 str = g_strdup (lookup_locale (item, key, locales[i]))g_strdup_inline (lookup_locale (item, key, locales[i]));
3506 }
3507 if (str != NULL((void*)0)) {
3508 /* We need a 7-bit ascii string, so whack all
3509 * above 127 chars */
3510 guchar *p;
3511 for (p = (guchar *)str; *p != '\0'; p++) {
3512 if (*p > 127)
3513 *p = '?';
3514 }
3515 }
3516 return str;
3517}
3518
3519static void
3520sanitize (MateDesktopItem *item, const char *uri)
3521{
3522 const char *type;
3523
3524 type = lookup (item, MATE_DESKTOP_ITEM_TYPE"Type");
3525
3526 /* understand old mate style url exec thingies */
3527 if (type != NULL((void*)0) && strcmp (type, "URL") == 0) {
3528 const char *exec = lookup (item, MATE_DESKTOP_ITEM_EXEC"Exec");
3529 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Link");
3530 if (exec != NULL((void*)0)) {
3531 /* Note, this must be in this order */
3532 set (item, MATE_DESKTOP_ITEM_URL"URL", exec);
3533 set (item, MATE_DESKTOP_ITEM_EXEC"Exec", NULL((void*)0));
3534 }
3535 }
3536
3537 /* we make sure we have Name, Encoding and Version */
3538 if (lookup (item, MATE_DESKTOP_ITEM_NAME"Name") == NULL((void*)0)) {
3539 char *name = try_english_key (item, MATE_DESKTOP_ITEM_NAME"Name");
3540 /* If no name, use the basename */
3541 if (name == NULL((void*)0) && uri != NULL((void*)0))
3542 name = g_path_get_basename (uri);
3543 /* If no uri either, use same default as mate_desktop_item_new */
3544 if (name == NULL((void*)0)) {
3545 /* Translators: the "name" mentioned here is the name of
3546 * an application or a document */
3547 name = g_strdup (_("No name"))g_strdup_inline (((char *) g_dgettext ("mate-desktop", "No name"
)))
;
3548 }
3549 g_hash_table_replace (item->main_hash,
3550 g_strdup (MATE_DESKTOP_ITEM_NAME)g_strdup_inline ("Name"),
3551 name);
3552 item->keys = g_list_prepend
3553 (item->keys, g_strdup (MATE_DESKTOP_ITEM_NAME)g_strdup_inline ("Name"));
3554 }
3555 if (lookup (item, MATE_DESKTOP_ITEM_ENCODING"Encoding") == NULL((void*)0)) {
3556 /* We store everything in UTF-8 so write that down */
3557 g_hash_table_replace (item->main_hash,
3558 g_strdup (MATE_DESKTOP_ITEM_ENCODING)g_strdup_inline ("Encoding"),
3559 g_strdup ("UTF-8")g_strdup_inline ("UTF-8"));
3560 item->keys = g_list_prepend
3561 (item->keys, g_strdup (MATE_DESKTOP_ITEM_ENCODING)g_strdup_inline ("Encoding"));
3562 }
3563 if (lookup (item, MATE_DESKTOP_ITEM_VERSION"Version") == NULL((void*)0)) {
3564 /* this is the version that we follow, so write it down */
3565 g_hash_table_replace (item->main_hash,
3566 g_strdup (MATE_DESKTOP_ITEM_VERSION)g_strdup_inline ("Version"),
3567 g_strdup ("1.0")g_strdup_inline ("1.0"));
3568 item->keys = g_list_prepend
3569 (item->keys, g_strdup (MATE_DESKTOP_ITEM_VERSION)g_strdup_inline ("Version"));
3570 }
3571}
3572
3573enum {
3574 FirstBrace,
3575 OnSecHeader,
3576 IgnoreToEOL,
3577 IgnoreToEOLFirst,
3578 KeyDef,
3579 KeyDefOnKey,
3580 KeyValue
3581};
3582
3583static MateDesktopItem *
3584ditem_load (ReadBuf *rb,
3585 gboolean no_translations,
3586 GError **error)
3587{
3588 int state;
3589 char CharBuffer [1024];
3590 char *next = CharBuffer;
3591 int c;
3592 Encoding encoding;
3593 MateDesktopItem *item;
3594 Section *cur_section = NULL((void*)0);
3595 char *key = NULL((void*)0);
3596 gboolean old_kde = FALSE(0);
3597
3598 encoding = get_encoding (rb);
3599 if (encoding == ENCODING_UNKNOWN) {
3600 /* spec says, don't read this file */
3601 g_set_error (error,
3602 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
3603 MATE_DESKTOP_ITEM_ERROR_UNKNOWN_ENCODING,
3604 _("Unknown encoding of: %s")((char *) g_dgettext ("mate-desktop", "Unknown encoding of: %s"
))
,
3605 rb->uri);
3606 readbuf_close (rb);
3607 return NULL((void*)0);
3608 }
3609
3610 /* Rewind since get_encoding goes through the file */
3611 if (! readbuf_rewind (rb, error)) {
3612 readbuf_close (rb);
3613 /* spec says, don't read this file */
3614 return NULL((void*)0);
3615 }
3616
3617 item = mate_desktop_item_new ();
3618 item->modified = FALSE(0);
3619
3620 /* Note: location and mtime are filled in by the new_from_file
3621 * function since it has those values */
3622
3623#define OVERFLOW (next == &CharBuffer [sizeof(CharBuffer)-1])
3624
3625 state = FirstBrace;
3626 while ((c = readbuf_getc (rb)) != EOF(-1)) {
3627 if (c == '\r') /* Ignore Carriage Return */
3628 continue;
3629
3630 switch (state) {
3631
3632 case OnSecHeader:
3633 if (c == ']' || OVERFLOW) {
3634 *next = '\0';
3635 next = CharBuffer;
3636
3637 /* keys were inserted in reverse */
3638 if (cur_section != NULL((void*)0) &&
3639 cur_section->keys != NULL((void*)0)) {
3640 cur_section->keys = g_list_reverse
3641 (cur_section->keys);
3642 }
3643 if (strcmp (CharBuffer,
3644 "KDE Desktop Entry") == 0) {
3645 /* Main section */
3646 cur_section = NULL((void*)0);
3647 old_kde = TRUE(!(0));
3648 } else if (strcmp (CharBuffer,
3649 "Desktop Entry") == 0) {
3650 /* Main section */
3651 cur_section = NULL((void*)0);
3652 } else {
3653 cur_section = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
3654 cur_section->name =
3655 g_strdup (CharBuffer)g_strdup_inline (CharBuffer);
3656 cur_section->keys = NULL((void*)0);
3657 item->sections = g_list_prepend
3658 (item->sections, cur_section);
3659 }
3660 state = IgnoreToEOL;
3661 } else if (c == '[') {
3662 /* FIXME: probably error out instead of ignoring this */
3663 } else {
3664 *next++ = c;
3665 }
3666 break;
3667
3668 case IgnoreToEOL:
3669 case IgnoreToEOLFirst:
3670 if (c == '\n'){
3671 if (state == IgnoreToEOLFirst)
3672 state = FirstBrace;
3673 else
3674 state = KeyDef;
3675 next = CharBuffer;
3676 }
3677 break;
3678
3679 case FirstBrace:
3680 case KeyDef:
3681 case KeyDefOnKey:
3682 if (c == '#') {
3683 if (state == FirstBrace)
3684 state = IgnoreToEOLFirst;
3685 else
3686 state = IgnoreToEOL;
3687 break;
3688 }
3689
3690 if (c == '[' && state != KeyDefOnKey){
3691 state = OnSecHeader;
3692 next = CharBuffer;
3693 g_free (key);
3694 key = NULL((void*)0);
3695 break;
3696 }
3697 /* On first pass, don't allow dangling keys */
3698 if (state == FirstBrace)
3699 break;
3700
3701 if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
3702 break;
3703
3704 if (c == '\n' || OVERFLOW) { /* Abort Definition */
3705 next = CharBuffer;
3706 state = KeyDef;
3707 break;
3708 }
3709
3710 if (c == '=' || OVERFLOW){
3711 *next = '\0';
3712
3713 g_free (key);
3714 key = g_strdup (CharBuffer)g_strdup_inline (CharBuffer);
3715 state = KeyValue;
3716 next = CharBuffer;
3717 } else {
3718 *next++ = c;
3719 state = KeyDefOnKey;
3720 }
3721 break;
3722
3723 case KeyValue:
3724 if (OVERFLOW || c == '\n'){
3725 *next = '\0';
3726
3727 insert_key (item, cur_section, encoding,
3728 key, CharBuffer, old_kde,
3729 no_translations);
3730
3731 g_free (key);
3732 key = NULL((void*)0);
3733
3734 state = (c == '\n') ? KeyDef : IgnoreToEOL;
3735 next = CharBuffer;
3736 } else {
3737 *next++ = c;
3738 }
3739 break;
3740
3741 } /* switch */
3742
3743 } /* while ((c = getc_unlocked (f)) != EOF) */
3744 if (c == EOF(-1) && state == KeyValue) {
3745 *next = '\0';
3746
3747 insert_key (item, cur_section, encoding,
3748 key, CharBuffer, old_kde,
3749 no_translations);
3750
3751 g_free (key);
3752 key = NULL((void*)0);
3753 }
3754
3755#undef OVERFLOW
3756
3757 /* keys were inserted in reverse */
3758 if (cur_section != NULL((void*)0) &&
3759 cur_section->keys != NULL((void*)0)) {
3760 cur_section->keys = g_list_reverse (cur_section->keys);
3761 }
3762 /* keys were inserted in reverse */
3763 item->keys = g_list_reverse (item->keys);
3764 /* sections were inserted in reverse */
3765 item->sections = g_list_reverse (item->sections);
3766
3767 /* sanitize some things */
3768 sanitize (item, rb->uri);
3769
3770 /* make sure that we set up the type */
3771 setup_type (item, rb->uri);
3772
3773 readbuf_close (rb);
3774
3775 return item;
3776}
3777
3778static void stream_printf (GFileOutputStream *stream,
3779 const char *format, ...) G_GNUC_PRINTF (2, 3)__attribute__((__format__ (__printf__, 2, 3)));
3780
3781static void
3782stream_printf (GFileOutputStream *stream, const char *format, ...)
3783{
3784 va_list args;
3785 gchar *s;
3786
3787 va_start (args, format)__builtin_va_start(args, format);
3788 s = g_strdup_vprintf (format, args);
3789 va_end (args)__builtin_va_end(args);
3790
3791 /* FIXME: what about errors */
3792 g_output_stream_write (G_OUTPUT_STREAM (stream)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((stream)), ((g_output_stream_get_type ()))))))
, s, strlen (s),
3793 NULL((void*)0), NULL((void*)0));
3794 g_free (s);
3795}
3796
3797static void
3798dump_section (MateDesktopItem *item, GFileOutputStream *stream, Section *section)
3799{
3800 GList *li;
3801
3802 stream_printf (stream, "[%s]\n", section->name);
3803 for (li = section->keys; li != NULL((void*)0); li = li->next) {
3804 const char *key = li->data;
3805 char *full = g_strdup_printf ("%s/%s", section->name, key);
3806 const char *value = g_hash_table_lookup (item->main_hash, full);
3807 if (value != NULL((void*)0)) {
3808 char *val = escape_string_and_dup (value);
3809 stream_printf (stream, "%s=%s\n", key, val);
3810 g_free (val);
3811 }
3812 g_free (full);
3813 }
3814}
3815
3816static gboolean
3817ditem_save (MateDesktopItem *item, const char *uri, GError **error)
3818{
3819 GList *li;
3820 GFile *file;
3821 GFileOutputStream *stream;
3822
3823 file = g_file_new_for_uri (uri);
3824 stream = g_file_replace (file, NULL((void*)0), FALSE(0), G_FILE_CREATE_NONE,
3825 NULL((void*)0), error);
3826 if (stream == NULL((void*)0))
5
Assuming 'stream' is not equal to NULL
6
Taking false branch
3827 return FALSE(0);
3828
3829 stream_printf (stream, "[Desktop Entry]\n");
3830 for (li = item->keys; li != NULL((void*)0); li = li->next) {
7
Assuming 'li' is not equal to NULL
8
Loop condition is true. Entering loop body
3831 const char *key = li->data;
3832 const char *value = g_hash_table_lookup (item->main_hash, key);
3833 if (value != NULL((void*)0)) {
9
Assuming 'value' is not equal to NULL
10
Taking true branch
3834 char *val = escape_string_and_dup (value);
11
Calling 'escape_string_and_dup'
3835 stream_printf (stream, "%s=%s\n", key, val);
3836 g_free (val);
3837 }
3838 }
3839
3840 if (item->sections != NULL((void*)0))
3841 stream_printf (stream, "\n");
3842
3843 for (li = item->sections; li != NULL((void*)0); li = li->next) {
3844 Section *section = li->data;
3845
3846 /* Don't write empty sections */
3847 if (section->keys == NULL((void*)0))
3848 continue;
3849
3850 dump_section (item, stream, section);
3851
3852 if (li->next != NULL((void*)0))
3853 stream_printf (stream, "\n");
3854 }
3855
3856 g_object_unref (stream);
3857 g_object_unref (file);
3858
3859 return TRUE(!(0));
3860}
3861
3862static gpointer
3863_mate_desktop_item_copy (gpointer boxed)
3864{
3865 return mate_desktop_item_copy (boxed);
3866}
3867
3868static void
3869_mate_desktop_item_free (gpointer boxed)
3870{
3871 mate_desktop_item_unref (boxed);
3872}
3873
3874GType
3875mate_desktop_item_get_type (void)
3876{
3877 static GType type = 0;
3878
3879 if (type == 0) {
3880 type = g_boxed_type_register_static ("MateDesktopItem",
3881 _mate_desktop_item_copy,
3882 _mate_desktop_item_free);
3883 }
3884
3885 return type;
3886}
3887
3888GQuark
3889mate_desktop_item_error_quark (void)
3890{
3891 static GQuark q = 0;
3892 if (q == 0)
3893 q = g_quark_from_static_string ("mate-desktop-item-error-quark");
3894
3895 return q;
3896}
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-4a69b4.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-4a69b4.html new file mode 100644 index 0000000..feb7adb --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-4a69b4.html @@ -0,0 +1,2115 @@ + + + +mate-hsv.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-hsv.c
Warning:line 652, column 20
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-hsv.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-hsv.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* HSV color selector for GTK+
2 *
3 * Copyright (C) 1999 The Free Software Foundation
4 * Copyright (C) 2019-2021 MATE Developers
5 *
6 * Authors: Simon Budig <Simon.Budig@unix-ag.org> (original code)
7 * Federico Mena-Quintero <federico@gimp.org> (cleanup for GTK+)
8 * Jonathan Blandford <jrb@redhat.com> (cleanup for GTK+)
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
26 * file for a list of people on the GTK+ Team. See the ChangeLog
27 * files for a list of changes. These files are distributed with
28 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29 *
30 * Modified to work internally in mate-desktop by Pablo Barciela 2019
31 */
32
33#ifdef HAVE_CONFIG_H1
34#include "config.h"
35#endif
36
37#include "mate-hsv.h"
38
39#include <math.h>
40#include <string.h>
41
42#include <gtk/gtk.h>
43
44#define I_(string)g_intern_static_string (string) g_intern_static_string (string)
45
46/**
47 * SECTION:mate-hsv
48 * @Short_description: A “color wheel” widget
49 * @Title: MateHSV
50 *
51 * #MateHSV is the “color wheel” part of a complete color selector widget.
52 * It allows to select a color by determining its HSV components in an
53 * intuitive way. Moving the selection around the outer ring changes the hue,
54 * and moving the selection point inside the inner triangle changes value and
55 * saturation.
56 */
57
58/* Default width/height */
59#define DEFAULT_SIZE100 100
60
61/* Default ring width */
62#define DEFAULT_RING_WIDTH10 10
63
64/* Dragging modes */
65typedef enum {
66 DRAG_NONE,
67 DRAG_H,
68 DRAG_SV
69} DragMode;
70
71/* Private part of the MateHSV structure */
72struct _MateHSVPrivate
73{
74 /* Color value */
75 double h;
76 double s;
77 double v;
78
79 /* Size and ring width */
80 int size;
81 int ring_width;
82
83 /* Window for capturing events */
84 GdkWindow *window;
85
86 /* Dragging mode */
87 DragMode mode;
88
89 guint focus_on_ring : 1;
90};
91
92/* Signal IDs */
93
94enum {
95 CHANGED,
96 MOVE,
97 LAST_SIGNAL
98};
99
100static void mate_hsv_destroy (GtkWidget *widget);
101static void mate_hsv_realize (GtkWidget *widget);
102static void mate_hsv_unrealize (GtkWidget *widget);
103static void mate_hsv_get_preferred_width (GtkWidget *widget,
104 gint *minimum,
105 gint *natural);
106static void mate_hsv_get_preferred_height (GtkWidget *widget,
107 gint *minimum,
108 gint *natural);
109static void mate_hsv_size_allocate (GtkWidget *widget,
110 GtkAllocation *allocation);
111static gboolean mate_hsv_button_press (GtkWidget *widget,
112 GdkEventButton *event);
113static gboolean mate_hsv_button_release (GtkWidget *widget,
114 GdkEventButton *event);
115static gboolean mate_hsv_motion (GtkWidget *widget,
116 GdkEventMotion *event);
117static gboolean mate_hsv_draw (GtkWidget *widget,
118 cairo_t *cr);
119static gboolean mate_hsv_grab_broken (GtkWidget *widget,
120 GdkEventGrabBroken *event);
121static gboolean mate_hsv_focus (GtkWidget *widget,
122 GtkDirectionType direction);
123static void mate_hsv_move (MateHSV *hsv,
124 GtkDirectionType dir);
125
126static guint hsv_signals[LAST_SIGNAL];
127
128G_DEFINE_TYPE_WITH_PRIVATE (MateHSV, mate_hsv, GTK_TYPE_WIDGET)static void mate_hsv_init (MateHSV *self); static void mate_hsv_class_init
(MateHSVClass *klass); static GType mate_hsv_get_type_once (
void); static gpointer mate_hsv_parent_class = ((void*)0); static
gint MateHSV_private_offset; static void mate_hsv_class_intern_init
(gpointer klass) { mate_hsv_parent_class = g_type_class_peek_parent
(klass); if (MateHSV_private_offset != 0) g_type_class_adjust_private_offset
(klass, &MateHSV_private_offset); mate_hsv_class_init ((
MateHSVClass*) klass); } __attribute__ ((__unused__)) static inline
gpointer mate_hsv_get_instance_private (MateHSV *self) { return
(((gpointer) ((guint8*) (self) + (glong) (MateHSV_private_offset
)))); } GType mate_hsv_get_type (void) { static gsize static_g_define_type_id
= 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&static_g_define_type_id) : ((void*)0
)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = mate_hsv_get_type_once ()
; (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType mate_hsv_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((gtk_widget_get_type ()), g_intern_static_string ("MateHSV"
), sizeof (MateHSVClass), (GClassInitFunc)(void (*)(void)) mate_hsv_class_intern_init
, sizeof (MateHSV), (GInstanceInitFunc)(void (*)(void)) mate_hsv_init
, (GTypeFlags) 0); { {{ MateHSV_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (MateHSVPrivate)); };} } return g_define_type_id
; }
129
130/* Class initialization function for the HSV color selector */
131static void
132mate_hsv_class_init (MateHSVClass *class)
133{
134 GObjectClass *gobject_class;
135 GtkWidgetClass *widget_class;
136 MateHSVClass *hsv_class;
137 GtkBindingSet *binding_set;
138
139 gobject_class = (GObjectClass *) class;
140 widget_class = (GtkWidgetClass *) class;
141 hsv_class = MATE_HSV_CLASS (class)((((MateHSVClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), ((mate_hsv_get_type ()))))))
;
142
143 widget_class->destroy = mate_hsv_destroy;
144 widget_class->realize = mate_hsv_realize;
145 widget_class->unrealize = mate_hsv_unrealize;
146 widget_class->get_preferred_width = mate_hsv_get_preferred_width;
147 widget_class->get_preferred_height = mate_hsv_get_preferred_height;
148 widget_class->size_allocate = mate_hsv_size_allocate;
149 widget_class->button_press_event = mate_hsv_button_press;
150 widget_class->button_release_event = mate_hsv_button_release;
151 widget_class->motion_notify_event = mate_hsv_motion;
152 widget_class->draw = mate_hsv_draw;
153 widget_class->focus = mate_hsv_focus;
154 widget_class->grab_broken_event = mate_hsv_grab_broken;
155
156 gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_COLOR_CHOOSER);
157
158 hsv_class->move = mate_hsv_move;
159
160 hsv_signals[CHANGED] =
161 g_signal_new (I_("changed")g_intern_static_string ("changed"),
162 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
163 G_SIGNAL_RUN_FIRST,
164 G_STRUCT_OFFSET (MateHSVClass, changed)((glong) __builtin_offsetof(MateHSVClass, changed)),
165 NULL((void*)0), NULL((void*)0),
166 NULL((void*)0),
167 G_TYPE_NONE((GType) ((1) << (2))), 0);
168
169 hsv_signals[MOVE] =
170 g_signal_new (I_("move")g_intern_static_string ("move"),
171 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
172 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
173 G_STRUCT_OFFSET (MateHSVClass, move)((glong) __builtin_offsetof(MateHSVClass, move)),
174 NULL((void*)0), NULL((void*)0),
175 NULL((void*)0),
176 G_TYPE_NONE((GType) ((1) << (2))), 1,
177 GTK_TYPE_DIRECTION_TYPE(gtk_direction_type_get_type ()));
178
179 binding_set = gtk_binding_set_by_class (class);
180
181 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Up0xff52, 0,
182 "move", 1,
183 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_UP);
184 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Up0xff97, 0,
185 "move", 1,
186 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_UP);
187 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Down0xff54, 0,
188 "move", 1,
189 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_DOWN);
190 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Down0xff99, 0,
191 "move", 1,
192 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_DOWN);
193 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right0xff53, 0,
194 "move", 1,
195 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_RIGHT);
196 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right0xff98, 0,
197 "move", 1,
198 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_RIGHT);
199 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left0xff51, 0,
200 "move", 1,
201 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_LEFT);
202 gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left0xff96, 0,
203 "move", 1,
204 G_TYPE_ENUM((GType) ((12) << (2))), GTK_DIR_LEFT);
205}
206
207static void
208mate_hsv_init (MateHSV *hsv)
209{
210 MateHSVPrivate *priv;
211
212 priv = mate_hsv_get_instance_private (hsv);
213 hsv->priv = priv;
214
215 gtk_widget_set_has_window (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
, FALSE(0));
216 gtk_widget_set_can_focus (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
, TRUE(!(0)));
217
218 priv->h = 0.0;
219 priv->s = 0.0;
220 priv->v = 0.0;
221
222 priv->size = DEFAULT_SIZE100;
223 priv->ring_width = DEFAULT_RING_WIDTH10;
224}
225
226static void
227mate_hsv_destroy (GtkWidget *widget)
228{
229 GTK_WIDGET_CLASS (mate_hsv_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((mate_hsv_parent_class)), ((gtk_widget_get_type ()))))))
->destroy (widget);
230}
231
232static void
233mate_hsv_realize (GtkWidget *widget)
234{
235 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
236 MateHSVPrivate *priv = hsv->priv;
237 GtkAllocation allocation;
238 GdkWindow *parent_window;
239 GdkWindowAttr attr;
240 int attr_mask;
241
242 gtk_widget_set_realized (widget, TRUE(!(0)));
243
244 gtk_widget_get_allocation (widget, &allocation);
245
246 attr.window_type = GDK_WINDOW_CHILD;
247 attr.x = allocation.x;
248 attr.y = allocation.y;
249 attr.width = allocation.width;
250 attr.height = allocation.height;
251 attr.wclass = GDK_INPUT_ONLY;
252 attr.event_mask = gtk_widget_get_events (widget);
253 attr.event_mask |= (GDK_KEY_PRESS_MASK
254 | GDK_BUTTON_PRESS_MASK
255 | GDK_BUTTON_RELEASE_MASK
256 | GDK_POINTER_MOTION_MASK
257 | GDK_ENTER_NOTIFY_MASK
258 | GDK_LEAVE_NOTIFY_MASK);
259 attr_mask = GDK_WA_X | GDK_WA_Y;
260
261 parent_window = gtk_widget_get_parent_window (widget);
262 gtk_widget_set_window (widget, parent_window);
263 g_object_ref (parent_window)((__typeof__ (parent_window)) (g_object_ref) (parent_window));
264
265 priv->window = gdk_window_new (parent_window, &attr, attr_mask);
266 gdk_window_set_user_data (priv->window, hsv);
267 gdk_window_show (priv->window);
268}
269
270static void
271mate_hsv_unrealize (GtkWidget *widget)
272{
273 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
274 MateHSVPrivate *priv = hsv->priv;
275
276 gdk_window_set_user_data (priv->window, NULL((void*)0));
277 gdk_window_destroy (priv->window);
278 priv->window = NULL((void*)0);
279
280 GTK_WIDGET_CLASS (mate_hsv_parent_class)((((GtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((mate_hsv_parent_class)), ((gtk_widget_get_type ()))))))
->unrealize (widget);
281}
282
283static void
284mate_hsv_get_preferred_width (GtkWidget *widget,
285 gint *minimum,
286 gint *natural)
287{
288 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
289 MateHSVPrivate *priv = hsv->priv;
290 gint focus_width;
291 gint focus_pad;
292
293 gtk_widget_style_get (widget,
294 "focus-line-width", &focus_width,
295 "focus-padding", &focus_pad,
296 NULL((void*)0));
297
298 *minimum = priv->size + 2 * (focus_width + focus_pad);
299 *natural = priv->size + 2 * (focus_width + focus_pad);
300}
301
302static void
303mate_hsv_get_preferred_height (GtkWidget *widget,
304 gint *minimum,
305 gint *natural)
306{
307 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
308 MateHSVPrivate *priv = hsv->priv;
309 gint focus_width;
310 gint focus_pad;
311
312 gtk_widget_style_get (widget,
313 "focus-line-width", &focus_width,
314 "focus-padding", &focus_pad,
315 NULL((void*)0));
316
317 *minimum = priv->size + 2 * (focus_width + focus_pad);
318 *natural = priv->size + 2 * (focus_width + focus_pad);
319}
320
321static void
322mate_hsv_size_allocate (GtkWidget *widget,
323 GtkAllocation *allocation)
324{
325 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
326 MateHSVPrivate *priv = hsv->priv;
327
328 gtk_widget_set_allocation (widget, allocation);
329
330 if (gtk_widget_get_realized (widget))
331 gdk_window_move_resize (priv->window,
332 allocation->x,
333 allocation->y,
334 allocation->width,
335 allocation->height);
336}
337
338/* Utility functions */
339
340#define INTENSITY(r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
341
342/* Converts from HSV to RGB */
343static void
344hsv_to_rgb (gdouble *h,
345 gdouble *s,
346 gdouble *v)
347{
348 gdouble hue, saturation, value;
349 gdouble f, p, q, t;
350
351 if (*s == 0.0)
352 {
353 *h = *v;
354 *s = *v;
355 *v = *v; /* heh */
356 }
357 else
358 {
359 hue = *h * 6.0;
360 saturation = *s;
361 value = *v;
362
363 if (hue == 6.0)
364 hue = 0.0;
365
366 f = hue - (int) hue;
367 p = value * (1.0 - saturation);
368 q = value * (1.0 - saturation * f);
369 t = value * (1.0 - saturation * (1.0 - f));
370
371 switch ((int) hue)
372 {
373 case 0:
374 *h = value;
375 *s = t;
376 *v = p;
377 break;
378
379 case 1:
380 *h = q;
381 *s = value;
382 *v = p;
383 break;
384
385 case 2:
386 *h = p;
387 *s = value;
388 *v = t;
389 break;
390
391 case 3:
392 *h = p;
393 *s = q;
394 *v = value;
395 break;
396
397 case 4:
398 *h = t;
399 *s = p;
400 *v = value;
401 break;
402
403 case 5:
404 *h = value;
405 *s = p;
406 *v = q;
407 break;
408
409 default:
410 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-hsv.c", 410
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
411 }
412 }
413}
414
415/* Computes the vertices of the saturation/value triangle */
416static void
417compute_triangle (MateHSV *hsv,
418 gint *hx,
419 gint *hy,
420 gint *sx,
421 gint *sy,
422 gint *vx,
423 gint *vy)
424{
425 MateHSVPrivate *priv = hsv->priv;
426 GtkWidget *widget = GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
;
427 gdouble center_x;
428 gdouble center_y;
429 gdouble inner, outer;
430 gdouble angle;
431
432 center_x = gtk_widget_get_allocated_width (widget) / 2.0;
433 center_y = gtk_widget_get_allocated_height (widget) / 2.0;
434 outer = priv->size / 2.0;
435 inner = outer - priv->ring_width;
436 angle = priv->h * 2.0 * G_PI3.1415926535897932384626433832795028841971693993751;
437
438 *hx = floor (center_x + cos (angle) * inner + 0.5);
439 *hy = floor (center_y - sin (angle) * inner + 0.5);
440 *sx = floor (center_x + cos (angle + 2.0 * G_PI3.1415926535897932384626433832795028841971693993751 / 3.0) * inner + 0.5);
441 *sy = floor (center_y - sin (angle + 2.0 * G_PI3.1415926535897932384626433832795028841971693993751 / 3.0) * inner + 0.5);
442 *vx = floor (center_x + cos (angle + 4.0 * G_PI3.1415926535897932384626433832795028841971693993751 / 3.0) * inner + 0.5);
443 *vy = floor (center_y - sin (angle + 4.0 * G_PI3.1415926535897932384626433832795028841971693993751 / 3.0) * inner + 0.5);
444}
445
446/* Computes whether a point is inside the hue ring */
447static gboolean
448is_in_ring (MateHSV *hsv,
449 gdouble x,
450 gdouble y)
451{
452 MateHSVPrivate *priv = hsv->priv;
453 GtkWidget *widget = GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
;
454 gdouble dx, dy, dist;
455 gdouble center_x;
456 gdouble center_y;
457 gdouble inner, outer;
458
459 center_x = gtk_widget_get_allocated_width (widget) / 2.0;
460 center_y = gtk_widget_get_allocated_height (widget) / 2.0;
461 outer = priv->size / 2.0;
462 inner = outer - priv->ring_width;
463
464 dx = x - center_x;
465 dy = center_y - y;
466 dist = dx * dx + dy * dy;
467
468 return (dist >= inner * inner && dist <= outer * outer);
469}
470
471/* Computes a saturation/value pair based on the mouse coordinates */
472static void
473compute_sv (MateHSV *hsv,
474 gdouble x,
475 gdouble y,
476 gdouble *s,
477 gdouble *v)
478{
479 GtkWidget *widget = GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
;
480 int ihx, ihy, isx, isy, ivx, ivy;
481 double hx, hy, sx, sy, vx, vy;
482 double center_x;
483 double center_y;
484
485 compute_triangle (hsv, &ihx, &ihy, &isx, &isy, &ivx, &ivy);
486 center_x = gtk_widget_get_allocated_width (widget) / 2.0;
487 center_y = gtk_widget_get_allocated_height (widget) / 2.0;
488 hx = ihx - center_x;
489 hy = center_y - ihy;
490 sx = isx - center_x;
491 sy = center_y - isy;
492 vx = ivx - center_x;
493 vy = center_y - ivy;
494 x -= center_x;
495 y = center_y - y;
496
497 if (vx * (x - sx) + vy * (y - sy) < 0.0)
498 {
499 *s = 1.0;
500 *v = (((x - sx) * (hx - sx) + (y - sy) * (hy-sy))
501 / ((hx - sx) * (hx - sx) + (hy - sy) * (hy - sy)));
502
503 if (*v < 0.0)
504 *v = 0.0;
505 else if (*v > 1.0)
506 *v = 1.0;
507 }
508 else if (hx * (x - sx) + hy * (y - sy) < 0.0)
509 {
510 *s = 0.0;
511 *v = (((x - sx) * (vx - sx) + (y - sy) * (vy - sy))
512 / ((vx - sx) * (vx - sx) + (vy - sy) * (vy - sy)));
513
514 if (*v < 0.0)
515 *v = 0.0;
516 else if (*v > 1.0)
517 *v = 1.0;
518 }
519 else if (sx * (x - hx) + sy * (y - hy) < 0.0)
520 {
521 *v = 1.0;
522 *s = (((x - vx) * (hx - vx) + (y - vy) * (hy - vy)) /
523 ((hx - vx) * (hx - vx) + (hy - vy) * (hy - vy)));
524
525 if (*s < 0.0)
526 *s = 0.0;
527 else if (*s > 1.0)
528 *s = 1.0;
529 }
530 else
531 {
532 *v = (((x - sx) * (hy - vy) - (y - sy) * (hx - vx))
533 / ((vx - sx) * (hy - vy) - (vy - sy) * (hx - vx)));
534
535 if (*v<= 0.0)
536 {
537 *v = 0.0;
538 *s = 0.0;
539 }
540 else
541 {
542 if (*v > 1.0)
543 *v = 1.0;
544
545 if (fabs (hy - vy) < fabs (hx - vx))
546 *s = (x - sx - *v * (vx - sx)) / (*v * (hx - vx));
547 else
548 *s = (y - sy - *v * (vy - sy)) / (*v * (hy - vy));
549
550 if (*s < 0.0)
551 *s = 0.0;
552 else if (*s > 1.0)
553 *s = 1.0;
554 }
555 }
556}
557
558/* Computes whether a point is inside the saturation/value triangle */
559static gboolean
560is_in_triangle (MateHSV *hsv,
561 gdouble x,
562 gdouble y)
563{
564 int hx, hy, sx, sy, vx, vy;
565 double det, s, v;
566
567 compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
568
569 det = (vx - sx) * (hy - sy) - (vy - sy) * (hx - sx);
570
571 s = ((x - sx) * (hy - sy) - (y - sy) * (hx - sx)) / det;
572 v = ((vx - sx) * (y - sy) - (vy - sy) * (x - sx)) / det;
573
574 return (s >= 0.0 && v >= 0.0 && s + v <= 1.0);
575}
576
577/* Computes a value based on the mouse coordinates */
578static double
579compute_v (MateHSV *hsv,
580 gdouble x,
581 gdouble y)
582{
583 GtkWidget *widget = GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
;
584 double center_x;
585 double center_y;
586 double dx, dy;
587 double angle;
588
589 center_x = gtk_widget_get_allocated_width (widget) / 2.0;
590 center_y = gtk_widget_get_allocated_height (widget) / 2.0;
591 dx = x - center_x;
592 dy = center_y - y;
593
594 angle = atan2 (dy, dx);
595 if (angle < 0.0)
596 angle += 2.0 * G_PI3.1415926535897932384626433832795028841971693993751;
597
598 return angle / (2.0 * G_PI3.1415926535897932384626433832795028841971693993751);
599}
600
601/* Event handlers */
602
603static void
604set_cross_grab (MateHSV *hsv,
605 GdkDevice *device,
606 guint32 time)
607{
608 MateHSVPrivate *priv = hsv->priv;
609 GdkCursor *cursor;
610
611 cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
),
612 GDK_CROSSHAIR);
613 gdk_seat_grab (gdk_device_get_seat (device),
614 priv->window,
615 GDK_SEAT_CAPABILITY_ALL_POINTING,
616 FALSE(0),
617 cursor,
618 NULL((void*)0),
619 NULL((void*)0),
620 NULL((void*)0));
621 g_object_unref (cursor);
622}
623
624static gboolean
625mate_hsv_grab_broken (GtkWidget *widget,
626 GdkEventGrabBroken *event)
627{
628 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
629 MateHSVPrivate *priv = hsv->priv;
630
631 priv->mode = DRAG_NONE;
632
633 return TRUE(!(0));
634}
635
636static gint
637mate_hsv_button_press (GtkWidget *widget,
638 GdkEventButton *event)
639{
640 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
641 MateHSVPrivate *priv = hsv->priv;
642 double x, y;
643
644 if (priv->mode != DRAG_NONE || event->button != GDK_BUTTON_PRIMARY(1))
645 return FALSE(0);
646
647 x = event->x;
648 y = event->y;
649
650 if (is_in_ring (hsv, x, y))
651 {
652 priv->mode = DRAG_H;
This statement is never executed
653 set_cross_grab (hsv, gdk_event_get_device ((GdkEvent *) event), event->time);
654
655 mate_hsv_set_color (hsv,
656 compute_v (hsv, x, y),
657 priv->s,
658 priv->v);
659
660 gtk_widget_grab_focus (widget);
661 priv->focus_on_ring = TRUE(!(0));
662
663 return TRUE(!(0));
664 }
665
666 if (is_in_triangle (hsv, x, y))
667 {
668 gdouble s, v;
669
670 priv->mode = DRAG_SV;
671 set_cross_grab (hsv, gdk_event_get_device ((GdkEvent *) event), event->time);
672
673 compute_sv (hsv, x, y, &s, &v);
674 mate_hsv_set_color (hsv, priv->h, s, v);
675
676 gtk_widget_grab_focus (widget);
677 priv->focus_on_ring = FALSE(0);
678
679 return TRUE(!(0));
680 }
681
682 return FALSE(0);
683}
684
685static gint
686mate_hsv_button_release (GtkWidget *widget,
687 GdkEventButton *event)
688{
689 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
690 MateHSVPrivate *priv = hsv->priv;
691 DragMode mode;
692 gdouble x, y;
693
694 if (priv->mode == DRAG_NONE || event->button != GDK_BUTTON_PRIMARY(1))
695 return FALSE(0);
696
697 /* Set the drag mode to DRAG_NONE so that signal handlers for "catched"
698 * can see that this is the final color state.
699 */
700 mode = priv->mode;
701 priv->mode = DRAG_NONE;
702
703 x = event->x;
704 y = event->y;
705
706 if (mode == DRAG_H)
707 {
708 mate_hsv_set_color (hsv, compute_v (hsv, x, y), priv->s, priv->v);
709 }
710 else if (mode == DRAG_SV)
711 {
712 gdouble s, v;
713
714 compute_sv (hsv, x, y, &s, &v);
715 mate_hsv_set_color (hsv, priv->h, s, v);
716 }
717 else
718 {
719 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-hsv.c", 719
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
720 }
721
722 gdk_seat_ungrab (gdk_device_get_seat (gdk_event_get_device ((GdkEvent *) event)));
723
724 return TRUE(!(0));
725}
726
727static gint
728mate_hsv_motion (GtkWidget *widget,
729 GdkEventMotion *event)
730{
731 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
732 MateHSVPrivate *priv = hsv->priv;
733 gdouble x, y;
734
735 if (priv->mode == DRAG_NONE)
736 return FALSE(0);
737
738 gdk_event_request_motions (event);
739 x = event->x;
740 y = event->y;
741
742 if (priv->mode == DRAG_H)
743 {
744 mate_hsv_set_color (hsv, compute_v (hsv, x, y), priv->s, priv->v);
745 return TRUE(!(0));
746 }
747 else if (priv->mode == DRAG_SV)
748 {
749 gdouble s, v;
750
751 compute_sv (hsv, x, y, &s, &v);
752 mate_hsv_set_color (hsv, priv->h, s, v);
753 return TRUE(!(0));
754 }
755
756 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-hsv.c", 756
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
757
758 return FALSE(0);
759}
760
761/* Redrawing */
762
763/* Paints the hue ring */
764static void
765paint_ring (MateHSV *hsv,
766 cairo_t *cr)
767{
768 MateHSVPrivate *priv = hsv->priv;
769 GtkWidget *widget = GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
;
770 int xx, yy, width, height;
771 gdouble dx, dy, dist;
772 gdouble center_x;
773 gdouble center_y;
774 gdouble inner, outer;
775 guint32 *buf, *p;
776 gdouble angle;
777 gdouble hue;
778 gdouble r, g, b;
779 cairo_surface_t *source;
780 cairo_t *source_cr;
781 gint stride;
782
783 width = gtk_widget_get_allocated_width (widget);
784 height = gtk_widget_get_allocated_height (widget);
785
786 center_x = width / 2.0;
787 center_y = height / 2.0;
788
789 outer = priv->size / 2.0;
790 inner = outer - priv->ring_width;
791
792 /* Create an image initialized with the ring colors */
793
794 stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
795 buf = g_new (guint32, height * stride / 4)((guint32 *) g_malloc_n ((height * stride / 4), sizeof (guint32
)))
;
796
797 for (yy = 0; yy < height; yy++)
798 {
799 p = buf + yy * width;
800
801 dy = -(yy - center_y);
802
803 for (xx = 0; xx < width; xx++)
804 {
805 dx = xx - center_x;
806
807 dist = dx * dx + dy * dy;
808 if (dist < ((inner-1) * (inner-1)) || dist > ((outer+1) * (outer+1)))
809 {
810 *p++ = 0;
811 continue;
812 }
813
814 angle = atan2 (dy, dx);
815 if (angle < 0.0)
816 angle += 2.0 * G_PI3.1415926535897932384626433832795028841971693993751;
817
818 hue = angle / (2.0 * G_PI3.1415926535897932384626433832795028841971693993751);
819
820 r = hue;
821 g = 1.0;
822 b = 1.0;
823 hsv_to_rgb (&r, &g, &b);
824
825 *p++ = (((int)(r * 255.0) << 16) |
826 ((int)(g * 255.0) << 8) |
827 (int)(b * 255.0));
828 }
829 }
830
831 source = cairo_image_surface_create_for_data ((unsigned char *)buf,
832 CAIRO_FORMAT_RGB24,
833 width, height, stride);
834
835 /* Now draw the value marker onto the source image, so that it
836 * will get properly clipped at the edges of the ring
837 */
838 source_cr = cairo_create (source);
839
840 r = priv->h;
841 g = 1.0;
842 b = 1.0;
843 hsv_to_rgb (&r, &g, &b);
844
845 if (INTENSITY (r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) > 0.5)
846 cairo_set_source_rgb (source_cr, 0., 0., 0.);
847 else
848 cairo_set_source_rgb (source_cr, 1., 1., 1.);
849
850 cairo_move_to (source_cr, center_x, center_y);
851 cairo_line_to (source_cr,
852 center_x + cos (priv->h * 2.0 * G_PI3.1415926535897932384626433832795028841971693993751) * priv->size / 2,
853 center_y - sin (priv->h * 2.0 * G_PI3.1415926535897932384626433832795028841971693993751) * priv->size / 2);
854 cairo_stroke (source_cr);
855 cairo_destroy (source_cr);
856
857 /* Draw the ring using the source image */
858
859 cairo_save (cr);
860
861 cairo_set_source_surface (cr, source, 0, 0);
862 cairo_surface_destroy (source);
863
864 cairo_set_line_width (cr, priv->ring_width);
865 cairo_new_path (cr);
866 cairo_arc (cr,
867 center_x, center_y,
868 priv->size / 2. - priv->ring_width / 2.,
869 0, 2 * G_PI3.1415926535897932384626433832795028841971693993751);
870 cairo_stroke (cr);
871
872 cairo_restore (cr);
873
874 g_free (buf);
875}
876
877/* Converts an HSV triplet to an integer RGB triplet */
878static void
879get_color (gdouble h,
880 gdouble s,
881 gdouble v,
882 gint *r,
883 gint *g,
884 gint *b)
885{
886 hsv_to_rgb (&h, &s, &v);
887
888 *r = floor (h * 255 + 0.5);
889 *g = floor (s * 255 + 0.5);
890 *b = floor (v * 255 + 0.5);
891}
892
893#define SWAP(a, b, t)((t) = (a), (a) = (b), (b) = (t)) ((t) = (a), (a) = (b), (b) = (t))
894
895#define LERP(a, b, v1, v2, i)(((v2) - (v1) != 0) ? ((a) + ((b) - (a)) * ((i) - (v1)) / ((v2
) - (v1))) : (a))
(((v2) - (v1) != 0) \
896 ? ((a) + ((b) - (a)) * ((i) - (v1)) / ((v2) - (v1))) \
897 : (a))
898
899/* Number of pixels we extend out from the edges when creating
900 * color source to avoid artifacts
901 */
902#define PAD3 3
903
904/* Paints the HSV triangle */
905static void
906paint_triangle (MateHSV *hsv,
907 cairo_t *cr,
908 gboolean draw_focus)
909{
910 MateHSVPrivate *priv = hsv->priv;
911 GtkWidget *widget = GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
;
912 gint hx, hy, sx, sy, vx, vy; /* HSV vertices */
913 gint x1, y1, r1, g1, b1; /* First vertex in scanline order */
914 gint x2, y2, r2, g2, b2; /* Second vertex */
915 gint x3, y3, r3, g3, b3; /* Third vertex */
916 gint t;
917 guint32 *buf, *p, c;
918 gint xl, xr, rl, rr, gl, gr, bl, br; /* Scanline data */
919 gint xx, yy;
920 gint x_interp, y_interp;
921 gint x_start, x_end;
922 cairo_surface_t *source;
923 gdouble r, g, b;
924 gint stride;
925 int width, height;
926 GtkStyleContext *context;
927
928 width = gtk_widget_get_allocated_width (widget);
929 height = gtk_widget_get_allocated_height (widget);
930 /* Compute triangle's vertices */
931
932 compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
933
934 x1 = hx;
935 y1 = hy;
936 get_color (priv->h, 1.0, 1.0, &r1, &g1, &b1);
937
938 x2 = sx;
939 y2 = sy;
940 get_color (priv->h, 1.0, 0.0, &r2, &g2, &b2);
941
942 x3 = vx;
943 y3 = vy;
944 get_color (priv->h, 0.0, 1.0, &r3, &g3, &b3);
945
946 if (y2 > y3)
947 {
948 SWAP (x2, x3, t)((t) = (x2), (x2) = (x3), (x3) = (t));
949 SWAP (y2, y3, t)((t) = (y2), (y2) = (y3), (y3) = (t));
950 SWAP (r2, r3, t)((t) = (r2), (r2) = (r3), (r3) = (t));
951 SWAP (g2, g3, t)((t) = (g2), (g2) = (g3), (g3) = (t));
952 SWAP (b2, b3, t)((t) = (b2), (b2) = (b3), (b3) = (t));
953 }
954
955 if (y1 > y3)
956 {
957 SWAP (x1, x3, t)((t) = (x1), (x1) = (x3), (x3) = (t));
958 SWAP (y1, y3, t)((t) = (y1), (y1) = (y3), (y3) = (t));
959 SWAP (r1, r3, t)((t) = (r1), (r1) = (r3), (r3) = (t));
960 SWAP (g1, g3, t)((t) = (g1), (g1) = (g3), (g3) = (t));
961 SWAP (b1, b3, t)((t) = (b1), (b1) = (b3), (b3) = (t));
962 }
963
964 if (y1 > y2)
965 {
966 SWAP (x1, x2, t)((t) = (x1), (x1) = (x2), (x2) = (t));
967 SWAP (y1, y2, t)((t) = (y1), (y1) = (y2), (y2) = (t));
968 SWAP (r1, r2, t)((t) = (r1), (r1) = (r2), (r2) = (t));
969 SWAP (g1, g2, t)((t) = (g1), (g1) = (g2), (g2) = (t));
970 SWAP (b1, b2, t)((t) = (b1), (b1) = (b2), (b2) = (t));
971 }
972
973 /* Shade the triangle */
974
975 stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
976 buf = g_new (guint32, height * stride / 4)((guint32 *) g_malloc_n ((height * stride / 4), sizeof (guint32
)))
;
977
978 for (yy = 0; yy < height; yy++)
979 {
980 p = buf + yy * width;
981
982 if (yy >= y1 - PAD3 && yy < y3 + PAD3) {
983 y_interp = CLAMP (yy, y1, y3)(((yy) > (y3)) ? (y3) : (((yy) < (y1)) ? (y1) : (yy)));
984
985 if (y_interp < y2)
986 {
987 xl = LERP (x1, x2, y1, y2, y_interp)(((y2) - (y1) != 0) ? ((x1) + ((x2) - (x1)) * ((y_interp) - (
y1)) / ((y2) - (y1))) : (x1))
;
988
989 rl = LERP (r1, r2, y1, y2, y_interp)(((y2) - (y1) != 0) ? ((r1) + ((r2) - (r1)) * ((y_interp) - (
y1)) / ((y2) - (y1))) : (r1))
;
990 gl = LERP (g1, g2, y1, y2, y_interp)(((y2) - (y1) != 0) ? ((g1) + ((g2) - (g1)) * ((y_interp) - (
y1)) / ((y2) - (y1))) : (g1))
;
991 bl = LERP (b1, b2, y1, y2, y_interp)(((y2) - (y1) != 0) ? ((b1) + ((b2) - (b1)) * ((y_interp) - (
y1)) / ((y2) - (y1))) : (b1))
;
992 }
993 else
994 {
995 xl = LERP (x2, x3, y2, y3, y_interp)(((y3) - (y2) != 0) ? ((x2) + ((x3) - (x2)) * ((y_interp) - (
y2)) / ((y3) - (y2))) : (x2))
;
996
997 rl = LERP (r2, r3, y2, y3, y_interp)(((y3) - (y2) != 0) ? ((r2) + ((r3) - (r2)) * ((y_interp) - (
y2)) / ((y3) - (y2))) : (r2))
;
998 gl = LERP (g2, g3, y2, y3, y_interp)(((y3) - (y2) != 0) ? ((g2) + ((g3) - (g2)) * ((y_interp) - (
y2)) / ((y3) - (y2))) : (g2))
;
999 bl = LERP (b2, b3, y2, y3, y_interp)(((y3) - (y2) != 0) ? ((b2) + ((b3) - (b2)) * ((y_interp) - (
y2)) / ((y3) - (y2))) : (b2))
;
1000 }
1001
1002 xr = LERP (x1, x3, y1, y3, y_interp)(((y3) - (y1) != 0) ? ((x1) + ((x3) - (x1)) * ((y_interp) - (
y1)) / ((y3) - (y1))) : (x1))
;
1003
1004 rr = LERP (r1, r3, y1, y3, y_interp)(((y3) - (y1) != 0) ? ((r1) + ((r3) - (r1)) * ((y_interp) - (
y1)) / ((y3) - (y1))) : (r1))
;
1005 gr = LERP (g1, g3, y1, y3, y_interp)(((y3) - (y1) != 0) ? ((g1) + ((g3) - (g1)) * ((y_interp) - (
y1)) / ((y3) - (y1))) : (g1))
;
1006 br = LERP (b1, b3, y1, y3, y_interp)(((y3) - (y1) != 0) ? ((b1) + ((b3) - (b1)) * ((y_interp) - (
y1)) / ((y3) - (y1))) : (b1))
;
1007
1008 if (xl > xr)
1009 {
1010 SWAP (xl, xr, t)((t) = (xl), (xl) = (xr), (xr) = (t));
1011 SWAP (rl, rr, t)((t) = (rl), (rl) = (rr), (rr) = (t));
1012 SWAP (gl, gr, t)((t) = (gl), (gl) = (gr), (gr) = (t));
1013 SWAP (bl, br, t)((t) = (bl), (bl) = (br), (br) = (t));
1014 }
1015
1016 x_start = MAX (xl - PAD, 0)(((xl - 3) > (0)) ? (xl - 3) : (0));
1017 x_end = MIN (xr + PAD, width)(((xr + 3) < (width)) ? (xr + 3) : (width));
1018 x_start = MIN (x_start, x_end)(((x_start) < (x_end)) ? (x_start) : (x_end));
1019
1020 c = (rl << 16) | (gl << 8) | bl;
1021
1022 for (xx = 0; xx < x_start; xx++)
1023 *p++ = c;
1024
1025 for (; xx < x_end; xx++)
1026 {
1027 x_interp = CLAMP (xx, xl, xr)(((xx) > (xr)) ? (xr) : (((xx) < (xl)) ? (xl) : (xx)));
1028
1029 *p++ = ((LERP (rl, rr, xl, xr, x_interp)(((xr) - (xl) != 0) ? ((rl) + ((rr) - (rl)) * ((x_interp) - (
xl)) / ((xr) - (xl))) : (rl))
<< 16) |
1030 (LERP (gl, gr, xl, xr, x_interp)(((xr) - (xl) != 0) ? ((gl) + ((gr) - (gl)) * ((x_interp) - (
xl)) / ((xr) - (xl))) : (gl))
<< 8) |
1031 LERP (bl, br, xl, xr, x_interp)(((xr) - (xl) != 0) ? ((bl) + ((br) - (bl)) * ((x_interp) - (
xl)) / ((xr) - (xl))) : (bl))
);
1032 }
1033
1034 c = (rr << 16) | (gr << 8) | br;
1035
1036 for (; xx < width; xx++)
1037 *p++ = c;
1038 }
1039 }
1040
1041 source = cairo_image_surface_create_for_data ((unsigned char *)buf,
1042 CAIRO_FORMAT_RGB24,
1043 width, height, stride);
1044
1045 /* Draw a triangle with the image as a source */
1046
1047 cairo_set_source_surface (cr, source, 0, 0);
1048 cairo_surface_destroy (source);
1049
1050 cairo_move_to (cr, x1, y1);
1051 cairo_line_to (cr, x2, y2);
1052 cairo_line_to (cr, x3, y3);
1053 cairo_close_path (cr);
1054 cairo_fill (cr);
1055
1056 g_free (buf);
1057
1058 /* Draw value marker */
1059
1060 xx = floor (sx + (vx - sx) * priv->v + (hx - vx) * priv->s * priv->v + 0.5);
1061 yy = floor (sy + (vy - sy) * priv->v + (hy - vy) * priv->s * priv->v + 0.5);
1062
1063 r = priv->h;
1064 g = priv->s;
1065 b = priv->v;
1066 hsv_to_rgb (&r, &g, &b);
1067
1068 context = gtk_widget_get_style_context (widget);
1069
1070 gtk_style_context_save (context);
1071
1072 if (INTENSITY (r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) > 0.5)
1073 {
1074 gtk_style_context_add_class (context, "light-area-focus");
1075 cairo_set_source_rgb (cr, 0., 0., 0.);
1076 }
1077 else
1078 {
1079 gtk_style_context_add_class (context, "dark-area-focus");
1080 cairo_set_source_rgb (cr, 1., 1., 1.);
1081 }
1082
1083#define RADIUS4 4
1084#define FOCUS_RADIUS6 6
1085
1086 cairo_new_path (cr);
1087 cairo_arc (cr, xx, yy, RADIUS4, 0, 2 * G_PI3.1415926535897932384626433832795028841971693993751);
1088 cairo_stroke (cr);
1089
1090 /* Draw focus outline */
1091
1092 if (draw_focus && !priv->focus_on_ring)
1093 {
1094 gint focus_width;
1095 gint focus_pad;
1096
1097 gtk_widget_style_get (widget,
1098 "focus-line-width", &focus_width,
1099 "focus-padding", &focus_pad,
1100 NULL((void*)0));
1101
1102 gtk_render_focus (context, cr,
1103 xx - FOCUS_RADIUS6 - focus_width - focus_pad,
1104 yy - FOCUS_RADIUS6 - focus_width - focus_pad,
1105 2 * (FOCUS_RADIUS6 + focus_width + focus_pad),
1106 2 * (FOCUS_RADIUS6 + focus_width + focus_pad));
1107 }
1108
1109 gtk_style_context_restore (context);
1110}
1111
1112/* Paints the contents of the HSV color selector */
1113static gboolean
1114mate_hsv_draw (GtkWidget *widget,
1115 cairo_t *cr)
1116{
1117 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
1118 MateHSVPrivate *priv = hsv->priv;
1119 gboolean draw_focus;
1120
1121 draw_focus = gtk_widget_has_visible_focus (widget);
1122
1123 paint_ring (hsv, cr);
1124 paint_triangle (hsv, cr, draw_focus);
1125
1126 if (draw_focus && priv->focus_on_ring)
1127 {
1128 GtkStyleContext *context;
1129
1130 context = gtk_widget_get_style_context (widget);
1131
1132 gtk_render_focus (context, cr, 0, 0,
1133 gtk_widget_get_allocated_width (widget),
1134 gtk_widget_get_allocated_height (widget));
1135 }
1136
1137 return FALSE(0);
1138}
1139
1140static gboolean
1141mate_hsv_focus (GtkWidget *widget,
1142 GtkDirectionType dir)
1143{
1144 MateHSV *hsv = MATE_HSV (widget)((((MateHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((mate_hsv_get_type ()))))))
;
1145 MateHSVPrivate *priv = hsv->priv;
1146
1147 if (!gtk_widget_has_focus (widget))
1148 {
1149 if (dir == GTK_DIR_TAB_BACKWARD)
1150 priv->focus_on_ring = FALSE(0);
1151 else
1152 priv->focus_on_ring = TRUE(!(0));
1153
1154 gtk_widget_grab_focus (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
);
1155 return TRUE(!(0));
1156 }
1157
1158 switch (dir)
1159 {
1160 case GTK_DIR_UP:
1161 if (priv->focus_on_ring)
1162 return FALSE(0);
1163 else
1164 priv->focus_on_ring = TRUE(!(0));
1165 break;
1166
1167 case GTK_DIR_DOWN:
1168 if (priv->focus_on_ring)
1169 priv->focus_on_ring = FALSE(0);
1170 else
1171 return FALSE(0);
1172 break;
1173
1174 case GTK_DIR_LEFT:
1175 case GTK_DIR_TAB_BACKWARD:
1176 if (priv->focus_on_ring)
1177 return FALSE(0);
1178 else
1179 priv->focus_on_ring = TRUE(!(0));
1180 break;
1181
1182 case GTK_DIR_RIGHT:
1183 case GTK_DIR_TAB_FORWARD:
1184 if (priv->focus_on_ring)
1185 priv->focus_on_ring = FALSE(0);
1186 else
1187 return FALSE(0);
1188 break;
1189 }
1190
1191 gtk_widget_queue_draw (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
);
1192
1193 return TRUE(!(0));
1194}
1195
1196/**
1197 * mate_hsv_new:
1198 *
1199 * Creates a new HSV color selector.
1200 *
1201 * Returns: A newly-created HSV color selector.
1202 */
1203GtkWidget*
1204mate_hsv_new (void)
1205{
1206 return g_object_new (MATE_TYPE_HSV(mate_hsv_get_type ()), NULL((void*)0));
1207}
1208
1209/**
1210 * mate_hsv_set_color:
1211 * @hsv: An HSV color selector
1212 * @h: Hue
1213 * @s: Saturation
1214 * @v: Value
1215 *
1216 * Sets the current color in an HSV color selector.
1217 * Color component values must be in the [0.0, 1.0] range.
1218 */
1219void
1220mate_hsv_set_color (MateHSV *hsv,
1221 gdouble h,
1222 gdouble s,
1223 gdouble v)
1224{
1225 MateHSVPrivate *priv;
1226
1227 g_return_if_fail (MATE_IS_HSV (hsv))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((mate_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_HSV (hsv)"); return; } } while (0)
;
1228 g_return_if_fail (h >= 0.0 && h <= 1.0)do { if ((h >= 0.0 && h <= 1.0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "h >= 0.0 && h <= 1.0"
); return; } } while (0)
;
1229 g_return_if_fail (s >= 0.0 && s <= 1.0)do { if ((s >= 0.0 && s <= 1.0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "s >= 0.0 && s <= 1.0"
); return; } } while (0)
;
1230 g_return_if_fail (v >= 0.0 && v <= 1.0)do { if ((v >= 0.0 && v <= 1.0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "v >= 0.0 && v <= 1.0"
); return; } } while (0)
;
1231
1232 priv = hsv->priv;
1233
1234 priv->h = h;
1235 priv->s = s;
1236 priv->v = v;
1237
1238 g_signal_emit (hsv, hsv_signals[CHANGED], 0);
1239
1240 gtk_widget_queue_draw (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
);
1241}
1242
1243/**
1244 * mate_hsv_get_color:
1245 * @hsv: An HSV color selector
1246 * @h: (out): Return value for the hue
1247 * @s: (out): Return value for the saturation
1248 * @v: (out): Return value for the value
1249 *
1250 * Queries the current color in an HSV color selector.
1251 * Returned values will be in the [0.0, 1.0] range.
1252 */
1253void
1254mate_hsv_get_color (MateHSV *hsv,
1255 double *h,
1256 double *s,
1257 double *v)
1258{
1259 MateHSVPrivate *priv;
1260
1261 g_return_if_fail (MATE_IS_HSV (hsv))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((mate_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_HSV (hsv)"); return; } } while (0)
;
1262
1263 priv = hsv->priv;
1264
1265 if (h)
1266 *h = priv->h;
1267
1268 if (s)
1269 *s = priv->s;
1270
1271 if (v)
1272 *v = priv->v;
1273}
1274
1275/**
1276 * mate_hsv_set_metrics:
1277 * @hsv: An HSV color selector
1278 * @size: Diameter for the hue ring
1279 * @ring_width: Width of the hue ring
1280 *
1281 * Sets the size and ring width of an HSV color selector.
1282 */
1283void
1284mate_hsv_set_metrics (MateHSV *hsv,
1285 gint size,
1286 gint ring_width)
1287{
1288 MateHSVPrivate *priv;
1289 int same_size;
1290
1291 g_return_if_fail (MATE_IS_HSV (hsv))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((mate_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_HSV (hsv)"); return; } } while (0)
;
1292 g_return_if_fail (size > 0)do { if ((size > 0)) { } else { g_return_if_fail_warning (
"MateDesktop", ((const char*) (__func__)), "size > 0"); return
; } } while (0)
;
1293 g_return_if_fail (ring_width > 0)do { if ((ring_width > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "ring_width > 0"
); return; } } while (0)
;
1294 g_return_if_fail (2 * ring_width + 1 <= size)do { if ((2 * ring_width + 1 <= size)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "2 * ring_width + 1 <= size"
); return; } } while (0)
;
1295
1296 priv = hsv->priv;
1297
1298 same_size = (priv->size == size);
1299
1300 priv->size = size;
1301 priv->ring_width = ring_width;
1302
1303 if (same_size)
1304 gtk_widget_queue_draw (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
);
1305 else
1306 gtk_widget_queue_resize (GTK_WIDGET (hsv)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((gtk_widget_get_type ()))))))
);
1307}
1308
1309/**
1310 * mate_hsv_get_metrics:
1311 * @hsv: An HSV color selector
1312 * @size: (out): Return value for the diameter of the hue ring
1313 * @ring_width: (out): Return value for the width of the hue ring
1314 *
1315 * Queries the size and ring width of an HSV color selector.
1316 */
1317void
1318mate_hsv_get_metrics (MateHSV *hsv,
1319 gint *size,
1320 gint *ring_width)
1321{
1322 MateHSVPrivate *priv;
1323
1324 g_return_if_fail (MATE_IS_HSV (hsv))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((mate_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_HSV (hsv)"); return; } } while (0)
;
1325
1326 priv = hsv->priv;
1327
1328 if (size)
1329 *size = priv->size;
1330
1331 if (ring_width)
1332 *ring_width = priv->ring_width;
1333}
1334
1335/**
1336 * mate_hsv_is_adjusting:
1337 * @hsv: A #MateHSV
1338 *
1339 * An HSV color selector can be said to be adjusting if multiple rapid
1340 * changes are being made to its value, for example, when the user is
1341 * adjusting the value with the mouse. This function queries whether
1342 * the HSV color selector is being adjusted or not.
1343 *
1344 * Returns: %TRUE if clients can ignore changes to the color value,
1345 * since they may be transitory, or %FALSE if they should consider
1346 * the color value status to be final.
1347 */
1348gboolean
1349mate_hsv_is_adjusting (MateHSV *hsv)
1350{
1351 MateHSVPrivate *priv;
1352
1353 g_return_val_if_fail (MATE_IS_HSV (hsv), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((mate_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_HSV (hsv)"); return ((0)); } } while
(0)
;
1354
1355 priv = hsv->priv;
1356
1357 return priv->mode != DRAG_NONE;
1358}
1359
1360static void
1361mate_hsv_move (MateHSV *hsv,
1362 GtkDirectionType dir)
1363{
1364 MateHSVPrivate *priv = hsv->priv;
1365 gdouble hue, sat, val;
1366 gint hx, hy, sx, sy, vx, vy; /* HSV vertices */
1367 gint x, y; /* position in triangle */
1368
1369 hue = priv->h;
1370 sat = priv->s;
1371 val = priv->v;
1372
1373 compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
1374
1375 x = floor (sx + (vx - sx) * priv->v + (hx - vx) * priv->s * priv->v + 0.5);
1376 y = floor (sy + (vy - sy) * priv->v + (hy - vy) * priv->s * priv->v + 0.5);
1377
1378#define HUE_DELTA0.002 0.002
1379 switch (dir)
1380 {
1381 case GTK_DIR_UP:
1382 if (priv->focus_on_ring)
1383 hue += HUE_DELTA0.002;
1384 else
1385 {
1386 y -= 1;
1387 compute_sv (hsv, x, y, &sat, &val);
1388 }
1389 break;
1390
1391 case GTK_DIR_DOWN:
1392 if (priv->focus_on_ring)
1393 hue -= HUE_DELTA0.002;
1394 else
1395 {
1396 y += 1;
1397 compute_sv (hsv, x, y, &sat, &val);
1398 }
1399 break;
1400
1401 case GTK_DIR_LEFT:
1402 if (priv->focus_on_ring)
1403 hue += HUE_DELTA0.002;
1404 else
1405 {
1406 x -= 1;
1407 compute_sv (hsv, x, y, &sat, &val);
1408 }
1409 break;
1410
1411 case GTK_DIR_RIGHT:
1412 if (priv->focus_on_ring)
1413 hue -= HUE_DELTA0.002
1414 ;
1415 else
1416 {
1417 x += 1;
1418 compute_sv (hsv, x, y, &sat, &val);
1419 }
1420 break;
1421
1422 default:
1423 /* we don't care about the tab directions */
1424 break;
1425 }
1426
1427 /* Wrap */
1428 if (hue < 0.0)
1429 hue = 1.0;
1430 else if (hue > 1.0)
1431 hue = 0.0;
1432
1433 mate_hsv_set_color (hsv, hue, sat, val);
1434}
1435
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-563e6a.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-563e6a.html new file mode 100644 index 0000000..7a72353 --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-563e6a.html @@ -0,0 +1,2013 @@ + + + +mate-languages.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-languages.c
Warning:line 1163, column 17
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-languages.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-languages.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright 2008 Red Hat, Inc,
4 * 2007 William Jon McCann <mccann@jhu.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * Written by : William Jon McCann <mccann@jhu.edu>
20 * Ray Strode <rstrode@redhat.com>
21 */
22
23#include "config.h"
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <string.h>
29#include <errno(*__errno_location ()).h>
30#include <dirent.h>
31#include <locale.h>
32#include <langinfo.h>
33#include <sys/stat.h>
34
35#include <glib.h>
36#include <glib/gi18n.h>
37#include <glib/gstdio.h>
38
39#define MATE_DESKTOP_USE_UNSTABLE_API
40#include "mate-languages.h"
41
42#include <langinfo.h>
43#ifndef __LC_LAST13
44#define __LC_LAST13 13
45#endif
46
47#define ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" ISO_CODES_PREFIX"/usr" "/share/xml/iso-codes"
48#define ISO_CODES_LOCALESDIR"/usr" "/share/locale" ISO_CODES_PREFIX"/usr" "/share/locale"
49
50typedef struct _MateLocale {
51 char *id;
52 char *name;
53 char *language_code;
54 char *territory_code;
55 char *codeset;
56 char *modifier;
57} MateLocale;
58
59static GHashTable *mate_languages_map;
60static GHashTable *mate_territories_map;
61static GHashTable *mate_available_locales_map;
62static GHashTable *mate_language_count_map;
63static GHashTable *mate_territory_count_map;
64
65static char * construct_language_name (const char *language,
66 const char *territory,
67 const char *codeset,
68 const char *modifier);
69
70static gboolean language_name_is_valid (const char *language_name);
71
72static void
73mate_locale_free (MateLocale *locale)
74{
75 if (locale == NULL((void*)0)) {
76 return;
77 }
78
79 g_free (locale->id);
80 g_free (locale->name);
81 g_free (locale->codeset);
82 g_free (locale->modifier);
83 g_free (locale->language_code);
84 g_free (locale->territory_code);
85 g_free (locale);
86}
87
88static char *
89normalize_codeset (const char *codeset)
90{
91 if (codeset == NULL((void*)0))
92 return NULL((void*)0);
93
94 if (g_str_equal (codeset, "UTF-8")(strcmp ((const char *) (codeset), (const char *) ("UTF-8")) ==
0)
||
95 g_str_equal (codeset, "utf8")(strcmp ((const char *) (codeset), (const char *) ("utf8")) ==
0)
)
96 return g_strdup ("UTF-8")g_strdup_inline ("UTF-8");
97
98 return g_strdup (codeset)g_strdup_inline (codeset);
99}
100
101/**
102 * mate_parse_locale:
103 * @locale: a locale string
104 * @language_codep: (out) (allow-none) (transfer full): location to
105 * store the language code, or %NULL
106 * @country_codep: (out) (allow-none) (transfer full): location to
107 * store the country code, or %NULL
108 * @codesetp: (out) (allow-none) (transfer full): location to
109 * store the codeset, or %NULL
110 * @modifierp: (out) (allow-none) (transfer full): location to
111 * store the modifier, or %NULL
112 *
113 * Extracts the various components of a locale string of the form
114 * [language[_country][.codeset][@modifier]]. See
115 * http://en.wikipedia.org/wiki/Locale.
116 *
117 * Return value: %TRUE if parsing was successful.
118 *
119 * Since: 1.22
120 */
121gboolean
122mate_parse_locale (const char *locale,
123 char **language_codep,
124 char **country_codep,
125 char **codesetp,
126 char **modifierp)
127{
128 static GRegex *re = NULL((void*)0);
129 GMatchInfo *match_info;
130 gboolean res;
131 gchar *normalized_codeset = NULL((void*)0);
132 gchar *normalized_name = NULL((void*)0);
133 gboolean retval;
134
135 match_info = NULL((void*)0);
136 retval = FALSE(0);
137
138 if (re == NULL((void*)0)) {
139 GError *error = NULL((void*)0);
140 re = g_regex_new ("^(?P<language>[^_.@[:space:]]+)"
141 "(_(?P<territory>[[:upper:]]+))?"
142 "(\\.(?P<codeset>[-_0-9a-zA-Z]+))?"
143 "(@(?P<modifier>[[:ascii:]]+))?$",
144 0, 0, &error);
145 if (re == NULL((void*)0)) {
146 g_warning ("%s", error->message);
147 g_error_free (error);
148 goto out;
149 }
150 }
151
152 if (!g_regex_match (re, locale, 0, &match_info) ||
153 g_match_info_is_partial_match (match_info)) {
154 g_warning ("locale '%s' isn't valid\n", locale);
155 goto out;
156 }
157
158 res = g_match_info_matches (match_info);
159 if (! res) {
160 g_warning ("Unable to parse locale: %s", locale);
161 goto out;
162 }
163
164 retval = TRUE(!(0));
165
166 if (language_codep != NULL((void*)0)) {
167 *language_codep = g_match_info_fetch_named (match_info, "language");
168 }
169
170 if (country_codep != NULL((void*)0)) {
171 *country_codep = g_match_info_fetch_named (match_info, "territory");
172
173 if (*country_codep != NULL((void*)0) &&
174 *country_codep[0] == '\0') {
175 g_free (*country_codep);
176 *country_codep = NULL((void*)0);
177 }
178 }
179
180 if (codesetp != NULL((void*)0)) {
181 *codesetp = g_match_info_fetch_named (match_info, "codeset");
182
183 if (*codesetp != NULL((void*)0) &&
184 *codesetp[0] == '\0') {
185 g_free (*codesetp);
186 *codesetp = NULL((void*)0);
187 }
188 }
189
190 if (modifierp != NULL((void*)0)) {
191 *modifierp = g_match_info_fetch_named (match_info, "modifier");
192
193 if (*modifierp != NULL((void*)0) &&
194 *modifierp[0] == '\0') {
195 g_free (*modifierp);
196 *modifierp = NULL((void*)0);
197 }
198 }
199
200 if (codesetp != NULL((void*)0) && *codesetp != NULL((void*)0)) {
201 normalized_codeset = normalize_codeset (*codesetp);
202 normalized_name = construct_language_name (language_codep ? *language_codep : NULL((void*)0),
203 country_codep ? *country_codep : NULL((void*)0),
204 normalized_codeset,
205 modifierp ? *modifierp : NULL((void*)0));
206
207 if (language_name_is_valid (normalized_name)) {
208 g_free (*codesetp);
209 *codesetp = normalized_codeset;
210 } else {
211 g_free (normalized_codeset);
212 }
213 g_free (normalized_name);
214 }
215
216 out:
217 g_match_info_free (match_info);
218
219 return retval;
220}
221
222static char *
223construct_language_name (const char *language,
224 const char *territory,
225 const char *codeset,
226 const char *modifier)
227{
228 char *name;
229
230 g_assert (language != NULL && language[0] != 0)do { if (language != ((void*)0) && language[0] != 0) ;
else g_assertion_message_expr ("MateDesktop", "mate-languages.c"
, 230, ((const char*) (__func__)), "language != NULL && language[0] != 0"
); } while (0)
;
231 g_assert (territory == NULL || territory[0] != 0)do { if (territory == ((void*)0) || territory[0] != 0) ; else
g_assertion_message_expr ("MateDesktop", "mate-languages.c",
231, ((const char*) (__func__)), "territory == NULL || territory[0] != 0"
); } while (0)
;
232 g_assert (codeset == NULL || codeset[0] != 0)do { if (codeset == ((void*)0) || codeset[0] != 0) ; else g_assertion_message_expr
("MateDesktop", "mate-languages.c", 232, ((const char*) (__func__
)), "codeset == NULL || codeset[0] != 0"); } while (0)
;
233 g_assert (modifier == NULL || modifier[0] != 0)do { if (modifier == ((void*)0) || modifier[0] != 0) ; else g_assertion_message_expr
("MateDesktop", "mate-languages.c", 233, ((const char*) (__func__
)), "modifier == NULL || modifier[0] != 0"); } while (0)
;
234
235 name = g_strdup_printf ("%s%s%s%s%s%s%s",
236 language,
237 territory != NULL((void*)0)? "_" : "",
238 territory != NULL((void*)0)? territory : "",
239 codeset != NULL((void*)0)? "." : "",
240 codeset != NULL((void*)0)? codeset : "",
241 modifier != NULL((void*)0)? "@" : "",
242 modifier != NULL((void*)0)? modifier : "");
243
244 return name;
245}
246
247/**
248 * mate_normalize_locale:
249 * @locale: a locale string
250 *
251 * Gets the normalized locale string in the form
252 * [language[_country][.codeset][@modifier]] for @name.
253 *
254 * Return value: (transfer full): normalized locale string. Caller
255 * takes ownership.
256 *
257 * Since: 1.22
258 */
259char *
260mate_normalize_locale (const char *locale)
261{
262 char *normalized_name;
263 gboolean valid;
264 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
265 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
266 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset = NULL((void*)0);
267 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *modifier = NULL((void*)0);
268
269 if (locale[0] == '\0') {
270 return NULL((void*)0);
271 }
272
273 valid = mate_parse_locale (locale,
274 &language_code,
275 &territory_code,
276 &codeset, &modifier);
277 if (!valid)
278 return NULL((void*)0);
279
280 normalized_name = construct_language_name (language_code,
281 territory_code,
282 codeset, modifier);
283 return normalized_name;
284}
285
286static gboolean
287language_name_is_valid (const char *language_name)
288{
289 gboolean is_valid;
290 int lc_type_id = LC_MESSAGES5;
291 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
292
293 old_locale = g_strdup (setlocale (lc_type_id, NULL))g_strdup_inline (setlocale (lc_type_id, ((void*)0)));
294 is_valid = setlocale (lc_type_id, language_name) != NULL((void*)0);
295 setlocale (lc_type_id, old_locale);
296
297 return is_valid;
298}
299
300static void
301language_name_get_codeset_details (const char *language_name,
302 char **pcodeset,
303 gboolean *is_utf8)
304{
305 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
306 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset = NULL((void*)0);
307
308 old_locale = g_strdup (setlocale (LC_CTYPE, NULL))g_strdup_inline (setlocale (0, ((void*)0)));
309
310 if (setlocale (LC_CTYPE0, language_name) == NULL((void*)0))
311 return;
312
313 codeset = nl_langinfo (CODESETCODESET);
314
315 if (pcodeset != NULL((void*)0)) {
316 *pcodeset = g_strdup (codeset)g_strdup_inline (codeset);
317 }
318
319 if (is_utf8 != NULL((void*)0)) {
320 codeset = normalize_codeset (codeset);
321
322 *is_utf8 = strcmp (codeset, "UTF-8") == 0;
323 }
324
325 setlocale (LC_CTYPE0, old_locale);
326}
327
328static gboolean
329locale_dir_has_mo_files (const gchar* path)
330{
331 GDir *dir;
332 const char *name;
333 gboolean has_translations;
334
335 has_translations = FALSE(0);
336 dir = g_dir_open (path, 0, NULL((void*)0));
337
338 if (dir == NULL((void*)0)) {
339 goto out;
340 }
341
342 do {
343 name = g_dir_read_name (dir);
344
345 if (name == NULL((void*)0)) {
346 break;
347 }
348
349 if (g_str_has_suffix (name, ".mo")(__builtin_constant_p (".mo")? __extension__ ({ const char * const
__str = (name); const char * const __suffix = (".mo"); gboolean
__result = (0); if (__str == ((void*)0) || __suffix == ((void
*)0)) __result = (g_str_has_suffix) (__str, __suffix); else {
const size_t __str_len = strlen (((__str) + !(__str))); const
size_t __suffix_len = strlen (((__suffix) + !(__suffix))); if
(__str_len >= __suffix_len) __result = memcmp (__str + __str_len
- __suffix_len, ((__suffix) + !(__suffix)), __suffix_len) ==
0; } __result; }) : (g_str_has_suffix) (name, ".mo") )
) {
350 has_translations = TRUE(!(0));
351 break;
352 }
353 } while (name != NULL((void*)0));
354 g_dir_close (dir);
355
356 out:
357 return has_translations;
358}
359
360/**
361 * mate_language_has_translations:
362 * @code: an ISO 639 code string
363 *
364 * Returns %TRUE if there are translations for language @code.
365 *
366 * Return value: %TRUE if there are translations for language @code.
367 *
368 * Since: 1.22
369 */
370gboolean
371mate_language_has_translations (const char *code)
372{
373 gboolean has_translations;
374 gchar *path;
375
376 path = g_build_filename (MATELOCALEDIR"/usr/share/locale", code, "LC_MESSAGES", NULL((void*)0));
377 has_translations = locale_dir_has_mo_files (path);
378
379 if (!has_translations) {
380 const char * const *system_data_dirs;
381 int i = 0;
382
383 system_data_dirs = g_get_system_data_dirs ();
384 while ((system_data_dirs[i] != NULL((void*)0)) && (has_translations == FALSE(0))) {
385 g_free (path);
386 path = g_build_filename (system_data_dirs[i], "locale", code, "LC_MESSAGES", NULL((void*)0));
387 has_translations = locale_dir_has_mo_files (path);
388 ++i;
389 }
390 }
391
392 g_free (path);
393 return has_translations;
394}
395
396static gboolean
397add_locale (const char *language_name,
398 gboolean utf8_only)
399{
400 MateLocale *locale;
401 MateLocale *old_locale;
402 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *name = NULL((void*)0);
403 gboolean is_utf8 = FALSE(0);
404 gboolean valid = FALSE(0);
405
406 g_return_val_if_fail (language_name != NULL, FALSE)do { if ((language_name != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "language_name != NULL"
); return ((0)); } } while (0)
;
407 g_return_val_if_fail (*language_name != '\0', FALSE)do { if ((*language_name != '\0')) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "*language_name != '\\0'"
); return ((0)); } } while (0)
;
408
409 language_name_get_codeset_details (language_name, NULL((void*)0), &is_utf8);
410
411 if (is_utf8) {
412 name = g_strdup (language_name)g_strdup_inline (language_name);
413 } else if (utf8_only) {
414
415 if (strchr (language_name, '.'))
416 return FALSE(0);
417
418 /* If the locale name has no dot, assume that its
419 * encoding part is missing and try again after adding
420 * ".UTF-8". This catches locale names like "de_DE".
421 */
422 name = g_strdup_printf ("%s.UTF-8", language_name);
423
424 language_name_get_codeset_details (name, NULL((void*)0), &is_utf8);
425 if (!is_utf8)
426 return FALSE(0);
427 } else {
428 name = g_strdup (language_name)g_strdup_inline (language_name);
429 }
430
431 if (!language_name_is_valid (name)) {
432 g_debug ("Ignoring '%s' as a locale, since it's invalid", name);
433 return FALSE(0);
434 }
435
436 locale = g_new0 (MateLocale, 1)((MateLocale *) g_malloc0_n ((1), sizeof (MateLocale)));
437 valid = mate_parse_locale (name,
438 &locale->language_code,
439 &locale->territory_code,
440 &locale->codeset,
441 &locale->modifier);
442 if (!valid) {
443 mate_locale_free (locale);
444 return FALSE(0);
445 }
446
447 locale->id = construct_language_name (locale->language_code, locale->territory_code,
448 NULL((void*)0), locale->modifier);
449 locale->name = construct_language_name (locale->language_code, locale->territory_code,
450 locale->codeset, locale->modifier);
451
452 if (!mate_language_has_translations (locale->name) &&
453 !mate_language_has_translations (locale->id) &&
454 !mate_language_has_translations (locale->language_code) &&
455 utf8_only) {
456 g_debug ("Ignoring '%s' as a locale, since it lacks translations", locale->name);
457 mate_locale_free (locale);
458 return FALSE(0);
459 }
460
461 if (!utf8_only) {
462 g_free (locale->id);
463 locale->id = g_strdup (locale->name)g_strdup_inline (locale->name);
464 }
465
466 old_locale = g_hash_table_lookup (mate_available_locales_map, locale->id);
467 if (old_locale != NULL((void*)0)) {
468 if (strlen (old_locale->name) > strlen (locale->name)) {
469 mate_locale_free (locale);
470 return FALSE(0);
471 }
472 }
473
474 g_hash_table_insert (mate_available_locales_map, g_strdup (locale->id)g_strdup_inline (locale->id), locale);
475
476 return TRUE(!(0));
477}
478
479static int
480select_dirs (const struct dirent *dirent)
481{
482 int result = 0;
483
484 if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0) {
485 mode_t mode = 0;
486
487#ifdef _DIRENT_HAVE_D_TYPE
488 if (dirent->d_type != DT_UNKNOWNDT_UNKNOWN && dirent->d_type != DT_LNKDT_LNK) {
489 mode = DTTOIF (dirent->d_type)((dirent->d_type) << 12);
490 } else
491#endif
492 {
493 struct stat st;
494 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *path = NULL((void*)0);
495
496 path = g_build_filename (MATELOCALEDIR"/usr/share/locale", dirent->d_name, NULL((void*)0));
497 if (g_statstat (path, &st) == 0) {
498 mode = st.st_mode;
499 }
500 }
501
502 result = S_ISDIR (mode)((((mode)) & 0170000) == (0040000));
503 }
504
505 return result;
506}
507
508static gboolean
509collect_locales_from_directory (void)
510{
511 gboolean found_locales = FALSE(0);
512 struct dirent **dirents;
513 int ndirents;
514 int cnt;
515
516 ndirents = scandir (MATELOCALEDIR"/usr/share/locale", &dirents, select_dirs, alphasort);
517
518 for (cnt = 0; cnt < ndirents; ++cnt) {
519 if (add_locale (dirents[cnt]->d_name, TRUE(!(0))))
520 found_locales = TRUE(!(0));
521 }
522
523 if (ndirents > 0) {
524 free (dirents);
525 }
526 return found_locales;
527}
528
529static gboolean
530collect_locales_from_localebin (void)
531{
532 gboolean found_locales = FALSE(0);
533 const gchar *argv[] = { "locale", "-a", NULL((void*)0) };
534 gchar **linep;
535 g_auto (GStrv)__attribute__((cleanup(glib_auto_cleanup_GStrv))) GStrv lines = NULL((void*)0);
536 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) gchar *output = NULL((void*)0);
537
538 if (g_spawn_sync (NULL((void*)0), (gchar **) argv, NULL((void*)0),
539 G_SPAWN_SEARCH_PATH|G_SPAWN_STDERR_TO_DEV_NULL,
540 NULL((void*)0), NULL((void*)0), &output, NULL((void*)0), NULL((void*)0), NULL((void*)0)) == FALSE(0))
541 return FALSE(0);
542
543 g_return_val_if_fail (output != NULL, FALSE)do { if ((output != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "output != NULL"
); return ((0)); } } while (0)
;
544
545 lines = g_strsplit (output, "\n", 0);
546 if (lines) {
547 linep = lines;
548 while (*linep) {
549 if (*linep[0] && add_locale (*linep, TRUE(!(0))))
550 found_locales = TRUE(!(0));
551 linep++;
552 }
553 }
554
555 return found_locales;
556}
557
558static void
559fill_count_map (GHashTable *count_map,
560 const char *code)
561{
562 int count;
563 gpointer pointer;
564
565 if (code == NULL((void*)0))
566 return;
567
568 if ((pointer = g_hash_table_lookup (count_map, code)) != NULL((void*)0))
569 count = GPOINTER_TO_INT (pointer)((gint) (glong) (pointer)) + 1;
570 else
571 count = 1;
572
573 g_hash_table_insert (count_map, g_strdup (code)g_strdup_inline (code), GINT_TO_POINTER (count)((gpointer) (glong) (count)));
574}
575
576static void
577count_languages_and_territories (void)
578{
579 gpointer value;
580 GHashTableIter iter;
581
582 mate_language_count_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
583 mate_territory_count_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
584
585 g_hash_table_iter_init (&iter, mate_available_locales_map);
586 while (g_hash_table_iter_next (&iter, NULL((void*)0), &value)) {
587 MateLocale *locale = (MateLocale *) value;
588 fill_count_map (mate_language_count_map, locale->language_code);
589 fill_count_map (mate_territory_count_map, locale->territory_code);
590 }
591}
592
593static void
594collect_locales (void)
595{
596 gboolean found_localebin_locales = FALSE(0);
597 gboolean found_dir_locales = FALSE(0);
598
599 if (mate_available_locales_map == NULL((void*)0)) {
600 mate_available_locales_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) mate_locale_free);
601 }
602
603 found_localebin_locales = collect_locales_from_localebin ();
604
605 found_dir_locales = collect_locales_from_directory ();
606
607 if (!(found_localebin_locales || found_dir_locales)) {
608 g_warning ("Could not read list of available locales from libc, "
609 "guessing possible locales from available translations, "
610 "but list may be incomplete!");
611 }
612
613 count_languages_and_territories ();
614}
615
616static gint
617get_language_count (const char *language)
618{
619 gint count = 0;
620 gpointer pointer;
621
622 if (mate_language_count_map == NULL((void*)0))
623 collect_locales ();
624
625 if ((pointer = g_hash_table_lookup (mate_language_count_map, language)) != NULL((void*)0))
626 count = GPOINTER_TO_INT (pointer)((gint) (glong) (pointer));
627
628 return count;
629}
630
631static gboolean
632is_unique_language (const char *language)
633{
634 return get_language_count (language) == 1;
635}
636
637static gint
638get_territory_count (const char *territory)
639{
640 gint count = 0;
641 gpointer pointer;
642
643 if (mate_territory_count_map == NULL((void*)0))
644 collect_locales ();
645
646 if ((pointer = g_hash_table_lookup (mate_territory_count_map, territory)) != NULL((void*)0))
647 count = GPOINTER_TO_INT (pointer)((gint) (glong) (pointer));
648
649 return count;
650}
651
652static gboolean
653is_unique_territory (const char *territory)
654{
655 return get_territory_count (territory) == 1;
656}
657
658static gboolean
659is_fallback_language (const char *code)
660{
661 const char *fallback_language_names[] = { "C", "POSIX", NULL((void*)0) };
662 int i;
663
664 for (i = 0; fallback_language_names[i] != NULL((void*)0); i++) {
665 if (strcmp (code, fallback_language_names[i]) == 0) {
666 return TRUE(!(0));
667 }
668 }
669
670 return FALSE(0);
671}
672
673static const char *
674get_language (const char *code)
675{
676 const char *name;
677 int len;
678
679 g_assert (code != NULL)do { if (code != ((void*)0)) ; else g_assertion_message_expr (
"MateDesktop", "mate-languages.c", 679, ((const char*) (__func__
)), "code != NULL"); } while (0)
;
680
681 if (is_fallback_language (code)) {
682 return "Unspecified";
683 }
684
685 len = strlen (code);
686 if (len != 2 && len != 3) {
687 return NULL((void*)0);
688 }
689
690 name = (const char *) g_hash_table_lookup (mate_languages_map, code);
691
692 return name;
693}
694
695static char *
696get_first_item_in_semicolon_list (const char *list)
697{
698 char **items;
699 char *item;
700
701 /* Some entries in iso codes have multiple values, separated
702 * by semicolons. Not really sure which one to pick, so
703 * we just arbitrarily pick the first one.
704 */
705 items = g_strsplit (list, "; ", 2);
706
707 item = g_strdup (items[0])g_strdup_inline (items[0]);
708 g_strfreev (items);
709
710 return item;
711}
712
713static char *
714capitalize_utf8_string (const char *str)
715{
716 char first[8] = { 0 };
717
718 if (!str)
719 return NULL((void*)0);
720
721 g_unichar_to_utf8 (g_unichar_totitle (g_utf8_get_char (str)), first);
722
723 return g_strconcat (first, g_utf8_offset_to_pointer (str, 1), NULL((void*)0));
724}
725
726static char *
727get_translated_language (const char *code,
728 const char *locale)
729{
730 const char *language;
731 char *name;
732
733 language = get_language (code);
734
735 name = NULL((void*)0);
736 if (language != NULL((void*)0)) {
737 const char *translated_name;
738 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
739
740 if (locale != NULL((void*)0)) {
741 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL))g_strdup_inline (setlocale (5, ((void*)0)));
742 setlocale (LC_MESSAGES5, locale);
743 }
744
745 if (is_fallback_language (code)) {
746 name = g_strdup (_("Unspecified"))g_strdup_inline (gettext ("Unspecified"));
747 } else {
748 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *tmp = NULL((void*)0);
749 translated_name = dgettext ("iso_639", language);
750 tmp = get_first_item_in_semicolon_list (translated_name);
751 name = capitalize_utf8_string (tmp);
752 }
753
754 if (locale != NULL((void*)0)) {
755 setlocale (LC_MESSAGES5, old_locale);
756 }
757 }
758
759 return name;
760}
761
762static const char *
763get_territory (const char *code)
764{
765 const char *name;
766 int len;
767
768 g_assert (code != NULL)do { if (code != ((void*)0)) ; else g_assertion_message_expr (
"MateDesktop", "mate-languages.c", 768, ((const char*) (__func__
)), "code != NULL"); } while (0)
;
769
770 len = strlen (code);
771 if (len != 2 && len != 3) {
772 return NULL((void*)0);
773 }
774
775 name = (const char *) g_hash_table_lookup (mate_territories_map, code);
776
777 return name;
778}
779
780static char *
781get_translated_territory (const char *code,
782 const char *locale)
783{
784 const char *territory;
785 char *name;
786
787 territory = get_territory (code);
788
789 name = NULL((void*)0);
790 if (territory != NULL((void*)0)) {
791 const char *translated_territory;
792 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
793 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *tmp = NULL((void*)0);
794
795 if (locale != NULL((void*)0)) {
796 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL))g_strdup_inline (setlocale (5, ((void*)0)));
797 setlocale (LC_MESSAGES5, locale);
798 }
799
800 translated_territory = dgettext ("iso_3166", territory);
801 tmp = get_first_item_in_semicolon_list (translated_territory);
802 name = capitalize_utf8_string (tmp);
803
804 if (locale != NULL((void*)0)) {
805 setlocale (LC_MESSAGES5, old_locale);
806 }
807 }
808
809 return name;
810}
811
812static void
813languages_parse_start_tag (GMarkupParseContext *ctx,
814 const char *element_name,
815 const char **attr_names,
816 const char **attr_values,
817 gpointer user_data,
818 GError **error)
819{
820 const char *ccode_longB;
821 const char *ccode_longT;
822 const char *ccode;
823 const char *ccode_id;
824 const char *lang_name;
825
826 if (! (g_str_equal (element_name, "iso_639_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_639_entry"
)) == 0)
|| g_str_equal (element_name, "iso_639_3_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_639_3_entry"
)) == 0)
)
827 || attr_names == NULL((void*)0) || attr_values == NULL((void*)0)) {
828 return;
829 }
830
831 ccode = NULL((void*)0);
832 ccode_longB = NULL((void*)0);
833 ccode_longT = NULL((void*)0);
834 ccode_id = NULL((void*)0);
835 lang_name = NULL((void*)0);
836
837 while (*attr_names && *attr_values) {
838 if (g_str_equal (*attr_names, "iso_639_1_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_1_code"
)) == 0)
) {
839 /* skip if empty */
840 if (**attr_values) {
841 if (strlen (*attr_values) != 2) {
842 return;
843 }
844 ccode = *attr_values;
845 }
846 } else if (g_str_equal (*attr_names, "iso_639_2B_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_2B_code"
)) == 0)
) {
847 /* skip if empty */
848 if (**attr_values) {
849 if (strlen (*attr_values) != 3) {
850 return;
851 }
852 ccode_longB = *attr_values;
853 }
854 } else if (g_str_equal (*attr_names, "iso_639_2T_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_2T_code"
)) == 0)
) {
855 /* skip if empty */
856 if (**attr_values) {
857 if (strlen (*attr_values) != 3) {
858 return;
859 }
860 ccode_longT = *attr_values;
861 }
862 } else if (g_str_equal (*attr_names, "id")(strcmp ((const char *) (*attr_names), (const char *) ("id"))
== 0)
) {
863 /* skip if empty */
864 if (**attr_values) {
865 if (strlen (*attr_values) != 2 &&
866 strlen (*attr_values) != 3) {
867 return;
868 }
869 ccode_id = *attr_values;
870 }
871 } else if (g_str_equal (*attr_names, "name")(strcmp ((const char *) (*attr_names), (const char *) ("name"
)) == 0)
) {
872 lang_name = *attr_values;
873 }
874
875 ++attr_names;
876 ++attr_values;
877 }
878
879 if (lang_name == NULL((void*)0)) {
880 return;
881 }
882
883 if (ccode != NULL((void*)0)) {
884 g_hash_table_insert (mate_languages_map,
885 g_strdup (ccode)g_strdup_inline (ccode),
886 g_strdup (lang_name)g_strdup_inline (lang_name));
887 }
888 if (ccode_longB != NULL((void*)0)) {
889 g_hash_table_insert (mate_languages_map,
890 g_strdup (ccode_longB)g_strdup_inline (ccode_longB),
891 g_strdup (lang_name)g_strdup_inline (lang_name));
892 }
893 if (ccode_longT != NULL((void*)0)) {
894 g_hash_table_insert (mate_languages_map,
895 g_strdup (ccode_longT)g_strdup_inline (ccode_longT),
896 g_strdup (lang_name)g_strdup_inline (lang_name));
897 }
898 if (ccode_id != NULL((void*)0)) {
899 g_hash_table_insert (mate_languages_map,
900 g_strdup (ccode_id)g_strdup_inline (ccode_id),
901 g_strdup (lang_name)g_strdup_inline (lang_name));
902 }
903}
904
905static void
906territories_parse_start_tag (GMarkupParseContext *ctx,
907 const char *element_name,
908 const char **attr_names,
909 const char **attr_values,
910 gpointer user_data,
911 GError **error)
912{
913 const char *acode_2;
914 const char *acode_3;
915 const char *ncode;
916 const char *territory_common_name;
917 const char *territory_name;
918
919 if (! g_str_equal (element_name, "iso_3166_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_3166_entry"
)) == 0)
|| attr_names == NULL((void*)0) || attr_values == NULL((void*)0)) {
920 return;
921 }
922
923 acode_2 = NULL((void*)0);
924 acode_3 = NULL((void*)0);
925 ncode = NULL((void*)0);
926 territory_common_name = NULL((void*)0);
927 territory_name = NULL((void*)0);
928
929 while (*attr_names && *attr_values) {
930 if (g_str_equal (*attr_names, "alpha_2_code")(strcmp ((const char *) (*attr_names), (const char *) ("alpha_2_code"
)) == 0)
) {
931 /* skip if empty */
932 if (**attr_values) {
933 if (strlen (*attr_values) != 2) {
934 return;
935 }
936 acode_2 = *attr_values;
937 }
938 } else if (g_str_equal (*attr_names, "alpha_3_code")(strcmp ((const char *) (*attr_names), (const char *) ("alpha_3_code"
)) == 0)
) {
939 /* skip if empty */
940 if (**attr_values) {
941 if (strlen (*attr_values) != 3) {
942 return;
943 }
944 acode_3 = *attr_values;
945 }
946 } else if (g_str_equal (*attr_names, "numeric_code")(strcmp ((const char *) (*attr_names), (const char *) ("numeric_code"
)) == 0)
) {
947 /* skip if empty */
948 if (**attr_values) {
949 if (strlen (*attr_values) != 3) {
950 return;
951 }
952 ncode = *attr_values;
953 }
954 } else if (g_str_equal (*attr_names, "common_name")(strcmp ((const char *) (*attr_names), (const char *) ("common_name"
)) == 0)
) {
955 /* skip if empty */
956 if (**attr_values) {
957 territory_common_name = *attr_values;
958 }
959 } else if (g_str_equal (*attr_names, "name")(strcmp ((const char *) (*attr_names), (const char *) ("name"
)) == 0)
) {
960 territory_name = *attr_values;
961 }
962
963 ++attr_names;
964 ++attr_values;
965 }
966
967 if (territory_common_name != NULL((void*)0)) {
968 territory_name = territory_common_name;
969 }
970
971 if (territory_name == NULL((void*)0)) {
972 return;
973 }
974
975 if (acode_2 != NULL((void*)0)) {
976 g_hash_table_insert (mate_territories_map,
977 g_strdup (acode_2)g_strdup_inline (acode_2),
978 g_strdup (territory_name)g_strdup_inline (territory_name));
979 }
980 if (acode_3 != NULL((void*)0)) {
981 g_hash_table_insert (mate_territories_map,
982 g_strdup (acode_3)g_strdup_inline (acode_3),
983 g_strdup (territory_name)g_strdup_inline (territory_name));
984 }
985 if (ncode != NULL((void*)0)) {
986 g_hash_table_insert (mate_territories_map,
987 g_strdup (ncode)g_strdup_inline (ncode),
988 g_strdup (territory_name)g_strdup_inline (territory_name));
989 }
990}
991
992static void
993languages_variant_init (const char *variant)
994{
995 gboolean res;
996 gsize buf_len;
997 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *buf = NULL((void*)0);
998 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *filename = NULL((void*)0);
999 g_autoptr (GError)__attribute__((cleanup(glib_autoptr_cleanup_GError))) GError_autoptr error = NULL((void*)0);
1000
1001 bindtextdomain (variant, ISO_CODES_LOCALESDIR"/usr" "/share/locale");
1002 bind_textdomain_codeset (variant, "UTF-8");
1003
1004 error = NULL((void*)0);
1005 filename = g_strdup_printf (ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/%s.xml", variant);
1006 res = g_file_get_contents (filename,
1007 &buf,
1008 &buf_len,
1009 &error);
1010 if (res) {
1011 g_autoptr (GMarkupParseContext)__attribute__((cleanup(glib_autoptr_cleanup_GMarkupParseContext
))) GMarkupParseContext_autoptr
ctx = NULL((void*)0);
1012 GMarkupParser parser = { languages_parse_start_tag, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0) };
1013
1014 ctx = g_markup_parse_context_new (&parser, 0, NULL((void*)0), NULL((void*)0));
1015
1016 error = NULL((void*)0);
1017 res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
1018
1019 if (! res) {
1020 g_warning ("Failed to parse '%s': %s\n",
1021 filename,
1022 error->message);
1023 }
1024 } else {
1025 g_warning ("Failed to load '%s': %s\n",
1026 filename,
1027 error->message);
1028 }
1029}
1030
1031static void
1032languages_init (void)
1033{
1034 if (mate_languages_map)
1035 return;
1036
1037 mate_languages_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1038
1039 languages_variant_init ("iso_639");
1040 languages_variant_init ("iso_639_3");
1041}
1042
1043static void
1044territories_init (void)
1045{
1046 gboolean res;
1047 gsize buf_len;
1048 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *buf = NULL((void*)0);
1049 g_autoptr (GError)__attribute__((cleanup(glib_autoptr_cleanup_GError))) GError_autoptr error = NULL((void*)0);
1050
1051 if (mate_territories_map)
1052 return;
1053
1054 bindtextdomain ("iso_3166", ISO_CODES_LOCALESDIR"/usr" "/share/locale");
1055 bind_textdomain_codeset ("iso_3166", "UTF-8");
1056
1057 mate_territories_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1058
1059 error = NULL((void*)0);
1060 res = g_file_get_contents (ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1061 &buf,
1062 &buf_len,
1063 &error);
1064 if (res) {
1065 g_autoptr (GMarkupParseContext)__attribute__((cleanup(glib_autoptr_cleanup_GMarkupParseContext
))) GMarkupParseContext_autoptr
ctx = NULL((void*)0);
1066 GMarkupParser parser = { territories_parse_start_tag, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0) };
1067
1068 ctx = g_markup_parse_context_new (&parser, 0, NULL((void*)0), NULL((void*)0));
1069
1070 error = NULL((void*)0);
1071 res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
1072
1073 if (! res) {
1074 g_warning ("Failed to parse '%s': %s\n",
1075 ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1076 error->message);
1077 }
1078 } else {
1079 g_warning ("Failed to load '%s': %s\n",
1080 ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1081 error->message);
1082 }
1083}
1084
1085/**
1086 * mate_get_language_from_locale:
1087 * @locale: a locale string
1088 * @translation: (allow-none): a locale string
1089 *
1090 * Gets the language description for @locale. If @translation is
1091 * provided the returned string is translated accordingly.
1092 *
1093 * Return value: (transfer full): the language description. Caller
1094 * takes ownership.
1095 *
1096 * Since: 1.22
1097 */
1098char *
1099mate_get_language_from_locale (const char *locale,
1100 const char *translation)
1101{
1102 GString *full_language;
1103 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
1104 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
1105 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset_code = NULL((void*)0);
1106 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *langinfo_codeset = NULL((void*)0);
1107 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_language = NULL((void*)0);
1108 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_territory = NULL((void*)0);
1109 gboolean is_utf8 = TRUE(!(0));
1110
1111 g_return_val_if_fail (locale != NULL, NULL)do { if ((locale != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "locale != NULL"
); return (((void*)0)); } } while (0)
;
1112 g_return_val_if_fail (*locale != '\0', NULL)do { if ((*locale != '\0')) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "*locale != '\\0'"
); return (((void*)0)); } } while (0)
;
1113
1114 full_language = g_string_new (NULL((void*)0));
1115
1116 languages_init ();
1117 territories_init ();
1118
1119 mate_parse_locale (locale,
1120 &language_code,
1121 &territory_code,
1122 &codeset_code,
1123 NULL((void*)0));
1124
1125 if (language_code == NULL((void*)0)) {
1126 goto out;
1127 }
1128
1129 translated_language = get_translated_language (language_code, translation);
1130 if (translated_language == NULL((void*)0)) {
1131 goto out;
1132 }
1133
1134 full_language = g_string_append (full_language, translated_language)(__builtin_constant_p (translated_language) ? __extension__ (
{ const char * const __val = (translated_language); g_string_append_len_inline
(full_language, __val, (__val != ((void*)0)) ? (gssize) strlen
(((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(full_language, translated_language, (gssize) -1))
;
1135
1136 if (is_unique_language (language_code)) {
1137 goto out;
1138 }
1139
1140 if (territory_code != NULL((void*)0)) {
1141 translated_territory = get_translated_territory (territory_code, translation);
1142 }
1143 if (translated_territory != NULL((void*)0)) {
1144 g_string_append_printf (full_language,
1145 " (%s)",
1146 translated_territory);
1147 }
1148
1149 language_name_get_codeset_details (locale, &langinfo_codeset, &is_utf8);
1150
1151 if (codeset_code == NULL((void*)0) && langinfo_codeset != NULL((void*)0)) {
1152 codeset_code = g_strdup (langinfo_codeset)g_strdup_inline (langinfo_codeset);
1153 }
1154
1155 if (!is_utf8 && codeset_code) {
1156 g_string_append_printf (full_language,
1157 " [%s]",
1158 codeset_code);
1159 }
1160
1161 out:
1162 if (full_language->len == 0) {
1163 g_string_free (full_language, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(full_language), ((!(0)))) : g_string_free_and_steal (full_language
)) : (g_string_free) ((full_language), ((!(0)))))
;
This statement is never executed
1164 return NULL((void*)0);
1165 }
1166
1167 return g_string_free (full_language, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((full_language
), ((0))) : g_string_free_and_steal (full_language)) : (g_string_free
) ((full_language), ((0))))
;
1168}
1169
1170/**
1171 * mate_get_country_from_locale:
1172 * @locale: a locale string
1173 * @translation: (allow-none): a locale string
1174 *
1175 * Gets the country description for @locale. If @translation is
1176 * provided the returned string is translated accordingly.
1177 *
1178 * Return value: (transfer full): the country description. Caller
1179 * takes ownership.
1180 *
1181 * Since: 1.22
1182 */
1183char *
1184mate_get_country_from_locale (const char *locale,
1185 const char *translation)
1186{
1187 GString *full_name;
1188 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
1189 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
1190 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset_code = NULL((void*)0);
1191 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *langinfo_codeset = NULL((void*)0);
1192 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_language = NULL((void*)0);
1193 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_territory = NULL((void*)0);
1194 gboolean is_utf8 = TRUE(!(0));
1195
1196 g_return_val_if_fail (locale != NULL, NULL)do { if ((locale != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "locale != NULL"
); return (((void*)0)); } } while (0)
;
1197 g_return_val_if_fail (*locale != '\0', NULL)do { if ((*locale != '\0')) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "*locale != '\\0'"
); return (((void*)0)); } } while (0)
;
1198
1199 full_name = g_string_new (NULL((void*)0));
1200
1201 languages_init ();
1202 territories_init ();
1203
1204 mate_parse_locale (locale,
1205 &language_code,
1206 &territory_code,
1207 &codeset_code,
1208 NULL((void*)0));
1209
1210 if (territory_code == NULL((void*)0)) {
1211 goto out;
1212 }
1213
1214 translated_territory = get_translated_territory (territory_code, translation);
1215 g_string_append (full_name, translated_territory)(__builtin_constant_p (translated_territory) ? __extension__ (
{ const char * const __val = (translated_territory); g_string_append_len_inline
(full_name, __val, (__val != ((void*)0)) ? (gssize) strlen (
((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(full_name, translated_territory, (gssize) -1))
;
1216
1217 if (is_unique_territory (territory_code)) {
1218 goto out;
1219 }
1220
1221 if (language_code != NULL((void*)0)) {
1222 translated_language = get_translated_language (language_code, translation);
1223 }
1224 if (translated_language != NULL((void*)0)) {
1225 g_string_append_printf (full_name,
1226 " (%s)",
1227 translated_language);
1228 }
1229
1230 language_name_get_codeset_details (translation, &langinfo_codeset, &is_utf8);
1231
1232 if (codeset_code == NULL((void*)0) && langinfo_codeset != NULL((void*)0)) {
1233 codeset_code = g_strdup (langinfo_codeset)g_strdup_inline (langinfo_codeset);
1234 }
1235
1236 if (!is_utf8 && codeset_code) {
1237 g_string_append_printf (full_name,
1238 " [%s]",
1239 codeset_code);
1240 }
1241
1242 out:
1243 if (full_name->len == 0) {
1244 g_string_free (full_name, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(full_name), ((!(0)))) : g_string_free_and_steal (full_name))
: (g_string_free) ((full_name), ((!(0)))))
;
1245 return NULL((void*)0);
1246 }
1247
1248 return g_string_free (full_name, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((full_name
), ((0))) : g_string_free_and_steal (full_name)) : (g_string_free
) ((full_name), ((0))))
;
1249}
1250
1251/**
1252 * mate_get_all_locales:
1253 *
1254 * Gets all locales.
1255 *
1256 * Return value: (array zero-terminated=1) (element-type utf8) (transfer full):
1257 * a newly allocated %NULL-terminated string array containing the
1258 * all locales. Free with g_strfreev().
1259 *
1260 * Since: 1.22
1261 */
1262char **
1263mate_get_all_locales (void)
1264{
1265 GHashTableIter iter;
1266 gpointer key, value;
1267 GPtrArray *array;
1268
1269 if (mate_available_locales_map == NULL((void*)0)) {
1270 collect_locales ();
1271 }
1272
1273 array = g_ptr_array_new ();
1274 g_hash_table_iter_init (&iter, mate_available_locales_map);
1275 while (g_hash_table_iter_next (&iter, &key, &value)) {
1276 MateLocale *locale;
1277
1278 locale = (MateLocale *) value;
1279
1280 g_ptr_array_add (array, g_strdup (locale->name)g_strdup_inline (locale->name));
1281 }
1282 g_ptr_array_add (array, NULL((void*)0));
1283
1284 return (char **) g_ptr_array_free (array, FALSE(0));
1285}
1286
1287/**
1288 * mate_get_language_from_code:
1289 * @code: an ISO 639 code string
1290 * @translation: (allow-none): a locale string
1291 *
1292 * Gets the language name for @code. If @locale is provided the
1293 * returned string is translated accordingly.
1294 *
1295 * Return value: (transfer full): the language name. Caller takes
1296 * ownership.
1297 *
1298 * Since: 1.22
1299 */
1300char *
1301mate_get_language_from_code (const char *code,
1302 const char *translation)
1303{
1304 g_return_val_if_fail (code != NULL, NULL)do { if ((code != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "code != NULL");
return (((void*)0)); } } while (0)
;
1305
1306 languages_init ();
1307
1308 return get_translated_language (code, translation);
1309}
1310
1311/**
1312 * mate_get_country_from_code:
1313 * @code: an ISO 3166 code string
1314 * @translation: (allow-none): a locale string
1315 *
1316 * Gets the country name for @code. If @locale is provided the
1317 * returned string is translated accordingly.
1318 *
1319 * Return value: (transfer full): the country name. Caller takes
1320 * ownership.
1321 *
1322 * Since: 1.22
1323 */
1324char *
1325mate_get_country_from_code (const char *code,
1326 const char *translation)
1327{
1328 g_return_val_if_fail (code != NULL, NULL)do { if ((code != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "code != NULL");
return (((void*)0)); } } while (0)
;
1329
1330 territories_init ();
1331
1332 return get_translated_territory (code, translation);
1333}
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-689d47.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-689d47.html new file mode 100644 index 0000000..bb36d2e --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-689d47.html @@ -0,0 +1,4660 @@ + + + +mate-desktop-item.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-desktop-item.c
Warning:line 3125, column 9
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-desktop-item.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-desktop-item.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* mate-desktop-item.c - MATE Desktop File Representation
3
4 Copyright (C) 1999, 2000 Red Hat Inc.
5 Copyright (C) 2001 Sid Vicious
6 All rights reserved.
7
8 This file is part of the Mate Library.
9
10 Developed by Elliot Lee <sopwith@redhat.com> and Sid Vicious
11
12 The Mate Library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Library General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
16
17 The Mate Library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Library General Public License for more details.
21
22 You should have received a copy of the GNU Library General Public
23 License along with the Mate Library; see the file COPYING.LIB. If not,
24 write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 Boston, MA 02110-1301, USA. */
26/*
27 @NOTATION@
28 */
29
30#include "config.h"
31
32#include <limits.h>
33#include <ctype.h>
34#include <stdio.h>
35#include <glib.h>
36#include <sys/types.h>
37#include <dirent.h>
38#include <unistd.h>
39#include <time.h>
40#include <string.h>
41#include <glib/gi18n-lib.h>
42#include <locale.h>
43#include <stdlib.h>
44
45#include <gio/gio.h>
46
47#ifdef HAVE_STARTUP_NOTIFICATION
48#define SN_API_NOT_YET_FROZEN
49#include <libsn/sn.h>
50#include <gdk/gdk.h>
51#include <gdk/gdkx.h>
52#include <gtk/gtk.h>
53#endif
54
55#define MATE_DESKTOP_USE_UNSTABLE_API
56#undef MATE_DISABLE_DEPRECATED
57#include <mate-desktop-item.h>
58#include <mate-desktop-utils.h>
59
60#include "private.h"
61
62struct _MateDesktopItem {
63 int refcount;
64
65 /* all languages used */
66 GList *languages;
67
68 MateDesktopItemType type;
69
70 /* `modified' means that the ditem has been
71 * modified since the last save. */
72 gboolean modified;
73
74 /* Keys of the main section only */
75 GList *keys;
76
77 GList *sections;
78
79 /* This includes ALL keys, including
80 * other sections, separated by '/' */
81 GHashTable *main_hash;
82
83 char *location;
84
85 gint64 mtime;
86
87 guint32 launch_time;
88};
89
90/* If mtime is set to this, set_location won't update mtime,
91 * this is to be used internally only. */
92#define DONT_UPDATE_MTIME((gint64)-2) ((gint64)-2)
93
94typedef struct {
95 char *name;
96 GList *keys;
97} Section;
98
99typedef enum {
100 ENCODING_UNKNOWN,
101 ENCODING_UTF8,
102 ENCODING_LEGACY_MIXED
103} Encoding;
104
105/*
106 * IO reading utils, that look like the libc buffered io stuff
107 */
108
109#define READ_BUF_SIZE(32 * 1024) (32 * 1024)
110
111typedef struct {
112 GFile *file;
113 GFileInputStream *stream;
114 char *uri;
115 char *buf;
116 gboolean buf_needs_free;
117 gboolean past_first_read;
118 gboolean eof;
119 guint64 size;
120 gsize pos;
121} ReadBuf;
122
123static MateDesktopItem *ditem_load (ReadBuf *rb,
124 gboolean no_translations,
125 GError **error);
126static gboolean ditem_save (MateDesktopItem *item,
127 const char *uri,
128 GError **error);
129
130static void mate_desktop_item_set_location_gfile (MateDesktopItem *item,
131 GFile *file);
132
133static MateDesktopItem *mate_desktop_item_new_from_gfile (GFile *file,
134 MateDesktopItemLoadFlags flags,
135 GError **error);
136
137static int
138readbuf_getc (ReadBuf *rb)
139{
140 if (rb->eof)
141 return EOF(-1);
142
143 if (rb->size == 0 ||
144 rb->pos == rb->size) {
145 gssize bytes_read;
146
147 if (rb->stream == NULL((void*)0))
148 bytes_read = 0;
149 else
150 bytes_read = g_input_stream_read (G_INPUT_STREAM (rb->stream)((((GInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((rb->stream)), ((g_input_stream_get_type ()))))))
,
151 rb->buf,
152 READ_BUF_SIZE(32 * 1024),
153 NULL((void*)0), NULL((void*)0));
154
155 /* FIXME: handle errors other than EOF */
156 if (bytes_read <= 0) {
157 rb->eof = TRUE(!(0));
158 return EOF(-1);
159 }
160
161 if (rb->size != 0)
162 rb->past_first_read = TRUE(!(0));
163 rb->size = bytes_read;
164 rb->pos = 0;
165
166 }
167
168 return (guchar) rb->buf[rb->pos++];
169}
170
171/* Note, does not include the trailing \n */
172static char *
173readbuf_gets (char *buf, gsize bufsize, ReadBuf *rb)
174{
175 int c;
176 gsize pos;
177
178 g_return_val_if_fail (buf != NULL, NULL)do { if ((buf != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "buf != NULL"); return
(((void*)0)); } } while (0)
;
179 g_return_val_if_fail (rb != NULL, NULL)do { if ((rb != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "rb != NULL"); return
(((void*)0)); } } while (0)
;
180
181 pos = 0;
182 buf[0] = '\0';
183
184 do {
185 c = readbuf_getc (rb);
186 if (c == EOF(-1) || c == '\n')
187 break;
188 buf[pos++] = c;
189 } while (pos < bufsize-1);
190
191 if (c == EOF(-1) && pos == 0)
192 return NULL((void*)0);
193
194 buf[pos++] = '\0';
195
196 return buf;
197}
198
199static ReadBuf *
200readbuf_open (GFile *file, GError **error)
201{
202 GError *local_error;
203 GFileInputStream *stream;
204 char *uri;
205 ReadBuf *rb;
206
207 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
208
209 uri = g_file_get_uri (file);
210 local_error = NULL((void*)0);
211 stream = g_file_read (file, NULL((void*)0), &local_error);
212
213 if (stream == NULL((void*)0)) {
214 g_set_error (error,
215 /* FIXME: better errors */
216 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
217 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
218 _("Error reading file '%s': %s")((char *) g_dgettext ("mate-desktop", "Error reading file '%s': %s"
))
,
219 uri, local_error->message);
220 g_error_free (local_error);
221 g_free (uri);
222 return NULL((void*)0);
223 }
224
225 rb = g_new0 (ReadBuf, 1)((ReadBuf *) g_malloc0_n ((1), sizeof (ReadBuf)));
226 rb->stream = stream;
227 rb->file = g_file_dup (file);
228 rb->uri = uri;
229 rb->buf = g_malloc (READ_BUF_SIZE(32 * 1024));
230 rb->buf_needs_free = TRUE(!(0));
231 /* rb->past_first_read = FALSE; */
232 /* rb->eof = FALSE; */
233 /* rb->size = 0; */
234 /* rb->pos = 0; */
235
236 return rb;
237}
238
239static ReadBuf *
240readbuf_new_from_string (const char *uri, const char *string, gssize length)
241{
242 ReadBuf *rb;
243
244 g_return_val_if_fail (string != NULL, NULL)do { if ((string != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "string != NULL"
); return (((void*)0)); } } while (0)
;
245 g_return_val_if_fail (length >= 0, NULL)do { if ((length >= 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "length >= 0"
); return (((void*)0)); } } while (0)
;
246
247 rb = g_new0 (ReadBuf, 1)((ReadBuf *) g_malloc0_n ((1), sizeof (ReadBuf)));
248 /* rb->file = NULL; */
249 /* rb->stream = NULL; */
250 rb->uri = g_strdup (uri)g_strdup_inline (uri);
251 rb->buf = (char *) string;
252 /* rb->buf_needs_free = FALSE; */
253 /* rb->past_first_read = FALSE; */
254 /* rb->eof = FALSE; */
255 rb->size = length;
256 /* rb->pos = 0; */
257
258 return rb;
259}
260
261static gboolean
262readbuf_rewind (ReadBuf *rb, GError **error)
263{
264 GError *local_error;
265
266 rb->eof = FALSE(0);
267 rb->pos = 0;
268
269 if (!rb->past_first_read)
270 return TRUE(!(0));
271
272 rb->size = 0;
273
274 if (g_seekable_seek (G_SEEKABLE (rb->stream)((((GSeekable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((rb->stream)), ((g_seekable_get_type ()))))))
,
275 0, G_SEEK_SET, NULL((void*)0), NULL((void*)0)))
276 return TRUE(!(0));
277
278 g_object_unref (rb->stream);
279 local_error = NULL((void*)0);
280 rb->stream = g_file_read (rb->file, NULL((void*)0), &local_error);
281
282 if (rb->stream == NULL((void*)0)) {
283 g_set_error (
284 error, MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
285 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
286 _("Error rewinding file '%s': %s")((char *) g_dgettext ("mate-desktop", "Error rewinding file '%s': %s"
))
,
287 rb->uri, local_error->message);
288 g_error_free (local_error);
289
290 return FALSE(0);
291 }
292
293 return TRUE(!(0));
294}
295
296static void
297readbuf_close (ReadBuf *rb)
298{
299 if (rb->stream != NULL((void*)0))
300 g_object_unref (rb->stream);
301 if (rb->file != NULL((void*)0))
302 g_object_unref (rb->file);
303 g_free (rb->uri);
304 if (rb->buf_needs_free)
305 g_free (rb->buf);
306 g_free (rb);
307}
308
309static MateDesktopItemType
310type_from_string (const char *type)
311{
312 if (!type)
313 return MATE_DESKTOP_ITEM_TYPE_NULL;
314
315 switch (type [0]) {
316 case 'A':
317 if (!strcmp (type, "Application"))
318 return MATE_DESKTOP_ITEM_TYPE_APPLICATION;
319 break;
320 case 'L':
321 if (!strcmp (type, "Link"))
322 return MATE_DESKTOP_ITEM_TYPE_LINK;
323 break;
324 case 'F':
325 if (!strcmp (type, "FSDevice"))
326 return MATE_DESKTOP_ITEM_TYPE_FSDEVICE;
327 break;
328 case 'M':
329 if (!strcmp (type, "MimeType"))
330 return MATE_DESKTOP_ITEM_TYPE_MIME_TYPE;
331 break;
332 case 'D':
333 if (!strcmp (type, "Directory"))
334 return MATE_DESKTOP_ITEM_TYPE_DIRECTORY;
335 break;
336 case 'S':
337 if (!strcmp (type, "Service"))
338 return MATE_DESKTOP_ITEM_TYPE_SERVICE;
339
340 else if (!strcmp (type, "ServiceType"))
341 return MATE_DESKTOP_ITEM_TYPE_SERVICE_TYPE;
342 break;
343 default:
344 break;
345 }
346
347 return MATE_DESKTOP_ITEM_TYPE_OTHER;
348}
349
350/**
351 * mate_desktop_item_new:
352 *
353 * Creates a MateDesktopItem object. The reference count on the returned value is set to '1'.
354 *
355 * Returns: The new MateDesktopItem
356 */
357MateDesktopItem *
358mate_desktop_item_new (void)
359{
360 MateDesktopItem *retval;
361
362 _mate_desktop_init_i18n ();
363
364 retval = g_new0 (MateDesktopItem, 1)((MateDesktopItem *) g_malloc0_n ((1), sizeof (MateDesktopItem
)))
;
365
366 retval->refcount++;
367
368 retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
369 (GDestroyNotify) g_free,
370 (GDestroyNotify) g_free);
371
372 /* These are guaranteed to be set */
373 mate_desktop_item_set_string (retval,
374 MATE_DESKTOP_ITEM_NAME"Name",
375 /* Translators: the "name" mentioned
376 * here is the name of an application or
377 * a document */
378 _("No name")((char *) g_dgettext ("mate-desktop", "No name")));
379 mate_desktop_item_set_string (retval,
380 MATE_DESKTOP_ITEM_ENCODING"Encoding",
381 "UTF-8");
382 mate_desktop_item_set_string (retval,
383 MATE_DESKTOP_ITEM_VERSION"Version",
384 "1.0");
385
386 retval->launch_time = 0;
387
388 return retval;
389}
390
391static Section *
392dup_section (Section *sec)
393{
394 GList *li;
395 Section *retval = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
396
397 retval->name = g_strdup (sec->name)g_strdup_inline (sec->name);
398
399 retval->keys = g_list_copy (sec->keys);
400 for (li = retval->keys; li != NULL((void*)0); li = li->next)
401 li->data = g_strdup (li->data)g_strdup_inline (li->data);
402
403 return retval;
404}
405
406static void
407copy_string_hash (gpointer key, gpointer value, gpointer user_data)
408{
409 GHashTable *copy = user_data;
410 g_hash_table_replace (copy,
411 g_strdup (key)g_strdup_inline (key),
412 g_strdup (value)g_strdup_inline (value));
413}
414
415/**
416 * mate_desktop_item_copy:
417 * @item: The item to be copied
418 *
419 * Creates a copy of a MateDesktopItem. The new copy has a refcount of 1.
420 * Note: Section stack is NOT copied.
421 *
422 * Returns: The new copy
423 */
424MateDesktopItem *
425mate_desktop_item_copy (const MateDesktopItem *item)
426{
427 GList *li;
428 MateDesktopItem *retval;
429
430 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
431 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
432
433 retval = mate_desktop_item_new ();
434
435 retval->type = item->type;
436 retval->modified = item->modified;
437 retval->location = g_strdup (item->location)g_strdup_inline (item->location);
438 retval->mtime = item->mtime;
439 retval->launch_time = item->launch_time;
440
441 /* Languages */
442 retval->languages = g_list_copy (item->languages);
443 for (li = retval->languages; li != NULL((void*)0); li = li->next)
444 li->data = g_strdup (li->data)g_strdup_inline (li->data);
445
446 /* Keys */
447 retval->keys = g_list_copy (item->keys);
448 for (li = retval->keys; li != NULL((void*)0); li = li->next)
449 li->data = g_strdup (li->data)g_strdup_inline (li->data);
450
451 /* Sections */
452 retval->sections = g_list_copy (item->sections);
453 for (li = retval->sections; li != NULL((void*)0); li = li->next)
454 li->data = dup_section (li->data);
455
456 retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
457 (GDestroyNotify) g_free,
458 (GDestroyNotify) g_free);
459
460 g_hash_table_foreach (item->main_hash,
461 copy_string_hash,
462 retval->main_hash);
463
464 return retval;
465}
466
467static void
468read_sort_order (MateDesktopItem *item, GFile *dir)
469{
470 GFile *child;
471 char buf[BUFSIZ8192];
472 GString *str;
473 ReadBuf *rb;
474
475 child = g_file_get_child (dir, ".order");
476
477 rb = readbuf_open (child, NULL((void*)0));
478 g_object_unref (child);
479
480 if (rb == NULL((void*)0))
481 return;
482
483 str = NULL((void*)0);
484 while (readbuf_gets (buf, sizeof (buf), rb) != NULL((void*)0)) {
485 if (str == NULL((void*)0))
486 str = g_string_new (buf);
487 else
488 g_string_append (str, buf)(__builtin_constant_p (buf) ? __extension__ ({ const char * const
__val = (buf); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, buf, (gssize) -1
))
;
489 g_string_append_c (str, ';')g_string_append_c_inline (str, ';');
490 }
491 readbuf_close (rb);
492 if (str != NULL((void*)0)) {
493 mate_desktop_item_set_string (item, MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder",
494 str->str);
495 g_string_free (str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(str), ((!(0)))) : g_string_free_and_steal (str)) : (g_string_free
) ((str), ((!(0)))))
;
496 }
497}
498
499static MateDesktopItem *
500make_fake_directory (GFile *dir)
501{
502 MateDesktopItem *item;
503 GFile *child;
504
505 item = mate_desktop_item_new ();
506 mate_desktop_item_set_entry_type (item,
507 MATE_DESKTOP_ITEM_TYPE_DIRECTORY);
508
509 item->mtime = DONT_UPDATE_MTIME((gint64)-2); /* it doesn't exist, we know that */
510 child = g_file_get_child (dir, ".directory");
511 mate_desktop_item_set_location_gfile (item, child);
512 item->mtime = 0;
513 g_object_unref (child);
514
515 read_sort_order (item, dir);
516
517 return item;
518}
519
520/**
521 * mate_desktop_item_new_from_file:
522 * @file: The filename or directory path to load the MateDesktopItem from
523 * @flags: Flags to influence the loading process
524 *
525 * This function loads 'file' and turns it into a MateDesktopItem.
526 *
527 * Returns: The newly loaded item.
528 */
529MateDesktopItem *
530mate_desktop_item_new_from_file (const char *file,
531 MateDesktopItemLoadFlags flags,
532 GError **error)
533{
534 MateDesktopItem *retval;
535 GFile *gfile;
536
537 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
538
539 gfile = g_file_new_for_path (file);
540 retval = mate_desktop_item_new_from_gfile (gfile, flags, error);
541 g_object_unref (gfile);
542
543 return retval;
544}
545
546/**
547 * mate_desktop_item_new_from_uri:
548 * @uri: URI to load the MateDesktopItem from
549 * @flags: Flags to influence the loading process
550 *
551 * This function loads 'uri' and turns it into a MateDesktopItem.
552 *
553 * Returns: The newly loaded item.
554 */
555MateDesktopItem *
556mate_desktop_item_new_from_uri (const char *uri,
557 MateDesktopItemLoadFlags flags,
558 GError **error)
559{
560 MateDesktopItem *retval;
561 GFile *file;
562
563 g_return_val_if_fail (uri != NULL, NULL)do { if ((uri != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "uri != NULL"); return
(((void*)0)); } } while (0)
;
564
565 file = g_file_new_for_uri (uri);
566 retval = mate_desktop_item_new_from_gfile (file, flags, error);
567 g_object_unref (file);
568
569 return retval;
570}
571
572static MateDesktopItem *
573mate_desktop_item_new_from_gfile (GFile *file,
574 MateDesktopItemLoadFlags flags,
575 GError **error)
576{
577 MateDesktopItem *retval;
578 GFile *subfn;
579 GFileInfo *info;
580 GFileType type;
581 GFile *parent;
582 gint64 mtime = 0;
583 ReadBuf *rb;
584
585 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
586
587 info = g_file_query_info (file,
588 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type"","G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
589 G_FILE_QUERY_INFO_NONE, NULL((void*)0), error);
590 if (info == NULL((void*)0))
591 return NULL((void*)0);
592
593 type = g_file_info_get_file_type (info);
594
595 if (type != G_FILE_TYPE_REGULAR && type != G_FILE_TYPE_DIRECTORY) {
596 char *uri;
597
598 uri = g_file_get_uri (file);
599 g_set_error (error,
600 /* FIXME: better errors */
601 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
602 MATE_DESKTOP_ITEM_ERROR_INVALID_TYPE,
603 _("File '%s' is not a regular file or directory.")((char *) g_dgettext ("mate-desktop", "File '%s' is not a regular file or directory."
))
,
604 uri);
605
606 g_free (uri);
607 g_object_unref (info);
608
609 return NULL((void*)0);
610 }
611
612 mtime = g_file_info_get_attribute_uint64 (info,
613 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
614
615 g_object_unref (info);
616
617 if (type == G_FILE_TYPE_DIRECTORY) {
618 GFile *child;
619 GFileInfo *child_info;
620
621 child = g_file_get_child (file, ".directory");
622 child_info = g_file_query_info (child,
623 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
624 G_FILE_QUERY_INFO_NONE,
625 NULL((void*)0), NULL((void*)0));
626
627 if (child_info == NULL((void*)0)) {
628 g_object_unref (child);
629
630 if (flags & MATE_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS) {
631 return NULL((void*)0);
632 } else {
633 return make_fake_directory (file);
634 }
635 }
636
637 mtime = g_file_info_get_attribute_uint64 (child_info,
638 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
639 g_object_unref (child_info);
640
641 subfn = child;
642 } else {
643 subfn = g_file_dup (file);
644 }
645
646 rb = readbuf_open (subfn, error);
647
648 if (rb == NULL((void*)0)) {
649 g_object_unref (subfn);
650 return NULL((void*)0);
651 }
652
653 retval = ditem_load (rb,
654 (flags & MATE_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS) != 0,
655 error);
656
657 if (retval == NULL((void*)0)) {
658 g_object_unref (subfn);
659 return NULL((void*)0);
660 }
661
662 if (flags & MATE_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS &&
663 ! mate_desktop_item_exists (retval)) {
664 mate_desktop_item_unref (retval);
665 g_object_unref (subfn);
666 return NULL((void*)0);
667 }
668
669 retval->mtime = DONT_UPDATE_MTIME((gint64)-2);
670 mate_desktop_item_set_location_gfile (retval, subfn);
671 retval->mtime = mtime;
672
673 parent = g_file_get_parent (file);
674 if (parent != NULL((void*)0)) {
675 read_sort_order (retval, parent);
676 g_object_unref (parent);
677 }
678
679 g_object_unref (subfn);
680
681 return retval;
682}
683
684/**
685 * mate_desktop_item_new_from_string:
686 * @string: string to load the MateDesktopItem from
687 * @length: length of string, or -1 to use strlen
688 * @flags: Flags to influence the loading process
689 * @error: place to put errors
690 *
691 * This function turns the contents of the string into a MateDesktopItem.
692 *
693 * Returns: The newly loaded item.
694 */
695MateDesktopItem *
696mate_desktop_item_new_from_string (const char *uri,
697 const char *string,
698 gssize length,
699 MateDesktopItemLoadFlags flags,
700 GError **error)
701{
702 MateDesktopItem *retval;
703 ReadBuf *rb;
704
705 g_return_val_if_fail (string != NULL, NULL)do { if ((string != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "string != NULL"
); return (((void*)0)); } } while (0)
;
706 g_return_val_if_fail (length >= -1, NULL)do { if ((length >= -1)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "length >= -1"
); return (((void*)0)); } } while (0)
;
707
708 if (length == -1) {
709 length = strlen (string);
710 }
711
712 rb = readbuf_new_from_string (uri, string, length);
713
714 retval = ditem_load (rb,
715 (flags & MATE_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS) != 0,
716 error);
717
718 if (retval == NULL((void*)0)) {
719 return NULL((void*)0);
720 }
721
722 /* FIXME: Sort order? */
723
724 return retval;
725}
726
727static char *
728lookup_desktop_file_in_data_dir (const char *desktop_file,
729 const char *data_dir)
730{
731 char *path;
732
733 path = g_build_filename (data_dir, "applications", desktop_file, NULL((void*)0));
734 if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
735 g_free (path);
736 return NULL((void*)0);
737 }
738 return path;
739}
740
741static char *
742file_from_basename (const char *basename)
743{
744 const char * const *system_data_dirs;
745 const char *user_data_dir;
746 char *retval;
747 int i;
748
749 user_data_dir = g_get_user_data_dir ();
750 system_data_dirs = g_get_system_data_dirs ();
751
752 if ((retval = lookup_desktop_file_in_data_dir (basename, user_data_dir))) {
753 return retval;
754 }
755 for (i = 0; system_data_dirs[i]; i++) {
756 if ((retval = lookup_desktop_file_in_data_dir (basename, system_data_dirs[i]))) {
757 return retval;
758 }
759 }
760 return NULL((void*)0);
761}
762
763/**
764 * mate_desktop_item_new_from_basename:
765 * @basename: The basename of the MateDesktopItem to load.
766 * @flags: Flags to influence the loading process
767 *
768 * This function loads 'basename' from a system data directory and
769 * returns its MateDesktopItem.
770 *
771 * Returns: The newly loaded item.
772 */
773MateDesktopItem *
774mate_desktop_item_new_from_basename (const char *basename,
775 MateDesktopItemLoadFlags flags,
776 GError **error)
777{
778 MateDesktopItem *retval;
779 char *file;
780
781 g_return_val_if_fail (basename != NULL, NULL)do { if ((basename != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "basename != NULL"
); return (((void*)0)); } } while (0)
;
782
783 if (!(file = file_from_basename (basename))) {
784 g_set_error (error,
785 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
786 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
787 _("Cannot find file '%s'")((char *) g_dgettext ("mate-desktop", "Cannot find file '%s'"
))
,
788 basename);
789 return NULL((void*)0);
790 }
791
792 retval = mate_desktop_item_new_from_file (file, flags, error);
793 g_free (file);
794
795 return retval;
796}
797
798/**
799 * mate_desktop_item_save:
800 * @item: A desktop item
801 * @under: A new uri (location) for this #MateDesktopItem
802 * @force: Save even if it wasn't modified
803 * @error: #GError return
804 *
805 * Writes the specified item to disk. If the 'under' is NULL, the original
806 * location is used. It sets the location of this entry to point to the
807 * new location.
808 *
809 * Returns: boolean. %TRUE if the file was saved, %FALSE otherwise
810 */
811gboolean
812mate_desktop_item_save (MateDesktopItem *item,
813 const char *under,
814 gboolean force,
815 GError **error)
816{
817 const char *uri;
818
819 if (under == NULL((void*)0) &&
1
Assuming 'under' is not equal to NULL
820 ! force &&
821 ! item->modified)
822 return TRUE(!(0));
823
824 if (under
1.1
'under' is not equal to NULL
== NULL((void*)0))
2
Taking false branch
825 uri = item->location;
826 else
827 uri = under;
828
829 if (uri
2.1
'uri' is not equal to NULL
== NULL((void*)0)) {
3
Taking false branch
830 g_set_error (error,
831 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
832 MATE_DESKTOP_ITEM_ERROR_NO_FILENAME,
833 _("No filename to save to")((char *) g_dgettext ("mate-desktop", "No filename to save to"
))
);
834 return FALSE(0);
835 }
836
837 if ( ! ditem_save (item, uri, error))
4
Calling 'ditem_save'
838 return FALSE(0);
839
840 item->modified = FALSE(0);
841 item->mtime = g_get_real_time () / G_USEC_PER_SEC1000000;
842
843 return TRUE(!(0));
844}
845
846/**
847 * mate_desktop_item_ref:
848 * @item: A desktop item
849 *
850 * Description: Increases the reference count of the specified item.
851 *
852 * Returns: the newly referenced @item
853 */
854MateDesktopItem *
855mate_desktop_item_ref (MateDesktopItem *item)
856{
857 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
858
859 item->refcount++;
860
861 return item;
862}
863
864static void
865free_section (gpointer data)
866{
867 Section *section = data;
868
869 g_free (section->name);
870 section->name = NULL((void*)0);
871
872 g_list_free_full (section->keys, g_free);
873 section->keys = NULL((void*)0);
874
875 g_free (section);
876}
877
878/**
879 * mate_desktop_item_unref:
880 * @item: A desktop item
881 *
882 * Decreases the reference count of the specified item, and destroys the item if there are no more references left.
883 */
884void
885mate_desktop_item_unref (MateDesktopItem *item)
886{
887 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
888 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
889
890 item->refcount--;
891
892 if(item->refcount != 0)
893 return;
894
895 g_list_free_full (item->languages, g_free);
896 item->languages = NULL((void*)0);
897
898 g_list_free_full (item->keys, g_free);
899 item->keys = NULL((void*)0);
900
901 g_list_free_full (item->sections, (GDestroyNotify) free_section);
902 item->sections = NULL((void*)0);
903
904 g_hash_table_destroy (item->main_hash);
905 item->main_hash = NULL((void*)0);
906
907 g_free (item->location);
908 item->location = NULL((void*)0);
909
910 g_free (item);
911}
912
913static Section *
914find_section (MateDesktopItem *item, const char *section)
915{
916 GList *li;
917 Section *sec;
918
919 if (section == NULL((void*)0))
920 return NULL((void*)0);
921 if (strcmp (section, "Desktop Entry") == 0)
922 return NULL((void*)0);
923
924 for (li = item->sections; li != NULL((void*)0); li = li->next) {
925 sec = li->data;
926 if (strcmp (sec->name, section) == 0)
927 return sec;
928 }
929
930 sec = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
931 sec->name = g_strdup (section)g_strdup_inline (section);
932 sec->keys = NULL((void*)0);
933
934 item->sections = g_list_append (item->sections, sec);
935
936 /* Don't mark the item modified, this is just an empty section,
937 * it won't be saved even */
938
939 return sec;
940}
941
942static Section *
943section_from_key (MateDesktopItem *item, const char *key)
944{
945 char *p;
946 char *name;
947 Section *sec;
948
949 if (key == NULL((void*)0))
950 return NULL((void*)0);
951
952 p = strchr (key, '/');
953 if (p == NULL((void*)0))
954 return NULL((void*)0);
955
956 name = g_strndup (key, p - key);
957
958 sec = find_section (item, name);
959
960 g_free (name);
961
962 return sec;
963}
964
965static const char *
966key_basename (const char *key)
967{
968 char *p = strrchr (key, '/');
969 if (p != NULL((void*)0))
970 return p+1;
971 else
972 return key;
973}
974
975static const char *
976lookup (const MateDesktopItem *item, const char *key)
977{
978 return g_hash_table_lookup (item->main_hash, key);
979}
980
981static const char *
982lookup_locale (const MateDesktopItem *item, const char *key, const char *locale)
983{
984 if (locale == NULL((void*)0) ||
985 strcmp (locale, "C") == 0) {
986 return lookup (item, key);
987 } else {
988 const char *ret;
989 char *full = g_strdup_printf ("%s[%s]", key, locale);
990 ret = lookup (item, full);
991 g_free (full);
992 return ret;
993 }
994}
995
996static const char *
997lookup_best_locale (const MateDesktopItem *item, const char *key)
998{
999 const char * const *langs_pointer;
1000 int i;
1001
1002 langs_pointer = g_get_language_names ();
1003 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
1004 const char *ret = NULL((void*)0);
1005
1006 ret = lookup_locale (item, key, langs_pointer[i]);
1007 if (ret != NULL((void*)0))
1008 return ret;
1009 }
1010
1011 return NULL((void*)0);
1012}
1013
1014static void
1015set (MateDesktopItem *item, const char *key, const char *value)
1016{
1017 Section *sec = section_from_key (item, key);
1018
1019 if (sec != NULL((void*)0)) {
1020 if (value != NULL((void*)0)) {
1021 if (g_hash_table_lookup (item->main_hash, key) == NULL((void*)0))
1022 sec->keys = g_list_append
1023 (sec->keys,
1024 g_strdup (key_basename (key))g_strdup_inline (key_basename (key)));
1025
1026 g_hash_table_replace (item->main_hash,
1027 g_strdup (key)g_strdup_inline (key),
1028 g_strdup (value)g_strdup_inline (value));
1029 } else {
1030 GList *list = g_list_find_custom
1031 (sec->keys, key_basename (key),
1032 (GCompareFunc)strcmp);
1033 if (list != NULL((void*)0)) {
1034 g_free (list->data);
1035 sec->keys =
1036 g_list_delete_link (sec->keys, list);
1037 }
1038 g_hash_table_remove (item->main_hash, key);
1039 }
1040 } else {
1041 if (value != NULL((void*)0)) {
1042 if (g_hash_table_lookup (item->main_hash, key) == NULL((void*)0))
1043 item->keys = g_list_append (item->keys,
1044 g_strdup (key)g_strdup_inline (key));
1045
1046 g_hash_table_replace (item->main_hash,
1047 g_strdup (key)g_strdup_inline (key),
1048 g_strdup (value)g_strdup_inline (value));
1049 } else {
1050 GList *list = g_list_find_custom
1051 (item->keys, key, (GCompareFunc)strcmp);
1052 if (list != NULL((void*)0)) {
1053 g_free (list->data);
1054 item->keys =
1055 g_list_delete_link (item->keys, list);
1056 }
1057 g_hash_table_remove (item->main_hash, key);
1058 }
1059 }
1060 item->modified = TRUE(!(0));
1061}
1062
1063static void
1064set_locale (MateDesktopItem *item, const char *key,
1065 const char *locale, const char *value)
1066{
1067 if (locale == NULL((void*)0) ||
1068 strcmp (locale, "C") == 0) {
1069 set (item, key, value);
1070 } else {
1071 char *full = g_strdup_printf ("%s[%s]", key, locale);
1072 set (item, full, value);
1073 g_free (full);
1074
1075 /* add the locale to the list of languages if it wasn't there
1076 * before */
1077 if (g_list_find_custom (item->languages, locale,
1078 (GCompareFunc)strcmp) == NULL((void*)0))
1079 item->languages = g_list_prepend (item->languages,
1080 g_strdup (locale)g_strdup_inline (locale));
1081 }
1082}
1083
1084static char **
1085list_to_vector (GSList *list)
1086{
1087 int len = g_slist_length (list);
1088 char **argv;
1089 int i;
1090 GSList *li;
1091
1092 argv = g_new0 (char *, len+1)((char * *) g_malloc0_n ((len+1), sizeof (char *)));
1093
1094 for (i = 0, li = list;
1095 li != NULL((void*)0);
1096 li = li->next, i++) {
1097 argv[i] = g_strdup (li->data)g_strdup_inline (li->data);
1098 }
1099 argv[i] = NULL((void*)0);
1100
1101 return argv;
1102}
1103
1104static GSList *
1105make_args (GList *files)
1106{
1107 GSList *list = NULL((void*)0);
1108 GList *li;
1109
1110 for (li = files; li != NULL((void*)0); li = li->next) {
1111 GFile *gfile;
1112 const char *file = li->data;
1113 if (file == NULL((void*)0))
1114 continue;
1115 gfile = g_file_new_for_uri (file);
1116 list = g_slist_prepend (list, gfile);
1117 }
1118
1119 return g_slist_reverse (list);
1120}
1121
1122static void
1123free_args (GSList *list)
1124{
1125 GSList *li;
1126
1127 for (li = list; li != NULL((void*)0); li = li->next) {
1128 g_object_unref (G_FILE (li->data)((((GFile*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((li->data)), ((g_file_get_type ()))))))
);
1129 li->data = NULL((void*)0);
1130 }
1131 g_slist_free (list);
1132}
1133
1134static char *
1135escape_single_quotes (const char *s,
1136 gboolean in_single_quotes,
1137 gboolean in_double_quotes)
1138{
1139 const char *p;
1140 GString *gs;
1141 const char *pre = "";
1142 const char *post = "";
1143
1144 if ( ! in_single_quotes && ! in_double_quotes) {
1145 pre = "'";
1146 post = "'";
1147 } else if ( ! in_single_quotes && in_double_quotes) {
1148 pre = "\"'";
1149 post = "'\"";
1150 }
1151
1152 if (strchr (s, '\'') == NULL((void*)0)) {
1153 return g_strconcat (pre, s, post, NULL((void*)0));
1154 }
1155
1156 gs = g_string_new (pre);
1157
1158 for (p = s; *p != '\0'; p++) {
1159 if (*p == '\'')
1160 g_string_append (gs, "'\\''")(__builtin_constant_p ("'\\''") ? __extension__ ({ const char
* const __val = ("'\\''"); g_string_append_len_inline (gs, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (gs, "'\\''"
, (gssize) -1))
;
1161 else
1162 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1163 }
1164
1165 g_string_append (gs, post)(__builtin_constant_p (post) ? __extension__ ({ const char * const
__val = (post); g_string_append_len_inline (gs, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (gs, post, (gssize) -1
))
;
1166
1167 return g_string_free (gs, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((gs),
((0))) : g_string_free_and_steal (gs)) : (g_string_free) ((gs
), ((0))))
;
1168}
1169
1170typedef enum {
1171 URI_TO_STRING,
1172 URI_TO_LOCAL_PATH,
1173 URI_TO_LOCAL_DIRNAME,
1174 URI_TO_LOCAL_BASENAME
1175} ConversionType;
1176
1177static char *
1178convert_uri (GFile *file,
1179 ConversionType conversion)
1180{
1181 char *retval = NULL((void*)0);
1182
1183 switch (conversion) {
1184 case URI_TO_STRING:
1185 retval = g_file_get_uri (file);
1186 break;
1187 case URI_TO_LOCAL_PATH:
1188 retval = g_file_get_path (file);
1189 break;
1190 case URI_TO_LOCAL_DIRNAME:
1191 {
1192 char *local_path;
1193
1194 local_path = g_file_get_path (file);
1195 retval = g_path_get_dirname (local_path);
1196 g_free (local_path);
1197 }
1198 break;
1199 case URI_TO_LOCAL_BASENAME:
1200 retval = g_file_get_basename (file);
1201 break;
1202 default:
1203 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-desktop-item.c"
, 1203, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1204 }
1205
1206 return retval;
1207}
1208
1209typedef enum {
1210 ADDED_NONE = 0,
1211 ADDED_SINGLE,
1212 ADDED_ALL
1213} AddedStatus;
1214
1215static AddedStatus
1216append_all_converted (GString *str,
1217 ConversionType conversion,
1218 GSList *args,
1219 gboolean in_single_quotes,
1220 gboolean in_double_quotes,
1221 AddedStatus added_status)
1222{
1223 GSList *l;
1224
1225 for (l = args; l; l = l->next) {
1226 char *converted;
1227 char *escaped;
1228
1229 if (!(converted = convert_uri (l->data, conversion)))
1230 continue;
1231
1232 g_string_append (str, " ")(__builtin_constant_p (" ") ? __extension__ ({ const char * const
__val = (" "); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, " ", (gssize) -1
))
;
1233
1234 escaped = escape_single_quotes (converted,
1235 in_single_quotes,
1236 in_double_quotes);
1237 g_string_append (str, escaped)(__builtin_constant_p (escaped) ? __extension__ ({ const char
* const __val = (escaped); g_string_append_len_inline (str, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (str, escaped
, (gssize) -1))
;
1238
1239 g_free (escaped);
1240 g_free (converted);
1241 }
1242
1243 return ADDED_ALL;
1244}
1245
1246static AddedStatus
1247append_first_converted (GString *str,
1248 ConversionType conversion,
1249 GSList **arg_ptr,
1250 gboolean in_single_quotes,
1251 gboolean in_double_quotes,
1252 AddedStatus added_status)
1253{
1254 GSList *l;
1255 char *converted = NULL((void*)0);
1256 char *escaped;
1257
1258 for (l = *arg_ptr; l; l = l->next) {
1259 if ((converted = convert_uri (l->data, conversion)))
1260 break;
1261
1262 *arg_ptr = l->next;
1263 }
1264
1265 if (!converted)
1266 return added_status;
1267
1268 escaped = escape_single_quotes (converted, in_single_quotes, in_double_quotes);
1269 g_string_append (str, escaped)(__builtin_constant_p (escaped) ? __extension__ ({ const char
* const __val = (escaped); g_string_append_len_inline (str, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (str, escaped
, (gssize) -1))
;
1270 g_free (escaped);
1271 g_free (converted);
1272
1273 return added_status != ADDED_ALL ? ADDED_SINGLE : added_status;
1274}
1275
1276static gboolean
1277do_percent_subst (const MateDesktopItem *item,
1278 const char *arg,
1279 GString *str,
1280 gboolean in_single_quotes,
1281 gboolean in_double_quotes,
1282 GSList *args,
1283 GSList **arg_ptr,
1284 AddedStatus *added_status)
1285{
1286 char *esc;
1287 const char *cs;
1288
1289 if (arg[0] != '%' || arg[1] == '\0') {
1290 return FALSE(0);
1291 }
1292
1293 switch (arg[1]) {
1294 case '%':
1295 g_string_append_c (str, '%')g_string_append_c_inline (str, '%');
1296 break;
1297 case 'U':
1298 *added_status = append_all_converted (str,
1299 URI_TO_STRING,
1300 args,
1301 in_single_quotes,
1302 in_double_quotes,
1303 *added_status);
1304 break;
1305 case 'F':
1306 *added_status = append_all_converted (str,
1307 URI_TO_LOCAL_PATH,
1308 args,
1309 in_single_quotes,
1310 in_double_quotes,
1311 *added_status);
1312 break;
1313 case 'N':
1314 *added_status = append_all_converted (str,
1315 URI_TO_LOCAL_BASENAME,
1316 args,
1317 in_single_quotes,
1318 in_double_quotes,
1319 *added_status);
1320 break;
1321 case 'D':
1322 *added_status = append_all_converted (str,
1323 URI_TO_LOCAL_DIRNAME,
1324 args,
1325 in_single_quotes,
1326 in_double_quotes,
1327 *added_status);
1328 break;
1329 case 'f':
1330 *added_status = append_first_converted (str,
1331 URI_TO_LOCAL_PATH,
1332 arg_ptr,
1333 in_single_quotes,
1334 in_double_quotes,
1335 *added_status);
1336 break;
1337 case 'u':
1338 *added_status = append_first_converted (str,
1339 URI_TO_STRING,
1340 arg_ptr,
1341 in_single_quotes,
1342 in_double_quotes,
1343 *added_status);
1344 break;
1345 case 'd':
1346 *added_status = append_first_converted (str,
1347 URI_TO_LOCAL_DIRNAME,
1348 arg_ptr,
1349 in_single_quotes,
1350 in_double_quotes,
1351 *added_status);
1352 break;
1353 case 'n':
1354 *added_status = append_first_converted (str,
1355 URI_TO_LOCAL_BASENAME,
1356 arg_ptr,
1357 in_single_quotes,
1358 in_double_quotes,
1359 *added_status);
1360 break;
1361 case 'm':
1362 /* Note: v0.9.4 of the spec says this is deprecated
1363 * and replace with --miniicon iconname */
1364 cs = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_MINI_ICON"MiniIcon");
1365 if (cs != NULL((void*)0)) {
1366 g_string_append (str, "--miniicon=")(__builtin_constant_p ("--miniicon=") ? __extension__ ({ const
char * const __val = ("--miniicon="); g_string_append_len_inline
(str, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(str, "--miniicon=", (gssize) -1))
;
1367 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1368 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1369 }
1370 break;
1371 case 'i':
1372 /* Note: v0.9.4 of the spec says replace with --icon iconname */
1373 cs = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_ICON"Icon");
1374 if (cs != NULL((void*)0)) {
1375 g_string_append (str, "--icon=")(__builtin_constant_p ("--icon=") ? __extension__ ({ const char
* const __val = ("--icon="); g_string_append_len_inline (str
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (str
, "--icon=", (gssize) -1))
;
1376 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1377 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1378 }
1379 break;
1380 case 'c':
1381 cs = mate_desktop_item_get_localestring (item, MATE_DESKTOP_ITEM_NAME"Name");
1382 if (cs != NULL((void*)0)) {
1383 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1384 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1385 g_free (esc);
1386 }
1387 break;
1388 case 'k':
1389 if (item->location != NULL((void*)0)) {
1390 esc = escape_single_quotes (item->location, in_single_quotes, in_double_quotes);
1391 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1392 g_free (esc);
1393 }
1394 break;
1395 case 'v':
1396 cs = mate_desktop_item_get_localestring (item, MATE_DESKTOP_ITEM_DEV"Dev");
1397 if (cs != NULL((void*)0)) {
1398 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1399 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1400 g_free (esc);
1401 }
1402 break;
1403 default:
1404 /* Maintain special characters - e.g. "%20" */
1405 if (g_ascii_isdigit (arg [1])((g_ascii_table[(guchar) (arg [1])] & G_ASCII_DIGIT) != 0
)
)
1406 g_string_append_c (str, '%')g_string_append_c_inline (str, '%');
1407 return FALSE(0);
1408 }
1409
1410 return TRUE(!(0));
1411}
1412
1413static char *
1414expand_string (const MateDesktopItem *item,
1415 const char *s,
1416 GSList *args,
1417 GSList **arg_ptr,
1418 AddedStatus *added_status)
1419{
1420 const char *p;
1421 gboolean escape = FALSE(0);
1422 gboolean single_quot = FALSE(0);
1423 gboolean double_quot = FALSE(0);
1424 GString *gs = g_string_new (NULL((void*)0));
1425
1426 for (p = s; *p != '\0'; p++) {
1427 if (escape) {
1428 escape = FALSE(0);
1429 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1430 } else if (*p == '\\') {
1431 if ( ! single_quot)
1432 escape = TRUE(!(0));
1433 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1434 } else if (*p == '\'') {
1435 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1436 if ( ! single_quot && ! double_quot) {
1437 single_quot = TRUE(!(0));
1438 } else if (single_quot) {
1439 single_quot = FALSE(0);
1440 }
1441 } else if (*p == '"') {
1442 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1443 if ( ! single_quot && ! double_quot) {
1444 double_quot = TRUE(!(0));
1445 } else if (double_quot) {
1446 double_quot = FALSE(0);
1447 }
1448 } else if (*p == '%') {
1449 if (do_percent_subst (item, p, gs,
1450 single_quot, double_quot,
1451 args, arg_ptr,
1452 added_status)) {
1453 p++;
1454 }
1455 } else {
1456 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1457 }
1458 }
1459 return g_string_free (gs, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((gs),
((0))) : g_string_free_and_steal (gs)) : (g_string_free) ((gs
), ((0))))
;
1460}
1461
1462/*Functions in this code block should only ever be reached in x11*/
1463#ifdef HAVE_STARTUP_NOTIFICATION
1464static void
1465sn_error_trap_push (SnDisplay *display,
1466 Display *xdisplay)
1467{
1468 GdkDisplay *gdkdisplay;
1469
1470 gdkdisplay = gdk_display_get_default ();
1471 gdk_x11_display_error_trap_push (gdkdisplay);
1472}
1473
1474static void
1475sn_error_trap_pop (SnDisplay *display,
1476 Display *xdisplay)
1477{
1478 GdkDisplay *gdkdisplay;
1479
1480 gdkdisplay = gdk_display_get_default ();
1481 gdk_x11_display_error_trap_pop_ignored (gdkdisplay);
1482}
1483
1484static char **
1485make_spawn_environment_for_sn_context (SnLauncherContext *sn_context,
1486 char **envp)
1487{
1488 char **retval;
1489 char **freeme;
1490 int i, j;
1491 int desktop_startup_id_len;
1492
1493 retval = freeme = NULL((void*)0);
1494
1495 if (envp == NULL((void*)0)) {
1496 envp = freeme = g_listenv ();
1497 for (i = 0; envp[i]; i++) {
1498 char *name = envp[i];
1499
1500 envp[i] = g_strjoin ("=", name, g_getenv (name), NULL((void*)0));
1501 g_free (name);
1502 }
1503 } else {
1504 for (i = 0; envp[i]; i++)
1505 ;
1506 }
1507
1508 retval = g_new (char *, i + 2)((char * *) g_malloc_n ((i + 2), sizeof (char *)));
1509
1510 desktop_startup_id_len = strlen ("DESKTOP_STARTUP_ID");
1511
1512 for (i = 0, j = 0; envp[i]; i++) {
1513 if (strncmp (envp[i], "DESKTOP_STARTUP_ID", desktop_startup_id_len) != 0) {
1514 retval[j] = g_strdup (envp[i])g_strdup_inline (envp[i]);
1515 ++j;
1516 }
1517 }
1518
1519 retval[j] = g_strdup_printf ("DESKTOP_STARTUP_ID=%s",
1520 sn_launcher_context_get_startup_id (sn_context));
1521 ++j;
1522 retval[j] = NULL((void*)0);
1523
1524 g_strfreev (freeme);
1525
1526 return retval;
1527}
1528
1529/* This should be fairly long, as it's confusing to users if a startup
1530 * ends when it shouldn't (it appears that the startup failed, and
1531 * they have to relaunch the app). Also the timeout only matters when
1532 * there are bugs and apps don't end their own startup sequence.
1533 *
1534 * This timeout is a "last resort" timeout that ignores whether the
1535 * startup sequence has shown activity or not. Marco and the
1536 * tasklist have smarter, and correspondingly able-to-be-shorter
1537 * timeouts. The reason our timeout is dumb is that we don't monitor
1538 * the sequence (don't use an SnMonitorContext)
1539 */
1540#define STARTUP_TIMEOUT_LENGTH_SEC30 30 /* seconds */
1541#define STARTUP_TIMEOUT_LENGTH(30 * 1000) (STARTUP_TIMEOUT_LENGTH_SEC30 * 1000)
1542
1543typedef struct
1544{
1545 GdkScreen *screen;
1546 GSList *contexts;
1547 guint timeout_id;
1548} StartupTimeoutData;
1549
1550static void
1551free_startup_timeout (void *data)
1552{
1553 StartupTimeoutData *std = data;
1554
1555 g_slist_free_full (std->contexts, (GDestroyNotify) sn_launcher_context_unref);
1556
1557 if (std->timeout_id != 0) {
1558 g_source_remove (std->timeout_id);
1559 std->timeout_id = 0;
1560 }
1561
1562 g_free (std);
1563}
1564
1565static gboolean
1566startup_timeout (void *data)
1567{
1568 StartupTimeoutData *std = data;
1569 GSList *tmp;
1570 int min_timeout;
1571
1572 min_timeout = STARTUP_TIMEOUT_LENGTH(30 * 1000);
1573
1574#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1575 gint64 now = g_get_real_time ();
1576#else
1577 GTimeVal now;
1578 g_get_current_time (&now);
1579#endif
1580
1581 tmp = std->contexts;
1582 while (tmp != NULL((void*)0)) {
1583 SnLauncherContext *sn_context = tmp->data;
1584 GSList *next = tmp->next;
1585 double elapsed;
1586
1587#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1588 time_t tv_sec;
1589 suseconds_t tv_usec;
1590 gint64 tv;
1591
1592 sn_launcher_context_get_last_active_time (sn_context, &tv_sec, &tv_usec);
1593 tv = (tv_sec * G_USEC_PER_SEC1000000) + tv_usec;
1594 elapsed = (double) (now - tv) / 1000.0;
1595#else
1596 long tv_sec, tv_usec;
1597
1598 sn_launcher_context_get_last_active_time (sn_context,
1599 &tv_sec, &tv_usec);
1600
1601 elapsed =
1602 ((((double)now.tv_sec - tv_sec) * G_USEC_PER_SEC1000000 +
1603 (now.tv_usec - tv_usec))) / 1000.0;
1604#endif
1605
1606 if (elapsed >= STARTUP_TIMEOUT_LENGTH(30 * 1000)) {
1607 std->contexts = g_slist_remove (std->contexts,
1608 sn_context);
1609 sn_launcher_context_complete (sn_context);
1610 sn_launcher_context_unref (sn_context);
1611 } else {
1612 min_timeout = MIN (min_timeout, (STARTUP_TIMEOUT_LENGTH - elapsed))(((min_timeout) < (((30 * 1000) - elapsed))) ? (min_timeout
) : (((30 * 1000) - elapsed)))
;
1613 }
1614
1615 tmp = next;
1616 }
1617
1618 /* we'll use seconds for the timeout */
1619 if (min_timeout < 1000)
1620 min_timeout = 1000;
1621
1622 if (std->contexts == NULL((void*)0)) {
1623 std->timeout_id = 0;
1624 } else {
1625 std->timeout_id = g_timeout_add_seconds (min_timeout / 1000,
1626 startup_timeout,
1627 std);
1628 }
1629
1630 /* always remove this one, but we may have reinstalled another one. */
1631 return FALSE(0);
1632}
1633
1634static void
1635add_startup_timeout (GdkScreen *screen,
1636 SnLauncherContext *sn_context)
1637{
1638 StartupTimeoutData *data;
1639
1640 data = g_object_get_data (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "mate-startup-data");
1641 if (data == NULL((void*)0)) {
1642 data = g_new (StartupTimeoutData, 1)((StartupTimeoutData *) g_malloc_n ((1), sizeof (StartupTimeoutData
)))
;
1643 data->screen = screen;
1644 data->contexts = NULL((void*)0);
1645 data->timeout_id = 0;
1646
1647 g_object_set_data_full (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "mate-startup-data",
1648 data, free_startup_timeout);
1649 }
1650
1651 sn_launcher_context_ref (sn_context);
1652 data->contexts = g_slist_prepend (data->contexts, sn_context);
1653
1654 if (data->timeout_id == 0) {
1655 data->timeout_id = g_timeout_add_seconds (
1656 STARTUP_TIMEOUT_LENGTH_SEC30,
1657 startup_timeout,
1658 data);
1659 }
1660}
1661#endif /* HAVE_STARTUP_NOTIFICATION - functions should only be reached in x11*/
1662
1663static inline char *
1664stringify_uris (GSList *args)
1665{
1666 GString *str;
1667
1668 str = g_string_new (NULL((void*)0));
1669
1670 append_all_converted (str, URI_TO_STRING, args, FALSE(0), FALSE(0), ADDED_NONE);
1671
1672 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1673}
1674
1675static inline char *
1676stringify_files (GSList *args)
1677{
1678 GString *str;
1679
1680 str = g_string_new (NULL((void*)0));
1681
1682 append_all_converted (str, URI_TO_LOCAL_PATH, args, FALSE(0), FALSE(0), ADDED_NONE);
1683
1684 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1685}
1686
1687static char **
1688make_environment_for_screen (GdkScreen *screen,
1689 char **envp)
1690{
1691 GdkDisplay *display;
1692 char **retval;
1693 char **freeme;
1694 char *display_name;
1695 int display_index = -1;
1696 int i, env_len;
1697
1698 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((screen)); GType __t = ((gdk_screen_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "GDK_IS_SCREEN (screen)"); return (((void*)0)
); } } while (0)
;
1699
1700 retval = freeme = NULL((void*)0);
1701
1702 if (envp == NULL((void*)0)) {
1703 envp = freeme = g_listenv ();
1704 for (i = 0; envp [i]; i++) {
1705 char *name = envp[i];
1706
1707 envp[i] = g_strjoin ("=", name, g_getenv (name), NULL((void*)0));
1708 g_free (name);
1709 }
1710 }
1711
1712 for (env_len = 0; envp [env_len]; env_len++)
1713 if (strncmp (envp [env_len], "DISPLAY", strlen ("DISPLAY")) == 0)
1714 display_index = env_len;
1715
1716 retval = g_new (char *, env_len + 1)((char * *) g_malloc_n ((env_len + 1), sizeof (char *)));
1717 retval [env_len] = NULL((void*)0);
1718
1719 display = gdk_screen_get_display (screen);
1720 display_name = g_strdup (gdk_display_get_name (display))g_strdup_inline (gdk_display_get_name (display));
1721
1722 for (i = 0; i < env_len; i++)
1723 if (i == display_index)
1724 retval [i] = g_strconcat ("DISPLAY=", display_name, NULL((void*)0));
1725 else
1726 retval [i] = g_strdup (envp[i])g_strdup_inline (envp[i]);
1727
1728 g_assert (i == env_len)do { if (i == env_len) ; else g_assertion_message_expr ("MateDesktop"
, "mate-desktop-item.c", 1728, ((const char*) (__func__)), "i == env_len"
); } while (0)
;
1729
1730 g_free (display_name);
1731 g_strfreev (freeme);
1732
1733 return retval;
1734}
1735
1736static void
1737dummy_child_watch (GPid pid,
1738 gint status,
1739 gpointer user_data)
1740{
1741 /* Nothing, this is just to ensure we don't double fork
1742 * and break pkexec:
1743 * https://bugzilla.gnome.org/show_bug.cgi?id=675789
1744 */
1745}
1746
1747static int
1748ditem_execute (const MateDesktopItem *item,
1749 const char *exec,
1750 GList *file_list,
1751 GdkScreen *screen,
1752 int workspace,
1753 char **envp,
1754 gboolean launch_only_one,
1755 gboolean use_current_dir,
1756 gboolean append_uris,
1757 gboolean append_paths,
1758 gboolean do_not_reap_child,
1759 GError **error)
1760{
1761 char **free_me = NULL((void*)0);
1762 char **real_argv;
1763 int i, ret;
1764 char **term_argv = NULL((void*)0);
1765 int term_argc = 0;
1766 GSList *vector_list;
1767 GSList *args, *arg_ptr;
1768 AddedStatus added_status;
1769 const char *working_dir = NULL((void*)0);
1770 char **temp_argv = NULL((void*)0);
1771 int temp_argc = 0;
1772 char *new_exec, *uris, *temp;
1773 char *exec_locale;
1774 int launched = 0;
1775 GPid pid;
1776#ifdef HAVE_STARTUP_NOTIFICATION
1777 GdkDisplay *gdkdisplay;
1778 SnLauncherContext *sn_context;
1779 SnDisplay *sn_display;
1780 const char *startup_class;
1781#endif
1782
1783 g_return_val_if_fail (item, -1)do { if ((item)) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "item"); return (-1); } } while
(0)
;
1784
1785 if (item->type == MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
1786 working_dir = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_PATH"Path");
1787 if (working_dir &&
1788 !g_file_test (working_dir, G_FILE_TEST_IS_DIR))
1789 working_dir = NULL((void*)0);
1790 }
1791
1792 if (working_dir == NULL((void*)0) && !use_current_dir)
1793 working_dir = g_get_home_dir ();
1794
1795 if (mate_desktop_item_get_boolean (item, MATE_DESKTOP_ITEM_TERMINAL"Terminal")) {
1796 const char *options =
1797 mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_TERMINAL_OPTIONS"TerminalOptions");
1798
1799 if (options != NULL((void*)0)) {
1800 g_shell_parse_argv (options,
1801 &term_argc,
1802 &term_argv,
1803 NULL((void*)0) /* error */);
1804 /* ignore errors */
1805 }
1806
1807 mate_desktop_prepend_terminal_to_vector (&term_argc, &term_argv);
1808 }
1809
1810 args = make_args (file_list);
1811 arg_ptr = make_args (file_list);
1812
1813#ifdef HAVE_STARTUP_NOTIFICATION
1814 GdkDisplay *display = gdk_screen_get_display (gdk_screen_get_default());
1815 if (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1816 {
1817 if (screen)
1818 gdkdisplay = gdk_screen_get_display (screen);
1819 else
1820 gdkdisplay = gdk_display_get_default ();
1821
1822 sn_display = sn_display_new (GDK_DISPLAY_XDISPLAY (gdkdisplay)(gdk_x11_display_get_xdisplay (gdkdisplay)),
1823 sn_error_trap_push,
1824 sn_error_trap_pop);
1825
1826 /* Only initiate notification if desktop file supports it.
1827 * (we could avoid setting up the SnLauncherContext if we aren't going
1828 * to initiate, but why bother)
1829 */
1830
1831 startup_class = mate_desktop_item_get_string (item,
1832 "StartupWMClass");
1833 if (startup_class ||
1834 mate_desktop_item_get_boolean (item, "StartupNotify")) {
1835 const char *name;
1836 const char *icon;
1837
1838 sn_context = sn_launcher_context_new (sn_display,
1839 screen ? gdk_x11_screen_get_screen_number (screen) :
1840 DefaultScreen (GDK_DISPLAY_XDISPLAY (gdkdisplay))(((_XPrivDisplay)((gdk_x11_display_get_xdisplay (gdkdisplay))
))->default_screen)
);
1841
1842 name = mate_desktop_item_get_localestring (item,
1843 MATE_DESKTOP_ITEM_NAME"Name");
1844
1845 if (name == NULL((void*)0))
1846 name = mate_desktop_item_get_localestring (item,
1847 MATE_DESKTOP_ITEM_GENERIC_NAME"GenericName");
1848
1849 if (name != NULL((void*)0)) {
1850 char *description;
1851
1852 sn_launcher_context_set_name (sn_context, name);
1853
1854 description = g_strdup_printf (_("Starting %s")((char *) g_dgettext ("mate-desktop", "Starting %s")), name);
1855
1856 sn_launcher_context_set_description (sn_context, description);
1857
1858 g_free (description);
1859 }
1860
1861 icon = mate_desktop_item_get_string (item,
1862 MATE_DESKTOP_ITEM_ICON"Icon");
1863
1864 if (icon != NULL((void*)0))
1865 sn_launcher_context_set_icon_name (sn_context, icon);
1866
1867 sn_launcher_context_set_workspace (sn_context, workspace);
1868
1869 if (startup_class != NULL((void*)0))
1870 sn_launcher_context_set_wmclass (sn_context,
1871 startup_class);
1872 } else {
1873 sn_context = NULL((void*)0);
1874 }
1875 }
1876 else {
1877 sn_context = NULL((void*)0);
1878 sn_display = NULL((void*)0);
1879 }
1880#endif
1881
1882 if (screen) {
1883 envp = make_environment_for_screen (screen, envp);
1884 if (free_me)
1885 g_strfreev (free_me);
1886 free_me = envp;
1887 }
1888
1889 exec_locale = g_filename_from_utf8 (exec, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
1890
1891 if (exec_locale == NULL((void*)0)) {
1892 exec_locale = g_strdup ("")g_strdup_inline ("");
1893 }
1894
1895 do {
1896 added_status = ADDED_NONE;
1897 new_exec = expand_string (item,
1898 exec_locale,
1899 args, &arg_ptr, &added_status);
1900
1901 if (launched == 0 && added_status == ADDED_NONE && append_uris) {
1902 uris = stringify_uris (args);
1903 temp = g_strconcat (new_exec, " ", uris, NULL((void*)0));
1904 g_free (uris);
1905 g_free (new_exec);
1906 new_exec = temp;
1907 added_status = ADDED_ALL;
1908 }
1909
1910 /* append_uris and append_paths are mutually exlusive */
1911 if (launched == 0 && added_status == ADDED_NONE && append_paths) {
1912 uris = stringify_files (args);
1913 temp = g_strconcat (new_exec, " ", uris, NULL((void*)0));
1914 g_free (uris);
1915 g_free (new_exec);
1916 new_exec = temp;
1917 added_status = ADDED_ALL;
1918 }
1919
1920 if (launched > 0 && added_status == ADDED_NONE) {
1921 g_free (new_exec);
1922 break;
1923 }
1924
1925 if ( ! g_shell_parse_argv (new_exec,
1926 &temp_argc, &temp_argv, error)) {
1927 /* The error now comes from g_shell_parse_argv */
1928 g_free (new_exec);
1929 ret = -1;
1930 break;
1931 }
1932 g_free (new_exec);
1933
1934 vector_list = NULL((void*)0);
1935 for(i = 0; i < term_argc; i++)
1936 vector_list = g_slist_append (vector_list,
1937 g_strdup (term_argv[i])g_strdup_inline (term_argv[i]));
1938
1939 for(i = 0; i < temp_argc; i++)
1940 vector_list = g_slist_append (vector_list,
1941 g_strdup (temp_argv[i])g_strdup_inline (temp_argv[i]));
1942
1943 g_strfreev (temp_argv);
1944
1945 real_argv = list_to_vector (vector_list);
1946 g_slist_free_full (vector_list, g_free);
1947
1948#ifdef HAVE_STARTUP_NOTIFICATION
1949 if (sn_context != NULL((void*)0) && (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) &&
1950 !sn_launcher_context_get_initiated (sn_context)) {
1951 guint32 launch_time;
1952
1953 /* This means that we always use the first real_argv[0]
1954 * we select for the "binary name", but it's probably
1955 * OK to do that. Binary name isn't super-important
1956 * anyway, and we can't initiate twice, and we
1957 * must initiate prior to fork/exec.
1958 */
1959
1960 sn_launcher_context_set_binary_name (sn_context,
1961 real_argv[0]);
1962
1963 if (item->launch_time > 0)
1964 launch_time = item->launch_time;
1965 else
1966 launch_time = gdk_x11_display_get_user_time (gdkdisplay);
1967
1968 sn_launcher_context_initiate (sn_context,
1969 g_get_prgname () ? g_get_prgname () : "unknown",
1970 real_argv[0],
1971 launch_time);
1972
1973 /* Don't allow accidental reuse of same timestamp */
1974 ((MateDesktopItem *)item)->launch_time = 0;
1975
1976 envp = make_spawn_environment_for_sn_context (sn_context, envp);
1977 if (free_me)
1978 g_strfreev (free_me);
1979 free_me = envp;
1980 }
1981#endif
1982
1983 if ( ! g_spawn_async (working_dir,
1984 real_argv,
1985 envp,
1986 (do_not_reap_child ? G_SPAWN_DO_NOT_REAP_CHILD : 0) | G_SPAWN_SEARCH_PATH /* flags */,
1987 NULL((void*)0), /* child_setup_func */
1988 NULL((void*)0), /* child_setup_func_data */
1989 (do_not_reap_child ? &pid : NULL((void*)0)) /* child_pid */,
1990 error)) {
1991 /* The error was set for us,
1992 * we just can't launch this thingie */
1993 ret = -1;
1994 g_strfreev (real_argv);
1995 break;
1996 } else if (do_not_reap_child) {
1997 g_child_watch_add (pid, dummy_child_watch, NULL((void*)0));
1998 }
1999
2000 launched ++;
2001
2002 g_strfreev (real_argv);
2003
2004 if (arg_ptr != NULL((void*)0))
2005 arg_ptr = arg_ptr->next;
2006
2007 /* rinse, repeat until we run out of arguments (That
2008 * is if we were adding singles anyway) */
2009 } while (added_status == ADDED_SINGLE &&
2010 arg_ptr != NULL((void*)0) &&
2011 ! launch_only_one);
2012
2013 g_free (exec_locale);
2014#ifdef HAVE_STARTUP_NOTIFICATION
2015 if ((sn_context != NULL((void*)0)) && (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)){
2016 if (ret < 0)
2017 sn_launcher_context_complete (sn_context); /* end sequence */
2018 else
2019 add_startup_timeout (screen ? screen :
2020 gdk_display_get_default_screen (gdk_display_get_default ()),
2021 sn_context);
2022 sn_launcher_context_unref (sn_context);
2023 }
2024 if (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2025 sn_display_unref (sn_display);
2026
2027#endif /* HAVE_STARTUP_NOTIFICATION */
2028
2029 free_args (args);
2030
2031 if (term_argv)
2032 g_strfreev (term_argv);
2033
2034 if (free_me)
2035 g_strfreev (free_me);
2036
2037 return ret;
2038}
2039
2040/* strip any trailing &, return FALSE if bad things happen and
2041 we end up with an empty string */
2042static gboolean
2043strip_the_amp (char *exec)
2044{
2045 size_t exec_len;
2046
2047 g_strstrip (exec)g_strchomp (g_strchug (exec));
2048 if (*exec == '\0')
2049 return FALSE(0);
2050
2051 exec_len = strlen (exec);
2052 /* kill any trailing '&' */
2053 if (exec[exec_len-1] == '&') {
2054 exec[exec_len-1] = '\0';
2055 g_strchomp (exec);
2056 }
2057
2058 /* can't exactly launch an empty thing */
2059 if (*exec == '\0')
2060 return FALSE(0);
2061
2062 return TRUE(!(0));
2063}
2064
2065static int
2066mate_desktop_item_launch_on_screen_with_env (
2067 const MateDesktopItem *item,
2068 GList *file_list,
2069 MateDesktopItemLaunchFlags flags,
2070 GdkScreen *screen,
2071 int workspace,
2072 char **envp,
2073 GError **error)
2074{
2075 const char *exec;
2076 char *the_exec;
2077 int ret;
2078
2079 exec = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_EXEC"Exec");
2080 /* This is a URL, so launch it as a url */
2081 if (item->type == MATE_DESKTOP_ITEM_TYPE_LINK) {
2082 const char *url;
2083 gboolean retval;
2084
2085 url = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_URL"URL");
2086 /* Mate panel used to put this in Exec */
2087 if (!(url && url[0] != '\0'))
2088 url = exec;
2089
2090 if (!(url && url[0] != '\0')) {
2091 g_set_error (error,
2092 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2093 MATE_DESKTOP_ITEM_ERROR_NO_URL,
2094 _("No URL to launch")((char *) g_dgettext ("mate-desktop", "No URL to launch")));
2095 return -1;
2096 }
2097
2098 retval = gtk_show_uri_on_window (NULL((void*)0),
2099 url,
2100 GDK_CURRENT_TIME0L,
2101 error);
2102 return retval ? 0 : -1;
2103 }
2104
2105 /* check the type, if there is one set */
2106 if (item->type != MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
2107 g_set_error (error,
2108 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2109 MATE_DESKTOP_ITEM_ERROR_NOT_LAUNCHABLE,
2110 _("Not a launchable item")((char *) g_dgettext ("mate-desktop", "Not a launchable item"
))
);
2111 return -1;
2112 }
2113
2114 if (exec == NULL((void*)0) ||
2115 exec[0] == '\0') {
2116 g_set_error (error,
2117 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2118 MATE_DESKTOP_ITEM_ERROR_NO_EXEC_STRING,
2119 _("No command (Exec) to launch")((char *) g_dgettext ("mate-desktop", "No command (Exec) to launch"
))
);
2120 return -1;
2121 }
2122
2123 /* make a new copy and get rid of spaces */
2124 the_exec = g_alloca (strlen (exec) + 1)__builtin_alloca (strlen (exec) + 1);
2125 g_strlcpy (the_exec, exec, strlen (exec) + 1);
2126
2127 if ( ! strip_the_amp (the_exec)) {
2128 g_set_error (error,
2129 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2130 MATE_DESKTOP_ITEM_ERROR_BAD_EXEC_STRING,
2131 _("Bad command (Exec) to launch")((char *) g_dgettext ("mate-desktop", "Bad command (Exec) to launch"
))
);
2132 return -1;
2133 }
2134
2135 ret = ditem_execute (item, the_exec, file_list, screen, workspace, envp,
2136 (flags & MATE_DESKTOP_ITEM_LAUNCH_ONLY_ONE),
2137 (flags & MATE_DESKTOP_ITEM_LAUNCH_USE_CURRENT_DIR),
2138 (flags & MATE_DESKTOP_ITEM_LAUNCH_APPEND_URIS),
2139 (flags & MATE_DESKTOP_ITEM_LAUNCH_APPEND_PATHS),
2140 (flags & MATE_DESKTOP_ITEM_LAUNCH_DO_NOT_REAP_CHILD),
2141 error);
2142
2143 return ret;
2144}
2145
2146/**
2147 * mate_desktop_item_launch:
2148 * @item: A desktop item
2149 * @file_list: Files/URIs to launch this item with, can be %NULL
2150 * @flags: FIXME
2151 * @error: FIXME
2152 *
2153 * This function runs the program listed in the specified 'item',
2154 * optionally appending additional arguments to its command line. It uses
2155 * #g_shell_parse_argv to parse the the exec string into a vector which is
2156 * then passed to #g_spawn_async for execution. This can return all
2157 * the errors from MateURL, #g_shell_parse_argv and #g_spawn_async,
2158 * in addition to it's own. The files are
2159 * only added if the entry defines one of the standard % strings in it's
2160 * Exec field.
2161 *
2162 * Returns: The the pid of the process spawned. If more then one
2163 * process was spawned the last pid is returned. On error -1
2164 * is returned and @error is set.
2165 */
2166int
2167mate_desktop_item_launch (const MateDesktopItem *item,
2168 GList *file_list,
2169 MateDesktopItemLaunchFlags flags,
2170 GError **error)
2171{
2172 return mate_desktop_item_launch_on_screen_with_env (
2173 item, file_list, flags, NULL((void*)0), -1, NULL((void*)0), error);
2174}
2175
2176/**
2177 * mate_desktop_item_launch_with_env:
2178 * @item: A desktop item
2179 * @file_list: Files/URIs to launch this item with, can be %NULL
2180 * @flags: FIXME
2181 * @envp: child's environment, or %NULL to inherit parent's
2182 * @error: FIXME
2183 *
2184 * See mate_desktop_item_launch for a full description. This function
2185 * additionally passes an environment vector for the child process
2186 * which is to be launched.
2187 *
2188 * Returns: The the pid of the process spawned. If more then one
2189 * process was spawned the last pid is returned. On error -1
2190 * is returned and @error is set.
2191 */
2192int
2193mate_desktop_item_launch_with_env (const MateDesktopItem *item,
2194 GList *file_list,
2195 MateDesktopItemLaunchFlags flags,
2196 char **envp,
2197 GError **error)
2198{
2199 return mate_desktop_item_launch_on_screen_with_env (
2200 item, file_list, flags,
2201 NULL((void*)0), -1, envp, error);
2202}
2203
2204/**
2205 * mate_desktop_item_launch_on_screen:
2206 * @item: A desktop item
2207 * @file_list: Files/URIs to launch this item with, can be %NULL
2208 * @flags: FIXME
2209 * @screen: the %GdkScreen on which the application should be launched
2210 * @workspace: the workspace on which the app should be launched (-1 for current)
2211 * @error: FIXME
2212 *
2213 * See mate_desktop_item_launch for a full description. This function
2214 * additionally attempts to launch the application on a given screen
2215 * and workspace.
2216 *
2217 * Returns: The the pid of the process spawned. If more then one
2218 * process was spawned the last pid is returned. On error -1
2219 * is returned and @error is set.
2220 */
2221int
2222mate_desktop_item_launch_on_screen (const MateDesktopItem *item,
2223 GList *file_list,
2224 MateDesktopItemLaunchFlags flags,
2225 GdkScreen *screen,
2226 int workspace,
2227 GError **error)
2228{
2229 return mate_desktop_item_launch_on_screen_with_env (
2230 item, file_list, flags,
2231 screen, workspace, NULL((void*)0), error);
2232}
2233
2234/**
2235 * mate_desktop_item_drop_uri_list:
2236 * @item: A desktop item
2237 * @uri_list: text as gotten from a text/uri-list
2238 * @flags: FIXME
2239 * @error: FIXME
2240 *
2241 * A list of files or urls dropped onto an icon, the proper (Url or File)
2242 * exec is run you can pass directly string that you got as the
2243 * text/uri-list. This just parses the list and calls
2244 *
2245 * Returns: The value returned by #mate_execute_async() upon execution of
2246 * the specified item or -1 on error. If multiple instances are run, the
2247 * return of the last one is returned.
2248 */
2249int
2250mate_desktop_item_drop_uri_list (const MateDesktopItem *item,
2251 const char *uri_list,
2252 MateDesktopItemLaunchFlags flags,
2253 GError **error)
2254{
2255 return mate_desktop_item_drop_uri_list_with_env (item, uri_list,
2256 flags, NULL((void*)0), error);
2257}
2258
2259/**
2260* mate_desktop_item_drop_uri_list_with_env:
2261* @item: A desktop item
2262* @uri_list: text as gotten from a text/uri-list
2263* @flags: FIXME
2264* @envp: child's environment
2265* @error: FIXME
2266*
2267* See mate_desktop_item_drop_uri_list for a full description. This function
2268* additionally passes an environment vector for the child process
2269* which is to be launched.
2270*
2271* Returns: The value returned by #mate_execute_async() upon execution of
2272* the specified item or -1 on error. If multiple instances are run, the
2273* return of the last one is returned.
2274*/
2275int
2276mate_desktop_item_drop_uri_list_with_env (const MateDesktopItem *item,
2277 const char *uri_list,
2278 MateDesktopItemLaunchFlags flags,
2279 char **envp,
2280 GError **error)
2281{
2282 int ret;
2283 char *uri;
2284 char **uris;
2285 GList *list = NULL((void*)0);
2286
2287 uris = g_uri_list_extract_uris (uri_list);
2288
2289 for (uri = uris[0]; uri != NULL((void*)0); uri++) {
2290 list = g_list_prepend (list, uri);
2291 }
2292 list = g_list_reverse (list);
2293
2294 ret = mate_desktop_item_launch_with_env (
2295 item, list, flags, envp, error);
2296
2297 g_strfreev (uris);
2298 g_list_free (list);
2299
2300 return ret;
2301}
2302
2303static gboolean
2304exec_exists (const char *exec)
2305{
2306 if (g_path_is_absolute (exec)) {
2307 if (access (exec, X_OK1) == 0)
2308 return TRUE(!(0));
2309 else
2310 return FALSE(0);
2311 } else {
2312 char *tryme;
2313
2314 tryme = g_find_program_in_path (exec);
2315 if (tryme != NULL((void*)0)) {
2316 g_free (tryme);
2317 return TRUE(!(0));
2318 }
2319 return FALSE(0);
2320 }
2321}
2322
2323/**
2324 * mate_desktop_item_exists:
2325 * @item: A desktop item
2326 *
2327 * Attempt to figure out if the program that can be executed by this item
2328 * actually exists. First it tries the TryExec attribute to see if that
2329 * contains a program that is in the path. Then if there is no such
2330 * attribute, it tries the first word of the Exec attribute.
2331 *
2332 * Returns: A boolean, %TRUE if it exists, %FALSE otherwise.
2333 */
2334gboolean
2335mate_desktop_item_exists (const MateDesktopItem *item)
2336{
2337 const char *try_exec;
2338 const char *exec;
2339
2340 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2341
2342 try_exec = lookup (item, MATE_DESKTOP_ITEM_TRY_EXEC"TryExec");
2343
2344 if (try_exec != NULL((void*)0) &&
2345 ! exec_exists (try_exec)) {
2346 return FALSE(0);
2347 }
2348
2349 if (item->type == MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
2350 int argc;
2351 char **argv;
2352 const char *exe;
2353
2354 exec = lookup (item, MATE_DESKTOP_ITEM_EXEC"Exec");
2355 if (exec == NULL((void*)0))
2356 return FALSE(0);
2357
2358 if ( ! g_shell_parse_argv (exec, &argc, &argv, NULL((void*)0)))
2359 return FALSE(0);
2360
2361 if (argc < 1) {
2362 g_strfreev (argv);
2363 return FALSE(0);
2364 }
2365
2366 exe = argv[0];
2367
2368 if ( ! exec_exists (exe)) {
2369 g_strfreev (argv);
2370 return FALSE(0);
2371 }
2372 g_strfreev (argv);
2373 }
2374
2375 return TRUE(!(0));
2376}
2377
2378/**
2379 * mate_desktop_item_get_entry_type:
2380 * @item: A desktop item
2381 *
2382 * Gets the type attribute (the 'Type' field) of the item. This should
2383 * usually be 'Application' for an application, but it can be 'Directory'
2384 * for a directory description. There are other types available as well.
2385 * The type usually indicates how the desktop item should be handeled and
2386 * how the 'Exec' field should be handeled.
2387 *
2388 * Returns: The type of the specified 'item'. The returned
2389 * memory remains owned by the MateDesktopItem and should not be freed.
2390 */
2391MateDesktopItemType
2392mate_desktop_item_get_entry_type (const MateDesktopItem *item)
2393{
2394 g_return_val_if_fail (item != NULL, 0)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (0); } } while (0)
;
2395 g_return_val_if_fail (item->refcount > 0, 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (0); } } while (0)
;
2396
2397 return item->type;
2398}
2399
2400void
2401mate_desktop_item_set_entry_type (MateDesktopItem *item,
2402 MateDesktopItemType type)
2403{
2404 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2405 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2406
2407 item->type = type;
2408
2409 switch (type) {
2410 case MATE_DESKTOP_ITEM_TYPE_NULL:
2411 set (item, MATE_DESKTOP_ITEM_TYPE"Type", NULL((void*)0));
2412 break;
2413 case MATE_DESKTOP_ITEM_TYPE_APPLICATION:
2414 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Application");
2415 break;
2416 case MATE_DESKTOP_ITEM_TYPE_LINK:
2417 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Link");
2418 break;
2419 case MATE_DESKTOP_ITEM_TYPE_FSDEVICE:
2420 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "FSDevice");
2421 break;
2422 case MATE_DESKTOP_ITEM_TYPE_MIME_TYPE:
2423 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "MimeType");
2424 break;
2425 case MATE_DESKTOP_ITEM_TYPE_DIRECTORY:
2426 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Directory");
2427 break;
2428 case MATE_DESKTOP_ITEM_TYPE_SERVICE:
2429 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Service");
2430 break;
2431 case MATE_DESKTOP_ITEM_TYPE_SERVICE_TYPE:
2432 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "ServiceType");
2433 break;
2434 default:
2435 break;
2436 }
2437}
2438
2439/**
2440 * mate_desktop_item_get_file_status:
2441 * @item: A desktop item
2442 *
2443 * This function checks the modification time of the on-disk file to
2444 * see if it is more recent than the in-memory data.
2445 *
2446 * Returns: An enum value that specifies whether the item has changed since being loaded.
2447 */
2448MateDesktopItemStatus
2449mate_desktop_item_get_file_status (const MateDesktopItem *item)
2450{
2451 MateDesktopItemStatus retval;
2452 GFile *file;
2453 GFileInfo *info;
2454
2455 g_return_val_if_fail (item != NULL, MATE_DESKTOP_ITEM_DISAPPEARED)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (MATE_DESKTOP_ITEM_DISAPPEARED); } } while (0)
;
2456 g_return_val_if_fail (item->refcount > 0, MATE_DESKTOP_ITEM_DISAPPEARED)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (MATE_DESKTOP_ITEM_DISAPPEARED); } } while (0)
;
2457
2458 if (item->location == NULL((void*)0))
2459 return MATE_DESKTOP_ITEM_DISAPPEARED;
2460
2461 file = g_file_new_for_uri (item->location);
2462 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2463 G_FILE_QUERY_INFO_NONE, NULL((void*)0), NULL((void*)0));
2464
2465 retval = MATE_DESKTOP_ITEM_UNCHANGED;
2466
2467 if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2468 retval = MATE_DESKTOP_ITEM_DISAPPEARED;
2469 else if (((guint64) item->mtime) < g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2470 retval = MATE_DESKTOP_ITEM_CHANGED;
2471
2472 g_object_unref (info);
2473 g_object_unref (file);
2474
2475 return retval;
2476}
2477
2478/**
2479 * mate_desktop_item_find_icon:
2480 * @icon_theme: a #GtkIconTheme
2481 * @icon: icon name, something you'd get out of the Icon key
2482 * @desired_size: FIXME
2483 * @flags: FIXME
2484 *
2485 * Description: This function goes and looks for the icon file. If the icon
2486 * is not an absolute filename, this will look for it in the standard places.
2487 * If it can't find the icon, it will return %NULL
2488 *
2489 * Returns: A newly allocated string
2490 */
2491char *
2492mate_desktop_item_find_icon (GtkIconTheme *icon_theme,
2493 const char *icon,
2494 int desired_size,
2495 int flags)
2496{
2497 GtkIconInfo *info;
2498 char *full = NULL((void*)0);
2499
2500 g_return_val_if_fail (icon_theme == NULL ||do { if ((icon_theme == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((icon_theme)); GType __t = ((gtk_icon_theme_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "icon_theme == NULL || GTK_IS_ICON_THEME (icon_theme)"
); return (((void*)0)); } } while (0)
2501 GTK_IS_ICON_THEME (icon_theme), NULL)do { if ((icon_theme == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((icon_theme)); GType __t = ((gtk_icon_theme_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "icon_theme == NULL || GTK_IS_ICON_THEME (icon_theme)"
); return (((void*)0)); } } while (0)
;
2502
2503 if (icon == NULL((void*)0) || strcmp(icon,"") == 0) {
2504 return NULL((void*)0);
2505 } else if (g_path_is_absolute (icon)) {
2506 if (g_file_test (icon, G_FILE_TEST_EXISTS)) {
2507 return g_strdup (icon)g_strdup_inline (icon);
2508 } else {
2509 return NULL((void*)0);
2510 }
2511 } else {
2512 char *icon_no_extension;
2513 char *p;
2514
2515 if (icon_theme == NULL((void*)0))
2516 icon_theme = gtk_icon_theme_get_default ();
2517
2518 icon_no_extension = g_strdup (icon)g_strdup_inline (icon);
2519 p = strrchr (icon_no_extension, '.');
2520 if (p &&
2521 (strcmp (p, ".png") == 0 ||
2522 strcmp (p, ".xpm") == 0 ||
2523 strcmp (p, ".svg") == 0)) {
2524 *p = 0;
2525 }
2526
2527 info = gtk_icon_theme_lookup_icon (icon_theme,
2528 icon_no_extension,
2529 desired_size,
2530 0);
2531
2532 full = NULL((void*)0);
2533 if (info) {
2534 full = g_strdup (gtk_icon_info_get_filename (info))g_strdup_inline (gtk_icon_info_get_filename (info));
2535 g_object_unref (info);
2536 }
2537 g_free (icon_no_extension);
2538 }
2539
2540 return full;
2541
2542}
2543
2544/**
2545 * mate_desktop_item_get_icon:
2546 * @icon_theme: a #GtkIconTheme
2547 * @item: A desktop item
2548 *
2549 * Description: This function goes and looks for the icon file. If the icon
2550 * is not set as an absolute filename, this will look for it in the standard places.
2551 * If it can't find the icon, it will return %NULL
2552 *
2553 * Returns: A newly allocated string
2554 */
2555char *
2556mate_desktop_item_get_icon (const MateDesktopItem *item,
2557 GtkIconTheme *icon_theme)
2558{
2559 /* maybe this function should be deprecated in favour of find icon
2560 * -George */
2561 const char *icon;
2562
2563 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2564 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2565
2566 icon = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_ICON"Icon");
2567
2568 return mate_desktop_item_find_icon (icon_theme, icon,
2569 48 /* desired_size */,
2570 0 /* flags */);
2571}
2572
2573/**
2574 * mate_desktop_item_get_location:
2575 * @item: A desktop item
2576 *
2577 * Returns: The file location associated with 'item'.
2578 *
2579 */
2580const char *
2581mate_desktop_item_get_location (const MateDesktopItem *item)
2582{
2583 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2584 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2585
2586 return item->location;
2587}
2588
2589/**
2590 * mate_desktop_item_set_location:
2591 * @item: A desktop item
2592 * @location: A uri string specifying the file location of this particular item.
2593 *
2594 * Set's the 'location' uri of this item.
2595 */
2596void
2597mate_desktop_item_set_location (MateDesktopItem *item, const char *location)
2598{
2599 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2600 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2601
2602 if (item->location != NULL((void*)0) &&
2603 location != NULL((void*)0) &&
2604 strcmp (item->location, location) == 0)
2605 return;
2606
2607 g_free (item->location);
2608 item->location = g_strdup (location)g_strdup_inline (location);
2609
2610 /* This is ugly, but useful internally */
2611 if (item->mtime != DONT_UPDATE_MTIME((gint64)-2)) {
2612 item->mtime = 0;
2613
2614 if (item->location) {
2615 GFile *file;
2616 GFileInfo *info;
2617
2618 file = g_file_new_for_uri (item->location);
2619
2620 info = g_file_query_info (file,
2621 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2622 G_FILE_QUERY_INFO_NONE,
2623 NULL((void*)0), NULL((void*)0));
2624 if (info) {
2625 if (g_file_info_has_attribute (info,
2626 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2627 item->mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
2628 g_object_unref (info);
2629 }
2630
2631 g_object_unref (file);
2632 }
2633 }
2634
2635 /* Make sure that save actually saves */
2636 item->modified = TRUE(!(0));
2637}
2638
2639/**
2640 * mate_desktop_item_set_location_file:
2641 * @item: A desktop item
2642 * @file: A local filename specifying the file location of this particular item.
2643 *
2644 * Set's the 'location' uri of this item to the given @file.
2645 */
2646void
2647mate_desktop_item_set_location_file (MateDesktopItem *item, const char *file)
2648{
2649 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2650 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2651
2652 if (file != NULL((void*)0)) {
2653 GFile *gfile;
2654
2655 gfile = g_file_new_for_path (file);
2656 mate_desktop_item_set_location_gfile (item, gfile);
2657 g_object_unref (gfile);
2658 } else {
2659 mate_desktop_item_set_location (item, NULL((void*)0));
2660 }
2661}
2662
2663static void
2664mate_desktop_item_set_location_gfile (MateDesktopItem *item, GFile *file)
2665{
2666 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2667 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2668
2669 if (file != NULL((void*)0)) {
2670 char *uri;
2671
2672 uri = g_file_get_uri (file);
2673 mate_desktop_item_set_location (item, uri);
2674 g_free (uri);
2675 } else {
2676 mate_desktop_item_set_location (item, NULL((void*)0));
2677 }
2678}
2679
2680/*
2681 * Reading/Writing different sections, NULL is the standard section
2682 */
2683
2684gboolean
2685mate_desktop_item_attr_exists (const MateDesktopItem *item,
2686 const char *attr)
2687{
2688 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2689 g_return_val_if_fail (item->refcount > 0, FALSE)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return ((0)); } } while (0)
;
2690 g_return_val_if_fail (attr != NULL, FALSE)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return ((0)); } } while (0)
;
2691
2692 return lookup (item, attr) != NULL((void*)0);
2693}
2694
2695/*
2696 * String type
2697 */
2698const char *
2699mate_desktop_item_get_string (const MateDesktopItem *item,
2700 const char *attr)
2701{
2702 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2703 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2704 g_return_val_if_fail (attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2705
2706 return lookup (item, attr);
2707}
2708
2709void
2710mate_desktop_item_set_string (MateDesktopItem *item,
2711 const char *attr,
2712 const char *value)
2713{
2714 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2715 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2716 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2717
2718 set (item, attr, value);
2719
2720 if (strcmp (attr, MATE_DESKTOP_ITEM_TYPE"Type") == 0)
2721 item->type = type_from_string (value);
2722}
2723
2724/*
2725 * LocaleString type
2726 */
2727const char* mate_desktop_item_get_localestring(const MateDesktopItem* item, const char* attr)
2728{
2729 g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2730 g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2731 g_return_val_if_fail(attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2732
2733 return lookup_best_locale(item, attr);
2734}
2735
2736const char* mate_desktop_item_get_localestring_lang(const MateDesktopItem* item, const char* attr, const char* language)
2737{
2738 g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2739 g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2740 g_return_val_if_fail(attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2741
2742 return lookup_locale(item, attr, language);
2743}
2744
2745/**
2746 * mate_desktop_item_get_string_locale:
2747 * @item: A desktop item
2748 * @attr: An attribute name
2749 *
2750 * Returns the current locale that is used for the given attribute.
2751 * This might not be the same for all attributes. For example, if your
2752 * locale is "en_US.ISO8859-1" but attribute FOO only has "en_US" then
2753 * that would be returned for attr = "FOO". If attribute BAR has
2754 * "en_US.ISO8859-1" then that would be returned for "BAR".
2755 *
2756 * Returns: a string equal to the current locale or NULL
2757 * if the attribute is invalid or there is no matching locale.
2758 */
2759const char *
2760mate_desktop_item_get_attr_locale (const MateDesktopItem *item,
2761 const char *attr)
2762{
2763 const char * const *langs_pointer;
2764 int i;
2765
2766 langs_pointer = g_get_language_names ();
2767 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
2768 const char *value = NULL((void*)0);
2769
2770 value = lookup_locale (item, attr, langs_pointer[i]);
2771 if (value)
2772 return langs_pointer[i];
2773 }
2774
2775 return NULL((void*)0);
2776}
2777
2778GList *
2779mate_desktop_item_get_languages (const MateDesktopItem *item,
2780 const char *attr)
2781{
2782 GList *li;
2783 GList *list = NULL((void*)0);
2784
2785 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2786 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2787
2788 for (li = item->languages; li != NULL((void*)0); li = li->next) {
2789 char *language = li->data;
2790 if (attr == NULL((void*)0) ||
2791 lookup_locale (item, attr, language) != NULL((void*)0)) {
2792 list = g_list_prepend (list, language);
2793 }
2794 }
2795
2796 return g_list_reverse (list);
2797}
2798
2799static const char *
2800get_language (void)
2801{
2802 const char * const *langs_pointer;
2803 int i;
2804
2805 langs_pointer = g_get_language_names ();
2806 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
2807 /* find first without encoding */
2808 if (strchr (langs_pointer[i], '.') == NULL((void*)0)) {
2809 return langs_pointer[i];
2810 }
2811 }
2812 return NULL((void*)0);
2813}
2814
2815void
2816mate_desktop_item_set_localestring (MateDesktopItem *item,
2817 const char *attr,
2818 const char *value)
2819{
2820 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2821 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2822 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2823
2824 set_locale (item, attr, get_language (), value);
2825}
2826
2827void
2828mate_desktop_item_set_localestring_lang (MateDesktopItem *item,
2829 const char *attr,
2830 const char *language,
2831 const char *value)
2832{
2833 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2834 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2835 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2836
2837 set_locale (item, attr, language, value);
2838}
2839
2840void
2841mate_desktop_item_clear_localestring (MateDesktopItem *item,
2842 const char *attr)
2843{
2844 GList *l;
2845
2846 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2847 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2848 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2849
2850 for (l = item->languages; l != NULL((void*)0); l = l->next)
2851 set_locale (item, attr, l->data, NULL((void*)0));
2852
2853 set (item, attr, NULL((void*)0));
2854}
2855
2856/*
2857 * Strings, Regexps types
2858 */
2859
2860char **
2861mate_desktop_item_get_strings (const MateDesktopItem *item,
2862 const char *attr)
2863{
2864 const char *value;
2865
2866 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2867 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2868 g_return_val_if_fail (attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2869
2870 value = lookup (item, attr);
2871 if (value == NULL((void*)0))
2872 return NULL((void*)0);
2873
2874 /* FIXME: there's no way to escape semicolons apparently */
2875 return g_strsplit (value, ";", -1);
2876}
2877
2878void
2879mate_desktop_item_set_strings (MateDesktopItem *item,
2880 const char *attr,
2881 char **strings)
2882{
2883 char *str, *str2;
2884
2885 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2886 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2887 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2888
2889 str = g_strjoinv (";", strings);
2890 str2 = g_strconcat (str, ";", NULL((void*)0));
2891 /* FIXME: there's no way to escape semicolons apparently */
2892 set (item, attr, str2);
2893 g_free (str);
2894 g_free (str2);
2895}
2896
2897/*
2898 * Boolean type
2899 */
2900gboolean
2901mate_desktop_item_get_boolean (const MateDesktopItem *item,
2902 const char *attr)
2903{
2904 const char *value;
2905
2906 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2907 g_return_val_if_fail (item->refcount > 0, FALSE)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return ((0)); } } while (0)
;
2908 g_return_val_if_fail (attr != NULL, FALSE)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return ((0)); } } while (0)
;
2909
2910 value = lookup (item, attr);
2911 if (value == NULL((void*)0))
2912 return FALSE(0);
2913
2914 return (value[0] == 'T' ||
2915 value[0] == 't' ||
2916 value[0] == 'Y' ||
2917 value[0] == 'y' ||
2918 atoi (value) != 0);
2919}
2920
2921void
2922mate_desktop_item_set_boolean (MateDesktopItem *item,
2923 const char *attr,
2924 gboolean value)
2925{
2926 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2927 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2928 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2929
2930 set (item, attr, value ? "true" : "false");
2931}
2932
2933void
2934mate_desktop_item_set_launch_time (MateDesktopItem *item,
2935 guint32 timestamp)
2936{
2937 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2938
2939 item->launch_time = timestamp;
2940}
2941
2942/*
2943 * Clearing attributes
2944 */
2945void
2946mate_desktop_item_clear_section (MateDesktopItem *item,
2947 const char *section)
2948{
2949 Section *sec;
2950 GList *li;
2951
2952 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2953 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2954
2955 sec = find_section (item, section);
2956
2957 if (sec == NULL((void*)0)) {
2958 for (li = item->keys; li != NULL((void*)0); li = li->next) {
2959 g_hash_table_remove (item->main_hash, li->data);
2960 g_free (li->data);
2961 li->data = NULL((void*)0);
2962 }
2963 g_list_free (item->keys);
2964 item->keys = NULL((void*)0);
2965 } else {
2966 for (li = sec->keys; li != NULL((void*)0); li = li->next) {
2967 char *key = li->data;
2968 char *full = g_strdup_printf ("%s/%s",
2969 sec->name, key);
2970 g_hash_table_remove (item->main_hash, full);
2971 g_free (full);
2972 g_free (key);
2973 li->data = NULL((void*)0);
2974 }
2975 g_list_free (sec->keys);
2976 sec->keys = NULL((void*)0);
2977 }
2978 item->modified = TRUE(!(0));
2979}
2980
2981/************************************************************
2982 * Parser: *
2983 ************************************************************/
2984
2985static gboolean G_GNUC_CONST__attribute__ ((__const__))
2986standard_is_boolean (const char * key)
2987{
2988 static GHashTable *bools = NULL((void*)0);
2989
2990 if (bools == NULL((void*)0)) {
2991 bools = g_hash_table_new (g_str_hash, g_str_equal);
2992 g_hash_table_insert (bools,
2993 MATE_DESKTOP_ITEM_NO_DISPLAY"NoDisplay",
2994 MATE_DESKTOP_ITEM_NO_DISPLAY"NoDisplay");
2995 g_hash_table_insert (bools,
2996 MATE_DESKTOP_ITEM_HIDDEN"Hidden",
2997 MATE_DESKTOP_ITEM_HIDDEN"Hidden");
2998 g_hash_table_insert (bools,
2999 MATE_DESKTOP_ITEM_TERMINAL"Terminal",
3000 MATE_DESKTOP_ITEM_TERMINAL"Terminal");
3001 g_hash_table_insert (bools,
3002 MATE_DESKTOP_ITEM_READ_ONLY"ReadOnly",
3003 MATE_DESKTOP_ITEM_READ_ONLY"ReadOnly");
3004 }
3005
3006 return g_hash_table_lookup (bools, key) != NULL((void*)0);
3007}
3008
3009static gboolean G_GNUC_CONST__attribute__ ((__const__))
3010standard_is_strings (const char *key)
3011{
3012 static GHashTable *strings = NULL((void*)0);
3013
3014 if (strings == NULL((void*)0)) {
3015 strings = g_hash_table_new (g_str_hash, g_str_equal);
3016 g_hash_table_insert (strings,
3017 MATE_DESKTOP_ITEM_FILE_PATTERN"FilePattern",
3018 MATE_DESKTOP_ITEM_FILE_PATTERN"FilePattern");
3019 g_hash_table_insert (strings,
3020 MATE_DESKTOP_ITEM_ACTIONS"Actions",
3021 MATE_DESKTOP_ITEM_ACTIONS"Actions");
3022 g_hash_table_insert (strings,
3023 MATE_DESKTOP_ITEM_MIME_TYPE"MimeType",
3024 MATE_DESKTOP_ITEM_MIME_TYPE"MimeType");
3025 g_hash_table_insert (strings,
3026 MATE_DESKTOP_ITEM_PATTERNS"Patterns",
3027 MATE_DESKTOP_ITEM_PATTERNS"Patterns");
3028 g_hash_table_insert (strings,
3029 MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder",
3030 MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder");
3031 }
3032
3033 return g_hash_table_lookup (strings, key) != NULL((void*)0);
3034}
3035
3036/* If no need to cannonize, returns NULL */
3037static char *
3038cannonize (const char *key, const char *value)
3039{
3040 if (standard_is_boolean (key)) {
3041 if (value[0] == 'T' ||
3042 value[0] == 't' ||
3043 value[0] == 'Y' ||
3044 value[0] == 'y' ||
3045 atoi (value) != 0) {
3046 return g_strdup ("true")g_strdup_inline ("true");
3047 } else {
3048 return g_strdup ("false")g_strdup_inline ("false");
3049 }
3050 } else if (standard_is_strings (key)) {
3051 int len = strlen (value);
3052 if (len == 0 || value[len-1] != ';') {
3053 return g_strconcat (value, ";", NULL((void*)0));
3054 }
3055 }
3056 /* XXX: Perhaps we should canonize numeric values as well, but this
3057 * has caused some subtle problems before so it needs to be done
3058 * carefully if at all */
3059 return NULL((void*)0);
3060}
3061
3062static char *
3063decode_string_and_dup (const char *s)
3064{
3065 char *p = g_malloc (strlen (s) + 1);
3066 char *q = p;
3067
3068 do {
3069 if (*s == '\\'){
3070 switch (*(++s)){
3071 case 's':
3072 *p++ = ' ';
3073 break;
3074 case 't':
3075 *p++ = '\t';
3076 break;
3077 case 'n':
3078 *p++ = '\n';
3079 break;
3080 case '\\':
3081 *p++ = '\\';
3082 break;
3083 case 'r':
3084 *p++ = '\r';
3085 break;
3086 default:
3087 *p++ = '\\';
3088 *p++ = *s;
3089 break;
3090 }
3091 } else {
3092 *p++ = *s;
3093 }
3094 } while (*s++);
3095
3096 return q;
3097}
3098
3099static char *
3100escape_string_and_dup (const char *s)
3101{
3102 char *return_value, *p;
3103 const char *q;
3104 int len = 0;
3105
3106 if (s
11.1
's' is not equal to NULL
== NULL((void*)0))
12
Taking false branch
3107 return g_strdup("")g_strdup_inline ("");
3108
3109 q = s;
3110 while (*q){
13
Loop condition is true. Entering loop body
16
Loop condition is true. Entering loop body
19
Loop condition is false. Execution continues on line 3116
3111 len++;
3112 if (strchr ("\n\r\t\\", *q) != NULL((void*)0))
14
Assuming the condition is false
15
Taking false branch
17
Assuming the condition is false
18
Taking false branch
3113 len++;
3114 q++;
3115 }
3116 return_value = p = (char *) g_malloc (len + 1);
3117 do {
22
Loop condition is true. Execution continues on line 3118
3118 switch (*s){
20
Control jumps to 'case 92:' at line 3131
23
Control jumps to 'case 10:' at line 3123
3119 case '\t':
3120 *p++ = '\\';
3121 *p++ = 't';
3122 break;
3123 case '\n':
3124 *p++ = '\\';
3125 *p++ = 'n';
24
Out of bound memory access (access exceeds upper limit of memory block)
3126 break;
3127 case '\r':
3128 *p++ = '\\';
3129 *p++ = 'r';
3130 break;
3131 case '\\':
3132 *p++ = '\\';
3133 *p++ = '\\';
3134 break;
21
Execution continues on line 3138
3135 default:
3136 *p++ = *s;
3137 }
3138 } while (*s++);
3139 return return_value;
3140}
3141
3142static gboolean
3143check_locale (const char *locale)
3144{
3145 GIConv cd = g_iconv_open ("UTF-8", locale);
3146 if ((GIConv)-1 == cd)
3147 return FALSE(0);
3148 g_iconv_close (cd);
3149 return TRUE(!(0));
3150}
3151
3152static void
3153insert_locales (GHashTable *encodings, char *enc, ...)
3154{
3155 va_list args;
3156 char *s;
3157
3158 va_start (args, enc)__builtin_va_start(args, enc);
3159 for (;;) {
3160 s = va_arg (args, char *)__builtin_va_arg(args, char *);
3161 if (s == NULL((void*)0))
3162 break;
3163 g_hash_table_insert (encodings, s, enc);
3164 }
3165 va_end (args)__builtin_va_end(args);
3166}
3167
3168/* make a standard conversion table from the desktop standard spec */
3169static GHashTable *
3170init_encodings (void)
3171{
3172 GHashTable *encodings = g_hash_table_new (g_str_hash, g_str_equal);
3173
3174 /* "C" is plain ascii */
3175 insert_locales (encodings, "ASCII", "C", NULL((void*)0));
3176
3177 insert_locales (encodings, "ARMSCII-8", "by", NULL((void*)0));
3178 insert_locales (encodings, "BIG5", "zh_TW", NULL((void*)0));
3179 insert_locales (encodings, "CP1251", "be", "bg", NULL((void*)0));
3180 if (check_locale ("EUC-CN")) {
3181 insert_locales (encodings, "EUC-CN", "zh_CN", NULL((void*)0));
3182 } else {
3183 insert_locales (encodings, "GB2312", "zh_CN", NULL((void*)0));
3184 }
3185 insert_locales (encodings, "EUC-JP", "ja", NULL((void*)0));
3186 insert_locales (encodings, "EUC-KR", "ko", NULL((void*)0));
3187 /*insert_locales (encodings, "GEORGIAN-ACADEMY", NULL);*/
3188 insert_locales (encodings, "GEORGIAN-PS", "ka", NULL((void*)0));
3189 insert_locales (encodings, "ISO-8859-1", "br", "ca", "da", "de", "en", "es", "eu", "fi", "fr", "gl", "it", "nl", "wa", "no", "pt", "pt", "sv", NULL((void*)0));
3190 insert_locales (encodings, "ISO-8859-2", "cs", "hr", "hu", "pl", "ro", "sk", "sl", "sq", "sr", NULL((void*)0));
3191 insert_locales (encodings, "ISO-8859-3", "eo", NULL((void*)0));
3192 insert_locales (encodings, "ISO-8859-5", "mk", "sp", NULL((void*)0));
3193 insert_locales (encodings, "ISO-8859-7", "el", NULL((void*)0));
3194 insert_locales (encodings, "ISO-8859-9", "tr", NULL((void*)0));
3195 insert_locales (encodings, "ISO-8859-13", "lt", "lv", "mi", NULL((void*)0));
3196 insert_locales (encodings, "ISO-8859-14", "ga", "cy", NULL((void*)0));
3197 insert_locales (encodings, "ISO-8859-15", "et", NULL((void*)0));
3198 insert_locales (encodings, "KOI8-R", "ru", NULL((void*)0));
3199 insert_locales (encodings, "KOI8-U", "uk", NULL((void*)0));
3200 if (check_locale ("TCVN-5712")) {
3201 insert_locales (encodings, "TCVN-5712", "vi", NULL((void*)0));
3202 } else {
3203 insert_locales (encodings, "TCVN", "vi", NULL((void*)0));
3204 }
3205 insert_locales (encodings, "TIS-620", "th", NULL((void*)0));
3206 /*insert_locales (encodings, "VISCII", NULL);*/
3207
3208 return encodings;
3209}
3210
3211static const char *
3212get_encoding_from_locale (const char *locale)
3213{
3214 char lang[3];
3215 const char *encoding;
3216 static GHashTable *encodings = NULL((void*)0);
3217
3218 if (locale == NULL((void*)0))
3219 return NULL((void*)0);
3220
3221 /* if locale includes encoding, use it */
3222 encoding = strchr (locale, '.');
3223 if (encoding != NULL((void*)0)) {
3224 return encoding+1;
3225 }
3226
3227 if (encodings == NULL((void*)0))
3228 encodings = init_encodings ();
3229
3230 /* first try the entire locale (at this point ll_CC) */
3231 encoding = g_hash_table_lookup (encodings, locale);
3232 if (encoding != NULL((void*)0))
3233 return encoding;
3234
3235 /* Try just the language */
3236 strncpy (lang, locale, 2);
3237 lang[2] = '\0';
3238 return g_hash_table_lookup (encodings, lang);
3239}
3240
3241static Encoding
3242get_encoding (ReadBuf *rb)
3243{
3244 gboolean old_kde = FALSE(0);
3245 char buf [BUFSIZ8192];
3246 gboolean all_valid_utf8 = TRUE(!(0));
3247
3248 while (readbuf_gets (buf, sizeof (buf), rb) != NULL((void*)0)) {
3249 if (strncmp (MATE_DESKTOP_ITEM_ENCODING"Encoding",
3250 buf,
3251 strlen (MATE_DESKTOP_ITEM_ENCODING"Encoding")) == 0) {
3252 char *p = &buf[strlen (MATE_DESKTOP_ITEM_ENCODING"Encoding")];
3253 if (*p == ' ')
3254 p++;
3255 if (*p != '=')
3256 continue;
3257 p++;
3258 if (*p == ' ')
3259 p++;
3260 if (strcmp (p, "UTF-8") == 0) {
3261 return ENCODING_UTF8;
3262 } else if (strcmp (p, "Legacy-Mixed") == 0) {
3263 return ENCODING_LEGACY_MIXED;
3264 } else {
3265 /* According to the spec we're not supposed
3266 * to read a file like this */
3267 return ENCODING_UNKNOWN;
3268 }
3269 } else if (strcmp ("[KDE Desktop Entry]", buf) == 0) {
3270 old_kde = TRUE(!(0));
3271 /* don't break yet, we still want to support
3272 * Encoding even here */
3273 }
3274 if (all_valid_utf8 && ! g_utf8_validate (buf, -1, NULL((void*)0)))
3275 all_valid_utf8 = FALSE(0);
3276 }
3277
3278 if (old_kde)
3279 return ENCODING_LEGACY_MIXED;
3280
3281 /* try to guess by location */
3282 if (rb->uri != NULL((void*)0) && strstr (rb->uri, "mate/apps/") != NULL((void*)0)) {
3283 /* old mate */
3284 return ENCODING_LEGACY_MIXED;
3285 }
3286
3287 /* A dilemma, new KDE files are in UTF-8 but have no Encoding
3288 * info, at this time we really can't tell. The best thing to
3289 * do right now is to just assume UTF-8 if the whole file
3290 * validates as utf8 I suppose */
3291
3292 if (all_valid_utf8)
3293 return ENCODING_UTF8;
3294 else
3295 return ENCODING_LEGACY_MIXED;
3296}
3297
3298static char *
3299decode_string (const char *value, Encoding encoding, const char *locale)
3300{
3301 char *retval = NULL((void*)0);
3302
3303 /* if legacy mixed, then convert */
3304 if (locale != NULL((void*)0) && encoding == ENCODING_LEGACY_MIXED) {
3305 const char *char_encoding = get_encoding_from_locale (locale);
3306 char *utf8_string;
3307 if (char_encoding == NULL((void*)0))
3308 return NULL((void*)0);
3309 if (strcmp (char_encoding, "ASCII") == 0) {
3310 return decode_string_and_dup (value);
3311 }
3312 utf8_string = g_convert (value, -1, "UTF-8", char_encoding,
3313 NULL((void*)0), NULL((void*)0), NULL((void*)0));
3314 if (utf8_string == NULL((void*)0))
3315 return NULL((void*)0);
3316 retval = decode_string_and_dup (utf8_string);
3317 g_free (utf8_string);
3318 return retval;
3319 /* if utf8, then validate */
3320 } else if (locale != NULL((void*)0) && encoding == ENCODING_UTF8) {
3321 if ( ! g_utf8_validate (value, -1, NULL((void*)0)))
3322 /* invalid utf8, ignore this key */
3323 return NULL((void*)0);
3324 return decode_string_and_dup (value);
3325 } else {
3326 /* Meaning this is not a localized string */
3327 return decode_string_and_dup (value);
3328 }
3329}
3330
3331static char *
3332snarf_locale_from_key (const char *key)
3333{
3334 const char *brace;
3335 char *locale, *p;
3336
3337 brace = strchr (key, '[');
3338 if (brace == NULL((void*)0))
3339 return NULL((void*)0);
3340
3341 locale = g_strdup (brace + 1)g_strdup_inline (brace + 1);
3342 if (*locale == '\0') {
3343 g_free (locale);
3344 return NULL((void*)0);
3345 }
3346 p = strchr (locale, ']');
3347 if (p == NULL((void*)0)) {
3348 g_free (locale);
3349 return NULL((void*)0);
3350 }
3351 *p = '\0';
3352 return locale;
3353}
3354
3355static void
3356insert_key (MateDesktopItem *item,
3357 Section *cur_section,
3358 Encoding encoding,
3359 const char *key,
3360 const char *value,
3361 gboolean old_kde,
3362 gboolean no_translations)
3363{
3364 char *k;
3365 char *val;
3366 /* we always store everything in UTF-8 */
3367 if (cur_section == NULL((void*)0) &&
3368 strcmp (key, MATE_DESKTOP_ITEM_ENCODING"Encoding") == 0) {
3369 k = g_strdup (key)g_strdup_inline (key);
3370 val = g_strdup ("UTF-8")g_strdup_inline ("UTF-8");
3371 } else {
3372 char *locale = snarf_locale_from_key (key);
3373 /* If we're ignoring translations */
3374 if (no_translations && locale != NULL((void*)0)) {
3375 g_free (locale);
3376 return;
3377 }
3378 val = decode_string (value, encoding, locale);
3379
3380 /* Ignore this key, it's whacked */
3381 if (val == NULL((void*)0)) {
3382 g_free (locale);
3383 return;
3384 }
3385
3386 g_strchomp (val);
3387
3388 /* For old KDE entries, we can also split by a comma
3389 * on sort order, so convert to semicolons */
3390 if (old_kde &&
3391 cur_section == NULL((void*)0) &&
3392 strcmp (key, MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder") == 0 &&
3393 strchr (val, ';') == NULL((void*)0)) {
3394 int i;
3395 for (i = 0; val[i] != '\0'; i++) {
3396 if (val[i] == ',')
3397 val[i] = ';';
3398 }
3399 }
3400
3401 /* Check some types, not perfect, but catches a lot
3402 * of things */
3403 if (cur_section == NULL((void*)0)) {
3404 char *cannon = cannonize (key, val);
3405 if (cannon != NULL((void*)0)) {
3406 g_free (val);
3407 val = cannon;
3408 }
3409 }
3410
3411 k = g_strdup (key)g_strdup_inline (key);
3412
3413 /* Take care of the language part */
3414 if (locale != NULL((void*)0) &&
3415 strcmp (locale, "C") == 0) {
3416 char *p;
3417 /* Whack C locale */
3418 p = strchr (k, '[');
3419 *p = '\0';
3420 g_free (locale);
3421 } else if (locale != NULL((void*)0)) {
3422 char *p, *brace;
3423
3424 /* Whack the encoding part */
3425 p = strchr (locale, '.');
3426 if (p != NULL((void*)0))
3427 *p = '\0';
3428
3429 if (g_list_find_custom (item->languages, locale,
3430 (GCompareFunc)strcmp) == NULL((void*)0)) {
3431 item->languages = g_list_prepend
3432 (item->languages, locale);
3433 } else {
3434 g_free (locale);
3435 }
3436
3437 /* Whack encoding from encoding in the key */
3438 brace = strchr (k, '[');
3439 p = strchr (brace, '.');
3440 if (p != NULL((void*)0)) {
3441 *p = ']';
3442 *(p+1) = '\0';
3443 }
3444 }
3445 }
3446
3447 if (cur_section == NULL((void*)0)) {
3448 /* only add to list if we haven't seen it before */
3449 if (g_hash_table_lookup (item->main_hash, k) == NULL((void*)0)) {
3450 item->keys = g_list_prepend (item->keys,
3451 g_strdup (k)g_strdup_inline (k));
3452 }
3453 /* later duplicates override earlier ones */
3454 g_hash_table_replace (item->main_hash, k, val);
3455 } else {
3456 char *full = g_strdup_printf
3457 ("%s/%s",
3458 cur_section->name, k);
3459 /* only add to list if we haven't seen it before */
3460 if (g_hash_table_lookup (item->main_hash, full) == NULL((void*)0)) {
3461 cur_section->keys =
3462 g_list_prepend (cur_section->keys, k);
3463 }
3464 /* later duplicates override earlier ones */
3465 g_hash_table_replace (item->main_hash,
3466 full, val);
3467 }
3468}
3469
3470static void
3471setup_type (MateDesktopItem *item, const char *uri)
3472{
3473 const char *type = g_hash_table_lookup (item->main_hash,
3474 MATE_DESKTOP_ITEM_TYPE"Type");
3475 if (type == NULL((void*)0) && uri != NULL((void*)0)) {
3476 char *base = g_path_get_basename (uri);
3477 if (base != NULL((void*)0) &&
3478 strcmp (base, ".directory") == 0) {
3479 /* This gotta be a directory */
3480 g_hash_table_replace (item->main_hash,
3481 g_strdup (MATE_DESKTOP_ITEM_TYPE)g_strdup_inline ("Type"),
3482 g_strdup ("Directory")g_strdup_inline ("Directory"));
3483 item->keys = g_list_prepend
3484 (item->keys, g_strdup (MATE_DESKTOP_ITEM_TYPE)g_strdup_inline ("Type"));
3485 item->type = MATE_DESKTOP_ITEM_TYPE_DIRECTORY;
3486 } else {
3487 item->type = MATE_DESKTOP_ITEM_TYPE_NULL;
3488 }
3489 g_free (base);
3490 } else {
3491 item->type = type_from_string (type);
3492 }
3493}
3494
3495/* fallback to find something suitable for C locale */
3496static char *
3497try_english_key (MateDesktopItem *item, const char *key)
3498{
3499 char *str;
3500 char *locales[] = { "en_US", "en_GB", "en_AU", "en", NULL((void*)0) };
3501 int i;
3502
3503 str = NULL((void*)0);
3504 for (i = 0; locales[i] != NULL((void*)0) && str == NULL((void*)0); i++) {
3505 str = g_strdup (lookup_locale (item, key, locales[i]))g_strdup_inline (lookup_locale (item, key, locales[i]));
3506 }
3507 if (str != NULL((void*)0)) {
3508 /* We need a 7-bit ascii string, so whack all
3509 * above 127 chars */
3510 guchar *p;
3511 for (p = (guchar *)str; *p != '\0'; p++) {
3512 if (*p > 127)
3513 *p = '?';
3514 }
3515 }
3516 return str;
3517}
3518
3519static void
3520sanitize (MateDesktopItem *item, const char *uri)
3521{
3522 const char *type;
3523
3524 type = lookup (item, MATE_DESKTOP_ITEM_TYPE"Type");
3525
3526 /* understand old mate style url exec thingies */
3527 if (type != NULL((void*)0) && strcmp (type, "URL") == 0) {
3528 const char *exec = lookup (item, MATE_DESKTOP_ITEM_EXEC"Exec");
3529 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Link");
3530 if (exec != NULL((void*)0)) {
3531 /* Note, this must be in this order */
3532 set (item, MATE_DESKTOP_ITEM_URL"URL", exec);
3533 set (item, MATE_DESKTOP_ITEM_EXEC"Exec", NULL((void*)0));
3534 }
3535 }
3536
3537 /* we make sure we have Name, Encoding and Version */
3538 if (lookup (item, MATE_DESKTOP_ITEM_NAME"Name") == NULL((void*)0)) {
3539 char *name = try_english_key (item, MATE_DESKTOP_ITEM_NAME"Name");
3540 /* If no name, use the basename */
3541 if (name == NULL((void*)0) && uri != NULL((void*)0))
3542 name = g_path_get_basename (uri);
3543 /* If no uri either, use same default as mate_desktop_item_new */
3544 if (name == NULL((void*)0)) {
3545 /* Translators: the "name" mentioned here is the name of
3546 * an application or a document */
3547 name = g_strdup (_("No name"))g_strdup_inline (((char *) g_dgettext ("mate-desktop", "No name"
)))
;
3548 }
3549 g_hash_table_replace (item->main_hash,
3550 g_strdup (MATE_DESKTOP_ITEM_NAME)g_strdup_inline ("Name"),
3551 name);
3552 item->keys = g_list_prepend
3553 (item->keys, g_strdup (MATE_DESKTOP_ITEM_NAME)g_strdup_inline ("Name"));
3554 }
3555 if (lookup (item, MATE_DESKTOP_ITEM_ENCODING"Encoding") == NULL((void*)0)) {
3556 /* We store everything in UTF-8 so write that down */
3557 g_hash_table_replace (item->main_hash,
3558 g_strdup (MATE_DESKTOP_ITEM_ENCODING)g_strdup_inline ("Encoding"),
3559 g_strdup ("UTF-8")g_strdup_inline ("UTF-8"));
3560 item->keys = g_list_prepend
3561 (item->keys, g_strdup (MATE_DESKTOP_ITEM_ENCODING)g_strdup_inline ("Encoding"));
3562 }
3563 if (lookup (item, MATE_DESKTOP_ITEM_VERSION"Version") == NULL((void*)0)) {
3564 /* this is the version that we follow, so write it down */
3565 g_hash_table_replace (item->main_hash,
3566 g_strdup (MATE_DESKTOP_ITEM_VERSION)g_strdup_inline ("Version"),
3567 g_strdup ("1.0")g_strdup_inline ("1.0"));
3568 item->keys = g_list_prepend
3569 (item->keys, g_strdup (MATE_DESKTOP_ITEM_VERSION)g_strdup_inline ("Version"));
3570 }
3571}
3572
3573enum {
3574 FirstBrace,
3575 OnSecHeader,
3576 IgnoreToEOL,
3577 IgnoreToEOLFirst,
3578 KeyDef,
3579 KeyDefOnKey,
3580 KeyValue
3581};
3582
3583static MateDesktopItem *
3584ditem_load (ReadBuf *rb,
3585 gboolean no_translations,
3586 GError **error)
3587{
3588 int state;
3589 char CharBuffer [1024];
3590 char *next = CharBuffer;
3591 int c;
3592 Encoding encoding;
3593 MateDesktopItem *item;
3594 Section *cur_section = NULL((void*)0);
3595 char *key = NULL((void*)0);
3596 gboolean old_kde = FALSE(0);
3597
3598 encoding = get_encoding (rb);
3599 if (encoding == ENCODING_UNKNOWN) {
3600 /* spec says, don't read this file */
3601 g_set_error (error,
3602 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
3603 MATE_DESKTOP_ITEM_ERROR_UNKNOWN_ENCODING,
3604 _("Unknown encoding of: %s")((char *) g_dgettext ("mate-desktop", "Unknown encoding of: %s"
))
,
3605 rb->uri);
3606 readbuf_close (rb);
3607 return NULL((void*)0);
3608 }
3609
3610 /* Rewind since get_encoding goes through the file */
3611 if (! readbuf_rewind (rb, error)) {
3612 readbuf_close (rb);
3613 /* spec says, don't read this file */
3614 return NULL((void*)0);
3615 }
3616
3617 item = mate_desktop_item_new ();
3618 item->modified = FALSE(0);
3619
3620 /* Note: location and mtime are filled in by the new_from_file
3621 * function since it has those values */
3622
3623#define OVERFLOW (next == &CharBuffer [sizeof(CharBuffer)-1])
3624
3625 state = FirstBrace;
3626 while ((c = readbuf_getc (rb)) != EOF(-1)) {
3627 if (c == '\r') /* Ignore Carriage Return */
3628 continue;
3629
3630 switch (state) {
3631
3632 case OnSecHeader:
3633 if (c == ']' || OVERFLOW) {
3634 *next = '\0';
3635 next = CharBuffer;
3636
3637 /* keys were inserted in reverse */
3638 if (cur_section != NULL((void*)0) &&
3639 cur_section->keys != NULL((void*)0)) {
3640 cur_section->keys = g_list_reverse
3641 (cur_section->keys);
3642 }
3643 if (strcmp (CharBuffer,
3644 "KDE Desktop Entry") == 0) {
3645 /* Main section */
3646 cur_section = NULL((void*)0);
3647 old_kde = TRUE(!(0));
3648 } else if (strcmp (CharBuffer,
3649 "Desktop Entry") == 0) {
3650 /* Main section */
3651 cur_section = NULL((void*)0);
3652 } else {
3653 cur_section = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
3654 cur_section->name =
3655 g_strdup (CharBuffer)g_strdup_inline (CharBuffer);
3656 cur_section->keys = NULL((void*)0);
3657 item->sections = g_list_prepend
3658 (item->sections, cur_section);
3659 }
3660 state = IgnoreToEOL;
3661 } else if (c == '[') {
3662 /* FIXME: probably error out instead of ignoring this */
3663 } else {
3664 *next++ = c;
3665 }
3666 break;
3667
3668 case IgnoreToEOL:
3669 case IgnoreToEOLFirst:
3670 if (c == '\n'){
3671 if (state == IgnoreToEOLFirst)
3672 state = FirstBrace;
3673 else
3674 state = KeyDef;
3675 next = CharBuffer;
3676 }
3677 break;
3678
3679 case FirstBrace:
3680 case KeyDef:
3681 case KeyDefOnKey:
3682 if (c == '#') {
3683 if (state == FirstBrace)
3684 state = IgnoreToEOLFirst;
3685 else
3686 state = IgnoreToEOL;
3687 break;
3688 }
3689
3690 if (c == '[' && state != KeyDefOnKey){
3691 state = OnSecHeader;
3692 next = CharBuffer;
3693 g_free (key);
3694 key = NULL((void*)0);
3695 break;
3696 }
3697 /* On first pass, don't allow dangling keys */
3698 if (state == FirstBrace)
3699 break;
3700
3701 if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
3702 break;
3703
3704 if (c == '\n' || OVERFLOW) { /* Abort Definition */
3705 next = CharBuffer;
3706 state = KeyDef;
3707 break;
3708 }
3709
3710 if (c == '=' || OVERFLOW){
3711 *next = '\0';
3712
3713 g_free (key);
3714 key = g_strdup (CharBuffer)g_strdup_inline (CharBuffer);
3715 state = KeyValue;
3716 next = CharBuffer;
3717 } else {
3718 *next++ = c;
3719 state = KeyDefOnKey;
3720 }
3721 break;
3722
3723 case KeyValue:
3724 if (OVERFLOW || c == '\n'){
3725 *next = '\0';
3726
3727 insert_key (item, cur_section, encoding,
3728 key, CharBuffer, old_kde,
3729 no_translations);
3730
3731 g_free (key);
3732 key = NULL((void*)0);
3733
3734 state = (c == '\n') ? KeyDef : IgnoreToEOL;
3735 next = CharBuffer;
3736 } else {
3737 *next++ = c;
3738 }
3739 break;
3740
3741 } /* switch */
3742
3743 } /* while ((c = getc_unlocked (f)) != EOF) */
3744 if (c == EOF(-1) && state == KeyValue) {
3745 *next = '\0';
3746
3747 insert_key (item, cur_section, encoding,
3748 key, CharBuffer, old_kde,
3749 no_translations);
3750
3751 g_free (key);
3752 key = NULL((void*)0);
3753 }
3754
3755#undef OVERFLOW
3756
3757 /* keys were inserted in reverse */
3758 if (cur_section != NULL((void*)0) &&
3759 cur_section->keys != NULL((void*)0)) {
3760 cur_section->keys = g_list_reverse (cur_section->keys);
3761 }
3762 /* keys were inserted in reverse */
3763 item->keys = g_list_reverse (item->keys);
3764 /* sections were inserted in reverse */
3765 item->sections = g_list_reverse (item->sections);
3766
3767 /* sanitize some things */
3768 sanitize (item, rb->uri);
3769
3770 /* make sure that we set up the type */
3771 setup_type (item, rb->uri);
3772
3773 readbuf_close (rb);
3774
3775 return item;
3776}
3777
3778static void stream_printf (GFileOutputStream *stream,
3779 const char *format, ...) G_GNUC_PRINTF (2, 3)__attribute__((__format__ (__printf__, 2, 3)));
3780
3781static void
3782stream_printf (GFileOutputStream *stream, const char *format, ...)
3783{
3784 va_list args;
3785 gchar *s;
3786
3787 va_start (args, format)__builtin_va_start(args, format);
3788 s = g_strdup_vprintf (format, args);
3789 va_end (args)__builtin_va_end(args);
3790
3791 /* FIXME: what about errors */
3792 g_output_stream_write (G_OUTPUT_STREAM (stream)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((stream)), ((g_output_stream_get_type ()))))))
, s, strlen (s),
3793 NULL((void*)0), NULL((void*)0));
3794 g_free (s);
3795}
3796
3797static void
3798dump_section (MateDesktopItem *item, GFileOutputStream *stream, Section *section)
3799{
3800 GList *li;
3801
3802 stream_printf (stream, "[%s]\n", section->name);
3803 for (li = section->keys; li != NULL((void*)0); li = li->next) {
3804 const char *key = li->data;
3805 char *full = g_strdup_printf ("%s/%s", section->name, key);
3806 const char *value = g_hash_table_lookup (item->main_hash, full);
3807 if (value != NULL((void*)0)) {
3808 char *val = escape_string_and_dup (value);
3809 stream_printf (stream, "%s=%s\n", key, val);
3810 g_free (val);
3811 }
3812 g_free (full);
3813 }
3814}
3815
3816static gboolean
3817ditem_save (MateDesktopItem *item, const char *uri, GError **error)
3818{
3819 GList *li;
3820 GFile *file;
3821 GFileOutputStream *stream;
3822
3823 file = g_file_new_for_uri (uri);
3824 stream = g_file_replace (file, NULL((void*)0), FALSE(0), G_FILE_CREATE_NONE,
3825 NULL((void*)0), error);
3826 if (stream == NULL((void*)0))
5
Assuming 'stream' is not equal to NULL
6
Taking false branch
3827 return FALSE(0);
3828
3829 stream_printf (stream, "[Desktop Entry]\n");
3830 for (li = item->keys; li != NULL((void*)0); li = li->next) {
7
Assuming 'li' is not equal to NULL
8
Loop condition is true. Entering loop body
3831 const char *key = li->data;
3832 const char *value = g_hash_table_lookup (item->main_hash, key);
3833 if (value != NULL((void*)0)) {
9
Assuming 'value' is not equal to NULL
10
Taking true branch
3834 char *val = escape_string_and_dup (value);
11
Calling 'escape_string_and_dup'
3835 stream_printf (stream, "%s=%s\n", key, val);
3836 g_free (val);
3837 }
3838 }
3839
3840 if (item->sections != NULL((void*)0))
3841 stream_printf (stream, "\n");
3842
3843 for (li = item->sections; li != NULL((void*)0); li = li->next) {
3844 Section *section = li->data;
3845
3846 /* Don't write empty sections */
3847 if (section->keys == NULL((void*)0))
3848 continue;
3849
3850 dump_section (item, stream, section);
3851
3852 if (li->next != NULL((void*)0))
3853 stream_printf (stream, "\n");
3854 }
3855
3856 g_object_unref (stream);
3857 g_object_unref (file);
3858
3859 return TRUE(!(0));
3860}
3861
3862static gpointer
3863_mate_desktop_item_copy (gpointer boxed)
3864{
3865 return mate_desktop_item_copy (boxed);
3866}
3867
3868static void
3869_mate_desktop_item_free (gpointer boxed)
3870{
3871 mate_desktop_item_unref (boxed);
3872}
3873
3874GType
3875mate_desktop_item_get_type (void)
3876{
3877 static GType type = 0;
3878
3879 if (type == 0) {
3880 type = g_boxed_type_register_static ("MateDesktopItem",
3881 _mate_desktop_item_copy,
3882 _mate_desktop_item_free);
3883 }
3884
3885 return type;
3886}
3887
3888GQuark
3889mate_desktop_item_error_quark (void)
3890{
3891 static GQuark q = 0;
3892 if (q == 0)
3893 q = g_quark_from_static_string ("mate-desktop-item-error-quark");
3894
3895 return q;
3896}
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-6a2986.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-6a2986.html new file mode 100644 index 0000000..0336e9c --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-6a2986.html @@ -0,0 +1,4711 @@ + + + +mate-desktop-item.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-desktop-item.c
Warning:line 2037, column 2
Undefined or garbage value returned to caller
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-desktop-item.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-desktop-item.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* mate-desktop-item.c - MATE Desktop File Representation
3
4 Copyright (C) 1999, 2000 Red Hat Inc.
5 Copyright (C) 2001 Sid Vicious
6 All rights reserved.
7
8 This file is part of the Mate Library.
9
10 Developed by Elliot Lee <sopwith@redhat.com> and Sid Vicious
11
12 The Mate Library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Library General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
16
17 The Mate Library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Library General Public License for more details.
21
22 You should have received a copy of the GNU Library General Public
23 License along with the Mate Library; see the file COPYING.LIB. If not,
24 write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 Boston, MA 02110-1301, USA. */
26/*
27 @NOTATION@
28 */
29
30#include "config.h"
31
32#include <limits.h>
33#include <ctype.h>
34#include <stdio.h>
35#include <glib.h>
36#include <sys/types.h>
37#include <dirent.h>
38#include <unistd.h>
39#include <time.h>
40#include <string.h>
41#include <glib/gi18n-lib.h>
42#include <locale.h>
43#include <stdlib.h>
44
45#include <gio/gio.h>
46
47#ifdef HAVE_STARTUP_NOTIFICATION
48#define SN_API_NOT_YET_FROZEN
49#include <libsn/sn.h>
50#include <gdk/gdk.h>
51#include <gdk/gdkx.h>
52#include <gtk/gtk.h>
53#endif
54
55#define MATE_DESKTOP_USE_UNSTABLE_API
56#undef MATE_DISABLE_DEPRECATED
57#include <mate-desktop-item.h>
58#include <mate-desktop-utils.h>
59
60#include "private.h"
61
62struct _MateDesktopItem {
63 int refcount;
64
65 /* all languages used */
66 GList *languages;
67
68 MateDesktopItemType type;
69
70 /* `modified' means that the ditem has been
71 * modified since the last save. */
72 gboolean modified;
73
74 /* Keys of the main section only */
75 GList *keys;
76
77 GList *sections;
78
79 /* This includes ALL keys, including
80 * other sections, separated by '/' */
81 GHashTable *main_hash;
82
83 char *location;
84
85 gint64 mtime;
86
87 guint32 launch_time;
88};
89
90/* If mtime is set to this, set_location won't update mtime,
91 * this is to be used internally only. */
92#define DONT_UPDATE_MTIME((gint64)-2) ((gint64)-2)
93
94typedef struct {
95 char *name;
96 GList *keys;
97} Section;
98
99typedef enum {
100 ENCODING_UNKNOWN,
101 ENCODING_UTF8,
102 ENCODING_LEGACY_MIXED
103} Encoding;
104
105/*
106 * IO reading utils, that look like the libc buffered io stuff
107 */
108
109#define READ_BUF_SIZE(32 * 1024) (32 * 1024)
110
111typedef struct {
112 GFile *file;
113 GFileInputStream *stream;
114 char *uri;
115 char *buf;
116 gboolean buf_needs_free;
117 gboolean past_first_read;
118 gboolean eof;
119 guint64 size;
120 gsize pos;
121} ReadBuf;
122
123static MateDesktopItem *ditem_load (ReadBuf *rb,
124 gboolean no_translations,
125 GError **error);
126static gboolean ditem_save (MateDesktopItem *item,
127 const char *uri,
128 GError **error);
129
130static void mate_desktop_item_set_location_gfile (MateDesktopItem *item,
131 GFile *file);
132
133static MateDesktopItem *mate_desktop_item_new_from_gfile (GFile *file,
134 MateDesktopItemLoadFlags flags,
135 GError **error);
136
137static int
138readbuf_getc (ReadBuf *rb)
139{
140 if (rb->eof)
141 return EOF(-1);
142
143 if (rb->size == 0 ||
144 rb->pos == rb->size) {
145 gssize bytes_read;
146
147 if (rb->stream == NULL((void*)0))
148 bytes_read = 0;
149 else
150 bytes_read = g_input_stream_read (G_INPUT_STREAM (rb->stream)((((GInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((rb->stream)), ((g_input_stream_get_type ()))))))
,
151 rb->buf,
152 READ_BUF_SIZE(32 * 1024),
153 NULL((void*)0), NULL((void*)0));
154
155 /* FIXME: handle errors other than EOF */
156 if (bytes_read <= 0) {
157 rb->eof = TRUE(!(0));
158 return EOF(-1);
159 }
160
161 if (rb->size != 0)
162 rb->past_first_read = TRUE(!(0));
163 rb->size = bytes_read;
164 rb->pos = 0;
165
166 }
167
168 return (guchar) rb->buf[rb->pos++];
169}
170
171/* Note, does not include the trailing \n */
172static char *
173readbuf_gets (char *buf, gsize bufsize, ReadBuf *rb)
174{
175 int c;
176 gsize pos;
177
178 g_return_val_if_fail (buf != NULL, NULL)do { if ((buf != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "buf != NULL"); return
(((void*)0)); } } while (0)
;
179 g_return_val_if_fail (rb != NULL, NULL)do { if ((rb != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "rb != NULL"); return
(((void*)0)); } } while (0)
;
180
181 pos = 0;
182 buf[0] = '\0';
183
184 do {
185 c = readbuf_getc (rb);
186 if (c == EOF(-1) || c == '\n')
187 break;
188 buf[pos++] = c;
189 } while (pos < bufsize-1);
190
191 if (c == EOF(-1) && pos == 0)
192 return NULL((void*)0);
193
194 buf[pos++] = '\0';
195
196 return buf;
197}
198
199static ReadBuf *
200readbuf_open (GFile *file, GError **error)
201{
202 GError *local_error;
203 GFileInputStream *stream;
204 char *uri;
205 ReadBuf *rb;
206
207 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
208
209 uri = g_file_get_uri (file);
210 local_error = NULL((void*)0);
211 stream = g_file_read (file, NULL((void*)0), &local_error);
212
213 if (stream == NULL((void*)0)) {
214 g_set_error (error,
215 /* FIXME: better errors */
216 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
217 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
218 _("Error reading file '%s': %s")((char *) g_dgettext ("mate-desktop", "Error reading file '%s': %s"
))
,
219 uri, local_error->message);
220 g_error_free (local_error);
221 g_free (uri);
222 return NULL((void*)0);
223 }
224
225 rb = g_new0 (ReadBuf, 1)((ReadBuf *) g_malloc0_n ((1), sizeof (ReadBuf)));
226 rb->stream = stream;
227 rb->file = g_file_dup (file);
228 rb->uri = uri;
229 rb->buf = g_malloc (READ_BUF_SIZE(32 * 1024));
230 rb->buf_needs_free = TRUE(!(0));
231 /* rb->past_first_read = FALSE; */
232 /* rb->eof = FALSE; */
233 /* rb->size = 0; */
234 /* rb->pos = 0; */
235
236 return rb;
237}
238
239static ReadBuf *
240readbuf_new_from_string (const char *uri, const char *string, gssize length)
241{
242 ReadBuf *rb;
243
244 g_return_val_if_fail (string != NULL, NULL)do { if ((string != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "string != NULL"
); return (((void*)0)); } } while (0)
;
245 g_return_val_if_fail (length >= 0, NULL)do { if ((length >= 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "length >= 0"
); return (((void*)0)); } } while (0)
;
246
247 rb = g_new0 (ReadBuf, 1)((ReadBuf *) g_malloc0_n ((1), sizeof (ReadBuf)));
248 /* rb->file = NULL; */
249 /* rb->stream = NULL; */
250 rb->uri = g_strdup (uri)g_strdup_inline (uri);
251 rb->buf = (char *) string;
252 /* rb->buf_needs_free = FALSE; */
253 /* rb->past_first_read = FALSE; */
254 /* rb->eof = FALSE; */
255 rb->size = length;
256 /* rb->pos = 0; */
257
258 return rb;
259}
260
261static gboolean
262readbuf_rewind (ReadBuf *rb, GError **error)
263{
264 GError *local_error;
265
266 rb->eof = FALSE(0);
267 rb->pos = 0;
268
269 if (!rb->past_first_read)
270 return TRUE(!(0));
271
272 rb->size = 0;
273
274 if (g_seekable_seek (G_SEEKABLE (rb->stream)((((GSeekable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((rb->stream)), ((g_seekable_get_type ()))))))
,
275 0, G_SEEK_SET, NULL((void*)0), NULL((void*)0)))
276 return TRUE(!(0));
277
278 g_object_unref (rb->stream);
279 local_error = NULL((void*)0);
280 rb->stream = g_file_read (rb->file, NULL((void*)0), &local_error);
281
282 if (rb->stream == NULL((void*)0)) {
283 g_set_error (
284 error, MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
285 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
286 _("Error rewinding file '%s': %s")((char *) g_dgettext ("mate-desktop", "Error rewinding file '%s': %s"
))
,
287 rb->uri, local_error->message);
288 g_error_free (local_error);
289
290 return FALSE(0);
291 }
292
293 return TRUE(!(0));
294}
295
296static void
297readbuf_close (ReadBuf *rb)
298{
299 if (rb->stream != NULL((void*)0))
300 g_object_unref (rb->stream);
301 if (rb->file != NULL((void*)0))
302 g_object_unref (rb->file);
303 g_free (rb->uri);
304 if (rb->buf_needs_free)
305 g_free (rb->buf);
306 g_free (rb);
307}
308
309static MateDesktopItemType
310type_from_string (const char *type)
311{
312 if (!type)
313 return MATE_DESKTOP_ITEM_TYPE_NULL;
314
315 switch (type [0]) {
316 case 'A':
317 if (!strcmp (type, "Application"))
318 return MATE_DESKTOP_ITEM_TYPE_APPLICATION;
319 break;
320 case 'L':
321 if (!strcmp (type, "Link"))
322 return MATE_DESKTOP_ITEM_TYPE_LINK;
323 break;
324 case 'F':
325 if (!strcmp (type, "FSDevice"))
326 return MATE_DESKTOP_ITEM_TYPE_FSDEVICE;
327 break;
328 case 'M':
329 if (!strcmp (type, "MimeType"))
330 return MATE_DESKTOP_ITEM_TYPE_MIME_TYPE;
331 break;
332 case 'D':
333 if (!strcmp (type, "Directory"))
334 return MATE_DESKTOP_ITEM_TYPE_DIRECTORY;
335 break;
336 case 'S':
337 if (!strcmp (type, "Service"))
338 return MATE_DESKTOP_ITEM_TYPE_SERVICE;
339
340 else if (!strcmp (type, "ServiceType"))
341 return MATE_DESKTOP_ITEM_TYPE_SERVICE_TYPE;
342 break;
343 default:
344 break;
345 }
346
347 return MATE_DESKTOP_ITEM_TYPE_OTHER;
348}
349
350/**
351 * mate_desktop_item_new:
352 *
353 * Creates a MateDesktopItem object. The reference count on the returned value is set to '1'.
354 *
355 * Returns: The new MateDesktopItem
356 */
357MateDesktopItem *
358mate_desktop_item_new (void)
359{
360 MateDesktopItem *retval;
361
362 _mate_desktop_init_i18n ();
363
364 retval = g_new0 (MateDesktopItem, 1)((MateDesktopItem *) g_malloc0_n ((1), sizeof (MateDesktopItem
)))
;
365
366 retval->refcount++;
367
368 retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
369 (GDestroyNotify) g_free,
370 (GDestroyNotify) g_free);
371
372 /* These are guaranteed to be set */
373 mate_desktop_item_set_string (retval,
374 MATE_DESKTOP_ITEM_NAME"Name",
375 /* Translators: the "name" mentioned
376 * here is the name of an application or
377 * a document */
378 _("No name")((char *) g_dgettext ("mate-desktop", "No name")));
379 mate_desktop_item_set_string (retval,
380 MATE_DESKTOP_ITEM_ENCODING"Encoding",
381 "UTF-8");
382 mate_desktop_item_set_string (retval,
383 MATE_DESKTOP_ITEM_VERSION"Version",
384 "1.0");
385
386 retval->launch_time = 0;
387
388 return retval;
389}
390
391static Section *
392dup_section (Section *sec)
393{
394 GList *li;
395 Section *retval = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
396
397 retval->name = g_strdup (sec->name)g_strdup_inline (sec->name);
398
399 retval->keys = g_list_copy (sec->keys);
400 for (li = retval->keys; li != NULL((void*)0); li = li->next)
401 li->data = g_strdup (li->data)g_strdup_inline (li->data);
402
403 return retval;
404}
405
406static void
407copy_string_hash (gpointer key, gpointer value, gpointer user_data)
408{
409 GHashTable *copy = user_data;
410 g_hash_table_replace (copy,
411 g_strdup (key)g_strdup_inline (key),
412 g_strdup (value)g_strdup_inline (value));
413}
414
415/**
416 * mate_desktop_item_copy:
417 * @item: The item to be copied
418 *
419 * Creates a copy of a MateDesktopItem. The new copy has a refcount of 1.
420 * Note: Section stack is NOT copied.
421 *
422 * Returns: The new copy
423 */
424MateDesktopItem *
425mate_desktop_item_copy (const MateDesktopItem *item)
426{
427 GList *li;
428 MateDesktopItem *retval;
429
430 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
431 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
432
433 retval = mate_desktop_item_new ();
434
435 retval->type = item->type;
436 retval->modified = item->modified;
437 retval->location = g_strdup (item->location)g_strdup_inline (item->location);
438 retval->mtime = item->mtime;
439 retval->launch_time = item->launch_time;
440
441 /* Languages */
442 retval->languages = g_list_copy (item->languages);
443 for (li = retval->languages; li != NULL((void*)0); li = li->next)
444 li->data = g_strdup (li->data)g_strdup_inline (li->data);
445
446 /* Keys */
447 retval->keys = g_list_copy (item->keys);
448 for (li = retval->keys; li != NULL((void*)0); li = li->next)
449 li->data = g_strdup (li->data)g_strdup_inline (li->data);
450
451 /* Sections */
452 retval->sections = g_list_copy (item->sections);
453 for (li = retval->sections; li != NULL((void*)0); li = li->next)
454 li->data = dup_section (li->data);
455
456 retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
457 (GDestroyNotify) g_free,
458 (GDestroyNotify) g_free);
459
460 g_hash_table_foreach (item->main_hash,
461 copy_string_hash,
462 retval->main_hash);
463
464 return retval;
465}
466
467static void
468read_sort_order (MateDesktopItem *item, GFile *dir)
469{
470 GFile *child;
471 char buf[BUFSIZ8192];
472 GString *str;
473 ReadBuf *rb;
474
475 child = g_file_get_child (dir, ".order");
476
477 rb = readbuf_open (child, NULL((void*)0));
478 g_object_unref (child);
479
480 if (rb == NULL((void*)0))
481 return;
482
483 str = NULL((void*)0);
484 while (readbuf_gets (buf, sizeof (buf), rb) != NULL((void*)0)) {
485 if (str == NULL((void*)0))
486 str = g_string_new (buf);
487 else
488 g_string_append (str, buf)(__builtin_constant_p (buf) ? __extension__ ({ const char * const
__val = (buf); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, buf, (gssize) -1
))
;
489 g_string_append_c (str, ';')g_string_append_c_inline (str, ';');
490 }
491 readbuf_close (rb);
492 if (str != NULL((void*)0)) {
493 mate_desktop_item_set_string (item, MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder",
494 str->str);
495 g_string_free (str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(str), ((!(0)))) : g_string_free_and_steal (str)) : (g_string_free
) ((str), ((!(0)))))
;
496 }
497}
498
499static MateDesktopItem *
500make_fake_directory (GFile *dir)
501{
502 MateDesktopItem *item;
503 GFile *child;
504
505 item = mate_desktop_item_new ();
506 mate_desktop_item_set_entry_type (item,
507 MATE_DESKTOP_ITEM_TYPE_DIRECTORY);
508
509 item->mtime = DONT_UPDATE_MTIME((gint64)-2); /* it doesn't exist, we know that */
510 child = g_file_get_child (dir, ".directory");
511 mate_desktop_item_set_location_gfile (item, child);
512 item->mtime = 0;
513 g_object_unref (child);
514
515 read_sort_order (item, dir);
516
517 return item;
518}
519
520/**
521 * mate_desktop_item_new_from_file:
522 * @file: The filename or directory path to load the MateDesktopItem from
523 * @flags: Flags to influence the loading process
524 *
525 * This function loads 'file' and turns it into a MateDesktopItem.
526 *
527 * Returns: The newly loaded item.
528 */
529MateDesktopItem *
530mate_desktop_item_new_from_file (const char *file,
531 MateDesktopItemLoadFlags flags,
532 GError **error)
533{
534 MateDesktopItem *retval;
535 GFile *gfile;
536
537 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
538
539 gfile = g_file_new_for_path (file);
540 retval = mate_desktop_item_new_from_gfile (gfile, flags, error);
541 g_object_unref (gfile);
542
543 return retval;
544}
545
546/**
547 * mate_desktop_item_new_from_uri:
548 * @uri: URI to load the MateDesktopItem from
549 * @flags: Flags to influence the loading process
550 *
551 * This function loads 'uri' and turns it into a MateDesktopItem.
552 *
553 * Returns: The newly loaded item.
554 */
555MateDesktopItem *
556mate_desktop_item_new_from_uri (const char *uri,
557 MateDesktopItemLoadFlags flags,
558 GError **error)
559{
560 MateDesktopItem *retval;
561 GFile *file;
562
563 g_return_val_if_fail (uri != NULL, NULL)do { if ((uri != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "uri != NULL"); return
(((void*)0)); } } while (0)
;
564
565 file = g_file_new_for_uri (uri);
566 retval = mate_desktop_item_new_from_gfile (file, flags, error);
567 g_object_unref (file);
568
569 return retval;
570}
571
572static MateDesktopItem *
573mate_desktop_item_new_from_gfile (GFile *file,
574 MateDesktopItemLoadFlags flags,
575 GError **error)
576{
577 MateDesktopItem *retval;
578 GFile *subfn;
579 GFileInfo *info;
580 GFileType type;
581 GFile *parent;
582 gint64 mtime = 0;
583 ReadBuf *rb;
584
585 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
586
587 info = g_file_query_info (file,
588 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type"","G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
589 G_FILE_QUERY_INFO_NONE, NULL((void*)0), error);
590 if (info == NULL((void*)0))
591 return NULL((void*)0);
592
593 type = g_file_info_get_file_type (info);
594
595 if (type != G_FILE_TYPE_REGULAR && type != G_FILE_TYPE_DIRECTORY) {
596 char *uri;
597
598 uri = g_file_get_uri (file);
599 g_set_error (error,
600 /* FIXME: better errors */
601 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
602 MATE_DESKTOP_ITEM_ERROR_INVALID_TYPE,
603 _("File '%s' is not a regular file or directory.")((char *) g_dgettext ("mate-desktop", "File '%s' is not a regular file or directory."
))
,
604 uri);
605
606 g_free (uri);
607 g_object_unref (info);
608
609 return NULL((void*)0);
610 }
611
612 mtime = g_file_info_get_attribute_uint64 (info,
613 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
614
615 g_object_unref (info);
616
617 if (type == G_FILE_TYPE_DIRECTORY) {
618 GFile *child;
619 GFileInfo *child_info;
620
621 child = g_file_get_child (file, ".directory");
622 child_info = g_file_query_info (child,
623 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
624 G_FILE_QUERY_INFO_NONE,
625 NULL((void*)0), NULL((void*)0));
626
627 if (child_info == NULL((void*)0)) {
628 g_object_unref (child);
629
630 if (flags & MATE_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS) {
631 return NULL((void*)0);
632 } else {
633 return make_fake_directory (file);
634 }
635 }
636
637 mtime = g_file_info_get_attribute_uint64 (child_info,
638 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
639 g_object_unref (child_info);
640
641 subfn = child;
642 } else {
643 subfn = g_file_dup (file);
644 }
645
646 rb = readbuf_open (subfn, error);
647
648 if (rb == NULL((void*)0)) {
649 g_object_unref (subfn);
650 return NULL((void*)0);
651 }
652
653 retval = ditem_load (rb,
654 (flags & MATE_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS) != 0,
655 error);
656
657 if (retval == NULL((void*)0)) {
658 g_object_unref (subfn);
659 return NULL((void*)0);
660 }
661
662 if (flags & MATE_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS &&
663 ! mate_desktop_item_exists (retval)) {
664 mate_desktop_item_unref (retval);
665 g_object_unref (subfn);
666 return NULL((void*)0);
667 }
668
669 retval->mtime = DONT_UPDATE_MTIME((gint64)-2);
670 mate_desktop_item_set_location_gfile (retval, subfn);
671 retval->mtime = mtime;
672
673 parent = g_file_get_parent (file);
674 if (parent != NULL((void*)0)) {
675 read_sort_order (retval, parent);
676 g_object_unref (parent);
677 }
678
679 g_object_unref (subfn);
680
681 return retval;
682}
683
684/**
685 * mate_desktop_item_new_from_string:
686 * @string: string to load the MateDesktopItem from
687 * @length: length of string, or -1 to use strlen
688 * @flags: Flags to influence the loading process
689 * @error: place to put errors
690 *
691 * This function turns the contents of the string into a MateDesktopItem.
692 *
693 * Returns: The newly loaded item.
694 */
695MateDesktopItem *
696mate_desktop_item_new_from_string (const char *uri,
697 const char *string,
698 gssize length,
699 MateDesktopItemLoadFlags flags,
700 GError **error)
701{
702 MateDesktopItem *retval;
703 ReadBuf *rb;
704
705 g_return_val_if_fail (string != NULL, NULL)do { if ((string != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "string != NULL"
); return (((void*)0)); } } while (0)
;
706 g_return_val_if_fail (length >= -1, NULL)do { if ((length >= -1)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "length >= -1"
); return (((void*)0)); } } while (0)
;
707
708 if (length == -1) {
709 length = strlen (string);
710 }
711
712 rb = readbuf_new_from_string (uri, string, length);
713
714 retval = ditem_load (rb,
715 (flags & MATE_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS) != 0,
716 error);
717
718 if (retval == NULL((void*)0)) {
719 return NULL((void*)0);
720 }
721
722 /* FIXME: Sort order? */
723
724 return retval;
725}
726
727static char *
728lookup_desktop_file_in_data_dir (const char *desktop_file,
729 const char *data_dir)
730{
731 char *path;
732
733 path = g_build_filename (data_dir, "applications", desktop_file, NULL((void*)0));
734 if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
735 g_free (path);
736 return NULL((void*)0);
737 }
738 return path;
739}
740
741static char *
742file_from_basename (const char *basename)
743{
744 const char * const *system_data_dirs;
745 const char *user_data_dir;
746 char *retval;
747 int i;
748
749 user_data_dir = g_get_user_data_dir ();
750 system_data_dirs = g_get_system_data_dirs ();
751
752 if ((retval = lookup_desktop_file_in_data_dir (basename, user_data_dir))) {
753 return retval;
754 }
755 for (i = 0; system_data_dirs[i]; i++) {
756 if ((retval = lookup_desktop_file_in_data_dir (basename, system_data_dirs[i]))) {
757 return retval;
758 }
759 }
760 return NULL((void*)0);
761}
762
763/**
764 * mate_desktop_item_new_from_basename:
765 * @basename: The basename of the MateDesktopItem to load.
766 * @flags: Flags to influence the loading process
767 *
768 * This function loads 'basename' from a system data directory and
769 * returns its MateDesktopItem.
770 *
771 * Returns: The newly loaded item.
772 */
773MateDesktopItem *
774mate_desktop_item_new_from_basename (const char *basename,
775 MateDesktopItemLoadFlags flags,
776 GError **error)
777{
778 MateDesktopItem *retval;
779 char *file;
780
781 g_return_val_if_fail (basename != NULL, NULL)do { if ((basename != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "basename != NULL"
); return (((void*)0)); } } while (0)
;
782
783 if (!(file = file_from_basename (basename))) {
784 g_set_error (error,
785 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
786 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
787 _("Cannot find file '%s'")((char *) g_dgettext ("mate-desktop", "Cannot find file '%s'"
))
,
788 basename);
789 return NULL((void*)0);
790 }
791
792 retval = mate_desktop_item_new_from_file (file, flags, error);
793 g_free (file);
794
795 return retval;
796}
797
798/**
799 * mate_desktop_item_save:
800 * @item: A desktop item
801 * @under: A new uri (location) for this #MateDesktopItem
802 * @force: Save even if it wasn't modified
803 * @error: #GError return
804 *
805 * Writes the specified item to disk. If the 'under' is NULL, the original
806 * location is used. It sets the location of this entry to point to the
807 * new location.
808 *
809 * Returns: boolean. %TRUE if the file was saved, %FALSE otherwise
810 */
811gboolean
812mate_desktop_item_save (MateDesktopItem *item,
813 const char *under,
814 gboolean force,
815 GError **error)
816{
817 const char *uri;
818
819 if (under == NULL((void*)0) &&
820 ! force &&
821 ! item->modified)
822 return TRUE(!(0));
823
824 if (under == NULL((void*)0))
825 uri = item->location;
826 else
827 uri = under;
828
829 if (uri == NULL((void*)0)) {
830 g_set_error (error,
831 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
832 MATE_DESKTOP_ITEM_ERROR_NO_FILENAME,
833 _("No filename to save to")((char *) g_dgettext ("mate-desktop", "No filename to save to"
))
);
834 return FALSE(0);
835 }
836
837 if ( ! ditem_save (item, uri, error))
838 return FALSE(0);
839
840 item->modified = FALSE(0);
841 item->mtime = g_get_real_time () / G_USEC_PER_SEC1000000;
842
843 return TRUE(!(0));
844}
845
846/**
847 * mate_desktop_item_ref:
848 * @item: A desktop item
849 *
850 * Description: Increases the reference count of the specified item.
851 *
852 * Returns: the newly referenced @item
853 */
854MateDesktopItem *
855mate_desktop_item_ref (MateDesktopItem *item)
856{
857 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
858
859 item->refcount++;
860
861 return item;
862}
863
864static void
865free_section (gpointer data)
866{
867 Section *section = data;
868
869 g_free (section->name);
870 section->name = NULL((void*)0);
871
872 g_list_free_full (section->keys, g_free);
873 section->keys = NULL((void*)0);
874
875 g_free (section);
876}
877
878/**
879 * mate_desktop_item_unref:
880 * @item: A desktop item
881 *
882 * Decreases the reference count of the specified item, and destroys the item if there are no more references left.
883 */
884void
885mate_desktop_item_unref (MateDesktopItem *item)
886{
887 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
888 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
889
890 item->refcount--;
891
892 if(item->refcount != 0)
893 return;
894
895 g_list_free_full (item->languages, g_free);
896 item->languages = NULL((void*)0);
897
898 g_list_free_full (item->keys, g_free);
899 item->keys = NULL((void*)0);
900
901 g_list_free_full (item->sections, (GDestroyNotify) free_section);
902 item->sections = NULL((void*)0);
903
904 g_hash_table_destroy (item->main_hash);
905 item->main_hash = NULL((void*)0);
906
907 g_free (item->location);
908 item->location = NULL((void*)0);
909
910 g_free (item);
911}
912
913static Section *
914find_section (MateDesktopItem *item, const char *section)
915{
916 GList *li;
917 Section *sec;
918
919 if (section == NULL((void*)0))
920 return NULL((void*)0);
921 if (strcmp (section, "Desktop Entry") == 0)
922 return NULL((void*)0);
923
924 for (li = item->sections; li != NULL((void*)0); li = li->next) {
925 sec = li->data;
926 if (strcmp (sec->name, section) == 0)
927 return sec;
928 }
929
930 sec = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
931 sec->name = g_strdup (section)g_strdup_inline (section);
932 sec->keys = NULL((void*)0);
933
934 item->sections = g_list_append (item->sections, sec);
935
936 /* Don't mark the item modified, this is just an empty section,
937 * it won't be saved even */
938
939 return sec;
940}
941
942static Section *
943section_from_key (MateDesktopItem *item, const char *key)
944{
945 char *p;
946 char *name;
947 Section *sec;
948
949 if (key == NULL((void*)0))
950 return NULL((void*)0);
951
952 p = strchr (key, '/');
953 if (p == NULL((void*)0))
954 return NULL((void*)0);
955
956 name = g_strndup (key, p - key);
957
958 sec = find_section (item, name);
959
960 g_free (name);
961
962 return sec;
963}
964
965static const char *
966key_basename (const char *key)
967{
968 char *p = strrchr (key, '/');
969 if (p != NULL((void*)0))
970 return p+1;
971 else
972 return key;
973}
974
975static const char *
976lookup (const MateDesktopItem *item, const char *key)
977{
978 return g_hash_table_lookup (item->main_hash, key);
979}
980
981static const char *
982lookup_locale (const MateDesktopItem *item, const char *key, const char *locale)
983{
984 if (locale == NULL((void*)0) ||
985 strcmp (locale, "C") == 0) {
986 return lookup (item, key);
987 } else {
988 const char *ret;
989 char *full = g_strdup_printf ("%s[%s]", key, locale);
990 ret = lookup (item, full);
991 g_free (full);
992 return ret;
993 }
994}
995
996static const char *
997lookup_best_locale (const MateDesktopItem *item, const char *key)
998{
999 const char * const *langs_pointer;
1000 int i;
1001
1002 langs_pointer = g_get_language_names ();
1003 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
1004 const char *ret = NULL((void*)0);
1005
1006 ret = lookup_locale (item, key, langs_pointer[i]);
1007 if (ret != NULL((void*)0))
1008 return ret;
1009 }
1010
1011 return NULL((void*)0);
1012}
1013
1014static void
1015set (MateDesktopItem *item, const char *key, const char *value)
1016{
1017 Section *sec = section_from_key (item, key);
1018
1019 if (sec != NULL((void*)0)) {
1020 if (value != NULL((void*)0)) {
1021 if (g_hash_table_lookup (item->main_hash, key) == NULL((void*)0))
1022 sec->keys = g_list_append
1023 (sec->keys,
1024 g_strdup (key_basename (key))g_strdup_inline (key_basename (key)));
1025
1026 g_hash_table_replace (item->main_hash,
1027 g_strdup (key)g_strdup_inline (key),
1028 g_strdup (value)g_strdup_inline (value));
1029 } else {
1030 GList *list = g_list_find_custom
1031 (sec->keys, key_basename (key),
1032 (GCompareFunc)strcmp);
1033 if (list != NULL((void*)0)) {
1034 g_free (list->data);
1035 sec->keys =
1036 g_list_delete_link (sec->keys, list);
1037 }
1038 g_hash_table_remove (item->main_hash, key);
1039 }
1040 } else {
1041 if (value != NULL((void*)0)) {
1042 if (g_hash_table_lookup (item->main_hash, key) == NULL((void*)0))
1043 item->keys = g_list_append (item->keys,
1044 g_strdup (key)g_strdup_inline (key));
1045
1046 g_hash_table_replace (item->main_hash,
1047 g_strdup (key)g_strdup_inline (key),
1048 g_strdup (value)g_strdup_inline (value));
1049 } else {
1050 GList *list = g_list_find_custom
1051 (item->keys, key, (GCompareFunc)strcmp);
1052 if (list != NULL((void*)0)) {
1053 g_free (list->data);
1054 item->keys =
1055 g_list_delete_link (item->keys, list);
1056 }
1057 g_hash_table_remove (item->main_hash, key);
1058 }
1059 }
1060 item->modified = TRUE(!(0));
1061}
1062
1063static void
1064set_locale (MateDesktopItem *item, const char *key,
1065 const char *locale, const char *value)
1066{
1067 if (locale == NULL((void*)0) ||
1068 strcmp (locale, "C") == 0) {
1069 set (item, key, value);
1070 } else {
1071 char *full = g_strdup_printf ("%s[%s]", key, locale);
1072 set (item, full, value);
1073 g_free (full);
1074
1075 /* add the locale to the list of languages if it wasn't there
1076 * before */
1077 if (g_list_find_custom (item->languages, locale,
1078 (GCompareFunc)strcmp) == NULL((void*)0))
1079 item->languages = g_list_prepend (item->languages,
1080 g_strdup (locale)g_strdup_inline (locale));
1081 }
1082}
1083
1084static char **
1085list_to_vector (GSList *list)
1086{
1087 int len = g_slist_length (list);
1088 char **argv;
1089 int i;
1090 GSList *li;
1091
1092 argv = g_new0 (char *, len+1)((char * *) g_malloc0_n ((len+1), sizeof (char *)));
1093
1094 for (i = 0, li = list;
1095 li != NULL((void*)0);
1096 li = li->next, i++) {
1097 argv[i] = g_strdup (li->data)g_strdup_inline (li->data);
1098 }
1099 argv[i] = NULL((void*)0);
1100
1101 return argv;
1102}
1103
1104static GSList *
1105make_args (GList *files)
1106{
1107 GSList *list = NULL((void*)0);
1108 GList *li;
1109
1110 for (li = files; li != NULL((void*)0); li = li->next) {
1111 GFile *gfile;
1112 const char *file = li->data;
1113 if (file == NULL((void*)0))
1114 continue;
1115 gfile = g_file_new_for_uri (file);
1116 list = g_slist_prepend (list, gfile);
1117 }
1118
1119 return g_slist_reverse (list);
1120}
1121
1122static void
1123free_args (GSList *list)
1124{
1125 GSList *li;
1126
1127 for (li = list; li != NULL((void*)0); li = li->next) {
1128 g_object_unref (G_FILE (li->data)((((GFile*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((li->data)), ((g_file_get_type ()))))))
);
1129 li->data = NULL((void*)0);
1130 }
1131 g_slist_free (list);
1132}
1133
1134static char *
1135escape_single_quotes (const char *s,
1136 gboolean in_single_quotes,
1137 gboolean in_double_quotes)
1138{
1139 const char *p;
1140 GString *gs;
1141 const char *pre = "";
1142 const char *post = "";
1143
1144 if ( ! in_single_quotes && ! in_double_quotes) {
1145 pre = "'";
1146 post = "'";
1147 } else if ( ! in_single_quotes && in_double_quotes) {
1148 pre = "\"'";
1149 post = "'\"";
1150 }
1151
1152 if (strchr (s, '\'') == NULL((void*)0)) {
1153 return g_strconcat (pre, s, post, NULL((void*)0));
1154 }
1155
1156 gs = g_string_new (pre);
1157
1158 for (p = s; *p != '\0'; p++) {
1159 if (*p == '\'')
1160 g_string_append (gs, "'\\''")(__builtin_constant_p ("'\\''") ? __extension__ ({ const char
* const __val = ("'\\''"); g_string_append_len_inline (gs, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (gs, "'\\''"
, (gssize) -1))
;
1161 else
1162 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1163 }
1164
1165 g_string_append (gs, post)(__builtin_constant_p (post) ? __extension__ ({ const char * const
__val = (post); g_string_append_len_inline (gs, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (gs, post, (gssize) -1
))
;
1166
1167 return g_string_free (gs, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((gs),
((0))) : g_string_free_and_steal (gs)) : (g_string_free) ((gs
), ((0))))
;
1168}
1169
1170typedef enum {
1171 URI_TO_STRING,
1172 URI_TO_LOCAL_PATH,
1173 URI_TO_LOCAL_DIRNAME,
1174 URI_TO_LOCAL_BASENAME
1175} ConversionType;
1176
1177static char *
1178convert_uri (GFile *file,
1179 ConversionType conversion)
1180{
1181 char *retval = NULL((void*)0);
1182
1183 switch (conversion) {
1184 case URI_TO_STRING:
1185 retval = g_file_get_uri (file);
1186 break;
1187 case URI_TO_LOCAL_PATH:
1188 retval = g_file_get_path (file);
1189 break;
1190 case URI_TO_LOCAL_DIRNAME:
1191 {
1192 char *local_path;
1193
1194 local_path = g_file_get_path (file);
1195 retval = g_path_get_dirname (local_path);
1196 g_free (local_path);
1197 }
1198 break;
1199 case URI_TO_LOCAL_BASENAME:
1200 retval = g_file_get_basename (file);
1201 break;
1202 default:
1203 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-desktop-item.c"
, 1203, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1204 }
1205
1206 return retval;
1207}
1208
1209typedef enum {
1210 ADDED_NONE = 0,
1211 ADDED_SINGLE,
1212 ADDED_ALL
1213} AddedStatus;
1214
1215static AddedStatus
1216append_all_converted (GString *str,
1217 ConversionType conversion,
1218 GSList *args,
1219 gboolean in_single_quotes,
1220 gboolean in_double_quotes,
1221 AddedStatus added_status)
1222{
1223 GSList *l;
1224
1225 for (l = args; l; l = l->next) {
1226 char *converted;
1227 char *escaped;
1228
1229 if (!(converted = convert_uri (l->data, conversion)))
1230 continue;
1231
1232 g_string_append (str, " ")(__builtin_constant_p (" ") ? __extension__ ({ const char * const
__val = (" "); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, " ", (gssize) -1
))
;
1233
1234 escaped = escape_single_quotes (converted,
1235 in_single_quotes,
1236 in_double_quotes);
1237 g_string_append (str, escaped)(__builtin_constant_p (escaped) ? __extension__ ({ const char
* const __val = (escaped); g_string_append_len_inline (str, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (str, escaped
, (gssize) -1))
;
1238
1239 g_free (escaped);
1240 g_free (converted);
1241 }
1242
1243 return ADDED_ALL;
1244}
1245
1246static AddedStatus
1247append_first_converted (GString *str,
1248 ConversionType conversion,
1249 GSList **arg_ptr,
1250 gboolean in_single_quotes,
1251 gboolean in_double_quotes,
1252 AddedStatus added_status)
1253{
1254 GSList *l;
1255 char *converted = NULL((void*)0);
1256 char *escaped;
1257
1258 for (l = *arg_ptr; l; l = l->next) {
1259 if ((converted = convert_uri (l->data, conversion)))
1260 break;
1261
1262 *arg_ptr = l->next;
1263 }
1264
1265 if (!converted)
1266 return added_status;
1267
1268 escaped = escape_single_quotes (converted, in_single_quotes, in_double_quotes);
1269 g_string_append (str, escaped)(__builtin_constant_p (escaped) ? __extension__ ({ const char
* const __val = (escaped); g_string_append_len_inline (str, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (str, escaped
, (gssize) -1))
;
1270 g_free (escaped);
1271 g_free (converted);
1272
1273 return added_status != ADDED_ALL ? ADDED_SINGLE : added_status;
1274}
1275
1276static gboolean
1277do_percent_subst (const MateDesktopItem *item,
1278 const char *arg,
1279 GString *str,
1280 gboolean in_single_quotes,
1281 gboolean in_double_quotes,
1282 GSList *args,
1283 GSList **arg_ptr,
1284 AddedStatus *added_status)
1285{
1286 char *esc;
1287 const char *cs;
1288
1289 if (arg[0] != '%' || arg[1] == '\0') {
1290 return FALSE(0);
1291 }
1292
1293 switch (arg[1]) {
1294 case '%':
1295 g_string_append_c (str, '%')g_string_append_c_inline (str, '%');
1296 break;
1297 case 'U':
1298 *added_status = append_all_converted (str,
1299 URI_TO_STRING,
1300 args,
1301 in_single_quotes,
1302 in_double_quotes,
1303 *added_status);
1304 break;
1305 case 'F':
1306 *added_status = append_all_converted (str,
1307 URI_TO_LOCAL_PATH,
1308 args,
1309 in_single_quotes,
1310 in_double_quotes,
1311 *added_status);
1312 break;
1313 case 'N':
1314 *added_status = append_all_converted (str,
1315 URI_TO_LOCAL_BASENAME,
1316 args,
1317 in_single_quotes,
1318 in_double_quotes,
1319 *added_status);
1320 break;
1321 case 'D':
1322 *added_status = append_all_converted (str,
1323 URI_TO_LOCAL_DIRNAME,
1324 args,
1325 in_single_quotes,
1326 in_double_quotes,
1327 *added_status);
1328 break;
1329 case 'f':
1330 *added_status = append_first_converted (str,
1331 URI_TO_LOCAL_PATH,
1332 arg_ptr,
1333 in_single_quotes,
1334 in_double_quotes,
1335 *added_status);
1336 break;
1337 case 'u':
1338 *added_status = append_first_converted (str,
1339 URI_TO_STRING,
1340 arg_ptr,
1341 in_single_quotes,
1342 in_double_quotes,
1343 *added_status);
1344 break;
1345 case 'd':
1346 *added_status = append_first_converted (str,
1347 URI_TO_LOCAL_DIRNAME,
1348 arg_ptr,
1349 in_single_quotes,
1350 in_double_quotes,
1351 *added_status);
1352 break;
1353 case 'n':
1354 *added_status = append_first_converted (str,
1355 URI_TO_LOCAL_BASENAME,
1356 arg_ptr,
1357 in_single_quotes,
1358 in_double_quotes,
1359 *added_status);
1360 break;
1361 case 'm':
1362 /* Note: v0.9.4 of the spec says this is deprecated
1363 * and replace with --miniicon iconname */
1364 cs = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_MINI_ICON"MiniIcon");
1365 if (cs != NULL((void*)0)) {
1366 g_string_append (str, "--miniicon=")(__builtin_constant_p ("--miniicon=") ? __extension__ ({ const
char * const __val = ("--miniicon="); g_string_append_len_inline
(str, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(str, "--miniicon=", (gssize) -1))
;
1367 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1368 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1369 }
1370 break;
1371 case 'i':
1372 /* Note: v0.9.4 of the spec says replace with --icon iconname */
1373 cs = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_ICON"Icon");
1374 if (cs != NULL((void*)0)) {
1375 g_string_append (str, "--icon=")(__builtin_constant_p ("--icon=") ? __extension__ ({ const char
* const __val = ("--icon="); g_string_append_len_inline (str
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (str
, "--icon=", (gssize) -1))
;
1376 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1377 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1378 }
1379 break;
1380 case 'c':
1381 cs = mate_desktop_item_get_localestring (item, MATE_DESKTOP_ITEM_NAME"Name");
1382 if (cs != NULL((void*)0)) {
1383 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1384 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1385 g_free (esc);
1386 }
1387 break;
1388 case 'k':
1389 if (item->location != NULL((void*)0)) {
1390 esc = escape_single_quotes (item->location, in_single_quotes, in_double_quotes);
1391 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1392 g_free (esc);
1393 }
1394 break;
1395 case 'v':
1396 cs = mate_desktop_item_get_localestring (item, MATE_DESKTOP_ITEM_DEV"Dev");
1397 if (cs != NULL((void*)0)) {
1398 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1399 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1400 g_free (esc);
1401 }
1402 break;
1403 default:
1404 /* Maintain special characters - e.g. "%20" */
1405 if (g_ascii_isdigit (arg [1])((g_ascii_table[(guchar) (arg [1])] & G_ASCII_DIGIT) != 0
)
)
1406 g_string_append_c (str, '%')g_string_append_c_inline (str, '%');
1407 return FALSE(0);
1408 }
1409
1410 return TRUE(!(0));
1411}
1412
1413static char *
1414expand_string (const MateDesktopItem *item,
1415 const char *s,
1416 GSList *args,
1417 GSList **arg_ptr,
1418 AddedStatus *added_status)
1419{
1420 const char *p;
1421 gboolean escape = FALSE(0);
1422 gboolean single_quot = FALSE(0);
1423 gboolean double_quot = FALSE(0);
1424 GString *gs = g_string_new (NULL((void*)0));
1425
1426 for (p = s; *p != '\0'; p++) {
1427 if (escape) {
1428 escape = FALSE(0);
1429 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1430 } else if (*p == '\\') {
1431 if ( ! single_quot)
1432 escape = TRUE(!(0));
1433 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1434 } else if (*p == '\'') {
1435 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1436 if ( ! single_quot && ! double_quot) {
1437 single_quot = TRUE(!(0));
1438 } else if (single_quot) {
1439 single_quot = FALSE(0);
1440 }
1441 } else if (*p == '"') {
1442 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1443 if ( ! single_quot && ! double_quot) {
1444 double_quot = TRUE(!(0));
1445 } else if (double_quot) {
1446 double_quot = FALSE(0);
1447 }
1448 } else if (*p == '%') {
1449 if (do_percent_subst (item, p, gs,
1450 single_quot, double_quot,
1451 args, arg_ptr,
1452 added_status)) {
1453 p++;
1454 }
1455 } else {
1456 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1457 }
1458 }
1459 return g_string_free (gs, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((gs),
((0))) : g_string_free_and_steal (gs)) : (g_string_free) ((gs
), ((0))))
;
1460}
1461
1462/*Functions in this code block should only ever be reached in x11*/
1463#ifdef HAVE_STARTUP_NOTIFICATION
1464static void
1465sn_error_trap_push (SnDisplay *display,
1466 Display *xdisplay)
1467{
1468 GdkDisplay *gdkdisplay;
1469
1470 gdkdisplay = gdk_display_get_default ();
1471 gdk_x11_display_error_trap_push (gdkdisplay);
1472}
1473
1474static void
1475sn_error_trap_pop (SnDisplay *display,
1476 Display *xdisplay)
1477{
1478 GdkDisplay *gdkdisplay;
1479
1480 gdkdisplay = gdk_display_get_default ();
1481 gdk_x11_display_error_trap_pop_ignored (gdkdisplay);
1482}
1483
1484static char **
1485make_spawn_environment_for_sn_context (SnLauncherContext *sn_context,
1486 char **envp)
1487{
1488 char **retval;
1489 char **freeme;
1490 int i, j;
1491 int desktop_startup_id_len;
1492
1493 retval = freeme = NULL((void*)0);
1494
1495 if (envp == NULL((void*)0)) {
1496 envp = freeme = g_listenv ();
1497 for (i = 0; envp[i]; i++) {
1498 char *name = envp[i];
1499
1500 envp[i] = g_strjoin ("=", name, g_getenv (name), NULL((void*)0));
1501 g_free (name);
1502 }
1503 } else {
1504 for (i = 0; envp[i]; i++)
1505 ;
1506 }
1507
1508 retval = g_new (char *, i + 2)((char * *) g_malloc_n ((i + 2), sizeof (char *)));
1509
1510 desktop_startup_id_len = strlen ("DESKTOP_STARTUP_ID");
1511
1512 for (i = 0, j = 0; envp[i]; i++) {
1513 if (strncmp (envp[i], "DESKTOP_STARTUP_ID", desktop_startup_id_len) != 0) {
1514 retval[j] = g_strdup (envp[i])g_strdup_inline (envp[i]);
1515 ++j;
1516 }
1517 }
1518
1519 retval[j] = g_strdup_printf ("DESKTOP_STARTUP_ID=%s",
1520 sn_launcher_context_get_startup_id (sn_context));
1521 ++j;
1522 retval[j] = NULL((void*)0);
1523
1524 g_strfreev (freeme);
1525
1526 return retval;
1527}
1528
1529/* This should be fairly long, as it's confusing to users if a startup
1530 * ends when it shouldn't (it appears that the startup failed, and
1531 * they have to relaunch the app). Also the timeout only matters when
1532 * there are bugs and apps don't end their own startup sequence.
1533 *
1534 * This timeout is a "last resort" timeout that ignores whether the
1535 * startup sequence has shown activity or not. Marco and the
1536 * tasklist have smarter, and correspondingly able-to-be-shorter
1537 * timeouts. The reason our timeout is dumb is that we don't monitor
1538 * the sequence (don't use an SnMonitorContext)
1539 */
1540#define STARTUP_TIMEOUT_LENGTH_SEC30 30 /* seconds */
1541#define STARTUP_TIMEOUT_LENGTH(30 * 1000) (STARTUP_TIMEOUT_LENGTH_SEC30 * 1000)
1542
1543typedef struct
1544{
1545 GdkScreen *screen;
1546 GSList *contexts;
1547 guint timeout_id;
1548} StartupTimeoutData;
1549
1550static void
1551free_startup_timeout (void *data)
1552{
1553 StartupTimeoutData *std = data;
1554
1555 g_slist_free_full (std->contexts, (GDestroyNotify) sn_launcher_context_unref);
1556
1557 if (std->timeout_id != 0) {
1558 g_source_remove (std->timeout_id);
1559 std->timeout_id = 0;
1560 }
1561
1562 g_free (std);
1563}
1564
1565static gboolean
1566startup_timeout (void *data)
1567{
1568 StartupTimeoutData *std = data;
1569 GSList *tmp;
1570 int min_timeout;
1571
1572 min_timeout = STARTUP_TIMEOUT_LENGTH(30 * 1000);
1573
1574#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1575 gint64 now = g_get_real_time ();
1576#else
1577 GTimeVal now;
1578 g_get_current_time (&now);
1579#endif
1580
1581 tmp = std->contexts;
1582 while (tmp != NULL((void*)0)) {
1583 SnLauncherContext *sn_context = tmp->data;
1584 GSList *next = tmp->next;
1585 double elapsed;
1586
1587#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1588 time_t tv_sec;
1589 suseconds_t tv_usec;
1590 gint64 tv;
1591
1592 sn_launcher_context_get_last_active_time (sn_context, &tv_sec, &tv_usec);
1593 tv = (tv_sec * G_USEC_PER_SEC1000000) + tv_usec;
1594 elapsed = (double) (now - tv) / 1000.0;
1595#else
1596 long tv_sec, tv_usec;
1597
1598 sn_launcher_context_get_last_active_time (sn_context,
1599 &tv_sec, &tv_usec);
1600
1601 elapsed =
1602 ((((double)now.tv_sec - tv_sec) * G_USEC_PER_SEC1000000 +
1603 (now.tv_usec - tv_usec))) / 1000.0;
1604#endif
1605
1606 if (elapsed >= STARTUP_TIMEOUT_LENGTH(30 * 1000)) {
1607 std->contexts = g_slist_remove (std->contexts,
1608 sn_context);
1609 sn_launcher_context_complete (sn_context);
1610 sn_launcher_context_unref (sn_context);
1611 } else {
1612 min_timeout = MIN (min_timeout, (STARTUP_TIMEOUT_LENGTH - elapsed))(((min_timeout) < (((30 * 1000) - elapsed))) ? (min_timeout
) : (((30 * 1000) - elapsed)))
;
1613 }
1614
1615 tmp = next;
1616 }
1617
1618 /* we'll use seconds for the timeout */
1619 if (min_timeout < 1000)
1620 min_timeout = 1000;
1621
1622 if (std->contexts == NULL((void*)0)) {
1623 std->timeout_id = 0;
1624 } else {
1625 std->timeout_id = g_timeout_add_seconds (min_timeout / 1000,
1626 startup_timeout,
1627 std);
1628 }
1629
1630 /* always remove this one, but we may have reinstalled another one. */
1631 return FALSE(0);
1632}
1633
1634static void
1635add_startup_timeout (GdkScreen *screen,
1636 SnLauncherContext *sn_context)
1637{
1638 StartupTimeoutData *data;
1639
1640 data = g_object_get_data (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "mate-startup-data");
1641 if (data == NULL((void*)0)) {
1642 data = g_new (StartupTimeoutData, 1)((StartupTimeoutData *) g_malloc_n ((1), sizeof (StartupTimeoutData
)))
;
1643 data->screen = screen;
1644 data->contexts = NULL((void*)0);
1645 data->timeout_id = 0;
1646
1647 g_object_set_data_full (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "mate-startup-data",
1648 data, free_startup_timeout);
1649 }
1650
1651 sn_launcher_context_ref (sn_context);
1652 data->contexts = g_slist_prepend (data->contexts, sn_context);
1653
1654 if (data->timeout_id == 0) {
1655 data->timeout_id = g_timeout_add_seconds (
1656 STARTUP_TIMEOUT_LENGTH_SEC30,
1657 startup_timeout,
1658 data);
1659 }
1660}
1661#endif /* HAVE_STARTUP_NOTIFICATION - functions should only be reached in x11*/
1662
1663static inline char *
1664stringify_uris (GSList *args)
1665{
1666 GString *str;
1667
1668 str = g_string_new (NULL((void*)0));
1669
1670 append_all_converted (str, URI_TO_STRING, args, FALSE(0), FALSE(0), ADDED_NONE);
1671
1672 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1673}
1674
1675static inline char *
1676stringify_files (GSList *args)
1677{
1678 GString *str;
1679
1680 str = g_string_new (NULL((void*)0));
1681
1682 append_all_converted (str, URI_TO_LOCAL_PATH, args, FALSE(0), FALSE(0), ADDED_NONE);
1683
1684 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1685}
1686
1687static char **
1688make_environment_for_screen (GdkScreen *screen,
1689 char **envp)
1690{
1691 GdkDisplay *display;
1692 char **retval;
1693 char **freeme;
1694 char *display_name;
1695 int display_index = -1;
1696 int i, env_len;
1697
1698 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((screen)); GType __t = ((gdk_screen_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "GDK_IS_SCREEN (screen)"); return (((void*)0)
); } } while (0)
;
1699
1700 retval = freeme = NULL((void*)0);
1701
1702 if (envp == NULL((void*)0)) {
1703 envp = freeme = g_listenv ();
1704 for (i = 0; envp [i]; i++) {
1705 char *name = envp[i];
1706
1707 envp[i] = g_strjoin ("=", name, g_getenv (name), NULL((void*)0));
1708 g_free (name);
1709 }
1710 }
1711
1712 for (env_len = 0; envp [env_len]; env_len++)
1713 if (strncmp (envp [env_len], "DISPLAY", strlen ("DISPLAY")) == 0)
1714 display_index = env_len;
1715
1716 retval = g_new (char *, env_len + 1)((char * *) g_malloc_n ((env_len + 1), sizeof (char *)));
1717 retval [env_len] = NULL((void*)0);
1718
1719 display = gdk_screen_get_display (screen);
1720 display_name = g_strdup (gdk_display_get_name (display))g_strdup_inline (gdk_display_get_name (display));
1721
1722 for (i = 0; i < env_len; i++)
1723 if (i == display_index)
1724 retval [i] = g_strconcat ("DISPLAY=", display_name, NULL((void*)0));
1725 else
1726 retval [i] = g_strdup (envp[i])g_strdup_inline (envp[i]);
1727
1728 g_assert (i == env_len)do { if (i == env_len) ; else g_assertion_message_expr ("MateDesktop"
, "mate-desktop-item.c", 1728, ((const char*) (__func__)), "i == env_len"
); } while (0)
;
1729
1730 g_free (display_name);
1731 g_strfreev (freeme);
1732
1733 return retval;
1734}
1735
1736static void
1737dummy_child_watch (GPid pid,
1738 gint status,
1739 gpointer user_data)
1740{
1741 /* Nothing, this is just to ensure we don't double fork
1742 * and break pkexec:
1743 * https://bugzilla.gnome.org/show_bug.cgi?id=675789
1744 */
1745}
1746
1747static int
1748ditem_execute (const MateDesktopItem *item,
1749 const char *exec,
1750 GList *file_list,
1751 GdkScreen *screen,
1752 int workspace,
1753 char **envp,
1754 gboolean launch_only_one,
1755 gboolean use_current_dir,
1756 gboolean append_uris,
1757 gboolean append_paths,
1758 gboolean do_not_reap_child,
1759 GError **error)
1760{
1761 char **free_me = NULL((void*)0);
1762 char **real_argv;
1763 int i, ret;
1
'ret' declared without an initial value
1764 char **term_argv = NULL((void*)0);
1765 int term_argc = 0;
1766 GSList *vector_list;
1767 GSList *args, *arg_ptr;
1768 AddedStatus added_status;
1769 const char *working_dir = NULL((void*)0);
1770 char **temp_argv = NULL((void*)0);
1771 int temp_argc = 0;
1772 char *new_exec, *uris, *temp;
1773 char *exec_locale;
1774 int launched = 0;
1775 GPid pid;
1776#ifdef HAVE_STARTUP_NOTIFICATION
1777 GdkDisplay *gdkdisplay;
1778 SnLauncherContext *sn_context;
1779 SnDisplay *sn_display;
1780 const char *startup_class;
1781#endif
1782
1783 g_return_val_if_fail (item, -1)do { if ((item)) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "item"); return (-1); } } while
(0)
;
2
Assuming 'item' is non-null
3
Taking true branch
4
Loop condition is false. Exiting loop
1784
1785 if (item->type == MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
5
Assuming field 'type' is not equal to MATE_DESKTOP_ITEM_TYPE_APPLICATION
1786 working_dir = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_PATH"Path");
1787 if (working_dir &&
1788 !g_file_test (working_dir, G_FILE_TEST_IS_DIR))
1789 working_dir = NULL((void*)0);
1790 }
1791
1792 if (working_dir
5.1
'working_dir' is equal to NULL
== NULL((void*)0) && !use_current_dir)
6
Assuming 'use_current_dir' is not equal to 0
7
Taking false branch
1793 working_dir = g_get_home_dir ();
1794
1795 if (mate_desktop_item_get_boolean (item, MATE_DESKTOP_ITEM_TERMINAL"Terminal")) {
8
Taking false branch
1796 const char *options =
1797 mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_TERMINAL_OPTIONS"TerminalOptions");
1798
1799 if (options != NULL((void*)0)) {
1800 g_shell_parse_argv (options,
1801 &term_argc,
1802 &term_argv,
1803 NULL((void*)0) /* error */);
1804 /* ignore errors */
1805 }
1806
1807 mate_desktop_prepend_terminal_to_vector (&term_argc, &term_argv);
1808 }
1809
1810 args = make_args (file_list);
1811 arg_ptr = make_args (file_list);
1812
1813#ifdef HAVE_STARTUP_NOTIFICATION
1814 GdkDisplay *display = gdk_screen_get_display (gdk_screen_get_default());
1815 if (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
9
Assuming '__inst' is non-null
10
Taking false branch
11
Assuming field 'g_class' is null
12
Assuming the condition is false
13
Taking false branch
1816 {
1817 if (screen)
1818 gdkdisplay = gdk_screen_get_display (screen);
1819 else
1820 gdkdisplay = gdk_display_get_default ();
1821
1822 sn_display = sn_display_new (GDK_DISPLAY_XDISPLAY (gdkdisplay)(gdk_x11_display_get_xdisplay (gdkdisplay)),
1823 sn_error_trap_push,
1824 sn_error_trap_pop);
1825
1826 /* Only initiate notification if desktop file supports it.
1827 * (we could avoid setting up the SnLauncherContext if we aren't going
1828 * to initiate, but why bother)
1829 */
1830
1831 startup_class = mate_desktop_item_get_string (item,
1832 "StartupWMClass");
1833 if (startup_class ||
1834 mate_desktop_item_get_boolean (item, "StartupNotify")) {
1835 const char *name;
1836 const char *icon;
1837
1838 sn_context = sn_launcher_context_new (sn_display,
1839 screen ? gdk_x11_screen_get_screen_number (screen) :
1840 DefaultScreen (GDK_DISPLAY_XDISPLAY (gdkdisplay))(((_XPrivDisplay)((gdk_x11_display_get_xdisplay (gdkdisplay))
))->default_screen)
);
1841
1842 name = mate_desktop_item_get_localestring (item,
1843 MATE_DESKTOP_ITEM_NAME"Name");
1844
1845 if (name == NULL((void*)0))
1846 name = mate_desktop_item_get_localestring (item,
1847 MATE_DESKTOP_ITEM_GENERIC_NAME"GenericName");
1848
1849 if (name != NULL((void*)0)) {
1850 char *description;
1851
1852 sn_launcher_context_set_name (sn_context, name);
1853
1854 description = g_strdup_printf (_("Starting %s")((char *) g_dgettext ("mate-desktop", "Starting %s")), name);
1855
1856 sn_launcher_context_set_description (sn_context, description);
1857
1858 g_free (description);
1859 }
1860
1861 icon = mate_desktop_item_get_string (item,
1862 MATE_DESKTOP_ITEM_ICON"Icon");
1863
1864 if (icon != NULL((void*)0))
1865 sn_launcher_context_set_icon_name (sn_context, icon);
1866
1867 sn_launcher_context_set_workspace (sn_context, workspace);
1868
1869 if (startup_class != NULL((void*)0))
1870 sn_launcher_context_set_wmclass (sn_context,
1871 startup_class);
1872 } else {
1873 sn_context = NULL((void*)0);
1874 }
1875 }
1876 else {
1877 sn_context = NULL((void*)0);
1878 sn_display = NULL((void*)0);
1879 }
1880#endif
1881
1882 if (screen) {
14
Assuming 'screen' is null
15
Taking false branch
1883 envp = make_environment_for_screen (screen, envp);
1884 if (free_me)
1885 g_strfreev (free_me);
1886 free_me = envp;
1887 }
1888
1889 exec_locale = g_filename_from_utf8 (exec, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
1890
1891 if (exec_locale == NULL((void*)0)) {
16
Assuming 'exec_locale' is not equal to NULL
17
Taking false branch
1892 exec_locale = g_strdup ("")g_strdup_inline ("");
1893 }
1894
1895 do {
32
Loop condition is false. Exiting loop
1896 added_status = ADDED_NONE;
1897 new_exec = expand_string (item,
1898 exec_locale,
1899 args, &arg_ptr, &added_status);
1900
1901 if (launched
17.1
'launched' is equal to 0
== 0 && added_status
17.2
'added_status' is equal to ADDED_NONE
== ADDED_NONE && append_uris) {
18
Assuming 'append_uris' is 0
1902 uris = stringify_uris (args);
1903 temp = g_strconcat (new_exec, " ", uris, NULL((void*)0));
1904 g_free (uris);
1905 g_free (new_exec);
1906 new_exec = temp;
1907 added_status = ADDED_ALL;
1908 }
1909
1910 /* append_uris and append_paths are mutually exlusive */
1911 if (launched
18.1
'launched' is equal to 0
== 0 && added_status
18.2
'added_status' is equal to ADDED_NONE
== ADDED_NONE && append_paths) {
19
Assuming 'append_paths' is 0
1912 uris = stringify_files (args);
1913 temp = g_strconcat (new_exec, " ", uris, NULL((void*)0));
1914 g_free (uris);
1915 g_free (new_exec);
1916 new_exec = temp;
1917 added_status = ADDED_ALL;
1918 }
1919
1920 if (launched
19.1
'launched' is <= 0
> 0 && added_status == ADDED_NONE) {
1921 g_free (new_exec);
1922 break;
1923 }
1924
1925 if ( ! g_shell_parse_argv (new_exec,
20
Assuming the condition is false
21
Taking false branch
1926 &temp_argc, &temp_argv, error)) {
1927 /* The error now comes from g_shell_parse_argv */
1928 g_free (new_exec);
1929 ret = -1;
1930 break;
1931 }
1932 g_free (new_exec);
1933
1934 vector_list = NULL((void*)0);
1935 for(i = 0; i < term_argc; i++)
22
Loop condition is false. Execution continues on line 1939
1936 vector_list = g_slist_append (vector_list,
1937 g_strdup (term_argv[i])g_strdup_inline (term_argv[i]));
1938
1939 for(i = 0; i < temp_argc; i++)
23
Assuming 'i' is >= 'temp_argc'
24
Loop condition is false. Execution continues on line 1943
1940 vector_list = g_slist_append (vector_list,
1941 g_strdup (temp_argv[i])g_strdup_inline (temp_argv[i]));
1942
1943 g_strfreev (temp_argv);
1944
1945 real_argv = list_to_vector (vector_list);
1946 g_slist_free_full (vector_list, g_free);
1947
1948#ifdef HAVE_STARTUP_NOTIFICATION
1949 if (sn_context
24.1
'sn_context' is equal to NULL
!= NULL((void*)0) && (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) &&
1950 !sn_launcher_context_get_initiated (sn_context)) {
1951 guint32 launch_time;
1952
1953 /* This means that we always use the first real_argv[0]
1954 * we select for the "binary name", but it's probably
1955 * OK to do that. Binary name isn't super-important
1956 * anyway, and we can't initiate twice, and we
1957 * must initiate prior to fork/exec.
1958 */
1959
1960 sn_launcher_context_set_binary_name (sn_context,
1961 real_argv[0]);
1962
1963 if (item->launch_time > 0)
1964 launch_time = item->launch_time;
1965 else
1966 launch_time = gdk_x11_display_get_user_time (gdkdisplay);
1967
1968 sn_launcher_context_initiate (sn_context,
1969 g_get_prgname () ? g_get_prgname () : "unknown",
1970 real_argv[0],
1971 launch_time);
1972
1973 /* Don't allow accidental reuse of same timestamp */
1974 ((MateDesktopItem *)item)->launch_time = 0;
1975
1976 envp = make_spawn_environment_for_sn_context (sn_context, envp);
1977 if (free_me)
1978 g_strfreev (free_me);
1979 free_me = envp;
1980 }
1981#endif
1982
1983 if ( ! g_spawn_async (working_dir,
28
Assuming the condition is false
29
Taking false branch
1984 real_argv,
1985 envp,
1986 (do_not_reap_child ? G_SPAWN_DO_NOT_REAP_CHILD : 0) | G_SPAWN_SEARCH_PATH /* flags */,
25
Assuming 'do_not_reap_child' is 0
26
'?' condition is false
1987 NULL((void*)0), /* child_setup_func */
1988 NULL((void*)0), /* child_setup_func_data */
1989 (do_not_reap_child
26.1
'do_not_reap_child' is 0
? &pid : NULL((void*)0)) /* child_pid */,
27
'?' condition is false
1990 error)) {
1991 /* The error was set for us,
1992 * we just can't launch this thingie */
1993 ret = -1;
1994 g_strfreev (real_argv);
1995 break;
1996 } else if (do_not_reap_child
29.1
'do_not_reap_child' is 0
) {
30
Taking false branch
1997 g_child_watch_add (pid, dummy_child_watch, NULL((void*)0));
1998 }
1999
2000 launched ++;
2001
2002 g_strfreev (real_argv);
2003
2004 if (arg_ptr != NULL((void*)0))
31
Assuming 'arg_ptr' is equal to NULL
2005 arg_ptr = arg_ptr->next;
2006
2007 /* rinse, repeat until we run out of arguments (That
2008 * is if we were adding singles anyway) */
2009 } while (added_status
31.1
'added_status' is not equal to ADDED_SINGLE
== ADDED_SINGLE &&
2010 arg_ptr != NULL((void*)0) &&
2011 ! launch_only_one);
2012
2013 g_free (exec_locale);
2014#ifdef HAVE_STARTUP_NOTIFICATION
2015 if ((sn_context
32.1
'sn_context' is equal to NULL
!= NULL((void*)0)) && (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)){
2016 if (ret < 0)
2017 sn_launcher_context_complete (sn_context); /* end sequence */
2018 else
2019 add_startup_timeout (screen ? screen :
2020 gdk_display_get_default_screen (gdk_display_get_default ()),
2021 sn_context);
2022 sn_launcher_context_unref (sn_context);
2023 }
2024 if (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
33
Taking false branch
34
Assuming the condition is false
35
Taking false branch
2025 sn_display_unref (sn_display);
2026
2027#endif /* HAVE_STARTUP_NOTIFICATION */
2028
2029 free_args (args);
2030
2031 if (term_argv
35.1
'term_argv' is null
)
36
Taking false branch
2032 g_strfreev (term_argv);
2033
2034 if (free_me
36.1
'free_me' is null
)
37
Taking false branch
2035 g_strfreev (free_me);
2036
2037 return ret;
38
Undefined or garbage value returned to caller
2038}
2039
2040/* strip any trailing &, return FALSE if bad things happen and
2041 we end up with an empty string */
2042static gboolean
2043strip_the_amp (char *exec)
2044{
2045 size_t exec_len;
2046
2047 g_strstrip (exec)g_strchomp (g_strchug (exec));
2048 if (*exec == '\0')
2049 return FALSE(0);
2050
2051 exec_len = strlen (exec);
2052 /* kill any trailing '&' */
2053 if (exec[exec_len-1] == '&') {
2054 exec[exec_len-1] = '\0';
2055 g_strchomp (exec);
2056 }
2057
2058 /* can't exactly launch an empty thing */
2059 if (*exec == '\0')
2060 return FALSE(0);
2061
2062 return TRUE(!(0));
2063}
2064
2065static int
2066mate_desktop_item_launch_on_screen_with_env (
2067 const MateDesktopItem *item,
2068 GList *file_list,
2069 MateDesktopItemLaunchFlags flags,
2070 GdkScreen *screen,
2071 int workspace,
2072 char **envp,
2073 GError **error)
2074{
2075 const char *exec;
2076 char *the_exec;
2077 int ret;
2078
2079 exec = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_EXEC"Exec");
2080 /* This is a URL, so launch it as a url */
2081 if (item->type == MATE_DESKTOP_ITEM_TYPE_LINK) {
2082 const char *url;
2083 gboolean retval;
2084
2085 url = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_URL"URL");
2086 /* Mate panel used to put this in Exec */
2087 if (!(url && url[0] != '\0'))
2088 url = exec;
2089
2090 if (!(url && url[0] != '\0')) {
2091 g_set_error (error,
2092 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2093 MATE_DESKTOP_ITEM_ERROR_NO_URL,
2094 _("No URL to launch")((char *) g_dgettext ("mate-desktop", "No URL to launch")));
2095 return -1;
2096 }
2097
2098 retval = gtk_show_uri_on_window (NULL((void*)0),
2099 url,
2100 GDK_CURRENT_TIME0L,
2101 error);
2102 return retval ? 0 : -1;
2103 }
2104
2105 /* check the type, if there is one set */
2106 if (item->type != MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
2107 g_set_error (error,
2108 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2109 MATE_DESKTOP_ITEM_ERROR_NOT_LAUNCHABLE,
2110 _("Not a launchable item")((char *) g_dgettext ("mate-desktop", "Not a launchable item"
))
);
2111 return -1;
2112 }
2113
2114 if (exec == NULL((void*)0) ||
2115 exec[0] == '\0') {
2116 g_set_error (error,
2117 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2118 MATE_DESKTOP_ITEM_ERROR_NO_EXEC_STRING,
2119 _("No command (Exec) to launch")((char *) g_dgettext ("mate-desktop", "No command (Exec) to launch"
))
);
2120 return -1;
2121 }
2122
2123 /* make a new copy and get rid of spaces */
2124 the_exec = g_alloca (strlen (exec) + 1)__builtin_alloca (strlen (exec) + 1);
2125 g_strlcpy (the_exec, exec, strlen (exec) + 1);
2126
2127 if ( ! strip_the_amp (the_exec)) {
2128 g_set_error (error,
2129 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2130 MATE_DESKTOP_ITEM_ERROR_BAD_EXEC_STRING,
2131 _("Bad command (Exec) to launch")((char *) g_dgettext ("mate-desktop", "Bad command (Exec) to launch"
))
);
2132 return -1;
2133 }
2134
2135 ret = ditem_execute (item, the_exec, file_list, screen, workspace, envp,
2136 (flags & MATE_DESKTOP_ITEM_LAUNCH_ONLY_ONE),
2137 (flags & MATE_DESKTOP_ITEM_LAUNCH_USE_CURRENT_DIR),
2138 (flags & MATE_DESKTOP_ITEM_LAUNCH_APPEND_URIS),
2139 (flags & MATE_DESKTOP_ITEM_LAUNCH_APPEND_PATHS),
2140 (flags & MATE_DESKTOP_ITEM_LAUNCH_DO_NOT_REAP_CHILD),
2141 error);
2142
2143 return ret;
2144}
2145
2146/**
2147 * mate_desktop_item_launch:
2148 * @item: A desktop item
2149 * @file_list: Files/URIs to launch this item with, can be %NULL
2150 * @flags: FIXME
2151 * @error: FIXME
2152 *
2153 * This function runs the program listed in the specified 'item',
2154 * optionally appending additional arguments to its command line. It uses
2155 * #g_shell_parse_argv to parse the the exec string into a vector which is
2156 * then passed to #g_spawn_async for execution. This can return all
2157 * the errors from MateURL, #g_shell_parse_argv and #g_spawn_async,
2158 * in addition to it's own. The files are
2159 * only added if the entry defines one of the standard % strings in it's
2160 * Exec field.
2161 *
2162 * Returns: The the pid of the process spawned. If more then one
2163 * process was spawned the last pid is returned. On error -1
2164 * is returned and @error is set.
2165 */
2166int
2167mate_desktop_item_launch (const MateDesktopItem *item,
2168 GList *file_list,
2169 MateDesktopItemLaunchFlags flags,
2170 GError **error)
2171{
2172 return mate_desktop_item_launch_on_screen_with_env (
2173 item, file_list, flags, NULL((void*)0), -1, NULL((void*)0), error);
2174}
2175
2176/**
2177 * mate_desktop_item_launch_with_env:
2178 * @item: A desktop item
2179 * @file_list: Files/URIs to launch this item with, can be %NULL
2180 * @flags: FIXME
2181 * @envp: child's environment, or %NULL to inherit parent's
2182 * @error: FIXME
2183 *
2184 * See mate_desktop_item_launch for a full description. This function
2185 * additionally passes an environment vector for the child process
2186 * which is to be launched.
2187 *
2188 * Returns: The the pid of the process spawned. If more then one
2189 * process was spawned the last pid is returned. On error -1
2190 * is returned and @error is set.
2191 */
2192int
2193mate_desktop_item_launch_with_env (const MateDesktopItem *item,
2194 GList *file_list,
2195 MateDesktopItemLaunchFlags flags,
2196 char **envp,
2197 GError **error)
2198{
2199 return mate_desktop_item_launch_on_screen_with_env (
2200 item, file_list, flags,
2201 NULL((void*)0), -1, envp, error);
2202}
2203
2204/**
2205 * mate_desktop_item_launch_on_screen:
2206 * @item: A desktop item
2207 * @file_list: Files/URIs to launch this item with, can be %NULL
2208 * @flags: FIXME
2209 * @screen: the %GdkScreen on which the application should be launched
2210 * @workspace: the workspace on which the app should be launched (-1 for current)
2211 * @error: FIXME
2212 *
2213 * See mate_desktop_item_launch for a full description. This function
2214 * additionally attempts to launch the application on a given screen
2215 * and workspace.
2216 *
2217 * Returns: The the pid of the process spawned. If more then one
2218 * process was spawned the last pid is returned. On error -1
2219 * is returned and @error is set.
2220 */
2221int
2222mate_desktop_item_launch_on_screen (const MateDesktopItem *item,
2223 GList *file_list,
2224 MateDesktopItemLaunchFlags flags,
2225 GdkScreen *screen,
2226 int workspace,
2227 GError **error)
2228{
2229 return mate_desktop_item_launch_on_screen_with_env (
2230 item, file_list, flags,
2231 screen, workspace, NULL((void*)0), error);
2232}
2233
2234/**
2235 * mate_desktop_item_drop_uri_list:
2236 * @item: A desktop item
2237 * @uri_list: text as gotten from a text/uri-list
2238 * @flags: FIXME
2239 * @error: FIXME
2240 *
2241 * A list of files or urls dropped onto an icon, the proper (Url or File)
2242 * exec is run you can pass directly string that you got as the
2243 * text/uri-list. This just parses the list and calls
2244 *
2245 * Returns: The value returned by #mate_execute_async() upon execution of
2246 * the specified item or -1 on error. If multiple instances are run, the
2247 * return of the last one is returned.
2248 */
2249int
2250mate_desktop_item_drop_uri_list (const MateDesktopItem *item,
2251 const char *uri_list,
2252 MateDesktopItemLaunchFlags flags,
2253 GError **error)
2254{
2255 return mate_desktop_item_drop_uri_list_with_env (item, uri_list,
2256 flags, NULL((void*)0), error);
2257}
2258
2259/**
2260* mate_desktop_item_drop_uri_list_with_env:
2261* @item: A desktop item
2262* @uri_list: text as gotten from a text/uri-list
2263* @flags: FIXME
2264* @envp: child's environment
2265* @error: FIXME
2266*
2267* See mate_desktop_item_drop_uri_list for a full description. This function
2268* additionally passes an environment vector for the child process
2269* which is to be launched.
2270*
2271* Returns: The value returned by #mate_execute_async() upon execution of
2272* the specified item or -1 on error. If multiple instances are run, the
2273* return of the last one is returned.
2274*/
2275int
2276mate_desktop_item_drop_uri_list_with_env (const MateDesktopItem *item,
2277 const char *uri_list,
2278 MateDesktopItemLaunchFlags flags,
2279 char **envp,
2280 GError **error)
2281{
2282 int ret;
2283 char *uri;
2284 char **uris;
2285 GList *list = NULL((void*)0);
2286
2287 uris = g_uri_list_extract_uris (uri_list);
2288
2289 for (uri = uris[0]; uri != NULL((void*)0); uri++) {
2290 list = g_list_prepend (list, uri);
2291 }
2292 list = g_list_reverse (list);
2293
2294 ret = mate_desktop_item_launch_with_env (
2295 item, list, flags, envp, error);
2296
2297 g_strfreev (uris);
2298 g_list_free (list);
2299
2300 return ret;
2301}
2302
2303static gboolean
2304exec_exists (const char *exec)
2305{
2306 if (g_path_is_absolute (exec)) {
2307 if (access (exec, X_OK1) == 0)
2308 return TRUE(!(0));
2309 else
2310 return FALSE(0);
2311 } else {
2312 char *tryme;
2313
2314 tryme = g_find_program_in_path (exec);
2315 if (tryme != NULL((void*)0)) {
2316 g_free (tryme);
2317 return TRUE(!(0));
2318 }
2319 return FALSE(0);
2320 }
2321}
2322
2323/**
2324 * mate_desktop_item_exists:
2325 * @item: A desktop item
2326 *
2327 * Attempt to figure out if the program that can be executed by this item
2328 * actually exists. First it tries the TryExec attribute to see if that
2329 * contains a program that is in the path. Then if there is no such
2330 * attribute, it tries the first word of the Exec attribute.
2331 *
2332 * Returns: A boolean, %TRUE if it exists, %FALSE otherwise.
2333 */
2334gboolean
2335mate_desktop_item_exists (const MateDesktopItem *item)
2336{
2337 const char *try_exec;
2338 const char *exec;
2339
2340 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2341
2342 try_exec = lookup (item, MATE_DESKTOP_ITEM_TRY_EXEC"TryExec");
2343
2344 if (try_exec != NULL((void*)0) &&
2345 ! exec_exists (try_exec)) {
2346 return FALSE(0);
2347 }
2348
2349 if (item->type == MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
2350 int argc;
2351 char **argv;
2352 const char *exe;
2353
2354 exec = lookup (item, MATE_DESKTOP_ITEM_EXEC"Exec");
2355 if (exec == NULL((void*)0))
2356 return FALSE(0);
2357
2358 if ( ! g_shell_parse_argv (exec, &argc, &argv, NULL((void*)0)))
2359 return FALSE(0);
2360
2361 if (argc < 1) {
2362 g_strfreev (argv);
2363 return FALSE(0);
2364 }
2365
2366 exe = argv[0];
2367
2368 if ( ! exec_exists (exe)) {
2369 g_strfreev (argv);
2370 return FALSE(0);
2371 }
2372 g_strfreev (argv);
2373 }
2374
2375 return TRUE(!(0));
2376}
2377
2378/**
2379 * mate_desktop_item_get_entry_type:
2380 * @item: A desktop item
2381 *
2382 * Gets the type attribute (the 'Type' field) of the item. This should
2383 * usually be 'Application' for an application, but it can be 'Directory'
2384 * for a directory description. There are other types available as well.
2385 * The type usually indicates how the desktop item should be handeled and
2386 * how the 'Exec' field should be handeled.
2387 *
2388 * Returns: The type of the specified 'item'. The returned
2389 * memory remains owned by the MateDesktopItem and should not be freed.
2390 */
2391MateDesktopItemType
2392mate_desktop_item_get_entry_type (const MateDesktopItem *item)
2393{
2394 g_return_val_if_fail (item != NULL, 0)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (0); } } while (0)
;
2395 g_return_val_if_fail (item->refcount > 0, 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (0); } } while (0)
;
2396
2397 return item->type;
2398}
2399
2400void
2401mate_desktop_item_set_entry_type (MateDesktopItem *item,
2402 MateDesktopItemType type)
2403{
2404 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2405 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2406
2407 item->type = type;
2408
2409 switch (type) {
2410 case MATE_DESKTOP_ITEM_TYPE_NULL:
2411 set (item, MATE_DESKTOP_ITEM_TYPE"Type", NULL((void*)0));
2412 break;
2413 case MATE_DESKTOP_ITEM_TYPE_APPLICATION:
2414 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Application");
2415 break;
2416 case MATE_DESKTOP_ITEM_TYPE_LINK:
2417 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Link");
2418 break;
2419 case MATE_DESKTOP_ITEM_TYPE_FSDEVICE:
2420 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "FSDevice");
2421 break;
2422 case MATE_DESKTOP_ITEM_TYPE_MIME_TYPE:
2423 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "MimeType");
2424 break;
2425 case MATE_DESKTOP_ITEM_TYPE_DIRECTORY:
2426 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Directory");
2427 break;
2428 case MATE_DESKTOP_ITEM_TYPE_SERVICE:
2429 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Service");
2430 break;
2431 case MATE_DESKTOP_ITEM_TYPE_SERVICE_TYPE:
2432 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "ServiceType");
2433 break;
2434 default:
2435 break;
2436 }
2437}
2438
2439/**
2440 * mate_desktop_item_get_file_status:
2441 * @item: A desktop item
2442 *
2443 * This function checks the modification time of the on-disk file to
2444 * see if it is more recent than the in-memory data.
2445 *
2446 * Returns: An enum value that specifies whether the item has changed since being loaded.
2447 */
2448MateDesktopItemStatus
2449mate_desktop_item_get_file_status (const MateDesktopItem *item)
2450{
2451 MateDesktopItemStatus retval;
2452 GFile *file;
2453 GFileInfo *info;
2454
2455 g_return_val_if_fail (item != NULL, MATE_DESKTOP_ITEM_DISAPPEARED)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (MATE_DESKTOP_ITEM_DISAPPEARED); } } while (0)
;
2456 g_return_val_if_fail (item->refcount > 0, MATE_DESKTOP_ITEM_DISAPPEARED)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (MATE_DESKTOP_ITEM_DISAPPEARED); } } while (0)
;
2457
2458 if (item->location == NULL((void*)0))
2459 return MATE_DESKTOP_ITEM_DISAPPEARED;
2460
2461 file = g_file_new_for_uri (item->location);
2462 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2463 G_FILE_QUERY_INFO_NONE, NULL((void*)0), NULL((void*)0));
2464
2465 retval = MATE_DESKTOP_ITEM_UNCHANGED;
2466
2467 if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2468 retval = MATE_DESKTOP_ITEM_DISAPPEARED;
2469 else if (((guint64) item->mtime) < g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2470 retval = MATE_DESKTOP_ITEM_CHANGED;
2471
2472 g_object_unref (info);
2473 g_object_unref (file);
2474
2475 return retval;
2476}
2477
2478/**
2479 * mate_desktop_item_find_icon:
2480 * @icon_theme: a #GtkIconTheme
2481 * @icon: icon name, something you'd get out of the Icon key
2482 * @desired_size: FIXME
2483 * @flags: FIXME
2484 *
2485 * Description: This function goes and looks for the icon file. If the icon
2486 * is not an absolute filename, this will look for it in the standard places.
2487 * If it can't find the icon, it will return %NULL
2488 *
2489 * Returns: A newly allocated string
2490 */
2491char *
2492mate_desktop_item_find_icon (GtkIconTheme *icon_theme,
2493 const char *icon,
2494 int desired_size,
2495 int flags)
2496{
2497 GtkIconInfo *info;
2498 char *full = NULL((void*)0);
2499
2500 g_return_val_if_fail (icon_theme == NULL ||do { if ((icon_theme == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((icon_theme)); GType __t = ((gtk_icon_theme_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "icon_theme == NULL || GTK_IS_ICON_THEME (icon_theme)"
); return (((void*)0)); } } while (0)
2501 GTK_IS_ICON_THEME (icon_theme), NULL)do { if ((icon_theme == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((icon_theme)); GType __t = ((gtk_icon_theme_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "icon_theme == NULL || GTK_IS_ICON_THEME (icon_theme)"
); return (((void*)0)); } } while (0)
;
2502
2503 if (icon == NULL((void*)0) || strcmp(icon,"") == 0) {
2504 return NULL((void*)0);
2505 } else if (g_path_is_absolute (icon)) {
2506 if (g_file_test (icon, G_FILE_TEST_EXISTS)) {
2507 return g_strdup (icon)g_strdup_inline (icon);
2508 } else {
2509 return NULL((void*)0);
2510 }
2511 } else {
2512 char *icon_no_extension;
2513 char *p;
2514
2515 if (icon_theme == NULL((void*)0))
2516 icon_theme = gtk_icon_theme_get_default ();
2517
2518 icon_no_extension = g_strdup (icon)g_strdup_inline (icon);
2519 p = strrchr (icon_no_extension, '.');
2520 if (p &&
2521 (strcmp (p, ".png") == 0 ||
2522 strcmp (p, ".xpm") == 0 ||
2523 strcmp (p, ".svg") == 0)) {
2524 *p = 0;
2525 }
2526
2527 info = gtk_icon_theme_lookup_icon (icon_theme,
2528 icon_no_extension,
2529 desired_size,
2530 0);
2531
2532 full = NULL((void*)0);
2533 if (info) {
2534 full = g_strdup (gtk_icon_info_get_filename (info))g_strdup_inline (gtk_icon_info_get_filename (info));
2535 g_object_unref (info);
2536 }
2537 g_free (icon_no_extension);
2538 }
2539
2540 return full;
2541
2542}
2543
2544/**
2545 * mate_desktop_item_get_icon:
2546 * @icon_theme: a #GtkIconTheme
2547 * @item: A desktop item
2548 *
2549 * Description: This function goes and looks for the icon file. If the icon
2550 * is not set as an absolute filename, this will look for it in the standard places.
2551 * If it can't find the icon, it will return %NULL
2552 *
2553 * Returns: A newly allocated string
2554 */
2555char *
2556mate_desktop_item_get_icon (const MateDesktopItem *item,
2557 GtkIconTheme *icon_theme)
2558{
2559 /* maybe this function should be deprecated in favour of find icon
2560 * -George */
2561 const char *icon;
2562
2563 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2564 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2565
2566 icon = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_ICON"Icon");
2567
2568 return mate_desktop_item_find_icon (icon_theme, icon,
2569 48 /* desired_size */,
2570 0 /* flags */);
2571}
2572
2573/**
2574 * mate_desktop_item_get_location:
2575 * @item: A desktop item
2576 *
2577 * Returns: The file location associated with 'item'.
2578 *
2579 */
2580const char *
2581mate_desktop_item_get_location (const MateDesktopItem *item)
2582{
2583 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2584 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2585
2586 return item->location;
2587}
2588
2589/**
2590 * mate_desktop_item_set_location:
2591 * @item: A desktop item
2592 * @location: A uri string specifying the file location of this particular item.
2593 *
2594 * Set's the 'location' uri of this item.
2595 */
2596void
2597mate_desktop_item_set_location (MateDesktopItem *item, const char *location)
2598{
2599 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2600 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2601
2602 if (item->location != NULL((void*)0) &&
2603 location != NULL((void*)0) &&
2604 strcmp (item->location, location) == 0)
2605 return;
2606
2607 g_free (item->location);
2608 item->location = g_strdup (location)g_strdup_inline (location);
2609
2610 /* This is ugly, but useful internally */
2611 if (item->mtime != DONT_UPDATE_MTIME((gint64)-2)) {
2612 item->mtime = 0;
2613
2614 if (item->location) {
2615 GFile *file;
2616 GFileInfo *info;
2617
2618 file = g_file_new_for_uri (item->location);
2619
2620 info = g_file_query_info (file,
2621 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2622 G_FILE_QUERY_INFO_NONE,
2623 NULL((void*)0), NULL((void*)0));
2624 if (info) {
2625 if (g_file_info_has_attribute (info,
2626 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2627 item->mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
2628 g_object_unref (info);
2629 }
2630
2631 g_object_unref (file);
2632 }
2633 }
2634
2635 /* Make sure that save actually saves */
2636 item->modified = TRUE(!(0));
2637}
2638
2639/**
2640 * mate_desktop_item_set_location_file:
2641 * @item: A desktop item
2642 * @file: A local filename specifying the file location of this particular item.
2643 *
2644 * Set's the 'location' uri of this item to the given @file.
2645 */
2646void
2647mate_desktop_item_set_location_file (MateDesktopItem *item, const char *file)
2648{
2649 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2650 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2651
2652 if (file != NULL((void*)0)) {
2653 GFile *gfile;
2654
2655 gfile = g_file_new_for_path (file);
2656 mate_desktop_item_set_location_gfile (item, gfile);
2657 g_object_unref (gfile);
2658 } else {
2659 mate_desktop_item_set_location (item, NULL((void*)0));
2660 }
2661}
2662
2663static void
2664mate_desktop_item_set_location_gfile (MateDesktopItem *item, GFile *file)
2665{
2666 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2667 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2668
2669 if (file != NULL((void*)0)) {
2670 char *uri;
2671
2672 uri = g_file_get_uri (file);
2673 mate_desktop_item_set_location (item, uri);
2674 g_free (uri);
2675 } else {
2676 mate_desktop_item_set_location (item, NULL((void*)0));
2677 }
2678}
2679
2680/*
2681 * Reading/Writing different sections, NULL is the standard section
2682 */
2683
2684gboolean
2685mate_desktop_item_attr_exists (const MateDesktopItem *item,
2686 const char *attr)
2687{
2688 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2689 g_return_val_if_fail (item->refcount > 0, FALSE)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return ((0)); } } while (0)
;
2690 g_return_val_if_fail (attr != NULL, FALSE)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return ((0)); } } while (0)
;
2691
2692 return lookup (item, attr) != NULL((void*)0);
2693}
2694
2695/*
2696 * String type
2697 */
2698const char *
2699mate_desktop_item_get_string (const MateDesktopItem *item,
2700 const char *attr)
2701{
2702 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2703 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2704 g_return_val_if_fail (attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2705
2706 return lookup (item, attr);
2707}
2708
2709void
2710mate_desktop_item_set_string (MateDesktopItem *item,
2711 const char *attr,
2712 const char *value)
2713{
2714 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2715 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2716 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2717
2718 set (item, attr, value);
2719
2720 if (strcmp (attr, MATE_DESKTOP_ITEM_TYPE"Type") == 0)
2721 item->type = type_from_string (value);
2722}
2723
2724/*
2725 * LocaleString type
2726 */
2727const char* mate_desktop_item_get_localestring(const MateDesktopItem* item, const char* attr)
2728{
2729 g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2730 g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2731 g_return_val_if_fail(attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2732
2733 return lookup_best_locale(item, attr);
2734}
2735
2736const char* mate_desktop_item_get_localestring_lang(const MateDesktopItem* item, const char* attr, const char* language)
2737{
2738 g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2739 g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2740 g_return_val_if_fail(attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2741
2742 return lookup_locale(item, attr, language);
2743}
2744
2745/**
2746 * mate_desktop_item_get_string_locale:
2747 * @item: A desktop item
2748 * @attr: An attribute name
2749 *
2750 * Returns the current locale that is used for the given attribute.
2751 * This might not be the same for all attributes. For example, if your
2752 * locale is "en_US.ISO8859-1" but attribute FOO only has "en_US" then
2753 * that would be returned for attr = "FOO". If attribute BAR has
2754 * "en_US.ISO8859-1" then that would be returned for "BAR".
2755 *
2756 * Returns: a string equal to the current locale or NULL
2757 * if the attribute is invalid or there is no matching locale.
2758 */
2759const char *
2760mate_desktop_item_get_attr_locale (const MateDesktopItem *item,
2761 const char *attr)
2762{
2763 const char * const *langs_pointer;
2764 int i;
2765
2766 langs_pointer = g_get_language_names ();
2767 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
2768 const char *value = NULL((void*)0);
2769
2770 value = lookup_locale (item, attr, langs_pointer[i]);
2771 if (value)
2772 return langs_pointer[i];
2773 }
2774
2775 return NULL((void*)0);
2776}
2777
2778GList *
2779mate_desktop_item_get_languages (const MateDesktopItem *item,
2780 const char *attr)
2781{
2782 GList *li;
2783 GList *list = NULL((void*)0);
2784
2785 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2786 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2787
2788 for (li = item->languages; li != NULL((void*)0); li = li->next) {
2789 char *language = li->data;
2790 if (attr == NULL((void*)0) ||
2791 lookup_locale (item, attr, language) != NULL((void*)0)) {
2792 list = g_list_prepend (list, language);
2793 }
2794 }
2795
2796 return g_list_reverse (list);
2797}
2798
2799static const char *
2800get_language (void)
2801{
2802 const char * const *langs_pointer;
2803 int i;
2804
2805 langs_pointer = g_get_language_names ();
2806 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
2807 /* find first without encoding */
2808 if (strchr (langs_pointer[i], '.') == NULL((void*)0)) {
2809 return langs_pointer[i];
2810 }
2811 }
2812 return NULL((void*)0);
2813}
2814
2815void
2816mate_desktop_item_set_localestring (MateDesktopItem *item,
2817 const char *attr,
2818 const char *value)
2819{
2820 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2821 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2822 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2823
2824 set_locale (item, attr, get_language (), value);
2825}
2826
2827void
2828mate_desktop_item_set_localestring_lang (MateDesktopItem *item,
2829 const char *attr,
2830 const char *language,
2831 const char *value)
2832{
2833 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2834 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2835 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2836
2837 set_locale (item, attr, language, value);
2838}
2839
2840void
2841mate_desktop_item_clear_localestring (MateDesktopItem *item,
2842 const char *attr)
2843{
2844 GList *l;
2845
2846 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2847 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2848 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2849
2850 for (l = item->languages; l != NULL((void*)0); l = l->next)
2851 set_locale (item, attr, l->data, NULL((void*)0));
2852
2853 set (item, attr, NULL((void*)0));
2854}
2855
2856/*
2857 * Strings, Regexps types
2858 */
2859
2860char **
2861mate_desktop_item_get_strings (const MateDesktopItem *item,
2862 const char *attr)
2863{
2864 const char *value;
2865
2866 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2867 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2868 g_return_val_if_fail (attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2869
2870 value = lookup (item, attr);
2871 if (value == NULL((void*)0))
2872 return NULL((void*)0);
2873
2874 /* FIXME: there's no way to escape semicolons apparently */
2875 return g_strsplit (value, ";", -1);
2876}
2877
2878void
2879mate_desktop_item_set_strings (MateDesktopItem *item,
2880 const char *attr,
2881 char **strings)
2882{
2883 char *str, *str2;
2884
2885 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2886 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2887 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2888
2889 str = g_strjoinv (";", strings);
2890 str2 = g_strconcat (str, ";", NULL((void*)0));
2891 /* FIXME: there's no way to escape semicolons apparently */
2892 set (item, attr, str2);
2893 g_free (str);
2894 g_free (str2);
2895}
2896
2897/*
2898 * Boolean type
2899 */
2900gboolean
2901mate_desktop_item_get_boolean (const MateDesktopItem *item,
2902 const char *attr)
2903{
2904 const char *value;
2905
2906 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2907 g_return_val_if_fail (item->refcount > 0, FALSE)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return ((0)); } } while (0)
;
2908 g_return_val_if_fail (attr != NULL, FALSE)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return ((0)); } } while (0)
;
2909
2910 value = lookup (item, attr);
2911 if (value == NULL((void*)0))
2912 return FALSE(0);
2913
2914 return (value[0] == 'T' ||
2915 value[0] == 't' ||
2916 value[0] == 'Y' ||
2917 value[0] == 'y' ||
2918 atoi (value) != 0);
2919}
2920
2921void
2922mate_desktop_item_set_boolean (MateDesktopItem *item,
2923 const char *attr,
2924 gboolean value)
2925{
2926 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2927 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2928 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2929
2930 set (item, attr, value ? "true" : "false");
2931}
2932
2933void
2934mate_desktop_item_set_launch_time (MateDesktopItem *item,
2935 guint32 timestamp)
2936{
2937 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2938
2939 item->launch_time = timestamp;
2940}
2941
2942/*
2943 * Clearing attributes
2944 */
2945void
2946mate_desktop_item_clear_section (MateDesktopItem *item,
2947 const char *section)
2948{
2949 Section *sec;
2950 GList *li;
2951
2952 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2953 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2954
2955 sec = find_section (item, section);
2956
2957 if (sec == NULL((void*)0)) {
2958 for (li = item->keys; li != NULL((void*)0); li = li->next) {
2959 g_hash_table_remove (item->main_hash, li->data);
2960 g_free (li->data);
2961 li->data = NULL((void*)0);
2962 }
2963 g_list_free (item->keys);
2964 item->keys = NULL((void*)0);
2965 } else {
2966 for (li = sec->keys; li != NULL((void*)0); li = li->next) {
2967 char *key = li->data;
2968 char *full = g_strdup_printf ("%s/%s",
2969 sec->name, key);
2970 g_hash_table_remove (item->main_hash, full);
2971 g_free (full);
2972 g_free (key);
2973 li->data = NULL((void*)0);
2974 }
2975 g_list_free (sec->keys);
2976 sec->keys = NULL((void*)0);
2977 }
2978 item->modified = TRUE(!(0));
2979}
2980
2981/************************************************************
2982 * Parser: *
2983 ************************************************************/
2984
2985static gboolean G_GNUC_CONST__attribute__ ((__const__))
2986standard_is_boolean (const char * key)
2987{
2988 static GHashTable *bools = NULL((void*)0);
2989
2990 if (bools == NULL((void*)0)) {
2991 bools = g_hash_table_new (g_str_hash, g_str_equal);
2992 g_hash_table_insert (bools,
2993 MATE_DESKTOP_ITEM_NO_DISPLAY"NoDisplay",
2994 MATE_DESKTOP_ITEM_NO_DISPLAY"NoDisplay");
2995 g_hash_table_insert (bools,
2996 MATE_DESKTOP_ITEM_HIDDEN"Hidden",
2997 MATE_DESKTOP_ITEM_HIDDEN"Hidden");
2998 g_hash_table_insert (bools,
2999 MATE_DESKTOP_ITEM_TERMINAL"Terminal",
3000 MATE_DESKTOP_ITEM_TERMINAL"Terminal");
3001 g_hash_table_insert (bools,
3002 MATE_DESKTOP_ITEM_READ_ONLY"ReadOnly",
3003 MATE_DESKTOP_ITEM_READ_ONLY"ReadOnly");
3004 }
3005
3006 return g_hash_table_lookup (bools, key) != NULL((void*)0);
3007}
3008
3009static gboolean G_GNUC_CONST__attribute__ ((__const__))
3010standard_is_strings (const char *key)
3011{
3012 static GHashTable *strings = NULL((void*)0);
3013
3014 if (strings == NULL((void*)0)) {
3015 strings = g_hash_table_new (g_str_hash, g_str_equal);
3016 g_hash_table_insert (strings,
3017 MATE_DESKTOP_ITEM_FILE_PATTERN"FilePattern",
3018 MATE_DESKTOP_ITEM_FILE_PATTERN"FilePattern");
3019 g_hash_table_insert (strings,
3020 MATE_DESKTOP_ITEM_ACTIONS"Actions",
3021 MATE_DESKTOP_ITEM_ACTIONS"Actions");
3022 g_hash_table_insert (strings,
3023 MATE_DESKTOP_ITEM_MIME_TYPE"MimeType",
3024 MATE_DESKTOP_ITEM_MIME_TYPE"MimeType");
3025 g_hash_table_insert (strings,
3026 MATE_DESKTOP_ITEM_PATTERNS"Patterns",
3027 MATE_DESKTOP_ITEM_PATTERNS"Patterns");
3028 g_hash_table_insert (strings,
3029 MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder",
3030 MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder");
3031 }
3032
3033 return g_hash_table_lookup (strings, key) != NULL((void*)0);
3034}
3035
3036/* If no need to cannonize, returns NULL */
3037static char *
3038cannonize (const char *key, const char *value)
3039{
3040 if (standard_is_boolean (key)) {
3041 if (value[0] == 'T' ||
3042 value[0] == 't' ||
3043 value[0] == 'Y' ||
3044 value[0] == 'y' ||
3045 atoi (value) != 0) {
3046 return g_strdup ("true")g_strdup_inline ("true");
3047 } else {
3048 return g_strdup ("false")g_strdup_inline ("false");
3049 }
3050 } else if (standard_is_strings (key)) {
3051 int len = strlen (value);
3052 if (len == 0 || value[len-1] != ';') {
3053 return g_strconcat (value, ";", NULL((void*)0));
3054 }
3055 }
3056 /* XXX: Perhaps we should canonize numeric values as well, but this
3057 * has caused some subtle problems before so it needs to be done
3058 * carefully if at all */
3059 return NULL((void*)0);
3060}
3061
3062static char *
3063decode_string_and_dup (const char *s)
3064{
3065 char *p = g_malloc (strlen (s) + 1);
3066 char *q = p;
3067
3068 do {
3069 if (*s == '\\'){
3070 switch (*(++s)){
3071 case 's':
3072 *p++ = ' ';
3073 break;
3074 case 't':
3075 *p++ = '\t';
3076 break;
3077 case 'n':
3078 *p++ = '\n';
3079 break;
3080 case '\\':
3081 *p++ = '\\';
3082 break;
3083 case 'r':
3084 *p++ = '\r';
3085 break;
3086 default:
3087 *p++ = '\\';
3088 *p++ = *s;
3089 break;
3090 }
3091 } else {
3092 *p++ = *s;
3093 }
3094 } while (*s++);
3095
3096 return q;
3097}
3098
3099static char *
3100escape_string_and_dup (const char *s)
3101{
3102 char *return_value, *p;
3103 const char *q;
3104 int len = 0;
3105
3106 if (s == NULL((void*)0))
3107 return g_strdup("")g_strdup_inline ("");
3108
3109 q = s;
3110 while (*q){
3111 len++;
3112 if (strchr ("\n\r\t\\", *q) != NULL((void*)0))
3113 len++;
3114 q++;
3115 }
3116 return_value = p = (char *) g_malloc (len + 1);
3117 do {
3118 switch (*s){
3119 case '\t':
3120 *p++ = '\\';
3121 *p++ = 't';
3122 break;
3123 case '\n':
3124 *p++ = '\\';
3125 *p++ = 'n';
3126 break;
3127 case '\r':
3128 *p++ = '\\';
3129 *p++ = 'r';
3130 break;
3131 case '\\':
3132 *p++ = '\\';
3133 *p++ = '\\';
3134 break;
3135 default:
3136 *p++ = *s;
3137 }
3138 } while (*s++);
3139 return return_value;
3140}
3141
3142static gboolean
3143check_locale (const char *locale)
3144{
3145 GIConv cd = g_iconv_open ("UTF-8", locale);
3146 if ((GIConv)-1 == cd)
3147 return FALSE(0);
3148 g_iconv_close (cd);
3149 return TRUE(!(0));
3150}
3151
3152static void
3153insert_locales (GHashTable *encodings, char *enc, ...)
3154{
3155 va_list args;
3156 char *s;
3157
3158 va_start (args, enc)__builtin_va_start(args, enc);
3159 for (;;) {
3160 s = va_arg (args, char *)__builtin_va_arg(args, char *);
3161 if (s == NULL((void*)0))
3162 break;
3163 g_hash_table_insert (encodings, s, enc);
3164 }
3165 va_end (args)__builtin_va_end(args);
3166}
3167
3168/* make a standard conversion table from the desktop standard spec */
3169static GHashTable *
3170init_encodings (void)
3171{
3172 GHashTable *encodings = g_hash_table_new (g_str_hash, g_str_equal);
3173
3174 /* "C" is plain ascii */
3175 insert_locales (encodings, "ASCII", "C", NULL((void*)0));
3176
3177 insert_locales (encodings, "ARMSCII-8", "by", NULL((void*)0));
3178 insert_locales (encodings, "BIG5", "zh_TW", NULL((void*)0));
3179 insert_locales (encodings, "CP1251", "be", "bg", NULL((void*)0));
3180 if (check_locale ("EUC-CN")) {
3181 insert_locales (encodings, "EUC-CN", "zh_CN", NULL((void*)0));
3182 } else {
3183 insert_locales (encodings, "GB2312", "zh_CN", NULL((void*)0));
3184 }
3185 insert_locales (encodings, "EUC-JP", "ja", NULL((void*)0));
3186 insert_locales (encodings, "EUC-KR", "ko", NULL((void*)0));
3187 /*insert_locales (encodings, "GEORGIAN-ACADEMY", NULL);*/
3188 insert_locales (encodings, "GEORGIAN-PS", "ka", NULL((void*)0));
3189 insert_locales (encodings, "ISO-8859-1", "br", "ca", "da", "de", "en", "es", "eu", "fi", "fr", "gl", "it", "nl", "wa", "no", "pt", "pt", "sv", NULL((void*)0));
3190 insert_locales (encodings, "ISO-8859-2", "cs", "hr", "hu", "pl", "ro", "sk", "sl", "sq", "sr", NULL((void*)0));
3191 insert_locales (encodings, "ISO-8859-3", "eo", NULL((void*)0));
3192 insert_locales (encodings, "ISO-8859-5", "mk", "sp", NULL((void*)0));
3193 insert_locales (encodings, "ISO-8859-7", "el", NULL((void*)0));
3194 insert_locales (encodings, "ISO-8859-9", "tr", NULL((void*)0));
3195 insert_locales (encodings, "ISO-8859-13", "lt", "lv", "mi", NULL((void*)0));
3196 insert_locales (encodings, "ISO-8859-14", "ga", "cy", NULL((void*)0));
3197 insert_locales (encodings, "ISO-8859-15", "et", NULL((void*)0));
3198 insert_locales (encodings, "KOI8-R", "ru", NULL((void*)0));
3199 insert_locales (encodings, "KOI8-U", "uk", NULL((void*)0));
3200 if (check_locale ("TCVN-5712")) {
3201 insert_locales (encodings, "TCVN-5712", "vi", NULL((void*)0));
3202 } else {
3203 insert_locales (encodings, "TCVN", "vi", NULL((void*)0));
3204 }
3205 insert_locales (encodings, "TIS-620", "th", NULL((void*)0));
3206 /*insert_locales (encodings, "VISCII", NULL);*/
3207
3208 return encodings;
3209}
3210
3211static const char *
3212get_encoding_from_locale (const char *locale)
3213{
3214 char lang[3];
3215 const char *encoding;
3216 static GHashTable *encodings = NULL((void*)0);
3217
3218 if (locale == NULL((void*)0))
3219 return NULL((void*)0);
3220
3221 /* if locale includes encoding, use it */
3222 encoding = strchr (locale, '.');
3223 if (encoding != NULL((void*)0)) {
3224 return encoding+1;
3225 }
3226
3227 if (encodings == NULL((void*)0))
3228 encodings = init_encodings ();
3229
3230 /* first try the entire locale (at this point ll_CC) */
3231 encoding = g_hash_table_lookup (encodings, locale);
3232 if (encoding != NULL((void*)0))
3233 return encoding;
3234
3235 /* Try just the language */
3236 strncpy (lang, locale, 2);
3237 lang[2] = '\0';
3238 return g_hash_table_lookup (encodings, lang);
3239}
3240
3241static Encoding
3242get_encoding (ReadBuf *rb)
3243{
3244 gboolean old_kde = FALSE(0);
3245 char buf [BUFSIZ8192];
3246 gboolean all_valid_utf8 = TRUE(!(0));
3247
3248 while (readbuf_gets (buf, sizeof (buf), rb) != NULL((void*)0)) {
3249 if (strncmp (MATE_DESKTOP_ITEM_ENCODING"Encoding",
3250 buf,
3251 strlen (MATE_DESKTOP_ITEM_ENCODING"Encoding")) == 0) {
3252 char *p = &buf[strlen (MATE_DESKTOP_ITEM_ENCODING"Encoding")];
3253 if (*p == ' ')
3254 p++;
3255 if (*p != '=')
3256 continue;
3257 p++;
3258 if (*p == ' ')
3259 p++;
3260 if (strcmp (p, "UTF-8") == 0) {
3261 return ENCODING_UTF8;
3262 } else if (strcmp (p, "Legacy-Mixed") == 0) {
3263 return ENCODING_LEGACY_MIXED;
3264 } else {
3265 /* According to the spec we're not supposed
3266 * to read a file like this */
3267 return ENCODING_UNKNOWN;
3268 }
3269 } else if (strcmp ("[KDE Desktop Entry]", buf) == 0) {
3270 old_kde = TRUE(!(0));
3271 /* don't break yet, we still want to support
3272 * Encoding even here */
3273 }
3274 if (all_valid_utf8 && ! g_utf8_validate (buf, -1, NULL((void*)0)))
3275 all_valid_utf8 = FALSE(0);
3276 }
3277
3278 if (old_kde)
3279 return ENCODING_LEGACY_MIXED;
3280
3281 /* try to guess by location */
3282 if (rb->uri != NULL((void*)0) && strstr (rb->uri, "mate/apps/") != NULL((void*)0)) {
3283 /* old mate */
3284 return ENCODING_LEGACY_MIXED;
3285 }
3286
3287 /* A dilemma, new KDE files are in UTF-8 but have no Encoding
3288 * info, at this time we really can't tell. The best thing to
3289 * do right now is to just assume UTF-8 if the whole file
3290 * validates as utf8 I suppose */
3291
3292 if (all_valid_utf8)
3293 return ENCODING_UTF8;
3294 else
3295 return ENCODING_LEGACY_MIXED;
3296}
3297
3298static char *
3299decode_string (const char *value, Encoding encoding, const char *locale)
3300{
3301 char *retval = NULL((void*)0);
3302
3303 /* if legacy mixed, then convert */
3304 if (locale != NULL((void*)0) && encoding == ENCODING_LEGACY_MIXED) {
3305 const char *char_encoding = get_encoding_from_locale (locale);
3306 char *utf8_string;
3307 if (char_encoding == NULL((void*)0))
3308 return NULL((void*)0);
3309 if (strcmp (char_encoding, "ASCII") == 0) {
3310 return decode_string_and_dup (value);
3311 }
3312 utf8_string = g_convert (value, -1, "UTF-8", char_encoding,
3313 NULL((void*)0), NULL((void*)0), NULL((void*)0));
3314 if (utf8_string == NULL((void*)0))
3315 return NULL((void*)0);
3316 retval = decode_string_and_dup (utf8_string);
3317 g_free (utf8_string);
3318 return retval;
3319 /* if utf8, then validate */
3320 } else if (locale != NULL((void*)0) && encoding == ENCODING_UTF8) {
3321 if ( ! g_utf8_validate (value, -1, NULL((void*)0)))
3322 /* invalid utf8, ignore this key */
3323 return NULL((void*)0);
3324 return decode_string_and_dup (value);
3325 } else {
3326 /* Meaning this is not a localized string */
3327 return decode_string_and_dup (value);
3328 }
3329}
3330
3331static char *
3332snarf_locale_from_key (const char *key)
3333{
3334 const char *brace;
3335 char *locale, *p;
3336
3337 brace = strchr (key, '[');
3338 if (brace == NULL((void*)0))
3339 return NULL((void*)0);
3340
3341 locale = g_strdup (brace + 1)g_strdup_inline (brace + 1);
3342 if (*locale == '\0') {
3343 g_free (locale);
3344 return NULL((void*)0);
3345 }
3346 p = strchr (locale, ']');
3347 if (p == NULL((void*)0)) {
3348 g_free (locale);
3349 return NULL((void*)0);
3350 }
3351 *p = '\0';
3352 return locale;
3353}
3354
3355static void
3356insert_key (MateDesktopItem *item,
3357 Section *cur_section,
3358 Encoding encoding,
3359 const char *key,
3360 const char *value,
3361 gboolean old_kde,
3362 gboolean no_translations)
3363{
3364 char *k;
3365 char *val;
3366 /* we always store everything in UTF-8 */
3367 if (cur_section == NULL((void*)0) &&
3368 strcmp (key, MATE_DESKTOP_ITEM_ENCODING"Encoding") == 0) {
3369 k = g_strdup (key)g_strdup_inline (key);
3370 val = g_strdup ("UTF-8")g_strdup_inline ("UTF-8");
3371 } else {
3372 char *locale = snarf_locale_from_key (key);
3373 /* If we're ignoring translations */
3374 if (no_translations && locale != NULL((void*)0)) {
3375 g_free (locale);
3376 return;
3377 }
3378 val = decode_string (value, encoding, locale);
3379
3380 /* Ignore this key, it's whacked */
3381 if (val == NULL((void*)0)) {
3382 g_free (locale);
3383 return;
3384 }
3385
3386 g_strchomp (val);
3387
3388 /* For old KDE entries, we can also split by a comma
3389 * on sort order, so convert to semicolons */
3390 if (old_kde &&
3391 cur_section == NULL((void*)0) &&
3392 strcmp (key, MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder") == 0 &&
3393 strchr (val, ';') == NULL((void*)0)) {
3394 int i;
3395 for (i = 0; val[i] != '\0'; i++) {
3396 if (val[i] == ',')
3397 val[i] = ';';
3398 }
3399 }
3400
3401 /* Check some types, not perfect, but catches a lot
3402 * of things */
3403 if (cur_section == NULL((void*)0)) {
3404 char *cannon = cannonize (key, val);
3405 if (cannon != NULL((void*)0)) {
3406 g_free (val);
3407 val = cannon;
3408 }
3409 }
3410
3411 k = g_strdup (key)g_strdup_inline (key);
3412
3413 /* Take care of the language part */
3414 if (locale != NULL((void*)0) &&
3415 strcmp (locale, "C") == 0) {
3416 char *p;
3417 /* Whack C locale */
3418 p = strchr (k, '[');
3419 *p = '\0';
3420 g_free (locale);
3421 } else if (locale != NULL((void*)0)) {
3422 char *p, *brace;
3423
3424 /* Whack the encoding part */
3425 p = strchr (locale, '.');
3426 if (p != NULL((void*)0))
3427 *p = '\0';
3428
3429 if (g_list_find_custom (item->languages, locale,
3430 (GCompareFunc)strcmp) == NULL((void*)0)) {
3431 item->languages = g_list_prepend
3432 (item->languages, locale);
3433 } else {
3434 g_free (locale);
3435 }
3436
3437 /* Whack encoding from encoding in the key */
3438 brace = strchr (k, '[');
3439 p = strchr (brace, '.');
3440 if (p != NULL((void*)0)) {
3441 *p = ']';
3442 *(p+1) = '\0';
3443 }
3444 }
3445 }
3446
3447 if (cur_section == NULL((void*)0)) {
3448 /* only add to list if we haven't seen it before */
3449 if (g_hash_table_lookup (item->main_hash, k) == NULL((void*)0)) {
3450 item->keys = g_list_prepend (item->keys,
3451 g_strdup (k)g_strdup_inline (k));
3452 }
3453 /* later duplicates override earlier ones */
3454 g_hash_table_replace (item->main_hash, k, val);
3455 } else {
3456 char *full = g_strdup_printf
3457 ("%s/%s",
3458 cur_section->name, k);
3459 /* only add to list if we haven't seen it before */
3460 if (g_hash_table_lookup (item->main_hash, full) == NULL((void*)0)) {
3461 cur_section->keys =
3462 g_list_prepend (cur_section->keys, k);
3463 }
3464 /* later duplicates override earlier ones */
3465 g_hash_table_replace (item->main_hash,
3466 full, val);
3467 }
3468}
3469
3470static void
3471setup_type (MateDesktopItem *item, const char *uri)
3472{
3473 const char *type = g_hash_table_lookup (item->main_hash,
3474 MATE_DESKTOP_ITEM_TYPE"Type");
3475 if (type == NULL((void*)0) && uri != NULL((void*)0)) {
3476 char *base = g_path_get_basename (uri);
3477 if (base != NULL((void*)0) &&
3478 strcmp (base, ".directory") == 0) {
3479 /* This gotta be a directory */
3480 g_hash_table_replace (item->main_hash,
3481 g_strdup (MATE_DESKTOP_ITEM_TYPE)g_strdup_inline ("Type"),
3482 g_strdup ("Directory")g_strdup_inline ("Directory"));
3483 item->keys = g_list_prepend
3484 (item->keys, g_strdup (MATE_DESKTOP_ITEM_TYPE)g_strdup_inline ("Type"));
3485 item->type = MATE_DESKTOP_ITEM_TYPE_DIRECTORY;
3486 } else {
3487 item->type = MATE_DESKTOP_ITEM_TYPE_NULL;
3488 }
3489 g_free (base);
3490 } else {
3491 item->type = type_from_string (type);
3492 }
3493}
3494
3495/* fallback to find something suitable for C locale */
3496static char *
3497try_english_key (MateDesktopItem *item, const char *key)
3498{
3499 char *str;
3500 char *locales[] = { "en_US", "en_GB", "en_AU", "en", NULL((void*)0) };
3501 int i;
3502
3503 str = NULL((void*)0);
3504 for (i = 0; locales[i] != NULL((void*)0) && str == NULL((void*)0); i++) {
3505 str = g_strdup (lookup_locale (item, key, locales[i]))g_strdup_inline (lookup_locale (item, key, locales[i]));
3506 }
3507 if (str != NULL((void*)0)) {
3508 /* We need a 7-bit ascii string, so whack all
3509 * above 127 chars */
3510 guchar *p;
3511 for (p = (guchar *)str; *p != '\0'; p++) {
3512 if (*p > 127)
3513 *p = '?';
3514 }
3515 }
3516 return str;
3517}
3518
3519static void
3520sanitize (MateDesktopItem *item, const char *uri)
3521{
3522 const char *type;
3523
3524 type = lookup (item, MATE_DESKTOP_ITEM_TYPE"Type");
3525
3526 /* understand old mate style url exec thingies */
3527 if (type != NULL((void*)0) && strcmp (type, "URL") == 0) {
3528 const char *exec = lookup (item, MATE_DESKTOP_ITEM_EXEC"Exec");
3529 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Link");
3530 if (exec != NULL((void*)0)) {
3531 /* Note, this must be in this order */
3532 set (item, MATE_DESKTOP_ITEM_URL"URL", exec);
3533 set (item, MATE_DESKTOP_ITEM_EXEC"Exec", NULL((void*)0));
3534 }
3535 }
3536
3537 /* we make sure we have Name, Encoding and Version */
3538 if (lookup (item, MATE_DESKTOP_ITEM_NAME"Name") == NULL((void*)0)) {
3539 char *name = try_english_key (item, MATE_DESKTOP_ITEM_NAME"Name");
3540 /* If no name, use the basename */
3541 if (name == NULL((void*)0) && uri != NULL((void*)0))
3542 name = g_path_get_basename (uri);
3543 /* If no uri either, use same default as mate_desktop_item_new */
3544 if (name == NULL((void*)0)) {
3545 /* Translators: the "name" mentioned here is the name of
3546 * an application or a document */
3547 name = g_strdup (_("No name"))g_strdup_inline (((char *) g_dgettext ("mate-desktop", "No name"
)))
;
3548 }
3549 g_hash_table_replace (item->main_hash,
3550 g_strdup (MATE_DESKTOP_ITEM_NAME)g_strdup_inline ("Name"),
3551 name);
3552 item->keys = g_list_prepend
3553 (item->keys, g_strdup (MATE_DESKTOP_ITEM_NAME)g_strdup_inline ("Name"));
3554 }
3555 if (lookup (item, MATE_DESKTOP_ITEM_ENCODING"Encoding") == NULL((void*)0)) {
3556 /* We store everything in UTF-8 so write that down */
3557 g_hash_table_replace (item->main_hash,
3558 g_strdup (MATE_DESKTOP_ITEM_ENCODING)g_strdup_inline ("Encoding"),
3559 g_strdup ("UTF-8")g_strdup_inline ("UTF-8"));
3560 item->keys = g_list_prepend
3561 (item->keys, g_strdup (MATE_DESKTOP_ITEM_ENCODING)g_strdup_inline ("Encoding"));
3562 }
3563 if (lookup (item, MATE_DESKTOP_ITEM_VERSION"Version") == NULL((void*)0)) {
3564 /* this is the version that we follow, so write it down */
3565 g_hash_table_replace (item->main_hash,
3566 g_strdup (MATE_DESKTOP_ITEM_VERSION)g_strdup_inline ("Version"),
3567 g_strdup ("1.0")g_strdup_inline ("1.0"));
3568 item->keys = g_list_prepend
3569 (item->keys, g_strdup (MATE_DESKTOP_ITEM_VERSION)g_strdup_inline ("Version"));
3570 }
3571}
3572
3573enum {
3574 FirstBrace,
3575 OnSecHeader,
3576 IgnoreToEOL,
3577 IgnoreToEOLFirst,
3578 KeyDef,
3579 KeyDefOnKey,
3580 KeyValue
3581};
3582
3583static MateDesktopItem *
3584ditem_load (ReadBuf *rb,
3585 gboolean no_translations,
3586 GError **error)
3587{
3588 int state;
3589 char CharBuffer [1024];
3590 char *next = CharBuffer;
3591 int c;
3592 Encoding encoding;
3593 MateDesktopItem *item;
3594 Section *cur_section = NULL((void*)0);
3595 char *key = NULL((void*)0);
3596 gboolean old_kde = FALSE(0);
3597
3598 encoding = get_encoding (rb);
3599 if (encoding == ENCODING_UNKNOWN) {
3600 /* spec says, don't read this file */
3601 g_set_error (error,
3602 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
3603 MATE_DESKTOP_ITEM_ERROR_UNKNOWN_ENCODING,
3604 _("Unknown encoding of: %s")((char *) g_dgettext ("mate-desktop", "Unknown encoding of: %s"
))
,
3605 rb->uri);
3606 readbuf_close (rb);
3607 return NULL((void*)0);
3608 }
3609
3610 /* Rewind since get_encoding goes through the file */
3611 if (! readbuf_rewind (rb, error)) {
3612 readbuf_close (rb);
3613 /* spec says, don't read this file */
3614 return NULL((void*)0);
3615 }
3616
3617 item = mate_desktop_item_new ();
3618 item->modified = FALSE(0);
3619
3620 /* Note: location and mtime are filled in by the new_from_file
3621 * function since it has those values */
3622
3623#define OVERFLOW (next == &CharBuffer [sizeof(CharBuffer)-1])
3624
3625 state = FirstBrace;
3626 while ((c = readbuf_getc (rb)) != EOF(-1)) {
3627 if (c == '\r') /* Ignore Carriage Return */
3628 continue;
3629
3630 switch (state) {
3631
3632 case OnSecHeader:
3633 if (c == ']' || OVERFLOW) {
3634 *next = '\0';
3635 next = CharBuffer;
3636
3637 /* keys were inserted in reverse */
3638 if (cur_section != NULL((void*)0) &&
3639 cur_section->keys != NULL((void*)0)) {
3640 cur_section->keys = g_list_reverse
3641 (cur_section->keys);
3642 }
3643 if (strcmp (CharBuffer,
3644 "KDE Desktop Entry") == 0) {
3645 /* Main section */
3646 cur_section = NULL((void*)0);
3647 old_kde = TRUE(!(0));
3648 } else if (strcmp (CharBuffer,
3649 "Desktop Entry") == 0) {
3650 /* Main section */
3651 cur_section = NULL((void*)0);
3652 } else {
3653 cur_section = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
3654 cur_section->name =
3655 g_strdup (CharBuffer)g_strdup_inline (CharBuffer);
3656 cur_section->keys = NULL((void*)0);
3657 item->sections = g_list_prepend
3658 (item->sections, cur_section);
3659 }
3660 state = IgnoreToEOL;
3661 } else if (c == '[') {
3662 /* FIXME: probably error out instead of ignoring this */
3663 } else {
3664 *next++ = c;
3665 }
3666 break;
3667
3668 case IgnoreToEOL:
3669 case IgnoreToEOLFirst:
3670 if (c == '\n'){
3671 if (state == IgnoreToEOLFirst)
3672 state = FirstBrace;
3673 else
3674 state = KeyDef;
3675 next = CharBuffer;
3676 }
3677 break;
3678
3679 case FirstBrace:
3680 case KeyDef:
3681 case KeyDefOnKey:
3682 if (c == '#') {
3683 if (state == FirstBrace)
3684 state = IgnoreToEOLFirst;
3685 else
3686 state = IgnoreToEOL;
3687 break;
3688 }
3689
3690 if (c == '[' && state != KeyDefOnKey){
3691 state = OnSecHeader;
3692 next = CharBuffer;
3693 g_free (key);
3694 key = NULL((void*)0);
3695 break;
3696 }
3697 /* On first pass, don't allow dangling keys */
3698 if (state == FirstBrace)
3699 break;
3700
3701 if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
3702 break;
3703
3704 if (c == '\n' || OVERFLOW) { /* Abort Definition */
3705 next = CharBuffer;
3706 state = KeyDef;
3707 break;
3708 }
3709
3710 if (c == '=' || OVERFLOW){
3711 *next = '\0';
3712
3713 g_free (key);
3714 key = g_strdup (CharBuffer)g_strdup_inline (CharBuffer);
3715 state = KeyValue;
3716 next = CharBuffer;
3717 } else {
3718 *next++ = c;
3719 state = KeyDefOnKey;
3720 }
3721 break;
3722
3723 case KeyValue:
3724 if (OVERFLOW || c == '\n'){
3725 *next = '\0';
3726
3727 insert_key (item, cur_section, encoding,
3728 key, CharBuffer, old_kde,
3729 no_translations);
3730
3731 g_free (key);
3732 key = NULL((void*)0);
3733
3734 state = (c == '\n') ? KeyDef : IgnoreToEOL;
3735 next = CharBuffer;
3736 } else {
3737 *next++ = c;
3738 }
3739 break;
3740
3741 } /* switch */
3742
3743 } /* while ((c = getc_unlocked (f)) != EOF) */
3744 if (c == EOF(-1) && state == KeyValue) {
3745 *next = '\0';
3746
3747 insert_key (item, cur_section, encoding,
3748 key, CharBuffer, old_kde,
3749 no_translations);
3750
3751 g_free (key);
3752 key = NULL((void*)0);
3753 }
3754
3755#undef OVERFLOW
3756
3757 /* keys were inserted in reverse */
3758 if (cur_section != NULL((void*)0) &&
3759 cur_section->keys != NULL((void*)0)) {
3760 cur_section->keys = g_list_reverse (cur_section->keys);
3761 }
3762 /* keys were inserted in reverse */
3763 item->keys = g_list_reverse (item->keys);
3764 /* sections were inserted in reverse */
3765 item->sections = g_list_reverse (item->sections);
3766
3767 /* sanitize some things */
3768 sanitize (item, rb->uri);
3769
3770 /* make sure that we set up the type */
3771 setup_type (item, rb->uri);
3772
3773 readbuf_close (rb);
3774
3775 return item;
3776}
3777
3778static void stream_printf (GFileOutputStream *stream,
3779 const char *format, ...) G_GNUC_PRINTF (2, 3)__attribute__((__format__ (__printf__, 2, 3)));
3780
3781static void
3782stream_printf (GFileOutputStream *stream, const char *format, ...)
3783{
3784 va_list args;
3785 gchar *s;
3786
3787 va_start (args, format)__builtin_va_start(args, format);
3788 s = g_strdup_vprintf (format, args);
3789 va_end (args)__builtin_va_end(args);
3790
3791 /* FIXME: what about errors */
3792 g_output_stream_write (G_OUTPUT_STREAM (stream)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((stream)), ((g_output_stream_get_type ()))))))
, s, strlen (s),
3793 NULL((void*)0), NULL((void*)0));
3794 g_free (s);
3795}
3796
3797static void
3798dump_section (MateDesktopItem *item, GFileOutputStream *stream, Section *section)
3799{
3800 GList *li;
3801
3802 stream_printf (stream, "[%s]\n", section->name);
3803 for (li = section->keys; li != NULL((void*)0); li = li->next) {
3804 const char *key = li->data;
3805 char *full = g_strdup_printf ("%s/%s", section->name, key);
3806 const char *value = g_hash_table_lookup (item->main_hash, full);
3807 if (value != NULL((void*)0)) {
3808 char *val = escape_string_and_dup (value);
3809 stream_printf (stream, "%s=%s\n", key, val);
3810 g_free (val);
3811 }
3812 g_free (full);
3813 }
3814}
3815
3816static gboolean
3817ditem_save (MateDesktopItem *item, const char *uri, GError **error)
3818{
3819 GList *li;
3820 GFile *file;
3821 GFileOutputStream *stream;
3822
3823 file = g_file_new_for_uri (uri);
3824 stream = g_file_replace (file, NULL((void*)0), FALSE(0), G_FILE_CREATE_NONE,
3825 NULL((void*)0), error);
3826 if (stream == NULL((void*)0))
3827 return FALSE(0);
3828
3829 stream_printf (stream, "[Desktop Entry]\n");
3830 for (li = item->keys; li != NULL((void*)0); li = li->next) {
3831 const char *key = li->data;
3832 const char *value = g_hash_table_lookup (item->main_hash, key);
3833 if (value != NULL((void*)0)) {
3834 char *val = escape_string_and_dup (value);
3835 stream_printf (stream, "%s=%s\n", key, val);
3836 g_free (val);
3837 }
3838 }
3839
3840 if (item->sections != NULL((void*)0))
3841 stream_printf (stream, "\n");
3842
3843 for (li = item->sections; li != NULL((void*)0); li = li->next) {
3844 Section *section = li->data;
3845
3846 /* Don't write empty sections */
3847 if (section->keys == NULL((void*)0))
3848 continue;
3849
3850 dump_section (item, stream, section);
3851
3852 if (li->next != NULL((void*)0))
3853 stream_printf (stream, "\n");
3854 }
3855
3856 g_object_unref (stream);
3857 g_object_unref (file);
3858
3859 return TRUE(!(0));
3860}
3861
3862static gpointer
3863_mate_desktop_item_copy (gpointer boxed)
3864{
3865 return mate_desktop_item_copy (boxed);
3866}
3867
3868static void
3869_mate_desktop_item_free (gpointer boxed)
3870{
3871 mate_desktop_item_unref (boxed);
3872}
3873
3874GType
3875mate_desktop_item_get_type (void)
3876{
3877 static GType type = 0;
3878
3879 if (type == 0) {
3880 type = g_boxed_type_register_static ("MateDesktopItem",
3881 _mate_desktop_item_copy,
3882 _mate_desktop_item_free);
3883 }
3884
3885 return type;
3886}
3887
3888GQuark
3889mate_desktop_item_error_quark (void)
3890{
3891 static GQuark q = 0;
3892 if (q == 0)
3893 q = g_quark_from_static_string ("mate-desktop-item-error-quark");
3894
3895 return q;
3896}
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-6e323f.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-6e323f.html new file mode 100644 index 0000000..03fea78 --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-6e323f.html @@ -0,0 +1,2013 @@ + + + +mate-languages.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-languages.c
Warning:line 1218, column 3
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-languages.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-languages.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright 2008 Red Hat, Inc,
4 * 2007 William Jon McCann <mccann@jhu.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * Written by : William Jon McCann <mccann@jhu.edu>
20 * Ray Strode <rstrode@redhat.com>
21 */
22
23#include "config.h"
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <string.h>
29#include <errno(*__errno_location ()).h>
30#include <dirent.h>
31#include <locale.h>
32#include <langinfo.h>
33#include <sys/stat.h>
34
35#include <glib.h>
36#include <glib/gi18n.h>
37#include <glib/gstdio.h>
38
39#define MATE_DESKTOP_USE_UNSTABLE_API
40#include "mate-languages.h"
41
42#include <langinfo.h>
43#ifndef __LC_LAST13
44#define __LC_LAST13 13
45#endif
46
47#define ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" ISO_CODES_PREFIX"/usr" "/share/xml/iso-codes"
48#define ISO_CODES_LOCALESDIR"/usr" "/share/locale" ISO_CODES_PREFIX"/usr" "/share/locale"
49
50typedef struct _MateLocale {
51 char *id;
52 char *name;
53 char *language_code;
54 char *territory_code;
55 char *codeset;
56 char *modifier;
57} MateLocale;
58
59static GHashTable *mate_languages_map;
60static GHashTable *mate_territories_map;
61static GHashTable *mate_available_locales_map;
62static GHashTable *mate_language_count_map;
63static GHashTable *mate_territory_count_map;
64
65static char * construct_language_name (const char *language,
66 const char *territory,
67 const char *codeset,
68 const char *modifier);
69
70static gboolean language_name_is_valid (const char *language_name);
71
72static void
73mate_locale_free (MateLocale *locale)
74{
75 if (locale == NULL((void*)0)) {
76 return;
77 }
78
79 g_free (locale->id);
80 g_free (locale->name);
81 g_free (locale->codeset);
82 g_free (locale->modifier);
83 g_free (locale->language_code);
84 g_free (locale->territory_code);
85 g_free (locale);
86}
87
88static char *
89normalize_codeset (const char *codeset)
90{
91 if (codeset == NULL((void*)0))
92 return NULL((void*)0);
93
94 if (g_str_equal (codeset, "UTF-8")(strcmp ((const char *) (codeset), (const char *) ("UTF-8")) ==
0)
||
95 g_str_equal (codeset, "utf8")(strcmp ((const char *) (codeset), (const char *) ("utf8")) ==
0)
)
96 return g_strdup ("UTF-8")g_strdup_inline ("UTF-8");
97
98 return g_strdup (codeset)g_strdup_inline (codeset);
99}
100
101/**
102 * mate_parse_locale:
103 * @locale: a locale string
104 * @language_codep: (out) (allow-none) (transfer full): location to
105 * store the language code, or %NULL
106 * @country_codep: (out) (allow-none) (transfer full): location to
107 * store the country code, or %NULL
108 * @codesetp: (out) (allow-none) (transfer full): location to
109 * store the codeset, or %NULL
110 * @modifierp: (out) (allow-none) (transfer full): location to
111 * store the modifier, or %NULL
112 *
113 * Extracts the various components of a locale string of the form
114 * [language[_country][.codeset][@modifier]]. See
115 * http://en.wikipedia.org/wiki/Locale.
116 *
117 * Return value: %TRUE if parsing was successful.
118 *
119 * Since: 1.22
120 */
121gboolean
122mate_parse_locale (const char *locale,
123 char **language_codep,
124 char **country_codep,
125 char **codesetp,
126 char **modifierp)
127{
128 static GRegex *re = NULL((void*)0);
129 GMatchInfo *match_info;
130 gboolean res;
131 gchar *normalized_codeset = NULL((void*)0);
132 gchar *normalized_name = NULL((void*)0);
133 gboolean retval;
134
135 match_info = NULL((void*)0);
136 retval = FALSE(0);
137
138 if (re == NULL((void*)0)) {
139 GError *error = NULL((void*)0);
140 re = g_regex_new ("^(?P<language>[^_.@[:space:]]+)"
141 "(_(?P<territory>[[:upper:]]+))?"
142 "(\\.(?P<codeset>[-_0-9a-zA-Z]+))?"
143 "(@(?P<modifier>[[:ascii:]]+))?$",
144 0, 0, &error);
145 if (re == NULL((void*)0)) {
146 g_warning ("%s", error->message);
147 g_error_free (error);
148 goto out;
149 }
150 }
151
152 if (!g_regex_match (re, locale, 0, &match_info) ||
153 g_match_info_is_partial_match (match_info)) {
154 g_warning ("locale '%s' isn't valid\n", locale);
155 goto out;
156 }
157
158 res = g_match_info_matches (match_info);
159 if (! res) {
160 g_warning ("Unable to parse locale: %s", locale);
161 goto out;
162 }
163
164 retval = TRUE(!(0));
165
166 if (language_codep != NULL((void*)0)) {
167 *language_codep = g_match_info_fetch_named (match_info, "language");
168 }
169
170 if (country_codep != NULL((void*)0)) {
171 *country_codep = g_match_info_fetch_named (match_info, "territory");
172
173 if (*country_codep != NULL((void*)0) &&
174 *country_codep[0] == '\0') {
175 g_free (*country_codep);
176 *country_codep = NULL((void*)0);
177 }
178 }
179
180 if (codesetp != NULL((void*)0)) {
181 *codesetp = g_match_info_fetch_named (match_info, "codeset");
182
183 if (*codesetp != NULL((void*)0) &&
184 *codesetp[0] == '\0') {
185 g_free (*codesetp);
186 *codesetp = NULL((void*)0);
187 }
188 }
189
190 if (modifierp != NULL((void*)0)) {
191 *modifierp = g_match_info_fetch_named (match_info, "modifier");
192
193 if (*modifierp != NULL((void*)0) &&
194 *modifierp[0] == '\0') {
195 g_free (*modifierp);
196 *modifierp = NULL((void*)0);
197 }
198 }
199
200 if (codesetp != NULL((void*)0) && *codesetp != NULL((void*)0)) {
201 normalized_codeset = normalize_codeset (*codesetp);
202 normalized_name = construct_language_name (language_codep ? *language_codep : NULL((void*)0),
203 country_codep ? *country_codep : NULL((void*)0),
204 normalized_codeset,
205 modifierp ? *modifierp : NULL((void*)0));
206
207 if (language_name_is_valid (normalized_name)) {
208 g_free (*codesetp);
209 *codesetp = normalized_codeset;
210 } else {
211 g_free (normalized_codeset);
212 }
213 g_free (normalized_name);
214 }
215
216 out:
217 g_match_info_free (match_info);
218
219 return retval;
220}
221
222static char *
223construct_language_name (const char *language,
224 const char *territory,
225 const char *codeset,
226 const char *modifier)
227{
228 char *name;
229
230 g_assert (language != NULL && language[0] != 0)do { if (language != ((void*)0) && language[0] != 0) ;
else g_assertion_message_expr ("MateDesktop", "mate-languages.c"
, 230, ((const char*) (__func__)), "language != NULL && language[0] != 0"
); } while (0)
;
231 g_assert (territory == NULL || territory[0] != 0)do { if (territory == ((void*)0) || territory[0] != 0) ; else
g_assertion_message_expr ("MateDesktop", "mate-languages.c",
231, ((const char*) (__func__)), "territory == NULL || territory[0] != 0"
); } while (0)
;
232 g_assert (codeset == NULL || codeset[0] != 0)do { if (codeset == ((void*)0) || codeset[0] != 0) ; else g_assertion_message_expr
("MateDesktop", "mate-languages.c", 232, ((const char*) (__func__
)), "codeset == NULL || codeset[0] != 0"); } while (0)
;
233 g_assert (modifier == NULL || modifier[0] != 0)do { if (modifier == ((void*)0) || modifier[0] != 0) ; else g_assertion_message_expr
("MateDesktop", "mate-languages.c", 233, ((const char*) (__func__
)), "modifier == NULL || modifier[0] != 0"); } while (0)
;
234
235 name = g_strdup_printf ("%s%s%s%s%s%s%s",
236 language,
237 territory != NULL((void*)0)? "_" : "",
238 territory != NULL((void*)0)? territory : "",
239 codeset != NULL((void*)0)? "." : "",
240 codeset != NULL((void*)0)? codeset : "",
241 modifier != NULL((void*)0)? "@" : "",
242 modifier != NULL((void*)0)? modifier : "");
243
244 return name;
245}
246
247/**
248 * mate_normalize_locale:
249 * @locale: a locale string
250 *
251 * Gets the normalized locale string in the form
252 * [language[_country][.codeset][@modifier]] for @name.
253 *
254 * Return value: (transfer full): normalized locale string. Caller
255 * takes ownership.
256 *
257 * Since: 1.22
258 */
259char *
260mate_normalize_locale (const char *locale)
261{
262 char *normalized_name;
263 gboolean valid;
264 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
265 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
266 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset = NULL((void*)0);
267 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *modifier = NULL((void*)0);
268
269 if (locale[0] == '\0') {
270 return NULL((void*)0);
271 }
272
273 valid = mate_parse_locale (locale,
274 &language_code,
275 &territory_code,
276 &codeset, &modifier);
277 if (!valid)
278 return NULL((void*)0);
279
280 normalized_name = construct_language_name (language_code,
281 territory_code,
282 codeset, modifier);
283 return normalized_name;
284}
285
286static gboolean
287language_name_is_valid (const char *language_name)
288{
289 gboolean is_valid;
290 int lc_type_id = LC_MESSAGES5;
291 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
292
293 old_locale = g_strdup (setlocale (lc_type_id, NULL))g_strdup_inline (setlocale (lc_type_id, ((void*)0)));
294 is_valid = setlocale (lc_type_id, language_name) != NULL((void*)0);
295 setlocale (lc_type_id, old_locale);
296
297 return is_valid;
298}
299
300static void
301language_name_get_codeset_details (const char *language_name,
302 char **pcodeset,
303 gboolean *is_utf8)
304{
305 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
306 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset = NULL((void*)0);
307
308 old_locale = g_strdup (setlocale (LC_CTYPE, NULL))g_strdup_inline (setlocale (0, ((void*)0)));
309
310 if (setlocale (LC_CTYPE0, language_name) == NULL((void*)0))
311 return;
312
313 codeset = nl_langinfo (CODESETCODESET);
314
315 if (pcodeset != NULL((void*)0)) {
316 *pcodeset = g_strdup (codeset)g_strdup_inline (codeset);
317 }
318
319 if (is_utf8 != NULL((void*)0)) {
320 codeset = normalize_codeset (codeset);
321
322 *is_utf8 = strcmp (codeset, "UTF-8") == 0;
323 }
324
325 setlocale (LC_CTYPE0, old_locale);
326}
327
328static gboolean
329locale_dir_has_mo_files (const gchar* path)
330{
331 GDir *dir;
332 const char *name;
333 gboolean has_translations;
334
335 has_translations = FALSE(0);
336 dir = g_dir_open (path, 0, NULL((void*)0));
337
338 if (dir == NULL((void*)0)) {
339 goto out;
340 }
341
342 do {
343 name = g_dir_read_name (dir);
344
345 if (name == NULL((void*)0)) {
346 break;
347 }
348
349 if (g_str_has_suffix (name, ".mo")(__builtin_constant_p (".mo")? __extension__ ({ const char * const
__str = (name); const char * const __suffix = (".mo"); gboolean
__result = (0); if (__str == ((void*)0) || __suffix == ((void
*)0)) __result = (g_str_has_suffix) (__str, __suffix); else {
const size_t __str_len = strlen (((__str) + !(__str))); const
size_t __suffix_len = strlen (((__suffix) + !(__suffix))); if
(__str_len >= __suffix_len) __result = memcmp (__str + __str_len
- __suffix_len, ((__suffix) + !(__suffix)), __suffix_len) ==
0; } __result; }) : (g_str_has_suffix) (name, ".mo") )
) {
350 has_translations = TRUE(!(0));
351 break;
352 }
353 } while (name != NULL((void*)0));
354 g_dir_close (dir);
355
356 out:
357 return has_translations;
358}
359
360/**
361 * mate_language_has_translations:
362 * @code: an ISO 639 code string
363 *
364 * Returns %TRUE if there are translations for language @code.
365 *
366 * Return value: %TRUE if there are translations for language @code.
367 *
368 * Since: 1.22
369 */
370gboolean
371mate_language_has_translations (const char *code)
372{
373 gboolean has_translations;
374 gchar *path;
375
376 path = g_build_filename (MATELOCALEDIR"/usr/share/locale", code, "LC_MESSAGES", NULL((void*)0));
377 has_translations = locale_dir_has_mo_files (path);
378
379 if (!has_translations) {
380 const char * const *system_data_dirs;
381 int i = 0;
382
383 system_data_dirs = g_get_system_data_dirs ();
384 while ((system_data_dirs[i] != NULL((void*)0)) && (has_translations == FALSE(0))) {
385 g_free (path);
386 path = g_build_filename (system_data_dirs[i], "locale", code, "LC_MESSAGES", NULL((void*)0));
387 has_translations = locale_dir_has_mo_files (path);
388 ++i;
389 }
390 }
391
392 g_free (path);
393 return has_translations;
394}
395
396static gboolean
397add_locale (const char *language_name,
398 gboolean utf8_only)
399{
400 MateLocale *locale;
401 MateLocale *old_locale;
402 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *name = NULL((void*)0);
403 gboolean is_utf8 = FALSE(0);
404 gboolean valid = FALSE(0);
405
406 g_return_val_if_fail (language_name != NULL, FALSE)do { if ((language_name != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "language_name != NULL"
); return ((0)); } } while (0)
;
407 g_return_val_if_fail (*language_name != '\0', FALSE)do { if ((*language_name != '\0')) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "*language_name != '\\0'"
); return ((0)); } } while (0)
;
408
409 language_name_get_codeset_details (language_name, NULL((void*)0), &is_utf8);
410
411 if (is_utf8) {
412 name = g_strdup (language_name)g_strdup_inline (language_name);
413 } else if (utf8_only) {
414
415 if (strchr (language_name, '.'))
416 return FALSE(0);
417
418 /* If the locale name has no dot, assume that its
419 * encoding part is missing and try again after adding
420 * ".UTF-8". This catches locale names like "de_DE".
421 */
422 name = g_strdup_printf ("%s.UTF-8", language_name);
423
424 language_name_get_codeset_details (name, NULL((void*)0), &is_utf8);
425 if (!is_utf8)
426 return FALSE(0);
427 } else {
428 name = g_strdup (language_name)g_strdup_inline (language_name);
429 }
430
431 if (!language_name_is_valid (name)) {
432 g_debug ("Ignoring '%s' as a locale, since it's invalid", name);
433 return FALSE(0);
434 }
435
436 locale = g_new0 (MateLocale, 1)((MateLocale *) g_malloc0_n ((1), sizeof (MateLocale)));
437 valid = mate_parse_locale (name,
438 &locale->language_code,
439 &locale->territory_code,
440 &locale->codeset,
441 &locale->modifier);
442 if (!valid) {
443 mate_locale_free (locale);
444 return FALSE(0);
445 }
446
447 locale->id = construct_language_name (locale->language_code, locale->territory_code,
448 NULL((void*)0), locale->modifier);
449 locale->name = construct_language_name (locale->language_code, locale->territory_code,
450 locale->codeset, locale->modifier);
451
452 if (!mate_language_has_translations (locale->name) &&
453 !mate_language_has_translations (locale->id) &&
454 !mate_language_has_translations (locale->language_code) &&
455 utf8_only) {
456 g_debug ("Ignoring '%s' as a locale, since it lacks translations", locale->name);
457 mate_locale_free (locale);
458 return FALSE(0);
459 }
460
461 if (!utf8_only) {
462 g_free (locale->id);
463 locale->id = g_strdup (locale->name)g_strdup_inline (locale->name);
464 }
465
466 old_locale = g_hash_table_lookup (mate_available_locales_map, locale->id);
467 if (old_locale != NULL((void*)0)) {
468 if (strlen (old_locale->name) > strlen (locale->name)) {
469 mate_locale_free (locale);
470 return FALSE(0);
471 }
472 }
473
474 g_hash_table_insert (mate_available_locales_map, g_strdup (locale->id)g_strdup_inline (locale->id), locale);
475
476 return TRUE(!(0));
477}
478
479static int
480select_dirs (const struct dirent *dirent)
481{
482 int result = 0;
483
484 if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0) {
485 mode_t mode = 0;
486
487#ifdef _DIRENT_HAVE_D_TYPE
488 if (dirent->d_type != DT_UNKNOWNDT_UNKNOWN && dirent->d_type != DT_LNKDT_LNK) {
489 mode = DTTOIF (dirent->d_type)((dirent->d_type) << 12);
490 } else
491#endif
492 {
493 struct stat st;
494 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *path = NULL((void*)0);
495
496 path = g_build_filename (MATELOCALEDIR"/usr/share/locale", dirent->d_name, NULL((void*)0));
497 if (g_statstat (path, &st) == 0) {
498 mode = st.st_mode;
499 }
500 }
501
502 result = S_ISDIR (mode)((((mode)) & 0170000) == (0040000));
503 }
504
505 return result;
506}
507
508static gboolean
509collect_locales_from_directory (void)
510{
511 gboolean found_locales = FALSE(0);
512 struct dirent **dirents;
513 int ndirents;
514 int cnt;
515
516 ndirents = scandir (MATELOCALEDIR"/usr/share/locale", &dirents, select_dirs, alphasort);
517
518 for (cnt = 0; cnt < ndirents; ++cnt) {
519 if (add_locale (dirents[cnt]->d_name, TRUE(!(0))))
520 found_locales = TRUE(!(0));
521 }
522
523 if (ndirents > 0) {
524 free (dirents);
525 }
526 return found_locales;
527}
528
529static gboolean
530collect_locales_from_localebin (void)
531{
532 gboolean found_locales = FALSE(0);
533 const gchar *argv[] = { "locale", "-a", NULL((void*)0) };
534 gchar **linep;
535 g_auto (GStrv)__attribute__((cleanup(glib_auto_cleanup_GStrv))) GStrv lines = NULL((void*)0);
536 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) gchar *output = NULL((void*)0);
537
538 if (g_spawn_sync (NULL((void*)0), (gchar **) argv, NULL((void*)0),
539 G_SPAWN_SEARCH_PATH|G_SPAWN_STDERR_TO_DEV_NULL,
540 NULL((void*)0), NULL((void*)0), &output, NULL((void*)0), NULL((void*)0), NULL((void*)0)) == FALSE(0))
541 return FALSE(0);
542
543 g_return_val_if_fail (output != NULL, FALSE)do { if ((output != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "output != NULL"
); return ((0)); } } while (0)
;
544
545 lines = g_strsplit (output, "\n", 0);
546 if (lines) {
547 linep = lines;
548 while (*linep) {
549 if (*linep[0] && add_locale (*linep, TRUE(!(0))))
550 found_locales = TRUE(!(0));
551 linep++;
552 }
553 }
554
555 return found_locales;
556}
557
558static void
559fill_count_map (GHashTable *count_map,
560 const char *code)
561{
562 int count;
563 gpointer pointer;
564
565 if (code == NULL((void*)0))
566 return;
567
568 if ((pointer = g_hash_table_lookup (count_map, code)) != NULL((void*)0))
569 count = GPOINTER_TO_INT (pointer)((gint) (glong) (pointer)) + 1;
570 else
571 count = 1;
572
573 g_hash_table_insert (count_map, g_strdup (code)g_strdup_inline (code), GINT_TO_POINTER (count)((gpointer) (glong) (count)));
574}
575
576static void
577count_languages_and_territories (void)
578{
579 gpointer value;
580 GHashTableIter iter;
581
582 mate_language_count_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
583 mate_territory_count_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
584
585 g_hash_table_iter_init (&iter, mate_available_locales_map);
586 while (g_hash_table_iter_next (&iter, NULL((void*)0), &value)) {
587 MateLocale *locale = (MateLocale *) value;
588 fill_count_map (mate_language_count_map, locale->language_code);
589 fill_count_map (mate_territory_count_map, locale->territory_code);
590 }
591}
592
593static void
594collect_locales (void)
595{
596 gboolean found_localebin_locales = FALSE(0);
597 gboolean found_dir_locales = FALSE(0);
598
599 if (mate_available_locales_map == NULL((void*)0)) {
600 mate_available_locales_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) mate_locale_free);
601 }
602
603 found_localebin_locales = collect_locales_from_localebin ();
604
605 found_dir_locales = collect_locales_from_directory ();
606
607 if (!(found_localebin_locales || found_dir_locales)) {
608 g_warning ("Could not read list of available locales from libc, "
609 "guessing possible locales from available translations, "
610 "but list may be incomplete!");
611 }
612
613 count_languages_and_territories ();
614}
615
616static gint
617get_language_count (const char *language)
618{
619 gint count = 0;
620 gpointer pointer;
621
622 if (mate_language_count_map == NULL((void*)0))
623 collect_locales ();
624
625 if ((pointer = g_hash_table_lookup (mate_language_count_map, language)) != NULL((void*)0))
626 count = GPOINTER_TO_INT (pointer)((gint) (glong) (pointer));
627
628 return count;
629}
630
631static gboolean
632is_unique_language (const char *language)
633{
634 return get_language_count (language) == 1;
635}
636
637static gint
638get_territory_count (const char *territory)
639{
640 gint count = 0;
641 gpointer pointer;
642
643 if (mate_territory_count_map == NULL((void*)0))
644 collect_locales ();
645
646 if ((pointer = g_hash_table_lookup (mate_territory_count_map, territory)) != NULL((void*)0))
647 count = GPOINTER_TO_INT (pointer)((gint) (glong) (pointer));
648
649 return count;
650}
651
652static gboolean
653is_unique_territory (const char *territory)
654{
655 return get_territory_count (territory) == 1;
656}
657
658static gboolean
659is_fallback_language (const char *code)
660{
661 const char *fallback_language_names[] = { "C", "POSIX", NULL((void*)0) };
662 int i;
663
664 for (i = 0; fallback_language_names[i] != NULL((void*)0); i++) {
665 if (strcmp (code, fallback_language_names[i]) == 0) {
666 return TRUE(!(0));
667 }
668 }
669
670 return FALSE(0);
671}
672
673static const char *
674get_language (const char *code)
675{
676 const char *name;
677 int len;
678
679 g_assert (code != NULL)do { if (code != ((void*)0)) ; else g_assertion_message_expr (
"MateDesktop", "mate-languages.c", 679, ((const char*) (__func__
)), "code != NULL"); } while (0)
;
680
681 if (is_fallback_language (code)) {
682 return "Unspecified";
683 }
684
685 len = strlen (code);
686 if (len != 2 && len != 3) {
687 return NULL((void*)0);
688 }
689
690 name = (const char *) g_hash_table_lookup (mate_languages_map, code);
691
692 return name;
693}
694
695static char *
696get_first_item_in_semicolon_list (const char *list)
697{
698 char **items;
699 char *item;
700
701 /* Some entries in iso codes have multiple values, separated
702 * by semicolons. Not really sure which one to pick, so
703 * we just arbitrarily pick the first one.
704 */
705 items = g_strsplit (list, "; ", 2);
706
707 item = g_strdup (items[0])g_strdup_inline (items[0]);
708 g_strfreev (items);
709
710 return item;
711}
712
713static char *
714capitalize_utf8_string (const char *str)
715{
716 char first[8] = { 0 };
717
718 if (!str)
719 return NULL((void*)0);
720
721 g_unichar_to_utf8 (g_unichar_totitle (g_utf8_get_char (str)), first);
722
723 return g_strconcat (first, g_utf8_offset_to_pointer (str, 1), NULL((void*)0));
724}
725
726static char *
727get_translated_language (const char *code,
728 const char *locale)
729{
730 const char *language;
731 char *name;
732
733 language = get_language (code);
734
735 name = NULL((void*)0);
736 if (language != NULL((void*)0)) {
737 const char *translated_name;
738 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
739
740 if (locale != NULL((void*)0)) {
741 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL))g_strdup_inline (setlocale (5, ((void*)0)));
742 setlocale (LC_MESSAGES5, locale);
743 }
744
745 if (is_fallback_language (code)) {
746 name = g_strdup (_("Unspecified"))g_strdup_inline (gettext ("Unspecified"));
747 } else {
748 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *tmp = NULL((void*)0);
749 translated_name = dgettext ("iso_639", language);
750 tmp = get_first_item_in_semicolon_list (translated_name);
751 name = capitalize_utf8_string (tmp);
752 }
753
754 if (locale != NULL((void*)0)) {
755 setlocale (LC_MESSAGES5, old_locale);
756 }
757 }
758
759 return name;
760}
761
762static const char *
763get_territory (const char *code)
764{
765 const char *name;
766 int len;
767
768 g_assert (code != NULL)do { if (code != ((void*)0)) ; else g_assertion_message_expr (
"MateDesktop", "mate-languages.c", 768, ((const char*) (__func__
)), "code != NULL"); } while (0)
;
769
770 len = strlen (code);
771 if (len != 2 && len != 3) {
772 return NULL((void*)0);
773 }
774
775 name = (const char *) g_hash_table_lookup (mate_territories_map, code);
776
777 return name;
778}
779
780static char *
781get_translated_territory (const char *code,
782 const char *locale)
783{
784 const char *territory;
785 char *name;
786
787 territory = get_territory (code);
788
789 name = NULL((void*)0);
790 if (territory != NULL((void*)0)) {
791 const char *translated_territory;
792 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
793 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *tmp = NULL((void*)0);
794
795 if (locale != NULL((void*)0)) {
796 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL))g_strdup_inline (setlocale (5, ((void*)0)));
797 setlocale (LC_MESSAGES5, locale);
798 }
799
800 translated_territory = dgettext ("iso_3166", territory);
801 tmp = get_first_item_in_semicolon_list (translated_territory);
802 name = capitalize_utf8_string (tmp);
803
804 if (locale != NULL((void*)0)) {
805 setlocale (LC_MESSAGES5, old_locale);
806 }
807 }
808
809 return name;
810}
811
812static void
813languages_parse_start_tag (GMarkupParseContext *ctx,
814 const char *element_name,
815 const char **attr_names,
816 const char **attr_values,
817 gpointer user_data,
818 GError **error)
819{
820 const char *ccode_longB;
821 const char *ccode_longT;
822 const char *ccode;
823 const char *ccode_id;
824 const char *lang_name;
825
826 if (! (g_str_equal (element_name, "iso_639_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_639_entry"
)) == 0)
|| g_str_equal (element_name, "iso_639_3_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_639_3_entry"
)) == 0)
)
827 || attr_names == NULL((void*)0) || attr_values == NULL((void*)0)) {
828 return;
829 }
830
831 ccode = NULL((void*)0);
832 ccode_longB = NULL((void*)0);
833 ccode_longT = NULL((void*)0);
834 ccode_id = NULL((void*)0);
835 lang_name = NULL((void*)0);
836
837 while (*attr_names && *attr_values) {
838 if (g_str_equal (*attr_names, "iso_639_1_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_1_code"
)) == 0)
) {
839 /* skip if empty */
840 if (**attr_values) {
841 if (strlen (*attr_values) != 2) {
842 return;
843 }
844 ccode = *attr_values;
845 }
846 } else if (g_str_equal (*attr_names, "iso_639_2B_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_2B_code"
)) == 0)
) {
847 /* skip if empty */
848 if (**attr_values) {
849 if (strlen (*attr_values) != 3) {
850 return;
851 }
852 ccode_longB = *attr_values;
853 }
854 } else if (g_str_equal (*attr_names, "iso_639_2T_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_2T_code"
)) == 0)
) {
855 /* skip if empty */
856 if (**attr_values) {
857 if (strlen (*attr_values) != 3) {
858 return;
859 }
860 ccode_longT = *attr_values;
861 }
862 } else if (g_str_equal (*attr_names, "id")(strcmp ((const char *) (*attr_names), (const char *) ("id"))
== 0)
) {
863 /* skip if empty */
864 if (**attr_values) {
865 if (strlen (*attr_values) != 2 &&
866 strlen (*attr_values) != 3) {
867 return;
868 }
869 ccode_id = *attr_values;
870 }
871 } else if (g_str_equal (*attr_names, "name")(strcmp ((const char *) (*attr_names), (const char *) ("name"
)) == 0)
) {
872 lang_name = *attr_values;
873 }
874
875 ++attr_names;
876 ++attr_values;
877 }
878
879 if (lang_name == NULL((void*)0)) {
880 return;
881 }
882
883 if (ccode != NULL((void*)0)) {
884 g_hash_table_insert (mate_languages_map,
885 g_strdup (ccode)g_strdup_inline (ccode),
886 g_strdup (lang_name)g_strdup_inline (lang_name));
887 }
888 if (ccode_longB != NULL((void*)0)) {
889 g_hash_table_insert (mate_languages_map,
890 g_strdup (ccode_longB)g_strdup_inline (ccode_longB),
891 g_strdup (lang_name)g_strdup_inline (lang_name));
892 }
893 if (ccode_longT != NULL((void*)0)) {
894 g_hash_table_insert (mate_languages_map,
895 g_strdup (ccode_longT)g_strdup_inline (ccode_longT),
896 g_strdup (lang_name)g_strdup_inline (lang_name));
897 }
898 if (ccode_id != NULL((void*)0)) {
899 g_hash_table_insert (mate_languages_map,
900 g_strdup (ccode_id)g_strdup_inline (ccode_id),
901 g_strdup (lang_name)g_strdup_inline (lang_name));
902 }
903}
904
905static void
906territories_parse_start_tag (GMarkupParseContext *ctx,
907 const char *element_name,
908 const char **attr_names,
909 const char **attr_values,
910 gpointer user_data,
911 GError **error)
912{
913 const char *acode_2;
914 const char *acode_3;
915 const char *ncode;
916 const char *territory_common_name;
917 const char *territory_name;
918
919 if (! g_str_equal (element_name, "iso_3166_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_3166_entry"
)) == 0)
|| attr_names == NULL((void*)0) || attr_values == NULL((void*)0)) {
920 return;
921 }
922
923 acode_2 = NULL((void*)0);
924 acode_3 = NULL((void*)0);
925 ncode = NULL((void*)0);
926 territory_common_name = NULL((void*)0);
927 territory_name = NULL((void*)0);
928
929 while (*attr_names && *attr_values) {
930 if (g_str_equal (*attr_names, "alpha_2_code")(strcmp ((const char *) (*attr_names), (const char *) ("alpha_2_code"
)) == 0)
) {
931 /* skip if empty */
932 if (**attr_values) {
933 if (strlen (*attr_values) != 2) {
934 return;
935 }
936 acode_2 = *attr_values;
937 }
938 } else if (g_str_equal (*attr_names, "alpha_3_code")(strcmp ((const char *) (*attr_names), (const char *) ("alpha_3_code"
)) == 0)
) {
939 /* skip if empty */
940 if (**attr_values) {
941 if (strlen (*attr_values) != 3) {
942 return;
943 }
944 acode_3 = *attr_values;
945 }
946 } else if (g_str_equal (*attr_names, "numeric_code")(strcmp ((const char *) (*attr_names), (const char *) ("numeric_code"
)) == 0)
) {
947 /* skip if empty */
948 if (**attr_values) {
949 if (strlen (*attr_values) != 3) {
950 return;
951 }
952 ncode = *attr_values;
953 }
954 } else if (g_str_equal (*attr_names, "common_name")(strcmp ((const char *) (*attr_names), (const char *) ("common_name"
)) == 0)
) {
955 /* skip if empty */
956 if (**attr_values) {
957 territory_common_name = *attr_values;
958 }
959 } else if (g_str_equal (*attr_names, "name")(strcmp ((const char *) (*attr_names), (const char *) ("name"
)) == 0)
) {
960 territory_name = *attr_values;
961 }
962
963 ++attr_names;
964 ++attr_values;
965 }
966
967 if (territory_common_name != NULL((void*)0)) {
968 territory_name = territory_common_name;
969 }
970
971 if (territory_name == NULL((void*)0)) {
972 return;
973 }
974
975 if (acode_2 != NULL((void*)0)) {
976 g_hash_table_insert (mate_territories_map,
977 g_strdup (acode_2)g_strdup_inline (acode_2),
978 g_strdup (territory_name)g_strdup_inline (territory_name));
979 }
980 if (acode_3 != NULL((void*)0)) {
981 g_hash_table_insert (mate_territories_map,
982 g_strdup (acode_3)g_strdup_inline (acode_3),
983 g_strdup (territory_name)g_strdup_inline (territory_name));
984 }
985 if (ncode != NULL((void*)0)) {
986 g_hash_table_insert (mate_territories_map,
987 g_strdup (ncode)g_strdup_inline (ncode),
988 g_strdup (territory_name)g_strdup_inline (territory_name));
989 }
990}
991
992static void
993languages_variant_init (const char *variant)
994{
995 gboolean res;
996 gsize buf_len;
997 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *buf = NULL((void*)0);
998 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *filename = NULL((void*)0);
999 g_autoptr (GError)__attribute__((cleanup(glib_autoptr_cleanup_GError))) GError_autoptr error = NULL((void*)0);
1000
1001 bindtextdomain (variant, ISO_CODES_LOCALESDIR"/usr" "/share/locale");
1002 bind_textdomain_codeset (variant, "UTF-8");
1003
1004 error = NULL((void*)0);
1005 filename = g_strdup_printf (ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/%s.xml", variant);
1006 res = g_file_get_contents (filename,
1007 &buf,
1008 &buf_len,
1009 &error);
1010 if (res) {
1011 g_autoptr (GMarkupParseContext)__attribute__((cleanup(glib_autoptr_cleanup_GMarkupParseContext
))) GMarkupParseContext_autoptr
ctx = NULL((void*)0);
1012 GMarkupParser parser = { languages_parse_start_tag, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0) };
1013
1014 ctx = g_markup_parse_context_new (&parser, 0, NULL((void*)0), NULL((void*)0));
1015
1016 error = NULL((void*)0);
1017 res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
1018
1019 if (! res) {
1020 g_warning ("Failed to parse '%s': %s\n",
1021 filename,
1022 error->message);
1023 }
1024 } else {
1025 g_warning ("Failed to load '%s': %s\n",
1026 filename,
1027 error->message);
1028 }
1029}
1030
1031static void
1032languages_init (void)
1033{
1034 if (mate_languages_map)
1035 return;
1036
1037 mate_languages_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1038
1039 languages_variant_init ("iso_639");
1040 languages_variant_init ("iso_639_3");
1041}
1042
1043static void
1044territories_init (void)
1045{
1046 gboolean res;
1047 gsize buf_len;
1048 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *buf = NULL((void*)0);
1049 g_autoptr (GError)__attribute__((cleanup(glib_autoptr_cleanup_GError))) GError_autoptr error = NULL((void*)0);
1050
1051 if (mate_territories_map)
1052 return;
1053
1054 bindtextdomain ("iso_3166", ISO_CODES_LOCALESDIR"/usr" "/share/locale");
1055 bind_textdomain_codeset ("iso_3166", "UTF-8");
1056
1057 mate_territories_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1058
1059 error = NULL((void*)0);
1060 res = g_file_get_contents (ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1061 &buf,
1062 &buf_len,
1063 &error);
1064 if (res) {
1065 g_autoptr (GMarkupParseContext)__attribute__((cleanup(glib_autoptr_cleanup_GMarkupParseContext
))) GMarkupParseContext_autoptr
ctx = NULL((void*)0);
1066 GMarkupParser parser = { territories_parse_start_tag, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0) };
1067
1068 ctx = g_markup_parse_context_new (&parser, 0, NULL((void*)0), NULL((void*)0));
1069
1070 error = NULL((void*)0);
1071 res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
1072
1073 if (! res) {
1074 g_warning ("Failed to parse '%s': %s\n",
1075 ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1076 error->message);
1077 }
1078 } else {
1079 g_warning ("Failed to load '%s': %s\n",
1080 ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1081 error->message);
1082 }
1083}
1084
1085/**
1086 * mate_get_language_from_locale:
1087 * @locale: a locale string
1088 * @translation: (allow-none): a locale string
1089 *
1090 * Gets the language description for @locale. If @translation is
1091 * provided the returned string is translated accordingly.
1092 *
1093 * Return value: (transfer full): the language description. Caller
1094 * takes ownership.
1095 *
1096 * Since: 1.22
1097 */
1098char *
1099mate_get_language_from_locale (const char *locale,
1100 const char *translation)
1101{
1102 GString *full_language;
1103 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
1104 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
1105 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset_code = NULL((void*)0);
1106 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *langinfo_codeset = NULL((void*)0);
1107 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_language = NULL((void*)0);
1108 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_territory = NULL((void*)0);
1109 gboolean is_utf8 = TRUE(!(0));
1110
1111 g_return_val_if_fail (locale != NULL, NULL)do { if ((locale != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "locale != NULL"
); return (((void*)0)); } } while (0)
;
1112 g_return_val_if_fail (*locale != '\0', NULL)do { if ((*locale != '\0')) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "*locale != '\\0'"
); return (((void*)0)); } } while (0)
;
1113
1114 full_language = g_string_new (NULL((void*)0));
1115
1116 languages_init ();
1117 territories_init ();
1118
1119 mate_parse_locale (locale,
1120 &language_code,
1121 &territory_code,
1122 &codeset_code,
1123 NULL((void*)0));
1124
1125 if (language_code == NULL((void*)0)) {
1126 goto out;
1127 }
1128
1129 translated_language = get_translated_language (language_code, translation);
1130 if (translated_language == NULL((void*)0)) {
1131 goto out;
1132 }
1133
1134 full_language = g_string_append (full_language, translated_language)(__builtin_constant_p (translated_language) ? __extension__ (
{ const char * const __val = (translated_language); g_string_append_len_inline
(full_language, __val, (__val != ((void*)0)) ? (gssize) strlen
(((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(full_language, translated_language, (gssize) -1))
;
1135
1136 if (is_unique_language (language_code)) {
1137 goto out;
1138 }
1139
1140 if (territory_code != NULL((void*)0)) {
1141 translated_territory = get_translated_territory (territory_code, translation);
1142 }
1143 if (translated_territory != NULL((void*)0)) {
1144 g_string_append_printf (full_language,
1145 " (%s)",
1146 translated_territory);
1147 }
1148
1149 language_name_get_codeset_details (locale, &langinfo_codeset, &is_utf8);
1150
1151 if (codeset_code == NULL((void*)0) && langinfo_codeset != NULL((void*)0)) {
1152 codeset_code = g_strdup (langinfo_codeset)g_strdup_inline (langinfo_codeset);
1153 }
1154
1155 if (!is_utf8 && codeset_code) {
1156 g_string_append_printf (full_language,
1157 " [%s]",
1158 codeset_code);
1159 }
1160
1161 out:
1162 if (full_language->len == 0) {
1163 g_string_free (full_language, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(full_language), ((!(0)))) : g_string_free_and_steal (full_language
)) : (g_string_free) ((full_language), ((!(0)))))
;
1164 return NULL((void*)0);
1165 }
1166
1167 return g_string_free (full_language, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((full_language
), ((0))) : g_string_free_and_steal (full_language)) : (g_string_free
) ((full_language), ((0))))
;
1168}
1169
1170/**
1171 * mate_get_country_from_locale:
1172 * @locale: a locale string
1173 * @translation: (allow-none): a locale string
1174 *
1175 * Gets the country description for @locale. If @translation is
1176 * provided the returned string is translated accordingly.
1177 *
1178 * Return value: (transfer full): the country description. Caller
1179 * takes ownership.
1180 *
1181 * Since: 1.22
1182 */
1183char *
1184mate_get_country_from_locale (const char *locale,
1185 const char *translation)
1186{
1187 GString *full_name;
1188 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
1189 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
1190 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset_code = NULL((void*)0);
1191 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *langinfo_codeset = NULL((void*)0);
1192 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_language = NULL((void*)0);
1193 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_territory = NULL((void*)0);
1194 gboolean is_utf8 = TRUE(!(0));
1195
1196 g_return_val_if_fail (locale != NULL, NULL)do { if ((locale != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "locale != NULL"
); return (((void*)0)); } } while (0)
;
1197 g_return_val_if_fail (*locale != '\0', NULL)do { if ((*locale != '\0')) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "*locale != '\\0'"
); return (((void*)0)); } } while (0)
;
1198
1199 full_name = g_string_new (NULL((void*)0));
1200
1201 languages_init ();
1202 territories_init ();
1203
1204 mate_parse_locale (locale,
1205 &language_code,
1206 &territory_code,
1207 &codeset_code,
1208 NULL((void*)0));
1209
1210 if (territory_code == NULL((void*)0)) {
1211 goto out;
1212 }
1213
1214 translated_territory = get_translated_territory (territory_code, translation);
1215 g_string_append (full_name, translated_territory)(__builtin_constant_p (translated_territory) ? __extension__ (
{ const char * const __val = (translated_territory); g_string_append_len_inline
(full_name, __val, (__val != ((void*)0)) ? (gssize) strlen (
((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(full_name, translated_territory, (gssize) -1))
;
1216
1217 if (is_unique_territory (territory_code)) {
1218 goto out;
This statement is never executed
1219 }
1220
1221 if (language_code != NULL((void*)0)) {
1222 translated_language = get_translated_language (language_code, translation);
1223 }
1224 if (translated_language != NULL((void*)0)) {
1225 g_string_append_printf (full_name,
1226 " (%s)",
1227 translated_language);
1228 }
1229
1230 language_name_get_codeset_details (translation, &langinfo_codeset, &is_utf8);
1231
1232 if (codeset_code == NULL((void*)0) && langinfo_codeset != NULL((void*)0)) {
1233 codeset_code = g_strdup (langinfo_codeset)g_strdup_inline (langinfo_codeset);
1234 }
1235
1236 if (!is_utf8 && codeset_code) {
1237 g_string_append_printf (full_name,
1238 " [%s]",
1239 codeset_code);
1240 }
1241
1242 out:
1243 if (full_name->len == 0) {
1244 g_string_free (full_name, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(full_name), ((!(0)))) : g_string_free_and_steal (full_name))
: (g_string_free) ((full_name), ((!(0)))))
;
1245 return NULL((void*)0);
1246 }
1247
1248 return g_string_free (full_name, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((full_name
), ((0))) : g_string_free_and_steal (full_name)) : (g_string_free
) ((full_name), ((0))))
;
1249}
1250
1251/**
1252 * mate_get_all_locales:
1253 *
1254 * Gets all locales.
1255 *
1256 * Return value: (array zero-terminated=1) (element-type utf8) (transfer full):
1257 * a newly allocated %NULL-terminated string array containing the
1258 * all locales. Free with g_strfreev().
1259 *
1260 * Since: 1.22
1261 */
1262char **
1263mate_get_all_locales (void)
1264{
1265 GHashTableIter iter;
1266 gpointer key, value;
1267 GPtrArray *array;
1268
1269 if (mate_available_locales_map == NULL((void*)0)) {
1270 collect_locales ();
1271 }
1272
1273 array = g_ptr_array_new ();
1274 g_hash_table_iter_init (&iter, mate_available_locales_map);
1275 while (g_hash_table_iter_next (&iter, &key, &value)) {
1276 MateLocale *locale;
1277
1278 locale = (MateLocale *) value;
1279
1280 g_ptr_array_add (array, g_strdup (locale->name)g_strdup_inline (locale->name));
1281 }
1282 g_ptr_array_add (array, NULL((void*)0));
1283
1284 return (char **) g_ptr_array_free (array, FALSE(0));
1285}
1286
1287/**
1288 * mate_get_language_from_code:
1289 * @code: an ISO 639 code string
1290 * @translation: (allow-none): a locale string
1291 *
1292 * Gets the language name for @code. If @locale is provided the
1293 * returned string is translated accordingly.
1294 *
1295 * Return value: (transfer full): the language name. Caller takes
1296 * ownership.
1297 *
1298 * Since: 1.22
1299 */
1300char *
1301mate_get_language_from_code (const char *code,
1302 const char *translation)
1303{
1304 g_return_val_if_fail (code != NULL, NULL)do { if ((code != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "code != NULL");
return (((void*)0)); } } while (0)
;
1305
1306 languages_init ();
1307
1308 return get_translated_language (code, translation);
1309}
1310
1311/**
1312 * mate_get_country_from_code:
1313 * @code: an ISO 3166 code string
1314 * @translation: (allow-none): a locale string
1315 *
1316 * Gets the country name for @code. If @locale is provided the
1317 * returned string is translated accordingly.
1318 *
1319 * Return value: (transfer full): the country name. Caller takes
1320 * ownership.
1321 *
1322 * Since: 1.22
1323 */
1324char *
1325mate_get_country_from_code (const char *code,
1326 const char *translation)
1327{
1328 g_return_val_if_fail (code != NULL, NULL)do { if ((code != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "code != NULL");
return (((void*)0)); } } while (0)
;
1329
1330 territories_init ();
1331
1332 return get_translated_territory (code, translation);
1333}
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-8fac16.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-8fac16.html new file mode 100644 index 0000000..dae0731 --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-8fac16.html @@ -0,0 +1,4693 @@ + + + +mate-desktop-item.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-desktop-item.c
Warning:line 3120, column 9
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-desktop-item.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-desktop-item.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* mate-desktop-item.c - MATE Desktop File Representation
3
4 Copyright (C) 1999, 2000 Red Hat Inc.
5 Copyright (C) 2001 Sid Vicious
6 All rights reserved.
7
8 This file is part of the Mate Library.
9
10 Developed by Elliot Lee <sopwith@redhat.com> and Sid Vicious
11
12 The Mate Library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Library General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
16
17 The Mate Library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Library General Public License for more details.
21
22 You should have received a copy of the GNU Library General Public
23 License along with the Mate Library; see the file COPYING.LIB. If not,
24 write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 Boston, MA 02110-1301, USA. */
26/*
27 @NOTATION@
28 */
29
30#include "config.h"
31
32#include <limits.h>
33#include <ctype.h>
34#include <stdio.h>
35#include <glib.h>
36#include <sys/types.h>
37#include <dirent.h>
38#include <unistd.h>
39#include <time.h>
40#include <string.h>
41#include <glib/gi18n-lib.h>
42#include <locale.h>
43#include <stdlib.h>
44
45#include <gio/gio.h>
46
47#ifdef HAVE_STARTUP_NOTIFICATION
48#define SN_API_NOT_YET_FROZEN
49#include <libsn/sn.h>
50#include <gdk/gdk.h>
51#include <gdk/gdkx.h>
52#include <gtk/gtk.h>
53#endif
54
55#define MATE_DESKTOP_USE_UNSTABLE_API
56#undef MATE_DISABLE_DEPRECATED
57#include <mate-desktop-item.h>
58#include <mate-desktop-utils.h>
59
60#include "private.h"
61
62struct _MateDesktopItem {
63 int refcount;
64
65 /* all languages used */
66 GList *languages;
67
68 MateDesktopItemType type;
69
70 /* `modified' means that the ditem has been
71 * modified since the last save. */
72 gboolean modified;
73
74 /* Keys of the main section only */
75 GList *keys;
76
77 GList *sections;
78
79 /* This includes ALL keys, including
80 * other sections, separated by '/' */
81 GHashTable *main_hash;
82
83 char *location;
84
85 gint64 mtime;
86
87 guint32 launch_time;
88};
89
90/* If mtime is set to this, set_location won't update mtime,
91 * this is to be used internally only. */
92#define DONT_UPDATE_MTIME((gint64)-2) ((gint64)-2)
93
94typedef struct {
95 char *name;
96 GList *keys;
97} Section;
98
99typedef enum {
100 ENCODING_UNKNOWN,
101 ENCODING_UTF8,
102 ENCODING_LEGACY_MIXED
103} Encoding;
104
105/*
106 * IO reading utils, that look like the libc buffered io stuff
107 */
108
109#define READ_BUF_SIZE(32 * 1024) (32 * 1024)
110
111typedef struct {
112 GFile *file;
113 GFileInputStream *stream;
114 char *uri;
115 char *buf;
116 gboolean buf_needs_free;
117 gboolean past_first_read;
118 gboolean eof;
119 guint64 size;
120 gsize pos;
121} ReadBuf;
122
123static MateDesktopItem *ditem_load (ReadBuf *rb,
124 gboolean no_translations,
125 GError **error);
126static gboolean ditem_save (MateDesktopItem *item,
127 const char *uri,
128 GError **error);
129
130static void mate_desktop_item_set_location_gfile (MateDesktopItem *item,
131 GFile *file);
132
133static MateDesktopItem *mate_desktop_item_new_from_gfile (GFile *file,
134 MateDesktopItemLoadFlags flags,
135 GError **error);
136
137static int
138readbuf_getc (ReadBuf *rb)
139{
140 if (rb->eof)
141 return EOF(-1);
142
143 if (rb->size == 0 ||
144 rb->pos == rb->size) {
145 gssize bytes_read;
146
147 if (rb->stream == NULL((void*)0))
148 bytes_read = 0;
149 else
150 bytes_read = g_input_stream_read (G_INPUT_STREAM (rb->stream)((((GInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((rb->stream)), ((g_input_stream_get_type ()))))))
,
151 rb->buf,
152 READ_BUF_SIZE(32 * 1024),
153 NULL((void*)0), NULL((void*)0));
154
155 /* FIXME: handle errors other than EOF */
156 if (bytes_read <= 0) {
157 rb->eof = TRUE(!(0));
158 return EOF(-1);
159 }
160
161 if (rb->size != 0)
162 rb->past_first_read = TRUE(!(0));
163 rb->size = bytes_read;
164 rb->pos = 0;
165
166 }
167
168 return (guchar) rb->buf[rb->pos++];
169}
170
171/* Note, does not include the trailing \n */
172static char *
173readbuf_gets (char *buf, gsize bufsize, ReadBuf *rb)
174{
175 int c;
176 gsize pos;
177
178 g_return_val_if_fail (buf != NULL, NULL)do { if ((buf != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "buf != NULL"); return
(((void*)0)); } } while (0)
;
179 g_return_val_if_fail (rb != NULL, NULL)do { if ((rb != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "rb != NULL"); return
(((void*)0)); } } while (0)
;
180
181 pos = 0;
182 buf[0] = '\0';
183
184 do {
185 c = readbuf_getc (rb);
186 if (c == EOF(-1) || c == '\n')
187 break;
188 buf[pos++] = c;
189 } while (pos < bufsize-1);
190
191 if (c == EOF(-1) && pos == 0)
192 return NULL((void*)0);
193
194 buf[pos++] = '\0';
195
196 return buf;
197}
198
199static ReadBuf *
200readbuf_open (GFile *file, GError **error)
201{
202 GError *local_error;
203 GFileInputStream *stream;
204 char *uri;
205 ReadBuf *rb;
206
207 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
208
209 uri = g_file_get_uri (file);
210 local_error = NULL((void*)0);
211 stream = g_file_read (file, NULL((void*)0), &local_error);
212
213 if (stream == NULL((void*)0)) {
214 g_set_error (error,
215 /* FIXME: better errors */
216 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
217 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
218 _("Error reading file '%s': %s")((char *) g_dgettext ("mate-desktop", "Error reading file '%s': %s"
))
,
219 uri, local_error->message);
220 g_error_free (local_error);
221 g_free (uri);
222 return NULL((void*)0);
223 }
224
225 rb = g_new0 (ReadBuf, 1)((ReadBuf *) g_malloc0_n ((1), sizeof (ReadBuf)));
226 rb->stream = stream;
227 rb->file = g_file_dup (file);
228 rb->uri = uri;
229 rb->buf = g_malloc (READ_BUF_SIZE(32 * 1024));
230 rb->buf_needs_free = TRUE(!(0));
231 /* rb->past_first_read = FALSE; */
232 /* rb->eof = FALSE; */
233 /* rb->size = 0; */
234 /* rb->pos = 0; */
235
236 return rb;
237}
238
239static ReadBuf *
240readbuf_new_from_string (const char *uri, const char *string, gssize length)
241{
242 ReadBuf *rb;
243
244 g_return_val_if_fail (string != NULL, NULL)do { if ((string != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "string != NULL"
); return (((void*)0)); } } while (0)
;
245 g_return_val_if_fail (length >= 0, NULL)do { if ((length >= 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "length >= 0"
); return (((void*)0)); } } while (0)
;
246
247 rb = g_new0 (ReadBuf, 1)((ReadBuf *) g_malloc0_n ((1), sizeof (ReadBuf)));
248 /* rb->file = NULL; */
249 /* rb->stream = NULL; */
250 rb->uri = g_strdup (uri)g_strdup_inline (uri);
251 rb->buf = (char *) string;
252 /* rb->buf_needs_free = FALSE; */
253 /* rb->past_first_read = FALSE; */
254 /* rb->eof = FALSE; */
255 rb->size = length;
256 /* rb->pos = 0; */
257
258 return rb;
259}
260
261static gboolean
262readbuf_rewind (ReadBuf *rb, GError **error)
263{
264 GError *local_error;
265
266 rb->eof = FALSE(0);
267 rb->pos = 0;
268
269 if (!rb->past_first_read)
270 return TRUE(!(0));
271
272 rb->size = 0;
273
274 if (g_seekable_seek (G_SEEKABLE (rb->stream)((((GSeekable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((rb->stream)), ((g_seekable_get_type ()))))))
,
275 0, G_SEEK_SET, NULL((void*)0), NULL((void*)0)))
276 return TRUE(!(0));
277
278 g_object_unref (rb->stream);
279 local_error = NULL((void*)0);
280 rb->stream = g_file_read (rb->file, NULL((void*)0), &local_error);
281
282 if (rb->stream == NULL((void*)0)) {
283 g_set_error (
284 error, MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
285 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
286 _("Error rewinding file '%s': %s")((char *) g_dgettext ("mate-desktop", "Error rewinding file '%s': %s"
))
,
287 rb->uri, local_error->message);
288 g_error_free (local_error);
289
290 return FALSE(0);
291 }
292
293 return TRUE(!(0));
294}
295
296static void
297readbuf_close (ReadBuf *rb)
298{
299 if (rb->stream != NULL((void*)0))
300 g_object_unref (rb->stream);
301 if (rb->file != NULL((void*)0))
302 g_object_unref (rb->file);
303 g_free (rb->uri);
304 if (rb->buf_needs_free)
305 g_free (rb->buf);
306 g_free (rb);
307}
308
309static MateDesktopItemType
310type_from_string (const char *type)
311{
312 if (!type)
313 return MATE_DESKTOP_ITEM_TYPE_NULL;
314
315 switch (type [0]) {
316 case 'A':
317 if (!strcmp (type, "Application"))
318 return MATE_DESKTOP_ITEM_TYPE_APPLICATION;
319 break;
320 case 'L':
321 if (!strcmp (type, "Link"))
322 return MATE_DESKTOP_ITEM_TYPE_LINK;
323 break;
324 case 'F':
325 if (!strcmp (type, "FSDevice"))
326 return MATE_DESKTOP_ITEM_TYPE_FSDEVICE;
327 break;
328 case 'M':
329 if (!strcmp (type, "MimeType"))
330 return MATE_DESKTOP_ITEM_TYPE_MIME_TYPE;
331 break;
332 case 'D':
333 if (!strcmp (type, "Directory"))
334 return MATE_DESKTOP_ITEM_TYPE_DIRECTORY;
335 break;
336 case 'S':
337 if (!strcmp (type, "Service"))
338 return MATE_DESKTOP_ITEM_TYPE_SERVICE;
339
340 else if (!strcmp (type, "ServiceType"))
341 return MATE_DESKTOP_ITEM_TYPE_SERVICE_TYPE;
342 break;
343 default:
344 break;
345 }
346
347 return MATE_DESKTOP_ITEM_TYPE_OTHER;
348}
349
350/**
351 * mate_desktop_item_new:
352 *
353 * Creates a MateDesktopItem object. The reference count on the returned value is set to '1'.
354 *
355 * Returns: The new MateDesktopItem
356 */
357MateDesktopItem *
358mate_desktop_item_new (void)
359{
360 MateDesktopItem *retval;
361
362 _mate_desktop_init_i18n ();
363
364 retval = g_new0 (MateDesktopItem, 1)((MateDesktopItem *) g_malloc0_n ((1), sizeof (MateDesktopItem
)))
;
365
366 retval->refcount++;
367
368 retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
369 (GDestroyNotify) g_free,
370 (GDestroyNotify) g_free);
371
372 /* These are guaranteed to be set */
373 mate_desktop_item_set_string (retval,
374 MATE_DESKTOP_ITEM_NAME"Name",
375 /* Translators: the "name" mentioned
376 * here is the name of an application or
377 * a document */
378 _("No name")((char *) g_dgettext ("mate-desktop", "No name")));
379 mate_desktop_item_set_string (retval,
380 MATE_DESKTOP_ITEM_ENCODING"Encoding",
381 "UTF-8");
382 mate_desktop_item_set_string (retval,
383 MATE_DESKTOP_ITEM_VERSION"Version",
384 "1.0");
385
386 retval->launch_time = 0;
387
388 return retval;
389}
390
391static Section *
392dup_section (Section *sec)
393{
394 GList *li;
395 Section *retval = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
396
397 retval->name = g_strdup (sec->name)g_strdup_inline (sec->name);
398
399 retval->keys = g_list_copy (sec->keys);
400 for (li = retval->keys; li != NULL((void*)0); li = li->next)
401 li->data = g_strdup (li->data)g_strdup_inline (li->data);
402
403 return retval;
404}
405
406static void
407copy_string_hash (gpointer key, gpointer value, gpointer user_data)
408{
409 GHashTable *copy = user_data;
410 g_hash_table_replace (copy,
411 g_strdup (key)g_strdup_inline (key),
412 g_strdup (value)g_strdup_inline (value));
413}
414
415/**
416 * mate_desktop_item_copy:
417 * @item: The item to be copied
418 *
419 * Creates a copy of a MateDesktopItem. The new copy has a refcount of 1.
420 * Note: Section stack is NOT copied.
421 *
422 * Returns: The new copy
423 */
424MateDesktopItem *
425mate_desktop_item_copy (const MateDesktopItem *item)
426{
427 GList *li;
428 MateDesktopItem *retval;
429
430 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
431 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
432
433 retval = mate_desktop_item_new ();
434
435 retval->type = item->type;
436 retval->modified = item->modified;
437 retval->location = g_strdup (item->location)g_strdup_inline (item->location);
438 retval->mtime = item->mtime;
439 retval->launch_time = item->launch_time;
440
441 /* Languages */
442 retval->languages = g_list_copy (item->languages);
443 for (li = retval->languages; li != NULL((void*)0); li = li->next)
444 li->data = g_strdup (li->data)g_strdup_inline (li->data);
445
446 /* Keys */
447 retval->keys = g_list_copy (item->keys);
448 for (li = retval->keys; li != NULL((void*)0); li = li->next)
449 li->data = g_strdup (li->data)g_strdup_inline (li->data);
450
451 /* Sections */
452 retval->sections = g_list_copy (item->sections);
453 for (li = retval->sections; li != NULL((void*)0); li = li->next)
454 li->data = dup_section (li->data);
455
456 retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
457 (GDestroyNotify) g_free,
458 (GDestroyNotify) g_free);
459
460 g_hash_table_foreach (item->main_hash,
461 copy_string_hash,
462 retval->main_hash);
463
464 return retval;
465}
466
467static void
468read_sort_order (MateDesktopItem *item, GFile *dir)
469{
470 GFile *child;
471 char buf[BUFSIZ8192];
472 GString *str;
473 ReadBuf *rb;
474
475 child = g_file_get_child (dir, ".order");
476
477 rb = readbuf_open (child, NULL((void*)0));
478 g_object_unref (child);
479
480 if (rb == NULL((void*)0))
481 return;
482
483 str = NULL((void*)0);
484 while (readbuf_gets (buf, sizeof (buf), rb) != NULL((void*)0)) {
485 if (str == NULL((void*)0))
486 str = g_string_new (buf);
487 else
488 g_string_append (str, buf)(__builtin_constant_p (buf) ? __extension__ ({ const char * const
__val = (buf); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, buf, (gssize) -1
))
;
489 g_string_append_c (str, ';')g_string_append_c_inline (str, ';');
490 }
491 readbuf_close (rb);
492 if (str != NULL((void*)0)) {
493 mate_desktop_item_set_string (item, MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder",
494 str->str);
495 g_string_free (str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(str), ((!(0)))) : g_string_free_and_steal (str)) : (g_string_free
) ((str), ((!(0)))))
;
496 }
497}
498
499static MateDesktopItem *
500make_fake_directory (GFile *dir)
501{
502 MateDesktopItem *item;
503 GFile *child;
504
505 item = mate_desktop_item_new ();
506 mate_desktop_item_set_entry_type (item,
507 MATE_DESKTOP_ITEM_TYPE_DIRECTORY);
508
509 item->mtime = DONT_UPDATE_MTIME((gint64)-2); /* it doesn't exist, we know that */
510 child = g_file_get_child (dir, ".directory");
511 mate_desktop_item_set_location_gfile (item, child);
512 item->mtime = 0;
513 g_object_unref (child);
514
515 read_sort_order (item, dir);
516
517 return item;
518}
519
520/**
521 * mate_desktop_item_new_from_file:
522 * @file: The filename or directory path to load the MateDesktopItem from
523 * @flags: Flags to influence the loading process
524 *
525 * This function loads 'file' and turns it into a MateDesktopItem.
526 *
527 * Returns: The newly loaded item.
528 */
529MateDesktopItem *
530mate_desktop_item_new_from_file (const char *file,
531 MateDesktopItemLoadFlags flags,
532 GError **error)
533{
534 MateDesktopItem *retval;
535 GFile *gfile;
536
537 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
538
539 gfile = g_file_new_for_path (file);
540 retval = mate_desktop_item_new_from_gfile (gfile, flags, error);
541 g_object_unref (gfile);
542
543 return retval;
544}
545
546/**
547 * mate_desktop_item_new_from_uri:
548 * @uri: URI to load the MateDesktopItem from
549 * @flags: Flags to influence the loading process
550 *
551 * This function loads 'uri' and turns it into a MateDesktopItem.
552 *
553 * Returns: The newly loaded item.
554 */
555MateDesktopItem *
556mate_desktop_item_new_from_uri (const char *uri,
557 MateDesktopItemLoadFlags flags,
558 GError **error)
559{
560 MateDesktopItem *retval;
561 GFile *file;
562
563 g_return_val_if_fail (uri != NULL, NULL)do { if ((uri != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "uri != NULL"); return
(((void*)0)); } } while (0)
;
564
565 file = g_file_new_for_uri (uri);
566 retval = mate_desktop_item_new_from_gfile (file, flags, error);
567 g_object_unref (file);
568
569 return retval;
570}
571
572static MateDesktopItem *
573mate_desktop_item_new_from_gfile (GFile *file,
574 MateDesktopItemLoadFlags flags,
575 GError **error)
576{
577 MateDesktopItem *retval;
578 GFile *subfn;
579 GFileInfo *info;
580 GFileType type;
581 GFile *parent;
582 gint64 mtime = 0;
583 ReadBuf *rb;
584
585 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
586
587 info = g_file_query_info (file,
588 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type"","G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
589 G_FILE_QUERY_INFO_NONE, NULL((void*)0), error);
590 if (info == NULL((void*)0))
591 return NULL((void*)0);
592
593 type = g_file_info_get_file_type (info);
594
595 if (type != G_FILE_TYPE_REGULAR && type != G_FILE_TYPE_DIRECTORY) {
596 char *uri;
597
598 uri = g_file_get_uri (file);
599 g_set_error (error,
600 /* FIXME: better errors */
601 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
602 MATE_DESKTOP_ITEM_ERROR_INVALID_TYPE,
603 _("File '%s' is not a regular file or directory.")((char *) g_dgettext ("mate-desktop", "File '%s' is not a regular file or directory."
))
,
604 uri);
605
606 g_free (uri);
607 g_object_unref (info);
608
609 return NULL((void*)0);
610 }
611
612 mtime = g_file_info_get_attribute_uint64 (info,
613 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
614
615 g_object_unref (info);
616
617 if (type == G_FILE_TYPE_DIRECTORY) {
618 GFile *child;
619 GFileInfo *child_info;
620
621 child = g_file_get_child (file, ".directory");
622 child_info = g_file_query_info (child,
623 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
624 G_FILE_QUERY_INFO_NONE,
625 NULL((void*)0), NULL((void*)0));
626
627 if (child_info == NULL((void*)0)) {
628 g_object_unref (child);
629
630 if (flags & MATE_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS) {
631 return NULL((void*)0);
632 } else {
633 return make_fake_directory (file);
634 }
635 }
636
637 mtime = g_file_info_get_attribute_uint64 (child_info,
638 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
639 g_object_unref (child_info);
640
641 subfn = child;
642 } else {
643 subfn = g_file_dup (file);
644 }
645
646 rb = readbuf_open (subfn, error);
647
648 if (rb == NULL((void*)0)) {
649 g_object_unref (subfn);
650 return NULL((void*)0);
651 }
652
653 retval = ditem_load (rb,
654 (flags & MATE_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS) != 0,
655 error);
656
657 if (retval == NULL((void*)0)) {
658 g_object_unref (subfn);
659 return NULL((void*)0);
660 }
661
662 if (flags & MATE_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS &&
663 ! mate_desktop_item_exists (retval)) {
664 mate_desktop_item_unref (retval);
665 g_object_unref (subfn);
666 return NULL((void*)0);
667 }
668
669 retval->mtime = DONT_UPDATE_MTIME((gint64)-2);
670 mate_desktop_item_set_location_gfile (retval, subfn);
671 retval->mtime = mtime;
672
673 parent = g_file_get_parent (file);
674 if (parent != NULL((void*)0)) {
675 read_sort_order (retval, parent);
676 g_object_unref (parent);
677 }
678
679 g_object_unref (subfn);
680
681 return retval;
682}
683
684/**
685 * mate_desktop_item_new_from_string:
686 * @string: string to load the MateDesktopItem from
687 * @length: length of string, or -1 to use strlen
688 * @flags: Flags to influence the loading process
689 * @error: place to put errors
690 *
691 * This function turns the contents of the string into a MateDesktopItem.
692 *
693 * Returns: The newly loaded item.
694 */
695MateDesktopItem *
696mate_desktop_item_new_from_string (const char *uri,
697 const char *string,
698 gssize length,
699 MateDesktopItemLoadFlags flags,
700 GError **error)
701{
702 MateDesktopItem *retval;
703 ReadBuf *rb;
704
705 g_return_val_if_fail (string != NULL, NULL)do { if ((string != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "string != NULL"
); return (((void*)0)); } } while (0)
;
706 g_return_val_if_fail (length >= -1, NULL)do { if ((length >= -1)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "length >= -1"
); return (((void*)0)); } } while (0)
;
707
708 if (length == -1) {
709 length = strlen (string);
710 }
711
712 rb = readbuf_new_from_string (uri, string, length);
713
714 retval = ditem_load (rb,
715 (flags & MATE_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS) != 0,
716 error);
717
718 if (retval == NULL((void*)0)) {
719 return NULL((void*)0);
720 }
721
722 /* FIXME: Sort order? */
723
724 return retval;
725}
726
727static char *
728lookup_desktop_file_in_data_dir (const char *desktop_file,
729 const char *data_dir)
730{
731 char *path;
732
733 path = g_build_filename (data_dir, "applications", desktop_file, NULL((void*)0));
734 if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
735 g_free (path);
736 return NULL((void*)0);
737 }
738 return path;
739}
740
741static char *
742file_from_basename (const char *basename)
743{
744 const char * const *system_data_dirs;
745 const char *user_data_dir;
746 char *retval;
747 int i;
748
749 user_data_dir = g_get_user_data_dir ();
750 system_data_dirs = g_get_system_data_dirs ();
751
752 if ((retval = lookup_desktop_file_in_data_dir (basename, user_data_dir))) {
753 return retval;
754 }
755 for (i = 0; system_data_dirs[i]; i++) {
756 if ((retval = lookup_desktop_file_in_data_dir (basename, system_data_dirs[i]))) {
757 return retval;
758 }
759 }
760 return NULL((void*)0);
761}
762
763/**
764 * mate_desktop_item_new_from_basename:
765 * @basename: The basename of the MateDesktopItem to load.
766 * @flags: Flags to influence the loading process
767 *
768 * This function loads 'basename' from a system data directory and
769 * returns its MateDesktopItem.
770 *
771 * Returns: The newly loaded item.
772 */
773MateDesktopItem *
774mate_desktop_item_new_from_basename (const char *basename,
775 MateDesktopItemLoadFlags flags,
776 GError **error)
777{
778 MateDesktopItem *retval;
779 char *file;
780
781 g_return_val_if_fail (basename != NULL, NULL)do { if ((basename != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "basename != NULL"
); return (((void*)0)); } } while (0)
;
782
783 if (!(file = file_from_basename (basename))) {
784 g_set_error (error,
785 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
786 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
787 _("Cannot find file '%s'")((char *) g_dgettext ("mate-desktop", "Cannot find file '%s'"
))
,
788 basename);
789 return NULL((void*)0);
790 }
791
792 retval = mate_desktop_item_new_from_file (file, flags, error);
793 g_free (file);
794
795 return retval;
796}
797
798/**
799 * mate_desktop_item_save:
800 * @item: A desktop item
801 * @under: A new uri (location) for this #MateDesktopItem
802 * @force: Save even if it wasn't modified
803 * @error: #GError return
804 *
805 * Writes the specified item to disk. If the 'under' is NULL, the original
806 * location is used. It sets the location of this entry to point to the
807 * new location.
808 *
809 * Returns: boolean. %TRUE if the file was saved, %FALSE otherwise
810 */
811gboolean
812mate_desktop_item_save (MateDesktopItem *item,
813 const char *under,
814 gboolean force,
815 GError **error)
816{
817 const char *uri;
818
819 if (under == NULL((void*)0) &&
1
Assuming 'under' is not equal to NULL
820 ! force &&
821 ! item->modified)
822 return TRUE(!(0));
823
824 if (under
1.1
'under' is not equal to NULL
== NULL((void*)0))
2
Taking false branch
825 uri = item->location;
826 else
827 uri = under;
828
829 if (uri
2.1
'uri' is not equal to NULL
== NULL((void*)0)) {
3
Taking false branch
830 g_set_error (error,
831 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
832 MATE_DESKTOP_ITEM_ERROR_NO_FILENAME,
833 _("No filename to save to")((char *) g_dgettext ("mate-desktop", "No filename to save to"
))
);
834 return FALSE(0);
835 }
836
837 if ( ! ditem_save (item, uri, error))
4
Calling 'ditem_save'
838 return FALSE(0);
839
840 item->modified = FALSE(0);
841 item->mtime = g_get_real_time () / G_USEC_PER_SEC1000000;
842
843 return TRUE(!(0));
844}
845
846/**
847 * mate_desktop_item_ref:
848 * @item: A desktop item
849 *
850 * Description: Increases the reference count of the specified item.
851 *
852 * Returns: the newly referenced @item
853 */
854MateDesktopItem *
855mate_desktop_item_ref (MateDesktopItem *item)
856{
857 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
858
859 item->refcount++;
860
861 return item;
862}
863
864static void
865free_section (gpointer data)
866{
867 Section *section = data;
868
869 g_free (section->name);
870 section->name = NULL((void*)0);
871
872 g_list_free_full (section->keys, g_free);
873 section->keys = NULL((void*)0);
874
875 g_free (section);
876}
877
878/**
879 * mate_desktop_item_unref:
880 * @item: A desktop item
881 *
882 * Decreases the reference count of the specified item, and destroys the item if there are no more references left.
883 */
884void
885mate_desktop_item_unref (MateDesktopItem *item)
886{
887 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
888 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
889
890 item->refcount--;
891
892 if(item->refcount != 0)
893 return;
894
895 g_list_free_full (item->languages, g_free);
896 item->languages = NULL((void*)0);
897
898 g_list_free_full (item->keys, g_free);
899 item->keys = NULL((void*)0);
900
901 g_list_free_full (item->sections, (GDestroyNotify) free_section);
902 item->sections = NULL((void*)0);
903
904 g_hash_table_destroy (item->main_hash);
905 item->main_hash = NULL((void*)0);
906
907 g_free (item->location);
908 item->location = NULL((void*)0);
909
910 g_free (item);
911}
912
913static Section *
914find_section (MateDesktopItem *item, const char *section)
915{
916 GList *li;
917 Section *sec;
918
919 if (section == NULL((void*)0))
920 return NULL((void*)0);
921 if (strcmp (section, "Desktop Entry") == 0)
922 return NULL((void*)0);
923
924 for (li = item->sections; li != NULL((void*)0); li = li->next) {
925 sec = li->data;
926 if (strcmp (sec->name, section) == 0)
927 return sec;
928 }
929
930 sec = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
931 sec->name = g_strdup (section)g_strdup_inline (section);
932 sec->keys = NULL((void*)0);
933
934 item->sections = g_list_append (item->sections, sec);
935
936 /* Don't mark the item modified, this is just an empty section,
937 * it won't be saved even */
938
939 return sec;
940}
941
942static Section *
943section_from_key (MateDesktopItem *item, const char *key)
944{
945 char *p;
946 char *name;
947 Section *sec;
948
949 if (key == NULL((void*)0))
950 return NULL((void*)0);
951
952 p = strchr (key, '/');
953 if (p == NULL((void*)0))
954 return NULL((void*)0);
955
956 name = g_strndup (key, p - key);
957
958 sec = find_section (item, name);
959
960 g_free (name);
961
962 return sec;
963}
964
965static const char *
966key_basename (const char *key)
967{
968 char *p = strrchr (key, '/');
969 if (p != NULL((void*)0))
970 return p+1;
971 else
972 return key;
973}
974
975static const char *
976lookup (const MateDesktopItem *item, const char *key)
977{
978 return g_hash_table_lookup (item->main_hash, key);
979}
980
981static const char *
982lookup_locale (const MateDesktopItem *item, const char *key, const char *locale)
983{
984 if (locale == NULL((void*)0) ||
985 strcmp (locale, "C") == 0) {
986 return lookup (item, key);
987 } else {
988 const char *ret;
989 char *full = g_strdup_printf ("%s[%s]", key, locale);
990 ret = lookup (item, full);
991 g_free (full);
992 return ret;
993 }
994}
995
996static const char *
997lookup_best_locale (const MateDesktopItem *item, const char *key)
998{
999 const char * const *langs_pointer;
1000 int i;
1001
1002 langs_pointer = g_get_language_names ();
1003 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
1004 const char *ret = NULL((void*)0);
1005
1006 ret = lookup_locale (item, key, langs_pointer[i]);
1007 if (ret != NULL((void*)0))
1008 return ret;
1009 }
1010
1011 return NULL((void*)0);
1012}
1013
1014static void
1015set (MateDesktopItem *item, const char *key, const char *value)
1016{
1017 Section *sec = section_from_key (item, key);
1018
1019 if (sec != NULL((void*)0)) {
1020 if (value != NULL((void*)0)) {
1021 if (g_hash_table_lookup (item->main_hash, key) == NULL((void*)0))
1022 sec->keys = g_list_append
1023 (sec->keys,
1024 g_strdup (key_basename (key))g_strdup_inline (key_basename (key)));
1025
1026 g_hash_table_replace (item->main_hash,
1027 g_strdup (key)g_strdup_inline (key),
1028 g_strdup (value)g_strdup_inline (value));
1029 } else {
1030 GList *list = g_list_find_custom
1031 (sec->keys, key_basename (key),
1032 (GCompareFunc)strcmp);
1033 if (list != NULL((void*)0)) {
1034 g_free (list->data);
1035 sec->keys =
1036 g_list_delete_link (sec->keys, list);
1037 }
1038 g_hash_table_remove (item->main_hash, key);
1039 }
1040 } else {
1041 if (value != NULL((void*)0)) {
1042 if (g_hash_table_lookup (item->main_hash, key) == NULL((void*)0))
1043 item->keys = g_list_append (item->keys,
1044 g_strdup (key)g_strdup_inline (key));
1045
1046 g_hash_table_replace (item->main_hash,
1047 g_strdup (key)g_strdup_inline (key),
1048 g_strdup (value)g_strdup_inline (value));
1049 } else {
1050 GList *list = g_list_find_custom
1051 (item->keys, key, (GCompareFunc)strcmp);
1052 if (list != NULL((void*)0)) {
1053 g_free (list->data);
1054 item->keys =
1055 g_list_delete_link (item->keys, list);
1056 }
1057 g_hash_table_remove (item->main_hash, key);
1058 }
1059 }
1060 item->modified = TRUE(!(0));
1061}
1062
1063static void
1064set_locale (MateDesktopItem *item, const char *key,
1065 const char *locale, const char *value)
1066{
1067 if (locale == NULL((void*)0) ||
1068 strcmp (locale, "C") == 0) {
1069 set (item, key, value);
1070 } else {
1071 char *full = g_strdup_printf ("%s[%s]", key, locale);
1072 set (item, full, value);
1073 g_free (full);
1074
1075 /* add the locale to the list of languages if it wasn't there
1076 * before */
1077 if (g_list_find_custom (item->languages, locale,
1078 (GCompareFunc)strcmp) == NULL((void*)0))
1079 item->languages = g_list_prepend (item->languages,
1080 g_strdup (locale)g_strdup_inline (locale));
1081 }
1082}
1083
1084static char **
1085list_to_vector (GSList *list)
1086{
1087 int len = g_slist_length (list);
1088 char **argv;
1089 int i;
1090 GSList *li;
1091
1092 argv = g_new0 (char *, len+1)((char * *) g_malloc0_n ((len+1), sizeof (char *)));
1093
1094 for (i = 0, li = list;
1095 li != NULL((void*)0);
1096 li = li->next, i++) {
1097 argv[i] = g_strdup (li->data)g_strdup_inline (li->data);
1098 }
1099 argv[i] = NULL((void*)0);
1100
1101 return argv;
1102}
1103
1104static GSList *
1105make_args (GList *files)
1106{
1107 GSList *list = NULL((void*)0);
1108 GList *li;
1109
1110 for (li = files; li != NULL((void*)0); li = li->next) {
1111 GFile *gfile;
1112 const char *file = li->data;
1113 if (file == NULL((void*)0))
1114 continue;
1115 gfile = g_file_new_for_uri (file);
1116 list = g_slist_prepend (list, gfile);
1117 }
1118
1119 return g_slist_reverse (list);
1120}
1121
1122static void
1123free_args (GSList *list)
1124{
1125 GSList *li;
1126
1127 for (li = list; li != NULL((void*)0); li = li->next) {
1128 g_object_unref (G_FILE (li->data)((((GFile*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((li->data)), ((g_file_get_type ()))))))
);
1129 li->data = NULL((void*)0);
1130 }
1131 g_slist_free (list);
1132}
1133
1134static char *
1135escape_single_quotes (const char *s,
1136 gboolean in_single_quotes,
1137 gboolean in_double_quotes)
1138{
1139 const char *p;
1140 GString *gs;
1141 const char *pre = "";
1142 const char *post = "";
1143
1144 if ( ! in_single_quotes && ! in_double_quotes) {
1145 pre = "'";
1146 post = "'";
1147 } else if ( ! in_single_quotes && in_double_quotes) {
1148 pre = "\"'";
1149 post = "'\"";
1150 }
1151
1152 if (strchr (s, '\'') == NULL((void*)0)) {
1153 return g_strconcat (pre, s, post, NULL((void*)0));
1154 }
1155
1156 gs = g_string_new (pre);
1157
1158 for (p = s; *p != '\0'; p++) {
1159 if (*p == '\'')
1160 g_string_append (gs, "'\\''")(__builtin_constant_p ("'\\''") ? __extension__ ({ const char
* const __val = ("'\\''"); g_string_append_len_inline (gs, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (gs, "'\\''"
, (gssize) -1))
;
1161 else
1162 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1163 }
1164
1165 g_string_append (gs, post)(__builtin_constant_p (post) ? __extension__ ({ const char * const
__val = (post); g_string_append_len_inline (gs, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (gs, post, (gssize) -1
))
;
1166
1167 return g_string_free (gs, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((gs),
((0))) : g_string_free_and_steal (gs)) : (g_string_free) ((gs
), ((0))))
;
1168}
1169
1170typedef enum {
1171 URI_TO_STRING,
1172 URI_TO_LOCAL_PATH,
1173 URI_TO_LOCAL_DIRNAME,
1174 URI_TO_LOCAL_BASENAME
1175} ConversionType;
1176
1177static char *
1178convert_uri (GFile *file,
1179 ConversionType conversion)
1180{
1181 char *retval = NULL((void*)0);
1182
1183 switch (conversion) {
1184 case URI_TO_STRING:
1185 retval = g_file_get_uri (file);
1186 break;
1187 case URI_TO_LOCAL_PATH:
1188 retval = g_file_get_path (file);
1189 break;
1190 case URI_TO_LOCAL_DIRNAME:
1191 {
1192 char *local_path;
1193
1194 local_path = g_file_get_path (file);
1195 retval = g_path_get_dirname (local_path);
1196 g_free (local_path);
1197 }
1198 break;
1199 case URI_TO_LOCAL_BASENAME:
1200 retval = g_file_get_basename (file);
1201 break;
1202 default:
1203 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-desktop-item.c"
, 1203, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1204 }
1205
1206 return retval;
1207}
1208
1209typedef enum {
1210 ADDED_NONE = 0,
1211 ADDED_SINGLE,
1212 ADDED_ALL
1213} AddedStatus;
1214
1215static AddedStatus
1216append_all_converted (GString *str,
1217 ConversionType conversion,
1218 GSList *args,
1219 gboolean in_single_quotes,
1220 gboolean in_double_quotes,
1221 AddedStatus added_status)
1222{
1223 GSList *l;
1224
1225 for (l = args; l; l = l->next) {
1226 char *converted;
1227 char *escaped;
1228
1229 if (!(converted = convert_uri (l->data, conversion)))
1230 continue;
1231
1232 g_string_append (str, " ")(__builtin_constant_p (" ") ? __extension__ ({ const char * const
__val = (" "); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, " ", (gssize) -1
))
;
1233
1234 escaped = escape_single_quotes (converted,
1235 in_single_quotes,
1236 in_double_quotes);
1237 g_string_append (str, escaped)(__builtin_constant_p (escaped) ? __extension__ ({ const char
* const __val = (escaped); g_string_append_len_inline (str, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (str, escaped
, (gssize) -1))
;
1238
1239 g_free (escaped);
1240 g_free (converted);
1241 }
1242
1243 return ADDED_ALL;
1244}
1245
1246static AddedStatus
1247append_first_converted (GString *str,
1248 ConversionType conversion,
1249 GSList **arg_ptr,
1250 gboolean in_single_quotes,
1251 gboolean in_double_quotes,
1252 AddedStatus added_status)
1253{
1254 GSList *l;
1255 char *converted = NULL((void*)0);
1256 char *escaped;
1257
1258 for (l = *arg_ptr; l; l = l->next) {
1259 if ((converted = convert_uri (l->data, conversion)))
1260 break;
1261
1262 *arg_ptr = l->next;
1263 }
1264
1265 if (!converted)
1266 return added_status;
1267
1268 escaped = escape_single_quotes (converted, in_single_quotes, in_double_quotes);
1269 g_string_append (str, escaped)(__builtin_constant_p (escaped) ? __extension__ ({ const char
* const __val = (escaped); g_string_append_len_inline (str, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (str, escaped
, (gssize) -1))
;
1270 g_free (escaped);
1271 g_free (converted);
1272
1273 return added_status != ADDED_ALL ? ADDED_SINGLE : added_status;
1274}
1275
1276static gboolean
1277do_percent_subst (const MateDesktopItem *item,
1278 const char *arg,
1279 GString *str,
1280 gboolean in_single_quotes,
1281 gboolean in_double_quotes,
1282 GSList *args,
1283 GSList **arg_ptr,
1284 AddedStatus *added_status)
1285{
1286 char *esc;
1287 const char *cs;
1288
1289 if (arg[0] != '%' || arg[1] == '\0') {
1290 return FALSE(0);
1291 }
1292
1293 switch (arg[1]) {
1294 case '%':
1295 g_string_append_c (str, '%')g_string_append_c_inline (str, '%');
1296 break;
1297 case 'U':
1298 *added_status = append_all_converted (str,
1299 URI_TO_STRING,
1300 args,
1301 in_single_quotes,
1302 in_double_quotes,
1303 *added_status);
1304 break;
1305 case 'F':
1306 *added_status = append_all_converted (str,
1307 URI_TO_LOCAL_PATH,
1308 args,
1309 in_single_quotes,
1310 in_double_quotes,
1311 *added_status);
1312 break;
1313 case 'N':
1314 *added_status = append_all_converted (str,
1315 URI_TO_LOCAL_BASENAME,
1316 args,
1317 in_single_quotes,
1318 in_double_quotes,
1319 *added_status);
1320 break;
1321 case 'D':
1322 *added_status = append_all_converted (str,
1323 URI_TO_LOCAL_DIRNAME,
1324 args,
1325 in_single_quotes,
1326 in_double_quotes,
1327 *added_status);
1328 break;
1329 case 'f':
1330 *added_status = append_first_converted (str,
1331 URI_TO_LOCAL_PATH,
1332 arg_ptr,
1333 in_single_quotes,
1334 in_double_quotes,
1335 *added_status);
1336 break;
1337 case 'u':
1338 *added_status = append_first_converted (str,
1339 URI_TO_STRING,
1340 arg_ptr,
1341 in_single_quotes,
1342 in_double_quotes,
1343 *added_status);
1344 break;
1345 case 'd':
1346 *added_status = append_first_converted (str,
1347 URI_TO_LOCAL_DIRNAME,
1348 arg_ptr,
1349 in_single_quotes,
1350 in_double_quotes,
1351 *added_status);
1352 break;
1353 case 'n':
1354 *added_status = append_first_converted (str,
1355 URI_TO_LOCAL_BASENAME,
1356 arg_ptr,
1357 in_single_quotes,
1358 in_double_quotes,
1359 *added_status);
1360 break;
1361 case 'm':
1362 /* Note: v0.9.4 of the spec says this is deprecated
1363 * and replace with --miniicon iconname */
1364 cs = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_MINI_ICON"MiniIcon");
1365 if (cs != NULL((void*)0)) {
1366 g_string_append (str, "--miniicon=")(__builtin_constant_p ("--miniicon=") ? __extension__ ({ const
char * const __val = ("--miniicon="); g_string_append_len_inline
(str, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(str, "--miniicon=", (gssize) -1))
;
1367 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1368 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1369 }
1370 break;
1371 case 'i':
1372 /* Note: v0.9.4 of the spec says replace with --icon iconname */
1373 cs = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_ICON"Icon");
1374 if (cs != NULL((void*)0)) {
1375 g_string_append (str, "--icon=")(__builtin_constant_p ("--icon=") ? __extension__ ({ const char
* const __val = ("--icon="); g_string_append_len_inline (str
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (str
, "--icon=", (gssize) -1))
;
1376 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1377 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1378 }
1379 break;
1380 case 'c':
1381 cs = mate_desktop_item_get_localestring (item, MATE_DESKTOP_ITEM_NAME"Name");
1382 if (cs != NULL((void*)0)) {
1383 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1384 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1385 g_free (esc);
1386 }
1387 break;
1388 case 'k':
1389 if (item->location != NULL((void*)0)) {
1390 esc = escape_single_quotes (item->location, in_single_quotes, in_double_quotes);
1391 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1392 g_free (esc);
1393 }
1394 break;
1395 case 'v':
1396 cs = mate_desktop_item_get_localestring (item, MATE_DESKTOP_ITEM_DEV"Dev");
1397 if (cs != NULL((void*)0)) {
1398 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1399 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1400 g_free (esc);
1401 }
1402 break;
1403 default:
1404 /* Maintain special characters - e.g. "%20" */
1405 if (g_ascii_isdigit (arg [1])((g_ascii_table[(guchar) (arg [1])] & G_ASCII_DIGIT) != 0
)
)
1406 g_string_append_c (str, '%')g_string_append_c_inline (str, '%');
1407 return FALSE(0);
1408 }
1409
1410 return TRUE(!(0));
1411}
1412
1413static char *
1414expand_string (const MateDesktopItem *item,
1415 const char *s,
1416 GSList *args,
1417 GSList **arg_ptr,
1418 AddedStatus *added_status)
1419{
1420 const char *p;
1421 gboolean escape = FALSE(0);
1422 gboolean single_quot = FALSE(0);
1423 gboolean double_quot = FALSE(0);
1424 GString *gs = g_string_new (NULL((void*)0));
1425
1426 for (p = s; *p != '\0'; p++) {
1427 if (escape) {
1428 escape = FALSE(0);
1429 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1430 } else if (*p == '\\') {
1431 if ( ! single_quot)
1432 escape = TRUE(!(0));
1433 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1434 } else if (*p == '\'') {
1435 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1436 if ( ! single_quot && ! double_quot) {
1437 single_quot = TRUE(!(0));
1438 } else if (single_quot) {
1439 single_quot = FALSE(0);
1440 }
1441 } else if (*p == '"') {
1442 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1443 if ( ! single_quot && ! double_quot) {
1444 double_quot = TRUE(!(0));
1445 } else if (double_quot) {
1446 double_quot = FALSE(0);
1447 }
1448 } else if (*p == '%') {
1449 if (do_percent_subst (item, p, gs,
1450 single_quot, double_quot,
1451 args, arg_ptr,
1452 added_status)) {
1453 p++;
1454 }
1455 } else {
1456 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1457 }
1458 }
1459 return g_string_free (gs, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((gs),
((0))) : g_string_free_and_steal (gs)) : (g_string_free) ((gs
), ((0))))
;
1460}
1461
1462/*Functions in this code block should only ever be reached in x11*/
1463#ifdef HAVE_STARTUP_NOTIFICATION
1464static void
1465sn_error_trap_push (SnDisplay *display,
1466 Display *xdisplay)
1467{
1468 GdkDisplay *gdkdisplay;
1469
1470 gdkdisplay = gdk_display_get_default ();
1471 gdk_x11_display_error_trap_push (gdkdisplay);
1472}
1473
1474static void
1475sn_error_trap_pop (SnDisplay *display,
1476 Display *xdisplay)
1477{
1478 GdkDisplay *gdkdisplay;
1479
1480 gdkdisplay = gdk_display_get_default ();
1481 gdk_x11_display_error_trap_pop_ignored (gdkdisplay);
1482}
1483
1484static char **
1485make_spawn_environment_for_sn_context (SnLauncherContext *sn_context,
1486 char **envp)
1487{
1488 char **retval;
1489 char **freeme;
1490 int i, j;
1491 int desktop_startup_id_len;
1492
1493 retval = freeme = NULL((void*)0);
1494
1495 if (envp == NULL((void*)0)) {
1496 envp = freeme = g_listenv ();
1497 for (i = 0; envp[i]; i++) {
1498 char *name = envp[i];
1499
1500 envp[i] = g_strjoin ("=", name, g_getenv (name), NULL((void*)0));
1501 g_free (name);
1502 }
1503 } else {
1504 for (i = 0; envp[i]; i++)
1505 ;
1506 }
1507
1508 retval = g_new (char *, i + 2)((char * *) g_malloc_n ((i + 2), sizeof (char *)));
1509
1510 desktop_startup_id_len = strlen ("DESKTOP_STARTUP_ID");
1511
1512 for (i = 0, j = 0; envp[i]; i++) {
1513 if (strncmp (envp[i], "DESKTOP_STARTUP_ID", desktop_startup_id_len) != 0) {
1514 retval[j] = g_strdup (envp[i])g_strdup_inline (envp[i]);
1515 ++j;
1516 }
1517 }
1518
1519 retval[j] = g_strdup_printf ("DESKTOP_STARTUP_ID=%s",
1520 sn_launcher_context_get_startup_id (sn_context));
1521 ++j;
1522 retval[j] = NULL((void*)0);
1523
1524 g_strfreev (freeme);
1525
1526 return retval;
1527}
1528
1529/* This should be fairly long, as it's confusing to users if a startup
1530 * ends when it shouldn't (it appears that the startup failed, and
1531 * they have to relaunch the app). Also the timeout only matters when
1532 * there are bugs and apps don't end their own startup sequence.
1533 *
1534 * This timeout is a "last resort" timeout that ignores whether the
1535 * startup sequence has shown activity or not. Marco and the
1536 * tasklist have smarter, and correspondingly able-to-be-shorter
1537 * timeouts. The reason our timeout is dumb is that we don't monitor
1538 * the sequence (don't use an SnMonitorContext)
1539 */
1540#define STARTUP_TIMEOUT_LENGTH_SEC30 30 /* seconds */
1541#define STARTUP_TIMEOUT_LENGTH(30 * 1000) (STARTUP_TIMEOUT_LENGTH_SEC30 * 1000)
1542
1543typedef struct
1544{
1545 GdkScreen *screen;
1546 GSList *contexts;
1547 guint timeout_id;
1548} StartupTimeoutData;
1549
1550static void
1551free_startup_timeout (void *data)
1552{
1553 StartupTimeoutData *std = data;
1554
1555 g_slist_free_full (std->contexts, (GDestroyNotify) sn_launcher_context_unref);
1556
1557 if (std->timeout_id != 0) {
1558 g_source_remove (std->timeout_id);
1559 std->timeout_id = 0;
1560 }
1561
1562 g_free (std);
1563}
1564
1565static gboolean
1566startup_timeout (void *data)
1567{
1568 StartupTimeoutData *std = data;
1569 GSList *tmp;
1570 int min_timeout;
1571
1572 min_timeout = STARTUP_TIMEOUT_LENGTH(30 * 1000);
1573
1574#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1575 gint64 now = g_get_real_time ();
1576#else
1577 GTimeVal now;
1578 g_get_current_time (&now);
1579#endif
1580
1581 tmp = std->contexts;
1582 while (tmp != NULL((void*)0)) {
1583 SnLauncherContext *sn_context = tmp->data;
1584 GSList *next = tmp->next;
1585 double elapsed;
1586
1587#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1588 time_t tv_sec;
1589 suseconds_t tv_usec;
1590 gint64 tv;
1591
1592 sn_launcher_context_get_last_active_time (sn_context, &tv_sec, &tv_usec);
1593 tv = (tv_sec * G_USEC_PER_SEC1000000) + tv_usec;
1594 elapsed = (double) (now - tv) / 1000.0;
1595#else
1596 long tv_sec, tv_usec;
1597
1598 sn_launcher_context_get_last_active_time (sn_context,
1599 &tv_sec, &tv_usec);
1600
1601 elapsed =
1602 ((((double)now.tv_sec - tv_sec) * G_USEC_PER_SEC1000000 +
1603 (now.tv_usec - tv_usec))) / 1000.0;
1604#endif
1605
1606 if (elapsed >= STARTUP_TIMEOUT_LENGTH(30 * 1000)) {
1607 std->contexts = g_slist_remove (std->contexts,
1608 sn_context);
1609 sn_launcher_context_complete (sn_context);
1610 sn_launcher_context_unref (sn_context);
1611 } else {
1612 min_timeout = MIN (min_timeout, (STARTUP_TIMEOUT_LENGTH - elapsed))(((min_timeout) < (((30 * 1000) - elapsed))) ? (min_timeout
) : (((30 * 1000) - elapsed)))
;
1613 }
1614
1615 tmp = next;
1616 }
1617
1618 /* we'll use seconds for the timeout */
1619 if (min_timeout < 1000)
1620 min_timeout = 1000;
1621
1622 if (std->contexts == NULL((void*)0)) {
1623 std->timeout_id = 0;
1624 } else {
1625 std->timeout_id = g_timeout_add_seconds (min_timeout / 1000,
1626 startup_timeout,
1627 std);
1628 }
1629
1630 /* always remove this one, but we may have reinstalled another one. */
1631 return FALSE(0);
1632}
1633
1634static void
1635add_startup_timeout (GdkScreen *screen,
1636 SnLauncherContext *sn_context)
1637{
1638 StartupTimeoutData *data;
1639
1640 data = g_object_get_data (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "mate-startup-data");
1641 if (data == NULL((void*)0)) {
1642 data = g_new (StartupTimeoutData, 1)((StartupTimeoutData *) g_malloc_n ((1), sizeof (StartupTimeoutData
)))
;
1643 data->screen = screen;
1644 data->contexts = NULL((void*)0);
1645 data->timeout_id = 0;
1646
1647 g_object_set_data_full (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "mate-startup-data",
1648 data, free_startup_timeout);
1649 }
1650
1651 sn_launcher_context_ref (sn_context);
1652 data->contexts = g_slist_prepend (data->contexts, sn_context);
1653
1654 if (data->timeout_id == 0) {
1655 data->timeout_id = g_timeout_add_seconds (
1656 STARTUP_TIMEOUT_LENGTH_SEC30,
1657 startup_timeout,
1658 data);
1659 }
1660}
1661#endif /* HAVE_STARTUP_NOTIFICATION - functions should only be reached in x11*/
1662
1663static inline char *
1664stringify_uris (GSList *args)
1665{
1666 GString *str;
1667
1668 str = g_string_new (NULL((void*)0));
1669
1670 append_all_converted (str, URI_TO_STRING, args, FALSE(0), FALSE(0), ADDED_NONE);
1671
1672 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1673}
1674
1675static inline char *
1676stringify_files (GSList *args)
1677{
1678 GString *str;
1679
1680 str = g_string_new (NULL((void*)0));
1681
1682 append_all_converted (str, URI_TO_LOCAL_PATH, args, FALSE(0), FALSE(0), ADDED_NONE);
1683
1684 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1685}
1686
1687static char **
1688make_environment_for_screen (GdkScreen *screen,
1689 char **envp)
1690{
1691 GdkDisplay *display;
1692 char **retval;
1693 char **freeme;
1694 char *display_name;
1695 int display_index = -1;
1696 int i, env_len;
1697
1698 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((screen)); GType __t = ((gdk_screen_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "GDK_IS_SCREEN (screen)"); return (((void*)0)
); } } while (0)
;
1699
1700 retval = freeme = NULL((void*)0);
1701
1702 if (envp == NULL((void*)0)) {
1703 envp = freeme = g_listenv ();
1704 for (i = 0; envp [i]; i++) {
1705 char *name = envp[i];
1706
1707 envp[i] = g_strjoin ("=", name, g_getenv (name), NULL((void*)0));
1708 g_free (name);
1709 }
1710 }
1711
1712 for (env_len = 0; envp [env_len]; env_len++)
1713 if (strncmp (envp [env_len], "DISPLAY", strlen ("DISPLAY")) == 0)
1714 display_index = env_len;
1715
1716 retval = g_new (char *, env_len + 1)((char * *) g_malloc_n ((env_len + 1), sizeof (char *)));
1717 retval [env_len] = NULL((void*)0);
1718
1719 display = gdk_screen_get_display (screen);
1720 display_name = g_strdup (gdk_display_get_name (display))g_strdup_inline (gdk_display_get_name (display));
1721
1722 for (i = 0; i < env_len; i++)
1723 if (i == display_index)
1724 retval [i] = g_strconcat ("DISPLAY=", display_name, NULL((void*)0));
1725 else
1726 retval [i] = g_strdup (envp[i])g_strdup_inline (envp[i]);
1727
1728 g_assert (i == env_len)do { if (i == env_len) ; else g_assertion_message_expr ("MateDesktop"
, "mate-desktop-item.c", 1728, ((const char*) (__func__)), "i == env_len"
); } while (0)
;
1729
1730 g_free (display_name);
1731 g_strfreev (freeme);
1732
1733 return retval;
1734}
1735
1736static void
1737dummy_child_watch (GPid pid,
1738 gint status,
1739 gpointer user_data)
1740{
1741 /* Nothing, this is just to ensure we don't double fork
1742 * and break pkexec:
1743 * https://bugzilla.gnome.org/show_bug.cgi?id=675789
1744 */
1745}
1746
1747static int
1748ditem_execute (const MateDesktopItem *item,
1749 const char *exec,
1750 GList *file_list,
1751 GdkScreen *screen,
1752 int workspace,
1753 char **envp,
1754 gboolean launch_only_one,
1755 gboolean use_current_dir,
1756 gboolean append_uris,
1757 gboolean append_paths,
1758 gboolean do_not_reap_child,
1759 GError **error)
1760{
1761 char **free_me = NULL((void*)0);
1762 char **real_argv;
1763 int i, ret;
1764 char **term_argv = NULL((void*)0);
1765 int term_argc = 0;
1766 GSList *vector_list;
1767 GSList *args, *arg_ptr;
1768 AddedStatus added_status;
1769 const char *working_dir = NULL((void*)0);
1770 char **temp_argv = NULL((void*)0);
1771 int temp_argc = 0;
1772 char *new_exec, *uris, *temp;
1773 char *exec_locale;
1774 int launched = 0;
1775 GPid pid;
1776#ifdef HAVE_STARTUP_NOTIFICATION
1777 GdkDisplay *gdkdisplay;
1778 SnLauncherContext *sn_context;
1779 SnDisplay *sn_display;
1780 const char *startup_class;
1781#endif
1782
1783 g_return_val_if_fail (item, -1)do { if ((item)) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "item"); return (-1); } } while
(0)
;
1784
1785 if (item->type == MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
1786 working_dir = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_PATH"Path");
1787 if (working_dir &&
1788 !g_file_test (working_dir, G_FILE_TEST_IS_DIR))
1789 working_dir = NULL((void*)0);
1790 }
1791
1792 if (working_dir == NULL((void*)0) && !use_current_dir)
1793 working_dir = g_get_home_dir ();
1794
1795 if (mate_desktop_item_get_boolean (item, MATE_DESKTOP_ITEM_TERMINAL"Terminal")) {
1796 const char *options =
1797 mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_TERMINAL_OPTIONS"TerminalOptions");
1798
1799 if (options != NULL((void*)0)) {
1800 g_shell_parse_argv (options,
1801 &term_argc,
1802 &term_argv,
1803 NULL((void*)0) /* error */);
1804 /* ignore errors */
1805 }
1806
1807 mate_desktop_prepend_terminal_to_vector (&term_argc, &term_argv);
1808 }
1809
1810 args = make_args (file_list);
1811 arg_ptr = make_args (file_list);
1812
1813#ifdef HAVE_STARTUP_NOTIFICATION
1814 GdkDisplay *display = gdk_screen_get_display (gdk_screen_get_default());
1815 if (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1816 {
1817 if (screen)
1818 gdkdisplay = gdk_screen_get_display (screen);
1819 else
1820 gdkdisplay = gdk_display_get_default ();
1821
1822 sn_display = sn_display_new (GDK_DISPLAY_XDISPLAY (gdkdisplay)(gdk_x11_display_get_xdisplay (gdkdisplay)),
1823 sn_error_trap_push,
1824 sn_error_trap_pop);
1825
1826 /* Only initiate notification if desktop file supports it.
1827 * (we could avoid setting up the SnLauncherContext if we aren't going
1828 * to initiate, but why bother)
1829 */
1830
1831 startup_class = mate_desktop_item_get_string (item,
1832 "StartupWMClass");
1833 if (startup_class ||
1834 mate_desktop_item_get_boolean (item, "StartupNotify")) {
1835 const char *name;
1836 const char *icon;
1837
1838 sn_context = sn_launcher_context_new (sn_display,
1839 screen ? gdk_x11_screen_get_screen_number (screen) :
1840 DefaultScreen (GDK_DISPLAY_XDISPLAY (gdkdisplay))(((_XPrivDisplay)((gdk_x11_display_get_xdisplay (gdkdisplay))
))->default_screen)
);
1841
1842 name = mate_desktop_item_get_localestring (item,
1843 MATE_DESKTOP_ITEM_NAME"Name");
1844
1845 if (name == NULL((void*)0))
1846 name = mate_desktop_item_get_localestring (item,
1847 MATE_DESKTOP_ITEM_GENERIC_NAME"GenericName");
1848
1849 if (name != NULL((void*)0)) {
1850 char *description;
1851
1852 sn_launcher_context_set_name (sn_context, name);
1853
1854 description = g_strdup_printf (_("Starting %s")((char *) g_dgettext ("mate-desktop", "Starting %s")), name);
1855
1856 sn_launcher_context_set_description (sn_context, description);
1857
1858 g_free (description);
1859 }
1860
1861 icon = mate_desktop_item_get_string (item,
1862 MATE_DESKTOP_ITEM_ICON"Icon");
1863
1864 if (icon != NULL((void*)0))
1865 sn_launcher_context_set_icon_name (sn_context, icon);
1866
1867 sn_launcher_context_set_workspace (sn_context, workspace);
1868
1869 if (startup_class != NULL((void*)0))
1870 sn_launcher_context_set_wmclass (sn_context,
1871 startup_class);
1872 } else {
1873 sn_context = NULL((void*)0);
1874 }
1875 }
1876 else {
1877 sn_context = NULL((void*)0);
1878 sn_display = NULL((void*)0);
1879 }
1880#endif
1881
1882 if (screen) {
1883 envp = make_environment_for_screen (screen, envp);
1884 if (free_me)
1885 g_strfreev (free_me);
1886 free_me = envp;
1887 }
1888
1889 exec_locale = g_filename_from_utf8 (exec, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
1890
1891 if (exec_locale == NULL((void*)0)) {
1892 exec_locale = g_strdup ("")g_strdup_inline ("");
1893 }
1894
1895 do {
1896 added_status = ADDED_NONE;
1897 new_exec = expand_string (item,
1898 exec_locale,
1899 args, &arg_ptr, &added_status);
1900
1901 if (launched == 0 && added_status == ADDED_NONE && append_uris) {
1902 uris = stringify_uris (args);
1903 temp = g_strconcat (new_exec, " ", uris, NULL((void*)0));
1904 g_free (uris);
1905 g_free (new_exec);
1906 new_exec = temp;
1907 added_status = ADDED_ALL;
1908 }
1909
1910 /* append_uris and append_paths are mutually exlusive */
1911 if (launched == 0 && added_status == ADDED_NONE && append_paths) {
1912 uris = stringify_files (args);
1913 temp = g_strconcat (new_exec, " ", uris, NULL((void*)0));
1914 g_free (uris);
1915 g_free (new_exec);
1916 new_exec = temp;
1917 added_status = ADDED_ALL;
1918 }
1919
1920 if (launched > 0 && added_status == ADDED_NONE) {
1921 g_free (new_exec);
1922 break;
1923 }
1924
1925 if ( ! g_shell_parse_argv (new_exec,
1926 &temp_argc, &temp_argv, error)) {
1927 /* The error now comes from g_shell_parse_argv */
1928 g_free (new_exec);
1929 ret = -1;
1930 break;
1931 }
1932 g_free (new_exec);
1933
1934 vector_list = NULL((void*)0);
1935 for(i = 0; i < term_argc; i++)
1936 vector_list = g_slist_append (vector_list,
1937 g_strdup (term_argv[i])g_strdup_inline (term_argv[i]));
1938
1939 for(i = 0; i < temp_argc; i++)
1940 vector_list = g_slist_append (vector_list,
1941 g_strdup (temp_argv[i])g_strdup_inline (temp_argv[i]));
1942
1943 g_strfreev (temp_argv);
1944
1945 real_argv = list_to_vector (vector_list);
1946 g_slist_free_full (vector_list, g_free);
1947
1948#ifdef HAVE_STARTUP_NOTIFICATION
1949 if (sn_context != NULL((void*)0) && (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) &&
1950 !sn_launcher_context_get_initiated (sn_context)) {
1951 guint32 launch_time;
1952
1953 /* This means that we always use the first real_argv[0]
1954 * we select for the "binary name", but it's probably
1955 * OK to do that. Binary name isn't super-important
1956 * anyway, and we can't initiate twice, and we
1957 * must initiate prior to fork/exec.
1958 */
1959
1960 sn_launcher_context_set_binary_name (sn_context,
1961 real_argv[0]);
1962
1963 if (item->launch_time > 0)
1964 launch_time = item->launch_time;
1965 else
1966 launch_time = gdk_x11_display_get_user_time (gdkdisplay);
1967
1968 sn_launcher_context_initiate (sn_context,
1969 g_get_prgname () ? g_get_prgname () : "unknown",
1970 real_argv[0],
1971 launch_time);
1972
1973 /* Don't allow accidental reuse of same timestamp */
1974 ((MateDesktopItem *)item)->launch_time = 0;
1975
1976 envp = make_spawn_environment_for_sn_context (sn_context, envp);
1977 if (free_me)
1978 g_strfreev (free_me);
1979 free_me = envp;
1980 }
1981#endif
1982
1983 if ( ! g_spawn_async (working_dir,
1984 real_argv,
1985 envp,
1986 (do_not_reap_child ? G_SPAWN_DO_NOT_REAP_CHILD : 0) | G_SPAWN_SEARCH_PATH /* flags */,
1987 NULL((void*)0), /* child_setup_func */
1988 NULL((void*)0), /* child_setup_func_data */
1989 (do_not_reap_child ? &pid : NULL((void*)0)) /* child_pid */,
1990 error)) {
1991 /* The error was set for us,
1992 * we just can't launch this thingie */
1993 ret = -1;
1994 g_strfreev (real_argv);
1995 break;
1996 } else if (do_not_reap_child) {
1997 g_child_watch_add (pid, dummy_child_watch, NULL((void*)0));
1998 }
1999
2000 launched ++;
2001
2002 g_strfreev (real_argv);
2003
2004 if (arg_ptr != NULL((void*)0))
2005 arg_ptr = arg_ptr->next;
2006
2007 /* rinse, repeat until we run out of arguments (That
2008 * is if we were adding singles anyway) */
2009 } while (added_status == ADDED_SINGLE &&
2010 arg_ptr != NULL((void*)0) &&
2011 ! launch_only_one);
2012
2013 g_free (exec_locale);
2014#ifdef HAVE_STARTUP_NOTIFICATION
2015 if ((sn_context != NULL((void*)0)) && (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)){
2016 if (ret < 0)
2017 sn_launcher_context_complete (sn_context); /* end sequence */
2018 else
2019 add_startup_timeout (screen ? screen :
2020 gdk_display_get_default_screen (gdk_display_get_default ()),
2021 sn_context);
2022 sn_launcher_context_unref (sn_context);
2023 }
2024 if (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2025 sn_display_unref (sn_display);
2026
2027#endif /* HAVE_STARTUP_NOTIFICATION */
2028
2029 free_args (args);
2030
2031 if (term_argv)
2032 g_strfreev (term_argv);
2033
2034 if (free_me)
2035 g_strfreev (free_me);
2036
2037 return ret;
2038}
2039
2040/* strip any trailing &, return FALSE if bad things happen and
2041 we end up with an empty string */
2042static gboolean
2043strip_the_amp (char *exec)
2044{
2045 size_t exec_len;
2046
2047 g_strstrip (exec)g_strchomp (g_strchug (exec));
2048 if (*exec == '\0')
2049 return FALSE(0);
2050
2051 exec_len = strlen (exec);
2052 /* kill any trailing '&' */
2053 if (exec[exec_len-1] == '&') {
2054 exec[exec_len-1] = '\0';
2055 g_strchomp (exec);
2056 }
2057
2058 /* can't exactly launch an empty thing */
2059 if (*exec == '\0')
2060 return FALSE(0);
2061
2062 return TRUE(!(0));
2063}
2064
2065static int
2066mate_desktop_item_launch_on_screen_with_env (
2067 const MateDesktopItem *item,
2068 GList *file_list,
2069 MateDesktopItemLaunchFlags flags,
2070 GdkScreen *screen,
2071 int workspace,
2072 char **envp,
2073 GError **error)
2074{
2075 const char *exec;
2076 char *the_exec;
2077 int ret;
2078
2079 exec = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_EXEC"Exec");
2080 /* This is a URL, so launch it as a url */
2081 if (item->type == MATE_DESKTOP_ITEM_TYPE_LINK) {
2082 const char *url;
2083 gboolean retval;
2084
2085 url = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_URL"URL");
2086 /* Mate panel used to put this in Exec */
2087 if (!(url && url[0] != '\0'))
2088 url = exec;
2089
2090 if (!(url && url[0] != '\0')) {
2091 g_set_error (error,
2092 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2093 MATE_DESKTOP_ITEM_ERROR_NO_URL,
2094 _("No URL to launch")((char *) g_dgettext ("mate-desktop", "No URL to launch")));
2095 return -1;
2096 }
2097
2098 retval = gtk_show_uri_on_window (NULL((void*)0),
2099 url,
2100 GDK_CURRENT_TIME0L,
2101 error);
2102 return retval ? 0 : -1;
2103 }
2104
2105 /* check the type, if there is one set */
2106 if (item->type != MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
2107 g_set_error (error,
2108 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2109 MATE_DESKTOP_ITEM_ERROR_NOT_LAUNCHABLE,
2110 _("Not a launchable item")((char *) g_dgettext ("mate-desktop", "Not a launchable item"
))
);
2111 return -1;
2112 }
2113
2114 if (exec == NULL((void*)0) ||
2115 exec[0] == '\0') {
2116 g_set_error (error,
2117 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2118 MATE_DESKTOP_ITEM_ERROR_NO_EXEC_STRING,
2119 _("No command (Exec) to launch")((char *) g_dgettext ("mate-desktop", "No command (Exec) to launch"
))
);
2120 return -1;
2121 }
2122
2123 /* make a new copy and get rid of spaces */
2124 the_exec = g_alloca (strlen (exec) + 1)__builtin_alloca (strlen (exec) + 1);
2125 g_strlcpy (the_exec, exec, strlen (exec) + 1);
2126
2127 if ( ! strip_the_amp (the_exec)) {
2128 g_set_error (error,
2129 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2130 MATE_DESKTOP_ITEM_ERROR_BAD_EXEC_STRING,
2131 _("Bad command (Exec) to launch")((char *) g_dgettext ("mate-desktop", "Bad command (Exec) to launch"
))
);
2132 return -1;
2133 }
2134
2135 ret = ditem_execute (item, the_exec, file_list, screen, workspace, envp,
2136 (flags & MATE_DESKTOP_ITEM_LAUNCH_ONLY_ONE),
2137 (flags & MATE_DESKTOP_ITEM_LAUNCH_USE_CURRENT_DIR),
2138 (flags & MATE_DESKTOP_ITEM_LAUNCH_APPEND_URIS),
2139 (flags & MATE_DESKTOP_ITEM_LAUNCH_APPEND_PATHS),
2140 (flags & MATE_DESKTOP_ITEM_LAUNCH_DO_NOT_REAP_CHILD),
2141 error);
2142
2143 return ret;
2144}
2145
2146/**
2147 * mate_desktop_item_launch:
2148 * @item: A desktop item
2149 * @file_list: Files/URIs to launch this item with, can be %NULL
2150 * @flags: FIXME
2151 * @error: FIXME
2152 *
2153 * This function runs the program listed in the specified 'item',
2154 * optionally appending additional arguments to its command line. It uses
2155 * #g_shell_parse_argv to parse the the exec string into a vector which is
2156 * then passed to #g_spawn_async for execution. This can return all
2157 * the errors from MateURL, #g_shell_parse_argv and #g_spawn_async,
2158 * in addition to it's own. The files are
2159 * only added if the entry defines one of the standard % strings in it's
2160 * Exec field.
2161 *
2162 * Returns: The the pid of the process spawned. If more then one
2163 * process was spawned the last pid is returned. On error -1
2164 * is returned and @error is set.
2165 */
2166int
2167mate_desktop_item_launch (const MateDesktopItem *item,
2168 GList *file_list,
2169 MateDesktopItemLaunchFlags flags,
2170 GError **error)
2171{
2172 return mate_desktop_item_launch_on_screen_with_env (
2173 item, file_list, flags, NULL((void*)0), -1, NULL((void*)0), error);
2174}
2175
2176/**
2177 * mate_desktop_item_launch_with_env:
2178 * @item: A desktop item
2179 * @file_list: Files/URIs to launch this item with, can be %NULL
2180 * @flags: FIXME
2181 * @envp: child's environment, or %NULL to inherit parent's
2182 * @error: FIXME
2183 *
2184 * See mate_desktop_item_launch for a full description. This function
2185 * additionally passes an environment vector for the child process
2186 * which is to be launched.
2187 *
2188 * Returns: The the pid of the process spawned. If more then one
2189 * process was spawned the last pid is returned. On error -1
2190 * is returned and @error is set.
2191 */
2192int
2193mate_desktop_item_launch_with_env (const MateDesktopItem *item,
2194 GList *file_list,
2195 MateDesktopItemLaunchFlags flags,
2196 char **envp,
2197 GError **error)
2198{
2199 return mate_desktop_item_launch_on_screen_with_env (
2200 item, file_list, flags,
2201 NULL((void*)0), -1, envp, error);
2202}
2203
2204/**
2205 * mate_desktop_item_launch_on_screen:
2206 * @item: A desktop item
2207 * @file_list: Files/URIs to launch this item with, can be %NULL
2208 * @flags: FIXME
2209 * @screen: the %GdkScreen on which the application should be launched
2210 * @workspace: the workspace on which the app should be launched (-1 for current)
2211 * @error: FIXME
2212 *
2213 * See mate_desktop_item_launch for a full description. This function
2214 * additionally attempts to launch the application on a given screen
2215 * and workspace.
2216 *
2217 * Returns: The the pid of the process spawned. If more then one
2218 * process was spawned the last pid is returned. On error -1
2219 * is returned and @error is set.
2220 */
2221int
2222mate_desktop_item_launch_on_screen (const MateDesktopItem *item,
2223 GList *file_list,
2224 MateDesktopItemLaunchFlags flags,
2225 GdkScreen *screen,
2226 int workspace,
2227 GError **error)
2228{
2229 return mate_desktop_item_launch_on_screen_with_env (
2230 item, file_list, flags,
2231 screen, workspace, NULL((void*)0), error);
2232}
2233
2234/**
2235 * mate_desktop_item_drop_uri_list:
2236 * @item: A desktop item
2237 * @uri_list: text as gotten from a text/uri-list
2238 * @flags: FIXME
2239 * @error: FIXME
2240 *
2241 * A list of files or urls dropped onto an icon, the proper (Url or File)
2242 * exec is run you can pass directly string that you got as the
2243 * text/uri-list. This just parses the list and calls
2244 *
2245 * Returns: The value returned by #mate_execute_async() upon execution of
2246 * the specified item or -1 on error. If multiple instances are run, the
2247 * return of the last one is returned.
2248 */
2249int
2250mate_desktop_item_drop_uri_list (const MateDesktopItem *item,
2251 const char *uri_list,
2252 MateDesktopItemLaunchFlags flags,
2253 GError **error)
2254{
2255 return mate_desktop_item_drop_uri_list_with_env (item, uri_list,
2256 flags, NULL((void*)0), error);
2257}
2258
2259/**
2260* mate_desktop_item_drop_uri_list_with_env:
2261* @item: A desktop item
2262* @uri_list: text as gotten from a text/uri-list
2263* @flags: FIXME
2264* @envp: child's environment
2265* @error: FIXME
2266*
2267* See mate_desktop_item_drop_uri_list for a full description. This function
2268* additionally passes an environment vector for the child process
2269* which is to be launched.
2270*
2271* Returns: The value returned by #mate_execute_async() upon execution of
2272* the specified item or -1 on error. If multiple instances are run, the
2273* return of the last one is returned.
2274*/
2275int
2276mate_desktop_item_drop_uri_list_with_env (const MateDesktopItem *item,
2277 const char *uri_list,
2278 MateDesktopItemLaunchFlags flags,
2279 char **envp,
2280 GError **error)
2281{
2282 int ret;
2283 char *uri;
2284 char **uris;
2285 GList *list = NULL((void*)0);
2286
2287 uris = g_uri_list_extract_uris (uri_list);
2288
2289 for (uri = uris[0]; uri != NULL((void*)0); uri++) {
2290 list = g_list_prepend (list, uri);
2291 }
2292 list = g_list_reverse (list);
2293
2294 ret = mate_desktop_item_launch_with_env (
2295 item, list, flags, envp, error);
2296
2297 g_strfreev (uris);
2298 g_list_free (list);
2299
2300 return ret;
2301}
2302
2303static gboolean
2304exec_exists (const char *exec)
2305{
2306 if (g_path_is_absolute (exec)) {
2307 if (access (exec, X_OK1) == 0)
2308 return TRUE(!(0));
2309 else
2310 return FALSE(0);
2311 } else {
2312 char *tryme;
2313
2314 tryme = g_find_program_in_path (exec);
2315 if (tryme != NULL((void*)0)) {
2316 g_free (tryme);
2317 return TRUE(!(0));
2318 }
2319 return FALSE(0);
2320 }
2321}
2322
2323/**
2324 * mate_desktop_item_exists:
2325 * @item: A desktop item
2326 *
2327 * Attempt to figure out if the program that can be executed by this item
2328 * actually exists. First it tries the TryExec attribute to see if that
2329 * contains a program that is in the path. Then if there is no such
2330 * attribute, it tries the first word of the Exec attribute.
2331 *
2332 * Returns: A boolean, %TRUE if it exists, %FALSE otherwise.
2333 */
2334gboolean
2335mate_desktop_item_exists (const MateDesktopItem *item)
2336{
2337 const char *try_exec;
2338 const char *exec;
2339
2340 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2341
2342 try_exec = lookup (item, MATE_DESKTOP_ITEM_TRY_EXEC"TryExec");
2343
2344 if (try_exec != NULL((void*)0) &&
2345 ! exec_exists (try_exec)) {
2346 return FALSE(0);
2347 }
2348
2349 if (item->type == MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
2350 int argc;
2351 char **argv;
2352 const char *exe;
2353
2354 exec = lookup (item, MATE_DESKTOP_ITEM_EXEC"Exec");
2355 if (exec == NULL((void*)0))
2356 return FALSE(0);
2357
2358 if ( ! g_shell_parse_argv (exec, &argc, &argv, NULL((void*)0)))
2359 return FALSE(0);
2360
2361 if (argc < 1) {
2362 g_strfreev (argv);
2363 return FALSE(0);
2364 }
2365
2366 exe = argv[0];
2367
2368 if ( ! exec_exists (exe)) {
2369 g_strfreev (argv);
2370 return FALSE(0);
2371 }
2372 g_strfreev (argv);
2373 }
2374
2375 return TRUE(!(0));
2376}
2377
2378/**
2379 * mate_desktop_item_get_entry_type:
2380 * @item: A desktop item
2381 *
2382 * Gets the type attribute (the 'Type' field) of the item. This should
2383 * usually be 'Application' for an application, but it can be 'Directory'
2384 * for a directory description. There are other types available as well.
2385 * The type usually indicates how the desktop item should be handeled and
2386 * how the 'Exec' field should be handeled.
2387 *
2388 * Returns: The type of the specified 'item'. The returned
2389 * memory remains owned by the MateDesktopItem and should not be freed.
2390 */
2391MateDesktopItemType
2392mate_desktop_item_get_entry_type (const MateDesktopItem *item)
2393{
2394 g_return_val_if_fail (item != NULL, 0)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (0); } } while (0)
;
2395 g_return_val_if_fail (item->refcount > 0, 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (0); } } while (0)
;
2396
2397 return item->type;
2398}
2399
2400void
2401mate_desktop_item_set_entry_type (MateDesktopItem *item,
2402 MateDesktopItemType type)
2403{
2404 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2405 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2406
2407 item->type = type;
2408
2409 switch (type) {
2410 case MATE_DESKTOP_ITEM_TYPE_NULL:
2411 set (item, MATE_DESKTOP_ITEM_TYPE"Type", NULL((void*)0));
2412 break;
2413 case MATE_DESKTOP_ITEM_TYPE_APPLICATION:
2414 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Application");
2415 break;
2416 case MATE_DESKTOP_ITEM_TYPE_LINK:
2417 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Link");
2418 break;
2419 case MATE_DESKTOP_ITEM_TYPE_FSDEVICE:
2420 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "FSDevice");
2421 break;
2422 case MATE_DESKTOP_ITEM_TYPE_MIME_TYPE:
2423 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "MimeType");
2424 break;
2425 case MATE_DESKTOP_ITEM_TYPE_DIRECTORY:
2426 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Directory");
2427 break;
2428 case MATE_DESKTOP_ITEM_TYPE_SERVICE:
2429 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Service");
2430 break;
2431 case MATE_DESKTOP_ITEM_TYPE_SERVICE_TYPE:
2432 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "ServiceType");
2433 break;
2434 default:
2435 break;
2436 }
2437}
2438
2439/**
2440 * mate_desktop_item_get_file_status:
2441 * @item: A desktop item
2442 *
2443 * This function checks the modification time of the on-disk file to
2444 * see if it is more recent than the in-memory data.
2445 *
2446 * Returns: An enum value that specifies whether the item has changed since being loaded.
2447 */
2448MateDesktopItemStatus
2449mate_desktop_item_get_file_status (const MateDesktopItem *item)
2450{
2451 MateDesktopItemStatus retval;
2452 GFile *file;
2453 GFileInfo *info;
2454
2455 g_return_val_if_fail (item != NULL, MATE_DESKTOP_ITEM_DISAPPEARED)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (MATE_DESKTOP_ITEM_DISAPPEARED); } } while (0)
;
2456 g_return_val_if_fail (item->refcount > 0, MATE_DESKTOP_ITEM_DISAPPEARED)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (MATE_DESKTOP_ITEM_DISAPPEARED); } } while (0)
;
2457
2458 if (item->location == NULL((void*)0))
2459 return MATE_DESKTOP_ITEM_DISAPPEARED;
2460
2461 file = g_file_new_for_uri (item->location);
2462 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2463 G_FILE_QUERY_INFO_NONE, NULL((void*)0), NULL((void*)0));
2464
2465 retval = MATE_DESKTOP_ITEM_UNCHANGED;
2466
2467 if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2468 retval = MATE_DESKTOP_ITEM_DISAPPEARED;
2469 else if (((guint64) item->mtime) < g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2470 retval = MATE_DESKTOP_ITEM_CHANGED;
2471
2472 g_object_unref (info);
2473 g_object_unref (file);
2474
2475 return retval;
2476}
2477
2478/**
2479 * mate_desktop_item_find_icon:
2480 * @icon_theme: a #GtkIconTheme
2481 * @icon: icon name, something you'd get out of the Icon key
2482 * @desired_size: FIXME
2483 * @flags: FIXME
2484 *
2485 * Description: This function goes and looks for the icon file. If the icon
2486 * is not an absolute filename, this will look for it in the standard places.
2487 * If it can't find the icon, it will return %NULL
2488 *
2489 * Returns: A newly allocated string
2490 */
2491char *
2492mate_desktop_item_find_icon (GtkIconTheme *icon_theme,
2493 const char *icon,
2494 int desired_size,
2495 int flags)
2496{
2497 GtkIconInfo *info;
2498 char *full = NULL((void*)0);
2499
2500 g_return_val_if_fail (icon_theme == NULL ||do { if ((icon_theme == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((icon_theme)); GType __t = ((gtk_icon_theme_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "icon_theme == NULL || GTK_IS_ICON_THEME (icon_theme)"
); return (((void*)0)); } } while (0)
2501 GTK_IS_ICON_THEME (icon_theme), NULL)do { if ((icon_theme == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((icon_theme)); GType __t = ((gtk_icon_theme_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "icon_theme == NULL || GTK_IS_ICON_THEME (icon_theme)"
); return (((void*)0)); } } while (0)
;
2502
2503 if (icon == NULL((void*)0) || strcmp(icon,"") == 0) {
2504 return NULL((void*)0);
2505 } else if (g_path_is_absolute (icon)) {
2506 if (g_file_test (icon, G_FILE_TEST_EXISTS)) {
2507 return g_strdup (icon)g_strdup_inline (icon);
2508 } else {
2509 return NULL((void*)0);
2510 }
2511 } else {
2512 char *icon_no_extension;
2513 char *p;
2514
2515 if (icon_theme == NULL((void*)0))
2516 icon_theme = gtk_icon_theme_get_default ();
2517
2518 icon_no_extension = g_strdup (icon)g_strdup_inline (icon);
2519 p = strrchr (icon_no_extension, '.');
2520 if (p &&
2521 (strcmp (p, ".png") == 0 ||
2522 strcmp (p, ".xpm") == 0 ||
2523 strcmp (p, ".svg") == 0)) {
2524 *p = 0;
2525 }
2526
2527 info = gtk_icon_theme_lookup_icon (icon_theme,
2528 icon_no_extension,
2529 desired_size,
2530 0);
2531
2532 full = NULL((void*)0);
2533 if (info) {
2534 full = g_strdup (gtk_icon_info_get_filename (info))g_strdup_inline (gtk_icon_info_get_filename (info));
2535 g_object_unref (info);
2536 }
2537 g_free (icon_no_extension);
2538 }
2539
2540 return full;
2541
2542}
2543
2544/**
2545 * mate_desktop_item_get_icon:
2546 * @icon_theme: a #GtkIconTheme
2547 * @item: A desktop item
2548 *
2549 * Description: This function goes and looks for the icon file. If the icon
2550 * is not set as an absolute filename, this will look for it in the standard places.
2551 * If it can't find the icon, it will return %NULL
2552 *
2553 * Returns: A newly allocated string
2554 */
2555char *
2556mate_desktop_item_get_icon (const MateDesktopItem *item,
2557 GtkIconTheme *icon_theme)
2558{
2559 /* maybe this function should be deprecated in favour of find icon
2560 * -George */
2561 const char *icon;
2562
2563 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2564 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2565
2566 icon = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_ICON"Icon");
2567
2568 return mate_desktop_item_find_icon (icon_theme, icon,
2569 48 /* desired_size */,
2570 0 /* flags */);
2571}
2572
2573/**
2574 * mate_desktop_item_get_location:
2575 * @item: A desktop item
2576 *
2577 * Returns: The file location associated with 'item'.
2578 *
2579 */
2580const char *
2581mate_desktop_item_get_location (const MateDesktopItem *item)
2582{
2583 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2584 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2585
2586 return item->location;
2587}
2588
2589/**
2590 * mate_desktop_item_set_location:
2591 * @item: A desktop item
2592 * @location: A uri string specifying the file location of this particular item.
2593 *
2594 * Set's the 'location' uri of this item.
2595 */
2596void
2597mate_desktop_item_set_location (MateDesktopItem *item, const char *location)
2598{
2599 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2600 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2601
2602 if (item->location != NULL((void*)0) &&
2603 location != NULL((void*)0) &&
2604 strcmp (item->location, location) == 0)
2605 return;
2606
2607 g_free (item->location);
2608 item->location = g_strdup (location)g_strdup_inline (location);
2609
2610 /* This is ugly, but useful internally */
2611 if (item->mtime != DONT_UPDATE_MTIME((gint64)-2)) {
2612 item->mtime = 0;
2613
2614 if (item->location) {
2615 GFile *file;
2616 GFileInfo *info;
2617
2618 file = g_file_new_for_uri (item->location);
2619
2620 info = g_file_query_info (file,
2621 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2622 G_FILE_QUERY_INFO_NONE,
2623 NULL((void*)0), NULL((void*)0));
2624 if (info) {
2625 if (g_file_info_has_attribute (info,
2626 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2627 item->mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
2628 g_object_unref (info);
2629 }
2630
2631 g_object_unref (file);
2632 }
2633 }
2634
2635 /* Make sure that save actually saves */
2636 item->modified = TRUE(!(0));
2637}
2638
2639/**
2640 * mate_desktop_item_set_location_file:
2641 * @item: A desktop item
2642 * @file: A local filename specifying the file location of this particular item.
2643 *
2644 * Set's the 'location' uri of this item to the given @file.
2645 */
2646void
2647mate_desktop_item_set_location_file (MateDesktopItem *item, const char *file)
2648{
2649 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2650 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2651
2652 if (file != NULL((void*)0)) {
2653 GFile *gfile;
2654
2655 gfile = g_file_new_for_path (file);
2656 mate_desktop_item_set_location_gfile (item, gfile);
2657 g_object_unref (gfile);
2658 } else {
2659 mate_desktop_item_set_location (item, NULL((void*)0));
2660 }
2661}
2662
2663static void
2664mate_desktop_item_set_location_gfile (MateDesktopItem *item, GFile *file)
2665{
2666 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2667 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2668
2669 if (file != NULL((void*)0)) {
2670 char *uri;
2671
2672 uri = g_file_get_uri (file);
2673 mate_desktop_item_set_location (item, uri);
2674 g_free (uri);
2675 } else {
2676 mate_desktop_item_set_location (item, NULL((void*)0));
2677 }
2678}
2679
2680/*
2681 * Reading/Writing different sections, NULL is the standard section
2682 */
2683
2684gboolean
2685mate_desktop_item_attr_exists (const MateDesktopItem *item,
2686 const char *attr)
2687{
2688 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2689 g_return_val_if_fail (item->refcount > 0, FALSE)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return ((0)); } } while (0)
;
2690 g_return_val_if_fail (attr != NULL, FALSE)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return ((0)); } } while (0)
;
2691
2692 return lookup (item, attr) != NULL((void*)0);
2693}
2694
2695/*
2696 * String type
2697 */
2698const char *
2699mate_desktop_item_get_string (const MateDesktopItem *item,
2700 const char *attr)
2701{
2702 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2703 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2704 g_return_val_if_fail (attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2705
2706 return lookup (item, attr);
2707}
2708
2709void
2710mate_desktop_item_set_string (MateDesktopItem *item,
2711 const char *attr,
2712 const char *value)
2713{
2714 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2715 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2716 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2717
2718 set (item, attr, value);
2719
2720 if (strcmp (attr, MATE_DESKTOP_ITEM_TYPE"Type") == 0)
2721 item->type = type_from_string (value);
2722}
2723
2724/*
2725 * LocaleString type
2726 */
2727const char* mate_desktop_item_get_localestring(const MateDesktopItem* item, const char* attr)
2728{
2729 g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2730 g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2731 g_return_val_if_fail(attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2732
2733 return lookup_best_locale(item, attr);
2734}
2735
2736const char* mate_desktop_item_get_localestring_lang(const MateDesktopItem* item, const char* attr, const char* language)
2737{
2738 g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2739 g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2740 g_return_val_if_fail(attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2741
2742 return lookup_locale(item, attr, language);
2743}
2744
2745/**
2746 * mate_desktop_item_get_string_locale:
2747 * @item: A desktop item
2748 * @attr: An attribute name
2749 *
2750 * Returns the current locale that is used for the given attribute.
2751 * This might not be the same for all attributes. For example, if your
2752 * locale is "en_US.ISO8859-1" but attribute FOO only has "en_US" then
2753 * that would be returned for attr = "FOO". If attribute BAR has
2754 * "en_US.ISO8859-1" then that would be returned for "BAR".
2755 *
2756 * Returns: a string equal to the current locale or NULL
2757 * if the attribute is invalid or there is no matching locale.
2758 */
2759const char *
2760mate_desktop_item_get_attr_locale (const MateDesktopItem *item,
2761 const char *attr)
2762{
2763 const char * const *langs_pointer;
2764 int i;
2765
2766 langs_pointer = g_get_language_names ();
2767 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
2768 const char *value = NULL((void*)0);
2769
2770 value = lookup_locale (item, attr, langs_pointer[i]);
2771 if (value)
2772 return langs_pointer[i];
2773 }
2774
2775 return NULL((void*)0);
2776}
2777
2778GList *
2779mate_desktop_item_get_languages (const MateDesktopItem *item,
2780 const char *attr)
2781{
2782 GList *li;
2783 GList *list = NULL((void*)0);
2784
2785 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2786 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2787
2788 for (li = item->languages; li != NULL((void*)0); li = li->next) {
2789 char *language = li->data;
2790 if (attr == NULL((void*)0) ||
2791 lookup_locale (item, attr, language) != NULL((void*)0)) {
2792 list = g_list_prepend (list, language);
2793 }
2794 }
2795
2796 return g_list_reverse (list);
2797}
2798
2799static const char *
2800get_language (void)
2801{
2802 const char * const *langs_pointer;
2803 int i;
2804
2805 langs_pointer = g_get_language_names ();
2806 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
2807 /* find first without encoding */
2808 if (strchr (langs_pointer[i], '.') == NULL((void*)0)) {
2809 return langs_pointer[i];
2810 }
2811 }
2812 return NULL((void*)0);
2813}
2814
2815void
2816mate_desktop_item_set_localestring (MateDesktopItem *item,
2817 const char *attr,
2818 const char *value)
2819{
2820 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2821 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2822 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2823
2824 set_locale (item, attr, get_language (), value);
2825}
2826
2827void
2828mate_desktop_item_set_localestring_lang (MateDesktopItem *item,
2829 const char *attr,
2830 const char *language,
2831 const char *value)
2832{
2833 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2834 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2835 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2836
2837 set_locale (item, attr, language, value);
2838}
2839
2840void
2841mate_desktop_item_clear_localestring (MateDesktopItem *item,
2842 const char *attr)
2843{
2844 GList *l;
2845
2846 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2847 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2848 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2849
2850 for (l = item->languages; l != NULL((void*)0); l = l->next)
2851 set_locale (item, attr, l->data, NULL((void*)0));
2852
2853 set (item, attr, NULL((void*)0));
2854}
2855
2856/*
2857 * Strings, Regexps types
2858 */
2859
2860char **
2861mate_desktop_item_get_strings (const MateDesktopItem *item,
2862 const char *attr)
2863{
2864 const char *value;
2865
2866 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2867 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2868 g_return_val_if_fail (attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2869
2870 value = lookup (item, attr);
2871 if (value == NULL((void*)0))
2872 return NULL((void*)0);
2873
2874 /* FIXME: there's no way to escape semicolons apparently */
2875 return g_strsplit (value, ";", -1);
2876}
2877
2878void
2879mate_desktop_item_set_strings (MateDesktopItem *item,
2880 const char *attr,
2881 char **strings)
2882{
2883 char *str, *str2;
2884
2885 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2886 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2887 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2888
2889 str = g_strjoinv (";", strings);
2890 str2 = g_strconcat (str, ";", NULL((void*)0));
2891 /* FIXME: there's no way to escape semicolons apparently */
2892 set (item, attr, str2);
2893 g_free (str);
2894 g_free (str2);
2895}
2896
2897/*
2898 * Boolean type
2899 */
2900gboolean
2901mate_desktop_item_get_boolean (const MateDesktopItem *item,
2902 const char *attr)
2903{
2904 const char *value;
2905
2906 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2907 g_return_val_if_fail (item->refcount > 0, FALSE)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return ((0)); } } while (0)
;
2908 g_return_val_if_fail (attr != NULL, FALSE)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return ((0)); } } while (0)
;
2909
2910 value = lookup (item, attr);
2911 if (value == NULL((void*)0))
2912 return FALSE(0);
2913
2914 return (value[0] == 'T' ||
2915 value[0] == 't' ||
2916 value[0] == 'Y' ||
2917 value[0] == 'y' ||
2918 atoi (value) != 0);
2919}
2920
2921void
2922mate_desktop_item_set_boolean (MateDesktopItem *item,
2923 const char *attr,
2924 gboolean value)
2925{
2926 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2927 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2928 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2929
2930 set (item, attr, value ? "true" : "false");
2931}
2932
2933void
2934mate_desktop_item_set_launch_time (MateDesktopItem *item,
2935 guint32 timestamp)
2936{
2937 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2938
2939 item->launch_time = timestamp;
2940}
2941
2942/*
2943 * Clearing attributes
2944 */
2945void
2946mate_desktop_item_clear_section (MateDesktopItem *item,
2947 const char *section)
2948{
2949 Section *sec;
2950 GList *li;
2951
2952 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2953 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2954
2955 sec = find_section (item, section);
2956
2957 if (sec == NULL((void*)0)) {
2958 for (li = item->keys; li != NULL((void*)0); li = li->next) {
2959 g_hash_table_remove (item->main_hash, li->data);
2960 g_free (li->data);
2961 li->data = NULL((void*)0);
2962 }
2963 g_list_free (item->keys);
2964 item->keys = NULL((void*)0);
2965 } else {
2966 for (li = sec->keys; li != NULL((void*)0); li = li->next) {
2967 char *key = li->data;
2968 char *full = g_strdup_printf ("%s/%s",
2969 sec->name, key);
2970 g_hash_table_remove (item->main_hash, full);
2971 g_free (full);
2972 g_free (key);
2973 li->data = NULL((void*)0);
2974 }
2975 g_list_free (sec->keys);
2976 sec->keys = NULL((void*)0);
2977 }
2978 item->modified = TRUE(!(0));
2979}
2980
2981/************************************************************
2982 * Parser: *
2983 ************************************************************/
2984
2985static gboolean G_GNUC_CONST__attribute__ ((__const__))
2986standard_is_boolean (const char * key)
2987{
2988 static GHashTable *bools = NULL((void*)0);
2989
2990 if (bools == NULL((void*)0)) {
2991 bools = g_hash_table_new (g_str_hash, g_str_equal);
2992 g_hash_table_insert (bools,
2993 MATE_DESKTOP_ITEM_NO_DISPLAY"NoDisplay",
2994 MATE_DESKTOP_ITEM_NO_DISPLAY"NoDisplay");
2995 g_hash_table_insert (bools,
2996 MATE_DESKTOP_ITEM_HIDDEN"Hidden",
2997 MATE_DESKTOP_ITEM_HIDDEN"Hidden");
2998 g_hash_table_insert (bools,
2999 MATE_DESKTOP_ITEM_TERMINAL"Terminal",
3000 MATE_DESKTOP_ITEM_TERMINAL"Terminal");
3001 g_hash_table_insert (bools,
3002 MATE_DESKTOP_ITEM_READ_ONLY"ReadOnly",
3003 MATE_DESKTOP_ITEM_READ_ONLY"ReadOnly");
3004 }
3005
3006 return g_hash_table_lookup (bools, key) != NULL((void*)0);
3007}
3008
3009static gboolean G_GNUC_CONST__attribute__ ((__const__))
3010standard_is_strings (const char *key)
3011{
3012 static GHashTable *strings = NULL((void*)0);
3013
3014 if (strings == NULL((void*)0)) {
3015 strings = g_hash_table_new (g_str_hash, g_str_equal);
3016 g_hash_table_insert (strings,
3017 MATE_DESKTOP_ITEM_FILE_PATTERN"FilePattern",
3018 MATE_DESKTOP_ITEM_FILE_PATTERN"FilePattern");
3019 g_hash_table_insert (strings,
3020 MATE_DESKTOP_ITEM_ACTIONS"Actions",
3021 MATE_DESKTOP_ITEM_ACTIONS"Actions");
3022 g_hash_table_insert (strings,
3023 MATE_DESKTOP_ITEM_MIME_TYPE"MimeType",
3024 MATE_DESKTOP_ITEM_MIME_TYPE"MimeType");
3025 g_hash_table_insert (strings,
3026 MATE_DESKTOP_ITEM_PATTERNS"Patterns",
3027 MATE_DESKTOP_ITEM_PATTERNS"Patterns");
3028 g_hash_table_insert (strings,
3029 MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder",
3030 MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder");
3031 }
3032
3033 return g_hash_table_lookup (strings, key) != NULL((void*)0);
3034}
3035
3036/* If no need to cannonize, returns NULL */
3037static char *
3038cannonize (const char *key, const char *value)
3039{
3040 if (standard_is_boolean (key)) {
3041 if (value[0] == 'T' ||
3042 value[0] == 't' ||
3043 value[0] == 'Y' ||
3044 value[0] == 'y' ||
3045 atoi (value) != 0) {
3046 return g_strdup ("true")g_strdup_inline ("true");
3047 } else {
3048 return g_strdup ("false")g_strdup_inline ("false");
3049 }
3050 } else if (standard_is_strings (key)) {
3051 int len = strlen (value);
3052 if (len == 0 || value[len-1] != ';') {
3053 return g_strconcat (value, ";", NULL((void*)0));
3054 }
3055 }
3056 /* XXX: Perhaps we should canonize numeric values as well, but this
3057 * has caused some subtle problems before so it needs to be done
3058 * carefully if at all */
3059 return NULL((void*)0);
3060}
3061
3062static char *
3063decode_string_and_dup (const char *s)
3064{
3065 char *p = g_malloc (strlen (s) + 1);
3066 char *q = p;
3067
3068 do {
3069 if (*s == '\\'){
3070 switch (*(++s)){
3071 case 's':
3072 *p++ = ' ';
3073 break;
3074 case 't':
3075 *p++ = '\t';
3076 break;
3077 case 'n':
3078 *p++ = '\n';
3079 break;
3080 case '\\':
3081 *p++ = '\\';
3082 break;
3083 case 'r':
3084 *p++ = '\r';
3085 break;
3086 default:
3087 *p++ = '\\';
3088 *p++ = *s;
3089 break;
3090 }
3091 } else {
3092 *p++ = *s;
3093 }
3094 } while (*s++);
3095
3096 return q;
3097}
3098
3099static char *
3100escape_string_and_dup (const char *s)
3101{
3102 char *return_value, *p;
3103 const char *q;
3104 int len = 0;
3105
3106 if (s
15.1
's' is not equal to NULL
== NULL((void*)0))
16
Taking false branch
3107 return g_strdup("")g_strdup_inline ("");
3108
3109 q = s;
3110 while (*q){
17
Loop condition is true. Entering loop body
20
Loop condition is true. Entering loop body
23
Loop condition is true. Entering loop body
26
Loop condition is false. Execution continues on line 3116
3111 len++;
3112 if (strchr ("\n\r\t\\", *q) != NULL((void*)0))
18
Assuming the condition is false
19
Taking false branch
21
Assuming the condition is false
22
Taking false branch
24
Assuming the condition is false
25
Taking false branch
3113 len++;
3114 q++;
3115 }
3116 return_value = p = (char *) g_malloc (len + 1);
3117 do {
29
Loop condition is true. Execution continues on line 3118
32
Loop condition is true. Execution continues on line 3118
3118 switch (*s){
27
Control jumps to 'case 92:' at line 3131
30
Control jumps to 'case 92:' at line 3131
33
Control jumps to 'case 9:' at line 3119
3119 case '\t':
3120 *p++ = '\\';
34
Out of bound memory access (access exceeds upper limit of memory block)
3121 *p++ = 't';
3122 break;
3123 case '\n':
3124 *p++ = '\\';
3125 *p++ = 'n';
3126 break;
3127 case '\r':
3128 *p++ = '\\';
3129 *p++ = 'r';
3130 break;
3131 case '\\':
3132 *p++ = '\\';
3133 *p++ = '\\';
3134 break;
28
Execution continues on line 3138
31
Execution continues on line 3138
3135 default:
3136 *p++ = *s;
3137 }
3138 } while (*s++);
3139 return return_value;
3140}
3141
3142static gboolean
3143check_locale (const char *locale)
3144{
3145 GIConv cd = g_iconv_open ("UTF-8", locale);
3146 if ((GIConv)-1 == cd)
3147 return FALSE(0);
3148 g_iconv_close (cd);
3149 return TRUE(!(0));
3150}
3151
3152static void
3153insert_locales (GHashTable *encodings, char *enc, ...)
3154{
3155 va_list args;
3156 char *s;
3157
3158 va_start (args, enc)__builtin_va_start(args, enc);
3159 for (;;) {
3160 s = va_arg (args, char *)__builtin_va_arg(args, char *);
3161 if (s == NULL((void*)0))
3162 break;
3163 g_hash_table_insert (encodings, s, enc);
3164 }
3165 va_end (args)__builtin_va_end(args);
3166}
3167
3168/* make a standard conversion table from the desktop standard spec */
3169static GHashTable *
3170init_encodings (void)
3171{
3172 GHashTable *encodings = g_hash_table_new (g_str_hash, g_str_equal);
3173
3174 /* "C" is plain ascii */
3175 insert_locales (encodings, "ASCII", "C", NULL((void*)0));
3176
3177 insert_locales (encodings, "ARMSCII-8", "by", NULL((void*)0));
3178 insert_locales (encodings, "BIG5", "zh_TW", NULL((void*)0));
3179 insert_locales (encodings, "CP1251", "be", "bg", NULL((void*)0));
3180 if (check_locale ("EUC-CN")) {
3181 insert_locales (encodings, "EUC-CN", "zh_CN", NULL((void*)0));
3182 } else {
3183 insert_locales (encodings, "GB2312", "zh_CN", NULL((void*)0));
3184 }
3185 insert_locales (encodings, "EUC-JP", "ja", NULL((void*)0));
3186 insert_locales (encodings, "EUC-KR", "ko", NULL((void*)0));
3187 /*insert_locales (encodings, "GEORGIAN-ACADEMY", NULL);*/
3188 insert_locales (encodings, "GEORGIAN-PS", "ka", NULL((void*)0));
3189 insert_locales (encodings, "ISO-8859-1", "br", "ca", "da", "de", "en", "es", "eu", "fi", "fr", "gl", "it", "nl", "wa", "no", "pt", "pt", "sv", NULL((void*)0));
3190 insert_locales (encodings, "ISO-8859-2", "cs", "hr", "hu", "pl", "ro", "sk", "sl", "sq", "sr", NULL((void*)0));
3191 insert_locales (encodings, "ISO-8859-3", "eo", NULL((void*)0));
3192 insert_locales (encodings, "ISO-8859-5", "mk", "sp", NULL((void*)0));
3193 insert_locales (encodings, "ISO-8859-7", "el", NULL((void*)0));
3194 insert_locales (encodings, "ISO-8859-9", "tr", NULL((void*)0));
3195 insert_locales (encodings, "ISO-8859-13", "lt", "lv", "mi", NULL((void*)0));
3196 insert_locales (encodings, "ISO-8859-14", "ga", "cy", NULL((void*)0));
3197 insert_locales (encodings, "ISO-8859-15", "et", NULL((void*)0));
3198 insert_locales (encodings, "KOI8-R", "ru", NULL((void*)0));
3199 insert_locales (encodings, "KOI8-U", "uk", NULL((void*)0));
3200 if (check_locale ("TCVN-5712")) {
3201 insert_locales (encodings, "TCVN-5712", "vi", NULL((void*)0));
3202 } else {
3203 insert_locales (encodings, "TCVN", "vi", NULL((void*)0));
3204 }
3205 insert_locales (encodings, "TIS-620", "th", NULL((void*)0));
3206 /*insert_locales (encodings, "VISCII", NULL);*/
3207
3208 return encodings;
3209}
3210
3211static const char *
3212get_encoding_from_locale (const char *locale)
3213{
3214 char lang[3];
3215 const char *encoding;
3216 static GHashTable *encodings = NULL((void*)0);
3217
3218 if (locale == NULL((void*)0))
3219 return NULL((void*)0);
3220
3221 /* if locale includes encoding, use it */
3222 encoding = strchr (locale, '.');
3223 if (encoding != NULL((void*)0)) {
3224 return encoding+1;
3225 }
3226
3227 if (encodings == NULL((void*)0))
3228 encodings = init_encodings ();
3229
3230 /* first try the entire locale (at this point ll_CC) */
3231 encoding = g_hash_table_lookup (encodings, locale);
3232 if (encoding != NULL((void*)0))
3233 return encoding;
3234
3235 /* Try just the language */
3236 strncpy (lang, locale, 2);
3237 lang[2] = '\0';
3238 return g_hash_table_lookup (encodings, lang);
3239}
3240
3241static Encoding
3242get_encoding (ReadBuf *rb)
3243{
3244 gboolean old_kde = FALSE(0);
3245 char buf [BUFSIZ8192];
3246 gboolean all_valid_utf8 = TRUE(!(0));
3247
3248 while (readbuf_gets (buf, sizeof (buf), rb) != NULL((void*)0)) {
3249 if (strncmp (MATE_DESKTOP_ITEM_ENCODING"Encoding",
3250 buf,
3251 strlen (MATE_DESKTOP_ITEM_ENCODING"Encoding")) == 0) {
3252 char *p = &buf[strlen (MATE_DESKTOP_ITEM_ENCODING"Encoding")];
3253 if (*p == ' ')
3254 p++;
3255 if (*p != '=')
3256 continue;
3257 p++;
3258 if (*p == ' ')
3259 p++;
3260 if (strcmp (p, "UTF-8") == 0) {
3261 return ENCODING_UTF8;
3262 } else if (strcmp (p, "Legacy-Mixed") == 0) {
3263 return ENCODING_LEGACY_MIXED;
3264 } else {
3265 /* According to the spec we're not supposed
3266 * to read a file like this */
3267 return ENCODING_UNKNOWN;
3268 }
3269 } else if (strcmp ("[KDE Desktop Entry]", buf) == 0) {
3270 old_kde = TRUE(!(0));
3271 /* don't break yet, we still want to support
3272 * Encoding even here */
3273 }
3274 if (all_valid_utf8 && ! g_utf8_validate (buf, -1, NULL((void*)0)))
3275 all_valid_utf8 = FALSE(0);
3276 }
3277
3278 if (old_kde)
3279 return ENCODING_LEGACY_MIXED;
3280
3281 /* try to guess by location */
3282 if (rb->uri != NULL((void*)0) && strstr (rb->uri, "mate/apps/") != NULL((void*)0)) {
3283 /* old mate */
3284 return ENCODING_LEGACY_MIXED;
3285 }
3286
3287 /* A dilemma, new KDE files are in UTF-8 but have no Encoding
3288 * info, at this time we really can't tell. The best thing to
3289 * do right now is to just assume UTF-8 if the whole file
3290 * validates as utf8 I suppose */
3291
3292 if (all_valid_utf8)
3293 return ENCODING_UTF8;
3294 else
3295 return ENCODING_LEGACY_MIXED;
3296}
3297
3298static char *
3299decode_string (const char *value, Encoding encoding, const char *locale)
3300{
3301 char *retval = NULL((void*)0);
3302
3303 /* if legacy mixed, then convert */
3304 if (locale != NULL((void*)0) && encoding == ENCODING_LEGACY_MIXED) {
3305 const char *char_encoding = get_encoding_from_locale (locale);
3306 char *utf8_string;
3307 if (char_encoding == NULL((void*)0))
3308 return NULL((void*)0);
3309 if (strcmp (char_encoding, "ASCII") == 0) {
3310 return decode_string_and_dup (value);
3311 }
3312 utf8_string = g_convert (value, -1, "UTF-8", char_encoding,
3313 NULL((void*)0), NULL((void*)0), NULL((void*)0));
3314 if (utf8_string == NULL((void*)0))
3315 return NULL((void*)0);
3316 retval = decode_string_and_dup (utf8_string);
3317 g_free (utf8_string);
3318 return retval;
3319 /* if utf8, then validate */
3320 } else if (locale != NULL((void*)0) && encoding == ENCODING_UTF8) {
3321 if ( ! g_utf8_validate (value, -1, NULL((void*)0)))
3322 /* invalid utf8, ignore this key */
3323 return NULL((void*)0);
3324 return decode_string_and_dup (value);
3325 } else {
3326 /* Meaning this is not a localized string */
3327 return decode_string_and_dup (value);
3328 }
3329}
3330
3331static char *
3332snarf_locale_from_key (const char *key)
3333{
3334 const char *brace;
3335 char *locale, *p;
3336
3337 brace = strchr (key, '[');
3338 if (brace == NULL((void*)0))
3339 return NULL((void*)0);
3340
3341 locale = g_strdup (brace + 1)g_strdup_inline (brace + 1);
3342 if (*locale == '\0') {
3343 g_free (locale);
3344 return NULL((void*)0);
3345 }
3346 p = strchr (locale, ']');
3347 if (p == NULL((void*)0)) {
3348 g_free (locale);
3349 return NULL((void*)0);
3350 }
3351 *p = '\0';
3352 return locale;
3353}
3354
3355static void
3356insert_key (MateDesktopItem *item,
3357 Section *cur_section,
3358 Encoding encoding,
3359 const char *key,
3360 const char *value,
3361 gboolean old_kde,
3362 gboolean no_translations)
3363{
3364 char *k;
3365 char *val;
3366 /* we always store everything in UTF-8 */
3367 if (cur_section == NULL((void*)0) &&
3368 strcmp (key, MATE_DESKTOP_ITEM_ENCODING"Encoding") == 0) {
3369 k = g_strdup (key)g_strdup_inline (key);
3370 val = g_strdup ("UTF-8")g_strdup_inline ("UTF-8");
3371 } else {
3372 char *locale = snarf_locale_from_key (key);
3373 /* If we're ignoring translations */
3374 if (no_translations && locale != NULL((void*)0)) {
3375 g_free (locale);
3376 return;
3377 }
3378 val = decode_string (value, encoding, locale);
3379
3380 /* Ignore this key, it's whacked */
3381 if (val == NULL((void*)0)) {
3382 g_free (locale);
3383 return;
3384 }
3385
3386 g_strchomp (val);
3387
3388 /* For old KDE entries, we can also split by a comma
3389 * on sort order, so convert to semicolons */
3390 if (old_kde &&
3391 cur_section == NULL((void*)0) &&
3392 strcmp (key, MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder") == 0 &&
3393 strchr (val, ';') == NULL((void*)0)) {
3394 int i;
3395 for (i = 0; val[i] != '\0'; i++) {
3396 if (val[i] == ',')
3397 val[i] = ';';
3398 }
3399 }
3400
3401 /* Check some types, not perfect, but catches a lot
3402 * of things */
3403 if (cur_section == NULL((void*)0)) {
3404 char *cannon = cannonize (key, val);
3405 if (cannon != NULL((void*)0)) {
3406 g_free (val);
3407 val = cannon;
3408 }
3409 }
3410
3411 k = g_strdup (key)g_strdup_inline (key);
3412
3413 /* Take care of the language part */
3414 if (locale != NULL((void*)0) &&
3415 strcmp (locale, "C") == 0) {
3416 char *p;
3417 /* Whack C locale */
3418 p = strchr (k, '[');
3419 *p = '\0';
3420 g_free (locale);
3421 } else if (locale != NULL((void*)0)) {
3422 char *p, *brace;
3423
3424 /* Whack the encoding part */
3425 p = strchr (locale, '.');
3426 if (p != NULL((void*)0))
3427 *p = '\0';
3428
3429 if (g_list_find_custom (item->languages, locale,
3430 (GCompareFunc)strcmp) == NULL((void*)0)) {
3431 item->languages = g_list_prepend
3432 (item->languages, locale);
3433 } else {
3434 g_free (locale);
3435 }
3436
3437 /* Whack encoding from encoding in the key */
3438 brace = strchr (k, '[');
3439 p = strchr (brace, '.');
3440 if (p != NULL((void*)0)) {
3441 *p = ']';
3442 *(p+1) = '\0';
3443 }
3444 }
3445 }
3446
3447 if (cur_section == NULL((void*)0)) {
3448 /* only add to list if we haven't seen it before */
3449 if (g_hash_table_lookup (item->main_hash, k) == NULL((void*)0)) {
3450 item->keys = g_list_prepend (item->keys,
3451 g_strdup (k)g_strdup_inline (k));
3452 }
3453 /* later duplicates override earlier ones */
3454 g_hash_table_replace (item->main_hash, k, val);
3455 } else {
3456 char *full = g_strdup_printf
3457 ("%s/%s",
3458 cur_section->name, k);
3459 /* only add to list if we haven't seen it before */
3460 if (g_hash_table_lookup (item->main_hash, full) == NULL((void*)0)) {
3461 cur_section->keys =
3462 g_list_prepend (cur_section->keys, k);
3463 }
3464 /* later duplicates override earlier ones */
3465 g_hash_table_replace (item->main_hash,
3466 full, val);
3467 }
3468}
3469
3470static void
3471setup_type (MateDesktopItem *item, const char *uri)
3472{
3473 const char *type = g_hash_table_lookup (item->main_hash,
3474 MATE_DESKTOP_ITEM_TYPE"Type");
3475 if (type == NULL((void*)0) && uri != NULL((void*)0)) {
3476 char *base = g_path_get_basename (uri);
3477 if (base != NULL((void*)0) &&
3478 strcmp (base, ".directory") == 0) {
3479 /* This gotta be a directory */
3480 g_hash_table_replace (item->main_hash,
3481 g_strdup (MATE_DESKTOP_ITEM_TYPE)g_strdup_inline ("Type"),
3482 g_strdup ("Directory")g_strdup_inline ("Directory"));
3483 item->keys = g_list_prepend
3484 (item->keys, g_strdup (MATE_DESKTOP_ITEM_TYPE)g_strdup_inline ("Type"));
3485 item->type = MATE_DESKTOP_ITEM_TYPE_DIRECTORY;
3486 } else {
3487 item->type = MATE_DESKTOP_ITEM_TYPE_NULL;
3488 }
3489 g_free (base);
3490 } else {
3491 item->type = type_from_string (type);
3492 }
3493}
3494
3495/* fallback to find something suitable for C locale */
3496static char *
3497try_english_key (MateDesktopItem *item, const char *key)
3498{
3499 char *str;
3500 char *locales[] = { "en_US", "en_GB", "en_AU", "en", NULL((void*)0) };
3501 int i;
3502
3503 str = NULL((void*)0);
3504 for (i = 0; locales[i] != NULL((void*)0) && str == NULL((void*)0); i++) {
3505 str = g_strdup (lookup_locale (item, key, locales[i]))g_strdup_inline (lookup_locale (item, key, locales[i]));
3506 }
3507 if (str != NULL((void*)0)) {
3508 /* We need a 7-bit ascii string, so whack all
3509 * above 127 chars */
3510 guchar *p;
3511 for (p = (guchar *)str; *p != '\0'; p++) {
3512 if (*p > 127)
3513 *p = '?';
3514 }
3515 }
3516 return str;
3517}
3518
3519static void
3520sanitize (MateDesktopItem *item, const char *uri)
3521{
3522 const char *type;
3523
3524 type = lookup (item, MATE_DESKTOP_ITEM_TYPE"Type");
3525
3526 /* understand old mate style url exec thingies */
3527 if (type != NULL((void*)0) && strcmp (type, "URL") == 0) {
3528 const char *exec = lookup (item, MATE_DESKTOP_ITEM_EXEC"Exec");
3529 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Link");
3530 if (exec != NULL((void*)0)) {
3531 /* Note, this must be in this order */
3532 set (item, MATE_DESKTOP_ITEM_URL"URL", exec);
3533 set (item, MATE_DESKTOP_ITEM_EXEC"Exec", NULL((void*)0));
3534 }
3535 }
3536
3537 /* we make sure we have Name, Encoding and Version */
3538 if (lookup (item, MATE_DESKTOP_ITEM_NAME"Name") == NULL((void*)0)) {
3539 char *name = try_english_key (item, MATE_DESKTOP_ITEM_NAME"Name");
3540 /* If no name, use the basename */
3541 if (name == NULL((void*)0) && uri != NULL((void*)0))
3542 name = g_path_get_basename (uri);
3543 /* If no uri either, use same default as mate_desktop_item_new */
3544 if (name == NULL((void*)0)) {
3545 /* Translators: the "name" mentioned here is the name of
3546 * an application or a document */
3547 name = g_strdup (_("No name"))g_strdup_inline (((char *) g_dgettext ("mate-desktop", "No name"
)))
;
3548 }
3549 g_hash_table_replace (item->main_hash,
3550 g_strdup (MATE_DESKTOP_ITEM_NAME)g_strdup_inline ("Name"),
3551 name);
3552 item->keys = g_list_prepend
3553 (item->keys, g_strdup (MATE_DESKTOP_ITEM_NAME)g_strdup_inline ("Name"));
3554 }
3555 if (lookup (item, MATE_DESKTOP_ITEM_ENCODING"Encoding") == NULL((void*)0)) {
3556 /* We store everything in UTF-8 so write that down */
3557 g_hash_table_replace (item->main_hash,
3558 g_strdup (MATE_DESKTOP_ITEM_ENCODING)g_strdup_inline ("Encoding"),
3559 g_strdup ("UTF-8")g_strdup_inline ("UTF-8"));
3560 item->keys = g_list_prepend
3561 (item->keys, g_strdup (MATE_DESKTOP_ITEM_ENCODING)g_strdup_inline ("Encoding"));
3562 }
3563 if (lookup (item, MATE_DESKTOP_ITEM_VERSION"Version") == NULL((void*)0)) {
3564 /* this is the version that we follow, so write it down */
3565 g_hash_table_replace (item->main_hash,
3566 g_strdup (MATE_DESKTOP_ITEM_VERSION)g_strdup_inline ("Version"),
3567 g_strdup ("1.0")g_strdup_inline ("1.0"));
3568 item->keys = g_list_prepend
3569 (item->keys, g_strdup (MATE_DESKTOP_ITEM_VERSION)g_strdup_inline ("Version"));
3570 }
3571}
3572
3573enum {
3574 FirstBrace,
3575 OnSecHeader,
3576 IgnoreToEOL,
3577 IgnoreToEOLFirst,
3578 KeyDef,
3579 KeyDefOnKey,
3580 KeyValue
3581};
3582
3583static MateDesktopItem *
3584ditem_load (ReadBuf *rb,
3585 gboolean no_translations,
3586 GError **error)
3587{
3588 int state;
3589 char CharBuffer [1024];
3590 char *next = CharBuffer;
3591 int c;
3592 Encoding encoding;
3593 MateDesktopItem *item;
3594 Section *cur_section = NULL((void*)0);
3595 char *key = NULL((void*)0);
3596 gboolean old_kde = FALSE(0);
3597
3598 encoding = get_encoding (rb);
3599 if (encoding == ENCODING_UNKNOWN) {
3600 /* spec says, don't read this file */
3601 g_set_error (error,
3602 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
3603 MATE_DESKTOP_ITEM_ERROR_UNKNOWN_ENCODING,
3604 _("Unknown encoding of: %s")((char *) g_dgettext ("mate-desktop", "Unknown encoding of: %s"
))
,
3605 rb->uri);
3606 readbuf_close (rb);
3607 return NULL((void*)0);
3608 }
3609
3610 /* Rewind since get_encoding goes through the file */
3611 if (! readbuf_rewind (rb, error)) {
3612 readbuf_close (rb);
3613 /* spec says, don't read this file */
3614 return NULL((void*)0);
3615 }
3616
3617 item = mate_desktop_item_new ();
3618 item->modified = FALSE(0);
3619
3620 /* Note: location and mtime are filled in by the new_from_file
3621 * function since it has those values */
3622
3623#define OVERFLOW (next == &CharBuffer [sizeof(CharBuffer)-1])
3624
3625 state = FirstBrace;
3626 while ((c = readbuf_getc (rb)) != EOF(-1)) {
3627 if (c == '\r') /* Ignore Carriage Return */
3628 continue;
3629
3630 switch (state) {
3631
3632 case OnSecHeader:
3633 if (c == ']' || OVERFLOW) {
3634 *next = '\0';
3635 next = CharBuffer;
3636
3637 /* keys were inserted in reverse */
3638 if (cur_section != NULL((void*)0) &&
3639 cur_section->keys != NULL((void*)0)) {
3640 cur_section->keys = g_list_reverse
3641 (cur_section->keys);
3642 }
3643 if (strcmp (CharBuffer,
3644 "KDE Desktop Entry") == 0) {
3645 /* Main section */
3646 cur_section = NULL((void*)0);
3647 old_kde = TRUE(!(0));
3648 } else if (strcmp (CharBuffer,
3649 "Desktop Entry") == 0) {
3650 /* Main section */
3651 cur_section = NULL((void*)0);
3652 } else {
3653 cur_section = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
3654 cur_section->name =
3655 g_strdup (CharBuffer)g_strdup_inline (CharBuffer);
3656 cur_section->keys = NULL((void*)0);
3657 item->sections = g_list_prepend
3658 (item->sections, cur_section);
3659 }
3660 state = IgnoreToEOL;
3661 } else if (c == '[') {
3662 /* FIXME: probably error out instead of ignoring this */
3663 } else {
3664 *next++ = c;
3665 }
3666 break;
3667
3668 case IgnoreToEOL:
3669 case IgnoreToEOLFirst:
3670 if (c == '\n'){
3671 if (state == IgnoreToEOLFirst)
3672 state = FirstBrace;
3673 else
3674 state = KeyDef;
3675 next = CharBuffer;
3676 }
3677 break;
3678
3679 case FirstBrace:
3680 case KeyDef:
3681 case KeyDefOnKey:
3682 if (c == '#') {
3683 if (state == FirstBrace)
3684 state = IgnoreToEOLFirst;
3685 else
3686 state = IgnoreToEOL;
3687 break;
3688 }
3689
3690 if (c == '[' && state != KeyDefOnKey){
3691 state = OnSecHeader;
3692 next = CharBuffer;
3693 g_free (key);
3694 key = NULL((void*)0);
3695 break;
3696 }
3697 /* On first pass, don't allow dangling keys */
3698 if (state == FirstBrace)
3699 break;
3700
3701 if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
3702 break;
3703
3704 if (c == '\n' || OVERFLOW) { /* Abort Definition */
3705 next = CharBuffer;
3706 state = KeyDef;
3707 break;
3708 }
3709
3710 if (c == '=' || OVERFLOW){
3711 *next = '\0';
3712
3713 g_free (key);
3714 key = g_strdup (CharBuffer)g_strdup_inline (CharBuffer);
3715 state = KeyValue;
3716 next = CharBuffer;
3717 } else {
3718 *next++ = c;
3719 state = KeyDefOnKey;
3720 }
3721 break;
3722
3723 case KeyValue:
3724 if (OVERFLOW || c == '\n'){
3725 *next = '\0';
3726
3727 insert_key (item, cur_section, encoding,
3728 key, CharBuffer, old_kde,
3729 no_translations);
3730
3731 g_free (key);
3732 key = NULL((void*)0);
3733
3734 state = (c == '\n') ? KeyDef : IgnoreToEOL;
3735 next = CharBuffer;
3736 } else {
3737 *next++ = c;
3738 }
3739 break;
3740
3741 } /* switch */
3742
3743 } /* while ((c = getc_unlocked (f)) != EOF) */
3744 if (c == EOF(-1) && state == KeyValue) {
3745 *next = '\0';
3746
3747 insert_key (item, cur_section, encoding,
3748 key, CharBuffer, old_kde,
3749 no_translations);
3750
3751 g_free (key);
3752 key = NULL((void*)0);
3753 }
3754
3755#undef OVERFLOW
3756
3757 /* keys were inserted in reverse */
3758 if (cur_section != NULL((void*)0) &&
3759 cur_section->keys != NULL((void*)0)) {
3760 cur_section->keys = g_list_reverse (cur_section->keys);
3761 }
3762 /* keys were inserted in reverse */
3763 item->keys = g_list_reverse (item->keys);
3764 /* sections were inserted in reverse */
3765 item->sections = g_list_reverse (item->sections);
3766
3767 /* sanitize some things */
3768 sanitize (item, rb->uri);
3769
3770 /* make sure that we set up the type */
3771 setup_type (item, rb->uri);
3772
3773 readbuf_close (rb);
3774
3775 return item;
3776}
3777
3778static void stream_printf (GFileOutputStream *stream,
3779 const char *format, ...) G_GNUC_PRINTF (2, 3)__attribute__((__format__ (__printf__, 2, 3)));
3780
3781static void
3782stream_printf (GFileOutputStream *stream, const char *format, ...)
3783{
3784 va_list args;
3785 gchar *s;
3786
3787 va_start (args, format)__builtin_va_start(args, format);
3788 s = g_strdup_vprintf (format, args);
3789 va_end (args)__builtin_va_end(args);
3790
3791 /* FIXME: what about errors */
3792 g_output_stream_write (G_OUTPUT_STREAM (stream)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((stream)), ((g_output_stream_get_type ()))))))
, s, strlen (s),
3793 NULL((void*)0), NULL((void*)0));
3794 g_free (s);
3795}
3796
3797static void
3798dump_section (MateDesktopItem *item, GFileOutputStream *stream, Section *section)
3799{
3800 GList *li;
3801
3802 stream_printf (stream, "[%s]\n", section->name);
3803 for (li = section->keys; li != NULL((void*)0); li = li->next) {
3804 const char *key = li->data;
3805 char *full = g_strdup_printf ("%s/%s", section->name, key);
3806 const char *value = g_hash_table_lookup (item->main_hash, full);
3807 if (value != NULL((void*)0)) {
3808 char *val = escape_string_and_dup (value);
3809 stream_printf (stream, "%s=%s\n", key, val);
3810 g_free (val);
3811 }
3812 g_free (full);
3813 }
3814}
3815
3816static gboolean
3817ditem_save (MateDesktopItem *item, const char *uri, GError **error)
3818{
3819 GList *li;
3820 GFile *file;
3821 GFileOutputStream *stream;
3822
3823 file = g_file_new_for_uri (uri);
3824 stream = g_file_replace (file, NULL((void*)0), FALSE(0), G_FILE_CREATE_NONE,
3825 NULL((void*)0), error);
3826 if (stream == NULL((void*)0))
5
Assuming 'stream' is not equal to NULL
6
Taking false branch
3827 return FALSE(0);
3828
3829 stream_printf (stream, "[Desktop Entry]\n");
3830 for (li = item->keys; li != NULL((void*)0); li = li->next) {
7
Assuming 'li' is not equal to NULL
8
Loop condition is true. Entering loop body
11
Assuming 'li' is not equal to NULL
12
Loop condition is true. Entering loop body
3831 const char *key = li->data;
3832 const char *value = g_hash_table_lookup (item->main_hash, key);
3833 if (value != NULL((void*)0)) {
9
Assuming 'value' is not equal to NULL
10
Taking true branch
13
Assuming 'value' is not equal to NULL
14
Taking true branch
3834 char *val = escape_string_and_dup (value);
15
Calling 'escape_string_and_dup'
3835 stream_printf (stream, "%s=%s\n", key, val);
3836 g_free (val);
3837 }
3838 }
3839
3840 if (item->sections != NULL((void*)0))
3841 stream_printf (stream, "\n");
3842
3843 for (li = item->sections; li != NULL((void*)0); li = li->next) {
3844 Section *section = li->data;
3845
3846 /* Don't write empty sections */
3847 if (section->keys == NULL((void*)0))
3848 continue;
3849
3850 dump_section (item, stream, section);
3851
3852 if (li->next != NULL((void*)0))
3853 stream_printf (stream, "\n");
3854 }
3855
3856 g_object_unref (stream);
3857 g_object_unref (file);
3858
3859 return TRUE(!(0));
3860}
3861
3862static gpointer
3863_mate_desktop_item_copy (gpointer boxed)
3864{
3865 return mate_desktop_item_copy (boxed);
3866}
3867
3868static void
3869_mate_desktop_item_free (gpointer boxed)
3870{
3871 mate_desktop_item_unref (boxed);
3872}
3873
3874GType
3875mate_desktop_item_get_type (void)
3876{
3877 static GType type = 0;
3878
3879 if (type == 0) {
3880 type = g_boxed_type_register_static ("MateDesktopItem",
3881 _mate_desktop_item_copy,
3882 _mate_desktop_item_free);
3883 }
3884
3885 return type;
3886}
3887
3888GQuark
3889mate_desktop_item_error_quark (void)
3890{
3891 static GQuark q = 0;
3892 if (q == 0)
3893 q = g_quark_from_static_string ("mate-desktop-item-error-quark");
3894
3895 return q;
3896}
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-a7ec2e.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-a7ec2e.html new file mode 100644 index 0000000..e715b2d --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-a7ec2e.html @@ -0,0 +1,2013 @@ + + + +mate-languages.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-languages.c
Warning:line 1137, column 3
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-languages.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-languages.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright 2008 Red Hat, Inc,
4 * 2007 William Jon McCann <mccann@jhu.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * Written by : William Jon McCann <mccann@jhu.edu>
20 * Ray Strode <rstrode@redhat.com>
21 */
22
23#include "config.h"
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <string.h>
29#include <errno(*__errno_location ()).h>
30#include <dirent.h>
31#include <locale.h>
32#include <langinfo.h>
33#include <sys/stat.h>
34
35#include <glib.h>
36#include <glib/gi18n.h>
37#include <glib/gstdio.h>
38
39#define MATE_DESKTOP_USE_UNSTABLE_API
40#include "mate-languages.h"
41
42#include <langinfo.h>
43#ifndef __LC_LAST13
44#define __LC_LAST13 13
45#endif
46
47#define ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" ISO_CODES_PREFIX"/usr" "/share/xml/iso-codes"
48#define ISO_CODES_LOCALESDIR"/usr" "/share/locale" ISO_CODES_PREFIX"/usr" "/share/locale"
49
50typedef struct _MateLocale {
51 char *id;
52 char *name;
53 char *language_code;
54 char *territory_code;
55 char *codeset;
56 char *modifier;
57} MateLocale;
58
59static GHashTable *mate_languages_map;
60static GHashTable *mate_territories_map;
61static GHashTable *mate_available_locales_map;
62static GHashTable *mate_language_count_map;
63static GHashTable *mate_territory_count_map;
64
65static char * construct_language_name (const char *language,
66 const char *territory,
67 const char *codeset,
68 const char *modifier);
69
70static gboolean language_name_is_valid (const char *language_name);
71
72static void
73mate_locale_free (MateLocale *locale)
74{
75 if (locale == NULL((void*)0)) {
76 return;
77 }
78
79 g_free (locale->id);
80 g_free (locale->name);
81 g_free (locale->codeset);
82 g_free (locale->modifier);
83 g_free (locale->language_code);
84 g_free (locale->territory_code);
85 g_free (locale);
86}
87
88static char *
89normalize_codeset (const char *codeset)
90{
91 if (codeset == NULL((void*)0))
92 return NULL((void*)0);
93
94 if (g_str_equal (codeset, "UTF-8")(strcmp ((const char *) (codeset), (const char *) ("UTF-8")) ==
0)
||
95 g_str_equal (codeset, "utf8")(strcmp ((const char *) (codeset), (const char *) ("utf8")) ==
0)
)
96 return g_strdup ("UTF-8")g_strdup_inline ("UTF-8");
97
98 return g_strdup (codeset)g_strdup_inline (codeset);
99}
100
101/**
102 * mate_parse_locale:
103 * @locale: a locale string
104 * @language_codep: (out) (allow-none) (transfer full): location to
105 * store the language code, or %NULL
106 * @country_codep: (out) (allow-none) (transfer full): location to
107 * store the country code, or %NULL
108 * @codesetp: (out) (allow-none) (transfer full): location to
109 * store the codeset, or %NULL
110 * @modifierp: (out) (allow-none) (transfer full): location to
111 * store the modifier, or %NULL
112 *
113 * Extracts the various components of a locale string of the form
114 * [language[_country][.codeset][@modifier]]. See
115 * http://en.wikipedia.org/wiki/Locale.
116 *
117 * Return value: %TRUE if parsing was successful.
118 *
119 * Since: 1.22
120 */
121gboolean
122mate_parse_locale (const char *locale,
123 char **language_codep,
124 char **country_codep,
125 char **codesetp,
126 char **modifierp)
127{
128 static GRegex *re = NULL((void*)0);
129 GMatchInfo *match_info;
130 gboolean res;
131 gchar *normalized_codeset = NULL((void*)0);
132 gchar *normalized_name = NULL((void*)0);
133 gboolean retval;
134
135 match_info = NULL((void*)0);
136 retval = FALSE(0);
137
138 if (re == NULL((void*)0)) {
139 GError *error = NULL((void*)0);
140 re = g_regex_new ("^(?P<language>[^_.@[:space:]]+)"
141 "(_(?P<territory>[[:upper:]]+))?"
142 "(\\.(?P<codeset>[-_0-9a-zA-Z]+))?"
143 "(@(?P<modifier>[[:ascii:]]+))?$",
144 0, 0, &error);
145 if (re == NULL((void*)0)) {
146 g_warning ("%s", error->message);
147 g_error_free (error);
148 goto out;
149 }
150 }
151
152 if (!g_regex_match (re, locale, 0, &match_info) ||
153 g_match_info_is_partial_match (match_info)) {
154 g_warning ("locale '%s' isn't valid\n", locale);
155 goto out;
156 }
157
158 res = g_match_info_matches (match_info);
159 if (! res) {
160 g_warning ("Unable to parse locale: %s", locale);
161 goto out;
162 }
163
164 retval = TRUE(!(0));
165
166 if (language_codep != NULL((void*)0)) {
167 *language_codep = g_match_info_fetch_named (match_info, "language");
168 }
169
170 if (country_codep != NULL((void*)0)) {
171 *country_codep = g_match_info_fetch_named (match_info, "territory");
172
173 if (*country_codep != NULL((void*)0) &&
174 *country_codep[0] == '\0') {
175 g_free (*country_codep);
176 *country_codep = NULL((void*)0);
177 }
178 }
179
180 if (codesetp != NULL((void*)0)) {
181 *codesetp = g_match_info_fetch_named (match_info, "codeset");
182
183 if (*codesetp != NULL((void*)0) &&
184 *codesetp[0] == '\0') {
185 g_free (*codesetp);
186 *codesetp = NULL((void*)0);
187 }
188 }
189
190 if (modifierp != NULL((void*)0)) {
191 *modifierp = g_match_info_fetch_named (match_info, "modifier");
192
193 if (*modifierp != NULL((void*)0) &&
194 *modifierp[0] == '\0') {
195 g_free (*modifierp);
196 *modifierp = NULL((void*)0);
197 }
198 }
199
200 if (codesetp != NULL((void*)0) && *codesetp != NULL((void*)0)) {
201 normalized_codeset = normalize_codeset (*codesetp);
202 normalized_name = construct_language_name (language_codep ? *language_codep : NULL((void*)0),
203 country_codep ? *country_codep : NULL((void*)0),
204 normalized_codeset,
205 modifierp ? *modifierp : NULL((void*)0));
206
207 if (language_name_is_valid (normalized_name)) {
208 g_free (*codesetp);
209 *codesetp = normalized_codeset;
210 } else {
211 g_free (normalized_codeset);
212 }
213 g_free (normalized_name);
214 }
215
216 out:
217 g_match_info_free (match_info);
218
219 return retval;
220}
221
222static char *
223construct_language_name (const char *language,
224 const char *territory,
225 const char *codeset,
226 const char *modifier)
227{
228 char *name;
229
230 g_assert (language != NULL && language[0] != 0)do { if (language != ((void*)0) && language[0] != 0) ;
else g_assertion_message_expr ("MateDesktop", "mate-languages.c"
, 230, ((const char*) (__func__)), "language != NULL && language[0] != 0"
); } while (0)
;
231 g_assert (territory == NULL || territory[0] != 0)do { if (territory == ((void*)0) || territory[0] != 0) ; else
g_assertion_message_expr ("MateDesktop", "mate-languages.c",
231, ((const char*) (__func__)), "territory == NULL || territory[0] != 0"
); } while (0)
;
232 g_assert (codeset == NULL || codeset[0] != 0)do { if (codeset == ((void*)0) || codeset[0] != 0) ; else g_assertion_message_expr
("MateDesktop", "mate-languages.c", 232, ((const char*) (__func__
)), "codeset == NULL || codeset[0] != 0"); } while (0)
;
233 g_assert (modifier == NULL || modifier[0] != 0)do { if (modifier == ((void*)0) || modifier[0] != 0) ; else g_assertion_message_expr
("MateDesktop", "mate-languages.c", 233, ((const char*) (__func__
)), "modifier == NULL || modifier[0] != 0"); } while (0)
;
234
235 name = g_strdup_printf ("%s%s%s%s%s%s%s",
236 language,
237 territory != NULL((void*)0)? "_" : "",
238 territory != NULL((void*)0)? territory : "",
239 codeset != NULL((void*)0)? "." : "",
240 codeset != NULL((void*)0)? codeset : "",
241 modifier != NULL((void*)0)? "@" : "",
242 modifier != NULL((void*)0)? modifier : "");
243
244 return name;
245}
246
247/**
248 * mate_normalize_locale:
249 * @locale: a locale string
250 *
251 * Gets the normalized locale string in the form
252 * [language[_country][.codeset][@modifier]] for @name.
253 *
254 * Return value: (transfer full): normalized locale string. Caller
255 * takes ownership.
256 *
257 * Since: 1.22
258 */
259char *
260mate_normalize_locale (const char *locale)
261{
262 char *normalized_name;
263 gboolean valid;
264 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
265 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
266 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset = NULL((void*)0);
267 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *modifier = NULL((void*)0);
268
269 if (locale[0] == '\0') {
270 return NULL((void*)0);
271 }
272
273 valid = mate_parse_locale (locale,
274 &language_code,
275 &territory_code,
276 &codeset, &modifier);
277 if (!valid)
278 return NULL((void*)0);
279
280 normalized_name = construct_language_name (language_code,
281 territory_code,
282 codeset, modifier);
283 return normalized_name;
284}
285
286static gboolean
287language_name_is_valid (const char *language_name)
288{
289 gboolean is_valid;
290 int lc_type_id = LC_MESSAGES5;
291 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
292
293 old_locale = g_strdup (setlocale (lc_type_id, NULL))g_strdup_inline (setlocale (lc_type_id, ((void*)0)));
294 is_valid = setlocale (lc_type_id, language_name) != NULL((void*)0);
295 setlocale (lc_type_id, old_locale);
296
297 return is_valid;
298}
299
300static void
301language_name_get_codeset_details (const char *language_name,
302 char **pcodeset,
303 gboolean *is_utf8)
304{
305 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
306 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset = NULL((void*)0);
307
308 old_locale = g_strdup (setlocale (LC_CTYPE, NULL))g_strdup_inline (setlocale (0, ((void*)0)));
309
310 if (setlocale (LC_CTYPE0, language_name) == NULL((void*)0))
311 return;
312
313 codeset = nl_langinfo (CODESETCODESET);
314
315 if (pcodeset != NULL((void*)0)) {
316 *pcodeset = g_strdup (codeset)g_strdup_inline (codeset);
317 }
318
319 if (is_utf8 != NULL((void*)0)) {
320 codeset = normalize_codeset (codeset);
321
322 *is_utf8 = strcmp (codeset, "UTF-8") == 0;
323 }
324
325 setlocale (LC_CTYPE0, old_locale);
326}
327
328static gboolean
329locale_dir_has_mo_files (const gchar* path)
330{
331 GDir *dir;
332 const char *name;
333 gboolean has_translations;
334
335 has_translations = FALSE(0);
336 dir = g_dir_open (path, 0, NULL((void*)0));
337
338 if (dir == NULL((void*)0)) {
339 goto out;
340 }
341
342 do {
343 name = g_dir_read_name (dir);
344
345 if (name == NULL((void*)0)) {
346 break;
347 }
348
349 if (g_str_has_suffix (name, ".mo")(__builtin_constant_p (".mo")? __extension__ ({ const char * const
__str = (name); const char * const __suffix = (".mo"); gboolean
__result = (0); if (__str == ((void*)0) || __suffix == ((void
*)0)) __result = (g_str_has_suffix) (__str, __suffix); else {
const size_t __str_len = strlen (((__str) + !(__str))); const
size_t __suffix_len = strlen (((__suffix) + !(__suffix))); if
(__str_len >= __suffix_len) __result = memcmp (__str + __str_len
- __suffix_len, ((__suffix) + !(__suffix)), __suffix_len) ==
0; } __result; }) : (g_str_has_suffix) (name, ".mo") )
) {
350 has_translations = TRUE(!(0));
351 break;
352 }
353 } while (name != NULL((void*)0));
354 g_dir_close (dir);
355
356 out:
357 return has_translations;
358}
359
360/**
361 * mate_language_has_translations:
362 * @code: an ISO 639 code string
363 *
364 * Returns %TRUE if there are translations for language @code.
365 *
366 * Return value: %TRUE if there are translations for language @code.
367 *
368 * Since: 1.22
369 */
370gboolean
371mate_language_has_translations (const char *code)
372{
373 gboolean has_translations;
374 gchar *path;
375
376 path = g_build_filename (MATELOCALEDIR"/usr/share/locale", code, "LC_MESSAGES", NULL((void*)0));
377 has_translations = locale_dir_has_mo_files (path);
378
379 if (!has_translations) {
380 const char * const *system_data_dirs;
381 int i = 0;
382
383 system_data_dirs = g_get_system_data_dirs ();
384 while ((system_data_dirs[i] != NULL((void*)0)) && (has_translations == FALSE(0))) {
385 g_free (path);
386 path = g_build_filename (system_data_dirs[i], "locale", code, "LC_MESSAGES", NULL((void*)0));
387 has_translations = locale_dir_has_mo_files (path);
388 ++i;
389 }
390 }
391
392 g_free (path);
393 return has_translations;
394}
395
396static gboolean
397add_locale (const char *language_name,
398 gboolean utf8_only)
399{
400 MateLocale *locale;
401 MateLocale *old_locale;
402 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *name = NULL((void*)0);
403 gboolean is_utf8 = FALSE(0);
404 gboolean valid = FALSE(0);
405
406 g_return_val_if_fail (language_name != NULL, FALSE)do { if ((language_name != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "language_name != NULL"
); return ((0)); } } while (0)
;
407 g_return_val_if_fail (*language_name != '\0', FALSE)do { if ((*language_name != '\0')) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "*language_name != '\\0'"
); return ((0)); } } while (0)
;
408
409 language_name_get_codeset_details (language_name, NULL((void*)0), &is_utf8);
410
411 if (is_utf8) {
412 name = g_strdup (language_name)g_strdup_inline (language_name);
413 } else if (utf8_only) {
414
415 if (strchr (language_name, '.'))
416 return FALSE(0);
417
418 /* If the locale name has no dot, assume that its
419 * encoding part is missing and try again after adding
420 * ".UTF-8". This catches locale names like "de_DE".
421 */
422 name = g_strdup_printf ("%s.UTF-8", language_name);
423
424 language_name_get_codeset_details (name, NULL((void*)0), &is_utf8);
425 if (!is_utf8)
426 return FALSE(0);
427 } else {
428 name = g_strdup (language_name)g_strdup_inline (language_name);
429 }
430
431 if (!language_name_is_valid (name)) {
432 g_debug ("Ignoring '%s' as a locale, since it's invalid", name);
433 return FALSE(0);
434 }
435
436 locale = g_new0 (MateLocale, 1)((MateLocale *) g_malloc0_n ((1), sizeof (MateLocale)));
437 valid = mate_parse_locale (name,
438 &locale->language_code,
439 &locale->territory_code,
440 &locale->codeset,
441 &locale->modifier);
442 if (!valid) {
443 mate_locale_free (locale);
444 return FALSE(0);
445 }
446
447 locale->id = construct_language_name (locale->language_code, locale->territory_code,
448 NULL((void*)0), locale->modifier);
449 locale->name = construct_language_name (locale->language_code, locale->territory_code,
450 locale->codeset, locale->modifier);
451
452 if (!mate_language_has_translations (locale->name) &&
453 !mate_language_has_translations (locale->id) &&
454 !mate_language_has_translations (locale->language_code) &&
455 utf8_only) {
456 g_debug ("Ignoring '%s' as a locale, since it lacks translations", locale->name);
457 mate_locale_free (locale);
458 return FALSE(0);
459 }
460
461 if (!utf8_only) {
462 g_free (locale->id);
463 locale->id = g_strdup (locale->name)g_strdup_inline (locale->name);
464 }
465
466 old_locale = g_hash_table_lookup (mate_available_locales_map, locale->id);
467 if (old_locale != NULL((void*)0)) {
468 if (strlen (old_locale->name) > strlen (locale->name)) {
469 mate_locale_free (locale);
470 return FALSE(0);
471 }
472 }
473
474 g_hash_table_insert (mate_available_locales_map, g_strdup (locale->id)g_strdup_inline (locale->id), locale);
475
476 return TRUE(!(0));
477}
478
479static int
480select_dirs (const struct dirent *dirent)
481{
482 int result = 0;
483
484 if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0) {
485 mode_t mode = 0;
486
487#ifdef _DIRENT_HAVE_D_TYPE
488 if (dirent->d_type != DT_UNKNOWNDT_UNKNOWN && dirent->d_type != DT_LNKDT_LNK) {
489 mode = DTTOIF (dirent->d_type)((dirent->d_type) << 12);
490 } else
491#endif
492 {
493 struct stat st;
494 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *path = NULL((void*)0);
495
496 path = g_build_filename (MATELOCALEDIR"/usr/share/locale", dirent->d_name, NULL((void*)0));
497 if (g_statstat (path, &st) == 0) {
498 mode = st.st_mode;
499 }
500 }
501
502 result = S_ISDIR (mode)((((mode)) & 0170000) == (0040000));
503 }
504
505 return result;
506}
507
508static gboolean
509collect_locales_from_directory (void)
510{
511 gboolean found_locales = FALSE(0);
512 struct dirent **dirents;
513 int ndirents;
514 int cnt;
515
516 ndirents = scandir (MATELOCALEDIR"/usr/share/locale", &dirents, select_dirs, alphasort);
517
518 for (cnt = 0; cnt < ndirents; ++cnt) {
519 if (add_locale (dirents[cnt]->d_name, TRUE(!(0))))
520 found_locales = TRUE(!(0));
521 }
522
523 if (ndirents > 0) {
524 free (dirents);
525 }
526 return found_locales;
527}
528
529static gboolean
530collect_locales_from_localebin (void)
531{
532 gboolean found_locales = FALSE(0);
533 const gchar *argv[] = { "locale", "-a", NULL((void*)0) };
534 gchar **linep;
535 g_auto (GStrv)__attribute__((cleanup(glib_auto_cleanup_GStrv))) GStrv lines = NULL((void*)0);
536 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) gchar *output = NULL((void*)0);
537
538 if (g_spawn_sync (NULL((void*)0), (gchar **) argv, NULL((void*)0),
539 G_SPAWN_SEARCH_PATH|G_SPAWN_STDERR_TO_DEV_NULL,
540 NULL((void*)0), NULL((void*)0), &output, NULL((void*)0), NULL((void*)0), NULL((void*)0)) == FALSE(0))
541 return FALSE(0);
542
543 g_return_val_if_fail (output != NULL, FALSE)do { if ((output != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "output != NULL"
); return ((0)); } } while (0)
;
544
545 lines = g_strsplit (output, "\n", 0);
546 if (lines) {
547 linep = lines;
548 while (*linep) {
549 if (*linep[0] && add_locale (*linep, TRUE(!(0))))
550 found_locales = TRUE(!(0));
551 linep++;
552 }
553 }
554
555 return found_locales;
556}
557
558static void
559fill_count_map (GHashTable *count_map,
560 const char *code)
561{
562 int count;
563 gpointer pointer;
564
565 if (code == NULL((void*)0))
566 return;
567
568 if ((pointer = g_hash_table_lookup (count_map, code)) != NULL((void*)0))
569 count = GPOINTER_TO_INT (pointer)((gint) (glong) (pointer)) + 1;
570 else
571 count = 1;
572
573 g_hash_table_insert (count_map, g_strdup (code)g_strdup_inline (code), GINT_TO_POINTER (count)((gpointer) (glong) (count)));
574}
575
576static void
577count_languages_and_territories (void)
578{
579 gpointer value;
580 GHashTableIter iter;
581
582 mate_language_count_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
583 mate_territory_count_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
584
585 g_hash_table_iter_init (&iter, mate_available_locales_map);
586 while (g_hash_table_iter_next (&iter, NULL((void*)0), &value)) {
587 MateLocale *locale = (MateLocale *) value;
588 fill_count_map (mate_language_count_map, locale->language_code);
589 fill_count_map (mate_territory_count_map, locale->territory_code);
590 }
591}
592
593static void
594collect_locales (void)
595{
596 gboolean found_localebin_locales = FALSE(0);
597 gboolean found_dir_locales = FALSE(0);
598
599 if (mate_available_locales_map == NULL((void*)0)) {
600 mate_available_locales_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) mate_locale_free);
601 }
602
603 found_localebin_locales = collect_locales_from_localebin ();
604
605 found_dir_locales = collect_locales_from_directory ();
606
607 if (!(found_localebin_locales || found_dir_locales)) {
608 g_warning ("Could not read list of available locales from libc, "
609 "guessing possible locales from available translations, "
610 "but list may be incomplete!");
611 }
612
613 count_languages_and_territories ();
614}
615
616static gint
617get_language_count (const char *language)
618{
619 gint count = 0;
620 gpointer pointer;
621
622 if (mate_language_count_map == NULL((void*)0))
623 collect_locales ();
624
625 if ((pointer = g_hash_table_lookup (mate_language_count_map, language)) != NULL((void*)0))
626 count = GPOINTER_TO_INT (pointer)((gint) (glong) (pointer));
627
628 return count;
629}
630
631static gboolean
632is_unique_language (const char *language)
633{
634 return get_language_count (language) == 1;
635}
636
637static gint
638get_territory_count (const char *territory)
639{
640 gint count = 0;
641 gpointer pointer;
642
643 if (mate_territory_count_map == NULL((void*)0))
644 collect_locales ();
645
646 if ((pointer = g_hash_table_lookup (mate_territory_count_map, territory)) != NULL((void*)0))
647 count = GPOINTER_TO_INT (pointer)((gint) (glong) (pointer));
648
649 return count;
650}
651
652static gboolean
653is_unique_territory (const char *territory)
654{
655 return get_territory_count (territory) == 1;
656}
657
658static gboolean
659is_fallback_language (const char *code)
660{
661 const char *fallback_language_names[] = { "C", "POSIX", NULL((void*)0) };
662 int i;
663
664 for (i = 0; fallback_language_names[i] != NULL((void*)0); i++) {
665 if (strcmp (code, fallback_language_names[i]) == 0) {
666 return TRUE(!(0));
667 }
668 }
669
670 return FALSE(0);
671}
672
673static const char *
674get_language (const char *code)
675{
676 const char *name;
677 int len;
678
679 g_assert (code != NULL)do { if (code != ((void*)0)) ; else g_assertion_message_expr (
"MateDesktop", "mate-languages.c", 679, ((const char*) (__func__
)), "code != NULL"); } while (0)
;
680
681 if (is_fallback_language (code)) {
682 return "Unspecified";
683 }
684
685 len = strlen (code);
686 if (len != 2 && len != 3) {
687 return NULL((void*)0);
688 }
689
690 name = (const char *) g_hash_table_lookup (mate_languages_map, code);
691
692 return name;
693}
694
695static char *
696get_first_item_in_semicolon_list (const char *list)
697{
698 char **items;
699 char *item;
700
701 /* Some entries in iso codes have multiple values, separated
702 * by semicolons. Not really sure which one to pick, so
703 * we just arbitrarily pick the first one.
704 */
705 items = g_strsplit (list, "; ", 2);
706
707 item = g_strdup (items[0])g_strdup_inline (items[0]);
708 g_strfreev (items);
709
710 return item;
711}
712
713static char *
714capitalize_utf8_string (const char *str)
715{
716 char first[8] = { 0 };
717
718 if (!str)
719 return NULL((void*)0);
720
721 g_unichar_to_utf8 (g_unichar_totitle (g_utf8_get_char (str)), first);
722
723 return g_strconcat (first, g_utf8_offset_to_pointer (str, 1), NULL((void*)0));
724}
725
726static char *
727get_translated_language (const char *code,
728 const char *locale)
729{
730 const char *language;
731 char *name;
732
733 language = get_language (code);
734
735 name = NULL((void*)0);
736 if (language != NULL((void*)0)) {
737 const char *translated_name;
738 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
739
740 if (locale != NULL((void*)0)) {
741 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL))g_strdup_inline (setlocale (5, ((void*)0)));
742 setlocale (LC_MESSAGES5, locale);
743 }
744
745 if (is_fallback_language (code)) {
746 name = g_strdup (_("Unspecified"))g_strdup_inline (gettext ("Unspecified"));
747 } else {
748 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *tmp = NULL((void*)0);
749 translated_name = dgettext ("iso_639", language);
750 tmp = get_first_item_in_semicolon_list (translated_name);
751 name = capitalize_utf8_string (tmp);
752 }
753
754 if (locale != NULL((void*)0)) {
755 setlocale (LC_MESSAGES5, old_locale);
756 }
757 }
758
759 return name;
760}
761
762static const char *
763get_territory (const char *code)
764{
765 const char *name;
766 int len;
767
768 g_assert (code != NULL)do { if (code != ((void*)0)) ; else g_assertion_message_expr (
"MateDesktop", "mate-languages.c", 768, ((const char*) (__func__
)), "code != NULL"); } while (0)
;
769
770 len = strlen (code);
771 if (len != 2 && len != 3) {
772 return NULL((void*)0);
773 }
774
775 name = (const char *) g_hash_table_lookup (mate_territories_map, code);
776
777 return name;
778}
779
780static char *
781get_translated_territory (const char *code,
782 const char *locale)
783{
784 const char *territory;
785 char *name;
786
787 territory = get_territory (code);
788
789 name = NULL((void*)0);
790 if (territory != NULL((void*)0)) {
791 const char *translated_territory;
792 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
793 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *tmp = NULL((void*)0);
794
795 if (locale != NULL((void*)0)) {
796 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL))g_strdup_inline (setlocale (5, ((void*)0)));
797 setlocale (LC_MESSAGES5, locale);
798 }
799
800 translated_territory = dgettext ("iso_3166", territory);
801 tmp = get_first_item_in_semicolon_list (translated_territory);
802 name = capitalize_utf8_string (tmp);
803
804 if (locale != NULL((void*)0)) {
805 setlocale (LC_MESSAGES5, old_locale);
806 }
807 }
808
809 return name;
810}
811
812static void
813languages_parse_start_tag (GMarkupParseContext *ctx,
814 const char *element_name,
815 const char **attr_names,
816 const char **attr_values,
817 gpointer user_data,
818 GError **error)
819{
820 const char *ccode_longB;
821 const char *ccode_longT;
822 const char *ccode;
823 const char *ccode_id;
824 const char *lang_name;
825
826 if (! (g_str_equal (element_name, "iso_639_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_639_entry"
)) == 0)
|| g_str_equal (element_name, "iso_639_3_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_639_3_entry"
)) == 0)
)
827 || attr_names == NULL((void*)0) || attr_values == NULL((void*)0)) {
828 return;
829 }
830
831 ccode = NULL((void*)0);
832 ccode_longB = NULL((void*)0);
833 ccode_longT = NULL((void*)0);
834 ccode_id = NULL((void*)0);
835 lang_name = NULL((void*)0);
836
837 while (*attr_names && *attr_values) {
838 if (g_str_equal (*attr_names, "iso_639_1_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_1_code"
)) == 0)
) {
839 /* skip if empty */
840 if (**attr_values) {
841 if (strlen (*attr_values) != 2) {
842 return;
843 }
844 ccode = *attr_values;
845 }
846 } else if (g_str_equal (*attr_names, "iso_639_2B_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_2B_code"
)) == 0)
) {
847 /* skip if empty */
848 if (**attr_values) {
849 if (strlen (*attr_values) != 3) {
850 return;
851 }
852 ccode_longB = *attr_values;
853 }
854 } else if (g_str_equal (*attr_names, "iso_639_2T_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_2T_code"
)) == 0)
) {
855 /* skip if empty */
856 if (**attr_values) {
857 if (strlen (*attr_values) != 3) {
858 return;
859 }
860 ccode_longT = *attr_values;
861 }
862 } else if (g_str_equal (*attr_names, "id")(strcmp ((const char *) (*attr_names), (const char *) ("id"))
== 0)
) {
863 /* skip if empty */
864 if (**attr_values) {
865 if (strlen (*attr_values) != 2 &&
866 strlen (*attr_values) != 3) {
867 return;
868 }
869 ccode_id = *attr_values;
870 }
871 } else if (g_str_equal (*attr_names, "name")(strcmp ((const char *) (*attr_names), (const char *) ("name"
)) == 0)
) {
872 lang_name = *attr_values;
873 }
874
875 ++attr_names;
876 ++attr_values;
877 }
878
879 if (lang_name == NULL((void*)0)) {
880 return;
881 }
882
883 if (ccode != NULL((void*)0)) {
884 g_hash_table_insert (mate_languages_map,
885 g_strdup (ccode)g_strdup_inline (ccode),
886 g_strdup (lang_name)g_strdup_inline (lang_name));
887 }
888 if (ccode_longB != NULL((void*)0)) {
889 g_hash_table_insert (mate_languages_map,
890 g_strdup (ccode_longB)g_strdup_inline (ccode_longB),
891 g_strdup (lang_name)g_strdup_inline (lang_name));
892 }
893 if (ccode_longT != NULL((void*)0)) {
894 g_hash_table_insert (mate_languages_map,
895 g_strdup (ccode_longT)g_strdup_inline (ccode_longT),
896 g_strdup (lang_name)g_strdup_inline (lang_name));
897 }
898 if (ccode_id != NULL((void*)0)) {
899 g_hash_table_insert (mate_languages_map,
900 g_strdup (ccode_id)g_strdup_inline (ccode_id),
901 g_strdup (lang_name)g_strdup_inline (lang_name));
902 }
903}
904
905static void
906territories_parse_start_tag (GMarkupParseContext *ctx,
907 const char *element_name,
908 const char **attr_names,
909 const char **attr_values,
910 gpointer user_data,
911 GError **error)
912{
913 const char *acode_2;
914 const char *acode_3;
915 const char *ncode;
916 const char *territory_common_name;
917 const char *territory_name;
918
919 if (! g_str_equal (element_name, "iso_3166_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_3166_entry"
)) == 0)
|| attr_names == NULL((void*)0) || attr_values == NULL((void*)0)) {
920 return;
921 }
922
923 acode_2 = NULL((void*)0);
924 acode_3 = NULL((void*)0);
925 ncode = NULL((void*)0);
926 territory_common_name = NULL((void*)0);
927 territory_name = NULL((void*)0);
928
929 while (*attr_names && *attr_values) {
930 if (g_str_equal (*attr_names, "alpha_2_code")(strcmp ((const char *) (*attr_names), (const char *) ("alpha_2_code"
)) == 0)
) {
931 /* skip if empty */
932 if (**attr_values) {
933 if (strlen (*attr_values) != 2) {
934 return;
935 }
936 acode_2 = *attr_values;
937 }
938 } else if (g_str_equal (*attr_names, "alpha_3_code")(strcmp ((const char *) (*attr_names), (const char *) ("alpha_3_code"
)) == 0)
) {
939 /* skip if empty */
940 if (**attr_values) {
941 if (strlen (*attr_values) != 3) {
942 return;
943 }
944 acode_3 = *attr_values;
945 }
946 } else if (g_str_equal (*attr_names, "numeric_code")(strcmp ((const char *) (*attr_names), (const char *) ("numeric_code"
)) == 0)
) {
947 /* skip if empty */
948 if (**attr_values) {
949 if (strlen (*attr_values) != 3) {
950 return;
951 }
952 ncode = *attr_values;
953 }
954 } else if (g_str_equal (*attr_names, "common_name")(strcmp ((const char *) (*attr_names), (const char *) ("common_name"
)) == 0)
) {
955 /* skip if empty */
956 if (**attr_values) {
957 territory_common_name = *attr_values;
958 }
959 } else if (g_str_equal (*attr_names, "name")(strcmp ((const char *) (*attr_names), (const char *) ("name"
)) == 0)
) {
960 territory_name = *attr_values;
961 }
962
963 ++attr_names;
964 ++attr_values;
965 }
966
967 if (territory_common_name != NULL((void*)0)) {
968 territory_name = territory_common_name;
969 }
970
971 if (territory_name == NULL((void*)0)) {
972 return;
973 }
974
975 if (acode_2 != NULL((void*)0)) {
976 g_hash_table_insert (mate_territories_map,
977 g_strdup (acode_2)g_strdup_inline (acode_2),
978 g_strdup (territory_name)g_strdup_inline (territory_name));
979 }
980 if (acode_3 != NULL((void*)0)) {
981 g_hash_table_insert (mate_territories_map,
982 g_strdup (acode_3)g_strdup_inline (acode_3),
983 g_strdup (territory_name)g_strdup_inline (territory_name));
984 }
985 if (ncode != NULL((void*)0)) {
986 g_hash_table_insert (mate_territories_map,
987 g_strdup (ncode)g_strdup_inline (ncode),
988 g_strdup (territory_name)g_strdup_inline (territory_name));
989 }
990}
991
992static void
993languages_variant_init (const char *variant)
994{
995 gboolean res;
996 gsize buf_len;
997 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *buf = NULL((void*)0);
998 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *filename = NULL((void*)0);
999 g_autoptr (GError)__attribute__((cleanup(glib_autoptr_cleanup_GError))) GError_autoptr error = NULL((void*)0);
1000
1001 bindtextdomain (variant, ISO_CODES_LOCALESDIR"/usr" "/share/locale");
1002 bind_textdomain_codeset (variant, "UTF-8");
1003
1004 error = NULL((void*)0);
1005 filename = g_strdup_printf (ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/%s.xml", variant);
1006 res = g_file_get_contents (filename,
1007 &buf,
1008 &buf_len,
1009 &error);
1010 if (res) {
1011 g_autoptr (GMarkupParseContext)__attribute__((cleanup(glib_autoptr_cleanup_GMarkupParseContext
))) GMarkupParseContext_autoptr
ctx = NULL((void*)0);
1012 GMarkupParser parser = { languages_parse_start_tag, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0) };
1013
1014 ctx = g_markup_parse_context_new (&parser, 0, NULL((void*)0), NULL((void*)0));
1015
1016 error = NULL((void*)0);
1017 res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
1018
1019 if (! res) {
1020 g_warning ("Failed to parse '%s': %s\n",
1021 filename,
1022 error->message);
1023 }
1024 } else {
1025 g_warning ("Failed to load '%s': %s\n",
1026 filename,
1027 error->message);
1028 }
1029}
1030
1031static void
1032languages_init (void)
1033{
1034 if (mate_languages_map)
1035 return;
1036
1037 mate_languages_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1038
1039 languages_variant_init ("iso_639");
1040 languages_variant_init ("iso_639_3");
1041}
1042
1043static void
1044territories_init (void)
1045{
1046 gboolean res;
1047 gsize buf_len;
1048 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *buf = NULL((void*)0);
1049 g_autoptr (GError)__attribute__((cleanup(glib_autoptr_cleanup_GError))) GError_autoptr error = NULL((void*)0);
1050
1051 if (mate_territories_map)
1052 return;
1053
1054 bindtextdomain ("iso_3166", ISO_CODES_LOCALESDIR"/usr" "/share/locale");
1055 bind_textdomain_codeset ("iso_3166", "UTF-8");
1056
1057 mate_territories_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1058
1059 error = NULL((void*)0);
1060 res = g_file_get_contents (ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1061 &buf,
1062 &buf_len,
1063 &error);
1064 if (res) {
1065 g_autoptr (GMarkupParseContext)__attribute__((cleanup(glib_autoptr_cleanup_GMarkupParseContext
))) GMarkupParseContext_autoptr
ctx = NULL((void*)0);
1066 GMarkupParser parser = { territories_parse_start_tag, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0) };
1067
1068 ctx = g_markup_parse_context_new (&parser, 0, NULL((void*)0), NULL((void*)0));
1069
1070 error = NULL((void*)0);
1071 res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
1072
1073 if (! res) {
1074 g_warning ("Failed to parse '%s': %s\n",
1075 ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1076 error->message);
1077 }
1078 } else {
1079 g_warning ("Failed to load '%s': %s\n",
1080 ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1081 error->message);
1082 }
1083}
1084
1085/**
1086 * mate_get_language_from_locale:
1087 * @locale: a locale string
1088 * @translation: (allow-none): a locale string
1089 *
1090 * Gets the language description for @locale. If @translation is
1091 * provided the returned string is translated accordingly.
1092 *
1093 * Return value: (transfer full): the language description. Caller
1094 * takes ownership.
1095 *
1096 * Since: 1.22
1097 */
1098char *
1099mate_get_language_from_locale (const char *locale,
1100 const char *translation)
1101{
1102 GString *full_language;
1103 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
1104 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
1105 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset_code = NULL((void*)0);
1106 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *langinfo_codeset = NULL((void*)0);
1107 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_language = NULL((void*)0);
1108 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_territory = NULL((void*)0);
1109 gboolean is_utf8 = TRUE(!(0));
1110
1111 g_return_val_if_fail (locale != NULL, NULL)do { if ((locale != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "locale != NULL"
); return (((void*)0)); } } while (0)
;
1112 g_return_val_if_fail (*locale != '\0', NULL)do { if ((*locale != '\0')) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "*locale != '\\0'"
); return (((void*)0)); } } while (0)
;
1113
1114 full_language = g_string_new (NULL((void*)0));
1115
1116 languages_init ();
1117 territories_init ();
1118
1119 mate_parse_locale (locale,
1120 &language_code,
1121 &territory_code,
1122 &codeset_code,
1123 NULL((void*)0));
1124
1125 if (language_code == NULL((void*)0)) {
1126 goto out;
1127 }
1128
1129 translated_language = get_translated_language (language_code, translation);
1130 if (translated_language == NULL((void*)0)) {
1131 goto out;
1132 }
1133
1134 full_language = g_string_append (full_language, translated_language)(__builtin_constant_p (translated_language) ? __extension__ (
{ const char * const __val = (translated_language); g_string_append_len_inline
(full_language, __val, (__val != ((void*)0)) ? (gssize) strlen
(((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(full_language, translated_language, (gssize) -1))
;
1135
1136 if (is_unique_language (language_code)) {
1137 goto out;
This statement is never executed
1138 }
1139
1140 if (territory_code != NULL((void*)0)) {
1141 translated_territory = get_translated_territory (territory_code, translation);
1142 }
1143 if (translated_territory != NULL((void*)0)) {
1144 g_string_append_printf (full_language,
1145 " (%s)",
1146 translated_territory);
1147 }
1148
1149 language_name_get_codeset_details (locale, &langinfo_codeset, &is_utf8);
1150
1151 if (codeset_code == NULL((void*)0) && langinfo_codeset != NULL((void*)0)) {
1152 codeset_code = g_strdup (langinfo_codeset)g_strdup_inline (langinfo_codeset);
1153 }
1154
1155 if (!is_utf8 && codeset_code) {
1156 g_string_append_printf (full_language,
1157 " [%s]",
1158 codeset_code);
1159 }
1160
1161 out:
1162 if (full_language->len == 0) {
1163 g_string_free (full_language, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(full_language), ((!(0)))) : g_string_free_and_steal (full_language
)) : (g_string_free) ((full_language), ((!(0)))))
;
1164 return NULL((void*)0);
1165 }
1166
1167 return g_string_free (full_language, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((full_language
), ((0))) : g_string_free_and_steal (full_language)) : (g_string_free
) ((full_language), ((0))))
;
1168}
1169
1170/**
1171 * mate_get_country_from_locale:
1172 * @locale: a locale string
1173 * @translation: (allow-none): a locale string
1174 *
1175 * Gets the country description for @locale. If @translation is
1176 * provided the returned string is translated accordingly.
1177 *
1178 * Return value: (transfer full): the country description. Caller
1179 * takes ownership.
1180 *
1181 * Since: 1.22
1182 */
1183char *
1184mate_get_country_from_locale (const char *locale,
1185 const char *translation)
1186{
1187 GString *full_name;
1188 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
1189 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
1190 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset_code = NULL((void*)0);
1191 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *langinfo_codeset = NULL((void*)0);
1192 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_language = NULL((void*)0);
1193 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_territory = NULL((void*)0);
1194 gboolean is_utf8 = TRUE(!(0));
1195
1196 g_return_val_if_fail (locale != NULL, NULL)do { if ((locale != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "locale != NULL"
); return (((void*)0)); } } while (0)
;
1197 g_return_val_if_fail (*locale != '\0', NULL)do { if ((*locale != '\0')) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "*locale != '\\0'"
); return (((void*)0)); } } while (0)
;
1198
1199 full_name = g_string_new (NULL((void*)0));
1200
1201 languages_init ();
1202 territories_init ();
1203
1204 mate_parse_locale (locale,
1205 &language_code,
1206 &territory_code,
1207 &codeset_code,
1208 NULL((void*)0));
1209
1210 if (territory_code == NULL((void*)0)) {
1211 goto out;
1212 }
1213
1214 translated_territory = get_translated_territory (territory_code, translation);
1215 g_string_append (full_name, translated_territory)(__builtin_constant_p (translated_territory) ? __extension__ (
{ const char * const __val = (translated_territory); g_string_append_len_inline
(full_name, __val, (__val != ((void*)0)) ? (gssize) strlen (
((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(full_name, translated_territory, (gssize) -1))
;
1216
1217 if (is_unique_territory (territory_code)) {
1218 goto out;
1219 }
1220
1221 if (language_code != NULL((void*)0)) {
1222 translated_language = get_translated_language (language_code, translation);
1223 }
1224 if (translated_language != NULL((void*)0)) {
1225 g_string_append_printf (full_name,
1226 " (%s)",
1227 translated_language);
1228 }
1229
1230 language_name_get_codeset_details (translation, &langinfo_codeset, &is_utf8);
1231
1232 if (codeset_code == NULL((void*)0) && langinfo_codeset != NULL((void*)0)) {
1233 codeset_code = g_strdup (langinfo_codeset)g_strdup_inline (langinfo_codeset);
1234 }
1235
1236 if (!is_utf8 && codeset_code) {
1237 g_string_append_printf (full_name,
1238 " [%s]",
1239 codeset_code);
1240 }
1241
1242 out:
1243 if (full_name->len == 0) {
1244 g_string_free (full_name, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(full_name), ((!(0)))) : g_string_free_and_steal (full_name))
: (g_string_free) ((full_name), ((!(0)))))
;
1245 return NULL((void*)0);
1246 }
1247
1248 return g_string_free (full_name, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((full_name
), ((0))) : g_string_free_and_steal (full_name)) : (g_string_free
) ((full_name), ((0))))
;
1249}
1250
1251/**
1252 * mate_get_all_locales:
1253 *
1254 * Gets all locales.
1255 *
1256 * Return value: (array zero-terminated=1) (element-type utf8) (transfer full):
1257 * a newly allocated %NULL-terminated string array containing the
1258 * all locales. Free with g_strfreev().
1259 *
1260 * Since: 1.22
1261 */
1262char **
1263mate_get_all_locales (void)
1264{
1265 GHashTableIter iter;
1266 gpointer key, value;
1267 GPtrArray *array;
1268
1269 if (mate_available_locales_map == NULL((void*)0)) {
1270 collect_locales ();
1271 }
1272
1273 array = g_ptr_array_new ();
1274 g_hash_table_iter_init (&iter, mate_available_locales_map);
1275 while (g_hash_table_iter_next (&iter, &key, &value)) {
1276 MateLocale *locale;
1277
1278 locale = (MateLocale *) value;
1279
1280 g_ptr_array_add (array, g_strdup (locale->name)g_strdup_inline (locale->name));
1281 }
1282 g_ptr_array_add (array, NULL((void*)0));
1283
1284 return (char **) g_ptr_array_free (array, FALSE(0));
1285}
1286
1287/**
1288 * mate_get_language_from_code:
1289 * @code: an ISO 639 code string
1290 * @translation: (allow-none): a locale string
1291 *
1292 * Gets the language name for @code. If @locale is provided the
1293 * returned string is translated accordingly.
1294 *
1295 * Return value: (transfer full): the language name. Caller takes
1296 * ownership.
1297 *
1298 * Since: 1.22
1299 */
1300char *
1301mate_get_language_from_code (const char *code,
1302 const char *translation)
1303{
1304 g_return_val_if_fail (code != NULL, NULL)do { if ((code != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "code != NULL");
return (((void*)0)); } } while (0)
;
1305
1306 languages_init ();
1307
1308 return get_translated_language (code, translation);
1309}
1310
1311/**
1312 * mate_get_country_from_code:
1313 * @code: an ISO 3166 code string
1314 * @translation: (allow-none): a locale string
1315 *
1316 * Gets the country name for @code. If @locale is provided the
1317 * returned string is translated accordingly.
1318 *
1319 * Return value: (transfer full): the country name. Caller takes
1320 * ownership.
1321 *
1322 * Since: 1.22
1323 */
1324char *
1325mate_get_country_from_code (const char *code,
1326 const char *translation)
1327{
1328 g_return_val_if_fail (code != NULL, NULL)do { if ((code != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "code != NULL");
return (((void*)0)); } } while (0)
;
1329
1330 territories_init ();
1331
1332 return get_translated_territory (code, translation);
1333}
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-d0e85f.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-d0e85f.html new file mode 100644 index 0000000..4b3d671 --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-d0e85f.html @@ -0,0 +1,4650 @@ + + + +mate-desktop-item.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-desktop-item.c
Warning:line 3136, column 9
Out of bound memory access (access exceeds upper limit of memory block)
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-desktop-item.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-desktop-item.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2/* mate-desktop-item.c - MATE Desktop File Representation
3
4 Copyright (C) 1999, 2000 Red Hat Inc.
5 Copyright (C) 2001 Sid Vicious
6 All rights reserved.
7
8 This file is part of the Mate Library.
9
10 Developed by Elliot Lee <sopwith@redhat.com> and Sid Vicious
11
12 The Mate Library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Library General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
16
17 The Mate Library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Library General Public License for more details.
21
22 You should have received a copy of the GNU Library General Public
23 License along with the Mate Library; see the file COPYING.LIB. If not,
24 write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 Boston, MA 02110-1301, USA. */
26/*
27 @NOTATION@
28 */
29
30#include "config.h"
31
32#include <limits.h>
33#include <ctype.h>
34#include <stdio.h>
35#include <glib.h>
36#include <sys/types.h>
37#include <dirent.h>
38#include <unistd.h>
39#include <time.h>
40#include <string.h>
41#include <glib/gi18n-lib.h>
42#include <locale.h>
43#include <stdlib.h>
44
45#include <gio/gio.h>
46
47#ifdef HAVE_STARTUP_NOTIFICATION
48#define SN_API_NOT_YET_FROZEN
49#include <libsn/sn.h>
50#include <gdk/gdk.h>
51#include <gdk/gdkx.h>
52#include <gtk/gtk.h>
53#endif
54
55#define MATE_DESKTOP_USE_UNSTABLE_API
56#undef MATE_DISABLE_DEPRECATED
57#include <mate-desktop-item.h>
58#include <mate-desktop-utils.h>
59
60#include "private.h"
61
62struct _MateDesktopItem {
63 int refcount;
64
65 /* all languages used */
66 GList *languages;
67
68 MateDesktopItemType type;
69
70 /* `modified' means that the ditem has been
71 * modified since the last save. */
72 gboolean modified;
73
74 /* Keys of the main section only */
75 GList *keys;
76
77 GList *sections;
78
79 /* This includes ALL keys, including
80 * other sections, separated by '/' */
81 GHashTable *main_hash;
82
83 char *location;
84
85 gint64 mtime;
86
87 guint32 launch_time;
88};
89
90/* If mtime is set to this, set_location won't update mtime,
91 * this is to be used internally only. */
92#define DONT_UPDATE_MTIME((gint64)-2) ((gint64)-2)
93
94typedef struct {
95 char *name;
96 GList *keys;
97} Section;
98
99typedef enum {
100 ENCODING_UNKNOWN,
101 ENCODING_UTF8,
102 ENCODING_LEGACY_MIXED
103} Encoding;
104
105/*
106 * IO reading utils, that look like the libc buffered io stuff
107 */
108
109#define READ_BUF_SIZE(32 * 1024) (32 * 1024)
110
111typedef struct {
112 GFile *file;
113 GFileInputStream *stream;
114 char *uri;
115 char *buf;
116 gboolean buf_needs_free;
117 gboolean past_first_read;
118 gboolean eof;
119 guint64 size;
120 gsize pos;
121} ReadBuf;
122
123static MateDesktopItem *ditem_load (ReadBuf *rb,
124 gboolean no_translations,
125 GError **error);
126static gboolean ditem_save (MateDesktopItem *item,
127 const char *uri,
128 GError **error);
129
130static void mate_desktop_item_set_location_gfile (MateDesktopItem *item,
131 GFile *file);
132
133static MateDesktopItem *mate_desktop_item_new_from_gfile (GFile *file,
134 MateDesktopItemLoadFlags flags,
135 GError **error);
136
137static int
138readbuf_getc (ReadBuf *rb)
139{
140 if (rb->eof)
141 return EOF(-1);
142
143 if (rb->size == 0 ||
144 rb->pos == rb->size) {
145 gssize bytes_read;
146
147 if (rb->stream == NULL((void*)0))
148 bytes_read = 0;
149 else
150 bytes_read = g_input_stream_read (G_INPUT_STREAM (rb->stream)((((GInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((rb->stream)), ((g_input_stream_get_type ()))))))
,
151 rb->buf,
152 READ_BUF_SIZE(32 * 1024),
153 NULL((void*)0), NULL((void*)0));
154
155 /* FIXME: handle errors other than EOF */
156 if (bytes_read <= 0) {
157 rb->eof = TRUE(!(0));
158 return EOF(-1);
159 }
160
161 if (rb->size != 0)
162 rb->past_first_read = TRUE(!(0));
163 rb->size = bytes_read;
164 rb->pos = 0;
165
166 }
167
168 return (guchar) rb->buf[rb->pos++];
169}
170
171/* Note, does not include the trailing \n */
172static char *
173readbuf_gets (char *buf, gsize bufsize, ReadBuf *rb)
174{
175 int c;
176 gsize pos;
177
178 g_return_val_if_fail (buf != NULL, NULL)do { if ((buf != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "buf != NULL"); return
(((void*)0)); } } while (0)
;
179 g_return_val_if_fail (rb != NULL, NULL)do { if ((rb != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "rb != NULL"); return
(((void*)0)); } } while (0)
;
180
181 pos = 0;
182 buf[0] = '\0';
183
184 do {
185 c = readbuf_getc (rb);
186 if (c == EOF(-1) || c == '\n')
187 break;
188 buf[pos++] = c;
189 } while (pos < bufsize-1);
190
191 if (c == EOF(-1) && pos == 0)
192 return NULL((void*)0);
193
194 buf[pos++] = '\0';
195
196 return buf;
197}
198
199static ReadBuf *
200readbuf_open (GFile *file, GError **error)
201{
202 GError *local_error;
203 GFileInputStream *stream;
204 char *uri;
205 ReadBuf *rb;
206
207 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
208
209 uri = g_file_get_uri (file);
210 local_error = NULL((void*)0);
211 stream = g_file_read (file, NULL((void*)0), &local_error);
212
213 if (stream == NULL((void*)0)) {
214 g_set_error (error,
215 /* FIXME: better errors */
216 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
217 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
218 _("Error reading file '%s': %s")((char *) g_dgettext ("mate-desktop", "Error reading file '%s': %s"
))
,
219 uri, local_error->message);
220 g_error_free (local_error);
221 g_free (uri);
222 return NULL((void*)0);
223 }
224
225 rb = g_new0 (ReadBuf, 1)((ReadBuf *) g_malloc0_n ((1), sizeof (ReadBuf)));
226 rb->stream = stream;
227 rb->file = g_file_dup (file);
228 rb->uri = uri;
229 rb->buf = g_malloc (READ_BUF_SIZE(32 * 1024));
230 rb->buf_needs_free = TRUE(!(0));
231 /* rb->past_first_read = FALSE; */
232 /* rb->eof = FALSE; */
233 /* rb->size = 0; */
234 /* rb->pos = 0; */
235
236 return rb;
237}
238
239static ReadBuf *
240readbuf_new_from_string (const char *uri, const char *string, gssize length)
241{
242 ReadBuf *rb;
243
244 g_return_val_if_fail (string != NULL, NULL)do { if ((string != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "string != NULL"
); return (((void*)0)); } } while (0)
;
245 g_return_val_if_fail (length >= 0, NULL)do { if ((length >= 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "length >= 0"
); return (((void*)0)); } } while (0)
;
246
247 rb = g_new0 (ReadBuf, 1)((ReadBuf *) g_malloc0_n ((1), sizeof (ReadBuf)));
248 /* rb->file = NULL; */
249 /* rb->stream = NULL; */
250 rb->uri = g_strdup (uri)g_strdup_inline (uri);
251 rb->buf = (char *) string;
252 /* rb->buf_needs_free = FALSE; */
253 /* rb->past_first_read = FALSE; */
254 /* rb->eof = FALSE; */
255 rb->size = length;
256 /* rb->pos = 0; */
257
258 return rb;
259}
260
261static gboolean
262readbuf_rewind (ReadBuf *rb, GError **error)
263{
264 GError *local_error;
265
266 rb->eof = FALSE(0);
267 rb->pos = 0;
268
269 if (!rb->past_first_read)
270 return TRUE(!(0));
271
272 rb->size = 0;
273
274 if (g_seekable_seek (G_SEEKABLE (rb->stream)((((GSeekable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((rb->stream)), ((g_seekable_get_type ()))))))
,
275 0, G_SEEK_SET, NULL((void*)0), NULL((void*)0)))
276 return TRUE(!(0));
277
278 g_object_unref (rb->stream);
279 local_error = NULL((void*)0);
280 rb->stream = g_file_read (rb->file, NULL((void*)0), &local_error);
281
282 if (rb->stream == NULL((void*)0)) {
283 g_set_error (
284 error, MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
285 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
286 _("Error rewinding file '%s': %s")((char *) g_dgettext ("mate-desktop", "Error rewinding file '%s': %s"
))
,
287 rb->uri, local_error->message);
288 g_error_free (local_error);
289
290 return FALSE(0);
291 }
292
293 return TRUE(!(0));
294}
295
296static void
297readbuf_close (ReadBuf *rb)
298{
299 if (rb->stream != NULL((void*)0))
300 g_object_unref (rb->stream);
301 if (rb->file != NULL((void*)0))
302 g_object_unref (rb->file);
303 g_free (rb->uri);
304 if (rb->buf_needs_free)
305 g_free (rb->buf);
306 g_free (rb);
307}
308
309static MateDesktopItemType
310type_from_string (const char *type)
311{
312 if (!type)
313 return MATE_DESKTOP_ITEM_TYPE_NULL;
314
315 switch (type [0]) {
316 case 'A':
317 if (!strcmp (type, "Application"))
318 return MATE_DESKTOP_ITEM_TYPE_APPLICATION;
319 break;
320 case 'L':
321 if (!strcmp (type, "Link"))
322 return MATE_DESKTOP_ITEM_TYPE_LINK;
323 break;
324 case 'F':
325 if (!strcmp (type, "FSDevice"))
326 return MATE_DESKTOP_ITEM_TYPE_FSDEVICE;
327 break;
328 case 'M':
329 if (!strcmp (type, "MimeType"))
330 return MATE_DESKTOP_ITEM_TYPE_MIME_TYPE;
331 break;
332 case 'D':
333 if (!strcmp (type, "Directory"))
334 return MATE_DESKTOP_ITEM_TYPE_DIRECTORY;
335 break;
336 case 'S':
337 if (!strcmp (type, "Service"))
338 return MATE_DESKTOP_ITEM_TYPE_SERVICE;
339
340 else if (!strcmp (type, "ServiceType"))
341 return MATE_DESKTOP_ITEM_TYPE_SERVICE_TYPE;
342 break;
343 default:
344 break;
345 }
346
347 return MATE_DESKTOP_ITEM_TYPE_OTHER;
348}
349
350/**
351 * mate_desktop_item_new:
352 *
353 * Creates a MateDesktopItem object. The reference count on the returned value is set to '1'.
354 *
355 * Returns: The new MateDesktopItem
356 */
357MateDesktopItem *
358mate_desktop_item_new (void)
359{
360 MateDesktopItem *retval;
361
362 _mate_desktop_init_i18n ();
363
364 retval = g_new0 (MateDesktopItem, 1)((MateDesktopItem *) g_malloc0_n ((1), sizeof (MateDesktopItem
)))
;
365
366 retval->refcount++;
367
368 retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
369 (GDestroyNotify) g_free,
370 (GDestroyNotify) g_free);
371
372 /* These are guaranteed to be set */
373 mate_desktop_item_set_string (retval,
374 MATE_DESKTOP_ITEM_NAME"Name",
375 /* Translators: the "name" mentioned
376 * here is the name of an application or
377 * a document */
378 _("No name")((char *) g_dgettext ("mate-desktop", "No name")));
379 mate_desktop_item_set_string (retval,
380 MATE_DESKTOP_ITEM_ENCODING"Encoding",
381 "UTF-8");
382 mate_desktop_item_set_string (retval,
383 MATE_DESKTOP_ITEM_VERSION"Version",
384 "1.0");
385
386 retval->launch_time = 0;
387
388 return retval;
389}
390
391static Section *
392dup_section (Section *sec)
393{
394 GList *li;
395 Section *retval = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
396
397 retval->name = g_strdup (sec->name)g_strdup_inline (sec->name);
398
399 retval->keys = g_list_copy (sec->keys);
400 for (li = retval->keys; li != NULL((void*)0); li = li->next)
401 li->data = g_strdup (li->data)g_strdup_inline (li->data);
402
403 return retval;
404}
405
406static void
407copy_string_hash (gpointer key, gpointer value, gpointer user_data)
408{
409 GHashTable *copy = user_data;
410 g_hash_table_replace (copy,
411 g_strdup (key)g_strdup_inline (key),
412 g_strdup (value)g_strdup_inline (value));
413}
414
415/**
416 * mate_desktop_item_copy:
417 * @item: The item to be copied
418 *
419 * Creates a copy of a MateDesktopItem. The new copy has a refcount of 1.
420 * Note: Section stack is NOT copied.
421 *
422 * Returns: The new copy
423 */
424MateDesktopItem *
425mate_desktop_item_copy (const MateDesktopItem *item)
426{
427 GList *li;
428 MateDesktopItem *retval;
429
430 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
431 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
432
433 retval = mate_desktop_item_new ();
434
435 retval->type = item->type;
436 retval->modified = item->modified;
437 retval->location = g_strdup (item->location)g_strdup_inline (item->location);
438 retval->mtime = item->mtime;
439 retval->launch_time = item->launch_time;
440
441 /* Languages */
442 retval->languages = g_list_copy (item->languages);
443 for (li = retval->languages; li != NULL((void*)0); li = li->next)
444 li->data = g_strdup (li->data)g_strdup_inline (li->data);
445
446 /* Keys */
447 retval->keys = g_list_copy (item->keys);
448 for (li = retval->keys; li != NULL((void*)0); li = li->next)
449 li->data = g_strdup (li->data)g_strdup_inline (li->data);
450
451 /* Sections */
452 retval->sections = g_list_copy (item->sections);
453 for (li = retval->sections; li != NULL((void*)0); li = li->next)
454 li->data = dup_section (li->data);
455
456 retval->main_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
457 (GDestroyNotify) g_free,
458 (GDestroyNotify) g_free);
459
460 g_hash_table_foreach (item->main_hash,
461 copy_string_hash,
462 retval->main_hash);
463
464 return retval;
465}
466
467static void
468read_sort_order (MateDesktopItem *item, GFile *dir)
469{
470 GFile *child;
471 char buf[BUFSIZ8192];
472 GString *str;
473 ReadBuf *rb;
474
475 child = g_file_get_child (dir, ".order");
476
477 rb = readbuf_open (child, NULL((void*)0));
478 g_object_unref (child);
479
480 if (rb == NULL((void*)0))
481 return;
482
483 str = NULL((void*)0);
484 while (readbuf_gets (buf, sizeof (buf), rb) != NULL((void*)0)) {
485 if (str == NULL((void*)0))
486 str = g_string_new (buf);
487 else
488 g_string_append (str, buf)(__builtin_constant_p (buf) ? __extension__ ({ const char * const
__val = (buf); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, buf, (gssize) -1
))
;
489 g_string_append_c (str, ';')g_string_append_c_inline (str, ';');
490 }
491 readbuf_close (rb);
492 if (str != NULL((void*)0)) {
493 mate_desktop_item_set_string (item, MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder",
494 str->str);
495 g_string_free (str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(str), ((!(0)))) : g_string_free_and_steal (str)) : (g_string_free
) ((str), ((!(0)))))
;
496 }
497}
498
499static MateDesktopItem *
500make_fake_directory (GFile *dir)
501{
502 MateDesktopItem *item;
503 GFile *child;
504
505 item = mate_desktop_item_new ();
506 mate_desktop_item_set_entry_type (item,
507 MATE_DESKTOP_ITEM_TYPE_DIRECTORY);
508
509 item->mtime = DONT_UPDATE_MTIME((gint64)-2); /* it doesn't exist, we know that */
510 child = g_file_get_child (dir, ".directory");
511 mate_desktop_item_set_location_gfile (item, child);
512 item->mtime = 0;
513 g_object_unref (child);
514
515 read_sort_order (item, dir);
516
517 return item;
518}
519
520/**
521 * mate_desktop_item_new_from_file:
522 * @file: The filename or directory path to load the MateDesktopItem from
523 * @flags: Flags to influence the loading process
524 *
525 * This function loads 'file' and turns it into a MateDesktopItem.
526 *
527 * Returns: The newly loaded item.
528 */
529MateDesktopItem *
530mate_desktop_item_new_from_file (const char *file,
531 MateDesktopItemLoadFlags flags,
532 GError **error)
533{
534 MateDesktopItem *retval;
535 GFile *gfile;
536
537 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
538
539 gfile = g_file_new_for_path (file);
540 retval = mate_desktop_item_new_from_gfile (gfile, flags, error);
541 g_object_unref (gfile);
542
543 return retval;
544}
545
546/**
547 * mate_desktop_item_new_from_uri:
548 * @uri: URI to load the MateDesktopItem from
549 * @flags: Flags to influence the loading process
550 *
551 * This function loads 'uri' and turns it into a MateDesktopItem.
552 *
553 * Returns: The newly loaded item.
554 */
555MateDesktopItem *
556mate_desktop_item_new_from_uri (const char *uri,
557 MateDesktopItemLoadFlags flags,
558 GError **error)
559{
560 MateDesktopItem *retval;
561 GFile *file;
562
563 g_return_val_if_fail (uri != NULL, NULL)do { if ((uri != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "uri != NULL"); return
(((void*)0)); } } while (0)
;
564
565 file = g_file_new_for_uri (uri);
566 retval = mate_desktop_item_new_from_gfile (file, flags, error);
567 g_object_unref (file);
568
569 return retval;
570}
571
572static MateDesktopItem *
573mate_desktop_item_new_from_gfile (GFile *file,
574 MateDesktopItemLoadFlags flags,
575 GError **error)
576{
577 MateDesktopItem *retval;
578 GFile *subfn;
579 GFileInfo *info;
580 GFileType type;
581 GFile *parent;
582 gint64 mtime = 0;
583 ReadBuf *rb;
584
585 g_return_val_if_fail (file != NULL, NULL)do { if ((file != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "file != NULL");
return (((void*)0)); } } while (0)
;
586
587 info = g_file_query_info (file,
588 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type"","G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
589 G_FILE_QUERY_INFO_NONE, NULL((void*)0), error);
590 if (info == NULL((void*)0))
591 return NULL((void*)0);
592
593 type = g_file_info_get_file_type (info);
594
595 if (type != G_FILE_TYPE_REGULAR && type != G_FILE_TYPE_DIRECTORY) {
596 char *uri;
597
598 uri = g_file_get_uri (file);
599 g_set_error (error,
600 /* FIXME: better errors */
601 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
602 MATE_DESKTOP_ITEM_ERROR_INVALID_TYPE,
603 _("File '%s' is not a regular file or directory.")((char *) g_dgettext ("mate-desktop", "File '%s' is not a regular file or directory."
))
,
604 uri);
605
606 g_free (uri);
607 g_object_unref (info);
608
609 return NULL((void*)0);
610 }
611
612 mtime = g_file_info_get_attribute_uint64 (info,
613 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
614
615 g_object_unref (info);
616
617 if (type == G_FILE_TYPE_DIRECTORY) {
618 GFile *child;
619 GFileInfo *child_info;
620
621 child = g_file_get_child (file, ".directory");
622 child_info = g_file_query_info (child,
623 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
624 G_FILE_QUERY_INFO_NONE,
625 NULL((void*)0), NULL((void*)0));
626
627 if (child_info == NULL((void*)0)) {
628 g_object_unref (child);
629
630 if (flags & MATE_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS) {
631 return NULL((void*)0);
632 } else {
633 return make_fake_directory (file);
634 }
635 }
636
637 mtime = g_file_info_get_attribute_uint64 (child_info,
638 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
639 g_object_unref (child_info);
640
641 subfn = child;
642 } else {
643 subfn = g_file_dup (file);
644 }
645
646 rb = readbuf_open (subfn, error);
647
648 if (rb == NULL((void*)0)) {
649 g_object_unref (subfn);
650 return NULL((void*)0);
651 }
652
653 retval = ditem_load (rb,
654 (flags & MATE_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS) != 0,
655 error);
656
657 if (retval == NULL((void*)0)) {
658 g_object_unref (subfn);
659 return NULL((void*)0);
660 }
661
662 if (flags & MATE_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS &&
663 ! mate_desktop_item_exists (retval)) {
664 mate_desktop_item_unref (retval);
665 g_object_unref (subfn);
666 return NULL((void*)0);
667 }
668
669 retval->mtime = DONT_UPDATE_MTIME((gint64)-2);
670 mate_desktop_item_set_location_gfile (retval, subfn);
671 retval->mtime = mtime;
672
673 parent = g_file_get_parent (file);
674 if (parent != NULL((void*)0)) {
675 read_sort_order (retval, parent);
676 g_object_unref (parent);
677 }
678
679 g_object_unref (subfn);
680
681 return retval;
682}
683
684/**
685 * mate_desktop_item_new_from_string:
686 * @string: string to load the MateDesktopItem from
687 * @length: length of string, or -1 to use strlen
688 * @flags: Flags to influence the loading process
689 * @error: place to put errors
690 *
691 * This function turns the contents of the string into a MateDesktopItem.
692 *
693 * Returns: The newly loaded item.
694 */
695MateDesktopItem *
696mate_desktop_item_new_from_string (const char *uri,
697 const char *string,
698 gssize length,
699 MateDesktopItemLoadFlags flags,
700 GError **error)
701{
702 MateDesktopItem *retval;
703 ReadBuf *rb;
704
705 g_return_val_if_fail (string != NULL, NULL)do { if ((string != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "string != NULL"
); return (((void*)0)); } } while (0)
;
706 g_return_val_if_fail (length >= -1, NULL)do { if ((length >= -1)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "length >= -1"
); return (((void*)0)); } } while (0)
;
707
708 if (length == -1) {
709 length = strlen (string);
710 }
711
712 rb = readbuf_new_from_string (uri, string, length);
713
714 retval = ditem_load (rb,
715 (flags & MATE_DESKTOP_ITEM_LOAD_NO_TRANSLATIONS) != 0,
716 error);
717
718 if (retval == NULL((void*)0)) {
719 return NULL((void*)0);
720 }
721
722 /* FIXME: Sort order? */
723
724 return retval;
725}
726
727static char *
728lookup_desktop_file_in_data_dir (const char *desktop_file,
729 const char *data_dir)
730{
731 char *path;
732
733 path = g_build_filename (data_dir, "applications", desktop_file, NULL((void*)0));
734 if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
735 g_free (path);
736 return NULL((void*)0);
737 }
738 return path;
739}
740
741static char *
742file_from_basename (const char *basename)
743{
744 const char * const *system_data_dirs;
745 const char *user_data_dir;
746 char *retval;
747 int i;
748
749 user_data_dir = g_get_user_data_dir ();
750 system_data_dirs = g_get_system_data_dirs ();
751
752 if ((retval = lookup_desktop_file_in_data_dir (basename, user_data_dir))) {
753 return retval;
754 }
755 for (i = 0; system_data_dirs[i]; i++) {
756 if ((retval = lookup_desktop_file_in_data_dir (basename, system_data_dirs[i]))) {
757 return retval;
758 }
759 }
760 return NULL((void*)0);
761}
762
763/**
764 * mate_desktop_item_new_from_basename:
765 * @basename: The basename of the MateDesktopItem to load.
766 * @flags: Flags to influence the loading process
767 *
768 * This function loads 'basename' from a system data directory and
769 * returns its MateDesktopItem.
770 *
771 * Returns: The newly loaded item.
772 */
773MateDesktopItem *
774mate_desktop_item_new_from_basename (const char *basename,
775 MateDesktopItemLoadFlags flags,
776 GError **error)
777{
778 MateDesktopItem *retval;
779 char *file;
780
781 g_return_val_if_fail (basename != NULL, NULL)do { if ((basename != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "basename != NULL"
); return (((void*)0)); } } while (0)
;
782
783 if (!(file = file_from_basename (basename))) {
784 g_set_error (error,
785 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
786 MATE_DESKTOP_ITEM_ERROR_CANNOT_OPEN,
787 _("Cannot find file '%s'")((char *) g_dgettext ("mate-desktop", "Cannot find file '%s'"
))
,
788 basename);
789 return NULL((void*)0);
790 }
791
792 retval = mate_desktop_item_new_from_file (file, flags, error);
793 g_free (file);
794
795 return retval;
796}
797
798/**
799 * mate_desktop_item_save:
800 * @item: A desktop item
801 * @under: A new uri (location) for this #MateDesktopItem
802 * @force: Save even if it wasn't modified
803 * @error: #GError return
804 *
805 * Writes the specified item to disk. If the 'under' is NULL, the original
806 * location is used. It sets the location of this entry to point to the
807 * new location.
808 *
809 * Returns: boolean. %TRUE if the file was saved, %FALSE otherwise
810 */
811gboolean
812mate_desktop_item_save (MateDesktopItem *item,
813 const char *under,
814 gboolean force,
815 GError **error)
816{
817 const char *uri;
818
819 if (under == NULL((void*)0) &&
1
Assuming 'under' is not equal to NULL
820 ! force &&
821 ! item->modified)
822 return TRUE(!(0));
823
824 if (under
1.1
'under' is not equal to NULL
== NULL((void*)0))
2
Taking false branch
825 uri = item->location;
826 else
827 uri = under;
828
829 if (uri
2.1
'uri' is not equal to NULL
== NULL((void*)0)) {
3
Taking false branch
830 g_set_error (error,
831 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
832 MATE_DESKTOP_ITEM_ERROR_NO_FILENAME,
833 _("No filename to save to")((char *) g_dgettext ("mate-desktop", "No filename to save to"
))
);
834 return FALSE(0);
835 }
836
837 if ( ! ditem_save (item, uri, error))
4
Calling 'ditem_save'
838 return FALSE(0);
839
840 item->modified = FALSE(0);
841 item->mtime = g_get_real_time () / G_USEC_PER_SEC1000000;
842
843 return TRUE(!(0));
844}
845
846/**
847 * mate_desktop_item_ref:
848 * @item: A desktop item
849 *
850 * Description: Increases the reference count of the specified item.
851 *
852 * Returns: the newly referenced @item
853 */
854MateDesktopItem *
855mate_desktop_item_ref (MateDesktopItem *item)
856{
857 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
858
859 item->refcount++;
860
861 return item;
862}
863
864static void
865free_section (gpointer data)
866{
867 Section *section = data;
868
869 g_free (section->name);
870 section->name = NULL((void*)0);
871
872 g_list_free_full (section->keys, g_free);
873 section->keys = NULL((void*)0);
874
875 g_free (section);
876}
877
878/**
879 * mate_desktop_item_unref:
880 * @item: A desktop item
881 *
882 * Decreases the reference count of the specified item, and destroys the item if there are no more references left.
883 */
884void
885mate_desktop_item_unref (MateDesktopItem *item)
886{
887 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
888 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
889
890 item->refcount--;
891
892 if(item->refcount != 0)
893 return;
894
895 g_list_free_full (item->languages, g_free);
896 item->languages = NULL((void*)0);
897
898 g_list_free_full (item->keys, g_free);
899 item->keys = NULL((void*)0);
900
901 g_list_free_full (item->sections, (GDestroyNotify) free_section);
902 item->sections = NULL((void*)0);
903
904 g_hash_table_destroy (item->main_hash);
905 item->main_hash = NULL((void*)0);
906
907 g_free (item->location);
908 item->location = NULL((void*)0);
909
910 g_free (item);
911}
912
913static Section *
914find_section (MateDesktopItem *item, const char *section)
915{
916 GList *li;
917 Section *sec;
918
919 if (section == NULL((void*)0))
920 return NULL((void*)0);
921 if (strcmp (section, "Desktop Entry") == 0)
922 return NULL((void*)0);
923
924 for (li = item->sections; li != NULL((void*)0); li = li->next) {
925 sec = li->data;
926 if (strcmp (sec->name, section) == 0)
927 return sec;
928 }
929
930 sec = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
931 sec->name = g_strdup (section)g_strdup_inline (section);
932 sec->keys = NULL((void*)0);
933
934 item->sections = g_list_append (item->sections, sec);
935
936 /* Don't mark the item modified, this is just an empty section,
937 * it won't be saved even */
938
939 return sec;
940}
941
942static Section *
943section_from_key (MateDesktopItem *item, const char *key)
944{
945 char *p;
946 char *name;
947 Section *sec;
948
949 if (key == NULL((void*)0))
950 return NULL((void*)0);
951
952 p = strchr (key, '/');
953 if (p == NULL((void*)0))
954 return NULL((void*)0);
955
956 name = g_strndup (key, p - key);
957
958 sec = find_section (item, name);
959
960 g_free (name);
961
962 return sec;
963}
964
965static const char *
966key_basename (const char *key)
967{
968 char *p = strrchr (key, '/');
969 if (p != NULL((void*)0))
970 return p+1;
971 else
972 return key;
973}
974
975static const char *
976lookup (const MateDesktopItem *item, const char *key)
977{
978 return g_hash_table_lookup (item->main_hash, key);
979}
980
981static const char *
982lookup_locale (const MateDesktopItem *item, const char *key, const char *locale)
983{
984 if (locale == NULL((void*)0) ||
985 strcmp (locale, "C") == 0) {
986 return lookup (item, key);
987 } else {
988 const char *ret;
989 char *full = g_strdup_printf ("%s[%s]", key, locale);
990 ret = lookup (item, full);
991 g_free (full);
992 return ret;
993 }
994}
995
996static const char *
997lookup_best_locale (const MateDesktopItem *item, const char *key)
998{
999 const char * const *langs_pointer;
1000 int i;
1001
1002 langs_pointer = g_get_language_names ();
1003 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
1004 const char *ret = NULL((void*)0);
1005
1006 ret = lookup_locale (item, key, langs_pointer[i]);
1007 if (ret != NULL((void*)0))
1008 return ret;
1009 }
1010
1011 return NULL((void*)0);
1012}
1013
1014static void
1015set (MateDesktopItem *item, const char *key, const char *value)
1016{
1017 Section *sec = section_from_key (item, key);
1018
1019 if (sec != NULL((void*)0)) {
1020 if (value != NULL((void*)0)) {
1021 if (g_hash_table_lookup (item->main_hash, key) == NULL((void*)0))
1022 sec->keys = g_list_append
1023 (sec->keys,
1024 g_strdup (key_basename (key))g_strdup_inline (key_basename (key)));
1025
1026 g_hash_table_replace (item->main_hash,
1027 g_strdup (key)g_strdup_inline (key),
1028 g_strdup (value)g_strdup_inline (value));
1029 } else {
1030 GList *list = g_list_find_custom
1031 (sec->keys, key_basename (key),
1032 (GCompareFunc)strcmp);
1033 if (list != NULL((void*)0)) {
1034 g_free (list->data);
1035 sec->keys =
1036 g_list_delete_link (sec->keys, list);
1037 }
1038 g_hash_table_remove (item->main_hash, key);
1039 }
1040 } else {
1041 if (value != NULL((void*)0)) {
1042 if (g_hash_table_lookup (item->main_hash, key) == NULL((void*)0))
1043 item->keys = g_list_append (item->keys,
1044 g_strdup (key)g_strdup_inline (key));
1045
1046 g_hash_table_replace (item->main_hash,
1047 g_strdup (key)g_strdup_inline (key),
1048 g_strdup (value)g_strdup_inline (value));
1049 } else {
1050 GList *list = g_list_find_custom
1051 (item->keys, key, (GCompareFunc)strcmp);
1052 if (list != NULL((void*)0)) {
1053 g_free (list->data);
1054 item->keys =
1055 g_list_delete_link (item->keys, list);
1056 }
1057 g_hash_table_remove (item->main_hash, key);
1058 }
1059 }
1060 item->modified = TRUE(!(0));
1061}
1062
1063static void
1064set_locale (MateDesktopItem *item, const char *key,
1065 const char *locale, const char *value)
1066{
1067 if (locale == NULL((void*)0) ||
1068 strcmp (locale, "C") == 0) {
1069 set (item, key, value);
1070 } else {
1071 char *full = g_strdup_printf ("%s[%s]", key, locale);
1072 set (item, full, value);
1073 g_free (full);
1074
1075 /* add the locale to the list of languages if it wasn't there
1076 * before */
1077 if (g_list_find_custom (item->languages, locale,
1078 (GCompareFunc)strcmp) == NULL((void*)0))
1079 item->languages = g_list_prepend (item->languages,
1080 g_strdup (locale)g_strdup_inline (locale));
1081 }
1082}
1083
1084static char **
1085list_to_vector (GSList *list)
1086{
1087 int len = g_slist_length (list);
1088 char **argv;
1089 int i;
1090 GSList *li;
1091
1092 argv = g_new0 (char *, len+1)((char * *) g_malloc0_n ((len+1), sizeof (char *)));
1093
1094 for (i = 0, li = list;
1095 li != NULL((void*)0);
1096 li = li->next, i++) {
1097 argv[i] = g_strdup (li->data)g_strdup_inline (li->data);
1098 }
1099 argv[i] = NULL((void*)0);
1100
1101 return argv;
1102}
1103
1104static GSList *
1105make_args (GList *files)
1106{
1107 GSList *list = NULL((void*)0);
1108 GList *li;
1109
1110 for (li = files; li != NULL((void*)0); li = li->next) {
1111 GFile *gfile;
1112 const char *file = li->data;
1113 if (file == NULL((void*)0))
1114 continue;
1115 gfile = g_file_new_for_uri (file);
1116 list = g_slist_prepend (list, gfile);
1117 }
1118
1119 return g_slist_reverse (list);
1120}
1121
1122static void
1123free_args (GSList *list)
1124{
1125 GSList *li;
1126
1127 for (li = list; li != NULL((void*)0); li = li->next) {
1128 g_object_unref (G_FILE (li->data)((((GFile*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((li->data)), ((g_file_get_type ()))))))
);
1129 li->data = NULL((void*)0);
1130 }
1131 g_slist_free (list);
1132}
1133
1134static char *
1135escape_single_quotes (const char *s,
1136 gboolean in_single_quotes,
1137 gboolean in_double_quotes)
1138{
1139 const char *p;
1140 GString *gs;
1141 const char *pre = "";
1142 const char *post = "";
1143
1144 if ( ! in_single_quotes && ! in_double_quotes) {
1145 pre = "'";
1146 post = "'";
1147 } else if ( ! in_single_quotes && in_double_quotes) {
1148 pre = "\"'";
1149 post = "'\"";
1150 }
1151
1152 if (strchr (s, '\'') == NULL((void*)0)) {
1153 return g_strconcat (pre, s, post, NULL((void*)0));
1154 }
1155
1156 gs = g_string_new (pre);
1157
1158 for (p = s; *p != '\0'; p++) {
1159 if (*p == '\'')
1160 g_string_append (gs, "'\\''")(__builtin_constant_p ("'\\''") ? __extension__ ({ const char
* const __val = ("'\\''"); g_string_append_len_inline (gs, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (gs, "'\\''"
, (gssize) -1))
;
1161 else
1162 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1163 }
1164
1165 g_string_append (gs, post)(__builtin_constant_p (post) ? __extension__ ({ const char * const
__val = (post); g_string_append_len_inline (gs, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (gs, post, (gssize) -1
))
;
1166
1167 return g_string_free (gs, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((gs),
((0))) : g_string_free_and_steal (gs)) : (g_string_free) ((gs
), ((0))))
;
1168}
1169
1170typedef enum {
1171 URI_TO_STRING,
1172 URI_TO_LOCAL_PATH,
1173 URI_TO_LOCAL_DIRNAME,
1174 URI_TO_LOCAL_BASENAME
1175} ConversionType;
1176
1177static char *
1178convert_uri (GFile *file,
1179 ConversionType conversion)
1180{
1181 char *retval = NULL((void*)0);
1182
1183 switch (conversion) {
1184 case URI_TO_STRING:
1185 retval = g_file_get_uri (file);
1186 break;
1187 case URI_TO_LOCAL_PATH:
1188 retval = g_file_get_path (file);
1189 break;
1190 case URI_TO_LOCAL_DIRNAME:
1191 {
1192 char *local_path;
1193
1194 local_path = g_file_get_path (file);
1195 retval = g_path_get_dirname (local_path);
1196 g_free (local_path);
1197 }
1198 break;
1199 case URI_TO_LOCAL_BASENAME:
1200 retval = g_file_get_basename (file);
1201 break;
1202 default:
1203 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-desktop-item.c"
, 1203, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1204 }
1205
1206 return retval;
1207}
1208
1209typedef enum {
1210 ADDED_NONE = 0,
1211 ADDED_SINGLE,
1212 ADDED_ALL
1213} AddedStatus;
1214
1215static AddedStatus
1216append_all_converted (GString *str,
1217 ConversionType conversion,
1218 GSList *args,
1219 gboolean in_single_quotes,
1220 gboolean in_double_quotes,
1221 AddedStatus added_status)
1222{
1223 GSList *l;
1224
1225 for (l = args; l; l = l->next) {
1226 char *converted;
1227 char *escaped;
1228
1229 if (!(converted = convert_uri (l->data, conversion)))
1230 continue;
1231
1232 g_string_append (str, " ")(__builtin_constant_p (" ") ? __extension__ ({ const char * const
__val = (" "); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, " ", (gssize) -1
))
;
1233
1234 escaped = escape_single_quotes (converted,
1235 in_single_quotes,
1236 in_double_quotes);
1237 g_string_append (str, escaped)(__builtin_constant_p (escaped) ? __extension__ ({ const char
* const __val = (escaped); g_string_append_len_inline (str, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (str, escaped
, (gssize) -1))
;
1238
1239 g_free (escaped);
1240 g_free (converted);
1241 }
1242
1243 return ADDED_ALL;
1244}
1245
1246static AddedStatus
1247append_first_converted (GString *str,
1248 ConversionType conversion,
1249 GSList **arg_ptr,
1250 gboolean in_single_quotes,
1251 gboolean in_double_quotes,
1252 AddedStatus added_status)
1253{
1254 GSList *l;
1255 char *converted = NULL((void*)0);
1256 char *escaped;
1257
1258 for (l = *arg_ptr; l; l = l->next) {
1259 if ((converted = convert_uri (l->data, conversion)))
1260 break;
1261
1262 *arg_ptr = l->next;
1263 }
1264
1265 if (!converted)
1266 return added_status;
1267
1268 escaped = escape_single_quotes (converted, in_single_quotes, in_double_quotes);
1269 g_string_append (str, escaped)(__builtin_constant_p (escaped) ? __extension__ ({ const char
* const __val = (escaped); g_string_append_len_inline (str, __val
, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val
))) : (gssize) -1); }) : g_string_append_len_inline (str, escaped
, (gssize) -1))
;
1270 g_free (escaped);
1271 g_free (converted);
1272
1273 return added_status != ADDED_ALL ? ADDED_SINGLE : added_status;
1274}
1275
1276static gboolean
1277do_percent_subst (const MateDesktopItem *item,
1278 const char *arg,
1279 GString *str,
1280 gboolean in_single_quotes,
1281 gboolean in_double_quotes,
1282 GSList *args,
1283 GSList **arg_ptr,
1284 AddedStatus *added_status)
1285{
1286 char *esc;
1287 const char *cs;
1288
1289 if (arg[0] != '%' || arg[1] == '\0') {
1290 return FALSE(0);
1291 }
1292
1293 switch (arg[1]) {
1294 case '%':
1295 g_string_append_c (str, '%')g_string_append_c_inline (str, '%');
1296 break;
1297 case 'U':
1298 *added_status = append_all_converted (str,
1299 URI_TO_STRING,
1300 args,
1301 in_single_quotes,
1302 in_double_quotes,
1303 *added_status);
1304 break;
1305 case 'F':
1306 *added_status = append_all_converted (str,
1307 URI_TO_LOCAL_PATH,
1308 args,
1309 in_single_quotes,
1310 in_double_quotes,
1311 *added_status);
1312 break;
1313 case 'N':
1314 *added_status = append_all_converted (str,
1315 URI_TO_LOCAL_BASENAME,
1316 args,
1317 in_single_quotes,
1318 in_double_quotes,
1319 *added_status);
1320 break;
1321 case 'D':
1322 *added_status = append_all_converted (str,
1323 URI_TO_LOCAL_DIRNAME,
1324 args,
1325 in_single_quotes,
1326 in_double_quotes,
1327 *added_status);
1328 break;
1329 case 'f':
1330 *added_status = append_first_converted (str,
1331 URI_TO_LOCAL_PATH,
1332 arg_ptr,
1333 in_single_quotes,
1334 in_double_quotes,
1335 *added_status);
1336 break;
1337 case 'u':
1338 *added_status = append_first_converted (str,
1339 URI_TO_STRING,
1340 arg_ptr,
1341 in_single_quotes,
1342 in_double_quotes,
1343 *added_status);
1344 break;
1345 case 'd':
1346 *added_status = append_first_converted (str,
1347 URI_TO_LOCAL_DIRNAME,
1348 arg_ptr,
1349 in_single_quotes,
1350 in_double_quotes,
1351 *added_status);
1352 break;
1353 case 'n':
1354 *added_status = append_first_converted (str,
1355 URI_TO_LOCAL_BASENAME,
1356 arg_ptr,
1357 in_single_quotes,
1358 in_double_quotes,
1359 *added_status);
1360 break;
1361 case 'm':
1362 /* Note: v0.9.4 of the spec says this is deprecated
1363 * and replace with --miniicon iconname */
1364 cs = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_MINI_ICON"MiniIcon");
1365 if (cs != NULL((void*)0)) {
1366 g_string_append (str, "--miniicon=")(__builtin_constant_p ("--miniicon=") ? __extension__ ({ const
char * const __val = ("--miniicon="); g_string_append_len_inline
(str, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val
) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(str, "--miniicon=", (gssize) -1))
;
1367 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1368 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1369 }
1370 break;
1371 case 'i':
1372 /* Note: v0.9.4 of the spec says replace with --icon iconname */
1373 cs = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_ICON"Icon");
1374 if (cs != NULL((void*)0)) {
1375 g_string_append (str, "--icon=")(__builtin_constant_p ("--icon=") ? __extension__ ({ const char
* const __val = ("--icon="); g_string_append_len_inline (str
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (str
, "--icon=", (gssize) -1))
;
1376 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1377 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1378 }
1379 break;
1380 case 'c':
1381 cs = mate_desktop_item_get_localestring (item, MATE_DESKTOP_ITEM_NAME"Name");
1382 if (cs != NULL((void*)0)) {
1383 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1384 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1385 g_free (esc);
1386 }
1387 break;
1388 case 'k':
1389 if (item->location != NULL((void*)0)) {
1390 esc = escape_single_quotes (item->location, in_single_quotes, in_double_quotes);
1391 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1392 g_free (esc);
1393 }
1394 break;
1395 case 'v':
1396 cs = mate_desktop_item_get_localestring (item, MATE_DESKTOP_ITEM_DEV"Dev");
1397 if (cs != NULL((void*)0)) {
1398 esc = escape_single_quotes (cs, in_single_quotes, in_double_quotes);
1399 g_string_append (str, esc)(__builtin_constant_p (esc) ? __extension__ ({ const char * const
__val = (esc); g_string_append_len_inline (str, __val, (__val
!= ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize
) -1); }) : g_string_append_len_inline (str, esc, (gssize) -1
))
;
1400 g_free (esc);
1401 }
1402 break;
1403 default:
1404 /* Maintain special characters - e.g. "%20" */
1405 if (g_ascii_isdigit (arg [1])((g_ascii_table[(guchar) (arg [1])] & G_ASCII_DIGIT) != 0
)
)
1406 g_string_append_c (str, '%')g_string_append_c_inline (str, '%');
1407 return FALSE(0);
1408 }
1409
1410 return TRUE(!(0));
1411}
1412
1413static char *
1414expand_string (const MateDesktopItem *item,
1415 const char *s,
1416 GSList *args,
1417 GSList **arg_ptr,
1418 AddedStatus *added_status)
1419{
1420 const char *p;
1421 gboolean escape = FALSE(0);
1422 gboolean single_quot = FALSE(0);
1423 gboolean double_quot = FALSE(0);
1424 GString *gs = g_string_new (NULL((void*)0));
1425
1426 for (p = s; *p != '\0'; p++) {
1427 if (escape) {
1428 escape = FALSE(0);
1429 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1430 } else if (*p == '\\') {
1431 if ( ! single_quot)
1432 escape = TRUE(!(0));
1433 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1434 } else if (*p == '\'') {
1435 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1436 if ( ! single_quot && ! double_quot) {
1437 single_quot = TRUE(!(0));
1438 } else if (single_quot) {
1439 single_quot = FALSE(0);
1440 }
1441 } else if (*p == '"') {
1442 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1443 if ( ! single_quot && ! double_quot) {
1444 double_quot = TRUE(!(0));
1445 } else if (double_quot) {
1446 double_quot = FALSE(0);
1447 }
1448 } else if (*p == '%') {
1449 if (do_percent_subst (item, p, gs,
1450 single_quot, double_quot,
1451 args, arg_ptr,
1452 added_status)) {
1453 p++;
1454 }
1455 } else {
1456 g_string_append_c (gs, *p)g_string_append_c_inline (gs, *p);
1457 }
1458 }
1459 return g_string_free (gs, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((gs),
((0))) : g_string_free_and_steal (gs)) : (g_string_free) ((gs
), ((0))))
;
1460}
1461
1462/*Functions in this code block should only ever be reached in x11*/
1463#ifdef HAVE_STARTUP_NOTIFICATION
1464static void
1465sn_error_trap_push (SnDisplay *display,
1466 Display *xdisplay)
1467{
1468 GdkDisplay *gdkdisplay;
1469
1470 gdkdisplay = gdk_display_get_default ();
1471 gdk_x11_display_error_trap_push (gdkdisplay);
1472}
1473
1474static void
1475sn_error_trap_pop (SnDisplay *display,
1476 Display *xdisplay)
1477{
1478 GdkDisplay *gdkdisplay;
1479
1480 gdkdisplay = gdk_display_get_default ();
1481 gdk_x11_display_error_trap_pop_ignored (gdkdisplay);
1482}
1483
1484static char **
1485make_spawn_environment_for_sn_context (SnLauncherContext *sn_context,
1486 char **envp)
1487{
1488 char **retval;
1489 char **freeme;
1490 int i, j;
1491 int desktop_startup_id_len;
1492
1493 retval = freeme = NULL((void*)0);
1494
1495 if (envp == NULL((void*)0)) {
1496 envp = freeme = g_listenv ();
1497 for (i = 0; envp[i]; i++) {
1498 char *name = envp[i];
1499
1500 envp[i] = g_strjoin ("=", name, g_getenv (name), NULL((void*)0));
1501 g_free (name);
1502 }
1503 } else {
1504 for (i = 0; envp[i]; i++)
1505 ;
1506 }
1507
1508 retval = g_new (char *, i + 2)((char * *) g_malloc_n ((i + 2), sizeof (char *)));
1509
1510 desktop_startup_id_len = strlen ("DESKTOP_STARTUP_ID");
1511
1512 for (i = 0, j = 0; envp[i]; i++) {
1513 if (strncmp (envp[i], "DESKTOP_STARTUP_ID", desktop_startup_id_len) != 0) {
1514 retval[j] = g_strdup (envp[i])g_strdup_inline (envp[i]);
1515 ++j;
1516 }
1517 }
1518
1519 retval[j] = g_strdup_printf ("DESKTOP_STARTUP_ID=%s",
1520 sn_launcher_context_get_startup_id (sn_context));
1521 ++j;
1522 retval[j] = NULL((void*)0);
1523
1524 g_strfreev (freeme);
1525
1526 return retval;
1527}
1528
1529/* This should be fairly long, as it's confusing to users if a startup
1530 * ends when it shouldn't (it appears that the startup failed, and
1531 * they have to relaunch the app). Also the timeout only matters when
1532 * there are bugs and apps don't end their own startup sequence.
1533 *
1534 * This timeout is a "last resort" timeout that ignores whether the
1535 * startup sequence has shown activity or not. Marco and the
1536 * tasklist have smarter, and correspondingly able-to-be-shorter
1537 * timeouts. The reason our timeout is dumb is that we don't monitor
1538 * the sequence (don't use an SnMonitorContext)
1539 */
1540#define STARTUP_TIMEOUT_LENGTH_SEC30 30 /* seconds */
1541#define STARTUP_TIMEOUT_LENGTH(30 * 1000) (STARTUP_TIMEOUT_LENGTH_SEC30 * 1000)
1542
1543typedef struct
1544{
1545 GdkScreen *screen;
1546 GSList *contexts;
1547 guint timeout_id;
1548} StartupTimeoutData;
1549
1550static void
1551free_startup_timeout (void *data)
1552{
1553 StartupTimeoutData *std = data;
1554
1555 g_slist_free_full (std->contexts, (GDestroyNotify) sn_launcher_context_unref);
1556
1557 if (std->timeout_id != 0) {
1558 g_source_remove (std->timeout_id);
1559 std->timeout_id = 0;
1560 }
1561
1562 g_free (std);
1563}
1564
1565static gboolean
1566startup_timeout (void *data)
1567{
1568 StartupTimeoutData *std = data;
1569 GSList *tmp;
1570 int min_timeout;
1571
1572 min_timeout = STARTUP_TIMEOUT_LENGTH(30 * 1000);
1573
1574#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1575 gint64 now = g_get_real_time ();
1576#else
1577 GTimeVal now;
1578 g_get_current_time (&now);
1579#endif
1580
1581 tmp = std->contexts;
1582 while (tmp != NULL((void*)0)) {
1583 SnLauncherContext *sn_context = tmp->data;
1584 GSList *next = tmp->next;
1585 double elapsed;
1586
1587#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1588 time_t tv_sec;
1589 suseconds_t tv_usec;
1590 gint64 tv;
1591
1592 sn_launcher_context_get_last_active_time (sn_context, &tv_sec, &tv_usec);
1593 tv = (tv_sec * G_USEC_PER_SEC1000000) + tv_usec;
1594 elapsed = (double) (now - tv) / 1000.0;
1595#else
1596 long tv_sec, tv_usec;
1597
1598 sn_launcher_context_get_last_active_time (sn_context,
1599 &tv_sec, &tv_usec);
1600
1601 elapsed =
1602 ((((double)now.tv_sec - tv_sec) * G_USEC_PER_SEC1000000 +
1603 (now.tv_usec - tv_usec))) / 1000.0;
1604#endif
1605
1606 if (elapsed >= STARTUP_TIMEOUT_LENGTH(30 * 1000)) {
1607 std->contexts = g_slist_remove (std->contexts,
1608 sn_context);
1609 sn_launcher_context_complete (sn_context);
1610 sn_launcher_context_unref (sn_context);
1611 } else {
1612 min_timeout = MIN (min_timeout, (STARTUP_TIMEOUT_LENGTH - elapsed))(((min_timeout) < (((30 * 1000) - elapsed))) ? (min_timeout
) : (((30 * 1000) - elapsed)))
;
1613 }
1614
1615 tmp = next;
1616 }
1617
1618 /* we'll use seconds for the timeout */
1619 if (min_timeout < 1000)
1620 min_timeout = 1000;
1621
1622 if (std->contexts == NULL((void*)0)) {
1623 std->timeout_id = 0;
1624 } else {
1625 std->timeout_id = g_timeout_add_seconds (min_timeout / 1000,
1626 startup_timeout,
1627 std);
1628 }
1629
1630 /* always remove this one, but we may have reinstalled another one. */
1631 return FALSE(0);
1632}
1633
1634static void
1635add_startup_timeout (GdkScreen *screen,
1636 SnLauncherContext *sn_context)
1637{
1638 StartupTimeoutData *data;
1639
1640 data = g_object_get_data (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "mate-startup-data");
1641 if (data == NULL((void*)0)) {
1642 data = g_new (StartupTimeoutData, 1)((StartupTimeoutData *) g_malloc_n ((1), sizeof (StartupTimeoutData
)))
;
1643 data->screen = screen;
1644 data->contexts = NULL((void*)0);
1645 data->timeout_id = 0;
1646
1647 g_object_set_data_full (G_OBJECT (screen)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((screen)), (((GType) ((20) << (2))))))))
, "mate-startup-data",
1648 data, free_startup_timeout);
1649 }
1650
1651 sn_launcher_context_ref (sn_context);
1652 data->contexts = g_slist_prepend (data->contexts, sn_context);
1653
1654 if (data->timeout_id == 0) {
1655 data->timeout_id = g_timeout_add_seconds (
1656 STARTUP_TIMEOUT_LENGTH_SEC30,
1657 startup_timeout,
1658 data);
1659 }
1660}
1661#endif /* HAVE_STARTUP_NOTIFICATION - functions should only be reached in x11*/
1662
1663static inline char *
1664stringify_uris (GSList *args)
1665{
1666 GString *str;
1667
1668 str = g_string_new (NULL((void*)0));
1669
1670 append_all_converted (str, URI_TO_STRING, args, FALSE(0), FALSE(0), ADDED_NONE);
1671
1672 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1673}
1674
1675static inline char *
1676stringify_files (GSList *args)
1677{
1678 GString *str;
1679
1680 str = g_string_new (NULL((void*)0));
1681
1682 append_all_converted (str, URI_TO_LOCAL_PATH, args, FALSE(0), FALSE(0), ADDED_NONE);
1683
1684 return g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str)
, ((0))) : g_string_free_and_steal (str)) : (g_string_free) (
(str), ((0))))
;
1685}
1686
1687static char **
1688make_environment_for_screen (GdkScreen *screen,
1689 char **envp)
1690{
1691 GdkDisplay *display;
1692 char **retval;
1693 char **freeme;
1694 char *display_name;
1695 int display_index = -1;
1696 int i, env_len;
1697
1698 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((screen)); GType __t = ((gdk_screen_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "GDK_IS_SCREEN (screen)"); return (((void*)0)
); } } while (0)
;
1699
1700 retval = freeme = NULL((void*)0);
1701
1702 if (envp == NULL((void*)0)) {
1703 envp = freeme = g_listenv ();
1704 for (i = 0; envp [i]; i++) {
1705 char *name = envp[i];
1706
1707 envp[i] = g_strjoin ("=", name, g_getenv (name), NULL((void*)0));
1708 g_free (name);
1709 }
1710 }
1711
1712 for (env_len = 0; envp [env_len]; env_len++)
1713 if (strncmp (envp [env_len], "DISPLAY", strlen ("DISPLAY")) == 0)
1714 display_index = env_len;
1715
1716 retval = g_new (char *, env_len + 1)((char * *) g_malloc_n ((env_len + 1), sizeof (char *)));
1717 retval [env_len] = NULL((void*)0);
1718
1719 display = gdk_screen_get_display (screen);
1720 display_name = g_strdup (gdk_display_get_name (display))g_strdup_inline (gdk_display_get_name (display));
1721
1722 for (i = 0; i < env_len; i++)
1723 if (i == display_index)
1724 retval [i] = g_strconcat ("DISPLAY=", display_name, NULL((void*)0));
1725 else
1726 retval [i] = g_strdup (envp[i])g_strdup_inline (envp[i]);
1727
1728 g_assert (i == env_len)do { if (i == env_len) ; else g_assertion_message_expr ("MateDesktop"
, "mate-desktop-item.c", 1728, ((const char*) (__func__)), "i == env_len"
); } while (0)
;
1729
1730 g_free (display_name);
1731 g_strfreev (freeme);
1732
1733 return retval;
1734}
1735
1736static void
1737dummy_child_watch (GPid pid,
1738 gint status,
1739 gpointer user_data)
1740{
1741 /* Nothing, this is just to ensure we don't double fork
1742 * and break pkexec:
1743 * https://bugzilla.gnome.org/show_bug.cgi?id=675789
1744 */
1745}
1746
1747static int
1748ditem_execute (const MateDesktopItem *item,
1749 const char *exec,
1750 GList *file_list,
1751 GdkScreen *screen,
1752 int workspace,
1753 char **envp,
1754 gboolean launch_only_one,
1755 gboolean use_current_dir,
1756 gboolean append_uris,
1757 gboolean append_paths,
1758 gboolean do_not_reap_child,
1759 GError **error)
1760{
1761 char **free_me = NULL((void*)0);
1762 char **real_argv;
1763 int i, ret;
1764 char **term_argv = NULL((void*)0);
1765 int term_argc = 0;
1766 GSList *vector_list;
1767 GSList *args, *arg_ptr;
1768 AddedStatus added_status;
1769 const char *working_dir = NULL((void*)0);
1770 char **temp_argv = NULL((void*)0);
1771 int temp_argc = 0;
1772 char *new_exec, *uris, *temp;
1773 char *exec_locale;
1774 int launched = 0;
1775 GPid pid;
1776#ifdef HAVE_STARTUP_NOTIFICATION
1777 GdkDisplay *gdkdisplay;
1778 SnLauncherContext *sn_context;
1779 SnDisplay *sn_display;
1780 const char *startup_class;
1781#endif
1782
1783 g_return_val_if_fail (item, -1)do { if ((item)) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "item"); return (-1); } } while
(0)
;
1784
1785 if (item->type == MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
1786 working_dir = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_PATH"Path");
1787 if (working_dir &&
1788 !g_file_test (working_dir, G_FILE_TEST_IS_DIR))
1789 working_dir = NULL((void*)0);
1790 }
1791
1792 if (working_dir == NULL((void*)0) && !use_current_dir)
1793 working_dir = g_get_home_dir ();
1794
1795 if (mate_desktop_item_get_boolean (item, MATE_DESKTOP_ITEM_TERMINAL"Terminal")) {
1796 const char *options =
1797 mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_TERMINAL_OPTIONS"TerminalOptions");
1798
1799 if (options != NULL((void*)0)) {
1800 g_shell_parse_argv (options,
1801 &term_argc,
1802 &term_argv,
1803 NULL((void*)0) /* error */);
1804 /* ignore errors */
1805 }
1806
1807 mate_desktop_prepend_terminal_to_vector (&term_argc, &term_argv);
1808 }
1809
1810 args = make_args (file_list);
1811 arg_ptr = make_args (file_list);
1812
1813#ifdef HAVE_STARTUP_NOTIFICATION
1814 GdkDisplay *display = gdk_screen_get_display (gdk_screen_get_default());
1815 if (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1816 {
1817 if (screen)
1818 gdkdisplay = gdk_screen_get_display (screen);
1819 else
1820 gdkdisplay = gdk_display_get_default ();
1821
1822 sn_display = sn_display_new (GDK_DISPLAY_XDISPLAY (gdkdisplay)(gdk_x11_display_get_xdisplay (gdkdisplay)),
1823 sn_error_trap_push,
1824 sn_error_trap_pop);
1825
1826 /* Only initiate notification if desktop file supports it.
1827 * (we could avoid setting up the SnLauncherContext if we aren't going
1828 * to initiate, but why bother)
1829 */
1830
1831 startup_class = mate_desktop_item_get_string (item,
1832 "StartupWMClass");
1833 if (startup_class ||
1834 mate_desktop_item_get_boolean (item, "StartupNotify")) {
1835 const char *name;
1836 const char *icon;
1837
1838 sn_context = sn_launcher_context_new (sn_display,
1839 screen ? gdk_x11_screen_get_screen_number (screen) :
1840 DefaultScreen (GDK_DISPLAY_XDISPLAY (gdkdisplay))(((_XPrivDisplay)((gdk_x11_display_get_xdisplay (gdkdisplay))
))->default_screen)
);
1841
1842 name = mate_desktop_item_get_localestring (item,
1843 MATE_DESKTOP_ITEM_NAME"Name");
1844
1845 if (name == NULL((void*)0))
1846 name = mate_desktop_item_get_localestring (item,
1847 MATE_DESKTOP_ITEM_GENERIC_NAME"GenericName");
1848
1849 if (name != NULL((void*)0)) {
1850 char *description;
1851
1852 sn_launcher_context_set_name (sn_context, name);
1853
1854 description = g_strdup_printf (_("Starting %s")((char *) g_dgettext ("mate-desktop", "Starting %s")), name);
1855
1856 sn_launcher_context_set_description (sn_context, description);
1857
1858 g_free (description);
1859 }
1860
1861 icon = mate_desktop_item_get_string (item,
1862 MATE_DESKTOP_ITEM_ICON"Icon");
1863
1864 if (icon != NULL((void*)0))
1865 sn_launcher_context_set_icon_name (sn_context, icon);
1866
1867 sn_launcher_context_set_workspace (sn_context, workspace);
1868
1869 if (startup_class != NULL((void*)0))
1870 sn_launcher_context_set_wmclass (sn_context,
1871 startup_class);
1872 } else {
1873 sn_context = NULL((void*)0);
1874 }
1875 }
1876 else {
1877 sn_context = NULL((void*)0);
1878 sn_display = NULL((void*)0);
1879 }
1880#endif
1881
1882 if (screen) {
1883 envp = make_environment_for_screen (screen, envp);
1884 if (free_me)
1885 g_strfreev (free_me);
1886 free_me = envp;
1887 }
1888
1889 exec_locale = g_filename_from_utf8 (exec, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
1890
1891 if (exec_locale == NULL((void*)0)) {
1892 exec_locale = g_strdup ("")g_strdup_inline ("");
1893 }
1894
1895 do {
1896 added_status = ADDED_NONE;
1897 new_exec = expand_string (item,
1898 exec_locale,
1899 args, &arg_ptr, &added_status);
1900
1901 if (launched == 0 && added_status == ADDED_NONE && append_uris) {
1902 uris = stringify_uris (args);
1903 temp = g_strconcat (new_exec, " ", uris, NULL((void*)0));
1904 g_free (uris);
1905 g_free (new_exec);
1906 new_exec = temp;
1907 added_status = ADDED_ALL;
1908 }
1909
1910 /* append_uris and append_paths are mutually exlusive */
1911 if (launched == 0 && added_status == ADDED_NONE && append_paths) {
1912 uris = stringify_files (args);
1913 temp = g_strconcat (new_exec, " ", uris, NULL((void*)0));
1914 g_free (uris);
1915 g_free (new_exec);
1916 new_exec = temp;
1917 added_status = ADDED_ALL;
1918 }
1919
1920 if (launched > 0 && added_status == ADDED_NONE) {
1921 g_free (new_exec);
1922 break;
1923 }
1924
1925 if ( ! g_shell_parse_argv (new_exec,
1926 &temp_argc, &temp_argv, error)) {
1927 /* The error now comes from g_shell_parse_argv */
1928 g_free (new_exec);
1929 ret = -1;
1930 break;
1931 }
1932 g_free (new_exec);
1933
1934 vector_list = NULL((void*)0);
1935 for(i = 0; i < term_argc; i++)
1936 vector_list = g_slist_append (vector_list,
1937 g_strdup (term_argv[i])g_strdup_inline (term_argv[i]));
1938
1939 for(i = 0; i < temp_argc; i++)
1940 vector_list = g_slist_append (vector_list,
1941 g_strdup (temp_argv[i])g_strdup_inline (temp_argv[i]));
1942
1943 g_strfreev (temp_argv);
1944
1945 real_argv = list_to_vector (vector_list);
1946 g_slist_free_full (vector_list, g_free);
1947
1948#ifdef HAVE_STARTUP_NOTIFICATION
1949 if (sn_context != NULL((void*)0) && (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
) &&
1950 !sn_launcher_context_get_initiated (sn_context)) {
1951 guint32 launch_time;
1952
1953 /* This means that we always use the first real_argv[0]
1954 * we select for the "binary name", but it's probably
1955 * OK to do that. Binary name isn't super-important
1956 * anyway, and we can't initiate twice, and we
1957 * must initiate prior to fork/exec.
1958 */
1959
1960 sn_launcher_context_set_binary_name (sn_context,
1961 real_argv[0]);
1962
1963 if (item->launch_time > 0)
1964 launch_time = item->launch_time;
1965 else
1966 launch_time = gdk_x11_display_get_user_time (gdkdisplay);
1967
1968 sn_launcher_context_initiate (sn_context,
1969 g_get_prgname () ? g_get_prgname () : "unknown",
1970 real_argv[0],
1971 launch_time);
1972
1973 /* Don't allow accidental reuse of same timestamp */
1974 ((MateDesktopItem *)item)->launch_time = 0;
1975
1976 envp = make_spawn_environment_for_sn_context (sn_context, envp);
1977 if (free_me)
1978 g_strfreev (free_me);
1979 free_me = envp;
1980 }
1981#endif
1982
1983 if ( ! g_spawn_async (working_dir,
1984 real_argv,
1985 envp,
1986 (do_not_reap_child ? G_SPAWN_DO_NOT_REAP_CHILD : 0) | G_SPAWN_SEARCH_PATH /* flags */,
1987 NULL((void*)0), /* child_setup_func */
1988 NULL((void*)0), /* child_setup_func_data */
1989 (do_not_reap_child ? &pid : NULL((void*)0)) /* child_pid */,
1990 error)) {
1991 /* The error was set for us,
1992 * we just can't launch this thingie */
1993 ret = -1;
1994 g_strfreev (real_argv);
1995 break;
1996 } else if (do_not_reap_child) {
1997 g_child_watch_add (pid, dummy_child_watch, NULL((void*)0));
1998 }
1999
2000 launched ++;
2001
2002 g_strfreev (real_argv);
2003
2004 if (arg_ptr != NULL((void*)0))
2005 arg_ptr = arg_ptr->next;
2006
2007 /* rinse, repeat until we run out of arguments (That
2008 * is if we were adding singles anyway) */
2009 } while (added_status == ADDED_SINGLE &&
2010 arg_ptr != NULL((void*)0) &&
2011 ! launch_only_one);
2012
2013 g_free (exec_locale);
2014#ifdef HAVE_STARTUP_NOTIFICATION
2015 if ((sn_context != NULL((void*)0)) && (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)){
2016 if (ret < 0)
2017 sn_launcher_context_complete (sn_context); /* end sequence */
2018 else
2019 add_startup_timeout (screen ? screen :
2020 gdk_display_get_default_screen (gdk_display_get_default ()),
2021 sn_context);
2022 sn_launcher_context_unref (sn_context);
2023 }
2024 if (GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2025 sn_display_unref (sn_display);
2026
2027#endif /* HAVE_STARTUP_NOTIFICATION */
2028
2029 free_args (args);
2030
2031 if (term_argv)
2032 g_strfreev (term_argv);
2033
2034 if (free_me)
2035 g_strfreev (free_me);
2036
2037 return ret;
2038}
2039
2040/* strip any trailing &, return FALSE if bad things happen and
2041 we end up with an empty string */
2042static gboolean
2043strip_the_amp (char *exec)
2044{
2045 size_t exec_len;
2046
2047 g_strstrip (exec)g_strchomp (g_strchug (exec));
2048 if (*exec == '\0')
2049 return FALSE(0);
2050
2051 exec_len = strlen (exec);
2052 /* kill any trailing '&' */
2053 if (exec[exec_len-1] == '&') {
2054 exec[exec_len-1] = '\0';
2055 g_strchomp (exec);
2056 }
2057
2058 /* can't exactly launch an empty thing */
2059 if (*exec == '\0')
2060 return FALSE(0);
2061
2062 return TRUE(!(0));
2063}
2064
2065static int
2066mate_desktop_item_launch_on_screen_with_env (
2067 const MateDesktopItem *item,
2068 GList *file_list,
2069 MateDesktopItemLaunchFlags flags,
2070 GdkScreen *screen,
2071 int workspace,
2072 char **envp,
2073 GError **error)
2074{
2075 const char *exec;
2076 char *the_exec;
2077 int ret;
2078
2079 exec = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_EXEC"Exec");
2080 /* This is a URL, so launch it as a url */
2081 if (item->type == MATE_DESKTOP_ITEM_TYPE_LINK) {
2082 const char *url;
2083 gboolean retval;
2084
2085 url = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_URL"URL");
2086 /* Mate panel used to put this in Exec */
2087 if (!(url && url[0] != '\0'))
2088 url = exec;
2089
2090 if (!(url && url[0] != '\0')) {
2091 g_set_error (error,
2092 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2093 MATE_DESKTOP_ITEM_ERROR_NO_URL,
2094 _("No URL to launch")((char *) g_dgettext ("mate-desktop", "No URL to launch")));
2095 return -1;
2096 }
2097
2098 retval = gtk_show_uri_on_window (NULL((void*)0),
2099 url,
2100 GDK_CURRENT_TIME0L,
2101 error);
2102 return retval ? 0 : -1;
2103 }
2104
2105 /* check the type, if there is one set */
2106 if (item->type != MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
2107 g_set_error (error,
2108 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2109 MATE_DESKTOP_ITEM_ERROR_NOT_LAUNCHABLE,
2110 _("Not a launchable item")((char *) g_dgettext ("mate-desktop", "Not a launchable item"
))
);
2111 return -1;
2112 }
2113
2114 if (exec == NULL((void*)0) ||
2115 exec[0] == '\0') {
2116 g_set_error (error,
2117 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2118 MATE_DESKTOP_ITEM_ERROR_NO_EXEC_STRING,
2119 _("No command (Exec) to launch")((char *) g_dgettext ("mate-desktop", "No command (Exec) to launch"
))
);
2120 return -1;
2121 }
2122
2123 /* make a new copy and get rid of spaces */
2124 the_exec = g_alloca (strlen (exec) + 1)__builtin_alloca (strlen (exec) + 1);
2125 g_strlcpy (the_exec, exec, strlen (exec) + 1);
2126
2127 if ( ! strip_the_amp (the_exec)) {
2128 g_set_error (error,
2129 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
2130 MATE_DESKTOP_ITEM_ERROR_BAD_EXEC_STRING,
2131 _("Bad command (Exec) to launch")((char *) g_dgettext ("mate-desktop", "Bad command (Exec) to launch"
))
);
2132 return -1;
2133 }
2134
2135 ret = ditem_execute (item, the_exec, file_list, screen, workspace, envp,
2136 (flags & MATE_DESKTOP_ITEM_LAUNCH_ONLY_ONE),
2137 (flags & MATE_DESKTOP_ITEM_LAUNCH_USE_CURRENT_DIR),
2138 (flags & MATE_DESKTOP_ITEM_LAUNCH_APPEND_URIS),
2139 (flags & MATE_DESKTOP_ITEM_LAUNCH_APPEND_PATHS),
2140 (flags & MATE_DESKTOP_ITEM_LAUNCH_DO_NOT_REAP_CHILD),
2141 error);
2142
2143 return ret;
2144}
2145
2146/**
2147 * mate_desktop_item_launch:
2148 * @item: A desktop item
2149 * @file_list: Files/URIs to launch this item with, can be %NULL
2150 * @flags: FIXME
2151 * @error: FIXME
2152 *
2153 * This function runs the program listed in the specified 'item',
2154 * optionally appending additional arguments to its command line. It uses
2155 * #g_shell_parse_argv to parse the the exec string into a vector which is
2156 * then passed to #g_spawn_async for execution. This can return all
2157 * the errors from MateURL, #g_shell_parse_argv and #g_spawn_async,
2158 * in addition to it's own. The files are
2159 * only added if the entry defines one of the standard % strings in it's
2160 * Exec field.
2161 *
2162 * Returns: The the pid of the process spawned. If more then one
2163 * process was spawned the last pid is returned. On error -1
2164 * is returned and @error is set.
2165 */
2166int
2167mate_desktop_item_launch (const MateDesktopItem *item,
2168 GList *file_list,
2169 MateDesktopItemLaunchFlags flags,
2170 GError **error)
2171{
2172 return mate_desktop_item_launch_on_screen_with_env (
2173 item, file_list, flags, NULL((void*)0), -1, NULL((void*)0), error);
2174}
2175
2176/**
2177 * mate_desktop_item_launch_with_env:
2178 * @item: A desktop item
2179 * @file_list: Files/URIs to launch this item with, can be %NULL
2180 * @flags: FIXME
2181 * @envp: child's environment, or %NULL to inherit parent's
2182 * @error: FIXME
2183 *
2184 * See mate_desktop_item_launch for a full description. This function
2185 * additionally passes an environment vector for the child process
2186 * which is to be launched.
2187 *
2188 * Returns: The the pid of the process spawned. If more then one
2189 * process was spawned the last pid is returned. On error -1
2190 * is returned and @error is set.
2191 */
2192int
2193mate_desktop_item_launch_with_env (const MateDesktopItem *item,
2194 GList *file_list,
2195 MateDesktopItemLaunchFlags flags,
2196 char **envp,
2197 GError **error)
2198{
2199 return mate_desktop_item_launch_on_screen_with_env (
2200 item, file_list, flags,
2201 NULL((void*)0), -1, envp, error);
2202}
2203
2204/**
2205 * mate_desktop_item_launch_on_screen:
2206 * @item: A desktop item
2207 * @file_list: Files/URIs to launch this item with, can be %NULL
2208 * @flags: FIXME
2209 * @screen: the %GdkScreen on which the application should be launched
2210 * @workspace: the workspace on which the app should be launched (-1 for current)
2211 * @error: FIXME
2212 *
2213 * See mate_desktop_item_launch for a full description. This function
2214 * additionally attempts to launch the application on a given screen
2215 * and workspace.
2216 *
2217 * Returns: The the pid of the process spawned. If more then one
2218 * process was spawned the last pid is returned. On error -1
2219 * is returned and @error is set.
2220 */
2221int
2222mate_desktop_item_launch_on_screen (const MateDesktopItem *item,
2223 GList *file_list,
2224 MateDesktopItemLaunchFlags flags,
2225 GdkScreen *screen,
2226 int workspace,
2227 GError **error)
2228{
2229 return mate_desktop_item_launch_on_screen_with_env (
2230 item, file_list, flags,
2231 screen, workspace, NULL((void*)0), error);
2232}
2233
2234/**
2235 * mate_desktop_item_drop_uri_list:
2236 * @item: A desktop item
2237 * @uri_list: text as gotten from a text/uri-list
2238 * @flags: FIXME
2239 * @error: FIXME
2240 *
2241 * A list of files or urls dropped onto an icon, the proper (Url or File)
2242 * exec is run you can pass directly string that you got as the
2243 * text/uri-list. This just parses the list and calls
2244 *
2245 * Returns: The value returned by #mate_execute_async() upon execution of
2246 * the specified item or -1 on error. If multiple instances are run, the
2247 * return of the last one is returned.
2248 */
2249int
2250mate_desktop_item_drop_uri_list (const MateDesktopItem *item,
2251 const char *uri_list,
2252 MateDesktopItemLaunchFlags flags,
2253 GError **error)
2254{
2255 return mate_desktop_item_drop_uri_list_with_env (item, uri_list,
2256 flags, NULL((void*)0), error);
2257}
2258
2259/**
2260* mate_desktop_item_drop_uri_list_with_env:
2261* @item: A desktop item
2262* @uri_list: text as gotten from a text/uri-list
2263* @flags: FIXME
2264* @envp: child's environment
2265* @error: FIXME
2266*
2267* See mate_desktop_item_drop_uri_list for a full description. This function
2268* additionally passes an environment vector for the child process
2269* which is to be launched.
2270*
2271* Returns: The value returned by #mate_execute_async() upon execution of
2272* the specified item or -1 on error. If multiple instances are run, the
2273* return of the last one is returned.
2274*/
2275int
2276mate_desktop_item_drop_uri_list_with_env (const MateDesktopItem *item,
2277 const char *uri_list,
2278 MateDesktopItemLaunchFlags flags,
2279 char **envp,
2280 GError **error)
2281{
2282 int ret;
2283 char *uri;
2284 char **uris;
2285 GList *list = NULL((void*)0);
2286
2287 uris = g_uri_list_extract_uris (uri_list);
2288
2289 for (uri = uris[0]; uri != NULL((void*)0); uri++) {
2290 list = g_list_prepend (list, uri);
2291 }
2292 list = g_list_reverse (list);
2293
2294 ret = mate_desktop_item_launch_with_env (
2295 item, list, flags, envp, error);
2296
2297 g_strfreev (uris);
2298 g_list_free (list);
2299
2300 return ret;
2301}
2302
2303static gboolean
2304exec_exists (const char *exec)
2305{
2306 if (g_path_is_absolute (exec)) {
2307 if (access (exec, X_OK1) == 0)
2308 return TRUE(!(0));
2309 else
2310 return FALSE(0);
2311 } else {
2312 char *tryme;
2313
2314 tryme = g_find_program_in_path (exec);
2315 if (tryme != NULL((void*)0)) {
2316 g_free (tryme);
2317 return TRUE(!(0));
2318 }
2319 return FALSE(0);
2320 }
2321}
2322
2323/**
2324 * mate_desktop_item_exists:
2325 * @item: A desktop item
2326 *
2327 * Attempt to figure out if the program that can be executed by this item
2328 * actually exists. First it tries the TryExec attribute to see if that
2329 * contains a program that is in the path. Then if there is no such
2330 * attribute, it tries the first word of the Exec attribute.
2331 *
2332 * Returns: A boolean, %TRUE if it exists, %FALSE otherwise.
2333 */
2334gboolean
2335mate_desktop_item_exists (const MateDesktopItem *item)
2336{
2337 const char *try_exec;
2338 const char *exec;
2339
2340 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2341
2342 try_exec = lookup (item, MATE_DESKTOP_ITEM_TRY_EXEC"TryExec");
2343
2344 if (try_exec != NULL((void*)0) &&
2345 ! exec_exists (try_exec)) {
2346 return FALSE(0);
2347 }
2348
2349 if (item->type == MATE_DESKTOP_ITEM_TYPE_APPLICATION) {
2350 int argc;
2351 char **argv;
2352 const char *exe;
2353
2354 exec = lookup (item, MATE_DESKTOP_ITEM_EXEC"Exec");
2355 if (exec == NULL((void*)0))
2356 return FALSE(0);
2357
2358 if ( ! g_shell_parse_argv (exec, &argc, &argv, NULL((void*)0)))
2359 return FALSE(0);
2360
2361 if (argc < 1) {
2362 g_strfreev (argv);
2363 return FALSE(0);
2364 }
2365
2366 exe = argv[0];
2367
2368 if ( ! exec_exists (exe)) {
2369 g_strfreev (argv);
2370 return FALSE(0);
2371 }
2372 g_strfreev (argv);
2373 }
2374
2375 return TRUE(!(0));
2376}
2377
2378/**
2379 * mate_desktop_item_get_entry_type:
2380 * @item: A desktop item
2381 *
2382 * Gets the type attribute (the 'Type' field) of the item. This should
2383 * usually be 'Application' for an application, but it can be 'Directory'
2384 * for a directory description. There are other types available as well.
2385 * The type usually indicates how the desktop item should be handeled and
2386 * how the 'Exec' field should be handeled.
2387 *
2388 * Returns: The type of the specified 'item'. The returned
2389 * memory remains owned by the MateDesktopItem and should not be freed.
2390 */
2391MateDesktopItemType
2392mate_desktop_item_get_entry_type (const MateDesktopItem *item)
2393{
2394 g_return_val_if_fail (item != NULL, 0)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (0); } } while (0)
;
2395 g_return_val_if_fail (item->refcount > 0, 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (0); } } while (0)
;
2396
2397 return item->type;
2398}
2399
2400void
2401mate_desktop_item_set_entry_type (MateDesktopItem *item,
2402 MateDesktopItemType type)
2403{
2404 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2405 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2406
2407 item->type = type;
2408
2409 switch (type) {
2410 case MATE_DESKTOP_ITEM_TYPE_NULL:
2411 set (item, MATE_DESKTOP_ITEM_TYPE"Type", NULL((void*)0));
2412 break;
2413 case MATE_DESKTOP_ITEM_TYPE_APPLICATION:
2414 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Application");
2415 break;
2416 case MATE_DESKTOP_ITEM_TYPE_LINK:
2417 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Link");
2418 break;
2419 case MATE_DESKTOP_ITEM_TYPE_FSDEVICE:
2420 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "FSDevice");
2421 break;
2422 case MATE_DESKTOP_ITEM_TYPE_MIME_TYPE:
2423 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "MimeType");
2424 break;
2425 case MATE_DESKTOP_ITEM_TYPE_DIRECTORY:
2426 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Directory");
2427 break;
2428 case MATE_DESKTOP_ITEM_TYPE_SERVICE:
2429 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Service");
2430 break;
2431 case MATE_DESKTOP_ITEM_TYPE_SERVICE_TYPE:
2432 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "ServiceType");
2433 break;
2434 default:
2435 break;
2436 }
2437}
2438
2439/**
2440 * mate_desktop_item_get_file_status:
2441 * @item: A desktop item
2442 *
2443 * This function checks the modification time of the on-disk file to
2444 * see if it is more recent than the in-memory data.
2445 *
2446 * Returns: An enum value that specifies whether the item has changed since being loaded.
2447 */
2448MateDesktopItemStatus
2449mate_desktop_item_get_file_status (const MateDesktopItem *item)
2450{
2451 MateDesktopItemStatus retval;
2452 GFile *file;
2453 GFileInfo *info;
2454
2455 g_return_val_if_fail (item != NULL, MATE_DESKTOP_ITEM_DISAPPEARED)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (MATE_DESKTOP_ITEM_DISAPPEARED); } } while (0)
;
2456 g_return_val_if_fail (item->refcount > 0, MATE_DESKTOP_ITEM_DISAPPEARED)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (MATE_DESKTOP_ITEM_DISAPPEARED); } } while (0)
;
2457
2458 if (item->location == NULL((void*)0))
2459 return MATE_DESKTOP_ITEM_DISAPPEARED;
2460
2461 file = g_file_new_for_uri (item->location);
2462 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2463 G_FILE_QUERY_INFO_NONE, NULL((void*)0), NULL((void*)0));
2464
2465 retval = MATE_DESKTOP_ITEM_UNCHANGED;
2466
2467 if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2468 retval = MATE_DESKTOP_ITEM_DISAPPEARED;
2469 else if (((guint64) item->mtime) < g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2470 retval = MATE_DESKTOP_ITEM_CHANGED;
2471
2472 g_object_unref (info);
2473 g_object_unref (file);
2474
2475 return retval;
2476}
2477
2478/**
2479 * mate_desktop_item_find_icon:
2480 * @icon_theme: a #GtkIconTheme
2481 * @icon: icon name, something you'd get out of the Icon key
2482 * @desired_size: FIXME
2483 * @flags: FIXME
2484 *
2485 * Description: This function goes and looks for the icon file. If the icon
2486 * is not an absolute filename, this will look for it in the standard places.
2487 * If it can't find the icon, it will return %NULL
2488 *
2489 * Returns: A newly allocated string
2490 */
2491char *
2492mate_desktop_item_find_icon (GtkIconTheme *icon_theme,
2493 const char *icon,
2494 int desired_size,
2495 int flags)
2496{
2497 GtkIconInfo *info;
2498 char *full = NULL((void*)0);
2499
2500 g_return_val_if_fail (icon_theme == NULL ||do { if ((icon_theme == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((icon_theme)); GType __t = ((gtk_icon_theme_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "icon_theme == NULL || GTK_IS_ICON_THEME (icon_theme)"
); return (((void*)0)); } } while (0)
2501 GTK_IS_ICON_THEME (icon_theme), NULL)do { if ((icon_theme == ((void*)0) || (((__extension__ ({ GTypeInstance
*__inst = (GTypeInstance*) ((icon_theme)); GType __t = ((gtk_icon_theme_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))) { } else { g_return_if_fail_warning ("MateDesktop"
, ((const char*) (__func__)), "icon_theme == NULL || GTK_IS_ICON_THEME (icon_theme)"
); return (((void*)0)); } } while (0)
;
2502
2503 if (icon == NULL((void*)0) || strcmp(icon,"") == 0) {
2504 return NULL((void*)0);
2505 } else if (g_path_is_absolute (icon)) {
2506 if (g_file_test (icon, G_FILE_TEST_EXISTS)) {
2507 return g_strdup (icon)g_strdup_inline (icon);
2508 } else {
2509 return NULL((void*)0);
2510 }
2511 } else {
2512 char *icon_no_extension;
2513 char *p;
2514
2515 if (icon_theme == NULL((void*)0))
2516 icon_theme = gtk_icon_theme_get_default ();
2517
2518 icon_no_extension = g_strdup (icon)g_strdup_inline (icon);
2519 p = strrchr (icon_no_extension, '.');
2520 if (p &&
2521 (strcmp (p, ".png") == 0 ||
2522 strcmp (p, ".xpm") == 0 ||
2523 strcmp (p, ".svg") == 0)) {
2524 *p = 0;
2525 }
2526
2527 info = gtk_icon_theme_lookup_icon (icon_theme,
2528 icon_no_extension,
2529 desired_size,
2530 0);
2531
2532 full = NULL((void*)0);
2533 if (info) {
2534 full = g_strdup (gtk_icon_info_get_filename (info))g_strdup_inline (gtk_icon_info_get_filename (info));
2535 g_object_unref (info);
2536 }
2537 g_free (icon_no_extension);
2538 }
2539
2540 return full;
2541
2542}
2543
2544/**
2545 * mate_desktop_item_get_icon:
2546 * @icon_theme: a #GtkIconTheme
2547 * @item: A desktop item
2548 *
2549 * Description: This function goes and looks for the icon file. If the icon
2550 * is not set as an absolute filename, this will look for it in the standard places.
2551 * If it can't find the icon, it will return %NULL
2552 *
2553 * Returns: A newly allocated string
2554 */
2555char *
2556mate_desktop_item_get_icon (const MateDesktopItem *item,
2557 GtkIconTheme *icon_theme)
2558{
2559 /* maybe this function should be deprecated in favour of find icon
2560 * -George */
2561 const char *icon;
2562
2563 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2564 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2565
2566 icon = mate_desktop_item_get_string (item, MATE_DESKTOP_ITEM_ICON"Icon");
2567
2568 return mate_desktop_item_find_icon (icon_theme, icon,
2569 48 /* desired_size */,
2570 0 /* flags */);
2571}
2572
2573/**
2574 * mate_desktop_item_get_location:
2575 * @item: A desktop item
2576 *
2577 * Returns: The file location associated with 'item'.
2578 *
2579 */
2580const char *
2581mate_desktop_item_get_location (const MateDesktopItem *item)
2582{
2583 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2584 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2585
2586 return item->location;
2587}
2588
2589/**
2590 * mate_desktop_item_set_location:
2591 * @item: A desktop item
2592 * @location: A uri string specifying the file location of this particular item.
2593 *
2594 * Set's the 'location' uri of this item.
2595 */
2596void
2597mate_desktop_item_set_location (MateDesktopItem *item, const char *location)
2598{
2599 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2600 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2601
2602 if (item->location != NULL((void*)0) &&
2603 location != NULL((void*)0) &&
2604 strcmp (item->location, location) == 0)
2605 return;
2606
2607 g_free (item->location);
2608 item->location = g_strdup (location)g_strdup_inline (location);
2609
2610 /* This is ugly, but useful internally */
2611 if (item->mtime != DONT_UPDATE_MTIME((gint64)-2)) {
2612 item->mtime = 0;
2613
2614 if (item->location) {
2615 GFile *file;
2616 GFileInfo *info;
2617
2618 file = g_file_new_for_uri (item->location);
2619
2620 info = g_file_query_info (file,
2621 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2622 G_FILE_QUERY_INFO_NONE,
2623 NULL((void*)0), NULL((void*)0));
2624 if (info) {
2625 if (g_file_info_has_attribute (info,
2626 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified"))
2627 item->mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
2628 g_object_unref (info);
2629 }
2630
2631 g_object_unref (file);
2632 }
2633 }
2634
2635 /* Make sure that save actually saves */
2636 item->modified = TRUE(!(0));
2637}
2638
2639/**
2640 * mate_desktop_item_set_location_file:
2641 * @item: A desktop item
2642 * @file: A local filename specifying the file location of this particular item.
2643 *
2644 * Set's the 'location' uri of this item to the given @file.
2645 */
2646void
2647mate_desktop_item_set_location_file (MateDesktopItem *item, const char *file)
2648{
2649 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2650 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2651
2652 if (file != NULL((void*)0)) {
2653 GFile *gfile;
2654
2655 gfile = g_file_new_for_path (file);
2656 mate_desktop_item_set_location_gfile (item, gfile);
2657 g_object_unref (gfile);
2658 } else {
2659 mate_desktop_item_set_location (item, NULL((void*)0));
2660 }
2661}
2662
2663static void
2664mate_desktop_item_set_location_gfile (MateDesktopItem *item, GFile *file)
2665{
2666 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2667 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2668
2669 if (file != NULL((void*)0)) {
2670 char *uri;
2671
2672 uri = g_file_get_uri (file);
2673 mate_desktop_item_set_location (item, uri);
2674 g_free (uri);
2675 } else {
2676 mate_desktop_item_set_location (item, NULL((void*)0));
2677 }
2678}
2679
2680/*
2681 * Reading/Writing different sections, NULL is the standard section
2682 */
2683
2684gboolean
2685mate_desktop_item_attr_exists (const MateDesktopItem *item,
2686 const char *attr)
2687{
2688 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2689 g_return_val_if_fail (item->refcount > 0, FALSE)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return ((0)); } } while (0)
;
2690 g_return_val_if_fail (attr != NULL, FALSE)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return ((0)); } } while (0)
;
2691
2692 return lookup (item, attr) != NULL((void*)0);
2693}
2694
2695/*
2696 * String type
2697 */
2698const char *
2699mate_desktop_item_get_string (const MateDesktopItem *item,
2700 const char *attr)
2701{
2702 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2703 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2704 g_return_val_if_fail (attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2705
2706 return lookup (item, attr);
2707}
2708
2709void
2710mate_desktop_item_set_string (MateDesktopItem *item,
2711 const char *attr,
2712 const char *value)
2713{
2714 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2715 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2716 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2717
2718 set (item, attr, value);
2719
2720 if (strcmp (attr, MATE_DESKTOP_ITEM_TYPE"Type") == 0)
2721 item->type = type_from_string (value);
2722}
2723
2724/*
2725 * LocaleString type
2726 */
2727const char* mate_desktop_item_get_localestring(const MateDesktopItem* item, const char* attr)
2728{
2729 g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2730 g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2731 g_return_val_if_fail(attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2732
2733 return lookup_best_locale(item, attr);
2734}
2735
2736const char* mate_desktop_item_get_localestring_lang(const MateDesktopItem* item, const char* attr, const char* language)
2737{
2738 g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2739 g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2740 g_return_val_if_fail(attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2741
2742 return lookup_locale(item, attr, language);
2743}
2744
2745/**
2746 * mate_desktop_item_get_string_locale:
2747 * @item: A desktop item
2748 * @attr: An attribute name
2749 *
2750 * Returns the current locale that is used for the given attribute.
2751 * This might not be the same for all attributes. For example, if your
2752 * locale is "en_US.ISO8859-1" but attribute FOO only has "en_US" then
2753 * that would be returned for attr = "FOO". If attribute BAR has
2754 * "en_US.ISO8859-1" then that would be returned for "BAR".
2755 *
2756 * Returns: a string equal to the current locale or NULL
2757 * if the attribute is invalid or there is no matching locale.
2758 */
2759const char *
2760mate_desktop_item_get_attr_locale (const MateDesktopItem *item,
2761 const char *attr)
2762{
2763 const char * const *langs_pointer;
2764 int i;
2765
2766 langs_pointer = g_get_language_names ();
2767 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
2768 const char *value = NULL((void*)0);
2769
2770 value = lookup_locale (item, attr, langs_pointer[i]);
2771 if (value)
2772 return langs_pointer[i];
2773 }
2774
2775 return NULL((void*)0);
2776}
2777
2778GList *
2779mate_desktop_item_get_languages (const MateDesktopItem *item,
2780 const char *attr)
2781{
2782 GList *li;
2783 GList *list = NULL((void*)0);
2784
2785 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2786 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2787
2788 for (li = item->languages; li != NULL((void*)0); li = li->next) {
2789 char *language = li->data;
2790 if (attr == NULL((void*)0) ||
2791 lookup_locale (item, attr, language) != NULL((void*)0)) {
2792 list = g_list_prepend (list, language);
2793 }
2794 }
2795
2796 return g_list_reverse (list);
2797}
2798
2799static const char *
2800get_language (void)
2801{
2802 const char * const *langs_pointer;
2803 int i;
2804
2805 langs_pointer = g_get_language_names ();
2806 for (i = 0; langs_pointer[i] != NULL((void*)0); i++) {
2807 /* find first without encoding */
2808 if (strchr (langs_pointer[i], '.') == NULL((void*)0)) {
2809 return langs_pointer[i];
2810 }
2811 }
2812 return NULL((void*)0);
2813}
2814
2815void
2816mate_desktop_item_set_localestring (MateDesktopItem *item,
2817 const char *attr,
2818 const char *value)
2819{
2820 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2821 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2822 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2823
2824 set_locale (item, attr, get_language (), value);
2825}
2826
2827void
2828mate_desktop_item_set_localestring_lang (MateDesktopItem *item,
2829 const char *attr,
2830 const char *language,
2831 const char *value)
2832{
2833 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2834 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2835 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2836
2837 set_locale (item, attr, language, value);
2838}
2839
2840void
2841mate_desktop_item_clear_localestring (MateDesktopItem *item,
2842 const char *attr)
2843{
2844 GList *l;
2845
2846 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2847 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2848 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2849
2850 for (l = item->languages; l != NULL((void*)0); l = l->next)
2851 set_locale (item, attr, l->data, NULL((void*)0));
2852
2853 set (item, attr, NULL((void*)0));
2854}
2855
2856/*
2857 * Strings, Regexps types
2858 */
2859
2860char **
2861mate_desktop_item_get_strings (const MateDesktopItem *item,
2862 const char *attr)
2863{
2864 const char *value;
2865
2866 g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return (((void*)0)); } } while (0)
;
2867 g_return_val_if_fail (item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return (((void*)0)); } } while (0)
;
2868 g_return_val_if_fail (attr != NULL, NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return (((void*)0)); } } while (0)
;
2869
2870 value = lookup (item, attr);
2871 if (value == NULL((void*)0))
2872 return NULL((void*)0);
2873
2874 /* FIXME: there's no way to escape semicolons apparently */
2875 return g_strsplit (value, ";", -1);
2876}
2877
2878void
2879mate_desktop_item_set_strings (MateDesktopItem *item,
2880 const char *attr,
2881 char **strings)
2882{
2883 char *str, *str2;
2884
2885 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2886 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2887 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2888
2889 str = g_strjoinv (";", strings);
2890 str2 = g_strconcat (str, ";", NULL((void*)0));
2891 /* FIXME: there's no way to escape semicolons apparently */
2892 set (item, attr, str2);
2893 g_free (str);
2894 g_free (str2);
2895}
2896
2897/*
2898 * Boolean type
2899 */
2900gboolean
2901mate_desktop_item_get_boolean (const MateDesktopItem *item,
2902 const char *attr)
2903{
2904 const char *value;
2905
2906 g_return_val_if_fail (item != NULL, FALSE)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return ((0)); } } while (0)
;
2907 g_return_val_if_fail (item->refcount > 0, FALSE)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return ((0)); } } while (0)
;
2908 g_return_val_if_fail (attr != NULL, FALSE)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return ((0)); } } while (0)
;
2909
2910 value = lookup (item, attr);
2911 if (value == NULL((void*)0))
2912 return FALSE(0);
2913
2914 return (value[0] == 'T' ||
2915 value[0] == 't' ||
2916 value[0] == 'Y' ||
2917 value[0] == 'y' ||
2918 atoi (value) != 0);
2919}
2920
2921void
2922mate_desktop_item_set_boolean (MateDesktopItem *item,
2923 const char *attr,
2924 gboolean value)
2925{
2926 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2927 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2928 g_return_if_fail (attr != NULL)do { if ((attr != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "attr != NULL");
return; } } while (0)
;
2929
2930 set (item, attr, value ? "true" : "false");
2931}
2932
2933void
2934mate_desktop_item_set_launch_time (MateDesktopItem *item,
2935 guint32 timestamp)
2936{
2937 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2938
2939 item->launch_time = timestamp;
2940}
2941
2942/*
2943 * Clearing attributes
2944 */
2945void
2946mate_desktop_item_clear_section (MateDesktopItem *item,
2947 const char *section)
2948{
2949 Section *sec;
2950 GList *li;
2951
2952 g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item != NULL");
return; } } while (0)
;
2953 g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "item->refcount > 0"
); return; } } while (0)
;
2954
2955 sec = find_section (item, section);
2956
2957 if (sec == NULL((void*)0)) {
2958 for (li = item->keys; li != NULL((void*)0); li = li->next) {
2959 g_hash_table_remove (item->main_hash, li->data);
2960 g_free (li->data);
2961 li->data = NULL((void*)0);
2962 }
2963 g_list_free (item->keys);
2964 item->keys = NULL((void*)0);
2965 } else {
2966 for (li = sec->keys; li != NULL((void*)0); li = li->next) {
2967 char *key = li->data;
2968 char *full = g_strdup_printf ("%s/%s",
2969 sec->name, key);
2970 g_hash_table_remove (item->main_hash, full);
2971 g_free (full);
2972 g_free (key);
2973 li->data = NULL((void*)0);
2974 }
2975 g_list_free (sec->keys);
2976 sec->keys = NULL((void*)0);
2977 }
2978 item->modified = TRUE(!(0));
2979}
2980
2981/************************************************************
2982 * Parser: *
2983 ************************************************************/
2984
2985static gboolean G_GNUC_CONST__attribute__ ((__const__))
2986standard_is_boolean (const char * key)
2987{
2988 static GHashTable *bools = NULL((void*)0);
2989
2990 if (bools == NULL((void*)0)) {
2991 bools = g_hash_table_new (g_str_hash, g_str_equal);
2992 g_hash_table_insert (bools,
2993 MATE_DESKTOP_ITEM_NO_DISPLAY"NoDisplay",
2994 MATE_DESKTOP_ITEM_NO_DISPLAY"NoDisplay");
2995 g_hash_table_insert (bools,
2996 MATE_DESKTOP_ITEM_HIDDEN"Hidden",
2997 MATE_DESKTOP_ITEM_HIDDEN"Hidden");
2998 g_hash_table_insert (bools,
2999 MATE_DESKTOP_ITEM_TERMINAL"Terminal",
3000 MATE_DESKTOP_ITEM_TERMINAL"Terminal");
3001 g_hash_table_insert (bools,
3002 MATE_DESKTOP_ITEM_READ_ONLY"ReadOnly",
3003 MATE_DESKTOP_ITEM_READ_ONLY"ReadOnly");
3004 }
3005
3006 return g_hash_table_lookup (bools, key) != NULL((void*)0);
3007}
3008
3009static gboolean G_GNUC_CONST__attribute__ ((__const__))
3010standard_is_strings (const char *key)
3011{
3012 static GHashTable *strings = NULL((void*)0);
3013
3014 if (strings == NULL((void*)0)) {
3015 strings = g_hash_table_new (g_str_hash, g_str_equal);
3016 g_hash_table_insert (strings,
3017 MATE_DESKTOP_ITEM_FILE_PATTERN"FilePattern",
3018 MATE_DESKTOP_ITEM_FILE_PATTERN"FilePattern");
3019 g_hash_table_insert (strings,
3020 MATE_DESKTOP_ITEM_ACTIONS"Actions",
3021 MATE_DESKTOP_ITEM_ACTIONS"Actions");
3022 g_hash_table_insert (strings,
3023 MATE_DESKTOP_ITEM_MIME_TYPE"MimeType",
3024 MATE_DESKTOP_ITEM_MIME_TYPE"MimeType");
3025 g_hash_table_insert (strings,
3026 MATE_DESKTOP_ITEM_PATTERNS"Patterns",
3027 MATE_DESKTOP_ITEM_PATTERNS"Patterns");
3028 g_hash_table_insert (strings,
3029 MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder",
3030 MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder");
3031 }
3032
3033 return g_hash_table_lookup (strings, key) != NULL((void*)0);
3034}
3035
3036/* If no need to cannonize, returns NULL */
3037static char *
3038cannonize (const char *key, const char *value)
3039{
3040 if (standard_is_boolean (key)) {
3041 if (value[0] == 'T' ||
3042 value[0] == 't' ||
3043 value[0] == 'Y' ||
3044 value[0] == 'y' ||
3045 atoi (value) != 0) {
3046 return g_strdup ("true")g_strdup_inline ("true");
3047 } else {
3048 return g_strdup ("false")g_strdup_inline ("false");
3049 }
3050 } else if (standard_is_strings (key)) {
3051 int len = strlen (value);
3052 if (len == 0 || value[len-1] != ';') {
3053 return g_strconcat (value, ";", NULL((void*)0));
3054 }
3055 }
3056 /* XXX: Perhaps we should canonize numeric values as well, but this
3057 * has caused some subtle problems before so it needs to be done
3058 * carefully if at all */
3059 return NULL((void*)0);
3060}
3061
3062static char *
3063decode_string_and_dup (const char *s)
3064{
3065 char *p = g_malloc (strlen (s) + 1);
3066 char *q = p;
3067
3068 do {
3069 if (*s == '\\'){
3070 switch (*(++s)){
3071 case 's':
3072 *p++ = ' ';
3073 break;
3074 case 't':
3075 *p++ = '\t';
3076 break;
3077 case 'n':
3078 *p++ = '\n';
3079 break;
3080 case '\\':
3081 *p++ = '\\';
3082 break;
3083 case 'r':
3084 *p++ = '\r';
3085 break;
3086 default:
3087 *p++ = '\\';
3088 *p++ = *s;
3089 break;
3090 }
3091 } else {
3092 *p++ = *s;
3093 }
3094 } while (*s++);
3095
3096 return q;
3097}
3098
3099static char *
3100escape_string_and_dup (const char *s)
3101{
3102 char *return_value, *p;
3103 const char *q;
3104 int len = 0;
3105
3106 if (s
11.1
's' is not equal to NULL
== NULL((void*)0))
12
Taking false branch
3107 return g_strdup("")g_strdup_inline ("");
3108
3109 q = s;
3110 while (*q){
13
Loop condition is true. Entering loop body
16
Loop condition is false. Execution continues on line 3116
3111 len++;
3112 if (strchr ("\n\r\t\\", *q) != NULL((void*)0))
14
Assuming the condition is false
15
Taking false branch
3113 len++;
3114 q++;
3115 }
3116 return_value = p = (char *) g_malloc (len + 1);
3117 do {
19
Loop condition is true. Execution continues on line 3118
3118 switch (*s){
17
Control jumps to 'case 92:' at line 3131
20
Control jumps to the 'default' case at line 3135
3119 case '\t':
3120 *p++ = '\\';
3121 *p++ = 't';
3122 break;
3123 case '\n':
3124 *p++ = '\\';
3125 *p++ = 'n';
3126 break;
3127 case '\r':
3128 *p++ = '\\';
3129 *p++ = 'r';
3130 break;
3131 case '\\':
3132 *p++ = '\\';
3133 *p++ = '\\';
3134 break;
18
Execution continues on line 3138
3135 default:
3136 *p++ = *s;
21
Out of bound memory access (access exceeds upper limit of memory block)
3137 }
3138 } while (*s++);
3139 return return_value;
3140}
3141
3142static gboolean
3143check_locale (const char *locale)
3144{
3145 GIConv cd = g_iconv_open ("UTF-8", locale);
3146 if ((GIConv)-1 == cd)
3147 return FALSE(0);
3148 g_iconv_close (cd);
3149 return TRUE(!(0));
3150}
3151
3152static void
3153insert_locales (GHashTable *encodings, char *enc, ...)
3154{
3155 va_list args;
3156 char *s;
3157
3158 va_start (args, enc)__builtin_va_start(args, enc);
3159 for (;;) {
3160 s = va_arg (args, char *)__builtin_va_arg(args, char *);
3161 if (s == NULL((void*)0))
3162 break;
3163 g_hash_table_insert (encodings, s, enc);
3164 }
3165 va_end (args)__builtin_va_end(args);
3166}
3167
3168/* make a standard conversion table from the desktop standard spec */
3169static GHashTable *
3170init_encodings (void)
3171{
3172 GHashTable *encodings = g_hash_table_new (g_str_hash, g_str_equal);
3173
3174 /* "C" is plain ascii */
3175 insert_locales (encodings, "ASCII", "C", NULL((void*)0));
3176
3177 insert_locales (encodings, "ARMSCII-8", "by", NULL((void*)0));
3178 insert_locales (encodings, "BIG5", "zh_TW", NULL((void*)0));
3179 insert_locales (encodings, "CP1251", "be", "bg", NULL((void*)0));
3180 if (check_locale ("EUC-CN")) {
3181 insert_locales (encodings, "EUC-CN", "zh_CN", NULL((void*)0));
3182 } else {
3183 insert_locales (encodings, "GB2312", "zh_CN", NULL((void*)0));
3184 }
3185 insert_locales (encodings, "EUC-JP", "ja", NULL((void*)0));
3186 insert_locales (encodings, "EUC-KR", "ko", NULL((void*)0));
3187 /*insert_locales (encodings, "GEORGIAN-ACADEMY", NULL);*/
3188 insert_locales (encodings, "GEORGIAN-PS", "ka", NULL((void*)0));
3189 insert_locales (encodings, "ISO-8859-1", "br", "ca", "da", "de", "en", "es", "eu", "fi", "fr", "gl", "it", "nl", "wa", "no", "pt", "pt", "sv", NULL((void*)0));
3190 insert_locales (encodings, "ISO-8859-2", "cs", "hr", "hu", "pl", "ro", "sk", "sl", "sq", "sr", NULL((void*)0));
3191 insert_locales (encodings, "ISO-8859-3", "eo", NULL((void*)0));
3192 insert_locales (encodings, "ISO-8859-5", "mk", "sp", NULL((void*)0));
3193 insert_locales (encodings, "ISO-8859-7", "el", NULL((void*)0));
3194 insert_locales (encodings, "ISO-8859-9", "tr", NULL((void*)0));
3195 insert_locales (encodings, "ISO-8859-13", "lt", "lv", "mi", NULL((void*)0));
3196 insert_locales (encodings, "ISO-8859-14", "ga", "cy", NULL((void*)0));
3197 insert_locales (encodings, "ISO-8859-15", "et", NULL((void*)0));
3198 insert_locales (encodings, "KOI8-R", "ru", NULL((void*)0));
3199 insert_locales (encodings, "KOI8-U", "uk", NULL((void*)0));
3200 if (check_locale ("TCVN-5712")) {
3201 insert_locales (encodings, "TCVN-5712", "vi", NULL((void*)0));
3202 } else {
3203 insert_locales (encodings, "TCVN", "vi", NULL((void*)0));
3204 }
3205 insert_locales (encodings, "TIS-620", "th", NULL((void*)0));
3206 /*insert_locales (encodings, "VISCII", NULL);*/
3207
3208 return encodings;
3209}
3210
3211static const char *
3212get_encoding_from_locale (const char *locale)
3213{
3214 char lang[3];
3215 const char *encoding;
3216 static GHashTable *encodings = NULL((void*)0);
3217
3218 if (locale == NULL((void*)0))
3219 return NULL((void*)0);
3220
3221 /* if locale includes encoding, use it */
3222 encoding = strchr (locale, '.');
3223 if (encoding != NULL((void*)0)) {
3224 return encoding+1;
3225 }
3226
3227 if (encodings == NULL((void*)0))
3228 encodings = init_encodings ();
3229
3230 /* first try the entire locale (at this point ll_CC) */
3231 encoding = g_hash_table_lookup (encodings, locale);
3232 if (encoding != NULL((void*)0))
3233 return encoding;
3234
3235 /* Try just the language */
3236 strncpy (lang, locale, 2);
3237 lang[2] = '\0';
3238 return g_hash_table_lookup (encodings, lang);
3239}
3240
3241static Encoding
3242get_encoding (ReadBuf *rb)
3243{
3244 gboolean old_kde = FALSE(0);
3245 char buf [BUFSIZ8192];
3246 gboolean all_valid_utf8 = TRUE(!(0));
3247
3248 while (readbuf_gets (buf, sizeof (buf), rb) != NULL((void*)0)) {
3249 if (strncmp (MATE_DESKTOP_ITEM_ENCODING"Encoding",
3250 buf,
3251 strlen (MATE_DESKTOP_ITEM_ENCODING"Encoding")) == 0) {
3252 char *p = &buf[strlen (MATE_DESKTOP_ITEM_ENCODING"Encoding")];
3253 if (*p == ' ')
3254 p++;
3255 if (*p != '=')
3256 continue;
3257 p++;
3258 if (*p == ' ')
3259 p++;
3260 if (strcmp (p, "UTF-8") == 0) {
3261 return ENCODING_UTF8;
3262 } else if (strcmp (p, "Legacy-Mixed") == 0) {
3263 return ENCODING_LEGACY_MIXED;
3264 } else {
3265 /* According to the spec we're not supposed
3266 * to read a file like this */
3267 return ENCODING_UNKNOWN;
3268 }
3269 } else if (strcmp ("[KDE Desktop Entry]", buf) == 0) {
3270 old_kde = TRUE(!(0));
3271 /* don't break yet, we still want to support
3272 * Encoding even here */
3273 }
3274 if (all_valid_utf8 && ! g_utf8_validate (buf, -1, NULL((void*)0)))
3275 all_valid_utf8 = FALSE(0);
3276 }
3277
3278 if (old_kde)
3279 return ENCODING_LEGACY_MIXED;
3280
3281 /* try to guess by location */
3282 if (rb->uri != NULL((void*)0) && strstr (rb->uri, "mate/apps/") != NULL((void*)0)) {
3283 /* old mate */
3284 return ENCODING_LEGACY_MIXED;
3285 }
3286
3287 /* A dilemma, new KDE files are in UTF-8 but have no Encoding
3288 * info, at this time we really can't tell. The best thing to
3289 * do right now is to just assume UTF-8 if the whole file
3290 * validates as utf8 I suppose */
3291
3292 if (all_valid_utf8)
3293 return ENCODING_UTF8;
3294 else
3295 return ENCODING_LEGACY_MIXED;
3296}
3297
3298static char *
3299decode_string (const char *value, Encoding encoding, const char *locale)
3300{
3301 char *retval = NULL((void*)0);
3302
3303 /* if legacy mixed, then convert */
3304 if (locale != NULL((void*)0) && encoding == ENCODING_LEGACY_MIXED) {
3305 const char *char_encoding = get_encoding_from_locale (locale);
3306 char *utf8_string;
3307 if (char_encoding == NULL((void*)0))
3308 return NULL((void*)0);
3309 if (strcmp (char_encoding, "ASCII") == 0) {
3310 return decode_string_and_dup (value);
3311 }
3312 utf8_string = g_convert (value, -1, "UTF-8", char_encoding,
3313 NULL((void*)0), NULL((void*)0), NULL((void*)0));
3314 if (utf8_string == NULL((void*)0))
3315 return NULL((void*)0);
3316 retval = decode_string_and_dup (utf8_string);
3317 g_free (utf8_string);
3318 return retval;
3319 /* if utf8, then validate */
3320 } else if (locale != NULL((void*)0) && encoding == ENCODING_UTF8) {
3321 if ( ! g_utf8_validate (value, -1, NULL((void*)0)))
3322 /* invalid utf8, ignore this key */
3323 return NULL((void*)0);
3324 return decode_string_and_dup (value);
3325 } else {
3326 /* Meaning this is not a localized string */
3327 return decode_string_and_dup (value);
3328 }
3329}
3330
3331static char *
3332snarf_locale_from_key (const char *key)
3333{
3334 const char *brace;
3335 char *locale, *p;
3336
3337 brace = strchr (key, '[');
3338 if (brace == NULL((void*)0))
3339 return NULL((void*)0);
3340
3341 locale = g_strdup (brace + 1)g_strdup_inline (brace + 1);
3342 if (*locale == '\0') {
3343 g_free (locale);
3344 return NULL((void*)0);
3345 }
3346 p = strchr (locale, ']');
3347 if (p == NULL((void*)0)) {
3348 g_free (locale);
3349 return NULL((void*)0);
3350 }
3351 *p = '\0';
3352 return locale;
3353}
3354
3355static void
3356insert_key (MateDesktopItem *item,
3357 Section *cur_section,
3358 Encoding encoding,
3359 const char *key,
3360 const char *value,
3361 gboolean old_kde,
3362 gboolean no_translations)
3363{
3364 char *k;
3365 char *val;
3366 /* we always store everything in UTF-8 */
3367 if (cur_section == NULL((void*)0) &&
3368 strcmp (key, MATE_DESKTOP_ITEM_ENCODING"Encoding") == 0) {
3369 k = g_strdup (key)g_strdup_inline (key);
3370 val = g_strdup ("UTF-8")g_strdup_inline ("UTF-8");
3371 } else {
3372 char *locale = snarf_locale_from_key (key);
3373 /* If we're ignoring translations */
3374 if (no_translations && locale != NULL((void*)0)) {
3375 g_free (locale);
3376 return;
3377 }
3378 val = decode_string (value, encoding, locale);
3379
3380 /* Ignore this key, it's whacked */
3381 if (val == NULL((void*)0)) {
3382 g_free (locale);
3383 return;
3384 }
3385
3386 g_strchomp (val);
3387
3388 /* For old KDE entries, we can also split by a comma
3389 * on sort order, so convert to semicolons */
3390 if (old_kde &&
3391 cur_section == NULL((void*)0) &&
3392 strcmp (key, MATE_DESKTOP_ITEM_SORT_ORDER"SortOrder") == 0 &&
3393 strchr (val, ';') == NULL((void*)0)) {
3394 int i;
3395 for (i = 0; val[i] != '\0'; i++) {
3396 if (val[i] == ',')
3397 val[i] = ';';
3398 }
3399 }
3400
3401 /* Check some types, not perfect, but catches a lot
3402 * of things */
3403 if (cur_section == NULL((void*)0)) {
3404 char *cannon = cannonize (key, val);
3405 if (cannon != NULL((void*)0)) {
3406 g_free (val);
3407 val = cannon;
3408 }
3409 }
3410
3411 k = g_strdup (key)g_strdup_inline (key);
3412
3413 /* Take care of the language part */
3414 if (locale != NULL((void*)0) &&
3415 strcmp (locale, "C") == 0) {
3416 char *p;
3417 /* Whack C locale */
3418 p = strchr (k, '[');
3419 *p = '\0';
3420 g_free (locale);
3421 } else if (locale != NULL((void*)0)) {
3422 char *p, *brace;
3423
3424 /* Whack the encoding part */
3425 p = strchr (locale, '.');
3426 if (p != NULL((void*)0))
3427 *p = '\0';
3428
3429 if (g_list_find_custom (item->languages, locale,
3430 (GCompareFunc)strcmp) == NULL((void*)0)) {
3431 item->languages = g_list_prepend
3432 (item->languages, locale);
3433 } else {
3434 g_free (locale);
3435 }
3436
3437 /* Whack encoding from encoding in the key */
3438 brace = strchr (k, '[');
3439 p = strchr (brace, '.');
3440 if (p != NULL((void*)0)) {
3441 *p = ']';
3442 *(p+1) = '\0';
3443 }
3444 }
3445 }
3446
3447 if (cur_section == NULL((void*)0)) {
3448 /* only add to list if we haven't seen it before */
3449 if (g_hash_table_lookup (item->main_hash, k) == NULL((void*)0)) {
3450 item->keys = g_list_prepend (item->keys,
3451 g_strdup (k)g_strdup_inline (k));
3452 }
3453 /* later duplicates override earlier ones */
3454 g_hash_table_replace (item->main_hash, k, val);
3455 } else {
3456 char *full = g_strdup_printf
3457 ("%s/%s",
3458 cur_section->name, k);
3459 /* only add to list if we haven't seen it before */
3460 if (g_hash_table_lookup (item->main_hash, full) == NULL((void*)0)) {
3461 cur_section->keys =
3462 g_list_prepend (cur_section->keys, k);
3463 }
3464 /* later duplicates override earlier ones */
3465 g_hash_table_replace (item->main_hash,
3466 full, val);
3467 }
3468}
3469
3470static void
3471setup_type (MateDesktopItem *item, const char *uri)
3472{
3473 const char *type = g_hash_table_lookup (item->main_hash,
3474 MATE_DESKTOP_ITEM_TYPE"Type");
3475 if (type == NULL((void*)0) && uri != NULL((void*)0)) {
3476 char *base = g_path_get_basename (uri);
3477 if (base != NULL((void*)0) &&
3478 strcmp (base, ".directory") == 0) {
3479 /* This gotta be a directory */
3480 g_hash_table_replace (item->main_hash,
3481 g_strdup (MATE_DESKTOP_ITEM_TYPE)g_strdup_inline ("Type"),
3482 g_strdup ("Directory")g_strdup_inline ("Directory"));
3483 item->keys = g_list_prepend
3484 (item->keys, g_strdup (MATE_DESKTOP_ITEM_TYPE)g_strdup_inline ("Type"));
3485 item->type = MATE_DESKTOP_ITEM_TYPE_DIRECTORY;
3486 } else {
3487 item->type = MATE_DESKTOP_ITEM_TYPE_NULL;
3488 }
3489 g_free (base);
3490 } else {
3491 item->type = type_from_string (type);
3492 }
3493}
3494
3495/* fallback to find something suitable for C locale */
3496static char *
3497try_english_key (MateDesktopItem *item, const char *key)
3498{
3499 char *str;
3500 char *locales[] = { "en_US", "en_GB", "en_AU", "en", NULL((void*)0) };
3501 int i;
3502
3503 str = NULL((void*)0);
3504 for (i = 0; locales[i] != NULL((void*)0) && str == NULL((void*)0); i++) {
3505 str = g_strdup (lookup_locale (item, key, locales[i]))g_strdup_inline (lookup_locale (item, key, locales[i]));
3506 }
3507 if (str != NULL((void*)0)) {
3508 /* We need a 7-bit ascii string, so whack all
3509 * above 127 chars */
3510 guchar *p;
3511 for (p = (guchar *)str; *p != '\0'; p++) {
3512 if (*p > 127)
3513 *p = '?';
3514 }
3515 }
3516 return str;
3517}
3518
3519static void
3520sanitize (MateDesktopItem *item, const char *uri)
3521{
3522 const char *type;
3523
3524 type = lookup (item, MATE_DESKTOP_ITEM_TYPE"Type");
3525
3526 /* understand old mate style url exec thingies */
3527 if (type != NULL((void*)0) && strcmp (type, "URL") == 0) {
3528 const char *exec = lookup (item, MATE_DESKTOP_ITEM_EXEC"Exec");
3529 set (item, MATE_DESKTOP_ITEM_TYPE"Type", "Link");
3530 if (exec != NULL((void*)0)) {
3531 /* Note, this must be in this order */
3532 set (item, MATE_DESKTOP_ITEM_URL"URL", exec);
3533 set (item, MATE_DESKTOP_ITEM_EXEC"Exec", NULL((void*)0));
3534 }
3535 }
3536
3537 /* we make sure we have Name, Encoding and Version */
3538 if (lookup (item, MATE_DESKTOP_ITEM_NAME"Name") == NULL((void*)0)) {
3539 char *name = try_english_key (item, MATE_DESKTOP_ITEM_NAME"Name");
3540 /* If no name, use the basename */
3541 if (name == NULL((void*)0) && uri != NULL((void*)0))
3542 name = g_path_get_basename (uri);
3543 /* If no uri either, use same default as mate_desktop_item_new */
3544 if (name == NULL((void*)0)) {
3545 /* Translators: the "name" mentioned here is the name of
3546 * an application or a document */
3547 name = g_strdup (_("No name"))g_strdup_inline (((char *) g_dgettext ("mate-desktop", "No name"
)))
;
3548 }
3549 g_hash_table_replace (item->main_hash,
3550 g_strdup (MATE_DESKTOP_ITEM_NAME)g_strdup_inline ("Name"),
3551 name);
3552 item->keys = g_list_prepend
3553 (item->keys, g_strdup (MATE_DESKTOP_ITEM_NAME)g_strdup_inline ("Name"));
3554 }
3555 if (lookup (item, MATE_DESKTOP_ITEM_ENCODING"Encoding") == NULL((void*)0)) {
3556 /* We store everything in UTF-8 so write that down */
3557 g_hash_table_replace (item->main_hash,
3558 g_strdup (MATE_DESKTOP_ITEM_ENCODING)g_strdup_inline ("Encoding"),
3559 g_strdup ("UTF-8")g_strdup_inline ("UTF-8"));
3560 item->keys = g_list_prepend
3561 (item->keys, g_strdup (MATE_DESKTOP_ITEM_ENCODING)g_strdup_inline ("Encoding"));
3562 }
3563 if (lookup (item, MATE_DESKTOP_ITEM_VERSION"Version") == NULL((void*)0)) {
3564 /* this is the version that we follow, so write it down */
3565 g_hash_table_replace (item->main_hash,
3566 g_strdup (MATE_DESKTOP_ITEM_VERSION)g_strdup_inline ("Version"),
3567 g_strdup ("1.0")g_strdup_inline ("1.0"));
3568 item->keys = g_list_prepend
3569 (item->keys, g_strdup (MATE_DESKTOP_ITEM_VERSION)g_strdup_inline ("Version"));
3570 }
3571}
3572
3573enum {
3574 FirstBrace,
3575 OnSecHeader,
3576 IgnoreToEOL,
3577 IgnoreToEOLFirst,
3578 KeyDef,
3579 KeyDefOnKey,
3580 KeyValue
3581};
3582
3583static MateDesktopItem *
3584ditem_load (ReadBuf *rb,
3585 gboolean no_translations,
3586 GError **error)
3587{
3588 int state;
3589 char CharBuffer [1024];
3590 char *next = CharBuffer;
3591 int c;
3592 Encoding encoding;
3593 MateDesktopItem *item;
3594 Section *cur_section = NULL((void*)0);
3595 char *key = NULL((void*)0);
3596 gboolean old_kde = FALSE(0);
3597
3598 encoding = get_encoding (rb);
3599 if (encoding == ENCODING_UNKNOWN) {
3600 /* spec says, don't read this file */
3601 g_set_error (error,
3602 MATE_DESKTOP_ITEM_ERRORmate_desktop_item_error_quark (),
3603 MATE_DESKTOP_ITEM_ERROR_UNKNOWN_ENCODING,
3604 _("Unknown encoding of: %s")((char *) g_dgettext ("mate-desktop", "Unknown encoding of: %s"
))
,
3605 rb->uri);
3606 readbuf_close (rb);
3607 return NULL((void*)0);
3608 }
3609
3610 /* Rewind since get_encoding goes through the file */
3611 if (! readbuf_rewind (rb, error)) {
3612 readbuf_close (rb);
3613 /* spec says, don't read this file */
3614 return NULL((void*)0);
3615 }
3616
3617 item = mate_desktop_item_new ();
3618 item->modified = FALSE(0);
3619
3620 /* Note: location and mtime are filled in by the new_from_file
3621 * function since it has those values */
3622
3623#define OVERFLOW (next == &CharBuffer [sizeof(CharBuffer)-1])
3624
3625 state = FirstBrace;
3626 while ((c = readbuf_getc (rb)) != EOF(-1)) {
3627 if (c == '\r') /* Ignore Carriage Return */
3628 continue;
3629
3630 switch (state) {
3631
3632 case OnSecHeader:
3633 if (c == ']' || OVERFLOW) {
3634 *next = '\0';
3635 next = CharBuffer;
3636
3637 /* keys were inserted in reverse */
3638 if (cur_section != NULL((void*)0) &&
3639 cur_section->keys != NULL((void*)0)) {
3640 cur_section->keys = g_list_reverse
3641 (cur_section->keys);
3642 }
3643 if (strcmp (CharBuffer,
3644 "KDE Desktop Entry") == 0) {
3645 /* Main section */
3646 cur_section = NULL((void*)0);
3647 old_kde = TRUE(!(0));
3648 } else if (strcmp (CharBuffer,
3649 "Desktop Entry") == 0) {
3650 /* Main section */
3651 cur_section = NULL((void*)0);
3652 } else {
3653 cur_section = g_new0 (Section, 1)((Section *) g_malloc0_n ((1), sizeof (Section)));
3654 cur_section->name =
3655 g_strdup (CharBuffer)g_strdup_inline (CharBuffer);
3656 cur_section->keys = NULL((void*)0);
3657 item->sections = g_list_prepend
3658 (item->sections, cur_section);
3659 }
3660 state = IgnoreToEOL;
3661 } else if (c == '[') {
3662 /* FIXME: probably error out instead of ignoring this */
3663 } else {
3664 *next++ = c;
3665 }
3666 break;
3667
3668 case IgnoreToEOL:
3669 case IgnoreToEOLFirst:
3670 if (c == '\n'){
3671 if (state == IgnoreToEOLFirst)
3672 state = FirstBrace;
3673 else
3674 state = KeyDef;
3675 next = CharBuffer;
3676 }
3677 break;
3678
3679 case FirstBrace:
3680 case KeyDef:
3681 case KeyDefOnKey:
3682 if (c == '#') {
3683 if (state == FirstBrace)
3684 state = IgnoreToEOLFirst;
3685 else
3686 state = IgnoreToEOL;
3687 break;
3688 }
3689
3690 if (c == '[' && state != KeyDefOnKey){
3691 state = OnSecHeader;
3692 next = CharBuffer;
3693 g_free (key);
3694 key = NULL((void*)0);
3695 break;
3696 }
3697 /* On first pass, don't allow dangling keys */
3698 if (state == FirstBrace)
3699 break;
3700
3701 if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
3702 break;
3703
3704 if (c == '\n' || OVERFLOW) { /* Abort Definition */
3705 next = CharBuffer;
3706 state = KeyDef;
3707 break;
3708 }
3709
3710 if (c == '=' || OVERFLOW){
3711 *next = '\0';
3712
3713 g_free (key);
3714 key = g_strdup (CharBuffer)g_strdup_inline (CharBuffer);
3715 state = KeyValue;
3716 next = CharBuffer;
3717 } else {
3718 *next++ = c;
3719 state = KeyDefOnKey;
3720 }
3721 break;
3722
3723 case KeyValue:
3724 if (OVERFLOW || c == '\n'){
3725 *next = '\0';
3726
3727 insert_key (item, cur_section, encoding,
3728 key, CharBuffer, old_kde,
3729 no_translations);
3730
3731 g_free (key);
3732 key = NULL((void*)0);
3733
3734 state = (c == '\n') ? KeyDef : IgnoreToEOL;
3735 next = CharBuffer;
3736 } else {
3737 *next++ = c;
3738 }
3739 break;
3740
3741 } /* switch */
3742
3743 } /* while ((c = getc_unlocked (f)) != EOF) */
3744 if (c == EOF(-1) && state == KeyValue) {
3745 *next = '\0';
3746
3747 insert_key (item, cur_section, encoding,
3748 key, CharBuffer, old_kde,
3749 no_translations);
3750
3751 g_free (key);
3752 key = NULL((void*)0);
3753 }
3754
3755#undef OVERFLOW
3756
3757 /* keys were inserted in reverse */
3758 if (cur_section != NULL((void*)0) &&
3759 cur_section->keys != NULL((void*)0)) {
3760 cur_section->keys = g_list_reverse (cur_section->keys);
3761 }
3762 /* keys were inserted in reverse */
3763 item->keys = g_list_reverse (item->keys);
3764 /* sections were inserted in reverse */
3765 item->sections = g_list_reverse (item->sections);
3766
3767 /* sanitize some things */
3768 sanitize (item, rb->uri);
3769
3770 /* make sure that we set up the type */
3771 setup_type (item, rb->uri);
3772
3773 readbuf_close (rb);
3774
3775 return item;
3776}
3777
3778static void stream_printf (GFileOutputStream *stream,
3779 const char *format, ...) G_GNUC_PRINTF (2, 3)__attribute__((__format__ (__printf__, 2, 3)));
3780
3781static void
3782stream_printf (GFileOutputStream *stream, const char *format, ...)
3783{
3784 va_list args;
3785 gchar *s;
3786
3787 va_start (args, format)__builtin_va_start(args, format);
3788 s = g_strdup_vprintf (format, args);
3789 va_end (args)__builtin_va_end(args);
3790
3791 /* FIXME: what about errors */
3792 g_output_stream_write (G_OUTPUT_STREAM (stream)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((stream)), ((g_output_stream_get_type ()))))))
, s, strlen (s),
3793 NULL((void*)0), NULL((void*)0));
3794 g_free (s);
3795}
3796
3797static void
3798dump_section (MateDesktopItem *item, GFileOutputStream *stream, Section *section)
3799{
3800 GList *li;
3801
3802 stream_printf (stream, "[%s]\n", section->name);
3803 for (li = section->keys; li != NULL((void*)0); li = li->next) {
3804 const char *key = li->data;
3805 char *full = g_strdup_printf ("%s/%s", section->name, key);
3806 const char *value = g_hash_table_lookup (item->main_hash, full);
3807 if (value != NULL((void*)0)) {
3808 char *val = escape_string_and_dup (value);
3809 stream_printf (stream, "%s=%s\n", key, val);
3810 g_free (val);
3811 }
3812 g_free (full);
3813 }
3814}
3815
3816static gboolean
3817ditem_save (MateDesktopItem *item, const char *uri, GError **error)
3818{
3819 GList *li;
3820 GFile *file;
3821 GFileOutputStream *stream;
3822
3823 file = g_file_new_for_uri (uri);
3824 stream = g_file_replace (file, NULL((void*)0), FALSE(0), G_FILE_CREATE_NONE,
3825 NULL((void*)0), error);
3826 if (stream == NULL((void*)0))
5
Assuming 'stream' is not equal to NULL
6
Taking false branch
3827 return FALSE(0);
3828
3829 stream_printf (stream, "[Desktop Entry]\n");
3830 for (li = item->keys; li != NULL((void*)0); li = li->next) {
7
Assuming 'li' is not equal to NULL
8
Loop condition is true. Entering loop body
3831 const char *key = li->data;
3832 const char *value = g_hash_table_lookup (item->main_hash, key);
3833 if (value != NULL((void*)0)) {
9
Assuming 'value' is not equal to NULL
10
Taking true branch
3834 char *val = escape_string_and_dup (value);
11
Calling 'escape_string_and_dup'
3835 stream_printf (stream, "%s=%s\n", key, val);
3836 g_free (val);
3837 }
3838 }
3839
3840 if (item->sections != NULL((void*)0))
3841 stream_printf (stream, "\n");
3842
3843 for (li = item->sections; li != NULL((void*)0); li = li->next) {
3844 Section *section = li->data;
3845
3846 /* Don't write empty sections */
3847 if (section->keys == NULL((void*)0))
3848 continue;
3849
3850 dump_section (item, stream, section);
3851
3852 if (li->next != NULL((void*)0))
3853 stream_printf (stream, "\n");
3854 }
3855
3856 g_object_unref (stream);
3857 g_object_unref (file);
3858
3859 return TRUE(!(0));
3860}
3861
3862static gpointer
3863_mate_desktop_item_copy (gpointer boxed)
3864{
3865 return mate_desktop_item_copy (boxed);
3866}
3867
3868static void
3869_mate_desktop_item_free (gpointer boxed)
3870{
3871 mate_desktop_item_unref (boxed);
3872}
3873
3874GType
3875mate_desktop_item_get_type (void)
3876{
3877 static GType type = 0;
3878
3879 if (type == 0) {
3880 type = g_boxed_type_register_static ("MateDesktopItem",
3881 _mate_desktop_item_copy,
3882 _mate_desktop_item_free);
3883 }
3884
3885 return type;
3886}
3887
3888GQuark
3889mate_desktop_item_error_quark (void)
3890{
3891 static GQuark q = 0;
3892 if (q == 0)
3893 q = g_quark_from_static_string ("mate-desktop-item-error-quark");
3894
3895 return q;
3896}
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-f1d0a2.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-f1d0a2.html new file mode 100644 index 0000000..e6f52fa --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-f1d0a2.html @@ -0,0 +1,4154 @@ + + + +mate-bg.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-bg.c
Warning:line 2276, column 15
3rd function call argument is an uninitialized value
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-bg.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-bg.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
2
3matebg.c: Object for the desktop background.
4
5Copyright (C) 2000 Eazel, Inc.
6Copyright (C) 2007-2008 Red Hat, Inc.
7Copyright (C) 2012 Jasmine Hassan <jasmine.aura@gmail.com>
8Copyright (C) 2012-2021 MATE Developers
9
10This program is free software; you can redistribute it and/or
11modify it under the terms of the GNU Library General Public License as
12published by the Free Software Foundation; either version 2 of the
13License, or (at your option) any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18Library General Public License for more details.
19
20You should have received a copy of the GNU Library General Public
21License along with this program; if not, write to the
22Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23Boston, MA 02110-1301, USA.
24
25Derived from eel-background.c and eel-gdk-pixbuf-extensions.c by
26Darin Adler <darin@eazel.com> and Ramiro Estrugo <ramiro@eazel.com>
27
28Authors: Soren Sandmann <sandmann@redhat.com>
29 Jasmine Hassan <jasmine.aura@gmail.com>
30
31*/
32
33#include <string.h>
34#include <math.h>
35#include <stdarg.h>
36#include <stdlib.h>
37
38#include <glib/gstdio.h>
39#include <gio/gio.h>
40
41#include <gdk/gdkx.h>
42#include <X11/Xlib.h>
43#include <X11/Xatom.h>
44
45#include <cairo.h>
46
47#define MATE_DESKTOP_USE_UNSTABLE_API
48#include <mate-bg.h>
49#include <mate-bg-crossfade.h>
50
51# include <cairo-xlib.h>
52
53#define MATE_BG_CACHE_DIR"mate/background" "mate/background"
54
55/* We keep the large pixbufs around if the next update
56 in the slideshow is less than 60 seconds away */
57#define KEEP_EXPENSIVE_CACHE_SECS60 60
58
59typedef struct _SlideShow SlideShow;
60typedef struct _Slide Slide;
61
62struct _Slide {
63 double duration; /* in seconds */
64 gboolean fixed;
65
66 GSList* file1;
67 GSList* file2; /* NULL if fixed is TRUE */
68};
69
70typedef struct _FileSize FileSize;
71struct _FileSize {
72 gint width;
73 gint height;
74
75 char* file;
76};
77
78#define THUMBNAIL_SIZE256 256
79
80typedef struct FileCacheEntry FileCacheEntry;
81#define CACHE_SIZE4 4
82
83/*
84 * Implementation of the MateBG class
85 */
86struct _MateBG {
87 GObject parent_instance;
88 char *filename;
89 MateBGPlacement placement;
90 MateBGColorType color_type;
91 GdkRGBA primary;
92 GdkRGBA secondary;
93 gboolean is_enabled;
94
95 GFileMonitor* file_monitor;
96
97 guint changed_id;
98 guint transitioned_id;
99 guint blow_caches_id;
100
101 /* Cached information, only access through cache accessor functions */
102 SlideShow* slideshow;
103 gint64 file_mtime;
104 GdkPixbuf* pixbuf_cache;
105 int timeout_id;
106
107 GList* file_cache;
108};
109
110struct _MateBGClass {
111 GObjectClass parent_class;
112};
113
114enum {
115 CHANGED,
116 TRANSITIONED,
117 N_SIGNALS
118};
119
120static guint signals[N_SIGNALS] = {0};
121
122G_DEFINE_TYPE(MateBG, mate_bg, G_TYPE_OBJECT)static void mate_bg_init (MateBG *self); static void mate_bg_class_init
(MateBGClass *klass); static GType mate_bg_get_type_once (void
); static gpointer mate_bg_parent_class = ((void*)0); static gint
MateBG_private_offset; static void mate_bg_class_intern_init
(gpointer klass) { mate_bg_parent_class = g_type_class_peek_parent
(klass); if (MateBG_private_offset != 0) g_type_class_adjust_private_offset
(klass, &MateBG_private_offset); mate_bg_class_init ((MateBGClass
*) klass); } __attribute__ ((__unused__)) static inline gpointer
mate_bg_get_instance_private (MateBG *self) { return (((gpointer
) ((guint8*) (self) + (glong) (MateBG_private_offset)))); } GType
mate_bg_get_type (void) { static gsize static_g_define_type_id
= 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&static_g_define_type_id) : ((void*)0
)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = mate_bg_get_type_once ();
(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType mate_bg_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("MateBG"
), sizeof (MateBGClass), (GClassInitFunc)(void (*)(void)) mate_bg_class_intern_init
, sizeof (MateBG), (GInstanceInitFunc)(void (*)(void)) mate_bg_init
, (GTypeFlags) 0); { {{};} } return g_define_type_id; }
123
124static cairo_surface_t *make_root_pixmap (GdkWindow *window,
125 gint width,
126 gint height);
127
128/* Pixbuf utils */
129static void pixbuf_average_value (GdkPixbuf *pixbuf,
130 GdkRGBA *result);
131static GdkPixbuf *pixbuf_scale_to_fit (GdkPixbuf *src,
132 int max_width,
133 int max_height);
134static GdkPixbuf *pixbuf_scale_to_min (GdkPixbuf *src,
135 int min_width,
136 int min_height);
137
138static void pixbuf_draw_gradient (GdkPixbuf *pixbuf,
139 gboolean horizontal,
140 GdkRGBA *c1,
141 GdkRGBA *c2,
142 GdkRectangle *rect);
143
144static void pixbuf_tile (GdkPixbuf *src,
145 GdkPixbuf *dest);
146static void pixbuf_blend (GdkPixbuf *src,
147 GdkPixbuf *dest,
148 int src_x,
149 int src_y,
150 int width,
151 int height,
152 int dest_x,
153 int dest_y,
154 double alpha);
155
156/* Thumbnail utilities */
157static GdkPixbuf *create_thumbnail_for_filename (MateDesktopThumbnailFactory *factory,
158 const char *filename);
159static gboolean get_thumb_annotations (GdkPixbuf *thumb,
160 int *orig_width,
161 int *orig_height);
162
163/* Cache */
164static GdkPixbuf *get_pixbuf_for_size (MateBG *bg,
165 gint num_monitor,
166 int width,
167 int height);
168static void clear_cache (MateBG *bg);
169static gboolean is_different (MateBG *bg,
170 const char *filename);
171static gint64 get_mtime (const char *filename);
172static GdkPixbuf *create_img_thumbnail (MateBG *bg,
173 MateDesktopThumbnailFactory *factory,
174 GdkScreen *screen,
175 int dest_width,
176 int dest_height,
177 int frame_num);
178static SlideShow * get_as_slideshow (MateBG *bg,
179 const char *filename);
180static Slide * get_current_slide (SlideShow *show,
181 double *alpha);
182static gboolean slideshow_has_multiple_sizes (SlideShow *show);
183
184static SlideShow *read_slideshow_file (const char *filename,
185 GError **err);
186static SlideShow *slideshow_ref (SlideShow *show);
187static void slideshow_unref (SlideShow *show);
188
189static FileSize *find_best_size (GSList *sizes,
190 gint width,
191 gint height);
192
193static void
194color_from_string (const char *string,
195 GdkRGBA *colorp)
196{
197 if (!string || *string == '\0' || !gdk_rgba_parse (colorp, string))
198 gdk_rgba_parse (colorp, "#000000"); /* If all else fails use black */
199}
200
201static char *
202color_to_string (const GdkRGBA *color)
203{
204 return g_strdup_printf ("#%02x%02x%02x",
205 ((guint) (color->red * 65535)) >> 8,
206 ((guint) (color->green * 65535)) >> 8,
207 ((guint) (color->blue * 65535)) >> 8);
208}
209
210static gboolean
211do_changed (MateBG *bg)
212{
213 bg->changed_id = 0;
214
215 g_signal_emit (G_OBJECT (bg)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg)), (((GType) ((20) << (2))))))))
, signals[CHANGED], 0);
216
217 return FALSE(0);
218}
219
220static void
221queue_changed (MateBG *bg)
222{
223 if (bg->changed_id > 0) {
224 g_source_remove (bg->changed_id);
225 }
226
227 bg->changed_id = g_timeout_add_full (G_PRIORITY_LOW300,
228 100,
229 (GSourceFunc)do_changed,
230 bg,
231 NULL((void*)0));
232}
233
234static gboolean
235do_transitioned (MateBG *bg)
236{
237 bg->transitioned_id = 0;
238
239 if (bg->pixbuf_cache) {
240 g_object_unref (bg->pixbuf_cache);
241 bg->pixbuf_cache = NULL((void*)0);
242 }
243
244 g_signal_emit (G_OBJECT (bg)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((bg)), (((GType) ((20) << (2))))))))
, signals[TRANSITIONED], 0);
245
246 return FALSE(0);
247}
248
249static void
250queue_transitioned (MateBG *bg)
251{
252 if (bg->transitioned_id > 0) {
253 g_source_remove (bg->transitioned_id);
254 }
255
256 bg->transitioned_id = g_timeout_add_full (G_PRIORITY_LOW300,
257 100,
258 (GSourceFunc)do_transitioned,
259 bg,
260 NULL((void*)0));
261}
262
263/* This function loads the user's preferences */
264void
265mate_bg_load_from_preferences (MateBG *bg)
266{
267 GSettings *settings;
268 settings = g_settings_new (MATE_BG_SCHEMA"org.mate.background");
269
270 mate_bg_load_from_gsettings (bg, settings);
271 g_object_unref (settings);
272
273 /* Queue change to force background redraw */
274 queue_changed (bg);
275}
276
277/* This function loads default system settings */
278void
279mate_bg_load_from_system_preferences (MateBG *bg)
280{
281 GSettings *settings;
282
283 /* FIXME: we need to bind system settings instead of user but
284 * that's currently impossible, not implemented yet.
285 * Hence, reset to system default values.
286 */
287 settings = g_settings_new (MATE_BG_SCHEMA"org.mate.background");
288
289 mate_bg_load_from_system_gsettings (bg, settings, FALSE(0));
290
291 g_object_unref (settings);
292}
293
294/* This function loads (and optionally resets to) default system settings */
295void
296mate_bg_load_from_system_gsettings (MateBG *bg,
297 GSettings *settings,
298 gboolean reset_apply)
299{
300 GSettingsSchema *schema;
301 gchar **keys;
302 gchar **k;
303
304 g_return_if_fail (MATE_IS_BG (bg))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((bg)); GType __t = ((mate_bg_get_type ())); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_BG (bg)"); return; } } while (0)
;
305 g_return_if_fail (G_IS_SETTINGS (settings))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((settings)); GType __t = ((g_settings_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "G_IS_SETTINGS (settings)"); return; } } while
(0)
;
306
307 g_settings_delay (settings);
308
309 g_object_get (settings, "settings-schema", &schema, NULL((void*)0));
310 keys = g_settings_schema_list_keys (schema);
311 g_settings_schema_unref (schema);
312
313 for (k = keys; *k; k++) {
314 g_settings_reset (settings, *k);
315 }
316 g_strfreev (keys);
317
318 if (reset_apply) {
319 /* Apply changes atomically. */
320 g_settings_apply (settings);
321 } else {
322 mate_bg_load_from_gsettings (bg, settings);
323 g_settings_revert (settings);
324 }
325}
326
327void
328mate_bg_load_from_gsettings (MateBG *bg,
329 GSettings *settings)
330{
331 char *tmp;
332 char *filename;
333 MateBGColorType ctype;
334 GdkRGBA c1, c2;
335 MateBGPlacement placement;
336
337 g_return_if_fail (MATE_IS_BG (bg))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((bg)); GType __t = ((mate_bg_get_type ())); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_BG (bg)"); return; } } while (0)
;
338 g_return_if_fail (G_IS_SETTINGS (settings))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((settings)); GType __t = ((g_settings_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "G_IS_SETTINGS (settings)"); return; } } while
(0)
;
339
340 bg->is_enabled = g_settings_get_boolean (settings, MATE_BG_KEY_DRAW_BACKGROUND"draw-background");
341
342 /* Filename */
343 filename = NULL((void*)0);
344 tmp = g_settings_get_string (settings, MATE_BG_KEY_PICTURE_FILENAME"picture-filename");
345 if (tmp && *tmp != '\0') {
346 /* FIXME: UTF-8 checks should go away.
347 * picture-filename is of type string, which can only be used for
348 * UTF-8 strings, and some filenames are not, dependending on the
349 * locale used.
350 * It would be better (and simpler) to change to a URI instead,
351 * as URIs are UTF-8 encoded strings.
352 */
353 if (g_utf8_validate (tmp, -1, NULL((void*)0)) &&
354 g_file_test (tmp, G_FILE_TEST_EXISTS)) {
355 filename = g_strdup (tmp)g_strdup_inline (tmp);
356 } else {
357 filename = g_filename_from_utf8 (tmp, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
358 }
359
360 /* Fallback to default BG if the filename set is non-existent */
361 if (filename != NULL((void*)0) && !g_file_test (filename, G_FILE_TEST_EXISTS)) {
362
363 g_free (filename);
364
365 g_settings_delay (settings);
366 g_settings_reset (settings, MATE_BG_KEY_PICTURE_FILENAME"picture-filename");
367 filename = g_settings_get_string (settings, MATE_BG_KEY_PICTURE_FILENAME"picture-filename");
368 g_settings_revert (settings);
369
370 //* Check if default background exists, also */
371 if (filename != NULL((void*)0) && !g_file_test (filename, G_FILE_TEST_EXISTS)) {
372 g_free (filename);
373 filename = NULL((void*)0);
374 }
375 }
376 }
377 g_free (tmp);
378
379 /* Colors */
380 tmp = g_settings_get_string (settings, MATE_BG_KEY_PRIMARY_COLOR"primary-color");
381 color_from_string (tmp, &c1);
382 g_free (tmp);
383
384 tmp = g_settings_get_string (settings, MATE_BG_KEY_SECONDARY_COLOR"secondary-color");
385 color_from_string (tmp, &c2);
386 g_free (tmp);
387
388 /* Color type */
389 ctype = g_settings_get_enum (settings, MATE_BG_KEY_COLOR_TYPE"color-shading-type");
390
391 /* Placement */
392 placement = g_settings_get_enum (settings, MATE_BG_KEY_PICTURE_PLACEMENT"picture-options");
393
394 mate_bg_set_color (bg, ctype, &c1, &c2);
395 mate_bg_set_placement (bg, placement);
396 mate_bg_set_filename (bg, filename);
397
398 g_free (filename);
399}
400
401void
402mate_bg_save_to_preferences (MateBG *bg)
403{
404 GSettings *settings;
405 settings = g_settings_new (MATE_BG_SCHEMA"org.mate.background");
406
407 mate_bg_save_to_gsettings (bg, settings);
408 g_object_unref (settings);
409}
410
411void
412mate_bg_save_to_gsettings (MateBG *bg,
413 GSettings *settings)
414{
415 gchar *primary;
416 gchar *secondary;
417
418 g_return_if_fail (MATE_IS_BG (bg))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((bg)); GType __t = ((mate_bg_get_type ())); gboolean __r;
if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "MATE_IS_BG (bg)"); return; } } while (0)
;
419 g_return_if_fail (G_IS_SETTINGS (settings))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((settings)); GType __t = ((g_settings_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("MateDesktop", ((const char
*) (__func__)), "G_IS_SETTINGS (settings)"); return; } } while
(0)
;
420
421 primary = color_to_string (&bg->primary);
422 secondary = color_to_string (&bg->secondary);
423
424 g_settings_delay (settings);
425
426 g_settings_set_boolean (settings, MATE_BG_KEY_DRAW_BACKGROUND"draw-background", bg->is_enabled);
427 g_settings_set_string (settings, MATE_BG_KEY_PICTURE_FILENAME"picture-filename", bg->filename);
428 g_settings_set_enum (settings, MATE_BG_KEY_PICTURE_PLACEMENT"picture-options", bg->placement);
429 g_settings_set_string (settings, MATE_BG_KEY_PRIMARY_COLOR"primary-color", primary);
430 g_settings_set_string (settings, MATE_BG_KEY_SECONDARY_COLOR"secondary-color", secondary);
431 g_settings_set_enum (settings, MATE_BG_KEY_COLOR_TYPE"color-shading-type", bg->color_type);
432
433 /* Apply changes atomically. */
434 g_settings_apply (settings);
435
436 g_free (primary);
437 g_free (secondary);
438}
439
440static void
441mate_bg_init (MateBG *bg)
442{
443}
444
445static void
446mate_bg_dispose (GObject *object)
447{
448 MateBG *bg = MATE_BG (object)((((MateBG*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((mate_bg_get_type ()))))))
;
449
450 if (bg->file_monitor) {
451 g_object_unref (bg->file_monitor);
452 bg->file_monitor = NULL((void*)0);
453 }
454
455 clear_cache (bg);
456
457 G_OBJECT_CLASS (mate_bg_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((mate_bg_parent_class)), (((GType) ((20) << (2)))))
)))
->dispose (object);
458}
459
460static void
461mate_bg_finalize (GObject *object)
462{
463 MateBG *bg = MATE_BG (object)((((MateBG*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((mate_bg_get_type ()))))))
;
464
465 if (bg->changed_id != 0) {
466 g_source_remove (bg->changed_id);
467 bg->changed_id = 0;
468 }
469
470 if (bg->transitioned_id != 0) {
471 g_source_remove (bg->transitioned_id);
472 bg->transitioned_id = 0;
473 }
474
475 if (bg->blow_caches_id != 0) {
476 g_source_remove (bg->blow_caches_id);
477 bg->blow_caches_id = 0;
478 }
479
480 g_free (bg->filename);
481 bg->filename = NULL((void*)0);
482
483 G_OBJECT_CLASS (mate_bg_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((mate_bg_parent_class)), (((GType) ((20) << (2)))))
)))
->finalize (object);
484}
485
486static void
487mate_bg_class_init (MateBGClass *klass)
488{
489 GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), (((GType) ((20) << (2))))))))
;
490
491 object_class->dispose = mate_bg_dispose;
492 object_class->finalize = mate_bg_finalize;
493
494 signals[CHANGED] = g_signal_new ("changed",
495 G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)),
496 G_SIGNAL_RUN_LAST,
497 0,
498 NULL((void*)0), NULL((void*)0),
499 g_cclosure_marshal_VOID__VOID,
500 G_TYPE_NONE((GType) ((1) << (2))), 0);
501
502 signals[TRANSITIONED] = g_signal_new ("transitioned",
503 G_OBJECT_CLASS_TYPE (object_class)((((GTypeClass*) (object_class))->g_type)),
504 G_SIGNAL_RUN_LAST,
505 0,
506 NULL((void*)0), NULL((void*)0),
507 g_cclosure_marshal_VOID__VOID,
508 G_TYPE_NONE((GType) ((1) << (2))), 0);
509}
510
511MateBG *
512mate_bg_new (void)
513{
514 return g_object_new (MATE_TYPE_BG(mate_bg_get_type ()), NULL((void*)0));
515}
516
517void
518mate_bg_set_color (MateBG *bg,
519 MateBGColorType type,
520 GdkRGBA *primary,
521 GdkRGBA *secondary)
522{
523 g_return_if_fail (bg != NULL)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
; } } while (0)
;
524 g_return_if_fail (primary != NULL)do { if ((primary != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "primary != NULL"
); return; } } while (0)
;
525
526 if (bg->color_type != type ||
527 !gdk_rgba_equal (&bg->primary, primary) ||
528 (secondary && !gdk_rgba_equal (&bg->secondary, secondary))) {
529 bg->color_type = type;
530 bg->primary = *primary;
531 if (secondary) {
532 bg->secondary = *secondary;
533 }
534
535 queue_changed (bg);
536 }
537}
538
539void
540mate_bg_set_placement (MateBG *bg,
541 MateBGPlacement placement)
542{
543 g_return_if_fail (bg != NULL)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
; } } while (0)
;
544
545 if (bg->placement != placement) {
546 bg->placement = placement;
547
548 queue_changed (bg);
549 }
550}
551
552MateBGPlacement
553mate_bg_get_placement (MateBG *bg)
554{
555 g_return_val_if_fail (bg != NULL, -1)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
(-1); } } while (0)
;
556
557 return bg->placement;
558}
559
560void
561mate_bg_get_color (MateBG *bg,
562 MateBGColorType *type,
563 GdkRGBA *primary,
564 GdkRGBA *secondary)
565{
566 g_return_if_fail (bg != NULL)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
; } } while (0)
;
567
568 if (type)
569 *type = bg->color_type;
570
571 if (primary)
572 *primary = bg->primary;
573
574 if (secondary)
575 *secondary = bg->secondary;
576}
577
578void
579mate_bg_set_draw_background (MateBG *bg,
580 gboolean draw_background)
581{
582 g_return_if_fail (bg != NULL)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
; } } while (0)
;
583
584 if (bg->is_enabled != draw_background) {
585 bg->is_enabled = draw_background;
586
587 queue_changed (bg);
588 }
589}
590
591gboolean
592mate_bg_get_draw_background (MateBG *bg)
593{
594 g_return_val_if_fail (bg != NULL, FALSE)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
((0)); } } while (0)
;
595
596 return bg->is_enabled;
597}
598
599const gchar *
600mate_bg_get_filename (MateBG *bg)
601{
602 g_return_val_if_fail (bg != NULL, NULL)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
(((void*)0)); } } while (0)
;
603
604 return bg->filename;
605}
606
607static inline gchar *
608get_wallpaper_cache_dir (void)
609{
610 return g_build_filename (g_get_user_cache_dir(), MATE_BG_CACHE_DIR"mate/background", NULL((void*)0));
611}
612
613static inline gchar *
614get_wallpaper_cache_prefix_name (gint num_monitor,
615 MateBGPlacement placement,
616 gint width,
617 gint height)
618{
619 return g_strdup_printf ("%i_%i_%i_%i", num_monitor, (gint) placement, width, height);
620}
621
622static char *
623get_wallpaper_cache_filename (const char *filename,
624 gint num_monitor,
625 MateBGPlacement placement,
626 gint width,
627 gint height)
628{
629 gchar *cache_filename;
630 gchar *cache_prefix_name;
631 gchar *md5_filename;
632 gchar *cache_basename;
633 gchar *cache_dir;
634
635 md5_filename = g_compute_checksum_for_data (G_CHECKSUM_MD5, (const guchar *) filename,
636 strlen (filename));
637 cache_prefix_name = get_wallpaper_cache_prefix_name (num_monitor, placement, width, height);
638 cache_basename = g_strdup_printf ("%s_%s", cache_prefix_name, md5_filename);
639 cache_dir = get_wallpaper_cache_dir ();
640 cache_filename = g_build_filename (cache_dir, cache_basename, NULL((void*)0));
641
642 g_free (cache_prefix_name);
643 g_free (md5_filename);
644 g_free (cache_basename);
645 g_free (cache_dir);
646
647 return cache_filename;
648}
649
650static void
651cleanup_cache_for_monitor (gchar *cache_dir,
652 gint num_monitor)
653{
654 GDir *g_cache_dir;
655 gchar *monitor_prefix;
656 const gchar *file;
657
658 g_cache_dir = g_dir_open (cache_dir, 0, NULL((void*)0));
659 monitor_prefix = g_strdup_printf ("%i_", num_monitor);
660
661 file = g_dir_read_name (g_cache_dir);
662 while (file != NULL((void*)0)) {
663 gchar *path = g_build_filename (cache_dir, file, NULL((void*)0));
664
665 /* purge files with same monitor id */
666 if (g_str_has_prefix (file, monitor_prefix)(__builtin_constant_p (monitor_prefix)? __extension__ ({ const
char * const __str = (file); const char * const __prefix = (
monitor_prefix); gboolean __result = (0); if (__str == ((void
*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix)
(__str, __prefix); else { const size_t __str_len = strlen ((
(__str) + !(__str))); const size_t __prefix_len = strlen (((__prefix
) + !(__prefix))); if (__str_len >= __prefix_len) __result
= memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len
) == 0; } __result; }) : (g_str_has_prefix) (file, monitor_prefix
) )
&&
667 g_file_test (path, G_FILE_TEST_IS_REGULAR))
668 g_unlink (path);
669
670 g_free (path);
671
672 file = g_dir_read_name (g_cache_dir);
673 }
674
675 g_free (monitor_prefix);
676 g_dir_close (g_cache_dir);
677}
678
679static gboolean
680cache_file_is_valid (const char *filename,
681 const char *cache_filename)
682{
683 if (!g_file_test (cache_filename, G_FILE_TEST_IS_REGULAR))
684 return FALSE(0);
685
686 return (get_mtime (filename) < get_mtime (cache_filename));
687}
688
689static void
690refresh_cache_file (MateBG *bg,
691 GdkPixbuf *new_pixbuf,
692 gint num_monitor,
693 gint width,
694 gint height)
695{
696 gchar *cache_filename;
697 gchar *cache_dir;
698 GdkPixbufFormat *format;
699 gchar *format_name;
700
701 if ((num_monitor == -1) || (width <= 300) || (height <= 300))
702 return;
703
704 cache_filename = get_wallpaper_cache_filename (bg->filename, num_monitor,
705 bg->placement, width, height);
706 cache_dir = get_wallpaper_cache_dir ();
707
708 /* Only refresh scaled file on disk if useful (and don't cache slideshow) */
709 if (!cache_file_is_valid (bg->filename, cache_filename)) {
710 format = gdk_pixbuf_get_file_info (bg->filename, NULL((void*)0), NULL((void*)0));
711
712 if (format != NULL((void*)0)) {
713 if (!g_file_test (cache_dir, G_FILE_TEST_IS_DIR)) {
714 g_mkdir_with_parents (cache_dir, 0700);
715 } else {
716 cleanup_cache_for_monitor (cache_dir, num_monitor);
717 }
718
719 format_name = gdk_pixbuf_format_get_name (format);
720
721 if (strcmp (format_name, "jpeg") == 0)
722 gdk_pixbuf_save (new_pixbuf, cache_filename, format_name,
723 NULL((void*)0), "quality", "100", NULL((void*)0));
724 else
725 gdk_pixbuf_save (new_pixbuf, cache_filename, format_name,
726 NULL((void*)0), NULL((void*)0));
727
728 g_free (format_name);
729 }
730 }
731
732 g_free (cache_filename);
733 g_free (cache_dir);
734}
735
736static void
737file_changed (GFileMonitor *file_monitor,
738 GFile *child,
739 GFile *other_file,
740 GFileMonitorEvent event_type,
741 gpointer user_data)
742{
743 MateBG *bg = MATE_BG (user_data)((((MateBG*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((user_data)), ((mate_bg_get_type ()))))))
;
744
745 clear_cache (bg);
746 queue_changed (bg);
747}
748
749void
750mate_bg_set_filename (MateBG *bg,
751 const char *filename)
752{
753 g_return_if_fail (bg != NULL)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
; } } while (0)
;
754
755 if (is_different (bg, filename)) {
756 g_free (bg->filename);
757
758 bg->filename = g_strdup (filename)g_strdup_inline (filename);
759 bg->file_mtime = get_mtime (bg->filename);
760
761 if (bg->file_monitor) {
762 g_object_unref (bg->file_monitor);
763 bg->file_monitor = NULL((void*)0);
764 }
765
766 if (bg->filename) {
767 GFile *f = g_file_new_for_path (bg->filename);
768
769 bg->file_monitor = g_file_monitor_file (f, 0, NULL((void*)0), NULL((void*)0));
770 g_signal_connect (bg->file_monitor, "changed",g_signal_connect_data ((bg->file_monitor), ("changed"), ((
(GCallback) (file_changed))), (bg), ((void*)0), (GConnectFlags
) 0)
771 G_CALLBACK (file_changed), bg)g_signal_connect_data ((bg->file_monitor), ("changed"), ((
(GCallback) (file_changed))), (bg), ((void*)0), (GConnectFlags
) 0)
;
772
773 g_object_unref (f);
774 }
775
776 clear_cache (bg);
777
778 queue_changed (bg);
779 }
780}
781
782static void
783draw_color_area (MateBG *bg,
784 GdkPixbuf *dest,
785 GdkRectangle *rect)
786{
787 guint32 pixel;
788 GdkRectangle extent;
789
790 extent.x = 0;
791 extent.y = 0;
792 extent.width = gdk_pixbuf_get_width (dest);
793 extent.height = gdk_pixbuf_get_height (dest);
794
795 gdk_rectangle_intersect (rect, &extent, rect);
796
797 switch (bg->color_type) {
798 case MATE_BG_COLOR_SOLID:
799 /* not really a big deal to ignore the area of interest */
800 pixel = ((guint) (bg->primary.red * 0xff) << 24) |
801 ((guint) (bg->primary.green * 0xff) << 16) |
802 ((guint) (bg->primary.blue * 0xff) << 8) |
803 (0xff);
804
805 gdk_pixbuf_fill (dest, pixel);
806 break;
807
808 case MATE_BG_COLOR_H_GRADIENT:
809 pixbuf_draw_gradient (dest, TRUE(!(0)), &(bg->primary), &(bg->secondary), rect);
810 break;
811
812 case MATE_BG_COLOR_V_GRADIENT:
813 pixbuf_draw_gradient (dest, FALSE(0), &(bg->primary), &(bg->secondary), rect);
814 break;
815
816 default:
817 break;
818 }
819}
820
821static void
822draw_color (MateBG *bg,
823 GdkPixbuf *dest)
824{
825 GdkRectangle rect;
826
827 rect.x = 0;
828 rect.y = 0;
829 rect.width = gdk_pixbuf_get_width (dest);
830 rect.height = gdk_pixbuf_get_height (dest);
831 draw_color_area (bg, dest, &rect);
832}
833
834static void
835draw_color_each_monitor (MateBG *bg,
836 GdkPixbuf *dest,
837 GdkScreen *screen)
838{
839 GdkDisplay *display;
840 GdkRectangle rect;
841 gint num_monitors;
842 int monitor;
843
844 display = gdk_screen_get_display (screen);
845 num_monitors = gdk_display_get_n_monitors (display);
846 for (monitor = 0; monitor < num_monitors; monitor++) {
847 gdk_monitor_get_geometry (gdk_display_get_monitor (display, monitor), &rect);
848 draw_color_area (bg, dest, &rect);
849 }
850}
851
852static GdkPixbuf *
853pixbuf_clip_to_fit (GdkPixbuf *src,
854 int max_width,
855 int max_height)
856{
857 int src_width, src_height;
858 int w, h;
859 int src_x, src_y;
860 GdkPixbuf *pixbuf;
861
862 src_width = gdk_pixbuf_get_width (src);
863 src_height = gdk_pixbuf_get_height (src);
864
865 if (src_width < max_width && src_height < max_height)
866 return g_object_ref (src)((__typeof__ (src)) (g_object_ref) (src));
867
868 w = MIN(src_width, max_width)(((src_width) < (max_width)) ? (src_width) : (max_width));
869 h = MIN(src_height, max_height)(((src_height) < (max_height)) ? (src_height) : (max_height
))
;
870
871 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
872 gdk_pixbuf_get_has_alpha (src),
873 8, w, h);
874
875 src_x = (src_width - w) / 2;
876 src_y = (src_height - h) / 2;
877 gdk_pixbuf_copy_area (src,
878 src_x, src_y,
879 w, h,
880 pixbuf,
881 0, 0);
882 return pixbuf;
883}
884
885static GdkPixbuf *
886get_scaled_pixbuf (MateBGPlacement placement,
887 GdkPixbuf *pixbuf,
888 int width, int height,
889 int *x, int *y,
890 int *w, int *h)
891{
892 GdkPixbuf *new;
893
894#if 0
895 g_print ("original_width: %d %d\n",
896 gdk_pixbuf_get_width (pixbuf),
897 gdk_pixbuf_get_height (pixbuf));
898#endif
899
900 switch (placement) {
901 case MATE_BG_PLACEMENT_SPANNED:
902 new = pixbuf_scale_to_fit (pixbuf, width, height);
903 break;
904 case MATE_BG_PLACEMENT_ZOOMED:
905 new = pixbuf_scale_to_min (pixbuf, width, height);
906 break;
907
908 case MATE_BG_PLACEMENT_FILL_SCREEN:
909 new = gdk_pixbuf_scale_simple (pixbuf, width, height,
910 GDK_INTERP_BILINEAR);
911 break;
912
913 case MATE_BG_PLACEMENT_SCALED:
914 new = pixbuf_scale_to_fit (pixbuf, width, height);
915 break;
916
917 case MATE_BG_PLACEMENT_CENTERED:
918 case MATE_BG_PLACEMENT_TILED:
919 default:
920 new = pixbuf_clip_to_fit (pixbuf, width, height);
921 break;
922 }
923
924 *w = gdk_pixbuf_get_width (new);
925 *h = gdk_pixbuf_get_height (new);
926 *x = (width - *w) / 2;
927 *y = (height - *h) / 2;
928
929 return new;
930}
931
932static void
933draw_image_area (MateBG *bg,
934 gint num_monitor,
935 GdkPixbuf *pixbuf,
936 GdkPixbuf *dest,
937 GdkRectangle *area)
938{
939 int dest_width = area->width;
940 int dest_height = area->height;
941 int x, y, w, h;
942 GdkPixbuf *scaled;
943
944 if (!pixbuf)
945 return;
946
947 scaled = get_scaled_pixbuf (bg->placement, pixbuf, dest_width, dest_height, &x, &y, &w, &h);
948
949 switch (bg->placement) {
950 case MATE_BG_PLACEMENT_TILED:
951 pixbuf_tile (scaled, dest);
952 break;
953 case MATE_BG_PLACEMENT_ZOOMED:
954 case MATE_BG_PLACEMENT_CENTERED:
955 case MATE_BG_PLACEMENT_FILL_SCREEN:
956 case MATE_BG_PLACEMENT_SCALED:
957 pixbuf_blend (scaled, dest, 0, 0, w, h, x + area->x, y + area->y, 1.0);
958 break;
959 case MATE_BG_PLACEMENT_SPANNED:
960 pixbuf_blend (scaled, dest, 0, 0, w, h, x, y, 1.0);
961 break;
962 default:
963 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-bg.c", 963
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
964 break;
965 }
966
967 refresh_cache_file (bg, scaled, num_monitor, dest_width, dest_height);
968
969 g_object_unref (scaled);
970}
971
972static void
973draw_image_for_thumb (MateBG *bg,
974 GdkPixbuf *pixbuf,
975 GdkPixbuf *dest)
976{
977 GdkRectangle rect;
978
979 rect.x = 0;
980 rect.y = 0;
981 rect.width = gdk_pixbuf_get_width (dest);
982 rect.height = gdk_pixbuf_get_height (dest);
983
984 draw_image_area (bg, -1, pixbuf, dest, &rect);
985}
986
987static void
988draw_once (MateBG *bg,
989 GdkPixbuf *dest,
990 gboolean is_root)
991{
992 GdkRectangle rect;
993 GdkPixbuf *pixbuf;
994 gint monitor;
995
996 /* whether we're drawing on root window or normal (Caja) window */
997 monitor = (is_root) ? 0 : -1;
998
999 rect.x = 0;
1000 rect.y = 0;
1001 rect.width = gdk_pixbuf_get_width (dest);
1002 rect.height = gdk_pixbuf_get_height (dest);
1003
1004 pixbuf = get_pixbuf_for_size (bg, monitor, rect.width, rect.height);
1005 if (pixbuf) {
1006 draw_image_area (bg, monitor, pixbuf, dest, &rect);
1007
1008 g_object_unref (pixbuf);
1009 }
1010}
1011
1012static void
1013draw_each_monitor (MateBG *bg,
1014 GdkPixbuf *dest,
1015 GdkScreen *screen)
1016{
1017 GdkDisplay *display;
1018
1019 display = gdk_screen_get_display (screen);
1020 gint num_monitors = gdk_display_get_n_monitors (display);
1021 gint monitor = 0;
1022
1023 for (; monitor < num_monitors; monitor++) {
1024 GdkRectangle rect;
1025 GdkPixbuf *pixbuf;
1026
1027 gdk_monitor_get_geometry (gdk_display_get_monitor (display, monitor), &rect);
1028
1029 pixbuf = get_pixbuf_for_size (bg, monitor, rect.width, rect.height);
1030 if (pixbuf) {
1031 draw_image_area (bg, monitor, pixbuf, dest, &rect);
1032
1033 g_object_unref (pixbuf);
1034 }
1035 }
1036}
1037
1038void
1039mate_bg_draw (MateBG *bg,
1040 GdkPixbuf *dest,
1041 GdkScreen *screen,
1042 gboolean is_root)
1043{
1044 if (!bg)
1045 return;
1046
1047 if (is_root && (bg->placement != MATE_BG_PLACEMENT_SPANNED)) {
1048 draw_color_each_monitor (bg, dest, screen);
1049 if (bg->filename) {
1050 draw_each_monitor (bg, dest, screen);
1051 }
1052 } else {
1053 draw_color (bg, dest);
1054 if (bg->filename) {
1055 draw_once (bg, dest, is_root);
1056 }
1057 }
1058}
1059
1060gboolean
1061mate_bg_has_multiple_sizes (MateBG *bg)
1062{
1063 SlideShow *show;
1064 gboolean ret;
1065
1066 g_return_val_if_fail (bg != NULL, FALSE)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
((0)); } } while (0)
;
1067
1068 ret = FALSE(0);
1069
1070 show = get_as_slideshow (bg, bg->filename);
1071 if (show) {
1072 ret = slideshow_has_multiple_sizes (show);
1073 slideshow_unref (show);
1074 }
1075
1076 return ret;
1077}
1078
1079static void
1080mate_bg_get_pixmap_size (MateBG *bg,
1081 int width,
1082 int height,
1083 int *pixmap_width,
1084 int *pixmap_height)
1085{
1086 int dummy;
1087
1088 if (!pixmap_width)
1089 pixmap_width = &dummy;
1090 if (!pixmap_height)
1091 pixmap_height = &dummy;
1092
1093 *pixmap_width = width;
1094 *pixmap_height = height;
1095
1096 if (!bg->filename) {
1097 switch (bg->color_type) {
1098 case MATE_BG_COLOR_SOLID:
1099 *pixmap_width = 1;
1100 *pixmap_height = 1;
1101 break;
1102
1103 case MATE_BG_COLOR_H_GRADIENT:
1104 case MATE_BG_COLOR_V_GRADIENT:
1105 break;
1106 }
1107
1108 return;
1109 }
1110}
1111
1112/**
1113 * mate_bg_create_surface:
1114 * @bg: MateBG
1115 * @window:
1116 * @width:
1117 * @height:
1118 * @root:
1119 *
1120 * Create a surface that can be set as background for @window. If @root is
1121 * TRUE, the surface created will be created by a temporary X server connection
1122 * so that if someone calls XKillClient on it, it won't affect the application
1123 * who created it.
1124 **/
1125cairo_surface_t *
1126mate_bg_create_surface (MateBG *bg,
1127 GdkWindow *window,
1128 int width,
1129 int height,
1130 gboolean root)
1131{
1132 return mate_bg_create_surface_scale (bg,
1133 window,
1134 width,
1135 height,
1136 1,
1137 root);
1138}
1139
1140/**
1141 * mate_bg_create_surface_scale:
1142 * @bg: MateBG
1143 * @window:
1144 * @width:
1145 * @height:
1146 * @scale:
1147 * @root:
1148 *
1149 * Create a scaled surface that can be set as background for @window. If @root is
1150 * TRUE, the surface created will be created by a temporary X server connection
1151 * so that if someone calls XKillClient on it, it won't affect the application
1152 * who created it.
1153 **/
1154cairo_surface_t *
1155mate_bg_create_surface_scale (MateBG *bg,
1156 GdkWindow *window,
1157 int width,
1158 int height,
1159 int scale,
1160 gboolean root)
1161{
1162 int pm_width, pm_height;
1163
1164 cairo_surface_t *surface;
1165 cairo_t *cr;
1166 GdkDisplay *display;
1167
1168 g_return_val_if_fail (bg != NULL, NULL)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
(((void*)0)); } } while (0)
;
1169 g_return_val_if_fail (window != NULL, NULL)do { if ((window != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "window != NULL"
); return (((void*)0)); } } while (0)
;
1170
1171 if (bg->pixbuf_cache &&
1172 (gdk_pixbuf_get_width (bg->pixbuf_cache) != width ||
1173 gdk_pixbuf_get_height (bg->pixbuf_cache) != height))
1174 {
1175 g_object_unref (bg->pixbuf_cache);
1176 bg->pixbuf_cache = NULL((void*)0);
1177 }
1178
1179 mate_bg_get_pixmap_size (bg, width, height, &pm_width, &pm_height);
1180
1181 display = gdk_display_get_default ();
1182
1183 if ((root) && GDK_IS_X11_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((gdk_x11_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1184 {
1185 surface = make_root_pixmap (window, pm_width * scale, pm_height * scale);
1186 }
1187 else
1188 {
1189 surface = gdk_window_create_similar_surface (window, CAIRO_CONTENT_COLOR,
1190 pm_width, pm_height);
1191 }
1192
1193 cr = cairo_create (surface);
1194 cairo_scale (cr, (double)scale, (double)scale);
1195
1196 if (!bg->filename && bg->color_type == MATE_BG_COLOR_SOLID) {
1197 gdk_cairo_set_source_rgba (cr, &(bg->primary));
1198 }
1199 else
1200 {
1201 GdkPixbuf *pixbuf;
1202
1203 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE(0), 8,
1204 width, height);
1205 mate_bg_draw (bg, pixbuf, gdk_window_get_screen (window), root);
1206 gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
1207 g_object_unref (pixbuf);
1208 }
1209
1210 cairo_paint (cr);
1211
1212 cairo_destroy (cr);
1213
1214 return surface;
1215}
1216
1217/* determine if a background is darker or lighter than average, to help
1218 * clients know what colors to draw on top with
1219 */
1220gboolean
1221mate_bg_is_dark (MateBG *bg,
1222 int width,
1223 int height)
1224{
1225 GdkRGBA color;
1226 int intensity;
1227 GdkPixbuf *pixbuf;
1228
1229 g_return_val_if_fail (bg != NULL, FALSE)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
((0)); } } while (0)
;
1230
1231 if (bg->color_type == MATE_BG_COLOR_SOLID) {
1232 color = bg->primary;
1233 } else {
1234 color.red = (bg->primary.red + bg->secondary.red) / 2;
1235 color.green = (bg->primary.green + bg->secondary.green) / 2;
1236 color.blue = (bg->primary.blue + bg->secondary.blue) / 2;
1237 }
1238 pixbuf = get_pixbuf_for_size (bg, -1, width, height);
1239 if (pixbuf) {
1240 GdkRGBA argb;
1241 guchar a, r, g, b;
1242
1243 pixbuf_average_value (pixbuf, &argb);
1244 a = argb.alpha * 0xff;
1245 r = argb.red * 0xff;
1246 g = argb.green * 0xff;
1247 b = argb.blue * 0xff;
1248
1249 color.red = (color.red * (0xFF - a) + r * 0x101 * a) / 0xFF;
1250 color.green = (color.green * (0xFF - a) + g * 0x101 * a) / 0xFF;
1251 color.blue = (color.blue * (0xFF - a) + b * 0x101 * a) / 0xFF;
1252 g_object_unref (pixbuf);
1253 }
1254
1255 intensity = ((guint) (color.red * 65535) * 77 +
1256 (guint) (color.green * 65535) * 150 +
1257 (guint) (color.blue * 65535) * 28) >> 16;
1258
1259 return intensity < 160; /* biased slightly to be dark */
1260}
1261
1262/*
1263 * Create a persistent pixmap. We create a separate display
1264 * and set the closedown mode on it to RetainPermanent.
1265 */
1266static cairo_surface_t *
1267make_root_pixmap (GdkWindow *window, gint width, gint height)
1268{
1269 GdkScreen *screen = gdk_window_get_screen(window);
1270 char *disp_name = DisplayString (GDK_WINDOW_XDISPLAY (window))(((_XPrivDisplay)(((gdk_x11_display_get_xdisplay (gdk_window_get_display
(window))))))->display_name)
;
1271 Display *display;
1272 Pixmap xpixmap;
1273 cairo_surface_t *surface;
1274 int depth;
1275
1276 /* Desktop background pixmap should be created from dummy X client since most
1277 * applications will try to kill it with XKillClient later when changing pixmap
1278 */
1279 display = XOpenDisplay (disp_name);
1280
1281 if (display == NULL((void*)0)) {
1282 g_warning ("Unable to open display '%s' when setting background pixmap\n",
1283 (disp_name) ? disp_name : "NULL");
1284 return NULL((void*)0);
1285 }
1286
1287 depth = DefaultDepth (display, gdk_x11_screen_get_screen_number (screen))((&((_XPrivDisplay)(display))->screens[gdk_x11_screen_get_screen_number
(screen)])->root_depth)
;
1288 xpixmap = XCreatePixmap (display, GDK_WINDOW_XID (window)(gdk_x11_window_get_xid (window)), width, height, depth);
1289
1290 XFlush (display);
1291 XSetCloseDownMode (display, RetainPermanent1);
1292 XCloseDisplay (display);
1293
1294 surface = cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (screen)(gdk_x11_display_get_xdisplay (gdk_screen_get_display (screen
)))
, xpixmap,
1295 GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen))(gdk_x11_visual_get_xvisual (gdk_screen_get_system_visual (screen
)))
,
1296 width, height);
1297
1298 return surface;
1299}
1300
1301static gboolean
1302get_original_size (const char *filename,
1303 int *orig_width,
1304 int *orig_height)
1305{
1306 gboolean result;
1307
1308 if (gdk_pixbuf_get_file_info (filename, orig_width, orig_height))
1309 result = TRUE(!(0));
1310 else
1311 result = FALSE(0);
1312
1313 return result;
1314}
1315
1316static const char *
1317get_filename_for_size (MateBG *bg, gint best_width, gint best_height)
1318{
1319 SlideShow *show;
1320 Slide *slide;
1321 FileSize *size;
1322
1323 if (!bg->filename)
1324 return NULL((void*)0);
1325
1326 show = get_as_slideshow (bg, bg->filename);
1327 if (!show) {
1328 return bg->filename;
1329 }
1330
1331 slide = get_current_slide (show, NULL((void*)0));
1332 slideshow_unref (show);
1333 size = find_best_size (slide->file1, best_width, best_height);
1334 return size->file;
1335}
1336
1337gboolean
1338mate_bg_get_image_size (MateBG *bg,
1339 MateDesktopThumbnailFactory *factory,
1340 int best_width,
1341 int best_height,
1342 int *width,
1343 int *height)
1344{
1345 GdkPixbuf *thumb;
1346 gboolean result = FALSE(0);
1347 const gchar *filename;
1348
1349 g_return_val_if_fail (bg != NULL, FALSE)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
((0)); } } while (0)
;
1350 g_return_val_if_fail (factory != NULL, FALSE)do { if ((factory != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "factory != NULL"
); return ((0)); } } while (0)
;
1351
1352 if (!bg->filename)
1353 return FALSE(0);
1354
1355 filename = get_filename_for_size (bg, best_width, best_height);
1356 thumb = create_thumbnail_for_filename (factory, filename);
1357 if (thumb) {
1358 if (get_thumb_annotations (thumb, width, height))
1359 result = TRUE(!(0));
1360
1361 g_object_unref (thumb);
1362 }
1363
1364 if (!result) {
1365 if (get_original_size (filename, width, height))
1366 result = TRUE(!(0));
1367 }
1368
1369 return result;
1370}
1371
1372static double
1373fit_factor (int from_width, int from_height,
1374 int to_width, int to_height)
1375{
1376 return MIN (to_width / (double) from_width, to_height / (double) from_height)(((to_width / (double) from_width) < (to_height / (double)
from_height)) ? (to_width / (double) from_width) : (to_height
/ (double) from_height))
;
1377}
1378
1379/**
1380 * mate_bg_create_thumbnail:
1381 *
1382 * Returns: (transfer full): a #GdkPixbuf showing the background as a thumbnail
1383 */
1384GdkPixbuf *
1385mate_bg_create_thumbnail (MateBG *bg,
1386 MateDesktopThumbnailFactory *factory,
1387 GdkScreen *screen,
1388 int dest_width,
1389 int dest_height)
1390{
1391 GdkPixbuf *result;
1392 GdkPixbuf *thumb;
1393
1394 g_return_val_if_fail (bg != NULL, NULL)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
(((void*)0)); } } while (0)
;
1395
1396 result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE(0), 8, dest_width, dest_height);
1397
1398 draw_color (bg, result);
1399
1400 if (bg->filename) {
1401 thumb = create_img_thumbnail (bg, factory, screen, dest_width, dest_height, -1);
1402
1403 if (thumb) {
1404 draw_image_for_thumb (bg, thumb, result);
1405 g_object_unref (thumb);
1406 }
1407 }
1408
1409 return result;
1410}
1411
1412/**
1413 * mate_bg_get_surface_from_root:
1414 * @screen: a #GdkScreen
1415 *
1416 * This function queries the _XROOTPMAP_ID property from
1417 * the root window associated with @screen to determine
1418 * the current root window background surface and returns
1419 * a copy of it. If the _XROOTPMAP_ID is not set, then
1420 * a black surface is returned.
1421 *
1422 * Return value: a #cairo_surface_t if successful or %NULL
1423 **/
1424cairo_surface_t *
1425mate_bg_get_surface_from_root (GdkScreen *screen)
1426{
1427 int result;
1428 gint format;
1429 gulong nitems;
1430 gulong bytes_after;
1431 guchar *data;
1432 Atom type;
1433 Display *display;
1434 int screen_num;
1435 cairo_surface_t *surface;
1436 cairo_surface_t *source_pixmap;
1437 GdkDisplay *gdkdisplay;
1438 int width, height;
1439 cairo_t *cr;
1440
1441 display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen))(gdk_x11_display_get_xdisplay (gdk_screen_get_display (screen
)))
;
1442 screen_num = gdk_x11_screen_get_screen_number (screen);
1443
1444 result = XGetWindowProperty (display,
1445 RootWindow (display, screen_num)((&((_XPrivDisplay)(display))->screens[screen_num])->
root)
,
1446 gdk_x11_get_xatom_by_name ("_XROOTPMAP_ID"),
1447 0L, 1L, False0, XA_PIXMAP((Atom) 20),
1448 &type, &format, &nitems, &bytes_after,
1449 &data);
1450 surface = NULL((void*)0);
1451 source_pixmap = NULL((void*)0);
1452
1453 if (result != Success0 || type != XA_PIXMAP((Atom) 20) ||
1454 format != 32 || nitems != 1) {
1455 XFree (data);
1456 data = NULL((void*)0);
1457 }
1458
1459 if (data != NULL((void*)0)) {
1460 gdkdisplay = gdk_screen_get_display (screen);
1461 gdk_x11_display_error_trap_push (gdkdisplay);
1462
1463 Pixmap xpixmap = *(Pixmap *) data;
1464 Window root_return;
1465 int x_ret, y_ret;
1466 unsigned int w_ret, h_ret, bw_ret, depth_ret;
1467
1468 if (XGetGeometry (GDK_SCREEN_XDISPLAY (screen)(gdk_x11_display_get_xdisplay (gdk_screen_get_display (screen
)))
,
1469 xpixmap,
1470 &root_return,
1471 &x_ret, &y_ret, &w_ret, &h_ret, &bw_ret, &depth_ret))
1472 {
1473 source_pixmap = cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (screen)(gdk_x11_display_get_xdisplay (gdk_screen_get_display (screen
)))
,
1474 xpixmap,
1475 GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen))(gdk_x11_visual_get_xvisual (gdk_screen_get_system_visual (screen
)))
,
1476 w_ret, h_ret);
1477 }
1478
1479 gdk_x11_display_error_trap_pop_ignored (gdkdisplay);
1480 }
1481
1482 width = WidthOfScreen (gdk_x11_screen_get_xscreen (screen))((gdk_x11_screen_get_xscreen (screen))->width);
1483 height = HeightOfScreen (gdk_x11_screen_get_xscreen (screen))((gdk_x11_screen_get_xscreen (screen))->height);
1484
1485 if (source_pixmap) {
1486 surface = cairo_surface_create_similar (source_pixmap,
1487 CAIRO_CONTENT_COLOR,
1488 width, height);
1489
1490 cr = cairo_create (surface);
1491 cairo_set_source_surface (cr, source_pixmap, 0, 0);
1492 cairo_paint (cr);
1493
1494 if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
1495 cairo_surface_destroy (surface);
1496 surface = NULL((void*)0);
1497 }
1498
1499 cairo_destroy (cr);
1500 }
1501
1502 if (surface == NULL((void*)0)) {
1503 surface = gdk_window_create_similar_surface (gdk_screen_get_root_window (screen),
1504 CAIRO_CONTENT_COLOR,
1505 width, height);
1506 }
1507
1508 if (source_pixmap != NULL((void*)0))
1509 cairo_surface_destroy (source_pixmap);
1510
1511 if (data != NULL((void*)0))
1512 XFree (data);
1513
1514 return surface;
1515}
1516
1517/* Sets the "ESETROOT_PMAP_ID" property to later be used to free the pixmap,
1518 */
1519static void
1520mate_bg_set_root_pixmap_id (GdkScreen *screen,
1521 Display *display,
1522 Pixmap xpixmap)
1523{
1524 Window xroot = RootWindow (display, gdk_x11_screen_get_screen_number (screen))((&((_XPrivDisplay)(display))->screens[gdk_x11_screen_get_screen_number
(screen)])->root)
;
1525 char *atom_names[] = {"_XROOTPMAP_ID", "ESETROOT_PMAP_ID"};
1526 Atom atoms[G_N_ELEMENTS(atom_names)(sizeof (atom_names) / sizeof ((atom_names)[0]))] = {0};
1527
1528 Atom type;
1529 int format, result;
1530 unsigned long nitems, after;
1531 unsigned char *data_root, *data_esetroot;
1532 GdkDisplay *gdkdisplay;
1533
1534 /* Get atoms for both properties in an array, only if they exist.
1535 * This method is to avoid multiple round-trips to Xserver
1536 */
1537 if (XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names)(sizeof (atom_names) / sizeof ((atom_names)[0])), True1, atoms) &&
1538 atoms[0] != None0L && atoms[1] != None0L) {
1539 result = XGetWindowProperty (display, xroot, atoms[0], 0L, 1L,
1540 False0, AnyPropertyType0L,
1541 &type, &format, &nitems, &after,
1542 &data_root);
1543
1544 if (data_root != NULL((void*)0) && result == Success0 &&
1545 type == XA_PIXMAP((Atom) 20) && format == 32 && nitems == 1) {
1546 result = XGetWindowProperty (display, xroot, atoms[1],
1547 0L, 1L, False0,
1548 AnyPropertyType0L,
1549 &type, &format, &nitems,
1550 &after, &data_esetroot);
1551
1552 if (data_esetroot != NULL((void*)0) && result == Success0 &&
1553 type == XA_PIXMAP((Atom) 20) && format == 32 && nitems == 1) {
1554 Pixmap xrootpmap = *((Pixmap *) data_root);
1555 Pixmap esetrootpmap = *((Pixmap *) data_esetroot);
1556
1557 gdkdisplay = gdk_screen_get_display (screen);
1558 gdk_x11_display_error_trap_push (gdkdisplay);
1559 if (xrootpmap && xrootpmap == esetrootpmap) {
1560 XKillClient (display, xrootpmap);
1561 }
1562 if (esetrootpmap && esetrootpmap != xrootpmap) {
1563 XKillClient (display, esetrootpmap);
1564 }
1565 gdk_x11_display_error_trap_pop_ignored (gdkdisplay);
1566 }
1567 if (data_esetroot != NULL((void*)0)) {
1568 XFree (data_esetroot);
1569 }
1570 }
1571 if (data_root != NULL((void*)0)) {
1572 XFree (data_root);
1573 }
1574 }
1575
1576 /* Get atoms for both properties in an array, create them if needed.
1577 * This method is to avoid multiple round-trips to Xserver
1578 */
1579 if (!XInternAtoms (display, atom_names, G_N_ELEMENTS(atom_names)(sizeof (atom_names) / sizeof ((atom_names)[0])), False0, atoms) ||
1580 atoms[0] == None0L || atoms[1] == None0L) {
1581 g_warning ("Could not create atoms needed to set root pixmap id/properties.\n");
1582 return;
1583 }
1584
1585 /* Set new _XROOTMAP_ID and ESETROOT_PMAP_ID properties */
1586 XChangeProperty (display, xroot, atoms[0], XA_PIXMAP((Atom) 20), 32,
1587 PropModeReplace0, (unsigned char *) &xpixmap, 1);
1588
1589 XChangeProperty (display, xroot, atoms[1], XA_PIXMAP((Atom) 20), 32,
1590 PropModeReplace0, (unsigned char *) &xpixmap, 1);
1591}
1592
1593/**
1594 * mate_bg_set_surface_as_root:
1595 * @screen: the #GdkScreen to change root background on
1596 * @surface: the #cairo_surface_t to set root background from.
1597 * Must be an xlib surface backing a pixmap.
1598 *
1599 * Set the root pixmap, and properties pointing to it. We
1600 * do this atomically with a server grab to make sure that
1601 * we won't leak the pixmap if somebody else it setting
1602 * it at the same time. (This assumes that they follow the
1603 * same conventions we do). @surface should come from a call
1604 * to mate_bg_create_surface().
1605 **/
1606void
1607mate_bg_set_surface_as_root (GdkScreen *screen, cairo_surface_t *surface)
1608{
1609 g_return_if_fail (screen != NULL)do { if ((screen != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "screen != NULL"
); return; } } while (0)
;
1610 g_return_if_fail (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)do { if ((cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB
)) { } else { g_return_if_fail_warning ("MateDesktop", ((const
char*) (__func__)), "cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB"
); return; } } while (0)
;
1611
1612 /* Desktop background pixmap should be created from dummy X client since most
1613 * applications will try to kill it with XKillClient later when changing pixmap
1614 */
1615 Display *display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen))(gdk_x11_display_get_xdisplay (gdk_screen_get_display (screen
)))
;
1616 Pixmap pixmap_id = cairo_xlib_surface_get_drawable (surface);
1617 Window xroot = RootWindow (display, gdk_x11_screen_get_screen_number (screen))((&((_XPrivDisplay)(display))->screens[gdk_x11_screen_get_screen_number
(screen)])->root)
;
1618
1619 XGrabServer (display);
1620 mate_bg_set_root_pixmap_id (screen, display, pixmap_id);
1621
1622 XSetWindowBackgroundPixmap (display, xroot, pixmap_id);
1623 XClearWindow (display, xroot);
1624
1625 XFlush (display);
1626 XUngrabServer (display);
1627}
1628
1629/**
1630 * mate_bg_set_surface_as_root_with_crossfade:
1631 * @screen: the #GdkScreen to change root background on
1632 * @surface: the cairo xlib surface to set root background from
1633 *
1634 * Set the root pixmap, and properties pointing to it.
1635 * This function differs from mate_bg_set_surface_as_root()
1636 * in that it adds a subtle crossfade animation from the
1637 * current root pixmap to the new one.
1638 *
1639 * Return value: (transfer full): a #MateBGCrossfade object
1640 **/
1641MateBGCrossfade *
1642mate_bg_set_surface_as_root_with_crossfade (GdkScreen *screen,
1643 cairo_surface_t *surface)
1644{
1645 GdkWindow *root_window;
1646 int width, height;
1647 MateBGCrossfade *fade;
1648 cairo_t *cr;
1649 cairo_surface_t *old_surface;
1650
1651 g_return_val_if_fail (screen != NULL, NULL)do { if ((screen != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "screen != NULL"
); return (((void*)0)); } } while (0)
;
1652 g_return_val_if_fail (surface != NULL, NULL)do { if ((surface != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "surface != NULL"
); return (((void*)0)); } } while (0)
;
1653
1654 root_window = gdk_screen_get_root_window (screen);
1655 width = gdk_window_get_width (root_window);
1656 height = gdk_window_get_height (root_window);
1657 fade = mate_bg_crossfade_new (width, height);
1658 old_surface = mate_bg_get_surface_from_root (screen);
1659
1660 mate_bg_crossfade_set_start_surface (fade, old_surface);
1661 mate_bg_crossfade_set_end_surface (fade, surface);
1662
1663 /* Before setting the surface as a root pixmap, let's have it draw
1664 * the old stuff, just so it won't be noticable
1665 * (crossfade will later get it back)
1666 */
1667 cr = cairo_create (surface);
1668 cairo_set_source_surface (cr, old_surface, 0, 0);
1669 cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
1670 cairo_paint (cr);
1671 cairo_destroy (cr);
1672 cairo_surface_destroy (old_surface);
1673
1674 mate_bg_set_surface_as_root (screen, surface);
1675 mate_bg_crossfade_start (fade, root_window);
1676
1677 return fade;
1678}
1679
1680/* Implementation of the pixbuf cache */
1681struct _SlideShow
1682{
1683 gint ref_count;
1684 double start_time;
1685 double total_duration;
1686
1687 GQueue *slides;
1688
1689 gboolean has_multiple_sizes;
1690
1691 /* used during parsing */
1692 struct tm start_tm;
1693 GQueue *stack;
1694};
1695
1696#if GLIB_CHECK_VERSION(2,61,2)(2 > (2) || (2 == (2) && 78 > (61)) || (2 == (2
) && 78 == (61) && 3 >= (2)))
1697static double
1698now (void)
1699{
1700 const double microseconds_per_second = (double) G_USEC_PER_SEC1000000;
1701 gint64 tv;
1702
1703 tv = g_get_real_time ();
1704
1705 return (double) (tv / microseconds_per_second);
1706}
1707#else
1708static double
1709now (void)
1710{
1711 const double microseconds_per_second = (double) G_USEC_PER_SEC1000000;
1712 GTimeVal tv;
1713
1714 g_get_current_time (&tv);
1715
1716 return (double)tv.tv_sec + (tv.tv_usec / microseconds_per_second);
1717}
1718#endif
1719
1720static Slide *
1721get_current_slide (SlideShow *show,
1722 double *alpha)
1723{
1724 double delta = fmod (now() - show->start_time, show->total_duration);
1725 GList *list;
1726 double elapsed;
1727 int i;
1728
1729 if (delta < 0)
1730 delta += show->total_duration;
1731
1732 elapsed = 0;
1733 i = 0;
1734 for (list = show->slides->head; list != NULL((void*)0); list = list->next) {
1735 Slide *slide = list->data;
1736
1737 if (elapsed + slide->duration > delta) {
1738 if (alpha)
1739 *alpha = (delta - elapsed) / (double)slide->duration;
1740 return slide;
1741 }
1742
1743 i++;
1744 elapsed += slide->duration;
1745 }
1746
1747 /* this should never happen since we have slides and we should always
1748 * find a current slide for the elapsed time since beginning -- we're
1749 * looping with fmod() */
1750 g_assert_not_reached ()do { g_assertion_message_expr ("MateDesktop", "mate-bg.c", 1750
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1751
1752 return NULL((void*)0);
1753}
1754
1755static GdkPixbuf *
1756blend (GdkPixbuf *p1,
1757 GdkPixbuf *p2,
1758 double alpha)
1759{
1760 GdkPixbuf *result = gdk_pixbuf_copy (p1);
1761 GdkPixbuf *tmp;
1762
1763 if (gdk_pixbuf_get_width (p2) != gdk_pixbuf_get_width (p1) ||
1764 gdk_pixbuf_get_height (p2) != gdk_pixbuf_get_height (p1)) {
1765 tmp = gdk_pixbuf_scale_simple (p2,
1766 gdk_pixbuf_get_width (p1),
1767 gdk_pixbuf_get_height (p1),
1768 GDK_INTERP_BILINEAR);
1769 }
1770 else {
1771 tmp = g_object_ref (p2)((__typeof__ (p2)) (g_object_ref) (p2));
1772 }
1773
1774 pixbuf_blend (tmp, result, 0, 0, -1, -1, 0, 0, alpha);
1775
1776 g_object_unref (tmp);
1777
1778 return result;
1779}
1780
1781typedef enum {
1782 PIXBUF,
1783 SLIDESHOW,
1784 THUMBNAIL
1785} FileType;
1786
1787struct FileCacheEntry
1788{
1789 FileType type;
1790 char *filename;
1791 union {
1792 GdkPixbuf *pixbuf;
1793 SlideShow *slideshow;
1794 GdkPixbuf *thumbnail;
1795 } u;
1796};
1797
1798static void
1799file_cache_entry_delete (FileCacheEntry *ent)
1800{
1801 g_free (ent->filename);
1802
1803 switch (ent->type) {
1804 case PIXBUF:
1805 g_object_unref (ent->u.pixbuf);
1806 break;
1807 case SLIDESHOW:
1808 slideshow_unref (ent->u.slideshow);
1809 break;
1810 case THUMBNAIL:
1811 g_object_unref (ent->u.thumbnail);
1812 break;
1813 }
1814
1815 g_free (ent);
1816}
1817
1818static void
1819bound_cache (MateBG *bg)
1820{
1821 while (g_list_length (bg->file_cache) >= CACHE_SIZE4) {
1822 GList *last_link = g_list_last (bg->file_cache);
1823 FileCacheEntry *ent = last_link->data;
1824
1825 file_cache_entry_delete (ent);
1826
1827 bg->file_cache = g_list_delete_link (bg->file_cache, last_link);
1828 }
1829}
1830
1831static const FileCacheEntry *
1832file_cache_lookup (MateBG *bg, FileType type, const char *filename)
1833{
1834 GList *list;
1835
1836 for (list = bg->file_cache; list != NULL((void*)0); list = list->next) {
1837 FileCacheEntry *ent = list->data;
1838
1839 if (ent && ent->type == type &&
1840 strcmp (ent->filename, filename) == 0) {
1841 return ent;
1842 }
1843 }
1844
1845 return NULL((void*)0);
1846}
1847
1848static FileCacheEntry *
1849file_cache_entry_new (MateBG *bg,
1850 FileType type,
1851 const char *filename)
1852{
1853 FileCacheEntry *ent = g_new0 (FileCacheEntry, 1)((FileCacheEntry *) g_malloc0_n ((1), sizeof (FileCacheEntry)
))
;
1854
1855 g_assert (!file_cache_lookup (bg, type, filename))do { if (!file_cache_lookup (bg, type, filename)) ; else g_assertion_message_expr
("MateDesktop", "mate-bg.c", 1855, ((const char*) (__func__)
), "!file_cache_lookup (bg, type, filename)"); } while (0)
;
1856
1857 ent->type = type;
1858 ent->filename = g_strdup (filename)g_strdup_inline (filename);
1859
1860 bg->file_cache = g_list_prepend (bg->file_cache, ent);
1861
1862 bound_cache (bg);
1863
1864 return ent;
1865}
1866
1867static void
1868file_cache_add_pixbuf (MateBG *bg,
1869 const char *filename,
1870 GdkPixbuf *pixbuf)
1871{
1872 FileCacheEntry *ent = file_cache_entry_new (bg, PIXBUF, filename);
1873 ent->u.pixbuf = g_object_ref (pixbuf)((__typeof__ (pixbuf)) (g_object_ref) (pixbuf));
1874}
1875
1876static void
1877file_cache_add_thumbnail (MateBG *bg,
1878 const char *filename,
1879 GdkPixbuf *pixbuf)
1880{
1881 FileCacheEntry *ent = file_cache_entry_new (bg, THUMBNAIL, filename);
1882 ent->u.thumbnail = g_object_ref (pixbuf)((__typeof__ (pixbuf)) (g_object_ref) (pixbuf));
1883}
1884
1885static void
1886file_cache_add_slide_show (MateBG *bg,
1887 const char *filename,
1888 SlideShow *show)
1889{
1890 FileCacheEntry *ent = file_cache_entry_new (bg, SLIDESHOW, filename);
1891 ent->u.slideshow = slideshow_ref (show);
1892}
1893
1894static GdkPixbuf *
1895load_from_cache_file (MateBG *bg,
1896 const char *filename,
1897 gint num_monitor,
1898 gint best_width,
1899 gint best_height)
1900{
1901 GdkPixbuf *pixbuf = NULL((void*)0);
1902 gchar *cache_filename;
1903
1904 cache_filename = get_wallpaper_cache_filename (filename, num_monitor, bg->placement,
1905 best_width, best_height);
1906
1907 if (cache_file_is_valid (filename, cache_filename))
1908 pixbuf = gdk_pixbuf_new_from_file (cache_filename, NULL((void*)0));
1909
1910 g_free (cache_filename);
1911
1912 return pixbuf;
1913}
1914
1915static GdkPixbuf *
1916get_as_pixbuf_for_size (MateBG *bg,
1917 const char *filename,
1918 gint monitor,
1919 gint best_width,
1920 gint best_height)
1921{
1922 const FileCacheEntry *ent;
1923 if ((ent = file_cache_lookup (bg, PIXBUF, filename))) {
1924 return g_object_ref (ent->u.pixbuf)((__typeof__ (ent->u.pixbuf)) (g_object_ref) (ent->u.pixbuf
))
;
1925 } else {
1926 GdkPixbufFormat *format;
1927 GdkPixbuf *pixbuf = NULL((void*)0);
1928 gchar *tmp = NULL((void*)0);
1929 GdkPixbuf *tmp_pixbuf;
1930
1931 /* Try to hit local cache first if relevant */
1932 if (monitor != -1)
1933 pixbuf = load_from_cache_file (bg, filename, monitor,
1934 best_width, best_height);
1935
1936 if (!pixbuf) {
1937 /* If scalable choose maximum size */
1938 format = gdk_pixbuf_get_file_info (filename, NULL((void*)0), NULL((void*)0));
1939 if (format != NULL((void*)0))
1940 tmp = gdk_pixbuf_format_get_name (format);
1941
1942 if (g_strcmp0 (tmp, "svg") == 0 &&
1943 (best_width > 0 && best_height > 0) &&
1944 (bg->placement == MATE_BG_PLACEMENT_FILL_SCREEN ||
1945 bg->placement == MATE_BG_PLACEMENT_SCALED ||
1946 bg->placement == MATE_BG_PLACEMENT_ZOOMED))
1947 {
1948 pixbuf = gdk_pixbuf_new_from_file_at_size (filename,
1949 best_width,
1950 best_height, NULL((void*)0));
1951 } else {
1952 pixbuf = gdk_pixbuf_new_from_file (filename, NULL((void*)0));
1953 }
1954
1955 if (tmp != NULL((void*)0))
1956 g_free (tmp);
1957 }
1958
1959 if (pixbuf) {
1960 tmp_pixbuf = gdk_pixbuf_apply_embedded_orientation (pixbuf);
1961 g_object_unref (pixbuf);
1962 pixbuf = tmp_pixbuf;
1963 file_cache_add_pixbuf (bg, filename, pixbuf);
1964 }
1965
1966 return pixbuf;
1967 }
1968}
1969
1970static SlideShow *
1971get_as_slideshow (MateBG *bg, const char *filename)
1972{
1973 const FileCacheEntry *ent;
1974 if ((ent = file_cache_lookup (bg, SLIDESHOW, filename))) {
5
Assuming 'ent' is null
6
Taking false branch
46
Assuming 'ent' is non-null
47
Taking true branch
1975 return slideshow_ref (ent->u.slideshow);
48
Returning pointer, which participates in a condition later
1976 }
1977 else {
1978 SlideShow *show = read_slideshow_file (filename, NULL((void*)0));
7
Calling 'read_slideshow_file'
22
Returning from 'read_slideshow_file'
1979
1980 if (show
22.1
'show' is non-null
)
23
Taking true branch
1981 file_cache_add_slide_show (bg, filename, show);
1982
1983 return show;
1984 }
1985}
1986
1987static GdkPixbuf *
1988get_as_thumbnail (MateBG *bg, MateDesktopThumbnailFactory *factory, const char *filename)
1989{
1990 const FileCacheEntry *ent;
1991 if ((ent = file_cache_lookup (bg, THUMBNAIL, filename))) {
39
Assuming 'ent' is non-null
40
Taking true branch
56
Assuming 'ent' is non-null
57
Taking true branch
61
Assuming 'ent' is non-null
62
Taking true branch
1992 return g_object_ref (ent->u.thumbnail)((__typeof__ (ent->u.thumbnail)) (g_object_ref) (ent->u
.thumbnail))
;
41
Returning pointer, which participates in a condition later
58
Returning pointer, which participates in a condition later
63
Returning pointer, which participates in a condition later
1993 }
1994 else {
1995 GdkPixbuf *thumb = create_thumbnail_for_filename (factory, filename);
1996
1997 if (thumb)
1998 file_cache_add_thumbnail (bg, filename, thumb);
1999
2000 return thumb;
2001 }
2002}
2003
2004static gboolean
2005blow_expensive_caches (gpointer data)
2006{
2007 MateBG *bg = data;
2008 GList *list, *next;
2009
2010 bg->blow_caches_id = 0;
2011
2012 for (list = bg->file_cache; list != NULL((void*)0); list = next) {
2013 FileCacheEntry *ent = list->data;
2014 next = list->next;
2015
2016 if (ent->type == PIXBUF) {
2017 file_cache_entry_delete (ent);
2018 bg->file_cache = g_list_delete_link (bg->file_cache,
2019 list);
2020 }
2021 }
2022
2023 if (bg->pixbuf_cache) {
2024 g_object_unref (bg->pixbuf_cache);
2025 bg->pixbuf_cache = NULL((void*)0);
2026 }
2027
2028 return FALSE(0);
2029}
2030
2031static void
2032blow_expensive_caches_in_idle (MateBG *bg)
2033{
2034 if (bg->blow_caches_id == 0) {
2035 bg->blow_caches_id =
2036 g_idle_add (blow_expensive_caches,
2037 bg);
2038 }
2039}
2040
2041static gboolean
2042on_timeout (gpointer data)
2043{
2044 MateBG *bg = data;
2045
2046 bg->timeout_id = 0;
2047
2048 queue_transitioned (bg);
2049
2050 return FALSE(0);
2051}
2052
2053static double
2054get_slide_timeout (Slide *slide)
2055{
2056 double timeout;
2057 if (slide->fixed) {
2058 timeout = slide->duration;
2059 } else {
2060 /* Maybe the number of steps should be configurable? */
2061
2062 /* In the worst case we will do a fade from 0 to 256, which mean
2063 * we will never use more than 255 steps, however in most cases
2064 * the first and last value are similar and users can't percieve
2065 * changes in pixel values as small as 1/255th. So, lets not waste
2066 * CPU cycles on transitioning to often.
2067 *
2068 * 64 steps is enough for each step to be just detectable in a 16bit
2069 * color mode in the worst case, so we'll use this as an approximation
2070 * of whats detectable.
2071 */
2072 timeout = slide->duration / 64.0;
2073 }
2074 return timeout;
2075}
2076
2077static void
2078ensure_timeout (MateBG *bg,
2079 Slide *slide)
2080{
2081 if (!bg->timeout_id) {
2082 double timeout = get_slide_timeout (slide);
2083
2084 /* G_MAXUINT means "only one slide" */
2085 if (timeout < G_MAXUINT(2147483647 *2U +1U)) {
2086 bg->timeout_id = g_timeout_add_full (
2087 G_PRIORITY_LOW300,
2088 timeout * 1000, on_timeout, bg, NULL((void*)0));
2089 }
2090
2091 }
2092}
2093
2094static gint64
2095get_mtime (const char *filename)
2096{
2097 GFile *file;
2098 GFileInfo *info;
2099 gint64 mtime = (gint64)-1;
2100
2101 if (filename) {
2102 file = g_file_new_for_path (filename);
2103 info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified",
2104 G_FILE_QUERY_INFO_NONE, NULL((void*)0), NULL((void*)0));
2105 if (info) {
2106 mtime = g_file_info_get_attribute_uint64 (info,
2107 G_FILE_ATTRIBUTE_TIME_MODIFIED"time::modified");
2108 g_object_unref (info);
2109 }
2110 g_object_unref (file);
2111 }
2112
2113 return mtime;
2114}
2115
2116static GdkPixbuf *
2117scale_thumbnail (MateBGPlacement placement,
2118 const char *filename,
2119 GdkPixbuf *thumb,
2120 GdkScreen *screen,
2121 int dest_width,
2122 int dest_height)
2123{
2124 int o_width;
2125 int o_height;
2126
2127 if (placement != MATE_BG_PLACEMENT_TILED &&
2128 placement != MATE_BG_PLACEMENT_CENTERED) {
2129
2130 /* In this case, the pixbuf will be scaled to fit the screen anyway,
2131 * so just return the pixbuf here
2132 */
2133 return g_object_ref (thumb)((__typeof__ (thumb)) (g_object_ref) (thumb));
2134 }
2135
2136 if (get_thumb_annotations (thumb, &o_width, &o_height) ||
2137 (filename && get_original_size (filename, &o_width, &o_height))) {
2138 GdkDisplay *display;
2139 int scr_height;
2140 int scr_width;
2141
2142 display = gdk_screen_get_display (screen);
2143
2144 /*Since we can use this in wayland, only use x11 specific code when in x11*/
2145 if (GDK_IS_X11_DISPLAY (gdk_screen_get_display (screen))(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(gdk_screen_get_display (screen))); GType __t = ((gdk_x11_display_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
)
2146 {
2147 scr_height = HeightOfScreen (gdk_x11_screen_get_xscreen (screen))((gdk_x11_screen_get_xscreen (screen))->height);
2148 scr_width = WidthOfScreen (gdk_x11_screen_get_xscreen (screen))((gdk_x11_screen_get_xscreen (screen))->width);
2149 }
2150 else
2151 {
2152 GdkRectangle geometry = {0};
2153 GdkMonitor *monitor;
2154 monitor = gdk_display_get_monitor (display, 0);
2155 gdk_monitor_get_geometry (monitor, &geometry);
2156 scr_height = geometry.width;
2157 scr_width = geometry.height;
2158 }
2159 int thumb_width = gdk_pixbuf_get_width (thumb);
2160 int thumb_height = gdk_pixbuf_get_height (thumb);
2161 double screen_to_dest = fit_factor (scr_width, scr_height,
2162 dest_width, dest_height);
2163 double thumb_to_orig = fit_factor (thumb_width, thumb_height,
2164 o_width, o_height);
2165 double f = thumb_to_orig * screen_to_dest;
2166 int new_width, new_height;
2167
2168 new_width = floor (thumb_width * f + 0.5);
2169 new_height = floor (thumb_height * f + 0.5);
2170
2171 if (placement == MATE_BG_PLACEMENT_TILED) {
2172 /* Heuristic to make sure tiles don't become so small that
2173 * they turn into a blur.
2174 *
2175 * This is strictly speaking incorrect, but the resulting
2176 * thumbnail gives a much better idea what the background
2177 * will actually look like.
2178 */
2179
2180 if ((new_width < 32 || new_height < 32) &&
2181 (new_width < o_width / 4 || new_height < o_height / 4)) {
2182 new_width = o_width / 4;
2183 new_height = o_height / 4;
2184 }
2185 }
2186
2187 thumb = gdk_pixbuf_scale_simple (thumb, new_width, new_height,
2188 GDK_INTERP_BILINEAR);
2189 }
2190 else
2191 g_object_ref (thumb)((__typeof__ (thumb)) (g_object_ref) (thumb));
2192
2193 return thumb;
2194}
2195
2196/* frame_num determines which slide to thumbnail.
2197 * -1 means 'current slide'.
2198 */
2199static GdkPixbuf *
2200create_img_thumbnail (MateBG *bg,
2201 MateDesktopThumbnailFactory *factory,
2202 GdkScreen *screen,
2203 int dest_width,
2204 int dest_height,
2205 int frame_num)
2206{
2207 if (bg->filename
36.1
Field 'filename' is non-null
) {
37
Taking true branch
2208 GdkPixbuf *thumb;
2209
2210 thumb = get_as_thumbnail (bg, factory, bg->filename);
38
Calling 'get_as_thumbnail'
42
Returning from 'get_as_thumbnail'
2211
2212 if (thumb) {
43
Assuming 'thumb' is null
44
Taking false branch
2213 GdkPixbuf *result;
2214 result = scale_thumbnail (bg->placement,
2215 bg->filename,
2216 thumb,
2217 screen,
2218 dest_width,
2219 dest_height);
2220 g_object_unref (thumb);
2221 return result;
2222 }
2223 else {
2224 SlideShow *show = get_as_slideshow (bg, bg->filename);
45
Calling 'get_as_slideshow'
49
Returning from 'get_as_slideshow'
2225
2226 if (show
49.1
'show' is non-null
) {
50
Taking true branch
2227 double alpha;
51
'alpha' declared without an initial value
2228 Slide *slide;
2229
2230 if (frame_num == -1)
52
Taking false branch
2231 slide = get_current_slide (show, &alpha);
2232 else
2233 slide = g_queue_peek_nth (show->slides, frame_num);
2234
2235 if (slide->fixed) {
53
Assuming field 'fixed' is 0
54
Taking false branch
2236 GdkPixbuf *tmp;
2237 FileSize *fs;
2238 fs = find_best_size (slide->file1, dest_width, dest_height);
2239 tmp = get_as_thumbnail (bg, factory, fs->file);
2240 if (tmp) {
2241 thumb = scale_thumbnail (bg->placement,
2242 fs->file,
2243 tmp,
2244 screen,
2245 dest_width,
2246 dest_height);
2247 g_object_unref (tmp);
2248 }
2249 }
2250 else {
2251 FileSize *fs1, *fs2;
2252 GdkPixbuf *p1, *p2;
2253 fs1 = find_best_size (slide->file1, dest_width, dest_height);
2254 p1 = get_as_thumbnail (bg, factory, fs1->file);
55
Calling 'get_as_thumbnail'
59
Returning from 'get_as_thumbnail'
2255
2256 fs2 = find_best_size (slide->file2, dest_width, dest_height);
2257 p2 = get_as_thumbnail (bg, factory, fs2->file);
60
Calling 'get_as_thumbnail'
64
Returning from 'get_as_thumbnail'
2258
2259 if (p1 && p2) {
65
Assuming 'p1' is non-null
66
Assuming 'p2' is non-null
67
Taking true branch
2260 GdkPixbuf *thumb1, *thumb2;
2261
2262 thumb1 = scale_thumbnail (bg->placement,
2263 fs1->file,
2264 p1,
2265 screen,
2266 dest_width,
2267 dest_height);
2268
2269 thumb2 = scale_thumbnail (bg->placement,
2270 fs2->file,
2271 p2,
2272 screen,
2273 dest_width,
2274 dest_height);
2275
2276 thumb = blend (thumb1, thumb2, alpha);
68
3rd function call argument is an uninitialized value
2277
2278 g_object_unref (thumb1);
2279 g_object_unref (thumb2);
2280 }
2281 if (p1)
2282 g_object_unref (p1);
2283 if (p2)
2284 g_object_unref (p2);
2285 }
2286
2287 ensure_timeout (bg, slide);
2288
2289 slideshow_unref (show);
2290 }
2291 }
2292
2293 return thumb;
2294 }
2295
2296 return NULL((void*)0);
2297}
2298
2299/*
2300 * Find the FileSize that best matches the given size.
2301 * Do two passes; the first pass only considers FileSizes
2302 * that are larger than the given size.
2303 * We are looking for the image that best matches the aspect ratio.
2304 * When two images have the same aspect ratio, prefer the one whose
2305 * width is closer to the given width.
2306 */
2307static FileSize *
2308find_best_size (GSList *sizes, gint width, gint height)
2309{
2310 GSList *s;
2311 gdouble a, d, distance;
2312 FileSize *best = NULL((void*)0);
2313 gint pass;
2314
2315 a = width/(gdouble)height;
2316 distance = 10000.0;
2317
2318 for (pass = 0; pass < 2; pass++) {
2319 for (s = sizes; s; s = s->next) {
2320 FileSize *size = s->data;
2321
2322 if (pass == 0 && (size->width < width || size->height < height))
2323 continue;
2324
2325 d = fabs (a - size->width/(gdouble)size->height);
2326 if (d < distance) {
2327 distance = d;
2328 best = size;
2329 }
2330 else if (d == distance) {
2331 if (best && (abs (size->width - width) < abs (best->width - width))) {
2332 best = size;
2333 }
2334 }
2335 }
2336
2337 if (best)
2338 break;
2339 }
2340
2341 return best;
2342}
2343
2344static GdkPixbuf *
2345get_pixbuf_for_size (MateBG *bg,
2346 gint monitor,
2347 gint best_width,
2348 gint best_height)
2349{
2350 guint time_until_next_change;
2351 gboolean hit_cache = FALSE(0);
2352
2353 /* only hit the cache if the aspect ratio matches */
2354 if (bg->pixbuf_cache) {
2355 int width, height;
2356 width = gdk_pixbuf_get_width (bg->pixbuf_cache);
2357 height = gdk_pixbuf_get_height (bg->pixbuf_cache);
2358 hit_cache = 0.2 > fabs ((best_width / (double)best_height) - (width / (double)height));
2359 if (!hit_cache) {
2360 g_object_unref (bg->pixbuf_cache);
2361 bg->pixbuf_cache = NULL((void*)0);
2362 }
2363 }
2364
2365 if (!hit_cache && bg->filename) {
2366 bg->file_mtime = get_mtime (bg->filename);
2367
2368 bg->pixbuf_cache = get_as_pixbuf_for_size (bg, bg->filename, monitor,
2369 best_width, best_height);
2370 time_until_next_change = G_MAXUINT(2147483647 *2U +1U);
2371 if (!bg->pixbuf_cache) {
2372 SlideShow *show = get_as_slideshow (bg, bg->filename);
2373
2374 if (show) {
2375 double alpha;
2376 double timeout;
2377 Slide *slide;
2378
2379 slideshow_ref (show);
2380
2381 slide = get_current_slide (show, &alpha);
2382 timeout = get_slide_timeout (slide);
2383 time_until_next_change = (guint) timeout;
2384 if (slide->fixed) {
2385 FileSize *size = find_best_size (slide->file1,
2386 best_width, best_height);
2387 bg->pixbuf_cache =
2388 get_as_pixbuf_for_size (bg, size->file, monitor,
2389 best_width, best_height);
2390 } else {
2391 FileSize *size;
2392 GdkPixbuf *p1, *p2;
2393
2394 size = find_best_size (slide->file1,
2395 best_width, best_height);
2396 p1 = get_as_pixbuf_for_size (bg, size->file, monitor,
2397 best_width, best_height);
2398
2399 size = find_best_size (slide->file2,
2400 best_width, best_height);
2401 p2 = get_as_pixbuf_for_size (bg, size->file, monitor,
2402 best_width, best_height);
2403
2404 if (p1 && p2)
2405 bg->pixbuf_cache = blend (p1, p2, alpha);
2406 if (p1)
2407 g_object_unref (p1);
2408 if (p2)
2409 g_object_unref (p2);
2410 }
2411
2412 ensure_timeout (bg, slide);
2413
2414 slideshow_unref (show);
2415 }
2416 }
2417
2418 /* If the next slideshow step is a long time away then
2419 we blow away the expensive stuff (large pixbufs) from
2420 the cache */
2421 if (time_until_next_change > KEEP_EXPENSIVE_CACHE_SECS60)
2422 blow_expensive_caches_in_idle (bg);
2423 }
2424
2425 if (bg->pixbuf_cache)
2426 g_object_ref (bg->pixbuf_cache)((__typeof__ (bg->pixbuf_cache)) (g_object_ref) (bg->pixbuf_cache
))
;
2427
2428 return bg->pixbuf_cache;
2429}
2430
2431static gboolean
2432is_different (MateBG *bg,
2433 const char *filename)
2434{
2435 if (!filename && bg->filename) {
2436 return TRUE(!(0));
2437 }
2438 else if (filename && !bg->filename) {
2439 return TRUE(!(0));
2440 }
2441 else if (!filename && !bg->filename) {
2442 return FALSE(0);
2443 }
2444 else {
2445 if (get_mtime (filename) != bg->file_mtime)
2446 return TRUE(!(0));
2447
2448 if (strcmp (filename, bg->filename) != 0)
2449 return TRUE(!(0));
2450
2451 return FALSE(0);
2452 }
2453}
2454
2455static void
2456clear_cache (MateBG *bg)
2457{
2458 GList *list;
2459
2460 if (bg->file_cache) {
2461 for (list = bg->file_cache; list != NULL((void*)0); list = list->next) {
2462 FileCacheEntry *ent = list->data;
2463
2464 file_cache_entry_delete (ent);
2465 }
2466 g_list_free (bg->file_cache);
2467 bg->file_cache = NULL((void*)0);
2468 }
2469
2470 if (bg->pixbuf_cache) {
2471 g_object_unref (bg->pixbuf_cache);
2472
2473 bg->pixbuf_cache = NULL((void*)0);
2474 }
2475
2476 if (bg->timeout_id) {
2477 g_source_remove (bg->timeout_id);
2478
2479 bg->timeout_id = 0;
2480 }
2481}
2482
2483/* Pixbuf utilities */
2484static void
2485pixbuf_average_value (GdkPixbuf *pixbuf,
2486 GdkRGBA *result)
2487{
2488 guint64 a_total, r_total, g_total, b_total;
2489 guint row, column;
2490 int row_stride;
2491 const guchar *pixels, *p;
2492 int r, g, b, a;
2493 guint64 dividend;
2494 guint width, height;
2495 gdouble dd;
2496
2497 width = gdk_pixbuf_get_width (pixbuf);
2498 height = gdk_pixbuf_get_height (pixbuf);
2499 row_stride = gdk_pixbuf_get_rowstride (pixbuf);
2500 pixels = gdk_pixbuf_get_pixels (pixbuf);
2501
2502 /* iterate through the pixbuf, counting up each component */
2503 a_total = 0;
2504 r_total = 0;
2505 g_total = 0;
2506 b_total = 0;
2507
2508 if (gdk_pixbuf_get_has_alpha (pixbuf)) {
2509 for (row = 0; row < height; row++) {
2510 p = pixels + (row * row_stride);
2511 for (column = 0; column < width; column++) {
2512 r = *p++;
2513 g = *p++;
2514 b = *p++;
2515 a = *p++;
2516
2517 a_total += a;
2518 r_total += r * a;
2519 g_total += g * a;
2520 b_total += b * a;
2521 }
2522 }
2523 dividend = height * width * 0xFF;
2524 a_total *= 0xFF;
2525 } else {
2526 for (row = 0; row < height; row++) {
2527 p = pixels + (row * row_stride);
2528 for (column = 0; column < width; column++) {
2529 r = *p++;
2530 g = *p++;
2531 b = *p++;
2532
2533 r_total += r;
2534 g_total += g;
2535 b_total += b;
2536 }
2537 }
2538 dividend = height * width;
2539 a_total = dividend * 0xFF;
2540 }
2541
2542 dd = dividend * 0xFF;
2543 result->alpha = a_total / dd;
2544 result->red = r_total / dd;
2545 result->green = g_total / dd;
2546 result->blue = b_total / dd;
2547}
2548
2549static GdkPixbuf *
2550pixbuf_scale_to_fit (GdkPixbuf *src, int max_width, int max_height)
2551{
2552 double factor;
2553 int src_width, src_height;
2554 int new_width, new_height;
2555
2556 src_width = gdk_pixbuf_get_width (src);
2557 src_height = gdk_pixbuf_get_height (src);
2558
2559 factor = MIN (max_width / (double) src_width, max_height / (double) src_height)(((max_width / (double) src_width) < (max_height / (double
) src_height)) ? (max_width / (double) src_width) : (max_height
/ (double) src_height))
;
2560
2561 new_width = floor (src_width * factor + 0.5);
2562 new_height = floor (src_height * factor + 0.5);
2563
2564 return gdk_pixbuf_scale_simple (src, new_width, new_height, GDK_INTERP_BILINEAR);
2565}
2566
2567static GdkPixbuf *
2568pixbuf_scale_to_min (GdkPixbuf *src, int min_width, int min_height)
2569{
2570 double factor;
2571 int src_width, src_height;
2572 int new_width, new_height;
2573 GdkPixbuf *dest;
2574
2575 src_width = gdk_pixbuf_get_width (src);
2576 src_height = gdk_pixbuf_get_height (src);
2577
2578 factor = MAX (min_width / (double) src_width, min_height / (double) src_height)(((min_width / (double) src_width) > (min_height / (double
) src_height)) ? (min_width / (double) src_width) : (min_height
/ (double) src_height))
;
2579
2580 new_width = floor (src_width * factor + 0.5);
2581 new_height = floor (src_height * factor + 0.5);
2582
2583 dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
2584 gdk_pixbuf_get_has_alpha (src),
2585 8, min_width, min_height);
2586 if (!dest)
2587 return NULL((void*)0);
2588
2589 /* crop the result */
2590 gdk_pixbuf_scale (src, dest,
2591 0, 0,
2592 min_width, min_height,
2593 (new_width - min_width) / -2,
2594 (new_height - min_height) / -2,
2595 factor,
2596 factor,
2597 GDK_INTERP_BILINEAR);
2598 return dest;
2599}
2600
2601static guchar *
2602create_gradient (const GdkRGBA *primary,
2603 const GdkRGBA *secondary,
2604 int n_pixels)
2605{
2606 guchar *result = g_malloc (n_pixels * 3);
2607 int i;
2608
2609 for (i = 0; i < n_pixels; ++i) {
2610 double ratio = (i + 0.5) / n_pixels;
2611
2612 result[3 * i + 0] = (guchar) ((primary->red * (1 - ratio) + secondary->red * ratio) * 0x100);
2613 result[3 * i + 1] = (guchar) ((primary->green * (1 - ratio) + secondary->green * ratio) * 0x100);
2614 result[3 * i + 2] = (guchar) ((primary->blue * (1 - ratio) + secondary->blue * ratio) * 0x100);
2615 }
2616
2617 return result;
2618}
2619
2620static void
2621pixbuf_draw_gradient (GdkPixbuf *pixbuf,
2622 gboolean horizontal,
2623 GdkRGBA *primary,
2624 GdkRGBA *secondary,
2625 GdkRectangle *rect)
2626{
2627 int width;
2628 int height;
2629 int rowstride;
2630 guchar *dst;
2631 int n_channels = 3;
2632
2633 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
2634 width = rect->width;
2635 height = rect->height;
2636 dst = gdk_pixbuf_get_pixels (pixbuf) + rect->x * n_channels + rowstride * rect->y;
2637
2638 if (horizontal) {
2639 guchar *gradient = create_gradient (primary, secondary, width);
2640 int copy_bytes_per_row = width * n_channels;
2641 int i;
2642
2643 for (i = 0; i < height; i++) {
2644 guchar *d;
2645 d = dst + rowstride * i;
2646 memcpy (d, gradient, copy_bytes_per_row);
2647 }
2648 g_free (gradient);
2649 } else {
2650 guchar *gb, *gradient;
2651 int i;
2652
2653 gradient = create_gradient (primary, secondary, height);
2654 for (i = 0; i < height; i++) {
2655 int j;
2656 guchar *d;
2657
2658 d = dst + rowstride * i;
2659 gb = gradient + n_channels * i;
2660 for (j = width; j > 0; j--) {
2661 int k;
2662
2663 for (k = 0; k < n_channels; k++) {
2664 *(d++) = gb[k];
2665 }
2666 }
2667 }
2668
2669 g_free (gradient);
2670 }
2671}
2672
2673static void
2674pixbuf_blend (GdkPixbuf *src,
2675 GdkPixbuf *dest,
2676 int src_x,
2677 int src_y,
2678 int src_width,
2679 int src_height,
2680 int dest_x,
2681 int dest_y,
2682 double alpha)
2683{
2684 int dest_width = gdk_pixbuf_get_width (dest);
2685 int dest_height = gdk_pixbuf_get_height (dest);
2686 int offset_x = dest_x - src_x;
2687 int offset_y = dest_y - src_y;
2688
2689 if (src_width < 0)
2690 src_width = gdk_pixbuf_get_width (src);
2691
2692 if (src_height < 0)
2693 src_height = gdk_pixbuf_get_height (src);
2694
2695 if (dest_x < 0)
2696 dest_x = 0;
2697
2698 if (dest_y < 0)
2699 dest_y = 0;
2700
2701 if (dest_x + src_width > dest_width) {
2702 src_width = dest_width - dest_x;
2703 }
2704
2705 if (dest_y + src_height > dest_height) {
2706 src_height = dest_height - dest_y;
2707 }
2708
2709 gdk_pixbuf_composite (src, dest,
2710 dest_x, dest_y,
2711 src_width, src_height,
2712 offset_x, offset_y,
2713 1, 1, GDK_INTERP_NEAREST,
2714 alpha * 0xFF + 0.5);
2715}
2716
2717static void
2718pixbuf_tile (GdkPixbuf *src, GdkPixbuf *dest)
2719{
2720 int x, y;
2721 int tile_width, tile_height;
2722 int dest_width = gdk_pixbuf_get_width (dest);
2723 int dest_height = gdk_pixbuf_get_height (dest);
2724
2725 tile_width = gdk_pixbuf_get_width (src);
2726 tile_height = gdk_pixbuf_get_height (src);
2727
2728 for (y = 0; y < dest_height; y += tile_height) {
2729 for (x = 0; x < dest_width; x += tile_width) {
2730 pixbuf_blend (src, dest, 0, 0,
2731 tile_width, tile_height, x, y, 1.0);
2732 }
2733 }
2734}
2735
2736static gboolean stack_is (SlideShow *parser, const char *s1, ...);
2737
2738/* Parser for fading background */
2739static void
2740handle_start_element (GMarkupParseContext *context,
2741 const gchar *name,
2742 const gchar **attr_names,
2743 const gchar **attr_values,
2744 gpointer user_data,
2745 GError **err)
2746{
2747 SlideShow *parser = user_data;
2748 gint i;
2749
2750 if (strcmp (name, "static") == 0 || strcmp (name, "transition") == 0) {
2751 Slide *slide = g_new0 (Slide, 1)((Slide *) g_malloc0_n ((1), sizeof (Slide)));
2752
2753 if (strcmp (name, "static") == 0)
2754 slide->fixed = TRUE(!(0));
2755
2756 g_queue_push_tail (parser->slides, slide);
2757 }
2758 else if (strcmp (name, "size") == 0) {
2759 Slide *slide = parser->slides->tail->data;
2760 FileSize *size = g_new0 (FileSize, 1)((FileSize *) g_malloc0_n ((1), sizeof (FileSize)));
2761 for (i = 0; attr_names[i]; i++) {
2762 if (strcmp (attr_names[i], "width") == 0)
2763 size->width = atoi (attr_values[i]);
2764 else if (strcmp (attr_names[i], "height") == 0)
2765 size->height = atoi (attr_values[i]);
2766 }
2767 if (parser->stack->tail &&
2768 (strcmp (parser->stack->tail->data, "file") == 0 ||
2769 strcmp (parser->stack->tail->data, "from") == 0)) {
2770 slide->file1 = g_slist_prepend (slide->file1, size);
2771 }
2772 else if (parser->stack->tail &&
2773 strcmp (parser->stack->tail->data, "to") == 0) {
2774 slide->file2 = g_slist_prepend (slide->file2, size);
2775 }
2776 else
2777 g_free (size);
2778 }
2779 g_queue_push_tail (parser->stack, g_strdup (name)g_strdup_inline (name));
2780}
2781
2782static void
2783handle_end_element (GMarkupParseContext *context,
2784 const gchar *name,
2785 gpointer user_data,
2786 GError **err)
2787{
2788 SlideShow *parser = user_data;
2789
2790 g_free (g_queue_pop_tail (parser->stack));
2791}
2792
2793static gboolean
2794stack_is (SlideShow *parser,
2795 const char *s1,
2796 ...)
2797{
2798 GList *stack = NULL((void*)0);
2799 const char *s;
2800 GList *l1, *l2;
2801 va_list args;
2802
2803 stack = g_list_prepend (stack, (gpointer)s1);
2804
2805 va_start (args, s1)__builtin_va_start(args, s1);
2806
2807 s = va_arg (args, const char *)__builtin_va_arg(args, const char *);
2808 while (s) {
2809 stack = g_list_prepend (stack, (gpointer)s);
2810 s = va_arg (args, const char *)__builtin_va_arg(args, const char *);
2811 }
2812
2813 va_end (args)__builtin_va_end(args);
2814
2815 l1 = stack;
2816 l2 = parser->stack->head;
2817
2818 while (l1 && l2) {
2819 if (strcmp (l1->data, l2->data) != 0) {
2820 g_list_free (stack);
2821 return FALSE(0);
2822 }
2823
2824 l1 = l1->next;
2825 l2 = l2->next;
2826 }
2827
2828 g_list_free (stack);
2829
2830 return (!l1 && !l2);
2831}
2832
2833static int
2834parse_int (const char *text)
2835{
2836 return strtol (text, NULL((void*)0), 0);
2837}
2838
2839static void
2840handle_text (GMarkupParseContext *context,
2841 const gchar *text,
2842 gsize text_len,
2843 gpointer user_data,
2844 GError **err)
2845{
2846 SlideShow *parser = user_data;
2847 FileSize *fs;
2848 gint i;
2849
2850 g_return_if_fail (parser != NULL)do { if ((parser != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "parser != NULL"
); return; } } while (0)
;
2851 g_return_if_fail (parser->slides != NULL)do { if ((parser->slides != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "parser->slides != NULL"
); return; } } while (0)
;
2852
2853 Slide *slide = parser->slides->tail ? parser->slides->tail->data : NULL((void*)0);
2854
2855 if (stack_is (parser, "year", "starttime", "background", NULL((void*)0))) {
2856 parser->start_tm.tm_year = parse_int (text) - 1900;
2857 }
2858 else if (stack_is (parser, "month", "starttime", "background", NULL((void*)0))) {
2859 parser->start_tm.tm_mon = parse_int (text) - 1;
2860 }
2861 else if (stack_is (parser, "day", "starttime", "background", NULL((void*)0))) {
2862 parser->start_tm.tm_mday = parse_int (text);
2863 }
2864 else if (stack_is (parser, "hour", "starttime", "background", NULL((void*)0))) {
2865 parser->start_tm.tm_hour = parse_int (text) - 1;
2866 }
2867 else if (stack_is (parser, "minute", "starttime", "background", NULL((void*)0))) {
2868 parser->start_tm.tm_min = parse_int (text);
2869 }
2870 else if (stack_is (parser, "second", "starttime", "background", NULL((void*)0))) {
2871 parser->start_tm.tm_sec = parse_int (text);
2872 }
2873 else if (stack_is (parser, "duration", "static", "background", NULL((void*)0)) ||
2874 stack_is (parser, "duration", "transition", "background", NULL((void*)0))) {
2875 g_return_if_fail (slide != NULL)do { if ((slide != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "slide != NULL")
; return; } } while (0)
;
2876
2877 slide->duration = g_strtod (text, NULL((void*)0));
2878 parser->total_duration += slide->duration;
2879 }
2880 else if (stack_is (parser, "file", "static", "background", NULL((void*)0)) ||
2881 stack_is (parser, "from", "transition", "background", NULL((void*)0))) {
2882 g_return_if_fail (slide != NULL)do { if ((slide != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "slide != NULL")
; return; } } while (0)
;
2883
2884 for (i = 0; text[i]; i++) {
2885 if (!g_ascii_isspace (text[i])((g_ascii_table[(guchar) (text[i])] & G_ASCII_SPACE) != 0
)
)
2886 break;
2887 }
2888 if (text[i] == 0)
2889 return;
2890 fs = g_new (FileSize, 1)((FileSize *) g_malloc_n ((1), sizeof (FileSize)));
2891 fs->width = -1;
2892 fs->height = -1;
2893 fs->file = g_strdup (text)g_strdup_inline (text);
2894 slide->file1 = g_slist_prepend (slide->file1, fs);
2895 if (slide->file1->next != NULL((void*)0))
2896 parser->has_multiple_sizes = TRUE(!(0));
2897 }
2898 else if (stack_is (parser, "size", "file", "static", "background", NULL((void*)0)) ||
2899 stack_is (parser, "size", "from", "transition", "background", NULL((void*)0))) {
2900 g_return_if_fail (slide != NULL)do { if ((slide != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "slide != NULL")
; return; } } while (0)
;
2901
2902 fs = slide->file1->data;
2903 fs->file = g_strdup (text)g_strdup_inline (text);
2904 if (slide->file1->next != NULL((void*)0))
2905 parser->has_multiple_sizes = TRUE(!(0));
2906 }
2907 else if (stack_is (parser, "to", "transition", "background", NULL((void*)0))) {
2908 g_return_if_fail (slide != NULL)do { if ((slide != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "slide != NULL")
; return; } } while (0)
;
2909
2910 for (i = 0; text[i]; i++) {
2911 if (!g_ascii_isspace (text[i])((g_ascii_table[(guchar) (text[i])] & G_ASCII_SPACE) != 0
)
)
2912 break;
2913 }
2914 if (text[i] == 0)
2915 return;
2916 fs = g_new (FileSize, 1)((FileSize *) g_malloc_n ((1), sizeof (FileSize)));
2917 fs->width = -1;
2918 fs->height = -1;
2919 fs->file = g_strdup (text)g_strdup_inline (text);
2920 slide->file2 = g_slist_prepend (slide->file2, fs);
2921 if (slide->file2->next != NULL((void*)0))
2922 parser->has_multiple_sizes = TRUE(!(0));
2923 }
2924 else if (stack_is (parser, "size", "to", "transition", "background", NULL((void*)0))) {
2925 g_return_if_fail (slide != NULL)do { if ((slide != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "slide != NULL")
; return; } } while (0)
;
2926
2927 fs = slide->file2->data;
2928 fs->file = g_strdup (text)g_strdup_inline (text);
2929 if (slide->file2->next != NULL((void*)0))
2930 parser->has_multiple_sizes = TRUE(!(0));
2931 }
2932}
2933
2934static SlideShow *
2935slideshow_ref (SlideShow *show)
2936{
2937 show->ref_count++;
2938 return show;
2939}
2940
2941static void
2942slideshow_unref (SlideShow *show)
2943{
2944 GList *list;
2945 GSList *slist;
2946 FileSize *size;
2947
2948 show->ref_count--;
2949 if (show->ref_count > 0)
2950 return;
2951
2952 for (list = show->slides->head; list != NULL((void*)0); list = list->next) {
2953 Slide *slide = list->data;
2954
2955 for (slist = slide->file1; slist != NULL((void*)0); slist = slist->next) {
2956 size = slist->data;
2957 g_free (size->file);
2958 g_free (size);
2959 }
2960 g_slist_free (slide->file1);
2961
2962 for (slist = slide->file2; slist != NULL((void*)0); slist = slist->next) {
2963 size = slist->data;
2964 g_free (size->file);
2965 g_free (size);
2966 }
2967 g_slist_free (slide->file2);
2968
2969 g_free (slide);
2970 }
2971
2972 g_queue_free (show->slides);
2973 g_queue_free_full (show->stack, g_free);
2974 g_free (show);
2975}
2976
2977static void
2978dump_bg (SlideShow *show)
2979{
2980#if 0
2981 GList *list;
2982 GSList *slist;
2983
2984 for (list = show->slides->head; list != NULL((void*)0); list = list->next)
2985 {
2986 Slide *slide = list->data;
2987
2988 g_print ("\nSlide: %s\n", slide->fixed? "fixed" : "transition");
2989 g_print ("duration: %f\n", slide->duration);
2990 g_print ("File1:\n");
2991 for (slist = slide->file1; slist != NULL((void*)0); slist = slist->next) {
2992 FileSize *size = slist->data;
2993 g_print ("\t%s (%dx%d)\n",
2994 size->file, size->width, size->height);
2995 }
2996 g_print ("File2:\n");
2997 for (slist = slide->file2; slist != NULL((void*)0); slist = slist->next) {
2998 FileSize *size = slist->data;
2999 g_print ("\t%s (%dx%d)\n",
3000 size->file, size->width, size->height);
3001 }
3002 }
3003#endif
3004}
3005
3006static void
3007threadsafe_localtime (time_t time, struct tm *tm)
3008{
3009 struct tm *res;
3010
3011 G_LOCK_DEFINE_STATIC (localtime_mutex)static GMutex g__localtime_mutex_lock;
3012
3013 G_LOCK (localtime_mutex)g_mutex_lock (&g__localtime_mutex_lock);
3014
3015 res = localtime (&time);
3016 if (tm) {
3017 *tm = *res;
3018 }
3019
3020 G_UNLOCK (localtime_mutex)g_mutex_unlock (&g__localtime_mutex_lock);
3021}
3022
3023static SlideShow *
3024read_slideshow_file (const char *filename,
3025 GError **err)
3026{
3027 GMarkupParser parser = {
3028 handle_start_element,
3029 handle_end_element,
3030 handle_text,
3031 NULL((void*)0), /* passthrough */
3032 NULL((void*)0), /* error */
3033 };
3034
3035 GFile *file;
3036 char *contents = NULL((void*)0);
3037 gsize len;
3038 SlideShow *show = NULL((void*)0);
3039 GMarkupParseContext *context = NULL((void*)0);
3040 time_t t;
3041
3042 if (!filename)
8
Assuming 'filename' is non-null
9
Taking false branch
3043 return NULL((void*)0);
3044
3045 file = g_file_new_for_path (filename);
3046 if (!g_file_load_contents (file, NULL((void*)0), &contents, &len, NULL((void*)0), NULL((void*)0))) {
10
Assuming the condition is false
11
Taking false branch
3047 g_object_unref (file);
3048 return NULL((void*)0);
3049 }
3050 g_object_unref (file);
3051
3052 show = g_new0 (SlideShow, 1)((SlideShow *) g_malloc0_n ((1), sizeof (SlideShow)));
3053 show->ref_count = 1;
3054 threadsafe_localtime ((time_t)0, &show->start_tm);
3055 show->stack = g_queue_new ();
3056 show->slides = g_queue_new ();
3057
3058 context = g_markup_parse_context_new (&parser, 0, show, NULL((void*)0));
3059
3060 if (!g_markup_parse_context_parse (context, contents, len, err)) {
12
Assuming the condition is false
13
Taking false branch
3061 slideshow_unref (show);
3062 show = NULL((void*)0);
3063 }
3064
3065 if (show
13.1
'show' is non-null
) {
14
Taking true branch
3066 if (!g_markup_parse_context_end_parse (context, err)) {
15
Assuming the condition is false
16
Taking false branch
3067 slideshow_unref (show);
3068 show = NULL((void*)0);
3069 }
3070 }
3071
3072 g_markup_parse_context_free (context);
3073
3074 if (show
16.1
'show' is non-null
) {
17
Taking true branch
3075 guint num_items;
3076
3077 t = mktime (&show->start_tm);
3078
3079 show->start_time = (double)t;
3080
3081 dump_bg (show);
3082
3083 num_items = g_queue_get_length (show->slides);
3084
3085 /* no slides, that's not a slideshow */
3086 if (num_items == 0) {
18
Assuming 'num_items' is not equal to 0
19
Taking false branch
3087 slideshow_unref (show);
3088 show = NULL((void*)0);
3089 /* one slide, there's no transition */
3090 } else if (num_items == 1) {
20
Assuming 'num_items' is not equal to 1
21
Taking false branch
3091 Slide *slide = show->slides->head->data;
3092 slide->duration = show->total_duration = G_MAXUINT(2147483647 *2U +1U);
3093 }
3094 }
3095
3096 g_free (contents);
3097
3098 return show;
3099}
3100
3101/* Thumbnail utilities */
3102static GdkPixbuf *
3103create_thumbnail_for_filename (MateDesktopThumbnailFactory *factory,
3104 const char *filename)
3105{
3106 char *thumb;
3107 gint64 mtime;
3108 GdkPixbuf *orig, *result = NULL((void*)0);
3109 char *uri;
3110
3111 mtime = get_mtime (filename);
3112 if (mtime == (gint64)-1)
3113 return NULL((void*)0);
3114
3115 uri = g_filename_to_uri (filename, NULL((void*)0), NULL((void*)0));
3116
3117 if (uri == NULL((void*)0))
3118 return NULL((void*)0);
3119
3120 thumb = mate_desktop_thumbnail_factory_lookup (factory, uri, mtime);
3121
3122 if (thumb) {
3123 result = gdk_pixbuf_new_from_file (thumb, NULL((void*)0));
3124 g_free (thumb);
3125 }
3126 else {
3127 orig = gdk_pixbuf_new_from_file (filename, NULL((void*)0));
3128 if (orig) {
3129 int orig_width = gdk_pixbuf_get_width (orig);
3130 int orig_height = gdk_pixbuf_get_height (orig);
3131
3132 result = pixbuf_scale_to_fit (orig, THUMBNAIL_SIZE256, THUMBNAIL_SIZE256);
3133
3134 g_object_set_data_full (G_OBJECT (result)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((result)), (((GType) ((20) << (2))))))))
, "mate-thumbnail-height",
3135 g_strdup_printf ("%d", orig_height), g_free);
3136 g_object_set_data_full (G_OBJECT (result)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((result)), (((GType) ((20) << (2))))))))
, "mate-thumbnail-width",
3137 g_strdup_printf ("%d", orig_width), g_free);
3138
3139 g_object_unref (orig);
3140
3141 mate_desktop_thumbnail_factory_save_thumbnail (factory, result, uri, mtime);
3142 }
3143 else {
3144 mate_desktop_thumbnail_factory_create_failed_thumbnail (factory, uri, mtime);
3145 }
3146 }
3147
3148 g_free (uri);
3149
3150 return result;
3151}
3152
3153static gboolean
3154get_thumb_annotations (GdkPixbuf *thumb,
3155 int *orig_width,
3156 int *orig_height)
3157{
3158 char *end;
3159 const char *wstr, *hstr;
3160
3161 wstr = gdk_pixbuf_get_option (thumb, "tEXt::Thumb::Image::Width");
3162 hstr = gdk_pixbuf_get_option (thumb, "tEXt::Thumb::Image::Height");
3163
3164 if (hstr && wstr) {
3165 *orig_width = strtol (wstr, &end, 10);
3166 if (*end != 0)
3167 return FALSE(0);
3168
3169 *orig_height = strtol (hstr, &end, 10);
3170 if (*end != 0)
3171 return FALSE(0);
3172
3173 return TRUE(!(0));
3174 }
3175
3176 return FALSE(0);
3177}
3178
3179static gboolean
3180slideshow_has_multiple_sizes (SlideShow *show)
3181{
3182 return show->has_multiple_sizes;
3183}
3184
3185/*
3186 * Returns whether the background is a slideshow.
3187 */
3188gboolean
3189mate_bg_changes_with_time (MateBG *bg)
3190{
3191 SlideShow *show;
3192
3193 g_return_val_if_fail (bg != NULL, FALSE)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
((0)); } } while (0)
;
3194
3195 if (!bg->filename)
3196 return FALSE(0);
3197
3198 if ((show = get_as_slideshow (bg, bg->filename)) != NULL((void*)0)) {
3199 gboolean result;
3200
3201 result = (g_queue_get_length (show->slides) > 1) ? TRUE(!(0)) : FALSE(0);
3202 slideshow_unref (show);
3203 return result;
3204 }
3205
3206 return FALSE(0);
3207}
3208
3209/**
3210 * mate_bg_create_frame_thumbnail:
3211 *
3212 * Creates a thumbnail for a certain frame, where 'frame' is somewhat
3213 * vaguely defined as 'suitable point to show while single-stepping
3214 * through the slideshow'.
3215 *
3216 * Returns: (transfer full): the newly created thumbnail or
3217 * or NULL if frame_num is out of bounds.
3218 */
3219GdkPixbuf *
3220mate_bg_create_frame_thumbnail (MateBG *bg,
3221 MateDesktopThumbnailFactory *factory,
3222 GdkScreen *screen,
3223 int dest_width,
3224 int dest_height,
3225 int frame_num)
3226{
3227 SlideShow *show;
3228 GdkPixbuf *result;
3229 GdkPixbuf *thumb;
3230 GList *l;
3231 int i, skipped;
3232 gboolean found;
3233
3234 g_return_val_if_fail (bg != NULL, FALSE)do { if ((bg != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "bg != NULL"); return
((0)); } } while (0)
;
1
Assuming 'bg' is not equal to null
2
Taking true branch
3
Loop condition is false. Exiting loop
3235
3236 show = get_as_slideshow (bg, bg->filename);
4
Calling 'get_as_slideshow'
24
Returning from 'get_as_slideshow'
3237
3238 if (!show
24.1
'show' is non-null
)
3239 return NULL((void*)0);
3240
3241 if (frame_num < 0 || (guint) frame_num >= g_queue_get_length (show->slides))
25
Assuming 'frame_num' is >= 0
26
Assuming the condition is false
27
Taking false branch
3242 return NULL((void*)0);
3243
3244 i = 0;
3245 skipped = 0;
3246 found = FALSE(0);
3247 for (l = show->slides->head; l; l = l->next) {
28
Loop condition is true. Entering loop body
3248 Slide *slide = l->data;
3249 if (!slide->fixed) {
29
Assuming field 'fixed' is not equal to 0
30
Taking false branch
3250 skipped++;
3251 continue;
3252 }
3253 if (i == frame_num) {
31
Assuming 'i' is equal to 'frame_num'
32
Taking true branch
3254 found = TRUE(!(0));
3255 break;
3256 }
3257 i++;
3258 }
3259 if (!found
33.1
'found' is 1
)
33
Execution continues on line 3259
34
Taking false branch
3260 return NULL((void*)0);
3261
3262 result = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE(0), 8, dest_width, dest_height);
3263
3264 draw_color (bg, result);
3265
3266 if (bg->filename
34.1
Field 'filename' is non-null
) {
35
Taking true branch
3267 thumb = create_img_thumbnail (bg, factory, screen,
36
Calling 'create_img_thumbnail'
3268 dest_width, dest_height,
3269 frame_num + skipped);
3270
3271 if (thumb) {
3272 draw_image_for_thumb (bg, thumb, result);
3273 g_object_unref (thumb);
3274 }
3275 }
3276
3277 return result;
3278}
3279
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-f4adeb.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-f4adeb.html new file mode 100644 index 0000000..0aca4d8 --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-f4adeb.html @@ -0,0 +1,2013 @@ + + + +mate-languages.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/mate-languages.c
Warning:line 1244, column 17
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mate-languages.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D HAVE_CONFIG_H -I . -I .. -I /usr/include/startup-notification-1.0 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /usr/include/dconf -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -D G_LOG_DOMAIN="MateDesktop" -D MATELOCALEDIR="/usr/share/locale" -D PNP_IDS="/usr/share/libmate-desktop/pnp.ids" -D ISO_CODES_PREFIX="/usr" -D PIC -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c mate-languages.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright 2008 Red Hat, Inc,
4 * 2007 William Jon McCann <mccann@jhu.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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 General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * Written by : William Jon McCann <mccann@jhu.edu>
20 * Ray Strode <rstrode@redhat.com>
21 */
22
23#include "config.h"
24
25#include <stdlib.h>
26#include <stdio.h>
27#include <unistd.h>
28#include <string.h>
29#include <errno(*__errno_location ()).h>
30#include <dirent.h>
31#include <locale.h>
32#include <langinfo.h>
33#include <sys/stat.h>
34
35#include <glib.h>
36#include <glib/gi18n.h>
37#include <glib/gstdio.h>
38
39#define MATE_DESKTOP_USE_UNSTABLE_API
40#include "mate-languages.h"
41
42#include <langinfo.h>
43#ifndef __LC_LAST13
44#define __LC_LAST13 13
45#endif
46
47#define ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" ISO_CODES_PREFIX"/usr" "/share/xml/iso-codes"
48#define ISO_CODES_LOCALESDIR"/usr" "/share/locale" ISO_CODES_PREFIX"/usr" "/share/locale"
49
50typedef struct _MateLocale {
51 char *id;
52 char *name;
53 char *language_code;
54 char *territory_code;
55 char *codeset;
56 char *modifier;
57} MateLocale;
58
59static GHashTable *mate_languages_map;
60static GHashTable *mate_territories_map;
61static GHashTable *mate_available_locales_map;
62static GHashTable *mate_language_count_map;
63static GHashTable *mate_territory_count_map;
64
65static char * construct_language_name (const char *language,
66 const char *territory,
67 const char *codeset,
68 const char *modifier);
69
70static gboolean language_name_is_valid (const char *language_name);
71
72static void
73mate_locale_free (MateLocale *locale)
74{
75 if (locale == NULL((void*)0)) {
76 return;
77 }
78
79 g_free (locale->id);
80 g_free (locale->name);
81 g_free (locale->codeset);
82 g_free (locale->modifier);
83 g_free (locale->language_code);
84 g_free (locale->territory_code);
85 g_free (locale);
86}
87
88static char *
89normalize_codeset (const char *codeset)
90{
91 if (codeset == NULL((void*)0))
92 return NULL((void*)0);
93
94 if (g_str_equal (codeset, "UTF-8")(strcmp ((const char *) (codeset), (const char *) ("UTF-8")) ==
0)
||
95 g_str_equal (codeset, "utf8")(strcmp ((const char *) (codeset), (const char *) ("utf8")) ==
0)
)
96 return g_strdup ("UTF-8")g_strdup_inline ("UTF-8");
97
98 return g_strdup (codeset)g_strdup_inline (codeset);
99}
100
101/**
102 * mate_parse_locale:
103 * @locale: a locale string
104 * @language_codep: (out) (allow-none) (transfer full): location to
105 * store the language code, or %NULL
106 * @country_codep: (out) (allow-none) (transfer full): location to
107 * store the country code, or %NULL
108 * @codesetp: (out) (allow-none) (transfer full): location to
109 * store the codeset, or %NULL
110 * @modifierp: (out) (allow-none) (transfer full): location to
111 * store the modifier, or %NULL
112 *
113 * Extracts the various components of a locale string of the form
114 * [language[_country][.codeset][@modifier]]. See
115 * http://en.wikipedia.org/wiki/Locale.
116 *
117 * Return value: %TRUE if parsing was successful.
118 *
119 * Since: 1.22
120 */
121gboolean
122mate_parse_locale (const char *locale,
123 char **language_codep,
124 char **country_codep,
125 char **codesetp,
126 char **modifierp)
127{
128 static GRegex *re = NULL((void*)0);
129 GMatchInfo *match_info;
130 gboolean res;
131 gchar *normalized_codeset = NULL((void*)0);
132 gchar *normalized_name = NULL((void*)0);
133 gboolean retval;
134
135 match_info = NULL((void*)0);
136 retval = FALSE(0);
137
138 if (re == NULL((void*)0)) {
139 GError *error = NULL((void*)0);
140 re = g_regex_new ("^(?P<language>[^_.@[:space:]]+)"
141 "(_(?P<territory>[[:upper:]]+))?"
142 "(\\.(?P<codeset>[-_0-9a-zA-Z]+))?"
143 "(@(?P<modifier>[[:ascii:]]+))?$",
144 0, 0, &error);
145 if (re == NULL((void*)0)) {
146 g_warning ("%s", error->message);
147 g_error_free (error);
148 goto out;
149 }
150 }
151
152 if (!g_regex_match (re, locale, 0, &match_info) ||
153 g_match_info_is_partial_match (match_info)) {
154 g_warning ("locale '%s' isn't valid\n", locale);
155 goto out;
156 }
157
158 res = g_match_info_matches (match_info);
159 if (! res) {
160 g_warning ("Unable to parse locale: %s", locale);
161 goto out;
162 }
163
164 retval = TRUE(!(0));
165
166 if (language_codep != NULL((void*)0)) {
167 *language_codep = g_match_info_fetch_named (match_info, "language");
168 }
169
170 if (country_codep != NULL((void*)0)) {
171 *country_codep = g_match_info_fetch_named (match_info, "territory");
172
173 if (*country_codep != NULL((void*)0) &&
174 *country_codep[0] == '\0') {
175 g_free (*country_codep);
176 *country_codep = NULL((void*)0);
177 }
178 }
179
180 if (codesetp != NULL((void*)0)) {
181 *codesetp = g_match_info_fetch_named (match_info, "codeset");
182
183 if (*codesetp != NULL((void*)0) &&
184 *codesetp[0] == '\0') {
185 g_free (*codesetp);
186 *codesetp = NULL((void*)0);
187 }
188 }
189
190 if (modifierp != NULL((void*)0)) {
191 *modifierp = g_match_info_fetch_named (match_info, "modifier");
192
193 if (*modifierp != NULL((void*)0) &&
194 *modifierp[0] == '\0') {
195 g_free (*modifierp);
196 *modifierp = NULL((void*)0);
197 }
198 }
199
200 if (codesetp != NULL((void*)0) && *codesetp != NULL((void*)0)) {
201 normalized_codeset = normalize_codeset (*codesetp);
202 normalized_name = construct_language_name (language_codep ? *language_codep : NULL((void*)0),
203 country_codep ? *country_codep : NULL((void*)0),
204 normalized_codeset,
205 modifierp ? *modifierp : NULL((void*)0));
206
207 if (language_name_is_valid (normalized_name)) {
208 g_free (*codesetp);
209 *codesetp = normalized_codeset;
210 } else {
211 g_free (normalized_codeset);
212 }
213 g_free (normalized_name);
214 }
215
216 out:
217 g_match_info_free (match_info);
218
219 return retval;
220}
221
222static char *
223construct_language_name (const char *language,
224 const char *territory,
225 const char *codeset,
226 const char *modifier)
227{
228 char *name;
229
230 g_assert (language != NULL && language[0] != 0)do { if (language != ((void*)0) && language[0] != 0) ;
else g_assertion_message_expr ("MateDesktop", "mate-languages.c"
, 230, ((const char*) (__func__)), "language != NULL && language[0] != 0"
); } while (0)
;
231 g_assert (territory == NULL || territory[0] != 0)do { if (territory == ((void*)0) || territory[0] != 0) ; else
g_assertion_message_expr ("MateDesktop", "mate-languages.c",
231, ((const char*) (__func__)), "territory == NULL || territory[0] != 0"
); } while (0)
;
232 g_assert (codeset == NULL || codeset[0] != 0)do { if (codeset == ((void*)0) || codeset[0] != 0) ; else g_assertion_message_expr
("MateDesktop", "mate-languages.c", 232, ((const char*) (__func__
)), "codeset == NULL || codeset[0] != 0"); } while (0)
;
233 g_assert (modifier == NULL || modifier[0] != 0)do { if (modifier == ((void*)0) || modifier[0] != 0) ; else g_assertion_message_expr
("MateDesktop", "mate-languages.c", 233, ((const char*) (__func__
)), "modifier == NULL || modifier[0] != 0"); } while (0)
;
234
235 name = g_strdup_printf ("%s%s%s%s%s%s%s",
236 language,
237 territory != NULL((void*)0)? "_" : "",
238 territory != NULL((void*)0)? territory : "",
239 codeset != NULL((void*)0)? "." : "",
240 codeset != NULL((void*)0)? codeset : "",
241 modifier != NULL((void*)0)? "@" : "",
242 modifier != NULL((void*)0)? modifier : "");
243
244 return name;
245}
246
247/**
248 * mate_normalize_locale:
249 * @locale: a locale string
250 *
251 * Gets the normalized locale string in the form
252 * [language[_country][.codeset][@modifier]] for @name.
253 *
254 * Return value: (transfer full): normalized locale string. Caller
255 * takes ownership.
256 *
257 * Since: 1.22
258 */
259char *
260mate_normalize_locale (const char *locale)
261{
262 char *normalized_name;
263 gboolean valid;
264 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
265 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
266 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset = NULL((void*)0);
267 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *modifier = NULL((void*)0);
268
269 if (locale[0] == '\0') {
270 return NULL((void*)0);
271 }
272
273 valid = mate_parse_locale (locale,
274 &language_code,
275 &territory_code,
276 &codeset, &modifier);
277 if (!valid)
278 return NULL((void*)0);
279
280 normalized_name = construct_language_name (language_code,
281 territory_code,
282 codeset, modifier);
283 return normalized_name;
284}
285
286static gboolean
287language_name_is_valid (const char *language_name)
288{
289 gboolean is_valid;
290 int lc_type_id = LC_MESSAGES5;
291 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
292
293 old_locale = g_strdup (setlocale (lc_type_id, NULL))g_strdup_inline (setlocale (lc_type_id, ((void*)0)));
294 is_valid = setlocale (lc_type_id, language_name) != NULL((void*)0);
295 setlocale (lc_type_id, old_locale);
296
297 return is_valid;
298}
299
300static void
301language_name_get_codeset_details (const char *language_name,
302 char **pcodeset,
303 gboolean *is_utf8)
304{
305 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
306 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset = NULL((void*)0);
307
308 old_locale = g_strdup (setlocale (LC_CTYPE, NULL))g_strdup_inline (setlocale (0, ((void*)0)));
309
310 if (setlocale (LC_CTYPE0, language_name) == NULL((void*)0))
311 return;
312
313 codeset = nl_langinfo (CODESETCODESET);
314
315 if (pcodeset != NULL((void*)0)) {
316 *pcodeset = g_strdup (codeset)g_strdup_inline (codeset);
317 }
318
319 if (is_utf8 != NULL((void*)0)) {
320 codeset = normalize_codeset (codeset);
321
322 *is_utf8 = strcmp (codeset, "UTF-8") == 0;
323 }
324
325 setlocale (LC_CTYPE0, old_locale);
326}
327
328static gboolean
329locale_dir_has_mo_files (const gchar* path)
330{
331 GDir *dir;
332 const char *name;
333 gboolean has_translations;
334
335 has_translations = FALSE(0);
336 dir = g_dir_open (path, 0, NULL((void*)0));
337
338 if (dir == NULL((void*)0)) {
339 goto out;
340 }
341
342 do {
343 name = g_dir_read_name (dir);
344
345 if (name == NULL((void*)0)) {
346 break;
347 }
348
349 if (g_str_has_suffix (name, ".mo")(__builtin_constant_p (".mo")? __extension__ ({ const char * const
__str = (name); const char * const __suffix = (".mo"); gboolean
__result = (0); if (__str == ((void*)0) || __suffix == ((void
*)0)) __result = (g_str_has_suffix) (__str, __suffix); else {
const size_t __str_len = strlen (((__str) + !(__str))); const
size_t __suffix_len = strlen (((__suffix) + !(__suffix))); if
(__str_len >= __suffix_len) __result = memcmp (__str + __str_len
- __suffix_len, ((__suffix) + !(__suffix)), __suffix_len) ==
0; } __result; }) : (g_str_has_suffix) (name, ".mo") )
) {
350 has_translations = TRUE(!(0));
351 break;
352 }
353 } while (name != NULL((void*)0));
354 g_dir_close (dir);
355
356 out:
357 return has_translations;
358}
359
360/**
361 * mate_language_has_translations:
362 * @code: an ISO 639 code string
363 *
364 * Returns %TRUE if there are translations for language @code.
365 *
366 * Return value: %TRUE if there are translations for language @code.
367 *
368 * Since: 1.22
369 */
370gboolean
371mate_language_has_translations (const char *code)
372{
373 gboolean has_translations;
374 gchar *path;
375
376 path = g_build_filename (MATELOCALEDIR"/usr/share/locale", code, "LC_MESSAGES", NULL((void*)0));
377 has_translations = locale_dir_has_mo_files (path);
378
379 if (!has_translations) {
380 const char * const *system_data_dirs;
381 int i = 0;
382
383 system_data_dirs = g_get_system_data_dirs ();
384 while ((system_data_dirs[i] != NULL((void*)0)) && (has_translations == FALSE(0))) {
385 g_free (path);
386 path = g_build_filename (system_data_dirs[i], "locale", code, "LC_MESSAGES", NULL((void*)0));
387 has_translations = locale_dir_has_mo_files (path);
388 ++i;
389 }
390 }
391
392 g_free (path);
393 return has_translations;
394}
395
396static gboolean
397add_locale (const char *language_name,
398 gboolean utf8_only)
399{
400 MateLocale *locale;
401 MateLocale *old_locale;
402 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *name = NULL((void*)0);
403 gboolean is_utf8 = FALSE(0);
404 gboolean valid = FALSE(0);
405
406 g_return_val_if_fail (language_name != NULL, FALSE)do { if ((language_name != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "language_name != NULL"
); return ((0)); } } while (0)
;
407 g_return_val_if_fail (*language_name != '\0', FALSE)do { if ((*language_name != '\0')) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "*language_name != '\\0'"
); return ((0)); } } while (0)
;
408
409 language_name_get_codeset_details (language_name, NULL((void*)0), &is_utf8);
410
411 if (is_utf8) {
412 name = g_strdup (language_name)g_strdup_inline (language_name);
413 } else if (utf8_only) {
414
415 if (strchr (language_name, '.'))
416 return FALSE(0);
417
418 /* If the locale name has no dot, assume that its
419 * encoding part is missing and try again after adding
420 * ".UTF-8". This catches locale names like "de_DE".
421 */
422 name = g_strdup_printf ("%s.UTF-8", language_name);
423
424 language_name_get_codeset_details (name, NULL((void*)0), &is_utf8);
425 if (!is_utf8)
426 return FALSE(0);
427 } else {
428 name = g_strdup (language_name)g_strdup_inline (language_name);
429 }
430
431 if (!language_name_is_valid (name)) {
432 g_debug ("Ignoring '%s' as a locale, since it's invalid", name);
433 return FALSE(0);
434 }
435
436 locale = g_new0 (MateLocale, 1)((MateLocale *) g_malloc0_n ((1), sizeof (MateLocale)));
437 valid = mate_parse_locale (name,
438 &locale->language_code,
439 &locale->territory_code,
440 &locale->codeset,
441 &locale->modifier);
442 if (!valid) {
443 mate_locale_free (locale);
444 return FALSE(0);
445 }
446
447 locale->id = construct_language_name (locale->language_code, locale->territory_code,
448 NULL((void*)0), locale->modifier);
449 locale->name = construct_language_name (locale->language_code, locale->territory_code,
450 locale->codeset, locale->modifier);
451
452 if (!mate_language_has_translations (locale->name) &&
453 !mate_language_has_translations (locale->id) &&
454 !mate_language_has_translations (locale->language_code) &&
455 utf8_only) {
456 g_debug ("Ignoring '%s' as a locale, since it lacks translations", locale->name);
457 mate_locale_free (locale);
458 return FALSE(0);
459 }
460
461 if (!utf8_only) {
462 g_free (locale->id);
463 locale->id = g_strdup (locale->name)g_strdup_inline (locale->name);
464 }
465
466 old_locale = g_hash_table_lookup (mate_available_locales_map, locale->id);
467 if (old_locale != NULL((void*)0)) {
468 if (strlen (old_locale->name) > strlen (locale->name)) {
469 mate_locale_free (locale);
470 return FALSE(0);
471 }
472 }
473
474 g_hash_table_insert (mate_available_locales_map, g_strdup (locale->id)g_strdup_inline (locale->id), locale);
475
476 return TRUE(!(0));
477}
478
479static int
480select_dirs (const struct dirent *dirent)
481{
482 int result = 0;
483
484 if (strcmp (dirent->d_name, ".") != 0 && strcmp (dirent->d_name, "..") != 0) {
485 mode_t mode = 0;
486
487#ifdef _DIRENT_HAVE_D_TYPE
488 if (dirent->d_type != DT_UNKNOWNDT_UNKNOWN && dirent->d_type != DT_LNKDT_LNK) {
489 mode = DTTOIF (dirent->d_type)((dirent->d_type) << 12);
490 } else
491#endif
492 {
493 struct stat st;
494 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *path = NULL((void*)0);
495
496 path = g_build_filename (MATELOCALEDIR"/usr/share/locale", dirent->d_name, NULL((void*)0));
497 if (g_statstat (path, &st) == 0) {
498 mode = st.st_mode;
499 }
500 }
501
502 result = S_ISDIR (mode)((((mode)) & 0170000) == (0040000));
503 }
504
505 return result;
506}
507
508static gboolean
509collect_locales_from_directory (void)
510{
511 gboolean found_locales = FALSE(0);
512 struct dirent **dirents;
513 int ndirents;
514 int cnt;
515
516 ndirents = scandir (MATELOCALEDIR"/usr/share/locale", &dirents, select_dirs, alphasort);
517
518 for (cnt = 0; cnt < ndirents; ++cnt) {
519 if (add_locale (dirents[cnt]->d_name, TRUE(!(0))))
520 found_locales = TRUE(!(0));
521 }
522
523 if (ndirents > 0) {
524 free (dirents);
525 }
526 return found_locales;
527}
528
529static gboolean
530collect_locales_from_localebin (void)
531{
532 gboolean found_locales = FALSE(0);
533 const gchar *argv[] = { "locale", "-a", NULL((void*)0) };
534 gchar **linep;
535 g_auto (GStrv)__attribute__((cleanup(glib_auto_cleanup_GStrv))) GStrv lines = NULL((void*)0);
536 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) gchar *output = NULL((void*)0);
537
538 if (g_spawn_sync (NULL((void*)0), (gchar **) argv, NULL((void*)0),
539 G_SPAWN_SEARCH_PATH|G_SPAWN_STDERR_TO_DEV_NULL,
540 NULL((void*)0), NULL((void*)0), &output, NULL((void*)0), NULL((void*)0), NULL((void*)0)) == FALSE(0))
541 return FALSE(0);
542
543 g_return_val_if_fail (output != NULL, FALSE)do { if ((output != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "output != NULL"
); return ((0)); } } while (0)
;
544
545 lines = g_strsplit (output, "\n", 0);
546 if (lines) {
547 linep = lines;
548 while (*linep) {
549 if (*linep[0] && add_locale (*linep, TRUE(!(0))))
550 found_locales = TRUE(!(0));
551 linep++;
552 }
553 }
554
555 return found_locales;
556}
557
558static void
559fill_count_map (GHashTable *count_map,
560 const char *code)
561{
562 int count;
563 gpointer pointer;
564
565 if (code == NULL((void*)0))
566 return;
567
568 if ((pointer = g_hash_table_lookup (count_map, code)) != NULL((void*)0))
569 count = GPOINTER_TO_INT (pointer)((gint) (glong) (pointer)) + 1;
570 else
571 count = 1;
572
573 g_hash_table_insert (count_map, g_strdup (code)g_strdup_inline (code), GINT_TO_POINTER (count)((gpointer) (glong) (count)));
574}
575
576static void
577count_languages_and_territories (void)
578{
579 gpointer value;
580 GHashTableIter iter;
581
582 mate_language_count_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
583 mate_territory_count_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL((void*)0));
584
585 g_hash_table_iter_init (&iter, mate_available_locales_map);
586 while (g_hash_table_iter_next (&iter, NULL((void*)0), &value)) {
587 MateLocale *locale = (MateLocale *) value;
588 fill_count_map (mate_language_count_map, locale->language_code);
589 fill_count_map (mate_territory_count_map, locale->territory_code);
590 }
591}
592
593static void
594collect_locales (void)
595{
596 gboolean found_localebin_locales = FALSE(0);
597 gboolean found_dir_locales = FALSE(0);
598
599 if (mate_available_locales_map == NULL((void*)0)) {
600 mate_available_locales_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) mate_locale_free);
601 }
602
603 found_localebin_locales = collect_locales_from_localebin ();
604
605 found_dir_locales = collect_locales_from_directory ();
606
607 if (!(found_localebin_locales || found_dir_locales)) {
608 g_warning ("Could not read list of available locales from libc, "
609 "guessing possible locales from available translations, "
610 "but list may be incomplete!");
611 }
612
613 count_languages_and_territories ();
614}
615
616static gint
617get_language_count (const char *language)
618{
619 gint count = 0;
620 gpointer pointer;
621
622 if (mate_language_count_map == NULL((void*)0))
623 collect_locales ();
624
625 if ((pointer = g_hash_table_lookup (mate_language_count_map, language)) != NULL((void*)0))
626 count = GPOINTER_TO_INT (pointer)((gint) (glong) (pointer));
627
628 return count;
629}
630
631static gboolean
632is_unique_language (const char *language)
633{
634 return get_language_count (language) == 1;
635}
636
637static gint
638get_territory_count (const char *territory)
639{
640 gint count = 0;
641 gpointer pointer;
642
643 if (mate_territory_count_map == NULL((void*)0))
644 collect_locales ();
645
646 if ((pointer = g_hash_table_lookup (mate_territory_count_map, territory)) != NULL((void*)0))
647 count = GPOINTER_TO_INT (pointer)((gint) (glong) (pointer));
648
649 return count;
650}
651
652static gboolean
653is_unique_territory (const char *territory)
654{
655 return get_territory_count (territory) == 1;
656}
657
658static gboolean
659is_fallback_language (const char *code)
660{
661 const char *fallback_language_names[] = { "C", "POSIX", NULL((void*)0) };
662 int i;
663
664 for (i = 0; fallback_language_names[i] != NULL((void*)0); i++) {
665 if (strcmp (code, fallback_language_names[i]) == 0) {
666 return TRUE(!(0));
667 }
668 }
669
670 return FALSE(0);
671}
672
673static const char *
674get_language (const char *code)
675{
676 const char *name;
677 int len;
678
679 g_assert (code != NULL)do { if (code != ((void*)0)) ; else g_assertion_message_expr (
"MateDesktop", "mate-languages.c", 679, ((const char*) (__func__
)), "code != NULL"); } while (0)
;
680
681 if (is_fallback_language (code)) {
682 return "Unspecified";
683 }
684
685 len = strlen (code);
686 if (len != 2 && len != 3) {
687 return NULL((void*)0);
688 }
689
690 name = (const char *) g_hash_table_lookup (mate_languages_map, code);
691
692 return name;
693}
694
695static char *
696get_first_item_in_semicolon_list (const char *list)
697{
698 char **items;
699 char *item;
700
701 /* Some entries in iso codes have multiple values, separated
702 * by semicolons. Not really sure which one to pick, so
703 * we just arbitrarily pick the first one.
704 */
705 items = g_strsplit (list, "; ", 2);
706
707 item = g_strdup (items[0])g_strdup_inline (items[0]);
708 g_strfreev (items);
709
710 return item;
711}
712
713static char *
714capitalize_utf8_string (const char *str)
715{
716 char first[8] = { 0 };
717
718 if (!str)
719 return NULL((void*)0);
720
721 g_unichar_to_utf8 (g_unichar_totitle (g_utf8_get_char (str)), first);
722
723 return g_strconcat (first, g_utf8_offset_to_pointer (str, 1), NULL((void*)0));
724}
725
726static char *
727get_translated_language (const char *code,
728 const char *locale)
729{
730 const char *language;
731 char *name;
732
733 language = get_language (code);
734
735 name = NULL((void*)0);
736 if (language != NULL((void*)0)) {
737 const char *translated_name;
738 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
739
740 if (locale != NULL((void*)0)) {
741 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL))g_strdup_inline (setlocale (5, ((void*)0)));
742 setlocale (LC_MESSAGES5, locale);
743 }
744
745 if (is_fallback_language (code)) {
746 name = g_strdup (_("Unspecified"))g_strdup_inline (gettext ("Unspecified"));
747 } else {
748 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *tmp = NULL((void*)0);
749 translated_name = dgettext ("iso_639", language);
750 tmp = get_first_item_in_semicolon_list (translated_name);
751 name = capitalize_utf8_string (tmp);
752 }
753
754 if (locale != NULL((void*)0)) {
755 setlocale (LC_MESSAGES5, old_locale);
756 }
757 }
758
759 return name;
760}
761
762static const char *
763get_territory (const char *code)
764{
765 const char *name;
766 int len;
767
768 g_assert (code != NULL)do { if (code != ((void*)0)) ; else g_assertion_message_expr (
"MateDesktop", "mate-languages.c", 768, ((const char*) (__func__
)), "code != NULL"); } while (0)
;
769
770 len = strlen (code);
771 if (len != 2 && len != 3) {
772 return NULL((void*)0);
773 }
774
775 name = (const char *) g_hash_table_lookup (mate_territories_map, code);
776
777 return name;
778}
779
780static char *
781get_translated_territory (const char *code,
782 const char *locale)
783{
784 const char *territory;
785 char *name;
786
787 territory = get_territory (code);
788
789 name = NULL((void*)0);
790 if (territory != NULL((void*)0)) {
791 const char *translated_territory;
792 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *old_locale = NULL((void*)0);
793 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *tmp = NULL((void*)0);
794
795 if (locale != NULL((void*)0)) {
796 old_locale = g_strdup (setlocale (LC_MESSAGES, NULL))g_strdup_inline (setlocale (5, ((void*)0)));
797 setlocale (LC_MESSAGES5, locale);
798 }
799
800 translated_territory = dgettext ("iso_3166", territory);
801 tmp = get_first_item_in_semicolon_list (translated_territory);
802 name = capitalize_utf8_string (tmp);
803
804 if (locale != NULL((void*)0)) {
805 setlocale (LC_MESSAGES5, old_locale);
806 }
807 }
808
809 return name;
810}
811
812static void
813languages_parse_start_tag (GMarkupParseContext *ctx,
814 const char *element_name,
815 const char **attr_names,
816 const char **attr_values,
817 gpointer user_data,
818 GError **error)
819{
820 const char *ccode_longB;
821 const char *ccode_longT;
822 const char *ccode;
823 const char *ccode_id;
824 const char *lang_name;
825
826 if (! (g_str_equal (element_name, "iso_639_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_639_entry"
)) == 0)
|| g_str_equal (element_name, "iso_639_3_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_639_3_entry"
)) == 0)
)
827 || attr_names == NULL((void*)0) || attr_values == NULL((void*)0)) {
828 return;
829 }
830
831 ccode = NULL((void*)0);
832 ccode_longB = NULL((void*)0);
833 ccode_longT = NULL((void*)0);
834 ccode_id = NULL((void*)0);
835 lang_name = NULL((void*)0);
836
837 while (*attr_names && *attr_values) {
838 if (g_str_equal (*attr_names, "iso_639_1_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_1_code"
)) == 0)
) {
839 /* skip if empty */
840 if (**attr_values) {
841 if (strlen (*attr_values) != 2) {
842 return;
843 }
844 ccode = *attr_values;
845 }
846 } else if (g_str_equal (*attr_names, "iso_639_2B_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_2B_code"
)) == 0)
) {
847 /* skip if empty */
848 if (**attr_values) {
849 if (strlen (*attr_values) != 3) {
850 return;
851 }
852 ccode_longB = *attr_values;
853 }
854 } else if (g_str_equal (*attr_names, "iso_639_2T_code")(strcmp ((const char *) (*attr_names), (const char *) ("iso_639_2T_code"
)) == 0)
) {
855 /* skip if empty */
856 if (**attr_values) {
857 if (strlen (*attr_values) != 3) {
858 return;
859 }
860 ccode_longT = *attr_values;
861 }
862 } else if (g_str_equal (*attr_names, "id")(strcmp ((const char *) (*attr_names), (const char *) ("id"))
== 0)
) {
863 /* skip if empty */
864 if (**attr_values) {
865 if (strlen (*attr_values) != 2 &&
866 strlen (*attr_values) != 3) {
867 return;
868 }
869 ccode_id = *attr_values;
870 }
871 } else if (g_str_equal (*attr_names, "name")(strcmp ((const char *) (*attr_names), (const char *) ("name"
)) == 0)
) {
872 lang_name = *attr_values;
873 }
874
875 ++attr_names;
876 ++attr_values;
877 }
878
879 if (lang_name == NULL((void*)0)) {
880 return;
881 }
882
883 if (ccode != NULL((void*)0)) {
884 g_hash_table_insert (mate_languages_map,
885 g_strdup (ccode)g_strdup_inline (ccode),
886 g_strdup (lang_name)g_strdup_inline (lang_name));
887 }
888 if (ccode_longB != NULL((void*)0)) {
889 g_hash_table_insert (mate_languages_map,
890 g_strdup (ccode_longB)g_strdup_inline (ccode_longB),
891 g_strdup (lang_name)g_strdup_inline (lang_name));
892 }
893 if (ccode_longT != NULL((void*)0)) {
894 g_hash_table_insert (mate_languages_map,
895 g_strdup (ccode_longT)g_strdup_inline (ccode_longT),
896 g_strdup (lang_name)g_strdup_inline (lang_name));
897 }
898 if (ccode_id != NULL((void*)0)) {
899 g_hash_table_insert (mate_languages_map,
900 g_strdup (ccode_id)g_strdup_inline (ccode_id),
901 g_strdup (lang_name)g_strdup_inline (lang_name));
902 }
903}
904
905static void
906territories_parse_start_tag (GMarkupParseContext *ctx,
907 const char *element_name,
908 const char **attr_names,
909 const char **attr_values,
910 gpointer user_data,
911 GError **error)
912{
913 const char *acode_2;
914 const char *acode_3;
915 const char *ncode;
916 const char *territory_common_name;
917 const char *territory_name;
918
919 if (! g_str_equal (element_name, "iso_3166_entry")(strcmp ((const char *) (element_name), (const char *) ("iso_3166_entry"
)) == 0)
|| attr_names == NULL((void*)0) || attr_values == NULL((void*)0)) {
920 return;
921 }
922
923 acode_2 = NULL((void*)0);
924 acode_3 = NULL((void*)0);
925 ncode = NULL((void*)0);
926 territory_common_name = NULL((void*)0);
927 territory_name = NULL((void*)0);
928
929 while (*attr_names && *attr_values) {
930 if (g_str_equal (*attr_names, "alpha_2_code")(strcmp ((const char *) (*attr_names), (const char *) ("alpha_2_code"
)) == 0)
) {
931 /* skip if empty */
932 if (**attr_values) {
933 if (strlen (*attr_values) != 2) {
934 return;
935 }
936 acode_2 = *attr_values;
937 }
938 } else if (g_str_equal (*attr_names, "alpha_3_code")(strcmp ((const char *) (*attr_names), (const char *) ("alpha_3_code"
)) == 0)
) {
939 /* skip if empty */
940 if (**attr_values) {
941 if (strlen (*attr_values) != 3) {
942 return;
943 }
944 acode_3 = *attr_values;
945 }
946 } else if (g_str_equal (*attr_names, "numeric_code")(strcmp ((const char *) (*attr_names), (const char *) ("numeric_code"
)) == 0)
) {
947 /* skip if empty */
948 if (**attr_values) {
949 if (strlen (*attr_values) != 3) {
950 return;
951 }
952 ncode = *attr_values;
953 }
954 } else if (g_str_equal (*attr_names, "common_name")(strcmp ((const char *) (*attr_names), (const char *) ("common_name"
)) == 0)
) {
955 /* skip if empty */
956 if (**attr_values) {
957 territory_common_name = *attr_values;
958 }
959 } else if (g_str_equal (*attr_names, "name")(strcmp ((const char *) (*attr_names), (const char *) ("name"
)) == 0)
) {
960 territory_name = *attr_values;
961 }
962
963 ++attr_names;
964 ++attr_values;
965 }
966
967 if (territory_common_name != NULL((void*)0)) {
968 territory_name = territory_common_name;
969 }
970
971 if (territory_name == NULL((void*)0)) {
972 return;
973 }
974
975 if (acode_2 != NULL((void*)0)) {
976 g_hash_table_insert (mate_territories_map,
977 g_strdup (acode_2)g_strdup_inline (acode_2),
978 g_strdup (territory_name)g_strdup_inline (territory_name));
979 }
980 if (acode_3 != NULL((void*)0)) {
981 g_hash_table_insert (mate_territories_map,
982 g_strdup (acode_3)g_strdup_inline (acode_3),
983 g_strdup (territory_name)g_strdup_inline (territory_name));
984 }
985 if (ncode != NULL((void*)0)) {
986 g_hash_table_insert (mate_territories_map,
987 g_strdup (ncode)g_strdup_inline (ncode),
988 g_strdup (territory_name)g_strdup_inline (territory_name));
989 }
990}
991
992static void
993languages_variant_init (const char *variant)
994{
995 gboolean res;
996 gsize buf_len;
997 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *buf = NULL((void*)0);
998 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *filename = NULL((void*)0);
999 g_autoptr (GError)__attribute__((cleanup(glib_autoptr_cleanup_GError))) GError_autoptr error = NULL((void*)0);
1000
1001 bindtextdomain (variant, ISO_CODES_LOCALESDIR"/usr" "/share/locale");
1002 bind_textdomain_codeset (variant, "UTF-8");
1003
1004 error = NULL((void*)0);
1005 filename = g_strdup_printf (ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/%s.xml", variant);
1006 res = g_file_get_contents (filename,
1007 &buf,
1008 &buf_len,
1009 &error);
1010 if (res) {
1011 g_autoptr (GMarkupParseContext)__attribute__((cleanup(glib_autoptr_cleanup_GMarkupParseContext
))) GMarkupParseContext_autoptr
ctx = NULL((void*)0);
1012 GMarkupParser parser = { languages_parse_start_tag, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0) };
1013
1014 ctx = g_markup_parse_context_new (&parser, 0, NULL((void*)0), NULL((void*)0));
1015
1016 error = NULL((void*)0);
1017 res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
1018
1019 if (! res) {
1020 g_warning ("Failed to parse '%s': %s\n",
1021 filename,
1022 error->message);
1023 }
1024 } else {
1025 g_warning ("Failed to load '%s': %s\n",
1026 filename,
1027 error->message);
1028 }
1029}
1030
1031static void
1032languages_init (void)
1033{
1034 if (mate_languages_map)
1035 return;
1036
1037 mate_languages_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1038
1039 languages_variant_init ("iso_639");
1040 languages_variant_init ("iso_639_3");
1041}
1042
1043static void
1044territories_init (void)
1045{
1046 gboolean res;
1047 gsize buf_len;
1048 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *buf = NULL((void*)0);
1049 g_autoptr (GError)__attribute__((cleanup(glib_autoptr_cleanup_GError))) GError_autoptr error = NULL((void*)0);
1050
1051 if (mate_territories_map)
1052 return;
1053
1054 bindtextdomain ("iso_3166", ISO_CODES_LOCALESDIR"/usr" "/share/locale");
1055 bind_textdomain_codeset ("iso_3166", "UTF-8");
1056
1057 mate_territories_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1058
1059 error = NULL((void*)0);
1060 res = g_file_get_contents (ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1061 &buf,
1062 &buf_len,
1063 &error);
1064 if (res) {
1065 g_autoptr (GMarkupParseContext)__attribute__((cleanup(glib_autoptr_cleanup_GMarkupParseContext
))) GMarkupParseContext_autoptr
ctx = NULL((void*)0);
1066 GMarkupParser parser = { territories_parse_start_tag, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0) };
1067
1068 ctx = g_markup_parse_context_new (&parser, 0, NULL((void*)0), NULL((void*)0));
1069
1070 error = NULL((void*)0);
1071 res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
1072
1073 if (! res) {
1074 g_warning ("Failed to parse '%s': %s\n",
1075 ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1076 error->message);
1077 }
1078 } else {
1079 g_warning ("Failed to load '%s': %s\n",
1080 ISO_CODES_DATADIR"/usr" "/share/xml/iso-codes" "/iso_3166.xml",
1081 error->message);
1082 }
1083}
1084
1085/**
1086 * mate_get_language_from_locale:
1087 * @locale: a locale string
1088 * @translation: (allow-none): a locale string
1089 *
1090 * Gets the language description for @locale. If @translation is
1091 * provided the returned string is translated accordingly.
1092 *
1093 * Return value: (transfer full): the language description. Caller
1094 * takes ownership.
1095 *
1096 * Since: 1.22
1097 */
1098char *
1099mate_get_language_from_locale (const char *locale,
1100 const char *translation)
1101{
1102 GString *full_language;
1103 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
1104 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
1105 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset_code = NULL((void*)0);
1106 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *langinfo_codeset = NULL((void*)0);
1107 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_language = NULL((void*)0);
1108 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_territory = NULL((void*)0);
1109 gboolean is_utf8 = TRUE(!(0));
1110
1111 g_return_val_if_fail (locale != NULL, NULL)do { if ((locale != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "locale != NULL"
); return (((void*)0)); } } while (0)
;
1112 g_return_val_if_fail (*locale != '\0', NULL)do { if ((*locale != '\0')) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "*locale != '\\0'"
); return (((void*)0)); } } while (0)
;
1113
1114 full_language = g_string_new (NULL((void*)0));
1115
1116 languages_init ();
1117 territories_init ();
1118
1119 mate_parse_locale (locale,
1120 &language_code,
1121 &territory_code,
1122 &codeset_code,
1123 NULL((void*)0));
1124
1125 if (language_code == NULL((void*)0)) {
1126 goto out;
1127 }
1128
1129 translated_language = get_translated_language (language_code, translation);
1130 if (translated_language == NULL((void*)0)) {
1131 goto out;
1132 }
1133
1134 full_language = g_string_append (full_language, translated_language)(__builtin_constant_p (translated_language) ? __extension__ (
{ const char * const __val = (translated_language); g_string_append_len_inline
(full_language, __val, (__val != ((void*)0)) ? (gssize) strlen
(((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(full_language, translated_language, (gssize) -1))
;
1135
1136 if (is_unique_language (language_code)) {
1137 goto out;
1138 }
1139
1140 if (territory_code != NULL((void*)0)) {
1141 translated_territory = get_translated_territory (territory_code, translation);
1142 }
1143 if (translated_territory != NULL((void*)0)) {
1144 g_string_append_printf (full_language,
1145 " (%s)",
1146 translated_territory);
1147 }
1148
1149 language_name_get_codeset_details (locale, &langinfo_codeset, &is_utf8);
1150
1151 if (codeset_code == NULL((void*)0) && langinfo_codeset != NULL((void*)0)) {
1152 codeset_code = g_strdup (langinfo_codeset)g_strdup_inline (langinfo_codeset);
1153 }
1154
1155 if (!is_utf8 && codeset_code) {
1156 g_string_append_printf (full_language,
1157 " [%s]",
1158 codeset_code);
1159 }
1160
1161 out:
1162 if (full_language->len == 0) {
1163 g_string_free (full_language, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(full_language), ((!(0)))) : g_string_free_and_steal (full_language
)) : (g_string_free) ((full_language), ((!(0)))))
;
1164 return NULL((void*)0);
1165 }
1166
1167 return g_string_free (full_language, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((full_language
), ((0))) : g_string_free_and_steal (full_language)) : (g_string_free
) ((full_language), ((0))))
;
1168}
1169
1170/**
1171 * mate_get_country_from_locale:
1172 * @locale: a locale string
1173 * @translation: (allow-none): a locale string
1174 *
1175 * Gets the country description for @locale. If @translation is
1176 * provided the returned string is translated accordingly.
1177 *
1178 * Return value: (transfer full): the country description. Caller
1179 * takes ownership.
1180 *
1181 * Since: 1.22
1182 */
1183char *
1184mate_get_country_from_locale (const char *locale,
1185 const char *translation)
1186{
1187 GString *full_name;
1188 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *language_code = NULL((void*)0);
1189 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *territory_code = NULL((void*)0);
1190 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *codeset_code = NULL((void*)0);
1191 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *langinfo_codeset = NULL((void*)0);
1192 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_language = NULL((void*)0);
1193 g_autofree__attribute__((cleanup(g_autoptr_cleanup_generic_gfree))) char *translated_territory = NULL((void*)0);
1194 gboolean is_utf8 = TRUE(!(0));
1195
1196 g_return_val_if_fail (locale != NULL, NULL)do { if ((locale != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "locale != NULL"
); return (((void*)0)); } } while (0)
;
1197 g_return_val_if_fail (*locale != '\0', NULL)do { if ((*locale != '\0')) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "*locale != '\\0'"
); return (((void*)0)); } } while (0)
;
1198
1199 full_name = g_string_new (NULL((void*)0));
1200
1201 languages_init ();
1202 territories_init ();
1203
1204 mate_parse_locale (locale,
1205 &language_code,
1206 &territory_code,
1207 &codeset_code,
1208 NULL((void*)0));
1209
1210 if (territory_code == NULL((void*)0)) {
1211 goto out;
1212 }
1213
1214 translated_territory = get_translated_territory (territory_code, translation);
1215 g_string_append (full_name, translated_territory)(__builtin_constant_p (translated_territory) ? __extension__ (
{ const char * const __val = (translated_territory); g_string_append_len_inline
(full_name, __val, (__val != ((void*)0)) ? (gssize) strlen (
((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(full_name, translated_territory, (gssize) -1))
;
1216
1217 if (is_unique_territory (territory_code)) {
1218 goto out;
1219 }
1220
1221 if (language_code != NULL((void*)0)) {
1222 translated_language = get_translated_language (language_code, translation);
1223 }
1224 if (translated_language != NULL((void*)0)) {
1225 g_string_append_printf (full_name,
1226 " (%s)",
1227 translated_language);
1228 }
1229
1230 language_name_get_codeset_details (translation, &langinfo_codeset, &is_utf8);
1231
1232 if (codeset_code == NULL((void*)0) && langinfo_codeset != NULL((void*)0)) {
1233 codeset_code = g_strdup (langinfo_codeset)g_strdup_inline (langinfo_codeset);
1234 }
1235
1236 if (!is_utf8 && codeset_code) {
1237 g_string_append_printf (full_name,
1238 " [%s]",
1239 codeset_code);
1240 }
1241
1242 out:
1243 if (full_name->len == 0) {
1244 g_string_free (full_name, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(full_name), ((!(0)))) : g_string_free_and_steal (full_name))
: (g_string_free) ((full_name), ((!(0)))))
;
This statement is never executed
1245 return NULL((void*)0);
1246 }
1247
1248 return g_string_free (full_name, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((full_name
), ((0))) : g_string_free_and_steal (full_name)) : (g_string_free
) ((full_name), ((0))))
;
1249}
1250
1251/**
1252 * mate_get_all_locales:
1253 *
1254 * Gets all locales.
1255 *
1256 * Return value: (array zero-terminated=1) (element-type utf8) (transfer full):
1257 * a newly allocated %NULL-terminated string array containing the
1258 * all locales. Free with g_strfreev().
1259 *
1260 * Since: 1.22
1261 */
1262char **
1263mate_get_all_locales (void)
1264{
1265 GHashTableIter iter;
1266 gpointer key, value;
1267 GPtrArray *array;
1268
1269 if (mate_available_locales_map == NULL((void*)0)) {
1270 collect_locales ();
1271 }
1272
1273 array = g_ptr_array_new ();
1274 g_hash_table_iter_init (&iter, mate_available_locales_map);
1275 while (g_hash_table_iter_next (&iter, &key, &value)) {
1276 MateLocale *locale;
1277
1278 locale = (MateLocale *) value;
1279
1280 g_ptr_array_add (array, g_strdup (locale->name)g_strdup_inline (locale->name));
1281 }
1282 g_ptr_array_add (array, NULL((void*)0));
1283
1284 return (char **) g_ptr_array_free (array, FALSE(0));
1285}
1286
1287/**
1288 * mate_get_language_from_code:
1289 * @code: an ISO 639 code string
1290 * @translation: (allow-none): a locale string
1291 *
1292 * Gets the language name for @code. If @locale is provided the
1293 * returned string is translated accordingly.
1294 *
1295 * Return value: (transfer full): the language name. Caller takes
1296 * ownership.
1297 *
1298 * Since: 1.22
1299 */
1300char *
1301mate_get_language_from_code (const char *code,
1302 const char *translation)
1303{
1304 g_return_val_if_fail (code != NULL, NULL)do { if ((code != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "code != NULL");
return (((void*)0)); } } while (0)
;
1305
1306 languages_init ();
1307
1308 return get_translated_language (code, translation);
1309}
1310
1311/**
1312 * mate_get_country_from_code:
1313 * @code: an ISO 3166 code string
1314 * @translation: (allow-none): a locale string
1315 *
1316 * Gets the country name for @code. If @locale is provided the
1317 * returned string is translated accordingly.
1318 *
1319 * Return value: (transfer full): the country name. Caller takes
1320 * ownership.
1321 *
1322 * Since: 1.22
1323 */
1324char *
1325mate_get_country_from_code (const char *code,
1326 const char *translation)
1327{
1328 g_return_val_if_fail (code != NULL, NULL)do { if ((code != ((void*)0))) { } else { g_return_if_fail_warning
("MateDesktop", ((const char*) (__func__)), "code != NULL");
return (((void*)0)); } } while (0)
;
1329
1330 territories_init ();
1331
1332 return get_translated_territory (code, translation);
1333}
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-fb6164.html b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-fb6164.html new file mode 100644 index 0000000..89e35d4 --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/report-fb6164.html @@ -0,0 +1,1437 @@ + + + +/rootdir/libmate-desktop/tmp-introspectv9kvk83f/MateDesktop-2.0.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:libmate-desktop/tmp-introspectv9kvk83f/MateDesktop-2.0.c
Warning:line 181, column 11
This statement is never executed
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name MateDesktop-2.0.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/libmate-desktop -resource-dir /usr/bin/../lib/clang/17 -D MATE_DESKTOP_USE_UNSTABLE_API -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/cairo -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/atk-1.0 -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/cloudproviders -I /usr/include/blkid -I /usr/include/libmount -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/fribidi -I /usr/include/sysprof-6 -I /usr/include/libpng16 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/dbus-1.0 -I /usr/lib64/dbus-1.0/include -I /usr/include/atk-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/glib-2.0 -I /usr/lib64/glib-2.0/include -I /usr/include/at-spi2-atk/2.0 -I /usr/include/cloudproviders -I /usr/include/at-spi-2.0 -I /usr/include/gio-unix-2.0 -I /usr/include/blkid -I /usr/include/pixman-1 -I /usr/include/libxml2 -I /usr/include/libmount -I /usr/include/fribidi -I /usr/include/libpng16 -I /usr/include/sysprof-6 -I /rootdir -internal-isystem /usr/bin/../lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-deprecated-declarations -fdebug-compilation-dir=/rootdir/libmate-desktop -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-checker security.insecureAPI.strcpy -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-04-04-053707-5943-1 -x c /rootdir/libmate-desktop/tmp-introspectv9kvk83f/MateDesktop-2.0.c +
+ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1/* This file is generated, do not edit */
2
3#undef GLIB_VERSION_MIN_REQUIRED((((2) << 16 | (78) << 8)))
4#undef GLIB_VERSION_MAX_ALLOWED((((2) << 16 | (78) << 8)))
5
6#include <glib.h>
7#include <string.h>
8#include <stdlib.h>
9
10/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
11 * GObject introspection: Dump introspection data
12 *
13 * Copyright (C) 2008 Colin Walters <walters@verbum.org>
14 *
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the
27 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28 * Boston, MA 02111-1307, USA.
29 */
30
31#include <stdlib.h>
32
33#include <glib.h>
34#include <glib-object.h>
35#include <gio/gio.h>
36
37/* This file is both compiled into libgirepository.so, and installed
38 * on the filesystem. But for the dumper, we want to avoid linking
39 * to libgirepository; see
40 * https://bugzilla.gnome.org/show_bug.cgi?id=630342
41 */
42#ifdef G_IREPOSITORY_COMPILATION
43#include "config.h"
44#include "girepository.h"
45#endif
46
47#include <string.h>
48
49static void
50escaped_printf (GOutputStream *out, const char *fmt, ...) G_GNUC_PRINTF (2, 3)__attribute__((__format__ (__printf__, 2, 3)));
51
52static void
53escaped_printf (GOutputStream *out, const char *fmt, ...)
54{
55 char *str;
56 va_list args;
57 gsize written;
58 GError *error = NULL((void*)0);
59
60 va_start (args, fmt)__builtin_va_start(args, fmt);
61
62 str = g_markup_vprintf_escaped (fmt, args);
63 if (!g_output_stream_write_all (out, str, strlen (str), &written, NULL((void*)0), &error))
64 {
65 g_critical ("failed to write to iochannel: %s", error->message);
66 g_clear_error (&error);
67 }
68 g_free (str);
69
70 va_end (args)__builtin_va_end(args);
71}
72
73static void
74goutput_write (GOutputStream *out, const char *str)
75{
76 gsize written;
77 GError *error = NULL((void*)0);
78 if (!g_output_stream_write_all (out, str, strlen (str), &written, NULL((void*)0), &error))
79 {
80 g_critical ("failed to write to iochannel: %s", error->message);
81 g_clear_error (&error);
82 }
83}
84
85typedef GType (*GetTypeFunc)(void);
86typedef GQuark (*ErrorQuarkFunc)(void);
87
88static GType
89invoke_get_type (GModule *self, const char *symbol, GError **error)
90{
91 GetTypeFunc sym;
92 GType ret;
93
94 if (!g_module_symbol (self, symbol, (void**)&sym))
95 {
96 g_set_error (error,
97 G_IO_ERRORg_io_error_quark(),
98 G_IO_ERROR_FAILED,
99 "Failed to find symbol '%s'", symbol);
100 return G_TYPE_INVALID((GType) ((0) << (2)));
101 }
102
103 ret = sym ();
104 if (ret == G_TYPE_INVALID((GType) ((0) << (2))))
105 {
106 g_set_error (error,
107 G_IO_ERRORg_io_error_quark(),
108 G_IO_ERROR_FAILED,
109 "Function '%s' returned G_TYPE_INVALID", symbol);
110 }
111 return ret;
112}
113
114static GQuark
115invoke_error_quark (GModule *self, const char *symbol, GError **error)
116{
117 ErrorQuarkFunc sym;
118
119 if (!g_module_symbol (self, symbol, (void**)&sym))
120 {
121 g_set_error (error,
122 G_IO_ERRORg_io_error_quark(),
123 G_IO_ERROR_FAILED,
124 "Failed to find symbol '%s'", symbol);
125 return G_TYPE_INVALID((GType) ((0) << (2)));
126 }
127
128 return sym ();
129}
130
131static char *
132value_transform_to_string (const GValue *value)
133{
134 GValue tmp = G_VALUE_INIT{ 0, { { 0 } } };
135 char *s = NULL((void*)0);
136
137 g_value_init (&tmp, G_TYPE_STRING((GType) ((16) << (2))));
138
139 if (g_value_transform (value, &tmp))
140 {
141 const char *str = g_value_get_string (&tmp);
142
143 if (str != NULL((void*)0))
144 s = g_strescape (str, NULL((void*)0));
145 }
146
147 g_value_unset (&tmp);
148
149 return s;
150}
151
152/* A simpler version of g_strdup_value_contents(), but with stable
153 * output and less complex semantics
154 */
155static char *
156value_to_string (const GValue *value)
157{
158 if (value == NULL((void*)0))
159 return NULL((void*)0);
160
161 if (G_VALUE_HOLDS_STRING (value)(((__extension__ ({ const GValue *__val = (const GValue*) ((value
)); GType __t = (((GType) ((16) << (2)))); gboolean __r
; if (!__val) __r = (0); else if (__val->g_type == __t) __r
= (!(0)); else __r = g_type_check_value_holds (__val, __t); __r
; }))))
)
162 {
163 const char *s = g_value_get_string (value);
164
165 if (s == NULL((void*)0))
166 return g_strdup ("NULL")g_strdup_inline ("NULL");
167
168 return g_strescape (s, NULL((void*)0));
169 }
170 else
171 {
172 GType value_type = G_VALUE_TYPE (value)(((GValue*) (value))->g_type);
173
174 switch (G_TYPE_FUNDAMENTAL (value_type)(g_type_fundamental (value_type)))
175 {
176 case G_TYPE_BOXED((GType) ((18) << (2))):
177 if (g_value_get_boxed (value) == NULL((void*)0))
178 return NULL((void*)0);
179 else
180 return value_transform_to_string (value);
181 break;
This statement is never executed
182
183 case G_TYPE_OBJECT((GType) ((20) << (2))):
184 if (g_value_get_object (value) == NULL((void*)0))
185 return NULL((void*)0);
186 else
187 return value_transform_to_string (value);
188 break;
189
190 case G_TYPE_POINTER((GType) ((17) << (2))):
191 return NULL((void*)0);
192
193 default:
194 return value_transform_to_string (value);
195 }
196 }
197
198 return NULL((void*)0);
199}
200
201static void
202dump_properties (GType type, GOutputStream *out)
203{
204 guint i;
205 guint n_properties;
206 GParamSpec **props;
207
208 if (G_TYPE_FUNDAMENTAL (type)(g_type_fundamental (type)) == G_TYPE_OBJECT((GType) ((20) << (2))))
209 {
210 GObjectClass *klass;
211 klass = g_type_class_ref (type);
212 props = g_object_class_list_properties (klass, &n_properties);
213 }
214 else
215 {
216 void *klass;
217 klass = g_type_default_interface_ref (type);
218 props = g_object_interface_list_properties (klass, &n_properties);
219 }
220
221 for (i = 0; i < n_properties; i++)
222 {
223 GParamSpec *prop;
224
225 prop = props[i];
226 if (prop->owner_type != type)
227 continue;
228
229 const GValue *v = g_param_spec_get_default_value (prop);
230 char *default_value = value_to_string (v);
231
232 if (v != NULL((void*)0) && default_value != NULL((void*)0))
233 {
234 escaped_printf (out, " <property name=\"%s\" type=\"%s\" flags=\"%d\" default-value=\"%s\"/>\n",
235 prop->name,
236 g_type_name (prop->value_type),
237 prop->flags,
238 default_value);
239 }
240 else
241 {
242 escaped_printf (out, " <property name=\"%s\" type=\"%s\" flags=\"%d\"/>\n",
243 prop->name,
244 g_type_name (prop->value_type),
245 prop->flags);
246 }
247
248 g_free (default_value);
249 }
250
251 g_free (props);
252}
253
254static void
255dump_signals (GType type, GOutputStream *out)
256{
257 guint i;
258 guint n_sigs;
259 guint *sig_ids;
260
261 sig_ids = g_signal_list_ids (type, &n_sigs);
262 for (i = 0; i < n_sigs; i++)
263 {
264 guint sigid;
265 GSignalQuery query;
266 guint j;
267
268 sigid = sig_ids[i];
269 g_signal_query (sigid, &query);
270
271 escaped_printf (out, " <signal name=\"%s\" return=\"%s\"",
272 query.signal_name, g_type_name (query.return_type));
273
274 if (query.signal_flags & G_SIGNAL_RUN_FIRST)
275 escaped_printf (out, " when=\"first\"");
276 else if (query.signal_flags & G_SIGNAL_RUN_LAST)
277 escaped_printf (out, " when=\"last\"");
278 else if (query.signal_flags & G_SIGNAL_RUN_CLEANUP)
279 escaped_printf (out, " when=\"cleanup\"");
280#if GLIB_CHECK_VERSION(2, 29, 15)(2 > (2) || (2 == (2) && 78 > (29)) || (2 == (2
) && 78 == (29) && 3 >= (15)))
281 else if (query.signal_flags & G_SIGNAL_MUST_COLLECT)
282 escaped_printf (out, " when=\"must-collect\"");
283#endif
284 if (query.signal_flags & G_SIGNAL_NO_RECURSE)
285 escaped_printf (out, " no-recurse=\"1\"");
286
287 if (query.signal_flags & G_SIGNAL_DETAILED)
288 escaped_printf (out, " detailed=\"1\"");
289
290 if (query.signal_flags & G_SIGNAL_ACTION)
291 escaped_printf (out, " action=\"1\"");
292
293 if (query.signal_flags & G_SIGNAL_NO_HOOKS)
294 escaped_printf (out, " no-hooks=\"1\"");
295
296 goutput_write (out, ">\n");
297
298 for (j = 0; j < query.n_params; j++)
299 {
300 escaped_printf (out, " <param type=\"%s\"/>\n",
301 g_type_name (query.param_types[j]));
302 }
303 goutput_write (out, " </signal>\n");
304 }
305 g_free (sig_ids);
306}
307
308static void
309dump_object_type (GType type, const char *symbol, GOutputStream *out)
310{
311 guint n_interfaces;
312 guint i;
313 GType *interfaces;
314
315 escaped_printf (out, " <class name=\"%s\" get-type=\"%s\"",
316 g_type_name (type), symbol);
317 if (type != G_TYPE_OBJECT((GType) ((20) << (2))))
318 {
319 GString *parent_str;
320 GType parent;
321 gboolean first = TRUE(!(0));
322
323 parent = g_type_parent (type);
324 parent_str = g_string_new ("");
325 while (parent != G_TYPE_INVALID((GType) ((0) << (2))))
326 {
327 if (first)
328 first = FALSE(0);
329 else
330 g_string_append_c (parent_str, ',')g_string_append_c_inline (parent_str, ',');
331 g_string_append (parent_str, g_type_name (parent))(__builtin_constant_p (g_type_name (parent)) ? __extension__ (
{ const char * const __val = (g_type_name (parent)); g_string_append_len_inline
(parent_str, __val, (__val != ((void*)0)) ? (gssize) strlen (
((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(parent_str, g_type_name (parent), (gssize) -1))
;
332 parent = g_type_parent (parent);
333 }
334
335 escaped_printf (out, " parents=\"%s\"", parent_str->str);
336
337 g_string_free (parent_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(parent_str), ((!(0)))) : g_string_free_and_steal (parent_str
)) : (g_string_free) ((parent_str), ((!(0)))))
;
338 }
339
340 if (G_TYPE_IS_ABSTRACT (type)(g_type_test_flags ((type), G_TYPE_FLAG_ABSTRACT)))
341 escaped_printf (out, " abstract=\"1\"");
342
343#if GLIB_CHECK_VERSION (2, 70, 0)(2 > (2) || (2 == (2) && 78 > (70)) || (2 == (2
) && 78 == (70) && 3 >= (0)))
344 if (G_TYPE_IS_FINAL (type)(g_type_test_flags ((type), G_TYPE_FLAG_FINAL)))
345 escaped_printf (out, " final=\"1\"");
346#endif
347
348 goutput_write (out, ">\n");
349
350 interfaces = g_type_interfaces (type, &n_interfaces);
351 for (i = 0; i < n_interfaces; i++)
352 {
353 GType itype = interfaces[i];
354 escaped_printf (out, " <implements name=\"%s\"/>\n",
355 g_type_name (itype));
356 }
357 g_free (interfaces);
358
359 dump_properties (type, out);
360 dump_signals (type, out);
361 goutput_write (out, " </class>\n");
362}
363
364static void
365dump_interface_type (GType type, const char *symbol, GOutputStream *out)
366{
367 guint n_interfaces;
368 guint i;
369 GType *interfaces;
370
371 escaped_printf (out, " <interface name=\"%s\" get-type=\"%s\">\n",
372 g_type_name (type), symbol);
373
374 interfaces = g_type_interface_prerequisites (type, &n_interfaces);
375 for (i = 0; i < n_interfaces; i++)
376 {
377 GType itype = interfaces[i];
378 if (itype == G_TYPE_OBJECT((GType) ((20) << (2))))
379 {
380 /* Treat this as implicit for now; in theory GInterfaces are
381 * supported on things like GstMiniObject, but right now
382 * the introspection system only supports GObject.
383 * http://bugzilla.gnome.org/show_bug.cgi?id=559706
384 */
385 continue;
386 }
387 escaped_printf (out, " <prerequisite name=\"%s\"/>\n",
388 g_type_name (itype));
389 }
390 g_free (interfaces);
391
392 dump_properties (type, out);
393 dump_signals (type, out);
394 goutput_write (out, " </interface>\n");
395}
396
397static void
398dump_boxed_type (GType type, const char *symbol, GOutputStream *out)
399{
400 escaped_printf (out, " <boxed name=\"%s\" get-type=\"%s\"/>\n",
401 g_type_name (type), symbol);
402}
403
404static void
405dump_flags_type (GType type, const char *symbol, GOutputStream *out)
406{
407 guint i;
408 GFlagsClass *klass;
409
410 klass = g_type_class_ref (type);
411 escaped_printf (out, " <flags name=\"%s\" get-type=\"%s\">\n",
412 g_type_name (type), symbol);
413
414 for (i = 0; i < klass->n_values; i++)
415 {
416 GFlagsValue *value = &(klass->values[i]);
417
418 escaped_printf (out, " <member name=\"%s\" nick=\"%s\" value=\"%u\"/>\n",
419 value->value_name, value->value_nick, value->value);
420 }
421 goutput_write (out, " </flags>\n");
422}
423
424static void
425dump_enum_type (GType type, const char *symbol, GOutputStream *out)
426{
427 guint i;
428 GEnumClass *klass;
429
430 klass = g_type_class_ref (type);
431 escaped_printf (out, " <enum name=\"%s\" get-type=\"%s\">\n",
432 g_type_name (type), symbol);
433
434 for (i = 0; i < klass->n_values; i++)
435 {
436 GEnumValue *value = &(klass->values[i]);
437
438 escaped_printf (out, " <member name=\"%s\" nick=\"%s\" value=\"%d\"/>\n",
439 value->value_name, value->value_nick, value->value);
440 }
441 goutput_write (out, " </enum>");
442}
443
444static void
445dump_fundamental_type (GType type, const char *symbol, GOutputStream *out)
446{
447 guint n_interfaces;
448 guint i;
449 GType *interfaces;
450 GString *parent_str;
451 GType parent;
452 gboolean first = TRUE(!(0));
453
454
455 escaped_printf (out, " <fundamental name=\"%s\" get-type=\"%s\"",
456 g_type_name (type), symbol);
457
458 if (G_TYPE_IS_ABSTRACT (type)(g_type_test_flags ((type), G_TYPE_FLAG_ABSTRACT)))
459 escaped_printf (out, " abstract=\"1\"");
460
461#if GLIB_CHECK_VERSION (2, 70, 0)(2 > (2) || (2 == (2) && 78 > (70)) || (2 == (2
) && 78 == (70) && 3 >= (0)))
462 if (G_TYPE_IS_FINAL (type)(g_type_test_flags ((type), G_TYPE_FLAG_FINAL)))
463 escaped_printf (out, " final=\"1\"");
464#endif
465
466 if (G_TYPE_IS_INSTANTIATABLE (type)(g_type_test_flags ((type), G_TYPE_FLAG_INSTANTIATABLE)))
467 escaped_printf (out, " instantiatable=\"1\"");
468
469 parent = g_type_parent (type);
470 parent_str = g_string_new ("");
471 while (parent != G_TYPE_INVALID((GType) ((0) << (2))))
472 {
473 if (first)
474 first = FALSE(0);
475 else
476 g_string_append_c (parent_str, ',')g_string_append_c_inline (parent_str, ',');
477 if (!g_type_name (parent))
478 break;
479 g_string_append (parent_str, g_type_name (parent))(__builtin_constant_p (g_type_name (parent)) ? __extension__ (
{ const char * const __val = (g_type_name (parent)); g_string_append_len_inline
(parent_str, __val, (__val != ((void*)0)) ? (gssize) strlen (
((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(parent_str, g_type_name (parent), (gssize) -1))
;
480 parent = g_type_parent (parent);
481 }
482
483 if (parent_str->len > 0)
484 escaped_printf (out, " parents=\"%s\"", parent_str->str);
485 g_string_free (parent_str, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(parent_str), ((!(0)))) : g_string_free_and_steal (parent_str
)) : (g_string_free) ((parent_str), ((!(0)))))
;
486
487 goutput_write (out, ">\n");
488
489 interfaces = g_type_interfaces (type, &n_interfaces);
490 for (i = 0; i < n_interfaces; i++)
491 {
492 GType itype = interfaces[i];
493 escaped_printf (out, " <implements name=\"%s\"/>\n",
494 g_type_name (itype));
495 }
496 g_free (interfaces);
497 goutput_write (out, " </fundamental>\n");
498}
499
500static void
501dump_type (GType type, const char *symbol, GOutputStream *out)
502{
503 switch (g_type_fundamental (type))
504 {
505 case G_TYPE_OBJECT((GType) ((20) << (2))):
506 dump_object_type (type, symbol, out);
507 break;
508 case G_TYPE_INTERFACE((GType) ((2) << (2))):
509 dump_interface_type (type, symbol, out);
510 break;
511 case G_TYPE_BOXED((GType) ((18) << (2))):
512 dump_boxed_type (type, symbol, out);
513 break;
514 case G_TYPE_FLAGS((GType) ((13) << (2))):
515 dump_flags_type (type, symbol, out);
516 break;
517 case G_TYPE_ENUM((GType) ((12) << (2))):
518 dump_enum_type (type, symbol, out);
519 break;
520 case G_TYPE_POINTER((GType) ((17) << (2))):
521 /* GValue, etc. Just skip them. */
522 break;
523 default:
524 dump_fundamental_type (type, symbol, out);
525 break;
526 }
527}
528
529static void
530dump_error_quark (GQuark quark, const char *symbol, GOutputStream *out)
531{
532 escaped_printf (out, " <error-quark function=\"%s\" domain=\"%s\"/>\n",
533 symbol, g_quark_to_string (quark));
534}
535
536/**
537 * g_irepository_dump:
538 * @arg: Comma-separated pair of input and output filenames
539 * @error: a %GError
540 *
541 * Argument specified is a comma-separated pair of filenames; i.e. of
542 * the form "input.txt,output.xml". The input file should be a
543 * UTF-8 Unix-line-ending text file, with each line containing either
544 * "get-type:" followed by the name of a GType _get_type function, or
545 * "error-quark:" followed by the name of an error quark function. No
546 * extra whitespace is allowed.
547 *
548 * The output file should already exist, but be empty. This function will
549 * overwrite its contents.
550 *
551 * Returns: %TRUE on success, %FALSE on error
552 */
553#ifndef G_IREPOSITORY_COMPILATION
554static gboolean
555dump_irepository (const char *arg, GError **error) G_GNUC_UNUSED__attribute__ ((__unused__));
556static gboolean
557dump_irepository (const char *arg, GError **error)
558#else
559gboolean
560g_irepository_dump (const char *arg, GError **error)
561#endif
562{
563 GHashTable *output_types;
564 char **args;
565 GFile *input_file;
566 GFile *output_file;
567 GFileInputStream *input;
568 GFileOutputStream *output;
569 GDataInputStream *in;
570 GModule *self;
571 gboolean caught_error = FALSE(0);
572
573 self = g_module_open (NULL((void*)0), 0);
574 if (!self)
575 {
576 g_set_error (error,
577 G_IO_ERRORg_io_error_quark(),
578 G_IO_ERROR_FAILED,
579 "failed to open self: %s",
580 g_module_error ());
581 return FALSE(0);
582 }
583
584 args = g_strsplit (arg, ",", 2);
585
586 input_file = g_file_new_for_path (args[0]);
587 output_file = g_file_new_for_path (args[1]);
588
589 g_strfreev (args);
590
591 input = g_file_read (input_file, NULL((void*)0), error);
592 g_object_unref (input_file);
593
594 if (input == NULL((void*)0))
595 {
596 g_object_unref (output_file);
597 return FALSE(0);
598 }
599
600 output = g_file_replace (output_file, NULL((void*)0), FALSE(0), 0, NULL((void*)0), error);
601 g_object_unref (output_file);
602
603 if (output == NULL((void*)0))
604 {
605 g_input_stream_close (G_INPUT_STREAM (input)((((GInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((input)), ((g_input_stream_get_type ()))))))
, NULL((void*)0), NULL((void*)0));
606 g_object_unref (input);
607 return FALSE(0);
608 }
609
610 goutput_write (G_OUTPUT_STREAM (output)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), ((g_output_stream_get_type ()))))))
, "<?xml version=\"1.0\"?>\n");
611 goutput_write (G_OUTPUT_STREAM (output)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), ((g_output_stream_get_type ()))))))
, "<dump>\n");
612
613 output_types = g_hash_table_new (NULL((void*)0), NULL((void*)0));
614
615 in = g_data_input_stream_new (G_INPUT_STREAM (input)((((GInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((input)), ((g_input_stream_get_type ()))))))
);
616 g_object_unref (input);
617
618 while (TRUE(!(0)))
619 {
620 gsize len;
621 char *line = g_data_input_stream_read_line (in, &len, NULL((void*)0), NULL((void*)0));
622 const char *function;
623
624 if (line == NULL((void*)0) || *line == '\0')
625 {
626 g_free (line);
627 break;
628 }
629
630 g_strchomp (line);
631
632 if (strncmp (line, "get-type:", strlen ("get-type:")) == 0)
633 {
634 GType type;
635
636 function = line + strlen ("get-type:");
637
638 type = invoke_get_type (self, function, error);
639
640 if (type == G_TYPE_INVALID((GType) ((0) << (2))))
641 {
642 g_printerr ("Invalid GType function: '%s'\n", function);
643 caught_error = TRUE(!(0));
644 g_free (line);
645 break;
646 }
647
648 if (g_hash_table_lookup (output_types, (gpointer) type))
649 goto next;
650 g_hash_table_insert (output_types, (gpointer) type, (gpointer) type);
651
652 dump_type (type, function, G_OUTPUT_STREAM (output)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), ((g_output_stream_get_type ()))))))
);
653 }
654 else if (strncmp (line, "error-quark:", strlen ("error-quark:")) == 0)
655 {
656 GQuark quark;
657 function = line + strlen ("error-quark:");
658 quark = invoke_error_quark (self, function, error);
659
660 if (quark == 0)
661 {
662 g_printerr ("Invalid error quark function: '%s'\n", function);
663 caught_error = TRUE(!(0));
664 g_free (line);
665 break;
666 }
667
668 dump_error_quark (quark, function, G_OUTPUT_STREAM (output)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), ((g_output_stream_get_type ()))))))
);
669 }
670
671
672 next:
673 g_free (line);
674 }
675
676 g_hash_table_destroy (output_types);
677
678 goutput_write (G_OUTPUT_STREAM (output)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), ((g_output_stream_get_type ()))))))
, "</dump>\n");
679
680 {
681 /* Avoid overwriting an earlier set error */
682 caught_error |= !g_input_stream_close (G_INPUT_STREAM (in)((((GInputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((in)), ((g_input_stream_get_type ()))))))
, NULL((void*)0),
683 caught_error ? NULL((void*)0) : error);
684 caught_error |= !g_output_stream_close (G_OUTPUT_STREAM (output)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((output)), ((g_output_stream_get_type ()))))))
, NULL((void*)0),
685 caught_error ? NULL((void*)0) : error);
686 }
687
688 g_object_unref (in);
689 g_object_unref (output);
690
691 return !caught_error;
692}
693
694
695int
696main(int argc, char **argv)
697{
698 GError *error = NULL((void*)0);
699 const char *introspect_dump_prefix = "--introspect-dump=";
700
701#if !GLIB_CHECK_VERSION(2,35,0)(2 > (2) || (2 == (2) && 78 > (35)) || (2 == (2
) && 78 == (35) && 3 >= (0)))
702 g_type_init ();
703#endif
704
705
706
707 if (argc != 2 || !g_str_has_prefix (argv[1], introspect_dump_prefix)(__builtin_constant_p (introspect_dump_prefix)? __extension__
({ const char * const __str = (argv[1]); const char * const __prefix
= (introspect_dump_prefix); gboolean __result = (0); if (__str
== ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix
) (__str, __prefix); else { const size_t __str_len = strlen (
((__str) + !(__str))); const size_t __prefix_len = strlen (((
__prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result
= memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len
) == 0; } __result; }) : (g_str_has_prefix) (argv[1], introspect_dump_prefix
) )
)
708 {
709 g_printerr ("Usage: %s --introspect-dump=input,output", argv[0]);
710 exit (1);
711 }
712
713 if (!dump_irepository (argv[1] + strlen(introspect_dump_prefix), &error))
714 {
715 g_printerr ("%s\n", error->message);
716 exit (1);
717 }
718 exit (0);
719}
720extern GType mate_desktop_item_get_type(void);
721extern GType mate_desktop_thumbnail_factory_get_type(void);
722extern GType mate_bg_crossfade_get_type(void);
723extern GType mate_bg_get_type(void);
724extern GType mate_rr_screen_get_type(void);
725extern GType mate_rr_output_get_type(void);
726extern GType mate_rr_crtc_get_type(void);
727extern GType mate_rr_mode_get_type(void);
728extern GType mate_rr_output_info_get_type(void);
729extern GType mate_rr_config_get_type(void);
730extern GType mate_rr_labeler_get_type(void);
731extern GType mate_color_selection_get_type(void);
732extern GType mate_hsv_get_type(void);
733extern GType mate_color_selection_dialog_get_type(void);
734extern GType mate_image_menu_item_get_type(void);
735G_MODULE_EXPORT__attribute__((visibility("default"))) GType (*GI_GET_TYPE_FUNCS_[])(void) = {
736 mate_desktop_item_get_type,
737 mate_desktop_thumbnail_factory_get_type,
738 mate_bg_crossfade_get_type,
739 mate_bg_get_type,
740 mate_rr_screen_get_type,
741 mate_rr_output_get_type,
742 mate_rr_crtc_get_type,
743 mate_rr_mode_get_type,
744 mate_rr_output_info_get_type,
745 mate_rr_config_get_type,
746 mate_rr_labeler_get_type,
747 mate_color_selection_get_type,
748 mate_hsv_get_type,
749 mate_color_selection_dialog_get_type,
750 mate_image_menu_item_get_type
751};
752extern GQuark mate_desktop_item_error_quark(void);
753extern GQuark mate_rr_error_quark(void);
754G_MODULE_EXPORT__attribute__((visibility("default"))) GQuark (*GI_ERROR_QUARK_FUNCS_[])(void) = {
755 mate_desktop_item_error_quark,
756 mate_rr_error_quark
757};
diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/scanview.css b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/scanview.css new file mode 100644 index 0000000..cf8a5a6 --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/sorttable.js b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/sorttable.js new file mode 100644 index 0000000..32faa07 --- /dev/null +++ b/2024-04-04-053707-5943-1@1192002dd454_wayland-bg-thumbnail/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write("