2018-10-03 21:14:51 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
// Copyright (c) 2018 Yuxuan Shui <yshuiv7@gmail.com>
|
2018-09-06 18:17:26 +00:00
|
|
|
#pragma once
|
|
|
|
#include <stdbool.h>
|
2019-02-03 15:59:31 +00:00
|
|
|
#include <stdint.h>
|
2019-01-18 23:30:44 +00:00
|
|
|
#include <stdlib.h>
|
2018-09-23 18:10:46 +00:00
|
|
|
#include <xcb/render.h>
|
2018-12-30 07:06:47 +00:00
|
|
|
#include <xcb/sync.h>
|
2019-02-03 15:59:31 +00:00
|
|
|
#include <xcb/xcb.h>
|
2018-09-23 18:10:46 +00:00
|
|
|
#include <xcb/xcb_renderutil.h>
|
2019-02-03 15:59:31 +00:00
|
|
|
#include <xcb/xfixes.h>
|
2018-09-29 22:36:53 +00:00
|
|
|
|
2019-01-18 23:30:44 +00:00
|
|
|
#include "compiler.h"
|
2019-02-17 23:47:46 +00:00
|
|
|
#include "kernel.h"
|
2019-08-09 23:56:04 +00:00
|
|
|
#include "log.h"
|
2020-01-18 17:26:53 +00:00
|
|
|
#include "region.h"
|
2018-09-29 22:36:53 +00:00
|
|
|
|
2018-09-06 18:17:26 +00:00
|
|
|
typedef struct session session_t;
|
2020-12-26 07:51:03 +00:00
|
|
|
struct atom;
|
2018-12-09 20:24:52 +00:00
|
|
|
|
|
|
|
/// Structure representing Window property value.
|
|
|
|
typedef struct winprop {
|
2019-02-03 15:59:31 +00:00
|
|
|
union {
|
|
|
|
void *ptr;
|
|
|
|
int8_t *p8;
|
|
|
|
int16_t *p16;
|
|
|
|
int32_t *p32;
|
|
|
|
uint32_t *c32; // 32bit cardinal
|
|
|
|
};
|
|
|
|
unsigned long nitems;
|
|
|
|
xcb_atom_t type;
|
|
|
|
int format;
|
|
|
|
|
|
|
|
xcb_get_property_reply_t *r;
|
2018-12-09 20:24:52 +00:00
|
|
|
} winprop_t;
|
2018-09-29 22:36:53 +00:00
|
|
|
|
2020-11-30 14:51:26 +00:00
|
|
|
typedef struct winprop_info {
|
|
|
|
xcb_atom_t type;
|
|
|
|
uint8_t format;
|
|
|
|
uint32_t length;
|
|
|
|
} winprop_info_t;
|
|
|
|
|
2019-02-26 23:52:37 +00:00
|
|
|
struct xvisual_info {
|
|
|
|
/// Bit depth of the red component
|
|
|
|
int red_size;
|
|
|
|
/// Bit depth of the green component
|
|
|
|
int green_size;
|
|
|
|
/// Bit depth of the blue component
|
|
|
|
int blue_size;
|
|
|
|
/// Bit depth of the alpha component
|
|
|
|
int alpha_size;
|
|
|
|
/// The depth of X visual
|
|
|
|
int visual_depth;
|
|
|
|
|
|
|
|
xcb_visualid_t visual;
|
|
|
|
};
|
|
|
|
|
2019-04-27 13:15:40 +00:00
|
|
|
#define XCB_AWAIT_VOID(func, c, ...) \
|
|
|
|
({ \
|
2020-03-27 21:02:38 +00:00
|
|
|
bool __success = true; \
|
|
|
|
__auto_type __e = xcb_request_check(c, func##_checked(c, __VA_ARGS__)); \
|
|
|
|
if (__e) { \
|
|
|
|
x_print_error(__e->sequence, __e->major_code, __e->minor_code, \
|
|
|
|
__e->error_code); \
|
|
|
|
free(__e); \
|
|
|
|
__success = false; \
|
2019-04-27 13:15:40 +00:00
|
|
|
} \
|
2020-03-27 21:02:38 +00:00
|
|
|
__success; \
|
2019-04-27 13:15:40 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
#define XCB_AWAIT(func, c, ...) \
|
2019-02-27 00:30:27 +00:00
|
|
|
({ \
|
2020-03-27 21:02:38 +00:00
|
|
|
xcb_generic_error_t *__e = NULL; \
|
|
|
|
__auto_type __r = func##_reply(c, func(c, __VA_ARGS__), &__e); \
|
|
|
|
if (__e) { \
|
|
|
|
x_print_error(__e->sequence, __e->major_code, __e->minor_code, \
|
|
|
|
__e->error_code); \
|
|
|
|
free(__e); \
|
2019-02-27 00:30:27 +00:00
|
|
|
} \
|
2020-03-27 21:02:38 +00:00
|
|
|
__r; \
|
2019-02-03 15:59:31 +00:00
|
|
|
})
|
2018-09-30 13:38:37 +00:00
|
|
|
|
2020-10-22 00:39:51 +00:00
|
|
|
#define log_debug_x_error(e, fmt, ...) \
|
|
|
|
LOG(DEBUG, fmt " (%s)", ##__VA_ARGS__, x_strerror(e))
|
2020-03-28 00:15:45 +00:00
|
|
|
#define log_error_x_error(e, fmt, ...) \
|
|
|
|
LOG(ERROR, fmt " (%s)", ##__VA_ARGS__, x_strerror(e))
|
|
|
|
#define log_fatal_x_error(e, fmt, ...) \
|
|
|
|
LOG(FATAL, fmt " (%s)", ##__VA_ARGS__, x_strerror(e))
|
|
|
|
|
2021-10-21 17:19:23 +00:00
|
|
|
// xcb-render specific macros
|
|
|
|
#define XFIXED_TO_DOUBLE(value) (((double)(value)) / 65536)
|
|
|
|
#define DOUBLE_TO_XFIXED(value) ((xcb_render_fixed_t)(((double)(value)) * 65536))
|
|
|
|
|
2019-04-08 04:49:39 +00:00
|
|
|
/// Wraps x_new_id. abort the program if x_new_id returns error
|
|
|
|
static inline uint32_t x_new_id(xcb_connection_t *c) {
|
|
|
|
auto ret = xcb_generate_id(c);
|
|
|
|
if (ret == (uint32_t)-1) {
|
|
|
|
log_fatal("We seems to have run of XIDs. This is either a bug in the X "
|
2020-01-18 17:26:53 +00:00
|
|
|
"server, or a resource leakage in the compositor. Please open "
|
|
|
|
"an issue about this problem. The compositor will die.");
|
2019-04-08 04:49:39 +00:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-10-03 13:27:48 +00:00
|
|
|
/**
|
|
|
|
* Send a request to X server and get the reply to make sure all previous
|
|
|
|
* requests are processed, and their replies received
|
|
|
|
*
|
|
|
|
* xcb_get_input_focus is used here because it is the same request used by
|
|
|
|
* libX11
|
|
|
|
*/
|
2019-02-03 15:59:31 +00:00
|
|
|
static inline void x_sync(xcb_connection_t *c) {
|
|
|
|
free(xcb_get_input_focus_reply(c, xcb_get_input_focus(c), NULL));
|
2018-10-03 13:27:48 +00:00
|
|
|
}
|
|
|
|
|
2018-09-06 18:17:26 +00:00
|
|
|
/**
|
|
|
|
* Get a specific attribute of a window.
|
|
|
|
*
|
|
|
|
* Returns a blank structure if the returned type and format does not
|
|
|
|
* match the requested type and format.
|
|
|
|
*
|
|
|
|
* @param ps current session
|
|
|
|
* @param w window
|
|
|
|
* @param atom atom of attribute to fetch
|
|
|
|
* @param length length to read
|
|
|
|
* @param rtype atom of the requested type
|
|
|
|
* @param rformat requested format
|
|
|
|
* @return a <code>winprop_t</code> structure containing the attribute
|
|
|
|
* and number of items. A blank one on failure.
|
|
|
|
*/
|
2020-12-26 07:39:21 +00:00
|
|
|
winprop_t x_get_prop_with_offset(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom,
|
2020-01-18 17:26:53 +00:00
|
|
|
int offset, int length, xcb_atom_t rtype, int rformat);
|
2018-09-06 18:17:26 +00:00
|
|
|
|
2018-12-09 20:24:52 +00:00
|
|
|
/**
|
|
|
|
* Wrapper of wid_get_prop_adv().
|
|
|
|
*/
|
2020-12-26 07:39:21 +00:00
|
|
|
static inline winprop_t x_get_prop(xcb_connection_t *c, xcb_window_t wid, xcb_atom_t atom,
|
2020-01-18 17:26:53 +00:00
|
|
|
int length, xcb_atom_t rtype, int rformat) {
|
2020-12-26 07:39:21 +00:00
|
|
|
return x_get_prop_with_offset(c, wid, atom, 0L, length, rtype, rformat);
|
2018-12-09 20:24:52 +00:00
|
|
|
}
|
|
|
|
|
2020-11-30 14:51:26 +00:00
|
|
|
/// Get the type, format and size in bytes of a window's specific attribute.
|
2020-12-26 07:39:21 +00:00
|
|
|
winprop_info_t x_get_prop_info(xcb_connection_t *c, xcb_window_t w, xcb_atom_t atom);
|
2020-11-30 14:51:26 +00:00
|
|
|
|
2019-04-19 00:56:53 +00:00
|
|
|
/// Discard all X events in queue or in flight. Should only be used when the server is
|
|
|
|
/// grabbed
|
|
|
|
static inline void x_discard_events(xcb_connection_t *c) {
|
|
|
|
xcb_generic_event_t *e;
|
|
|
|
while ((e = xcb_poll_for_event(c))) {
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-06 18:17:26 +00:00
|
|
|
/**
|
2018-12-27 20:45:38 +00:00
|
|
|
* Get the value of a type-<code>xcb_window_t</code> property of a window.
|
2018-09-06 18:17:26 +00:00
|
|
|
*
|
|
|
|
* @return the value if successful, 0 otherwise
|
|
|
|
*/
|
2020-12-26 07:51:03 +00:00
|
|
|
xcb_window_t wid_get_prop_window(xcb_connection_t *c, xcb_window_t wid, xcb_atom_t aprop);
|
2018-09-06 18:17:26 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the value of a text property of a window.
|
2020-10-22 00:39:51 +00:00
|
|
|
*
|
|
|
|
* @param[out] pstrlst Out parameter for an array of strings, caller needs to free this
|
|
|
|
* array
|
|
|
|
* @param[out] pnstr Number of strings in the array
|
2018-09-06 18:17:26 +00:00
|
|
|
*/
|
2019-02-27 00:30:27 +00:00
|
|
|
bool wid_get_text_prop(session_t *ps, xcb_window_t wid, xcb_atom_t prop, char ***pstrlst,
|
|
|
|
int *pnstr);
|
2018-09-23 18:10:46 +00:00
|
|
|
|
2019-02-27 00:30:27 +00:00
|
|
|
const xcb_render_pictforminfo_t *
|
|
|
|
x_get_pictform_for_visual(xcb_connection_t *, xcb_visualid_t);
|
2019-02-03 16:41:04 +00:00
|
|
|
int x_get_visual_depth(xcb_connection_t *, xcb_visualid_t);
|
2018-09-23 18:10:46 +00:00
|
|
|
|
2019-02-03 15:59:31 +00:00
|
|
|
xcb_render_picture_t
|
2019-02-27 00:30:27 +00:00
|
|
|
x_create_picture_with_pictfmt_and_pixmap(xcb_connection_t *,
|
|
|
|
const xcb_render_pictforminfo_t *pictfmt,
|
2019-03-30 09:07:21 +00:00
|
|
|
xcb_pixmap_t pixmap, uint32_t valuemask,
|
2019-02-03 15:59:31 +00:00
|
|
|
const xcb_render_create_picture_value_list_t *attr)
|
|
|
|
attr_nonnull(1, 2);
|
2018-09-23 18:10:46 +00:00
|
|
|
|
2019-02-03 15:59:31 +00:00
|
|
|
xcb_render_picture_t
|
|
|
|
x_create_picture_with_visual_and_pixmap(xcb_connection_t *, xcb_visualid_t visual,
|
2019-03-30 09:07:21 +00:00
|
|
|
xcb_pixmap_t pixmap, uint32_t valuemask,
|
2019-02-03 15:59:31 +00:00
|
|
|
const xcb_render_create_picture_value_list_t *attr)
|
|
|
|
attr_nonnull(1);
|
2018-09-23 18:10:46 +00:00
|
|
|
|
2019-02-03 15:59:31 +00:00
|
|
|
xcb_render_picture_t
|
|
|
|
x_create_picture_with_standard_and_pixmap(xcb_connection_t *, xcb_pict_standard_t standard,
|
2019-03-30 09:07:21 +00:00
|
|
|
xcb_pixmap_t pixmap, uint32_t valuemask,
|
2019-02-03 15:59:31 +00:00
|
|
|
const xcb_render_create_picture_value_list_t *attr)
|
|
|
|
attr_nonnull(1);
|
2018-09-23 18:10:46 +00:00
|
|
|
|
2020-08-19 18:22:17 +00:00
|
|
|
xcb_render_picture_t
|
|
|
|
x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
|
|
|
|
xcb_pict_standard_t standard, uint32_t valuemask,
|
|
|
|
const xcb_render_create_picture_value_list_t *attr)
|
|
|
|
attr_nonnull(1);
|
|
|
|
|
2018-09-23 18:10:46 +00:00
|
|
|
/**
|
|
|
|
* Create an picture.
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
xcb_render_picture_t
|
2019-03-30 09:07:21 +00:00
|
|
|
x_create_picture_with_pictfmt(xcb_connection_t *, xcb_drawable_t, int w, int h,
|
|
|
|
const xcb_render_pictforminfo_t *pictfmt, uint32_t valuemask,
|
2019-03-10 12:34:37 +00:00
|
|
|
const xcb_render_create_picture_value_list_t *attr)
|
|
|
|
attr_nonnull(1, 5);
|
2018-09-29 22:36:53 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
xcb_render_picture_t
|
|
|
|
x_create_picture_with_visual(xcb_connection_t *, xcb_drawable_t, int w, int h,
|
2019-03-30 09:07:21 +00:00
|
|
|
xcb_visualid_t visual, uint32_t valuemask,
|
2019-03-10 12:34:37 +00:00
|
|
|
const xcb_render_create_picture_value_list_t *attr)
|
|
|
|
attr_nonnull(1);
|
2018-12-21 23:44:42 +00:00
|
|
|
|
2018-09-29 22:36:53 +00:00
|
|
|
/// Fetch a X region and store it in a pixman region
|
2019-02-03 15:59:31 +00:00
|
|
|
bool x_fetch_region(xcb_connection_t *, xcb_xfixes_region_t r, region_t *res);
|
2018-09-29 22:36:53 +00:00
|
|
|
|
2022-12-14 07:37:27 +00:00
|
|
|
/// Create a X region from a pixman region
|
|
|
|
uint32_t x_create_region(xcb_connection_t *c, const region_t *reg);
|
|
|
|
|
|
|
|
/// Destroy a X region
|
|
|
|
void x_destroy_region(xcb_connection_t *c, uint32_t region);
|
|
|
|
|
2019-03-30 09:07:21 +00:00
|
|
|
void x_set_picture_clip_region(xcb_connection_t *, xcb_render_picture_t, int16_t clip_x_origin,
|
|
|
|
int16_t clip_y_origin, const region_t *);
|
2018-09-30 13:37:21 +00:00
|
|
|
|
2019-02-03 15:59:31 +00:00
|
|
|
void x_clear_picture_clip_region(xcb_connection_t *, xcb_render_picture_t pict);
|
2018-12-21 23:44:42 +00:00
|
|
|
|
2018-09-30 13:37:21 +00:00
|
|
|
/**
|
2020-03-27 23:07:19 +00:00
|
|
|
* Log a X11 error
|
2018-09-30 13:37:21 +00:00
|
|
|
*/
|
2019-03-30 09:07:21 +00:00
|
|
|
void x_print_error(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_code);
|
2022-12-14 14:23:55 +00:00
|
|
|
void x_log_error(enum log_level level, unsigned long serial, uint8_t major,
|
|
|
|
uint16_t minor, uint8_t error_code);
|
2018-09-30 19:53:52 +00:00
|
|
|
|
2020-03-27 23:07:19 +00:00
|
|
|
/*
|
|
|
|
* Convert a xcb_generic_error_t to a string that describes the error
|
|
|
|
*
|
|
|
|
* @return a pointer to a string. this pointer shouldn NOT be freed, same buffer is used
|
|
|
|
* for multiple calls to this function,
|
|
|
|
*/
|
|
|
|
const char *x_strerror(xcb_generic_error_t *e);
|
|
|
|
|
2019-02-03 15:59:31 +00:00
|
|
|
xcb_pixmap_t x_create_pixmap(xcb_connection_t *, uint8_t depth, xcb_drawable_t drawable,
|
2019-03-30 09:07:21 +00:00
|
|
|
int width, int height);
|
2018-12-09 20:54:16 +00:00
|
|
|
|
2019-02-03 15:59:31 +00:00
|
|
|
bool x_validate_pixmap(xcb_connection_t *, xcb_pixmap_t pxmap);
|
2018-12-15 21:11:41 +00:00
|
|
|
|
2018-12-09 20:54:16 +00:00
|
|
|
/**
|
|
|
|
* Free a <code>winprop_t</code>.
|
|
|
|
*
|
|
|
|
* @param pprop pointer to the <code>winprop_t</code> to free.
|
|
|
|
*/
|
2019-02-03 15:59:31 +00:00
|
|
|
static inline void free_winprop(winprop_t *pprop) {
|
|
|
|
// Empty the whole structure to avoid possible issues
|
|
|
|
if (pprop->r)
|
|
|
|
free(pprop->r);
|
|
|
|
pprop->ptr = NULL;
|
|
|
|
pprop->r = NULL;
|
|
|
|
pprop->nitems = 0;
|
2018-12-09 20:54:16 +00:00
|
|
|
}
|
2020-12-26 07:51:03 +00:00
|
|
|
|
2018-12-21 23:44:42 +00:00
|
|
|
/// Get the back pixmap of the root window
|
2020-12-26 07:51:03 +00:00
|
|
|
xcb_pixmap_t
|
|
|
|
x_get_root_back_pixmap(xcb_connection_t *c, xcb_window_t root, struct atom *atoms);
|
2018-12-21 23:44:42 +00:00
|
|
|
|
|
|
|
/// Return true if the atom refers to a property name that is used for the
|
|
|
|
/// root window background pixmap
|
2020-12-26 07:51:03 +00:00
|
|
|
bool x_is_root_back_pixmap_atom(struct atom *atoms, xcb_atom_t atom);
|
2018-12-30 07:06:47 +00:00
|
|
|
|
2019-02-03 15:59:31 +00:00
|
|
|
bool x_fence_sync(xcb_connection_t *, xcb_sync_fence_t);
|
2019-02-17 23:47:46 +00:00
|
|
|
|
2019-06-06 06:37:48 +00:00
|
|
|
struct x_convolution_kernel {
|
|
|
|
int size;
|
|
|
|
int capacity;
|
|
|
|
xcb_render_fixed_t kernel[];
|
|
|
|
};
|
|
|
|
|
2019-02-17 23:47:46 +00:00
|
|
|
/**
|
2019-02-20 16:43:42 +00:00
|
|
|
* Convert a struct conv to a X picture convolution filter, normalizing the kernel
|
|
|
|
* in the process. Allow the caller to specify the element at the center of the kernel,
|
|
|
|
* for compatibility with legacy code.
|
2019-02-17 23:47:46 +00:00
|
|
|
*
|
2019-02-20 16:43:42 +00:00
|
|
|
* @param[in] kernel the convolution kernel
|
|
|
|
* @param[in] center the element to put at the center of the matrix
|
|
|
|
* @param[inout] ret pointer to an array of `size`, if `size` is too small, more space
|
|
|
|
* will be allocated, and `*ret` will be updated.
|
|
|
|
* @param[inout] size size of the array pointed to by `ret`.
|
2019-02-17 23:47:46 +00:00
|
|
|
*/
|
2019-06-06 06:37:48 +00:00
|
|
|
void attr_nonnull(1, 3) x_create_convolution_kernel(const conv *kernel, double center,
|
|
|
|
struct x_convolution_kernel **ret);
|
2019-02-26 23:52:37 +00:00
|
|
|
|
|
|
|
/// Generate a search criteria for fbconfig from a X visual.
|
|
|
|
/// Returns {-1, -1, -1, -1, -1, -1} on failure
|
2019-03-10 12:34:37 +00:00
|
|
|
struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual);
|
2019-02-26 23:52:37 +00:00
|
|
|
|
2019-03-10 12:34:37 +00:00
|
|
|
xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std);
|
2019-03-30 09:07:21 +00:00
|
|
|
|
2020-08-19 18:22:17 +00:00
|
|
|
xcb_render_pictformat_t
|
|
|
|
x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std);
|
|
|
|
|
2019-03-30 09:07:21 +00:00
|
|
|
xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen);
|
2019-05-21 22:23:30 +00:00
|
|
|
|
2023-01-13 11:27:45 +00:00
|
|
|
/**
|
|
|
|
* X RandR-related functions.
|
|
|
|
*
|
|
|
|
* The x_update_randr_monitors function populates ps->randr_nmonitors and
|
|
|
|
* ps->randr_monitor_regs with the data X RandR provided and the
|
|
|
|
* x_free_randr_info function frees them.
|
|
|
|
*/
|
|
|
|
void x_update_randr_monitors(session_t *ps);
|
|
|
|
void x_free_randr_info(session_t *ps);
|
|
|
|
|
2019-05-21 22:23:30 +00:00
|
|
|
uint32_t attr_deprecated xcb_generate_id(xcb_connection_t *c);
|