1 /*
2  * Compton - a compositor for X11
3  *
4  * Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
5  *
6  * Copyright (c) 2011-2013, Christopher Jeffrey
7  * See LICENSE for more information.
8  *
9  */
10 
11 #ifndef COMPTON_COMMON_H
12 #define COMPTON_COMMON_H
13 
14 // === Options ===
15 
16 // Debug options, enable them using -D in CFLAGS
17 // #define DEBUG_BACKTRACE  1
18 // #define DEBUG_REPAINT    1
19 // #define DEBUG_EVENTS     1
20 // #define DEBUG_RESTACK    1
21 // #define DEBUG_WINTYPE    1
22 // #define DEBUG_CLIENTWIN  1
23 // #define DEBUG_WINDATA    1
24 // #define DEBUG_WINMATCH   1
25 // #define DEBUG_REDIR      1
26 // #define DEBUG_ALLOC_REG  1
27 // #define DEBUG_FRAME      1
28 // #define DEBUG_LEADER     1
29 // #define DEBUG_C2         1
30 // #define DEBUG_GLX        1
31 // #define DEBUG_GLX_GLSL   1
32 // #define DEBUG_GLX_ERR    1
33 // #define DEBUG_GLX_MARK   1
34 // #define DEBUG_GLX_PAINTREG 1
35 // #define MONITOR_REPAINT  1
36 
37 // Whether to enable PCRE regular expression support in blacklists, enabled
38 // by default
39 // #define CONFIG_REGEX_PCRE 1
40 // Whether to enable JIT support of libpcre. This may cause problems on PaX
41 // kernels.
42 // #define CONFIG_REGEX_PCRE_JIT 1
43 // Whether to enable parsing of configuration files using libconfig.
44 // #define CONFIG_LIBCONFIG 1
45 // Whether we are using a legacy version of libconfig (1.3.x).
46 // #define CONFIG_LIBCONFIG_LEGACY 1
47 // Whether to enable DRM VSync support
48 // #define CONFIG_VSYNC_DRM 1
49 // Whether to enable OpenGL support
50 // #define CONFIG_VSYNC_OPENGL 1
51 // Whether to enable GLX GLSL support
52 // #define CONFIG_VSYNC_OPENGL_GLSL 1
53 // Whether to enable GLX FBO support
54 // #define CONFIG_VSYNC_OPENGL_FBO 1
55 // Whether to enable DBus support with libdbus.
56 // #define CONFIG_DBUS 1
57 // Whether to enable condition support.
58 // #define CONFIG_C2 1
59 // Whether to enable X Sync support.
60 // #define CONFIG_XSYNC 1
61 // Whether to enable GLX Sync support.
62 // #define CONFIG_GLX_XSYNC 1
63 
64 #if !defined(CONFIG_C2) && defined(DEBUG_C2)
65 #error Cannot enable c2 debugging without c2 support.
66 #endif
67 
68 #if (!defined(CONFIG_XSYNC) || !defined(CONFIG_VSYNC_OPENGL)) && defined(CONFIG_GLX_SYNC)
69 #error Cannot enable GL sync without X Sync / OpenGL support.
70 #endif
71 
72 #ifndef COMPTON_VERSION
73 #define COMPTON_VERSION "unknown"
74 #endif
75 
76 #if defined(DEBUG_ALLOC_REG)
77 #define DEBUG_BACKTRACE 1
78 #endif
79 
80 // === Includes ===
81 
82 // For some special functions
83 #define _GNU_SOURCE
84 
85 #include <stdbool.h>
86 #include <stdio.h>
87 #include <stdlib.h>
88 #include <string.h>
89 #include <inttypes.h>
90 #include <sys/poll.h>
91 #include <assert.h>
92 #include <time.h>
93 #include <ctype.h>
94 #include <sys/time.h>
95 
96 #include <X11/Xlib.h>
97 #include <X11/Xutil.h>
98 #include <X11/Xatom.h>
99 #include <X11/extensions/Xcomposite.h>
100 #include <X11/extensions/Xdamage.h>
101 #include <X11/extensions/Xrender.h>
102 #include <X11/extensions/shape.h>
103 #include <X11/extensions/Xrandr.h>
104 #include <X11/extensions/Xdbe.h>
105 #ifdef CONFIG_XSYNC
106 #include <X11/extensions/sync.h>
107 #endif
108 
109 #ifdef CONFIG_XINERAMA
110 #include <X11/extensions/Xinerama.h>
111 #endif
112 
113 // Workarounds for missing definitions in very old versions of X headers,
114 // thanks to consolers for reporting
115 #ifndef PictOpDifference
116 #define PictOpDifference 0x39
117 #endif
118 
119 // libconfig
120 #ifdef CONFIG_LIBCONFIG
121 #include <libgen.h>
122 #include <libconfig.h>
123 #endif
124 
125 // libdbus
126 #ifdef CONFIG_DBUS
127 #include <dbus/dbus.h>
128 #endif
129 
130 #ifdef CONFIG_VSYNC_OPENGL
131 
132 // libGL
133 #if defined(CONFIG_VSYNC_OPENGL_GLSL) || defined(CONFIG_VSYNC_OPENGL_FBO)
134 #define GL_GLEXT_PROTOTYPES
135 #endif
136 
137 #include <GL/glx.h>
138 
139 // Workarounds for missing definitions in some broken GL drivers, thanks to
140 // douglasp and consolers for reporting
141 #ifndef GL_TEXTURE_RECTANGLE
142 #define GL_TEXTURE_RECTANGLE 0x84F5
143 #endif
144 
145 #ifndef GLX_BACK_BUFFER_AGE_EXT
146 #define GLX_BACK_BUFFER_AGE_EXT 0x20F4
147 #endif
148 
149 #endif
150 
151 // === Macros ===
152 
153 #define MSTR_(s)        #s
154 #define MSTR(s)         MSTR_(s)
155 
156 /// @brief Wrapper for gcc branch prediction builtin, for likely branch.
157 #define likely(x)    __builtin_expect(!!(x), 1)
158 
159 /// @brief Wrapper for gcc branch prediction builtin, for unlikely branch.
160 #define unlikely(x)  __builtin_expect(!!(x), 0)
161 
162 /// Print out an error message.
163 #define printf_err(format, ...) \
164   fprintf(stderr, format "\n", ## __VA_ARGS__)
165 
166 /// Print out an error message with function name.
167 #define printf_errf(format, ...) \
168   printf_err("%s" format,  __func__, ## __VA_ARGS__)
169 
170 /// Print out an error message with function name, and quit with a
171 /// specific exit code.
172 #define printf_errfq(code, format, ...) { \
173   printf_err("%s" format,  __func__, ## __VA_ARGS__); \
174   exit(code); \
175 }
176 
177 /// Print out a debug message.
178 #define printf_dbg(format, ...) \
179   printf(format, ## __VA_ARGS__); \
180   fflush(stdout)
181 
182 /// Print out a debug message with function name.
183 #define printf_dbgf(format, ...) \
184   printf_dbg("%s" format, __func__, ## __VA_ARGS__)
185 
186 // Use #s here to prevent macro expansion
187 /// Macro used for shortening some debugging code.
188 #define CASESTRRET(s)   case s: return #s
189 
190 // X resource checker
191 #ifdef DEBUG_XRC
192 #include "xrescheck.h"
193 #endif
194 
195 // === Constants ===
196 #if !(COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2)
197 #error libXcomposite version unsupported
198 #endif
199 
200 /// @brief Length of generic buffers.
201 #define BUF_LEN 80
202 
203 #define ROUNDED_PERCENT 0.05
204 #define ROUNDED_PIXELS  10
205 
206 #define OPAQUE 0xffffffff
207 #define REGISTER_PROP "_NET_WM_CM_S"
208 
209 #define TIME_MS_MAX LONG_MAX
210 #define FADE_DELTA_TOLERANCE 0.2
211 #define SWOPTI_TOLERANCE 3000
212 #define TIMEOUT_RUN_TOLERANCE 0.05
213 #define WIN_GET_LEADER_MAX_RECURSION 20
214 
215 #define SEC_WRAP (15L * 24L * 60L * 60L)
216 
217 #define NS_PER_SEC 1000000000L
218 #define US_PER_SEC 1000000L
219 #define MS_PER_SEC 1000
220 
221 #define XRFILTER_CONVOLUTION  "convolution"
222 #define XRFILTER_GAUSSIAN     "gaussian"
223 #define XRFILTER_BINOMIAL     "binomial"
224 
225 /// @brief Maximum OpenGL FBConfig depth.
226 #define OPENGL_MAX_DEPTH 32
227 
228 /// @brief Maximum OpenGL buffer age.
229 #define CGLX_MAX_BUFFER_AGE 5
230 
231 /// @brief Maximum passes for blur.
232 #define MAX_BLUR_PASS 5
233 
234 // Window flags
235 
236 // Window size is changed
237 #define WFLAG_SIZE_CHANGE   0x0001
238 // Window size/position is changed
239 #define WFLAG_POS_CHANGE    0x0002
240 // Window opacity / dim state changed
241 #define WFLAG_OPCT_CHANGE   0x0004
242 
243 // === Types ===
244 
245 typedef uint32_t opacity_t;
246 typedef long time_ms_t;
247 
248 typedef enum {
249   WINTYPE_UNKNOWN,
250   WINTYPE_DESKTOP,
251   WINTYPE_DOCK,
252   WINTYPE_TOOLBAR,
253   WINTYPE_MENU,
254   WINTYPE_UTILITY,
255   WINTYPE_SPLASH,
256   WINTYPE_DIALOG,
257   WINTYPE_NORMAL,
258   WINTYPE_DROPDOWN_MENU,
259   WINTYPE_POPUP_MENU,
260   WINTYPE_TOOLTIP,
261   WINTYPE_NOTIFY,
262   WINTYPE_COMBO,
263   WINTYPE_DND,
264   NUM_WINTYPES
265 } wintype_t;
266 
267 /// Enumeration type to represent switches.
268 typedef enum {
269   OFF,    // false
270   ON,     // true
271   UNSET
272 } switch_t;
273 
274 /// Structure representing a X geometry.
275 typedef struct {
276   int wid;
277   int hei;
278   int x;
279   int y;
280 } geometry_t;
281 
282 /// A structure representing margins around a rectangle.
283 typedef struct {
284   int top;
285   int left;
286   int bottom;
287   int right;
288 } margin_t;
289 
290 // Or use cmemzero().
291 #define MARGIN_INIT { 0, 0, 0, 0 }
292 
293 /// Enumeration type of window painting mode.
294 typedef enum {
295   WMODE_TRANS,
296   WMODE_SOLID,
297   WMODE_ARGB
298 } winmode_t;
299 
300 /// Structure representing needed window updates.
301 typedef struct {
302   bool shadow       : 1;
303   bool fade         : 1;
304   bool focus        : 1;
305   bool invert_color : 1;
306 } win_upd_t;
307 
308 /// Structure representing Window property value.
309 typedef struct {
310   // All pointers have the same length, right?
311   // I wanted to use anonymous union but it's a GNU extension...
312   union {
313     unsigned char *p8;
314     short *p16;
315     long *p32;
316   } data;
317   unsigned long nitems;
318   Atom type;
319   int format;
320 } winprop_t;
321 
322 typedef struct _ignore {
323   struct _ignore *next;
324   unsigned long sequence;
325 } ignore_t;
326 
327 enum wincond_target {
328   CONDTGT_NAME,
329   CONDTGT_CLASSI,
330   CONDTGT_CLASSG,
331   CONDTGT_ROLE,
332 };
333 
334 enum wincond_type {
335   CONDTP_EXACT,
336   CONDTP_ANYWHERE,
337   CONDTP_FROMSTART,
338   CONDTP_WILDCARD,
339   CONDTP_REGEX_PCRE,
340 };
341 
342 #define CONDF_IGNORECASE 0x0001
343 
344 /// VSync modes.
345 typedef enum {
346   VSYNC_NONE,
347   VSYNC_DRM,
348   VSYNC_OPENGL,
349   VSYNC_OPENGL_OML,
350   VSYNC_OPENGL_SWC,
351   VSYNC_OPENGL_MSWC,
352   NUM_VSYNC,
353 } vsync_t;
354 
355 /// @brief Possible backends of compton.
356 enum backend {
357   BKEND_XRENDER,
358   BKEND_GLX,
359   BKEND_XR_GLX_HYBRID,
360   NUM_BKEND,
361 };
362 
363 /// @brief Possible swap methods.
364 enum {
365   SWAPM_BUFFER_AGE = -1,
366   SWAPM_UNDEFINED = 0,
367   SWAPM_COPY = 1,
368   SWAPM_EXCHANGE = 2,
369 };
370 
371 typedef struct _glx_texture glx_texture_t;
372 
373 #ifdef CONFIG_VSYNC_OPENGL
374 #ifdef DEBUG_GLX_DEBUG_CONTEXT
375 typedef GLXContext (*f_glXCreateContextAttribsARB) (Display *dpy,
376     GLXFBConfig config, GLXContext share_context, Bool direct,
377     const int *attrib_list);
378 typedef void (*GLDEBUGPROC) (GLenum source, GLenum type,
379     GLuint id, GLenum severity, GLsizei length, const GLchar* message,
380     GLvoid* userParam);
381 typedef void (*f_DebugMessageCallback) (GLDEBUGPROC, void *userParam);
382 #endif
383 
384 typedef int (*f_WaitVideoSync) (int, int, unsigned *);
385 typedef int (*f_GetVideoSync) (unsigned *);
386 
387 typedef Bool (*f_GetSyncValuesOML) (Display* dpy, GLXDrawable drawable, int64_t* ust, int64_t* msc, int64_t* sbc);
388 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);
389 
390 typedef int (*f_SwapIntervalSGI) (int interval);
391 typedef int (*f_SwapIntervalMESA) (unsigned int interval);
392 
393 typedef void (*f_BindTexImageEXT) (Display *display, GLXDrawable drawable, int buffer, const int *attrib_list);
394 typedef void (*f_ReleaseTexImageEXT) (Display *display, GLXDrawable drawable, int buffer);
395 
396 typedef void (*f_CopySubBuffer) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);
397 
398 #ifdef CONFIG_GLX_SYNC
399 // Looks like duplicate typedef of the same type is safe?
400 typedef int64_t GLint64;
401 typedef uint64_t GLuint64;
402 typedef struct __GLsync *GLsync;
403 
404 #ifndef GL_SYNC_FLUSH_COMMANDS_BIT
405 #define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
406 #endif
407 
408 #ifndef GL_TIMEOUT_IGNORED
409 #define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull
410 #endif
411 
412 #ifndef GL_ALREADY_SIGNALED
413 #define GL_ALREADY_SIGNALED 0x911A
414 #endif
415 
416 #ifndef GL_TIMEOUT_EXPIRED
417 #define GL_TIMEOUT_EXPIRED 0x911B
418 #endif
419 
420 #ifndef GL_CONDITION_SATISFIED
421 #define GL_CONDITION_SATISFIED 0x911C
422 #endif
423 
424 #ifndef GL_WAIT_FAILED
425 #define GL_WAIT_FAILED 0x911D
426 #endif
427 
428 typedef GLsync (*f_FenceSync) (GLenum condition, GLbitfield flags);
429 typedef GLboolean (*f_IsSync) (GLsync sync);
430 typedef void (*f_DeleteSync) (GLsync sync);
431 typedef GLenum (*f_ClientWaitSync) (GLsync sync, GLbitfield flags,
432     GLuint64 timeout);
433 typedef void (*f_WaitSync) (GLsync sync, GLbitfield flags,
434     GLuint64 timeout);
435 typedef GLsync (*f_ImportSyncEXT) (GLenum external_sync_type,
436     GLintptr external_sync, GLbitfield flags);
437 #endif
438 
439 #ifdef DEBUG_GLX_MARK
440 typedef void (*f_StringMarkerGREMEDY) (GLsizei len, const void *string);
441 typedef void (*f_FrameTerminatorGREMEDY) (void);
442 #endif
443 
444 /// @brief Wrapper of a GLX FBConfig.
445 typedef struct {
446   GLXFBConfig cfg;
447   GLint texture_fmt;
448   GLint texture_tgts;
449   bool y_inverted;
450 } glx_fbconfig_t;
451 
452 /// @brief Wrapper of a binded GLX texture.
453 struct _glx_texture {
454   GLuint texture;
455   GLXPixmap glpixmap;
456   Pixmap pixmap;
457   GLenum target;
458   unsigned width;
459   unsigned height;
460   unsigned depth;
461   bool y_inverted;
462 };
463 
464 #ifdef CONFIG_VSYNC_OPENGL_GLSL
465 typedef struct {
466   /// Fragment shader for blur.
467   GLuint frag_shader;
468   /// GLSL program for blur.
469   GLuint prog;
470   /// Location of uniform "offset_x" in blur GLSL program.
471   GLint unifm_offset_x;
472   /// Location of uniform "offset_y" in blur GLSL program.
473   GLint unifm_offset_y;
474   /// Location of uniform "factor_center" in blur GLSL program.
475   GLint unifm_factor_center;
476 } glx_blur_pass_t;
477 
478 typedef struct {
479   /// Framebuffer used for blurring.
480   GLuint fbo;
481   /// Textures used for blurring.
482   GLuint textures[2];
483   /// Width of the textures.
484   int width;
485   /// Height of the textures.
486   int height;
487 } glx_blur_cache_t;
488 
489 typedef struct {
490   /// GLSL program.
491   GLuint prog;
492   /// Location of uniform "opacity" in window GLSL program.
493   GLint unifm_opacity;
494   /// Location of uniform "invert_color" in blur GLSL program.
495   GLint unifm_invert_color;
496   /// Location of uniform "tex" in window GLSL program.
497   GLint unifm_tex;
498 } glx_prog_main_t;
499 
500 #define GLX_PROG_MAIN_INIT { \
501   .prog = 0, \
502   .unifm_opacity = -1, \
503   .unifm_invert_color = -1, \
504   .unifm_tex = -1, \
505 }
506 
507 #endif
508 #endif
509 
510 typedef struct {
511   Pixmap pixmap;
512   Picture pict;
513   glx_texture_t *ptex;
514 } paint_t;
515 
516 #define PAINT_INIT { .pixmap = None, .pict = None }
517 
518 typedef struct {
519   int size;
520   double *data;
521 } conv;
522 
523 /// Linked list type of atoms.
524 typedef struct _latom {
525   Atom atom;
526   struct _latom *next;
527 } latom_t;
528 
529 /// A representation of raw region data
530 typedef struct {
531   XRectangle *rects;
532   int nrects;
533 } reg_data_t;
534 
535 #define REG_DATA_INIT { NULL, 0 }
536 
537 struct _timeout_t;
538 
539 struct _win;
540 
541 typedef struct _c2_lptr c2_lptr_t;
542 
543 /// Structure representing all options.
544 typedef struct _options_t {
545   // === General ===
546   /// The configuration file we used.
547   char *config_file;
548   /// Path to write PID to.
549   char *write_pid_path;
550   /// The display name we used. NULL means we are using the value of the
551   /// <code>DISPLAY</code> environment variable.
552   char *display;
553   /// Safe representation of display name.
554   char *display_repr;
555   /// The backend in use.
556   enum backend backend;
557   /// Whether to sync X drawing to avoid certain delay issues with
558   /// GLX backend.
559   bool xrender_sync;
560   /// Whether to sync X drawing with X Sync fence.
561   bool xrender_sync_fence;
562   /// Whether to avoid using stencil buffer under GLX backend. Might be
563   /// unsafe.
564   bool glx_no_stencil;
565   /// Whether to copy unmodified regions from front buffer.
566   bool glx_copy_from_front;
567   /// Whether to use glXCopySubBufferMESA() to update screen.
568   bool glx_use_copysubbuffermesa;
569   /// Whether to avoid rebinding pixmap on window damage.
570   bool glx_no_rebind_pixmap;
571   /// GLX swap method we assume OpenGL uses.
572   int glx_swap_method;
573   /// Whether to use GL_EXT_gpu_shader4 to (hopefully) accelerates blurring.
574   bool glx_use_gpushader4;
575   /// Custom fragment shader for painting windows, as a string.
576   char *glx_fshader_win_str;
577 #ifdef CONFIG_VSYNC_OPENGL_GLSL
578   /// Custom GLX program used for painting window.
579   glx_prog_main_t glx_prog_win;
580 #endif
581   /// Whether to fork to background.
582   bool fork_after_register;
583   /// Whether to detect rounded corners.
584   bool detect_rounded_corners;
585   /// Whether to paint on X Composite overlay window instead of root
586   /// window.
587   bool paint_on_overlay;
588   /// Force painting of window content with blending.
589   bool force_win_blend;
590   /// Resize damage for a specific number of pixels.
591   int resize_damage;
592   /// Whether to unredirect all windows if a full-screen opaque window
593   /// is detected.
594   bool unredir_if_possible;
595   /// List of conditions of windows to ignore as a full-screen window
596   /// when determining if a window could be unredirected.
597   c2_lptr_t *unredir_if_possible_blacklist;
598   /// Delay before unredirecting screen.
599   time_ms_t unredir_if_possible_delay;
600   /// Forced redirection setting through D-Bus.
601   switch_t redirected_force;
602   /// Whether to stop painting. Controlled through D-Bus.
603   switch_t stoppaint_force;
604   /// Whether to re-redirect screen on root size change.
605   bool reredir_on_root_change;
606   /// Whether to reinitialize GLX on root size change.
607   bool glx_reinit_on_root_change;
608   /// Whether to enable D-Bus support.
609   bool dbus;
610   /// Path to log file.
611   char *logpath;
612   /// Number of cycles to paint in benchmark mode. 0 for disabled.
613   int benchmark;
614   /// Window to constantly repaint in benchmark mode. 0 for full-screen.
615   Window benchmark_wid;
616   /// A list of conditions of windows not to paint.
617   c2_lptr_t *paint_blacklist;
618   /// Whether to avoid using XCompositeNameWindowPixmap(), for debugging.
619   bool no_name_pixmap;
620   /// Whether to work under synchronized mode for debugging.
621   bool synchronize;
622   /// Whether to show all X errors.
623   bool show_all_xerrors;
624   /// Whether to avoid acquiring X Selection.
625   bool no_x_selection;
626 
627   // === VSync & software optimization ===
628   /// User-specified refresh rate.
629   int refresh_rate;
630   /// Whether to enable refresh-rate-based software optimization.
631   bool sw_opti;
632   /// VSync method to use;
633   vsync_t vsync;
634   /// Whether to enable double buffer.
635   bool dbe;
636   /// Whether to do VSync aggressively.
637   bool vsync_aggressive;
638   /// Whether to use glFinish() instead of glFlush() for (possibly) better
639   /// VSync yet probably higher CPU usage.
640   bool vsync_use_glfinish;
641 
642   // === Shadow ===
643   /// Enable/disable shadow for specific window types.
644   bool wintype_shadow[NUM_WINTYPES];
645   /// Red, green and blue tone of the shadow.
646   double shadow_red, shadow_green, shadow_blue;
647   int shadow_radius;
648   int shadow_offset_x, shadow_offset_y;
649   double shadow_opacity;
650   bool clear_shadow;
651   /// Geometry of a region in which shadow is not painted on.
652   geometry_t shadow_exclude_reg_geom;
653   /// Shadow blacklist. A linked list of conditions.
654   c2_lptr_t *shadow_blacklist;
655   /// Whether bounding-shaped window should be ignored.
656   bool shadow_ignore_shaped;
657   /// Whether to respect _COMPTON_SHADOW.
658   bool respect_prop_shadow;
659   /// Whether to crop shadow to the very Xinerama screen.
660   bool xinerama_shadow_crop;
661 
662   // === Fading ===
663   /// Enable/disable fading for specific window types.
664   bool wintype_fade[NUM_WINTYPES];
665   /// How much to fade in in a single fading step.
666   opacity_t fade_in_step;
667   /// How much to fade out in a single fading step.
668   opacity_t fade_out_step;
669   /// Fading time delta. In milliseconds.
670   time_ms_t fade_delta;
671   /// Whether to disable fading on window open/close.
672   bool no_fading_openclose;
673   /// Whether to disable fading on ARGB managed destroyed windows.
674   bool no_fading_destroyed_argb;
675   /// Fading blacklist. A linked list of conditions.
676   c2_lptr_t *fade_blacklist;
677 
678   // === Opacity ===
679   /// Default opacity for specific window types
680   double wintype_opacity[NUM_WINTYPES];
681   /// Default opacity for inactive windows.
682   /// 32-bit integer with the format of _NET_WM_OPACITY. 0 stands for
683   /// not enabled, default.
684   opacity_t inactive_opacity;
685   /// Default opacity for inactive windows.
686   opacity_t active_opacity;
687   /// Whether inactive_opacity overrides the opacity set by window
688   /// attributes.
689   bool inactive_opacity_override;
690   /// Frame opacity. Relative to window opacity, also affects shadow
691   /// opacity.
692   double frame_opacity;
693   /// Whether to detect _NET_WM_OPACITY on client windows. Used on window
694   /// managers that don't pass _NET_WM_OPACITY to frame windows.
695   bool detect_client_opacity;
696   /// Step for pregenerating alpha pictures. 0.01 - 1.0.
697   double alpha_step;
698 
699   // === Other window processing ===
700   /// Whether to blur background of semi-transparent / ARGB windows.
701   bool blur_background;
702   /// Whether to blur background when the window frame is not opaque.
703   /// Implies blur_background.
704   bool blur_background_frame;
705   /// Whether to use fixed blur strength instead of adjusting according
706   /// to window opacity.
707   bool blur_background_fixed;
708   /// Background blur blacklist. A linked list of conditions.
709   c2_lptr_t *blur_background_blacklist;
710   /// Blur convolution kernel.
711   XFixed *blur_kerns[MAX_BLUR_PASS];
712   /// How much to dim an inactive window. 0.0 - 1.0, 0 to disable.
713   double inactive_dim;
714   /// Whether to use fixed inactive dim opacity, instead of deciding
715   /// based on window opacity.
716   bool inactive_dim_fixed;
717   /// Conditions of windows to have inverted colors.
718   c2_lptr_t *invert_color_list;
719   /// Rules to change window opacity.
720   c2_lptr_t *opacity_rules;
721 
722   // === Focus related ===
723   /// Consider windows of specific types to be always focused.
724   bool wintype_focus[NUM_WINTYPES];
725   /// Whether to try to detect WM windows and mark them as focused.
726   bool mark_wmwin_focused;
727   /// Whether to mark override-redirect windows as focused.
728   bool mark_ovredir_focused;
729   /// Whether to use EWMH _NET_ACTIVE_WINDOW to find active window.
730   bool use_ewmh_active_win;
731   /// A list of windows always to be considered focused.
732   c2_lptr_t *focus_blacklist;
733   /// Whether to do window grouping with <code>WM_TRANSIENT_FOR</code>.
734   bool detect_transient;
735   /// Whether to do window grouping with <code>WM_CLIENT_LEADER</code>.
736   bool detect_client_leader;
737 
738   // === Calculated ===
739   /// Whether compton needs to track focus changes.
740   bool track_focus;
741   /// Whether compton needs to track window name and class.
742   bool track_wdata;
743   /// Whether compton needs to track window leaders.
744   bool track_leader;
745 } options_t;
746 
747 #ifdef CONFIG_VSYNC_OPENGL
748 /// Structure containing GLX-dependent data for a compton session.
749 typedef struct {
750   // === OpenGL related ===
751   /// GLX context.
752   GLXContext context;
753   /// Whether we have GL_ARB_texture_non_power_of_two.
754   bool has_texture_non_power_of_two;
755   /// Pointer to glXGetVideoSyncSGI function.
756   f_GetVideoSync glXGetVideoSyncSGI;
757   /// Pointer to glXWaitVideoSyncSGI function.
758   f_WaitVideoSync glXWaitVideoSyncSGI;
759    /// Pointer to glXGetSyncValuesOML function.
760   f_GetSyncValuesOML glXGetSyncValuesOML;
761   /// Pointer to glXWaitForMscOML function.
762   f_WaitForMscOML glXWaitForMscOML;
763   /// Pointer to glXSwapIntervalSGI function.
764   f_SwapIntervalSGI glXSwapIntervalProc;
765   /// Pointer to glXSwapIntervalMESA function.
766   f_SwapIntervalMESA glXSwapIntervalMESAProc;
767   /// Pointer to glXBindTexImageEXT function.
768   f_BindTexImageEXT glXBindTexImageProc;
769   /// Pointer to glXReleaseTexImageEXT function.
770   f_ReleaseTexImageEXT glXReleaseTexImageProc;
771   /// Pointer to glXCopySubBufferMESA function.
772   f_CopySubBuffer glXCopySubBufferProc;
773 #ifdef CONFIG_GLX_SYNC
774   /// Pointer to the glFenceSync() function.
775   f_FenceSync glFenceSyncProc;
776   /// Pointer to the glIsSync() function.
777   f_IsSync glIsSyncProc;
778   /// Pointer to the glDeleteSync() function.
779   f_DeleteSync glDeleteSyncProc;
780   /// Pointer to the glClientWaitSync() function.
781   f_ClientWaitSync glClientWaitSyncProc;
782   /// Pointer to the glWaitSync() function.
783   f_WaitSync glWaitSyncProc;
784   /// Pointer to the glImportSyncEXT() function.
785   f_ImportSyncEXT glImportSyncEXT;
786 #endif
787 #ifdef DEBUG_GLX_MARK
788   /// Pointer to StringMarkerGREMEDY function.
789   f_StringMarkerGREMEDY glStringMarkerGREMEDY;
790   /// Pointer to FrameTerminatorGREMEDY function.
791   f_FrameTerminatorGREMEDY glFrameTerminatorGREMEDY;
792 #endif
793   /// Current GLX Z value.
794   int z;
795   /// FBConfig-s for GLX pixmap of different depths.
796   glx_fbconfig_t *fbconfigs[OPENGL_MAX_DEPTH + 1];
797 #ifdef CONFIG_VSYNC_OPENGL_GLSL
798   glx_blur_pass_t blur_passes[MAX_BLUR_PASS];
799 #endif
800 } glx_session_t;
801 
802 #define CGLX_SESSION_INIT { .context = NULL }
803 
804 #endif
805 
806 /// Structure containing all necessary data for a compton session.
807 typedef struct _session_t {
808   // === Display related ===
809   /// Display in use.
810   Display *dpy;
811   /// Default screen.
812   int scr;
813   /// Default visual.
814   Visual *vis;
815   /// Default depth.
816   int depth;
817   /// Root window.
818   Window root;
819   /// Height of root window.
820   int root_height;
821   /// Width of root window.
822   int root_width;
823   // Damage of root window.
824   // Damage root_damage;
825   /// X Composite overlay window. Used if <code>--paint-on-overlay</code>.
826   Window overlay;
827   /// Whether the root tile is filled by compton.
828   bool root_tile_fill;
829   /// Picture of the root window background.
830   paint_t root_tile_paint;
831   /// A region of the size of the screen.
832   XserverRegion screen_reg;
833   /// Picture of root window. Destination of painting in no-DBE painting
834   /// mode.
835   Picture root_picture;
836   /// A Picture acting as the painting target.
837   Picture tgt_picture;
838   /// Temporary buffer to paint to before sending to display.
839   paint_t tgt_buffer;
840 #ifdef CONFIG_XSYNC
841   XSyncFence tgt_buffer_fence;
842 #endif
843   /// DBE back buffer for root window. Used in DBE painting mode.
844   XdbeBackBuffer root_dbe;
845   /// Window ID of the window we register as a symbol.
846   Window reg_win;
847 #ifdef CONFIG_VSYNC_OPENGL
848   /// Pointer to GLX data.
849   glx_session_t *psglx;
850 #endif
851 
852   // === Operation related ===
853   /// Program options.
854   options_t o;
855   /// File descriptors to check for reading.
856   fd_set *pfds_read;
857   /// File descriptors to check for writing.
858   fd_set *pfds_write;
859   /// File descriptors to check for exceptions.
860   fd_set *pfds_except;
861   /// Largest file descriptor in fd_set-s above.
862   int nfds_max;
863   /// Linked list of all timeouts.
864   struct _timeout_t *tmout_lst;
865   /// Timeout for delayed unredirection.
866   struct _timeout_t *tmout_unredir;
867   /// Whether we have hit unredirection timeout.
868   bool tmout_unredir_hit;
869   /// Whether we have received an event in this cycle.
870   bool ev_received;
871   /// Whether the program is idling. I.e. no fading, no potential window
872   /// changes.
873   bool idling;
874   /// Program start time.
875   struct timeval time_start;
876   /// The region needs to painted on next paint.
877   XserverRegion all_damage;
878   /// The region damaged on the last paint.
879   XserverRegion all_damage_last[CGLX_MAX_BUFFER_AGE];
880   /// Whether all windows are currently redirected.
881   bool redirected;
882   /// Pre-generated alpha pictures.
883   Picture *alpha_picts;
884   /// Whether all reg_ignore of windows should expire in this paint.
885   bool reg_ignore_expire;
886   /// Time of last fading. In milliseconds.
887   time_ms_t fade_time;
888   /// Head pointer of the error ignore linked list.
889   ignore_t *ignore_head;
890   /// Pointer to the <code>next</code> member of tail element of the error
891   /// ignore linked list.
892   ignore_t **ignore_tail;
893   // Cached blur convolution kernels.
894   XFixed *blur_kerns_cache[MAX_BLUR_PASS];
895   /// Reset program after next paint.
896   bool reset;
897 
898   // === Expose event related ===
899   /// Pointer to an array of <code>XRectangle</code>-s of exposed region.
900   XRectangle *expose_rects;
901   /// Number of <code>XRectangle</code>-s in <code>expose_rects</code>.
902   int size_expose;
903   /// Index of the next free slot in <code>expose_rects</code>.
904   int n_expose;
905 
906   // === Window related ===
907   /// Linked list of all windows.
908   struct _win *list;
909   /// Pointer to <code>win</code> of current active window. Used by
910   /// EWMH <code>_NET_ACTIVE_WINDOW</code> focus detection. In theory,
911   /// it's more reliable to store the window ID directly here, just in
912   /// case the WM does something extraordinary, but caching the pointer
913   /// means another layer of complexity.
914   struct _win *active_win;
915   /// Window ID of leader window of currently active window. Used for
916   /// subsidiary window detection.
917   Window active_leader;
918 
919   // === Shadow/dimming related ===
920   /// 1x1 black Picture.
921   Picture black_picture;
922   /// 1x1 Picture of the shadow color.
923   Picture cshadow_picture;
924   /// 1x1 white Picture.
925   Picture white_picture;
926   /// Gaussian map of shadow.
927   conv *gaussian_map;
928   // for shadow precomputation
929   /// Shadow depth on one side.
930   int cgsize;
931   /// Pre-computed color table for corners of shadow.
932   unsigned char *shadow_corner;
933   /// Pre-computed color table for a side of shadow.
934   unsigned char *shadow_top;
935   /// A region in which shadow is not painted on.
936   XserverRegion shadow_exclude_reg;
937 
938   // === Software-optimization-related ===
939   /// Currently used refresh rate.
940   short refresh_rate;
941   /// Interval between refresh in nanoseconds.
942   long refresh_intv;
943   /// Nanosecond offset of the first painting.
944   long paint_tm_offset;
945 
946 #ifdef CONFIG_VSYNC_DRM
947   // === DRM VSync related ===
948   /// File descriptor of DRI device file. Used for DRM VSync.
949   int drm_fd;
950 #endif
951 
952   // === X extension related ===
953   /// Event base number for X Fixes extension.
954   int xfixes_event;
955   /// Error base number for X Fixes extension.
956   int xfixes_error;
957   /// Event base number for X Damage extension.
958   int damage_event;
959   /// Error base number for X Damage extension.
960   int damage_error;
961   /// Event base number for X Render extension.
962   int render_event;
963   /// Error base number for X Render extension.
964   int render_error;
965   /// Event base number for X Composite extension.
966   int composite_event;
967   /// Error base number for X Composite extension.
968   int composite_error;
969   /// Major opcode for X Composite extension.
970   int composite_opcode;
971   /// Whether X Composite NameWindowPixmap is available. Aka if X
972   /// Composite version >= 0.2.
973   bool has_name_pixmap;
974   /// Whether X Shape extension exists.
975   bool shape_exists;
976   /// Event base number for X Shape extension.
977   int shape_event;
978   /// Error base number for X Shape extension.
979   int shape_error;
980   /// Whether X RandR extension exists.
981   bool randr_exists;
982   /// Event base number for X RandR extension.
983   int randr_event;
984   /// Error base number for X RandR extension.
985   int randr_error;
986 #ifdef CONFIG_VSYNC_OPENGL
987   /// Whether X GLX extension exists.
988   bool glx_exists;
989   /// Event base number for X GLX extension.
990   int glx_event;
991   /// Error base number for X GLX extension.
992   int glx_error;
993 #endif
994   /// Whether X DBE extension exists.
995   bool dbe_exists;
996 #ifdef CONFIG_XINERAMA
997   /// Whether X Xinerama extension exists.
998   bool xinerama_exists;
999   /// Xinerama screen info.
1000   XineramaScreenInfo *xinerama_scrs;
1001   /// Xinerama screen regions.
1002   XserverRegion *xinerama_scr_regs;
1003   /// Number of Xinerama screens.
1004   int xinerama_nscrs;
1005 #endif
1006 #ifdef CONFIG_XSYNC
1007   /// Whether X Sync extension exists.
1008   bool xsync_exists;
1009   /// Event base number for X Sync extension.
1010   int xsync_event;
1011   /// Error base number for X Sync extension.
1012   int xsync_error;
1013 #endif
1014   /// Whether X Render convolution filter exists.
1015   bool xrfilter_convolution_exists;
1016 
1017   // === Atoms ===
1018   /// Atom of property <code>_NET_WM_OPACITY</code>.
1019   Atom atom_opacity;
1020   /// Atom of <code>_NET_FRAME_EXTENTS</code>.
1021   Atom atom_frame_extents;
1022   /// Property atom to identify top-level frame window. Currently
1023   /// <code>WM_STATE</code>.
1024   Atom atom_client;
1025   /// Atom of property <code>WM_NAME</code>.
1026   Atom atom_name;
1027   /// Atom of property <code>_NET_WM_NAME</code>.
1028   Atom atom_name_ewmh;
1029   /// Atom of property <code>WM_CLASS</code>.
1030   Atom atom_class;
1031   /// Atom of property <code>WM_WINDOW_ROLE</code>.
1032   Atom atom_role;
1033   /// Atom of property <code>WM_TRANSIENT_FOR</code>.
1034   Atom atom_transient;
1035   /// Atom of property <code>WM_CLIENT_LEADER</code>.
1036   Atom atom_client_leader;
1037   /// Atom of property <code>_NET_ACTIVE_WINDOW</code>.
1038   Atom atom_ewmh_active_win;
1039   /// Atom of property <code>_COMPTON_SHADOW</code>.
1040   Atom atom_compton_shadow;
1041   /// Atom of property <code>_NET_WM_WINDOW_TYPE</code>.
1042   Atom atom_win_type;
1043   /// Array of atoms of all possible window types.
1044   Atom atoms_wintypes[NUM_WINTYPES];
1045   /// Linked list of additional atoms to track.
1046   latom_t *track_atom_lst;
1047 
1048 #ifdef CONFIG_DBUS
1049   // === DBus related ===
1050   // DBus connection.
1051   DBusConnection *dbus_conn;
1052   // DBus service name.
1053   char *dbus_service;
1054 #endif
1055 } session_t;
1056 
1057 /// Structure representing a top-level window compton manages.
1058 typedef struct _win {
1059   /// Pointer to the next structure in the linked list.
1060   struct _win *next;
1061   /// Pointer to the next higher window to paint.
1062   struct _win *prev_trans;
1063 
1064   // Core members
1065   /// ID of the top-level frame window.
1066   Window id;
1067   /// Window attributes.
1068   XWindowAttributes a;
1069 #ifdef CONFIG_XINERAMA
1070   /// Xinerama screen this window is on.
1071   int xinerama_scr;
1072 #endif
1073   /// Window visual pict format;
1074   XRenderPictFormat *pictfmt;
1075   /// Window painting mode.
1076   winmode_t mode;
1077   /// Whether the window has been damaged at least once.
1078   bool damaged;
1079 #ifdef CONFIG_XSYNC
1080   /// X Sync fence of drawable.
1081   XSyncFence fence;
1082 #endif
1083   /// Whether the window was damaged after last paint.
1084   bool pixmap_damaged;
1085   /// Damage of the window.
1086   Damage damage;
1087   /// Paint info of the window.
1088   paint_t paint;
1089   /// Bounding shape of the window.
1090   XserverRegion border_size;
1091   /// Region of the whole window, shadow region included.
1092   XserverRegion extents;
1093   /// Window flags. Definitions above.
1094   int_fast16_t flags;
1095   /// Whether there's a pending <code>ConfigureNotify</code> happening
1096   /// when the window is unmapped.
1097   bool need_configure;
1098   /// Queued <code>ConfigureNotify</code> when the window is unmapped.
1099   XConfigureEvent queue_configure;
1100   /// Region to be ignored when painting. Basically the region where
1101   /// higher opaque windows will paint upon. Depends on window frame
1102   /// opacity state, window geometry, window mapped/unmapped state,
1103   /// window mode, of this and all higher windows.
1104   XserverRegion reg_ignore;
1105   /// Cached width/height of the window including border.
1106   int widthb, heightb;
1107   /// Whether the window has been destroyed.
1108   bool destroyed;
1109   /// Whether the window is bounding-shaped.
1110   bool bounding_shaped;
1111   /// Whether the window just have rounded corners.
1112   bool rounded_corners;
1113   /// Whether this window is to be painted.
1114   bool to_paint;
1115   /// Whether the window is painting excluded.
1116   bool paint_excluded;
1117   /// Whether the window is unredirect-if-possible excluded.
1118   bool unredir_if_possible_excluded;
1119   /// Whether this window is in open/close state.
1120   bool in_openclose;
1121 
1122   // Client window related members
1123   /// ID of the top-level client window of the window.
1124   Window client_win;
1125   /// Type of the window.
1126   wintype_t window_type;
1127   /// Whether it looks like a WM window. We consider a window WM window if
1128   /// it does not have a decedent with WM_STATE and it is not override-
1129   /// redirected itself.
1130   bool wmwin;
1131   /// Leader window ID of the window.
1132   Window leader;
1133   /// Cached topmost window ID of the window.
1134   Window cache_leader;
1135 
1136   // Focus-related members
1137   /// Whether the window is to be considered focused.
1138   bool focused;
1139   /// Override value of window focus state. Set by D-Bus method calls.
1140   switch_t focused_force;
1141 
1142   // Blacklist related members
1143   /// Name of the window.
1144   char *name;
1145   /// Window instance class of the window.
1146   char *class_instance;
1147   /// Window general class of the window.
1148   char *class_general;
1149   /// <code>WM_WINDOW_ROLE</code> value of the window.
1150   char *role;
1151   const c2_lptr_t *cache_sblst;
1152   const c2_lptr_t *cache_fblst;
1153   const c2_lptr_t *cache_fcblst;
1154   const c2_lptr_t *cache_ivclst;
1155   const c2_lptr_t *cache_bbblst;
1156   const c2_lptr_t *cache_oparule;
1157   const c2_lptr_t *cache_pblst;
1158   const c2_lptr_t *cache_uipblst;
1159 
1160   // Opacity-related members
1161   /// Current window opacity.
1162   opacity_t opacity;
1163   /// Target window opacity.
1164   opacity_t opacity_tgt;
1165   /// Cached value of opacity window attribute.
1166   opacity_t opacity_prop;
1167   /// Cached value of opacity window attribute on client window. For
1168   /// broken window managers not transferring client window's
1169   /// _NET_WM_OPACITY value
1170   opacity_t opacity_prop_client;
1171   /// Last window opacity value we set.
1172   opacity_t opacity_set;
1173 
1174   // Fading-related members
1175   /// Do not fade if it's false. Change on window type change.
1176   /// Used by fading blacklist in the future.
1177   bool fade;
1178   /// Fade state on last paint.
1179   bool fade_last;
1180   /// Override value of window fade state. Set by D-Bus method calls.
1181   switch_t fade_force;
1182   /// Callback to be called after fading completed.
1183   void (*fade_callback) (session_t *ps, struct _win *w);
1184 
1185   // Frame-opacity-related members
1186   /// Current window frame opacity. Affected by window opacity.
1187   double frame_opacity;
1188   /// Frame extents. Acquired from _NET_FRAME_EXTENTS.
1189   margin_t frame_extents;
1190 
1191   // Shadow-related members
1192   /// Whether a window has shadow. Calculated.
1193   bool shadow;
1194   /// Shadow state on last paint.
1195   bool shadow_last;
1196   /// Override value of window shadow state. Set by D-Bus method calls.
1197   switch_t shadow_force;
1198   /// Opacity of the shadow. Affected by window opacity and frame opacity.
1199   double shadow_opacity;
1200   /// X offset of shadow. Affected by commandline argument.
1201   int shadow_dx;
1202   /// Y offset of shadow. Affected by commandline argument.
1203   int shadow_dy;
1204   /// Width of shadow. Affected by window size and commandline argument.
1205   int shadow_width;
1206   /// Height of shadow. Affected by window size and commandline argument.
1207   int shadow_height;
1208   /// Picture to render shadow. Affected by window size.
1209   paint_t shadow_paint;
1210   /// The value of _COMPTON_SHADOW attribute of the window. Below 0 for
1211   /// none.
1212   long prop_shadow;
1213 
1214   // Dim-related members
1215   /// Whether the window is to be dimmed.
1216   bool dim;
1217 
1218   /// Whether to invert window color.
1219   bool invert_color;
1220   /// Color inversion state on last paint.
1221   bool invert_color_last;
1222   /// Override value of window color inversion state. Set by D-Bus method
1223   /// calls.
1224   switch_t invert_color_force;
1225 
1226   /// Whether to blur window background.
1227   bool blur_background;
1228   /// Background state on last paint.
1229   bool blur_background_last;
1230 
1231 #ifdef CONFIG_VSYNC_OPENGL_GLSL
1232   /// Textures and FBO background blur use.
1233   glx_blur_cache_t glx_blur_cache;
1234 #endif
1235 } win;
1236 
1237 /// Temporary structure used for communication between
1238 /// <code>get_cfg()</code> and <code>parse_config()</code>.
1239 struct options_tmp {
1240   bool no_dock_shadow;
1241   bool no_dnd_shadow;
1242   double menu_opacity;
1243 };
1244 
1245 /// Structure for a recorded timeout.
1246 typedef struct _timeout_t {
1247   bool enabled;
1248   void *data;
1249   bool (*callback)(session_t *ps, struct _timeout_t *ptmout);
1250   time_ms_t interval;
1251   time_ms_t firstrun;
1252   time_ms_t lastrun;
1253   struct _timeout_t *next;
1254 } timeout_t;
1255 
1256 /// Enumeration for window event hints.
1257 typedef enum {
1258   WIN_EVMODE_UNKNOWN,
1259   WIN_EVMODE_FRAME,
1260   WIN_EVMODE_CLIENT
1261 } win_evmode_t;
1262 
1263 extern const char * const WINTYPES[NUM_WINTYPES];
1264 extern const char * const VSYNC_STRS[NUM_VSYNC + 1];
1265 extern const char * const BACKEND_STRS[NUM_BKEND + 1];
1266 extern session_t *ps_g;
1267 
1268 // == Debugging code ==
1269 static inline void
1270 print_timestamp(session_t *ps);
1271 
1272 #ifdef DEBUG_BACKTRACE
1273 
1274 #include <execinfo.h>
1275 #define BACKTRACE_SIZE  25
1276 
1277 /**
1278  * Print current backtrace.
1279  *
1280  * Stolen from glibc manual.
1281  */
1282 static inline void
print_backtrace(void)1283 print_backtrace(void) {
1284   void *array[BACKTRACE_SIZE];
1285   size_t size;
1286   char **strings;
1287 
1288   size = backtrace(array, BACKTRACE_SIZE);
1289   strings = backtrace_symbols(array, size);
1290 
1291   for (size_t i = 0; i < size; i++)
1292      printf ("%s\n", strings[i]);
1293 
1294   free(strings);
1295 }
1296 
1297 #ifdef DEBUG_ALLOC_REG
1298 
1299 /**
1300  * Wrapper of <code>XFixesCreateRegion</code>, for debugging.
1301  */
1302 static inline XserverRegion
XFixesCreateRegion_(Display * dpy,XRectangle * p,int n,const char * func,int line)1303 XFixesCreateRegion_(Display *dpy, XRectangle *p, int n,
1304     const char *func, int line) {
1305   XserverRegion reg = XFixesCreateRegion(dpy, p, n);
1306   print_timestamp(ps_g);
1307   printf("%#010lx: XFixesCreateRegion() in %s():%d\n", reg, func, line);
1308   print_backtrace();
1309   fflush(stdout);
1310   return reg;
1311 }
1312 
1313 /**
1314  * Wrapper of <code>XFixesDestroyRegion</code>, for debugging.
1315  */
1316 static inline void
XFixesDestroyRegion_(Display * dpy,XserverRegion reg,const char * func,int line)1317 XFixesDestroyRegion_(Display *dpy, XserverRegion reg,
1318     const char *func, int line) {
1319   XFixesDestroyRegion(dpy, reg);
1320   print_timestamp(ps_g);
1321   printf("%#010lx: XFixesDestroyRegion() in %s():%d\n", reg, func, line);
1322   fflush(stdout);
1323 }
1324 
1325 #define XFixesCreateRegion(dpy, p, n) XFixesCreateRegion_(dpy, p, n, __func__, __LINE__)
1326 #define XFixesDestroyRegion(dpy, reg) XFixesDestroyRegion_(dpy, reg, __func__, __LINE__)
1327 #endif
1328 
1329 #endif
1330 
1331 // === Functions ===
1332 
1333 /**
1334  * @brief Quit if the passed-in pointer is empty.
1335  */
1336 static inline void *
allocchk_(const char * func_name,void * ptr)1337 allocchk_(const char *func_name, void *ptr) {
1338   if (!ptr) {
1339     printf_err("%s(): Failed to allocate memory.", func_name);
1340     exit(1);
1341   }
1342   return ptr;
1343 }
1344 
1345 /// @brief Wrapper of allocchk_().
1346 #define allocchk(ptr) allocchk_(__func__, ptr)
1347 
1348 /// @brief Wrapper of malloc().
1349 #define cmalloc(nmemb, type) ((type *) allocchk(malloc((nmemb) * sizeof(type))))
1350 
1351 /// @brief Wrapper of calloc().
1352 #define ccalloc(nmemb, type) ((type *) allocchk(calloc((nmemb), sizeof(type))))
1353 
1354 /// @brief Wrapper of ealloc().
1355 #define crealloc(ptr, nmemb, type) ((type *) allocchk(realloc((ptr), (nmemb) * sizeof(type))))
1356 
1357 /// @brief Zero out the given memory block.
1358 #define cmemzero(ptr, size) memset((ptr), 0, (size))
1359 
1360 /// @brief Wrapper of cmemzero() that handles a pointer to a single item, for
1361 ///        convenience.
1362 #define cmemzero_one(ptr) cmemzero((ptr), sizeof(*(ptr)))
1363 
1364 /**
1365  * Return whether a struct timeval value is empty.
1366  */
1367 static inline bool
timeval_isempty(struct timeval * ptv)1368 timeval_isempty(struct timeval *ptv) {
1369   if (!ptv)
1370     return false;
1371 
1372   return ptv->tv_sec <= 0 && ptv->tv_usec <= 0;
1373 }
1374 
1375 /**
1376  * Compare a struct timeval with a time in milliseconds.
1377  *
1378  * @return > 0 if ptv > ms, 0 if ptv == 0, -1 if ptv < ms
1379  */
1380 static inline int
timeval_ms_cmp(struct timeval * ptv,time_ms_t ms)1381 timeval_ms_cmp(struct timeval *ptv, time_ms_t ms) {
1382   assert(ptv);
1383 
1384   // We use those if statement instead of a - expression because of possible
1385   // truncation problem from long to int.
1386   {
1387     long sec = ms / MS_PER_SEC;
1388     if (ptv->tv_sec > sec)
1389       return 1;
1390     if (ptv->tv_sec < sec)
1391       return -1;
1392   }
1393 
1394   {
1395     long usec = ms % MS_PER_SEC * (US_PER_SEC / MS_PER_SEC);
1396     if (ptv->tv_usec > usec)
1397       return 1;
1398     if (ptv->tv_usec < usec)
1399       return -1;
1400   }
1401 
1402   return 0;
1403 }
1404 
1405 /**
1406  * Subtracting two struct timeval values.
1407  *
1408  * Taken from glibc manual.
1409  *
1410  * Subtract the `struct timeval' values X and Y,
1411  * storing the result in RESULT.
1412  * Return 1 if the difference is negative, otherwise 0.
1413  */
1414 static inline int
timeval_subtract(struct timeval * result,struct timeval * x,struct timeval * y)1415 timeval_subtract(struct timeval *result,
1416                  struct timeval *x,
1417                  struct timeval *y) {
1418   /* Perform the carry for the later subtraction by updating y. */
1419   if (x->tv_usec < y->tv_usec) {
1420     long nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
1421     y->tv_usec -= 1000000 * nsec;
1422     y->tv_sec += nsec;
1423   }
1424 
1425   if (x->tv_usec - y->tv_usec > 1000000) {
1426     long nsec = (x->tv_usec - y->tv_usec) / 1000000;
1427     y->tv_usec += 1000000 * nsec;
1428     y->tv_sec -= nsec;
1429   }
1430 
1431   /* Compute the time remaining to wait.
1432      tv_usec is certainly positive. */
1433   result->tv_sec = x->tv_sec - y->tv_sec;
1434   result->tv_usec = x->tv_usec - y->tv_usec;
1435 
1436   /* Return 1 if result is negative. */
1437   return x->tv_sec < y->tv_sec;
1438 }
1439 
1440 /**
1441  * Subtracting two struct timespec values.
1442  *
1443  * Taken from glibc manual.
1444  *
1445  * Subtract the `struct timespec' values X and Y,
1446  * storing the result in RESULT.
1447  * Return 1 if the difference is negative, otherwise 0.
1448  */
1449 static inline int
timespec_subtract(struct timespec * result,struct timespec * x,struct timespec * y)1450 timespec_subtract(struct timespec *result,
1451                  struct timespec *x,
1452                  struct timespec *y) {
1453   /* Perform the carry for the later subtraction by updating y. */
1454   if (x->tv_nsec < y->tv_nsec) {
1455     long nsec = (y->tv_nsec - x->tv_nsec) / NS_PER_SEC + 1;
1456     y->tv_nsec -= NS_PER_SEC * nsec;
1457     y->tv_sec += nsec;
1458   }
1459 
1460   if (x->tv_nsec - y->tv_nsec > NS_PER_SEC) {
1461     long nsec = (x->tv_nsec - y->tv_nsec) / NS_PER_SEC;
1462     y->tv_nsec += NS_PER_SEC * nsec;
1463     y->tv_sec -= nsec;
1464   }
1465 
1466   /* Compute the time remaining to wait.
1467      tv_nsec is certainly positive. */
1468   result->tv_sec = x->tv_sec - y->tv_sec;
1469   result->tv_nsec = x->tv_nsec - y->tv_nsec;
1470 
1471   /* Return 1 if result is negative. */
1472   return x->tv_sec < y->tv_sec;
1473 }
1474 
1475 /**
1476  * Get current time in struct timeval.
1477  */
1478 static inline struct timeval
get_time_timeval(void)1479 get_time_timeval(void) {
1480   struct timeval tv = { 0, 0 };
1481 
1482   gettimeofday(&tv, NULL);
1483 
1484   // Return a time of all 0 if the call fails
1485   return tv;
1486 }
1487 
1488 /**
1489  * Get current time in struct timespec.
1490  *
1491  * Note its starting time is unspecified.
1492  */
1493 static inline struct timespec
get_time_timespec(void)1494 get_time_timespec(void) {
1495   struct timespec tm = { 0, 0 };
1496 
1497   clock_gettime(CLOCK_MONOTONIC, &tm);
1498 
1499   // Return a time of all 0 if the call fails
1500   return tm;
1501 }
1502 
1503 
1504 /**
1505  * Print time passed since program starts execution.
1506  *
1507  * Used for debugging.
1508  */
1509 static inline void
print_timestamp(session_t * ps)1510 print_timestamp(session_t *ps) {
1511   struct timeval tm, diff;
1512 
1513   if (gettimeofday(&tm, NULL)) return;
1514 
1515   timeval_subtract(&diff, &tm, &ps->time_start);
1516   printf("[ %5ld.%02ld ] ", diff.tv_sec, diff.tv_usec / 10000);
1517 }
1518 
1519 /**
1520  * Allocate the space and copy a string.
1521  */
1522 static inline char *
mstrcpy(const char * src)1523 mstrcpy(const char *src) {
1524   char *str = cmalloc(strlen(src) + 1, char);
1525 
1526   strcpy(str, src);
1527 
1528   return str;
1529 }
1530 
1531 /**
1532  * Allocate the space and copy a string.
1533  */
1534 static inline char *
mstrncpy(const char * src,unsigned len)1535 mstrncpy(const char *src, unsigned len) {
1536   char *str = cmalloc(len + 1, char);
1537 
1538   strncpy(str, src, len);
1539   str[len] = '\0';
1540 
1541   return str;
1542 }
1543 
1544 /**
1545  * Allocate the space and join two strings.
1546  */
1547 static inline char *
mstrjoin(const char * src1,const char * src2)1548 mstrjoin(const char *src1, const char *src2) {
1549   char *str = cmalloc(strlen(src1) + strlen(src2) + 1, char);
1550 
1551   strcpy(str, src1);
1552   strcat(str, src2);
1553 
1554   return str;
1555 }
1556 
1557 /**
1558  * Allocate the space and join two strings;
1559  */
1560 static inline char *
mstrjoin3(const char * src1,const char * src2,const char * src3)1561 mstrjoin3(const char *src1, const char *src2, const char *src3) {
1562   char *str = cmalloc(strlen(src1) + strlen(src2)
1563         + strlen(src3) + 1, char);
1564 
1565   strcpy(str, src1);
1566   strcat(str, src2);
1567   strcat(str, src3);
1568 
1569   return str;
1570 }
1571 
1572 /**
1573  * Concatenate a string on heap with another string.
1574  */
1575 static inline void
mstrextend(char ** psrc1,const char * src2)1576 mstrextend(char **psrc1, const char *src2) {
1577   *psrc1 = crealloc(*psrc1, (*psrc1 ? strlen(*psrc1): 0) + strlen(src2) + 1,
1578       char);
1579 
1580   strcat(*psrc1, src2);
1581 }
1582 
1583 /**
1584  * Normalize an int value to a specific range.
1585  *
1586  * @param i int value to normalize
1587  * @param min minimal value
1588  * @param max maximum value
1589  * @return normalized value
1590  */
1591 static inline int __attribute__((const))
normalize_i_range(int i,int min,int max)1592 normalize_i_range(int i, int min, int max) {
1593   if (i > max) return max;
1594   if (i < min) return min;
1595   return i;
1596 }
1597 
1598 /**
1599  * Select the larger integer of two.
1600  */
1601 static inline int __attribute__((const))
max_i(int a,int b)1602 max_i(int a, int b) {
1603   return (a > b ? a : b);
1604 }
1605 
1606 /**
1607  * Select the smaller integer of two.
1608  */
1609 static inline int __attribute__((const))
min_i(int a,int b)1610 min_i(int a, int b) {
1611   return (a > b ? b : a);
1612 }
1613 
1614 /**
1615  * Select the larger long integer of two.
1616  */
1617 static inline long __attribute__((const))
max_l(long a,long b)1618 max_l(long a, long b) {
1619   return (a > b ? a : b);
1620 }
1621 
1622 /**
1623  * Select the smaller long integer of two.
1624  */
1625 static inline long __attribute__((const))
min_l(long a,long b)1626 min_l(long a, long b) {
1627   return (a > b ? b : a);
1628 }
1629 
1630 /**
1631  * Normalize a double value to a specific range.
1632  *
1633  * @param d double value to normalize
1634  * @param min minimal value
1635  * @param max maximum value
1636  * @return normalized value
1637  */
1638 static inline double __attribute__((const))
normalize_d_range(double d,double min,double max)1639 normalize_d_range(double d, double min, double max) {
1640   if (d > max) return max;
1641   if (d < min) return min;
1642   return d;
1643 }
1644 
1645 /**
1646  * Normalize a double value to 0.\ 0 - 1.\ 0.
1647  *
1648  * @param d double value to normalize
1649  * @return normalized value
1650  */
1651 static inline double __attribute__((const))
normalize_d(double d)1652 normalize_d(double d) {
1653   return normalize_d_range(d, 0.0, 1.0);
1654 }
1655 
1656 /**
1657  * Parse a VSync option argument.
1658  */
1659 static inline bool
parse_vsync(session_t * ps,const char * str)1660 parse_vsync(session_t *ps, const char *str) {
1661   for (vsync_t i = 0; VSYNC_STRS[i]; ++i)
1662     if (!strcasecmp(str, VSYNC_STRS[i])) {
1663       ps->o.vsync = i;
1664       return true;
1665     }
1666 
1667   printf_errf("(\"%s\"): Invalid vsync argument.", str);
1668   return false;
1669 }
1670 
1671 /**
1672  * Parse a backend option argument.
1673  */
1674 static inline bool
parse_backend(session_t * ps,const char * str)1675 parse_backend(session_t *ps, const char *str) {
1676   for (enum backend i = 0; BACKEND_STRS[i]; ++i)
1677     if (!strcasecmp(str, BACKEND_STRS[i])) {
1678       ps->o.backend = i;
1679       return true;
1680     }
1681   // Keep compatibility with an old revision containing a spelling mistake...
1682   if (!strcasecmp(str, "xr_glx_hybird")) {
1683     ps->o.backend = BKEND_XR_GLX_HYBRID;
1684     return true;
1685   }
1686   // cju wants to use dashes
1687   if (!strcasecmp(str, "xr-glx-hybrid")) {
1688     ps->o.backend = BKEND_XR_GLX_HYBRID;
1689     return true;
1690   }
1691   printf_errf("(\"%s\"): Invalid backend argument.", str);
1692   return false;
1693 }
1694 
1695 /**
1696  * Parse a glx_swap_method option argument.
1697  */
1698 static inline bool
parse_glx_swap_method(session_t * ps,const char * str)1699 parse_glx_swap_method(session_t *ps, const char *str) {
1700   // Parse alias
1701   if (!strcmp("undefined", str)) {
1702     ps->o.glx_swap_method = 0;
1703     return true;
1704   }
1705 
1706   if (!strcmp("copy", str)) {
1707     ps->o.glx_swap_method = 1;
1708     return true;
1709   }
1710 
1711   if (!strcmp("exchange", str)) {
1712     ps->o.glx_swap_method = 2;
1713     return true;
1714   }
1715 
1716   if (!strcmp("buffer-age", str)) {
1717     ps->o.glx_swap_method = -1;
1718     return true;
1719   }
1720 
1721   // Parse number
1722   {
1723     char *pc = NULL;
1724     int age = strtol(str, &pc, 0);
1725     if (!pc || str == pc) {
1726       printf_errf("(\"%s\"): Invalid number.", str);
1727       return false;
1728     }
1729 
1730     for (; *pc; ++pc)
1731       if (!isspace(*pc)) {
1732         printf_errf("(\"%s\"): Trailing characters.", str);
1733         return false;
1734       }
1735 
1736     if (age > CGLX_MAX_BUFFER_AGE + 1 || age < -1) {
1737       printf_errf("(\"%s\"): Number too large / too small.", str);
1738       return false;
1739     }
1740 
1741     ps->o.glx_swap_method = age;
1742   }
1743 
1744   return true;
1745 }
1746 
1747 timeout_t *
1748 timeout_insert(session_t *ps, time_ms_t interval,
1749     bool (*callback)(session_t *ps, timeout_t *ptmout), void *data);
1750 
1751 void
1752 timeout_invoke(session_t *ps, timeout_t *ptmout);
1753 
1754 bool
1755 timeout_drop(session_t *ps, timeout_t *prm);
1756 
1757 void
1758 timeout_reset(session_t *ps, timeout_t *ptmout);
1759 
1760 /**
1761  * Add a file descriptor to a select() fd_set.
1762  */
1763 static inline bool
fds_insert_select(fd_set ** ppfds,int fd)1764 fds_insert_select(fd_set **ppfds, int fd) {
1765   assert(fd <= FD_SETSIZE);
1766 
1767   if (!*ppfds) {
1768     if ((*ppfds = malloc(sizeof(fd_set)))) {
1769       FD_ZERO(*ppfds);
1770     }
1771     else {
1772       fprintf(stderr, "Failed to allocate memory for select() fdset.\n");
1773       exit(1);
1774     }
1775   }
1776 
1777   FD_SET(fd, *ppfds);
1778 
1779   return true;
1780 }
1781 
1782 /**
1783  * Add a new file descriptor to wait for.
1784  */
1785 static inline bool
fds_insert(session_t * ps,int fd,short events)1786 fds_insert(session_t *ps, int fd, short events) {
1787   bool result = true;
1788 
1789   ps->nfds_max = max_i(fd + 1, ps->nfds_max);
1790 
1791   if (POLLIN & events)
1792     result = fds_insert_select(&ps->pfds_read, fd) && result;
1793   if (POLLOUT & events)
1794     result = fds_insert_select(&ps->pfds_write, fd) && result;
1795   if (POLLPRI & events)
1796     result = fds_insert_select(&ps->pfds_except, fd) && result;
1797 
1798   return result;
1799 }
1800 
1801 /**
1802  * Delete a file descriptor to wait for.
1803  */
1804 static inline void
fds_drop(session_t * ps,int fd,short events)1805 fds_drop(session_t *ps, int fd, short events) {
1806   // Drop fd from respective fd_set-s
1807   if (POLLIN & events && ps->pfds_read)
1808     FD_CLR(fd, ps->pfds_read);
1809   if (POLLOUT & events && ps->pfds_write)
1810     FD_CLR(fd, ps->pfds_write);
1811   if (POLLPRI & events && ps->pfds_except)
1812     FD_CLR(fd, ps->pfds_except);
1813 }
1814 
1815 #define CPY_FDS(key) \
1816   fd_set * key = NULL; \
1817   if (ps->key) { \
1818     key = malloc(sizeof(fd_set)); \
1819     memcpy(key, ps->key, sizeof(fd_set)); \
1820     if (!key) { \
1821       fprintf(stderr, "Failed to allocate memory for copying select() fdset.\n"); \
1822       exit(1); \
1823     } \
1824   } \
1825 
1826 /**
1827  * Poll for changes.
1828  *
1829  * poll() is much better than select(), but ppoll() does not exist on
1830  * *BSD.
1831  */
1832 static inline int
fds_poll(session_t * ps,struct timeval * ptv)1833 fds_poll(session_t *ps, struct timeval *ptv) {
1834   // Copy fds
1835   CPY_FDS(pfds_read);
1836   CPY_FDS(pfds_write);
1837   CPY_FDS(pfds_except);
1838 
1839   int ret = select(ps->nfds_max, pfds_read, pfds_write, pfds_except, ptv);
1840 
1841   free(pfds_read);
1842   free(pfds_write);
1843   free(pfds_except);
1844 
1845   return ret;
1846 }
1847 #undef CPY_FDS
1848 
1849 /**
1850  * Wrapper of XFree() for convenience.
1851  *
1852  * Because a NULL pointer cannot be passed to XFree(), its man page says.
1853  */
1854 static inline void
cxfree(void * data)1855 cxfree(void *data) {
1856   if (data)
1857     XFree(data);
1858 }
1859 
1860 /**
1861  * Wrapper of XInternAtom() for convenience.
1862  */
1863 static inline Atom
get_atom(session_t * ps,const char * atom_name)1864 get_atom(session_t *ps, const char *atom_name) {
1865   return XInternAtom(ps->dpy, atom_name, False);
1866 }
1867 
1868 /**
1869  * Return the painting target window.
1870  */
1871 static inline Window
get_tgt_window(session_t * ps)1872 get_tgt_window(session_t *ps) {
1873   return ps->o.paint_on_overlay ? ps->overlay: ps->root;
1874 }
1875 
1876 /**
1877  * Find a window from window id in window linked list of the session.
1878  */
1879 static inline win *
find_win(session_t * ps,Window id)1880 find_win(session_t *ps, Window id) {
1881   if (!id)
1882     return NULL;
1883 
1884   win *w;
1885 
1886   for (w = ps->list; w; w = w->next) {
1887     if (w->id == id && !w->destroyed)
1888       return w;
1889   }
1890 
1891   return 0;
1892 }
1893 
1894 /**
1895  * Find out the WM frame of a client window using existing data.
1896  *
1897  * @param id window ID
1898  * @return struct _win object of the found window, NULL if not found
1899  */
1900 static inline win *
find_toplevel(session_t * ps,Window id)1901 find_toplevel(session_t *ps, Window id) {
1902   if (!id)
1903     return NULL;
1904 
1905   for (win *w = ps->list; w; w = w->next) {
1906     if (w->client_win == id && !w->destroyed)
1907       return w;
1908   }
1909 
1910   return NULL;
1911 }
1912 
1913 
1914 /**
1915  * Check if current backend uses XRender for rendering.
1916  */
1917 static inline bool
bkend_use_xrender(session_t * ps)1918 bkend_use_xrender(session_t *ps) {
1919   return BKEND_XRENDER == ps->o.backend
1920     || BKEND_XR_GLX_HYBRID == ps->o.backend;
1921 }
1922 
1923 /**
1924  * Check if current backend uses GLX.
1925  */
1926 static inline bool
bkend_use_glx(session_t * ps)1927 bkend_use_glx(session_t *ps) {
1928   return BKEND_GLX == ps->o.backend
1929     || BKEND_XR_GLX_HYBRID == ps->o.backend;
1930 }
1931 
1932 /**
1933  * Check if there's a GLX context.
1934  */
1935 static inline bool
glx_has_context(session_t * ps)1936 glx_has_context(session_t *ps) {
1937 #ifdef CONFIG_VSYNC_OPENGL
1938   return ps->psglx && ps->psglx->context;
1939 #else
1940   return false;
1941 #endif
1942 }
1943 
1944 /**
1945  * Check if a window is really focused.
1946  */
1947 static inline bool
win_is_focused_real(session_t * ps,const win * w)1948 win_is_focused_real(session_t *ps, const win *w) {
1949   return IsViewable == w->a.map_state && ps->active_win == w;
1950 }
1951 
1952 /**
1953  * Find out the currently focused window.
1954  *
1955  * @return struct _win object of the found window, NULL if not found
1956  */
1957 static inline win *
find_focused(session_t * ps)1958 find_focused(session_t *ps) {
1959   if (!ps->o.track_focus) return NULL;
1960 
1961   if (ps->active_win && win_is_focused_real(ps, ps->active_win))
1962     return ps->active_win;
1963   return NULL;
1964 }
1965 
1966 /**
1967  * Copies a region.
1968  */
1969 static inline XserverRegion
copy_region(const session_t * ps,XserverRegion oldregion)1970 copy_region(const session_t *ps, XserverRegion oldregion) {
1971   if (!oldregion)
1972     return None;
1973 
1974   XserverRegion region = XFixesCreateRegion(ps->dpy, NULL, 0);
1975 
1976   XFixesCopyRegion(ps->dpy, region, oldregion);
1977 
1978   return region;
1979 }
1980 
1981 /**
1982  * Destroy a <code>XserverRegion</code>.
1983  */
1984 static inline void
free_region(session_t * ps,XserverRegion * p)1985 free_region(session_t *ps, XserverRegion *p) {
1986   if (*p) {
1987     XFixesDestroyRegion(ps->dpy, *p);
1988     *p = None;
1989   }
1990 }
1991 
1992 /**
1993  * Free all regions in ps->all_damage_last .
1994  */
1995 static inline void
free_all_damage_last(session_t * ps)1996 free_all_damage_last(session_t *ps) {
1997   for (int i = 0; i < CGLX_MAX_BUFFER_AGE; ++i)
1998     free_region(ps, &ps->all_damage_last[i]);
1999 }
2000 
2001 #ifdef CONFIG_XSYNC
2002 /**
2003  * Free a XSync fence.
2004  */
2005 static inline void
free_fence(session_t * ps,XSyncFence * pfence)2006 free_fence(session_t *ps, XSyncFence *pfence) {
2007   if (*pfence)
2008     XSyncDestroyFence(ps->dpy, *pfence);
2009   *pfence = None;
2010 }
2011 #else
2012 #define free_fence(ps, pfence) ((void) 0)
2013 #endif
2014 
2015 /**
2016  * Crop a rectangle by another rectangle.
2017  *
2018  * psrc and pdst cannot be the same.
2019  */
2020 static inline void
rect_crop(XRectangle * pdst,const XRectangle * psrc,const XRectangle * pbound)2021 rect_crop(XRectangle *pdst, const XRectangle *psrc, const XRectangle *pbound) {
2022   assert(psrc != pdst);
2023   pdst->x = max_i(psrc->x, pbound->x);
2024   pdst->y = max_i(psrc->y, pbound->y);
2025   pdst->width = max_i(0, min_i(psrc->x + psrc->width, pbound->x + pbound->width) - pdst->x);
2026   pdst->height = max_i(0, min_i(psrc->y + psrc->height, pbound->y + pbound->height) - pdst->y);
2027 }
2028 
2029 /**
2030  * Check if a rectangle includes the whole screen.
2031  */
2032 static inline bool
rect_is_fullscreen(session_t * ps,int x,int y,unsigned wid,unsigned hei)2033 rect_is_fullscreen(session_t *ps, int x, int y, unsigned wid, unsigned hei) {
2034   return (x <= 0 && y <= 0
2035       && (x + wid) >= ps->root_width && (y + hei) >= ps->root_height);
2036 }
2037 
2038 /**
2039  * Check if a window is a fullscreen window.
2040  *
2041  * It's not using w->border_size for performance measures.
2042  */
2043 static inline bool
win_is_fullscreen(session_t * ps,const win * w)2044 win_is_fullscreen(session_t *ps, const win *w) {
2045   return rect_is_fullscreen(ps, w->a.x, w->a.y, w->widthb, w->heightb)
2046       && (!w->bounding_shaped || w->rounded_corners);
2047 }
2048 
2049 /**
2050  * Check if a window will be painted solid.
2051  */
2052 static inline bool
win_is_solid(session_t * ps,const win * w)2053 win_is_solid(session_t *ps, const win *w) {
2054   return WMODE_SOLID == w->mode && !ps->o.force_win_blend;
2055 }
2056 
2057 /**
2058  * Determine if a window has a specific property.
2059  *
2060  * @param ps current session
2061  * @param w window to check
2062  * @param atom atom of property to check
2063  * @return 1 if it has the attribute, 0 otherwise
2064  */
2065 static inline bool
wid_has_prop(const session_t * ps,Window w,Atom atom)2066 wid_has_prop(const session_t *ps, Window w, Atom atom) {
2067   Atom type = None;
2068   int format;
2069   unsigned long nitems, after;
2070   unsigned char *data;
2071 
2072   if (Success == XGetWindowProperty(ps->dpy, w, atom, 0, 0, False,
2073         AnyPropertyType, &type, &format, &nitems, &after, &data)) {
2074     cxfree(data);
2075     if (type) return true;
2076   }
2077 
2078   return false;
2079 }
2080 
2081 winprop_t
2082 wid_get_prop_adv(const session_t *ps, Window w, Atom atom, long offset,
2083     long length, Atom rtype, int rformat);
2084 
2085 /**
2086  * Wrapper of wid_get_prop_adv().
2087  */
2088 static inline winprop_t
wid_get_prop(const session_t * ps,Window wid,Atom atom,long length,Atom rtype,int rformat)2089 wid_get_prop(const session_t *ps, Window wid, Atom atom, long length,
2090     Atom rtype, int rformat) {
2091   return wid_get_prop_adv(ps, wid, atom, 0L, length, rtype, rformat);
2092 }
2093 
2094 /**
2095  * Get the numeric property value from a win_prop_t.
2096  */
2097 static inline long
winprop_get_int(winprop_t prop)2098 winprop_get_int(winprop_t prop) {
2099   long tgt = 0;
2100 
2101   if (!prop.nitems)
2102     return 0;
2103 
2104   switch (prop.format) {
2105     case 8:   tgt = *(prop.data.p8);    break;
2106     case 16:  tgt = *(prop.data.p16);   break;
2107     case 32:  tgt = *(prop.data.p32);   break;
2108     default:  assert(0);
2109               break;
2110   }
2111 
2112   return tgt;
2113 }
2114 
2115 bool
2116 wid_get_text_prop(session_t *ps, Window wid, Atom prop,
2117     char ***pstrlst, int *pnstr);
2118 
2119 /**
2120  * Free a <code>winprop_t</code>.
2121  *
2122  * @param pprop pointer to the <code>winprop_t</code> to free.
2123  */
2124 static inline void
free_winprop(winprop_t * pprop)2125 free_winprop(winprop_t *pprop) {
2126   // Empty the whole structure to avoid possible issues
2127   if (pprop->data.p8) {
2128     cxfree(pprop->data.p8);
2129     pprop->data.p8 = NULL;
2130   }
2131   pprop->nitems = 0;
2132 }
2133 
2134 void
2135 force_repaint(session_t *ps);
2136 
2137 bool
2138 vsync_init(session_t *ps);
2139 
2140 void
2141 vsync_deinit(session_t *ps);
2142 
2143 #ifdef CONFIG_VSYNC_OPENGL
2144 /** @name GLX
2145  */
2146 ///@{
2147 
2148 #ifdef CONFIG_GLX_SYNC
2149 void
2150 xr_glx_sync(session_t *ps, Drawable d, XSyncFence *pfence);
2151 #endif
2152 
2153 bool
2154 glx_init(session_t *ps, bool need_render);
2155 
2156 void
2157 glx_destroy(session_t *ps);
2158 
2159 bool
2160 glx_reinit(session_t *ps, bool need_render);
2161 
2162 void
2163 glx_on_root_change(session_t *ps);
2164 
2165 bool
2166 glx_init_blur(session_t *ps);
2167 
2168 #ifdef CONFIG_VSYNC_OPENGL_GLSL
2169 bool
2170 glx_load_prog_main(session_t *ps,
2171     const char *vshader_str, const char *fshader_str,
2172     glx_prog_main_t *pprogram);
2173 #endif
2174 
2175 bool
2176 glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
2177     unsigned width, unsigned height, unsigned depth);
2178 
2179 void
2180 glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
2181 
2182 void
2183 glx_paint_pre(session_t *ps, XserverRegion *preg);
2184 
2185 /**
2186  * Check if a texture is binded, or is binded to the given pixmap.
2187  */
2188 static inline bool
glx_tex_binded(const glx_texture_t * ptex,Pixmap pixmap)2189 glx_tex_binded(const glx_texture_t *ptex, Pixmap pixmap) {
2190   return ptex && ptex->glpixmap && ptex->texture
2191     && (!pixmap || pixmap == ptex->pixmap);
2192 }
2193 
2194 void
2195 glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg);
2196 
2197 #ifdef CONFIG_VSYNC_OPENGL_GLSL
2198 bool
2199 glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
2200     GLfloat factor_center,
2201     XserverRegion reg_tgt, const reg_data_t *pcache_reg,
2202     glx_blur_cache_t *pbc);
2203 #endif
2204 
2205 bool
2206 glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
2207     GLfloat factor, XserverRegion reg_tgt, const reg_data_t *pcache_reg);
2208 
2209 bool
2210 glx_render_(session_t *ps, const glx_texture_t *ptex,
2211     int x, int y, int dx, int dy, int width, int height, int z,
2212     double opacity, bool argb, bool neg,
2213     XserverRegion reg_tgt, const reg_data_t *pcache_reg
2214 #ifdef CONFIG_VSYNC_OPENGL_GLSL
2215     , const glx_prog_main_t *pprogram
2216 #endif
2217     );
2218 
2219 #ifdef CONFIG_VSYNC_OPENGL_GLSL
2220 #define \
2221    glx_render(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, reg_tgt, pcache_reg, pprogram) \
2222   glx_render_(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, reg_tgt, pcache_reg, pprogram)
2223 #else
2224 #define \
2225    glx_render(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, reg_tgt, pcache_reg, pprogram) \
2226   glx_render_(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, reg_tgt, pcache_reg)
2227 #endif
2228 
2229 void
2230 glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg);
2231 
2232 unsigned char *
2233 glx_take_screenshot(session_t *ps, int *out_length);
2234 
2235 #ifdef CONFIG_VSYNC_OPENGL_GLSL
2236 GLuint
2237 glx_create_shader(GLenum shader_type, const char *shader_str);
2238 
2239 GLuint
2240 glx_create_program(const GLuint * const shaders, int nshaders);
2241 
2242 GLuint
2243 glx_create_program_from_str(const char *vert_shader_str,
2244     const char *frag_shader_str);
2245 #endif
2246 
2247 /**
2248  * Free a GLX texture.
2249  */
2250 static inline void
free_texture_r(session_t * ps,GLuint * ptexture)2251 free_texture_r(session_t *ps, GLuint *ptexture) {
2252   if (*ptexture) {
2253     assert(glx_has_context(ps));
2254     glDeleteTextures(1, ptexture);
2255     *ptexture = 0;
2256   }
2257 }
2258 
2259 /**
2260  * Free a GLX Framebuffer object.
2261  */
2262 static inline void
free_glx_fbo(session_t * ps,GLuint * pfbo)2263 free_glx_fbo(session_t *ps, GLuint *pfbo) {
2264 #ifdef CONFIG_VSYNC_OPENGL_FBO
2265   if (*pfbo) {
2266     glDeleteFramebuffers(1, pfbo);
2267     *pfbo = 0;
2268   }
2269 #endif
2270   assert(!*pfbo);
2271 }
2272 
2273 #ifdef CONFIG_VSYNC_OPENGL_GLSL
2274 /**
2275  * Free data in glx_blur_cache_t on resize.
2276  */
2277 static inline void
free_glx_bc_resize(session_t * ps,glx_blur_cache_t * pbc)2278 free_glx_bc_resize(session_t *ps, glx_blur_cache_t *pbc) {
2279   free_texture_r(ps, &pbc->textures[0]);
2280   free_texture_r(ps, &pbc->textures[1]);
2281   pbc->width = 0;
2282   pbc->height = 0;
2283 }
2284 
2285 /**
2286  * Free a glx_blur_cache_t
2287  */
2288 static inline void
free_glx_bc(session_t * ps,glx_blur_cache_t * pbc)2289 free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) {
2290   free_glx_fbo(ps, &pbc->fbo);
2291   free_glx_bc_resize(ps, pbc);
2292 }
2293 #endif
2294 #endif
2295 
2296 /**
2297  * Free a glx_texture_t.
2298  */
2299 static inline void
free_texture(session_t * ps,glx_texture_t ** pptex)2300 free_texture(session_t *ps, glx_texture_t **pptex) {
2301   glx_texture_t *ptex = *pptex;
2302 
2303   // Quit if there's nothing
2304   if (!ptex)
2305     return;
2306 
2307 #ifdef CONFIG_VSYNC_OPENGL
2308   glx_release_pixmap(ps, ptex);
2309 
2310   free_texture_r(ps, &ptex->texture);
2311 
2312   // Free structure itself
2313   free(ptex);
2314   *pptex = NULL;
2315 #endif
2316   assert(!*pptex);
2317 }
2318 
2319 /**
2320  * Free GLX part of paint_t.
2321  */
2322 static inline void
free_paint_glx(session_t * ps,paint_t * ppaint)2323 free_paint_glx(session_t *ps, paint_t *ppaint) {
2324   free_texture(ps, &ppaint->ptex);
2325 }
2326 
2327 /**
2328  * Free GLX part of win.
2329  */
2330 static inline void
free_win_res_glx(session_t * ps,win * w)2331 free_win_res_glx(session_t *ps, win *w) {
2332   free_paint_glx(ps, &w->paint);
2333   free_paint_glx(ps, &w->shadow_paint);
2334 #ifdef CONFIG_VSYNC_OPENGL_GLSL
2335   free_glx_bc(ps, &w->glx_blur_cache);
2336 #endif
2337 }
2338 
2339 /**
2340  * Add a OpenGL debugging marker.
2341  */
2342 static inline void
glx_mark_(session_t * ps,const char * func,XID xid,bool start)2343 glx_mark_(session_t *ps, const char *func, XID xid, bool start) {
2344 #ifdef DEBUG_GLX_MARK
2345   if (glx_has_context(ps) && ps->psglx->glStringMarkerGREMEDY) {
2346     if (!func) func = "(unknown)";
2347     const char *postfix = (start ? " (start)": " (end)");
2348     char *str = malloc((strlen(func) + 12 + 2
2349           + strlen(postfix) + 5) * sizeof(char));
2350     strcpy(str, func);
2351     sprintf(str + strlen(str), "(%#010lx)%s", xid, postfix);
2352     ps->psglx->glStringMarkerGREMEDY(strlen(str), str);
2353     free(str);
2354   }
2355 #endif
2356 }
2357 
2358 #define glx_mark(ps, xid, start) glx_mark_(ps, __func__, xid, start)
2359 
2360 /**
2361  * Add a OpenGL debugging marker.
2362  */
2363 static inline void
glx_mark_frame(session_t * ps)2364 glx_mark_frame(session_t *ps) {
2365 #ifdef DEBUG_GLX_MARK
2366   if (glx_has_context(ps) && ps->psglx->glFrameTerminatorGREMEDY)
2367     ps->psglx->glFrameTerminatorGREMEDY();
2368 #endif
2369 }
2370 
2371 ///@}
2372 
2373 #ifdef CONFIG_XSYNC
2374 #define xr_sync(ps, d, pfence) xr_sync_(ps, d, pfence)
2375 #else
2376 #define xr_sync(ps, d, pfence) xr_sync_(ps, d)
2377 #endif
2378 
2379 /**
2380  * Synchronizes a X Render drawable to ensure all pending painting requests
2381  * are completed.
2382  */
2383 static inline void
xr_sync_(session_t * ps,Drawable d,XSyncFence * pfence)2384 xr_sync_(session_t *ps, Drawable d
2385 #ifdef CONFIG_XSYNC
2386     , XSyncFence *pfence
2387 #endif
2388     ) {
2389   if (!ps->o.xrender_sync)
2390     return;
2391 
2392   XSync(ps->dpy, False);
2393 #ifdef CONFIG_XSYNC
2394   if (ps->o.xrender_sync_fence && ps->xsync_exists) {
2395     // TODO: If everybody just follows the rules stated in X Sync prototype,
2396     // we need only one fence per screen, but let's stay a bit cautious right
2397     // now
2398     XSyncFence tmp_fence = None;
2399     if (!pfence)
2400       pfence = &tmp_fence;
2401     assert(pfence);
2402     if (!*pfence)
2403       *pfence = XSyncCreateFence(ps->dpy, d, False);
2404     if (*pfence) {
2405       Bool triggered = False;
2406       /* if (XSyncQueryFence(ps->dpy, *pfence, &triggered) && triggered)
2407         XSyncResetFence(ps->dpy, *pfence); */
2408       // The fence may fail to be created (e.g. because of died drawable)
2409       assert(!XSyncQueryFence(ps->dpy, *pfence, &triggered) || !triggered);
2410       XSyncTriggerFence(ps->dpy, *pfence);
2411       XSyncAwaitFence(ps->dpy, pfence, 1);
2412       assert(!XSyncQueryFence(ps->dpy, *pfence, &triggered) || triggered);
2413     }
2414     else {
2415       printf_errf("(%#010lx): Failed to create X Sync fence.", d);
2416     }
2417     free_fence(ps, &tmp_fence);
2418     if (*pfence)
2419       XSyncResetFence(ps->dpy, *pfence);
2420   }
2421 #endif
2422 #ifdef CONFIG_GLX_SYNC
2423   xr_glx_sync(ps, d, pfence);
2424 #endif
2425 }
2426 
2427 /** @name DBus handling
2428  */
2429 ///@{
2430 #ifdef CONFIG_DBUS
2431 /** @name DBus handling
2432  */
2433 ///@{
2434 bool
2435 cdbus_init(session_t *ps);
2436 
2437 void
2438 cdbus_destroy(session_t *ps);
2439 
2440 void
2441 cdbus_loop(session_t *ps);
2442 
2443 void
2444 cdbus_ev_win_added(session_t *ps, win *w);
2445 
2446 void
2447 cdbus_ev_win_destroyed(session_t *ps, win *w);
2448 
2449 void
2450 cdbus_ev_win_mapped(session_t *ps, win *w);
2451 
2452 void
2453 cdbus_ev_win_unmapped(session_t *ps, win *w);
2454 
2455 void
2456 cdbus_ev_win_focusout(session_t *ps, win *w);
2457 
2458 void
2459 cdbus_ev_win_focusin(session_t *ps, win *w);
2460 //!@}
2461 
2462 /** @name DBus hooks
2463  */
2464 ///@{
2465 void
2466 win_set_shadow_force(session_t *ps, win *w, switch_t val);
2467 
2468 void
2469 win_set_fade_force(session_t *ps, win *w, switch_t val);
2470 
2471 void
2472 win_set_focused_force(session_t *ps, win *w, switch_t val);
2473 
2474 void
2475 win_set_invert_color_force(session_t *ps, win *w, switch_t val);
2476 
2477 void
2478 opts_init_track_focus(session_t *ps);
2479 
2480 void
2481 opts_set_no_fading_openclose(session_t *ps, bool newval);
2482 //!@}
2483 #endif
2484 
2485 #ifdef CONFIG_C2
2486 /** @name c2
2487  */
2488 ///@{
2489 
2490 c2_lptr_t *
2491 c2_parsed(session_t *ps, c2_lptr_t **pcondlst, const char *pattern,
2492     void *data);
2493 
2494 #define c2_parse(ps, pcondlst, pattern) c2_parsed((ps), (pcondlst), (pattern), NULL)
2495 
2496 c2_lptr_t *
2497 c2_free_lptr(c2_lptr_t *lp);
2498 
2499 bool
2500 c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst,
2501     const c2_lptr_t **cache, void **pdata);
2502 
2503 #define c2_match(ps, w, condlst, cache) c2_matchd((ps), (w), (condlst), \
2504     (cache), NULL)
2505 #endif
2506 
2507 ///@}
2508 
2509 /**
2510  * @brief Dump the given data to a file.
2511  */
2512 static inline bool
write_binary_data(const char * path,const unsigned char * data,int length)2513 write_binary_data(const char *path, const unsigned char *data, int length) {
2514   if (!data)
2515     return false;
2516   FILE *f = fopen(path, "wb");
2517   if (!f) {
2518     printf_errf("(\"%s\"): Failed to open file for writing.", path);
2519     return false;
2520   }
2521   int wrote_len = fwrite(data, sizeof(unsigned char), length, f);
2522   fclose(f);
2523   if (wrote_len != length) {
2524     printf_errf("(\"%s\"): Failed to write all blocks: %d / %d", path,
2525         wrote_len, length);
2526     return false;
2527   }
2528   return true;
2529 }
2530 
2531 /**
2532  * @brief Dump raw bytes in HEX format.
2533  *
2534  * @param data pointer to raw data
2535  * @param len length of data
2536  */
2537 static inline void
hexdump(const char * data,int len)2538 hexdump(const char *data, int len) {
2539   static const int BYTE_PER_LN = 16;
2540 
2541   if (len <= 0)
2542     return;
2543 
2544   // Print header
2545   printf("%10s:", "Offset");
2546   for (int i = 0; i < BYTE_PER_LN; ++i)
2547     printf(" %2d", i);
2548   putchar('\n');
2549 
2550   // Dump content
2551   for (int offset = 0; offset < len; ++offset) {
2552     if (!(offset % BYTE_PER_LN))
2553       printf("0x%08x:", offset);
2554 
2555     printf(" %02hhx", data[offset]);
2556 
2557     if ((BYTE_PER_LN - 1) == offset % BYTE_PER_LN)
2558       putchar('\n');
2559   }
2560   if (len % BYTE_PER_LN)
2561     putchar('\n');
2562 
2563   fflush(stdout);
2564 }
2565 
2566 #endif
2567