Bug fix #84: Root window not repainted sometimes on wallpaper change

- Fix a bug that root window is not repainted on wallpaper change unless
  an Expose X event is received. Seemingly, if there's no mapped window
  on a screen, X will not send an Expose event when the wallpaper
  changes. Thanks to baskerville for reporting.

- Fix a X Pixmap leak when there's no existing wallpaper pixmap found.

- Fix a bug in mstrncpy() that null character is not added to the end of
  the copied string.

- Make VSYNC_STRS public, for use in src/dbus.c. Adjust the type of
  WINTYPES array. Add NUM_VSYNC.

- Add more targets for various D-Bus methods. Add "bad_target" D-Bus
  error. Improve error handling. Add more helper functions to append
  arguments to a D-Bus message. Add Introspect method to D-Bus
  introspection reply.

- Add public declarations of things in the new condition format code to
  common.h. Move definitions of some inline functions from compton.h to
  common.h. Make some functions public. Move wid_get_prop_adv() to
  compton.c. The primary code files of the new format src/c2.{c,h} will
  be published when ready.

- Add support for dumping version string in Makefile (make version), to
  make snapshot generation easier.

- Add repeated inclusion protection to common.h.

- Update documentation.

- Use gsed instead of sed in dbus-examples/cdbus-driver.sh if possible,
  as some BSD systems does not come with GNU sed by default. Thanks to
  DaChiChang for reporting.

- Code clean-up. Small type changes in register_cm() to silence
  warnings. Quit on failure in parse_vsync(). Apply stricter checks in
  force_repaint().
This commit is contained in:
Richard Grenville 2013-01-24 13:38:03 +08:00
parent 58c0ecec40
commit 00424b1082
8 changed files with 415 additions and 190 deletions

View File

@ -54,6 +54,12 @@ ifeq "$(NO_DBUS)" ""
OBJS += dbus.o OBJS += dbus.o
endif endif
# ==== C2 ====
# ifeq "$(NO_C2)" ""
# CFG += -DCONFIG_C2
# OBJS += c2.o
# endif
# === Version string === # === Version string ===
COMPTON_VERSION ?= git-$(shell git describe --always --dirty)-$(shell git log -1 --date=short --pretty=format:%cd) COMPTON_VERSION ?= git-$(shell git describe --always --dirty)-$(shell git log -1 --date=short --pretty=format:%cd)
CFG += -DCOMPTON_VERSION="\"$(COMPTON_VERSION)\"" CFG += -DCOMPTON_VERSION="\"$(COMPTON_VERSION)\""
@ -101,4 +107,7 @@ uninstall:
clean: clean:
@rm -f $(OBJS) compton $(MANPAGES) $(MANPAGES_HTML) @rm -f $(OBJS) compton $(MANPAGES) $(MANPAGES_HTML)
.PHONY: uninstall clean docs version:
@echo "$(COMPTON_VERSION)"
.PHONY: uninstall clean docs version

View File

@ -1,5 +1,10 @@
#!/bin/sh #!/bin/sh
if [ -z "$SED" ]; then
SED="sed"
command -v gsed > /dev/null && SED="gsed"
fi
# === Get connection parameters === # === Get connection parameters ===
dpy=$(echo -n "$DISPLAY" | tr -c '[:alnum:]' _) dpy=$(echo -n "$DISPLAY" | tr -c '[:alnum:]' _)
@ -21,7 +26,7 @@ type_enum='uint16'
dbus-send --print-reply --dest="$service" "$object" "${interface}.list_win" dbus-send --print-reply --dest="$service" "$object" "${interface}.list_win"
# Get window ID of currently focused window # 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') 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 if [ -n "$focused" ]; then
# Get invert_color_force property of the window # Get invert_color_force property of the window

View File

