summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZack Rusin <zack@kde.org>2005-12-31 06:21:45 +0000
committerZack Rusin <zack@kde.org>2005-12-31 06:21:45 +0000
commite4b17d9630385493c8bdf29b67a831de9374c939 (patch)
tree33649c485493ee9b6ff22b7b0cafd21d61fd954c /src
adding glxcompmgr. currently depends on some mesa patches (will add them in
a second)
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am22
-rw-r--r--src/display.c1149
-rw-r--r--src/event.c268
-rw-r--r--src/glxcompmgr.c146
-rw-r--r--src/option.c256
-rw-r--r--src/paint.c555
-rw-r--r--src/plugin.c358
-rw-r--r--src/privates.c68
-rw-r--r--src/readpng.c199
-rw-r--r--src/screen.c1294
-rw-r--r--src/texture.c286
-rw-r--r--src/window.c605
12 files changed, 5206 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..2705fb3
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,22 @@
+INCLUDES = \
+ @GLXCOMP_CFLAGS@ \
+ -I$(top_srcdir)/include \
+ -DPLUGINDIR=\"$(plugindir)\" \
+ -DIMAGEDIR=\"$(imagedir)\"
+
+bin_PROGRAMS = glxcompmgr
+
+glxcompmgr_LDADD = @GLXCOMP_LIBS@ @GL_LIBS@ -lm
+glxcompmgr_LDFLAGS = -export-dynamic
+glxcompmgr_SOURCES = \
+ glxcompmgr.c \
+ privates.c \
+ texture.c \
+ display.c \
+ screen.c \
+ window.c \
+ event.c \
+ paint.c \
+ option.c \
+ plugin.c \
+ readpng.c
diff --git a/src/display.c b/src/display.c
new file mode 100644
index 0000000..69d01b0
--- /dev/null
+++ b/src/display.c
@@ -0,0 +1,1149 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <unistd.h>
+
+#define XK_MISCELLANY
+#include <X11/keysymdef.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/shape.h>
+
+#include <comp.h>
+
+static unsigned int virtualModMask[] = {
+ CompAltMask, CompMetaMask, CompSuperMask, CompHyperMask,
+ CompModeSwitchMask, CompNumLockMask, CompScrollLockMask
+};
+
+typedef struct _CompTimeout {
+ struct _CompTimeout *next;
+ int time;
+ int left;
+ CallBackProc callBack;
+ void *closure;
+ CompTimeoutHandle handle;
+} CompTimeout;
+
+static CompTimeout *timeouts = 0;
+static struct timeval lastTimeout;
+static CompTimeoutHandle lastTimeoutHandle = 1;
+
+#define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
+
+static char *textureFilter[] = { "Fast", "Good", "Best" };
+
+#define NUM_TEXTURE_FILTER (sizeof (textureFilter) / sizeof (textureFilter[0]))
+
+CompDisplay *compDisplays = 0;
+
+static CompDisplay compDisplay;
+
+static char *displayPrivateIndices = 0;
+static int displayPrivateLen = 0;
+
+static int
+reallocDisplayPrivate (int size,
+ void *closure)
+{
+ CompDisplay *d = compDisplays;
+ void *privates;
+
+ if (d)
+ {
+ privates = realloc (d->privates, size * sizeof (CompPrivate));
+ if (!privates)
+ return FALSE;
+
+ d->privates = (CompPrivate *) privates;
+ }
+
+ return TRUE;
+}
+
+int
+allocateDisplayPrivateIndex (void)
+{
+ return allocatePrivateIndex (&displayPrivateLen,
+ &displayPrivateIndices,
+ reallocDisplayPrivate,
+ 0);
+}
+
+void
+freeDisplayPrivateIndex (int index)
+{
+ freePrivateIndex (displayPrivateLen, displayPrivateIndices, index);
+}
+
+static void
+compDisplayInitOptions (CompDisplay *display,
+ char **plugin,
+ int nPlugin)
+{
+ CompOption *o;
+ int i;
+
+ o = &display->opt[COMP_DISPLAY_OPTION_ACTIVE_PLUGINS];
+ o->name = "active_plugins";
+ o->shortDesc = "Active Plugins";
+ o->longDesc = "List of currently active plugins";
+ o->type = CompOptionTypeList;
+ o->value.list.type = CompOptionTypeString;
+ o->value.list.nValue = nPlugin;
+ o->value.list.value = malloc (sizeof (CompOptionValue) * nPlugin);
+ for (i = 0; i < nPlugin; i++)
+ o->value.list.value[i].s = strdup (plugin[i]);
+ o->rest.s.string = 0;
+ o->rest.s.nString = 0;
+
+ display->dirtyPluginList = TRUE;
+
+ o = &display->opt[COMP_DISPLAY_OPTION_TEXTURE_FILTER];
+ o->name = "texture_filter";
+ o->shortDesc = "Texture Filter";
+ o->longDesc = "Texture filtering";
+ o->type = CompOptionTypeString;
+ o->value.s = strdup (defaultTextureFilter);
+ o->rest.s.string = textureFilter;
+ o->rest.s.nString = NUM_TEXTURE_FILTER;
+}
+
+CompOption *
+compGetDisplayOptions (CompDisplay *display,
+ int *count)
+{
+ *count = NUM_OPTIONS (display);
+ return display->opt;
+}
+
+static Bool
+setDisplayOption (CompDisplay *display,
+ char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ o = compFindOption (display->opt, NUM_OPTIONS (display), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index) {
+ case COMP_DISPLAY_OPTION_ACTIVE_PLUGINS:
+ if (compSetOptionList (o, value))
+ {
+ display->dirtyPluginList = TRUE;
+ return TRUE;
+ }
+ break;
+ case COMP_DISPLAY_OPTION_TEXTURE_FILTER:
+ if (compSetStringOption (o, value))
+ {
+ CompScreen *s;
+
+ for (s = display->screens; s; s = s->next)
+ damageScreen (s);
+
+ if (strcmp (o->value.s, "Fast") == 0)
+ display->textureFilter = GL_NEAREST;
+ else
+ display->textureFilter = GL_LINEAR;
+
+ return TRUE;
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static Bool
+setDisplayOptionForPlugin (CompDisplay *display,
+ char *plugin,
+ char *name,
+ CompOptionValue *value)
+{
+ CompPlugin *p;
+
+ p = findActivePlugin (plugin);
+ if (p && p->vTable->setDisplayOption)
+ return (*p->vTable->setDisplayOption) (display, name, value);
+
+ return FALSE;
+}
+
+static Bool
+initPluginForDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ return (*p->vTable->initDisplay) (p, d);
+}
+
+static void
+finiPluginForDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ (*p->vTable->finiDisplay) (p, d);
+}
+
+static void
+updatePlugins (CompDisplay *d)
+{
+ CompOption *o;
+ CompPlugin *p, **pop = 0;
+ int nPop, i, j;
+
+ d->dirtyPluginList = FALSE;
+
+ o = &d->opt[COMP_DISPLAY_OPTION_ACTIVE_PLUGINS];
+ for (i = 0; i < d->plugin.list.nValue && i < o->value.list.nValue; i++)
+ {
+ if (strcmp (d->plugin.list.value[i].s, o->value.list.value[i].s))
+ break;
+ }
+
+ nPop = d->plugin.list.nValue - i;
+
+ if (nPop)
+ {
+ pop = malloc (sizeof (CompPlugin *) * nPop);
+ if (!pop)
+ {
+ (*d->setDisplayOption) (d, o->name, &d->plugin);
+ return;
+ }
+ }
+
+ for (j = 0; j < nPop; j++)
+ {
+ pop[j] = popPlugin ();
+ d->plugin.list.nValue--;
+ free (d->plugin.list.value[d->plugin.list.nValue].s);
+ }
+
+ for (; i < o->value.list.nValue; i++)
+ {
+ p = 0;
+ for (j = 0; j < nPop; j++)
+ {
+ if (pop[j] && strcmp (pop[j]->vTable->name,
+ o->value.list.value[i].s) == 0)
+ {
+ if (pushPlugin (pop[j]))
+ {
+ p = pop[j];
+ pop[j] = 0;
+ break;
+ }
+ }
+ }
+
+ if (p == 0)
+ {
+ p = loadPlugin (o->value.list.value[i].s);
+ if (p)
+ {
+ if (!pushPlugin (p))
+ {
+ unloadPlugin (p);
+ p = 0;
+ }
+ }
+ }
+
+ if (p)
+ {
+ CompOptionValue *value;
+
+ value = realloc (d->plugin.list.value, sizeof (CompOption) *
+ (d->plugin.list.nValue + 1));
+ if (value)
+ {
+ value[d->plugin.list.nValue].s = strdup (p->vTable->name);
+
+ d->plugin.list.value = value;
+ d->plugin.list.nValue++;
+ }
+ else
+ {
+ p = popPlugin ();
+ unloadPlugin (p);
+ }
+ }
+ }
+
+ for (j = 0; j < nPop; j++)
+ {
+ if (pop[j])
+ unloadPlugin (pop[j]);
+ }
+
+ if (nPop)
+ free (pop);
+
+ (*d->setDisplayOption) (d, o->name, &d->plugin);
+}
+
+static void
+addTimeout (CompTimeout *timeout)
+{
+ CompTimeout *p = 0, *t;
+
+ for (t = timeouts; t; t = t->next)
+ {
+ if (timeout->time < t->left)
+ break;
+
+ p = t;
+ }
+
+ timeout->next = t;
+ timeout->left = timeout->time;
+
+ if (p)
+ p->next = timeout;
+ else
+ timeouts = timeout;
+}
+
+CompTimeoutHandle
+compAddTimeout (int time,
+ CallBackProc callBack,
+ void *closure)
+{
+ CompTimeout *timeout;
+
+ timeout = malloc (sizeof (CompTimeout));
+ if (!timeout)
+ return 0;
+
+ timeout->time = time;
+ timeout->callBack = callBack;
+ timeout->closure = closure;
+ timeout->handle = lastTimeoutHandle++;
+
+ if (lastTimeoutHandle == MAXSHORT)
+ lastTimeoutHandle = 1;
+
+ if (!timeouts)
+ gettimeofday (&lastTimeout, 0);
+
+ addTimeout (timeout);
+
+ return timeout->handle;
+}
+
+void
+compRemoveTimeout (CompTimeoutHandle handle)
+{
+ CompTimeout *p = 0, *t;
+
+ for (t = timeouts; t; t = t->next)
+ {
+ if (t->handle == handle)
+ break;
+
+ p = t;
+ }
+
+ if (t)
+ {
+ if (p)
+ p->next = t->next;
+ else
+ timeouts = t->next;
+
+ free (t);
+ }
+}
+
+#define TIMEVALDIFF(tv1, tv2) \
+ ((tv1)->tv_sec == (tv2)->tv_sec || (tv1)->tv_usec >= (tv2)->tv_usec) ? \
+ ((((tv1)->tv_sec - (tv2)->tv_sec) * 1000000) + \
+ ((tv1)->tv_usec - (tv2)->tv_usec)) / 1000 : \
+ ((((tv1)->tv_sec - 1 - (tv2)->tv_sec) * 1000000) + \
+ (1000000 + (tv1)->tv_usec - (tv2)->tv_usec)) / 1000
+
+static int
+getTimeToNextRedraw (CompScreen *s,
+ struct timeval *lastTv)
+{
+ struct timeval tv;
+ int diff;
+
+ gettimeofday (&tv, 0);
+
+ diff = TIMEVALDIFF (&tv, lastTv);
+
+ if (diff > s->redrawTime)
+ return 0;
+
+ return s->redrawTime - diff;
+}
+
+static CompWindow *
+findWindowAt (CompDisplay *d,
+ Window root,
+ int x,
+ int y)
+{
+ CompScreen *s;
+ CompWindow *w;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ if (s->root == root && s->maxGrab == 0)
+ {
+ for (w = s->reverseWindows; w; w = w->prev)
+ {
+ if (x >= w->attrib.x &&
+ y >= w->attrib.y &&
+ x < w->attrib.x + w->width &&
+ y < w->attrib.y + w->height)
+ return w;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static Window
+translateToRootWindow (CompDisplay *d,
+ Window child)
+{
+ CompScreen *s;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ if (s->root == child || s->grabWindow == child)
+ return s->root;
+ }
+
+ return child;
+}
+
+void
+updateModifierMappings (CompDisplay *d)
+{
+ XModifierKeymap *modmap;
+ unsigned int i, modMask[CompModNum];
+
+ for (i = 0; i < CompModNum; i++)
+ modMask[i] = 0;
+
+ modmap = XGetModifierMapping (d->display);
+ if (modmap && modmap->max_keypermod > 0)
+ {
+ static int maskTable[] = {
+ ShiftMask, LockMask, ControlMask, Mod1Mask,
+ Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
+ };
+ KeySym keysym;
+ int i, size, mask;
+
+ size = (sizeof (maskTable) / sizeof (int)) * modmap->max_keypermod;
+
+ for (i = 0; i < size; ++i)
+ {
+ if (!modmap->modifiermap[i])
+ continue;
+
+ keysym = XKeycodeToKeysym (d->display, modmap->modifiermap[i], 0);
+ if (keysym)
+ {
+ mask = maskTable[i / modmap->max_keypermod];
+
+ if (keysym == XK_Alt_L ||
+ keysym == XK_Alt_R)
+ {
+ modMask[CompModAlt] |= mask;
+ }
+ else if (keysym == XK_Meta_L ||
+ keysym == XK_Meta_R)
+ {
+ modMask[CompModMeta] |= mask;
+ }
+ else if (keysym == XK_Super_L ||
+ keysym == XK_Super_R)
+ {
+ modMask[CompModSuper] |= mask;
+ }
+ else if (keysym == XK_Hyper_L ||
+ keysym == XK_Hyper_R)
+ {
+ modMask[CompModHyper] |= mask;
+ }
+ else if (keysym == XK_Mode_switch)
+ {
+ modMask[CompModModeSwitch] |= mask;
+ }
+ else if (keysym == XK_Scroll_Lock)
+ {
+ modMask[CompModScrollLock] |= mask;
+ }
+ else if (keysym == XK_Num_Lock)
+ {
+ modMask[CompModNumLock] |= mask;
+ }
+ }
+ }
+
+ if (modmap)
+ XFreeModifiermap (modmap);
+
+ for (i = 0; i < CompModNum; i++)
+ {
+ if (!modMask[i])
+ modMask[i] = CompNoMask;
+ }
+
+ if (memcmp (modMask, d->modMask, sizeof (modMask)))
+ {
+ CompScreen *s;
+
+ memcpy (d->modMask, modMask, sizeof (modMask));
+
+ for (s = d->screens; s; s = s->next)
+ updatePassiveGrabs (s);
+ }
+ }
+}
+
+unsigned int
+virtualToRealModMask (CompDisplay *d,
+ unsigned int modMask)
+{
+ int i;
+
+ for (i = 0; i < CompModNum; i++)
+ {
+ if (modMask & virtualModMask[i])
+ {
+ modMask &= ~virtualModMask[i];
+ modMask |= d->modMask[i];
+ }
+ }
+
+ return (modMask & ~(CompPressMask | CompReleaseMask));
+}
+
+static unsigned int
+realToVirtualModMask (CompDisplay *d,
+ unsigned int modMask)
+{
+ int i;
+
+ for (i = 0; i < CompModNum; i++)
+ {
+ if (modMask & d->modMask[i])
+ modMask |= virtualModMask[i];
+ }
+
+ return modMask;
+}
+
+void
+eventLoop (void)
+{
+ XEvent event;
+ struct pollfd ufd;
+ int timeDiff;
+ struct timeval tv;
+ Region tmpRegion;
+ CompDisplay *display = compDisplays;
+ CompScreen *s = display->screens;
+ int timeToNextRedraw = 0;
+ CompWindow *move = 0;
+ int px = 0, py = 0;
+ CompTimeout *t;
+
+ tmpRegion = XCreateRegion ();
+ if (!tmpRegion)
+ {
+ fprintf (stderr, "%s: Couldn't create region\n", programName);
+ return;
+ }
+
+ ufd.fd = ConnectionNumber (display->display);
+ ufd.events = POLLIN;
+
+ for (;;)
+ {
+ if (display->dirtyPluginList)
+ updatePlugins (display);
+
+ if (restartSignal)
+ {
+ execvp (programName, programArgv);
+ exit (1);
+ }
+
+ while (XPending (display->display))
+ {
+ XNextEvent (display->display, &event);
+
+ /* translate root window */
+ if (testMode)
+ {
+ Window root, child;
+
+ switch (event.type) {
+ case ButtonPress:
+ if (!move)
+ {
+ px = event.xbutton.x;
+ py = event.xbutton.y;
+
+ move = findWindowAt (display, event.xbutton.window,
+ px, py);
+ if (move)
+ {
+ XRaiseWindow (display->display, move->id);
+ continue;
+ }
+ }
+ case ButtonRelease:
+ move = 0;
+
+ root = translateToRootWindow (display,
+ event.xbutton.window);
+ XTranslateCoordinates (display->display,
+ event.xbutton.root, root,
+ event.xbutton.x_root,
+ event.xbutton.y_root,
+ &event.xbutton.x_root,
+ &event.xbutton.y_root,
+ &child);
+ event.xbutton.root = root;
+ break;
+ case KeyPress:
+ case KeyRelease:
+ root = translateToRootWindow (display, event.xkey.window);
+ XTranslateCoordinates (display->display,
+ event.xkey.root, root,
+ event.xkey.x_root,
+ event.xkey.y_root,
+ &event.xkey.x_root,
+ &event.xkey.y_root,
+ &child);
+ event.xkey.root = root;
+ break;
+ case MotionNotify:
+ if (move)
+ {
+ XMoveWindow (display->display, move->id,
+ move->attrib.x + event.xbutton.x - px,
+ move->attrib.y + event.xbutton.y - py);
+
+ px = event.xbutton.x;
+ py = event.xbutton.y;
+ continue;
+ }
+
+ root = translateToRootWindow (display,
+ event.xmotion.window);
+ XTranslateCoordinates (display->display,
+ event.xmotion.root, root,
+ event.xmotion.x_root,
+ event.xmotion.y_root,
+ &event.xmotion.x_root,
+ &event.xmotion.y_root,
+ &child);
+ event.xmotion.root = root;
+ default:
+ break;
+ }
+ }
+
+ /* add virtual modifiers */
+ switch (event.type) {
+ case ButtonPress:
+ event.xbutton.state |= CompPressMask;
+ event.xbutton.state =
+ realToVirtualModMask (display, event.xbutton.state);
+ break;
+ case ButtonRelease:
+ event.xbutton.state |= CompReleaseMask;
+ event.xbutton.state =
+ realToVirtualModMask (display, event.xbutton.state);
+ break;
+ case KeyPress:
+ event.xkey.state |= CompPressMask;
+ event.xkey.state = realToVirtualModMask (display,
+ event.xkey.state);
+ break;
+ case KeyRelease:
+ event.xkey.state |= CompReleaseMask;
+ event.xkey.state = realToVirtualModMask (display,
+ event.xkey.state);
+ break;
+ case MotionNotify:
+ event.xmotion.state =
+ realToVirtualModMask (display, event.xmotion.state);
+ break;
+ default:
+ break;
+ }
+
+ (*display->handleEvent) (display, &event);
+ }
+
+ if (s->allDamaged || REGION_NOT_EMPTY (s->damage))
+ {
+ if (timeToNextRedraw == 0)
+ {
+ /* wait for X drawing requests to finish
+ glXWaitX (); */
+
+ gettimeofday (&tv, 0);
+
+ timeDiff = TIMEVALDIFF (&tv, &s->lastRedraw);
+
+ (*s->preparePaintScreen) (s, timeDiff);
+
+ if (s->allDamaged)
+ {
+ EMPTY_REGION (s->damage);
+ s->allDamaged = 0;
+
+ (*s->paintScreen) (s,
+ &defaultScreenPaintAttrib,
+ &defaultWindowPaintAttrib,
+ &s->region,
+ PAINT_SCREEN_REGION_MASK |
+ PAINT_SCREEN_FULL_MASK);
+
+ glXSwapBuffers (s->display->display, s->root);
+ }
+ else
+ {
+ XIntersectRegion (s->damage, &s->region, tmpRegion);
+
+ EMPTY_REGION (s->damage);
+
+ if ((*s->paintScreen) (s,
+ &defaultScreenPaintAttrib,
+ &defaultWindowPaintAttrib,
+ tmpRegion,
+ PAINT_SCREEN_REGION_MASK))
+ {
+ BoxPtr pBox;
+ int nBox, y;
+
+ glEnable (GL_SCISSOR_TEST);
+ glDrawBuffer (GL_FRONT);
+
+ pBox = tmpRegion->rects;
+ nBox = tmpRegion->numRects;
+ while (nBox--)
+ {
+ y = s->height - pBox->y2;
+
+ glBitmap (0, 0, 0, 0,
+ pBox->x1 - s->rasterX, y - s->rasterY,
+ NULL);
+
+ s->rasterX = pBox->x1;
+ s->rasterY = y;
+
+ glScissor (pBox->x1, y,
+ pBox->x2 - pBox->x1,
+ pBox->y2 - pBox->y1);
+
+ glCopyPixels (pBox->x1, y,
+ pBox->x2 - pBox->x1,
+ pBox->y2 - pBox->y1,
+ GL_COLOR);
+
+ pBox++;
+ }
+
+ glDrawBuffer (GL_BACK);
+ glDisable (GL_SCISSOR_TEST);
+ glFlush ();
+ }
+ else
+ {
+ (*s->paintScreen) (s,
+ &defaultScreenPaintAttrib,
+ &defaultWindowPaintAttrib,
+ &s->region,
+ PAINT_SCREEN_FULL_MASK);
+
+ glXSwapBuffers (s->display->display, s->root);
+ }
+ }
+
+ s->lastRedraw = tv;
+
+ (*s->donePaintScreen) (s);
+
+ /* remove destroyed windows */
+ while (s->pendingDestroys)
+ {
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (w->destroyed)
+ {
+ addWindowDamage (w);
+ removeWindow (w);
+ break;
+ }
+ }
+
+ s->pendingDestroys--;
+ }
+ }
+
+ timeToNextRedraw = getTimeToNextRedraw (s, &s->lastRedraw);
+ if (timeToNextRedraw)
+ timeToNextRedraw = poll (&ufd, 1, timeToNextRedraw);
+ }
+ else
+ {
+ if (timeouts)
+ {
+ if (timeouts->left > 0)
+ poll (&ufd, 1, timeouts->left);
+
+ gettimeofday (&tv, 0);
+
+ timeDiff = TIMEVALDIFF (&tv, &lastTimeout);
+
+ for (t = timeouts; t; t = t->next)
+ t->left -= timeDiff;
+
+ while (timeouts && timeouts->left <= 0)
+ {
+ t = timeouts;
+ if ((*t->callBack) (t->closure))
+ {
+ timeouts = t->next;
+ addTimeout (t);
+ }
+ else
+ {
+ timeouts = t->next;
+ free (t);
+ }
+ }
+
+ s->lastRedraw = lastTimeout = tv;
+ }
+ else
+ {
+ poll (&ufd, 1, 1000);
+ gettimeofday (&s->lastRedraw, 0);
+ }
+
+ /* just redraw immediately */
+ timeToNextRedraw = 0;
+ }
+ }
+}
+
+static int errors = 0;
+static int redirectFailed;
+
+static int
+errorHandler (Display *dpy,
+ XErrorEvent *e)
+{
+
+#ifdef DEBUG
+ char str[128];
+ char *name = 0;
+ int o;
+#endif
+
+ errors++;
+
+ if (e->request_code == compDisplays->compositeOpcode &&
+ e->minor_code == X_CompositeRedirectSubwindows)
+ {
+ redirectFailed = 1;
+ return 0;
+ }
+
+#ifdef DEBUG
+ XGetErrorDatabaseText (dpy, "XlibMessage", "XError", "", str, 128);
+ fprintf (stderr, "%s", str);
+
+ o = e->error_code - compDisplays->damageError;
+ switch (o) {
+ case BadDamage:
+ name = "BadDamage";
+ break;
+ default:
+ break;
+ }
+
+ if (name)
+ {
+ fprintf (stderr, ": %s\n ", name);
+ }
+ else
+ {
+ XGetErrorText (dpy, e->error_code, str, 128);
+ fprintf (stderr, ": %s\n ", str);
+ }
+
+ XGetErrorDatabaseText (dpy, "XlibMessage", "MajorCode", "%d", str, 128);
+ fprintf (stderr, str, e->request_code);
+
+ sprintf (str, "%d", e->request_code);
+ XGetErrorDatabaseText (dpy, "XRequest", str, "", str, 128);
+ if (strcmp (str, ""))
+ fprintf (stderr, " (%s)", str);
+ fprintf (stderr, "\n ");
+
+ XGetErrorDatabaseText (dpy, "XlibMessage", "MinorCode", "%d", str, 128);
+ fprintf (stderr, str, e->minor_code);
+ fprintf (stderr, "\n ");
+
+ XGetErrorDatabaseText (dpy, "XlibMessage", "ResourceID", "%d", str, 128);
+ fprintf (stderr, str, e->resourceid);
+ fprintf (stderr, "\n");
+
+ /* abort (); */
+#endif
+
+ return 0;
+}
+
+int
+compCheckForError (void)
+{
+ int e;
+
+ e = errors;
+ errors = 0;
+
+ return e;
+}
+
+Bool
+addDisplay (char *name,
+ char **plugin,
+ int nPlugin)
+{
+ CompDisplay *d;
+ Display *dpy;
+ int i;
+
+ d = &compDisplay;
+
+ if (displayPrivateLen)
+ {
+ d->privates = malloc (displayPrivateLen * sizeof (CompPrivate));
+ if (!d->privates)
+ return FALSE;
+ }
+ else
+ d->privates = 0;
+
+ d->screenPrivateIndices = 0;
+ d->screenPrivateLen = 0;
+
+ for (i = 0; i < CompModNum; i++)
+ d->modMask[i] = CompNoMask;
+
+ d->plugin.list.type = CompOptionTypeString;
+ d->plugin.list.nValue = 0;
+ d->plugin.list.value = 0;
+
+ compDisplayInitOptions (d, plugin, nPlugin);
+
+ d->textureFilter = GL_LINEAR;
+
+ d->display = dpy = XOpenDisplay (name);
+ if (!d->display)
+ {
+ fprintf (stderr, "%s: Couldn't open display %s\n",
+ programName, XDisplayName (name));
+ return FALSE;
+ }
+
+#ifdef DEBUG
+ XSynchronize (dpy, TRUE);
+#endif
+
+ XSetErrorHandler (errorHandler);
+
+ updateModifierMappings (d);
+
+ d->setDisplayOption = setDisplayOption;
+ d->setDisplayOptionForPlugin = setDisplayOptionForPlugin;
+
+ d->initPluginForDisplay = initPluginForDisplay;
+ d->finiPluginForDisplay = finiPluginForDisplay;
+
+ d->handleEvent = handleEvent;
+ d->handleDamageEvent = handleDamageEvent;
+
+ d->winTypeAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", 0);
+ d->winDesktopAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", 0);
+ d->winDockAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", 0);
+ d->winToolbarAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", 0);
+ d->winMenuAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", 0);
+ d->winUtilAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY", 0);
+ d->winSplashAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", 0);
+ d->winDialogAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", 0);
+ d->winNormalAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", 0);
+ d->winOpacityAtom = XInternAtom (dpy, "_NET_WM_WINDOW_OPACITY", 0);
+ d->winActiveAtom = XInternAtom (dpy, "_NET_ACTIVE_WINDOW", 0);
+
+ d->wmStateAtom = XInternAtom (dpy, "WM_STATE", 0);
+ d->wmDeleteWindowAtom = XInternAtom (dpy, "WM_DELETE_WINDOW", 0);
+
+ d->xBackgroundAtom[0] = XInternAtom (dpy, "_XSETROOT_ID", 0);
+ d->xBackgroundAtom[1] = XInternAtom (dpy, "_XROOTPMAP_ID", 0);
+
+ if (testMode)
+ {
+ d->compositeOpcode = MAXSHORT;
+ d->compositeEvent = MAXSHORT;
+ d->compositeError = MAXSHORT;
+
+ d->damageEvent = MAXSHORT;
+ d->damageError = MAXSHORT;
+ }
+ else
+ {
+ int compositeMajor, compositeMinor;
+
+ if (!XQueryExtension (dpy,
+ COMPOSITE_NAME,
+ &d->compositeOpcode,
+ &d->compositeEvent,
+ &d->compositeError))
+ {
+ fprintf (stderr, "%s: No composite extension\n", programName);
+ return FALSE;
+ }
+
+ XCompositeQueryVersion (dpy, &compositeMajor, &compositeMinor);
+ if (compositeMajor == 0 && compositeMinor < 2)
+ {
+ fprintf (stderr, "%s: Old composite extension\n", programName);
+ return FALSE;
+ }
+
+ if (!XDamageQueryExtension (dpy, &d->damageEvent, &d->damageError))
+ {
+ fprintf (stderr, "%s: No damage extension\n", programName);
+ return FALSE;
+ }
+ }
+
+ d->shapeExtension = XShapeQueryExtension (dpy,
+ &d->shapeEvent,
+ &d->shapeError);
+
+ compDisplays = d;
+
+ if (testMode)
+ {
+ addScreen (d, 0);
+ }
+ else
+ {
+ XGrabServer (dpy);
+
+ for (i = 0; i < ScreenCount (dpy); i++)
+ {
+ redirectFailed = 0;
+ XCompositeRedirectSubwindows (dpy, XRootWindow (dpy, i),
+ CompositeRedirectManual);
+ XSync (dpy, FALSE);
+ if (redirectFailed)
+ {
+ fprintf (stderr, "%s: Another composite manager is already "
+ "running on screen: %d\n", programName, i);
+ }
+ else
+ {
+ if (!addScreen (d, i))
+ {
+ fprintf (stderr, "%s: Failed to manage screen: %d\n",
+ programName, i);
+ }
+ }
+ }
+
+ XUngrabServer (dpy);
+ }
+
+ if (!d->screens)
+ {
+ fprintf (stderr, "%s: No managable screens found on display %s\n",
+ programName, XDisplayName (name));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+CompScreen *
+findScreenAtDisplay (CompDisplay *d,
+ Window root)
+{
+ CompScreen *s;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ if (s->root == root)
+ return s;
+ }
+
+ return 0;
+}
+
+CompWindow *
+findWindowAtDisplay (CompDisplay *d,
+ Window id)
+{
+ CompScreen *s;
+ CompWindow *w;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ w = findWindowAtScreen (s, id);
+ if (w)
+ return w;
+ }
+
+ return 0;
+}
diff --git a/src/event.c b/src/event.c
new file mode 100644
index 0000000..ccabfca
--- /dev/null
+++ b/src/event.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/shape.h>
+
+#include <comp.h>
+
+void
+handleEvent (CompDisplay *display,
+ XEvent *event)
+{
+ CompScreen *s;
+ CompWindow *w;
+
+ switch (event->type) {
+ case Expose:
+ s = findScreenAtDisplay (display, event->xexpose.window);
+ if (s)
+ {
+ int more = event->xexpose.count + 1;
+
+ if (s->nExpose == s->sizeExpose)
+ {
+ if (s->exposeRects)
+ {
+ s->exposeRects = realloc (s->exposeRects,
+ (s->sizeExpose + more) *
+ sizeof (XRectangle));
+ s->sizeExpose += more;
+ }
+ else
+ {
+ s->exposeRects = malloc (more * sizeof (XRectangle));
+ s->sizeExpose = more;
+ }
+ }
+
+ s->exposeRects[s->nExpose].x = event->xexpose.x;
+ s->exposeRects[s->nExpose].y = event->xexpose.y;
+ s->exposeRects[s->nExpose].width = event->xexpose.width;
+ s->exposeRects[s->nExpose].height = event->xexpose.height;
+ s->nExpose++;
+
+ if (event->xexpose.count == 0)
+ {
+ REGION rect;
+
+ rect.rects = &rect.extents;
+ rect.numRects = rect.size = 1;
+
+ while (s->nExpose--)
+ {
+ rect.extents.x1 = s->exposeRects[s->nExpose].x;
+ rect.extents.y1 = s->exposeRects[s->nExpose].y;
+ rect.extents.x2 = rect.extents.x1 +
+ s->exposeRects[s->nExpose].width;
+ rect.extents.y2 = rect.extents.y1 +
+ s->exposeRects[s->nExpose].height;
+
+ damageScreenRegion (s, &rect);
+ }
+ s->nExpose = 0;
+ }
+ }
+ break;
+ case ConfigureNotify:
+ w = findWindowAtDisplay (display, event->xconfigure.window);
+ if (w)
+ {
+ configureWindow (w, &event->xconfigure);
+ }
+ else
+ {
+ s = findScreenAtDisplay (display, event->xconfigure.window);
+ if (s)
+ configureScreen (s, &event->xconfigure);
+ }
+ break;
+ case CreateNotify:
+ s = findScreenAtDisplay (display, event->xcreatewindow.parent);
+ if (s)
+ addWindow (s, event->xcreatewindow.window, 0);
+ break;
+ case DestroyNotify:
+ w = findWindowAtDisplay (display, event->xdestroywindow.window);
+ if (w)
+ {
+ addWindowDamage (w);
+ removeWindow (w);
+ }
+ break;
+ case MapNotify:
+ w = findWindowAtDisplay (display, event->xmap.window);
+ if (w)
+ mapWindow (w);
+ break;
+ case UnmapNotify:
+ w = findWindowAtDisplay (display, event->xunmap.window);
+ if (w)
+ unmapWindow (w);
+ break;
+ case ReparentNotify:
+ s = findScreenAtDisplay (display, event->xreparent.parent);
+ if (s)
+ {
+ addWindow (s, event->xreparent.window, 0);
+ }
+ else
+ {
+ w = findWindowAtDisplay (display, event->xreparent.window);
+ if (w)
+ {
+ addWindowDamage (w);
+ removeWindow (w);
+ }
+ }
+ break;
+ case CirculateNotify:
+ w = findWindowAtDisplay (display, event->xcirculate.window);
+ if (w)
+ circulateWindow (w, &event->xcirculate);
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ case KeyPress:
+ case KeyRelease:
+ break;
+ case PropertyNotify:
+ if (event->xproperty.atom == display->winActiveAtom)
+ {
+ s = findScreenAtDisplay (display, event->xproperty.window);
+ if (s)
+ s->activeWindow = getActiveWindow (display, s->root);
+ }
+ else if (event->xproperty.atom == display->winTypeAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ {
+ Atom type;
+
+ type = getWindowType (display, w->client);
+ if (type != w->type)
+ {
+
+ if (w->attrib.map_state == IsViewable)
+ {
+ if (w->type == display->winDesktopAtom)
+ w->screen->desktopWindowCount--;
+ else if (type == display->winDesktopAtom)
+ w->screen->desktopWindowCount++;
+
+ addWindowDamage (w);
+ }
+ w->type = type;
+ }
+ }
+ }
+ else if (event->xproperty.atom == display->winOpacityAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ {
+ GLuint opacity;
+
+ opacity = getWindowOpacity (display, w->id);
+ if (opacity != w->opacity)
+ {
+ w->opacity = opacity;
+ if (w->attrib.map_state == IsViewable)
+ addWindowDamage (w);
+ }
+ }
+ }
+ else if (event->xproperty.atom == display->xBackgroundAtom[0] ||
+ event->xproperty.atom == display->xBackgroundAtom[1])
+ {
+ s = findScreenAtDisplay (display, event->xproperty.window);
+ if (s)
+ {
+ finiTexture (s, &s->backgroundTexture);
+ initTexture (s, &s->backgroundTexture);
+
+ damageScreen (s);
+ }
+ }
+ break;
+ case MotionNotify:
+ break;
+ case ClientMessage:
+ if (event->xclient.format == 32 &&
+ event->xclient.data.l[0] == display->wmDeleteWindowAtom)
+ exit (0);
+ break;
+ case MappingNotify:
+ updateModifierMappings (display);
+ break;
+ default:
+ if (display->shapeExtension &&
+ event->type == display->shapeEvent + ShapeNotify)
+ {
+ w = findWindowAtDisplay (display, ((XShapeEvent *) event)->window);
+ if (w)
+ updateWindowRegion (w);
+ }
+ else if (event->type == display->damageEvent + XDamageNotify)
+ {
+ (*display->handleDamageEvent) (display,
+ (XDamageNotifyEvent *) event);
+ }
+ break;
+ }
+}
+
+void
+handleDamageEvent (CompDisplay *display,
+ XDamageNotifyEvent *event)
+{
+ CompScreen *screen;
+ REGION rect;
+
+ rect.rects = &rect.extents;
+ rect.numRects = rect.size = 1;
+
+ screen = display->screens;
+ if (screen->next)
+ {
+ CompWindow *w;
+
+ w = findWindowAtDisplay (display, event->drawable);
+ if (!w)
+ return;
+
+ screen = w->screen;
+ }
+
+ rect.extents.x1 = event->geometry.x + event->area.x;
+ rect.extents.y1 = event->geometry.y + event->area.y;
+ rect.extents.x2 = rect.extents.x1 + event->area.width;
+ rect.extents.y2 = rect.extents.y1 + event->area.height;
+
+ damageScreenRegion (screen, &rect);
+}
diff --git a/src/glxcompmgr.c b/src/glxcompmgr.c
new file mode 100644
index 0000000..21673f3
--- /dev/null
+++ b/src/glxcompmgr.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <comp.h>
+
+char *programName;
+char **programArgv;
+int programArgc;
+
+char *backgroundImage = "background.png";
+char *windowImage = "window.png";
+
+REGION emptyRegion;
+GLushort defaultColor[4] = { 0, 0, 0, 0 };
+Window currentRoot = 0;
+
+int defaultRefreshRate = 60;
+char *defaultTextureFilter = "Good";
+
+Bool testMode = FALSE;
+Bool restartSignal = FALSE;
+
+static void
+usage (void)
+{
+ printf ("Usage: %s "
+ "[--display DISPLAY] "
+ "[--bg-image PNG] "
+ "[--window-image PNG]\n "
+ "[--refresh-rate RATE] "
+ "[--fast-filter] "
+ "[--test-mode]\n "
+ "[--help] "
+ "[PLUGIN]...\n",
+ programName);
+}
+
+static void
+signalHandler (int sig)
+{
+ if (sig == SIGHUP)
+ restartSignal = TRUE;
+}
+
+int
+main (int argc, char **argv)
+{
+ char *displayName = 0;
+ char *plugin[256];
+ int i, nPlugin = 0;
+
+ programName = argv[0];
+ programArgc = argc;
+ programArgv = argv;
+
+ signal (SIGHUP, signalHandler);
+
+ emptyRegion.rects = &emptyRegion.extents;
+ emptyRegion.numRects = 0;
+ emptyRegion.extents.x1 = 0;
+ emptyRegion.extents.y1 = 0;
+ emptyRegion.extents.x2 = 0;
+ emptyRegion.extents.y2 = 0;
+ emptyRegion.size = 0;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "--help"))
+ {
+ usage ();
+ return 0;
+ }
+ else if (!strcmp (argv[i], "--display"))
+ {
+ if (i + 1 < argc)
+ displayName = argv[++i];
+ }
+ else if (!strcmp (argv[i], "--refresh-rate"))
+ {
+ if (i + 1 < argc)
+ {
+ defaultRefreshRate = atoi (programArgv[++i]);
+ defaultRefreshRate = RESTRICT_VALUE (defaultRefreshRate,
+ 1, 1000);
+ }
+ }
+ else if (!strcmp (argv[i], "--fast-filter"))
+ {
+ defaultTextureFilter = "Fast";
+ }
+ else if (!strcmp (argv[i], "--test-mode"))
+ {
+ testMode = TRUE;
+ }
+ else if (!strcmp (argv[i], "--bg-image"))
+ {
+ if (i + 1 < argc)
+ backgroundImage = argv[++i];
+ }
+ else if (!strcmp (argv[i], "--window-image"))
+ {
+ if (i + 1 < argc)
+ windowImage = argv[++i];
+ }
+ else
+ {
+ if (nPlugin < 256)
+ plugin[nPlugin++] = argv[i];
+ }
+ }
+
+ if (!addDisplay (displayName, plugin, nPlugin))
+ return 1;
+
+ eventLoop ();
+
+ return 0;
+}
diff --git a/src/option.c b/src/option.c
new file mode 100644
index 0000000..7369b5e
--- /dev/null
+++ b/src/option.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <comp.h>
+
+CompOption *
+compFindOption (CompOption *option,
+ int nOption,
+ char *name,
+ int *index)
+{
+ int i;
+
+ for (i = 0; i < nOption; i++)
+ {
+ if (strcmp (option[i].name, name) == 0)
+ {
+ if (index)
+ *index = i;
+
+ return &option[i];
+ }
+ }
+
+ return 0;
+}
+
+Bool
+compSetBoolOption (CompOption *option,
+ CompOptionValue *value)
+{
+ option->value.i = (value->b) ? TRUE : FALSE;
+
+ return TRUE;
+}
+
+Bool
+compSetIntOption (CompOption *option,
+ CompOptionValue *value)
+{
+ if (value->i <= option->rest.i.min ||
+ value->i >= option->rest.i.max ||
+ value->i == option->value.i)
+ return FALSE;
+
+ option->value.i = value->i;
+
+ return TRUE;
+}
+
+Bool
+compSetFloatOption (CompOption *option,
+ CompOptionValue *value)
+{
+ float v, p;
+
+ p = 1.0f / option->rest.f.precision;
+ v = ((int) (value->f * p + 0.5f)) / p;
+
+ if (v <= option->rest.f.min ||
+ v >= option->rest.f.max ||
+ v == option->value.f)
+ return FALSE;
+
+ option->value.f = v;
+
+ return TRUE;
+}
+
+Bool
+compSetStringOption (CompOption *option,
+ CompOptionValue *value)
+{
+ if (option->rest.s.nString)
+ {
+ int i;
+
+ if (!value->s)
+ return FALSE;
+
+ for (i = 0; i < option->rest.s.nString; i++)
+ {
+ if (strcmp (option->rest.s.string[i], value->s) == 0)
+ break;
+ }
+
+ if (i == option->rest.s.nString)
+ return FALSE;
+ }
+
+ if (option->value.s == value->s)
+ return FALSE;
+
+ if (option->value.s && value->s)
+ {
+ if (strcmp (option->value.s, value->s) == 0)
+ return FALSE;
+ }
+
+ if (option->value.s)
+ free (option->value.s);
+
+ if (value->s)
+ option->value.s = strdup (value->s);
+ else
+ option->value.s = 0;
+
+ return TRUE;
+}
+
+Bool
+compSetColorOption (CompOption *option,
+ CompOptionValue *value)
+{
+ if (memcmp (value->c, option->value.c, sizeof (value->c)) == 0)
+ return FALSE;
+
+ memcpy (option->value.c, value->c, sizeof (value->c));
+
+ return TRUE;
+}
+
+Bool
+compSetBindingOption (CompOption *option,
+ CompOptionValue *value)
+{
+ CompBinding *binding;
+
+ binding = &option->value.bind;
+ if (value->bind.type == CompBindingTypeButton)
+ {
+ if (binding->type == CompBindingTypeButton &&
+ binding->u.button.button == value->bind.u.button.button &&
+ binding->u.button.modifiers == value->bind.u.button.modifiers)
+ return FALSE;
+ }
+ else
+ {
+ if (binding->type == CompBindingTypeKey &&
+ binding->u.key.keycode == value->bind.u.key.keycode &&
+ binding->u.key.modifiers == value->bind.u.key.modifiers)
+ return FALSE;
+ }
+
+ *binding = value->bind;
+
+ return TRUE;
+}
+
+Bool
+compSetOptionList (CompOption *option,
+ CompOptionValue *value)
+{
+ CompOption o;
+ Bool status = FALSE;
+ int i, min;
+
+ if (value->list.nValue != option->value.list.nValue)
+ {
+ CompOptionValue *v;
+
+ v = malloc (sizeof (CompOptionValue) * value->list.nValue);
+ if (!v)
+ return FALSE;
+
+ min = MIN (value->list.nValue, option->value.list.nValue);
+
+ if (min < option->value.list.nValue)
+ {
+ switch (option->value.list.type) {
+ case CompOptionTypeString:
+ for (i = min; i < option->value.list.nValue; i++)
+ {
+ if (option->value.list.value[i].s)
+ free (option->value.list.value[i].s);
+ }
+ default:
+ break;
+ }
+ }
+
+ memset (v, 0, sizeof (CompOptionValue) * value->list.nValue);
+
+ if (min)
+ memcpy (v, option->value.list.value,
+ sizeof (CompOptionValue) * min);
+
+ if (option->value.list.value)
+ free (option->value.list.value);
+
+ option->value.list.value = v;
+ option->value.list.nValue = value->list.nValue;
+
+ status = TRUE;
+ }
+
+ o = *option;
+ o.type = option->value.list.type;
+
+ for (i = 0; i < value->list.nValue; i++)
+ {
+ o.value = option->value.list.value[i];
+
+ switch (o.type) {
+ case CompOptionTypeBool:
+ status |= compSetBoolOption (&o, &value->list.value[i]);
+ break;
+ case CompOptionTypeInt:
+ status |= compSetIntOption (&o, &value->list.value[i]);
+ break;
+ case CompOptionTypeFloat:
+ status |= compSetFloatOption (&o, &value->list.value[i]);
+ break;
+ case CompOptionTypeString:
+ status |= compSetStringOption (&o, &value->list.value[i]);
+ break;
+ case CompOptionTypeColor:
+ status |= compSetColorOption (&o, &value->list.value[i]);
+ break;
+ case CompOptionTypeBinding:
+ status |= compSetBindingOption (&o, &value->list.value[i]);
+ default:
+ break;
+ }
+
+ option->value.list.value[i] = o.value;
+ }
+
+ return status;
+}
diff --git a/src/paint.c b/src/paint.c
new file mode 100644
index 0000000..5174e95
--- /dev/null
+++ b/src/paint.c
@@ -0,0 +1,555 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <comp.h>
+
+ScreenPaintAttrib defaultScreenPaintAttrib = {
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f
+};
+
+WindowPaintAttrib defaultWindowPaintAttrib = {
+ OPAQUE, 0.0f, 0.0f, 1.0f, 1.0f
+};
+
+void
+preparePaintScreen (CompScreen *screen,
+ int msSinceLastPaint) {}
+
+void
+donePaintScreen (CompScreen *screen) {}
+
+void
+paintTransformedScreen (CompScreen *screen,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ unsigned int mask)
+{
+ CompWindow *w;
+ int windowMask;
+ int backgroundMask;
+
+ glPushMatrix ();
+
+ glTranslatef (sAttrib->xTranslate,
+ sAttrib->yTranslate,
+ sAttrib->zTranslate - BASE_Z_TRANSLATE);
+
+ glRotatef (sAttrib->xRotate, 0.0f, 1.0f, 0.0f);
+ glRotatef (sAttrib->vRotate,
+ 1.0f - sAttrib->xRotate / 90.0f,
+ 0.0f,
+ sAttrib->xRotate / 90.0f);
+ glRotatef (sAttrib->yRotate, 0.0f, 1.0f, 0.0f);
+
+ glTranslatef (-0.5f, -0.5f, 0.5f);
+ glScalef (1.0f / screen->width, -1.0f / screen->height, 1.0f);
+ glTranslatef (0.0f, -screen->height, 0.0f);
+
+ if (mask & PAINT_SCREEN_TRANSFORMED_MASK)
+ {
+ windowMask = PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
+ backgroundMask = PAINT_BACKGROUND_ON_TRANSFORMED_SCREEN_MASK;
+
+ if (mask & PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK)
+ {
+ backgroundMask |= PAINT_BACKGROUND_WITH_STENCIL_MASK;
+
+ (*screen->paintBackground) (screen, &screen->region,
+ backgroundMask);
+
+ glEnable (GL_STENCIL_TEST);
+
+ for (w = screen->windows; w; w = w->next)
+ (*screen->paintWindow) (w, wAttrib, &screen->region,
+ windowMask);
+
+ glDisable (GL_STENCIL_TEST);
+
+ glPopMatrix ();
+
+ return;
+ }
+ }
+ else
+ windowMask = backgroundMask = 0;
+
+ (*screen->paintBackground) (screen, &screen->region, backgroundMask);
+
+ for (w = screen->windows; w; w = w->next)
+ (*screen->paintWindow) (w, wAttrib, &screen->region, windowMask);
+
+ glPopMatrix ();
+}
+
+Bool
+paintScreen (CompScreen *screen,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ Region region,
+ unsigned int mask)
+{
+ static Region tmpRegion = NULL;
+ CompWindow *w;
+
+ if (mask & PAINT_SCREEN_REGION_MASK)
+ {
+ if ((mask & PAINT_SCREEN_TRANSFORMED_MASK) ||
+ (mask & PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK))
+ {
+ if (mask & PAINT_SCREEN_FULL_MASK)
+ {
+ (*screen->paintTransformedScreen) (screen, sAttrib, wAttrib,
+ mask);
+
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ /* fall through and redraw region */
+ }
+ else if (mask & PAINT_SCREEN_FULL_MASK)
+ {
+ (*screen->paintTransformedScreen) (screen, sAttrib, wAttrib, mask);
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+
+ if (!tmpRegion)
+ {
+ tmpRegion = XCreateRegion ();
+ if (!tmpRegion)
+ return FALSE;
+ }
+
+ XSubtractRegion (region, &emptyRegion, tmpRegion);
+
+ glPushMatrix ();
+
+ glTranslatef (0.0f, 0.0f, -BASE_Z_TRANSLATE);
+
+ glTranslatef (-0.5f, -0.5f, 0.5f);
+ glScalef (1.0f / screen->width, -1.0f / screen->height, 1.0f);
+ glTranslatef (0.0f, -screen->height, 0.0f);
+
+ /* paint solid windows */
+ for (w = screen->reverseWindows; w; w = w->prev)
+ {
+ if (w->invisible)
+ continue;
+
+ if ((*screen->paintWindow) (w, wAttrib, tmpRegion,
+ PAINT_WINDOW_SOLID_MASK))
+ XSubtractRegion (tmpRegion, w->region, tmpRegion);
+
+ /* copy region */
+ XSubtractRegion (tmpRegion, &emptyRegion, w->clip);
+ }
+
+ (*screen->paintBackground) (screen, tmpRegion, 0);
+
+ /* paint translucent windows */
+ for (w = screen->windows; w; w = w->next)
+ {
+ if (w->invisible)
+ continue;
+
+ (*screen->paintWindow) (w, wAttrib, w->clip,
+ PAINT_WINDOW_TRANSLUCENT_MASK);
+ }
+
+ glPopMatrix ();
+
+ return TRUE;
+}
+
+#define ADD_QUAD(data, w, x1, y1, x2, y2) \
+ if (!(w)->pixmap) \
+ bindWindow (w); \
+ *(data)++ = X_WINDOW_TO_TEXTURE_SPACE (w, x1); \
+ *(data)++ = Y_WINDOW_TO_TEXTURE_SPACE (w, y2); \
+ *(data)++ = (x1); \
+ *(data)++ = (y2); \
+ *(data)++ = X_WINDOW_TO_TEXTURE_SPACE (w, x2); \
+ *(data)++ = Y_WINDOW_TO_TEXTURE_SPACE (w, y2); \
+ *(data)++ = (x2); \
+ *(data)++ = (y2); \
+ *(data)++ = X_WINDOW_TO_TEXTURE_SPACE (w, x2); \
+ *(data)++ = Y_WINDOW_TO_TEXTURE_SPACE (w, y1); \
+ *(data)++ = (x2); \
+ *(data)++ = (y1); \
+ *(data)++ = X_WINDOW_TO_TEXTURE_SPACE (w, x1); \
+ *(data)++ = Y_WINDOW_TO_TEXTURE_SPACE (w, y1); \
+ *(data)++ = (x1); \
+ *(data)++ = (y1)
+
+#define ADD_BOX(data, w, box) \
+ ADD_QUAD (data, w, (box)->x1, (box)->y1, (box)->x2, (box)->y2)
+
+Bool
+paintWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib,
+ Region region,
+ unsigned int mask)
+{
+ BoxPtr pClip;
+ int nClip, n;
+ GLfloat *data, *d;
+ GLushort opacity;
+ int x1, y1, x2, y2;
+
+ if (!region->numRects)
+ return TRUE;
+
+ if (w->destroyed || w->attrib.map_state != IsViewable)
+ return TRUE;
+
+ if (mask & PAINT_WINDOW_SOLID_MASK)
+ {
+ if (w->alpha)
+ return FALSE;
+
+ opacity = MULTIPLY_USHORT (w->opacity, attrib->opacity);
+ if (opacity != OPAQUE)
+ return FALSE;
+ }
+ else if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ {
+ opacity = MULTIPLY_USHORT (w->opacity, attrib->opacity);
+ if (!w->alpha && opacity == OPAQUE)
+ return FALSE;
+ }
+ else
+ {
+ opacity = MULTIPLY_USHORT (w->opacity, attrib->opacity);
+ if (w->alpha || opacity != OPAQUE)
+ mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+ else
+ mask |= PAINT_WINDOW_SOLID_MASK;
+ }
+
+ if (attrib->xTranslate != 0.0f ||
+ attrib->yTranslate != 0.0f ||
+ attrib->xScale != 1.0f ||
+ attrib->yScale != 1.0f)
+ {
+ nClip = w->region->numRects;
+ pClip = w->region->rects;
+
+ mask |= PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
+
+ data = malloc (sizeof (GLfloat) * nClip * 16);
+ if (!data)
+ return FALSE;
+
+ d = data;
+
+ n = nClip;
+ while (nClip--)
+ {
+ x1 = pClip->x1 - w->attrib.x;
+ y1 = pClip->y1 - w->attrib.y;
+ x2 = pClip->x2 - w->attrib.x;
+ y2 = pClip->y2 - w->attrib.y;
+
+ ADD_QUAD (d, w, x1, y1, x2, y2);
+
+ pClip++;
+ }
+ }
+ else
+ {
+ BoxRec clip, full;
+ BoxPtr pExtent = &region->extents;
+ BoxPtr pBox = region->rects;
+ int nBox = region->numRects;
+ int dataSize;
+
+ full.x1 = 0;
+ full.y1 = 0;
+ full.x2 = w->width;
+ full.y2 = w->height;
+
+ x1 = pExtent->x1 - w->attrib.x;
+ y1 = pExtent->y1 - w->attrib.y;
+ x2 = pExtent->x2 - w->attrib.x;
+ y2 = pExtent->y2 - w->attrib.y;
+
+ if (x1 > 0)
+ full.x1 = x1;
+ if (y1 > 0)
+ full.y1 = y1;
+ if (x2 < w->width)
+ full.x2 = x2;
+ if (y2 < w->height)
+ full.y2 = y2;
+
+ if (full.x1 >= full.x2 || full.y1 >= full.y2)
+ return TRUE;
+
+ dataSize = nBox * 16;
+ data = malloc (sizeof (GLfloat) * dataSize);
+ if (!data)
+ return FALSE;
+
+ d = data;
+ n = 0;
+
+ pBox = region->rects;
+ nBox = region->numRects;
+ while (nBox--)
+ {
+ x1 = pBox->x1 - w->attrib.x;
+ y1 = pBox->y1 - w->attrib.y;
+ x2 = pBox->x2 - w->attrib.x;
+ y2 = pBox->y2 - w->attrib.y;
+
+ pBox++;
+
+ if (x1 < full.x1)
+ x1 = full.x1;
+ if (y1 < full.y1)
+ y1 = full.y1;
+ if (x2 > full.x2)
+ x2 = full.x2;
+ if (y2 > full.y2)
+ y2 = full.y2;
+
+ if (x1 < x2 && y1 < y2)
+ {
+ nClip = w->region->numRects;
+
+ if (nClip == 1)
+ {
+ ADD_QUAD (d, w, x1, y1, x2, y2);
+
+ n++;
+ }
+ else
+ {
+ pClip = w->region->rects;
+
+ while (nClip--)
+ {
+ clip.x1 = pClip->x1 - w->attrib.x;
+ clip.y1 = pClip->y1 - w->attrib.y;
+ clip.x2 = pClip->x2 - w->attrib.x;
+ clip.y2 = pClip->y2 - w->attrib.y;
+
+ pClip++;
+
+ if (clip.x1 < x1)
+ clip.x1 = x1;
+ if (clip.y1 < y1)
+ clip.y1 = y1;
+ if (clip.x2 > x2)
+ clip.x2 = x2;
+ if (clip.y2 > y2)
+ clip.y2 = y2;
+
+ if (clip.x1 < clip.x2 && clip.y1 < clip.y2)
+ {
+ if ((n << 4) == dataSize)
+ {
+ dataSize <<= 2;
+ data = realloc (data,
+ sizeof (GLfloat) * dataSize);
+ if (!data)
+ return FALSE;
+
+ d = data + (n * 16);
+ }
+
+ ADD_BOX (d, w, &clip);
+
+ n++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (n)
+ {
+ glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, data);
+ glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, data + 2);
+
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ {
+ glEnable (GL_BLEND);
+ if (opacity != OPAQUE)
+ {
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4us (opacity, opacity, opacity, opacity);
+ }
+ }
+
+ glPushMatrix ();
+
+ if (mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK)
+ {
+ glTranslatef (w->attrib.x + attrib->xTranslate,
+ w->attrib.y + attrib->yTranslate, 0.0f);
+ glScalef (attrib->xScale, attrib->yScale, 0.0f);
+
+ enableTexture (w->screen, &w->texture, COMP_TEXTURE_FILTER_GOOD);
+ }
+ else
+ {
+ glTranslatef (w->attrib.x, w->attrib.y, 0.0f);
+
+ enableTexture (w->screen, &w->texture, COMP_TEXTURE_FILTER_FAST);
+ }
+
+ glDrawArrays (GL_QUADS, 0, n * 4);
+
+ disableTexture (&w->texture);
+
+ glPopMatrix ();
+
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ {
+ if (opacity != OPAQUE)
+ {
+ glColor4usv (defaultColor);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ }
+ glDisable (GL_BLEND);
+ }
+ }
+
+ free (data);
+
+ return TRUE;
+}
+
+void
+paintBackground (CompScreen *s,
+ Region region,
+ unsigned int mask)
+{
+ CompTexture *bg = &s->backgroundTexture;
+ BoxPtr pBox = region->rects;
+ int n, nBox = region->numRects;
+ GLfloat *d, *data;
+
+ if (!nBox)
+ return;
+
+ if (s->desktopWindowCount)
+ {
+ if (bg->name)
+ {
+ finiTexture (s, bg);
+ initTexture (s, bg);
+ }
+
+ if (!(mask & PAINT_BACKGROUND_WITH_STENCIL_MASK))
+ return;
+ }
+ else
+ {
+ if (!bg->name)
+ updateScreenBackground (s, bg);
+ }
+
+ data = malloc (sizeof (GLfloat) * nBox * 16);
+ if (!data)
+ return;
+
+ d = data;
+ n = nBox;
+ while (n--)
+ {
+ *d++ = bg->dx * pBox->x1;
+ *d++ = bg->dy * (s->backgroundHeight - pBox->y2);
+
+ *d++ = pBox->x1;
+ *d++ = pBox->y2;
+
+ *d++ = bg->dx * pBox->x2;
+ *d++ = bg->dy * (s->backgroundHeight - pBox->y2);
+
+ *d++ = pBox->x2;
+ *d++ = pBox->y2;
+
+ *d++ = bg->dx * pBox->x2;
+ *d++ = bg->dy * (s->backgroundHeight - pBox->y1);
+
+ *d++ = pBox->x2;
+ *d++ = pBox->y1;
+
+ *d++ = bg->dx * pBox->x1;
+ *d++ = bg->dy * (s->backgroundHeight - pBox->y1);
+
+ *d++ = pBox->x1;
+ *d++ = pBox->y1;
+
+ pBox++;
+ }
+
+ if (mask & PAINT_BACKGROUND_WITH_STENCIL_MASK)
+ {
+ glEnable (GL_STENCIL_TEST);
+ glStencilFunc (GL_ALWAYS, s->stencilRef, ~0);
+ glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
+ }
+
+ glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, data);
+ glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, data + 2);
+
+ if (s->desktopWindowCount)
+ {
+ glDrawArrays (GL_QUADS, 0, nBox * 4);
+ }
+ else
+ {
+ if (mask & PAINT_BACKGROUND_ON_TRANSFORMED_SCREEN_MASK)
+ enableTexture (s, bg, COMP_TEXTURE_FILTER_GOOD);
+ else
+ enableTexture (s, bg, COMP_TEXTURE_FILTER_FAST);
+
+ glDrawArrays (GL_QUADS, 0, nBox * 4);
+
+ disableTexture (bg);
+ }
+
+ if (mask & PAINT_BACKGROUND_WITH_STENCIL_MASK)
+ {
+ glStencilFunc (GL_EQUAL, s->stencilRef, ~0);
+ glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
+ glDisable (GL_STENCIL_TEST);
+ }
+
+ free (data);
+}
diff --git a/src/plugin.c b/src/plugin.c
new file mode 100644
index 0000000..b679070
--- /dev/null
+++ b/src/plugin.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+
+#include <comp.h>
+
+#define HOME_PLUGINDIR ".glxcomp/plugins"
+
+CompPlugin *plugins = 0;
+
+static Bool
+initPlugin (CompPlugin *p)
+{
+ CompDisplay *d = compDisplays;
+ int failed = 0;
+
+ if (!(*p->vTable->init) (p))
+ {
+ fprintf (stderr, "%s: InitPlugin '%s' failed\n", programName,
+ p->vTable->name);
+ return FALSE;
+ }
+
+ if (d)
+ {
+ if ((*d->initPluginForDisplay) (p, d))
+ {
+ CompScreen *s, *failedScreen = d->screens;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ if (!p->vTable->initScreen || (*s->initPluginForScreen) (p, s))
+ {
+ CompWindow *w, *failedWindow = s->windows;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (p->vTable->initWindow &&
+ !(*p->vTable->initWindow) (p, w))
+ {
+ fprintf (stderr, "%s: Plugin '%s':initWindow "
+ "failed\n", programName, p->vTable->name);
+ failedWindow = w;
+ failed = 1;
+ break;
+ }
+ }
+
+ for (w = s->windows; w != failedWindow; w = w->next)
+ {
+ if (p->vTable->finiWindow)
+ (*p->vTable->finiWindow) (p, w);
+ }
+ }
+ else
+ {
+ fprintf (stderr, "%s: Plugin '%s':initScreen failed\n",
+ programName, p->vTable->name);
+ failedScreen = s;
+ failed = 1;
+ break;
+ }
+ }
+
+ for (s = d->screens; s != failedScreen; s = s->next)
+ (*s->finiPluginForScreen) (p, s);
+ }
+ else
+ {
+ fprintf (stderr, "%s: Plugin '%s':initDisplay failed\n",
+ programName, p->vTable->name);
+
+ failed = 1;
+ (*d->finiPluginForDisplay) (p, d);
+ }
+ }
+
+ if (failed)
+ {
+ (*p->vTable->fini) (p);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+finiPlugin (CompPlugin *p)
+{
+ CompDisplay *d = compDisplays;
+ CompScreen *s;
+
+ if (d)
+ {
+ for (s = d->screens; s; s = s->next)
+ {
+ CompWindow *w = s->windows;
+
+ if (p->vTable->finiWindow)
+ {
+ for (w = s->windows; w; w = w->next)
+ (*p->vTable->finiWindow) (p, w);
+ }
+
+ (*s->finiPluginForScreen) (p, s);
+ }
+
+ (*d->finiPluginForDisplay) (p, d);
+ }
+
+ (*p->vTable->fini) (p);
+}
+
+void
+screenInitPlugins (CompScreen *s)
+{
+ CompPlugin *p;
+ int i, j = 0;
+
+ for (p = plugins; p; p = p->next)
+ j++;
+
+ while (j--)
+ {
+ i = 0;
+ for (p = plugins; i < j; p = p->next)
+ i++;
+
+ if (p->vTable->initScreen)
+ (*s->initPluginForScreen) (p, s);
+ }
+}
+
+void
+screenFiniPlugins (CompScreen *s)
+{
+ CompPlugin *p;
+
+ for (p = plugins; p; p = p->next)
+ {
+ if (p->vTable->finiScreen)
+ (*s->initPluginForScreen) (p, s);
+ }
+}
+
+void
+windowInitPlugins (CompWindow *w)
+{
+ CompPlugin *p;
+
+ for (p = plugins; p; p = p->next)
+ {
+ if (p->vTable->initWindow)
+ (*p->vTable->initWindow) (p, w);
+ }
+}
+
+void
+windowFiniPlugins (CompWindow *w)
+{
+ CompPlugin *p;
+
+ for (p = plugins; p; p = p->next)
+ {
+ if (p->vTable->finiWindow)
+ (*p->vTable->finiWindow) (p, w);
+ }
+}
+
+CompPlugin *
+findActivePlugin (char *name)
+{
+ CompPlugin *p;
+
+ for (p = plugins; p; p = p->next)
+ {
+ if (strcmp (p->vTable->name, name) == 0)
+ return p;
+ }
+
+ return 0;
+}
+
+CompPlugin *
+loadPlugin (char *name)
+{
+ CompPlugin *p;
+ char *file;
+
+ p = malloc (sizeof (CompPlugin));
+ if (!p)
+ return 0;
+
+ file = malloc (strlen (name) + 7);
+ if (!file)
+ {
+ free (p);
+ return 0;
+ }
+
+ sprintf (file, "lib%s.so", name);
+
+ p->next = 0;
+ p->dlhand = 0;
+ p->vTable = 0;
+
+ p->dlhand = dlopen (file, RTLD_LAZY);
+ if (!p->dlhand)
+ {
+ char *home, *plugindir;
+
+ home = getenv ("HOME");
+ if (home)
+ {
+ plugindir = malloc (strlen (home) +
+ strlen (HOME_PLUGINDIR) +
+ strlen (file) + 3);
+ if (plugindir)
+ {
+ sprintf (plugindir, "%s/%s/%s", home, HOME_PLUGINDIR, file);
+ p->dlhand = dlopen (plugindir, RTLD_LAZY);
+ free (plugindir);
+ }
+ }
+
+ if (!p->dlhand)
+ {
+ plugindir = malloc (strlen (PLUGINDIR) + strlen (file) + 2);
+ if (plugindir)
+ {
+ sprintf (plugindir, "%s/%s", PLUGINDIR, file);
+ p->dlhand = dlopen (plugindir, RTLD_LAZY);
+ free (plugindir);
+ }
+ }
+ }
+
+ if (p->dlhand)
+ {
+ PluginGetInfoProc getInfo;
+
+ dlerror ();
+
+ getInfo = (PluginGetInfoProc) dlsym (p->dlhand, "getCompPluginInfo");
+
+ if (dlerror () != 0)
+ getInfo = 0;
+
+ if (getInfo)
+ {
+ p->vTable = (*getInfo) ();
+ if (!p->vTable)
+ {
+ fprintf (stderr, "%s: Couldn't get vtable from '%s' plugin\n",
+ programName, file);
+
+ dlclose (p->dlhand);
+ free (p);
+ p = 0;
+ }
+ }
+ else
+ {
+ fprintf (stderr, "%s: Failed to lookup getCompPluginInfo in '%s' "
+ "plugin\n", programName, file);
+
+ dlclose (p->dlhand);
+ free (p);
+ p = 0;
+ }
+ }
+ else
+ {
+ fprintf (stderr, "%s: Couldn't load plugin '%s'\n", programName,
+ file);
+ free (p);
+ p = 0;
+ }
+
+ free (file);
+
+ return p;
+}
+
+void
+unloadPlugin (CompPlugin *p)
+{
+ dlclose (p->dlhand);
+ free (p);
+}
+
+Bool
+pushPlugin (CompPlugin *p)
+{
+ if (findActivePlugin (p->vTable->name))
+ {
+ fprintf (stderr, "%s: Plugin '%s' already active\n", programName,
+ p->vTable->name);
+
+ return FALSE;
+ }
+
+ p->next = plugins;
+ plugins = p;
+
+ if (!initPlugin (p))
+ {
+ fprintf (stderr, "%s: Couldn't activate plugin '%s'\n", programName,
+ p->vTable->name);
+ plugins = p->next;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+CompPlugin *
+popPlugin (void)
+{
+ CompPlugin *p = plugins;
+
+ if (!p)
+ return 0;
+
+ finiPlugin (p);
+
+ plugins = p->next;
+
+ return p;
+}
diff --git a/src/privates.c b/src/privates.c
new file mode 100644
index 0000000..b004452
--- /dev/null
+++ b/src/privates.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+
+#include <comp.h>
+
+int
+allocatePrivateIndex (int *len,
+ char **indices,
+ ReallocPrivatesProc reallocProc,
+ void *closure)
+{
+ char *newIndices;
+ int i;
+
+ for (i = 0; i < *len; i++)
+ {
+ if (!(*indices)[i])
+ {
+ (*indices)[i] = 1;
+ return i;
+ }
+ }
+
+ newIndices = (char *) realloc (*indices, (*len + 1) * sizeof (char));
+ if (!newIndices)
+ return -1;
+
+ newIndices[*len] = 1;
+ *indices = newIndices;
+
+ if (!(*reallocProc) (*len + 1, closure))
+ return -1;
+
+ return (*len)++;
+}
+
+void
+freePrivateIndex (int len,
+ char *indices,
+ int index)
+{
+ if (index < len)
+ indices[index] = 0;
+}
diff --git a/src/readpng.c b/src/readpng.c
new file mode 100644
index 0000000..a9e1661
--- /dev/null
+++ b/src/readpng.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <png.h>
+#include <setjmp.h>
+
+#include <comp.h>
+
+#define HOME_IMAGEDIR ".glxcomp/images"
+
+static void
+premultiplyData (png_structp png,
+ png_row_infop row_info,
+ png_bytep data)
+{
+ unsigned int i;
+
+ for (i = 0; i < row_info->rowbytes; i += 4)
+ {
+ unsigned char *base = &data[i];
+ unsigned char blue = base[0];
+ unsigned char green = base[1];
+ unsigned char red = base[2];
+ unsigned char alpha = base[3];
+ int p;
+
+ red = (unsigned) red * (unsigned) alpha / 255;
+ green = (unsigned) green * (unsigned) alpha / 255;
+ blue = (unsigned) blue * (unsigned) alpha / 255;
+
+ p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
+ memcpy (base, &p, sizeof (int));
+ }
+}
+
+Bool
+readPng (const char *filename,
+ char **data,
+ unsigned int *width,
+ unsigned int *height)
+{
+ static const int PNG_SIG_SIZE = 8;
+ unsigned char png_sig[PNG_SIG_SIZE];
+ FILE *file;
+ int sig_bytes;
+ png_struct *png;
+ png_info *info;
+ png_uint_32 png_width, png_height;
+ int depth, color_type, interlace, i;
+ unsigned int pixel_size;
+ png_byte **row_pointers;
+
+ file = fopen (filename, "r");
+ if (!file)
+ {
+ char *home, *imagedir;
+
+ home = getenv ("HOME");
+ if (home)
+ {
+ imagedir = malloc (strlen (home) +
+ strlen (HOME_IMAGEDIR) +
+ strlen (filename) + 3);
+ if (imagedir)
+ {
+ sprintf (imagedir, "%s/%s/%s", home, HOME_IMAGEDIR, filename);
+ file = fopen (imagedir, "r");
+ free (imagedir);
+ }
+ }
+
+ if (!file)
+ {
+ imagedir = malloc (strlen (IMAGEDIR) + strlen (filename) + 2);
+ if (imagedir)
+ {
+ sprintf (imagedir, "%s/%s", IMAGEDIR, filename);
+ file = fopen (imagedir, "r");
+ free (imagedir);
+ }
+
+ if (!file)
+ return FALSE;
+ }
+ }
+
+ sig_bytes = fread (png_sig, 1, PNG_SIG_SIZE, file);
+ if (png_check_sig (png_sig, sig_bytes) == 0)
+ {
+ fclose (file);
+ return FALSE;
+ }
+
+ png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png)
+ {
+ fclose (file);
+ return FALSE;
+ }
+
+ info = png_create_info_struct (png);
+ if (info == NULL)
+ {
+ fclose (file);
+ png_destroy_read_struct (&png, NULL, NULL);
+ return FALSE;
+ }
+
+ png_init_io (png, file);
+ png_set_sig_bytes (png, sig_bytes);
+
+ png_read_info (png, info);
+
+ png_get_IHDR (png, info,
+ &png_width, &png_height, &depth,
+ &color_type, &interlace, NULL, NULL);
+ *width = png_width;
+ *height = png_height;
+
+ /* convert palette/gray image to rgb */
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb (png);
+
+ /* expand gray bit depth if needed */
+ if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8)
+ png_set_gray_1_2_4_to_8 (png);
+
+ /* transform transparency to alpha */
+ if (png_get_valid(png, info, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha (png);
+
+ if (depth == 16)
+ png_set_strip_16 (png);
+
+ if (depth < 8)
+ png_set_packing (png);
+
+ /* convert grayscale to RGB */
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb (png);
+
+ if (interlace != PNG_INTERLACE_NONE)
+ png_set_interlace_handling (png);
+
+ png_set_bgr (png);
+ png_set_filler (png, 0xff, PNG_FILLER_AFTER);
+
+ png_set_read_user_transform_fn (png, premultiplyData);
+
+ png_read_update_info (png, info);
+
+ pixel_size = 4;
+ *data = (char *) malloc (png_width * png_height * pixel_size);
+ if (*data == NULL)
+ {
+ fclose (file);
+ return FALSE;
+ }
+
+ row_pointers = (png_byte **) malloc (png_height * sizeof (char *));
+ for (i=0; i < png_height; i++)
+ row_pointers[i] = (png_byte *) (*data + i * png_width * pixel_size);
+
+ png_read_image (png, row_pointers);
+ png_read_end (png, info);
+
+ free (row_pointers);
+ fclose (file);
+
+ png_destroy_read_struct (&png, &info, NULL);
+
+ return TRUE;
+}
diff --git a/src/screen.c b/src/screen.c
new file mode 100644
index 0000000..3664961
--- /dev/null
+++ b/src/screen.c
@@ -0,0 +1,1294 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <dlfcn.h>
+#include <string.h>
+
+#include <comp.h>
+
+#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
+
+static int
+reallocScreenPrivate (int size,
+ void *closure)
+{
+ CompDisplay *d = (CompDisplay *) closure;
+ CompScreen *s;
+ void *privates;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ privates = realloc (s->privates, size * sizeof (CompPrivate));
+ if (!privates)
+ return FALSE;
+
+ s->privates = (CompPrivate *) privates;
+ }
+
+ return TRUE;
+}
+
+int
+allocateScreenPrivateIndex (CompDisplay *display)
+{
+ return allocatePrivateIndex (&display->screenPrivateLen,
+ &display->screenPrivateIndices,
+ reallocScreenPrivate,
+ (void *) display);
+}
+
+void
+freeScreenPrivateIndex (CompDisplay *display,
+ int index)
+{
+ freePrivateIndex (display->screenPrivateLen,
+ display->screenPrivateIndices,
+ index);
+}
+
+CompOption *
+compGetScreenOptions (CompScreen *screen,
+ int *count)
+{
+ *count = NUM_OPTIONS (screen);
+ return screen->opt;
+}
+
+static Bool
+setScreenOption (CompScreen *screen,
+ char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ o = compFindOption (screen->opt, NUM_OPTIONS (screen), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index) {
+ case COMP_SCREEN_OPTION_REFRESH_RATE:
+ if (compSetIntOption (o, value))
+ {
+ screen->redrawTime = 1000 / o->value.i;
+ return TRUE;
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static Bool
+setScreenOptionForPlugin (CompScreen *screen,
+ char *plugin,
+ char *name,
+ CompOptionValue *value)
+{
+ CompPlugin *p;
+
+ p = findActivePlugin (plugin);
+ if (p && p->vTable->setScreenOption)
+ return (*p->vTable->setScreenOption) (screen, name, value);
+
+ return FALSE;
+}
+
+static void
+compScreenInitOptions (CompScreen *screen)
+{
+ CompOption *o;
+
+ o = &screen->opt[COMP_SCREEN_OPTION_REFRESH_RATE];
+ o->name = "refresh_rate";
+ o->shortDesc = "Refresh Rate";
+ o->longDesc = "The rate at which the screen is redrawn (times/second)";
+ o->type = CompOptionTypeInt;
+ o->value.i = defaultRefreshRate;
+ o->rest.i.min = 1;
+ o->rest.i.max = 200;
+}
+
+static Bool
+initPluginForScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ if (p->vTable->initScreen)
+ return (*p->vTable->initScreen) (p, s);
+
+ return FALSE;
+}
+
+static void
+finiPluginForScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ if (p->vTable->finiScreen)
+ (*p->vTable->finiScreen) (p, s);
+}
+
+static void
+frustum (GLfloat left,
+ GLfloat right,
+ GLfloat bottom,
+ GLfloat top,
+ GLfloat nearval,
+ GLfloat farval)
+{
+ GLfloat x, y, a, b, c, d;
+ GLfloat m[16];
+
+ x = (2.0 * nearval) / (right - left);
+ y = (2.0 * nearval) / (top - bottom);
+ a = (right + left) / (right - left);
+ b = (top + bottom) / (top - bottom);
+ c = -(farval + nearval) / ( farval - nearval);
+ d = -(2.0 * farval * nearval) / (farval - nearval);
+
+#define M(row,col) m[col*4+row]
+ M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
+ M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
+ M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
+ M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
+#undef M
+
+ glMultMatrixf (m);
+}
+
+static void
+perspective (GLfloat fovy,
+ GLfloat aspect,
+ GLfloat zNear,
+ GLfloat zFar)
+{
+ GLfloat xmin, xmax, ymin, ymax;
+
+ ymax = zNear * tan (fovy * M_PI / 360.0);
+ ymin = -ymax;
+ xmin = ymin * aspect;
+ xmax = ymax * aspect;
+
+ frustum (xmin, xmax, ymin, ymax, zNear, zFar);
+}
+
+static void
+reshape (CompScreen *s,
+ int w,
+ int h)
+{
+ s->width = w;
+ s->height = h;
+
+ glViewport (0, 0, w, h);
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ perspective (60.0f, 1.0f, 0.1f, 100.0f);
+ glMatrixMode (GL_MODELVIEW);
+
+ s->region.rects = &s->region.extents;
+ s->region.numRects = 1;
+ s->region.extents.x1 = 0;
+ s->region.extents.y1 = 0;
+ s->region.extents.x2 = w;
+ s->region.extents.y2 = h;
+ s->region.size = 1;
+}
+
+void
+configureScreen (CompScreen *s,
+ XConfigureEvent *ce)
+{
+ if (s->attrib.width != ce->width ||
+ s->attrib.height != ce->height)
+ {
+ s->attrib.width = ce->width;
+ s->attrib.height = ce->height;
+
+ reshape (s, ce->width, ce->height);
+
+ damageScreen (s);
+ }
+}
+
+static FuncPtr
+getProcAddress (CompScreen *s,
+ const char *name)
+{
+ static void *dlhand = NULL;
+ FuncPtr funcPtr = NULL;
+
+ if (s->getProcAddress)
+ funcPtr = s->getProcAddress ((GLubyte *) name);
+
+ if (!funcPtr)
+ {
+ if (!dlhand)
+ dlhand = dlopen (NULL, RTLD_LAZY);
+
+ if (dlhand)
+ {
+ dlerror ();
+ funcPtr = (FuncPtr) dlsym (dlhand, name);
+ if (dlerror () != NULL)
+ funcPtr = NULL;
+ }
+ }
+
+ return funcPtr;
+}
+
+void
+updateScreenBackground (CompScreen *screen,
+ CompTexture *texture)
+{
+ Display *dpy = screen->display->display;
+ Atom pixmapAtom, actualType;
+ int actualFormat, i, status;
+ unsigned int width = 1, height = 1, depth = 0;
+ unsigned long nItems;
+ unsigned long bytesAfter;
+ unsigned char *prop;
+ Pixmap pixmap = 0;
+
+ pixmapAtom = XInternAtom (dpy, "PIXMAP", FALSE);
+
+ for (i = 0; pixmap == 0 && i < 2; i++)
+ {
+ status = XGetWindowProperty (dpy, screen->root,
+ screen->display->xBackgroundAtom[i],
+ 0, 4, FALSE, AnyPropertyType,
+ &actualType, &actualFormat, &nItems,
+ &bytesAfter, &prop);
+
+ if (status == Success && nItems && prop)
+ {
+ if (actualType == pixmapAtom &&
+ actualFormat == 32 &&
+ nItems == 1)
+ {
+ Pixmap p;
+
+ memcpy (&p, prop, 4);
+
+ if (p)
+ {
+ unsigned int ui;
+ int i;
+ Window w;
+
+ if (XGetGeometry (dpy, p, &w, &i, &i,
+ &width, &height, &ui, &depth))
+ {
+ if (depth == screen->attrib.depth)
+ pixmap = p;
+ }
+ }
+ }
+
+ XFree (prop);
+ }
+ }
+
+ if (!testMode && pixmap)
+ {
+ if (pixmap == texture->pixmap)
+ return;
+
+ finiTexture (screen, texture);
+ initTexture (screen, texture);
+
+ if (!bindPixmapToTexture (screen, texture, pixmap,
+ width, height, depth))
+ {
+ fprintf (stderr, "%s: Couldn't bind background pixmap 0x%x to "
+ "texture\n", programName, (int) pixmap);
+ }
+ }
+ else
+ {
+ finiTexture (screen, texture);
+ initTexture (screen, texture);
+ }
+
+ if (!texture->name)
+ readImageToTexture (screen, texture, backgroundImage, &width, &height);
+
+ if (texture->target == GL_TEXTURE_2D)
+ {
+ glBindTexture (texture->target, texture->name);
+ glTexParameteri (texture->target, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri (texture->target, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glBindTexture (texture->target, 0);
+ }
+
+ screen->backgroundWidth = width;
+ screen->backgroundHeight = height;
+}
+
+Bool
+addScreen (CompDisplay *display,
+ int screenNum)
+{
+ CompScreen *s;
+ Display *dpy = display->display;
+ static char data = 0;
+ XColor black, dummy;
+ Pixmap bitmap;
+ XVisualInfo templ;
+ XVisualInfo *visinfo;
+ VisualID visualIDs[MAX_DEPTH + 1];
+ Window rootReturn, parentReturn;
+ Window *children;
+ unsigned int nchildren;
+ int defaultDepth, nvisinfo, value, i;
+ const char *glxExtensions, *glExtensions;
+ GLint stencilBits;
+
+ s = malloc (sizeof (CompScreen));
+ if (!s)
+ return FALSE;
+
+ s->windowPrivateIndices = 0;
+ s->windowPrivateLen = 0;
+
+ if (display->screenPrivateLen)
+ {
+ s->privates = malloc (display->screenPrivateLen *
+ sizeof (CompPrivate));
+ if (!s->privates)
+ {
+ free (s);
+ return FALSE;
+ }
+ }
+ else
+ s->privates = 0;
+
+ compScreenInitOptions (s);
+
+ s->redrawTime = 1000 / s->opt[COMP_SCREEN_OPTION_REFRESH_RATE].value.i;
+
+ s->display = display;
+
+ s->damage = XCreateRegion ();
+ if (!s->damage)
+ return FALSE;
+
+ s->buttonGrab = 0;
+ s->nButtonGrab = 0;
+ s->keyGrab = 0;
+ s->nKeyGrab = 0;
+
+ s->grabs = 0;
+ s->grabSize = 0;
+ s->maxGrab = 0;
+
+ s->pendingDestroys = 0;
+
+ s->screenNum = screenNum;
+ s->colormap = DefaultColormap (dpy, screenNum);
+ s->root = XRootWindow (dpy, screenNum);
+
+ if (testMode)
+ {
+ XSetWindowAttributes attrib;
+ XWMHints *wmHints;
+ XSizeHints *normalHints;
+ XClassHint *classHint;
+ int glx_attrib[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_STENCIL_SIZE, 2,
+ GLX_DOUBLEBUFFER,
+ None
+ };
+
+ visinfo = glXChooseVisual (dpy, screenNum, glx_attrib);
+ if (!visinfo)
+ {
+ int glx_attrib2[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None
+ };
+
+ visinfo = glXChooseVisual (dpy, screenNum, glx_attrib2);
+ if (!visinfo)
+ {
+ fprintf (stderr, "%s: Couldn't find a double buffered "
+ "RGB visual.\n", programName);
+ return FALSE;
+ }
+ }
+
+ attrib.colormap = XCreateColormap (dpy, s->root, visinfo->visual,
+ AllocNone);
+
+ normalHints = XAllocSizeHints ();
+ normalHints->flags = 0;
+ normalHints->x = 0;
+ normalHints->y = 0;
+ normalHints->width = 800;
+ normalHints->height = 600;
+
+ classHint = XAllocClassHint ();
+ classHint->res_name = "glxcompmgr";
+ classHint->res_class = "Glxcompmgr";
+
+ wmHints = XAllocWMHints ();
+ wmHints->flags = InputHint;
+ wmHints->input = TRUE;
+
+ s->root = XCreateWindow (dpy, s->root, 0, 0,
+ normalHints->width, normalHints->height, 0,
+ visinfo->depth, InputOutput, visinfo->visual,
+ CWColormap, &attrib);
+
+ XSetWMProtocols (dpy, s->root, &display->wmDeleteWindowAtom, 1);
+
+ XmbSetWMProperties (dpy, s->root,
+ "glxcompmgr - Test mode", "glxcompmgr",
+ programArgv, programArgc,
+ normalHints, wmHints, classHint);
+
+ s->fake[0] = XCreateWindow (dpy, s->root, 64, 32, 1, 1, 0,
+ visinfo->depth, InputOutput,
+ visinfo->visual,
+ CWColormap, &attrib);
+
+ s->fake[1] = XCreateWindow (dpy, s->root, 256, 256, 1, 1, 0,
+ visinfo->depth, InputOutput,
+ visinfo->visual,
+ CWColormap, &attrib);
+
+ XMapWindow (dpy, s->root);
+
+ XFree (wmHints);
+ XFree (classHint);
+ XFree (normalHints);
+ }
+ else
+ s->fake[0] = s->fake[1] = 0;
+
+ s->escapeKeyCode = XKeysymToKeycode (display->display,
+ XStringToKeysym ("Escape"));
+
+ s->allDamaged = TRUE;
+ s->next = 0;
+ s->exposeRects = 0;
+ s->sizeExpose = 0;
+ s->nExpose = 0;
+
+ s->rasterX = 0;
+ s->rasterY = 0;
+
+ s->windows = 0;
+ s->reverseWindows = 0;
+
+ s->stencilRef = 0x1;
+
+ s->nextRedraw = 0;
+
+ gettimeofday (&s->lastRedraw, 0);
+
+ s->setScreenOption = setScreenOption;
+ s->setScreenOptionForPlugin = setScreenOptionForPlugin;
+
+ s->initPluginForScreen = initPluginForScreen;
+ s->finiPluginForScreen = finiPluginForScreen;
+
+ s->preparePaintScreen = preparePaintScreen;
+ s->donePaintScreen = donePaintScreen;
+ s->paintScreen = paintScreen;
+ s->paintTransformedScreen = paintTransformedScreen;
+ s->paintBackground = paintBackground;
+ s->paintWindow = paintWindow;
+ s->invisibleWindowMove = invisibleWindowMove;
+
+ s->getProcAddress = 0;
+
+ if (s->root)
+ {
+ XSetWindowAttributes attrib;
+
+ attrib.override_redirect = 1;
+ s->grabWindow = XCreateWindow (dpy, s->root, -100, -100, 1, 1, 0,
+ CopyFromParent, CopyFromParent,
+ CopyFromParent, CWOverrideRedirect,
+ &attrib);
+
+ XMapWindow (dpy, s->grabWindow);
+ }
+
+ if (!XGetWindowAttributes (dpy, s->root, &s->attrib))
+ return FALSE;
+
+ s->activeWindow = None;
+
+ templ.visualid = XVisualIDFromVisual (s->attrib.visual);
+
+ visinfo = XGetVisualInfo (dpy, VisualIDMask, &templ, &nvisinfo);
+ if (!nvisinfo)
+ {
+ fprintf (stderr, "%s: Couldn't get visual info for default visual\n",
+ programName);
+ return FALSE;
+ }
+
+ defaultDepth = visinfo->depth;
+
+ if (!XAllocNamedColor (dpy, s->colormap, "black", &black, &dummy))
+ {
+ fprintf (stderr, "%s: Couldn't allocate color\n", programName);
+ return FALSE;
+ }
+
+ bitmap = XCreateBitmapFromData (dpy, s->root, &data, 1, 1);
+ if (!bitmap)
+ {
+ fprintf (stderr, "%s: Couldn't create bitmap\n", programName);
+ return FALSE;
+ }
+
+ s->invisibleCursor = XCreatePixmapCursor (dpy, bitmap, bitmap,
+ &black, &black, 0, 0);
+ if (!s->invisibleCursor)
+ {
+ fprintf (stderr, "%s: Couldn't create invisible cursor\n",
+ programName);
+ return FALSE;
+ }
+
+ XFreePixmap (dpy, bitmap);
+ XFreeColors (dpy, s->colormap, &black.pixel, 1, 0);
+
+ glXGetConfig (dpy, visinfo, GLX_USE_GL, &value);
+ if (!value)
+ {
+ fprintf (stderr, "%s: Root visual is not a GL visual\n",
+ programName);
+ return FALSE;
+ }
+
+ glXGetConfig (dpy, visinfo, GLX_DOUBLEBUFFER, &value);
+ if (!value)
+ {
+ fprintf (stderr,
+ "%s: Root visual is not a double buffered GL visual\n",
+ programName);
+ return FALSE;
+ }
+
+ s->ctx = glXCreateContext (dpy, visinfo, NULL, TRUE);
+ if (!s->ctx)
+ {
+ fprintf (stderr, "%s: glXCreateContext failed\n", programName);
+ return FALSE;
+ }
+
+ XFree (visinfo);
+
+ /* we don't want to allocate back, stencil or depth buffers for pixmaps
+ so lets see if we can find an approriate visual without these buffers */
+ for (i = 0; i <= MAX_DEPTH; i++)
+ {
+ int j, db, stencil, depth;
+
+ visualIDs[i] = 0;
+
+ db = MAXSHORT;
+ stencil = MAXSHORT;
+ depth = MAXSHORT;
+
+ templ.depth = i;
+
+ visinfo = XGetVisualInfo (dpy, VisualDepthMask, &templ, &nvisinfo);
+ for (j = 0; j < nvisinfo; j++)
+ {
+ glXGetConfig (dpy, &visinfo[j], GLX_USE_GL, &value);
+ if (!value)
+ continue;
+
+ glXGetConfig (dpy, &visinfo[j], GLX_DOUBLEBUFFER, &value);
+ if (value > db)
+ continue;
+
+ db = value;
+ glXGetConfig (dpy, &visinfo[j], GLX_STENCIL_SIZE, &value);
+ if (value > stencil)
+ continue;
+
+ stencil = value;
+ glXGetConfig (dpy, &visinfo[j], GLX_DEPTH_SIZE, &value);
+ if (value > depth)
+ continue;
+
+ depth = value;
+ visualIDs[i] = visinfo[j].visualid;
+ }
+
+ if (nvisinfo)
+ XFree (visinfo);
+ }
+
+ /* create contexts for supported depths */
+ for (i = 0; i <= MAX_DEPTH; i++)
+ {
+ templ.visualid = visualIDs[i];
+ s->glxPixmapVisuals[i] = XGetVisualInfo (dpy,
+ VisualIDMask,
+ &templ,
+ &nvisinfo);
+ }
+
+ if (!s->glxPixmapVisuals[defaultDepth])
+ {
+ fprintf (stderr, "%s: No GL visual for default depth, "
+ "this isn't going to work.\n", programName);
+ return FALSE;
+ }
+
+ glXMakeCurrent (dpy, s->root, s->ctx);
+ currentRoot = s->root;
+
+ glxExtensions = glXQueryExtensionsString (s->display->display, screenNum);
+ if (!testMode && !strstr (glxExtensions, "GLX_MESA_render_texture"))
+ {
+ fprintf (stderr, "%s: GLX_MESA_render_texture is missing\n",
+ programName);
+ return FALSE;
+ }
+
+ s->getProcAddress = (GLXGetProcAddressProc)
+ getProcAddress (s, "glXGetProcAddressARB");
+ s->bindTexImage = (GLXBindTexImageProc)
+ getProcAddress (s, "glXBindTexImageMESA");
+ s->releaseTexImage = (GLXReleaseTexImageProc)
+ getProcAddress (s, "glXReleaseTexImageMESA");
+ s->queryDrawable = (GLXQueryDrawableProc)
+ getProcAddress (s, "glXQueryDrawable");
+
+ if (!testMode && !s->bindTexImage)
+ {
+ fprintf (stderr, "%s: glXBindTexImageMESA is missing\n", programName);
+ return FALSE;
+ }
+
+ if (!testMode && !s->releaseTexImage)
+ {
+ fprintf (stderr, "%s: glXReleaseTexImageMESA is missing\n",
+ programName);
+ return FALSE;
+ }
+
+ if (!testMode && !s->queryDrawable)
+ {
+ fprintf (stderr, "%s: glXQueryDrawable is missing\n", programName);
+ return FALSE;
+ }
+
+ glExtensions = (const char *) glGetString (GL_EXTENSIONS);
+ if (strstr (glExtensions, "GL_NV_texture_rectangle") ||
+ strstr (glExtensions, "GL_EXT_texture_rectangle") ||
+ strstr (glExtensions, "GL_ARB_texture_rectangle"))
+ s->textureRectangle = 1;
+
+ if (strstr (glExtensions, "GL_ARB_texture_non_power_of_two"))
+ s->textureNonPowerOfTwo = 1;
+
+ if (!(s->textureRectangle || s->textureNonPowerOfTwo))
+ {
+ fprintf (stderr, "%s: Support for non power of two textures missing\n",
+ programName);
+ return FALSE;
+ }
+
+ initTexture (s, &s->backgroundTexture);
+
+ s->desktopWindowCount = 0;
+
+ glGetIntegerv (GL_STENCIL_BITS, &stencilBits);
+ if (!stencilBits)
+ {
+ fprintf (stderr, "%s: No stencil buffer. Clipping of transformed "
+ "windows is not going to be correct when screen is "
+ "transformed.\n", programName);
+ }
+
+ glClearColor (0.0, 0.0, 0.0, 1.0);
+ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable (GL_CULL_FACE);
+ glDisable (GL_BLEND);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnableClientState (GL_VERTEX_ARRAY);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+ glColor4usv (defaultColor);
+
+ s->activeWindow = getActiveWindow (display, s->root);
+
+ reshape (s, s->attrib.width, s->attrib.height);
+
+ s->next = display->screens;
+ display->screens = s;
+
+ screenInitPlugins (s);
+
+ XSelectInput (dpy, s->root,
+ SubstructureNotifyMask |
+ StructureNotifyMask |
+ PropertyChangeMask |
+ ExposureMask |
+ ButtonPressMask |
+ ButtonReleaseMask |
+ ButtonMotionMask);
+
+ XQueryTree (dpy, s->root,
+ &rootReturn, &parentReturn,
+ &children, &nchildren);
+
+ for (i = 0; i < nchildren; i++)
+ {
+ if (children[i] == s->grabWindow)
+ continue;
+
+ addWindow (s, children[i], i ? children[i - 1] : 0);
+ }
+
+ XFree (children);
+
+ return TRUE;
+}
+
+void
+damageScreenRegion (CompScreen *screen,
+ Region region)
+{
+ if (screen->allDamaged)
+ return;
+
+ XUnionRegion (screen->damage, region, screen->damage);
+}
+
+void
+damageScreen (CompScreen *s)
+{
+ s->allDamaged = TRUE;
+}
+
+CompWindow *
+findWindowAtScreen (CompScreen *s,
+ Window id)
+{
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ if (w->id == id)
+ return w;
+
+ return 0;
+}
+
+CompWindow *
+findClientWindowAtScreen (CompScreen *s,
+ Window id)
+{
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ if (w->client == id)
+ return w;
+
+ return 0;
+}
+
+void
+insertWindowIntoScreen (CompScreen *s,
+ CompWindow *w,
+ Window aboveId)
+{
+ CompWindow *p;
+
+ if (s->windows)
+ {
+ for (p = s->windows; p; p = p->next)
+ {
+ if (p->id == aboveId)
+ {
+ w->next = p->next;
+ w->prev = p;
+ if (p->next)
+ p->next->prev = w;
+ p->next = w;
+
+ if (s->reverseWindows == p)
+ s->reverseWindows = w;
+
+ return;
+ }
+
+ if (!p->next)
+ {
+ p->next = w;
+ w->next = NULL;
+ w->prev = p;
+
+ s->reverseWindows = w;
+
+ return;
+ }
+ }
+ }
+ else
+ {
+ s->reverseWindows = s->windows = w;
+ w->prev = w->next = NULL;
+ }
+}
+
+void
+unhookWindowFromScreen (CompScreen *s,
+ CompWindow *w)
+{
+ CompWindow *p;
+
+ if (s->windows == w)
+ {
+ s->windows = w->next;
+ if (w->next)
+ w->next->prev = NULL;
+ }
+
+ if (s->reverseWindows == w)
+ {
+ s->reverseWindows = w->prev;
+ if (w->prev)
+ w->prev->next = NULL;
+ }
+
+ for (p = s->windows; p; p = p->next)
+ {
+ if (p->next == w)
+ {
+ p->next = w->next;
+ if (w->next)
+ w->next->prev = p;
+
+ p->next = w->next;
+ break;
+ }
+ }
+}
+
+#define POINTER_GRAB_MASK (ButtonReleaseMask | \
+ ButtonPressMask | \
+ PointerMotionMask)
+int
+pushScreenGrab (CompScreen *s,
+ Cursor cursor)
+{
+ if (s->maxGrab == 0)
+ {
+ int status;
+
+ status = XGrabPointer (s->display->display, s->grabWindow, TRUE,
+ POINTER_GRAB_MASK,
+ GrabModeAsync, GrabModeAsync,
+ s->root, cursor,
+ CurrentTime);
+
+ if (status == GrabSuccess)
+ {
+ status = XGrabKeyboard (s->display->display,
+ s->grabWindow, TRUE,
+ GrabModeAsync, GrabModeAsync,
+ CurrentTime);
+ if (status != GrabSuccess)
+ {
+ XUngrabPointer (s->display->display, CurrentTime);
+ return 0;
+ }
+ }
+ else
+ return 0;
+ }
+ else
+ {
+ XChangeActivePointerGrab (s->display->display, POINTER_GRAB_MASK,
+ cursor, CurrentTime);
+ }
+
+ if (s->grabSize <= s->maxGrab)
+ {
+ s->grabs = realloc (s->grabs, sizeof (CompGrab) * (s->maxGrab + 1));
+ if (!s->grabs)
+ return 0;
+
+ s->grabSize = s->maxGrab + 1;
+ }
+
+ s->grabs[s->maxGrab].cursor = cursor;
+ s->grabs[s->maxGrab].active = TRUE;
+
+ s->maxGrab++;
+
+ return s->maxGrab;
+}
+
+void
+removeScreenGrab (CompScreen *s,
+ int index,
+ XPoint *restorePointer)
+{
+ int maxGrab;
+
+ index--;
+ if (index < 0 || index >= s->maxGrab)
+ abort ();
+
+ s->grabs[index].cursor = None;
+ s->grabs[index].active = FALSE;
+
+ for (maxGrab = s->maxGrab; maxGrab; maxGrab--)
+ if (s->grabs[maxGrab - 1].active)
+ break;
+
+ if (maxGrab != s->maxGrab)
+ {
+ if (maxGrab)
+ {
+ XChangeActivePointerGrab (s->display->display,
+ POINTER_GRAB_MASK,
+ s->grabs[s->maxGrab - 1].cursor,
+ CurrentTime);
+ }
+ else
+ {
+ if (restorePointer)
+ XWarpPointer (s->display->display, None, s->root, 0, 0, 0, 0,
+ restorePointer->x, restorePointer->y);
+
+ XUngrabPointer (s->display->display, CurrentTime);
+ XUngrabKeyboard (s->display->display, CurrentTime);
+ }
+ s->maxGrab = maxGrab;
+ }
+}
+
+static Bool
+addPassiveKeyGrab (CompScreen *s,
+ CompKeyBinding *key)
+{
+ CompKeyGrab *keyGrab;
+ unsigned int modifiers, mask;
+ int i;
+
+ modifiers = key->modifiers & ~(CompPressMask | CompReleaseMask);
+ if (modifiers == key->modifiers)
+ return TRUE;
+
+ for (i = 0; i < s->nKeyGrab; i++)
+ {
+ if (key->keycode == s->keyGrab[i].keycode &&
+ modifiers == s->keyGrab[i].modifiers)
+ {
+ s->keyGrab[i].count++;
+ return TRUE;
+ }
+ }
+
+ keyGrab = realloc (s->keyGrab, sizeof (CompKeyGrab) * (s->nKeyGrab + 1));
+ if (!keyGrab)
+ return FALSE;
+
+ s->keyGrab = keyGrab;
+
+ mask = virtualToRealModMask (s->display, modifiers);
+ if (!(mask & CompNoMask))
+ {
+ compCheckForError ();
+
+ XGrabKey (s->display->display,
+ key->keycode,
+ mask,
+ s->root,
+ TRUE,
+ GrabModeAsync,
+ GrabModeAsync);
+
+ XSync (s->display->display, FALSE);
+
+ if (compCheckForError ())
+ {
+
+#ifdef DEBUG
+ KeySym keysym;
+ char *keyname;
+
+ keysym = XKeycodeToKeysym (s->display->display,
+ key->keycode,
+ 0);
+ keyname = XKeysymToString (keysym);
+
+ fprintf (stderr, "XGrabKey failed: %s 0x%x\n",
+ keyname, modifiers);
+#endif
+
+ return FALSE;
+ }
+ }
+
+ s->keyGrab[s->nKeyGrab].keycode = key->keycode;
+ s->keyGrab[s->nKeyGrab].modifiers = modifiers;
+ s->keyGrab[s->nKeyGrab].count = 1;
+
+ s->nKeyGrab++;
+
+ return TRUE;
+}
+
+static void
+removePassiveKeyGrab (CompScreen *s,
+ CompKeyBinding *key)
+{
+ unsigned int modifiers, mask;
+ int i;
+
+ modifiers = key->modifiers & ~(CompPressMask | CompReleaseMask);
+ if (modifiers == key->modifiers)
+ return;
+
+ for (i = 0; i < s->nKeyGrab; i++)
+ {
+ if (key->keycode == s->keyGrab[i].keycode &&
+ modifiers == s->keyGrab[i].modifiers)
+ {
+ s->keyGrab[i].count--;
+ if (s->keyGrab[i].count)
+ return;
+
+ s->nKeyGrab--;
+ s->keyGrab = realloc (s->keyGrab,
+ sizeof (CompKeyGrab) * s->nKeyGrab);
+
+ mask = virtualToRealModMask (s->display, modifiers);
+ if (!(mask & CompNoMask))
+ {
+ XUngrabKey (s->display->display,
+ key->keycode,
+ mask,
+ s->root);
+ }
+ }
+ }
+}
+
+static void
+updatePassiveKeyGrabs (CompScreen *s)
+{
+ unsigned int mask;
+ int i;
+
+ XUngrabKey (s->display->display, AnyKey, AnyModifier, s->root);
+
+ for (i = 0; i < s->nKeyGrab; i++)
+ {
+ mask = virtualToRealModMask (s->display, s->keyGrab[i].modifiers);
+ if (!(mask & CompNoMask))
+ {
+ XGrabKey (s->display->display,
+ s->keyGrab[i].keycode,
+ mask,
+ s->root,
+ TRUE,
+ GrabModeAsync,
+ GrabModeAsync);
+ }
+ }
+}
+
+static Bool
+addPassiveButtonGrab (CompScreen *s,
+ CompButtonBinding *button)
+{
+ CompButtonGrab *buttonGrab;
+ unsigned int modifiers, mask;
+ int i;
+
+ modifiers = button->modifiers & ~(CompPressMask | CompReleaseMask);
+ if (modifiers == button->modifiers)
+ return TRUE;
+
+ for (i = 0; i < s->nButtonGrab; i++)
+ {
+ if (button->button == s->buttonGrab[i].button &&
+ modifiers == s->buttonGrab[i].modifiers)
+ {
+ s->buttonGrab[i].count++;
+ return TRUE;
+ }
+ }
+
+ buttonGrab = realloc (s->buttonGrab,
+ sizeof (CompButtonGrab) * (s->nButtonGrab + 1));
+ if (!buttonGrab)
+ return FALSE;
+
+ s->buttonGrab = buttonGrab;
+
+ mask = virtualToRealModMask (s->display, modifiers);
+ if (!(mask & CompNoMask))
+ {
+ compCheckForError ();
+
+ XGrabButton (s->display->display,
+ button->button,
+ mask,
+ s->root,
+ TRUE,
+ POINTER_GRAB_MASK,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ None);
+
+ XSync (s->display->display, FALSE);
+
+ if (compCheckForError ())
+ {
+
+#ifdef DEBUG
+ fprintf (stderr, "XGrabButton failed: %s 0x%x\n",
+ button->button, modifiers);
+#endif
+
+ return FALSE;
+ }
+ }
+
+ s->buttonGrab[s->nButtonGrab].button = button->button;
+ s->buttonGrab[s->nButtonGrab].modifiers = modifiers;
+ s->buttonGrab[s->nButtonGrab].count = 1;
+
+ s->nButtonGrab++;
+
+ return TRUE;
+}
+
+static void
+removePassiveButtonGrab (CompScreen *s,
+ CompButtonBinding *button)
+{
+ unsigned int modifiers, mask;
+ int i;
+
+ modifiers = button->modifiers & ~(CompPressMask | CompReleaseMask);
+ if (modifiers == button->modifiers)
+ return;
+
+ for (i = 0; i < s->nButtonGrab; i++)
+ {
+ if (button->button == s->buttonGrab[i].button &&
+ modifiers == s->buttonGrab[i].modifiers)
+ {
+ s->buttonGrab[i].count--;
+ if (s->buttonGrab[i].count)
+ return;
+
+ s->nButtonGrab--;
+ s->buttonGrab = realloc (s->buttonGrab,
+ sizeof (CompButtonGrab) * s->nButtonGrab);
+
+ mask = virtualToRealModMask (s->display, modifiers);
+ if (!(mask & CompNoMask))
+ {
+ XUngrabButton (s->display->display,
+ button->button,
+ mask,
+ s->root);
+ }
+ }
+ }
+}
+
+static void
+updatePassiveButtonGrabs (CompScreen *s)
+{
+ unsigned int mask;
+ int i;
+
+ XUngrabButton (s->display->display, AnyButton, AnyModifier, s->root);
+
+ for (i = 0; i < s->nButtonGrab; i++)
+ {
+ mask = virtualToRealModMask (s->display, s->buttonGrab[i].modifiers);
+ if (!(mask & CompNoMask))
+ {
+ XGrabButton (s->display->display,
+ s->buttonGrab[i].button,
+ mask,
+ s->root,
+ TRUE,
+ POINTER_GRAB_MASK,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ None);
+ }
+ }
+}
+
+Bool
+addScreenBinding (CompScreen *s,
+ CompBinding *binding)
+{
+ if (binding->type == CompBindingTypeKey)
+ return addPassiveKeyGrab (s, &binding->u.key);
+ else if (binding->type == CompBindingTypeButton)
+ return addPassiveButtonGrab (s, &binding->u.button);
+
+ return FALSE;
+}
+
+void
+removeScreenBinding (CompScreen *s,
+ CompBinding *binding)
+{
+ if (binding->type == CompBindingTypeKey)
+ removePassiveKeyGrab (s, &binding->u.key);
+ else if (binding->type == CompBindingTypeButton)
+ removePassiveButtonGrab (s, &binding->u.button);
+}
+
+void
+updatePassiveGrabs (CompScreen *s)
+{
+ updatePassiveButtonGrabs (s);
+ updatePassiveKeyGrabs (s);
+}
diff --git a/src/texture.c b/src/texture.c
new file mode 100644
index 0000000..6ef4e74
--- /dev/null
+++ b/src/texture.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <comp.h>
+
+void
+initTexture (CompScreen *screen,
+ CompTexture *texture)
+{
+ texture->name = 0;
+ texture->target = GL_TEXTURE_2D;
+ texture->dx = 0.0f;
+ texture->dy = 0.0f;
+ texture->pixmap = None;
+ texture->filter = COMP_TEXTURE_FILTER_FAST;
+}
+
+void
+finiTexture (CompScreen *screen,
+ CompTexture *texture)
+{
+ if (texture->name)
+ {
+ releasePixmapFromTexture (screen, texture);
+ glDeleteTextures (1, &texture->name);
+ }
+}
+
+Bool
+readImageToTexture (CompScreen *screen,
+ CompTexture *texture,
+ char *imageFileName,
+ unsigned int *returnWidth,
+ unsigned int *returnHeight)
+{
+ char *data, *image;
+ unsigned int width, height;
+ int i;
+
+ if (!readPng (imageFileName, &image, &width, &height))
+ {
+ fprintf (stderr, "%s: Failed to load image: %s\n",
+ programName, imageFileName);
+ return FALSE;
+ }
+
+ data = malloc (4 * width * height);
+ if (!data)
+ {
+ free (image);
+ return FALSE;
+ }
+
+ for (i = 0; i < height; i++)
+ memcpy (&data[i * width * 4],
+ &image[(height - i - 1) * width * 4],
+ width * 4);
+
+ free (image);
+
+ releasePixmapFromTexture (screen, texture);
+
+ if (screen->textureNonPowerOfTwo ||
+ (POWER_OF_TWO (width) && POWER_OF_TWO (height)))
+ {
+ texture->target = GL_TEXTURE_2D;
+ texture->dx = 1.0f / width;
+ texture->dy = 1.0f / height;
+ }
+ else
+ {
+ texture->target = GL_TEXTURE_RECTANGLE_NV;
+ texture->dx = texture->dy = 1.0f;
+ }
+
+ if (!texture->name)
+ glGenTextures (1, &texture->name);
+
+ glBindTexture (texture->target, texture->name);
+
+ glTexImage2D (texture->target, 0, GL_RGB, width, height, 0, GL_BGRA,
+
+#if IMAGE_BYTE_ORDER == MSBFirst
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+#else
+ GL_UNSIGNED_BYTE,
+#endif
+
+ data);
+
+ texture->filter = COMP_TEXTURE_FILTER_FAST;
+
+ glTexParameteri (texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri (texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glTexParameteri (texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri (texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glBindTexture (texture->target, 0);
+
+ free (data);
+
+ *returnWidth = width;
+ *returnHeight = height;
+
+ return TRUE;
+}
+
+Bool
+bindPixmapToTexture (CompScreen *screen,
+ CompTexture *texture,
+ Pixmap pixmap,
+ int width,
+ int height,
+ int depth)
+{
+ XVisualInfo *visinfo;
+ unsigned int target;
+
+ visinfo = screen->glxPixmapVisuals[depth];
+ if (!visinfo)
+ {
+ fprintf (stderr, "%s: No GL visual for depth %d\n",
+ programName, depth);
+
+ return FALSE;
+ }
+
+ texture->pixmap = glXCreateGLXPixmap (screen->display->display,
+ visinfo, pixmap);
+ if (!texture->pixmap)
+ {
+ fprintf (stderr, "%s: glXCreateGLXPixmap failed\n", programName);
+
+ return FALSE;
+ }
+
+ if (screen->queryDrawable (screen->display->display,
+ texture->pixmap,
+ GLX_TEXTURE_TARGET_EXT,
+ &target))
+ {
+ fprintf (stderr, "%s: glXQueryDrawable failed\n", programName);
+
+ glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
+ texture->pixmap = None;
+
+ return FALSE;
+ }
+
+ switch (target) {
+ case GLX_TEXTURE_2D_EXT:
+ texture->target = GL_TEXTURE_2D;
+ texture->dx = 1.0f / width;
+ texture->dy = 1.0f / height;
+ break;
+ case GLX_TEXTURE_RECTANGLE_EXT:
+ texture->target = GL_TEXTURE_RECTANGLE_ARB;
+ texture->dx = texture->dy = 1.0f;
+ break;
+ default:
+ fprintf (stderr, "%s: pixmap 0x%x can't be bound to texture\n",
+ programName, (int) pixmap);
+
+ glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
+ texture->pixmap = None;
+
+ return FALSE;
+ }
+
+ if (!texture->name)
+ glGenTextures (1, &texture->name);
+
+ glBindTexture (texture->target, texture->name);
+
+ if (!screen->bindTexImage (screen->display->display,
+ texture->pixmap,
+ GLX_FRONT_LEFT_EXT))
+ {
+ fprintf (stderr, "%s: glXBindTexImage failed\n", programName);
+
+ glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
+ texture->pixmap = None;
+
+ return FALSE;
+ }
+
+ texture->filter = COMP_TEXTURE_FILTER_FAST;
+
+ glTexParameteri (texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri (texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glTexParameteri (texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri (texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glBindTexture (texture->target, 0);
+
+ return TRUE;
+}
+
+void
+releasePixmapFromTexture (CompScreen *screen,
+ CompTexture *texture)
+{
+ if (texture->pixmap)
+ {
+ glEnable (texture->target);
+ glBindTexture (texture->target, texture->name);
+
+ screen->releaseTexImage (screen->display->display,
+ texture->pixmap,
+ GLX_FRONT_LEFT_EXT);
+
+ glBindTexture (texture->target, 0);
+ glDisable (texture->target);
+
+ glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
+ texture->pixmap = None;
+ }
+}
+
+void
+enableTexture (CompScreen *screen,
+ CompTexture *texture,
+ CompTextureFilter filter)
+{
+ glEnable (texture->target);
+ glBindTexture (texture->target, texture->name);
+
+ if (filter != texture->filter)
+ {
+ switch (filter) {
+ case COMP_TEXTURE_FILTER_FAST:
+ glTexParameteri (texture->target,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glTexParameteri (texture->target,
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ break;
+ case COMP_TEXTURE_FILTER_GOOD:
+ glTexParameteri (texture->target,
+ GL_TEXTURE_MIN_FILTER,
+ screen->display->textureFilter);
+ glTexParameteri (texture->target,
+ GL_TEXTURE_MAG_FILTER,
+ screen->display->textureFilter);
+ break;
+ }
+
+ texture->filter = filter;
+ }
+}
+
+void
+disableTexture (CompTexture *texture)
+{
+ glBindTexture (texture->target, 0);
+ glDisable (texture->target);
+}
diff --git a/src/window.c b/src/window.c
new file mode 100644
index 0000000..8c9a126
--- /dev/null
+++ b/src/window.c
@@ -0,0 +1,605 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. 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.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
+#include <X11/extensions/Xcomposite.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <comp.h>
+
+static int
+reallocWindowPrivates (int size,
+ void *closure)
+{
+ CompScreen *s = (CompScreen *) closure;
+ CompWindow *w;
+ void *privates;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ privates = realloc (w->privates, size * sizeof (CompPrivate));
+ if (!privates)
+ return FALSE;
+
+ w->privates = (CompPrivate *) privates;
+ }
+
+ return TRUE;
+}
+
+int
+allocateWindowPrivateIndex (CompScreen *screen)
+{
+ return allocatePrivateIndex (&screen->windowPrivateLen,
+ &screen->windowPrivateIndices,
+ reallocWindowPrivates,
+ (void *) screen);
+}
+
+void
+freeWindowPrivateIndex (CompScreen *screen,
+ int index)
+{
+ freePrivateIndex (screen->windowPrivateLen,
+ screen->windowPrivateIndices,
+ index);
+}
+
+static Window
+tryChildren (CompDisplay *display,
+ Window win)
+{
+ Window root, parent;
+ Window *children;
+ unsigned int nchildren;
+ unsigned int i;
+ Atom type = None;
+ int format;
+ unsigned long nitems, after;
+ unsigned char *data;
+ Window inf = 0;
+
+ if (!XQueryTree (display->display, win, &root, &parent,
+ &children, &nchildren))
+ return 0;
+
+ for (i = 0; !inf && (i < nchildren); i++)
+ {
+ data = NULL;
+
+ XGetWindowProperty (display->display, children[i],
+ display->wmStateAtom, 0, 0,
+ False, AnyPropertyType, &type, &format, &nitems,
+ &after, &data);
+ if (data)
+ XFree (data);
+
+ if (type)
+ inf = children[i];
+ }
+
+ for (i = 0; !inf && (i < nchildren); i++)
+ inf = tryChildren (display, children[i]);
+
+ if (children)
+ XFree (children);
+
+ return inf;
+}
+
+static Window
+clientWindow (CompDisplay *display,
+ Window win)
+{
+ Atom type = None;
+ int format;
+ unsigned long nitems, after;
+ unsigned char *data = NULL;
+ Window inf;
+
+ XGetWindowProperty (display->display, win, display->wmStateAtom, 0, 0,
+ False, AnyPropertyType, &type, &format, &nitems,
+ &after, &data);
+
+ if (data)
+ XFree (data);
+
+ if (type)
+ return win;
+
+ inf = tryChildren (display, win);
+ if (!inf)
+ inf = win;
+
+ return inf;
+}
+
+Window
+getActiveWindow (CompDisplay *display,
+ Window root)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+
+ result = XGetWindowProperty (display->display, root,
+ display->winActiveAtom, 0L, 1L, False,
+ XA_WINDOW, &actual, &format,
+ &n, &left, &data);
+
+ if (result == Success && n && data)
+ {
+ Window w;
+
+ memcpy (&w, data, sizeof (Window));
+ XFree ((void *) data);
+
+ return w;
+ }
+
+ return None;
+}
+
+Atom
+getWindowType (CompDisplay *display,
+ Window id)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+
+ result = XGetWindowProperty (display->display, id, display->winTypeAtom,
+ 0L, 1L, FALSE, XA_ATOM, &actual, &format,
+ &n, &left, &data);
+
+ if (result == Success && n && data)
+ {
+ Atom a;
+
+ memcpy (&a, data, sizeof (Atom));
+ XFree ((void *) data);
+
+ return a;
+ }
+
+ return display->winNormalAtom;
+}
+
+unsigned short
+getWindowOpacity (CompDisplay *display,
+ Window id)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+
+ result = XGetWindowProperty (display->display, id, display->winOpacityAtom,
+ 0L, 1L, FALSE, XA_CARDINAL, &actual, &format,
+ &n, &left, &data);
+
+ if (result == Success && n && data)
+ {
+ unsigned int o;
+
+ memcpy (&o, data, sizeof (Atom));
+ XFree ((void *) data);
+
+ return (o / 0xffff);
+ }
+
+ return MAXSHORT;
+}
+
+void
+bindWindow (CompWindow *w)
+{
+ if (testMode)
+ {
+ unsigned int width, height;
+
+ if (readImageToTexture (w->screen, &w->texture,
+ windowImage, &width, &height))
+ {
+ XResizeWindow (w->screen->display->display, w->id, width, height);
+
+ w->width = width;
+ w->height = height;
+ }
+
+ w->pixmap = 1;
+ }
+ else
+ {
+ w->pixmap = XCompositeNameWindowPixmap (w->screen->display->display,
+ w->id);
+ if (!w->pixmap)
+ {
+ fprintf (stderr, "%s: XCompositeNameWindowPixmap failed\n",
+ programName);
+ return;
+ }
+
+ if (!bindPixmapToTexture (w->screen, &w->texture, w->pixmap,
+ w->width, w->height,
+ w->attrib.depth))
+ {
+ fprintf (stderr, "%s: Couldn't bind redirected window 0x%x to "
+ "texture\n", programName, (int) w->id);
+ }
+ }
+}
+
+void
+releaseWindow (CompWindow *w)
+{
+ if (w->pixmap)
+ {
+ releasePixmapFromTexture (w->screen, &w->texture);
+
+ if (!testMode)
+ XFreePixmap (w->screen->display->display, w->pixmap);
+
+ w->pixmap = None;
+ }
+}
+
+static void
+freeWindow (CompWindow *w)
+{
+ releaseWindow (w);
+
+ if (w->texture.name)
+ finiTexture (w->screen, &w->texture);
+
+ if (w->clip)
+ XDestroyRegion (w->clip);
+
+ if (w->region)
+ XDestroyRegion (w->region);
+
+ if (w->privates)
+ free (w->privates);
+
+ free (w);
+}
+
+void
+addWindowDamage (CompWindow *w)
+{
+ if (w->attrib.map_state == IsViewable)
+ damageScreenRegion (w->screen, w->region);
+}
+
+void
+updateWindowRegion (CompWindow *w)
+{
+ REGION rect;
+ XRectangle r, *rects, *shapeRects = 0;
+ int i, n = 0;
+
+ EMPTY_REGION (w->region);
+
+ if (w->screen->display->shapeExtension)
+ {
+ int order;
+
+ shapeRects = XShapeGetRectangles (w->screen->display->display, w->id,
+ ShapeBounding, &n, &order);
+ }
+
+ if (n < 2)
+ {
+ r.x = 0;
+ r.y = 0;
+ r.width = w->width;
+ r.height = w->height;
+
+ rects = &r;
+ n = 1;
+ }
+ else
+ {
+ rects = shapeRects;
+ }
+
+ rect.rects = &rect.extents;
+ rect.numRects = rect.size = 1;
+
+ for (i = 0; i < n; i++)
+ {
+ rect.extents.x1 = rects[i].x + w->attrib.x;
+ rect.extents.y1 = rects[i].y + w->attrib.y;
+ rect.extents.x2 = rect.extents.x1 + rects[i].width;
+ rect.extents.y2 = rect.extents.y1 + rects[i].height;
+
+ XUnionRegion (&rect, w->region, w->region);
+ }
+
+ if (shapeRects)
+ XFree (shapeRects);
+}
+
+void
+addWindow (CompScreen *screen,
+ Window id,
+ Window aboveId)
+{
+ CompWindow *w;
+
+ w = (CompWindow *) malloc (sizeof (CompWindow));
+ if (!w)
+ return;
+
+ w->next = NULL;
+ w->prev = NULL;
+
+ w->screen = screen;
+ w->texture.name = 0;
+ w->pixmap = None;
+ w->destroyed = FALSE;
+
+ if (screen->windowPrivateLen)
+ {
+ w->privates = malloc (screen->windowPrivateLen * sizeof (CompPrivate));
+ if (!w->privates)
+ {
+ free (w);
+ return;
+ }
+ }
+ else
+ w->privates = 0;
+
+ w->region = XCreateRegion ();
+ if (!w->region)
+ {
+ freeWindow (w);
+ return;
+ }
+
+ w->clip = XCreateRegion ();
+ if (!w->clip)
+ {
+ freeWindow (w);
+ return;
+ }
+
+ if (!XGetWindowAttributes (screen->display->display, id, &w->attrib))
+ {
+ freeWindow (w);
+ return;
+ }
+
+ XSelectInput (screen->display->display, id, PropertyChangeMask);
+
+ w->id = id;
+ w->client = clientWindow (screen->display, id);
+ w->alpha = (w->attrib.depth == 32);
+ w->opacity = OPAQUE;
+ w->type = getWindowType (screen->display, w->client);
+
+ w->width = w->attrib.width + w->attrib.border_width * 2;
+ w->height = w->attrib.height + w->attrib.border_width * 2;
+
+ if (screen->display->shapeExtension)
+ XShapeSelectInput (screen->display->display, id, ShapeNotifyMask);
+
+ updateWindowRegion (w);
+
+ insertWindowIntoScreen (screen, w, aboveId);
+
+ if (w->attrib.class != InputOnly)
+ {
+ initTexture (screen, &w->texture);
+
+ w->damage = XDamageCreate (screen->display->display, id,
+ XDamageReportRawRectangles);
+ }
+ else
+ {
+ w->damage = None;
+ w->attrib.map_state = IsUnmapped;
+ }
+
+ if (testMode)
+ {
+ w->attrib.map_state = IsViewable;
+ bindWindow (w);
+ }
+
+ w->invisible = WINDOW_INVISIBLE (w);
+
+ if (w->type == w->screen->display->winDesktopAtom)
+ w->screen->desktopWindowCount++;
+
+ windowInitPlugins (w);
+
+ addWindowDamage (w);
+}
+
+void
+removeWindow (CompWindow *w)
+{
+ if (w->attrib.map_state == IsViewable)
+ {
+ if (w->type == w->screen->display->winDesktopAtom)
+ w->screen->desktopWindowCount++;
+ }
+
+ unhookWindowFromScreen (w->screen, w);
+ windowFiniPlugins (w);
+ freeWindow (w);
+}
+
+void
+destroyWindow (CompWindow *w)
+{
+ if (!w->destroyed)
+ {
+ w->destroyed = TRUE;
+ w->screen->pendingDestroys++;
+ }
+}
+
+void
+mapWindow (CompWindow *w)
+{
+ if (w->attrib.class == InputOnly)
+ return;
+
+ if (w->attrib.map_state == IsViewable)
+ return;
+
+ if (w->type == w->screen->display->winDesktopAtom)
+ w->screen->desktopWindowCount++;
+
+ w->attrib.map_state = IsViewable;
+ w->invisible = WINDOW_INVISIBLE (w);
+
+ addWindowDamage (w);
+}
+
+void
+unmapWindow (CompWindow *w)
+{
+ if (w->attrib.map_state != IsViewable)
+ return;
+
+ if (w->type == w->screen->display->winDesktopAtom)
+ w->screen->desktopWindowCount--;
+
+ addWindowDamage (w);
+
+ w->attrib.map_state = IsUnmapped;
+ w->invisible = WINDOW_INVISIBLE (w);
+
+ releaseWindow (w);
+}
+
+static int
+restackWindow (CompWindow *w,
+ Window aboveId)
+{
+ if (w->prev)
+ {
+ if (aboveId == w->prev->id)
+ return 0;
+ }
+ else if (aboveId == None)
+ return 0;
+
+ unhookWindowFromScreen (w->screen, w);
+ insertWindowIntoScreen (w->screen, w, aboveId);
+
+ return 1;
+}
+
+void
+configureWindow (CompWindow *w,
+ XConfigureEvent *ce)
+{
+ Bool damage;
+
+ if (w->attrib.width != ce->width ||
+ w->attrib.height != ce->height ||
+ w->attrib.border_width != ce->border_width)
+ {
+ addWindowDamage (w);
+
+ w->attrib.x = ce->x;
+ w->attrib.y = ce->y;
+ w->attrib.width = ce->width;
+ w->attrib.height = ce->height;
+ w->attrib.border_width = ce->border_width;
+
+ w->width = w->attrib.width + w->attrib.border_width * 2;
+ w->height = w->attrib.height + w->attrib.border_width * 2;
+
+ releaseWindow (w);
+
+ EMPTY_REGION (w->region);
+
+ damage = TRUE;
+ }
+ else if (w->attrib.x != ce->x || w->attrib.y != ce->y)
+ {
+ addWindowDamage (w);
+
+ XOffsetRegion (w->region, ce->x - w->attrib.x, ce->y - w->attrib.y);
+
+ w->attrib.x = ce->x;
+ w->attrib.y = ce->y;
+
+ damage = TRUE;
+ }
+ else
+ damage = FALSE;
+
+ w->attrib.override_redirect = ce->override_redirect;
+
+ w->invisible = WINDOW_INVISIBLE (w);
+
+ if (restackWindow (w, ce->above) || damage)
+ {
+ if (!REGION_NOT_EMPTY (w->region))
+ updateWindowRegion (w);
+
+ addWindowDamage (w);
+ }
+}
+
+void
+circulateWindow (CompWindow *w,
+ XCirculateEvent *ce)
+{
+ Window newAboveId;
+
+ if (ce->place == PlaceOnTop && w->screen->windows)
+ newAboveId = w->screen->windows->id;
+ else
+ newAboveId = 0;
+
+ if (restackWindow (w, newAboveId))
+ addWindowDamage (w);
+}
+
+void
+invisibleWindowMove (CompWindow *w,
+ int dx,
+ int dy)
+{
+ w->attrib.x += dx;
+ w->attrib.y += dy;
+
+ XOffsetRegion (w->region, dx, dy);
+}