When a window that is mapped is reparented away from root, that is the same as it being completely unmapped+destroyed from our persective. The window will no longer be in the same position on screen, and we will no longer want to listen to events on it. Prior to this, the w->pixmap would not be freed when a mapped window was reparented away from root, and damage would not be updated for the screen correctly.
2198 lines
52 KiB
C
2198 lines
52 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
* 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
|
|
*/
|
|
|
|
|
|
#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>
|
|
|
|
#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 */
|
|
|
|
/* 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);
|
|
Display *dpy;
|
|
} fade;
|
|
|
|
win *list;
|
|
fade *fades;
|
|
Display *dpy;
|
|
int scr;
|
|
Window root;
|
|
Picture rootPicture;
|
|
Picture rootBuffer;
|
|
Picture blackPicture;
|
|
Picture transBlackPicture;
|
|
Picture rootTile;
|
|
XserverRegion allDamage;
|
|
Bool clipChanged;
|
|
#if HAS_NAME_WINDOW_PIXMAP
|
|
Bool hasNamePixmap;
|
|
#endif
|
|
int root_height, root_width;
|
|
ignore *ignore_head, **ignore_tail = &ignore_head;
|
|
int xfixes_event, xfixes_error;
|
|
int damage_event, damage_error;
|
|
int composite_event, composite_error;
|
|
int render_event, render_error;
|
|
Bool synchronize;
|
|
int composite_opcode;
|
|
|
|
/* find these once and be done with it */
|
|
Atom opacityAtom;
|
|
Atom winTypeAtom;
|
|
Atom winDesktopAtom;
|
|
Atom winDockAtom;
|
|
Atom winToolbarAtom;
|
|
Atom winMenuAtom;
|
|
Atom winUtilAtom;
|
|
Atom winSplashAtom;
|
|
Atom winDialogAtom;
|
|
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
|
|
|
|
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 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);
|
|
|
|
CompMode compMode = CompSimple;
|
|
|
|
int shadowRadius = 12;
|
|
int shadowOffsetX = -15;
|
|
int shadowOffsetY = -15;
|
|
double shadowOpacity = .75;
|
|
|
|
double fade_in_step = 0.028;
|
|
double fade_out_step = 0.03;
|
|
int fade_delta = 10;
|
|
int fade_time = 0;
|
|
Bool fadeWindows = False;
|
|
Bool excludeDockShadows = False;
|
|
Bool fadeTrans = False;
|
|
|
|
Bool autoRedirect = False;
|
|
|
|
/* For shadow precomputation */
|
|
int Gsize = -1;
|
|
unsigned char *shadowCorner = NULL;
|
|
unsigned char *shadowTop = NULL;
|
|
|
|
int
|
|
get_time_in_milliseconds ()
|
|
{
|
|
struct timeval tv;
|
|
|
|
gettimeofday (&tv, NULL);
|
|
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
|
}
|
|
|
|
fade *
|
|
find_fade (win *w)
|
|
{
|
|
fade *f;
|
|
|
|
for (f = fades; f; f = f->next)
|
|
{
|
|
if (f->w == w)
|
|
return f;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
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);
|
|
free (f);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
cleanup_fade (Display *dpy, win *w)
|
|
{
|
|
fade *f = find_fade (w);
|
|
if (f)
|
|
dequeue_fade (dpy, f);
|
|
}
|
|
|
|
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 exec_callback, Bool override)
|
|
{
|
|
fade *f;
|
|
|
|
f = find_fade (w);
|
|
if (!f)
|
|
{
|
|
f = malloc (sizeof (fade));
|
|
f->next = 0;
|
|
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);
|
|
}
|
|
|
|
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;
|
|
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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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 0;
|
|
ximage = XCreateImage (dpy,
|
|
DefaultVisual(dpy, DefaultScreen(dpy)),
|
|
8,
|
|
ZPixmap,
|
|
0,
|
|
(char *) data,
|
|
swidth, sheight, 8, swidth * sizeof (unsigned char));
|
|
if (!ximage)
|
|
{
|
|
free (data);
|
|
return 0;
|
|
}
|
|
/*
|
|
* 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, 0);
|
|
if (!shadowPicture)
|
|
{
|
|
XDestroyImage (shadowImage);
|
|
XFreePixmap (dpy, shadowPixmap);
|
|
return None;
|
|
}
|
|
|
|
gc = XCreateGC (dpy, shadowPixmap, 0, 0);
|
|
if (!gc)
|
|
{
|
|
XDestroyImage (shadowImage);
|
|
XFreePixmap (dpy, shadowPixmap);
|
|
XRenderFreePicture (dpy, shadowPicture);
|
|
return 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
void
|
|
set_ignore (Display *dpy, unsigned long sequence)
|
|
{
|
|
ignore *i = malloc (sizeof (ignore));
|
|
if (!i)
|
|
return;
|
|
i->sequence = sequence;
|
|
i->next = 0;
|
|
*ignore_tail = i;
|
|
ignore_tail = &i->next;
|
|
}
|
|
|
|
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 0;
|
|
}
|
|
|
|
static const char *backgroundProps[] = {
|
|
"_XROOTPMAP_ID",
|
|
"_XSETROOT_ID",
|
|
0,
|
|
};
|
|
|
|
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 = 0;
|
|
|
|
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, 0);
|
|
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, 0, 0);
|
|
XFixesCopyRegion (dpy, w->borderClip, region);
|
|
}
|
|
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, 0, 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, 0, 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 HAS_NAME_WINDOW_PIXMAP
|
|
/* If the window was previously mapped and its pixmap still exists, it
|
|
is out of date now, so force us to reacquire it. (If the window
|
|
re-maps before the unmap fade-out finished) */
|
|
if (w->pixmap)
|
|
{
|
|
XFreePixmap (dpy, w->pixmap);
|
|
w->pixmap = None;
|
|
}
|
|
#endif
|
|
|
|
if (fade && fadeWindows)
|
|
set_fade (dpy, w, 0, get_opacity_percent (dpy, w, 1.0), fade_in_step, 0, 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)
|
|
{
|
|
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, 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 != 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 = 0;
|
|
}
|
|
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, 0, 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->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);
|
|
}
|
|
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 = 0;
|
|
|
|
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);
|
|
}
|
|
|
|
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, 0, 0);
|
|
if (w->extents != None)
|
|
XFixesCopyRegion (dpy, damage, w->extents);
|
|
}
|
|
w->a.x = ce->x;
|
|
w->a.y = ce->y;
|
|
/* Only destroy the pixmap if the window is mapped */
|
|
if (w->a.map_state != IsUnmapped &&
|
|
(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 (w->a.map_state != IsUnmapped && damage)
|
|
{
|
|
XserverRegion extents = win_extents (dpy, w);
|
|
XFixesUnionRegion (dpy, damage, damage, extents);
|
|
XFixesDestroyRegion (dpy, extents);
|
|
add_damage (dpy, damage);
|
|
}
|
|
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)
|
|
{
|
|
win **prev, *w;
|
|
|
|
for (prev = &list; (w = *prev); prev = &w->next)
|
|
if (w->id == id)
|
|
{
|
|
finish_unmap_win (dpy, w);
|
|
*prev = w->next;
|
|
if (w->alphaPict)
|
|
{
|
|
XRenderFreePicture (dpy, w->alphaPict);
|
|
w->alphaPict = None;
|
|
}
|
|
if (w->shadowPict)
|
|
{
|
|
XRenderFreePicture (dpy, w->shadowPict);
|
|
w->shadowPict = 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)
|
|
{
|
|
finish_destroy_win (dpy, w->id);
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
destroy_win (Display *dpy, Window id, 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, False, (w->a.map_state != IsUnmapped));
|
|
else
|
|
#endif
|
|
{
|
|
finish_destroy_win (dpy, id);
|
|
}
|
|
}
|
|
|
|
/*
|
|
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, True, True);
|
|
w->usable = True;
|
|
}
|
|
}
|
|
if (w->usable)
|
|
#endif
|
|
repair_win (dpy, w);
|
|
}
|
|
|
|
static int
|
|
error (Display *dpy, XErrorEvent *ev)
|
|
{
|
|
int o;
|
|
const char *name = 0;
|
|
|
|
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;
|
|
}
|
|
|
|
printf ("error %d request %d minor %d serial %lu\n",
|
|
ev->error_code, 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";
|
|
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;
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void
|
|
usage (char *program)
|
|
{
|
|
fprintf (stderr, "%s v1.1.3\n", program);
|
|
fprintf (stderr, "usage: %s [options]\n", program);
|
|
fprintf (stderr, "Options\n");
|
|
fprintf (stderr, " -d display\n Specifies which display should be managed.\n");
|
|
fprintf (stderr, " -r radius\n Specifies the blur radius for client-side shadows. (default 12)\n");
|
|
fprintf (stderr, " -o opacity\n Specifies the translucency for client-side shadows. (default .75)\n");
|
|
fprintf (stderr, " -l left-offset\n Specifies the left offset for client-side shadows. (default -15)\n");
|
|
fprintf (stderr, " -t top-offset\n Specifies the top offset for clinet-side shadows. (default -15)\n");
|
|
fprintf (stderr, " -I fade-in-step\n Specifies the opacity change between steps while fading in. (default 0.028)\n");
|
|
fprintf (stderr, " -O fade-out-step\n Specifies the opacity change between steps while fading out. (default 0.03)\n");
|
|
fprintf (stderr, " -D fade-delta-time\n Specifies the time between steps in a fade in milliseconds. (default 10)\n");
|
|
fprintf (stderr, " -a\n Use automatic server-side compositing. Faster, but no special effects.\n");
|
|
fprintf (stderr, " -c\n Draw client-side shadows with fuzzy edges.\n");
|
|
fprintf (stderr, " -C\n Avoid drawing shadows on dock/panel windows.\n");
|
|
fprintf (stderr, " -f\n Fade windows in/out when opening/closing.\n");
|
|
fprintf (stderr, " -F\n Fade windows during opacity changes.\n");
|
|
fprintf (stderr, " -n\n Normal client-side compositing with transparency support\n");
|
|
fprintf (stderr, " -s\n Draw server-side shadows with sharp edges.\n");
|
|
fprintf (stderr, " -S\n Enable synchronous operation (for debugging).\n");
|
|
exit (1);
|
|
}
|
|
|
|
static void
|
|
register_cm (void)
|
|
{
|
|
Window w;
|
|
Atom a;
|
|
|
|
w = XCreateSimpleWindow (dpy, RootWindow (dpy, 0), 0, 0, 1, 1, 0, None,
|
|
None);
|
|
|
|
Xutf8SetWMProperties (dpy, w, "xcompmgr", "xcompmgr", NULL, 0, NULL, NULL,
|
|
NULL);
|
|
|
|
/* FIXME: Don't hard code the screen number */
|
|
a = XInternAtom (dpy, "_NET_WM_CM_S0", False);
|
|
|
|
XSetSelectionOwner (dpy, a, w, 0);
|
|
}
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
XEvent ev;
|
|
Window root_return, parent_return;
|
|
Window *children;
|
|
unsigned int nchildren;
|
|
int i;
|
|
XRenderPictureAttributes pa;
|
|
XRectangle *expose_rects = 0;
|
|
int size_expose = 0;
|
|
int n_expose = 0;
|
|
struct pollfd ufd;
|
|
int p;
|
|
int composite_major, composite_minor;
|
|
char *display = 0;
|
|
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);
|
|
}
|
|
|
|
register_cm();
|
|
|
|
/* 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);
|
|
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);
|
|
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, 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, 0, 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);
|
|
break;
|
|
}
|
|
} while (QLength (dpy));
|
|
if (allDamage && !autoRedirect)
|
|
{
|
|
static int paint;
|
|
paint_all (dpy, allDamage);
|
|
paint++;
|
|
XSync (dpy, False);
|
|
allDamage = None;
|
|
clipChanged = False;
|
|
}
|
|
}
|
|
}
|