/* * Support for manipulating .desktop files * * (C) 1997, 1999 the Free Software Foundation * * Authors: Miguel de Icaza * Federico Mena */ #include #include #include #include #include #include #include "gnome-defs.h" #include "gnome-util.h" #include "gnome-config.h" #include "gnome-dentry.h" #include "gnome-exec.h" /* g_free already checks if x is NULL */ #define free_if_empty(x) g_free (x) /** * gnome_desktop_entry_load_flags_conditional: * @file: a file name that contains a desktop entry. * @clean_from_memory_after_load: flag * @unconditional: flag * * Returns a newly created desktop entry loaded from @file or NULL * if the file does not exist. * * if @unconditional is TRUE then the desktop entry is loaded even if * it contains stale data, otherwise, NULL is returned if stale data * is found (like, the program referenced not existing). * * if @clean_from_memory_after_load is TRUE, then any data cached used by loading * process is discarded after loading the desktop entry. */ GnomeDesktopEntry * gnome_desktop_entry_load_flags_conditional (const char *file, int clean_from_memory_after_load, int unconditional) { GnomeDesktopEntry *newitem; char *prefix; char *name, *type; char *try_file; char **exec_vector; int exec_length; char *icon_base; char *p = NULL; gboolean is_kde = FALSE; g_assert (file != NULL); prefix = g_strconcat ("=", file, "=/Desktop Entry/", NULL); gnome_config_push_prefix (prefix); g_free (prefix); name = gnome_config_get_translated_string ("Name"); if (!name) { gnome_config_pop_prefix (); prefix = g_strconcat ("=", file, "=/KDE Desktop Entry/", NULL); gnome_config_push_prefix (prefix); g_free (prefix); is_kde = TRUE; name = gnome_config_get_translated_string ("Name"); if (!name) { gnome_config_pop_prefix (); return NULL; } } /* FIXME: we only test for presence of Exec/TryExec keys if * the type of the desktop entry is not a Directory. Since * Exec/TryExec may not make sense for other types of desktop * entries, we will later need to make this code smarter. */ type = gnome_config_get_string ("Type"); gnome_config_get_vector ("Exec", &exec_length, &exec_vector); try_file = gnome_config_get_string ("TryExec"); if (!type || (strcmp (type, "Directory") != 0)){ if(!unconditional && ( !exec_vector || (try_file && !(p = gnome_is_program_in_path(try_file))))){ free_if_empty (p); free_if_empty (name); free_if_empty (type); g_strfreev (exec_vector); free_if_empty (try_file); gnome_config_pop_prefix (); return NULL; } if (p) g_free (p); } newitem = g_new (GnomeDesktopEntry, 1); newitem->name = name; newitem->comment = gnome_config_get_translated_string ("Comment"); newitem->exec_length = exec_length; newitem->exec = exec_vector; newitem->tryexec = try_file; newitem->docpath = gnome_config_get_string ("DocPath"); newitem->terminal = gnome_config_get_bool ("Terminal=0"); newitem->type = type; newitem->geometry = gnome_config_get_string ("Geometry"); newitem->multiple_args = gnome_config_get_bool ("MultipleArgs=0"); newitem->location = g_strdup (file); newitem->is_kde = is_kde; icon_base = gnome_config_get_string ("Icon"); if (icon_base && *icon_base) { /* Sigh, now we need to make them local to the gnome install */ if (*icon_base != '/') { /* We look for KDE icons in hardcoded /usr/share/icons * I don't how we can efficiently look in the "right" * place - maybe a configure time test for KDE location? */ if (newitem->is_kde) { gchar *iconname = g_concat_dir_and_file ("/usr/share/icons/", icon_base); if (g_file_exists (iconname)) newitem->icon = iconname; else { g_free (iconname); newitem->icon = NULL; } } else newitem->icon = gnome_pixmap_file (icon_base); g_free (icon_base); } else newitem->icon = icon_base; } else { /*no icon*/ if(icon_base) g_free(icon_base); newitem->icon = NULL; } gnome_config_pop_prefix (); if (clean_from_memory_after_load){ prefix = g_strconcat ("=", file, "=", NULL); gnome_config_drop_file (prefix); g_free (prefix); } return newitem; } /** * gnome_desktop_entry_load_flags: * @file: a file name that contains a desktop entry. * @clean_from_memory_after_load: flag * * Returns a newly created desktop entry loaded from @file or NULL * if the file does not exist or contains stale data. * * if @clean_from_memory_after_load is TRUE, then any data cached used by loading * process is discarded after loading the desktop entry. */ GnomeDesktopEntry * gnome_desktop_entry_load_flags (const char *file, int clean_from_memory_after_load) { return gnome_desktop_entry_load_flags_conditional (file, clean_from_memory_after_load, FALSE); } /** * gnome_desktop_entry_load: * @file: a file name that contains a desktop entry. * * Returns a newly created desktop entry loaded from @file or NULL * if the file does not exist or contains stale data. */ GnomeDesktopEntry * gnome_desktop_entry_load (const char *file) { return gnome_desktop_entry_load_flags (file, 1); } /** * gnome_desktop_entry_load_unconditional: * @file: file name where the desktop entry resides * * Returns a newly created GnomeDesktopEntry loaded from * @file even if the file does not contain a valid desktop entry or NULL * if the file does not exist. */ GnomeDesktopEntry * gnome_desktop_entry_load_unconditional (const char *file) { return gnome_desktop_entry_load_flags_conditional (file, 1, TRUE); } /** * gnome_desktop_entry_save: * @dentry: A gnome desktop entry. * * Saves the desktop entry to disk */ void gnome_desktop_entry_save (GnomeDesktopEntry *dentry) { char *prefix; /* XXX:this should have same clean_from_memory logic as above maybe??? */ g_return_if_fail (dentry != NULL); g_return_if_fail (dentry->location != NULL); g_return_if_fail (!dentry->is_kde); gnome_config_push_prefix (""); prefix = g_strconcat ("=", dentry->location, "=/Desktop Entry/", NULL); gnome_config_clean_section (prefix); gnome_config_push_prefix (prefix); g_free (prefix); if (dentry->name) gnome_config_set_translated_string ("Name", dentry->name); if (dentry->comment) gnome_config_set_translated_string ("Comment", dentry->comment); if (dentry->exec) gnome_config_set_vector ("Exec", dentry->exec_length, (const char * const *) dentry->exec); if (dentry->tryexec) gnome_config_set_string ("TryExec", dentry->tryexec); if (dentry->icon) gnome_config_set_string ("Icon", dentry->icon); if (dentry->geometry) gnome_config_set_string ("Geometry", dentry->geometry); if (dentry->docpath) gnome_config_set_string ("DocPath", dentry->docpath); gnome_config_set_bool ("Terminal", dentry->terminal); gnome_config_set_bool ("MultipleArgs", dentry->multiple_args); if (dentry->type) gnome_config_set_string ("Type", dentry->type); gnome_config_pop_prefix (); prefix = g_strconcat ("=", dentry->location, "=", NULL); gnome_config_sync_file (prefix); gnome_config_drop_file (prefix); g_free (prefix); gnome_config_pop_prefix (); } /** * gnome_desktop_entry_free: * @item: a gnome desktop entry. * * Releases the information used by @item. */ void gnome_desktop_entry_free (GnomeDesktopEntry *item) { if(item){ free_if_empty (item->name); free_if_empty (item->comment); g_strfreev (item->exec); free_if_empty (item->tryexec); free_if_empty (item->icon); free_if_empty (item->docpath); free_if_empty (item->type); free_if_empty (item->location); free_if_empty (item->geometry); g_free (item); } } /* Replace the KDE subsitution strings %... in this argument * if any are found, returns g_malloc()'d string containing * new argument, otherwise NULL. */ static gchar * gnome_desktop_entry_sub_kde_arg (GnomeDesktopEntry *item, gchar *arg) { char *p, *q; char tmp; GString *result = NULL; p = arg; q = strchr(arg, '%'); while (q) { tmp = *q; *q = '\0'; if (!result) result = g_string_new (p); else g_string_append (result, p); *q = tmp; q++; switch (*q) { case '\0': q = NULL; p = NULL; break; case 'c': /* The comment field */ if (item->comment) g_string_append (result, item->comment); break; case 'i': /* The item field */ if (item->icon) { g_string_append (result, "-icon "); g_string_append (result, item->icon); } break; case 'm': /* The mini-icon field. Ignore for now. * sometime this seems to be %mi, so we * ignore that too. */ if (*(q+1) == 'i') q++; break; case 'f': /* File arguments */ case 'u': /* File arguments as URLs */ default: break; } if (q) { p = q + 1; q = strchr (p, '%'); } } if (result) { char *r = result->str; if (p) g_string_append (result, p); arg = result->str; g_string_free (result, FALSE); return r; } else return NULL; } /** * gnome_desktop_entry_launch_with_args: * @item: a gnome desktop entry. * @the_argc: the number of arguments to invoke the desktop entry with. * @the_argv: a vector of arguments for calling the program in @item * * Launches the program associated with @item with @the_argv as its * arguments. */ void gnome_desktop_entry_launch_with_args (GnomeDesktopEntry *item, int the_argc, char *the_argv[]) { char *uargv[4]; char *exec_str; char **term_argv; int term_argc = 0; char *xterm_argv[2]; char **argv; GSList *args_to_free = NULL; gchar *sub_arg; int i, argc; g_assert (item != NULL); if (!item->terminal && the_argc == 0 && !item->is_kde) exec_str = g_strjoinv (" ", (char **)(item->exec)); else { if (item->terminal) { gnome_config_get_vector ("/Gnome/Applications/Terminal", &term_argc, &term_argv); if (term_argv == NULL) { term_argc = 2; term_argv = xterm_argv; xterm_argv[0] = "xterm"; xterm_argv[1] = "-e"; } } /* ... terminal arguments */ argc = the_argc + term_argc + item->exec_length; argv = (char **) g_malloc ((argc + 1) * sizeof (char *)); /* Assemble together... */ /* ... terminal arguments */ for (i = 0; i < term_argc; ++i) argv[i] = term_argv[i]; /* ... arguments from the desktop file */ for (i = 0; i < item->exec_length; ++i) { if (item->is_kde) { sub_arg = gnome_desktop_entry_sub_kde_arg (item, item->exec[i]); if (sub_arg) { args_to_free = g_slist_prepend (args_to_free, sub_arg); argv[term_argc + i] = sub_arg; } else argv[term_argc + i] = item->exec[i]; } else argv[term_argc + i] = item->exec[i]; } /* ... supplied arguments */ for (i = 0; i < the_argc; i++) argv[term_argc + item->exec_length + i] = the_argv [i]; argv[argc] = NULL; exec_str = g_strjoinv (" ", (char **)argv); /* clean up */ if (term_argc && term_argv != xterm_argv) g_strfreev (term_argv); if (args_to_free) { g_slist_foreach (args_to_free, (GFunc)g_free, NULL); g_slist_free (args_to_free); } g_free ((char *) argv); } uargv[0] = "/bin/sh"; uargv[1] = "-c"; uargv[2] = exec_str; uargv[3] = NULL; /* FIXME: do something if there's an error. */ gnome_execute_async (NULL, 4, uargv); g_free (exec_str); } /** * gnome_desktop_entry_launch: * @item: a gnome desktop entry. * * Launchs the program associated to the @item desktop entry. */ void gnome_desktop_entry_launch (GnomeDesktopEntry *item) { gnome_desktop_entry_launch_with_args (item, 0, 0); } /** * gnome_desktop_entry_destroy: * @item: a gnome deskop entry. * * Erases the file that represents @item and releases the * memory used by @item. */ void gnome_desktop_entry_destroy (GnomeDesktopEntry *item) { char *prefix; if (!item) return; prefix = g_strconcat ("=", item->location, "=", NULL); gnome_config_clean_file (prefix); gnome_desktop_entry_free (item); gnome_config_sync_file (prefix); g_free (prefix); } /** * gnome_desktop_entry_copy: * @source: a GnomeDesktop entry. * * Returns a copy of the @source GnomeDesktopEntry */ GnomeDesktopEntry * gnome_desktop_entry_copy (GnomeDesktopEntry * source) { GnomeDesktopEntry * newitem; g_return_val_if_fail (source != NULL, NULL); newitem = g_new (GnomeDesktopEntry, 1); newitem->name = g_strdup (source->name); newitem->comment = g_strdup (source->comment); newitem->exec_length = source->exec_length; newitem->exec = g_copy_vector (source->exec); newitem->tryexec = g_strdup (source->tryexec); newitem->docpath = g_strdup (source->docpath); newitem->terminal = source->terminal; newitem->type = g_strdup (source->type); newitem->geometry = g_strdup (source->geometry); newitem->multiple_args = source->multiple_args; newitem->location = g_strdup (source->location); newitem->icon = g_strdup (source->icon); newitem->is_kde = source->is_kde; return newitem; }