2018-10-04 05:14:51 +08:00
|
|
|
// SPDX-License-Identifier: MIT
|
2013-03-15 23:16:23 +08:00
|
|
|
/*
|
|
|
|
* Compton - a compositor for X11
|
|
|
|
*
|
|
|
|
* Based on `xcompmgr` - Copyright (c) 2003, Keith Packard
|
|
|
|
*
|
|
|
|
* Copyright (c) 2011-2013, Christopher Jeffrey
|
2018-10-04 05:24:12 +08:00
|
|
|
* See LICENSE-mit for more information.
|
2013-03-15 23:16:23 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2018-10-04 05:14:51 +08:00
|
|
|
#pragma once
|
|
|
|
|
2013-03-15 23:16:23 +08:00
|
|
|
#include "common.h"
|
2019-01-19 07:30:44 +08:00
|
|
|
#include "region.h"
|
|
|
|
#include "render.h"
|
|
|
|
#include "compiler.h"
|
|
|
|
#include "win.h"
|
2018-12-16 01:53:17 +08:00
|
|
|
#include "log.h"
|
2013-03-15 23:16:23 +08:00
|
|
|
|
2019-01-21 05:15:20 +08:00
|
|
|
#include <xcb/xcb.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2013-03-15 23:16:23 +08:00
|
|
|
#include <ctype.h>
|
2013-09-15 08:56:53 +08:00
|
|
|
#include <locale.h>
|
2019-01-21 05:15:20 +08:00
|
|
|
#include <GL/glx.h>
|
2013-03-15 23:16:23 +08:00
|
|
|
|
2018-12-31 08:38:13 +08:00
|
|
|
/// @brief Wrapper of a GLX FBConfig.
|
|
|
|
typedef struct glx_fbconfig {
|
|
|
|
GLXFBConfig cfg;
|
|
|
|
GLint texture_fmt;
|
|
|
|
GLint texture_tgts;
|
|
|
|
bool y_inverted;
|
|
|
|
} glx_fbconfig_t;
|
|
|
|
|
2013-03-16 22:54:43 +08:00
|
|
|
/**
|
|
|
|
* Check if a word is in string.
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
wd_is_in_str(const char *haystick, const char *needle) {
|
|
|
|
if (!haystick)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
assert(*needle);
|
|
|
|
|
|
|
|
const char *pos = haystick - 1;
|
|
|
|
while ((pos = strstr(pos + 1, needle))) {
|
|
|
|
// Continue if it isn't a word boundary
|
|
|
|
if (((pos - haystick) && !isspace(*(pos - 1)))
|
|
|
|
|| (strlen(pos) > strlen(needle) && !isspace(pos[strlen(needle)])))
|
|
|
|
continue;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-03-15 23:16:23 +08:00
|
|
|
/**
|
|
|
|
* Check if a GLX extension exists.
|
|
|
|
*/
|
|
|
|
static inline bool
|
2013-03-16 22:54:43 +08:00
|
|
|
glx_hasglxext(session_t *ps, const char *ext) {
|
2013-03-15 23:16:23 +08:00
|
|
|
const char *glx_exts = glXQueryExtensionsString(ps->dpy, ps->scr);
|
2013-03-16 22:54:43 +08:00
|
|
|
if (!glx_exts) {
|
2018-12-20 10:49:29 +08:00
|
|
|
log_error("Failed get GLX extension list.");
|
2013-03-15 23:16:23 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-03-16 22:54:43 +08:00
|
|
|
bool found = wd_is_in_str(glx_exts, ext);
|
|
|
|
if (!found)
|
2018-12-20 10:49:29 +08:00
|
|
|
log_info("Missing GLX extension %s.", ext);
|
2013-03-16 22:54:43 +08:00
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2018-09-30 05:47:12 +08:00
|
|
|
bool
|
|
|
|
glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
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>
2018-09-30 11:56:00 +08:00
|
|
|
GLfloat factor, const region_t *reg_tgt);
|
2018-09-30 05:47:12 +08:00
|
|
|
|
|
|
|
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,
|
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>
2018-09-30 11:56:00 +08:00
|
|
|
const region_t *reg_tgt,
|
2018-09-30 05:47:12 +08:00
|
|
|
const glx_prog_main_t *pprogram);
|
|
|
|
|
|
|
|
bool
|
|
|
|
glx_init(session_t *ps, bool need_render);
|
|
|
|
|
|
|
|
void
|
|
|
|
glx_destroy(session_t *ps);
|
|
|
|
|
|
|
|
bool
|
|
|
|
glx_reinit(session_t *ps, bool need_render);
|
|
|
|
|
|
|
|
void
|
|
|
|
glx_on_root_change(session_t *ps);
|
|
|
|
|
|
|
|
bool
|
|
|
|
glx_init_blur(session_t *ps);
|
|
|
|
|
|
|
|
#ifdef CONFIG_OPENGL
|
|
|
|
bool
|
|
|
|
glx_load_prog_main(session_t *ps,
|
|
|
|
const char *vshader_str, const char *fshader_str,
|
|
|
|
glx_prog_main_t *pprogram);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool
|
2018-10-01 03:53:52 +08:00
|
|
|
glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, xcb_pixmap_t pixmap,
|
2018-09-30 05:47:12 +08:00
|
|
|
unsigned width, unsigned height, unsigned depth);
|
|
|
|
|
|
|
|
void
|
|
|
|
glx_release_pixmap(session_t *ps, glx_texture_t *ptex);
|
|
|
|
|
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>
2018-09-30 11:56:00 +08:00
|
|
|
void glx_paint_pre(session_t *ps, region_t *preg)
|
2018-12-20 04:50:02 +08:00
|
|
|
attr_nonnull(1, 2);
|
2018-09-30 05:47:12 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if a texture is binded, or is binded to the given pixmap.
|
|
|
|
*/
|
|
|
|
static inline bool
|
2018-10-01 03:53:52 +08:00
|
|
|
glx_tex_binded(const glx_texture_t *ptex, xcb_pixmap_t pixmap) {
|
2018-09-30 05:47:12 +08:00
|
|
|
return ptex && ptex->glpixmap && ptex->texture
|
|
|
|
&& (!pixmap || pixmap == ptex->pixmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
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>
2018-09-30 11:56:00 +08:00
|
|
|
glx_set_clip(session_t *ps, const region_t *reg);
|
2018-09-30 05:47:12 +08:00
|
|
|
|
|
|
|
bool
|
|
|
|
glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
|
|
|
|
GLfloat factor_center,
|
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>
2018-09-30 11:56:00 +08:00
|
|
|
const region_t *reg_tgt,
|
2018-09-30 05:47:12 +08:00
|
|
|
glx_blur_cache_t *pbc);
|
|
|
|
|
|
|
|
GLuint
|
|
|
|
glx_create_shader(GLenum shader_type, const char *shader_str);
|
|
|
|
|
|
|
|
GLuint
|
|
|
|
glx_create_program(const GLuint * const shaders, int nshaders);
|
|
|
|
|
|
|
|
GLuint
|
|
|
|
glx_create_program_from_str(const char *vert_shader_str,
|
|
|
|
const char *frag_shader_str);
|
|
|
|
|
|
|
|
unsigned char *
|
|
|
|
glx_take_screenshot(session_t *ps, int *out_length);
|
|
|
|
|
2018-12-16 05:11:41 +08:00
|
|
|
/**
|
|
|
|
* Check if there's a GLX context.
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
glx_has_context(session_t *ps) {
|
|
|
|
return ps->psglx && ps->psglx->context;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Ensure we have a GLX context.
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
ensure_glx_context(session_t *ps) {
|
|
|
|
// Create GLX context
|
|
|
|
if (!glx_has_context(ps))
|
|
|
|
glx_init(ps, false);
|
|
|
|
|
|
|
|
return ps->psglx->context;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free a GLX texture.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
free_texture_r(session_t *ps, GLuint *ptexture) {
|
|
|
|
if (*ptexture) {
|
|
|
|
assert(glx_has_context(ps));
|
|
|
|
glDeleteTextures(1, ptexture);
|
|
|
|
*ptexture = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free a GLX Framebuffer object.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
free_glx_fbo(session_t *ps, GLuint *pfbo) {
|
|
|
|
if (*pfbo) {
|
|
|
|
glDeleteFramebuffers(1, pfbo);
|
|
|
|
*pfbo = 0;
|
|
|
|
}
|
|
|
|
assert(!*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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free a glx_blur_cache_t
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
free_glx_bc(session_t *ps, glx_blur_cache_t *pbc) {
|
|
|
|
free_glx_fbo(ps, &pbc->fbo);
|
|
|
|
free_glx_bc_resize(ps, pbc);
|
|
|
|
}
|
|
|
|
|
2018-09-30 05:47:12 +08:00
|
|
|
/**
|
|
|
|
* Free a glx_texture_t.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
free_texture(session_t *ps, glx_texture_t **pptex) {
|
|
|
|
glx_texture_t *ptex = *pptex;
|
|
|
|
|
|
|
|
// Quit if there's nothing
|
|
|
|
if (!ptex)
|
|
|
|
return;
|
|
|
|
|
|
|
|
glx_release_pixmap(ps, ptex);
|
|
|
|
|
|
|
|
free_texture_r(ps, &ptex->texture);
|
|
|
|
|
|
|
|
// Free structure itself
|
|
|
|
free(ptex);
|
|
|
|
*pptex = NULL;
|
|
|
|
assert(!*pptex);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free GLX part of paint_t.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
free_paint_glx(session_t *ps, paint_t *ppaint) {
|
|
|
|
free_texture(ps, &ppaint->ptex);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Free GLX part of win.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
free_win_res_glx(session_t *ps, win *w) {
|
|
|
|
free_paint_glx(ps, &w->paint);
|
|
|
|
free_paint_glx(ps, &w->shadow_paint);
|
|
|
|
#ifdef CONFIG_OPENGL
|
|
|
|
free_glx_bc(ps, &w->glx_blur_cache);
|
|
|
|
#endif
|
|
|
|
}
|