GDesktopAppInfo: Try to always correctly set id

Specs say that on Unix id should be desktop file id from the xdg menu
specification, however, currently code just uses basename of .desktop file.
Fix that by finding the .desktop file in all the desktop_file_dirs and use
basename only as a fallback.

See https://specifications.freedesktop.org/menu-spec/latest/go01.html#term-desktop-file-id
and https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s02.html#desktop-file-id

"To determine the ID of a desktop file, make its full path relative to the
$XDG_DATA_DIRS component in which the desktop file is installed, remove the
"applications/" prefix, and turn '/' into '-'."

Also, add unit test that verifies Desktop Id is being correctly set

Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
This commit is contained in:
Ivaylo Dimitrov 2021-12-13 23:43:44 +02:00 committed by Philip Withnall
parent 62be185463
commit f065497acf
2 changed files with 95 additions and 14 deletions

View File

@ -89,6 +89,7 @@ enum {
static void g_desktop_app_info_iface_init (GAppInfoIface *iface);
static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info,
GError **error);
static gboolean g_desktop_app_info_load_file (GDesktopAppInfo *self);
/**
* GDesktopAppInfo:
@ -1002,6 +1003,19 @@ desktop_file_dir_unindexed_init (DesktopFileDir *dir)
desktop_file_dir_unindexed_read_mimeapps_lists (dir);
}
static GDesktopAppInfo *
g_desktop_app_info_new_from_filename_unlocked (const char *filename)
{
GDesktopAppInfo *info = NULL;
info = g_object_new (G_TYPE_DESKTOP_APP_INFO, "filename", filename, NULL);
if (!g_desktop_app_info_load_file (info))
g_clear_object (&info);
return info;
}
static GDesktopAppInfo *
desktop_file_dir_unindexed_get_app (DesktopFileDir *dir,
const gchar *desktop_id)
@ -1013,7 +1027,7 @@ desktop_file_dir_unindexed_get_app (DesktopFileDir *dir,
if (!filename)
return NULL;
return g_desktop_app_info_new_from_filename (filename);
return g_desktop_app_info_new_from_filename_unlocked (filename);
}
static void
@ -1033,7 +1047,7 @@ desktop_file_dir_unindexed_get_all (DesktopFileDir *dir,
if (desktop_file_dir_app_name_is_masked (dir, app_name))
continue;
add_to_table_if_appropriate (apps, app_name, g_desktop_app_info_new_from_filename (filename));
add_to_table_if_appropriate (apps, app_name, g_desktop_app_info_new_from_filename_unlocked (filename));
}
}
@ -1754,6 +1768,56 @@ binary_from_exec (const char *exec)
return g_strndup (start, p - start);
}
/*< internal >
* g_desktop_app_info_get_desktop_id_for_filename
* @self: #GDesktopAppInfo to get desktop id of
*
* Tries to find the desktop ID for a particular `.desktop` filename, as per the
* [Desktop Entry Specification](https://specifications.freedesktop.org/desktop-
* entry-spec/desktop-entry-spec-latest.html#desktop-file-id).
*
* Returns: desktop id or basename if filename is unknown.
*/
static char *
g_desktop_app_info_get_desktop_id_for_filename (GDesktopAppInfo *self)
{
guint i;
gchar *desktop_id = NULL;
g_return_val_if_fail (self->filename != NULL, NULL);
for (i = 0; i < desktop_file_dirs->len; i++)
{
DesktopFileDir *dir = g_ptr_array_index (desktop_file_dirs, i);
GHashTable *app_names;
GHashTableIter iter;
gpointer key, value;
app_names = dir->app_names;
if (!app_names)
continue;
g_hash_table_iter_init (&iter, app_names);
while (g_hash_table_iter_next (&iter, &key, &value))
{
if (!strcmp (value, self->filename))
{
desktop_id = g_strdup (key);
break;
}
}
if (desktop_id)
break;
}
if (!desktop_id)
desktop_id = g_path_get_basename (self->filename);
return g_steal_pointer (&desktop_id);
}
static gboolean
g_desktop_app_info_load_from_keyfile (GDesktopAppInfo *info,
GKeyFile *key_file)
@ -1912,6 +1976,9 @@ g_desktop_app_info_load_from_keyfile (GDesktopAppInfo *info,
g_free (basename);
}
if (info->filename)
info->desktop_id = g_desktop_app_info_get_desktop_id_for_filename (info);
info->keyfile = g_key_file_ref (key_file);
return TRUE;
@ -1925,8 +1992,6 @@ g_desktop_app_info_load_file (GDesktopAppInfo *self)
g_return_val_if_fail (self->filename != NULL, FALSE);
self->desktop_id = g_path_get_basename (self->filename);
key_file = g_key_file_new ();
if (g_key_file_load_from_file (key_file, self->filename, G_KEY_FILE_NONE, NULL))
@ -1953,11 +2018,14 @@ g_desktop_app_info_new_from_keyfile (GKeyFile *key_file)
info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
info->filename = NULL;
desktop_file_dirs_lock ();
if (!g_desktop_app_info_load_from_keyfile (info, key_file))
{
g_object_unref (info);
return NULL;
}
g_clear_object (&info);
desktop_file_dirs_unlock ();
return info;
}
@ -1975,12 +2043,12 @@ g_desktop_app_info_new_from_filename (const char *filename)
{
GDesktopAppInfo *info = NULL;
info = g_object_new (G_TYPE_DESKTOP_APP_INFO, "filename", filename, NULL);
if (!g_desktop_app_info_load_file (info))
{
g_object_unref (info);
return NULL;
}
desktop_file_dirs_lock ();
info = g_desktop_app_info_new_from_filename_unlocked (filename);
desktop_file_dirs_unlock ();
return info;
}

View File

@ -797,6 +797,18 @@ test_launch_as_manager (void)
g_assert_finalize_object (context);
}
/* Test if Desktop-File Id is correctly formed */
static void
test_id (void)
{
gchar *result;
result = run_apps ("default-for-type", "application/vnd.kde.okular-archive",
TRUE, FALSE, NULL, NULL, NULL);
g_assert_cmpstr (result, ==, "kde4-okular.desktop\n");
g_free (result);
}
int
main (int argc,
char *argv[])
@ -818,6 +830,7 @@ main (int argc,
g_test_add_func ("/desktop-app-info/implements", test_implements);
g_test_add_func ("/desktop-app-info/show-in", test_show_in);
g_test_add_func ("/desktop-app-info/launch-as-manager", test_launch_as_manager);
g_test_add_func ("/desktop-app-info/id", test_id);
return g_test_run ();
}