2
* Copyright (C) 2002 - 2004 Red Hat, Inc.
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library; if not, write to the
16
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
* Boston, MA 02111-1307, USA.
22
#include "desktop-entries.h"
26
#include "menu-util.h"
28
#define DESKTOP_ENTRY_GROUP "Desktop Entry"
29
#define KDE_DESKTOP_ENTRY_GROUP "KDE Desktop Entry"
33
DESKTOP_ENTRY_NO_DISPLAY = 1 << 0,
34
DESKTOP_ENTRY_HIDDEN = 1 << 1,
35
DESKTOP_ENTRY_SHOW_IN_GNOME = 1 << 2,
36
DESKTOP_ENTRY_TRYEXEC_FAILED = 1 << 3
59
struct DesktopEntrySet
70
get_flags_from_key_file (DesktopEntry *entry,
72
const char *desktop_entry_group)
78
gboolean show_in_gnome;
79
gboolean tryexec_failed;
85
no_display = g_key_file_get_boolean (key_file,
96
hidden = g_key_file_get_boolean (key_file,
103
g_error_free (error);
106
show_in_gnome = TRUE;
107
strv = g_key_file_get_string_list (key_file,
114
show_in_gnome = FALSE;
115
for (i = 0; strv[i]; i++)
117
if (!strcmp (strv[i], "GNOME"))
119
show_in_gnome = TRUE;
126
strv = g_key_file_get_string_list (key_file,
133
show_in_gnome = TRUE;
134
for (i = 0; strv[i]; i++)
136
if (!strcmp (strv[i], "GNOME"))
138
show_in_gnome = FALSE;
145
tryexec_failed = FALSE;
146
tryexec = g_key_file_get_string (key_file,
154
path = g_find_program_in_path (g_strstrip (tryexec));
156
tryexec_failed = (path == NULL);
164
flags |= DESKTOP_ENTRY_NO_DISPLAY;
166
flags |= DESKTOP_ENTRY_HIDDEN;
168
flags |= DESKTOP_ENTRY_SHOW_IN_GNOME;
170
flags |= DESKTOP_ENTRY_TRYEXEC_FAILED;
176
get_categories_from_key_file (DesktopEntry *entry,
178
const char *desktop_entry_group)
185
strv = g_key_file_get_string_list (key_file,
193
retval = g_new0 (GQuark, len + 1);
195
for (i = 0; strv[i]; i++)
196
retval[i] = g_quark_from_string (strv[i]);
203
static DesktopEntry *
204
desktop_entry_load (DesktopEntry *entry)
206
DesktopEntry *retval = NULL;
209
const char *desktop_entry_group;
213
key_file = g_key_file_new ();
216
if (!g_key_file_load_from_file (key_file, entry->path, 0, &error))
218
menu_verbose ("Failed to load \"%s\": %s\n",
219
entry->path, error->message);
220
g_error_free (error);
224
if (g_key_file_has_group (key_file, DESKTOP_ENTRY_GROUP))
226
desktop_entry_group = DESKTOP_ENTRY_GROUP;
230
menu_verbose ("\"%s\" contains no \"" DESKTOP_ENTRY_GROUP "\" group\n",
233
if (g_key_file_has_group (key_file, KDE_DESKTOP_ENTRY_GROUP))
235
desktop_entry_group = KDE_DESKTOP_ENTRY_GROUP;
236
menu_verbose ("\"%s\" contains deprecated \"" KDE_DESKTOP_ENTRY_GROUP "\" group\n",
245
if (!g_key_file_has_key (key_file, desktop_entry_group, "Name", NULL))
247
menu_verbose ("\"%s\" contains no \"Name\" key\n", entry->path);
251
name_str = g_key_file_get_locale_string (key_file, desktop_entry_group, "Name", NULL, NULL);
254
menu_verbose ("\"%s\" contains an invalid \"Name\" key\n", entry->path);
260
type_str = g_key_file_get_string (key_file, desktop_entry_group, "Type", NULL);
263
menu_verbose ("\"%s\" contains no \"Type\" key\n", entry->path);
267
if ((entry->type == DESKTOP_ENTRY_DESKTOP && strcmp (type_str, "Application") != 0) ||
268
(entry->type == DESKTOP_ENTRY_DIRECTORY && strcmp (type_str, "Directory") != 0))
270
menu_verbose ("\"%s\" does not contain the correct \"Type\" value\n", entry->path);
277
if (entry->type == DESKTOP_ENTRY_DESKTOP &&
278
!g_key_file_has_key (key_file, desktop_entry_group, "Exec", NULL))
280
menu_verbose ("\"%s\" does not contain an \"Exec\" key\n", entry->path);
286
#define GET_LOCALE_STRING(n) g_key_file_get_locale_string (key_file, desktop_entry_group, (n), NULL, NULL)
288
retval->name = GET_LOCALE_STRING ("Name");
289
retval->generic_name = GET_LOCALE_STRING ("GenericName");
290
retval->full_name = GET_LOCALE_STRING ("X-GNOME-FullName");
291
retval->comment = GET_LOCALE_STRING ("Comment");
292
retval->icon = GET_LOCALE_STRING ("Icon");
293
retval->flags = get_flags_from_key_file (retval, key_file, desktop_entry_group);
294
retval->categories = get_categories_from_key_file (retval, key_file, desktop_entry_group);
296
if (entry->type == DESKTOP_ENTRY_DESKTOP)
298
retval->exec = g_key_file_get_string (key_file, desktop_entry_group, "Exec", NULL);
299
retval->terminal = g_key_file_get_boolean (key_file, desktop_entry_group, "Terminal", NULL);
302
#undef GET_LOCALE_STRING
304
menu_verbose ("Desktop entry \"%s\" (%s, %s, %s, %s, %s) flags: NoDisplay=%s, Hidden=%s, ShowInGNOME=%s, TryExecFailed=%s\n",
307
retval->generic_name ? retval->generic_name : "(null)",
308
retval->full_name ? retval->full_name : "(null)",
309
retval->comment ? retval->comment : "(null)",
310
retval->icon ? retval->icon : "(null)",
311
retval->flags & DESKTOP_ENTRY_NO_DISPLAY ? "(true)" : "(false)",
312
retval->flags & DESKTOP_ENTRY_HIDDEN ? "(true)" : "(false)",
313
retval->flags & DESKTOP_ENTRY_SHOW_IN_GNOME ? "(true)" : "(false)",
314
retval->flags & DESKTOP_ENTRY_TRYEXEC_FAILED ? "(true)" : "(false)");
317
g_key_file_free (key_file);
320
desktop_entry_unref (entry);
326
desktop_entry_new (const char *path)
328
DesktopEntryType type;
329
DesktopEntry *retval;
331
menu_verbose ("Loading desktop entry \"%s\"\n", path);
333
if (g_str_has_suffix (path, ".desktop"))
335
type = DESKTOP_ENTRY_DESKTOP;
337
else if (g_str_has_suffix (path, ".directory"))
339
type = DESKTOP_ENTRY_DIRECTORY;
343
menu_verbose ("Unknown desktop entry suffix in \"%s\"\n",
348
retval = g_new0 (DesktopEntry, 1);
350
retval->refcount = 1;
352
retval->basename = g_path_get_basename (path);
353
retval->path = g_strdup (path);
355
return desktop_entry_load (retval);
359
desktop_entry_reload (DesktopEntry *entry)
361
g_return_val_if_fail (entry != NULL, NULL);
363
menu_verbose ("Re-loading desktop entry \"%s\"\n", entry->path);
365
g_free (entry->categories);
366
entry->categories = NULL;
368
g_free (entry->name);
371
g_free (entry->generic_name);
372
entry->generic_name = NULL;
374
g_free (entry->full_name);
375
entry->full_name = NULL;
377
g_free (entry->comment);
378
entry->comment = NULL;
380
g_free (entry->icon);
383
g_free (entry->exec);
389
return desktop_entry_load (entry);
393
desktop_entry_ref (DesktopEntry *entry)
395
g_return_val_if_fail (entry != NULL, NULL);
396
g_return_val_if_fail (entry->refcount > 0, NULL);
398
entry->refcount += 1;
404
desktop_entry_copy (DesktopEntry *entry)
406
DesktopEntry *retval;
409
menu_verbose ("Copying desktop entry \"%s\"\n",
412
retval = g_new0 (DesktopEntry, 1);
414
retval->refcount = 1;
415
retval->type = entry->type;
416
retval->basename = g_strdup (entry->basename);
417
retval->path = g_strdup (entry->path);
418
retval->name = g_strdup (entry->name);
419
retval->generic_name = g_strdup (entry->generic_name);
420
retval->full_name = g_strdup (entry->full_name);
421
retval->comment = g_strdup (entry->comment);
422
retval->icon = g_strdup (entry->icon);
423
retval->exec = g_strdup (entry->exec);
424
retval->terminal = entry->terminal;
425
retval->flags = entry->flags;
428
if (entry->categories != NULL)
430
for (; entry->categories[i]; i++);
433
retval->categories = g_new0 (GQuark, i + 1);
436
if (entry->categories != NULL)
438
for (; entry->categories[i]; i++)
439
retval->categories[i] = entry->categories[i];
446
desktop_entry_unref (DesktopEntry *entry)
448
g_return_if_fail (entry != NULL);
449
g_return_if_fail (entry->refcount > 0);
451
entry->refcount -= 1;
452
if (entry->refcount == 0)
454
g_free (entry->categories);
455
entry->categories = NULL;
457
g_free (entry->name);
460
g_free (entry->generic_name);
461
entry->generic_name = NULL;
463
g_free (entry->full_name);
464
entry->full_name = NULL;
466
g_free (entry->comment);
467
entry->comment = NULL;
469
g_free (entry->icon);
472
g_free (entry->exec);
475
g_free (entry->basename);
476
entry->basename = NULL;
478
g_free (entry->path);
486
desktop_entry_get_type (DesktopEntry *entry)
492
desktop_entry_get_path (DesktopEntry *entry)
498
desktop_entry_get_basename (DesktopEntry *entry)
500
return entry->basename;
504
desktop_entry_get_name (DesktopEntry *entry)
510
desktop_entry_get_generic_name (DesktopEntry *entry)
512
return entry->generic_name;
516
desktop_entry_get_full_name (DesktopEntry *entry)
518
return entry->full_name;
522
desktop_entry_get_comment (DesktopEntry *entry)
524
return entry->comment;
528
desktop_entry_get_icon (DesktopEntry *entry)
534
desktop_entry_get_exec (DesktopEntry *entry)
540
desktop_entry_get_launch_in_terminal (DesktopEntry *entry)
542
return entry->terminal;
546
desktop_entry_get_hidden (DesktopEntry *entry)
548
return (entry->flags & DESKTOP_ENTRY_HIDDEN) != 0;
552
desktop_entry_get_no_display (DesktopEntry *entry)
554
return (entry->flags & DESKTOP_ENTRY_NO_DISPLAY) != 0;
558
desktop_entry_get_show_in_gnome (DesktopEntry *entry)
560
return (entry->flags & DESKTOP_ENTRY_SHOW_IN_GNOME) != 0;
564
desktop_entry_get_tryexec_failed (DesktopEntry *entry)
566
return (entry->flags & DESKTOP_ENTRY_TRYEXEC_FAILED) != 0;
570
desktop_entry_has_categories (DesktopEntry *entry)
572
return (entry->categories != NULL && entry->categories[0] != 0);
576
desktop_entry_has_category (DesktopEntry *entry,
577
const char *category)
582
if (entry->categories == NULL)
585
if (!(quark = g_quark_try_string (category)))
588
for (i = 0; entry->categories[i]; i++)
590
if (quark == entry->categories[i])
598
desktop_entry_add_legacy_category (DesktopEntry *entry)
603
menu_verbose ("Adding Legacy category to \"%s\"\n",
607
if (entry->categories != NULL)
609
for (; entry->categories[i]; i++);
612
categories = g_new0 (GQuark, i + 2);
615
if (entry->categories != NULL)
617
for (; entry->categories[i]; i++)
618
categories[i] = entry->categories[i];
621
categories[i] = g_quark_from_string ("Legacy");
623
g_free (entry->categories);
624
entry->categories = categories;
632
desktop_entry_set_new (void)
634
DesktopEntrySet *set;
636
set = g_new0 (DesktopEntrySet, 1);
639
menu_verbose (" New entry set %p\n", set);
645
desktop_entry_set_ref (DesktopEntrySet *set)
647
g_return_val_if_fail (set != NULL, NULL);
648
g_return_val_if_fail (set->refcount > 0, NULL);
656
desktop_entry_set_unref (DesktopEntrySet *set)
658
g_return_if_fail (set != NULL);
659
g_return_if_fail (set->refcount > 0);
662
if (set->refcount == 0)
664
menu_verbose (" Deleting entry set %p\n", set);
667
g_hash_table_destroy (set->hash);
675
desktop_entry_set_add_entry (DesktopEntrySet *set,
679
menu_verbose (" Adding to set %p entry %s\n", set, file_id);
681
if (set->hash == NULL)
683
set->hash = g_hash_table_new_full (g_str_hash,
686
(GDestroyNotify) desktop_entry_unref);
689
g_hash_table_replace (set->hash,
691
desktop_entry_ref (entry));
695
desktop_entry_set_lookup (DesktopEntrySet *set,
698
if (set->hash == NULL)
701
return g_hash_table_lookup (set->hash, file_id);
706
DesktopEntrySetForeachFunc func;
708
} EntryHashForeachData;
711
entry_hash_foreach (const char *file_id,
713
EntryHashForeachData *fd)
715
fd->func (file_id, entry, fd->user_data);
719
desktop_entry_set_foreach (DesktopEntrySet *set,
720
DesktopEntrySetForeachFunc func,
723
g_return_if_fail (set != NULL);
724
g_return_if_fail (func != NULL);
726
if (set->hash != NULL)
728
EntryHashForeachData fd;
731
fd.user_data = user_data;
733
g_hash_table_foreach (set->hash,
734
(GHFunc) entry_hash_foreach,
740
desktop_entry_set_clear (DesktopEntrySet *set)
742
menu_verbose (" Clearing set %p\n", set);
744
if (set->hash != NULL)
746
g_hash_table_destroy (set->hash);
752
desktop_entry_set_get_count (DesktopEntrySet *set)
754
if (set->hash == NULL)
757
return g_hash_table_size (set->hash);
761
union_foreach (const char *file_id,
763
DesktopEntrySet *set)
765
/* we are iterating over "with" adding anything not
766
* already in "set". We unconditionally overwrite
767
* the stuff in "set" because we can assume
768
* two entries with the same name are equivalent.
770
desktop_entry_set_add_entry (set, entry, file_id);
774
desktop_entry_set_union (DesktopEntrySet *set,
775
DesktopEntrySet *with)
777
menu_verbose (" Union of %p and %p\n", set, with);
779
if (desktop_entry_set_get_count (with) == 0)
780
return; /* A fast simple case */
782
g_hash_table_foreach (with->hash,
783
(GHFunc) union_foreach,
789
DesktopEntrySet *set;
790
DesktopEntrySet *with;
794
intersect_foreach_remove (const char *file_id,
798
/* Remove everything in "set" which is not in "with" */
800
if (g_hash_table_lookup (id->with->hash, file_id) != NULL)
803
menu_verbose (" Removing from %p entry %s\n", id->set, file_id);
805
return TRUE; /* return TRUE to remove */
809
desktop_entry_set_intersection (DesktopEntrySet *set,
810
DesktopEntrySet *with)
814
menu_verbose (" Intersection of %p and %p\n", set, with);
816
if (desktop_entry_set_get_count (set) == 0 ||
817
desktop_entry_set_get_count (with) == 0)
819
/* A fast simple case */
820
desktop_entry_set_clear (set);
827
g_hash_table_foreach_remove (set->hash,
828
(GHRFunc) intersect_foreach_remove,
834
DesktopEntrySet *set;
835
DesktopEntrySet *other;
839
subtract_foreach_remove (const char *file_id,
843
/* Remove everything in "set" which is not in "other" */
845
if (g_hash_table_lookup (sd->other->hash, file_id) == NULL)
848
menu_verbose (" Removing from %p entry %s\n", sd->set, file_id);
850
return TRUE; /* return TRUE to remove */
854
desktop_entry_set_subtract (DesktopEntrySet *set,
855
DesktopEntrySet *other)
859
menu_verbose (" Subtract from %p set %p\n", set, other);
861
if (desktop_entry_set_get_count (set) == 0 ||
862
desktop_entry_set_get_count (other) == 0)
863
return; /* A fast simple case */
868
g_hash_table_foreach_remove (set->hash,
869
(GHRFunc) subtract_foreach_remove,
874
desktop_entry_set_swap_contents (DesktopEntrySet *a,
879
menu_verbose (" Swap contents of %p and %p\n", a, b);