there are two x extensions for working with monitors (especially multiple): xinerama and randr. xinerama is old, feature-poor and in general isn't used anymore compared to the randr: new, feature-rich and widely-used. for some reason we were using both of them, so let's drop xinerama to keep things simple, clean and small. and to be modern. the drop was done in three steps: * first step was to replace all the xinerama-based code with the randr-based one and to replace or remove all the xinerama mentions; * second step was to replace the xinerama's terminology with the randr's one. xinerama was referring only to the word "screen", while randr refers to multiple words and i think the word "monitor" is the most suitable for us and, hopefully, clear both to a contributor and to an end user; * third step was to refactor the new randr-based code if needed and to address related todo's (mostly about moving related functions elsewhere). all the steps were done well except addressing a leftover todo about moving the win_update_monitor function to the x.c which wasn't done. the xinerama-shadow-crop option was renamed to crop-shadow-to-monitor, but it's previous name is still accepted, has effect and the deprecation message is printed to preserve backwards-compatibility.
1704 lines
50 KiB
C
1704 lines
50 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__))
|
|
|
|
#define PICOM_WINDOW_INTERFACE "picom.Window"
|
|
#define PICOM_COMPOSITOR_INTERFACE "picom.Compositor"
|
|
|
|
static DBusHandlerResult cdbus_process(DBusConnection *conn, DBusMessage *m, void *);
|
|
static DBusHandlerResult cdbus_process_windows(DBusConnection *c, DBusMessage *msg, void *ud);
|
|
|
|
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_register_object_path(
|
|
cd->dbus_conn, CDBUS_OBJECT_NAME,
|
|
(DBusObjectPathVTable[]){{NULL, cdbus_process}}, ps);
|
|
dbus_connection_register_fallback(
|
|
cd->dbus_conn, CDBUS_OBJECT_NAME "/windows",
|
|
(DBusObjectPathVTable[]){{NULL, cdbus_process_windows}}, ps);
|
|
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 a Window argument to a message as a variant.
|
|
*/
|
|
static bool
|
|
cdbus_append_wid_variant(session_t *ps attr_unused, DBusMessage *msg, const void *data) {
|
|
assert(data);
|
|
cdbus_window_t val = *(const xcb_window_t *)data;
|
|
|
|
DBusMessageIter it, it2;
|
|
dbus_message_iter_init_append(msg, &it);
|
|
if (!dbus_message_iter_open_container(&it, DBUS_TYPE_VARIANT,
|
|
CDBUS_TYPE_WINDOW_STR, &it2)) {
|
|
return false;
|
|
}
|
|
if (!dbus_message_iter_append_basic(&it2, CDBUS_TYPE_WINDOW, &val)) {
|
|
log_error("Failed to append argument.");
|
|
return false;
|
|
}
|
|
if (!dbus_message_iter_close_container(&it, &it2)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Callback to append a bool argument to a message as a variant.
|
|
*/
|
|
static bool
|
|
cdbus_append_bool_variant(session_t *ps attr_unused, DBusMessage *msg, const void *data) {
|
|
assert(data);
|
|
|
|
dbus_bool_t val = *(const bool *)data;
|
|
DBusMessageIter it, it2;
|
|
dbus_message_iter_init_append(msg, &it);
|
|
if (!dbus_message_iter_open_container(&it, DBUS_TYPE_VARIANT,
|
|
DBUS_TYPE_BOOLEAN_AS_STRING, &it2)) {
|
|
return false;
|
|
}
|
|
if (!dbus_message_iter_append_basic(&it2, DBUS_TYPE_BOOLEAN, &val)) {
|
|
log_error("Failed to append argument.");
|
|
return false;
|
|
}
|
|
if (!dbus_message_iter_close_container(&it, &it2)) {
|
|
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 a string argument to a message as a variant.
|
|
*/
|
|
static bool
|
|
cdbus_append_string_variant(session_t *ps attr_unused, DBusMessage *msg, const void *data) {
|
|
const char *str = *(const char **)data;
|
|
if (!str) {
|
|
str = "";
|
|
}
|
|
|
|
DBusMessageIter it, it2;
|
|
dbus_message_iter_init_append(msg, &it);
|
|
if (!dbus_message_iter_open_container(&it, DBUS_TYPE_VARIANT,
|
|
DBUS_TYPE_STRING_AS_STRING, &it2)) {
|
|
return false;
|
|
}
|
|
if (!dbus_message_iter_append_basic(&it2, DBUS_TYPE_STRING, &str)) {
|
|
log_error("Failed to append argument.");
|
|
return false;
|
|
}
|
|
if (!dbus_message_iter_close_container(&it, &it2)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool cdbus_append_empty_dict(session_t *ps attr_unused, DBusMessage *msg,
|
|
const void *data attr_unused) {
|
|
DBusMessageIter it, it2;
|
|
dbus_message_iter_init_append(msg, &it);
|
|
if (!dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "{sv}", &it2)) {
|
|
return false;
|
|
}
|
|
if (!dbus_message_iter_close_container(&it, &it2)) {
|
|
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 *interface, 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, interface, 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 *interface, const char *name, xcb_window_t wid) {
|
|
return cdbus_signal(ps, interface, 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_window_property_get(session_t *ps, DBusMessage *msg, cdbus_window_t wid) {
|
|
const char *target = NULL;
|
|
const char *interface = NULL;
|
|
DBusError err = {};
|
|
|
|
if (!dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &interface,
|
|
DBUS_TYPE_STRING, &target, DBUS_TYPE_INVALID)) {
|
|
log_error("Failed to parse argument of \"Get\" (%s).", err.message);
|
|
dbus_error_free(&err);
|
|
return false;
|
|
}
|
|
|
|
if (strcmp(interface, PICOM_WINDOW_INTERFACE)) {
|
|
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, member, apdarg_func) \
|
|
if (!strcmp(#tgt, target)) { \
|
|
cdbus_reply(ps, msg, apdarg_func, &w->member); \
|
|
return true; \
|
|
}
|
|
|
|
if (!strcmp("Mapped", target)) {
|
|
cdbus_reply(ps, msg, cdbus_append_bool_variant,
|
|
(bool[]){win_is_mapped_in_x(w)});
|
|
return true;
|
|
}
|
|
|
|
if (!strcmp(target, "Id")) {
|
|
cdbus_reply(ps, msg, cdbus_append_wid_variant, &w->base.id);
|
|
return true;
|
|
}
|
|
|
|
// next
|
|
if (!strcmp("Next", target)) {
|
|
cdbus_window_t next_id = 0;
|
|
if (!list_node_is_last(&ps->window_stack, &w->base.stack_neighbour)) {
|
|
next_id = list_entry(w->base.stack_neighbour.next, struct win,
|
|
stack_neighbour)
|
|
->id;
|
|
}
|
|
cdbus_reply(ps, msg, cdbus_append_wid_variant, &next_id);
|
|
return true;
|
|
}
|
|
|
|
cdbus_m_win_get_do(ClientWin, client_win, cdbus_append_wid_variant);
|
|
cdbus_m_win_get_do(Leader, leader, cdbus_append_wid_variant);
|
|
cdbus_m_win_get_do(Name, name, cdbus_append_string_variant);
|
|
if (!strcmp("Type", target)) {
|
|
cdbus_reply(ps, msg, cdbus_append_string_variant, &WINTYPES[w->window_type]);
|
|
return true;
|
|
}
|
|
if (!strcmp("RawFocused", target)) {
|
|
cdbus_reply(ps, msg, cdbus_append_bool_variant,
|
|
(bool[]){win_is_focused_raw(ps, w)});
|
|
return true;
|
|
}
|
|
|
|
#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_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; \
|
|
}
|
|
|
|
if (!strcmp(target, "id")) {
|
|
cdbus_reply_wid(ps, msg, w->base.id);
|
|
return true;
|
|
}
|
|
|
|
// 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, PICOM_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_stub(refresh_rate, cdbus_reply_int32, 0);
|
|
cdbus_m_opts_get_stub(sw_opti, cdbus_reply_bool, false);
|
|
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(crop_shadow_to_monitor, 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"
|
|
" <interface name='" PICOM_COMPOSITOR_INTERFACE "'>\n"
|
|
" <signal name='WinAdded'>\n"
|
|
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
|
|
" </signal>\n"
|
|
" <signal name='WinDestroyed'>\n"
|
|
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
|
|
" </signal>\n"
|
|
" <signal name='WinMapped'>\n"
|
|
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
|
|
" </signal>\n"
|
|
" <signal name='WinUnmapped'>\n"
|
|
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
|
|
" </signal>\n"
|
|
" </interface>\n"
|
|
" <node name='windows' />\n"
|
|
"</node>\n";
|
|
|
|
cdbus_reply_string(ps, msg, str_introspect);
|
|
|
|
return true;
|
|
}
|
|
///@}
|
|
|
|
/**
|
|
* Process an D-Bus Introspect request, for /windows.
|
|
*/
|
|
static bool cdbus_process_windows_root_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>\n"
|
|
" <interface name='org.freedesktop.DBus.Introspectable'>\n"
|
|
" <method name='Introspect'>\n"
|
|
" <arg name='data' direction='out' type='s' />\n"
|
|
" </method>\n"
|
|
" </interface>\n";
|
|
|
|
char *ret = NULL;
|
|
mstrextend(&ret, str_introspect);
|
|
|
|
HASH_ITER2(ps->windows, w) {
|
|
assert(!w->destroyed);
|
|
if (!w->managed) {
|
|
continue;
|
|
}
|
|
char *tmp = NULL;
|
|
if (asprintf(&tmp, "<node name='%#010x'/>\n", w->id) < 0) {
|
|
log_fatal("Failed to allocate memory.");
|
|
abort();
|
|
}
|
|
mstrextend(&ret, tmp);
|
|
free(tmp);
|
|
}
|
|
mstrextend(&ret, "</node>");
|
|
|
|
bool success = cdbus_reply_string(ps, msg, ret);
|
|
free(ret);
|
|
return success;
|
|
}
|
|
|
|
static bool cdbus_process_window_introspect(session_t *ps, DBusMessage *msg) {
|
|
// clang-format off
|
|
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>\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.Properties'>\n"
|
|
" <method name='Get'>\n"
|
|
" <arg type='s' name='interface_name' direction='in'/>\n"
|
|
" <arg type='s' name='property_name' direction='in'/>\n"
|
|
" <arg type='v' name='value' direction='out'/>\n"
|
|
" </method>\n"
|
|
" <method name='GetAll'>\n"
|
|
" <arg type='s' name='interface_name' direction='in'/>\n"
|
|
" <arg type='a{sv}' name='properties' direction='out'/>\n"
|
|
" </method>\n"
|
|
" <method name='Set'>\n"
|
|
" <arg type='s' name='interface_name' direction='in'/>\n"
|
|
" <arg type='s' name='property_name' direction='in'/>\n"
|
|
" <arg type='v' name='value' direction='in'/>\n"
|
|
" </method>\n"
|
|
" <signal name='PropertiesChanged'>\n"
|
|
" <arg type='s' name='interface_name'/>\n"
|
|
" <arg type='a{sv}' name='changed_properties'/>\n"
|
|
" <arg type='as' name='invalidated_properties'/>\n"
|
|
" </signal>\n"
|
|
" </interface>\n"
|
|
" <interface name='" PICOM_WINDOW_INTERFACE "'>\n"
|
|
" <property type='" CDBUS_TYPE_WINDOW_STR "' name='Leader' access='read'/>\n"
|
|
" <property type='" CDBUS_TYPE_WINDOW_STR "' name='ClientWin' access='read'/>\n"
|
|
" <property type='" CDBUS_TYPE_WINDOW_STR "' name='Id' access='read'/>\n"
|
|
" <property type='" CDBUS_TYPE_WINDOW_STR "' name='Next' access='read'/>\n"
|
|
" <property type='b' name='RawFocused' access='read'/>\n"
|
|
" <property type='b' name='Mapped' access='read'/>\n"
|
|
" <property type='s' name='Name' access='read'/>\n"
|
|
" <property type='s' name='Type' access='read'/>\n"
|
|
" </interface>\n"
|
|
"</node>\n";
|
|
// clang-format on
|
|
|
|
return cdbus_reply_string(ps, msg, str_introspect);
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* Process a message from D-Bus, for /windows path.
|
|
*/
|
|
static DBusHandlerResult
|
|
cdbus_process_windows(DBusConnection *c attr_unused, DBusMessage *msg, void *ud) {
|
|
session_t *ps = ud;
|
|
bool handled = false;
|
|
const char *path = dbus_message_get_path(msg);
|
|
const char *last_segment = strrchr(path, '/');
|
|
if (last_segment == NULL) {
|
|
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);
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
}
|
|
bool is_root = strncmp(last_segment, "/windows", 8) == 0;
|
|
if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Introspectable",
|
|
"Introspect")) {
|
|
if (is_root) {
|
|
handled = cdbus_process_windows_root_introspect(ps, msg);
|
|
} else {
|
|
handled = cdbus_process_window_introspect(ps, msg);
|
|
}
|
|
goto finished;
|
|
}
|
|
|
|
if (!is_root) {
|
|
auto wid = (cdbus_window_t)strtol(last_segment + 1, NULL, 0);
|
|
if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Properties",
|
|
"GetAll")) {
|
|
handled = cdbus_reply(ps, msg, cdbus_append_empty_dict, NULL);
|
|
goto finished;
|
|
}
|
|
|
|
if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Properties", "Get")) {
|
|
handled = cdbus_process_window_property_get(ps, msg, wid);
|
|
goto finished;
|
|
}
|
|
}
|
|
|
|
if (dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameAcquired") ||
|
|
dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameLost")) {
|
|
return DBUS_HANDLER_RESULT_HANDLED;
|
|
}
|
|
|
|
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)) {
|
|
handled = cdbus_reply_err(ps, msg, CDBUS_ERROR_BADMSG, CDBUS_ERROR_BADMSG_S);
|
|
}
|
|
|
|
finished:
|
|
if (!handled && dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL &&
|
|
!dbus_message_get_no_reply(msg)) {
|
|
handled =
|
|
cdbus_reply_err(ps, msg, CDBUS_ERROR_UNKNOWN, CDBUS_ERROR_UNKNOWN_S);
|
|
}
|
|
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, CDBUS_INTERFACE_NAME, "win_added", w->id);
|
|
cdbus_signal_wid(ps, PICOM_COMPOSITOR_INTERFACE, "WinAdded", 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, CDBUS_INTERFACE_NAME, "win_destroyed", w->id);
|
|
cdbus_signal_wid(ps, PICOM_COMPOSITOR_INTERFACE, "WinDestroyed", 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, CDBUS_INTERFACE_NAME, "win_mapped", w->id);
|
|
cdbus_signal_wid(ps, PICOM_COMPOSITOR_INTERFACE, "WinMapped", 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, CDBUS_INTERFACE_NAME, "win_unmapped", w->id);
|
|
cdbus_signal_wid(ps, PICOM_COMPOSITOR_INTERFACE, "WinUnmapped", 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, CDBUS_INTERFACE_NAME, "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, CDBUS_INTERFACE_NAME, "win_focusin", w->id);
|
|
}
|
|
}
|
|
//!@}
|