Skip to content

Instantly share code, notes, and snippets.

@richardgv
Created August 22, 2013 06:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richardgv/6303981 to your computer and use it in GitHub Desktop.
Save richardgv/6303981 to your computer and use it in GitHub Desktop.
chjj/compton #137: Untested --xinerama-shadow-crop patch
diff --git a/Makefile b/Makefile
index 9acba9d..655c77d 100644
--- a/Makefile
+++ b/Makefile
@@ -17,6 +17,12 @@ OBJS = compton.o
# === Configuration flags ===
CFG = -std=c99
+# ==== Xinerama ====
+ifeq "$(NO_XINERAMA)" ""
+ CFG += -DCONFIG_XINERAMA
+ PACKAGES += xinerama
+endif
+
# ==== libconfig ====
ifeq "$(NO_LIBCONFIG)" ""
CFG += -DCONFIG_LIBCONFIG
diff --git a/src/common.h b/src/common.h
index bf0b480..f90cba7 100644
--- a/src/common.h
+++ b/src/common.h
@@ -85,6 +85,10 @@
#include <X11/extensions/Xrandr.h>
#include <X11/extensions/Xdbe.h>
+#ifdef CONFIG_XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+
// Workarounds for missing definitions in very old versions of X headers,
// thanks to consolers for reporting
#ifndef PictOpDifference
@@ -506,6 +510,8 @@ typedef struct {
bool shadow_ignore_shaped;
/// Whether to respect _COMPTON_SHADOW.
bool respect_prop_shadow;
+ /// Whether to crop shadow to the very Xinerama screen.
+ bool xinerama_shadow_crop;
// === Fading ===
/// Enable/disable fading for specific window types.
@@ -806,6 +812,16 @@ typedef struct {
#endif
/// Whether X DBE extension exists.
bool dbe_exists;
+#ifdef CONFIG_XINERAMA
+ /// Whether X Xinerama extension exists.
+ bool xinerama_exists;
+ /// Xinerama screen info.
+ XineramaScreenInfo *xinerama_scrs;
+ /// Xinerama screen regions.
+ XserverRegion *xinerama_scr_regs;
+ /// Number of Xinerama screens.
+ int xinerama_nscrs;
+#endif
/// Whether X Render convolution filter exists.
bool xrfilter_convolution_exists;
@@ -861,6 +877,10 @@ typedef struct _win {
Window id;
/// Window attributes.
XWindowAttributes a;
+#ifdef CONFIG_XINERAMA
+ /// Xinerama screen this window is on.
+ int xinerama_scr;
+#endif
/// Window visual pict format;
XRenderPictFormat *pictfmt;
/// Window painting mode.
@@ -1107,12 +1127,13 @@ XFixesDestroyRegion_(Display *dpy, XserverRegion reg,
/**
* @brief Quit if the passed-in pointer is empty.
*/
-static inline void
+static inline void *
allocchk_(const char *func_name, void *ptr) {
if (!ptr) {
printf_err("%s(): Failed to allocate memory.", func_name);
exit(1);
}
+ return ptr;
}
/// @brief Wrapper of allocchk_().
diff --git a/src/compton.c b/src/compton.c
index 474d2a2..eebe77d 100644
--- a/src/compton.c
+++ b/src/compton.c
@@ -1817,6 +1817,12 @@ paint_all(session_t *ps, XserverRegion region, XserverRegion region_real, win *t
if (ps->o.clear_shadow && w->border_size)
XFixesSubtractRegion(ps->dpy, reg_paint, reg_paint, w->border_size);
+#ifdef CONFIG_XINERAMA
+ if (ps->o.xinerama_shadow_crop && w->xinerama_scr >= 0)
+ XFixesIntersectRegion(ps->dpy, reg_paint, reg_paint,
+ ps->xinerama_scr_regs[w->xinerama_scr]);
+#endif
+
// Detect if the region is empty before painting
{
reg_data_t cache_reg = REG_DATA_INIT;
@@ -2035,6 +2041,8 @@ map_win(session_t *ps, Window id) {
w->a.map_state = IsViewable;
+ cxinerama_win_upd_scr(ps, w);
+
// Set focused to false
bool focused_real = false;
if (ps->o.track_focus && ps->o.use_ewmh_active_win
@@ -2677,6 +2685,9 @@ add_win(session_t *ps, Window id, Window prev) {
.id = None,
.a = { },
+#ifdef CONFIG_XINERAMA
+ .xinerama_scr = -1,
+#endif
.pictfmt = NULL,
.mode = WMODE_TRANS,
.damaged = false,
@@ -2960,6 +2971,7 @@ configure_win(session_t *ps, XConfigureEvent *ce) {
factor_change = true;
free_region(ps, &w->extents);
free_region(ps, &w->border_size);
+ cxinerama_win_upd_scr(ps, w);
}
w->a.x = ce->x;
@@ -4417,6 +4429,15 @@ usage(int ret) {
" should not be painted in, such as a dock window region.\n"
" Use --shadow-exclude-reg \'x10+0-0\', for example, if the 10 pixels\n"
" on the bottom of the screen should not have shadows painted on.\n"
+#undef WARNING
+#ifndef CONFIG_XINERAMA
+#define WARNING WARNING_DISABLED
+#else
+#define WARNING
+#endif
+ "--xinerama-shadow-crop\n"
+ " Crop shadow of a window fully on a particular Xinerama screen to the\n"
+ " screen." WARNING "\n"
"--backend backend\n"
" Choose backend. Possible choices are xrender and glx" WARNING ".\n"
"--glx-no-stencil\n"
@@ -5245,6 +5266,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
{ "opacity-rule", required_argument, NULL, 304 },
{ "shadow-exclude-reg", required_argument, NULL, 305 },
{ "paint-exclude", required_argument, NULL, 306 },
+ { "xinerama-shadow-crop", no_argument, NULL, 307 },
// Must terminate with a NULL entry
{ NULL, 0, NULL, 0 },
};
@@ -5492,6 +5514,7 @@ get_cfg(session_t *ps, int argc, char *const *argv, bool first_pass) {
// --paint-exclude
condlst_add(ps, &ps->o.paint_blacklist, optarg);
break;
+ P_CASEBOOL(307, xinerama_shadow_crop);
default:
usage(1);
break;
@@ -6343,6 +6366,35 @@ mainloop(session_t *ps) {
return true;
}
+#ifdef CONFIG_XINERAMA
+static void
+cxinerama_upd_scrs(session_t *ps) {
+ free_xinerama_info(ps);
+
+ if (!ps->o.xinerama_shadow_crop || !ps->xinerama_exists) return;
+
+ if (!XineramaIsActive(ps->dpy)) return;
+
+ ps->xinerama_scrs = XineramaQueryScreens(ps->dpy, &ps->xinerama_nscrs);
+
+ // Just in case the shit hits the fan...
+ if (!ps->xinerama_nscrs) {
+ cxfree(ps->xinerama_scrs);
+ ps->xinerama_scrs = NULL;
+ return;
+ }
+
+ ps->xinerama_scr_regs = allocchk(malloc(sizeof(XserverRegion *)
+ * ps->xinerama_nscrs));
+ for (int i = 0; i < ps->xinerama_nscrs; ++i) {
+ const XineramaScreenInfo * const s = &ps->xinerama_scrs[i];
+ XRectangle r = { .x = s->x_org, .y = s->y_org,
+ .width = s->width, .height = s->height };
+ ps->xinerama_scr_regs[i] = XFixesCreateRegion(ps->dpy, &r, 1);
+ }
+}
+#endif
+
/**
* Initialize a session.
*
@@ -6409,6 +6461,7 @@ session_init(session_t *ps_old, int argc, char **argv) {
.shadow_blacklist = NULL,
.shadow_ignore_shaped = false,
.respect_prop_shadow = false,
+ .xinerama_shadow_crop = false,
.wintype_fade = { false },
.fade_in_step = 0.028 * OPAQUE,
@@ -6663,6 +6716,17 @@ session_init(session_t *ps_old, int argc, char **argv) {
ps->o.dbe = false;
}
+ // Query X Xinerama extension
+ if (ps->o.xinerama_shadow_crop) {
+#ifdef CONFIG_XINERAMA
+ int xinerama_event = 0, xinerama_error = 0;
+ if (!XineramaQueryExtension(ps->dpy, &xinerama_event, &xinerama_error))
+ ps->o.xinerama_shadow_crop = false;
+#else
+ printf_errf("(): Xinerama support not compiled in.");
+#endif
+ }
+
rebuild_screen_reg(ps);
// Overlay must be initialized before double buffer, and before creation
@@ -6923,6 +6987,7 @@ session_destroy(session_t *ps) {
free(ps->pfds_read);
free(ps->pfds_write);
free(ps->pfds_except);
+ free_xinerama_info(ps);
#ifdef CONFIG_VSYNC_OPENGL
glx_destroy(ps);
diff --git a/src/compton.h b/src/compton.h
index c0773db..f4a7ef9 100644
--- a/src/compton.h
+++ b/src/compton.h
@@ -193,6 +193,23 @@ free_wincondlst(c2_lptr_t **pcondlst) {
}
/**
+ * Free Xinerama screen info.
+ */
+static inline void
+free_xinerama_info(session_t *ps) {
+#ifdef CONFIG_XINERAMA
+ if (ps->xinerama_scr_regs) {
+ for (int i = 0; i < ps->xinerama_nscrs; ++i)
+ free_region(ps, &ps->xinerama_scr_regs[i]);
+ free(ps->xinerama_scr_regs);
+ }
+ cxfree(ps->xinerama_scrs);
+ ps->xinerama_scrs = NULL;
+ ps->xinerama_nscrs = 0;
+#endif
+}
+
+/**
* Check whether a paint_t contains enough data.
*/
static inline bool
@@ -1191,6 +1208,31 @@ timeout_clear(session_t *ps);
static bool
mainloop(session_t *ps);
+#ifdef CONFIG_XINERAMA
+static void
+cxinerama_upd_scrs(session_t *ps);
+#endif
+
+/**
+ * Get the Xinerama screen a window is on.
+ *
+ * Return an index >= 0, or -1 if not found.
+ */
+static inline void
+cxinerama_win_upd_scr(session_t *ps, win *w) {
+#ifdef CONFIG_XINERAMA
+ w->xinerama_scr = -1;
+ for (XineramaScreenInfo *s = ps->xinerama_scrs;
+ s < ps->xinerama_scrs + ps->xinerama_nscrs; ++s)
+ if (s->x_org <= w->a.x && s->y_org <= w->a.y
+ && s->x_org + s->width >= w->a.x + w->widthb
+ && s->y_org + s->height >= w->a.y + w->heightb) {
+ w->xinerama_scr = s - ps->xinerama_scrs;
+ return;
+ }
+#endif
+}
+
static session_t *
session_init(session_t *ps_old, int argc, char **argv);
diff --git a/src/dbus.c b/src/dbus.c
index 671ef8e..8f53eee 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -926,6 +926,7 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
cdbus_m_opts_get_do(shadow_offset_y, cdbus_reply_int32);
cdbus_m_opts_get_do(shadow_opacity, cdbus_reply_double);
cdbus_m_opts_get_do(clear_shadow, cdbus_reply_bool);
+ cdbus_m_opts_get_do(xinerama_shadow_crop, cdbus_reply_bool);
cdbus_m_opts_get_do(fade_delta, cdbus_reply_int32);
cdbus_m_opts_get_do(fade_in_step, cdbus_reply_int32);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment