mirror of
https://github.com/yshui/picom.git
synced 2024-11-18 13:55:36 -05:00
b14e85a6bc
Per POSIX, "The c argument is an int, the value of which the application shall ensure is a character representable as an unsigned char or equal to the value of the macro EOF. If the argument has any other value, the behavior is undefined." https://pubs.opengroup.org/onlinepubs/009604499/functions/isspace.html Signed-off-by: Nia Alarie <nia@NetBSD.org>
1340 lines
38 KiB
C
1340 lines
38 KiB
C
// SPDX-License-Identifier: MIT
|
|
/*
|
|
* Compton - a compositor for X11
|
|
*
|
|
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
|
|
*
|
|
* Copyright (c) 2011-2013, Christopher Jeffrey
|
|
* See LICENSE-mit for more information.
|
|
*
|
|
*/
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <xcb/xcb.h>
|
|
|
|
#include "common.h"
|
|
#include "compiler.h"
|
|
#include "config.h"
|
|
#include "list.h"
|
|
#include "log.h"
|
|
#include "string_utils.h"
|
|
#include "types.h"
|
|
#include "uthash_extra.h"
|
|
#include "utils.h"
|
|
#include "win.h"
|
|
|
|
#include "dbus.h"
|
|
|
|
struct cdbus_data {
|
|
/// DBus connection.
|
|
DBusConnection *dbus_conn;
|
|
/// DBus service name.
|
|
char *dbus_service;
|
|
};
|
|
|
|
// Window type
|
|
typedef uint32_t cdbus_window_t;
|
|
#define CDBUS_TYPE_WINDOW DBUS_TYPE_UINT32
|
|
#define CDBUS_TYPE_WINDOW_STR DBUS_TYPE_UINT32_AS_STRING
|
|
|
|
typedef uint32_t cdbus_enum_t;
|
|
#define CDBUS_TYPE_ENUM DBUS_TYPE_UINT32
|
|
#define CDBUS_TYPE_ENUM_STR DBUS_TYPE_UINT32_AS_STRING
|
|
|
|
#define CDBUS_SERVICE_NAME "com.github.chjj.compton"
|
|
#define CDBUS_INTERFACE_NAME CDBUS_SERVICE_NAME
|
|
#define CDBUS_OBJECT_NAME "/com/github/chjj/compton"
|
|
#define CDBUS_ERROR_PREFIX CDBUS_INTERFACE_NAME ".error"
|
|
#define CDBUS_ERROR_UNKNOWN CDBUS_ERROR_PREFIX ".unknown"
|
|
#define CDBUS_ERROR_UNKNOWN_S "Well, I don't know what happened. Do you?"
|
|
#define CDBUS_ERROR_BADMSG CDBUS_ERROR_PREFIX ".bad_message"
|
|
#define CDBUS_ERROR_BADMSG_S \
|
|
"Unrecognized command. Beware compton " \
|
|
"cannot make you a sandwich."
|
|
#define CDBUS_ERROR_BADARG CDBUS_ERROR_PREFIX ".bad_argument"
|
|
#define CDBUS_ERROR_BADARG_S "Failed to parse argument %d: %s"
|
|
#define CDBUS_ERROR_BADWIN CDBUS_ERROR_PREFIX ".bad_window"
|
|
#define CDBUS_ERROR_BADWIN_S "Requested window %#010x not found."
|
|
#define CDBUS_ERROR_BADTGT CDBUS_ERROR_PREFIX ".bad_target"
|
|
#define CDBUS_ERROR_BADTGT_S "Target \"%s\" not found."
|
|
#define CDBUS_ERROR_FORBIDDEN CDBUS_ERROR_PREFIX ".forbidden"
|
|
#define CDBUS_ERROR_FORBIDDEN_S "Incorrect password, access denied."
|
|
#define CDBUS_ERROR_CUSTOM CDBUS_ERROR_PREFIX ".custom"
|
|
#define CDBUS_ERROR_CUSTOM_S "%s"
|
|
|
|
#define cdbus_reply_err(ps, srcmsg, err_name, err_format, ...) \
|
|
cdbus_reply_errm((ps), dbus_message_new_error_printf( \
|
|
(srcmsg), (err_name), (err_format), ##__VA_ARGS__))
|
|
|
|
static DBusHandlerResult cdbus_process(DBusConnection *conn, DBusMessage *m, void *);
|
|
|
|
static dbus_bool_t cdbus_callback_add_timeout(DBusTimeout *timeout, void *data);
|
|
|
|
static void cdbus_callback_remove_timeout(DBusTimeout *timeout, void *data);
|
|
|
|
static void cdbus_callback_timeout_toggled(DBusTimeout *timeout, void *data);
|
|
|
|
static dbus_bool_t cdbus_callback_add_watch(DBusWatch *watch, void *data);
|
|
|
|
static void cdbus_callback_remove_watch(DBusWatch *watch, void *data);
|
|
|
|
static void cdbus_callback_watch_toggled(DBusWatch *watch, void *data);
|
|
|
|
/**
|
|
* Initialize D-Bus connection.
|
|
*/
|
|
bool cdbus_init(session_t *ps, const char *uniq) {
|
|
auto cd = cmalloc(struct cdbus_data);
|
|
cd->dbus_service = NULL;
|
|
|
|
// Set ps->dbus_data here because add_watch functions need it
|
|
ps->dbus_data = cd;
|
|
|
|
DBusError err = {};
|
|
|
|
// Initialize
|
|
dbus_error_init(&err);
|
|
|
|
// Connect to D-Bus
|
|
// Use dbus_bus_get_private() so we can fully recycle it ourselves
|
|
cd->dbus_conn = dbus_bus_get_private(DBUS_BUS_SESSION, &err);
|
|
if (dbus_error_is_set(&err)) {
|
|
log_error("D-Bus connection failed (%s).", err.message);
|
|
dbus_error_free(&err);
|
|
goto fail;
|
|
}
|
|
|
|
if (!cd->dbus_conn) {
|
|
log_error("D-Bus connection failed for unknown reason.");
|
|
goto fail;
|
|
}
|
|
|
|
// Avoid exiting on disconnect
|
|
dbus_connection_set_exit_on_disconnect(cd->dbus_conn, false);
|
|
|
|
// Request service name
|
|
{
|
|
// Build service name
|
|
size_t service_len = strlen(CDBUS_SERVICE_NAME) + strlen(uniq) + 2;
|
|
char *service = ccalloc(service_len, char);
|
|
snprintf(service, service_len, "%s.%s", CDBUS_SERVICE_NAME, uniq);
|
|
|
|
// Make a valid dbus name by converting non alphanumeric characters to
|
|
// underscore
|
|
char *tmp = service + strlen(CDBUS_SERVICE_NAME) + 1;
|
|
while (*tmp) {
|
|
if (!isalnum((unsigned char)*tmp)) {
|
|
*tmp = '_';
|
|
}
|
|
tmp++;
|
|
}
|
|
cd->dbus_service = service;
|
|
|
|
// Request for the name
|
|
int ret = dbus_bus_request_name(cd->dbus_conn, service,
|
|
DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
|
|
|
|
if (dbus_error_is_set(&err)) {
|
|
log_error("Failed to obtain D-Bus name (%s).", err.message);
|
|
dbus_error_free(&err);
|
|
goto fail;
|
|
}
|
|
|
|
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret &&
|
|
DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER != ret) {
|
|
log_error("Failed to become the primary owner of requested D-Bus "
|
|
"name (%d).",
|
|
ret);
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
// Add watch handlers
|
|
if (!dbus_connection_set_watch_functions(cd->dbus_conn, cdbus_callback_add_watch,
|
|
cdbus_callback_remove_watch,
|
|
cdbus_callback_watch_toggled, ps, NULL)) {
|
|
log_error("Failed to add D-Bus watch functions.");
|
|
goto fail;
|
|
}
|
|
|
|
// Add timeout handlers
|
|
if (!dbus_connection_set_timeout_functions(
|
|
cd->dbus_conn, cdbus_callback_add_timeout, cdbus_callback_remove_timeout,
|
|
cdbus_callback_timeout_toggled, ps, NULL)) {
|
|
log_error("Failed to add D-Bus timeout functions.");
|
|
goto fail;
|
|
}
|
|
|
|
// Add match
|
|
dbus_bus_add_match(cd->dbus_conn,
|
|
"type='method_call',interface='" CDBUS_INTERFACE_NAME "'", &err);
|
|
if (dbus_error_is_set(&err)) {
|
|
log_error("Failed to add D-Bus match.");
|
|
dbus_error_free(&err);
|
|
goto fail;
|
|
}
|
|
dbus_connection_add_filter(cd->dbus_conn, cdbus_process, ps, NULL);
|
|
return true;
|
|
fail:
|
|
ps->dbus_data = NULL;
|
|
free(cd->dbus_service);
|
|
free(cd);
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Destroy D-Bus connection.
|
|
*/
|
|
void cdbus_destroy(session_t *ps) {
|
|
struct cdbus_data *cd = ps->dbus_data;
|
|
if (cd->dbus_conn) {
|
|
// Release DBus name firstly
|
|
if (cd->dbus_service) {
|
|
DBusError err = {};
|
|
dbus_error_init(&err);
|
|
|
|
dbus_bus_release_name(cd->dbus_conn, cd->dbus_service, &err);
|
|
if (dbus_error_is_set(&err)) {
|
|
log_error("Failed to release DBus name (%s).", err.message);
|
|
dbus_error_free(&err);
|
|
}
|
|
free(cd->dbus_service);
|
|
}
|
|
|
|
// Close and unref the connection
|
|
dbus_connection_close(cd->dbus_conn);
|
|
dbus_connection_unref(cd->dbus_conn);
|
|
}
|
|
free(cd);
|
|
}
|
|
|
|
/** @name DBusTimeout handling
|
|
*/
|
|
///@{
|
|
|
|
typedef struct ev_dbus_timer {
|
|
ev_timer w;
|
|
DBusTimeout *t;
|
|
} ev_dbus_timer;
|
|
|
|
/**
|
|
* Callback for handling a D-Bus timeout.
|
|
*/
|
|
static void
|
|
cdbus_callback_handle_timeout(EV_P attr_unused, ev_timer *w, int revents attr_unused) {
|
|
ev_dbus_timer *t = (void *)w;
|
|
dbus_timeout_handle(t->t);
|
|
}
|
|
|
|
/**
|
|
* Callback for adding D-Bus timeout.
|
|
*/
|
|
static dbus_bool_t cdbus_callback_add_timeout(DBusTimeout *timeout, void *data) {
|
|
session_t *ps = data;
|
|
|
|
auto t = ccalloc(1, ev_dbus_timer);
|
|
double i = dbus_timeout_get_interval(timeout) / 1000.0;
|
|
ev_timer_init(&t->w, cdbus_callback_handle_timeout, i, i);
|
|
t->t = timeout;
|
|
dbus_timeout_set_data(timeout, t, NULL);
|
|
|
|
if (dbus_timeout_get_enabled(timeout))
|
|
ev_timer_start(ps->loop, &t->w);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Callback for removing D-Bus timeout.
|
|
*/
|
|
static void cdbus_callback_remove_timeout(DBusTimeout *timeout, void *data) {
|
|
session_t *ps = data;
|
|
|
|
ev_dbus_timer *t = dbus_timeout_get_data(timeout);
|
|
assert(t);
|
|
ev_timer_stop(ps->loop, &t->w);
|
|
free(t);
|
|
}
|
|
|
|
/**
|
|
* Callback for toggling a D-Bus timeout.
|
|
*/
|
|
static void cdbus_callback_timeout_toggled(DBusTimeout *timeout, void *data) {
|
|
session_t *ps = data;
|
|
ev_dbus_timer *t = dbus_timeout_get_data(timeout);
|
|
|
|
assert(t);
|
|
ev_timer_stop(ps->loop, &t->w);
|
|
if (dbus_timeout_get_enabled(timeout)) {
|
|
double i = dbus_timeout_get_interval(timeout) / 1000.0;
|
|
ev_timer_set(&t->w, i, i);
|
|
ev_timer_start(ps->loop, &t->w);
|
|
}
|
|
}
|
|
|
|
///@}
|
|
|
|
/** @name DBusWatch handling
|
|
*/
|
|
///@{
|
|
|
|
typedef struct ev_dbus_io {
|
|
ev_io w;
|
|
struct cdbus_data *cd;
|
|
DBusWatch *dw;
|
|
} ev_dbus_io;
|
|
|
|
void cdbus_io_callback(EV_P attr_unused, ev_io *w, int revents) {
|
|
ev_dbus_io *dw = (void *)w;
|
|
DBusWatchFlags flags = 0;
|
|
if (revents & EV_READ)
|
|
flags |= DBUS_WATCH_READABLE;
|
|
if (revents & EV_WRITE)
|
|
flags |= DBUS_WATCH_WRITABLE;
|
|
dbus_watch_handle(dw->dw, flags);
|
|
while (dbus_connection_dispatch(dw->cd->dbus_conn) != DBUS_DISPATCH_COMPLETE)
|
|
;
|
|
}
|
|
|
|
/**
|
|
* Determine the poll condition of a DBusWatch.
|
|
*/
|
|
static inline int cdbus_get_watch_cond(DBusWatch *watch) {
|
|
const unsigned flags = dbus_watch_get_flags(watch);
|
|
int condition = 0;
|
|
if (flags & DBUS_WATCH_READABLE)
|
|
condition |= EV_READ;
|
|
if (flags & DBUS_WATCH_WRITABLE)
|
|
condition |= EV_WRITE;
|
|
|
|
return condition;
|
|
}
|
|
|
|
/**
|
|
* Callback for adding D-Bus watch.
|
|
*/
|
|
static dbus_bool_t cdbus_callback_add_watch(DBusWatch *watch, void *data) {
|
|
session_t *ps = data;
|
|
|
|
auto w = ccalloc(1, ev_dbus_io);
|
|
w->dw = watch;
|
|
w->cd = ps->dbus_data;
|
|
ev_io_init(&w->w, cdbus_io_callback, dbus_watch_get_unix_fd(watch),
|
|
cdbus_get_watch_cond(watch));
|
|
|
|
// Leave disabled watches alone
|
|
if (dbus_watch_get_enabled(watch))
|
|
ev_io_start(ps->loop, &w->w);
|
|
|
|
dbus_watch_set_data(watch, w, NULL);
|
|
|
|
// 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;
|
|
ev_dbus_io *w = dbus_watch_get_data(watch);
|
|
ev_io_stop(ps->loop, &w->w);
|
|
free(w);
|
|
}
|
|
|
|
/**
|
|
* Callback for toggling D-Bus watch status.
|
|
*/
|
|
static void cdbus_callback_watch_toggled(DBusWatch *watch, void *data) {
|
|
session_t *ps = data;
|
|
ev_io *w = dbus_watch_get_data(watch);
|
|
if (dbus_watch_get_enabled(watch))
|
|
ev_io_start(ps->loop, w);
|
|
else
|
|
ev_io_stop(ps->loop, w);
|
|
}
|
|
|
|
///@}
|
|
|
|
/** @name Message argument appending callbacks
|
|
*/
|
|
///@{
|
|
|
|
/**
|
|
* Callback to append a bool argument to a message.
|
|
*/
|
|
static bool cdbus_apdarg_bool(session_t *ps attr_unused, 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)) {
|
|
log_error("Failed to append argument.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Callback to append an int32 argument to a message.
|
|
*/
|
|
static bool cdbus_apdarg_int32(session_t *ps attr_unused, DBusMessage *msg, const void *data) {
|
|
if (!dbus_message_append_args(msg, DBUS_TYPE_INT32, data, DBUS_TYPE_INVALID)) {
|
|
log_error("Failed to append argument.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Callback to append an uint32 argument to a message.
|
|
*/
|
|
static bool
|
|
cdbus_apdarg_uint32(session_t *ps attr_unused, DBusMessage *msg, const void *data) {
|
|
if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, data, DBUS_TYPE_INVALID)) {
|
|
log_error("Failed to append argument.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Callback to append a double argument to a message.
|
|
*/
|
|
static bool
|
|
cdbus_apdarg_double(session_t *ps attr_unused, DBusMessage *msg, const void *data) {
|
|
if (!dbus_message_append_args(msg, DBUS_TYPE_DOUBLE, data, DBUS_TYPE_INVALID)) {
|
|
log_error("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 attr_unused, DBusMessage *msg, const void *data) {
|
|
assert(data);
|
|
cdbus_window_t val = *(const xcb_window_t *)data;
|
|
|
|
if (!dbus_message_append_args(msg, CDBUS_TYPE_WINDOW, &val, DBUS_TYPE_INVALID)) {
|
|
log_error("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 attr_unused, DBusMessage *msg, const void *data) {
|
|
assert(data);
|
|
if (!dbus_message_append_args(msg, CDBUS_TYPE_ENUM, data, DBUS_TYPE_INVALID)) {
|
|
log_error("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 attr_unused, 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)) {
|
|
log_error("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 attr_unused) {
|
|
// Get the number of wids we are to include
|
|
unsigned count = 0;
|
|
HASH_ITER2(ps->windows, w) {
|
|
assert(!w->destroyed);
|
|
++count;
|
|
}
|
|
|
|
if (!count) {
|
|
// Nothing to append
|
|
return true;
|
|
}
|
|
|
|
// Allocate memory for an array of window IDs
|
|
auto arr = ccalloc(count, cdbus_window_t);
|
|
|
|
// Build the array
|
|
cdbus_window_t *pcur = arr;
|
|
HASH_ITER2(ps->windows, w) {
|
|
assert(!w->destroyed);
|
|
*pcur = w->id;
|
|
++pcur;
|
|
}
|
|
assert(pcur == arr + count);
|
|
|
|
// Append arguments
|
|
if (!dbus_message_append_args(msg, DBUS_TYPE_ARRAY, CDBUS_TYPE_WINDOW, &arr,
|
|
count, DBUS_TYPE_INVALID)) {
|
|
log_error("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) {
|
|
struct cdbus_data *cd = ps->dbus_data;
|
|
DBusMessage *msg = NULL;
|
|
|
|
// Create a signal
|
|
msg = dbus_message_new_signal(CDBUS_OBJECT_NAME, CDBUS_INTERFACE_NAME, name);
|
|
if (!msg) {
|
|
log_error("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(cd->dbus_conn, msg, NULL)) {
|
|
log_error("Failed to send D-Bus signal.");
|
|
dbus_message_unref(msg);
|
|
return false;
|
|
}
|
|
dbus_connection_flush(cd->dbus_conn);
|
|
|
|
// Free the message
|
|
dbus_message_unref(msg);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Send a signal with a Window ID as argument.
|
|
*/
|
|
static inline bool cdbus_signal_wid(session_t *ps, const char *name, xcb_window_t wid) {
|
|
return cdbus_signal(ps, name, cdbus_apdarg_wid, &wid);
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
struct cdbus_data *cd = ps->dbus_data;
|
|
DBusMessage *msg = NULL;
|
|
|
|
// Create a reply
|
|
msg = dbus_message_new_method_return(srcmsg);
|
|
if (!msg) {
|
|
log_error("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(cd->dbus_conn, msg, NULL)) {
|
|
log_error("Failed to send D-Bus reply.");
|
|
dbus_message_unref(msg);
|
|
return false;
|
|
}
|
|
dbus_connection_flush(cd->dbus_conn);
|
|
|
|
// Free the message
|
|
dbus_message_unref(msg);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Send a reply with a bool argument.
|
|
*/
|
|
static inline bool cdbus_reply_bool(session_t *ps, DBusMessage *srcmsg, bool bval) {
|
|
return cdbus_reply(ps, srcmsg, cdbus_apdarg_bool, &bval);
|
|
}
|
|
|
|
/**
|
|
* Send a reply with an int32 argument.
|
|
*/
|
|
static inline bool cdbus_reply_int32(session_t *ps, DBusMessage *srcmsg, int32_t val) {
|
|
return cdbus_reply(ps, srcmsg, cdbus_apdarg_int32, &val);
|
|
}
|
|
|
|
/**
|
|
* Send a reply with an int32 argument, cast from a long.
|
|
*/
|
|
static inline bool cdbus_reply_int32l(session_t *ps, DBusMessage *srcmsg, long val) {
|
|
int32_t tmp = (int32_t)val;
|
|
return cdbus_reply(ps, srcmsg, cdbus_apdarg_int32, &tmp);
|
|
}
|
|
|
|
/**
|
|
* Send a reply with an uint32 argument.
|
|
*/
|
|
static inline bool cdbus_reply_uint32(session_t *ps, DBusMessage *srcmsg, uint32_t val) {
|
|
return cdbus_reply(ps, srcmsg, cdbus_apdarg_uint32, &val);
|
|
}
|
|
|
|
/**
|
|
* Send a reply with a double argument.
|
|
*/
|
|
static inline bool cdbus_reply_double(session_t *ps, DBusMessage *srcmsg, double val) {
|
|
return cdbus_reply(ps, srcmsg, cdbus_apdarg_double, &val);
|
|
}
|
|
|
|
/**
|
|
* Send a reply with a wid argument.
|
|
*/
|
|
static inline bool cdbus_reply_wid(session_t *ps, DBusMessage *srcmsg, xcb_window_t wid) {
|
|
return cdbus_reply(ps, srcmsg, cdbus_apdarg_wid, &wid);
|
|
}
|
|
|
|
/**
|
|
* Send a reply with a string argument.
|
|
*/
|
|
static inline bool cdbus_reply_string(session_t *ps, DBusMessage *srcmsg, const char *str) {
|
|
return cdbus_reply(ps, srcmsg, cdbus_apdarg_string, str);
|
|
}
|
|
|
|
/**
|
|
* Send a reply with a enum argument.
|
|
*/
|
|
static inline bool cdbus_reply_enum(session_t *ps, DBusMessage *srcmsg, cdbus_enum_t eval) {
|
|
return cdbus_reply(ps, srcmsg, cdbus_apdarg_enum, &eval);
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
struct cdbus_data *cd = ps->dbus_data;
|
|
if (!msg) {
|
|
log_error("Failed to create D-Bus reply.");
|
|
return false;
|
|
}
|
|
|
|
// Send the message and flush the connection
|
|
if (!dbus_connection_send(cd->dbus_conn, msg, NULL)) {
|
|
log_error("Failed to send D-Bus reply.");
|
|
dbus_message_unref(msg);
|
|
return false;
|
|
}
|
|
dbus_connection_flush(cd->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)) {
|
|
log_error("Message has no argument.");
|
|
return false;
|
|
}
|
|
|
|
{
|
|
const int oldcount = count;
|
|
while (count) {
|
|
if (!dbus_message_iter_next(&iter)) {
|
|
log_error("Failed to find argument %d.", oldcount);
|
|
return false;
|
|
}
|
|
--count;
|
|
}
|
|
}
|
|
|
|
if (type != dbus_message_iter_get_arg_type(&iter)) {
|
|
log_error("Argument has incorrect type.");
|
|
return false;
|
|
}
|
|
|
|
dbus_message_iter_get_basic(&iter, pdest);
|
|
|
|
return true;
|
|
}
|
|
|
|
/** @name Message processing
|
|
*/
|
|
///@{
|
|
|
|
/**
|
|
* 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 = XCB_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)) {
|
|
log_error("Failed to parse argument of \"win_get\" (%s).", err.message);
|
|
dbus_error_free(&err);
|
|
return false;
|
|
}
|
|
|
|
auto w = find_managed_win(ps, wid);
|
|
|
|
if (!w) {
|
|
log_error("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(#tgt, target)) { \
|
|
apdarg_func(ps, msg, w->tgt); \
|
|
return true; \
|
|
}
|
|
|
|
cdbus_m_win_get_do(base.id, cdbus_reply_wid);
|
|
|
|
// next
|
|
if (!strcmp("next", target)) {
|
|
cdbus_reply_wid(
|
|
ps, msg,
|
|
(list_node_is_last(&ps->window_stack, &w->base.stack_neighbour)
|
|
? 0
|
|
: list_entry(w->base.stack_neighbour.next, struct win, stack_neighbour)
|
|
->id));
|
|
return true;
|
|
}
|
|
|
|
// map_state
|
|
if (!strcmp("map_state", target)) {
|
|
cdbus_reply_bool(ps, msg, w->a.map_state);
|
|
return true;
|
|
}
|
|
|
|
cdbus_m_win_get_do(mode, cdbus_reply_enum);
|
|
cdbus_m_win_get_do(client_win, cdbus_reply_wid);
|
|
cdbus_m_win_get_do(ever_damaged, 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);
|
|
if (!strcmp("focused_raw", target)) {
|
|
cdbus_reply_bool(ps, msg, win_is_focused_raw(ps, w));
|
|
return true;
|
|
}
|
|
cdbus_m_win_get_do(fade_force, cdbus_reply_enum);
|
|
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);
|
|
cdbus_m_win_get_do(name, cdbus_reply_string);
|
|
cdbus_m_win_get_do(class_instance, cdbus_reply_string);
|
|
cdbus_m_win_get_do(class_general, cdbus_reply_string);
|
|
cdbus_m_win_get_do(role, cdbus_reply_string);
|
|
|
|
cdbus_m_win_get_do(opacity, cdbus_reply_double);
|
|
cdbus_m_win_get_do(opacity_target, cdbus_reply_double);
|
|
cdbus_m_win_get_do(has_opacity_prop, cdbus_reply_bool);
|
|
cdbus_m_win_get_do(opacity_prop, cdbus_reply_uint32);
|
|
cdbus_m_win_get_do(opacity_is_set, cdbus_reply_bool);
|
|
cdbus_m_win_get_do(opacity_set, cdbus_reply_double);
|
|
|
|
cdbus_m_win_get_do(frame_opacity, cdbus_reply_double);
|
|
if (!strcmp("left_width", target)) {
|
|
cdbus_reply_int32(ps, msg, w->frame_extents.left);
|
|
return true;
|
|
}
|
|
if (!strcmp("right_width", target)) {
|
|
cdbus_reply_int32(ps, msg, w->frame_extents.right);
|
|
return true;
|
|
}
|
|
if (!strcmp("top_width", target)) {
|
|
cdbus_reply_int32(ps, msg, w->frame_extents.top);
|
|
return true;
|
|
}
|
|
if (!strcmp("bottom_width", target)) {
|
|
cdbus_reply_int32(ps, msg, w->frame_extents.bottom);
|
|
return true;
|
|
}
|
|
|
|
cdbus_m_win_get_do(shadow, cdbus_reply_bool);
|
|
cdbus_m_win_get_do(invert_color, cdbus_reply_bool);
|
|
cdbus_m_win_get_do(blur_background, cdbus_reply_bool);
|
|
#undef cdbus_m_win_get_do
|
|
|
|
log_error(CDBUS_ERROR_BADTGT_S, target);
|
|
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Process a win_set D-Bus request.
|
|
*/
|
|
static bool cdbus_process_win_set(session_t *ps, DBusMessage *msg) {
|
|
cdbus_window_t wid = XCB_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)) {
|
|
log_error("(): Failed to parse argument of \"win_set\" (%s).", err.message);
|
|
dbus_error_free(&err);
|
|
return false;
|
|
}
|
|
|
|
auto w = find_managed_win(ps, wid);
|
|
|
|
if (!w) {
|
|
log_error("Window %#010x not found.", wid);
|
|
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADWIN, CDBUS_ERROR_BADWIN_S, wid);
|
|
return 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("fade_force", target)) {
|
|
cdbus_enum_t val = UNSET;
|
|
if (!cdbus_msg_get_arg(msg, 2, CDBUS_TYPE_ENUM, &val))
|
|
return false;
|
|
win_set_fade_force(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
|
|
|
|
log_error(CDBUS_ERROR_BADTGT_S, target);
|
|
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);
|
|
|
|
return true;
|
|
|
|
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;
|
|
|
|
xcb_window_t wid = XCB_NONE;
|
|
|
|
// Find window by client window
|
|
if (!strcmp("client", target)) {
|
|
cdbus_window_t client = XCB_NONE;
|
|
if (!cdbus_msg_get_arg(msg, 1, CDBUS_TYPE_WINDOW, &client))
|
|
return false;
|
|
auto w = find_toplevel(ps, client);
|
|
if (w) {
|
|
wid = w->base.id;
|
|
}
|
|
}
|
|
// Find focused window
|
|
else if (!strcmp("focused", target)) {
|
|
if (ps->active_win && ps->active_win->state != WSTATE_UNMAPPED) {
|
|
wid = ps->active_win->base.id;
|
|
}
|
|
} else {
|
|
log_error(CDBUS_ERROR_BADTGT_S, target);
|
|
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);
|
|
|
|
return true;
|
|
}
|
|
|
|
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(#tgt, target)) { \
|
|
apdarg_func(ps, msg, ps->o.tgt); \
|
|
return true; \
|
|
}
|
|
|
|
#define cdbus_m_opts_get_stub(tgt, apdarg_func, ret) \
|
|
if (!strcmp(#tgt, target)) { \
|
|
apdarg_func(ps, msg, ret); \
|
|
return true; \
|
|
}
|
|
|
|
// version
|
|
if (!strcmp("version", target)) {
|
|
cdbus_reply_string(ps, msg, COMPTON_VERSION);
|
|
return true;
|
|
}
|
|
|
|
// pid
|
|
if (!strcmp("pid", target)) {
|
|
cdbus_reply_int32(ps, msg, getpid());
|
|
return true;
|
|
}
|
|
|
|
// display
|
|
if (!strcmp("display", target)) {
|
|
cdbus_reply_string(ps, msg, DisplayString(ps->dpy));
|
|
return true;
|
|
}
|
|
|
|
cdbus_m_opts_get_stub(config_file, cdbus_reply_string, "Unknown");
|
|
cdbus_m_opts_get_do(write_pid_path, 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(detect_rounded_corners, cdbus_reply_bool);
|
|
cdbus_m_opts_get_stub(paint_on_overlay, cdbus_reply_bool, ps->overlay != XCB_NONE);
|
|
// paint_on_overlay_id: Get ID of the X composite overlay window
|
|
if (!strcmp("paint_on_overlay_id", target)) {
|
|
cdbus_reply_uint32(ps, msg, ps->overlay);
|
|
return true;
|
|
}
|
|
cdbus_m_opts_get_do(unredir_if_possible, cdbus_reply_bool);
|
|
cdbus_m_opts_get_do(unredir_if_possible_delay, cdbus_reply_int32l);
|
|
cdbus_m_opts_get_do(redirected_force, cdbus_reply_enum);
|
|
cdbus_m_opts_get_do(stoppaint_force, cdbus_reply_enum);
|
|
cdbus_m_opts_get_do(logpath, cdbus_reply_string);
|
|
|
|
cdbus_m_opts_get_do(refresh_rate, cdbus_reply_int32);
|
|
cdbus_m_opts_get_do(sw_opti, cdbus_reply_bool);
|
|
cdbus_m_opts_get_do(vsync, cdbus_reply_bool);
|
|
if (!strcmp("backend", target)) {
|
|
assert(ps->o.backend < sizeof(BACKEND_STRS) / sizeof(BACKEND_STRS[0]));
|
|
cdbus_reply_string(ps, msg, BACKEND_STRS[ps->o.backend]);
|
|
return true;
|
|
}
|
|
|
|
cdbus_m_opts_get_do(shadow_red, cdbus_reply_double);
|
|
cdbus_m_opts_get_do(shadow_green, cdbus_reply_double);
|
|
cdbus_m_opts_get_do(shadow_blue, cdbus_reply_double);
|
|
cdbus_m_opts_get_do(shadow_radius, cdbus_reply_int32);
|
|
cdbus_m_opts_get_do(shadow_offset_x, cdbus_reply_int32);
|
|
cdbus_m_opts_get_do(shadow_offset_y, cdbus_reply_int32);
|
|
cdbus_m_opts_get_do(shadow_opacity, cdbus_reply_double);
|
|
cdbus_m_opts_get_do(xinerama_shadow_crop, cdbus_reply_bool);
|
|
|
|
cdbus_m_opts_get_do(fade_delta, cdbus_reply_int32);
|
|
cdbus_m_opts_get_do(fade_in_step, cdbus_reply_double);
|
|
cdbus_m_opts_get_do(fade_out_step, cdbus_reply_double);
|
|
cdbus_m_opts_get_do(no_fading_openclose, cdbus_reply_bool);
|
|
|
|
cdbus_m_opts_get_do(blur_method, cdbus_reply_bool);
|
|
cdbus_m_opts_get_do(blur_background_frame, cdbus_reply_bool);
|
|
cdbus_m_opts_get_do(blur_background_fixed, cdbus_reply_bool);
|
|
|
|
cdbus_m_opts_get_do(inactive_dim, cdbus_reply_double);
|
|
cdbus_m_opts_get_do(inactive_dim_fixed, cdbus_reply_bool);
|
|
|
|
cdbus_m_opts_get_do(max_brightness, cdbus_reply_double);
|
|
|
|
cdbus_m_opts_get_do(use_ewmh_active_win, cdbus_reply_bool);
|
|
cdbus_m_opts_get_do(detect_transient, cdbus_reply_bool);
|
|
cdbus_m_opts_get_do(detect_client_leader, cdbus_reply_bool);
|
|
cdbus_m_opts_get_do(use_damage, cdbus_reply_bool);
|
|
|
|
#ifdef CONFIG_OPENGL
|
|
cdbus_m_opts_get_do(glx_no_stencil, cdbus_reply_bool);
|
|
cdbus_m_opts_get_do(glx_no_rebind_pixmap, cdbus_reply_bool);
|
|
#endif
|
|
|
|
#undef cdbus_m_opts_get_do
|
|
#undef cdbus_m_opts_get_stub
|
|
|
|
log_error(CDBUS_ERROR_BADTGT_S, target);
|
|
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);
|
|
|
|
return true;
|
|
}
|
|
|
|
// XXX Remove this after header clean up
|
|
void queue_redraw(session_t *ps);
|
|
|
|
/**
|
|
* 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(#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; \
|
|
}
|
|
|
|
// fade_delta
|
|
if (!strcmp("fade_delta", target)) {
|
|
int32_t val = 0;
|
|
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_INT32, &val)) {
|
|
return false;
|
|
}
|
|
if (val <= 0) {
|
|
return false;
|
|
}
|
|
ps->o.fade_delta = max2(val, 1);
|
|
goto cdbus_process_opts_set_success;
|
|
}
|
|
|
|
// fade_in_step
|
|
if (!strcmp("fade_in_step", target)) {
|
|
double val = 0.0;
|
|
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val))
|
|
return false;
|
|
ps->o.fade_in_step = normalize_d(val);
|
|
goto cdbus_process_opts_set_success;
|
|
}
|
|
|
|
// fade_out_step
|
|
if (!strcmp("fade_out_step", target)) {
|
|
double val = 0.0;
|
|
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_DOUBLE, &val))
|
|
return false;
|
|
ps->o.fade_out_step = normalize_d(val);
|
|
goto cdbus_process_opts_set_success;
|
|
}
|
|
|
|
// no_fading_openclose
|
|
if (!strcmp("no_fading_openclose", target)) {
|
|
dbus_bool_t val = FALSE;
|
|
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_BOOLEAN, &val))
|
|
return false;
|
|
opts_set_no_fading_openclose(ps, 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;
|
|
queue_redraw(ps);
|
|
}
|
|
goto cdbus_process_opts_set_success;
|
|
}
|
|
|
|
// clear_shadow
|
|
if (!strcmp("clear_shadow", target)) {
|
|
goto cdbus_process_opts_set_success;
|
|
}
|
|
|
|
// track_focus
|
|
if (!strcmp("track_focus", target)) {
|
|
goto cdbus_process_opts_set_success;
|
|
}
|
|
|
|
// redirected_force
|
|
if (!strcmp("redirected_force", target)) {
|
|
cdbus_enum_t val = UNSET;
|
|
if (!cdbus_msg_get_arg(msg, 1, CDBUS_TYPE_ENUM, &val))
|
|
return false;
|
|
ps->o.redirected_force = val;
|
|
force_repaint(ps);
|
|
goto cdbus_process_opts_set_success;
|
|
}
|
|
|
|
// stoppaint_force
|
|
cdbus_m_opts_set_do(stoppaint_force, CDBUS_TYPE_ENUM, cdbus_enum_t);
|
|
|
|
#undef cdbus_m_opts_set_do
|
|
|
|
log_error(CDBUS_ERROR_BADTGT_S, target);
|
|
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);
|
|
|
|
return true;
|
|
|
|
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) {
|
|
static const 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='org.freedesktop.DBus.Introspectable'>\n"
|
|
" <method name='Introspect'>\n"
|
|
" <arg name='data' direction='out' type='s' />\n"
|
|
" </method>\n"
|
|
" </interface>\n"
|
|
" <interface name='org.freedesktop.DBus.Peer'>\n"
|
|
" <method name='Ping' />\n"
|
|
" <method name='GetMachineId'>\n"
|
|
" <arg name='machine_uuid' direction='out' type='s' />\n"
|
|
" </method>\n"
|
|
" </interface>\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"
|
|
" <signal name='win_focusin'>\n"
|
|
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
|
|
" </signal>\n"
|
|
" <signal name='win_focusout'>\n"
|
|
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
|
|
" </signal>\n"
|
|
" <method name='reset' />\n"
|
|
" <method name='repaint' />\n"
|
|
" </interface>\n"
|
|
"</node>\n";
|
|
|
|
cdbus_reply_string(ps, msg, str_introspect);
|
|
|
|
return true;
|
|
}
|
|
///@}
|
|
|
|
/**
|
|
* Process a message from D-Bus.
|
|
*/
|
|
static DBusHandlerResult
|
|
cdbus_process(DBusConnection *c attr_unused, DBusMessage *msg, void *ud) {
|
|
session_t *ps = ud;
|
|
bool handled = false;
|
|
|
|
#define cdbus_m_ismethod(method) \
|
|
dbus_message_is_method_call(msg, CDBUS_INTERFACE_NAME, method)
|
|
|
|
if (cdbus_m_ismethod("reset")) {
|
|
log_info("picom is resetting...");
|
|
ev_break(ps->loop, EVBREAK_ALL);
|
|
if (!dbus_message_get_no_reply(msg))
|
|
cdbus_reply_bool(ps, msg, true);
|
|
handled = true;
|
|
} else if (cdbus_m_ismethod("repaint")) {
|
|
force_repaint(ps);
|
|
if (!dbus_message_get_no_reply(msg))
|
|
cdbus_reply_bool(ps, msg, true);
|
|
handled = true;
|
|
} else if (cdbus_m_ismethod("list_win")) {
|
|
handled = cdbus_process_list_win(ps, msg);
|
|
} else if (cdbus_m_ismethod("win_get")) {
|
|
handled = cdbus_process_win_get(ps, msg);
|
|
} else if (cdbus_m_ismethod("win_set")) {
|
|
handled = cdbus_process_win_set(ps, msg);
|
|
} else if (cdbus_m_ismethod("find_win")) {
|
|
handled = cdbus_process_find_win(ps, msg);
|
|
} else if (cdbus_m_ismethod("opts_get")) {
|
|
handled = cdbus_process_opts_get(ps, msg);
|
|
} else if (cdbus_m_ismethod("opts_set")) {
|
|
handled = cdbus_process_opts_set(ps, msg);
|
|
}
|
|
#undef cdbus_m_ismethod
|
|
else if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Introspectable",
|
|
"Introspect")) {
|
|
handled = cdbus_process_introspect(ps, msg);
|
|
} else if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Peer", "Ping")) {
|
|
cdbus_reply(ps, msg, NULL, NULL);
|
|
handled = true;
|
|
} else if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Peer",
|
|
"GetMachineId")) {
|
|
char *uuid = dbus_get_local_machine_id();
|
|
if (uuid) {
|
|
cdbus_reply_string(ps, msg, uuid);
|
|
dbus_free(uuid);
|
|
handled = true;
|
|
}
|
|
} else if (dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameAcquired") ||
|
|
dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameLost")) {
|
|
handled = true;
|
|
} else {
|
|
if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(msg)) {
|
|
log_error(
|
|
"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 {
|
|
log_error("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);
|
|
handled = true;
|
|
}
|
|
|
|
// If the message could not be processed, and an reply is expected, return
|
|
// an empty reply.
|
|
if (!handled && 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);
|
|
handled = true;
|
|
}
|
|
|
|
return handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
}
|
|
|
|
/** @name Core callbacks
|
|
*/
|
|
///@{
|
|
void cdbus_ev_win_added(session_t *ps, struct win *w) {
|
|
struct cdbus_data *cd = ps->dbus_data;
|
|
if (cd->dbus_conn)
|
|
cdbus_signal_wid(ps, "win_added", w->id);
|
|
}
|
|
|
|
void cdbus_ev_win_destroyed(session_t *ps, struct win *w) {
|
|
struct cdbus_data *cd = ps->dbus_data;
|
|
if (cd->dbus_conn)
|
|
cdbus_signal_wid(ps, "win_destroyed", w->id);
|
|
}
|
|
|
|
void cdbus_ev_win_mapped(session_t *ps, struct win *w) {
|
|
struct cdbus_data *cd = ps->dbus_data;
|
|
if (cd->dbus_conn)
|
|
cdbus_signal_wid(ps, "win_mapped", w->id);
|
|
}
|
|
|
|
void cdbus_ev_win_unmapped(session_t *ps, struct win *w) {
|
|
struct cdbus_data *cd = ps->dbus_data;
|
|
if (cd->dbus_conn)
|
|
cdbus_signal_wid(ps, "win_unmapped", w->id);
|
|
}
|
|
|
|
void cdbus_ev_win_focusout(session_t *ps, struct win *w) {
|
|
struct cdbus_data *cd = ps->dbus_data;
|
|
if (cd->dbus_conn)
|
|
cdbus_signal_wid(ps, "win_focusout", w->id);
|
|
}
|
|
|
|
void cdbus_ev_win_focusin(session_t *ps, struct win *w) {
|
|
struct cdbus_data *cd = ps->dbus_data;
|
|
if (cd->dbus_conn)
|
|
cdbus_signal_wid(ps, "win_focusin", w->id);
|
|
}
|
|
//!@}
|