mirror of
https://github.com/yshui/picom.git
synced 2025-04-14 17:53:25 -04:00
WIP core: struct sesion is now opaque
This commit is contained in:
parent
4c8515cf50
commit
959f400ae1
22 changed files with 1983 additions and 1548 deletions
|
@ -9,6 +9,7 @@
|
|||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "region.h"
|
||||
#include "transition.h"
|
||||
#include "types.h"
|
||||
|
@ -35,15 +36,17 @@ struct backend_operations *backend_list[NUM_BKEND] = {
|
|||
*/
|
||||
region_t get_damage(session_t *ps, bool all_damage) {
|
||||
region_t region;
|
||||
auto buffer_age_fn = ps->backend_data->ops->buffer_age;
|
||||
int buffer_age = buffer_age_fn ? buffer_age_fn(ps->backend_data) : -1;
|
||||
auto backend_data = session_get_backend_data(ps);
|
||||
auto buffer_age_fn = backend_data->ops->buffer_age;
|
||||
int buffer_age = buffer_age_fn ? buffer_age_fn(backend_data) : -1;
|
||||
|
||||
if (all_damage) {
|
||||
buffer_age = -1;
|
||||
}
|
||||
|
||||
pixman_region32_init(®ion);
|
||||
damage_ring_collect(&ps->damage_ring, &ps->screen_reg, ®ion, buffer_age);
|
||||
damage_ring_collect(session_get_damage_ring(ps), session_get_screen_reg(ps),
|
||||
®ion, buffer_age);
|
||||
return region;
|
||||
}
|
||||
|
||||
|
@ -69,7 +72,7 @@ void handle_device_reset(session_t *ps) {
|
|||
|
||||
// Reset picom
|
||||
log_info("Resetting picom after device reset");
|
||||
ev_break(ps->loop, EVBREAK_ALL);
|
||||
ev_break(session_get_mainloop(ps), EVBREAK_ALL);
|
||||
}
|
||||
|
||||
/// paint all windows
|
||||
|
@ -78,34 +81,31 @@ void handle_device_reset(session_t *ps) {
|
|||
/// this function will return false.
|
||||
bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
||||
struct timespec now = get_time_timespec();
|
||||
uint64_t after_sync_fence_us = 0, after_damage_us = 0;
|
||||
auto paint_all_start_us =
|
||||
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
|
||||
if (ps->backend_data->ops->device_status &&
|
||||
ps->backend_data->ops->device_status(ps->backend_data) != DEVICE_STATUS_NORMAL) {
|
||||
auto backend_data = session_get_backend_data(ps);
|
||||
auto backend_blur_context = session_get_backend_blur_context(ps);
|
||||
auto options = session_get_options(ps);
|
||||
if (backend_data->ops->device_status &&
|
||||
backend_data->ops->device_status(backend_data) != DEVICE_STATUS_NORMAL) {
|
||||
handle_device_reset(ps);
|
||||
return false;
|
||||
}
|
||||
if (ps->o.xrender_sync_fence) {
|
||||
if (ps->xsync_exists && !x_fence_sync(&ps->c, ps->sync_fence)) {
|
||||
log_error("x_fence_sync failed, xrender-sync-fence will be "
|
||||
"disabled from now on.");
|
||||
xcb_sync_destroy_fence(ps->c.c, ps->sync_fence);
|
||||
ps->sync_fence = XCB_NONE;
|
||||
ps->o.xrender_sync_fence = false;
|
||||
ps->xsync_exists = false;
|
||||
}
|
||||
}
|
||||
session_xsync_wait_fence(ps);
|
||||
|
||||
now = get_time_timespec();
|
||||
auto after_sync_fence_us =
|
||||
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
|
||||
log_trace("Time spent on sync fence: %" PRIu64 " us",
|
||||
after_sync_fence_us - paint_all_start_us);
|
||||
if (unlikely(log_get_level_tls() > LOG_LEVEL_TRACE)) {
|
||||
now = get_time_timespec();
|
||||
after_sync_fence_us =
|
||||
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
|
||||
log_trace("Time spent on sync fence: %" PRIu64 " us",
|
||||
after_sync_fence_us - paint_all_start_us);
|
||||
}
|
||||
// All painting will be limited to the damage, if _some_ of
|
||||
// the paints bleed out of the damage region, it will destroy
|
||||
// part of the image we want to reuse
|
||||
region_t reg_damage;
|
||||
reg_damage = get_damage(ps, ps->o.monitor_repaint || !ps->o.use_damage);
|
||||
reg_damage = get_damage(ps, options->monitor_repaint || !options->use_damage);
|
||||
|
||||
if (!pixman_region32_not_empty(®_damage)) {
|
||||
pixman_region32_fini(®_damage);
|
||||
|
@ -127,11 +127,12 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
|
||||
/// The adjusted damaged regions
|
||||
region_t reg_paint;
|
||||
assert(ps->o.blur_method != BLUR_METHOD_INVALID);
|
||||
if (ps->o.blur_method != BLUR_METHOD_NONE && ps->backend_data->ops->get_blur_size) {
|
||||
region_t *screen_reg = session_get_screen_reg(ps);
|
||||
assert(options->blur_method != BLUR_METHOD_INVALID);
|
||||
if (options->blur_method != BLUR_METHOD_NONE && backend_data->ops->get_blur_size) {
|
||||
int blur_width, blur_height;
|
||||
ps->backend_data->ops->get_blur_size(ps->backend_blur_context,
|
||||
&blur_width, &blur_height);
|
||||
backend_data->ops->get_blur_size(backend_blur_context, &blur_width,
|
||||
&blur_height);
|
||||
|
||||
// The region of screen a given window influences will be smeared
|
||||
// out by blur. With more windows on top of the given window, the
|
||||
|
@ -155,8 +156,8 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
blur_height * resize_factor);
|
||||
reg_paint = resize_region(®_damage, blur_width * resize_factor,
|
||||
blur_height * resize_factor);
|
||||
pixman_region32_intersect(®_paint, ®_paint, &ps->screen_reg);
|
||||
pixman_region32_intersect(®_damage, ®_damage, &ps->screen_reg);
|
||||
pixman_region32_intersect(®_paint, ®_paint, screen_reg);
|
||||
pixman_region32_intersect(®_damage, ®_damage, screen_reg);
|
||||
} else {
|
||||
pixman_region32_init(®_paint);
|
||||
pixman_region32_copy(®_paint, ®_damage);
|
||||
|
@ -166,8 +167,8 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
// backend can optimize based on this info
|
||||
region_t reg_visible;
|
||||
pixman_region32_init(®_visible);
|
||||
pixman_region32_copy(®_visible, &ps->screen_reg);
|
||||
if (t && !ps->o.transparent_clipping) {
|
||||
pixman_region32_copy(®_visible, screen_reg);
|
||||
if (t && !options->transparent_clipping) {
|
||||
// Calculate the region upon which the root window (wallpaper) is to be
|
||||
// painted based on the ignore region of the lowest window, if available
|
||||
//
|
||||
|
@ -181,31 +182,25 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
region_t reg_shadow_clip;
|
||||
pixman_region32_init(®_shadow_clip);
|
||||
|
||||
now = get_time_timespec();
|
||||
auto after_damage_us = (uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
|
||||
log_trace("Getting damage took %" PRIu64 " us", after_damage_us - after_sync_fence_us);
|
||||
if (ps->next_render > 0) {
|
||||
log_verbose("Render schedule deviation: %ld us (%s) %" PRIu64 " %" PRIu64,
|
||||
labs((long)after_damage_us - (long)ps->next_render),
|
||||
after_damage_us < ps->next_render ? "early" : "late",
|
||||
after_damage_us, ps->next_render);
|
||||
ps->last_schedule_delay = 0;
|
||||
if (after_damage_us > ps->next_render) {
|
||||
ps->last_schedule_delay = after_damage_us - ps->next_render;
|
||||
}
|
||||
if (unlikely(log_get_level_tls() > LOG_LEVEL_TRACE)) {
|
||||
now = get_time_timespec();
|
||||
after_damage_us =
|
||||
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
|
||||
log_trace("Getting damage took %" PRIu64 " us",
|
||||
after_damage_us - after_sync_fence_us);
|
||||
}
|
||||
session_record_cpu_time(ps);
|
||||
|
||||
if (backend_data->ops->prepare) {
|
||||
backend_data->ops->prepare(backend_data, ®_paint);
|
||||
}
|
||||
|
||||
if (ps->backend_data->ops->prepare) {
|
||||
ps->backend_data->ops->prepare(ps->backend_data, ®_paint);
|
||||
}
|
||||
|
||||
if (ps->root_image) {
|
||||
ps->backend_data->ops->compose(ps->backend_data, ps->root_image,
|
||||
(coord_t){0}, NULL, (coord_t){0},
|
||||
®_paint, ®_visible);
|
||||
auto root_image = session_get_root_image(ps);
|
||||
if (root_image) {
|
||||
backend_data->ops->compose(backend_data, root_image, (coord_t){0}, NULL,
|
||||
(coord_t){0}, ®_paint, ®_visible);
|
||||
} else {
|
||||
ps->backend_data->ops->fill(ps->backend_data, (struct color){0, 0, 0, 1},
|
||||
®_paint);
|
||||
backend_data->ops->fill(backend_data, (struct color){0, 0, 0, 1}, ®_paint);
|
||||
}
|
||||
|
||||
// Windows are sorted from bottom to top
|
||||
|
@ -214,7 +209,7 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
//
|
||||
// Whether this is beneficial is to be determined XXX
|
||||
for (struct managed_win *w = t; w; w = w->prev_trans) {
|
||||
pixman_region32_subtract(®_visible, &ps->screen_reg, w->reg_ignore);
|
||||
pixman_region32_subtract(®_visible, screen_reg, w->reg_ignore);
|
||||
assert(!(w->flags & WIN_FLAGS_IMAGE_ERROR));
|
||||
assert(!(w->flags & WIN_FLAGS_PIXMAP_STALE));
|
||||
assert(!(w->flags & WIN_FLAGS_PIXMAP_NONE));
|
||||
|
@ -226,7 +221,7 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
win_get_bounding_shape_global_without_corners_by_val(w);
|
||||
|
||||
if (!w->mask_image && (w->bounding_shaped || w->corner_radius != 0)) {
|
||||
win_bind_mask(ps->backend_data, w);
|
||||
win_bind_mask(backend_data, w);
|
||||
}
|
||||
|
||||
// The clip region for the current window, in global/target coordinates
|
||||
|
@ -234,7 +229,7 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
region_t reg_paint_in_bound;
|
||||
pixman_region32_init(®_paint_in_bound);
|
||||
pixman_region32_intersect(®_paint_in_bound, ®_bound, ®_paint);
|
||||
if (ps->o.transparent_clipping) {
|
||||
if (options->transparent_clipping) {
|
||||
// <transparent-clipping-note>
|
||||
// If transparent_clipping is enabled, we need to be SURE that
|
||||
// things are not drawn inside reg_ignore, because otherwise they
|
||||
|
@ -256,8 +251,8 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
|
||||
const double window_opacity = animatable_get(&w->opacity);
|
||||
if (w->blur_background &&
|
||||
(ps->o.force_win_blend || real_win_mode == WMODE_TRANS ||
|
||||
(ps->o.blur_background_frame && real_win_mode == WMODE_FRAME_TRANS))) {
|
||||
(options->force_win_blend || real_win_mode == WMODE_TRANS ||
|
||||
(options->blur_background_frame && real_win_mode == WMODE_FRAME_TRANS))) {
|
||||
// Minimize the region we try to blur, if the window
|
||||
// itself is not opaque, only the frame is.
|
||||
|
||||
|
@ -267,32 +262,32 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
if (blur_opacity * MAX_ALPHA < 1) {
|
||||
// We don't need to blur if it would be completely
|
||||
// transparent
|
||||
} else if (real_win_mode == WMODE_TRANS || ps->o.force_win_blend) {
|
||||
} else if (real_win_mode == WMODE_TRANS || options->force_win_blend) {
|
||||
// We need to blur the bounding shape of the window
|
||||
// (reg_paint_in_bound = reg_bound \cap reg_paint)
|
||||
ps->backend_data->ops->blur(
|
||||
ps->backend_data, blur_opacity,
|
||||
ps->backend_blur_context, w->mask_image, window_coord,
|
||||
®_paint_in_bound, ®_visible);
|
||||
backend_data->ops->blur(backend_data, blur_opacity,
|
||||
backend_blur_context,
|
||||
w->mask_image, window_coord,
|
||||
®_paint_in_bound, ®_visible);
|
||||
} else {
|
||||
// Window itself is solid, we only need to blur the frame
|
||||
// region
|
||||
|
||||
// Readability assertions
|
||||
assert(ps->o.blur_background_frame);
|
||||
assert(options->blur_background_frame);
|
||||
assert(real_win_mode == WMODE_FRAME_TRANS);
|
||||
|
||||
auto reg_blur = win_get_region_frame_local_by_val(w);
|
||||
pixman_region32_translate(®_blur, w->g.x, w->g.y);
|
||||
// make sure reg_blur \in reg_paint
|
||||
pixman_region32_intersect(®_blur, ®_blur, ®_paint);
|
||||
if (ps->o.transparent_clipping) {
|
||||
if (options->transparent_clipping) {
|
||||
// ref: <transparent-clipping-note>
|
||||
pixman_region32_intersect(®_blur, ®_blur,
|
||||
®_visible);
|
||||
}
|
||||
ps->backend_data->ops->blur(
|
||||
ps->backend_data, blur_opacity, ps->backend_blur_context,
|
||||
backend_data->ops->blur(
|
||||
backend_data, blur_opacity, backend_blur_context,
|
||||
w->mask_image, window_coord, ®_blur, ®_visible);
|
||||
pixman_region32_fini(®_blur);
|
||||
}
|
||||
|
@ -301,11 +296,12 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
// The win_bind_shadow function must be called before checking if a window
|
||||
// has shadow enabled because it disables shadow for a window on failure.
|
||||
if (w->shadow && !w->shadow_image) {
|
||||
struct color shadow_color = {.red = ps->o.shadow_red,
|
||||
.green = ps->o.shadow_green,
|
||||
.blue = ps->o.shadow_blue,
|
||||
.alpha = ps->o.shadow_opacity};
|
||||
win_bind_shadow(ps->backend_data, w, shadow_color, ps->shadow_context);
|
||||
struct color shadow_color = {.red = options->shadow_red,
|
||||
.green = options->shadow_green,
|
||||
.blue = options->shadow_blue,
|
||||
.alpha = options->shadow_opacity};
|
||||
win_bind_shadow(backend_data, w, shadow_color,
|
||||
session_get_backend_shadow_context(ps));
|
||||
}
|
||||
|
||||
// Draw shadow on target
|
||||
|
@ -316,17 +312,19 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
pixman_region32_intersect(®_shadow, ®_shadow, ®_paint);
|
||||
|
||||
// Mask out the region we don't want shadow on
|
||||
if (pixman_region32_not_empty(&ps->shadow_exclude_reg)) {
|
||||
auto shadow_exclude_reg = session_get_shadow_exclude_reg(ps);
|
||||
if (pixman_region32_not_empty(shadow_exclude_reg)) {
|
||||
pixman_region32_subtract(®_shadow, ®_shadow,
|
||||
&ps->shadow_exclude_reg);
|
||||
shadow_exclude_reg);
|
||||
}
|
||||
if (pixman_region32_not_empty(®_shadow_clip)) {
|
||||
pixman_region32_subtract(®_shadow, ®_shadow,
|
||||
®_shadow_clip);
|
||||
}
|
||||
|
||||
if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 &&
|
||||
w->randr_monitor < ps->monitors.count) {
|
||||
auto monitors = session_get_monitors(ps);
|
||||
if (options->crop_shadow_to_monitor && w->randr_monitor >= 0 &&
|
||||
w->randr_monitor < monitors->count) {
|
||||
// There can be a window where number of monitors is
|
||||
// updated, but the monitor number attached to the window
|
||||
// have not.
|
||||
|
@ -334,42 +332,40 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
// Window monitor number will be updated eventually, so
|
||||
// here we just check to make sure we don't access out of
|
||||
// bounds.
|
||||
pixman_region32_intersect(
|
||||
®_shadow, ®_shadow,
|
||||
&ps->monitors.regions[w->randr_monitor]);
|
||||
pixman_region32_intersect(®_shadow, ®_shadow,
|
||||
&monitors->regions[w->randr_monitor]);
|
||||
}
|
||||
|
||||
if (ps->o.transparent_clipping) {
|
||||
if (options->transparent_clipping) {
|
||||
// ref: <transparent-clipping-note>
|
||||
pixman_region32_intersect(®_shadow, ®_shadow,
|
||||
®_visible);
|
||||
}
|
||||
|
||||
assert(w->shadow_image);
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_OPACITY, w->shadow_image,
|
||||
&w->opacity);
|
||||
backend_data->ops->set_image_property(
|
||||
backend_data, IMAGE_PROPERTY_OPACITY, w->shadow_image, &w->opacity);
|
||||
coord_t shadow_coord = {.x = w->g.x + w->shadow_dx,
|
||||
.y = w->g.y + w->shadow_dy};
|
||||
|
||||
auto inverted_mask = NULL;
|
||||
if (!ps->o.wintype_option[w->window_type].full_shadow) {
|
||||
if (!options->wintype_option[w->window_type].full_shadow) {
|
||||
pixman_region32_subtract(®_shadow, ®_shadow,
|
||||
®_bound_no_corner);
|
||||
if (w->mask_image) {
|
||||
inverted_mask = w->mask_image;
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_INVERTED,
|
||||
backend_data->ops->set_image_property(
|
||||
backend_data, IMAGE_PROPERTY_INVERTED,
|
||||
inverted_mask, (bool[]){true});
|
||||
}
|
||||
}
|
||||
ps->backend_data->ops->compose(
|
||||
ps->backend_data, w->shadow_image, shadow_coord,
|
||||
inverted_mask, window_coord, ®_shadow, ®_visible);
|
||||
backend_data->ops->compose(backend_data, w->shadow_image,
|
||||
shadow_coord, inverted_mask,
|
||||
window_coord, ®_shadow, ®_visible);
|
||||
if (inverted_mask) {
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_INVERTED,
|
||||
inverted_mask, (bool[]){false});
|
||||
backend_data->ops->set_image_property(
|
||||
backend_data, IMAGE_PROPERTY_INVERTED, inverted_mask,
|
||||
(bool[]){false});
|
||||
}
|
||||
pixman_region32_fini(®_shadow);
|
||||
}
|
||||
|
@ -378,26 +374,25 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
{
|
||||
double dim_opacity = 0.0;
|
||||
if (w->dim) {
|
||||
dim_opacity = ps->o.inactive_dim;
|
||||
if (!ps->o.inactive_dim_fixed) {
|
||||
dim_opacity = options->inactive_dim;
|
||||
if (!options->inactive_dim_fixed) {
|
||||
dim_opacity *= window_opacity;
|
||||
}
|
||||
}
|
||||
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_MAX_BRIGHTNESS, w->win_image,
|
||||
&ps->o.max_brightness);
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_INVERTED, w->win_image,
|
||||
backend_data->ops->set_image_property(
|
||||
backend_data, IMAGE_PROPERTY_MAX_BRIGHTNESS, w->win_image,
|
||||
&options->max_brightness);
|
||||
backend_data->ops->set_image_property(
|
||||
backend_data, IMAGE_PROPERTY_INVERTED, w->win_image,
|
||||
&w->invert_color);
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_DIM_LEVEL, w->win_image,
|
||||
&dim_opacity);
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_OPACITY, w->win_image,
|
||||
&window_opacity);
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_CORNER_RADIUS, w->win_image,
|
||||
backend_data->ops->set_image_property(backend_data,
|
||||
IMAGE_PROPERTY_DIM_LEVEL,
|
||||
w->win_image, &dim_opacity);
|
||||
backend_data->ops->set_image_property(
|
||||
backend_data, IMAGE_PROPERTY_OPACITY, w->win_image, &window_opacity);
|
||||
backend_data->ops->set_image_property(
|
||||
backend_data, IMAGE_PROPERTY_CORNER_RADIUS, w->win_image,
|
||||
(double[]){w->corner_radius});
|
||||
if (w->corner_radius) {
|
||||
int border_width = w->g.border_width;
|
||||
|
@ -407,13 +402,13 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
w->frame_extents.right,
|
||||
w->frame_extents.bottom);
|
||||
}
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_BORDER_WIDTH,
|
||||
backend_data->ops->set_image_property(
|
||||
backend_data, IMAGE_PROPERTY_BORDER_WIDTH,
|
||||
w->win_image, &border_width);
|
||||
}
|
||||
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_CUSTOM_SHADER, w->win_image,
|
||||
backend_data->ops->set_image_property(
|
||||
backend_data, IMAGE_PROPERTY_CUSTOM_SHADER, w->win_image,
|
||||
w->fg_shader ? (void *)w->fg_shader->backend_shader : NULL);
|
||||
}
|
||||
|
||||
|
@ -433,9 +428,9 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
|
||||
// Draw window on target
|
||||
if (w->frame_opacity == 1) {
|
||||
ps->backend_data->ops->compose(ps->backend_data, w->win_image,
|
||||
window_coord, NULL, window_coord,
|
||||
®_paint_in_bound, ®_visible);
|
||||
backend_data->ops->compose(backend_data, w->win_image,
|
||||
window_coord, NULL, window_coord,
|
||||
®_paint_in_bound, ®_visible);
|
||||
} else {
|
||||
// For window image processing, we don't have to limit the process
|
||||
// region to damage for correctness. (see <damager-note> for
|
||||
|
@ -466,17 +461,17 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
®_visible_local, ®_visible_local, ®_bound_local);
|
||||
}
|
||||
|
||||
auto new_img = ps->backend_data->ops->clone_image(
|
||||
ps->backend_data, w->win_image, ®_visible_local);
|
||||
auto new_img = backend_data->ops->clone_image(
|
||||
backend_data, w->win_image, ®_visible_local);
|
||||
auto reg_frame = win_get_region_frame_local_by_val(w);
|
||||
ps->backend_data->ops->image_op(
|
||||
ps->backend_data, IMAGE_OP_APPLY_ALPHA, new_img, ®_frame,
|
||||
®_visible_local, (double[]){w->frame_opacity});
|
||||
backend_data->ops->image_op(backend_data, IMAGE_OP_APPLY_ALPHA,
|
||||
new_img, ®_frame, ®_visible_local,
|
||||
(double[]){w->frame_opacity});
|
||||
pixman_region32_fini(®_frame);
|
||||
ps->backend_data->ops->compose(ps->backend_data, new_img,
|
||||
window_coord, NULL, window_coord,
|
||||
®_paint_in_bound, ®_visible);
|
||||
ps->backend_data->ops->release_image(ps->backend_data, new_img);
|
||||
backend_data->ops->compose(backend_data, new_img, window_coord,
|
||||
NULL, window_coord,
|
||||
®_paint_in_bound, ®_visible);
|
||||
backend_data->ops->release_image(backend_data, new_img);
|
||||
pixman_region32_fini(®_visible_local);
|
||||
pixman_region32_fini(®_bound_local);
|
||||
}
|
||||
|
@ -488,20 +483,20 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
pixman_region32_fini(®_paint);
|
||||
pixman_region32_fini(®_shadow_clip);
|
||||
|
||||
if (ps->o.monitor_repaint) {
|
||||
if (options->monitor_repaint) {
|
||||
const struct color DEBUG_COLOR = {0.5, 0, 0, 0.5};
|
||||
auto reg_damage_debug = get_damage(ps, false);
|
||||
ps->backend_data->ops->fill(ps->backend_data, DEBUG_COLOR, ®_damage_debug);
|
||||
backend_data->ops->fill(backend_data, DEBUG_COLOR, ®_damage_debug);
|
||||
pixman_region32_fini(®_damage_debug);
|
||||
}
|
||||
|
||||
// Move the head of the damage ring
|
||||
damage_ring_advance(&ps->damage_ring);
|
||||
damage_ring_advance(session_get_damage_ring(ps));
|
||||
|
||||
if (ps->backend_data->ops->present) {
|
||||
if (backend_data->ops->present) {
|
||||
// Present the rendered scene
|
||||
// Vsync is done here
|
||||
ps->backend_data->ops->present(ps->backend_data, ®_damage);
|
||||
backend_data->ops->present(backend_data, ®_damage);
|
||||
}
|
||||
|
||||
pixman_region32_fini(®_damage);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "config.h"
|
||||
#include "kernel.h"
|
||||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "utils.h"
|
||||
#include "win.h"
|
||||
#include "x.h"
|
||||
|
@ -508,8 +509,8 @@ struct backend_image *default_new_backend_image(int w, int h) {
|
|||
}
|
||||
|
||||
void init_backend_base(struct backend_base *base, session_t *ps) {
|
||||
base->c = &ps->c;
|
||||
base->loop = ps->loop;
|
||||
base->c = session_get_x_connection(ps);
|
||||
base->loop = session_get_mainloop(ps);
|
||||
base->busy = false;
|
||||
base->ops = NULL;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
/// Apply driver specified global workarounds. It's safe to call this multiple times.
|
||||
void apply_driver_workarounds(struct session *ps, enum driver driver) {
|
||||
if (driver & DRIVER_NVIDIA) {
|
||||
ps->o.xrender_sync_fence = true;
|
||||
session_get_options(ps)->xrender_sync_fence = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,9 +30,7 @@ struct dummy_data {
|
|||
|
||||
struct backend_base *dummy_init(session_t *ps attr_unused, xcb_window_t target attr_unused) {
|
||||
auto ret = (struct backend_base *)ccalloc(1, struct dummy_data);
|
||||
ret->c = &ps->c;
|
||||
ret->loop = ps->loop;
|
||||
ret->busy = false;
|
||||
init_backend_base(ret, ps);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -136,10 +136,11 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) {
|
|||
}
|
||||
|
||||
gd = ccalloc(1, struct egl_data);
|
||||
gd->display = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, ps->c.dpy,
|
||||
auto c = session_get_x_connection(ps);
|
||||
gd->display = eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_EXT, c->dpy,
|
||||
(EGLint[]){
|
||||
EGL_PLATFORM_X11_SCREEN_EXT,
|
||||
ps->c.screen,
|
||||
c->screen,
|
||||
EGL_NONE,
|
||||
});
|
||||
if (gd->display == EGL_NO_DISPLAY) {
|
||||
|
@ -172,7 +173,7 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) {
|
|||
goto end;
|
||||
}
|
||||
|
||||
auto visual_info = x_get_visual_info(&ps->c, ps->c.screen_info->root_visual);
|
||||
auto visual_info = x_get_visual_info(c, c->screen_info->root_visual);
|
||||
EGLConfig config = NULL;
|
||||
int nconfigs = 1;
|
||||
// clang-format off
|
||||
|
@ -228,7 +229,7 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) {
|
|||
gd->gl.decouple_texture_user_data = egl_decouple_user_data;
|
||||
gd->gl.release_user_data = egl_release_image;
|
||||
|
||||
if (ps->o.vsync) {
|
||||
if (session_get_options(ps)->vsync) {
|
||||
if (!egl_set_swap_interval(1, gd->display)) {
|
||||
log_error("Failed to enable vsync. %#x", eglGetError());
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "config.h"
|
||||
#include "kernel.h"
|
||||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "region.h"
|
||||
#include "string_utils.h"
|
||||
#include "types.h"
|
||||
|
@ -623,7 +624,8 @@ static bool gl_win_shader_from_stringv(const char **vshader_strv,
|
|||
|
||||
void gl_root_change(backend_t *base, session_t *ps) {
|
||||
auto gd = (struct gl_data *)base;
|
||||
gl_resize(gd, ps->root_width, ps->root_height);
|
||||
auto root_extent = session_get_root_extent(ps);
|
||||
gl_resize(gd, root_extent.width, root_extent.height);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -889,7 +891,7 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
|
|||
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
|
||||
glUseProgram(0);
|
||||
|
||||
gd->dithered_present = ps->o.dithered_present;
|
||||
gd->dithered_present = session_get_options(ps)->dithered_present;
|
||||
gd->dummy_prog =
|
||||
gl_create_program_from_strv((const char *[]){present_vertex_shader, NULL},
|
||||
(const char *[]){dummy_frag, NULL});
|
||||
|
@ -949,8 +951,9 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
|
|||
const GLint *format = gd->dithered_present ? (const GLint[]){GL_RGB16, GL_RGBA16}
|
||||
: (const GLint[]){GL_RGB8, GL_RGBA8};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
auto root_extent = session_get_root_extent(ps);
|
||||
gd->back_format = format[i];
|
||||
gl_resize(gd, ps->root_width, ps->root_height);
|
||||
gl_resize(gd, root_extent.width, root_extent.height);
|
||||
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, gd->back_texture, 0);
|
||||
|
|
|
@ -245,7 +245,8 @@ static bool glx_set_swap_interval(int interval, Display *dpy, GLXDrawable drawab
|
|||
*/
|
||||
static backend_t *glx_init(session_t *ps, xcb_window_t target) {
|
||||
bool success = false;
|
||||
glxext_init(ps->c.dpy, ps->c.screen);
|
||||
auto c = session_get_x_connection(ps);
|
||||
glxext_init(c->dpy, c->screen);
|
||||
auto gd = ccalloc(1, struct _glx_data);
|
||||
init_backend_base(&gd->gl.base, ps);
|
||||
|
||||
|
@ -254,15 +255,15 @@ static backend_t *glx_init(session_t *ps, xcb_window_t target) {
|
|||
XVisualInfo *pvis = NULL;
|
||||
|
||||
// Check for GLX extension
|
||||
if (!ps->glx_exists) {
|
||||
if (!session_has_glx_extension(ps)) {
|
||||
log_error("No GLX extension.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Get XVisualInfo
|
||||
int nitems = 0;
|
||||
XVisualInfo vreq = {.visualid = ps->c.screen_info->root_visual};
|
||||
pvis = XGetVisualInfo(ps->c.dpy, VisualIDMask, &vreq, &nitems);
|
||||
XVisualInfo vreq = {.visualid = c->screen_info->root_visual};
|
||||
pvis = XGetVisualInfo(c->dpy, VisualIDMask, &vreq, &nitems);
|
||||
if (!pvis) {
|
||||
log_error("Failed to acquire XVisualInfo for current visual.");
|
||||
goto end;
|
||||
|
@ -270,22 +271,22 @@ static backend_t *glx_init(session_t *ps, xcb_window_t target) {
|
|||
|
||||
// Ensure the visual is double-buffered
|
||||
int value = 0;
|
||||
if (glXGetConfig(ps->c.dpy, pvis, GLX_USE_GL, &value) || !value) {
|
||||
if (glXGetConfig(c->dpy, pvis, GLX_USE_GL, &value) || !value) {
|
||||
log_error("Root visual is not a GL visual.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (glXGetConfig(ps->c.dpy, pvis, GLX_STENCIL_SIZE, &value) || !value) {
|
||||
if (glXGetConfig(c->dpy, pvis, GLX_STENCIL_SIZE, &value) || !value) {
|
||||
log_error("Root visual lacks stencil buffer.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (glXGetConfig(ps->c.dpy, pvis, GLX_DOUBLEBUFFER, &value) || !value) {
|
||||
if (glXGetConfig(c->dpy, pvis, GLX_DOUBLEBUFFER, &value) || !value) {
|
||||
log_error("Root visual is not a double buffered GL visual.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (glXGetConfig(ps->c.dpy, pvis, GLX_RGBA, &value) || !value) {
|
||||
if (glXGetConfig(c->dpy, pvis, GLX_RGBA, &value) || !value) {
|
||||
log_error("Root visual is a color index visual, not supported");
|
||||
goto end;
|
||||
}
|
||||
|
@ -303,11 +304,11 @@ static backend_t *glx_init(session_t *ps, xcb_window_t target) {
|
|||
// Find a fbconfig with visualid matching the one from the target win, so we can
|
||||
// be sure that the fbconfig is compatible with our target window.
|
||||
int ncfgs;
|
||||
GLXFBConfig *cfg = glXGetFBConfigs(ps->c.dpy, ps->c.screen, &ncfgs);
|
||||
GLXFBConfig *cfg = glXGetFBConfigs(c->dpy, c->screen, &ncfgs);
|
||||
bool found = false;
|
||||
for (int i = 0; i < ncfgs; i++) {
|
||||
int visualid;
|
||||
glXGetFBConfigAttribChecked(ps->c.dpy, cfg[i], GLX_VISUAL_ID, &visualid);
|
||||
glXGetFBConfigAttribChecked(c->dpy, cfg[i], GLX_VISUAL_ID, &visualid);
|
||||
if ((VisualID)visualid != pvis->visualid) {
|
||||
continue;
|
||||
}
|
||||
|
@ -326,7 +327,7 @@ static backend_t *glx_init(session_t *ps, xcb_window_t target) {
|
|||
attributes[7] = GLX_LOSE_CONTEXT_ON_RESET_ARB;
|
||||
}
|
||||
|
||||
gd->ctx = glXCreateContextAttribsARB(ps->c.dpy, cfg[i], 0, true, attributes);
|
||||
gd->ctx = glXCreateContextAttribsARB(c->dpy, cfg[i], 0, true, attributes);
|
||||
free(cfg);
|
||||
|
||||
if (!gd->ctx) {
|
||||
|
@ -344,7 +345,7 @@ static backend_t *glx_init(session_t *ps, xcb_window_t target) {
|
|||
|
||||
// Attach GLX context
|
||||
GLXDrawable tgt = gd->target_win;
|
||||
if (!glXMakeCurrent(ps->c.dpy, tgt, gd->ctx)) {
|
||||
if (!glXMakeCurrent(c->dpy, tgt, gd->ctx)) {
|
||||
log_error("Failed to attach GLX context.");
|
||||
goto end;
|
||||
}
|
||||
|
@ -357,12 +358,12 @@ static backend_t *glx_init(session_t *ps, xcb_window_t target) {
|
|||
gd->gl.decouple_texture_user_data = glx_decouple_user_data;
|
||||
gd->gl.release_user_data = glx_release_image;
|
||||
|
||||
if (ps->o.vsync) {
|
||||
if (!glx_set_swap_interval(1, ps->c.dpy, tgt)) {
|
||||
if (session_get_options(ps)->vsync) {
|
||||
if (!glx_set_swap_interval(1, c->dpy, tgt)) {
|
||||
log_error("Failed to enable vsync.");
|
||||
}
|
||||
} else {
|
||||
glx_set_swap_interval(0, ps->c.dpy, tgt);
|
||||
glx_set_swap_interval(0, c->dpy, tgt);
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
|
|
@ -893,7 +893,9 @@ static void xrender_get_blur_size(void *blur_context, int *width, int *height) {
|
|||
}
|
||||
|
||||
static backend_t *xrender_init(session_t *ps, xcb_window_t target) {
|
||||
if (ps->o.dithered_present) {
|
||||
auto c = session_get_x_connection(ps);
|
||||
auto options = session_get_options(ps);
|
||||
if (options->dithered_present) {
|
||||
log_warn("\"dithered-present\" is not supported by the xrender backend.");
|
||||
}
|
||||
|
||||
|
@ -902,30 +904,29 @@ static backend_t *xrender_init(session_t *ps, xcb_window_t target) {
|
|||
|
||||
for (int i = 0; i <= MAX_ALPHA; ++i) {
|
||||
double o = (double)i / (double)MAX_ALPHA;
|
||||
xd->alpha_pict[i] = solid_picture(&ps->c, false, o, 0, 0, 0);
|
||||
xd->alpha_pict[i] = solid_picture(c, false, o, 0, 0, 0);
|
||||
assert(xd->alpha_pict[i] != XCB_NONE);
|
||||
}
|
||||
|
||||
xd->target_width = ps->root_width;
|
||||
xd->target_height = ps->root_height;
|
||||
xd->black_pixel = solid_picture(&ps->c, true, 1, 0, 0, 0);
|
||||
xd->white_pixel = solid_picture(&ps->c, true, 1, 1, 1, 1);
|
||||
auto root_extent = session_get_root_extent(ps);
|
||||
xd->target_width = root_extent.width;
|
||||
xd->target_height = root_extent.height;
|
||||
xd->black_pixel = solid_picture(c, true, 1, 0, 0, 0);
|
||||
xd->white_pixel = solid_picture(c, true, 1, 1, 1, 1);
|
||||
|
||||
xd->target_win = target;
|
||||
xcb_render_create_picture_value_list_t pa = {
|
||||
.subwindowmode = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS,
|
||||
};
|
||||
xd->target = x_create_picture_with_visual_and_pixmap(
|
||||
&ps->c, ps->c.screen_info->root_visual, xd->target_win,
|
||||
XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
|
||||
c, c->screen_info->root_visual, xd->target_win, XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
|
||||
|
||||
xd->vsync = ps->o.vsync;
|
||||
if (ps->present_exists) {
|
||||
auto eid = x_new_id(&ps->c);
|
||||
auto e =
|
||||
xcb_request_check(ps->c.c, xcb_present_select_input_checked(
|
||||
ps->c.c, eid, xd->target_win,
|
||||
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY));
|
||||
xd->vsync = options->vsync;
|
||||
if (session_has_present_extension(ps)) {
|
||||
auto eid = x_new_id(c);
|
||||
auto e = xcb_request_check(c->c, xcb_present_select_input_checked(
|
||||
c->c, eid, xd->target_win,
|
||||
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY));
|
||||
if (e) {
|
||||
log_error("Cannot select present input, vsync will be disabled");
|
||||
xd->vsync = false;
|
||||
|
@ -933,7 +934,7 @@ static backend_t *xrender_init(session_t *ps, xcb_window_t target) {
|
|||
}
|
||||
|
||||
xd->present_event =
|
||||
xcb_register_for_special_xge(ps->c.c, &xcb_present_id, eid, NULL);
|
||||
xcb_register_for_special_xge(c->c, &xcb_present_id, eid, NULL);
|
||||
if (!xd->present_event) {
|
||||
log_error("Cannot register for special XGE, vsync will be "
|
||||
"disabled");
|
||||
|
@ -944,22 +945,22 @@ static backend_t *xrender_init(session_t *ps, xcb_window_t target) {
|
|||
}
|
||||
|
||||
if (xd->vsync) {
|
||||
xd->present_region = x_create_region(&ps->c, &ps->screen_reg);
|
||||
xd->present_region = x_create_region(c, session_get_screen_reg(ps));
|
||||
}
|
||||
|
||||
// We might need to do double buffering for vsync, and buffer 0 and 1 are for
|
||||
// double buffering.
|
||||
int first_buffer_index = xd->vsync ? 0 : 2;
|
||||
for (int i = first_buffer_index; i < 3; i++) {
|
||||
xd->back_pixmap[i] = x_create_pixmap(&ps->c, ps->c.screen_info->root_depth,
|
||||
to_u16_checked(ps->root_width),
|
||||
to_u16_checked(ps->root_height));
|
||||
xd->back_pixmap[i] = x_create_pixmap(c, c->screen_info->root_depth,
|
||||
to_u16_checked(root_extent.width),
|
||||
to_u16_checked(root_extent.height));
|
||||
const uint32_t pic_attrs_mask = XCB_RENDER_CP_REPEAT;
|
||||
const xcb_render_create_picture_value_list_t pic_attrs = {
|
||||
.repeat = XCB_RENDER_REPEAT_PAD};
|
||||
xd->back[i] = x_create_picture_with_visual_and_pixmap(
|
||||
&ps->c, ps->c.screen_info->root_visual, xd->back_pixmap[i],
|
||||
pic_attrs_mask, &pic_attrs);
|
||||
c, c->screen_info->root_visual, xd->back_pixmap[i], pic_attrs_mask,
|
||||
&pic_attrs);
|
||||
xd->buffer_age[i] = -1;
|
||||
if (xd->back_pixmap[i] == XCB_NONE || xd->back[i] == XCB_NONE) {
|
||||
log_error("Cannot create pixmap for rendering");
|
||||
|
|
257
src/common.h
257
src/common.h
|
@ -145,249 +145,7 @@ struct damage_ring {
|
|||
/// Number of damage regions we track
|
||||
int count;
|
||||
};
|
||||
|
||||
/// 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;
|
||||
/// Use an ev_timer callback for drawing
|
||||
ev_timer draw_timer;
|
||||
/// Called every time 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 related ===
|
||||
/// 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;
|
||||
/// Shaders
|
||||
struct shader_info *shaders;
|
||||
|
||||
// === Display related ===
|
||||
/// X connection
|
||||
struct x_connection c;
|
||||
/// Whether the X server is grabbed by us
|
||||
bool server_grabbed;
|
||||
/// Width of root window.
|
||||
int root_width;
|
||||
/// Height of root window.
|
||||
int root_height;
|
||||
/// X Composite overlay window.
|
||||
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
|
||||
image_handle 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;
|
||||
/// Whether screen has been turned off
|
||||
bool screen_is_off;
|
||||
/// When last MSC event happened, in useconds.
|
||||
uint64_t last_msc_instant;
|
||||
/// The last MSC number
|
||||
uint64_t last_msc;
|
||||
/// The delay between when the last frame was scheduled to be rendered, and when
|
||||
/// the render actually started.
|
||||
uint64_t last_schedule_delay;
|
||||
/// When do we want our next frame to start rendering.
|
||||
uint64_t next_render;
|
||||
/// Whether we can perform frame pacing.
|
||||
bool frame_pacing;
|
||||
/// Vblank event scheduler
|
||||
struct vblank_scheduler *vblank_scheduler;
|
||||
|
||||
/// Render statistics
|
||||
struct render_statistics render_stats;
|
||||
|
||||
// === Operation related ===
|
||||
/// Flags related to the root window
|
||||
uint64_t root_flags;
|
||||
/// Program options.
|
||||
options_t o;
|
||||
/// State object for c2.
|
||||
struct c2_state *c2_state;
|
||||
/// Whether we have hit unredirection timeout.
|
||||
bool tmout_unredir_hit;
|
||||
/// If the backend is busy. This means two things:
|
||||
/// Either the backend is currently rendering a frame, or a frame has been
|
||||
/// rendered but has yet to be presented. In either case, we should not start
|
||||
/// another render right now. As if we start issuing rendering commands now, we
|
||||
/// will have to wait for either the current render to finish, or the current
|
||||
/// back buffer to become available again. In either case, we will be wasting
|
||||
/// time.
|
||||
bool backend_busy;
|
||||
/// Whether a render is queued. This generally means there are pending updates
|
||||
/// to the screen that's neither included in the current render, nor on the
|
||||
/// screen.
|
||||
bool render_queued;
|
||||
/// For tracking damage regions
|
||||
struct damage_ring damage_ring;
|
||||
/// 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 long fade_time;
|
||||
// Cached blur convolution kernels.
|
||||
struct x_convolution_kernel **blur_kerns_cache;
|
||||
/// If we should quit
|
||||
bool quit : 1;
|
||||
// TODO(yshui) use separate flags for different 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;
|
||||
/// Backend shadow context.
|
||||
struct backend_shadow_context *shadow_context;
|
||||
// for shadow precomputation
|
||||
/// A region in which shadow is not painted on.
|
||||
region_t shadow_exclude_reg;
|
||||
|
||||
// === Software-optimization-related ===
|
||||
/// 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 DPMS extension exists
|
||||
bool dpms_exists;
|
||||
/// 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;
|
||||
/// Information about monitors.
|
||||
struct x_monitors monitors;
|
||||
/// 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;
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// === DBus related ===
|
||||
struct cdbus_data *dbus_data;
|
||||
#endif
|
||||
|
||||
int (*vsync_wait)(session_t *);
|
||||
} session_t;
|
||||
struct session;
|
||||
|
||||
/// Enumeration for window event hints.
|
||||
typedef enum { WIN_EVMODE_UNKNOWN, WIN_EVMODE_FRAME, WIN_EVMODE_CLIENT } win_evmode_t;
|
||||
|
@ -461,18 +219,13 @@ static inline struct timespec get_time_timespec(void) {
|
|||
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->c.screen_info->root;
|
||||
}
|
||||
|
||||
struct options *session_get_options(session_t *ps);
|
||||
/**
|
||||
* 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;
|
||||
auto backend = session_get_options(ps)->backend;
|
||||
return backend == BKEND_GLX || backend == BKEND_XR_GLX_HYBRID;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -520,7 +273,7 @@ static inline void damage_ring_advance(struct damage_ring *ring) {
|
|||
pixman_region32_clear(&ring->damages[ring->cursor]);
|
||||
}
|
||||
|
||||
static inline void damage_ring_collect(struct damage_ring *ring, region_t *all_region,
|
||||
static inline void damage_ring_collect(const struct damage_ring *ring, region_t *all_region,
|
||||
region_t *region, int buffer_age) {
|
||||
if (buffer_age == -1 || buffer_age > ring->count) {
|
||||
pixman_region32_copy(region, all_region);
|
||||
|
|
11
src/config.c
11
src/config.c
|
@ -25,6 +25,7 @@
|
|||
#include "compiler.h"
|
||||
#include "kernel.h"
|
||||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "region.h"
|
||||
#include "string_utils.h"
|
||||
#include "types.h"
|
||||
|
@ -420,12 +421,14 @@ bool parse_geometry(session_t *ps, const char *src, region_t *dest) {
|
|||
if (!src) {
|
||||
return true;
|
||||
}
|
||||
if (!ps->root_width || !ps->root_height) {
|
||||
|
||||
auto root_extent = session_get_root_extent(ps);
|
||||
if (!root_extent.width || !root_extent.height) {
|
||||
return true;
|
||||
}
|
||||
|
||||
long x = 0, y = 0;
|
||||
long width = ps->root_width, height = ps->root_height;
|
||||
long width = root_extent.width, height = root_extent.height;
|
||||
long val = 0L;
|
||||
char *endptr = NULL;
|
||||
|
||||
|
@ -472,7 +475,7 @@ bool parse_geometry(session_t *ps, const char *src, region_t *dest) {
|
|||
if (endptr && src != endptr) {
|
||||
x = val;
|
||||
if (*src == '-') {
|
||||
x += ps->root_width - width;
|
||||
x += root_extent.width - width;
|
||||
}
|
||||
src = endptr;
|
||||
}
|
||||
|
@ -485,7 +488,7 @@ bool parse_geometry(session_t *ps, const char *src, region_t *dest) {
|
|||
if (endptr && src != endptr) {
|
||||
y = val;
|
||||
if (*src == '-') {
|
||||
y += ps->root_height - height;
|
||||
y += root_extent.height - height;
|
||||
}
|
||||
src = endptr;
|
||||
}
|
||||
|
|
165
src/dbus.c
165
src/dbus.c
|
@ -24,12 +24,11 @@
|
|||
#include "config.h"
|
||||
#include "dbus/dbus-protocol.h"
|
||||
#include "dbus/dbus-shared.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "string_utils.h"
|
||||
#include "transition.h"
|
||||
#include "types.h"
|
||||
#include "uthash_extra.h"
|
||||
#include "utils.h"
|
||||
#include "win.h"
|
||||
#include "win_defs.h"
|
||||
|
@ -163,7 +162,7 @@ struct cdbus_data *cdbus_init(session_t *ps, const char *uniq) {
|
|||
}
|
||||
|
||||
// Add watch handlers
|
||||
cd->loop = ps->loop;
|
||||
cd->loop = session_get_mainloop(ps);
|
||||
if (!dbus_connection_set_watch_functions(cd->dbus_conn, cdbus_callback_add_watch,
|
||||
cdbus_callback_remove_watch,
|
||||
cdbus_callback_watch_toggled, cd, NULL)) {
|
||||
|
@ -472,41 +471,45 @@ static bool cdbus_append_string_variant(DBusMessage *msg, const char *data) {
|
|||
return true;
|
||||
}
|
||||
|
||||
struct cdbus_append_wids_data {
|
||||
DBusMessageIter iter;
|
||||
bool success;
|
||||
};
|
||||
|
||||
static void cdbus_append_wids_callback(struct win *w, void *user_data) {
|
||||
auto data = (struct cdbus_append_wids_data *)user_data;
|
||||
assert(!w->destroyed);
|
||||
if (data->success) {
|
||||
data->success =
|
||||
dbus_message_iter_append_basic(&data->iter, CDBUS_TYPE_WINDOW, &w->id);
|
||||
}
|
||||
}
|
||||
|
||||
/// Append all window IDs in the window list of a session to a D-Bus message
|
||||
static bool cdbus_append_wids(DBusMessage *msg, session_t *ps) {
|
||||
// Get the number of wids we are to include
|
||||
unsigned count = 0;
|
||||
HASH_ITER2(ps->windows, w) {
|
||||
assert(!w->destroyed);
|
||||
++count;
|
||||
}
|
||||
|
||||
auto count = session_get_window_count(ps);
|
||||
if (!count) {
|
||||
// Nothing to append
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allocate memory for an array of window IDs
|
||||
auto arr = ccalloc(count, cdbus_window_t);
|
||||
|
||||
// Build the array
|
||||
cdbus_window_t *pcur = arr;
|
||||
HASH_ITER2(ps->windows, w) {
|
||||
assert(!w->destroyed);
|
||||
*pcur = w->id;
|
||||
++pcur;
|
||||
}
|
||||
assert(pcur == arr + count);
|
||||
|
||||
// Append arguments
|
||||
if (!dbus_message_append_args(msg, DBUS_TYPE_ARRAY, CDBUS_TYPE_WINDOW, &arr,
|
||||
count, DBUS_TYPE_INVALID)) {
|
||||
DBusMessageIter iter;
|
||||
struct cdbus_append_wids_data callback_data = {.success = true};
|
||||
dbus_message_iter_init_append(msg, &iter);
|
||||
if (!dbus_message_iter_open_container(
|
||||
&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32_AS_STRING, &callback_data.iter)) {
|
||||
log_error("Failed to append argument.");
|
||||
free(arr);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(arr);
|
||||
session_foreach_win(ps, cdbus_append_wids_callback, &callback_data);
|
||||
if (callback_data.success) {
|
||||
callback_data.success =
|
||||
dbus_message_iter_close_container(&iter, &callback_data.iter);
|
||||
}
|
||||
if (!callback_data.success) {
|
||||
log_error("Failed to append argument.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -615,12 +618,8 @@ cdbus_process_window_property_get(session_t *ps, DBusMessage *msg, cdbus_window_
|
|||
append_win_property(Name, name, string_variant);
|
||||
|
||||
if (!strcmp("Next", target)) {
|
||||
cdbus_window_t next_id = 0;
|
||||
if (!list_node_is_last(&ps->window_stack, &w->base.stack_neighbour)) {
|
||||
next_id = list_entry(w->base.stack_neighbour.next, struct win,
|
||||
stack_neighbour)
|
||||
->id;
|
||||
}
|
||||
auto next_win = session_get_next_win_in_stack(ps, &w->base);
|
||||
cdbus_window_t next_id = next_win ? next_win->id : XCB_NONE;
|
||||
if (!cdbus_append_wid_variant(reply, next_id)) {
|
||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||
}
|
||||
|
@ -640,7 +639,7 @@ static DBusHandlerResult cdbus_process_reset(session_t *ps, DBusMessage *msg att
|
|||
DBusMessage *reply, DBusError *e attr_unused) {
|
||||
// Reset the compositor
|
||||
log_info("picom is resetting...");
|
||||
ev_break(ps->loop, EVBREAK_ALL);
|
||||
ev_break(session_get_mainloop(ps), EVBREAK_ALL);
|
||||
if (reply != NULL && !cdbus_append_boolean(reply, true)) {
|
||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||
}
|
||||
|
@ -694,11 +693,8 @@ cdbus_process_win_get(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBusE
|
|||
#define append_win_property(tgt, type) append(tgt, type, w->tgt)
|
||||
|
||||
if (!strcmp("next", target)) {
|
||||
xcb_window_t next_id =
|
||||
list_node_is_last(&ps->window_stack, &w->base.stack_neighbour)
|
||||
? 0
|
||||
: list_entry(w->base.stack_neighbour.next, struct win, stack_neighbour)
|
||||
->id;
|
||||
auto next_win = session_get_next_win_in_stack(ps, &w->base);
|
||||
xcb_window_t next_id = next_win ? next_win->id : XCB_NONE;
|
||||
if (!cdbus_append_wid(reply, next_id)) {
|
||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||
}
|
||||
|
@ -818,14 +814,15 @@ cdbus_process_find_win(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
|
|||
dbus_set_error_const(err, DBUS_ERROR_INVALID_ARGS, NULL);
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
auto w = find_toplevel(ps, client);
|
||||
auto w = session_find_toplevel(ps, client);
|
||||
if (w) {
|
||||
wid = w->base.id;
|
||||
}
|
||||
} else if (!strcmp("focused", target)) {
|
||||
// Find focused window
|
||||
if (ps->active_win && ps->active_win->state != WSTATE_UNMAPPED) {
|
||||
wid = ps->active_win->base.id;
|
||||
auto active_win = session_get_active_win(ps);
|
||||
if (active_win && active_win->state != WSTATE_UNMAPPED) {
|
||||
wid = active_win->base.id;
|
||||
}
|
||||
} else {
|
||||
log_debug(CDBUS_ERROR_BADTGT_S, target);
|
||||
|
@ -853,7 +850,6 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
|
|||
dbus_set_error_const(err, DBUS_ERROR_INVALID_ARGS, NULL);
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
assert(ps->o.backend < sizeof(BACKEND_STRS) / sizeof(BACKEND_STRS[0]));
|
||||
|
||||
#define append(tgt, type, ret) \
|
||||
if (!strcmp(#tgt, target)) { \
|
||||
|
@ -862,20 +858,21 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
|
|||
} \
|
||||
return DBUS_HANDLER_RESULT_HANDLED; \
|
||||
}
|
||||
#define append_session_option(tgt, type) append(tgt, type, ps->o.tgt)
|
||||
#define append_session_option(tgt, type) append(tgt, type, options->tgt)
|
||||
|
||||
auto options = session_get_options(ps);
|
||||
assert(options->backend < sizeof(BACKEND_STRS) / sizeof(BACKEND_STRS[0]));
|
||||
|
||||
append(version, string, PICOM_VERSION);
|
||||
append(pid, int32, getpid());
|
||||
append(display, string, DisplayString(ps->c.dpy));
|
||||
append(display, string, DisplayString(session_get_x_connection(ps)->dpy));
|
||||
append(config_file, string, "Unknown");
|
||||
append(paint_on_overlay, boolean, ps->overlay != XCB_NONE);
|
||||
append(paint_on_overlay_id, uint32, ps->overlay); // Sending ID of the X
|
||||
// composite overlay
|
||||
// window
|
||||
append(unredir_if_possible_delay, int32, (int32_t)ps->o.unredir_if_possible_delay);
|
||||
append(paint_on_overlay, boolean, session_get_overlay(ps) != XCB_NONE);
|
||||
append(paint_on_overlay_id, uint32, session_get_overlay(ps));
|
||||
append(unredir_if_possible_delay, int32, (int32_t)options->unredir_if_possible_delay);
|
||||
append(refresh_rate, int32, 0);
|
||||
append(sw_opti, boolean, false);
|
||||
append(backend, string, BACKEND_STRS[ps->o.backend]);
|
||||
append(backend, string, BACKEND_STRS[options->backend]);
|
||||
|
||||
append_session_option(unredir_if_possible, boolean);
|
||||
append_session_option(write_pid_path, string);
|
||||
|
@ -928,9 +925,6 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
|
|||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
// XXX Remove this after header clean up
|
||||
void queue_redraw(session_t *ps);
|
||||
|
||||
/**
|
||||
* Process a opts_set D-Bus request.
|
||||
*/
|
||||
|
@ -953,7 +947,7 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
|
|||
if (strcmp(#tgt, target) == 0) { \
|
||||
type val; \
|
||||
get_msg_arg(dbus_type, val); \
|
||||
ps->o.tgt = expr; \
|
||||
options->tgt = expr; \
|
||||
goto cdbus_process_opts_set_success; \
|
||||
}
|
||||
|
||||
|
@ -961,6 +955,7 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
|
|||
goto cdbus_process_opts_set_success;
|
||||
}
|
||||
|
||||
auto options = session_get_options(ps);
|
||||
opts_set_do(fade_delta, INT32, int32_t, max2(val, 1));
|
||||
opts_set_do(fade_in_step, DOUBLE, double, normalize_d(val));
|
||||
opts_set_do(fade_out_step, DOUBLE, double, normalize_d(val));
|
||||
|
@ -970,8 +965,8 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
|
|||
if (!strcmp("unredir_if_possible", target)) {
|
||||
dbus_bool_t val = FALSE;
|
||||
get_msg_arg(BOOLEAN, val);
|
||||
if (ps->o.unredir_if_possible != val) {
|
||||
ps->o.unredir_if_possible = val;
|
||||
if (options->unredir_if_possible != val) {
|
||||
options->unredir_if_possible = val;
|
||||
queue_redraw(ps);
|
||||
}
|
||||
goto cdbus_process_opts_set_success;
|
||||
|
@ -980,8 +975,8 @@ cdbus_process_opts_set(session_t *ps, DBusMessage *msg, DBusMessage *reply, DBus
|
|||
if (!strcmp("redirected_force", target)) {
|
||||
cdbus_enum_t val = UNSET;
|
||||
get_msg_arg(UINT32, val);
|
||||
if (ps->o.redirected_force != val) {
|
||||
ps->o.redirected_force = val;
|
||||
if (options->redirected_force != val) {
|
||||
options->redirected_force = val;
|
||||
force_repaint(ps);
|
||||
}
|
||||
goto cdbus_process_opts_set_success;
|
||||
|
@ -1068,6 +1063,24 @@ static DBusHandlerResult cdbus_process_introspect(DBusMessage *reply) {
|
|||
}
|
||||
///@}
|
||||
|
||||
struct cdbus_window_root_introspect_data {
|
||||
char *introspect;
|
||||
bool success;
|
||||
};
|
||||
static void cdbus_window_root_introspect_callback(struct win *w, void *user_data) {
|
||||
auto data = (struct cdbus_window_root_introspect_data *)user_data;
|
||||
assert(!w->destroyed);
|
||||
if (data->success) {
|
||||
char *tmp = NULL;
|
||||
if (asprintf(&tmp, "<node name='%#010x'/>\n", w->id) < 0) {
|
||||
log_fatal("Failed to allocate memory.");
|
||||
data->success = false;
|
||||
return;
|
||||
}
|
||||
mstrextend(&data->introspect, tmp);
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Process an D-Bus Introspect request, for /windows.
|
||||
*/
|
||||
|
@ -1088,31 +1101,19 @@ cdbus_process_windows_root_introspect(session_t *ps, DBusMessage *reply) {
|
|||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
char *ret = NULL;
|
||||
bool success = true;
|
||||
mstrextend(&ret, str_introspect);
|
||||
struct cdbus_window_root_introspect_data callback_data = {.introspect = NULL,
|
||||
.success = true};
|
||||
mstrextend(&callback_data.introspect, str_introspect);
|
||||
session_foreach_win(ps, cdbus_window_root_introspect_callback, &callback_data);
|
||||
mstrextend(&callback_data.introspect, "</node>");
|
||||
|
||||
HASH_ITER2(ps->windows, w) {
|
||||
assert(!w->destroyed);
|
||||
if (!w->managed) {
|
||||
continue;
|
||||
}
|
||||
char *tmp = NULL;
|
||||
if (asprintf(&tmp, "<node name='%#010x'/>\n", w->id) < 0) {
|
||||
log_fatal("Failed to allocate memory.");
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
mstrextend(&ret, tmp);
|
||||
free(tmp);
|
||||
if (callback_data.success) {
|
||||
callback_data.success = cdbus_append_string(reply, callback_data.introspect);
|
||||
}
|
||||
mstrextend(&ret, "</node>");
|
||||
|
||||
if (success) {
|
||||
success = cdbus_append_string(reply, ret);
|
||||
}
|
||||
free(ret);
|
||||
return success ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||
free(callback_data.introspect);
|
||||
return callback_data.success ? DBUS_HANDLER_RESULT_HANDLED
|
||||
: DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||
}
|
||||
|
||||
static bool cdbus_process_window_introspect(DBusMessage *reply) {
|
||||
|
|
|
@ -15,12 +15,12 @@ void print_diagnostics(session_t *ps, const char *config_file, bool compositor_r
|
|||
printf("**Version:** " PICOM_VERSION "\n");
|
||||
// printf("**CFLAGS:** %s\n", "??");
|
||||
printf("\n### Extensions:\n\n");
|
||||
printf("* Shape: %s\n", ps->shape_exists ? "Yes" : "No");
|
||||
printf("* RandR: %s\n", ps->randr_exists ? "Yes" : "No");
|
||||
printf("* Present: %s\n", ps->present_exists ? "Present" : "Not Present");
|
||||
printf("* Shape: %s\n", session_has_shape_extension(ps) ? "Yes" : "No");
|
||||
printf("* RandR: %s\n", session_has_randr_extension(ps) ? "Yes" : "No");
|
||||
printf("* Present: %s\n", session_has_present_extension(ps) ? "Present" : "Not Present");
|
||||
printf("\n### Misc:\n\n");
|
||||
printf("* Use Overlay: %s\n", ps->overlay != XCB_NONE ? "Yes" : "No");
|
||||
if (ps->overlay == XCB_NONE) {
|
||||
printf("* Use Overlay: %s\n", session_get_overlay(ps) != XCB_NONE ? "Yes" : "No");
|
||||
if (session_get_overlay(ps) == XCB_NONE) {
|
||||
if (compositor_running) {
|
||||
printf(" (Another compositor is already running)\n");
|
||||
} else if (session_redirection_mode(ps) != XCB_COMPOSITE_REDIRECT_MANUAL) {
|
||||
|
@ -34,7 +34,7 @@ void print_diagnostics(session_t *ps, const char *config_file, bool compositor_r
|
|||
#endif
|
||||
printf("* Config file used: %s\n", config_file ?: "None");
|
||||
printf("\n### Drivers (inaccurate):\n\n");
|
||||
print_drivers(ps->drivers);
|
||||
print_drivers(session_get_driver(ps));
|
||||
|
||||
for (int i = 0; i < NUM_BKEND; i++) {
|
||||
if (backend_list[i] && backend_list[i]->diagnostics) {
|
||||
|
|
243
src/event.c
243
src/event.c
|
@ -23,6 +23,7 @@
|
|||
#include "win.h"
|
||||
#include "win_defs.h"
|
||||
#include "x.h"
|
||||
#include "xcb/xfixes.h"
|
||||
|
||||
/// Event handling with X is complicated. Handling events with other events possibly
|
||||
/// in-flight is no good. Because your internal state won't be up to date. Also, querying
|
||||
|
@ -66,14 +67,14 @@ static inline const char *ev_window_name(session_t *ps, xcb_window_t wid) {
|
|||
char *name = "";
|
||||
if (wid) {
|
||||
name = "(Failed to get title)";
|
||||
if (ps->c.screen_info->root == wid) {
|
||||
if (session_get_x_connection(ps)->screen_info->root == wid) {
|
||||
name = "(Root window)";
|
||||
} else if (ps->overlay == wid) {
|
||||
} else if (session_get_overlay(ps) == wid) {
|
||||
name = "(Overlay)";
|
||||
} else {
|
||||
auto w = find_managed_win(ps, wid);
|
||||
if (!w) {
|
||||
w = find_toplevel(ps, wid);
|
||||
w = session_find_toplevel(ps, wid);
|
||||
}
|
||||
|
||||
if (w && w->name) {
|
||||
|
@ -99,11 +100,13 @@ static inline xcb_window_t attr_pure ev_window(session_t *ps, xcb_generic_event_
|
|||
case PropertyNotify: return ((xcb_property_notify_event_t *)ev)->window;
|
||||
case ClientMessage: return ((xcb_client_message_event_t *)ev)->window;
|
||||
default:
|
||||
if (ps->damage_event + XCB_DAMAGE_NOTIFY == ev->response_type) {
|
||||
if (session_get_damage_extention_event(ps) + XCB_DAMAGE_NOTIFY ==
|
||||
ev->response_type) {
|
||||
return ((xcb_damage_notify_event_t *)ev)->drawable;
|
||||
}
|
||||
|
||||
if (ps->shape_exists && ev->response_type == ps->shape_event) {
|
||||
if (session_has_shape_extension(ps) &&
|
||||
ev->response_type == session_get_shape_extention_event(ps)) {
|
||||
return ((xcb_shape_notify_event_t *)ev)->affected_window;
|
||||
}
|
||||
|
||||
|
@ -131,16 +134,17 @@ static inline const char *ev_name(session_t *ps, xcb_generic_event_t *ev) {
|
|||
CASESTRRET(ClientMessage);
|
||||
}
|
||||
|
||||
if (ps->damage_event + XCB_DAMAGE_NOTIFY == ev->response_type) {
|
||||
if (session_get_damage_extention_event(ps) + XCB_DAMAGE_NOTIFY == ev->response_type) {
|
||||
return "Damage";
|
||||
}
|
||||
|
||||
if (ps->shape_exists && ev->response_type == ps->shape_event) {
|
||||
if (session_has_shape_extension(ps) &&
|
||||
ev->response_type == session_get_shape_extention_event(ps)) {
|
||||
return "ShapeNotify";
|
||||
}
|
||||
|
||||
if (ps->xsync_exists) {
|
||||
int o = ev->response_type - ps->xsync_event;
|
||||
if (session_has_xsync_extension(ps)) {
|
||||
int o = ev->response_type - session_get_xsync_extention_event(ps);
|
||||
switch (o) {
|
||||
CASESTRRET(XSyncCounterNotify);
|
||||
CASESTRRET(XSyncAlarmNotify);
|
||||
|
@ -183,37 +187,37 @@ static inline const char *attr_pure ev_focus_detail_name(xcb_focus_in_event_t *e
|
|||
static inline void ev_focus_in(session_t *ps, xcb_focus_in_event_t *ev) {
|
||||
log_debug("{ mode: %s, detail: %s }\n", ev_focus_mode_name(ev),
|
||||
ev_focus_detail_name(ev));
|
||||
ps->pending_updates = true;
|
||||
session_mark_updates_pending(ps);
|
||||
}
|
||||
|
||||
static inline void ev_focus_out(session_t *ps, xcb_focus_out_event_t *ev) {
|
||||
log_debug("{ mode: %s, detail: %s }\n", ev_focus_mode_name(ev),
|
||||
ev_focus_detail_name(ev));
|
||||
ps->pending_updates = true;
|
||||
session_mark_updates_pending(ps);
|
||||
}
|
||||
|
||||
static inline void ev_create_notify(session_t *ps, xcb_create_notify_event_t *ev) {
|
||||
if (ev->parent == ps->c.screen_info->root) {
|
||||
add_win_top(ps, ev->window);
|
||||
if (ev->parent == session_get_x_connection(ps)->screen_info->root) {
|
||||
session_add_win_top(ps, ev->window);
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle configure event of a regular window
|
||||
static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
||||
auto w = find_win(ps, ce->window);
|
||||
auto w = session_find_win(ps, ce->window);
|
||||
|
||||
if (!w) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!w->managed) {
|
||||
restack_above(ps, w, ce->above_sibling);
|
||||
session_restack_above(ps, w, ce->above_sibling);
|
||||
return;
|
||||
}
|
||||
|
||||
auto mw = (struct managed_win *)w;
|
||||
|
||||
restack_above(ps, w, ce->above_sibling);
|
||||
session_restack_above(ps, w, ce->above_sibling);
|
||||
|
||||
// We check against pending_g here, because there might have been multiple
|
||||
// configure notifies in this cycle, or the window could receive multiple updates
|
||||
|
@ -227,7 +231,7 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
|||
win_set_flags(mw, WIN_FLAGS_FACTOR_CHANGED);
|
||||
// TODO(yshui) don't set pending_updates if the window is not
|
||||
// visible/mapped
|
||||
ps->pending_updates = true;
|
||||
session_mark_updates_pending(ps);
|
||||
|
||||
// At least one of the following if's is true
|
||||
if (position_changed) {
|
||||
|
@ -248,7 +252,7 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
|||
}
|
||||
|
||||
// Recalculate which monitor this window is on
|
||||
win_update_monitor(&ps->monitors, mw);
|
||||
win_update_monitor(session_get_monitors(ps), mw);
|
||||
}
|
||||
|
||||
// override_redirect flag cannot be changed after window creation, as far
|
||||
|
@ -259,7 +263,7 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
|||
static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event_t *ev) {
|
||||
log_debug("{ send_event: %d, id: %#010x, above: %#010x, override_redirect: %d }",
|
||||
ev->event, ev->window, ev->above_sibling, ev->override_redirect);
|
||||
if (ev->window == ps->c.screen_info->root) {
|
||||
if (ev->window == session_get_x_connection(ps)->screen_info->root) {
|
||||
set_root_flags(ps, ROOT_FLAGS_CONFIGURED);
|
||||
} else {
|
||||
configure_win(ps, ev);
|
||||
|
@ -267,8 +271,8 @@ static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event
|
|||
}
|
||||
|
||||
static inline void ev_destroy_notify(session_t *ps, xcb_destroy_notify_event_t *ev) {
|
||||
auto w = find_win(ps, ev->window);
|
||||
auto mw = find_toplevel(ps, ev->window);
|
||||
auto w = session_find_win(ps, ev->window);
|
||||
auto mw = session_find_toplevel(ps, ev->window);
|
||||
if (mw && mw->client_win == mw->base.id) {
|
||||
// We only want _real_ frame window
|
||||
assert(&mw->base == w);
|
||||
|
@ -291,7 +295,7 @@ static inline void ev_destroy_notify(session_t *ps, xcb_destroy_notify_event_t *
|
|||
if (mw != NULL) {
|
||||
win_unmark_client(ps, mw);
|
||||
win_set_flags(mw, WIN_FLAGS_CLIENT_STALE);
|
||||
ps->pending_updates = true;
|
||||
session_mark_updates_pending(ps);
|
||||
return;
|
||||
}
|
||||
log_debug("Received a destroy notify from an unknown window, %#010x", ev->window);
|
||||
|
@ -300,10 +304,11 @@ static inline void ev_destroy_notify(session_t *ps, xcb_destroy_notify_event_t *
|
|||
static inline void ev_map_notify(session_t *ps, xcb_map_notify_event_t *ev) {
|
||||
// Unmap overlay window if it got mapped but we are currently not
|
||||
// in redirected state.
|
||||
if (ps->overlay && ev->window == ps->overlay && !ps->redirected) {
|
||||
auto overlay = session_get_overlay(ps);
|
||||
auto c = session_get_x_connection(ps);
|
||||
if (overlay && ev->window == overlay && !session_is_redirected(ps)) {
|
||||
log_debug("Overlay is mapped while we are not redirected");
|
||||
auto e = xcb_request_check(
|
||||
ps->c.c, xcb_unmap_window_checked(ps->c.c, ps->overlay));
|
||||
auto e = xcb_request_check(c->c, xcb_unmap_window_checked(c->c, overlay));
|
||||
if (e) {
|
||||
log_error("Failed to unmap the overlay window");
|
||||
free(e);
|
||||
|
@ -328,7 +333,7 @@ static inline void ev_map_notify(session_t *ps, xcb_map_notify_event_t *ev) {
|
|||
|
||||
// FocusIn/Out may be ignored when the window is unmapped, so we must
|
||||
// recheck focus here
|
||||
ps->pending_updates = true; // to update focus
|
||||
session_mark_updates_pending(ps); // to update focus
|
||||
}
|
||||
|
||||
static inline void ev_unmap_notify(session_t *ps, xcb_unmap_notify_event_t *ev) {
|
||||
|
@ -341,30 +346,31 @@ static inline void ev_unmap_notify(session_t *ps, xcb_unmap_notify_event_t *ev)
|
|||
static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t *ev) {
|
||||
log_debug("Window %#010x has new parent: %#010x, override_redirect: %d",
|
||||
ev->window, ev->parent, ev->override_redirect);
|
||||
auto w_top = find_toplevel(ps, ev->window);
|
||||
auto w_top = session_find_toplevel(ps, ev->window);
|
||||
if (w_top) {
|
||||
win_unmark_client(ps, w_top);
|
||||
win_set_flags(w_top, WIN_FLAGS_CLIENT_STALE);
|
||||
ps->pending_updates = true;
|
||||
session_mark_updates_pending(ps);
|
||||
}
|
||||
|
||||
if (ev->parent == ps->c.screen_info->root) {
|
||||
auto c = session_get_x_connection(ps);
|
||||
if (ev->parent == c->screen_info->root) {
|
||||
// X will generate reparent notify even if the parent didn't actually
|
||||
// change (i.e. reparent again to current parent). So we check if that's
|
||||
// the case
|
||||
auto w = find_win(ps, ev->window);
|
||||
auto w = session_find_win(ps, ev->window);
|
||||
if (w) {
|
||||
// This window has already been reparented to root before,
|
||||
// so we don't need to create a new window for it, we just need to
|
||||
// move it to the top
|
||||
restack_top(ps, w);
|
||||
session_restack_top(ps, w);
|
||||
} else {
|
||||
add_win_top(ps, ev->window);
|
||||
session_add_win_top(ps, ev->window);
|
||||
}
|
||||
} else {
|
||||
// otherwise, find and destroy the window first
|
||||
{
|
||||
auto w = find_win(ps, ev->window);
|
||||
auto w = session_find_win(ps, ev->window);
|
||||
if (w) {
|
||||
if (w->managed) {
|
||||
auto mw = (struct managed_win *)w;
|
||||
|
@ -395,7 +401,8 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
|
|||
// Reset event mask in case something wrong happens
|
||||
uint32_t evmask = determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN);
|
||||
|
||||
if (!wid_has_prop(ps->c.c, ev->window, ps->atoms->aWM_STATE)) {
|
||||
auto atoms = session_get_atoms(ps);
|
||||
if (!wid_has_prop(c->c, ev->window, atoms->aWM_STATE)) {
|
||||
log_debug("Window %#010x doesn't have WM_STATE property, it is "
|
||||
"probably not a client window. But we will listen for "
|
||||
"property change in case it gains one.",
|
||||
|
@ -408,70 +415,50 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
|
|||
"client",
|
||||
w_real_top->base.id, w_real_top->name);
|
||||
win_set_flags(w_real_top, WIN_FLAGS_CLIENT_STALE);
|
||||
ps->pending_updates = true;
|
||||
session_mark_updates_pending(ps);
|
||||
} else {
|
||||
log_debug("parent %#010x not found", ev->parent);
|
||||
}
|
||||
}
|
||||
XCB_AWAIT_VOID(xcb_change_window_attributes, ps->c.c, ev->window,
|
||||
XCB_AWAIT_VOID(xcb_change_window_attributes, c->c, ev->window,
|
||||
XCB_CW_EVENT_MASK, (const uint32_t[]){evmask});
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ev_circulate_notify(session_t *ps, xcb_circulate_notify_event_t *ev) {
|
||||
auto w = find_win(ps, ev->window);
|
||||
auto w = session_find_win(ps, ev->window);
|
||||
|
||||
if (!w) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev->place == PlaceOnTop) {
|
||||
restack_top(ps, w);
|
||||
session_restack_top(ps, w);
|
||||
} else {
|
||||
restack_bottom(ps, w);
|
||||
session_restack_bottom(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void expose_root(session_t *ps, const rect_t *rects, int nrects) {
|
||||
region_t region;
|
||||
pixman_region32_init_rects(®ion, rects, nrects);
|
||||
add_damage(ps, ®ion);
|
||||
pixman_region32_fini(®ion);
|
||||
}
|
||||
|
||||
static inline void ev_expose(session_t *ps, xcb_expose_event_t *ev) {
|
||||
if (ev->window == ps->c.screen_info->root ||
|
||||
(ps->overlay && ev->window == ps->overlay)) {
|
||||
int more = ev->count + 1;
|
||||
if (ps->n_expose == ps->size_expose) {
|
||||
if (ps->expose_rects) {
|
||||
ps->expose_rects =
|
||||
crealloc(ps->expose_rects, ps->size_expose + more);
|
||||
ps->size_expose += more;
|
||||
} else {
|
||||
ps->expose_rects = ccalloc(more, rect_t);
|
||||
ps->size_expose = more;
|
||||
}
|
||||
}
|
||||
|
||||
ps->expose_rects[ps->n_expose].x1 = ev->x;
|
||||
ps->expose_rects[ps->n_expose].y1 = ev->y;
|
||||
ps->expose_rects[ps->n_expose].x2 = ev->x + ev->width;
|
||||
ps->expose_rects[ps->n_expose].y2 = ev->y + ev->height;
|
||||
ps->n_expose++;
|
||||
|
||||
if (ev->count == 0) {
|
||||
expose_root(ps, ps->expose_rects, ps->n_expose);
|
||||
ps->n_expose = 0;
|
||||
}
|
||||
auto overlay = session_get_overlay(ps);
|
||||
if (ev->window == session_get_x_connection(ps)->screen_info->root ||
|
||||
(overlay && ev->window == overlay)) {
|
||||
region_t region;
|
||||
pixman_region32_init_rect(®ion, ev->x, ev->y, ev->width, ev->height);
|
||||
add_damage(ps, ®ion);
|
||||
pixman_region32_fini(®ion);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t *ev) {
|
||||
auto options = session_get_options(ps);
|
||||
auto atoms = session_get_atoms(ps);
|
||||
auto c = session_get_x_connection(ps);
|
||||
auto c2_state = session_get_c2(ps);
|
||||
if (unlikely(log_get_level_tls() <= LOG_LEVEL_TRACE)) {
|
||||
// Print out changed atom
|
||||
xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(
|
||||
ps->c.c, xcb_get_atom_name(ps->c.c, ev->atom), NULL);
|
||||
xcb_get_atom_name_reply_t *reply =
|
||||
xcb_get_atom_name_reply(c->c, xcb_get_atom_name(c->c, ev->atom), NULL);
|
||||
const char *name = "?";
|
||||
int name_len = 1;
|
||||
if (reply) {
|
||||
|
@ -483,13 +470,13 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
free(reply);
|
||||
}
|
||||
|
||||
if (ps->c.screen_info->root == ev->window) {
|
||||
if (ps->o.use_ewmh_active_win && ps->atoms->a_NET_ACTIVE_WINDOW == ev->atom) {
|
||||
if (c->screen_info->root == ev->window) {
|
||||
if (options->use_ewmh_active_win && atoms->a_NET_ACTIVE_WINDOW == ev->atom) {
|
||||
// to update focus
|
||||
ps->pending_updates = true;
|
||||
session_mark_updates_pending(ps);
|
||||
} else {
|
||||
// Destroy the root "image" if the wallpaper probably changed
|
||||
if (x_is_root_back_pixmap_atom(ps->atoms, ev->atom)) {
|
||||
if (x_is_root_back_pixmap_atom(atoms, ev->atom)) {
|
||||
root_damaged(ps);
|
||||
}
|
||||
}
|
||||
|
@ -498,15 +485,15 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
return;
|
||||
}
|
||||
|
||||
ps->pending_updates = true;
|
||||
session_mark_updates_pending(ps);
|
||||
// If WM_STATE changes
|
||||
if (ev->atom == ps->atoms->aWM_STATE) {
|
||||
if (ev->atom == atoms->aWM_STATE) {
|
||||
// Check whether it could be a client window
|
||||
if (!find_toplevel(ps, ev->window)) {
|
||||
if (!session_find_toplevel(ps, ev->window)) {
|
||||
// Reset event mask anyway
|
||||
const uint32_t evmask =
|
||||
determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN);
|
||||
XCB_AWAIT_VOID(xcb_change_window_attributes, ps->c.c, ev->window,
|
||||
XCB_AWAIT_VOID(xcb_change_window_attributes, c->c, ev->window,
|
||||
XCB_CW_EVENT_MASK, (const uint32_t[]){evmask});
|
||||
|
||||
auto w_top = find_managed_window_or_parent(ps, ev->window);
|
||||
|
@ -521,60 +508,61 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
|
||||
// If _NET_WM_WINDOW_TYPE changes... God knows why this would happen, but
|
||||
// there are always some stupid applications. (#144)
|
||||
if (ev->atom == ps->atoms->a_NET_WM_WINDOW_TYPE) {
|
||||
struct managed_win *w = find_toplevel(ps, ev->window);
|
||||
if (ev->atom == atoms->a_NET_WM_WINDOW_TYPE) {
|
||||
struct managed_win *w = session_find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
if (ev->atom == ps->atoms->a_NET_WM_BYPASS_COMPOSITOR) {
|
||||
if (ev->atom == atoms->a_NET_WM_BYPASS_COMPOSITOR) {
|
||||
// Unnecessary until we remove the queue_redraw in ev_handle
|
||||
queue_redraw(ps);
|
||||
}
|
||||
|
||||
// If _NET_WM_WINDOW_OPACITY changes
|
||||
if (ev->atom == ps->atoms->a_NET_WM_WINDOW_OPACITY) {
|
||||
auto w = find_managed_win(ps, ev->window) ?: find_toplevel(ps, ev->window);
|
||||
if (ev->atom == atoms->a_NET_WM_WINDOW_OPACITY) {
|
||||
auto w = find_managed_win(ps, ev->window)
|
||||
?: session_find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
// If frame extents property changes
|
||||
if (ev->atom == ps->atoms->a_NET_FRAME_EXTENTS) {
|
||||
auto w = find_toplevel(ps, ev->window);
|
||||
if (ev->atom == atoms->a_NET_FRAME_EXTENTS) {
|
||||
auto w = session_find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
// If name changes
|
||||
if (ps->atoms->aWM_NAME == ev->atom || ps->atoms->a_NET_WM_NAME == ev->atom) {
|
||||
auto w = find_toplevel(ps, ev->window);
|
||||
if (atoms->aWM_NAME == ev->atom || atoms->a_NET_WM_NAME == ev->atom) {
|
||||
auto w = session_find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
// If class changes
|
||||
if (ps->atoms->aWM_CLASS == ev->atom) {
|
||||
auto w = find_toplevel(ps, ev->window);
|
||||
if (atoms->aWM_CLASS == ev->atom) {
|
||||
auto w = session_find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
// If role changes
|
||||
if (ps->atoms->aWM_WINDOW_ROLE == ev->atom) {
|
||||
auto w = find_toplevel(ps, ev->window);
|
||||
if (atoms->aWM_WINDOW_ROLE == ev->atom) {
|
||||
auto w = session_find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
// If _COMPTON_SHADOW changes
|
||||
if (ps->atoms->a_COMPTON_SHADOW == ev->atom) {
|
||||
if (atoms->a_COMPTON_SHADOW == ev->atom) {
|
||||
auto w = find_managed_win(ps, ev->window);
|
||||
if (w) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
|
@ -582,31 +570,31 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
|||
}
|
||||
|
||||
// If a leader property changes
|
||||
if ((ps->o.detect_transient && ps->atoms->aWM_TRANSIENT_FOR == ev->atom) ||
|
||||
(ps->o.detect_client_leader && ps->atoms->aWM_CLIENT_LEADER == ev->atom)) {
|
||||
auto w = find_toplevel(ps, ev->window);
|
||||
if ((options->detect_transient && atoms->aWM_TRANSIENT_FOR == ev->atom) ||
|
||||
(options->detect_client_leader && atoms->aWM_CLIENT_LEADER == ev->atom)) {
|
||||
auto w = session_find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ps->o.no_ewmh_fullscreen && ev->atom == ps->atoms->a_NET_WM_STATE) {
|
||||
auto w = find_toplevel(ps, ev->window);
|
||||
if (!options->no_ewmh_fullscreen && ev->atom == atoms->a_NET_WM_STATE) {
|
||||
auto w = session_find_toplevel(ps, ev->window);
|
||||
if (w) {
|
||||
win_set_property_stale(w, ev->atom);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for other atoms we are tracking
|
||||
if (c2_state_is_property_tracked(ps->c2_state, ev->atom)) {
|
||||
if (c2_state_is_property_tracked(c2_state, ev->atom)) {
|
||||
bool change_is_on_client = false;
|
||||
auto w = find_managed_win(ps, ev->window);
|
||||
if (!w) {
|
||||
w = find_toplevel(ps, ev->window);
|
||||
w = session_find_toplevel(ps, ev->window);
|
||||
change_is_on_client = true;
|
||||
}
|
||||
if (w) {
|
||||
c2_window_state_mark_dirty(ps->c2_state, &w->c2_state, ev->atom,
|
||||
c2_window_state_mark_dirty(c2_state, &w->c2_state, ev->atom,
|
||||
change_is_on_client);
|
||||
// Set FACTOR_CHANGED so rules based on properties will be
|
||||
// re-evaluated.
|
||||
|
@ -621,6 +609,8 @@ static inline void repair_win(session_t *ps, struct managed_win *w) {
|
|||
// Only mapped window can receive damages
|
||||
assert(w->state == WSTATE_MAPPED || win_check_flags_all(w, WIN_FLAGS_MAPPED));
|
||||
|
||||
auto options = session_get_options(ps);
|
||||
auto c = session_get_x_connection(ps);
|
||||
region_t parts;
|
||||
pixman_region32_init(&parts);
|
||||
|
||||
|
@ -632,10 +622,9 @@ static inline void repair_win(session_t *ps, struct managed_win *w) {
|
|||
// from the X server, which implies it has received our DamageSubtract request.
|
||||
if (!w->ever_damaged) {
|
||||
auto e = xcb_request_check(
|
||||
ps->c.c,
|
||||
xcb_damage_subtract_checked(ps->c.c, w->damage, XCB_NONE, XCB_NONE));
|
||||
c->c, xcb_damage_subtract_checked(c->c, w->damage, XCB_NONE, XCB_NONE));
|
||||
if (e) {
|
||||
if (ps->o.show_all_xerrors) {
|
||||
if (options->show_all_xerrors) {
|
||||
x_print_error(e->sequence, e->major_code, e->minor_code,
|
||||
e->error_code);
|
||||
}
|
||||
|
@ -645,14 +634,14 @@ static inline void repair_win(session_t *ps, struct managed_win *w) {
|
|||
|
||||
// We only binds the window pixmap once the window is damaged.
|
||||
win_set_flags(w, WIN_FLAGS_PIXMAP_STALE);
|
||||
ps->pending_updates = true;
|
||||
session_mark_updates_pending(ps);
|
||||
} else {
|
||||
auto cookie = xcb_damage_subtract(ps->c.c, w->damage, XCB_NONE,
|
||||
ps->damage_ring.x_region);
|
||||
if (!ps->o.show_all_xerrors) {
|
||||
set_ignore_cookie(&ps->c, cookie);
|
||||
xcb_xfixes_region_t damage_region = session_get_damage_ring(ps)->x_region;
|
||||
auto cookie = xcb_damage_subtract(c->c, w->damage, XCB_NONE, damage_region);
|
||||
if (!options->show_all_xerrors) {
|
||||
set_ignore_cookie(c, cookie);
|
||||
}
|
||||
x_fetch_region(&ps->c, ps->damage_ring.x_region, &parts);
|
||||
x_fetch_region(c, damage_region, &parts);
|
||||
pixman_region32_translate(&parts, w->g.x + w->g.border_width,
|
||||
w->g.y + w->g.border_width);
|
||||
}
|
||||
|
@ -663,13 +652,13 @@ static inline void repair_win(session_t *ps, struct managed_win *w) {
|
|||
|
||||
// Why care about damage when screen is unredirected?
|
||||
// We will force full-screen repaint on redirection.
|
||||
if (!ps->redirected) {
|
||||
if (!session_is_redirected(ps)) {
|
||||
pixman_region32_fini(&parts);
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the part in the damage area that could be ignored
|
||||
if (w->reg_ignore && win_is_region_ignore_valid(ps, w)) {
|
||||
if (w->reg_ignore && session_is_win_region_ignore_valid(ps, w)) {
|
||||
pixman_region32_subtract(&parts, &parts, w->reg_ignore);
|
||||
}
|
||||
|
||||
|
@ -714,7 +703,7 @@ static inline void ev_shape_notify(session_t *ps, xcb_shape_notify_event_t *ev)
|
|||
w->reg_ignore_valid = false;
|
||||
|
||||
win_set_flags(w, WIN_FLAGS_SIZE_STALE);
|
||||
ps->pending_updates = true;
|
||||
session_mark_updates_pending(ps);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -727,12 +716,13 @@ ev_selection_clear(session_t *ps, xcb_selection_clear_event_t attr_unused *ev) {
|
|||
}
|
||||
|
||||
void ev_handle(session_t *ps, xcb_generic_event_t *ev) {
|
||||
auto c = session_get_x_connection(ps);
|
||||
if (XCB_EVENT_RESPONSE_TYPE(ev) != KeymapNotify) {
|
||||
x_discard_pending(&ps->c, ev->full_sequence);
|
||||
x_discard_pending(c, ev->full_sequence);
|
||||
}
|
||||
|
||||
xcb_window_t wid = ev_window(ps, ev);
|
||||
if (ev->response_type != ps->damage_event + XCB_DAMAGE_NOTIFY) {
|
||||
if (ev->response_type != session_get_damage_extention_event(ps) + XCB_DAMAGE_NOTIFY) {
|
||||
log_debug("event %10.10s serial %#010x window %#010x \"%s\"",
|
||||
ev_name(ps, ev), ev->full_sequence, wid, ev_window_name(ps, wid));
|
||||
} else {
|
||||
|
@ -750,9 +740,9 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) {
|
|||
// https://bugs.freedesktop.org/show_bug.cgi?id=35945
|
||||
// https://lists.freedesktop.org/archives/xcb/2011-November/007337.html
|
||||
auto response_type = XCB_EVENT_RESPONSE_TYPE(ev);
|
||||
auto proc = XESetWireToEvent(ps->c.dpy, response_type, 0);
|
||||
auto proc = XESetWireToEvent(c->dpy, response_type, 0);
|
||||
if (proc) {
|
||||
XESetWireToEvent(ps->c.dpy, response_type, proc);
|
||||
XESetWireToEvent(c->dpy, response_type, proc);
|
||||
XEvent dummy;
|
||||
|
||||
// Stop Xlib from complaining about lost sequence numbers.
|
||||
|
@ -762,8 +752,8 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) {
|
|||
//
|
||||
// We only need the low 16 bits
|
||||
uint16_t seq = ev->sequence;
|
||||
ev->sequence = (uint16_t)(LastKnownRequestProcessed(ps->c.dpy) & 0xffff);
|
||||
proc(ps->c.dpy, &dummy, (xEvent *)ev);
|
||||
ev->sequence = (uint16_t)(LastKnownRequestProcessed(c->dpy) & 0xffff);
|
||||
proc(c->dpy, &dummy, (xEvent *)ev);
|
||||
// Restore the sequence number
|
||||
ev->sequence = seq;
|
||||
}
|
||||
|
@ -798,18 +788,21 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) {
|
|||
case SelectionClear:
|
||||
ev_selection_clear(ps, (xcb_selection_clear_event_t *)ev);
|
||||
break;
|
||||
case 0: x_handle_error(&ps->c, (xcb_generic_error_t *)ev); break;
|
||||
case 0: x_handle_error(c, (xcb_generic_error_t *)ev); break;
|
||||
default:
|
||||
if (ps->shape_exists && ev->response_type == ps->shape_event) {
|
||||
if (session_has_shape_extension(ps) &&
|
||||
ev->response_type == session_get_shape_extention_event(ps)) {
|
||||
ev_shape_notify(ps, (xcb_shape_notify_event_t *)ev);
|
||||
break;
|
||||
}
|
||||
if (ps->randr_exists &&
|
||||
ev->response_type == (ps->randr_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY)) {
|
||||
if (session_has_randr_extension(ps) &&
|
||||
ev->response_type == (session_get_randr_extention_event(ps) +
|
||||
XCB_RANDR_SCREEN_CHANGE_NOTIFY)) {
|
||||
set_root_flags(ps, ROOT_FLAGS_SCREEN_CHANGE);
|
||||
break;
|
||||
}
|
||||
if (ps->damage_event + XCB_DAMAGE_NOTIFY == ev->response_type) {
|
||||
if (session_get_damage_extention_event(ps) + XCB_DAMAGE_NOTIFY ==
|
||||
ev->response_type) {
|
||||
ev_damage_notify(ps, (xcb_damage_notify_event_t *)ev);
|
||||
break;
|
||||
}
|
||||
|
|
204
src/opengl.c
204
src/opengl.c
|
@ -23,7 +23,9 @@
|
|||
#include "config.h"
|
||||
#include "kernel.h"
|
||||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "region.h"
|
||||
#include "render.h"
|
||||
#include "string_utils.h"
|
||||
#include "uthash_extra.h"
|
||||
#include "utils.h"
|
||||
|
@ -39,24 +41,26 @@ static inline XVisualInfo *get_visualinfo_from_visual(session_t *ps, xcb_visuali
|
|||
XVisualInfo vreq = {.visualid = visual};
|
||||
int nitems = 0;
|
||||
|
||||
return XGetVisualInfo(ps->c.dpy, VisualIDMask, &vreq, &nitems);
|
||||
return XGetVisualInfo(session_get_x_connection(ps)->dpy, VisualIDMask, &vreq, &nitems);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize OpenGL.
|
||||
*/
|
||||
bool glx_init(session_t *ps, bool need_render) {
|
||||
struct glx_session *glx_init(session_t *ps, bool need_render) {
|
||||
bool success = false;
|
||||
XVisualInfo *pvis = NULL;
|
||||
glx_session_t *psglx = NULL;
|
||||
auto c = session_get_x_connection(ps);
|
||||
|
||||
// Check for GLX extension
|
||||
if (!ps->glx_exists) {
|
||||
if (!session_has_glx_extension(ps)) {
|
||||
log_error("No GLX extension.");
|
||||
goto glx_init_end;
|
||||
}
|
||||
|
||||
// Get XVisualInfo
|
||||
pvis = get_visualinfo_from_visual(ps, ps->c.screen_info->root_visual);
|
||||
pvis = get_visualinfo_from_visual(ps, c->screen_info->root_visual);
|
||||
if (!pvis) {
|
||||
log_error("Failed to acquire XVisualInfo for current visual.");
|
||||
goto glx_init_end;
|
||||
|
@ -65,13 +69,12 @@ bool glx_init(session_t *ps, bool need_render) {
|
|||
// Ensure the visual is double-buffered
|
||||
if (need_render) {
|
||||
int value = 0;
|
||||
if (Success != glXGetConfig(ps->c.dpy, pvis, GLX_USE_GL, &value) || !value) {
|
||||
if (Success != glXGetConfig(c->dpy, pvis, GLX_USE_GL, &value) || !value) {
|
||||
log_error("Root visual is not a GL visual.");
|
||||
goto glx_init_end;
|
||||
}
|
||||
|
||||
if (Success != glXGetConfig(ps->c.dpy, pvis, GLX_DOUBLEBUFFER, &value) ||
|
||||
!value) {
|
||||
if (Success != glXGetConfig(c->dpy, pvis, GLX_DOUBLEBUFFER, &value) || !value) {
|
||||
log_error("Root visual is not a double buffered GL visual.");
|
||||
goto glx_init_end;
|
||||
}
|
||||
|
@ -83,38 +86,34 @@ bool glx_init(session_t *ps, bool need_render) {
|
|||
}
|
||||
|
||||
// Initialize GLX data structure
|
||||
if (!ps->psglx) {
|
||||
static const glx_session_t CGLX_SESSION_DEF = CGLX_SESSION_INIT;
|
||||
ps->psglx = cmalloc(glx_session_t);
|
||||
memcpy(ps->psglx, &CGLX_SESSION_DEF, sizeof(glx_session_t));
|
||||
auto options = session_get_options(ps);
|
||||
psglx = cmalloc(glx_session_t);
|
||||
*psglx = (glx_session_t){.context = NULL, .glx_prog_win = GLX_PROG_MAIN_INIT};
|
||||
|
||||
// +1 for the zero terminator
|
||||
ps->psglx->blur_passes = ccalloc(ps->o.blur_kernel_count, glx_blur_pass_t);
|
||||
// +1 for the zero terminator
|
||||
psglx->blur_passes = ccalloc(options->blur_kernel_count, glx_blur_pass_t);
|
||||
|
||||
for (int i = 0; i < ps->o.blur_kernel_count; ++i) {
|
||||
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
||||
ppass->unifm_factor_center = -1;
|
||||
ppass->unifm_offset_x = -1;
|
||||
ppass->unifm_offset_y = -1;
|
||||
}
|
||||
|
||||
ps->psglx->round_passes = ccalloc(1, glx_round_pass_t);
|
||||
glx_round_pass_t *ppass = ps->psglx->round_passes;
|
||||
ppass->unifm_radius = -1;
|
||||
ppass->unifm_texcoord = -1;
|
||||
ppass->unifm_texsize = -1;
|
||||
ppass->unifm_borderw = -1;
|
||||
ppass->unifm_borderc = -1;
|
||||
ppass->unifm_resolution = -1;
|
||||
ppass->unifm_tex_scr = -1;
|
||||
for (int i = 0; i < options->blur_kernel_count; ++i) {
|
||||
glx_blur_pass_t *ppass = &psglx->blur_passes[i];
|
||||
ppass->unifm_factor_center = -1;
|
||||
ppass->unifm_offset_x = -1;
|
||||
ppass->unifm_offset_y = -1;
|
||||
}
|
||||
|
||||
glx_session_t *psglx = ps->psglx;
|
||||
psglx->round_passes = ccalloc(1, glx_round_pass_t);
|
||||
glx_round_pass_t *ppass = psglx->round_passes;
|
||||
ppass->unifm_radius = -1;
|
||||
ppass->unifm_texcoord = -1;
|
||||
ppass->unifm_texsize = -1;
|
||||
ppass->unifm_borderw = -1;
|
||||
ppass->unifm_borderc = -1;
|
||||
ppass->unifm_resolution = -1;
|
||||
ppass->unifm_tex_scr = -1;
|
||||
|
||||
if (!psglx->context) {
|
||||
// Get GLX context
|
||||
#ifndef DEBUG_GLX_DEBUG_CONTEXT
|
||||
psglx->context = glXCreateContext(ps->c.dpy, pvis, None, GL_TRUE);
|
||||
psglx->context = glXCreateContext(c->dpy, pvis, None, GL_TRUE);
|
||||
#else
|
||||
{
|
||||
GLXFBConfig fbconfig = get_fbconfig_from_visualinfo(ps, pvis);
|
||||
|
@ -136,7 +135,7 @@ bool glx_init(session_t *ps, bool need_render) {
|
|||
static const int attrib_list[] = {
|
||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, None};
|
||||
psglx->context = p_glXCreateContextAttribsARB(
|
||||
ps->c.dpy, fbconfig, NULL, GL_TRUE, attrib_list);
|
||||
c->dpy, fbconfig, NULL, GL_TRUE, attrib_list);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -146,7 +145,7 @@ bool glx_init(session_t *ps, bool need_render) {
|
|||
}
|
||||
|
||||
// Attach GLX context
|
||||
if (!glXMakeCurrent(ps->c.dpy, get_tgt_window(ps), psglx->context)) {
|
||||
if (!glXMakeCurrent(c->dpy, session_get_target_window(ps), psglx->context)) {
|
||||
log_error("Failed to attach GLX context.");
|
||||
goto glx_init_end;
|
||||
}
|
||||
|
@ -168,7 +167,7 @@ bool glx_init(session_t *ps, bool need_render) {
|
|||
// Ensure we have a stencil buffer. X Fixes does not guarantee rectangles
|
||||
// in regions don't overlap, so we must use stencil buffer to make sure
|
||||
// we don't paint a region for more than one time, I think?
|
||||
if (need_render && !ps->o.glx_no_stencil) {
|
||||
if (need_render && !options->glx_no_stencil) {
|
||||
GLint val = 0;
|
||||
glGetIntegerv(GL_STENCIL_BITS, &val);
|
||||
if (!val) {
|
||||
|
@ -193,7 +192,7 @@ bool glx_init(session_t *ps, bool need_render) {
|
|||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
if (!ps->o.glx_no_stencil) {
|
||||
if (!options->glx_no_stencil) {
|
||||
// Initialize stencil buffer
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
@ -204,7 +203,7 @@ bool glx_init(session_t *ps, bool need_render) {
|
|||
// Clear screen
|
||||
glClearColor(0.0F, 0.0F, 0.0F, 1.0F);
|
||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
// glXSwapBuffers(ps->c.dpy, get_tgt_window(ps));
|
||||
// glXSwapBuffers(ps->c.dpy, session_get_target_window(ps));
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
@ -213,10 +212,11 @@ glx_init_end:
|
|||
XFree(pvis);
|
||||
|
||||
if (!success) {
|
||||
glx_destroy(ps);
|
||||
glx_destroy(ps, psglx);
|
||||
psglx = NULL;
|
||||
}
|
||||
|
||||
return success;
|
||||
return psglx;
|
||||
}
|
||||
|
||||
static void glx_free_prog_main(glx_prog_main_t *pprogram) {
|
||||
|
@ -235,19 +235,14 @@ static void glx_free_prog_main(glx_prog_main_t *pprogram) {
|
|||
/**
|
||||
* Destroy GLX related resources.
|
||||
*/
|
||||
void glx_destroy(session_t *ps) {
|
||||
if (!ps->psglx) {
|
||||
void glx_destroy(struct session *ps, struct glx_session *psglx) {
|
||||
if (!psglx) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Free all GLX resources of windows
|
||||
win_stack_foreach_managed(w, &ps->window_stack) {
|
||||
free_win_res_glx(ps, w);
|
||||
}
|
||||
|
||||
// Free GLSL shaders/programs
|
||||
for (int i = 0; i < ps->o.blur_kernel_count; ++i) {
|
||||
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
||||
for (int i = 0; i < session_get_options(ps)->blur_kernel_count; ++i) {
|
||||
glx_blur_pass_t *ppass = &psglx->blur_passes[i];
|
||||
if (ppass->frag_shader) {
|
||||
glDeleteShader(ppass->frag_shader);
|
||||
}
|
||||
|
@ -255,43 +250,44 @@ void glx_destroy(session_t *ps) {
|
|||
glDeleteProgram(ppass->prog);
|
||||
}
|
||||
}
|
||||
free(ps->psglx->blur_passes);
|
||||
free(psglx->blur_passes);
|
||||
|
||||
glx_round_pass_t *ppass = ps->psglx->round_passes;
|
||||
glx_round_pass_t *ppass = psglx->round_passes;
|
||||
if (ppass->frag_shader) {
|
||||
glDeleteShader(ppass->frag_shader);
|
||||
}
|
||||
if (ppass->prog) {
|
||||
glDeleteProgram(ppass->prog);
|
||||
}
|
||||
free(ps->psglx->round_passes);
|
||||
free(psglx->round_passes);
|
||||
|
||||
glx_free_prog_main(&ps->glx_prog_win);
|
||||
glx_free_prog_main(&psglx->glx_prog_win);
|
||||
|
||||
gl_check_err();
|
||||
|
||||
// Destroy GLX context
|
||||
if (ps->psglx->context) {
|
||||
glXMakeCurrent(ps->c.dpy, None, NULL);
|
||||
glXDestroyContext(ps->c.dpy, ps->psglx->context);
|
||||
ps->psglx->context = NULL;
|
||||
auto c = session_get_x_connection(ps);
|
||||
if (psglx->context) {
|
||||
glXMakeCurrent(c->dpy, None, NULL);
|
||||
glXDestroyContext(c->dpy, psglx->context);
|
||||
psglx->context = NULL;
|
||||
}
|
||||
|
||||
free(ps->psglx);
|
||||
ps->psglx = NULL;
|
||||
ps->argb_fbconfig = (struct glx_fbconfig_info){0};
|
||||
free(psglx);
|
||||
psglx = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to run on root window size change.
|
||||
*/
|
||||
void glx_on_root_change(session_t *ps) {
|
||||
glViewport(0, 0, ps->root_width, ps->root_height);
|
||||
auto root_extent = session_get_root_extent(ps);
|
||||
glViewport(0, 0, root_extent.width, root_extent.height);
|
||||
|
||||
// Initialize matrix, copied from dcompmgr
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, ps->root_width, 0, ps->root_height, -1000.0, 1000.0);
|
||||
glOrtho(0, root_extent.width, 0, root_extent.height, -1000.0, 1000.0);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
@ -300,12 +296,13 @@ void glx_on_root_change(session_t *ps) {
|
|||
* Initialize GLX blur filter.
|
||||
*/
|
||||
bool glx_init_blur(session_t *ps) {
|
||||
assert(ps->o.blur_kernel_count > 0);
|
||||
assert(ps->o.blur_kerns);
|
||||
assert(ps->o.blur_kerns[0]);
|
||||
auto options = session_get_options(ps);
|
||||
assert(options->blur_kernel_count > 0);
|
||||
assert(options->blur_kerns);
|
||||
assert(options->blur_kerns[0]);
|
||||
|
||||
// Allocate PBO if more than one blur kernel is present
|
||||
if (ps->o.blur_kernel_count > 1) {
|
||||
if (options->blur_kernel_count > 1) {
|
||||
// Try to generate a framebuffer
|
||||
GLuint fbo = 0;
|
||||
glGenFramebuffers(1, &fbo);
|
||||
|
@ -343,7 +340,8 @@ bool glx_init_blur(session_t *ps) {
|
|||
" gl_FragColor = sum / (factor_center + float(%.7g));\n"
|
||||
"}\n";
|
||||
|
||||
const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two;
|
||||
auto psglx = session_get_psglx(ps);
|
||||
const bool use_texture_rect = !psglx->has_texture_non_power_of_two;
|
||||
const char *sampler_type = (use_texture_rect ? "sampler2DRect" : "sampler2D");
|
||||
const char *texture_func = (use_texture_rect ? "texture2DRect" : "texture2D");
|
||||
const char *shader_add = FRAG_SHADER_BLUR_ADD;
|
||||
|
@ -356,9 +354,9 @@ bool glx_init_blur(session_t *ps) {
|
|||
extension = strdup("");
|
||||
}
|
||||
|
||||
for (int i = 0; i < ps->o.blur_kernel_count; ++i) {
|
||||
auto kern = ps->o.blur_kerns[i];
|
||||
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
||||
for (int i = 0; i < options->blur_kernel_count; ++i) {
|
||||
auto kern = options->blur_kerns[i];
|
||||
glx_blur_pass_t *ppass = &psglx->blur_passes[i];
|
||||
|
||||
// Build shader
|
||||
int width = kern->w, height = kern->h;
|
||||
|
@ -505,7 +503,8 @@ bool glx_init_rounded_corners(session_t *ps) {
|
|||
"\n"
|
||||
"}\n";
|
||||
|
||||
const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two;
|
||||
auto psglx = session_get_psglx(ps);
|
||||
const bool use_texture_rect = !psglx->has_texture_non_power_of_two;
|
||||
const char *sampler_type = (use_texture_rect ? "sampler2DRect" : "sampler2D");
|
||||
const char *texture_func = (use_texture_rect ? "texture2DRect" : "texture2D");
|
||||
char *extension = NULL;
|
||||
|
@ -519,7 +518,7 @@ bool glx_init_rounded_corners(session_t *ps) {
|
|||
|
||||
bool success = false;
|
||||
// Build rounded corners shader
|
||||
auto ppass = ps->psglx->round_passes;
|
||||
auto ppass = psglx->round_passes;
|
||||
auto len = strlen(FRAG_SHADER) + strlen(extension) + strlen(sampler_type) +
|
||||
strlen(texture_func) + 1;
|
||||
char *shader_str = ccalloc(len, char);
|
||||
|
@ -614,7 +613,8 @@ static inline void glx_copy_region_to_tex(session_t *ps, GLenum tex_tgt, int bas
|
|||
int basey, int dx, int dy, int width, int height) {
|
||||
if (width > 0 && height > 0) {
|
||||
glCopyTexSubImage2D(tex_tgt, 0, dx - basex, dy - basey, dx,
|
||||
ps->root_height - dy - height, width, height);
|
||||
session_get_root_extent(ps).height - dy - height,
|
||||
width, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -641,7 +641,7 @@ static inline GLuint glx_gen_texture(GLenum tex_tgt, int width, int height) {
|
|||
*/
|
||||
bool glx_bind_texture(session_t *ps attr_unused, glx_texture_t **pptex, int x, int y,
|
||||
int width, int height) {
|
||||
if (ps->o.backend != BKEND_GLX && ps->o.backend != BKEND_XR_GLX_HYBRID) {
|
||||
if (!bkend_use_glx(ps)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -662,7 +662,7 @@ bool glx_bind_texture(session_t *ps attr_unused, glx_texture_t **pptex, int x, i
|
|||
ptex->width = width;
|
||||
ptex->height = height;
|
||||
ptex->target = GL_TEXTURE_RECTANGLE;
|
||||
if (ps->psglx->has_texture_non_power_of_two) {
|
||||
if (session_get_psglx(ps)->has_texture_non_power_of_two) {
|
||||
ptex->target = GL_TEXTURE_2D;
|
||||
}
|
||||
}
|
||||
|
@ -697,7 +697,7 @@ bool glx_bind_texture(session_t *ps attr_unused, glx_texture_t **pptex, int x, i
|
|||
*/
|
||||
bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap, int width,
|
||||
int height, bool repeat, const struct glx_fbconfig_info *fbcfg) {
|
||||
if (ps->o.backend != BKEND_GLX && ps->o.backend != BKEND_XR_GLX_HYBRID) {
|
||||
if (!bkend_use_glx(ps)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -734,13 +734,14 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
|||
|
||||
// Create GLX pixmap
|
||||
int depth = 0;
|
||||
auto c = session_get_x_connection(ps);
|
||||
if (!ptex->glpixmap) {
|
||||
need_release = false;
|
||||
|
||||
// Retrieve pixmap parameters, if they aren't provided
|
||||
if (!width || !height) {
|
||||
auto r = xcb_get_geometry_reply(
|
||||
ps->c.c, xcb_get_geometry(ps->c.c, pixmap), NULL);
|
||||
c->c, xcb_get_geometry(c->c, pixmap), NULL);
|
||||
if (!r) {
|
||||
log_error("Failed to query info of pixmap %#010x.", pixmap);
|
||||
return false;
|
||||
|
@ -761,7 +762,7 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
|||
// pixmap-specific parameters, and this may change in the future
|
||||
GLenum tex_tgt = 0;
|
||||
if (GLX_TEXTURE_2D_BIT_EXT & fbcfg->texture_tgts &&
|
||||
ps->psglx->has_texture_non_power_of_two) {
|
||||
session_get_psglx(ps)->has_texture_non_power_of_two) {
|
||||
tex_tgt = GLX_TEXTURE_2D_EXT;
|
||||
} else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & fbcfg->texture_tgts) {
|
||||
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT;
|
||||
|
@ -782,7 +783,7 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
|||
0,
|
||||
};
|
||||
|
||||
ptex->glpixmap = glXCreatePixmap(ps->c.dpy, fbcfg->cfg, pixmap, attrs);
|
||||
ptex->glpixmap = glXCreatePixmap(c->dpy, fbcfg->cfg, pixmap, attrs);
|
||||
ptex->pixmap = pixmap;
|
||||
ptex->target =
|
||||
(GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE);
|
||||
|
@ -829,10 +830,10 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
|||
// The specification requires rebinding whenever the content changes...
|
||||
// We can't follow this, too slow.
|
||||
if (need_release) {
|
||||
glXReleaseTexImageEXT(ps->c.dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
|
||||
glXReleaseTexImageEXT(c->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
|
||||
}
|
||||
|
||||
glXBindTexImageEXT(ps->c.dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
|
||||
glXBindTexImageEXT(c->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
|
||||
|
||||
// Cleanup
|
||||
glBindTexture(ptex->target, 0);
|
||||
|
@ -847,16 +848,17 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
|||
* @brief Release binding of a texture.
|
||||
*/
|
||||
void glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
|
||||
auto c = session_get_x_connection(ps);
|
||||
// Release binding
|
||||
if (ptex->glpixmap && ptex->texture) {
|
||||
glBindTexture(ptex->target, ptex->texture);
|
||||
glXReleaseTexImageEXT(ps->c.dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
|
||||
glXReleaseTexImageEXT(c->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
|
||||
glBindTexture(ptex->target, 0);
|
||||
}
|
||||
|
||||
// Free GLX Pixmap
|
||||
if (ptex->glpixmap) {
|
||||
glXDestroyPixmap(ps->c.dpy, ptex->glpixmap);
|
||||
glXDestroyPixmap(c->dpy, ptex->glpixmap);
|
||||
ptex->glpixmap = 0;
|
||||
}
|
||||
|
||||
|
@ -868,7 +870,7 @@ void glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
|
|||
*/
|
||||
void glx_set_clip(session_t *ps, const region_t *reg) {
|
||||
// Quit if we aren't using stencils
|
||||
if (ps->o.glx_no_stencil) {
|
||||
if (session_get_options(ps)->glx_no_stencil) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -884,7 +886,7 @@ void glx_set_clip(session_t *ps, const region_t *reg) {
|
|||
|
||||
if (nrects == 1) {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(rects[0].x1, ps->root_height - rects[0].y2,
|
||||
glScissor(rects[0].x1, session_get_root_extent(ps).height - rects[0].y2,
|
||||
rects[0].x2 - rects[0].x1, rects[0].y2 - rects[0].y1);
|
||||
}
|
||||
|
||||
|
@ -917,8 +919,10 @@ void glx_set_clip(session_t *ps, const region_t *reg) {
|
|||
*/
|
||||
bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||
GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc) {
|
||||
assert(ps->psglx->blur_passes[0].prog);
|
||||
const bool more_passes = ps->o.blur_kernel_count > 1;
|
||||
auto psglx = session_get_psglx(ps);
|
||||
assert(psglx->blur_passes[0].prog);
|
||||
auto options = session_get_options(ps);
|
||||
const bool more_passes = options->blur_kernel_count > 1;
|
||||
const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST);
|
||||
const bool have_stencil = glIsEnabled(GL_STENCIL_TEST);
|
||||
bool ret = false;
|
||||
|
@ -954,7 +958,7 @@ bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
|||
*/
|
||||
|
||||
GLenum tex_tgt = GL_TEXTURE_RECTANGLE;
|
||||
if (ps->psglx->has_texture_non_power_of_two) {
|
||||
if (psglx->has_texture_non_power_of_two) {
|
||||
tex_tgt = GL_TEXTURE_2D;
|
||||
}
|
||||
|
||||
|
@ -1017,9 +1021,9 @@ bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
|||
}
|
||||
|
||||
bool last_pass = false;
|
||||
for (int i = 0; i < ps->o.blur_kernel_count; ++i) {
|
||||
last_pass = (i == ps->o.blur_kernel_count - 1);
|
||||
const glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
||||
for (int i = 0; i < options->blur_kernel_count; ++i) {
|
||||
last_pass = (i == options->blur_kernel_count - 1);
|
||||
const glx_blur_pass_t *ppass = &psglx->blur_passes[i];
|
||||
assert(ppass->prog);
|
||||
|
||||
assert(tex_scr);
|
||||
|
@ -1071,7 +1075,7 @@ bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
|||
auto rdy = (GLfloat)(mheight - crect.y1 + mdy);
|
||||
if (last_pass) {
|
||||
rdx = (GLfloat)crect.x1;
|
||||
rdy = (GLfloat)(ps->root_height - crect.y1);
|
||||
rdy = (GLfloat)(session_get_root_extent(ps).height - crect.y1);
|
||||
}
|
||||
auto rdxe = rdx + (GLfloat)(crect.x2 - crect.x1);
|
||||
auto rdye = rdy - (GLfloat)(crect.y2 - crect.y1);
|
||||
|
@ -1176,8 +1180,9 @@ void glx_read_border_pixel(int root_height, int root_width, int x, int y, int wi
|
|||
bool glx_round_corners_dst(session_t *ps, struct managed_win *w,
|
||||
const glx_texture_t *ptex, int dx, int dy, int width,
|
||||
int height, float z, float cr, const region_t *reg_tgt) {
|
||||
assert(ps->psglx->round_passes->prog);
|
||||
assert(session_get_psglx(ps)->round_passes->prog);
|
||||
bool ret = false;
|
||||
auto psglx = session_get_psglx(ps);
|
||||
|
||||
// log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d) b(%d), f(%d)",
|
||||
// dx, dy, width, height, ps->root_width, ps->root_height, w->g.border_width,
|
||||
|
@ -1186,13 +1191,14 @@ bool glx_round_corners_dst(session_t *ps, struct managed_win *w,
|
|||
int mdx = dx, mdy = dy, mwidth = width, mheight = height;
|
||||
log_trace("%d, %d, %d, %d", mdx, mdy, mwidth, mheight);
|
||||
|
||||
auto root_extent = session_get_root_extent(ps);
|
||||
if (w->g.border_width > 0) {
|
||||
glx_read_border_pixel(ps->root_height, ps->root_width, dx, dy, width,
|
||||
height, &w->border_col[0]);
|
||||
glx_read_border_pixel(root_extent.height, root_extent.width, dx, dy,
|
||||
width, height, &w->border_col[0]);
|
||||
}
|
||||
|
||||
{
|
||||
const glx_round_pass_t *ppass = ps->psglx->round_passes;
|
||||
const glx_round_pass_t *ppass = psglx->round_passes;
|
||||
assert(ppass->prog);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
|
@ -1229,8 +1235,8 @@ bool glx_round_corners_dst(session_t *ps, struct managed_win *w,
|
|||
w->border_col[1], w->border_col[2], w->border_col[3]);
|
||||
}
|
||||
if (ppass->unifm_resolution >= 0) {
|
||||
glUniform2f(ppass->unifm_resolution, (float)ps->root_width,
|
||||
(float)ps->root_height);
|
||||
glUniform2f(ppass->unifm_resolution, (float)root_extent.width,
|
||||
(float)root_extent.height);
|
||||
}
|
||||
|
||||
// Painting
|
||||
|
@ -1250,7 +1256,7 @@ bool glx_round_corners_dst(session_t *ps, struct managed_win *w,
|
|||
|
||||
// coordinates for the texture in the target
|
||||
auto rdx = (GLfloat)crect.x1;
|
||||
auto rdy = (GLfloat)(ps->root_height - crect.y1);
|
||||
auto rdy = (GLfloat)(root_extent.height - crect.y1);
|
||||
auto rdxe = (GLfloat)rdx + (GLfloat)(crect.x2 - crect.x1);
|
||||
auto rdye = (GLfloat)rdy - (GLfloat)(crect.y2 - crect.y1);
|
||||
|
||||
|
@ -1305,7 +1311,7 @@ bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z,
|
|||
P_PAINTREG_START(crect) {
|
||||
// XXX what does all of these variables mean?
|
||||
GLint rdx = crect.x1;
|
||||
GLint rdy = ps->root_height - crect.y1;
|
||||
GLint rdy = session_get_root_extent(ps).height - crect.y1;
|
||||
GLint rdxe = rdx + (crect.x2 - crect.x1);
|
||||
GLint rdye = rdy - (crect.y2 - crect.y1);
|
||||
|
||||
|
@ -1481,7 +1487,7 @@ bool glx_render(session_t *ps, const glx_texture_t *ptex, int x, int y, int dx,
|
|||
|
||||
// coordinates for the texture in the target
|
||||
GLint rdx = crect.x1;
|
||||
GLint rdy = ps->root_height - crect.y1;
|
||||
GLint rdy = session_get_root_extent(ps).height - crect.y1;
|
||||
GLint rdxe = rdx + (crect.x2 - crect.x1);
|
||||
GLint rdye = rdy - (crect.y2 - crect.y1);
|
||||
|
||||
|
|
13
src/opengl.h
13
src/opengl.h
|
@ -13,12 +13,11 @@
|
|||
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
#include "log.h"
|
||||
#include "picom.h"
|
||||
#include "region.h"
|
||||
#include "render.h"
|
||||
#include "win.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <epoxy/gl.h>
|
||||
#include <epoxy/glx.h>
|
||||
#include <locale.h>
|
||||
|
@ -73,6 +72,9 @@ typedef struct glx_session {
|
|||
int z;
|
||||
glx_blur_pass_t *blur_passes;
|
||||
glx_round_pass_t *round_passes;
|
||||
/// Custom GLX program used for painting window.
|
||||
glx_prog_main_t glx_prog_win;
|
||||
struct glx_fbconfig_info argb_fbconfig;
|
||||
} glx_session_t;
|
||||
|
||||
/// @brief Wrapper of a bound GLX texture.
|
||||
|
@ -96,9 +98,9 @@ bool glx_render(session_t *ps, const glx_texture_t *ptex, int x, int y, int dx,
|
|||
int width, int height, int z, double opacity, bool argb, bool neg,
|
||||
const region_t *reg_tgt, const glx_prog_main_t *pprogram);
|
||||
|
||||
bool glx_init(session_t *ps, bool need_render);
|
||||
struct glx_session *glx_init(session_t *ps, bool need_render);
|
||||
|
||||
void glx_destroy(session_t *ps);
|
||||
void glx_destroy(struct session *ps, struct glx_session *psglx);
|
||||
|
||||
void glx_on_root_change(session_t *ps);
|
||||
|
||||
|
@ -148,7 +150,8 @@ unsigned char *glx_take_screenshot(session_t *ps, int *out_length);
|
|||
* Check if there's a GLX context.
|
||||
*/
|
||||
static inline bool glx_has_context(session_t *ps) {
|
||||
return ps->psglx && ps->psglx->context;
|
||||
auto psglx = session_get_psglx(ps);
|
||||
return psglx && psglx->context;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
776
src/picom.c
776
src/picom.c
|
@ -19,6 +19,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <libgen.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
#include <sched.h>
|
||||
#include <stddef.h>
|
||||
|
@ -41,6 +42,7 @@
|
|||
#include <ev.h>
|
||||
#include <test.h>
|
||||
|
||||
#include "backend/driver.h"
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
|
@ -50,6 +52,7 @@
|
|||
#include "picom.h"
|
||||
#include "transition.h"
|
||||
#include "win_defs.h"
|
||||
#include "xcb/xproto.h"
|
||||
#ifdef CONFIG_OPENGL
|
||||
#include "opengl.h"
|
||||
#endif
|
||||
|
@ -73,6 +76,246 @@
|
|||
#include "win.h"
|
||||
#include "x.h"
|
||||
|
||||
/// 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;
|
||||
/// Use an ev_timer callback for drawing
|
||||
ev_timer draw_timer;
|
||||
/// Called every time 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 related ===
|
||||
/// 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;
|
||||
/// Shaders
|
||||
struct shader_info *shaders;
|
||||
|
||||
// === Display related ===
|
||||
/// X connection
|
||||
struct x_connection c;
|
||||
/// Whether the X server is grabbed by us
|
||||
bool server_grabbed;
|
||||
/// Width of root window.
|
||||
int root_width;
|
||||
/// Height of root window.
|
||||
int root_height;
|
||||
/// X Composite overlay window.
|
||||
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
|
||||
image_handle 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;
|
||||
#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;
|
||||
/// Whether screen has been turned off
|
||||
bool screen_is_off;
|
||||
/// When last MSC event happened, in useconds.
|
||||
uint64_t last_msc_instant;
|
||||
/// The last MSC number
|
||||
uint64_t last_msc;
|
||||
/// The delay between when the last frame was scheduled to be rendered, and when
|
||||
/// the render actually started.
|
||||
uint64_t last_schedule_delay;
|
||||
/// When do we want our next frame to start rendering.
|
||||
uint64_t next_render;
|
||||
/// Whether we can perform frame pacing.
|
||||
bool frame_pacing;
|
||||
/// Vblank event scheduler
|
||||
struct vblank_scheduler *vblank_scheduler;
|
||||
|
||||
/// Render statistics
|
||||
struct render_statistics render_stats;
|
||||
|
||||
// === Operation related ===
|
||||
/// Flags related to the root window
|
||||
uint64_t root_flags;
|
||||
/// Program options.
|
||||
options_t o;
|
||||
/// State object for c2.
|
||||
struct c2_state *c2_state;
|
||||
/// Whether we have hit unredirection timeout.
|
||||
bool tmout_unredir_hit;
|
||||
/// If the backend is busy. This means two things:
|
||||
/// Either the backend is currently rendering a frame, or a frame has been
|
||||
/// rendered but has yet to be presented. In either case, we should not start
|
||||
/// another render right now. As if we start issuing rendering commands now, we
|
||||
/// will have to wait for either the current render to finish, or the current
|
||||
/// back buffer to become available again. In either case, we will be wasting
|
||||
/// time.
|
||||
bool backend_busy;
|
||||
/// Whether a render is queued. This generally means there are pending updates
|
||||
/// to the screen that's neither included in the current render, nor on the
|
||||
/// screen.
|
||||
bool render_queued;
|
||||
|
||||
/// For tracking damaged regions
|
||||
struct damage_ring damage_ring;
|
||||
/// 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 long fade_time;
|
||||
// Cached blur convolution kernels.
|
||||
struct x_convolution_kernel **blur_kerns_cache;
|
||||
/// If we should quit
|
||||
bool quit : 1;
|
||||
// TODO(yshui) use separate flags for different 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;
|
||||
/// Backend shadow context.
|
||||
struct backend_shadow_context *shadow_context;
|
||||
// for shadow precomputation
|
||||
/// A region in which shadow is not painted on.
|
||||
region_t shadow_exclude_reg;
|
||||
|
||||
// === Software-optimization-related ===
|
||||
/// 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 DPMS extension exists
|
||||
bool dpms_exists;
|
||||
/// 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;
|
||||
/// Information about monitors.
|
||||
struct x_monitors monitors;
|
||||
/// 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;
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// === DBus related ===
|
||||
struct cdbus_data *dbus_data;
|
||||
#endif
|
||||
|
||||
int (*vsync_wait)(session_t *);
|
||||
} session_t;
|
||||
|
||||
/// Get session_t pointer from a pointer to a member of session_t
|
||||
#define session_ptr(ptr, member) \
|
||||
({ \
|
||||
|
@ -156,7 +399,7 @@ static inline struct managed_win *find_win_all(session_t *ps, const xcb_window_t
|
|||
|
||||
auto w = find_managed_win(ps, wid);
|
||||
if (!w) {
|
||||
w = find_toplevel(ps, wid);
|
||||
w = session_find_toplevel(ps, wid);
|
||||
}
|
||||
if (!w) {
|
||||
w = find_managed_window_or_parent(ps, wid);
|
||||
|
@ -536,8 +779,8 @@ uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode) {
|
|||
}
|
||||
|
||||
// Check if it's a mapped client window
|
||||
if (mode == WIN_EVMODE_CLIENT ||
|
||||
((w = find_toplevel(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) {
|
||||
if (mode == WIN_EVMODE_CLIENT || ((w = session_find_toplevel(ps, wid)) &&
|
||||
w->a.map_state == XCB_MAP_STATE_VIEWABLE)) {
|
||||
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE;
|
||||
}
|
||||
|
||||
|
@ -824,7 +1067,7 @@ static void configure_root(session_t *ps) {
|
|||
rebuild_shadow_exclude_reg(ps);
|
||||
|
||||
// Invalidate reg_ignore from the top
|
||||
auto top_w = win_stack_find_next_managed(ps, &ps->window_stack);
|
||||
auto top_w = session_get_next_managed_win_in_stack(ps, &ps->window_stack);
|
||||
if (top_w) {
|
||||
rc_region_unref(&top_w->reg_ignore);
|
||||
top_w->reg_ignore_valid = false;
|
||||
|
@ -1459,9 +1702,505 @@ xcb_window_t session_get_target_window(session_t *ps) {
|
|||
return ps->overlay != XCB_NONE ? ps->overlay : ps->c.screen_info->root;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
struct cdbus_data *session_get_cdbus(struct session *ps) {
|
||||
return ps->dbus_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ev_loop *session_get_mainloop(struct session *ps) {
|
||||
return ps->loop;
|
||||
}
|
||||
|
||||
struct options *session_get_options(struct session *ps) {
|
||||
return &ps->o;
|
||||
}
|
||||
|
||||
enum driver session_get_driver(struct session *ps) {
|
||||
return ps->drivers;
|
||||
}
|
||||
|
||||
unsigned int session_get_window_count(session_t *ps) {
|
||||
unsigned int count = 0;
|
||||
HASH_ITER2(ps->windows, w) {
|
||||
assert(!w->destroyed);
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
struct managed_win *session_get_active_win(session_t *ps) {
|
||||
return ps->active_win;
|
||||
}
|
||||
|
||||
void session_set_active_win(session_t *ps, struct managed_win *w) {
|
||||
ps->active_win = w;
|
||||
}
|
||||
|
||||
xcb_window_t session_get_active_leader(session_t *ps) {
|
||||
return ps->active_leader;
|
||||
}
|
||||
|
||||
void session_set_active_leader(session_t *ps, xcb_window_t leader) {
|
||||
ps->active_leader = leader;
|
||||
}
|
||||
|
||||
struct x_connection *session_get_x_connection(session_t *ps) {
|
||||
return &ps->c;
|
||||
}
|
||||
|
||||
struct win *session_get_next_win_in_stack(struct session *ps, struct win *w) {
|
||||
if (!list_node_is_last(&ps->window_stack, &w->stack_neighbour)) {
|
||||
return list_entry(w->stack_neighbour.next, struct win, stack_neighbour);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Find the managed window immediately below `i` in the window stack
|
||||
struct managed_win *
|
||||
session_get_next_managed_win_in_stack(const session_t *ps, const struct list_node *cursor) {
|
||||
while (!list_node_is_last(&ps->window_stack, cursor)) {
|
||||
auto next = list_entry(cursor->next, struct win, stack_neighbour);
|
||||
if (next->managed) {
|
||||
return (struct managed_win *)next;
|
||||
}
|
||||
cursor = &next->stack_neighbour;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xcb_window_t session_get_overlay(session_t *ps) {
|
||||
return ps->overlay;
|
||||
}
|
||||
|
||||
struct damage_ring *session_get_damage_ring(session_t *ps) {
|
||||
return &ps->damage_ring;
|
||||
}
|
||||
|
||||
void session_assert_server_grabbed(session_t *ps attr_unused) {
|
||||
assert(ps->server_grabbed);
|
||||
}
|
||||
|
||||
image_handle session_get_root_image(session_t *ps) {
|
||||
return ps->root_image;
|
||||
}
|
||||
|
||||
void session_record_cpu_time(session_t *ps) {
|
||||
auto now = get_time_timespec();
|
||||
auto now_us = (uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
|
||||
if (ps->next_render > 0) {
|
||||
log_verbose("Render schedule deviation: %ld us (%s) %" PRIu64 " %" PRIu64,
|
||||
labs((long)now_us - (long)ps->next_render),
|
||||
now_us < ps->next_render ? "early" : "late", now_us,
|
||||
ps->next_render);
|
||||
ps->last_schedule_delay = 0;
|
||||
if (now_us > ps->next_render) {
|
||||
ps->last_schedule_delay = now_us - ps->next_render;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typeof(session_get_root_extent(NULL)) session_get_root_extent(session_t *ps) {
|
||||
typeof(session_get_root_extent(ps)) ret = {.height = ps->root_height,
|
||||
.width = ps->root_width};
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct atom *session_get_atoms(session_t *ps) {
|
||||
return ps->atoms;
|
||||
}
|
||||
|
||||
struct c2_state *session_get_c2(session_t *ps) {
|
||||
return ps->c2_state;
|
||||
}
|
||||
|
||||
void session_mark_updates_pending(session_t *ps) {
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
|
||||
struct backend_base *session_get_backend_data(session_t *ps) {
|
||||
return ps->backend_data;
|
||||
}
|
||||
|
||||
struct backend_shadow_context *session_get_backend_shadow_context(session_t *ps) {
|
||||
return ps->shadow_context;
|
||||
}
|
||||
|
||||
void *session_get_backend_blur_context(session_t *ps) {
|
||||
return ps->backend_blur_context;
|
||||
}
|
||||
|
||||
struct x_convolution_kernel **session_get_blur_kern_cache(session_t *ps) {
|
||||
return ps->blur_kerns_cache;
|
||||
}
|
||||
|
||||
void session_set_blur_kern_cache(session_t *ps, struct x_convolution_kernel **cache) {
|
||||
ps->blur_kerns_cache = cache;
|
||||
}
|
||||
|
||||
void session_foreach_win(session_t *ps, void (*func)(struct win *, void *), void *data) {
|
||||
HASH_ITER2(ps->windows, w) {
|
||||
assert(!w->destroyed);
|
||||
func(w, data);
|
||||
}
|
||||
}
|
||||
|
||||
struct shader_info *session_get_shader_info(session_t *ps, const char *key) {
|
||||
struct shader_info *info = NULL;
|
||||
if (key) {
|
||||
HASH_FIND_STR(ps->shaders, key, info);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
bool session_is_redirected(session_t *ps) {
|
||||
return ps->redirected;
|
||||
}
|
||||
|
||||
void session_delete_win(session_t *ps, struct win *w) {
|
||||
HASH_DEL(ps->windows, w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a managed window from window id in window linked list of the session.
|
||||
*/
|
||||
struct win *session_find_win(session_t *ps, xcb_window_t id) {
|
||||
if (!id) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct win *w = NULL;
|
||||
HASH_FIND_INT(ps->windows, &id, w);
|
||||
assert(w == NULL || !w->destroyed);
|
||||
return w;
|
||||
}
|
||||
|
||||
/// Insert a new window after list_node `prev`
|
||||
/// New window will be in unmapped state
|
||||
static struct win *session_add_win(session_t *ps, xcb_window_t id, struct list_node *prev) {
|
||||
log_debug("Adding window %#010x", id);
|
||||
struct win *old_w = NULL;
|
||||
HASH_FIND_INT(ps->windows, &id, old_w);
|
||||
assert(old_w == NULL);
|
||||
|
||||
auto new_w = cmalloc(struct win);
|
||||
list_insert_after(prev, &new_w->stack_neighbour);
|
||||
new_w->id = id;
|
||||
new_w->managed = false;
|
||||
new_w->is_new = true;
|
||||
new_w->destroyed = false;
|
||||
|
||||
HASH_ADD_INT(ps->windows, id, new_w);
|
||||
session_mark_updates_pending(ps);
|
||||
return new_w;
|
||||
}
|
||||
|
||||
/// Insert a new win entry at the top of the stack
|
||||
struct win *session_add_win_top(session_t *ps, xcb_window_t id) {
|
||||
return session_add_win(ps, id, &ps->window_stack);
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
struct win *w = NULL;
|
||||
HASH_FIND_INT(ps->windows, &below, w);
|
||||
if (!w) {
|
||||
if (!list_is_empty(&ps->window_stack)) {
|
||||
// `below` window is not found even if the window stack is
|
||||
// not empty
|
||||
return NULL;
|
||||
}
|
||||
return session_add_win_top(ps, id);
|
||||
}
|
||||
// we found something from the hash table, so if the stack is
|
||||
// empty, we are in an inconsistent state.
|
||||
assert(!list_is_empty(&ps->window_stack));
|
||||
return session_add_win(ps, id, w->stack_neighbour.prev);
|
||||
}
|
||||
|
||||
/// Move window `w` so it's before `next` in the list
|
||||
static inline void session_restack_win(session_t *ps, struct win *w, struct list_node *next) {
|
||||
struct managed_win *mw = NULL;
|
||||
if (w->managed) {
|
||||
mw = (struct managed_win *)w;
|
||||
}
|
||||
|
||||
if (mw) {
|
||||
// This invalidates all reg_ignore below the new stack position of
|
||||
// `w`
|
||||
mw->reg_ignore_valid = false;
|
||||
rc_region_unref(&mw->reg_ignore);
|
||||
|
||||
// This invalidates all reg_ignore below the old stack position of
|
||||
// `w`
|
||||
auto next_w = session_get_next_managed_win_in_stack(ps, &w->stack_neighbour);
|
||||
if (next_w) {
|
||||
next_w->reg_ignore_valid = false;
|
||||
rc_region_unref(&next_w->reg_ignore);
|
||||
}
|
||||
}
|
||||
|
||||
list_move_before(&w->stack_neighbour, next);
|
||||
|
||||
// add damage for this window
|
||||
if (mw) {
|
||||
add_damage_from_win(ps, mw);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_RESTACK
|
||||
log_trace("Window stack modified. Current stack:");
|
||||
for (auto c = ps->list; c; c = c->next) {
|
||||
const char *desc = "";
|
||||
if (c->state == WSTATE_DESTROYING) {
|
||||
desc = "(D) ";
|
||||
}
|
||||
log_trace("%#010x \"%s\" %s", c->id, c->name, desc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct list_node *session_get_win_stack(session_t *ps) {
|
||||
return &ps->window_stack;
|
||||
}
|
||||
|
||||
/// Move window `w` so it's right above `below`
|
||||
void session_restack_above(session_t *ps, struct win *w, xcb_window_t below) {
|
||||
xcb_window_t old_below;
|
||||
|
||||
if (!list_node_is_last(&ps->window_stack, &w->stack_neighbour)) {
|
||||
old_below = list_next_entry(w, stack_neighbour)->id;
|
||||
} else {
|
||||
old_below = XCB_NONE;
|
||||
}
|
||||
log_debug("Restack %#010x (%s), old_below: %#010x, new_below: %#010x", w->id,
|
||||
win_get_name_if_managed(w), old_below, below);
|
||||
|
||||
if (old_below != below) {
|
||||
struct list_node *new_next;
|
||||
if (!below) {
|
||||
new_next = &ps->window_stack;
|
||||
} else {
|
||||
struct win *tmp_w = NULL;
|
||||
HASH_FIND_INT(ps->windows, &below, tmp_w);
|
||||
|
||||
if (!tmp_w) {
|
||||
log_error("Failed to found new below window %#010x.", below);
|
||||
return;
|
||||
}
|
||||
|
||||
new_next = &tmp_w->stack_neighbour;
|
||||
}
|
||||
session_restack_win(ps, w, new_next);
|
||||
}
|
||||
}
|
||||
|
||||
void session_restack_bottom(session_t *ps, struct win *w) {
|
||||
session_restack_above(ps, w, 0);
|
||||
}
|
||||
|
||||
void session_restack_top(session_t *ps, struct win *w) {
|
||||
log_debug("Restack %#010x (%s) to top", w->id, win_get_name_if_managed(w));
|
||||
if (&w->stack_neighbour == ps->window_stack.next) {
|
||||
// already at top
|
||||
return;
|
||||
}
|
||||
session_restack_win(ps, w, ps->window_stack.next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear leader cache of all windows.
|
||||
*/
|
||||
void session_clear_cache_win_leaders(session_t *ps) {
|
||||
win_stack_foreach_managed(w, &ps->window_stack) {
|
||||
w->cache_leader = XCB_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
bool session_is_win_region_ignore_valid(session_t *ps, const struct managed_win *w) {
|
||||
win_stack_foreach_managed(i, &ps->window_stack) {
|
||||
if (i == w) {
|
||||
break;
|
||||
}
|
||||
if (!i->reg_ignore_valid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if (!id) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HASH_ITER2(ps->windows, w) {
|
||||
assert(!w->destroyed);
|
||||
if (!w->managed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto mw = (struct managed_win *)w;
|
||||
if (mw->client_win == id) {
|
||||
return mw;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
struct glx_session *session_get_psglx(session_t *ps) {
|
||||
return ps->psglx;
|
||||
}
|
||||
void session_set_psglx(session_t *ps, struct glx_session *psglx) {
|
||||
ps->psglx = psglx;
|
||||
}
|
||||
#endif
|
||||
|
||||
xcb_render_picture_t *session_get_alpha_pictures(session_t *ps) {
|
||||
return ps->alpha_picts;
|
||||
}
|
||||
|
||||
struct x_monitors *session_get_monitors(session_t *ps) {
|
||||
return &ps->monitors;
|
||||
}
|
||||
|
||||
paint_t *session_get_tgt_buffer(session_t *ps) {
|
||||
return &ps->tgt_buffer;
|
||||
}
|
||||
|
||||
xcb_render_picture_t session_get_tgt_picture(session_t *ps) {
|
||||
return ps->tgt_picture;
|
||||
}
|
||||
|
||||
paint_t *session_get_root_tile_paint(session_t *ps) {
|
||||
return &ps->root_tile_paint;
|
||||
}
|
||||
|
||||
bool session_get_root_tile_fill(session_t *ps) {
|
||||
return ps->root_tile_fill;
|
||||
}
|
||||
|
||||
void session_set_root_tile_fill(session_t *ps, bool fill) {
|
||||
ps->root_tile_fill = fill;
|
||||
}
|
||||
|
||||
void session_vsync_wait(session_t *ps) {
|
||||
if (ps->vsync_wait) {
|
||||
ps->vsync_wait(ps);
|
||||
}
|
||||
}
|
||||
|
||||
xcb_render_picture_t session_get_white_picture(session_t *ps) {
|
||||
return ps->white_picture;
|
||||
}
|
||||
|
||||
xcb_render_picture_t session_get_black_picture(session_t *ps) {
|
||||
return ps->black_picture;
|
||||
}
|
||||
|
||||
xcb_render_picture_t session_get_cshadow_picture(session_t *ps) {
|
||||
return ps->cshadow_picture;
|
||||
}
|
||||
|
||||
void session_set_white_picture(session_t *ps, xcb_render_picture_t p) {
|
||||
ps->white_picture = p;
|
||||
}
|
||||
|
||||
void session_set_black_picture(session_t *ps, xcb_render_picture_t p) {
|
||||
ps->black_picture = p;
|
||||
}
|
||||
|
||||
void session_set_cshadow_picture(session_t *ps, xcb_render_picture_t p) {
|
||||
ps->cshadow_picture = p;
|
||||
}
|
||||
|
||||
region_t *session_get_screen_reg(session_t *ps) {
|
||||
return &ps->screen_reg;
|
||||
}
|
||||
|
||||
region_t *session_get_shadow_exclude_reg(session_t *ps) {
|
||||
return &ps->shadow_exclude_reg;
|
||||
}
|
||||
|
||||
void session_set_vsync_wait(session_t *ps, int (*vsync_wait)(session_t *)) {
|
||||
ps->vsync_wait = vsync_wait;
|
||||
}
|
||||
|
||||
bool session_has_glx_extension(session_t *ps) {
|
||||
return ps->glx_exists;
|
||||
}
|
||||
|
||||
bool session_has_shape_extension(session_t *ps) {
|
||||
return ps->shape_exists;
|
||||
}
|
||||
|
||||
bool session_has_present_extension(session_t *ps) {
|
||||
return ps->present_exists;
|
||||
}
|
||||
|
||||
bool session_has_xsync_extension(session_t *ps) {
|
||||
return ps->xsync_exists;
|
||||
}
|
||||
|
||||
bool session_has_randr_extension(session_t *ps) {
|
||||
return ps->randr_exists;
|
||||
}
|
||||
|
||||
int session_get_xfixes_extension_error(session_t *ps) {
|
||||
return ps->xfixes_error;
|
||||
}
|
||||
|
||||
int session_get_render_extension_error(session_t *ps) {
|
||||
return ps->render_error;
|
||||
}
|
||||
|
||||
int session_get_damage_extension_error(session_t *ps) {
|
||||
return ps->damage_error;
|
||||
}
|
||||
|
||||
int session_get_glx_extension_error(session_t *ps) {
|
||||
return ps->glx_error;
|
||||
}
|
||||
|
||||
int session_get_xsync_extension_error(session_t *ps) {
|
||||
return ps->xsync_error;
|
||||
}
|
||||
|
||||
int session_get_xsync_extention_event(session_t *ps) {
|
||||
return ps->xsync_event;
|
||||
}
|
||||
|
||||
int session_get_damage_extention_event(session_t *ps) {
|
||||
return ps->damage_event;
|
||||
}
|
||||
|
||||
int session_get_shape_extention_event(session_t *ps) {
|
||||
return ps->shape_event;
|
||||
}
|
||||
|
||||
int session_get_randr_extention_event(session_t *ps) {
|
||||
return ps->randr_event;
|
||||
}
|
||||
|
||||
void session_xsync_wait_fence(session_t *ps) {
|
||||
if (ps->o.xrender_sync_fence && ps->xsync_exists &&
|
||||
!x_fence_sync(&ps->c, ps->sync_fence)) {
|
||||
log_error("x_fence_sync failed, xrender-sync-fence will be "
|
||||
"disabled from now on.");
|
||||
xcb_sync_destroy_fence(ps->c.c, ps->sync_fence);
|
||||
ps->sync_fence = XCB_NONE;
|
||||
ps->o.xrender_sync_fence = false;
|
||||
ps->xsync_exists = false;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t session_redirection_mode(session_t *ps) {
|
||||
if (ps->o.debug_mode) {
|
||||
|
@ -1679,7 +2418,7 @@ static void handle_new_windows(session_t *ps) {
|
|||
}
|
||||
// Send D-Bus signal
|
||||
if (ps->o.dbus) {
|
||||
cdbus_ev_win_added(ps->dbus_data, new_w);
|
||||
cdbus_ev_win_added(session_get_cdbus(ps), new_w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2031,9 +2770,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
|||
.tgt_picture = XCB_NONE,
|
||||
.tgt_buffer = PAINT_INIT,
|
||||
.reg_win = XCB_NONE,
|
||||
#ifdef CONFIG_OPENGL
|
||||
.glx_prog_win = GLX_PROG_MAIN_INIT,
|
||||
#endif
|
||||
.redirected = false,
|
||||
.alpha_picts = NULL,
|
||||
.fade_time = 0L,
|
||||
|
@ -2413,9 +3149,12 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
|||
apply_driver_workarounds(ps, ps->drivers);
|
||||
|
||||
// Initialize filters, must be preceded by OpenGL context creation
|
||||
if (ps->o.legacy_backends && !init_render(ps)) {
|
||||
log_fatal("Failed to initialize the backend");
|
||||
exit(1);
|
||||
if (ps->o.legacy_backends) {
|
||||
ps->alpha_picts = ccalloc(MAX_ALPHA + 1, xcb_render_picture_t);
|
||||
if (!init_render(ps)) {
|
||||
log_fatal("Failed to initialize the backend");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (ps->o.print_diagnostics) {
|
||||
|
@ -2554,7 +3293,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
|||
nchildren = xcb_query_tree_children_length(query_tree_reply);
|
||||
|
||||
for (int i = 0; i < nchildren; i++) {
|
||||
add_win_above(ps, children[i], i ? children[i - 1] : XCB_NONE);
|
||||
session_add_win_above(ps, children[i], i ? children[i - 1] : XCB_NONE);
|
||||
}
|
||||
free(query_tree_reply);
|
||||
}
|
||||
|
@ -2697,16 +3436,15 @@ static void session_destroy(session_t *ps) {
|
|||
// backend is deinitialized in unredirect()
|
||||
assert(ps->backend_data == NULL);
|
||||
} else {
|
||||
// Free all GLX resources of windows
|
||||
win_stack_foreach_managed(w, &ps->window_stack) {
|
||||
free_win_res_glx(ps, w);
|
||||
}
|
||||
deinit_render(ps);
|
||||
free(ps->alpha_picts);
|
||||
ps->alpha_picts = NULL;
|
||||
}
|
||||
|
||||
#if CONFIG_OPENGL
|
||||
if (glx_has_context(ps)) {
|
||||
// GLX context created, but not for rendering
|
||||
glx_destroy(ps);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Flush all events
|
||||
xcb_aux_sync(ps->c.c);
|
||||
ev_io_stop(ps->loop, &ps->xiow);
|
||||
|
|
148
src/picom.h
148
src/picom.h
|
@ -1,29 +1,25 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c)
|
||||
|
||||
// Throw everything in here.
|
||||
// !!! DON'T !!!
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright (c) Yuxuan Shui.
|
||||
|
||||
// === Includes ===
|
||||
|
||||
#include <locale.h>
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
#include <X11/Xutil.h>
|
||||
#include "backend/backend.h"
|
||||
#include "backend/driver.h"
|
||||
#include "c2.h"
|
||||
#include "common.h"
|
||||
#include "compiler.h"
|
||||
#include "config.h"
|
||||
#include "log.h" // XXX clean up
|
||||
#include "ev.h"
|
||||
#include "list.h"
|
||||
#include "region.h"
|
||||
#include "render.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "win.h"
|
||||
#include "x.h"
|
||||
#include "xcb/render.h"
|
||||
|
||||
enum root_flags {
|
||||
ROOT_FLAGS_SCREEN_CHANGE = 1, // Received RandR screen change notify, we
|
||||
|
@ -31,28 +27,120 @@ enum root_flags {
|
|||
ROOT_FLAGS_CONFIGURED = 2 // Received configure notify on the root window
|
||||
};
|
||||
|
||||
// == Functions ==
|
||||
// TODO(yshui) move static inline functions that are only used in picom.c, into picom.c
|
||||
|
||||
void add_damage(session_t *ps, const region_t *damage);
|
||||
|
||||
uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode);
|
||||
|
||||
void circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce);
|
||||
|
||||
void root_damaged(session_t *ps);
|
||||
|
||||
void queue_redraw(session_t *ps);
|
||||
|
||||
void discard_pending(session_t *ps, uint32_t sequence);
|
||||
|
||||
void set_root_flags(session_t *ps, uint64_t flags);
|
||||
|
||||
void quit(session_t *ps);
|
||||
|
||||
xcb_window_t session_get_target_window(session_t *);
|
||||
|
||||
uint8_t session_redirection_mode(session_t *ps);
|
||||
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);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
struct cdbus_data *session_get_cdbus(struct session *);
|
||||
|
@ -99,17 +187,3 @@ static inline void
|
|||
free_win_res_glx(session_t *ps attr_unused, struct managed_win *w attr_unused) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Dump an drawable's info.
|
||||
*/
|
||||
static inline void dump_drawable(session_t *ps, xcb_drawable_t drawable) {
|
||||
auto r = xcb_get_geometry_reply(ps->c.c, xcb_get_geometry(ps->c.c, drawable), NULL);
|
||||
if (!r) {
|
||||
log_trace("Drawable %#010x: Failed", drawable);
|
||||
return;
|
||||
}
|
||||
log_trace("Drawable %#010x: x = %u, y = %u, wid = %u, hei = %d, b = %u, d = %u",
|
||||
drawable, r->x, r->y, r->width, r->height, r->border_width, r->depth);
|
||||
free(r);
|
||||
}
|
||||
|
|
618
src/render.c
618
src/render.c
File diff suppressed because it is too large
Load diff
21
src/vsync.c
21
src/vsync.c
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
#include "picom.h"
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
#include "backend/gl/glx.h"
|
||||
|
@ -105,7 +106,8 @@ static inline bool vsync_opengl_swc_swap_interval(session_t *ps, int interval) {
|
|||
// We don't have a context??
|
||||
return false;
|
||||
}
|
||||
glXSwapIntervalEXT(ps->c.dpy, glXGetCurrentDrawable(), interval);
|
||||
glXSwapIntervalEXT(session_get_x_connection(ps)->dpy,
|
||||
glXGetCurrentDrawable(), interval);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -143,9 +145,11 @@ static int vsync_opengl_wait(session_t *ps attr_unused) {
|
|||
*/
|
||||
static int vsync_opengl_oml_wait(session_t *ps) {
|
||||
int64_t ust = 0, msc = 0, sbc = 0;
|
||||
auto c = session_get_x_connection(ps);
|
||||
|
||||
glXGetSyncValuesOML(ps->c.dpy, ps->reg_win, &ust, &msc, &sbc);
|
||||
glXWaitForMscOML(ps->c.dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc);
|
||||
glXGetSyncValuesOML(c->dpy, session_get_target_window(ps), &ust, &msc, &sbc);
|
||||
glXWaitForMscOML(c->dpy, session_get_target_window(ps), 0, 2, (msc + 1) % 2, &ust,
|
||||
&msc, &sbc);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -164,7 +168,7 @@ bool vsync_init(session_t *ps) {
|
|||
log_warn("The DRM vsync method is deprecated, please don't enable it.");
|
||||
#endif
|
||||
|
||||
if (!ps->o.vsync) {
|
||||
if (!session_get_options(ps)->vsync) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -173,8 +177,9 @@ bool vsync_init(session_t *ps) {
|
|||
if (!vsync_opengl_swc_init(ps)) {
|
||||
return false;
|
||||
}
|
||||
ps->vsync_wait = NULL; // glXSwapBuffers will automatically wait
|
||||
// for vsync, we don't need to do anything.
|
||||
// glXSwapBuffers will automatically wait for vsync, we don't
|
||||
// need to do anything.
|
||||
session_set_vsync_wait(ps, NULL);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -184,13 +189,13 @@ bool vsync_init(session_t *ps) {
|
|||
#ifdef CONFIG_OPENGL
|
||||
if (vsync_opengl_oml_init(ps)) {
|
||||
log_info("Using the opengl-oml vsync method");
|
||||
ps->vsync_wait = vsync_opengl_oml_wait;
|
||||
session_set_vsync_wait(ps, vsync_opengl_oml_wait);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (vsync_opengl_init(ps)) {
|
||||
log_info("Using the opengl vsync method");
|
||||
ps->vsync_wait = vsync_opengl_wait;
|
||||
session_set_vsync_wait(ps, vsync_opengl_wait);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
|
30
src/win.h
30
src/win.h
|
@ -340,11 +340,11 @@ bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w);
|
|||
void win_update_monitor(struct x_monitors *monitors, struct managed_win *mw);
|
||||
|
||||
/// Recheck if a window is fullscreen
|
||||
void win_update_is_fullscreen(const session_t *ps, struct managed_win *w);
|
||||
void win_update_is_fullscreen(session_t *ps, struct managed_win *w);
|
||||
/**
|
||||
* Check if a window has BYPASS_COMPOSITOR property set
|
||||
*/
|
||||
bool win_is_bypassing_compositor(const session_t *ps, const struct managed_win *w);
|
||||
bool win_is_bypassing_compositor(session_t *ps, const struct managed_win *w);
|
||||
/**
|
||||
* Get a rectangular region in global coordinates a window (and possibly
|
||||
* its shadow) occupies.
|
||||
|
@ -373,20 +373,9 @@ void win_get_region_noframe_local_without_corners(const struct managed_win *w, r
|
|||
void win_get_region_frame_local(const struct managed_win *w, region_t *res);
|
||||
/// Get the region for the frame of the window, by value
|
||||
region_t win_get_region_frame_local_by_val(const struct managed_win *w);
|
||||
/// 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 *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 *add_win_top(session_t *ps, xcb_window_t id);
|
||||
/// Query the Xorg for information about window `win`
|
||||
/// `win` pointer might become invalid after this function returns
|
||||
struct win *attr_ret_nonnull maybe_allocate_managed_win(session_t *ps, struct win *win);
|
||||
/// Move window `w` to be right above `below`
|
||||
void restack_above(session_t *ps, struct win *w, xcb_window_t below);
|
||||
/// Move window `w` to the bottom of the stack
|
||||
void restack_bottom(session_t *ps, struct win *w);
|
||||
/// Move window `w` to the top of the stack
|
||||
void restack_top(session_t *ps, struct win *w);
|
||||
|
||||
/**
|
||||
* Release a destroyed window that is no longer needed.
|
||||
|
@ -403,8 +392,6 @@ void win_skip_fading(struct managed_win *w);
|
|||
* Find a managed window from window id in window linked list of the session.
|
||||
*/
|
||||
struct managed_win *find_managed_win(session_t *ps, xcb_window_t id);
|
||||
struct win *find_win(session_t *ps, xcb_window_t id);
|
||||
struct managed_win *find_toplevel(session_t *ps, xcb_window_t id);
|
||||
/**
|
||||
* Find a managed window that is, or is a parent of `wid`.
|
||||
*
|
||||
|
@ -429,15 +416,16 @@ static inline bool attr_pure win_is_wmwin(const struct managed_win *w) {
|
|||
return w->base.id == w->client_win && !w->a.override_redirect;
|
||||
}
|
||||
|
||||
/// check if reg_ignore_valid is true for all windows above us
|
||||
bool attr_pure win_is_region_ignore_valid(session_t *ps, const struct managed_win *w);
|
||||
static inline const char *win_get_name_if_managed(const struct win *w) {
|
||||
if (!w->managed) {
|
||||
return "(unmanaged)";
|
||||
}
|
||||
auto mw = (struct managed_win *)w;
|
||||
return mw->name;
|
||||
}
|
||||
|
||||
/// Whether a given window is mapped on the X server side
|
||||
bool win_is_mapped_in_x(const struct managed_win *w);
|
||||
|
||||
// Find the managed window immediately below `w` in the window stack
|
||||
struct managed_win *attr_pure win_stack_find_next_managed(const session_t *ps,
|
||||
const struct list_node *w);
|
||||
/// Set flags on a window. Some sanity checks are performed
|
||||
void win_set_flags(struct managed_win *w, uint64_t flags);
|
||||
/// Clear flags on a window. Some sanity checks are performed
|
||||
|
|
17
src/x.c
17
src/x.c
|
@ -21,6 +21,7 @@
|
|||
#include <xcb/xfixes.h>
|
||||
|
||||
#include "atom.h"
|
||||
#include "picom.h"
|
||||
#ifdef CONFIG_OPENGL
|
||||
#include "backend/gl/glx.h"
|
||||
#endif
|
||||
|
@ -49,7 +50,7 @@ static int xerror(Display attr_unused *dpy, XErrorEvent *ev) {
|
|||
xcb_err.major_code = ev->request_code;
|
||||
xcb_err.minor_code = ev->minor_code;
|
||||
xcb_err.error_code = ev->error_code;
|
||||
x_handle_error(&ps_g->c, &xcb_err);
|
||||
x_handle_error(session_get_x_connection(ps_g), &xcb_err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -588,13 +589,13 @@ _x_strerror(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_c
|
|||
case XCB_##s: name = #s; break
|
||||
|
||||
// TODO(yshui) separate error code out from session_t
|
||||
o = error_code - ps->xfixes_error;
|
||||
o = error_code - session_get_xfixes_extension_error(ps);
|
||||
switch (o) { CASESTRRET2(XFIXES_BAD_REGION); }
|
||||
|
||||
o = error_code - ps->damage_error;
|
||||
o = error_code - session_get_damage_extension_error(ps);
|
||||
switch (o) { CASESTRRET2(DAMAGE_BAD_DAMAGE); }
|
||||
|
||||
o = error_code - ps->render_error;
|
||||
o = error_code - session_get_render_extension_error(ps);
|
||||
switch (o) {
|
||||
CASESTRRET2(RENDER_PICT_FORMAT);
|
||||
CASESTRRET2(RENDER_PICTURE);
|
||||
|
@ -603,8 +604,8 @@ _x_strerror(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_c
|
|||
CASESTRRET2(RENDER_GLYPH);
|
||||
}
|
||||
|
||||
if (ps->glx_exists) {
|
||||
o = error_code - ps->glx_error;
|
||||
if (session_has_glx_extension(ps)) {
|
||||
o = error_code - session_get_glx_extension_error(ps);
|
||||
switch (o) {
|
||||
CASESTRRET2(GLX_BAD_CONTEXT);
|
||||
CASESTRRET2(GLX_BAD_CONTEXT_STATE);
|
||||
|
@ -623,8 +624,8 @@ _x_strerror(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_c
|
|||
}
|
||||
}
|
||||
|
||||
if (ps->xsync_exists) {
|
||||
o = error_code - ps->xsync_error;
|
||||
if (session_get_xsync_extension_error(ps)) {
|
||||
o = error_code - session_get_xsync_extension_error(ps);
|
||||
switch (o) {
|
||||
CASESTRRET(XSyncBadCounter);
|
||||
CASESTRRET(XSyncBadAlarm);
|
||||
|
|
Loading…
Add table
Reference in a new issue