1 // SPDX-License-Identifier: MPL-2.0
2 // Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
3 #pragma once
4 #include <stdbool.h>
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <xcb/render.h>
8 #include <xcb/sync.h>
9 #include <xcb/xcb.h>
10 #include <xcb/xcb_renderutil.h>
11 #include <xcb/xfixes.h>
12 
13 #include "compiler.h"
14 #include "kernel.h"
15 #include "log.h"
16 #include "region.h"
17 
18 typedef struct session session_t;
19 
20 /// Structure representing Window property value.
21 typedef struct winprop {
22 	union {
23 		void *ptr;
24 		int8_t *p8;
25 		int16_t *p16;
26 		int32_t *p32;
27 		uint32_t *c32;        // 32bit cardinal
28 	};
29 	unsigned long nitems;
30 	xcb_atom_t type;
31 	int format;
32 
33 	xcb_get_property_reply_t *r;
34 } winprop_t;
35 
36 struct xvisual_info {
37 	/// Bit depth of the red component
38 	int red_size;
39 	/// Bit depth of the green component
40 	int green_size;
41 	/// Bit depth of the blue component
42 	int blue_size;
43 	/// Bit depth of the alpha component
44 	int alpha_size;
45 	/// The depth of X visual
46 	int visual_depth;
47 
48 	xcb_visualid_t visual;
49 };
50 
51 #define XCB_AWAIT_VOID(func, c, ...)                                                     \
52 	({                                                                               \
53 		bool __success = true;                                                   \
54 		__auto_type __e = xcb_request_check(c, func##_checked(c, __VA_ARGS__));  \
55 		if (__e) {                                                               \
56 			x_print_error(__e->sequence, __e->major_code, __e->minor_code,   \
57 			              __e->error_code);                                  \
58 			free(__e);                                                       \
59 			__success = false;                                               \
60 		}                                                                        \
61 		__success;                                                               \
62 	})
63 
64 #define XCB_AWAIT(func, c, ...)                                                          \
65 	({                                                                               \
66 		xcb_generic_error_t *__e = NULL;                                         \
67 		__auto_type __r = func##_reply(c, func(c, __VA_ARGS__), &__e);           \
68 		if (__e) {                                                               \
69 			x_print_error(__e->sequence, __e->major_code, __e->minor_code,   \
70 			              __e->error_code);                                  \
71 			free(__e);                                                       \
72 		}                                                                        \
73 		__r;                                                                     \
74 	})
75 
76 #define log_error_x_error(e, fmt, ...)                                                   \
77 	LOG(ERROR, fmt " (%s)", ##__VA_ARGS__, x_strerror(e))
78 #define log_fatal_x_error(e, fmt, ...)                                                   \
79 	LOG(FATAL, fmt " (%s)", ##__VA_ARGS__, x_strerror(e))
80 
81 /// Wraps x_new_id. abort the program if x_new_id returns error
x_new_id(xcb_connection_t * c)82 static inline uint32_t x_new_id(xcb_connection_t *c) {
83 	auto ret = xcb_generate_id(c);
84 	if (ret == (uint32_t)-1) {
85 		log_fatal("We seems to have run of XIDs. This is either a bug in the X "
86 		          "server, or a resource leakage in the compositor. Please open "
87 		          "an issue about this problem. The compositor will die.");
88 		abort();
89 	}
90 	return ret;
91 }
92 
93 /**
94  * Send a request to X server and get the reply to make sure all previous
95  * requests are processed, and their replies received
96  *
97  * xcb_get_input_focus is used here because it is the same request used by
98  * libX11
99  */
x_sync(xcb_connection_t * c)100 static inline void x_sync(xcb_connection_t *c) {
101 	free(xcb_get_input_focus_reply(c, xcb_get_input_focus(c), NULL));
102 }
103 
104 /**
105  * Get a specific attribute of a window.
106  *
107  * Returns a blank structure if the returned type and format does not
108  * match the requested type and format.
109  *
110  * @param ps current session
111  * @param w window
112  * @param atom atom of attribute to fetch
113  * @param length length to read
114  * @param rtype atom of the requested type
115  * @param rformat requested format
116  * @return a <code>winprop_t</code> structure containing the attribute
117  *    and number of items. A blank one on failure.
118  */
119 winprop_t x_get_prop_with_offset(const session_t *ps, xcb_window_t w, xcb_atom_t atom,
120                                  int offset, int length, xcb_atom_t rtype, int rformat);
121 
122 /**
123  * Wrapper of wid_get_prop_adv().
124  */
x_get_prop(const session_t * ps,xcb_window_t wid,xcb_atom_t atom,int length,xcb_atom_t rtype,int rformat)125 static inline winprop_t x_get_prop(const session_t *ps, xcb_window_t wid, xcb_atom_t atom,
126                                    int length, xcb_atom_t rtype, int rformat) {
127 	return x_get_prop_with_offset(ps, wid, atom, 0L, length, rtype, rformat);
128 }
129 
130 /// Discard all X events in queue or in flight. Should only be used when the server is
131 /// grabbed
x_discard_events(xcb_connection_t * c)132 static inline void x_discard_events(xcb_connection_t *c) {
133 	xcb_generic_event_t *e;
134 	while ((e = xcb_poll_for_event(c))) {
135 		free(e);
136 	}
137 }
138 
139 /**
140  * Get the value of a type-<code>xcb_window_t</code> property of a window.
141  *
142  * @return the value if successful, 0 otherwise
143  */
144 xcb_window_t wid_get_prop_window(session_t *ps, xcb_window_t wid, xcb_atom_t aprop);
145 
146 /**
147  * Get the value of a text property of a window.
148  */
149 bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst,
150                        int *pnstr);
151 
152 const xcb_render_pictforminfo_t *
153 x_get_pictform_for_visual(xcb_connection_t *, xcb_visualid_t);
154 int x_get_visual_depth(xcb_connection_t *, xcb_visualid_t);
155 
156 xcb_render_picture_t
157 x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *,
158                                          const xcb_render_pictforminfo_t *pictfmt,
159                                          xcb_pixmap_t pixmap, uint32_t valuemask,
160                                          const xcb_render_create_picture_value_list_t *attr)
161     attr_nonnull(1, 2);
162 
163 xcb_render_picture_t
164 x_create_picture_with_visual_and_pixmap(xcb_connection_t *, xcb_visualid_t visual,
165                                         xcb_pixmap_t pixmap, uint32_t valuemask,
166                                         const xcb_render_create_picture_value_list_t *attr)
167     attr_nonnull(1);
168 
169 xcb_render_picture_t
170 x_create_picture_with_standard_and_pixmap(xcb_connection_t *, xcb_pict_standard_t standard,
171                                           xcb_pixmap_t pixmap, uint32_t valuemask,
172                                           const xcb_render_create_picture_value_list_t *attr)
173     attr_nonnull(1);
174 
175 /**
176  * Create an picture.
177  */
178 xcb_render_picture_t
179 x_create_picture_with_pictfmt(xcb_connection_t *, xcb_drawable_t, int w, int h,
180                               const xcb_render_pictforminfo_t *pictfmt, uint32_t valuemask,
181                               const xcb_render_create_picture_value_list_t *attr)
182     attr_nonnull(1, 5);
183 
184 xcb_render_picture_t
185 x_create_picture_with_visual(xcb_connection_t *, xcb_drawable_t, int w, int h,
186                              xcb_visualid_t visual, uint32_t valuemask,
187                              const xcb_render_create_picture_value_list_t *attr)
188     attr_nonnull(1);
189 
190 /// Fetch a X region and store it in a pixman region
191 bool x_fetch_region(xcb_connection_t *, xcb_xfixes_region_t r, region_t *res);
192 
193 void x_set_picture_clip_region(xcb_connection_t *, xcb_render_picture_t, int16_t clip_x_origin,
194                                int16_t clip_y_origin, const region_t *);
195 
196 void x_clear_picture_clip_region(xcb_connection_t *, xcb_render_picture_t pict);
197 
198 /**
199  * Log a X11 error
200  */
201 void x_print_error(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_code);
202 
203 /*
204  * Convert a xcb_generic_error_t to a string that describes the error
205  *
206  * @return a pointer to a string. this pointer shouldn NOT be freed, same buffer is used
207  *         for multiple calls to this function,
208  */
209 const char *x_strerror(xcb_generic_error_t *e);
210 
211 xcb_pixmap_t x_create_pixmap(xcb_connection_t *, uint8_t depth, xcb_drawable_t drawable,
212                              int width, int height);
213 
214 bool x_validate_pixmap(xcb_connection_t *, xcb_pixmap_t pxmap);
215 
216 /**
217  * Free a <code>winprop_t</code>.
218  *
219  * @param pprop pointer to the <code>winprop_t</code> to free.
220  */
free_winprop(winprop_t * pprop)221 static inline void free_winprop(winprop_t *pprop) {
222 	// Empty the whole structure to avoid possible issues
223 	if (pprop->r)
224 		free(pprop->r);
225 	pprop->ptr = NULL;
226 	pprop->r = NULL;
227 	pprop->nitems = 0;
228 }
229 /// Get the back pixmap of the root window
230 xcb_pixmap_t x_get_root_back_pixmap(session_t *ps);
231 
232 /// Return true if the atom refers to a property name that is used for the
233 /// root window background pixmap
234 bool x_is_root_back_pixmap_atom(session_t *ps, xcb_atom_t atom);
235 
236 bool x_fence_sync(xcb_connection_t *, xcb_sync_fence_t);
237 
238 struct x_convolution_kernel {
239 	int size;
240 	int capacity;
241 	xcb_render_fixed_t kernel[];
242 };
243 
244 /**
245  * Convert a struct conv to a X picture convolution filter, normalizing the kernel
246  * in the process. Allow the caller to specify the element at the center of the kernel,
247  * for compatibility with legacy code.
248  *
249  * @param[in] kernel the convolution kernel
250  * @param[in] center the element to put at the center of the matrix
251  * @param[inout] ret pointer to an array of `size`, if `size` is too small, more space
252  *                   will be allocated, and `*ret` will be updated.
253  * @param[inout] size size of the array pointed to by `ret`.
254  */
255 void attr_nonnull(1, 3) x_create_convolution_kernel(const conv *kernel, double center,
256                                                     struct x_convolution_kernel **ret);
257 
258 /// Generate a search criteria for fbconfig from a X visual.
259 /// Returns {-1, -1, -1, -1, -1, -1} on failure
260 struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual);
261 
262 xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std);
263 
264 xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen);
265 
266 uint32_t attr_deprecated xcb_generate_id(xcb_connection_t *c);
267