summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Grenville <pyxlcy@gmail.com>2013-01-19 20:20:27 +0800
committerRichard Grenville <pyxlcy@gmail.com>2013-01-19 20:20:27 +0800
commit32132312985e3a7f63444dcd4b54f821520a6042 (patch)
treee00f787bf4b13ca6b4e92eec1bea392ad2296499
parenta5dc829944175cab684e5b4488ddff409f308099 (diff)
downloadtdebase-32132312985e3a7f63444dcd4b54f821520a6042.tar.gz
tdebase-32132312985e3a7f63444dcd4b54f821520a6042.zip
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).
-rw-r--r--common.h1370
-rw-r--r--compton.c155
-rw-r--r--compton.h1256
-rw-r--r--dbus.c920
-rw-r--r--dbus.h213
5 files changed, 2650 insertions, 1264 deletions
diff --git a/common.h b/common.h
new file mode 100644
index 000000000..31c9c2002
--- /dev/null
+++ b/common.h
@@ -0,0 +1,1370 @@
+/*
+ * Compton - a compositor for X11
+ *
+ * Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
+ *
+ * Copyright (c) 2011-2013, Christopher Jeffrey
+ * See LICENSE for more information.
+ *
+ */
+
+// === Options ===
+
+// Debug options, enable them using -D in CFLAGS
+// #define DEBUG_REPAINT 1
+// #define DEBUG_EVENTS 1
+// #define DEBUG_RESTACK 1
+// #define DEBUG_WINTYPE 1
+// #define DEBUG_CLIENTWIN 1
+// #define DEBUG_WINDATA 1
+// #define DEBUG_WINMATCH 1
+// #define DEBUG_REDIR 1
+// #define DEBUG_ALLOC_REG 1
+// #define DEBUG_FRAME 1
+// #define DEBUG_LEADER 1
+// #define MONITOR_REPAINT 1
+
+// Whether to enable PCRE regular expression support in blacklists, enabled
+// by default
+// #define CONFIG_REGEX_PCRE 1
+// Whether to enable JIT support of libpcre. This may cause problems on PaX
+// kernels.
+// #define CONFIG_REGEX_PCRE_JIT 1
+// Whether to enable parsing of configuration files using libconfig.
+// #define CONFIG_LIBCONFIG 1
+// Whether we are using a legacy version of libconfig (1.3.x).
+// #define CONFIG_LIBCONFIG_LEGACY 1
+// Whether to enable DRM VSync support
+// #define CONFIG_VSYNC_DRM 1
+// Whether to enable OpenGL VSync support
+// #define CONFIG_VSYNC_OPENGL 1
+// Whether to enable DBus support with libdbus.
+// #define CONFIG_DBUS 1
+
+// === Includes ===
+
+// For some special functions
+#define _GNU_SOURCE
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/poll.h>
+#include <assert.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/Xrender.h>
+#include <X11/extensions/shape.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/extensions/Xdbe.h>
+
+// libpcre
+#ifdef CONFIG_REGEX_PCRE
+#include <pcre.h>
+
+// For compatiblity with <libpcre-8.20
+#ifndef PCRE_STUDY_JIT_COMPILE
+#define PCRE_STUDY_JIT_COMPILE 0
+#define LPCRE_FREE_STUDY(extra) pcre_free(extra)
+#else
+#define LPCRE_FREE_STUDY(extra) pcre_free_study(extra)
+#endif
+
+#endif
+
+// libconfig
+#ifdef CONFIG_LIBCONFIG
+#include <libgen.h>
+#include <libconfig.h>
+#endif
+
+// libdbus
+#ifdef CONFIG_DBUS
+#include <dbus/dbus.h>
+#endif
+
+// libGL
+#ifdef CONFIG_VSYNC_OPENGL
+#include <GL/glx.h>
+#endif
+
+// === Macros ===
+
+#define MSTR_(s) #s
+#define MSTR(s) MSTR_(s)
+
+/// Print out an error message.
+#define printf_err(format, ...) \
+ fprintf(stderr, format "\n", ## __VA_ARGS__)
+
+/// Print out an error message with function name.
+#define printf_errf(format, ...) \
+ printf_err("%s" format, __func__, ## __VA_ARGS__)
+
+/// Print out an error message with function name, and quit with a
+/// specific exit code.
+#define printf_errfq(code, format, ...) { \
+ printf_err("%s" format, __func__, ## __VA_ARGS__); \
+ exit(code); \
+}
+
+/// Print out a debug message.
+#define printf_dbg(format, ...) \
+ printf(format, ## __VA_ARGS__); \
+ fflush(stdout)
+
+/// Print out a debug message with function name.
+#define printf_dbgf(format, ...) \
+ printf_dbg("%s" format, __func__, ## __VA_ARGS__)
+
+// Use #s here to prevent macro expansion
+/// Macro used for shortening some debugging code.
+#define CASESTRRET(s) case s: return #s
+
+// === Constants ===
+#if !(COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2)
+#error libXcomposite version unsupported
+#endif
+
+#define ROUNDED_PERCENT 0.05
+#define ROUNDED_PIXELS 10
+
+#define OPAQUE 0xffffffff
+#define REGISTER_PROP "_NET_WM_CM_S"
+
+#define TIME_MS_MAX LONG_MAX
+#define FADE_DELTA_TOLERANCE 0.2
+#define SWOPTI_TOLERANCE 3000
+#define TIMEOUT_RUN_TOLERANCE 0.05
+#define WIN_GET_LEADER_MAX_RECURSION 20
+
+#define SEC_WRAP (15L * 24L * 60L * 60L)
+
+#define NS_PER_SEC 1000000000L
+#define US_PER_SEC 1000000L
+#define MS_PER_SEC 1000
+
+#define XRFILTER_CONVOLUTION "convolution"
+#define XRFILTER_GUASSIAN "gaussian"
+#define XRFILTER_BINOMIAL "binomial"
+
+// Window flags
+
+// Window size is changed
+#define WFLAG_SIZE_CHANGE 0x0001
+// Window size/position is changed
+#define WFLAG_POS_CHANGE 0x0002
+// Window opacity / dim state changed
+#define WFLAG_OPCT_CHANGE 0x0004
+
+// === Types ===
+
+typedef uint32_t opacity_t;
+typedef long time_ms_t;
+
+typedef enum {
+ WINTYPE_UNKNOWN,
+ WINTYPE_DESKTOP,
+ WINTYPE_DOCK,
+ WINTYPE_TOOLBAR,
+ WINTYPE_MENU,
+ WINTYPE_UTILITY,
+ WINTYPE_SPLASH,
+ WINTYPE_DIALOG,
+ WINTYPE_NORMAL,
+ WINTYPE_DROPDOWN_MENU,
+ WINTYPE_POPUP_MENU,
+ WINTYPE_TOOLTIP,
+ WINTYPE_NOTIFY,
+ WINTYPE_COMBO,
+ WINTYPE_DND,
+ NUM_WINTYPES
+} wintype_t;
+
+/// Enumeration type to represent switches.
+typedef enum {
+ OFF, // false
+ ON, // true
+ UNSET
+} switch_t;
+
+/// Enumeration type of window painting mode.
+typedef enum {
+ WMODE_TRANS,
+ WMODE_SOLID,
+ WMODE_ARGB
+} winmode_t;
+
+/// Structure representing needed window updates.
+typedef struct {
+ bool shadow : 1;
+ bool fade : 1;
+ bool focus : 1;
+ bool invert_color : 1;
+} win_upd_t;
+
+/// Structure representing Window property value.
+typedef struct {
+ // All pointers have the same length, right?
+ // I wanted to use anonymous union but it's a GNU extension...
+ union {
+ unsigned char *p8;
+ short *p16;
+ long *p32;
+ } data;
+ unsigned long nitems;
+ Atom type;
+ int format;
+} winprop_t;
+
+typedef struct _ignore {
+ struct _ignore *next;
+ unsigned long sequence;
+} ignore_t;
+
+enum wincond_target {
+ CONDTGT_NAME,
+ CONDTGT_CLASSI,
+ CONDTGT_CLASSG,
+ CONDTGT_ROLE,
+};
+
+enum wincond_type {
+ CONDTP_EXACT,
+ CONDTP_ANYWHERE,
+ CONDTP_FROMSTART,
+ CONDTP_WILDCARD,
+ CONDTP_REGEX_PCRE,
+};
+
+#define CONDF_IGNORECASE 0x0001
+
+typedef struct _wincond {
+ enum wincond_target target;
+ enum wincond_type type;
+ char *pattern;
+#ifdef CONFIG_REGEX_PCRE
+ pcre *regex_pcre;
+ pcre_extra *regex_pcre_extra;
+#endif
+ int16_t flags;
+ struct _wincond *next;
+} wincond_t;
+
+/// VSync modes.
+typedef enum {
+ VSYNC_NONE,
+ VSYNC_DRM,
+ VSYNC_OPENGL,
+} vsync_t;
+
+#ifdef CONFIG_VSYNC_OPENGL
+typedef int (*f_WaitVideoSync) (int, int, unsigned *);
+typedef int (*f_GetVideoSync) (unsigned *);
+#endif
+
+typedef struct {
+ int size;
+ double *data;
+} conv;
+
+/// Linked list type of atoms.
+typedef struct _latom {
+ Atom atom;
+ struct _latom *next;
+} latom_t;
+
+struct _timeout_t;
+
+struct _win;
+
+/// Structure representing all options.
+typedef struct {
+ // === General ===
+ char *display;
+ /// Whether to try to detect WM windows and mark them as focused.
+ bool mark_wmwin_focused;
+ /// Whether to mark override-redirect windows as focused.
+ bool mark_ovredir_focused;
+ /// Whether to fork to background.
+ bool fork_after_register;
+ /// Whether to detect rounded corners.
+ bool detect_rounded_corners;
+ /// Whether to paint on X Composite overlay window instead of root
+ /// window.
+ bool paint_on_overlay;
+ /// Whether to unredirect all windows if a full-screen opaque window
+ /// is detected.
+ bool unredir_if_possible;
+ /// Whether to enable D-Bus support.
+ bool dbus;
+ /// Path to log file.
+ char *logpath;
+ /// Whether to work under synchronized mode for debugging.
+ bool synchronize;
+
+ // === VSync & software optimization ===
+ /// User-specified refresh rate.
+ int refresh_rate;
+ /// Whether to enable refresh-rate-based software optimization.
+ bool sw_opti;
+ /// VSync method to use;
+ vsync_t vsync;
+ /// Whether to enable double buffer.
+ bool dbe;
+ /// Whether to do VSync aggressively.
+ bool vsync_aggressive;
+
+ // === Shadow ===
+ /// Enable/disable shadow for specific window types.
+ bool wintype_shadow[NUM_WINTYPES];
+ /// Red, green and blue tone of the shadow.
+ double shadow_red, shadow_green, shadow_blue;
+ int shadow_radius;
+ int shadow_offset_x, shadow_offset_y;
+ double shadow_opacity;
+ bool clear_shadow;
+ /// Shadow blacklist. A linked list of conditions.
+ wincond_t *shadow_blacklist;
+ /// Whether bounding-shaped window should be ignored.
+ bool shadow_ignore_shaped;
+ /// Whether to respect _COMPTON_SHADOW.
+ bool respect_prop_shadow;
+
+ // === Fading ===
+ /// Enable/disable fading for specific window types.
+ bool wintype_fade[NUM_WINTYPES];
+ /// How much to fade in in a single fading step.
+ opacity_t fade_in_step;
+ /// How much to fade out in a single fading step.
+ opacity_t fade_out_step;
+ /// Fading time delta. In milliseconds.
+ time_ms_t fade_delta;
+ /// Whether to disable fading on window open/close.
+ bool no_fading_openclose;
+ /// Fading blacklist. A linked list of conditions.
+ wincond_t *fade_blacklist;
+
+ // === Opacity ===
+ /// Default opacity for specific window types
+ double wintype_opacity[NUM_WINTYPES];
+ /// Default opacity for inactive windows.
+ /// 32-bit integer with the format of _NET_WM_OPACITY. 0 stands for
+ /// not enabled, default.
+ opacity_t inactive_opacity;
+ /// Whether inactive_opacity overrides the opacity set by window
+ /// attributes.
+ bool inactive_opacity_override;
+ /// Frame opacity. Relative to window opacity, also affects shadow
+ /// opacity.
+ double frame_opacity;
+ /// Whether to detect _NET_WM_OPACITY on client windows. Used on window
+ /// managers that don't pass _NET_WM_OPACITY to frame windows.
+ bool detect_client_opacity;
+ /// Step for pregenerating alpha pictures. 0.01 - 1.0.
+ double alpha_step;
+
+ // === Other window processing ===
+ /// Whether to blur background of semi-transparent / ARGB windows.
+ bool blur_background;
+ /// Whether to blur background when the window frame is not opaque.
+ /// Implies blur_background.
+ bool blur_background_frame;
+ /// Whether to use fixed blur strength instead of adjusting according
+ /// to window opacity.
+ bool blur_background_fixed;
+ /// How much to dim an inactive window. 0.0 - 1.0, 0 to disable.
+ double inactive_dim;
+ /// Whether to use fixed inactive dim opacity, instead of deciding
+ /// based on window opacity.
+ bool inactive_dim_fixed;
+ /// Conditions of windows to have inverted colors.
+ wincond_t *invert_color_list;
+
+ // === Focus related ===
+ /// Consider windows of specific types to be always focused.
+ bool wintype_focus[NUM_WINTYPES];
+ /// Whether to use EWMH _NET_ACTIVE_WINDOW to find active window.
+ bool use_ewmh_active_win;
+ /// A list of windows always to be considered focused.
+ wincond_t *focus_blacklist;
+ /// Whether to do window grouping with <code>WM_TRANSIENT_FOR</code>.
+ bool detect_transient;
+ /// Whether to do window grouping with <code>WM_CLIENT_LEADER</code>.
+ bool detect_client_leader;
+
+ // === Calculated ===
+ /// Whether compton needs to track focus changes.
+ bool track_focus;
+ /// Whether compton needs to track window name and class.
+ bool track_wdata;
+ /// Whether compton needs to track window leaders.
+ bool track_leader;
+} options_t;
+
+/// Structure containing all necessary data for a compton session.
+typedef struct {
+ // === Display related ===
+ /// Display in use.
+ Display *dpy;
+ /// Default screen.
+ int scr;
+ /// Default visual.
+ Visual *vis;
+ /// Default depth.
+ int depth;
+ /// Root window.
+ Window root;
+ /// Height of root window.
+ int root_height;
+ /// Width of root window.
+ int root_width;
+ // Damage of root window.
+ // Damage root_damage;
+ /// X Composite overlay window. Used if <code>--paint-on-overlay</code>.
+ Window overlay;
+ /// Picture of the root window background.
+ Picture root_tile;
+ /// A region of the size of the screen.
+ XserverRegion screen_reg;
+ /// Picture of root window. Destination of painting in no-DBE painting
+ /// mode.
+ Picture root_picture;
+ /// A Picture acting as the painting target.
+ Picture tgt_picture;
+ /// Temporary buffer to paint to before sending to display.
+ Picture tgt_buffer;
+ /// DBE back buffer for root window. Used in DBE painting mode.
+ XdbeBackBuffer root_dbe;
+ /// Window ID of the window we register as a symbol.
+ Window reg_win;
+
+ // === Operation related ===
+ /// Program options.
+ options_t o;
+ /// File descriptors to check for reading.
+ fd_set *pfds_read;
+ /// File descriptors to check for writing.
+ fd_set *pfds_write;
+ /// File descriptors to check for exceptions.
+ fd_set *pfds_except;
+ /// Largest file descriptor in fd_set-s above.
+ int nfds_max;
+ /// Linked list of all timeouts.
+ struct _timeout_t *tmout_lst;
+ /// Whether we have received an event in this cycle.
+ bool ev_received;
+ /// Whether the program is idling. I.e. no fading, no potential window
+ /// changes.
+ bool idling;
+ /// Program start time.
+ struct timeval time_start;
+ /// The region needs to painted on next paint.
+ XserverRegion all_damage;
+ /// Whether all windows are currently redirected.
+ bool redirected;
+ /// Whether there's a highest full-screen window, and all windows could
+ /// be unredirected.
+ bool unredir_possible;
+ /// Pre-generated alpha pictures.
+ Picture *alpha_picts;
+ /// Whether all reg_ignore of windows should expire in this paint.
+ bool reg_ignore_expire;
+ /// Time of last fading. In milliseconds.
+ time_ms_t fade_time;
+ /// Head pointer of the error ignore linked list.
+ ignore_t *ignore_head;
+ /// Pointer to the <code>next</code> member of tail element of the error
+ /// ignore linked list.
+ ignore_t **ignore_tail;
+ /// Reset program after next paint.
+ bool reset;
+
+ // === Expose event related ===
+ /// Pointer to an array of <code>XRectangle</code>-s of exposed region.
+ XRectangle *expose_rects;
+ /// Number of <code>XRectangle</code>-s in <code>expose_rects</code>.
+ int size_expose;
+ /// Index of the next free slot in <code>expose_rects</code>.
+ int n_expose;
+
+ // === Window related ===
+ /// Linked list of all windows.
+ struct _win *list;
+ /// Pointer to <code>win</code> of current active window. Used by
+ /// EWMH <code>_NET_ACTIVE_WINDOW</code> focus detection. In theory,
+ /// it's more reliable to store the window ID directly here, just in
+ /// case the WM does something extraordinary, but caching the pointer
+ /// means another layer of complexity.
+ struct _win *active_win;
+ /// Window ID of leader window of currently active window. Used for
+ /// subsidiary window detection.
+ Window active_leader;
+
+ // === Shadow/dimming related ===
+ /// 1x1 black Picture.
+ Picture black_picture;
+ /// 1x1 Picture of the shadow color.
+ Picture cshadow_picture;
+ /// 1x1 white Picture.
+ Picture white_picture;
+ /// Gaussian map of shadow.
+ conv *gaussian_map;
+ // for shadow precomputation
+ /// Shadow depth on one side.
+ int cgsize;
+ /// Pre-computed color table for corners of shadow.
+ unsigned char *shadow_corner;
+ /// Pre-computed color table for a side of shadow.
+ unsigned char *shadow_top;
+
+ // === Software-optimization-related ===
+ /// Currently used refresh rate.
+ short refresh_rate;
+ /// Interval between refresh in nanoseconds.
+ long refresh_intv;
+ /// Nanosecond offset of the first painting.
+ long paint_tm_offset;
+
+ #ifdef CONFIG_VSYNC_DRM
+ // === DRM VSync related ===
+ /// File descriptor of DRI device file. Used for DRM VSync.
+ int drm_fd;
+ #endif
+
+ #ifdef CONFIG_VSYNC_OPENGL
+ // === OpenGL VSync related ===
+ /// GLX context.
+ GLXContext glx_context;
+ /// Pointer to glXGetVideoSyncSGI function.
+ f_GetVideoSync glx_get_video_sync;
+ /// Pointer to glXWaitVideoSyncSGI function.
+ f_WaitVideoSync glx_wait_video_sync;
+ #endif
+
+ // === X extension related ===
+ /// Event base number for X Fixes extension.
+ int xfixes_event;
+ /// Error base number for X Fixes extension.
+ int xfixes_error;
+ /// Event base number for X Damage extension.
+ int damage_event;
+ /// Error base number for X Damage extension.
+ int damage_error;
+ /// Event base number for X Render extension.
+ int render_event;
+ /// Error base number for X Render extension.
+ int render_error;
+ /// Event base number for X Composite extension.
+ int composite_event;
+ /// Error base number for X Composite extension.
+ int composite_error;
+ /// Major opcode for X Composite extension.
+ int composite_opcode;
+ /// Whether X Composite NameWindowPixmap is available. Aka if X
+ /// Composite version >= 0.2.
+ bool has_name_pixmap;
+ /// Whether X Shape extension exists.
+ bool shape_exists;
+ /// Event base number for X Shape extension.
+ int shape_event;
+ /// Error base number for X Shape extension.
+ int shape_error;
+ /// Whether X RandR extension exists.
+ bool randr_exists;
+ /// Event base number for X RandR extension.
+ int randr_event;
+ /// Error base number for X RandR extension.
+ int randr_error;
+ #ifdef CONFIG_VSYNC_OPENGL
+ /// Whether X GLX extension exists.
+ bool glx_exists;
+ /// Event base number for X GLX extension.
+ int glx_event;
+ /// Error base number for X GLX extension.
+ int glx_error;
+ #endif
+ /// Whether X DBE extension exists.
+ bool dbe_exists;
+ /// Whether X Render convolution filter exists.
+ bool xrfilter_convolution_exists;
+
+ // === Atoms ===
+ /// Atom of property <code>_NET_WM_OPACITY</code>.
+ Atom atom_opacity;
+ /// Atom of <code>_NET_FRAME_EXTENTS</code>.
+ Atom atom_frame_extents;
+ /// Property atom to identify top-level frame window. Currently
+ /// <code>WM_STATE</code>.
+ Atom atom_client;
+ /// Atom of property <code>WM_NAME</code>.
+ Atom atom_name;
+ /// Atom of property <code>_NET_WM_NAME</code>.
+ Atom atom_name_ewmh;
+ /// Atom of property <code>WM_CLASS</code>.
+ Atom atom_class;
+ /// Atom of property <code>WM_WINDOW_ROLE</code>.
+ Atom atom_role;
+ /// Atom of property <code>WM_TRANSIENT_FOR</code>.
+ Atom atom_transient;
+ /// Atom of property <code>WM_CLIENT_LEADER</code>.
+ Atom atom_client_leader;
+ /// Atom of property <code>_NET_ACTIVE_WINDOW</code>.
+ Atom atom_ewmh_active_win;
+ /// Atom of property <code>_COMPTON_SHADOW</code>.
+ Atom atom_compton_shadow;
+ /// Atom of property <code>_NET_WM_WINDOW_TYPE</code>.
+ Atom atom_win_type;
+ /// Array of atoms of all possible window types.
+ Atom atoms_wintypes[NUM_WINTYPES];
+ /// Linked list of additional atoms to track.
+ latom_t *track_atom_lst;
+
+#ifdef CONFIG_DBUS
+ // === DBus related ===
+ // DBus connection.
+ DBusConnection *dbus_conn;
+ // DBus service name.
+ char *dbus_service;
+#endif
+} session_t;
+
+/// Structure representing a top-level window compton manages.
+typedef struct _win {
+ /// Pointer to the next structure in the linked list.
+ struct _win *next;
+ /// Pointer to the next higher window to paint.
+ struct _win *prev_trans;
+
+ // Core members
+ /// ID of the top-level frame window.
+ Window id;
+ /// Window attributes.
+ XWindowAttributes a;
+ /// Window painting mode.
+ winmode_t mode;
+ /// Whether the window has been damaged at least once.
+ bool damaged;
+ /// Damage of the window.
+ Damage damage;
+ /// NameWindowPixmap of the window.
+ Pixmap pixmap;
+ /// Picture of the window.
+ Picture picture;
+ /// Bounding shape of the window.
+ XserverRegion border_size;
+ /// Region of the whole window, shadow region included.
+ XserverRegion extents;
+ /// Window flags. Definitions above.
+ int_fast16_t flags;
+ /// Whether there's a pending <code>ConfigureNotify</code> happening
+ /// when the window is unmapped.
+ bool need_configure;
+ /// Queued <code>ConfigureNotify</code> when the window is unmapped.
+ XConfigureEvent queue_configure;
+ /// Region to be ignored when painting. Basically the region where
+ /// higher opaque windows will paint upon. Depends on window frame
+ /// opacity state, window geometry, window mapped/unmapped state,
+ /// window mode, of this and all higher windows.
+ XserverRegion reg_ignore;
+ /// Cached width/height of the window including border.
+ int widthb, heightb;
+ /// Whether the window has been destroyed.
+ bool destroyed;
+ /// Whether the window is bounding-shaped.
+ bool bounding_shaped;
+ /// Whether the window just have rounded corners.
+ bool rounded_corners;
+ /// Whether this window is to be painted.
+ bool to_paint;
+ /// Whether this window is in open/close state.
+ bool in_openclose;
+
+ // Client window related members
+ /// ID of the top-level client window of the window.
+ Window client_win;
+ /// Type of the window.
+ wintype_t window_type;
+ /// Whether it looks like a WM window. We consider a window WM window if
+ /// it does not have a decedent with WM_STATE and it is not override-
+ /// redirected itself.
+ bool wmwin;
+ /// Leader window ID of the window.
+ Window leader;
+ /// Cached topmost window ID of the window.
+ Window cache_leader;
+
+ // Focus-related members
+ /// Whether the window is to be considered focused.
+ bool focused;
+ /// Override value of window focus state. Set by D-Bus method calls.
+ switch_t focused_force;
+ /// Whether the window is actually focused.
+ bool focused_real;
+
+ // Blacklist related members
+ /// Name of the window.
+ char *name;
+ /// Window instance class of the window.
+ char *class_instance;
+ /// Window general class of the window.
+ char *class_general;
+ /// <code>WM_WINDOW_ROLE</code> value of the window.
+ char *role;
+ wincond_t *cache_sblst;
+ wincond_t *cache_fblst;
+ wincond_t *cache_fcblst;
+ wincond_t *cache_ivclst;
+
+ // Opacity-related members
+ /// Current window opacity.
+ opacity_t opacity;
+ /// Target window opacity.
+ opacity_t opacity_tgt;
+ /// Cached value of opacity window attribute.
+ opacity_t opacity_prop;
+ /// Cached value of opacity window attribute on client window. For
+ /// broken window managers not transferring client window's
+ /// _NET_WM_OPACITY value
+ opacity_t opacity_prop_client;
+ /// Alpha mask Picture to render window with opacity.
+ Picture alpha_pict;
+
+ // Fading-related members
+ /// Do not fade if it's false. Change on window type change.
+ /// Used by fading blacklist in the future.
+ bool fade;
+ /// Callback to be called after fading completed.
+ void (*fade_callback) (session_t *ps, struct _win *w);
+
+ // Frame-opacity-related members
+ /// Current window frame opacity. Affected by window opacity.
+ double frame_opacity;
+ /// Alpha mask Picture to render window frame with opacity.
+ Picture frame_alpha_pict;
+ /// Frame widths. Determined by client window attributes.
+ unsigned int left_width, right_width, top_width, bottom_width;
+
+ // Shadow-related members
+ /// Whether a window has shadow. Calculated.
+ bool shadow;
+ /// Override value of window shadow state. Set by D-Bus method calls.
+ switch_t shadow_force;
+ /// Opacity of the shadow. Affected by window opacity and frame opacity.
+ double shadow_opacity;
+ /// X offset of shadow. Affected by commandline argument.
+ int shadow_dx;
+ /// Y offset of shadow. Affected by commandline argument.
+ int shadow_dy;
+ /// Width of shadow. Affected by window size and commandline argument.
+ int shadow_width;
+ /// Height of shadow. Affected by window size and commandline argument.
+ int shadow_height;
+ /// Picture to render shadow. Affected by window size.
+ Picture shadow_pict;
+ /// Alpha mask Picture to render shadow. Affected by shadow opacity.
+ Picture shadow_alpha_pict;
+ /// The value of _COMPTON_SHADOW attribute of the window. Below 0 for
+ /// none.
+ long prop_shadow;
+
+ // Dim-related members
+ /// Whether the window is to be dimmed.
+ bool dim;
+ /// Picture for dimming. Affected by user-specified inactive dim
+ /// opacity and window opacity.
+ Picture dim_alpha_pict;
+
+ /// Whether to invert window color.
+ bool invert_color;
+ /// Override value of window color inversion state. Set by D-Bus method
+ /// calls.
+ switch_t invert_color_force;
+} win;
+
+/// Temporary structure used for communication between
+/// <code>get_cfg()</code> and <code>parse_config()</code>.
+struct options_tmp {
+ bool no_dock_shadow;
+ bool no_dnd_shadow;
+ double menu_opacity;
+};
+
+/// Structure for a recorded timeout.
+typedef struct _timeout_t {
+ bool enabled;
+ void *data;
+ bool (*callback)(session_t *ps, struct _timeout_t *ptmout);
+ time_ms_t interval;
+ time_ms_t firstrun;
+ time_ms_t lastrun;
+ struct _timeout_t *next;
+} timeout_t;
+
+/// Enumeration for window event hints.
+typedef enum {
+ WIN_EVMODE_UNKNOWN,
+ WIN_EVMODE_FRAME,
+ WIN_EVMODE_CLIENT
+} win_evmode_t;
+
+extern const char *WINTYPES[NUM_WINTYPES];
+extern session_t *ps_g;
+
+// == Debugging code ==
+static inline void
+print_timestamp(session_t *ps);
+
+#ifdef DEBUG_ALLOC_REG
+
+#include <execinfo.h>
+#define BACKTRACE_SIZE 5
+
+/**
+ * Print current backtrace, excluding the first two items.
+ *
+ * Stolen from glibc manual.
+ */
+static inline void
+print_backtrace(void) {
+ void *array[BACKTRACE_SIZE];
+ size_t size;
+ char **strings;
+
+ size = backtrace(array, BACKTRACE_SIZE);
+ strings = backtrace_symbols(array, size);
+
+ for (size_t i = 2; i < size; i++)
+ printf ("%s\n", strings[i]);
+
+ free(strings);
+}
+
+/**
+ * Wrapper of <code>XFixesCreateRegion</code>, for debugging.
+ */
+static inline XserverRegion
+XFixesCreateRegion_(Display *dpy, XRectangle *p, int n,
+ const char *func, int line) {
+ XserverRegion reg = XFixesCreateRegion(dpy, p, n);
+ print_timestamp(ps_g);
+ printf("%#010lx: XFixesCreateRegion() in %s():%d\n", reg, func, line);
+ print_backtrace();
+ fflush(stdout);
+ return reg;
+}
+
+/**
+ * Wrapper of <code>XFixesDestroyRegion</code>, for debugging.
+ */
+static inline void
+XFixesDestroyRegion_(Display *dpy, XserverRegion reg,
+ const char *func, int line) {
+ XFixesDestroyRegion(dpy, reg);
+ print_timestamp(ps_g);
+ printf("%#010lx: XFixesDestroyRegion() in %s():%d\n", reg, func, line);
+ fflush(stdout);
+}
+
+#define XFixesCreateRegion(dpy, p, n) XFixesCreateRegion_(dpy, p, n, __func__, __LINE__)
+#define XFixesDestroyRegion(dpy, reg) XFixesDestroyRegion_(dpy, reg, __func__, __LINE__)
+#endif
+
+// === Functions ===
+
+/**
+ * Return whether a struct timeval value is empty.
+ */
+static inline bool
+timeval_isempty(struct timeval *ptv) {
+ if (!ptv)
+ return false;
+
+ return ptv->tv_sec <= 0 && ptv->tv_usec <= 0;
+}
+
+/**
+ * Compare a struct timeval with a time in milliseconds.
+ *
+ * @return > 0 if ptv > ms, 0 if ptv == 0, -1 if ptv < ms
+ */
+static inline int
+timeval_ms_cmp(struct timeval *ptv, time_ms_t ms) {
+ assert(ptv);
+
+ // We use those if statement instead of a - expression because of possible
+ // truncation problem from long to int.
+ {
+ long sec = ms / MS_PER_SEC;
+ if (ptv->tv_sec > sec)
+ return 1;
+ if (ptv->tv_sec < sec)
+ return -1;
+ }
+
+ {
+ long usec = ms % MS_PER_SEC * (US_PER_SEC / MS_PER_SEC);
+ if (ptv->tv_usec > usec)
+ return 1;
+ if (ptv->tv_usec < usec)
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Subtracting two struct timeval values.
+ *
+ * Taken from glibc manual.
+ *
+ * Subtract the `struct timeval' values X and Y,
+ * storing the result in RESULT.
+ * Return 1 if the difference is negative, otherwise 0.
+ */
+static inline int
+timeval_subtract(struct timeval *result,
+ struct timeval *x,
+ struct timeval *y) {
+ /* Perform the carry for the later subtraction by updating y. */
+ if (x->tv_usec < y->tv_usec) {
+ long nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
+ y->tv_usec -= 1000000 * nsec;
+ y->tv_sec += nsec;
+ }
+
+ if (x->tv_usec - y->tv_usec > 1000000) {
+ long nsec = (x->tv_usec - y->tv_usec) / 1000000;
+ y->tv_usec += 1000000 * nsec;
+ y->tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait.
+ tv_usec is certainly positive. */
+ result->tv_sec = x->tv_sec - y->tv_sec;
+ result->tv_usec = x->tv_usec - y->tv_usec;
+
+ /* Return 1 if result is negative. */
+ return x->tv_sec < y->tv_sec;
+}
+
+/**
+ * Subtracting two struct timespec values.
+ *
+ * Taken from glibc manual.
+ *
+ * Subtract the `struct timespec' values X and Y,
+ * storing the result in RESULT.
+ * Return 1 if the difference is negative, otherwise 0.
+ */
+static inline int
+timespec_subtract(struct timespec *result,
+ struct timespec *x,
+ struct timespec *y) {
+ /* Perform the carry for the later subtraction by updating y. */
+ if (x->tv_nsec < y->tv_nsec) {
+ long nsec = (y->tv_nsec - x->tv_nsec) / NS_PER_SEC + 1;
+ y->tv_nsec -= NS_PER_SEC * nsec;
+ y->tv_sec += nsec;
+ }
+
+ if (x->tv_nsec - y->tv_nsec > NS_PER_SEC) {
+ long nsec = (x->tv_nsec - y->tv_nsec) / NS_PER_SEC;
+ y->tv_nsec += NS_PER_SEC * nsec;
+ y->tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait.
+ tv_nsec is certainly positive. */
+ result->tv_sec = x->tv_sec - y->tv_sec;
+ result->tv_nsec = x->tv_nsec - y->tv_nsec;
+
+ /* Return 1 if result is negative. */
+ return x->tv_sec < y->tv_sec;
+}
+
+/**
+ * Get current time in struct timeval.
+ */
+static inline struct timeval __attribute__((const))
+get_time_timeval(void) {
+ struct timeval tv = { 0, 0 };
+
+ gettimeofday(&tv, NULL);
+
+ // Return a time of all 0 if the call fails
+ return tv;
+}
+
+/**
+ * Get current time in struct timespec.
+ *
+ * Note its starting time is unspecified.
+ */
+static inline struct timespec __attribute__((const))
+get_time_timespec(void) {
+ struct timespec tm = { 0, 0 };
+
+ clock_gettime(CLOCK_MONOTONIC, &tm);
+
+ // Return a time of all 0 if the call fails
+ return tm;
+}
+
+
+/**
+ * Print time passed since program starts execution.
+ *
+ * Used for debugging.
+ */
+static inline void
+print_timestamp(session_t *ps) {
+ struct timeval tm, diff;
+
+ if (gettimeofday(&tm, NULL)) return;
+
+ timeval_subtract(&diff, &tm, &ps->time_start);
+ printf("[ %5ld.%02ld ] ", diff.tv_sec, diff.tv_usec / 10000);
+}
+
+/**
+ * Allocate the space and copy a string.
+ */
+static inline char * __attribute__((const))
+mstrcpy(const char *src) {
+ char *str = malloc(sizeof(char) * (strlen(src) + 1));
+
+ strcpy(str, src);
+
+ return str;
+}
+
+/**
+ * Allocate the space and copy a string.
+ */
+static inline char * __attribute__((const))
+mstrncpy(const char *src, unsigned len) {
+ char *str = malloc(sizeof(char) * (len + 1));
+
+ strncpy(str, src, len);
+
+ return str;
+}
+
+/**
+ * Allocate the space and join two strings.
+ */
+static inline char * __attribute__((const))
+mstrjoin(const char *src1, const char *src2) {
+ char *str = malloc(sizeof(char) * (strlen(src1) + strlen(src2) + 1));
+
+ strcpy(str, src1);
+ strcat(str, src2);
+
+ return str;
+}
+
+/**
+ * Allocate the space and join two strings;
+ */
+static inline char * __attribute__((const))
+mstrjoin3(const char *src1, const char *src2, const char *src3) {
+ char *str = malloc(sizeof(char) * (strlen(src1) + strlen(src2)
+ + strlen(src3) + 1));
+
+ strcpy(str, src1);
+ strcat(str, src2);
+ strcat(str, src3);
+
+ return str;
+}
+
+/**
+ * Normalize an int value to a specific range.
+ *
+ * @param i int value to normalize
+ * @param min minimal value
+ * @param max maximum value
+ * @return normalized value
+ */
+static inline int __attribute__((const))
+normalize_i_range(int i, int min, int max) {
+ if (i > max) return max;
+ if (i < min) return min;
+ return i;
+}
+
+/**
+ * Select the larger integer of two.
+ */
+static inline int __attribute__((const))
+max_i(int a, int b) {
+ return (a > b ? a : b);
+}
+
+/**
+ * Select the smaller integer of two.
+ */
+static inline int __attribute__((const))
+min_i(int a, int b) {
+ return (a > b ? b : a);
+}
+
+/**
+ * Select the larger long integer of two.
+ */
+static inline long __attribute__((const))
+max_l(long a, long b) {
+ return (a > b ? a : b);
+}
+
+/**
+ * Select the smaller long integer of two.
+ */
+static inline long __attribute__((const))
+min_l(long a, long b) {
+ return (a > b ? b : a);
+}
+
+/**
+ * Normalize a double value to a specific range.
+ *
+ * @param d double value to normalize
+ * @param min minimal value
+ * @param max maximum value
+ * @return normalized value
+ */
+static inline double __attribute__((const))
+normalize_d_range(double d, double min, double max) {
+ if (d > max) return max;
+ if (d < min) return min;
+ return d;
+}
+
+/**
+ * Normalize a double value to 0.\ 0 - 1.\ 0.
+ *
+ * @param d double value to normalize
+ * @return normalized value
+ */
+static inline double __attribute__((const))
+normalize_d(double d) {
+ return normalize_d_range(d, 0.0, 1.0);
+}
+
+timeout_t *
+timeout_insert(session_t *ps, time_ms_t interval,
+ bool (*callback)(session_t *ps, timeout_t *ptmout), void *data);
+
+void
+timeout_invoke(session_t *ps, timeout_t *ptmout);
+
+bool
+timeout_drop(session_t *ps, timeout_t *prm);
+
+/**
+ * Add a file descriptor to a select() fd_set.
+ */
+static inline bool
+fds_insert_select(fd_set **ppfds, int fd) {
+ assert(fd <= FD_SETSIZE);
+
+ if (!*ppfds) {
+ if ((*ppfds = malloc(sizeof(fd_set)))) {
+ FD_ZERO(*ppfds);
+ }
+ else {
+ fprintf(stderr, "Failed to allocate memory for select() fdset.\n");
+ exit(1);
+ }
+ }
+
+ FD_SET(fd, *ppfds);
+
+ return true;
+}
+
+/**
+ * Add a new file descriptor to wait for.
+ */
+static inline bool
+fds_insert(session_t *ps, int fd, short events) {
+ bool result = true;
+
+ ps->nfds_max = max_i(fd + 1, ps->nfds_max);
+
+ if (POLLIN & events)
+ result = fds_insert_select(&ps->pfds_read, fd) && result;
+ if (POLLOUT & events)
+ result = fds_insert_select(&ps->pfds_write, fd) && result;
+ if (POLLPRI & events)
+ result = fds_insert_select(&ps->pfds_except, fd) && result;
+
+ return result;
+}
+
+/**
+ * Delete a file descriptor to wait for.
+ */
+static inline void
+fds_drop(session_t *ps, int fd, short events) {
+ // Drop fd from respective fd_set-s
+ if (POLLIN & events && ps->pfds_read)
+ FD_CLR(fd, ps->pfds_read);
+ if (POLLOUT & events && ps->pfds_write)
+ FD_CLR(fd, ps->pfds_write);
+ if (POLLPRI & events && ps->pfds_except)
+ FD_CLR(fd, ps->pfds_except);
+}
+
+#define CPY_FDS(key) \
+ fd_set * key = NULL; \
+ if (ps->key) { \
+ key = malloc(sizeof(fd_set)); \
+ memcpy(key, ps->key, sizeof(fd_set)); \
+ if (!key) { \
+ fprintf(stderr, "Failed to allocate memory for copying select() fdset.\n"); \
+ exit(1); \
+ } \
+ } \
+
+/**
+ * Poll for changes.
+ *
+ * poll() is much better than select(), but ppoll() does not exist on
+ * *BSD.
+ */
+static inline int
+fds_poll(session_t *ps, struct timeval *ptv) {
+ // Copy fds
+ CPY_FDS(pfds_read);
+ CPY_FDS(pfds_write);
+ CPY_FDS(pfds_except);
+
+ int ret = select(ps->nfds_max, pfds_read, pfds_write, pfds_except, ptv);
+
+ free(pfds_read);
+ free(pfds_write);
+ free(pfds_except);
+
+ return ret;
+}
+#undef CPY_FDS
+
+/**
+ * Find a window from window id in window linked list of the session.
+ */
+static inline win *
+find_win(session_t *ps, Window id) {
+ if (!id)
+ return NULL;
+
+ win *w;
+
+ for (w = ps->list; w; w = w->next) {
+ if (w->id == id && !w->destroyed)
+ return w;
+ }
+
+ return 0;
+}
+
+/**
+ * Find out the WM frame of a client window using existing data.
+ *
+ * @param id window ID
+ * @return struct _win object of the found window, NULL if not found
+ */
+static inline win *
+find_toplevel(session_t *ps, Window id) {
+ if (!id)
+ return NULL;
+
+ for (win *w = ps->list; w; w = w->next) {
+ if (w->client_win == id && !w->destroyed)
+ return w;
+ }
+
+ return NULL;
+}
+
+/**
+ * Find out the currently focused window.
+ *
+ * @return struct _win object of the found window, NULL if not found
+ */
+static inline win *
+find_focused(session_t *ps) {
+ if (!ps->o.track_focus)
+ return NULL;
+
+ for (win *w = ps->list; w; w = w->next) {
+ if (w->focused_real && !w->destroyed)
+ return w;
+ }
+
+ return NULL;
+}
+
+/**
+ * Copies a region
+ */
+static inline XserverRegion
+copy_region(const session_t *ps, XserverRegion oldregion) {
+ XserverRegion region = XFixesCreateRegion(ps->dpy, NULL, 0);
+
+ XFixesCopyRegion(ps->dpy, region, oldregion);
+
+ return region;
+}
+
+#ifdef CONFIG_DBUS
+/** @name DBus handling
+ */
+///@{
+bool
+cdbus_init(session_t *ps);
+
+void
+cdbus_destroy(session_t *ps);
+
+void
+cdbus_loop(session_t *ps);
+
+void
+cdbus_ev_win_added(session_t *ps, win *w);
+
+void
+cdbus_ev_win_destroyed(session_t *ps, win *w);
+
+void
+cdbus_ev_win_mapped(session_t *ps, win *w);
+
+void
+cdbus_ev_win_unmapped(session_t *ps, win *w);
+//!@}
+
+/** @name DBus hooks
+ */
+///@{
+void
+win_set_shadow_force(session_t *ps, win *w, switch_t val);
+
+void
+win_set_focused_force(session_t *ps, win *w, switch_t val);
+
+void
+win_set_invert_color_force(session_t *ps, win *w, switch_t val);
+
+void
+force_repaint(session_t *ps);
+//!@}
+#endif
diff --git a/compton.c b/compton.c
index f933d437d..90133d11c 100644
--- a/compton.c
+++ b/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;
diff --git a/compton.h b/compton.h
index 2154f865b..c30991076 100644
--- a/compton.h
+++ b/compton.h
@@ -4,92 +4,20 @@
// Throw everything in here.
-// === Options ===
-
-// Debug options, enable them using -D in CFLAGS
-// #define DEBUG_REPAINT 1
-// #define DEBUG_EVENTS 1
-// #define DEBUG_RESTACK 1
-// #define DEBUG_WINTYPE 1
-// #define DEBUG_CLIENTWIN 1
-// #define DEBUG_WINDATA 1
-// #define DEBUG_WINMATCH 1
-// #define DEBUG_REDIR 1
-// #define DEBUG_ALLOC_REG 1
-// #define DEBUG_FRAME 1
-// #define DEBUG_LEADER 1
-// #define MONITOR_REPAINT 1
-
-// Whether to enable PCRE regular expression support in blacklists, enabled
-// by default
-// #define CONFIG_REGEX_PCRE 1
-// Whether to enable JIT support of libpcre. This may cause problems on PaX
-// kernels.
-// #define CONFIG_REGEX_PCRE_JIT 1
-// Whether to enable parsing of configuration files using libconfig
-// #define CONFIG_LIBCONFIG 1
-// Whether to enable DRM VSync support
-// #define CONFIG_VSYNC_DRM 1
-// Whether to enable OpenGL VSync support
-// #define CONFIG_VSYNC_OPENGL 1
// === Includes ===
-// For some special functions
-#define _GNU_SOURCE
+#include "common.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
#include <math.h>
#include <sys/select.h>
-#include <sys/poll.h>
-#include <sys/time.h>
-#include <time.h>
#include <limits.h>
#include <unistd.h>
#include <getopt.h>
-#include <stdbool.h>
#include <locale.h>
-#include <assert.h>
#include <fnmatch.h>
#include <signal.h>
-// libpcre
-#ifdef CONFIG_REGEX_PCRE
-#include <pcre.h>
-
-// For compatiblity with <libpcre-8.20
-#ifndef PCRE_STUDY_JIT_COMPILE
-#define PCRE_STUDY_JIT_COMPILE 0
-#define LPCRE_FREE_STUDY(extra) pcre_free(extra)
-#else
-#define LPCRE_FREE_STUDY(extra) pcre_free_study(extra)
-#endif
-
-#endif
-
-#ifdef CONFIG_LIBCONFIG
-#include <libgen.h>
-#include <libconfig.h>
-#endif
-
-#ifdef CONFIG_DBUS
-#include <dbus/dbus.h>
-#endif
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/Xatom.h>
-#include <X11/extensions/Xcomposite.h>
-#include <X11/extensions/Xdamage.h>
-#include <X11/extensions/Xrender.h>
-#include <X11/extensions/shape.h>
-#include <X11/extensions/Xrandr.h>
-#include <X11/extensions/Xdbe.h>
-#include <time.h>
-
#ifdef CONFIG_VSYNC_DRM
#include <fcntl.h>
// We references some definitions in drm.h, which could also be found in
@@ -100,776 +28,6 @@
#include <errno.h>
#endif
-#ifdef CONFIG_VSYNC_OPENGL
-#include <GL/glx.h>
-#endif
-
-// === Constants ===
-#if !(COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2)
-#error libXcomposite version unsupported
-#endif
-
-#define ROUNDED_PERCENT 0.05
-#define ROUNDED_PIXELS 10
-
-#define OPAQUE 0xffffffff
-#define REGISTER_PROP "_NET_WM_CM_S"
-
-#define TIME_MS_MAX LONG_MAX
-#define FADE_DELTA_TOLERANCE 0.2
-#define SWOPTI_TOLERANCE 3000
-#define TIMEOUT_RUN_TOLERANCE 0.2
-#define WIN_GET_LEADER_MAX_RECURSION 20
-
-#define SEC_WRAP (15L * 24L * 60L * 60L)
-
-#define NS_PER_SEC 1000000000L
-#define US_PER_SEC 1000000L
-#define MS_PER_SEC 1000
-
-#define XRFILTER_CONVOLUTION "convolution"
-#define XRFILTER_GUASSIAN "gaussian"
-#define XRFILTER_BINOMIAL "binomial"
-
-// Window flags
-
-// Window size is changed
-#define WFLAG_SIZE_CHANGE 0x0001
-// Window size/position is changed
-#define WFLAG_POS_CHANGE 0x0002
-// Window opacity / dim state changed
-#define WFLAG_OPCT_CHANGE 0x0004
-
-// === Macros ===
-
-// #define MSTR_(s) #s
-// #define MSTR(s) MSTR_(s)
-
-/// Print out an error message.
-#define printf_err(format, ...) \
- fprintf(stderr, format "\n", ## __VA_ARGS__)
-
-/// Print out an error message with function name.
-#define printf_errf(format, ...) \
- printf_err("%s" format, __func__, ## __VA_ARGS__)
-
-/// Print out an error message with function name, and quit with a
-/// specific exit code.
-#define printf_errfq(code, format, ...) { \
- printf_err("%s" format, __func__, ## __VA_ARGS__); \
- exit(code); \
-}
-
-/// Print out a debug message.
-#define printf_dbg(format, ...) \
- printf(format, ## __VA_ARGS__); \
- fflush(stdout)
-
-/// Print out a debug message with function name.
-#define printf_dbgf(format, ...) \
- printf_dbg("%s" format, __func__, ## __VA_ARGS__)
-
-// Use #s here to prevent macro expansion
-/// Macro used for shortening some debugging code.
-#define CASESTRRET(s) case s: return #s
-
-// === Types ===
-
-typedef uint32_t opacity_t;
-typedef long time_ms_t;
-
-typedef enum {
- WINTYPE_UNKNOWN,
- WINTYPE_DESKTOP,
- WINTYPE_DOCK,
- WINTYPE_TOOLBAR,
- WINTYPE_MENU,
- WINTYPE_UTILITY,
- WINTYPE_SPLASH,
- WINTYPE_DIALOG,
- WINTYPE_NORMAL,
- WINTYPE_DROPDOWN_MENU,
- WINTYPE_POPUP_MENU,
- WINTYPE_TOOLTIP,
- WINTYPE_NOTIFY,
- WINTYPE_COMBO,
- WINTYPE_DND,
- NUM_WINTYPES
-} wintype_t;
-
-/// Enumeration type to represent switches.
-typedef enum {
- OFF, // false
- ON, // true
- UNSET
-} switch_t;
-
-/// Enumeration type of window painting mode.
-typedef enum {
- WMODE_TRANS,
- WMODE_SOLID,
- WMODE_ARGB
-} winmode_t;
-
-/// Structure representing needed window updates.
-typedef struct {
- bool shadow : 1;
- bool fade : 1;
- bool focus : 1;
- bool invert_color : 1;
-} win_upd_t;
-
-/// Structure representing Window property value.
-typedef struct {
- // All pointers have the same length, right?
- // I wanted to use anonymous union but it's a GNU extension...
- union {
- unsigned char *p8;
- short *p16;
- long *p32;
- } data;
- unsigned long nitems;
- Atom type;
- int format;
-} winprop_t;
-
-typedef struct _ignore {
- struct _ignore *next;
- unsigned long sequence;
-} ignore_t;
-
-enum wincond_target {
- CONDTGT_NAME,
- CONDTGT_CLASSI,
- CONDTGT_CLASSG,
- CONDTGT_ROLE,
-};
-
-enum wincond_type {
- CONDTP_EXACT,
- CONDTP_ANYWHERE,
- CONDTP_FROMSTART,
- CONDTP_WILDCARD,
- CONDTP_REGEX_PCRE,
-};
-
-#define CONDF_IGNORECASE 0x0001
-
-typedef struct _wincond {
- enum wincond_target target;
- enum wincond_type type;
- char *pattern;
-#ifdef CONFIG_REGEX_PCRE
- pcre *regex_pcre;
- pcre_extra *regex_pcre_extra;
-#endif
- int16_t flags;
- struct _wincond *next;
-} wincond_t;
-
-/// VSync modes.
-typedef enum {
- VSYNC_NONE,
- VSYNC_DRM,
- VSYNC_OPENGL,
-} vsync_t;
-
-#ifdef CONFIG_VSYNC_OPENGL
-typedef int (*f_WaitVideoSync) (int, int, unsigned *);
-typedef int (*f_GetVideoSync) (unsigned *);
-#endif
-
-typedef struct {
- int size;
- double *data;
-} conv;
-
-struct _timeout_t;
-
-struct _win;
-
-/// Structure representing all options.
-typedef struct {
- // === General ===
- char *display;
- /// Whether to try to detect WM windows and mark them as focused.
- bool mark_wmwin_focused;
- /// Whether to mark override-redirect windows as focused.
- bool mark_ovredir_focused;
- /// Whether to fork to background.
- bool fork_after_register;
- /// Whether to detect rounded corners.
- bool detect_rounded_corners;
- /// Whether to paint on X Composite overlay window instead of root
- /// window.
- bool paint_on_overlay;
- /// Whether to unredirect all windows if a full-screen opaque window
- /// is detected.
- bool unredir_if_possible;
- /// Whether to enable D-Bus support.
- bool dbus;
- /// Path to log file.
- char *logpath;
- /// Whether to work under synchronized mode for debugging.
- bool synchronize;
-
- // === VSync & software optimization ===
- /// User-specified refresh rate.
- int refresh_rate;
- /// Whether to enable refresh-rate-based software optimization.
- bool sw_opti;
- /// VSync method to use;
- vsync_t vsync;
- /// Whether to enable double buffer.
- bool dbe;
- /// Whether to do VSync aggressively.
- bool vsync_aggressive;
-
- // === Shadow ===
- /// Enable/disable shadow for specific window types.
- bool wintype_shadow[NUM_WINTYPES];
- /// Red, green and blue tone of the shadow.
- double shadow_red, shadow_green, shadow_blue;
- int shadow_radius;
- int shadow_offset_x, shadow_offset_y;
- double shadow_opacity;
- bool clear_shadow;
- /// Shadow blacklist. A linked list of conditions.
- wincond_t *shadow_blacklist;
- /// Whether bounding-shaped window should be ignored.
- bool shadow_ignore_shaped;
- /// Whether to respect _COMPTON_SHADOW.
- bool respect_prop_shadow;
-
- // === Fading ===
- /// Enable/disable fading for specific window types.
- bool wintype_fade[NUM_WINTYPES];
- /// How much to fade in in a single fading step.
- opacity_t fade_in_step;
- /// How much to fade out in a single fading step.
- opacity_t fade_out_step;
- /// Fading time delta. In milliseconds.
- time_ms_t fade_delta;
- /// Whether to disable fading on window open/close.
- bool no_fading_openclose;
- /// Fading blacklist. A linked list of conditions.
- wincond_t *fade_blacklist;
-
- // === Opacity ===
- /// Default opacity for specific window types
- double wintype_opacity[NUM_WINTYPES];
- /// Default opacity for inactive windows.
- /// 32-bit integer with the format of _NET_WM_OPACITY. 0 stands for
- /// not enabled, default.
- opacity_t inactive_opacity;
- /// Whether inactive_opacity overrides the opacity set by window
- /// attributes.
- bool inactive_opacity_override;
- /// Frame opacity. Relative to window opacity, also affects shadow
- /// opacity.
- double frame_opacity;
- /// Whether to detect _NET_WM_OPACITY on client windows. Used on window
- /// managers that don't pass _NET_WM_OPACITY to frame windows.
- bool detect_client_opacity;
- /// Step for pregenerating alpha pictures. 0.01 - 1.0.
- double alpha_step;
-
- // === Other window processing ===
- /// Whether to blur background of semi-transparent / ARGB windows.
- bool blur_background;
- /// Whether to blur background when the window frame is not opaque.
- /// Implies blur_background.
- bool blur_background_frame;
- /// Whether to use fixed blur strength instead of adjusting according
- /// to window opacity.
- bool blur_background_fixed;
- /// How much to dim an inactive window. 0.0 - 1.0, 0 to disable.
- double inactive_dim;
- /// Whether to use fixed inactive dim opacity, instead of deciding
- /// based on window opacity.
- bool inactive_dim_fixed;
- /// Conditions of windows to have inverted colors.
- wincond_t *invert_color_list;
-
- // === Focus related ===
- /// Consider windows of specific types to be always focused.
- bool wintype_focus[NUM_WINTYPES];
- /// Whether to use EWMH _NET_ACTIVE_WINDOW to find active window.
- bool use_ewmh_active_win;
- /// A list of windows always to be considered focused.
- wincond_t *focus_blacklist;
- /// Whether to do window grouping with <code>WM_TRANSIENT_FOR</code>.
- bool detect_transient;
- /// Whether to do window grouping with <code>WM_CLIENT_LEADER</code>.
- bool detect_client_leader;
-
- // === Calculated ===
- /// Whether compton needs to track focus changes.
- bool track_focus;
- /// Whether compton needs to track window name and class.
- bool track_wdata;
- /// Whether compton needs to track window leaders.
- bool track_leader;
-} options_t;
-
-/// Structure containing all necessary data for a compton session.
-typedef struct {
- // === Display related ===
- /// Display in use.
- Display *dpy;
- /// Default screen.
- int scr;
- /// Default visual.
- Visual *vis;
- /// Default depth.
- int depth;
- /// Root window.
- Window root;
- /// Height of root window.
- int root_height;
- /// Width of root window.
- int root_width;
- // Damage of root window.
- // Damage root_damage;
- /// X Composite overlay window. Used if <code>--paint-on-overlay</code>.
- Window overlay;
- /// Picture of the root window background.
- Picture root_tile;
- /// A region of the size of the screen.
- XserverRegion screen_reg;
- /// Picture of root window. Destination of painting in no-DBE painting
- /// mode.
- Picture root_picture;
- /// A Picture acting as the painting target.
- Picture tgt_picture;
- /// Temporary buffer to paint to before sending to display.
- Picture tgt_buffer;
- /// DBE back buffer for root window. Used in DBE painting mode.
- XdbeBackBuffer root_dbe;
- /// Window ID of the window we register as a symbol.
- Window reg_win;
-
- // === Operation related ===
- /// Program options.
- options_t o;
- /// File descriptors to check for reading.
- fd_set *pfds_read;
- /// File descriptors to check for writing.
- fd_set *pfds_write;
- /// File descriptors to check for exceptions.
- fd_set *pfds_except;
- /// Largest file descriptor in fd_set-s above.
- int nfds_max;
- /// Linked list of all timeouts.
- struct _timeout_t *tmout_lst;
- /// Whether we have received an event in this cycle.
- bool ev_received;
- /// Whether the program is idling. I.e. no fading, no potential window
- /// changes.
- bool idling;
- /// Program start time.
- struct timeval time_start;
- /// The region needs to painted on next paint.
- XserverRegion all_damage;
- /// Whether all windows are currently redirected.
- bool redirected;
- /// Whether there's a highest full-screen window, and all windows could
- /// be unredirected.
- bool unredir_possible;
- /// Pre-generated alpha pictures.
- Picture *alpha_picts;
- /// Whether all reg_ignore of windows should expire in this paint.
- bool reg_ignore_expire;
- /// Time of last fading. In milliseconds.
- time_ms_t fade_time;
- /// Head pointer of the error ignore linked list.
- ignore_t *ignore_head;
- /// Pointer to the <code>next</code> member of tail element of the error
- /// ignore linked list.
- ignore_t **ignore_tail;
- /// Reset program after next paint.
- bool reset;
-
- // === Expose event related ===
- /// Pointer to an array of <code>XRectangle</code>-s of exposed region.
- XRectangle *expose_rects;
- /// Number of <code>XRectangle</code>-s in <code>expose_rects</code>.
- int size_expose;
- /// Index of the next free slot in <code>expose_rects</code>.
- int n_expose;
-
- // === Window related ===
- /// Linked list of all windows.
- struct _win *list;
- /// Pointer to <code>win</code> of current active window. Used by
- /// EWMH <code>_NET_ACTIVE_WINDOW</code> focus detection. In theory,
- /// it's more reliable to store the window ID directly here, just in
- /// case the WM does something extraordinary, but caching the pointer
- /// means another layer of complexity.
- struct _win *active_win;
- /// Window ID of leader window of currently active window. Used for
- /// subsidiary window detection.
- Window active_leader;
-
- // === Shadow/dimming related ===
- /// 1x1 black Picture.
- Picture black_picture;
- /// 1x1 Picture of the shadow color.
- Picture cshadow_picture;
- /// 1x1 white Picture.
- Picture white_picture;
- /// Gaussian map of shadow.
- conv *gaussian_map;
- // for shadow precomputation
- /// Shadow depth on one side.
- int cgsize;
- /// Pre-computed color table for corners of shadow.
- unsigned char *shadow_corner;
- /// Pre-computed color table for a side of shadow.
- unsigned char *shadow_top;
-
- // === Software-optimization-related ===
- /// Currently used refresh rate.
- short refresh_rate;
- /// Interval between refresh in nanoseconds.
- long refresh_intv;
- /// Nanosecond offset of the first painting.
- long paint_tm_offset;
-
- #ifdef CONFIG_VSYNC_DRM
- // === DRM VSync related ===
- /// File descriptor of DRI device file. Used for DRM VSync.
- int drm_fd;
- #endif
-
- #ifdef CONFIG_VSYNC_OPENGL
- // === OpenGL VSync related ===
- /// GLX context.
- GLXContext glx_context;
- /// Pointer to glXGetVideoSyncSGI function.
- f_GetVideoSync glx_get_video_sync;
- /// Pointer to glXWaitVideoSyncSGI function.
- f_WaitVideoSync glx_wait_video_sync;
- #endif
-
- // === X extension related ===
- /// Event base number for X Fixes extension.
- int xfixes_event;
- /// Error base number for X Fixes extension.
- int xfixes_error;
- /// Event base number for X Damage extension.
- int damage_event;
- /// Error base number for X Damage extension.
- int damage_error;
- /// Event base number for X Render extension.
- int render_event;
- /// Error base number for X Render extension.
- int render_error;
- /// Event base number for X Composite extension.
- int composite_event;
- /// Error base number for X Composite extension.
- int composite_error;
- /// Major opcode for X Composite extension.
- int composite_opcode;
- /// Whether X Composite NameWindowPixmap is available. Aka if X
- /// Composite version >= 0.2.
- bool has_name_pixmap;
- /// Whether X Shape extension exists.
- bool shape_exists;
- /// Event base number for X Shape extension.
- int shape_event;
- /// Error base number for X Shape extension.
- int shape_error;
- /// Whether X RandR extension exists.
- bool randr_exists;
- /// Event base number for X RandR extension.
- int randr_event;
- /// Error base number for X RandR extension.
- int randr_error;
- #ifdef CONFIG_VSYNC_OPENGL
- /// Whether X GLX extension exists.
- bool glx_exists;
- /// Event base number for X GLX extension.
- int glx_event;
- /// Error base number for X GLX extension.
- int glx_error;
- #endif
- /// Whether X DBE extension exists.
- bool dbe_exists;
- /// Whether X Render convolution filter exists.
- bool xrfilter_convolution_exists;
-
- // === Atoms ===
- /// Atom of property <code>_NET_WM_OPACITY</code>.
- Atom atom_opacity;
- /// Atom of <code>_NET_FRAME_EXTENTS</code>.
- Atom atom_frame_extents;
- /// Property atom to identify top-level frame window. Currently
- /// <code>WM_STATE</code>.
- Atom atom_client;
- /// Atom of property <code>WM_NAME</code>.
- Atom atom_name;
- /// Atom of property <code>_NET_WM_NAME</code>.
- Atom atom_name_ewmh;
- /// Atom of property <code>WM_CLASS</code>.
- Atom atom_class;
- /// Atom of property <code>WM_WINDOW_ROLE</code>.
- Atom atom_role;
- /// Atom of property <code>WM_TRANSIENT_FOR</code>.
- Atom atom_transient;
- /// Atom of property <code>WM_CLIENT_LEADER</code>.
- Atom atom_client_leader;
- /// Atom of property <code>_NET_ACTIVE_WINDOW</code>.
- Atom atom_ewmh_active_win;
- /// Atom of property <code>_COMPTON_SHADOW</code>.
- Atom atom_compton_shadow;
- /// Atom of property <code>_NET_WM_WINDOW_TYPE</code>.
- Atom atom_win_type;
- /// Array of atoms of all possible window types.
- Atom atoms_wintypes[NUM_WINTYPES];
-} session_t;
-
-/// Structure representing a top-level window compton manages.
-typedef struct _win {
- /// Pointer to the next structure in the linked list.
- struct _win *next;
- /// Pointer to the next higher window to paint.
- struct _win *prev_trans;
-
- // Core members
- /// ID of the top-level frame window.
- Window id;
- /// Window attributes.
- XWindowAttributes a;
- /// Window painting mode.
- winmode_t mode;
- /// Whether the window has been damaged at least once.
- bool damaged;
- /// Damage of the window.
- Damage damage;
- /// NameWindowPixmap of the window.
- Pixmap pixmap;
- /// Picture of the window.
- Picture picture;
- /// Bounding shape of the window.
- XserverRegion border_size;
- /// Region of the whole window, shadow region included.
- XserverRegion extents;
- /// Window flags. Definitions above.
- int_fast16_t flags;
- /// Whether there's a pending <code>ConfigureNotify</code> happening
- /// when the window is unmapped.
- bool need_configure;
- /// Queued <code>ConfigureNotify</code> when the window is unmapped.
- XConfigureEvent queue_configure;
- /// Region to be ignored when painting. Basically the region where
- /// higher opaque windows will paint upon. Depends on window frame
- /// opacity state, window geometry, window mapped/unmapped state,
- /// window mode, of this and all higher windows.
- XserverRegion reg_ignore;
- /// Cached width/height of the window including border.
- int widthb, heightb;
- /// Whether the window has been destroyed.
- bool destroyed;
- /// Whether the window is bounding-shaped.
- bool bounding_shaped;
- /// Whether the window just have rounded corners.
- bool rounded_corners;
- /// Whether this window is to be painted.
- bool to_paint;
- /// Whether this window is in open/close state.
- bool in_openclose;
-
- // Client window related members
- /// ID of the top-level client window of the window.
- Window client_win;
- /// Type of the window.
- wintype_t window_type;
- /// Whether it looks like a WM window. We consider a window WM window if
- /// it does not have a decedent with WM_STATE and it is not override-
- /// redirected itself.
- bool wmwin;
- /// Leader window ID of the window.
- Window leader;
- /// Cached topmost window ID of the window.
- Window cache_leader;
-
- // Focus-related members
- /// Whether the window is to be considered focused.
- bool focused;
- /// Override value of window focus state. Set by D-Bus method calls.
- switch_t focused_force;
- /// Whether the window is actually focused.
- bool focused_real;
-
- // Blacklist related members
- /// Name of the window.
- char *name;
- /// Window instance class of the window.
- char *class_instance;
- /// Window general class of the window.
- char *class_general;
- /// <code>WM_WINDOW_ROLE</code> value of the window.
- char *role;
- wincond_t *cache_sblst;
- wincond_t *cache_fblst;
- wincond_t *cache_fcblst;
- wincond_t *cache_ivclst;
-
- // Opacity-related members
- /// Current window opacity.
- opacity_t opacity;
- /// Target window opacity.
- opacity_t opacity_tgt;
- /// Cached value of opacity window attribute.
- opacity_t opacity_prop;
- /// Cached value of opacity window attribute on client window. For
- /// broken window managers not transferring client window's
- /// _NET_WM_OPACITY value
- opacity_t opacity_prop_client;
- /// Alpha mask Picture to render window with opacity.
- Picture alpha_pict;
-
- // Fading-related members
- /// Do not fade if it's false. Change on window type change.
- /// Used by fading blacklist in the future.
- bool fade;
- /// Callback to be called after fading completed.
- void (*fade_callback) (session_t *ps, struct _win *w);
-
- // Frame-opacity-related members
- /// Current window frame opacity. Affected by window opacity.
- double frame_opacity;
- /// Alpha mask Picture to render window frame with opacity.
- Picture frame_alpha_pict;
- /// Frame widths. Determined by client window attributes.
- unsigned int left_width, right_width, top_width, bottom_width;
-
- // Shadow-related members
- /// Whether a window has shadow. Calculated.
- bool shadow;
- /// Override value of window shadow state. Set by D-Bus method calls.
- switch_t shadow_force;
- /// Opacity of the shadow. Affected by window opacity and frame opacity.
- double shadow_opacity;
- /// X offset of shadow. Affected by commandline argument.
- int shadow_dx;
- /// Y offset of shadow. Affected by commandline argument.
- int shadow_dy;
- /// Width of shadow. Affected by window size and commandline argument.
- int shadow_width;
- /// Height of shadow. Affected by window size and commandline argument.
- int shadow_height;
- /// Picture to render shadow. Affected by window size.
- Picture shadow_pict;
- /// Alpha mask Picture to render shadow. Affected by shadow opacity.
- Picture shadow_alpha_pict;
- /// The value of _COMPTON_SHADOW attribute of the window. Below 0 for
- /// none.
- long prop_shadow;
-
- // Dim-related members
- /// Whether the window is to be dimmed.
- bool dim;
- /// Picture for dimming. Affected by user-specified inactive dim
- /// opacity and window opacity.
- Picture dim_alpha_pict;
-
- /// Whether to invert window color.
- bool invert_color;
- /// Override value of window color inversion state. Set by D-Bus method
- /// calls.
- switch_t invert_color_force;
-} win;
-
-/// Temporary structure used for communication between
-/// <code>get_cfg()</code> and <code>parse_config()</code>.
-struct options_tmp {
- bool no_dock_shadow;
- bool no_dnd_shadow;
- double menu_opacity;
-};
-
-/// Structure for a recorded timeout.
-typedef struct _timeout_t {
- bool enabled;
- void *data;
- bool (*callback)(session_t *ps, struct _timeout_t *ptmout);
- time_ms_t interval;
- time_ms_t firstrun;
- time_ms_t lastrun;
- struct _timeout_t *next;
-} timeout_t;
-
-/// Enumeration for window event hints.
-typedef enum {
- WIN_EVMODE_UNKNOWN,
- WIN_EVMODE_FRAME,
- WIN_EVMODE_CLIENT
-} win_evmode_t;
-
-extern const char *WINTYPES[NUM_WINTYPES];
-extern session_t *ps_g;
-
-// == Debugging code ==
-static void
-print_timestamp(session_t *ps);
-
-#ifdef DEBUG_ALLOC_REG
-
-#include <execinfo.h>
-#define BACKTRACE_SIZE 5
-
-/**
- * Print current backtrace, excluding the first two items.
- *
- * Stolen from glibc manual.
- */
-static inline void
-print_backtrace(void) {
- void *array[BACKTRACE_SIZE];
- size_t size;
- char **strings;
-
- size = backtrace(array, BACKTRACE_SIZE);
- strings = backtrace_symbols(array, size);
-
- for (size_t i = 2; i < size; i++)
- printf ("%s\n", strings[i]);
-
- free(strings);
-}
-
-/**
- * Wrapper of <code>XFixesCreateRegion</code>, for debugging.
- */
-static inline XserverRegion
-XFixesCreateRegion_(Display *dpy, XRectangle *p, int n,
- const char *func, int line) {
- XserverRegion reg = XFixesCreateRegion(dpy, p, n);
- print_timestamp(ps_g);
- printf("%#010lx: XFixesCreateRegion() in %s():%d\n", reg, func, line);
- print_backtrace();
- fflush(stdout);
- return reg;
-}
-
-/**
- * Wrapper of <code>XFixesDestroyRegion</code>, for debugging.
- */
-static inline void
-XFixesDestroyRegion_(Display *dpy, XserverRegion reg,
- const char *func, int line) {
- XFixesDestroyRegion(dpy, reg);
- print_timestamp(ps_g);
- printf("%#010lx: XFixesDestroyRegion() in %s():%d\n", reg, func, line);
- fflush(stdout);
-}
-
-#define XFixesCreateRegion(dpy, p, n) XFixesCreateRegion_(dpy, p, n, __func__, __LINE__)
-#define XFixesDestroyRegion(dpy, reg) XFixesDestroyRegion_(dpy, reg, __func__, __LINE__)
-#endif
-
// == Functions ==
// inline functions must be made static to compile correctly under clang:
@@ -953,111 +111,6 @@ wintype_arr_enable_unset(switch_t arr[]) {
}
/**
- * Allocate the space and copy a string.
- */
-static inline char * __attribute__((const))
-mstrcpy(const char *src) {
- char *str = malloc(sizeof(char) * (strlen(src) + 1));
-
- strcpy(str, src);
-
- return str;
-}
-
-/**
- * Allocate the space and join two strings.
- */
-static inline char * __attribute__((const))
-mstrjoin(const char *src1, const char *src2) {
- char *str = malloc(sizeof(char) * (strlen(src1) + strlen(src2) + 1));
-
- strcpy(str, src1);
- strcat(str, src2);
-
- return str;
-}
-
-/**
- * Allocate the space and join two strings;
- */
-static inline char * __attribute__((const))
-mstrjoin3(const char *src1, const char *src2, const char *src3) {
- char *str = malloc(sizeof(char) * (strlen(src1) + strlen(src2)
- + strlen(src3) + 1));
-
- strcpy(str, src1);
- strcat(str, src2);
- strcat(str, src3);
-
- return str;
-}
-
-/**
- * Normalize an int value to a specific range.
- *
- * @param i int value to normalize
- * @param min minimal value
- * @param max maximum value
- * @return normalized value
- */
-static inline int __attribute__((const))
-normalize_i_range(int i, int min, int max) {
- if (i > max) return max;
- if (i < min) return min;
- return i;
-}
-
-/**
- * Select the larger integer of two.
- */
-static inline int __attribute__((const))
-max_i(int a, int b) {
- return (a > b ? a : b);
-}
-
-/**
- * Select the smaller integer of two.
- */
-static inline int __attribute__((const))
-min_i(int a, int b) {
- return (a > b ? b : a);
-}
-
-/**
- * Select the smaller long integer of two.
- */
-static inline long __attribute__((const))
-min_l(long a, long b) {
- return (a > b ? b : a);
-}
-
-/**
- * Normalize a double value to a specific range.
- *
- * @param d double value to normalize
- * @param min minimal value
- * @param max maximum value
- * @return normalized value
- */
-static inline double __attribute__((const))
-normalize_d_range(double d, double min, double max) {
- if (d > max) return max;
- if (d < min) return min;
- return d;
-}
-
-/**
- * Normalize a double value to 0.\ 0 - 1.\ 0.
- *
- * @param d double value to normalize
- * @return normalized value
- */
-static inline double __attribute__((const))
-normalize_d(double d) {
- return normalize_d_range(d, 0.0, 1.0);
-}
-
-/**
* Check if a window ID exists in an array of window IDs.
*
* @param arr the array of window IDs
@@ -1074,160 +127,6 @@ array_wid_exists(const Window *arr, int count, Window wid) {
return false;
}
-
-/**
- * Return whether a struct timeval value is empty.
- */
-static inline bool
-timeval_isempty(struct timeval *ptv) {
- if (!ptv)
- return false;
-
- return ptv->tv_sec <= 0 && ptv->tv_usec <= 0;
-}
-
-/**
- * Compare a struct timeval with a time in milliseconds.
- *
- * @return > 0 if ptv > ms, 0 if ptv == 0, -1 if ptv < ms
- */
-static inline int
-timeval_ms_cmp(struct timeval *ptv, time_ms_t ms) {
- assert(ptv);
-
- // We use those if statement instead of a - expression because of possible
- // truncation problem from long to int.
- {
- long sec = ms / MS_PER_SEC;
- if (ptv->tv_sec > sec)
- return 1;
- if (ptv->tv_sec < sec)
- return -1;
- }
-
- {
- long usec = ms % MS_PER_SEC * (US_PER_SEC / MS_PER_SEC);
- if (ptv->tv_usec > usec)
- return 1;
- if (ptv->tv_usec < usec)
- return -1;
- }
-
- return 0;
-}
-
-/*
- * Subtracting two struct timeval values.
- *
- * Taken from glibc manual.
- *
- * Subtract the `struct timeval' values X and Y,
- * storing the result in RESULT.
- * Return 1 if the difference is negative, otherwise 0. */
-static int
-timeval_subtract(struct timeval *result,
- struct timeval *x,
- struct timeval *y) {
- /* Perform the carry for the later subtraction by updating y. */
- if (x->tv_usec < y->tv_usec) {
- long nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
- y->tv_usec -= 1000000 * nsec;
- y->tv_sec += nsec;
- }
-
- if (x->tv_usec - y->tv_usec > 1000000) {
- long nsec = (x->tv_usec - y->tv_usec) / 1000000;
- y->tv_usec += 1000000 * nsec;
- y->tv_sec -= nsec;
- }
-
- /* Compute the time remaining to wait.
- tv_usec is certainly positive. */
- result->tv_sec = x->tv_sec - y->tv_sec;
- result->tv_usec = x->tv_usec - y->tv_usec;
-
- /* Return 1 if result is negative. */
- return x->tv_sec < y->tv_sec;
-}
-
-/*
- * Subtracting two struct timespec values.
- *
- * Taken from glibc manual.
- *
- * Subtract the `struct timespec' values X and Y,
- * storing the result in RESULT.
- * Return 1 if the difference is negative, otherwise 0.
- */
-static inline int
-timespec_subtract(struct timespec *result,
- struct timespec *x,
- struct timespec *y) {
- /* Perform the carry for the later subtraction by updating y. */
- if (x->tv_nsec < y->tv_nsec) {
- long nsec = (y->tv_nsec - x->tv_nsec) / NS_PER_SEC + 1;
- y->tv_nsec -= NS_PER_SEC * nsec;
- y->tv_sec += nsec;
- }
-
- if (x->tv_nsec - y->tv_nsec > NS_PER_SEC) {
- long nsec = (x->tv_nsec - y->tv_nsec) / NS_PER_SEC;
- y->tv_nsec += NS_PER_SEC * nsec;
- y->tv_sec -= nsec;
- }
-
- /* Compute the time remaining to wait.
- tv_nsec is certainly positive. */
- result->tv_sec = x->tv_sec - y->tv_sec;
- result->tv_nsec = x->tv_nsec - y->tv_nsec;
-
- /* Return 1 if result is negative. */
- return x->tv_sec < y->tv_sec;
-}
-
-/**
- * Get current time in struct timeval.
- */
-static inline struct timeval __attribute__((const))
-get_time_timeval(void) {
- struct timeval tv = { 0, 0 };
-
- gettimeofday(&tv, NULL);
-
- // Return a time of all 0 if the call fails
- return tv;
-}
-
-/**
- * Get current time in struct timespec.
- *
- * Note its starting time is unspecified.
- */
-static inline struct timespec __attribute__((const))
-get_time_timespec(void) {
- struct timespec tm = { 0, 0 };
-
- clock_gettime(CLOCK_MONOTONIC, &tm);
-
- // Return a time of all 0 if the call fails
- return tm;
-}
-
-/**
- * Print time passed since program starts execution.
- *
- * Used for debugging.
- */
-static void
-print_timestamp(session_t *ps) {
- struct timeval tm, diff;
-
- if (gettimeofday(&tm, NULL)) return;
-
- timeval_subtract(&diff, &tm, &ps->time_start);
- printf("[ %5ld.%02ld ] ", diff.tv_sec, diff.tv_usec / 10000);
-}
-
/**
* Destroy a <code>XserverRegion</code>.
*/
@@ -1347,95 +246,6 @@ ms_to_tv(int timeout) {
};
}
-/**
- * Add a file descriptor to a select() fd_set.
- */
-static inline bool
-fds_insert_select(fd_set **ppfds, int fd) {
- assert(fd <= FD_SETSIZE);
-
- if (!*ppfds) {
- if ((*ppfds = malloc(sizeof(fd_set)))) {
- FD_ZERO(*ppfds);
- }
- else {
- fprintf(stderr, "Failed to allocate memory for select() fdset.\n");
- exit(1);
- }
- }
-
- FD_SET(fd, *ppfds);
-
- return true;
-}
-
-/**
- * Add a new file descriptor to wait for.
- */
-static inline bool
-fds_insert(session_t *ps, int fd, short events) {
- bool result = true;
-
- ps->nfds_max = max_i(fd + 1, ps->nfds_max);
-
- if (POLLIN & events)
- result = fds_insert_select(&ps->pfds_read, fd) && result;
- if (POLLOUT & events)
- result = fds_insert_select(&ps->pfds_write, fd) && result;
- if (POLLPRI & events)
- result = fds_insert_select(&ps->pfds_except, fd) && result;
-
- return result;
-}
-
-/**
- * Delete a file descriptor to wait for.
- */
-static inline void
-fds_drop(session_t *ps, int fd, short events) {
- // Drop fd from respective fd_set-s
- if (POLLIN & events)
- FD_CLR(fd, ps->pfds_read);
- if (POLLOUT & events)
- FD_CLR(fd, ps->pfds_write);
- if (POLLPRI & events)
- FD_CLR(fd, ps->pfds_except);
-}
-
-#define CPY_FDS(key) \
- fd_set * key = NULL; \
- if (ps->key) { \
- key = malloc(sizeof(fd_set)); \
- memcpy(key, ps->key, sizeof(fd_set)); \
- if (!key) { \
- fprintf(stderr, "Failed to allocate memory for copying select() fdset.\n"); \
- exit(1); \
- } \
- } \
-
-/**
- * Poll for changes.
- *
- * poll() is much better than select(), but ppoll() does not exist on
- * *BSD.
- */
-static inline int
-fds_poll(session_t *ps, struct timeval *ptv) {
- // Copy fds
- CPY_FDS(pfds_read);
- CPY_FDS(pfds_write);
- CPY_FDS(pfds_except);
-
- int ret = select(ps->nfds_max, pfds_read, pfds_write, pfds_except, ptv);
-
- free(pfds_read);
- free(pfds_write);
- free(pfds_except);
-
- return ret;
-}
-#undef CPY_FDS
-
static void
run_fade(session_t *ps, win *w, unsigned steps);
@@ -1723,43 +533,6 @@ static long
determine_evmask(session_t *ps, Window wid, win_evmode_t mode);
/**
- * Find a window from window id in window linked list of the session.
- */
-static inline win *
-find_win(session_t *ps, Window id) {
- if (!id)
- return NULL;
-
- win *w;
-
- for (w = ps->list; w; w = w->next) {
- if (w->id == id && !w->destroyed)
- return w;
- }
-
- return 0;
-}
-
-/**
- * Find out the WM frame of a client window using existing data.
- *
- * @param w window ID
- * @return struct _win object of the found window, NULL if not found
- */
-static inline win *
-find_toplevel(session_t *ps, Window id) {
- if (!id)
- return NULL;
-
- for (win *w = ps->list; w; w = w->next) {
- if (w->client_win == id && !w->destroyed)
- return w;
- }
-
- return NULL;
-}
-
-/**
* Clear leader cache of all windows.
*/
static void
@@ -2113,18 +886,6 @@ get_screen_region(session_t *ps) {
}
/**
- * Copies a region
- */
-inline static XserverRegion
-copy_region(const session_t *ps, XserverRegion oldregion) {
- XserverRegion region = XFixesCreateRegion(ps->dpy, NULL, 0);
-
- XFixesCopyRegion(ps->dpy, region, oldregion);
-
- return region;
-}
-
-/**
* Dump a region.
*/
static inline void
@@ -2281,19 +1042,14 @@ redir_start(session_t *ps);
static void
redir_stop(session_t *ps);
+static inline time_ms_t
+timeout_get_newrun(const timeout_t *ptmout) {
+ return ptmout->firstrun + (max_l((ptmout->lastrun + (long) (ptmout->interval * TIMEOUT_RUN_TOLERANCE) - ptmout->firstrun) / ptmout->interval, (ptmout->lastrun + ptmout->interval * (1 - TIMEOUT_RUN_TOLERANCE) - ptmout->firstrun) / ptmout->interval) + 1) * ptmout->interval;
+}
+
static time_ms_t
timeout_get_poll_time(session_t *ps);
-static timeout_t *
-timeout_insert(session_t *ps, time_ms_t interval,
- bool (*callback)(session_t *ps, timeout_t *ptmout), void *data);
-
-static void
-timeout_invoke(session_t *ps, timeout_t *ptmout);
-
-static bool
-timeout_drop(session_t *ps, timeout_t *prm);
-
static void
timeout_clear(session_t *ps);
diff --git a/dbus.c b/dbus.c
new file mode 100644
index 000000000..16be7cc8f
--- /dev/null
+++ b/dbus.c
@@ -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);
+}
+//!@}
diff --git a/dbus.h b/dbus.h
new file mode 100644
index 000000000..fb51c8cc4
--- /dev/null
+++ b/dbus.h
@@ -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);
+
+///@}