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) { if (pleaf->predef) {
switch (pleaf->predef) { switch (pleaf->predef) {
case C2_L_PFOCUSED: ps->o.track_focus = true; break; 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_PNAME:
case C2_L_PCLASSG: case C2_L_PCLASSG:
case C2_L_PCLASSI: 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_PARGB: tgt = (WMODE_ARGB == w->mode); break;
case C2_L_PFOCUSED: tgt = win_is_focused_real(ps, w); break; case C2_L_PFOCUSED: tgt = win_is_focused_real(ps, w); break;
case C2_L_PWMWIN: tgt = w->wmwin; 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_PCLIENT: tgt = w->client_win; break;
case C2_L_PLEADER: tgt = w->leader; break; case C2_L_PLEADER: tgt = w->leader; break;
default: *perr = true; assert(0); 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 bool
c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst, c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst,
const c2_lptr_t **cache, void **pdata) { const c2_lptr_t **cache, void **pdata) {
assert(IsViewable == w->a.map_state);
// Check if the cached entry matches firstly // Check if the cached entry matches firstly
if (cache && *cache && c2_match_once(ps, w, (*cache)->ptr)) { if (cache && *cache && c2_match_once(ps, w, (*cache)->ptr)) {
if (pdata) if (pdata)

@ -113,6 +113,8 @@ struct _c2_l {
C2_L_PARGB, C2_L_PARGB,
C2_L_PFOCUSED, C2_L_PFOCUSED,
C2_L_PWMWIN, C2_L_PWMWIN,
C2_L_PBSHAPED,
C2_L_PROUNDED,
C2_L_PCLIENT, C2_L_PCLIENT,
C2_L_PWINDOWTYPE, C2_L_PWINDOWTYPE,
C2_L_PLEADER, C2_L_PLEADER,
@ -201,6 +203,8 @@ const static c2_predef_t C2_PREDEFS[] = {
[C2_L_PARGB ] = { "argb" , C2_L_TCARDINAL , 0 }, [C2_L_PARGB ] = { "argb" , C2_L_TCARDINAL , 0 },
[C2_L_PFOCUSED ] = { "focused" , C2_L_TCARDINAL , 0 }, [C2_L_PFOCUSED ] = { "focused" , C2_L_TCARDINAL , 0 },
[C2_L_PWMWIN ] = { "wmwin" , 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_PCLIENT ] = { "client" , C2_L_TWINDOW , 0 },
[C2_L_PWINDOWTYPE ] = { "window_type" , C2_L_TSTRING , 0 }, [C2_L_PWINDOWTYPE ] = { "window_type" , C2_L_TSTRING , 0 },
[C2_L_PLEADER ] = { "leader" , C2_L_TWINDOW , 0 }, [C2_L_PLEADER ] = { "leader" , C2_L_TWINDOW , 0 },

@ -17,6 +17,7 @@
// === Options === // === Options ===
// Debug options, enable them using -D in CFLAGS // Debug options, enable them using -D in CFLAGS
// #define DEBUG_BACKTRACE 1
// #define DEBUG_REPAINT 1 // #define DEBUG_REPAINT 1
// #define DEBUG_EVENTS 1 // #define DEBUG_EVENTS 1
// #define DEBUG_RESTACK 1 // #define DEBUG_RESTACK 1
@ -83,6 +84,10 @@
#define COMPTON_VERSION "unknown" #define COMPTON_VERSION "unknown"
#endif #endif
#if defined(DEBUG_ALLOC_REG)
#define DEBUG_BACKTRACE 1
#endif
// === Includes === // === Includes ===
// For some special functions // For some special functions
@ -154,8 +159,6 @@
#define GLX_BACK_BUFFER_AGE_EXT 0x20F4 #define GLX_BACK_BUFFER_AGE_EXT 0x20F4
#endif #endif
#endif
// === Macros === // === Macros ===
#define MSTR_(s) #s #define MSTR_(s) #s
@ -195,6 +198,11 @@
/// Macro used for shortening some debugging code. /// Macro used for shortening some debugging code.
#define CASESTRRET(s) case s: return #s #define CASESTRRET(s) case s: return #s
// X resource checker
#ifdef DEBUG_XRC
#include "xrescheck.h"
#endif
// === Constants === // === Constants ===
#if !(COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2) #if !(COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2)
#error libXcomposite version unsupported #error libXcomposite version unsupported
@ -222,7 +230,7 @@
#define MS_PER_SEC 1000 #define MS_PER_SEC 1000
#define XRFILTER_CONVOLUTION "convolution" #define XRFILTER_CONVOLUTION "convolution"
#define XRFILTER_GUASSIAN "gaussian" #define XRFILTER_GAUSSIAN "gaussian"
#define XRFILTER_BINOMIAL "binomial" #define XRFILTER_BINOMIAL "binomial"
/// @brief Maximum OpenGL FBConfig depth. /// @brief Maximum OpenGL FBConfig depth.
@ -454,7 +462,6 @@ struct _glx_texture {
unsigned depth; unsigned depth;
bool y_inverted; bool y_inverted;
}; };
#endif
#ifdef CONFIG_VSYNC_OPENGL_GLSL #ifdef CONFIG_VSYNC_OPENGL_GLSL
typedef struct { typedef struct {
@ -480,6 +487,26 @@ typedef struct {
/// Height of the textures. /// Height of the textures.
int height; int height;
} glx_blur_cache_t; } 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 #endif
typedef struct { typedef struct {
@ -547,10 +574,12 @@ typedef struct _options_t {
int glx_swap_method; int glx_swap_method;
/// Whether to use GL_EXT_gpu_shader4 to (hopefully) accelerates blurring. /// Whether to use GL_EXT_gpu_shader4 to (hopefully) accelerates blurring.
bool glx_use_gpushader4; bool glx_use_gpushader4;
/// Whether to try to detect WM windows and mark them as focused. /// Custom fragment shader for painting windows, as a string.
bool mark_wmwin_focused; char *glx_fshader_win_str;
/// Whether to mark override-redirect windows as focused. #ifdef CONFIG_VSYNC_OPENGL_GLSL
bool mark_ovredir_focused; /// Custom GLX program used for painting window.
glx_prog_main_t glx_prog_win;
#endif
/// Whether to fork to background. /// Whether to fork to background.
bool fork_after_register; bool fork_after_register;
/// Whether to detect rounded corners. /// Whether to detect rounded corners.
@ -558,6 +587,8 @@ typedef struct _options_t {
/// Whether to paint on X Composite overlay window instead of root /// Whether to paint on X Composite overlay window instead of root
/// window. /// window.
bool paint_on_overlay; bool paint_on_overlay;
/// Force painting of window content with blending.
bool force_win_blend;
/// Resize damage for a specific number of pixels. /// Resize damage for a specific number of pixels.
int resize_damage; int resize_damage;
/// Whether to unredirect all windows if a full-screen opaque window /// Whether to unredirect all windows if a full-screen opaque window
@ -572,6 +603,10 @@ typedef struct _options_t {
switch_t redirected_force; switch_t redirected_force;
/// Whether to stop painting. Controlled through D-Bus. /// Whether to stop painting. Controlled through D-Bus.
switch_t stoppaint_force; 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. /// Whether to enable D-Bus support.
bool dbus; bool dbus;
/// Path to log file. /// Path to log file.
@ -582,8 +617,14 @@ typedef struct _options_t {
Window benchmark_wid; Window benchmark_wid;
/// A list of conditions of windows not to paint. /// A list of conditions of windows not to paint.
c2_lptr_t *paint_blacklist; c2_lptr_t *paint_blacklist;
/// Whether to avoid using XCompositeNameWindowPixmap(), for debugging.
bool no_name_pixmap;
/// Whether to work under synchronized mode for debugging. /// Whether to work under synchronized mode for debugging.
bool synchronize; 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 === // === VSync & software optimization ===
/// User-specified refresh rate. /// User-specified refresh rate.
@ -631,6 +672,8 @@ typedef struct _options_t {
time_ms_t fade_delta; time_ms_t fade_delta;
/// Whether to disable fading on window open/close. /// Whether to disable fading on window open/close.
bool no_fading_openclose; 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 /// Whether to disable fading on opacity change
bool no_fading_opacitychange; bool no_fading_opacitychange;
/// Fading blacklist. A linked list of conditions. /// Fading blacklist. A linked list of conditions.
@ -683,6 +726,10 @@ typedef struct _options_t {
// === Focus related === // === Focus related ===
/// Consider windows of specific types to be always focused. /// Consider windows of specific types to be always focused.
bool wintype_focus[NUM_WINTYPES]; 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. /// Whether to use EWMH _NET_ACTIVE_WINDOW to find active window.
bool use_ewmh_active_win; bool use_ewmh_active_win;
/// A list of windows always to be considered focused. /// A list of windows always to be considered focused.
@ -701,6 +748,65 @@ typedef struct _options_t {
bool track_leader; bool track_leader;
} options_t; } 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. /// Structure containing all necessary data for a compton session.
typedef struct _session_t { typedef struct _session_t {
// === Display related === // === Display related ===
@ -742,6 +848,10 @@ typedef struct _session_t {
XdbeBackBuffer root_dbe; XdbeBackBuffer root_dbe;
/// Window ID of the window we register as a symbol. /// Window ID of the window we register as a symbol.
Window reg_win; Window reg_win;
#ifdef CONFIG_VSYNC_OPENGL
/// Pointer to GLX data.
glx_session_t *psglx;
#endif
// === Operation related === // === Operation related ===
/// Program options. /// Program options.
@ -784,10 +894,6 @@ typedef struct _session_t {
/// Pointer to the <code>next</code> member of tail element of the error /// Pointer to the <code>next</code> member of tail element of the error
/// ignore linked list. /// ignore linked list.
ignore_t **ignore_tail; ignore_t **ignore_tail;
#ifdef CONFIG_VSYNC_OPENGL
/// Current GLX Z value.
int glx_z;
#endif
// Cached blur convolution kernels. // Cached blur convolution kernels.
XFixed *blur_kerns_cache[MAX_BLUR_PASS]; XFixed *blur_kerns_cache[MAX_BLUR_PASS];
/// Reset program after next paint. /// Reset program after next paint.
@ -847,57 +953,6 @@ typedef struct _session_t {
int drm_fd; int drm_fd;
#endif #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 === // === X extension related ===
/// Event base number for X Fixes extension. /// Event base number for X Fixes extension.
int xfixes_event; int xfixes_event;
@ -1130,6 +1185,8 @@ typedef struct _win {
/// Do not fade if it's false. Change on window type change. /// Do not fade if it's false. Change on window type change.
/// Used by fading blacklist in the future. /// Used by fading blacklist in the future.
bool fade; bool fade;
/// Fade state on last paint.
bool fade_last;
/// Override value of window fade state. Set by D-Bus method calls. /// Override value of window fade state. Set by D-Bus method calls.
switch_t fade_force; switch_t fade_force;
/// Callback to be called after fading completed. /// Callback to be called after fading completed.
@ -1144,6 +1201,8 @@ typedef struct _win {
// Shadow-related members // Shadow-related members
/// Whether a window has shadow. Calculated. /// Whether a window has shadow. Calculated.
bool shadow; bool shadow;
/// Shadow state on last paint.
bool shadow_last;
/// Override value of window shadow state. Set by D-Bus method calls. /// Override value of window shadow state. Set by D-Bus method calls.
switch_t shadow_force; switch_t shadow_force;
/// Opacity of the shadow. Affected by window opacity and frame opacity. /// Opacity of the shadow. Affected by window opacity and frame opacity.
@ -1170,12 +1229,16 @@ typedef struct _win {
/// Whether to invert window color. /// Whether to invert window color.
bool invert_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 /// Override value of window color inversion state. Set by D-Bus method
/// calls. /// calls.
switch_t invert_color_force; switch_t invert_color_force;
/// Whether to blur window background. /// Whether to blur window background.
bool blur_background; bool blur_background;
/// Background state on last paint.
bool blur_background_last;
/// Whether to show black background /// Whether to show black background
bool show_black_background; bool show_black_background;
@ -1224,13 +1287,13 @@ extern session_t *ps_g;
static inline void static inline void
print_timestamp(session_t *ps); print_timestamp(session_t *ps);
#ifdef DEBUG_ALLOC_REG #ifdef DEBUG_BACKTRACE
#include <execinfo.h> #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. * Stolen from glibc manual.
*/ */
@ -1243,12 +1306,14 @@ print_backtrace(void) {
size = backtrace(array, BACKTRACE_SIZE); size = backtrace(array, BACKTRACE_SIZE);
strings = backtrace_symbols(array, 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]); printf ("%s\n", strings[i]);
free(strings); free(strings);
} }
#ifdef DEBUG_ALLOC_REG
/** /**
* Wrapper of <code>XFixesCreateRegion</code>, for debugging. * 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__) #define XFixesDestroyRegion(dpy, reg) XFixesDestroyRegion_(dpy, reg, __func__, __LINE__)
#endif #endif
#endif
// === Functions === // === Functions ===
/** /**
@ -1873,6 +1940,18 @@ bkend_use_glx(session_t *ps) {
|| BKEND_XR_GLX_HYBRID == ps->o.backend; || 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. * 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 static inline bool
win_is_fullscreen(session_t *ps, const win *w) { win_is_fullscreen(session_t *ps, const win *w) {
return rect_is_fullscreen(ps, w->a.x, w->a.y, w->widthb, w->heightb) 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 void
glx_destroy(session_t *ps); glx_destroy(session_t *ps);
bool
glx_reinit(session_t *ps, bool need_render);
void void
glx_on_root_change(session_t *ps); glx_on_root_change(session_t *ps);
bool bool
glx_init_blur(session_t *ps); 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 bool
glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap, glx_bind_pixmap(session_t *ps, glx_texture_t **pptex, Pixmap pixmap,
unsigned width, unsigned height, unsigned depth); 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); GLfloat factor, XserverRegion reg_tgt, const reg_data_t *pcache_reg);
bool bool
glx_render(session_t *ps, const glx_texture_t *ptex, glx_render_(session_t *ps, const glx_texture_t *ptex,
int x, int y, int dx, int dy, int width, int height, int z, int x, int y, int dx, int dy, int width, int height, int z,
double opacity, bool neg, double opacity, bool argb, bool neg,
XserverRegion reg_tgt, const reg_data_t *pcache_reg); 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 bool
glx_render_specified_color(session_t *ps, int color, int dx, int dy, int width, int height, int z, 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 void
glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg); glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg);
unsigned char *
glx_take_screenshot(session_t *ps, int *out_length);
#ifdef CONFIG_VSYNC_OPENGL_GLSL #ifdef CONFIG_VSYNC_OPENGL_GLSL
GLuint GLuint
glx_create_shader(GLenum shader_type, const char *shader_str); glx_create_shader(GLenum shader_type, const char *shader_str);
GLuint GLuint
glx_create_program(const GLuint * const shaders, int nshaders); 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 #endif
/** /**
@ -2147,7 +2265,7 @@ glx_create_program(const GLuint * const shaders, int nshaders);
static inline void static inline void
free_texture_r(session_t *ps, GLuint *ptexture) { free_texture_r(session_t *ps, GLuint *ptexture) {
if (*ptexture) { if (*ptexture) {
assert(ps->glx_context); assert(glx_has_context(ps));
glDeleteTextures(1, ptexture); glDeleteTextures(1, ptexture);
*ptexture = 0; *ptexture = 0;
} }
@ -2213,20 +2331,40 @@ free_texture(session_t *ps, glx_texture_t **pptex) {
assert(!*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. * Add a OpenGL debugging marker.
*/ */
static inline void static inline void
glx_mark_(session_t *ps, const char *func, XID xid, bool start) { glx_mark_(session_t *ps, const char *func, XID xid, bool start) {
#ifdef DEBUG_GLX_MARK #ifdef DEBUG_GLX_MARK
if (bkend_use_glx(ps) && ps->glStringMarkerGREMEDY) { if (glx_has_context(ps) && ps->psglx->glStringMarkerGREMEDY) {
if (!func) func = "(unknown)"; if (!func) func = "(unknown)";
const char *postfix = (start ? " (start)": " (end)"); const char *postfix = (start ? " (start)": " (end)");
char *str = malloc((strlen(func) + 12 + 2 char *str = malloc((strlen(func) + 12 + 2
+ strlen(postfix) + 5) * sizeof(char)); + strlen(postfix) + 5) * sizeof(char));
strcpy(str, func); strcpy(str, func);
sprintf(str + strlen(str), "(%#010lx)%s", xid, postfix); sprintf(str + strlen(str), "(%#010lx)%s", xid, postfix);
ps->glStringMarkerGREMEDY(strlen(str), str); ps->psglx->glStringMarkerGREMEDY(strlen(str), str);
free(str); free(str);
} }
#endif #endif
@ -2240,8 +2378,8 @@ glx_mark_(session_t *ps, const char *func, XID xid, bool start) {
static inline void static inline void
glx_mark_frame(session_t *ps) { glx_mark_frame(session_t *ps) {
#ifdef DEBUG_GLX_MARK #ifdef DEBUG_GLX_MARK
if (bkend_use_glx(ps) && ps->glFrameTerminatorGREMEDY) if (glx_has_context(ps) && ps->psglx->glFrameTerminatorGREMEDY)
ps->glFrameTerminatorGREMEDY(); ps->psglx->glFrameTerminatorGREMEDY();
#endif #endif
} }
@ -2388,6 +2526,28 @@ c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst,
#endif #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. * @brief Dump raw bytes in HEX format.
* *
@ -2423,3 +2583,4 @@ hexdump(const char *data, int len) {
fflush(stdout); 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_picture_argb, 0, 0, 0, 0, 0, 0,
shadow_image->width, shadow_image->height); shadow_image->width, shadow_image->height);
assert(!w->shadow_paint.pixmap);
w->shadow_paint.pixmap = shadow_pixmap_argb; w->shadow_paint.pixmap = shadow_pixmap_argb;
assert(!w->shadow_paint.pict);
w->shadow_paint.pict = shadow_picture_argb; w->shadow_paint.pict = shadow_picture_argb;
// Sync it once and only once // Sync it once and only once
xr_sync(ps, w->shadow_paint.pixmap, NULL); 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); XFreeGC(ps->dpy, gc);
XDestroyImage(shadow_image); XDestroyImage(shadow_image);
XFreePixmap(ps->dpy, shadow_pixmap); XFreePixmap(ps->dpy, shadow_pixmap);
XRenderFreePicture(ps->dpy, shadow_picture); XRenderFreePicture(ps->dpy, shadow_picture);
return success; return true;
shadow_picture_err: shadow_picture_err:
if (shadow_image) if (shadow_image)
@ -711,6 +711,9 @@ discard_ignore(session_t *ps, unsigned long sequence) {
static void static void
set_ignore(session_t *ps, unsigned long sequence) { set_ignore(session_t *ps, unsigned long sequence) {
if (ps->o.show_all_xerrors)
return;
ignore_t *i = malloc(sizeof(ignore_t)); ignore_t *i = malloc(sizeof(ignore_t));
if (!i) return; if (!i) return;
@ -779,6 +782,8 @@ wid_get_prop_adv(const session_t *ps, Window w, Atom atom, long offset,
*/ */
static void static void
win_rounded_corners(session_t *ps, win *w) { win_rounded_corners(session_t *ps, win *w) {
w->rounded_corners = false;
if (!w->bounding_shaped) if (!w->bounding_shaped)
return; return;
@ -808,11 +813,9 @@ win_rounded_corners(session_t *ps, win *w) {
for (i = 0; i < nrects; ++i) for (i = 0; i < nrects; ++i)
if (rects[i].width >= minwidth && rects[i].height >= minheight) { if (rects[i].width >= minwidth && rects[i].height >= minheight) {
w->rounded_corners = true; w->rounded_corners = true;
cxfree(rects); break;
return;
} }
w->rounded_corners = false;
cxfree(rects); cxfree(rects);
} }
@ -1257,6 +1260,14 @@ paint_preprocess(session_t *ps, win *list) {
free_region(ps, &w->reg_ignore); 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 // Update window opacity target and dim state if asked
if (WFLAG_OPCT_CHANGE & w->flags) { if (WFLAG_OPCT_CHANGE & w->flags) {
calc_opacity(ps, w); 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 // If the window is solid, we add the window region to the
// ignored region // ignored region
if (WMODE_SOLID == w->mode) { if (win_is_solid(ps, w)) {
if (!w->frame_opacity) { if (!w->frame_opacity) {
if (w->border_size) if (w->border_size)
w->reg_ignore = copy_region(ps, 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. // is not correctly set.
if (ps->o.unredir_if_possible && is_highest && to_paint) { if (ps->o.unredir_if_possible && is_highest && to_paint) {
is_highest = false; is_highest = false;
if (WMODE_SOLID == w->mode if (win_is_solid(ps, w)
&& (!w->frame_opacity || !win_has_frame(w)) && (!w->frame_opacity || !win_has_frame(w))
&& win_is_fullscreen(ps, w) && win_is_fullscreen(ps, w)
&& !w->unredir_if_possible_excluded) && !w->unredir_if_possible_excluded)
@ -1393,8 +1404,17 @@ paint_preprocess(session_t *ps, win *list) {
check_fade_fin(ps, w); check_fade_fin(ps, w);
} }
if (!destroyed) if (!destroyed) {
w->to_paint = to_paint; 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 static inline void
win_paint_shadow(session_t *ps, win *w, win_paint_shadow(session_t *ps, win *w,
XserverRegion reg_paint, const reg_data_t *pcache_reg) { 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)) { if (!paint_isvalid(ps, &w->shadow_paint)) {
printf_errf("(%#010lx): Missing painting data. This is a bad sign.", w->id); printf_errf("(%#010lx): Missing painting data. This is a bad sign.", w->id);
return; 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, render(ps, 0, 0, w->a.x + w->shadow_dx, w->a.y + w->shadow_dy,
w->shadow_width, w->shadow_height, w->shadow_opacity, true, false, w->shadow_width, w->shadow_height, w->shadow_opacity, true, false,
w->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; 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. * 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 // Minimize the region we try to blur, if the window itself is not
// opaque, only the frame is. // opaque, only the frame is.
XserverRegion reg_noframe = None; XserverRegion reg_noframe = None;
if (WMODE_SOLID == w->mode) { if (win_is_solid(ps, w)) {
XserverRegion reg_all = border_size(ps, w, false); XserverRegion reg_all = border_size(ps, w, false);
reg_noframe = win_get_region_noframe(ps, w, false); reg_noframe = win_get_region_noframe(ps, w, false);
XFixesSubtractRegion(ps->dpy, reg_noframe, reg_all, reg_noframe); 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 #ifdef CONFIG_VSYNC_OPENGL_GLSL
case BKEND_GLX: case BKEND_GLX:
// TODO: Handle frame opacity // 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); reg_paint, pcache_reg, &w->glx_blur_cache);
break; break;
#endif #endif
@ -1617,10 +1654,14 @@ win_blur_background(session_t *ps, win *w, Picture tgt_buffer,
} }
static void 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, double opacity, bool argb, bool neg,
Picture pict, glx_texture_t *ptex, 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) { switch (ps->o.backend) {
case BKEND_XRENDER: case BKEND_XRENDER:
case BKEND_XR_GLX_HYBRID: 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 #ifdef CONFIG_VSYNC_OPENGL
case BKEND_GLX: case BKEND_GLX:
glx_render(ps, ptex, x, y, dx, dy, wid, hei, glx_render(ps, ptex, x, y, dx, dy, wid, hei,
ps->glx_z, opacity, neg, reg_paint, pcache_reg); ps->psglx->z, opacity, argb, neg, reg_paint, pcache_reg, pprogram);
ps->glx_z += 1; ps->psglx->z += 1;
break; break;
#endif #endif
default: default:
@ -1818,7 +1859,7 @@ win_paint_win(session_t *ps, win *w, XserverRegion reg_paint,
break; break;
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
case BKEND_GLX: 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); reg_paint, pcache_reg);
break; break;
#endif #endif
@ -1942,7 +1983,7 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
// Painting shadow // Painting shadow
if (w->shadow) { if (w->shadow) {
// Lazy shadow building // Lazy shadow building
if (!paint_isvalid(ps, &w->shadow_paint)) if (!w->shadow_paint.pixmap)
win_build_shadow(ps, w, 1); win_build_shadow(ps, w, 1);
// Shadow is to be painted based on the ignore region of current // 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 // 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))) { || (ps->o.blur_background_frame && w->frame_opacity))) {
win_blur_background(ps, w, ps->tgt_buffer.pict, reg_paint, &cache_reg); 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 // effect
XSync(ps->dpy, False); XSync(ps->dpy, False);
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
if (ps->glx_context) { if (glx_has_context(ps)) {
if (ps->o.vsync_use_glfinish) if (ps->o.vsync_use_glfinish)
glFinish(); glFinish();
else else
@ -2152,7 +2193,8 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
glFlush(); glFlush();
glXWaitX(); glXWaitX();
glx_render(ps, ps->tgt_buffer.ptex, 0, 0, 0, 0, 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! // No break here!
case BKEND_GLX: case BKEND_GLX:
if (ps->o.glx_use_copysubbuffermesa) 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); XFlush(ps->dpy);
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
if (ps->glx_context) { if (glx_has_context(ps)) {
glFlush(); glFlush();
glXWaitX(); glXWaitX();
} }
@ -2678,9 +2720,21 @@ static void
win_determine_fade(session_t *ps, win *w) { win_determine_fade(session_t *ps, win *w) {
if (UNSET != w->fade_force) if (UNSET != w->fade_force)
w->fade = w->fade_force; w->fade = w->fade_force;
else if ((ps->o.no_fading_openclose && w->in_openclose) else if (ps->o.no_fading_opacitychange && (!w->in_openclose))
|| win_match(ps, w, ps->o.fade_blacklist, &w->cache_fblst) w->fade = false;
|| (ps->o.no_fading_opacitychange && (!w->in_openclose))) 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; w->fade = false;
else else
w->fade = ps->o.wintype_fade[w->window_type]; 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); win_update_shape_raw(ps, w);
// Shadow state could be changed win_on_factor_change(ps, w);
win_determine_shadow(ps, w);
/* /*
// If clear_shadow state on the window possibly changed, destroy the old // 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); 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 * Determine if a window should have shadow, and update things depending
* on shadow state. * on shadow state.
*/ */
static void static void
win_determine_shadow(session_t *ps, win *w) { win_determine_shadow(session_t *ps, win *w) {
bool shadow_old = w->shadow; bool shadow_new = w->shadow;
w->shadow = (UNSET == w->shadow_force ? if (UNSET != w->shadow_force)
(ps->o.wintype_shadow[w->window_type] shadow_new = w->shadow_force;
&& !win_match(ps, w, ps->o.shadow_blacklist, &w->cache_sblst) else if (IsViewable == w->a.map_state)
&& !(ps->o.shadow_ignore_shaped && w->bounding_shaped shadow_new = (ps->o.wintype_shadow[w->window_type]
&& !w->rounded_corners) && !win_match(ps, w, ps->o.shadow_blacklist, &w->cache_sblst)
&& !(ps->o.respect_prop_shadow && 0 == w->prop_shadow)) && !(ps->o.shadow_ignore_shaped && w->bounding_shaped
: w->shadow_force); && !w->rounded_corners)
&& !(ps->o.respect_prop_shadow && 0 == w->prop_shadow));
// Window extents need update on shadow state change win_set_shadow(ps, w, shadow_new);
if (w->shadow != shadow_old) { }
// Shadow geometry currently doesn't change on shadow state change
// calc_shadow_geometry(ps, w); static void
if (w->extents) { win_set_invert_color(session_t *ps, win *w, bool invert_color_new) {
// Mark the old extents as damaged if the shadow is removed if (w->invert_color == invert_color_new) return;
if (!w->shadow)
add_damage(ps, w->extents); w->invert_color = invert_color_new;
else
free_region(ps, &w->extents); add_damage_win(ps, w);
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);
}
}
} }
/** /**
@ -2793,19 +2863,27 @@ win_determine_shadow(session_t *ps, win *w) {
*/ */
static void static void
win_determine_invert_color(session_t *ps, win *w) { win_determine_invert_color(session_t *ps, win *w) {
// Do not change window invert color state when the window is unmapped, bool invert_color_new = w->invert_color;
// 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;
if (UNSET != w->invert_color_force) if (UNSET != w->invert_color_force)
w->invert_color = w->invert_color_force; invert_color_new = w->invert_color_force;
else else if (IsViewable == w->a.map_state)
w->invert_color = win_match(ps, w, ps->o.invert_color_list, &w->cache_ivclst); 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); add_damage_win(ps, w);
} }
@ -2814,16 +2892,13 @@ win_determine_invert_color(session_t *ps, win *w) {
*/ */
static void static void
win_determine_blur_background(session_t *ps, win *w) { 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); && !win_match(ps, w, ps->o.blur_background_blacklist, &w->cache_bbblst);
// Only consider window damaged if it's previously painted with background win_set_blur_background(ps, w, blur_background_new);
// 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);
} }
/** /**
@ -2831,6 +2906,10 @@ win_determine_blur_background(session_t *ps, win *w) {
*/ */
static void static void
win_update_opacity_rule(session_t *ps, win *w) { 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", // If long is 32-bit, unfortunately there's no way could we express "unset",
// so we just entirely don't distinguish "unset" and OPAQUE // so we just entirely don't distinguish "unset" and OPAQUE
opacity_t opacity = OPAQUE; opacity_t opacity = OPAQUE;
@ -2846,6 +2925,7 @@ win_update_opacity_rule(session_t *ps, win *w) {
else if (OPAQUE != w->opacity_set) else if (OPAQUE != w->opacity_set)
wid_rm_opacity_prop(ps, w->id); wid_rm_opacity_prop(ps, w->id);
w->opacity_set = opacity; w->opacity_set = opacity;
#endif
} }
/** /**
@ -2879,10 +2959,10 @@ win_on_factor_change(session_t *ps, win *w) {
win_determine_blur_background(ps, w); win_determine_blur_background(ps, w);
if (ps->o.opacity_rules) if (ps->o.opacity_rules)
win_update_opacity_rule(ps, w); 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->paint_excluded = win_match(ps, w, ps->o.paint_blacklist,
&w->cache_pblst); &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, w->unredir_if_possible_excluded = win_match(ps, w,
ps->o.unredir_if_possible_blacklist, &w->cache_uipblst); 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 static void
configure_win(session_t *ps, XConfigureEvent *ce) { configure_win(session_t *ps, XConfigureEvent *ce) {
// On root window changes // On root window changes
@ -3312,11 +3395,28 @@ configure_win(session_t *ps, XConfigureEvent *ce) {
rebuild_shadow_exclude_reg(ps); rebuild_shadow_exclude_reg(ps);
free_all_damage_last(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 #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) if (BKEND_GLX == ps->o.backend)
glx_on_root_change(ps); glx_on_root_change(ps);
#endif #endif
force_repaint(ps);
return; return;
} }
@ -3466,6 +3566,9 @@ destroy_win(session_t *ps, Window id) {
w->destroyed = true; w->destroyed = true;
if (ps->o.no_fading_destroyed_argb)
win_determine_fade(ps, w);
// Set fading callback // Set fading callback
set_fade_callback(ps, w, destroy_callback, false); set_fade_callback(ps, w, destroy_callback, false);
@ -3604,11 +3707,13 @@ xerror(Display __attribute__((unused)) *dpy, XErrorEvent *ev) {
{ {
char buf[BUF_LEN] = ""; char buf[BUF_LEN] = "";
XGetErrorText(ps->dpy, ev->error_code, 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->error_code, name, ev->request_code,
ev->minor_code, ev->serial, buf); ev->minor_code, ev->serial, buf);
} }
// print_backtrace();
return 0; return 0;
} }
@ -3659,7 +3764,7 @@ win_update_focused(session_t *ps, win *w) {
|| (ps->o.mark_wmwin_focused && w->wmwin) || (ps->o.mark_wmwin_focused && w->wmwin)
|| (ps->o.mark_ovredir_focused || (ps->o.mark_ovredir_focused
&& w->id == w->client_win && !w->wmwin) && 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; w->focused = true;
// If window grouping detection is enabled, mark the window active if // 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> * Determine whether we should respond to a <code>FocusIn/Out</code>
* event. * event.
*/ */
/*
inline static bool inline static bool
ev_focus_accept(XFocusChangeEvent *ev) { ev_focus_accept(XFocusChangeEvent *ev) {
return NotifyNormal == ev->mode || NotifyUngrab == ev->mode; return NotifyNormal == ev->mode || NotifyUngrab == ev->mode;
} }
*/
static inline void static inline void
ev_focus_in(session_t *ps, XFocusChangeEvent *ev) { ev_focus_in(session_t *ps, XFocusChangeEvent *ev) {
@ -4727,6 +4834,8 @@ usage(int ret) {
" Daemonize process.\n" " Daemonize process.\n"
"-S\n" "-S\n"
" Enable synchronous operation (for debugging).\n" " Enable synchronous operation (for debugging).\n"
"--show-all-xerrors\n"
" Show all X errors (for debugging).\n"
"-v\n" "-v\n"
" Print version Number and exit\\n" " Print version Number and exit\\n"
"--config path\n" "--config path\n"
@ -4755,13 +4864,21 @@ usage(int ret) {
" Mark windows that have no WM frame as active.\n" " Mark windows that have no WM frame as active.\n"
"--no-fading-openclose\n" "--no-fading-openclose\n"
" Do not fade on window open/close.\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" "--no-fading-opacitychange\n"
" Do not fade on window opacity change.\n" " Do not fade on window opacity change.\n"
"--shadow-ignore-shaped\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" "--detect-rounded-corners\n"
" Try to detect windows with rounded corners and don't consider\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-client-opacity\n"
" Detect _NET_WM_OPACITY on client windows, useful for window\n" " Detect _NET_WM_OPACITY on client windows, useful for window\n"
" managers not passing _NET_WM_OPACITY of client windows to frame\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" " 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" " 1.0 or changing based on opacity, depending on whether you have\n"
" --blur-background-fixed.\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" " --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" " Up to 4 blur kernels may be specified, separated with semicolon, for\n"
" multi-pass blur.\n" " multi-pass blur.\n"
@ -4919,7 +5036,8 @@ usage(int ret) {
"--glx-no-rebind-pixmap\n" "--glx-no-rebind-pixmap\n"
" GLX backend: Avoid rebinding pixmap on window damage. Probably\n" " GLX backend: Avoid rebinding pixmap on window damage. Probably\n"
" could improve performance on rapid window content changes, but is\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-swap-method undefined/copy/exchange/3/4/5/6/buffer-age\n"
" GLX backend: GLX buffer swap method we assume. Could be\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" " undefined (0), copy (1), exchange (2), 3-6, or buffer-age (-1).\n"
@ -4949,6 +5067,12 @@ usage(int ret) {
#else #else
#define WARNING #define WARNING
#endif #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" "--dbus\n"
" Enable remote control via D-Bus. See the D-BUS API section in the\n" " Enable remote control via D-Bus. See the D-BUS API section in the\n"
" man page for more details." WARNING "\n" " man page for more details." WARNING "\n"
@ -5011,7 +5135,8 @@ register_cm(session_t *ps) {
printf_errf("(): Failed to set COMPTON_VERSION."); 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; unsigned len = strlen(REGISTER_PROP) + 2;
int s = ps->scr; int s = ps->scr;
@ -5066,7 +5191,7 @@ fork_after(session_t *ps) {
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
// GLX context must be released and reattached on fork // 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."); printf_errf("(): Failed to detach GLx context.");
return false; return false;
} }
@ -5084,8 +5209,8 @@ fork_after(session_t *ps) {
setsid(); setsid();
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
if (ps->glx_context if (glx_has_context(ps)
&& !glXMakeCurrent(ps->dpy, get_tgt_window(ps), ps->glx_context)) { && !glXMakeCurrent(ps->dpy, get_tgt_window(ps), ps->psglx->context)) {
printf_errf("(): Failed to make GLX context current."); printf_errf("(): Failed to make GLX context current.");
return false; return false;
} }
@ -5399,6 +5524,7 @@ parse_geometry_end:
*/ */
static inline bool static inline bool
parse_rule_opacity(session_t *ps, const char *src) { parse_rule_opacity(session_t *ps, const char *src) {
#ifdef CONFIG_C2
// Find opacity value // Find opacity value
char *endptr = NULL; char *endptr = NULL;
long val = strtol(src, &endptr, 0); long val = strtol(src, &endptr, 0);
@ -5423,6 +5549,10 @@ parse_rule_opacity(session_t *ps, const char *src) {
// Parse pattern // Parse pattern
// I hope 1-100 is acceptable for (void *) // I hope 1-100 is acceptable for (void *)
return c2_parsed(ps, &ps->o.opacity_rules, endptr, (void *) val); 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 #ifdef CONFIG_LIBCONFIG
@ -5650,6 +5780,9 @@ parse_config(session_t *ps, struct options_tmp *pcfgtmp) {
wintype_arr_enable(ps->o.wintype_fade); wintype_arr_enable(ps->o.wintype_fade);
// --no-fading-open-close // --no-fading-open-close
lcfg_lookup_bool(&cfg, "no-fading-openclose", &ps->o.no_fading_openclose); 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 // --no-fading-opacitychange
lcfg_lookup_bool(&cfg, "no-fading-opacitychange", &ps->o.no_fading_opacitychange); lcfg_lookup_bool(&cfg, "no-fading-opacitychange", &ps->o.no_fading_opacitychange);
// --shadow-red // --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)) && !parse_conv_kern_lst(ps, sval, ps->o.blur_kerns, MAX_BLUR_PASS))
exit(1); exit(1);
// --resize-damage // --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 // --glx-no-stencil
lcfg_lookup_bool(&cfg, "glx-no-stencil", &ps->o.glx_no_stencil); lcfg_lookup_bool(&cfg, "glx-no-stencil", &ps->o.glx_no_stencil);
// --glx-copy-from-front // --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' }, { "shadow-offset-y", required_argument, NULL, 't' },
{ "fade-in-step", required_argument, NULL, 'I' }, { "fade-in-step", required_argument, NULL, 'I' },
{ "fade-out-step", required_argument, NULL, 'O' }, { "fade-out-step", required_argument, NULL, 'O' },
{ "fade-delta", required_argument, NULL, 'D' },
{ "menu-opacity", required_argument, NULL, 'm' }, { "menu-opacity", required_argument, NULL, 'm' },
{ "shadow", no_argument, NULL, 'c' }, { "shadow", no_argument, NULL, 'c' },
{ "no-dock-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' }, { "fading", no_argument, NULL, 'f' },
{ "inactive-opacity", required_argument, NULL, 'i' }, { "inactive-opacity", required_argument, NULL, 'i' },
{ "frame-opacity", required_argument, NULL, 'e' }, { "frame-opacity", required_argument, NULL, 'e' },
{ "daemon", no_argument, NULL, 'b' },
{ "no-dnd-shadow", no_argument, NULL, 'G' }, { "no-dnd-shadow", no_argument, NULL, 'G' },
{ "shadow-red", required_argument, NULL, 257 }, { "shadow-red", required_argument, NULL, 257 },
{ "shadow-green", required_argument, NULL, 258 }, { "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 }, { "vsync-use-glfinish", no_argument, NULL, 311 },
{ "xrender-sync", no_argument, NULL, 312 }, { "xrender-sync", no_argument, NULL, 312 },
{ "xrender-sync-fence", no_argument, NULL, 313 }, { "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 // Must terminate with a NULL entry
{ NULL, 0, NULL, 0 }, { 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); ps->o.display = mstrcpy(optarg);
else if ('S' == o) else if ('S' == o)
ps->o.synchronize = true; 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) else if ('?' == o || ':' == o)
usage(1); 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 'v': fprintf (stderr, "%s v%-3.2f\n", argv[0], _TDE_COMP_MGR_VERSION_); my_exit_code=0; exit (0);
case 'd': case 'd':
case 'S': case 'S':
case 314:
case 318:
case 320:
break; break;
P_CASELONG('D', fade_delta); P_CASELONG('D', fade_delta);
case 'I': 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(311, vsync_use_glfinish);
P_CASEBOOL(312, xrender_sync); P_CASEBOOL(312, xrender_sync);
P_CASEBOOL(313, xrender_sync_fence); 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: default:
usage(1); usage(1);
break; break;
@ -6416,13 +6579,13 @@ vsync_opengl_init(session_t *ps) {
return false; return false;
// Get video sync functions // Get video sync functions
if (!ps->glXGetVideoSyncSGI) if (!ps->psglx->glXGetVideoSyncSGI)
ps->glXGetVideoSyncSGI = (f_GetVideoSync) ps->psglx->glXGetVideoSyncSGI = (f_GetVideoSync)
glXGetProcAddress((const GLubyte *) "glXGetVideoSyncSGI"); glXGetProcAddress((const GLubyte *) "glXGetVideoSyncSGI");
if (!ps->glXWaitVideoSyncSGI) if (!ps->psglx->glXWaitVideoSyncSGI)
ps->glXWaitVideoSyncSGI = (f_WaitVideoSync) ps->psglx->glXWaitVideoSyncSGI = (f_WaitVideoSync)
glXGetProcAddress((const GLubyte *) "glXWaitVideoSyncSGI"); glXGetProcAddress((const GLubyte *) "glXWaitVideoSyncSGI");
if (!ps->glXWaitVideoSyncSGI || !ps->glXGetVideoSyncSGI) { if (!ps->psglx->glXWaitVideoSyncSGI || !ps->psglx->glXGetVideoSyncSGI) {
printf_errf("(): Failed to get glXWait/GetVideoSyncSGI function."); printf_errf("(): Failed to get glXWait/GetVideoSyncSGI function.");
return false; return false;
} }
@ -6441,13 +6604,13 @@ vsync_opengl_oml_init(session_t *ps) {
return false; return false;
// Get video sync functions // Get video sync functions
if (!ps->glXGetSyncValuesOML) if (!ps->psglx->glXGetSyncValuesOML)
ps->glXGetSyncValuesOML = (f_GetSyncValuesOML) ps->psglx->glXGetSyncValuesOML = (f_GetSyncValuesOML)
glXGetProcAddress ((const GLubyte *) "glXGetSyncValuesOML"); glXGetProcAddress ((const GLubyte *) "glXGetSyncValuesOML");
if (!ps->glXWaitForMscOML) if (!ps->psglx->glXWaitForMscOML)
ps->glXWaitForMscOML = (f_WaitForMscOML) ps->psglx->glXWaitForMscOML = (f_WaitForMscOML)
glXGetProcAddress ((const GLubyte *) "glXWaitForMscOML"); 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."); printf_errf("(): Failed to get OML_sync_control functions.");
return false; return false;
} }
@ -6471,14 +6634,14 @@ vsync_opengl_swc_init(session_t *ps) {
} }
// Get video sync functions // Get video sync functions
if (!ps->glXSwapIntervalProc) if (!ps->psglx->glXSwapIntervalProc)
ps->glXSwapIntervalProc = (f_SwapIntervalSGI) ps->psglx->glXSwapIntervalProc = (f_SwapIntervalSGI)
glXGetProcAddress ((const GLubyte *) "glXSwapIntervalSGI"); glXGetProcAddress ((const GLubyte *) "glXSwapIntervalSGI");
if (!ps->glXSwapIntervalProc) { if (!ps->psglx->glXSwapIntervalProc) {
printf_errf("(): Failed to get SGI_swap_control function."); printf_errf("(): Failed to get SGI_swap_control function.");
return false; return false;
} }
ps->glXSwapIntervalProc(1); ps->psglx->glXSwapIntervalProc(1);
return true; return true;
#else #else
@ -6499,14 +6662,14 @@ vsync_opengl_mswc_init(session_t *ps) {
} }
// Get video sync functions // Get video sync functions
if (!ps->glXSwapIntervalMESAProc) if (!ps->psglx->glXSwapIntervalMESAProc)
ps->glXSwapIntervalMESAProc = (f_SwapIntervalMESA) ps->psglx->glXSwapIntervalMESAProc = (f_SwapIntervalMESA)
glXGetProcAddress ((const GLubyte *) "glXSwapIntervalMESA"); glXGetProcAddress ((const GLubyte *) "glXSwapIntervalMESA");
if (!ps->glXSwapIntervalMESAProc) { if (!ps->psglx->glXSwapIntervalMESAProc) {
printf_errf("(): Failed to get MESA_swap_control function."); printf_errf("(): Failed to get MESA_swap_control function.");
return false; return false;
} }
ps->glXSwapIntervalMESAProc(1); ps->psglx->glXSwapIntervalMESAProc(1);
return true; return true;
#else #else
@ -6523,8 +6686,8 @@ static int
vsync_opengl_wait(session_t *ps) { vsync_opengl_wait(session_t *ps) {
unsigned vblank_count = 0; unsigned vblank_count = 0;
ps->glXGetVideoSyncSGI(&vblank_count); ps->psglx->glXGetVideoSyncSGI(&vblank_count);
ps->glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count); ps->psglx->glXWaitVideoSyncSGI(2, (vblank_count + 1) % 2, &vblank_count);
// I see some code calling glXSwapIntervalSGI(1) afterwards, is it required? // I see some code calling glXSwapIntervalSGI(1) afterwards, is it required?
return 0; return 0;
@ -6539,8 +6702,8 @@ static int
vsync_opengl_oml_wait(session_t *ps) { vsync_opengl_oml_wait(session_t *ps) {
int64_t ust = 0, msc = 0, sbc = 0; int64_t ust = 0, msc = 0, sbc = 0;
ps->glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc); ps->psglx->glXGetSyncValuesOML(ps->dpy, ps->reg_win, &ust, &msc, &sbc);
ps->glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2, ps->psglx->glXWaitForMscOML(ps->dpy, ps->reg_win, 0, 2, (msc + 1) % 2,
&ust, &msc, &sbc); &ust, &msc, &sbc);
return 0; return 0;
@ -6549,14 +6712,14 @@ vsync_opengl_oml_wait(session_t *ps) {
static void static void
vsync_opengl_swc_deinit(session_t *ps) { vsync_opengl_swc_deinit(session_t *ps) {
// The standard says it doesn't accept 0, but in fact it probably does // The standard says it doesn't accept 0, but in fact it probably does
if (ps->glx_context && ps->glXSwapIntervalProc) if (glx_has_context(ps) && ps->psglx->glXSwapIntervalProc)
ps->glXSwapIntervalProc(0); ps->psglx->glXSwapIntervalProc(0);
} }
static void static void
vsync_opengl_mswc_deinit(session_t *ps) { vsync_opengl_mswc_deinit(session_t *ps) {
if (ps->glx_context && ps->glXSwapIntervalMESAProc) if (glx_has_context(ps) && ps->psglx->glXSwapIntervalMESAProc)
ps->glXSwapIntervalMESAProc(0); ps->psglx->glXSwapIntervalMESAProc(0);
} }
#endif #endif
@ -6593,7 +6756,6 @@ void
vsync_deinit(session_t *ps) { vsync_deinit(session_t *ps) {
if (ps->o.vsync && VSYNC_FUNCS_DEINIT[ps->o.vsync]) if (ps->o.vsync && VSYNC_FUNCS_DEINIT[ps->o.vsync])
VSYNC_FUNCS_DEINIT[ps->o.vsync](ps); 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. * Initialize X composite overlay window.
*/ */
static void static bool
init_overlay(session_t *ps) { init_overlay(session_t *ps) {
ps->overlay = XCompositeGetOverlayWindow(ps->dpy, ps->root); ps->overlay = XCompositeGetOverlayWindow(ps->dpy, ps->root);
if (ps->overlay) { if (ps->overlay) {
@ -6661,6 +6823,11 @@ init_overlay(session_t *ps) {
"back to painting on root window.\n"); "back to painting on root window.\n");
ps->o.paint_on_overlay = false; 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, .backend = BKEND_XRENDER,
.glx_no_stencil = false, .glx_no_stencil = false,
.glx_copy_from_front = false, .glx_copy_from_front = false,
#ifdef CONFIG_VSYNC_OPENGL_GLSL
.glx_prog_win = GLX_PROG_MAIN_INIT,
#endif
.mark_wmwin_focused = false, .mark_wmwin_focused = false,
.mark_ovredir_focused = false, .mark_ovredir_focused = false,
.fork_after_register = 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_out_step = 0.03 * OPAQUE,
.fade_delta = 10, .fade_delta = 10,
.no_fading_openclose = false, .no_fading_openclose = false,
.no_fading_destroyed_argb = false,
.no_fading_opacitychange = false, .no_fading_opacitychange = false,
.fade_blacklist = NULL, .fade_blacklist = NULL,
@ -7187,15 +7358,6 @@ session_init(session_t *ps_old, int argc, char **argv) {
.drm_fd = -1, .drm_fd = -1,
#endif #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_event = 0,
.xfixes_error = 0, .xfixes_error = 0,
.damage_event = 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 // Allocate a session and copy default values into it
session_t *ps = malloc(sizeof(session_t)); session_t *ps = malloc(sizeof(session_t));
memcpy(ps, &s_def, 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_g = ps;
ps->ignore_tail = &ps->ignore_head; ps->ignore_tail = &ps->ignore_head;
gettimeofday(&ps->time_start, NULL); 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); 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; ps->has_name_pixmap = true;
} }
} }
@ -7450,6 +7605,17 @@ session_init(session_t *ps_old, int argc, char **argv) {
#endif #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 // Initialize software optimization
if (ps->o.sw_opti) if (ps->o.sw_opti)
ps->o.sw_opti = swopti_init(ps); ps->o.sw_opti = swopti_init(ps);
@ -7543,12 +7709,13 @@ session_init(session_t *ps_old, int argc, char **argv) {
cxfree(children); cxfree(children);
} }
if (ps->o.track_focus) { if (ps->o.track_focus) {
recheck_focus(ps); recheck_focus(ps);
} }
XUngrabServer(ps->dpy); XUngrabServer(ps->dpy);
// ALWAYS flush after XUngrabServer()!
XFlush(ps->dpy);
// Initialize DBus // Initialize DBus
if (ps->o.dbus) { if (ps->o.dbus) {
@ -7711,6 +7878,7 @@ session_destroy(session_t *ps) {
free(ps->pfds_read); free(ps->pfds_read);
free(ps->pfds_write); free(ps->pfds_write);
free(ps->pfds_except); free(ps->pfds_except);
free(ps->o.glx_fshader_win_str);
free_xinerama_info(ps); free_xinerama_info(ps);
#ifdef CONFIG_VSYNC_OPENGL #ifdef CONFIG_VSYNC_OPENGL
@ -7746,6 +7914,11 @@ session_destroy(session_t *ps) {
// Flush all events // Flush all events
XSync(ps->dpy, True); XSync(ps->dpy, True);
#ifdef DEBUG_XRC
// Report about resource leakage
xrc_report_xid();
#endif
// Free timeouts // Free timeouts
ps->tmout_unredir = NULL; ps->tmout_unredir = NULL;
timeout_clear(ps); timeout_clear(ps);
@ -7754,6 +7927,16 @@ session_destroy(session_t *ps) {
ps_g = NULL; 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. * Do the actual work.
* *

@ -273,7 +273,7 @@ free_reg_data(reg_data_t *pregd) {
*/ */
static inline void static inline void
free_paint(session_t *ps, paint_t *ppaint) { free_paint(session_t *ps, paint_t *ppaint) {
free_texture(ps, &ppaint->ptex); free_paint_glx(ps, ppaint);
free_picture(ps, &ppaint->pict); free_picture(ps, &ppaint->pict);
free_pixmap(ps, &ppaint->pixmap); free_pixmap(ps, &ppaint->pixmap);
} }
@ -292,6 +292,7 @@ free_wpaint(session_t *ps, win *w) {
*/ */
static inline void static inline void
free_win_res(session_t *ps, win *w) { free_win_res(session_t *ps, win *w) {
free_win_res_glx(ps, w);
free_region(ps, &w->extents); free_region(ps, &w->extents);
free_paint(ps, &w->paint); free_paint(ps, &w->paint);
free_region(ps, &w->border_size); 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_instance);
free(w->class_general); free(w->class_general);
free(w->role); 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 * static inline XTextProperty *
make_text_prop(session_t *ps, char *str) { 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)) { if (XmbTextListToTextProperty(ps->dpy, &str, 1, XStringStyle, pprop)) {
cxfree(pprop->value); cxfree(pprop->value);
@ -678,20 +676,37 @@ static win *
paint_preprocess(session_t *ps, win *list); paint_preprocess(session_t *ps, win *list);
static void 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, double opacity, bool argb, bool neg,
Picture pict, glx_texture_t *ptex, 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 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 dx = (w ? w->a.x: 0) + x;
const int dy = (w ? w->a.y: 0) + y; 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); const bool neg = (w && w->invert_color);
render(ps, x, y, dx, dy, wid, hei, opacity, argb, neg, 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 static inline void
@ -837,12 +852,21 @@ win_update_prop_shadow_raw(session_t *ps, win *w);
static void static void
win_update_prop_shadow(session_t *ps, win *w); win_update_prop_shadow(session_t *ps, win *w);
static void
win_set_shadow(session_t *ps, win *w, bool shadow_new);
static void static void
win_determine_shadow(session_t *ps, win *w); 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 static void
win_determine_invert_color(session_t *ps, win *w); 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 static void
win_determine_blur_background(session_t *ps, win *w); 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 static inline bool
ensure_glx_context(session_t *ps) { ensure_glx_context(session_t *ps) {
// Create GLX context // Create GLX context
if (!ps->glx_context) if (!glx_has_context(ps))
glx_init(ps, false); glx_init(ps, false);
return ps->glx_context; return ps->psglx->context;
} }
#endif #endif
@ -1254,7 +1278,7 @@ init_alpha_picts(session_t *ps);
static bool static bool
init_dbe(session_t *ps); init_dbe(session_t *ps);
static void static bool
init_overlay(session_t *ps); init_overlay(session_t *ps);
static void 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(fork_after_register, cdbus_reply_bool);
cdbus_m_opts_get_do(detect_rounded_corners, 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); 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, cdbus_reply_bool);
cdbus_m_opts_get_do(unredir_if_possible_delay, cdbus_reply_int32); cdbus_m_opts_get_do(unredir_if_possible_delay, cdbus_reply_int32);
cdbus_m_opts_get_do(redirected_force, cdbus_reply_enum); cdbus_m_opts_get_do(redirected_force, cdbus_reply_enum);

@ -15,15 +15,15 @@
void void
xr_glx_sync(session_t *ps, Drawable d, XSyncFence *pfence) { xr_glx_sync(session_t *ps, Drawable d, XSyncFence *pfence) {
if (*pfence) { if (*pfence) {
// GLsync sync = ps->glFenceSyncProc(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); // GLsync sync = ps->psglx->glFenceSyncProc(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
GLsync sync = ps->glImportSyncEXT(GL_SYNC_X11_FENCE_EXT, *pfence, 0); GLsync sync = ps->psglx->glImportSyncEXT(GL_SYNC_X11_FENCE_EXT, *pfence, 0);
/* GLenum ret = ps->glClientWaitSyncProc(sync, GL_SYNC_FLUSH_COMMANDS_BIT, /* GLenum ret = ps->psglx->glClientWaitSyncProc(sync, GL_SYNC_FLUSH_COMMANDS_BIT,
1000); 1000);
assert(GL_CONDITION_SATISFIED == ret); */ assert(GL_CONDITION_SATISFIED == ret); */
XSyncTriggerFence(ps->dpy, *pfence); XSyncTriggerFence(ps->dpy, *pfence);
XFlush(ps->dpy); XFlush(ps->dpy);
ps->glWaitSyncProc(sync, 0, GL_TIMEOUT_IGNORED); ps->psglx->glWaitSyncProc(sync, 0, GL_TIMEOUT_IGNORED);
// ps->glDeleteSyncProc(sync); // ps->psglx->glDeleteSyncProc(sync);
// XSyncResetFence(ps->dpy, *pfence); // XSyncResetFence(ps->dpy, *pfence);
} }
glx_check_err(ps); 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")) if (need_render && !glx_hasglxext(ps, "GLX_EXT_texture_from_pixmap"))
goto glx_init_end; 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 // Get GLX context
#ifndef DEBUG_GLX_DEBUG_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 #else
{ {
GLXFBConfig fbconfig = get_fbconfig_from_visualinfo(ps, pvis); 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, GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
None None
}; };
ps->glx_context = p_glXCreateContextAttribsARB(ps->dpy, fbconfig, NULL, psglx->context = p_glXCreateContextAttribsARB(ps->dpy, fbconfig, NULL,
GL_TRUE, attrib_list); GL_TRUE, attrib_list);
} }
#endif #endif
if (!ps->glx_context) { if (!psglx->context) {
printf_errf("(): Failed to get GLX context."); printf_errf("(): Failed to get GLX context.");
goto glx_init_end; goto glx_init_end;
} }
// Attach GLX context // 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."); printf_errf("(): Failed to attach GLX context.");
goto glx_init_end; 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 // Check GL_ARB_texture_non_power_of_two, requires a GLX context and
// must precede FBConfig fetching // must precede FBConfig fetching
if (need_render) 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"); "GL_ARB_texture_non_power_of_two");
// Acquire function addresses // Acquire function addresses
if (need_render) { if (need_render) {
#ifdef DEBUG_GLX_MARK #ifdef DEBUG_GLX_MARK
ps->glStringMarkerGREMEDY = (f_StringMarkerGREMEDY) psglx->glStringMarkerGREMEDY = (f_StringMarkerGREMEDY)
glXGetProcAddress((const GLubyte *) "glStringMarkerGREMEDY"); glXGetProcAddress((const GLubyte *) "glStringMarkerGREMEDY");
ps->glFrameTerminatorGREMEDY = (f_FrameTerminatorGREMEDY) psglx->glFrameTerminatorGREMEDY = (f_FrameTerminatorGREMEDY)
glXGetProcAddress((const GLubyte *) "glFrameTerminatorGREMEDY"); glXGetProcAddress((const GLubyte *) "glFrameTerminatorGREMEDY");
#endif #endif
ps->glXBindTexImageProc = (f_BindTexImageEXT) psglx->glXBindTexImageProc = (f_BindTexImageEXT)
glXGetProcAddress((const GLubyte *) "glXBindTexImageEXT"); glXGetProcAddress((const GLubyte *) "glXBindTexImageEXT");
ps->glXReleaseTexImageProc = (f_ReleaseTexImageEXT) psglx->glXReleaseTexImageProc = (f_ReleaseTexImageEXT)
glXGetProcAddress((const GLubyte *) "glXReleaseTexImageEXT"); glXGetProcAddress((const GLubyte *) "glXReleaseTexImageEXT");
if (!ps->glXBindTexImageProc || !ps->glXReleaseTexImageProc) { if (!psglx->glXBindTexImageProc || !psglx->glXReleaseTexImageProc) {
printf_errf("(): Failed to acquire glXBindTexImageEXT() / glXReleaseTexImageEXT()."); printf_errf("(): Failed to acquire glXBindTexImageEXT() / glXReleaseTexImageEXT().");
goto glx_init_end; goto glx_init_end;
} }
if (ps->o.glx_use_copysubbuffermesa) { if (ps->o.glx_use_copysubbuffermesa) {
ps->glXCopySubBufferProc = (f_CopySubBuffer) psglx->glXCopySubBufferProc = (f_CopySubBuffer)
glXGetProcAddress((const GLubyte *) "glXCopySubBufferMESA"); glXGetProcAddress((const GLubyte *) "glXCopySubBufferMESA");
if (!ps->glXCopySubBufferProc) { if (!psglx->glXCopySubBufferProc) {
printf_errf("(): Failed to acquire glXCopySubBufferMESA()."); printf_errf("(): Failed to acquire glXCopySubBufferMESA().");
goto glx_init_end; goto glx_init_end;
} }
} }
#ifdef CONFIG_GLX_SYNC #ifdef CONFIG_GLX_SYNC
ps->glFenceSyncProc = (f_FenceSync) psglx->glFenceSyncProc = (f_FenceSync)
glXGetProcAddress((const GLubyte *) "glFenceSync"); glXGetProcAddress((const GLubyte *) "glFenceSync");
ps->glIsSyncProc = (f_IsSync) psglx->glIsSyncProc = (f_IsSync)
glXGetProcAddress((const GLubyte *) "glIsSync"); glXGetProcAddress((const GLubyte *) "glIsSync");
ps->glDeleteSyncProc = (f_DeleteSync) psglx->glDeleteSyncProc = (f_DeleteSync)
glXGetProcAddress((const GLubyte *) "glDeleteSync"); glXGetProcAddress((const GLubyte *) "glDeleteSync");
ps->glClientWaitSyncProc = (f_ClientWaitSync) psglx->glClientWaitSyncProc = (f_ClientWaitSync)
glXGetProcAddress((const GLubyte *) "glClientWaitSync"); glXGetProcAddress((const GLubyte *) "glClientWaitSync");
ps->glWaitSyncProc = (f_WaitSync) psglx->glWaitSyncProc = (f_WaitSync)
glXGetProcAddress((const GLubyte *) "glWaitSync"); glXGetProcAddress((const GLubyte *) "glWaitSync");
ps->glImportSyncEXT = (f_ImportSyncEXT) psglx->glImportSyncEXT = (f_ImportSyncEXT)
glXGetProcAddress((const GLubyte *) "glImportSyncEXT"); glXGetProcAddress((const GLubyte *) "glImportSyncEXT");
if (!ps->glFenceSyncProc || !ps->glIsSyncProc || !ps->glDeleteSyncProc if (!psglx->glFenceSyncProc || !psglx->glIsSyncProc || !psglx->glDeleteSyncProc
|| !ps->glClientWaitSyncProc || !ps->glWaitSyncProc || !psglx->glClientWaitSyncProc || !psglx->glWaitSyncProc
|| !ps->glImportSyncEXT) { || !psglx->glImportSyncEXT) {
printf_errf("(): Failed to acquire GLX sync functions."); printf_errf("(): Failed to acquire GLX sync functions.");
goto glx_init_end; goto glx_init_end;
} }
@ -260,33 +278,86 @@ glx_init_end:
return success; 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. * Destroy GLX related resources.
*/ */
void void
glx_destroy(session_t *ps) { 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 #ifdef CONFIG_VSYNC_OPENGL_GLSL
// Free GLSL shaders/programs // Free GLSL shaders/programs
for (int i = 0; i < MAX_BLUR_PASS; ++i) { 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) if (ppass->frag_shader)
glDeleteShader(ppass->frag_shader); glDeleteShader(ppass->frag_shader);
if (ppass->prog) if (ppass->prog)
glDeleteProgram(ppass->prog); glDeleteProgram(ppass->prog);
} }
glx_free_prog_main(ps, &ps->o.glx_prog_win);
glx_check_err(ps);
#endif #endif
// Free FBConfigs // Free FBConfigs
for (int i = 0; i <= OPENGL_MAX_DEPTH; ++i) { for (int i = 0; i <= OPENGL_MAX_DEPTH; ++i) {
free(ps->glx_fbconfigs[i]); free(ps->psglx->fbconfigs[i]);
ps->glx_fbconfigs[i] = NULL; ps->psglx->fbconfigs[i] = NULL;
} }
// Destroy GLX context // Destroy GLX context
if (ps->glx_context) { if (ps->psglx->context) {
glXDestroyContext(ps->dpy, ps->glx_context); glXDestroyContext(ps->dpy, ps->psglx->context);
ps->glx_context = NULL; 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" " gl_FragColor = sum / (factor_center + float(%.7g));\n"
"}\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 ? const char *sampler_type = (use_texture_rect ?
"sampler2DRect": "sampler2D"); "sampler2DRect": "sampler2D");
const char *texture_func = (use_texture_rect ? const char *texture_func = (use_texture_rect ?
@ -375,7 +446,7 @@ glx_init_blur(session_t *ps) {
if (!kern) if (!kern)
break; break;
glx_blur_pass_t *ppass = &ps->glx_blur_passes[i]; glx_blur_pass_t *ppass = &ps->psglx->blur_passes[i];
// Build shader // 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_x", unifm_offset_x);
P_GET_UNIFM_LOC("offset_y", unifm_offset_y); P_GET_UNIFM_LOC("offset_y", unifm_offset_y);
} }
#undef P_GET_UNIFM_LOC #undef P_GET_UNIFM_LOC
} }
free(extension); free(extension);
@ -459,6 +531,43 @@ glx_init_blur(session_t *ps) {
#endif #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. * @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; return;
// Compare new FBConfig with current one // 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 #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 #endif
if (!ps->glx_fbconfigs[depth]) { if (!ps->psglx->fbconfigs[depth]) {
ps->glx_fbconfigs[depth] = malloc(sizeof(glx_fbconfig_t)); ps->psglx->fbconfigs[depth] = malloc(sizeof(glx_fbconfig_t));
allocchk(ps->glx_fbconfigs[depth]); 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); cxfree(pfbcfgs);
// Sanity checks // 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); printf_errf("(): No FBConfig found for default depth %d.", ps->depth);
return false; return false;
} }
if (!ps->glx_fbconfigs[32]) { if (!ps->psglx->fbconfigs[32]) {
printf_errf("(): No FBConfig found for depth 32. Expect crazy things."); printf_errf("(): No FBConfig found for depth 32. Expect crazy things.");
} }
#ifdef DEBUG_GLX #ifdef DEBUG_GLX
printf_dbgf("(): %d-bit: %#3x, 32-bit: %#3x\n", printf_dbgf("(): %d-bit: %#3x, 32-bit: %#3x\n",
ps->depth, (int) ps->glx_fbconfigs[ps->depth]->cfg, ps->depth, (int) ps->psglx->fbconfigs[ps->depth]->cfg,
(int) ps->glx_fbconfigs[32]->cfg); (int) ps->psglx->fbconfigs[32]->cfg);
#endif #endif
return true; 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) { if (!pcfg) {
printf_errf("(%d): Couldn't find FBConfig with requested depth.", depth); printf_errf("(%d): Couldn't find FBConfig with requested depth.", depth);
return false; 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 // pixmap-specific parameters, and this may change in the future
GLenum tex_tgt = 0; GLenum tex_tgt = 0;
if (GLX_TEXTURE_2D_BIT_EXT & pcfg->texture_tgts 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; tex_tgt = GLX_TEXTURE_2D_EXT;
else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & pcfg->texture_tgts) else if (GLX_TEXTURE_RECTANGLE_BIT_EXT & pcfg->texture_tgts)
tex_tgt = GLX_TEXTURE_RECTANGLE_EXT; 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... // The specification requires rebinding whenever the content changes...
// We can't follow this, too slow. // We can't follow this, too slow.
if (need_release) 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 // Cleanup
glBindTexture(ptex->target, 0); glBindTexture(ptex->target, 0);
@ -772,7 +881,7 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
// Release binding // Release binding
if (ptex->glpixmap && ptex->texture) { if (ptex->glpixmap && ptex->texture) {
glBindTexture(ptex->target, 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); glBindTexture(ptex->target, 0);
} }
@ -790,7 +899,7 @@ glx_release_pixmap(session_t *ps, glx_texture_t *ptex) {
*/ */
void void
glx_paint_pre(session_t *ps, XserverRegion *preg) { 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); // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Get buffer age // 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, GLfloat factor_center,
XserverRegion reg_tgt, const reg_data_t *pcache_reg, XserverRegion reg_tgt, const reg_data_t *pcache_reg,
glx_blur_cache_t *pbc) { glx_blur_cache_t *pbc) {
assert(ps->glx_blur_passes[0].prog); assert(ps->psglx->blur_passes[0].prog);
const bool more_passes = ps->glx_blur_passes[1].prog; const bool more_passes = ps->psglx->blur_passes[1].prog;
const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST); const bool have_scissors = glIsEnabled(GL_SCISSOR_TEST);
const bool have_stencil = glIsEnabled(GL_STENCIL_TEST); const bool have_stencil = glIsEnabled(GL_STENCIL_TEST);
bool ret = false; 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; 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; tex_tgt = GL_TEXTURE_2D;
// Free textures if size inconsistency discovered // 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; bool last_pass = false;
for (int i = 0; !last_pass; ++i) { 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); 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(ppass->prog);
assert(tex_scr); 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. * @brief Render a region with texture data.
*/ */
bool bool
glx_render(session_t *ps, const glx_texture_t *ptex, glx_render_(session_t *ps, const glx_texture_t *ptex,
int x, int y, int dx, int dy, int width, int height, int z, int x, int y, int dx, int dy, int width, int height, int z,
double opacity, bool neg, double opacity, bool argb, bool neg,
XserverRegion reg_tgt, const reg_data_t *pcache_reg) { 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) { if (!ptex || !ptex->texture) {
printf_errf("(): Missing texture."); printf_errf("(): Missing texture.");
return false; return false;
@ -1329,8 +1442,11 @@ glx_render(session_t *ps, const glx_texture_t *ptex,
return true; return true;
#endif #endif
const bool argb = (GLX_TEXTURE_FORMAT_RGBA_EXT == argb = argb || (GLX_TEXTURE_FORMAT_RGBA_EXT ==
ps->glx_fbconfigs[ptex->depth]->texture_fmt); ps->psglx->fbconfigs[ptex->depth]->texture_fmt);
#ifdef CONFIG_VSYNC_OPENGL_GLSL
const bool has_prog = pprogram && pprogram->prog;
#endif
bool dual_texture = false; bool dual_texture = false;
// It's required by legacy versions of OpenGL to enable texture target // 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); glColor4f(opacity, opacity, opacity, opacity);
} }
// Color negation #ifdef CONFIG_VSYNC_OPENGL_GLSL
if (neg) { if (!has_prog)
// Simple color negation #endif
if (!glIsEnabled(GL_BLEND)) { {
glEnable(GL_COLOR_LOGIC_OP); // Color negation
glLogicOp(GL_COPY_INVERTED); if (neg) {
} // Simple color negation
// ARGB texture color negation if (!glIsEnabled(GL_BLEND)) {
else if (argb) { glEnable(GL_COLOR_LOGIC_OP);
dual_texture = true; glLogicOp(GL_COPY_INVERTED);
}
// Use two texture stages because the calculation is too complicated, // ARGB texture color negation
// thanks to madsy for providing code else if (argb) {
// Texture stage 0 dual_texture = true;
glActiveTexture(GL_TEXTURE0);
// Use two texture stages because the calculation is too complicated,
// Negation for premultiplied color: color = A - C // thanks to madsy for providing code
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); // Texture stage 0
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT); glActiveTexture(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA); // Negation for premultiplied color: color = A - C
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
// Pass texture alpha through glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
// Pass texture alpha through
// Texture stage 1 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glActiveTexture(GL_TEXTURE1); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glEnable(ptex->target); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glBindTexture(ptex->target, ptex->texture);
// Texture stage 1
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glActiveTexture(GL_TEXTURE1);
glEnable(ptex->target);
// Modulation with constant factor glBindTexture(ptex->target, ptex->texture);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR); // Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
// Modulation with constant factor glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR); // Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
glActiveTexture(GL_TEXTURE0); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
} glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
// RGB blend color negation glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
else {
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glActiveTexture(GL_TEXTURE0);
}
// Modulation with constant factor // RGB blend color negation
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); else {
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR); // Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
// Modulation with constant factor glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR); // Modulation with constant factor
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); 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 #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); 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); glActiveTexture(GL_TEXTURE0);
} }
#ifdef CONFIG_VSYNC_OPENGL_GLSL
if (has_prog)
glUseProgram(0);
#endif
glx_check_err(ps); glx_check_err(ps);
return true; return true;
@ -1641,7 +1780,7 @@ glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg) {
#ifdef DEBUG_GLX #ifdef DEBUG_GLX
printf_dbgf("(): %d, %d, %d, %d\n", x, y, wid, hei); printf_dbgf("(): %d, %d, %d, %d\n", x, y, wid, hei);
#endif #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); 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 #ifdef CONFIG_VSYNC_OPENGL_GLSL
GLuint GLuint
glx_create_shader(GLenum shader_type, const char *shader_str) { 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; bool success = false;
GLuint shader = glCreateShader(shader_type); GLuint shader = glCreateShader(shader_type);
if (!shader) { 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; goto glx_create_shader_end;
} }
glShaderSource(shader, 1, &shader_str, NULL); glShaderSource(shader, 1, &shader_str, NULL);
@ -1737,5 +1902,40 @@ glx_create_program_end:
return program; 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 #endif

@ -41,10 +41,10 @@ glx_dump_err_str(GLenum err) {
*/ */
static inline void static inline void
glx_check_err_(session_t *ps, const char *func, int line) { 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; GLenum err = GL_NO_ERROR;
while (GL_NO_ERROR != (err = glGetError())) { while (GL_NO_ERROR != (err = glGetError())) {
print_timestamp(ps); print_timestamp(ps);
printf("%s():%d: GLX error ", func, line); 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