diff options
-rw-r--r-- | .gitignore | 21 | ||||
-rw-r--r-- | LICENSE (renamed from COPYING) | 3 | ||||
-rw-r--r-- | Makefile | 27 | ||||
-rw-r--r-- | Makefile.am | 19 | ||||
-rw-r--r-- | README | 32 | ||||
-rwxr-xr-x | autogen.sh | 14 | ||||
-rw-r--r-- | config.mk | 6 | ||||
-rw-r--r-- | configure.ac | 25 | ||||
-rw-r--r-- | man/Makefile.am | 12 | ||||
-rw-r--r-- | man/xcompmgr.man | 69 | ||||
-rw-r--r-- | xcman.1 | 9 | ||||
-rw-r--r-- | xcman.c | 798 | ||||
-rw-r--r-- | xcompmgr.c | 2378 |
13 files changed, 851 insertions, 2562 deletions
@@ -1,20 +1,3 @@ -.deps -Makefile -Makefile.in -aclocal.m4 -autom4te.cache -config.h -config.h.in -config.log -config.status -configure -depcomp -install-sh -missing -stamp-h1 -xcompmgr -*.o *~ -xcompmgr-*.tar.* -ChangeLog -tags +*\#* +/xcman @@ -1,4 +1,5 @@ -Copyright © 2003 Keith Packard +Copyright © 2018 Mattias Andrée <maandree@kth.se> +Copyright © 2003 Keith Packard (xcompmgr) Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..afde4e8 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +.POSIX: + +CONFIGFILE = config.mk +include $(CONFIGFILE) + +all: xcman + +install: xcman + mkdir -p -- "$(DESTDIR)$(PREFIX)/bin" + mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man1" + mkdir -p -- "$(DESTDIR)$(PREFIX)/share/licenses/xcman" + cp -- xcman "$(DESTDIR)$(PREFIX)/bin" + cp -- xcman.1 "$(DESTDIR)$(MANPREFIX)/man1" + cp -- LICENSE "$(DESTDIR)$(PREFIX)/share/licenses/xcman" + +uninstall: + -rm -f -- "$(DESTDIR)$(PREFIX)/bin/xcman" + -rm -f -- "$(DESTDIR)$(MANPREFIX)/man1/xcman.1" + -rm -rf -- "$(DESTDIR)$(PREFIX)/share/licenses/xcman" + +clean: + -rm -f -- xcman + +.SUFFIXES: +.SUFFIXES: .c + +.PHONY: all install uninstall clean diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 25d5adb..0000000 --- a/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -SUBDIRS = man - -bin_PROGRAMS = xcompmgr - -AM_CFLAGS = $(CWARNFLAGS) $(XCOMPMGR_CFLAGS) -xcompmgr_LDADD = $(XCOMPMGR_LIBS) -lm - -MAINTAINERCLEANFILES = ChangeLog INSTALL - -.PHONY: ChangeLog INSTALL - -INSTALL: - $(INSTALL_CMD) - -ChangeLog: - $(CHANGELOG_CMD) - -dist-hook: ChangeLog INSTALL - @@ -1,27 +1,9 @@ -xcompmgr is a sample compositing manager for X servers supporting the -XFIXES, DAMAGE, RENDER, and COMPOSITE extensions. It enables basic -eye-candy effects. +NAME + xcman - Minimal compositing manager for X -All questions regarding this software should be directed at the -Xorg mailing list: - - http://lists.freedesktop.org/mailman/listinfo/xorg - -Please submit bug reports to the Xorg bugzilla: - - https://bugs.freedesktop.org/enter_bug.cgi?product=xorg - -The master development code repository can be found at: - - git://anongit.freedesktop.org/git/xorg/app/xcompmgr - - http://cgit.freedesktop.org/xorg/app/xcompmgr - -For patch submission instructions, see: - - http://www.x.org/wiki/Development/Documentation/SubmittingPatches - -For more information on the git code manager, see: - - http://wiki.x.org/wiki/GitPage +SYNOPSIS + xcman +DESCRIPTION + xcman is a minimal compositing manager, for X, forked + from xcompmgr. It only provides transparancy support. diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index fc34bd5..0000000 --- a/autogen.sh +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/sh - -srcdir=`dirname $0` -test -z "$srcdir" && srcdir=. - -ORIGDIR=`pwd` -cd $srcdir - -autoreconf -v --install || exit 1 -cd $ORIGDIR || exit $? - -if test -z "$NOCONFIGURE"; then - $srcdir/configure "$@" -fi diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..64ac473 --- /dev/null +++ b/config.mk @@ -0,0 +1,6 @@ +PREFIX = /usr/local +MANPREFIX = $(PREFIX)/share/man + +CPPFLAGS = +CFLAGS = -std=c99 -Wall -Wextra $(CPPFLAGS) +LDFLAGS = -lXext -lXdamage -lXfixes -lXcomposite -lXrender -lX11 diff --git a/configure.ac b/configure.ac deleted file mode 100644 index e63f1e6..0000000 --- a/configure.ac +++ /dev/null @@ -1,25 +0,0 @@ -# -*- Autoconf -*- -# Process this file with autoconf to produce a configure script. - -# Initialize Autoconf -AC_PREREQ(2.60) -AC_INIT([xcompmgr], [1.1.7], - [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg]) -AC_CONFIG_SRCDIR([xcompmgr.c]) -AC_CONFIG_HEADERS([config.h]) - -# Initialize Automake -AM_INIT_AUTOMAKE([foreign dist-bzip2]) - -# Require X.Org macros 1.8 or later for MAN_SUBSTS set by XORG_MANPAGE_SECTIONS -m4_ifndef([XORG_MACROS_VERSION], - [m4_fatal([must install xorg-macros 1.8 or later before running autoconf/autogen])]) -XORG_MACROS_VERSION(1.8) -XORG_DEFAULT_OPTIONS - -PKG_CHECK_MODULES(XCOMPMGR, xcomposite xfixes xdamage xrender xext) - -AC_CONFIG_FILES([ - Makefile - man/Makefile]) -AC_OUTPUT diff --git a/man/Makefile.am b/man/Makefile.am deleted file mode 100644 index 988f6ff..0000000 --- a/man/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ - -appmandir = $(APP_MAN_DIR) -appman_PRE = xcompmgr.man -appman_DATA = $(appman_PRE:man=$(APP_MAN_SUFFIX)) - -EXTRA_DIST = $(appman_PRE) -CLEANFILES = $(appman_DATA) -SUFFIXES = .$(APP_MAN_SUFFIX) .man - -# String replacements in MAN_SUBSTS now come from xorg-macros.m4 via configure -.man.$(APP_MAN_SUFFIX): - $(AM_V_GEN)$(SED) $(MAN_SUBSTS) < $< > $@ diff --git a/man/xcompmgr.man b/man/xcompmgr.man deleted file mode 100644 index 5f51ac5..0000000 --- a/man/xcompmgr.man +++ /dev/null @@ -1,69 +0,0 @@ -.ds q \N'34' -.TH xcompmgr 1 __xorgversion__ -.SH NAME -xcompmgr \- sample X compositing manager -.SH SYNOPSIS -.BI "xcompmgr [\-d " display "] [\-r " radius "]" -.BI "[\-o " opacity "] [\-l " left-offset "]" -.BI "[\-t " top-offset "] [\-acCfFnsS]" -.SH DESCRIPTION -.B xcompmgr -is a sample compositing manager for X servers supporting the XFIXES, DAMAGE, -and COMPOSITE extensions. It enables basic eye-candy effects. -.SH OPTIONS -.TP -.BI \-d\ display -Specifies the display to manage. -.TP -.BI \-r\ radius -Specifies the blur radius for client-side shadows. -.TP -.BI \-o\ opacity -Specifies the opacity for client-side shadows. -.TP -.BI \-l\ left-offset -Specifies the left offset for client-side shadows. -.TP -.BI \-t\ top-offset -Specifies the top offset for client-side shadows. -.TP -.BI \-I\ fade-in-step -Specifies the opacity change between steps while fading in. -.TP -.BI \-O\ fade-out-step -Specifies the opacity change between steps while fading out. -.TP -.BI \-D\ fade-delta -Specifies the time (in milliseconds) between steps in a fade. -.TP -.BI \-a -Automatic server-side compositing. This instructs the server to use the -standard composition rules. Useful for debugging. -.TP -.BI \-c -Client-side compositing with soft shadows and translucency support. -.TP -.BI \-f -When \-c is specified, enables a smooth fade effect for transient windows like -menus, and for all windows on hide and restore events. -.TP -.BI \-n -Simple client-side compositing. This is the default mode. -.TP -.BI \-s -Server-side compositing with hard-edged shadows. -.TP -.BI \-C -When \-c is specified, attempts to avoid painting shadows on panels and docks. -.TP -.BI \-F -When \-f is specified, also enables the fade effect when windows change their -opacity, as with transset(1). -.TP -.BI \-S -Enables synchronous operation. Useful for debugging. -.SH BUGS -Probably. Please report any you find to http://bugs.freedesktop.org/. -.SH AUTHORS -Keith Packard, with contributions from Matthew Allum, Eric Anholt, Dan Doel, -Thomas Luebking, Matthew Hawn, Ely Levy, Phil Blundell, and Carl Worth. @@ -0,0 +1,9 @@ +.TH XCMAN 1 xcman +.SH NAME +xcman - Minimal compositing manager for X +.SH SYNOPSIS +.B xcman +.SH DESCRIPTION +.B xcman +is a minimal compositing manager, for X, forked +from xcompmgr. It only provides transparancy support. @@ -0,0 +1,798 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/extensions/Xcomposite.h> +#include <X11/extensions/Xdamage.h> +#include <X11/extensions/Xrender.h> +#include <X11/extensions/shape.h> + +#define eprintf(...) (fprintf(stderr, __VA_ARGS__), exit(1)) +#define erealloc(P, N) ((tmp_ = realloc((P), (N))) ? tmp_ : (eprintf("realloc: out of memory\n"), NULL)) +#define ecalloc(N, M) ((tmp_ = calloc((N), (M))) ? tmp_ : (eprintf("calloc: out of memory\n"), NULL)) +static void *tmp_; + +#define OPAQUE (~(uint32_t)0) + +#define COPY_AREA(DEST, SRC)\ + ((DEST)->x = (SRC)->x,\ + (DEST)->y = (SRC)->y,\ + (DEST)->width = (SRC)->width,\ + (DEST)->height = (SRC)->height) + +struct window { + struct window *next; + Window id; + Pixmap pixmap; + XWindowAttributes a; + int solid; + int damaged; + Damage damage; + Picture picture; + Picture alpha_picture; + XserverRegion border_size; + XserverRegion extents; + uint32_t opacity; + int shaped; + XRectangle shape_bounds; + + /* for drawing translucent windows */ + XserverRegion border_clip; + struct window *prev_trans; +}; + +static unsigned long int *ignores = NULL; +static size_t n_ignores = 0, size_ignores = 0; +static Display *dpy; +static int screen; +static Window root; +static int root_height, root_width; +static int damage_error, xfixes_error, render_error; +static int damage_event, xshape_event; +static int composite_opcode; +static Atom opacity_atom; +static XRenderColor alpha_colour = {.red = 0, .green = 0, .blue = 0}; + +static struct window *window_list; +static Picture root_picture; +static Picture root_buffer; +static Picture root_tile; +static XserverRegion all_damage; +static int clip_changed; + +static const char *background_properties[] = {"_XROOTPMAP_ID", "_XSETROOT_ID", NULL}; + +static void +usage(const char *program) +{ + fprintf(stderr, "usage: %s\n", program); + exit(1); +} + +static Picture +solid_picture(double a) +{ + Pixmap pixmap; + Picture picture; + XRenderPictureAttributes pa; + + pixmap = XCreatePixmap(dpy, root, 1, 1, 8); + if (!pixmap) + return None; + + pa.repeat = 1; + picture = XRenderCreatePicture(dpy, pixmap, XRenderFindStandardFormat(dpy, PictStandardA8), CPRepeat, &pa); + if (!picture) { + XFreePixmap(dpy, pixmap); + return None; + } + + alpha_colour.alpha = a * 0xFFFF; + XRenderFillRectangle(dpy, PictOpSrc, picture, &alpha_colour, 0, 0, 1, 1); + XFreePixmap(dpy, pixmap); + return picture; +} + +static void +discard_ignore(unsigned long int sequence) +{ + size_t i; + for (i = 0; i < n_ignores && sequence > ignores[i]; i++); + memmove(ignores, &ignores[i], (n_ignores -= i) * sizeof(*ignores)); +} + +static void +set_ignore(unsigned long int sequence) +{ + if (n_ignores == size_ignores) + ignores = erealloc(ignores, (size_ignores += 64) * sizeof(*ignores)); + ignores[n_ignores++] = sequence; +} + +static int +should_ignore(unsigned long int sequence) +{ + discard_ignore(sequence); + return n_ignores && ignores[0] == sequence; +} + +static struct window * +find_window(Window id) +{ + struct window *w; + for (w = window_list; w; w = w->next) + if (w->id == id) + return w; + return NULL; +} + +static Picture +make_root_tile(void) +{ + Picture picture; + Atom actual_type; + Pixmap pixmap; + int actual_format; + unsigned long int nitems; + unsigned long int bytes_after; + unsigned char *prop; + int fill; + XRenderPictureAttributes pa; + int p; + + pixmap = None; + for (p = 0; background_properties[p]; p++) { + if (!XGetWindowProperty(dpy, root, XInternAtom(dpy, background_properties[p], 0), 0, 4, 0, AnyPropertyType, + &actual_type, &actual_format, &nitems, &bytes_after, &prop) && + actual_type == XInternAtom(dpy, "PIXMAP", 0) && actual_format == 32 && nitems == 1) { + memcpy(&pixmap, prop, 4); + XFree(prop); + fill = 0; + break; + } + } + if (!pixmap) { + pixmap = XCreatePixmap(dpy, root, 1, 1, DefaultDepth(dpy, screen)); + fill = 1; + } + pa.repeat = 1; + picture = XRenderCreatePicture(dpy, pixmap, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, screen)), CPRepeat, &pa); + if (fill) { + alpha_colour.alpha = 0xFFFF; + XRenderFillRectangle(dpy, PictOpSrc, picture, &alpha_colour, 0, 0, 1, 1); + } + return picture; +} + +static void +paint_root(void) +{ + if (!root_tile) + root_tile = make_root_tile(); + XRenderComposite(dpy, PictOpSrc, root_tile, None, root_buffer, 0, 0, 0, 0, 0, 0, root_width, root_height); +} + +static XserverRegion +win_extents(struct window *w) +{ + XRectangle r; + COPY_AREA(&r, &w->a); + r.width += w->a.border_width * 2; + r.height += w->a.border_width * 2; + return XFixesCreateRegion(dpy, &r, 1); +} + +static XserverRegion +border_size(struct window *w) +{ + XserverRegion border; + set_ignore(NextRequest(dpy)); + border = XFixesCreateRegionFromWindow(dpy, w->id, WindowRegionBounding); + set_ignore(NextRequest(dpy)); + XFixesTranslateRegion(dpy, border, w->a.x + w->a.border_width, w->a.y + w->a.border_width); + return border; +} + +static void +paint_all(XserverRegion region) +{ + struct window *w, *t = NULL; + XRectangle r; + int x, y, wid, hei; + Pixmap rootPixmap; + XRenderPictureAttributes pa; + XRenderPictFormat *format; + Drawable draw; + + if (!region) { + r.x = r.y = 0; + r.width = root_width; + r.height = root_height; + region = XFixesCreateRegion(dpy, &r, 1); + } + if (!root_buffer) { + rootPixmap = XCreatePixmap(dpy, root, root_width, root_height, DefaultDepth(dpy, screen)); + root_buffer = XRenderCreatePicture(dpy, rootPixmap, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, screen)), 0, NULL); + XFreePixmap(dpy, rootPixmap); + } + XFixesSetPictureClipRegion(dpy, root_picture, 0, 0, region); + for (w = window_list; w; w = w->next) { + if (!w->damaged) + continue; + if (w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1 || w->a.x >= root_width || w->a.y >= root_height) + continue; + if (!w->picture) { + draw = w->id; + if (w->pixmap) + draw = w->pixmap; + else + w->pixmap = XCompositeNameWindowPixmap(dpy, w->id); + format = XRenderFindVisualFormat(dpy, w->a.visual); + pa.subwindow_mode = IncludeInferiors; + w->picture = XRenderCreatePicture(dpy, draw, format, CPSubwindowMode, &pa); + } + if (clip_changed) { + if (w->border_size) { + set_ignore(NextRequest(dpy)); + XFixesDestroyRegion(dpy, w->border_size); + w->border_size = None; + } + if (w->extents) { + XFixesDestroyRegion(dpy, w->extents); + w->extents = None; + } + if (w->border_clip) { + XFixesDestroyRegion(dpy, w->border_clip); + w->border_clip = None; + } + } + if (!w->border_size) + w->border_size = border_size(w); + if (!w->extents) + w->extents = win_extents(w); + if (w->solid) { + x = w->a.x; + y = w->a.y; + wid = w->a.width + w->a.border_width * 2; + hei = w->a.height + w->a.border_width * 2; + XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, region); + set_ignore(NextRequest(dpy)); + XFixesSubtractRegion(dpy, region, region, w->border_size); + set_ignore(NextRequest(dpy)); + XRenderComposite(dpy, PictOpSrc, w->picture, None, root_buffer, 0, 0, 0, 0, x, y, wid, hei); + } + if (!w->border_clip) { + w->border_clip = XFixesCreateRegion(dpy, NULL, 0); + XFixesCopyRegion(dpy, w->border_clip, region); + XFixesIntersectRegion(dpy, w->border_clip, w->border_clip, w->border_size); + } + w->prev_trans = t; + t = w; + } + XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, region); + paint_root(); + for (w = t; w; w = w->prev_trans) { + XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, w->border_clip); + if (w->opacity != OPAQUE && !w->alpha_picture) + w->alpha_picture = solid_picture((double)w->opacity / OPAQUE); + if (!w->solid) { + x = w->a.x; + y = w->a.y; + wid = w->a.width + w->a.border_width * 2; + hei = w->a.height + w->a.border_width * 2; + set_ignore(NextRequest(dpy)); + XRenderComposite(dpy, PictOpOver, w->picture, w->alpha_picture, root_buffer, 0, 0, 0, 0, x, y, wid, hei); + } + XFixesDestroyRegion(dpy, w->border_clip); + w->border_clip = None; + } + XFixesDestroyRegion(dpy, region); + if (root_buffer != root_picture) { + XFixesSetPictureClipRegion(dpy, root_buffer, 0, 0, None); + XRenderComposite(dpy, PictOpSrc, root_buffer, None, root_picture, 0, 0, 0, 0, 0, 0, root_width, root_height); + } +} + +static void +add_damage(XserverRegion damage) +{ + if (all_damage) { + XFixesUnionRegion(dpy, all_damage, all_damage, damage); + XFixesDestroyRegion(dpy, damage); + } else { + all_damage = damage; + } +} + +static unsigned int +get_opacity_prop(struct window *w, unsigned int def) +{ + uint32_t i; + Atom actual; + int format; + unsigned long int n, left; + unsigned char *data; + int err = XGetWindowProperty(dpy, w->id, opacity_atom, 0L, 1L, 0, XA_CARDINAL, &actual, &format, &n, &left, &data); + if (!err && data) { + i = *(uint32_t *)data; + XFree((void *)data); + return i; + } + return def; +} + +static void +determine_mode(struct window *w) +{ + XRenderPictFormat *format; + XserverRegion damage; + + if (w->alpha_picture) { + XRenderFreePicture(dpy, w->alpha_picture); + w->alpha_picture = None; + } + + w->opacity = get_opacity_prop(w, OPAQUE); + + w->solid = (w->opacity == OPAQUE && + ((format = w->a.class == InputOnly ? NULL : XRenderFindVisualFormat(dpy, w->a.visual)), + (!format || format->type != PictTypeDirect || !format->direct.alphaMask))); + + if (w->extents) { + damage = XFixesCreateRegion(dpy, NULL, 0); + XFixesCopyRegion(dpy, damage, w->extents); + add_damage(damage); + } +} + +static void +map_window(Window id) +{ + struct window *w = find_window(id); + if (!w) + return; + + w->a.map_state = IsViewable; + + /* This needs to be here or else we lose transparency messages */ + XSelectInput(dpy, id, PropertyChangeMask); + + /* This needs to be here since we don't get PropertyNotify when unmapped */ + determine_mode(w); + + w->damaged = 0; +} + +static void +finish_unmap_window(struct window *w) +{ + w->damaged = 0; + if (w->extents != None) { + add_damage(w->extents); /* destroys region */ + w->extents = None; + } + + if (w->pixmap) { + XFreePixmap(dpy, w->pixmap); + w->pixmap = None; + } + + if (w->picture) { + set_ignore(NextRequest(dpy)); + XRenderFreePicture(dpy, w->picture); + w->picture = None; + } + + /* don't care about properties anymore */ + set_ignore(NextRequest(dpy)); + XSelectInput(dpy, w->id, 0); + + if (w->border_size) { + set_ignore(NextRequest(dpy)); + XFixesDestroyRegion(dpy, w->border_size); + w->border_size = None; + } + if (w->border_clip) { + XFixesDestroyRegion(dpy, w->border_clip); + w->border_clip = None; + } + + clip_changed = 1; +} + +static void +unmap_window(Window id) +{ + struct window *w = find_window(id); + if (w) { + w->a.map_state = IsUnmapped; + finish_unmap_window(w); + } +} + +static void +add_window(Window id) +{ + struct window *w = ecalloc(1, sizeof(struct window)); + w->id = id; + set_ignore(NextRequest(dpy)); + if (!XGetWindowAttributes(dpy, id, &w->a)) { + free(w); + return; + } + COPY_AREA(&w->shape_bounds, &w->a); + if (w->a.class != InputOnly) { + w->damage = XDamageCreate(dpy, id, XDamageReportNonEmpty); + XShapeSelectInput(dpy, id, ShapeNotifyMask); + } + w->opacity = OPAQUE; + w->next = window_list; + window_list = w; + if (w->a.map_state == IsViewable) + map_window(id); +} + +static void +restack_window(struct window *w, Window new_above) +{ + Window old_above; + struct window **prev; + + old_above = w->next ? w->next->id : None; + + if (old_above != new_above) { + /* unhook */ + for (prev = &window_list; *prev; prev = &(*prev)->next) + if ((*prev) == w) + break; + *prev = w->next; + + /* rehook */ + for (prev = &window_list; *prev; prev = &(*prev)->next) + if ((*prev)->id == new_above) + break; + w->next = *prev; + *prev = w; + } +} + +static void +configure_window(XConfigureEvent *ce) +{ + struct window *w = find_window(ce->window); + XserverRegion extents, damage = None; + + if (!w) { + if (ce->window == root) { + if (root_buffer) { + XRenderFreePicture(dpy, root_buffer); + root_buffer = None; + } + root_width = ce->width; + root_height = ce->height; + } + return; + } + + damage = XFixesCreateRegion(dpy, NULL, 0); + if (w->extents != None) + XFixesCopyRegion(dpy, damage, w->extents); + if (w->a.width != ce->width || w->a.height != ce->height) { + if (w->pixmap) { + XFreePixmap(dpy, w->pixmap); + w->pixmap = None; + if (w->picture) { + XRenderFreePicture(dpy, w->picture); + w->picture = None; + } + } + } + w->shape_bounds.x -= w->a.x; + w->shape_bounds.y -= w->a.y; + COPY_AREA(&w->a, ce); + w->a.border_width = ce->border_width; + w->a.override_redirect = ce->override_redirect; + restack_window(w, ce->above); + if (damage) { + extents = win_extents(w); + XFixesUnionRegion(dpy, damage, damage, extents); + XFixesDestroyRegion(dpy, extents); + add_damage(damage); + } + w->shape_bounds.x += w->a.x; + w->shape_bounds.y += w->a.y; + if (!w->shaped) { + w->shape_bounds.width = w->a.width; + w->shape_bounds.height = w->a.height; + } + + clip_changed = 1; +} + +static void +circulate_window(XCirculateEvent *ce) +{ + Window new_above; + struct window *w = find_window(ce->window); + if (!w) + return; + new_above = ce->place == PlaceOnTop ? window_list->id : None; + restack_window(w, new_above); + clip_changed = 1; +} + +static void +destroy_window(Window id, int gone) +{ + struct window **prev, *w; + for (prev = &window_list; (w = *prev); prev = &w->next) { + if (w->id == id) { + if (gone) + finish_unmap_window(w); + *prev = w->next; + if (w->picture) { + set_ignore(NextRequest(dpy)); + XRenderFreePicture(dpy, w->picture); + w->picture = None; + } + if (w->alpha_picture) { + XRenderFreePicture(dpy, w->alpha_picture); + w->alpha_picture = None; + } + if (w->damage != None) { + set_ignore(NextRequest(dpy)); + XDamageDestroy(dpy, w->damage); + w->damage = None; + } + free(w); + break; + } + } +} + +static void +damage_window(XDamageNotifyEvent *de) +{ + XserverRegion parts; + struct window *w = find_window(de->drawable); + if (!w) + return; + if (!w->damaged) { + parts = win_extents(w); + set_ignore(NextRequest(dpy)); + XDamageSubtract(dpy, w->damage, None, None); + } else { + parts = XFixesCreateRegion(dpy, NULL, 0); + set_ignore(NextRequest(dpy)); + XDamageSubtract(dpy, w->damage, None, parts); + XFixesTranslateRegion(dpy, parts, w->a.x + w->a.border_width, w->a.y + w->a.border_width); + } + add_damage(parts); + w->damaged = 1; +} + +static void +shape_window(XShapeEvent *se) +{ + XserverRegion region0, region1; + struct window *w = find_window(se->window); + + if (!w) + return; + + if (se->kind == ShapeClip || se->kind == ShapeBounding) { + clip_changed = 1; + + region0 = XFixesCreateRegion(dpy, &w->shape_bounds, 1); + + if (se->shaped) { + w->shaped = 1; + COPY_AREA(&w->shape_bounds, se); + w->shape_bounds.x += w->a.x; + w->shape_bounds.y += w->a.y; + } else { + w->shaped = 0; + COPY_AREA(&w->shape_bounds, &w->a); + } + + region1 = XFixesCreateRegion(dpy, &w->shape_bounds, 1); + XFixesUnionRegion(dpy, region0, region0, region1); + XFixesDestroyRegion(dpy, region1); + + /* ask for repaint of the old and new region */ + paint_all(region0); + } +} + +static int +error(Display *display, XErrorEvent *ev) +{ + const char *name = NULL; + static char buffer[256]; + + if (should_ignore(ev->serial)) + return 0; + + if (ev->request_code == composite_opcode && ev->minor_code == X_CompositeRedirectSubwindows) + eprintf("another composite manager is already running\n"); + + if (ev->error_code - xfixes_error == BadRegion) { + name = "BadRegion"; + } else if (ev->error_code - damage_error == BadDamage) { + name = "BadDamage"; + } else { + switch (ev->error_code - render_error) { + case BadPictFormat: name = "BadPictFormat"; break; + case BadPicture: name = "BadPicture"; break; + case BadPictOp: name = "BadPictOp"; break; + case BadGlyphSet: name = "BadGlyphSet"; break; + case BadGlyph: name = "BadGlyph"; break; + default: + break; + } + } + + if (!name) { + buffer[0] = '\0'; + XGetErrorText(display, ev->error_code, buffer, sizeof(buffer)); + name = buffer; + } + + fprintf(stderr, "error %i: %s request %i minor %i serial %lu\n", + ev->error_code, (strlen(name) > 0) ? name : "unknown", + ev->request_code, ev->minor_code, ev->serial); + + return 0; +} + +static void +register_composite_manager(void) +{ + static char net_wm_cm[sizeof("_NET_WM_CM_S") + 3 * sizeof(screen)]; + Window w; + Atom a, winNameAtom; + XTextProperty tp; + char **strs; + int count; + + sprintf(net_wm_cm, "_NET_WM_CM_S%i", screen); + a = XInternAtom(dpy, net_wm_cm, 0); + + w = XGetSelectionOwner(dpy, a); + if (w != None) { + winNameAtom = XInternAtom(dpy, "_NET_WM_NAME", 0); + if (!XGetTextProperty(dpy, w, &tp, winNameAtom) && + !XGetTextProperty(dpy, w, &tp, XA_WM_NAME)) { + eprintf("another composite manager is already running (0x%lx)\n", (unsigned long int)w); + } + if (!XmbTextPropertyToTextList(dpy, &tp, &strs, &count)) { + fprintf(stderr, "another composite manager is already running (%s)\n", strs[0]); + XFreeStringList(strs); + } + XFree(tp.value); + exit(1); + } + + w = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), 0, 0, 1, 1, 0, None, None); + Xutf8SetWMProperties(dpy, w, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL, NULL); + XSetSelectionOwner(dpy, a, w, 0); +} + +int +main(int argc, char **argv) +{ + XEvent ev; + Window root_return, parent_return, *children; + XRenderPictureAttributes pa; + XRectangle *expose_rects = NULL; + size_t n_expose = 0, size_expose = 0; + unsigned int i, n; + int more, composite_major, composite_minor; + struct window *w; + + if (argc > 1) + usage(argv[0]); + + dpy = XOpenDisplay(NULL); + if (!dpy) + eprintf("cannot open display\n"); + XSetErrorHandler(error); + screen = DefaultScreen(dpy); + root = RootWindow(dpy, screen); + + if (!XRenderQueryExtension(dpy, &(int){0}, &render_error)) + eprintf("no render extension\n"); + if (!XQueryExtension(dpy, COMPOSITE_NAME, &composite_opcode, &(int){0}, &(int){0})) + eprintf("no composite extension\n"); + XCompositeQueryVersion(dpy, &composite_major, &composite_minor); + if (!composite_major && composite_minor < 2) + eprintf("no composite extension version is too old\n"); + if (!XDamageQueryExtension(dpy, &damage_event, &damage_error)) + eprintf("no damage extension\n"); + if (!XFixesQueryExtension(dpy, &(int){0}, &xfixes_error)) + eprintf("no XFixes extension\n"); + if (!XShapeQueryExtension(dpy, &xshape_event, &(int){0})) + eprintf("no XShape extension\n"); + + register_composite_manager(); + opacity_atom = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", 0); + pa.subwindow_mode = IncludeInferiors; + root_width = DisplayWidth(dpy, screen); + root_height = DisplayHeight(dpy, screen); + root_picture = XRenderCreatePicture(dpy, root, XRenderFindVisualFormat(dpy, DefaultVisual(dpy, screen)), CPSubwindowMode, &pa); + all_damage = None; + clip_changed = 1; + XGrabServer(dpy); + XCompositeRedirectSubwindows(dpy, root, CompositeRedirectManual); + XSelectInput(dpy, root, SubstructureNotifyMask | ExposureMask | StructureNotifyMask | PropertyChangeMask); + XShapeSelectInput(dpy, root, ShapeNotifyMask); + XQueryTree(dpy, root, &root_return, &parent_return, &children, &n); + for (i = 0; i < n; i++) + add_window(children[i]); + XFree(children); + XUngrabServer(dpy); + paint_all(None); + + for (;;) { + XNextEvent(dpy, &ev); + if ((ev.type & 0x7F) != KeymapNotify) + discard_ignore(ev.xany.serial); + switch (ev.type) { + case CreateNotify: add_window(ev.xcreatewindow.window); break; + case ConfigureNotify: configure_window(&ev.xconfigure); break; + case DestroyNotify: destroy_window(ev.xdestroywindow.window, 1); break; + case CirculateNotify: circulate_window(&ev.xcirculate); break; + case MapNotify: map_window(ev.xmap.window); break; + case UnmapNotify: unmap_window(ev.xunmap.window); break; + case ReparentNotify: + if (ev.xreparent.parent == root) + add_window(ev.xreparent.window); + else + destroy_window(ev.xreparent.window, 0); + break; + case Expose: + if (ev.xexpose.window == root) { + more = ev.xexpose.count + 1; + if (n_expose == size_expose) + expose_rects = erealloc(expose_rects, (size_expose += more) * sizeof(XRectangle)); + COPY_AREA(&expose_rects[n_expose], &ev.xexpose); + n_expose++; + if (!ev.xexpose.count) { + add_damage(XFixesCreateRegion(dpy, expose_rects, n_expose)); + n_expose = 0; + } + } + break; + case PropertyNotify: + if (ev.xproperty.atom == opacity_atom) { + if ((w = find_window(ev.xproperty.window))) + determine_mode(w); + } else if (root_tile) { + for (i = 0; background_properties[i]; i++) { + if (ev.xproperty.atom == XInternAtom(dpy, background_properties[i], 0)) { + XClearArea(dpy, root, 0, 0, 0, 0, 1); + XRenderFreePicture(dpy, root_tile); + root_tile = None; + break; + } + } + } + break; + default: + if (ev.type == damage_event + XDamageNotify) + damage_window((XDamageNotifyEvent *)&ev); + else if (ev.type == xshape_event + ShapeNotify) + shape_window((XShapeEvent *)&ev); + break; + } + if (!QLength(dpy) && all_damage) { + paint_all(all_damage); + XSync(dpy, 0); + all_damage = None; + clip_changed = 0; + } + } +} diff --git a/xcompmgr.c b/xcompmgr.c deleted file mode 100644 index 3968def..0000000 --- a/xcompmgr.c +++ /dev/null @@ -1,2378 +0,0 @@ -/* - * Copyright © 2003 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - - -/* Modified by Matthew Hawn. I don't know what to say here so follow what it - says above. Not that I can really do anything about it -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <math.h> -#include <sys/poll.h> -#include <sys/time.h> -#include <time.h> -#include <unistd.h> -#include <getopt.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/Xatom.h> -#include <X11/extensions/Xcomposite.h> -#include <X11/extensions/Xdamage.h> -#include <X11/extensions/Xrender.h> -#include <X11/extensions/shape.h> - -#if COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR >= 2 -#define HAS_NAME_WINDOW_PIXMAP 1 -#endif - -#define CAN_DO_USABLE 0 - -typedef struct _ignore { - struct _ignore *next; - unsigned long sequence; -} ignore; - -typedef struct _win { - struct _win *next; - Window id; -#if HAS_NAME_WINDOW_PIXMAP - Pixmap pixmap; -#endif - XWindowAttributes a; -#if CAN_DO_USABLE - Bool usable; /* mapped and all damaged at one point */ - XRectangle damage_bounds; /* bounds of damage */ -#endif - int mode; - int damaged; - Damage damage; - Picture picture; - Picture alphaPict; - Picture shadowPict; - XserverRegion borderSize; - XserverRegion extents; - Picture shadow; - int shadow_dx; - int shadow_dy; - int shadow_width; - int shadow_height; - unsigned int opacity; - Atom windowType; - unsigned long damage_sequence; /* sequence when damage was created */ - Bool shaped; - XRectangle shape_bounds; - - /* for drawing translucent windows */ - XserverRegion borderClip; - struct _win *prev_trans; -} win; - -typedef struct _conv { - int size; - double *data; -} conv; - -typedef struct _fade { - struct _fade *next; - win *w; - double cur; - double finish; - double step; - void (*callback) (Display *dpy, win *w, Bool gone); - Display *dpy; - Bool gone; -} fade; - -static win *list; -static fade *fades; -static int scr; -static Window root; -static Picture rootPicture; -static Picture rootBuffer; -static Picture blackPicture; -static Picture transBlackPicture; -static Picture rootTile; -static XserverRegion allDamage; -static Bool clipChanged; -#if HAS_NAME_WINDOW_PIXMAP -static Bool hasNamePixmap; -#endif -static int root_height, root_width; -static ignore *ignore_head, **ignore_tail = &ignore_head; -static int xfixes_event, xfixes_error; -static int damage_event, damage_error; -static int composite_event, composite_error; -static int render_event, render_error; -static int xshape_event, xshape_error; -static Bool synchronize; -static int composite_opcode; - -/* find these once and be done with it */ -static Atom opacityAtom; -static Atom winTypeAtom; -static Atom winDesktopAtom; -static Atom winDockAtom; -static Atom winToolbarAtom; -static Atom winMenuAtom; -static Atom winUtilAtom; -static Atom winSplashAtom; -static Atom winDialogAtom; -static Atom winNormalAtom; - -/* opacity property name; sometime soon I'll write up an EWMH spec for it */ -#define OPACITY_PROP "_NET_WM_WINDOW_OPACITY" - -#define TRANSLUCENT 0xe0000000 -#define OPAQUE 0xffffffff - -static conv *gaussianMap; - -#define WINDOW_SOLID 0 -#define WINDOW_TRANS 1 -#define WINDOW_ARGB 2 - -#define TRANS_OPACITY 0.75 - -#define DEBUG_REPAINT 0 -#define DEBUG_EVENTS 0 -#define DEBUG_SHAPE 0 -#define MONITOR_REPAINT 0 - -#define SHADOWS 1 -#define SHARP_SHADOW 0 - -typedef enum _compMode { - CompSimple, /* looks like a regular X server */ - CompServerShadows, /* use window alpha for shadow; sharp, but precise */ - CompClientShadows, /* use window extents for shadow, blurred */ -} CompMode; - -static void -determine_mode(Display *dpy, win *w); - -static double -get_opacity_percent(Display *dpy, win *w, double def); - -static XserverRegion -win_extents (Display *dpy, win *w); - -static CompMode compMode = CompSimple; - -static int shadowRadius = 12; -static int shadowOffsetX = -15; -static int shadowOffsetY = -15; -static double shadowOpacity = .75; - -static double fade_in_step = 0.028; -static double fade_out_step = 0.03; -static int fade_delta = 10; -static int fade_time = 0; -static Bool fadeWindows = False; -static Bool excludeDockShadows = False; -static Bool fadeTrans = False; - -static Bool autoRedirect = False; - -/* For shadow precomputation */ -static int Gsize = -1; -static unsigned char *shadowCorner = NULL; -static unsigned char *shadowTop = NULL; - -static int -get_time_in_milliseconds (void) -{ - struct timeval tv; - - gettimeofday (&tv, NULL); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -} - -static fade * -find_fade (win *w) -{ - fade *f; - - for (f = fades; f; f = f->next) - { - if (f->w == w) - return f; - } - return NULL; -} - -static void -dequeue_fade (Display *dpy, fade *f) -{ - fade **prev; - - for (prev = &fades; *prev; prev = &(*prev)->next) - if (*prev == f) - { - *prev = f->next; - if (f->callback) - (*f->callback) (dpy, f->w, f->gone); - free (f); - break; - } -} - -static void -cleanup_fade (Display *dpy, win *w) -{ - fade *f = find_fade (w); - if (f) - dequeue_fade (dpy, f); -} - -static void -enqueue_fade (Display *dpy, fade *f) -{ - if (!fades) - fade_time = get_time_in_milliseconds () + fade_delta; - f->next = fades; - fades = f; -} - -static void -set_fade (Display *dpy, win *w, double start, double finish, double step, - void (*callback) (Display *dpy, win *w, Bool gone), - Bool gone, Bool exec_callback, Bool override) -{ - fade *f; - - f = find_fade (w); - if (!f) - { - f = malloc (sizeof (fade)); - f->next = NULL; - f->w = w; - f->cur = start; - enqueue_fade (dpy, f); - } - else if(!override) - return; - else - { - if (exec_callback) - if (f->callback) - (*f->callback)(dpy, f->w, f->gone); - } - - if (finish < 0) - finish = 0; - if (finish > 1) - finish = 1; - f->finish = finish; - if (f->cur < finish) - f->step = step; - else if (f->cur > finish) - f->step = -step; - f->callback = callback; - f->gone = gone; - w->opacity = f->cur * OPAQUE; -#if 0 - printf ("set_fade start %g step %g\n", f->cur, f->step); -#endif - determine_mode (dpy, w); - if (w->shadow) - { - XRenderFreePicture (dpy, w->shadow); - w->shadow = None; - w->extents = win_extents (dpy, w); - } -} - -static int -fade_timeout (void) -{ - int now; - int delta; - if (!fades) - return -1; - now = get_time_in_milliseconds(); - delta = fade_time - now; - if (delta < 0) - delta = 0; -/* printf ("timeout %d\n", delta); */ - return delta; -} - -static void -run_fades (Display *dpy) -{ - int now = get_time_in_milliseconds(); - fade *next = fades; - int steps; - Bool need_dequeue; - -#if 0 - printf ("run fades\n"); -#endif - if (fade_time - now > 0) - return; - steps = 1 + (now - fade_time) / fade_delta; - - while (next) - { - fade *f = next; - win *w = f->w; - next = f->next; - f->cur += f->step * steps; - if (f->cur >= 1) - f->cur = 1; - else if (f->cur < 0) - f->cur = 0; -#if 0 - printf ("opacity now %g\n", f->cur); -#endif - w->opacity = f->cur * OPAQUE; - need_dequeue = False; - if (f->step > 0) - { - if (f->cur >= f->finish) - { - w->opacity = f->finish*OPAQUE; - need_dequeue = True; - } - } - else - { - if (f->cur <= f->finish) - { - w->opacity = f->finish*OPAQUE; - need_dequeue = True; - } - } - determine_mode (dpy, w); - if (w->shadow) - { - XRenderFreePicture (dpy, w->shadow); - w->shadow = None; - w->extents = win_extents(dpy, w); - } - /* Must do this last as it might destroy f->w in callbacks */ - if (need_dequeue) - dequeue_fade (dpy, f); - } - fade_time = now + fade_delta; -} - -static double -gaussian (double r, double x, double y) -{ - return ((1 / (sqrt (2 * M_PI * r))) * - exp ((- (x * x + y * y)) / (2 * r * r))); -} - - -static conv * -make_gaussian_map (Display *dpy, double r) -{ - conv *c; - int size = ((int) ceil ((r * 3)) + 1) & ~1; - int center = size / 2; - int x, y; - double t; - double g; - - c = malloc (sizeof (conv) + size * size * sizeof (double)); - c->size = size; - c->data = (double *) (c + 1); - t = 0.0; - for (y = 0; y < size; y++) - for (x = 0; x < size; x++) - { - g = gaussian (r, (double) (x - center), (double) (y - center)); - t += g; - c->data[y * size + x] = g; - } -/* printf ("gaussian total %f\n", t); */ - for (y = 0; y < size; y++) - for (x = 0; x < size; x++) - { - c->data[y*size + x] /= t; - } - return c; -} - -/* - * A picture will help - * - * -center 0 width width+center - * -center +-----+-------------------+-----+ - * | | | | - * | | | | - * 0 +-----+-------------------+-----+ - * | | | | - * | | | | - * | | | | - * height +-----+-------------------+-----+ - * | | | | - * height+ | | | | - * center +-----+-------------------+-----+ - */ - -static unsigned char -sum_gaussian (conv *map, double opacity, int x, int y, int width, int height) -{ - int fx, fy; - double *g_data; - double *g_line = map->data; - int g_size = map->size; - int center = g_size / 2; - int fx_start, fx_end; - int fy_start, fy_end; - double v; - - /* - * Compute set of filter values which are "in range", - * that's the set with: - * 0 <= x + (fx-center) && x + (fx-center) < width && - * 0 <= y + (fy-center) && y + (fy-center) < height - * - * 0 <= x + (fx - center) x + fx - center < width - * center - x <= fx fx < width + center - x - */ - - fx_start = center - x; - if (fx_start < 0) - fx_start = 0; - fx_end = width + center - x; - if (fx_end > g_size) - fx_end = g_size; - - fy_start = center - y; - if (fy_start < 0) - fy_start = 0; - fy_end = height + center - y; - if (fy_end > g_size) - fy_end = g_size; - - g_line = g_line + fy_start * g_size + fx_start; - - v = 0; - for (fy = fy_start; fy < fy_end; fy++) - { - g_data = g_line; - g_line += g_size; - - for (fx = fx_start; fx < fx_end; fx++) - v += *g_data++; - } - if (v > 1) - v = 1; - - return ((unsigned char) (v * opacity * 255.0)); -} - -/* precompute shadow corners and sides to save time for large windows */ -static void -presum_gaussian (conv *map) -{ - int center = map->size/2; - int opacity, x, y; - - Gsize = map->size; - - if (shadowCorner) - free ((void *)shadowCorner); - if (shadowTop) - free ((void *)shadowTop); - - shadowCorner = (unsigned char *)(malloc ((Gsize + 1) * (Gsize + 1) * 26)); - shadowTop = (unsigned char *)(malloc ((Gsize + 1) * 26)); - - for (x = 0; x <= Gsize; x++) - { - shadowTop[25 * (Gsize + 1) + x] = sum_gaussian (map, 1, x - center, center, Gsize * 2, Gsize * 2); - for(opacity = 0; opacity < 25; opacity++) - shadowTop[opacity * (Gsize + 1) + x] = shadowTop[25 * (Gsize + 1) + x] * opacity / 25; - for(y = 0; y <= x; y++) - { - shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] - = sum_gaussian (map, 1, x - center, y - center, Gsize * 2, Gsize * 2); - shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y] - = shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]; - for(opacity = 0; opacity < 25; opacity++) - shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] - = shadowCorner[opacity * (Gsize + 1) * (Gsize + 1) + x * (Gsize + 1) + y] - = shadowCorner[25 * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x] * opacity / 25; - } - } -} - -static XImage * -make_shadow (Display *dpy, double opacity, int width, int height) -{ - XImage *ximage; - unsigned char *data; - int gsize = gaussianMap->size; - int ylimit, xlimit; - int swidth = width + gsize; - int sheight = height + gsize; - int center = gsize / 2; - int x, y; - unsigned char d; - int x_diff; - int opacity_int = (int)(opacity * 25); - data = malloc (swidth * sheight * sizeof (unsigned char)); - if (!data) - return NULL; - ximage = XCreateImage (dpy, - DefaultVisual(dpy, DefaultScreen(dpy)), - 8, - ZPixmap, - 0, - (char *) data, - swidth, sheight, 8, swidth * sizeof (unsigned char)); - if (!ximage) - { - free (data); - return NULL; - } - /* - * Build the gaussian in sections - */ - - /* - * center (fill the complete data array) - */ - if (Gsize > 0) - d = shadowTop[opacity_int * (Gsize + 1) + Gsize]; - else - d = sum_gaussian (gaussianMap, opacity, center, center, width, height); - memset(data, d, sheight * swidth); - - /* - * corners - */ - ylimit = gsize; - if (ylimit > sheight / 2) - ylimit = (sheight + 1) / 2; - xlimit = gsize; - if (xlimit > swidth / 2) - xlimit = (swidth + 1) / 2; - - for (y = 0; y < ylimit; y++) - for (x = 0; x < xlimit; x++) - { - if (xlimit == Gsize && ylimit == Gsize) - d = shadowCorner[opacity_int * (Gsize + 1) * (Gsize + 1) + y * (Gsize + 1) + x]; - else - d = sum_gaussian (gaussianMap, opacity, x - center, y - center, width, height); - data[y * swidth + x] = d; - data[(sheight - y - 1) * swidth + x] = d; - data[(sheight - y - 1) * swidth + (swidth - x - 1)] = d; - data[y * swidth + (swidth - x - 1)] = d; - } - - /* - * top/bottom - */ - x_diff = swidth - (gsize * 2); - if (x_diff > 0 && ylimit > 0) - { - for (y = 0; y < ylimit; y++) - { - if (ylimit == Gsize) - d = shadowTop[opacity_int * (Gsize + 1) + y]; - else - d = sum_gaussian (gaussianMap, opacity, center, y - center, width, height); - memset (&data[y * swidth + gsize], d, x_diff); - memset (&data[(sheight - y - 1) * swidth + gsize], d, x_diff); - } - } - - /* - * sides - */ - - for (x = 0; x < xlimit; x++) - { - if (xlimit == Gsize) - d = shadowTop[opacity_int * (Gsize + 1) + x]; - else - d = sum_gaussian (gaussianMap, opacity, x - center, center, width, height); - for (y = gsize; y < sheight - gsize; y++) - { - data[y * swidth + x] = d; - data[y * swidth + (swidth - x - 1)] = d; - } - } - - return ximage; -} - -static Picture -shadow_picture (Display *dpy, double opacity, Picture alpha_pict, int width, int height, int *wp, int *hp) -{ - XImage *shadowImage; - Pixmap shadowPixmap; - Picture shadowPicture; - GC gc; - - shadowImage = make_shadow (dpy, opacity, width, height); - if (!shadowImage) - return None; - shadowPixmap = XCreatePixmap (dpy, root, - shadowImage->width, - shadowImage->height, - 8); - if (!shadowPixmap) - { - XDestroyImage (shadowImage); - return None; - } - - shadowPicture = XRenderCreatePicture (dpy, shadowPixmap, - XRenderFindStandardFormat (dpy, PictStandardA8), - 0, NULL); - if (!shadowPicture) - { - XDestroyImage (shadowImage); - XFreePixmap (dpy, shadowPixmap); - return (Picture)None; - } - - gc = XCreateGC (dpy, shadowPixmap, 0, NULL); - if (!gc) - { - XDestroyImage (shadowImage); - XFreePixmap (dpy, shadowPixmap); - XRenderFreePicture (dpy, shadowPicture); - return (Picture)None; - } - - XPutImage (dpy, shadowPixmap, gc, shadowImage, 0, 0, 0, 0, - shadowImage->width, - shadowImage->height); - *wp = shadowImage->width; - *hp = shadowImage->height; - XFreeGC (dpy, gc); - XDestroyImage (shadowImage); - XFreePixmap (dpy, shadowPixmap); - return shadowPicture; -} - -static Picture -solid_picture (Display *dpy, Bool argb, double a, double r, double g, double b) -{ - Pixmap pixmap; - Picture picture; - XRenderPictureAttributes pa; - XRenderColor c; - - pixmap = XCreatePixmap (dpy, root, 1, 1, argb ? 32 : 8); - if (!pixmap) - return None; - - pa.repeat = True; - picture = XRenderCreatePicture (dpy, pixmap, - XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8), - CPRepeat, - &pa); - if (!picture) - { - XFreePixmap (dpy, pixmap); - return None; - } - - c.alpha = a * 0xffff; - c.red = r * 0xffff; - c.green = g * 0xffff; - c.blue = b * 0xffff; - XRenderFillRectangle (dpy, PictOpSrc, picture, &c, 0, 0, 1, 1); - XFreePixmap (dpy, pixmap); - return picture; -} - -static void -discard_ignore (Display *dpy, unsigned long sequence) -{ - while (ignore_head) - { - if ((long) (sequence - ignore_head->sequence) > 0) - { - ignore *next = ignore_head->next; - free (ignore_head); - ignore_head = next; - if (!ignore_head) - ignore_tail = &ignore_head; - } - else - break; - } -} - -static void -set_ignore (Display *dpy, unsigned long sequence) -{ - ignore *i = malloc (sizeof (ignore)); - if (!i) - return; - i->sequence = sequence; - i->next = NULL; - *ignore_tail = i; - ignore_tail = &i->next; -} - -static int -should_ignore (Display *dpy, unsigned long sequence) -{ - discard_ignore (dpy, sequence); - return ignore_head && ignore_head->sequence == sequence; -} - -static win * -find_win (Display *dpy, Window id) -{ - win *w; - - for (w = list; w; w = w->next) - if (w->id == id) - return w; - return NULL; -} - -static const char *backgroundProps[] = { - "_XROOTPMAP_ID", - "_XSETROOT_ID", - NULL, -}; - -static Picture -root_tile (Display *dpy) -{ - Picture picture; - Atom actual_type; - Pixmap pixmap; - int actual_format; - unsigned long nitems; - unsigned long bytes_after; - unsigned char *prop; - Bool fill; - XRenderPictureAttributes pa; - int p; - - pixmap = None; - for (p = 0; backgroundProps[p]; p++) - { - if (XGetWindowProperty (dpy, root, XInternAtom (dpy, backgroundProps[p], False), - 0, 4, False, AnyPropertyType, - &actual_type, &actual_format, &nitems, &bytes_after, &prop) == Success && - actual_type == XInternAtom (dpy, "PIXMAP", False) && actual_format == 32 && nitems == 1) - { - memcpy (&pixmap, prop, 4); - XFree (prop); - fill = False; - break; - } - } - if (!pixmap) - { - pixmap = XCreatePixmap (dpy, root, 1, 1, DefaultDepth (dpy, scr)); - fill = True; - } - pa.repeat = True; - picture = XRenderCreatePicture (dpy, pixmap, - XRenderFindVisualFormat (dpy, - DefaultVisual (dpy, scr)), - CPRepeat, &pa); - if (fill) - { - XRenderColor c; - - c.red = c.green = c.blue = 0x8080; - c.alpha = 0xffff; - XRenderFillRectangle (dpy, PictOpSrc, picture, &c, - 0, 0, 1, 1); - } - return picture; -} - -static void -paint_root (Display *dpy) -{ - if (!rootTile) - rootTile = root_tile (dpy); - - XRenderComposite (dpy, PictOpSrc, - rootTile, None, rootBuffer, - 0, 0, 0, 0, 0, 0, root_width, root_height); -} - -static XserverRegion -win_extents (Display *dpy, win *w) -{ - XRectangle r; - - r.x = w->a.x; - r.y = w->a.y; - r.width = w->a.width + w->a.border_width * 2; - r.height = w->a.height + w->a.border_width * 2; - if (compMode != CompSimple && !(w->windowType == winDockAtom && excludeDockShadows)) - { - if (compMode == CompServerShadows || w->mode != WINDOW_ARGB) - { - XRectangle sr; - - if (compMode == CompServerShadows) - { - w->shadow_dx = 2; - w->shadow_dy = 7; - w->shadow_width = w->a.width; - w->shadow_height = w->a.height; - } - else - { - w->shadow_dx = shadowOffsetX; - w->shadow_dy = shadowOffsetY; - if (!w->shadow) - { - double opacity = shadowOpacity; - if (w->mode == WINDOW_TRANS) - opacity = opacity * ((double)w->opacity)/((double)OPAQUE); - w->shadow = shadow_picture (dpy, opacity, w->alphaPict, - w->a.width + w->a.border_width * 2, - w->a.height + w->a.border_width * 2, - &w->shadow_width, &w->shadow_height); - } - } - sr.x = w->a.x + w->shadow_dx; - sr.y = w->a.y + w->shadow_dy; - sr.width = w->shadow_width; - sr.height = w->shadow_height; - if (sr.x < r.x) - { - r.width = (r.x + r.width) - sr.x; - r.x = sr.x; - } - if (sr.y < r.y) - { - r.height = (r.y + r.height) - sr.y; - r.y = sr.y; - } - if (sr.x + sr.width > r.x + r.width) - r.width = sr.x + sr.width - r.x; - if (sr.y + sr.height > r.y + r.height) - r.height = sr.y + sr.height - r.y; - } - } - return XFixesCreateRegion (dpy, &r, 1); -} - -static XserverRegion -border_size (Display *dpy, win *w) -{ - XserverRegion border; - /* - * if window doesn't exist anymore, this will generate an error - * as well as not generate a region. Perhaps a better XFixes - * architecture would be to have a request that copies instead - * of creates, that way you'd just end up with an empty region - * instead of an invalid XID. - */ - set_ignore (dpy, NextRequest (dpy)); - border = XFixesCreateRegionFromWindow (dpy, w->id, WindowRegionBounding); - /* translate this */ - set_ignore (dpy, NextRequest (dpy)); - XFixesTranslateRegion (dpy, border, - w->a.x + w->a.border_width, - w->a.y + w->a.border_width); - return border; -} - -static void -paint_all (Display *dpy, XserverRegion region) -{ - win *w; - win *t = NULL; - - if (!region) - { - XRectangle r; - r.x = 0; - r.y = 0; - r.width = root_width; - r.height = root_height; - region = XFixesCreateRegion (dpy, &r, 1); - } -#if MONITOR_REPAINT - rootBuffer = rootPicture; -#else - if (!rootBuffer) - { - Pixmap rootPixmap = XCreatePixmap (dpy, root, root_width, root_height, - DefaultDepth (dpy, scr)); - rootBuffer = XRenderCreatePicture (dpy, rootPixmap, - XRenderFindVisualFormat (dpy, - DefaultVisual (dpy, scr)), - 0, NULL); - XFreePixmap (dpy, rootPixmap); - } -#endif - XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region); -#if MONITOR_REPAINT - XRenderComposite (dpy, PictOpSrc, blackPicture, None, rootPicture, - 0, 0, 0, 0, 0, 0, root_width, root_height); -#endif -#if DEBUG_REPAINT - printf ("paint:"); -#endif - for (w = list; w; w = w->next) - { -#if CAN_DO_USABLE - if (!w->usable) - continue; -#endif - /* never painted, ignore it */ - if (!w->damaged) - continue; - /* if invisible, ignore it */ - if (w->a.x + w->a.width < 1 || w->a.y + w->a.height < 1 - || w->a.x >= root_width || w->a.y >= root_height) - continue; - if (!w->picture) - { - XRenderPictureAttributes pa; - XRenderPictFormat *format; - Drawable draw = w->id; - -#if HAS_NAME_WINDOW_PIXMAP - if (hasNamePixmap && !w->pixmap) - w->pixmap = XCompositeNameWindowPixmap (dpy, w->id); - if (w->pixmap) - draw = w->pixmap; -#endif - format = XRenderFindVisualFormat (dpy, w->a.visual); - pa.subwindow_mode = IncludeInferiors; - w->picture = XRenderCreatePicture (dpy, draw, - format, - CPSubwindowMode, - &pa); - } -#if DEBUG_REPAINT - printf (" 0x%x", w->id); -#endif - if (clipChanged) - { - if (w->borderSize) - { - set_ignore (dpy, NextRequest (dpy)); - XFixesDestroyRegion (dpy, w->borderSize); - w->borderSize = None; - } - if (w->extents) - { - XFixesDestroyRegion (dpy, w->extents); - w->extents = None; - } - if (w->borderClip) - { - XFixesDestroyRegion (dpy, w->borderClip); - w->borderClip = None; - } - } - if (!w->borderSize) - w->borderSize = border_size (dpy, w); - if (!w->extents) - w->extents = win_extents (dpy, w); - if (w->mode == WINDOW_SOLID) - { - int x, y, wid, hei; -#if HAS_NAME_WINDOW_PIXMAP - x = w->a.x; - y = w->a.y; - wid = w->a.width + w->a.border_width * 2; - hei = w->a.height + w->a.border_width * 2; -#else - x = w->a.x + w->a.border_width; - y = w->a.y + w->a.border_width; - wid = w->a.width; - hei = w->a.height; -#endif - XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region); - set_ignore (dpy, NextRequest (dpy)); - XFixesSubtractRegion (dpy, region, region, w->borderSize); - set_ignore (dpy, NextRequest (dpy)); - XRenderComposite (dpy, PictOpSrc, w->picture, None, rootBuffer, - 0, 0, 0, 0, - x, y, wid, hei); - } - if (!w->borderClip) - { - w->borderClip = XFixesCreateRegion (dpy, NULL, 0); - XFixesCopyRegion (dpy, w->borderClip, region); - XFixesIntersectRegion(dpy, w->borderClip, w->borderClip, w->borderSize); - } - w->prev_trans = t; - t = w; - } -#if DEBUG_REPAINT - printf ("\n"); - fflush (stdout); -#endif - XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region); - paint_root (dpy); - for (w = t; w; w = w->prev_trans) - { - XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip); - switch (compMode) { - case CompSimple: - break; - case CompServerShadows: - /* dont' bother drawing shadows on desktop windows */ - if (w->windowType == winDesktopAtom) - break; - set_ignore (dpy, NextRequest (dpy)); - if (w->opacity != OPAQUE && !w->shadowPict) - w->shadowPict = solid_picture (dpy, True, - (double) w->opacity / OPAQUE * 0.3, - 0, 0, 0); - XRenderComposite (dpy, PictOpOver, - w->shadowPict ? w->shadowPict : transBlackPicture, - w->picture, rootBuffer, - 0, 0, 0, 0, - w->a.x + w->shadow_dx, - w->a.y + w->shadow_dy, - w->shadow_width, w->shadow_height); - break; - case CompClientShadows: - /* don't bother drawing shadows on desktop windows */ - if (w->shadow && w->windowType != winDesktopAtom) - { - XRenderComposite (dpy, PictOpOver, blackPicture, w->shadow, rootBuffer, - 0, 0, 0, 0, - w->a.x + w->shadow_dx, - w->a.y + w->shadow_dy, - w->shadow_width, w->shadow_height); - } - break; - } - if (w->opacity != OPAQUE && !w->alphaPict) - w->alphaPict = solid_picture (dpy, False, - (double) w->opacity / OPAQUE, 0, 0, 0); - if (w->mode == WINDOW_TRANS) - { - int x, y, wid, hei; -#if HAS_NAME_WINDOW_PIXMAP - x = w->a.x; - y = w->a.y; - wid = w->a.width + w->a.border_width * 2; - hei = w->a.height + w->a.border_width * 2; -#else - x = w->a.x + w->a.border_width; - y = w->a.y + w->a.border_width; - wid = w->a.width; - hei = w->a.height; -#endif - set_ignore (dpy, NextRequest (dpy)); - XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer, - 0, 0, 0, 0, - x, y, wid, hei); - } - else if (w->mode == WINDOW_ARGB) - { - int x, y, wid, hei; -#if HAS_NAME_WINDOW_PIXMAP - x = w->a.x; - y = w->a.y; - wid = w->a.width + w->a.border_width * 2; - hei = w->a.height + w->a.border_width * 2; -#else - x = w->a.x + w->a.border_width; - y = w->a.y + w->a.border_width; - wid = w->a.width; - hei = w->a.height; -#endif - set_ignore (dpy, NextRequest (dpy)); - XRenderComposite (dpy, PictOpOver, w->picture, w->alphaPict, rootBuffer, - 0, 0, 0, 0, - x, y, wid, hei); - } - XFixesDestroyRegion (dpy, w->borderClip); - w->borderClip = None; - } - XFixesDestroyRegion (dpy, region); - if (rootBuffer != rootPicture) - { - XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, None); - XRenderComposite (dpy, PictOpSrc, rootBuffer, None, rootPicture, - 0, 0, 0, 0, 0, 0, root_width, root_height); - } -} - -static void -add_damage (Display *dpy, XserverRegion damage) -{ - if (allDamage) - { - XFixesUnionRegion (dpy, allDamage, allDamage, damage); - XFixesDestroyRegion (dpy, damage); - } - else - allDamage = damage; -} - -static void -repair_win (Display *dpy, win *w) -{ - XserverRegion parts; - - if (!w->damaged) - { - parts = win_extents (dpy, w); - set_ignore (dpy, NextRequest (dpy)); - XDamageSubtract (dpy, w->damage, None, None); - } - else - { - XserverRegion o; - parts = XFixesCreateRegion (dpy, NULL, 0); - set_ignore (dpy, NextRequest (dpy)); - XDamageSubtract (dpy, w->damage, None, parts); - XFixesTranslateRegion (dpy, parts, - w->a.x + w->a.border_width, - w->a.y + w->a.border_width); - if (compMode == CompServerShadows) - { - o = XFixesCreateRegion (dpy, NULL, 0); - XFixesCopyRegion (dpy, o, parts); - XFixesTranslateRegion (dpy, o, w->shadow_dx, w->shadow_dy); - XFixesUnionRegion (dpy, parts, parts, o); - XFixesDestroyRegion (dpy, o); - } - } - add_damage (dpy, parts); - w->damaged = 1; -} - -static unsigned int -get_opacity_prop (Display *dpy, win *w, unsigned int def); - -static void -map_win (Display *dpy, Window id, unsigned long sequence, Bool fade) -{ - win *w = find_win (dpy, id); - - if (!w) - return; - - w->a.map_state = IsViewable; - - /* This needs to be here or else we lose transparency messages */ - XSelectInput (dpy, id, PropertyChangeMask); - - /* This needs to be here since we don't get PropertyNotify when unmapped */ - w->opacity = get_opacity_prop (dpy, w, OPAQUE); - determine_mode (dpy, w); - -#if CAN_DO_USABLE - w->damage_bounds.x = w->damage_bounds.y = 0; - w->damage_bounds.width = w->damage_bounds.height = 0; -#endif - w->damaged = 0; - - if (fade && fadeWindows) - set_fade (dpy, w, 0, get_opacity_percent (dpy, w, 1.0), fade_in_step, NULL, False, True, True); -} - -static void -finish_unmap_win (Display *dpy, win *w) -{ - w->damaged = 0; -#if CAN_DO_USABLE - w->usable = False; -#endif - if (w->extents != None) - { - add_damage (dpy, w->extents); /* destroys region */ - w->extents = None; - } - -#if HAS_NAME_WINDOW_PIXMAP - if (w->pixmap) - { - XFreePixmap (dpy, w->pixmap); - w->pixmap = None; - } -#endif - - if (w->picture) - { - set_ignore (dpy, NextRequest (dpy)); - XRenderFreePicture (dpy, w->picture); - w->picture = None; - } - - /* don't care about properties anymore */ - set_ignore (dpy, NextRequest (dpy)); - XSelectInput(dpy, w->id, 0); - - if (w->borderSize) - { - set_ignore (dpy, NextRequest (dpy)); - XFixesDestroyRegion (dpy, w->borderSize); - w->borderSize = None; - } - if (w->shadow) - { - XRenderFreePicture (dpy, w->shadow); - w->shadow = None; - } - if (w->borderClip) - { - XFixesDestroyRegion (dpy, w->borderClip); - w->borderClip = None; - } - - clipChanged = True; -} - -#if HAS_NAME_WINDOW_PIXMAP -static void -unmap_callback (Display *dpy, win *w, Bool gone) -{ - finish_unmap_win (dpy, w); -} -#endif - -static void -unmap_win (Display *dpy, Window id, Bool fade) -{ - win *w = find_win (dpy, id); - if (!w) - return; - w->a.map_state = IsUnmapped; -#if HAS_NAME_WINDOW_PIXMAP - if (w->pixmap && fade && fadeWindows) - set_fade (dpy, w, w->opacity*1.0/OPAQUE, 0.0, fade_out_step, unmap_callback, False, False, True); - else -#endif - finish_unmap_win (dpy, w); -} - -/* Get the opacity prop from window - not found: default - otherwise the value - */ -static unsigned int -get_opacity_prop(Display *dpy, win *w, unsigned int def) -{ - Atom actual; - int format; - unsigned long n, left; - - unsigned char *data; - int result = XGetWindowProperty(dpy, w->id, opacityAtom, 0L, 1L, False, - XA_CARDINAL, &actual, &format, - &n, &left, &data); - if (result == Success && data != NULL) - { - unsigned int i; - memcpy (&i, data, sizeof (unsigned int)); - XFree( (void *) data); - return i; - } - return def; -} - -/* Get the opacity property from the window in a percent format - not found: default - otherwise: the value -*/ -static double -get_opacity_percent(Display *dpy, win *w, double def) -{ - unsigned int opacity = get_opacity_prop (dpy, w, (unsigned int)(OPAQUE*def)); - - return opacity*1.0/OPAQUE; -} - -/* determine mode for window all in one place. - Future might check for menu flag and other cool things -*/ - -static Atom -get_wintype_prop(Display * dpy, Window w) -{ - Atom actual; - int format; - unsigned long n, left; - - unsigned char *data; - int result = XGetWindowProperty (dpy, w, winTypeAtom, 0L, 1L, False, - XA_ATOM, &actual, &format, - &n, &left, &data); - - if (result == Success && data != (unsigned char *)None) - { - Atom a; - memcpy (&a, data, sizeof (Atom)); - XFree ( (void *) data); - return a; - } - return winNormalAtom; -} - -static void -determine_mode(Display *dpy, win *w) -{ - int mode; - XRenderPictFormat *format; - - /* if trans prop == -1 fall back on previous tests*/ - - if (w->alphaPict) - { - XRenderFreePicture (dpy, w->alphaPict); - w->alphaPict = None; - } - if (w->shadowPict) - { - XRenderFreePicture (dpy, w->shadowPict); - w->shadowPict = None; - } - - if (w->a.class == InputOnly) - { - format = NULL; - } - else - { - format = XRenderFindVisualFormat (dpy, w->a.visual); - } - - if (format && format->type == PictTypeDirect && format->direct.alphaMask) - { - mode = WINDOW_ARGB; - } - else if (w->opacity != OPAQUE) - { - mode = WINDOW_TRANS; - } - else - { - mode = WINDOW_SOLID; - } - w->mode = mode; - if (w->extents) - { - XserverRegion damage; - damage = XFixesCreateRegion (dpy, NULL, 0); - XFixesCopyRegion (dpy, damage, w->extents); - add_damage (dpy, damage); - } -} - -static Atom -determine_wintype (Display *dpy, Window w) -{ - Window root_return, parent_return; - Window *children = NULL; - unsigned int nchildren, i; - Atom type; - - type = get_wintype_prop (dpy, w); - if (type != winNormalAtom) - return type; - - if (!XQueryTree (dpy, w, &root_return, &parent_return, &children, - &nchildren)) - { - /* XQueryTree failed. */ - if (children) - XFree ((void *)children); - return winNormalAtom; - } - - for (i = 0;i < nchildren;i++) - { - type = determine_wintype (dpy, children[i]); - if (type != winNormalAtom) - return type; - } - - if (children) - XFree ((void *)children); - - return winNormalAtom; -} - -static void -add_win (Display *dpy, Window id, Window prev) -{ - win *new = malloc (sizeof (win)); - win **p; - - if (!new) - return; - if (prev) - { - for (p = &list; *p; p = &(*p)->next) - if ((*p)->id == prev) - break; - } - else - p = &list; - new->id = id; - set_ignore (dpy, NextRequest (dpy)); - if (!XGetWindowAttributes (dpy, id, &new->a)) - { - free (new); - return; - } - new->shaped = False; - new->shape_bounds.x = new->a.x; - new->shape_bounds.y = new->a.y; - new->shape_bounds.width = new->a.width; - new->shape_bounds.height = new->a.height; - new->damaged = 0; -#if CAN_DO_USABLE - new->usable = False; -#endif -#if HAS_NAME_WINDOW_PIXMAP - new->pixmap = None; -#endif - new->picture = None; - if (new->a.class == InputOnly) - { - new->damage_sequence = 0; - new->damage = None; - } - else - { - new->damage_sequence = NextRequest (dpy); - new->damage = XDamageCreate (dpy, id, XDamageReportNonEmpty); - XShapeSelectInput (dpy, id, ShapeNotifyMask); - } - new->alphaPict = None; - new->shadowPict = None; - new->borderSize = None; - new->extents = None; - new->shadow = None; - new->shadow_dx = 0; - new->shadow_dy = 0; - new->shadow_width = 0; - new->shadow_height = 0; - new->opacity = OPAQUE; - - new->borderClip = None; - new->prev_trans = NULL; - - new->windowType = determine_wintype (dpy, new->id); - - new->next = *p; - *p = new; - if (new->a.map_state == IsViewable) - map_win (dpy, id, new->damage_sequence - 1, True); -} - -static void -restack_win (Display *dpy, win *w, Window new_above) -{ - Window old_above; - - if (w->next) - old_above = w->next->id; - else - old_above = None; - if (old_above != new_above) - { - win **prev; - - /* unhook */ - for (prev = &list; *prev; prev = &(*prev)->next) - if ((*prev) == w) - break; - *prev = w->next; - - /* rehook */ - for (prev = &list; *prev; prev = &(*prev)->next) - { - if ((*prev)->id == new_above) - break; - } - w->next = *prev; - *prev = w; - } -} - -static void -configure_win (Display *dpy, XConfigureEvent *ce) -{ - win *w = find_win (dpy, ce->window); - XserverRegion damage = None; - - if (!w) - { - if (ce->window == root) - { - if (rootBuffer) - { - XRenderFreePicture (dpy, rootBuffer); - rootBuffer = None; - } - root_width = ce->width; - root_height = ce->height; - } - return; - } -#if CAN_DO_USABLE - if (w->usable) -#endif - { - damage = XFixesCreateRegion (dpy, NULL, 0); - if (w->extents != None) - XFixesCopyRegion (dpy, damage, w->extents); - } - w->shape_bounds.x -= w->a.x; - w->shape_bounds.y -= w->a.y; - w->a.x = ce->x; - w->a.y = ce->y; - if (w->a.width != ce->width || w->a.height != ce->height) - { -#if HAS_NAME_WINDOW_PIXMAP - if (w->pixmap) - { - XFreePixmap (dpy, w->pixmap); - w->pixmap = None; - if (w->picture) - { - XRenderFreePicture (dpy, w->picture); - w->picture = None; - } - } -#endif - if (w->shadow) - { - XRenderFreePicture (dpy, w->shadow); - w->shadow = None; - } - } - w->a.width = ce->width; - w->a.height = ce->height; - w->a.border_width = ce->border_width; - w->a.override_redirect = ce->override_redirect; - restack_win (dpy, w, ce->above); - if (damage) - { - XserverRegion extents = win_extents (dpy, w); - XFixesUnionRegion (dpy, damage, damage, extents); - XFixesDestroyRegion (dpy, extents); - add_damage (dpy, damage); - } - w->shape_bounds.x += w->a.x; - w->shape_bounds.y += w->a.y; - if (!w->shaped) - { - w->shape_bounds.width = w->a.width; - w->shape_bounds.height = w->a.height; - } - - clipChanged = True; -} - -static void -circulate_win (Display *dpy, XCirculateEvent *ce) -{ - win *w = find_win (dpy, ce->window); - Window new_above; - - if (!w) - return; - - if (ce->place == PlaceOnTop) - new_above = list->id; - else - new_above = None; - restack_win (dpy, w, new_above); - clipChanged = True; -} - -static void -finish_destroy_win (Display *dpy, Window id, Bool gone) -{ - win **prev, *w; - - for (prev = &list; (w = *prev); prev = &w->next) - if (w->id == id) - { - if (gone) - finish_unmap_win (dpy, w); - *prev = w->next; - if (w->picture) - { - set_ignore (dpy, NextRequest (dpy)); - XRenderFreePicture (dpy, w->picture); - w->picture = None; - } - if (w->alphaPict) - { - XRenderFreePicture (dpy, w->alphaPict); - w->alphaPict = None; - } - if (w->shadowPict) - { - XRenderFreePicture (dpy, w->shadowPict); - w->shadowPict = None; - } - if (w->shadow) - { - XRenderFreePicture (dpy, w->shadow); - w->shadow = None; - } - if (w->damage != None) - { - set_ignore (dpy, NextRequest (dpy)); - XDamageDestroy (dpy, w->damage); - w->damage = None; - } - cleanup_fade (dpy, w); - free (w); - break; - } -} - -#if HAS_NAME_WINDOW_PIXMAP -static void -destroy_callback (Display *dpy, win *w, Bool gone) -{ - finish_destroy_win (dpy, w->id, gone); -} -#endif - -static void -destroy_win (Display *dpy, Window id, Bool gone, Bool fade) -{ - win *w = find_win (dpy, id); -#if HAS_NAME_WINDOW_PIXMAP - if (w && w->pixmap && fade && fadeWindows) - set_fade (dpy, w, w->opacity*1.0/OPAQUE, 0.0, fade_out_step, destroy_callback, gone, False, True); - else -#endif - { - finish_destroy_win (dpy, id, gone); - } -} - -/* -static void -dump_win (win *w) -{ - printf ("\t%08lx: %d x %d + %d + %d (%d)\n", w->id, - w->a.width, w->a.height, w->a.x, w->a.y, w->a.border_width); -} - - -static void -dump_wins (void) -{ - win *w; - - printf ("windows:\n"); - for (w = list; w; w = w->next) - dump_win (w); -} -*/ - -static void -damage_win (Display *dpy, XDamageNotifyEvent *de) -{ - win *w = find_win (dpy, de->drawable); - - if (!w) - return; -#if CAN_DO_USABLE - if (!w->usable) - { - if (w->damage_bounds.width == 0 || w->damage_bounds.height == 0) - { - w->damage_bounds = de->area; - } - else - { - if (de->area.x < w->damage_bounds.x) - { - w->damage_bounds.width += (w->damage_bounds.x - de->area.x); - w->damage_bounds.x = de->area.x; - } - if (de->area.y < w->damage_bounds.y) - { - w->damage_bounds.height += (w->damage_bounds.y - de->area.y); - w->damage_bounds.y = de->area.y; - } - if (de->area.x + de->area.width > w->damage_bounds.x + w->damage_bounds.width) - w->damage_bounds.width = de->area.x + de->area.width - w->damage_bounds.x; - if (de->area.y + de->area.height > w->damage_bounds.y + w->damage_bounds.height) - w->damage_bounds.height = de->area.y + de->area.height - w->damage_bounds.y; - } -#if 0 - printf ("unusable damage %d, %d: %d x %d bounds %d, %d: %d x %d\n", - de->area.x, - de->area.y, - de->area.width, - de->area.height, - w->damage_bounds.x, - w->damage_bounds.y, - w->damage_bounds.width, - w->damage_bounds.height); -#endif - if (w->damage_bounds.x <= 0 && - w->damage_bounds.y <= 0 && - w->a.width <= w->damage_bounds.x + w->damage_bounds.width && - w->a.height <= w->damage_bounds.y + w->damage_bounds.height) - { - clipChanged = True; - if (fadeWindows) - set_fade (dpy, w, 0, get_opacity_percent (dpy, w, 1.0), fade_in_step, 0, False, True, True); - w->usable = True; - } - } - if (w->usable) -#endif - repair_win (dpy, w); -} - -#if DEBUG_SHAPE -static const char * -shape_kind(int kind) -{ - static char buf[128]; - - switch(kind){ - case ShapeBounding: - return "ShapeBounding"; - case ShapeClip: - return "ShapeClip"; - case ShapeInput: - return "ShapeInput"; - default: - sprintf (buf, "Shape %d", kind); - return buf; - } -} -#endif - -static void -shape_win (Display *dpy, XShapeEvent *se) -{ - win *w = find_win (dpy, se->window); - - if (!w) - return; - - if (se->kind == ShapeClip || se->kind == ShapeBounding) - { - XserverRegion region0; - XserverRegion region1; - -#if DEBUG_SHAPE - printf("win 0x%lx %s:%s %ux%u+%d+%d\n", - (unsigned long) se->window, - shape_kind(se->kind), - (se->shaped == True) ? "true" : "false", - se->width, se->height, - se->x, se->y); -#endif - - clipChanged = True; - - region0 = XFixesCreateRegion (dpy, &w->shape_bounds, 1); - - if (se->shaped == True) - { - w->shaped = True; - w->shape_bounds.x = w->a.x + se->x; - w->shape_bounds.y = w->a.y + se->y; - w->shape_bounds.width = se->width; - w->shape_bounds.height = se->height; - } - else - { - w->shaped = False; - w->shape_bounds.x = w->a.x; - w->shape_bounds.y = w->a.y; - w->shape_bounds.width = w->a.width; - w->shape_bounds.height = w->a.height; - } - - region1 = XFixesCreateRegion (dpy, &w->shape_bounds, 1); - XFixesUnionRegion (dpy, region0, region0, region1); - XFixesDestroyRegion (dpy, region1); - - /* ask for repaint of the old and new region */ - paint_all (dpy, region0); - } -} - -static int -error (Display *dpy, XErrorEvent *ev) -{ - int o; - const char *name = NULL; - static char buffer[256]; - - if (should_ignore (dpy, ev->serial)) - return 0; - - if (ev->request_code == composite_opcode && - ev->minor_code == X_CompositeRedirectSubwindows) - { - fprintf (stderr, "Another composite manager is already running\n"); - exit (1); - } - - o = ev->error_code - xfixes_error; - switch (o) { - case BadRegion: name = "BadRegion"; break; - default: break; - } - o = ev->error_code - damage_error; - switch (o) { - case BadDamage: name = "BadDamage"; break; - default: break; - } - o = ev->error_code - render_error; - switch (o) { - case BadPictFormat: name ="BadPictFormat"; break; - case BadPicture: name ="BadPicture"; break; - case BadPictOp: name ="BadPictOp"; break; - case BadGlyphSet: name ="BadGlyphSet"; break; - case BadGlyph: name ="BadGlyph"; break; - default: break; - } - - if (name == NULL) - { - buffer[0] = '\0'; - XGetErrorText (dpy, ev->error_code, buffer, sizeof (buffer)); - name = buffer; - } - - fprintf (stderr, "error %d: %s request %d minor %d serial %lu\n", - ev->error_code, (strlen (name) > 0) ? name : "unknown", - ev->request_code, ev->minor_code, ev->serial); - -/* abort (); this is just annoying to most people */ - return 0; -} - -static void -expose_root (Display *dpy, Window root, XRectangle *rects, int nrects) -{ - XserverRegion region = XFixesCreateRegion (dpy, rects, nrects); - - add_damage (dpy, region); -} - -#if DEBUG_EVENTS -static int -ev_serial (XEvent *ev) -{ - if (ev->type & 0x7f != KeymapNotify) - return ev->xany.serial; - return NextRequest (ev->xany.display); -} - -static char * -ev_name (XEvent *ev) -{ - static char buf[128]; - switch (ev->type & 0x7f) { - case Expose: - return "Expose"; - case MapNotify: - return "Map"; - case UnmapNotify: - return "Unmap"; - case ReparentNotify: - return "Reparent"; - case CirculateNotify: - return "Circulate"; - default: - if (ev->type == damage_event + XDamageNotify) - { - return "Damage"; - } - else if (ev->type == xshape_event + ShapeNotify) - { - return "Shape"; - } - sprintf (buf, "Event %d", ev->type); - return buf; - } -} - -static Window -ev_window (XEvent *ev) -{ - switch (ev->type) { - case Expose: - return ev->xexpose.window; - case MapNotify: - return ev->xmap.window; - case UnmapNotify: - return ev->xunmap.window; - case ReparentNotify: - return ev->xreparent.window; - case CirculateNotify: - return ev->xcirculate.window; - default: - if (ev->type == damage_event + XDamageNotify) - { - return ((XDamageNotifyEvent *) ev)->drawable; - } - else if (ev->type == xshape_event + ShapeNotify) - { - return ((XShapeEvent *) ev)->window; - } - return 0; - } -} -#endif - -static void -usage (const char *program) -{ - fprintf (stderr, "%s v%s\n", program, PACKAGE_VERSION); - fprintf (stderr, "usage: %s [options]\n%s\n", program, - "Options:\n" - " -d display\n" - " Specifies which display should be managed.\n" - " -r radius\n" - " Specifies the blur radius for client-side shadows. (default 12)\n" - " -o opacity\n" - " Specifies the translucency for client-side shadows. (default .75)\n" - " -l left-offset\n" - " Specifies the left offset for client-side shadows. (default -15)\n" - " -t top-offset\n" - " Specifies the top offset for clinet-side shadows. (default -15)\n" - " -I fade-in-step\n" - " Specifies the opacity change between steps while fading in. (default 0.028)\n" - " -O fade-out-step\n" - " Specifies the opacity change between steps while fading out. (default 0.03)\n" - " -D fade-delta-time\n" - " Specifies the time between steps in a fade in milliseconds. (default 10)\n" - " -a\n" - " Use automatic server-side compositing. Faster, but no special effects.\n" - " -c\n" - " Draw client-side shadows with fuzzy edges.\n" - " -C\n" - " Avoid drawing shadows on dock/panel windows.\n" - " -f\n" - " Fade windows in/out when opening/closing.\n" - " -F\n" - " Fade windows during opacity changes.\n" - " -n\n" - " Normal client-side compositing with transparency support\n" - " -s\n" - " Draw server-side shadows with sharp edges.\n" - " -S\n" - " Enable synchronous operation (for debugging).\n" - ); - exit (1); -} - -static Bool -register_cm (Display *dpy) -{ - Window w; - Atom a; - static char net_wm_cm[] = "_NET_WM_CM_Sxx"; - - snprintf (net_wm_cm, sizeof (net_wm_cm), "_NET_WM_CM_S%d", scr); - a = XInternAtom (dpy, net_wm_cm, False); - - w = XGetSelectionOwner (dpy, a); - if (w != None) - { - XTextProperty tp; - char **strs; - int count; - Atom winNameAtom = XInternAtom (dpy, "_NET_WM_NAME", False); - - if (!XGetTextProperty (dpy, w, &tp, winNameAtom) && - !XGetTextProperty (dpy, w, &tp, XA_WM_NAME)) - { - fprintf (stderr, - "Another composite manager is already running (0x%lx)\n", - (unsigned long) w); - return False; - } - if (XmbTextPropertyToTextList (dpy, &tp, &strs, &count) == Success) - { - fprintf (stderr, - "Another composite manager is already running (%s)\n", - strs[0]); - - XFreeStringList (strs); - } - - XFree (tp.value); - - return False; - } - - w = XCreateSimpleWindow (dpy, RootWindow (dpy, scr), 0, 0, 1, 1, 0, None, - None); - - Xutf8SetWMProperties (dpy, w, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL, - NULL); - - XSetSelectionOwner (dpy, a, w, 0); - - return True; -} - -int -main (int argc, char **argv) -{ - Display *dpy; - XEvent ev; - Window root_return, parent_return; - Window *children; - unsigned int nchildren; - int i; - XRenderPictureAttributes pa; - XRectangle *expose_rects = NULL; - int size_expose = 0; - int n_expose = 0; - struct pollfd ufd; - int p; - int composite_major, composite_minor; - char *display = NULL; - int o; - - while ((o = getopt (argc, argv, "D:I:O:d:r:o:l:t:scnfFCaS")) != -1) - { - switch (o) { - case 'd': - display = optarg; - break; - case 'D': - fade_delta = atoi (optarg); - if (fade_delta < 1) - fade_delta = 10; - break; - case 'I': - fade_in_step = atof (optarg); - if (fade_in_step <= 0) - fade_in_step = 0.01; - break; - case 'O': - fade_out_step = atof (optarg); - if (fade_out_step <= 0) - fade_out_step = 0.01; - break; - case 's': - compMode = CompServerShadows; - break; - case 'c': - compMode = CompClientShadows; - break; - case 'C': - excludeDockShadows = True; - break; - case 'n': - compMode = CompSimple; - break; - case 'f': - fadeWindows = True; - break; - case 'F': - fadeTrans = True; - break; - case 'a': - autoRedirect = True; - break; - case 'S': - synchronize = True; - break; - case 'r': - shadowRadius = atoi (optarg); - break; - case 'o': - shadowOpacity = atof (optarg); - break; - case 'l': - shadowOffsetX = atoi (optarg); - break; - case 't': - shadowOffsetY = atoi (optarg); - break; - default: - usage (argv[0]); - break; - } - } - - dpy = XOpenDisplay (display); - if (!dpy) - { - fprintf (stderr, "Can't open display\n"); - exit (1); - } - XSetErrorHandler (error); - if (synchronize) - XSynchronize (dpy, 1); - scr = DefaultScreen (dpy); - root = RootWindow (dpy, scr); - - if (!XRenderQueryExtension (dpy, &render_event, &render_error)) - { - fprintf (stderr, "No render extension\n"); - exit (1); - } - if (!XQueryExtension (dpy, COMPOSITE_NAME, &composite_opcode, - &composite_event, &composite_error)) - { - fprintf (stderr, "No composite extension\n"); - exit (1); - } - XCompositeQueryVersion (dpy, &composite_major, &composite_minor); -#if HAS_NAME_WINDOW_PIXMAP - if (composite_major > 0 || composite_minor >= 2) - hasNamePixmap = True; -#endif - - if (!XDamageQueryExtension (dpy, &damage_event, &damage_error)) - { - fprintf (stderr, "No damage extension\n"); - exit (1); - } - if (!XFixesQueryExtension (dpy, &xfixes_event, &xfixes_error)) - { - fprintf (stderr, "No XFixes extension\n"); - exit (1); - } - if (!XShapeQueryExtension (dpy, &xshape_event, &xshape_error)) - { - fprintf (stderr, "No XShape extension\n"); - exit (1); - } - - if (!register_cm(dpy)) - { - exit (1); - } - - /* get atoms */ - opacityAtom = XInternAtom (dpy, OPACITY_PROP, False); - winTypeAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", False); - winDesktopAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False); - winDockAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); - winToolbarAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False); - winMenuAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", False); - winUtilAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False); - winSplashAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False); - winDialogAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False); - winNormalAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False); - - pa.subwindow_mode = IncludeInferiors; - - if (compMode == CompClientShadows) - { - gaussianMap = make_gaussian_map(dpy, shadowRadius); - presum_gaussian (gaussianMap); - } - - root_width = DisplayWidth (dpy, scr); - root_height = DisplayHeight (dpy, scr); - - rootPicture = XRenderCreatePicture (dpy, root, - XRenderFindVisualFormat (dpy, - DefaultVisual (dpy, scr)), - CPSubwindowMode, - &pa); - blackPicture = solid_picture (dpy, True, 1, 0, 0, 0); - if (compMode == CompServerShadows) - transBlackPicture = solid_picture (dpy, True, 0.3, 0, 0, 0); - allDamage = None; - clipChanged = True; - XGrabServer (dpy); - if (autoRedirect) - XCompositeRedirectSubwindows (dpy, root, CompositeRedirectAutomatic); - else - { - XCompositeRedirectSubwindows (dpy, root, CompositeRedirectManual); - XSelectInput (dpy, root, - SubstructureNotifyMask| - ExposureMask| - StructureNotifyMask| - PropertyChangeMask); - XShapeSelectInput (dpy, root, ShapeNotifyMask); - XQueryTree (dpy, root, &root_return, &parent_return, &children, &nchildren); - for (i = 0; i < nchildren; i++) - add_win (dpy, children[i], i ? children[i-1] : None); - XFree (children); - } - XUngrabServer (dpy); - ufd.fd = ConnectionNumber (dpy); - ufd.events = POLLIN; - if (!autoRedirect) - paint_all (dpy, None); - for (;;) - { - /* dump_wins (); */ - do { - if (autoRedirect) - XFlush (dpy); - if (!QLength (dpy)) - { - if (poll (&ufd, 1, fade_timeout()) == 0) - { - run_fades (dpy); - break; - } - } - - XNextEvent (dpy, &ev); - if ((ev.type & 0x7f) != KeymapNotify) - discard_ignore (dpy, ev.xany.serial); -#if DEBUG_EVENTS - printf ("event %10.10s serial 0x%08x window 0x%08x\n", - ev_name(&ev), ev_serial (&ev), ev_window (&ev)); -#endif - if (!autoRedirect) switch (ev.type) { - case CreateNotify: - add_win (dpy, ev.xcreatewindow.window, 0); - break; - case ConfigureNotify: - configure_win (dpy, &ev.xconfigure); - break; - case DestroyNotify: - destroy_win (dpy, ev.xdestroywindow.window, True, True); - break; - case MapNotify: - map_win (dpy, ev.xmap.window, ev.xmap.serial, True); - break; - case UnmapNotify: - unmap_win (dpy, ev.xunmap.window, True); - break; - case ReparentNotify: - if (ev.xreparent.parent == root) - add_win (dpy, ev.xreparent.window, 0); - else - destroy_win (dpy, ev.xreparent.window, False, True); - break; - case CirculateNotify: - circulate_win (dpy, &ev.xcirculate); - break; - case Expose: - if (ev.xexpose.window == root) - { - int more = ev.xexpose.count + 1; - if (n_expose == size_expose) - { - if (expose_rects) - { - expose_rects = realloc (expose_rects, - (size_expose + more) * - sizeof (XRectangle)); - size_expose += more; - } - else - { - expose_rects = malloc (more * sizeof (XRectangle)); - size_expose = more; - } - } - expose_rects[n_expose].x = ev.xexpose.x; - expose_rects[n_expose].y = ev.xexpose.y; - expose_rects[n_expose].width = ev.xexpose.width; - expose_rects[n_expose].height = ev.xexpose.height; - n_expose++; - if (ev.xexpose.count == 0) - { - expose_root (dpy, root, expose_rects, n_expose); - n_expose = 0; - } - } - break; - case PropertyNotify: - for (p = 0; backgroundProps[p]; p++) - { - if (ev.xproperty.atom == XInternAtom (dpy, backgroundProps[p], False)) - { - if (rootTile) - { - XClearArea (dpy, root, 0, 0, 0, 0, True); - XRenderFreePicture (dpy, rootTile); - rootTile = None; - break; - } - } - } - /* check if Trans property was changed */ - if (ev.xproperty.atom == opacityAtom) - { - /* reset mode and redraw window */ - win * w = find_win(dpy, ev.xproperty.window); - if (w) - { - if (fadeTrans) - set_fade (dpy, w, w->opacity*1.0/OPAQUE, get_opacity_percent (dpy, w, 1.0), - fade_out_step, NULL, False, True, False); - else - { - w->opacity = get_opacity_prop(dpy, w, OPAQUE); - determine_mode(dpy, w); - if (w->shadow) - { - XRenderFreePicture (dpy, w->shadow); - w->shadow = None; - w->extents = win_extents (dpy, w); - } - } - } - } - break; - default: - if (ev.type == damage_event + XDamageNotify) - { - damage_win (dpy, (XDamageNotifyEvent *) &ev); - } - else if (ev.type == xshape_event + ShapeNotify) - { - shape_win (dpy, (XShapeEvent *) &ev); - } - break; - } - } while (QLength (dpy)); - if (allDamage && !autoRedirect) - { - static int paint; - paint_all (dpy, allDamage); - paint++; - XSync (dpy, False); - allDamage = None; - clipChanged = False; - } - } -} |