summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Reveman <c99drn@cs.umu.se>2006-02-09 06:03:09 +0000
committerDavid Reveman <c99drn@cs.umu.se>2006-02-09 06:03:09 +0000
commit9959c2b13ded64a5e66359a8097250dc9d87fc1c (patch)
tree23478d196cd4acb4a9d2949c0438e9df75c2e8d6 /src
Initial revision
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am22
-rw-r--r--src/action.c41
-rw-r--r--src/display.c1844
-rw-r--r--src/event.c1005
-rw-r--r--src/main.c211
-rw-r--r--src/option.c292
-rw-r--r--src/paint.c864
-rw-r--r--src/plugin.c404
-rw-r--r--src/privates.c68
-rw-r--r--src/readpng.c266
-rw-r--r--src/screen.c2521
-rw-r--r--src/texture.c337
-rw-r--r--src/window.c2903
13 files changed, 10778 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 00000000..289e7e93
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,22 @@
+INCLUDES = \
+ @COMPIZ_CFLAGS@ \
+ -I$(top_srcdir)/include \
+ -DPLUGINDIR=\"$(plugindir)\" \
+ -DIMAGEDIR=\"$(imagedir)\"
+
+bin_PROGRAMS = compiz
+
+compiz_LDADD = @COMPIZ_LIBS@ @GL_LIBS@ -lm
+compiz_LDFLAGS = -export-dynamic
+compiz_SOURCES = \
+ main.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/action.c b/src/action.c
new file mode 100644
index 00000000..ebcd37e7
--- /dev/null
+++ b/src/action.c
@@ -0,0 +1,41 @@
+/*
+ * 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 <compiz.h>
+
+typedef struct _CompAction {
+ char *name;
+ char *description;
+ CompOptionType type;
+ union {
+ Bool b;
+ int i;
+ float f;
+ } value;
+} CompAction;
diff --git a/src/display.c b/src/display.c
new file mode 100644
index 00000000..57e090cc
--- /dev/null
+++ b/src/display.c
@@ -0,0 +1,1844 @@
+/*
+ * 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>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "../config.h"
+#endif
+
+#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/Xatom.h>
+#include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/Xrandr.h>
+/* #include <X11/extensions/Xevie.h> */
+#include <X11/extensions/shape.h>
+
+#include <compiz.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 CLICK_TO_FOCUS_DEFAULT TRUE
+
+#define AUTORAISE_DEFAULT TRUE
+
+#define AUTORAISE_DELAY_DEFAULT 1000
+#define AUTORAISE_DELAY_MIN 0
+#define AUTORAISE_DELAY_MAX 10000
+
+#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;
+
+ o = &display->opt[COMP_DISPLAY_OPTION_CLICK_TO_FOCUS];
+ o->name = "click_to_focus";
+ o->shortDesc = "Click To Focus";
+ o->longDesc = "Click on window moves input focus to it";
+ o->type = CompOptionTypeBool;
+ o->value.b = CLICK_TO_FOCUS_DEFAULT;
+
+ o = &display->opt[COMP_DISPLAY_OPTION_AUTORAISE];
+ o->name = "autoraise";
+ o->shortDesc = "Auto-Raise";
+ o->longDesc = "Raise selected windows after interval";
+ o->type = CompOptionTypeBool;
+ o->value.b = AUTORAISE_DEFAULT;
+
+ o = &display->opt[COMP_DISPLAY_OPTION_AUTORAISE_DELAY];
+ o->name = "autoraise_delay";
+ o->shortDesc = "Auto-Raise Delay";
+ o->longDesc = "Interval before raising selected windows";
+ o->type = CompOptionTypeInt;
+ o->value.i = AUTORAISE_DELAY_DEFAULT;
+ o->rest.i.min = AUTORAISE_DELAY_MIN;
+ o->rest.i.max = AUTORAISE_DELAY_MAX;
+}
+
+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;
+ }
+ break;
+ case COMP_DISPLAY_OPTION_CLICK_TO_FOCUS:
+ if (compSetBoolOption (o, value))
+ return TRUE;
+ break;
+ case COMP_DISPLAY_OPTION_AUTORAISE:
+ if (compSetBoolOption (o, value))
+ return TRUE;
+ break;
+ case COMP_DISPLAY_OPTION_AUTORAISE_DELAY:
+ if (compSetIntOption (o, value))
+ 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,
+ Bool idle)
+{
+ struct timeval tv;
+ int diff, next;
+ static int timeMult = 1;
+
+ gettimeofday (&tv, 0);
+
+ diff = TIMEVALDIFF (&tv, lastTv);
+
+ if (idle)
+ {
+ if (timeMult > 1)
+ {
+ s->frameStatus = -1;
+ s->redrawTime = s->optimalRedrawTime;
+ timeMult--;
+ }
+ }
+ else
+ {
+ if (diff > s->redrawTime)
+ {
+ if (s->frameStatus > 0)
+ s->frameStatus = 0;
+
+ next = s->optimalRedrawTime * (timeMult + 1);
+ if (diff > next)
+ {
+ s->frameStatus--;
+ if (s->frameStatus < -1)
+ {
+ timeMult++;
+ s->redrawTime = diff = next;
+ }
+ }
+ }
+ else if (diff < s->redrawTime)
+ {
+ if (s->frameStatus < 0)
+ s->frameStatus = 0;
+
+ if (timeMult > 1)
+ {
+ next = s->optimalRedrawTime * (timeMult - 1);
+ if (diff < next)
+ {
+ s->frameStatus++;
+ if (s->frameStatus > 4)
+ {
+ timeMult--;
+ s->redrawTime = next;
+ }
+ }
+ }
+ }
+ }
+
+ 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 modMask[CompModNum];
+ int i, minKeycode, maxKeycode, keysymsPerKeycode = 0;
+
+ for (i = 0; i < CompModNum; i++)
+ modMask[i] = 0;
+
+ XDisplayKeycodes (d->display, &minKeycode, &maxKeycode);
+ XGetKeyboardMapping (d->display, minKeycode, (maxKeycode - minKeycode + 1),
+ &keysymsPerKeycode);
+
+ modmap = XGetModifierMapping (d->display);
+ if (modmap && modmap->max_keypermod > 0)
+ {
+ static int maskTable[] = {
+ ShiftMask, LockMask, ControlMask, Mod1Mask,
+ Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
+ };
+ KeySym keysym;
+ int index, size, mask;
+
+ size = (sizeof (maskTable) / sizeof (int)) * modmap->max_keypermod;
+
+ for (i = 0; i < size; i++)
+ {
+ if (!modmap->modifiermap[i])
+ continue;
+
+ index = 0;
+ do
+ {
+ keysym = XKeycodeToKeysym (d->display,
+ modmap->modifiermap[i],
+ index++);
+ } while (!keysym && index < keysymsPerKeycode);
+
+ 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));
+
+ d->ignoredModMask = LockMask |
+ (modMask[CompModNumLock] & ~CompNoMask) |
+ (modMask[CompModScrollLock] & ~CompNoMask);
+
+ 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;
+ int moveX = 0, moveY = 0;
+ CompTimeout *t;
+ Bool idle = TRUE;
+
+ 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 coordinates */
+ 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)
+ {
+ moveX = move->attrib.x;
+ moveY = move->attrib.y;
+ XRaiseWindow (display->display, move->id);
+ continue;
+ }
+ }
+ /* fall-through */
+ 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)
+ {
+ moveX += event.xbutton.x - px;
+ moveY += event.xbutton.y - py;
+ px = event.xbutton.x;
+ py = event.xbutton.y;
+
+ XMoveWindow (display->display, move->id, moveX, moveY);
+
+ 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;
+ }
+
+ sn_display_process_event (display->snDisplay, &event);
+
+ (*display->handleEvent) (display, &event);
+ }
+
+ if (s->damageMask)
+ {
+ /* sync with server */
+ glFinish ();
+
+ timeToNextRedraw = getTimeToNextRedraw (s, &s->lastRedraw, idle);
+ if (timeToNextRedraw)
+ timeToNextRedraw = poll (&ufd, 1, timeToNextRedraw);
+
+ if (timeToNextRedraw == 0)
+ {
+ gettimeofday (&tv, 0);
+
+ timeDiff = TIMEVALDIFF (&tv, &s->lastRedraw);
+
+ s->stencilRef = 0;
+
+ (*s->preparePaintScreen) (s, idle ? s->redrawTime : timeDiff);
+
+ if (s->damageMask & COMP_SCREEN_DAMAGE_REGION_MASK)
+ {
+ XIntersectRegion (s->damage, &s->region, tmpRegion);
+
+ if (tmpRegion->numRects == 1 &&
+ tmpRegion->rects->x1 == 0 &&
+ tmpRegion->rects->y1 == 0 &&
+ tmpRegion->rects->x2 == s->width &&
+ tmpRegion->rects->y2 == s->height)
+ damageScreen (s);
+ }
+
+ EMPTY_REGION (s->damage);
+
+ if (s->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
+ {
+ s->damageMask = 0;
+
+ (*s->paintScreen) (s,
+ &defaultScreenPaintAttrib,
+ &s->region,
+ PAINT_SCREEN_REGION_MASK |
+ PAINT_SCREEN_FULL_MASK);
+
+ glXSwapBuffers (s->display->display, s->root);
+ }
+ else if (s->damageMask & COMP_SCREEN_DAMAGE_REGION_MASK)
+ {
+ s->damageMask = 0;
+
+ if ((*s->paintScreen) (s,
+ &defaultScreenPaintAttrib,
+ tmpRegion,
+ PAINT_SCREEN_REGION_MASK))
+ {
+ BoxPtr pBox;
+ int nBox, y;
+
+ /*
+ pBox = tmpRegion->rects;
+ nBox = tmpRegion->numRects;
+ while (nBox--)
+ {
+ y = s->height - pBox->y2;
+
+ glXCopySubBufferMESA (s->display->display,
+ s->root,
+ pBox->x1, y,
+ pBox->x2 - pBox->x1,
+ pBox->y2 - pBox->y1);
+
+ pBox++;
+ }
+
+ */ /* ugly empty rect flush hack */ /*
+ glXCopySubBufferMESA (s->display->display, s->root,
+ 0, 0, 0, 0);
+ */
+
+ 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,
+ &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--;
+ }
+ }
+
+ idle = FALSE;
+ }
+ 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);
+ }
+ }
+
+ lastTimeout = tv;
+ }
+ else
+ {
+ poll (&ufd, 1, 1000);
+ }
+
+ idle = TRUE;
+ }
+ }
+}
+
+static int errors = 0;
+
+static int
+errorHandler (Display *dpy,
+ XErrorEvent *e)
+{
+
+#ifdef DEBUG
+ char str[128];
+ char *name = 0;
+ int o;
+#endif
+
+ errors++;
+
+#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 (Display *dpy)
+{
+ int e;
+
+ XSync (dpy, FALSE);
+
+ e = errors;
+ errors = 0;
+
+ return e;
+}
+
+#define PING_DELAY 5000
+
+static Bool
+pingTimeout (void *closure)
+{
+ CompDisplay *d = closure;
+ CompScreen *s;
+ CompWindow *w;
+ XEvent ev;
+ int ping = d->lastPing + 1;
+
+ ev.type = ClientMessage;
+ ev.xclient.window = 0;
+ ev.xclient.message_type = d->wmProtocolsAtom;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = d->wmPingAtom;
+ ev.xclient.data.l[1] = ping;
+ ev.xclient.data.l[2] = 0;
+ ev.xclient.data.l[3] = 0;
+ ev.xclient.data.l[4] = 0;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ for (w = s->windows; w; w = w->next)
+ {
+ if (w->attrib.map_state != IsViewable)
+ continue;
+
+ if (!(w->type & CompWindowTypeNormalMask))
+ continue;
+
+ if (w->protocols & CompWindowProtocolPingMask)
+ {
+ if (w->transientFor)
+ continue;
+
+ if (w->lastPong < d->lastPing)
+ {
+ if (w->alive)
+ {
+ w->alive = FALSE;
+ w->paint.saturation = 0;
+
+ addWindowDamage (w);
+ }
+ }
+
+ ev.xclient.window = w->id;
+ ev.xclient.data.l[2] = w->id;
+
+ XSendEvent (d->display, w->id, FALSE, NoEventMask, &ev);
+ }
+ }
+ }
+
+ d->lastPing = ping;
+
+ return TRUE;
+}
+
+Bool
+addDisplay (char *name,
+ char **plugin,
+ int nPlugin)
+{
+ CompDisplay *d;
+ Display *dpy;
+ Window focus;
+ int revertTo, 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->ignoredModMask = LockMask;
+
+ d->plugin.list.type = CompOptionTypeString;
+ d->plugin.list.nValue = 0;
+ d->plugin.list.value = 0;
+
+ compDisplayInitOptions (d, plugin, nPlugin);
+
+ d->textureFilter = GL_LINEAR;
+ d->below = None;
+
+ d->activeWindow = 0;
+
+ d->autoRaiseHandle = 0;
+ d->autoRaiseWindow = None;
+
+ d->display = dpy = XOpenDisplay (name);
+ if (!d->display)
+ {
+ fprintf (stderr, "%s: Couldn't open display %s\n",
+ programName, XDisplayName (name));
+ return FALSE;
+ }
+
+ snprintf (d->displayString, 255, "DISPLAY=%s", DisplayString (dpy));
+
+#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->supportedAtom = XInternAtom (dpy, "_NET_SUPPORTED", 0);
+ d->supportingWmCheckAtom = XInternAtom (dpy, "_NET_SUPPORTING_WM_CHECK", 0);
+
+ d->utf8StringAtom = XInternAtom (dpy, "UTF8_STRING", 0);
+
+ d->wmNameAtom = XInternAtom (dpy, "_NET_WM_NAME", 0);
+
+ d->winTypeAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", 0);
+ d->winTypeDesktopAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP",
+ 0);
+ d->winTypeDockAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", 0);
+ d->winTypeToolbarAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR",
+ 0);
+ d->winTypeMenuAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", 0);
+ d->winTypeUtilAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY",
+ 0);
+ d->winTypeSplashAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", 0);
+ d->winTypeDialogAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", 0);
+ d->winTypeNormalAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", 0);
+
+ d->winOpacityAtom = XInternAtom (dpy, "_NET_WM_WINDOW_OPACITY", 0);
+ d->winBrightnessAtom = XInternAtom (dpy, "_NET_WM_WINDOW_BRIGHTNESS", 0);
+ d->winSaturationAtom = XInternAtom (dpy, "_NET_WM_WINDOW_SATURATION", 0);
+
+ d->winActiveAtom = XInternAtom (dpy, "_NET_ACTIVE_WINDOW", 0);
+
+ d->workareaAtom = XInternAtom (dpy, "_NET_WORKAREA", 0);
+
+ d->desktopViewportAtom = XInternAtom (dpy, "_NET_DESKTOP_VIEWPORT", 0);
+ d->desktopGeometryAtom = XInternAtom (dpy, "_NET_DESKTOP_GEOMETRY", 0);
+ d->currentDesktopAtom = XInternAtom (dpy, "_NET_CURRENT_DESKTOP", 0);
+ d->numberOfDesktopsAtom = XInternAtom (dpy, "_NET_NUMBER_OF_DESKTOPS", 0);
+
+ d->winStateAtom = XInternAtom (dpy, "_NET_WM_STATE", 0);
+ d->winStateModalAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_MODAL", 0);
+ d->winStateStickyAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_STICKY", 0);
+ d->winStateMaximizedVertAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_MAXIMIZED_VERT", 0);
+ d->winStateMaximizedHorzAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", 0);
+ d->winStateShadedAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_SHADED", 0);
+ d->winStateSkipTaskbarAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_SKIP_TASKBAR", 0);
+ d->winStateSkipPagerAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_SKIP_PAGER", 0);
+ d->winStateHiddenAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_HIDDEN", 0);
+ d->winStateFullscreenAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_FULLSCREEN", 0);
+ d->winStateAboveAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_ABOVE", 0);
+ d->winStateBelowAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_BELOW", 0);
+ d->winStateDemandsAttentionAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_DEMANDS_ATTENTION", 0);
+ d->winStateDisplayModalAtom =
+ XInternAtom (dpy, "_NET_WM_STATE_DISPLAY_MODAL", 0);
+
+ d->winActionMoveAtom = XInternAtom (dpy, "_NET_WM_ACTION_MOVE", 0);
+ d->winActionResizeAtom = XInternAtom (dpy, "_NET_WM_ACTION_RESIZE", 0);
+ d->winActionStickAtom = XInternAtom (dpy, "_NET_WM_ACTION_STICK", 0);
+ d->winActionMinimizeAtom =
+ XInternAtom (dpy, "_NET_WM_ACTION_MINIMIZE", 0);
+ d->winActionMaximizeHorzAtom =
+ XInternAtom (dpy, "_NET_WM_ACTION_MAXIMIZE_HORZ", 0);
+ d->winActionMaximizeVertAtom =
+ XInternAtom (dpy, "_NET_WM_ACTION_MAXIMIZE_VERT", 0);
+ d->winActionFullscreenAtom =
+ XInternAtom (dpy, "_NET_WM_ACTION_FULLSCREEN", 0);
+ d->winActionCloseAtom = XInternAtom (dpy, "_NET_WM_ACTION_CLOSE", 0);
+
+ d->wmAllowedActionsAtom = XInternAtom (dpy, "_NET_WM_ALLOWED_ACTIONS", 0);
+
+ d->wmStrutAtom = XInternAtom (dpy, "_NET_WM_STRUT", 0);
+ d->wmStrutPartialAtom = XInternAtom (dpy, "_NET_WM_STRUT_PARTIAL", 0);
+
+ d->clientListAtom = XInternAtom (dpy, "_NET_CLIENT_LIST", 0);
+ d->clientListStackingAtom =
+ XInternAtom (dpy, "_NET_CLIENT_LIST_STACKING", 0);
+
+ d->frameExtentsAtom = XInternAtom (dpy, "_NET_FRAME_EXTENTS", 0);
+ d->frameWindowAtom = XInternAtom (dpy, "_NET_FRAME_WINDOW", 0);
+
+ d->wmStateAtom = XInternAtom (dpy, "WM_STATE", 0);
+ d->wmChangeStateAtom = XInternAtom (dpy, "WM_CHANGE_STATE", 0);
+ d->wmProtocolsAtom = XInternAtom (dpy, "WM_PROTOCOLS", 0);
+ d->wmClientLeaderAtom = XInternAtom (dpy, "WM_CLIENT_LEADER", 0);
+
+ d->wmDeleteWindowAtom = XInternAtom (dpy, "WM_DELETE_WINDOW", 0);
+ d->wmTakeFocusAtom = XInternAtom (dpy, "WM_TAKE_FOCUS", 0);
+ d->wmPingAtom = XInternAtom (dpy, "_NET_WM_PING", 0);
+ d->wmSyncRequestAtom = XInternAtom (dpy, "_NET_WM_SYNC_REQUEST", 0);
+
+ d->wmSyncRequestCounterAtom =
+ XInternAtom (dpy, "_NET_WM_SYNC_REQUEST_COUNTER", 0);
+
+ d->closeWindowAtom = XInternAtom (dpy, "_NET_CLOSE_WINDOW", 0);
+ d->wmMoveResizeAtom = XInternAtom (dpy, "_NET_WM_MOVERESIZE", 0);
+ d->moveResizeWindowAtom = XInternAtom (dpy, "_NET_MOVERESIZE_WINDOW", 0);
+
+ d->showingDesktopAtom = XInternAtom (dpy, "_NET_SHOWING_DESKTOP", 0);
+
+ d->xBackgroundAtom[0] = XInternAtom (dpy, "_XSETROOT_ID", 0);
+ d->xBackgroundAtom[1] = XInternAtom (dpy, "_XROOTPMAP_ID", 0);
+
+ d->panelActionAtom = XInternAtom (dpy, "_GNOME_PANEL_ACTION", 0);
+ d->panelActionMainMenuAtom =
+ XInternAtom (dpy, "_GNOME_PANEL_ACTION_MAIN_MENU", 0);
+ d->panelActionRunDialogAtom =
+ XInternAtom (dpy, "_GNOME_PANEL_ACTION_RUN_DIALOG", 0);
+
+ d->mwmHintsAtom = XInternAtom (dpy, "_MOTIF_WM_HINTS", 0);
+
+ d->managerAtom = XInternAtom (dpy, "MANAGER", 0);
+ d->targetsAtom = XInternAtom (dpy, "TARGETS", 0);
+ d->multipleAtom = XInternAtom (dpy, "MULTIPLE", 0);
+ d->timestampAtom = XInternAtom (dpy, "TIMESTAMP", 0);
+ d->versionAtom = XInternAtom (dpy, "VERSION", 0);
+ d->atomPairAtom = XInternAtom (dpy, "ATOM_PAIR", 0);
+
+ d->snDisplay = sn_display_new (dpy, NULL, NULL);
+ if (!d->snDisplay)
+ return FALSE;
+
+ d->lastPing = 1;
+
+ 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;
+ }
+
+ if (!XRRQueryExtension (dpy, &d->randrEvent, &d->randrError))
+ {
+ fprintf (stderr, "%s: No RandR extension\n", programName);
+ return FALSE;
+ }
+
+ if (!XSyncQueryExtension (dpy, &d->syncEvent, &d->syncError))
+ {
+ fprintf (stderr, "%s: No sync extension\n", programName);
+ return FALSE;
+ }
+ }
+
+ d->shapeExtension = XShapeQueryExtension (dpy,
+ &d->shapeEvent,
+ &d->shapeError);
+
+ compDisplays = d;
+
+ if (testMode)
+ {
+ addScreen (d, 0, None, 0, 0);
+ }
+ else
+ {
+ for (i = 0; i < ScreenCount (dpy); i++)
+ {
+ Window newWmSnOwner = None;
+ Atom wmSnAtom = 0;
+ Time wmSnTimestamp = 0;
+ XEvent event;
+ XSetWindowAttributes attr;
+ Window currentWmSnOwner;
+ char buf[128];
+
+ sprintf (buf, "WM_S%d", i);
+ wmSnAtom = XInternAtom (dpy, buf, 0);
+
+ currentWmSnOwner = XGetSelectionOwner (dpy, wmSnAtom);
+
+ if (currentWmSnOwner != None)
+ {
+ if (!replaceCurrentWm)
+ {
+ fprintf (stderr,
+ "%s: Screen %d on display \"%s\" already "
+ "has a window manager; try using the "
+ "--replace option to replace the current "
+ "window manager.\n",
+ programName, i, DisplayString (dpy));
+
+ continue;
+ }
+
+ XSelectInput (dpy, currentWmSnOwner,
+ StructureNotifyMask);
+ }
+
+ attr.override_redirect = TRUE;
+ attr.event_mask = PropertyChangeMask;
+
+ newWmSnOwner =
+ XCreateWindow (dpy, XRootWindow (dpy, i),
+ -100, -100, 1, 1, 0,
+ CopyFromParent, CopyFromParent,
+ CopyFromParent,
+ CWOverrideRedirect | CWEventMask,
+ &attr);
+
+ XChangeProperty (dpy,
+ newWmSnOwner,
+ d->wmNameAtom,
+ d->utf8StringAtom, 8,
+ PropModeReplace,
+ (unsigned char *) PACKAGE,
+ strlen (PACKAGE));
+
+ XWindowEvent (dpy,
+ newWmSnOwner,
+ PropertyChangeMask,
+ &event);
+
+ wmSnTimestamp = event.xproperty.time;
+
+ XSetSelectionOwner (dpy, wmSnAtom, newWmSnOwner,
+ wmSnTimestamp);
+
+ if (XGetSelectionOwner (dpy, wmSnAtom) != newWmSnOwner)
+ {
+ fprintf (stderr,
+ "%s: Could not acquire window manager "
+ "selection on screen %d display \"%s\"\n",
+ programName, i, DisplayString (dpy));
+
+ XDestroyWindow (dpy, newWmSnOwner);
+
+ continue;
+ }
+
+ /* Send client message indicating that we are now the WM */
+ event.xclient.type = ClientMessage;
+ event.xclient.window = XRootWindow (dpy, i);
+ event.xclient.message_type = d->managerAtom;
+ event.xclient.format = 32;
+ event.xclient.data.l[0] = wmSnTimestamp;
+ event.xclient.data.l[1] = wmSnAtom;
+ event.xclient.data.l[2] = 0;
+ event.xclient.data.l[3] = 0;
+ event.xclient.data.l[4] = 0;
+
+ XSendEvent (dpy, XRootWindow (dpy, i), FALSE,
+ StructureNotifyMask, &event);
+
+ /* Wait for old window manager to go away */
+ if (currentWmSnOwner != None)
+ {
+ do {
+ XWindowEvent (dpy, currentWmSnOwner,
+ StructureNotifyMask, &event);
+ } while (event.type != DestroyNotify);
+ }
+
+ compCheckForError (dpy);
+
+ XCompositeRedirectSubwindows (dpy, XRootWindow (dpy, i),
+ CompositeRedirectManual);
+
+ if (compCheckForError (dpy))
+ {
+ fprintf (stderr, "%s: Another composite manager is already "
+ "running on screen: %d\n", programName, i);
+
+ continue;
+ }
+
+ XSelectInput (dpy, XRootWindow (dpy, i),
+ SubstructureRedirectMask |
+ SubstructureNotifyMask |
+ StructureNotifyMask |
+ PropertyChangeMask |
+ LeaveWindowMask |
+ EnterWindowMask |
+ KeyPressMask |
+ KeyReleaseMask |
+ FocusChangeMask |
+ ExposureMask);
+
+ if (compCheckForError (dpy))
+ {
+ fprintf (stderr, "%s: Another window manager is "
+ "already running on screen: %d\n",
+ programName, i);
+
+ continue;
+ }
+
+ if (!addScreen (d, i, newWmSnOwner, wmSnAtom, wmSnTimestamp))
+ {
+ fprintf (stderr, "%s: Failed to manage screen: %d\n",
+ programName, i);
+ }
+ }
+ }
+
+ if (!d->screens)
+ {
+ fprintf (stderr, "%s: No managable screens found on display %s\n",
+ programName, XDisplayName (name));
+ return FALSE;
+ }
+
+ XGetInputFocus (dpy, &focus, &revertTo);
+
+ if (focus == None || focus == PointerRoot)
+ {
+ focusDefaultWindow (d);
+ }
+ else
+ {
+ CompWindow *w;
+
+ w = findWindowAtDisplay (d, focus);
+ if (w)
+ {
+ moveInputFocusToWindow (w);
+ }
+ else
+ focusDefaultWindow (d);
+ }
+
+ d->pingHandle = compAddTimeout (PING_DELAY, pingTimeout, d);
+
+ return TRUE;
+}
+
+void
+focusDefaultWindow (CompDisplay *d)
+{
+ CompScreen *s;
+ CompWindow *w;
+ CompWindow *focus = NULL;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ for (w = s->reverseWindows; w; w = w->prev)
+ {
+ if (w->type & CompWindowTypeDockMask)
+ continue;
+
+ if ((*s->focusWindow) (w))
+ {
+ if (focus)
+ {
+ if (w->type & (CompWindowTypeNormalMask |
+ CompWindowTypeDialogMask |
+ CompWindowTypeModalDialogMask))
+ {
+ if (w->activeNum > focus->activeNum)
+ focus = w;
+ }
+ }
+ else
+ focus = w;
+ }
+ }
+ }
+
+ if (focus)
+ {
+ if (focus->id != d->activeWindow)
+ moveInputFocusToWindow (focus);
+ }
+ else
+ {
+ XSetInputFocus (d->display, d->screens->root, RevertToPointerRoot,
+ CurrentTime);
+ }
+}
+
+CompScreen *
+findScreenAtDisplay (CompDisplay *d,
+ Window root)
+{
+ CompScreen *s;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ if (s->root == root)
+ return s;
+ }
+
+ return 0;
+}
+
+void
+forEachWindowOnDisplay (CompDisplay *display,
+ ForEachWindowProc proc,
+ void *closure)
+{
+ CompScreen *s;
+
+ for (s = display->screens; s; s = s->next)
+ forEachWindowOnScreen (s, proc, closure);
+}
+
+CompWindow *
+findWindowAtDisplay (CompDisplay *d,
+ Window id)
+{
+ if (lastFoundWindow && lastFoundWindow->id == id)
+ {
+ return lastFoundWindow;
+ }
+ else
+ {
+ CompScreen *s;
+ CompWindow *w;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ w = findWindowAtScreen (s, id);
+ if (w)
+ return w;
+ }
+ }
+
+ return 0;
+}
+
+static CompScreen *
+findScreenForSelection (CompDisplay *display,
+ Window owner,
+ Atom selection)
+{
+ CompScreen *s;
+
+ for (s = display->screens; s; s = s->next)
+ {
+ if (s->wmSnSelectionWindow == owner && s->wmSnAtom == selection)
+ return s;
+ }
+
+ return NULL;
+}
+
+/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
+static Bool
+convertProperty (CompDisplay *display,
+ CompScreen *screen,
+ Window w,
+ Atom target,
+ Atom property)
+{
+
+#define N_TARGETS 4
+
+ Atom conversionTargets[N_TARGETS];
+ long icccmVersion[] = { 2, 0 };
+
+ conversionTargets[0] = display->targetsAtom;
+ conversionTargets[1] = display->multipleAtom;
+ conversionTargets[2] = display->timestampAtom;
+ conversionTargets[3] = display->versionAtom;
+
+ if (target == display->targetsAtom)
+ XChangeProperty (display->display, w, property,
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *) conversionTargets, N_TARGETS);
+ else if (target == display->timestampAtom)
+ XChangeProperty (display->display, w, property,
+ XA_INTEGER, 32, PropModeReplace,
+ (unsigned char *) &screen->wmSnTimestamp, 1);
+ else if (target == display->versionAtom)
+ XChangeProperty (display->display, w, property,
+ XA_INTEGER, 32, PropModeReplace,
+ (unsigned char *) icccmVersion, 2);
+ else
+ return FALSE;
+
+ /* Be sure the PropertyNotify has arrived so we
+ * can send SelectionNotify
+ */
+ XSync (display->display, FALSE);
+
+ return TRUE;
+}
+
+/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
+void
+handleSelectionRequest (CompDisplay *display,
+ XEvent *event)
+{
+ XSelectionEvent reply;
+ CompScreen *screen;
+
+ screen = findScreenForSelection (display,
+ event->xselectionrequest.owner,
+ event->xselectionrequest.selection);
+ if (!screen)
+ return;
+
+ reply.type = SelectionNotify;
+ reply.display = display->display;
+ reply.requestor = event->xselectionrequest.requestor;
+ reply.selection = event->xselectionrequest.selection;
+ reply.target = event->xselectionrequest.target;
+ reply.property = None;
+ reply.time = event->xselectionrequest.time;
+
+ if (event->xselectionrequest.target == display->multipleAtom)
+ {
+ if (event->xselectionrequest.property != None)
+ {
+ Atom type, *adata;
+ int i, format;
+ unsigned long num, rest;
+ unsigned char *data;
+
+ if (XGetWindowProperty (display->display,
+ event->xselectionrequest.requestor,
+ event->xselectionrequest.property,
+ 0, 256, FALSE,
+ display->atomPairAtom,
+ &type, &format, &num, &rest,
+ &data) != Success)
+ return;
+
+ /* FIXME: to be 100% correct, should deal with rest > 0,
+ * but since we have 4 possible targets, we will hardly ever
+ * meet multiple requests with a length > 8
+ */
+ adata = (Atom *) data;
+ i = 0;
+ while (i < (int) num)
+ {
+ if (!convertProperty (display, screen,
+ event->xselectionrequest.requestor,
+ adata[i], adata[i + 1]))
+ adata[i + 1] = None;
+
+ i += 2;
+ }
+
+ XChangeProperty (display->display,
+ event->xselectionrequest.requestor,
+ event->xselectionrequest.property,
+ display->atomPairAtom,
+ 32, PropModeReplace, data, num);
+ }
+ }
+ else
+ {
+ if (event->xselectionrequest.property == None)
+ event->xselectionrequest.property = event->xselectionrequest.target;
+
+ if (convertProperty (display, screen,
+ event->xselectionrequest.requestor,
+ event->xselectionrequest.target,
+ event->xselectionrequest.property))
+ reply.property = event->xselectionrequest.property;
+ }
+
+ XSendEvent (display->display,
+ event->xselectionrequest.requestor,
+ FALSE, 0L, (XEvent *) &reply);
+}
+
+void
+handleSelectionClear (CompDisplay *display,
+ XEvent *event)
+{
+ /* We need to unmanage the screen on which we lost the selection */
+ CompScreen *screen;
+
+ screen = findScreenForSelection (display,
+ event->xselectionclear.window,
+ event->xselectionclear.selection);
+
+ if (!screen)
+ return;
+
+ /* removeScreen (screen); */
+
+ exit (0);
+}
diff --git a/src/event.c b/src/event.c
new file mode 100644
index 00000000..f97f5581
--- /dev/null
+++ b/src/event.c
@@ -0,0 +1,1005 @@
+/*
+ * 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 <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/extensions/Xevie.h>
+
+#include <compiz.h>
+
+static void
+handleWindowDamageRect (CompWindow *w,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ REGION region;
+ Bool initial = FALSE;
+
+ if (!w->damaged)
+ {
+ w->damaged = initial = TRUE;
+ w->invisible = WINDOW_INVISIBLE (w);
+ }
+
+ region.extents.x1 = x;
+ region.extents.y1 = y;
+ region.extents.x2 = region.extents.x1 + width;
+ region.extents.y2 = region.extents.y1 + height;
+
+ if (!(*w->screen->damageWindowRect) (w, initial, &region.extents))
+ {
+ region.extents.x1 += w->attrib.x + w->attrib.border_width;
+ region.extents.y1 += w->attrib.y + w->attrib.border_width;
+ region.extents.x2 += w->attrib.x + w->attrib.border_width;
+ region.extents.y2 += w->attrib.y + w->attrib.border_width;
+
+ region.rects = &region.extents;
+ region.numRects = region.size = 1;
+
+ damageWindowRegion (w, &region);
+
+ if (initial)
+ damageWindowOutputExtents (w);
+ }
+}
+
+void
+handleSyncAlarm (CompWindow *w)
+{
+ if (w->syncWait)
+ {
+ if (w->syncWaitHandle)
+ {
+ compRemoveTimeout (w->syncWaitHandle);
+ w->syncWaitHandle = 0;
+ }
+
+ if (resizeWindow (w,
+ w->syncX, w->syncY,
+ w->syncWidth, w->syncHeight,
+ w->syncBorderWidth))
+ {
+ XRectangle *rects;
+ int nDamage;
+
+ nDamage = w->nDamage;
+ rects = w->damageRects;
+ while (nDamage--)
+ {
+ handleWindowDamageRect (w,
+ rects[nDamage].x,
+ rects[nDamage].y,
+ rects[nDamage].width,
+ rects[nDamage].height);
+ }
+
+ w->nDamage = 0;
+ w->syncWait = FALSE;
+ }
+ }
+}
+
+static void
+moveInputFocusToOtherWindow (CompWindow *w)
+{
+ CompDisplay *display = w->screen->display;
+
+ if (w->id == display->activeWindow)
+ {
+ CompWindow *ancestor;
+
+ if (w->transientFor && w->transientFor != w->screen->root)
+ {
+ ancestor = findWindowAtDisplay (display, w->transientFor);
+ if (ancestor && !(ancestor->type & (CompWindowTypeDesktopMask |
+ CompWindowTypeDockMask)))
+ {
+ moveInputFocusToWindow (ancestor);
+ }
+ else
+ focusDefaultWindow (display);
+ }
+ else if (w->type & (CompWindowTypeDialogMask |
+ CompWindowTypeModalDialogMask))
+ {
+ CompWindow *a, *focus = NULL;
+
+ for (a = w->screen->reverseWindows; a; a = a->prev)
+ {
+ if (a->clientLeader == w->clientLeader)
+ {
+ if ((*w->screen->focusWindow) (a))
+ {
+ if (focus)
+ {
+ if (a->type & (CompWindowTypeNormalMask |
+ CompWindowTypeDialogMask |
+ CompWindowTypeModalDialogMask))
+ {
+ if (a->activeNum > focus->activeNum)
+ focus = a;
+ }
+ }
+ else
+ focus = a;
+ }
+ }
+ }
+
+ if (focus && !(focus->type & (CompWindowTypeDesktopMask |
+ CompWindowTypeDockMask)))
+ {
+ moveInputFocusToWindow (focus);
+ }
+ else
+ focusDefaultWindow (display);
+ }
+ else
+ focusDefaultWindow (display);
+ }
+}
+
+static Bool
+autoRaiseTimeout (void *closure)
+{
+ CompDisplay *display = closure;
+
+ if (display->autoRaiseWindow == display->activeWindow)
+ {
+ CompWindow *w;
+
+ w = findWindowAtDisplay (display, display->autoRaiseWindow);
+ if (w)
+ updateWindowAttributes (w);
+ }
+
+ return FALSE;
+}
+
+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 SelectionRequest:
+ handleSelectionRequest (display, event);
+ break;
+ case SelectionClear:
+ handleSelectionClear (display, event);
+ 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,
+ s->reverseWindows ? s->reverseWindows->id : 0);
+ }
+ break;
+ case DestroyNotify:
+ w = findWindowAtDisplay (display, event->xdestroywindow.window);
+ if (w)
+ {
+ destroyWindow (w);
+ moveInputFocusToOtherWindow (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);
+ moveInputFocusToOtherWindow (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)
+ {
+ destroyWindow (w);
+ moveInputFocusToOtherWindow (w);
+ }
+ }
+ break;
+ case CirculateNotify:
+ w = findWindowAtDisplay (display, event->xcirculate.window);
+ if (w)
+ circulateWindow (w, &event->xcirculate);
+ break;
+ case ButtonPress:
+ if (!display->screens->maxGrab)
+ XAllowEvents (display->display, ReplayPointer, event->xbutton.time);
+
+ s = findScreenAtDisplay (display, event->xbutton.root);
+ if (s)
+ {
+ if (event->xbutton.button == Button1 ||
+ event->xbutton.button == Button3)
+ {
+ w = findTopLevelWindowAtScreen (s, event->xbutton.window);
+ if (w)
+ activateWindow (w);
+ }
+
+ if (EV_BUTTON (&s->opt[COMP_SCREEN_OPTION_CLOSE_WINDOW], event))
+ closeActiveWindow (s);
+
+ if (EV_BUTTON (&s->opt[COMP_SCREEN_OPTION_MAIN_MENU], event))
+ panelAction (s, s->display->panelActionMainMenuAtom);
+
+ if (EV_BUTTON (&s->opt[COMP_SCREEN_OPTION_RUN_DIALOG], event))
+ panelAction (s, s->display->panelActionRunDialogAtom);
+
+ if (EV_BUTTON (&s->opt[COMP_SCREEN_OPTION_RUN_COMMAND0], event))
+ runCommand (s, s->opt[COMP_SCREEN_OPTION_COMMAND0].value.s);
+
+ if (EV_BUTTON (&s->opt[COMP_SCREEN_OPTION_RUN_COMMAND1], event))
+ runCommand (s, s->opt[COMP_SCREEN_OPTION_COMMAND1].value.s);
+ }
+ break;
+ case ButtonRelease:
+ break;
+ case KeyPress:
+ s = findScreenAtDisplay (display, event->xkey.root);
+ if (s)
+ {
+ if (EV_KEY (&s->opt[COMP_SCREEN_OPTION_CLOSE_WINDOW], event))
+ closeActiveWindow (s);
+
+ if (EV_KEY (&s->opt[COMP_SCREEN_OPTION_MAIN_MENU], event))
+ panelAction (s, s->display->panelActionMainMenuAtom);
+
+ if (EV_KEY (&s->opt[COMP_SCREEN_OPTION_RUN_DIALOG], event))
+ panelAction (s, s->display->panelActionRunDialogAtom);
+
+ if (EV_KEY (&s->opt[COMP_SCREEN_OPTION_RUN_COMMAND0], event))
+ runCommand (s, s->opt[COMP_SCREEN_OPTION_COMMAND0].value.s);
+
+ if (EV_KEY (&s->opt[COMP_SCREEN_OPTION_RUN_COMMAND1], event))
+ runCommand (s, s->opt[COMP_SCREEN_OPTION_COMMAND1].value.s);
+ }
+ break;
+ case KeyRelease:
+ break;
+ case PropertyNotify:
+ if (event->xproperty.atom == display->winActiveAtom)
+ {
+ Window newActiveWindow;
+
+ newActiveWindow = getActiveWindow (display, event->xproperty.window);
+ if (newActiveWindow != display->activeWindow)
+ {
+ display->activeWindow = newActiveWindow;
+
+ s = findScreenAtDisplay (display, event->xproperty.window);
+ if (s)
+ {
+ w = findWindowAtDisplay (display, newActiveWindow);
+ if (w)
+ w->activeNum = s->activeNum++;
+ }
+ }
+ }
+ else if (event->xproperty.atom == display->winTypeAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ {
+ unsigned int type;
+
+ type = getWindowType (display, w->id);
+
+ if (type != w->wmType)
+ {
+ if (w->attrib.map_state == IsViewable)
+ {
+ if (w->type == CompWindowTypeDesktopMask)
+ w->screen->desktopWindowCount--;
+ else if (type == CompWindowTypeDesktopMask)
+ w->screen->desktopWindowCount++;
+ }
+
+ w->wmType = type;
+
+ recalcWindowType (w);
+
+ if (w->type & CompWindowTypeDesktopMask)
+ w->paint.opacity = OPAQUE;
+ }
+ }
+ }
+ else if (event->xproperty.atom == display->winStateAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ {
+ unsigned int state;
+
+ state = getWindowState (display, w->id);
+
+ if (state != w->state)
+ {
+ w->state = state;
+
+ recalcWindowType (w);
+
+ if (w->type & CompWindowTypeDesktopMask)
+ w->paint.opacity = OPAQUE;
+ }
+ }
+ }
+ else if (event->xproperty.atom == XA_WM_NORMAL_HINTS)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ updateNormalHints (w);
+ }
+ else if (event->xproperty.atom == XA_WM_HINTS)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ updateWmHints (w);
+ }
+ else if (event->xproperty.atom == XA_WM_TRANSIENT_FOR)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ XGetTransientForHint (display->display,
+ w->id, &w->transientFor);
+ }
+ else if (event->xproperty.atom == display->wmClientLeaderAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ w->clientLeader = getClientLeader (w);
+ }
+ else if (event->xproperty.atom == display->winOpacityAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w && (w->type & CompWindowTypeDesktopMask) == 0)
+ {
+ GLushort opacity;
+
+ opacity = getWindowProp32 (display, w->id,
+ display->winOpacityAtom,
+ OPAQUE);
+ if (opacity != w->paint.opacity)
+ {
+ w->paint.opacity = opacity;
+ addWindowDamage (w);
+ }
+ }
+ }
+ else if (event->xproperty.atom == display->winBrightnessAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ {
+ GLushort brightness;
+
+ brightness = getWindowProp32 (display, w->id,
+ display->winBrightnessAtom,
+ BRIGHT);
+ if (brightness != w->paint.brightness)
+ {
+ w->paint.brightness = brightness;
+ addWindowDamage (w);
+ }
+ }
+ }
+ else if (event->xproperty.atom == display->winSaturationAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w && w->screen->canDoSaturated)
+ {
+ GLushort saturation;
+
+ saturation = getWindowProp32 (display, w->id,
+ display->winSaturationAtom,
+ COLOR);
+ if (saturation != w->saturation)
+ {
+ w->saturation = saturation;
+ if (w->alive)
+ {
+ w->paint.saturation = w->saturation;
+ 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);
+ }
+ }
+ else if (event->xproperty.atom == display->wmStrutAtom ||
+ event->xproperty.atom == display->wmStrutPartialAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ {
+ if (updateWindowStruts (w))
+ updateWorkareaForScreen (w->screen);
+ }
+ }
+ else if (event->xproperty.atom == display->mwmHintsAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ {
+ w->mwmDecor = getMwmDecor (w->screen->display, w->id);
+
+ updateWindowAttributes (w);
+ }
+ }
+ else if (event->xproperty.atom == display->wmProtocolsAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ w->protocols = getProtocols (w->screen->display, w->id);
+ }
+ break;
+ case MotionNotify:
+ break;
+ case ClientMessage:
+ if (event->xclient.message_type == display->winActiveAtom)
+ {
+ w = findWindowAtDisplay (display, event->xclient.window);
+ if (w)
+ activateWindow (w);
+ }
+ else if (event->xclient.message_type == display->winOpacityAtom)
+ {
+ w = findWindowAtDisplay (display, event->xclient.window);
+ if (w && (w->type & CompWindowTypeDesktopMask) == 0)
+ {
+ GLushort opacity;
+
+ opacity = event->xclient.data.l[0] >> 16;
+ if (opacity != w->paint.opacity)
+ {
+ w->paint.opacity = opacity;
+
+ setWindowProp32 (display, w->id, display->winOpacityAtom,
+ w->paint.opacity);
+ addWindowDamage (w);
+ }
+ }
+ }
+ else if (event->xclient.message_type == display->winBrightnessAtom)
+ {
+ w = findWindowAtDisplay (display, event->xclient.window);
+ if (w)
+ {
+ GLushort brightness;
+
+ brightness = event->xclient.data.l[0] >> 16;
+ if (brightness != w->paint.brightness)
+ {
+ w->paint.brightness = brightness;
+
+ setWindowProp32 (display, w->id, display->winBrightnessAtom,
+ w->paint.brightness);
+ addWindowDamage (w);
+ }
+ }
+ }
+ else if (event->xclient.message_type == display->winSaturationAtom)
+ {
+ w = findWindowAtDisplay (display, event->xclient.window);
+ if (w && w->screen->canDoSaturated)
+ {
+ GLushort saturation;
+
+ saturation = event->xclient.data.l[0] >> 16;
+ if (saturation != w->saturation)
+ {
+ w->saturation = saturation;
+
+ setWindowProp32 (display, w->id, display->winSaturationAtom,
+ w->saturation);
+
+ if (w->alive)
+ {
+ w->paint.saturation = w->saturation;
+ addWindowDamage (w);
+ }
+ }
+ }
+ }
+ else if (event->xclient.message_type == display->winStateAtom)
+ {
+ w = findWindowAtDisplay (display, event->xclient.window);
+ if (w)
+ {
+ unsigned long wState, state;
+ int i;
+
+ wState = w->state;
+
+ for (i = 1; i < 3; i++)
+ {
+ state = windowStateMask (display, event->xclient.data.l[i]);
+ if (state & ~CompWindowStateHiddenMask)
+ {
+
+#define _NET_WM_STATE_REMOVE 0
+#define _NET_WM_STATE_ADD 1
+#define _NET_WM_STATE_TOGGLE 2
+
+ switch (event->xclient.data.l[0]) {
+ case _NET_WM_STATE_REMOVE:
+ wState &= ~state;
+ break;
+ case _NET_WM_STATE_ADD:
+ wState |= state;
+ break;
+ case _NET_WM_STATE_TOGGLE:
+ wState ^= state;
+ break;
+ }
+ }
+ }
+
+ if (wState != w->state)
+ {
+ w->state = wState;
+
+ recalcWindowType (w);
+
+ if (!w->attrib.override_redirect)
+ updateWindowAttributes (w);
+
+ setWindowState (display, wState, w->id);
+ }
+ }
+ }
+ else if (event->xclient.message_type == display->wmProtocolsAtom)
+ {
+ if (event->xclient.data.l[0] == display->wmPingAtom)
+ {
+ w = findWindowAtDisplay (display, event->xclient.data.l[2]);
+ if (w)
+ {
+ if (!w->alive)
+ {
+ w->alive = TRUE;
+ w->paint.saturation = w->saturation;
+
+ addWindowDamage (w);
+ }
+ w->lastPong = display->lastPing;
+ }
+ }
+ }
+ else if (event->xclient.message_type == display->closeWindowAtom)
+ {
+ w = findWindowAtDisplay (display, event->xclient.window);
+ if (w)
+ closeWindow (w);
+ }
+ else if (event->xclient.message_type == display->desktopGeometryAtom)
+ {
+ s = findScreenAtDisplay (display, event->xclient.window);
+ if (s)
+ {
+ CompOptionValue value;
+
+ value.i = event->xclient.data.l[0] / s->width;
+
+ (*s->setScreenOption) (s, "size", &value);
+ }
+ }
+ else if (event->xclient.message_type == display->moveResizeWindowAtom)
+ {
+ unsigned int xwcm = 0;
+ XWindowChanges xwc;
+
+ if (event->xclient.data.l[0] & (1 << 7))
+ {
+ xwcm |= CWX;
+ xwc.x = event->xclient.data.l[1];
+ }
+
+ if (event->xclient.data.l[0] & (1 << 8))
+ {
+ xwcm |= CWY;
+ xwc.y = event->xclient.data.l[2];
+ }
+
+ if (event->xclient.data.l[0] & (1 << 9))
+ {
+ xwcm |= CWWidth;
+ xwc.width = event->xclient.data.l[3];
+ }
+
+ if (event->xclient.data.l[0] & (1 << 10))
+ {
+ xwcm |= CWHeight;
+ xwc.height = event->xclient.data.l[4];
+ }
+
+ /* TODO: gravity */
+
+ if (xwcm & (CWX | CWY))
+ {
+ w = findWindowAtDisplay (display, event->xclient.window);
+ if (w)
+ {
+ if (xwcm & CWX)
+ xwc.x += w->input.left;
+
+ if (xwcm & CWY)
+ xwc.y += w->input.top;
+ }
+ }
+
+ XConfigureWindow (display->display,
+ event->xclient.window,
+ xwcm, &xwc);
+ }
+ else if (event->xclient.message_type == display->wmChangeStateAtom)
+ {
+ w = findWindowAtDisplay (display, event->xclient.window);
+ if (w && w->type & CompWindowTypeNormalMask)
+ {
+ if (event->xclient.data.l[0] == IconicState)
+ minimizeWindow (w);
+ else if (event->xclient.data.l[0] == NormalState)
+ unminimizeWindow (w);
+ }
+ }
+ else if (event->xclient.message_type == display->showingDesktopAtom)
+ {
+ s = findScreenAtDisplay (display, event->xclient.window);
+ if (s)
+ {
+ if (event->xclient.data.l[0])
+ enterShowDesktopMode (s);
+ else
+ leaveShowDesktopMode (s);
+ }
+ }
+ break;
+ case MappingNotify:
+ updateModifierMappings (display);
+ break;
+ case MapRequest:
+ w = findWindowAtDisplay (display, event->xmaprequest.window);
+ if (w)
+ {
+ if (w->minimized)
+ unminimizeWindow (w);
+
+ if (w->screen->showingDesktopMask)
+ leaveShowDesktopMode (w->screen);
+
+ if (!(w->state & CompWindowStateHiddenMask))
+ {
+ XMapWindow (display->display, event->xmaprequest.window);
+
+ updateWindowAttributes (w);
+
+ if (!(w->type & (CompWindowTypeDesktopMask |
+ CompWindowTypeDockMask)))
+ moveInputFocusToWindow (w);
+ }
+ }
+ else
+ {
+ XMapWindow (display->display, event->xmaprequest.window);
+ }
+ break;
+ case ConfigureRequest: {
+ unsigned int xwcm;
+ XWindowChanges xwc;
+
+ xwcm = event->xconfigurerequest.value_mask &
+ (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
+
+ xwc.x = event->xconfigurerequest.x;
+ xwc.y = event->xconfigurerequest.y;
+ xwc.width = event->xconfigurerequest.width;
+ xwc.height = event->xconfigurerequest.height;
+ xwc.border_width = event->xconfigurerequest.border_width;
+
+ /* TODO: gravity */
+
+ if (xwcm & (CWX | CWY))
+ {
+ w = findWindowAtDisplay (display, event->xconfigurerequest.window);
+ if (w)
+ {
+ xwc.x += w->input.left;
+ xwc.y += w->input.top;
+ }
+ }
+
+ XConfigureWindow (display->display,
+ event->xconfigurerequest.window,
+ xwcm, &xwc);
+ } break;
+ case CirculateRequest:
+ break;
+ case FocusIn:
+ if (event->xfocus.window != display->activeWindow &&
+ event->xfocus.mode != NotifyGrab)
+ {
+ w = findWindowAtDisplay (display, event->xfocus.window);
+ if (w)
+ {
+ XChangeProperty (display->display, w->screen->root,
+ display->winActiveAtom,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &w->id, 1);
+ }
+ }
+ break;
+ case EnterNotify:
+ if (!display->screens->maxGrab &&
+ event->xcrossing.mode != NotifyGrab &&
+ event->xcrossing.detail != NotifyInferior)
+ {
+ Bool raise;
+ int delay;
+
+ raise = display->opt[COMP_DISPLAY_OPTION_AUTORAISE].value.b;
+ delay = display->opt[COMP_DISPLAY_OPTION_AUTORAISE_DELAY].value.i;
+
+ s = findScreenAtDisplay (display, event->xcrossing.root);
+ if (s)
+ w = findTopLevelWindowAtScreen (s, event->xcrossing.window);
+ else
+ w = NULL;
+
+ if (w && w->id != display->below)
+ {
+ display->below = w->id;
+
+ if (!display->opt[COMP_DISPLAY_OPTION_CLICK_TO_FOCUS].value.b)
+ {
+ if (display->autoRaiseHandle &&
+ display->autoRaiseWindow != w->id)
+ {
+ compRemoveTimeout (display->autoRaiseHandle);
+ display->autoRaiseHandle = 0;
+ }
+
+ if (w->type & ~(CompWindowTypeDockMask |
+ CompWindowTypeDesktopMask))
+ {
+ moveInputFocusToWindow (w);
+
+ if (raise)
+ {
+ if (delay > 0)
+ {
+ display->autoRaiseWindow = w->id;
+ display->autoRaiseHandle =
+ compAddTimeout (delay, autoRaiseTimeout,
+ display);
+ }
+ else
+ updateWindowAttributes (w);
+ }
+ }
+ }
+ }
+ }
+ break;
+ case LeaveNotify:
+ if (event->xcrossing.detail != NotifyInferior)
+ {
+ if (event->xcrossing.window == display->below)
+ display->below = None;
+ }
+ break;
+ default:
+ if (event->type == display->damageEvent + XDamageNotify)
+ {
+ XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
+
+ if (lastDamagedWindow && de->drawable == lastDamagedWindow->id)
+ {
+ w = lastDamagedWindow;
+ }
+ else
+ {
+ w = findWindowAtDisplay (display, de->drawable);
+ if (w)
+ lastDamagedWindow = w;
+ }
+
+ if (w)
+ {
+ if (w->syncWait)
+ {
+ if (w->nDamage == w->sizeDamage)
+ {
+ if (w->damageRects)
+ {
+ w->damageRects = realloc (w->damageRects,
+ (w->sizeDamage + 1) *
+ sizeof (XRectangle));
+ w->sizeDamage += 1;
+ }
+ else
+ {
+ w->damageRects = malloc (sizeof (XRectangle));
+ w->sizeDamage = 1;
+ }
+ }
+
+ w->damageRects[w->nDamage].x = de->area.x;
+ w->damageRects[w->nDamage].y = de->area.y;
+ w->damageRects[w->nDamage].width = de->area.width;
+ w->damageRects[w->nDamage].height = de->area.height;
+ w->nDamage++;
+ }
+ else
+ {
+ handleWindowDamageRect (w,
+ de->area.x,
+ de->area.y,
+ de->area.width,
+ de->area.height);
+ }
+ }
+ }
+ else if (display->shapeExtension &&
+ event->type == display->shapeEvent + ShapeNotify)
+ {
+ w = findWindowAtDisplay (display, ((XShapeEvent *) event)->window);
+ if (w)
+ {
+ if (w->mapNum)
+ {
+ addWindowDamage (w);
+ updateWindowRegion (w);
+ addWindowDamage (w);
+ }
+ }
+ }
+ else if (event->type == display->randrEvent + RRScreenChangeNotify)
+ {
+ XRRScreenChangeNotifyEvent *rre;
+
+ rre = (XRRScreenChangeNotifyEvent *) event;
+
+ s = findScreenAtDisplay (display, rre->root);
+ if (s)
+ detectRefreshRateOfScreen (s);
+ }
+ else if (event->type == display->syncEvent + XSyncAlarmNotify)
+ {
+ XSyncAlarmNotifyEvent *sa;
+
+ sa = (XSyncAlarmNotifyEvent *) event;
+
+ w = NULL;
+
+ for (s = display->screens; s; s = s->next)
+ for (w = s->windows; w; w = w->next)
+ if (w->syncAlarm == sa->alarm)
+ break;
+
+ if (w)
+ handleSyncAlarm (w);
+ }
+ break;
+ }
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 00000000..b715f42f
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,211 @@
+/*
+ * 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 <sys/wait.h>
+
+#include <compiz.h>
+
+char *programName;
+char **programArgv;
+int programArgc;
+
+char *backgroundImage = "background.png";
+char *windowImage = "window.png";
+
+REGION emptyRegion;
+REGION infiniteRegion;
+GLushort defaultColor[4] = { 0, 0, 0, 0 };
+Window currentRoot = 0;
+
+int defaultRefreshRate = 50;
+char *defaultTextureFilter = "Good";
+
+char *windowTypeString[] = {
+ "Desktop",
+ "Dock",
+ "Toolbar",
+ "Menu",
+ "Utility",
+ "Splash",
+ "Dialog",
+ "ModalDialog",
+ "Normal",
+ "Fullscreen",
+ "Unknown"
+};
+int nWindowTypeString =
+ sizeof (windowTypeString) / sizeof (windowTypeString[0]);
+
+Bool testMode = FALSE;
+Bool restartSignal = FALSE;
+
+CompWindow *lastFoundWindow = 0;
+CompWindow *lastDamagedWindow = 0;
+
+Bool replaceCurrentWm = FALSE;
+
+static void
+usage (void)
+{
+ printf ("Usage: %s "
+ "[--display DISPLAY] "
+ "[--bg-image PNG] "
+ "[--window-image PNG]\n "
+ "[--refresh-rate RATE] "
+ "[--fast-filter] "
+ "[--test-mode] "
+ "[--replace]\n "
+ "[--sm-disable] "
+ "[--sm-save-file] "
+ "[--sm-client-id] "
+ "[--help] "
+ "[PLUGIN]...\n",
+ programName);
+}
+
+static void
+signalHandler (int sig)
+{
+ int status;
+
+ switch (sig) {
+ case SIGCHLD:
+ waitpid (-1, &status, WNOHANG | WUNTRACED);
+ break;
+ case SIGHUP:
+ restartSignal = TRUE;
+ default:
+ break;
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ char *displayName = 0;
+ char *plugin[256];
+ int i, nPlugin = 0;
+ Bool disableSm = TRUE;
+ char *clientId = NULL;
+ char *saveFile = NULL;
+
+ programName = argv[0];
+ programArgc = argc;
+ programArgv = argv;
+
+ signal (SIGHUP, signalHandler);
+ signal (SIGCHLD, 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;
+
+ infiniteRegion.rects = &infiniteRegion.extents;
+ infiniteRegion.numRects = 1;
+ infiniteRegion.extents.x1 = MINSHORT;
+ infiniteRegion.extents.y1 = MINSHORT;
+ infiniteRegion.extents.x2 = MAXSHORT;
+ infiniteRegion.extents.y2 = MAXSHORT;
+
+ 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], "--replace"))
+ {
+ replaceCurrentWm = TRUE;
+ }
+ else if (!strcmp (argv[i], "--sm-disable"))
+ {
+ disableSm = TRUE;
+ }
+ else if (!strcmp (argv[i], "--sm-client-id"))
+ {
+ if (i + 1 < argc)
+ clientId = argv[++i];
+ }
+ else if (!strcmp (argv[i], "--sm-save-file"))
+ {
+ if (i + 1 < argc)
+ saveFile = argv[++i];
+ }
+ 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 00000000..23999c66
--- /dev/null
+++ b/src/option.c
@@ -0,0 +1,292 @@
+/*
+ * 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 <strings.h>
+#include <math.h>
+
+#include <compiz.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)
+{
+ char *s;
+
+ s = value->s;
+ if (!s)
+ s = "";
+
+ if (option->rest.s.nString)
+ {
+ int i;
+
+ for (i = 0; i < option->rest.s.nString; i++)
+ {
+ if (strcmp (option->rest.s.string[i], s) == 0)
+ break;
+ }
+
+ if (i == option->rest.s.nString)
+ s = option->rest.s.string[0];
+ }
+
+ if (option->value.s == s)
+ return FALSE;
+
+ if (option->value.s && s)
+ {
+ if (strcmp (option->value.s, s) == 0)
+ return FALSE;
+ }
+
+ if (option->value.s)
+ free (option->value.s);
+
+ option->value.s = strdup (s);
+
+ 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;
+}
+
+unsigned int
+compWindowTypeMaskFromStringList (CompOptionValue *value)
+{
+ int i;
+ unsigned int mask = 0;
+
+ for (i = 0; i < value->list.nValue; i++)
+ {
+ if (strcasecmp (value->list.value[i].s, "desktop") == 0)
+ mask |= CompWindowTypeDesktopMask;
+ else if (strcasecmp (value->list.value[i].s, "dock") == 0)
+ mask |= CompWindowTypeDockMask;
+ else if (strcasecmp (value->list.value[i].s, "toolbar") == 0)
+ mask |= CompWindowTypeToolbarMask;
+ else if (strcasecmp (value->list.value[i].s, "menu") == 0)
+ mask |= CompWindowTypeMenuMask;
+ else if (strcasecmp (value->list.value[i].s, "utility") == 0)
+ mask |= CompWindowTypeUtilMask;
+ else if (strcasecmp (value->list.value[i].s, "splash") == 0)
+ mask |= CompWindowTypeSplashMask;
+ else if (strcasecmp (value->list.value[i].s, "dialog") == 0)
+ mask |= CompWindowTypeDialogMask;
+ else if (strcasecmp (value->list.value[i].s, "modaldialog") == 0)
+ mask |= CompWindowTypeModalDialogMask;
+ else if (strcasecmp (value->list.value[i].s, "normal") == 0)
+ mask |= CompWindowTypeNormalMask;
+ else if (strcasecmp (value->list.value[i].s, "fullscreen") == 0)
+ mask |= CompWindowTypeFullscreenMask;
+ else if (strcasecmp (value->list.value[i].s, "unknown") == 0)
+ mask |= CompWindowTypeUnknownMask;
+ }
+
+ return mask;
+}
diff --git a/src/paint.c b/src/paint.c
new file mode 100644
index 00000000..f329d825
--- /dev/null
+++ b/src/paint.c
@@ -0,0 +1,864 @@
+/*
+ * 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 <compiz.h>
+
+ScreenPaintAttrib defaultScreenPaintAttrib = {
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -DEFAULT_Z_CAMERA
+};
+
+WindowPaintAttrib defaultWindowPaintAttrib = {
+ OPAQUE, 1.0f, 1.0f
+};
+
+void
+preparePaintScreen (CompScreen *screen,
+ int msSinceLastPaint) {}
+
+void
+donePaintScreen (CompScreen *screen) {}
+
+void
+translateRotateScreen (const ScreenPaintAttrib *sa)
+{
+ glTranslatef (sa->xTranslate,
+ sa->yTranslate,
+ sa->zTranslate + sa->zCamera);
+
+ glRotatef (sa->xRotate, 0.0f, 1.0f, 0.0f);
+ glRotatef (sa->vRotate,
+ 1.0f - sa->xRotate / 90.0f,
+ 0.0f,
+ sa->xRotate / 90.0f);
+ glRotatef (sa->yRotate, 0.0f, 1.0f, 0.0f);
+}
+
+void
+paintTransformedScreen (CompScreen *screen,
+ const ScreenPaintAttrib *sAttrib,
+ unsigned int mask)
+{
+ CompWindow *w;
+ int windowMask;
+ int backgroundMask;
+
+ glPushMatrix ();
+
+ translateRotateScreen (sAttrib);
+
+ glTranslatef (-0.5f, -0.5f, -sAttrib->zTranslate);
+ 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)
+ {
+ if (w->destroyed || w->attrib.map_state != IsViewable)
+ continue;
+
+ if (w->damaged)
+ (*screen->paintWindow) (w, &w->paint, &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)
+ {
+ if (w->destroyed || w->attrib.map_state != IsViewable)
+ continue;
+
+ if (w->damaged)
+ (*screen->paintWindow) (w, &w->paint, &screen->region, windowMask);
+ }
+
+ glPopMatrix ();
+}
+
+Bool
+paintScreen (CompScreen *screen,
+ const ScreenPaintAttrib *sAttrib,
+ Region region,
+ unsigned int mask)
+{
+ static Region tmpRegion = NULL;
+ CompWindow *w;
+
+ if (mask & PAINT_SCREEN_REGION_MASK)
+ {
+ if (mask & PAINT_SCREEN_TRANSFORMED_MASK)
+ {
+ if (mask & PAINT_SCREEN_FULL_MASK)
+ {
+ (*screen->paintTransformedScreen) (screen, sAttrib, mask);
+
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ /* fall through and redraw region */
+ }
+ else if (mask & PAINT_SCREEN_FULL_MASK)
+ {
+ (*screen->paintTransformedScreen) (screen, sAttrib, mask);
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+
+ glPushMatrix ();
+
+ glTranslatef (-0.5f, -0.5f, -DEFAULT_Z_CAMERA);
+ glScalef (1.0f / screen->width, -1.0f / screen->height, 1.0f);
+ glTranslatef (0.0f, -screen->height, 0.0f);
+
+ if (mask & PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK)
+ {
+ (*screen->paintBackground) (screen, region, 0);
+
+ /* paint all windows from bottom to top */
+ for (w = screen->windows; w; w = w->next)
+ {
+ if (w->destroyed || w->attrib.map_state != IsViewable)
+ continue;
+
+ (*screen->paintWindow) (w, &w->paint, region, 0);
+ }
+ }
+ else
+ {
+ if (!tmpRegion)
+ {
+ tmpRegion = XCreateRegion ();
+ if (!tmpRegion)
+ return FALSE;
+ }
+
+ XSubtractRegion (region, &emptyRegion, tmpRegion);
+
+ /* paint solid windows */
+ for (w = screen->reverseWindows; w; w = w->prev)
+ {
+ if (w->destroyed || w->invisible)
+ continue;
+
+ if (tmpRegion->numRects)
+ {
+ if ((*screen->paintWindow) (w, &w->paint, tmpRegion,
+ PAINT_WINDOW_SOLID_MASK))
+ XSubtractRegion (tmpRegion, w->region, tmpRegion);
+ }
+
+ /* copy region */
+ XSubtractRegion (tmpRegion, &emptyRegion, w->clip);
+ }
+
+ if (tmpRegion->numRects)
+ (*screen->paintBackground) (screen, tmpRegion, 0);
+
+ /* paint translucent windows */
+ for (w = screen->windows; w; w = w->next)
+ {
+ if (w->destroyed || w->invisible)
+ continue;
+
+ if (w->clip->numRects)
+ (*screen->paintWindow) (w, &w->paint, w->clip,
+ PAINT_WINDOW_TRANSLUCENT_MASK);
+ }
+ }
+
+ glPopMatrix ();
+
+ return TRUE;
+}
+
+#define ADD_RECT(data, m, n, x1, y1, x2, y2) \
+ for (it = 0; it < n; it++) \
+ { \
+ *(data)++ = COMP_TEX_COORD_X (&m[it], x1); \
+ *(data)++ = COMP_TEX_COORD_Y (&m[it], y2); \
+ } \
+ *(data)++ = (x1); \
+ *(data)++ = (y2); \
+ for (it = 0; it < n; it++) \
+ { \
+ *(data)++ = COMP_TEX_COORD_X (&m[it], x2); \
+ *(data)++ = COMP_TEX_COORD_Y (&m[it], y2); \
+ } \
+ *(data)++ = (x2); \
+ *(data)++ = (y2); \
+ for (it = 0; it < n; it++) \
+ { \
+ *(data)++ = COMP_TEX_COORD_X (&m[it], x2); \
+ *(data)++ = COMP_TEX_COORD_Y (&m[it], y1); \
+ } \
+ *(data)++ = (x2); \
+ *(data)++ = (y1); \
+ for (it = 0; it < n; it++) \
+ { \
+ *(data)++ = COMP_TEX_COORD_X (&m[it], x1); \
+ *(data)++ = COMP_TEX_COORD_Y (&m[it], y1); \
+ } \
+ *(data)++ = (x1); \
+ *(data)++ = (y1)
+
+#define ADD_QUAD(data, m, n, x1, y1, x2, y2) \
+ for (it = 0; it < n; it++) \
+ { \
+ *(data)++ = COMP_TEX_COORD_XY (&m[it], x1, y2); \
+ *(data)++ = COMP_TEX_COORD_YX (&m[it], x1, y2); \
+ } \
+ *(data)++ = (x1); \
+ *(data)++ = (y2); \
+ for (it = 0; it < n; it++) \
+ { \
+ *(data)++ = COMP_TEX_COORD_XY (&m[it], x2, y2); \
+ *(data)++ = COMP_TEX_COORD_YX (&m[it], x2, y2); \
+ } \
+ *(data)++ = (x2); \
+ *(data)++ = (y2); \
+ for (it = 0; it < n; it++) \
+ { \
+ *(data)++ = COMP_TEX_COORD_XY (&m[it], x2, y1); \
+ *(data)++ = COMP_TEX_COORD_YX (&m[it], x2, y1); \
+ } \
+ *(data)++ = (x2); \
+ *(data)++ = (y1); \
+ for (it = 0; it < n; it++) \
+ { \
+ *(data)++ = COMP_TEX_COORD_XY (&m[it], x1, y1); \
+ *(data)++ = COMP_TEX_COORD_YX (&m[it], x1, y1); \
+ } \
+ *(data)++ = (x1); \
+ *(data)++ = (y1)
+
+
+Bool
+moreWindowVertices (CompWindow *w,
+ int newSize)
+{
+ if (newSize > w->vertexSize)
+ {
+ GLfloat *vertices;
+
+ vertices = realloc (w->vertices, sizeof (GLfloat) * newSize);
+ if (!vertices)
+ return FALSE;
+
+ w->vertices = vertices;
+ w->vertexSize = newSize;
+ }
+
+ return TRUE;
+}
+
+Bool
+moreWindowIndices (CompWindow *w,
+ int newSize)
+{
+ if (newSize > w->indexSize)
+ {
+ GLushort *indices;
+
+ indices = realloc (w->indices, sizeof (GLushort) * newSize);
+ if (!indices)
+ return FALSE;
+
+ w->indices = indices;
+ w->indexSize = newSize;
+ }
+
+ return TRUE;
+}
+
+void
+addWindowGeometry (CompWindow *w,
+ CompMatrix *matrix,
+ int nMatrix,
+ Region region,
+ Region clip)
+{
+ BoxRec full;
+
+ w->texUnits = nMatrix;
+
+ full = clip->extents;
+ if (region->extents.x1 > full.x1)
+ full.x1 = region->extents.x1;
+ if (region->extents.y1 > full.y1)
+ full.y1 = region->extents.y1;
+ if (region->extents.x2 < full.x2)
+ full.x2 = region->extents.x2;
+ if (region->extents.y2 < full.y2)
+ full.y2 = region->extents.y2;
+
+ if (full.x1 < full.x2 && full.y1 < full.y2)
+ {
+ BoxPtr pBox;
+ int nBox;
+ BoxPtr pClip;
+ int nClip;
+ BoxRec cbox;
+ int vSize;
+ int n, it, x1, y1, x2, y2;
+ GLfloat *d;
+ Bool rect = TRUE;
+
+ for (it = 0; it < nMatrix; it++)
+ {
+ if (matrix[it].xy != 0.0f && matrix[it].yx != 0.0f)
+ {
+ rect = FALSE;
+ break;
+ }
+ }
+
+ pBox = region->rects;
+ nBox = region->numRects;
+
+ vSize = 2 + nMatrix * 2;
+
+ n = w->vCount / 4;
+
+ if ((n + nBox) * vSize * 4 > w->vertexSize)
+ {
+ if (!moreWindowVertices (w, (n + nBox) * vSize * 4))
+ return;
+ }
+
+ d = w->vertices + (w->vCount * vSize);
+
+ while (nBox--)
+ {
+ x1 = pBox->x1;
+ y1 = pBox->y1;
+ x2 = pBox->x2;
+ y2 = pBox->y2;
+
+ 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 = clip->numRects;
+
+ if (nClip == 1)
+ {
+ if (rect)
+ {
+ ADD_RECT (d, matrix, nMatrix, x1, y1, x2, y2);
+ }
+ else
+ {
+ ADD_QUAD (d, matrix, nMatrix, x1, y1, x2, y2);
+ }
+
+ n++;
+ }
+ else
+ {
+ pClip = clip->rects;
+
+ if (((n + nClip) * vSize * 4) > w->vertexSize)
+ {
+ if (!moreWindowVertices (w, (n + nClip) * vSize * 4))
+ return;
+
+ d = w->vertices + (n * vSize * 4);
+ }
+
+ while (nClip--)
+ {
+ cbox = *pClip;
+
+ pClip++;
+
+ if (cbox.x1 < x1)
+ cbox.x1 = x1;
+ if (cbox.y1 < y1)
+ cbox.y1 = y1;
+ if (cbox.x2 > x2)
+ cbox.x2 = x2;
+ if (cbox.y2 > y2)
+ cbox.y2 = y2;
+
+ if (cbox.x1 < cbox.x2 && cbox.y1 < cbox.y2)
+ {
+ if (rect)
+ {
+ ADD_RECT (d, matrix, nMatrix,
+ cbox.x1, cbox.y1, cbox.x2, cbox.y2);
+ }
+ else
+ {
+ ADD_QUAD (d, matrix, nMatrix,
+ cbox.x1, cbox.y1, cbox.x2, cbox.y2);
+ }
+
+ n++;
+ }
+ }
+ }
+ }
+ }
+ w->vCount = n * 4;
+ }
+}
+
+void
+drawWindowGeometry (CompWindow *w)
+{
+ int texUnit = w->texUnits;
+ int currentTexUnit = 0;
+ int stride = (1 + texUnit) * 2;
+ GLfloat *vertices = w->vertices + (stride - 2);
+
+ stride *= sizeof (GLfloat);
+
+ glVertexPointer (2, GL_FLOAT, stride, vertices);
+
+ while (texUnit--)
+ {
+ if (texUnit != currentTexUnit)
+ {
+ w->screen->clientActiveTexture (GL_TEXTURE0_ARB + texUnit);
+ currentTexUnit = texUnit;
+ }
+ vertices -= 2;
+ glTexCoordPointer (2, GL_FLOAT, stride, vertices);
+ }
+
+ glDrawArrays (GL_QUADS, 0, w->vCount);
+}
+
+void
+drawWindowTexture (CompWindow *w,
+ CompTexture *texture,
+ const WindowPaintAttrib *attrib,
+ unsigned int mask)
+{
+ int filter;
+
+ glPushMatrix ();
+
+ if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
+ {
+ glTranslatef (w->attrib.x, w->attrib.y, 0.0f);
+ glScalef (attrib->xScale, attrib->yScale, 0.0f);
+ glTranslatef (-w->attrib.x, -w->attrib.y, 0.0f);
+
+ filter = COMP_TEXTURE_FILTER_GOOD;
+ }
+ else if (mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK)
+ {
+ filter = COMP_TEXTURE_FILTER_GOOD;
+ }
+ else
+ {
+ filter = COMP_TEXTURE_FILTER_FAST;
+ }
+
+ if (w->screen->canDoSaturated && attrib->saturation != COLOR)
+ {
+ GLfloat constant[4];
+
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ glEnable (GL_BLEND);
+
+ enableTexture (w->screen, texture, filter);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PRIMARY_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+ glColor4f (1.0f, 1.0f, 1.0f, 0.5f);
+
+ w->screen->activeTexture (GL_TEXTURE1_ARB);
+
+ enableTexture (w->screen, texture, filter);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+
+ if (w->screen->canDoSlightlySaturated && attrib->saturation > 0)
+ {
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+ constant[0] = 0.5f + 0.5f * RED_SATURATION_WEIGHT;
+ constant[1] = 0.5f + 0.5f * GREEN_SATURATION_WEIGHT;
+ constant[2] = 0.5f + 0.5f * BLUE_SATURATION_WEIGHT;
+ constant[3] = 1.0;
+
+ glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
+
+ w->screen->activeTexture (GL_TEXTURE2_ARB);
+
+ enableTexture (w->screen, texture, filter);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+
+ constant[3] = attrib->saturation / 65535.0f;
+
+ glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
+
+ if (attrib->opacity < OPAQUE || attrib->brightness != BRIGHT)
+ {
+ w->screen->activeTexture (GL_TEXTURE3_ARB);
+
+ enableTexture (w->screen, texture, filter);
+
+ constant[3] = attrib->opacity / 65535.0f;
+ constant[0] = constant[1] = constant[2] = constant[3] *
+ attrib->brightness / 65535.0f;
+
+ glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+
+ (*w->screen->drawWindowGeometry) (w);
+
+ disableTexture (texture);
+
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ w->screen->activeTexture (GL_TEXTURE2_ARB);
+ }
+ else
+ {
+ (*w->screen->drawWindowGeometry) (w);
+ }
+
+ disableTexture (texture);
+
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ w->screen->activeTexture (GL_TEXTURE1_ARB);
+ }
+ else
+ {
+ glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ glTexEnvf (GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvf (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+
+ constant[3] = attrib->opacity / 65535.0f;
+ constant[0] = constant[1] = constant[2] = constant[3] *
+ attrib->brightness / 65535.0f;
+
+ constant[0] = 0.5f + 0.5f * RED_SATURATION_WEIGHT * constant[0];
+ constant[1] = 0.5f + 0.5f * GREEN_SATURATION_WEIGHT * constant[1];
+ constant[2] = 0.5f + 0.5f * BLUE_SATURATION_WEIGHT * constant[2];
+
+ glTexEnvfv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant);
+
+ (*w->screen->drawWindowGeometry) (w);
+ }
+
+ disableTexture (texture);
+
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ w->screen->activeTexture (GL_TEXTURE0_ARB);
+
+ disableTexture (texture);
+
+ glColor4usv (defaultColor);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ glDisable (GL_BLEND);
+ }
+ else
+ {
+ enableTexture (w->screen, texture, filter);
+
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ {
+ glEnable (GL_BLEND);
+ if (attrib->opacity != OPAQUE || attrib->brightness != BRIGHT)
+ {
+ GLushort color;
+
+ color = (attrib->opacity * attrib->brightness) >> 16;
+
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4us (color, color, color, attrib->opacity);
+
+ (*w->screen->drawWindowGeometry) (w);
+
+ glColor4usv (defaultColor);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ }
+ else
+ {
+ (*w->screen->drawWindowGeometry) (w);
+ }
+
+ glDisable (GL_BLEND);
+ }
+ else if (attrib->brightness != BRIGHT)
+ {
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4us (attrib->brightness, attrib->brightness,
+ attrib->brightness, BRIGHT);
+
+ (*w->screen->drawWindowGeometry) (w);
+
+ glColor4usv (defaultColor);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ }
+ else
+ {
+ (*w->screen->drawWindowGeometry) (w);
+ }
+
+ disableTexture (texture);
+ }
+
+ glPopMatrix ();
+}
+
+Bool
+paintWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib,
+ Region region,
+ unsigned int mask)
+{
+ if (mask & PAINT_WINDOW_SOLID_MASK)
+ {
+ if (w->alpha)
+ return FALSE;
+
+ if (attrib->opacity != OPAQUE)
+ return FALSE;
+ }
+ else if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ {
+ if (!w->alpha && attrib->opacity == OPAQUE)
+ return FALSE;
+ }
+ else
+ {
+ if (w->alpha || attrib->opacity != OPAQUE)
+ mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+ else
+ mask |= PAINT_WINDOW_SOLID_MASK;
+ }
+
+ if (!w->texture.pixmap)
+ bindWindow (w);
+
+ if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
+ region = &infiniteRegion;
+
+ w->vCount = 0;
+ (*w->screen->addWindowGeometry) (w, &w->matrix, 1, w->region, region);
+ if (w->vCount)
+ drawWindowTexture (w, &w->texture, attrib, mask);
+
+ 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++ = COMP_TEX_COORD_X (&bg->matrix, pBox->x1);
+ *d++ = COMP_TEX_COORD_Y (&bg->matrix, pBox->y2);
+
+ *d++ = pBox->x1;
+ *d++ = pBox->y2;
+
+ *d++ = COMP_TEX_COORD_X (&bg->matrix, pBox->x2);
+ *d++ = COMP_TEX_COORD_Y (&bg->matrix, pBox->y2);
+
+ *d++ = pBox->x2;
+ *d++ = pBox->y2;
+
+ *d++ = COMP_TEX_COORD_X (&bg->matrix, pBox->x2);
+ *d++ = COMP_TEX_COORD_Y (&bg->matrix, pBox->y1);
+
+ *d++ = pBox->x2;
+ *d++ = pBox->y1;
+
+ *d++ = COMP_TEX_COORD_X (&bg->matrix, pBox->x1);
+ *d++ = COMP_TEX_COORD_Y (&bg->matrix, 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 00000000..fb9ddfc3
--- /dev/null
+++ b/src/plugin.c
@@ -0,0 +1,404 @@
+/*
+ * 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 <compiz.h>
+
+#define HOME_PLUGINDIR ".compiz/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, *home, *plugindir;
+
+ 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;
+
+ 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)
+ p->dlhand = dlopen (file, RTLD_LAZY);
+ }
+
+ if (p->dlhand)
+ {
+ PluginGetInfoProc getInfo;
+ char *error;
+
+ dlerror ();
+
+ getInfo = (PluginGetInfoProc) dlsym (p->dlhand, "getCompPluginInfo");
+
+ error = dlerror ();
+ if (error)
+ {
+ fprintf (stderr, "%s: dlsym: %s\n", programName, error);
+
+ 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);
+}
+
+static Bool
+checkPluginDeps (CompPlugin *p)
+{
+ CompPluginDep *deps = p->vTable->deps;
+ int nDeps = p->vTable->nDeps;
+
+ while (nDeps--)
+ {
+ switch (deps->rule) {
+ case CompPluginRuleBefore:
+ if (findActivePlugin (deps->plugin))
+ {
+ fprintf (stderr, "%s: '%s' plugin must be loaded before '%s' "
+ "plugin\n", programName, p->vTable->name, deps->plugin);
+
+ return FALSE;
+ }
+ break;
+ case CompPluginRuleAfter:
+ if (!findActivePlugin (deps->plugin))
+ {
+ fprintf (stderr, "%s: '%s' plugin must be loaded after '%s' "
+ "plugin\n", programName, p->vTable->name, deps->plugin);
+
+ return FALSE;
+ }
+ break;
+ }
+
+ deps++;
+ }
+
+ return TRUE;
+}
+
+Bool
+pushPlugin (CompPlugin *p)
+{
+ if (findActivePlugin (p->vTable->name))
+ {
+ fprintf (stderr, "%s: Plugin '%s' already active\n", programName,
+ p->vTable->name);
+
+ return FALSE;
+ }
+
+ if (!checkPluginDeps (p))
+ {
+ fprintf (stderr, "%s: Can't activate '%s' plugin due to dependency "
+ "problems\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 00000000..ea5b57ac
--- /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 <compiz.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 00000000..79bb5a53
--- /dev/null
+++ b/src/readpng.c
@@ -0,0 +1,266 @@
+/*
+ * 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 <compiz.h>
+
+#define HOME_IMAGEDIR ".compiz/images"
+
+#define PNG_SIG_SIZE 8
+
+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));
+ }
+}
+
+static Bool
+readPngData (png_struct *png,
+ png_info *info,
+ char **data,
+ unsigned int *width,
+ unsigned int *height)
+{
+ png_uint_32 png_width, png_height;
+ int depth, color_type, interlace, i;
+ unsigned int pixel_size;
+ png_byte **row_pointers;
+
+ 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)
+ return FALSE;
+
+ row_pointers = (png_byte **) malloc (png_height * sizeof (char *));
+ if (!row_pointers)
+ {
+ free (*data);
+ return FALSE;
+ }
+
+ 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);
+
+ return TRUE;
+}
+
+Bool
+readPng (const char *filename,
+ char **data,
+ unsigned int *width,
+ unsigned int *height)
+{
+ unsigned char png_sig[PNG_SIG_SIZE];
+ FILE *file;
+ int sig_bytes;
+ png_struct *png;
+ png_info *info;
+ Bool status;
+
+ 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)
+ return FALSE;
+
+ info = png_create_info_struct (png);
+ if (info == NULL)
+ {
+ png_destroy_read_struct (&png, NULL, NULL);
+ fclose (file);
+
+ return FALSE;
+ }
+
+ png_init_io (png, file);
+ png_set_sig_bytes (png, sig_bytes);
+
+ status = readPngData (png, info, data, width, height);
+
+ png_destroy_read_struct (&png, &info, NULL);
+ fclose (file);
+
+ return status;
+}
+
+static void
+userReadData (png_structp png_ptr,
+ png_bytep data,
+ png_size_t length)
+{
+ const unsigned char **buffer = (const unsigned char **)
+ png_get_io_ptr (png_ptr);
+
+ memcpy (data, *buffer, length);
+ *buffer += length;
+}
+
+Bool
+readPngBuffer (const unsigned char *buffer,
+ char **data,
+ unsigned int *width,
+ unsigned int *height)
+{
+ unsigned char png_sig[PNG_SIG_SIZE];
+ png_struct *png;
+ png_info *info;
+ const unsigned char *b = buffer + PNG_SIG_SIZE;
+ Bool status;
+
+ memcpy (png_sig, buffer, PNG_SIG_SIZE);
+ if (png_check_sig (png_sig, PNG_SIG_SIZE) == 0)
+ return FALSE;
+
+ png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png)
+ return FALSE;
+
+ info = png_create_info_struct (png);
+ if (info == NULL)
+ {
+ png_destroy_read_struct (&png, NULL, NULL);
+ return FALSE;
+ }
+
+ png_set_read_fn (png, (void *) &b, userReadData);
+ png_set_sig_bytes (png, PNG_SIG_SIZE);
+
+ status = readPngData (png, info, data, width, height);
+
+ png_destroy_read_struct (&png, &info, NULL);
+
+ return status;
+}
+
diff --git a/src/screen.c b/src/screen.c
new file mode 100644
index 00000000..27c7d9d8
--- /dev/null
+++ b/src/screen.c
@@ -0,0 +1,2521 @@
+/*
+ * 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>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "../config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/cursorfont.h>
+
+#include <compiz.h>
+
+#define DETECT_REFRESH_RATE_DEFAULT TRUE
+
+#define SCREEN_SIZE_DEFAULT 4
+#define SCREEN_SIZE_MIN 4
+#define SCREEN_SIZE_MAX 32
+
+#define CLOSE_WINDOW_KEY_DEFAULT "F4"
+#define CLOSE_WINDOW_MODIFIERS_DEFAULT (CompPressMask | CompAltMask)
+
+#define MAIN_MENU_KEY_DEFAULT "F1"
+#define MAIN_MENU_MODIFIERS_DEFAULT (CompPressMask | CompAltMask)
+
+#define RUN_DIALOG_KEY_DEFAULT "F2"
+#define RUN_DIALOG_MODIFIERS_DEFAULT (CompPressMask | CompAltMask)
+
+#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);
+}
+
+static void
+setVirtualScreenSize (CompScreen *screen,
+ int size)
+{
+ unsigned long data[2];
+
+ data[0] = screen->width * size;
+ data[1] = screen->height;
+
+ XChangeProperty (screen->display->display, screen->root,
+ screen->display->desktopGeometryAtom,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) data, 2);
+
+ screen->size = size;
+}
+
+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_DETECT_REFRESH_RATE:
+ if (compSetBoolOption (o, value))
+ return TRUE;
+ break;
+ case COMP_SCREEN_OPTION_REFRESH_RATE:
+ if (screen->opt[COMP_SCREEN_OPTION_DETECT_REFRESH_RATE].value.b)
+ return FALSE;
+
+ if (compSetIntOption (o, value))
+ {
+ screen->redrawTime = 1000 / o->value.i;
+ screen->optimalRedrawTime = screen->redrawTime;
+ return TRUE;
+ }
+ break;
+ case COMP_SCREEN_OPTION_SIZE:
+ if (compSetIntOption (o, value))
+ {
+ if (o->value.i * screen->width > MAXSHORT)
+ return FALSE;
+
+ setVirtualScreenSize (screen, o->value.i);
+ return TRUE;
+ }
+ break;
+ case COMP_SCREEN_OPTION_COMMAND0:
+ case COMP_SCREEN_OPTION_COMMAND1:
+ if (compSetStringOption (o, value))
+ return TRUE;
+ break;
+ case COMP_SCREEN_OPTION_CLOSE_WINDOW:
+ case COMP_SCREEN_OPTION_MAIN_MENU:
+ case COMP_SCREEN_OPTION_RUN_DIALOG:
+ case COMP_SCREEN_OPTION_RUN_COMMAND0:
+ case COMP_SCREEN_OPTION_RUN_COMMAND1:
+ if (addScreenBinding (screen, &value->bind))
+ {
+ removeScreenBinding (screen, &o->value.bind);
+
+ if (compSetBindingOption (o, value))
+ 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_DETECT_REFRESH_RATE];
+ o->name = "detect_refresh_rate";
+ o->shortDesc = "Detect Refresh Rate";
+ o->longDesc = "Automatic detection of refresh rate";
+ o->type = CompOptionTypeBool;
+ o->value.b = DETECT_REFRESH_RATE_DEFAULT;
+
+ 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;
+
+ o = &screen->opt[COMP_SCREEN_OPTION_SIZE];
+ o->name = "size";
+ o->shortDesc = "Virtual Size";
+ o->longDesc = "Screen size multiplier for virtual size";
+ o->type = CompOptionTypeInt;
+ o->value.i = SCREEN_SIZE_DEFAULT;
+ o->rest.i.min = SCREEN_SIZE_MIN;
+ o->rest.i.max = SCREEN_SIZE_MAX;
+
+ o = &screen->opt[COMP_SCREEN_OPTION_CLOSE_WINDOW];
+ o->name = "close_window";
+ o->shortDesc = "Close Window";
+ o->longDesc = "Close active window";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = CLOSE_WINDOW_MODIFIERS_DEFAULT;
+ o->value.bind.u.key.keycode =
+ XKeysymToKeycode (screen->display->display,
+ XStringToKeysym (CLOSE_WINDOW_KEY_DEFAULT));
+
+ o = &screen->opt[COMP_SCREEN_OPTION_MAIN_MENU];
+ o->name = "main_menu";
+ o->shortDesc = "Main Menu";
+ o->longDesc = "Open main menu";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = MAIN_MENU_MODIFIERS_DEFAULT;
+ o->value.bind.u.key.keycode =
+ XKeysymToKeycode (screen->display->display,
+ XStringToKeysym (MAIN_MENU_KEY_DEFAULT));
+
+ o = &screen->opt[COMP_SCREEN_OPTION_RUN_DIALOG];
+ o->name = "run";
+ o->shortDesc = "Run";
+ o->longDesc = "Run application";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = RUN_DIALOG_MODIFIERS_DEFAULT;
+ o->value.bind.u.key.keycode =
+ XKeysymToKeycode (screen->display->display,
+ XStringToKeysym (RUN_DIALOG_KEY_DEFAULT));
+
+ o = &screen->opt[COMP_SCREEN_OPTION_COMMAND0];
+ o->name = "command0";
+ o->shortDesc = "Command line";
+ o->longDesc = "Command line to be executed in shell";
+ o->type = CompOptionTypeString;
+ o->value.s = strdup ("");
+ o->rest.s.string = NULL;
+ o->rest.s.nString = 0;
+
+ o = &screen->opt[COMP_SCREEN_OPTION_RUN_COMMAND0];
+ o->name = "run_command0";
+ o->shortDesc = "Run command";
+ o->longDesc = "Run shell command";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = 0;
+ o->value.bind.u.key.keycode = 0;
+
+ o = &screen->opt[COMP_SCREEN_OPTION_COMMAND1];
+ o->name = "command1";
+ o->shortDesc = "Command line";
+ o->longDesc = "Command line to be executed in shell";
+ o->type = CompOptionTypeString;
+ o->value.s = strdup ("");
+ o->rest.s.string = NULL;
+ o->rest.s.nString = 0;
+
+ o = &screen->opt[COMP_SCREEN_OPTION_RUN_COMMAND1];
+ o->name = "run_command1";
+ o->shortDesc = "Run command";
+ o->longDesc = "Run shell command";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = 0;
+ o->value.bind.u.key.keycode = 0;
+}
+
+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
+updateStartupFeedback (CompScreen *s)
+{
+ if (s->startupSequences)
+ XDefineCursor (s->display->display, s->root, s->busyCursor);
+ else
+ XDefineCursor (s->display->display, s->root, s->normalCursor);
+}
+
+#define STARTUP_TIMEOUT_DELAY 15000
+
+static Bool
+startupSequenceTimeout (void *data)
+{
+ CompScreen *screen = data;
+ CompStartupSequence *s;
+ struct timeval now, active;
+ double elapsed;
+
+ gettimeofday (&now, NULL);
+
+ for (s = screen->startupSequences; s; s = s->next)
+ {
+ sn_startup_sequence_get_last_active_time (s->sequence,
+ &active.tv_sec,
+ &active.tv_usec);
+
+ elapsed = ((((double) now.tv_sec - active.tv_sec) * 1000000.0 +
+ (now.tv_usec - active.tv_usec))) / 1000.0;
+
+ if (elapsed > STARTUP_TIMEOUT_DELAY)
+ sn_startup_sequence_complete (s->sequence);
+ }
+
+ return TRUE;
+}
+
+static void
+addSequence (CompScreen *screen,
+ SnStartupSequence *sequence)
+{
+ CompStartupSequence *s;
+
+ s = malloc (sizeof (CompStartupSequence));
+ if (!s)
+ return;
+
+ sn_startup_sequence_ref (sequence);
+
+ s->next = screen->startupSequences;
+ s->sequence = sequence;
+
+ screen->startupSequences = s;
+
+ if (!screen->startupSequenceTimeoutHandle)
+ compAddTimeout (1000,
+ startupSequenceTimeout,
+ screen);
+
+ updateStartupFeedback (screen);
+}
+
+static void
+removeSequence (CompScreen *screen,
+ SnStartupSequence *sequence)
+{
+ CompStartupSequence *s, *p = NULL;
+
+ for (s = screen->startupSequences; s; s = s->next)
+ {
+ if (s->sequence == sequence)
+ break;
+
+ p = s;
+ }
+
+ if (!s)
+ return;
+
+ sn_startup_sequence_unref (sequence);
+
+ if (p)
+ p->next = s->next;
+ else
+ screen->startupSequences = NULL;
+
+ free (s);
+
+ if (!screen->startupSequences && screen->startupSequenceTimeoutHandle)
+ {
+ compRemoveTimeout (screen->startupSequenceTimeoutHandle);
+ screen->startupSequenceTimeoutHandle = 0;
+ }
+
+ updateStartupFeedback (screen);
+}
+
+static void
+compScreenSnEvent (SnMonitorEvent *event,
+ void *userData)
+{
+ CompScreen *screen = userData;
+ SnStartupSequence *sequence;
+
+ sequence = sn_monitor_event_get_startup_sequence (event);
+
+ switch (sn_monitor_event_get_type (event)) {
+ case SN_MONITOR_EVENT_INITIATED:
+ addSequence (screen, sequence);
+ break;
+ case SN_MONITOR_EVENT_COMPLETED:
+ removeSequence (screen, sn_monitor_event_get_startup_sequence (event));
+ break;
+ case SN_MONITOR_EVENT_CHANGED:
+ case SN_MONITOR_EVENT_CANCELED:
+ break;
+ }
+}
+
+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;
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ glMatrixMode (GL_MODELVIEW);
+ glLoadIdentity ();
+ glDepthRange (0, 1);
+ glViewport (-1, -1, 2, 2);
+ glRasterPos2f (0, 0);
+
+ s->rasterX = s->rasterY = 0;
+
+ 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;
+
+ updateWorkareaForScreen (s);
+}
+
+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);
+ }
+}
+
+void
+detectRefreshRateOfScreen (CompScreen *s)
+{
+ if (s->opt[COMP_SCREEN_OPTION_DETECT_REFRESH_RATE].value.b)
+ {
+ XRRScreenConfiguration *config;
+ char *name;
+ CompOptionValue value;
+
+ config = XRRGetScreenInfo (s->display->display, s->root);
+ value.i = (int) XRRConfigCurrentRate (config);
+
+ XRRFreeScreenConfigInfo (config);
+
+ name = s->opt[COMP_SCREEN_OPTION_REFRESH_RATE].name;
+
+ s->opt[COMP_SCREEN_OPTION_DETECT_REFRESH_RATE].value.b = FALSE;
+ (*s->setScreenOption) (s, name, &value);
+ s->opt[COMP_SCREEN_OPTION_DETECT_REFRESH_RATE].value.b = TRUE;
+ }
+}
+
+static void
+setSupportingWmCheck (CompScreen *s)
+{
+ CompDisplay *d = s->display;
+
+ XChangeProperty (d->display, s->grabWindow, d->supportingWmCheckAtom,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &s->grabWindow, 1);
+
+ XChangeProperty (d->display, s->grabWindow, d->wmNameAtom,
+ d->utf8StringAtom, 8, PropModeReplace,
+ (unsigned char *) PACKAGE, strlen (PACKAGE));
+ XChangeProperty (d->display, s->grabWindow, d->winStateAtom,
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *) &d->winStateSkipTaskbarAtom, 1);
+ XChangeProperty (d->display, s->grabWindow, d->winStateAtom,
+ XA_ATOM, 32, PropModeAppend,
+ (unsigned char *) &d->winStateSkipPagerAtom, 1);
+ XChangeProperty (d->display, s->grabWindow, d->winStateAtom,
+ XA_ATOM, 32, PropModeAppend,
+ (unsigned char *) &d->winStateHiddenAtom, 1);
+
+ XChangeProperty (d->display, s->root, d->supportingWmCheckAtom,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &s->grabWindow, 1);
+}
+
+static void
+setSupported (CompScreen *s)
+{
+ CompDisplay *d = s->display;
+ Atom data[256];
+ int i = 0;
+
+ data[i++] = d->supportedAtom;
+ data[i++] = d->supportingWmCheckAtom;
+
+ data[i++] = d->utf8StringAtom;
+
+ data[i++] = d->clientListAtom;
+ data[i++] = d->clientListStackingAtom;
+
+ data[i++] = d->winActiveAtom;
+
+ data[i++] = d->desktopViewportAtom;
+ data[i++] = d->desktopGeometryAtom;
+ data[i++] = d->currentDesktopAtom;
+ data[i++] = d->numberOfDesktopsAtom;
+ data[i++] = d->showingDesktopAtom;
+
+ data[i++] = d->workareaAtom;
+
+ data[i++] = d->wmNameAtom;
+/*
+ data[i++] = d->wmVisibleNameAtom;
+*/
+
+ data[i++] = d->wmStrutAtom;
+ data[i++] = d->wmStrutPartialAtom;
+
+/*
+ data[i++] = d->wmPidAtom;
+ data[i++] = d->wmUserTimeAtom;
+*/
+
+ data[i++] = d->frameExtentsAtom;
+ data[i++] = d->frameWindowAtom;
+
+ data[i++] = d->winStateModalAtom;
+ data[i++] = d->winStateStickyAtom;
+ data[i++] = d->winStateMaximizedVertAtom;
+ data[i++] = d->winStateMaximizedHorzAtom;
+ data[i++] = d->winStateShadedAtom;
+ data[i++] = d->winStateSkipTaskbarAtom;
+ data[i++] = d->winStateSkipPagerAtom;
+ data[i++] = d->winStateHiddenAtom;
+ data[i++] = d->winStateFullscreenAtom;
+ data[i++] = d->winStateAboveAtom;
+ data[i++] = d->winStateBelowAtom;
+ data[i++] = d->winStateDemandsAttentionAtom;
+
+ data[i++] = d->winOpacityAtom;
+ data[i++] = d->winBrightnessAtom;
+
+ if (s->canDoSaturated)
+ {
+ data[i++] = d->winSaturationAtom;
+ data[i++] = d->winStateDisplayModalAtom;
+ }
+
+ data[i++] = d->wmAllowedActionsAtom;
+
+ data[i++] = d->winActionMoveAtom;
+ data[i++] = d->winActionResizeAtom;
+ data[i++] = d->winActionStickAtom;
+ data[i++] = d->winActionMinimizeAtom;
+ data[i++] = d->winActionMaximizeHorzAtom;
+ data[i++] = d->winActionMaximizeVertAtom;
+ data[i++] = d->winActionFullscreenAtom;
+ data[i++] = d->winActionCloseAtom;
+
+ data[i++] = d->winTypeAtom;
+ data[i++] = d->winTypeDesktopAtom;
+ data[i++] = d->winTypeDockAtom;
+ data[i++] = d->winTypeToolbarAtom;
+ data[i++] = d->winTypeMenuAtom;
+ data[i++] = d->winTypeSplashAtom;
+ data[i++] = d->winTypeDialogAtom;
+ data[i++] = d->winTypeUtilAtom;
+ data[i++] = d->winTypeNormalAtom;
+
+ data[i++] = d->wmDeleteWindowAtom;
+ data[i++] = d->wmPingAtom;
+
+ data[i++] = d->wmMoveResizeAtom;
+ data[i++] = d->moveResizeWindowAtom;
+
+ XChangeProperty (d->display, s->root, d->supportedAtom, XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) data, i);
+}
+
+static void
+setDesktopHints (CompScreen *s)
+{
+ CompDisplay *d = s->display;
+ unsigned long data[2];
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *propData;
+
+ result = XGetWindowProperty (s->display->display, s->root,
+ d->desktopViewportAtom, 0L, 2L, FALSE,
+ XA_CARDINAL, &actual, &format,
+ &n, &left, &propData);
+
+ if (result == Success && n && propData)
+ {
+ if (n == 2)
+ {
+ memcpy (data, propData, sizeof (unsigned long));
+
+ if (data[0] / s->width < s->size - 1)
+ s->x = data[0] / s->width;
+ }
+
+ XFree (propData);
+ }
+
+ data[0] = s->x * s->width;
+ data[1] = 0;
+
+ XChangeProperty (d->display, s->root, d->desktopViewportAtom,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) data, 2);
+
+ data[0] = s->width * s->size;
+ data[1] = s->height;
+
+ XChangeProperty (d->display, s->root, d->desktopGeometryAtom,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) data, 2);
+
+ data[0] = 1;
+
+ XChangeProperty (d->display, s->root, d->numberOfDesktopsAtom,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) data, 1);
+
+ data[0] = 0;
+
+ XChangeProperty (d->display, s->root, d->currentDesktopAtom,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) data, 1);
+
+ data[0] = 0;
+
+ result = XGetWindowProperty (s->display->display, s->root,
+ d->showingDesktopAtom, 0L, 1L, FALSE,
+ XA_CARDINAL, &actual, &format,
+ &n, &left, &propData);
+
+ if (result == Success && n && propData)
+ {
+ memcpy (data, propData, sizeof (unsigned long));
+ XFree (propData);
+
+ if (data[0])
+ enterShowDesktopMode (s);
+ }
+
+ XChangeProperty (d->display, s->root, d->showingDesktopAtom,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) data, 1);
+}
+
+Bool
+addScreen (CompDisplay *display,
+ int screenNum,
+ Window wmSnSelectionWindow,
+ Atom wmSnAtom,
+ Time wmSnTimestamp)
+{
+ CompScreen *s;
+ Display *dpy = display->display;
+ static char data = 0;
+ XColor black;
+ 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;
+ XSetWindowAttributes attrib;
+ CompWindow *w;
+
+ 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;
+
+ s->display = display;
+
+ compScreenInitOptions (s);
+
+ s->damage = XCreateRegion ();
+ if (!s->damage)
+ return FALSE;
+
+ s->x = 0;
+ s->size = 4;
+
+ 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->clientList = 0;
+ s->nClientList = 0;
+
+ s->screenNum = screenNum;
+ s->colormap = DefaultColormap (dpy, screenNum);
+ s->root = XRootWindow (dpy, screenNum);
+
+ s->mapNum = 1;
+ s->activeNum = 1;
+
+ s->groups = NULL;
+
+ s->snContext = sn_monitor_context_new (display->snDisplay,
+ screenNum,
+ compScreenSnEvent, s,
+ NULL);
+
+ s->startupSequences = NULL;
+ s->startupSequenceTimeoutHandle = 0;
+
+ s->wmSnSelectionWindow = wmSnSelectionWindow;
+ s->wmSnAtom = wmSnAtom;
+ s->wmSnTimestamp = wmSnTimestamp;
+
+ if (testMode)
+ {
+ 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 = "compiz";
+ classHint->res_class = "Compiz";
+
+ 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);
+
+ XSelectInput (dpy, s->root,
+ SubstructureNotifyMask |
+ ExposureMask |
+ ButtonPressMask |
+ ButtonReleaseMask |
+ ButtonMotionMask);
+
+ XRRSelectInput (dpy, s->root, RRScreenChangeNotifyMask);
+
+ XSetWMProtocols (dpy, s->root, &display->wmDeleteWindowAtom, 1);
+
+ XmbSetWMProperties (dpy, s->root,
+ "glxcompmgr - Test mode", "glxcompmgr",
+ programArgv, programArgc,
+ normalHints, wmHints, classHint);
+
+ XMapWindow (dpy, s->root);
+
+ XFree (wmHints);
+ XFree (classHint);
+ XFree (normalHints);
+ }
+
+ s->fake[0] = s->fake[1] = 0;
+
+ s->escapeKeyCode = XKeysymToKeycode (display->display,
+ XStringToKeysym ("Escape"));
+
+ s->damageMask = COMP_SCREEN_DAMAGE_ALL_MASK;
+ 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;
+ s->frameStatus = 0;
+
+ s->showingDesktopMask = 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->addWindowGeometry = addWindowGeometry;
+ s->drawWindowGeometry = drawWindowGeometry;
+ s->damageWindowRect = damageWindowRect;
+ s->focusWindow = focusWindow;
+ s->setWindowScale = setWindowScale;
+
+ s->windowResizeNotify = windowResizeNotify;
+ s->windowMoveNotify = windowMoveNotify;
+ s->windowGrabNotify = windowGrabNotify;
+ s->windowUngrabNotify = windowUngrabNotify;
+
+ s->getProcAddress = 0;
+
+ if (!XGetWindowAttributes (dpy, s->root, &s->attrib))
+ return FALSE;
+
+ s->workArea.x = 0;
+ s->workArea.y = 0;
+ s->workArea.width = s->attrib.width;
+ s->workArea.height = s->attrib.height;
+
+ s->grabWindow = 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;
+
+ black.red = black.green = black.blue = 0;
+
+ if (!XAllocColor (dpy, s->colormap, &black))
+ {
+ 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;
+ }
+
+ addScreenBinding (s, &s->opt[COMP_SCREEN_OPTION_CLOSE_WINDOW].value.bind);
+ addScreenBinding (s, &s->opt[COMP_SCREEN_OPTION_MAIN_MENU].value.bind);
+ addScreenBinding (s, &s->opt[COMP_SCREEN_OPTION_RUN_DIALOG].value.bind);
+
+ 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_EXT_texture_from_pixmap"))
+ {
+ fprintf (stderr, "%s: GLX_EXT_texture_from_pixmap is missing\n",
+ programName);
+ return FALSE;
+ }
+
+ s->getProcAddress = (GLXGetProcAddressProc)
+ getProcAddress (s, "glXGetProcAddressARB");
+ s->bindTexImage = (GLXBindTexImageProc)
+ getProcAddress (s, "glXBindTexImageEXT");
+ s->releaseTexImage = (GLXReleaseTexImageProc)
+ getProcAddress (s, "glXReleaseTexImageEXT");
+ s->queryDrawable = (GLXQueryDrawableProc)
+ getProcAddress (s, "glXQueryDrawable");
+
+ if (!testMode && !s->bindTexImage)
+ {
+ fprintf (stderr, "%s: glXBindTexImageEXT is missing\n", programName);
+ return FALSE;
+ }
+
+ if (!testMode && !s->releaseTexImage)
+ {
+ fprintf (stderr, "%s: glXReleaseTexImageEXT is missing\n",
+ programName);
+ return FALSE;
+ }
+
+ if (!testMode && !s->queryDrawable)
+ {
+ fprintf (stderr, "%s: glXQueryDrawable is missing\n", programName);
+ return FALSE;
+ }
+
+ s->textureRectangle = 0;
+ 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;
+
+ s->textureNonPowerOfTwo = 0;
+ 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;
+ }
+
+ s->textureEnvCombine = s->textureEnvCrossbar = 0;
+ if (strstr (glExtensions, "GL_ARB_texture_env_combine"))
+ {
+ s->textureEnvCombine = 1;
+
+ /* XXX: GL_NV_texture_env_combine4 need special code but it seams to
+ be working anyway for now... */
+ if (strstr (glExtensions, "GL_ARB_texture_env_crossbar") ||
+ strstr (glExtensions, "GL_NV_texture_env_combine4"))
+ s->textureEnvCrossbar = 1;
+ }
+
+ s->textureBorderClamp = 0;
+ if (strstr (glExtensions, "GL_ARB_texture_border_clamp") ||
+ strstr (glExtensions, "GL_SGIS_texture_border_clamp"))
+ s->textureBorderClamp = 1;
+
+ s->maxTextureUnits = 1;
+ if (strstr (glExtensions, "GL_ARB_multitexture"))
+ {
+ s->activeTexture = (GLActiveTextureProc)
+ getProcAddress (s, "glActiveTexture");
+ s->clientActiveTexture = (GLClientActiveTextureProc)
+ getProcAddress (s, "glClientActiveTexture");
+
+ if (s->activeTexture && s->clientActiveTexture)
+ glGetIntegerv (GL_MAX_TEXTURE_UNITS_ARB, &s->maxTextureUnits);
+ }
+
+ 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);
+ glColor4usv (defaultColor);
+ glEnableClientState (GL_VERTEX_ARRAY);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ s->canDoSaturated = s->canDoSlightlySaturated = FALSE;
+ if (s->textureEnvCombine && s->maxTextureUnits >= 2)
+ {
+ s->canDoSaturated = TRUE;
+ if (s->textureEnvCrossbar && s->maxTextureUnits >= 4)
+ s->canDoSlightlySaturated = TRUE;
+ }
+
+ s->redrawTime = 1000 / defaultRefreshRate;
+ s->optimalRedrawTime = s->redrawTime;
+
+ reshape (s, s->attrib.width, s->attrib.height);
+
+ s->next = display->screens;
+ display->screens = s;
+
+ screenInitPlugins (s);
+
+ detectRefreshRateOfScreen (s);
+
+ XGrabServer (dpy);
+
+ XQueryTree (dpy, s->root,
+ &rootReturn, &parentReturn,
+ &children, &nchildren);
+
+ for (i = 0; i < nchildren; i++)
+ addWindow (s, children[i], i ? children[i - 1] : 0);
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (w->attrib.map_state == IsViewable)
+ {
+ w->activeNum = s->activeNum++;
+ w->damaged = TRUE;
+ w->placed = TRUE;
+ w->invisible = WINDOW_INVISIBLE (w);
+ }
+ else if (w->state & CompWindowStateHiddenMask)
+ {
+ w->placed = TRUE;
+ }
+ }
+
+ XUngrabServer (dpy);
+
+ XFree (children);
+
+ attrib.override_redirect = 1;
+ s->grabWindow = XCreateWindow (dpy, s->root, -100, -100, 1, 1, 0,
+ CopyFromParent, InputOnly,
+ CopyFromParent, CWOverrideRedirect,
+ &attrib);
+
+ XMapWindow (dpy, s->grabWindow);
+
+ if (testMode)
+ {
+ s->fake[0] = XCreateWindow (dpy, s->root, 64, 32, 1, 1, 0,
+ CopyFromParent, InputOutput,
+ CopyFromParent, 0, NULL);
+
+ s->fake[1] = XCreateWindow (dpy, s->root, 256, 256, 1, 1, 0,
+ CopyFromParent, InputOutput,
+ CopyFromParent, 0, NULL);
+ }
+
+ setDesktopHints (s);
+ setSupportingWmCheck (s);
+ setSupported (s);
+
+ s->normalCursor = XCreateFontCursor (dpy, XC_left_ptr);
+ s->busyCursor = XCreateFontCursor (dpy, XC_watch);
+
+ XDefineCursor (dpy, s->root, s->normalCursor);
+
+ return TRUE;
+}
+
+void
+damageScreenRegion (CompScreen *screen,
+ Region region)
+{
+ if (screen->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
+ return;
+
+ XUnionRegion (screen->damage, region, screen->damage);
+
+ screen->damageMask |= COMP_SCREEN_DAMAGE_REGION_MASK;
+}
+
+void
+damageScreen (CompScreen *s)
+{
+ s->damageMask |= COMP_SCREEN_DAMAGE_ALL_MASK;
+ s->damageMask &= ~COMP_SCREEN_DAMAGE_REGION_MASK;
+}
+
+void
+damagePendingOnScreen (CompScreen *s)
+{
+ s->damageMask |= COMP_SCREEN_DAMAGE_PENDING_MASK;
+}
+
+void
+forEachWindowOnScreen (CompScreen *screen,
+ ForEachWindowProc proc,
+ void *closure)
+{
+ CompWindow *w;
+
+ for (w = screen->windows; w; w = w->next)
+ (*proc) (w, closure);
+}
+
+CompWindow *
+findWindowAtScreen (CompScreen *s,
+ Window id)
+{
+ if (lastFoundWindow && lastFoundWindow->id == id)
+ {
+ return lastFoundWindow;
+ }
+ else
+ {
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ if (w->id == id)
+ return (lastFoundWindow = w);
+ }
+
+ return 0;
+}
+
+CompWindow *
+findTopLevelWindowAtScreen (CompScreen *s,
+ Window id)
+{
+ CompWindow *found = NULL;
+
+ if (lastFoundWindow && lastFoundWindow->id == id)
+ {
+ found = lastFoundWindow;
+ }
+ else
+ {
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (w->id == id)
+ {
+ found = (lastFoundWindow = w);
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ return NULL;
+
+ if (found->attrib.override_redirect)
+ {
+ /* likely a frame window */
+ if (found->attrib.class == InputOnly)
+ {
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ if (w->frame == id)
+ return w;
+ }
+
+ return NULL;
+ }
+
+ return found;
+}
+
+void
+insertWindowIntoScreen (CompScreen *s,
+ CompWindow *w,
+ Window aboveId)
+{
+ CompWindow *p;
+
+ if (s->windows)
+ {
+ if (!aboveId)
+ {
+ w->next = s->windows;
+ w->prev = NULL;
+ s->windows->prev = w;
+ s->windows = w;
+ }
+ else
+ {
+ for (p = s->windows; p; p = p->next)
+ {
+ if (p->next)
+ {
+ if (p->id == aboveId && p->mapNum)
+ {
+ w->next = p->next;
+ w->prev = p;
+ p->next->prev = w;
+ p->next = w;
+
+ break;
+ }
+ }
+ else
+ {
+ p->next = w;
+ w->next = NULL;
+ w->prev = p;
+ s->reverseWindows = w;
+
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ s->reverseWindows = s->windows = w;
+ w->prev = w->next = NULL;
+ }
+}
+
+void
+unhookWindowFromScreen (CompScreen *s,
+ CompWindow *w)
+{
+ CompWindow *next, *prev;
+
+ next = w->next;
+ prev = w->prev;
+
+ if (next || prev)
+ {
+ if (next)
+ {
+ if (prev)
+ {
+ next->prev = prev;
+ }
+ else
+ {
+ s->windows = next;
+ next->prev = NULL;
+ }
+ }
+
+ if (prev)
+ {
+ if (next)
+ {
+ prev->next = next;
+ }
+ else
+ {
+ s->reverseWindows = prev;
+ prev->next = NULL;
+ }
+ }
+ }
+ else
+ {
+ s->windows = s->reverseWindows = NULL;
+ }
+
+ if (w == lastFoundWindow)
+ lastFoundWindow = NULL;
+ if (w == lastDamagedWindow)
+ lastDamagedWindow = NULL;
+}
+
+#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, ignore;
+ 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 (s->display->display);
+
+ for (ignore = 0; ignore <= s->display->ignoredModMask; ignore++)
+ {
+ if (ignore & ~s->display->ignoredModMask)
+ continue;
+
+ XGrabKey (s->display->display,
+ key->keycode,
+ mask | ignore,
+ s->root,
+ TRUE,
+ GrabModeAsync,
+ GrabModeAsync);
+ }
+
+ if (compCheckForError (s->display->display))
+ {
+
+#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, ignore;
+ 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))
+ {
+ for (ignore = 0; ignore <= s->display->ignoredModMask; ignore++)
+ {
+ if (ignore & ~s->display->ignoredModMask)
+ continue;
+
+ XUngrabKey (s->display->display,
+ key->keycode,
+ mask | ignore,
+ s->root);
+ }
+ }
+ }
+ }
+}
+
+static void
+updatePassiveKeyGrabs (CompScreen *s)
+{
+ unsigned int mask, ignore;
+ 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))
+ {
+ for (ignore = 0; ignore <= s->display->ignoredModMask; ignore++)
+ {
+ if (ignore & ~s->display->ignoredModMask)
+ continue;
+
+ XGrabKey (s->display->display,
+ s->keyGrab[i].keycode,
+ mask | ignore,
+ s->root,
+ TRUE,
+ GrabModeAsync,
+ GrabModeAsync);
+ }
+ }
+ }
+}
+
+static Bool
+addPassiveButtonGrab (CompScreen *s,
+ CompButtonBinding *button)
+{
+ CompButtonGrab *buttonGrab;
+ unsigned int modifiers;
+ 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;
+
+ 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;
+ 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);
+ }
+ }
+}
+
+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)
+{
+ updatePassiveKeyGrabs (s);
+}
+
+void
+updateWorkareaForScreen (CompScreen *s)
+{
+ CompWindow *w;
+ int leftStrut, rightStrut, topStrut, bottomStrut;
+ XRectangle workArea;
+
+ leftStrut = 0;
+ rightStrut = 0;
+ topStrut = 0;
+ bottomStrut = 0;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (w->attrib.map_state == IsUnmapped)
+ continue;
+
+ if (w->struts)
+ {
+ if (w->struts->left.width > leftStrut)
+ leftStrut = w->struts->left.width;
+
+ if (w->struts->right.width > rightStrut)
+ rightStrut = w->struts->right.width;
+
+ if (w->struts->top.height > topStrut)
+ topStrut = w->struts->top.height;
+
+ if (w->struts->bottom.height > bottomStrut)
+ bottomStrut = w->struts->bottom.height;
+ }
+ }
+
+#define MIN_SANE_AREA 100
+
+ if ((leftStrut + rightStrut) > (s->width - MIN_SANE_AREA))
+ {
+ leftStrut = (s->width - MIN_SANE_AREA) / 2;
+ rightStrut = leftStrut;
+ }
+
+ if ((topStrut + bottomStrut) > (s->height - MIN_SANE_AREA))
+ {
+ topStrut = (s->height - MIN_SANE_AREA) / 2;
+ bottomStrut = topStrut;
+ }
+
+ workArea.x = leftStrut;
+ workArea.y = topStrut;
+ workArea.width = s->width - leftStrut - rightStrut;
+ workArea.height = s->height - topStrut - bottomStrut;
+
+ if (memcmp (&workArea, &s->workArea, sizeof (XRectangle)))
+ {
+ unsigned long data[4];
+
+ data[0] = workArea.x;
+ data[1] = workArea.y;
+ data[2] = workArea.width;
+ data[3] = workArea.height;
+
+ XChangeProperty (s->display->display, s->root,
+ s->display->workareaAtom, XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *) data, 4);
+
+ s->workArea = workArea;
+ }
+}
+
+static Bool
+isClientListWindow (CompWindow *w)
+{
+ if (w->attrib.override_redirect)
+ return FALSE;
+
+ if (w->attrib.map_state != IsViewable)
+ {
+ if (!(w->state & CompWindowStateHiddenMask))
+ return FALSE;
+ }
+
+ if (w->type & CompWindowTypeNormalMask)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+countClientListWindow (CompWindow *w,
+ void *closure)
+{
+ if (isClientListWindow (w))
+ {
+ int *num = (int *) closure;
+
+ *num = *num + 1;
+ }
+}
+
+static void
+addClientListWindow (CompWindow *w,
+ void *closure)
+{
+ if (isClientListWindow (w))
+ {
+ int *num = (int *) closure;
+
+ w->screen->clientList[*num] = w;
+ *num = *num + 1;
+ }
+}
+
+static int
+compareMappingOrder (const void *w1,
+ const void *w2)
+{
+ return (*((CompWindow **) w1))->mapNum - (*((CompWindow **) w2))->mapNum;
+}
+
+void
+updateClientListForScreen (CompScreen *s)
+{
+ Window *clientList;
+ Window *clientListStacking;
+ Bool updateClientList = FALSE;
+ Bool updateClientListStacking = FALSE;
+ int i, n = 0;
+
+ forEachWindowOnScreen (s, countClientListWindow, (void *) &n);
+
+ if (n == 0)
+ {
+ if (n != s->nClientList)
+ {
+ free (s->clientList);
+
+ s->clientList = NULL;
+ s->nClientList = 0;
+
+ XChangeProperty (s->display->display, s->root,
+ s->display->clientListAtom,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &s->grabWindow, 1);
+ XChangeProperty (s->display->display, s->root,
+ s->display->clientListStackingAtom,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &s->grabWindow, 1);
+ }
+
+ return;
+ }
+
+ if (n != s->nClientList)
+ {
+ CompWindow **list;
+
+ list = realloc (s->clientList,
+ (sizeof (CompWindow *) + sizeof (Window) * 2) * n);
+ if (!list)
+ return;
+
+ s->clientList = list;
+ s->nClientList = n;
+
+ updateClientList = updateClientListStacking = TRUE;
+ }
+
+ clientList = (Window *) (s->clientList + n);
+ clientListStacking = clientList + n;
+
+ i = 0;
+ forEachWindowOnScreen (s, addClientListWindow, (void *) &i);
+
+ for (i = 0; i < n; i++)
+ {
+ if (!updateClientListStacking)
+ {
+ if (clientListStacking[i] != s->clientList[i]->id)
+ updateClientListStacking = TRUE;
+ }
+
+ clientListStacking[i] = s->clientList[i]->id;
+ }
+
+ /* sort window list in mapping order */
+ qsort (s->clientList, n, sizeof (CompWindow *), compareMappingOrder);
+
+ for (i = 0; i < n; i++)
+ {
+ if (!updateClientList)
+ {
+ if (clientList[i] != s->clientList[i]->id)
+ updateClientList = TRUE;
+ }
+
+ clientList[i] = s->clientList[i]->id;
+ }
+
+ if (updateClientList)
+ XChangeProperty (s->display->display, s->root,
+ s->display->clientListAtom,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) clientList, s->nClientList);
+
+ if (updateClientListStacking)
+ XChangeProperty (s->display->display, s->root,
+ s->display->clientListStackingAtom,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) clientListStacking, s->nClientList);
+}
+
+Window
+getActiveWindow (CompDisplay *display,
+ Window root)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+ Window w = None;
+
+ result = XGetWindowProperty (display->display, root,
+ display->winActiveAtom, 0L, 1L, FALSE,
+ XA_WINDOW, &actual, &format,
+ &n, &left, &data);
+
+ if (result == Success && n && data)
+ {
+ memcpy (&w, data, sizeof (Window));
+ XFree (data);
+ }
+
+ return w;
+}
+
+void
+closeActiveWindow (CompScreen *s)
+{
+ CompWindow *w;
+
+ w = findWindowAtDisplay (s->display, s->display->activeWindow);
+ if (w)
+ closeWindow (w);
+}
+
+void
+panelAction (CompScreen *s,
+ Atom panelAction)
+{
+ XEvent ev;
+
+ ev.type = ClientMessage;
+ ev.xclient.window = s->root;
+ ev.xclient.message_type = s->display->panelActionAtom;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = panelAction;
+ ev.xclient.data.l[1] = CurrentTime;
+ ev.xclient.data.l[2] = 0;
+ ev.xclient.data.l[3] = 0;
+ ev.xclient.data.l[4] = 0;
+
+ XUngrabPointer (s->display->display, CurrentTime);
+ XUngrabKeyboard (s->display->display, CurrentTime);
+
+ XSendEvent (s->display->display, s->root, FALSE, StructureNotifyMask, &ev);
+}
+
+void
+runCommand (CompScreen *s,
+ const char *command)
+{
+ if (*command == '\0')
+ return;
+
+ if (fork () == 0)
+ {
+ setsid ();
+ putenv (s->display->displayString);
+ execl ("/bin/sh", "/bin/sh", "-c", command, NULL);
+ exit (0);
+ }
+}
+
+void
+moveScreenViewport (CompScreen *s,
+ int tx,
+ Bool sync)
+{
+ tx = s->x - tx;
+ tx = MOD (tx, s->size);
+ tx -= s->x;
+
+ if (tx)
+ {
+ CompWindow *w;
+ int m, wx, vWidth = s->width * s->size;
+
+ s->x += tx;
+
+ tx *= -s->width;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (w->attrib.map_state != IsViewable)
+ continue;
+
+ if (w->attrib.override_redirect)
+ continue;
+
+ if (w->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
+ continue;
+
+ if (w->state & CompWindowStateStickyMask)
+ continue;
+
+ m = w->attrib.x + tx;
+ if (m - w->output.left < s->width - vWidth)
+ wx = tx + vWidth;
+ else if (m + w->width + w->output.right > vWidth)
+ wx = tx - vWidth;
+ else
+ wx = tx;
+
+ if (w->saveMask & CWX)
+ w->saveWc.x += wx;
+
+ moveWindow (w, wx, 0, sync);
+
+ if (sync)
+ syncWindowPosition (w);
+ }
+
+ if (sync)
+ {
+ unsigned long data[2];
+
+ data[0] = s->x * s->width;
+ data[1] = 0;
+
+ XChangeProperty (s->display->display, s->root,
+ s->display->desktopViewportAtom,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) data, 2);
+ }
+ }
+}
+
+void
+moveWindowToViewportPosition (CompWindow *w,
+ int x,
+ Bool sync)
+{
+ int tx, vWidth = w->screen->width * w->screen->size;
+
+ x += w->screen->x * w->screen->width;
+ x = MOD (x, vWidth);
+ x -= w->screen->x * w->screen->width;
+
+ tx = x - w->attrib.x;
+ if (tx)
+ {
+ int m, wx;
+
+ if (w->attrib.map_state != IsViewable)
+ return;
+
+ if (w->attrib.override_redirect)
+ return;
+
+ if (w->type & (CompWindowTypeDesktopMask | CompWindowTypeDockMask))
+ return;
+
+ if (w->state & CompWindowStateStickyMask)
+ return;
+
+ m = w->attrib.x + tx;
+ if (m - w->output.left < w->screen->width - vWidth)
+ wx = tx + vWidth;
+ else if (m + w->width + w->output.right > vWidth)
+ wx = tx - vWidth;
+ else
+ wx = tx;
+
+ if (w->saveMask & CWX)
+ w->saveWc.x += wx;
+
+ moveWindow (w, wx, 0, sync);
+
+ if (sync)
+ syncWindowPosition (w);
+ }
+}
+
+CompGroup *
+addGroupToScreen (CompScreen *s,
+ Window id)
+{
+ CompGroup *group;
+
+ group = malloc (sizeof (CompGroup));
+ if (!group)
+ return NULL;
+
+ group->next = s->groups;
+ group->refCnt = 1;
+ group->id = id;
+
+ s->groups = group;
+
+ return group;
+}
+
+void
+removeGroupFromScreen (CompScreen *s,
+ CompGroup *group)
+{
+ group->refCnt--;
+ if (group->refCnt)
+ return;
+
+ if (group == s->groups)
+ {
+ s->groups = group->next;
+ }
+ else
+ {
+ CompGroup *g;
+
+ for (g = s->groups; g; g = g->next)
+ {
+ if (g->next == group)
+ {
+ g->next = group->next;
+ break;
+ }
+ }
+ }
+
+ free (group);
+}
+
+CompGroup *
+findGroupAtScreen (CompScreen *s,
+ Window id)
+{
+ CompGroup *g;
+
+ for (g = s->groups; g; g = g->next)
+ if (g->id == id)
+ return g;
+
+ return NULL;
+}
+
+void
+applyStartupProperties (CompScreen *screen,
+ CompWindow *window)
+{
+ CompStartupSequence *s = NULL;
+ const char *startupId = window->startupId;
+
+ printf ("Applying startup props to %d id \"%s\"\n",
+ (int) window->id, window->startupId ? window->startupId : "(none)");
+
+ if (!startupId)
+ {
+ const char *wmClass;
+
+ for (s = screen->startupSequences; s; s = s->next)
+ {
+ wmClass = sn_startup_sequence_get_wmclass (s->sequence);
+ if (!wmClass)
+ continue;
+
+ if ((window->resClass && strcmp (wmClass, window->resClass) == 0) ||
+ (window->resName && strcmp (wmClass, window->resName) == 0))
+ {
+ startupId = sn_startup_sequence_get_id (s->sequence);
+
+ window->startupId = strdup (startupId);
+
+ printf ("Ending legacy sequence %s due to window %d\n",
+ startupId, (int) window->id);
+
+ sn_startup_sequence_complete (s->sequence);
+ break;
+ }
+ }
+
+ if (!startupId)
+ return;
+ }
+
+ if (!s)
+ {
+ const char *id;
+
+ for (s = screen->startupSequences; s; s = s->next)
+ {
+ id = sn_startup_sequence_get_id (s->sequence);
+
+ if (strcmp (id, startupId) == 0)
+ break;
+ }
+ }
+
+ if (s)
+ {
+ printf ("Found startup sequence for window %d ID \"%s\"\n",
+ (int) window->id, startupId);
+ }
+ else
+ {
+ printf ("Did not find startup sequence for window %d ID \"%s\"\n",
+ (int) window->id, startupId);
+ }
+}
+
+void
+enterShowDesktopMode (CompScreen *s)
+{
+ CompWindow *w;
+ unsigned long data = 1;
+
+ s->showingDesktopMask = ~(CompWindowTypeDesktopMask |
+ CompWindowTypeDockMask);
+
+ for (w = s->windows; w; w = w->next)
+ hideWindow (w);
+
+ XChangeProperty (s->display->display, s->root,
+ s->display->showingDesktopAtom,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) &data, 1);
+}
+
+void
+leaveShowDesktopMode (CompScreen *s)
+{
+ CompWindow *w;
+ unsigned long data = 0;
+
+ s->showingDesktopMask = 0;
+
+ for (w = s->windows; w; w = w->next)
+ showWindow (w);
+
+ XChangeProperty (s->display->display, s->root,
+ s->display->showingDesktopAtom,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) &data, 1);
+}
+
+void
+sendWindowActivationRequest (CompScreen *s,
+ Window id)
+{
+ XEvent xev;
+
+ xev.xclient.type = ClientMessage;
+ xev.xclient.display = s->display->display;
+ xev.xclient.format = 32;
+
+ xev.xclient.message_type = s->display->winActiveAtom;
+ xev.xclient.window = id;
+
+ xev.xclient.data.l[0] = 2;
+ xev.xclient.data.l[1] = 0;
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+
+ XSendEvent (s->display->display,
+ s->root,
+ FALSE,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &xev);
+}
diff --git a/src/texture.c b/src/texture.c
new file mode 100644
index 00000000..02e680a2
--- /dev/null
+++ b/src/texture.c
@@ -0,0 +1,337 @@
+/*
+ * 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 <compiz.h>
+
+static CompMatrix _identity_matrix = {
+ 1.0f, 0.0f,
+ 0.0f, 1.0f,
+ 0.0f, 0.0f
+};
+
+void
+initTexture (CompScreen *screen,
+ CompTexture *texture)
+{
+ texture->name = 0;
+ texture->target = GL_TEXTURE_2D;
+ texture->pixmap = None;
+ texture->filter = COMP_TEXTURE_FILTER_FAST;
+ texture->wrap = GL_CLAMP_TO_EDGE;
+ texture->matrix = _identity_matrix;
+}
+
+void
+finiTexture (CompScreen *screen,
+ CompTexture *texture)
+{
+ if (texture->name)
+ {
+ releasePixmapFromTexture (screen, texture);
+ glDeleteTextures (1, &texture->name);
+ }
+}
+
+static Bool
+imageToTexture (CompScreen *screen,
+ CompTexture *texture,
+ char *image,
+ unsigned int width,
+ unsigned int height)
+{
+ char *data;
+ int i;
+
+ data = malloc (4 * width * height);
+ if (!data)
+ return FALSE;
+
+ for (i = 0; i < height; i++)
+ memcpy (&data[i * width * 4],
+ &image[(height - i - 1) * width * 4],
+ width * 4);
+
+ releasePixmapFromTexture (screen, texture);
+
+ if (screen->textureNonPowerOfTwo ||
+ (POWER_OF_TWO (width) && POWER_OF_TWO (height)))
+ {
+ texture->target = GL_TEXTURE_2D;
+ texture->matrix.xx = 1.0f / width;
+ texture->matrix.yy = -1.0f / height;
+ texture->matrix.y0 = 1.0f;
+ }
+ else
+ {
+ texture->target = GL_TEXTURE_RECTANGLE_NV;
+ texture->matrix.xx = 1.0f;
+ texture->matrix.yy = -1.0f;
+ texture->matrix.y0 = height;
+ }
+
+ if (!texture->name)
+ glGenTextures (1, &texture->name);
+
+ glBindTexture (texture->target, texture->name);
+
+ glTexImage2D (texture->target, 0, GL_RGBA, 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);
+
+ texture->wrap = GL_CLAMP_TO_EDGE;
+
+ glBindTexture (texture->target, 0);
+
+ free (data);
+
+ return TRUE;
+}
+
+Bool
+readImageToTexture (CompScreen *screen,
+ CompTexture *texture,
+ char *imageFileName,
+ unsigned int *returnWidth,
+ unsigned int *returnHeight)
+{
+ char *image;
+ unsigned int width, height;
+ Bool status;
+
+ if (!readPng (imageFileName, &image, &width, &height))
+ {
+ fprintf (stderr, "%s: Failed to load image: %s\n",
+ programName, imageFileName);
+ return FALSE;
+ }
+
+ status = imageToTexture (screen, texture, image, width, height);
+
+ free (image);
+
+ *returnWidth = width;
+ *returnHeight = height;
+
+ return status;
+}
+
+Bool
+readImageBufferToTexture (CompScreen *screen,
+ CompTexture *texture,
+ const unsigned char *imageBuffer,
+ unsigned int *returnWidth,
+ unsigned int *returnHeight)
+{
+ char *image;
+ unsigned int width, height;
+ Bool status;
+
+ if (!readPngBuffer (imageBuffer, &image, &width, &height))
+ {
+ fprintf (stderr, "%s: Failed to load image buffer\n", programName);
+ return FALSE;
+ }
+
+ status = imageToTexture (screen, texture, image, width, height);
+
+ free (image);
+
+ *returnWidth = width;
+ *returnHeight = height;
+
+ return status;
+}
+
+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;
+ }
+
+ screen->queryDrawable (screen->display->display,
+ texture->pixmap,
+ GLX_TEXTURE_TARGET_EXT,
+ &target);
+ switch (target) {
+ case GLX_TEXTURE_2D_EXT:
+ texture->target = GL_TEXTURE_2D;
+ texture->matrix.xx = 1.0f / width;
+ texture->matrix.yy = -1.0f / height;
+ texture->matrix.y0 = 1.0f;
+ break;
+ case GLX_TEXTURE_RECTANGLE_EXT:
+ texture->target = GL_TEXTURE_RECTANGLE_ARB;
+ texture->matrix.xx = 1.0f;
+ texture->matrix.yy = -1.0f;
+ texture->matrix.y0 = height;
+ break;
+ case GLX_NO_TEXTURE_EXT:
+ fprintf (stderr, "%s: pixmap 0x%x can't be bound to texture\n",
+ programName, (int) pixmap);
+
+ /* fall-through */
+ default:
+ 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);
+
+ texture->wrap = GL_CLAMP_TO_EDGE;
+
+ glBindTexture (texture->target, 0);
+
+ return TRUE;
+}
+
+void
+releasePixmapFromTexture (CompScreen *screen,
+ CompTexture *texture)
+{
+ if (texture->pixmap)
+ {
+ if (!testMode)
+ {
+ 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 00000000..fc19390d
--- /dev/null
+++ b/src/window.c
@@ -0,0 +1,2903 @@
+/*
+ * 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/Xproto.h>
+#include <X11/extensions/shape.h>
+#include <X11/extensions/Xcomposite.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <compiz.h>
+
+#define MwmHintsDecorations (1L << 1)
+
+#define PropMotifWmHintElements 3
+
+typedef struct {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+} MwmHints;
+
+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 void
+recalcNormalHints (CompWindow *window)
+{
+ window->sizeHints.x = window->attrib.x;
+ window->sizeHints.y = window->attrib.y;
+ window->sizeHints.width = window->attrib.width;
+ window->sizeHints.height = window->attrib.height;
+
+ if (window->sizeHints.flags & PMinSize)
+ {
+ window->sizeHints.base_width = window->sizeHints.min_width;
+ window->sizeHints.base_height = window->sizeHints.min_height;
+ }
+ else
+ {
+ window->sizeHints.base_width = 0;
+ window->sizeHints.base_height = 0;
+ }
+
+ window->sizeHints.flags |= PBaseSize;
+
+ if (window->sizeHints.flags & PBaseSize)
+ {
+ window->sizeHints.min_width = window->sizeHints.base_width;
+ window->sizeHints.min_height = window->sizeHints.base_height;
+ }
+ else
+ {
+ window->sizeHints.min_width = 0;
+ window->sizeHints.min_height = 0;
+ }
+ window->sizeHints.flags |= PMinSize;
+
+ if (!(window->sizeHints.flags & PMaxSize))
+ {
+ window->sizeHints.max_width = 65535;
+ window->sizeHints.max_height = 65535;
+ window->sizeHints.flags |= PMaxSize;
+ }
+
+ if (window->sizeHints.max_width < window->sizeHints.min_width)
+ window->sizeHints.max_width = window->sizeHints.min_width;
+
+ if (window->sizeHints.max_height < window->sizeHints.min_height)
+ window->sizeHints.max_height = window->sizeHints.min_height;
+
+ if (window->sizeHints.min_width < 1)
+ window->sizeHints.min_width = 1;
+
+ if (window->sizeHints.max_width < 1)
+ window->sizeHints.max_width = 1;
+
+ if (window->sizeHints.min_height < 1)
+ window->sizeHints.min_height = 1;
+
+ if (window->sizeHints.max_height < 1)
+ window->sizeHints.max_height = 1;
+
+ if (window->sizeHints.flags & PResizeInc)
+ {
+ if (window->sizeHints.width_inc == 0)
+ window->sizeHints.width_inc = 1;
+
+ if (window->sizeHints.height_inc == 0)
+ window->sizeHints.height_inc = 1;
+ }
+ else
+ {
+ window->sizeHints.width_inc = 1;
+ window->sizeHints.height_inc = 1;
+ window->sizeHints.flags |= PResizeInc;
+ }
+
+ if (window->sizeHints.flags & PAspect)
+ {
+ /* don't divide by 0 */
+ if (window->sizeHints.min_aspect.y < 1)
+ window->sizeHints.min_aspect.y = 1;
+
+ if (window->sizeHints.max_aspect.y < 1)
+ window->sizeHints.max_aspect.y = 1;
+ }
+ else
+ {
+ window->sizeHints.min_aspect.x = 1;
+ window->sizeHints.min_aspect.y = 65535;
+ window->sizeHints.max_aspect.x = 65535;
+ window->sizeHints.max_aspect.y = 1;
+ window->sizeHints.flags |= PAspect;
+ }
+
+ if (!(window->sizeHints.flags & PWinGravity))
+ {
+ window->sizeHints.win_gravity = NorthWestGravity;
+ window->sizeHints.flags |= PWinGravity;
+ }
+}
+
+void
+updateNormalHints (CompWindow *w)
+{
+ Status status;
+ long supplied;
+
+ status = XGetWMNormalHints (w->screen->display->display, w->id,
+ &w->sizeHints, &supplied);
+
+ if (!status)
+ w->sizeHints.flags = 0;
+
+ recalcNormalHints (w);
+}
+
+void
+updateWmHints (CompWindow *w)
+{
+ XWMHints *hints;
+
+ hints = XGetWMHints (w->screen->display->display, w->id);
+ if (hints)
+ {
+ if (hints->flags & InputHint)
+ w->inputHint = hints->input;
+
+ XFree (hints);
+ }
+}
+
+void
+updateWindowClassHints (CompWindow *w)
+{
+ XClassHint classHint;
+ int status;
+
+ status = XGetClassHint (w->screen->display->display, w->id, &classHint);
+
+ if (status)
+ {
+ if (classHint.res_name)
+ {
+ if (w->resName)
+ free (w->resName);
+
+ w->resName = strdup (classHint.res_name);
+ XFree (classHint.res_name);
+ }
+
+ if (classHint.res_class)
+ {
+ if (w->resClass)
+ free (w->resClass);
+
+ w->resClass = strdup (classHint.res_class);
+ XFree (classHint.res_class);
+ }
+ }
+}
+
+static Window
+getClientLeaderOfAncestor (CompWindow *w)
+{
+ if (w->transientFor)
+ {
+ w = findWindowAtScreen (w->screen, w->transientFor);
+ if (w)
+ {
+ if (w->clientLeader)
+ return w->clientLeader;
+
+ return getClientLeaderOfAncestor (w);
+ }
+ }
+
+ return None;
+}
+
+Window
+getClientLeader (CompWindow *w)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+
+ result = XGetWindowProperty (w->screen->display->display, w->id,
+ w->screen->display->wmClientLeaderAtom,
+ 0L, 1L, False, XA_WINDOW, &actual, &format,
+ &n, &left, &data);
+
+ if (result == Success && n && data)
+ {
+ Window win;
+
+ memcpy (&win, data, sizeof (Window));
+ XFree ((void *) data);
+
+ if (win)
+ return win;
+ }
+
+ return getClientLeaderOfAncestor (w);
+}
+
+int
+getWmState (CompDisplay *display,
+ Window id)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+ unsigned long state = NormalState;
+
+ result = XGetWindowProperty (display->display, id,
+ display->wmStateAtom, 0L, 2L, FALSE,
+ display->wmStateAtom, &actual, &format,
+ &n, &left, &data);
+
+ if (result == Success && n && data)
+ {
+ memcpy (&state, data, sizeof (unsigned long));
+ XFree ((void *) data);
+ }
+
+ return state;
+}
+
+void
+setWmState (CompDisplay *display,
+ int state,
+ Window id)
+{
+ unsigned long data[2];
+
+ data[0] = state;
+ data[1] = None;
+
+ XChangeProperty (display->display, id,
+ display->wmStateAtom, display->wmStateAtom,
+ 32, PropModeReplace, (unsigned char *) data, 2);
+}
+
+unsigned int
+windowStateMask (CompDisplay *display,
+ Atom state)
+{
+ if (state == display->winStateModalAtom)
+ return CompWindowStateModalMask;
+ else if (state == display->winStateStickyAtom)
+ return CompWindowStateStickyMask;
+ else if (state == display->winStateMaximizedVertAtom)
+ return CompWindowStateMaximizedVertMask;
+ else if (state == display->winStateMaximizedHorzAtom)
+ return CompWindowStateMaximizedHorzMask;
+ else if (state == display->winStateShadedAtom)
+ return CompWindowStateShadedMask;
+ else if (state == display->winStateSkipTaskbarAtom)
+ return CompWindowStateSkipTaskbarMask;
+ else if (state == display->winStateSkipPagerAtom)
+ return CompWindowStateSkipPagerMask;
+ else if (state == display->winStateHiddenAtom)
+ return CompWindowStateHiddenMask;
+ else if (state == display->winStateFullscreenAtom)
+ return CompWindowStateFullscreenMask;
+ else if (state == display->winStateAboveAtom)
+ return CompWindowStateAboveMask;
+ else if (state == display->winStateBelowAtom)
+ return CompWindowStateBelowMask;
+ else if (state == display->winStateDemandsAttentionAtom)
+ return CompWindowStateDemandsAttentationMask;
+ else if (state == display->winStateDisplayModalAtom)
+ return CompWindowStateDisplayModalMask;
+
+ return 0;
+}
+
+unsigned int
+getWindowState (CompDisplay *display,
+ Window id)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+ unsigned int state = 0;
+
+ result = XGetWindowProperty (display->display, id, display->winStateAtom,
+ 0L, 1024L, FALSE, XA_ATOM, &actual, &format,
+ &n, &left, &data);
+
+ if (result == Success && n && data)
+ {
+ Atom *a = (Atom *) data;
+
+ while (n--)
+ state |= windowStateMask (display, *a++);
+
+ XFree ((void *) data);
+ }
+
+ return state;
+}
+
+void
+setWindowState (CompDisplay *display,
+ unsigned int state,
+ Window id)
+{
+ Atom data[32];
+ int i = 0;
+
+ if (state & CompWindowStateModalMask)
+ data[i++] = display->winStateModalAtom;
+ if (state & CompWindowStateStickyMask)
+ data[i++] = display->winStateStickyAtom;
+ if (state & CompWindowStateMaximizedVertMask)
+ data[i++] = display->winStateMaximizedVertAtom;
+ if (state & CompWindowStateMaximizedHorzMask)
+ data[i++] = display->winStateMaximizedHorzAtom;
+ if (state & CompWindowStateShadedMask)
+ data[i++] = display->winStateShadedAtom;
+ if (state & CompWindowStateSkipTaskbarMask)
+ data[i++] = display->winStateSkipTaskbarAtom;
+ if (state & CompWindowStateSkipPagerMask)
+ data[i++] = display->winStateSkipPagerAtom;
+ if (state & CompWindowStateHiddenMask)
+ data[i++] = display->winStateHiddenAtom;
+ if (state & CompWindowStateFullscreenMask)
+ data[i++] = display->winStateFullscreenAtom;
+ if (state & CompWindowStateAboveMask)
+ data[i++] = display->winStateAboveAtom;
+ if (state & CompWindowStateBelowMask)
+ data[i++] = display->winStateBelowAtom;
+ if (state & CompWindowStateDemandsAttentationMask)
+ data[i++] = display->winStateDemandsAttentionAtom;
+ if (state & CompWindowStateDisplayModalMask)
+ data[i++] = display->winStateDisplayModalAtom;
+
+ XChangeProperty (display->display, id, display->winStateAtom,
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *) data, i);
+}
+
+static void
+setWindowActions (CompDisplay *display,
+ unsigned int actions,
+ Window id)
+{
+ Atom data[32];
+ int i = 0;
+
+ if (actions & CompWindowActionMoveMask)
+ data[i++] = display->winActionMoveAtom;
+ if (actions & CompWindowActionResizeMask)
+ data[i++] = display->winActionResizeAtom;
+ if (actions & CompWindowActionStickMask)
+ data[i++] = display->winActionStickAtom;
+ if (actions & CompWindowActionMinimizeMask)
+ data[i++] = display->winActionMinimizeAtom;
+ if (actions & CompWindowActionMaximizeHorzMask)
+ data[i++] = display->winActionMaximizeHorzAtom;
+ if (actions & CompWindowActionMaximizeVertMask)
+ data[i++] = display->winActionMaximizeVertAtom;
+ if (actions & CompWindowActionFullscreenMask)
+ data[i++] = display->winActionFullscreenAtom;
+ if (actions & CompWindowActionCloseMask)
+ data[i++] = display->winActionCloseAtom;
+
+ XChangeProperty (display->display, id, display->wmAllowedActionsAtom,
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *) data, i);
+}
+
+static void
+recalcWindowActions (CompWindow *w)
+{
+ unsigned int actions = 0;
+
+ switch (w->type) {
+ case CompWindowTypeFullscreenMask:
+ case CompWindowTypeNormalMask:
+ actions |=
+ CompWindowActionMinimizeMask |
+ CompWindowActionMaximizeHorzMask |
+ CompWindowActionMaximizeVertMask |
+ CompWindowActionFullscreenMask;
+ /* fall-through */
+ case CompWindowTypeDialogMask:
+ case CompWindowTypeModalDialogMask:
+ actions |=
+ CompWindowActionMoveMask |
+ CompWindowActionResizeMask |
+ CompWindowActionStickMask |
+ CompWindowActionCloseMask;
+ break;
+ case CompWindowTypeUtilMask:
+ case CompWindowTypeToolbarMask:
+ case CompWindowTypeMenuMask:
+ case CompWindowTypeSplashMask:
+ case CompWindowTypeDesktopMask:
+ case CompWindowTypeDockMask:
+ case CompWindowTypeUnknownMask:
+ default:
+ break;
+ }
+
+ if (actions != w->actions)
+ {
+ w->actions = actions;
+ setWindowActions (w->screen->display, actions, w->id);
+ }
+}
+
+unsigned int
+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);
+
+ if (a == display->winTypeNormalAtom)
+ return CompWindowTypeNormalMask;
+ else if (a == display->winTypeMenuAtom)
+ return CompWindowTypeMenuMask;
+ else if (a == display->winTypeDesktopAtom)
+ return CompWindowTypeDesktopMask;
+ else if (a == display->winTypeDockAtom)
+ return CompWindowTypeDockMask;
+ else if (a == display->winTypeToolbarAtom)
+ return CompWindowTypeToolbarMask;
+ else if (a == display->winTypeUtilAtom)
+ return CompWindowTypeUtilMask;
+ else if (a == display->winTypeSplashAtom)
+ return CompWindowTypeSplashMask;
+ else if (a == display->winTypeDialogAtom)
+ return CompWindowTypeDialogMask;
+ }
+
+ return CompWindowTypeUnknownMask;
+}
+
+void
+recalcWindowType (CompWindow *w)
+{
+ unsigned int type;
+
+ type = w->wmType;
+
+ if (!w->attrib.override_redirect && w->wmType == CompWindowTypeUnknownMask)
+ type = CompWindowTypeNormalMask;
+
+ if (w->state & CompWindowStateFullscreenMask)
+ type = CompWindowTypeFullscreenMask;
+
+ if (type == CompWindowTypeNormalMask)
+ {
+ if (w->transientFor)
+ type = CompWindowTypeDialogMask;
+ }
+
+ if ((type & (CompWindowTypeNormalMask | CompWindowTypeDialogMask)) &&
+ (w->state & CompWindowStateModalMask))
+ type = CompWindowTypeModalDialogMask;
+
+ if (type != w->type)
+ {
+ w->type = type;
+ recalcWindowActions (w);
+ }
+}
+
+unsigned int
+getMwmDecor (CompDisplay *display,
+ Window id)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ MwmHints *mwmHints;
+ unsigned int decor = MwmDecorAll;
+
+ result = XGetWindowProperty (display->display, id, display->mwmHintsAtom,
+ 0L, 20L, FALSE, display->mwmHintsAtom,
+ &actual, &format, &n, &left,
+ (unsigned char **) &mwmHints);
+
+ if (result == Success && n && mwmHints)
+ {
+ if (n >= PropMotifWmHintElements)
+ {
+ if (mwmHints->flags & MwmHintsDecorations)
+ decor = mwmHints->decorations;
+ }
+
+ XFree (mwmHints);
+ }
+
+ return decor;
+}
+
+unsigned int
+getProtocols (CompDisplay *display,
+ Window id)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ Atom *protocol;
+ unsigned int protocols = 0;
+
+ result = XGetWindowProperty (display->display, id, display->wmProtocolsAtom,
+ 0L, 20L, FALSE, XA_ATOM,
+ &actual, &format, &n, &left,
+ (unsigned char **) &protocol);
+
+ if (result == Success && n && protocol)
+ {
+ int i;
+
+ for (i = 0; i < n; i++)
+ {
+ if (protocol[i] == display->wmDeleteWindowAtom)
+ protocols |= CompWindowProtocolDeleteMask;
+ else if (protocol[i] == display->wmTakeFocusAtom)
+ protocols |= CompWindowProtocolTakeFocusMask;
+ else if (protocol[i] == display->wmPingAtom)
+ protocols |= CompWindowProtocolPingMask;
+ else if (protocol[i] == display->wmSyncRequestAtom)
+ protocols |= CompWindowProtocolSyncRequestMask;
+ }
+
+ XFree (protocol);
+ }
+
+ return protocols;
+}
+
+unsigned short
+getWindowProp32 (CompDisplay *display,
+ Window id,
+ Atom property,
+ unsigned short defaultValue)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+
+ result = XGetWindowProperty (display->display, id, property,
+ 0L, 1L, FALSE, XA_CARDINAL, &actual, &format,
+ &n, &left, &data);
+
+ if (result == Success && n && data)
+ {
+ CARD32 value;
+
+ memcpy (&value, data, sizeof (CARD32));
+
+ XFree (data);
+
+ return value >> 16;
+ }
+
+ return defaultValue;
+}
+
+void
+setWindowProp32 (CompDisplay *display,
+ Window id,
+ Atom property,
+ unsigned short value)
+{
+ CARD32 value32;
+
+ value32 = value << 16 | value;
+
+ XChangeProperty (display->display, id, property,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) &value32, 1);
+}
+
+
+static void
+updateFrameWindow (CompWindow *w)
+{
+ if (w->input.left || w->input.right || w->input.top || w->input.bottom)
+ {
+ XRectangle rects[4];
+ int x, y, width, height;
+
+ x = w->serverX - w->input.left;
+ y = w->serverY - w->input.top;
+ width = w->width + w->input.left + w->input.right;
+ height = w->height + w->input.top + w->input.bottom;
+
+ if (!w->frame)
+ {
+ XSetWindowAttributes attr;
+ XWindowChanges xwc;
+
+ attr.event_mask = 0;
+ attr.override_redirect = TRUE;
+
+ w->frame = XCreateWindow (w->screen->display->display,
+ w->screen->root,
+ x, y, width, height, 0,
+ CopyFromParent,
+ InputOnly,
+ CopyFromParent,
+ CWOverrideRedirect | CWEventMask, &attr);
+
+ XGrabButton (w->screen->display->display, AnyButton,
+ AnyModifier, w->frame, TRUE, ButtonPressMask |
+ ButtonReleaseMask | ButtonMotionMask,
+ GrabModeSync, GrabModeSync, None, None);
+
+ xwc.stack_mode = Below;
+ xwc.sibling = w->id;
+
+ XConfigureWindow (w->screen->display->display, w->frame,
+ CWSibling | CWStackMode, &xwc);
+
+ if (w->mapNum)
+ XMapWindow (w->screen->display->display, w->frame);
+
+ XChangeProperty (w->screen->display->display, w->id,
+ w->screen->display->frameWindowAtom,
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &w->frame, 1);
+ }
+
+ XResizeWindow (w->screen->display->display, w->frame, width, height);
+
+ rects[0].x = 0;
+ rects[0].y = 0;
+ rects[0].width = width;
+ rects[0].height = w->input.top;
+
+ rects[1].x = 0;
+ rects[1].y = w->input.top;
+ rects[1].width = w->input.left;
+ rects[1].height = height - w->input.top - w->input.bottom;
+
+ rects[2].x = width - w->input.right;
+ rects[2].y = w->input.top;
+ rects[2].width = w->input.right;
+ rects[2].height = height - w->input.top - w->input.bottom;
+
+ rects[3].x = 0;
+ rects[3].y = height - w->input.bottom;
+ rects[3].width = width;
+ rects[3].height = w->input.bottom;
+
+ XShapeCombineRectangles (w->screen->display->display,
+ w->frame,
+ ShapeInput,
+ 0,
+ 0,
+ rects,
+ 4,
+ ShapeSet,
+ YXBanded);
+ }
+ else
+ {
+ if (w->frame)
+ {
+ XDestroyWindow (w->screen->display->display, w->frame);
+ w->frame = None;
+ }
+ }
+}
+
+void
+setWindowFrameExtents (CompWindow *w,
+ CompWindowExtents *input,
+ CompWindowExtents *output)
+{
+ if (input->left != w->input.left ||
+ input->right != w->input.right ||
+ input->top != w->input.top ||
+ input->bottom != w->input.bottom)
+ {
+ unsigned long data[4];
+
+ w->input = *input;
+
+ data[0] = input->left;
+ data[1] = input->right;
+ data[2] = input->top;
+ data[3] = input->bottom;
+
+ updateFrameWindow (w);
+
+ XChangeProperty (w->screen->display->display, w->id,
+ w->screen->display->frameExtentsAtom,
+ XA_CARDINAL, 32, PropModeReplace,
+ (unsigned char *) data, 4);
+ }
+
+ if (output->left != w->output.left ||
+ output->right != w->output.right ||
+ output->top != w->output.top ||
+ output->bottom != w->output.bottom)
+ {
+ w->output = *output;
+
+ (*w->screen->windowResizeNotify) (w);
+ }
+}
+
+static void
+setWindowMatrix (CompWindow *w)
+{
+ w->matrix = w->texture.matrix;
+ w->matrix.x0 -= (w->attrib.x * w->matrix.xx);
+ w->matrix.y0 -= (w->attrib.y * w->matrix.yy);
+}
+
+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;
+ w->texture.pixmap = 1;
+ }
+ else
+ {
+ if (!w->pixmap)
+ {
+ w->pixmap =
+ XCompositeNameWindowPixmap (w->screen->display->display,
+ w->id);
+ if (!w->pixmap)
+ {
+ fprintf (stderr, "%s: XCompositeNameWindowPixmap failed\n",
+ programName);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ setWindowMatrix (w);
+}
+
+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->syncAlarm)
+ XSyncDestroyAlarm (w->screen->display->display, w->syncAlarm);
+
+ if (w->syncWaitHandle)
+ compRemoveTimeout (w->syncWaitHandle);
+
+ 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);
+
+ if (w->sizeDamage)
+ free (w->damageRects);
+
+ if (w->vertices)
+ free (w->vertices);
+
+ if (w->indices)
+ free (w->indices);
+
+ if (lastFoundWindow == w)
+ lastFoundWindow = 0;
+
+ if (lastDamagedWindow == w)
+ lastDamagedWindow = 0;
+
+ if (w->struts)
+ free (w->struts);
+
+ if (w->startupId)
+ free (w->startupId);
+
+ if (w->resName)
+ free (w->resName);
+
+ if (w->resClass)
+ free (w->resClass);
+
+ free (w);
+}
+
+void
+damageWindowRegion (CompWindow *w,
+ Region region)
+{
+ if (w->scaled)
+ {
+ REGION reg;
+ int x1, y1, x2, y2;
+
+ reg.rects = &reg.extents;
+ reg.numRects = 1;
+
+ x1 = region->extents.x1 - w->attrib.x;
+ y1 = region->extents.y1 - w->attrib.y;
+ x2 = region->extents.x2 - w->attrib.x;
+ y2 = region->extents.y2 - w->attrib.y;
+
+ reg.extents.x1 = (x1 * w->paint.xScale) + w->attrib.x;
+ reg.extents.y1 = (y1 * w->paint.yScale) + w->attrib.y;
+ reg.extents.x2 = (x2 * w->paint.xScale + 0.5f) + w->attrib.x;
+ reg.extents.y2 = (y2 * w->paint.yScale + 0.5f) + w->attrib.y;
+
+ if (reg.extents.x2 > reg.extents.x1 && reg.extents.y2 > reg.extents.y1)
+ damageScreenRegion (w->screen, &reg);
+ }
+ else
+ {
+ damageScreenRegion (w->screen, region);
+ }
+}
+
+void
+damageWindowOutputExtents (CompWindow *w)
+{
+ if (w->screen->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
+ return;
+
+ if (w->attrib.map_state == IsViewable && w->damaged)
+ {
+ REGION reg;
+
+ reg.rects = &reg.extents;
+ reg.numRects = reg.size = 1;
+
+ /* top */
+ reg.extents.x1 = w->attrib.x - w->output.left;
+ reg.extents.y1 = w->attrib.y - w->output.top;
+ reg.extents.x2 = w->attrib.x + w->width + w->output.right;
+ reg.extents.y2 = w->attrib.y;
+
+ if (reg.extents.x1 < reg.extents.x2 && reg.extents.y1 < reg.extents.y2)
+ damageWindowRegion (w, &reg);
+
+ /* bottom */
+ reg.extents.y1 = w->attrib.y + w->height;
+ reg.extents.y2 = reg.extents.y1 + w->output.bottom;
+
+ if (reg.extents.x1 < reg.extents.x2 && reg.extents.y1 < reg.extents.y2)
+ damageWindowRegion (w, &reg);
+
+ /* left */
+ reg.extents.x1 = w->attrib.x - w->output.left;
+ reg.extents.y1 = w->attrib.y;
+ reg.extents.x2 = w->attrib.x;
+ reg.extents.y2 = w->attrib.y + w->height;
+
+ if (reg.extents.x1 < reg.extents.x2 && reg.extents.y1 < reg.extents.y2)
+ damageWindowRegion (w, &reg);
+
+ /* right */
+ reg.extents.x1 = w->attrib.x + w->width;
+ reg.extents.x2 = reg.extents.x1 + w->output.right;
+
+ if (reg.extents.x1 < reg.extents.x2 && reg.extents.y1 < reg.extents.y2)
+ damageWindowRegion (w, &reg);
+ }
+}
+
+Bool
+damageWindowRect (CompWindow *w,
+ Bool initial,
+ BoxPtr rect)
+{
+ return FALSE;
+}
+
+void
+addWindowDamage (CompWindow *w)
+{
+ if (w->screen->damageMask & COMP_SCREEN_DAMAGE_ALL_MASK)
+ return;
+
+ if (w->attrib.map_state == IsViewable && w->damaged)
+ {
+ REGION region;
+
+ region.extents.x1 = -w->output.left - w->attrib.border_width;
+ region.extents.y1 = -w->output.top - w->attrib.border_width;
+ region.extents.x2 = w->width + w->output.right;
+ region.extents.y2 = w->height + w->output.bottom;
+
+ if (!(*w->screen->damageWindowRect) (w, FALSE, &region.extents))
+ {
+ region.extents.x1 += w->attrib.x + w->attrib.border_width;
+ region.extents.y1 += w->attrib.y + w->attrib.border_width;
+ region.extents.x2 += w->attrib.x + w->attrib.border_width;
+ region.extents.y2 += w->attrib.y + w->attrib.border_width;
+
+ region.rects = &region.extents;
+ region.numRects = region.size = 1;
+
+ damageWindowRegion (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 = -w->attrib.border_width;
+ r.y = -w->attrib.border_width;
+ 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.border_width;
+ rect.extents.y1 = rects[i].y + w->attrib.border_width;
+ rect.extents.x2 = rect.extents.x1 + rects[i].width;
+ rect.extents.y2 = rect.extents.y1 + rects[i].height;
+
+ if (rect.extents.x1 < 0)
+ rect.extents.x1 = 0;
+ if (rect.extents.y1 < 0)
+ rect.extents.y1 = 0;
+ if (rect.extents.x2 > w->width)
+ rect.extents.x2 = w->width;
+ if (rect.extents.y2 > w->height)
+ rect.extents.y2 = w->height;
+
+ if (rect.extents.y1 < rect.extents.y2 &&
+ rect.extents.x1 < rect.extents.x2)
+ {
+ rect.extents.x1 += w->attrib.x;
+ rect.extents.y1 += w->attrib.y;
+ rect.extents.x2 += w->attrib.x;
+ rect.extents.y2 += w->attrib.y;
+
+ XUnionRegion (&rect, w->region, w->region);
+ }
+ }
+
+ if (shapeRects)
+ XFree (shapeRects);
+}
+
+Bool
+updateWindowStruts (CompWindow *w)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned long *struts = NULL;
+ Bool hasOld, hasNew;
+ CompStruts old, new;
+
+#define MIN_EMPTY 76
+
+ if (w->struts)
+ {
+ hasOld = TRUE;
+
+ old.left = w->struts->left;
+ old.right = w->struts->right;
+ old.top = w->struts->top;
+ old.bottom = w->struts->bottom;
+ }
+ else
+ {
+ hasOld = FALSE;
+ }
+
+ hasNew = FALSE;
+
+ new.left.x = 0;
+ new.left.y = 0;
+ new.left.width = 0;
+ new.left.height = w->screen->height;
+
+ new.right.x = w->screen->width;
+ new.right.y = 0;
+ new.right.width = 0;
+ new.right.height = w->screen->height;
+
+ new.top.x = 0;
+ new.top.y = 0;
+ new.top.width = w->screen->width;
+ new.top.height = 0;
+
+ new.bottom.x = 0;
+ new.bottom.y = w->screen->height;
+ new.bottom.width = w->screen->width;
+ new.bottom.height = 0;
+
+ result = XGetWindowProperty (w->screen->display->display, w->id,
+ w->screen->display->wmStrutPartialAtom,
+ 0L, 12L, FALSE, XA_CARDINAL, &actual, &format,
+ &n, &left, (unsigned char **) &struts);
+
+ if (result == Success && n && struts)
+ {
+ if (n == 12)
+ {
+ int gap;
+
+ hasNew = TRUE;
+
+ gap = w->screen->width - struts[0] - struts[1];
+ gap -= MIN_EMPTY;
+
+ new.left.width = (int) struts[0] + MIN (0, gap / 2);
+ new.right.width = (int) struts[1] + MIN (0, gap / 2);
+
+ gap = w->screen->height - struts[2] - struts[3];
+ gap -= MIN_EMPTY;
+
+ new.top.height = (int) struts[2] + MIN (0, gap / 2);
+ new.bottom.height = (int) struts[3] + MIN (0, gap / 2);
+
+ new.right.x = w->screen->width - new.right.width;
+ new.bottom.y = w->screen->height - new.bottom.height;
+
+ new.left.y = struts[4];
+ new.left.height = struts[5] - new.left.y + 1;
+ new.right.y = struts[6];
+ new.right.height = struts[7] - new.right.y + 1;
+
+ new.top.x = struts[8];
+ new.top.width = struts[9] - new.top.x + 1;
+ new.bottom.x = struts[10];
+ new.bottom.width = struts[11] - new.bottom.x + 1;
+ }
+
+ XFree (struts);
+ }
+
+ if (!hasNew)
+ {
+ result = XGetWindowProperty (w->screen->display->display, w->id,
+ w->screen->display->wmStrutAtom,
+ 0L, 4L, FALSE, XA_CARDINAL,
+ &actual, &format, &n, &left,
+ (unsigned char **) &struts);
+
+ if (result == Success && n && struts)
+ {
+ if (n == 4)
+ {
+ int gap;
+
+ hasNew = TRUE;
+
+ gap = w->screen->width - struts[0] - struts[1];
+ gap -= MIN_EMPTY;
+
+ new.left.width = (int) struts[0] + MIN (0, gap / 2);
+ new.right.width = (int) struts[1] + MIN (0, gap / 2);
+
+ gap = w->screen->height - struts[2] - struts[3];
+ gap -= MIN_EMPTY;
+
+ new.top.height = (int) struts[2] + MIN (0, gap / 2);
+ new.bottom.height = (int) struts[3] + MIN (0, gap / 2);
+
+ new.left.x = 0;
+ new.right.x = w->screen->width - new.right.width;
+
+ new.top.y = 0;
+ new.bottom.y = w->screen->height - new.bottom.height;
+ }
+
+ XFree (struts);
+ }
+ }
+
+ if (hasOld != hasNew || (hasNew && hasOld &&
+ memcmp (&new, &old, sizeof (CompStruts))))
+ {
+ if (hasNew)
+ {
+ if (!w->struts)
+ w->struts = malloc (sizeof (CompStruts));
+
+ *w->struts = new;
+ }
+ else
+ {
+ free (w->struts);
+ w->struts = NULL;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+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->mapNum = 0;
+ w->activeNum = 0;
+
+ w->frame = None;
+
+ w->placed = FALSE;
+ w->minimized = FALSE;
+
+ w->startupId = NULL;
+ w->resName = NULL;
+ w->resClass = NULL;
+
+ initTexture (screen, &w->texture);
+
+ w->screen = screen;
+ w->pixmap = None;
+ w->destroyed = FALSE;
+ w->damaged = FALSE;
+
+ w->destroyRefCnt = 1;
+ w->unmapRefCnt = 1;
+
+ w->group = NULL;
+
+ w->damageRects = 0;
+ w->sizeDamage = 0;
+ w->nDamage = 0;
+
+ w->vertices = 0;
+ w->vertexSize = 0;
+ w->indices = 0;
+ w->indexSize = 0;
+ w->vCount = 0;
+
+ w->struts = 0;
+
+ w->input.left = 0;
+ w->input.right = 0;
+ w->input.top = 0;
+ w->input.bottom = 0;
+
+ w->output.left = 0;
+ w->output.right = 0;
+ w->output.top = 0;
+ w->output.bottom = 0;
+
+ w->paint.opacity = OPAQUE;
+ w->paint.brightness = 0xffff;
+ w->paint.saturation = COLOR;
+ w->paint.xScale = 1.0f;
+ w->paint.yScale = 1.0f;
+
+ w->alive = TRUE;
+ w->saturation = COLOR;
+
+ w->scaled = FALSE;
+
+ w->mwmDecor = MwmDecorAll;
+
+ 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;
+ }
+
+ w->width = w->attrib.width + w->attrib.border_width * 2;
+ w->height = w->attrib.height + w->attrib.border_width * 2;
+
+ w->sizeHints.flags = 0;
+
+ recalcNormalHints (w);
+
+ w->transientFor = None;
+ w->clientLeader = None;
+
+ w->serverX = w->attrib.x;
+ w->serverY = w->attrib.y;
+
+ w->syncAlarm = None;
+ w->syncCounter = 0;
+ w->syncWaitHandle = 0;
+
+ w->syncWait = FALSE;
+ w->syncX = w->attrib.x;
+ w->syncY = w->attrib.y;
+ w->syncWidth = w->attrib.width;
+ w->syncHeight = w->attrib.height;
+ w->syncBorderWidth = w->attrib.border_width;
+
+ w->saveMask = 0;
+
+ XSelectInput (screen->display->display, id,
+ PropertyChangeMask |
+ EnterWindowMask |
+ FocusChangeMask);
+
+ w->id = id;
+
+ XGrabButton (screen->display->display, AnyButton,
+ AnyModifier, w->id, TRUE, ButtonPressMask |
+ ButtonReleaseMask | ButtonMotionMask,
+ GrabModeSync, GrabModeSync, None, None);
+
+ w->inputHint = TRUE;
+ w->alpha = (w->attrib.depth == 32);
+ w->wmType = 0;
+ w->state = 0;
+ w->actions = 0;
+ w->protocols = 0;
+ w->type = CompWindowTypeUnknownMask;
+ w->lastPong = screen->display->lastPing;
+
+ if (screen->display->shapeExtension)
+ XShapeSelectInput (screen->display->display, id, ShapeNotifyMask);
+
+ insertWindowIntoScreen (screen, w, aboveId);
+
+ EMPTY_REGION (w->region);
+
+ if (w->attrib.class != InputOnly)
+ {
+ REGION rect;
+
+ rect.rects = &rect.extents;
+ rect.numRects = rect.size = 1;
+
+ rect.extents.x1 = w->attrib.x;
+ rect.extents.y1 = w->attrib.y;
+ rect.extents.x2 = w->attrib.x + w->width;
+ rect.extents.y2 = w->attrib.y + w->height;
+
+ XUnionRegion (&rect, w->region, w->region);
+
+ initTexture (screen, &w->texture);
+
+ w->damage = XDamageCreate (screen->display->display, id,
+ XDamageReportRawRectangles);
+
+ /* need to check for DisplayModal state on all windows */
+ w->state = getWindowState (w->screen->display, w->id);
+
+ updateWindowClassHints (w);
+ }
+ else
+ {
+ w->damage = None;
+ w->attrib.map_state = IsUnmapped;
+ }
+
+ if (testMode)
+ {
+ static int useAlpha = 0;
+
+ w->attrib.map_state = IsViewable;
+ w->damaged = TRUE;
+
+ w->attrib.width = 0;
+ w->attrib.height = 0;
+
+ bindWindow (w);
+
+ w->alpha = useAlpha;
+ useAlpha = !useAlpha;
+ }
+
+ w->invisible = TRUE;
+
+ if (!w->attrib.override_redirect)
+ {
+ updateNormalHints (w);
+ updateWindowStruts (w);
+
+ updateWmHints (w);
+
+ XGetTransientForHint (w->screen->display->display,
+ w->id, &w->transientFor);
+
+ w->clientLeader = getClientLeader (w);
+
+ w->wmType = getWindowType (w->screen->display, w->id);
+
+ recalcWindowType (w);
+
+ w->mwmDecor = getMwmDecor (w->screen->display, w->id);
+ w->protocols = getProtocols (w->screen->display, w->id);
+
+ if (!(w->type & CompWindowTypeDesktopMask))
+ w->paint.opacity =
+ getWindowProp32 (w->screen->display, w->id,
+ w->screen->display->winOpacityAtom,
+ OPAQUE);
+
+ w->paint.brightness =
+ getWindowProp32 (w->screen->display, w->id,
+ w->screen->display->winBrightnessAtom,
+ BRIGHT);
+
+ if (w->screen->canDoSaturated)
+ {
+ w->saturation =
+ getWindowProp32 (w->screen->display, w->id,
+ w->screen->display->winSaturationAtom,
+ COLOR);
+ if (w->alive)
+ w->paint.saturation = w->saturation;
+ }
+ }
+
+ if (w->attrib.map_state == IsViewable)
+ {
+ w->attrib.map_state = IsUnmapped;
+
+ mapWindow (w);
+
+ if (!w->attrib.override_redirect)
+ updateWindowAttributes (w);
+ }
+
+ windowInitPlugins (w);
+}
+
+void
+removeWindow (CompWindow *w)
+{
+ unhookWindowFromScreen (w->screen, w);
+
+ if (w->attrib.map_state == IsViewable && w->damaged)
+ {
+ if (w->type == CompWindowTypeDesktopMask)
+ w->screen->desktopWindowCount--;
+
+ if (w->struts)
+ updateWorkareaForScreen (w->screen);
+
+ updateClientListForScreen (w->screen);
+ }
+ else if (w->state & CompWindowStateHiddenMask)
+ {
+ updateClientListForScreen (w->screen);
+ }
+
+ windowFiniPlugins (w);
+
+ freeWindow (w);
+}
+
+void
+destroyWindow (CompWindow *w)
+{
+ w->id = 1;
+ w->mapNum = 0;
+
+ w->destroyRefCnt--;
+ if (w->destroyRefCnt)
+ return;
+
+ if (!w->destroyed)
+ {
+ w->destroyed = TRUE;
+ w->screen->pendingDestroys++;
+ }
+}
+
+static void
+sendConfigureNotify (CompWindow *w)
+{
+ XConfigureEvent xev;
+
+ xev.type = ConfigureNotify;
+ xev.event = w->id;
+ xev.window = w->id;
+ xev.x = w->serverX;
+ xev.y = w->serverY;
+ xev.width = w->attrib.width;
+ xev.height = w->attrib.height;
+ xev.border_width = w->attrib.border_width;
+
+ xev.above = (w->prev) ? w->prev->id : None;
+ xev.override_redirect = w->attrib.override_redirect;
+
+ XSendEvent (w->screen->display->display, w->id, FALSE,
+ StructureNotifyMask, (XEvent *) &xev);
+}
+
+void
+mapWindow (CompWindow *w)
+{
+ if (w->attrib.class == InputOnly)
+ return;
+
+ if (w->attrib.map_state == IsViewable)
+ return;
+
+ w->unmapRefCnt = 1;
+
+ w->attrib.map_state = IsViewable;
+
+ setWmState (w->screen->display, NormalState, w->id);
+
+ w->invisible = TRUE;
+ w->damaged = FALSE;
+ w->alive = TRUE;
+
+ w->lastPong = w->screen->display->lastPing;
+
+ w->mapNum = w->screen->mapNum++;
+
+ updateWindowRegion (w);
+
+ if (w->frame)
+ XMapWindow (w->screen->display->display, w->frame);
+
+ if (w->struts)
+ updateWorkareaForScreen (w->screen);
+
+ updateClientListForScreen (w->screen);
+
+ if (w->type & CompWindowTypeDesktopMask)
+ w->screen->desktopWindowCount++;
+
+ if (w->protocols & CompWindowProtocolSyncRequestMask)
+ {
+ sendSyncRequest (w);
+ sendConfigureNotify (w);
+ }
+}
+
+void
+unmapWindow (CompWindow *w)
+{
+ w->mapNum = 0;
+
+ if (w->frame)
+ XUnmapWindow (w->screen->display->display, w->frame);
+
+ w->unmapRefCnt--;
+ if (w->unmapRefCnt > 0)
+ return;
+
+ if (w->attrib.map_state != IsViewable)
+ return;
+
+ if (w->type == CompWindowTypeDesktopMask)
+ w->screen->desktopWindowCount--;
+
+ addWindowDamage (w);
+
+ w->attrib.map_state = IsUnmapped;
+
+ setWmState (w->screen->display, IconicState, w->id);
+
+ w->invisible = TRUE;
+
+ releaseWindow (w);
+
+ if (w->struts)
+ updateWorkareaForScreen (w->screen);
+
+ updateClientListForScreen (w->screen);
+}
+
+static int
+restackWindow (CompWindow *w,
+ Window aboveId)
+{
+ if (w->prev)
+ {
+ if (aboveId && aboveId == w->prev->id)
+ return 0;
+ }
+ else if (aboveId == None)
+ return 0;
+
+ unhookWindowFromScreen (w->screen, w);
+ insertWindowIntoScreen (w->screen, w, aboveId);
+
+ updateClientListForScreen (w->screen);
+
+ return 1;
+}
+
+Bool
+resizeWindow (CompWindow *w,
+ int x,
+ int y,
+ int width,
+ int height,
+ int borderWidth)
+{
+ Window frame = None;
+
+ if (x != w->serverX)
+ {
+ frame = w->frame;
+ w->serverX = x;
+ }
+ else
+ x = w->attrib.x;
+
+ if (y != w->serverY)
+ {
+ frame = w->frame;
+ w->serverY = y;
+ }
+ else
+ y = w->attrib.y;
+
+ if (frame)
+ XMoveWindow (w->screen->display->display, frame,
+ w->serverX - w->input.left,
+ w->serverY - w->input.top);
+
+ if (w->attrib.width != width ||
+ w->attrib.height != height ||
+ w->attrib.border_width != borderWidth)
+ {
+ unsigned int pw, ph, actualWidth, actualHeight, ui;
+ Pixmap pixmap = None;
+ Window root;
+ Status result;
+ int i;
+
+ pw = width + borderWidth * 2;
+ ph = height + borderWidth * 2;
+
+ if (!w->invisible)
+ {
+ pixmap = XCompositeNameWindowPixmap (w->screen->display->display,
+ w->id);
+ if (!pixmap)
+ {
+ fprintf (stderr, "%s: XCompositeNameWindowPixmap failed\n",
+ programName);
+
+ return FALSE;
+ }
+
+ result = XGetGeometry (w->screen->display->display, pixmap, &root,
+ &i, &i, &actualWidth, &actualHeight,
+ &ui, &ui);
+
+ if (actualWidth != pw || actualHeight != ph)
+ {
+ XFreePixmap (w->screen->display->display, pixmap);
+
+ return FALSE;
+ }
+ }
+
+ addWindowDamage (w);
+
+ w->attrib.x = x;
+ w->attrib.y = y;
+ w->attrib.width = width;
+ w->attrib.height = height;
+ w->attrib.border_width = borderWidth;
+
+ w->width = pw;
+ w->height = ph;
+
+ releaseWindow (w);
+
+ w->pixmap = pixmap;
+
+ if (w->mapNum)
+ updateWindowRegion (w);
+
+ (*w->screen->windowResizeNotify) (w);
+
+ addWindowDamage (w);
+
+ w->invisible = WINDOW_INVISIBLE (w);
+
+ updateFrameWindow (w);
+ }
+ else if (w->attrib.x != x || w->attrib.y != y)
+ {
+ int dx, dy;
+
+ dx = x - w->attrib.x;
+ dy = y - w->attrib.y;
+
+ moveWindow (w, dx, dy, TRUE);
+ }
+
+ return TRUE;
+}
+
+static void
+syncValueIncrement (XSyncValue *value)
+{
+ XSyncValue one;
+ int overflow;
+
+ XSyncIntToValue (&one, 1);
+ XSyncValueAdd (value, *value, one, &overflow);
+}
+
+static Bool
+initializeSyncCounter (CompWindow *w)
+{
+ XSyncAlarmAttributes values;
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned long *counter;
+
+ if (w->syncCounter)
+ return w->syncAlarm != None;
+
+ if (!(w->protocols & CompWindowProtocolSyncRequestMask))
+ return FALSE;
+
+ result = XGetWindowProperty (w->screen->display->display, w->id,
+ w->screen->display->wmSyncRequestCounterAtom,
+ 0L, 1L, FALSE, XA_CARDINAL, &actual, &format,
+ &n, &left, (unsigned char **) &counter);
+
+ if (result == Success && n && counter)
+ {
+ w->syncCounter = *counter;
+
+ XFree (counter);
+
+ XSyncIntsToValue (&w->syncValue, (unsigned int) rand (), 0);
+ XSyncSetCounter (w->screen->display->display,
+ w->syncCounter,
+ w->syncValue);
+
+ syncValueIncrement (&w->syncValue);
+
+ values.events = TRUE;
+
+ values.trigger.counter = w->syncCounter;
+ values.trigger.wait_value = w->syncValue;
+
+ values.trigger.value_type = XSyncAbsolute;
+ values.trigger.test_type = XSyncPositiveComparison;
+
+ XSyncIntToValue (&values.delta, 1);
+
+ values.events = TRUE;
+
+ compCheckForError (w->screen->display->display);
+
+ /* Note that by default, the alarm increments the trigger value
+ * when it fires until the condition (counter.value < trigger.value)
+ * is FALSE again.
+ */
+ w->syncAlarm = XSyncCreateAlarm (w->screen->display->display,
+ XSyncCACounter |
+ XSyncCAValue |
+ XSyncCAValueType |
+ XSyncCATestType |
+ XSyncCADelta |
+ XSyncCAEvents,
+ &values);
+
+ if (!compCheckForError (w->screen->display->display))
+ return TRUE;
+
+ XSyncDestroyAlarm (w->screen->display->display, w->syncAlarm);
+ w->syncAlarm = None;
+ }
+
+ return FALSE;
+}
+
+static Bool
+syncWaitTimeout (void *closure)
+{
+ CompWindow *w = closure;
+
+ w->syncWaitHandle = 0;
+ handleSyncAlarm (w);
+
+ return FALSE;
+}
+
+void
+sendSyncRequest (CompWindow *w)
+{
+ XClientMessageEvent xev;
+
+ if (w->syncWait)
+ return;
+
+ if (!initializeSyncCounter (w))
+ return;
+
+ xev.type = ClientMessage;
+ xev.window = w->id;
+ xev.message_type = w->screen->display->wmProtocolsAtom;
+ xev.format = 32;
+ xev.data.l[0] = w->screen->display->wmSyncRequestAtom;
+ xev.data.l[1] = CurrentTime;
+ xev.data.l[2] = XSyncValueLow32 (w->syncValue);
+ xev.data.l[3] = XSyncValueHigh32 (w->syncValue);
+ xev.data.l[4] = 0;
+
+ syncValueIncrement (&w->syncValue);
+
+ XSendEvent (w->screen->display->display, w->id, FALSE, 0, (XEvent *) &xev);
+
+ w->syncWait = TRUE;
+ w->syncX = w->serverX;
+ w->syncY = w->serverY;
+ w->syncWidth = w->attrib.width;
+ w->syncHeight = w->attrib.height;
+ w->syncBorderWidth = w->attrib.border_width;
+
+ if (!w->syncWaitHandle)
+ w->syncWaitHandle = compAddTimeout (1000, syncWaitTimeout, w);
+}
+
+void
+configureWindow (CompWindow *w,
+ XConfigureEvent *ce)
+{
+ if (w->syncWait)
+ {
+ w->syncX = ce->x;
+ w->syncY = ce->y;
+ w->syncWidth = ce->width;
+ w->syncHeight = ce->height;
+ w->syncBorderWidth = ce->border_width;
+ }
+ else
+ {
+ resizeWindow (w, ce->x, ce->y, ce->width, ce->height,
+ ce->border_width);
+ }
+
+ w->attrib.override_redirect = ce->override_redirect;
+
+ if (restackWindow (w, ce->above))
+ addWindowDamage (w);
+}
+
+void
+circulateWindow (CompWindow *w,
+ XCirculateEvent *ce)
+{
+ Window newAboveId;
+
+ if (ce->place == PlaceOnTop && w->screen->reverseWindows)
+ newAboveId = w->screen->reverseWindows->id;
+ else
+ newAboveId = 0;
+
+ if (restackWindow (w, newAboveId))
+ addWindowDamage (w);
+}
+
+void
+moveWindow (CompWindow *w,
+ int dx,
+ int dy,
+ Bool damage)
+{
+ if (dx || dy)
+ {
+ if (damage)
+ addWindowDamage (w);
+
+ w->attrib.x += dx;
+ w->attrib.y += dy;
+
+ XOffsetRegion (w->region, dx, dy);
+
+ setWindowMatrix (w);
+
+ w->invisible = WINDOW_INVISIBLE (w);
+
+ (*w->screen->windowMoveNotify) (w, dx, dy);
+
+ if (damage)
+ addWindowDamage (w);
+ }
+}
+
+void
+syncWindowPosition (CompWindow *w)
+{
+ if (w->attrib.x != w->serverX || w->attrib.y != w->serverY)
+ {
+ XMoveWindow (w->screen->display->display, w->id,
+ w->attrib.x,
+ w->attrib.y);
+
+ if (0 && !w->attrib.override_redirect)
+ {
+ XConfigureEvent ce;
+
+ ce.type = ConfigureNotify;
+ ce.display = w->screen->display->display;
+ ce.event = w->id;
+ ce.window = w->id;
+ ce.x = w->attrib.x;
+ ce.y = w->attrib.y;
+ ce.width = w->attrib.width;
+ ce.height = w->attrib.height;
+ ce.border_width = w->attrib.border_width;
+ ce.above = (w->prev) ? w->prev->id : None;
+ ce.override_redirect = FALSE;
+
+ XSendEvent (w->screen->display->display,
+ w->id, FALSE, StructureNotifyMask,
+ (XEvent *) &ce);
+ }
+ }
+}
+
+void
+setWindowScale (CompWindow *w,
+ float xScale,
+ float yScale)
+{
+ if (xScale > 0.999f && xScale < 1.001f &&
+ yScale > 0.999f && yScale < 1.001f)
+ {
+ w->paint.xScale = 1.0f;
+ w->paint.yScale = 1.0f;
+
+ w->scaled = FALSE;
+ }
+ else
+ {
+ w->paint.xScale = xScale;
+ w->paint.yScale = yScale;
+
+ w->scaled = TRUE;
+ }
+}
+
+Bool
+focusWindow (CompWindow *w)
+{
+ if (w->attrib.override_redirect)
+ return FALSE;
+
+ if (!w->mapNum || w->attrib.map_state != IsViewable)
+ return FALSE;
+
+ if (w->attrib.x + w->width <= 0 ||
+ w->attrib.y + w->height <= 0 ||
+ w->attrib.x >= w->screen->width ||
+ w->attrib.y >= w->screen->height)
+ return FALSE;
+
+ if (w->inputHint || (w->protocols & CompWindowProtocolTakeFocusMask))
+ return TRUE;
+
+ return FALSE;
+}
+
+void
+windowResizeNotify (CompWindow *w)
+{
+}
+
+void
+windowMoveNotify (CompWindow *w,
+ int dx,
+ int dy)
+{
+}
+
+void
+windowGrabNotify (CompWindow *w,
+ int x,
+ int y,
+ unsigned int state,
+ unsigned int mask)
+{
+}
+
+void
+windowUngrabNotify (CompWindow *w)
+{
+}
+
+static Bool
+isGroupTransient (CompWindow *w,
+ Window clientLeader)
+{
+ if (!clientLeader)
+ return FALSE;
+
+ if (w->transientFor == None || w->transientFor == w->screen->root)
+ {
+ if (w->type & (CompWindowTypeDialogMask |
+ CompWindowTypeModalDialogMask))
+ {
+ if (w->clientLeader == clientLeader)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static CompWindow *
+getModalTransient (CompWindow *window)
+{
+ CompWindow *w, *modalTransient;
+
+ modalTransient = window;
+
+ for (w = window->screen->reverseWindows; w; w = w->prev)
+ {
+ if (w == modalTransient || w->mapNum == 0)
+ continue;
+
+ if (w->transientFor == modalTransient->id)
+ {
+ if (w->state & CompWindowStateModalMask)
+ {
+ modalTransient = w;
+ w = window->screen->reverseWindows;
+ }
+ }
+ }
+
+ if (modalTransient == window)
+ {
+ for (w = window->screen->reverseWindows; w; w = w->prev)
+ {
+ if (w == modalTransient || w->mapNum == 0)
+ continue;
+
+ if (isGroupTransient (w, modalTransient->clientLeader))
+ {
+ if (w->state & CompWindowStateModalMask)
+ {
+ modalTransient = w;
+ break;
+ }
+ }
+ }
+ }
+
+ if (modalTransient == window)
+ modalTransient = NULL;
+
+ return modalTransient;
+}
+
+void
+moveInputFocusToWindow (CompWindow *w)
+{
+ CompDisplay *d = w->screen->display;
+ CompWindow *modalTransient;
+
+ modalTransient = getModalTransient (w);
+ if (modalTransient)
+ w = modalTransient;
+
+ if (w->id != d->activeWindow)
+ {
+ if (w->inputHint || (w->protocols & CompWindowProtocolTakeFocusMask))
+ XSetInputFocus (d->display, w->id, RevertToPointerRoot,
+ CurrentTime);
+ }
+}
+
+static Bool
+isAncestorTo (CompWindow *transient,
+ CompWindow *ancestor)
+{
+ if (transient->transientFor)
+ {
+ if (transient->transientFor == ancestor->id)
+ return TRUE;
+
+ transient = findWindowAtScreen (transient->screen,
+ transient->transientFor);
+ if (transient)
+ return isAncestorTo (transient, ancestor);
+ }
+
+ return FALSE;
+}
+
+
+static Bool
+stackLayerCheck (CompWindow *w,
+ Window clientLeader,
+ CompWindow *below)
+{
+ if (w->transientFor == below->id)
+ return TRUE;
+
+ if (isAncestorTo (below, w))
+ return FALSE;
+
+ if (clientLeader && below->clientLeader == clientLeader)
+ if (isGroupTransient (below, clientLeader))
+ return FALSE;
+
+ if (w->state & CompWindowStateAboveMask)
+ {
+ return TRUE;
+ }
+ else if (w->state & CompWindowStateBelowMask)
+ {
+ if (below->state & CompWindowStateBelowMask)
+ return TRUE;
+ }
+ else if (!(below->state & CompWindowStateAboveMask))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* goes through the stack, top-down until we find a window we should
+ stack above, normal windows can be stacked above fullscreen windows. */
+static CompWindow *
+findSibilingBelow (CompWindow *w)
+{
+ CompWindow *below;
+ Window clientLeader = w->clientLeader;
+ unsigned int type = w->type;
+
+ /* normal stacking fullscreen windows with below state */
+ if ((type & CompWindowTypeFullscreenMask) &&
+ (w->state & CompWindowStateBelowMask))
+ type = CompWindowTypeNormalMask;
+
+ if (w->transientFor || isGroupTransient (w, clientLeader))
+ clientLeader = None;
+
+ for (below = w->screen->reverseWindows; below; below = below->prev)
+ {
+ if (below == w)
+ continue;
+
+ if (below->attrib.override_redirect)
+ continue;
+
+ if (below->attrib.map_state != IsViewable || below->mapNum == 0)
+ continue;
+
+ /* always above desktop windows */
+ if (below->type & CompWindowTypeDesktopMask)
+ return below;
+
+ switch (type) {
+ case CompWindowTypeDesktopMask:
+ /* desktop window layer */
+ break;
+ case CompWindowTypeFullscreenMask:
+ case CompWindowTypeDockMask:
+ /* fullscreen and dock layer */
+ if (below->type & (CompWindowTypeFullscreenMask |
+ CompWindowTypeDockMask))
+ {
+ if (stackLayerCheck (w, clientLeader, below))
+ return below;
+ }
+ else
+ {
+ return below;
+ }
+ break;
+ default:
+ /* fullscreen and normal layer */
+ if (!(below->type & CompWindowTypeDockMask))
+ {
+ if (stackLayerCheck (w, clientLeader, below))
+ return below;
+ }
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+saveWindowGeometry (CompWindow *w,
+ int mask)
+{
+ int m = mask & ~w->saveMask;
+
+ /* only save geometry if window has been placed */
+ if (!w->placed)
+ return;
+
+ if (m & CWX)
+ w->saveWc.x = w->attrib.x;
+
+ if (m & CWY)
+ w->saveWc.y = w->attrib.y;
+
+ if (m & CWWidth)
+ w->saveWc.width = w->attrib.width;
+
+ if (m & CWHeight)
+ w->saveWc.height = w->attrib.height;
+
+ if (m & CWBorderWidth)
+ w->saveWc.border_width = w->attrib.border_width;
+
+ w->saveMask |= m;
+}
+
+static int
+restoreWindowGeometry (CompWindow *w,
+ XWindowChanges *xwc,
+ int mask)
+{
+ int m = mask & w->saveMask;
+
+ if (m & CWX)
+ xwc->x = w->saveWc.x;
+
+ if (m & CWY)
+ xwc->y = w->saveWc.y;
+
+ if (m & CWWidth)
+ xwc->width = w->saveWc.width;
+
+ if (m & CWHeight)
+ xwc->height = w->saveWc.height;
+
+ if (m & CWBorderWidth)
+ xwc->border_width = w->saveWc.border_width;
+
+ w->saveMask &= ~mask;
+
+ return m;
+}
+static void
+configureXWindow (Display *dpy,
+ CompWindow *w,
+ unsigned int valueMask,
+ XWindowChanges *xwc)
+{
+ XConfigureWindow (w->screen->display->display, w->id,
+ valueMask, xwc);
+
+ if (w->frame && (valueMask & (CWSibling | CWStackMode)))
+ XConfigureWindow (w->screen->display->display, w->frame,
+ valueMask & (CWSibling | CWStackMode), xwc);
+}
+
+static Bool
+stackTransients (CompWindow *w,
+ CompWindow *avoid,
+ XWindowChanges *xwc)
+{
+ CompWindow *t;
+ Window clientLeader = w->clientLeader;
+
+ if (w->transientFor || isGroupTransient (w, clientLeader))
+ clientLeader = None;
+
+ for (t = w->screen->reverseWindows; t; t = t->prev)
+ {
+ if (t == w || t == avoid)
+ continue;
+
+ if (t->transientFor == w->id || isGroupTransient (t, clientLeader))
+ {
+ if (!stackTransients (t, avoid, xwc))
+ return FALSE;
+
+ if (xwc->sibling == t->id)
+ return FALSE;
+
+ if (t->mapNum)
+ configureXWindow (w->screen->display->display, t,
+ CWSibling | CWStackMode, xwc);
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+stackAncestors (CompWindow *w,
+ XWindowChanges *xwc)
+{
+ if (w->transientFor && xwc->sibling != w->transientFor)
+ {
+ CompWindow *ancestor;
+
+ ancestor = findWindowAtScreen (w->screen, w->transientFor);
+ if (ancestor)
+ {
+ if (!stackTransients (ancestor, w, xwc))
+ return;
+
+ if (ancestor->mapNum)
+ configureXWindow (w->screen->display->display, ancestor,
+ CWSibling | CWStackMode,
+ xwc);
+
+ stackAncestors (ancestor, xwc);
+ }
+ }
+ else if (isGroupTransient (w, w->clientLeader))
+ {
+ CompWindow *a;
+
+ for (a = w->screen->reverseWindows; a; a = a->prev)
+ {
+ if (a->clientLeader == w->clientLeader &&
+ a->transientFor == None &&
+ !isGroupTransient (a, w->clientLeader))
+ {
+ if (xwc->sibling == a->id)
+ break;
+
+ if (!stackTransients (a, w, xwc))
+ break;
+
+ if (a->mapNum)
+ configureXWindow (w->screen->display->display, a,
+ CWSibling | CWStackMode,
+ xwc);
+ }
+ }
+ }
+}
+
+void
+updateWindowAttributes (CompWindow *w)
+{
+ CompWindow *sibiling;
+ XWindowChanges xwc;
+ int mask = 0;
+
+ if (w->state & CompWindowStateHiddenMask)
+ return;
+
+ xwc.stack_mode = Above;
+ xwc.sibling = None;
+
+ sibiling = findSibilingBelow (w);
+ if (sibiling)
+ xwc.sibling = sibiling->id;
+
+ if (xwc.sibling != w->id)
+ {
+ if (w->prev)
+ {
+ if (xwc.sibling == None)
+ {
+ XLowerWindow (w->screen->display->display, w->id);
+ if (w->frame)
+ XLowerWindow (w->screen->display->display, w->frame);
+ }
+ else if (xwc.sibling != w->prev->id)
+ mask |= CWSibling | CWStackMode;
+ }
+ else if (xwc.sibling != None)
+ mask |= CWSibling | CWStackMode;
+ }
+
+ /* only update fullscreen and maximized size if window is visible on
+ current viewport. Size is updated once we switch to the windows
+ viewport. */
+ if (w->attrib.x < w->screen->width && w->attrib.x + w->width > 0)
+ {
+ if (w->type & CompWindowTypeFullscreenMask)
+ {
+ saveWindowGeometry (w,
+ CWX | CWY | CWWidth | CWHeight |
+ CWBorderWidth);
+
+ xwc.width = w->screen->width;
+ xwc.height = w->screen->height;
+ xwc.border_width = 0;
+
+ mask |= CWWidth | CWHeight | CWBorderWidth;
+ }
+ else
+ {
+ mask |= restoreWindowGeometry (w, &xwc, CWBorderWidth);
+
+ if (w->state & CompWindowStateMaximizedVertMask)
+ {
+ saveWindowGeometry (w, CWY | CWHeight);
+
+ xwc.height = w->screen->workArea.height - w->input.top -
+ w->input.bottom - w->attrib.border_width * 2;
+
+ mask |= CWHeight;
+ }
+ else
+ {
+ mask |= restoreWindowGeometry (w, &xwc, CWY | CWHeight);
+ }
+
+ if (w->state & CompWindowStateMaximizedHorzMask)
+ {
+ saveWindowGeometry (w, CWX | CWWidth);
+
+ xwc.width = w->screen->workArea.width - w->input.left -
+ w->input.right - w->attrib.border_width * 2;
+
+ mask |= CWWidth;
+ }
+ else
+ {
+ mask |= restoreWindowGeometry (w, &xwc, CWX | CWWidth);
+ }
+ }
+ }
+
+ if (mask & (CWWidth | CWHeight))
+ {
+ if (w->type & CompWindowTypeFullscreenMask)
+ {
+ xwc.x = 0;
+ xwc.y = 0;
+
+ mask |= CWX | CWY;
+ }
+ else
+ {
+ int width, height, max;
+
+ width = (mask & CWWidth) ? xwc.width : w->attrib.width;
+ height = (mask & CWHeight) ? xwc.height : w->attrib.height;
+
+ xwc.width = w->attrib.width;
+ xwc.height = w->attrib.height;
+
+ if (constrainNewWindowSize (w, width, height, &width, &height))
+ {
+ xwc.width = width;
+ xwc.height = height;
+ }
+ else
+ mask &= ~(CWWidth | CWHeight);
+
+ if (w->state & CompWindowStateMaximizedVertMask)
+ {
+ if (w->attrib.y < w->screen->workArea.y + w->input.top)
+ {
+ xwc.y = w->screen->workArea.y + w->input.top;
+ mask |= CWY;
+ }
+ else
+ {
+ height = xwc.height + w->attrib.border_width * 2;
+
+ max = w->screen->workArea.y + w->screen->workArea.height;
+ if (w->attrib.y + height + w->input.bottom > max)
+ {
+ xwc.y = max - height - w->input.bottom;
+ mask |= CWY;
+ }
+ }
+ }
+
+ if (w->state & CompWindowStateMaximizedHorzMask)
+ {
+ if (w->attrib.x < w->screen->workArea.x + w->input.left)
+ {
+ xwc.x = w->screen->workArea.x + w->input.left;
+ mask |= CWX;
+ }
+ else
+ {
+ width = xwc.width + w->attrib.border_width * 2;
+
+ max = w->screen->workArea.x + w->screen->workArea.width;
+ if (w->attrib.x + width + w->input.right > max)
+ {
+ xwc.x = max - width - w->input.right;
+ mask |= CWX;
+ }
+ }
+ }
+ }
+ }
+
+ if (!mask)
+ return;
+
+ if (mask & (CWSibling | CWStackMode))
+ {
+ /* a normal window can be stacked above fullscreen windows but we
+ don't wont normal windows to be stacked above dock window so if
+ the sibiling we're stacking above is a fullscreen window we also
+ update all dock windows. */
+ if ((sibiling->type & CompWindowTypeFullscreenMask) &&
+ (!(w->type & (CompWindowTypeFullscreenMask |
+ CompWindowTypeDockMask))))
+ {
+ CompWindow *dw;
+
+ for (dw = w->screen->reverseWindows; dw; dw = dw->prev)
+ if (dw == sibiling)
+ break;
+
+ for (; dw; dw = dw->prev)
+ if (dw->type & CompWindowTypeDockMask)
+ configureXWindow (w->screen->display->display, dw,
+ CWSibling | CWStackMode,
+ &xwc);
+ }
+
+ /* transient children above */
+ if (stackTransients (w, NULL, &xwc))
+ {
+ configureXWindow (w->screen->display->display, w, mask, &xwc);
+
+ /* ancestors, sibilings and sibiling transients below */
+ stackAncestors (w, &xwc);
+ }
+ }
+ else
+ {
+ configureXWindow (w->screen->display->display, w, mask, &xwc);
+ }
+}
+
+void
+activateWindow (CompWindow *w)
+{
+ if (w->state & CompWindowStateHiddenMask)
+ {
+ if (w->minimized)
+ unminimizeWindow (w);
+
+ if (w->screen->showingDesktopMask)
+ leaveShowDesktopMode (w->screen);
+
+ showWindow (w);
+ }
+
+ if (w->state & CompWindowStateHiddenMask)
+ return;
+
+ updateWindowAttributes (w);
+
+ if (!(w->type & CompWindowTypeDockMask))
+ moveInputFocusToWindow (w);
+}
+
+void
+closeWindow (CompWindow *w)
+{
+ CompDisplay *display = w->screen->display;
+
+ if (w->actions & CompWindowActionCloseMask)
+ {
+ XEvent ev;
+
+ ev.type = ClientMessage;
+ ev.xclient.window = w->id;
+ ev.xclient.message_type = display->wmProtocolsAtom;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = display->wmDeleteWindowAtom;
+ ev.xclient.data.l[1] = CurrentTime;
+ ev.xclient.data.l[2] = 0;
+ ev.xclient.data.l[3] = 0;
+ ev.xclient.data.l[4] = 0;
+
+ XSendEvent (display->display, w->id, FALSE, NoEventMask, &ev);
+ }
+ else
+ {
+ XKillClient (display->display, w->id);
+ }
+}
+
+void
+getOuterRectOfWindow (CompWindow *w,
+ XRectangle *r)
+{
+ r->x = w->attrib.x - w->input.left;
+ r->y = w->attrib.y - w->input.top;
+ r->width = w->width + w->input.left + w->input.right;
+ r->height = w->height + w->input.top + w->input.bottom;
+}
+
+Bool
+constrainNewWindowSize (CompWindow *w,
+ int width,
+ int height,
+ int *newWidth,
+ int *newHeight)
+{
+ const XSizeHints *hints = &w->sizeHints;
+ int min_width = 0;
+ int min_height = 0;
+ int base_width = 0;
+ int base_height = 0;
+ int xinc = 1;
+ int yinc = 1;
+ int max_width = MAXSHORT;
+ int max_height = MAXSHORT;
+
+ /* Ater gdk_window_constrain_size(), which is partially borrowed from fvwm.
+ *
+ * Copyright 1993, Robert Nation
+ * You may use this code for any purpose, as long as the original
+ * copyright remains in the source code and all documentation
+ *
+ * which in turn borrows parts of the algorithm from uwm
+ */
+
+#define FLOOR(value, base) (((int) ((value) / (base))) * (base))
+#define FLOOR64(value, base) (((uint64_t) ((value) / (base))) * (base))
+#define CLAMP(v, min, max) ((v) <= (min) ? (min) : (v) >= (max) ? (max) : (v))
+
+ if ((hints->flags & PBaseSize) && (hints->flags & PMinSize))
+ {
+ base_width = hints->base_width;
+ base_height = hints->base_height;
+ min_width = hints->min_width;
+ min_height = hints->min_height;
+ }
+ else if (hints->flags & PBaseSize)
+ {
+ base_width = hints->base_width;
+ base_height = hints->base_height;
+ min_width = hints->base_width;
+ min_height = hints->base_height;
+ }
+ else if (hints->flags & PMinSize)
+ {
+ base_width = hints->min_width;
+ base_height = hints->min_height;
+ min_width = hints->min_width;
+ min_height = hints->min_height;
+ }
+
+ if (hints->flags & PMaxSize)
+ {
+ max_width = hints->max_width ;
+ max_height = hints->max_height;
+ }
+
+ if (hints->flags & PResizeInc)
+ {
+ xinc = MAX (xinc, hints->width_inc);
+ yinc = MAX (yinc, hints->height_inc);
+ }
+
+ /* clamp width and height to min and max values */
+ width = CLAMP (width, min_width, max_width);
+ height = CLAMP (height, min_height, max_height);
+
+ /* shrink to base + N * inc */
+ width = base_width + FLOOR (width - base_width, xinc);
+ height = base_height + FLOOR (height - base_height, yinc);
+
+ /* constrain aspect ratio, according to:
+ *
+ * min_aspect.x width max_aspect.x
+ * ------------ <= -------- <= -----------
+ * min_aspect.y height max_aspect.y
+ */
+ if (hints->flags & PAspect &&
+ hints->min_aspect.y > 0 && hints->max_aspect.x > 0)
+ {
+ /* Use 64 bit arithmetic to prevent overflow */
+
+ uint64_t min_aspect_x = hints->min_aspect.x;
+ uint64_t min_aspect_y = hints->min_aspect.y;
+ uint64_t max_aspect_x = hints->max_aspect.x;
+ uint64_t max_aspect_y = hints->max_aspect.y;
+ uint64_t delta;
+
+ if (min_aspect_x * height > width * min_aspect_y)
+ {
+ delta = FLOOR64 (height - width * min_aspect_y / min_aspect_x, yinc);
+ if (height - delta >= min_height)
+ height -= delta;
+ else
+ {
+ delta = FLOOR64 (height * min_aspect_x / min_aspect_y - width,
+ xinc);
+ if (width + delta <= max_width)
+ width += delta;
+ }
+ }
+
+ if (width * max_aspect_y > max_aspect_x * height)
+ {
+ delta = FLOOR64 (width - height * max_aspect_x / max_aspect_y, xinc);
+ if (width - delta >= min_width)
+ width -= delta;
+ else
+ {
+ delta = FLOOR64 (width * min_aspect_y / max_aspect_y - height,
+ yinc);
+ if (height + delta <= max_height)
+ height += delta;
+ }
+ }
+ }
+
+#undef FLOOR
+#undef FLOOR64
+
+ if (width != w->attrib.width || height != w->attrib.height)
+ {
+ *newWidth = width;
+ *newHeight = height;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+hideWindow (CompWindow *w)
+{
+ if (w->attrib.map_state != IsViewable)
+ return;
+
+ if (w->state & CompWindowStateHiddenMask)
+ return;
+
+ if (!w->minimized && !(w->type & w->screen->showingDesktopMask))
+ return;
+
+ w->state |= CompWindowStateHiddenMask;
+
+ XUnmapWindow (w->screen->display->display, w->id);
+
+ setWindowState (w->screen->display, w->state, w->id);
+}
+
+void
+showWindow (CompWindow *w)
+{
+ if (!(w->state & CompWindowStateHiddenMask))
+ return;
+
+ if (w->minimized || (w->type & w->screen->showingDesktopMask))
+ return;
+
+ w->state &= ~CompWindowStateHiddenMask;
+
+ XMapWindow (w->screen->display->display, w->id);
+
+ setWindowState (w->screen->display, w->state, w->id);
+}
+
+static void
+minimizeTransients (CompWindow *w,
+ void *closure)
+{
+ CompWindow *ancestor = closure;
+
+ if (w->transientFor == ancestor->id ||
+ isGroupTransient (w, ancestor->clientLeader))
+ minimizeWindow (w);
+}
+
+void
+minimizeWindow (CompWindow *w)
+{
+ if (!w->minimized)
+ {
+ w->minimized = TRUE;
+
+ forEachWindowOnScreen (w->screen, minimizeTransients, (void *) w);
+
+ hideWindow (w);
+ }
+}
+
+static void
+unminimizeTransients (CompWindow *w,
+ void *closure)
+{
+ CompWindow *ancestor = closure;
+
+ if (w->transientFor == ancestor->id ||
+ isGroupTransient (w, ancestor->clientLeader))
+ unminimizeWindow (w);
+}
+
+void
+unminimizeWindow (CompWindow *w)
+{
+ if (w->minimized)
+ {
+ w->minimized = FALSE;
+
+ showWindow (w);
+
+ forEachWindowOnScreen (w->screen, unminimizeTransients, (void *) w);
+ }
+}