Feature #80: D-Bus support
- Add D-Bus support. Currently 7 methods are available: "reset" (same as SIGUSR1), "list_win" (list the windows compton manages), "win_get" (get a property of the window), "win_set" (set a property of the window), "find_win" (find window based on client window / focus), "opts_get" (get the value of a compton option), and "opts_set" (set the value of a compton option), together with 4 signals: "win_added", "win_destroyed", "win_mapped", "win_unmapped". - D-Bus support depends on libdbus. - As there are many items and my time is tight, no much tests are done. Bugs to be expected. - Create a new header file `common.h` that contains shared content. - Fix some bugs in timeout handling. - Update file headers in all source files. - Re-enable --unredir-if-possible on multi-screen set-ups, as the user could turn if off manually anyway. - Check if the window is mapped in `repair_win()`. - Add ps->track_atom_lst and its handlers, to prepare for the new condition format. - Known issue 1: "win_get", "win_set", "opts_get", "opts_set" support a very limited number of targets only. New ones will be added gradually. - Known issue 2: Accidental drop of D-Bus connection is not handled. - Known issue 3: Introspection does not reveal all available methods, because some methods have unpredictable prototypes. Still hesitating about what to do... - Known issue 4: Error handling is not finished yet. Compton does not always reply with the correct error message (but it does print out the correct error message, usually).
This commit is contained in:
parent
e60fe72dcb
commit
58c0ecec40
14
Makefile
14
Makefile
|
@ -11,6 +11,8 @@ PACKAGES = x11 xcomposite xfixes xdamage xrender xext xrandr
|
|||
LIBS = -lm -lrt
|
||||
INCS =
|
||||
|
||||
OBJS = compton.o
|
||||
|
||||
# === Configuration flags ===
|
||||
CFG =
|
||||
|
||||
|
@ -46,10 +48,11 @@ ifeq "$(NO_VSYNC_OPENGL)" ""
|
|||
endif
|
||||
|
||||
# ==== D-Bus ====
|
||||
# ifeq "$(NO_DBUS)" ""
|
||||
# CFG += -DCONFIG_DBUS
|
||||
# PACKAGES += dbus-1
|
||||
# endif
|
||||
ifeq "$(NO_DBUS)" ""
|
||||
CFG += -DCONFIG_DBUS
|
||||
PACKAGES += dbus-1
|
||||
OBJS += dbus.o
|
||||
endif
|
||||
|
||||
# === Version string ===
|
||||
COMPTON_VERSION ?= git-$(shell git describe --always --dirty)-$(shell git log -1 --date=short --pretty=format:%cd)
|
||||
|
@ -63,14 +66,13 @@ LIBS += $(shell pkg-config --libs $(PACKAGES))
|
|||
INCS += $(shell pkg-config --cflags $(PACKAGES))
|
||||
|
||||
CFLAGS += -Wall -std=c99
|
||||
OBJS = compton.o
|
||||
MANPAGES = man/compton.1 man/compton-trans.1
|
||||
MANPAGES_HTML = $(addsuffix .html,$(MANPAGES))
|
||||
|
||||
# === Recipes ===
|
||||
.DEFAULT_GOAL := compton
|
||||
|
||||
%.o: src/%.c src/%.h
|
||||
%.o: src/%.c src/%.h src/common.h
|
||||
$(CC) $(CFLAGS) $(INCS) -c src/$*.c
|
||||
|
||||
compton: $(OBJS)
|
||||
|
|
22
README.md
22
README.md
|
@ -11,17 +11,18 @@ partially doing this out of a desire to learn Xlib.
|
|||
|
||||
## Changes from xcompmgr:
|
||||
|
||||
* __inactive window transparency__ (specified with `-i`)
|
||||
* __inactive window transparency / dimming__
|
||||
* __titlebar/frame transparency__ (specified with `-e`)
|
||||
* menu transparency (thanks to Dana)
|
||||
* shadows are now enabled for argb windows, e.g. terminals with transparency
|
||||
* removed serverside shadows (and simple compositing) to clean the code,
|
||||
the only option that remains is clientside shadows
|
||||
* configuration files (specified with `--config`)
|
||||
* colored shadows (with `--shadow-[red/green/blue] value`)
|
||||
* configuration files (see the man page for more details)
|
||||
* colored shadows (`--shadow-[red/green/blue]`)
|
||||
* a new fade system
|
||||
* vsync (still under development)
|
||||
* several more options
|
||||
* VSync support (not always working)
|
||||
* Blur of background of transparent windows, window color inversion (bad in performance)
|
||||
* Some more options...
|
||||
|
||||
## Fixes from the original xcompmgr:
|
||||
|
||||
|
@ -51,10 +52,11 @@ __R__ for runtime
|
|||
* xproto / x11proto (B)
|
||||
* bash (R)
|
||||
* xprop,xwininfo / x11-utils (R)
|
||||
* libpcre (B,R) (Will probably be made optional soon)
|
||||
* libconfig (B,R) (Will probably be made optional soon)
|
||||
* libdrm (B) (Will probably be made optional soon)
|
||||
* libGL (B,R) (Will probably be made optional soon)
|
||||
* libpcre (B,R) (Can be disabled with `NO_REGEX_PCRE` at compile time)
|
||||
* libconfig (B,R) (Can be disabled with `NO_LIBCONFIG` at compile time)
|
||||
* libdrm (B) (Can be disabled with `NO_VSYNC_DRM` at compile time)
|
||||
* libGL (B,R) (Can be disabled with `NO_VSYNC_OPENGL` at compile time)
|
||||
* libdbus (B,R) (Can be disabled with `NO_DBUS` at compile time)
|
||||
* asciidoc (B)
|
||||
|
||||
### How to build
|
||||
|
@ -64,7 +66,7 @@ To build, make sure you have the dependencies above:
|
|||
``` bash
|
||||
# Make the main program
|
||||
$ make
|
||||
# Make the newer man pages
|
||||
# Make the man pages
|
||||
$ make docs
|
||||
# Install
|
||||
$ make install
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
#!/bin/sh
|
||||
|
||||
# === Get connection parameters ===
|
||||
|
||||
dpy=$(echo -n "$DISPLAY" | tr -c '[:alnum:]' _)
|
||||
|
||||
if [ -z "$dpy" ]; then
|
||||
echo "Cannot find display."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
service="com.github.chjj.compton.${dpy}"
|
||||
interface='com.github.chjj.compton'
|
||||
object='/com/github/chjj/compton'
|
||||
type_win='uint32'
|
||||
type_enum='uint16'
|
||||
|
||||
# === DBus methods ===
|
||||
|
||||
# List all window ID compton manages (except destroyed ones)
|
||||
dbus-send --print-reply --dest="$service" "$object" "${interface}.list_win"
|
||||
|
||||
# Get window ID of currently focused window
|
||||
focused=$(dbus-send --print-reply --dest="$service" "$object" "${interface}.find_win" string:focused | sed -n 's/^[[:space:]]*'${type_win}'\s*\([[:digit:]]*\).*/\1/p')
|
||||
|
||||
if [ -n "$focused" ]; then
|
||||
# Get invert_color_force property of the window
|
||||
dbus-send --print-reply --dest="$service" "$object" "${interface}.win_get" "${type_win}:${focused}" string:invert_color_force
|
||||
|
||||
# Set the window to have inverted color
|
||||
dbus-send --print-reply --dest="$service" "$object" "${interface}.win_set" "${type_win}:${focused}" string:invert_color_force "${type_enum}:1"
|
||||
else
|
||||
echo "Cannot find focused window."
|
||||
fi
|
||||
|
||||
# Set the clear_shadow setting to true
|
||||
dbus-send --print-reply --dest="$service" "$object" "${interface}.opts_set" string:clear_shadow boolean:true
|
||||
|
||||
# Get the clear_shadow setting
|
||||
dbus-send --print-reply --dest="$service" "$object" "${interface}.opts_get" string:clear_shadow
|
||||
|
||||
# Reset compton
|
||||
sleep 3
|
||||
dbus-send --print-reply --dest="$service" "$object" "${interface}.reset"
|
||||
|
File diff suppressed because it is too large
Load Diff
155
src/compton.c
155
src/compton.c
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
|
||||
*
|
||||
* Copyright (c) 2011, Christopher Jeffrey
|
||||
* Copyright (c) 2011-2013, Christopher Jeffrey
|
||||
* See LICENSE for more information.
|
||||
*
|
||||
*/
|
||||
|
@ -837,7 +837,7 @@ determine_evmask(session_t *ps, Window wid, win_evmode_t mode) {
|
|||
// Check if it's a mapped client window
|
||||
if (WIN_EVMODE_CLIENT == mode
|
||||
|| ((w = find_toplevel(ps, wid)) && IsViewable == w->a.map_state)) {
|
||||
if (ps->o.frame_opacity || ps->o.track_wdata
|
||||
if (ps->o.frame_opacity || ps->o.track_wdata || ps->track_atom_lst
|
||||
|| ps->o.detect_client_opacity)
|
||||
evmask |= PropertyChangeMask;
|
||||
}
|
||||
|
@ -1361,8 +1361,7 @@ paint_preprocess(session_t *ps, win *list) {
|
|||
// Disable unredirection for multi-screen setups
|
||||
if (WMODE_SOLID == w->mode
|
||||
&& (!w->frame_opacity || !win_has_frame(w))
|
||||
&& win_is_fullscreen(ps, w)
|
||||
&& ScreenCount(ps->dpy) <= 1)
|
||||
&& win_is_fullscreen(ps, w))
|
||||
ps->unredir_possible = true;
|
||||
}
|
||||
|
||||
|
@ -1848,6 +1847,9 @@ add_damage(session_t *ps, XserverRegion damage) {
|
|||
|
||||
static void
|
||||
repair_win(session_t *ps, win *w) {
|
||||
if (IsViewable != w->a.map_state)
|
||||
return;
|
||||
|
||||
XserverRegion parts;
|
||||
|
||||
if (!w->damaged) {
|
||||
|
@ -1986,6 +1988,13 @@ map_win(session_t *ps, Window id) {
|
|||
if (w->need_configure) {
|
||||
configure_win(ps, &w->queue_configure);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
if (ps->o.dbus) {
|
||||
cdbus_ev_win_mapped(ps, w);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2042,6 +2051,13 @@ unmap_win(session_t *ps, Window id) {
|
|||
|
||||
// don't care about properties anymore
|
||||
win_ev_stop(ps, w);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
if (ps->o.dbus) {
|
||||
cdbus_ev_win_unmapped(ps, w);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static opacity_t
|
||||
|
@ -2583,8 +2599,8 @@ add_win(session_t *ps, Window id, Window prev) {
|
|||
|
||||
// Fill structure
|
||||
new->id = id;
|
||||
set_ignore_next(ps);
|
||||
|
||||
set_ignore_next(ps);
|
||||
if (!XGetWindowAttributes(ps->dpy, id, &new->a)) {
|
||||
// Failed to get window attributes. Which probably means, the window
|
||||
// is gone already.
|
||||
|
@ -2608,7 +2624,14 @@ add_win(session_t *ps, Window id, Window prev) {
|
|||
new->next = *p;
|
||||
*p = new;
|
||||
|
||||
if (map_state == IsViewable) {
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
if (ps->o.dbus) {
|
||||
cdbus_ev_win_added(ps, new);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (IsViewable == map_state) {
|
||||
map_win(ps, id);
|
||||
}
|
||||
|
||||
|
@ -2811,6 +2834,13 @@ destroy_win(session_t *ps, Window id) {
|
|||
// Fading out the window
|
||||
w->flags |= WFLAG_OPCT_CHANGE;
|
||||
set_fade_callback(ps, w, destroy_callback, false);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
if (ps->o.dbus) {
|
||||
cdbus_ev_win_destroyed(ps, w);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3252,6 +3282,58 @@ win_get_class(session_t *ps, win *w) {
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
/** @name DBus hooks
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Set w->shadow_force of a window.
|
||||
*/
|
||||
void
|
||||
win_set_shadow_force(session_t *ps, win *w, switch_t val) {
|
||||
if (val != w->shadow_force) {
|
||||
w->shadow_force = val;
|
||||
win_determine_shadow(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set w->focused_force of a window.
|
||||
*/
|
||||
void
|
||||
win_set_focused_force(session_t *ps, win *w, switch_t val) {
|
||||
if (val != w->focused_force) {
|
||||
w->focused_force = val;
|
||||
win_update_focused(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set w->invert_color_force of a window.
|
||||
*/
|
||||
void
|
||||
win_set_invert_color_force(session_t *ps, win *w, switch_t val) {
|
||||
if (val != w->invert_color_force) {
|
||||
w->invert_color_force = val;
|
||||
win_determine_invert_color(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force a full-screen repaint.
|
||||
*/
|
||||
void
|
||||
force_repaint(session_t *ps) {
|
||||
XserverRegion reg = None;
|
||||
if (ps->screen_reg && (reg = copy_region(ps, ps->screen_reg))) {
|
||||
ps->ev_received = true;
|
||||
add_damage(ps, reg);
|
||||
}
|
||||
}
|
||||
//!@}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_EVENTS
|
||||
static int
|
||||
ev_serial(XEvent *ev) {
|
||||
|
@ -3647,6 +3729,17 @@ ev_property_notify(session_t *ps, XPropertyEvent *ev) {
|
|||
}
|
||||
}
|
||||
|
||||
// Check for other atoms we are tracking
|
||||
for (latom_t *platom = ps->track_atom_lst; platom; platom = platom->next) {
|
||||
if (platom->atom == ev->atom) {
|
||||
win *w = find_win(ps, ev->window);
|
||||
if (!w)
|
||||
w = find_toplevel(ps, ev->window);
|
||||
if (w)
|
||||
win_on_wdata_change(ps, w);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline static void
|
||||
|
@ -5129,8 +5222,7 @@ timeout_get_poll_time(session_t *ps) {
|
|||
// Traverse throught the timeout linked list
|
||||
for (timeout_t *ptmout = ps->tmout_lst; ptmout; ptmout = ptmout->next) {
|
||||
if (ptmout->enabled) {
|
||||
// Truncate the last run time to the closest interval
|
||||
time_ms_t newrun = ptmout->firstrun + ((ptmout->lastrun - ptmout->firstrun) / ptmout->interval + 1) * ptmout->interval;
|
||||
time_ms_t newrun = timeout_get_newrun(ptmout);
|
||||
if (newrun <= now) {
|
||||
wait = 0;
|
||||
break;
|
||||
|
@ -5149,7 +5241,7 @@ timeout_get_poll_time(session_t *ps) {
|
|||
/**
|
||||
* Insert a new timeout.
|
||||
*/
|
||||
static timeout_t *
|
||||
timeout_t *
|
||||
timeout_insert(session_t *ps, time_ms_t interval,
|
||||
bool (*callback)(session_t *ps, timeout_t *ptmout), void *data) {
|
||||
const static timeout_t tmout_def = {
|
||||
|
@ -5184,7 +5276,7 @@ timeout_insert(session_t *ps, time_ms_t interval,
|
|||
* @return true if we have found the timeout and removed it, false
|
||||
* otherwise
|
||||
*/
|
||||
static bool
|
||||
bool
|
||||
timeout_drop(session_t *ps, timeout_t *prm) {
|
||||
timeout_t **pplast = &ps->tmout_lst;
|
||||
|
||||
|
@ -5224,12 +5316,14 @@ static bool
|
|||
timeout_run(session_t *ps) {
|
||||
const time_ms_t now = get_time_ms();
|
||||
bool ret = false;
|
||||
timeout_t *pnext = NULL;
|
||||
|
||||
for (timeout_t *ptmout = ps->tmout_lst; ptmout; ptmout = ptmout->next) {
|
||||
for (timeout_t *ptmout = ps->tmout_lst; ptmout; ptmout = pnext) {
|
||||
pnext = ptmout->next;
|
||||
if (ptmout->enabled) {
|
||||
const time_ms_t max = now +
|
||||
(time_ms_t) (ptmout->interval * TIMEOUT_RUN_TOLERANCE);
|
||||
time_ms_t newrun = ptmout->firstrun + ((ptmout->lastrun - ptmout->firstrun) / ptmout->interval + 1) * ptmout->interval;
|
||||
time_ms_t newrun = timeout_get_newrun(ptmout);
|
||||
if (newrun <= max) {
|
||||
ret = true;
|
||||
timeout_invoke(ps, ptmout);
|
||||
|
@ -5243,7 +5337,7 @@ timeout_run(session_t *ps) {
|
|||
/**
|
||||
* Invoke a timeout.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
timeout_invoke(session_t *ps, timeout_t *ptmout) {
|
||||
const time_ms_t now = get_time_ms();
|
||||
ptmout->lastrun = now;
|
||||
|
@ -5301,6 +5395,12 @@ mainloop(session_t *ps) {
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
if (ps->o.dbus) {
|
||||
cdbus_loop(ps);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ps->reset)
|
||||
return false;
|
||||
|
||||
|
@ -5531,7 +5631,13 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||
.atom_ewmh_active_win = None,
|
||||
.atom_compton_shadow = None,
|
||||
.atom_win_type = None,
|
||||
.atoms_wintypes = { 0 }
|
||||
.atoms_wintypes = { 0 },
|
||||
.track_atom_lst = NULL,
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
.dbus_conn = NULL,
|
||||
.dbus_service = NULL,
|
||||
#endif
|
||||
};
|
||||
|
||||
// Allocate a session and copy default values into it
|
||||
|
@ -5740,6 +5846,19 @@ session_init(session_t *ps_old, int argc, char **argv) {
|
|||
|
||||
XUngrabServer(ps->dpy);
|
||||
|
||||
// Initialize DBus
|
||||
if (ps->o.dbus) {
|
||||
#ifdef CONFIG_DBUS
|
||||
cdbus_init(ps);
|
||||
if (!ps->dbus_conn) {
|
||||
cdbus_destroy(ps);
|
||||
ps->o.dbus = false;
|
||||
}
|
||||
#else
|
||||
printf_errfq(1, "(): DBus support not compiled in!");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Fork to background, if asked
|
||||
if (ps->o.fork_after_register) {
|
||||
if (!fork_after(ps)) {
|
||||
|
@ -5770,6 +5889,14 @@ session_destroy(session_t *ps) {
|
|||
// Stop listening to events on root window
|
||||
XSelectInput(ps->dpy, ps->root, 0);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Kill DBus connection
|
||||
if (ps->o.dbus)
|
||||
cdbus_destroy(ps);
|
||||
|
||||
free(ps->dbus_service);
|
||||
#endif
|
||||
|
||||
// Free window linked list
|
||||
{
|
||||
win *next = NULL;
|
||||
|
|
1256
src/compton.h
1256
src/compton.h
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,920 @@
|
|||
/*
|
||||
* Compton - a compositor for X11
|
||||
*
|
||||
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
|
||||
*
|
||||
* Copyright (c) 2011-2013, Christopher Jeffrey
|
||||
* See LICENSE for more information.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dbus.h"
|
||||
|
||||
/**
|
||||
* Initialize D-Bus connection.
|
||||
*/
|
||||
bool
|
||||
cdbus_init(session_t *ps) {
|
||||
DBusError err = { };
|
||||
|
||||
// Initialize
|
||||
dbus_error_init(&err);
|
||||
|
||||
// Connect to D-Bus
|
||||
// Use dbus_bus_get_private() so we can fully recycle it ourselves
|
||||
ps->dbus_conn = dbus_bus_get_private(DBUS_BUS_SESSION, &err);
|
||||
if (dbus_error_is_set(&err)) {
|
||||
printf_errf("(): D-Bus connection failed (%s).", err.message);
|
||||
dbus_error_free(&err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ps->dbus_conn) {
|
||||
printf_errf("(): D-Bus connection failed for unknown reason.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Avoid exiting on disconnect
|
||||
dbus_connection_set_exit_on_disconnect(ps->dbus_conn, false);
|
||||
|
||||
// Request service name
|
||||
{
|
||||
// Get display name
|
||||
char *display = DisplayString(ps->dpy);
|
||||
if (!display)
|
||||
display = "unknown";
|
||||
display = mstrcpy(display);
|
||||
|
||||
// Convert all special characters in display name to underscore
|
||||
{
|
||||
char *pdisp = display;
|
||||
|
||||
while (*pdisp) {
|
||||
if (!isalnum(*pdisp))
|
||||
*pdisp = '_';
|
||||
++pdisp;
|
||||
}
|
||||
}
|
||||
|
||||
// Build service name
|
||||
char *service = mstrjoin3(CDBUS_SERVICE_NAME, ".", display);
|
||||
ps->dbus_service = service;
|
||||
|
||||
free(display);
|
||||
display = NULL;
|
||||
|
||||
// Request for the name
|
||||
int ret = dbus_bus_request_name(ps->dbus_conn, service,
|
||||
DBUS_NAME_FLAG_DO_NOT_QUEUE, &err);
|
||||
|
||||
if (dbus_error_is_set(&err)) {
|
||||
printf_errf("(): Failed to obtain D-Bus name (%s).", err.message);
|
||||
dbus_error_free(&err);
|
||||
}
|
||||
|
||||
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret
|
||||
&& DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER != ret) {
|
||||
printf_errf("(): Failed to become the primary owner of requested "
|
||||
"D-Bus name (%d).", ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add watch handlers
|
||||
if (!dbus_connection_set_watch_functions(ps->dbus_conn,
|
||||
cdbus_callback_add_watch, cdbus_callback_remove_watch,
|
||||
cdbus_callback_watch_toggled, ps, NULL)) {
|
||||
printf_errf("(): Failed to add D-Bus watch functions.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add timeout handlers
|
||||
if (!dbus_connection_set_timeout_functions(ps->dbus_conn,
|
||||
cdbus_callback_add_timeout, cdbus_callback_remove_timeout,
|
||||
cdbus_callback_timeout_toggled, ps, NULL)) {
|
||||
printf_errf("(): Failed to add D-Bus timeout functions.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add match
|
||||
dbus_bus_add_match(ps->dbus_conn,
|
||||
"type='method_call',interface='" CDBUS_INTERFACE_NAME "'", &err);
|
||||
if (dbus_error_is_set(&err)) {
|
||||
printf_errf("(): Failed to add D-Bus match.");
|
||||
dbus_error_free(&err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy D-Bus connection.
|
||||
*/
|
||||
void
|
||||
cdbus_destroy(session_t *ps) {
|
||||
if (ps->dbus_conn) {
|
||||
// Release DBus name firstly
|
||||
if (ps->dbus_service) {
|
||||
DBusError err = { };
|
||||
dbus_error_init(&err);
|
||||
|
||||
dbus_bus_release_name(ps->dbus_conn, ps->dbus_service, &err);
|
||||
if (dbus_error_is_set(&err)) {
|
||||
printf_errf("(): Failed to release DBus name (%s).",
|
||||
err.message);
|
||||
dbus_error_free(&err);
|
||||
}
|
||||
}
|
||||
|
||||
// Close and unref the connection
|
||||
dbus_connection_close(ps->dbus_conn);
|
||||
dbus_connection_unref(ps->dbus_conn);
|
||||
}
|
||||
}
|
||||
|
||||
/** @name DBusTimeout handling
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Callback for adding D-Bus timeout.
|
||||
*/
|
||||
static dbus_bool_t
|
||||
cdbus_callback_add_timeout(DBusTimeout *timeout, void *data) {
|
||||
session_t *ps = data;
|
||||
|
||||
timeout_t *ptmout = timeout_insert(ps, dbus_timeout_get_interval(timeout),
|
||||
cdbus_callback_handle_timeout, timeout);
|
||||
if (ptmout)
|
||||
dbus_timeout_set_data(timeout, ptmout, NULL);
|
||||
|
||||
return (bool) ptmout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for removing D-Bus timeout.
|
||||
*/
|
||||
static void
|
||||
cdbus_callback_remove_timeout(DBusTimeout *timeout, void *data) {
|
||||
session_t *ps = data;
|
||||
|
||||
timeout_t *ptmout = dbus_timeout_get_data(timeout);
|
||||
assert(ptmout);
|
||||
if (ptmout)
|
||||
timeout_drop(ps, ptmout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for toggling a D-Bus timeout.
|
||||
*/
|
||||
static void
|
||||
cdbus_callback_timeout_toggled(DBusTimeout *timeout, void *data) {
|
||||
timeout_t *ptmout = dbus_timeout_get_data(timeout);
|
||||
|
||||
assert(ptmout);
|
||||
if (ptmout) {
|
||||
ptmout->enabled = dbus_timeout_get_enabled(timeout);
|
||||
// Refresh interval as libdbus doc says: "Whenever a timeout is toggled,
|
||||
// its interval may change."
|
||||
ptmout->interval = dbus_timeout_get_interval(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for handling a D-Bus timeout.
|
||||
*/
|
||||
static bool
|
||||
cdbus_callback_handle_timeout(session_t *ps, timeout_t *ptmout) {
|
||||
assert(ptmout && ptmout->data);
|
||||
if (ptmout && ptmout->data)
|
||||
return dbus_timeout_handle(ptmout->data);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
/** @name DBusWatch handling
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Callback for adding D-Bus watch.
|
||||
*/
|
||||
static dbus_bool_t
|
||||
cdbus_callback_add_watch(DBusWatch *watch, void *data) {
|
||||
// Leave disabled watches alone
|
||||
if (!dbus_watch_get_enabled(watch))
|
||||
return TRUE;
|
||||
|
||||
session_t *ps = data;
|
||||
|
||||
// Insert the file descriptor
|
||||
fds_insert(ps, dbus_watch_get_unix_fd(watch),
|
||||
cdbus_get_watch_cond(watch));
|
||||
|
||||
// Always return true
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for removing D-Bus watch.
|
||||
*/
|
||||
static void
|
||||
cdbus_callback_remove_watch(DBusWatch *watch, void *data) {
|
||||
session_t *ps = data;
|
||||
|
||||
fds_drop(ps, dbus_watch_get_unix_fd(watch),
|
||||
cdbus_get_watch_cond(watch));
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for toggling D-Bus watch status.
|
||||
*/
|
||||
static void
|
||||
cdbus_callback_watch_toggled(DBusWatch *watch, void *data) {
|
||||
if (dbus_watch_get_enabled(watch)) {
|
||||
cdbus_callback_add_watch(watch, data);
|
||||
}
|
||||
else {
|
||||
cdbus_callback_remove_watch(watch, data);
|
||||
}
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
/** @name Message argument appending callbacks
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Callback to append a bool argument to a message.
|
||||
*/
|
||||
static bool
|
||||
cdbus_apdarg_bool(session_t *ps, DBusMessage *msg, const void *data) {
|
||||
assert(data);
|
||||
|
||||
dbus_bool_t val = *(const bool *) data;
|
||||
|
||||
if (!dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &val,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
printf_errf("(): Failed to append argument.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to append a Window argument to a message.
|
||||
*/
|
||||
static bool
|
||||
cdbus_apdarg_wid(session_t *ps, DBusMessage *msg, const void *data) {
|
||||
assert(data);
|
||||
cdbus_window_t val = *(const Window *)data;
|
||||
|
||||
if (!dbus_message_append_args(msg, CDBUS_TYPE_WINDOW, &val,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
printf_errf("(): Failed to append argument.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to append an cdbus_enum_t argument to a message.
|
||||
*/
|
||||
static bool
|
||||
cdbus_apdarg_enum(session_t *ps, DBusMessage *msg, const void *data) {
|
||||
assert(data);
|
||||
if (!dbus_message_append_args(msg, CDBUS_TYPE_ENUM, data,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
printf_errf("(): Failed to append argument.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to append a string argument to a message.
|
||||
*/
|
||||
static bool
|
||||
cdbus_apdarg_string(session_t *ps, DBusMessage *msg, const void *data) {
|
||||
const char *str = data;
|
||||
if (!str)
|
||||
str = "";
|
||||
|
||||
if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &str,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
printf_errf("(): Failed to append argument.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to append all window IDs to a message.
|
||||
*/
|
||||
static bool
|
||||
cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data) {
|
||||
// Get the number of wids we are to include
|
||||
unsigned count = 0;
|
||||
for (win *w = ps->list; w; w = w->next) {
|
||||
if (!w->destroyed)
|
||||
++count;
|
||||
}
|
||||
|
||||
// Allocate memory for an array of window IDs
|
||||
cdbus_window_t *arr = malloc(sizeof(cdbus_window_t) * count);
|
||||
if (!arr) {
|
||||
printf_errf("(): Failed to allocate memory for window ID array.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build the array
|
||||
{
|
||||
cdbus_window_t *pcur = arr;
|
||||
for (win *w = ps->list; w; w = w->next) {
|
||||
if (!w->destroyed) {
|
||||
*pcur = w->id;
|
||||
++pcur;
|
||||
assert(pcur <= arr + count);
|
||||
}
|
||||
}
|
||||
assert(pcur == arr + count);
|
||||
}
|
||||
|
||||
// Append arguments
|
||||
if (!dbus_message_append_args(msg, DBUS_TYPE_ARRAY, CDBUS_TYPE_WINDOW,
|
||||
&arr, count, DBUS_TYPE_INVALID)) {
|
||||
printf_errf("(): Failed to append argument.");
|
||||
free(arr);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(arr);
|
||||
return true;
|
||||
}
|
||||
///@}
|
||||
|
||||
/**
|
||||
* Send a D-Bus signal.
|
||||
*
|
||||
* @param ps current session
|
||||
* @param name signal name
|
||||
* @param func a function that modifies the built message, to, for example,
|
||||
* add an argument
|
||||
* @param data data pointer to pass to the function
|
||||
*/
|
||||
static bool
|
||||
cdbus_signal(session_t *ps, const char *name,
|
||||
bool (*func)(session_t *ps, DBusMessage *msg, const void *data),
|
||||
const void *data) {
|
||||
DBusMessage* msg = NULL;
|
||||
|
||||
// Create a signal
|
||||
msg = dbus_message_new_signal(CDBUS_OBJECT_NAME, CDBUS_INTERFACE_NAME,
|
||||
name);
|
||||
if (!msg) {
|
||||
printf_errf("(): Failed to create D-Bus signal.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Append arguments onto message
|
||||
if (func && !func(ps, msg, data)) {
|
||||
dbus_message_unref(msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send the message and flush the connection
|
||||
if (!dbus_connection_send(ps->dbus_conn, msg, NULL)) {
|
||||
printf_errf("(): Failed to send D-Bus signal.");
|
||||
dbus_message_unref(msg);
|
||||
return false;
|
||||
}
|
||||
dbus_connection_flush(ps->dbus_conn);
|
||||
|
||||
// Free the message
|
||||
dbus_message_unref(msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a D-Bus reply.
|
||||
*
|
||||
* @param ps current session
|
||||
* @param srcmsg original message
|
||||
* @param func a function that modifies the built message, to, for example,
|
||||
* add an argument
|
||||
* @param data data pointer to pass to the function
|
||||
*/
|
||||
static bool
|
||||
cdbus_reply(session_t *ps, DBusMessage *srcmsg,
|
||||
bool (*func)(session_t *ps, DBusMessage *msg, const void *data),
|
||||
const void *data) {
|
||||
DBusMessage* msg = NULL;
|
||||
|
||||
// Create a reply
|
||||
msg = dbus_message_new_method_return(srcmsg);
|
||||
if (!msg) {
|
||||
printf_errf("(): Failed to create D-Bus reply.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Append arguments onto message
|
||||
if (func && !func(ps, msg, data)) {
|
||||
dbus_message_unref(msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send the message and flush the connection
|
||||
if (!dbus_connection_send(ps->dbus_conn, msg, NULL)) {
|
||||
printf_errf("(): Failed to send D-Bus reply.");
|
||||
dbus_message_unref(msg);
|
||||
return false;
|
||||
}
|
||||
dbus_connection_flush(ps->dbus_conn);
|
||||
|
||||
// Free the message
|
||||
dbus_message_unref(msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a D-Bus error reply.
|
||||
*
|
||||
* @param ps current session
|
||||
* @param msg the new error DBusMessage
|
||||
*/
|
||||
static bool
|
||||
cdbus_reply_errm(session_t *ps, DBusMessage *msg) {
|
||||
if (!msg) {
|
||||
printf_errf("(): Failed to create D-Bus reply.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send the message and flush the connection
|
||||
if (!dbus_connection_send(ps->dbus_conn, msg, NULL)) {
|
||||
printf_errf("(): Failed to send D-Bus reply.");
|
||||
dbus_message_unref(msg);
|
||||
return false;
|
||||
}
|
||||
dbus_connection_flush(ps->dbus_conn);
|
||||
|
||||
// Free the message
|
||||
dbus_message_unref(msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get n-th argument of a D-Bus message.
|
||||
*
|
||||
* @param count the position of the argument to get, starting from 0
|
||||
* @param type libdbus type number of the type
|
||||
* @param pdest pointer to the target
|
||||
* @return true if successful, false otherwise.
|
||||
*/
|
||||
static bool
|
||||
cdbus_msg_get_arg(DBusMessage *msg, int count, const int type, void *pdest) {
|
||||
assert(count >= 0);
|
||||
|
||||
DBusMessageIter iter = { };
|
||||
if (!dbus_message_iter_init(msg, &iter)) {
|
||||
printf_errf("(): Message has no argument.");
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
const int oldcount = count;
|
||||
while (count) {
|
||||
if (!dbus_message_iter_next(&iter)) {
|
||||
printf_errf("(): Failed to find argument %d.", oldcount);
|
||||
return false;
|
||||
}
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
if (type != dbus_message_iter_get_arg_type(&iter)) {
|
||||
printf_errf("(): Argument has incorrect type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
dbus_message_iter_get_basic(&iter, pdest);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
cdbus_loop(session_t *ps) {
|
||||
dbus_connection_read_write(ps->dbus_conn, 0);
|
||||
DBusMessage *msg = NULL;
|
||||
while ((msg = dbus_connection_pop_message(ps->dbus_conn)))
|
||||
cdbus_process(ps, msg);
|
||||
}
|
||||
|
||||
/** @name Message processing
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Process a message from D-Bus.
|
||||
*/
|
||||
static void
|
||||
cdbus_process(session_t *ps, DBusMessage *msg) {
|
||||
bool success = false;
|
||||
|
||||
#define cdbus_m_ismethod(method) \
|
||||
dbus_message_is_method_call(msg, CDBUS_INTERFACE_NAME, method)
|
||||
|
||||
if (cdbus_m_ismethod("reset")) {
|
||||
ps->reset = true;
|
||||
if (!dbus_message_get_no_reply(msg))
|
||||
cdbus_reply_bool(ps, msg, true);
|
||||
success = true;
|
||||
}
|
||||
else if (cdbus_m_ismethod("list_win")) {
|
||||
success = cdbus_process_list_win(ps, msg);
|
||||
}
|
||||
else if (cdbus_m_ismethod("win_get")) {
|
||||
success = cdbus_process_win_get(ps, msg);
|
||||
}
|
||||
else if (cdbus_m_ismethod("win_set")) {
|
||||
success = cdbus_process_win_set(ps, msg);
|
||||
}
|
||||
else if (cdbus_m_ismethod("find_win")) {
|
||||
success = cdbus_process_find_win(ps, msg);
|
||||
}
|
||||
else if (cdbus_m_ismethod("opts_get")) {
|
||||
success = cdbus_process_opts_get(ps, msg);
|
||||
}
|
||||
else if (cdbus_m_ismethod("opts_set")) {
|
||||
success = cdbus_process_opts_set(ps, msg);
|
||||
}
|
||||
#undef cdbus_m_ismethod
|
||||
else if (dbus_message_is_method_call(msg,
|
||||
"org.freedesktop.DBus.Introspectable", "Introspect")) {
|
||||
success = cdbus_process_introspect(ps, msg);
|
||||
}
|
||||
else if (dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameAcquired")
|
||||
|| dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameLost")) {
|
||||
success = true;
|
||||
}
|
||||
else {
|
||||
if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(msg)) {
|
||||
printf_errf("(): Error message of path \"%s\" "
|
||||
"interface \"%s\", member \"%s\", error \"%s\"",
|
||||
dbus_message_get_path(msg), dbus_message_get_interface(msg),
|
||||
dbus_message_get_member(msg), dbus_message_get_error_name(msg));
|
||||
}
|
||||
else {
|
||||
printf_errf("(): Illegal message of type \"%s\", path \"%s\" "
|
||||
"interface \"%s\", member \"%s\"",
|
||||
cdbus_repr_msgtype(msg), dbus_message_get_path(msg),
|
||||
dbus_message_get_interface(msg), dbus_message_get_member(msg));
|
||||
}
|
||||
if (DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg)
|
||||
&& !dbus_message_get_no_reply(msg))
|
||||
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADMSG, CDBUS_ERROR_BADMSG_S);
|
||||
success = true;
|
||||
}
|
||||
|
||||
// If the message could not be processed, and an reply is expected, return
|
||||
// an empty reply.
|
||||
if (!success && DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg)
|
||||
&& !dbus_message_get_no_reply(msg))
|
||||
cdbus_reply_err(ps, msg, CDBUS_ERROR_UNKNOWN, CDBUS_ERROR_UNKNOWN_S);
|
||||
|
||||
// Free the message
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a list_win D-Bus request.
|
||||
*/
|
||||
static bool
|
||||
cdbus_process_list_win(session_t *ps, DBusMessage *msg) {
|
||||
cdbus_reply(ps, msg, cdbus_apdarg_wids, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a win_get D-Bus request.
|
||||
*/
|
||||
static bool
|
||||
cdbus_process_win_get(session_t *ps, DBusMessage *msg) {
|
||||
cdbus_window_t wid = None;
|
||||
const char *target = NULL;
|
||||
DBusError err = { };
|
||||
|
||||
if (!dbus_message_get_args(msg, &err,
|
||||
CDBUS_TYPE_WINDOW, &wid,
|
||||
DBUS_TYPE_STRING, &target,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
printf_errf("(): Failed to parse argument of \"win_get\" (%s).",
|
||||
err.message);
|
||||
dbus_error_free(&err);
|
||||
return false;
|
||||
}
|
||||
|
||||
win *w = find_win(ps, wid);
|
||||
|
||||
if (!w) {
|
||||
printf_errf("(): Window %#010x not found.", wid);
|
||||
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADWIN, CDBUS_ERROR_BADWIN_S, wid);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define cdbus_m_win_get_do(tgt, apdarg_func) \
|
||||
if (!strcmp(MSTR(tgt), target)) { \
|
||||
apdarg_func(ps, msg, w->tgt); \
|
||||
return true; \
|
||||
}
|
||||
|
||||
cdbus_m_win_get_do(client_win, cdbus_reply_wid);
|
||||
cdbus_m_win_get_do(damaged, cdbus_reply_bool);
|
||||
cdbus_m_win_get_do(destroyed, cdbus_reply_bool);
|
||||
cdbus_m_win_get_do(window_type, cdbus_reply_enum);
|
||||
cdbus_m_win_get_do(wmwin, cdbus_reply_bool);
|
||||
cdbus_m_win_get_do(leader, cdbus_reply_wid);
|
||||
cdbus_m_win_get_do(focused_real, cdbus_reply_bool);
|
||||
cdbus_m_win_get_do(shadow_force, cdbus_reply_enum);
|
||||
cdbus_m_win_get_do(focused_force, cdbus_reply_enum);
|
||||
cdbus_m_win_get_do(invert_color_force, cdbus_reply_enum);
|
||||
if (!strcmp("map_state", target)) {
|
||||
cdbus_reply_bool(ps, msg, w->a.map_state);
|
||||
return true;
|
||||
}
|
||||
#undef cdbus_m_win_get_do
|
||||
|
||||
printf_errf("(): No matching target found.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a win_set D-Bus request.
|
||||
*/
|
||||
static bool
|
||||
cdbus_process_win_set(session_t *ps, DBusMessage *msg) {
|
||||
cdbus_window_t wid = None;
|
||||
const char *target = NULL;
|
||||
DBusError err = { };
|
||||
|
||||
if (!dbus_message_get_args(msg, &err,
|
||||
CDBUS_TYPE_WINDOW, &wid,
|
||||
DBUS_TYPE_STRING, &target,
|
||||
DBUS_TYPE_INVALID)) {
|
||||
printf_errf("(): Failed to parse argument of \"win_set\" (%s).",
|
||||
err.message);
|
||||
dbus_error_free(&err);
|
||||
return false;
|
||||
}
|
||||
|
||||
win *w = find_win(ps, wid);
|
||||
|
||||
if (!w) {
|
||||
printf_errf("(): Window %#010x not found.", wid);
|
||||
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADWIN, CDBUS_ERROR_BADWIN_S, wid);
|
||||
return true;
|
||||
}
|
||||
|
||||
ps->ev_received = true;
|
||||
|
||||
#define cdbus_m_win_set_do(tgt, type, real_type) \
|
||||
if (!strcmp(MSTR(tgt), target)) { \
|
||||
real_type val; \
|
||||
if (!cdbus_msg_get_arg(msg, 2, type, &val)) \
|
||||
return false; \
|
||||
w->tgt = val; \
|
||||
goto cdbus_process_win_set_success; \
|
||||
}
|
||||
|
||||
if (!strcmp("shadow_force", target)) {
|
||||
cdbus_enum_t val = UNSET;
|
||||
if (!cdbus_msg_get_arg(msg, 2, CDBUS_TYPE_ENUM, &val))
|
||||
return false;
|
||||
win_set_shadow_force(ps, w, val);
|
||||
goto cdbus_process_win_set_success;
|
||||
}
|
||||
|
||||
if (!strcmp("focused_force", target)) {
|
||||
cdbus_enum_t val = UNSET;
|
||||
if (!cdbus_msg_get_arg(msg, 2, CDBUS_TYPE_ENUM, &val))
|
||||
return false;
|
||||
win_set_focused_force(ps, w, val);
|
||||
goto cdbus_process_win_set_success;
|
||||
}
|
||||
|
||||
if (!strcmp("invert_color_force", target)) {
|
||||
cdbus_enum_t val = UNSET;
|
||||
if (!cdbus_msg_get_arg(msg, 2, CDBUS_TYPE_ENUM, &val))
|
||||
return false;
|
||||
win_set_invert_color_force(ps, w, val);
|
||||
goto cdbus_process_win_set_success;
|
||||
}
|
||||
#undef cdbus_m_win_set_do
|
||||
|
||||
printf_errf("(): No matching target found.");
|
||||
|
||||
return false;
|
||||
|
||||
cdbus_process_win_set_success:
|
||||
if (!dbus_message_get_no_reply(msg))
|
||||
cdbus_reply_bool(ps, msg, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a find_win D-Bus request.
|
||||
*/
|
||||
static bool
|
||||
cdbus_process_find_win(session_t *ps, DBusMessage *msg) {
|
||||
const char *target = NULL;
|
||||
|
||||
if (!cdbus_msg_get_arg(msg, 0, DBUS_TYPE_STRING, &target))
|
||||
return false;
|
||||
|
||||
Window wid = None;
|
||||
|
||||
// Find window by client window
|
||||
if (!strcmp("client", target)) {
|
||||
cdbus_window_t client = None;
|
||||
if (!cdbus_msg_get_arg(msg, 1, CDBUS_TYPE_WINDOW, &client))
|
||||
return false;
|
||||
win *w = find_toplevel(ps, client);
|
||||
if (w)
|
||||
wid = w->id;
|
||||
}
|
||||
// Find focused window
|
||||
else if (!strcmp("focused", target)) {
|
||||
win *w = find_focused(ps);
|
||||
if (w)
|
||||
wid = w->id;
|
||||
}
|
||||
else {
|
||||
printf_errf("(): No matching target found.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
cdbus_reply_wid(ps, msg, wid);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a opts_get D-Bus request.
|
||||
*/
|
||||
static bool
|
||||
cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
|
||||
const char *target = NULL;
|
||||
|
||||
if (!cdbus_msg_get_arg(msg, 0, DBUS_TYPE_STRING, &target))
|
||||
return false;
|
||||
|
||||
#define cdbus_m_opts_get_do(tgt, apdarg_func) \
|
||||
if (!strcmp(MSTR(tgt), target)) { \
|
||||
apdarg_func(ps, msg, ps->o.tgt); \
|
||||
return true; \
|
||||
}
|
||||
|
||||
cdbus_m_opts_get_do(display, cdbus_reply_string);
|
||||
cdbus_m_opts_get_do(mark_wmwin_focused, cdbus_reply_bool);
|
||||
cdbus_m_opts_get_do(mark_ovredir_focused, cdbus_reply_bool);
|
||||
cdbus_m_opts_get_do(fork_after_register, cdbus_reply_bool);
|
||||
cdbus_m_opts_get_do(detect_rounded_corners, cdbus_reply_bool);
|
||||
cdbus_m_opts_get_do(paint_on_overlay, cdbus_reply_bool);
|
||||
cdbus_m_opts_get_do(unredir_if_possible, cdbus_reply_bool);
|
||||
cdbus_m_opts_get_do(logpath, cdbus_reply_string);
|
||||
cdbus_m_opts_get_do(synchronize, cdbus_reply_bool);
|
||||
|
||||
cdbus_m_opts_get_do(clear_shadow, cdbus_reply_bool);
|
||||
#undef cdbus_m_opts_get_do
|
||||
|
||||
printf_errf("(): No matching target found.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a opts_set D-Bus request.
|
||||
*/
|
||||
static bool
|
||||
cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
|
||||
const char *target = NULL;
|
||||
|
||||
if (!cdbus_msg_get_arg(msg, 0, DBUS_TYPE_STRING, &target))
|
||||
return false;
|
||||
|
||||
#define cdbus_m_opts_set_do(tgt, type, real_type) \
|
||||
if (!strcmp(MSTR(tgt), target)) { \
|
||||
real_type val; \
|
||||
if (!cdbus_msg_get_arg(msg, 1, type, &val)) \
|
||||
return false; \
|
||||
ps->o.tgt = val; \
|
||||
goto cdbus_process_opts_set_success; \
|
||||
}
|
||||
|
||||
// unredir_if_possible
|
||||
if (!strcmp("unredir_if_possible", target)) {
|
||||
dbus_bool_t val = FALSE;
|
||||
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_BOOLEAN, &val))
|
||||
return false;
|
||||
if (ps->o.unredir_if_possible != val) {
|
||||
ps->o.unredir_if_possible = val;
|
||||
ps->ev_received = true;
|
||||
}
|
||||
goto cdbus_process_opts_set_success;
|
||||
}
|
||||
|
||||
// clear_shadow
|
||||
if (!strcmp("clear_shadow", target)) {
|
||||
dbus_bool_t val = FALSE;
|
||||
if (!cdbus_msg_get_arg(msg, 1, DBUS_TYPE_BOOLEAN, &val))
|
||||
return false;
|
||||
if (ps->o.clear_shadow != val) {
|
||||
ps->o.clear_shadow = val;
|
||||
force_repaint(ps);
|
||||
}
|
||||
goto cdbus_process_opts_set_success;
|
||||
}
|
||||
#undef cdbus_m_opts_set_do
|
||||
|
||||
printf_errf("(): No matching target found.");
|
||||
|
||||
return false;
|
||||
|
||||
cdbus_process_opts_set_success:
|
||||
if (!dbus_message_get_no_reply(msg))
|
||||
cdbus_reply_bool(ps, msg, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an Introspect D-Bus request.
|
||||
*/
|
||||
static bool
|
||||
cdbus_process_introspect(session_t *ps, DBusMessage *msg) {
|
||||
const static char *str_introspect =
|
||||
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
|
||||
" \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
|
||||
"<node name='" CDBUS_OBJECT_NAME "'>\n"
|
||||
" <interface name='" CDBUS_INTERFACE_NAME "'>\n"
|
||||
" <signal name='win_added'>\n"
|
||||
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name='win_destroyed'>\n"
|
||||
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name='win_mapped'>\n"
|
||||
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name='win_unmapped'>\n"
|
||||
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"
|
||||
" </signal>\n"
|
||||
" <method name='reset' />\n"
|
||||
" </interface>\n"
|
||||
"</node>\n";
|
||||
|
||||
cdbus_reply_string(ps, msg, str_introspect);
|
||||
|
||||
return true;
|
||||
}
|
||||
///@}
|
||||
|
||||
/** @name Core callbacks
|
||||
*/
|
||||
///@{
|
||||
void
|
||||
cdbus_ev_win_added(session_t *ps, win *w) {
|
||||
if (ps->dbus_conn)
|
||||
cdbus_signal_wid(ps, "win_added", w->id);
|
||||
}
|
||||
|
||||
void
|
||||
cdbus_ev_win_destroyed(session_t *ps, win *w) {
|
||||
if (ps->dbus_conn)
|
||||
cdbus_signal_wid(ps, "win_destroyed", w->id);
|
||||
}
|
||||
|
||||
void
|
||||
cdbus_ev_win_mapped(session_t *ps, win *w) {
|
||||
if (ps->dbus_conn)
|
||||
cdbus_signal_wid(ps, "win_mapped", w->id);
|
||||
}
|
||||
|
||||
void
|
||||
cdbus_ev_win_unmapped(session_t *ps, win *w) {
|
||||
if (ps->dbus_conn)
|
||||
cdbus_signal_wid(ps, "win_unmapped", w->id);
|
||||
}
|
||||
//!@}
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* Compton - a compositor for X11
|
||||
*
|
||||
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
|
||||
*
|
||||
* Copyright (c) 2011-2013, Christopher Jeffrey
|
||||
* See LICENSE for more information.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#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 "Something wrong in arguments?"
|
||||
#define CDBUS_ERROR_BADWIN CDBUS_ERROR_PREFIX ".bad_window"
|
||||
#define CDBUS_ERROR_BADWIN_S "Requested window %#010lx not found."
|
||||
#define CDBUS_ERROR_FORBIDDEN CDBUS_ERROR_PREFIX ".forbidden"
|
||||
#define CDBUS_ERROR_FORBIDDEN_S "Incorrect password, access denied."
|
||||
|
||||
// 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 uint16_t cdbus_enum_t;
|
||||
#define CDBUS_TYPE_ENUM DBUS_TYPE_UINT16
|
||||
#define CDBUS_TYPE_ENUM_STR DBUS_TYPE_UINT16_AS_STRING
|
||||
|
||||
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 bool
|
||||
cdbus_callback_handle_timeout(session_t *ps, timeout_t *ptmout);
|
||||
|
||||
/**
|
||||
* Determine the poll condition of a DBusWatch.
|
||||
*/
|
||||
static inline short
|
||||
cdbus_get_watch_cond(DBusWatch *watch) {
|
||||
const unsigned flags = dbus_watch_get_flags(watch);
|
||||
short condition = POLLERR | POLLHUP;
|
||||
if (flags & DBUS_WATCH_READABLE)
|
||||
condition |= POLLIN;
|
||||
if (flags & DBUS_WATCH_WRITABLE)
|
||||
condition |= POLLOUT;
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
static bool
|
||||
cdbus_apdarg_bool(session_t *ps, DBusMessage *msg, const void *data);
|
||||
|
||||
static bool
|
||||
cdbus_apdarg_wid(session_t *ps, DBusMessage *msg, const void *data);
|
||||
|
||||
static bool
|
||||
cdbus_apdarg_enum(session_t *ps, DBusMessage *msg, const void *data);
|
||||
|
||||
static bool
|
||||
cdbus_apdarg_string(session_t *ps, DBusMessage *msg, const void *data);
|
||||
|
||||
static bool
|
||||
cdbus_apdarg_wids(session_t *ps, DBusMessage *msg, const void *data);
|
||||
|
||||
/** @name DBus signal sending
|
||||
*/
|
||||
///@{
|
||||
|
||||
static bool
|
||||
cdbus_signal(session_t *ps, const char *name,
|
||||
bool (*func)(session_t *ps, DBusMessage *msg, const void *data),
|
||||
const void *data);
|
||||
|
||||
/**
|
||||
* Send a signal with no argument.
|
||||
*/
|
||||
static inline bool
|
||||
cdbus_signal_noarg(session_t *ps, const char *name) {
|
||||
return cdbus_signal(ps, name, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a signal with a Window ID as argument.
|
||||
*/
|
||||
static inline bool
|
||||
cdbus_signal_wid(session_t *ps, const char *name, Window wid) {
|
||||
return cdbus_signal(ps, name, cdbus_apdarg_wid, &wid);
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
/** @name DBus reply sending
|
||||
*/
|
||||
///@{
|
||||
|
||||
static bool
|
||||
cdbus_reply(session_t *ps, DBusMessage *srcmsg,
|
||||
bool (*func)(session_t *ps, DBusMessage *msg, const void *data),
|
||||
const void *data);
|
||||
|
||||
static bool
|
||||
cdbus_reply_errm(session_t *ps, DBusMessage *msg);
|
||||
|
||||
#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__))
|
||||
|
||||
/**
|
||||
* Send a reply with no argument.
|
||||
*/
|
||||
static inline bool
|
||||
cdbus_reply_noarg(session_t *ps, DBusMessage *srcmsg) {
|
||||
return cdbus_reply(ps, srcmsg, NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 a wid argument.
|
||||
*/
|
||||
static inline bool
|
||||
cdbus_reply_wid(session_t *ps, DBusMessage *srcmsg, Window 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);
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
static bool
|
||||
cdbus_msg_get_arg(DBusMessage *msg, int count, const int type, void *pdest);
|
||||
|
||||
/**
|
||||
* Return a string representation of a D-Bus message type.
|
||||
*/
|
||||
static inline const char *
|
||||
cdbus_repr_msgtype(DBusMessage *msg) {
|
||||
return dbus_message_type_to_string(dbus_message_get_type(msg));
|
||||
}
|
||||
|
||||
/** @name Message processing
|
||||
*/
|
||||
///@{
|
||||
|
||||
static void
|
||||
cdbus_process(session_t *ps, DBusMessage *msg);
|
||||
|
||||
static bool
|
||||
cdbus_process_list_win(session_t *ps, DBusMessage *msg);
|
||||
|
||||
static bool
|
||||
cdbus_process_win_get(session_t *ps, DBusMessage *msg);
|
||||
|
||||
static bool
|
||||
cdbus_process_win_set(session_t *ps, DBusMessage *msg);
|
||||
|
||||
static bool
|
||||
cdbus_process_find_win(session_t *ps, DBusMessage *msg);
|
||||
|
||||
static bool
|
||||
cdbus_process_opts_get(session_t *ps, DBusMessage *msg);
|
||||
|
||||
static bool
|
||||
cdbus_process_opts_set(session_t *ps, DBusMessage *msg);
|
||||
|
||||
static bool
|
||||
cdbus_process_introspect(session_t *ps, DBusMessage *msg);
|
||||
|
||||
///@}
|
Loading…
Reference in New Issue