diff options
author | Richard Grenville <pyxlcy@gmail.com> | 2013-01-19 20:20:27 +0800 |
---|---|---|
committer | Richard Grenville <pyxlcy@gmail.com> | 2013-01-19 20:20:27 +0800 |
commit | 32132312985e3a7f63444dcd4b54f821520a6042 (patch) | |
tree | e00f787bf4b13ca6b4e92eec1bea392ad2296499 /common.h | |
parent | a5dc829944175cab684e5b4488ddff409f308099 (diff) | |
download | tdebase-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).
Diffstat (limited to 'common.h')
-rw-r--r-- | common.h | 1370 |
1 files changed, 1370 insertions, 0 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 |