Merge remote-tracking branch 'compton-update/master'

Conflicts:
	twin/compton-tde/common.h
	twin/compton-tde/compton.c
	twin/compton-tde/opengl.c
pull/2/head
Timothy Pearson 10 years ago
commit d74fed9b65

@ -764,6 +764,7 @@ c2_l_postprocess(session_t *ps, c2_l_t *pleaf) {
if (pleaf->predef) {
switch (pleaf->predef) {
case C2_L_PFOCUSED: ps->o.track_focus = true; break;
// case C2_L_PROUNDED: ps->o.detect_rounded_corners = true; break;
case C2_L_PNAME:
case C2_L_PCLASSG:
case C2_L_PCLASSI:
@ -1057,6 +1058,8 @@ c2_match_once_leaf(session_t *ps, win *w, const c2_l_t *pleaf,
case C2_L_PARGB: tgt = (WMODE_ARGB == w->mode); break;
case C2_L_PFOCUSED: tgt = win_is_focused_real(ps, w); break;
case C2_L_PWMWIN: tgt = w->wmwin; break;
case C2_L_PBSHAPED: tgt = w->bounding_shaped; break;
case C2_L_PROUNDED: tgt = w->rounded_corners; break;
case C2_L_PCLIENT: tgt = w->client_win; break;
case C2_L_PLEADER: tgt = w->leader; break;
default: *perr = true; assert(0); break;
@ -1292,6 +1295,8 @@ c2_match_once(session_t *ps, win *w, const c2_ptr_t cond) {
bool
c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst,
const c2_lptr_t **cache, void **pdata) {
assert(IsViewable == w->a.map_state);
// Check if the cached entry matches firstly
if (cache && *cache && c2_match_once(ps, w, (*cache)->ptr)) {
if (pdata)

@ -113,6 +113,8 @@ struct _c2_l {
C2_L_PARGB,
C2_L_PFOCUSED,
C2_L_PWMWIN,
C2_L_PBSHAPED,
C2_L_PROUNDED,
C2_L_PCLIENT,
C2_L_PWINDOWTYPE,
C2_L_PLEADER,
@ -201,6 +203,8 @@ const static c2_predef_t C2_PREDEFS[] = {
[C2_L_PARGB ] = { "argb" , C2_L_TCARDINAL , 0 },
[C2_L_PFOCUSED ] = { "focused" , C2_L_TCARDINAL , 0 },
[C2_L_PWMWIN ] = { "wmwin" , C2_L_TCARDINAL , 0 },
[C2_L_PBSHAPED ] = { "bounding_shaped" , C2_L_TCARDINAL , 0 },
[C2_L_PROUNDED ] = { "rounded_corners" , C2_L_TCARDINAL , 0 },
[C2_L_PCLIENT ] = { "client" , C2_L_TWINDOW , 0 },
[C2_L_PWINDOWTYPE ] = { "window_type" , C2_L_TSTRING , 0 },
[C2_L_PLEADER ] = { "leader" , C2_L_TWINDOW , 0 },

@ -17,6 +17,7 @@
// === Options ===
// Debug options, enable them using -D in CFLAGS
// #define DEBUG_BACKTRACE 1
// #define DEBUG_REPAINT 1
// #define DEBUG_EVENTS 1
// #define DEBUG_RESTACK 1
@ -83,6 +84,10 @@
#define COMPTON_VERSION "unknown"
#endif
#if defined(DEBUG_ALLOC_REG)
#define DEBUG_BACKTRACE 1
#endif
// === Includes ===
// For some special functions
@ -154,8 +159,6 @@
#define GLX_BACK_BUFFER_AGE_EXT 0x20F4
#endif
#endif
// === Macros ===
#define MSTR_(s) #s
@ -195,6 +198,11 @@
/// Macro used for shortening some debugging code.
#define CASESTRRET(s) case s: return #s
// X resource checker
#ifdef DEBUG_XRC
#include "xrescheck.h"
#endif
// === Constants ===
#if !(COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2)
#error libXcomposite version unsupported
@ -222,7 +230,7 @@
#define MS_PER_SEC 1000
#define XRFILTER_CONVOLUTION "convolution"
#define XRFILTER_GUASSIAN "gaussian"
#define XRFILTER_GAUSSIAN "gaussian"
#define XRFILTER_BINOMIAL "binomial"
/// @brief Maximum OpenGL FBConfig depth.
@ -454,7 +462,6 @@ struct _glx_texture {
unsigned depth;
bool y_inverted;
};
#endif
#ifdef CONFIG_VSYNC_OPENGL_GLSL
typedef struct {
@ -480,6 +487,26 @@ typedef struct {
/// Height of the textures.
int height;
} glx_blur_cache_t;
typedef struct {
/// GLSL program.
GLuint prog;
/// Location of uniform "opacity" in window GLSL program.
GLint unifm_opacity;
/// Location of uniform "invert_color" in blur GLSL program.
GLint unifm_invert_color;
/// Location of uniform "tex" in window GLSL program.
GLint unifm_tex;
} glx_prog_main_t;
#define GLX_PROG_MAIN_INIT { \
.prog = 0, \
.unifm_opacity = -1, \
.unifm_invert_color = -1, \
.unifm_tex = -1, \
}
#endif
#endif
typedef struct {
@ -547,10 +574,12 @@ typedef struct _options_t {
int glx_swap_method;
/// Whether to use GL_EXT_gpu_shader4 to (hopefully) accelerates blurring.
bool glx_use_gpushader4;
/// Whether to try to detect WM windows and mark them as focused.
bool mark_wmwin_focused;
/// Whether to mark override-redirect windows as focused.
bool mark_ovredir_focused;
/// Custom fragment shader for painting windows, as a string.
char *glx_fshader_win_str;
#ifdef CONFIG_VSYNC_OPENGL_GLSL
/// Custom GLX program used for painting window.
glx_prog_main_t glx_prog_win;
#endif
/// Whether to fork to background.
bool fork_after_register;
/// Whether to detect rounded corners.
@ -558,6 +587,8 @@ typedef struct _options_t {
/// Whether to paint on X Composite overlay window instead of root
/// window.
bool paint_on_overlay;
/// Force painting of window content with blending.
bool force_win_blend;
/// Resize damage for a specific number of pixels.
int resize_damage;
/// Whether to unredirect all windows if a full-screen opaque window
@ -572,6 +603,10 @@ typedef struct _options_t {
switch_t redirected_force;
/// Whether to stop painting. Controlled through D-Bus.
switch_t stoppaint_force;
/// Whether to re-redirect screen on root size change.
bool reredir_on_root_change;
/// Whether to reinitialize GLX on root size change.
bool glx_reinit_on_root_change;
/// Whether to enable D-Bus support.
bool dbus;
/// Path to log file.
@ -582,8 +617,14 @@ typedef struct _options_t {
Window benchmark_wid;
/// A list of conditions of windows not to paint.
c2_lptr_t *paint_blacklist;
/// Whether to avoid using XCompositeNameWindowPixmap(), for debugging.
bool no_name_pixmap;
/// Whether to work under synchronized mode for debugging.
bool synchronize;
/// Whether to show all X errors.
bool show_all_xerrors;
/// Whether to avoid acquiring X Selection.
bool no_x_selection;
// === VSync & software optimization ===
/// User-specified refresh rate.
@ -631,6 +672,8 @@ typedef struct _options_t {
time_ms_t fade_delta;
/// Whether to disable fading on window open/close.
bool no_fading_openclose;
/// Whether to disable fading on ARGB managed destroyed windows.
bool no_fading_destroyed_argb;
/// Whether to disable fading on opacity change
bool no_fading_opacitychange;
/// Fading blacklist. A linked list of conditions.
@ -683,6 +726,10 @@ typedef struct _options_t {
// === Focus related ===
/// Consider windows of specific types to be always focused.
bool wintype_focus[NUM_WINTYPES];
/// Whether to try to detect WM windows and mark them as focused.
bool mark_wmwin_focused;
/// Whether to mark override-redirect windows as focused.
bool mark_ovredir_focused;
/// Whether to use EWMH _NET_ACTIVE_WINDOW to find active window.
bool use_ewmh_active_win;
/// A list of windows always to be considered focused.
@ -701,6 +748,65 @@ typedef struct _options_t {
bool track_leader;
} options_t;
#ifdef CONFIG_VSYNC_OPENGL
/// Structure containing GLX-dependent data for a compton session.
typedef struct {
// === OpenGL related ===
/// GLX context.
GLXContext context;
/// Whether we have GL_ARB_texture_non_power_of_two.
bool has_texture_non_power_of_two;
/// Pointer to glXGetVideoSyncSGI function.
f_GetVideoSync glXGetVideoSyncSGI;
/// Pointer to glXWaitVideoSyncSGI function.
f_WaitVideoSync glXWaitVideoSyncSGI;
/// Pointer to glXGetSyncValuesOML function.
f_GetSyncValuesOML glXGetSyncValuesOML;
/// Pointer to glXWaitForMscOML function.
f_WaitForMscOML glXWaitForMscOML;
/// Pointer to glXSwapIntervalSGI function.
f_SwapIntervalSGI glXSwapIntervalProc;
/// Pointer to glXSwapIntervalMESA function.
f_SwapIntervalMESA glXSwapIntervalMESAProc;
/// Pointer to glXBindTexImageEXT function.
f_BindTexImageEXT glXBindTexImageProc;
/// Pointer to glXReleaseTexImageEXT function.
f_ReleaseTexImageEXT glXReleaseTexImageProc;
/// Pointer to glXCopySubBufferMESA function.
f_CopySubBuffer glXCopySubBufferProc;
#ifdef CONFIG_GLX_SYNC
/// Pointer to the glFenceSync() function.
f_FenceSync glFenceSyncProc;
/// Pointer to the glIsSync() function.
f_IsSync glIsSyncProc;
/// Pointer to the glDeleteSync() function.
f_DeleteSync glDeleteSyncProc;
/// Pointer to the glClientWaitSync() function.
f_ClientWaitSync glClientWaitSyncProc;
/// Pointer to the glWaitSync() function.
f_WaitSync glWaitSyncProc;
/// Pointer to the glImportSyncEXT() function.
f_ImportSyncEXT glImportSyncEXT;
#endif
#ifdef DEBUG_GLX_MARK
/// Pointer to StringMarkerGREMEDY function.
f_StringMarkerGREMEDY glStringMarkerGREMEDY;
/// Pointer to FrameTerminatorGREMEDY function.
f_FrameTerminatorGREMEDY glFrameTerminatorGREMEDY;
#endif
/// Current GLX Z value.
int z;
/// FBConfig-s for GLX pixmap of different depths.
glx_fbconfig_t *fbconfigs[OPENGL_MAX_DEPTH + 1];
#ifdef CONFIG_VSYNC_OPENGL_GLSL
glx_blur_pass_t blur_passes[MAX_BLUR_PASS];
#endif
} glx_session_t;
#define CGLX_SESSION_INIT { .context = NULL }
#endif
/// Structure containing all necessary data for a compton session.
typedef struct _session_t {
// === Display related ===
@ -742,6 +848,10 @@ typedef struct _session_t {
XdbeBackBuffer root_dbe;
/// Window ID of the window we register as a symbol.
Window reg_win;
#ifdef CONFIG_VSYNC_OPENGL
/// Pointer to GLX data.
glx_session_t *psglx;
#endif
// === Operation related ===
/// Program options.
@ -784,10 +894,6 @@ typedef struct _session_t {
/// Pointer to the <code>next</code> member of tail element of the error
/// ignore linked list.
ignore_t **ignore_tail;
#ifdef CONFIG_VSYNC_OPENGL
/// Current GLX Z value.
int glx_z;
#endif
// Cached blur convolution kernels.
XFixed *blur_kerns_cache[MAX_BLUR_PASS];
/// Reset program after next paint.
@ -847,57 +953,6 @@ typedef struct _session_t {
int drm_fd;
#endif
#ifdef CONFIG_VSYNC_OPENGL
// === OpenGL related ===
/// GLX context.
GLXContext glx_context;
/// Whether we have GL_ARB_texture_non_power_of_two.
bool glx_has_texture_non_power_of_two;
/// Pointer to glXGetVideoSyncSGI function.
f_GetVideoSync glXGetVideoSyncSGI;
/// Pointer to glXWaitVideoSyncSGI function.
f_WaitVideoSync glXWaitVideoSyncSGI;
/// Pointer to glXGetSyncValuesOML function.
f_GetSyncValuesOML glXGetSyncValuesOML;
/// Pointer to glXWaitForMscOML function.
f_WaitForMscOML glXWaitForMscOML;
/// Pointer to glXSwapIntervalSGI function.
f_SwapIntervalSGI glXSwapIntervalProc;
/// Pointer to glXSwapIntervalMESA function.
f_SwapIntervalMESA glXSwapIntervalMESAProc;
/// Pointer to glXBindTexImageEXT function.
f_BindTexImageEXT glXBindTexImageProc;
/// Pointer to glXReleaseTexImageEXT function.
f_ReleaseTexImageEXT glXReleaseTexImageProc;
/// Pointer to glXCopySubBufferMESA function.
f_CopySubBuffer glXCopySubBufferProc;
#ifdef CONFIG_GLX_SYNC
/// Pointer to the glFenceSync() function.
f_FenceSync glFenceSyncProc;
/// Pointer to the glIsSync() function.
f_IsSync glIsSyncProc;
/// Pointer to the glDeleteSync() function.
f_DeleteSync glDeleteSyncProc;
/// Pointer to the glClientWaitSync() function.
f_ClientWaitSync glClientWaitSyncProc;
/// Pointer to the glWaitSync() function.
f_WaitSync glWaitSyncProc;
/// Pointer to the glImportSyncEXT() function.
f_ImportSyncEXT glImportSyncEXT;
#endif
#ifdef DEBUG_GLX_MARK
/// Pointer to StringMarkerGREMEDY function.
f_StringMarkerGREMEDY glStringMarkerGREMEDY;
/// Pointer to FrameTerminatorGREMEDY function.
f_FrameTerminatorGREMEDY glFrameTerminatorGREMEDY;
#endif
/// FBConfig-s for GLX pixmap of different depths.
glx_fbconfig_t *glx_fbconfigs[OPENGL_MAX_DEPTH + 1];
#ifdef CONFIG_VSYNC_OPENGL_GLSL
glx_blur_pass_t glx_blur_passes[MAX_BLUR_PASS];
#endif
#endif
// === X extension related ===
/// Event base number for X Fixes extension.
int xfixes_event;
@ -1130,6 +1185,8 @@ typedef struct _win {
/// Do not fade if it's false. Change on window type change.
/// Used by fading blacklist in the future.
bool fade;
/// Fade state on last paint.
bool fade_last;
/// Override value of window fade state. Set by D-Bus method calls.
switch_t fade_force;
/// Callback to be called after fading completed.
@ -1144,6 +1201,8 @@ typedef struct _win {
// Shadow-related members
/// Whether a window has shadow. Calculated.
bool shadow;
/// Shadow state on last paint.
bool shadow_last;
/// Override value of window shadow state. Set by D-Bus method calls.
switch_t shadow_force;
/// Opacity of the shadow. Affected by window opacity and frame opacity.
@ -1170,12 +1229,16 @@ typedef struct _win {
/// Whether to invert window color.
bool invert_color;
/// Color inversion state on last paint.
bool invert_color_last;
/// Override value of window color inversion state. Set by D-Bus method
/// calls.
switch_t invert_color_force;
/// Whether to blur window background.
bool blur_background;
/// Background state on last paint.
bool blur_background_last;
/// Whether to show black background
bool show_black_background;
@ -1224,13 +1287,13 @@ extern session_t *ps_g;
static inline void
print_timestamp(session_t *ps);
#ifdef DEBUG_ALLOC_REG
#ifdef DEBUG_BACKTRACE
#include <execinfo.h>
#define BACKTRACE_SIZE 5
#define BACKTRACE_SIZE 25
/**
* Print current backtrace, excluding the first two items.
* Print current backtrace.
*
* Stolen from glibc manual.
*/
@ -1243,12 +1306,14 @@ print_backtrace(void) {
size = backtrace(array, BACKTRACE_SIZE);
strings = backtrace_symbols(array, size);
for (size_t i = 2; i < size; i++)
for (size_t i = 0; i < size; i++)
printf ("%s\n", strings[i]);
free(strings);
}
#ifdef DEBUG_ALLOC_REG
/**
* Wrapper of <code>XFixesCreateRegion</code>, for debugging.
*/
@ -1279,6 +1344,8 @@ XFixesDestroyRegion_(Display *dpy, XserverRegion reg,
#define XFixesDestroyRegion(dpy, reg) XFixesDestroyRegion_(dpy, reg, __func__, __LINE__)
#endif
#endif
// === Functions ===
/**
@ -1873,6 +1940,18 @@ 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_VSYNC_OPENGL
return ps->psglx && ps->psglx->context;
#else
return false;
#endif
}
/**
* Check if a window is really focused.
*/
@ -1975,7 +2054,15 @@ rect_is_fullscreen(session_t *ps, int x, int y, unsigned wid, unsigned hei) {
static inline bool
win_is_fullscreen(session_t *ps, const win *w) {
return rect_is_fullscreen(ps, w->a.x, w->a.y, w->widthb, w->heightb)
&& !w->bounding_shaped;
&& (!w->bounding_shaped || w->rounded_corners);
}
/**
* Check if a window will be painted solid.
*/
static inline bool
win_is_solid(session_t *ps, const win *w) {
return WMODE_SOLID == w->mode && !ps->o.force_win_blend;
}
/**
@ -2080,12 +2167,22 @@ 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_VSYNC_OPENGL_GLSL
bool
glx_load_prog_main(session_t *ps,
const char *vshader_str, const char *fshader_str,
glx_prog_main_t *pprogram);
#endif
bool
glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
unsigned width, unsigned height, unsigned depth);
@ -2121,10 +2218,24 @@ 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);
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,
double opacity, bool neg,
XserverRegion reg_tgt, const reg_data_t *pcache_reg);
double opacity, bool argb, bool neg,
XserverRegion reg_tgt, const reg_data_t *pcache_reg
#ifdef CONFIG_VSYNC_OPENGL_GLSL
, const glx_prog_main_t *pprogram
#endif
);
#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)
#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)
#endif
bool
glx_render_specified_color(session_t *ps, int color, int dx, int dy, int width, int height, int z,
@ -2133,12 +2244,19 @@ glx_render_specified_color(session_t *ps, int color, int dx, int dy, int width,
void
glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg);
unsigned char *
glx_take_screenshot(session_t *ps, int *out_length);
#ifdef CONFIG_VSYNC_OPENGL_GLSL
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);
#endif
/**
@ -2147,7 +2265,7 @@ glx_create_program(const GLuint * const shaders, int nshaders);
static inline void
free_texture_r(session_t *ps, GLuint *ptexture) {
if (*ptexture) {
assert(ps->glx_context);
assert(glx_has_context(ps));
glDeleteTextures(1, ptexture);
*ptexture = 0;
}
@ -2213,20 +2331,40 @@ free_texture(session_t *ps, glx_texture_t **pptex) {
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_VSYNC_OPENGL_GLSL
free_glx_bc(ps, &w->glx_blur_cache);
#endif
}
/**
* Add a OpenGL debugging marker.
*/
static inline void
glx_mark_(session_t *ps, const char *func, XID xid, bool start) {
#ifdef DEBUG_GLX_MARK
if (bkend_use_glx(ps) && ps->glStringMarkerGREMEDY) {
if (glx_has_context(ps) && ps->psglx->glStringMarkerGREMEDY) {
if (!func) func = "(unknown)";
const char *postfix = (start ? " (start)": " (end)");
char *str = malloc((strlen(func) + 12 + 2
+ strlen(postfix) + 5) * sizeof(char));
strcpy(str, func);
sprintf(str + strlen(str), "(%#010lx)%s", xid, postfix);
ps->glStringMarkerGREMEDY(strlen(str), str);
ps->psglx->glStringMarkerGREMEDY(strlen(str), str);
free(str);
}
#endif
@ -2240,8 +2378,8 @@ glx_mark_(session_t *ps, const char *func, XID xid, bool start) {
static inline void
glx_mark_frame(session_t *ps) {
#ifdef DEBUG_GLX_MARK
if (bkend_use_glx(ps) && ps->glFrameTerminatorGREMEDY)
ps->glFrameTerminatorGREMEDY();
if (glx_has_context(ps) && ps->psglx->glFrameTerminatorGREMEDY)
ps->psglx->glFrameTerminatorGREMEDY();
#endif
}
@ -2388,6 +2526,28 @@ c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst,
#endif
/**
* @brief Dump the given data to a file.
*/
static inline bool
write_binary_data(const char *path, const unsigned char *data, int length) {
if (!data)
return false;
FILE *f = fopen(path, "wb");
if (!f) {
printf_errf("(\"%s\"): Failed to open file for writing.", path);
return false;
}
int wrote_len = fwrite(data, sizeof(unsigned char), length, f);
fclose(f);
if (wrote_len != length) {
printf_errf("(\"%s\"): Failed to write all blocks: %d / %d", path,
wrote_len, length);
return false;
}
return true;
}
/**
* @brief Dump raw bytes in HEX format.
*
@ -2423,3 +2583,4 @@ hexdump(const char *data, int len) {
fflush(stdout);
}
#endif

@ -621,20 +621,20 @@ win_build_shadow(session_t *ps, win *w, double opacity) {
shadow_picture_argb, 0, 0, 0, 0, 0, 0,
shadow_image->width, shadow_image->height);
assert(!w->shadow_paint.pixmap);
w->shadow_paint.pixmap = shadow_pixmap_argb;
assert(!w->shadow_paint.pict);
w->shadow_paint.pict = shadow_picture_argb;
// Sync it once and only once
xr_sync(ps, w->shadow_paint.pixmap, NULL);
bool success = paint_bind_tex(ps, &w->shadow_paint, shadow_image->width, shadow_image->height, 32, true);
XFreeGC(ps->dpy, gc);
XDestroyImage(shadow_image);
XFreePixmap(ps->dpy, shadow_pixmap);
XRenderFreePicture(ps->dpy, shadow_picture);
return success;
return true;
shadow_picture_err:
if (shadow_image)
@ -711,6 +711,9 @@ discard_ignore(session_t *ps, unsigned long sequence) {
static void
set_ignore(session_t *ps, unsigned long sequence) {
if (ps->o.show_all_xerrors)
return;
ignore_t *i = malloc(sizeof(ignore_t));
if (!i) return;
@ -779,6 +782,8 @@ wid_get_prop_adv(const session_t *ps, Window w, Atom atom, long offset,
*/
static void
win_rounded_corners(session_t *ps, win *w) {
w->rounded_corners = false;
if (!w->bounding_shaped)
return;
@ -808,11 +813,9 @@ win_rounded_corners(session_t *ps, win *w) {
for (i = 0; i < nrects; ++i)
if (rects[i].width >= minwidth && rects[i].height >= minheight) {
w->rounded_corners = true;
cxfree(rects);
return;
break;
}
w->rounded_corners = false;
cxfree(rects);
}
@ -1257,6 +1260,14 @@ paint_preprocess(session_t *ps, win *list) {
free_region(ps, &w->reg_ignore);
}
// Restore flags from last paint if the window is being faded out
if (IsUnmapped == w->a.map_state) {
win_set_shadow(ps, w, w->shadow_last);
w->fade = w->fade_last;
win_set_invert_color(ps, w, w->invert_color_last);
win_set_blur_background(ps, w, w->blur_background_last);
}
// Update window opacity target and dim state if asked
if (WFLAG_OPCT_CHANGE & w->flags) {
calc_opacity(ps, w);
@ -1336,7 +1347,7 @@ paint_preprocess(session_t *ps, win *list) {
// If the window is solid, we add the window region to the
// ignored region
if (WMODE_SOLID == w->mode) {
if (win_is_solid(ps, w)) {
if (!w->frame_opacity) {
if (w->border_size)
w->reg_ignore = copy_region(ps, w->border_size);
@ -1370,7 +1381,7 @@ paint_preprocess(session_t *ps, win *list) {
// is not correctly set.
if (ps->o.unredir_if_possible && is_highest && to_paint) {
is_highest = false;
if (WMODE_SOLID == w->mode
if (win_is_solid(ps, w)
&& (!w->frame_opacity || !win_has_frame(w))
&& win_is_fullscreen(ps, w)
&& !w->unredir_if_possible_excluded)
@ -1393,8 +1404,17 @@ paint_preprocess(session_t *ps, win *list) {
check_fade_fin(ps, w);
}
if (!destroyed)
if (!destroyed) {
w->to_paint = to_paint;
if (w->to_paint) {
// Save flags
w->shadow_last = w->shadow;
w->fade_last = w->fade;
w->invert_color_last = w->invert_color;
w->blur_background_last = w->blur_background;
}
}
}
@ -1430,6 +1450,9 @@ paint_preprocess(session_t *ps, win *list) {
static inline void
win_paint_shadow(session_t *ps, win *w,
XserverRegion reg_paint, const reg_data_t *pcache_reg) {
// Bind shadow pixmap to GLX texture if needed
paint_bind_tex(ps, &w->shadow_paint, 0, 0, 32, false);
if (!paint_isvalid(ps, &w->shadow_paint)) {
printf_errf("(%#010lx): Missing painting data. This is a bad sign.", w->id);
return;
@ -1437,7 +1460,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_paint.pict, w->shadow_paint.ptex, reg_paint, pcache_reg);
w->shadow_paint.pict, w->shadow_paint.ptex, reg_paint, pcache_reg, NULL);
}
/**
@ -1529,6 +1552,20 @@ xr_blur_dst(session_t *ps, Picture tgt_buffer,
return true;
}
/*
* WORK-IN-PROGRESS!
static void
xr_take_screenshot(session_t *ps) {
XImage *img = XGetImage(ps->dpy, get_tgt_window(ps), 0, 0,
ps->root_width, ps->root_height, AllPlanes, XYPixmap);
if (!img) {
printf_errf("(): Failed to get XImage.");
return NULL;
}
assert(0 == img->xoffset);
}
*/
/**
* Blur the background of a window.
*/
@ -1593,7 +1630,7 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
// Minimize the region we try to blur, if the window itself is not
// opaque, only the frame is.
XserverRegion reg_noframe = None;
if (WMODE_SOLID == w->mode) {
if (win_is_solid(ps, w)) {
XserverRegion reg_all = border_size(ps, w, false);
reg_noframe = win_get_region_noframe(ps, w, false);
XFixesSubtractRegion(ps->dpy, reg_noframe, reg_all, reg_noframe);
@ -1607,7 +1644,7 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
#ifdef CONFIG_VSYNC_OPENGL_GLSL
case BKEND_GLX:
// TODO: Handle frame opacity
glx_blur_dst(ps, x, y, wid, hei, ps->glx_z - 0.5, factor_center,
glx_blur_dst(ps, x, y, wid, hei, ps->psglx->z - 0.5, factor_center,
reg_paint, pcache_reg, &w->glx_blur_cache);
break;
#endif
@ -1617,10 +1654,14 @@ 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,
render_(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
double opacity, bool argb, bool neg,
Picture pict, glx_texture_t *ptex,
XserverRegion reg_paint, const reg_data_t *pcache_reg) {
XserverRegion reg_paint, const reg_data_t *pcache_reg
#ifdef CONFIG_VSYNC_OPENGL_GLSL
, const glx_prog_main_t *pprogram
#endif
) {
switch (ps->o.backend) {
case BKEND_XRENDER:
case BKEND_XR_GLX_HYBRID:
@ -1636,8 +1677,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->glx_z, opacity, neg, reg_paint, pcache_reg);
ps->glx_z += 1;
ps->psglx->z, opacity, argb, neg, reg_paint, pcache_reg, pprogram);
ps->psglx->z += 1;
break;
#endif
default:
@ -1818,7 +1859,7 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint,
break;
#ifdef CONFIG_VSYNC_OPENGL
case BKEND_GLX:
glx_dim_dst(ps, x, y, wid, hei, ps->glx_z - 0.7, dim_opacity,
glx_dim_dst(ps, x, y, wid, hei, ps->psglx->z - 0.7, dim_opacity,
reg_paint, pcache_reg);
break;
#endif
@ -1942,7 +1983,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
// Painting shadow
if (w->shadow) {
// Lazy shadow building
if (!paint_isvalid(ps, &w->shadow_paint))
if (!w->shadow_paint.pixmap)
win_build_shadow(ps, w, 1);
// Shadow is to be painted based on the ignore region of current
@ -2071,7 +2112,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
}
// Blur window background
if (w->blur_background && (WMODE_SOLID != w->mode
if (w->blur_background && (!win_is_solid(ps, w)
|| (ps->o.blur_background_frame && w->frame_opacity))) {
win_blur_background(ps, w, ps->tgt_buffer.pict, reg_paint, &cache_reg);
}
@ -2096,7 +2137,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
// effect
XSync(ps->dpy, False);
#ifdef CONFIG_VSYNC_OPENGL
if (ps->glx_context) {
if (glx_has_context(ps)) {
if (ps->o.vsync_use_glfinish)
glFinish();
else
@ -2152,7 +2193,8 @@ 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, region_real, NULL);
ps->root_width, ps->root_height, 0, 1.0, false, false,
region_real, NULL, NULL);
// No break here!
case BKEND_GLX:
if (ps->o.glx_use_copysubbuffermesa)
@ -2172,7 +2214,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
XFlush(ps->dpy);
#ifdef CONFIG_VSYNC_OPENGL
if (ps->glx_context) {
if (glx_has_context(ps)) {
glFlush();
glXWaitX();
}
@ -2678,9 +2720,21 @@ static void
win_determine_fade(session_t *ps, win *w) {
if (UNSET != w->fade_force)
w->fade = w->fade_force;
else if ((ps->o.no_fading_openclose && w->in_openclose)
|| win_match(ps, w, ps->o.fade_blacklist, &w->cache_fblst)
|| (ps->o.no_fading_opacitychange && (!w->in_openclose)))
else if (ps->o.no_fading_opacitychange && (!w->in_openclose))
w->fade = false;
else if (ps->o.no_fading_openclose && w->in_openclose)
w->fade = false;
else if (ps->o.no_fading_destroyed_argb && w->destroyed
&& WMODE_ARGB == w->mode && w->client_win && w->client_win != w->id) {
w->fade = false;
// Prevent it from being overwritten by last-paint value
w->fade_last = false;
}
// Ignore other possible causes of fading state changes after window
// gets unmapped
else if (IsViewable != w->a.map_state) {
}
else if (win_match(ps, w, ps->o.fade_blacklist, &w->cache_fblst))
w->fade = false;
else
w->fade = ps->o.wintype_fade[w->window_type];
@ -2708,8 +2762,7 @@ win_update_shape(session_t *ps, win *w) {
win_update_shape_raw(ps, w);
// Shadow state could be changed
win_determine_shadow(ps, w);
win_on_factor_change(ps, w);
/*
// If clear_shadow state on the window possibly changed, destroy the old
@ -2754,38 +2807,55 @@ win_update_prop_shadow(session_t *ps, win *w) {
win_determine_shadow(ps, w);
}
static void
win_set_shadow(session_t *ps, win *w, bool shadow_new) {
if (w->shadow == shadow_new) return;
w->shadow = shadow_new;
// Window extents need update on shadow state change
// Shadow geometry currently doesn't change on shadow state change
// calc_shadow_geometry(ps, w);
if (w->extents) {
// Mark the old extents as damaged if the shadow is removed
if (!w->shadow)
add_damage(ps, w->extents);
else
free_region(ps, &w->extents);
w->extents = win_extents(ps, w);
// Mark the new extents as damaged if the shadow is added
if (w->shadow)
add_damage_win(ps, w);
}
}
/**
* Determine if a window should have shadow, and update things depending
* on shadow state.
*/
static void
win_determine_shadow(session_t *ps, win *w) {
bool shadow_old = w->shadow;
bool shadow_new = w->shadow;
w->shadow = (UNSET == w->shadow_force ?
(ps->o.wintype_shadow[w->window_type]
&& !win_match(ps, w, ps->o.shadow_blacklist, &w->cache_sblst)
&& !(ps->o.shadow_ignore_shaped && w->bounding_shaped
&& !w->rounded_corners)
&& !(ps->o.respect_prop_shadow && 0 == w->prop_shadow))
: w->shadow_force);
if (UNSET != w->shadow_force)
shadow_new = w->shadow_force;
else if (IsViewable == w->a.map_state)
shadow_new = (ps->o.wintype_shadow[w->window_type]
&& !win_match(ps, w, ps->o.shadow_blacklist, &w->cache_sblst)
&& !(ps->o.shadow_ignore_shaped && w->bounding_shaped
&& !w->rounded_corners)
&& !(ps->o.respect_prop_shadow && 0 == w->prop_shadow));
// Window extents need update on shadow state change
if (w->shadow != shadow_old) {
// Shadow geometry currently doesn't change on shadow state change
// calc_shadow_geometry(ps, w);
if (w->extents) {
// Mark the old extents as damaged if the shadow is removed
if (!w->shadow)
add_damage(ps, w->extents);
else
free_region(ps, &w->extents);
w->extents = win_extents(ps, w);
// Mark the new extents as damaged if the shadow is added
if (w->shadow)
add_damage_win(ps, w);
}
}
win_set_shadow(ps, w, shadow_new);
}
static void
win_set_invert_color(session_t *ps, win *w, bool invert_color_new) {
if (w->invert_color == invert_color_new) return;
w->invert_color = invert_color_new;
add_damage_win(ps, w);
}
/**
@ -2793,19 +2863,27 @@ win_determine_shadow(session_t *ps, win *w) {
*/
static void
win_determine_invert_color(session_t *ps, win *w) {
// Do not change window invert color state when the window is unmapped,
// unless it comes from w->invert_color_force.
if (UNSET == w->invert_color_force && IsViewable != w->a.map_state)
return;
bool invert_color_old = w->invert_color;
bool invert_color_new = w->invert_color;
if (UNSET != w->invert_color_force)
w->invert_color = w->invert_color_force;
else
w->invert_color = win_match(ps, w, ps->o.invert_color_list, &w->cache_ivclst);
invert_color_new = w->invert_color_force;
else if (IsViewable == w->a.map_state)
invert_color_new = win_match(ps, w, ps->o.invert_color_list,
&w->cache_ivclst);
win_set_invert_color(ps, w, invert_color_new);
}
if (w->invert_color != invert_color_old)
static void
win_set_blur_background(session_t *ps, win *w, bool blur_background_new) {
if (w->blur_background == blur_background_new) return;
w->blur_background = blur_background_new;
// Only consider window damaged if it's previously painted with background
// blurred
if (!win_is_solid(ps, w)
|| (ps->o.blur_background_frame && w->frame_opacity))
add_damage_win(ps, w);
}
@ -2814,16 +2892,13 @@ win_determine_invert_color(session_t *ps, win *w) {
*/
static void
win_determine_blur_background(session_t *ps, win *w) {
bool blur_background_old = w->blur_background;
if (IsViewable != w->a.map_state)
return;
w->blur_background = ps->o.blur_background
bool blur_background_new = ps->o.blur_background
&& !win_match(ps, w, ps->o.blur_background_blacklist, &w->cache_bbblst);
// Only consider window damaged if it's previously painted with background
// blurred
if (w->blur_background != blur_background_old && (WMODE_SOLID != w->mode
|| (ps->o.blur_background_frame && w->frame_opacity)))
add_damage_win(ps, w);
win_set_blur_background(ps, w, blur_background_new);
}
/**
@ -2831,6 +2906,10 @@ win_determine_blur_background(session_t *ps, win *w) {
*/
static void
win_update_opacity_rule(session_t *ps, win *w) {
if (IsViewable != w->a.map_state)
return;
#ifdef CONFIG_C2
// If long is 32-bit, unfortunately there's no way could we express "unset",
// so we just entirely don't distinguish "unset" and OPAQUE
opacity_t opacity = OPAQUE;
@ -2846,6 +2925,7 @@ win_update_opacity_rule(session_t *ps, win *w) {
else if (OPAQUE != w->opacity_set)
wid_rm_opacity_prop(ps, w->id);
w->opacity_set = opacity;
#endif
}
/**
@ -2879,10 +2959,10 @@ win_on_factor_change(session_t *ps, win *w) {
win_determine_blur_background(ps, w);
if (ps->o.opacity_rules)
win_update_opacity_rule(ps, w);
if (ps->o.paint_blacklist)
if (IsViewable == w->a.map_state && ps->o.paint_blacklist)
w->paint_excluded = win_match(ps, w, ps->o.paint_blacklist,
&w->cache_pblst);
if (ps->o.unredir_if_possible_blacklist)
if (IsViewable == w->a.map_state && ps->o.unredir_if_possible_blacklist)
w->unredir_if_possible_excluded = win_match(ps, w,
ps->o.unredir_if_possible_blacklist, &w->cache_uipblst);
}
@ -3299,6 +3379,9 @@ restack_win(session_t *ps, win *w, Window new_above) {
}
}
static bool
init_filters(session_t *ps);
static void
configure_win(session_t *ps, XConfigureEvent *ce) {
// On root window changes
@ -3312,11 +3395,28 @@ configure_win(session_t *ps, XConfigureEvent *ce) {
rebuild_shadow_exclude_reg(ps);
free_all_damage_last(ps);
// Re-redirect screen if required
if (ps->o.reredir_on_root_change && ps->redirected) {
redir_stop(ps);
redir_start(ps);
}
#ifdef CONFIG_VSYNC_OPENGL
// Reinitialize GLX on root change
if (ps->o.glx_reinit_on_root_change && ps->psglx) {
if (!glx_reinit(ps, bkend_use_glx(ps)))
printf_errf("(): Failed to reinitialize GLX, troubles ahead.");
if (BKEND_GLX == ps->o.backend && !init_filters(ps))
printf_errf("(): Failed to initialize filters.");
}
// GLX root change callback
if (BKEND_GLX == ps->o.backend)
glx_on_root_change(ps);
#endif
force_repaint(ps);
return;
}
@ -3466,6 +3566,9 @@ destroy_win(session_t *ps, Window id) {
w->destroyed = true;
if (ps->o.no_fading_destroyed_argb)
win_determine_fade(ps, w);
// Set fading callback
set_fade_callback(ps, w, destroy_callback, false);
@ -3604,11 +3707,13 @@ xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) {
{
char buf[BUF_LEN] = "";
XGetErrorText(ps->dpy, ev->error_code, buf, BUF_LEN);
printf("error %d (%s) request %d minor %d serial %lu (\"%s\")\n",
printf("error %4d %-12s request %4d minor %4d serial %6lu: \"%s\"\n",
ev->error_code, name, ev->request_code,
ev->minor_code, ev->serial, buf);
}
// print_backtrace();
return 0;
}
@ -3659,7 +3764,7 @@ win_update_focused(session_t *ps, win *w) {
|| (ps->o.mark_wmwin_focused && w->wmwin)
|| (ps->o.mark_ovredir_focused
&& w->id == w->client_win && !w->wmwin)
|| win_match(ps, w, ps->o.focus_blacklist, &w->cache_fcblst))
|| (IsViewable == w->a.map_state && win_match(ps, w, ps->o.focus_blacklist, &w->cache_fcblst)))
w->focused = true;
// If window grouping detection is enabled, mark the window active if
@ -4226,10 +4331,12 @@ ev_focus_report(XFocusChangeEvent* ev) {
* Determine whether we should respond to a <code>FocusIn/Out</code>
* event.
*/
/*
inline static bool
ev_focus_accept(XFocusChangeEvent *ev) {
return NotifyNormal == ev->mode || NotifyUngrab == ev->mode;
}
*/
static inline void
ev_focus_in(session_t *ps, XFocusChangeEvent *ev) {
@ -4727,6 +4834,8 @@ usage(int ret) {
" Daemonize process.\n"
"-S\n"
" Enable synchronous operation (for debugging).\n"
"--show-all-xerrors\n"
" Show all X errors (for debugging).\n"
"-v\n"
" Print version Number and exit\\n"
"--config path\n"
@ -4755,13 +4864,21 @@ usage(int ret) {
" Mark windows that have no WM frame as active.\n"
"--no-fading-openclose\n"
" Do not fade on window open/close.\n"
"--no-fading-destroyed-argb\n"
" Do not fade destroyed ARGB windows with WM frame. Workaround of bugs\n"
" in Openbox, Fluxbox, etc.\n"
"--no-fading-opacitychange\n"
" Do not fade on window opacity change.\n"
"--shadow-ignore-shaped\n"
" Do not paint shadows on shaped windows.\n"
" Do not paint shadows on shaped windows. (Deprecated, use\n"
" --shadow-exclude \'bounding_shaped\' or\n"
" --shadow-exclude \'bounding_shaped && !rounded_corners\' instead.)\n"
"--detect-rounded-corners\n"
" Try to detect windows with rounded corners and don't consider\n"
" them shaped windows.\n"
" them shaped windows. Affects --shadow-ignore-shaped,\n"
" --unredir-if-possible, and possibly others. You need to turn this\n"
" on manually if you want to match against rounded_corners in\n"
" conditions.\n"
"--detect-client-opacity\n"
" Detect _NET_WM_OPACITY on client windows, useful for window\n"
" managers not passing _NET_WM_OPACITY of client windows to frame\n"
@ -4861,7 +4978,7 @@ usage(int ret) {
" The element in the center must not be included, it will be forever\n"
" 1.0 or changing based on opacity, depending on whether you have\n"
" --blur-background-fixed.\n"
" A 7x7 Guassian blur kernel looks like:\n"
" A 7x7 Gaussian blur kernel looks like:\n"
" --blur-kern '7,7,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003,0.000102,0.003494,0.029143,0.059106,0.029143,0.003494,0.000102,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.001723,0.059106,0.493069,0.493069,0.059106,0.001723,0.000849,0.029143,0.243117,0.493069,0.243117,0.029143,0.000849,0.000102,0.003494,0.029143,0.059106,0.029143,0.003494,0.000102,0.000003,0.000102,0.000849,0.001723,0.000849,0.000102,0.000003'\n"
" Up to 4 blur kernels may be specified, separated with semicolon, for\n"
" multi-pass blur.\n"
@ -4919,7 +5036,8 @@ usage(int ret) {
"--glx-no-rebind-pixmap\n"
" GLX backend: Avoid rebinding pixmap on window damage. Probably\n"
" could improve performance on rapid window content changes, but is\n"
" known to break things on some drivers.\n"
" known to break things on some drivers (LLVMpipe, xf86-video-intel,\n"
" etc.).\n"
"--glx-swap-method undefined/copy/exchange/3/4/5/6/buffer-age\n"
" GLX backend: GLX buffer swap method we assume. Could be\n"
" undefined (0), copy (1), exchange (2), 3-6, or buffer-age (-1).\n"
@ -4949,6 +5067,12 @@ usage(int ret) {
#else
#define WARNING
#endif
"--glx-fshader-win shader\n"
" GLX backend: Use specified GLSL fragment shader for rendering window\n"
" contents.\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"
"--dbus\n"
" Enable remote control via D-Bus. See the D-BUS API section in the\n"
" man page for more details." WARNING "\n"
@ -5011,7 +5135,8 @@ register_cm(session_t *ps) {
printf_errf("(): Failed to set COMPTON_VERSION.");
}
{
// Acquire X Selection _NET_WM_CM_S?
if (!ps->o.no_x_selection) {
unsigned len = strlen(REGISTER_PROP) + 2;
int s = ps->scr;
@ -5066,7 +5191,7 @@ fork_after(session_t *ps) {
#ifdef CONFIG_VSYNC_OPENGL
// GLX context must be released and reattached on fork
if (ps->glx_context && !glXMakeCurrent(ps->dpy, None, NULL)) {
if (glx_has_context(ps) && !glXMakeCurrent(ps->dpy, None, NULL)) {
printf_errf("(): Failed to detach GLx context.");
return false;
}
@ -5084,8 +5209,8 @@ fork_after(session_t *ps) {
setsid();
#ifdef CONFIG_VSYNC_OPENGL
if (ps->glx_context
&& !glXMakeCurrent(ps->dpy, get_tgt_window(ps), ps->glx_context)) {
if (glx_has_context(ps)
&& !glXMakeCurrent(ps->dpy, get_tgt_window(ps), ps->psglx->context)) {
printf_errf("(): Failed to make GLX context current.");
return false;
}
@ -5399,6 +5524,7 @@ parse_geometry_end:
*/
static inline bool
parse_rule_opacity(session_t *ps, const char *src) {
#ifdef CONFIG_C2
// Find opacity value
char *endptr = NULL;
long val = strtol(src, &endptr, 0);
@ -5423,6 +5549,10 @@ parse_rule_opacity(session_t *ps, const char *src) {
// Parse pattern
// I hope 1-100 is acceptable for (void *)
return c2_parsed(ps, &ps->o.opacity_rules, endptr, (void *) val);
#else
printf_errf("(\"%s\"): Condition support not compiled in.", src);
return false;
#endif
}
#ifdef CONFIG_LIBCONFIG
@ -5650,6 +5780,9 @@ parse_config(session_t *ps, struct options_tmp *pcfgtmp) {
wintype_arr_enable(ps->o.wintype_fade);
// --no-fading-open-close
lcfg_lookup_bool(&cfg, "no-fading-openclose", &ps->o.no_fading_openclose);
// --no-fading-destroyed-argb
lcfg_lookup_bool(&cfg, "no-fading-destroyed-argb",
&ps->o.no_fading_destroyed_argb);
// --no-fading-opacitychange
lcfg_lookup_bool(&cfg, "no-fading-opacitychange", &ps->o.no_fading_opacitychange);
// --shadow-red
@ -5743,7 +5876,7 @@ parse_config(session_t *ps, struct options_tmp *pcfgtmp) {
&& !parse_conv_kern_lst(ps, sval, ps->o.blur_kerns, MAX_BLUR_PASS))
exit(1);
// --resize-damage
config_lookup_int(&cfg, "resize-damage", &ps->o.resize_damage);
lcfg_lookup_int(&cfg, "resize-damage", &ps->o.resize_damage);
// --glx-no-stencil
lcfg_lookup_bool(&cfg, "glx-no-stencil", &ps->o.glx_no_stencil);
// --glx-copy-from-front
@ -5806,6 +5939,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
{ "shadow-offset-y", required_argument, NULL, 't' },
{ "fade-in-step", required_argument, NULL, 'I' },
{ "fade-out-step", required_argument, NULL, 'O' },
{ "fade-delta", required_argument, NULL, 'D' },
{ "menu-opacity", required_argument, NULL, 'm' },
{ "shadow", no_argument, NULL, 'c' },
{ "no-dock-shadow", no_argument, NULL, 'C' },
@ -5813,6 +5947,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
{ "fading", no_argument, NULL, 'f' },
{ "inactive-opacity", required_argument, NULL, 'i' },
{ "frame-opacity", required_argument, NULL, 'e' },
{ "daemon", no_argument, NULL, 'b' },
{ "no-dnd-shadow", no_argument, NULL, 'G' },
{ "shadow-red", required_argument, NULL, 257 },
{ "shadow-green", required_argument, NULL, 258 },
@ -5871,7 +6006,16 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
{ "vsync-use-glfinish", no_argument, NULL, 311 },
{ "xrender-sync", no_argument, NULL, 312 },
{ "xrender-sync-fence", no_argument, NULL, 313 },
{ "no-fading-opacitychange", no_argument, NULL, 314 },
{ "show-all-xerrors", no_argument, NULL, 314 },
{ "no-fading-destroyed-argb", no_argument, NULL, 315 },
{ "force-win-blend", no_argument, NULL, 316 },
{ "glx-fshader-win", required_argument, NULL, 317 },
{ "version", no_argument, NULL, 318 },
{ "no-x-selection", no_argument, NULL, 319 },
{ "no-name-pixmap", no_argument, NULL, 320 },
{ "no-fading-opacitychange", no_argument, NULL, 321 },
{ "reredir-on-root-change", no_argument, NULL, 731 },
{ "glx-reinit-on-root-change", no_argument, NULL, 732 },
// Must terminate with a NULL entry
{ NULL, 0, NULL, 0 },
};
@ -5892,6 +6036,14 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
ps->o.display = mstrcpy(optarg);
else if ('S' == o)
ps->o.synchronize = true;
else if (314 == o)
ps->o.show_all_xerrors = true;
else if (318 == o) {
printf("%s\n", COMPTON_VERSION);
exit(0);
}
else if (320 == o)
ps->o.no_name_pixmap = true;
else if ('?' == o || ':' == o)
usage(1);
}
@ -5946,6 +6098,9 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
case 'v': fprintf (stderr, "%s v%-3.2f\n", argv[0], _TDE_COMP_MGR_VERSION_); my_exit_code=0; exit (0);
case 'd':
case 'S':
case 314:
case 318:
case 320:
break;
P_CASELONG('D', fade_delta);
case 'I':
@ -6125,7 +6280,15 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
P_CASEBOOL(311, vsync_use_glfinish);
P_CASEBOOL(312, xrender_sync);
P_CASEBOOL(313, xrender_sync_fence);
P_CASEBOOL(314, no_fading_opacitychange);
P_CASEBOOL(315, no_fading_destroyed_argb);
P_CASEBOOL(316, force_win_blend);
case 317:
ps->o.glx_fshader_win_str = mstrcpy(optarg);
break;
P_CASEBOOL(319, no_x_selection);
P_CASEBOOL(321, no_fading_opacitychange);
P_CASEBOOL(731, reredir_on_root_change);
P_CASEBOOL(732, glx_reinit_on_root_change);
default:
usage(1);
break;
@ -6416,13 +6579,13 @@ vsync_opengl_init(session_t *ps) {
return false;
// Get video sync functions
if (!ps->glXGetVideoSyncSGI)
ps->glXGetVideoSyncSGI = (f_GetVideoSync)
if (!ps->psglx->glXGetVideoSyncSGI)
ps->psglx->glXGetVideoSyncSGI = (f_GetVideoSync)
glXGetProcAddress((const GLubyte *) "glXGetVideoSyncSGI");
if (!ps->glXWaitVideoSyncSGI)
ps->glXWaitVideoSyncSGI = (f_WaitVideoSync)
if (!ps->psglx->glXWaitVideoSyncSGI)
ps->psglx->glXWaitVideoSyncSGI = (f_WaitVideoSync)
glXGetProcAddress((const GLubyte *) "glXWaitVideoSyncSGI");
if (!ps->glXWaitVideoSyncSGI || !ps->glXGetVideoSyncSGI) {
if (!ps->psglx->glXWaitVideoSyncSGI || !ps->psglx->glXGetVideoSyncSGI) {
printf_errf("(): Failed to get glXWait/GetVideoSyncSGI function.");
return false;
}
@ -6441,13 +6604,13 @@ vsync_opengl_oml_init(session_t *ps) {
return false;
// Get video sync functions
if (!ps->glXGetSyncValuesOML)
ps->glXGetSyncValuesOML = (f_GetSyncValuesOML)
if (!ps->psglx->glXGetSyncValuesOML)
ps->psglx->glXGetSyncValuesOML = (f_GetSyncValuesOML)
glXGetProcAddress ((const GLubyte *) "glXGetSyncValuesOML");
if (!ps->glXWaitForMscOML)
ps->glXWaitForMscOML = (f_WaitForMscOML)
if (!ps->psglx->glXWaitForMscOML)
ps->psglx->glXWaitForMscOML = (f_WaitForMscOML)
glXGetProcAddress ((const GLubyte *) "glXWaitForMscOML");
if (!ps->glXGetSyncValuesOML || !ps->glXWaitForMscOML) {
if (!ps->psglx->glXGetSyncValuesOML || !ps->psglx->glXWaitForMscOML) {
printf_errf("(): Failed to get OML_sync_control functions.");
return false;
}
@ -6471,14 +6634,14 @@ vsync_opengl_swc_init(session_t *ps) {
}
// Get video sync functions
if (!ps->glXSwapIntervalProc)
ps->glXSwapIntervalProc = (f_SwapIntervalSGI)
if (!ps->psglx->glXSwapIntervalProc)
ps->psglx->glXSwapIntervalProc = (f_SwapIntervalSGI)
glXGetProcAddress ((const GLubyte *) "glXSwapIntervalSGI");
if (!ps->glXSwapIntervalProc) {
if (!ps->psglx->glXSwapIntervalProc) {
printf_errf("(): Failed to get SGI_swap_control function.");
return false;
}
ps->glXSwapIntervalProc(1);
ps->psglx->glXSwapIntervalProc(1);
return true;
#else
@ -6499,14 +6662,14 @@ vsync_opengl_mswc_init(session_t *ps) {
}
// Get video sync functions
if (!ps->glXSwapIntervalMESAProc)
ps->glXSwapIntervalMESAProc = (f_SwapIntervalMESA)
if (!ps->psglx->glXSwapIntervalMESAProc)
ps->psglx->glXSwapIntervalMESAProc = (f_SwapIntervalMESA)
glXGetProcAddress ((const GLubyte *) "glXSwapIntervalMESA");
if (!ps->glXSwapIntervalMESAProc) {
if (!ps->psglx->glXSwapIntervalMESAProc) {
printf_errf("(): Failed to get MESA_swap_control function.");
return false;
}
ps->glXSwapIntervalMESAProc(1);
ps->psglx->glXSwapIntervalMESAProc(1);
return true;
#else
@ -6523,8 +6686,8 @@ static int
vsync_opengl_wait(session_t *ps) {
unsigned vblank_count = 0;
ps->glXGetVideoSyncSGI(&vblank_count);
ps->glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count);
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;
@ -6539,8 +6702,8 @@ static int
vsync_opengl_oml_wait(session_t *ps) {
int64_t ust = 0, msc = 0, sbc = 0;
ps->glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc);
ps->glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2,
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;
@ -6549,14 +6712,14 @@ vsync_opengl_oml_wait(session_t *ps) {
static void
vsync_opengl_swc_deinit(session_t *ps) {
// The standard says it doesn't accept 0, but in fact it probably does
if (ps->glx_context && ps->glXSwapIntervalProc)
ps->glXSwapIntervalProc(0);
if (glx_has_context(ps) && ps->psglx->glXSwapIntervalProc)
ps->psglx->glXSwapIntervalProc(0);
}
static void
vsync_opengl_mswc_deinit(session_t *ps) {
if (ps->glx_context && ps->glXSwapIntervalMESAProc)
ps->glXSwapIntervalMESAProc(0);
if (glx_has_context(ps) && ps->psglx->glXSwapIntervalMESAProc)
ps->psglx->glXSwapIntervalMESAProc(0);
}
#endif
@ -6593,7 +6756,6 @@ void
vsync_deinit(session_t *ps) {
if (ps->o.vsync && VSYNC_FUNCS_DEINIT[ps->o.vsync])
VSYNC_FUNCS_DEINIT[ps->o.vsync](ps);
ps->o.vsync = VSYNC_NONE;
}
/**
@ -6633,7 +6795,7 @@ init_dbe(session_t *ps) {
/**
* Initialize X composite overlay window.
*/
static void
static bool
init_overlay(session_t *ps) {
ps->overlay = XCompositeGetOverlayWindow(ps->dpy, ps->root);
if (ps->overlay) {
@ -6661,6 +6823,11 @@ init_overlay(session_t *ps) {
"back to painting on root window.\n");
ps->o.paint_on_overlay = false;
}
#ifdef DEBUG_REDIR
printf_dbgf("(): overlay = %#010lx\n", ps->overlay);
#endif
return ps->overlay;
}
/**
@ -7071,6 +7238,9 @@ session_init(session_t *ps_old, int argc, char **argv) {
.backend = BKEND_XRENDER,
.glx_no_stencil = false,
.glx_copy_from_front = false,
#ifdef CONFIG_VSYNC_OPENGL_GLSL
.glx_prog_win = GLX_PROG_MAIN_INIT,
#endif
.mark_wmwin_focused = false,
.mark_ovredir_focused = false,
.fork_after_register = false,
@ -7113,6 +7283,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
.fade_out_step = 0.03 * OPAQUE,
.fade_delta = 10,
.no_fading_openclose = false,
.no_fading_destroyed_argb = false,
.no_fading_opacitychange = false,
.fade_blacklist = NULL,
@ -7187,15 +7358,6 @@ session_init(session_t *ps_old, int argc, char **argv) {
.drm_fd = -1,
#endif
#ifdef CONFIG_VSYNC_OPENGL
.glx_context = None,
.glx_has_texture_non_power_of_two = false,
.glXGetVideoSyncSGI = NULL,
.glXWaitVideoSyncSGI = NULL,
.glXGetSyncValuesOML = NULL,
.glXWaitForMscOML = NULL,
#endif
.xfixes_event = 0,
.xfixes_error = 0,
.damage_event = 0,
@ -7247,14 +7409,6 @@ session_init(session_t *ps_old, int argc, char **argv) {
// Allocate a session and copy default values into it
session_t *ps = malloc(sizeof(session_t));
memcpy(ps, &s_def, sizeof(session_t));
#ifdef CONFIG_VSYNC_OPENGL_GLSL
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
glx_blur_pass_t *ppass = &ps->glx_blur_passes[i];
ppass->unifm_factor_center = -1;
ppass->unifm_offset_x = -1;
ppass->unifm_offset_y = -1;
}
#endif
ps_g = ps;
ps->ignore_tail = &ps->ignore_head;
gettimeofday(&ps->time_start, NULL);
@ -7319,7 +7473,8 @@ session_init(session_t *ps_old, int argc, char **argv) {
XCompositeQueryVersion(ps->dpy, &composite_major, &composite_minor);
if (composite_major > 0 || composite_minor >= 2) {
if (!ps->o.no_name_pixmap
&& (composite_major > 0 || composite_minor >= 2)) {
ps->has_name_pixmap = true;
}
}
@ -7450,6 +7605,17 @@ session_init(session_t *ps_old, int argc, char **argv) {
#endif
}
// Initialize window GL shader
if (BKEND_GLX == ps->o.backend && ps->o.glx_fshader_win_str) {
#ifdef CONFIG_VSYNC_OPENGL_GLSL
if (!glx_load_prog_main(ps, NULL, ps->o.glx_fshader_win_str, &ps->o.glx_prog_win))
exit(1);
#else
printf_errf("(): GLSL supported not compiled in, can't load shader.");
exit(1);
#endif
}
// Initialize software optimization
if (ps->o.sw_opti)
ps->o.sw_opti = swopti_init(ps);
@ -7543,12 +7709,13 @@ session_init(session_t *ps_old, int argc, char **argv) {
cxfree(children);
}
if (ps->o.track_focus) {
recheck_focus(ps);
}
XUngrabServer(ps->dpy);
// ALWAYS flush after XUngrabServer()!
XFlush(ps->dpy);
// Initialize DBus
if (ps->o.dbus) {
@ -7711,6 +7878,7 @@ session_destroy(session_t *ps) {
free(ps->pfds_read);
free(ps->pfds_write);
free(ps->pfds_except);
free(ps->o.glx_fshader_win_str);
free_xinerama_info(ps);
#ifdef CONFIG_VSYNC_OPENGL
@ -7746,6 +7914,11 @@ session_destroy(session_t *ps) {
// Flush all events
XSync(ps->dpy, True);
#ifdef DEBUG_XRC
// Report about resource leakage
xrc_report_xid();
#endif
// Free timeouts
ps->tmout_unredir = NULL;
timeout_clear(ps);
@ -7754,6 +7927,16 @@ session_destroy(session_t *ps) {
ps_g = NULL;
}
/*
static inline void
dump_img(session_t *ps) {
int len = 0;
unsigned char *d = glx_take_screenshot(ps, &len);
write_binary_data("/tmp/dump.raw", d, len);
free(d);
}
*/
/**
* Do the actual work.
*

@ -273,7 +273,7 @@ free_reg_data(reg_data_t *pregd) {
*/
static inline void
free_paint(session_t *ps, paint_t *ppaint) {
free_texture(ps, &ppaint->ptex);
free_paint_glx(ps, ppaint);
free_picture(ps, &ppaint->pict);
free_pixmap(ps, &ppaint->pixmap);
}
@ -292,6 +292,7 @@ free_wpaint(session_t *ps, win *w) {
*/
static inline void
free_win_res(session_t *ps, win *w) {
free_win_res_glx(ps, w);
free_region(ps, &w->extents);
free_paint(ps, &w->paint);
free_region(ps, &w->border_size);
@ -302,9 +303,6 @@ free_win_res(session_t *ps, win *w) {
free(w->class_instance);
free(w->class_general);
free(w->role);
#ifdef CONFIG_VSYNC_OPENGL_GLSL
free_glx_bc(ps, &w->glx_blur_cache);
#endif
}
/**
@ -356,7 +354,7 @@ isdamagenotify(session_t *ps, const XEvent *ev) {
*/
static inline XTextProperty *
make_text_prop(session_t *ps, char *str) {
XTextProperty *pprop = cmalloc(1, XTextProperty);
XTextProperty *pprop = ccalloc(1, XTextProperty);
if (XmbTextListToTextProperty(ps->dpy, &str, 1, XStringStyle, pprop)) {
cxfree(pprop->value);
@ -678,20 +676,37 @@ static win *
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,
render_(session_t *ps, int x, int y, int dx, int dy, int wid, int hei,
double opacity, bool argb, bool neg,
Picture pict, glx_texture_t *ptex,
XserverRegion reg_paint, const reg_data_t *pcache_reg);
XserverRegion reg_paint, const reg_data_t *pcache_reg
#ifdef CONFIG_VSYNC_OPENGL_GLSL
, const glx_prog_main_t *pprogram
#endif
);
#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)
#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)
#endif
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, Picture pict) {
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,
Picture pict) {
const int dx = (w ? w->a.x: 0) + x;
const int dy = (w ? w->a.y: 0) + y;
const bool argb = (w && w->mode == WMODE_ARGB);
const bool argb = (w && (WMODE_ARGB == w->mode || 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);
pict, (w ? w->paint.ptex: ps->root_tile_paint.ptex),
reg_paint, pcache_reg, (w ? &ps->o.glx_prog_win: NULL));
}
static inline void
@ -837,12 +852,21 @@ win_update_prop_shadow_raw(session_t *ps, win *w);
static void
win_update_prop_shadow(session_t *ps, win *w);
static void
win_set_shadow(session_t *ps, win *w, bool shadow_new);
static void
win_determine_shadow(session_t *ps, win *w);
static void
win_set_invert_color(session_t *ps, win *w, bool invert_color_new);
static void
win_determine_invert_color(session_t *ps, win *w);
static void
win_set_blur_background(session_t *ps, win *w, bool blur_background_new);
static void
win_determine_blur_background(session_t *ps, win *w);
@ -1204,10 +1228,10 @@ swopti_handle_timeout(session_t *ps, struct timeval *ptv);
static inline bool
ensure_glx_context(session_t *ps) {
// Create GLX context
if (!ps->glx_context)
if (!glx_has_context(ps))
glx_init(ps, false);
return ps->glx_context;
return ps->psglx->context;
}
#endif
@ -1254,7 +1278,7 @@ init_alpha_picts(session_t *ps);
static bool
init_dbe(session_t *ps);
static void
static bool
init_overlay(session_t *ps);
static void

@ -901,6 +901,11 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
cdbus_m_opts_get_do(fork_after_register, cdbus_reply_bool);
cdbus_m_opts_get_do(detect_rounded_corners, cdbus_reply_bool);
cdbus_m_opts_get_do(paint_on_overlay, cdbus_reply_bool);
// paint_on_overlay_id: Get ID of the X composite overlay window
if (!strcmp("paint_on_overlay_id", target)) {
cdbus_reply_uint32(ps, msg, ps->overlay);
return true;
}
cdbus_m_opts_get_do(unredir_if_possible, cdbus_reply_bool);
cdbus_m_opts_get_do(unredir_if_possible_delay, cdbus_reply_int32);
cdbus_m_opts_get_do(redirected_force, cdbus_reply_enum);

@ -15,15 +15,15 @@
void
xr_glx_sync(session_t *ps, Drawable d, XSyncFence *pfence) {
if (*pfence) {
// GLsync sync = ps->glFenceSyncProc(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
GLsync sync = ps->glImportSyncEXT(GL_SYNC_X11_FENCE_EXT, *pfence, 0);
/* GLenum ret = ps->glClientWaitSyncProc(sync, GL_SYNC_FLUSH_COMMANDS_BIT,
// GLsync sync = ps->psglx->glFenceSyncProc(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
GLsync sync = ps->psglx->glImportSyncEXT(GL_SYNC_X11_FENCE_EXT, *pfence, 0);
/* GLenum ret = ps->psglx->glClientWaitSyncProc(sync, GL_SYNC_FLUSH_COMMANDS_BIT,
1000);
assert(GL_CONDITION_SATISFIED == ret); */
XSyncTriggerFence(ps->dpy, *pfence);
XFlush(ps->dpy);
ps->glWaitSyncProc(sync, 0, GL_TIMEOUT_IGNORED);
// ps->glDeleteSyncProc(sync);
ps->psglx->glWaitSyncProc(sync, 0, GL_TIMEOUT_IGNORED);
// ps->psglx->glDeleteSyncProc(sync);
// XSyncResetFence(ps->dpy, *pfence);
}
glx_check_err(ps);
@ -99,10 +99,28 @@ glx_init(session_t *ps, bool need_render) {
if (need_render && !glx_hasglxext(ps, "GLX_EXT_texture_from_pixmap"))
goto glx_init_end;
if (!ps->glx_context) {
// Initialize GLX data structure
if (!ps->psglx) {
static const glx_session_t CGLX_SESSION_DEF = CGLX_SESSION_INIT;
ps->psglx = cmalloc(1, glx_session_t);
memcpy(ps->psglx, &CGLX_SESSION_DEF, sizeof(glx_session_t));
#ifdef CONFIG_VSYNC_OPENGL_GLSL
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
ppass->unifm_factor_center = -1;
ppass->unifm_offset_x = -1;
ppass->unifm_offset_y = -1;
}
#endif
}
glx_session_t *psglx = ps->psglx;
if (!psglx->context) {
// Get GLX context
#ifndef DEBUG_GLX_DEBUG_CONTEXT
ps->glx_context = glXCreateContext(ps->dpy, pvis, None, GL_TRUE);
psglx->context = glXCreateContext(ps->dpy, pvis, None, GL_TRUE);
#else
{
GLXFBConfig fbconfig = get_fbconfig_from_visualinfo(ps, pvis);
@ -124,18 +142,18 @@ glx_init(session_t *ps, bool need_render) {
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
None
};
ps->glx_context = p_glXCreateContextAttribsARB(ps->dpy, fbconfig, NULL,
psglx->context = p_glXCreateContextAttribsARB(ps->dpy, fbconfig, NULL,
GL_TRUE, attrib_list);
}
#endif
if (!ps->glx_context) {
if (!psglx->context) {
printf_errf("(): Failed to get GLX context.");
goto glx_init_end;
}
// Attach GLX context
if (!glXMakeCurrent(ps->dpy, get_tgt_window(ps), ps->glx_context)) {
if (!glXMakeCurrent(ps->dpy, get_tgt_window(ps), psglx->context)) {
printf_errf("(): Failed to attach GLX context.");
goto glx_init_end;
}
@ -170,52 +188,52 @@ glx_init(session_t *ps, bool need_render) {
// Check GL_ARB_texture_non_power_of_two, requires a GLX context and
// must precede FBConfig fetching
if (need_render)
ps->glx_has_texture_non_power_of_two = glx_hasglext(ps,
psglx->has_texture_non_power_of_two = glx_hasglext(ps,
"GL_ARB_texture_non_power_of_two");
// Acquire function addresses
if (need_render) {
#ifdef DEBUG_GLX_MARK
ps->glStringMarkerGREMEDY = (f_StringMarkerGREMEDY)
psglx->glStringMarkerGREMEDY = (f_StringMarkerGREMEDY)
glXGetProcAddress((const GLubyte *) "glStringMarkerGREMEDY");
ps->glFrameTerminatorGREMEDY = (f_FrameTerminatorGREMEDY)
psglx->glFrameTerminatorGREMEDY = (f_FrameTerminatorGREMEDY)
glXGetProcAddress((const GLubyte *) "glFrameTerminatorGREMEDY");
#endif
ps->glXBindTexImageProc = (f_BindTexImageEXT)
psglx->glXBindTexImageProc = (f_BindTexImageEXT)
glXGetProcAddress((const GLubyte *) "glXBindTexImageEXT");
ps->glXReleaseTexImageProc = (f_ReleaseTexImageEXT)
psglx->glXReleaseTexImageProc = (f_ReleaseTexImageEXT)
glXGetProcAddress((const GLubyte *) "glXReleaseTexImageEXT");
if (!ps->glXBindTexImageProc || !ps->glXReleaseTexImageProc) {
if (!psglx->glXBindTexImageProc || !psglx->glXReleaseTexImageProc) {
printf_errf("(): Failed to acquire glXBindTexImageEXT() / glXReleaseTexImageEXT().");
goto glx_init_end;
}
if (ps->o.glx_use_copysubbuffermesa) {
ps->glXCopySubBufferProc = (f_CopySubBuffer)
psglx->glXCopySubBufferProc = (f_CopySubBuffer)
glXGetProcAddress((const GLubyte *) "glXCopySubBufferMESA");
if (!ps->glXCopySubBufferProc) {
if (!psglx->glXCopySubBufferProc) {
printf_errf("(): Failed to acquire glXCopySubBufferMESA().");
goto glx_init_end;
}
}
#ifdef CONFIG_GLX_SYNC
ps->glFenceSyncProc = (f_FenceSync)
psglx->glFenceSyncProc = (f_FenceSync)
glXGetProcAddress((const GLubyte *) "glFenceSync");
ps->glIsSyncProc = (f_IsSync)
psglx->glIsSyncProc = (f_IsSync)
glXGetProcAddress((const GLubyte *) "glIsSync");
ps->glDeleteSyncProc = (f_DeleteSync)
psglx->glDeleteSyncProc = (f_DeleteSync)
glXGetProcAddress((const GLubyte *) "glDeleteSync");
ps->glClientWaitSyncProc = (f_ClientWaitSync)
psglx->glClientWaitSyncProc = (f_ClientWaitSync)
glXGetProcAddress((const GLubyte *) "glClientWaitSync");
ps->glWaitSyncProc = (f_WaitSync)
psglx->glWaitSyncProc = (f_WaitSync)
glXGetProcAddress((const GLubyte *) "glWaitSync");
ps->glImportSyncEXT = (f_ImportSyncEXT)
psglx->glImportSyncEXT = (f_ImportSyncEXT)
glXGetProcAddress((const GLubyte *) "glImportSyncEXT");
if (!ps->glFenceSyncProc || !ps->glIsSyncProc || !ps->glDeleteSyncProc
|| !ps->glClientWaitSyncProc || !ps->glWaitSyncProc
|| !ps->glImportSyncEXT) {
if (!psglx->glFenceSyncProc || !psglx->glIsSyncProc || !psglx->glDeleteSyncProc
|| !psglx->glClientWaitSyncProc || !psglx->glWaitSyncProc
|| !psglx->glImportSyncEXT) {
printf_errf("(): Failed to acquire GLX sync functions.");
goto glx_init_end;
}
@ -260,33 +278,86 @@ glx_init_end:
return success;
}
#ifdef CONFIG_VSYNC_OPENGL_GLSL
static void
glx_free_prog_main(session_t *ps, glx_prog_main_t *pprogram) {
if (!pprogram)
return;
if (pprogram->prog) {
glDeleteProgram(pprogram->prog);
pprogram->prog = 0;
}
pprogram->unifm_opacity = -1;
pprogram->unifm_invert_color = -1;
pprogram->unifm_tex = -1;
}
#endif
/**
* Destroy GLX related resources.
*/
void
glx_destroy(session_t *ps) {
if (!ps->psglx)
return;
// Free all GLX resources of windows
for (win *w = ps->list; w; w = w->next)
free_win_res_glx(ps, w);
#ifdef CONFIG_VSYNC_OPENGL_GLSL
// Free GLSL shaders/programs
for (int i = 0; i < MAX_BLUR_PASS; ++i) {
glx_blur_pass_t *ppass = &ps->glx_blur_passes[i];
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
if (ppass->frag_shader)
glDeleteShader(ppass->frag_shader);
if (ppass->prog)
glDeleteProgram(ppass->prog);
}
glx_free_prog_main(ps, &ps->o.glx_prog_win);
glx_check_err(ps);
#endif
// Free FBConfigs
for (int i = 0; i <= OPENGL_MAX_DEPTH; ++i) {
free(ps->glx_fbconfigs[i]);
ps->glx_fbconfigs[i] = NULL;
free(ps->psglx->fbconfigs[i]);
ps->psglx->fbconfigs[i] = NULL;
}
// Destroy GLX context
if (ps->glx_context) {
glXDestroyContext(ps->dpy, ps->glx_context);
ps->glx_context = NULL;
if (ps->psglx->context) {
glXDestroyContext(ps->dpy, ps->psglx->context);
ps->psglx->context = NULL;
}
free(ps->psglx);
ps->psglx = NULL;
}
/**
* Reinitialize GLX.
*/
bool
glx_reinit(session_t *ps, bool need_render) {
// Reinitialize VSync as well
vsync_deinit(ps);
glx_destroy(ps);
if (!glx_init(ps, need_render)) {
printf_errf("(): Failed to initialize GLX.");
return false;
}
if (!vsync_init(ps)) {
printf_errf("(): Failed to initialize VSync.");
return false;
}
return true;
}
/**
@ -356,7 +427,7 @@ glx_init_blur(session_t *ps) {
" gl_FragColor = sum / (factor_center + float(%.7g));\n"
"}\n";
const bool use_texture_rect = !ps->glx_has_texture_non_power_of_two;
const bool use_texture_rect = !ps->psglx->has_texture_non_power_of_two;
const char *sampler_type = (use_texture_rect ?
"sampler2DRect": "sampler2D");
const char *texture_func = (use_texture_rect ?
@ -375,7 +446,7 @@ glx_init_blur(session_t *ps) {
if (!kern)
break;
glx_blur_pass_t *ppass = &ps->glx_blur_passes[i];
glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
// Build shader
{
@ -440,6 +511,7 @@ glx_init_blur(session_t *ps) {
P_GET_UNIFM_LOC("offset_x", unifm_offset_x);
P_GET_UNIFM_LOC("offset_y", unifm_offset_y);
}
#undef P_GET_UNIFM_LOC
}
free(extension);
@ -459,6 +531,43 @@ glx_init_blur(session_t *ps) {
#endif
}
#ifdef CONFIG_VSYNC_OPENGL_GLSL
/**
* Load a GLSL main program from shader strings.
*/
bool
glx_load_prog_main(session_t *ps,
const char *vshader_str, const char *fshader_str,
glx_prog_main_t *pprogram) {
assert(pprogram);
// Build program
pprogram->prog = glx_create_program_from_str(vshader_str, fshader_str);
if (!pprogram->prog) {
printf_errf("(): Failed to create GLSL program.");
return false;
}
// Get uniform addresses
#define P_GET_UNIFM_LOC(name, target) { \
pprogram->target = glGetUniformLocation(pprogram->prog, name); \
if (pprogram->target < 0) { \
printf_errf("(): Failed to get location of uniform '" name "'. Might be troublesome."); \
} \
}
P_GET_UNIFM_LOC("opacity", unifm_opacity);
P_GET_UNIFM_LOC("invert_color", unifm_invert_color);
P_GET_UNIFM_LOC("tex", unifm_tex);
#undef P_GET_UNIFM_LOC
glx_check_err(ps);
return true;
}
#endif
/**
* @brief Update the FBConfig of given depth.
*/
@ -469,15 +578,15 @@ glx_update_fbconfig_bydepth(session_t *ps, int depth, glx_fbconfig_t *pfbcfg) {
return;
// Compare new FBConfig with current one
if (glx_cmp_fbconfig(ps, ps->glx_fbconfigs[depth], pfbcfg) < 0) {
if (glx_cmp_fbconfig(ps, ps->psglx->fbconfigs[depth], pfbcfg) < 0) {
#ifdef DEBUG_GLX
printf_dbgf("(%d): %#x overrides %#x, target %#x.\n", depth, (unsigned) pfbcfg->cfg, (ps->glx_fbconfigs[depth] ? (unsigned) ps->glx_fbconfigs[depth]->cfg: 0), pfbcfg->texture_tgts);
printf_dbgf("(%d): %#x overrides %#x, target %#x.\n", depth, (unsigned) pfbcfg->cfg, (ps->psglx->fbconfigs[depth] ? (unsigned) ps->psglx->fbconfigs[depth]->cfg: 0), pfbcfg->texture_tgts);
#endif
if (!ps->glx_fbconfigs[depth]) {
ps->glx_fbconfigs[depth] = malloc(sizeof(glx_fbconfig_t));
allocchk(ps->glx_fbconfigs[depth]);
if (!ps->psglx->fbconfigs[depth]) {
ps->psglx->fbconfigs[depth] = malloc(sizeof(glx_fbconfig_t));
allocchk(ps->psglx->fbconfigs[depth]);
}
(*ps->glx_fbconfigs[depth]) = *pfbcfg;
(*ps->psglx->fbconfigs[depth]) = *pfbcfg;
}
}
@ -559,19 +668,19 @@ glx_update_fbconfig(session_t *ps) {
cxfree(pfbcfgs);
// Sanity checks
if (!ps->glx_fbconfigs[ps->depth]) {
if (!ps->psglx->fbconfigs[ps->depth]) {
printf_errf("(): No FBConfig found for default depth %d.", ps->depth);
return false;
}
if (!ps->glx_fbconfigs[32]) {
if (!ps->psglx->fbconfigs[32]) {
printf_errf("(): No FBConfig found for depth 32. Expect crazy things.");
}
#ifdef DEBUG_GLX
printf_dbgf("(): %d-bit: %#3x, 32-bit: %#3x\n",
ps->depth, (int) ps->glx_fbconfigs[ps->depth]->cfg,
(int) ps->glx_fbconfigs[32]->cfg);
ps->depth, (int) ps->psglx->fbconfigs[ps->depth]->cfg,
(int) ps->psglx->fbconfigs[32]->cfg);
#endif
return true;
@ -675,7 +784,7 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
}
}
const glx_fbconfig_t *pcfg = ps->glx_fbconfigs[depth];
const glx_fbconfig_t *pcfg = ps->psglx->fbconfigs[depth];
if (!pcfg) {
printf_errf("(%d): Couldn't find FBConfig with requested depth.", depth);
return false;
@ -686,7 +795,7 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
// pixmap-specific parameters, and this may change in the future
GLenum tex_tgt = 0;
if (GLX_TEXTURE_2D_BIT_EXT & pcfg->texture_tgts
&& ps->glx_has_texture_non_power_of_two)
&& ps->psglx->has_texture_non_power_of_two)
tex_tgt = GLX_TEXTURE_2D_EXT;
else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & pcfg->texture_tgts)
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT;
@ -751,9 +860,9 @@ glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
// The specification requires rebinding whenever the content changes...
// We can't follow this, too slow.
if (need_release)
ps->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
ps->psglx->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
ps->glXBindTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
ps->psglx->glXBindTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
// Cleanup
glBindTexture(ptex->target, 0);
@ -772,7 +881,7 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
// Release binding
if (ptex->glpixmap && ptex->texture) {
glBindTexture(ptex->target, ptex->texture);
ps->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
ps->psglx->glXReleaseTexImageProc(ps->dpy, ptex->glpixmap, GLX_FRONT_LEFT_EXT);
glBindTexture(ptex->target, 0);
}
@ -790,7 +899,7 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
*/
void
glx_paint_pre(session_t *ps, XserverRegion *preg) {
ps->glx_z = 0.0;
ps->psglx->z = 0.0;
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Get buffer age
@ -1058,8 +1167,8 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
GLfloat factor_center,
XserverRegion reg_tgt, const reg_data_t *pcache_reg,
glx_blur_cache_t *pbc) {
assert(ps->glx_blur_passes[0].prog);
const bool more_passes = ps->glx_blur_passes[1].prog;
assert(ps->psglx->blur_passes[0].prog);
const bool more_passes = ps->psglx->blur_passes[1].prog;
const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST);
const bool have_stencil = glIsEnabled(GL_STENCIL_TEST);
bool ret = false;
@ -1096,7 +1205,7 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
*/
GLenum tex_tgt = GL_TEXTURE_RECTANGLE;
if (ps->glx_has_texture_non_power_of_two)
if (ps->psglx->has_texture_non_power_of_two)
tex_tgt = GL_TEXTURE_2D;
// Free textures if size inconsistency discovered
@ -1159,9 +1268,9 @@ glx_blur_dst(session_t *ps, int dx, int dy, int width, int height, float z,
bool last_pass = false;
for (int i = 0; !last_pass; ++i) {
last_pass = !ps->glx_blur_passes[i + 1].prog;
last_pass = !ps->psglx->blur_passes[i + 1].prog;
assert(i < MAX_BLUR_PASS - 1);
const glx_blur_pass_t *ppass = &ps->glx_blur_passes[i];
const glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
assert(ppass->prog);
assert(tex_scr);
@ -1315,10 +1424,14 @@ glx_dim_dst(session_t *ps, int dx, int dy, int width, int height, float z,
* @brief Render a region with texture data.
*/
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,
double opacity, bool neg,
XserverRegion reg_tgt, const reg_data_t *pcache_reg) {
double opacity, bool argb, bool neg,
XserverRegion reg_tgt, const reg_data_t *pcache_reg
#ifdef CONFIG_VSYNC_OPENGL_GLSL
, const glx_prog_main_t *pprogram
#endif
) {
if (!ptex || !ptex->texture) {
printf_errf("(): Missing texture.");
return false;
@ -1329,8 +1442,11 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
return true;
#endif
const bool argb = (GLX_TEXTURE_FORMAT_RGBA_EXT ==
ps->glx_fbconfigs[ptex->depth]->texture_fmt);
argb = argb || (GLX_TEXTURE_FORMAT_RGBA_EXT ==
ps->psglx->fbconfigs[ptex->depth]->texture_fmt);
#ifdef CONFIG_VSYNC_OPENGL_GLSL
const bool has_prog = pprogram && pprogram->prog;
#endif
bool dual_texture = false;
// It's required by legacy versions of OpenGL to enable texture target
@ -1351,77 +1467,95 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
glColor4f(opacity, opacity, opacity, opacity);
}
// Color negation
if (neg) {
// Simple color negation
if (!glIsEnabled(GL_BLEND)) {
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(GL_COPY_INVERTED);
}
// ARGB texture color negation
else if (argb) {
dual_texture = true;
// Use two texture stages because the calculation is too complicated,
// thanks to madsy for providing code
// Texture stage 0
glActiveTexture(GL_TEXTURE0);
// Negation for premultiplied color: color = A - C
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
// Pass texture alpha through
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
// Texture stage 1
glActiveTexture(GL_TEXTURE1);
glEnable(ptex->target);
glBindTexture(ptex->target, ptex->texture);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
// Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
}
// RGB blend color negation
else {
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
// Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
#ifdef CONFIG_VSYNC_OPENGL_GLSL
if (!has_prog)
#endif
{
// Color negation
if (neg) {
// Simple color negation
if (!glIsEnabled(GL_BLEND)) {
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(GL_COPY_INVERTED);
}
// ARGB texture color negation
else if (argb) {
dual_texture = true;
// Use two texture stages because the calculation is too complicated,
// thanks to madsy for providing code
// Texture stage 0
glActiveTexture(GL_TEXTURE0);
// Negation for premultiplied color: color = A - C
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
// Pass texture alpha through
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
// Texture stage 1
glActiveTexture(GL_TEXTURE1);
glEnable(ptex->target);
glBindTexture(ptex->target, ptex->texture);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
// Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
glActiveTexture(GL_TEXTURE0);
}
// RGB blend color negation
else {
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
// Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
}
}
}
#ifdef CONFIG_VSYNC_OPENGL_GLSL
else {
// Programmable path
assert(pprogram->prog);
glUseProgram(pprogram->prog);
if (pprogram->unifm_opacity >= 0)
glUniform1f(pprogram->unifm_opacity, opacity);
if (pprogram->unifm_invert_color >= 0)
glUniform1i(pprogram->unifm_invert_color, neg);
if (pprogram->unifm_tex >= 0)
glUniform1i(pprogram->unifm_tex, 0);
}
#endif
#ifdef DEBUG_GLX
printf_dbgf("(): Draw: %d, %d, %d, %d -> %d, %d (%d, %d) z %d\n", x, y, width, height, dx, dy, ptex->width, ptex->height, z);
@ -1504,6 +1638,11 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
glActiveTexture(GL_TEXTURE0);
}
#ifdef CONFIG_VSYNC_OPENGL_GLSL
if (has_prog)
glUseProgram(0);
#endif
glx_check_err(ps);
return true;
@ -1641,7 +1780,7 @@ glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg) {
#ifdef DEBUG_GLX
printf_dbgf("(): %d, %d, %d, %d\n", x, y, wid, hei);
#endif
ps->glXCopySubBufferProc(ps->dpy, get_tgt_window(ps), x, y, wid, hei);
ps->psglx->glXCopySubBufferProc(ps->dpy, get_tgt_window(ps), x, y, wid, hei);
}
}
@ -1650,6 +1789,32 @@ glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg) {
cxfree(rects);
}
/**
* @brief Get tightly packed RGB888 data from GL front buffer.
*
* Don't expect any sort of decent performance.
*
* @returns tightly packed RGB888 data of the size of the screen,
* to be freed with `free()`
*/
unsigned char *
glx_take_screenshot(session_t *ps, int *out_length) {
int length = 3 * ps->root_width * ps->root_height;
GLint unpack_align_old = 0;
glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_align_old);
assert(unpack_align_old > 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
unsigned char *buf = cmalloc(length, unsigned char);
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, ps->root_width, ps->root_height, GL_RGB,
GL_UNSIGNED_BYTE, buf);
glReadBuffer(GL_BACK);
glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_align_old);
if (out_length)
*out_length = sizeof(unsigned char) * length;
return buf;
}
#ifdef CONFIG_VSYNC_OPENGL_GLSL
GLuint
glx_create_shader(GLenum shader_type, const char *shader_str) {
@ -1661,7 +1826,7 @@ glx_create_shader(GLenum shader_type, const char *shader_str) {
bool success = false;
GLuint shader = glCreateShader(shader_type);
if (!shader) {
printf_errf("(): Failed to create shader with type %d.", shader_type);
printf_errf("(): Failed to create shader with type %#x.", shader_type);
goto glx_create_shader_end;
}
glShaderSource(shader, 1, &shader_str, NULL);
@ -1737,5 +1902,40 @@ glx_create_program_end:
return program;
}
/**
* @brief Create a program from vertex and fragment shader strings.
*/
GLuint
glx_create_program_from_str(const char *vert_shader_str,
const char *frag_shader_str) {
GLuint vert_shader = 0;
GLuint frag_shader = 0;
GLuint prog = 0;
if (vert_shader_str)
vert_shader = glx_create_shader(GL_VERTEX_SHADER, vert_shader_str);
if (frag_shader_str)
frag_shader = glx_create_shader(GL_FRAGMENT_SHADER, frag_shader_str);
{
GLuint shaders[2];
int count = 0;
if (vert_shader)
shaders[count++] = vert_shader;
if (frag_shader)
shaders[count++] = frag_shader;
assert(count <= sizeof(shaders) / sizeof(shaders[0]));
if (count)
prog = glx_create_program(shaders, count);
}
if (vert_shader)
glDeleteShader(vert_shader);
if (frag_shader)
glDeleteShader(frag_shader);
return prog;
}
#endif

@ -41,10 +41,10 @@ glx_dump_err_str(GLenum err) {
*/
static inline void
glx_check_err_(session_t *ps, const char *func, int line) {
if (!ps->glx_context) return;
if (!ps->psglx->context) return;
GLenum err = GL_NO_ERROR;
while (GL_NO_ERROR != (err = glGetError())) {
print_timestamp(ps);
printf("%s():%d: GLX error ", func, line);

@ -0,0 +1,65 @@
#include "xrescheck.h"
static xrc_xid_record_t *gs_xid_records = NULL;
#define HASH_ADD_XID(head, xidfield, add) \
HASH_ADD(hh, head, xidfield, sizeof(xid), add)
#define HASH_FIND_XID(head, findxid, out) \
HASH_FIND(hh, head, findxid, sizeof(xid), out)
#define M_CPY_POS_DATA(prec) \
prec->file = file; \
prec->func = func; \
prec->line = line; \
/**
* @brief Add a record of given XID to the allocation table.
*/
void
xrc_add_xid_(XID xid, const char *type, M_POS_DATA_PARAMS) {
xrc_xid_record_t *prec = cmalloc(1, xrc_xid_record_t);
prec->xid = xid;
prec->type = type;
M_CPY_POS_DATA(prec);
HASH_ADD_XID(gs_xid_records, xid, prec);
}
/**
* @brief Delete a record of given XID in the allocation table.
*/
void
xrc_delete_xid_(XID xid, M_POS_DATA_PARAMS) {
xrc_xid_record_t *prec = NULL;
HASH_FIND_XID(gs_xid_records, &xid, prec);
if (!prec) {
printf_err("XRC: %s:%d %s(): Can't find XID %#010lx we want to delete.",
file, line, func, xid);
return;
}
HASH_DEL(gs_xid_records, prec);
free(prec);
}
/**
* @brief Report about issues found in the XID allocation table.
*/
void
xrc_report_xid(void) {
for (xrc_xid_record_t *prec = gs_xid_records; prec; prec = prec->hh.next)
printf_dbg("XRC: %s:%d %s(): %#010lx (%s) not freed.\n",
prec->file, prec->line, prec->func, prec->xid, prec->type);
}
/**
* @brief Clear the XID allocation table.
*/
void
xrc_clear_xid(void) {
xrc_xid_record_t *prec = NULL, *ptmp = NULL;
HASH_ITER(hh, gs_xid_records, prec, ptmp) {
HASH_DEL(gs_xid_records, prec);
free(prec);
}
}

@ -0,0 +1,70 @@
#ifndef COMPTON_XRESCHECK_H
#define COMPTON_XRESCHECK_H
#include "common.h"
#include <uthash.h>
typedef struct {
XID xid;
const char *type;
const char *file;
const char *func;
int line;
UT_hash_handle hh;
} xrc_xid_record_t;
#define M_POS_DATA_PARAMS const char *file, int line, const char *func
#define M_POS_DATA_PASSTHROUGH file, line, func
#define M_POS_DATA __FILE__, __LINE__, __func__
void
xrc_add_xid_(XID xid, const char *type, M_POS_DATA_PARAMS);
#define xrc_add_xid(xid, type) xrc_add_xid_(xid, type, M_POS_DATA)
void
xrc_delete_xid_(XID xid, M_POS_DATA_PARAMS);
#define xrc_delete_xid(xid) xrc_delete_xid_(xid, M_POS_DATA)
void
xrc_report_xid(void);
void
xrc_clear_xid(void);
// Pixmap
static inline Pixmap
XCreatePixmap_(Display *dpy, Drawable drawable,
unsigned int width, unsigned int height, unsigned int depth,
M_POS_DATA_PARAMS) {
Pixmap ret = XCreatePixmap(dpy, drawable, width, height, depth);
if (ret)
xrc_add_xid_(ret, "Pixmap", M_POS_DATA_PASSTHROUGH);
return ret;
}
#define XCreatePixmap(dpy, drawable, width, height, depth) \
XCreatePixmap_(dpy, drawable, width, height, depth, M_POS_DATA)
static inline Pixmap
XCompositeNameWindowPixmap_(Display *dpy, Window window, M_POS_DATA_PARAMS) {
Pixmap ret = XCompositeNameWindowPixmap(dpy, window);
if (ret)
xrc_add_xid_(ret, "PixmapC", M_POS_DATA_PASSTHROUGH);
return ret;
}
#define XCompositeNameWindowPixmap(dpy, window) \
XCompositeNameWindowPixmap_(dpy, window, M_POS_DATA)
static inline void
XFreePixmap_(Display *dpy, Pixmap pixmap, M_POS_DATA_PARAMS) {
XFreePixmap(dpy, pixmap);
xrc_delete_xid_(pixmap, M_POS_DATA_PASSTHROUGH);
}
#define XFreePixmap(dpy, pixmap) XFreePixmap_(dpy, pixmap, M_POS_DATA);
#endif
Loading…
Cancel
Save