Merge branch 'misc-docs-and-tests-fixes' into 'main'

Misc docs fixes and test improvements in GAction and GNotificationBackend

See merge request GNOME/glib!3073
This commit is contained in:
Philip Withnall 2022-11-16 12:16:07 +00:00
commit 66bb4ab8cc
8 changed files with 127 additions and 128 deletions

View File

@ -437,8 +437,9 @@ g_action_name_is_valid (const gchar *action_name)
/**
* g_action_parse_detailed_name:
* @detailed_name: a detailed action name
* @action_name: (out): the action name
* @target_value: (out): the target value, or %NULL for no target
* @action_name: (out) (optional) (not nullable) (transfer full): the action name
* @target_value: (out) (optional) (nullable) (transfer full): the target value,
* or %NULL for no target
* @error: a pointer to a %NULL #GError, or %NULL
*
* Parses a detailed action name into its separate name and target
@ -448,23 +449,29 @@ g_action_name_is_valid (const gchar *action_name)
*
* The first format is used to represent an action name with no target
* value and consists of just an action name containing no whitespace
* nor the characters ':', '(' or ')'. For example: "app.action".
* nor the characters `:`, `(` or `)`. For example: `app.action`.
*
* The second format is used to represent an action with a target value
* that is a non-empty string consisting only of alphanumerics, plus '-'
* and '.'. In that case, the action name and target value are
* separated by a double colon ("::"). For example:
* "app.action::target".
* that is a non-empty string consisting only of alphanumerics, plus `-`
* and `.`. In that case, the action name and target value are
* separated by a double colon (`::`). For example:
* `app.action::target`.
*
* The third format is used to represent an action with any type of
* target value, including strings. The target value follows the action
* name, surrounded in parens. For example: "app.action(42)". The
* name, surrounded in parens. For example: `app.action(42)`. The
* target value is parsed using g_variant_parse(). If a tuple-typed
* value is desired, it must be specified in the same way, resulting in
* two sets of parens, for example: "app.action((1,2,3))". A string
* target can be specified this way as well: "app.action('target')".
* For strings, this third format must be used if * target value is
* empty or contains characters other than alphanumerics, '-' and '.'.
* two sets of parens, for example: `app.action((1,2,3))`. A string
* target can be specified this way as well: `app.action('target')`.
* For strings, this third format must be used if target value is
* empty or contains characters other than alphanumerics, `-` and `.`.
*
* If this function returns %TRUE, a non-%NULL value is guaranteed to be returned
* in @action_name (if a pointer is passed in). A %NULL value may still be
* returned in @target_value, as the @detailed_name may not contain a target.
*
* If returned, the #GVariant in @target_value is guaranteed to not be floating.
*
* Returns: %TRUE if successful, else %FALSE with @error set
*

View File

@ -497,7 +497,7 @@ g_application_command_line_get_arguments (GApplicationCommandLine *cmdline,
* g_application_command_line_get_options_dict:
* @cmdline: a #GApplicationCommandLine
*
* Gets the options there were passed to g_application_command_line().
* Gets the options that were passed to g_application_command_line().
*
* If you did not override local_command_line() then these are the same
* options that were parsed according to the #GOptionEntrys added to the
@ -795,7 +795,7 @@ g_application_command_line_get_exit_status (GApplicationCommandLine *cmdline)
*
* For local invocation, it will be %NULL.
*
* Returns: (nullable): the platform data, or %NULL
* Returns: (nullable) (transfer full): the platform data, or %NULL
*
* Since: 2.28
**/

View File

