Move rendering related functions out of compton.c

Moved:
* Blur kernel related functions to kernel.c
* Vsync related functions to vsync.c
* paint related functions to render.c

This will make the `split-backend` branch easier to rebase.

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2018-12-15 21:11:41 +00:00
parent 85c5d34ce1
commit baeb4572ff
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
16 changed files with 1726 additions and 1647 deletions

View File

@ -138,6 +138,7 @@
#include "log.h"
#include "utils.h"
#include "compiler.h"
#include "kernel.h"
// === Constants ===
@ -354,7 +355,7 @@ typedef struct {
GLint unifm_factor_center;
} glx_blur_pass_t;
typedef struct {
typedef struct glx_prog_main {
/// GLSL program.
GLuint prog;
/// Location of uniform "opacity" in window GLSL program.
@ -379,11 +380,6 @@ typedef uint32_t glx_prog_main_t;
#define PAINT_INIT { .pixmap = None, .pict = None }
typedef struct conv {
int size;
double data[];
} conv;
/// Linked list type of atoms.
typedef struct _latom {
Atom atom;
@ -1308,18 +1304,6 @@ bkend_use_glx(session_t *ps) {
|| BKEND_XR_GLX_HYBRID == ps->o.backend;
}
/**
* Check if there's a GLX context.
*/
static inline bool
glx_has_context(session_t *ps) {
#ifdef CONFIG_OPENGL
return ps->psglx && ps->psglx->context;
#else
return false;
#endif
}
/**
* Check if a window is really focused.
*/
@ -1483,53 +1467,6 @@ vsync_deinit(session_t *ps);
*/
///@{
/**
* 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) {
#ifdef CONFIG_OPENGL
if (*pfbo) {
glDeleteFramebuffers(1, pfbo);
*pfbo = 0;
}
#endif
assert(!*pfbo);
}
#ifdef CONFIG_OPENGL
/**
* 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);
}
#endif
#endif
/**

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@
#include "x.h"
#include "c2.h"
#include "log.h" // XXX clean up
#include "render.h"
// == Functions ==
// TODO move static inline functions that are only used in compton.c, into
@ -53,16 +54,6 @@ win *find_toplevel2(session_t *ps, Window wid);
void map_win(session_t *ps, Window id);
/**
* Reset filter on a <code>Picture</code>.
*/
static inline void
xrfilter_reset(session_t *ps, xcb_render_picture_t p) {
#define FILTER "Nearest"
xcb_render_set_picture_filter(ps->c, p, strlen(FILTER), FILTER, 0, NULL);
#undef FILTER
}
/**
* Subtract two unsigned long values.
*
@ -103,17 +94,6 @@ array_wid_exists(const Window *arr, int count, Window wid) {
return false;
}
/**
* Destroy a <code>Picture</code>.
*/
inline static void
free_picture(session_t *ps, xcb_render_picture_t *p) {
if (*p) {
xcb_render_free_picture(ps->c, *p);
*p = None;
}
}
/**
* Destroy a condition list.
*/
@ -123,29 +103,7 @@ free_wincondlst(c2_lptr_t **pcondlst) {
continue;
}
#ifdef CONFIG_OPENGL
/**
* Bind texture in paint_t if we are using GLX backend.
*/
static inline bool
paint_bind_tex(session_t *ps, paint_t *ppaint,
unsigned wid, unsigned hei, unsigned depth, bool force)
{
if (!ppaint->pixmap)
return false;
if (force || !glx_tex_binded(ppaint->ptex, ppaint->pixmap))
return glx_bind_pixmap(ps, &ppaint->ptex, ppaint->pixmap, wid, hei, depth);
return true;
}
#else
static inline bool
paint_bind_tex(session_t *ps, paint_t *ppaint,
unsigned wid, unsigned hei, unsigned depth, bool force)
{
return true;
}
#ifndef CONFIG_OPENGL
static inline void
free_paint_glx(session_t *ps, paint_t *p) {}
static inline void
@ -156,18 +114,6 @@ free_texture(session_t *ps, glx_texture_t **t) {
}
#endif
/**
* Free paint_t.
*/
static inline void
free_paint(session_t *ps, paint_t *ppaint) {
free_paint_glx(ps, ppaint);
free_picture(ps, &ppaint->pict);
if (ppaint->pixmap)
xcb_free_pixmap(ps->c, ppaint->pixmap);
ppaint->pixmap = XCB_NONE;
}
/**
* Create a XTextProperty of a single string.
*/
@ -220,59 +166,14 @@ dump_drawable(session_t *ps, Drawable drawable) {
}
}
/**
* Validate a pixmap.
*
* Detect whether the pixmap is valid with XGetGeometry. Well, maybe there
* are better ways.
*/
static inline bool
validate_pixmap(session_t *ps, xcb_pixmap_t pxmap) {
if (!pxmap) return false;
Window rroot = None;
int rx = 0, ry = 0;
unsigned rwid = 0, rhei = 0, rborder = 0, rdepth = 0;
return XGetGeometry(ps->dpy, pxmap, &rroot, &rx, &ry,
&rwid, &rhei, &rborder, &rdepth) && rwid && rhei;
}
/**
* Validate pixmap of a window, and destroy pixmap and picture if invalid.
*/
static inline void
win_validate_pixmap(session_t *ps, win *w) {
// Destroy pixmap and picture, if invalid
if (!validate_pixmap(ps, w->paint.pixmap))
if (!x_validate_pixmap(ps, w->paint.pixmap))
free_paint(ps, &w->paint);
}
/**
* Normalize a convolution kernel.
*/
static inline void
normalize_conv_kern(int wid, int hei, xcb_render_fixed_t *kern) {
double sum = 0.0;
for (int i = 0; i < wid * hei; ++i)
sum += XFIXED_TO_DOUBLE(kern[i]);
double factor = 1.0 / sum;
for (int i = 0; i < wid * hei; ++i)
kern[i] = DOUBLE_TO_XFIXED(XFIXED_TO_DOUBLE(kern[i]) * factor);
}
#ifdef CONFIG_OPENGL
/**
* 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;
}
#endif
// vim: set et sw=2 :

121
src/kernel.c Normal file
View File

@ -0,0 +1,121 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#include <math.h>
#include "utils.h"
#include "kernel.h"
/*
* A picture will help
*
* -center 0 width width+center
* -center +-----+-------------------+-----+
* | | | |
* | | | |
* 0 +-----+-------------------+-----+
* | | | |
* | | | |
* | | | |
* height +-----+-------------------+-----+
* | | | |
* height+ | | | |
* center +-----+-------------------+-----+
*/
double
sum_kernel(conv *map, int x, int y, int width, int height) {
int fx, fy;
double *g_data;
double *g_line = map->data;
int g_size = map->size;
int center = g_size / 2;
int fx_start, fx_end;
int fy_start, fy_end;
double v;
/*
* Compute set of filter values which are "in range",
* that's the set with:
* 0 <= x + (fx-center) && x + (fx-center) < width &&
* 0 <= y + (fy-center) && y + (fy-center) < height
*
* 0 <= x + (fx - center) x + fx - center < width
* center - x <= fx fx < width + center - x
*/
fx_start = center - x;
if (fx_start < 0)
fx_start = 0;
fx_end = width + center - x;
if (fx_end > g_size)
fx_end = g_size;
fy_start = center - y;
if (fy_start < 0)
fy_start = 0;
fy_end = height + center - y;
if (fy_end > g_size)
fy_end = g_size;
g_line = g_line + fy_start * g_size + fx_start;
v = 0;
for (fy = fy_start; fy < fy_end; fy++) {
g_data = g_line;
g_line += g_size;
for (fx = fx_start; fx < fx_end; fx++) {
v += *g_data++;
}
}
if (v > 1)
v = 1;
return v;
}
static double __attribute__((const)) gaussian(double r, double x, double y) {
// Formula can be found here:
// https://en.wikipedia.org/wiki/Gaussian_blur#Mathematics
// Except a special case for r == 0 to produce sharp shadows
if (r == 0)
return 1;
return exp(-0.5 * (x * x + y * y) / (r * r)) / (2 * M_PI * r * r);
}
conv *gaussian_kernel(double r) {
conv *c;
int size = r * 2 + 1;
int center = size / 2;
double t;
c = cvalloc(sizeof(conv) + size * size * sizeof(double));
c->size = size;
t = 0.0;
/*printf_errf("(): %f", r);*/
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
double g = gaussian(r, x - center, y - center);
t += g;
c->data[y * size + x] = g;
/*printf("%f ", c->data[y*size+x]);*/
}
/*printf("\n");*/
}
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
c->data[y * size + x] /= t;
/*printf("%f ", c->data[y*size+x]);*/
}
/*printf("\n");*/
}
return c;
}
// vim: set noet sw=8 ts=8 :

