+/*
+ * $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.
+ */
+
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
+#include <sys/poll.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xcomposite.h>
int scr;
Window root;
Picture rootPicture;
+Picture rootBuffer;
Picture transPicture;
+Picture rootTile;
XserverRegion allDamage;
+int root_height, root_width;
+
+#define BACKGROUND_PROP "_XROOTPMAP_ID"
+
+#define WINDOW_SOLID 0
+#define WINDOW_TRANS 1
+#define WINDOW_ARGB 2
-#define WINDOW_PLAIN 0
-#define WINDOW_DROP 1
-#define WINDOW_TRANS 2
#define TRANS_OPACITY 0.75
#define SHADOW_RADIUS 15
#define SHADOW_OPACITY 0.75
return 0;
}
+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;
+
+ if (XGetWindowProperty (dpy, root, XInternAtom (dpy, BACKGROUND_PROP, 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;
+ }
+ else
+ {
+ 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;
+}
+
void
paint_root (Display *dpy)
{
- XRenderColor c;
+ if (!rootTile)
+ rootTile = root_tile (dpy);
- c.red = c.green = c.blue = 0x8080;
- c.alpha = 0xffff;
- XRenderFillRectangle (dpy, PictOpSrc, rootPicture, &c,
- 0, 0, 32767, 32767);
+ XRenderComposite (dpy, PictOpSrc,
+ rootTile, None, rootBuffer,
+ 0, 0, 0, 0, 0, 0, root_width, root_height);
}
XserverRegion
{
XRectangle r;
- if (!w->shadow)
+ if (w->mode == WINDOW_ARGB)
{
- double opacity = SHADOW_OPACITY;
- if (w->mode == WINDOW_TRANS)
- opacity = opacity * TRANS_OPACITY;
- w->shadow = shadow_picture (dpy, opacity, SHADOW_RADIUS,
- w->a.width, w->a.height,
- &w->shadow_width, &w->shadow_height);
- w->shadow_dx = SHADOW_OFFSET_X;
- w->shadow_dy = SHADOW_OFFSET_Y;
+ 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;
+ }
+ else
+ {
+ if (!w->shadow)
+ {
+ double opacity = SHADOW_OPACITY;
+ if (w->mode == WINDOW_TRANS)
+ opacity = opacity * TRANS_OPACITY;
+ w->shadow = shadow_picture (dpy, opacity, SHADOW_RADIUS,
+ w->a.width, w->a.height,
+ &w->shadow_width, &w->shadow_height);
+ w->shadow_dx = SHADOW_OFFSET_X;
+ w->shadow_dy = SHADOW_OFFSET_Y;
+ }
+ r.x = w->a.x + w->a.border_width + w->shadow_dx;
+ r.y = w->a.y + w->a.border_width + w->shadow_dy;
+ r.width = w->shadow_width;
+ r.height = w->shadow_height;
}
- r.x = w->a.x + w->a.border_width + w->shadow_dx;
- r.y = w->a.y + w->a.border_width + w->shadow_dy;
- r.width = w->shadow_width;
- r.height = w->shadow_height;
return XFixesCreateRegion (dpy, &r, 1);
}
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 (!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);
+ }
+ XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region);
for (w = list; w; w = w->next)
{
Picture mask;
if (w->a.map_state != IsViewable)
continue;
+ if (!w->picture)
+ continue;
+
if (w->borderSize)
XFixesDestroyRegion (dpy, w->borderSize);
w->borderSize = border_size (dpy, w);
if (w->extents)
XFixesDestroyRegion (dpy, w->extents);
w->extents = win_extents (dpy, w);
- if (w->mode != WINDOW_TRANS)
+ if (w->mode == WINDOW_SOLID)
{
- XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region);
+ XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
XFixesSubtractRegion (dpy, region, region, 0, 0, w->borderSize, 0, 0);
- XRenderComposite (dpy, PictOpSrc, w->picture, None, rootPicture,
+ XRenderComposite (dpy, PictOpSrc, w->picture, None, rootBuffer,
0, 0, 0, 0,
w->a.x + w->a.border_width,
w->a.y + w->a.border_width,
w->prev_trans = t;
t = w;
}
- XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, region);
+ XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, region);
paint_root (dpy);
for (w = t; w; w = w->prev_trans)
{
- XFixesSetPictureClipRegion (dpy, rootPicture, 0, 0, w->borderClip);
+ XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, w->borderClip);
if (w->shadow)
{
- XRenderComposite (dpy, PictOpOver, w->shadow, None, rootPicture,
+ XRenderComposite (dpy, PictOpOver, w->shadow, None, rootBuffer,
0, 0, 0, 0,
w->a.x + w->a.border_width + w->shadow_dx,
w->a.y + w->a.border_width + w->shadow_dy,
w->shadow_width, w->shadow_height);
}
if (w->mode == WINDOW_TRANS)
- XRenderComposite (dpy, PictOpOver, w->picture, transPicture, rootPicture,
+ XRenderComposite (dpy, PictOpOver, w->picture, transPicture, rootBuffer,
+ 0, 0, 0, 0,
+ w->a.x + w->a.border_width,
+ w->a.y + w->a.border_width,
+ w->a.width,
+ w->a.height);
+ else if (w->mode == WINDOW_ARGB)
+ XRenderComposite (dpy, PictOpOver, w->picture, None, rootBuffer,
0, 0, 0, 0,
w->a.x + w->a.border_width,
w->a.y + w->a.border_width,
w->borderClip = None;
}
XFixesDestroyRegion (dpy, region);
+ XFixesSetPictureClipRegion (dpy, rootBuffer, 0, 0, None);
+ XRenderComposite (dpy, PictOpSrc, rootBuffer, None, rootPicture,
+ 0, 0, 0, 0, 0, 0, root_width, root_height);
}
void
if (!w)
return;
w->a.map_state = IsViewable;
- w->damage = XDamageCreate (dpy, id, XDamageReportNonEmpty);
- region = win_extents (dpy, w);
- add_damage (dpy, region);
+ if (w->picture)
+ {
+ w->damage = XDamageCreate (dpy, id, XDamageReportNonEmpty);
+ region = win_extents (dpy, w);
+ add_damage (dpy, region);
+ }
}
void
void
add_win (Display *dpy, Window id, Window prev)
{
- win *new = malloc (sizeof (win));
- win **p;
- XWindowAttributes a;
- XRenderPictureAttributes pa;
+ win *new = malloc (sizeof (win));
+ win **p;
+ XWindowAttributes a;
+ XRenderPictureAttributes pa;
+ XRenderPictFormat *format;
if (!new)
return;
new->damaged = 0;
new->damage = None;
pa.subwindow_mode = IncludeInferiors;
- new->picture = XRenderCreatePicture (dpy, id,
- XRenderFindVisualFormat (dpy,
- new->a.visual),
- CPSubwindowMode,
- &pa);
+ if (new->a.class == InputOnly)
+ {
+ new->picture = 0;
+ format = 0;
+ }
+ else
+ {
+ format = XRenderFindVisualFormat (dpy, new->a.visual);
+ new->picture = XRenderCreatePicture (dpy, id,
+ format,
+ CPSubwindowMode,
+ &pa);
+ }
new->shadow = None;
new->borderSize = None;
new->extents = None;
- if (new->a.override_redirect)
+ if (format && format->type == PictTypeDirect && format->direct.alphaMask)
+ new->mode = WINDOW_ARGB;
+ else if (new->a.override_redirect)
new->mode = WINDOW_TRANS;
else
- new->mode = WINDOW_DROP;
+ new->mode = WINDOW_SOLID;
new->next = *p;
*p = new;
if (new->a.map_state == IsViewable)
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 (w->a.map_state == IsViewable)
{
damage = XFixesCreateRegion (dpy, 0, 0);
}
if (damage)
{
- XserverRegion border = border_size (dpy, w);
- XFixesUnionRegion (dpy, damage, damage, 0, 0, border, 0, 0);
+ XserverRegion extents = win_extents (dpy, w);
+ XFixesUnionRegion (dpy, damage, damage, 0, 0, extents, 0, 0);
+ XFixesDestroyRegion (dpy, extents);
add_damage (dpy, damage);
}
}
if (!gone)
{
unmap_win (dpy, id);
- XRenderFreePicture (dpy, w->picture);
+ if (w->picture)
+ XRenderFreePicture (dpy, w->picture);
}
*prev = w->next;
free (w);
add_damage (dpy, region);
}
+int
+time_in_millis ()
+{
+ struct timeval tp;
+
+ gettimeofday (&tp, 0);
+ return(tp.tv_sec * 1000) + (tp.tv_usec / 1000);
+}
+
+#define INTERVAL 30
+
main ()
{
XEvent ev;
GC gc;
int size_expose = 0;
int n_expose = 0;
+ struct pollfd ufd;
+ int n;
+ int last_update;
+ int now;
+ int timeout;
dpy = XOpenDisplay (0);
if (!dpy)
c.alpha = 0xc0c0;
XRenderFillRectangle (dpy, PictOpSrc, transPicture, &c, 0, 0, 1, 1);
+ root_width = DisplayWidth (dpy, scr);
+ root_height = DisplayHeight (dpy, scr);
+
rootPicture = XRenderCreatePicture (dpy, root,
XRenderFindVisualFormat (dpy,
DefaultVisual (dpy, scr)),
fprintf (stderr, "No composite extension\n");
exit (1);
}
+ printf ("Composite error %d\n", error_base);
if (!XDamageQueryExtension (dpy, &damage_event, &damage_error))
{
fprintf (stderr, "No damage extension\n");
exit (1);
}
+ printf ("Damage error %d\n", damage_error);
if (!XFixesQueryExtension (dpy, &xfixes_event, &xfixes_error))
{
fprintf (stderr, "No XFixes extension\n");
exit (1);
}
+ printf ("XFixes error %d\n", xfixes_error);
allDamage = None;
XGrabServer (dpy);
XCompositeRedirectSubwindows (dpy, root, CompositeRedirectManual);
- paint_root (dpy);
- XSelectInput (dpy, root, SubstructureNotifyMask|ExposureMask);
+ 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);
+ paint_all (dpy, None);
+ last_update = time_in_millis ();
for (;;)
{
/* dump_wins (); */
}
}
break;
+ case PropertyNotify:
+ if (ev.xproperty.atom == XInternAtom (dpy, BACKGROUND_PROP, False))
+ {
+ if (rootTile)
+ {
+ XClearArea (dpy, root, 0, 0, 0, 0, True);
+ XRenderFreePicture (dpy, rootTile);
+ rootTile = None;
+ }
+ }
+ break;
default:
if (ev.type == damage_event + XDamageNotify)
damage_win (dpy, (XDamageNotifyEvent *) &ev);
break;
}
} while (XEventsQueued (dpy, QueuedAfterReading));
+ now = time_in_millis ();
+ timeout = INTERVAL - (now - last_update);
+ if (timeout > 0)
+ {
+ ufd.fd = ConnectionNumber (dpy);
+ ufd.events = POLLIN;
+ n = poll (&ufd, 1, timeout);
+ if (n > 0 && (ufd.revents & POLLIN) && XEventsQueued (dpy, QueuedAfterReading))
+ continue;
+ }
+ last_update = time_in_millis();
if (allDamage)
{
paint_all (dpy, allDamage);