Switch to using variants for timestamps, split out signals

Like how we're handling activation, use GVariant for timestamps.  To
avoid polluting the GtkApplication API with GVariants, we rename the
GApplication signals to "quit-with-data" and "action-with-data".
GtkApplication will then wrap those as just "quit" and "action".

https://bugzilla.gnome.org/show_bug.cgi?id=621002
This commit is contained in:
Colin Walters 2010-06-08 16:25:33 -04:00
parent 8c4e1fa0af
commit 85210bcf9b
8 changed files with 159 additions and 97 deletions

View File

@ -106,7 +106,7 @@
* <void/>
* <methodname>InvokeAction</methodname>
* <methodparam><modifier>in</modifier><type>s</type><parameter>action</parameter></methodparam>
* <methodparam><modifier>in</modifier><type>u</type><parameter>timestamp</parameter></methodparam>
* <methodparam><modifier>in</modifier><type>a{sv}</type><parameter>data</parameter></methodparam>
* </methodsynopsis>
* <methodsynopsis>
* <type>a{s(sb)}</type>
@ -116,7 +116,7 @@
* <methodsynopsis>
* <void/>
* <methodname>Quit</methodname>
* <methodparam><modifier>in</modifier><type>u</type><parameter>timestamp</parameter></methodparam>
* <methodparam><modifier>in</modifier><type>a{sv}</type><parameter>data</parameter></methodparam>
* </methodsynopsis>
* <methodsynopsis>
* <modifier>Signal</modifier>
@ -129,14 +129,13 @@
* The <methodname>Activate</methodname> function is called on the existing
* application instance when a second instance fails to take the bus name.
* @arguments contains the commandline arguments given to the second instance
* and @data contains platform-specific additional data, see
* g_application_format_activation_data().
* and @data contains platform-specific additional data.
* </para>
* <para>
* The <methodname>InvokeAction</methodname> function can be called to invoke
* one of the actions exported by the application. The @timestamp parameter
* should be taken from the user event that triggered the method call (e.g.
* a button press event).
* The <methodname>InvokeAction</methodname> function can be called to
* invoke one of the actions exported by the application. On X11
* platforms, the platform_data argument should have a "timestamp"
* parameter of type "u" with the server time of the initiating event.
* </para>
* <para>
* The <methodname>ListActions</methodname> function returns a dictionary
@ -145,9 +144,11 @@
* for the action and a boolean that represents if the action is enabled or not.
* </para>
* <para>
* The <methodname>Quit</methodname> function can be called to terminate
* the application. The @timestamp parameter should be taken from the user
* event that triggered the method call (e.g. a button press event).
* The <methodname>Quit</methodname> function can be called to
* terminate the application. The @data parameter contains
* platform-specific data. On X11 platforms, the platform_data
* argument should have a "timestamp" parameter of type "u" with the
* server time of the initiating event.
* </para>
* <para>
* The <methodname>ActionsChanged</methodname> signal is emitted when the
@ -173,8 +174,8 @@ enum
enum
{
QUIT,
ACTION,
QUIT_WITH_DATA,
ACTION_WITH_DATA,
PREPARE_ACTIVATION,
LAST_SIGNAL
@ -213,9 +214,9 @@ static gboolean _g_application_platform_acquire_single_instance (GApplication *
GError **error);
static void _g_application_platform_remote_invoke_action (GApplication *app,
const gchar *action,
guint timestamp);
GVariant *platform_data);
static void _g_application_platform_remote_quit (GApplication *app,
guint timestamp);
GVariant *platform_data);
static void _g_application_platform_activate (GApplication *app,
GVariant *data) G_GNUC_NORETURN;
static void _g_application_platform_on_actions_changed (GApplication *app);
@ -269,8 +270,8 @@ application_for_appid (const char *appid)
}
static gboolean
g_application_default_quit (GApplication *application,
guint timestamp)
g_application_default_quit_with_data (GApplication *application,
GVariant *platform_data)
{
g_return_val_if_fail (application->priv->mainloop != NULL, FALSE);
g_main_loop_quit (application->priv->mainloop);
@ -534,8 +535,7 @@ g_application_remove_action (GApplication *application,
* g_application_invoke_action:
* @application: a #GApplication
* @name: the name of the action to invoke
* @timestamp: the timestamp that is going to be passed to
* the #GApplication::action signal
* @platform_data: (allow-none): platform-specific event data
*
* Invokes the action @name of the passed #GApplication.
*
@ -555,19 +555,21 @@ g_application_remove_action (GApplication *application,
void
g_application_invoke_action (GApplication *application,
const gchar *name,
guint timestamp)
GVariant *platform_data)
{
GApplicationPrivate *priv;
GApplicationAction *action;
g_return_if_fail (G_IS_APPLICATION (application));
g_return_if_fail (name != NULL);
g_return_if_fail (platform_data == NULL
|| g_variant_is_of_type (platform_data, "a{sv}"));
priv = application->priv;
if (priv->is_remote)
{
_g_application_platform_remote_invoke_action (application, name, timestamp);
_g_application_platform_remote_invoke_action (application, name, platform_data);
return;
}
@ -576,10 +578,10 @@ g_application_invoke_action (GApplication *application,
if (!action->enabled)
return;
g_signal_emit (application, application_signals[ACTION],
g_signal_emit (application, application_signals[ACTION_WITH_DATA],
g_quark_from_string (name),
name,
timestamp);
platform_data);
}
/**
@ -751,9 +753,9 @@ g_application_run (GApplication *application)
}
/**
* g_application_quit:
* g_application_quit_with_data:
* @application: a #GApplication
* @timestamp: Platform-specific event timestamp, may be 0 for default
* @platform_data: (allow-none): platform-specific data
*
* Request that the application quits.
*
@ -770,20 +772,22 @@ g_application_run (GApplication *application)
* Since: 2.26
*/
gboolean
g_application_quit (GApplication *application,
guint timestamp)
g_application_quit_with_data (GApplication *application,
GVariant *platform_data)
{
gboolean retval = FALSE;
g_return_val_if_fail (G_IS_APPLICATION (application), FALSE);
g_return_val_if_fail (platform_data == NULL
|| g_variant_is_of_type (platform_data, "a{sv}"), FALSE);
if (application->priv->is_remote)
{
_g_application_platform_remote_quit (application, timestamp);
_g_application_platform_remote_quit (application, platform_data);
retval = TRUE;
}
else
g_signal_emit (application, application_signals[QUIT], 0, timestamp, &retval);
g_signal_emit (application, application_signals[QUIT_WITH_DATA], 0, platform_data, &retval);
return retval;
}
@ -976,12 +980,12 @@ g_application_class_init (GApplicationClass *klass)
gobject_class->finalize = g_application_finalize;
klass->run = g_application_default_run;
klass->quit = g_application_default_quit;
klass->quit_with_data = g_application_default_quit_with_data;
/**
* GApplication::quit:
* GApplication::quit-with-data:
* @application: the object on which the signal is emitted
* @timestamp: Platform-specific event timestamp, may be 0 for default
* @platform_data: Platform-specific data, or %NULL
*
* This signal is emitted when the Quit action is invoked on the
* application.
@ -992,21 +996,21 @@ g_application_class_init (GApplicationClass *klass)
* Returns: %TRUE if the signal has been handled, %FALSE to continue
* signal emission
*/
application_signals[QUIT] =
g_signal_new (g_intern_static_string ("quit"),
application_signals[QUIT_WITH_DATA] =
g_signal_new (g_intern_static_string ("quit-with-data"),
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GApplicationClass, quit),
G_STRUCT_OFFSET (GApplicationClass, quit_with_data),
g_signal_accumulator_true_handled, NULL,
_gio_marshal_BOOLEAN__UINT,
_gio_marshal_BOOLEAN__BOXED,
G_TYPE_BOOLEAN, 1,
G_TYPE_UINT);
G_TYPE_VARIANT);
/**
* GApplication::action:
* GApplication::action-with-data:
* @application: the object on which the signal is emitted
* @name: The name of the activated action
* @timestamp: Platform-specific event timestamp, may be 0 for default
* @platform_data: Platform-specific data, or %NULL
*
* This signal is emitted when an action is activated. The action name
* is passed as the first argument, but also as signal detail, so it
@ -1014,22 +1018,22 @@ g_application_class_init (GApplicationClass *klass)
*
* The signal is never emitted for disabled actions.
*/
application_signals[ACTION] =
g_signal_new (g_intern_static_string ("action"),
application_signals[ACTION_WITH_DATA] =
g_signal_new (g_intern_static_string ("action-with-data"),
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED,
G_STRUCT_OFFSET (GApplicationClass, action),
G_STRUCT_OFFSET (GApplicationClass, action_with_data),
NULL, NULL,
_gio_marshal_VOID__STRING_UINT,
_gio_marshal_VOID__STRING_BOXED,
G_TYPE_NONE, 2,
G_TYPE_STRING,
G_TYPE_UINT);
G_TYPE_VARIANT);
/**
* GApplication::prepare-activation:
* @application: the object on which the signal is emitted
* @arguments: A #GVariant with the signature "aay"
* @platform_data: A #GVariant with the signature "a{sv}"
* @platform_data: A #GVariant with the signature "a{sv}", or %NULL
*
* This signal is emitted when a non-primary process for a given
* application is invoked while your application is running; for

View File

@ -66,7 +66,6 @@ struct _GApplication
* @quit: class handler for the #GApplication::quit signal
* @prepare_activation: class handler for the #GApplication::prepare-activation signal
* @run: virtual function, called by g_application_run()
* @format_activation_data: virtual function, called by g_application_format_activation_data()
*
* The <structname>GApplicationClass</structname> structure contains
* private data only
@ -80,19 +79,17 @@ struct _GApplicationClass
/*< public >*/
/* signals */
void (* action) (GApplication *application,
const gchar *action_name,
guint timestamp);
gboolean (* quit) (GApplication *application,
guint timestamp);
void (* action_with_data) (GApplication *application,
const gchar *action_name,
GVariant *platform_data);
gboolean (* quit_with_data) (GApplication *application,
GVariant *platform_data);
void (* prepare_activation) (GApplication *application,
GVariant *arguments,
GVariant *platform_data);
/* vfuncs */
void (* run) (GApplication *application);
void (*format_activation_data) (GApplication *application,
GVariantBuilder *builder);
/*< private >*/
/* Padding for future expansion */
@ -130,22 +127,18 @@ void g_application_set_action_enabled (GApplication
gboolean enabled);
gboolean g_application_get_action_enabled (GApplication *application,
const gchar *name);
G_CONST_RETURN gchar * g_application_get_action_description (GApplication *application,
const gchar *name);
G_CONST_RETURN gchar * g_application_get_action_description (GApplication *application,
const gchar *name);
void g_application_invoke_action (GApplication *application,
const gchar *name,
guint timestamp);
GVariant *platform_data);
void g_application_run (GApplication *application);
gboolean g_application_quit (GApplication *app,
guint timestamp);
gboolean g_application_quit_with_data (GApplication *app,
GVariant *platform_data);
gboolean g_application_is_remote (GApplication *application);
void g_application_format_activation_data (GApplication *app,
GVariantBuilder *builder);
G_END_DECLS
#endif /* __G_APPLICATION_H__ */

View File

@ -39,12 +39,15 @@ application_dbus_method_call (GDBusConnection *connection,
if (strcmp (method_name, "Quit") == 0)
{
guint32 timestamp;
g_variant_get (parameters, "(u)", &timestamp);
GVariant *platform_data;
g_variant_get (parameters, "(@a{sv})", &platform_data);
g_dbus_method_invocation_return_value (invocation, NULL);
g_application_quit (app, timestamp);
g_application_quit_with_data (app, platform_data);
g_variant_unref (platform_data);
}
else if (strcmp (method_name, "ListActions") == 0)
{
@ -68,10 +71,10 @@ application_dbus_method_call (GDBusConnection *connection,
else if (strcmp (method_name, "InvokeAction") == 0)
{
const char *action_name;
guint32 timestamp;
GVariant *platform_data;
GApplicationAction *action;
g_variant_get (parameters, "(&su)", &action_name, &timestamp);
g_variant_get (parameters, "(&s@a{sv})", &action_name, &platform_data);
action = g_hash_table_lookup (app->priv->actions, action_name);
@ -80,12 +83,15 @@ application_dbus_method_call (GDBusConnection *connection,
char *errmsg = g_strdup_printf ("Invalid action: %s", action_name);
g_dbus_method_invocation_return_dbus_error (invocation, G_APPLICATION_IFACE ".InvalidAction", errmsg);
g_free (errmsg);
g_variant_unref (platform_data);
return;
}
g_signal_emit (app, application_signals[ACTION], g_quark_from_string (action_name), action_name, (guint)timestamp);
g_signal_emit (app, application_signals[ACTION_WITH_DATA],
g_quark_from_string (action_name), action_name, platform_data);
g_dbus_method_invocation_return_value (invocation, NULL);
g_variant_unref (platform_data);
}
else if (strcmp (method_name, "Activate") == 0)
{
@ -107,8 +113,8 @@ static const GDBusArgInfo application_quit_in_args[] =
{
{
-1,
"timestamp",
"u",
"platform_data",
"a{sv}",
NULL
}
};
@ -143,8 +149,8 @@ static const GDBusArgInfo application_invoke_action_in_args[] =
},
{
-1,
"timestamp",
"u",
"platform_data",
"a{sv}",
NULL
}
};
@ -253,6 +259,15 @@ static GDBusInterfaceVTable application_dbus_vtable =
NULL
};
static GVariant *
create_empty_vardict ()
{
GVariantBuilder builder;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
return g_variant_builder_end (&builder);
}
static gchar *
application_path_from_appid (const gchar *appid)
{
@ -368,7 +383,7 @@ _g_application_platform_on_actions_changed (GApplication *app)
static void
_g_application_platform_remote_invoke_action (GApplication *app,
const gchar *action,
guint timestamp)
GVariant *platform_data)
{
GVariant *result;
@ -379,9 +394,9 @@ _g_application_platform_remote_invoke_action (GApplication *app,
app->priv->dbus_path,
G_APPLICATION_IFACE,
"InvokeAction",
g_variant_new ("(su)",
g_variant_new ("(s@a{sv})",
action,
timestamp),
platform_data || create_empty_vardict ()),
NULL, 0, -1, NULL, NULL);
if (result)
g_variant_unref (result);
@ -389,7 +404,7 @@ _g_application_platform_remote_invoke_action (GApplication *app,
static void
_g_application_platform_remote_quit (GApplication *app,
guint timestamp)
GVariant *platform_data)
{
GVariant *result;
@ -400,8 +415,8 @@ _g_application_platform_remote_quit (GApplication *app,
app->priv->dbus_path,
G_APPLICATION_IFACE,
"Quit",
g_variant_new ("(u)",
timestamp),
g_variant_new ("(@a{sv})",
platform_data || create_empty_vardict ()),
NULL, 0, -1, NULL, NULL);
if (result)
g_variant_unref (result);

View File

@ -6,6 +6,8 @@ BOOLEAN:OBJECT,OBJECT
VOID:STRING,BOXED,BOXED
BOOL:POINTER,INT
BOOL:UINT
BOOL:BOXED
BOOL:VOID
VOID:STRING,STRING,BOXED
VOID:BOOL,BOXED
VOID:BOXED,BOXED

View File

@ -42,7 +42,7 @@ g_application_register_with_data
g_application_invoke_action
g_application_list_actions
g_application_run
g_application_quit
g_application_quit_with_data
g_application_is_remote
#endif
#endif

View File

@ -21,20 +21,60 @@ static gboolean action_invoked = FALSE;
static void
on_app_action (GApplication *application,
const gchar *action_name,
guint action_timestamp)
GVariant *platform_data)
{
gboolean found_timestamp;
GVariantIter *iter;
const char *key;
guint action_timestamp;
GVariant *value;
if (g_test_verbose ())
g_print ("Action '%s' invoked (timestamp: %u, expected: %u)\n",
action_name,
action_timestamp,
timestamp);
{
char *str = g_variant_print (platform_data, FALSE);
g_print ("Action '%s' invoked (data: %s, expected: %u)\n",
action_name,
str,
timestamp);
g_free (str);
}
g_assert_cmpstr (action_name, ==, "About");
g_assert_cmpint (action_timestamp, ==, timestamp);
g_variant_get (platform_data, "a{sv}", &iter);
found_timestamp = FALSE;
while (g_variant_iter_next (iter, "{&sv}",
&key, &value))
{
if (g_strcmp0 ("timestamp", key) == 0)
{
found_timestamp = TRUE;
g_variant_get (value, "u", &action_timestamp);
break;
}
}
g_variant_iter_free (iter);
g_assert_cmpuint (timestamp, ==, action_timestamp);
action_invoked = TRUE;
}
static GVariant *
create_timestamp_data ()
{
GVariantBuilder builder;
timestamp = 42 + timestamp;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&builder, "{sv}",
"timestamp", g_variant_new ("u", timestamp));
return g_variant_builder_end (&builder);
}
static gboolean
check_invoke_action (gpointer data)
{
@ -42,12 +82,11 @@ check_invoke_action (gpointer data)
if (state == INVOKE_ACTION)
{
timestamp = (guint) time (NULL);
if (g_test_verbose ())
g_print ("Invoking About...\n");
g_application_invoke_action (application, "About", timestamp);
g_application_invoke_action (application, "About", create_timestamp_data ());
state = CHECK_ACTION;
return TRUE;
}
@ -78,7 +117,7 @@ check_invoke_action (gpointer data)
if (g_test_verbose ())
g_print ("Invoking disabled About action...\n");
g_application_invoke_action (application, "About", (guint) time (NULL));
g_application_invoke_action (application, "About", create_timestamp_data ());
state = CHECK_DISABLED_ACTION;
return TRUE;
}
@ -98,7 +137,7 @@ check_invoke_action (gpointer data)
if (g_test_verbose ())
g_print ("Test complete\n");
g_application_quit (application, (guint) time (NULL));
g_application_quit_with_data (application, create_timestamp_data ());
return FALSE;
}
@ -113,7 +152,7 @@ test_basic (void)
app = g_application_new_and_register ("org.gtk.TestApplication", 0, NULL);
g_application_add_action (app, "About", "Print an about message");
g_signal_connect (app, "action::About", G_CALLBACK (on_app_action), NULL);
g_signal_connect (app, "action-with-data::About", G_CALLBACK (on_app_action), NULL);
state = INVOKE_ACTION;
g_timeout_add (100, check_invoke_action, app);

View File

@ -12,7 +12,7 @@ static gboolean action3_added = FALSE;
static void
on_app_action (GApplication *application,
const gchar *action_name,
guint action_timestamp)
GVariant *platform_data)
{
if (strcmp (action_name, "action1") == 0)
exit (1);
@ -72,7 +72,7 @@ main (int argc, char *argv[])
{
g_application_add_action (app, "action1", "Action1");
g_application_add_action (app, "action2", "Action2");
g_signal_connect (app, "action",
g_signal_connect (app, "action-with-data",
G_CALLBACK (on_app_action), NULL);
g_signal_connect (app, "prepare-activation",
G_CALLBACK (on_app_activated), NULL);

View File

@ -290,6 +290,15 @@ on_name_disappeared_quit (GDBusConnection *connection,
g_main_loop_quit (loop);
}
static GVariant *
create_empty_vardict ()
{
GVariantBuilder builder;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
return g_variant_builder_end (&builder);
}
static gboolean
call_quit (gpointer data)
{
@ -303,8 +312,8 @@ call_quit (gpointer data)
"/org/gtk/test/app",
"org.gtk.Application",
"Quit",
g_variant_new ("(u)", 0),
NULL,
g_variant_new ("(@a{sv})", create_empty_vardict ()),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
@ -447,9 +456,9 @@ invoke_action (gpointer user_data)
"/org/gtk/test/app",
"org.gtk.Application",
"InvokeAction",
g_variant_new ("(su)",
g_variant_new ("(s@a{sv})",
action,
0),
create_empty_vardict ()),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,