19
src/kernel.h Normal file
View File

@ -0,0 +1,19 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#pragma once
/// Code for generating convolution kernels
typedef struct conv {
int size;
double data[];
} conv;
/// Calculate the sum of a rectangle part of the convolution kernel
/// the rectangle is defined by top left (x, y), and a size (width x height)
double
sum_kernel(conv *map, int x, int y, int width, int height);
/// Create a kernel with gaussian distribution of radius r
conv *gaussian_kernel(double r);

View File

@ -4,7 +4,8 @@ deps = [
dependency('xcb', version: '>=1.9.2'),
]
srcs = ['compton.c', 'win.c', 'c2.c', 'x.c', 'config.c', 'diagnostic.c', 'string_utils.c']
srcs = [ files('compton.c', 'win.c', 'c2.c', 'x.c', 'config.c', 'vsync.c',
'diagnostic.c', 'string_utils.c', 'render.c', 'kernel.c')]
cflags = []

View File

@ -199,6 +199,70 @@ glx_create_program_from_str(const char *vert_shader_str,
unsigned char *
glx_take_screenshot(session_t *ps, int *out_length);
/**
* 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);
}
/**
* Free a glx_texture_t.
*/

1090
src/render.c Normal file

File diff suppressed because it is too large Load Diff

32
src/render.h Normal file
View File

@ -0,0 +1,32 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#pragma once
#include <xcb/render.h>
#include "region.h"
typedef struct _glx_texture glx_texture_t;
typedef struct glx_prog_main glx_prog_main_t;
typedef struct win win;
typedef struct session session_t;
typedef struct paint {
xcb_pixmap_t pixmap;
xcb_render_picture_t pict;
glx_texture_t *ptex;
} paint_t;
void
render(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
double opacity, bool argb, bool neg,
xcb_render_picture_t pict, glx_texture_t *ptex,
const region_t *reg_paint, const glx_prog_main_t *pprogram);
void
paint_one(session_t *ps, win *w, const region_t *reg_paint);
void
paint_all(session_t *ps, region_t *region, const region_t *region_real, win * const t);
void free_picture(xcb_connection_t *c, xcb_render_picture_t *p);
void free_paint(session_t *ps, paint_t *ppaint);

View File

@ -1,3 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#include <string.h>
#include "compiler.h"

290
src/vsync.c Normal file
View File

@ -0,0 +1,290 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
/// Function pointers to init VSync modes.
#include "common.h"
#include "log.h"
#include "opengl.h"
#include "vsync.h"
/**
* Initialize DRM VSync.
*
* @return true for success, false otherwise
*/
static bool
vsync_drm_init(session_t *ps) {
#ifdef CONFIG_VSYNC_DRM
// Should we always open card0?
if (ps->drm_fd < 0 && (ps->drm_fd = open("/dev/dri/card0", O_RDWR)) < 0) {
printf_errf("(): Failed to open device.");
return false;
}
if (vsync_drm_wait(ps))
return false;
return true;
#else
printf_errf("(): Program not compiled with DRM VSync support.");
return false;
#endif
}
/**
* Initialize OpenGL VSync.
*
* Stolen from: http://git.tuxfamily.org/?p=ccm/cairocompmgr.git;a=commitdiff;h=efa4ceb97da501e8630ca7f12c99b1dce853c73e
* Possible original source: http://www.inb.uni-luebeck.de/~boehme/xvideo_sync.html
*
* @return true for success, false otherwise
*/
static bool
vsync_opengl_init(session_t *ps) {
#ifdef CONFIG_OPENGL
if (!ensure_glx_context(ps))
return false;
if (!glx_hasglxext(ps, "GLX_SGI_video_sync")) {
printf_errf("(): Your driver doesn't support SGI_video_sync, giving up.");
return false;
}
// Get video sync functions
if (!ps->psglx->glXGetVideoSyncSGI)
ps->psglx->glXGetVideoSyncSGI = (f_GetVideoSync)
glXGetProcAddress((const GLubyte *) "glXGetVideoSyncSGI");
if (!ps->psglx->glXWaitVideoSyncSGI)
ps->psglx->glXWaitVideoSyncSGI = (f_WaitVideoSync)
glXGetProcAddress((const GLubyte *) "glXWaitVideoSyncSGI");
if (!ps->psglx->glXWaitVideoSyncSGI || !ps->psglx->glXGetVideoSyncSGI) {
printf_errf("(): Failed to get glXWait/GetVideoSyncSGI function.");
return false;
}
return true;
#else
printf_errf("(): Program not compiled with OpenGL VSync support.");
return false;
#endif
}
static bool
vsync_opengl_oml_init(session_t *ps) {
#ifdef CONFIG_OPENGL
if (!ensure_glx_context(ps))
return false;
if (!glx_hasglxext(ps, "GLX_OML_sync_control")) {
printf_errf("(): Your driver doesn't support OML_sync_control, giving up.");
return false;
}
// Get video sync functions
if (!ps->psglx->glXGetSyncValuesOML)
ps->psglx->glXGetSyncValuesOML = (f_GetSyncValuesOML)
glXGetProcAddress ((const GLubyte *) "glXGetSyncValuesOML");
if (!ps->psglx->glXWaitForMscOML)
ps->psglx->glXWaitForMscOML = (f_WaitForMscOML)
glXGetProcAddress ((const GLubyte *) "glXWaitForMscOML");
if (!ps->psglx->glXGetSyncValuesOML || !ps->psglx->glXWaitForMscOML) {
printf_errf("(): Failed to get OML_sync_control functions.");
return false;
}
return true;
#else
printf_errf("(): Program not compiled with OpenGL VSync support.");
return false;
#endif
}
static bool
vsync_opengl_swc_swap_interval(session_t *ps, unsigned int interval) {
#ifdef CONFIG_OPENGL
if (!ensure_glx_context(ps))
return false;
if (!ps->psglx->glXSwapIntervalProc && !ps->psglx->glXSwapIntervalMESAProc) {
if (glx_hasglxext(ps, "GLX_MESA_swap_control")) {
ps->psglx->glXSwapIntervalMESAProc = (f_SwapIntervalMESA)
glXGetProcAddress ((const GLubyte *) "glXSwapIntervalMESA");
} else if (glx_hasglxext(ps, "GLX_SGI_swap_control")) {
ps->psglx->glXSwapIntervalProc = (f_SwapIntervalSGI)
glXGetProcAddress ((const GLubyte *) "glXSwapIntervalSGI");
} else {
printf_errf("(): Your driver doesn't support SGI_swap_control nor MESA_swap_control, giving up.");
return false;
}
}
if (ps->psglx->glXSwapIntervalMESAProc)
ps->psglx->glXSwapIntervalMESAProc(interval);
else if (ps->psglx->glXSwapIntervalProc)
ps->psglx->glXSwapIntervalProc(interval);
else
return false;
#endif
return true;
}
static bool
vsync_opengl_swc_init(session_t *ps) {
#ifdef CONFIG_OPENGL
if (!bkend_use_glx(ps)) {
printf_errf("(): OpenGL swap control requires the GLX backend.");
return false;
}
if (!vsync_opengl_swc_swap_interval(ps, 1)) {
printf_errf("(): Failed to load a swap control extension.");
return false;
}
return true;
#else
printf_errf("(): Program not compiled with OpenGL VSync support.");
return false;
#endif
}
static bool
vsync_opengl_mswc_init(session_t *ps) {
printf_errf("(): opengl-mswc is deprecated, please use opengl-swc instead.");
return vsync_opengl_swc_init(ps);
}
bool (*const VSYNC_FUNCS_INIT[])(session_t *ps) = {
[VSYNC_DRM ] = vsync_drm_init,
[VSYNC_OPENGL ] = vsync_opengl_init,
[VSYNC_OPENGL_OML ] = vsync_opengl_oml_init,
[VSYNC_OPENGL_SWC ] = vsync_opengl_swc_init,
[VSYNC_OPENGL_MSWC ] = vsync_opengl_mswc_init,
};
#ifdef CONFIG_VSYNC_DRM
/**
* Wait for next VSync, DRM method.
*
* Stolen from: https://github.com/MythTV/mythtv/blob/master/mythtv/libs/libmythtv/vsync.cpp
*/
static int
vsync_drm_wait(session_t *ps) {
int ret = -1;
drm_wait_vblank_t vbl;
vbl.request.type = _DRM_VBLANK_RELATIVE,
vbl.request.sequence = 1;
do {
ret = ioctl(ps->drm_fd, DRM_IOCTL_WAIT_VBLANK, &vbl);
vbl.request.type &= ~_DRM_VBLANK_RELATIVE;
} while (ret && errno == EINTR);
if (ret)
fprintf(stderr, "vsync_drm_wait(): VBlank ioctl did not work, "
"unimplemented in this drmver?\n");
return ret;
}
#endif
#ifdef CONFIG_OPENGL
/**
* Wait for next VSync, OpenGL method.
*/
static int
vsync_opengl_wait(session_t *ps) {
unsigned vblank_count = 0;
ps->psglx->glXGetVideoSyncSGI(&vblank_count);
ps->psglx->glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count);
// I see some code calling glXSwapIntervalSGI(1) afterwards, is it required?
return 0;
}
/**
* Wait for next VSync, OpenGL OML method.
*
* https://mail.gnome.org/archives/clutter-list/2012-November/msg00031.html
*/
static int
vsync_opengl_oml_wait(session_t *ps) {
int64_t ust = 0, msc = 0, sbc = 0;
ps->psglx->glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc);
ps->psglx->glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2,
&ust, &msc, &sbc);
return 0;
}
#endif
/// Function pointers to wait for VSync.
int (*const VSYNC_FUNCS_WAIT[])(session_t *ps) = {
#ifdef CONFIG_VSYNC_DRM
[VSYNC_DRM ] = vsync_drm_wait,
#endif
#ifdef CONFIG_OPENGL
[VSYNC_OPENGL ] = vsync_opengl_wait,
[VSYNC_OPENGL_OML ] = vsync_opengl_oml_wait,
#endif
};
#ifdef CONFIG_OPENGL
static void
vsync_opengl_swc_deinit(session_t *ps) {
vsync_opengl_swc_swap_interval(ps, 0);
}
#endif
/// Function pointers to deinitialize VSync.
void (*const VSYNC_FUNCS_DEINIT[])(session_t *ps) = {
#ifdef CONFIG_OPENGL
[VSYNC_OPENGL_SWC ] = vsync_opengl_swc_deinit,
[VSYNC_OPENGL_MSWC ] = vsync_opengl_swc_deinit,
#endif
};
/**
* Initialize current VSync method.
*/
bool vsync_init(session_t *ps) {
// Mesa turns on swap control by default, undo that
if (bkend_use_glx(ps))
vsync_opengl_swc_swap_interval(ps, 0);
if (ps->o.vsync && VSYNC_FUNCS_INIT[ps->o.vsync]
&& !VSYNC_FUNCS_INIT[ps->o.vsync](ps)) {
ps->o.vsync = VSYNC_NONE;
return false;
}
else
return true;
}
/**
* Wait for next VSync.
*/
void vsync_wait(session_t *ps) {
if (!ps->o.vsync)
return;
if (VSYNC_FUNCS_WAIT[ps->o.vsync])
VSYNC_FUNCS_WAIT[ps->o.vsync](ps);
}
/**
* Deinitialize current VSync method.
*/
void vsync_deinit(session_t *ps) {
if (ps->o.vsync && VSYNC_FUNCS_DEINIT[ps->o.vsync])
VSYNC_FUNCS_DEINIT[ps->o.vsync](ps);
}

