mirror of https://github.com/yshui/picom.git
WIP core: struct sesion is now opaque
This commit is contained in:
parent
4c8515cf50
commit
959f400ae1
|
@ -9,6 +9,7 @@
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "picom.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "transition.h"
|
#include "transition.h"
|
||||||
#include "types.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 get_damage(session_t *ps, bool all_damage) {
|
||||||
region_t region;
|
region_t region;
|
||||||
auto buffer_age_fn = ps->backend_data->ops->buffer_age;
|
auto backend_data = session_get_backend_data(ps);
|
||||||
int buffer_age = buffer_age_fn ? buffer_age_fn(ps->backend_data) : -1;
|
auto buffer_age_fn = backend_data->ops->buffer_age;
|
||||||
|
int buffer_age = buffer_age_fn ? buffer_age_fn(backend_data) : -1;
|
||||||
|
|
||||||
if (all_damage) {
|
if (all_damage) {
|
||||||
buffer_age = -1;
|
buffer_age = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_init(®ion);
|
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;
|
return region;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +72,7 @@ void handle_device_reset(session_t *ps) {
|
||||||
|
|
||||||
// Reset picom
|
// Reset picom
|
||||||
log_info("Resetting picom after device reset");
|
log_info("Resetting picom after device reset");
|
||||||
ev_break(ps->loop, EVBREAK_ALL);
|
ev_break(session_get_mainloop(ps), EVBREAK_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// paint all windows
|
/// paint all windows
|
||||||
|
@ -78,34 +81,31 @@ void handle_device_reset(session_t *ps) {
|
||||||
/// this function will return false.
|
/// this function will return false.
|
||||||
bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
||||||
struct timespec now = get_time_timespec();
|
struct timespec now = get_time_timespec();
|
||||||
|
uint64_t after_sync_fence_us = 0, after_damage_us = 0;
|
||||||
auto paint_all_start_us =
|
auto paint_all_start_us =
|
||||||
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
|
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
|
||||||
if (ps->backend_data->ops->device_status &&
|
auto backend_data = session_get_backend_data(ps);
|
||||||
ps->backend_data->ops->device_status(ps->backend_data) != DEVICE_STATUS_NORMAL) {
|
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);
|
handle_device_reset(ps);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ps->o.xrender_sync_fence) {
|
session_xsync_wait_fence(ps);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (unlikely(log_get_level_tls() > LOG_LEVEL_TRACE)) {
|
||||||
now = get_time_timespec();
|
now = get_time_timespec();
|
||||||
auto after_sync_fence_us =
|
after_sync_fence_us =
|
||||||
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
|
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
|
||||||
log_trace("Time spent on sync fence: %" PRIu64 " us",
|
log_trace("Time spent on sync fence: %" PRIu64 " us",
|
||||||
after_sync_fence_us - paint_all_start_us);
|
after_sync_fence_us - paint_all_start_us);
|
||||||
|
}
|
||||||
// All painting will be limited to the damage, if _some_ of
|
// All painting will be limited to the damage, if _some_ of
|
||||||
// the paints bleed out of the damage region, it will destroy
|
// the paints bleed out of the damage region, it will destroy
|
||||||
// part of the image we want to reuse
|
// part of the image we want to reuse
|
||||||
region_t reg_damage;
|
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)) {
|
if (!pixman_region32_not_empty(®_damage)) {
|
||||||
pixman_region32_fini(®_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
|
/// The adjusted damaged regions
|
||||||
region_t reg_paint;
|
region_t reg_paint;
|
||||||
assert(ps->o.blur_method != BLUR_METHOD_INVALID);
|
region_t *screen_reg = session_get_screen_reg(ps);
|
||||||
if (ps->o.blur_method != BLUR_METHOD_NONE && ps->backend_data->ops->get_blur_size) {
|
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;
|
int blur_width, blur_height;
|
||||||
ps->backend_data->ops->get_blur_size(ps->backend_blur_context,
|
backend_data->ops->get_blur_size(backend_blur_context, &blur_width,
|
||||||
&blur_width, &blur_height);
|
&blur_height);
|
||||||
|
|
||||||
// The region of screen a given window influences will be smeared
|
// The region of screen a given window influences will be smeared
|
||||||
// out by blur. With more windows on top of the given window, the
|
// 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);
|
blur_height * resize_factor);
|
||||||
reg_paint = resize_region(®_damage, blur_width * resize_factor,
|
reg_paint = resize_region(®_damage, blur_width * resize_factor,
|
||||||
blur_height * resize_factor);
|
blur_height * resize_factor);
|
||||||
pixman_region32_intersect(®_paint, ®_paint, &ps->screen_reg);
|
pixman_region32_intersect(®_paint, ®_paint, screen_reg);
|
||||||
pixman_region32_intersect(®_damage, ®_damage, &ps->screen_reg);
|
pixman_region32_intersect(®_damage, ®_damage, screen_reg);
|
||||||
} else {
|
} else {
|
||||||
pixman_region32_init(®_paint);
|
pixman_region32_init(®_paint);
|
||||||
pixman_region32_copy(®_paint, ®_damage);
|
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
|
// backend can optimize based on this info
|
||||||
region_t reg_visible;
|
region_t reg_visible;
|
||||||
pixman_region32_init(®_visible);
|
pixman_region32_init(®_visible);
|
||||||
pixman_region32_copy(®_visible, &ps->screen_reg);
|
pixman_region32_copy(®_visible, screen_reg);
|
||||||
if (t && !ps->o.transparent_clipping) {
|
if (t && !options->transparent_clipping) {
|
||||||
// Calculate the region upon which the root window (wallpaper) is to be
|
// Calculate the region upon which the root window (wallpaper) is to be
|
||||||
// painted based on the ignore region of the lowest window, if available
|
// 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;
|
region_t reg_shadow_clip;
|
||||||
pixman_region32_init(®_shadow_clip);
|
pixman_region32_init(®_shadow_clip);
|
||||||
|
|
||||||
|
if (unlikely(log_get_level_tls() > LOG_LEVEL_TRACE)) {
|
||||||
now = get_time_timespec();
|
now = get_time_timespec();
|
||||||
auto after_damage_us = (uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
|
after_damage_us =
|
||||||
log_trace("Getting damage took %" PRIu64 " us", after_damage_us - after_sync_fence_us);
|
(uint64_t)now.tv_sec * 1000000UL + (uint64_t)now.tv_nsec / 1000;
|
||||||
if (ps->next_render > 0) {
|
log_trace("Getting damage took %" PRIu64 " us",
|
||||||
log_verbose("Render schedule deviation: %ld us (%s) %" PRIu64 " %" PRIu64,
|
after_damage_us - after_sync_fence_us);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
session_record_cpu_time(ps);
|
||||||
|
|
||||||
|
if (backend_data->ops->prepare) {
|
||||||
|
backend_data->ops->prepare(backend_data, ®_paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps->backend_data->ops->prepare) {
|
auto root_image = session_get_root_image(ps);
|
||||||
ps->backend_data->ops->prepare(ps->backend_data, ®_paint);
|
if (root_image) {
|
||||||
}
|
backend_data->ops->compose(backend_data, root_image, (coord_t){0}, NULL,
|
||||||
|
(coord_t){0}, ®_paint, ®_visible);
|
||||||
if (ps->root_image) {
|
|
||||||
ps->backend_data->ops->compose(ps->backend_data, ps->root_image,
|
|
||||||
(coord_t){0}, NULL, (coord_t){0},
|
|
||||||
®_paint, ®_visible);
|
|
||||||
} else {
|
} else {
|
||||||
ps->backend_data->ops->fill(ps->backend_data, (struct color){0, 0, 0, 1},
|
backend_data->ops->fill(backend_data, (struct color){0, 0, 0, 1}, ®_paint);
|
||||||
®_paint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Windows are sorted from bottom to top
|
// 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
|
// Whether this is beneficial is to be determined XXX
|
||||||
for (struct managed_win *w = t; w; w = w->prev_trans) {
|
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_IMAGE_ERROR));
|
||||||
assert(!(w->flags & WIN_FLAGS_PIXMAP_STALE));
|
assert(!(w->flags & WIN_FLAGS_PIXMAP_STALE));
|
||||||
assert(!(w->flags & WIN_FLAGS_PIXMAP_NONE));
|
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);
|
win_get_bounding_shape_global_without_corners_by_val(w);
|
||||||
|
|
||||||
if (!w->mask_image && (w->bounding_shaped || w->corner_radius != 0)) {
|
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
|
// 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;
|
region_t reg_paint_in_bound;
|
||||||
pixman_region32_init(®_paint_in_bound);
|
pixman_region32_init(®_paint_in_bound);
|
||||||
pixman_region32_intersect(®_paint_in_bound, ®_bound, ®_paint);
|
pixman_region32_intersect(®_paint_in_bound, ®_bound, ®_paint);
|
||||||
if (ps->o.transparent_clipping) {
|
if (options->transparent_clipping) {
|
||||||
// <transparent-clipping-note>
|
// <transparent-clipping-note>
|
||||||
// If transparent_clipping is enabled, we need to be SURE that
|
// If transparent_clipping is enabled, we need to be SURE that
|
||||||
// things are not drawn inside reg_ignore, because otherwise they
|
// 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);
|
const double window_opacity = animatable_get(&w->opacity);
|
||||||
if (w->blur_background &&
|
if (w->blur_background &&
|
||||||
(ps->o.force_win_blend || real_win_mode == WMODE_TRANS ||
|
(options->force_win_blend || real_win_mode == WMODE_TRANS ||
|
||||||
(ps->o.blur_background_frame && real_win_mode == WMODE_FRAME_TRANS))) {
|
(options->blur_background_frame && real_win_mode == WMODE_FRAME_TRANS))) {
|
||||||
// Minimize the region we try to blur, if the window
|
// Minimize the region we try to blur, if the window
|
||||||
// itself is not opaque, only the frame is.
|
// 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) {
|
if (blur_opacity * MAX_ALPHA < 1) {
|
||||||
// We don't need to blur if it would be completely
|
// We don't need to blur if it would be completely
|
||||||
// transparent
|
// 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
|
// We need to blur the bounding shape of the window
|
||||||
// (reg_paint_in_bound = reg_bound \cap reg_paint)
|
// (reg_paint_in_bound = reg_bound \cap reg_paint)
|
||||||
ps->backend_data->ops->blur(
|
backend_data->ops->blur(backend_data, blur_opacity,
|
||||||
ps->backend_data, blur_opacity,
|
backend_blur_context,
|
||||||
ps->backend_blur_context, w->mask_image, window_coord,
|
w->mask_image, window_coord,
|
||||||
®_paint_in_bound, ®_visible);
|
®_paint_in_bound, ®_visible);
|
||||||
} else {
|
} else {
|
||||||
// Window itself is solid, we only need to blur the frame
|
// Window itself is solid, we only need to blur the frame
|
||||||
// region
|
// region
|
||||||
|
|
||||||
// Readability assertions
|
// Readability assertions
|
||||||
assert(ps->o.blur_background_frame);
|
assert(options->blur_background_frame);
|
||||||
assert(real_win_mode == WMODE_FRAME_TRANS);
|
assert(real_win_mode == WMODE_FRAME_TRANS);
|
||||||
|
|
||||||
auto reg_blur = win_get_region_frame_local_by_val(w);
|
auto reg_blur = win_get_region_frame_local_by_val(w);
|
||||||
pixman_region32_translate(®_blur, w->g.x, w->g.y);
|
pixman_region32_translate(®_blur, w->g.x, w->g.y);
|
||||||
// make sure reg_blur \in reg_paint
|
// make sure reg_blur \in reg_paint
|
||||||
pixman_region32_intersect(®_blur, ®_blur, ®_paint);
|
pixman_region32_intersect(®_blur, ®_blur, ®_paint);
|
||||||
if (ps->o.transparent_clipping) {
|
if (options->transparent_clipping) {
|
||||||
// ref: <transparent-clipping-note>
|
// ref: <transparent-clipping-note>
|
||||||
pixman_region32_intersect(®_blur, ®_blur,
|
pixman_region32_intersect(®_blur, ®_blur,
|
||||||
®_visible);
|
®_visible);
|
||||||
}
|
}
|
||||||
ps->backend_data->ops->blur(
|
backend_data->ops->blur(
|
||||||
ps->backend_data, blur_opacity, ps->backend_blur_context,
|
backend_data, blur_opacity, backend_blur_context,
|
||||||
w->mask_image, window_coord, ®_blur, ®_visible);
|
w->mask_image, window_coord, ®_blur, ®_visible);
|
||||||
pixman_region32_fini(®_blur);
|
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
|
// 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.
|
// has shadow enabled because it disables shadow for a window on failure.
|
||||||
if (w->shadow && !w->shadow_image) {
|
if (w->shadow && !w->shadow_image) {
|
||||||
struct color shadow_color = {.red = ps->o.shadow_red,
|
struct color shadow_color = {.red = options->shadow_red,
|
||||||
.green = ps->o.shadow_green,
|
.green = options->shadow_green,
|
||||||
.blue = ps->o.shadow_blue,
|
.blue = options->shadow_blue,
|
||||||
.alpha = ps->o.shadow_opacity};
|
.alpha = options->shadow_opacity};
|
||||||
win_bind_shadow(ps->backend_data, w, shadow_color, ps->shadow_context);
|
win_bind_shadow(backend_data, w, shadow_color,
|
||||||
|
session_get_backend_shadow_context(ps));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw shadow on target
|
// 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);
|
pixman_region32_intersect(®_shadow, ®_shadow, ®_paint);
|
||||||
|
|
||||||
// Mask out the region we don't want shadow on
|
// 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,
|
pixman_region32_subtract(®_shadow, ®_shadow,
|
||||||
&ps->shadow_exclude_reg);
|
shadow_exclude_reg);
|
||||||
}
|
}
|
||||||
if (pixman_region32_not_empty(®_shadow_clip)) {
|
if (pixman_region32_not_empty(®_shadow_clip)) {
|
||||||
pixman_region32_subtract(®_shadow, ®_shadow,
|
pixman_region32_subtract(®_shadow, ®_shadow,
|
||||||
®_shadow_clip);
|
®_shadow_clip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps->o.crop_shadow_to_monitor && w->randr_monitor >= 0 &&
|
auto monitors = session_get_monitors(ps);
|
||||||
w->randr_monitor < ps->monitors.count) {
|
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
|
// There can be a window where number of monitors is
|
||||||
// updated, but the monitor number attached to the window
|
// updated, but the monitor number attached to the window
|
||||||
// have not.
|
// 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
|
// Window monitor number will be updated eventually, so
|
||||||
// here we just check to make sure we don't access out of
|
// here we just check to make sure we don't access out of
|
||||||
// bounds.
|
// bounds.
|
||||||
pixman_region32_intersect(
|
pixman_region32_intersect(®_shadow, ®_shadow,
|
||||||
®_shadow, ®_shadow,
|
&monitors->regions[w->randr_monitor]);
|
||||||
&ps->monitors.regions[w->randr_monitor]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps->o.transparent_clipping) {
|
if (options->transparent_clipping) {
|
||||||
// ref: <transparent-clipping-note>
|
// ref: <transparent-clipping-note>
|
||||||
pixman_region32_intersect(®_shadow, ®_shadow,
|
pixman_region32_intersect(®_shadow, ®_shadow,
|
||||||
®_visible);
|
®_visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(w->shadow_image);
|
assert(w->shadow_image);
|
||||||
ps->backend_data->ops->set_image_property(
|
backend_data->ops->set_image_property(
|
||||||
ps->backend_data, IMAGE_PROPERTY_OPACITY, w->shadow_image,
|
backend_data, IMAGE_PROPERTY_OPACITY, w->shadow_image, &w->opacity);
|
||||||
&w->opacity);
|
|
||||||
coord_t shadow_coord = {.x = w->g.x + w->shadow_dx,
|
coord_t shadow_coord = {.x = w->g.x + w->shadow_dx,
|
||||||
.y = w->g.y + w->shadow_dy};
|
.y = w->g.y + w->shadow_dy};
|
||||||
|
|
||||||
auto inverted_mask = NULL;
|
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,
|
pixman_region32_subtract(®_shadow, ®_shadow,
|
||||||
®_bound_no_corner);
|
®_bound_no_corner);
|
||||||
if (w->mask_image) {
|
if (w->mask_image) {
|
||||||
inverted_mask = w->mask_image;
|
inverted_mask = w->mask_image;
|
||||||
ps->backend_data->ops->set_image_property(
|
backend_data->ops->set_image_property(
|
||||||
ps->backend_data, IMAGE_PROPERTY_INVERTED,
|
backend_data, IMAGE_PROPERTY_INVERTED,
|
||||||
inverted_mask, (bool[]){true});
|
inverted_mask, (bool[]){true});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ps->backend_data->ops->compose(
|
backend_data->ops->compose(backend_data, w->shadow_image,
|
||||||
ps->backend_data, w->shadow_image, shadow_coord,
|
shadow_coord, inverted_mask,
|
||||||
inverted_mask, window_coord, ®_shadow, ®_visible);
|
window_coord, ®_shadow, ®_visible);
|
||||||
if (inverted_mask) {
|
if (inverted_mask) {
|
||||||
ps->backend_data->ops->set_image_property(
|
backend_data->ops->set_image_property(
|
||||||
ps->backend_data, IMAGE_PROPERTY_INVERTED,
|
backend_data, IMAGE_PROPERTY_INVERTED, inverted_mask,
|
||||||
inverted_mask, (bool[]){false});
|
(bool[]){false});
|
||||||
}
|
}
|
||||||
pixman_region32_fini(®_shadow);
|
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;
|
double dim_opacity = 0.0;
|
||||||
if (w->dim) {
|
if (w->dim) {
|
||||||
dim_opacity = ps->o.inactive_dim;
|
dim_opacity = options->inactive_dim;
|
||||||
if (!ps->o.inactive_dim_fixed) {
|
if (!options->inactive_dim_fixed) {
|
||||||
dim_opacity *= window_opacity;
|
dim_opacity *= window_opacity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ps->backend_data->ops->set_image_property(
|
backend_data->ops->set_image_property(
|
||||||
ps->backend_data, IMAGE_PROPERTY_MAX_BRIGHTNESS, w->win_image,
|
backend_data, IMAGE_PROPERTY_MAX_BRIGHTNESS, w->win_image,
|
||||||
&ps->o.max_brightness);
|
&options->max_brightness);
|
||||||
ps->backend_data->ops->set_image_property(
|
backend_data->ops->set_image_property(
|
||||||
ps->backend_data, IMAGE_PROPERTY_INVERTED, w->win_image,
|
backend_data, IMAGE_PROPERTY_INVERTED, w->win_image,
|
||||||
&w->invert_color);
|
&w->invert_color);
|
||||||
ps->backend_data->ops->set_image_property(
|
backend_data->ops->set_image_property(backend_data,
|
||||||
ps->backend_data, IMAGE_PROPERTY_DIM_LEVEL, w->win_image,
|
IMAGE_PROPERTY_DIM_LEVEL,
|
||||||
&dim_opacity);
|
w->win_image, &dim_opacity);
|
||||||
ps->backend_data->ops->set_image_property(
|
backend_data->ops->set_image_property(
|
||||||
ps->backend_data, IMAGE_PROPERTY_OPACITY, w->win_image,
|
backend_data, IMAGE_PROPERTY_OPACITY, w->win_image, &window_opacity);
|
||||||
&window_opacity);
|
backend_data->ops->set_image_property(
|
||||||
ps->backend_data->ops->set_image_property(
|
backend_data, IMAGE_PROPERTY_CORNER_RADIUS, w->win_image,
|
||||||
ps->backend_data, IMAGE_PROPERTY_CORNER_RADIUS, w->win_image,
|
|
||||||
(double[]){w->corner_radius});
|
(double[]){w->corner_radius});
|
||||||
if (w->corner_radius) {
|
if (w->corner_radius) {
|
||||||
int border_width = w->g.border_width;
|
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.right,
|
||||||
w->frame_extents.bottom);
|
w->frame_extents.bottom);
|
||||||
}
|
}
|
||||||
ps->backend_data->ops->set_image_property(
|
backend_data->ops->set_image_property(
|
||||||
ps->backend_data, IMAGE_PROPERTY_BORDER_WIDTH,
|
backend_data, IMAGE_PROPERTY_BORDER_WIDTH,
|
||||||
w->win_image, &border_width);
|
w->win_image, &border_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
ps->backend_data->ops->set_image_property(
|
backend_data->ops->set_image_property(
|
||||||
ps->backend_data, IMAGE_PROPERTY_CUSTOM_SHADER, w->win_image,
|
backend_data, IMAGE_PROPERTY_CUSTOM_SHADER, w->win_image,
|
||||||
w->fg_shader ? (void *)w->fg_shader->backend_shader : NULL);
|
w->fg_shader ? (void *)w->fg_shader->backend_shader : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +428,7 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
||||||
|
|
||||||
// Draw window on target
|
// Draw window on target
|
||||||
if (w->frame_opacity == 1) {
|
if (w->frame_opacity == 1) {
|
||||||
ps->backend_data->ops->compose(ps->backend_data, w->win_image,
|
backend_data->ops->compose(backend_data, w->win_image,
|
||||||
window_coord, NULL, window_coord,
|
window_coord, NULL, window_coord,
|
||||||
®_paint_in_bound, ®_visible);
|
®_paint_in_bound, ®_visible);
|
||||||
} else {
|
} else {
|
||||||
|
@ -466,17 +461,17 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
||||||
®_visible_local, ®_visible_local, ®_bound_local);
|
®_visible_local, ®_visible_local, ®_bound_local);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto new_img = ps->backend_data->ops->clone_image(
|
auto new_img = backend_data->ops->clone_image(
|
||||||
ps->backend_data, w->win_image, ®_visible_local);
|
backend_data, w->win_image, ®_visible_local);
|
||||||
auto reg_frame = win_get_region_frame_local_by_val(w);
|
auto reg_frame = win_get_region_frame_local_by_val(w);
|
||||||
ps->backend_data->ops->image_op(
|
backend_data->ops->image_op(backend_data, IMAGE_OP_APPLY_ALPHA,
|
||||||
ps->backend_data, IMAGE_OP_APPLY_ALPHA, new_img, ®_frame,
|
new_img, ®_frame, ®_visible_local,
|
||||||
®_visible_local, (double[]){w->frame_opacity});
|
(double[]){w->frame_opacity});
|
||||||
pixman_region32_fini(®_frame);
|
pixman_region32_fini(®_frame);
|
||||||
ps->backend_data->ops->compose(ps->backend_data, new_img,
|
backend_data->ops->compose(backend_data, new_img, window_coord,
|
||||||
window_coord, NULL, window_coord,
|
NULL, window_coord,
|
||||||
®_paint_in_bound, ®_visible);
|
®_paint_in_bound, ®_visible);
|
||||||
ps->backend_data->ops->release_image(ps->backend_data, new_img);
|
backend_data->ops->release_image(backend_data, new_img);
|
||||||
pixman_region32_fini(®_visible_local);
|
pixman_region32_fini(®_visible_local);
|
||||||
pixman_region32_fini(®_bound_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(®_paint);
|
||||||
pixman_region32_fini(®_shadow_clip);
|
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};
|
const struct color DEBUG_COLOR = {0.5, 0, 0, 0.5};
|
||||||
auto reg_damage_debug = get_damage(ps, false);
|
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);
|
pixman_region32_fini(®_damage_debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the head of the damage ring
|
// 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
|
// Present the rendered scene
|
||||||
// Vsync is done here
|
// Vsync is done here
|
||||||
ps->backend_data->ops->present(ps->backend_data, ®_damage);
|
backend_data->ops->present(backend_data, ®_damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_fini(®_damage);
|
pixman_region32_fini(®_damage);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "picom.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "x.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) {
|
void init_backend_base(struct backend_base *base, session_t *ps) {
|
||||||
base->c = &ps->c;
|
base->c = session_get_x_connection(ps);
|
||||||
base->loop = ps->loop;
|
base->loop = session_get_mainloop(ps);
|
||||||
base->busy = false;
|
base->busy = false;
|
||||||
base->ops = NULL;
|
base->ops = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
/// Apply driver specified global workarounds. It's safe to call this multiple times.
|
/// Apply driver specified global workarounds. It's safe to call this multiple times.
|
||||||
void apply_driver_workarounds(struct session *ps, enum driver driver) {
|
void apply_driver_workarounds(struct session *ps, enum driver driver) {
|
||||||
if (driver & DRIVER_NVIDIA) {
|
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) {
|
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);
|
auto ret = (struct backend_base *)ccalloc(1, struct dummy_data);
|
||||||
ret->c = &ps->c;
|
init_backend_base(ret, ps);
|
||||||
ret->loop = ps->loop;
|
|
||||||
ret->busy = false;
|
|
||||||
return ret;
|
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 = 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[]){
|
(EGLint[]){
|
||||||
EGL_PLATFORM_X11_SCREEN_EXT,
|
EGL_PLATFORM_X11_SCREEN_EXT,
|
||||||
ps->c.screen,
|
c->screen,
|
||||||
EGL_NONE,
|
EGL_NONE,
|
||||||
});
|
});
|
||||||
if (gd->display == EGL_NO_DISPLAY) {
|
if (gd->display == EGL_NO_DISPLAY) {
|
||||||
|
@ -172,7 +173,7 @@ static backend_t *egl_init(session_t *ps, xcb_window_t target) {
|
||||||
goto end;
|
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;
|
EGLConfig config = NULL;
|
||||||
int nconfigs = 1;
|
int nconfigs = 1;
|
||||||
// clang-format off
|
// 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.decouple_texture_user_data = egl_decouple_user_data;
|
||||||
gd->gl.release_user_data = egl_release_image;
|
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)) {
|
if (!egl_set_swap_interval(1, gd->display)) {
|
||||||
log_error("Failed to enable vsync. %#x", eglGetError());
|
log_error("Failed to enable vsync. %#x", eglGetError());
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "picom.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
#include "types.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) {
|
void gl_root_change(backend_t *base, session_t *ps) {
|
||||||
auto gd = (struct gl_data *)base;
|
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]);
|
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
|
|
||||||
gd->dithered_present = ps->o.dithered_present;
|
gd->dithered_present = session_get_options(ps)->dithered_present;
|
||||||
gd->dummy_prog =
|
gd->dummy_prog =
|
||||||
gl_create_program_from_strv((const char *[]){present_vertex_shader, NULL},
|
gl_create_program_from_strv((const char *[]){present_vertex_shader, NULL},
|
||||||
(const char *[]){dummy_frag, 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 *format = gd->dithered_present ? (const GLint[]){GL_RGB16, GL_RGBA16}
|
||||||
: (const GLint[]){GL_RGB8, GL_RGBA8};
|
: (const GLint[]){GL_RGB8, GL_RGBA8};
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
|
auto root_extent = session_get_root_extent(ps);
|
||||||
gd->back_format = format[i];
|
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,
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||||
GL_TEXTURE_2D, gd->back_texture, 0);
|
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) {
|
static backend_t *glx_init(session_t *ps, xcb_window_t target) {
|
||||||
bool success = false;
|
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);
|
auto gd = ccalloc(1, struct _glx_data);
|
||||||
init_backend_base(&gd->gl.base, ps);
|
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;
|
XVisualInfo *pvis = NULL;
|
||||||
|
|
||||||
// Check for GLX extension
|
// Check for GLX extension
|
||||||
if (!ps->glx_exists) {
|
if (!session_has_glx_extension(ps)) {
|
||||||
log_error("No GLX extension.");
|
log_error("No GLX extension.");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get XVisualInfo
|
// Get XVisualInfo
|
||||||
int nitems = 0;
|
int nitems = 0;
|
||||||
XVisualInfo vreq = {.visualid = ps->c.screen_info->root_visual};
|
XVisualInfo vreq = {.visualid = c->screen_info->root_visual};
|
||||||
pvis = XGetVisualInfo(ps->c.dpy, VisualIDMask, &vreq, &nitems);
|
pvis = XGetVisualInfo(c->dpy, VisualIDMask, &vreq, &nitems);
|
||||||
if (!pvis) {
|
if (!pvis) {
|
||||||
log_error("Failed to acquire XVisualInfo for current visual.");
|
log_error("Failed to acquire XVisualInfo for current visual.");
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -270,22 +271,22 @@ static backend_t *glx_init(session_t *ps, xcb_window_t target) {
|
||||||
|
|
||||||
// Ensure the visual is double-buffered
|
// Ensure the visual is double-buffered
|
||||||
int value = 0;
|
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.");
|
log_error("Root visual is not a GL visual.");
|
||||||
goto end;
|
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.");
|
log_error("Root visual lacks stencil buffer.");
|
||||||
goto end;
|
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.");
|
log_error("Root visual is not a double buffered GL visual.");
|
||||||
goto end;
|
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");
|
log_error("Root visual is a color index visual, not supported");
|
||||||
goto end;
|
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
|
// 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.
|
// be sure that the fbconfig is compatible with our target window.
|
||||||
int ncfgs;
|
int ncfgs;
|
||||||
GLXFBConfig *cfg = glXGetFBConfigs(ps->c.dpy, ps->c.screen, &ncfgs);
|
GLXFBConfig *cfg = glXGetFBConfigs(c->dpy, c->screen, &ncfgs);
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (int i = 0; i < ncfgs; i++) {
|
for (int i = 0; i < ncfgs; i++) {
|
||||||
int visualid;
|
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) {
|
if ((VisualID)visualid != pvis->visualid) {
|
||||||
continue;
|
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;
|
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);
|
free(cfg);
|
||||||
|
|
||||||
if (!gd->ctx) {
|
if (!gd->ctx) {
|
||||||
|
@ -344,7 +345,7 @@ static backend_t *glx_init(session_t *ps, xcb_window_t target) {
|
||||||
|
|
||||||
// Attach GLX context
|
// Attach GLX context
|
||||||
GLXDrawable tgt = gd->target_win;
|
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.");
|
log_error("Failed to attach GLX context.");
|
||||||
goto end;
|
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.decouple_texture_user_data = glx_decouple_user_data;
|
||||||
gd->gl.release_user_data = glx_release_image;
|
gd->gl.release_user_data = glx_release_image;
|
||||||
|
|
||||||
if (ps->o.vsync) {
|
if (session_get_options(ps)->vsync) {
|
||||||
if (!glx_set_swap_interval(1, ps->c.dpy, tgt)) {
|
if (!glx_set_swap_interval(1, c->dpy, tgt)) {
|
||||||
log_error("Failed to enable vsync.");
|
log_error("Failed to enable vsync.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
glx_set_swap_interval(0, ps->c.dpy, tgt);
|
glx_set_swap_interval(0, c->dpy, tgt);
|
||||||
}
|
}
|
||||||
|
|
||||||
success = true;
|
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) {
|
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.");
|
log_warn("\"dithered-present\" is not supported by the xrender backend.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -902,29 +904,28 @@ static backend_t *xrender_init(session_t *ps, xcb_window_t target) {
|
||||||
|
|
||||||
for (int i = 0; i <= MAX_ALPHA; ++i) {
|
for (int i = 0; i <= MAX_ALPHA; ++i) {
|
||||||
double o = (double)i / (double)MAX_ALPHA;
|
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);
|
assert(xd->alpha_pict[i] != XCB_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
xd->target_width = ps->root_width;
|
auto root_extent = session_get_root_extent(ps);
|
||||||
xd->target_height = ps->root_height;
|
xd->target_width = root_extent.width;
|
||||||
xd->black_pixel = solid_picture(&ps->c, true, 1, 0, 0, 0);
|
xd->target_height = root_extent.height;
|
||||||
xd->white_pixel = solid_picture(&ps->c, true, 1, 1, 1, 1);
|
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;
|
xd->target_win = target;
|
||||||
xcb_render_create_picture_value_list_t pa = {
|
xcb_render_create_picture_value_list_t pa = {
|
||||||
.subwindowmode = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS,
|
.subwindowmode = XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS,
|
||||||
};
|
};
|
||||||
xd->target = x_create_picture_with_visual_and_pixmap(
|
xd->target = x_create_picture_with_visual_and_pixmap(
|
||||||
&ps->c, ps->c.screen_info->root_visual, xd->target_win,
|
c, c->screen_info->root_visual, xd->target_win, XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
|
||||||
XCB_RENDER_CP_SUBWINDOW_MODE, &pa);
|
|
||||||
|
|
||||||
xd->vsync = ps->o.vsync;
|
xd->vsync = options->vsync;
|
||||||
if (ps->present_exists) {
|
if (session_has_present_extension(ps)) {
|
||||||
auto eid = x_new_id(&ps->c);
|
auto eid = x_new_id(c);
|
||||||
auto e =
|
auto e = xcb_request_check(c->c, xcb_present_select_input_checked(
|
||||||
xcb_request_check(ps->c.c, xcb_present_select_input_checked(
|
c->c, eid, xd->target_win,
|
||||||
ps->c.c, eid, xd->target_win,
|
|
||||||
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY));
|
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY));
|
||||||
if (e) {
|
if (e) {
|
||||||
log_error("Cannot select present input, vsync will be disabled");
|
log_error("Cannot select present input, vsync will be disabled");
|
||||||
|
@ -933,7 +934,7 @@ static backend_t *xrender_init(session_t *ps, xcb_window_t target) {
|
||||||
}
|
}
|
||||||
|
|
||||||
xd->present_event =
|
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) {
|
if (!xd->present_event) {
|
||||||
log_error("Cannot register for special XGE, vsync will be "
|
log_error("Cannot register for special XGE, vsync will be "
|
||||||
"disabled");
|
"disabled");
|
||||||
|
@ -944,22 +945,22 @@ static backend_t *xrender_init(session_t *ps, xcb_window_t target) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xd->vsync) {
|
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
|
// We might need to do double buffering for vsync, and buffer 0 and 1 are for
|
||||||
// double buffering.
|
// double buffering.
|
||||||
int first_buffer_index = xd->vsync ? 0 : 2;
|
int first_buffer_index = xd->vsync ? 0 : 2;
|
||||||
for (int i = first_buffer_index; i < 3; i++) {
|
for (int i = first_buffer_index; i < 3; i++) {
|
||||||
xd->back_pixmap[i] = x_create_pixmap(&ps->c, ps->c.screen_info->root_depth,
|
xd->back_pixmap[i] = x_create_pixmap(c, c->screen_info->root_depth,
|
||||||
to_u16_checked(ps->root_width),
|
to_u16_checked(root_extent.width),
|
||||||
to_u16_checked(ps->root_height));
|
to_u16_checked(root_extent.height));
|
||||||
const uint32_t pic_attrs_mask = XCB_RENDER_CP_REPEAT;
|
const uint32_t pic_attrs_mask = XCB_RENDER_CP_REPEAT;
|
||||||
const xcb_render_create_picture_value_list_t pic_attrs = {
|
const xcb_render_create_picture_value_list_t pic_attrs = {
|
||||||
.repeat = XCB_RENDER_REPEAT_PAD};
|
.repeat = XCB_RENDER_REPEAT_PAD};
|
||||||
xd->back[i] = x_create_picture_with_visual_and_pixmap(
|
xd->back[i] = x_create_picture_with_visual_and_pixmap(
|
||||||
&ps->c, ps->c.screen_info->root_visual, xd->back_pixmap[i],
|
c, c->screen_info->root_visual, xd->back_pixmap[i], pic_attrs_mask,
|
||||||
pic_attrs_mask, &pic_attrs);
|
&pic_attrs);
|
||||||
xd->buffer_age[i] = -1;
|
xd->buffer_age[i] = -1;
|
||||||
if (xd->back_pixmap[i] == XCB_NONE || xd->back[i] == XCB_NONE) {
|
if (xd->back_pixmap[i] == XCB_NONE || xd->back[i] == XCB_NONE) {
|
||||||
log_error("Cannot create pixmap for rendering");
|
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
|
/// Number of damage regions we track
|
||||||
int count;
|
int count;
|
||||||
};
|
};
|
||||||
|
struct session;
|
||||||
/// 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;
|
|
||||||
|
|
||||||
/// Enumeration for window event hints.
|
/// Enumeration for window event hints.
|
||||||
typedef enum { WIN_EVMODE_UNKNOWN, WIN_EVMODE_FRAME, WIN_EVMODE_CLIENT } win_evmode_t;
|
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 tm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
struct options *session_get_options(session_t *ps);
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if current backend uses GLX.
|
* Check if current backend uses GLX.
|
||||||
*/
|
*/
|
||||||
static inline bool bkend_use_glx(session_t *ps) {
|
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]);
|
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) {
|
region_t *region, int buffer_age) {
|
||||||
if (buffer_age == -1 || buffer_age > ring->count) {
|
if (buffer_age == -1 || buffer_age > ring->count) {
|
||||||
pixman_region32_copy(region, all_region);
|
pixman_region32_copy(region, all_region);
|
||||||
|
|
11
src/config.c
11
src/config.c
|
@ -25,6 +25,7 @@
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "picom.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
@ -420,12 +421,14 @@ bool parse_geometry(session_t *ps, const char *src, region_t *dest) {
|
||||||
if (!src) {
|
if (!src) {
|
||||||
return true;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
long x = 0, y = 0;
|
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;
|
long val = 0L;
|
||||||
char *endptr = NULL;
|
char *endptr = NULL;
|
||||||
|
|
||||||
|
@ -472,7 +475,7 @@ bool parse_geometry(session_t *ps, const char *src, region_t *dest) {
|
||||||
if (endptr && src != endptr) {
|
if (endptr && src != endptr) {
|
||||||
x = val;
|
x = val;
|
||||||
if (*src == '-') {
|
if (*src == '-') {
|
||||||
x += ps->root_width - width;
|
x += root_extent.width - width;
|
||||||
}
|
}
|
||||||
src = endptr;
|
src = endptr;
|
||||||
}
|
}
|
||||||
|
@ -485,7 +488,7 @@ bool parse_geometry(session_t *ps, const char *src, region_t *dest) {
|
||||||
if (endptr && src != endptr) {
|
if (endptr && src != endptr) {
|
||||||
y = val;
|
y = val;
|
||||||
if (*src == '-') {
|
if (*src == '-') {
|
||||||
y += ps->root_height - height;
|
y += root_extent.height - height;
|
||||||
}
|
}
|
||||||
src = endptr;
|
src = endptr;
|
||||||
}
|
}
|
||||||
|
|
163
src/dbus.c
163
src/dbus.c
|
@ -24,12 +24,11 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "dbus/dbus-protocol.h"
|
#include "dbus/dbus-protocol.h"
|
||||||
#include "dbus/dbus-shared.h"
|
#include "dbus/dbus-shared.h"
|
||||||
#include "list.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "picom.h"
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
#include "transition.h"
|
#include "transition.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "uthash_extra.h"
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "win_defs.h"
|
#include "win_defs.h"
|
||||||
|
@ -163,7 +162,7 @@ struct cdbus_data *cdbus_init(session_t *ps, const char *uniq) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add watch handlers
|
// 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,
|
if (!dbus_connection_set_watch_functions(cd->dbus_conn, cdbus_callback_add_watch,
|
||||||
cdbus_callback_remove_watch,
|
cdbus_callback_remove_watch,
|
||||||
cdbus_callback_watch_toggled, cd, NULL)) {
|
cdbus_callback_watch_toggled, cd, NULL)) {
|
||||||
|
@ -472,41 +471,45 @@ static bool cdbus_append_string_variant(DBusMessage *msg, const char *data) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append all window IDs in the window list of a session to a D-Bus message
|
struct cdbus_append_wids_data {
|
||||||
static bool cdbus_append_wids(DBusMessage *msg, session_t *ps) {
|
DBusMessageIter iter;
|
||||||
// Get the number of wids we are to include
|
bool success;
|
||||||
unsigned count = 0;
|
};
|
||||||
HASH_ITER2(ps->windows, w) {
|
|
||||||
|
static void cdbus_append_wids_callback(struct win *w, void *user_data) {
|
||||||
|
auto data = (struct cdbus_append_wids_data *)user_data;
|
||||||
assert(!w->destroyed);
|
assert(!w->destroyed);
|
||||||
++count;
|
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) {
|
||||||
|
auto count = session_get_window_count(ps);
|
||||||
if (!count) {
|
if (!count) {
|
||||||
// Nothing to append
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate memory for an array of window IDs
|
DBusMessageIter iter;
|
||||||
auto arr = ccalloc(count, cdbus_window_t);
|
struct cdbus_append_wids_data callback_data = {.success = true};
|
||||||
|
dbus_message_iter_init_append(msg, &iter);
|
||||||
// Build the array
|
if (!dbus_message_iter_open_container(
|
||||||
cdbus_window_t *pcur = arr;
|
&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32_AS_STRING, &callback_data.iter)) {
|
||||||
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)) {
|
|
||||||
log_error("Failed to append argument.");
|
log_error("Failed to append argument.");
|
||||||
free(arr);
|
|
||||||
return false;
|
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;
|
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);
|
append_win_property(Name, name, string_variant);
|
||||||
|
|
||||||
if (!strcmp("Next", target)) {
|
if (!strcmp("Next", target)) {
|
||||||
cdbus_window_t next_id = 0;
|
auto next_win = session_get_next_win_in_stack(ps, &w->base);
|
||||||
if (!list_node_is_last(&ps->window_stack, &w->base.stack_neighbour)) {
|
cdbus_window_t next_id = next_win ? next_win->id : XCB_NONE;
|
||||||
next_id = list_entry(w->base.stack_neighbour.next, struct win,
|
|
||||||
stack_neighbour)
|
|
||||||
->id;
|
|
||||||
}
|
|
||||||
if (!cdbus_append_wid_variant(reply, next_id)) {
|
if (!cdbus_append_wid_variant(reply, next_id)) {
|
||||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
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) {
|
DBusMessage *reply, DBusError *e attr_unused) {
|
||||||
// Reset the compositor
|
// Reset the compositor
|
||||||
log_info("picom is resetting...");
|
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)) {
|
if (reply != NULL && !cdbus_append_boolean(reply, true)) {
|
||||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
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)
|
#define append_win_property(tgt, type) append(tgt, type, w->tgt)
|
||||||
|
|
||||||
if (!strcmp("next", target)) {
|
if (!strcmp("next", target)) {
|
||||||
xcb_window_t next_id =
|
auto next_win = session_get_next_win_in_stack(ps, &w->base);
|
||||||
list_node_is_last(&ps->window_stack, &w->base.stack_neighbour)
|
xcb_window_t next_id = next_win ? next_win->id : XCB_NONE;
|
||||||
? 0
|
|
||||||
: list_entry(w->base.stack_neighbour.next, struct win, stack_neighbour)
|
|
||||||
->id;
|
|
||||||
if (!cdbus_append_wid(reply, next_id)) {
|
if (!cdbus_append_wid(reply, next_id)) {
|
||||||
return DBUS_HANDLER_RESULT_NEED_MEMORY;
|
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);
|
dbus_set_error_const(err, DBUS_ERROR_INVALID_ARGS, NULL);
|
||||||
return DBUS_HANDLER_RESULT_HANDLED;
|
return DBUS_HANDLER_RESULT_HANDLED;
|
||||||
}
|
}
|
||||||
auto w = find_toplevel(ps, client);
|
auto w = session_find_toplevel(ps, client);
|
||||||
if (w) {
|
if (w) {
|
||||||
wid = w->base.id;
|
wid = w->base.id;
|
||||||
}
|
}
|
||||||
} else if (!strcmp("focused", target)) {
|
} else if (!strcmp("focused", target)) {
|
||||||
// Find focused window
|
// Find focused window
|
||||||
if (ps->active_win && ps->active_win->state != WSTATE_UNMAPPED) {
|
auto active_win = session_get_active_win(ps);
|
||||||
wid = ps->active_win->base.id;
|
if (active_win && active_win->state != WSTATE_UNMAPPED) {
|
||||||
|
wid = active_win->base.id;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log_debug(CDBUS_ERROR_BADTGT_S, target);
|
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);
|
dbus_set_error_const(err, DBUS_ERROR_INVALID_ARGS, NULL);
|
||||||
return DBUS_HANDLER_RESULT_HANDLED;
|
return DBUS_HANDLER_RESULT_HANDLED;
|
||||||
}
|
}
|
||||||
assert(ps->o.backend < sizeof(BACKEND_STRS) / sizeof(BACKEND_STRS[0]));
|
|
||||||
|
|
||||||
#define append(tgt, type, ret) \
|
#define append(tgt, type, ret) \
|
||||||
if (!strcmp(#tgt, target)) { \
|
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; \
|
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(version, string, PICOM_VERSION);
|
||||||
append(pid, int32, getpid());
|
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(config_file, string, "Unknown");
|
||||||
append(paint_on_overlay, boolean, ps->overlay != XCB_NONE);
|
append(paint_on_overlay, boolean, session_get_overlay(ps) != XCB_NONE);
|
||||||
append(paint_on_overlay_id, uint32, ps->overlay); // Sending ID of the X
|
append(paint_on_overlay_id, uint32, session_get_overlay(ps));
|
||||||
// composite overlay
|
append(unredir_if_possible_delay, int32, (int32_t)options->unredir_if_possible_delay);
|
||||||
// window
|
|
||||||
append(unredir_if_possible_delay, int32, (int32_t)ps->o.unredir_if_possible_delay);
|
|
||||||
append(refresh_rate, int32, 0);
|
append(refresh_rate, int32, 0);
|
||||||
append(sw_opti, boolean, false);
|
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(unredir_if_possible, boolean);
|
||||||
append_session_option(write_pid_path, string);
|
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;
|
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.
|
* 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) { \
|
if (strcmp(#tgt, target) == 0) { \
|
||||||
type val; \
|
type val; \
|
||||||
get_msg_arg(dbus_type, val); \
|
get_msg_arg(dbus_type, val); \
|
||||||
ps->o.tgt = expr; \
|
options->tgt = expr; \
|
||||||
goto cdbus_process_opts_set_success; \
|
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;
|
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_delta, INT32, int32_t, max2(val, 1));
|
||||||
opts_set_do(fade_in_step, DOUBLE, double, normalize_d(val));
|
opts_set_do(fade_in_step, DOUBLE, double, normalize_d(val));
|
||||||
opts_set_do(fade_out_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)) {
|
if (!strcmp("unredir_if_possible", target)) {
|
||||||
dbus_bool_t val = FALSE;
|
dbus_bool_t val = FALSE;
|
||||||
get_msg_arg(BOOLEAN, val);
|
get_msg_arg(BOOLEAN, val);
|
||||||
if (ps->o.unredir_if_possible != val) {
|
if (options->unredir_if_possible != val) {
|
||||||
ps->o.unredir_if_possible = val;
|
options->unredir_if_possible = val;
|
||||||
queue_redraw(ps);
|
queue_redraw(ps);
|
||||||
}
|
}
|
||||||
goto cdbus_process_opts_set_success;
|
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)) {
|
if (!strcmp("redirected_force", target)) {
|
||||||
cdbus_enum_t val = UNSET;
|
cdbus_enum_t val = UNSET;
|
||||||
get_msg_arg(UINT32, val);
|
get_msg_arg(UINT32, val);
|
||||||
if (ps->o.redirected_force != val) {
|
if (options->redirected_force != val) {
|
||||||
ps->o.redirected_force = val;
|
options->redirected_force = val;
|
||||||
force_repaint(ps);
|
force_repaint(ps);
|
||||||
}
|
}
|
||||||
goto cdbus_process_opts_set_success;
|
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.
|
* 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;
|
return DBUS_HANDLER_RESULT_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *ret = NULL;
|
struct cdbus_window_root_introspect_data callback_data = {.introspect = NULL,
|
||||||
bool success = true;
|
.success = true};
|
||||||
mstrextend(&ret, str_introspect);
|
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) {
|
if (callback_data.success) {
|
||||||
assert(!w->destroyed);
|
callback_data.success = cdbus_append_string(reply, callback_data.introspect);
|
||||||
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);
|
|
||||||
}
|
|
||||||
mstrextend(&ret, "</node>");
|
|
||||||
|
|
||||||
if (success) {
|
free(callback_data.introspect);
|
||||||
success = cdbus_append_string(reply, ret);
|
return callback_data.success ? DBUS_HANDLER_RESULT_HANDLED
|
||||||
}
|
: DBUS_HANDLER_RESULT_NEED_MEMORY;
|
||||||
free(ret);
|
|
||||||
return success ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NEED_MEMORY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cdbus_process_window_introspect(DBusMessage *reply) {
|
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("**Version:** " PICOM_VERSION "\n");
|
||||||
// printf("**CFLAGS:** %s\n", "??");
|
// printf("**CFLAGS:** %s\n", "??");
|
||||||
printf("\n### Extensions:\n\n");
|
printf("\n### Extensions:\n\n");
|
||||||
printf("* Shape: %s\n", ps->shape_exists ? "Yes" : "No");
|
printf("* Shape: %s\n", session_has_shape_extension(ps) ? "Yes" : "No");
|
||||||
printf("* RandR: %s\n", ps->randr_exists ? "Yes" : "No");
|
printf("* RandR: %s\n", session_has_randr_extension(ps) ? "Yes" : "No");
|
||||||
printf("* Present: %s\n", ps->present_exists ? "Present" : "Not Present");
|
printf("* Present: %s\n", session_has_present_extension(ps) ? "Present" : "Not Present");
|
||||||
printf("\n### Misc:\n\n");
|
printf("\n### Misc:\n\n");
|
||||||
printf("* Use Overlay: %s\n", ps->overlay != XCB_NONE ? "Yes" : "No");
|
printf("* Use Overlay: %s\n", session_get_overlay(ps) != XCB_NONE ? "Yes" : "No");
|
||||||
if (ps->overlay == XCB_NONE) {
|
if (session_get_overlay(ps) == XCB_NONE) {
|
||||||
if (compositor_running) {
|
if (compositor_running) {
|
||||||
printf(" (Another compositor is already running)\n");
|
printf(" (Another compositor is already running)\n");
|
||||||
} else if (session_redirection_mode(ps) != XCB_COMPOSITE_REDIRECT_MANUAL) {
|
} 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
|
#endif
|
||||||
printf("* Config file used: %s\n", config_file ?: "None");
|
printf("* Config file used: %s\n", config_file ?: "None");
|
||||||
printf("\n### Drivers (inaccurate):\n\n");
|
printf("\n### Drivers (inaccurate):\n\n");
|
||||||
print_drivers(ps->drivers);
|
print_drivers(session_get_driver(ps));
|
||||||
|
|
||||||
for (int i = 0; i < NUM_BKEND; i++) {
|
for (int i = 0; i < NUM_BKEND; i++) {
|
||||||
if (backend_list[i] && backend_list[i]->diagnostics) {
|
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.h"
|
||||||
#include "win_defs.h"
|
#include "win_defs.h"
|
||||||
#include "x.h"
|
#include "x.h"
|
||||||
|
#include "xcb/xfixes.h"
|
||||||
|
|
||||||
/// Event handling with X is complicated. Handling events with other events possibly
|
/// 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
|
/// 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 = "";
|
char *name = "";
|
||||||
if (wid) {
|
if (wid) {
|
||||||
name = "(Failed to get title)";
|
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)";
|
name = "(Root window)";
|
||||||
} else if (ps->overlay == wid) {
|
} else if (session_get_overlay(ps) == wid) {
|
||||||
name = "(Overlay)";
|
name = "(Overlay)";
|
||||||
} else {
|
} else {
|
||||||
auto w = find_managed_win(ps, wid);
|
auto w = find_managed_win(ps, wid);
|
||||||
if (!w) {
|
if (!w) {
|
||||||
w = find_toplevel(ps, wid);
|
w = session_find_toplevel(ps, wid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w && w->name) {
|
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 PropertyNotify: return ((xcb_property_notify_event_t *)ev)->window;
|
||||||
case ClientMessage: return ((xcb_client_message_event_t *)ev)->window;
|
case ClientMessage: return ((xcb_client_message_event_t *)ev)->window;
|
||||||
default:
|
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;
|
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;
|
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);
|
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";
|
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";
|
return "ShapeNotify";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps->xsync_exists) {
|
if (session_has_xsync_extension(ps)) {
|
||||||
int o = ev->response_type - ps->xsync_event;
|
int o = ev->response_type - session_get_xsync_extention_event(ps);
|
||||||
switch (o) {
|
switch (o) {
|
||||||
CASESTRRET(XSyncCounterNotify);
|
CASESTRRET(XSyncCounterNotify);
|
||||||
CASESTRRET(XSyncAlarmNotify);
|
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) {
|
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),
|
log_debug("{ mode: %s, detail: %s }\n", ev_focus_mode_name(ev),
|
||||||
ev_focus_detail_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) {
|
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),
|
log_debug("{ mode: %s, detail: %s }\n", ev_focus_mode_name(ev),
|
||||||
ev_focus_detail_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) {
|
static inline void ev_create_notify(session_t *ps, xcb_create_notify_event_t *ev) {
|
||||||
if (ev->parent == ps->c.screen_info->root) {
|
if (ev->parent == session_get_x_connection(ps)->screen_info->root) {
|
||||||
add_win_top(ps, ev->window);
|
session_add_win_top(ps, ev->window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle configure event of a regular window
|
/// Handle configure event of a regular window
|
||||||
static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
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) {
|
if (!w) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!w->managed) {
|
if (!w->managed) {
|
||||||
restack_above(ps, w, ce->above_sibling);
|
session_restack_above(ps, w, ce->above_sibling);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mw = (struct managed_win *)w;
|
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
|
// We check against pending_g here, because there might have been multiple
|
||||||
// configure notifies in this cycle, or the window could receive multiple updates
|
// 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);
|
win_set_flags(mw, WIN_FLAGS_FACTOR_CHANGED);
|
||||||
// TODO(yshui) don't set pending_updates if the window is not
|
// TODO(yshui) don't set pending_updates if the window is not
|
||||||
// visible/mapped
|
// visible/mapped
|
||||||
ps->pending_updates = true;
|
session_mark_updates_pending(ps);
|
||||||
|
|
||||||
// At least one of the following if's is true
|
// At least one of the following if's is true
|
||||||
if (position_changed) {
|
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
|
// 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
|
// 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) {
|
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 }",
|
log_debug("{ send_event: %d, id: %#010x, above: %#010x, override_redirect: %d }",
|
||||||
ev->event, ev->window, ev->above_sibling, ev->override_redirect);
|
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);
|
set_root_flags(ps, ROOT_FLAGS_CONFIGURED);
|
||||||
} else {
|
} else {
|
||||||
configure_win(ps, ev);
|
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) {
|
static inline void ev_destroy_notify(session_t *ps, xcb_destroy_notify_event_t *ev) {
|
||||||
auto w = find_win(ps, ev->window);
|
auto w = session_find_win(ps, ev->window);
|
||||||
auto mw = find_toplevel(ps, ev->window);
|
auto mw = session_find_toplevel(ps, ev->window);
|
||||||
if (mw && mw->client_win == mw->base.id) {
|
if (mw && mw->client_win == mw->base.id) {
|
||||||
// We only want _real_ frame window
|
// We only want _real_ frame window
|
||||||
assert(&mw->base == w);
|
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) {
|
if (mw != NULL) {
|
||||||
win_unmark_client(ps, mw);
|
win_unmark_client(ps, mw);
|
||||||
win_set_flags(mw, WIN_FLAGS_CLIENT_STALE);
|
win_set_flags(mw, WIN_FLAGS_CLIENT_STALE);
|
||||||
ps->pending_updates = true;
|
session_mark_updates_pending(ps);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log_debug("Received a destroy notify from an unknown window, %#010x", ev->window);
|
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) {
|
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
|
// Unmap overlay window if it got mapped but we are currently not
|
||||||
// in redirected state.
|
// 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");
|
log_debug("Overlay is mapped while we are not redirected");
|
||||||
auto e = xcb_request_check(
|
auto e = xcb_request_check(c->c, xcb_unmap_window_checked(c->c, overlay));
|
||||||
ps->c.c, xcb_unmap_window_checked(ps->c.c, ps->overlay));
|
|
||||||
if (e) {
|
if (e) {
|
||||||
log_error("Failed to unmap the overlay window");
|
log_error("Failed to unmap the overlay window");
|
||||||
free(e);
|
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
|
// FocusIn/Out may be ignored when the window is unmapped, so we must
|
||||||
// recheck focus here
|
// 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) {
|
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) {
|
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",
|
log_debug("Window %#010x has new parent: %#010x, override_redirect: %d",
|
||||||
ev->window, ev->parent, ev->override_redirect);
|
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) {
|
if (w_top) {
|
||||||
win_unmark_client(ps, w_top);
|
win_unmark_client(ps, w_top);
|
||||||
win_set_flags(w_top, WIN_FLAGS_CLIENT_STALE);
|
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
|
// 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
|
// change (i.e. reparent again to current parent). So we check if that's
|
||||||
// the case
|
// the case
|
||||||
auto w = find_win(ps, ev->window);
|
auto w = session_find_win(ps, ev->window);
|
||||||
if (w) {
|
if (w) {
|
||||||
// This window has already been reparented to root before,
|
// 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
|
// so we don't need to create a new window for it, we just need to
|
||||||
// move it to the top
|
// move it to the top
|
||||||
restack_top(ps, w);
|
session_restack_top(ps, w);
|
||||||
} else {
|
} else {
|
||||||
add_win_top(ps, ev->window);
|
session_add_win_top(ps, ev->window);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// otherwise, find and destroy the window first
|
// 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) {
|
||||||
if (w->managed) {
|
if (w->managed) {
|
||||||
auto mw = (struct managed_win *)w;
|
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
|
// Reset event mask in case something wrong happens
|
||||||
uint32_t evmask = determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN);
|
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 "
|
log_debug("Window %#010x doesn't have WM_STATE property, it is "
|
||||||
"probably not a client window. But we will listen for "
|
"probably not a client window. But we will listen for "
|
||||||
"property change in case it gains one.",
|
"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",
|
"client",
|
||||||
w_real_top->base.id, w_real_top->name);
|
w_real_top->base.id, w_real_top->name);
|
||||||
win_set_flags(w_real_top, WIN_FLAGS_CLIENT_STALE);
|
win_set_flags(w_real_top, WIN_FLAGS_CLIENT_STALE);
|
||||||
ps->pending_updates = true;
|
session_mark_updates_pending(ps);
|
||||||
} else {
|
} else {
|
||||||
log_debug("parent %#010x not found", ev->parent);
|
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});
|
XCB_CW_EVENT_MASK, (const uint32_t[]){evmask});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ev_circulate_notify(session_t *ps, xcb_circulate_notify_event_t *ev) {
|
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) {
|
if (!w) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ev->place == PlaceOnTop) {
|
if (ev->place == PlaceOnTop) {
|
||||||
restack_top(ps, w);
|
session_restack_top(ps, w);
|
||||||
} else {
|
} 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) {
|
static inline void ev_expose(session_t *ps, xcb_expose_event_t *ev) {
|
||||||
if (ev->window == ps->c.screen_info->root ||
|
auto overlay = session_get_overlay(ps);
|
||||||
(ps->overlay && ev->window == ps->overlay)) {
|
if (ev->window == session_get_x_connection(ps)->screen_info->root ||
|
||||||
int more = ev->count + 1;
|
(overlay && ev->window == overlay)) {
|
||||||
if (ps->n_expose == ps->size_expose) {
|
region_t region;
|
||||||
if (ps->expose_rects) {
|
pixman_region32_init_rect(®ion, ev->x, ev->y, ev->width, ev->height);
|
||||||
ps->expose_rects =
|
add_damage(ps, ®ion);
|
||||||
crealloc(ps->expose_rects, ps->size_expose + more);
|
pixman_region32_fini(®ion);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t *ev) {
|
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)) {
|
if (unlikely(log_get_level_tls() <= LOG_LEVEL_TRACE)) {
|
||||||
// Print out changed atom
|
// Print out changed atom
|
||||||
xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(
|
xcb_get_atom_name_reply_t *reply =
|
||||||
ps->c.c, xcb_get_atom_name(ps->c.c, ev->atom), NULL);
|
xcb_get_atom_name_reply(c->c, xcb_get_atom_name(c->c, ev->atom), NULL);
|
||||||
const char *name = "?";
|
const char *name = "?";
|
||||||
int name_len = 1;
|
int name_len = 1;
|
||||||
if (reply) {
|
if (reply) {
|
||||||
|
@ -483,13 +470,13 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
||||||
free(reply);
|
free(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps->c.screen_info->root == ev->window) {
|
if (c->screen_info->root == ev->window) {
|
||||||
if (ps->o.use_ewmh_active_win && ps->atoms->a_NET_ACTIVE_WINDOW == ev->atom) {
|
if (options->use_ewmh_active_win && atoms->a_NET_ACTIVE_WINDOW == ev->atom) {
|
||||||
// to update focus
|
// to update focus
|
||||||
ps->pending_updates = true;
|
session_mark_updates_pending(ps);
|
||||||
} else {
|
} else {
|
||||||
// Destroy the root "image" if the wallpaper probably changed
|
// 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);
|
root_damaged(ps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -498,15 +485,15 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ps->pending_updates = true;
|
session_mark_updates_pending(ps);
|
||||||
// If WM_STATE changes
|
// 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
|
// 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
|
// Reset event mask anyway
|
||||||
const uint32_t evmask =
|
const uint32_t evmask =
|
||||||
determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN);
|
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});
|
XCB_CW_EVENT_MASK, (const uint32_t[]){evmask});
|
||||||
|
|
||||||
auto w_top = find_managed_window_or_parent(ps, ev->window);
|
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
|
// If _NET_WM_WINDOW_TYPE changes... God knows why this would happen, but
|
||||||
// there are always some stupid applications. (#144)
|
// there are always some stupid applications. (#144)
|
||||||
if (ev->atom == ps->atoms->a_NET_WM_WINDOW_TYPE) {
|
if (ev->atom == atoms->a_NET_WM_WINDOW_TYPE) {
|
||||||
struct managed_win *w = find_toplevel(ps, ev->window);
|
struct managed_win *w = session_find_toplevel(ps, ev->window);
|
||||||
if (w) {
|
if (w) {
|
||||||
win_set_property_stale(w, ev->atom);
|
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
|
// Unnecessary until we remove the queue_redraw in ev_handle
|
||||||
queue_redraw(ps);
|
queue_redraw(ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If _NET_WM_WINDOW_OPACITY changes
|
// If _NET_WM_WINDOW_OPACITY changes
|
||||||
if (ev->atom == ps->atoms->a_NET_WM_WINDOW_OPACITY) {
|
if (ev->atom == atoms->a_NET_WM_WINDOW_OPACITY) {
|
||||||
auto w = find_managed_win(ps, ev->window) ?: find_toplevel(ps, ev->window);
|
auto w = find_managed_win(ps, ev->window)
|
||||||
|
?: session_find_toplevel(ps, ev->window);
|
||||||
if (w) {
|
if (w) {
|
||||||
win_set_property_stale(w, ev->atom);
|
win_set_property_stale(w, ev->atom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If frame extents property changes
|
// If frame extents property changes
|
||||||
if (ev->atom == ps->atoms->a_NET_FRAME_EXTENTS) {
|
if (ev->atom == atoms->a_NET_FRAME_EXTENTS) {
|
||||||
auto w = find_toplevel(ps, ev->window);
|
auto w = session_find_toplevel(ps, ev->window);
|
||||||
if (w) {
|
if (w) {
|
||||||
win_set_property_stale(w, ev->atom);
|
win_set_property_stale(w, ev->atom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If name changes
|
// If name changes
|
||||||
if (ps->atoms->aWM_NAME == ev->atom || ps->atoms->a_NET_WM_NAME == ev->atom) {
|
if (atoms->aWM_NAME == ev->atom || atoms->a_NET_WM_NAME == ev->atom) {
|
||||||
auto w = find_toplevel(ps, ev->window);
|
auto w = session_find_toplevel(ps, ev->window);
|
||||||
if (w) {
|
if (w) {
|
||||||
win_set_property_stale(w, ev->atom);
|
win_set_property_stale(w, ev->atom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If class changes
|
// If class changes
|
||||||
if (ps->atoms->aWM_CLASS == ev->atom) {
|
if (atoms->aWM_CLASS == ev->atom) {
|
||||||
auto w = find_toplevel(ps, ev->window);
|
auto w = session_find_toplevel(ps, ev->window);
|
||||||
if (w) {
|
if (w) {
|
||||||
win_set_property_stale(w, ev->atom);
|
win_set_property_stale(w, ev->atom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If role changes
|
// If role changes
|
||||||
if (ps->atoms->aWM_WINDOW_ROLE == ev->atom) {
|
if (atoms->aWM_WINDOW_ROLE == ev->atom) {
|
||||||
auto w = find_toplevel(ps, ev->window);
|
auto w = session_find_toplevel(ps, ev->window);
|
||||||
if (w) {
|
if (w) {
|
||||||
win_set_property_stale(w, ev->atom);
|
win_set_property_stale(w, ev->atom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If _COMPTON_SHADOW changes
|
// 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);
|
auto w = find_managed_win(ps, ev->window);
|
||||||
if (w) {
|
if (w) {
|
||||||
win_set_property_stale(w, ev->atom);
|
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 a leader property changes
|
||||||
if ((ps->o.detect_transient && ps->atoms->aWM_TRANSIENT_FOR == ev->atom) ||
|
if ((options->detect_transient && atoms->aWM_TRANSIENT_FOR == ev->atom) ||
|
||||||
(ps->o.detect_client_leader && ps->atoms->aWM_CLIENT_LEADER == ev->atom)) {
|
(options->detect_client_leader && atoms->aWM_CLIENT_LEADER == ev->atom)) {
|
||||||
auto w = find_toplevel(ps, ev->window);
|
auto w = session_find_toplevel(ps, ev->window);
|
||||||
if (w) {
|
if (w) {
|
||||||
win_set_property_stale(w, ev->atom);
|
win_set_property_stale(w, ev->atom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ps->o.no_ewmh_fullscreen && ev->atom == ps->atoms->a_NET_WM_STATE) {
|
if (!options->no_ewmh_fullscreen && ev->atom == atoms->a_NET_WM_STATE) {
|
||||||
auto w = find_toplevel(ps, ev->window);
|
auto w = session_find_toplevel(ps, ev->window);
|
||||||
if (w) {
|
if (w) {
|
||||||
win_set_property_stale(w, ev->atom);
|
win_set_property_stale(w, ev->atom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for other atoms we are tracking
|
// 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;
|
bool change_is_on_client = false;
|
||||||
auto w = find_managed_win(ps, ev->window);
|
auto w = find_managed_win(ps, ev->window);
|
||||||
if (!w) {
|
if (!w) {
|
||||||
w = find_toplevel(ps, ev->window);
|
w = session_find_toplevel(ps, ev->window);
|
||||||
change_is_on_client = true;
|
change_is_on_client = true;
|
||||||
}
|
}
|
||||||
if (w) {
|
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);
|
change_is_on_client);
|
||||||
// Set FACTOR_CHANGED so rules based on properties will be
|
// Set FACTOR_CHANGED so rules based on properties will be
|
||||||
// re-evaluated.
|
// re-evaluated.
|
||||||
|
@ -621,6 +609,8 @@ static inline void repair_win(session_t *ps, struct managed_win *w) {
|
||||||
// Only mapped window can receive damages
|
// Only mapped window can receive damages
|
||||||
assert(w->state == WSTATE_MAPPED || win_check_flags_all(w, WIN_FLAGS_MAPPED));
|
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;
|
region_t parts;
|
||||||
pixman_region32_init(&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.
|
// from the X server, which implies it has received our DamageSubtract request.
|
||||||
if (!w->ever_damaged) {
|
if (!w->ever_damaged) {
|
||||||
auto e = xcb_request_check(
|
auto e = xcb_request_check(
|
||||||
ps->c.c,
|
c->c, xcb_damage_subtract_checked(c->c, w->damage, XCB_NONE, XCB_NONE));
|
||||||
xcb_damage_subtract_checked(ps->c.c, w->damage, XCB_NONE, XCB_NONE));
|
|
||||||
if (e) {
|
if (e) {
|
||||||
if (ps->o.show_all_xerrors) {
|
if (options->show_all_xerrors) {
|
||||||
x_print_error(e->sequence, e->major_code, e->minor_code,
|
x_print_error(e->sequence, e->major_code, e->minor_code,
|
||||||
e->error_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.
|
// We only binds the window pixmap once the window is damaged.
|
||||||
win_set_flags(w, WIN_FLAGS_PIXMAP_STALE);
|
win_set_flags(w, WIN_FLAGS_PIXMAP_STALE);
|
||||||
ps->pending_updates = true;
|
session_mark_updates_pending(ps);
|
||||||
} else {
|
} else {
|
||||||
auto cookie = xcb_damage_subtract(ps->c.c, w->damage, XCB_NONE,
|
xcb_xfixes_region_t damage_region = session_get_damage_ring(ps)->x_region;
|
||||||
ps->damage_ring.x_region);
|
auto cookie = xcb_damage_subtract(c->c, w->damage, XCB_NONE, damage_region);
|
||||||
if (!ps->o.show_all_xerrors) {
|
if (!options->show_all_xerrors) {
|
||||||
set_ignore_cookie(&ps->c, cookie);
|
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,
|
pixman_region32_translate(&parts, w->g.x + w->g.border_width,
|
||||||
w->g.y + 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?
|
// Why care about damage when screen is unredirected?
|
||||||
// We will force full-screen repaint on redirection.
|
// We will force full-screen repaint on redirection.
|
||||||
if (!ps->redirected) {
|
if (!session_is_redirected(ps)) {
|
||||||
pixman_region32_fini(&parts);
|
pixman_region32_fini(&parts);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the part in the damage area that could be ignored
|
// 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);
|
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;
|
w->reg_ignore_valid = false;
|
||||||
|
|
||||||
win_set_flags(w, WIN_FLAGS_SIZE_STALE);
|
win_set_flags(w, WIN_FLAGS_SIZE_STALE);
|
||||||
ps->pending_updates = true;
|
session_mark_updates_pending(ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
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) {
|
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) {
|
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);
|
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\"",
|
log_debug("event %10.10s serial %#010x window %#010x \"%s\"",
|
||||||
ev_name(ps, ev), ev->full_sequence, wid, ev_window_name(ps, wid));
|
ev_name(ps, ev), ev->full_sequence, wid, ev_window_name(ps, wid));
|
||||||
} else {
|
} 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://bugs.freedesktop.org/show_bug.cgi?id=35945
|
||||||
// https://lists.freedesktop.org/archives/xcb/2011-November/007337.html
|
// https://lists.freedesktop.org/archives/xcb/2011-November/007337.html
|
||||||
auto response_type = XCB_EVENT_RESPONSE_TYPE(ev);
|
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) {
|
if (proc) {
|
||||||
XESetWireToEvent(ps->c.dpy, response_type, proc);
|
XESetWireToEvent(c->dpy, response_type, proc);
|
||||||
XEvent dummy;
|
XEvent dummy;
|
||||||
|
|
||||||
// Stop Xlib from complaining about lost sequence numbers.
|
// 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
|
// We only need the low 16 bits
|
||||||
uint16_t seq = ev->sequence;
|
uint16_t seq = ev->sequence;
|
||||||
ev->sequence = (uint16_t)(LastKnownRequestProcessed(ps->c.dpy) & 0xffff);
|
ev->sequence = (uint16_t)(LastKnownRequestProcessed(c->dpy) & 0xffff);
|
||||||
proc(ps->c.dpy, &dummy, (xEvent *)ev);
|
proc(c->dpy, &dummy, (xEvent *)ev);
|
||||||
// Restore the sequence number
|
// Restore the sequence number
|
||||||
ev->sequence = seq;
|
ev->sequence = seq;
|
||||||
}
|
}
|
||||||
|
@ -798,18 +788,21 @@ void ev_handle(session_t *ps, xcb_generic_event_t *ev) {
|
||||||
case SelectionClear:
|
case SelectionClear:
|
||||||
ev_selection_clear(ps, (xcb_selection_clear_event_t *)ev);
|
ev_selection_clear(ps, (xcb_selection_clear_event_t *)ev);
|
||||||
break;
|
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:
|
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);
|
ev_shape_notify(ps, (xcb_shape_notify_event_t *)ev);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ps->randr_exists &&
|
if (session_has_randr_extension(ps) &&
|
||||||
ev->response_type == (ps->randr_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY)) {
|
ev->response_type == (session_get_randr_extention_event(ps) +
|
||||||
|
XCB_RANDR_SCREEN_CHANGE_NOTIFY)) {
|
||||||
set_root_flags(ps, ROOT_FLAGS_SCREEN_CHANGE);
|
set_root_flags(ps, ROOT_FLAGS_SCREEN_CHANGE);
|
||||||
break;
|
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);
|
ev_damage_notify(ps, (xcb_damage_notify_event_t *)ev);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
182
src/opengl.c
182
src/opengl.c
|
@ -23,7 +23,9 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "picom.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
|
#include "render.h"
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
#include "uthash_extra.h"
|
#include "uthash_extra.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
@ -39,24 +41,26 @@ static inline XVisualInfo *get_visualinfo_from_visual(session_t *ps, xcb_visuali
|
||||||
XVisualInfo vreq = {.visualid = visual};
|
XVisualInfo vreq = {.visualid = visual};
|
||||||
int nitems = 0;
|
int nitems = 0;
|
||||||
|
|
||||||
return XGetVisualInfo(ps->c.dpy, VisualIDMask, &vreq, &nitems);
|
return XGetVisualInfo(session_get_x_connection(ps)->dpy, VisualIDMask, &vreq, &nitems);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize OpenGL.
|
* 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;
|
bool success = false;
|
||||||
XVisualInfo *pvis = NULL;
|
XVisualInfo *pvis = NULL;
|
||||||
|
glx_session_t *psglx = NULL;
|
||||||
|
auto c = session_get_x_connection(ps);
|
||||||
|
|
||||||
// Check for GLX extension
|
// Check for GLX extension
|
||||||
if (!ps->glx_exists) {
|
if (!session_has_glx_extension(ps)) {
|
||||||
log_error("No GLX extension.");
|
log_error("No GLX extension.");
|
||||||
goto glx_init_end;
|
goto glx_init_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get XVisualInfo
|
// 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) {
|
if (!pvis) {
|
||||||
log_error("Failed to acquire XVisualInfo for current visual.");
|
log_error("Failed to acquire XVisualInfo for current visual.");
|
||||||
goto glx_init_end;
|
goto glx_init_end;
|
||||||
|
@ -65,13 +69,12 @@ bool glx_init(session_t *ps, bool need_render) {
|
||||||
// Ensure the visual is double-buffered
|
// Ensure the visual is double-buffered
|
||||||
if (need_render) {
|
if (need_render) {
|
||||||
int value = 0;
|
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.");
|
log_error("Root visual is not a GL visual.");
|
||||||
goto glx_init_end;
|
goto glx_init_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Success != glXGetConfig(ps->c.dpy, pvis, GLX_DOUBLEBUFFER, &value) ||
|
if (Success != glXGetConfig(c->dpy, pvis, GLX_DOUBLEBUFFER, &value) || !value) {
|
||||||
!value) {
|
|
||||||
log_error("Root visual is not a double buffered GL visual.");
|
log_error("Root visual is not a double buffered GL visual.");
|
||||||
goto glx_init_end;
|
goto glx_init_end;
|
||||||
}
|
}
|
||||||
|
@ -83,23 +86,22 @@ bool glx_init(session_t *ps, bool need_render) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize GLX data structure
|
// Initialize GLX data structure
|
||||||
if (!ps->psglx) {
|
auto options = session_get_options(ps);
|
||||||
static const glx_session_t CGLX_SESSION_DEF = CGLX_SESSION_INIT;
|
psglx = cmalloc(glx_session_t);
|
||||||
ps->psglx = cmalloc(glx_session_t);
|
*psglx = (glx_session_t){.context = NULL, .glx_prog_win = GLX_PROG_MAIN_INIT};
|
||||||
memcpy(ps->psglx, &CGLX_SESSION_DEF, sizeof(glx_session_t));
|
|
||||||
|
|
||||||
// +1 for the zero terminator
|
// +1 for the zero terminator
|
||||||
ps->psglx->blur_passes = ccalloc(ps->o.blur_kernel_count, glx_blur_pass_t);
|
psglx->blur_passes = ccalloc(options->blur_kernel_count, glx_blur_pass_t);
|
||||||
|
|
||||||
for (int i = 0; i < ps->o.blur_kernel_count; ++i) {
|
for (int i = 0; i < options->blur_kernel_count; ++i) {
|
||||||
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
glx_blur_pass_t *ppass = &psglx->blur_passes[i];
|
||||||
ppass->unifm_factor_center = -1;
|
ppass->unifm_factor_center = -1;
|
||||||
ppass->unifm_offset_x = -1;
|
ppass->unifm_offset_x = -1;
|
||||||
ppass->unifm_offset_y = -1;
|
ppass->unifm_offset_y = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ps->psglx->round_passes = ccalloc(1, glx_round_pass_t);
|
psglx->round_passes = ccalloc(1, glx_round_pass_t);
|
||||||
glx_round_pass_t *ppass = ps->psglx->round_passes;
|
glx_round_pass_t *ppass = psglx->round_passes;
|
||||||
ppass->unifm_radius = -1;
|
ppass->unifm_radius = -1;
|
||||||
ppass->unifm_texcoord = -1;
|
ppass->unifm_texcoord = -1;
|
||||||
ppass->unifm_texsize = -1;
|
ppass->unifm_texsize = -1;
|
||||||
|
@ -107,14 +109,11 @@ bool glx_init(session_t *ps, bool need_render) {
|
||||||
ppass->unifm_borderc = -1;
|
ppass->unifm_borderc = -1;
|
||||||
ppass->unifm_resolution = -1;
|
ppass->unifm_resolution = -1;
|
||||||
ppass->unifm_tex_scr = -1;
|
ppass->unifm_tex_scr = -1;
|
||||||
}
|
|
||||||
|
|
||||||
glx_session_t *psglx = ps->psglx;
|
|
||||||
|
|
||||||
if (!psglx->context) {
|
if (!psglx->context) {
|
||||||
// Get GLX context
|
// Get GLX context
|
||||||
#ifndef DEBUG_GLX_DEBUG_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
|
#else
|
||||||
{
|
{
|
||||||
GLXFBConfig fbconfig = get_fbconfig_from_visualinfo(ps, pvis);
|
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[] = {
|
static const int attrib_list[] = {
|
||||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, None};
|
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, None};
|
||||||
psglx->context = p_glXCreateContextAttribsARB(
|
psglx->context = p_glXCreateContextAttribsARB(
|
||||||
ps->c.dpy, fbconfig, NULL, GL_TRUE, attrib_list);
|
c->dpy, fbconfig, NULL, GL_TRUE, attrib_list);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -146,7 +145,7 @@ bool glx_init(session_t *ps, bool need_render) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach GLX context
|
// 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.");
|
log_error("Failed to attach GLX context.");
|
||||||
goto glx_init_end;
|
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
|
// 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
|
// 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?
|
// 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;
|
GLint val = 0;
|
||||||
glGetIntegerv(GL_STENCIL_BITS, &val);
|
glGetIntegerv(GL_STENCIL_BITS, &val);
|
||||||
if (!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);
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
if (!ps->o.glx_no_stencil) {
|
if (!options->glx_no_stencil) {
|
||||||
// Initialize stencil buffer
|
// Initialize stencil buffer
|
||||||
glClear(GL_STENCIL_BUFFER_BIT);
|
glClear(GL_STENCIL_BUFFER_BIT);
|
||||||
glDisable(GL_STENCIL_TEST);
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
@ -204,7 +203,7 @@ bool glx_init(session_t *ps, bool need_render) {
|
||||||
// Clear screen
|
// Clear screen
|
||||||
glClearColor(0.0F, 0.0F, 0.0F, 1.0F);
|
glClearColor(0.0F, 0.0F, 0.0F, 1.0F);
|
||||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
// 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;
|
success = true;
|
||||||
|
@ -213,10 +212,11 @@ glx_init_end:
|
||||||
XFree(pvis);
|
XFree(pvis);
|
||||||
|
|
||||||
if (!success) {
|
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) {
|
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.
|
* Destroy GLX related resources.
|
||||||
*/
|
*/
|
||||||
void glx_destroy(session_t *ps) {
|
void glx_destroy(struct session *ps, struct glx_session *psglx) {
|
||||||
if (!ps->psglx) {
|
if (!psglx) {
|
||||||
return;
|
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
|
// Free GLSL shaders/programs
|
||||||
for (int i = 0; i < ps->o.blur_kernel_count; ++i) {
|
for (int i = 0; i < session_get_options(ps)->blur_kernel_count; ++i) {
|
||||||
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
glx_blur_pass_t *ppass = &psglx->blur_passes[i];
|
||||||
if (ppass->frag_shader) {
|
if (ppass->frag_shader) {
|
||||||
glDeleteShader(ppass->frag_shader);
|
glDeleteShader(ppass->frag_shader);
|
||||||
}
|
}
|
||||||
|
@ -255,43 +250,44 @@ void glx_destroy(session_t *ps) {
|
||||||
glDeleteProgram(ppass->prog);
|
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) {
|
if (ppass->frag_shader) {
|
||||||
glDeleteShader(ppass->frag_shader);
|
glDeleteShader(ppass->frag_shader);
|
||||||
}
|
}
|
||||||
if (ppass->prog) {
|
if (ppass->prog) {
|
||||||
glDeleteProgram(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();
|
gl_check_err();
|
||||||
|
|
||||||
// Destroy GLX context
|
// Destroy GLX context
|
||||||
if (ps->psglx->context) {
|
auto c = session_get_x_connection(ps);
|
||||||
glXMakeCurrent(ps->c.dpy, None, NULL);
|
if (psglx->context) {
|
||||||
glXDestroyContext(ps->c.dpy, ps->psglx->context);
|
glXMakeCurrent(c->dpy, None, NULL);
|
||||||
ps->psglx->context = NULL;
|
glXDestroyContext(c->dpy, psglx->context);
|
||||||
|
psglx->context = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(ps->psglx);
|
free(psglx);
|
||||||
ps->psglx = NULL;
|
psglx = NULL;
|
||||||
ps->argb_fbconfig = (struct glx_fbconfig_info){0};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback to run on root window size change.
|
* Callback to run on root window size change.
|
||||||
*/
|
*/
|
||||||
void glx_on_root_change(session_t *ps) {
|
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
|
// Initialize matrix, copied from dcompmgr
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glLoadIdentity();
|
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);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
}
|
}
|
||||||
|
@ -300,12 +296,13 @@ void glx_on_root_change(session_t *ps) {
|
||||||
* Initialize GLX blur filter.
|
* Initialize GLX blur filter.
|
||||||
*/
|
*/
|
||||||
bool glx_init_blur(session_t *ps) {
|
bool glx_init_blur(session_t *ps) {
|
||||||
assert(ps->o.blur_kernel_count > 0);
|
auto options = session_get_options(ps);
|
||||||
assert(ps->o.blur_kerns);
|
assert(options->blur_kernel_count > 0);
|
||||||
assert(ps->o.blur_kerns[0]);
|
assert(options->blur_kerns);
|
||||||
|
assert(options->blur_kerns[0]);
|
||||||
|
|
||||||
// Allocate PBO if more than one blur kernel is present
|
// 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
|
// Try to generate a framebuffer
|
||||||
GLuint fbo = 0;
|
GLuint fbo = 0;
|
||||||
glGenFramebuffers(1, &fbo);
|
glGenFramebuffers(1, &fbo);
|
||||||
|
@ -343,7 +340,8 @@ bool glx_init_blur(session_t *ps) {
|
||||||
" gl_FragColor = sum / (factor_center + float(%.7g));\n"
|
" gl_FragColor = sum / (factor_center + float(%.7g));\n"
|
||||||
"}\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 *sampler_type = (use_texture_rect ? "sampler2DRect" : "sampler2D");
|
||||||
const char *texture_func = (use_texture_rect ? "texture2DRect" : "texture2D");
|
const char *texture_func = (use_texture_rect ? "texture2DRect" : "texture2D");
|
||||||
const char *shader_add = FRAG_SHADER_BLUR_ADD;
|
const char *shader_add = FRAG_SHADER_BLUR_ADD;
|
||||||
|
@ -356,9 +354,9 @@ bool glx_init_blur(session_t *ps) {
|
||||||
extension = strdup("");
|
extension = strdup("");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ps->o.blur_kernel_count; ++i) {
|
for (int i = 0; i < options->blur_kernel_count; ++i) {
|
||||||
auto kern = ps->o.blur_kerns[i];
|
auto kern = options->blur_kerns[i];
|
||||||
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
glx_blur_pass_t *ppass = &psglx->blur_passes[i];
|
||||||
|
|
||||||
// Build shader
|
// Build shader
|
||||||
int width = kern->w, height = kern->h;
|
int width = kern->w, height = kern->h;
|
||||||
|
@ -505,7 +503,8 @@ bool glx_init_rounded_corners(session_t *ps) {
|
||||||
"\n"
|
"\n"
|
||||||
"}\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 *sampler_type = (use_texture_rect ? "sampler2DRect" : "sampler2D");
|
||||||
const char *texture_func = (use_texture_rect ? "texture2DRect" : "texture2D");
|
const char *texture_func = (use_texture_rect ? "texture2DRect" : "texture2D");
|
||||||
char *extension = NULL;
|
char *extension = NULL;
|
||||||
|
@ -519,7 +518,7 @@ bool glx_init_rounded_corners(session_t *ps) {
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
// Build rounded corners shader
|
// 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) +
|
auto len = strlen(FRAG_SHADER) + strlen(extension) + strlen(sampler_type) +
|
||||||
strlen(texture_func) + 1;
|
strlen(texture_func) + 1;
|
||||||
char *shader_str = ccalloc(len, char);
|
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) {
|
int basey, int dx, int dy, int width, int height) {
|
||||||
if (width > 0 && height > 0) {
|
if (width > 0 && height > 0) {
|
||||||
glCopyTexSubImage2D(tex_tgt, 0, dx - basex, dy - basey, dx,
|
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,
|
bool glx_bind_texture(session_t *ps attr_unused, glx_texture_t **pptex, int x, int y,
|
||||||
int width, int height) {
|
int width, int height) {
|
||||||
if (ps->o.backend != BKEND_GLX && ps->o.backend != BKEND_XR_GLX_HYBRID) {
|
if (!bkend_use_glx(ps)) {
|
||||||
return true;
|
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->width = width;
|
||||||
ptex->height = height;
|
ptex->height = height;
|
||||||
ptex->target = GL_TEXTURE_RECTANGLE;
|
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;
|
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,
|
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) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,13 +734,14 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
||||||
|
|
||||||
// Create GLX pixmap
|
// Create GLX pixmap
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
|
auto c = session_get_x_connection(ps);
|
||||||
if (!ptex->glpixmap) {
|
if (!ptex->glpixmap) {
|
||||||
need_release = false;
|
need_release = false;
|
||||||
|
|
||||||
// Retrieve pixmap parameters, if they aren't provided
|
// Retrieve pixmap parameters, if they aren't provided
|
||||||
if (!width || !height) {
|
if (!width || !height) {
|
||||||
auto r = xcb_get_geometry_reply(
|
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) {
|
if (!r) {
|
||||||
log_error("Failed to query info of pixmap %#010x.", pixmap);
|
log_error("Failed to query info of pixmap %#010x.", pixmap);
|
||||||
return false;
|
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
|
// pixmap-specific parameters, and this may change in the future
|
||||||
GLenum tex_tgt = 0;
|
GLenum tex_tgt = 0;
|
||||||
if (GLX_TEXTURE_2D_BIT_EXT & fbcfg->texture_tgts &&
|
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;
|
tex_tgt = GLX_TEXTURE_2D_EXT;
|
||||||
} else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & fbcfg->texture_tgts) {
|
} else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & fbcfg->texture_tgts) {
|
||||||
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT;
|
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,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
ptex->glpixmap = glXCreatePixmap(ps->c.dpy, fbcfg->cfg, pixmap, attrs);
|
ptex->glpixmap = glXCreatePixmap(c->dpy, fbcfg->cfg, pixmap, attrs);
|
||||||
ptex->pixmap = pixmap;
|
ptex->pixmap = pixmap;
|
||||||
ptex->target =
|
ptex->target =
|
||||||
(GLX_TEXTURE_2D_EXT == tex_tgt ? GL_TEXTURE_2D : GL_TEXTURE_RECTANGLE);
|
(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...
|
// The specification requires rebinding whenever the content changes...
|
||||||
// We can't follow this, too slow.
|
// We can't follow this, too slow.
|
||||||
if (need_release) {
|
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
|
// Cleanup
|
||||||
glBindTexture(ptex->target, 0);
|
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.
|
* @brief Release binding of a texture.
|
||||||
*/
|
*/
|
||||||
void glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
|
void glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
|
||||||
|
auto c = session_get_x_connection(ps);
|
||||||
// Release binding
|
// Release binding
|
||||||
if (ptex->glpixmap && ptex->texture) {
|
if (ptex->glpixmap && ptex->texture) {
|
||||||
glBindTexture(ptex->target, 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);
|
glBindTexture(ptex->target, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free GLX Pixmap
|
// Free GLX Pixmap
|
||||||
if (ptex->glpixmap) {
|
if (ptex->glpixmap) {
|
||||||
glXDestroyPixmap(ps->c.dpy, ptex->glpixmap);
|
glXDestroyPixmap(c->dpy, ptex->glpixmap);
|
||||||
ptex->glpixmap = 0;
|
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) {
|
void glx_set_clip(session_t *ps, const region_t *reg) {
|
||||||
// Quit if we aren't using stencils
|
// Quit if we aren't using stencils
|
||||||
if (ps->o.glx_no_stencil) {
|
if (session_get_options(ps)->glx_no_stencil) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,7 +886,7 @@ void glx_set_clip(session_t *ps, const region_t *reg) {
|
||||||
|
|
||||||
if (nrects == 1) {
|
if (nrects == 1) {
|
||||||
glEnable(GL_SCISSOR_TEST);
|
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);
|
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,
|
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) {
|
GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc) {
|
||||||
assert(ps->psglx->blur_passes[0].prog);
|
auto psglx = session_get_psglx(ps);
|
||||||
const bool more_passes = ps->o.blur_kernel_count > 1;
|
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_scissors = glIsEnabled(GL_SCISSOR_TEST);
|
||||||
const bool have_stencil = glIsEnabled(GL_STENCIL_TEST);
|
const bool have_stencil = glIsEnabled(GL_STENCIL_TEST);
|
||||||
bool ret = false;
|
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;
|
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;
|
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;
|
bool last_pass = false;
|
||||||
for (int i = 0; i < ps->o.blur_kernel_count; ++i) {
|
for (int i = 0; i < options->blur_kernel_count; ++i) {
|
||||||
last_pass = (i == ps->o.blur_kernel_count - 1);
|
last_pass = (i == options->blur_kernel_count - 1);
|
||||||
const glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
|
const glx_blur_pass_t *ppass = &psglx->blur_passes[i];
|
||||||
assert(ppass->prog);
|
assert(ppass->prog);
|
||||||
|
|
||||||
assert(tex_scr);
|
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);
|
auto rdy = (GLfloat)(mheight - crect.y1 + mdy);
|
||||||
if (last_pass) {
|
if (last_pass) {
|
||||||
rdx = (GLfloat)crect.x1;
|
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 rdxe = rdx + (GLfloat)(crect.x2 - crect.x1);
|
||||||
auto rdye = rdy - (GLfloat)(crect.y2 - crect.y1);
|
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,
|
bool glx_round_corners_dst(session_t *ps, struct managed_win *w,
|
||||||
const glx_texture_t *ptex, int dx, int dy, int width,
|
const glx_texture_t *ptex, int dx, int dy, int width,
|
||||||
int height, float z, float cr, const region_t *reg_tgt) {
|
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;
|
bool ret = false;
|
||||||
|
auto psglx = session_get_psglx(ps);
|
||||||
|
|
||||||
// log_warn("dxy(%d, %d) wh(%d %d) rwh(%d %d) b(%d), f(%d)",
|
// 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,
|
// 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;
|
int mdx = dx, mdy = dy, mwidth = width, mheight = height;
|
||||||
log_trace("%d, %d, %d, %d", mdx, mdy, mwidth, mheight);
|
log_trace("%d, %d, %d, %d", mdx, mdy, mwidth, mheight);
|
||||||
|
|
||||||
|
auto root_extent = session_get_root_extent(ps);
|
||||||
if (w->g.border_width > 0) {
|
if (w->g.border_width > 0) {
|
||||||
glx_read_border_pixel(ps->root_height, ps->root_width, dx, dy, width,
|
glx_read_border_pixel(root_extent.height, root_extent.width, dx, dy,
|
||||||
height, &w->border_col[0]);
|
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);
|
assert(ppass->prog);
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
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]);
|
w->border_col[1], w->border_col[2], w->border_col[3]);
|
||||||
}
|
}
|
||||||
if (ppass->unifm_resolution >= 0) {
|
if (ppass->unifm_resolution >= 0) {
|
||||||
glUniform2f(ppass->unifm_resolution, (float)ps->root_width,
|
glUniform2f(ppass->unifm_resolution, (float)root_extent.width,
|
||||||
(float)ps->root_height);
|
(float)root_extent.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Painting
|
// Painting
|
||||||
|
@ -1250,7 +1256,7 @@ bool glx_round_corners_dst(session_t *ps, struct managed_win *w,
|
||||||
|
|
||||||
// coordinates for the texture in the target
|
// coordinates for the texture in the target
|
||||||
auto rdx = (GLfloat)crect.x1;
|
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 rdxe = (GLfloat)rdx + (GLfloat)(crect.x2 - crect.x1);
|
||||||
auto rdye = (GLfloat)rdy - (GLfloat)(crect.y2 - crect.y1);
|
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) {
|
P_PAINTREG_START(crect) {
|
||||||
// XXX what does all of these variables mean?
|
// XXX what does all of these variables mean?
|
||||||
GLint rdx = crect.x1;
|
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 rdxe = rdx + (crect.x2 - crect.x1);
|
||||||
GLint rdye = rdy - (crect.y2 - crect.y1);
|
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
|
// coordinates for the texture in the target
|
||||||
GLint rdx = crect.x1;
|
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 rdxe = rdx + (crect.x2 - crect.x1);
|
||||||
GLint rdye = rdy - (crect.y2 - crect.y1);
|
GLint rdye = rdy - (crect.y2 - crect.y1);
|
||||||
|
|
||||||
|
|
13
src/opengl.h
13
src/opengl.h
|
@ -13,12 +13,11 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "log.h"
|
#include "picom.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <epoxy/gl.h>
|
#include <epoxy/gl.h>
|
||||||
#include <epoxy/glx.h>
|
#include <epoxy/glx.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
@ -73,6 +72,9 @@ typedef struct glx_session {
|
||||||
int z;
|
int z;
|
||||||
glx_blur_pass_t *blur_passes;
|
glx_blur_pass_t *blur_passes;
|
||||||
glx_round_pass_t *round_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;
|
} glx_session_t;
|
||||||
|
|
||||||
/// @brief Wrapper of a bound GLX texture.
|
/// @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,
|
int width, int height, int z, double opacity, bool argb, bool neg,
|
||||||
const region_t *reg_tgt, const glx_prog_main_t *pprogram);
|
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);
|
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.
|
* Check if there's a GLX context.
|
||||||
*/
|
*/
|
||||||
static inline bool glx_has_context(session_t *ps) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
772
src/picom.c
772
src/picom.c
|
@ -19,6 +19,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
|
#include <locale.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
#include <ev.h>
|
#include <ev.h>
|
||||||
#include <test.h>
|
#include <test.h>
|
||||||
|
|
||||||
|
#include "backend/driver.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -50,6 +52,7 @@
|
||||||
#include "picom.h"
|
#include "picom.h"
|
||||||
#include "transition.h"
|
#include "transition.h"
|
||||||
#include "win_defs.h"
|
#include "win_defs.h"
|
||||||
|
#include "xcb/xproto.h"
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
#include "opengl.h"
|
#include "opengl.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -73,6 +76,246 @@
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "x.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
|
/// Get session_t pointer from a pointer to a member of session_t
|
||||||
#define session_ptr(ptr, member) \
|
#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);
|
auto w = find_managed_win(ps, wid);
|
||||||
if (!w) {
|
if (!w) {
|
||||||
w = find_toplevel(ps, wid);
|
w = session_find_toplevel(ps, wid);
|
||||||
}
|
}
|
||||||
if (!w) {
|
if (!w) {
|
||||||
w = find_managed_window_or_parent(ps, wid);
|
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
|
// Check if it's a mapped client window
|
||||||
if (mode == WIN_EVMODE_CLIENT ||
|
if (mode == WIN_EVMODE_CLIENT || ((w = session_find_toplevel(ps, wid)) &&
|
||||||
((w = find_toplevel(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) {
|
w->a.map_state == XCB_MAP_STATE_VIEWABLE)) {
|
||||||
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE;
|
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -824,7 +1067,7 @@ static void configure_root(session_t *ps) {
|
||||||
rebuild_shadow_exclude_reg(ps);
|
rebuild_shadow_exclude_reg(ps);
|
||||||
|
|
||||||
// Invalidate reg_ignore from the top
|
// 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) {
|
if (top_w) {
|
||||||
rc_region_unref(&top_w->reg_ignore);
|
rc_region_unref(&top_w->reg_ignore);
|
||||||
top_w->reg_ignore_valid = false;
|
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;
|
return ps->overlay != XCB_NONE ? ps->overlay : ps->c.screen_info->root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_DBUS
|
||||||
struct cdbus_data *session_get_cdbus(struct session *ps) {
|
struct cdbus_data *session_get_cdbus(struct session *ps) {
|
||||||
return ps->dbus_data;
|
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) {
|
uint8_t session_redirection_mode(session_t *ps) {
|
||||||
if (ps->o.debug_mode) {
|
if (ps->o.debug_mode) {
|
||||||
|
@ -1679,7 +2418,7 @@ static void handle_new_windows(session_t *ps) {
|
||||||
}
|
}
|
||||||
// Send D-Bus signal
|
// Send D-Bus signal
|
||||||
if (ps->o.dbus) {
|
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_picture = XCB_NONE,
|
||||||
.tgt_buffer = PAINT_INIT,
|
.tgt_buffer = PAINT_INIT,
|
||||||
.reg_win = XCB_NONE,
|
.reg_win = XCB_NONE,
|
||||||
#ifdef CONFIG_OPENGL
|
|
||||||
.glx_prog_win = GLX_PROG_MAIN_INIT,
|
|
||||||
#endif
|
|
||||||
.redirected = false,
|
.redirected = false,
|
||||||
.alpha_picts = NULL,
|
.alpha_picts = NULL,
|
||||||
.fade_time = 0L,
|
.fade_time = 0L,
|
||||||
|
@ -2413,10 +3149,13 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||||
apply_driver_workarounds(ps, ps->drivers);
|
apply_driver_workarounds(ps, ps->drivers);
|
||||||
|
|
||||||
// Initialize filters, must be preceded by OpenGL context creation
|
// Initialize filters, must be preceded by OpenGL context creation
|
||||||
if (ps->o.legacy_backends && !init_render(ps)) {
|
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");
|
log_fatal("Failed to initialize the backend");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ps->o.print_diagnostics) {
|
if (ps->o.print_diagnostics) {
|
||||||
print_diagnostics(ps, config_file, compositor_running);
|
print_diagnostics(ps, config_file, compositor_running);
|
||||||
|
@ -2554,7 +3293,7 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||||
nchildren = xcb_query_tree_children_length(query_tree_reply);
|
nchildren = xcb_query_tree_children_length(query_tree_reply);
|
||||||
|
|
||||||
for (int i = 0; i < nchildren; i++) {
|
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);
|
free(query_tree_reply);
|
||||||
}
|
}
|
||||||
|
@ -2697,16 +3436,15 @@ static void session_destroy(session_t *ps) {
|
||||||
// backend is deinitialized in unredirect()
|
// backend is deinitialized in unredirect()
|
||||||
assert(ps->backend_data == NULL);
|
assert(ps->backend_data == NULL);
|
||||||
} else {
|
} else {
|
||||||
|
// Free all GLX resources of windows
|
||||||
|
win_stack_foreach_managed(w, &ps->window_stack) {
|
||||||
|
free_win_res_glx(ps, w);
|
||||||
|
}
|
||||||
deinit_render(ps);
|
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
|
// Flush all events
|
||||||
xcb_aux_sync(ps->c.c);
|
xcb_aux_sync(ps->c.c);
|
||||||
ev_io_stop(ps->loop, &ps->xiow);
|
ev_io_stop(ps->loop, &ps->xiow);
|
||||||
|
|
148
src/picom.h
148
src/picom.h
|
@ -1,29 +1,25 @@
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
// Copyright (c)
|
// Copyright (c) Yuxuan Shui.
|
||||||
|
|
||||||
// Throw everything in here.
|
|
||||||
// !!! DON'T !!!
|
|
||||||
|
|
||||||
// === Includes ===
|
// === Includes ===
|
||||||
|
#pragma once
|
||||||
#include <locale.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <xcb/xproto.h>
|
#include <xcb/xproto.h>
|
||||||
|
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
#include "backend/backend.h"
|
#include "backend/backend.h"
|
||||||
|
#include "backend/driver.h"
|
||||||
#include "c2.h"
|
#include "c2.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "compiler.h"
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "log.h" // XXX clean up
|
#include "ev.h"
|
||||||
|
#include "list.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "x.h"
|
#include "x.h"
|
||||||
|
#include "xcb/render.h"
|
||||||
|
|
||||||
enum root_flags {
|
enum root_flags {
|
||||||
ROOT_FLAGS_SCREEN_CHANGE = 1, // Received RandR screen change notify, we
|
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
|
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);
|
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);
|
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 circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce);
|
||||||
|
|
||||||
void root_damaged(session_t *ps);
|
void root_damaged(session_t *ps);
|
||||||
|
|
||||||
void queue_redraw(session_t *ps);
|
void queue_redraw(session_t *ps);
|
||||||
|
|
||||||
void discard_pending(session_t *ps, uint32_t sequence);
|
void discard_pending(session_t *ps, uint32_t sequence);
|
||||||
|
|
||||||
void set_root_flags(session_t *ps, uint64_t flags);
|
void set_root_flags(session_t *ps, uint64_t flags);
|
||||||
|
|
||||||
void quit(session_t *ps);
|
void quit(session_t *ps);
|
||||||
|
|
||||||
xcb_window_t session_get_target_window(session_t *);
|
xcb_window_t session_get_target_window(session_t *);
|
||||||
|
|
||||||
uint8_t session_redirection_mode(session_t *ps);
|
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
|
#ifdef CONFIG_DBUS
|
||||||
struct cdbus_data *session_get_cdbus(struct session *);
|
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) {
|
free_win_res_glx(session_t *ps attr_unused, struct managed_win *w attr_unused) {
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
|
||||||
}
|
|
||||||
|
|
622
src/render.c
622
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 "common.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "picom.h"
|
||||||
|
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
#include "backend/gl/glx.h"
|
#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??
|
// We don't have a context??
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
glXSwapIntervalEXT(ps->c.dpy, glXGetCurrentDrawable(), interval);
|
glXSwapIntervalEXT(session_get_x_connection(ps)->dpy,
|
||||||
|
glXGetCurrentDrawable(), interval);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
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) {
|
static int vsync_opengl_oml_wait(session_t *ps) {
|
||||||
int64_t ust = 0, msc = 0, sbc = 0;
|
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);
|
glXGetSyncValuesOML(c->dpy, session_get_target_window(ps), &ust, &msc, &sbc);
|
||||||
glXWaitForMscOML(ps->c.dpy, ps->reg_win, 0, 2, (msc + 1) % 2, &ust, &msc, &sbc);
|
glXWaitForMscOML(c->dpy, session_get_target_window(ps), 0, 2, (msc + 1) % 2, &ust,
|
||||||
|
&msc, &sbc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -164,7 +168,7 @@ bool vsync_init(session_t *ps) {
|
||||||
log_warn("The DRM vsync method is deprecated, please don't enable it.");
|
log_warn("The DRM vsync method is deprecated, please don't enable it.");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!ps->o.vsync) {
|
if (!session_get_options(ps)->vsync) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,8 +177,9 @@ bool vsync_init(session_t *ps) {
|
||||||
if (!vsync_opengl_swc_init(ps)) {
|
if (!vsync_opengl_swc_init(ps)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ps->vsync_wait = NULL; // glXSwapBuffers will automatically wait
|
// glXSwapBuffers will automatically wait for vsync, we don't
|
||||||
// for vsync, we don't need to do anything.
|
// need to do anything.
|
||||||
|
session_set_vsync_wait(ps, NULL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -184,13 +189,13 @@ bool vsync_init(session_t *ps) {
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
if (vsync_opengl_oml_init(ps)) {
|
if (vsync_opengl_oml_init(ps)) {
|
||||||
log_info("Using the opengl-oml vsync method");
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vsync_opengl_init(ps)) {
|
if (vsync_opengl_init(ps)) {
|
||||||
log_info("Using the opengl vsync method");
|
log_info("Using the opengl vsync method");
|
||||||
ps->vsync_wait = vsync_opengl_wait;
|
session_set_vsync_wait(ps, vsync_opengl_wait);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
void win_update_monitor(struct x_monitors *monitors, struct managed_win *mw);
|
||||||
|
|
||||||
/// Recheck if a window is fullscreen
|
/// 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
|
* 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
|
* Get a rectangular region in global coordinates a window (and possibly
|
||||||
* its shadow) occupies.
|
* 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);
|
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
|
/// 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);
|
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`
|
/// Query the Xorg for information about window `win`
|
||||||
/// `win` pointer might become invalid after this function returns
|
/// `win` pointer might become invalid after this function returns
|
||||||
struct win *attr_ret_nonnull maybe_allocate_managed_win(session_t *ps, struct win *win);
|
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.
|
* 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.
|
* 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 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`.
|
* 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;
|
return w->base.id == w->client_win && !w->a.override_redirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// check if reg_ignore_valid is true for all windows above us
|
static inline const char *win_get_name_if_managed(const struct win *w) {
|
||||||
bool attr_pure win_is_region_ignore_valid(session_t *ps, const struct managed_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
|
/// Whether a given window is mapped on the X server side
|
||||||
bool win_is_mapped_in_x(const struct managed_win *w);
|
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
|
/// Set flags on a window. Some sanity checks are performed
|
||||||
void win_set_flags(struct managed_win *w, uint64_t flags);
|
void win_set_flags(struct managed_win *w, uint64_t flags);
|
||||||
/// Clear flags on a window. Some sanity checks are performed
|
/// 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 <xcb/xfixes.h>
|
||||||
|
|
||||||
#include "atom.h"
|
#include "atom.h"
|
||||||
|
#include "picom.h"
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
#include "backend/gl/glx.h"
|
#include "backend/gl/glx.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -49,7 +50,7 @@ static int xerror(Display attr_unused *dpy, XErrorEvent *ev) {
|
||||||
xcb_err.major_code = ev->request_code;
|
xcb_err.major_code = ev->request_code;
|
||||||
xcb_err.minor_code = ev->minor_code;
|
xcb_err.minor_code = ev->minor_code;
|
||||||
xcb_err.error_code = ev->error_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;
|
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
|
case XCB_##s: name = #s; break
|
||||||
|
|
||||||
// TODO(yshui) separate error code out from session_t
|
// 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); }
|
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); }
|
switch (o) { CASESTRRET2(DAMAGE_BAD_DAMAGE); }
|
||||||
|
|
||||||
o = error_code - ps->render_error;
|
o = error_code - session_get_render_extension_error(ps);
|
||||||
switch (o) {
|
switch (o) {
|
||||||
CASESTRRET2(RENDER_PICT_FORMAT);
|
CASESTRRET2(RENDER_PICT_FORMAT);
|
||||||
CASESTRRET2(RENDER_PICTURE);
|
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);
|
CASESTRRET2(RENDER_GLYPH);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps->glx_exists) {
|
if (session_has_glx_extension(ps)) {
|
||||||
o = error_code - ps->glx_error;
|
o = error_code - session_get_glx_extension_error(ps);
|
||||||
switch (o) {
|
switch (o) {
|
||||||
CASESTRRET2(GLX_BAD_CONTEXT);
|
CASESTRRET2(GLX_BAD_CONTEXT);
|
||||||
CASESTRRET2(GLX_BAD_CONTEXT_STATE);
|
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) {
|
if (session_get_xsync_extension_error(ps)) {
|
||||||
o = error_code - ps->xsync_error;
|
o = error_code - session_get_xsync_extension_error(ps);
|
||||||
switch (o) {
|
switch (o) {
|
||||||
CASESTRRET(XSyncBadCounter);
|
CASESTRRET(XSyncBadCounter);
|
||||||
CASESTRRET(XSyncBadAlarm);
|
CASESTRRET(XSyncBadAlarm);
|
||||||
|
|
Loading…
Reference in New Issue