Various component fixes, and fix dbind_method_call_reentrant_va
[platform/upstream/at-spi2-core.git] / dbind / dbind.c
1
2
3 #include <stdio.h>
4 #include <stdarg.h>
5 #include <glib.h>
6
7 #include "config.h"
8 #include "dbind/dbind.h"
9
10 static int dbind_timeout = -1;
11
12 /*
13  * FIXME: compare types - to ensure they match &
14  *        do dynamic padding of structures etc.
15  */
16
17 /*---------------------------------------------------------------------------*/
18
19 typedef struct _SpiReentrantCallClosure 
20 {
21   GMainLoop   *loop;
22   DBusMessage *reply;
23 } SpiReentrantCallClosure;
24
25 static void
26 set_reply (DBusPendingCall * pending, void *user_data)
27 {
28   SpiReentrantCallClosure* closure = (SpiReentrantCallClosure *) user_data; 
29
30   closure->reply = dbus_pending_call_steal_reply (pending);
31   g_main_loop_quit (closure->loop);
32 }
33
34 DBusMessage *
35 dbind_send_and_allow_reentry (DBusConnection * bus, DBusMessage * message, DBusError *error)
36 {
37   DBusPendingCall *pending;
38   SpiReentrantCallClosure closure;
39
40   if (strcmp (dbus_message_get_destination (message),
41               dbus_bus_get_unique_name (bus)) != 0)
42     return dbus_connection_send_with_reply_and_block (bus, message, dbind_timeout, error);
43
44   if (!dbus_connection_send_with_reply (bus, message, &pending, dbind_timeout))
45       return NULL;
46   dbus_pending_call_set_notify (pending, set_reply, (void *) &closure, NULL);
47   closure.loop = g_main_loop_new (NULL, FALSE);
48   dbus_connection_setup_with_g_main(bus, NULL);
49
50   if (1)
51     {
52       g_main_loop_run  (closure.loop);
53     }
54   else
55     {
56       closure.reply = NULL;
57       while (!closure.reply)
58         {
59           if (!dbus_connection_read_write_dispatch (bus, dbind_timeout))
60             return NULL;
61         }
62     }
63   
64   g_main_loop_unref (closure.loop);
65   return closure.reply;
66 }
67
68 dbus_bool_t
69 dbind_method_call_reentrant_va (DBusConnection *cnx,
70                                 const char     *bus_name,
71                                 const char     *path,
72                                 const char     *interface,
73                                 const char     *method,
74                                 DBusError      *opt_error,
75                                 const char     *arg_types,
76                                 va_list         args)
77 {
78     dbus_bool_t success = FALSE;
79     DBusMessage *msg = NULL, *reply = NULL;
80     DBusMessageIter iter;
81     DBusError *err, real_err;
82     const char *p;
83
84     if (opt_error)
85         err = opt_error;
86     else {
87         dbus_error_init (&real_err);
88         err = &real_err;
89     }
90
91     msg = dbus_message_new_method_call (bus_name, path, interface, method);
92     if (!msg)
93         goto out;
94
95     p = arg_types;
96     dbus_message_iter_init_append (msg, &iter);
97     dbind_any_marshal_va (&iter, &p, &args);
98
99     reply = dbind_send_and_allow_reentry (cnx, msg, err);
100     if (!reply)
101         goto out;
102
103     if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR)
104     {
105       const char *name = dbus_message_get_error_name (reply);
106       dbus_set_error (err, name, g_strdup (""));
107       goto out;
108     }
109     /* demarshal */
110     if (p[0] == '=' && p[1] == '>')
111     {
112         DBusMessageIter iter;
113         p += 2;
114         dbus_message_iter_init (reply, &iter);
115         dbind_any_demarshal_va (&iter, &p, &args);
116     }
117
118     success = TRUE;
119 out:
120     if (msg)
121         dbus_message_unref (msg);
122
123     if (reply)
124         dbus_message_unref (reply);
125
126     if (err == &real_err)
127         dbus_error_free (err);
128
129     return success;
130 }
131
132 /**
133  * dbind_method_call_reentrant:
134  *
135  * @cnx:       A D-Bus Connection used to make the method call.
136  * @bus_name:  The D-Bus bus name of the program where the method call should
137  *             be made.
138  * @path:      The D-Bus object path that should handle the method.
139  * @interface: The D-Bus interface used to scope the method name.
140  * @method:    Method to be invoked.
141  * @opt_error: D-Bus error.
142  * @arg_types: Variable length arguments interleaving D-Bus argument types
143  *             and pointers to argument data.
144  *
145  * Makes a D-Bus method call using the supplied location data, method name and
146  * argument data.This function is re-entrant. It continuously reads from the D-Bus
147  * bus and dispatches messages until a reply has been recieved.
148  **/
149 dbus_bool_t
150 dbind_method_call_reentrant (DBusConnection *cnx,
151                              const char     *bus_name,
152                              const char     *path,
153                              const char     *interface,
154                              const char     *method,
155                              DBusError      *opt_error,
156                              const char     *arg_types,
157                              ...)
158 {
159     dbus_bool_t success = FALSE;
160     va_list args;
161
162     va_start (args, arg_types);
163     success = dbind_method_call_reentrant_va (cnx,
164                                               bus_name,
165                                               path,
166                                               interface,
167                                               method,
168                                               opt_error,
169                                               arg_types,
170                                               args);
171     va_end (args);
172
173     return success;
174 }
175
176 /*---------------------------------------------------------------------------*/
177
178 dbus_bool_t
179 dbind_emit_signal_va (DBusConnection *cnx,
180                       const char     *path,
181                       const char     *interface,
182                       const char     *signal,
183                       DBusError      *opt_error,
184                       const char     *arg_types,
185                       va_list         args)
186 {
187     dbus_bool_t success = FALSE;
188     DBusMessage *msg = NULL;
189     DBusMessageIter iter;
190     DBusError *err, real_err;
191     const char *p;
192
193     if (opt_error)
194         err = opt_error;
195     else {
196         dbus_error_init (&real_err);
197         err = &real_err;
198     }
199
200     msg = dbus_message_new_signal (path, interface, signal);
201     if (!msg)
202         goto out;
203
204     p = arg_types;
205     dbus_message_iter_init_append (msg, &iter);
206     dbind_any_marshal_va (&iter, &p, &args);
207
208     if (!dbus_connection_send (cnx, msg, NULL))
209        goto out;
210
211     success = TRUE;
212 out:
213
214     if (msg)
215         dbus_message_unref (msg);
216
217     if (err == &real_err)
218         dbus_error_free (err);
219
220     return success;
221 }
222
223 /**
224  * dbind_emit_signal:
225  *
226  * @cnx:       A D-Bus Connection used to make the method call.
227  * @path:      The D-Bus object path that this signal is emitted from.
228  * @interface: The D-Bus interface used to scope the method name.
229  * @signal:    Name of signal to emit.
230  * @opt_error: D-Bus error.
231  * @arg_types: Variable length arguments interleaving D-Bus argument types
232  *             and pointers to argument data.
233  *
234  * Emits a D-Bus signal  using the supplied signal name and argument data.
235  **/
236 dbus_bool_t
237 dbind_emit_signal (DBusConnection *cnx,
238                    const char     *path,
239                    const char     *interface,
240                    const char     *signal,
241                    DBusError      *opt_error,
242                    const char     *arg_types,
243                    ...)
244 {
245     dbus_bool_t success = FALSE;
246     va_list args;
247
248     va_start (args, arg_types);
249     success = dbind_emit_signal_va (cnx, path, interface, signal, opt_error, arg_types, args);
250     va_end (args);
251
252     return success;
253 }
254 void
255 dbind_set_timeout (int timeout)
256 {
257   dbind_timeout = timeout;
258 }
259
260
261 /*END------------------------------------------------------------------------*/