9
src/vsync.h Normal file
View File

@ -0,0 +1,9 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Yuxuan Shui <yshuiv7@gmail.com>
#include <stdbool.h>
typedef struct session session_t;
bool vsync_init(session_t *ps);
void vsync_wait(session_t *ps);
void vsync_deinit(session_t *ps);

View File

@ -1289,3 +1289,35 @@ void win_ev_stop(session_t *ps, win *w) {
xcb_shape_select_input(ps->c, w->id, 0));
}
}
/**
* Set fade callback of a window, and possibly execute the previous
* callback.
*
* If a callback can cause rendering result to change, it should call
* `queue_redraw`.
*
* @param exec_callback whether the previous callback is to be executed
*/
void win_set_fade_callback(session_t *ps, win **_w,
void (*callback) (session_t *ps, win **w), bool exec_callback) {
win *w = *_w;
void (*old_callback) (session_t *ps, win **w) = w->fade_callback;
w->fade_callback = callback;
// Must be the last line as the callback could destroy w!
if (exec_callback && old_callback)
old_callback(ps, _w);
}
/**
* Execute fade callback of a window if fading finished.
*/
void
win_check_fade_finished(session_t *ps, win **_w) {
win *w = *_w;
if (w->fade_callback && w->opacity == w->opacity_tgt) {
// Must be the last line as the callback could destroy w!
win_set_fade_callback(ps, _w, NULL, true);
}
}

