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