@ -63,8 +63,8 @@ typedef struct
GFdoNotificationBackend *backend;
gchar *id;
guint32 notify_id;
gchar *default_action;
GVariant *default_action_target;
gchar *default_action; /* (nullable) (owned) */
GVariant *default_action_target; /* (nullable) (owned), not floating */
} FreedesktopNotification;
static void
@ -138,6 +138,9 @@ activate_action (GFdoNotificationBackend *backend,
{
GNotificationBackend *g_backend = G_NOTIFICATION_BACKEND (backend);
/* Callers should not provide a floating variant here */
g_assert (parameter == NULL || !g_variant_is_floating (parameter));
if (name)
{
if (g_str_has_prefix (name, "app."))

View File

@ -50,7 +50,7 @@ g_gtk_notification_backend_is_supported (void)
GVariant *reply;
/* Find out if the notification server is running. This is a
* synchronous call because gio extension points don't support asnyc
* synchronous call because gio extension points don't support async
* backend verification. This is only run once and only contacts the
* dbus daemon. */

View File

@ -102,7 +102,7 @@ struct _GNotification
gchar *category;
GPtrArray *buttons;
gchar *default_action;
GVariant *default_action_target;
GVariant *default_action_target; /* (nullable) (owned), not floating */
};
typedef struct
@ -355,11 +355,11 @@ g_notification_set_urgent (GNotification *notification,
* g_notification_get_category:
* @notification: a #GNotification
*
* Gets the cateogry of @notification.
* Gets the category of @notification.
*
* This will be %NULL if no category is set.
*
* Returns: (nullable): the cateogry of @notification
* Returns: (nullable): the category of @notification
*
* Since: 2.70
*/
@ -615,11 +615,17 @@ g_notification_get_button_with_action (GNotification *notification,
/*< private >
* g_notification_get_default_action:
* @notification: a #GNotification
* @action: (nullable): return location for the default action
* @target: (nullable): return location for the target of the default action
* @action: (out) (optional) (nullable) (transfer full): return location for the
* default action, or %NULL if unset
* @target: (out) (optional) (nullable) (transfer full): return location for the
* target of the default action, or %NULL if unset
*
* Gets the action and target for the default action of @notification.
*
* If this function returns %TRUE, @action is guaranteed to be set to a non-%NULL
* value (if a pointer is passed to @action). @target may still return a %NULL
* value, as the default action may have no target.
*
* Returns: %TRUE if @notification has a default action
*/
gboolean
@ -736,7 +742,7 @@ g_notification_set_default_action_and_target (GNotification *notification,
* application-wide action (start with "app.").
*
* If @target is non-%NULL, @action will be activated with @target as
* its parameter.
* its parameter. If @target is floating, it will be consumed.
*
* When no default action is set, the application that the notification
* was sent on is activated.

View File

@ -28,9 +28,23 @@
G_DEFINE_TYPE (GNotificationBackend, g_notification_backend, G_TYPE_OBJECT)
static void
g_notification_backend_dispose (GObject *obj)
{
GNotificationBackend *backend = G_NOTIFICATION_BACKEND (obj);
backend->application = NULL; /* no reference held, but clear the pointer anyway to avoid it dangling */
g_clear_object (&backend->dbus_connection);
G_OBJECT_CLASS (g_notification_backend_parent_class)->dispose (obj);
}
static void
g_notification_backend_class_init (GNotificationBackendClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = g_notification_backend_dispose;
}
static void

View File

@ -94,7 +94,7 @@ _g_object_unref_and_wait_weak_notify (gpointer object)
g_idle_add (unref_on_idle, object);
/* Make sure we don't block forever */
timeout_id = g_timeout_add (30 * 1000, on_weak_notify_timeout, &data);
timeout_id = g_timeout_add_seconds (30, on_weak_notify_timeout, &data);
g_main_loop_run (data.loop);

View File

@ -2,6 +2,7 @@
* Copyright © 2010, 2011, 2013, 2014 Codethink Limited
* Copyright © 2010, 2011, 2012, 2013, 2015 Red Hat, Inc.
* Copyright © 2012 Pavel Vasin
* Copyright © 2022 Endless OS Foundation, LLC
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
@ -644,11 +645,13 @@ compare_action_groups (GActionGroup *a, GActionGroup *b)
}
static gboolean
stop_loop (gpointer data)
timeout_cb (gpointer user_data)
{
GMainLoop *loop = data;
gboolean *timed_out = user_data;
g_main_loop_quit (loop);
g_assert_false (*timed_out);
*timed_out = TRUE;
g_main_context_wakeup (NULL);
return G_SOURCE_REMOVE;
}
@ -664,96 +667,16 @@ static GActionEntry exported_entries[] = {
};
static void
list_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
async_result_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
GDBusConnection *bus = G_DBUS_CONNECTION (source);
GMainLoop *loop = user_data;
GError *error = NULL;
GVariant *v;
gchar **actions;
GAsyncResult **result_out = user_data;
v = g_dbus_connection_call_finish (bus, res, &error);
g_assert_nonnull (v);
g_variant_get (v, "(^a&s)", &actions);
g_assert_cmpint (g_strv_length (actions), ==, G_N_ELEMENTS (exported_entries));
g_free (actions);
g_variant_unref (v);
g_main_loop_quit (loop);
}
g_assert_null (*result_out);
*result_out = g_object_ref (res);
static gboolean
call_list (gpointer user_data)
{
GDBusConnection *bus;
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
g_dbus_connection_call (bus,
g_dbus_connection_get_unique_name (bus),
"/",
"org.gtk.Actions",
"List",
NULL,
NULL,
0,
G_MAXINT,
NULL,
list_cb,
user_data);
g_object_unref (bus);
return G_SOURCE_REMOVE;
}
static void
describe_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
GDBusConnection *bus = G_DBUS_CONNECTION (source);
GMainLoop *loop = user_data;
GError *error = NULL;
GVariant *v;
gboolean enabled;
gchar *param;
GVariantIter *iter;
v = g_dbus_connection_call_finish (bus, res, &error);
g_assert_nonnull (v);
/* FIXME: there's an extra level of tuplelization in here */
g_variant_get (v, "((bgav))", &enabled, &param, &iter);
g_assert_true (enabled);
g_assert_cmpstr (param, ==, "");
g_assert_cmpint (g_variant_iter_n_children (iter), ==, 0);
g_free (param);
g_variant_iter_free (iter);
g_variant_unref (v);
g_main_loop_quit (loop);
}
static gboolean
call_describe (gpointer user_data)
{
GDBusConnection *bus;
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
g_dbus_connection_call (bus,
g_dbus_connection_get_unique_name (bus),
"/",
"org.gtk.Actions",
"Describe",
g_variant_new ("(s)", "copy"),
NULL,
0,
G_MAXINT,
NULL,
describe_cb,
user_data);
g_object_unref (bus);
return G_SOURCE_REMOVE;
g_main_context_wakeup (NULL);
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
@ -800,15 +723,16 @@ test_dbus_export (void)
GSimpleActionGroup *group;
GDBusActionGroup *proxy;
GSimpleAction *action;
GMainLoop *loop;
GError *error = NULL;
GVariant *v;
guint id;
gchar **actions;
guint n_actions_added = 0, n_actions_enabled_changed = 0, n_actions_removed = 0, n_actions_state_changed = 0;
gulong added_signal_id, enabled_changed_signal_id, removed_signal_id, state_changed_signal_id;
loop = g_main_loop_new (NULL, FALSE);
gboolean enabled;
gchar *param;
GVariantIter *iter;
GAsyncResult *async_result = NULL;
session_bus_up ();
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
@ -842,12 +766,60 @@ test_dbus_export (void)
g_strfreev (actions);
/* check that calling "List" works too */
g_idle_add (call_list, loop);
g_main_loop_run (loop);
g_dbus_connection_call (bus,
g_dbus_connection_get_unique_name (bus),
"/",
"org.gtk.Actions",
"List",
NULL,
NULL,
0,
G_MAXINT,
NULL,
async_result_cb,
&async_result);
while (async_result == NULL)
g_main_context_iteration (NULL, TRUE);
v = g_dbus_connection_call_finish (bus, async_result, &error);
g_assert_no_error (error);
g_assert_nonnull (v);
g_variant_get (v, "(^a&s)", &actions);
g_assert_cmpuint (g_strv_length (actions), ==, G_N_ELEMENTS (exported_entries));
g_free (actions);
g_variant_unref (v);
g_clear_object (&async_result);
/* check that calling "Describe" works */
g_idle_add (call_describe, loop);
g_main_loop_run (loop);
g_dbus_connection_call (bus,
g_dbus_connection_get_unique_name (bus),
"/",
"org.gtk.Actions",
"Describe",
g_variant_new ("(s)", "copy"),
NULL,
0,
G_MAXINT,
NULL,
async_result_cb,
&async_result);
while (async_result == NULL)
g_main_context_iteration (NULL, TRUE);
v = g_dbus_connection_call_finish (bus, async_result, &error);
g_assert_no_error (error);
g_assert_nonnull (v);
/* FIXME: there's an extra level of tuplelization in here */
g_variant_get (v, "((bgav))", &enabled, &param, &iter);
g_assert_true (enabled);
g_assert_cmpstr (param, ==, "");
g_assert_cmpint (g_variant_iter_n_children (iter), ==, 0);
g_free (param);
g_variant_iter_free (iter);
g_variant_unref (v);
g_clear_object (&async_result);
/* test that the initial transfer works */
g_assert_true (G_IS_DBUS_ACTION_GROUP (proxy));
@ -931,7 +903,6 @@ test_dbus_export (void)
g_signal_handler_disconnect (proxy, state_changed_signal_id);
g_object_unref (proxy);
g_object_unref (group);
g_main_loop_unref (loop);
g_object_unref (bus);
session_bus_down ();
@ -1016,9 +987,7 @@ test_bug679509 (void)
{
GDBusConnection *bus;
GDBusActionGroup *proxy;
GMainLoop *loop;
loop = g_main_loop_new (NULL, FALSE);
gboolean timed_out = FALSE;
session_bus_up ();
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
@ -1027,10 +996,10 @@ test_bug679509 (void)
g_strfreev (g_action_group_list_actions (G_ACTION_GROUP (proxy)));
g_object_unref (proxy);
g_timeout_add (100, stop_loop, loop);
g_main_loop_run (loop);
g_timeout_add (100, timeout_cb, &timed_out);
while (!timed_out)
g_main_context_iteration (NULL, TRUE);
g_main_loop_unref (loop);
g_object_unref (bus);
session_bus_down ();