1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3 /* ibus - The Input Bus
4 * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
5 * Copyright (C) 2008-2010 Red Hat, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
29 #include "marshalers.h"
30 #include "matchrule.h"
45 static guint dbus_signals[LAST_SIGNAL] = { 0 };
50 /* instance members */
51 /* a map from a unique bus name (e.g. ":1.0") to a BusConnection. */
52 GHashTable *unique_names;
53 /* a map from a requested well-known name (e.g. "org.freedesktop.IBus.Panel") to a BusNameService. */
55 /* a list of IBusService objects. */
57 /* a list of active BusConnections. */
59 /* a list of BusMatchRules requested by the connections above. */
61 /* a serial number used to generate a unique name of a bus. */
64 GMutex *dispatch_lock;
65 GList *dispatch_queue;
70 /* a list of BusMethodCall to be used to reply when services are
72 GList *start_service_calls;
75 struct _BusDBusImplClass {
76 IBusServiceClass parent;
79 void (* name_owner_changed) (BusDBusImpl *dbus,
80 BusConnection *connection,
85 void (* name_lost) (BusDBusImpl *dbus,
86 BusConnection *connection,
89 void (* name_acquired) (BusDBusImpl *dbus,
90 BusConnection *connection,
94 typedef struct _BusDispatchData BusDispatchData;
95 struct _BusDispatchData {
96 GDBusMessage *message;
97 BusConnection *skip_connection;
100 typedef struct _BusNameService BusNameService;
101 struct _BusNameService {
106 typedef struct _BusConnectionOwner BusConnectionOwner;
107 struct _BusConnectionOwner {
110 guint allow_replacement : 1;
111 guint do_not_queue : 1;
114 typedef struct _BusMethodCall BusMethodCall;
115 struct _BusMethodCall {
117 BusConnection *connection;
118 GVariant *parameters;
119 GDBusMethodInvocation *invocation;
123 /* functions prototype */
124 static void bus_dbus_impl_destroy (BusDBusImpl *dbus);
125 static void bus_dbus_impl_service_method_call
126 (IBusService *service,
127 GDBusConnection *dbus_connection,
129 const gchar *object_path,
130 const gchar *interface_name,
131 const gchar *method_name,
132 GVariant *parameters,
133 GDBusMethodInvocation
135 static GVariant *bus_dbus_impl_service_get_property
136 (IBusService *service,
137 GDBusConnection *connection,
139 const gchar *object_path,
140 const gchar *interface_name,
141 const gchar *property_name,
143 static gboolean bus_dbus_impl_service_set_property
144 (IBusService *service,
145 GDBusConnection *connection,
147 const gchar *object_path,
148 const gchar *interface_name,
149 const gchar *property_name,
152 static void bus_dbus_impl_name_owner_changed
154 BusConnection *connection,
158 static void bus_dbus_impl_name_lost
160 BusConnection *connection,
162 static void bus_dbus_impl_name_acquired
164 BusConnection *connection,
166 static void bus_dbus_impl_connection_destroy_cb
167 (BusConnection *connection,
169 static void bus_dbus_impl_rule_destroy_cb (BusMatchRule *rule,
171 static void bus_dbus_impl_object_destroy_cb(IBusService *object,
174 G_DEFINE_TYPE(BusDBusImpl, bus_dbus_impl, IBUS_TYPE_SERVICE)
176 /* The D-Bus interfaces available in this class, which consists of a list of methods this class implements and
177 * a list of signals this class may emit. See bus_dbus_impl_new_connection and ibusservice.c for more details. */
178 static const gchar introspection_xml[] =
180 " <interface name='org.freedesktop.DBus'>"
181 " <method name='Hello'>"
182 " <arg direction='out' type='s' name='unique_name' />"
184 " <method name='RequestName'>"
185 " <arg direction='in' type='s' name='name' />"
186 " <arg direction='in' type='u' name='flags' />"
187 " <arg direction='out' type='u' />"
189 " <method name='ReleaseName'>"
190 " <arg direction='in' type='s' name='name' />"
191 " <arg direction='out' type='u' />"
193 " <method name='StartServiceByName'>"
194 " <arg direction='in' type='s' />"
195 " <arg direction='in' type='u' />"
196 " <arg direction='out' type='u' />"
198 " <method name='UpdateActivationEnvironment'>"
199 " <arg direction='in' type='a{ss}'/>"
201 " <method name='NameHasOwner'>"
202 " <arg direction='in' type='s' name='name' />"
203 " <arg direction='out' type='b' />"
205 " <method name='ListNames'>"
206 " <arg direction='out' type='as' />"
208 " <method name='ListActivatableNames'>"
209 " <arg direction='out' type='as' />"
211 " <method name='AddMatch'>"
212 " <arg direction='in' type='s' name='match_rule' />"
214 " <method name='RemoveMatch'>"
215 " <arg direction='in' type='s' name='match_rule' />"
217 " <method name='GetNameOwner'>"
218 " <arg direction='in' type='s' name='name' />"
219 " <arg direction='out' type='s' name='unique_name' />"
221 " <method name='ListQueuedOwners'>"
222 " <arg direction='in' type='s' name='name' />"
223 " <arg direction='out' type='as' />"
225 " <method name='GetConnectionUnixUser'>"
226 " <arg direction='in' type='s' />"
227 " <arg direction='out' type='u' />"
229 " <method name='GetConnectionUnixProcessID'>"
230 " <arg direction='in' type='s' />"
231 " <arg direction='out' type='u' />"
233 " <method name='GetAdtAuditSessionData'>"
234 " <arg direction='in' type='s' />"
235 " <arg direction='out' type='ay' />"
237 " <method name='GetConnectionSELinuxSecurityContext'>"
238 " <arg direction='in' type='s' />"
239 " <arg direction='out' type='ay' />"
241 " <method name='ReloadConfig' />"
242 " <method name='GetId'>"
243 " <arg direction='out' type='s' />"
245 " <signal name='NameOwnerChanged'>"
246 " <arg type='s' name='name' />"
247 " <arg type='s' name='old_owner' />"
248 " <arg type='s' name='new_owner' />"
250 " <signal name='NameLost'>"
251 " <arg type='s' name='name' />"
253 " <signal name='NameAcquired'>"
254 " <arg type='s' name='name' />"
260 bus_connection_owner_set_flags (BusConnectionOwner *owner,
263 owner->allow_replacement =
264 (flags & IBUS_BUS_NAME_FLAG_ALLOW_REPLACEMENT) != 0;
266 owner->do_not_queue =
267 (flags & IBUS_BUS_NAME_FLAG_DO_NOT_QUEUE) != 0;
270 static BusConnectionOwner *
271 bus_connection_owner_new (BusConnection *connection,
274 BusConnectionOwner *owner = NULL;
276 g_assert (BUS_IS_CONNECTION (connection));
278 owner = g_slice_new (BusConnectionOwner);
280 owner->conn = g_object_ref (connection);
281 bus_connection_owner_set_flags (owner, flags);
288 bus_connection_owner_free (BusConnectionOwner *owner)
290 g_assert (owner != NULL);
292 g_object_unref (owner->conn);
294 g_slice_free (BusConnectionOwner, owner);
298 bus_name_service_find_owner_link (BusNameService *service,
299 BusConnection *connection)
301 GSList *owners = service->owners;
304 BusConnectionOwner *owner = (BusConnectionOwner *) owners->data;
305 if (owner->conn == connection) {
308 owners = owners->next;
314 static BusNameService *
315 bus_name_service_new (const gchar *name)
317 BusNameService *service = NULL;
319 g_assert (name != NULL);
321 service = g_slice_new (BusNameService);
322 g_assert (service != NULL);
324 service->name = g_strdup (name);
325 service->owners = NULL;
331 bus_name_service_free (BusNameService *service)
335 g_assert (service != NULL);
337 g_slist_free_full (service->owners,
338 (GDestroyNotify) bus_connection_owner_free);
339 service->owners = NULL;
341 g_free (service->name);
342 g_slice_free (BusNameService, service);
346 bus_name_service_set_primary_owner (BusNameService *service,
347 BusConnectionOwner *owner,
350 g_assert (service != NULL);
351 g_assert (owner != NULL);
352 g_assert (dbus != NULL);
354 BusConnectionOwner *old = service->owners != NULL ?
355 (BusConnectionOwner *)service->owners->data : NULL;
359 dbus_signals[NAME_LOST],
366 dbus_signals[NAME_ACQUIRED],
369 service->name ? service->name : "");
372 dbus_signals[NAME_OWNER_CHANGED],
376 old != NULL ? bus_connection_get_unique_name (old->conn) : "",
377 bus_connection_get_unique_name (owner->conn));
379 if (old != NULL && old->do_not_queue != 0) {
380 /* If old primary owner does not want to be in queue, we remove it. */
381 service->owners = g_slist_remove (service->owners, old);
382 bus_connection_remove_name (old->conn, service->name);
383 bus_connection_owner_free (old);
386 service->owners = g_slist_prepend (service->owners, (gpointer) owner);
389 static BusConnectionOwner *
390 bus_name_service_get_primary_owner (BusNameService *service)
392 g_assert (service != NULL);
394 if (service->owners == NULL) {
398 return (BusConnectionOwner *) service->owners->data;
402 bus_name_service_add_non_primary_owner (BusNameService *service,
403 BusConnectionOwner *owner,
406 g_assert (service != NULL);
407 g_assert (owner != NULL);
408 g_assert (dbus != NULL);
409 g_assert (service->owners != NULL);
411 service->owners = g_slist_append (service->owners, (gpointer) owner);
414 static BusConnectionOwner *
415 bus_name_service_find_owner (BusNameService *service,
416 BusConnection *connection)
418 g_assert (service != NULL);
419 g_assert (connection != NULL);
421 GSList *owners = bus_name_service_find_owner_link (service, connection);
423 return (BusConnectionOwner *)owners->data;
428 bus_name_service_remove_owner (BusNameService *service,
429 BusConnectionOwner *owner,
434 g_assert (service != NULL);
435 g_assert (owner != NULL);
438 owners = bus_name_service_find_owner_link (service, owner->conn);
439 g_assert (owners != NULL);
441 if (owners->data == bus_name_service_get_primary_owner (service)) {
442 BusConnectionOwner *_new = NULL;
443 if (owners->next != NULL) {
444 _new = (BusConnectionOwner *)owners->next->data;
449 dbus_signals[NAME_LOST],
455 dbus_signals[NAME_ACQUIRED],
461 dbus_signals[NAME_OWNER_CHANGED],
463 _new != NULL ? _new->conn : NULL,
465 bus_connection_get_unique_name (owner->conn),
466 _new != NULL ? bus_connection_get_unique_name (_new->conn) : "");
471 service->owners = g_slist_remove_link (service->owners, (gpointer) owners);
475 bus_name_service_get_allow_replacement (BusNameService *service)
477 BusConnectionOwner *owner = NULL;
479 g_assert (service != NULL);
481 owner = bus_name_service_get_primary_owner (service);
485 return owner->allow_replacement;
488 static BusMethodCall *
489 bus_method_call_new (BusDBusImpl *dbus,
490 BusConnection *connection,
491 GVariant *parameters,
492 GDBusMethodInvocation *invocation)
494 BusMethodCall *call = g_slice_new0 (BusMethodCall);
495 call->dbus = g_object_ref (dbus);
496 call->connection = g_object_ref (connection);
497 call->parameters = g_variant_ref (parameters);
498 call->invocation = g_object_ref (invocation);
503 bus_method_call_free (BusMethodCall *call)
505 if (call->timeout_id != 0) {
506 g_source_remove (call->timeout_id);
509 g_object_unref (call->dbus);
510 g_object_unref (call->connection);
511 g_variant_unref (call->parameters);
512 g_object_unref (call->invocation);
513 g_slice_free (BusMethodCall, call);
517 bus_dbus_impl_class_init (BusDBusImplClass *class)
519 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
521 IBUS_OBJECT_CLASS (gobject_class)->destroy = (IBusObjectDestroyFunc) bus_dbus_impl_destroy;
523 /* override the default implementations in the parent class. */
524 IBUS_SERVICE_CLASS (class)->service_method_call = bus_dbus_impl_service_method_call;
525 IBUS_SERVICE_CLASS (class)->service_get_property = bus_dbus_impl_service_get_property;
526 IBUS_SERVICE_CLASS (class)->service_set_property = bus_dbus_impl_service_set_property;
528 ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
530 /* register a handler of the name-owner-changed signal below. */
531 class->name_owner_changed = bus_dbus_impl_name_owner_changed;
533 /* register a handler of the name-lost signal below. */
534 class->name_lost = bus_dbus_impl_name_lost;
536 /* register a handler of the name-acquired signal below. */
537 class->name_acquired = bus_dbus_impl_name_acquired;
539 /* install signals */
540 dbus_signals[NAME_OWNER_CHANGED] =
541 g_signal_new (I_("name-owner-changed"),
542 G_TYPE_FROM_CLASS (class),
544 G_STRUCT_OFFSET (BusDBusImplClass, name_owner_changed),
546 bus_marshal_VOID__OBJECT_STRING_STRING_STRING,
554 dbus_signals[NAME_LOST] =
555 g_signal_new (I_("name-lost"),
556 G_TYPE_FROM_CLASS (class),
558 G_STRUCT_OFFSET (BusDBusImplClass, name_lost),
560 bus_marshal_VOID__OBJECT_STRING,
566 dbus_signals[NAME_ACQUIRED] =
567 g_signal_new (I_("name-acquired"),
568 G_TYPE_FROM_CLASS (class),
570 G_STRUCT_OFFSET (BusDBusImplClass, name_acquired),
572 bus_marshal_VOID__OBJECT_STRING,
580 bus_dbus_impl_init (BusDBusImpl *dbus)
582 dbus->unique_names = g_hash_table_new (g_str_hash, g_str_equal);
583 dbus->names = g_hash_table_new_full (g_str_hash, g_str_equal,
585 (GDestroyNotify) bus_name_service_free);
587 dbus->dispatch_lock = g_mutex_new ();
588 dbus->forward_lock = g_mutex_new ();
590 /* other members are automatically zero-initialized. */
594 bus_dbus_impl_destroy (BusDBusImpl *dbus)
598 for (p = dbus->objects; p != NULL; p = p->next) {
599 IBusService *object = (IBusService *) p->data;
600 g_signal_handlers_disconnect_by_func (object,
601 G_CALLBACK (bus_dbus_impl_object_destroy_cb), dbus);
602 ibus_object_destroy ((IBusObject *) object);
603 g_object_unref (object);
605 g_list_free (dbus->objects);
606 dbus->objects = NULL;
608 for (p = dbus->rules; p != NULL; p = p->next) {
609 BusMatchRule *rule = BUS_MATCH_RULE (p->data);
610 g_signal_handlers_disconnect_by_func (rule,
611 G_CALLBACK (bus_dbus_impl_rule_destroy_cb), dbus);
612 ibus_object_destroy ((IBusObject *) rule);
613 g_object_unref (rule);
615 g_list_free (dbus->rules);
618 for (p = dbus->connections; p != NULL; p = p->next) {
619 BusConnection *connection = BUS_CONNECTION (p->data);
620 g_signal_handlers_disconnect_by_func (connection,
621 bus_dbus_impl_connection_destroy_cb, dbus);
622 ibus_object_destroy (IBUS_OBJECT (connection));
623 g_object_unref (connection);
625 g_list_free (dbus->connections);
626 dbus->connections = NULL;
628 g_hash_table_remove_all (dbus->unique_names);
629 g_hash_table_remove_all (dbus->names);
631 dbus->unique_names = NULL;
634 g_list_free_full (dbus->start_service_calls,
635 (GDestroyNotify) bus_method_call_free);
636 dbus->start_service_calls = NULL;
638 /* FIXME destruct _lock and _queue members. */
639 IBUS_OBJECT_CLASS(bus_dbus_impl_parent_class)->destroy ((IBusObject *) dbus);
643 * bus_dbus_impl_hello:
645 * Implement the "Hello" method call of the org.freedesktop.DBus interface.
646 * Assign a unique bus name like ":1.0" for the connection and return the name (as a D-Bus reply.)
649 bus_dbus_impl_hello (BusDBusImpl *dbus,
650 BusConnection *connection,
651 GVariant *parameters,
652 GDBusMethodInvocation *invocation)
654 if (bus_connection_get_unique_name (connection) != NULL) {
655 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
656 "Already handled an Hello message");
659 gchar *name = g_strdup_printf (":1.%u", ++dbus->id);
660 bus_connection_set_unique_name (connection, name);
663 name = (gchar *) bus_connection_get_unique_name (connection);
664 g_hash_table_insert (dbus->unique_names, name, connection);
665 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", name));
668 dbus_signals[NAME_OWNER_CHANGED],
678 * bus_dbus_impl_list_names:
680 * Implement the "ListNames" method call of the org.freedesktop.DBus interface.
681 * Return all bus names (e.g. ":1.0", "org.freedesktop.IBus.Panel") as a D-Bus reply.
684 bus_dbus_impl_list_names (BusDBusImpl *dbus,
685 BusConnection *connection,
686 GVariant *parameters,
687 GDBusMethodInvocation *invocation)
689 GVariantBuilder builder;
690 g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
692 /* FIXME should add them? */
693 g_variant_builder_add (&builder, "s", "org.freedesktop.DBus");
694 g_variant_builder_add (&builder, "s", "org.freedesktop.IBus");
696 /* append well-known names */
698 names = g_hash_table_get_keys (dbus->names);
699 for (name = names; name != NULL; name = name->next) {
700 g_variant_builder_add (&builder, "s", name->data);
704 /* append unique names */
705 names = g_hash_table_get_keys (dbus->unique_names);
706 for (name = names; name != NULL; name = name->next) {
707 g_variant_builder_add (&builder, "s", name->data);
711 g_dbus_method_invocation_return_value (invocation,
712 g_variant_new ("(as)", &builder));
716 * bus_dbus_impl_list_names:
718 * Implement the "NameHasOwner" method call of the org.freedesktop.DBus interface.
719 * Return TRUE (as a D-Bus reply) if the name is available in dbus->unique_names or is a well-known name.
722 bus_dbus_impl_name_has_owner (BusDBusImpl *dbus,
723 BusConnection *connection,
724 GVariant *parameters,
725 GDBusMethodInvocation *invocation)
727 const gchar *name = NULL;
728 g_variant_get (parameters, "(&s)", &name);
731 if (!g_dbus_is_name (name)) {
732 g_dbus_method_invocation_return_error (invocation,
735 "'%s' is not a legal bus name");
739 if (g_dbus_is_unique_name (name)) {
740 has_owner = g_hash_table_lookup (dbus->unique_names, name) != NULL;
743 if (g_strcmp0 (name, "org.freedesktop.DBus") == 0 ||
744 g_strcmp0 (name, "org.freedesktop.IBus") == 0)
747 has_owner = g_hash_table_lookup (dbus->names, name) != NULL;
749 g_dbus_method_invocation_return_value (invocation,
750 g_variant_new ("(b)", has_owner));
754 * bus_dbus_impl_get_name_owner:
756 * Implement the "GetNameOwner" method call of the org.freedesktop.DBus interface.
759 bus_dbus_impl_get_name_owner (BusDBusImpl *dbus,
760 BusConnection *connection,
761 GVariant *parameters,
762 GDBusMethodInvocation *invocation)
764 const gchar *name_owner = NULL;
765 const gchar *name = NULL;
766 g_variant_get (parameters, "(&s)", &name);
768 if (g_strcmp0 (name, "org.freedesktop.DBus") == 0 ||
769 g_strcmp0 (name, "org.freedesktop.IBus") == 0) {
773 BusConnection *owner = bus_dbus_impl_get_connection_by_name (dbus, name);
775 name_owner = bus_connection_get_unique_name (owner);
779 if (name_owner == NULL) {
780 g_dbus_method_invocation_return_error (invocation,
781 G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
782 "Can not get name owner of '%s': no such name", name);
785 g_dbus_method_invocation_return_value (invocation,
786 g_variant_new ("(s)", name_owner));
791 * bus_dbus_impl_list_queued_owners:
793 * Implement the "ListQueuedOwners" method call of the org.freedesktop.DBus interface.
796 bus_dbus_impl_list_queued_owners (BusDBusImpl *dbus,
797 BusConnection *connection,
798 GVariant *parameters,
799 GDBusMethodInvocation *invocation)
801 const gchar *name = NULL;
802 const gchar *name_owner = NULL;
803 GVariantBuilder builder;
804 BusConnection *named_conn = NULL;
806 g_variant_get (parameters, "(&s)", &name);
808 g_assert (BUS_IS_DBUS_IMPL (dbus));
809 g_assert (name != NULL);
811 g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
813 if (G_LIKELY (g_dbus_is_unique_name (name))) {
814 named_conn = (BusConnection *) g_hash_table_lookup (dbus->unique_names, name);
815 if (named_conn == NULL) {
816 g_dbus_method_invocation_return_value (invocation,
817 g_variant_new ("(as)", &builder));
820 name_owner = bus_connection_get_unique_name (named_conn);
821 if (name_owner == NULL) {
822 g_dbus_method_invocation_return_error (invocation,
823 G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
824 "Can not get name owner of '%s': no such name", name);
827 g_variant_builder_add (&builder, "s", name_owner);
830 BusNameService *service;
833 service = (BusNameService *) g_hash_table_lookup (dbus->names, name);
834 if (service == NULL) {
835 g_dbus_method_invocation_return_value (invocation,
836 g_variant_new ("(as)", &builder));
839 for (owners = service->owners; owners; owners = owners->next) {
840 BusConnectionOwner *owner = (BusConnectionOwner *) owners->data;
844 named_conn = owner->conn;
845 if (named_conn == NULL) {
848 name_owner = bus_connection_get_unique_name (named_conn);
849 if (name_owner == NULL) {
850 g_dbus_method_invocation_return_error (invocation,
851 G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
852 "Can not get name owner of '%s': no such name", name);
855 g_variant_builder_add (&builder, "s", name_owner);
859 g_dbus_method_invocation_return_value (invocation,
860 g_variant_new ("(as)", &builder));
864 * bus_dbus_impl_get_id:
866 * Implement the "GetId" method call of the org.freedesktop.DBus interface.
867 * This function is not implemented yet and always returns a dummy string - "FIXME".
870 bus_dbus_impl_get_id (BusDBusImpl *dbus,
871 BusConnection *connection,
872 GVariant *parameters,
873 GDBusMethodInvocation *invocation)
876 const gchar *uuid = "FIXME";
877 g_dbus_method_invocation_return_value (invocation,
878 g_variant_new ("(s)", uuid));
882 * bus_dbus_impl_rule_destroy_cb:
884 * A function to be called when one of the dbus->rules is destroyed.
887 bus_dbus_impl_rule_destroy_cb (BusMatchRule *rule,
890 dbus->rules = g_list_remove (dbus->rules, rule);
891 g_object_unref (rule);
895 * bus_dbus_impl_get_id:
897 * Implement the "AddMatch" method call of the org.freedesktop.DBus interface.
900 bus_dbus_impl_add_match (BusDBusImpl *dbus,
901 BusConnection *connection,
902 GVariant *parameters,
903 GDBusMethodInvocation *invocation)
905 const gchar *rule_text = NULL;
906 g_variant_get (parameters, "(&s)", &rule_text);
908 BusMatchRule *rule = bus_match_rule_new (rule_text);
910 g_dbus_method_invocation_return_error (invocation,
911 G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_INVALID,
912 "Parse match rule [%s] failed", rule_text);
916 g_dbus_method_invocation_return_value (invocation, NULL);
918 for (p = dbus->rules; p != NULL; p = p->next) {
919 if (bus_match_rule_is_equal (rule, (BusMatchRule *) p->data)) {
920 /* The same rule is already registered. Just reuse it. */
921 bus_match_rule_add_recipient ((BusMatchRule *) p->data, connection);
922 g_object_unref (rule);
928 bus_match_rule_add_recipient (rule, connection);
929 dbus->rules = g_list_append (dbus->rules, rule);
930 g_signal_connect (rule, "destroy", G_CALLBACK (bus_dbus_impl_rule_destroy_cb), dbus);
935 * bus_dbus_impl_get_id:
937 * Implement the "RemoveMatch" method call of the org.freedesktop.DBus interface.
940 bus_dbus_impl_remove_match (BusDBusImpl *dbus,
941 BusConnection *connection,
942 GVariant *parameters,
943 GDBusMethodInvocation *invocation)
945 const gchar *rule_text = NULL;
946 g_variant_get (parameters, "(&s)", &rule_text);
948 BusMatchRule *rule = bus_match_rule_new (rule_text);
950 g_dbus_method_invocation_return_error (invocation,
951 G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_INVALID,
952 "Parse match rule [%s] failed", rule_text);
956 g_dbus_method_invocation_return_value (invocation, NULL);
958 for (p = dbus->rules; p != NULL; p = p->next) {
959 if (bus_match_rule_is_equal (rule, (BusMatchRule *) p->data)) {
960 /* p->data will be destroyed when the final recipient is removed. */
961 bus_match_rule_remove_recipient ((BusMatchRule *) p->data, connection);
964 /* FIXME should we return G_DBUS_ERROR if rule is not found in dbus->rules */
966 g_object_unref (rule);
970 * bus_dbus_impl_request_name:
972 * Implement the "RequestName" method call of the org.freedesktop.DBus interface.
975 bus_dbus_impl_request_name (BusDBusImpl *dbus,
976 BusConnection *connection,
977 GVariant *parameters,
978 GDBusMethodInvocation *invocation)
980 const gchar *name = NULL; // e.g. "org.freedesktop.IBus.Panel"
982 BusNameService *service = NULL;
983 BusConnectionOwner *primary_owner = NULL;
984 BusConnectionOwner *owner = NULL;
986 g_variant_get (parameters, "(&su)", &name, &flags);
989 !g_dbus_is_name (name) ||
990 g_dbus_is_unique_name (name)) {
991 g_dbus_method_invocation_return_error (invocation,
992 G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
993 "'%s' is not a legal service name.", name);
997 if (g_strcmp0 (name, "org.freedesktop.DBus") == 0 ||
998 g_strcmp0 (name, "org.freedesktop.IBus") == 0) {
999 g_dbus_method_invocation_return_error (invocation,
1000 G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1001 "Can not acquire the service name '%s', it is reserved by IBus", name);
1011 } action = ACTION_INVALID;
1013 service = (BusNameService *) g_hash_table_lookup (dbus->names, name);
1015 /* If the name servise does not exist, we will create one. */
1016 if (service == NULL) {
1017 service = bus_name_service_new (name);
1018 g_hash_table_insert (dbus->names,
1023 primary_owner = bus_name_service_get_primary_owner (service);
1026 if (primary_owner != NULL) {
1027 if (primary_owner->conn == connection) {
1028 action = ACTION_ALREADY_OWN;
1031 action = (flags & IBUS_BUS_NAME_FLAG_DO_NOT_QUEUE) ?
1032 ACTION_EXISTS : ACTION_IN_QUEUE;
1033 if ((bus_name_service_get_allow_replacement (service) == TRUE) &&
1034 (flags & IBUS_BUS_NAME_FLAG_REPLACE_EXISTING)) {
1035 action = ACTION_REPLACE;
1040 action = ACTION_REPLACE;
1043 if (action == ACTION_ALREADY_OWN) {
1044 g_dbus_method_invocation_return_value (invocation,
1045 g_variant_new ("(u)", IBUS_BUS_REQUEST_NAME_REPLY_ALREADY_OWNER));
1049 owner = bus_name_service_find_owner (service, connection);
1050 /* If connection already in queue, we need remove it at first. */
1051 if (owner != NULL) {
1052 bus_connection_remove_name (connection, name);
1053 bus_name_service_remove_owner (service, owner, NULL);
1054 bus_connection_owner_free (owner);
1059 g_dbus_method_invocation_return_value (invocation,
1060 g_variant_new ("(u)", IBUS_BUS_REQUEST_NAME_REPLY_EXISTS));
1063 case ACTION_IN_QUEUE:
1064 owner = bus_connection_owner_new (connection, flags);
1065 g_dbus_method_invocation_return_value (invocation,
1066 g_variant_new ("(u)", IBUS_BUS_REQUEST_NAME_REPLY_IN_QUEUE));
1067 bus_name_service_add_non_primary_owner (service, owner, dbus);
1070 case ACTION_REPLACE:
1071 bus_connection_add_name (connection, name);
1072 owner = bus_connection_owner_new (connection, flags);
1073 g_dbus_method_invocation_return_value (invocation,
1074 g_variant_new ("(u)", IBUS_BUS_REQUEST_NAME_REPLY_PRIMARY_OWNER));
1075 bus_name_service_set_primary_owner (service, owner, dbus);
1079 g_assert_not_reached ();
1084 * bus_dbus_impl_release_name:
1086 * Implement the "ReleaseName" method call of the org.freedesktop.DBus interface.
1089 bus_dbus_impl_release_name (BusDBusImpl *dbus,
1090 BusConnection *connection,
1091 GVariant *parameters,
1092 GDBusMethodInvocation *invocation)
1094 const gchar *name= NULL;
1095 g_variant_get (parameters, "(&s)", &name);
1098 !g_dbus_is_name (name) ||
1099 g_dbus_is_unique_name (name)) {
1100 g_dbus_method_invocation_return_error (invocation,
1101 G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1102 "'%s' is not a legal service name.", name);
1106 if (g_strcmp0 (name, "org.freedesktop.DBus") == 0 ||
1107 g_strcmp0 (name, "org.freedesktop.IBus") == 0) {
1108 g_dbus_method_invocation_return_error (invocation,
1109 G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1110 "Service name '%s' is owned by IBus.", name);
1115 if (g_hash_table_lookup (dbus->names, name) == NULL) {
1116 retval = 2; /* DBUS_RELEASE_NAME_REPLY_NON_EXISTENT */
1119 if (bus_connection_remove_name (connection, name)) {
1120 retval = 1; /* DBUS_RELEASE_NAME_REPLY_RELEASED */
1123 retval = 3; /* DBUS_RELEASE_NAME_REPLY_NOT_OWNER */
1126 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", retval));
1130 start_service_timeout_cb (BusMethodCall *call)
1132 const gchar *name= NULL;
1133 guint32 flags; /* currently not used in the D-Bus spec */
1134 g_variant_get (call->parameters, "(&su)", &name, &flags);
1136 g_dbus_method_invocation_return_error (call->invocation,
1137 G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1138 "Timeout reached before starting %s", name);
1140 GList *p = g_list_find (call->dbus->start_service_calls, call);
1141 g_return_val_if_fail (p != NULL, FALSE);
1143 bus_method_call_free ((BusMethodCall *) p->data);
1144 call->dbus->start_service_calls =
1145 g_list_delete_link (call->dbus->start_service_calls, p);
1151 * bus_dbus_impl_start_service_by_name:
1153 * Implement the "StartServiceByName" method call of the
1154 * org.freedesktop.DBus interface.
1157 bus_dbus_impl_start_service_by_name (BusDBusImpl *dbus,
1158 BusConnection *connection,
1159 GVariant *parameters,
1160 GDBusMethodInvocation *invocation)
1162 const gchar *name= NULL;
1163 guint32 flags; /* currently not used in the D-Bus spec */
1164 g_variant_get (parameters, "(&su)", &name, &flags);
1167 !g_dbus_is_name (name) ||
1168 g_dbus_is_unique_name (name)) {
1169 g_dbus_method_invocation_return_error (invocation,
1170 G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1171 "'%s' is not a legal service name.", name);
1175 if (g_strcmp0 (name, "org.freedesktop.DBus") == 0 ||
1176 g_strcmp0 (name, "org.freedesktop.IBus") == 0) {
1177 g_dbus_method_invocation_return_error (invocation,
1178 G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
1179 "Service name '%s' is owned by IBus.", name);
1183 if (g_hash_table_lookup (dbus->names, name) != NULL) {
1184 g_dbus_method_invocation_return_value (invocation,
1185 g_variant_new ("(u)",
1186 IBUS_BUS_START_REPLY_ALREADY_RUNNING));
1190 BusRegistry *registry = BUS_DEFAULT_REGISTRY;
1191 BusComponent *component = bus_registry_lookup_component_by_name (registry,
1194 if (component == NULL || !bus_component_start (component, g_verbose)) {
1195 g_dbus_method_invocation_return_error (invocation,
1196 G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
1197 "Failed to start %s", name);
1201 BusMethodCall *call = bus_method_call_new (dbus,
1205 call->timeout_id = g_timeout_add (g_gdbus_timeout,
1206 (GSourceFunc) start_service_timeout_cb,
1208 dbus->start_service_calls = g_list_prepend (dbus->start_service_calls,
1213 * bus_dbus_impl_name_owner_changed:
1215 * The function is called on name-owner-changed signal, typically when g_signal_emit (dbus, NAME_OWNER_CHANGED)
1216 * is called, and broadcasts the signal to clients.
1219 bus_dbus_impl_name_owner_changed (BusDBusImpl *dbus,
1220 BusConnection *connection,
1225 g_assert (BUS_IS_DBUS_IMPL (dbus));
1226 g_assert (name != NULL);
1227 g_assert (old_owner != NULL);
1228 g_assert (new_owner != NULL);
1230 GDBusMessage *message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
1231 "org.freedesktop.DBus",
1232 "NameOwnerChanged");
1233 g_dbus_message_set_sender (message, "org.freedesktop.DBus");
1235 /* set a non-zero serial to make libdbus happy */
1236 g_dbus_message_set_serial (message, 1);
1237 g_dbus_message_set_body (message,
1238 g_variant_new ("(sss)", name, old_owner, new_owner));
1240 /* broadcast the message to clients that listen to the signal. */
1241 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1242 g_object_unref (message);
1246 * bus_dbus_impl_name_lost:
1248 * The function is called on name-lost signal, typically when g_signal_emit (dbus, NAME_LOST)
1249 * is called, and broadcasts the signal to clients.
1252 bus_dbus_impl_name_lost (BusDBusImpl *dbus,
1253 BusConnection *connection,
1256 g_assert (BUS_IS_DBUS_IMPL (dbus));
1257 g_assert (name != NULL);
1259 GDBusMessage *message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
1260 "org.freedesktop.DBus",
1262 g_dbus_message_set_sender (message, "org.freedesktop.DBus");
1263 g_dbus_message_set_destination (message, bus_connection_get_unique_name (connection));
1265 /* set a non-zero serial to make libdbus happy */
1266 g_dbus_message_set_serial (message, 1);
1267 g_dbus_message_set_body (message,
1268 g_variant_new ("(s)", name));
1270 bus_dbus_impl_forward_message (dbus, connection, message);
1271 g_object_unref (message);
1275 * bus_dbus_impl_name_acquired:
1277 * The function is called on name-acquired signal, typically when g_signal_emit (dbus, NAME_ACQUIRED)
1278 * is called, and broadcasts the signal to clients.
1281 bus_dbus_impl_name_acquired (BusDBusImpl *dbus,
1282 BusConnection *connection,
1285 g_assert (BUS_IS_DBUS_IMPL (dbus));
1286 g_assert (name != NULL);
1288 GDBusMessage *message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
1289 "org.freedesktop.DBus",
1291 g_dbus_message_set_sender (message, "org.freedesktop.DBus");
1292 g_dbus_message_set_destination (message, bus_connection_get_unique_name (connection));
1294 /* set a non-zero serial to make libdbus happy */
1295 g_dbus_message_set_serial (message, 1);
1296 g_dbus_message_set_body (message,
1297 g_variant_new ("(s)", name));
1299 bus_dbus_impl_forward_message (dbus, connection, message);
1300 g_object_unref (message);
1302 GList *p = dbus->start_service_calls;
1304 BusMethodCall *call = p->data;
1305 const gchar *_name= NULL;
1307 GList *next = p->next;
1309 g_variant_get (call->parameters, "(&su)", &_name, &flags);
1310 if (g_strcmp0 (name, _name) == 0) {
1311 g_dbus_method_invocation_return_value (call->invocation,
1312 g_variant_new ("(u)",
1313 IBUS_BUS_START_REPLY_SUCCESS));
1314 bus_method_call_free ((BusMethodCall *) p->data);
1316 dbus->start_service_calls =
1317 g_list_delete_link (dbus->start_service_calls, p);
1324 * bus_dbus_impl_service_method_call:
1326 * Handle a D-Bus method call from a client. This function overrides an implementation in src/ibusservice.c.
1329 bus_dbus_impl_service_method_call (IBusService *service,
1330 GDBusConnection *dbus_connection,
1331 const gchar *sender,
1332 const gchar *object_path,
1333 const gchar *interface_name,
1334 const gchar *method_name,
1335 GVariant *parameters,
1336 GDBusMethodInvocation *invocation)
1338 BusDBusImpl *dbus = BUS_DBUS_IMPL (service);
1340 if (g_strcmp0 (interface_name, "org.freedesktop.DBus") != 0) {
1341 IBUS_SERVICE_CLASS (bus_dbus_impl_parent_class)->service_method_call (
1342 (IBusService *) dbus,
1353 static const struct {
1354 const gchar *method_name;
1355 void (* method) (BusDBusImpl *, BusConnection *, GVariant *, GDBusMethodInvocation *);
1357 /* DBus interface */
1358 { "Hello", bus_dbus_impl_hello },
1359 { "ListNames", bus_dbus_impl_list_names },
1360 { "NameHasOwner", bus_dbus_impl_name_has_owner },
1361 { "GetNameOwner", bus_dbus_impl_get_name_owner },
1362 { "ListQueuedOwners", bus_dbus_impl_list_queued_owners },
1363 { "GetId", bus_dbus_impl_get_id },
1364 { "AddMatch", bus_dbus_impl_add_match },
1365 { "RemoveMatch", bus_dbus_impl_remove_match },
1366 { "RequestName", bus_dbus_impl_request_name },
1367 { "ReleaseName", bus_dbus_impl_release_name },
1368 { "StartServiceByName", bus_dbus_impl_start_service_by_name },
1372 for (i = 0; i < G_N_ELEMENTS (methods); i++) {
1373 if (g_strcmp0 (method_name, methods[i].method_name) == 0) {
1374 BusConnection *connection = bus_connection_lookup (dbus_connection);
1375 g_assert (BUS_IS_CONNECTION (connection));
1376 methods[i].method (dbus, connection, parameters, invocation);
1381 /* unsupported methods */
1382 g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD,
1383 "org.freedesktop.DBus does not support %s", method_name);
1387 * bus_dbus_impl_service_get_property:
1389 * Handle a D-Bus method call from a client. This function overrides an implementation in src/ibusservice.c.
1392 bus_dbus_impl_service_get_property (IBusService *service,
1393 GDBusConnection *connection,
1394 const gchar *sender,
1395 const gchar *object_path,
1396 const gchar *interface_name,
1397 const gchar *property_name,
1400 /* FIXME implement the function. */
1401 return IBUS_SERVICE_CLASS (bus_dbus_impl_parent_class)->
1402 service_get_property (service,
1412 * bus_dbus_impl_service_set_property:
1414 * Handle a D-Bus method call from a client. This function overrides an implementation in src/ibusservice.c.
1417 bus_dbus_impl_service_set_property (IBusService *service,
1418 GDBusConnection *connection,
1419 const gchar *sender,
1420 const gchar *object_path,
1421 const gchar *interface_name,
1422 const gchar *property_name,
1426 /* FIXME implement the function. */
1427 return IBUS_SERVICE_CLASS (bus_dbus_impl_parent_class)->
1428 service_set_property (service,
1440 * bus_dbus_impl_connection_filter_cb:
1441 * @returns: A GDBusMessage that will be processed by bus_dbus_impl_service_method_call. NULL when dropping the message.
1443 * A filter function that is called for all incoming and outgoing messages.
1444 * WARNING - this function could be called by the GDBus's worker thread. So you should not call thread unsafe IBus functions.
1446 static GDBusMessage *
1447 bus_dbus_impl_connection_filter_cb (GDBusConnection *dbus_connection,
1448 GDBusMessage *message,
1452 g_assert (G_IS_DBUS_CONNECTION (dbus_connection));
1453 g_assert (G_IS_DBUS_MESSAGE (message));
1454 g_assert (BUS_IS_DBUS_IMPL (user_data));
1456 BusDBusImpl *dbus = (BusDBusImpl *) user_data;
1457 BusConnection *connection = bus_connection_lookup (dbus_connection);
1458 g_assert (connection != NULL);
1461 /* is incoming message */
1463 /* get the destination aka bus name of the message. the destination is set by g_dbus_connection_call_sync (for DBus and IBus messages
1464 * in the IBusBus class) or g_initable_new (for config and context messages in the IBusProxy sub classes.) */
1465 const gchar *destination = g_dbus_message_get_destination (message);
1466 GDBusMessageType message_type = g_dbus_message_get_message_type (message);
1468 if (g_dbus_message_get_locked (message)) {
1469 /* If the message is locked, we need make a copy of it. */
1470 GDBusMessage *new_message = g_dbus_message_copy (message, NULL);
1471 g_assert (new_message != NULL);
1472 g_object_unref (message);
1473 message = new_message;
1476 /* connection unique name as sender of the message*/
1477 g_dbus_message_set_sender (message, bus_connection_get_unique_name (connection));
1479 if (g_strcmp0 (destination, "org.freedesktop.IBus") == 0) {
1480 /* the message is sent to IBus service. messages from ibusbus and ibuscontext may fall into this category. */
1481 switch (message_type) {
1482 case G_DBUS_MESSAGE_TYPE_METHOD_CALL:
1483 case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
1484 case G_DBUS_MESSAGE_TYPE_ERROR:
1485 /* dispatch messages by match rule */
1486 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1488 case G_DBUS_MESSAGE_TYPE_SIGNAL:
1489 /* notreached - signals should not be sent to IBus service. dispatch signal messages by match rule, just in case. */
1490 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1491 g_object_unref (message);
1492 g_return_val_if_reached (NULL); /* return NULL since the service does not handle signals. */
1494 g_object_unref (message);
1495 g_return_val_if_reached (NULL); /* return NULL since the service does not handle signals. */
1498 else if (g_strcmp0 (destination, "org.freedesktop.DBus") == 0) {
1499 /* the message is sent to DBus service. messages from ibusbus may fall into this category. */
1500 switch (message_type) {
1501 case G_DBUS_MESSAGE_TYPE_METHOD_CALL:
1502 case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
1503 case G_DBUS_MESSAGE_TYPE_ERROR:
1504 /* dispatch messages by match rule */
1505 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1507 case G_DBUS_MESSAGE_TYPE_SIGNAL:
1508 /* notreached - signals should not be sent to IBus service. dispatch signal messages by match rule, just in case. */
1509 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1510 g_object_unref (message);
1511 g_return_val_if_reached (NULL); /* return NULL since the service does not handle signals. */
1513 g_object_unref (message);
1514 g_return_val_if_reached (NULL); /* return NULL since the service does not handle signals. */
1517 else if (destination == NULL) {
1518 /* the message is sent to the current connection. communications between ibus-daemon and panel/engines may fall into this
1519 * category since the panel/engine proxies created by ibus-daemon does not set bus name. */
1520 switch (message_type) {
1521 case G_DBUS_MESSAGE_TYPE_SIGNAL:
1522 case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
1523 case G_DBUS_MESSAGE_TYPE_ERROR:
1524 /* dispatch messages by match rule */
1525 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1527 case G_DBUS_MESSAGE_TYPE_METHOD_CALL:
1528 g_warning ("Unknown method call: destination=NULL, path='%s', interface='%s', member='%s'",
1529 g_dbus_message_get_path (message),
1530 g_dbus_message_get_interface (message),
1531 g_dbus_message_get_member (message));
1532 bus_dbus_impl_dispatch_message_by_rule (dbus, message, NULL);
1533 return message; /* return the message, GDBus library will handle it */
1536 g_object_unref (message);
1537 g_return_val_if_reached (NULL); /* return NULL since the service does not handle messages. */
1541 /* The message is sent to an other service. Forward it.
1542 * For example, the config proxy class in src/ibusconfig.c sets its "g-name" property (i.e. destination) to IBUS_SERVICE_CONFIG. */
1543 bus_dbus_impl_forward_message (dbus, connection, message);
1544 g_object_unref (message);
1549 /* is outgoing message */
1550 if (g_dbus_message_get_sender (message) == NULL) {
1551 if (g_dbus_message_get_locked (message)) {
1552 GDBusMessage *new_message = g_dbus_message_copy (message, NULL);
1553 g_assert (new_message != NULL);
1554 g_object_unref (message);
1555 message = new_message;
1557 /* If the message is sending from ibus-daemon directly,
1558 * we set the sender to org.freedesktop.DBus */
1559 g_dbus_message_set_sender (message, "org.freedesktop.DBus");
1562 /* dispatch the outgoing message by rules. */
1563 bus_dbus_impl_dispatch_message_by_rule (dbus, message, connection);
1569 bus_dbus_impl_get_default (void)
1571 static BusDBusImpl *dbus = NULL;
1574 dbus = (BusDBusImpl *) g_object_new (BUS_TYPE_DBUS_IMPL,
1575 "object-path", "/org/freedesktop/DBus",
1583 bus_dbus_impl_connection_destroy_cb (BusConnection *connection,
1586 const gchar *unique_name = bus_connection_get_unique_name (connection);
1587 const GList *names = NULL;
1588 BusNameService *service = NULL;
1590 if (unique_name != NULL) {
1591 GList *p = dbus->start_service_calls;
1593 BusMethodCall *call = p->data;
1594 GList *next = p->next;
1596 if (call->connection == connection) {
1597 bus_method_call_free ((BusMethodCall *) p->data);
1598 dbus->start_service_calls =
1599 g_list_delete_link (dbus->start_service_calls, p);
1604 g_hash_table_remove (dbus->unique_names, unique_name);
1605 g_signal_emit (dbus,
1606 dbus_signals[NAME_OWNER_CHANGED],
1614 /* service->owners is the queue of connections.
1615 * If the connection is the primary owner and
1616 * bus_name_service_remove_owner() is called, the owner is removed
1617 * in the queue and the next owner will become the primary owner
1618 * automatically because service->owners is just a GSList.
1619 * If service->owners == NULL, it's good to remove the service in
1621 * I suppose dbus->names are the global queue for every connection
1622 * and connection->names are the private queue of the connection.
1624 names = bus_connection_get_names (connection);
1625 while (names != NULL) {
1626 const gchar *name = (const gchar *)names->data;
1627 service = (BusNameService *) g_hash_table_lookup (dbus->names,
1629 g_assert (service != NULL);
1630 BusConnectionOwner *owner = bus_name_service_find_owner (service,
1632 g_assert (owner != NULL);
1633 bus_name_service_remove_owner (service, owner, dbus);
1634 if (service->owners == NULL) {
1635 g_hash_table_remove (dbus->names, service->name);
1637 bus_connection_owner_free (owner);
1638 names = names->next;
1641 dbus->connections = g_list_remove (dbus->connections, connection);
1642 g_object_unref (connection);
1647 bus_dbus_impl_new_connection (BusDBusImpl *dbus,
1648 BusConnection *connection)
1650 g_assert (BUS_IS_DBUS_IMPL (dbus));
1651 g_assert (BUS_IS_CONNECTION (connection));
1652 g_assert (g_list_find (dbus->connections, connection) == NULL);
1654 g_object_ref_sink (connection);
1655 dbus->connections = g_list_append (dbus->connections, connection);
1657 bus_connection_set_filter (connection,
1658 bus_dbus_impl_connection_filter_cb, g_object_ref (dbus), g_object_unref);
1660 g_signal_connect (connection,
1662 G_CALLBACK (bus_dbus_impl_connection_destroy_cb),
1665 /* add introspection_xml[] (see above) to the connection. */
1666 ibus_service_register ((IBusService *) dbus,
1667 bus_connection_get_dbus_connection (connection), NULL);
1669 for (p = dbus->objects; p != NULL; p = p->next) {
1670 /* add all introspection xmls in dbus->objects to the connection. */
1671 ibus_service_register ((IBusService *) p->data,
1672 bus_connection_get_dbus_connection (connection), NULL);
1678 bus_dbus_impl_get_connection_by_name (BusDBusImpl *dbus,
1681 g_assert (BUS_IS_DBUS_IMPL (dbus));
1682 g_assert (name != NULL);
1684 if (G_LIKELY (g_dbus_is_unique_name (name))) {
1685 return (BusConnection *) g_hash_table_lookup (dbus->unique_names, name);
1688 BusNameService *service;
1689 BusConnectionOwner *owner;
1691 service = (BusNameService *) g_hash_table_lookup (dbus->names, name);
1692 if (service == NULL) {
1695 owner = bus_name_service_get_primary_owner (service);
1696 return owner ? owner->conn : NULL;
1700 typedef struct _BusForwardData BusForwardData;
1701 struct _BusForwardData {
1702 GDBusMessage *message;
1703 BusConnection *sender_connection;
1707 * bus_dbus_impl_forward_message_ible_cb:
1709 * Process the first element of the dbus->forward_queue. The first element is forwarded by g_dbus_connection_send_message.
1712 bus_dbus_impl_forward_message_idle_cb (BusDBusImpl *dbus)
1714 g_return_val_if_fail (dbus->forward_queue != NULL, FALSE);
1716 g_mutex_lock (dbus->forward_lock);
1717 BusForwardData *data = (BusForwardData *) dbus->forward_queue->data;
1718 dbus->forward_queue = g_list_delete_link (dbus->forward_queue, dbus->forward_queue);
1719 gboolean has_message = (dbus->forward_queue != NULL);
1720 g_mutex_unlock (dbus->forward_lock);
1723 const gchar *destination = g_dbus_message_get_destination (data->message);
1724 BusConnection *dest_connection = NULL;
1725 if (destination != NULL)
1726 dest_connection = bus_dbus_impl_get_connection_by_name (dbus, destination);
1727 if (dest_connection != NULL) {
1728 /* FIXME workaround for gdbus. gdbus can not set an empty body message with signature '()' */
1729 if (g_dbus_message_get_body (data->message) == NULL)
1730 g_dbus_message_set_signature (data->message, NULL);
1731 GError *error = NULL;
1732 gboolean retval = g_dbus_connection_send_message (
1733 bus_connection_get_dbus_connection (dest_connection),
1735 G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL,
1739 g_warning ("forward message failed: %s.", error->message);
1740 g_error_free (error);
1742 /* can not forward message */
1743 if (g_dbus_message_get_message_type (data->message) != G_DBUS_MESSAGE_TYPE_METHOD_CALL) {
1744 /* skip non method messages */
1748 /* reply an error message, if forward method call message failed. */
1749 GDBusMessage *reply_message = g_dbus_message_new_method_error (data->message,
1750 "org.freedesktop.DBus.Error.ServiceUnknown ",
1751 "The service name is '%s'.", destination);
1752 g_dbus_message_set_sender (reply_message, "org.freedesktop.DBus");
1753 g_dbus_message_set_destination (reply_message, bus_connection_get_unique_name (data->sender_connection));
1754 g_dbus_connection_send_message (bus_connection_get_dbus_connection (data->sender_connection),
1756 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
1758 g_object_unref (reply_message);
1761 g_object_unref (data->message);
1762 g_object_unref (data->sender_connection);
1763 g_slice_free (BusForwardData, data);
1768 bus_dbus_impl_forward_message (BusDBusImpl *dbus,
1769 BusConnection *connection,
1770 GDBusMessage *message)
1772 /* WARNING - this function could be called by the GDBus's worker thread. So you should not call thread unsafe IBus functions. */
1773 g_assert (BUS_IS_DBUS_IMPL (dbus));
1774 g_assert (BUS_IS_CONNECTION (connection));
1775 g_assert (G_IS_DBUS_MESSAGE (message));
1777 if (G_UNLIKELY (IBUS_OBJECT_DESTROYED (dbus)))
1779 /* FIXME the check above might not be sufficient. dbus object could be destroyed in the main thread right after the check, though the
1780 * dbus structure itself would not be freed (since the dbus object is ref'ed in bus_dbus_impl_new_connection.)
1781 * Anyway, it'd be better to investigate whether the thread safety issue could cause any real problems. */
1783 BusForwardData *data = g_slice_new (BusForwardData);
1784 data->message = g_object_ref (message);
1785 data->sender_connection = g_object_ref (connection);
1787 g_mutex_lock (dbus->forward_lock);
1788 gboolean is_running = (dbus->forward_queue != NULL);
1789 dbus->forward_queue = g_list_append (dbus->forward_queue, data);
1790 g_mutex_unlock (dbus->forward_lock);
1793 g_idle_add_full (G_PRIORITY_DEFAULT,
1794 (GSourceFunc) bus_dbus_impl_forward_message_idle_cb,
1795 g_object_ref (dbus), (GDestroyNotify) g_object_unref);
1796 /* the idle callback function will be called from the ibus's main thread. */
1800 static BusDispatchData *
1801 bus_dispatch_data_new (GDBusMessage *message,
1802 BusConnection *skip_connection)
1804 BusDispatchData *data = g_slice_new (BusDispatchData);
1806 data->message = (GDBusMessage *) g_object_ref (message);
1807 if (skip_connection) {
1808 data->skip_connection = (BusConnection *) g_object_ref (skip_connection);
1811 data->skip_connection = NULL;
1817 bus_dispatch_data_free (BusDispatchData *data)
1819 g_object_unref (data->message);
1820 if (data->skip_connection)
1821 g_object_unref (data->skip_connection);
1822 g_slice_free (BusDispatchData, data);
1826 * bus_dbus_impl_dispatch_message_by_rule_idle_cb:
1828 * Process the first element of the dbus->dispatch_queue.
1831 bus_dbus_impl_dispatch_message_by_rule_idle_cb (BusDBusImpl *dbus)
1833 g_return_val_if_fail (dbus->dispatch_queue != NULL, FALSE);
1835 if (G_UNLIKELY (IBUS_OBJECT_DESTROYED (dbus))) {
1836 /* dbus was destryed */
1837 g_mutex_lock (dbus->dispatch_lock);
1838 g_list_free_full (dbus->dispatch_queue,
1839 (GDestroyNotify) bus_dispatch_data_free);
1840 dbus->dispatch_queue = NULL;
1841 g_mutex_unlock (dbus->dispatch_lock);
1842 return FALSE; /* return FALSE to prevent this callback to be called again. */
1845 /* remove fist node */
1846 g_mutex_lock (dbus->dispatch_lock);
1847 BusDispatchData *data = (BusDispatchData *) dbus->dispatch_queue->data;
1848 dbus->dispatch_queue = g_list_delete_link (dbus->dispatch_queue, dbus->dispatch_queue);
1849 gboolean has_message = (dbus->dispatch_queue != NULL);
1850 g_mutex_unlock (dbus->dispatch_lock);
1853 GList *recipients = NULL;
1855 /* check each match rules, and get recipients */
1856 for (link = dbus->rules; link != NULL; link = link->next) {
1857 GList *list = bus_match_rule_get_recipients ((BusMatchRule *) link->data,
1859 recipients = g_list_concat (recipients, list);
1862 /* send message to each recipients */
1863 for (link = recipients; link != NULL; link = link->next) {
1864 BusConnection *connection = (BusConnection *) link->data;
1865 if (G_LIKELY (connection != data->skip_connection)) {
1866 g_dbus_connection_send_message (bus_connection_get_dbus_connection (connection),
1868 G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL,
1872 g_list_free (recipients);
1873 bus_dispatch_data_free (data);
1875 return has_message; /* remove this idle callback if no message is left by returning FALSE. */
1879 bus_dbus_impl_dispatch_message_by_rule (BusDBusImpl *dbus,
1880 GDBusMessage *message,
1881 BusConnection *skip_connection)
1883 /* WARNING - this function could be called by the GDBus's worker thread. So you should not call thread unsafe IBus functions. */
1884 g_assert (BUS_IS_DBUS_IMPL (dbus));
1885 g_assert (message != NULL);
1886 g_assert (skip_connection == NULL || BUS_IS_CONNECTION (skip_connection));
1888 if (G_UNLIKELY (IBUS_OBJECT_DESTROYED (dbus)))
1890 /* FIXME - see the FIXME comment in bus_dbus_impl_forward_message. */
1892 static GQuark dispatched_quark = 0;
1893 if (dispatched_quark == 0) {
1894 dispatched_quark = g_quark_from_static_string ("DISPATCHED");
1897 /* A message sent or forwarded by bus_dbus_impl_dispatch_message_by_rule_idle_cb is also processed by the filter callback.
1898 * If this message has been dispatched by rule, do nothing. */
1899 if (g_object_get_qdata ((GObject *) message, dispatched_quark) != NULL)
1901 g_object_set_qdata ((GObject *) message, dispatched_quark, GINT_TO_POINTER (1));
1903 /* append dispatch data into the queue, and start idle task if necessary */
1904 g_mutex_lock (dbus->dispatch_lock);
1905 gboolean is_running = (dbus->dispatch_queue != NULL);
1906 dbus->dispatch_queue = g_list_append (dbus->dispatch_queue,
1907 bus_dispatch_data_new (message, skip_connection));
1908 g_mutex_unlock (dbus->dispatch_lock);
1910 g_idle_add_full (G_PRIORITY_DEFAULT,
1911 (GSourceFunc) bus_dbus_impl_dispatch_message_by_rule_idle_cb,
1912 g_object_ref (dbus),
1913 (GDestroyNotify) g_object_unref);
1914 /* the idle callback function will be called from the ibus's main thread. */
1919 bus_dbus_impl_object_destroy_cb (IBusService *object,
1922 bus_dbus_impl_unregister_object (dbus, object);
1927 bus_dbus_impl_register_object (BusDBusImpl *dbus,
1928 IBusService *object)
1930 g_assert (BUS_IS_DBUS_IMPL (dbus));
1931 g_assert (IBUS_IS_SERVICE (object));
1933 if (G_UNLIKELY (IBUS_OBJECT_DESTROYED (dbus))) {
1937 dbus->objects = g_list_prepend (dbus->objects, g_object_ref (object));
1938 g_signal_connect (object, "destroy",
1939 G_CALLBACK (bus_dbus_impl_object_destroy_cb), dbus);
1942 for (p = dbus->connections; p != NULL; p = p->next) {
1943 GDBusConnection *connection = bus_connection_get_dbus_connection ((BusConnection *) p->data);
1944 if (connection != ibus_service_get_connection ((IBusService *) object))
1945 ibus_service_register ((IBusService *) object,
1946 bus_connection_get_dbus_connection ((BusConnection *) p->data), NULL);
1952 bus_dbus_impl_unregister_object (BusDBusImpl *dbus,
1953 IBusService *object)
1955 g_assert (BUS_IS_DBUS_IMPL (dbus));
1956 g_assert (IBUS_IS_SERVICE (object));
1958 GList *p = g_list_find (dbus->objects, object);
1962 g_signal_handlers_disconnect_by_func (object,
1963 G_CALLBACK (bus_dbus_impl_object_destroy_cb), dbus);
1964 dbus->objects = g_list_delete_link (dbus->objects, p);
1965 if (!IBUS_OBJECT_DESTROYED (object)) {
1967 for (p = dbus->connections; p != NULL; p = p->next) {
1968 ibus_service_unregister ((IBusService *) object,
1969 bus_connection_get_dbus_connection ((BusConnection *) p->data));
1972 g_object_unref (object);