| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | /*
 | 
					
						
							|  |  |  |  |  * Copyright © 2010 Codethink Limited | 
					
						
							|  |  |  |  |  * Copyright © 2011 Canonical Limited | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2022-05-18 09:12:45 +01:00
										 |  |  |  |  * SPDX-License-Identifier: LGPL-2.1-or-later | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2017-05-27 18:21:30 +02:00
										 |  |  |  |  * This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							|  |  |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * You should have received a copy of the GNU Lesser General | 
					
						
							| 
									
										
										
										
											2014-01-23 12:58:29 +01:00
										 |  |  |  |  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Authors: Ryan Lortie <desrt@desrt.ca> | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include "config.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include "gactiongroupexporter.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include "gdbusmethodinvocation.h"
 | 
					
						
							| 
									
										
										
										
											2011-12-17 00:26:11 -05:00
										 |  |  |  | #include "gremoteactiongroup.h"
 | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | #include "gdbusintrospection.h"
 | 
					
						
							|  |  |  |  | #include "gdbusconnection.h"
 | 
					
						
							|  |  |  |  | #include "gactiongroup.h"
 | 
					
						
							|  |  |  |  | #include "gdbuserror.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2023-10-23 00:07:36 +01:00
										 |  |  |  |  * GActionGroupExporter: | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2024-05-30 14:57:26 +02:00
										 |  |  |  |  * These functions support exporting a [iface@Gio.ActionGroup] on D-Bus. | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |  * The D-Bus interface that is used is a private implementation | 
					
						
							|  |  |  |  |  * detail. | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2023-10-23 00:07:36 +01:00
										 |  |  |  |  * To access an exported `GActionGroup` remotely, use | 
					
						
							|  |  |  |  |  * [method@Gio.DBusActionGroup.get] to obtain a [class@Gio.DBusActionGroup]. | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-01 19:43:02 -04:00
										 |  |  |  | static GVariant * | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | g_action_group_describe_action (GActionGroup *action_group, | 
					
						
							|  |  |  |  |                                 const gchar  *name) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   const GVariantType *type; | 
					
						
							|  |  |  |  |   GVariantBuilder builder; | 
					
						
							|  |  |  |  |   gboolean enabled; | 
					
						
							|  |  |  |  |   GVariant *state; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-25 11:09:07 -07:00
										 |  |  |  |   g_variant_builder_init_static (&builder, G_VARIANT_TYPE ("(bgav)")); | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   enabled = g_action_group_get_action_enabled (action_group, name); | 
					
						
							|  |  |  |  |   g_variant_builder_add (&builder, "b", enabled); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if ((type = g_action_group_get_action_parameter_type (action_group, name))) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       gchar *str = g_variant_type_dup_string (type); | 
					
						
							|  |  |  |  |       g_variant_builder_add (&builder, "g", str); | 
					
						
							|  |  |  |  |       g_free (str); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     g_variant_builder_add (&builder, "g", ""); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_variant_builder_open (&builder, G_VARIANT_TYPE ("av")); | 
					
						
							|  |  |  |  |   if ((state = g_action_group_get_action_state (action_group, name))) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_variant_builder_add (&builder, "v", state); | 
					
						
							|  |  |  |  |       g_variant_unref (state); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   g_variant_builder_close (&builder); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return g_variant_builder_end (&builder); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* Using XML saves us dozens of relocations vs. using the introspection
 | 
					
						
							|  |  |  |  |  * structure types.  We only need to burn cycles and memory if we | 
					
						
							|  |  |  |  |  * actually use the exporter -- not in every single app using GIO. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * It's also a lot easier to read. :) | 
					
						
							| 
									
										
										
										
											2011-12-20 12:15:05 -05:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * For documentation of this interface, see | 
					
						
							| 
									
										
										
										
											2014-07-01 23:52:19 -05:00
										 |  |  |  |  * https://wiki.gnome.org/Projects/GLib/GApplication/DBusAPI
 | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |  */ | 
					
						
							|  |  |  |  | const char org_gtk_Actions_xml[] = | 
					
						
							|  |  |  |  |   "<node>" | 
					
						
							|  |  |  |  |   "  <interface name='org.gtk.Actions'>" | 
					
						
							|  |  |  |  |   "    <method name='List'>" | 
					
						
							|  |  |  |  |   "      <arg type='as' name='list' direction='out'/>" | 
					
						
							|  |  |  |  |   "    </method>" | 
					
						
							|  |  |  |  |   "    <method name='Describe'>" | 
					
						
							|  |  |  |  |   "      <arg type='s' name='action_name' direction='in'/>" | 
					
						
							|  |  |  |  |   "      <arg type='(bgav)' name='description' direction='out'/>" | 
					
						
							|  |  |  |  |   "    </method>" | 
					
						
							|  |  |  |  |   "    <method name='DescribeAll'>" | 
					
						
							|  |  |  |  |   "      <arg type='a{s(bgav)}' name='descriptions' direction='out'/>" | 
					
						
							|  |  |  |  |   "    </method>" | 
					
						
							|  |  |  |  |   "    <method name='Activate'>" | 
					
						
							|  |  |  |  |   "      <arg type='s' name='action_name' direction='in'/>" | 
					
						
							|  |  |  |  |   "      <arg type='av' name='parameter' direction='in'/>" | 
					
						
							|  |  |  |  |   "      <arg type='a{sv}' name='platform_data' direction='in'/>" | 
					
						
							|  |  |  |  |   "    </method>" | 
					
						
							|  |  |  |  |   "    <method name='SetState'>" | 
					
						
							|  |  |  |  |   "      <arg type='s' name='action_name' direction='in'/>" | 
					
						
							|  |  |  |  |   "      <arg type='v' name='value' direction='in'/>" | 
					
						
							|  |  |  |  |   "      <arg type='a{sv}' name='platform_data' direction='in'/>" | 
					
						
							|  |  |  |  |   "    </method>" | 
					
						
							|  |  |  |  |   "    <signal name='Changed'>" | 
					
						
							|  |  |  |  |   "      <arg type='as' name='removals'/>" | 
					
						
							|  |  |  |  |   "      <arg type='a{sb}' name='enable_changes'/>" | 
					
						
							|  |  |  |  |   "      <arg type='a{sv}' name='state_changes'/>" | 
					
						
							|  |  |  |  |   "      <arg type='a{s(bgav)}' name='additions'/>" | 
					
						
							|  |  |  |  |   "    </signal>" | 
					
						
							|  |  |  |  |   "  </interface>" | 
					
						
							|  |  |  |  |   "</node>"; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GDBusInterfaceInfo *org_gtk_Actions; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | typedef struct | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GActionGroup    *action_group; | 
					
						
							|  |  |  |  |   GDBusConnection *connection; | 
					
						
							| 
									
										
										
										
											2011-12-07 20:39:23 -05:00
										 |  |  |  |   GMainContext    *context; | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |   gchar           *object_path; | 
					
						
							|  |  |  |  |   GHashTable      *pending_changes; | 
					
						
							| 
									
										
										
										
											2011-12-07 20:23:41 -05:00
										 |  |  |  |   GSource         *pending_source; | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | } GActionGroupExporter; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #define ACTION_ADDED_EVENT             (1u<<0)
 | 
					
						
							|  |  |  |  | #define ACTION_REMOVED_EVENT           (1u<<1)
 | 
					
						
							|  |  |  |  | #define ACTION_STATE_CHANGED_EVENT     (1u<<2)
 | 
					
						
							|  |  |  |  | #define ACTION_ENABLED_CHANGED_EVENT   (1u<<3)
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static gboolean | 
					
						
							|  |  |  |  | g_action_group_exporter_dispatch_events (gpointer user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GActionGroupExporter *exporter = user_data; | 
					
						
							|  |  |  |  |   GVariantBuilder removes; | 
					
						
							|  |  |  |  |   GVariantBuilder enabled_changes; | 
					
						
							|  |  |  |  |   GVariantBuilder state_changes; | 
					
						
							|  |  |  |  |   GVariantBuilder adds; | 
					
						
							|  |  |  |  |   GHashTableIter iter; | 
					
						
							|  |  |  |  |   gpointer value; | 
					
						
							|  |  |  |  |   gpointer key; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-25 11:09:07 -07:00
										 |  |  |  |   g_variant_builder_init_static (&removes, G_VARIANT_TYPE_STRING_ARRAY); | 
					
						
							|  |  |  |  |   g_variant_builder_init_static (&enabled_changes, G_VARIANT_TYPE ("a{sb}")); | 
					
						
							|  |  |  |  |   g_variant_builder_init_static (&state_changes, G_VARIANT_TYPE ("a{sv}")); | 
					
						
							|  |  |  |  |   g_variant_builder_init_static (&adds, G_VARIANT_TYPE ("a{s(bgav)}")); | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_hash_table_iter_init (&iter, exporter->pending_changes); | 
					
						
							|  |  |  |  |   while (g_hash_table_iter_next (&iter, &key, &value)) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       guint events = GPOINTER_TO_INT (value); | 
					
						
							|  |  |  |  |       const gchar *name = key; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       /* Adds and removes are incompatible with enabled or state
 | 
					
						
							|  |  |  |  |        * changes, but we must report at least one event. | 
					
						
							|  |  |  |  |        */ | 
					
						
							|  |  |  |  |       g_assert (((events & (ACTION_ENABLED_CHANGED_EVENT | ACTION_STATE_CHANGED_EVENT)) == 0) != | 
					
						
							|  |  |  |  |                 ((events & (ACTION_REMOVED_EVENT | ACTION_ADDED_EVENT)) == 0)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (events & ACTION_REMOVED_EVENT) | 
					
						
							|  |  |  |  |         g_variant_builder_add (&removes, "s", name); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (events & ACTION_ENABLED_CHANGED_EVENT) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           gboolean enabled; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           enabled = g_action_group_get_action_enabled (exporter->action_group, name); | 
					
						
							|  |  |  |  |           g_variant_builder_add (&enabled_changes, "{sb}", name, enabled); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (events & ACTION_STATE_CHANGED_EVENT) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           GVariant *state; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           state = g_action_group_get_action_state (exporter->action_group, name); | 
					
						
							|  |  |  |  |           g_variant_builder_add (&state_changes, "{sv}", name, state); | 
					
						
							|  |  |  |  |           g_variant_unref (state); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (events & ACTION_ADDED_EVENT) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           GVariant *description; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           description = g_action_group_describe_action (exporter->action_group, name); | 
					
						
							|  |  |  |  |           g_variant_builder_add (&adds, "{s@(bgav)}", name, description); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_hash_table_remove_all (exporter->pending_changes); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_dbus_connection_emit_signal (exporter->connection, NULL, exporter->object_path, | 
					
						
							|  |  |  |  |                                  "org.gtk.Actions", "Changed", | 
					
						
							|  |  |  |  |                                  g_variant_new ("(asa{sb}a{sv}a{s(bgav)})", | 
					
						
							|  |  |  |  |                                                 &removes, &enabled_changes, | 
					
						
							|  |  |  |  |                                                 &state_changes, &adds), | 
					
						
							|  |  |  |  |                                  NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-07 20:23:41 -05:00
										 |  |  |  |   exporter->pending_source = NULL; | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   return FALSE; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-21 12:32:20 -05:00
										 |  |  |  | static void | 
					
						
							|  |  |  |  | g_action_group_exporter_flush_queue (GActionGroupExporter *exporter) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   if (exporter->pending_source) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_source_destroy (exporter->pending_source); | 
					
						
							|  |  |  |  |       g_action_group_exporter_dispatch_events (exporter); | 
					
						
							|  |  |  |  |       g_assert (exporter->pending_source == NULL); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | static guint | 
					
						
							|  |  |  |  | g_action_group_exporter_get_events (GActionGroupExporter *exporter, | 
					
						
							|  |  |  |  |                                     const gchar          *name) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   return (gsize) g_hash_table_lookup (exporter->pending_changes, name); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_action_group_exporter_set_events (GActionGroupExporter *exporter, | 
					
						
							|  |  |  |  |                                     const gchar          *name, | 
					
						
							|  |  |  |  |                                     guint                 events) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   gboolean have_events; | 
					
						
							|  |  |  |  |   gboolean is_queued; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (events != 0) | 
					
						
							|  |  |  |  |     g_hash_table_insert (exporter->pending_changes, g_strdup (name), GINT_TO_POINTER (events)); | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     g_hash_table_remove (exporter->pending_changes, name); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   have_events = g_hash_table_size (exporter->pending_changes) > 0; | 
					
						
							| 
									
										
										
										
											2011-12-07 20:23:41 -05:00
										 |  |  |  |   is_queued = exporter->pending_source != NULL; | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (have_events && !is_queued) | 
					
						
							| 
									
										
										
										
											2011-12-07 20:23:41 -05:00
										 |  |  |  |     { | 
					
						
							|  |  |  |  |       GSource *source; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       source = g_idle_source_new (); | 
					
						
							|  |  |  |  |       exporter->pending_source = source; | 
					
						
							|  |  |  |  |       g_source_set_callback (source, g_action_group_exporter_dispatch_events, exporter, NULL); | 
					
						
							| 
									
										
										
										
											2021-07-26 10:53:02 +01:00
										 |  |  |  |       g_source_set_static_name (source, "[gio] g_action_group_exporter_dispatch_events"); | 
					
						
							| 
									
										
										
										
											2011-12-07 20:39:23 -05:00
										 |  |  |  |       g_source_attach (source, exporter->context); | 
					
						
							| 
									
										
										
										
											2011-12-07 20:23:41 -05:00
										 |  |  |  |       g_source_unref (source); | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (!have_events && is_queued) | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-12-07 20:23:41 -05:00
										 |  |  |  |       g_source_destroy (exporter->pending_source); | 
					
						
							|  |  |  |  |       exporter->pending_source = NULL; | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_action_group_exporter_action_added (GActionGroup *action_group, | 
					
						
							|  |  |  |  |                                       const gchar  *action_name, | 
					
						
							|  |  |  |  |                                       gpointer      user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GActionGroupExporter *exporter = user_data; | 
					
						
							|  |  |  |  |   guint event_mask; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   event_mask = g_action_group_exporter_get_events (exporter, action_name); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* The action is new, so we should not have any pending
 | 
					
						
							|  |  |  |  |    * enabled-changed or state-changed signals for it. | 
					
						
							|  |  |  |  |    */ | 
					
						
							|  |  |  |  |   g_assert (~event_mask & (ACTION_STATE_CHANGED_EVENT | | 
					
						
							|  |  |  |  |                            ACTION_ENABLED_CHANGED_EVENT)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   event_mask |= ACTION_ADDED_EVENT; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_action_group_exporter_set_events (exporter, action_name, event_mask); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_action_group_exporter_action_removed (GActionGroup *action_group, | 
					
						
							|  |  |  |  |                                         const gchar  *action_name, | 
					
						
							|  |  |  |  |                                         gpointer      user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GActionGroupExporter *exporter = user_data; | 
					
						
							|  |  |  |  |   guint event_mask; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   event_mask = g_action_group_exporter_get_events (exporter, action_name); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* If the add event for this is still queued then just cancel it since
 | 
					
						
							|  |  |  |  |    * it's gone now. | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * If the event was freshly added, there should not have been any | 
					
						
							|  |  |  |  |    * enabled or state changed events. | 
					
						
							|  |  |  |  |    */ | 
					
						
							|  |  |  |  |   if (event_mask & ACTION_ADDED_EVENT) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_assert (~event_mask & ~(ACTION_STATE_CHANGED_EVENT | ACTION_ENABLED_CHANGED_EVENT)); | 
					
						
							|  |  |  |  |       event_mask &= ~ACTION_ADDED_EVENT; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* Otherwise, queue a remove event.  Drop any state or enabled changes
 | 
					
						
							|  |  |  |  |    * that were queued before the remove. */ | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       event_mask |= ACTION_REMOVED_EVENT; | 
					
						
							|  |  |  |  |       event_mask &= ~(ACTION_STATE_CHANGED_EVENT | ACTION_ENABLED_CHANGED_EVENT); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_action_group_exporter_set_events (exporter, action_name, event_mask); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_action_group_exporter_action_state_changed (GActionGroup *action_group, | 
					
						
							|  |  |  |  |                                               const gchar  *action_name, | 
					
						
							|  |  |  |  |                                               GVariant     *value, | 
					
						
							|  |  |  |  |                                               gpointer      user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GActionGroupExporter *exporter = user_data; | 
					
						
							|  |  |  |  |   guint event_mask; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   event_mask = g_action_group_exporter_get_events (exporter, action_name); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* If it was removed, it must have been added back.  Otherwise, why
 | 
					
						
							|  |  |  |  |    * are we hearing about changes? | 
					
						
							|  |  |  |  |    */ | 
					
						
							|  |  |  |  |   g_assert (~event_mask & ACTION_REMOVED_EVENT || | 
					
						
							|  |  |  |  |             event_mask & ACTION_ADDED_EVENT); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* If it is freshly added, don't also bother with the state change
 | 
					
						
							|  |  |  |  |    * signal since the updated state will be sent as part of the pending | 
					
						
							|  |  |  |  |    * add message. | 
					
						
							|  |  |  |  |    */ | 
					
						
							|  |  |  |  |   if (~event_mask & ACTION_ADDED_EVENT) | 
					
						
							|  |  |  |  |     event_mask |= ACTION_STATE_CHANGED_EVENT; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_action_group_exporter_set_events (exporter, action_name, event_mask); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_action_group_exporter_action_enabled_changed (GActionGroup *action_group, | 
					
						
							|  |  |  |  |                                                 const gchar  *action_name, | 
					
						
							|  |  |  |  |                                                 gboolean      enabled, | 
					
						
							|  |  |  |  |                                                 gpointer      user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GActionGroupExporter *exporter = user_data; | 
					
						
							|  |  |  |  |   guint event_mask; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   event_mask = g_action_group_exporter_get_events (exporter, action_name); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* Reasoning as above. */ | 
					
						
							|  |  |  |  |   g_assert (~event_mask & ACTION_REMOVED_EVENT || | 
					
						
							|  |  |  |  |             event_mask & ACTION_ADDED_EVENT); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (~event_mask & ACTION_ADDED_EVENT) | 
					
						
							|  |  |  |  |     event_mask |= ACTION_ENABLED_CHANGED_EVENT; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_action_group_exporter_set_events (exporter, action_name, event_mask); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | org_gtk_Actions_method_call (GDBusConnection       *connection, | 
					
						
							|  |  |  |  |                              const gchar           *sender, | 
					
						
							|  |  |  |  |                              const gchar           *object_path, | 
					
						
							|  |  |  |  |                              const gchar           *interface_name, | 
					
						
							|  |  |  |  |                              const gchar           *method_name, | 
					
						
							|  |  |  |  |                              GVariant              *parameters, | 
					
						
							|  |  |  |  |                              GDBusMethodInvocation *invocation, | 
					
						
							|  |  |  |  |                              gpointer               user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GActionGroupExporter *exporter = user_data; | 
					
						
							|  |  |  |  |   GVariant *result = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-21 12:32:20 -05:00
										 |  |  |  |   g_action_group_exporter_flush_queue (exporter); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |   if (g_str_equal (method_name, "List")) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       gchar **list; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       list = g_action_group_list_actions (exporter->action_group); | 
					
						
							|  |  |  |  |       result = g_variant_new ("(^as)", list); | 
					
						
							|  |  |  |  |       g_strfreev (list); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   else if (g_str_equal (method_name, "Describe")) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       const gchar *name; | 
					
						
							|  |  |  |  |       GVariant *desc; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       g_variant_get (parameters, "(&s)", &name); | 
					
						
							| 
									
										
										
										
											2013-10-28 14:49:14 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (!g_action_group_has_action (exporter->action_group, name)) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, | 
					
						
							| 
									
										
										
										
											2013-10-28 14:49:14 -07:00
										 |  |  |  |                                                  "The named action ('%s') does not exist.", name); | 
					
						
							| 
									
										
										
										
											2013-10-28 14:49:14 -07:00
										 |  |  |  |           return; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |       desc = g_action_group_describe_action (exporter->action_group, name); | 
					
						
							|  |  |  |  |       result = g_variant_new ("(@(bgav))", desc); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   else if (g_str_equal (method_name, "DescribeAll")) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       GVariantBuilder builder; | 
					
						
							|  |  |  |  |       gchar **list; | 
					
						
							|  |  |  |  |       gint i; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       list = g_action_group_list_actions (exporter->action_group); | 
					
						
							| 
									
										
										
										
											2024-09-25 11:09:07 -07:00
										 |  |  |  |       g_variant_builder_init_static (&builder, G_VARIANT_TYPE ("a{s(bgav)}")); | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |       for (i = 0; list[i]; i++) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           const gchar *name = list[i]; | 
					
						
							|  |  |  |  |           GVariant *description; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           description = g_action_group_describe_action (exporter->action_group, name); | 
					
						
							|  |  |  |  |           g_variant_builder_add (&builder, "{s@(bgav)}", name, description); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |       result = g_variant_new ("(a{s(bgav)})", &builder); | 
					
						
							|  |  |  |  |       g_strfreev (list); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   else if (g_str_equal (method_name, "Activate")) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       GVariant *parameter = NULL; | 
					
						
							|  |  |  |  |       GVariant *platform_data; | 
					
						
							|  |  |  |  |       GVariantIter *iter; | 
					
						
							|  |  |  |  |       const gchar *name; | 
					
						
							| 
									
										
										
										
											2022-11-10 13:28:10 +00:00
										 |  |  |  |       const GVariantType *parameter_type = NULL; | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       g_variant_get (parameters, "(&sav@a{sv})", &name, &iter, &platform_data); | 
					
						
							|  |  |  |  |       g_variant_iter_next (iter, "v", ¶meter); | 
					
						
							|  |  |  |  |       g_variant_iter_free (iter); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 13:28:10 +00:00
										 |  |  |  |       /* Check the action exists and the parameter type matches. */ | 
					
						
							|  |  |  |  |       if (!g_action_group_query_action (exporter->action_group, | 
					
						
							|  |  |  |  |                                         name, NULL, ¶meter_type, | 
					
						
							|  |  |  |  |                                         NULL, NULL, NULL)) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, | 
					
						
							|  |  |  |  |                                                  "Unknown action ‘%s’", name); | 
					
						
							|  |  |  |  |           g_clear_pointer (¶meter, g_variant_unref); | 
					
						
							|  |  |  |  |           g_variant_unref (platform_data); | 
					
						
							|  |  |  |  |           return; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (!((parameter_type == NULL && parameter == NULL) || | 
					
						
							|  |  |  |  |             (parameter_type != NULL && parameter != NULL && g_variant_is_of_type (parameter, parameter_type)))) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, | 
					
						
							|  |  |  |  |                                                  "Invalid parameter for action ‘%s’: expected type %s but got type %s", | 
					
						
							|  |  |  |  |                                                  name, | 
					
						
							|  |  |  |  |                                                  (parameter_type != NULL) ? (const gchar *) parameter_type : "()", | 
					
						
							|  |  |  |  |                                                  (parameter != NULL) ? g_variant_get_type_string (parameter) : "()"); | 
					
						
							|  |  |  |  |           g_clear_pointer (¶meter, g_variant_unref); | 
					
						
							|  |  |  |  |           g_variant_unref (platform_data); | 
					
						
							|  |  |  |  |           return; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-17 00:26:11 -05:00
										 |  |  |  |       if (G_IS_REMOTE_ACTION_GROUP (exporter->action_group)) | 
					
						
							|  |  |  |  |         g_remote_action_group_activate_action_full (G_REMOTE_ACTION_GROUP (exporter->action_group), | 
					
						
							|  |  |  |  |                                                     name, parameter, platform_data); | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         g_action_group_activate_action (exporter->action_group, name, parameter); | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (parameter) | 
					
						
							|  |  |  |  |         g_variant_unref (parameter); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       g_variant_unref (platform_data); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   else if (g_str_equal (method_name, "SetState")) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       GVariant *platform_data; | 
					
						
							|  |  |  |  |       const gchar *name; | 
					
						
							|  |  |  |  |       GVariant *state; | 
					
						
							| 
									
										
										
										
											2022-11-10 13:28:10 +00:00
										 |  |  |  |       const GVariantType *state_type = NULL; | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       g_variant_get (parameters, "(&sv@a{sv})", &name, &state, &platform_data); | 
					
						
							| 
									
										
										
										
											2011-12-17 00:26:11 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 13:28:10 +00:00
										 |  |  |  |       /* Check the action exists and the state type matches. */ | 
					
						
							|  |  |  |  |       if (!g_action_group_query_action (exporter->action_group, | 
					
						
							|  |  |  |  |                                         name, NULL, NULL, | 
					
						
							|  |  |  |  |                                         &state_type, NULL, NULL)) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, | 
					
						
							|  |  |  |  |                                                  "Unknown action ‘%s’", name); | 
					
						
							|  |  |  |  |           g_variant_unref (state); | 
					
						
							|  |  |  |  |           g_variant_unref (platform_data); | 
					
						
							|  |  |  |  |           return; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (state_type == NULL) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, | 
					
						
							|  |  |  |  |                                                  "Cannot change state of action ‘%s’ as it is stateless", name); | 
					
						
							|  |  |  |  |           g_variant_unref (state); | 
					
						
							|  |  |  |  |           g_variant_unref (platform_data); | 
					
						
							|  |  |  |  |           return; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (!g_variant_is_of_type (state, state_type)) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, | 
					
						
							|  |  |  |  |                                                  "Invalid state for action ‘%s’: expected type %s but got type %s", | 
					
						
							|  |  |  |  |                                                  name, | 
					
						
							|  |  |  |  |                                                  (const gchar *) state_type, | 
					
						
							|  |  |  |  |                                                  g_variant_get_type_string (state)); | 
					
						
							|  |  |  |  |           g_variant_unref (state); | 
					
						
							|  |  |  |  |           g_variant_unref (platform_data); | 
					
						
							|  |  |  |  |           return; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-17 00:26:11 -05:00
										 |  |  |  |       if (G_IS_REMOTE_ACTION_GROUP (exporter->action_group)) | 
					
						
							|  |  |  |  |         g_remote_action_group_change_action_state_full (G_REMOTE_ACTION_GROUP (exporter->action_group), | 
					
						
							|  |  |  |  |                                                         name, state, platform_data); | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         g_action_group_change_action_state (exporter->action_group, name, state); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |       g_variant_unref (platform_data); | 
					
						
							|  |  |  |  |       g_variant_unref (state); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     g_assert_not_reached (); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_dbus_method_invocation_return_value (invocation, result); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-02 15:04:53 -05:00
										 |  |  |  | static void | 
					
						
							| 
									
										
										
										
											2024-05-15 14:00:09 +01:00
										 |  |  |  | g_action_group_exporter_free (GActionGroupExporter *exporter) | 
					
						
							| 
									
										
										
										
											2011-12-02 15:04:53 -05:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-12 13:28:09 -05:00
										 |  |  |  |   g_signal_handlers_disconnect_by_func (exporter->action_group, | 
					
						
							|  |  |  |  |                                         g_action_group_exporter_action_added, exporter); | 
					
						
							|  |  |  |  |   g_signal_handlers_disconnect_by_func (exporter->action_group, | 
					
						
							|  |  |  |  |                                         g_action_group_exporter_action_enabled_changed, exporter); | 
					
						
							|  |  |  |  |   g_signal_handlers_disconnect_by_func (exporter->action_group, | 
					
						
							|  |  |  |  |                                         g_action_group_exporter_action_state_changed, exporter); | 
					
						
							|  |  |  |  |   g_signal_handlers_disconnect_by_func (exporter->action_group, | 
					
						
							|  |  |  |  |                                         g_action_group_exporter_action_removed, exporter); | 
					
						
							| 
									
										
										
										
											2011-12-07 14:43:50 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_hash_table_unref (exporter->pending_changes); | 
					
						
							| 
									
										
										
										
											2011-12-07 20:23:41 -05:00
										 |  |  |  |   if (exporter->pending_source) | 
					
						
							|  |  |  |  |     g_source_destroy (exporter->pending_source); | 
					
						
							| 
									
										
										
										
											2011-12-07 14:43:50 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-07 20:39:23 -05:00
										 |  |  |  |   g_main_context_unref (exporter->context); | 
					
						
							| 
									
										
										
										
											2011-12-02 15:04:53 -05:00
										 |  |  |  |   g_object_unref (exporter->connection); | 
					
						
							|  |  |  |  |   g_object_unref (exporter->action_group); | 
					
						
							|  |  |  |  |   g_free (exporter->object_path); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_slice_free (GActionGroupExporter, exporter); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-12-02 16:50:09 -05:00
										 |  |  |  |  * g_dbus_connection_export_action_group: | 
					
						
							| 
									
										
										
										
											2024-05-30 14:57:26 +02:00
										 |  |  |  |  * @connection: the D-Bus connection | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |  * @object_path: a D-Bus object path | 
					
						
							| 
									
										
										
										
											2024-05-30 14:57:26 +02:00
										 |  |  |  |  * @action_group: an action group | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Exports @action_group on @connection at @object_path. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * The implemented D-Bus API should be considered private.  It is | 
					
						
							|  |  |  |  |  * subject to change in the future. | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-12-07 20:39:23 -05:00
										 |  |  |  |  * A given object path can only have one action group exported on it. | 
					
						
							| 
									
										
										
										
											2011-12-02 16:50:09 -05:00
										 |  |  |  |  * If this constraint is violated, the export will fail and 0 will be | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |  * returned (with @error set accordingly). | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-12-02 16:50:09 -05:00
										 |  |  |  |  * You can unexport the action group using | 
					
						
							| 
									
										
										
										
											2024-05-30 14:57:26 +02:00
										 |  |  |  |  * [method@Gio.DBusConnection.unexport_action_group] with the return value of | 
					
						
							| 
									
										
										
										
											2011-12-02 16:50:09 -05:00
										 |  |  |  |  * this function. | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-12-07 20:39:23 -05:00
										 |  |  |  |  * The thread default main context is taken at the time of this call. | 
					
						
							|  |  |  |  |  * All incoming action activations and state change requests are | 
					
						
							|  |  |  |  |  * reported from this context.  Any changes on the action group that | 
					
						
							|  |  |  |  |  * cause it to emit signals must also come from this same context. | 
					
						
							|  |  |  |  |  * Since incoming action activations and state change requests are | 
					
						
							|  |  |  |  |  * rather likely to cause changes on the action group, this effectively | 
					
						
							|  |  |  |  |  * limits a given action group to being exported from only one main | 
					
						
							|  |  |  |  |  * context. | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-12-02 16:50:09 -05:00
										 |  |  |  |  * Returns: the ID of the export (never zero), or 0 in case of failure | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Since: 2.32 | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |  **/ | 
					
						
							| 
									
										
										
										
											2011-12-02 15:04:53 -05:00
										 |  |  |  | guint | 
					
						
							|  |  |  |  | g_dbus_connection_export_action_group (GDBusConnection  *connection, | 
					
						
							|  |  |  |  |                                        const gchar      *object_path, | 
					
						
							|  |  |  |  |                                        GActionGroup     *action_group, | 
					
						
							|  |  |  |  |                                        GError          **error) | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   const GDBusInterfaceVTable vtable = { | 
					
						
							| 
									
										
										
										
											2020-11-17 11:47:20 +01:00
										 |  |  |  |     org_gtk_Actions_method_call, NULL, NULL, { 0 } | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |   }; | 
					
						
							|  |  |  |  |   GActionGroupExporter *exporter; | 
					
						
							| 
									
										
										
										
											2011-12-02 15:04:53 -05:00
										 |  |  |  |   guint id; | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   if G_UNLIKELY (org_gtk_Actions == NULL) | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-01-19 18:28:46 +01:00
										 |  |  |  |       GError *my_error = NULL; | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |       GDBusNodeInfo *info; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 18:28:46 +01:00
										 |  |  |  |       info = g_dbus_node_info_new_for_xml (org_gtk_Actions_xml, &my_error); | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |       if G_UNLIKELY (info == NULL) | 
					
						
							| 
									
										
										
										
											2022-01-19 18:28:46 +01:00
										 |  |  |  |         g_error ("%s", my_error->message); | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |       org_gtk_Actions = g_dbus_node_info_lookup_interface (info, "org.gtk.Actions"); | 
					
						
							|  |  |  |  |       g_assert (org_gtk_Actions != NULL); | 
					
						
							|  |  |  |  |       g_dbus_interface_info_ref (org_gtk_Actions); | 
					
						
							|  |  |  |  |       g_dbus_node_info_unref (info); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   exporter = g_slice_new (GActionGroupExporter); | 
					
						
							| 
									
										
										
										
											2011-12-07 20:39:23 -05:00
										 |  |  |  |   exporter->context = g_main_context_ref_thread_default (); | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |   exporter->pending_changes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); | 
					
						
							| 
									
										
										
										
											2011-12-07 20:23:41 -05:00
										 |  |  |  |   exporter->pending_source = NULL; | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  |   exporter->action_group = g_object_ref (action_group); | 
					
						
							|  |  |  |  |   exporter->connection = g_object_ref (connection); | 
					
						
							|  |  |  |  |   exporter->object_path = g_strdup (object_path); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-15 14:00:09 +01:00
										 |  |  |  |   id = g_dbus_connection_register_object (connection, object_path, org_gtk_Actions, &vtable, | 
					
						
							|  |  |  |  |                                           exporter, (GDestroyNotify) g_action_group_exporter_free, error); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (id != 0) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_signal_connect (action_group, "action-added", | 
					
						
							|  |  |  |  |                         G_CALLBACK (g_action_group_exporter_action_added), exporter); | 
					
						
							|  |  |  |  |       g_signal_connect (action_group, "action-removed", | 
					
						
							|  |  |  |  |                         G_CALLBACK (g_action_group_exporter_action_removed), exporter); | 
					
						
							|  |  |  |  |       g_signal_connect (action_group, "action-state-changed", | 
					
						
							|  |  |  |  |                         G_CALLBACK (g_action_group_exporter_action_state_changed), exporter); | 
					
						
							|  |  |  |  |       g_signal_connect (action_group, "action-enabled-changed", | 
					
						
							|  |  |  |  |                         G_CALLBACK (g_action_group_exporter_action_enabled_changed), exporter); | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-02 15:04:53 -05:00
										 |  |  |  |   return id; | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-02 16:50:09 -05:00
										 |  |  |  | /**
 | 
					
						
							|  |  |  |  |  * g_dbus_connection_unexport_action_group: | 
					
						
							| 
									
										
										
										
											2024-05-30 14:57:26 +02:00
										 |  |  |  |  * @connection: the D-Bus connection | 
					
						
							|  |  |  |  |  * @export_id: the ID from [method@Gio.DBusConnection.export_action_group] | 
					
						
							| 
									
										
										
										
											2011-12-02 16:50:09 -05:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Reverses the effect of a previous call to | 
					
						
							| 
									
										
										
										
											2024-05-30 14:57:26 +02:00
										 |  |  |  |  * [method@Gio.DBusConnection.export_action_group]. | 
					
						
							| 
									
										
										
										
											2011-12-02 16:50:09 -05:00
										 |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2024-05-30 14:57:26 +02:00
										 |  |  |  |  * It is an error to call this function with an ID that wasn’t returned from | 
					
						
							|  |  |  |  |  * [method@Gio.DBusConnection.export_action_group] or to call it with the same | 
					
						
							|  |  |  |  |  * ID more than once. | 
					
						
							| 
									
										
										
										
											2011-12-02 16:50:09 -05:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Since: 2.32 | 
					
						
							|  |  |  |  |  **/ | 
					
						
							|  |  |  |  | void | 
					
						
							| 
									
										
										
										
											2011-12-02 15:04:53 -05:00
										 |  |  |  | g_dbus_connection_unexport_action_group (GDBusConnection *connection, | 
					
						
							|  |  |  |  |                                          guint            export_id) | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-02 16:50:09 -05:00
										 |  |  |  |   g_dbus_connection_unregister_object (connection, export_id); | 
					
						
							| 
									
										
										
										
											2011-06-29 01:02:21 +01:00
										 |  |  |  | } |