2024-03-24 02:02:14 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
// Copyright (c) Yuxuan Shui.
|
Feature: Issue #29: Alternative shadow blacklist implementation
- Add shadow blacklist feature, but a different implementation from
nicklan's. 5 matching modes (exact, starts-with, contains, wildcard,
PCRE) and 3 matching targets (window name, window class instance,
window general class). Not extensively tested, bugs to be expected.
It's slower for exact matching than nicklan's as it uses linear search
instead of hash table. Also, PCRE's JIT optimization may cause issues
on PaX kernels.
- Add dependency to libpcre. Could be made optional if we have a
graceful way to handle that in Makefile.
- Some matching functions are GNU extensions of glibc. So this version
may have troubles running on platforms not using glibc.
- Fix a bug that access freed memory blocks in set_fade_callcack() and
check_fade_fin(). valgrind found it out.
- Use WM_CLASS to detect client windows instead of WM_STATE. Some client
windows (like notification windows) have WM_CLASS but not WM_STATE.
- Mark the extents as damaged if shadow state changed in
determine_shadow().
- Rewrite wid_get_name(). Code clean-up.
- Two debugging options: DEBUG_WINDATA and DEBUG_WINMATCH.
- As the matching system is ready, it should be rather easy to add other
kinds of blacklists, like fading blacklist.
2012-09-22 03:42:39 +00:00
|
|
|
|
|
|
|
// === Includes ===
|
2024-03-24 02:02:14 +00:00
|
|
|
#pragma once
|
2019-03-10 12:34:37 +00:00
|
|
|
#include <stdbool.h>
|
2019-01-20 21:15:20 +00:00
|
|
|
#include <xcb/xproto.h>
|
Feature: #7: VSync
- Add VSync feature. 3 possible VSync methods available: "sw" (software,
not too reliable, but at least you have something to fallback to),
"drm" (using DRM_IOCTL_WAIT_VBLANK, should work only on DRI drivers),
"opengl" (using SGI_swap_control extension OpenGL, might work on more
drivers than the DRM method). "sw" and "opengl" are briefly tested,
"drm" received utterly no test (because I use the nVidia binary blob).
They are enabled with "--vsync sw" / "--vsync drm" / "--vsync opengl".
- Add --refresh-rate to let user specify a refresh rate for software
VSync, in case the automatic refresh rate detection does not work
well.
- Seemingly the automatic refresh rate detection using X RandR in
software VSync detects refresh rate incorrectly. Need further investigation.
- Fix a few bugs in fading timing.
- Add a workaround for client window detection on Fluxbox, as Fluxbox
(incorrectly?) sets the override-redirect flag upon all frame
windows.
- Software VSync adds dependency on librt (a part of glibc) for
nanosecond-level timing functions, and libXrandr for automatic refresh
rate detection; DRM VSync adds dependency on libdrm to use its drm.h,
but does not link to libdrm; OpenGL VSync adds dependency on libGL.
- Print timing information on DEBUG_REPAINT.
2012-10-08 02:20:01 +00:00
|
|
|
|
2018-10-25 22:31:40 +00:00
|
|
|
#include <X11/Xutil.h>
|
2019-02-09 15:52:40 +00:00
|
|
|
#include "backend/backend.h"
|
2024-03-24 02:02:14 +00:00
|
|
|
#include "backend/driver.h"
|
2018-08-22 12:26:42 +00:00
|
|
|
#include "c2.h"
|
2019-03-10 12:34:37 +00:00
|
|
|
#include "common.h"
|
|
|
|
#include "config.h"
|
2024-03-24 02:02:14 +00:00
|
|
|
#include "ev.h"
|
|
|
|
#include "list.h"
|
2019-03-10 12:34:37 +00:00
|
|
|
#include "region.h"
|
|
|
|
#include "render.h"
|
2019-01-18 23:30:44 +00:00
|
|
|
#include "types.h"
|
2019-03-10 12:34:37 +00:00
|
|
|
#include "win.h"
|
|
|
|
#include "x.h"
|
2024-03-24 02:02:14 +00:00
|
|
|
#include "xcb/render.h"
|
2018-08-22 12:26:42 +00:00
|
|
|
|
core: delayed handling of root ConfigureNotify
Previously, root ConfigureNotify is handled immediately, by resetting
the backend, which in turn releases all the window images. This puts all
the windows into a state where they don't have images attached, which
they really should be in when the screen is redirected.
(To expand a little, a window without images should only exist if:
* It's an unmanaged window.
* Screen is unredirected.)
Normally, this kind of window could be fine, as the next render phase
will re-acquire images for them. However, if a window in this state is
destroyed with fading enabled, then the render phase won't try to
acquire images for it, causing it to go into the main rendering function
without images attached, and trigger an assertion.
This commit delays the handling of root ConfigureNotify until the render
phase. This way, the images will be immediately re-acquired after they
are released, thus prevent this problem from happening.
Also adds a testcase for this.
Fixes #357
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2020-03-31 04:01:14 +00:00
|
|
|
enum root_flags {
|
|
|
|
ROOT_FLAGS_SCREEN_CHANGE = 1, // Received RandR screen change notify, we
|
|
|
|
// use this to track refresh rate changes
|
|
|
|
ROOT_FLAGS_CONFIGURED = 2 // Received configure notify on the root window
|
|
|
|
};
|
2019-03-17 15:17:48 +00:00
|
|
|
|
Convert XfixesRegion to pixman region
Re-did the painting logic, and document it.
It is unclear to me what is the previous painting logic. But the current
one is basically this:
1. Go through all windows top to bottom, and put visible windows (not
unmapped, opacity > 0, etc) into a linked list, from bottom to top
2. Accumulate a region of ignore on each window, which is basically the
region of screen that is obscured by all the windows above current
one.
3. Paint all the visible windows from bottom to top. Subtract the region
of ignore from the painting region. If we need to paint shadow, we
subtract the body of the window from the shadow painting region too,
because we don't want shadow behind the window.
4. region of ignore is invalidated when window stack change, an
window on top moved or changed shape, when window changed between
opaque and transparent, etc.
Notes:
It is unclear whether all the different shapes of a window (extents,
noframe, border, bounding shape, etc) are calculated correctly or not.
It is unclear if window shape related events are handled correctly or
not. Need more testing.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
2018-09-30 03:56:00 +00:00
|
|
|
void add_damage(session_t *ps, const region_t *damage);
|
2019-03-30 09:07:21 +00:00
|
|
|
uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode);
|
2019-03-17 13:44:26 +00:00
|
|
|
void circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce);
|
|
|
|
void root_damaged(session_t *ps);
|
|
|
|
void queue_redraw(session_t *ps);
|
2022-12-14 14:23:55 +00:00
|
|
|
void discard_pending(session_t *ps, uint32_t sequence);
|
2019-03-17 15:17:48 +00:00
|
|
|
void set_root_flags(session_t *ps, uint64_t flags);
|
2019-10-23 18:27:30 +00:00
|
|
|
void quit(session_t *ps);
|
2019-07-07 15:12:17 +00:00
|
|
|
xcb_window_t session_get_target_window(session_t *);
|
2020-03-11 19:15:26 +00:00
|
|
|
uint8_t session_redirection_mode(session_t *ps);
|
2024-03-24 02:02:14 +00:00
|
|
|
struct options *session_get_options(session_t *ps);
|
|
|
|
struct ev_loop *session_get_mainloop(session_t *ps);
|
|
|
|
struct x_connection *session_get_x_connection(session_t *ps);
|
|
|
|
xcb_window_t session_get_overlay(session_t *ps);
|
|
|
|
struct atom *session_get_atoms(session_t *ps);
|
|
|
|
struct c2_state *session_get_c2(session_t *ps);
|
|
|
|
void session_mark_updates_pending(session_t *ps);
|
|
|
|
// TODO(yshui) can we lump these 3 backend related functions together?
|
|
|
|
struct backend_base *session_get_backend_data(session_t *ps);
|
|
|
|
struct backend_shadow_context *session_get_backend_shadow_context(session_t *ps);
|
|
|
|
void *session_get_backend_blur_context(session_t *ps);
|
|
|
|
struct shader_info *session_get_shader_info(session_t *ps, const char *key);
|
|
|
|
bool session_is_redirected(session_t *ps);
|
|
|
|
void session_xsync_wait_fence(session_t *ps);
|
|
|
|
enum driver session_get_driver(session_t *ps);
|
|
|
|
struct damage_ring *session_get_damage_ring(session_t *ps);
|
|
|
|
void session_assert_server_grabbed(session_t *ps);
|
|
|
|
image_handle session_get_root_image(session_t *ps);
|
|
|
|
/// Record the amount of CPU time spent in the render cycle. This is called in
|
|
|
|
/// backend.c just before we start sending backend rendering commands. `struct session`
|
|
|
|
/// keeps track when each render call started, when this function is called, the time
|
|
|
|
/// difference is used as the CPU time spent in the render cycle.
|
|
|
|
void session_record_cpu_time(session_t *ps);
|
|
|
|
|
|
|
|
// TODO(yshui) move window related data out of session_t, and remove these getters
|
|
|
|
void session_delete_win(session_t *ps, struct win *w);
|
|
|
|
struct list_node *session_get_win_stack(session_t *ps);
|
|
|
|
struct managed_win *session_get_active_win(session_t *ps);
|
|
|
|
void session_set_active_win(session_t *ps, struct managed_win *w);
|
|
|
|
struct win *session_get_next_win_in_stack(session_t *ps, struct win *w);
|
|
|
|
unsigned int session_get_window_count(session_t *ps);
|
|
|
|
void session_foreach_win(session_t *ps, void (*func)(struct win *w, void *data), void *data);
|
|
|
|
xcb_window_t session_get_active_leader(session_t *ps);
|
|
|
|
void session_set_active_leader(session_t *ps, xcb_window_t leader);
|
|
|
|
void session_clear_cache_win_leaders(session_t *ps);
|
|
|
|
bool session_is_win_region_ignore_valid(session_t *ps, const struct managed_win *w);
|
|
|
|
struct win *session_find_win(session_t *ps, xcb_window_t id);
|
|
|
|
/// Insert a new window above window with id `below`, if there is no window, add to top
|
|
|
|
/// New window will be in unmapped state
|
|
|
|
struct win *session_add_win_above(session_t *ps, xcb_window_t id, xcb_window_t below);
|
|
|
|
/// Insert a new win entry at the top of the stack
|
|
|
|
struct win *session_add_win_top(session_t *ps, xcb_window_t id);
|
|
|
|
/// Move window `w` to be right above `below`
|
|
|
|
void session_restack_above(session_t *ps, struct win *w, xcb_window_t below);
|
|
|
|
/// Move window `w` to the bottom of the stack
|
|
|
|
void session_restack_bottom(session_t *ps, struct win *w);
|
|
|
|
/// Move window `w` to the top of the stack
|
|
|
|
void session_restack_top(session_t *ps, struct win *w);
|
|
|
|
/**
|
|
|
|
* Find out the WM frame of a client window using existing data.
|
|
|
|
*
|
|
|
|
* @param id window ID
|
|
|
|
* @return struct win object of the found window, NULL if not found
|
|
|
|
*/
|
|
|
|
struct managed_win *session_find_toplevel(session_t *ps, xcb_window_t id);
|
|
|
|
// Find the managed window immediately below `w` in the window stack
|
|
|
|
struct managed_win *
|
|
|
|
session_get_next_managed_win_in_stack(const session_t *ps, const struct list_node *cursor);
|
|
|
|
|
|
|
|
// TODO(yshui) Legacy backend stuff, should probably lump them together. Also remove them
|
|
|
|
// once the legacy backends are removed.
|
|
|
|
#ifdef CONFIG_OPENGL
|
|
|
|
struct glx_session *session_get_psglx(session_t *ps);
|
|
|
|
void session_set_psglx(session_t *ps, struct glx_session *psglx);
|
|
|
|
#endif
|
|
|
|
struct {
|
|
|
|
int height, width;
|
|
|
|
} session_get_root_extent(session_t *ps);
|
|
|
|
xcb_render_picture_t *session_get_alpha_pictures(session_t *ps);
|
|
|
|
struct x_monitors *session_get_monitors(session_t *ps);
|
|
|
|
paint_t *session_get_tgt_buffer(session_t *ps);
|
|
|
|
xcb_render_picture_t session_get_tgt_picture(session_t *ps);
|
|
|
|
paint_t *session_get_root_tile_paint(session_t *ps);
|
|
|
|
bool session_get_root_tile_fill(session_t *ps);
|
|
|
|
void session_set_root_tile_fill(session_t *ps, bool fill);
|
|
|
|
void session_vsync_wait(session_t *ps);
|
|
|
|
void session_set_vsync_wait(session_t *ps, int (*vsync_wait)(session_t *));
|
|
|
|
xcb_render_picture_t session_get_white_picture(session_t *ps);
|
|
|
|
xcb_render_picture_t session_get_black_picture(session_t *ps);
|
|
|
|
xcb_render_picture_t session_get_cshadow_picture(session_t *ps);
|
|
|
|
void session_set_black_picture(session_t *ps, xcb_render_picture_t p);
|
|
|
|
void session_set_white_picture(session_t *ps, xcb_render_picture_t p);
|
|
|
|
void session_set_cshadow_picture(session_t *ps, xcb_render_picture_t p);
|
|
|
|
region_t *session_get_screen_reg(session_t *ps);
|
|
|
|
region_t *session_get_shadow_exclude_reg(session_t *ps);
|
|
|
|
struct x_convolution_kernel **session_get_blur_kern_cache(session_t *ps);
|
|
|
|
void session_set_blur_kern_cache(session_t *ps, struct x_convolution_kernel **cache);
|
|
|
|
|
|
|
|
// TODO(yshui) has_extension and get_*_extension_error should probably be in struct
|
|
|
|
// x_connection, or just use xcb functions instead - those are cached as well.
|
|
|
|
bool session_has_glx_extension(session_t *ps);
|
|
|
|
bool session_has_shape_extension(session_t *ps);
|
|
|
|
bool session_has_present_extension(session_t *ps);
|
|
|
|
bool session_has_randr_extension(session_t *ps);
|
|
|
|
bool session_has_xsync_extension(session_t *ps);
|
|
|
|
int session_get_xfixes_extension_error(session_t *ps);
|
|
|
|
int session_get_render_extension_error(session_t *ps);
|
|
|
|
int session_get_damage_extension_error(session_t *ps);
|
|
|
|
int session_get_glx_extension_error(session_t *ps);
|
|
|
|
int session_get_xsync_extension_error(session_t *ps);
|
|
|
|
int session_get_xsync_extention_event(session_t *ps);
|
|
|
|
int session_get_damage_extention_event(session_t *ps);
|
|
|
|
int session_get_shape_extention_event(session_t *ps);
|
|
|
|
int session_get_randr_extention_event(session_t *ps);
|
2020-03-11 19:15:26 +00:00
|
|
|
|
2024-03-23 14:01:46 +00:00
|
|
|
#ifdef CONFIG_DBUS
|
|
|
|
struct cdbus_data *session_get_cdbus(struct session *);
|
|
|
|
#else
|
|
|
|
static inline struct cdbus_data *session_get_cdbus(session_t *ps attr_unused) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-12-10 02:31:24 +00:00
|
|
|
/**
|
|
|
|
* Set a <code>switch_t</code> array of all unset wintypes to true.
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static inline void wintype_arr_enable_unset(switch_t arr[]) {
|
|
|
|
wintype_t i;
|
2012-12-10 02:31:24 +00:00
|
|
|
|
2023-08-10 22:38:22 +00:00
|
|
|
for (i = 0; i < NUM_WINTYPES; ++i) {
|
|
|
|
if (UNSET == arr[i]) {
|
2019-03-10 12:34:37 +00:00
|
|
|
arr[i] = ON;
|
2023-08-10 22:38:22 +00:00
|
|
|
}
|
|
|
|
}
|
2012-12-10 02:31:24 +00:00
|
|
|
}
|
|
|
|
|
2012-09-11 14:22:58 +00:00
|
|
|
/**
|
|
|
|
* Check if a window ID exists in an array of window IDs.
|
|
|
|
*
|
|
|
|
* @param arr the array of window IDs
|
|
|
|
* @param count amount of elements in the array
|
|
|
|
* @param wid window ID to search for
|
|
|
|
*/
|
2019-03-10 12:34:37 +00:00
|
|
|
static inline bool array_wid_exists(const xcb_window_t *arr, int count, xcb_window_t wid) {
|
|
|
|
while (count--) {
|
|
|
|
if (arr[count] == wid) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2012-09-11 14:22:58 +00:00
|
|
|
}
|
2012-09-16 15:12:02 +00:00
|
|
|
|
2018-12-15 21:11:41 +00:00
|
|
|
#ifndef CONFIG_OPENGL
|
2019-07-25 01:48:12 +00:00
|
|
|
static inline void free_paint_glx(session_t *ps attr_unused, paint_t *p attr_unused) {
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2019-07-25 01:48:12 +00:00
|
|
|
static inline void
|
|
|
|
free_win_res_glx(session_t *ps attr_unused, struct managed_win *w attr_unused) {
|
2019-03-10 12:34:37 +00:00
|
|
|
}
|
2018-09-29 21:47:12 +00:00
|
|
|
#endif
|