beautiful: simplify data retrieval
[awesome.git] / dbus.c
blob92e4f9fc962f5cc3e52c062b1cde01372d4a9d3f
1 /*
2 * dbus.c - awesome dbus support
4 * Copyright © 2008 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "config.h"
23 #include "dbus.h"
24 #include "client.h"
26 #ifdef WITH_DBUS
28 #include <ev.h>
29 #include <dbus/dbus.h>
30 #include <unistd.h>
31 #include <fcntl.h>
33 #include "widget.h"
35 extern awesome_t globalconf;
37 static DBusError err;
38 static DBusConnection *dbus_connection = NULL;
39 ev_io dbusio = { .fd = -1 };
41 static int
42 a_dbus_message_iter(DBusMessageIter *iter)
44 int nargs = 0;
48 switch(dbus_message_iter_get_arg_type(iter))
50 case DBUS_TYPE_INVALID:
51 break;
52 case DBUS_TYPE_VARIANT:
54 DBusMessageIter subiter;
55 dbus_message_iter_recurse(iter, &subiter);
56 a_dbus_message_iter(&subiter);
58 nargs++;
59 break;
60 case DBUS_TYPE_DICT_ENTRY:
62 DBusMessageIter subiter;
64 /* initialize a sub iterator */
65 dbus_message_iter_recurse(iter, &subiter);
66 /* create a new table to store the dict */
67 a_dbus_message_iter(&subiter);
69 nargs++;
70 break;
71 case DBUS_TYPE_ARRAY:
73 int array_type = dbus_message_iter_get_element_type(iter);
75 /* create a new table to store all the value */
76 lua_newtable(globalconf.L);
78 if(dbus_type_is_fixed(array_type))
79 switch(array_type)
81 int datalen;
82 #define DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER(type, dbustype) \
83 case dbustype: \
84 { \
85 type *data; \
86 dbus_message_iter_get_fixed_array(iter, &data, &datalen); \
87 for(int i = 0; i < datalen; i++) \
88 { \
89 lua_pushnumber(globalconf.L, data[i]); \
90 lua_rawseti(globalconf.L, -2, i + 1); \
91 } \
92 } \
93 break;
94 DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER(int16_t, DBUS_TYPE_INT16)
95 DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER(uint16_t, DBUS_TYPE_UINT16)
96 DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER(int32_t, DBUS_TYPE_INT32)
97 DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER(uint32_t, DBUS_TYPE_UINT32)
98 DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER(int64_t, DBUS_TYPE_INT64)
99 DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER(uint64_t, DBUS_TYPE_UINT64)
100 #undef DBUS_MSG_HANDLE_ARRAY_TYPE_NUMBER
102 else if(array_type == DBUS_TYPE_DICT_ENTRY)
104 DBusMessageIter subiter;
106 /* initialize a sub iterator */
107 dbus_message_iter_recurse(iter, &subiter);
108 /* get the keys and the values
109 * n is the number of entry in * dict */
110 int n = a_dbus_message_iter(&subiter);
112 for(int i = 0; i < n; i ++)
113 lua_rawset(globalconf.L, - (n * 2) - 1 + i * 2);
115 else
117 DBusMessageIter subiter;
119 /* prepare to dig into the array*/
120 dbus_message_iter_recurse(iter, &subiter);
122 /* now iterate over every element of the array */
123 int n = a_dbus_message_iter(&subiter);
125 for(int i = n; i > 0; i--)
127 lua_rawseti(globalconf.L, - i - 1, i);
131 nargs++;
132 break;
133 case DBUS_TYPE_BOOLEAN:
135 bool b;
136 dbus_message_iter_get_basic(iter, &b);
137 lua_pushboolean(globalconf.L, b);
139 nargs++;
140 break;
141 case DBUS_TYPE_BYTE:
143 char c;
144 dbus_message_iter_get_basic(iter, &c);
145 lua_pushlstring(globalconf.L, &c, 1);
147 nargs++;
148 break;
149 #define DBUS_MSG_HANDLE_TYPE_NUMBER(type, dbustype) \
150 case dbustype: \
152 type ui; \
153 dbus_message_iter_get_basic(iter, &ui); \
154 lua_pushnumber(globalconf.L, ui); \
156 nargs++; \
157 break;
158 DBUS_MSG_HANDLE_TYPE_NUMBER(int16_t, DBUS_TYPE_INT16)
159 DBUS_MSG_HANDLE_TYPE_NUMBER(uint16_t, DBUS_TYPE_UINT16)
160 DBUS_MSG_HANDLE_TYPE_NUMBER(int32_t, DBUS_TYPE_INT32)
161 DBUS_MSG_HANDLE_TYPE_NUMBER(uint32_t, DBUS_TYPE_UINT32)
162 DBUS_MSG_HANDLE_TYPE_NUMBER(int64_t, DBUS_TYPE_INT64)
163 DBUS_MSG_HANDLE_TYPE_NUMBER(uint64_t, DBUS_TYPE_UINT64)
164 #undef DBUS_MSG_HANDLE_TYPE_NUMBER
165 case DBUS_TYPE_STRING:
167 char *s;
168 dbus_message_iter_get_basic(iter, &s);
169 lua_pushstring(globalconf.L, s);
171 nargs++;
172 break;
174 } while(dbus_message_iter_next(iter));
176 return nargs;
179 static void
180 a_dbus_process_request(DBusMessage *msg)
182 if(globalconf.hooks.dbus == LUA_REFNIL)
183 return;
185 lua_newtable(globalconf.L);
187 switch(dbus_message_get_type(msg))
189 case DBUS_MESSAGE_TYPE_SIGNAL:
190 lua_pushliteral(globalconf.L, "signal");
191 break;
192 case DBUS_MESSAGE_TYPE_METHOD_CALL:
193 lua_pushliteral(globalconf.L, "method_call");
194 break;
195 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
196 lua_pushliteral(globalconf.L, "method_return");
197 break;
198 case DBUS_MESSAGE_TYPE_ERROR:
199 lua_pushliteral(globalconf.L, "error");
200 break;
201 default:
202 lua_pushliteral(globalconf.L, "unknown");
203 break;
206 lua_setfield(globalconf.L, -2, "type");
208 const char *s = dbus_message_get_interface(msg);
209 lua_pushstring(globalconf.L, NONULL(s));
210 lua_setfield(globalconf.L, -2, "interface");
212 s = dbus_message_get_path(msg);
213 lua_pushstring(globalconf.L, NONULL(s));
214 lua_setfield(globalconf.L, -2, "path");
216 s = dbus_message_get_member(msg);
217 lua_pushstring(globalconf.L, NONULL(s));
218 lua_setfield(globalconf.L, -2, "member");
220 /* + 1 for the table above */
221 DBusMessageIter iter;
222 int nargs = 1;
224 if(dbus_message_iter_init(msg, &iter))
225 nargs += a_dbus_message_iter(&iter);
227 if(dbus_message_get_no_reply(msg))
228 luaA_dofunction(globalconf.L, globalconf.hooks.dbus, nargs, 0);
229 else
231 int n = lua_gettop(globalconf.L) - nargs;
232 luaA_dofunction(globalconf.L, globalconf.hooks.dbus, nargs, LUA_MULTRET);
233 n -= lua_gettop(globalconf.L);
235 DBusMessage *reply = dbus_message_new_method_return(msg);
237 dbus_message_iter_init_append(reply, &iter);
239 /* i is negative */
240 for(int i = n; i < 0; i += 2)
242 /* i is the type name, i+1 the value */
243 size_t len;
244 const char *type = lua_tolstring(globalconf.L, i, &len);
246 if(!type || len != 1)
247 break;
249 switch(*type)
251 case DBUS_TYPE_BOOLEAN:
253 bool b = lua_toboolean(globalconf.L, i + 1);
254 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b);
256 break;
257 #define DBUS_MSG_RETURN_HANDLE_TYPE_STRING(dbustype) \
258 case dbustype: \
259 if((s = lua_tostring(globalconf.L, i + 1))) \
260 dbus_message_iter_append_basic(&iter, dbustype, &s); \
261 break;
262 DBUS_MSG_RETURN_HANDLE_TYPE_STRING(DBUS_TYPE_STRING)
263 DBUS_MSG_RETURN_HANDLE_TYPE_STRING(DBUS_TYPE_BYTE)
264 #undef DBUS_MSG_RETURN_HANDLE_TYPE_STRING
265 #define DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(type, dbustype) \
266 case dbustype: \
268 type num = lua_tonumber(globalconf.L, i + 1); \
269 dbus_message_iter_append_basic(&iter, dbustype, &num); \
271 break;
272 DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(int16_t, DBUS_TYPE_INT16)
273 DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(uint16_t, DBUS_TYPE_UINT16)
274 DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(int32_t, DBUS_TYPE_INT32)
275 DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(uint32_t, DBUS_TYPE_UINT32)
276 DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(int64_t, DBUS_TYPE_INT64)
277 DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(uint64_t, DBUS_TYPE_UINT64)
278 DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER(double, DBUS_TYPE_DOUBLE)
279 #undef DBUS_MSG_RETURN_HANDLE_TYPE_NUMBER
282 lua_remove(globalconf.L, i);
283 lua_remove(globalconf.L, i + 1);
286 dbus_connection_send(dbus_connection, reply, NULL);
287 dbus_message_unref(reply);
291 static void
292 a_dbus_process_requests(EV_P_ ev_io *w, int revents)
294 DBusMessage *msg;
295 int nmsg = 0;
297 if(!dbus_connection && !a_dbus_init())
298 return;
300 while(true)
302 dbus_connection_read_write(dbus_connection, 0);
304 if(!(msg = dbus_connection_pop_message(dbus_connection)))
305 break;
307 if(dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL, "Disconnected"))
309 a_dbus_cleanup();
310 dbus_message_unref(msg);
311 return;
313 else
314 a_dbus_process_request(msg);
316 dbus_message_unref(msg);
318 nmsg++;
321 if(nmsg)
322 dbus_connection_flush(dbus_connection);
325 static bool
326 a_dbus_request_name(const char *name)
328 int ret = dbus_bus_request_name(dbus_connection, name, 0, &err);
330 if(dbus_error_is_set(&err))
332 warn("failed to request D-Bus name: %s", err.message);
333 return false;
336 switch(ret)
338 case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
339 return true;
340 case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
341 warn("already primary D-Bus name owner for %s", name);
342 return true;
344 return false;
347 static bool
348 a_dbus_release_name(const char *name)
350 int ret = dbus_bus_release_name(dbus_connection, name, &err);
352 if(dbus_error_is_set(&err))
354 warn("failed to release D-Bus name: %s", err.message);
355 return false;
358 switch(ret)
360 case DBUS_RELEASE_NAME_REPLY_NOT_OWNER:
361 warn("not primary D-Bus name owner for %s", name);
362 return false;
363 case DBUS_RELEASE_NAME_REPLY_NON_EXISTENT:
364 warn("non existent D-Bus name: %s", name);
365 return false;
367 return true;
370 bool
371 a_dbus_init(void)
373 int fd;
375 dbus_error_init(&err);
377 dbus_connection = dbus_bus_get(DBUS_BUS_SESSION, &err);
378 if(dbus_error_is_set(&err))
380 warn("D-Bus system bus connection failed: %s", err.message);
381 dbus_connection = NULL;
382 dbus_error_free(&err);
383 return false;
386 dbus_connection_set_exit_on_disconnect(dbus_connection, FALSE);
388 a_dbus_request_name("org.awesome");
390 if(!dbus_connection_get_unix_fd(dbus_connection, &fd))
392 warn("cannot get D-Bus connection file descriptor");
393 a_dbus_cleanup();
394 return false;
397 fcntl(fd, F_SETFD, FD_CLOEXEC);
399 ev_io_init(&dbusio, a_dbus_process_requests, fd, EV_READ);
400 ev_io_start(EV_DEFAULT_UC_ &dbusio);
401 ev_unref(EV_DEFAULT_UC);
402 return true;
405 void
406 a_dbus_cleanup(void)
408 if(!dbus_connection)
409 return;
411 dbus_error_free(&err);
413 if (dbusio.fd >= 0) {
414 ev_ref(EV_DEFAULT_UC);
415 ev_io_stop(EV_DEFAULT_UC_ &dbusio);
416 dbusio.fd = -1;
419 /* This is a shared connection owned by libdbus
420 * Do not close it, only unref
422 dbus_connection_unref(dbus_connection);
423 dbus_connection = NULL;
426 /** Register a D-Bus name to receive message from.
427 * \param L The Lua VM state.
428 * \return The number of elements pushed on stack.
429 * \luastack
430 * \lparam A string with the name of the D-Bus name to register. Note that
431 * org.awesome is registered by default.
432 * \lreturn True if everything worked fine, false otherwise.
434 static int
435 luaA_dbus_request_name(lua_State *L)
437 const char *name = luaL_checkstring(L, 1);
438 lua_pushboolean(L, a_dbus_request_name(name));
439 return 1;
442 /** Release a D-Bus name.
443 * \param L The Lua VM state.
444 * \return The number of elements pushed on stack.
445 * \luastack
446 * \lparam A string with the name of the D-Bus name to unregister.
447 * \lreturn True if everything worked fine, false otherwise.
449 static int
450 luaA_dbus_release_name(lua_State *L)
452 const char *name = luaL_checkstring(L, 1);
453 lua_pushboolean(L, a_dbus_release_name(name));
454 return 1;
457 /** Add a match rule to match messages going through the message bus.
458 * \param L The Lua VM state.
459 * \return The number of elements pushed on stack.
460 * \luastack
461 * \lparam A string with the name of the match rule.
463 static int
464 luaA_dbus_add_match(lua_State *L)
466 const char *name = luaL_checkstring(L, 1);
467 dbus_bus_add_match(dbus_connection, name, NULL);
468 dbus_connection_flush(dbus_connection);
469 return 0;
472 /** Remove a previously added match rule "by value"
473 * (the most recently-added identical rule gets removed).
474 * \param L The Lua VM state.
475 * \return The number of elements pushed on stack.
476 * \luastack
477 * \lparam A string with the name of the match rule.
479 static int
480 luaA_dbus_remove_match(lua_State *L)
482 const char *name = luaL_checkstring(L, 1);
483 dbus_bus_remove_match(dbus_connection, name, NULL);
484 dbus_connection_flush(dbus_connection);
485 return 0;
488 const struct luaL_reg awesome_dbus_lib[] =
490 { "request_name", luaA_dbus_request_name },
491 { "release_name", luaA_dbus_release_name },
492 { "add_match", luaA_dbus_add_match },
493 { "remove_match", luaA_dbus_remove_match },
494 { NULL, NULL }
497 #else /* HAVE_DBUS */
499 bool
500 a_dbus_init(void)
502 return false;
505 void
506 a_dbus_cleanup(void)
508 /* empty */
511 static int
512 luaA_donothing(lua_State *L)
514 return 0;
517 const struct luaL_reg awesome_dbus_lib[] =
519 { "request_name", luaA_donothing },
520 { "release_name", luaA_donothing },
521 { "add_match", luaA_donothing },
522 { "remove_match", luaA_donothing },
523 { NULL, NULL }
526 #endif
527 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80