This adds optional libdbus integration for weston. If libdbus is available and not disabled via --disable-dbus during weston build, we now provide basic DBusConnection main-loop integration for weston. The dbus.c file provides a new helper to integrate any DBusConnection object into a wl_event_loop object. This avoids any glib/qt/.. dependencies but instead only uses the low-level libdbus library. Note that we do not provide dummy fallbacks for dbus helpers in case dbus-support is disabled. The reason for that is that you need dbus/dbus.h for nearly any operation you want to do via dbus. Therefore, only the most basic helpers which can be used independently provide a "static inline" dummy fallback to avoid #ifdef all over the code.dev
parent
afb9828d57
commit
59ab90049f
@ -0,0 +1,336 @@ |
|||||||
|
/*
|
||||||
|
* Copyright © 2013 David Herrmann <dh.herrmann@gmail.com> |
||||||
|
* |
||||||
|
* Permission to use, copy, modify, distribute, and sell this software and |
||||||
|
* its documentation for any purpose is hereby granted without fee, provided |
||||||
|
* that the above copyright notice appear in all copies and that both that |
||||||
|
* copyright notice and this permission notice appear in supporting |
||||||
|
* documentation, and that the name of the copyright holders not be used in |
||||||
|
* advertising or publicity pertaining to distribution of the software |
||||||
|
* without specific, written prior permission. The copyright holders make |
||||||
|
* no representations about the suitability of this software for any |
||||||
|
* purpose. It is provided "as is" without express or implied warranty. |
||||||
|
* |
||||||
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
||||||
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
||||||
|
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||||
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER |
||||||
|
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF |
||||||
|
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
* DBus Helpers |
||||||
|
* This file contains the dbus mainloop integration and several helpers to |
||||||
|
* make lowlevel libdbus access easier. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "config.h" |
||||||
|
|
||||||
|
#include <dbus/dbus.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <fcntl.h> |
||||||
|
#include <stdbool.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
#include <sys/epoll.h> |
||||||
|
#include <sys/eventfd.h> |
||||||
|
#include <sys/timerfd.h> |
||||||
|
#include <unistd.h> |
||||||
|
#include <wayland-server.h> |
||||||
|
|
||||||
|
#include "compositor.h" |
||||||
|
#include "dbus.h" |
||||||
|
|
||||||
|
/*
|
||||||
|
* DBus Mainloop Integration |
||||||
|
* weston_dbus_bind() and weston_dbus_unbind() allow to bind an existing |
||||||
|
* DBusConnection to an existing wl_event_loop object. All dbus dispatching |
||||||
|
* is then nicely integrated into the wayland event loop. |
||||||
|
* Note that this only provides basic watch and timeout dispatching. No |
||||||
|
* remote thread wakeup, signal handling or other dbus insanity is supported. |
||||||
|
* This is fine as long as you don't use any of the deprecated libdbus |
||||||
|
* interfaces (like waking up remote threads..). There is really no rational |
||||||
|
* reason to support these. |
||||||
|
*/ |
||||||
|
|
||||||
|
static int weston_dbus_dispatch_watch(int fd, uint32_t mask, void *data) |
||||||
|
{ |
||||||
|
DBusWatch *watch = data; |
||||||
|
uint32_t flags = 0; |
||||||
|
|
||||||
|
if (dbus_watch_get_enabled(watch)) { |
||||||
|
if (mask & WL_EVENT_READABLE) |
||||||
|
flags |= DBUS_WATCH_READABLE; |
||||||
|
if (mask & WL_EVENT_WRITABLE) |
||||||
|
flags |= DBUS_WATCH_WRITABLE; |
||||||
|
if (mask & WL_EVENT_HANGUP) |
||||||
|
flags |= DBUS_WATCH_HANGUP; |
||||||
|
if (mask & WL_EVENT_ERROR) |
||||||
|
flags |= DBUS_WATCH_ERROR; |
||||||
|
|
||||||
|
dbus_watch_handle(watch, flags); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static dbus_bool_t weston_dbus_add_watch(DBusWatch *watch, void *data) |
||||||
|
{ |
||||||
|
struct wl_event_loop *loop = data; |
||||||
|
struct wl_event_source *s; |
||||||
|
int fd; |
||||||
|
uint32_t mask = 0, flags; |
||||||
|
|
||||||
|
if (dbus_watch_get_enabled(watch)) { |
||||||
|
flags = dbus_watch_get_flags(watch); |
||||||
|
if (flags & DBUS_WATCH_READABLE) |
||||||
|
mask |= WL_EVENT_READABLE; |
||||||
|
if (flags & DBUS_WATCH_WRITABLE) |
||||||
|
mask |= WL_EVENT_WRITABLE; |
||||||
|
} |
||||||
|
|
||||||
|
fd = dbus_watch_get_unix_fd(watch); |
||||||
|
s = wl_event_loop_add_fd(loop, fd, mask, weston_dbus_dispatch_watch, |
||||||
|
watch); |
||||||
|
if (!s) |
||||||
|
return FALSE; |
||||||
|
|
||||||
|
dbus_watch_set_data(watch, s, NULL); |
||||||
|
return TRUE; |
||||||
|
} |
||||||
|
|
||||||
|
static void weston_dbus_remove_watch(DBusWatch *watch, void *data) |
||||||
|
{ |
||||||
|
struct wl_event_source *s; |
||||||
|
|
||||||
|
s = dbus_watch_get_data(watch); |
||||||
|
if (!s) |
||||||
|
return; |
||||||
|
|
||||||
|
wl_event_source_remove(s); |
||||||
|
} |
||||||
|
|
||||||
|
static void weston_dbus_toggle_watch(DBusWatch *watch, void *data) |
||||||
|
{ |
||||||
|
struct wl_event_source *s; |
||||||
|
uint32_t mask = 0, flags; |
||||||
|
|
||||||
|
s = dbus_watch_get_data(watch); |
||||||
|
if (!s) |
||||||
|
return; |
||||||
|
|
||||||
|
if (dbus_watch_get_enabled(watch)) { |
||||||
|
flags = dbus_watch_get_flags(watch); |
||||||
|
if (flags & DBUS_WATCH_READABLE) |
||||||
|
mask |= WL_EVENT_READABLE; |
||||||
|
if (flags & DBUS_WATCH_WRITABLE) |
||||||
|
mask |= WL_EVENT_WRITABLE; |
||||||
|
} |
||||||
|
|
||||||
|
wl_event_source_fd_update(s, mask); |
||||||
|
} |
||||||
|
|
||||||
|
static int weston_dbus_dispatch_timeout(void *data) |
||||||
|
{ |
||||||
|
DBusTimeout *timeout = data; |
||||||
|
|
||||||
|
if (dbus_timeout_get_enabled(timeout)) |
||||||
|
dbus_timeout_handle(timeout); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int weston_dbus_adjust_timeout(DBusTimeout *timeout, |
||||||
|
struct wl_event_source *s) |
||||||
|
{ |
||||||
|
int64_t t = 0; |
||||||
|
|
||||||
|
if (dbus_timeout_get_enabled(timeout)) |
||||||
|
t = dbus_timeout_get_interval(timeout); |
||||||
|
|
||||||
|
return wl_event_source_timer_update(s, t); |
||||||
|
} |
||||||
|
|
||||||
|
static dbus_bool_t weston_dbus_add_timeout(DBusTimeout *timeout, void *data) |
||||||
|
{ |
||||||
|
struct wl_event_loop *loop = data; |
||||||
|
struct wl_event_source *s; |
||||||
|
int r; |
||||||
|
|
||||||
|
s = wl_event_loop_add_timer(loop, weston_dbus_dispatch_timeout, |
||||||
|
timeout); |
||||||
|
if (!s) |
||||||
|
return FALSE; |
||||||
|
|
||||||
|
r = weston_dbus_adjust_timeout(timeout, s); |
||||||
|
if (r < 0) { |
||||||
|
wl_event_source_remove(s); |
||||||
|
return FALSE; |
||||||
|
} |
||||||
|
|
||||||
|
dbus_timeout_set_data(timeout, s, NULL); |
||||||
|
return TRUE; |
||||||
|
} |
||||||
|
|
||||||
|
static void weston_dbus_remove_timeout(DBusTimeout *timeout, void *data) |
||||||
|
{ |
||||||
|
struct wl_event_source *s; |
||||||
|
|
||||||
|
s = dbus_timeout_get_data(timeout); |
||||||
|
if (!s) |
||||||
|
return; |
||||||
|
|
||||||
|
wl_event_source_remove(s); |
||||||
|
} |
||||||
|
|
||||||
|
static void weston_dbus_toggle_timeout(DBusTimeout *timeout, void *data) |
||||||
|
{ |
||||||
|
struct wl_event_source *s; |
||||||
|
|
||||||
|
s = dbus_timeout_get_data(timeout); |
||||||
|
if (!s) |
||||||
|
return; |
||||||
|
|
||||||
|
weston_dbus_adjust_timeout(timeout, s); |
||||||
|
} |
||||||
|
|
||||||
|
static int weston_dbus_dispatch(int fd, uint32_t mask, void *data) |
||||||
|
{ |
||||||
|
DBusConnection *c = data; |
||||||
|
int r; |
||||||
|
|
||||||
|
do { |
||||||
|
r = dbus_connection_dispatch(c); |
||||||
|
if (r == DBUS_DISPATCH_COMPLETE) |
||||||
|
r = 0; |
||||||
|
else if (r == DBUS_DISPATCH_DATA_REMAINS) |
||||||
|
r = -EAGAIN; |
||||||
|
else if (r == DBUS_DISPATCH_NEED_MEMORY) |
||||||
|
r = -ENOMEM; |
||||||
|
else |
||||||
|
r = -EIO; |
||||||
|
} while (r == -EAGAIN); |
||||||
|
|
||||||
|
if (r) |
||||||
|
weston_log("cannot dispatch dbus events: %d\n", r); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int weston_dbus_bind(struct wl_event_loop *loop, DBusConnection *c, |
||||||
|
struct wl_event_source **ctx_out) |
||||||
|
{ |
||||||
|
bool b; |
||||||
|
int r, fd; |
||||||
|
|
||||||
|
/* Idle events cannot reschedule themselves, therefore we use a dummy
|
||||||
|
* event-fd and mark it for post-dispatch. Hence, the dbus |
||||||
|
* dispatcher is called after every dispatch-round. |
||||||
|
* This is required as dbus doesn't allow dispatching events from |
||||||
|
* within its own event sources. */ |
||||||
|
fd = eventfd(0, EFD_CLOEXEC); |
||||||
|
if (fd < 0) |
||||||
|
return -errno; |
||||||
|
|
||||||
|
*ctx_out = wl_event_loop_add_fd(loop, fd, 0, weston_dbus_dispatch, c); |
||||||
|
close(fd); |
||||||
|
|
||||||
|
if (!*ctx_out) |
||||||
|
return -ENOMEM; |
||||||
|
|
||||||
|
wl_event_source_check(*ctx_out); |
||||||
|
|
||||||
|
b = dbus_connection_set_watch_functions(c, |
||||||
|
weston_dbus_add_watch, |
||||||
|
weston_dbus_remove_watch, |
||||||
|
weston_dbus_toggle_watch, |
||||||
|
loop, |
||||||
|
NULL); |
||||||
|
if (!b) { |
||||||
|
r = -ENOMEM; |
||||||
|
goto error; |
||||||
|
} |
||||||
|
|
||||||
|
b = dbus_connection_set_timeout_functions(c, |
||||||
|
weston_dbus_add_timeout, |
||||||
|
weston_dbus_remove_timeout, |
||||||
|
weston_dbus_toggle_timeout, |
||||||
|
loop, |
||||||
|
NULL); |
||||||
|
if (!b) { |
||||||
|
r = -ENOMEM; |
||||||
|
goto error; |
||||||
|
} |
||||||
|
|
||||||
|
dbus_connection_ref(c); |
||||||
|
return 0; |
||||||
|
|
||||||
|
error: |
||||||
|
dbus_connection_set_timeout_functions(c, NULL, NULL, NULL, |
||||||
|
NULL, NULL); |
||||||
|
dbus_connection_set_watch_functions(c, NULL, NULL, NULL, |
||||||
|
NULL, NULL); |
||||||
|
wl_event_source_remove(*ctx_out); |
||||||
|
*ctx_out = NULL; |
||||||
|
return r; |
||||||
|
} |
||||||
|
|
||||||
|
static void weston_dbus_unbind(DBusConnection *c, struct wl_event_source *ctx) |
||||||
|
{ |
||||||
|
dbus_connection_set_timeout_functions(c, NULL, NULL, NULL, |
||||||
|
NULL, NULL); |
||||||
|
dbus_connection_set_watch_functions(c, NULL, NULL, NULL, |
||||||
|
NULL, NULL); |
||||||
|
dbus_connection_unref(c); |
||||||
|
wl_event_source_remove(ctx); |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Convenience Helpers |
||||||
|
* Several convenience helpers are provided to make using dbus in weston |
||||||
|
* easier. We don't use any of the gdbus or qdbus helpers as they pull in |
||||||
|
* huge dependencies and actually are quite awful to use. Instead, we only |
||||||
|
* use the basic low-level libdbus library. |
||||||
|
*/ |
||||||
|
|
||||||
|
int weston_dbus_open(struct wl_event_loop *loop, DBusBusType bus, |
||||||
|
DBusConnection **out, struct wl_event_source **ctx_out) |
||||||
|
{ |
||||||
|
DBusConnection *c; |
||||||
|
int r; |
||||||
|
|
||||||
|
/* Ihhh, global state.. stupid dbus. */ |
||||||
|
dbus_connection_set_change_sigpipe(FALSE); |
||||||
|
|
||||||
|
/* This is actually synchronous. It blocks for some authentication and
|
||||||
|
* setup. We just trust the dbus-server here and accept this blocking |
||||||
|
* call. There is no real reason to complicate things further and make |
||||||
|
* this asynchronous/non-blocking. A context should be created during |
||||||
|
* thead/process/app setup, so blocking calls should be fine. */ |
||||||
|
c = dbus_bus_get_private(bus, NULL); |
||||||
|
if (!c) |
||||||
|
return -EIO; |
||||||
|
|
||||||
|
dbus_connection_set_exit_on_disconnect(c, FALSE); |
||||||
|
|
||||||
|
r = weston_dbus_bind(loop, c, ctx_out); |
||||||
|
if (r < 0) |
||||||
|
goto error; |
||||||
|
|
||||||
|
*out = c; |
||||||
|
return r; |
||||||
|
|
||||||
|
error: |
||||||
|
dbus_connection_close(c); |
||||||
|
dbus_connection_unref(c); |
||||||
|
return r; |
||||||
|
} |
||||||
|
|
||||||
|
void weston_dbus_close(DBusConnection *c, struct wl_event_source *ctx) |
||||||
|
{ |
||||||
|
weston_dbus_unbind(c, ctx); |
||||||
|
dbus_connection_close(c); |
||||||
|
dbus_connection_unref(c); |
||||||
|
} |
@ -0,0 +1,67 @@ |
|||||||
|
/*
|
||||||
|
* Copyright © 2013 David Herrmann <dh.herrmann@gmail.com> |
||||||
|
* |
||||||
|
* Permission to use, copy, modify, distribute, and sell this software and |
||||||
|
* its documentation for any purpose is hereby granted without fee, provided |
||||||
|
* that the above copyright notice appear in all copies and that both that |
||||||
|
* copyright notice and this permission notice appear in supporting |
||||||
|
* documentation, and that the name of the copyright holders not be used in |
||||||
|
* advertising or publicity pertaining to distribution of the software |
||||||
|
* without specific, written prior permission. The copyright holders make |
||||||
|
* no representations about the suitability of this software for any |
||||||
|
* purpose. It is provided "as is" without express or implied warranty. |
||||||
|
* |
||||||
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS |
||||||
|
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
||||||
|
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||||
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER |
||||||
|
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF |
||||||
|
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef _WESTON_DBUS_H_ |
||||||
|
#define _WESTON_DBUS_H_ |
||||||
|
|
||||||
|
#include "config.h" |
||||||
|
|
||||||
|
#include <errno.h> |
||||||
|
#include <wayland-server.h> |
||||||
|
|
||||||
|
#include "compositor.h" |
||||||
|
|
||||||
|
#ifdef HAVE_DBUS |
||||||
|
|
||||||
|
#include <dbus/dbus.h> |
||||||
|
|
||||||
|
/*
|
||||||
|
* weston_dbus_open() - Open new dbus connection |
||||||
|
* |
||||||
|
* Opens a new dbus connection to the bus given as @bus. It automatically |
||||||
|
* integrates the new connection into the main-loop @loop. The connection |
||||||
|
* itself is returned in @out. |
||||||
|
* This also returns a context source used for dbus dispatching. It is |
||||||
|
* returned on success in @ctx_out and must be passed to weston_dbus_close() |
||||||
|
* unchanged. You must not access it from outside of a dbus helper! |
||||||
|
* |
||||||
|
* Returns 0 on success, negative error code on failure. |
||||||
|
*/ |
||||||
|
int weston_dbus_open(struct wl_event_loop *loop, DBusBusType bus, |
||||||
|
DBusConnection **out, struct wl_event_source **ctx_out); |
||||||
|
|
||||||
|
/*
|
||||||
|
* weston_dbus_close() - Close dbus connection |
||||||
|
* |
||||||
|
* Closes a dbus connection that was previously opened via weston_dbus_open(). |
||||||
|
* It unbinds the connection from the main-loop it was previously bound to, |
||||||
|
* closes the dbus connection and frees all resources. If you want to access |
||||||
|
* @c after this call returns, you must hold a dbus-reference to it. But |
||||||
|
* notice that the connection is closed after this returns so it cannot be |
||||||
|
* used to spawn new dbus requests. |
||||||
|
* You must pass the context source returns by weston_dbus_open() as @ctx. |
||||||
|
*/ |
||||||
|
void weston_dbus_close(DBusConnection *c, struct wl_event_source *ctx); |
||||||
|
|
||||||
|
#endif /* HAVE_DBUS */ |
||||||
|
|
||||||
|
#endif // _WESTON_DBUS_H_
|
Loading…
Reference in new issue