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
51
gboolean terminal : 1;
52
gboolean startup_notify : 1;
54
guint32 show_in_flags;
61
struct DesktopEntrySet
67
/* defined in menu-cache-gen.c */
68
guint32 menu_cache_get_de_flag( const char* de_name );
75
get_flags_from_key_file (DesktopEntry *entry,
77
const char *desktop_entry_group)
83
gboolean show_in_gnome;
84
gboolean tryexec_failed;
90
no_display = g_key_file_get_boolean (key_file,
101
hidden = g_key_file_get_boolean (key_file,
108
g_error_free (error);
111
show_in_gnome = TRUE;
112
strv = g_key_file_get_string_list (key_file,
119
/* show_in_gnome = FALSE; */
120
for (i = 0; strv[i]; i++)
122
guint32 de_flag = menu_cache_get_de_flag(strv[i]);
123
entry->show_in_flags |= de_flag; /* add the DE */
125
if (!strcmp (strv[i], "GNOME"))
127
show_in_gnome = TRUE;
135
strv = g_key_file_get_string_list (key_file,
142
/* show in all DEs by default */
143
entry->show_in_flags = (guint32)-1;
144
/* show_in_gnome = TRUE; */
145
for (i = 0; strv[i]; i++)
147
guint32 de_flag = menu_cache_get_de_flag(strv[i]);
148
entry->show_in_flags &= (~de_flag); /* remove the DE */
150
if (!strcmp (strv[i], "GNOME"))
152
show_in_gnome = FALSE;
159
/* printf( "DE flag of %s is %d\n", entry->name, entry->show_in_flags); */
160
tryexec_failed = FALSE;
161
tryexec = g_key_file_get_string (key_file,
169
path = g_find_program_in_path (g_strstrip (tryexec));
171
tryexec_failed = (path == NULL);
179
flags |= DESKTOP_ENTRY_NO_DISPLAY;
181
flags |= DESKTOP_ENTRY_HIDDEN;
183
flags |= DESKTOP_ENTRY_SHOW_IN_GNOME;
185
flags |= DESKTOP_ENTRY_TRYEXEC_FAILED;
191
get_categories_from_key_file (DesktopEntry *entry,
193
const char *desktop_entry_group)
200
strv = g_key_file_get_string_list (key_file,
208
retval = g_new0 (GQuark, len + 1);
210
for (i = 0; strv[i]; i++)
211
retval[i] = g_quark_from_string (strv[i]);
218
static DesktopEntry *
219
desktop_entry_load (DesktopEntry *entry)
221
DesktopEntry *retval = NULL;
224
const char *desktop_entry_group;
228
key_file = g_key_file_new ();
231
if (!g_key_file_load_from_file (key_file, entry->path, 0, &error))
233
menu_verbose ("Failed to load \"%s\": %s\n",
234
entry->path, error->message);
235
g_error_free (error);
239
if (g_key_file_has_group (key_file, DESKTOP_ENTRY_GROUP))
241
desktop_entry_group = DESKTOP_ENTRY_GROUP;
245
menu_verbose ("\"%s\" contains no \"" DESKTOP_ENTRY_GROUP "\" group\n",
248
if (g_key_file_has_group (key_file, KDE_DESKTOP_ENTRY_GROUP))
250
desktop_entry_group = KDE_DESKTOP_ENTRY_GROUP;
251
menu_verbose ("\"%s\" contains deprecated \"" KDE_DESKTOP_ENTRY_GROUP "\" group\n",
260
if (!g_key_file_has_key (key_file, desktop_entry_group, "Name", NULL))
262
menu_verbose ("\"%s\" contains no \"Name\" key\n", entry->path);
266
name_str = g_key_file_get_locale_string (key_file, desktop_entry_group, "Name", NULL, NULL);
269
menu_verbose ("\"%s\" contains an invalid \"Name\" key\n", entry->path);
275
type_str = g_key_file_get_string (key_file, desktop_entry_group, "Type", NULL);
278
menu_verbose ("\"%s\" contains no \"Type\" key\n", entry->path);
282
if ((entry->type == DESKTOP_ENTRY_DESKTOP && strcmp (type_str, "Application") != 0) ||
283
(entry->type == DESKTOP_ENTRY_DIRECTORY && strcmp (type_str, "Directory") != 0))
285
menu_verbose ("\"%s\" does not contain the correct \"Type\" value\n", entry->path);
292
if (entry->type == DESKTOP_ENTRY_DESKTOP &&
293
!g_key_file_has_key (key_file, desktop_entry_group, "Exec", NULL))
295
menu_verbose ("\"%s\" does not contain an \"Exec\" key\n", entry->path);
301
#define GET_LOCALE_STRING(n) g_key_file_get_locale_string (key_file, desktop_entry_group, (n), NULL, NULL)
303
retval->name = GET_LOCALE_STRING ("Name");
304
retval->generic_name = GET_LOCALE_STRING ("GenericName");
305
retval->comment = GET_LOCALE_STRING ("Comment");
306
retval->icon = GET_LOCALE_STRING ("Icon");
307
retval->flags = get_flags_from_key_file (retval, key_file, desktop_entry_group);
308
retval->categories = get_categories_from_key_file (retval, key_file, desktop_entry_group);
310
if (entry->type == DESKTOP_ENTRY_DESKTOP)
312
retval->exec = g_key_file_get_string (key_file, desktop_entry_group, "Exec", NULL);
313
retval->terminal = g_key_file_get_boolean (key_file, desktop_entry_group, "Terminal", NULL);
314
retval->startup_notify = g_key_file_get_boolean (key_file, desktop_entry_group, "StartupNotify", NULL);
317
#undef GET_LOCALE_STRING
319
menu_verbose ("Desktop entry \"%s\" (%s, %s, %s) flags: NoDisplay=%s, Hidden=%s, ShowInGNOME=%s, TryExecFailed=%s\n",
322
retval->comment ? retval->comment : "(null)",
323
retval->icon ? retval->icon : "(null)",
324
retval->flags & DESKTOP_ENTRY_NO_DISPLAY ? "(true)" : "(false)",
325
retval->flags & DESKTOP_ENTRY_HIDDEN ? "(true)" : "(false)",
326
retval->flags & DESKTOP_ENTRY_SHOW_IN_GNOME ? "(true)" : "(false)",
327
retval->flags & DESKTOP_ENTRY_TRYEXEC_FAILED ? "(true)" : "(false)");
330
g_key_file_free (key_file);
333
desktop_entry_unref (entry);
339
desktop_entry_new (const char *path)
341
DesktopEntryType type;
342
DesktopEntry *retval;
344
menu_verbose ("Loading desktop entry \"%s\"\n", path);
346
if (g_str_has_suffix (path, ".desktop"))
348
type = DESKTOP_ENTRY_DESKTOP;
350
else if (g_str_has_suffix (path, ".directory"))
352
type = DESKTOP_ENTRY_DIRECTORY;
356
menu_verbose ("Unknown desktop entry suffix in \"%s\"\n",
361
retval = g_new0 (DesktopEntry, 1);
363
retval->refcount = 1;
365
retval->basename = g_path_get_basename (path);
366
retval->path = g_strdup (path);
368
return desktop_entry_load (retval);
372
desktop_entry_reload (DesktopEntry *entry)
374
g_return_val_if_fail (entry != NULL, NULL);
376
menu_verbose ("Re-loading desktop entry \"%s\"\n", entry->path);
378
g_free (entry->categories);
379
entry->categories = NULL;
381
g_free (entry->name);
384
g_free (entry->generic_name);
385
entry->generic_name = NULL;
387
g_free (entry->comment);
388
entry->comment = NULL;
390
g_free (entry->icon);
393
g_free (entry->exec);
397
entry->startup_notify = 0;
400
return desktop_entry_load (entry);
404
desktop_entry_ref (DesktopEntry *entry)
406
g_return_val_if_fail (entry != NULL, NULL);
407
g_return_val_if_fail (entry->refcount > 0, NULL);
409
entry->refcount += 1;
415
desktop_entry_copy (DesktopEntry *entry)
417
DesktopEntry *retval;
420
menu_verbose ("Copying desktop entry \"%s\"\n",
423
retval = g_new0 (DesktopEntry, 1);
425
retval->refcount = 1;
426
retval->type = entry->type;
427
retval->basename = g_strdup (entry->basename);
428
retval->path = g_strdup (entry->path);
429
retval->name = g_strdup (entry->name);
430
retval->generic_name = g_strdup (entry->generic_name);
431
retval->comment = g_strdup (entry->comment);
432
retval->icon = g_strdup (entry->icon);
433
retval->exec = g_strdup (entry->exec);
434
retval->terminal = entry->terminal;
435
retval->startup_notify = entry->startup_notify;
436
retval->flags = entry->flags;
439
if (entry->categories != NULL)
441
for (; entry->categories[i]; i++);
444
retval->categories = g_new0 (GQuark, i + 1);
447
if (entry->categories != NULL)
449
for (; entry->categories[i]; i++)
450
retval->categories[i] = entry->categories[i];
457
desktop_entry_unref (DesktopEntry *entry)
459
g_return_if_fail (entry != NULL);
460
g_return_if_fail (entry->refcount > 0);
462
entry->refcount -= 1;
463
if (entry->refcount == 0)
465
g_free (entry->categories);
466
entry->categories = NULL;
468
g_free (entry->name);
471
g_free (entry->generic_name);
472
entry->generic_name = NULL;
474
g_free (entry->comment);
475
entry->comment = NULL;
477
g_free (entry->icon);
480
g_free (entry->exec);
483
g_free (entry->basename);
484
entry->basename = NULL;
486
g_free (entry->path);
494
desktop_entry_get_type (DesktopEntry *entry)
500
desktop_entry_get_path (DesktopEntry *entry)
506
desktop_entry_get_basename (DesktopEntry *entry)
508
return entry->basename;
512
desktop_entry_get_name (DesktopEntry *entry)
518
desktop_entry_get_generic_name (DesktopEntry *entry)
520
return entry->generic_name;
524
desktop_entry_get_comment (DesktopEntry *entry)
526
return entry->comment;
530
desktop_entry_get_icon (DesktopEntry *entry)
536
desktop_entry_get_exec (DesktopEntry *entry)
542
desktop_entry_get_categories (DesktopEntry *entry)
544
return entry->categories;
548
desktop_entry_get_launch_in_terminal (DesktopEntry *entry)
550
return entry->terminal;
554
desktop_entry_get_use_startup_notify (DesktopEntry *entry)
556
return entry->startup_notify;
560
desktop_entry_get_hidden (DesktopEntry *entry)
562
return (entry->flags & DESKTOP_ENTRY_HIDDEN) != 0;
566
desktop_entry_get_no_display (DesktopEntry *entry)
568
return (entry->flags & DESKTOP_ENTRY_NO_DISPLAY) != 0;
572
desktop_entry_get_show_in_gnome (DesktopEntry *entry)
574
return (entry->flags & DESKTOP_ENTRY_SHOW_IN_GNOME) != 0;
578
desktop_entry_get_show_in_flags (DesktopEntry *entry)
580
return entry->show_in_flags;
584
desktop_entry_get_tryexec_failed (DesktopEntry *entry)
586
return (entry->flags & DESKTOP_ENTRY_TRYEXEC_FAILED) != 0;
590
desktop_entry_has_categories (DesktopEntry *entry)
592
return (entry->categories != NULL && entry->categories[0] != 0);
596
desktop_entry_has_category (DesktopEntry *entry,
597
const char *category)
602
if (entry->categories == NULL)
605
if (!(quark = g_quark_try_string (category)))
608
for (i = 0; entry->categories[i]; i++)
610
if (quark == entry->categories[i])
618
desktop_entry_add_legacy_category (DesktopEntry *entry)
623
menu_verbose ("Adding Legacy category to \"%s\"\n",
627
if (entry->categories != NULL)
629
for (; entry->categories[i]; i++);
632
categories = g_new0 (GQuark, i + 2);
635
if (entry->categories != NULL)
637
for (; entry->categories[i]; i++)
638
categories[i] = entry->categories[i];
641
categories[i] = g_quark_from_string ("Legacy");
643
g_free (entry->categories);
644
entry->categories = categories;
652
desktop_entry_set_new (void)
654
DesktopEntrySet *set;
656
set = g_new0 (DesktopEntrySet, 1);
659
menu_verbose (" New entry set %p\n", set);
665
desktop_entry_set_ref (DesktopEntrySet *set)
667
g_return_val_if_fail (set != NULL, NULL);
668
g_return_val_if_fail (set->refcount > 0, NULL);
676
desktop_entry_set_unref (DesktopEntrySet *set)
678
g_return_if_fail (set != NULL);
679
g_return_if_fail (set->refcount > 0);
682
if (set->refcount == 0)
684
menu_verbose (" Deleting entry set %p\n", set);
687
g_hash_table_destroy (set->hash);
695
desktop_entry_set_add_entry (DesktopEntrySet *set,
699
menu_verbose (" Adding to set %p entry %s\n", set, file_id);
701
if (set->hash == NULL)
703
set->hash = g_hash_table_new_full (g_str_hash,
706
(GDestroyNotify) desktop_entry_unref);
709
g_hash_table_replace (set->hash,
711
desktop_entry_ref (entry));
715
desktop_entry_set_lookup (DesktopEntrySet *set,
718
if (set->hash == NULL)
721
return g_hash_table_lookup (set->hash, file_id);
726
DesktopEntrySetForeachFunc func;
728
} EntryHashForeachData;
731
entry_hash_foreach (const char *file_id,
733
EntryHashForeachData *fd)
735
fd->func (file_id, entry, fd->user_data);
739
desktop_entry_set_foreach (DesktopEntrySet *set,
740
DesktopEntrySetForeachFunc func,
743
g_return_if_fail (set != NULL);
744
g_return_if_fail (func != NULL);
746
if (set->hash != NULL)
748
EntryHashForeachData fd;
751
fd.user_data = user_data;
753
g_hash_table_foreach (set->hash,
754
(GHFunc) entry_hash_foreach,
760
desktop_entry_set_clear (DesktopEntrySet *set)
762
menu_verbose (" Clearing set %p\n", set);
764
if (set->hash != NULL)
766
g_hash_table_destroy (set->hash);
772
desktop_entry_set_get_count (DesktopEntrySet *set)
774
if (set->hash == NULL)
777
return g_hash_table_size (set->hash);
781
union_foreach (const char *file_id,
783
DesktopEntrySet *set)
785
/* we are iterating over "with" adding anything not
786
* already in "set". We unconditionally overwrite
787
* the stuff in "set" because we can assume
788
* two entries with the same name are equivalent.
790
desktop_entry_set_add_entry (set, entry, file_id);
794
desktop_entry_set_union (DesktopEntrySet *set,
795
DesktopEntrySet *with)
797
menu_verbose (" Union of %p and %p\n", set, with);
799
if (desktop_entry_set_get_count (with) == 0)
800
return; /* A fast simple case */
802
g_hash_table_foreach (with->hash,
803
(GHFunc) union_foreach,
809
DesktopEntrySet *set;
810
DesktopEntrySet *with;
814
intersect_foreach_remove (const char *file_id,
818
/* Remove everything in "set" which is not in "with" */
820
if (g_hash_table_lookup (id->with->hash, file_id) != NULL)
823
menu_verbose (" Removing from %p entry %s\n", id->set, file_id);
825
return TRUE; /* return TRUE to remove */
829
desktop_entry_set_intersection (DesktopEntrySet *set,
830
DesktopEntrySet *with)
834
menu_verbose (" Intersection of %p and %p\n", set, with);
836
if (desktop_entry_set_get_count (set) == 0 ||
837
desktop_entry_set_get_count (with) == 0)
839
/* A fast simple case */
840
desktop_entry_set_clear (set);
847
g_hash_table_foreach_remove (set->hash,
848
(GHRFunc) intersect_foreach_remove,
854
DesktopEntrySet *set;
855
DesktopEntrySet *other;
859
subtract_foreach_remove (const char *file_id,
863
/* Remove everything in "set" which is not in "other" */
865
if (g_hash_table_lookup (sd->other->hash, file_id) == NULL)
868
menu_verbose (" Removing from %p entry %s\n", sd->set, file_id);
870
return TRUE; /* return TRUE to remove */
874
desktop_entry_set_subtract (DesktopEntrySet *set,
875
DesktopEntrySet *other)
879
menu_verbose (" Subtract from %p set %p\n", set, other);
881
if (desktop_entry_set_get_count (set) == 0 ||
882
desktop_entry_set_get_count (other) == 0)
883
return; /* A fast simple case */
888
g_hash_table_foreach_remove (set->hash,
889
(GHRFunc) subtract_foreach_remove,
894
desktop_entry_set_swap_contents (DesktopEntrySet *a,
899
menu_verbose (" Swap contents of %p and %p\n", a, b);