Added New Backend Dual Kawase Blur + Rounded Corners - merged with Ibhagwan
This commit is contained in:
@@ -55,7 +55,7 @@ region_t get_damage(session_t *ps, bool all_damage) {
|
||||
|
||||
/// paint all windows
|
||||
void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
if (ps->o.xrender_sync_fence) {
|
||||
if (ps->o.xrender_sync_fence || (ps->drivers & DRIVER_NVIDIA)) {
|
||||
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.");
|
||||
@@ -151,11 +151,8 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
}
|
||||
|
||||
if (ps->root_image) {
|
||||
ps->backend_data->ops->compose(ps->backend_data, ps->root_image, 0, 0,
|
||||
ps->backend_data->ops->compose(ps->backend_data, t, ps->root_image, 0, 0,
|
||||
®_paint, ®_visible);
|
||||
} else {
|
||||
ps->backend_data->ops->fill(ps->backend_data, (struct color){0, 0, 0, 1},
|
||||
®_paint);
|
||||
}
|
||||
|
||||
// Windows are sorted from bottom to top
|
||||
@@ -171,7 +168,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
|
||||
// The bounding shape of the window, in global/target coordinates
|
||||
// reminder: bounding shape contains the WM frame
|
||||
auto reg_bound = win_get_bounding_shape_global_by_val(w);
|
||||
auto reg_bound = win_get_bounding_shape_global_by_val(w, true);
|
||||
|
||||
// The clip region for the current window, in global/target coordinates
|
||||
// reg_paint_in_bound \in reg_paint
|
||||
@@ -190,6 +187,17 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
®_paint_in_bound, ®_visible);
|
||||
}
|
||||
|
||||
// Store the window background for rounded corners
|
||||
// If rounded corners backup the region first
|
||||
if (w->corner_radius > 0) {
|
||||
const int16_t x = w->g.x;
|
||||
const int16_t y = w->g.y;
|
||||
const auto wid = to_u16_checked(w->widthb);
|
||||
const auto hei = to_u16_checked(w->heightb);
|
||||
ps->backend_data->ops->store_back_texture(ps->backend_data, w,
|
||||
ps->backend_round_context, ®_bound, x, y, wid, hei);
|
||||
}
|
||||
|
||||
// Blur window background
|
||||
// TODO since the background might change the content of the window (e.g.
|
||||
// with shaders), we should consult the background whether the window
|
||||
@@ -204,36 +212,20 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
// itself is not opaque, only the frame is.
|
||||
|
||||
double blur_opacity = 1;
|
||||
if (w->opacity < (1.0 / MAX_ALPHA)) {
|
||||
// Hide blur for fully transparent windows.
|
||||
blur_opacity = 0;
|
||||
} else if (w->state == WSTATE_MAPPING) {
|
||||
if (w->state == WSTATE_MAPPING) {
|
||||
// Gradually increase the blur intensity during
|
||||
// fading in.
|
||||
assert(w->opacity <= w->opacity_target);
|
||||
blur_opacity = w->opacity / w->opacity_target;
|
||||
} else if (w->state == WSTATE_UNMAPPING ||
|
||||
w->state == WSTATE_DESTROYING) {
|
||||
// Gradually decrease the blur intensity during
|
||||
// fading out.
|
||||
assert(w->opacity <= w->opacity_target_old);
|
||||
blur_opacity = w->opacity / w->opacity_target_old;
|
||||
} else if (w->state == WSTATE_FADING) {
|
||||
if (w->opacity < w->opacity_target &&
|
||||
w->opacity_target_old < (1.0 / MAX_ALPHA)) {
|
||||
// Gradually increase the blur intensity during
|
||||
// fading in.
|
||||
assert(w->opacity <= w->opacity_target);
|
||||
blur_opacity = w->opacity / w->opacity_target;
|
||||
} else if (w->opacity > w->opacity_target &&
|
||||
w->opacity_target < (1.0 / MAX_ALPHA)) {
|
||||
// Gradually decrease the blur intensity during
|
||||
// fading out.
|
||||
assert(w->opacity <= w->opacity_target_old);
|
||||
blur_opacity = w->opacity / w->opacity_target_old;
|
||||
}
|
||||
blur_opacity =
|
||||
w->opacity / win_calc_opacity_target(ps, w, true);
|
||||
} else if (!ps->o.blur_background_fixed) {
|
||||
// Apply blur intensity depending on the window opacity.
|
||||
blur_opacity = w->opacity;
|
||||
}
|
||||
assert(blur_opacity >= 0 && blur_opacity <= 1);
|
||||
|
||||
if (real_win_mode == WMODE_TRANS || ps->o.force_win_blend) {
|
||||
// We need to blur the bounding shape of the window
|
||||
@@ -249,7 +241,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
assert(ps->o.blur_background_frame);
|
||||
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, true);
|
||||
pixman_region32_translate(®_blur, w->g.x, w->g.y);
|
||||
// make sure reg_blur \in reg_paint
|
||||
pixman_region32_intersect(®_blur, ®_blur, ®_paint);
|
||||
@@ -305,7 +297,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
assert(w->shadow_image);
|
||||
if (w->opacity == 1) {
|
||||
ps->backend_data->ops->compose(
|
||||
ps->backend_data, w->shadow_image, w->g.x + w->shadow_dx,
|
||||
ps->backend_data, w, w->shadow_image, w->g.x + w->shadow_dx,
|
||||
w->g.y + w->shadow_dy, ®_shadow, ®_visible);
|
||||
} else {
|
||||
auto new_img = ps->backend_data->ops->copy(
|
||||
@@ -314,7 +306,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
ps->backend_data, IMAGE_OP_APPLY_ALPHA_ALL, new_img,
|
||||
NULL, ®_visible, (double[]){w->opacity});
|
||||
ps->backend_data->ops->compose(
|
||||
ps->backend_data, new_img, w->g.x + w->shadow_dx,
|
||||
ps->backend_data, w, new_img, w->g.x + w->shadow_dx,
|
||||
w->g.y + w->shadow_dy, ®_shadow, ®_visible);
|
||||
ps->backend_data->ops->release_image(ps->backend_data, new_img);
|
||||
}
|
||||
@@ -330,7 +322,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
|
||||
// Draw window on target
|
||||
if (!w->invert_color && !w->dim && w->frame_opacity == 1 && w->opacity == 1) {
|
||||
ps->backend_data->ops->compose(ps->backend_data, w->win_image,
|
||||
ps->backend_data->ops->compose(ps->backend_data, w, w->win_image,
|
||||
w->g.x, w->g.y,
|
||||
®_paint_in_bound, ®_visible);
|
||||
} else if (w->opacity * MAX_ALPHA >= 1) {
|
||||
@@ -379,7 +371,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
®_visible_local, (double[]){dim_opacity});
|
||||
}
|
||||
if (w->frame_opacity != 1) {
|
||||
auto reg_frame = win_get_region_frame_local_by_val(w);
|
||||
auto reg_frame = win_get_region_frame_local_by_val(w, true);
|
||||
ps->backend_data->ops->image_op(
|
||||
ps->backend_data, IMAGE_OP_APPLY_ALPHA, new_img, ®_frame,
|
||||
®_visible_local, (double[]){w->frame_opacity});
|
||||
@@ -390,13 +382,21 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
ps->backend_data, IMAGE_OP_APPLY_ALPHA_ALL, new_img,
|
||||
NULL, ®_visible_local, (double[]){w->opacity});
|
||||
}
|
||||
ps->backend_data->ops->compose(ps->backend_data, new_img, w->g.x,
|
||||
ps->backend_data->ops->compose(ps->backend_data, w, new_img, w->g.x,
|
||||
w->g.y, ®_paint_in_bound,
|
||||
®_visible);
|
||||
ps->backend_data->ops->release_image(ps->backend_data, new_img);
|
||||
pixman_region32_fini(®_visible_local);
|
||||
pixman_region32_fini(®_bound_local);
|
||||
}
|
||||
|
||||
// Round the corners as last step after blur/shadow/dim/etc
|
||||
if (w->corner_radius > 0.0) {
|
||||
ps->backend_data->ops->round(ps->backend_data, w,
|
||||
ps->backend_round_context, w->win_image,
|
||||
®_bound, ®_visible);
|
||||
}
|
||||
|
||||
pixman_region32_fini(®_bound);
|
||||
pixman_region32_fini(®_paint_in_bound);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,9 @@ typedef struct backend_base {
|
||||
/// Whether the backend can accept new render request at the moment
|
||||
bool busy;
|
||||
// ...
|
||||
|
||||
// Session data
|
||||
session_t *ps;
|
||||
} backend_t;
|
||||
|
||||
typedef void (*backend_ready_callback_t)(void *);
|
||||
@@ -56,6 +59,11 @@ struct gaussian_blur_args {
|
||||
double deviation;
|
||||
};
|
||||
|
||||
struct dual_kawase_blur_args {
|
||||
int size;
|
||||
blur_strength_t strength;
|
||||
};
|
||||
|
||||
struct box_blur_args {
|
||||
int size;
|
||||
};
|
||||
@@ -65,6 +73,11 @@ struct kernel_blur_args {
|
||||
int kernel_count;
|
||||
};
|
||||
|
||||
struct round_corners_args {
|
||||
int corner_radius;
|
||||
bool round_borders;
|
||||
};
|
||||
|
||||
struct backend_operations {
|
||||
// =========== Initialization ===========
|
||||
|
||||
@@ -126,7 +139,7 @@ struct backend_operations {
|
||||
* @param reg_paint the clip region, in target coordinates
|
||||
* @param reg_visible the visible region, in target coordinates
|
||||
*/
|
||||
void (*compose)(backend_t *backend_data, void *image_data, int dst_x, int dst_y,
|
||||
void (*compose)(backend_t *backend_data, struct managed_win *const w, void *image_data, int dst_x, int dst_y,
|
||||
const region_t *reg_paint, const region_t *reg_visible);
|
||||
|
||||
/// Fill rectangle of the rendering buffer, mostly for debug purposes, optional.
|
||||
@@ -137,6 +150,11 @@ struct backend_operations {
|
||||
const region_t *reg_blur, const region_t *reg_visible)
|
||||
attr_nonnull(1, 3, 4, 5);
|
||||
|
||||
/// Round a given region of the rendering buffer.
|
||||
bool (*round)(backend_t *backend_data, struct managed_win *w, void *round_ctx,
|
||||
void *image_data, const region_t *reg_round, const region_t *reg_visible)
|
||||
attr_nonnull(1, 2, 3, 5, 6);
|
||||
|
||||
/// Update part of the back buffer with the rendering buffer, then present the
|
||||
/// back buffer onto the target window (if not back buffered, update part of the
|
||||
/// target window directly).
|
||||
@@ -218,6 +236,15 @@ struct backend_operations {
|
||||
/// Get how many pixels outside of the blur area is needed for blur
|
||||
void (*get_blur_size)(void *blur_context, int *width, int *height);
|
||||
|
||||
/// Backup our current window background so we can use it for "erasing" corners
|
||||
bool (*store_back_texture)(backend_t *base, struct managed_win *w, void *ctx_,
|
||||
const region_t *reg_tgt, int x, int y, int width, int height);
|
||||
|
||||
/// Create a rounded corners context
|
||||
void *(*create_round_context)(backend_t *base, void *args);
|
||||
/// Destroy a rounded corners context
|
||||
void (*destroy_round_context)(backend_t *base, void *ctx);
|
||||
|
||||
// =========== Hooks ============
|
||||
/// Let the backend hook into the event handling queue
|
||||
/// Not implemented yet
|
||||
|
||||
@@ -362,10 +362,106 @@ struct conv **generate_blur_kernel(enum blur_method method, void *args, int *ker
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Generate kernel parameters for dual-kawase blur method. Falls back on approximating
|
||||
/// standard gauss radius if strength is not supplied
|
||||
struct dual_kawase_params *generate_dual_kawase_params(void *args) {
|
||||
struct dual_kawase_blur_args *blur_args = args;
|
||||
static const struct {
|
||||
int iterations;
|
||||
float offset;
|
||||
} strength_levels[20] = {
|
||||
{.iterations = 1, .offset = 1.25f}, // LVL 1 => radius 4
|
||||
{.iterations = 1, .offset = 2.25f}, // LVL 2 => radius 7
|
||||
{.iterations = 2, .offset = 2.00f}, // LVL 3 => radius 14
|
||||
{.iterations = 2, .offset = 3.00f}, // LVL 4 => radius 20
|
||||
{.iterations = 2, .offset = 4.25f}, // LVL 5 => radius 28
|
||||
{.iterations = 3, .offset = 2.50f}, // LVL 6 => radius 35
|
||||
{.iterations = 3, .offset = 3.25f}, // LVL 7 => radius 45
|
||||
{.iterations = 3, .offset = 4.25f}, // LVL 8 => radius 57
|
||||
{.iterations = 3, .offset = 5.50f}, // LVL 9 => radius 74
|
||||
{.iterations = 4, .offset = 3.25f}, // LVL 10 => radius 91
|
||||
{.iterations = 4, .offset = 4.00f}, // LVL 11 => radius 110
|
||||
{.iterations = 4, .offset = 5.00f}, // LVL 12 => radius 135
|
||||
{.iterations = 4, .offset = 6.00f}, // LVL 13 => radius 161
|
||||
{.iterations = 4, .offset = 7.25f}, // LVL 14 => radius 195
|
||||
{.iterations = 4, .offset = 8.25f}, // LVL 15 => radius 221
|
||||
{.iterations = 5, .offset = 4.50f}, // LVL 16 => radius 250
|
||||
{.iterations = 5, .offset = 5.25f}, // LVL 17 => radius 287
|
||||
{.iterations = 5, .offset = 6.25f}, // LVL 18 => radius 330
|
||||
{.iterations = 5, .offset = 7.25f}, // LVL 19 => radius 383
|
||||
{.iterations = 5, .offset = 8.50f}, // LVL 20 => radius >450
|
||||
};
|
||||
|
||||
auto params = ccalloc(1, struct dual_kawase_params);
|
||||
params->iterations = 0;
|
||||
params->offset = 1.0f;
|
||||
|
||||
if (blur_args->strength.strength <= 0 && blur_args->size) {
|
||||
// approximate blur_strength with gaussian blur_radius
|
||||
if (blur_args->size < 6) {
|
||||
blur_args->strength.strength = 1;
|
||||
} else if (blur_args->size < 11) {
|
||||
blur_args->strength.strength = 2;
|
||||
} else if (blur_args->size < 17) {
|
||||
blur_args->strength.strength = 3;
|
||||
} else if (blur_args->size < 24) {
|
||||
blur_args->strength.strength = 4;
|
||||
} else if (blur_args->size < 32) {
|
||||
blur_args->strength.strength = 5;
|
||||
} else if (blur_args->size < 40) {
|
||||
blur_args->strength.strength = 6;
|
||||
} else if (blur_args->size < 51) {
|
||||
blur_args->strength.strength = 7;
|
||||
} else if (blur_args->size < 67) {
|
||||
blur_args->strength.strength = 8;
|
||||
} else if (blur_args->size < 83) {
|
||||
blur_args->strength.strength = 9;
|
||||
} else if (blur_args->size < 101) {
|
||||
blur_args->strength.strength = 10;
|
||||
} else if (blur_args->size < 123) {
|
||||
blur_args->strength.strength = 11;
|
||||
} else if (blur_args->size < 148) {
|
||||
blur_args->strength.strength = 12;
|
||||
} else if (blur_args->size < 177) {
|
||||
blur_args->strength.strength = 13;
|
||||
} else if (blur_args->size < 208) {
|
||||
blur_args->strength.strength = 14;
|
||||
} else if (blur_args->size < 236) {
|
||||
blur_args->strength.strength = 15;
|
||||
} else if (blur_args->size < 269) {
|
||||
blur_args->strength.strength = 16;
|
||||
} else if (blur_args->size < 309) {
|
||||
blur_args->strength.strength = 17;
|
||||
} else if (blur_args->size < 357) {
|
||||
blur_args->strength.strength = 18;
|
||||
} else if (blur_args->size < 417) {
|
||||
blur_args->strength.strength = 19;
|
||||
} else {
|
||||
blur_args->strength.strength = 20;
|
||||
}
|
||||
}
|
||||
|
||||
if (blur_args->strength.strength > 0) {
|
||||
assert(blur_args->strength.strength <= 20);
|
||||
params->iterations = strength_levels[blur_args->strength.strength - 1].iterations;
|
||||
params->offset = strength_levels[blur_args->strength.strength - 1].offset;
|
||||
}
|
||||
|
||||
params->expand = 2 * (int)exp2f((float)params->iterations) *
|
||||
(256 - (int)(256.0f - params->offset)) +
|
||||
1;
|
||||
|
||||
log_info("blur-strength: %d [.iter = %d, .offset = %f]",
|
||||
blur_args->strength.strength, params->iterations, params->offset);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
void init_backend_base(struct backend_base *base, session_t *ps) {
|
||||
base->c = ps->c;
|
||||
base->loop = ps->loop;
|
||||
base->root = ps->root;
|
||||
base->busy = false;
|
||||
base->ops = NULL;
|
||||
base->ps = ps;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,15 @@ typedef struct conv conv;
|
||||
typedef struct backend_base backend_t;
|
||||
struct backend_operations;
|
||||
|
||||
typedef struct dual_kawase_params {
|
||||
/// Number of downsample passes
|
||||
int iterations;
|
||||
/// Pixel offset for down- and upsample
|
||||
float offset;
|
||||
/// Save area around blur target (@ref resize_width, @ref resize_height)
|
||||
int expand;
|
||||
} dual_kawase_params_t;
|
||||
|
||||
bool build_shadow(xcb_connection_t *, xcb_drawable_t, double opacity, int width,
|
||||
int height, const conv *kernel, xcb_render_picture_t shadow_pixel,
|
||||
xcb_pixmap_t *pixmap, xcb_render_picture_t *pict);
|
||||
@@ -41,3 +50,5 @@ default_backend_render_shadow(backend_t *backend_data, int width, int height,
|
||||
void init_backend_base(struct backend_base *base, session_t *ps);
|
||||
|
||||
struct conv **generate_blur_kernel(enum blur_method method, void *args, int *kernel_count);
|
||||
|
||||
struct dual_kawase_params *generate_dual_kawase_params(void *args);
|
||||
|
||||
@@ -12,14 +12,6 @@
|
||||
#include "compiler.h"
|
||||
#include "log.h"
|
||||
|
||||
/// Apply driver specified global workarounds. It's safe to call this multiple times.
|
||||
void apply_driver_workarounds(struct session *ps, enum driver driver) {
|
||||
if (driver & DRIVER_NVIDIA) {
|
||||
setenv("__GL_YIELD", "usleep", true);
|
||||
ps->o.xrender_sync_fence = true;
|
||||
}
|
||||
}
|
||||
|
||||
enum driver detect_driver(xcb_connection_t *c, backend_t *backend_data, xcb_window_t window) {
|
||||
enum driver ret = 0;
|
||||
// First we try doing backend agnostic detection using RANDR
|
||||
|
||||
@@ -32,9 +32,6 @@ enum driver {
|
||||
/// Note, this is a best-effort test, so no guarantee all drivers will be detected.
|
||||
enum driver detect_driver(xcb_connection_t *, struct backend_base *, xcb_window_t);
|
||||
|
||||
/// Apply driver specified global workarounds. It's safe to call this multiple times.
|
||||
void apply_driver_workarounds(struct session *ps, enum driver);
|
||||
|
||||
// Print driver names to stdout, for diagnostics
|
||||
static inline void print_drivers(enum driver drivers) {
|
||||
if (drivers & DRIVER_AMDGPU) {
|
||||
|
||||
@@ -56,7 +56,7 @@ static void dummy_check_image(struct backend_base *base, const struct dummy_imag
|
||||
assert(*tmp->refcount > 0);
|
||||
}
|
||||
|
||||
void dummy_compose(struct backend_base *base, void *image, int dst_x attr_unused,
|
||||
void dummy_compose(struct backend_base *base, struct managed_win *w attr_unused, void *image, int dst_x attr_unused,
|
||||
int dst_y attr_unused, const region_t *reg_paint attr_unused,
|
||||
const region_t *reg_visible attr_unused) {
|
||||
dummy_check_image(base, image);
|
||||
@@ -72,6 +72,12 @@ bool dummy_blur(struct backend_base *backend_data attr_unused, double opacity at
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dummy_round(struct backend_base *backend_data attr_unused, struct managed_win *w attr_unused,
|
||||
void *ctx_ attr_unused, void *image_data attr_unused, const region_t *reg_round attr_unused,
|
||||
const region_t *reg_visible attr_unused) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void *dummy_bind_pixmap(struct backend_base *base, xcb_pixmap_t pixmap,
|
||||
struct xvisual_info fmt, bool owned attr_unused) {
|
||||
auto dummy = (struct dummy_data *)base;
|
||||
@@ -138,6 +144,14 @@ void *dummy_create_blur_context(struct backend_base *base attr_unused,
|
||||
void dummy_destroy_blur_context(struct backend_base *base attr_unused, void *ctx attr_unused) {
|
||||
}
|
||||
|
||||
void *dummy_create_round_context(struct backend_base *base attr_unused, void *args attr_unused) {
|
||||
static int dummy_context;
|
||||
return &dummy_context;
|
||||
}
|
||||
|
||||
void dummy_destroy_round_context(struct backend_base *base attr_unused, void *ctx attr_unused) {
|
||||
}
|
||||
|
||||
void dummy_get_blur_size(void *ctx attr_unused, int *width, int *height) {
|
||||
// These numbers are arbitrary, to make sure the reisze_region code path is
|
||||
// covered.
|
||||
@@ -145,12 +159,18 @@ void dummy_get_blur_size(void *ctx attr_unused, int *width, int *height) {
|
||||
*height = 5;
|
||||
}
|
||||
|
||||
bool dummy_store_back_texture(backend_t *backend_data attr_unused, struct managed_win *w attr_unused, void *ctx_ attr_unused,
|
||||
const region_t *reg_tgt attr_unused, int x attr_unused, int y attr_unused, int width attr_unused, int height attr_unused) {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct backend_operations dummy_ops = {
|
||||
.init = dummy_init,
|
||||
.deinit = dummy_deinit,
|
||||
.compose = dummy_compose,
|
||||
.fill = dummy_fill,
|
||||
.blur = dummy_blur,
|
||||
.round = dummy_round,
|
||||
.bind_pixmap = dummy_bind_pixmap,
|
||||
.render_shadow = default_backend_render_shadow,
|
||||
.release_image = dummy_release_image,
|
||||
@@ -162,6 +182,9 @@ struct backend_operations dummy_ops = {
|
||||
.copy = dummy_image_copy,
|
||||
.create_blur_context = dummy_create_blur_context,
|
||||
.destroy_blur_context = dummy_destroy_blur_context,
|
||||
.create_round_context = dummy_create_round_context,
|
||||
.destroy_round_context = dummy_destroy_round_context,
|
||||
.get_blur_size = dummy_get_blur_size,
|
||||
.store_back_texture = dummy_store_back_texture
|
||||
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,10 +33,25 @@ typedef struct {
|
||||
typedef struct {
|
||||
GLuint prog;
|
||||
GLint unifm_opacity;
|
||||
GLint unifm_texture_size;
|
||||
GLint unifm_halfpixel;
|
||||
GLint orig_loc;
|
||||
GLint texorig_loc;
|
||||
GLint projection_loc;
|
||||
} gl_blur_shader_t;
|
||||
|
||||
typedef struct {
|
||||
GLuint prog;
|
||||
GLint projection_loc;
|
||||
GLint unifm_radius;
|
||||
GLint unifm_texcoord;
|
||||
GLint unifm_texsize;
|
||||
GLint unifm_borderw;
|
||||
GLint unifm_resolution;
|
||||
GLint unifm_tex_bg;
|
||||
GLint unifm_tex_wnd;
|
||||
} gl_round_shader_t;
|
||||
|
||||
typedef struct {
|
||||
GLuint prog;
|
||||
GLint color_loc;
|
||||
@@ -68,7 +83,7 @@ struct gl_data {
|
||||
backend_t base;
|
||||
// If we are using proprietary NVIDIA driver
|
||||
bool is_nvidia;
|
||||
// Height and width of the root window
|
||||
// Height and width of the viewport
|
||||
int height, width;
|
||||
gl_win_shader_t win_shader;
|
||||
gl_brightness_shader_t brightness_shader;
|
||||
@@ -98,7 +113,7 @@ GLuint gl_create_program_from_str(const char *vert_shader_str, const char *frag_
|
||||
/**
|
||||
* @brief Render a region with texture data.
|
||||
*/
|
||||
void gl_compose(backend_t *, void *ptex, int dst_x, int dst_y, const region_t *reg_tgt,
|
||||
void gl_compose(backend_t *, struct managed_win *, void *ptex, int dst_x, int dst_y, const region_t *reg_tgt,
|
||||
const region_t *reg_visible);
|
||||
|
||||
void gl_resize(struct gl_data *, int width, int height);
|
||||
@@ -121,6 +136,14 @@ void *gl_create_blur_context(backend_t *base, enum blur_method, void *args);
|
||||
void gl_destroy_blur_context(backend_t *base, void *ctx);
|
||||
void gl_get_blur_size(void *blur_context, int *width, int *height);
|
||||
|
||||
|
||||
bool gl_round(backend_t *backend_data, struct managed_win *w, void *ctx_,
|
||||
void *image_data, const region_t *reg_round, const region_t *reg_visible);
|
||||
void *gl_create_round_context(backend_t *base, void *args);
|
||||
void gl_destroy_round_context(backend_t *base, void *ctx);
|
||||
bool gl_store_back_texture(backend_t *backend_data, struct managed_win *w,
|
||||
void *ctx_, const region_t *reg_tgt, int x, int y, int width, int height);
|
||||
|
||||
bool gl_is_image_transparent(backend_t *base, void *image_data);
|
||||
void gl_fill(backend_t *base, struct color, const region_t *clip);
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ struct _glx_data {
|
||||
Display *display;
|
||||
int screen;
|
||||
xcb_window_t target_win;
|
||||
int glx_event;
|
||||
int glx_error;
|
||||
GLXContext ctx;
|
||||
};
|
||||
|
||||
@@ -244,7 +246,7 @@ static backend_t *glx_init(session_t *ps) {
|
||||
XVisualInfo *pvis = NULL;
|
||||
|
||||
// Check for GLX extension
|
||||
if (!ps->glx_exists) {
|
||||
if (!glXQueryExtension(ps->dpy, &gd->glx_event, &gd->glx_error)) {
|
||||
log_error("No GLX extension.");
|
||||
goto end;
|
||||
}
|
||||
@@ -466,7 +468,10 @@ static void glx_present(backend_t *base, const region_t *region attr_unused) {
|
||||
struct _glx_data *gd = (void *)base;
|
||||
gl_present(base, region);
|
||||
glXSwapBuffers(gd->display, gd->target_win);
|
||||
glFinish();
|
||||
// XXX there should be no need to block, the core should wait for render to finish
|
||||
if (!gd->gl.is_nvidia) {
|
||||
glFinish();
|
||||
}
|
||||
}
|
||||
|
||||
static int glx_buffer_age(backend_t *base) {
|
||||
@@ -489,6 +494,7 @@ struct backend_operations glx_ops = {
|
||||
.image_op = gl_image_op,
|
||||
.copy = gl_copy,
|
||||
.blur = gl_blur,
|
||||
.round = gl_round,
|
||||
.is_image_transparent = gl_is_image_transparent,
|
||||
.present = glx_present,
|
||||
.buffer_age = glx_buffer_age,
|
||||
@@ -496,7 +502,10 @@ struct backend_operations glx_ops = {
|
||||
.fill = gl_fill,
|
||||
.create_blur_context = gl_create_blur_context,
|
||||
.destroy_blur_context = gl_destroy_blur_context,
|
||||
.create_round_context = gl_create_round_context,
|
||||
.destroy_round_context = gl_destroy_round_context,
|
||||
.get_blur_size = gl_get_blur_size,
|
||||
.store_back_texture = gl_store_back_texture,
|
||||
.max_buffer_age = 5, // Why?
|
||||
};
|
||||
|
||||
|
||||
@@ -90,7 +90,9 @@ struct _xrender_image_data {
|
||||
bool owned;
|
||||
};
|
||||
|
||||
static void compose(backend_t *base, void *img_data, int dst_x, int dst_y,
|
||||
uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_ntraps, int cr, int wid, int hei);
|
||||
|
||||
static void compose(backend_t *base, struct managed_win *w, void *img_data, int dst_x, int dst_y,
|
||||
const region_t *reg_paint, const region_t *reg_visible) {
|
||||
struct _xrender_data *xd = (void *)base;
|
||||
struct _xrender_image_data *img = img_data;
|
||||
@@ -104,10 +106,52 @@ static void compose(backend_t *base, void *img_data, int dst_x, int dst_y,
|
||||
// sure we get everything into the buffer
|
||||
x_clear_picture_clip_region(base->c, img->pict);
|
||||
|
||||
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, ®);
|
||||
xcb_render_composite(base->c, op, img->pict, alpha_pict, xd->back[2], 0, 0, 0, 0,
|
||||
to_i16_checked(dst_x), to_i16_checked(dst_y),
|
||||
to_u16_checked(img->ewidth), to_u16_checked(img->eheight));
|
||||
// Are we rounding corners?
|
||||
session_t *ps = base->ps;
|
||||
int cr = (w ? w->corner_radius : 0);
|
||||
|
||||
if (cr == 0) {
|
||||
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, ®);
|
||||
xcb_render_composite(base->c, op, img->pict, alpha_pict, xd->back[2], 0, 0, 0, 0,
|
||||
to_i16_checked(dst_x), to_i16_checked(dst_y),
|
||||
to_u16_checked(img->ewidth), to_u16_checked(img->eheight));
|
||||
} else {
|
||||
// Rounded corners
|
||||
const int fullwid = w ? w->widthb : 0;
|
||||
const int fullhei = w ? w-> heightb : 0;
|
||||
//const int fullwid = img->width;
|
||||
//const int fullhei = img->height;
|
||||
//log_warn("f(%d, %d) imge(%d %d) imgf(%d %d) sdw(%d %d) dst(%d %d) s:%d b:%d", fullwid, fullhei, img->ewidth, img->eheight, img->width, img->height, w->shadow_width, w->shadow_height, dst_x, dst_y, w->shadow, w->g.border_width);
|
||||
xcb_render_picture_t p_tmp = x_create_picture_with_standard(
|
||||
ps->c, ps->root, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
|
||||
xcb_render_color_t trans = {
|
||||
.red = 0, .blue = 0, .green = 0, .alpha = 0};
|
||||
const xcb_rectangle_t rect = {.x = 0,
|
||||
.y = 0,
|
||||
.width = to_u16_checked(fullwid),
|
||||
.height = to_u16_checked(fullhei)};
|
||||
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC,
|
||||
p_tmp, trans, 1, &rect);
|
||||
|
||||
uint32_t max_ntraps = to_u32_checked(cr);
|
||||
xcb_render_trapezoid_t traps[4 * max_ntraps + 5];
|
||||
|
||||
uint32_t n = make_rounded_window_shape(traps, max_ntraps, cr, fullwid, fullhei);
|
||||
|
||||
xcb_render_trapezoids(
|
||||
ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp,
|
||||
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8),
|
||||
0, 0, n, traps);
|
||||
|
||||
x_set_picture_clip_region(base->c, xd->back[2], 0, 0, ®);
|
||||
xcb_render_composite(base->c, XCB_RENDER_PICT_OP_OVER, img->pict, p_tmp, xd->back[2],
|
||||
0, 0, 0, 0,
|
||||
//0, 0, to_i16_checked(x), to_i16_checked(y),
|
||||
to_i16_checked(dst_x), to_i16_checked(dst_y),
|
||||
to_u16_checked(img->ewidth), to_u16_checked(img->eheight));
|
||||
|
||||
xcb_render_free_picture(ps->c, p_tmp);
|
||||
}
|
||||
pixman_region32_fini(®);
|
||||
}
|
||||
|
||||
@@ -245,6 +289,15 @@ static bool blur(backend_t *backend_data, double opacity, void *ctx_,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool x_round(struct backend_base *backend_data attr_unused, struct managed_win *w attr_unused,
|
||||
void *ctx_ attr_unused, void *image_data attr_unused, const region_t *reg_blur attr_unused,
|
||||
const region_t *reg_visible attr_unused) {
|
||||
|
||||
// dummy implementation, we already perform the rounding in compose
|
||||
// TODO: should move the compose code here and call it from here
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *
|
||||
bind_pixmap(backend_t *base, xcb_pixmap_t pixmap, struct xvisual_info fmt, bool owned) {
|
||||
xcb_generic_error_t *e;
|
||||
@@ -506,6 +559,13 @@ void *create_blur_context(backend_t *base attr_unused, enum blur_method method,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (method == BLUR_METHOD_DUAL_KAWASE || method == BLUR_METHOD_ALT_KAWASE) {
|
||||
log_warn("Blur method 'kawase' is not compatible with the 'xrender' "
|
||||
"backend.");
|
||||
ret->method = BLUR_METHOD_NONE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret->method = BLUR_METHOD_KERNEL;
|
||||
struct conv **kernels;
|
||||
int kernel_count;
|
||||
@@ -551,6 +611,19 @@ void get_blur_size(void *blur_context, int *width, int *height) {
|
||||
*height = ctx->resize_height;
|
||||
}
|
||||
|
||||
bool store_back_texture(backend_t *backend_data attr_unused, struct managed_win *w attr_unused, void *ctx_ attr_unused,
|
||||
const region_t *reg_tgt attr_unused, int x attr_unused, int y attr_unused, int width attr_unused, int height attr_unused) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void *create_round_context(struct backend_base *base attr_unused, void *args attr_unused) {
|
||||
static int dummy_context;
|
||||
return &dummy_context;
|
||||
}
|
||||
|
||||
void destroy_round_context(struct backend_base *base attr_unused, void *ctx attr_unused) {
|
||||
}
|
||||
|
||||
backend_t *backend_xrender_init(session_t *ps) {
|
||||
auto xd = ccalloc(1, struct _xrender_data);
|
||||
init_backend_base(&xd->base, ps);
|
||||
@@ -638,6 +711,7 @@ struct backend_operations xrender_ops = {
|
||||
.init = backend_xrender_init,
|
||||
.deinit = deinit,
|
||||
.blur = blur,
|
||||
.round = x_round,
|
||||
.present = present,
|
||||
.compose = compose,
|
||||
.fill = fill,
|
||||
@@ -654,7 +728,11 @@ struct backend_operations xrender_ops = {
|
||||
.copy = copy,
|
||||
.create_blur_context = create_blur_context,
|
||||
.destroy_blur_context = destroy_blur_context,
|
||||
.create_round_context = create_round_context,
|
||||
.destroy_round_context = destroy_round_context,
|
||||
.get_blur_size = get_blur_size,
|
||||
.store_back_texture = store_back_texture
|
||||
|
||||
};
|
||||
|
||||
// vim: set noet sw=8 ts=8:
|
||||
|
||||
11
src/common.h
11
src/common.h
@@ -75,6 +75,9 @@
|
||||
/// @brief Maximum OpenGL buffer age.
|
||||
#define CGLX_MAX_BUFFER_AGE 5
|
||||
|
||||
/// @brief Maximum passes for blur.
|
||||
#define MAX_BLUR_PASS 6
|
||||
|
||||
// Window flags
|
||||
|
||||
// === Types ===
|
||||
@@ -157,6 +160,8 @@ typedef struct session {
|
||||
backend_t *backend_data;
|
||||
/// backend blur context
|
||||
void *backend_blur_context;
|
||||
/// round corners context
|
||||
void *backend_round_context;
|
||||
/// graphic drivers used
|
||||
enum driver drivers;
|
||||
/// file watch handle
|
||||
@@ -214,7 +219,6 @@ typedef struct session {
|
||||
/// 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;
|
||||
@@ -340,12 +344,14 @@ typedef struct session {
|
||||
int randr_error;
|
||||
/// Whether X Present extension exists.
|
||||
bool present_exists;
|
||||
#ifdef CONFIG_OPENGL
|
||||
/// 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;
|
||||
#endif
|
||||
/// Whether X Xinerama extension exists.
|
||||
bool xinerama_exists;
|
||||
/// Xinerama screen regions.
|
||||
@@ -528,7 +534,8 @@ static inline void wintype_arr_enable(bool arr[]) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get current system clock in 40 microseconds.
|
||||
* Get current system clock in milliseconds.
|
||||
*/
|
||||
int64_t get_time_ms(void);
|
||||
|
||||
34
src/config.c
34
src/config.c
@@ -88,6 +88,11 @@ enum blur_method parse_blur_method(const char *src) {
|
||||
return BLUR_METHOD_BOX;
|
||||
} else if (strcmp(src, "gaussian") == 0) {
|
||||
return BLUR_METHOD_GAUSSIAN;
|
||||
} else if (strcmp(src, "kawase") == 0 || strcmp(src, "dual_kawase") == 0) {
|
||||
return BLUR_METHOD_DUAL_KAWASE;
|
||||
} else if (strcmp(src, "kawase_alt") == 0 || strcmp(src, "alt_kawase") == 0) {
|
||||
// new code from tryone144's `improved_dbo` branch
|
||||
return BLUR_METHOD_ALT_KAWASE;
|
||||
} else if (strcmp(src, "none") == 0) {
|
||||
return BLUR_METHOD_NONE;
|
||||
}
|
||||
@@ -489,6 +494,12 @@ void set_default_winopts(options_t *opt, win_option_mask_t *mask, bool shadow_en
|
||||
// opacity logic is complicated, and needs an "unset" state
|
||||
opt->wintype_option[i].opacity = NAN;
|
||||
}
|
||||
if (!mask[i].corner_radius) {
|
||||
opt->wintype_option[i].corner_radius = -1;
|
||||
}
|
||||
if (!mask[i].round_borders) {
|
||||
opt->wintype_option[i].round_borders = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,15 +508,6 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
|
||||
*opt = (struct options){
|
||||
.backend = BKEND_XRENDER,
|
||||
.glx_no_stencil = false,
|
||||
.transition_length = 300,
|
||||
.transition_pow_x = 0.1,
|
||||
.transition_pow_y = 0.1,
|
||||
.transition_pow_w = 0.1,
|
||||
.transition_pow_h = 0.1,
|
||||
.size_transition = true,
|
||||
.no_scale_down = false,
|
||||
.spawn_center_screen = false,
|
||||
.spawn_center = true,
|
||||
.mark_wmwin_focused = false,
|
||||
.mark_ovredir_focused = false,
|
||||
.detect_rounded_corners = false,
|
||||
@@ -519,6 +521,15 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
|
||||
.benchmark = 0,
|
||||
.benchmark_wid = XCB_NONE,
|
||||
.logpath = NULL,
|
||||
.transition_length = 300,
|
||||
.transition_pow_x = 0.1,
|
||||
.transition_pow_y = 0.1,
|
||||
.transition_pow_w = 0.1,
|
||||
.transition_pow_h = 0.1,
|
||||
.size_transition = true,
|
||||
.no_scale_down = false,
|
||||
.spawn_center_screen = false,
|
||||
.spawn_center = true,
|
||||
|
||||
.refresh_rate = 0,
|
||||
.sw_opti = false,
|
||||
@@ -551,6 +562,7 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
|
||||
.blur_method = BLUR_METHOD_NONE,
|
||||
.blur_radius = 3,
|
||||
.blur_deviation = 0.84089642,
|
||||
.blur_strength = {.strength = -1, .iterations = 3, .offset = 2.75, .expand = 50},
|
||||
.blur_background_frame = false,
|
||||
.blur_background_fixed = false,
|
||||
.blur_background_blacklist = NULL,
|
||||
@@ -569,7 +581,9 @@ char *parse_config(options_t *opt, const char *config_file, bool *shadow_enable,
|
||||
.no_ewmh_fullscreen = false,
|
||||
|
||||
.track_leader = false,
|
||||
};
|
||||
|
||||
.rounded_corners_blacklist = NULL,
|
||||
.round_borders_blacklist = NULL};
|
||||
|
||||
char *ret = NULL;
|
||||
#ifdef CONFIG_LIBCONFIG
|
||||
|
||||
65
src/config.h
65
src/config.h
@@ -44,6 +44,8 @@ typedef struct win_option_mask {
|
||||
bool full_shadow : 1;
|
||||
bool redir_ignore : 1;
|
||||
bool opacity : 1;
|
||||
bool corner_radius : 1;
|
||||
bool round_borders : 1;
|
||||
} win_option_mask_t;
|
||||
|
||||
typedef struct win_option {
|
||||
@@ -53,6 +55,8 @@ typedef struct win_option {
|
||||
bool full_shadow;
|
||||
bool redir_ignore;
|
||||
double opacity;
|
||||
int corner_radius;
|
||||
int round_borders;
|
||||
} win_option_t;
|
||||
|
||||
enum blur_method {
|
||||
@@ -60,9 +64,18 @@ enum blur_method {
|
||||
BLUR_METHOD_KERNEL,
|
||||
BLUR_METHOD_BOX,
|
||||
BLUR_METHOD_GAUSSIAN,
|
||||
BLUR_METHOD_DUAL_KAWASE,
|
||||
BLUR_METHOD_ALT_KAWASE,
|
||||
BLUR_METHOD_INVALID,
|
||||
};
|
||||
|
||||
typedef struct blur_strength {
|
||||
int expand;
|
||||
int strength;
|
||||
int iterations;
|
||||
float offset;
|
||||
} blur_strength_t;
|
||||
|
||||
typedef struct _c2_lptr c2_lptr_t;
|
||||
|
||||
/// Structure representing all options.
|
||||
@@ -87,7 +100,7 @@ typedef struct options {
|
||||
bool glx_no_stencil;
|
||||
/// Whether to avoid rebinding pixmap on window damage.
|
||||
bool glx_no_rebind_pixmap;
|
||||
/// Length of window transitions
|
||||
/// Length of window transitions
|
||||
int transition_length;
|
||||
/// For smoothing on the x-coordinate of window animations
|
||||
float transition_pow_x;
|
||||
@@ -207,6 +220,8 @@ typedef struct options {
|
||||
int blur_radius;
|
||||
// Standard deviation for the gaussian blur
|
||||
double blur_deviation;
|
||||
/// Blur strength (for kawase blur)
|
||||
blur_strength_t blur_strength;
|
||||
/// Whether to blur background when the window frame is not opaque.
|
||||
/// Implies blur_background.
|
||||
bool blur_background_frame;
|
||||
@@ -255,6 +270,15 @@ typedef struct options {
|
||||
// Make transparent windows clip other windows, instead of blending on top of
|
||||
// them
|
||||
bool transparent_clipping;
|
||||
|
||||
// === Rounded corners related ===
|
||||
int corner_radius;
|
||||
/// Rounded corners blacklist. A linked list of conditions.
|
||||
c2_lptr_t *rounded_corners_blacklist;
|
||||
/// Do we round the borders of rounded windows?
|
||||
int round_borders;
|
||||
/// Rounded borders blacklist. A linked list of conditions.
|
||||
c2_lptr_t *round_borders_blacklist;
|
||||
} options_t;
|
||||
|
||||
extern const char *const BACKEND_STRS[NUM_BKEND + 1];
|
||||
@@ -331,3 +355,42 @@ static inline bool parse_vsync(const char *str) {
|
||||
}
|
||||
|
||||
// vim: set noet sw=8 ts=8 :
|
||||
|
||||
/**
|
||||
* Parse a blur_strength option argument.
|
||||
*/
|
||||
static inline attr_pure blur_strength_t
|
||||
parse_kawase_blur_strength(const int level) {
|
||||
static const blur_strength_t values[20] = {
|
||||
{ .expand = 10, .strength =1, .iterations = 1, .offset = 1.5 }, // 1
|
||||
{ .expand = 10, .strength =2, .iterations = 1, .offset = 2.0 }, // 2
|
||||
{ .expand = 20, .strength =3, .iterations = 2, .offset = 2.5 }, // 3
|
||||
{ .expand = 20, .strength =4, .iterations = 2, .offset = 3.0 }, // 4
|
||||
{ .expand = 50, .strength =5, .iterations = 3, .offset = 2.75 }, // 5
|
||||
{ .expand = 50, .strength =6, .iterations = 3, .offset = 3.5 }, // 6
|
||||
{ .expand = 50, .strength =7, .iterations = 3, .offset = 4.25 }, // 7
|
||||
{ .expand = 50, .strength =8, .iterations = 3, .offset = 5.0 }, // 8
|
||||
{ .expand = 150, .strength =9, .iterations = 4, .offset = 3.71429f }, // 9
|
||||
{ .expand = 150, .strength =10, .iterations = 4, .offset = 4.42857f }, // 10
|
||||
{ .expand = 150, .strength =11, .iterations = 4, .offset = 5.14286f }, // 11
|
||||
{ .expand = 150, .strength =12, .iterations = 4, .offset = 5.85714f }, // 12
|
||||
{ .expand = 150, .strength =13, .iterations = 4, .offset = 6.57143f }, // 13
|
||||
{ .expand = 150, .strength =14, .iterations = 4, .offset = 7.28571f }, // 14
|
||||
{ .expand = 150, .strength =15, .iterations = 4, .offset = 8.0 }, // 15
|
||||
{ .expand = 400, .strength =16, .iterations = 5, .offset = 6.0 }, // 16
|
||||
{ .expand = 400, .strength =17, .iterations = 5, .offset = 7.0 }, // 17
|
||||
{ .expand = 400, .strength =18, .iterations = 5, .offset = 8.0 }, // 18
|
||||
{ .expand = 400, .strength =19, .iterations = 5, .offset = 9.0 }, // 19
|
||||
{ .expand = 400, .strength =20, .iterations = 5, .offset = 10.0 }, // 20
|
||||
};
|
||||
|
||||
if (level < 1 || level > 20) {
|
||||
log_error("(\"%d\"): Invalid blur_strength argument. Needs to be a number between 1 and 20. Will default to 5", level);
|
||||
return values[5];
|
||||
}
|
||||
|
||||
log_info("blur-strength: %d [.iter = %d, .offset = %f, .expand = %d]",
|
||||
level, values[level - 1].iterations, values[level - 1].offset, values[level - 1].expand);
|
||||
|
||||
return values[level - 1];;
|
||||
}
|
||||
|
||||
@@ -284,6 +284,17 @@ static inline void parse_wintype_config(const config_t *cfg, const char *member_
|
||||
o->opacity = normalize_d(fval);
|
||||
mask->opacity = true;
|
||||
}
|
||||
|
||||
if (config_setting_lookup_int(setting, "corner-radius", &ival)) {
|
||||
o->corner_radius = ival;
|
||||
mask->corner_radius = true;
|
||||
// log_warn("%s: corner-radius: %d", member_name, ival);
|
||||
}
|
||||
if (config_setting_lookup_int(setting, "round-borders", &ival)) {
|
||||
o->round_borders = ival;
|
||||
mask->round_borders = true;
|
||||
// log_warn("%s: round_borders: %d", member_name, ival);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,29 +364,31 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||
// -O (fade_out_step)
|
||||
if (config_lookup_float(&cfg, "fade-out-step", &dval))
|
||||
opt->fade_out_step = normalize_d(dval);
|
||||
// --transition-length
|
||||
if (config_lookup_int(&cfg, "transition-length", &ival))
|
||||
opt->transition_length = ival;
|
||||
// --transition-pow-x
|
||||
if (config_lookup_float(&cfg, "transition-pow-x", &dval))
|
||||
opt->transition_pow_x = dval;
|
||||
// --transition-pow-y
|
||||
if (config_lookup_float(&cfg, "transition-pow-y", &dval))
|
||||
opt->transition_pow_y = dval;
|
||||
// --transition-pow-w
|
||||
if (config_lookup_float(&cfg, "transition-pow-w", &dval))
|
||||
opt->transition_pow_w = dval;
|
||||
// --transition-pow-h
|
||||
if (config_lookup_float(&cfg, "transition-pow-h", &dval))
|
||||
opt->transition_pow_h = dval;
|
||||
// --size-transition
|
||||
lcfg_lookup_bool(&cfg, "size-transition", &opt->size_transition);
|
||||
// --spawn-center-screen
|
||||
lcfg_lookup_bool(&cfg, "spawn-center-screen", &opt->spawn_center_screen);
|
||||
// --spawn-center
|
||||
lcfg_lookup_bool(&cfg, "spawn-center", &opt->spawn_center);
|
||||
// --no-scale-down
|
||||
lcfg_lookup_bool(&cfg, "no-scale-down", &opt->no_scale_down);
|
||||
|
||||
// --transition-length
|
||||
if (config_lookup_int(&cfg, "transition-length", &ival))
|
||||
opt->transition_length = ival;
|
||||
// --transition-pow-x
|
||||
if (config_lookup_float(&cfg, "transition-pow-x", &dval))
|
||||
opt->transition_pow_x = dval;
|
||||
// --transition-pow-y
|
||||
if (config_lookup_float(&cfg, "transition-pow-y", &dval))
|
||||
opt->transition_pow_y = dval;
|
||||
// --transition-pow-w
|
||||
if (config_lookup_float(&cfg, "transition-pow-w", &dval))
|
||||
opt->transition_pow_w = dval;
|
||||
// --transition-pow-h
|
||||
if (config_lookup_float(&cfg, "transition-pow-h", &dval))
|
||||
opt->transition_pow_h = dval;
|
||||
// --size-transition
|
||||
lcfg_lookup_bool(&cfg, "size-transition", &opt->size_transition);
|
||||
// --spawn-center-screen
|
||||
lcfg_lookup_bool(&cfg, "spawn-center-screen", &opt->spawn_center_screen);
|
||||
// --spawn-center
|
||||
lcfg_lookup_bool(&cfg, "spawn-center", &opt->spawn_center);
|
||||
// --no-scale-down
|
||||
lcfg_lookup_bool(&cfg, "no-scale-down", &opt->no_scale_down);
|
||||
|
||||
// -r (shadow_radius)
|
||||
config_lookup_int(&cfg, "shadow-radius", &opt->shadow_radius);
|
||||
// -o (shadow_opacity)
|
||||
@@ -390,6 +403,14 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||
// --active_opacity
|
||||
if (config_lookup_float(&cfg, "active-opacity", &dval))
|
||||
opt->active_opacity = normalize_d(dval);
|
||||
// --corner-radius
|
||||
config_lookup_int(&cfg, "corner-radius", &opt->corner_radius);
|
||||
// --rounded-corners-exclude
|
||||
parse_cfg_condlst(&cfg, &opt->rounded_corners_blacklist, "rounded-corners-exclude");
|
||||
// --round-borders
|
||||
config_lookup_int(&cfg, "round-borders", &opt->round_borders);
|
||||
// --round-borders-exclude
|
||||
parse_cfg_condlst(&cfg, &opt->round_borders_blacklist, "round-borders-exclude");
|
||||
// -e (frame_opacity)
|
||||
config_lookup_float(&cfg, "frame-opacity", &opt->frame_opacity);
|
||||
// -c (shadow_enable)
|
||||
@@ -469,6 +490,7 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||
}
|
||||
lcfg_lookup_bool(&cfg, "vsync", &opt->vsync);
|
||||
// --backend
|
||||
lcfg_lookup_bool(&cfg, "experimental-backends", &opt->experimental_backends);
|
||||
if (config_lookup_string(&cfg, "backend", &sval)) {
|
||||
opt->backend = parse_backend(sval);
|
||||
if (opt->backend >= NUM_BKEND) {
|
||||
@@ -545,6 +567,10 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||
config_lookup_int(&cfg, "blur-size", &opt->blur_radius);
|
||||
// --blur-deviation
|
||||
config_lookup_float(&cfg, "blur-deviation", &opt->blur_deviation);
|
||||
// --blur-strength
|
||||
if (config_lookup_int(&cfg, "blur-strength", &ival) && ival) {
|
||||
opt->blur_strength = parse_kawase_blur_strength(ival);
|
||||
}
|
||||
// --blur-background
|
||||
if (config_lookup_bool(&cfg, "blur-background", &ival) && ival) {
|
||||
if (opt->blur_method == BLUR_METHOD_NONE) {
|
||||
@@ -570,7 +596,6 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||
lcfg_lookup_bool(&cfg, "glx-no-stencil", &opt->glx_no_stencil);
|
||||
// --glx-no-rebind-pixmap
|
||||
lcfg_lookup_bool(&cfg, "glx-no-rebind-pixmap", &opt->glx_no_rebind_pixmap);
|
||||
lcfg_lookup_bool(&cfg, "force-win-blend", &opt->force_win_blend);
|
||||
// --glx-swap-method
|
||||
if (config_lookup_string(&cfg, "glx-swap-method", &sval)) {
|
||||
char *endptr;
|
||||
@@ -608,8 +633,8 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||
}
|
||||
// --xrender-sync
|
||||
if (config_lookup_bool(&cfg, "xrender-sync", &ival) && ival) {
|
||||
log_error("Please use xrender-sync-fence instead of xrender-sync.");
|
||||
goto err;
|
||||
log_warn("Please use xrender-sync-fence instead of xrender-sync.");
|
||||
opt->xrender_sync_fence = true;
|
||||
}
|
||||
// --xrender-sync-fence
|
||||
lcfg_lookup_bool(&cfg, "xrender-sync-fence", &opt->xrender_sync_fence);
|
||||
@@ -617,21 +642,25 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||
if (lcfg_lookup_bool(&cfg, "clear-shadow", &bval))
|
||||
log_warn("\"clear-shadow\" is removed as an option, and is always"
|
||||
" enabled now. Consider removing it from your config file");
|
||||
if (lcfg_lookup_bool(&cfg, "paint-on-overlay", &bval)) {
|
||||
log_error("\"paint-on-overlay\" has been removed as an option, and "
|
||||
"the feature is enabled whenever possible");
|
||||
goto err;
|
||||
}
|
||||
if (lcfg_lookup_bool(&cfg, "paint-on-overlay", &bval))
|
||||
log_warn("\"paint-on-overlay\" has been removed as an option, and "
|
||||
"is enabled whenever possible");
|
||||
|
||||
if (config_lookup_float(&cfg, "alpha-step", &dval)) {
|
||||
log_error("\"alpha-step\" has been removed, compton now tries to make use"
|
||||
" of all alpha values");
|
||||
goto err;
|
||||
}
|
||||
if (config_lookup_float(&cfg, "alpha-step", &dval))
|
||||
log_warn("\"alpha-step\" has been removed, compton now tries to make use"
|
||||
" of all alpha values");
|
||||
|
||||
const char *deprecation_message attr_unused =
|
||||
const char *deprecation_message =
|
||||
"has been removed. If you encounter problems "
|
||||
"without this feature, please feel free to open a bug report";
|
||||
if (lcfg_lookup_bool(&cfg, "glx-use-copysubbuffermesa", &bval) && bval) {
|
||||
log_error("\"glx-use-copysubbuffermesa\" %s", deprecation_message);
|
||||
return ERR_PTR(-1);
|
||||
}
|
||||
if (lcfg_lookup_bool(&cfg, "glx-copy-from-front", &bval) && bval) {
|
||||
log_error("\"glx-copy-from-front\" %s", deprecation_message);
|
||||
return ERR_PTR(-1);
|
||||
}
|
||||
|
||||
config_setting_t *blur_cfg = config_lookup(&cfg, "blur");
|
||||
if (blur_cfg) {
|
||||
@@ -655,6 +684,10 @@ char *parse_config_libconfig(options_t *opt, const char *config_file, bool *shad
|
||||
}
|
||||
|
||||
config_setting_lookup_float(blur_cfg, "deviation", &opt->blur_deviation);
|
||||
|
||||
if (config_setting_lookup_int(blur_cfg, "strength", &ival) && ival) {
|
||||
opt->blur_strength = parse_kawase_blur_strength(ival);
|
||||
}
|
||||
}
|
||||
|
||||
// Wintype settings
|
||||
|
||||
328
src/event.c
328
src/event.c
@@ -100,9 +100,6 @@ static inline xcb_window_t attr_pure ev_window(session_t *ps, xcb_generic_event_
|
||||
}
|
||||
}
|
||||
|
||||
#define CASESTRRET(s) \
|
||||
case s: return #s;
|
||||
|
||||
static inline const char *ev_name(session_t *ps, xcb_generic_event_t *ev) {
|
||||
static char buf[128];
|
||||
switch (ev->response_type & 0x7f) {
|
||||
@@ -165,8 +162,6 @@ static inline const char *attr_pure ev_focus_detail_name(xcb_focus_in_event_t *e
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
#undef CASESTRRET
|
||||
|
||||
static inline void ev_focus_in(session_t *ps, xcb_focus_in_event_t *ev) {
|
||||
log_debug("{ mode: %s, detail: %s }\n", ev_focus_mode_name(ev),
|
||||
ev_focus_detail_name(ev));
|
||||
@@ -180,9 +175,8 @@ static inline void ev_focus_out(session_t *ps, xcb_focus_out_event_t *ev) {
|
||||
}
|
||||
|
||||
static inline void ev_create_notify(session_t *ps, xcb_create_notify_event_t *ev) {
|
||||
if (ev->parent == ps->root) {
|
||||
add_win_top(ps, ev->window);
|
||||
}
|
||||
assert(ev->parent == ps->root);
|
||||
add_win_top(ps, ev->window);
|
||||
}
|
||||
|
||||
/// Handle configure event of a regular window
|
||||
@@ -202,105 +196,122 @@ static void configure_win(session_t *ps, xcb_configure_notify_event_t *ce) {
|
||||
|
||||
auto mw = (struct managed_win *)w;
|
||||
|
||||
float t = get_time_ms();
|
||||
if (mw->oldX == -500 && mw->oldY == -500 && mw->oldW == 0 && mw->oldH == 0) {
|
||||
if (!mw->isOld) {
|
||||
/* mw->isOld = true; */
|
||||
float t = get_time_ms();
|
||||
if (mw->oldX == -10000 && mw->oldY == -10000 && mw->oldW == 0 && mw->oldH == 0) {
|
||||
if (!mw->isOld) {
|
||||
/* mw->isOld = true; */
|
||||
|
||||
if (ps->o.spawn_center_screen) {
|
||||
mw->oldX = ps->root_width/2;
|
||||
mw->oldY = ps->root_height/2;
|
||||
mw->oldW = 1;
|
||||
mw->oldH = 1;
|
||||
} else if (ps->o.spawn_center) {
|
||||
mw->oldX = ce->x + ce->width/2;
|
||||
mw->oldY = ce->y + ce->height/2;
|
||||
mw->oldW = 1;
|
||||
mw->oldH = 1;
|
||||
} else {
|
||||
mw->oldX = ce->x;
|
||||
mw->oldY = ce->y;
|
||||
mw->oldW = ce->width;
|
||||
mw->oldH = ce->height;
|
||||
}
|
||||
} else {
|
||||
mw->oldX = ce->x;
|
||||
mw->oldY = ce->y;
|
||||
mw->oldW = ce->width;
|
||||
mw->oldH = ce->height;
|
||||
}
|
||||
if (ps->o.spawn_center_screen) {
|
||||
mw->oldX = ps->root_width / 2;
|
||||
mw->oldY = ps->root_height / 2;
|
||||
mw->oldW = 1;
|
||||
mw->oldH = 1;
|
||||
} else if (ps->o.spawn_center) {
|
||||
mw->oldX = ce->x + ce->width / 2;
|
||||
mw->oldY = ce->y + ce->height / 2;
|
||||
mw->oldW = 1;
|
||||
mw->oldH = 1;
|
||||
} else {
|
||||
mw->oldX = ce->x;
|
||||
mw->oldY = ce->y;
|
||||
mw->oldW = ce->width;
|
||||
mw->oldH = ce->height;
|
||||
}
|
||||
} else {
|
||||
mw->oldX = ce->x;
|
||||
mw->oldY = ce->y;
|
||||
mw->oldW = ce->width;
|
||||
mw->oldH = ce->height;
|
||||
}
|
||||
|
||||
mw->newX = ce->x;
|
||||
mw->newY = ce->y;
|
||||
mw->newW = ce->width;
|
||||
mw->newH = ce->height;
|
||||
mw->moveTimeX = t;
|
||||
mw->moveTimeY = t;
|
||||
mw->moveTimeW = t;
|
||||
mw->moveTimeH = t;
|
||||
} else {
|
||||
if (mw->newX == mw->g.x && mw->newY == mw->g.y) {
|
||||
mw->oldX = mw->g.x;
|
||||
mw->oldY = mw->g.y;
|
||||
mw->oldW = mw->g.width;
|
||||
mw->oldH = mw->g.height;
|
||||
mw->moveTimeX = t;
|
||||
mw->moveTimeY = t;
|
||||
mw->moveTimeW = t;
|
||||
mw->moveTimeH = t;
|
||||
}
|
||||
if (mw->newX != ce->x || mw->newY != ce->y || mw->newW != ce->width || mw->newH != ce->height) {
|
||||
float moveDx = ((float) t - mw->moveTimeX) / ps->o.transition_length;
|
||||
float moveDy = ((float) t - mw->moveTimeY) / ps->o.transition_length;
|
||||
float moveDw = ((float) t - mw->moveTimeW) / ps->o.transition_length;
|
||||
float moveDh = ((float) t - mw->moveTimeH) / ps->o.transition_length;
|
||||
mw->newX = ce->x;
|
||||
mw->newY = ce->y;
|
||||
mw->newW = ce->width;
|
||||
mw->newH = ce->height;
|
||||
mw->moveTimeX = t;
|
||||
mw->moveTimeY = t;
|
||||
mw->moveTimeW = t;
|
||||
mw->moveTimeH = t;
|
||||
} else {
|
||||
if (mw->newX == mw->g.x && mw->newY == mw->g.y) {
|
||||
mw->oldX = mw->g.x;
|
||||
mw->oldY = mw->g.y;
|
||||
mw->oldW = mw->g.width;
|
||||
mw->oldH = mw->g.height;
|
||||
mw->moveTimeX = t;
|
||||
mw->moveTimeY = t;
|
||||
mw->moveTimeW = t;
|
||||
mw->moveTimeH = t;
|
||||
}
|
||||
if (mw->newX != ce->x || mw->newY != ce->y || mw->newW != ce->width ||
|
||||
mw->newH != ce->height) {
|
||||
float moveDx = ((float)t - mw->moveTimeX) / ps->o.transition_length;
|
||||
float moveDy = ((float)t - mw->moveTimeY) / ps->o.transition_length;
|
||||
float moveDw = ((float)t - mw->moveTimeW) / ps->o.transition_length;
|
||||
float moveDh = ((float)t - mw->moveTimeH) / ps->o.transition_length;
|
||||
|
||||
if (mw->moveTimeX != 0.0 && moveDx < 1.0 && mw->oldX != mw->newX) {
|
||||
float oldMoveDx = pow((float) (mw->newX - mw->g.x) / (float) (mw->newX - ce->x), 1 / ps->o.transition_pow_x);
|
||||
float fakeT = (t - oldMoveDx * (float) ps->o.transition_length);
|
||||
/* printf("X: %f,%f\n", fakeT, t); */
|
||||
mw->moveTimeX = isnanf(fakeT)? t : fakeT;
|
||||
} else {
|
||||
mw->moveTimeX = t;
|
||||
}
|
||||
if (mw->moveTimeY != 0.0 && moveDy < 1.0 && mw->oldY != mw->newY) {
|
||||
float oldMoveDy = pow((float) (mw->newY - mw->g.y) / (float) (mw->newY - ce->y), 1 / ps->o.transition_pow_y);
|
||||
float fakeT = (t - oldMoveDy * (float) ps->o.transition_length);
|
||||
/* printf("Y: %f,%f\n", fakeT, t); */
|
||||
mw->moveTimeY = isnanf(fakeT)? t : fakeT;
|
||||
} else {
|
||||
mw->moveTimeY = t;
|
||||
}
|
||||
if (mw->moveTimeW != 0.0 && moveDw < 1.0 && mw->oldW != mw->newW) {
|
||||
float oldMoveDw = pow((float) (mw->newW - mw->g.width) / (float) (mw->newW - ce->width), 1 / ps->o.transition_pow_w);
|
||||
float fakeT = (t - oldMoveDw * (float) ps->o.transition_length);
|
||||
/* printf("Y: %f,%f\n", fakeT, t); */
|
||||
mw->moveTimeW = isnanf(fakeT)? t : fakeT;
|
||||
} else {
|
||||
mw->moveTimeW = t;
|
||||
}
|
||||
if (mw->moveTimeH != 0.0 && moveDh < 1.0 && mw->oldH != mw->newH) {
|
||||
float oldMoveDh = pow((float) (mw->newH - mw->g.height) / (float) (mw->newH - ce->height), 1 / ps->o.transition_pow_h);
|
||||
float fakeT = (t - oldMoveDh * (float) ps->o.transition_length);
|
||||
/* printf("Y: %f,%f\n", fakeT, t); */
|
||||
mw->moveTimeH = isnanf(fakeT)? t : fakeT;
|
||||
} else {
|
||||
mw->moveTimeH = t;
|
||||
}
|
||||
if (mw->moveTimeX != 0.0 && moveDx < 1.0 && mw->oldX != mw->newX) {
|
||||
float oldMoveDx = pow(
|
||||
(float)(mw->newX - mw->g.x) / (float)(mw->newX - ce->x),
|
||||
1 / ps->o.transition_pow_x);
|
||||
float fakeT =
|
||||
(t - oldMoveDx * (float)ps->o.transition_length);
|
||||
/* printf("X: %f,%f\n", fakeT, t); */
|
||||
mw->moveTimeX = isnanf(fakeT) ? t : fakeT;
|
||||
} else {
|
||||
mw->moveTimeX = t;
|
||||
}
|
||||
if (mw->moveTimeY != 0.0 && moveDy < 1.0 && mw->oldY != mw->newY) {
|
||||
float oldMoveDy = pow(
|
||||
(float)(mw->newY - mw->g.y) / (float)(mw->newY - ce->y),
|
||||
1 / ps->o.transition_pow_y);
|
||||
float fakeT =
|
||||
(t - oldMoveDy * (float)ps->o.transition_length);
|
||||
/* printf("Y: %f,%f\n", fakeT, t); */
|
||||
mw->moveTimeY = isnanf(fakeT) ? t : fakeT;
|
||||
} else {
|
||||
mw->moveTimeY = t;
|
||||
}
|
||||
if (mw->moveTimeW != 0.0 && moveDw < 1.0 && mw->oldW != mw->newW) {
|
||||
float oldMoveDw = pow((float)(mw->newW - mw->g.width) /
|
||||
(float)(mw->newW - ce->width),
|
||||
1 / ps->o.transition_pow_w);
|
||||
float fakeT =
|
||||
(t - oldMoveDw * (float)ps->o.transition_length);
|
||||
/* printf("Y: %f,%f\n", fakeT, t); */
|
||||
mw->moveTimeW = isnanf(fakeT) ? t : fakeT;
|
||||
} else {
|
||||
mw->moveTimeW = t;
|
||||
}
|
||||
if (mw->moveTimeH != 0.0 && moveDh < 1.0 && mw->oldH != mw->newH) {
|
||||
float oldMoveDh = pow((float)(mw->newH - mw->g.height) /
|
||||
(float)(mw->newH - ce->height),
|
||||
1 / ps->o.transition_pow_h);
|
||||
float fakeT =
|
||||
(t - oldMoveDh * (float)ps->o.transition_length);
|
||||
/* printf("Y: %f,%f\n", fakeT, t); */
|
||||
mw->moveTimeH = isnanf(fakeT) ? t : fakeT;
|
||||
} else {
|
||||
mw->moveTimeH = t;
|
||||
}
|
||||
|
||||
mw->oldX = mw->newX;
|
||||
mw->oldY = mw->newY;
|
||||
mw->oldW = mw->newW;
|
||||
mw->oldH = mw->newH;
|
||||
mw->newX = ce->x;
|
||||
mw->newY = ce->y;
|
||||
mw->newW = ce->width;
|
||||
mw->newH = ce->height;
|
||||
mw->oldX = mw->newX;
|
||||
mw->oldY = mw->newY;
|
||||
mw->oldW = mw->newW;
|
||||
mw->oldH = mw->newH;
|
||||
mw->newX = ce->x;
|
||||
mw->newY = ce->y;
|
||||
mw->newW = ce->width;
|
||||
mw->newH = ce->height;
|
||||
|
||||
if (ps->o.no_scale_down && mw->newW < mw->oldW) { mw->oldW = mw->newW; }
|
||||
if (ps->o.no_scale_down && mw->newH < mw->oldH) { mw->oldH = mw->newH; }
|
||||
}
|
||||
}
|
||||
if (ps->o.no_scale_down && mw->newW < mw->oldW) {
|
||||
mw->oldW = mw->newW;
|
||||
}
|
||||
if (ps->o.no_scale_down && mw->newH < mw->oldH) {
|
||||
mw->oldH = mw->newH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mw->state == WSTATE_UNMAPPED || mw->state == WSTATE_UNMAPPING ||
|
||||
mw->state == WSTATE_DESTROYING) {
|
||||
@@ -353,7 +364,7 @@ static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event
|
||||
log_debug("{ send_event: %d, id: %#010x, above: %#010x, override_redirect: %d }",
|
||||
ev->event, ev->window, ev->above_sibling, ev->override_redirect);
|
||||
if (ev->window == ps->root) {
|
||||
set_root_flags(ps, ROOT_FLAGS_CONFIGURED);
|
||||
configure_root(ps, ev->width, ev->height);
|
||||
} else {
|
||||
configure_win(ps, ev);
|
||||
}
|
||||
@@ -361,23 +372,8 @@ static inline void ev_configure_notify(session_t *ps, xcb_configure_notify_event
|
||||
|
||||
static inline void ev_destroy_notify(session_t *ps, xcb_destroy_notify_event_t *ev) {
|
||||
auto w = find_win(ps, ev->window);
|
||||
auto mw = find_toplevel(ps, ev->window);
|
||||
if (mw && mw->client_win == mw->base.id) {
|
||||
// We only want _real_ frame window
|
||||
assert(&mw->base == w);
|
||||
mw = NULL;
|
||||
}
|
||||
assert(w == NULL || mw == NULL);
|
||||
|
||||
if (w != NULL) {
|
||||
if (w) {
|
||||
auto _ attr_unused = destroy_win_start(ps, w);
|
||||
} else if (mw != NULL) {
|
||||
win_unmark_client(ps, mw);
|
||||
win_set_flags(mw, WIN_FLAGS_CLIENT_STALE);
|
||||
ps->pending_updates = true;
|
||||
} else {
|
||||
log_debug("Received a destroy notify from an unknown window, %#010x",
|
||||
ev->window);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +396,7 @@ static inline void ev_map_notify(session_t *ps, xcb_map_notify_event_t *ev) {
|
||||
return;
|
||||
}
|
||||
|
||||
win_set_flags(w, WIN_FLAGS_MAPPED);
|
||||
win_queue_update(w, WIN_UPDATE_MAP);
|
||||
|
||||
// FocusIn/Out may be ignored when the window is unmapped, so we must
|
||||
// recheck focus here
|
||||
@@ -415,14 +411,8 @@ static inline void ev_unmap_notify(session_t *ps, xcb_unmap_notify_event_t *ev)
|
||||
}
|
||||
|
||||
static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t *ev) {
|
||||
log_debug("Window %#010x has new parent: %#010x, override_redirect: %d",
|
||||
ev->window, ev->parent, ev->override_redirect);
|
||||
auto w_top = find_toplevel(ps, ev->window);
|
||||
if (w_top) {
|
||||
win_unmark_client(ps, w_top);
|
||||
win_set_flags(w_top, WIN_FLAGS_CLIENT_STALE);
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
log_debug("{ new_parent: %#010x, override_redirect: %d }", ev->parent,
|
||||
ev->override_redirect);
|
||||
|
||||
if (ev->parent == ps->root) {
|
||||
// X will generate reparent notifiy even if the parent didn't actually
|
||||
@@ -442,11 +432,7 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
|
||||
{
|
||||
auto w = find_win(ps, ev->window);
|
||||
if (w) {
|
||||
auto ret = destroy_win_start(ps, w);
|
||||
if (!ret && w->managed) {
|
||||
auto mw = (struct managed_win *)w;
|
||||
CHECK(win_skip_fading(ps, mw));
|
||||
}
|
||||
auto _ attr_unused = destroy_win_start(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,35 +441,28 @@ static inline void ev_reparent_notify(session_t *ps, xcb_reparent_notify_event_t
|
||||
ps->c, ev->window, XCB_CW_EVENT_MASK,
|
||||
(const uint32_t[]){determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN)});
|
||||
|
||||
if (!wid_has_prop(ps, ev->window, ps->atoms->aWM_STATE)) {
|
||||
log_debug("Window %#010x doesn't have WM_STATE property, it is "
|
||||
"probably not a client window. But we will listen for "
|
||||
"property change in case it gains one.",
|
||||
ev->window);
|
||||
xcb_change_window_attributes(
|
||||
ps->c, ev->window, XCB_CW_EVENT_MASK,
|
||||
(const uint32_t[]){determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN) |
|
||||
XCB_EVENT_MASK_PROPERTY_CHANGE});
|
||||
} else {
|
||||
auto w_real_top = find_managed_window_or_parent(ps, ev->parent);
|
||||
if (w_real_top && w_real_top->state != WSTATE_UNMAPPED &&
|
||||
w_real_top->state != WSTATE_UNMAPPING) {
|
||||
log_debug("Mark window %#010x (%s) as having a stale "
|
||||
"client",
|
||||
w_real_top->base.id, w_real_top->name);
|
||||
win_set_flags(w_real_top, WIN_FLAGS_CLIENT_STALE);
|
||||
ps->pending_updates = true;
|
||||
} else {
|
||||
if (!w_real_top)
|
||||
log_debug("parent %#010x not found", ev->parent);
|
||||
// Check if the window is an undetected client window
|
||||
// Firstly, check if it's a known client window
|
||||
if (!find_toplevel(ps, ev->window)) {
|
||||
// If not, look for its frame window
|
||||
auto w_top = find_toplevel2(ps, ev->parent);
|
||||
// If found, and the client window has not been determined, or its
|
||||
// frame may not have a correct client, continue
|
||||
if (w_top &&
|
||||
(!w_top->client_win || w_top->client_win == w_top->base.id)) {
|
||||
// If it has WM_STATE, mark it the client window
|
||||
if (wid_has_prop(ps, ev->window, ps->atoms->aWM_STATE)) {
|
||||
w_top->wmwin = false;
|
||||
win_unmark_client(ps, w_top);
|
||||
win_mark_client(ps, w_top, ev->window);
|
||||
}
|
||||
// Otherwise, watch for WM_STATE on it
|
||||
else {
|
||||
// Window is not currently mapped, unmark its
|
||||
// client to trigger a client recheck when it is
|
||||
// mapped later.
|
||||
win_unmark_client(ps, w_real_top);
|
||||
log_debug("parent %#010x (%s) is in state %d",
|
||||
w_real_top->base.id, w_real_top->name,
|
||||
w_real_top->state);
|
||||
xcb_change_window_attributes(
|
||||
ps->c, ev->window, XCB_CW_EVENT_MASK,
|
||||
(const uint32_t[]){
|
||||
determine_evmask(ps, ev->window, WIN_EVMODE_UNKNOWN) |
|
||||
XCB_EVENT_MASK_PROPERTY_CHANGE});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -576,12 +555,14 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
||||
(const uint32_t[]){determine_evmask(
|
||||
ps, ev->window, WIN_EVMODE_UNKNOWN)});
|
||||
|
||||
auto w_top = find_managed_window_or_parent(ps, ev->window);
|
||||
// ev->window might have not been managed yet, in that case w_top
|
||||
// would be NULL.
|
||||
if (w_top) {
|
||||
win_set_flags(w_top, WIN_FLAGS_CLIENT_STALE);
|
||||
ps->pending_updates = true;
|
||||
auto w_top = find_toplevel2(ps, ev->window);
|
||||
// Initialize client_win as early as possible
|
||||
if (w_top &&
|
||||
(!w_top->client_win || w_top->client_win == w_top->base.id) &&
|
||||
wid_has_prop(ps, ev->window, ps->atoms->aWM_STATE)) {
|
||||
w_top->wmwin = false;
|
||||
win_unmark_client(ps, w_top);
|
||||
win_mark_client(ps, w_top, ev->window);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -606,7 +587,14 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
||||
win_update_opacity_prop(ps, w);
|
||||
// we cannot receive OPACITY change when window is destroyed
|
||||
assert(w->state != WSTATE_DESTROYING);
|
||||
win_update_opacity_target(ps, w);
|
||||
w->opacity_target = win_calc_opacity_target(ps, w, false);
|
||||
if (w->state == WSTATE_MAPPED) {
|
||||
// See the winstate_t transition table
|
||||
w->state = WSTATE_FADING;
|
||||
}
|
||||
if (!ps->redirected) {
|
||||
CHECK(!win_skip_fading(ps, w));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -743,14 +731,14 @@ static inline void ev_shape_notify(session_t *ps, xcb_shape_notify_event_t *ev)
|
||||
* if we attempt to rebuild border_size
|
||||
*/
|
||||
// Mark the old border_size as damaged
|
||||
region_t tmp = win_get_bounding_shape_global_by_val(w);
|
||||
region_t tmp = win_get_bounding_shape_global_by_val(w, true);
|
||||
add_damage(ps, &tmp);
|
||||
pixman_region32_fini(&tmp);
|
||||
|
||||
win_update_bounding_shape(ps, w);
|
||||
|
||||
// Mark the new border_size as damaged
|
||||
tmp = win_get_bounding_shape_global_by_val(w);
|
||||
tmp = win_get_bounding_shape_global_by_val(w, true);
|
||||
add_damage(ps, &tmp);
|
||||
pixman_region32_fini(&tmp);
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ cflags = []
|
||||
|
||||
required_xcb_packages = [
|
||||
'xcb-render', 'xcb-damage', 'xcb-randr', 'xcb-sync', 'xcb-composite',
|
||||
'xcb-shape', 'xcb-xinerama', 'xcb-xfixes', 'xcb-present', 'xcb-glx', 'xcb'
|
||||
'xcb-shape', 'xcb-xinerama', 'xcb-xfixes', 'xcb-present', 'xcb'
|
||||
]
|
||||
|
||||
required_packages = [
|
||||
@@ -81,8 +81,8 @@ endif
|
||||
host_system = host_machine.system()
|
||||
if host_system == 'linux'
|
||||
cflags += ['-DHAS_INOTIFY']
|
||||
elif (host_system == 'freebsd' or host_system == 'netbsd' or
|
||||
host_system == 'dragonfly' or host_system == 'openbsd')
|
||||
elif host_system == 'freebsd' or host_system == 'netbsd' or
|
||||
host_system == 'dragonfly' or host_system == 'openbsd'
|
||||
cflags += ['-DHAS_KQUEUE']
|
||||
endif
|
||||
|
||||
|
||||
1797
src/opengl.c
1797
src/opengl.c
File diff suppressed because it is too large
Load Diff
73
src/opengl.h
73
src/opengl.h
@@ -36,10 +36,40 @@ typedef struct {
|
||||
GLint unifm_offset_x;
|
||||
/// Location of uniform "offset_y" in blur GLSL program.
|
||||
GLint unifm_offset_y;
|
||||
/// Location of uniform "factor_center" in blur GLSL program.
|
||||
GLint unifm_factor_center;
|
||||
/// Location of uniform "opacity" in conv-blur and (dual filter) kawase-blur GLSL program.
|
||||
GLint unifm_opacity;
|
||||
/// Location of uniform "offset" in kawase-blur GLSL program.
|
||||
GLint unifm_offset;
|
||||
/// Location of uniform "halfpixel" in kawase-blur GLSL program.
|
||||
GLint unifm_halfpixel;
|
||||
/// Location of uniform "fulltex" in kawase-blur GLSL program.
|
||||
GLint unifm_fulltex;
|
||||
} glx_blur_pass_t;
|
||||
|
||||
typedef struct {
|
||||
/// Fragment shader for rounded corners.
|
||||
GLuint frag_shader;
|
||||
/// GLSL program for rounded corners.
|
||||
GLuint prog;
|
||||
/// Location of uniform "radius" in rounded-corners GLSL program.
|
||||
GLint unifm_radius;
|
||||
/// Location of uniform "texcoord" in rounded-corners GLSL program.
|
||||
GLint unifm_texcoord;
|
||||
/// Location of uniform "texsize" in rounded-corners GLSL program.
|
||||
GLint unifm_texsize;
|
||||
/// Location of uniform "borderw" in rounded-corners GLSL program.
|
||||
GLint unifm_borderw;
|
||||
/// Location of uniform "borderc" in rounded-corners GLSL program.
|
||||
GLint unifm_borderc;
|
||||
/// Location of uniform "resolution" in rounded-corners GLSL program.
|
||||
GLint unifm_resolution;
|
||||
/// Location of uniform "texture_scr" in rounded-corners GLSL program.
|
||||
GLint unifm_tex_scr;
|
||||
/// Location of uniform "texture_wnd" in rounded-corners GLSL program.
|
||||
GLint unifm_tex_wnd;
|
||||
|
||||
} glx_round_pass_t;
|
||||
|
||||
/// Structure containing GLX-dependent data for a session.
|
||||
typedef struct glx_session {
|
||||
// === OpenGL related ===
|
||||
@@ -49,7 +79,10 @@ typedef struct glx_session {
|
||||
bool has_texture_non_power_of_two;
|
||||
/// Current GLX Z value.
|
||||
int z;
|
||||
/// Cached blur textures for every pass
|
||||
glx_blur_cache_t blur_cache;
|
||||
glx_blur_pass_t *blur_passes;
|
||||
glx_round_pass_t *round_passes;
|
||||
} glx_session_t;
|
||||
|
||||
/// @brief Wrapper of a binded GLX texture.
|
||||
@@ -69,8 +102,8 @@ typedef struct _glx_texture {
|
||||
bool glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, int z,
|
||||
GLfloat factor, const region_t *reg_tgt);
|
||||
|
||||
bool glx_render(session_t *ps, const glx_texture_t *ptex, int x, int y, int dx, int dy,
|
||||
int width, int height, int z, double opacity, bool argb, bool neg,
|
||||
bool glx_render(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int x, int y, int dx, int dy,
|
||||
int width, int height, int z, double opacity, bool argb, bool neg, int cr,
|
||||
const region_t *reg_tgt, const glx_prog_main_t *pprogram);
|
||||
|
||||
bool glx_init(session_t *ps, bool need_render);
|
||||
@@ -81,6 +114,8 @@ void glx_on_root_change(session_t *ps);
|
||||
|
||||
bool glx_init_blur(session_t *ps);
|
||||
|
||||
bool glx_init_rounded_corners(session_t *ps);
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
bool glx_load_prog_main(const char *vshader_str, const char *fshader_str,
|
||||
glx_prog_main_t *pprogram);
|
||||
@@ -91,6 +126,11 @@ bool glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
||||
|
||||
void glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
|
||||
|
||||
bool glx_bind_texture(session_t *ps, glx_texture_t **pptex,
|
||||
int x, int y, int width, int height, bool repeat);
|
||||
|
||||
void glx_release_texture(session_t *ps, glx_texture_t **ptex);
|
||||
|
||||
void glx_paint_pre(session_t *ps, region_t *preg) attr_nonnull(1, 2);
|
||||
|
||||
/**
|
||||
@@ -103,7 +143,15 @@ static inline bool glx_tex_binded(const glx_texture_t *ptex, xcb_pixmap_t pixmap
|
||||
void glx_set_clip(session_t *ps, const region_t *reg);
|
||||
|
||||
bool glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||
GLfloat factor_center, const region_t *reg_tgt, glx_blur_cache_t *pbc);
|
||||
double opacity, const region_t *reg_tgt, glx_blur_cache_t *pbc);
|
||||
|
||||
bool glx_round_corners_dst0(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int shader_idx,
|
||||
int dx, int dy, int width, int height, float z, float cr,
|
||||
const region_t *reg_tgt, glx_blur_cache_t *pbc);
|
||||
|
||||
bool glx_round_corners_dst1(session_t *ps, struct managed_win *w, const glx_texture_t *ptex, int shader_idx,
|
||||
int dx, int dy, int width, int height, float z, float cr,
|
||||
const region_t *reg_tgt, glx_blur_cache_t *pbc);
|
||||
|
||||
GLuint glx_create_shader(GLenum shader_type, const char *shader_str);
|
||||
|
||||
@@ -157,17 +205,19 @@ static inline void free_glx_fbo(GLuint *pfbo) {
|
||||
* Free data in glx_blur_cache_t on resize.
|
||||
*/
|
||||
static inline void free_glx_bc_resize(session_t *ps, glx_blur_cache_t *pbc) {
|
||||
free_texture_r(ps, &pbc->textures[0]);
|
||||
free_texture_r(ps, &pbc->textures[1]);
|
||||
pbc->width = 0;
|
||||
pbc->height = 0;
|
||||
for (int i = 0; i < MAX_BLUR_PASS; i++) {
|
||||
free_texture_r(ps, &pbc->textures[i]);
|
||||
pbc->width[i] = 0;
|
||||
pbc->height[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a glx_blur_cache_t
|
||||
*/
|
||||
static inline void free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) {
|
||||
free_glx_fbo(&pbc->fbo);
|
||||
for (int i = 0; i < MAX_BLUR_PASS; i++)
|
||||
free_glx_fbo(&pbc->fbos[i]);
|
||||
free_glx_bc_resize(ps, pbc);
|
||||
}
|
||||
|
||||
@@ -196,7 +246,6 @@ static inline void free_texture(session_t *ps, glx_texture_t **pptex) {
|
||||
*/
|
||||
static inline void free_paint_glx(session_t *ps, paint_t *ppaint) {
|
||||
free_texture(ps, &ppaint->ptex);
|
||||
ppaint->fbcfg = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,6 +256,8 @@ static inline void free_win_res_glx(session_t *ps, struct managed_win *w) {
|
||||
free_paint_glx(ps, &w->shadow_paint);
|
||||
#ifdef CONFIG_OPENGL
|
||||
free_glx_bc(ps, &w->glx_blur_cache);
|
||||
free_glx_bc(ps, &w->glx_round_cache);
|
||||
free_texture(ps, &w->glx_texture_bg);
|
||||
free(w->paint.fbcfg);
|
||||
#endif
|
||||
}
|
||||
|
||||
106
src/options.c
106
src/options.c
@@ -114,6 +114,18 @@ static void usage(const char *argv0, int ret) {
|
||||
"--active-opacity opacity\n"
|
||||
" Default opacity for active windows. (0.0 - 1.0)\n"
|
||||
"\n"
|
||||
"--corner-radius value\n"
|
||||
" Round the corners of windows. (defaults to 0)\n"
|
||||
"\n"
|
||||
"--rounded-corners-exclude condition\n"
|
||||
" Exclude conditions for rounded corners.\n"
|
||||
"\n"
|
||||
"--round-borders value\n"
|
||||
" When rounding corners, round the borders of windows. (defaults to 1)\n"
|
||||
"\n"
|
||||
"--round-borders-exclude condition\n"
|
||||
" Exclude conditions for rounding borders.\n"
|
||||
"\n"
|
||||
"--mark-wmwin-focused\n"
|
||||
" Try to detect WM windows and mark them as active.\n"
|
||||
"\n"
|
||||
@@ -202,8 +214,8 @@ static void usage(const char *argv0, int ret) {
|
||||
"\n"
|
||||
"--blur-method\n"
|
||||
" The algorithm used for background bluring. Available choices are:\n"
|
||||
" 'none' to disable, 'gaussian', 'box' or 'kernel' for custom\n"
|
||||
" convolution blur with --blur-kern.\n"
|
||||
" 'none' to disable, 'dual_kawase', 'gaussian', 'box' or 'kernel'\n"
|
||||
" for custom convolution blur with --blur-kern.\n"
|
||||
" Note: 'gaussian' and 'box' require --experimental-backends.\n"
|
||||
"\n"
|
||||
"--blur-size\n"
|
||||
@@ -211,6 +223,10 @@ static void usage(const char *argv0, int ret) {
|
||||
"\n"
|
||||
"--blur-deviation\n"
|
||||
" The standard deviation for the 'gaussian' blur method.\n"
|
||||
"\n"
|
||||
"--blur-strength\n"
|
||||
" Only valid for '--blur-method dual_kawase'!\n"
|
||||
" The strength of the kawase blur as an integer between 1 and 20. Defaults to 5.\n"
|
||||
"\n"
|
||||
"--blur-background\n"
|
||||
" Blur background of semi-transparent / ARGB windows. Bad in\n"
|
||||
@@ -227,6 +243,7 @@ static void usage(const char *argv0, int ret) {
|
||||
" opacity.\n"
|
||||
"\n"
|
||||
"--blur-kern matrix\n"
|
||||
" Only valid for '--blur-method convolution'!\n"
|
||||
" Specify the blur convolution kernel, with the following format:\n"
|
||||
" WIDTH,HEIGHT,ELE1,ELE2,ELE3,ELE4,ELE5...\n"
|
||||
" The element in the center must not be included, it will be forever\n"
|
||||
@@ -398,8 +415,10 @@ static const struct option longopts[] = {
|
||||
{"opengl", no_argument, NULL, 289},
|
||||
{"backend", required_argument, NULL, 290},
|
||||
{"glx-no-stencil", no_argument, NULL, 291},
|
||||
{"glx-copy-from-front", no_argument, NULL, 292},
|
||||
{"benchmark", required_argument, NULL, 293},
|
||||
{"benchmark-wid", required_argument, NULL, 294},
|
||||
{"glx-use-copysubbuffermesa", no_argument, NULL, 295},
|
||||
{"blur-background-exclude", required_argument, NULL, 296},
|
||||
{"active-opacity", required_argument, NULL, 297},
|
||||
{"glx-no-rebind-pixmap", no_argument, NULL, 298},
|
||||
@@ -435,6 +454,11 @@ static const struct option longopts[] = {
|
||||
{"blur-method", required_argument, NULL, 328},
|
||||
{"blur-size", required_argument, NULL, 329},
|
||||
{"blur-deviation", required_argument, NULL, 330},
|
||||
{"blur-strength", required_argument, NULL, 331},
|
||||
{"corner-radius", required_argument, NULL, 332},
|
||||
{"rounded-corners-exclude", required_argument, NULL, 333},
|
||||
{"round-borders", required_argument, NULL, 334},
|
||||
{"round-borders-exclude", required_argument, NULL, 335},
|
||||
{"experimental-backends", no_argument, NULL, 733},
|
||||
{"monitor-repaint", no_argument, NULL, 800},
|
||||
{"diagnostics", no_argument, NULL, 801},
|
||||
@@ -467,23 +491,21 @@ bool get_early_config(int argc, char *const *argv, char **config_file, bool *all
|
||||
} else if (o == 'b') {
|
||||
*fork = true;
|
||||
} else if (o == 'd') {
|
||||
log_error("-d is removed, please use the DISPLAY "
|
||||
"environment variable");
|
||||
goto err;
|
||||
log_warn("-d will be ignored, please use the DISPLAY "
|
||||
"environment variable");
|
||||
} else if (o == 314) {
|
||||
*all_xerrors = true;
|
||||
} else if (o == 318) {
|
||||
printf("%s\n", COMPTON_VERSION);
|
||||
return true;
|
||||
} else if (o == 'S') {
|
||||
log_error("-S is no longer available");
|
||||
goto err;
|
||||
log_warn("-S will be ignored");
|
||||
} else if (o == 320) {
|
||||
log_error("--no-name-pixmap is no longer available");
|
||||
goto err;
|
||||
log_warn("--no-name-pixmap will be ignored");
|
||||
} else if (o == '?' || o == ':') {
|
||||
usage(argv[0], 1);
|
||||
goto err;
|
||||
*exit_code = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,13 +513,11 @@ bool get_early_config(int argc, char *const *argv, char **config_file, bool *all
|
||||
if (optind < argc) {
|
||||
// log is not initialized here yet
|
||||
fprintf(stderr, "picom doesn't accept positional arguments.\n");
|
||||
goto err;
|
||||
*exit_code = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
err:
|
||||
*exit_code = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -516,10 +536,9 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
||||
|
||||
// Parse commandline arguments. Range checking will be done later.
|
||||
|
||||
const char *deprecation_message attr_unused =
|
||||
"has been removed. If you encounter problems "
|
||||
"without this feature, please feel free to "
|
||||
"open a bug report.";
|
||||
const char *deprecation_message = "has been removed. If you encounter problems "
|
||||
"without this feature, please feel free to "
|
||||
"open a bug report.";
|
||||
optind = 1;
|
||||
while (-1 != (o = getopt_long(argc, argv, shortopts, longopts, &longopt_idx))) {
|
||||
switch (o) {
|
||||
@@ -645,14 +664,14 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
||||
break;
|
||||
case 271:
|
||||
// --alpha-step
|
||||
log_error("--alpha-step has been removed, we now tries to "
|
||||
log_warn("--alpha-step has been removed, we now tries to "
|
||||
"make use of all alpha values");
|
||||
return false;
|
||||
case 272: log_error("use of --dbe is deprecated"); return false;
|
||||
break;
|
||||
case 272: log_warn("use of --dbe is deprecated"); break;
|
||||
case 273:
|
||||
log_error("--paint-on-overlay has been removed, the feature is enabled "
|
||||
"whenever possible");
|
||||
return false;
|
||||
log_warn("--paint-on-overlay has been removed, and is enabled "
|
||||
"when possible");
|
||||
break;
|
||||
P_CASEBOOL(274, sw_opti);
|
||||
case 275:
|
||||
// --vsync-aggressive
|
||||
@@ -704,11 +723,19 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
||||
exit(1);
|
||||
break;
|
||||
P_CASEBOOL(291, glx_no_stencil);
|
||||
case 292:
|
||||
log_error("--glx-copy-from-front %s", deprecation_message);
|
||||
exit(1);
|
||||
break;
|
||||
P_CASEINT(293, benchmark);
|
||||
case 294:
|
||||
// --benchmark-wid
|
||||
opt->benchmark_wid = (xcb_window_t)strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 295:
|
||||
log_error("--glx-use-copysubbuffermesa %s", deprecation_message);
|
||||
exit(1);
|
||||
break;
|
||||
case 296:
|
||||
// --blur-background-exclude
|
||||
condlst_add(&opt->blur_background_blacklist, optarg);
|
||||
@@ -787,8 +814,9 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
||||
P_CASEBOOL(311, vsync_use_glfinish);
|
||||
case 312:
|
||||
// --xrender-sync
|
||||
log_error("Please use --xrender-sync-fence instead of --xrender-sync");
|
||||
return false;
|
||||
log_warn("Please use --xrender-sync-fence instead of --xrender-sync");
|
||||
opt->xrender_sync_fence = true;
|
||||
break;
|
||||
P_CASEBOOL(313, xrender_sync_fence);
|
||||
P_CASEBOOL(315, no_fading_destroyed_argb);
|
||||
P_CASEBOOL(316, force_win_blend);
|
||||
@@ -835,7 +863,15 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
||||
// --blur-deviation
|
||||
opt->blur_deviation = atof(optarg);
|
||||
break;
|
||||
|
||||
case 331:
|
||||
// --blur-strength
|
||||
opt->blur_strength = parse_kawase_blur_strength(atoi(optarg));
|
||||
break;
|
||||
case 332: opt->corner_radius = atoi(optarg); break;
|
||||
case 333: condlst_add(&opt->rounded_corners_blacklist, optarg); break;
|
||||
case 334: opt->round_borders = atoi(optarg); break;
|
||||
case 335: condlst_add(&opt->round_borders_blacklist, optarg); break;
|
||||
|
||||
P_CASEBOOL(733, experimental_backends);
|
||||
P_CASEBOOL(800, monitor_repaint);
|
||||
case 801: opt->print_diagnostics = true; break;
|
||||
@@ -915,6 +951,13 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
||||
opt->track_leader = true;
|
||||
}
|
||||
|
||||
// Blur method kawase is not compatible with the xrender backend
|
||||
if (opt->backend != BKEND_GLX && (opt->blur_method == BLUR_METHOD_DUAL_KAWASE
|
||||
|| opt->blur_method == BLUR_METHOD_ALT_KAWASE)) {
|
||||
log_warn("Blur method 'kawase' is incompatible with the XRender backend. Fall back to default.\n");
|
||||
opt->blur_method = BLUR_METHOD_KERNEL;
|
||||
}
|
||||
|
||||
// Fill default blur kernel
|
||||
if (opt->blur_method == BLUR_METHOD_KERNEL &&
|
||||
(!opt->blur_kerns || !opt->blur_kerns[0])) {
|
||||
@@ -924,6 +967,15 @@ bool get_cfg(options_t *opt, int argc, char *const *argv, bool shadow_enable,
|
||||
CHECK(opt->blur_kernel_count);
|
||||
}
|
||||
|
||||
// override blur_kernel_count for kawase
|
||||
if (opt->blur_method == BLUR_METHOD_DUAL_KAWASE ||
|
||||
opt->blur_method == BLUR_METHOD_ALT_KAWASE) {
|
||||
opt->blur_kernel_count = MAX_BLUR_PASS;
|
||||
opt->blur_kerns = ccalloc(opt->blur_kernel_count, struct conv *);
|
||||
CHECK(opt->blur_kerns);
|
||||
CHECK(opt->blur_kernel_count);
|
||||
}
|
||||
|
||||
if (opt->resize_damage < 0) {
|
||||
log_warn("Negative --resize-damage will not work correctly.");
|
||||
}
|
||||
|
||||
666
src/picom.c
666
src/picom.c
@@ -19,7 +19,6 @@
|
||||
#include <string.h>
|
||||
#include <xcb/composite.h>
|
||||
#include <xcb/damage.h>
|
||||
#include <xcb/glx.h>
|
||||
#include <xcb/present.h>
|
||||
#include <xcb/randr.h>
|
||||
#include <xcb/render.h>
|
||||
@@ -99,9 +98,7 @@ const char *const BACKEND_STRS[] = {[BKEND_XRENDER] = "xrender",
|
||||
session_t *ps_g = NULL;
|
||||
|
||||
void set_root_flags(session_t *ps, uint64_t flags) {
|
||||
log_debug("Setting root flags: %lu", flags);
|
||||
ps->root_flags |= flags;
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
|
||||
void quit(session_t *ps) {
|
||||
@@ -124,16 +121,15 @@ static inline void free_xinerama_info(session_t *ps) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current system clock in 40micro second accuracy.
|
||||
* Get current system clock in milliseconds.
|
||||
*/
|
||||
int64_t get_time_ms(void) {
|
||||
struct timespec tp;
|
||||
clock_gettime(CLOCK_MONOTONIC, &tp);
|
||||
/* return (int64_t)tp.tv_sec * 1000 + (int64_t)tp.tv_nsec / 1000000; //ultra high refresh */
|
||||
return (int64_t)tp.tv_sec * 100 + (int64_t)tp.tv_nsec / 250000; //ultra high refresh
|
||||
// return (int64_t)tp.tv_sec * 1000 + (int64_t)tp.tv_nsec / 1000000;
|
||||
return (int64_t)tp.tv_sec * 100 + (int64_t)tp.tv_nsec / 250000;
|
||||
}
|
||||
|
||||
|
||||
// XXX Move to x.c
|
||||
void cxinerama_upd_scrs(session_t *ps) {
|
||||
// XXX Consider deprecating Xinerama, switch to RandR when necessary
|
||||
@@ -182,7 +178,7 @@ static inline struct managed_win *find_win_all(session_t *ps, const xcb_window_t
|
||||
if (!w)
|
||||
w = find_toplevel(ps, wid);
|
||||
if (!w)
|
||||
w = find_managed_window_or_parent(ps, wid);
|
||||
w = find_toplevel2(ps, wid);
|
||||
return w;
|
||||
}
|
||||
|
||||
@@ -305,9 +301,9 @@ uint32_t determine_evmask(session_t *ps, xcb_window_t wid, win_evmode_t mode) {
|
||||
struct managed_win *w = NULL;
|
||||
|
||||
// Check if it's a mapped frame window
|
||||
if (mode == WIN_EVMODE_FRAME ||
|
||||
if (WIN_EVMODE_FRAME == mode ||
|
||||
((w = find_managed_win(ps, wid)) && w->a.map_state == XCB_MAP_STATE_VIEWABLE)) {
|
||||
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
|
||||
evmask |= XCB_EVENT_MASK_PROPERTY_CHANGE;
|
||||
if (!ps->o.use_ewmh_active_win) {
|
||||
evmask |= XCB_EVENT_MASK_FOCUS_CHANGE;
|
||||
}
|
||||
@@ -377,219 +373,31 @@ static void recheck_focus(session_t *ps) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild cached <code>screen_reg</code>.
|
||||
* Look for the client window of a particular window.
|
||||
*/
|
||||
static void rebuild_screen_reg(session_t *ps) {
|
||||
get_screen_region(ps, &ps->screen_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild <code>shadow_exclude_reg</code>.
|
||||
*/
|
||||
static void rebuild_shadow_exclude_reg(session_t *ps) {
|
||||
bool ret = parse_geometry(ps, ps->o.shadow_exclude_reg_str, &ps->shadow_exclude_reg);
|
||||
if (!ret)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/// Free up all the images and deinit the backend
|
||||
static void destroy_backend(session_t *ps) {
|
||||
win_stack_foreach_managed_safe(w, &ps->window_stack) {
|
||||
// Wrapping up fading in progress
|
||||
if (win_skip_fading(ps, w)) {
|
||||
// `w` is freed by win_skip_fading
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ps->backend_data) {
|
||||
if (w->state == WSTATE_MAPPED) {
|
||||
win_release_images(ps->backend_data, w);
|
||||
} else {
|
||||
assert(!w->win_image);
|
||||
assert(!w->shadow_image);
|
||||
}
|
||||
}
|
||||
free_paint(ps, &w->paint);
|
||||
xcb_window_t find_client_win(session_t *ps, xcb_window_t w) {
|
||||
if (wid_has_prop(ps, w, ps->atoms->aWM_STATE)) {
|
||||
return w;
|
||||
}
|
||||
|
||||
if (ps->backend_data && ps->root_image) {
|
||||
ps->backend_data->ops->release_image(ps->backend_data, ps->root_image);
|
||||
ps->root_image = NULL;
|
||||
xcb_query_tree_reply_t *reply =
|
||||
xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, w), NULL);
|
||||
if (!reply)
|
||||
return 0;
|
||||
|
||||
xcb_window_t *children = xcb_query_tree_children(reply);
|
||||
int nchildren = xcb_query_tree_children_length(reply);
|
||||
int i;
|
||||
xcb_window_t ret = 0;
|
||||
|
||||
for (i = 0; i < nchildren; ++i) {
|
||||
if ((ret = find_client_win(ps, children[i])))
|
||||
break;
|
||||
}
|
||||
|
||||
if (ps->backend_data) {
|
||||
// deinit backend
|
||||
if (ps->backend_blur_context) {
|
||||
ps->backend_data->ops->destroy_blur_context(
|
||||
ps->backend_data, ps->backend_blur_context);
|
||||
ps->backend_blur_context = NULL;
|
||||
}
|
||||
ps->backend_data->ops->deinit(ps->backend_data);
|
||||
ps->backend_data = NULL;
|
||||
}
|
||||
}
|
||||
free(reply);
|
||||
|
||||
static bool initialize_blur(session_t *ps) {
|
||||
struct kernel_blur_args kargs;
|
||||
struct gaussian_blur_args gargs;
|
||||
struct box_blur_args bargs;
|
||||
|
||||
void *args = NULL;
|
||||
switch (ps->o.blur_method) {
|
||||
case BLUR_METHOD_BOX:
|
||||
bargs.size = ps->o.blur_radius;
|
||||
args = (void *)&bargs;
|
||||
break;
|
||||
case BLUR_METHOD_KERNEL:
|
||||
kargs.kernel_count = ps->o.blur_kernel_count;
|
||||
kargs.kernels = ps->o.blur_kerns;
|
||||
args = (void *)&kargs;
|
||||
break;
|
||||
case BLUR_METHOD_GAUSSIAN:
|
||||
gargs.size = ps->o.blur_radius;
|
||||
gargs.deviation = ps->o.blur_deviation;
|
||||
args = (void *)&gargs;
|
||||
break;
|
||||
default: return true;
|
||||
}
|
||||
|
||||
ps->backend_blur_context = ps->backend_data->ops->create_blur_context(
|
||||
ps->backend_data, ps->o.blur_method, args);
|
||||
return ps->backend_blur_context != NULL;
|
||||
}
|
||||
|
||||
/// Init the backend and bind all the window pixmap to backend images
|
||||
static bool initialize_backend(session_t *ps) {
|
||||
if (ps->o.experimental_backends) {
|
||||
assert(!ps->backend_data);
|
||||
// Reinitialize win_data
|
||||
assert(backend_list[ps->o.backend]);
|
||||
ps->backend_data = backend_list[ps->o.backend]->init(ps);
|
||||
if (!ps->backend_data) {
|
||||
log_fatal("Failed to initialize backend, aborting...");
|
||||
quit(ps);
|
||||
return false;
|
||||
}
|
||||
ps->backend_data->ops = backend_list[ps->o.backend];
|
||||
|
||||
if (!initialize_blur(ps)) {
|
||||
log_fatal("Failed to prepare for background blur, aborting...");
|
||||
ps->backend_data->ops->deinit(ps->backend_data);
|
||||
ps->backend_data = NULL;
|
||||
quit(ps);
|
||||
return false;
|
||||
}
|
||||
|
||||
// window_stack shouldn't include window that's
|
||||
// not in the hash table at this point. Since
|
||||
// there cannot be any fading windows.
|
||||
HASH_ITER2(ps->windows, _w) {
|
||||
if (!_w->managed) {
|
||||
continue;
|
||||
}
|
||||
auto w = (struct managed_win *)_w;
|
||||
assert(w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED);
|
||||
if (w->state == WSTATE_MAPPED) {
|
||||
// We need to reacquire image
|
||||
log_debug("Marking window %#010x (%s) for update after "
|
||||
"redirection",
|
||||
w->base.id, w->name);
|
||||
if (w->shadow) {
|
||||
struct color c = {
|
||||
.red = ps->o.shadow_red,
|
||||
.green = ps->o.shadow_green,
|
||||
.blue = ps->o.shadow_blue,
|
||||
.alpha = ps->o.shadow_opacity,
|
||||
};
|
||||
win_bind_shadow(ps->backend_data, w, c,
|
||||
ps->gaussian_map);
|
||||
}
|
||||
|
||||
w->flags |= WIN_FLAGS_PIXMAP_STALE;
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The old backends binds pixmap lazily, nothing to do here
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Handle configure event of the root window
|
||||
static void configure_root(session_t *ps) {
|
||||
auto r = XCB_AWAIT(xcb_get_geometry, ps->c, ps->root);
|
||||
if (!r) {
|
||||
log_fatal("Failed to fetch root geometry");
|
||||
abort();
|
||||
}
|
||||
|
||||
log_info("Root configuration changed, new geometry: %dx%d", r->width, r->height);
|
||||
bool has_root_change = false;
|
||||
if (ps->redirected) {
|
||||
// On root window changes
|
||||
if (ps->o.experimental_backends) {
|
||||
assert(ps->backend_data);
|
||||
has_root_change = ps->backend_data->ops->root_change != NULL;
|
||||
} else {
|
||||
// Old backend can handle root change
|
||||
has_root_change = true;
|
||||
}
|
||||
|
||||
if (!has_root_change) {
|
||||
// deinit/reinit backend and free up resources if the backend
|
||||
// cannot handle root change
|
||||
destroy_backend(ps);
|
||||
}
|
||||
free_paint(ps, &ps->tgt_buffer);
|
||||
}
|
||||
|
||||
ps->root_width = r->width;
|
||||
ps->root_height = r->height;
|
||||
|
||||
rebuild_screen_reg(ps);
|
||||
rebuild_shadow_exclude_reg(ps);
|
||||
|
||||
// Invalidate reg_ignore from the top
|
||||
auto top_w = win_stack_find_next_managed(ps, &ps->window_stack);
|
||||
if (top_w) {
|
||||
rc_region_unref(&top_w->reg_ignore);
|
||||
top_w->reg_ignore_valid = false;
|
||||
}
|
||||
|
||||
if (ps->redirected) {
|
||||
for (int i = 0; i < ps->ndamage; i++) {
|
||||
pixman_region32_clear(&ps->damage_ring[i]);
|
||||
}
|
||||
ps->damage = ps->damage_ring + ps->ndamage - 1;
|
||||
#ifdef CONFIG_OPENGL
|
||||
// GLX root change callback
|
||||
if (BKEND_GLX == ps->o.backend && !ps->o.experimental_backends) {
|
||||
glx_on_root_change(ps);
|
||||
}
|
||||
#endif
|
||||
if (has_root_change) {
|
||||
if (ps->backend_data != NULL) {
|
||||
ps->backend_data->ops->root_change(ps->backend_data, ps);
|
||||
}
|
||||
// Old backend's root_change is not a specific function
|
||||
} else {
|
||||
if (!initialize_backend(ps)) {
|
||||
log_fatal("Failed to re-initialize backend after root "
|
||||
"change, aborting...");
|
||||
ps->quit = true;
|
||||
// TODO only event handlers should request ev_break,
|
||||
// otherwise it's too hard to keep track of what can break
|
||||
// the event loop
|
||||
ev_break(ps->loop, EVBREAK_ALL);
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-acquire the root pixmap.
|
||||
root_damaged(ps);
|
||||
}
|
||||
force_repaint(ps);
|
||||
}
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void handle_root_flags(session_t *ps) {
|
||||
@@ -607,11 +415,6 @@ static void handle_root_flags(session_t *ps) {
|
||||
}
|
||||
ps->root_flags &= ~(uint64_t)ROOT_FLAGS_SCREEN_CHANGE;
|
||||
}
|
||||
|
||||
if ((ps->root_flags & ROOT_FLAGS_CONFIGURED) != 0) {
|
||||
configure_root(ps);
|
||||
ps->root_flags &= ~(uint64_t)ROOT_FLAGS_CONFIGURED;
|
||||
}
|
||||
}
|
||||
|
||||
static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
|
||||
@@ -668,8 +471,20 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
|
||||
w->frame_opacity = 1.0;
|
||||
}
|
||||
|
||||
// The below moved to it's own function:
|
||||
// `win_determine_rounded_corners` (win.c)
|
||||
/*
|
||||
// Don't round full screen windows & excluded windows
|
||||
if ((w && win_is_fullscreen(ps, w)) ||
|
||||
c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL)) {
|
||||
w->corner_radius = 0;
|
||||
} else {
|
||||
w->corner_radius = ps->o.corner_radius;
|
||||
}
|
||||
*/
|
||||
|
||||
// Update window mode
|
||||
w->mode = win_calc_mode(w);
|
||||
w->mode = win_calc_mode(ps, w);
|
||||
|
||||
// Destroy all reg_ignore above when frame opaque state changes on
|
||||
// SOLID mode
|
||||
@@ -678,56 +493,63 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
|
||||
}
|
||||
}
|
||||
|
||||
win_stack_foreach_managed(w, &ps->window_stack) {
|
||||
bool posChanged = (w->oldX != -30000 && w->oldY != -30000 && w->oldW != 0 && w->oldH != 0)
|
||||
&& (w->g.x != w->newX || w->g.y != w->newY || w->g.width != w->newW || w->g.height != w->newH);
|
||||
win_stack_foreach_managed(w, &ps->window_stack) {
|
||||
bool posChanged =
|
||||
(w->oldX != -10000 && w->oldY != -10000 && w->oldW != 0 && w->oldH != 0) &&
|
||||
(w->g.x != w->newX || w->g.y != w->newY || w->g.width != w->newW ||
|
||||
w->g.height != w->newH);
|
||||
|
||||
if (posChanged) {
|
||||
float t = get_time_ms();
|
||||
float moveDx = (t - w->moveTimeX) / ps->o.transition_length;
|
||||
float moveDy = (t - w->moveTimeY) / ps->o.transition_length;
|
||||
float moveDw = (t - w->moveTimeW) / ps->o.transition_length;
|
||||
float moveDh = (t - w->moveTimeH) / ps->o.transition_length;
|
||||
if (moveDx >= 1.0) moveDx = 1.0;
|
||||
if (moveDy >= 1.0) moveDy = 1.0;
|
||||
if (moveDw >= 1.0) moveDw = 1.0;
|
||||
if (moveDh >= 1.0) moveDh = 1.0;
|
||||
if (posChanged) {
|
||||
float t = get_time_ms();
|
||||
float moveDx = (t - w->moveTimeX) / ps->o.transition_length;
|
||||
float moveDy = (t - w->moveTimeY) / ps->o.transition_length;
|
||||
float moveDw = (t - w->moveTimeW) / ps->o.transition_length;
|
||||
float moveDh = (t - w->moveTimeH) / ps->o.transition_length;
|
||||
if (moveDx >= 1.0)
|
||||
moveDx = 1.0;
|
||||
if (moveDy >= 1.0)
|
||||
moveDy = 1.0;
|
||||
if (moveDw >= 1.0)
|
||||
moveDw = 1.0;
|
||||
if (moveDh >= 1.0)
|
||||
moveDh = 1.0;
|
||||
|
||||
float q = pow (moveDx, ps->o.transition_pow_x);
|
||||
float k = pow (moveDy, ps->o.transition_pow_y);
|
||||
float g = pow (moveDw, ps->o.transition_pow_w);
|
||||
float z = pow (moveDh, ps->o.transition_pow_h);
|
||||
float q = pow(moveDx, ps->o.transition_pow_x);
|
||||
float k = pow(moveDy, ps->o.transition_pow_y);
|
||||
float g = pow(moveDw, ps->o.transition_pow_w);
|
||||
float z = pow(moveDh, ps->o.transition_pow_h);
|
||||
|
||||
float x = (float) w->oldX * (1-q) + (float) w->newX * q;
|
||||
float y = (float) w->oldY * (1-k) + (float) w->newY * k;
|
||||
float W = (float) w->oldW * (1-g) + (float) w->newW * g;
|
||||
float h = (float) w->oldH * (1-z) + (float) w->newH * z;
|
||||
float x = (float)w->oldX * (1 - q) + (float)w->newX * q;
|
||||
float y = (float)w->oldY * (1 - k) + (float)w->newY * k;
|
||||
float W = (float)w->oldW * (1 - g) + (float)w->newW * g;
|
||||
float h = (float)w->oldH * (1 - z) + (float)w->newH * z;
|
||||
|
||||
add_damage_from_win(ps, w);
|
||||
w->g.x = (int) x;
|
||||
w->g.y = (int) y;
|
||||
if (ps->o.size_transition) {
|
||||
w->g.width = (int) W;
|
||||
w->g.height = (int) h;
|
||||
}
|
||||
add_damage_from_win(ps, w);
|
||||
w->g.x = (int)x;
|
||||
w->g.y = (int)y;
|
||||
if (ps->o.size_transition) {
|
||||
w->g.width = (int)W;
|
||||
w->g.height = (int)h;
|
||||
}
|
||||
|
||||
/* w->to_paint = true; */
|
||||
w->mode = WMODE_TRANS;
|
||||
*fade_running = true;
|
||||
}
|
||||
// TODO
|
||||
//if ((w->shadow && posChanged) || (ps->o.size_transition && w->pixmap_damaged)) {
|
||||
// rc_region_unref(&w->extents);
|
||||
// rc_region_unref(&w->border_size);
|
||||
// w->extents = win_extents(ps, w);
|
||||
// calc_win_size(ps, w);
|
||||
/* w->to_paint = true; */
|
||||
w->mode = WMODE_TRANS;
|
||||
*fade_running = true;
|
||||
}
|
||||
// TODO
|
||||
// if ((w->shadow && posChanged) || (ps->o.size_transition &&
|
||||
// w->pixmap_damaged)) {
|
||||
// rc_region_unref(&w->extents);
|
||||
// rc_region_unref(&w->border_size);
|
||||
// w->extents = win_extents(ps, w);
|
||||
// calc_win_size(ps, w);
|
||||
|
||||
// if (ps->shape_exists && ps->o.shadow_ignore_shaped
|
||||
// && ps->o.detect_rounded_corners && w->bounding_shaped)
|
||||
// win_update_shape(ps, w);
|
||||
//}
|
||||
/* add_damage_win(ps, w); */
|
||||
}
|
||||
// if (ps->shape_exists && ps->o.shadow_ignore_shaped
|
||||
// && ps->o.detect_rounded_corners && w->bounding_shaped)
|
||||
// win_update_shape(ps, w);
|
||||
//}
|
||||
/* add_damage_win(ps, w); */
|
||||
}
|
||||
|
||||
// Opacity will not change, from now on.
|
||||
rc_region_t *last_reg_ignore = rc_region_new();
|
||||
@@ -747,6 +569,11 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
|
||||
rc_region_unref(&w->reg_ignore);
|
||||
}
|
||||
|
||||
// Clear flags if we are not using experimental backends
|
||||
if (!ps->o.experimental_backends) {
|
||||
w->flags = 0;
|
||||
}
|
||||
|
||||
// log_trace("%d %d %s", w->a.map_state, w->ever_damaged, w->name);
|
||||
|
||||
// Give up if it's not damaged or invisible, or it's unmapped and its
|
||||
@@ -801,10 +628,10 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
|
||||
// w->mode == WMODE_SOLID or WMODE_FRAME_TRANS
|
||||
region_t *tmp = rc_region_new();
|
||||
if (w->mode == WMODE_SOLID) {
|
||||
*tmp = win_get_bounding_shape_global_by_val(w);
|
||||
*tmp = win_get_bounding_shape_global_by_val(w, false);
|
||||
} else {
|
||||
// w->mode == WMODE_FRAME_TRANS
|
||||
win_get_region_noframe_local(w, tmp);
|
||||
win_get_region_noframe_local(w, tmp, false);
|
||||
pixman_region32_intersect(tmp, tmp, &w->bounding_shape);
|
||||
pixman_region32_translate(tmp, w->g.x, w->g.y);
|
||||
}
|
||||
@@ -894,6 +721,243 @@ static struct managed_win *paint_preprocess(session_t *ps, bool *fade_running) {
|
||||
return bottom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild cached <code>screen_reg</code>.
|
||||
*/
|
||||
static void rebuild_screen_reg(session_t *ps) {
|
||||
get_screen_region(ps, &ps->screen_reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild <code>shadow_exclude_reg</code>.
|
||||
*/
|
||||
static void rebuild_shadow_exclude_reg(session_t *ps) {
|
||||
bool ret = parse_geometry(ps, ps->o.shadow_exclude_reg_str, &ps->shadow_exclude_reg);
|
||||
if (!ret)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/// Free up all the images and deinit the backend
|
||||
static void destroy_backend(session_t *ps) {
|
||||
win_stack_foreach_managed_safe(w, &ps->window_stack) {
|
||||
// Wrapping up fading in progress
|
||||
if (win_skip_fading(ps, w)) {
|
||||
// `w` is freed by win_skip_fading
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ps->backend_data) {
|
||||
if (w->state == WSTATE_MAPPED) {
|
||||
win_release_images(ps->backend_data, w);
|
||||
} else {
|
||||
assert(!w->win_image);
|
||||
assert(!w->shadow_image);
|
||||
}
|
||||
}
|
||||
free_paint(ps, &w->paint);
|
||||
}
|
||||
|
||||
if (ps->backend_data && ps->root_image) {
|
||||
ps->backend_data->ops->release_image(ps->backend_data, ps->root_image);
|
||||
ps->root_image = NULL;
|
||||
}
|
||||
|
||||
if (ps->backend_data) {
|
||||
// deinit backend
|
||||
if (ps->backend_blur_context) {
|
||||
ps->backend_data->ops->destroy_blur_context(
|
||||
ps->backend_data, ps->backend_blur_context);
|
||||
ps->backend_blur_context = NULL;
|
||||
}
|
||||
if (ps->backend_round_context) {
|
||||
ps->backend_data->ops->destroy_round_context(
|
||||
ps->backend_data, ps->backend_round_context);
|
||||
ps->backend_round_context = NULL;
|
||||
}
|
||||
ps->backend_data->ops->deinit(ps->backend_data);
|
||||
ps->backend_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool initialize_blur(session_t *ps) {
|
||||
struct kernel_blur_args kargs;
|
||||
struct gaussian_blur_args gargs;
|
||||
struct dual_kawase_blur_args dkargs;
|
||||
struct box_blur_args bargs;
|
||||
|
||||
void *args = NULL;
|
||||
switch (ps->o.blur_method) {
|
||||
case BLUR_METHOD_BOX:
|
||||
bargs.size = ps->o.blur_radius;
|
||||
args = (void *)&bargs;
|
||||
break;
|
||||
case BLUR_METHOD_KERNEL:
|
||||
kargs.kernel_count = ps->o.blur_kernel_count;
|
||||
kargs.kernels = ps->o.blur_kerns;
|
||||
args = (void *)&kargs;
|
||||
break;
|
||||
case BLUR_METHOD_GAUSSIAN:
|
||||
gargs.size = ps->o.blur_radius;
|
||||
gargs.deviation = ps->o.blur_deviation;
|
||||
args = (void *)&gargs;
|
||||
break;
|
||||
case BLUR_METHOD_ALT_KAWASE:
|
||||
case BLUR_METHOD_DUAL_KAWASE:
|
||||
dkargs.size = ps->o.blur_radius;
|
||||
dkargs.strength = ps->o.blur_strength;
|
||||
args = (void *)&dkargs;
|
||||
break;
|
||||
default: return true;
|
||||
}
|
||||
|
||||
ps->backend_blur_context = ps->backend_data->ops->create_blur_context(
|
||||
ps->backend_data, ps->o.blur_method, args);
|
||||
return ps->backend_blur_context != NULL;
|
||||
}
|
||||
|
||||
static bool initialize_round_corners(session_t *ps) {
|
||||
struct round_corners_args cargs;
|
||||
cargs.corner_radius = ps->o.corner_radius;
|
||||
cargs.round_borders = ps->o.round_borders;
|
||||
ps->backend_round_context =
|
||||
ps->backend_data->ops->create_round_context(ps->backend_data, &cargs);
|
||||
return ps->backend_round_context != NULL;
|
||||
}
|
||||
|
||||
/// Init the backend and bind all the window pixmap to backend images
|
||||
static bool initialize_backend(session_t *ps) {
|
||||
if (ps->o.experimental_backends) {
|
||||
assert(!ps->backend_data);
|
||||
// Reinitialize win_data
|
||||
assert(backend_list[ps->o.backend]);
|
||||
ps->backend_data = backend_list[ps->o.backend]->init(ps);
|
||||
if (!ps->backend_data) {
|
||||
log_fatal("Failed to initialize backend, aborting...");
|
||||
quit(ps);
|
||||
return false;
|
||||
}
|
||||
ps->backend_data->ops = backend_list[ps->o.backend];
|
||||
|
||||
if (!initialize_blur(ps)) {
|
||||
log_fatal("Failed to prepare for background blur, aborting...");
|
||||
ps->backend_data->ops->deinit(ps->backend_data);
|
||||
ps->backend_data = NULL;
|
||||
quit(ps);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!initialize_round_corners(ps)) {
|
||||
log_fatal("Failed to prepare for rounded corners, will "
|
||||
"ignore...");
|
||||
ps->o.corner_radius = 0;
|
||||
}
|
||||
|
||||
// window_stack shouldn't include window that's
|
||||
// not in the hash table at this point. Since
|
||||
// there cannot be any fading windows.
|
||||
HASH_ITER2(ps->windows, _w) {
|
||||
if (!_w->managed) {
|
||||
continue;
|
||||
}
|
||||
auto w = (struct managed_win *)_w;
|
||||
assert(w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED);
|
||||
if (w->state == WSTATE_MAPPED) {
|
||||
// We need to reacquire image
|
||||
log_debug("Marking window %#010x (%s) for update after "
|
||||
"redirection",
|
||||
w->base.id, w->name);
|
||||
if (w->shadow) {
|
||||
struct color c = {
|
||||
.red = ps->o.shadow_red,
|
||||
.green = ps->o.shadow_green,
|
||||
.blue = ps->o.shadow_blue,
|
||||
.alpha = ps->o.shadow_opacity,
|
||||
};
|
||||
win_bind_shadow(ps->backend_data, w, c,
|
||||
ps->gaussian_map);
|
||||
}
|
||||
|
||||
w->flags |= WIN_FLAGS_PIXMAP_STALE;
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The old backends binds pixmap lazily, nothing to do here
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Handle configure event of a root window
|
||||
void configure_root(session_t *ps, int width, int height) {
|
||||
log_info("Root configuration changed, new geometry: %dx%d", width, height);
|
||||
bool has_root_change = false;
|
||||
if (ps->redirected) {
|
||||
// On root window changes
|
||||
if (ps->o.experimental_backends) {
|
||||
assert(ps->backend_data);
|
||||
has_root_change = ps->backend_data->ops->root_change != NULL;
|
||||
} else {
|
||||
// Old backend can handle root change
|
||||
has_root_change = true;
|
||||
}
|
||||
|
||||
if (!has_root_change) {
|
||||
// deinit/reinit backend and free up resources if the backend
|
||||
// cannot handle root change
|
||||
destroy_backend(ps);
|
||||
}
|
||||
free_paint(ps, &ps->tgt_buffer);
|
||||
}
|
||||
|
||||
ps->root_width = width;
|
||||
ps->root_height = height;
|
||||
|
||||
rebuild_screen_reg(ps);
|
||||
rebuild_shadow_exclude_reg(ps);
|
||||
|
||||
// Invalidate reg_ignore from the top
|
||||
auto top_w = win_stack_find_next_managed(ps, &ps->window_stack);
|
||||
if (top_w) {
|
||||
rc_region_unref(&top_w->reg_ignore);
|
||||
top_w->reg_ignore_valid = false;
|
||||
}
|
||||
|
||||
if (ps->redirected) {
|
||||
for (int i = 0; i < ps->ndamage; i++) {
|
||||
pixman_region32_clear(&ps->damage_ring[i]);
|
||||
}
|
||||
ps->damage = ps->damage_ring + ps->ndamage - 1;
|
||||
#ifdef CONFIG_OPENGL
|
||||
// GLX root change callback
|
||||
if (BKEND_GLX == ps->o.backend && !ps->o.experimental_backends) {
|
||||
glx_on_root_change(ps);
|
||||
}
|
||||
#endif
|
||||
if (has_root_change) {
|
||||
if (ps->backend_data != NULL) {
|
||||
ps->backend_data->ops->root_change(ps->backend_data, ps);
|
||||
}
|
||||
// Old backend's root_change is not a specific function
|
||||
} else {
|
||||
if (!initialize_backend(ps)) {
|
||||
log_fatal("Failed to re-initialize backend after root "
|
||||
"change, aborting...");
|
||||
ps->quit = true;
|
||||
// TODO only event handlers should request ev_break,
|
||||
// otherwise it's too hard to keep track of what can break
|
||||
// the event loop
|
||||
ev_break(ps->loop, EVBREAK_ALL);
|
||||
return;
|
||||
}
|
||||
|
||||
// Re-acquire the root pixmap.
|
||||
root_damaged(ps);
|
||||
}
|
||||
force_repaint(ps);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void root_damaged(session_t *ps) {
|
||||
if (ps->root_tile_paint.pixmap) {
|
||||
free_root_tile(ps);
|
||||
@@ -1277,7 +1341,6 @@ static bool redirect_start(session_t *ps) {
|
||||
|
||||
// Re-detect driver since we now have a backend
|
||||
ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root);
|
||||
apply_driver_workarounds(ps, ps->drivers);
|
||||
|
||||
root_damaged(ps);
|
||||
|
||||
@@ -1363,6 +1426,12 @@ static void handle_new_windows(session_t *ps) {
|
||||
}
|
||||
|
||||
static void refresh_windows(session_t *ps) {
|
||||
win_stack_foreach_managed_safe(w, &ps->window_stack) {
|
||||
win_process_updates(ps, w);
|
||||
}
|
||||
}
|
||||
|
||||
static void refresh_stale_images(session_t *ps) {
|
||||
win_stack_foreach_managed(w, &ps->window_stack) {
|
||||
win_process_flags(ps, w);
|
||||
}
|
||||
@@ -1399,13 +1468,7 @@ static void handle_pending_updates(EV_P_ struct session *ps) {
|
||||
// Call fill_win on new windows
|
||||
handle_new_windows(ps);
|
||||
|
||||
// Handle screen changes
|
||||
// This HAS TO be called before refresh_windows, as handle_root_flags
|
||||
// could call configure_root, which will release images and mark them
|
||||
// stale.
|
||||
handle_root_flags(ps);
|
||||
|
||||
// Process window flags
|
||||
// Process window updates
|
||||
refresh_windows(ps);
|
||||
|
||||
{
|
||||
@@ -1417,6 +1480,12 @@ static void handle_pending_updates(EV_P_ struct session *ps) {
|
||||
free(r);
|
||||
}
|
||||
|
||||
// Refresh pixmaps and shadows
|
||||
refresh_stale_images(ps);
|
||||
|
||||
// Handle screen changes
|
||||
handle_root_flags(ps);
|
||||
|
||||
e = xcb_request_check(ps->c, xcb_ungrab_server_checked(ps->c));
|
||||
if (e) {
|
||||
log_fatal_x_error(e, "failed to ungrab x server");
|
||||
@@ -1670,9 +1739,11 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||
.randr_exists = 0,
|
||||
.randr_event = 0,
|
||||
.randr_error = 0,
|
||||
#ifdef CONFIG_OPENGL
|
||||
.glx_exists = false,
|
||||
.glx_event = 0,
|
||||
.glx_error = 0,
|
||||
#endif
|
||||
.xrfilter_convolution_exists = false,
|
||||
|
||||
.atoms_wintypes = {0},
|
||||
@@ -1739,7 +1810,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||
xcb_prefetch_extension_data(ps->c, &xcb_xinerama_id);
|
||||
xcb_prefetch_extension_data(ps->c, &xcb_present_id);
|
||||
xcb_prefetch_extension_data(ps->c, &xcb_sync_id);
|
||||
xcb_prefetch_extension_data(ps->c, &xcb_glx_id);
|
||||
|
||||
ext_info = xcb_get_extension_data(ps->c, &xcb_render_id);
|
||||
if (!ext_info || !ext_info->present) {
|
||||
@@ -1795,13 +1865,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||
XCB_XFIXES_MINOR_VERSION)
|
||||
.sequence);
|
||||
|
||||
ext_info = xcb_get_extension_data(ps->c, &xcb_glx_id);
|
||||
if (ext_info && ext_info->present) {
|
||||
ps->glx_exists = true;
|
||||
ps->glx_error = ext_info->first_error;
|
||||
ps->glx_event = ext_info->first_event;
|
||||
}
|
||||
|
||||
// Parse configuration file
|
||||
win_option_mask_t winopt_mask[NUM_WINTYPES] = {{0}};
|
||||
bool shadow_enabled = false, fading_enable = false, hasneg = false;
|
||||
@@ -1869,6 +1932,8 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||
c2_list_postprocess(ps, ps->o.blur_background_blacklist) &&
|
||||
c2_list_postprocess(ps, ps->o.invert_color_list) &&
|
||||
c2_list_postprocess(ps, ps->o.opacity_rules) &&
|
||||
c2_list_postprocess(ps, ps->o.rounded_corners_blacklist) &&
|
||||
c2_list_postprocess(ps, ps->o.round_borders_blacklist) &&
|
||||
c2_list_postprocess(ps, ps->o.focus_blacklist))) {
|
||||
log_error("Post-processing of conditionals failed, some of your rules "
|
||||
"might not work");
|
||||
@@ -1925,24 +1990,23 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||
}
|
||||
|
||||
ps->sync_fence = XCB_NONE;
|
||||
if (ps->xsync_exists) {
|
||||
if (!ps->xsync_exists && ps->o.xrender_sync_fence) {
|
||||
log_error("XSync extension not found. No XSync fence sync is "
|
||||
"possible. (xrender-sync-fence can't be enabled)");
|
||||
ps->o.xrender_sync_fence = false;
|
||||
}
|
||||
|
||||
if (ps->o.xrender_sync_fence) {
|
||||
ps->sync_fence = x_new_id(ps->c);
|
||||
e = xcb_request_check(
|
||||
ps->c, xcb_sync_create_fence(ps->c, ps->root, ps->sync_fence, 0));
|
||||
if (e) {
|
||||
if (ps->o.xrender_sync_fence) {
|
||||
log_error_x_error(e, "Failed to create a XSync fence. "
|
||||
"xrender-sync-fence will be "
|
||||
"disabled");
|
||||
ps->o.xrender_sync_fence = false;
|
||||
}
|
||||
log_error_x_error(e, "Failed to create a XSync fence. "
|
||||
"xrender-sync-fence will be disabled");
|
||||
ps->o.xrender_sync_fence = false;
|
||||
ps->sync_fence = XCB_NONE;
|
||||
free(e);
|
||||
}
|
||||
} else if (ps->o.xrender_sync_fence) {
|
||||
log_error("XSync extension not found. No XSync fence sync is "
|
||||
"possible. (xrender-sync-fence can't be enabled)");
|
||||
ps->o.xrender_sync_fence = false;
|
||||
}
|
||||
|
||||
// Query X RandR
|
||||
@@ -2014,8 +2078,12 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||
}
|
||||
}
|
||||
|
||||
// Target window must be initialized before the backend
|
||||
//
|
||||
// backend_operations::present == NULL means this backend doesn't need a target
|
||||
// window; non experimental backends always need a target window
|
||||
|
||||
ps->drivers = detect_driver(ps->c, ps->backend_data, ps->root);
|
||||
apply_driver_workarounds(ps, ps->drivers);
|
||||
|
||||
// Initialize filters, must be preceded by OpenGL context creation
|
||||
if (!ps->o.experimental_backends && !init_render(ps)) {
|
||||
@@ -2132,7 +2200,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||
e = xcb_request_check(ps->c, xcb_grab_server_checked(ps->c));
|
||||
if (e) {
|
||||
log_fatal_x_error(e, "Failed to grab X server");
|
||||
free(e);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -2151,7 +2218,6 @@ static session_t *session_init(int argc, char **argv, Display *dpy,
|
||||
if (e) {
|
||||
log_fatal_x_error(e, "Failed to ungrab server");
|
||||
free(e);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ps->server_grabbed = false;
|
||||
@@ -2241,6 +2307,8 @@ static void session_destroy(session_t *ps) {
|
||||
free_wincondlst(&ps->o.opacity_rules);
|
||||
free_wincondlst(&ps->o.paint_blacklist);
|
||||
free_wincondlst(&ps->o.unredir_if_possible_blacklist);
|
||||
free_wincondlst(&ps->o.rounded_corners_blacklist);
|
||||
free_wincondlst(&ps->o.round_borders_blacklist);
|
||||
|
||||
// Free tracked atom list
|
||||
{
|
||||
|
||||
11
src/picom.h
11
src/picom.h
@@ -25,11 +25,7 @@
|
||||
#include "win.h"
|
||||
#include "x.h"
|
||||
|
||||
enum root_flags {
|
||||
ROOT_FLAGS_SCREEN_CHANGE = 1, // Received RandR screen change notify, we
|
||||
// use this to track refresh rate changes
|
||||
ROOT_FLAGS_CONFIGURED = 2 // Received configure notify on the root window
|
||||
};
|
||||
enum root_flags { ROOT_FLAGS_SCREEN_CHANGE = 1 };
|
||||
|
||||
// == Functions ==
|
||||
// TODO move static inline functions that are only used in picom.c, into
|
||||
@@ -42,6 +38,11 @@ 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);
|
||||
|
||||
xcb_window_t find_client_win(session_t *ps, xcb_window_t w);
|
||||
|
||||
/// Handle configure event of a root window
|
||||
void configure_root(session_t *ps, int width, int height);
|
||||
|
||||
void circulate_win(session_t *ps, xcb_circulate_notify_event_t *ce);
|
||||
|
||||
void update_refresh_rate(session_t *ps);
|
||||
|
||||
302
src/render.c
302
src/render.c
@@ -48,14 +48,15 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h
|
||||
bool repeat, int depth, xcb_visualid_t visual, bool force) {
|
||||
#ifdef CONFIG_OPENGL
|
||||
// XXX This is a mess. But this will go away after the backend refactor.
|
||||
static thread_local struct glx_fbconfig_info *argb_fbconfig = NULL;
|
||||
if (!ppaint->pixmap)
|
||||
return false;
|
||||
|
||||
struct glx_fbconfig_info *fbcfg;
|
||||
if (!visual) {
|
||||
assert(depth == 32);
|
||||
if (!ps->argb_fbconfig) {
|
||||
ps->argb_fbconfig =
|
||||
if (!argb_fbconfig) {
|
||||
argb_fbconfig =
|
||||
glx_find_fbconfig(ps->dpy, ps->scr,
|
||||
(struct xvisual_info){.red_size = 8,
|
||||
.green_size = 8,
|
||||
@@ -63,11 +64,11 @@ static inline bool paint_bind_tex(session_t *ps, paint_t *ppaint, int wid, int h
|
||||
.alpha_size = 8,
|
||||
.visual_depth = 32});
|
||||
}
|
||||
if (!ps->argb_fbconfig) {
|
||||
if (!argb_fbconfig) {
|
||||
log_error("Failed to find appropriate FBConfig for 32 bit depth");
|
||||
return false;
|
||||
}
|
||||
fbcfg = ps->argb_fbconfig;
|
||||
fbcfg = argb_fbconfig;
|
||||
} else {
|
||||
auto m = x_get_visual_info(ps->c, visual);
|
||||
if (m.visual_depth < 0) {
|
||||
@@ -185,28 +186,139 @@ void free_paint(session_t *ps, paint_t *ppaint) {
|
||||
ppaint->pixmap = XCB_NONE;
|
||||
}
|
||||
|
||||
void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, double opacity,
|
||||
bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex,
|
||||
const region_t *reg_paint, const glx_prog_main_t *pprogram) {
|
||||
uint32_t
|
||||
make_circle(int cx, int cy, int radius, uint32_t max_ntraps, xcb_render_trapezoid_t traps[]) {
|
||||
uint32_t n = 0, k = 0;
|
||||
int y1, y2;
|
||||
double w;
|
||||
while (k < max_ntraps) {
|
||||
y1 = (int)(-radius * cos(M_PI * k / max_ntraps));
|
||||
traps[n].top = (cy + y1) << 16;
|
||||
traps[n].left.p1.y = (cy + y1) << 16;
|
||||
traps[n].right.p1.y = (cy + y1) << 16;
|
||||
w = sqrt(radius * radius - y1 * y1) * 65536;
|
||||
traps[n].left.p1.x = (int)((cx << 16) - w);
|
||||
traps[n].right.p1.x = (int)((cx << 16) + w);
|
||||
|
||||
do {
|
||||
k++;
|
||||
y2 = (int)(-radius * cos(M_PI * k / max_ntraps));
|
||||
} while (y1 == y2);
|
||||
|
||||
traps[n].bottom = (cy + y2) << 16;
|
||||
traps[n].left.p2.y = (cy + y2) << 16;
|
||||
traps[n].right.p2.y = (cy + y2) << 16;
|
||||
w = sqrt(radius * radius - y2 * y2) * 65536;
|
||||
traps[n].left.p2.x = (int)((cx << 16) - w);
|
||||
traps[n].right.p2.x = (int)((cx << 16) + w);
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
uint32_t make_rectangle(int x, int y, int wid, int hei, xcb_render_trapezoid_t traps[]) {
|
||||
traps[0].top = y << 16;
|
||||
traps[0].left.p1.y = y << 16;
|
||||
traps[0].left.p1.x = x << 16;
|
||||
traps[0].left.p2.y = (y + hei) << 16;
|
||||
traps[0].left.p2.x = x << 16;
|
||||
traps[0].bottom = (y + hei) << 16;
|
||||
traps[0].right.p1.x = (x + wid) << 16;
|
||||
traps[0].right.p1.y = y << 16;
|
||||
traps[0].right.p2.x = (x + wid) << 16;
|
||||
traps[0].right.p2.y = (y + hei) << 16;
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t make_rounded_window_shape(xcb_render_trapezoid_t traps[], uint32_t max_ntraps, int cr, int wid, int hei)
|
||||
{
|
||||
uint32_t n = make_circle(cr, cr, cr, max_ntraps, traps);
|
||||
n += make_circle(wid - cr, cr, cr, max_ntraps, traps + n);
|
||||
n += make_circle(wid - cr, hei - cr, cr, max_ntraps, traps + n);
|
||||
n += make_circle(cr, hei - cr, cr, max_ntraps, traps + n);
|
||||
n += make_rectangle(0, cr, cr, hei - 2 * cr, traps + n);
|
||||
n += make_rectangle(cr, 0, wid - 2 * cr, cr, traps + n);
|
||||
n += make_rectangle(wid - cr, cr, cr, hei - 2 * cr, traps + n);
|
||||
n += make_rectangle(cr, hei - cr, wid - 2 * cr, cr, traps + n);
|
||||
n += make_rectangle(cr, cr, wid - 2 * cr, hei - 2 * cr,
|
||||
traps + n);
|
||||
return n;
|
||||
}
|
||||
|
||||
void render(session_t *ps, struct managed_win *w attr_unused, int x, int y,
|
||||
int dx, int dy, int wid, int hei, int fullwid, int fullhei, double opacity,
|
||||
bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex,
|
||||
const region_t *reg_paint, const glx_prog_main_t *pprogram, clip_t *clip) {
|
||||
switch (ps->o.backend) {
|
||||
case BKEND_XRENDER:
|
||||
case BKEND_XR_GLX_HYBRID: {
|
||||
auto alpha_step = (int)(opacity * MAX_ALPHA);
|
||||
xcb_render_picture_t alpha_pict = ps->alpha_picts[alpha_step];
|
||||
if (alpha_step != 0) {
|
||||
uint8_t op = ((!argb && !alpha_pict) ? XCB_RENDER_PICT_OP_SRC
|
||||
if (cr) {
|
||||
//log_warn("f(%d, %d) wh(%d %d) xy(%d %d) dxy(%d %d)", fullwid, fullhei, wid, hei, x, y, dx, dy);
|
||||
xcb_render_picture_t p_tmp = x_create_picture_with_standard(
|
||||
ps->c, ps->root, fullwid, fullhei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
|
||||
xcb_render_color_t trans = {
|
||||
.red = 0, .blue = 0, .green = 0, .alpha = 0};
|
||||
const xcb_rectangle_t rect = {.x = 0,
|
||||
.y = 0,
|
||||
.width = to_u16_checked(fullwid),
|
||||
.height = to_u16_checked(fullhei)};
|
||||
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC,
|
||||
p_tmp, trans, 1, &rect);
|
||||
|
||||
uint32_t max_ntraps = to_u32_checked(cr);
|
||||
xcb_render_trapezoid_t traps[4 * max_ntraps + 5];
|
||||
|
||||
uint32_t n = make_rounded_window_shape(traps, max_ntraps, cr, fullwid, fullhei);
|
||||
|
||||
xcb_render_trapezoids(
|
||||
ps->c, XCB_RENDER_PICT_OP_OVER, alpha_pict, p_tmp,
|
||||
x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8),
|
||||
0, 0, n, traps);
|
||||
|
||||
xcb_render_composite(
|
||||
ps->c, XCB_RENDER_PICT_OP_OVER, pict, p_tmp,
|
||||
ps->tgt_buffer.pict, to_i16_checked(x), to_i16_checked(y),
|
||||
to_i16_checked(x), to_i16_checked(y), to_i16_checked(dx), to_i16_checked(dy),
|
||||
to_u16_checked(wid), to_u16_checked(hei));
|
||||
|
||||
xcb_render_free_picture(ps->c, p_tmp);
|
||||
|
||||
} else {
|
||||
|
||||
xcb_render_picture_t p_tmp = alpha_pict;
|
||||
if(clip){
|
||||
p_tmp = x_create_picture_with_standard(ps->c, ps->root, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
|
||||
|
||||
xcb_render_color_t black = {.red = 255, .blue = 255, .green = 255, .alpha = 255};
|
||||
const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(wid), .height = to_u16_checked(hei)};
|
||||
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, p_tmp, black, 1, &rect);
|
||||
if(alpha_pict) {
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, alpha_pict, XCB_NONE, p_tmp, 0, 0, 0, 0, 0, 0, to_u16_checked(wid), to_u16_checked(hei));
|
||||
}
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OUT_REVERSE, clip->pict, XCB_NONE, p_tmp, 0, 0, 0, 0, to_i16_checked(clip->x), to_i16_checked(clip->y), to_u16_checked(wid), to_u16_checked(hei));
|
||||
}
|
||||
|
||||
uint8_t op = ((!argb && !alpha_pict && !clip) ? XCB_RENDER_PICT_OP_SRC
|
||||
: XCB_RENDER_PICT_OP_OVER);
|
||||
xcb_render_composite(
|
||||
ps->c, op, pict, alpha_pict, ps->tgt_buffer.pict,
|
||||
to_i16_checked(x), to_i16_checked(y), 0, 0, to_i16_checked(dx),
|
||||
to_i16_checked(dy), to_u16_checked(wid), to_u16_checked(hei));
|
||||
xcb_render_composite(
|
||||
ps->c, op, pict, p_tmp/*alpha_pict*/, ps->tgt_buffer.pict,
|
||||
to_i16_checked(x), to_i16_checked(y), 0, 0, to_i16_checked(dx),
|
||||
to_i16_checked(dy), to_u16_checked(wid), to_u16_checked(hei));
|
||||
|
||||
if(clip){
|
||||
xcb_render_free_picture(ps->c, p_tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_OPENGL
|
||||
case BKEND_GLX:
|
||||
glx_render(ps, ptex, x, y, dx, dy, wid, hei, ps->psglx->z, opacity, argb,
|
||||
neg, reg_paint, pprogram);
|
||||
glx_render(ps, w, ptex, x, y, dx, dy, wid, hei, ps->psglx->z, opacity, argb,
|
||||
neg, cr, reg_paint, pprogram);
|
||||
ps->psglx->z += 1;
|
||||
break;
|
||||
#endif
|
||||
@@ -221,21 +333,24 @@ void render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei, doubl
|
||||
}
|
||||
|
||||
static inline void
|
||||
paint_region(session_t *ps, const struct managed_win *w, int x, int y, int wid, int hei,
|
||||
paint_region(session_t *ps, struct managed_win *w, int x, int y, int wid, int hei,
|
||||
double opacity, const region_t *reg_paint, xcb_render_picture_t pict) {
|
||||
const int dx = (w ? w->g.x : 0) + x;
|
||||
const int dy = (w ? w->g.y : 0) + y;
|
||||
const int fullwid = w ? w->widthb : 0;
|
||||
const int fullhei = w ? w-> heightb : 0;
|
||||
const bool argb = (w && (win_has_alpha(w) || ps->o.force_win_blend));
|
||||
const bool neg = (w && w->invert_color);
|
||||
|
||||
render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, pict,
|
||||
(w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint,
|
||||
render(ps, w, x, y, dx, dy, wid, hei, fullwid, fullhei, opacity, argb, neg,
|
||||
(w ? w->corner_radius : 0),
|
||||
pict, (w ? w->paint.ptex : ps->root_tile_paint.ptex), reg_paint,
|
||||
#ifdef CONFIG_OPENGL
|
||||
w ? &ps->glx_prog_win : NULL
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
);
|
||||
, XCB_NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,6 +373,46 @@ static inline bool paint_isvalid(session_t *ps, const paint_t *ppaint) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounde the corners of a window.
|
||||
* Applies a fragment shader to discard corners
|
||||
*
|
||||
*/
|
||||
static inline void
|
||||
win_round_corners(session_t *ps, struct managed_win *w attr_unused, int shader_idx attr_unused, float cr attr_unused,
|
||||
xcb_render_picture_t tgt_buffer attr_unused, const region_t *reg_paint) {
|
||||
#ifdef CONFIG_OPENGL
|
||||
const int16_t x = w->g.x;
|
||||
const int16_t y = w->g.y;
|
||||
const auto wid = to_u16_checked(w->widthb);
|
||||
const auto hei = to_u16_checked(w->heightb);
|
||||
#endif
|
||||
|
||||
//log_debug("x:%d y:%d w:%d h:%d", x, y, wid, hei);
|
||||
|
||||
switch (ps->o.backend) {
|
||||
case BKEND_XRENDER:
|
||||
case BKEND_XR_GLX_HYBRID: {
|
||||
// XRender method is implemented inside render()
|
||||
} break;
|
||||
#ifdef CONFIG_OPENGL
|
||||
case BKEND_GLX:
|
||||
if (shader_idx == 1) {
|
||||
glx_round_corners_dst1(ps, w, w->glx_texture_bg, shader_idx, x, y, wid, hei,
|
||||
(float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache);
|
||||
} else {
|
||||
glx_round_corners_dst0(ps, w, w->glx_texture_bg, shader_idx, x, y, wid, hei,
|
||||
(float)ps->psglx->z - 0.5f, cr, reg_paint, &w->glx_round_cache);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default: assert(0);
|
||||
}
|
||||
#ifndef CONFIG_OPENGL
|
||||
(void)reg_paint;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint a window itself and dim it if asked.
|
||||
*/
|
||||
@@ -529,8 +684,8 @@ static void paint_root(session_t *ps, const region_t *reg_paint) {
|
||||
* Generate shadow <code>Picture</code> for a window.
|
||||
*/
|
||||
static bool win_build_shadow(session_t *ps, struct managed_win *w, double opacity) {
|
||||
/* const int width = w->widthb; */
|
||||
/* const int height = w->heightb; */
|
||||
//const int width = w->widthb;
|
||||
//const int height = w->heightb;
|
||||
const int width = w->newW; // TODO!
|
||||
const int height = w->newH;
|
||||
// log_trace("(): building shadow for %s %d %d", w->name, width, height);
|
||||
@@ -613,9 +768,29 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) {
|
||||
return;
|
||||
}
|
||||
|
||||
render(ps, 0, 0, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width,
|
||||
w->shadow_height, w->shadow_opacity, true, false, w->shadow_paint.pict,
|
||||
w->shadow_paint.ptex, reg_paint, NULL);
|
||||
xcb_render_picture_t td = XCB_NONE;
|
||||
if (w->corner_radius) {
|
||||
uint32_t max_ntraps = to_u32_checked(w->corner_radius);
|
||||
xcb_render_trapezoid_t traps[4 * max_ntraps + 5];
|
||||
uint32_t n = make_rounded_window_shape(traps, max_ntraps, w->corner_radius, w->widthb, w->heightb);
|
||||
|
||||
td = x_create_picture_with_standard(ps->c, ps->root, w->widthb, w->heightb, XCB_PICT_STANDARD_ARGB_32, 0, 0);
|
||||
xcb_render_color_t trans = {.red = 0, .blue = 0, .green = 0, .alpha = 0};
|
||||
const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(w->widthb), .height = to_u16_checked(w->heightb)};
|
||||
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, trans, 1, &rect);
|
||||
|
||||
xcb_render_trapezoids(ps->c, XCB_RENDER_PICT_OP_OVER, solid_picture(ps->c, ps->root, false, 1, 0, 0, 0), td, x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps);
|
||||
}
|
||||
|
||||
clip_t clip = { .pict = td, -(w->shadow_dx), .y = -(w->shadow_dy) };
|
||||
|
||||
render(ps, w, 0, 0, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width,
|
||||
w->shadow_height, w->widthb, w->heightb, w->shadow_opacity, true, false, 0, w->shadow_paint.pict,
|
||||
w->shadow_paint.ptex, reg_paint, NULL, w->corner_radius ? &clip : NULL);
|
||||
|
||||
if(td){
|
||||
xcb_render_free_picture(ps->c, td);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -635,7 +810,7 @@ win_paint_shadow(session_t *ps, struct managed_win *w, region_t *reg_paint) {
|
||||
*/
|
||||
static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t x, int16_t y,
|
||||
uint16_t wid, uint16_t hei, struct x_convolution_kernel **blur_kerns,
|
||||
int nkernels, const region_t *reg_clip) {
|
||||
int nkernels, const region_t *reg_clip, xcb_render_picture_t rounded) {
|
||||
assert(blur_kerns);
|
||||
assert(blur_kerns[0]);
|
||||
|
||||
@@ -680,7 +855,8 @@ static bool xr_blur_dst(session_t *ps, xcb_render_picture_t tgt_buffer, int16_t
|
||||
}
|
||||
|
||||
if (src_pict != tgt_buffer)
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, src_pict, XCB_NONE,
|
||||
//xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_SRC, src_pict, rounded,
|
||||
xcb_render_composite(ps->c, XCB_RENDER_PICT_OP_OVER, src_pict, rounded,
|
||||
tgt_buffer, 0, 0, 0, 0, x, y, wid, hei);
|
||||
|
||||
free_picture(ps->c, &tmp_picture);
|
||||
@@ -698,6 +874,7 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
|
||||
const int16_t y = w->g.y;
|
||||
const auto wid = to_u16_checked(w->widthb);
|
||||
const auto hei = to_u16_checked(w->heightb);
|
||||
const int cr = (w ? w->corner_radius : 0);
|
||||
|
||||
double factor_center = 1.0;
|
||||
// Adjust blur strength according to window opacity, to make it appear
|
||||
@@ -729,13 +906,27 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
|
||||
&ps->blur_kerns_cache[i]);
|
||||
}
|
||||
|
||||
xcb_render_picture_t td = XCB_NONE;
|
||||
if (cr) {
|
||||
uint32_t max_ntraps = to_u32_checked(cr);
|
||||
xcb_render_trapezoid_t traps[4 * max_ntraps + 5];
|
||||
uint32_t n = make_rounded_window_shape(traps, max_ntraps, cr, wid, hei);
|
||||
|
||||
td = x_create_picture_with_standard(ps->c, ps->root, wid, hei, XCB_PICT_STANDARD_ARGB_32, 0, 0);
|
||||
xcb_render_color_t trans = {.red = 0, .blue = 0, .green = 0, .alpha = 0};
|
||||
const xcb_rectangle_t rect = {.x = 0, .y = 0, .width = to_u16_checked(wid), .height = to_u16_checked(hei)};
|
||||
xcb_render_fill_rectangles(ps->c, XCB_RENDER_PICT_OP_SRC, td, trans, 1, &rect);
|
||||
|
||||
xcb_render_trapezoids(ps->c, XCB_RENDER_PICT_OP_OVER, solid_picture(ps->c, ps->root, false, 1, 0, 0, 0), td, x_get_pictfmt_for_standard(ps->c, XCB_PICT_STANDARD_A_8), 0, 0, n, traps);
|
||||
}
|
||||
|
||||
// Minimize the region we try to blur, if the window itself is not
|
||||
// opaque, only the frame is.
|
||||
region_t reg_blur = win_get_bounding_shape_global_by_val(w);
|
||||
region_t reg_blur = win_get_bounding_shape_global_by_val(w, true);
|
||||
if (w->mode == WMODE_FRAME_TRANS && !ps->o.force_win_blend) {
|
||||
region_t reg_noframe;
|
||||
pixman_region32_init(®_noframe);
|
||||
win_get_region_noframe_local(w, ®_noframe);
|
||||
win_get_region_noframe_local(w, ®_noframe, true);
|
||||
pixman_region32_translate(®_noframe, w->g.x, w->g.y);
|
||||
pixman_region32_subtract(®_blur, ®_blur, ®_noframe);
|
||||
pixman_region32_fini(®_noframe);
|
||||
@@ -743,14 +934,14 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
|
||||
// Translate global coordinates to local ones
|
||||
pixman_region32_translate(®_blur, -x, -y);
|
||||
xr_blur_dst(ps, tgt_buffer, x, y, wid, hei, ps->blur_kerns_cache,
|
||||
ps->o.blur_kernel_count, ®_blur);
|
||||
ps->o.blur_kernel_count, ®_blur, td);
|
||||
pixman_region32_clear(®_blur);
|
||||
} break;
|
||||
#ifdef CONFIG_OPENGL
|
||||
case BKEND_GLX:
|
||||
// TODO: Handle frame opacity
|
||||
glx_blur_dst(ps, x, y, wid, hei, (float)ps->psglx->z - 0.5f,
|
||||
(float)factor_center, reg_paint, &w->glx_blur_cache);
|
||||
(float)w->opacity, reg_paint, &w->glx_blur_cache);
|
||||
break;
|
||||
#endif
|
||||
default: assert(0);
|
||||
@@ -852,7 +1043,9 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
//
|
||||
// Whether this is beneficial is to be determined XXX
|
||||
for (auto w = t; w; w = w->prev_trans) {
|
||||
region_t bshape = win_get_bounding_shape_global_by_val(w);
|
||||
region_t bshape_no_corners = win_get_bounding_shape_global_by_val(w, false);
|
||||
region_t bshape_corners = win_get_bounding_shape_global_by_val(w, true);
|
||||
|
||||
// Painting shadow
|
||||
if (w->shadow) {
|
||||
// Lazy shadow building
|
||||
@@ -881,7 +1074,7 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
// saving GPU power and handling shaped windows (XXX
|
||||
// unconfirmed)
|
||||
if (!ps->o.wintype_option[w->window_type].full_shadow)
|
||||
pixman_region32_subtract(®_tmp, ®_tmp, &bshape);
|
||||
pixman_region32_subtract(®_tmp, ®_tmp, &bshape_no_corners);
|
||||
|
||||
if (ps->o.xinerama_shadow_crop && w->xinerama_scr >= 0 &&
|
||||
w->xinerama_scr < ps->xinerama_nscrs)
|
||||
@@ -908,12 +1101,25 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
// Remember, reg_ignore is the union of all windows above the current
|
||||
// window.
|
||||
pixman_region32_subtract(®_tmp, ®ion, w->reg_ignore);
|
||||
pixman_region32_intersect(®_tmp, ®_tmp, &bshape);
|
||||
pixman_region32_fini(&bshape);
|
||||
pixman_region32_intersect(®_tmp, ®_tmp, &bshape_corners);
|
||||
pixman_region32_fini(&bshape_corners);
|
||||
pixman_region32_fini(&bshape_no_corners);
|
||||
|
||||
reg_tmp = region;
|
||||
if (pixman_region32_not_empty(®_tmp) || true) {
|
||||
set_tgt_clip(ps, ®_tmp);
|
||||
|
||||
// If rounded corners backup the region first
|
||||
#ifdef CONFIG_OPENGL
|
||||
if (w->corner_radius > 0) {
|
||||
const int16_t x = w->g.x;
|
||||
const int16_t y = w->g.y;
|
||||
const auto wid = to_u16_checked(w->widthb);
|
||||
const auto hei = to_u16_checked(w->heightb);
|
||||
glx_bind_texture(ps, &w->glx_texture_bg, x, y, wid, hei, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Blur window background
|
||||
if (w->blur_background &&
|
||||
(w->mode == WMODE_TRANS ||
|
||||
@@ -923,6 +1129,12 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
|
||||
// Painting the window
|
||||
paint_one(ps, w, ®_tmp);
|
||||
|
||||
// Round window corners
|
||||
if (w->corner_radius > 0) {
|
||||
win_round_corners(ps, w, 1, (float)w->corner_radius,
|
||||
ps->tgt_buffer.pict, ®_tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1011,8 +1223,8 @@ void paint_all(session_t *ps, struct managed_win *t, bool ignore_damage) {
|
||||
else
|
||||
glFlush();
|
||||
glXWaitX();
|
||||
glx_render(ps, ps->tgt_buffer.ptex, 0, 0, 0, 0, ps->root_width,
|
||||
ps->root_height, 0, 1.0, false, false, ®ion, NULL);
|
||||
glx_render(ps, t, ps->tgt_buffer.ptex, 0, 0, 0, 0, ps->root_width,
|
||||
ps->root_height, 0, 1.0, false, false, 0, ®ion, NULL);
|
||||
// falls through
|
||||
case BKEND_GLX: glXSwapBuffers(ps->dpy, get_tgt_window(ps)); break;
|
||||
#endif
|
||||
@@ -1131,13 +1343,15 @@ bool init_render(session_t *ps) {
|
||||
}
|
||||
|
||||
// Blur filter
|
||||
if (ps->o.blur_method && ps->o.blur_method != BLUR_METHOD_KERNEL) {
|
||||
log_warn("Old backends only support blur method \"kernel\". Your blur "
|
||||
if (ps->o.blur_method && ps->o.blur_method != BLUR_METHOD_KERNEL &&
|
||||
ps->o.blur_method != BLUR_METHOD_DUAL_KAWASE && ps->o.blur_method != BLUR_METHOD_ALT_KAWASE) {
|
||||
log_warn("Old backends only support blur methods \"kernel|kawase\". Your blur "
|
||||
"setting will not be applied");
|
||||
ps->o.blur_method = BLUR_METHOD_NONE;
|
||||
}
|
||||
|
||||
if (ps->o.blur_method == BLUR_METHOD_KERNEL) {
|
||||
if (ps->o.blur_method == BLUR_METHOD_KERNEL || ps->o.blur_method == BLUR_METHOD_DUAL_KAWASE
|
||||
|| ps->o.blur_method == BLUR_METHOD_ALT_KAWASE) {
|
||||
ps->blur_kerns_cache =
|
||||
ccalloc(ps->o.blur_kernel_count, struct x_convolution_kernel *);
|
||||
|
||||
@@ -1176,6 +1390,18 @@ bool init_render(session_t *ps) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize our rounded corners fragment shader
|
||||
if (ps->o.corner_radius > 0 && ps->o.backend == BKEND_GLX) {
|
||||
#ifdef CONFIG_OPENGL
|
||||
if (!glx_init_rounded_corners(ps)) {
|
||||
log_error("Failed to init rounded corners shader.");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
assert(false);
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
12
src/render.h
12
src/render.h
@@ -25,9 +25,15 @@ typedef struct paint {
|
||||
#endif
|
||||
} paint_t;
|
||||
|
||||
void render(session_t *ps, int x, int y, int dx, int dy, int w, int h, double opacity,
|
||||
bool argb, bool neg, xcb_render_picture_t pict, glx_texture_t *ptex,
|
||||
const region_t *reg_paint, const glx_prog_main_t *pprogram);
|
||||
typedef struct clip {
|
||||
xcb_render_picture_t pict;
|
||||
int x;
|
||||
int y;
|
||||
} clip_t;
|
||||
|
||||
void render(session_t *ps, struct managed_win *, int x, int y, int dx, int dy, int w, int h, int fullw, int fullh, double opacity,
|
||||
bool argb, bool neg, int cr, xcb_render_picture_t pict, glx_texture_t *ptex,
|
||||
const region_t *reg_paint, const glx_prog_main_t *pprogram, clip_t *clip);
|
||||
void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint);
|
||||
|
||||
void paint_all(session_t *ps, struct managed_win *const t, bool ignore_damage);
|
||||
|
||||
@@ -33,6 +33,9 @@ safe_isnan(double a) {
|
||||
return __builtin_isnan(a);
|
||||
}
|
||||
|
||||
#define CASESTRRET(s) \
|
||||
case s: return #s
|
||||
|
||||
/// Same as assert(false), but make sure we abort _even in release builds_.
|
||||
/// Silence compiler warning caused by release builds making some code paths reachable.
|
||||
#define BUG() \
|
||||
|
||||
364
src/win.c
364
src/win.c
@@ -46,6 +46,9 @@
|
||||
// TODO Make more window states internal
|
||||
struct managed_win_internal {
|
||||
struct managed_win base;
|
||||
|
||||
/// A bit mask of unhandled window updates
|
||||
uint_fast32_t pending_updates;
|
||||
};
|
||||
|
||||
#define OPAQUE (0xffffffff)
|
||||
@@ -53,6 +56,17 @@ static const int WIN_GET_LEADER_MAX_RECURSION = 20;
|
||||
static const int ROUNDED_PIXELS = 1;
|
||||
static const double ROUNDED_PERCENT = 0.05;
|
||||
|
||||
/// Generate a "return by value" function, from a function that returns the
|
||||
/// region via a region_t pointer argument.
|
||||
/// Function signature has to be (win *, region_t *, bool)
|
||||
#define gen_by_val_corners(fun) \
|
||||
region_t fun##_by_val(const struct managed_win *w, bool include_corners) { \
|
||||
region_t ret; \
|
||||
pixman_region32_init(&ret); \
|
||||
fun(w, &ret, include_corners); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
/// Generate a "return by value" function, from a function that returns the
|
||||
/// region via a region_t pointer argument.
|
||||
/// Function signature has to be (win *, region_t *)
|
||||
@@ -109,6 +123,19 @@ static void win_update_focused(session_t *ps, struct managed_win *w) {
|
||||
w->focused = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Always recalculate the window target opacity, since some opacity-related
|
||||
// options depend on the output value of win_is_focused_real() instead of
|
||||
// w->focused
|
||||
auto opacity_target_old = w->opacity_target;
|
||||
w->opacity_target = win_calc_opacity_target(ps, w, false);
|
||||
if (opacity_target_old != w->opacity_target && w->state == WSTATE_MAPPED) {
|
||||
// Only MAPPED can transition to FADING
|
||||
w->state = WSTATE_FADING;
|
||||
if (!ps->redirected) {
|
||||
CHECK(!win_skip_fading(ps, w));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,16 +197,18 @@ static inline bool group_is_focused(session_t *ps, xcb_window_t leader) {
|
||||
/**
|
||||
* Get a rectangular region a window occupies, excluding shadow.
|
||||
*/
|
||||
static void win_get_region_local(const struct managed_win *w, region_t *res) {
|
||||
static void win_get_region_local(const struct managed_win *w, region_t *res, bool include_corners) {
|
||||
assert(w->widthb >= 0 && w->heightb >= 0);
|
||||
pixman_region32_fini(res);
|
||||
pixman_region32_init_rect(res, 0, 0, (uint)w->widthb, (uint)w->heightb);
|
||||
|
||||
if(!include_corners) win_region_remove_corners(w, res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a rectangular region a window occupies, excluding frame and shadow.
|
||||
*/
|
||||
void win_get_region_noframe_local(const struct managed_win *w, region_t *res) {
|
||||
void win_get_region_noframe_local(const struct managed_win *w, region_t *res, bool include_corners) {
|
||||
const margin_t extents = win_calc_frame_extents(w);
|
||||
|
||||
int x = extents.left;
|
||||
@@ -190,10 +219,11 @@ void win_get_region_noframe_local(const struct managed_win *w, region_t *res) {
|
||||
pixman_region32_fini(res);
|
||||
if (width > 0 && height > 0) {
|
||||
pixman_region32_init_rect(res, x, y, (uint)width, (uint)height);
|
||||
if(!include_corners) win_region_remove_corners(w, res);
|
||||
}
|
||||
}
|
||||
|
||||
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, bool include_corners) {
|
||||
const margin_t extents = win_calc_frame_extents(w);
|
||||
auto outer_width = extents.left + extents.right + w->g.width;
|
||||
auto outer_height = extents.top + extents.bottom + w->g.height;
|
||||
@@ -216,10 +246,11 @@ void win_get_region_frame_local(const struct managed_win *w, region_t *res) {
|
||||
region_t reg_win;
|
||||
pixman_region32_init_rects(®_win, (rect_t[]){0, 0, outer_width, outer_height}, 1);
|
||||
pixman_region32_intersect(res, ®_win, res);
|
||||
if(!include_corners) win_region_remove_corners(w, res);
|
||||
pixman_region32_fini(®_win);
|
||||
}
|
||||
|
||||
gen_by_val(win_get_region_frame_local);
|
||||
gen_by_val_corners(win_get_region_frame_local);
|
||||
|
||||
/**
|
||||
* Add a window to damaged area.
|
||||
@@ -244,7 +275,6 @@ static inline void win_release_pixmap(backend_t *base, struct managed_win *w) {
|
||||
if (w->win_image) {
|
||||
base->ops->release_image(base, w->win_image);
|
||||
w->win_image = NULL;
|
||||
// Bypassing win_set_flags, because `w` might have been destroyed
|
||||
w->flags |= WIN_FLAGS_PIXMAP_NONE;
|
||||
}
|
||||
}
|
||||
@@ -254,7 +284,6 @@ static inline void win_release_shadow(backend_t *base, struct managed_win *w) {
|
||||
if (w->shadow_image) {
|
||||
base->ops->release_image(base, w->shadow_image);
|
||||
w->shadow_image = NULL;
|
||||
// Bypassing win_set_flags, because `w` might have been destroyed
|
||||
w->flags |= WIN_FLAGS_SHADOW_NONE;
|
||||
}
|
||||
}
|
||||
@@ -275,11 +304,11 @@ static inline bool win_bind_pixmap(struct backend_base *b, struct managed_win *w
|
||||
b->ops->bind_pixmap(b, pixmap, x_get_visual_info(b->c, w->a.visual), true);
|
||||
if (!w->win_image) {
|
||||
log_error("Failed to bind pixmap");
|
||||
win_set_flags(w, WIN_FLAGS_IMAGE_ERROR);
|
||||
w->flags |= WIN_FLAGS_IMAGE_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
win_clear_flags(w, WIN_FLAGS_PIXMAP_NONE);
|
||||
w->flags &= ~WIN_FLAGS_PIXMAP_NONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -293,13 +322,13 @@ bool win_bind_shadow(struct backend_base *b, struct managed_win *w, struct color
|
||||
log_error("Failed to bind shadow image, shadow will be disabled for "
|
||||
"%#010x (%s)",
|
||||
w->base.id, w->name);
|
||||
win_set_flags(w, WIN_FLAGS_SHADOW_NONE);
|
||||
w->flags |= WIN_FLAGS_SHADOW_NONE;
|
||||
w->shadow = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
log_debug("New shadow for %#010x (%s)", w->base.id, w->name);
|
||||
win_clear_flags(w, WIN_FLAGS_SHADOW_NONE);
|
||||
w->flags &= ~WIN_FLAGS_SHADOW_NONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -309,38 +338,40 @@ void win_release_images(struct backend_base *backend, struct managed_win *w) {
|
||||
// But if we are not releasing any images anyway, we don't care about the stale
|
||||
// flags.
|
||||
|
||||
if (!win_check_flags_all(w, WIN_FLAGS_PIXMAP_NONE)) {
|
||||
assert(!win_check_flags_all(w, WIN_FLAGS_PIXMAP_STALE));
|
||||
if ((w->flags & WIN_FLAGS_PIXMAP_NONE) == 0) {
|
||||
assert((w->flags & WIN_FLAGS_PIXMAP_STALE) == 0);
|
||||
win_release_pixmap(backend, w);
|
||||
}
|
||||
|
||||
if (!win_check_flags_all(w, WIN_FLAGS_SHADOW_NONE)) {
|
||||
assert(!win_check_flags_all(w, WIN_FLAGS_SHADOW_STALE));
|
||||
if ((w->flags & WIN_FLAGS_SHADOW_NONE) == 0) {
|
||||
assert((w->flags & WIN_FLAGS_SHADOW_STALE) == 0);
|
||||
win_release_shadow(backend, w);
|
||||
}
|
||||
}
|
||||
|
||||
void win_process_flags(session_t *ps, struct managed_win *w) {
|
||||
if (win_check_flags_all(w, WIN_FLAGS_MAPPED)) {
|
||||
map_win_start(ps, w);
|
||||
win_clear_flags(w, WIN_FLAGS_MAPPED);
|
||||
// Make sure all pending window updates are processed before this. Making this
|
||||
// assumption simplifies some checks (e.g. whether window is mapped)
|
||||
assert(((struct managed_win_internal *)w)->pending_updates == 0);
|
||||
|
||||
if (!w->flags || (w->flags & WIN_FLAGS_IMAGE_ERROR) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Not a loop
|
||||
while (win_check_flags_any(w, WIN_FLAGS_IMAGES_STALE) &&
|
||||
!win_check_flags_all(w, WIN_FLAGS_IMAGE_ERROR)) {
|
||||
while ((w->flags & WIN_FLAGS_IMAGES_STALE) != 0) {
|
||||
// Image needs to be updated, update it.
|
||||
if (!ps->backend_data) {
|
||||
// We are using legacy backend, nothing to do here.
|
||||
break;
|
||||
}
|
||||
|
||||
if (win_check_flags_all(w, WIN_FLAGS_PIXMAP_STALE)) {
|
||||
if ((w->flags & WIN_FLAGS_PIXMAP_STALE) != 0) {
|
||||
// Check to make sure the window is still mapped, otherwise we
|
||||
// won't be able to rebind pixmap after releasing it, yet we might
|
||||
// still need the pixmap for rendering.
|
||||
assert(w->state != WSTATE_UNMAPPING && w->state != WSTATE_DESTROYING);
|
||||
if (!win_check_flags_all(w, WIN_FLAGS_PIXMAP_NONE)) {
|
||||
if ((w->flags & WIN_FLAGS_PIXMAP_NONE) == 0) {
|
||||
// Must release images first, otherwise breaks
|
||||
// NVIDIA driver
|
||||
win_release_pixmap(ps->backend_data, w);
|
||||
@@ -348,8 +379,8 @@ void win_process_flags(session_t *ps, struct managed_win *w) {
|
||||
win_bind_pixmap(ps->backend_data, w);
|
||||
}
|
||||
|
||||
if (win_check_flags_all(w, WIN_FLAGS_SHADOW_STALE)) {
|
||||
if (!win_check_flags_all(w, WIN_FLAGS_SHADOW_NONE)) {
|
||||
if ((w->flags & WIN_FLAGS_SHADOW_STALE) != 0) {
|
||||
if ((w->flags & WIN_FLAGS_SHADOW_NONE) == 0) {
|
||||
win_release_shadow(ps->backend_data, w);
|
||||
}
|
||||
if (w->shadow) {
|
||||
@@ -367,14 +398,7 @@ void win_process_flags(session_t *ps, struct managed_win *w) {
|
||||
}
|
||||
|
||||
// Clear stale image flags
|
||||
if (win_check_flags_any(w, WIN_FLAGS_IMAGES_STALE)) {
|
||||
win_clear_flags(w, WIN_FLAGS_IMAGES_STALE);
|
||||
}
|
||||
|
||||
if (win_check_flags_all(w, WIN_FLAGS_CLIENT_STALE)) {
|
||||
win_recheck_client(ps, w);
|
||||
win_clear_flags(w, WIN_FLAGS_CLIENT_STALE);
|
||||
}
|
||||
w->flags &= ~WIN_FLAGS_IMAGES_STALE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -542,11 +566,15 @@ bool win_client_has_alpha(const struct managed_win *w) {
|
||||
w->client_pictfmt->direct.alpha_mask;
|
||||
}
|
||||
|
||||
winmode_t win_calc_mode(const struct managed_win *w) {
|
||||
winmode_t win_calc_mode(session_t *ps, const struct managed_win *w) {
|
||||
if (w->opacity < 1.0) {
|
||||
return WMODE_TRANS;
|
||||
}
|
||||
|
||||
if (ps->o.backend == BKEND_GLX && w->corner_radius > 0) {
|
||||
return WMODE_TRANS;
|
||||
}
|
||||
|
||||
if (win_has_alpha(w)) {
|
||||
if (w->client_win == XCB_NONE) {
|
||||
// This is a window not managed by the WM, and it has alpha,
|
||||
@@ -586,17 +614,18 @@ winmode_t win_calc_mode(const struct managed_win *w) {
|
||||
*
|
||||
* @param ps current session
|
||||
* @param w struct _win object representing the window
|
||||
* @param ignore_state whether window state should be ignored in opacity calculation
|
||||
*
|
||||
* @return target opacity
|
||||
*/
|
||||
double win_calc_opacity_target(session_t *ps, const struct managed_win *w) {
|
||||
double win_calc_opacity_target(session_t *ps, const struct managed_win *w, bool ignore_state) {
|
||||
double opacity = 1;
|
||||
|
||||
if (w->state == WSTATE_UNMAPPED) {
|
||||
if (w->state == WSTATE_UNMAPPED && !ignore_state) {
|
||||
// be consistent
|
||||
return 0;
|
||||
}
|
||||
if (w->state == WSTATE_UNMAPPING || w->state == WSTATE_DESTROYING) {
|
||||
if ((w->state == WSTATE_UNMAPPING || w->state == WSTATE_DESTROYING) && !ignore_state) {
|
||||
return 0;
|
||||
}
|
||||
// Try obeying opacity property and window type opacity firstly
|
||||
@@ -697,7 +726,7 @@ static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new
|
||||
w->shadow = shadow_new;
|
||||
assert(!w->shadow_image);
|
||||
assert(!w->win_image);
|
||||
assert(win_check_flags_all(w, WIN_FLAGS_IMAGES_NONE));
|
||||
//assert(w->flags & WIN_FLAGS_IMAGES_NONE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -723,14 +752,14 @@ static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new
|
||||
// asserting the existence of the shadow image.
|
||||
if (w->shadow) {
|
||||
// Mark the new extents as damaged if the shadow is added
|
||||
assert(!w->shadow_image || win_check_flags_all(w, WIN_FLAGS_SHADOW_STALE) ||
|
||||
assert(!w->shadow_image || (w->flags & WIN_FLAGS_SHADOW_STALE) ||
|
||||
!ps->o.experimental_backends);
|
||||
pixman_region32_clear(&extents);
|
||||
win_extents(w, &extents);
|
||||
add_damage_from_win(ps, w);
|
||||
} else {
|
||||
// Mark the old extents as damaged if the shadow is removed
|
||||
assert(w->shadow_image || win_check_flags_all(w, WIN_FLAGS_SHADOW_STALE) ||
|
||||
assert(w->shadow_image || (w->flags & WIN_FLAGS_SHADOW_STALE) ||
|
||||
!ps->o.experimental_backends);
|
||||
add_damage(ps, &extents);
|
||||
}
|
||||
@@ -740,7 +769,7 @@ static void win_set_shadow(session_t *ps, struct managed_win *w, bool shadow_new
|
||||
// Delayed update of shadow image
|
||||
// By setting WIN_FLAGS_SHADOW_STALE, we ask win_process_flags to re-create or
|
||||
// release the shaodw in based on whether w->shadow is set.
|
||||
win_set_flags(w, WIN_FLAGS_SHADOW_STALE);
|
||||
w->flags |= WIN_FLAGS_SHADOW_STALE;
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
|
||||
@@ -878,6 +907,48 @@ static void win_determine_blur_background(session_t *ps, struct managed_win *w)
|
||||
win_set_blur_background(ps, w, blur_background_new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a window should have rounded corners.
|
||||
*/
|
||||
static void win_determine_rounded_corners(session_t *ps, struct managed_win *w) {
|
||||
if (w->a.map_state != XCB_MAP_STATE_VIEWABLE /*|| ps->o.corner_radius == 0*/)
|
||||
return;
|
||||
|
||||
// Don't round full screen windows & excluded windows
|
||||
if ((w && win_is_fullscreen(ps, w)) ||
|
||||
c2_match(ps, w, ps->o.rounded_corners_blacklist, NULL)) {
|
||||
w->corner_radius = 0;
|
||||
//log_warn("xy(%d %d) wh(%d %d) will NOT round corners", w->g.x, w->g.y, w->widthb, w->heightb);
|
||||
} else {
|
||||
w->corner_radius = ps->o.corner_radius;
|
||||
//log_warn("xy(%d %d) wh(%d %d) will round corners", w->g.x, w->g.y, w->widthb, w->heightb);
|
||||
|
||||
// HACK: we reset this so we can query the color once
|
||||
// we query the color in glx_round_corners_dst0 using glReadPixels
|
||||
//w->border_col = { -1., -1, -1, -1 };
|
||||
w->border_col[0] = w->border_col[1] = w->border_col[2] = w->border_col[3] = -1.0;
|
||||
|
||||
// wintypes config section override
|
||||
if (!safe_isnan(ps->o.wintype_option[w->window_type].corner_radius) &&
|
||||
ps->o.wintype_option[w->window_type].corner_radius >= 0) {
|
||||
w->corner_radius = ps->o.wintype_option[w->window_type].corner_radius;
|
||||
//log_warn("xy(%d %d) wh(%d %d) wintypes:corner_radius: %d", w->g.x, w->g.y, w->widthb, w->heightb, w->corner_radius);
|
||||
}
|
||||
|
||||
if (w && c2_match(ps, w, ps->o.round_borders_blacklist, NULL)) {
|
||||
w->round_borders = 0;
|
||||
} else {
|
||||
w->round_borders = ps->o.round_borders;
|
||||
// wintypes config section override
|
||||
if (!safe_isnan(ps->o.wintype_option[w->window_type].round_borders) &&
|
||||
ps->o.wintype_option[w->window_type].round_borders >= 0) {
|
||||
w->round_borders = ps->o.wintype_option[w->window_type].round_borders;
|
||||
//log_warn("wintypes:round_borders: %d", w->round_borders);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update window opacity according to opacity rules.
|
||||
*/
|
||||
@@ -904,7 +975,6 @@ void win_update_opacity_rule(session_t *ps, struct managed_win *w) {
|
||||
* TODO need better name
|
||||
*/
|
||||
void win_on_factor_change(session_t *ps, struct managed_win *w) {
|
||||
log_debug("Window %#010x (%s) factor change", w->base.id, w->name);
|
||||
// Focus needs to be updated first, as other rules might depend on the focused
|
||||
// state of the window
|
||||
win_update_focused(ps, w);
|
||||
@@ -912,8 +982,7 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) {
|
||||
win_determine_shadow(ps, w);
|
||||
win_determine_invert_color(ps, w);
|
||||
win_determine_blur_background(ps, w);
|
||||
w->mode = win_calc_mode(w);
|
||||
log_debug("Window mode changed to %d", w->mode);
|
||||
win_determine_rounded_corners(ps, w);
|
||||
win_update_opacity_rule(ps, w);
|
||||
if (w->a.map_state == XCB_MAP_STATE_VIEWABLE)
|
||||
w->paint_excluded = c2_match(ps, w, ps->o.paint_blacklist, NULL);
|
||||
@@ -921,7 +990,15 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) {
|
||||
w->unredir_if_possible_excluded =
|
||||
c2_match(ps, w, ps->o.unredir_if_possible_blacklist, NULL);
|
||||
|
||||
win_update_opacity_target(ps, w);
|
||||
auto opacity_target_old = w->opacity_target;
|
||||
w->opacity_target = win_calc_opacity_target(ps, w, false);
|
||||
if (opacity_target_old != w->opacity_target && w->state == WSTATE_MAPPED) {
|
||||
// Only MAPPED can transition to FADING
|
||||
w->state = WSTATE_FADING;
|
||||
if (!ps->redirected) {
|
||||
CHECK(!win_skip_fading(ps, w));
|
||||
}
|
||||
}
|
||||
|
||||
w->reg_ignore_valid = false;
|
||||
}
|
||||
@@ -940,7 +1017,7 @@ void win_on_win_size_change(session_t *ps, struct managed_win *w) {
|
||||
// Invalidate the shadow we built
|
||||
if (w->state == WSTATE_MAPPED || w->state == WSTATE_MAPPING ||
|
||||
w->state == WSTATE_FADING) {
|
||||
win_set_flags(w, WIN_FLAGS_IMAGES_STALE);
|
||||
w->flags |= WIN_FLAGS_IMAGES_STALE;
|
||||
ps->pending_updates = true;
|
||||
} else {
|
||||
assert(w->state == WSTATE_UNMAPPED);
|
||||
@@ -1014,9 +1091,9 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client)
|
||||
win_on_factor_change(ps, w);
|
||||
|
||||
auto r = xcb_get_window_attributes_reply(
|
||||
ps->c, xcb_get_window_attributes(ps->c, w->client_win), &e);
|
||||
ps->c, xcb_get_window_attributes(ps->c, w->client_win), NULL);
|
||||
if (!r) {
|
||||
log_error_x_error(e, "Failed to get client window attributes");
|
||||
log_error("Failed to get client window attributes");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1032,8 +1109,6 @@ void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client)
|
||||
*/
|
||||
void win_unmark_client(session_t *ps, struct managed_win *w) {
|
||||
xcb_window_t client = w->client_win;
|
||||
log_debug("Detaching client window %#010x from frame %#010x (%s)", client,
|
||||
w->base.id, w->name);
|
||||
|
||||
w->client_win = XCB_NONE;
|
||||
|
||||
@@ -1043,42 +1118,13 @@ void win_unmark_client(session_t *ps, struct managed_win *w) {
|
||||
(const uint32_t[]){determine_evmask(ps, client, WIN_EVMODE_UNKNOWN)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for the client window of a particular window.
|
||||
*/
|
||||
static xcb_window_t find_client_win(session_t *ps, xcb_window_t w) {
|
||||
if (wid_has_prop(ps, w, ps->atoms->aWM_STATE)) {
|
||||
return w;
|
||||
}
|
||||
|
||||
xcb_query_tree_reply_t *reply =
|
||||
xcb_query_tree_reply(ps->c, xcb_query_tree(ps->c, w), NULL);
|
||||
if (!reply)
|
||||
return 0;
|
||||
|
||||
xcb_window_t *children = xcb_query_tree_children(reply);
|
||||
int nchildren = xcb_query_tree_children_length(reply);
|
||||
int i;
|
||||
xcb_window_t ret = 0;
|
||||
|
||||
for (i = 0; i < nchildren; ++i) {
|
||||
if ((ret = find_client_win(ps, children[i])))
|
||||
break;
|
||||
}
|
||||
|
||||
free(reply);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recheck client window of a window.
|
||||
*
|
||||
* @param ps current session
|
||||
* @param w struct _win of the parent window
|
||||
*/
|
||||
void win_recheck_client(session_t *ps, struct managed_win *w) {
|
||||
assert(ps->server_grabbed);
|
||||
static void win_recheck_client(session_t *ps, struct managed_win *w) {
|
||||
// Initialize wmwin to false
|
||||
w->wmwin = false;
|
||||
|
||||
@@ -1088,14 +1134,14 @@ void win_recheck_client(session_t *ps, struct managed_win *w) {
|
||||
// sets override-redirect flags on all frame windows.
|
||||
xcb_window_t cw = find_client_win(ps, w->base.id);
|
||||
if (cw) {
|
||||
log_debug("(%#010x): client %#010x", w->base.id, cw);
|
||||
log_trace("(%#010x): client %#010x", w->base.id, cw);
|
||||
}
|
||||
// Set a window's client window to itself if we couldn't find a
|
||||
// client window
|
||||
if (!cw) {
|
||||
cw = w->base.id;
|
||||
w->wmwin = !w->a.override_redirect;
|
||||
log_debug("(%#010x): client self (%s)", w->base.id,
|
||||
log_trace("(%#010x): client self (%s)", w->base.id,
|
||||
(w->wmwin ? "wmwin" : "override-redirected"));
|
||||
}
|
||||
|
||||
@@ -1191,10 +1237,10 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
||||
.invert_color = false,
|
||||
.blur_background = false,
|
||||
|
||||
.oldX = -10000,
|
||||
.oldY = -10000,
|
||||
.oldW = 0,
|
||||
.oldH = 0,
|
||||
.oldX = -10000,
|
||||
.oldY = -10000,
|
||||
.oldW = 0,
|
||||
.oldH = 0,
|
||||
|
||||
.reg_ignore = NULL,
|
||||
// The following ones are updated for other reasons
|
||||
@@ -1262,6 +1308,8 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
||||
// Initialized during paint
|
||||
.paint = PAINT_INIT,
|
||||
.shadow_paint = PAINT_INIT,
|
||||
|
||||
.corner_radius = 0,
|
||||
};
|
||||
|
||||
assert(!w->destroyed);
|
||||
@@ -1305,6 +1353,7 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
||||
// Allocate and initialize the new win structure
|
||||
auto new_internal = cmalloc(struct managed_win_internal);
|
||||
auto new = (struct managed_win *)new_internal;
|
||||
new_internal->pending_updates = 0;
|
||||
|
||||
// Fill structure
|
||||
// We only need to initialize the part that are not initialized
|
||||
@@ -1550,7 +1599,7 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) {
|
||||
|
||||
pixman_region32_clear(&w->bounding_shape);
|
||||
// Start with the window rectangular region
|
||||
win_get_region_local(w, &w->bounding_shape);
|
||||
win_get_region_local(w, &w->bounding_shape, true);
|
||||
|
||||
// Only request for a bounding region if the window is shaped
|
||||
// (while loop is used to avoid goto, not an actual loop)
|
||||
@@ -1602,7 +1651,7 @@ void win_update_bounding_shape(session_t *ps, struct managed_win *w) {
|
||||
// Note we only do this when screen is redirected, because
|
||||
// otherwise win_data is not valid
|
||||
assert(w->state != WSTATE_UNMAPPING && w->state != WSTATE_DESTROYING);
|
||||
win_set_flags(w, WIN_FLAGS_IMAGES_STALE);
|
||||
w->flags |= WIN_FLAGS_IMAGES_STALE;
|
||||
ps->pending_updates = true;
|
||||
}
|
||||
free_paint(ps, &w->paint);
|
||||
@@ -1716,7 +1765,7 @@ static void unmap_win_finish(session_t *ps, struct managed_win *w) {
|
||||
free_paint(ps, &w->shadow_paint);
|
||||
|
||||
// Try again at binding images when the window is mapped next time
|
||||
win_clear_flags(w, WIN_FLAGS_IMAGE_ERROR);
|
||||
w->flags &= ~WIN_FLAGS_IMAGE_ERROR;
|
||||
}
|
||||
|
||||
/// Finish the destruction of a window (e.g. after fading has finished).
|
||||
@@ -1778,7 +1827,7 @@ static void destroy_win_finish(session_t *ps, struct win *w) {
|
||||
|
||||
static void map_win_finish(struct managed_win *w) {
|
||||
w->in_openclose = false;
|
||||
w->isOld = true;
|
||||
w->isOld = true;
|
||||
w->state = WSTATE_MAPPED;
|
||||
}
|
||||
|
||||
@@ -1890,15 +1939,14 @@ bool destroy_win_start(session_t *ps, struct win *w) {
|
||||
}
|
||||
|
||||
if (w->managed) {
|
||||
// Clear PIXMAP_STALE flag, since the window is destroyed there is no
|
||||
// pixmap available so STALE doesn't make sense.
|
||||
// Do this before changing the window state to destroying
|
||||
win_clear_flags(mw, WIN_FLAGS_PIXMAP_STALE);
|
||||
|
||||
// Update state flags of a managed window
|
||||
mw->state = WSTATE_DESTROYING;
|
||||
mw->a.map_state = XCB_MAP_STATE_UNMAPPED;
|
||||
mw->in_openclose = true;
|
||||
|
||||
// Clear PIXMAP_STALE flag, since the window is destroyed there is no
|
||||
// pixmap available so STALE doesn't make sense.
|
||||
mw->flags &= ~WIN_FLAGS_PIXMAP_STALE;
|
||||
}
|
||||
|
||||
// don't need win_ev_stop because the window is gone anyway
|
||||
@@ -1918,6 +1966,7 @@ bool destroy_win_start(session_t *ps, struct win *w) {
|
||||
}
|
||||
|
||||
void unmap_win_start(session_t *ps, struct managed_win *w) {
|
||||
auto internal_w = (struct managed_win_internal *)w;
|
||||
assert(w);
|
||||
assert(w->base.managed);
|
||||
assert(w->a._class != XCB_WINDOW_CLASS_INPUT_ONLY);
|
||||
@@ -1930,9 +1979,8 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
|
||||
}
|
||||
|
||||
if (unlikely(w->state == WSTATE_UNMAPPING || w->state == WSTATE_UNMAPPED)) {
|
||||
if (win_check_flags_all(w, WIN_FLAGS_MAPPED)) {
|
||||
// Clear the pending map as this window is now unmapped
|
||||
win_clear_flags(w, WIN_FLAGS_MAPPED);
|
||||
if (internal_w->pending_updates & WIN_UPDATE_MAP) {
|
||||
internal_w->pending_updates &= ~(unsigned long)WIN_UPDATE_MAP;
|
||||
} else {
|
||||
log_warn("Trying to unmapping an already unmapped window %#010x "
|
||||
"\"%s\"",
|
||||
@@ -1947,12 +1995,11 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
|
||||
|
||||
w->a.map_state = XCB_MAP_STATE_UNMAPPED;
|
||||
w->state = WSTATE_UNMAPPING;
|
||||
w->opacity_target_old = fmax(w->opacity_target, w->opacity_target_old);
|
||||
w->opacity_target = win_calc_opacity_target(ps, w);
|
||||
w->opacity_target = win_calc_opacity_target(ps, w, false);
|
||||
|
||||
// Clear PIXMAP_STALE flag, since the window is unmapped there is no pixmap
|
||||
// available so STALE doesn't make sense.
|
||||
win_clear_flags(w, WIN_FLAGS_PIXMAP_STALE);
|
||||
w->flags &= ~WIN_FLAGS_PIXMAP_STALE;
|
||||
|
||||
// don't care about properties anymore
|
||||
win_ev_stop(ps, &w->base);
|
||||
@@ -2059,7 +2106,8 @@ void map_win_start(session_t *ps, struct managed_win *w) {
|
||||
}
|
||||
|
||||
assert(w->state == WSTATE_UNMAPPED);
|
||||
assert(win_check_flags_all(w, WIN_FLAGS_IMAGES_NONE) || !ps->o.experimental_backends);
|
||||
assert((w->flags & WIN_FLAGS_IMAGES_NONE) == WIN_FLAGS_IMAGES_NONE ||
|
||||
!ps->o.experimental_backends);
|
||||
|
||||
// We stopped processing window size change when we were unmapped, refresh the
|
||||
// size of the window
|
||||
@@ -2087,13 +2135,14 @@ void map_win_start(session_t *ps, struct managed_win *w) {
|
||||
// XXX Can we assume map_state is always viewable?
|
||||
w->a.map_state = XCB_MAP_STATE_VIEWABLE;
|
||||
|
||||
if (!w->isOld) {
|
||||
w->oldX = -1000;
|
||||
w->oldY = -1000;
|
||||
if (!w->isOld) {
|
||||
w->oldX = -10000;
|
||||
w->oldY = -10000;
|
||||
w->oldW = 0;
|
||||
w->oldH = 0;
|
||||
}
|
||||
|
||||
|
||||
win_update_screen(ps, w);
|
||||
|
||||
// Set window event mask before reading properties so that no property
|
||||
@@ -2108,7 +2157,7 @@ void map_win_start(session_t *ps, struct managed_win *w) {
|
||||
}
|
||||
|
||||
// Update window mode here to check for ARGB windows
|
||||
w->mode = win_calc_mode(w);
|
||||
w->mode = win_calc_mode(ps, w);
|
||||
|
||||
// Detect client window here instead of in add_win() as the client
|
||||
// window should have been prepared at this point
|
||||
@@ -2139,13 +2188,13 @@ void map_win_start(session_t *ps, struct managed_win *w) {
|
||||
// XXX We need to make sure that win_data is available
|
||||
// iff `state` is MAPPED
|
||||
w->state = WSTATE_MAPPING;
|
||||
w->opacity_target_old = 0;
|
||||
w->opacity_target = win_calc_opacity_target(ps, w);
|
||||
w->opacity_target = win_calc_opacity_target(ps, w, false);
|
||||
|
||||
log_debug("Window %#010x has opacity %f, opacity target is %f", w->base.id,
|
||||
w->opacity, w->opacity_target);
|
||||
|
||||
win_determine_blur_background(ps, w);
|
||||
win_determine_rounded_corners(ps, w);
|
||||
|
||||
// Cannot set w->ever_damaged = false here, since window mapping could be
|
||||
// delayed, so a damage event might have already arrived before this function
|
||||
@@ -2161,7 +2210,7 @@ void map_win_start(session_t *ps, struct managed_win *w) {
|
||||
// the window's image will be bound
|
||||
win_update_bounding_shape(ps, w);
|
||||
|
||||
assert(win_check_flags_all(w, WIN_FLAGS_IMAGES_STALE));
|
||||
assert((w->flags & WIN_FLAGS_IMAGES_STALE) == WIN_FLAGS_IMAGES_STALE);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
@@ -2175,60 +2224,6 @@ void map_win_start(session_t *ps, struct managed_win *w) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update target window opacity depending on the current state.
|
||||
*/
|
||||
void win_update_opacity_target(session_t *ps, struct managed_win *w) {
|
||||
auto opacity_target_old = w->opacity_target;
|
||||
w->opacity_target = win_calc_opacity_target(ps, w);
|
||||
|
||||
if (opacity_target_old == w->opacity_target) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (w->state == WSTATE_MAPPED) {
|
||||
// Opacity target changed while MAPPED. Transition to FADING.
|
||||
assert(w->opacity == opacity_target_old);
|
||||
w->opacity_target_old = opacity_target_old;
|
||||
w->state = WSTATE_FADING;
|
||||
log_debug("Window %#010x (%s) opacity %f, opacity target %f, set "
|
||||
"old target %f",
|
||||
w->base.id, w->name, w->opacity, w->opacity_target,
|
||||
w->opacity_target_old);
|
||||
} else if (w->state == WSTATE_MAPPING) {
|
||||
// Opacity target changed while fading in.
|
||||
if (w->opacity >= w->opacity_target) {
|
||||
// Already reached new target opacity. Transition to
|
||||
// FADING.
|
||||
map_win_finish(w);
|
||||
w->opacity_target_old = fmax(opacity_target_old, w->opacity);
|
||||
w->state = WSTATE_FADING;
|
||||
log_debug("Window %#010x (%s) opacity %f already reached "
|
||||
"new opacity target %f while mapping, set old "
|
||||
"target %f",
|
||||
w->base.id, w->name, w->opacity, w->opacity_target,
|
||||
w->opacity_target_old);
|
||||
}
|
||||
} else if (w->state == WSTATE_FADING) {
|
||||
// Opacity target changed while FADING.
|
||||
if ((w->opacity < opacity_target_old && w->opacity > w->opacity_target) ||
|
||||
(w->opacity > opacity_target_old && w->opacity < w->opacity_target)) {
|
||||
// Changed while fading in and will fade out or while
|
||||
// fading out and will fade in.
|
||||
w->opacity_target_old = opacity_target_old;
|
||||
log_debug("Window %#010x (%s) opacity %f already reached "
|
||||
"new opacity target %f while fading, set "
|
||||
"old target %f",
|
||||
w->base.id, w->name, w->opacity, w->opacity_target,
|
||||
w->opacity_target_old);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ps->redirected) {
|
||||
CHECK(!win_skip_fading(ps, w));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a managed window from window id in window linked list of the session.
|
||||
*/
|
||||
@@ -2284,13 +2279,13 @@ 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 out the WM frame of a client window by querying X.
|
||||
*
|
||||
* @param ps current session
|
||||
* @param wid window ID
|
||||
* @return struct _win object of the found window, NULL if not found
|
||||
*/
|
||||
struct managed_win *find_managed_window_or_parent(session_t *ps, xcb_window_t wid) {
|
||||
struct managed_win *find_toplevel2(session_t *ps, xcb_window_t wid) {
|
||||
// TODO this should probably be an "update tree", then find_toplevel.
|
||||
// current approach is a bit more "racy"
|
||||
struct win *w = NULL;
|
||||
@@ -2351,35 +2346,31 @@ win_is_fullscreen_xcb(xcb_connection_t *c, const struct atom *a, const xcb_windo
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Set flags on a window. Some sanity checks are performed
|
||||
void win_set_flags(struct managed_win *w, uint64_t flags) {
|
||||
log_debug("Set flags %lu to window %#010x (%s)", flags, w->base.id, w->name);
|
||||
if (unlikely(w->state == WSTATE_DESTROYING)) {
|
||||
log_error("Flags set on a destroyed window %#010x (%s)", w->base.id, w->name);
|
||||
/// Queue an update on a window. A series of sanity checks are performed
|
||||
void win_queue_update(struct managed_win *_w, enum win_update update) {
|
||||
auto w = (struct managed_win_internal *)_w;
|
||||
assert(popcount(update) == 1);
|
||||
assert(update == WIN_UPDATE_MAP); // Currently the only supported update
|
||||
|
||||
if (unlikely(_w->state == WSTATE_DESTROYING)) {
|
||||
log_error("Updates queued on a destroyed window %#010x (%s)", _w->base.id,
|
||||
_w->name);
|
||||
return;
|
||||
}
|
||||
|
||||
w->flags |= flags;
|
||||
w->pending_updates |= update;
|
||||
}
|
||||
|
||||
/// Clear flags on a window. Some sanity checks are performed
|
||||
void win_clear_flags(struct managed_win *w, uint64_t flags) {
|
||||
log_debug("Clear flags %lu from window %#010x (%s)", flags, w->base.id, w->name);
|
||||
if (unlikely(w->state == WSTATE_DESTROYING)) {
|
||||
log_warn("Flags cleared on a destroyed window %#010x (%s)", w->base.id,
|
||||
w->name);
|
||||
return;
|
||||
/// Process pending updates on a window. Has to be called in X critical section
|
||||
void win_process_updates(struct session *ps, struct managed_win *_w) {
|
||||
assert(ps->server_grabbed);
|
||||
auto w = (struct managed_win_internal *)_w;
|
||||
|
||||
if (w->pending_updates & WIN_UPDATE_MAP) {
|
||||
map_win_start(ps, _w);
|
||||
}
|
||||
|
||||
w->flags = w->flags & (~flags);
|
||||
}
|
||||
|
||||
bool win_check_flags_any(struct managed_win *w, uint64_t flags) {
|
||||
return (w->flags & flags) != 0;
|
||||
}
|
||||
|
||||
bool win_check_flags_all(struct managed_win *w, uint64_t flags) {
|
||||
return (w->flags & flags) == flags;
|
||||
w->pending_updates = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2435,6 +2426,7 @@ win_stack_find_next_managed(const session_t *ps, const struct list_node *i) {
|
||||
|
||||
/// Return whether this window is mapped on the X server side
|
||||
bool win_is_mapped_in_x(const struct managed_win *w) {
|
||||
auto iw = (const struct managed_win_internal *)w;
|
||||
return w->state == WSTATE_MAPPING || w->state == WSTATE_FADING ||
|
||||
w->state == WSTATE_MAPPED || (w->flags & WIN_FLAGS_MAPPED);
|
||||
w->state == WSTATE_MAPPED || (iw->pending_updates & WIN_UPDATE_MAP);
|
||||
}
|
||||
|
||||
80
src/win.h
80
src/win.h
@@ -40,13 +40,13 @@ typedef struct _glx_texture glx_texture_t;
|
||||
// it is very unideal for it to be here
|
||||
typedef struct {
|
||||
/// Framebuffer used for blurring.
|
||||
GLuint fbo;
|
||||
GLuint fbos[MAX_BLUR_PASS];
|
||||
/// Textures used for blurring.
|
||||
GLuint textures[2];
|
||||
GLuint textures[MAX_BLUR_PASS];
|
||||
/// Width of the textures.
|
||||
int width;
|
||||
int width[MAX_BLUR_PASS];
|
||||
/// Height of the textures.
|
||||
int height;
|
||||
int height[MAX_BLUR_PASS];
|
||||
} glx_blur_cache_t;
|
||||
#endif
|
||||
|
||||
@@ -131,7 +131,7 @@ struct managed_win {
|
||||
/// See above about coordinate systems.
|
||||
region_t bounding_shape;
|
||||
/// Window flags. Definitions above.
|
||||
uint64_t flags;
|
||||
int_fast16_t flags;
|
||||
/// The region of screen that will be obscured when windows above is painted,
|
||||
/// in global coordinates.
|
||||
/// We use this to reduce the pixels that needed to be paint when painting
|
||||
@@ -192,8 +192,6 @@ struct managed_win {
|
||||
double opacity;
|
||||
/// Target window opacity.
|
||||
double opacity_target;
|
||||
/// Previous window opacity.
|
||||
double opacity_target_old;
|
||||
/// true if window (or client window, for broken window managers
|
||||
/// not transferring client window's _NET_WM_OPACITY value) has opacity prop
|
||||
bool has_opacity_prop;
|
||||
@@ -204,6 +202,11 @@ struct managed_win {
|
||||
/// Last window opacity value set by the rules.
|
||||
double opacity_set;
|
||||
|
||||
/// Corner radius
|
||||
int corner_radius;
|
||||
bool round_borders;
|
||||
float border_col[4];
|
||||
|
||||
// Fading-related members
|
||||
/// Override value of window fade state. Set by D-Bus method calls.
|
||||
switch_t fade_force;
|
||||
@@ -248,21 +251,29 @@ struct managed_win {
|
||||
/// Whether to blur window background.
|
||||
bool blur_background;
|
||||
|
||||
/// Animation state
|
||||
int oldX; int oldY; int oldW; int oldH;
|
||||
int newX; int newY; int newW; int newH;
|
||||
float moveTimeX; float moveTimeY;
|
||||
float moveTimeW; float moveTimeH;
|
||||
bool isOld;
|
||||
/// Animation state
|
||||
int oldX; int oldY; int oldW; int oldH;
|
||||
int newX; int newY; int newW; int newH;
|
||||
float moveTimeX; float moveTimeY;
|
||||
float moveTimeW; float moveTimeH;
|
||||
bool isOld;
|
||||
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
/// Textures and FBO background blur use.
|
||||
glx_blur_cache_t glx_blur_cache;
|
||||
glx_blur_cache_t glx_round_cache;
|
||||
/// Background texture of the window
|
||||
glx_texture_t *glx_texture_bg;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Process pending updates on a window. Has to be called in X critical section
|
||||
void win_process_updates(struct session *ps, struct managed_win *_w);
|
||||
/// Process pending images flags on a window. Has to be called in X critical section
|
||||
void win_process_flags(session_t *ps, struct managed_win *w);
|
||||
/// Queue an update on a window. A series of sanity checks are performed
|
||||
void win_queue_update(struct managed_win *_w, enum win_update update);
|
||||
/// Bind a shadow to the window, with color `c` and shadow kernel `kernel`
|
||||
bool win_bind_shadow(struct backend_base *b, struct managed_win *w, struct color c,
|
||||
struct conv *kernel);
|
||||
@@ -284,7 +295,7 @@ bool must_use destroy_win_start(session_t *ps, struct win *w);
|
||||
void win_release_images(struct backend_base *base, struct managed_win *w);
|
||||
int win_update_name(session_t *ps, struct managed_win *w);
|
||||
int win_get_role(session_t *ps, struct managed_win *w);
|
||||
winmode_t attr_pure win_calc_mode(const struct managed_win *w);
|
||||
winmode_t attr_pure win_calc_mode(session_t *ps, const struct managed_win *w);
|
||||
void win_set_shadow_force(session_t *ps, struct managed_win *w, switch_t val);
|
||||
void win_set_fade_force(struct managed_win *w, switch_t val);
|
||||
void win_set_focused_force(session_t *ps, struct managed_win *w, switch_t val);
|
||||
@@ -296,7 +307,6 @@ void win_set_focused(session_t *ps, struct managed_win *w);
|
||||
bool attr_pure win_should_fade(session_t *ps, const struct managed_win *w);
|
||||
void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w);
|
||||
void win_update_prop_shadow(session_t *ps, struct managed_win *w);
|
||||
void win_update_opacity_target(session_t *ps, struct managed_win *w);
|
||||
void win_on_factor_change(session_t *ps, struct managed_win *w);
|
||||
/**
|
||||
* Update cache data in struct _win that depends on window size.
|
||||
@@ -305,7 +315,6 @@ void win_on_win_size_change(session_t *ps, struct managed_win *w);
|
||||
void win_update_wintype(session_t *ps, struct managed_win *w);
|
||||
void win_mark_client(session_t *ps, struct managed_win *w, xcb_window_t client);
|
||||
void win_unmark_client(session_t *ps, struct managed_win *w);
|
||||
void win_recheck_client(session_t *ps, struct managed_win *w);
|
||||
bool win_get_class(session_t *ps, struct managed_win *w);
|
||||
|
||||
/**
|
||||
@@ -318,10 +327,12 @@ bool win_get_class(session_t *ps, struct managed_win *w);
|
||||
*
|
||||
* @param ps current session
|
||||
* @param w struct _win object representing the window
|
||||
* @param ignore_state whether window state should be ignored in opacity calculation
|
||||
*
|
||||
* @return target opacity
|
||||
*/
|
||||
double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w);
|
||||
double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w,
|
||||
bool ignore_state);
|
||||
bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w);
|
||||
void win_update_screen(session_t *, struct managed_win *);
|
||||
/**
|
||||
@@ -362,12 +373,12 @@ void add_damage_from_win(session_t *ps, const struct managed_win *w);
|
||||
*
|
||||
* Return region in global coordinates.
|
||||
*/
|
||||
void win_get_region_noframe_local(const struct managed_win *w, region_t *);
|
||||
void win_get_region_noframe_local(const struct managed_win *w, region_t *, bool include_corners);
|
||||
|
||||
/// Get the region for the frame of the window
|
||||
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, bool include_corners);
|
||||
/// 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, bool include_corners);
|
||||
/**
|
||||
* Retrieve frame extents from a window.
|
||||
*/
|
||||
@@ -407,13 +418,13 @@ 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 out the WM frame of a client window by querying X.
|
||||
*
|
||||
* @param ps current session
|
||||
* @param wid window ID
|
||||
* @return struct _win object of the found window, NULL if not found
|
||||
*/
|
||||
struct managed_win *find_managed_window_or_parent(session_t *ps, xcb_window_t wid);
|
||||
struct managed_win *find_toplevel2(session_t *ps, xcb_window_t wid);
|
||||
|
||||
/**
|
||||
* Check if a window is a fullscreen window.
|
||||
@@ -439,22 +450,29 @@ bool win_is_mapped_in_x(const struct managed_win *w);
|
||||
// Find the managed window immediately below `w` in the window stack
|
||||
struct managed_win *attr_pure win_stack_find_next_managed(const session_t *ps,
|
||||
const struct list_node *w);
|
||||
/// Set flags on a window. Some sanity checks are performed
|
||||
void win_set_flags(struct managed_win *w, uint64_t flags);
|
||||
/// Clear flags on a window. Some sanity checks are performed
|
||||
void win_clear_flags(struct managed_win *w, uint64_t flags);
|
||||
/// Returns true if any of the flags in `flags` is set
|
||||
bool win_check_flags_any(struct managed_win *w, uint64_t flags);
|
||||
/// Returns true if all of the flags in `flags` are set
|
||||
bool win_check_flags_all(struct managed_win *w, uint64_t flags);
|
||||
|
||||
/// Free all resources in a struct win
|
||||
void free_win_res(session_t *ps, struct managed_win *w);
|
||||
|
||||
static inline region_t win_get_bounding_shape_global_by_val(struct managed_win *w) {
|
||||
static inline void win_region_remove_corners(const struct managed_win *w, region_t *res) {
|
||||
region_t corners;
|
||||
pixman_region32_init_rects(
|
||||
&corners,
|
||||
(rect_t[]){
|
||||
{.x1 = 0, .y1 = 0, .x2 = w->corner_radius, .y2 = w->corner_radius},
|
||||
{.x1 = 0, .y1 = w->heightb-w->corner_radius, .x2 = w->corner_radius, .y2 = w->heightb},
|
||||
{.x1 = w->widthb-w->corner_radius, .y1 = 0, .x2 = w->widthb, .y2 = w->corner_radius},
|
||||
{.x1 = w->widthb-w->corner_radius, .y1 = w->heightb-w->corner_radius, .x2 = w->widthb, .y2 = w->heightb},
|
||||
},
|
||||
4);
|
||||
pixman_region32_subtract(res, res, &corners);
|
||||
}
|
||||
|
||||
static inline region_t win_get_bounding_shape_global_by_val(struct managed_win *w, bool include_corners) {
|
||||
region_t ret;
|
||||
pixman_region32_init(&ret);
|
||||
pixman_region32_copy(&ret, &w->bounding_shape);
|
||||
if(!include_corners) win_region_remove_corners(w, &ret);
|
||||
pixman_region32_translate(&ret, w->g.x, w->g.y);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,11 @@ typedef enum {
|
||||
WMODE_SOLID, // The window is opaque including the frame
|
||||
} winmode_t;
|
||||
|
||||
/// Pending window updates
|
||||
enum win_update {
|
||||
WIN_UPDATE_MAP = 1,
|
||||
};
|
||||
|
||||
/// Transition table:
|
||||
/// (DESTROYED is when the win struct is destroyed and freed)
|
||||
/// ('o' means in all other cases)
|
||||
@@ -40,8 +45,8 @@ typedef enum {
|
||||
/// | DESTROYING | - | o | - | - | - | - | Fading |
|
||||
/// | | | | | | | |finished |
|
||||
/// +-------------+---------+----------+-------+-------+--------+--------+---------+
|
||||
/// | MAPPING | Window | Window | o |Opacity| - | Fading | - |
|
||||
/// | |unmapped |destroyed | |change | |finished| |
|
||||
/// | MAPPING | Window | Window | o | - | - | Fading | - |
|
||||
/// | |unmapped |destroyed | | | |finished| |
|
||||
/// +-------------+---------+----------+-------+-------+--------+--------+---------+
|
||||
/// | FADING | Window | Window | - | o | - | Fading | - |
|
||||
/// | |unmapped |destroyed | | | |finished| |
|
||||
@@ -81,13 +86,9 @@ enum win_flags {
|
||||
WIN_FLAGS_SHADOW_STALE = 8,
|
||||
/// shadow has not been generated
|
||||
WIN_FLAGS_SHADOW_NONE = 16,
|
||||
/// the client window needs to be updated
|
||||
WIN_FLAGS_CLIENT_STALE = 32,
|
||||
/// the window is mapped by X, we need to call map_win_start for it
|
||||
WIN_FLAGS_MAPPED = 64,
|
||||
};
|
||||
|
||||
static const uint64_t WIN_FLAGS_IMAGES_STALE =
|
||||
static const int_fast16_t WIN_FLAGS_IMAGES_STALE =
|
||||
WIN_FLAGS_PIXMAP_STALE | WIN_FLAGS_SHADOW_STALE;
|
||||
|
||||
#define WIN_FLAGS_IMAGES_NONE (WIN_FLAGS_PIXMAP_NONE | WIN_FLAGS_SHADOW_NONE)
|
||||
|
||||
107
src/x.c
107
src/x.c
@@ -7,7 +7,6 @@
|
||||
#include <pixman.h>
|
||||
#include <xcb/composite.h>
|
||||
#include <xcb/damage.h>
|
||||
#include <xcb/glx.h>
|
||||
#include <xcb/render.h>
|
||||
#include <xcb/sync.h>
|
||||
#include <xcb/xcb.h>
|
||||
@@ -168,6 +167,15 @@ xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_
|
||||
return x_get_visual_for_pictfmt(g_pictfmts, pictfmt->id);
|
||||
}
|
||||
|
||||
xcb_render_pictformat_t
|
||||
x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std) {
|
||||
x_get_server_pictfmts(c);
|
||||
|
||||
auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, std);
|
||||
|
||||
return pictfmt->id;
|
||||
}
|
||||
|
||||
int x_get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) {
|
||||
auto setup = xcb_get_setup(c);
|
||||
for (auto screen = xcb_setup_roots_iterator(setup); screen.rem;
|
||||
@@ -231,6 +239,17 @@ x_create_picture_with_standard_and_pixmap(xcb_connection_t *c, xcb_pict_standard
|
||||
return x_create_picture_with_pictfmt_and_pixmap(c, pictfmt, pixmap, valuemask, attr);
|
||||
}
|
||||
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
|
||||
xcb_pict_standard_t standard, uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr) {
|
||||
x_get_server_pictfmts(c);
|
||||
|
||||
auto pictfmt = xcb_render_util_find_standard_format(g_pictfmts, standard);
|
||||
assert(pictfmt);
|
||||
return x_create_picture_with_pictfmt(c, d, w, h, pictfmt, valuemask, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an picture.
|
||||
*/
|
||||
@@ -338,80 +357,69 @@ _x_strerror(unsigned long serial, uint8_t major, uint16_t minor, uint8_t error_c
|
||||
int o = 0;
|
||||
const char *name = "Unknown";
|
||||
|
||||
#define CASESTRRET(s) \
|
||||
case s: \
|
||||
name = #s; \
|
||||
break
|
||||
|
||||
#define CASESTRRET2(s) \
|
||||
case XCB_##s: name = #s; break
|
||||
case s: name = #s; break
|
||||
|
||||
// TODO separate error code out from session_t
|
||||
o = error_code - ps->xfixes_error;
|
||||
switch (o) { CASESTRRET2(XFIXES_BAD_REGION); }
|
||||
switch (o) { CASESTRRET2(XCB_XFIXES_BAD_REGION); }
|
||||
|
||||
o = error_code - ps->damage_error;
|
||||
switch (o) { CASESTRRET2(DAMAGE_BAD_DAMAGE); }
|
||||
switch (o) { CASESTRRET2(XCB_DAMAGE_BAD_DAMAGE); }
|
||||
|
||||
o = error_code - ps->render_error;
|
||||
switch (o) {
|
||||
CASESTRRET2(RENDER_PICT_FORMAT);
|
||||
CASESTRRET2(RENDER_PICTURE);
|
||||
CASESTRRET2(RENDER_PICT_OP);
|
||||
CASESTRRET2(RENDER_GLYPH_SET);
|
||||
CASESTRRET2(RENDER_GLYPH);
|
||||
CASESTRRET2(XCB_RENDER_PICT_FORMAT);
|
||||
CASESTRRET2(XCB_RENDER_PICTURE);
|
||||
CASESTRRET2(XCB_RENDER_PICT_OP);
|
||||
CASESTRRET2(XCB_RENDER_GLYPH_SET);
|
||||
CASESTRRET2(XCB_RENDER_GLYPH);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
if (ps->glx_exists) {
|
||||
o = error_code - ps->glx_error;
|
||||
switch (o) {
|
||||
CASESTRRET2(GLX_BAD_SCREEN);
|
||||
CASESTRRET2(GLX_BAD_ATTRIBUTE);
|
||||
CASESTRRET2(GLX_NO_EXTENSION);
|
||||
CASESTRRET2(GLX_BAD_VISUAL);
|
||||
CASESTRRET2(GLX_BAD_CONTEXT);
|
||||
CASESTRRET2(GLX_BAD_CONTEXT_STATE);
|
||||
CASESTRRET2(GLX_BAD_DRAWABLE);
|
||||
CASESTRRET2(GLX_BAD_PIXMAP);
|
||||
CASESTRRET2(GLX_BAD_CONTEXT_TAG);
|
||||
CASESTRRET2(GLX_BAD_CURRENT_WINDOW);
|
||||
CASESTRRET2(GLX_BAD_RENDER_REQUEST);
|
||||
CASESTRRET2(GLX_BAD_LARGE_REQUEST);
|
||||
CASESTRRET2(GLX_UNSUPPORTED_PRIVATE_REQUEST);
|
||||
CASESTRRET2(GLX_BAD_FB_CONFIG);
|
||||
CASESTRRET2(GLX_BAD_PBUFFER);
|
||||
CASESTRRET2(GLX_BAD_CURRENT_DRAWABLE);
|
||||
CASESTRRET2(GLX_BAD_WINDOW);
|
||||
CASESTRRET2(GLX_GLX_BAD_PROFILE_ARB);
|
||||
CASESTRRET2(GLX_BAD_VALUE);
|
||||
CASESTRRET2(GLX_BAD_ENUM);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ps->xsync_exists) {
|
||||
o = error_code - ps->xsync_error;
|
||||
switch (o) {
|
||||
CASESTRRET(XSyncBadCounter);
|
||||
CASESTRRET(XSyncBadAlarm);
|
||||
CASESTRRET(XSyncBadFence);
|
||||
CASESTRRET2(XSyncBadCounter);
|
||||
CASESTRRET2(XSyncBadAlarm);
|
||||
CASESTRRET2(XSyncBadFence);
|
||||
}
|
||||
}
|
||||
|
||||
switch (error_code) {
|
||||
CASESTRRET2(ACCESS);
|
||||
CASESTRRET2(ALLOC);
|
||||
CASESTRRET2(ATOM);
|
||||
CASESTRRET2(COLORMAP);
|
||||
CASESTRRET2(CURSOR);
|
||||
CASESTRRET2(DRAWABLE);
|
||||
CASESTRRET2(FONT);
|
||||
CASESTRRET2(G_CONTEXT);
|
||||
CASESTRRET2(ID_CHOICE);
|
||||
CASESTRRET2(IMPLEMENTATION);
|
||||
CASESTRRET2(LENGTH);
|
||||
CASESTRRET2(MATCH);
|
||||
CASESTRRET2(NAME);
|
||||
CASESTRRET2(PIXMAP);
|
||||
CASESTRRET2(REQUEST);
|
||||
CASESTRRET2(VALUE);
|
||||
CASESTRRET2(WINDOW);
|
||||
CASESTRRET2(BadAccess);
|
||||
CASESTRRET2(BadAlloc);
|
||||
CASESTRRET2(BadAtom);
|
||||
CASESTRRET2(BadColor);
|
||||
CASESTRRET2(BadCursor);
|
||||
CASESTRRET2(BadDrawable);
|
||||
CASESTRRET2(BadFont);
|
||||
CASESTRRET2(BadGC);
|
||||
CASESTRRET2(BadIDChoice);
|
||||
CASESTRRET2(BadImplementation);
|
||||
CASESTRRET2(BadLength);
|
||||
CASESTRRET2(BadMatch);
|
||||
CASESTRRET2(BadName);
|
||||
CASESTRRET2(BadPixmap);
|
||||
CASESTRRET2(BadRequest);
|
||||
CASESTRRET2(BadValue);
|
||||
CASESTRRET2(BadWindow);
|
||||
}
|
||||
|
||||
#undef CASESTRRET
|
||||
#undef CASESTRRET2
|
||||
|
||||
thread_local static char buffer[256];
|
||||
@@ -434,9 +442,6 @@ void x_print_error(unsigned long serial, uint8_t major, uint16_t minor, uint8_t
|
||||
* for multiple calls to this function,
|
||||
*/
|
||||
const char *x_strerror(xcb_generic_error_t *e) {
|
||||
if (!e) {
|
||||
return "No error";
|
||||
}
|
||||
return _x_strerror(e->full_sequence, e->major_code, e->minor_code, e->error_code);
|
||||
}
|
||||
|
||||
|
||||
8
src/x.h
8
src/x.h
@@ -172,6 +172,12 @@ x_create_picture_with_standard_and_pixmap(xcb_connection_t *, xcb_pict_standard_
|
||||
const xcb_render_create_picture_value_list_t *attr)
|
||||
attr_nonnull(1);
|
||||
|
||||
xcb_render_picture_t
|
||||
x_create_picture_with_standard(xcb_connection_t *c, xcb_drawable_t d, int w, int h,
|
||||
xcb_pict_standard_t standard, uint32_t valuemask,
|
||||
const xcb_render_create_picture_value_list_t *attr)
|
||||
attr_nonnull(1);
|
||||
|
||||
/**
|
||||
* Create an picture.
|
||||
*/
|
||||
@@ -261,6 +267,8 @@ struct xvisual_info x_get_visual_info(xcb_connection_t *c, xcb_visualid_t visual
|
||||
|
||||
xcb_visualid_t x_get_visual_for_standard(xcb_connection_t *c, xcb_pict_standard_t std);
|
||||
|
||||
xcb_render_pictformat_t x_get_pictfmt_for_standard(xcb_connection_t *c, xcb_pict_standard_t std);
|
||||
|
||||
xcb_screen_t *x_screen_of_display(xcb_connection_t *c, int screen);
|
||||
|
||||
uint32_t attr_deprecated xcb_generate_id(xcb_connection_t *c);
|
||||
|
||||
Reference in New Issue
Block a user