1
2 /* -*- mode: C; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
3 /*
4 * Copyright (C) 2011 Tiger Soldier <tigersoldier@gmail.com>
5 *
6 * This file is part of OSD Lyrics.
7 *
8 * OSD Lyrics is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * OSD Lyrics is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with OSD Lyrics. If not, see <http://www.gnu.org/licenses/>.
20 */
21 #include <string.h>
22 #include "ol_app_info.h"
23 #include "ol_intl.h"
24 #include "ol_debug.h"
25
26 struct _OlAppInfo
27 {
28 GObject parent;
29 gchar *cmdline;
30 gchar *name;
31 GIcon *icon;
32 gchar *binfile;
33 gboolean should_show;
34 };
35
36 static gchar *_str_join_argv (gchar **argv);
37 static gboolean _shell_arg_need_quote (const gchar *arg);
38 static gchar *_find_binfile (const gchar *binfile, gboolean match_prefix);
39 static gchar *_find_file_in_path_list (GList *path_list,
40 const gchar *prefix,
41 const gchar *suffix,
42 gboolean match_prefix,
43 gboolean (*file_test_func) (const gchar *));
44 static gboolean _file_is_executable (const gchar *filename);
45 static gboolean _file_exists (const gchar *filename);
46 static GIcon *_icon_new_from_name (const gchar *icon_name);
47 static void _app_info_set_from_desktop_file (OlAppInfo *info,
48 enum OlAppInfoFlags flags);
49 static void ol_app_info_finalize (GObject *object);
50 static void ol_app_info_iface_init (GAppInfoIface *iface);
51 static void ol_app_info_class_init (OlAppInfoClass *klass);
52 static void ol_app_info_init (OlAppInfo *info);
53 static void _strv_replace (gchar **argv,
54 guint index,
55 const gchar *new_value);
56 static GList *_get_desktop_file_path_list ();
57 static gpointer _get_desktop_file_path_list_once (gpointer data);
58 static GList *_prepend_subdirs (GList *list);
59 /* -----------GAppInfo interfaces--------------- */
60 static GAppInfo *_app_info_dup (GAppInfo *appinfo);
61 static gboolean _app_info_equal (GAppInfo *appinfo1,
62 GAppInfo *appinfo2);
63 static const char *_app_info_get_id (GAppInfo *appinfo);
64 static const char *_app_info_get_name (GAppInfo *appinfo);
65 static const char *_app_info_get_display_name (GAppInfo *appinfo);
66 static const char *_app_info_get_description (GAppInfo *appinfo);
67 static const char *_app_info_get_executable (GAppInfo *appinfo);
68 static const char *_app_info_get_commandline (GAppInfo *appinfo);
69 static GIcon *_app_info_get_icon (GAppInfo *appinfo);
70 static gboolean _app_info_launch (GAppInfo *appinfo,
71 GList *files,
72 GAppLaunchContext *launch_context,
73 GError **error);
74 static gboolean _app_info_supports_uris (GAppInfo *appinfo);
75 static gboolean _app_info_supports_files (GAppInfo *appinfo);
76 static gboolean _app_info_launch_uris (GAppInfo *appinfo,
77 GList *uris,
78 GAppLaunchContext *launch_context,
79 GError **error);
80 static gboolean _app_info_should_show (GAppInfo *appinfo);
81 static gboolean _app_info_set_as_default_for_type (GAppInfo *appinfo,
82 const char *content_type,
83 GError **error);
84 static gboolean _app_info_set_as_default_for_extension (GAppInfo *appinfo,
85 const char *extension,
86 GError **error);
87 static gboolean _app_info_add_supports_type (GAppInfo *appinfo,
88 const char *content_type,
89 GError **error);
90 static gboolean _app_info_can_remove_supports_type (GAppInfo *appinfo);
91 static gboolean _app_info_remove_supports_type (GAppInfo *appinfo,
92 const char *content_type,
93 GError **error);
94 static gboolean _app_info_can_delete (GAppInfo *appinfo);
95 static gboolean _app_info_do_delete (GAppInfo *appinfo);
96
97 G_DEFINE_TYPE_WITH_CODE (OlAppInfo, ol_app_info, G_TYPE_OBJECT,
98 G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO,
99 ol_app_info_iface_init));
100
101 static void
ol_app_info_class_init(OlAppInfoClass * klass)102 ol_app_info_class_init (OlAppInfoClass *klass)
103 {
104 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
105 gobject_class->finalize = ol_app_info_finalize;
106 }
107
108 static void
ol_app_info_init(OlAppInfo * info)109 ol_app_info_init (OlAppInfo *info)
110 {
111 }
112
113 static void
ol_app_info_iface_init(GAppInfoIface * iface)114 ol_app_info_iface_init (GAppInfoIface *iface)
115 {
116 iface->dup = _app_info_dup;
117 iface->equal = _app_info_equal;
118 iface->get_id = _app_info_get_id;
119 iface->get_name = _app_info_get_name;
120 iface->get_description = _app_info_get_description;
121 iface->get_executable = _app_info_get_executable;
122 iface->get_icon = _app_info_get_icon;
123 iface->launch = _app_info_launch;
124 iface->supports_uris = _app_info_supports_uris;
125 iface->supports_files = _app_info_supports_files;
126 iface->launch_uris = _app_info_launch_uris;
127 iface->should_show = _app_info_should_show;
128 iface->set_as_default_for_type = _app_info_set_as_default_for_type;
129 iface->set_as_default_for_extension = _app_info_set_as_default_for_extension;
130 iface->add_supports_type = _app_info_add_supports_type;
131 iface->can_remove_supports_type = _app_info_can_remove_supports_type;
132 iface->remove_supports_type = _app_info_remove_supports_type;
133 iface->can_delete = _app_info_can_delete;
134 iface->do_delete = _app_info_do_delete;
135 iface->get_commandline = _app_info_get_commandline;
136 iface->get_display_name = _app_info_get_display_name;
137 }
138
139 static GAppInfo *
_app_info_dup(GAppInfo * appinfo)140 _app_info_dup (GAppInfo *appinfo)
141 {
142 OlAppInfo *info = OL_APP_INFO (appinfo);
143 OlAppInfo *new_info;
144
145 new_info = g_object_new (OL_TYPE_APP_INFO, NULL);
146 new_info->cmdline = g_strdup (info->cmdline);
147 new_info->name = g_strdup (info->name);
148 new_info->binfile = g_strdup (info->binfile);
149 if (info->icon)
150 new_info->icon = g_object_ref (info->icon);
151 new_info->should_show = info->should_show;
152 return G_APP_INFO (new_info);
153 }
154
155 static gboolean
_app_info_equal(GAppInfo * appinfo1,GAppInfo * appinfo2)156 _app_info_equal (GAppInfo *appinfo1,
157 GAppInfo *appinfo2)
158 {
159 OlAppInfo *info1 = OL_APP_INFO (appinfo1);
160 OlAppInfo *info2 = OL_APP_INFO (appinfo2);
161
162 return strcmp (info1->cmdline, info2->cmdline) == 0;
163 }
164
165 static const char *
_app_info_get_id(GAppInfo * appinfo)166 _app_info_get_id (GAppInfo *appinfo)
167 {
168 OlAppInfo *info = OL_APP_INFO (appinfo);
169
170 return info->cmdline;
171 }
172
173 static const char *
_app_info_get_name(GAppInfo * appinfo)174 _app_info_get_name (GAppInfo *appinfo)
175 {
176 OlAppInfo *info = OL_APP_INFO (appinfo);
177
178 if (info->name == NULL)
179 return _("Unnamed");
180 return info->name;
181 }
182
183 static const char *
_app_info_get_display_name(GAppInfo * appinfo)184 _app_info_get_display_name (GAppInfo *appinfo)
185 {
186 OlAppInfo *info = OL_APP_INFO (appinfo);
187
188 if (info->name == NULL)
189 return _("Unnamed");
190 return info->name;
191 }
192
193 static const char *
_app_info_get_description(GAppInfo * appinfo)194 _app_info_get_description (GAppInfo *appinfo)
195 {
196 return "";
197 }
198
199 static const char *
_app_info_get_executable(GAppInfo * appinfo)200 _app_info_get_executable (GAppInfo *appinfo)
201 {
202 OlAppInfo *info = OL_APP_INFO (appinfo);
203
204 return info->binfile;
205 }
206
207 static const char *
_app_info_get_commandline(GAppInfo * appinfo)208 _app_info_get_commandline (GAppInfo *appinfo)
209 {
210 OlAppInfo *info = OL_APP_INFO (appinfo);
211
212 return info->cmdline;
213 }
214
215 static GIcon *
_app_info_get_icon(GAppInfo * appinfo)216 _app_info_get_icon (GAppInfo *appinfo)
217 {
218 OlAppInfo *info = OL_APP_INFO (appinfo);
219
220 return info->icon;
221 }
222
223 static gboolean
_app_info_launch(GAppInfo * appinfo,GList * files,GAppLaunchContext * launch_context,GError ** error)224 _app_info_launch (GAppInfo *appinfo,
225 GList *files,
226 GAppLaunchContext *launch_context,
227 GError **error)
228 {
229 OlAppInfo *info = OL_APP_INFO (appinfo);
230 /* TODO: implement launching. */
231 GAppInfo* app = g_app_info_create_from_commandline (info->cmdline, "", 0, NULL);
232 gboolean ret = g_app_info_launch (app, files, launch_context, error);
233 g_object_unref (G_OBJECT (app));
234 return ret;
235 }
236
237 static gboolean
_app_info_supports_uris(GAppInfo * appinfo)238 _app_info_supports_uris (GAppInfo *appinfo)
239 {
240 return FALSE;
241 }
242
243 static gboolean
_app_info_supports_files(GAppInfo * appinfo)244 _app_info_supports_files (GAppInfo *appinfo)
245 {
246 return FALSE;
247 }
248
249 static gboolean
_app_info_launch_uris(GAppInfo * appinfo,GList * uris,GAppLaunchContext * launch_context,GError ** error)250 _app_info_launch_uris (GAppInfo *appinfo,
251 GList *uris,
252 GAppLaunchContext *launch_context,
253 GError **error)
254 {
255 OlAppInfo *info = OL_APP_INFO (appinfo);
256 /* TODO: implement launching. */
257 GAppInfo* app = g_app_info_create_from_commandline (info->cmdline, "", 0, NULL);
258 gboolean ret = g_app_info_launch_uris (app, uris, launch_context, error);
259 g_object_unref (G_OBJECT (app));
260 return ret;
261 }
262
263 static gboolean
_app_info_should_show(GAppInfo * appinfo)264 _app_info_should_show (GAppInfo *appinfo)
265 {
266 OlAppInfo *info = OL_APP_INFO (appinfo);
267 return info->should_show;
268 }
269
270 static gboolean
_app_info_set_as_default_for_type(GAppInfo * appinfo,const char * content_type,GError ** error)271 _app_info_set_as_default_for_type (GAppInfo *appinfo,
272 const char *content_type,
273 GError **error)
274 {
275 if (error)
276 *error = g_error_new (g_quark_from_string ("OSD Lyrics"),
277 0, /* error code */
278 "OlAppInfo does not support set_as_default_for_type");
279 return FALSE;
280 }
281
282 static gboolean
_app_info_set_as_default_for_extension(GAppInfo * appinfo,const char * extension,GError ** error)283 _app_info_set_as_default_for_extension (GAppInfo *appinfo,
284 const char *extension,
285 GError **error)
286 {
287 if (error)
288 *error = g_error_new (g_quark_from_string ("OSD Lyrics"),
289 0, /* error code */
290 "OlAppInfo does not support set_as_default_for_extension");
291 return FALSE;
292 }
293
294 static gboolean
_app_info_add_supports_type(GAppInfo * appinfo,const char * content_type,GError ** error)295 _app_info_add_supports_type (GAppInfo *appinfo,
296 const char *content_type,
297 GError **error)
298 {
299 if (error)
300 *error = g_error_new (g_quark_from_string ("OSD Lyrics"),
301 0, /* error code */
302 "OlAppInfo does not support add_supports_type");
303 return FALSE;
304 }
305
306 static gboolean
_app_info_can_remove_supports_type(GAppInfo * appinfo)307 _app_info_can_remove_supports_type (GAppInfo *appinfo)
308 {
309 return FALSE;
310 }
311
312 static gboolean
_app_info_remove_supports_type(GAppInfo * appinfo,const char * content_type,GError ** error)313 _app_info_remove_supports_type (GAppInfo *appinfo,
314 const char *content_type,
315 GError **error)
316 {
317 if (error)
318 *error = g_error_new (g_quark_from_string ("OSD Lyrics"),
319 0, /* error code */
320 "OlAppInfo does not support remove_supports_type");
321 return FALSE;
322 }
323
324 static gboolean
_app_info_can_delete(GAppInfo * appinfo)325 _app_info_can_delete (GAppInfo *appinfo)
326 {
327 return FALSE;
328 }
329
330 static gboolean
_app_info_do_delete(GAppInfo * appinfo)331 _app_info_do_delete (GAppInfo *appinfo)
332 {
333 return FALSE;
334 }
335
336 OlAppInfo *
ol_app_info_new(const char * cmdline,const char * name,const char * icon_name,enum OlAppInfoFlags flags,GError ** error)337 ol_app_info_new (const char *cmdline,
338 const char *name,
339 const char *icon_name,
340 enum OlAppInfoFlags flags,
341 GError **error)
342 {
343 if (cmdline == NULL)
344 {
345 if (error)
346 *error = g_error_new (g_quark_from_string ("OSD Lyrics"),
347 0,
348 "cmdline cannot be NULL");
349 return NULL;
350 }
351 int cmd_index = 0;
352 if (flags & OL_APP_INFO_SECOND_IS_EXEC)
353 cmd_index = 1;
354 gchar **argv = NULL;
355 gint argc = 0;
356 GError *parse_error = NULL;
357 if (!g_shell_parse_argv (cmdline, &argc, &argv, &parse_error))
358 {
359 if (error)
360 *error = g_error_new (g_quark_from_string ("OSD Lyrics"),
361 0,
362 "Cannot parse cmdline: %s", parse_error->message);
363 g_error_free (parse_error);
364 return NULL;
365 }
366 if (argc <= cmd_index)
367 {
368 if (error)
369 *error = g_error_new (g_quark_from_string ("OSD Lyrics"),
370 0,
371 "Command name is required in cmdline");
372 g_strfreev (argv);
373 return NULL;
374 }
375 OlAppInfo *info = g_object_new (OL_TYPE_APP_INFO, NULL);
376 info->binfile = _find_binfile (argv[cmd_index],
377 (flags & OL_APP_INFO_WITH_PREFIX) != 0);
378 if (info->binfile == NULL)
379 {
380 info->binfile = g_strdup (argv[cmd_index]);
381 info->cmdline = g_strdup (cmdline);
382 info->should_show = FALSE;
383 }
384 else
385 {
386 info->should_show = TRUE;
387 _strv_replace (argv, cmd_index, info->binfile);
388 info->cmdline = _str_join_argv (argv);
389 }
390 if (!name)
391 name = info->binfile;
392 if (!icon_name)
393 icon_name = info->binfile;
394 info->icon = _icon_new_from_name (icon_name);
395 info->name = g_strdup (name);
396 if (flags & OL_APP_INFO_PREFER_DESKTOP_FILE)
397 _app_info_set_from_desktop_file (info, flags);
398 return info;
399 }
400
401 static gchar *
_str_join_argv(gchar ** argv)402 _str_join_argv (gchar **argv)
403 {
404 GString *str_builder = g_string_new ("");
405 gboolean first = TRUE;
406 while (argv && *argv)
407 {
408 if (!first)
409 g_string_append_c (str_builder, ' ');
410 else
411 first = FALSE;
412 if (_shell_arg_need_quote (*argv))
413 {
414 gchar *quoted = g_shell_quote (*argv);
415 g_string_append (str_builder, quoted);
416 g_free (quoted);
417 }
418 else
419 {
420 g_string_append (str_builder, *argv);
421 }
422 argv++;
423 }
424 return g_string_free (str_builder, FALSE);
425 }
426
427 static gboolean
_shell_arg_need_quote(const gchar * arg)428 _shell_arg_need_quote (const gchar *arg)
429 {
430 if (arg == NULL)
431 return FALSE;
432 if (!strchr (arg, ' ') && !strchr (arg, '\t') && !strchr (arg, '\n') &&
433 !strchr (arg, '\'') && !strchr (arg, '\"') && !strchr (arg, '\\'))
434 return FALSE;
435 else
436 return TRUE;
437 }
438
439 static gchar *
_find_binfile(const gchar * binfile,gboolean match_prefix)440 _find_binfile (const gchar *binfile, gboolean match_prefix)
441 {
442 GList *path_list = NULL;
443 gchar *ret = NULL;
444 if (g_path_is_absolute (binfile))
445 {
446 gchar *dirname = g_path_get_dirname (binfile);
447 path_list = g_list_append (path_list, dirname);
448 binfile += strlen (dirname);
449 if (*binfile == G_DIR_SEPARATOR)
450 binfile++;
451 }
452 else
453 {
454 const char *env_path = g_getenv ("PATH");
455 if (!env_path)
456 {
457 env_path = "/bin:/usr/bin";
458 }
459 gchar **pathv = g_strsplit (env_path, G_SEARCHPATH_SEPARATOR_S, -1);
460 gchar **pathiter;
461 for (pathiter = pathv; *pathiter != NULL; pathiter++)
462 {
463 if (*pathiter != '\0')
464 path_list = g_list_prepend (path_list, g_strdup (*pathiter));
465 }
466 path_list = g_list_reverse (path_list);
467 g_strfreev (pathv);
468 }
469 gchar *filepath = _find_file_in_path_list (path_list,
470 binfile,
471 "",
472 match_prefix,
473 _file_is_executable);
474 if (filepath)
475 {
476 ret = g_path_get_basename (filepath);
477 g_free (filepath);
478 }
479 for (; path_list != NULL; path_list = g_list_delete_link (path_list, path_list))
480 g_free (path_list->data);
481 return ret;
482 }
483
484 /**
485 *
486 *
487 * @param path_list A GList of gchar*.
488 * @param prefix The prefix of the filename, cannot be #NULL.
489 * @param suffix The suffix of filename. If #match_prefix is #TRUE, #NULL or
490 * empty string means any suffix is acceptable.
491 * @param match_prefix
492 *
493 * @return
494 */
495 static gchar *
_find_file_in_path_list(GList * path_list,const gchar * prefix,const gchar * suffix,gboolean match_prefix,gboolean (* file_test_func)(const gchar *))496 _find_file_in_path_list (GList *path_list,
497 const gchar *prefix,
498 const gchar *suffix,
499 gboolean match_prefix,
500 gboolean (*file_test_func) (const gchar *))
501 {
502 ol_assert_ret (prefix != NULL, NULL);
503 if (suffix == NULL)
504 suffix = "";
505 if (!file_test_func)
506 file_test_func = _file_exists;
507 GList *pathiter;
508 gchar *ret = NULL;
509 for (pathiter = path_list; pathiter != NULL; pathiter = g_list_next (pathiter))
510 {
511 gchar *path = pathiter->data;
512 if (!match_prefix)
513 {
514 gchar *filename = NULL;
515 gchar *fullname = g_strdup_printf ("%s%s", prefix, suffix);
516 filename = g_build_filename (path, fullname, NULL);
517 g_free (fullname);
518 if (file_test_func (filename))
519 ret = filename;
520 else
521 g_free (filename);
522 } /* if !match_prefix */
523 else
524 {
525 GError *error = NULL;
526 GDir *dir = g_dir_open (path, 0, &error);
527 if (!dir)
528 {
529 ol_errorf ("Cannot open path %s: %s\n", path, error->message);
530 g_error_free (error);
531 continue;
532 }
533 const gchar *name;
534 while ((name = g_dir_read_name (dir)) != NULL)
535 {
536 if (g_str_has_prefix (name, prefix) && g_str_has_suffix (name, suffix))
537 {
538 gchar *filename = g_build_filename (path, name, NULL);
539 if (file_test_func (filename) &&
540 (!ret || strcmp (filename, ret) < 0))
541 {
542 g_free (ret);
543 ret = filename;
544 }
545 else
546 {
547 g_free (filename);
548 }
549 }
550 }
551 g_dir_close (dir);
552 }
553 if (ret != NULL) break;
554 }
555 return ret;
556 }
557
558 static gboolean
_file_is_executable(const gchar * filename)559 _file_is_executable (const gchar *filename)
560 {
561 return (g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE) &&
562 !g_file_test (filename, G_FILE_TEST_IS_DIR));
563 }
564
565 static gboolean
_file_exists(const gchar * filename)566 _file_exists (const gchar *filename)
567 {
568 return (g_file_test (filename, G_FILE_TEST_EXISTS) &&
569 !g_file_test (filename, G_FILE_TEST_IS_DIR));
570 }
571
572 static GIcon *
_icon_new_from_name(const gchar * icon_name)573 _icon_new_from_name (const gchar *icon_name)
574 {
575 ol_assert_ret (icon_name != NULL, NULL);
576 /* This is taken from gdesktopappinfo.c of GIO */
577 GIcon *icon = NULL;
578 if (g_path_is_absolute (icon_name))
579 {
580 GFile *file;
581 file = g_file_new_for_path (icon_name);
582 icon = g_file_icon_new (file);
583 g_object_unref (file);
584 }
585 else
586 {
587 char *p;
588 /* Work around a common mistake in desktop files */
589 if ((p = strrchr (icon_name, '.')) != NULL &&
590 (strcmp (p, ".png") == 0 ||
591 strcmp (p, ".xpm") == 0 ||
592 strcmp (p, ".svg") == 0))
593 {
594 gchar *real_name = g_strndup (icon_name, p - icon_name);
595 icon = g_themed_icon_new (real_name);
596 g_free (real_name);
597 }
598 else
599 {
600 icon = g_themed_icon_new (icon_name);
601 }
602 }
603 return icon;
604 }
605
606 static void
_app_info_set_from_desktop_file(OlAppInfo * info,enum OlAppInfoFlags flags)607 _app_info_set_from_desktop_file (OlAppInfo *info,
608 enum OlAppInfoFlags flags)
609 {
610 GList *path_list = _get_desktop_file_path_list ();
611 gchar *filename = _find_file_in_path_list (path_list,
612 info->binfile,
613 ".desktop",
614 (flags & OL_APP_INFO_WITH_PREFIX) != 0,
615 NULL);
616 if (!filename)
617 {
618 ol_debugf ("Cannot find desktop file for %s\n", info->binfile);
619 return;
620 }
621 GKeyFile *keyfile = g_key_file_new ();
622 GError *error = NULL;
623 if (!g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, &error))
624 {
625 ol_errorf ("Cannot open desktop file %s: %s\n", filename, error->message);
626 g_error_free (error);
627 }
628 else
629 {
630 if (flags & OL_APP_INFO_USE_DESKTOP_NAME)
631 {
632 gchar *name = g_key_file_get_locale_string (keyfile,
633 G_KEY_FILE_DESKTOP_GROUP,
634 G_KEY_FILE_DESKTOP_KEY_NAME,
635 NULL,
636 NULL);
637 if (name != NULL)
638 {
639 if (info->name != NULL)
640 g_free (info->name);
641 info->name = name;
642 }
643 }
644 if (flags & OL_APP_INFO_USE_DESKTOP_CMDLINE)
645 {
646 gchar *cmdline = g_key_file_get_locale_string (keyfile,
647 G_KEY_FILE_DESKTOP_GROUP,
648 G_KEY_FILE_DESKTOP_KEY_EXEC,
649 NULL,
650 NULL);
651 if (cmdline != NULL)
652 {
653 if (info->cmdline != NULL)
654 g_free (info->cmdline);
655 info->cmdline = cmdline;
656 }
657 }
658 if (flags & OL_APP_INFO_USE_DESKTOP_ICON)
659 {
660 gchar *icon_name = g_key_file_get_locale_string (keyfile,
661 G_KEY_FILE_DESKTOP_GROUP,
662 G_KEY_FILE_DESKTOP_KEY_ICON,
663 NULL,
664 NULL);
665 GIcon *icon = _icon_new_from_name (icon_name);
666 if (icon != NULL)
667 {
668 if (info->icon != NULL)
669 g_object_unref (info->icon);
670 info->icon = icon;
671 }
672 }
673 info->should_show = !g_key_file_get_boolean (keyfile,
674 G_KEY_FILE_DESKTOP_GROUP,
675 G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY,
676 NULL);
677 }
678 g_free (filename);
679 g_key_file_free (keyfile);
680 }
681
682 static void
ol_app_info_finalize(GObject * object)683 ol_app_info_finalize (GObject *object)
684 {
685 OlAppInfo *info = OL_APP_INFO (object);
686 if (info->name)
687 {
688 g_free (info->name);
689 info->name = NULL;
690 }
691 if (info->cmdline)
692 {
693 g_free (info->cmdline);
694 info->cmdline = NULL;
695 }
696 if (info->binfile)
697 {
698 g_free (info->binfile);
699 info->binfile = NULL;
700 }
701 if (info->icon)
702 {
703 g_object_unref (info->icon);
704 info->icon = NULL;
705 }
706 G_OBJECT_CLASS (ol_app_info_parent_class)->finalize (object);
707 }
708
709 static void
_strv_replace(gchar ** argv,guint index,const gchar * new_value)710 _strv_replace (gchar **argv, guint index, const gchar *new_value)
711 {
712 g_free (argv[index]);
713 argv[index] = g_strdup (new_value);
714 }
715
716 /**
717 * Returns the list of paths to find desktop files.
718 *
719 *
720 * @return A GList of gchar*. Should NOT be freed.
721 */
722 static GList *
_get_desktop_file_path_list()723 _get_desktop_file_path_list ()
724 {
725 GOnce once = G_ONCE_INIT;
726 g_once (&once, _get_desktop_file_path_list_once, NULL);
727 return (GList*) once.retval;
728 }
729
730 static gpointer
_get_desktop_file_path_list_once(gpointer data)731 _get_desktop_file_path_list_once (gpointer data)
732 {
733 GList *list = NULL;
734 list = g_list_prepend (list,
735 g_build_filename (g_get_user_data_dir(),
736 "applications",
737 NULL));
738 list = _prepend_subdirs (list);
739 const gchar * const * data_dirs = g_get_system_data_dirs ();
740 while (*data_dirs != NULL)
741 {
742 list = g_list_prepend (list,
743 g_build_filename (*data_dirs, "applications", NULL));
744 list = _prepend_subdirs (list);
745 data_dirs++;
746 }
747 return g_list_reverse (list);
748 }
749
750 static GList *
_prepend_subdirs(GList * list)751 _prepend_subdirs (GList *list)
752 {
753 gchar *path = list->data;
754 GError *error = NULL;
755 GDir *dir = g_dir_open (path, 0, &error);
756 if (!dir)
757 {
758 ol_errorf ("Cannot open dir %s: %s\n", path, error->message);
759 g_error_free (error);
760 return list;
761 }
762 const gchar *name;
763 while ((name = g_dir_read_name (dir)) != NULL)
764 {
765 gchar *filepath = g_build_filename (path, name, NULL);
766 if (g_file_test (filepath, G_FILE_TEST_IS_DIR))
767 {
768 list = g_list_prepend (list, filepath);
769 list = _prepend_subdirs (list);
770 }
771 else
772 {
773 g_free (filepath);
774 }
775 }
776 g_dir_close (dir);
777 return list;
778 }
779