@ -15,7 +15,7 @@ SYNOPSIS
WARNING WARNING
------- -------
This man page may be less up-to-date than the usage text in compton. This man page may be less up-to-date than the usage text in compton (`compton -h`).
DESCRIPTION DESCRIPTION
----------- -----------
@ -23,6 +23,9 @@ compton is a compositor based on Dana Jansens' version of xcompmgr (which itself
OPTIONS OPTIONS
------- -------
*-h*, *--help*::
Get the usage text embedded in program code, which may be more up-to-date than this man page.
*-d* 'DISPLAY':: *-d* 'DISPLAY'::
Display to be managed. Display to be managed.
@ -169,6 +172,12 @@ OPTIONS
*--blur-background-fixed*:: *--blur-background-fixed*::
Use fixed blur strength rather than adjusting according to window opacity. Use fixed blur strength rather than adjusting according to window opacity.
*--invert-color-include* condition::
Specify a list of conditions of windows that should be painted with inverted color. Resource-hogging, and is not well tested.
*--dbus*::
Enable remote control via D-Bus. See the *D-BUS API* section below for more details.
FORMAT OF CONDITIONS FORMAT OF CONDITIONS
-------------------- --------------------
@ -193,6 +202,12 @@ SIGNALS
* compton reinitializes itself upon receiving `SIGUSR1`. * compton reinitializes itself upon receiving `SIGUSR1`.
D-BUS API
---------
It's possible to control compton via D-Bus messages, by running compton with *--dbus* and send messages to `com.github.chjj.compton.<DISPLAY>`. `<DISPLAY>` is the display used by compton, with all non-alphanumeric characters transformed to underscores. For `DISPLAY=:0.0` you should use `com.github.chjj.compton._0_0`, for example.
The D-Bus methods and signals are not yet stable, thus undocumented right now.
EXAMPLES EXAMPLES
-------- --------

View File

