Convert XfixesRegion to pixman region
Re-did the painting logic, and document it. It is unclear to me what is the previous painting logic. But the current one is basically this: 1. Go through all windows top to bottom, and put visible windows (not unmapped, opacity > 0, etc) into a linked list, from bottom to top 2. Accumulate a region of ignore on each window, which is basically the region of screen that is obscured by all the windows above current one. 3. Paint all the visible windows from bottom to top. Subtract the region of ignore from the painting region. If we need to paint shadow, we subtract the body of the window from the shadow painting region too, because we don't want shadow behind the window. 4. region of ignore is invalidated when window stack change, an window on top moved or changed shape, when window changed between opaque and transparent, etc. Notes: It is unclear whether all the different shapes of a window (extents, noframe, border, bounding shape, etc) are calculated correctly or not. It is unclear if window shape related events are handled correctly or not. Need more testing. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
56f7dd36f6
commit
28a2cc62fa
120
src/common.h
120
src/common.h
|
@ -97,6 +97,7 @@
|
||||||
#ifdef CONFIG_XINERAMA
|
#ifdef CONFIG_XINERAMA
|
||||||
#include <xcb/xinerama.h>
|
#include <xcb/xinerama.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <pixman.h>
|
||||||
|
|
||||||
// Workarounds for missing definitions in very old versions of X headers,
|
// Workarounds for missing definitions in very old versions of X headers,
|
||||||
// thanks to consolers for reporting
|
// thanks to consolers for reporting
|
||||||
|
@ -171,6 +172,9 @@
|
||||||
#include "xrescheck.h"
|
#include "xrescheck.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "x.h"
|
||||||
|
#include "region.h"
|
||||||
|
|
||||||
// === Constants ===
|
// === Constants ===
|
||||||
|
|
||||||
/// @brief Length of generic buffers.
|
/// @brief Length of generic buffers.
|
||||||
|
@ -509,12 +513,6 @@ typedef struct _latom {
|
||||||
struct _latom *next;
|
struct _latom *next;
|
||||||
} latom_t;
|
} latom_t;
|
||||||
|
|
||||||
/// A representation of raw region data
|
|
||||||
typedef struct {
|
|
||||||
XRectangle *rects;
|
|
||||||
int nrects;
|
|
||||||
} reg_data_t;
|
|
||||||
|
|
||||||
#define REG_DATA_INIT { NULL, 0 }
|
#define REG_DATA_INIT { NULL, 0 }
|
||||||
|
|
||||||
struct _timeout_t;
|
struct _timeout_t;
|
||||||
|
@ -522,7 +520,7 @@ struct _timeout_t;
|
||||||
typedef struct win win;
|
typedef struct win win;
|
||||||
|
|
||||||
/// Structure representing all options.
|
/// Structure representing all options.
|
||||||
typedef struct _options_t {
|
typedef struct options_t {
|
||||||
// === General ===
|
// === General ===
|
||||||
/// The configuration file we used.
|
/// The configuration file we used.
|
||||||
char *config_file;
|
char *config_file;
|
||||||
|
@ -626,8 +624,8 @@ typedef struct _options_t {
|
||||||
int shadow_radius;
|
int shadow_radius;
|
||||||
int shadow_offset_x, shadow_offset_y;
|
int shadow_offset_x, shadow_offset_y;
|
||||||
double shadow_opacity;
|
double shadow_opacity;
|
||||||
/// Geometry of a region in which shadow is not painted on.
|
/// argument string to shadow-exclude-reg option
|
||||||
geometry_t shadow_exclude_reg_geom;
|
char *shadow_exclude_reg_str;
|
||||||
/// Shadow blacklist. A linked list of conditions.
|
/// Shadow blacklist. A linked list of conditions.
|
||||||
c2_lptr_t *shadow_blacklist;
|
c2_lptr_t *shadow_blacklist;
|
||||||
/// Whether bounding-shaped window should be ignored.
|
/// Whether bounding-shaped window should be ignored.
|
||||||
|
@ -809,7 +807,7 @@ typedef struct session {
|
||||||
/// Picture of the root window background.
|
/// Picture of the root window background.
|
||||||
paint_t root_tile_paint;
|
paint_t root_tile_paint;
|
||||||
/// A region of the size of the screen.
|
/// A region of the size of the screen.
|
||||||
XserverRegion screen_reg;
|
region_t screen_reg;
|
||||||
/// Picture of root window. Destination of painting in no-DBE painting
|
/// Picture of root window. Destination of painting in no-DBE painting
|
||||||
/// mode.
|
/// mode.
|
||||||
xcb_render_picture_t root_picture;
|
xcb_render_picture_t root_picture;
|
||||||
|
@ -854,15 +852,13 @@ typedef struct session {
|
||||||
/// Program start time.
|
/// Program start time.
|
||||||
struct timeval time_start;
|
struct timeval time_start;
|
||||||
/// The region needs to painted on next paint.
|
/// The region needs to painted on next paint.
|
||||||
XserverRegion all_damage;
|
region_t all_damage;
|
||||||
/// The region damaged on the last paint.
|
/// The region damaged on the last paint.
|
||||||
XserverRegion all_damage_last[CGLX_MAX_BUFFER_AGE];
|
region_t all_damage_last[CGLX_MAX_BUFFER_AGE];
|
||||||
/// Whether all windows are currently redirected.
|
/// Whether all windows are currently redirected.
|
||||||
bool redirected;
|
bool redirected;
|
||||||
/// Pre-generated alpha pictures.
|
/// Pre-generated alpha pictures.
|
||||||
xcb_render_picture_t *alpha_picts;
|
xcb_render_picture_t *alpha_picts;
|
||||||
/// Whether all reg_ignore of windows should expire in this paint.
|
|
||||||
bool reg_ignore_expire;
|
|
||||||
/// Time of last fading. In milliseconds.
|
/// Time of last fading. In milliseconds.
|
||||||
time_ms_t fade_time;
|
time_ms_t fade_time;
|
||||||
/// Head pointer of the error ignore linked list.
|
/// Head pointer of the error ignore linked list.
|
||||||
|
@ -877,7 +873,8 @@ typedef struct session {
|
||||||
|
|
||||||
// === Expose event related ===
|
// === Expose event related ===
|
||||||
/// Pointer to an array of <code>XRectangle</code>-s of exposed region.
|
/// Pointer to an array of <code>XRectangle</code>-s of exposed region.
|
||||||
XRectangle *expose_rects;
|
/// XXX why do we need this array?
|
||||||
|
rect_t *expose_rects;
|
||||||
/// Number of <code>XRectangle</code>-s in <code>expose_rects</code>.
|
/// Number of <code>XRectangle</code>-s in <code>expose_rects</code>.
|
||||||
int size_expose;
|
int size_expose;
|
||||||
/// Index of the next free slot in <code>expose_rects</code>.
|
/// Index of the next free slot in <code>expose_rects</code>.
|
||||||
|
@ -913,7 +910,7 @@ typedef struct session {
|
||||||
/// Pre-computed color table for a side of shadow.
|
/// Pre-computed color table for a side of shadow.
|
||||||
unsigned char *shadow_top;
|
unsigned char *shadow_top;
|
||||||
/// A region in which shadow is not painted on.
|
/// A region in which shadow is not painted on.
|
||||||
XserverRegion shadow_exclude_reg;
|
region_t shadow_exclude_reg;
|
||||||
|
|
||||||
// === Software-optimization-related ===
|
// === Software-optimization-related ===
|
||||||
/// Currently used refresh rate.
|
/// Currently used refresh rate.
|
||||||
|
@ -979,7 +976,7 @@ typedef struct session {
|
||||||
/// Xinerama screen info.
|
/// Xinerama screen info.
|
||||||
xcb_xinerama_query_screens_reply_t *xinerama_scrs;
|
xcb_xinerama_query_screens_reply_t *xinerama_scrs;
|
||||||
/// Xinerama screen regions.
|
/// Xinerama screen regions.
|
||||||
XserverRegion *xinerama_scr_regs;
|
region_t *xinerama_scr_regs;
|
||||||
/// Number of Xinerama screens.
|
/// Number of Xinerama screens.
|
||||||
int xinerama_nscrs;
|
int xinerama_nscrs;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1036,7 +1033,7 @@ typedef struct session {
|
||||||
|
|
||||||
/// Structure representing a top-level window compton manages.
|
/// Structure representing a top-level window compton manages.
|
||||||
struct win {
|
struct win {
|
||||||
/// Pointer to the next structure in the linked list.
|
/// Pointer to the next lower window in window stack.
|
||||||
win *next;
|
win *next;
|
||||||
/// Pointer to the next higher window to paint.
|
/// Pointer to the next higher window to paint.
|
||||||
win *prev_trans;
|
win *prev_trans;
|
||||||
|
@ -1068,9 +1065,7 @@ struct win {
|
||||||
/// Paint info of the window.
|
/// Paint info of the window.
|
||||||
paint_t paint;
|
paint_t paint;
|
||||||
/// Bounding shape of the window.
|
/// Bounding shape of the window.
|
||||||
XserverRegion border_size;
|
region_t bounding_shape;
|
||||||
/// Region of the whole window, shadow region included.
|
|
||||||
XserverRegion extents;
|
|
||||||
/// Window flags. Definitions above.
|
/// Window flags. Definitions above.
|
||||||
int_fast16_t flags;
|
int_fast16_t flags;
|
||||||
/// Whether there's a pending <code>ConfigureNotify</code> happening
|
/// Whether there's a pending <code>ConfigureNotify</code> happening
|
||||||
|
@ -1078,11 +1073,15 @@ struct win {
|
||||||
bool need_configure;
|
bool need_configure;
|
||||||
/// Queued <code>ConfigureNotify</code> when the window is unmapped.
|
/// Queued <code>ConfigureNotify</code> when the window is unmapped.
|
||||||
xcb_configure_notify_event_t queue_configure;
|
xcb_configure_notify_event_t queue_configure;
|
||||||
/// Region to be ignored when painting. Basically the region where
|
/// The region of screen that will be obscured when windows above is painted.
|
||||||
/// higher opaque windows will paint upon. Depends on window frame
|
/// We use this to reduce the pixels that needed to be paint when painting
|
||||||
|
/// this window and anything underneath. Depends on window frame
|
||||||
/// opacity state, window geometry, window mapped/unmapped state,
|
/// opacity state, window geometry, window mapped/unmapped state,
|
||||||
/// window mode, of this and all higher windows.
|
/// window mode of the windows above. DOES NOT INCLUDE the body of THIS WINDOW.
|
||||||
XserverRegion reg_ignore;
|
/// NULL means reg_ignore has not been calculated for this window.
|
||||||
|
rc_region_t *reg_ignore;
|
||||||
|
/// Whether the reg_ignore of all windows beneath this window are valid
|
||||||
|
bool reg_ignore_valid;
|
||||||
/// Cached width/height of the window including border.
|
/// Cached width/height of the window including border.
|
||||||
int widthb, heightb;
|
int widthb, heightb;
|
||||||
/// Whether the window has been destroyed.
|
/// Whether the window has been destroyed.
|
||||||
|
@ -1279,38 +1278,6 @@ print_backtrace(void) {
|
||||||
free(strings);
|
free(strings);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC_REG
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper of <code>XFixesCreateRegion</code>, for debugging.
|
|
||||||
*/
|
|
||||||
static inline XserverRegion
|
|
||||||
XFixesCreateRegion_(Display *dpy, XRectangle *p, int n,
|
|
||||||
const char *func, int line) {
|
|
||||||
XserverRegion reg = XFixesCreateRegion(dpy, p, n);
|
|
||||||
print_timestamp(ps_g);
|
|
||||||
printf("%#010lx: XFixesCreateRegion() in %s():%d\n", reg, func, line);
|
|
||||||
print_backtrace();
|
|
||||||
fflush(stdout);
|
|
||||||
return reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper of <code>XFixesDestroyRegion</code>, for debugging.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
XFixesDestroyRegion_(Display *dpy, XserverRegion reg,
|
|
||||||
const char *func, int line) {
|
|
||||||
XFixesDestroyRegion(dpy, reg);
|
|
||||||
print_timestamp(ps_g);
|
|
||||||
printf("%#010lx: XFixesDestroyRegion() in %s():%d\n", reg, func, line);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define XFixesCreateRegion(dpy, p, n) XFixesCreateRegion_(dpy, p, n, __func__, __LINE__)
|
|
||||||
#define XFixesDestroyRegion(dpy, reg) XFixesDestroyRegion_(dpy, reg, __func__, __LINE__)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// === Functions ===
|
// === Functions ===
|
||||||
|
@ -1903,39 +1870,13 @@ find_focused(session_t *ps) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies a region.
|
|
||||||
*/
|
|
||||||
static inline XserverRegion
|
|
||||||
copy_region(const session_t *ps, XserverRegion oldregion) {
|
|
||||||
if (!oldregion)
|
|
||||||
return None;
|
|
||||||
|
|
||||||
XserverRegion region = XFixesCreateRegion(ps->dpy, NULL, 0);
|
|
||||||
|
|
||||||
XFixesCopyRegion(ps->dpy, region, oldregion);
|
|
||||||
|
|
||||||
return region;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy a <code>XserverRegion</code>.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
free_region(session_t *ps, XserverRegion *p) {
|
|
||||||
if (*p) {
|
|
||||||
XFixesDestroyRegion(ps->dpy, *p);
|
|
||||||
*p = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free all regions in ps->all_damage_last .
|
* Free all regions in ps->all_damage_last .
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
free_all_damage_last(session_t *ps) {
|
free_all_damage_last(session_t *ps) {
|
||||||
for (int i = 0; i < CGLX_MAX_BUFFER_AGE; ++i)
|
for (int i = 0; i < CGLX_MAX_BUFFER_AGE; ++i)
|
||||||
free_region(ps, &ps->all_damage_last[i]);
|
pixman_region32_clear(&ps->all_damage_last[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_XSYNC
|
#ifdef CONFIG_XSYNC
|
||||||
|
@ -1958,12 +1899,13 @@ free_fence(session_t *ps, XSyncFence *pfence) {
|
||||||
* psrc and pdst cannot be the same.
|
* psrc and pdst cannot be the same.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
rect_crop(XRectangle *pdst, const XRectangle *psrc, const XRectangle *pbound) {
|
rect_crop(rect_t *restrict pdst, const rect_t *psrc, const rect_t *pbound) {
|
||||||
assert(psrc != pdst);
|
assert(psrc != pdst);
|
||||||
pdst->x = max_i(psrc->x, pbound->x);
|
assert(psrc != pbound);
|
||||||
pdst->y = max_i(psrc->y, pbound->y);
|
pdst->x1 = max_i(psrc->x1, pbound->x1);
|
||||||
pdst->width = max_i(0, min_i(psrc->x + psrc->width, pbound->x + pbound->width) - pdst->x);
|
pdst->y1 = max_i(psrc->y1, pbound->y1);
|
||||||
pdst->height = max_i(0, min_i(psrc->y + psrc->height, pbound->y + pbound->height) - pdst->y);
|
pdst->x2 = min_i(psrc->x2, pbound->x2);
|
||||||
|
pdst->y2 = min_i(psrc->y2, pbound->y2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
797
src/compton.c
797
src/compton.c
File diff suppressed because it is too large
Load Diff
183
src/compton.h
183
src/compton.h
|
@ -25,10 +25,12 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <pixman.h>
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
#include "opengl.h"
|
#include "opengl.h" // XXX clean up
|
||||||
#endif
|
#endif
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "x.h"
|
||||||
#include "c2.h"
|
#include "c2.h"
|
||||||
|
|
||||||
// == Functions ==
|
// == Functions ==
|
||||||
|
@ -38,7 +40,7 @@
|
||||||
// inline functions must be made static to compile correctly under clang:
|
// inline functions must be made static to compile correctly under clang:
|
||||||
// http://clang.llvm.org/compatibility.html#inline
|
// http://clang.llvm.org/compatibility.html#inline
|
||||||
|
|
||||||
void add_damage(session_t *ps, XserverRegion damage);
|
void add_damage(session_t *ps, const region_t *damage);
|
||||||
|
|
||||||
long determine_evmask(session_t *ps, Window wid, win_evmode_t mode);
|
long determine_evmask(session_t *ps, Window wid, win_evmode_t mode);
|
||||||
|
|
||||||
|
@ -53,9 +55,7 @@ void
|
||||||
render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
|
render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
|
||||||
double opacity, bool argb, bool neg,
|
double opacity, bool argb, bool neg,
|
||||||
xcb_render_picture_t pict, glx_texture_t *ptex,
|
xcb_render_picture_t pict, glx_texture_t *ptex,
|
||||||
XserverRegion reg_paint, const reg_data_t *pcache_reg
|
const region_t *reg_paint, const glx_prog_main_t *pprogram);
|
||||||
, const glx_prog_main_t *pprogram
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset filter on a <code>Picture</code>.
|
* Reset filter on a <code>Picture</code>.
|
||||||
|
@ -108,41 +108,6 @@ array_wid_exists(const Window *arr, int count, Window wid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a geometry_t value to XRectangle.
|
|
||||||
*/
|
|
||||||
static inline XRectangle
|
|
||||||
geom_to_rect(session_t *ps, const geometry_t *src, const XRectangle *def) {
|
|
||||||
XRectangle rect_def = { .x = 0, .y = 0,
|
|
||||||
.width = ps->root_width, .height = ps->root_height };
|
|
||||||
if (!def) def = &rect_def;
|
|
||||||
|
|
||||||
XRectangle rect = { .x = src->x, .y = src->y,
|
|
||||||
.width = src->wid, .height = src->hei };
|
|
||||||
if (src->wid < 0) rect.width = def->width;
|
|
||||||
if (src->hei < 0) rect.height = def->height;
|
|
||||||
if (-1 == src->x) rect.x = def->x;
|
|
||||||
else if (src->x < 0) rect.x = ps->root_width + rect.x + 2 - rect.width;
|
|
||||||
if (-1 == src->y) rect.y = def->y;
|
|
||||||
else if (src->y < 0) rect.y = ps->root_height + rect.y + 2 - rect.height;
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a XRectangle to a XServerRegion.
|
|
||||||
*/
|
|
||||||
static inline XserverRegion
|
|
||||||
rect_to_reg(session_t *ps, const XRectangle *src) {
|
|
||||||
if (!src) return None;
|
|
||||||
XRectangle bound = { .x = 0, .y = 0,
|
|
||||||
.width = ps->root_width, .height = ps->root_height };
|
|
||||||
XRectangle res = { };
|
|
||||||
rect_crop(&res, src, &bound);
|
|
||||||
if (res.width && res.height)
|
|
||||||
return XFixesCreateRegion(ps->dpy, &res, 1);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy a <code>Picture</code>.
|
* Destroy a <code>Picture</code>.
|
||||||
*/
|
*/
|
||||||
|
@ -185,7 +150,7 @@ free_xinerama_info(session_t *ps) {
|
||||||
#ifdef CONFIG_XINERAMA
|
#ifdef CONFIG_XINERAMA
|
||||||
if (ps->xinerama_scr_regs) {
|
if (ps->xinerama_scr_regs) {
|
||||||
for (int i = 0; i < ps->xinerama_nscrs; ++i)
|
for (int i = 0; i < ps->xinerama_nscrs; ++i)
|
||||||
free_region(ps, &ps->xinerama_scr_regs[i]);
|
pixman_region32_fini(&ps->xinerama_scr_regs[i]);
|
||||||
free(ps->xinerama_scr_regs);
|
free(ps->xinerama_scr_regs);
|
||||||
}
|
}
|
||||||
cxfree(ps->xinerama_scrs);
|
cxfree(ps->xinerama_scrs);
|
||||||
|
@ -227,16 +192,6 @@ free_texture(session_t *ps, glx_texture_t **t) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* Free data in a reg_data_t.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
free_reg_data(reg_data_t *pregd) {
|
|
||||||
cxfree(pregd->rects);
|
|
||||||
pregd->rects = NULL;
|
|
||||||
pregd->nrects = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free paint_t.
|
* Free paint_t.
|
||||||
*/
|
*/
|
||||||
|
@ -262,12 +217,11 @@ free_wpaint(session_t *ps, win *w) {
|
||||||
static inline void
|
static inline void
|
||||||
free_win_res(session_t *ps, win *w) {
|
free_win_res(session_t *ps, win *w) {
|
||||||
free_win_res_glx(ps, w);
|
free_win_res_glx(ps, w);
|
||||||
free_region(ps, &w->extents);
|
|
||||||
free_paint(ps, &w->paint);
|
free_paint(ps, &w->paint);
|
||||||
free_region(ps, &w->border_size);
|
pixman_region32_fini(&w->bounding_shape);
|
||||||
free_paint(ps, &w->shadow_paint);
|
free_paint(ps, &w->shadow_paint);
|
||||||
free_damage(ps, &w->damage);
|
free_damage(ps, &w->damage);
|
||||||
free_region(ps, &w->reg_ignore);
|
rc_region_unref(&w->reg_ignore);
|
||||||
free(w->name);
|
free(w->name);
|
||||||
free(w->class_instance);
|
free(w->class_instance);
|
||||||
free(w->class_general);
|
free(w->class_general);
|
||||||
|
@ -389,16 +343,6 @@ wid_get_children(session_t *ps, Window w,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if a window change affects <code>reg_ignore</code> and set
|
|
||||||
* <code>reg_ignore_expire</code> accordingly.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
update_reg_ignore_expire(session_t *ps, const win *w) {
|
|
||||||
if (w->to_paint && WMODE_SOLID == w->mode)
|
|
||||||
ps->reg_ignore_expire = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether a window has WM frames.
|
* Check whether a window has WM frames.
|
||||||
*/
|
*/
|
||||||
|
@ -482,38 +426,6 @@ find_win_all(session_t *ps, const Window wid) {
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool win_has_alpha(win *);
|
|
||||||
static inline void
|
|
||||||
win_render(session_t *ps, win *w, int x, int y, int wid, int hei,
|
|
||||||
double opacity, XserverRegion reg_paint, const reg_data_t *pcache_reg,
|
|
||||||
xcb_render_picture_t pict) {
|
|
||||||
const int dx = (w ? w->g.x: 0) + x;
|
|
||||||
const int dy = (w ? w->g.y: 0) + y;
|
|
||||||
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, pcache_reg, (w ? &ps->o.glx_prog_win: NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
set_tgt_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg) {
|
|
||||||
switch (ps->o.backend) {
|
|
||||||
case BKEND_XRENDER:
|
|
||||||
case BKEND_XR_GLX_HYBRID:
|
|
||||||
XFixesSetPictureClipRegion(ps->dpy, ps->tgt_buffer.pict, 0, 0, reg);
|
|
||||||
break;
|
|
||||||
#ifdef CONFIG_OPENGL
|
|
||||||
case BKEND_GLX:
|
|
||||||
glx_set_clip(ps, reg, pcache_reg);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize a convolution kernel.
|
* Normalize a convolution kernel.
|
||||||
*/
|
*/
|
||||||
|
@ -527,87 +439,38 @@ normalize_conv_kern(int wid, int hei, xcb_render_fixed_t *kern) {
|
||||||
kern[i] = DOUBLE_TO_XFIXED(XFIXED_TO_DOUBLE(kern[i]) * factor);
|
kern[i] = DOUBLE_TO_XFIXED(XFIXED_TO_DOUBLE(kern[i]) * factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a region of the screen size.
|
|
||||||
*/
|
|
||||||
inline static XserverRegion
|
|
||||||
get_screen_region(session_t *ps) {
|
|
||||||
XRectangle r;
|
|
||||||
|
|
||||||
r.x = 0;
|
|
||||||
r.y = 0;
|
|
||||||
r.width = ps->root_width;
|
|
||||||
r.height = ps->root_height;
|
|
||||||
return XFixesCreateRegion(ps->dpy, &r, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resize a region.
|
* Resize a region.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
resize_region(session_t *ps, XserverRegion region, short mod) {
|
resize_region(session_t *ps, region_t *region, short mod) {
|
||||||
if (!mod || !region) return;
|
if (!mod || !region) return;
|
||||||
|
|
||||||
int nrects = 0, nnewrects = 0;
|
|
||||||
XRectangle *newrects = NULL;
|
|
||||||
XRectangle *rects = XFixesFetchRegion(ps->dpy, region, &nrects);
|
|
||||||
if (!rects || !nrects)
|
|
||||||
goto resize_region_end;
|
|
||||||
|
|
||||||
// Allocate memory for new rectangle list, because I don't know if it's
|
|
||||||
// safe to write in the memory Xlib allocates
|
|
||||||
newrects = calloc(nrects, sizeof(XRectangle));
|
|
||||||
if (!newrects) {
|
|
||||||
printf_errf("(): Failed to allocate memory.");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through all rectangles
|
// Loop through all rectangles
|
||||||
for (int i = 0; i < nrects; ++i) {
|
int nrects;
|
||||||
int x1 = max_i(rects[i].x - mod, 0);
|
int nnewrects = 0;
|
||||||
int y1 = max_i(rects[i].y - mod, 0);
|
pixman_box32_t *rects = pixman_region32_rectangles(region, &nrects);
|
||||||
int x2 = min_i(rects[i].x + rects[i].width + mod, ps->root_width);
|
pixman_box32_t *newrects = calloc(nrects, sizeof *newrects);
|
||||||
int y2 = min_i(rects[i].y + rects[i].height + mod, ps->root_height);
|
for (int i = 0; i < nrects; i++) {
|
||||||
|
int x1 = max_i(rects[i].x1 - mod, 0);
|
||||||
|
int y1 = max_i(rects[i].y1 - mod, 0);
|
||||||
|
int x2 = min_i(rects[i].x2 + mod, ps->root_width);
|
||||||
|
int y2 = min_i(rects[i].y2 + mod, ps->root_height);
|
||||||
int wid = x2 - x1;
|
int wid = x2 - x1;
|
||||||
int hei = y2 - y1;
|
int hei = y2 - y1;
|
||||||
if (wid <= 0 || hei <= 0)
|
if (wid <= 0 || hei <= 0)
|
||||||
continue;
|
continue;
|
||||||
newrects[nnewrects].x = x1;
|
newrects[nnewrects] = (pixman_box32_t) {
|
||||||
newrects[nnewrects].y = y1;
|
.x1 = x1, .x2 = x2, .y1 = y1, .y2 = y2
|
||||||
newrects[nnewrects].width = wid;
|
};
|
||||||
newrects[nnewrects].height = hei;
|
|
||||||
++nnewrects;
|
++nnewrects;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set region
|
pixman_region32_fini(region);
|
||||||
XFixesSetRegion(ps->dpy, region, newrects, nnewrects);
|
pixman_region32_init_rects(region, newrects, nnewrects);
|
||||||
|
|
||||||
resize_region_end:
|
|
||||||
cxfree(rects);
|
|
||||||
free(newrects);
|
free(newrects);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Dump a region.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
dump_region(const session_t *ps, XserverRegion region) {
|
|
||||||
int nrects = 0;
|
|
||||||
XRectangle *rects = NULL;
|
|
||||||
if (!rects && region)
|
|
||||||
rects = XFixesFetchRegion(ps->dpy, region, &nrects);
|
|
||||||
|
|
||||||
printf_dbgf("(%#010lx): %d rects\n", region, nrects);
|
|
||||||
if (!rects) return;
|
|
||||||
for (int i = 0; i < nrects; ++i)
|
|
||||||
printf("Rect #%d: %8d, %8d, %8d, %8d\n", i, rects[i].x, rects[i].y,
|
|
||||||
rects[i].width, rects[i].height);
|
|
||||||
putchar('\n');
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
cxfree(rects);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
/**
|
/**
|
||||||
* Ensure we have a GLX context.
|
* Ensure we have a GLX context.
|
||||||
|
|
43
src/config.c
43
src/config.c
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "utils.h"
|
||||||
#include "c2.h"
|
#include "c2.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -201,19 +202,24 @@ parse_conv_kern_lst(session_t *ps, const char *src, xcb_render_fixed_t **dest, i
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a X geometry.
|
* Parse a X geometry.
|
||||||
|
*
|
||||||
|
* ps->root_width and ps->root_height must be valid
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
parse_geometry(session_t *ps, const char *src, geometry_t *dest) {
|
parse_geometry(session_t *ps, const char *src, region_t *dest) {
|
||||||
|
pixman_region32_clear(dest);
|
||||||
|
if (!src)
|
||||||
|
return true;
|
||||||
|
if (!ps->root_width || !ps->root_height)
|
||||||
|
return true;
|
||||||
|
|
||||||
geometry_t geom = { .wid = -1, .hei = -1, .x = -1, .y = -1 };
|
geometry_t geom = { .wid = -1, .hei = -1, .x = -1, .y = -1 };
|
||||||
long val = 0L;
|
long val = 0L;
|
||||||
char *endptr = NULL;
|
char *endptr = NULL;
|
||||||
|
|
||||||
#define T_STRIPSPACE() do { \
|
src = skip_space(src);
|
||||||
while (*src && isspace(*src)) ++src; \
|
if (!*src)
|
||||||
if (!*src) goto parse_geometry_end; \
|
goto parse_geometry_end;
|
||||||
} while(0)
|
|
||||||
|
|
||||||
T_STRIPSPACE();
|
|
||||||
|
|
||||||
// Parse width
|
// Parse width
|
||||||
// Must be base 10, because "0x0..." may appear
|
// Must be base 10, because "0x0..." may appear
|
||||||
|
@ -221,10 +227,13 @@ parse_geometry(session_t *ps, const char *src, geometry_t *dest) {
|
||||||
val = strtol(src, &endptr, 10);
|
val = strtol(src, &endptr, 10);
|
||||||
if (endptr && src != endptr) {
|
if (endptr && src != endptr) {
|
||||||
geom.wid = val;
|
geom.wid = val;
|
||||||
assert(geom.wid >= 0);
|
if (geom.wid < 0) {
|
||||||
|
printf_errf("(\"%s\"): Invalid width.", src);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
src = endptr;
|
src = endptr;
|
||||||
}
|
}
|
||||||
T_STRIPSPACE();
|
src = skip_space(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse height
|
// Parse height
|
||||||
|
@ -239,7 +248,7 @@ parse_geometry(session_t *ps, const char *src, geometry_t *dest) {
|
||||||
}
|
}
|
||||||
src = endptr;
|
src = endptr;
|
||||||
}
|
}
|
||||||
T_STRIPSPACE();
|
src = skip_space(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse x
|
// Parse x
|
||||||
|
@ -247,11 +256,11 @@ parse_geometry(session_t *ps, const char *src, geometry_t *dest) {
|
||||||
val = strtol(src, &endptr, 10);
|
val = strtol(src, &endptr, 10);
|
||||||
if (endptr && src != endptr) {
|
if (endptr && src != endptr) {
|
||||||
geom.x = val;
|
geom.x = val;
|
||||||
if ('-' == *src && geom.x <= 0)
|
if (*src == '-')
|
||||||
geom.x -= 2;
|
geom.x += ps->root_width - geom.wid;
|
||||||
src = endptr;
|
src = endptr;
|
||||||
}
|
}
|
||||||
T_STRIPSPACE();
|
src = skip_space(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse y
|
// Parse y
|
||||||
|
@ -259,11 +268,11 @@ parse_geometry(session_t *ps, const char *src, geometry_t *dest) {
|
||||||
val = strtol(src, &endptr, 10);
|
val = strtol(src, &endptr, 10);
|
||||||
if (endptr && src != endptr) {
|
if (endptr && src != endptr) {
|
||||||
geom.y = val;
|
geom.y = val;
|
||||||
if ('-' == *src && geom.y <= 0)
|
if (*src == '-')
|
||||||
geom.y -= 2;
|
geom.y += ps->root_height - geom.hei;
|
||||||
src = endptr;
|
src = endptr;
|
||||||
}
|
}
|
||||||
T_STRIPSPACE();
|
src = skip_space(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*src) {
|
if (*src) {
|
||||||
|
@ -272,7 +281,7 @@ parse_geometry(session_t *ps, const char *src, geometry_t *dest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_geometry_end:
|
parse_geometry_end:
|
||||||
*dest = geom;
|
pixman_region32_union_rect(dest, dest, geom.x, geom.y, geom.wid, geom.hei);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ const char *parse_matrix_readnum(const char *, double *);
|
||||||
xcb_render_fixed_t *parse_matrix(session_t *, const char *, const char **);
|
xcb_render_fixed_t *parse_matrix(session_t *, const char *, const char **);
|
||||||
xcb_render_fixed_t *parse_conv_kern(session_t *, const char *, const char **);
|
xcb_render_fixed_t *parse_conv_kern(session_t *, const char *, const char **);
|
||||||
bool parse_conv_kern_lst(session_t *, const char *, xcb_render_fixed_t **, int);
|
bool parse_conv_kern_lst(session_t *, const char *, xcb_render_fixed_t **, int);
|
||||||
bool parse_geometry(session_t *, const char *, geometry_t *);
|
bool parse_geometry(session_t *, const char *, region_t *);
|
||||||
bool parse_rule_opacity(session_t *, const char *);
|
bool parse_rule_opacity(session_t *, const char *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -269,9 +269,8 @@ parse_config(session_t *ps, struct options_tmp *pcfgtmp) {
|
||||||
// --shadow-blue
|
// --shadow-blue
|
||||||
config_lookup_float(&cfg, "shadow-blue", &ps->o.shadow_blue);
|
config_lookup_float(&cfg, "shadow-blue", &ps->o.shadow_blue);
|
||||||
// --shadow-exclude-reg
|
// --shadow-exclude-reg
|
||||||
if (config_lookup_string(&cfg, "shadow-exclude-reg", &sval)
|
if (config_lookup_string(&cfg, "shadow-exclude-reg", &sval))
|
||||||
&& !parse_geometry(ps, sval, &ps->o.shadow_exclude_reg_geom))
|
ps->o.shadow_exclude_reg_str = strdup(sval);
|
||||||
exit(1);
|
|
||||||
// --inactive-opacity-override
|
// --inactive-opacity-override
|
||||||
lcfg_lookup_bool(&cfg, "inactive-opacity-override",
|
lcfg_lookup_bool(&cfg, "inactive-opacity-override",
|
||||||
&ps->o.inactive_opacity_override);
|
&ps->o.inactive_opacity_override);
|
||||||
|
|
274
src/opengl.c
274
src/opengl.c
|
@ -900,7 +900,7 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
|
||||||
* Preprocess function before start painting.
|
* Preprocess function before start painting.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
glx_paint_pre(session_t *ps, XserverRegion *preg) {
|
glx_paint_pre(session_t *ps, region_t *preg) {
|
||||||
ps->psglx->z = 0.0;
|
ps->psglx->z = 0.0;
|
||||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
@ -908,22 +908,17 @@ glx_paint_pre(session_t *ps, XserverRegion *preg) {
|
||||||
bool trace_damage = (ps->o.glx_swap_method < 0 || ps->o.glx_swap_method > 1);
|
bool trace_damage = (ps->o.glx_swap_method < 0 || ps->o.glx_swap_method > 1);
|
||||||
|
|
||||||
// Trace raw damage regions
|
// Trace raw damage regions
|
||||||
XserverRegion newdamage = None;
|
region_t newdamage;
|
||||||
if (trace_damage && *preg)
|
pixman_region32_init(&newdamage);
|
||||||
newdamage = copy_region(ps, *preg);
|
if (trace_damage)
|
||||||
|
copy_region(&newdamage, preg);
|
||||||
|
|
||||||
// OpenGL doesn't support partial repaint without GLX_MESA_copy_sub_buffer,
|
// We use GLX buffer_age extension to decide which pixels in
|
||||||
// we could redraw the whole screen or copy unmodified pixels from
|
// the back buffer is reusable, and limit our redrawing
|
||||||
// front buffer with --glx-copy-from-front.
|
int buffer_age = 0;
|
||||||
if (ps->o.glx_use_copysubbuffermesa || !*preg) {
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int buffer_age = ps->o.glx_swap_method;
|
|
||||||
|
|
||||||
// Getting buffer age
|
|
||||||
{
|
|
||||||
// Query GLX_EXT_buffer_age for buffer age
|
// Query GLX_EXT_buffer_age for buffer age
|
||||||
if (SWAPM_BUFFER_AGE == buffer_age) {
|
if (ps->o.glx_swap_method == SWAPM_BUFFER_AGE) {
|
||||||
unsigned val = 0;
|
unsigned val = 0;
|
||||||
glXQueryDrawable(ps->dpy, get_tgt_window(ps),
|
glXQueryDrawable(ps->dpy, get_tgt_window(ps),
|
||||||
GLX_BACK_BUFFER_AGE_EXT, &val);
|
GLX_BACK_BUFFER_AGE_EXT, &val);
|
||||||
|
@ -934,81 +929,25 @@ glx_paint_pre(session_t *ps, XserverRegion *preg) {
|
||||||
if (buffer_age > CGLX_MAX_BUFFER_AGE + 1)
|
if (buffer_age > CGLX_MAX_BUFFER_AGE + 1)
|
||||||
buffer_age = 0;
|
buffer_age = 0;
|
||||||
|
|
||||||
// Make sure buffer age >= 0
|
assert(buffer_age >= 0);
|
||||||
buffer_age = max_i(buffer_age, 0);
|
|
||||||
|
|
||||||
// Check if we have we have empty regions
|
|
||||||
if (buffer_age > 1) {
|
|
||||||
for (int i = 0; i < buffer_age - 1; ++i)
|
|
||||||
if (!ps->all_damage_last[i]) { buffer_age = 0; break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do nothing for buffer_age 1 (copy)
|
|
||||||
if (1 != buffer_age) {
|
|
||||||
// Copy pixels
|
|
||||||
if (ps->o.glx_copy_from_front) {
|
|
||||||
// Determine copy area
|
|
||||||
XserverRegion reg_copy = XFixesCreateRegion(ps->dpy, NULL, 0);
|
|
||||||
if (!buffer_age) {
|
|
||||||
XFixesSubtractRegion(ps->dpy, reg_copy, ps->screen_reg, *preg);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (int i = 0; i < buffer_age - 1; ++i)
|
|
||||||
XFixesUnionRegion(ps->dpy, reg_copy, reg_copy,
|
|
||||||
ps->all_damage_last[i]);
|
|
||||||
XFixesSubtractRegion(ps->dpy, reg_copy, reg_copy, *preg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actually copy pixels
|
|
||||||
{
|
|
||||||
GLfloat raster_pos[4];
|
|
||||||
GLfloat curx = 0.0f, cury = 0.0f;
|
|
||||||
glGetFloatv(GL_CURRENT_RASTER_POSITION, raster_pos);
|
|
||||||
glReadBuffer(GL_FRONT);
|
|
||||||
glRasterPos2f(0.0, 0.0);
|
|
||||||
{
|
|
||||||
int nrects = 0;
|
|
||||||
XRectangle *rects = XFixesFetchRegion(ps->dpy, reg_copy, &nrects);
|
|
||||||
for (int i = 0; i < nrects; ++i) {
|
|
||||||
const int x = rects[i].x;
|
|
||||||
const int y = ps->root_height - rects[i].y - rects[i].height;
|
|
||||||
// Kwin patch says glRasterPos2f() causes artifacts on bottom
|
|
||||||
// screen edge with some drivers
|
|
||||||
glBitmap(0, 0, 0, 0, x - curx, y - cury, NULL);
|
|
||||||
curx = x;
|
|
||||||
cury = y;
|
|
||||||
glCopyPixels(x, y, rects[i].width, rects[i].height, GL_COLOR);
|
|
||||||
}
|
|
||||||
cxfree(rects);
|
|
||||||
}
|
|
||||||
glReadBuffer(GL_BACK);
|
|
||||||
glRasterPos4fv(raster_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
free_region(ps, ®_copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (buffer_age) {
|
||||||
// Determine paint area
|
// Determine paint area
|
||||||
if (ps->o.glx_copy_from_front) { }
|
|
||||||
else if (buffer_age) {
|
|
||||||
for (int i = 0; i < buffer_age - 1; ++i)
|
for (int i = 0; i < buffer_age - 1; ++i)
|
||||||
XFixesUnionRegion(ps->dpy, *preg, *preg, ps->all_damage_last[i]);
|
pixman_region32_union(preg, preg, &ps->all_damage_last[i]);
|
||||||
}
|
} else
|
||||||
else {
|
// buffer_age == 0 means buffer age is not available, paint everything
|
||||||
free_region(ps, preg);
|
copy_region(preg, &ps->screen_reg);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trace_damage) {
|
if (trace_damage) {
|
||||||
free_region(ps, &ps->all_damage_last[CGLX_MAX_BUFFER_AGE - 1]);
|
// XXX use a circular queue instead of memmove
|
||||||
|
pixman_region32_fini(&ps->all_damage_last[CGLX_MAX_BUFFER_AGE - 1]);
|
||||||
memmove(ps->all_damage_last + 1, ps->all_damage_last,
|
memmove(ps->all_damage_last + 1, ps->all_damage_last,
|
||||||
(CGLX_MAX_BUFFER_AGE - 1) * sizeof(XserverRegion));
|
(CGLX_MAX_BUFFER_AGE - 1) * sizeof(region_t *));
|
||||||
ps->all_damage_last[0] = newdamage;
|
ps->all_damage_last[0] = newdamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
glx_set_clip(ps, *preg, NULL);
|
glx_set_clip(ps, preg);
|
||||||
|
|
||||||
#ifdef DEBUG_GLX_PAINTREG
|
#ifdef DEBUG_GLX_PAINTREG
|
||||||
glx_render_color(ps, 0, 0, ps->root_width, ps->root_height, 0, *preg, NULL);
|
glx_render_color(ps, 0, 0, ps->root_width, ps->root_height, 0, *preg, NULL);
|
||||||
|
@ -1021,118 +960,46 @@ glx_paint_pre(session_t *ps, XserverRegion *preg) {
|
||||||
* Set clipping region on the target window.
|
* Set clipping region on the target window.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *pcache_reg) {
|
glx_set_clip(session_t *ps, const region_t *reg) {
|
||||||
// Quit if we aren't using stencils
|
// Quit if we aren't using stencils
|
||||||
if (ps->o.glx_no_stencil)
|
if (ps->o.glx_no_stencil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
static XRectangle rect_blank = { .x = 0, .y = 0, .width = 0, .height = 0 };
|
|
||||||
|
|
||||||
glDisable(GL_STENCIL_TEST);
|
glDisable(GL_STENCIL_TEST);
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
|
||||||
if (!reg)
|
if (!reg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int nrects = 0;
|
int nrects;
|
||||||
XRectangle *rects_free = NULL;
|
const rect_t *rects = pixman_region32_rectangles((region_t *)reg, &nrects);
|
||||||
const XRectangle *rects = NULL;
|
|
||||||
if (pcache_reg) {
|
|
||||||
rects = pcache_reg->rects;
|
|
||||||
nrects = pcache_reg->nrects;
|
|
||||||
}
|
|
||||||
if (!rects) {
|
|
||||||
nrects = 0;
|
|
||||||
rects = rects_free = XFixesFetchRegion(ps->dpy, reg, &nrects);
|
|
||||||
}
|
|
||||||
// Use one empty rectangle if the region is empty
|
|
||||||
if (!nrects) {
|
|
||||||
cxfree(rects_free);
|
|
||||||
rects_free = NULL;
|
|
||||||
nrects = 1;
|
|
||||||
rects = &rect_blank;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(nrects);
|
if (nrects == 1) {
|
||||||
if (1 == nrects) {
|
|
||||||
glEnable(GL_SCISSOR_TEST);
|
glEnable(GL_SCISSOR_TEST);
|
||||||
glScissor(rects[0].x, ps->root_height - rects[0].y - rects[0].height,
|
glScissor(rects[0].x1, ps->root_height-rects[0].y2,
|
||||||
rects[0].width, rects[0].height);
|
rects[0].x2-rects[0].x1, rects[0].y2-rects[0].y1);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
glEnable(GL_STENCIL_TEST);
|
|
||||||
glClear(GL_STENCIL_BUFFER_BIT);
|
|
||||||
|
|
||||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
|
||||||
glDepthMask(GL_FALSE);
|
|
||||||
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
|
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
|
|
||||||
for (int i = 0; i < nrects; ++i) {
|
|
||||||
GLint rx = rects[i].x;
|
|
||||||
GLint ry = ps->root_height - rects[i].y;
|
|
||||||
GLint rxe = rx + rects[i].width;
|
|
||||||
GLint rye = ry - rects[i].height;
|
|
||||||
GLint z = 0;
|
|
||||||
|
|
||||||
#ifdef DEBUG_GLX
|
|
||||||
printf_dbgf("(): Rect %d: %d, %d, %d, %d\n", i, rx, ry, rxe, rye);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
glVertex3i(rx, ry, z);
|
|
||||||
glVertex3i(rxe, ry, z);
|
|
||||||
glVertex3i(rxe, rye, z);
|
|
||||||
glVertex3i(rx, rye, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
|
||||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
||||||
// glDepthMask(GL_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
cxfree(rects_free);
|
|
||||||
|
|
||||||
glx_check_err(ps);
|
glx_check_err(ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define P_PAINTREG_START() \
|
#define P_PAINTREG_START(var) \
|
||||||
XserverRegion reg_new = None; \
|
region_t reg_new; \
|
||||||
XRectangle rec_all = { .x = dx, .y = dy, .width = width, .height = height }; \
|
int nrects; \
|
||||||
XRectangle *rects = &rec_all; \
|
const rect_t *rects; \
|
||||||
int nrects = 1; \
|
pixman_region32_init_rect(®_new, dx, dy, width, height); \
|
||||||
\
|
pixman_region32_intersect(®_new, ®_new, (region_t *)reg_tgt); \
|
||||||
if (ps->o.glx_no_stencil && reg_tgt) { \
|
rects = pixman_region32_rectangles(®_new, &nrects); \
|
||||||
if (pcache_reg) { \
|
|
||||||
rects = pcache_reg->rects; \
|
|
||||||
nrects = pcache_reg->nrects; \
|
|
||||||
} \
|
|
||||||
else { \
|
|
||||||
reg_new = XFixesCreateRegion(ps->dpy, &rec_all, 1); \
|
|
||||||
XFixesIntersectRegion(ps->dpy, reg_new, reg_new, reg_tgt); \
|
|
||||||
\
|
|
||||||
nrects = 0; \
|
|
||||||
rects = XFixesFetchRegion(ps->dpy, reg_new, &nrects); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
glBegin(GL_QUADS); \
|
glBegin(GL_QUADS); \
|
||||||
\
|
\
|
||||||
for (int ri = 0; ri < nrects; ++ri) { \
|
for (int ri = 0; ri < nrects; ++ri) { \
|
||||||
XRectangle crect; \
|
rect_t var = rects[ri];
|
||||||
rect_crop(&crect, &rects[ri], &rec_all); \
|
|
||||||
\
|
|
||||||
if (!crect.width || !crect.height) \
|
|
||||||
continue; \
|
|
||||||
|
|
||||||
#define P_PAINTREG_END() \
|
#define P_PAINTREG_END() \
|
||||||
} \
|
} \
|
||||||
glEnd(); \
|
glEnd(); \
|
||||||
\
|
\
|
||||||
if (rects && rects != &rec_all && !(pcache_reg && pcache_reg->rects == rects)) \
|
pixman_region32_fini(®_new);
|
||||||
cxfree(rects); \
|
|
||||||
free_region(ps, ®_new); \
|
|
||||||
|
|
||||||
static inline GLuint
|
static inline GLuint
|
||||||
glx_gen_texture(session_t *ps, GLenum tex_tgt, int width, int height) {
|
glx_gen_texture(session_t *ps, GLenum tex_tgt, int width, int height) {
|
||||||
|
@ -1162,11 +1029,13 @@ glx_copy_region_to_tex(session_t *ps, GLenum tex_tgt, int basex, int basey,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blur contents in a particular region.
|
* Blur contents in a particular region.
|
||||||
|
*
|
||||||
|
* XXX seems to be way to complex for what it does
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
GLfloat factor_center,
|
GLfloat factor_center,
|
||||||
XserverRegion reg_tgt, const reg_data_t *pcache_reg,
|
const region_t *reg_tgt,
|
||||||
glx_blur_cache_t *pbc) {
|
glx_blur_cache_t *pbc) {
|
||||||
assert(ps->psglx->blur_passes[0].prog);
|
assert(ps->psglx->blur_passes[0].prog);
|
||||||
const bool more_passes = ps->psglx->blur_passes[1].prog;
|
const bool more_passes = ps->psglx->blur_passes[1].prog;
|
||||||
|
@ -1310,23 +1179,19 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
glUniform1f(ppass->unifm_factor_center, factor_center);
|
glUniform1f(ppass->unifm_factor_center, factor_center);
|
||||||
|
|
||||||
{
|
{
|
||||||
P_PAINTREG_START();
|
P_PAINTREG_START(crect) {
|
||||||
{
|
const GLfloat rx = (crect.x1 - mdx) * texfac_x;
|
||||||
const GLfloat rx = (crect.x - mdx) * texfac_x;
|
const GLfloat ry = (mheight - (crect.y1 - mdy)) * texfac_y;
|
||||||
const GLfloat ry = (mheight - (crect.y - mdy)) * texfac_y;
|
const GLfloat rxe = rx + (crect.x2 - crect.x1) * texfac_x;
|
||||||
const GLfloat rxe = rx + crect.width * texfac_x;
|
const GLfloat rye = ry - (crect.y2 - crect.y1) * texfac_y;
|
||||||
const GLfloat rye = ry - crect.height * texfac_y;
|
GLfloat rdx = crect.x1 - mdx;
|
||||||
GLfloat rdx = crect.x - mdx;
|
GLfloat rdy = mheight - crect.y1 + mdy;
|
||||||
GLfloat rdy = mheight - crect.y + mdy;
|
|
||||||
GLfloat rdxe = rdx + crect.width;
|
|
||||||
GLfloat rdye = rdy - crect.height;
|
|
||||||
|
|
||||||
if (last_pass) {
|
if (last_pass) {
|
||||||
rdx = crect.x;
|
rdx = crect.x1;
|
||||||
rdy = ps->root_height - crect.y;
|
rdy = ps->root_height - crect.y1;
|
||||||
rdxe = rdx + crect.width;
|
|
||||||
rdye = rdy - crect.height;
|
|
||||||
}
|
}
|
||||||
|
GLfloat rdxe = rdx + (crect.x2 - crect.x1);
|
||||||
|
GLfloat rdye = rdy - (crect.y2 - crect.y1);
|
||||||
|
|
||||||
#ifdef DEBUG_GLX
|
#ifdef DEBUG_GLX
|
||||||
printf_dbgf("(): %f, %f, %f, %f -> %f, %f, %f, %f\n", rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
|
printf_dbgf("(): %f, %f, %f, %f -> %f, %f, %f, %f\n", rx, ry, rxe, rye, rdx, rdy, rdxe, rdye);
|
||||||
|
@ -1343,8 +1208,7 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
|
|
||||||
glTexCoord2f(rx, rye);
|
glTexCoord2f(rx, rye);
|
||||||
glVertex3f(rdx, rdye, z);
|
glVertex3f(rdx, rdye, z);
|
||||||
}
|
} P_PAINTREG_END();
|
||||||
P_PAINTREG_END();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
|
@ -1379,7 +1243,7 @@ glx_blur_dst_end:
|
||||||
|
|
||||||
bool
|
bool
|
||||||
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
GLfloat factor, XserverRegion reg_tgt, const reg_data_t *pcache_reg) {
|
GLfloat factor, const region_t *reg_tgt) {
|
||||||
// It's possible to dim in glx_render(), but it would be over-complicated
|
// It's possible to dim in glx_render(), but it would be over-complicated
|
||||||
// considering all those mess in color negation and modulation
|
// considering all those mess in color negation and modulation
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
|
@ -1387,12 +1251,12 @@ glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
glColor4f(0.0f, 0.0f, 0.0f, factor);
|
glColor4f(0.0f, 0.0f, 0.0f, factor);
|
||||||
|
|
||||||
{
|
{
|
||||||
P_PAINTREG_START();
|
P_PAINTREG_START(crect) {
|
||||||
{
|
// XXX what does all of these variables mean?
|
||||||
GLint rdx = crect.x;
|
GLint rdx = crect.x1;
|
||||||
GLint rdy = ps->root_height - crect.y;
|
GLint rdy = ps->root_height - crect.y1;
|
||||||
GLint rdxe = rdx + crect.width;
|
GLint rdxe = rdx + (crect.x2 - crect.x1);
|
||||||
GLint rdye = rdy - crect.height;
|
GLint rdye = rdy - (crect.y2 - crect.y1);
|
||||||
|
|
||||||
glVertex3i(rdx, rdy, z);
|
glVertex3i(rdx, rdy, z);
|
||||||
glVertex3i(rdxe, rdy, z);
|
glVertex3i(rdxe, rdy, z);
|
||||||
|
@ -1419,8 +1283,7 @@ bool
|
||||||
glx_render(session_t *ps, const glx_texture_t *ptex,
|
glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||||
int x, int y, int dx, int dy, int width, int height, int z,
|
int x, int y, int dx, int dy, int width, int height, int z,
|
||||||
double opacity, bool argb, bool neg,
|
double opacity, bool argb, bool neg,
|
||||||
XserverRegion reg_tgt, const reg_data_t *pcache_reg
|
const region_t *reg_tgt, const glx_prog_main_t *pprogram
|
||||||
, const glx_prog_main_t *pprogram
|
|
||||||
) {
|
) {
|
||||||
if (!ptex || !ptex->texture) {
|
if (!ptex || !ptex->texture) {
|
||||||
printf_errf("(): Missing texture.");
|
printf_errf("(): Missing texture.");
|
||||||
|
@ -1551,12 +1414,12 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||||
|
|
||||||
// Painting
|
// Painting
|
||||||
{
|
{
|
||||||
P_PAINTREG_START();
|
P_PAINTREG_START(crect) {
|
||||||
{
|
// XXX explain these variables
|
||||||
GLfloat rx = (double) (crect.x - dx + x);
|
GLfloat rx = (double) (crect.x1 - dx + x);
|
||||||
GLfloat ry = (double) (crect.y - dy + y);
|
GLfloat ry = (double) (crect.y1 - dy + y);
|
||||||
GLfloat rxe = rx + (double) crect.width;
|
GLfloat rxe = rx + (double) (crect.x2 - crect.x1);
|
||||||
GLfloat rye = ry + (double) crect.height;
|
GLfloat rye = ry + (double) (crect.y2 - crect.y1);
|
||||||
// Rectangle textures have [0-w] [0-h] while 2D texture has [0-1] [0-1]
|
// Rectangle textures have [0-w] [0-h] while 2D texture has [0-1] [0-1]
|
||||||
// Thanks to amonakov for pointing out!
|
// Thanks to amonakov for pointing out!
|
||||||
if (GL_TEXTURE_2D == ptex->target) {
|
if (GL_TEXTURE_2D == ptex->target) {
|
||||||
|
@ -1565,10 +1428,10 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||||
rxe = rxe / ptex->width;
|
rxe = rxe / ptex->width;
|
||||||
rye = rye / ptex->height;
|
rye = rye / ptex->height;
|
||||||
}
|
}
|
||||||
GLint rdx = crect.x;
|
GLint rdx = crect.x1;
|
||||||
GLint rdy = ps->root_height - crect.y;
|
GLint rdy = ps->root_height - crect.y1;
|
||||||
GLint rdxe = rdx + crect.width;
|
GLint rdxe = rdx + (crect.x2 - crect.x1);
|
||||||
GLint rdye = rdy - crect.height;
|
GLint rdye = rdy - (crect.y2 - crect.y1);
|
||||||
|
|
||||||
// Invert Y if needed, this may not work as expected, though. I don't
|
// Invert Y if needed, this may not work as expected, though. I don't
|
||||||
// have such a FBConfig to test with.
|
// have such a FBConfig to test with.
|
||||||
|
@ -1599,8 +1462,7 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||||
|
|
||||||
P_TEXCOORD(rx, rye);
|
P_TEXCOORD(rx, rye);
|
||||||
glVertex3i(rdx, rdye, z);
|
glVertex3i(rdx, rdye, z);
|
||||||
}
|
} P_PAINTREG_END();
|
||||||
P_PAINTREG_END();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
|
|
11
src/opengl.h
11
src/opengl.h
|
@ -124,13 +124,13 @@ glx_hasglext(session_t *ps, const char *ext) {
|
||||||
|
|
||||||
bool
|
bool
|
||||||
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
GLfloat factor, XserverRegion reg_tgt, const reg_data_t *);
|
GLfloat factor, const region_t *reg_tgt);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
glx_render(session_t *ps, const glx_texture_t *ptex,
|
glx_render(session_t *ps, const glx_texture_t *ptex,
|
||||||
int x, int y, int dx, int dy, int width, int height, int z,
|
int x, int y, int dx, int dy, int width, int height, int z,
|
||||||
double opacity, bool argb, bool neg,
|
double opacity, bool argb, bool neg,
|
||||||
XserverRegion reg_tgt, const reg_data_t *,
|
const region_t *reg_tgt,
|
||||||
const glx_prog_main_t *pprogram);
|
const glx_prog_main_t *pprogram);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -162,7 +162,7 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
|
||||||
void
|
void
|
||||||
glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
|
glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
|
||||||
|
|
||||||
void glx_paint_pre(session_t *ps, XserverRegion *preg)
|
void glx_paint_pre(session_t *ps, region_t *preg)
|
||||||
__attribute__((nonnull(1, 2)));
|
__attribute__((nonnull(1, 2)));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -175,13 +175,12 @@ glx_tex_binded(const glx_texture_t *ptex, Pixmap pixmap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
glx_set_clip(session_t *ps, XserverRegion reg, const reg_data_t *);
|
glx_set_clip(session_t *ps, const region_t *reg);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
||||||
GLfloat factor_center,
|
GLfloat factor_center,
|
||||||
XserverRegion reg_tgt,
|
const region_t *reg_tgt,
|
||||||
const reg_data_t *,
|
|
||||||
glx_blur_cache_t *pbc);
|
glx_blur_cache_t *pbc);
|
||||||
|
|
||||||
GLuint
|
GLuint
|
||||||
|
|
|
@ -11,12 +11,12 @@ RC_TYPE(region_t, rc_region, pixman_region32_init, pixman_region32_fini, static
|
||||||
|
|
||||||
/// copy a region_t
|
/// copy a region_t
|
||||||
static inline void
|
static inline void
|
||||||
copy_region_(region_t *dst, const region_t *p) {
|
copy_region(region_t *dst, const region_t *p) {
|
||||||
pixman_region32_copy(dst, (region_t *)p);
|
pixman_region32_copy(dst, (region_t *)p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
dump_region_(const region_t *x) {
|
dump_region(const region_t *x) {
|
||||||
int nrects;
|
int nrects;
|
||||||
const rect_t *rects = pixman_region32_rectangles((region_t *)x, &nrects);
|
const rect_t *rects = pixman_region32_rectangles((region_t *)x, &nrects);
|
||||||
fprintf(stderr, "nrects: %d\n", nrects);
|
fprintf(stderr, "nrects: %d\n", nrects);
|
||||||
|
|
235
src/win.c
235
src/win.c
|
@ -1,5 +1,4 @@
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/extensions/Xfixes.h>
|
|
||||||
#include <xcb/render.h>
|
#include <xcb/render.h>
|
||||||
#include <xcb/damage.h>
|
#include <xcb/damage.h>
|
||||||
#include <xcb/xcb_renderutil.h>
|
#include <xcb/xcb_renderutil.h>
|
||||||
|
@ -75,36 +74,27 @@ group_is_focused(session_t *ps, Window leader) {
|
||||||
/**
|
/**
|
||||||
* Get a rectangular region a window occupies, excluding shadow.
|
* Get a rectangular region a window occupies, excluding shadow.
|
||||||
*/
|
*/
|
||||||
XserverRegion
|
void win_get_region(session_t *ps, win *w, bool global, region_t *res) {
|
||||||
win_get_region(session_t *ps, win *w, bool use_offset) {
|
pixman_region32_union_rect(res, res,
|
||||||
XRectangle r;
|
global ? w->g.x : 0,
|
||||||
|
global ? w->g.y : 0,
|
||||||
r.x = (use_offset ? w->g.x: 0);
|
w->widthb, w->heightb);
|
||||||
r.y = (use_offset ? w->g.y: 0);
|
|
||||||
r.width = w->widthb;
|
|
||||||
r.height = w->heightb;
|
|
||||||
|
|
||||||
return XFixesCreateRegion(ps->dpy, &r, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a rectangular region a window occupies, excluding frame and shadow.
|
* Get a rectangular region a window occupies, excluding frame and shadow.
|
||||||
*/
|
*/
|
||||||
XserverRegion
|
void win_get_region_noframe(session_t *ps, win *w, bool global, region_t *res) {
|
||||||
win_get_region_noframe(session_t *ps, win *w, bool use_offset) {
|
|
||||||
const margin_t extents = win_calc_frame_extents(ps, w);
|
const margin_t extents = win_calc_frame_extents(ps, w);
|
||||||
XRectangle r;
|
|
||||||
|
|
||||||
r.x = (use_offset ? w->g.x: 0) + extents.left;
|
int x = (global ? w->g.x: 0) + extents.left;
|
||||||
r.y = (use_offset ? w->g.y: 0) + extents.top;
|
int y = (global ? w->g.y: 0) + extents.top;
|
||||||
r.width = max_i(w->g.width - extents.left - extents.right, 0);
|
int width = max_i(w->g.width - extents.left - extents.right, 0);
|
||||||
r.height = max_i(w->g.height - extents.top - extents.bottom, 0);
|
int height = max_i(w->g.height - extents.top - extents.bottom, 0);
|
||||||
|
|
||||||
if (r.width > 0 && r.height > 0)
|
if (width > 0 && height > 0)
|
||||||
return XFixesCreateRegion(ps->dpy, &r, 1);
|
pixman_region32_union_rect(res, res, x, y, width, height);
|
||||||
else
|
|
||||||
return XFixesCreateRegion(ps->dpy, NULL, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -114,13 +104,18 @@ win_get_region_noframe(session_t *ps, win *w, bool use_offset) {
|
||||||
* @param w struct _win element representing the window
|
* @param w struct _win element representing the window
|
||||||
*/
|
*/
|
||||||
void add_damage_from_win(session_t *ps, win *w) {
|
void add_damage_from_win(session_t *ps, win *w) {
|
||||||
if (w->extents) {
|
// XXX there was a cached extents region, investigate
|
||||||
add_damage(ps, copy_region(ps, w->extents));
|
// if that's better
|
||||||
}
|
region_t extents;
|
||||||
|
pixman_region32_init(&extents);
|
||||||
|
win_extents(w, &extents);
|
||||||
|
add_damage(ps, &extents);
|
||||||
|
pixman_region32_fini(&extents);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a window has rounded corners.
|
* Check if a window has rounded corners.
|
||||||
|
* XXX This is really dumb
|
||||||
*/
|
*/
|
||||||
void win_rounded_corners(session_t *ps, win *w) {
|
void win_rounded_corners(session_t *ps, win *w) {
|
||||||
w->rounded_corners = false;
|
w->rounded_corners = false;
|
||||||
|
@ -129,11 +124,11 @@ void win_rounded_corners(session_t *ps, win *w) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Fetch its bounding region
|
// Fetch its bounding region
|
||||||
if (!w->border_size)
|
if (!pixman_region32_not_empty(&w->bounding_shape))
|
||||||
w->border_size = win_border_size(ps, w, true);
|
win_update_bounding_shape(ps, w);
|
||||||
|
|
||||||
// Quit if border_size() returns None
|
// Quit if border_size() returns None
|
||||||
if (!w->border_size)
|
if (!pixman_region32_not_empty(&w->bounding_shape))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Determine the minimum width/height of a rectangle that could mark
|
// Determine the minimum width/height of a rectangle that could mark
|
||||||
|
@ -144,20 +139,16 @@ void win_rounded_corners(session_t *ps, win *w) {
|
||||||
w->heightb - ROUNDED_PIXELS);
|
w->heightb - ROUNDED_PIXELS);
|
||||||
|
|
||||||
// Get the rectangles in the bounding region
|
// Get the rectangles in the bounding region
|
||||||
int nrects = 0, i;
|
int nrects = 0;
|
||||||
XRectangle *rects = XFixesFetchRegion(ps->dpy, w->border_size, &nrects);
|
const rect_t *rects = pixman_region32_rectangles(&w->bounding_shape, &nrects);
|
||||||
if (!rects)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Look for a rectangle large enough for this window be considered
|
// Look for a rectangle large enough for this window be considered
|
||||||
// having rounded corners
|
// having rounded corners
|
||||||
for (i = 0; i < nrects; ++i)
|
for (int i = 0; i < nrects; ++i)
|
||||||
if (rects[i].width >= minwidth && rects[i].height >= minheight) {
|
if (rects[i].x2 - rects[i].x1 >= minwidth && rects[i].y2 - rects[i].y1 >= minheight) {
|
||||||
w->rounded_corners = true;
|
w->rounded_corners = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cxfree(rects);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int win_get_name(session_t *ps, win *w) {
|
int win_get_name(session_t *ps, win *w) {
|
||||||
|
@ -291,7 +282,7 @@ bool win_has_alpha(win *w) {
|
||||||
void win_determine_mode(session_t *ps, win *w) {
|
void win_determine_mode(session_t *ps, win *w) {
|
||||||
if (win_has_alpha(w) || w->opacity != OPAQUE) {
|
if (win_has_alpha(w) || w->opacity != OPAQUE) {
|
||||||
w->mode = WMODE_TRANS;
|
w->mode = WMODE_TRANS;
|
||||||
} else if (w->frame_opacity) {
|
} else if (w->frame_opacity != 1.0) {
|
||||||
w->mode = WMODE_FRAME_TRANS;
|
w->mode = WMODE_FRAME_TRANS;
|
||||||
} else {
|
} else {
|
||||||
w->mode = WMODE_SOLID;
|
w->mode = WMODE_SOLID;
|
||||||
|
@ -389,34 +380,6 @@ void win_determine_fade(session_t *ps, win *w) {
|
||||||
w->fade = ps->o.wintype_fade[w->window_type];
|
w->fade = ps->o.wintype_fade[w->window_type];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update window-shape.
|
|
||||||
*/
|
|
||||||
void win_update_shape_raw(session_t *ps, win *w) {
|
|
||||||
if (ps->shape_exists) {
|
|
||||||
w->bounding_shaped = win_bounding_shaped(ps, w->id);
|
|
||||||
if (w->bounding_shaped && ps->o.detect_rounded_corners)
|
|
||||||
win_rounded_corners(ps, w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update window-shape related information.
|
|
||||||
*/
|
|
||||||
void win_update_shape(session_t *ps, win *w) {
|
|
||||||
if (ps->shape_exists) {
|
|
||||||
// bool bounding_shaped_old = w->bounding_shaped;
|
|
||||||
|
|
||||||
win_update_shape_raw(ps, w);
|
|
||||||
|
|
||||||
win_on_factor_change(ps, w);
|
|
||||||
|
|
||||||
// XXX Window shape changed, and if we didn't fill in the pixels
|
|
||||||
// behind the window (not implemented yet), we should rebuild
|
|
||||||
// the shadow_pict
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reread _COMPTON_SHADOW property from a window.
|
* Reread _COMPTON_SHADOW property from a window.
|
||||||
*
|
*
|
||||||
|
@ -452,22 +415,26 @@ void win_set_shadow(session_t *ps, win *w, bool shadow_new) {
|
||||||
if (w->shadow == shadow_new)
|
if (w->shadow == shadow_new)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
region_t extents;
|
||||||
|
pixman_region32_init(&extents);
|
||||||
|
win_extents(w, &extents);
|
||||||
|
|
||||||
w->shadow = shadow_new;
|
w->shadow = shadow_new;
|
||||||
|
|
||||||
// Window extents need update on shadow state change
|
// Window extents need update on shadow state change
|
||||||
// Shadow geometry currently doesn't change on shadow state change
|
// Shadow geometry currently doesn't change on shadow state change
|
||||||
// calc_shadow_geometry(ps, w);
|
// calc_shadow_geometry(ps, w);
|
||||||
if (w->extents) {
|
|
||||||
// Mark the old extents as damaged if the shadow is removed
|
// Mark the old extents as damaged if the shadow is removed
|
||||||
if (!w->shadow)
|
if (!w->shadow)
|
||||||
add_damage(ps, w->extents);
|
add_damage(ps, &extents);
|
||||||
else
|
|
||||||
free_region(ps, &w->extents);
|
pixman_region32_clear(&extents);
|
||||||
w->extents = win_extents(ps, w);
|
|
||||||
// Mark the new extents as damaged if the shadow is added
|
// Mark the new extents as damaged if the shadow is added
|
||||||
if (w->shadow)
|
if (w->shadow) {
|
||||||
|
win_extents(w, &extents);
|
||||||
add_damage_from_win(ps, w);
|
add_damage_from_win(ps, w);
|
||||||
}
|
}
|
||||||
|
pixman_region32_fini(&extents);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -521,7 +488,7 @@ void win_set_blur_background(session_t *ps, win *w, bool blur_background_new) {
|
||||||
|
|
||||||
// Only consider window damaged if it's previously painted with background
|
// Only consider window damaged if it's previously painted with background
|
||||||
// blurred
|
// blurred
|
||||||
if (!win_is_solid(ps, w) || (ps->o.blur_background_frame && w->frame_opacity))
|
if (!win_is_solid(ps, w) || (ps->o.blur_background_frame && w->frame_opacity != 1))
|
||||||
add_damage_from_win(ps, w);
|
add_damage_from_win(ps, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,6 +567,7 @@ void win_on_factor_change(session_t *ps, win *w) {
|
||||||
if (IsViewable == w->a.map_state && ps->o.unredir_if_possible_blacklist)
|
if (IsViewable == w->a.map_state && ps->o.unredir_if_possible_blacklist)
|
||||||
w->unredir_if_possible_excluded = c2_match(
|
w->unredir_if_possible_excluded = c2_match(
|
||||||
ps, w, ps->o.unredir_if_possible_blacklist, &w->cache_uipblst);
|
ps, w, ps->o.unredir_if_possible_blacklist, &w->cache_uipblst);
|
||||||
|
w->reg_ignore_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -610,6 +578,8 @@ void calc_win_size(session_t *ps, win *w) {
|
||||||
w->heightb = w->g.height + w->g.border_width * 2;
|
w->heightb = w->g.height + w->g.border_width * 2;
|
||||||
calc_shadow_geometry(ps, w);
|
calc_shadow_geometry(ps, w);
|
||||||
w->flags |= WFLAG_SIZE_CHANGE;
|
w->flags |= WFLAG_SIZE_CHANGE;
|
||||||
|
// Invalidate the shadow we built
|
||||||
|
free_paint(ps, &w->shadow_paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -670,8 +640,8 @@ void win_mark_client(session_t *ps, win *w, Window client) {
|
||||||
win_upd_wintype(ps, w);
|
win_upd_wintype(ps, w);
|
||||||
|
|
||||||
// Get frame widths. The window is in damaged area already.
|
// Get frame widths. The window is in damaged area already.
|
||||||
if (ps->o.frame_opacity)
|
if (ps->o.frame_opacity != 1)
|
||||||
win_get_frame_extents(ps, w, client);
|
win_update_frame_extents(ps, w, client);
|
||||||
|
|
||||||
// Get window group
|
// Get window group
|
||||||
if (ps->o.track_leader)
|
if (ps->o.track_leader)
|
||||||
|
@ -762,12 +732,12 @@ bool add_win(session_t *ps, Window id, Window prev) {
|
||||||
.damage = None,
|
.damage = None,
|
||||||
.pixmap_damaged = false,
|
.pixmap_damaged = false,
|
||||||
.paint = PAINT_INIT,
|
.paint = PAINT_INIT,
|
||||||
.border_size = None,
|
|
||||||
.extents = None,
|
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.need_configure = false,
|
.need_configure = false,
|
||||||
.queue_configure = {},
|
.queue_configure = {},
|
||||||
.reg_ignore = None,
|
.reg_ignore = NULL,
|
||||||
|
.reg_ignore_valid = false,
|
||||||
|
|
||||||
.widthb = 0,
|
.widthb = 0,
|
||||||
.heightb = 0,
|
.heightb = 0,
|
||||||
.destroyed = false,
|
.destroyed = false,
|
||||||
|
@ -807,7 +777,7 @@ bool add_win(session_t *ps, Window id, Window prev) {
|
||||||
.fade_force = UNSET,
|
.fade_force = UNSET,
|
||||||
.fade_callback = NULL,
|
.fade_callback = NULL,
|
||||||
|
|
||||||
.frame_opacity = 0.0,
|
.frame_opacity = 1.0,
|
||||||
.frame_extents = MARGIN_INIT,
|
.frame_extents = MARGIN_INIT,
|
||||||
|
|
||||||
.shadow = false,
|
.shadow = false,
|
||||||
|
@ -845,7 +815,8 @@ bool add_win(session_t *ps, Window id, Window prev) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(new, &win_def, sizeof(win));
|
*new = win_def;
|
||||||
|
pixman_region32_init(&new->bounding_shape);
|
||||||
|
|
||||||
// Find window insertion point
|
// Find window insertion point
|
||||||
win **p = NULL;
|
win **p = NULL;
|
||||||
|
@ -1154,51 +1125,26 @@ win_set_focused(session_t *ps, win *w, bool focused) {
|
||||||
* Note w->shadow and shadow geometry must be correct before calling this
|
* Note w->shadow and shadow geometry must be correct before calling this
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
XserverRegion win_extents(session_t *ps, win *w) {
|
void win_extents(win *w, region_t *res) {
|
||||||
XRectangle r;
|
pixman_region32_clear(res);
|
||||||
|
pixman_region32_union_rect(res, res, w->g.x, w->g.y, w->widthb, w->heightb);
|
||||||
|
|
||||||
r.x = w->g.x;
|
if (w->shadow)
|
||||||
r.y = w->g.y;
|
pixman_region32_union_rect(res, res, w->g.x + w->shadow_dx, w->g.y + w->shadow_dy, w->shadow_width, w->shadow_height);
|
||||||
r.width = w->widthb;
|
|
||||||
r.height = w->heightb;
|
|
||||||
|
|
||||||
if (w->shadow) {
|
|
||||||
XRectangle sr;
|
|
||||||
|
|
||||||
sr.x = w->g.x + w->shadow_dx;
|
|
||||||
sr.y = w->g.y + w->shadow_dy;
|
|
||||||
sr.width = w->shadow_width;
|
|
||||||
sr.height = w->shadow_height;
|
|
||||||
|
|
||||||
if (sr.x < r.x) {
|
|
||||||
r.width = (r.x + r.width) - sr.x;
|
|
||||||
r.x = sr.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sr.y < r.y) {
|
|
||||||
r.height = (r.y + r.height) - sr.y;
|
|
||||||
r.y = sr.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sr.x + sr.width > r.x + r.width) {
|
|
||||||
r.width = sr.x + sr.width - r.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sr.y + sr.height > r.y + r.height) {
|
|
||||||
r.height = sr.y + sr.height - r.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return XFixesCreateRegion(ps->dpy, &r, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the bounding shape of a window.
|
* Update the out-dated bounding shape of a window.
|
||||||
|
*
|
||||||
|
* Mark the window shape as updated
|
||||||
*/
|
*/
|
||||||
XserverRegion
|
void win_update_bounding_shape(session_t *ps, win *w) {
|
||||||
win_border_size(session_t *ps, win *w, bool use_offset) {
|
if (ps->shape_exists)
|
||||||
|
w->bounding_shaped = win_bounding_shaped(ps, w->id);
|
||||||
|
|
||||||
|
pixman_region32_clear(&w->bounding_shape);
|
||||||
// Start with the window rectangular region
|
// Start with the window rectangular region
|
||||||
XserverRegion fin = win_get_region(ps, w, use_offset);
|
win_get_region(ps, w, true, &w->bounding_shape);
|
||||||
|
|
||||||
// Only request for a bounding region if the window is shaped
|
// Only request for a bounding region if the window is shaped
|
||||||
if (w->bounding_shaped) {
|
if (w->bounding_shaped) {
|
||||||
|
@ -1214,23 +1160,32 @@ win_border_size(session_t *ps, win *w, bool use_offset) {
|
||||||
ps->dpy, w->id, WindowRegionBounding);
|
ps->dpy, w->id, WindowRegionBounding);
|
||||||
|
|
||||||
if (!border)
|
if (!border)
|
||||||
return fin;
|
return;
|
||||||
|
|
||||||
if (use_offset) {
|
region_t br;
|
||||||
// Translate the region to the correct place
|
pixman_region32_init(&br);
|
||||||
XFixesTranslateRegion(ps->dpy, border,
|
x_fetch_region(ps, border, &br);
|
||||||
w->g.x + w->g.border_width,
|
|
||||||
|
// Add border width because we are using a different origin.
|
||||||
|
// X thinks the top left of the inner window is the origin,
|
||||||
|
// We think the top left of the border is the origin
|
||||||
|
pixman_region32_translate(&br, w->g.x + w->g.border_width,
|
||||||
w->g.y + w->g.border_width);
|
w->g.y + w->g.border_width);
|
||||||
}
|
|
||||||
|
|
||||||
// Intersect the bounding region we got with the window rectangle, to
|
// Intersect the bounding region we got with the window rectangle, to
|
||||||
// make sure the bounding region is not bigger than the window
|
// make sure the bounding region is not bigger than the window
|
||||||
// rectangle
|
// rectangle
|
||||||
XFixesIntersectRegion(ps->dpy, fin, fin, border);
|
pixman_region32_intersect(&w->bounding_shape, &w->bounding_shape, &br);
|
||||||
XFixesDestroyRegion(ps->dpy, border);
|
pixman_region32_fini(&br);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fin;
|
if (w->bounding_shaped && ps->o.detect_rounded_corners)
|
||||||
|
win_rounded_corners(ps, w);
|
||||||
|
|
||||||
|
// XXX Window shape changed, and if we didn't fill in the pixels
|
||||||
|
// behind the window (not implemented yet), we should rebuild
|
||||||
|
// the shadow_pict
|
||||||
|
win_on_factor_change(ps, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1258,21 +1213,25 @@ void win_update_opacity_prop(session_t *ps, win *w) {
|
||||||
* Retrieve frame extents from a window.
|
* Retrieve frame extents from a window.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
win_get_frame_extents(session_t *ps, win *w, Window client) {
|
win_update_frame_extents(session_t *ps, win *w, Window client) {
|
||||||
cmemzero_one(&w->frame_extents);
|
|
||||||
|
|
||||||
winprop_t prop = wid_get_prop(ps, client, ps->atom_frame_extents,
|
winprop_t prop = wid_get_prop(ps, client, ps->atom_frame_extents,
|
||||||
4L, XA_CARDINAL, 32);
|
4L, XA_CARDINAL, 32);
|
||||||
|
|
||||||
if (4 == prop.nitems) {
|
if (prop.nitems == 4) {
|
||||||
const long * const extents = prop.data.p32;
|
const long * const extents = prop.data.p32;
|
||||||
|
const bool changed = w->frame_extents.left != extents[0] ||
|
||||||
|
w->frame_extents.right != extents[1] ||
|
||||||
|
w->frame_extents.top != extents[2] ||
|
||||||
|
w->frame_extents.bottom != extents[3];
|
||||||
w->frame_extents.left = extents[0];
|
w->frame_extents.left = extents[0];
|
||||||
w->frame_extents.right = extents[1];
|
w->frame_extents.right = extents[1];
|
||||||
w->frame_extents.top = extents[2];
|
w->frame_extents.top = extents[2];
|
||||||
w->frame_extents.bottom = extents[3];
|
w->frame_extents.bottom = extents[3];
|
||||||
|
|
||||||
if (ps->o.frame_opacity)
|
// If frame_opacity != 1, then frame of this window
|
||||||
update_reg_ignore_expire(ps, w);
|
// is not included in reg_ignore of underneath windows
|
||||||
|
if (ps->o.frame_opacity == 1 && changed)
|
||||||
|
w->reg_ignore_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_FRAME
|
#ifdef DEBUG_FRAME
|
||||||
|
@ -1283,3 +1242,13 @@ win_get_frame_extents(session_t *ps, win *w, Window client) {
|
||||||
|
|
||||||
free_winprop(&prop);
|
free_winprop(&prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool win_is_region_ignore_valid(session_t *ps, win *w) {
|
||||||
|
for(win *i = ps->list; w; w = w->next) {
|
||||||
|
if (i == w)
|
||||||
|
break;
|
||||||
|
if (!i->reg_ignore_valid)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
24
src/win.h
24
src/win.h
|
@ -1,7 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/extensions/Xfixes.h>
|
|
||||||
|
#include "x.h"
|
||||||
|
|
||||||
typedef struct session session_t;
|
typedef struct session session_t;
|
||||||
typedef struct win win;
|
typedef struct win win;
|
||||||
|
@ -15,8 +16,6 @@ void win_determine_mode(session_t *ps, win *w);
|
||||||
*/
|
*/
|
||||||
void win_set_focused(session_t *ps, win *w, bool focused);
|
void win_set_focused(session_t *ps, win *w, bool focused);
|
||||||
void win_determine_fade(session_t *ps, win *w);
|
void win_determine_fade(session_t *ps, win *w);
|
||||||
void win_update_shape_raw(session_t *ps, win *w);
|
|
||||||
void win_update_shape(session_t *ps, win *w);
|
|
||||||
void win_update_prop_shadow_raw(session_t *ps, win *w);
|
void win_update_prop_shadow_raw(session_t *ps, win *w);
|
||||||
void win_update_prop_shadow(session_t *ps, win *w);
|
void win_update_prop_shadow(session_t *ps, win *w);
|
||||||
void win_set_shadow(session_t *ps, win *w, bool shadow_new);
|
void win_set_shadow(session_t *ps, win *w, bool shadow_new);
|
||||||
|
@ -53,15 +52,15 @@ void win_update_focused(session_t *ps, win *w);
|
||||||
/**
|
/**
|
||||||
* Retrieve the bounding shape of a window.
|
* Retrieve the bounding shape of a window.
|
||||||
*/
|
*/
|
||||||
XserverRegion
|
// XXX was win_border_size
|
||||||
win_border_size(session_t *ps, win *w, bool use_offset);
|
void win_update_bounding_shape(session_t *ps, win *w);
|
||||||
/**
|
/**
|
||||||
* Get a rectangular region a window (and possibly its shadow) occupies.
|
* Get a rectangular region a window (and possibly its shadow) occupies.
|
||||||
*
|
*
|
||||||
* Note w->shadow and shadow geometry must be correct before calling this
|
* Note w->shadow and shadow geometry must be correct before calling this
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
XserverRegion win_extents(session_t *ps, win *w);
|
void win_extents(win *w, region_t *res);
|
||||||
/**
|
/**
|
||||||
* Add a window to damaged area.
|
* Add a window to damaged area.
|
||||||
*
|
*
|
||||||
|
@ -71,19 +70,19 @@ XserverRegion win_extents(session_t *ps, win *w);
|
||||||
void add_damage_from_win(session_t *ps, win *w);
|
void add_damage_from_win(session_t *ps, win *w);
|
||||||
/**
|
/**
|
||||||
* Get a rectangular region a window occupies, excluding shadow.
|
* Get a rectangular region a window occupies, excluding shadow.
|
||||||
|
*
|
||||||
|
* global = use global coordinates
|
||||||
*/
|
*/
|
||||||
XserverRegion
|
void win_get_region(session_t *ps, win *w, bool global, region_t *);
|
||||||
win_get_region(session_t *ps, win *w, bool use_offset);
|
|
||||||
/**
|
/**
|
||||||
* Get a rectangular region a window occupies, excluding frame and shadow.
|
* Get a rectangular region a window occupies, excluding frame and shadow.
|
||||||
*/
|
*/
|
||||||
XserverRegion
|
void win_get_region_noframe(session_t *ps, win *w, bool global, region_t *);
|
||||||
win_get_region_noframe(session_t *ps, win *w, bool use_offset);
|
|
||||||
/**
|
/**
|
||||||
* Retrieve frame extents from a window.
|
* Retrieve frame extents from a window.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
win_get_frame_extents(session_t *ps, win *w, Window client);
|
win_update_frame_extents(session_t *ps, win *w, Window client);
|
||||||
bool add_win(session_t *ps, Window id, Window prev);
|
bool add_win(session_t *ps, Window id, Window prev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,3 +97,6 @@ win_get_leader(session_t *ps, win *w) {
|
||||||
|
|
||||||
/// check if window has ARGB visual
|
/// check if window has ARGB visual
|
||||||
bool win_has_alpha(win *w);
|
bool win_has_alpha(win *w);
|
||||||
|
|
||||||
|
/// check if reg_ignore_valid is true for all windows above us
|
||||||
|
bool win_is_region_ignore_valid(session_t *ps, win *w);
|
||||||
|
|
Loading…
Reference in New Issue