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.
6 *
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.1 of the License, or (at your option) any later version.
11 *
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.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
20 * USA
21 */
22
23 #include "ibusproxy.h"
24 #include "ibusmarshalers.h"
25 #include "ibusinternal.h"
26 #include "ibusobject.h"
27
28 #define IBUS_PROXY_GET_PRIVATE(o) \
29 (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_PROXY, IBusProxyPrivate))
30
31 enum {
32 DESTROY,
33 LAST_SIGNAL,
34 };
35
36 static guint proxy_signals[LAST_SIGNAL] = { 0 };
37
38 /* functions prototype */
39 static void ibus_proxy_dispose (GObject *object);
40 static void ibus_proxy_real_destroy (IBusProxy *proxy);
41
42 static void ibus_proxy_connection_closed_cb
43 (GDBusConnection *connection,
44 gboolean remote_peer_vanished,
45 GError *error,
46 IBusProxy *proxy);
47 static void initable_iface_init (GInitableIface *initable_iface);
48 static void async_initable_iface_init (GAsyncInitableIface
49 *async_initable_iface);
50 G_DEFINE_TYPE_WITH_CODE (IBusProxy, ibus_proxy, G_TYPE_DBUS_PROXY,
51 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
52 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
53 );
54
55 static void
ibus_proxy_class_init(IBusProxyClass * class)56 ibus_proxy_class_init (IBusProxyClass *class)
57 {
58 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
59
60 gobject_class->dispose = ibus_proxy_dispose;
61
62 class->destroy = ibus_proxy_real_destroy;
63
64 /* install signals */
65 /**
66 * IBusProxy::destroy:
67 * @object: An IBusProxy.
68 *
69 * Destroy and free an IBusProxy
70 *
71 * See also: ibus_proxy_destroy().
72 *
73 * <note><para>Argument @user_data is ignored in this function.</para></note>
74 */
75 proxy_signals[DESTROY] =
76 g_signal_new (I_("destroy"),
77 G_TYPE_FROM_CLASS (gobject_class),
78 G_SIGNAL_RUN_LAST,
79 G_STRUCT_OFFSET (IBusProxyClass, destroy),
80 NULL, NULL,
81 _ibus_marshal_VOID__VOID,
82 G_TYPE_NONE, 0);
83 }
84
85 static void
ibus_proxy_init(IBusProxy * proxy)86 ibus_proxy_init (IBusProxy *proxy)
87 {
88 proxy->own = TRUE;
89 }
90
91 /**
92 * ibus_proxy_dispose:
93 *
94 * Override GObject's dispose function.
95 */
96 static void
ibus_proxy_dispose(GObject * object)97 ibus_proxy_dispose (GObject *object)
98 {
99 if (! (IBUS_PROXY_FLAGS (object) & IBUS_IN_DESTRUCTION)) {
100 IBUS_PROXY_SET_FLAGS (object, IBUS_IN_DESTRUCTION);
101 if (! (IBUS_PROXY_FLAGS (object) & IBUS_DESTROYED)) {
102 g_signal_emit (object, proxy_signals[DESTROY], 0);
103 IBUS_PROXY_SET_FLAGS (object, IBUS_DESTROYED);
104 }
105 IBUS_PROXY_UNSET_FLAGS (object, IBUS_IN_DESTRUCTION);
106 }
107
108 G_OBJECT_CLASS(ibus_proxy_parent_class)->dispose (object);
109 }
110
111 /**
112 * ibus_proxy_real_destroy:
113 *
114 * Handle "destroy" signal which is emitted by ibus_proxy_dispose.
115 */
116 static void
ibus_proxy_real_destroy(IBusProxy * proxy)117 ibus_proxy_real_destroy (IBusProxy *proxy)
118 {
119 GDBusConnection *connection = g_dbus_proxy_get_connection ((GDBusProxy *) proxy);
120 g_assert (connection != NULL);
121 if (!g_dbus_connection_is_closed (connection) && proxy->own) {
122 g_dbus_proxy_call ((GDBusProxy *)proxy,
123 "org.freedesktop.IBus.Service.Destroy",
124 NULL,
125 G_DBUS_CALL_FLAGS_NONE,
126 -1, NULL, NULL, NULL);
127 }
128 g_signal_handlers_disconnect_by_func (connection,
129 (GCallback) ibus_proxy_connection_closed_cb,
130 proxy);
131 }
132
133 static void
ibus_proxy_connection_closed_cb(GDBusConnection * connection,gboolean remote_peer_vanished,GError * error,IBusProxy * proxy)134 ibus_proxy_connection_closed_cb (GDBusConnection *connection,
135 gboolean remote_peer_vanished,
136 GError *error,
137 IBusProxy *proxy)
138 {
139 ibus_proxy_destroy (proxy);
140 }
141
142 void
ibus_proxy_destroy(IBusProxy * proxy)143 ibus_proxy_destroy (IBusProxy *proxy)
144 {
145 g_assert (IBUS_IS_PROXY (proxy));
146
147 if (! (IBUS_PROXY_FLAGS (proxy) & IBUS_IN_DESTRUCTION)) {
148 g_object_run_dispose (G_OBJECT (proxy));
149 }
150 }
151
152 static gboolean
ibus_proxy_init_finish(IBusProxy * proxy,GError ** error)153 ibus_proxy_init_finish (IBusProxy *proxy,
154 GError **error)
155 {
156 g_assert (IBUS_IS_PROXY (proxy));
157 g_assert (error == NULL || *error == NULL);
158
159 GDBusConnection *connection =
160 g_dbus_proxy_get_connection ((GDBusProxy *)proxy);
161
162 if (connection == NULL || g_dbus_connection_is_closed (connection)) {
163 /*
164 * When proxy is created asynchronously, the connection may be closed
165 * before proxy is ready. In this case, we need override interfaces
166 * GInitable and GAsyncInitable to report the error.
167 */
168 if (error != NULL)
169 *error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
170 "Connection is closed.");
171 return FALSE;
172 }
173
174 g_signal_connect (connection, "closed",
175 G_CALLBACK (ibus_proxy_connection_closed_cb), proxy);
176
177 return TRUE;
178 }
179
180
181 static GInitableIface *initable_iface_parent = NULL;
182
183 static gboolean
initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)184 initable_init (GInitable *initable,
185 GCancellable *cancellable,
186 GError **error)
187 {
188 if (!initable_iface_parent->init (initable, cancellable, error))
189 return FALSE;
190 return ibus_proxy_init_finish ((IBusProxy *)initable, error);
191 }
192
193 static void
initable_iface_init(GInitableIface * initable_iface)194 initable_iface_init (GInitableIface *initable_iface)
195 {
196 initable_iface_parent = g_type_interface_peek_parent (initable_iface);
197 initable_iface->init = initable_init;
198 }
199
200 static GAsyncInitableIface *async_initable_iface_parent = NULL;
201
202 static void
async_initable_init_async(GAsyncInitable * initable,gint io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)203 async_initable_init_async (GAsyncInitable *initable,
204 gint io_priority,
205 GCancellable *cancellable,
206 GAsyncReadyCallback callback,
207 gpointer user_data)
208 {
209 async_initable_iface_parent->init_async (initable,
210 io_priority, cancellable, callback, user_data);
211 }
212
213 static gboolean
async_initable_init_finish(GAsyncInitable * initable,GAsyncResult * res,GError ** error)214 async_initable_init_finish (GAsyncInitable *initable,
215 GAsyncResult *res,
216 GError **error)
217 {
218 if (!async_initable_iface_parent->init_finish (initable, res, error))
219 return FALSE;
220 return ibus_proxy_init_finish ((IBusProxy *)initable, error);
221 }
222
223 static void
async_initable_iface_init(GAsyncInitableIface * async_initable_iface)224 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
225 {
226 async_initable_iface_parent = g_type_interface_peek_parent (async_initable_iface);
227 async_initable_iface->init_async = async_initable_init_async;
228 async_initable_iface->init_finish = async_initable_init_finish;
229 }
230