View File

@ -16,17 +16,11 @@
#include "x.h"
#include "types.h"
#include "c2.h"
#include "render.h"
typedef struct session session_t;
typedef struct _glx_texture glx_texture_t;
// FIXME not the best place for this type
typedef struct {
xcb_pixmap_t pixmap;
xcb_render_picture_t pict;
glx_texture_t *ptex;
} paint_t;
#ifdef CONFIG_OPENGL
// FIXME this type should be in opengl.h
// it is very unideal for it to be here
@ -335,6 +329,24 @@ void
win_update_frame_extents(session_t *ps, win *w, Window client);
bool add_win(session_t *ps, Window id, Window prev);
/**
* Set fade callback of a window, and possibly execute the previous
* callback.
*
* If a callback can cause rendering result to change, it should call
* `queue_redraw`.
*
* @param exec_callback whether the previous callback is to be executed
*/
void win_set_fade_callback(session_t *ps, win **_w,
void (*callback) (session_t *ps, win **w), bool exec_callback);
/**
* Execute fade callback of a window if fading finished.
*/
void
win_check_fade_finished(session_t *ps, win **_w);
// Stop receiving events (except ConfigureNotify, XXX why?) from a window
void win_ev_stop(session_t *ps, win *w);

17
src/x.c
View File

@ -377,3 +377,20 @@ x_create_pixmap(session_t *ps, uint8_t depth, xcb_drawable_t drawable, uint16_t
free(err);
return XCB_NONE;
}
/**
* Validate a pixmap.
*
* Detect whether the pixmap is valid with XGetGeometry. Well, maybe there
* are better ways.
*/
bool
x_validate_pixmap(session_t *ps, xcb_pixmap_t pxmap) {
if (!pxmap) return false;
Window rroot = None;
int rx = 0, ry = 0;
unsigned rwid = 0, rhei = 0, rborder = 0, rdepth = 0;
return XGetGeometry(ps->dpy, pxmap, &rroot, &rx, &ry,
&rwid, &rhei, &rborder, &rdepth) && rwid && rhei;
}

View File

@ -137,6 +137,9 @@ x_print_error(unsigned long serial, uint8_t major, uint8_t minor, uint8_t error_
xcb_pixmap_t
x_create_pixmap(session_t *ps, uint8_t depth, xcb_drawable_t drawable, uint16_t width, uint16_t height);
bool
x_validate_pixmap(session_t *ps, xcb_pixmap_t pxmap);
/**
* Free a <code>winprop_t</code>.
*