Feature #80: D-Bus support

- Add D-Bus support. Currently 7 methods are available: "reset" (same as
  SIGUSR1), "list_win" (list the windows compton manages), "win_get"
  (get a property of the window), "win_set" (set a property of the
  window), "find_win" (find window based on client window / focus),
  "opts_get" (get the value of a compton option), and "opts_set" (set
  the value of a compton option), together with 4 signals: "win_added",
  "win_destroyed", "win_mapped", "win_unmapped".

- D-Bus support depends on libdbus.

- As there are many items and my time is tight, no much tests are done.
  Bugs to be expected.

- Create a new header file `common.h` that contains shared content.

- Fix some bugs in timeout handling.

- Update file headers in all source files.

- Re-enable --unredir-if-possible on multi-screen set-ups, as the user
  could turn if off manually anyway.

- Check if the window is mapped in `repair_win()`.

- Add ps->track_atom_lst and its handlers, to prepare for the new
  condition format.

- Known issue 1: "win_get", "win_set", "opts_get", "opts_set" support a
  very limited number of targets only. New ones will be added gradually.

- Known issue 2: Accidental drop of D-Bus connection is not handled.

- Known issue 3: Introspection does not reveal all available methods,
  because some methods have unpredictable prototypes. Still hesitating
  about what to do...

- Known issue 4: Error handling is not finished yet. Compton does not
  always reply with the correct error message (but it does print out the
  correct error message, usually).
This commit is contained in:
Richard Grenville
2013-01-19 20:20:27 +08:00
parent e60fe72dcb
commit 58c0ecec40
8 changed files with 2715 additions and 1280 deletions

920
src/dbus.c Normal file
View File

