/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* vim:set et sts=4: */ /* ibus - The Input Bus * Copyright (C) 2008-2010 Peng Huang * Copyright (C) 2008-2010 Red Hat, Inc. * * 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. * * 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 Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA */ #include "ibusproxy.h" #include "ibusmarshalers.h" #include "ibusinternal.h" #include "ibusobject.h" #define IBUS_PROXY_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_PROXY, IBusProxyPrivate)) enum { DESTROY, LAST_SIGNAL, }; static guint proxy_signals[LAST_SIGNAL] = { 0 }; /* functions prototype */ static void ibus_proxy_dispose (GObject *object); static void ibus_proxy_real_destroy (IBusProxy *proxy); static void ibus_proxy_connection_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, IBusProxy *proxy); static void initable_iface_init (GInitableIface *initable_iface); static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface); G_DEFINE_TYPE_WITH_CODE (IBusProxy, ibus_proxy, G_TYPE_DBUS_PROXY, G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init) G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init) ); static void ibus_proxy_class_init (IBusProxyClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); gobject_class->dispose = ibus_proxy_dispose; class->destroy = ibus_proxy_real_destroy; /* install signals */ /** * IBusProxy::destroy: * @object: An IBusProxy. * * Destroy and free an IBusProxy * * See also: ibus_proxy_destroy(). * * Argument @user_data is ignored in this function. */ proxy_signals[DESTROY] = g_signal_new (I_("destroy"), G_TYPE_FROM_CLASS (gobject_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (IBusProxyClass, destroy), NULL, NULL, _ibus_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void ibus_proxy_init (IBusProxy *proxy) { proxy->own = TRUE; } /** * ibus_proxy_dispose: * * Override GObject's dispose function. */ static void ibus_proxy_dispose (GObject *object) { if (! (IBUS_PROXY_FLAGS (object) & IBUS_IN_DESTRUCTION)) { IBUS_PROXY_SET_FLAGS (object, IBUS_IN_DESTRUCTION); if (! (IBUS_PROXY_FLAGS (object) & IBUS_DESTROYED)) { g_signal_emit (object, proxy_signals[DESTROY], 0); IBUS_PROXY_SET_FLAGS (object, IBUS_DESTROYED); } IBUS_PROXY_UNSET_FLAGS (object, IBUS_IN_DESTRUCTION); } G_OBJECT_CLASS(ibus_proxy_parent_class)->dispose (object); } /** * ibus_proxy_real_destroy: * * Handle "destroy" signal which is emitted by ibus_proxy_dispose. */ static void ibus_proxy_real_destroy (IBusProxy *proxy) { GDBusConnection *connection = g_dbus_proxy_get_connection ((GDBusProxy *) proxy); g_assert (connection != NULL); if (!g_dbus_connection_is_closed (connection) && proxy->own) { g_dbus_proxy_call ((GDBusProxy *)proxy, "org.freedesktop.IBus.Service.Destroy", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); } g_signal_handlers_disconnect_by_func (connection, (GCallback) ibus_proxy_connection_closed_cb, proxy); } static void ibus_proxy_connection_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, IBusProxy *proxy) { ibus_proxy_destroy (proxy); } void ibus_proxy_destroy (IBusProxy *proxy) { g_assert (IBUS_IS_PROXY (proxy)); if (! (IBUS_PROXY_FLAGS (proxy) & IBUS_IN_DESTRUCTION)) { g_object_run_dispose (G_OBJECT (proxy)); } } static gboolean ibus_proxy_init_finish (IBusProxy *proxy, GError **error) { g_assert (IBUS_IS_PROXY (proxy)); g_assert (error == NULL || *error == NULL); GDBusConnection *connection = g_dbus_proxy_get_connection ((GDBusProxy *)proxy); if (connection == NULL || g_dbus_connection_is_closed (connection)) { /* * When proxy is created asynchronously, the connection may be closed * before proxy is ready. In this case, we need override interfaces * GInitable and GAsyncInitable to report the error. */ if (error != NULL) *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Connection is closed."); return FALSE; } g_signal_connect (connection, "closed", G_CALLBACK (ibus_proxy_connection_closed_cb), proxy); return TRUE; } static GInitableIface *initable_iface_parent = NULL; static gboolean initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { if (!initable_iface_parent->init (initable, cancellable, error)) return FALSE; return ibus_proxy_init_finish ((IBusProxy *)initable, error); } static void initable_iface_init (GInitableIface *initable_iface) { initable_iface_parent = g_type_interface_peek_parent (initable_iface); initable_iface->init = initable_init; } static GAsyncInitableIface *async_initable_iface_parent = NULL; static void async_initable_init_async (GAsyncInitable *initable, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { async_initable_iface_parent->init_async (initable, io_priority, cancellable, callback, user_data); } static gboolean async_initable_init_finish (GAsyncInitable *initable, GAsyncResult *res, GError **error) { if (!async_initable_iface_parent->init_finish (initable, res, error)) return FALSE; return ibus_proxy_init_finish ((IBusProxy *)initable, error); } static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface) { async_initable_iface_parent = g_type_interface_peek_parent (async_initable_iface); async_initable_iface->init_async = async_initable_init_async; async_initable_iface->init_finish = async_initable_init_finish; }