@ -8,6 +8,9 @@
* *
*/ */
#ifndef COMPTON_COMMON_H
#define COMPTON_COMMON_H
// === Options === // === Options ===
// Debug options, enable them using -D in CFLAGS // Debug options, enable them using -D in CFLAGS
@ -22,6 +25,7 @@
// #define DEBUG_ALLOC_REG 1 // #define DEBUG_ALLOC_REG 1
// #define DEBUG_FRAME 1 // #define DEBUG_FRAME 1
// #define DEBUG_LEADER 1 // #define DEBUG_LEADER 1
// #define DEBUG_C2 1
// #define MONITOR_REPAINT 1 // #define MONITOR_REPAINT 1
// Whether to enable PCRE regular expression support in blacklists, enabled // Whether to enable PCRE regular expression support in blacklists, enabled
@ -40,6 +44,12 @@
// #define CONFIG_VSYNC_OPENGL 1 // #define CONFIG_VSYNC_OPENGL 1
// Whether to enable DBus support with libdbus. // Whether to enable DBus support with libdbus.
// #define CONFIG_DBUS 1 // #define CONFIG_DBUS 1
// Whether to enable condition support.
// #define CONFIG_C2 1
#if !defined(CONFIG_C2) && defined(DEBUG_C2)
#error Cannot enable c2 debugging without c2 support.
#endif
// === Includes === // === Includes ===
@ -264,6 +274,7 @@ typedef enum {
VSYNC_NONE, VSYNC_NONE,
VSYNC_DRM, VSYNC_DRM,
VSYNC_OPENGL, VSYNC_OPENGL,
NUM_VSYNC,
} vsync_t; } vsync_t;
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
@ -286,9 +297,15 @@ struct _timeout_t;
struct _win; struct _win;
#ifdef CONFIG_C2
typedef struct _c2_lptr c2_lptr_t;
#endif
/// Structure representing all options. /// Structure representing all options.
typedef struct { typedef struct {
// === General === // === General ===
/// The display name we used. NULL means we are using the value of the
/// <code>DISPLAY</code> environment variable.
char *display; char *display;
/// Whether to try to detect WM windows and mark them as focused. /// Whether to try to detect WM windows and mark them as focused.
bool mark_wmwin_focused; bool mark_wmwin_focused;
@ -534,13 +551,13 @@ typedef struct {
/// Nanosecond offset of the first painting. /// Nanosecond offset of the first painting.
long paint_tm_offset; long paint_tm_offset;
#ifdef CONFIG_VSYNC_DRM #ifdef CONFIG_VSYNC_DRM
// === DRM VSync related === // === DRM VSync related ===
/// File descriptor of DRI device file. Used for DRM VSync. /// File descriptor of DRI device file. Used for DRM VSync.
int drm_fd; int drm_fd;
#endif #endif
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
// === OpenGL VSync related === // === OpenGL VSync related ===
/// GLX context. /// GLX context.
GLXContext glx_context; GLXContext glx_context;
@ -548,7 +565,7 @@ typedef struct {
f_GetVideoSync glx_get_video_sync; f_GetVideoSync glx_get_video_sync;
/// Pointer to glXWaitVideoSyncSGI function. /// Pointer to glXWaitVideoSyncSGI function.
f_WaitVideoSync glx_wait_video_sync; f_WaitVideoSync glx_wait_video_sync;
#endif #endif
// === X extension related === // === X extension related ===
/// Event base number for X Fixes extension. /// Event base number for X Fixes extension.
@ -584,14 +601,14 @@ typedef struct {
int randr_event; int randr_event;
/// Error base number for X RandR extension. /// Error base number for X RandR extension.
int randr_error; int randr_error;
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
/// Whether X GLX extension exists. /// Whether X GLX extension exists.
bool glx_exists; bool glx_exists;
/// Event base number for X GLX extension. /// Event base number for X GLX extension.
int glx_event; int glx_event;
/// Error base number for X GLX extension. /// Error base number for X GLX extension.
int glx_error; int glx_error;
#endif #endif
/// Whether X DBE extension exists. /// Whether X DBE extension exists.
bool dbe_exists; bool dbe_exists;
/// Whether X Render convolution filter exists. /// Whether X Render convolution filter exists.
@ -816,7 +833,8 @@ typedef enum {
WIN_EVMODE_CLIENT WIN_EVMODE_CLIENT
} win_evmode_t; } win_evmode_t;
extern const char *WINTYPES[NUM_WINTYPES]; extern const char * const WINTYPES[NUM_WINTYPES];
extern const char * const VSYNC_STRS[NUM_VSYNC];
extern session_t *ps_g; extern session_t *ps_g;
// == Debugging code == // == Debugging code ==
@ -1055,6 +1073,7 @@ mstrncpy(const char *src, unsigned len) {
char *str = malloc(sizeof(char) * (len + 1)); char *str = malloc(sizeof(char) * (len + 1));
strncpy(str, src, len); strncpy(str, src, len);
str[len] = '\0';
return str; return str;
} }
@ -1259,6 +1278,14 @@ fds_poll(session_t *ps, struct timeval *ptv) {
} }
#undef CPY_FDS #undef CPY_FDS
/**
* Wrapper of XInternAtom() for convenience.
*/
static inline Atom
get_atom(session_t *ps, const char *atom_name) {
return XInternAtom(ps->dpy, atom_name, False);
}
/** /**
* Find a window from window id in window linked list of the session. * Find a window from window id in window linked list of the session.
*/ */
@ -1326,6 +1353,86 @@ copy_region(const session_t *ps, XserverRegion oldregion) {
return region; return region;
} }
/**
* Determine if a window has a specific property.
*
* @param ps current session
* @param w window to check
* @param atom atom of property to check
* @return 1 if it has the attribute, 0 otherwise
*/
static inline bool
wid_has_prop(const session_t *ps, Window w, Atom atom) {
Atom type = None;
int format;
unsigned long nitems, after;
unsigned char *data;
if (Success == XGetWindowProperty(ps->dpy, w, atom, 0, 0, False,
AnyPropertyType, &type, &format, &nitems, &after, &data)) {
XFree(data);
if (type) return true;
}
return false;
}
winprop_t
wid_get_prop_adv(const session_t *ps, Window w, Atom atom, long offset,
long length, Atom rtype, int rformat);
/**
* Wrapper of wid_get_prop_adv().
*/
static inline winprop_t
wid_get_prop(const session_t *ps, Window wid, Atom atom, long length,
Atom rtype, int rformat) {
return wid_get_prop_adv(ps, wid, atom, 0L, length, rtype, rformat);
}
/**
* Get the numeric property value from a win_prop_t.
*/
static inline long
winprop_get_int(winprop_t prop) {
long tgt = 0;
if (!prop.nitems)
return 0;
switch (prop.format) {
case 8: tgt = *(prop.data.p8); break;
case 16: tgt = *(prop.data.p16); break;
case 32: tgt = *(prop.data.p32); break;
default: assert(0);
break;
}
return tgt;
}
bool
wid_get_text_prop(session_t *ps, Window wid, Atom prop,
char ***pstrlst, int *pnstr);
/**
* Free a <code>winprop_t</code>.
*
* @param pprop pointer to the <code>winprop_t</code> to free.
*/
static inline void
free_winprop(winprop_t *pprop) {
// Empty the whole structure to avoid possible issues
if (pprop->data.p8) {
XFree(pprop->data.p8);
pprop->data.p8 = NULL;
}
pprop->nitems = 0;
}
void
force_repaint(session_t *ps);
#ifdef CONFIG_DBUS #ifdef CONFIG_DBUS
/** @name DBus handling /** @name DBus handling
*/ */
@ -1363,8 +1470,25 @@ win_set_focused_force(session_t *ps, win *w, switch_t val);
void void
win_set_invert_color_force(session_t *ps, win *w, switch_t val); win_set_invert_color_force(session_t *ps, win *w, switch_t val);
void
force_repaint(session_t *ps);
//!@} //!@}
#endif #endif
#ifdef CONFIG_C2
/** @name c2
*/
///@{
c2_lptr_t *
c2_parse(session_t *ps, c2_lptr_t **pcondlst, char *pattern);
c2_lptr_t *
c2_free_lptr(c2_lptr_t *lp);
bool
c2_match(session_t *ps, win *w, const c2_lptr_t *condlst,
const c2_lptr_t **cache);
#endif
///@}
#endif

View File

@ -13,7 +13,7 @@
// === Global constants === // === Global constants ===
/// Name strings for window types. /// Name strings for window types.
const char *WINTYPES[NUM_WINTYPES] = { const char * const WINTYPES[NUM_WINTYPES] = {
"unknown", "unknown",
"desktop", "desktop",
"dock", "dock",
@ -31,9 +31,16 @@ const char *WINTYPES[NUM_WINTYPES] = {
"dnd", "dnd",
}; };
/// Names of VSync modes
const char * const VSYNC_STRS[NUM_VSYNC] = {
"none", // VSYNC_NONE
"drm", // VSYNC_DRM
"opengl", // VSYNC_OPENGL
};
/// Names of root window properties that could point to a pixmap of /// Names of root window properties that could point to a pixmap of
/// background. /// background.
const char *background_props_str[] = { const static char *background_props_str[] = {
"_XROOTPMAP_ID", "_XROOTPMAP_ID",
"_XSETROOT_ID", "_XSETROOT_ID",
0, 0,
@ -534,6 +541,52 @@ should_ignore(session_t *ps, unsigned long sequence) {
// === Windows === // === Windows ===
/**
* Get a specific attribute of a window.
*
* Returns a blank structure if the returned type and format does not
* match the requested type and format.
*
* @param ps current session
* @param w window
* @param atom atom of attribute to fetch
* @param length length to read
* @param rtype atom of the requested type
* @param rformat requested format
* @return a <code>winprop_t</code> structure containing the attribute
* and number of items. A blank one on failure.
*/
winprop_t
wid_get_prop_adv(const session_t *ps, Window w, Atom atom, long offset,
long length, Atom rtype, int rformat) {
Atom type = None;
int format = 0;
unsigned long nitems = 0, after = 0;
unsigned char *data = NULL;
if (Success == XGetWindowProperty(ps->dpy, w, atom, offset, length,
False, rtype, &type, &format, &nitems, &after, &data)
&& nitems && (AnyPropertyType == type || type == rtype)
&& (!format || format == rformat)
&& (8 == format || 16 == format || 32 == format)) {
return (winprop_t) {
.data.p8 = data,
.nitems = nitems,
.type = type,
.format = format,
};
}
XFree(data);
return (winprop_t) {
.data.p8 = NULL,
.nitems = 0,
.type = AnyPropertyType,
.format = 0
};
}
/** /**
* Check if a window has rounded corners. * Check if a window has rounded corners.
*/ */
@ -966,6 +1019,8 @@ root_tile_f(session_t *ps) {
c.alpha = 0xffff; c.alpha = 0xffff;
XRenderFillRectangle( XRenderFillRectangle(
ps->dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); ps->dpy, PictOpSrc, picture, &c, 0, 0, 1, 1);
free_pixmap(ps, &pixmap);
} }
return picture; return picture;
@ -2120,10 +2175,8 @@ win_determine_mode(session_t *ps, win *w) {
* > window type default opacity (if not opaque) * > window type default opacity (if not opaque)
* > inactive_opacity * > inactive_opacity
* *
* @param dpy X display to use * @param ps current session
* @param w struct _win object representing the window * @param w struct _win object representing the window
* @param refetch_prop whether _NET_WM_OPACITY of the window needs to be
* refetched
*/ */
static void static void
calc_opacity(session_t *ps, win *w) { calc_opacity(session_t *ps, win *w) {
@ -2858,9 +2911,9 @@ root_damaged(session_t *ps) {
add_damage(ps, parts); add_damage(ps, parts);
} */ } */
} }
// Mark screen damaged if we are painting on overlay
if (ps->o.paint_on_overlay) // Mark screen damaged
add_damage(ps, get_screen_region(ps)); force_repaint(ps);
} }
static void static void
@ -3133,7 +3186,7 @@ win_get_leader_raw(session_t *ps, win *w, int recursions) {
/** /**
* Get the value of a text property of a window. * Get the value of a text property of a window.
*/ */
static bool bool
wid_get_text_prop(session_t *ps, Window wid, Atom prop, wid_get_text_prop(session_t *ps, Window wid, Atom prop,
char ***pstrlst, int *pnstr) { char ***pstrlst, int *pnstr) {
XTextProperty text_prop = { NULL, None, 0, 0 }; XTextProperty text_prop = { NULL, None, 0, 0 };
@ -3282,6 +3335,19 @@ win_get_class(session_t *ps, win *w) {
return true; return true;
} }
/**
* Force a full-screen repaint.
*/
void
force_repaint(session_t *ps) {
assert(ps->screen_reg);
XserverRegion reg = None;
if (ps->screen_reg && (reg = copy_region(ps, ps->screen_reg))) {
ps->ev_received = true;
add_damage(ps, reg);
}
}
#ifdef CONFIG_DBUS #ifdef CONFIG_DBUS
/** @name DBus hooks /** @name DBus hooks
*/ */
@ -3319,18 +3385,6 @@ win_set_invert_color_force(session_t *ps, win *w, switch_t val) {
win_determine_invert_color(ps, w); 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 #endif
@ -4039,6 +4093,9 @@ usage(void) {
"--invert-color-include condition\n" "--invert-color-include condition\n"
" Specify a list of conditions of windows that should be painted with\n" " Specify a list of conditions of windows that should be painted with\n"
" inverted color. Resource-hogging, and is not well tested.\n" " inverted color. Resource-hogging, and is not well tested.\n"
"--dbus\n"
" Enable remote control via D-Bus. See the D-BUS API section in the\n"
" man page for more details.\n"
"\n" "\n"
"Format of a condition:\n" "Format of a condition:\n"
"\n" "\n"
@ -4068,7 +4125,6 @@ static void
register_cm(session_t *ps, bool want_glxct) { register_cm(session_t *ps, bool want_glxct) {
Atom a; Atom a;
char *buf; char *buf;
int len, s;
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
// Create a window with the wanted GLX visual // Create a window with the wanted GLX visual
@ -4128,8 +4184,8 @@ register_cm(session_t *ps, bool want_glxct) {
Xutf8SetWMProperties(ps->dpy, ps->reg_win, "xcompmgr", "xcompmgr", Xutf8SetWMProperties(ps->dpy, ps->reg_win, "xcompmgr", "xcompmgr",
NULL, 0, NULL, NULL, NULL); NULL, 0, NULL, NULL, NULL);
len = strlen(REGISTER_PROP) + 2; unsigned len = strlen(REGISTER_PROP) + 2;
s = ps->scr; int s = ps->scr;
while (s >= 10) { while (s >= 10) {
++len; ++len;
@ -4284,21 +4340,15 @@ open_config_file(char *cpath, char **ppath) {
*/ */
static inline void static inline void
parse_vsync(session_t *ps, const char *optarg) { parse_vsync(session_t *ps, const char *optarg) {
const static char * const vsync_str[] = {
"none", // VSYNC_NONE
"drm", // VSYNC_DRM
"opengl", // VSYNC_OPENGL
};
vsync_t i; vsync_t i;
for (i = 0; i < (sizeof(vsync_str) / sizeof(vsync_str[0])); ++i) for (i = 0; i < (sizeof(VSYNC_STRS) / sizeof(VSYNC_STRS[0])); ++i)
if (!strcasecmp(optarg, vsync_str[i])) { if (!strcasecmp(optarg, VSYNC_STRS[i])) {
ps->o.vsync = i; ps->o.vsync = i;
break; break;
} }
if ((sizeof(vsync_str) / sizeof(vsync_str[0])) == i) { if ((sizeof(VSYNC_STRS) / sizeof(VSYNC_STRS[0])) == i) {
fputs("Invalid --vsync argument. Ignored.\n", stderr); printf_errfq(1, "(\"%s\"): Invalid --vsync argument.", optarg);
} }
} }
@ -6114,6 +6164,11 @@ main(int argc, char **argv) {
printf_errf("Failed to create new session."); printf_errf("Failed to create new session.");
return 1; return 1;
} }
#ifdef DEBUG_C2
// c2_parse(ps_g, NULL, "name ~= \"master\"");
// c2_parse(ps_g, NULL, "n:e:Notification");
c2_parse(ps_g, NULL, "(WM_NAME:16s = 'Notification' || class_g = 'fox') && class_g = 'fox'");
#endif
session_run(ps_g); session_run(ps_g);
ps_old = ps_g; ps_old = ps_g;
session_destroy(ps_g); session_destroy(ps_g);

View File

@ -52,14 +52,6 @@ set_ignore_next(session_t *ps) {
static int static int
should_ignore(session_t *ps, unsigned long sequence); should_ignore(session_t *ps, unsigned long sequence);
/**
* Wrapper of XInternAtom() for convenience.
*/
static inline Atom
get_atom(session_t *ps, const char *atom_name) {
return XInternAtom(ps->dpy, atom_name, False);
}
/** /**
* Return the painting target window. * Return the painting target window.
*/ */
@ -291,122 +283,6 @@ static Picture
solid_picture(session_t *ps, bool argb, double a, solid_picture(session_t *ps, bool argb, double a,
double r, double g, double b); double r, double g, double b);
/**
* Determine if a window has a specific property.
*
* @param session_t current session
* @param w window to check
* @param atom atom of property to check
* @return 1 if it has the attribute, 0 otherwise
*/
static inline bool
wid_has_prop(const session_t *ps, Window w, Atom atom) {
Atom type = None;
int format;
unsigned long nitems, after;
unsigned char *data;
if (Success == XGetWindowProperty(ps->dpy, w, atom, 0, 0, False,
AnyPropertyType, &type, &format, &nitems, &after, &data)) {
XFree(data);
if (type) return true;
}
return false;
}
/**
* Get a specific attribute of a window.
*
* Returns a blank structure if the returned type and format does not
* match the requested type and format.
*
* @param session_t current session
* @param w window
* @param atom atom of attribute to fetch
* @param length length to read
* @param rtype atom of the requested type
* @param rformat requested format
* @return a <code>winprop_t</code> structure containing the attribute
* and number of items. A blank one on failure.
*/
// TODO: Move to compton.c
static winprop_t
wid_get_prop_adv(const session_t *ps, Window w, Atom atom, long offset,
long length, Atom rtype, int rformat) {
Atom type = None;
int format = 0;
unsigned long nitems = 0, after = 0;
unsigned char *data = NULL;
if (Success == XGetWindowProperty(ps->dpy, w, atom, offset, length,
False, rtype, &type, &format, &nitems, &after, &data)
&& nitems && (AnyPropertyType == type || type == rtype)
&& (!format || format == rformat)
&& (8 == format || 16 == format || 32 == format)) {
return (winprop_t) {
.data.p8 = data,
.nitems = nitems,
.type = type,
.format = format,
};
}
XFree(data);
return (winprop_t) {
.data.p8 = NULL,
.nitems = 0,
.type = AnyPropertyType,
.format = 0
};
}
/**
* Wrapper of wid_get_prop_adv().
*/
static inline winprop_t
wid_get_prop(const session_t *ps, Window wid, Atom atom, long length,
Atom rtype, int rformat) {
return wid_get_prop_adv(ps, wid, atom, 0L, length, rtype, rformat);
}
/**
* Get the numeric property value from a win_prop_t.
*/
static inline long
winprop_get_int(winprop_t prop) {
long tgt = 0;
if (!prop.nitems)
return 0;
switch (prop.format) {
case 8: tgt = *(prop.data.p8); break;
case 16: tgt = *(prop.data.p16); break;
case 32: tgt = *(prop.data.p32); break;
default: assert(0);
break;
}
return tgt;
}
/**
* Free a <code>winprop_t</code>.
*
* @param pprop pointer to the <code>winprop_t</code> to free.
*/
static inline void
free_winprop(winprop_t *pprop) {
// Empty the whole structure to avoid possible issues
if (pprop->data.p8) {
XFree(pprop->data.p8);
pprop->data.p8 = NULL;
}
pprop->nitems = 0;
}
/** /**
* Stop listening for events on a particular window. * Stop listening for events on a particular window.
*/ */
@ -768,10 +644,6 @@ error(Display *dpy, XErrorEvent *ev);
static void static void
expose_root(session_t *ps, XRectangle *rects, int nrects); expose_root(session_t *ps, XRectangle *rects, int nrects);
static bool
wid_get_text_prop(session_t *ps, Window wid, Atom prop,
char ***pstrlst, int *pnstr);
static Window static Window
wid_get_prop_window(session_t *ps, Window wid, Atom aprop); wid_get_prop_window(session_t *ps, Window wid, Atom aprop);

View File

@ -266,6 +266,48 @@ cdbus_apdarg_bool(session_t *ps, DBusMessage *msg, const void *data) {
return true; return true;
} }
/**
* Callback to append an int32 argument to a message.
*/
static bool
cdbus_apdarg_int32(session_t *ps, DBusMessage *msg, const void *data) {
if (!dbus_message_append_args(msg, DBUS_TYPE_INT32, data,
DBUS_TYPE_INVALID)) {
printf_errf("(): 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, DBusMessage *msg, const void *data) {
if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, data,
DBUS_TYPE_INVALID)) {
printf_errf("(): 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, DBusMessage *msg, const void *data) {
if (!dbus_message_append_args(msg, DBUS_TYPE_DOUBLE, data,
DBUS_TYPE_INVALID)) {
printf_errf("(): Failed to append argument.");
return false;
}
return true;
}
/** /**
* Callback to append a Window argument to a message. * Callback to append a Window argument to a message.
*/ */
@ -639,6 +681,21 @@ cdbus_process_win_get(session_t *ps, DBusMessage *msg) {
return true; \ return true; \
} }
cdbus_m_win_get_do(id, cdbus_reply_wid);
// next
if (!strcmp("next", target)) {
cdbus_reply_wid(ps, msg, (w->next ? w->next->id: 0));
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(client_win, cdbus_reply_wid);
cdbus_m_win_get_do(damaged, cdbus_reply_bool); cdbus_m_win_get_do(damaged, cdbus_reply_bool);
cdbus_m_win_get_do(destroyed, cdbus_reply_bool); cdbus_m_win_get_do(destroyed, cdbus_reply_bool);
@ -649,15 +706,22 @@ cdbus_process_win_get(session_t *ps, DBusMessage *msg) {
cdbus_m_win_get_do(shadow_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(focused_force, cdbus_reply_enum);
cdbus_m_win_get_do(invert_color_force, cdbus_reply_enum); cdbus_m_win_get_do(invert_color_force, cdbus_reply_enum);
if (!strcmp("map_state", target)) { cdbus_m_win_get_do(name, cdbus_reply_string);
cdbus_reply_bool(ps, msg, w->a.map_state); cdbus_m_win_get_do(class_instance, cdbus_reply_string);
return true; 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_uint32);
cdbus_m_win_get_do(frame_opacity, cdbus_reply_double);
cdbus_m_win_get_do(left_width, cdbus_reply_uint32);
cdbus_m_win_get_do(right_width, cdbus_reply_uint32);
cdbus_m_win_get_do(top_width, cdbus_reply_uint32);
cdbus_m_win_get_do(bottom_width, cdbus_reply_uint32);
#undef cdbus_m_win_get_do #undef cdbus_m_win_get_do
printf_errf("(): No matching target found."); printf_errf("(): " CDBUS_ERROR_BADTGT_S, target);
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);
return false; return true;
} }
/** /**
@ -723,9 +787,10 @@ cdbus_process_win_set(session_t *ps, DBusMessage *msg) {
} }
#undef cdbus_m_win_set_do #undef cdbus_m_win_set_do
printf_errf("(): No matching target found."); printf_errf("(): " CDBUS_ERROR_BADTGT_S, target);
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);
return false; return true;
cdbus_process_win_set_success: cdbus_process_win_set_success:
if (!dbus_message_get_no_reply(msg)) if (!dbus_message_get_no_reply(msg))
@ -761,9 +826,10 @@ cdbus_process_find_win(session_t *ps, DBusMessage *msg) {
wid = w->id; wid = w->id;
} }
else { else {
printf_errf("(): No matching target found."); printf_errf("(): " CDBUS_ERROR_BADTGT_S, target);
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);
return false; return true;
} }
cdbus_reply_wid(ps, msg, wid); cdbus_reply_wid(ps, msg, wid);
@ -787,7 +853,12 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
return true; \ return true; \
} }
cdbus_m_opts_get_do(display, cdbus_reply_string); // display
if (!strcmp("display", target)) {
cdbus_reply_string(ps, msg, DisplayString(ps->dpy));
return true;
}
cdbus_m_opts_get_do(mark_wmwin_focused, cdbus_reply_bool); 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(mark_ovredir_focused, cdbus_reply_bool);
cdbus_m_opts_get_do(fork_after_register, cdbus_reply_bool); cdbus_m_opts_get_do(fork_after_register, cdbus_reply_bool);
@ -797,12 +868,45 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
cdbus_m_opts_get_do(logpath, cdbus_reply_string); cdbus_m_opts_get_do(logpath, cdbus_reply_string);
cdbus_m_opts_get_do(synchronize, cdbus_reply_bool); cdbus_m_opts_get_do(synchronize, cdbus_reply_bool);
cdbus_m_opts_get_do(refresh_rate, cdbus_reply_int32);
cdbus_m_opts_get_do(sw_opti, cdbus_reply_bool);
if (!strcmp("vsync", target)) {
assert(ps->o.vsync < sizeof(VSYNC_STRS) / sizeof(VSYNC_STRS[0]));
cdbus_reply_string(ps, msg, VSYNC_STRS[ps->o.vsync]);
return true;
}
cdbus_m_opts_get_do(dbe, cdbus_reply_bool);
cdbus_m_opts_get_do(vsync_aggressive, cdbus_reply_bool);
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(clear_shadow, cdbus_reply_bool); cdbus_m_opts_get_do(clear_shadow, cdbus_reply_bool);
cdbus_m_opts_get_do(blur_background, 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(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(track_focus, cdbus_reply_bool);
cdbus_m_opts_get_do(track_wdata, cdbus_reply_bool);
cdbus_m_opts_get_do(track_leader, cdbus_reply_bool);
#undef cdbus_m_opts_get_do #undef cdbus_m_opts_get_do
printf_errf("(): No matching target found."); printf_errf("(): " CDBUS_ERROR_BADTGT_S, target);
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);
return false; return true;
} }
/** /**
@ -849,9 +953,10 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg) {
} }
#undef cdbus_m_opts_set_do #undef cdbus_m_opts_set_do
printf_errf("(): No matching target found."); printf_errf("(): " CDBUS_ERROR_BADTGT_S, target);
cdbus_reply_err(ps, msg, CDBUS_ERROR_BADTGT, CDBUS_ERROR_BADTGT_S, target);
return false; return true;
cdbus_process_opts_set_success: cdbus_process_opts_set_success:
if (!dbus_message_get_no_reply(msg)) if (!dbus_message_get_no_reply(msg))
@ -868,6 +973,11 @@ cdbus_process_introspect(session_t *ps, DBusMessage *msg) {
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
" \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" " \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
"<node name='" CDBUS_OBJECT_NAME "'>\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='" CDBUS_INTERFACE_NAME "'>\n" " <interface name='" CDBUS_INTERFACE_NAME "'>\n"
" <signal name='win_added'>\n" " <signal name='win_added'>\n"
" <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n" " <arg name='wid' type='" CDBUS_TYPE_WINDOW_STR "'/>\n"

View File

@ -24,6 +24,8 @@
#define CDBUS_ERROR_BADARG_S "Something wrong in arguments?" #define CDBUS_ERROR_BADARG_S "Something wrong in arguments?"
#define CDBUS_ERROR_BADWIN CDBUS_ERROR_PREFIX ".bad_window" #define CDBUS_ERROR_BADWIN CDBUS_ERROR_PREFIX ".bad_window"
#define CDBUS_ERROR_BADWIN_S "Requested window %#010lx not found." #define CDBUS_ERROR_BADWIN_S "Requested window %#010lx 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 CDBUS_ERROR_PREFIX ".forbidden"
#define CDBUS_ERROR_FORBIDDEN_S "Incorrect password, access denied." #define CDBUS_ERROR_FORBIDDEN_S "Incorrect password, access denied."
@ -75,6 +77,15 @@ cdbus_callback_watch_toggled(DBusWatch *watch, void *data);
static bool static bool
cdbus_apdarg_bool(session_t *ps, DBusMessage *msg, const void *data); cdbus_apdarg_bool(session_t *ps, DBusMessage *msg, const void *data);
static bool
cdbus_apdarg_int32(session_t *ps, DBusMessage *msg, const void *data);
static bool
cdbus_apdarg_uint32(session_t *ps, DBusMessage *msg, const void *data);
static bool
cdbus_apdarg_double(session_t *ps, DBusMessage *msg, const void *data);
static bool static bool
cdbus_apdarg_wid(session_t *ps, DBusMessage *msg, const void *data); cdbus_apdarg_wid(session_t *ps, DBusMessage *msg, const void *data);
@ -145,6 +156,30 @@ cdbus_reply_bool(session_t *ps, DBusMessage *srcmsg, bool bval) {
return cdbus_reply(ps, srcmsg, cdbus_apdarg_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 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. * Send a reply with a wid argument.
*/ */