@ -0,0 +1,920 @@
/*
* Compton - a compositor for X11
*
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
*
* Copyright (c) 2011-2013, Christopher Jeffrey
* See LICENSE for more information.
*
*/
#include "dbus.h"
/**
* Initialize D-Bus connection.
*/
bool
cdbus_init(session_t *ps) {
DBusError err = { };
// Initialize
dbus_error_init(&err);
// Connect to D-Bus
// Use dbus_bus_get_private() so we can fully recycle it ourselves
ps->dbus_conn = dbus_bus_get_private(DBUS_BUS_SESSION, &err);
if (dbus_error_is_set(&err)) {
printf_errf("(): D-Bus connection failed (%s).", err.message);
dbus_error_free(&err);
return false;
}
if (!ps->dbus_conn) {
printf_errf("(): D-Bus connection failed for unknown reason.");
return false;
}
// Avoid exiting on disconnect
dbus_connection_set_exit_on_disconnect(ps->dbus_conn, false);
// Request service name
{
// Get display name
char *display = DisplayString(ps->dpy);
if (!display)
display = "unknown";
display = mstrcpy(display);
// Convert all special characters in display name to underscore
{
char *pdisp = display;
while (*pdisp) {
if (!isalnum(*pdisp))
*pdisp = '_';
++pdisp;
}
}
// Build service name
char *service = mstrjoin3(CDBUS_SERVICE_NAME, ".", display);
ps->dbus_service = service;
free(display);
display = NULL;
// Request for the name
int ret = dbus_bus_request_name(ps->dbus_conn, service,
DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
if (dbus_error_is_set(&err)) {
printf_errf("(): Failed to obtain D-Bus name (%s).", err.message);
dbus_error_free(&err);
}
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret
&& DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER != ret) {
printf_errf("(): Failed to become the primary owner of requested "
"D-Bus name (%d).", ret);
}
}
// Add watch handlers
if (!dbus_connection_set_watch_functions(ps->dbus_conn,
cdbus_callback_add_watch, cdbus_callback_remove_watch,
cdbus_callback_watch_toggled, ps, NULL)) {
printf_errf("(): Failed to add D-Bus watch functions.");
return false;
}
// Add timeout handlers
if (!dbus_connection_set_timeout_functions(ps->dbus_conn,
cdbus_callback_add_timeout, cdbus_callback_remove_timeout,
cdbus_callback_timeout_toggled, ps, NULL)) {
printf_errf("(): Failed to add D-Bus timeout functions.");
return false;
}
// Add match
dbus_bus_add_match(ps->dbus_conn,
"type='method_call',interface='" CDBUS_INTERFACE_NAME "'", &err);
if (dbus_error_is_set(&err)) {
printf_errf("(): Failed to add D-Bus match.");
dbus_error_free(&err);
return false;
}
return true;
}
/**
* Destroy D-Bus connection.
*/
void
cdbus_destroy(session_t *ps) {
if (ps->dbus_conn) {
// Release DBus name firstly
if (ps->dbus_service) {
DBusError err = { };
dbus_error_init(&err);
dbus_bus_release_name(ps->dbus_conn, ps->dbus_service, &err);
if (dbus_error_is_set(&err)) {
printf_errf("(): Failed to release DBus name (%s).",
err.message);
dbus_error_free(&err);
}
}
// Close and unref the connection
dbus_connection_close(ps->dbus_conn);
dbus_connection_unref(ps->dbus_conn);
}
}
/** @name DBusTimeout handling
*/
///@{
/**
* Callback for adding D-Bus timeout.
*/
static dbus_bool_t
cdbus_callback_add_timeout(DBusTimeout *timeout, void *data) {
session_t *ps = data;
timeout_t *ptmout = timeout_insert(ps, dbus_timeout_get_interval(timeout),
cdbus_callback_handle_timeout, timeout);
if (ptmout)
dbus_timeout_set_data(timeout, ptmout, NULL);
return (bool) ptmout;
}
/**
* Callback for removing D-Bus timeout.
*/
static void
cdbus_callback_remove_timeout(DBusTimeout *timeout, void *data) {
session_t *ps = data;
timeout_t *ptmout = dbus_timeout_get_data(timeout);
assert(ptmout);
if (ptmout)
timeout_drop(ps, ptmout);
}
/**
* Callback for toggling a D-Bus timeout.
*/
static void
cdbus_callback_timeout_toggled(DBusTimeout *timeout, void *data) {
timeout_t *ptmout = dbus_timeout_get_data(timeout);
assert(ptmout);
if (ptmout) {
ptmout->enabled = dbus_timeout_get_enabled(timeout);
// Refresh interval as libdbus doc says: "Whenever a timeout is toggled,
// its interval may change."
ptmout->interval = dbus_timeout_get_interval(timeout);
}
}
/**
* Callback for handling a D-Bus timeout.
*/
static bool
cdbus_callback_handle_timeout(session_t *ps, timeout_t *ptmout) {
assert(ptmout && ptmout->data);
if (ptmout && ptmout->data)
return dbus_timeout_handle(ptmout->data);
return false;
}
///@}
/** @name DBusWatch handling
*/
///@{
/**
* Callback for adding D-Bus watch.
*/
static dbus_bool_t
cdbus_callback_add_watch(DBusWatch *watch, void *data) {
// Leave disabled watches alone
if (!dbus_watch_get_enabled(watch))
return TRUE;
session_t *ps = data;
// Insert the file descriptor
fds_insert(ps, dbus_watch_get_unix_fd(watch),
cdbus_get_watch_cond(watch));
// Always return true
return TRUE;
}
/**
* Callback for removing D-Bus watch.
*/
static void
cdbus_callback_remove_watch(DBusWatch *watch, void *data) {
session_t *ps = data;
fds_drop(ps, dbus_watch_get_unix_fd(watch),
cdbus_get_watch_cond(watch));
}
/**
* Callback for toggling D-Bus watch status.
*/
static void
cdbus_callback_watch_toggled(DBusWatch *watch, void *data) {
if (dbus_watch_get_enabled(watch)) {
cdbus_callback_add_watch(watch, data);
}
else {
cdbus_callback_remove_watch(watch, data);
}
}
///@}
/** @name Message argument appending callbacks
*/
///@{
/**
* Callback to append a bool argument to a message.
*/
static bool
cdbus_apdarg_bool(session_t *ps, DBusMessage *msg, const void *data) {
assert(data);
dbus_bool_t val = *(const bool *) data;
if (!dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &val,
DBUS_TYPE_INVALID)) {
printf_errf("(): Failed to append argument.");
return false;
}
return true;
}
/**
* Callback to append a Window argument to a message.
*/
static bool
cdbus_apdarg_wid(session_t *ps, DBusMessage *msg, const void *data) {
assert(data);
cdbus_window_t val = *(const Window *)data;
if (!dbus_message_append_args(msg, CDBUS_TYPE_WINDOW, &val,
DBUS_TYPE_INVALID)) {
printf_errf("(): Failed to append argument.");
return false;
}
return true;
}
/**
* Callback to append an cdbus_enum_t argument to a message.
*/
static bool
cdbus_apdarg_enum(session_t *ps, DBusMessage *msg, const void *data) {
assert(data);
if (!dbus_message_append_args(msg, CDBUS_TYPE_ENUM, data,
DBUS_TYPE_INVALID)) {
printf_errf("(): Failed to append argument.");
return false;
}
return true;
}
/**
* Callback to append a string argument to a message.
*/
static bool
cdbus_apdarg_string(session_t *ps, DBusMessage *msg, const void *data) {
const char *str = data;
if (!str)
str = "";
if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &str,
DBUS_TYPE_INVALID)) {
printf_errf("(): Failed to append argument.");
return false;
}
return true;
}
/**
* Callback to append all window IDs to a message.
*/
static bool
cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data) {
// Get the number of wids we are to include
unsigned count = 0;
for (win *w = ps->list; w; w = w->next) {
if (!w->destroyed)
++count;
}
// Allocate memory for an array of window IDs
cdbus_window_t *arr = malloc(sizeof(cdbus_window_t) * count);
if (!arr) {
printf_errf("(): Failed to allocate memory for window ID array.");
return false;
}
// Build the array
{
cdbus_window_t *pcur = arr;
for (win *w = ps->list; w; w = w->next) {
if (!w->destroyed) {
*pcur = w->id;
++pcur;
assert(pcur <= arr + count);
}
}
assert(pcur == arr + count);
}
// Append arguments
if (!dbus_message_append_args(msg, DBUS_TYPE_ARRAY, CDBUS_TYPE_WINDOW,
&arr, count, DBUS_TYPE_INVALID)) {
printf_errf("(): Failed to append argument.");
free(arr);
return false;
}
free(arr);
return true;
}
///@}
/**
* Send a D-Bus signal.
*
* @param ps current session
* @param name signal name
* @param func a function that modifies the built message, to, for example,
* add an argument
* @param data data pointer to pass to the function
*/
static bool
cdbus_signal(session_t *ps, const char *name,
bool (*func)(session_t *ps, DBusMessage *msg, const void *data),
const void *data) {
DBusMessage* msg = NULL;
// Create a signal
msg = dbus_message_new_signal(CDBUS_OBJECT_NAME, CDBUS_INTERFACE_NAME,
name);
if (!msg) {
printf_errf("(): Failed to create D-Bus signal.");
return false;
}
// Append arguments onto message
if (func && !func(ps, msg, data)) {
dbus_message_unref(msg);
return false;
}
// Send the message and flush the connection
if (!dbus_connection_send(ps->dbus_conn, msg, NULL)) {
printf_errf("(): Failed to send D-Bus signal.");
dbus_message_unref(msg);
return false;
}
dbus_connection_flush(ps->dbus_conn);
// Free the message
dbus_message_unref(msg);
return true;
}
/**
* Send a D-Bus reply.
*
* @param ps current session
* @param srcmsg original message
* @param func a function that modifies the built message, to, for example,
* add an argument
* @param data data pointer to pass to the function
*/
static bool
cdbus_reply(session_t *ps, DBusMessage *srcmsg,
bool (*func)(session_t *ps, DBusMessage *msg, const void *data),
const void *data) {
DBusMessage* msg = NULL;
// Create a reply
msg = dbus_message_new_method_return(srcmsg);
if (!msg) {
printf_errf("(): Failed to create D-Bus reply.");
return false;
}
// Append arguments onto message
if (func && !func(ps, msg, data)) {
dbus_message_unref(msg);
return false;
}
// Send the message and flush the connection
if (!dbus_connection_send(ps->dbus_conn, msg, NULL)) {
printf_errf("(): Failed to send D-Bus reply.");
dbus_message_unref(msg);
return false;
}
dbus_connection_flush(ps->dbus_conn);
// Free the message
dbus_message_unref(msg);
return true;
}
/**
* Send a D-Bus error reply.
*
* @param ps current session
* @param msg the new error DBusMessage
*/
static bool
cdbus_reply_errm(session_t *ps, DBusMessage *msg) {
if (!msg) {
printf_errf("(): Failed to create D-Bus reply.");
return false;
}
// Send the message and flush the connection
if (!dbus_connection_send(ps->dbus_conn, msg, NULL)) {
printf_errf("(): Failed to send D-Bus reply.");
dbus_message_unref(msg);
return false;
}
dbus_connection_flush(ps->dbus_conn);
// Free the message
dbus_message_unref(msg);
return true;
}
/**
* Get n-th argument of a D-Bus message.
*
* @param count the position of the argument to get, starting from 0
* @param type libdbus type number of the type
* @param pdest pointer to the target
* @return true if successful, false otherwise.
*/
static bool
cdbus_msg_get_arg(DBusMessage *msg, int count, const int type, void *pdest) {
assert(count >= 0);
DBusMessageIter iter = { };
if (!dbus_message_iter_init(msg, &iter)) {
printf_errf("(): Message has no argument.");
return false;
}
{
const int oldcount = count;
while (count) {
if (!dbus_message_iter_next(&iter)) {
printf_errf("(): Failed to find argument %d.", oldcount);
return false;
}
--count;
}
}
if (type != dbus_message_iter_get_arg_type(&iter)) {
printf_errf("(): Argument has incorrect type.");
return false;
}
dbus_message_iter_get_basic(&iter, pdest);
return true;
}
void
cdbus_loop(session_t *ps) {
dbus_connection_read_write(ps->dbus_conn, 0);
DBusMessage *msg = NULL;
while ((msg = dbus_connection_pop_message(ps->dbus_conn)))
cdbus_process(ps, msg);
}
/** @name Message processing
*/
///@{
/**
* Process a message from D-Bus.
*/
static void
cdbus_process(session_t *ps, DBusMessage *msg) {
bool success = false;
#define cdbus_m_ismethod(method) \
dbus_message_is_method_call(msg, CDBUS_INTERFACE_NAME, method)
if (cdbus_m_ismethod("reset")) {
ps->reset = true;
if (!dbus_message_get_no_reply(msg))
cdbus_reply_bool(ps, msg, true);
success = true;
}
else if (cdbus_m_ismethod("list_win")) {
success = cdbus_process_list_win(ps, msg);
}
else if (cdbus_m_ismethod("win_get")) {
success = cdbus_process_win_get(ps, msg);
}
else if (cdbus_m_ismethod("win_set")) {
success = cdbus_process_win_set(ps, msg);
}
else if (cdbus_m_ismethod("find_win")) {
success = cdbus_process_find_win(ps, msg);
}
else if (cdbus_m_ismethod("opts_get")) {
success = cdbus_process_opts_get(ps, msg);
}
else if (cdbus_m_ismethod("opts_set")) {
success = cdbus_process_opts_set(ps, msg);
}
#undef cdbus_m_ismethod
else if (dbus_message_is_method_call(msg,
"org.freedesktop.DBus.Introspectable", "Introspect")) {
success = cdbus_process_introspect(ps, msg);
}
else if (dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameAcquired")
|| dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameLost")) {
success = true;
}
else {
if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(msg)) {
printf_errf("(): Error message of path \"%s\" "
"interface \"%s\", member \"%s\", error \"%s\"",
dbus_message_get_path(msg), dbus_message_get_interface(msg),
dbus_message_get_member(msg), dbus_message_get_error_name(msg));
}
else {
printf_errf("(): Illegal message of type \"%s\", path \"%s\" "
"interface \"%s\", member \"%s\"",
cdbus_repr_msgtype(msg), dbus_message_get_path(msg),
dbus_message_get_interface(msg), dbus_message_get_member(msg));
}
if (DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg)
&& !dbus_message_get_no_reply(msg))
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADMSG, CDBUS_ERROR_BADMSG_S);
success = true;
}
// If the message could not be processed, and an reply is expected, return
// an empty reply.
if (!success && DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg)
&& !dbus_message_get_no_reply(msg))
cdbus_reply_err(ps, msg, CDBUS_ERROR_UNKNOWN, CDBUS_ERROR_UNKNOWN_S);
// Free the message
dbus_message_unref(msg);
}
/**
* Process a list_win D-Bus request.
*/
static bool
cdbus_process_list_win(session_t *ps, DBusMessage *msg) {
cdbus_reply(ps, msg, cdbus_apdarg_wids, NULL);
return true;
}
/**
* Process a win_get D-Bus request.
*/
static bool
cdbus_process_win_get(session_t *ps, DBusMessage *msg) {
cdbus_window_t wid = None;
const char *target = NULL;
DBusError err = { };
if (!dbus_message_get_args(msg, &err,
CDBUS_TYPE_WINDOW, &wid,
DBUS_TYPE_STRING, &target,
DBUS_TYPE_INVALID)) {
printf_errf("(): Failed to parse argument of \"win_get\" (%s).",
err.message);
dbus_error_free(&err);
return false;
}
win *w = find_win(ps, wid);
if (!w) {
printf_errf("(): Window %#010x not found.", wid);
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADWIN, CDBUS_ERROR_BADWIN_S, wid);
return true;
}
#define cdbus_m_win_get_do(tgt, apdarg_func) \
if (!strcmp(MSTR(tgt), target)) { \
apdarg_func(ps, msg, w->tgt); \
return true; \
}
cdbus_m_win_get_do(client_win, cdbus_reply_wid);
cdbus_m_win_get_do(damaged, cdbus_reply_bool);
cdbus_m_win_get_do(destroyed, cdbus_reply_bool);
cdbus_m_win_get_do(window_type, cdbus_reply_enum);
cdbus_m_win_get_do(wmwin, cdbus_reply_bool);
cdbus_m_win_get_do(leader, cdbus_reply_wid);
cdbus_m_win_get_do(focused_real, cdbus_reply_bool);
cdbus_m_win_get_do(shadow_force, cdbus_reply_enum);
cdbus_m_win_get_do(focused_force, cdbus_reply_enum);
cdbus_m_win_get_do(invert_color_force, cdbus_reply_enum);
if (!strcmp("map_state", target)) {
cdbus_reply_bool(ps, msg, w->a.map_state);
return true;
}
#undef cdbus_m_win_get_do
printf_errf("(): No matching target found.");
return false;
}
/**
* Process a win_set D-Bus request.
*/
static bool
cdbus_process_win_set(session_t *ps, DBusMessage *msg) {
cdbus_window_t wid = None;
const char *target = NULL;
DBusError err = { };
if (!dbus_message_get_args(msg, &err,
CDBUS_TYPE_WINDOW, &wid,
DBUS_TYPE_STRING, &target,
DBUS_TYPE_INVALID)) {
printf_errf("(): Failed to parse argument of \"win_set\" (%s).",
err.message);
dbus_error_free(&err);
return false;
}
win *w = find_win(ps, wid);
if (!w) {
printf_errf("(): Window %#010x not found.", wid);
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADWIN, CDBUS_ERROR_BADWIN_S, wid);
return true;
}
ps->ev_received = true;
#define cdbus_m_win_set_do(tgt, type, real_type) \
if (!strcmp(MSTR(tgt), target)) { \
real_type val; \
if (!cdbus_msg_get_arg(msg, 2, type, &val)) \
return false; \
w->tgt = val; \
goto cdbus_process_win_set_success; \
}
if (!strcmp("shadow_force", target)) {
cdbus_enum_t val = UNSET;
if (!cdbus_msg_get_arg(msg, 2, CDBUS_TYPE_ENUM, &val))
return false;
win_set_shadow_force(ps, w, val);
goto cdbus_process_win_set_success;
}
if (!strcmp("focused_force", target)) {
cdbus_enum_t val = UNSET;
if (!cdbus_msg_get_arg(msg, 2, CDBUS_TYPE_ENUM, &val))
return false;
win_set_focused_force(ps, w, val);
goto cdbus_process_win_set_success;
}
if (!strcmp("invert_color_force", target)) {
cdbus_enum_t val = UNSET;
if (!cdbus_msg_get_arg(msg, 2, CDBUS_TYPE_ENUM, &val))
return false;
win_set_invert_color_force(ps, w, val);
goto cdbus_process_win_set_success;
}
#undef cdbus_m_win_set_do
printf_errf("(): No matching target found.");
return false;
cdbus_process_win_set_success:
if (!dbus_message_get_no_reply(msg))
cdbus_reply_bool(ps, msg, true);
return true;
}
/**
* Process a find_win D-Bus request.
*/
static bool
cdbus_process_find_win(session_t *ps, DBusMessage *msg) {
const char *target = NULL;
if (!cdbus_msg_get_arg(msg, 0, DBUS_TYPE_STRING, &target))
return false;
Window wid = None;
// Find window by client window
if (!strcmp("client", target)) {
cdbus_window_t client = None;
if (!cdbus_msg_get_arg(msg, 1, CDBUS_TYPE_WINDOW, &client))
return false;
win *w = find_toplevel(ps, client);
if (w)
wid = w->id;
}
// Find focused window
else if (!strcmp("focused", target)) {
win *w = find_focused(ps);
if (w)
wid = w->id;
}
else {
printf_errf("(): No matching target found.");
return false;
}
cdbus_reply_wid(ps, msg, wid);
return true;
}
/**
* Process a opts_get D-Bus request.
*/
static bool
cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
const char *target = NULL;
if (!cdbus_msg_get_arg(msg, 0, DBUS_TYPE_STRING, &target))
return false;
#define cdbus_m_opts_get_do(tgt, apdarg_func) \
if (!strcmp(MSTR(tgt), target)) { \
apdarg_func(ps, msg, ps->o.tgt); \
return true; \
}
cdbus_m_opts_get_do(display, cdbus_reply_string);
cdbus_m_opts_get_do(mark_wmwin_focused, cdbus_reply_bool);
cdbus_m_opts_get_do(mark_ovredir_focused, cdbus_reply_bool);
cdbus_m_opts_get_do(fork_after_register, cdbus_reply_bool);
cdbus_m_opts_get_do(detect_rounded_corners, cdbus_reply_bool);
cdbus_m_opts_get_do(paint_on_overlay, cdbus_reply_bool);
cdbus_m_opts_get_do(unredir_if_possible, cdbus_reply_bool);
cdbus_m_opts_get_do(logpath, cdbus_reply_string);
cdbus_m_opts_get_do(synchronize, cdbus_reply_bool);
cdbus_m_opts_get_do(clear_shadow, cdbus_reply_bool);
#undef cdbus_m_opts_get_do
printf_errf("(): No matching target found.");
return false;
}
/**
* Process a opts_set D-Bus request.
*/
static bool
cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
const char *target = NULL;
if (!cdbus_msg_get_arg(msg, 0, DBUS_TYPE_STRING, &target))
return false;
#define cdbus_m_opts_set_do(tgt, type, real_type) \
if (!strcmp(MSTR(tgt), target)) { \
real_type val; \
if (!cdbus_msg_get_arg(msg, 1, type, &val)) \
return false; \
ps->o.tgt = val; \
goto cdbus_process_opts_set_success; \
}
// unredir_if_possible
if (!strcmp("unredir_if_possible", target)) {
dbus_bool_t val = FALSE;
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_BOOLEAN, &val))
return false;
if (ps->o.unredir_if_possible != val) {
ps->o.unredir_if_possible = val;
ps->ev_received = true;
}
goto cdbus_process_opts_set_success;
}
// clear_shadow
if (!strcmp("clear_shadow", target)) {
dbus_bool_t val = FALSE;
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_BOOLEAN, &val))
return false;
if (ps->o.clear_shadow != val) {
ps->o.clear_shadow = val;
force_repaint(ps);
}
goto cdbus_process_opts_set_success;
}
#undef cdbus_m_opts_set_do
printf_errf("(): No matching target found.");
return false;
cdbus_process_opts_set_success:
if (!dbus_message_get_no_reply(msg))
cdbus_reply_bool(ps, msg, true);
return true;
}
/**
* Process an Introspect D-Bus request.
*/
static bool
cdbus_process_introspect(session_t *ps, DBusMessage *msg) {
const static char *str_introspect =
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
" \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
"<node name='" CDBUS_OBJECT_NAME "'>\n"
" <interface name='" CDBUS_INTERFACE_NAME "'>\n"
" <signal name='win_added'>\n"
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
" </signal>\n"
" <signal name='win_destroyed'>\n"
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
" </signal>\n"
" <signal name='win_mapped'>\n"
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
" </signal>\n"
" <signal name='win_unmapped'>\n"
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
" </signal>\n"
" <method name='reset' />\n"
" </interface>\n"
"</node>\n";
cdbus_reply_string(ps, msg, str_introspect);
return true;
}
///@}
/** @name Core callbacks
*/
///@{
void
cdbus_ev_win_added(session_t *ps, win *w) {
if (ps->dbus_conn)
cdbus_signal_wid(ps, "win_added", w->id);
}
void
cdbus_ev_win_destroyed(session_t *ps, win *w) {
if (ps->dbus_conn)
cdbus_signal_wid(ps, "win_destroyed", w->id);
}
void
cdbus_ev_win_mapped(session_t *ps, win *w) {
if (ps->dbus_conn)
cdbus_signal_wid(ps, "win_mapped", w->id);
}
void
cdbus_ev_win_unmapped(session_t *ps, win *w) {
if (ps->dbus_conn)
cdbus_signal_wid(ps, "win_unmapped", w->id);
}
//!@}