1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
|
// SPDX-License-Identifier: MIT
/*
* Compton - a compositor for X11
*
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
*
* Copyright (c) 2011-2013, Christopher Jeffrey
* Copyright (c) 2018, Yuxuan Shui <[email protected]>
*
* See LICENSE-mit for more information.
*
*/
#pragma once
// === Options ===
// Debug options, enable them using -D in CFLAGS
// #define DEBUG_REPAINT 1
// #define DEBUG_EVENTS 1
// #define DEBUG_RESTACK 1
// #define DEBUG_WINMATCH 1
// #define DEBUG_C2 1
// #define DEBUG_GLX_DEBUG_CONTEXT 1
#define MAX_ALPHA (255)
// === Includes ===
// For some special functions
#include <assert.h>
#include <stdbool.h>
#include <sys/time.h>
#include <time.h>
#include <X11/Xlib.h>
#include <ev.h>
#include <pixman.h>
#include <xcb/xproto.h>
#include <xcb/render.h>
#include <xcb/sync.h>
#include "uthash_extra.h"
#ifdef CONFIG_OPENGL
#include "backend/gl/glx.h"
#endif
// X resource checker
#ifdef DEBUG_XRC
#include "xrescheck.h"
#endif
// FIXME This list of includes should get shorter
#include "backend/backend.h"
#include "backend/driver.h"
#include "compiler.h"
#include "config.h"
#include "region.h"
#include "types.h"
#include "utils.h"
#include "list.h"
#include "render.h"
#include "win_defs.h"
#include "x.h"
// === Constants ===0
#define NS_PER_SEC 1000000000L
#define US_PER_SEC 1000000L
#define MS_PER_SEC 1000
/// @brief Maximum OpenGL FBConfig depth.
#define OPENGL_MAX_DEPTH 32
/// @brief Maximum OpenGL buffer age.
#define CGLX_MAX_BUFFER_AGE 5
// Window flags
// === Types ===
typedef struct glx_fbconfig glx_fbconfig_t;
struct glx_session;
struct atom;
struct conv;
typedef struct _ignore {
struct _ignore *next;
unsigned long sequence;
} ignore_t;
#ifdef CONFIG_OPENGL
#ifdef DEBUG_GLX_DEBUG_CONTEXT
typedef GLXContext (*f_glXCreateContextAttribsARB)(Display *dpy, GLXFBConfig config,
GLXContext share_context, Bool direct,
const int *attrib_list);
typedef void (*GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity,
GLsizei length, const GLchar *message, GLvoid *userParam);
typedef void (*f_DebugMessageCallback)(GLDEBUGPROC, void *userParam);
#endif
typedef struct glx_prog_main {
/// GLSL program.
GLuint prog;
/// Location of uniform "opacity" in window GLSL program.
GLint unifm_opacity;
/// Location of uniform "invert_color" in blur GLSL program.
GLint unifm_invert_color;
/// Location of uniform "tex" in window GLSL program.
GLint unifm_tex;
/// Location of uniform "time" in window GLSL program.
GLint unifm_time;
} glx_prog_main_t;
#define GLX_PROG_MAIN_INIT \
{ \
.prog = 0, .unifm_opacity = -1, .unifm_invert_color = -1, \
.unifm_tex = -1, .unifm_time = -1 \
}
#else
struct glx_prog_main {};
#endif
#define PAINT_INIT \
{ .pixmap = XCB_NONE, .pict = XCB_NONE }
/// Linked list type of atoms.
typedef struct _latom {
xcb_atom_t atom;
struct _latom *next;
} latom_t;
/// Structure containing all necessary data for a session.
typedef struct session {
// === Event handlers ===
/// ev_io for X connection
ev_io xiow;
/// Timeout for delayed unredirection.
ev_timer unredir_timer;
/// Timer for fading
ev_timer fade_timer;
/// Timer for animations
ev_timer animation_timer;
/// Timer for delayed drawing, right now only used by
/// swopti
ev_timer delayed_draw_timer;
/// Use an ev_idle callback for drawing
/// So we only start drawing when events are processed
ev_idle draw_idle;
/// Called everytime we have timeouts or new data on socket,
/// so we can be sure if xcb read from X socket at anytime during event
/// handling, we will not left any event unhandled in the queue
ev_prepare event_check;
/// Signal handler for SIGUSR1
ev_signal usr1_signal;
/// Signal handler for SIGINT
ev_signal int_signal;
/// backend data
backend_t *backend_data;
/// backend blur context
void *backend_blur_context;
/// graphic drivers used
enum driver drivers;
/// file watch handle
void *file_watch_handle;
/// libev mainloop
struct ev_loop *loop;
// === Display related ===
/// Whether the X server is grabbed by us
bool server_grabbed;
/// Display in use.
Display *dpy;
/// Previous handler of X errors
XErrorHandler previous_xerror_handler;
/// Default screen.
int scr;
/// XCB connection.
xcb_connection_t *c;
/// Default visual.
xcb_visualid_t vis;
/// Default depth.
int depth;
/// Root window.
xcb_window_t root;
/// Height of root window.
int root_height;
/// Width of root window.
int root_width;
/// Current desktop number of root window
int root_desktop_num;
/// Desktop switch direction
int root_desktop_switch_direction;
// Damage of root window.
// Damage root_damage;
/// X Composite overlay window. Used if <code>--paint-on-overlay</code>.
xcb_window_t overlay;
/// The target window for debug mode
xcb_window_t debug_window;
/// Whether the root tile is filled by us.
bool root_tile_fill;
/// Picture of the root window background.
paint_t root_tile_paint;
/// The backend data the root pixmap bound to
void *root_image;
/// A region of the size of the screen.
region_t screen_reg;
/// Picture of root window. Destination of painting in no-DBE painting
/// mode.
xcb_render_picture_t root_picture;
/// A Picture acting as the painting target.
xcb_render_picture_t tgt_picture;
/// Temporary buffer to paint to before sending to display.
paint_t tgt_buffer;
/// Window ID of the window we register as a symbol.
xcb_window_t reg_win;
#ifdef CONFIG_OPENGL
/// Pointer to GLX data.
struct glx_session *psglx;
/// Custom GLX program used for painting window.
// XXX should be in struct glx_session
glx_prog_main_t glx_prog_win;
struct glx_fbconfig_info *argb_fbconfig;
#endif
/// Sync fence to sync draw operations
xcb_sync_fence_t sync_fence;
/// Whether we are rendering the first frame after screen is redirected
bool first_frame;
// === Operation related ===
/// Flags related to the root window
uint64_t root_flags;
/// Program options.
options_t o;
/// Whether we have hit unredirection timeout.
bool tmout_unredir_hit;
/// Whether we need to redraw the screen
bool redraw_needed;
/// Cache a xfixes region so we don't need to allocate it everytime.
/// A workaround for yshui/picom#301
xcb_xfixes_region_t damaged_region;
/// The region needs to painted on next paint.
region_t *damage;
/// The region damaged on the last paint.
region_t *damage_ring;
/// Number of damage regions we track
int ndamage;
/// Whether all windows are currently redirected.
bool redirected;
/// Pre-generated alpha pictures.
xcb_render_picture_t *alpha_picts;
/// Time of last fading. In milliseconds.
long fade_time;
/// Time of last window animation step. In milliseconds.
long animation_time;
/// Head pointer of the error ignore linked list.
ignore_t *ignore_head;
/// Pointer to the <code>next</code> member of tail element of the error
/// ignore linked list.
ignore_t **ignore_tail;
// Cached blur convolution kernels.
struct x_convolution_kernel **blur_kerns_cache;
/// If we should quit
bool quit:1;
// TODO(yshui) use separate flags for dfferent kinds of updates so we don't
// waste our time.
/// Whether there are pending updates, like window creation, etc.
bool pending_updates:1;
// === Expose event related ===
/// Pointer to an array of <code>XRectangle</code>-s of exposed region.
/// XXX why do we need this array?
rect_t *expose_rects;
/// Number of <code>XRectangle</code>-s in <code>expose_rects</code>.
int size_expose;
/// Index of the next free slot in <code>expose_rects</code>.
int n_expose;
// === Window related ===
/// A hash table of all windows.
struct win *windows;
/// Windows in their stacking order
struct list_node window_stack;
/// Pointer to <code>win</code> of current active window. Used by
/// EWMH <code>_NET_ACTIVE_WINDOW</code> focus detection. In theory,
/// it's more reliable to store the window ID directly here, just in
/// case the WM does something extraordinary, but caching the pointer
/// means another layer of complexity.
struct managed_win *active_win;
/// Window ID of leader window of currently active window. Used for
/// subsidiary window detection.
xcb_window_t active_leader;
// === Shadow/dimming related ===
/// 1x1 black Picture.
xcb_render_picture_t black_picture;
/// 1x1 Picture of the shadow color.
xcb_render_picture_t cshadow_picture;
/// 1x1 white Picture.
xcb_render_picture_t white_picture;
/// Gaussian map of shadow.
struct conv *gaussian_map;
// for shadow precomputation
/// A region in which shadow is not painted on.
region_t shadow_exclude_reg;
// === Software-optimization-related ===
/// Currently used refresh rate.
int refresh_rate;
/// Interval between refresh in nanoseconds.
long refresh_intv;
/// Nanosecond offset of the first painting.
long paint_tm_offset;
#ifdef CONFIG_VSYNC_DRM
// === DRM VSync related ===
/// File descriptor of DRI device file. Used for DRM VSync.
int drm_fd;
#endif
// === X extension related ===
/// Event base number for X Fixes extension.
int xfixes_event;
/// Error base number for X Fixes extension.
int xfixes_error;
/// Event base number for X Damage extension.
int damage_event;
/// Error base number for X Damage extension.
int damage_error;
/// Event base number for X Render extension.
int render_event;
/// Error base number for X Render extension.
int render_error;
/// Event base number for X Composite extension.
int composite_event;
/// Error base number for X Composite extension.
int composite_error;
/// Major opcode for X Composite extension.
int composite_opcode;
/// Whether X Shape extension exists.
bool shape_exists;
/// Event base number for X Shape extension.
int shape_event;
/// Error base number for X Shape extension.
int shape_error;
/// Whether X RandR extension exists.
bool randr_exists;
/// Event base number for X RandR extension.
int randr_event;
/// Error base number for X RandR extension.
int randr_error;
/// Whether X Present extension exists.
bool present_exists;
/// Whether X GLX extension exists.
bool glx_exists;
/// Event base number for X GLX extension.
int glx_event;
/// Error base number for X GLX extension.
int glx_error;
/// Whether X Xinerama extension exists.
bool xinerama_exists;
/// Xinerama screen regions.
region_t *xinerama_scr_regs;
/// Number of Xinerama screens.
int xinerama_nscrs;
/// Whether X Sync extension exists.
bool xsync_exists;
/// Event base number for X Sync extension.
int xsync_event;
/// Error base number for X Sync extension.
int xsync_error;
/// Whether X Render convolution filter exists.
bool xrfilter_convolution_exists;
// === Atoms ===
struct atom *atoms;
/// Array of atoms of all possible window types.
xcb_atom_t atoms_wintypes[NUM_WINTYPES];
/// Linked list of additional atoms to track.
latom_t *track_atom_lst;
#ifdef CONFIG_DBUS
// === DBus related ===
void *dbus_data;
#endif
int (*vsync_wait)(session_t *);
} session_t;
/// Enumeration for window event hints.
typedef enum { WIN_EVMODE_UNKNOWN, WIN_EVMODE_FRAME, WIN_EVMODE_CLIENT } win_evmode_t;
extern const char *const WINTYPES[NUM_WINTYPES];
extern session_t *ps_g;
void ev_xcb_error(session_t *ps, xcb_generic_error_t *err);
// === Functions ===
/**
* Subtracting two struct timespec values.
*
* Taken from glibc manual.
*
* Subtract the `struct timespec' values X and Y,
* storing the result in RESULT.
* Return 1 if the difference is negative, otherwise 0.
*/
static inline int
timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y) {
/* Perform the carry for the later subtraction by updating y. */
if (x->tv_nsec < y->tv_nsec) {
long nsec = (y->tv_nsec - x->tv_nsec) / NS_PER_SEC + 1;
y->tv_nsec -= NS_PER_SEC * nsec;
y->tv_sec += nsec;
}
if (x->tv_nsec - y->tv_nsec > NS_PER_SEC) {
long nsec = (x->tv_nsec - y->tv_nsec) / NS_PER_SEC;
y->tv_nsec += NS_PER_SEC * nsec;
y->tv_sec -= nsec;
}
/* Compute the time remaining to wait.
tv_nsec is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_nsec = x->tv_nsec - y->tv_nsec;
/* Return 1 if result is negative. */
return x->tv_sec < y->tv_sec;
}
/**
* Get current time in struct timeval.
*/
static inline struct timeval get_time_timeval(void) {
struct timeval tv = {0, 0};
gettimeofday(&tv, NULL);
// Return a time of all 0 if the call fails
return tv;
}
/**
* Get current time in struct timespec.
*
* Note its starting time is unspecified.
*/
static inline struct timespec get_time_timespec(void) {
struct timespec tm = {0, 0};
clock_gettime(CLOCK_MONOTONIC, &tm);
// Return a time of all 0 if the call fails
return tm;
}
/**
* Return the painting target window.
*/
static inline xcb_window_t get_tgt_window(session_t *ps) {
return ps->overlay != XCB_NONE ? ps->overlay : ps->root;
}
/**
* Check if current backend uses GLX.
*/
static inline bool bkend_use_glx(session_t *ps) {
return BKEND_GLX == ps->o.backend || BKEND_XR_GLX_HYBRID == ps->o.backend;
}
static void set_ignore(session_t *ps, unsigned long sequence) {
if (ps->o.show_all_xerrors)
return;
auto i = cmalloc(ignore_t);
if (!i)
return;
i->sequence = sequence;
i->next = 0;
*ps->ignore_tail = i;
ps->ignore_tail = &i->next;
}
/**
* Ignore X errors caused by given X request.
*/
static inline void set_ignore_cookie(session_t *ps, xcb_void_cookie_t cookie) {
set_ignore(ps, cookie.sequence);
}
/**
* Determine if a window has a specific property.
*
* @param ps current session
* @param w window to check
* @param atom atom of property to check
* @return true if it has the attribute, false otherwise
*/
static inline bool wid_has_prop(const session_t *ps, xcb_window_t w, xcb_atom_t atom) {
auto r = xcb_get_property_reply(
ps->c, xcb_get_property(ps->c, 0, w, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, 0), NULL);
if (!r) {
return false;
}
auto rtype = r->type;
free(r);
if (rtype != XCB_NONE) {
return true;
}
return false;
}
void force_repaint(session_t *ps);
/** @name DBus handling
*/
///@{
#ifdef CONFIG_DBUS
/** @name DBus hooks
*/
///@{
void opts_set_no_fading_openclose(session_t *ps, bool newval);
//!@}
#endif
/**
* Set a <code>bool</code> array of all wintypes to true.
*/
static inline void wintype_arr_enable(bool arr[]) {
wintype_t i;
for (i = 0; i < NUM_WINTYPES; ++i) {
arr[i] = true;
}
}
|