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