Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve behavior of invert-color-include #467

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions compton-default-fshader-win.glsl
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
uniform float opacity;
uniform bool invert_color;
uniform sampler2D tex;
uniform vec4 margin;

float min3(vec3 v) { return min(min(v.x, v.y), v.z); }
float max3(vec3 v) { return max(max(v.x, v.y), v.z); }

void main() {
vec4 c = texture2D(tex, gl_TexCoord[0]);
if (invert_color)
c = vec4(vec3(c.a, c.a, c.a) - vec3(c), c.a);
c *= opacity;
gl_FragColor = c;
vec2 coord = vec2(gl_TexCoord[0]);
vec4 c = texture2D(tex, coord);

// If current window should be inverted and the pixel is inside client area
if (invert_color
&& all(greaterThan(coord.xy, margin.st))
&& all(lessThan(coord.xy, margin.pq))
) {
// Fast luminance inversion, while preserving hue
c.rgb += 1.0 - max3(c.rgb) - min3(c.rgb);
}

c *= opacity;
gl_FragColor = c;
}
5 changes: 4 additions & 1 deletion man/compton.1.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,10 @@ May also be one of the predefined kernels: `3x3box` (default), `5x5box`, `7x7box
Additionally use X Sync fence to sync clients' draw calls. Needed on nvidia-drivers with GLX backend for some users. May be disabled at compile time with `NO_XSYNC=1`.

*--glx-fshader-win* 'SHADER'::
GLX backend: Use specified GLSL fragment shader for rendering window contents. See `compton-default-fshader-win.glsl` and `compton-fake-transparency-fshader-win.glsl` in the source tree for examples.
GLX backend: Use specified GLSL fragment shader, supplied as a string, for rendering window contents. See `compton-default-fshader-win.glsl` and `compton-fake-transparency-fshader-win.glsl` in the source tree for examples.

*--glx-fshader-win-file* 'PATH'::
GLX backend: Load GLSL fragment shader from the given path and use it for rendering window contents. See `compton-default-fshader-win.glsl` and `compton-fake-transparency-fshader-win.glsl` in the source tree for examples.

*--force-win-blend*::
Force all windows to be painted with blending. Useful if you have a *--glx-fshader-win* that could turn opaque pixels transparent.
Expand Down
33 changes: 28 additions & 5 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -495,13 +495,16 @@ typedef struct {
GLint unifm_invert_color;
/// Location of uniform "tex" in window GLSL program.
GLint unifm_tex;
/// Location of uniform "margin" in window GLSL program.
GLint unifm_margin;
} glx_prog_main_t;

#define GLX_PROG_MAIN_INIT { \
.prog = 0, \
.unifm_opacity = -1, \
.unifm_invert_color = -1, \
.unifm_tex = -1, \
.unifm_margin = -1, \
}

#endif
Expand Down Expand Up @@ -1528,6 +1531,26 @@ mstrcpy(const char *src) {
return str;
}

/**
* Allocate the space and read a text file into a string.
*/
static inline char *
mfread(const char *path) {
FILE *f = fopen(path, "r");
if (!f) return NULL;

fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);

char *str = cmalloc(fsize + 1, char);
fread(str, 1, fsize, f);
fclose(f);
str[fsize] = 0;

return str;
}

/**
* Allocate the space and copy a string.
*/
Expand Down Expand Up @@ -2209,7 +2232,7 @@ glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
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,
double opacity, bool argb, bool neg, margin_t *margin,
XserverRegion reg_tgt, const reg_data_t *pcache_reg
#ifdef CONFIG_VSYNC_OPENGL_GLSL
, const glx_prog_main_t *pprogram
Expand All @@ -2218,12 +2241,12 @@ glx_render_(session_t *ps, const glx_texture_t *ptex,

#ifdef CONFIG_VSYNC_OPENGL_GLSL
#define \
glx_render(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, reg_tgt, pcache_reg, pprogram) \
glx_render_(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, reg_tgt, pcache_reg, pprogram)
glx_render(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, margin, reg_tgt, pcache_reg, pprogram) \
glx_render_(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, margin, reg_tgt, pcache_reg, pprogram)
#else
#define \
glx_render(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, reg_tgt, pcache_reg, pprogram) \
glx_render_(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, reg_tgt, pcache_reg)
glx_render(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, margin, reg_tgt, pcache_reg, pprogram) \
glx_render_(ps, ptex, x, y, dx, dy, width, height, z, opacity, argb, neg, margin, reg_tgt, pcache_reg)
#endif

void
Expand Down
69 changes: 49 additions & 20 deletions src/compton.c
Original file line number Diff line number Diff line change
Expand Up @@ -1317,7 +1317,7 @@ win_paint_shadow(session_t *ps, win *w,
}

render(ps, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy,
w->shadow_width, w->shadow_height, w->shadow_opacity, true, false,
w->shadow_width, w->shadow_height, w->shadow_opacity, true, false, &w->frame_extents,
w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, pcache_reg, NULL);
}

Expand Down Expand Up @@ -1513,7 +1513,7 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer,

static void
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, margin_t *margin,
Picture pict, glx_texture_t *ptex,
XserverRegion reg_paint, const reg_data_t *pcache_reg
#ifdef CONFIG_VSYNC_OPENGL_GLSL
Expand All @@ -1534,8 +1534,8 @@ render_(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
}
#ifdef CONFIG_VSYNC_OPENGL
case BKEND_GLX:
glx_render(ps, ptex, x, y, dx, dy, wid, hei,
ps->psglx->z, opacity, argb, neg, reg_paint, pcache_reg, pprogram);
glx_render(ps, ptex, x, y, dx, dy, wid, hei, ps->psglx->z, opacity,
argb, neg, margin, reg_paint, pcache_reg, pprogram);
ps->psglx->z += 1;
break;
#endif
Expand Down Expand Up @@ -1598,37 +1598,42 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint,
const int y = w->a.y;
const int wid = w->widthb;
const int hei = w->heightb;
const bool invert_color = bkend_use_xrender(ps) && w->invert_color;

Picture pict = w->paint.pict;
Picture invpict = NULL;

// Invert window color, if required
if (bkend_use_xrender(ps) && w->invert_color) {
Picture newpict = xr_build_picture(ps, wid, hei, w->pictfmt);
if (newpict) {
if (invert_color) {
invpict = xr_build_picture(ps, wid, hei, w->pictfmt);
if (invpict) {
// Apply clipping region to save some CPU
if (reg_paint) {
XserverRegion reg = copy_region(ps, reg_paint);
XFixesTranslateRegion(ps->dpy, reg, -x, -y);
XFixesSetPictureClipRegion(ps->dpy, newpict, 0, 0, reg);
XFixesSetPictureClipRegion(ps->dpy, invpict, 0, 0, reg);
free_region(ps, &reg);
}

XRenderComposite(ps->dpy, PictOpSrc, pict, None,
newpict, 0, 0, 0, 0, 0, 0, wid, hei);
invpict, 0, 0, 0, 0, 0, 0, wid, hei);
XRenderComposite(ps->dpy, PictOpDifference, ps->white_picture, None,
newpict, 0, 0, 0, 0, 0, 0, wid, hei);
invpict, 0, 0, 0, 0, 0, 0, wid, hei);
// Restore hue after inverting colors
XRenderComposite(ps->dpy, PictOpHSLHue, pict, None,
invpict, 0, 0, 0, 0, 0, 0, wid, hei);
// We use an extra PictOpInReverse operation to get correct pixel
// alpha. There could be a better solution.
if (WMODE_ARGB == w->mode)
XRenderComposite(ps->dpy, PictOpInReverse, pict, None,
newpict, 0, 0, 0, 0, 0, 0, wid, hei);
pict = newpict;
invpict, 0, 0, 0, 0, 0, 0, wid, hei);
}
}

const double dopacity = get_opacity_percent(w);

if (!w->frame_opacity) {
if (!w->frame_opacity && !invert_color) {
// If neither frame opacity nor inverted color is required
win_render(ps, w, 0, 0, wid, hei, dopacity, reg_paint, pcache_reg, pict);
}
else {
Expand All @@ -1638,9 +1643,10 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint,
const int l = extents.left;
const int b = extents.bottom;
const int r = extents.right;
const double frame_opacity = w->frame_opacity ? w->frame_opacity : 1.0;

#define COMP_BDR(cx, cy, cwid, chei) \
win_render(ps, w, (cx), (cy), (cwid), (chei), w->frame_opacity, \
win_render(ps, w, (cx), (cy), (cwid), (chei), frame_opacity, \
reg_paint, pcache_reg, pict)

// The following complicated logic is required because some broken
Expand Down Expand Up @@ -1676,7 +1682,8 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint,
pwid = wid - l - pwid;
if (pwid > 0) {
// body
win_render(ps, w, l, t, pwid, phei, dopacity, reg_paint, pcache_reg, pict);
win_render(ps, w, l, t, pwid, phei, dopacity, reg_paint, pcache_reg,
invpict ? invpict : pict);
}
}
}
Expand All @@ -1685,8 +1692,8 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint,

#undef COMP_BDR

if (pict != w->paint.pict)
free_picture(ps, &pict);
if (invpict)
free_picture(ps, &invpict);

// Dimming the window if needed
if (w->dim) {
Expand Down Expand Up @@ -2013,7 +2020,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
glFlush();
glXWaitX();
glx_render(ps, ps->tgt_buffer.ptex, 0, 0, 0, 0,
ps->root_width, ps->root_height, 0, 1.0, false, false,
ps->root_width, ps->root_height, 0, 1.0, false, false, NULL,
region_real, NULL, NULL);
// No break here!
case BKEND_GLX:
Expand Down Expand Up @@ -2759,7 +2766,7 @@ win_mark_client(session_t *ps, win *w, Window client) {
win_upd_wintype(ps, w);

// Get frame widths. The window is in damaged area already.
if (ps->o.frame_opacity)
if (ps->o.frame_opacity || ps->o.invert_color_list)
get_frame_extents(ps, w, client);

// Get window group
Expand Down Expand Up @@ -4814,6 +4821,10 @@ usage(int ret) {
" GLX backend: Use specified GLSL fragment shader for rendering window\n"
" contents.\n"
"\n"
"--glx-fshader-win-file path\n"
" GLX backend: Load GLSL fragment shader from the given path and use it\n"
" for rendering window contents.\n"
"\n"
"--force-win-blend\n"
" Force all windows to be painted with blending. Useful if you have a\n"
" --glx-fshader-win that could turn opaque pixels transparent.\n"
Expand Down Expand Up @@ -5040,7 +5051,7 @@ parse_matrix(session_t *ps, const char *src, const char **endptr) {
int wid = 0, hei = 0;
const char *pc = NULL;
XFixed *matrix = NULL;

// Get matrix width and height
{
double val = 0.0;
Expand Down Expand Up @@ -5638,6 +5649,17 @@ parse_config(session_t *ps, struct options_tmp *pcfgtmp) {
exit(1);
// --glx-use-gpushader4
lcfg_lookup_bool(&cfg, "glx-use-gpushader4", &ps->o.glx_use_gpushader4);
// --glx-fshader-win
if (config_lookup_string(&cfg, "glx-fshader-win", &sval))
ps->o.glx_fshader_win_str = mstrcpy(sval);
// --glx-fshader-win-file
if (config_lookup_string(&cfg, "glx-fshader-win-file", &sval)
&& !(ps->o.glx_fshader_win_str = mfread(sval))) {
printf("Cannot read file %s\n", sval);
exit(1);
}
// --glx-reinit-on-root-change
lcfg_lookup_bool(&cfg, "glx-reinit-on-root-change", &ps->o.glx_reinit_on_root_change);
// --xrender-sync
lcfg_lookup_bool(&cfg, "xrender-sync", &ps->o.xrender_sync);
// --xrender-sync-fence
Expand Down Expand Up @@ -5753,6 +5775,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
{ "no-fading-destroyed-argb", no_argument, NULL, 315 },
{ "force-win-blend", no_argument, NULL, 316 },
{ "glx-fshader-win", required_argument, NULL, 317 },
{ "glx-fshader-win-file", required_argument, NULL, 321 },
{ "version", no_argument, NULL, 318 },
{ "no-x-selection", no_argument, NULL, 319 },
{ "no-name-pixmap", no_argument, NULL, 320 },
Expand Down Expand Up @@ -6026,6 +6049,12 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
case 317:
ps->o.glx_fshader_win_str = mstrcpy(optarg);
break;
case 321:
if (!(ps->o.glx_fshader_win_str = mfread(optarg))) {
printf("Cannot read file %s\n", optarg);
exit(1);
}
break;
P_CASEBOOL(319, no_x_selection);
P_CASEBOOL(731, reredir_on_root_change);
P_CASEBOOL(732, glx_reinit_on_root_change);
Expand Down
11 changes: 6 additions & 5 deletions src/compton.h
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ paint_preprocess(session_t *ps, win *list);

static void
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, margin_t *margin,
Picture pict, glx_texture_t *ptex,
XserverRegion reg_paint, const reg_data_t *pcache_reg
#ifdef CONFIG_VSYNC_OPENGL_GLSL
Expand All @@ -699,12 +699,12 @@ render_(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,

#ifdef CONFIG_VSYNC_OPENGL_GLSL
#define \
render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, pict, ptex, reg_paint, pcache_reg, pprogram) \
render_(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, pict, ptex, reg_paint, pcache_reg, pprogram)
render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, margin, pict, ptex, reg_paint, pcache_reg, pprogram) \
render_(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, margin, pict, ptex, reg_paint, pcache_reg, pprogram)
#else
#define \
render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, pict, ptex, reg_paint, pcache_reg, pprogram) \
render_(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, pict, ptex, reg_paint, pcache_reg)
render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, margin, pict, ptex, reg_paint, pcache_reg, pprogram) \
render_(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, margin, pict, ptex, reg_paint, pcache_reg)
#endif

static inline void
Expand All @@ -717,6 +717,7 @@ win_render(session_t *ps, win *w, int x, int y, int wid, int hei,
const bool neg = (w && w->invert_color);

render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg,
(w ? &w->frame_extents : NULL),
pict, (w ? w->paint.ptex: ps->root_tile_paint.ptex),
reg_paint, pcache_reg, (w ? &ps->o.glx_prog_win: NULL));
}
Expand Down
11 changes: 10 additions & 1 deletion src/opengl.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ glx_free_prog_main(session_t *ps, glx_prog_main_t *pprogram) {
pprogram->unifm_opacity = -1;
pprogram->unifm_invert_color = -1;
pprogram->unifm_tex = -1;
pprogram->unifm_margin = -1;
}

#endif
Expand Down Expand Up @@ -558,6 +559,7 @@ glx_load_prog_main(session_t *ps,
P_GET_UNIFM_LOC("opacity", unifm_opacity);
P_GET_UNIFM_LOC("invert_color", unifm_invert_color);
P_GET_UNIFM_LOC("tex", unifm_tex);
P_GET_UNIFM_LOC("margin", unifm_margin);
#undef P_GET_UNIFM_LOC

glx_check_err(ps);
Expand Down Expand Up @@ -1425,7 +1427,7 @@ glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
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,
double opacity, bool argb, bool neg, margin_t *margin,
XserverRegion reg_tgt, const reg_data_t *pcache_reg
#ifdef CONFIG_VSYNC_OPENGL_GLSL
, const glx_prog_main_t *pprogram
Expand Down Expand Up @@ -1554,6 +1556,13 @@ glx_render_(session_t *ps, const glx_texture_t *ptex,
glUniform1i(pprogram->unifm_invert_color, neg);
if (pprogram->unifm_tex >= 0)
glUniform1i(pprogram->unifm_tex, 0);
if (margin && pprogram->unifm_margin >= 0)
glUniform4f(pprogram->unifm_margin,
(float) margin->left / ptex->width,
(float) margin->top / ptex->height,
1.0 - (float) margin->right / ptex->width,
1.0 - (float) margin->bottom / ptex->height
);
}
#endif

Expand Down