chiark / gitweb /
New option: movres.ignore_transience.
[e16] / src / edbus.c
1 /*
2  * Copyright (C) 2007-2008 Kim Woelders
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies of the Software, its documentation and marketing & publicity
13  * materials, and acknowledgment shall be given in the documentation, materials
14  * and software packages that this Software was used.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #include "E.h"
24 #include "edbus.h"
25 #include "events.h"
26 #include "ipc.h"
27 #include "xwin.h"
28 #include <dbus/dbus.h>
29
30 #define ENABLE_INTROSPECTION 1
31
32 #define DEBUG_DBUS 1
33 #if DEBUG_DBUS
34 #define Dprintf(fmt...)  if(EDebug(EDBUG_TYPE_DBUS))Eprintf(fmt)
35 #define D2printf(fmt...) if(EDebug(EDBUG_TYPE_DBUS)>1)Eprintf(fmt)
36 #else
37 #define Dprintf(fmt...)
38 #define D2printf(fmt...)
39 #endif
40
41 typedef struct {
42    char               *name;
43    DBusConnection     *conn;
44    DBusWatch          *watch;
45    int                 fd;
46 } DbusData;
47
48 static DbusData     dbus_data;
49
50 static EventFdDesc *db_efd = NULL;
51
52 static              dbus_bool_t
53 DbusWatchAdd(DBusWatch * watch, void *data __UNUSED__)
54 {
55    dbus_data.watch = watch;
56    dbus_data.fd = dbus_watch_get_unix_fd(watch);
57
58    D2printf("DbusWatchAdd fd=%d flags=%d\n", dbus_data.fd,
59             dbus_watch_get_flags(dbus_data.watch));
60
61    return TRUE;
62 }
63
64 static void
65 DbusWatchRemove(DBusWatch * watch __UNUSED__, void *data __UNUSED__)
66 {
67    D2printf("DbusWatchRemove\n");
68 }
69
70 #if 0                           /* Don't need this */
71 static void
72 DbusWatchToggle(DBusWatch * watch __UNUSED__, void *data __UNUSED__)
73 {
74    D2printf("DbusWatchToggle\n");
75 }
76 #else
77 #define DbusWatchToggle NULL
78 #endif
79
80 static void
81 DbusReplyString(DBusConnection * conn, DBusMessage * msg, const char *str)
82 {
83    DBusMessage        *reply;
84    DBusMessageIter     args;
85
86    reply = dbus_message_new_method_return(msg);
87
88    dbus_message_iter_init_append(reply, &args);
89    if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &str))
90       goto done;
91    if (!dbus_connection_send(conn, reply, NULL))
92       goto done;
93    dbus_connection_flush(conn);
94
95  done:
96    dbus_message_unref(reply);
97 }
98
99 static void
100 DbusIpcReply(void *data, const char *str)
101 {
102    DBusMessage        *msg = (DBusMessage *) data;
103
104    if (!str)
105       str = "ok";
106    DbusReplyString(dbus_data.conn, msg, str);
107 }
108
109 static void
110 DbusMethodCommand(DBusConnection * conn, DBusMessage * msg)
111 {
112    DBusMessageIter     args;
113    const char         *param = "";
114
115    if (!dbus_message_iter_init(msg, &args) ||
116        dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
117      {
118         DbusReplyString(conn, msg, "String arg required\n");
119         return;
120      }
121    else
122       dbus_message_iter_get_basic(&args, &param);
123
124    IpcExecReply(param, DbusIpcReply, msg);
125 }
126
127 #if ENABLE_INTROSPECTION
128 /* *INDENT-OFF* */
129 static const char   dbus_introspect_data[] =
130    "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'\n"
131    "'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n"
132    "<node>\n"
133    " <interface name='org.freedesktop.DBus.Introspectable'>\n"
134    "  <method name='Introspect'>\n"
135    "   <arg name='data' direction='out' type='s'/>\n"
136    "  </method>\n"
137    " </interface>\n"
138    " <interface name='%s'>\n"
139    "  <method name='Command'>\n"
140    "   <arg name='data' direction='out' type='s'/>\n"
141    "  </method>\n"
142    "  <signal name='Signal'>\n"
143    "   <arg name='data' direction='in' type='s'/>\n"
144    "  </signal>\n"
145    " </interface>\n"
146    "</node>";
147 /* *INDENT-ON* */
148
149 static void
150 DbusMsgIntrospect(DBusConnection * conn, DBusMessage * msg)
151 {
152    char                buf[1024];
153
154    D2printf("Introspect\n");
155
156    Esnprintf(buf, sizeof(buf), dbus_introspect_data, dbus_data.name);
157    if (!strcmp(dbus_message_get_path(msg), "/"))
158       DbusReplyString(conn, msg, buf);
159    else
160       DbusReplyString(conn, msg, "");
161 }
162 #endif
163
164 static              DBusHandlerResult
165 DbusMsgHandler(DBusConnection * conn, DBusMessage * msg,
166                void *user_data __UNUSED__)
167 {
168    int                 msg_type;
169    const char         *msg_dest, *msg_ifc, *msg_memb;
170
171    D2printf("DbusMsgHandler\n");
172
173    msg_type = dbus_message_get_type(msg);
174    msg_dest = dbus_message_get_destination(msg);
175    msg_ifc = dbus_message_get_interface(msg);
176    msg_memb = dbus_message_get_member(msg);
177
178    switch (msg_type)
179      {
180      default:                   /* Should not be possible */
181         Dprintf("MESSAGE type=%d\n", msg_type);
182         break;
183
184      case DBUS_MESSAGE_TYPE_METHOD_CALL:
185         Dprintf("METHOD %s %s\n", msg_ifc, msg_memb);
186         if (strcmp(msg_dest, dbus_data.name))
187            break;
188         if (!strcmp(msg_ifc, "org.e16"))
189           {
190              if (!strcmp(msg_memb, "Command"))
191                 DbusMethodCommand(conn, msg);
192              else
193                 DbusReplyString(conn, msg, "Error");
194           }
195 #if ENABLE_INTROSPECTION
196         else if (!strcmp(msg_ifc, "org.freedesktop.DBus.Introspectable"))
197           {
198              if (!strcmp(msg_memb, "Introspect"))
199                 DbusMsgIntrospect(conn, msg);
200           }
201 #endif
202         break;
203
204      case DBUS_MESSAGE_TYPE_SIGNAL:
205         Dprintf("SIGNAL %s %s\n", msg_ifc, msg_memb);
206         if (!strcmp(msg_ifc, "org.e16"))
207           {
208              Dprintf("... for me!\n");
209           }
210         break;
211      }
212
213    D2printf("sender    = %s\n", dbus_message_get_sender(msg));
214    D2printf("dest      = %s\n", dbus_message_get_destination(msg));
215    D2printf("path      = %s\n", dbus_message_get_path(msg));
216    D2printf("interface = %s\n", dbus_message_get_interface(msg));
217    D2printf("member    = %s\n", dbus_message_get_member(msg));
218
219    return DBUS_HANDLER_RESULT_HANDLED;
220 }
221
222 static void
223 DbusHandleFd(void)
224 {
225    int                 rc;
226
227    D2printf("DbusHandleFd flags=%d\n", dbus_watch_get_flags(dbus_data.watch));
228    dbus_watch_handle(dbus_data.watch,
229                      DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE);
230
231    for (;;)
232      {
233         D2printf("DbusHandleFd: Dispatch flags=%d\n",
234                  dbus_watch_get_flags(dbus_data.watch));
235         rc = dbus_connection_dispatch(dbus_data.conn);
236         if (rc == DBUS_DISPATCH_COMPLETE)
237            break;
238      }
239 }
240
241 void
242 DbusInit(void)
243 {
244    DBusError           dberr;
245    int                 err;
246    char                buf[128];
247
248    if (Mode.wm.window)
249      {
250         sprintf(buf, "org.e16.wm.p%u", (unsigned int)Mode.wm.pid);
251      }
252    else
253      {
254         const char         *s;
255
256         s = strchr(Dpy.name, ':');
257         if (!s)
258            return;
259         sprintf(buf, "org.e16.wm.d%ds%d", atoi(s + 1), Dpy.screen);
260      }
261    dbus_data.name = Estrdup(buf);
262    Esetenv("ENL_DBUS_NAME", dbus_data.name);
263
264    dbus_error_init(&dberr);
265
266    dbus_data.fd = -1;
267
268    dbus_data.conn = dbus_bus_get(DBUS_BUS_SESSION, &dberr);
269    if (dbus_error_is_set(&dberr))
270       goto bail_out;
271    dbus_connection_set_exit_on_disconnect(dbus_data.conn, FALSE);
272
273    err = dbus_bus_request_name(dbus_data.conn, dbus_data.name,
274                                DBUS_NAME_FLAG_DO_NOT_QUEUE, &dberr);
275    if (dbus_error_is_set(&dberr))
276       goto bail_out;
277    if (err != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
278      {
279         Eprintf("*** DbusInit error: Not Primary Owner (%d)\n", err);
280         return;
281      }
282
283    Esnprintf(buf, sizeof(buf), "type='signal',destination='%s'",
284              dbus_data.name);
285    if (EDebug(EDBUG_TYPE_DBUS) > 1)     /* Catch all signals if extra debug is enabled */
286       dbus_bus_add_match(dbus_data.conn, "type='signal'", &dberr);
287    else
288       dbus_bus_add_match(dbus_data.conn, buf, &dberr);
289    if (dbus_error_is_set(&dberr))
290       goto bail_out;
291    Esnprintf(buf, sizeof(buf), "type='method_call',destination='%s'",
292              dbus_data.name);
293    dbus_bus_add_match(dbus_data.conn, buf, &dberr);
294    if (dbus_error_is_set(&dberr))
295       goto bail_out;
296 #if 0                           /* Debug */
297    dbus_bus_add_match(dbus_data.conn, "type='method_return'", &dberr);
298    if (dbus_error_is_set(&dberr))
299       goto bail_out;
300    dbus_bus_add_match(dbus_data.conn, "type='error'", &dberr);
301    if (dbus_error_is_set(&dberr))
302       goto bail_out;
303 #endif
304
305    if (!dbus_connection_add_filter(dbus_data.conn, DbusMsgHandler, NULL, NULL))
306       return;
307
308    err = dbus_connection_set_watch_functions(dbus_data.conn,
309                                              DbusWatchAdd, DbusWatchRemove,
310                                              DbusWatchToggle, NULL, NULL);
311
312    /* Handle pending D-Bus stuff */
313    DbusHandleFd();
314    db_efd = EventFdRegister(dbus_data.fd, DbusHandleFd);
315    return;
316
317  bail_out:
318    if (dbus_error_is_set(&dberr))
319      {
320         Eprintf("*** DbusInit error: %s\n", dberr.message);
321         dbus_error_free(&dberr);
322      }
323    return;
324 }
325
326 #if 0                           /* No need? */
327 void
328 DbusExit(void)
329 {
330 }
331 #endif