mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 15:06:14 +01:00
Implement the Desktop Action specification
For some time, the desktop file specification has supported "additional application actions". This is intended to allow for additional methods of starting an app, such as a mail client having a "Compose New Message" action that brings up the compose window instead of the folder list. This patch adds support for this with a relatively minimal API. In the case that the application is a GApplication and DBusActivatable, desktop actions are translated into GActions that have been added to the application with g_action_map_add_action(). This more or less closes the loop on being able to activate an application with an action invocation (instead of 'activate'). https://bugzilla.gnome.org/show_bug.cgi?id=664444
This commit is contained in:
parent
f77e121650
commit
6dc5c118e4
@ -1518,6 +1518,10 @@ g_desktop_app_info_get_boolean
|
|||||||
g_desktop_app_info_has_key
|
g_desktop_app_info_has_key
|
||||||
GDesktopAppLaunchCallback
|
GDesktopAppLaunchCallback
|
||||||
g_desktop_app_info_launch_uris_as_manager
|
g_desktop_app_info_launch_uris_as_manager
|
||||||
|
<SUBSECTION>
|
||||||
|
g_desktop_app_info_list_actions
|
||||||
|
g_desktop_app_info_get_action_name
|
||||||
|
g_desktop_app_info_launch_action
|
||||||
<SUBSECTION Standard>
|
<SUBSECTION Standard>
|
||||||
GDesktopAppInfoClass
|
GDesktopAppInfoClass
|
||||||
G_TYPE_DESKTOP_APP_INFO
|
G_TYPE_DESKTOP_APP_INFO
|
||||||
|
@ -115,6 +115,7 @@ struct _GDesktopAppInfo
|
|||||||
char *categories;
|
char *categories;
|
||||||
char *startup_wm_class;
|
char *startup_wm_class;
|
||||||
char **mime_types;
|
char **mime_types;
|
||||||
|
char **actions;
|
||||||
|
|
||||||
guint nodisplay : 1;
|
guint nodisplay : 1;
|
||||||
guint hidden : 1;
|
guint hidden : 1;
|
||||||
@ -200,6 +201,7 @@ g_desktop_app_info_finalize (GObject *object)
|
|||||||
g_free (info->startup_wm_class);
|
g_free (info->startup_wm_class);
|
||||||
g_strfreev (info->mime_types);
|
g_strfreev (info->mime_types);
|
||||||
g_free (info->app_id);
|
g_free (info->app_id);
|
||||||
|
g_strfreev (info->actions);
|
||||||
|
|
||||||
G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
|
G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
@ -380,6 +382,11 @@ g_desktop_app_info_load_from_keyfile (GDesktopAppInfo *info,
|
|||||||
info->startup_wm_class = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, STARTUP_WM_CLASS_KEY, NULL);
|
info->startup_wm_class = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, STARTUP_WM_CLASS_KEY, NULL);
|
||||||
info->mime_types = g_key_file_get_string_list (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_MIME_TYPE, NULL, NULL);
|
info->mime_types = g_key_file_get_string_list (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_MIME_TYPE, NULL, NULL);
|
||||||
bus_activatable = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE, NULL);
|
bus_activatable = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE, NULL);
|
||||||
|
info->actions = g_key_file_get_string_list (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ACTIONS, NULL, NULL);
|
||||||
|
|
||||||
|
/* Remove the special-case: no Actions= key just means 0 extra actions */
|
||||||
|
if (info->actions == NULL)
|
||||||
|
info->actions = g_new0 (gchar *, 0 + 1);
|
||||||
|
|
||||||
info->icon = NULL;
|
info->icon = NULL;
|
||||||
if (info->icon_name)
|
if (info->icon_name)
|
||||||
@ -1050,17 +1057,18 @@ expand_macro (char macro,
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
expand_application_parameters (GDesktopAppInfo *info,
|
expand_application_parameters (GDesktopAppInfo *info,
|
||||||
|
const gchar *exec_line,
|
||||||
GList **uris,
|
GList **uris,
|
||||||
int *argc,
|
int *argc,
|
||||||
char ***argv,
|
char ***argv,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
GList *uri_list = *uris;
|
GList *uri_list = *uris;
|
||||||
const char *p = info->exec;
|
const char *p = exec_line;
|
||||||
GString *expanded_exec;
|
GString *expanded_exec;
|
||||||
gboolean res;
|
gboolean res;
|
||||||
|
|
||||||
if (info->exec == NULL)
|
if (exec_line == NULL)
|
||||||
{
|
{
|
||||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
_("Desktop file didn't specify Exec field"));
|
_("Desktop file didn't specify Exec field"));
|
||||||
@ -1303,6 +1311,7 @@ notify_desktop_launch (GDBusConnection *session_bus,
|
|||||||
static gboolean
|
static gboolean
|
||||||
g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
||||||
GDBusConnection *session_bus,
|
GDBusConnection *session_bus,
|
||||||
|
const gchar *exec_line,
|
||||||
GList *uris,
|
GList *uris,
|
||||||
GAppLaunchContext *launch_context,
|
GAppLaunchContext *launch_context,
|
||||||
GSpawnFlags spawn_flags,
|
GSpawnFlags spawn_flags,
|
||||||
@ -1335,8 +1344,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
|
|||||||
char *display, *sn_id;
|
char *display, *sn_id;
|
||||||
|
|
||||||
old_uris = uris;
|
old_uris = uris;
|
||||||
if (!expand_application_parameters (info, &uris,
|
if (!expand_application_parameters (info, exec_line, &uris, &argc, &argv, error))
|
||||||
&argc, &argv, error))
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Get the subset of URIs we're launching with this process */
|
/* Get the subset of URIs we're launching with this process */
|
||||||
@ -1478,6 +1486,33 @@ object_path_from_appid (const gchar *app_id)
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GVariant *
|
||||||
|
g_desktop_app_info_make_platform_data (GDesktopAppInfo *info,
|
||||||
|
GList *uris,
|
||||||
|
GAppLaunchContext *launch_context)
|
||||||
|
{
|
||||||
|
GVariantBuilder builder;
|
||||||
|
|
||||||
|
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
|
||||||
|
|
||||||
|
if (launch_context)
|
||||||
|
{
|
||||||
|
GList *launched_files = create_files_for_uris (uris);
|
||||||
|
|
||||||
|
if (info->startup_notify)
|
||||||
|
{
|
||||||
|
gchar *sn_id;
|
||||||
|
|
||||||
|
sn_id = g_app_launch_context_get_startup_notify_id (launch_context, G_APP_INFO (info), launched_files);
|
||||||
|
g_variant_builder_add (&builder, "{sv}", "desktop-startup-id", g_variant_new_take_string (sn_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free_full (launched_files, g_object_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_variant_builder_end (&builder);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
g_desktop_app_info_launch_uris_with_dbus (GDesktopAppInfo *info,
|
g_desktop_app_info_launch_uris_with_dbus (GDesktopAppInfo *info,
|
||||||
GDBusConnection *session_bus,
|
GDBusConnection *session_bus,
|
||||||
@ -1501,24 +1536,7 @@ g_desktop_app_info_launch_uris_with_dbus (GDesktopAppInfo *info,
|
|||||||
g_variant_builder_close (&builder);
|
g_variant_builder_close (&builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_variant_builder_open (&builder, G_VARIANT_TYPE_VARDICT);
|
g_variant_builder_add_value (&builder, g_desktop_app_info_make_platform_data (info, uris, launch_context));
|
||||||
|
|
||||||
if (launch_context)
|
|
||||||
{
|
|
||||||
GList *launched_files = create_files_for_uris (uris);
|
|
||||||
|
|
||||||
if (info->startup_notify)
|
|
||||||
{
|
|
||||||
gchar *sn_id;
|
|
||||||
|
|
||||||
sn_id = g_app_launch_context_get_startup_notify_id (launch_context, G_APP_INFO (info), launched_files);
|
|
||||||
g_variant_builder_add (&builder, "{sv}", "desktop-startup-id", g_variant_new_take_string (sn_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
g_list_free_full (launched_files, g_object_unref);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_variant_builder_close (&builder);
|
|
||||||
|
|
||||||
/* This is non-blocking API. Similar to launching via fork()/exec()
|
/* This is non-blocking API. Similar to launching via fork()/exec()
|
||||||
* we don't wait around to see if the program crashed during startup.
|
* we don't wait around to see if the program crashed during startup.
|
||||||
@ -1553,7 +1571,7 @@ g_desktop_app_info_launch_uris_internal (GAppInfo *appinfo,
|
|||||||
if (session_bus && info->app_id)
|
if (session_bus && info->app_id)
|
||||||
g_desktop_app_info_launch_uris_with_dbus (info, session_bus, uris, launch_context);
|
g_desktop_app_info_launch_uris_with_dbus (info, session_bus, uris, launch_context);
|
||||||
else
|
else
|
||||||
success = g_desktop_app_info_launch_uris_with_spawn (info, session_bus, uris, launch_context,
|
success = g_desktop_app_info_launch_uris_with_spawn (info, session_bus, info->exec, uris, launch_context,
|
||||||
spawn_flags, user_setup, user_setup_data,
|
spawn_flags, user_setup, user_setup_data,
|
||||||
pid_callback, pid_callback_data, error);
|
pid_callback, pid_callback_data, error);
|
||||||
|
|
||||||
@ -3699,3 +3717,156 @@ g_desktop_app_info_has_key (GDesktopAppInfo *info,
|
|||||||
return g_key_file_has_key (info->keyfile,
|
return g_key_file_has_key (info->keyfile,
|
||||||
G_KEY_FILE_DESKTOP_GROUP, key, NULL);
|
G_KEY_FILE_DESKTOP_GROUP, key, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_desktop_app_info_list_actions:
|
||||||
|
* @info: a #GDesktopAppInfo
|
||||||
|
*
|
||||||
|
* Returns the list of "additional application actions" supported on the
|
||||||
|
* desktop file, as per the desktop file specification.
|
||||||
|
*
|
||||||
|
* As per the specification, this is the list of actions that are
|
||||||
|
* explicitly listed in the "Actions" key of the [Desktop Entry] group.
|
||||||
|
*
|
||||||
|
* Similar to g_app_info_get_all(), this returns all listed actions and
|
||||||
|
* ignores <literal>OnlyShowIn</literal> or <literal>NotShowIn</literal>
|
||||||
|
* keys. Use g_desktop_app_info_should_show_action() to determine if an
|
||||||
|
* action should actually be shown.
|
||||||
|
*
|
||||||
|
* Returns: (array zero-terminated=1) (element-type utf8) (transfer none): a list of strings, always non-%NULL
|
||||||
|
*
|
||||||
|
* Since: 2.38
|
||||||
|
**/
|
||||||
|
const gchar * const *
|
||||||
|
g_desktop_app_info_list_actions (GDesktopAppInfo *info)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (G_IS_DESKTOP_APP_INFO (info), NULL);
|
||||||
|
|
||||||
|
return (const gchar **) info->actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
app_info_has_action (GDesktopAppInfo *info,
|
||||||
|
const gchar *action_name)
|
||||||
|
{
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
for (i = 0; info->actions[i]; i++)
|
||||||
|
if (g_str_equal (info->actions[i], action_name))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_desktop_app_info_get_action_name:
|
||||||
|
* @info: a #GDesktopAppInfo
|
||||||
|
* @action_name: the name of the action as from
|
||||||
|
* g_desktop_app_info_list_actions()
|
||||||
|
*
|
||||||
|
* Gets the user-visible display name of the "additional application
|
||||||
|
* action" specified by @action_name.
|
||||||
|
*
|
||||||
|
* This corresponds to the "Name" key within the keyfile group for the
|
||||||
|
* action.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): the locale-specific action name
|
||||||
|
*
|
||||||
|
* Since: 2.38
|
||||||
|
*/
|
||||||
|
gchar *
|
||||||
|
g_desktop_app_info_get_action_name (GDesktopAppInfo *info,
|
||||||
|
const gchar *action_name)
|
||||||
|
{
|
||||||
|
gchar *group_name;
|
||||||
|
gchar *result;
|
||||||
|
|
||||||
|
g_return_val_if_fail (G_IS_DESKTOP_APP_INFO (info), NULL);
|
||||||
|
g_return_val_if_fail (action_name != NULL, NULL);
|
||||||
|
g_return_if_fail (app_info_has_action (info, action_name));
|
||||||
|
|
||||||
|
group_name = g_strdup_printf ("Desktop Action %s", action_name);
|
||||||
|
result = g_key_file_get_locale_string (info->keyfile, group_name, "Name", NULL, NULL);
|
||||||
|
g_free (group_name);
|
||||||
|
|
||||||
|
/* The spec says that the Name field must be given.
|
||||||
|
*
|
||||||
|
* If it's not, let's follow the behaviour of our get_name()
|
||||||
|
* implementation above and never return %NULL.
|
||||||
|
*/
|
||||||
|
if (result == NULL)
|
||||||
|
result = g_strdup (_("Unnamed"));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_desktop_app_info_launch_action:
|
||||||
|
* @info: a #GDesktopAppInfo
|
||||||
|
* @action_name: the name of the action as from
|
||||||
|
* g_desktop_app_info_list_actions()
|
||||||
|
* @launch_context: (allow-none): a #GAppLaunchContext
|
||||||
|
*
|
||||||
|
* Activates the named application action.
|
||||||
|
*
|
||||||
|
* You may only call this function on action names that were
|
||||||
|
* returned from g_desktop_app_info_list_actions().
|
||||||
|
*
|
||||||
|
* Note that if the main entry of the desktop file indicates that the
|
||||||
|
* application supports startup notification, and @launch_context is
|
||||||
|
* non-%NULL, then startup notification will be used when activating the
|
||||||
|
* action (and as such, invocation of the action on the receiving side
|
||||||
|
* must signal the end of startup notification when it is completed).
|
||||||
|
* This is the expected behaviour of applications declaring additional
|
||||||
|
* actions, as per the desktop file specification.
|
||||||
|
*
|
||||||
|
* As with g_app_info_launch() there is no way to detect failures that
|
||||||
|
* occur while using this function.
|
||||||
|
*
|
||||||
|
* Since: 2.38
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
g_desktop_app_info_launch_action (GDesktopAppInfo *info,
|
||||||
|
const gchar *action_name,
|
||||||
|
GAppLaunchContext *launch_context)
|
||||||
|
{
|
||||||
|
GDBusConnection *session_bus;
|
||||||
|
|
||||||
|
g_return_if_fail (G_IS_DESKTOP_APP_INFO (info));
|
||||||
|
g_return_if_fail (action_name != NULL);
|
||||||
|
g_return_if_fail (app_info_has_action (info, action_name));
|
||||||
|
|
||||||
|
session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
|
||||||
|
|
||||||
|
if (session_bus && info->app_id)
|
||||||
|
{
|
||||||
|
gchar *object_path;
|
||||||
|
|
||||||
|
object_path = object_path_from_appid (info->app_id);
|
||||||
|
g_dbus_connection_call (session_bus, info->app_id, object_path,
|
||||||
|
"org.freedesktop.Application", "ActivateAction",
|
||||||
|
g_variant_new ("(sav@a{sv})", action_name, NULL,
|
||||||
|
g_desktop_app_info_make_platform_data (info, NULL, launch_context)),
|
||||||
|
NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
|
||||||
|
g_free (object_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gchar *group_name;
|
||||||
|
gchar *exec_line;
|
||||||
|
|
||||||
|
group_name = g_strdup_printf ("Desktop Action %s", action_name);
|
||||||
|
exec_line = g_key_file_get_string (info->keyfile, group_name, "Exec", NULL);
|
||||||
|
g_free (group_name);
|
||||||
|
|
||||||
|
if (exec_line)
|
||||||
|
g_desktop_app_info_launch_uris_with_spawn (info, session_bus, exec_line, NULL, launch_context,
|
||||||
|
_SPAWN_FLAGS_DEFAULT, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_bus != NULL)
|
||||||
|
{
|
||||||
|
g_dbus_connection_flush (session_bus, NULL, NULL, NULL);
|
||||||
|
g_object_unref (session_bus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -86,6 +86,18 @@ GLIB_AVAILABLE_IN_2_36
|
|||||||
gboolean g_desktop_app_info_get_boolean (GDesktopAppInfo *info,
|
gboolean g_desktop_app_info_get_boolean (GDesktopAppInfo *info,
|
||||||
const char *key);
|
const char *key);
|
||||||
|
|
||||||
|
GLIB_AVAILABLE_IN_2_38
|
||||||
|
const gchar * const * g_desktop_app_info_list_actions (GDesktopAppInfo *info);
|
||||||
|
|
||||||
|
GLIB_AVAILABLE_IN_2_38
|
||||||
|
void g_desktop_app_info_launch_action (GDesktopAppInfo *info,
|
||||||
|
const gchar *action_name,
|
||||||
|
GAppLaunchContext *launch_context);
|
||||||
|
|
||||||
|
GLIB_AVAILABLE_IN_2_38
|
||||||
|
gchar * g_desktop_app_info_get_action_name (GDesktopAppInfo *info,
|
||||||
|
const gchar *action_name);
|
||||||
|
|
||||||
#ifndef G_DISABLE_DEPRECATED
|
#ifndef G_DISABLE_DEPRECATED
|
||||||
|
|
||||||
#define G_TYPE_DESKTOP_APP_INFO_LOOKUP (g_desktop_app_info_lookup_get_type ())
|
#define G_TYPE_DESKTOP_APP_INFO_LOOKUP (g_desktop_app_info_lookup_get_type ())
|
||||||
|
@ -226,6 +226,7 @@ uninstalled_test_programs += \
|
|||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
dist_test_data += \
|
dist_test_data += \
|
||||||
|
appinfo-test-actions.desktop \
|
||||||
appinfo-test-gnome.desktop \
|
appinfo-test-gnome.desktop \
|
||||||
appinfo-test-notgnome.desktop \
|
appinfo-test-notgnome.desktop \
|
||||||
appinfo-test.desktop \
|
appinfo-test.desktop \
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <gio/gdesktopappinfo.h>
|
#include <gio/gdesktopappinfo.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
static char *basedir;
|
static char *basedir;
|
||||||
|
|
||||||
@ -373,6 +374,82 @@ test_extra_getters (void)
|
|||||||
g_object_unref (appinfo);
|
g_object_unref (appinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wait_for_file (const gchar *want_this,
|
||||||
|
const gchar *but_not_this,
|
||||||
|
const gchar *or_this)
|
||||||
|
{
|
||||||
|
gint retries = 600;
|
||||||
|
|
||||||
|
/* I hate time-based conditions in tests, but this will wait up to one
|
||||||
|
* whole minute for "touch file" to finish running. I think it should
|
||||||
|
* be OK.
|
||||||
|
*
|
||||||
|
* 600 * 100ms = 60 seconds.
|
||||||
|
*/
|
||||||
|
while (access (want_this, F_OK) != 0)
|
||||||
|
{
|
||||||
|
g_usleep (100000); /* 100ms */
|
||||||
|
g_assert (retries);
|
||||||
|
retries--;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (access (but_not_this, F_OK) != 0);
|
||||||
|
g_assert (access (or_this, F_OK) != 0);
|
||||||
|
|
||||||
|
unlink (want_this);
|
||||||
|
unlink (but_not_this);
|
||||||
|
unlink (or_this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_actions (void)
|
||||||
|
{
|
||||||
|
const gchar * const *actions;
|
||||||
|
GDesktopAppInfo *appinfo;
|
||||||
|
gchar *name;
|
||||||
|
|
||||||
|
appinfo = g_desktop_app_info_new_from_filename (g_test_get_filename (G_TEST_DIST, "appinfo-test-actions.desktop", NULL));
|
||||||
|
g_assert (appinfo != NULL);
|
||||||
|
|
||||||
|
actions = g_desktop_app_info_list_actions (appinfo);
|
||||||
|
g_assert_cmpstr (actions[0], ==, "frob");
|
||||||
|
g_assert_cmpstr (actions[1], ==, "tweak");
|
||||||
|
g_assert_cmpstr (actions[2], ==, "twiddle");
|
||||||
|
g_assert_cmpstr (actions[3], ==, "broken");
|
||||||
|
g_assert_cmpstr (actions[4], ==, NULL);
|
||||||
|
|
||||||
|
name = g_desktop_app_info_get_action_name (appinfo, "frob");
|
||||||
|
g_assert_cmpstr (name, ==, "Frobnicate");
|
||||||
|
g_free (name);
|
||||||
|
|
||||||
|
name = g_desktop_app_info_get_action_name (appinfo, "tweak");
|
||||||
|
g_assert_cmpstr (name, ==, "Tweak");
|
||||||
|
g_free (name);
|
||||||
|
|
||||||
|
name = g_desktop_app_info_get_action_name (appinfo, "twiddle");
|
||||||
|
g_assert_cmpstr (name, ==, "Twiddle");
|
||||||
|
g_free (name);
|
||||||
|
|
||||||
|
name = g_desktop_app_info_get_action_name (appinfo, "broken");
|
||||||
|
g_assert (name != NULL);
|
||||||
|
g_assert (g_utf8_validate (name, -1, NULL));
|
||||||
|
g_free (name);
|
||||||
|
|
||||||
|
unlink ("frob"); unlink ("tweak"); unlink ("twiddle");
|
||||||
|
|
||||||
|
g_desktop_app_info_launch_action (appinfo, "frob", NULL);
|
||||||
|
wait_for_file ("frob", "tweak", "twiddle");
|
||||||
|
|
||||||
|
g_desktop_app_info_launch_action (appinfo, "tweak", NULL);
|
||||||
|
wait_for_file ("tweak", "frob", "twiddle");
|
||||||
|
|
||||||
|
g_desktop_app_info_launch_action (appinfo, "twiddle", NULL);
|
||||||
|
wait_for_file ("twiddle", "frob", "tweak");
|
||||||
|
|
||||||
|
g_object_unref (appinfo);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc,
|
main (int argc,
|
||||||
char *argv[])
|
char *argv[])
|
||||||
@ -390,6 +467,7 @@ main (int argc,
|
|||||||
g_test_add_func ("/desktop-app-info/fallback", test_fallback);
|
g_test_add_func ("/desktop-app-info/fallback", test_fallback);
|
||||||
g_test_add_func ("/desktop-app-info/lastused", test_last_used);
|
g_test_add_func ("/desktop-app-info/lastused", test_last_used);
|
||||||
g_test_add_func ("/desktop-app-info/extra-getters", test_extra_getters);
|
g_test_add_func ("/desktop-app-info/extra-getters", test_extra_getters);
|
||||||
|
g_test_add_func ("/desktop-app-info/actions", test_actions);
|
||||||
|
|
||||||
result = g_test_run ();
|
result = g_test_run ();
|
||||||
|
|
||||||
|
@ -306,6 +306,7 @@ gboolean g_key_file_remove_group (GKeyFile *key_file,
|
|||||||
#define G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS "StartupWMClass"
|
#define G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS "StartupWMClass"
|
||||||
#define G_KEY_FILE_DESKTOP_KEY_URL "URL"
|
#define G_KEY_FILE_DESKTOP_KEY_URL "URL"
|
||||||
#define G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE "DBusActivatable"
|
#define G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE "DBusActivatable"
|
||||||
|
#define G_KEY_FILE_DESKTOP_KEY_ACTIONS "Actions"
|
||||||
|
|
||||||
#define G_KEY_FILE_DESKTOP_TYPE_APPLICATION "Application"
|
#define G_KEY_FILE_DESKTOP_TYPE_APPLICATION "Application"
|
||||||
#define G_KEY_FILE_DESKTOP_TYPE_LINK "Link"
|
#define G_KEY_FILE_DESKTOP_TYPE_LINK "Link"
|
||||||
|
Loading…
Reference in New Issue
Block a user