Switch to using variants for timestamps, split out signals
authorColin Walters <walters@verbum.org>
Tue, 8 Jun 2010 20:25:33 +0000 (16:25 -0400)
committerColin Walters <walters@verbum.org>
Mon, 14 Jun 2010 20:36:23 +0000 (16:36 -0400)
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

gio/gapplication.c
gio/gapplication.h
gio/gdbusapplication.c
gio/gio-marshal.list
gio/gio.symbols
gio/tests/application.c
gio/tests/testapp.c
gio/tests/testapps.c

index 5981e9b..9f85db3 100644 (file)
  *     <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>
  *   <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>
  * 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
  * 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
index 7a77199..898c43a 100644 (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__ */
index e687199..e0f1fec 100644 (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);
index 14d7504..f4abf4d 100644 (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
index 689f96e..690dd81 100644 (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
index d8a1a63..d2e60dc 100644 (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);
index 85f93b7..34e88d6 100644 (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);
index 00a5f9f..854d7fa 100644 (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,