Files
picom/src/common.h
Yuxuan Shui b18d46bcbd Revert "Remove xrender-sync and xrender-sync-fence"
This reverts commit 50e2259404.

Temporarily revert the removal until we have more information about this whole
thing.

Turns out a couple of drivers don't work properly without the sync fence,
including intel, llvmpipe and NVIDIA.

Although sync fence is needed, from the information I have gathered (looking
at old bug reports, protocol specifications, look at other compositors' code),
compton's usage of it is not proper. So we need to rewrite it in the future,
after we get more information from driver developers.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-11-08 18:07:18 +00:00

1895 lines
48 KiB
C

// SPDX-License-Identifier: MIT
/*
* Compton - a compositor for X11
*
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
*
* Copyright (c) 2011-2013, Christopher Jeffrey
* Copyright (c) 2018, Yuxuan Shui <yshuiv7@gmail.com>
*
* See LICENSE-mit for more information.
*
*/
#pragma once
// === Options ===
// Debug options, enable them using -D in CFLAGS
// #define DEBUG_BACKTRACE 1
// #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 DEBUG_C2 1
// #define DEBUG_GLX 1
// #define DEBUG_GLX_GLSL 1
// #define DEBUG_GLX_ERR 1
// #define DEBUG_GLX_MARK 1
// #define DEBUG_GLX_PAINTREG 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 support (include GLSL, FBO)
// #define CONFIG_OPENGL 1
// Whether to enable DBus support with libdbus.
// #define CONFIG_DBUS 1
// Whether to enable X Sync support.
// #define CONFIG_XSYNC 1
// Whether to enable GLX Sync support.
// #define CONFIG_GLX_XSYNC 1
#ifndef COMPTON_VERSION
#define COMPTON_VERSION "unknown"
#endif
#if defined(DEBUG_ALLOC_REG)
#define DEBUG_BACKTRACE 1
#endif
// === Includes ===
// For some special functions
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <assert.h>
#include <time.h>
#include <ctype.h>
#include <sys/time.h>
#include <X11/Xlib-xcb.h>
#include <X11/Xlib.h>
#include <X11/extensions/sync.h>
#include <xcb/composite.h>
#include <xcb/render.h>
#include <xcb/damage.h>
#include <xcb/randr.h>
#include <xcb/shape.h>
#ifdef CONFIG_XINERAMA
#include <xcb/xinerama.h>
#endif
#include <ev.h>
#include <pixman.h>
// libdbus
#ifdef CONFIG_DBUS
#include <dbus/dbus.h>
#endif
#ifdef CONFIG_OPENGL
// libGL
#define GL_GLEXT_PROTOTYPES
#include <GL/glx.h>
// Workarounds for missing definitions in some broken GL drivers, thanks to
// douglasp and consolers for reporting
#ifndef GL_TEXTURE_RECTANGLE
#define GL_TEXTURE_RECTANGLE 0x84F5
#endif
#ifndef GLX_BACK_BUFFER_AGE_EXT
#define GLX_BACK_BUFFER_AGE_EXT 0x20F4
#endif
#endif
// === Macros ===
#define MSTR_(s) #s
#define MSTR(s) MSTR_(s)
/// @brief Wrapper for gcc branch prediction builtin, for likely branch.
#define likely(x) __builtin_expect(!!(x), 1)
/// @brief Wrapper for gcc branch prediction builtin, for unlikely branch.
#define unlikely(x) __builtin_expect(!!(x), 0)
/// 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
// X resource checker
#ifdef DEBUG_XRC
#include "xrescheck.h"
#endif
// FIXME This list of includes should get shorter
#include "types.h"
#include "win.h"
#include "x.h"
#include "region.h"
// === Constants ===
/// @brief Length of generic buffers.
#define BUF_LEN 80
#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 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_GAUSSIAN "gaussian"
#define XRFILTER_BINOMIAL "binomial"
/// @brief Maximum OpenGL FBConfig depth.
#define OPENGL_MAX_DEPTH 32
/// @brief Maximum OpenGL buffer age.
#define CGLX_MAX_BUFFER_AGE 5
/// @brief Maximum passes for blur.
#define MAX_BLUR_PASS 5
// 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
// xcb-render specific macros
#define XFIXED_TO_DOUBLE(value) (((double) (value)) / 65536)
#define DOUBLE_TO_XFIXED(value) ((xcb_render_fixed_t) (((double) (value)) * 65536))
// === Types ===
typedef long time_ms_t;
typedef struct _c2_lptr c2_lptr_t;
// Or use cmemzero().
/// 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 winprop {
union {
void *ptr;
uint8_t *p8;
int16_t *p16;
int32_t *p32;
uint32_t *c32; // 32bit cardinal
};
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
/// VSync modes.
typedef enum {
VSYNC_NONE,
VSYNC_DRM,
VSYNC_OPENGL,
VSYNC_OPENGL_OML,
VSYNC_OPENGL_SWC,
VSYNC_OPENGL_MSWC,
NUM_VSYNC,
} vsync_t;
/// @brief Possible backends of compton.
enum backend {
BKEND_XRENDER,
BKEND_GLX,
BKEND_XR_GLX_HYBRID,
NUM_BKEND,
};
/// @brief Possible swap methods.
enum {
SWAPM_BUFFER_AGE = -1,
SWAPM_UNDEFINED = 0,
SWAPM_COPY = 1,
SWAPM_EXCHANGE = 2,
};
typedef struct _glx_texture glx_texture_t;
#ifdef CONFIG_OPENGL
#ifdef DEBUG_GLX_DEBUG_CONTEXT
typedef GLXContext (*f_glXCreateContextAttribsARB) (Display *dpy,
GLXFBConfig config, GLXContext share_context, Bool direct,
const int *attrib_list);
typedef void (*GLDEBUGPROC) (GLenum source, GLenum type,
GLuint id, GLenum severity, GLsizei length, const GLchar* message,
GLvoid* userParam);
typedef void (*f_DebugMessageCallback) (GLDEBUGPROC, void *userParam);
#endif
typedef int (*f_WaitVideoSync) (int, int, unsigned *);
typedef int (*f_GetVideoSync) (unsigned *);
typedef Bool (*f_GetSyncValuesOML) (Display* dpy, GLXDrawable drawable, int64_t* ust, int64_t* msc, int64_t* sbc);
typedef Bool (*f_WaitForMscOML) (Display* dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t* ust, int64_t* msc, int64_t* sbc);
typedef int (*f_SwapIntervalSGI) (int interval);
typedef int (*f_SwapIntervalMESA) (unsigned int interval);
typedef void (*f_BindTexImageEXT) (Display *display, GLXDrawable drawable, int buffer, const int *attrib_list);
typedef void (*f_ReleaseTexImageEXT) (Display *display, GLXDrawable drawable, int buffer);
#ifdef CONFIG_OPENGL
// Looks like duplicate typedef of the same type is safe?
typedef int64_t GLint64;
typedef uint64_t GLuint64;
typedef struct __GLsync *GLsync;
#ifndef GL_SYNC_FLUSH_COMMANDS_BIT
#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
#endif
#ifndef GL_TIMEOUT_IGNORED
#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull
#endif
#ifndef GL_ALREADY_SIGNALED
#define GL_ALREADY_SIGNALED 0x911A
#endif
#ifndef GL_TIMEOUT_EXPIRED
#define GL_TIMEOUT_EXPIRED 0x911B
#endif
#ifndef GL_CONDITION_SATISFIED
#define GL_CONDITION_SATISFIED 0x911C
#endif
#ifndef GL_WAIT_FAILED
#define GL_WAIT_FAILED 0x911D
#endif
typedef GLsync (*f_FenceSync) (GLenum condition, GLbitfield flags);
typedef GLboolean (*f_IsSync) (GLsync sync);
typedef void (*f_DeleteSync) (GLsync sync);
typedef GLenum (*f_ClientWaitSync) (GLsync sync, GLbitfield flags,
GLuint64 timeout);
typedef void (*f_WaitSync) (GLsync sync, GLbitfield flags,
GLuint64 timeout);
typedef GLsync (*f_ImportSyncEXT) (GLenum external_sync_type,
GLintptr external_sync, GLbitfield flags);
#endif
#ifdef DEBUG_GLX_MARK
typedef void (*f_StringMarkerGREMEDY) (GLsizei len, const void *string);
typedef void (*f_FrameTerminatorGREMEDY) (void);
#endif
/// @brief Wrapper of a GLX FBConfig.
typedef struct {
GLXFBConfig cfg;
GLint texture_fmt;
GLint texture_tgts;
bool y_inverted;
} glx_fbconfig_t;
/// @brief Wrapper of a binded GLX texture.
struct _glx_texture {
GLuint texture;
GLXPixmap glpixmap;
xcb_pixmap_t pixmap;
GLenum target;
unsigned width;
unsigned height;
unsigned depth;
bool y_inverted;
};
#ifdef CONFIG_OPENGL
typedef struct {
/// Fragment shader for blur.
GLuint frag_shader;
/// GLSL program for blur.
GLuint prog;
/// Location of uniform "offset_x" in blur GLSL program.
GLint unifm_offset_x;
/// Location of uniform "offset_y" in blur GLSL program.
GLint unifm_offset_y;
/// Location of uniform "factor_center" in blur GLSL program.
GLint unifm_factor_center;
} glx_blur_pass_t;
typedef struct {
/// GLSL program.
GLuint prog;
/// Location of uniform "opacity" in window GLSL program.
GLint unifm_opacity;
/// Location of uniform "invert_color" in blur GLSL program.
GLint unifm_invert_color;
/// Location of uniform "tex" in window GLSL program.
GLint unifm_tex;
} glx_prog_main_t;
#define GLX_PROG_MAIN_INIT { \
.prog = 0, \
.unifm_opacity = -1, \
.unifm_invert_color = -1, \
.unifm_tex = -1, \
}
#endif
#else
typedef uint32_t glx_prog_main_t;
#endif
#define PAINT_INIT { .pixmap = None, .pict = None }
typedef struct conv {
int size;
double *data;
} conv;
/// Linked list type of atoms.
typedef struct _latom {
Atom atom;
struct _latom *next;
} latom_t;
#define REG_DATA_INIT { NULL, 0 }
typedef struct ev_session_timer ev_session_timer;
typedef struct ev_session_idle ev_session_idle;
typedef struct ev_session_prepare ev_session_prepare;
/// Structure representing all options.
typedef struct options_t {
// === Debugging ===
bool monitor_repaint;
bool print_diagnostics;
// === General ===
/// The configuration file we used.
char *config_file;
/// Path to write PID to.
char *write_pid_path;
/// The display name we used. NULL means we are using the value of the
/// <code>DISPLAY</code> environment variable.
char *display;
/// Safe representation of display name.
char *display_repr;
/// The backend in use.
enum backend backend;
/// Whether to sync X drawing to avoid certain delay issues with
/// GLX backend.
bool xrender_sync;
/// Whether to sync X drawing with X Sync fence.
bool xrender_sync_fence;
/// Whether to avoid using stencil buffer under GLX backend. Might be
/// unsafe.
bool glx_no_stencil;
/// Whether to avoid rebinding pixmap on window damage.
bool glx_no_rebind_pixmap;
/// GLX swap method we assume OpenGL uses.
int glx_swap_method;
/// Whether to use GL_EXT_gpu_shader4 to (hopefully) accelerates blurring.
bool glx_use_gpushader4;
/// Custom fragment shader for painting windows, as a string.
char *glx_fshader_win_str;
/// Custom GLX program used for painting window.
glx_prog_main_t glx_prog_win;
/// Whether to fork to background.
bool fork_after_register;
/// Whether to detect rounded corners.
bool detect_rounded_corners;
/// Force painting of window content with blending.
bool force_win_blend;
/// Resize damage for a specific number of pixels.
int resize_damage;
/// Whether to unredirect all windows if a full-screen opaque window
/// is detected.
bool unredir_if_possible;
/// List of conditions of windows to ignore as a full-screen window
/// when determining if a window could be unredirected.
c2_lptr_t *unredir_if_possible_blacklist;
/// Delay before unredirecting screen.
time_ms_t unredir_if_possible_delay;
/// Forced redirection setting through D-Bus.
switch_t redirected_force;
/// Whether to stop painting. Controlled through D-Bus.
switch_t stoppaint_force;
/// Whether to re-redirect screen on root size change.
bool reredir_on_root_change;
/// Whether to reinitialize GLX on root size change.
bool glx_reinit_on_root_change;
/// Whether to enable D-Bus support.
bool dbus;
/// Path to log file.
char *logpath;
/// Number of cycles to paint in benchmark mode. 0 for disabled.
int benchmark;
/// Window to constantly repaint in benchmark mode. 0 for full-screen.
Window benchmark_wid;
/// A list of conditions of windows not to paint.
c2_lptr_t *paint_blacklist;
/// Whether to avoid using xcb_composite_name_window_pixmap(), for debugging.
bool no_name_pixmap;
/// Whether to work under synchronized mode for debugging.
bool synchronize;
/// Whether to show all X errors.
bool show_all_xerrors;
/// Whether to avoid acquiring X Selection.
bool no_x_selection;
// === 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 do VSync aggressively.
bool vsync_aggressive;
/// Whether to use glFinish() instead of glFlush() for (possibly) better
/// VSync yet probably higher CPU usage.
bool vsync_use_glfinish;
// === 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;
/// argument string to shadow-exclude-reg option
char *shadow_exclude_reg_str;
/// Shadow blacklist. A linked list of conditions.
c2_lptr_t *shadow_blacklist;
/// Whether bounding-shaped window should be ignored.
bool shadow_ignore_shaped;
/// Whether to respect _COMPTON_SHADOW.
bool respect_prop_shadow;
/// Whether to crop shadow to the very Xinerama screen.
bool xinerama_shadow_crop;
// === 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;
/// Whether to disable fading on ARGB managed destroyed windows.
bool no_fading_destroyed_argb;
/// Fading blacklist. A linked list of conditions.
c2_lptr_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;
/// Default opacity for inactive windows.
opacity_t active_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;
/// Background blur blacklist. A linked list of conditions.
c2_lptr_t *blur_background_blacklist;
/// Blur convolution kernel.
xcb_render_fixed_t *blur_kerns[MAX_BLUR_PASS];
/// 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.
c2_lptr_t *invert_color_list;
/// Rules to change window opacity.
c2_lptr_t *opacity_rules;
// === Focus related ===
/// Consider windows of specific types to be always focused.
bool wintype_focus[NUM_WINTYPES];
/// 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 use EWMH _NET_ACTIVE_WINDOW to find active window.
bool use_ewmh_active_win;
/// A list of windows always to be considered focused.
c2_lptr_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;
#ifdef CONFIG_OPENGL
/// Structure containing GLX-dependent data for a compton session.
typedef struct {
// === OpenGL related ===
/// GLX context.
GLXContext context;
/// Whether we have GL_ARB_texture_non_power_of_two.
bool has_texture_non_power_of_two;
/// Pointer to glXGetVideoSyncSGI function.
f_GetVideoSync glXGetVideoSyncSGI;
/// Pointer to glXWaitVideoSyncSGI function.
f_WaitVideoSync glXWaitVideoSyncSGI;
/// Pointer to glXGetSyncValuesOML function.
f_GetSyncValuesOML glXGetSyncValuesOML;
/// Pointer to glXWaitForMscOML function.
f_WaitForMscOML glXWaitForMscOML;
/// Pointer to glXSwapIntervalSGI function.
f_SwapIntervalSGI glXSwapIntervalProc;
/// Pointer to glXSwapIntervalMESA function.
f_SwapIntervalMESA glXSwapIntervalMESAProc;
/// Pointer to glXBindTexImageEXT function.
f_BindTexImageEXT glXBindTexImageProc;
/// Pointer to glXReleaseTexImageEXT function.
f_ReleaseTexImageEXT glXReleaseTexImageProc;
/// Pointer to the glFenceSync() function.
f_FenceSync glFenceSyncProc;
/// Pointer to the glIsSync() function.
f_IsSync glIsSyncProc;
/// Pointer to the glDeleteSync() function.
f_DeleteSync glDeleteSyncProc;
/// Pointer to the glClientWaitSync() function.
f_ClientWaitSync glClientWaitSyncProc;
/// Pointer to the glWaitSync() function.
f_WaitSync glWaitSyncProc;
/// Pointer to the glImportSyncEXT() function.
f_ImportSyncEXT glImportSyncEXT;
#ifdef DEBUG_GLX_MARK
/// Pointer to StringMarkerGREMEDY function.
f_StringMarkerGREMEDY glStringMarkerGREMEDY;
/// Pointer to FrameTerminatorGREMEDY function.
f_FrameTerminatorGREMEDY glFrameTerminatorGREMEDY;
#endif
/// Current GLX Z value.
int z;
/// FBConfig-s for GLX pixmap of different depths.
glx_fbconfig_t *fbconfigs[OPENGL_MAX_DEPTH + 1];
#ifdef CONFIG_OPENGL
glx_blur_pass_t blur_passes[MAX_BLUR_PASS];
#endif
} glx_session_t;
#define CGLX_SESSION_INIT { .context = NULL }
#endif
/// Structure containing all necessary data for a compton session.
typedef struct session {
/// ev_io for X connection
ev_io xiow;
/// libev mainloop
struct ev_loop *loop;
// === Display related ===
/// Display in use.
Display *dpy;
/// Default screen.
int scr;
/// XCB connection.
xcb_connection_t *c;
/// Default visual.
xcb_visualid_t vis;
/// Pict formats info
xcb_render_query_pict_formats_reply_t *pictfmts;
/// 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;
/// Whether the root tile is filled by compton.
bool root_tile_fill;
/// Picture of the root window background.
paint_t root_tile_paint;
/// A region of the size of the screen.
region_t screen_reg;
/// Picture of root window. Destination of painting in no-DBE painting
/// mode.
xcb_render_picture_t root_picture;
/// A Picture acting as the painting target.
xcb_render_picture_t tgt_picture;
/// Temporary buffer to paint to before sending to display.
paint_t tgt_buffer;
XSyncFence tgt_buffer_fence;
/// Window ID of the window we register as a symbol.
Window reg_win;
#ifdef CONFIG_OPENGL
/// Pointer to GLX data.
glx_session_t *psglx;
#endif
// === Operation related ===
/// Program options.
options_t o;
/// Timeout for delayed unredirection.
ev_session_timer *unredir_timer;
/// Timer for fading
ev_session_timer *fade_timer;
/// Timer for delayed drawing, right now only used by
/// swopti
ev_session_timer *delayed_draw_timer;
/// Use an ev_idle callback for drawing
/// So we only start drawing when events are processed
ev_session_idle *draw_idle;
/// Called everytime we have timeouts or new data on socket,
/// so we can be sure if xcb read from X socket at anytime during event
/// handling, we will not left any event unhandled in the queue
ev_session_prepare *event_check;
/// Whether we have hit unredirection timeout.
bool tmout_unredir_hit;
/// Whether we need to redraw the screen
bool redraw_needed;
/// Whether the program is idling. I.e. no fading, no potential window
/// changes.
bool fade_running;
/// Program start time.
struct timeval time_start;
/// The region needs to painted on next paint.
region_t all_damage;
/// The region damaged on the last paint.
region_t all_damage_last[CGLX_MAX_BUFFER_AGE];
/// Whether all windows are currently redirected.
bool redirected;
/// Pre-generated alpha pictures.
xcb_render_picture_t *alpha_picts;
/// 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;
// Cached blur convolution kernels.
xcb_render_fixed_t *blur_kerns_cache[MAX_BLUR_PASS];
/// Reset program after next paint.
bool reset;
/// If compton should quit
bool quit;
// === Expose event related ===
/// Pointer to an array of <code>XRectangle</code>-s of exposed region.
/// XXX why do we need this array?
rect_t *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.
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.
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.
xcb_render_picture_t black_picture;
/// 1x1 Picture of the shadow color.
xcb_render_picture_t cshadow_picture;
/// 1x1 white Picture.
xcb_render_picture_t 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;
/// A region in which shadow is not painted on.
region_t shadow_exclude_reg;
// === 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
// === 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;
/// Whether X Present extension exists.
bool present_exists;
#ifdef CONFIG_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
#ifdef CONFIG_XINERAMA
/// Whether X Xinerama extension exists.
bool xinerama_exists;
/// Xinerama screen info.
xcb_xinerama_query_screens_reply_t *xinerama_scrs;
/// Xinerama screen regions.
region_t *xinerama_scr_regs;
/// Number of Xinerama screens.
int xinerama_nscrs;
#endif
/// Whether X Sync extension exists.
bool xsync_exists;
/// Event base number for X Sync extension.
int xsync_event;
/// Error base number for X Sync extension.
int xsync_error;
/// 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;
/// 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;
};
/// Enumeration for window event hints.
typedef enum {
WIN_EVMODE_UNKNOWN,
WIN_EVMODE_FRAME,
WIN_EVMODE_CLIENT
} win_evmode_t;
extern const char * const WINTYPES[NUM_WINTYPES];
extern const char * const VSYNC_STRS[NUM_VSYNC + 1];
extern const char * const BACKEND_STRS[NUM_BKEND + 1];
extern session_t *ps_g;
// == Debugging code ==
static inline void
print_timestamp(session_t *ps);
void
ev_xcb_error(session_t *ps, xcb_generic_error_t *err);
#ifdef DEBUG_BACKTRACE
#include <execinfo.h>
#define BACKTRACE_SIZE 25
/**
* Print current backtrace.
*
* 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 = 0; i < size; i++)
printf ("%s\n", strings[i]);
free(strings);
}
#endif
// === Functions ===
/**
* @brief Quit if the passed-in pointer is empty.
*/
static inline void *
allocchk_(const char *func_name, void *ptr) {
if (!ptr) {
printf_err("%s(): Failed to allocate memory.", func_name);
exit(1);
}
return ptr;
}
/// @brief Wrapper of allocchk_().
#define allocchk(ptr) allocchk_(__func__, ptr)
/// @brief Wrapper of malloc().
#define cmalloc(nmemb, type) ((type *) allocchk(malloc((nmemb) * sizeof(type))))
/// @brief Wrapper of calloc().
#define ccalloc(nmemb, type) ((type *) allocchk(calloc((nmemb), sizeof(type))))
/// @brief Wrapper of ealloc().
#define crealloc(ptr, nmemb, type) ((type *) allocchk(realloc((ptr), (nmemb) * sizeof(type))))
/// @brief Zero out the given memory block.
#define cmemzero(ptr, size) memset((ptr), 0, (size))
/// @brief Wrapper of cmemzero() that handles a pointer to a single item, for
/// convenience.
#define cmemzero_one(ptr) cmemzero((ptr), sizeof(*(ptr)))
/**
* 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;
}
static inline double
get_opacity_percent(win *w) {
return ((double) w->opacity) / OPAQUE;
}
/**
* Get current time in struct timeval.
*/
static inline struct timeval
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
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);
fprintf(stderr, "[ %5ld.%06ld ] ", diff.tv_sec, diff.tv_usec);
}
/**
* Allocate the space and copy a string.
*/
static inline char *
mstrcpy(const char *src) {
char *str = cmalloc(strlen(src) + 1, char);
strcpy(str, src);
return str;
}
/**
* Allocate the space and copy a string.
*/
static inline char *
mstrncpy(const char *src, unsigned len) {
char *str = cmalloc(len + 1, char);
strncpy(str, src, len);
str[len] = '\0';
return str;
}
/**
* Allocate the space and join two strings.
*/
static inline char *
mstrjoin(const char *src1, const char *src2) {
char *str = cmalloc(strlen(src1) + strlen(src2) + 1, char);
strcpy(str, src1);
strcat(str, src2);
return str;
}
/**
* Allocate the space and join two strings;
*/
static inline char *
mstrjoin3(const char *src1, const char *src2, const char *src3) {
char *str = cmalloc(strlen(src1) + strlen(src2)
+ strlen(src3) + 1, char);
strcpy(str, src1);
strcat(str, src2);
strcat(str, src3);
return str;
}
/**
* Concatenate a string on heap with another string.
*/
static inline void
mstrextend(char **psrc1, const char *src2) {
*psrc1 = crealloc(*psrc1, (*psrc1 ? strlen(*psrc1): 0) + strlen(src2) + 1,
char);
strcat(*psrc1, src2);
}
/**
* Parse a VSync option argument.
*/
static inline bool
parse_vsync(session_t *ps, const char *str) {
for (vsync_t i = 0; VSYNC_STRS[i]; ++i)
if (!strcasecmp(str, VSYNC_STRS[i])) {
ps->o.vsync = i;
return true;
}
printf_errf("(\"%s\"): Invalid vsync argument.", str);
return false;
}
/**
* Parse a backend option argument.
*/
static inline bool
parse_backend(session_t *ps, const char *str) {
for (enum backend i = 0; BACKEND_STRS[i]; ++i)
if (!strcasecmp(str, BACKEND_STRS[i])) {
ps->o.backend = i;
return true;
}
// Keep compatibility with an old revision containing a spelling mistake...
if (!strcasecmp(str, "xr_glx_hybird")) {
ps->o.backend = BKEND_XR_GLX_HYBRID;
return true;
}
// cju wants to use dashes
if (!strcasecmp(str, "xr-glx-hybrid")) {
ps->o.backend = BKEND_XR_GLX_HYBRID;
return true;
}
printf_errf("(\"%s\"): Invalid backend argument.", str);
return false;
}
/**
* Parse a glx_swap_method option argument.
*/
static inline bool
parse_glx_swap_method(session_t *ps, const char *str) {
// Parse alias
if (!strcmp("undefined", str)) {
ps->o.glx_swap_method = 0;
return true;
}
if (!strcmp("copy", str)) {
ps->o.glx_swap_method = 1;
return true;
}
if (!strcmp("exchange", str)) {
ps->o.glx_swap_method = 2;
return true;
}
if (!strcmp("buffer-age", str)) {
ps->o.glx_swap_method = -1;
return true;
}
// Parse number
{
char *pc = NULL;
int age = strtol(str, &pc, 0);
if (!pc || str == pc) {
printf_errf("(\"%s\"): Invalid number.", str);
return false;
}
for (; *pc; ++pc)
if (!isspace(*pc)) {
printf_errf("(\"%s\"): Trailing characters.", str);
return false;
}
if (age > CGLX_MAX_BUFFER_AGE + 1 || age < -1) {
printf_errf("(\"%s\"): Number too large / too small.", str);
return false;
}
ps->o.glx_swap_method = age;
}
return true;
}
/**
* Wrapper of XFree() for convenience.
*
* Because a NULL pointer cannot be passed to XFree(), its man page says.
*/
static inline void
cxfree(void *data) {
if (data)
XFree(data);
}
_Noreturn static inline void
die(const char *msg) {
puts(msg);
exit(1);
}
/**
* Wrapper of XInternAtom() for convenience.
*/
static inline xcb_atom_t
get_atom(session_t *ps, const char *atom_name) {
xcb_intern_atom_reply_t *reply =
xcb_intern_atom_reply(ps->c,
xcb_intern_atom(ps->c, False, strlen(atom_name), atom_name),
NULL);
xcb_atom_t atom = XCB_NONE;
if (reply) {
atom = reply->atom;
free(reply);
} else
die("Failed to intern atoms, bail out");
return atom;
}
/**
* Return the painting target window.
*/
static inline Window
get_tgt_window(session_t *ps) {
return ps->overlay != XCB_NONE ? ps->overlay: ps->root;
}
/**
* 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;
}
/**
* Check if current backend uses GLX.
*/
static inline bool
bkend_use_glx(session_t *ps) {
return BKEND_GLX == ps->o.backend
|| BKEND_XR_GLX_HYBRID == ps->o.backend;
}
/**
* Check if there's a GLX context.
*/
static inline bool
glx_has_context(session_t *ps) {
#ifdef CONFIG_OPENGL
return ps->psglx && ps->psglx->context;
#else
return false;
#endif
}
/**
* Check if a window is really focused.
*/
static inline bool
win_is_focused_real(session_t *ps, const win *w) {
return w->a.map_state == XCB_MAP_STATE_VIEWABLE && ps->active_win == w;
}
/**
* 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;
if (ps->active_win && win_is_focused_real(ps, ps->active_win))
return ps->active_win;
return NULL;
}
/**
* Free all regions in ps->all_damage_last .
*/
static inline void
free_all_damage_last(session_t *ps) {
for (int i = 0; i < CGLX_MAX_BUFFER_AGE; ++i)
pixman_region32_clear(&ps->all_damage_last[i]);
}
/**
* Free a XSync fence.
*/
static inline void
free_fence(session_t *ps, XSyncFence *pfence) {
if (*pfence)
XSyncDestroyFence(ps->dpy, *pfence);
*pfence = None;
}
/**
* Check if a rectangle includes the whole screen.
*/
static inline bool
rect_is_fullscreen(session_t *ps, int x, int y, int wid, int hei) {
return (x <= 0 && y <= 0 &&
(x + wid) >= ps->root_width &&
(y + hei) >= ps->root_height);
}
static void
set_ignore(session_t *ps, unsigned long sequence) {
if (ps->o.show_all_xerrors)
return;
ignore_t *i = malloc(sizeof(ignore_t));
if (!i) return;
i->sequence = sequence;
i->next = 0;
*ps->ignore_tail = i;
ps->ignore_tail = &i->next;
}
/**
* Ignore X errors caused by next X request.
*/
static inline void
set_ignore_next(session_t *ps) {
set_ignore(ps, NextRequest(ps->dpy));
}
/**
* Ignore X errors caused by given X request.
*/
static inline void
set_ignore_cookie(session_t *ps, xcb_void_cookie_t cookie) {
set_ignore(ps, cookie.sequence);
}
/**
* Check if a window is a fullscreen window.
*
* It's not using w->border_size for performance measures.
*/
static inline bool
win_is_fullscreen(session_t *ps, const win *w) {
return rect_is_fullscreen(ps, w->g.x, w->g.y, w->widthb, w->heightb)
&& (!w->bounding_shaped || w->rounded_corners);
}
/**
* Check if a window will be painted solid.
*/
static inline bool
win_is_solid(session_t *ps, const win *w) {
return WMODE_SOLID == w->mode && !ps->o.force_win_blend;
}
/**
* Determine if a window has a specific property.
*
* @param ps current session
* @param w window to check
* @param atom atom of property to check
* @return 1 if it has the attribute, 0 otherwise
*/
static inline bool
wid_has_prop(const session_t *ps, Window w, Atom atom) {
Atom type = None;
int format;
unsigned long nitems, after;
unsigned char *data;
if (Success == XGetWindowProperty(ps->dpy, w, atom, 0, 0, False,
AnyPropertyType, &type, &format, &nitems, &after, &data)) {
cxfree(data);
if (type) return true;
}
return false;
}
winprop_t
wid_get_prop_adv(const session_t *ps, Window w, Atom atom, long offset,
long length, Atom rtype, int rformat);
/**
* Wrapper of wid_get_prop_adv().
*/
static inline winprop_t
wid_get_prop(const session_t *ps, Window wid, Atom atom, long length,
Atom rtype, int rformat) {
return wid_get_prop_adv(ps, wid, atom, 0L, length, rtype, rformat);
}
/**
* Get the numeric property value from a win_prop_t.
*/
static inline long
winprop_get_int(winprop_t prop) {
long tgt = 0;
if (!prop.nitems)
return 0;
switch (prop.format) {
case 8: tgt = *(prop.p8); break;
case 16: tgt = *(prop.p16); break;
case 32: tgt = *(prop.p32); break;
default: assert(0);
break;
}
return tgt;
}
bool
wid_get_text_prop(session_t *ps, Window wid, Atom prop,
char ***pstrlst, int *pnstr);
/**
* Free a <code>winprop_t</code>.
*
* @param pprop pointer to the <code>winprop_t</code> to free.
*/
static inline void
free_winprop(winprop_t *pprop) {
// Empty the whole structure to avoid possible issues
if (pprop->ptr) {
cxfree(pprop->ptr);
pprop->ptr = NULL;
}
pprop->nitems = 0;
}
void
force_repaint(session_t *ps);
bool
vsync_init(session_t *ps);
void
vsync_deinit(session_t *ps);
#ifdef CONFIG_OPENGL
/** @name GLX
*/
///@{
void
xr_glx_sync(session_t *ps, Drawable d, XSyncFence *pfence);
/**
* Free a GLX texture.
*/
static inline void
free_texture_r(session_t *ps, GLuint *ptexture) {
if (*ptexture) {
assert(glx_has_context(ps));
glDeleteTextures(1, ptexture);
*ptexture = 0;
}
}
/**
* Free a GLX Framebuffer object.
*/
static inline void
free_glx_fbo(session_t *ps, GLuint *pfbo) {
#ifdef CONFIG_OPENGL
if (*pfbo) {
glDeleteFramebuffers(1, pfbo);
*pfbo = 0;
}
#endif
assert(!*pfbo);
}
#ifdef CONFIG_OPENGL
/**
* Free data in glx_blur_cache_t on resize.
*/
static inline void
free_glx_bc_resize(session_t *ps, glx_blur_cache_t *pbc) {
free_texture_r(ps, &pbc->textures[0]);
free_texture_r(ps, &pbc->textures[1]);
pbc->width = 0;
pbc->height = 0;
}
/**
* Free a glx_blur_cache_t
*/
static inline void
free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) {
free_glx_fbo(ps, &pbc->fbo);
free_glx_bc_resize(ps, pbc);
}
#endif
#endif
/**
* Add a OpenGL debugging marker.
*/
static inline void
glx_mark_(session_t *ps, const char *func, XID xid, bool start) {
#ifdef DEBUG_GLX_MARK
if (glx_has_context(ps) && ps->psglx->glStringMarkerGREMEDY) {
if (!func) func = "(unknown)";
const char *postfix = (start ? " (start)": " (end)");
char *str = malloc((strlen(func) + 12 + 2
+ strlen(postfix) + 5) * sizeof(char));
strcpy(str, func);
sprintf(str + strlen(str), "(%#010lx)%s", xid, postfix);
ps->psglx->glStringMarkerGREMEDY(strlen(str), str);
free(str);
}
#endif
}
#define glx_mark(ps, xid, start) glx_mark_(ps, __func__, xid, start)
/**
* Add a OpenGL debugging marker.
*/
static inline void
glx_mark_frame(session_t *ps) {
#ifdef DEBUG_GLX_MARK
if (glx_has_context(ps) && ps->psglx->glFrameTerminatorGREMEDY)
ps->psglx->glFrameTerminatorGREMEDY();
#endif
}
///@}
/**
* Synchronizes a X Render drawable to ensure all pending painting requests
* are completed.
*/
static inline void
xr_sync(session_t *ps, Drawable d, XSyncFence *pfence) {
if (!ps->o.xrender_sync)
return;
x_sync(ps->c);
if (ps->o.xrender_sync_fence && ps->xsync_exists) {
// TODO: If everybody just follows the rules stated in X Sync prototype,
// we need only one fence per screen, but let's stay a bit cautious right
// now
XSyncFence tmp_fence = None;
if (!pfence)
pfence = &tmp_fence;
assert(pfence);
if (!*pfence)
*pfence = XSyncCreateFence(ps->dpy, d, False);
if (*pfence) {
Bool __attribute__((unused)) triggered = False;
/* if (XSyncQueryFence(ps->dpy, *pfence, &triggered) && triggered)
XSyncResetFence(ps->dpy, *pfence); */
// The fence may fail to be created (e.g. because of died drawable)
assert(!XSyncQueryFence(ps->dpy, *pfence, &triggered) || !triggered);
XSyncTriggerFence(ps->dpy, *pfence);
XSyncAwaitFence(ps->dpy, pfence, 1);
assert(!XSyncQueryFence(ps->dpy, *pfence, &triggered) || triggered);
}
else {
printf_errf("(%#010lx): Failed to create X Sync fence.", d);
}
free_fence(ps, &tmp_fence);
if (*pfence)
XSyncResetFence(ps->dpy, *pfence);
}
#ifdef OPENGL
xr_glx_sync(ps, d, pfence);
#endif
}
/** @name DBus handling
*/
///@{
#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);
void
cdbus_ev_win_focusout(session_t *ps, win *w);
void
cdbus_ev_win_focusin(session_t *ps, win *w);
//!@}
/** @name DBus hooks
*/
///@{
void
win_set_shadow_force(session_t *ps, win *w, switch_t val);
void
win_set_fade_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
opts_init_track_focus(session_t *ps);
void
opts_set_no_fading_openclose(session_t *ps, bool newval);
//!@}
#endif
/**
* @brief Dump the given data to a file.
*/
static inline bool
write_binary_data(const char *path, const unsigned char *data, int length) {
if (!data)
return false;
FILE *f = fopen(path, "wb");
if (!f) {
printf_errf("(\"%s\"): Failed to open file for writing.", path);
return false;
}
int wrote_len = fwrite(data, sizeof(unsigned char), length, f);
fclose(f);
if (wrote_len != length) {
printf_errf("(\"%s\"): Failed to write all blocks: %d / %d", path,
wrote_len, length);
return false;
}
return true;
}
/**
* @brief Dump raw bytes in HEX format.
*
* @param data pointer to raw data
* @param len length of data
*/
static inline void
hexdump(const char *data, int len) {
static const int BYTE_PER_LN = 16;
if (len <= 0)
return;
// Print header
printf("%10s:", "Offset");
for (int i = 0; i < BYTE_PER_LN; ++i)
printf(" %2d", i);
putchar('\n');
// Dump content
for (int offset = 0; offset < len; ++offset) {
if (!(offset % BYTE_PER_LN))
printf("0x%08x:", offset);
printf(" %02hhx", data[offset]);
if ((BYTE_PER_LN - 1) == offset % BYTE_PER_LN)
putchar('\n');
}
if (len % BYTE_PER_LN)
putchar('\n');
fflush(stdout);
}
/**
* Set a <code>bool</code> array of all wintypes to true.
*/
static inline void
wintype_arr_enable(bool arr[]) {
wintype_t i;
for (i = 0; i < NUM_WINTYPES; ++i) {
arr[i] = true;
}
}