summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZack Rusin <zack@kde.org>2005-12-31 06:21:45 +0000
committerZack Rusin <zack@kde.org>2005-12-31 06:21:45 +0000
commite4b17d9630385493c8bdf29b67a831de9374c939 (patch)
tree33649c485493ee9b6ff22b7b0cafd21d61fd954c
adding glxcompmgr. currently depends on some mesa patches (will add them in
a second)
-rw-r--r--AUTHORS1
-rw-r--r--COPYING21
-rw-r--r--ChangeLog0
-rw-r--r--INSTALL9
-rw-r--r--Makefile.am8
-rw-r--r--NEWS0
-rw-r--r--README8
-rwxr-xr-xautogen.sh13
-rw-r--r--configure.ac137
-rw-r--r--glxcomp.pc.in12
-rw-r--r--images/Makefile.am8
-rw-r--r--images/background.pngbin0 -> 135524 bytes
-rw-r--r--images/window.pngbin0 -> 9989 bytes
-rw-r--r--include/Makefile.am4
-rw-r--r--include/comp.h942
-rw-r--r--include/region.h198
-rw-r--r--plugins/Makefile.am49
-rw-r--r--plugins/cube.c701
-rw-r--r--plugins/expose.c1073
-rw-r--r--plugins/fade.c437
-rw-r--r--plugins/gconf.c1110
-rw-r--r--plugins/rotate.c807
-rw-r--r--plugins/wobbly.c1496
-rw-r--r--plugins/zoom.c690
-rw-r--r--src/Makefile.am22
-rw-r--r--src/display.c1149
-rw-r--r--src/event.c268
-rw-r--r--src/glxcompmgr.c146
-rw-r--r--src/option.c256
-rw-r--r--src/paint.c555
-rw-r--r--src/plugin.c358
-rw-r--r--src/privates.c68
-rw-r--r--src/readpng.c199
-rw-r--r--src/screen.c1294
-rw-r--r--src/texture.c286
-rw-r--r--src/window.c605
36 files changed, 12930 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..41c6efe
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+David Reveman <davidr@novell.com>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..69ef1bf
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,21 @@
+
+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. \ No newline at end of file
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..2de5452
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,9 @@
+glxcompmgr uses automake, in order to generate the Makefiles for glxcompmgr use:
+
+ $ autogen.sh
+
+After that, standard build procedures apply:
+
+ $ make
+ # make install
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..b888c76
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = include src plugins images
+
+EXTRA_DIST = \
+ COPYING \
+ glxcomp.pc.in
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = glxcomp.pc
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..36851dd
--- /dev/null
+++ b/README
@@ -0,0 +1,8 @@
+glxcompmgr - OpenGL compositing manager
+
+glxcompmgr is an OpenGL compositing manager that use GLX_MESA_render_texture
+for binding redirected top-level windows to texture objects. It has a flexible
+plug-in system and it is designed to run well on most graphics hardware.
+
+David Reveman
+davidr@novell.com
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..e81f989
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,13 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+autoreconf -v --install || exit 1
+cd $ORIGDIR || exit $?
+
+$srcdir/configure --enable-maintainer-mode "$@"
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..002ee8c
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,137 @@
+AC_PREREQ(2.57)
+
+AC_INIT([glxcompmgr], [0.0.1], [davidr@novell.com])
+
+AC_CONFIG_AUX_DIR(config)
+
+AM_INIT_AUTOMAKE([dist-bzip2])
+AC_CONFIG_HEADER([config.h])
+AM_MAINTAINER_MODE
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_LIBTOOL
+AC_HEADER_STDC
+AC_CHECK_HEADERS([stdlib.h sys/time.h unistd.h])
+
+if test "x$GCC" = "xyes"; then
+ case " $CFLAGS " in
+ *[[\ \ ]]-Wall[[\ \ ]]*) ;;
+ *) CFLAGS="$CFLAGS -Wall" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[[\ \ ]]-Wpointer-arith[[\ \ ]]*) ;;
+ *) CFLAGS="$CFLAGS -Wpointer-arith" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[[\ \ ]]-Wstrict-prototypes[[\ \ ]]*) ;;
+ *) CFLAGS="$CFLAGS -Wstrict-prototypes" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[[\ \ ]]-Wmissing-prototypes[[\ \ ]]*) ;;
+ *) CFLAGS="$CFLAGS -Wmissing-prototypes" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[[\ \ ]]-Wmissing-declarations[[\ \ ]]*) ;;
+ *) CFLAGS="$CFLAGS -Wmissing-declarations" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[[\ \ ]]-Wnested-externs[[\ \ ]]*) ;;
+ *) CFLAGS="$CFLAGS -Wnested-externs" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[[\ \ ]]-fno-strict-aliasing[[\ \ ]]*) ;;
+ *) CFLAGS="$CFLAGS -fno-strict-aliasing" ;;
+ esac
+
+ if test "x$enable_ansi" = "xyes"; then
+ case " $CFLAGS " in
+ *[[\ \ ]]-ansi[[\ \ ]]*) ;;
+ *) CFLAGS="$CFLAGS -ansi" ;;
+ esac
+
+ case " $CFLAGS " in
+ *[[\ \ ]]-pedantic[[\ \ ]]*) ;;
+ *) CFLAGS="$CFLAGS -pedantic" ;;
+ esac
+ fi
+fi
+
+AC_C_BIGENDIAN
+
+plugindir=$libdir/glxcomp
+AC_SUBST(plugindir)
+
+imagedir=$datadir/glxcomp
+AC_SUBST(imagedir)
+
+GLXCOMP_REQUIRES="libpng xcomposite xfixes xdamage"
+PKG_CHECK_MODULES(GLXCOMP, $GLXCOMP_REQUIRES)
+AC_SUBST(GLXCOMP_REQUIRES)
+
+AC_MSG_CHECKING(for GL_CFLAGS)
+AC_ARG_WITH(gl-cflags, [ --with-gl-cflags=CFLAGS ],
+ [GL_CFLAGS="$withval"],
+ [GL_CFLAGS=""])
+
+AC_MSG_RESULT($GL_CFLAGS)
+AC_MSG_CHECKING(for GL_LIBS)
+AC_ARG_WITH(gl-libs, [ --with-gl-libs=LIBS ],
+ [GL_LIBS="$withval"],
+ [GL_LIBS="-lGL"])
+AC_MSG_RESULT($GL_LIBS)
+
+AC_SUBST(GL_CFLAGS)
+AC_SUBST(GL_LIBS)
+
+AC_ARG_ENABLE(gconf,
+ [ --disable-gconf Disable gconf plugin],
+ [use_gconf=$enableval], [use_gconf=yes])
+
+if test "x$use_gconf" = "xyes"; then
+ PKG_CHECK_MODULES(GCONF, gconf-2.0, [use_gconf=yes], [use_gconf=no])
+fi
+
+AM_CONDITIONAL(GCONF_PLUGIN, test "x$use_gconf" = "xyes")
+if test "$use_gconf" = yes; then
+ AC_DEFINE(USE_GCONF, 1, [Build gconf plugin])
+fi
+
+AC_ARG_ENABLE(libsvg-cairo,
+ [ --enable-libsvg-cairo Enable svg support],
+ [use_libsvg_cairo=$enableval], [use_libsvg_cairo=no])
+
+if test "x$use_libsvg_cairo" = "xyes"; then
+ PKG_CHECK_MODULES(LIBSVG_CAIRO, libsvg-cairo,
+ [use_libsvg_cairo=yes],
+ [use_libsvg_cairo=no])
+fi
+
+AM_CONDITIONAL(USE_LIBSVG_CAIRO, [test x$use_libsvg_cairo = xyes])
+if test "$use_libsvg_cairo" = yes; then
+ AC_DEFINE(USE_LIBSVG_CAIRO, 1, [libsvg-cairo for SVG support])
+fi
+
+AC_OUTPUT([
+glxcomp.pc
+Makefile
+src/Makefile
+include/Makefile
+plugins/Makefile
+images/Makefile
+])
+
+echo ""
+echo "the following optional plugins will be compiled:"
+echo " gconf: $use_gconf"
+echo ""
+echo "and the following optional features will be compiled:"
+echo " svg: $use_libsvg_cairo"
+echo ""
diff --git a/glxcomp.pc.in b/glxcomp.pc.in
new file mode 100644
index 0000000..bd6ba1c
--- /dev/null
+++ b/glxcomp.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: glxcompmgr
+Description: OpenGL compositing manager
+Version: @VERSION@
+
+Requires: @GLXCOMP_REQUIRES@
+Libs: @GLXCOMP_LIBS@ @GL_LIBS@
+Cflags: @GLXCOMP_CFLAGS@ @GL_CFLAGS@ -I${includedir}/glxcomp
diff --git a/images/Makefile.am b/images/Makefile.am
new file mode 100644
index 0000000..f3b7aad
--- /dev/null
+++ b/images/Makefile.am
@@ -0,0 +1,8 @@
+imagesdir = $(imagedir)
+images_DATA = \
+ background.png \
+ window.png
+
+EXTRA_DIST = \
+ background.png \
+ window.png
diff --git a/images/background.png b/images/background.png
new file mode 100644
index 0000000..c3285c6
--- /dev/null
+++ b/images/background.png
Binary files differ
diff --git a/images/window.png b/images/window.png
new file mode 100644
index 0000000..06742e0
--- /dev/null
+++ b/images/window.png
Binary files differ
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..04b985e
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,4 @@
+glxcompincludedir = $(includedir)/glxcomp
+glxcompinclude_HEADERS = \
+ comp.h \
+ region.h
diff --git a/include/comp.h b/include/comp.h
new file mode 100644
index 0000000..808ba84
--- /dev/null
+++ b/include/comp.h
@@ -0,0 +1,942 @@
+/*
+ * 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>
+ */
+
+#ifndef _COMP_H
+#define _COMP_H
+
+#include <sys/time.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/Xdamage.h>
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+#include <region.h>
+
+typedef struct _CompPlugin CompPlugin;
+typedef struct _CompDisplay CompDisplay;
+typedef struct _CompScreen CompScreen;
+typedef struct _CompWindow CompWindow;
+typedef struct _CompTexture CompTexture;
+
+/* virtual modifiers */
+
+#define CompModAlt 0
+#define CompModMeta 1
+#define CompModSuper 2
+#define CompModHyper 3
+#define CompModModeSwitch 4
+#define CompModNumLock 5
+#define CompModScrollLock 6
+#define CompModNum 7
+
+#define CompAltMask (1 << 16)
+#define CompMetaMask (1 << 17)
+#define CompSuperMask (1 << 18)
+#define CompHyperMask (1 << 19)
+#define CompModeSwitchMask (1 << 20)
+#define CompNumLockMask (1 << 21)
+#define CompScrollLockMask (1 << 22)
+
+#define CompPressMask (1 << 23)
+#define CompReleaseMask (1 << 24)
+
+#define CompNoMask (1 << 25)
+
+#define OPAQUE 0xffff
+
+extern char *programName;
+extern char **programArgv;
+extern int programArgc;
+extern char *backgroundImage;
+extern char *windowImage;
+extern REGION emptyRegion;
+extern GLushort defaultColor[4];
+extern Window currentRoot;
+extern Bool testMode;
+extern Bool restartSignal;
+
+extern int defaultRefreshRate;
+extern char *defaultTextureFilter;
+
+#define RESTRICT_VALUE(value, min, max) \
+ (((value) < (min)) ? (min): ((value) > (max)) ? (max) : (value))
+
+
+/* privates.h */
+
+#define WRAP(priv, real, func, wrapFunc) \
+ (priv)->func = (real)->func; \
+ (real)->func = (wrapFunc)
+
+#define UNWRAP(priv, real, func) \
+ (real)->func = (priv)->func
+
+typedef union _CompPrivate {
+ void *ptr;
+ long val;
+ unsigned long uval;
+ void *(*fptr) (void);
+} CompPrivate;
+
+typedef int (*ReallocPrivatesProc) (int size, void *closure);
+
+int
+allocatePrivateIndex (int *len,
+ char **indices,
+ ReallocPrivatesProc reallocProc,
+ void *closure);
+
+void
+freePrivateIndex (int len,
+ char *indices,
+ int index);
+
+
+/* readpng.c */
+
+Bool
+readPng (const char *filename,
+ char **data,
+ unsigned int *width,
+ unsigned int *height);
+
+
+/* option.c */
+
+typedef enum {
+ CompOptionTypeBool,
+ CompOptionTypeInt,
+ CompOptionTypeFloat,
+ CompOptionTypeString,
+ CompOptionTypeColor,
+ CompOptionTypeBinding,
+ CompOptionTypeList
+} CompOptionType;
+
+typedef enum {
+ CompBindingTypeKey,
+ CompBindingTypeButton
+} CompBindingType;
+
+typedef struct _CompKeyBinding {
+ int keycode;
+ unsigned int modifiers;
+} CompKeyBinding;
+
+typedef struct _CompButtonBinding {
+ int button;
+ unsigned int modifiers;
+} CompButtonBinding;
+
+typedef struct {
+ CompBindingType type;
+ union {
+ CompKeyBinding key;
+ CompButtonBinding button;
+ } u;
+} CompBinding;
+
+typedef union _CompOptionValue CompOptionValue;
+
+typedef struct {
+ CompOptionType type;
+ CompOptionValue *value;
+ int nValue;
+} CompListValue;
+
+union _CompOptionValue {
+ Bool b;
+ int i;
+ float f;
+ char *s;
+ unsigned short c[4];
+ CompBinding bind;
+ CompListValue list;
+};
+
+typedef struct _CompOptionIntRestriction {
+ int min;
+ int max;
+} CompOptionIntRestriction;
+
+typedef struct _CompOptionFloatRestriction {
+ float min;
+ float max;
+ float precision;
+} CompOptionFloatRestriction;
+
+typedef struct _CompOptionStringRestriction {
+ char **string;
+ int nString;
+} CompOptionStringRestriction;
+
+typedef union {
+ CompOptionIntRestriction i;
+ CompOptionFloatRestriction f;
+ CompOptionStringRestriction s;
+} CompOptionRestriction;
+
+typedef struct _CompOption {
+ char *name;
+ char *shortDesc;
+ char *longDesc;
+ CompOptionType type;
+ CompOptionValue value;
+ CompOptionRestriction rest;
+} CompOption;
+
+typedef CompOption *(*DisplayOptionsProc) (CompDisplay *display, int *count);
+typedef CompOption *(*ScreenOptionsProc) (CompScreen *screen, int *count);
+
+CompOption *
+compFindOption (CompOption *option,
+ int nOption,
+ char *name,
+ int *index);
+
+Bool
+compSetBoolOption (CompOption *option,
+ CompOptionValue *value);
+
+Bool
+compSetIntOption (CompOption *option,
+ CompOptionValue *value);
+
+Bool
+compSetFloatOption (CompOption *option,
+ CompOptionValue *value);
+
+Bool
+compSetStringOption (CompOption *option,
+ CompOptionValue *value);
+
+Bool
+compSetColorOption (CompOption *option,
+ CompOptionValue *value);
+
+Bool
+compSetBindingOption (CompOption *option,
+ CompOptionValue *value);
+
+Bool
+compSetOptionList (CompOption *option,
+ CompOptionValue *value);
+
+
+/* display.c */
+
+#define COMP_DISPLAY_OPTION_ACTIVE_PLUGINS 0
+#define COMP_DISPLAY_OPTION_TEXTURE_FILTER 1
+#define COMP_DISPLAY_OPTION_NUM 2
+
+typedef CompOption *(*GetDisplayOptionsProc) (CompDisplay *display,
+ int *count);
+typedef Bool (*SetDisplayOptionProc) (CompDisplay *display,
+ char *name,
+ CompOptionValue *value);
+typedef Bool (*SetDisplayOptionForPluginProc) (CompDisplay *display,
+ char *plugin,
+ char *name,
+ CompOptionValue *value);
+
+typedef Bool (*InitPluginForDisplayProc) (CompPlugin *plugin,
+ CompDisplay *display);
+
+typedef void (*FiniPluginForDisplayProc) (CompPlugin *plugin,
+ CompDisplay *display);
+
+typedef void (*HandleEventProc) (CompDisplay *display,
+ XEvent *event);
+typedef void (*HandleDamageEventProc) (CompDisplay *display,
+ XDamageNotifyEvent *event);
+
+typedef Bool (*CallBackProc) (void *closure);
+
+struct _CompDisplay {
+ Display *display;
+ CompScreen *screens;
+
+ char *screenPrivateIndices;
+ int screenPrivateLen;
+
+ int compositeEvent, compositeError, compositeOpcode;
+ int damageEvent, damageError;
+
+ Bool shapeExtension;
+ int shapeEvent, shapeError;
+
+ Atom winTypeAtom;
+ Atom winDesktopAtom;
+ Atom winDockAtom;
+ Atom winToolbarAtom;
+ Atom winMenuAtom;
+ Atom winUtilAtom;
+ Atom winSplashAtom;
+ Atom winDialogAtom;
+ Atom winNormalAtom;
+ Atom winOpacityAtom;
+ Atom winActiveAtom;
+
+ Atom wmStateAtom;
+ Atom wmDeleteWindowAtom;
+
+ Atom xBackgroundAtom[2];
+
+ GLenum textureFilter;
+
+ unsigned int modMask[CompModNum];
+
+ CompOption opt[COMP_DISPLAY_OPTION_NUM];
+
+ CompOptionValue plugin;
+ Bool dirtyPluginList;
+
+ SetDisplayOptionProc setDisplayOption;
+ SetDisplayOptionForPluginProc setDisplayOptionForPlugin;
+
+ InitPluginForDisplayProc initPluginForDisplay;
+ FiniPluginForDisplayProc finiPluginForDisplay;
+
+ HandleEventProc handleEvent;
+ HandleDamageEventProc handleDamageEvent;
+
+ CompPrivate *privates;
+};
+
+extern CompDisplay *compDisplays;
+
+int
+allocateDisplayPrivateIndex (void);
+
+void
+freeDisplayPrivateIndex (int index);
+
+CompOption *
+compGetDisplayOptions (CompDisplay *display,
+ int *count);
+
+
+typedef int CompTimeoutHandle;
+
+CompTimeoutHandle
+compAddTimeout (int time,
+ CallBackProc callBack,
+ void *closure);
+
+void
+compRemoveTimeout (CompTimeoutHandle handle);
+
+int
+compCheckForError (void);
+
+Bool
+addDisplay (char *name,
+ char **plugin,
+ int nPlugin);
+
+CompScreen *
+findScreenAtDisplay (CompDisplay *d,
+ Window root);
+
+CompWindow *
+findWindowAtDisplay (CompDisplay *display,
+ Window id);
+
+unsigned int
+virtualToRealModMask (CompDisplay *d,
+ unsigned int modMask);
+
+void
+updateModifierMappings (CompDisplay *d);
+
+void
+eventLoop (void);
+
+
+/* event.c */
+
+#define EV_BUTTON(opt, event) \
+ ((opt)->value.bind.type == CompBindingTypeButton && \
+ (opt)->value.bind.u.button.button == (event)->xbutton.button && \
+ ((opt)->value.bind.u.button.modifiers & (event)->xbutton.state) == \
+ (opt)->value.bind.u.button.modifiers)
+
+#define EV_KEY(opt, event) \
+ ((opt)->value.bind.type == CompBindingTypeKey && \
+ (opt)->value.bind.u.key.keycode == (event)->xkey.keycode && \
+ ((opt)->value.bind.u.key.modifiers & (event)->xkey.state) == \
+ (opt)->value.bind.u.key.modifiers)
+
+void
+handleEvent (CompDisplay *display,
+ XEvent *event);
+
+void
+handleDamageEvent (CompDisplay *display,
+ XDamageNotifyEvent *event);
+
+
+/* paint.c */
+
+#define MULTIPLY_USHORT(us1, us2) \
+ (((GLuint) (us1) * (GLuint) (us2)) / 0xffff)
+
+/* 0.5 + 0.5 * tan (FOV) */
+#define BASE_Z_TRANSLATE 1.366025404f
+
+typedef struct _ScreenPaintAttrib {
+ GLfloat xRotate;
+ GLfloat yRotate;
+ GLfloat vRotate;
+ GLfloat xTranslate;
+ GLfloat yTranslate;
+ GLfloat zTranslate;
+} ScreenPaintAttrib;
+
+typedef struct _WindowPaintAttrib {
+ GLushort opacity;
+ GLfloat xTranslate;
+ GLfloat yTranslate;
+ GLfloat xScale;
+ GLfloat yScale;
+} WindowPaintAttrib;
+
+extern ScreenPaintAttrib defaultScreenPaintAttrib;
+extern WindowPaintAttrib defaultWindowPaintAttrib;
+
+#define X_WINDOW_TO_TEXTURE_SPACE(w, _x) ((w)->texture.dx * (_x))
+#define Y_WINDOW_TO_TEXTURE_SPACE(w, _y) \
+ ((w)->texture.dy * ((w)->height - (_y)))
+
+typedef void (*PreparePaintScreenProc) (CompScreen *screen,
+ int msSinceLastPaint);
+
+typedef void (*DonePaintScreenProc) (CompScreen *screen);
+
+#define PAINT_SCREEN_REGION_MASK (1 << 0)
+#define PAINT_SCREEN_FULL_MASK (1 << 1)
+#define PAINT_SCREEN_TRANSFORMED_MASK (1 << 2)
+#define PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK (1 << 3)
+
+typedef Bool (*PaintScreenProc) (CompScreen *screen,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ Region region,
+ unsigned int mask);
+
+typedef void (*PaintTransformedScreenProc) (CompScreen *screen,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ unsigned int mask);
+
+
+#define PAINT_WINDOW_SOLID_MASK (1 << 0)
+#define PAINT_WINDOW_TRANSLUCENT_MASK (1 << 1)
+#define PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK (1 << 2)
+
+typedef Bool (*PaintWindowProc) (CompWindow *window,
+ const WindowPaintAttrib *attrib,
+ Region region,
+ unsigned int mask);
+
+#define PAINT_BACKGROUND_ON_TRANSFORMED_SCREEN_MASK (1 << 0)
+#define PAINT_BACKGROUND_WITH_STENCIL_MASK (1 << 1)
+
+typedef void (*PaintBackgroundProc) (CompScreen *screen,
+ Region region,
+ unsigned int mask);
+
+
+void
+preparePaintScreen (CompScreen *screen,
+ int msSinceLastPaint);
+
+void
+donePaintScreen (CompScreen *screen);
+
+void
+paintTransformedScreen (CompScreen *screen,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ unsigned int mask);
+
+Bool
+paintScreen (CompScreen *screen,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ Region region,
+ unsigned int mask);
+
+Bool
+paintWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib,
+ Region region,
+ unsigned int mask);
+
+void
+paintBackground (CompScreen *screen,
+ Region region,
+ unsigned int mask);
+
+
+/* texture.c */
+
+#define POWER_OF_TWO(v) ((v & (v - 1)) == 0)
+
+typedef enum {
+ COMP_TEXTURE_FILTER_FAST,
+ COMP_TEXTURE_FILTER_GOOD
+} CompTextureFilter;
+
+struct _CompTexture {
+ GLuint name;
+ GLenum target;
+ GLfloat dx, dy;
+ GLXPixmap pixmap;
+ CompTextureFilter filter;
+};
+
+void
+initTexture (CompScreen *screen,
+ CompTexture *texture);
+
+void
+finiTexture (CompScreen *screen,
+ CompTexture *texture);
+
+Bool
+readImageToTexture (CompScreen *screen,
+ CompTexture *texture,
+ char *imageFileName,
+ unsigned int *width,
+ unsigned int *height);
+
+Bool
+bindPixmapToTexture (CompScreen *screen,
+ CompTexture *texture,
+ Pixmap pixmap,
+ int width,
+ int height,
+ int depth);
+
+void
+releasePixmapFromTexture (CompScreen *screen,
+ CompTexture *texture);
+
+void
+enableTexture (CompScreen *screen,
+ CompTexture *texture,
+ CompTextureFilter filter);
+
+void
+disableTexture (CompTexture *texture);
+
+
+/* screen.c */
+
+#define COMP_SCREEN_OPTION_REFRESH_RATE 0
+#define COMP_SCREEN_OPTION_NUM 1
+
+typedef void (*FuncPtr) (void);
+typedef FuncPtr (*GLXGetProcAddressProc) (const GLubyte *procName);
+
+#ifndef GLX_EXT_render_texture
+#define GLX_TEXTURE_TARGET_EXT 0x6001
+#define GLX_TEXTURE_2D_EXT 0x6002
+#define GLX_TEXTURE_RECTANGLE_EXT 0x6003
+#define GLX_NO_TEXTURE_EXT 0x6004
+#define GLX_FRONT_LEFT_EXT 0x6005
+#endif
+
+typedef Bool (*GLXBindTexImageProc) (Display *display,
+ GLXDrawable drawable,
+ int buffer);
+typedef Bool (*GLXReleaseTexImageProc) (Display *display,
+ GLXDrawable drawable,
+ int buffer);
+typedef Bool (*GLXQueryDrawableProc) (Display *display,
+ GLXDrawable drawable,
+ int attribute,
+ unsigned int *value);
+
+#define MAX_DEPTH 32
+
+typedef CompOption *(*GetScreenOptionsProc) (CompScreen *screen,
+ int *count);
+typedef Bool (*SetScreenOptionProc) (CompScreen *screen,
+ char *name,
+ CompOptionValue *value);
+typedef Bool (*SetScreenOptionForPluginProc) (CompScreen *screen,
+ char *plugin,
+ char *name,
+ CompOptionValue *value);
+
+typedef Bool (*InitPluginForScreenProc) (CompPlugin *plugin,
+ CompScreen *screen);
+
+typedef void (*FiniPluginForScreenProc) (CompPlugin *plugin,
+ CompScreen *screen);
+
+typedef void (*InvisibleWindowMoveProc) (CompWindow *w,
+ int dx,
+ int dy);
+
+
+typedef struct _CompKeyGrab {
+ int keycode;
+ unsigned int modifiers;
+ int count;
+} CompKeyGrab;
+
+typedef struct _CompButtonGrab {
+ int button;
+ unsigned int modifiers;
+ int count;
+} CompButtonGrab;
+
+typedef struct _CompGrab {
+ Bool active;
+ Cursor cursor;
+} CompGrab;
+
+struct _CompScreen {
+ CompScreen *next;
+ CompDisplay *display;
+ CompWindow *windows;
+ CompWindow *reverseWindows;
+
+ char *windowPrivateIndices;
+ int windowPrivateLen;
+
+ Colormap colormap;
+ int screenNum;
+ int width;
+ int height;
+ REGION region;
+ Region damage;
+ Bool allDamaged;
+ Window root;
+ Window fake[2];
+ XWindowAttributes attrib;
+ Window grabWindow;
+ XVisualInfo *glxPixmapVisuals[MAX_DEPTH + 1];
+ int textureRectangle;
+ int textureNonPowerOfTwo;
+ Cursor invisibleCursor;
+ XRectangle *exposeRects;
+ int sizeExpose;
+ int nExpose;
+ CompTexture backgroundTexture;
+ int backgroundWidth;
+ int backgroundHeight;
+ unsigned int pendingDestroys;
+ int desktopWindowCount;
+ KeyCode escapeKeyCode;
+
+ CompButtonGrab *buttonGrab;
+ int nButtonGrab;
+ CompKeyGrab *keyGrab;
+ int nKeyGrab;
+
+ CompGrab *grabs;
+ int grabSize;
+ int maxGrab;
+
+ int rasterX;
+ int rasterY;
+ struct timeval lastRedraw;
+ int nextRedraw;
+ int redrawTime;
+
+ GLint stencilRef;
+
+ Window activeWindow;
+
+ GLXGetProcAddressProc getProcAddress;
+ GLXBindTexImageProc bindTexImage;
+ GLXReleaseTexImageProc releaseTexImage;
+ GLXQueryDrawableProc queryDrawable;
+
+ GLXContext ctx;
+
+ CompOption opt[COMP_SCREEN_OPTION_NUM];
+
+ SetScreenOptionProc setScreenOption;
+ SetScreenOptionForPluginProc setScreenOptionForPlugin;
+
+ InitPluginForScreenProc initPluginForScreen;
+ FiniPluginForScreenProc finiPluginForScreen;
+
+ PreparePaintScreenProc preparePaintScreen;
+ DonePaintScreenProc donePaintScreen;
+ PaintScreenProc paintScreen;
+ PaintTransformedScreenProc paintTransformedScreen;
+ PaintBackgroundProc paintBackground;
+ PaintWindowProc paintWindow;
+ InvisibleWindowMoveProc invisibleWindowMove;
+
+ CompPrivate *privates;
+};
+
+int
+allocateScreenPrivateIndex (CompDisplay *display);
+
+void
+freeScreenPrivateIndex (CompDisplay *display,
+ int index);
+
+CompOption *
+compGetScreenOptions (CompScreen *screen,
+ int *count);
+
+void
+configureScreen (CompScreen *s,
+ XConfigureEvent *ce);
+
+void
+updateScreenBackground (CompScreen *screen,
+ CompTexture *texture);
+
+Bool
+addScreen (CompDisplay *display,
+ int screenNum);
+
+void
+damageScreenRegion (CompScreen *screen,
+ Region region);
+
+void
+damageScreen (CompScreen *screen);
+
+void
+insertWindowIntoScreen (CompScreen *s,
+ CompWindow *w,
+ Window aboveId);
+
+void
+unhookWindowFromScreen (CompScreen *s,
+ CompWindow *w);
+
+CompWindow *
+findWindowAtScreen (CompScreen *s,
+ Window id);
+
+CompWindow *
+findClientWindowAtScreen (CompScreen *s,
+ Window id);
+
+int
+pushScreenGrab (CompScreen *s,
+ Cursor cursor);
+
+void
+removeScreenGrab (CompScreen *s,
+ int index,
+ XPoint *restorePointer);
+
+Bool
+addScreenBinding (CompScreen *s,
+ CompBinding *binding);
+
+void
+removeScreenBinding (CompScreen *s,
+ CompBinding *binding);
+
+void
+updatePassiveGrabs (CompScreen *s);
+
+
+/* window.c */
+
+#define WINDOW_INVISIBLE(w) \
+ ((w)->attrib.map_state != IsViewable || \
+ (w)->attrib.x + (w)->width <= 0 || \
+ (w)->attrib.y + (w)->height <= 0 || \
+ (w)->attrib.x >= (w)->screen->width || \
+ (w)->attrib.y >= (w)->screen->height)
+
+typedef Bool (*InitPluginForWindowProc) (CompPlugin *plugin,
+ CompWindow *window);
+typedef void (*FiniPluginForWindowProc) (CompPlugin *plugin,
+ CompWindow *window);
+
+struct _CompWindow {
+ CompScreen *screen;
+ CompWindow *next;
+ CompWindow *prev;
+
+ int refcnt;
+ Window id;
+ Window client;
+ XWindowAttributes attrib;
+ Pixmap pixmap;
+ CompTexture texture;
+ Damage damage;
+ Bool alpha;
+ GLint width;
+ GLint height;
+ Region region;
+ Region clip;
+ Atom type;
+ Bool invisible;
+ GLushort opacity;
+ Bool destroyed;
+
+ CompPrivate *privates;
+};
+
+int
+allocateWindowPrivateIndex (CompScreen *screen);
+
+void
+freeWindowPrivateIndex (CompScreen *screen,
+ int index);
+
+
+Atom
+getWindowType (CompDisplay *display,
+ Window id);
+
+Window
+getActiveWindow (CompDisplay *display,
+ Window root);
+
+unsigned short
+getWindowOpacity (CompDisplay *display,
+ Window id);
+
+void
+updateWindowRegion (CompWindow *w);
+
+void
+addWindow (CompScreen *screen,
+ Window id,
+ Window aboveId);
+
+void
+removeWindow (CompWindow *w);
+
+void
+destroyWindow (CompWindow *w);
+
+void
+mapWindow (CompWindow *w);
+
+void
+unmapWindow (CompWindow *w);
+
+void
+bindWindow (CompWindow *w);
+
+void
+releaseWindow (CompWindow *w);
+
+void
+configureWindow (CompWindow *w,
+ XConfigureEvent *ce);
+
+void
+circulateWindow (CompWindow *w,
+ XCirculateEvent *ce);
+
+void
+addWindowDamage (CompWindow *w);
+
+void
+invisibleWindowMove (CompWindow *w,
+ int dx,
+ int dy);
+
+
+/* plugin.c */
+
+typedef Bool (*InitPluginProc) (CompPlugin *plugin);
+typedef void (*FiniPluginProc) (CompPlugin *plugin);
+
+typedef struct _CompPluginVTable {
+ char *name;
+ char *shortDesc;
+ char *longDesc;
+
+ InitPluginProc init;
+ FiniPluginProc fini;
+
+ InitPluginForDisplayProc initDisplay;
+ FiniPluginForDisplayProc finiDisplay;
+
+ InitPluginForScreenProc initScreen;
+ FiniPluginForScreenProc finiScreen;
+
+ InitPluginForWindowProc initWindow;
+ FiniPluginForWindowProc finiWindow;
+
+ GetDisplayOptionsProc getDisplayOptions;
+ SetDisplayOptionProc setDisplayOption;
+ GetScreenOptionsProc getScreenOptions;
+ SetScreenOptionProc setScreenOption;
+} CompPluginVTable;
+
+typedef CompPluginVTable *(*PluginGetInfoProc) (void);
+
+struct _CompPlugin {
+ CompPlugin *next;
+ void *dlhand;
+ CompPluginVTable *vTable;
+};
+
+CompPluginVTable *
+getCompPluginInfo (void);
+
+void
+screenInitPlugins (CompScreen *s);
+
+void
+screenFiniPlugins (CompScreen *s);
+
+void
+windowInitPlugins (CompWindow *w);
+
+void
+windowFiniPlugins (CompWindow *w);
+
+CompPlugin *
+findActivePlugin (char *name);
+
+CompPlugin *
+loadPlugin (char *plugin);
+
+void
+unloadPlugin (CompPlugin *p);
+
+Bool
+pushPlugin (CompPlugin *p);
+
+CompPlugin *
+popPlugin (void);
+
+#endif
diff --git a/include/region.h b/include/region.h
new file mode 100644
index 0000000..5ec983a
--- /dev/null
+++ b/include/region.h
@@ -0,0 +1,198 @@
+/* $Xorg: region.h,v 1.4 2001/02/09 02:03:40 xorgcvs Exp $ */
+/************************************************************************
+
+Copyright 1987, 1998 The Open Group
+
+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.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+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 Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL 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.
+
+************************************************************************/
+
+#ifndef _XREGION_H
+#define _XREGION_H
+
+typedef struct {
+ short x1, x2, y1, y2;
+} Box, BOX, BoxRec, *BoxPtr;
+
+typedef struct {
+ short x, y, width, height;
+}RECTANGLE, RectangleRec, *RectanglePtr;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef MAXSHORT
+#define MAXSHORT 32767
+#endif
+#ifndef MINSHORT
+#define MINSHORT -MAXSHORT
+#endif
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+
+/*
+ * clip region
+ */
+
+typedef struct _XRegion {
+ long size;
+ long numRects;
+ BOX *rects;
+ BOX extents;
+} REGION;
+
+/* Xutil.h contains the declaration:
+ * typedef struct _XRegion *Region;
+ */
+
+/* 1 if two BOXs overlap.
+ * 0 if two BOXs do not overlap.
+ * Remember, x2 and y2 are not in the region
+ */
+#define EXTENTCHECK(r1, r2) \
+ ((r1)->x2 > (r2)->x1 && \
+ (r1)->x1 < (r2)->x2 && \
+ (r1)->y2 > (r2)->y1 && \
+ (r1)->y1 < (r2)->y2)
+
+/*
+ * update region extents
+ */
+#define EXTENTS(r,idRect){\
+ if((r)->x1 < (idRect)->extents.x1)\
+ (idRect)->extents.x1 = (r)->x1;\
+ if((r)->y1 < (idRect)->extents.y1)\
+ (idRect)->extents.y1 = (r)->y1;\
+ if((r)->x2 > (idRect)->extents.x2)\
+ (idRect)->extents.x2 = (r)->x2;\
+ if((r)->y2 > (idRect)->extents.y2)\
+ (idRect)->extents.y2 = (r)->y2;\
+ }
+
+/*
+ * Check to see if there is enough memory in the present region.
+ */
+#define MEMCHECK(reg, rect, firstrect){\
+ if ((reg)->numRects >= ((reg)->size - 1)){\
+ (firstrect) = (BOX *) Xrealloc \
+ ((char *)(firstrect), (unsigned) (2 * (sizeof(BOX)) * ((reg)->size)));\
+ if ((firstrect) == 0)\
+ return(0);\
+ (reg)->size *= 2;\
+ (rect) = &(firstrect)[(reg)->numRects];\
+ }\
+ }
+
+/* this routine checks to see if the previous rectangle is the same
+ * or subsumes the new rectangle to add.
+ */
+
+#define CHECK_PREVIOUS(Reg, R, Rx1, Ry1, Rx2, Ry2)\
+ (!(((Reg)->numRects > 0)&&\
+ ((R-1)->y1 == (Ry1)) &&\
+ ((R-1)->y2 == (Ry2)) &&\
+ ((R-1)->x1 <= (Rx1)) &&\
+ ((R-1)->x2 >= (Rx2))))
+
+/* add a rectangle to the given Region */
+#define ADDRECT(reg, r, rx1, ry1, rx2, ry2){\
+ if (((rx1) < (rx2)) && ((ry1) < (ry2)) &&\
+ CHECK_PREVIOUS((reg), (r), (rx1), (ry1), (rx2), (ry2))){\
+ (r)->x1 = (rx1);\
+ (r)->y1 = (ry1);\
+ (r)->x2 = (rx2);\
+ (r)->y2 = (ry2);\
+ EXTENTS((r), (reg));\
+ (reg)->numRects++;\
+ (r)++;\
+ }\
+ }
+
+
+
+/* add a rectangle to the given Region */
+#define ADDRECTNOX(reg, r, rx1, ry1, rx2, ry2){\
+ if ((rx1 < rx2) && (ry1 < ry2) &&\
+ CHECK_PREVIOUS((reg), (r), (rx1), (ry1), (rx2), (ry2))){\
+ (r)->x1 = (rx1);\
+ (r)->y1 = (ry1);\
+ (r)->x2 = (rx2);\
+ (r)->y2 = (ry2);\
+ (reg)->numRects++;\
+ (r)++;\
+ }\
+ }
+
+#define EMPTY_REGION(pReg) pReg->numRects = 0
+
+#define REGION_NOT_EMPTY(pReg) pReg->numRects
+
+#define INBOX(r, x, y) \
+ ( ( ((r).x2 > x)) && \
+ ( ((r).x1 <= x)) && \
+ ( ((r).y2 > y)) && \
+ ( ((r).y1 <= y)) )
+
+/*
+ * number of points to buffer before sending them off
+ * to scanlines() : Must be an even number
+ */
+#define NUMPTSTOBUFFER 200
+
+/*
+ * used to allocate buffers for points and link
+ * the buffers together
+ */
+typedef struct _POINTBLOCK {
+ XPoint pts[NUMPTSTOBUFFER];
+ struct _POINTBLOCK *next;
+} POINTBLOCK;
+
+#endif
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
new file mode 100644
index 0000000..73cc860
--- /dev/null
+++ b/plugins/Makefile.am
@@ -0,0 +1,49 @@
+libfade_la_LDFLAGS = -avoid-version
+libfade_la_LIBADD = @GLXCOMP_LIBS@
+libfade_la_SOURCES = fade.c
+
+libcube_la_LDFLAGS = -avoid-version
+libcube_la_LIBADD = @GLXCOMP_LIBS@ @LIBSVG_CAIRO_LIBS@
+libcube_la_SOURCES = cube.c
+
+librotate_la_LDFLAGS = -avoid-version
+librotate_la_LIBADD = @GLXCOMP_LIBS@
+librotate_la_SOURCES = rotate.c
+
+libzoom_la_LDFLAGS = -avoid-version
+libzoom_la_LIBADD = @GLXCOMP_LIBS@
+libzoom_la_SOURCES = zoom.c
+
+libexpose_la_LDFLAGS = -avoid-version
+libexpose_la_LIBADD = @GLXCOMP_LIBS@
+libexpose_la_SOURCES = expose.c
+
+libwobbly_la_LDFLAGS = -avoid-version
+libwobbly_la_LIBADD = @GLXCOMP_LIBS@
+libwobbly_la_SOURCES = wobbly.c
+
+if GCONF_PLUGIN
+libgconf_la_LDFLAGS = -avoid-version
+libgconf_la_LIBADD = @GLXCOMP_LIBS@ @GCONF_LIBS@
+libgconf_la_SOURCES = gconf.c
+libgconf_library = libgconf.la
+libgconf_includes = @GCONF_CFLAGS@
+endif
+
+INCLUDES = \
+ @GLXCOMP_CFLAGS@ \
+ @LIBSVG_CAIRO_CFLAGS@ \
+ @GCONF_CFLAGS@ \
+ -I$(top_srcdir)/include
+
+moduledir = $(plugindir)
+
+module_LTLIBRARIES = \
+ libgconf.la \
+ libfade.la \
+ libcube.la \
+ librotate.la \
+ libzoom.la \
+ libexpose.la \
+ libwobbly.la \
+ $(libgconf_library)
diff --git a/plugins/cube.c b/plugins/cube.c
new file mode 100644
index 0000000..03bb793
--- /dev/null
+++ b/plugins/cube.c
@@ -0,0 +1,701 @@
+/*
+ * 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
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/time.h>
+
+#ifdef USE_LIBSVG_CAIRO
+#include <cairo-xlib.h>
+#include <svg-cairo.h>
+#endif
+
+#include <comp.h>
+
+#define CUBE_COLOR_RED_DEFAULT 0xffff
+#define CUBE_COLOR_GREEN_DEFAULT 0xffff
+#define CUBE_COLOR_BLUE_DEFAULT 0xffff
+
+#define CUBE_NEXT_KEY_DEFAULT "space"
+#define CUBE_NEXT_MODIFIERS_DEFAULT CompPressMask
+
+#define CUBE_PREV_KEY_DEFAULT "BackSpace"
+#define CUBE_PREV_MODIFIERS_DEFAULT CompPressMask
+
+static int displayPrivateIndex;
+
+typedef struct _CubeDisplay {
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+} CubeDisplay;
+
+#define CUBE_SCREEN_OPTION_COLOR 0
+#define CUBE_SCREEN_OPTION_SVGS 1
+#define CUBE_SCREEN_OPTION_NEXT 2
+#define CUBE_SCREEN_OPTION_PREV 3
+#define CUBE_SCREEN_OPTION_NUM 4
+
+typedef struct _CubeScreen {
+ PaintTransformedScreenProc paintTransformedScreen;
+ PaintBackgroundProc paintBackground;
+
+ CompOption opt[CUBE_SCREEN_OPTION_NUM];
+
+ int xrotations;
+ Bool paintTopBottom;
+ GLushort color[3];
+ GLfloat tc[8];
+
+ Pixmap pixmap;
+ CompTexture texture;
+
+#ifdef USE_LIBSVG_CAIRO
+ cairo_t *cr;
+ svg_cairo_t *svgc;
+ int svgNFile;
+ int svgCurFile;
+ CompOptionValue *svgFiles;
+#endif
+
+} CubeScreen;
+
+#define GET_CUBE_DISPLAY(d) \
+ ((CubeDisplay *) (d)->privates[displayPrivateIndex].ptr)
+
+#define CUBE_DISPLAY(d) \
+ CubeDisplay *cd = GET_CUBE_DISPLAY (d)
+
+#define GET_CUBE_SCREEN(s, cd) \
+ ((CubeScreen *) (s)->privates[(cd)->screenPrivateIndex].ptr)
+
+#define CUBE_SCREEN(s) \
+ CubeScreen *cs = GET_CUBE_SCREEN (s, GET_CUBE_DISPLAY (s->display))
+
+#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
+
+#ifdef USE_LIBSVG_CAIRO
+static void
+cubeInitSvg (CompScreen *s)
+
+{
+ CUBE_SCREEN (s);
+
+ cs->pixmap = None;
+ cs->cr = 0;
+ cs->svgc = 0;
+}
+
+static void
+cubeFiniSvg (CompScreen *s)
+
+{
+ CUBE_SCREEN (s);
+
+ if (cs->svgc)
+ svg_cairo_destroy (cs->svgc);
+
+ if (cs->cr)
+ cairo_destroy (cs->cr);
+
+ if (cs->pixmap)
+ XFreePixmap (s->display->display, cs->pixmap);
+}
+
+static void
+cubeLoadSvg (CompScreen *s,
+ int n)
+{
+ int width, height;
+
+ CUBE_SCREEN (s);
+
+ if (!cs->svgNFile)
+ {
+ finiTexture (s, &cs->texture);
+ initTexture (s, &cs->texture);
+ cubeFiniSvg (s);
+ cubeInitSvg (s);
+ return;
+ }
+
+ if (!cs->pixmap)
+ {
+ cairo_surface_t *surface;
+ Visual *visual;
+ int depth;
+
+ depth = DefaultDepth (s->display->display, s->screenNum);
+ cs->pixmap = XCreatePixmap (s->display->display, s->root,
+ s->width, s->height,
+ depth);
+
+ if (!bindPixmapToTexture (s, &cs->texture, cs->pixmap,
+ s->width, s->height, depth))
+ {
+ fprintf (stderr, "%s: Couldn't bind slide pixmap 0x%x to "
+ "texture\n", programName, (int) cs->pixmap);
+ }
+
+ switch (cs->texture.target) {
+ case GL_TEXTURE_RECTANGLE_ARB:
+ cs->tc[2] = cs->tc[4] = s->width;
+ cs->tc[5] = cs->tc[7] = s->height;
+ break;
+ case GL_TEXTURE_2D:
+ default:
+ cs->tc[2] = cs->tc[4] = 1.0f;
+ cs->tc[5] = cs->tc[7] = 1.0f;
+ break;
+ }
+
+ visual = DefaultVisual (s->display->display, s->screenNum);
+ surface = cairo_xlib_surface_create (s->display->display,
+ cs->pixmap, visual,
+ s->width, s->height);
+ cs->cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
+ }
+
+ cs->svgCurFile = n % cs->svgNFile;
+
+ if (cs->svgc)
+ svg_cairo_destroy (cs->svgc);
+
+ if (svg_cairo_create (&cs->svgc))
+ {
+ fprintf (stderr, "%s: Failed to create svg_cairo_t.\n",
+ programName);
+ return;
+ }
+
+ svg_cairo_set_viewport_dimension (cs->svgc, s->width, s->height);
+
+ if (svg_cairo_parse (cs->svgc, cs->svgFiles[cs->svgCurFile].s))
+ {
+ fprintf (stderr, "%s: Failed to load svg: %s.\n",
+ programName, cs->svgFiles[cs->svgCurFile].s);
+ return;
+ }
+
+ svg_cairo_get_size (cs->svgc, &width, &height);
+
+ cairo_save (cs->cr);
+ cairo_set_source_rgb (cs->cr,
+ (double) cs->color[0] / 0xffff,
+ (double) cs->color[1] / 0xffff,
+ (double) cs->color[2] / 0xffff);
+ cairo_rectangle (cs->cr, 0, 0, s->width, s->height);
+ cairo_fill (cs->cr);
+
+ cairo_scale (cs->cr,
+ (double) s->width / width,
+ (double) s->height / height);
+
+ svg_cairo_render (cs->svgc, cs->cr);
+ cairo_restore (cs->cr);
+}
+#endif
+
+static CompOption *
+cubeGetScreenOptions (CompScreen *screen,
+ int *count)
+{
+ CUBE_SCREEN (screen);
+
+ *count = NUM_OPTIONS (cs);
+ return cs->opt;
+}
+
+static Bool
+cubeSetScreenOption (CompScreen *screen,
+ char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ CUBE_SCREEN (screen);
+
+ o = compFindOption (cs->opt, NUM_OPTIONS (cs), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index) {
+ case CUBE_SCREEN_OPTION_COLOR:
+ if (compSetColorOption (o, value))
+ {
+ memcpy (cs->color, o->value.c, sizeof (cs->color));
+ damageScreen (screen);
+ return TRUE;
+ }
+ break;
+ case CUBE_SCREEN_OPTION_SVGS:
+ if (compSetOptionList (o, value))
+ {
+
+#ifdef USE_LIBSVG_CAIRO
+ cs->svgFiles = cs->opt[CUBE_SCREEN_OPTION_SVGS].value.list.value;
+ cs->svgNFile = cs->opt[CUBE_SCREEN_OPTION_SVGS].value.list.nValue;
+
+ cubeLoadSvg (screen, cs->svgCurFile);
+ damageScreen (screen);
+#endif
+
+ return TRUE;
+ }
+ break;
+ case CUBE_SCREEN_OPTION_NEXT:
+ case CUBE_SCREEN_OPTION_PREV:
+ if (compSetBindingOption (o, value))
+ return TRUE;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static void
+cubeScreenInitOptions (CubeScreen *cs,
+ Display *display)
+{
+ CompOption *o;
+
+ o = &cs->opt[CUBE_SCREEN_OPTION_COLOR];
+ o->name = "color";
+ o->shortDesc = "Cube Color";
+ o->longDesc = "Color of top and bottom sides of the cube";
+ o->type = CompOptionTypeColor;
+ o->value.c[0] = CUBE_COLOR_RED_DEFAULT;
+ o->value.c[1] = CUBE_COLOR_GREEN_DEFAULT;
+ o->value.c[2] = CUBE_COLOR_BLUE_DEFAULT;
+ o->value.c[3] = 0xffff;
+
+ o = &cs->opt[CUBE_SCREEN_OPTION_SVGS];
+ o->name = "svgs";
+ o->shortDesc = "SVG files";
+ o->longDesc = "List of SVG files rendered on top face of cube";
+ o->type = CompOptionTypeList;
+ o->value.list.type = CompOptionTypeString;
+ o->value.list.nValue = 0;
+ o->value.list.value = 0;
+ o->rest.s.string = 0;
+ o->rest.s.nString = 0;
+
+ o = &cs->opt[CUBE_SCREEN_OPTION_NEXT];
+ o->name = "next_slide";
+ o->shortDesc = "Next Slide";
+ o->longDesc = "Adavence to next slide";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = CUBE_NEXT_MODIFIERS_DEFAULT;
+ o->value.bind.u.key.keycode =
+ XKeysymToKeycode (display, XStringToKeysym (CUBE_NEXT_KEY_DEFAULT));
+
+ o = &cs->opt[CUBE_SCREEN_OPTION_PREV];
+ o->name = "prev_slide";
+ o->shortDesc = "Previous Slide";
+ o->longDesc = "Go back to previous slide";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = CUBE_PREV_MODIFIERS_DEFAULT;
+ o->value.bind.u.key.keycode =
+ XKeysymToKeycode (display, XStringToKeysym (CUBE_PREV_KEY_DEFAULT));
+}
+
+static void
+cubeTranslateWindows (CompScreen *s,
+ int tx)
+{
+ CompWindow *w;
+
+ if (tx == 0)
+ return;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (w->attrib.map_state != IsViewable)
+ continue;
+
+ if (w->type == s->display->winDesktopAtom ||
+ w->type == s->display->winDockAtom)
+ continue;
+
+ (*s->invisibleWindowMove) (w, tx, 0);
+ }
+}
+
+static void
+cubePaintTransformedScreen (CompScreen *s,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ unsigned int mask)
+{
+ ScreenPaintAttrib sa = defaultScreenPaintAttrib;
+ int xMove = 0;
+
+ CUBE_SCREEN (s);
+
+ sa.xTranslate = sAttrib->xTranslate;
+ sa.yTranslate = sAttrib->yTranslate;
+ sa.zTranslate = sAttrib->zTranslate;
+
+ if (sAttrib->xRotate > 0.0f)
+ {
+ cs->xrotations = (int) sAttrib->xRotate / 90;
+ sa.xRotate = sAttrib->xRotate - (cs->xrotations * 90.0f);
+ }
+ else
+ {
+ cs->xrotations = (int) sAttrib->xRotate / 90;
+ sa.xRotate = (sAttrib->xRotate - cs->xrotations * 90.0f) + 90.0f;
+ cs->xrotations--;
+ }
+
+ if (sa.vRotate > 100.0f)
+ sa.vRotate = 100.0f;
+ else if (sAttrib->vRotate < -100.0f)
+ sa.vRotate = -100.0f;
+ else
+ sa.vRotate = sAttrib->vRotate;
+
+ if (mask & PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK)
+ glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ else
+ glClear (GL_COLOR_BUFFER_BIT);
+
+ UNWRAP (cs, s, paintTransformedScreen);
+
+ cs->paintTopBottom = TRUE;
+
+ if (sAttrib->xRotate != 0.0f)
+ {
+ xMove = cs->xrotations * s->width;
+ cubeTranslateWindows (s, xMove);
+
+ (*s->paintTransformedScreen) (s, &sa, wAttrib, mask);
+
+ xMove += s->width;
+ cubeTranslateWindows (s, s->width);
+
+ cs->paintTopBottom = FALSE;
+ }
+
+ sa.yRotate -= 90.0f;
+
+ (*s->paintTransformedScreen) (s, &sa, wAttrib, mask);
+
+ cubeTranslateWindows (s, -xMove);
+
+ WRAP (cs, s, paintTransformedScreen, cubePaintTransformedScreen);
+}
+
+static void
+cubePaintBackground (CompScreen *s,
+ Region region,
+ unsigned int mask)
+{
+ GLint stencilRef = s->stencilRef;
+
+ CUBE_SCREEN (s);
+
+ if (cs->paintTopBottom)
+ {
+ int first, count, rot;
+ GLfloat data[] = {
+ /* top */
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, s->width, 0.0f, 0.0f,
+
+ 0.0f, 0.0f, s->width, 0.0f, -1.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, -1.0f,
+
+ /* bottom */
+ 0.0f, 0.0f, 0.0f, s->height, -1.0f,
+ 0.0f, 0.0f, s->width, s->height, -1.0f,
+
+ 0.0f, 0.0f, s->width, s->height, 0.0f,
+ 0.0f, 0.0f, 0.0f, s->height, 0.0f
+ };
+
+ rot = 2 * cs->xrotations;
+
+#define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b))
+
+ data[0] = cs->tc[MOD (0 - rot, 8)];
+ data[1] = cs->tc[MOD (1 - rot, 8)];
+ data[5] = cs->tc[MOD (2 - rot, 8)];
+ data[6] = cs->tc[MOD (3 - rot, 8)];
+
+ data[10] = cs->tc[MOD (4 - rot, 8)];
+ data[11] = cs->tc[MOD (5 - rot, 8)];
+ data[15] = cs->tc[MOD (6 - rot, 8)];
+ data[16] = cs->tc[MOD (7 - rot, 8)];
+
+#undef MOD
+
+ first = 0;
+
+ glVertexPointer (3, GL_FLOAT, sizeof (GLfloat) * 5, data + 2);
+ glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat) * 5, data);
+
+ if (cs->texture.name)
+ {
+ if (mask & PAINT_BACKGROUND_ON_TRANSFORMED_SCREEN_MASK)
+ enableTexture (s, &cs->texture, COMP_TEXTURE_FILTER_GOOD);
+ else
+ enableTexture (s, &cs->texture, COMP_TEXTURE_FILTER_FAST);
+
+ glDrawArrays (GL_QUADS, first, 4);
+
+ disableTexture (&cs->texture);
+
+ first += 4;
+ count = 4;
+ }
+ else
+ count = 8;
+
+ glColor3usv (cs->color);
+ glDrawArrays (GL_QUADS, first, count);
+ glColor4usv (defaultColor);
+ }
+ else
+ s->stencilRef++;
+
+ UNWRAP (cs, s, paintBackground);
+ (*s->paintBackground) (s, region, mask);
+ WRAP (cs, s, paintBackground, cubePaintBackground);
+
+ s->stencilRef = stencilRef;
+}
+
+#ifdef USE_LIBSVG_CAIRO
+static void
+cubeHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ CompScreen *s;
+
+ CUBE_DISPLAY (d);
+
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ s = findScreenAtDisplay (d, event->xkey.root);
+ if (s)
+ {
+ CUBE_SCREEN (s);
+
+ if (EV_KEY (&cs->opt[CUBE_SCREEN_OPTION_NEXT], event))
+ {
+ cubeLoadSvg (s, (cs->svgCurFile + 1) % cs->svgNFile);
+ damageScreen (s);
+ }
+
+ if (EV_KEY (&cs->opt[CUBE_SCREEN_OPTION_PREV], event))
+ {
+ cubeLoadSvg (s, (cs->svgCurFile - 1 + cs->svgNFile) %
+ cs->svgNFile);
+ damageScreen (s);
+ }
+ }
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ s = findScreenAtDisplay (d, event->xbutton.root);
+ if (s)
+ {
+ CUBE_SCREEN (s);
+
+ if (EV_BUTTON (&cs->opt[CUBE_SCREEN_OPTION_NEXT], event))
+ {
+ cubeLoadSvg (s, (cs->svgCurFile + 1) % cs->svgNFile);
+ damageScreen (s);
+ }
+
+ if (EV_BUTTON (&cs->opt[CUBE_SCREEN_OPTION_PREV], event))
+ {
+ cubeLoadSvg (s, (cs->svgCurFile - 1 + cs->svgNFile) %
+ cs->svgNFile);
+ damageScreen (s);
+ }
+ }
+ default:
+ break;
+ }
+
+ UNWRAP (cd, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (cd, d, handleEvent, cubeHandleEvent);
+}
+#endif
+
+static Bool
+cubeInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ CubeDisplay *cd;
+
+ cd = malloc (sizeof (CubeDisplay));
+ if (!cd)
+ return FALSE;
+
+ cd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (cd->screenPrivateIndex < 0)
+ {
+ free (cd);
+ return FALSE;
+ }
+
+#ifdef USE_LIBSVG_CAIRO
+ WRAP (cd, d, handleEvent, cubeHandleEvent);
+#endif
+
+ d->privates[displayPrivateIndex].ptr = cd;
+
+ return TRUE;
+}
+
+static void
+cubeFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ CUBE_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, cd->screenPrivateIndex);
+
+#ifdef USE_LIBSVG_CAIRO
+ UNWRAP (cd, d, handleEvent);
+#endif
+
+ free (cd);
+}
+
+static Bool
+cubeInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ CubeScreen *cs;
+
+ CUBE_DISPLAY (s->display);
+
+ cs = malloc (sizeof (CubeScreen));
+ if (!cs)
+ return FALSE;
+
+ cs->tc[0] = cs->tc[1] = cs->tc[2] = cs->tc[3] = 0.0f;
+ cs->tc[4] = cs->tc[5] = cs->tc[6] = cs->tc[7] = 0.0f;
+
+ cs->color[0] = CUBE_COLOR_RED_DEFAULT;
+ cs->color[1] = CUBE_COLOR_GREEN_DEFAULT;
+ cs->color[2] = CUBE_COLOR_BLUE_DEFAULT;
+
+ s->privates[cd->screenPrivateIndex].ptr = cs;
+
+ cs->paintTopBottom = FALSE;
+
+ initTexture (s, &cs->texture);
+
+#ifdef USE_LIBSVG_CAIRO
+ cubeInitSvg (s);
+
+ cs->svgFiles = 0;
+ cs->svgNFile = 0;
+ cs->svgCurFile = 0;
+#endif
+
+ cubeScreenInitOptions (cs, s->display->display);
+
+ WRAP (cs, s, paintTransformedScreen, cubePaintTransformedScreen);
+ WRAP (cs, s, paintBackground, cubePaintBackground);
+
+ return TRUE;
+}
+
+static void
+cubeFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ CUBE_SCREEN (s);
+
+ UNWRAP (cs, s, paintTransformedScreen);
+ UNWRAP (cs, s, paintBackground);
+
+ finiTexture (s, &cs->texture);
+
+#ifdef USE_LIBSVG_CAIRO
+ cubeFiniSvg (s);
+#endif
+
+ free (cs);
+}
+
+static Bool
+cubeInit (CompPlugin *p)
+{
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+cubeFini (CompPlugin *p)
+{
+ if (displayPrivateIndex >= 0)
+ freeDisplayPrivateIndex (displayPrivateIndex);
+}
+
+CompPluginVTable cubeVTable = {
+ "cube",
+ "Desktop Cube",
+ "Place windows on cube",
+ cubeInit,
+ cubeFini,
+ cubeInitDisplay,
+ cubeFiniDisplay,
+ cubeInitScreen,
+ cubeFiniScreen,
+ 0, /* InitWindow */
+ 0, /* FiniWindow */
+ 0, /* GetDisplayOptions */
+ 0, /* SetDisplayOption */
+ cubeGetScreenOptions,
+ cubeSetScreenOption
+};
+
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &cubeVTable;
+}
diff --git a/plugins/expose.c b/plugins/expose.c
new file mode 100644
index 0000000..62900d4
--- /dev/null
+++ b/plugins/expose.c
@@ -0,0 +1,1073 @@
+/*
+ * 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 <math.h>
+#include <sys/time.h>
+
+#include <X11/cursorfont.h>
+
+#include <comp.h>
+
+#define EXPOSE_SPACING_DEFAULT 25
+#define EXPOSE_SPACING_MIN 0
+#define EXPOSE_SPACING_MAX 250
+
+#define EXPOSE_SLOPPY_FOCUS_DEFAULT FALSE
+
+#define EXPOSE_INITIATE_KEY_DEFAULT "Tab"
+#define EXPOSE_INITIATE_MODIFIERS_DEFAULT (CompPressMask | CompSuperMask)
+
+#define EXPOSE_TERMINATE_KEY_DEFAULT "Super_L"
+#define EXPOSE_TERMINATE_MODIFIERS_DEFAULT CompReleaseMask
+
+#define EXPOSE_NEXT_WINDOW_KEY_DEFAULT "Tab"
+#define EXPOSE_NEXT_WINDOW_MODIFIERS_DEFAULT (CompPressMask | CompSuperMask)
+
+#define EXPOSE_STATE_NONE 0
+#define EXPOSE_STATE_OUT 1
+#define EXPOSE_STATE_WAIT 2
+#define EXPOSE_STATE_IN 3
+
+static int displayPrivateIndex;
+
+typedef struct _ExposeSlot {
+ int x1, y1, x2, y2;
+ int line;
+} ExposeSlot;
+
+typedef struct _ExposeDisplay {
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+} ExposeDisplay;
+
+#define EXPOSE_SCREEN_OPTION_SPACING 0
+#define EXPOSE_SCREEN_OPTION_SLOPPY_FOCUS 1
+#define EXPOSE_SCREEN_OPTION_INITIATE 2
+#define EXPOSE_SCREEN_OPTION_TERMINATE 3
+#define EXPOSE_SCREEN_OPTION_NEXT_WINDOW 4
+#define EXPOSE_SCREEN_OPTION_NUM 5
+
+typedef struct _ExposeScreen {
+ int windowPrivateIndex;
+
+ PreparePaintScreenProc preparePaintScreen;
+ DonePaintScreenProc donePaintScreen;
+ PaintScreenProc paintScreen;
+ PaintWindowProc paintWindow;
+
+ CompOption opt[EXPOSE_SCREEN_OPTION_NUM];
+
+ int spacing;
+
+ int grabIndex;
+
+ int state;
+ int moreAdjust;
+
+ Cursor cursor;
+
+ ExposeSlot *slots;
+ int slotsSize;
+ int nSlots;
+
+ int *line;
+ int lineSize;
+ int nLine;
+
+ /* only used for sorting */
+ CompWindow **windows;
+ int windowsSize;
+ int nWindows;
+
+ GLfloat scale;
+} ExposeScreen;
+
+typedef struct _ExposeWindow {
+ ExposeSlot *slot;
+
+ GLfloat xVelocity, yVelocity, scaleVelocity;
+ GLfloat scale;
+ GLfloat tx, ty;
+ Bool adjust;
+} ExposeWindow;
+
+
+#define GET_EXPOSE_DISPLAY(d) \
+ ((ExposeDisplay *) (d)->privates[displayPrivateIndex].ptr)
+
+#define EXPOSE_DISPLAY(d) \
+ ExposeDisplay *ed = GET_EXPOSE_DISPLAY (d)
+
+#define GET_EXPOSE_SCREEN(s, ed) \
+ ((ExposeScreen *) (s)->privates[(ed)->screenPrivateIndex].ptr)
+
+#define EXPOSE_SCREEN(s) \
+ ExposeScreen *es = GET_EXPOSE_SCREEN (s, GET_EXPOSE_DISPLAY (s->display))
+
+#define GET_EXPOSE_WINDOW(w, es) \
+ ((ExposeWindow *) (w)->privates[(es)->windowPrivateIndex].ptr)
+
+#define EXPOSE_WINDOW(w) \
+ ExposeWindow *ew = GET_EXPOSE_WINDOW (w, \
+ GET_EXPOSE_SCREEN (w->screen, \
+ GET_EXPOSE_DISPLAY (w->screen->display)))
+
+#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
+
+static CompOption *
+exposeGetScreenOptions (CompScreen *screen,
+ int *count)
+{
+ EXPOSE_SCREEN (screen);
+
+ *count = NUM_OPTIONS (es);
+ return es->opt;
+}
+
+static Bool
+exposeSetScreenOption (CompScreen *screen,
+ char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ EXPOSE_SCREEN (screen);
+
+ o = compFindOption (es->opt, NUM_OPTIONS (es), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index) {
+ case EXPOSE_SCREEN_OPTION_SPACING:
+ if (compSetIntOption (o, value))
+ {
+ es->spacing = o->value.i;
+ return TRUE;
+ }
+ break;
+ case EXPOSE_SCREEN_OPTION_SLOPPY_FOCUS:
+ if (compSetBoolOption (o, value))
+ return TRUE;
+ break;
+ case EXPOSE_SCREEN_OPTION_INITIATE:
+ if (addScreenBinding (screen, &value->bind))
+ {
+ removeScreenBinding (screen, &o->value.bind);
+
+ if (compSetBindingOption (o, value))
+ return TRUE;
+ }
+ break;
+ case EXPOSE_SCREEN_OPTION_TERMINATE:
+ case EXPOSE_SCREEN_OPTION_NEXT_WINDOW:
+ if (compSetBindingOption (o, value))
+ return TRUE;
+ break;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static void
+exposeScreenInitOptions (ExposeScreen *es,
+ Display *display)
+{
+ CompOption *o;
+
+ o = &es->opt[EXPOSE_SCREEN_OPTION_SPACING];
+ o->name = "spacing";
+ o->shortDesc = "Spacing";
+ o->longDesc = "Space between windows";
+ o->type = CompOptionTypeInt;
+ o->value.i = EXPOSE_SPACING_DEFAULT;
+ o->rest.i.min = EXPOSE_SPACING_MIN;
+ o->rest.i.max = EXPOSE_SPACING_MAX;
+
+ o = &es->opt[EXPOSE_SCREEN_OPTION_SLOPPY_FOCUS];
+ o->name = "sloppy_focus";
+ o->shortDesc = "Sloppy Focus";
+ o->longDesc = "Focus window when mouse moves over them";
+ o->type = CompOptionTypeBool;
+ o->value.b = EXPOSE_SLOPPY_FOCUS_DEFAULT;
+
+ o = &es->opt[EXPOSE_SCREEN_OPTION_INITIATE];
+ o->name = "initiate";
+ o->shortDesc = "Initiate";
+ o->longDesc = "Layout and start transforming windows";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = EXPOSE_INITIATE_MODIFIERS_DEFAULT;
+ o->value.bind.u.key.keycode =
+ XKeysymToKeycode (display,
+ XStringToKeysym (EXPOSE_INITIATE_KEY_DEFAULT));
+
+ o = &es->opt[EXPOSE_SCREEN_OPTION_TERMINATE];
+ o->name = "terminate";
+ o->shortDesc = "Terminate";
+ o->longDesc = "Return from expose view";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = EXPOSE_TERMINATE_MODIFIERS_DEFAULT;
+ o->value.bind.u.key.keycode =
+ XKeysymToKeycode (display,
+ XStringToKeysym (EXPOSE_TERMINATE_KEY_DEFAULT));
+
+ o = &es->opt[EXPOSE_SCREEN_OPTION_NEXT_WINDOW];
+ o->name = "next_window";
+ o->shortDesc = "Next Window";
+ o->longDesc = "Focus nextwindow";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = EXPOSE_NEXT_WINDOW_MODIFIERS_DEFAULT;
+ o->value.bind.u.key.keycode =
+ XKeysymToKeycode (display,
+ XStringToKeysym (EXPOSE_NEXT_WINDOW_KEY_DEFAULT));
+}
+
+static Bool
+exposePaintWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib,
+ Region region,
+ unsigned int mask)
+{
+ CompScreen *s = w->screen;
+ Bool status;
+
+ EXPOSE_SCREEN (s);
+
+ if (es->grabIndex)
+ {
+ WindowPaintAttrib exposeAttrib = *attrib;
+
+ EXPOSE_WINDOW (w);
+
+ exposeAttrib.xTranslate += ew->tx;
+ exposeAttrib.yTranslate += ew->ty;
+ exposeAttrib.xScale *= ew->scale;
+ exposeAttrib.yScale *= ew->scale;
+
+ UNWRAP (es, s, paintWindow);
+ status = (*s->paintWindow) (w, &exposeAttrib, region, mask);
+ WRAP (es, s, paintWindow, exposePaintWindow);
+ }
+ else
+ {
+ UNWRAP (es, s, paintWindow);
+ status = (*s->paintWindow) (w, attrib, region, mask);
+ WRAP (es, s, paintWindow, exposePaintWindow);
+ }
+
+ return status;
+}
+
+static Bool
+isExposeWin (CompWindow *w)
+{
+ if (w->attrib.map_state != IsViewable)
+ return FALSE;
+
+ if (w->type == w->screen->display->winDesktopAtom ||
+ w->type == w->screen->display->winDockAtom)
+ return FALSE;
+
+ if (w->attrib.x >= w->screen->width ||
+ w->attrib.y >= w->screen->height ||
+ w->attrib.x + w->width <= 0 ||
+ w->attrib.y + w->height <= 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static int
+compareWindows (const void *elem1,
+ const void *elem2)
+{
+ CompWindow *w1 = *((CompWindow **) elem1);
+ CompWindow *w2 = *((CompWindow **) elem2);
+ int s1, s2;
+
+ s1 = (w1->screen->width - (w1->attrib.x + w1->attrib.width)) +
+ (w1->screen->height - (w1->attrib.y + w1->attrib.height)) -
+ w1->attrib.x - w1->attrib.y;
+
+ s2 = (w2->screen->width - (w2->attrib.x + w2->attrib.width)) +
+ (w2->screen->height - (w2->attrib.y + w2->attrib.height)) -
+ w2->attrib.x - w2->attrib.y;
+
+ return s2 - s1;
+}
+
+/* TODO: Place window thumbnails at smarter positions and use
+ WM_STRUT HINTS instead of static top/bottom offsets == 24 */
+static Bool
+layoutThumbs (CompScreen *s)
+{
+ CompWindow *w;
+ int i, j, y2;
+ int cx, cy;
+ int lineLength, itemsPerLine;
+ float scaleW, scaleH;
+ int totalWidth, totalHeight;
+
+ EXPOSE_SCREEN (s);
+
+ cx = cy = es->nWindows = 0;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ EXPOSE_WINDOW (w);
+
+ if (ew->slot)
+ ew->adjust = TRUE;
+
+ ew->slot = 0;
+
+ if (!isExposeWin (w))
+ continue;
+
+ if (es->windowsSize <= es->nWindows)
+ {
+ es->windows = realloc (es->windows,
+ sizeof (CompWindow *) * (es->nWindows + 32));
+ if (!es->windows)
+ return FALSE;
+
+ es->windowsSize = es->nWindows + 32;
+ }
+
+ es->windows[es->nWindows++] = w;
+ }
+
+ if (!es->nWindows)
+ return FALSE;
+
+ qsort (es->windows, es->nWindows, sizeof (CompWindow *), compareWindows);
+
+ itemsPerLine = (sqrt (es->nWindows) * s->width) / s->height;
+ if (itemsPerLine < 1)
+ itemsPerLine = 1;
+
+ if (es->lineSize <= es->nWindows / itemsPerLine)
+ {
+ es->line = realloc (es->line, sizeof (int) *
+ (es->nWindows / itemsPerLine + 1));
+ if (!es->line)
+ return FALSE;
+
+ es->lineSize = es->nWindows / itemsPerLine + 1;
+ }
+
+ totalWidth = totalHeight = 0;
+
+ es->line[0] = 0;
+ es->nLine = 1;
+ lineLength = itemsPerLine;
+
+ if (es->slotsSize <= es->nWindows)
+ {
+ es->slots = realloc (es->slots, sizeof (ExposeSlot) *
+ (es->nWindows + 1));
+ if (!es->slots)
+ return FALSE;
+
+ es->slotsSize = es->nWindows + 1;
+ }
+ es->nSlots = 0;
+
+ for (i = 0; i < es->nWindows; i++)
+ {
+ EXPOSE_WINDOW (es->windows[i]);
+
+ w = es->windows[i];
+
+ /* find a good place between other elements */
+ for (j = 0; j < es->nSlots; j++)
+ {
+ y2 = es->slots[j].y2 + es->spacing + w->height;
+ if (w->width < es->slots[j].x2 - es->slots[j].x1 &&
+ y2 <= es->line[es->slots[j].line])
+ break;
+ }
+
+ /* otherwise append or start a new line */
+ if (j == es->nSlots)
+ {
+ if (lineLength < itemsPerLine)
+ {
+ lineLength++;
+
+ es->slots[es->nSlots].x1 = cx;
+ es->slots[es->nSlots].y1 = cy;
+ es->slots[es->nSlots].x2 = cx + w->width;
+ es->slots[es->nSlots].y2 = cy + w->height;
+ es->slots[es->nSlots].line = es->nLine - 1;
+
+ es->line[es->nLine - 1] = MAX (es->line[es->nLine - 1],
+ es->slots[es->nSlots].y2);
+ }
+ else
+ {
+ lineLength = 1;
+
+ cx = es->spacing;
+ cy = es->line[es->nLine - 1] + es->spacing;
+
+ es->slots[es->nSlots].x1 = cx;
+ es->slots[es->nSlots].y1 = cy;
+ es->slots[es->nSlots].x2 = cx + w->width;
+ es->slots[es->nSlots].y2 = cy + w->height;
+ es->slots[es->nSlots].line = es->nLine - 1;
+
+ es->line[es->nLine] = es->slots[es->nSlots].y2;
+
+ es->nLine++;
+ }
+
+ if (es->slots[es->nSlots].y2 > totalHeight)
+ totalHeight = es->slots[es->nSlots].y2;
+ }
+ else
+ {
+ es->slots[es->nSlots].x1 = es->slots[j].x1;
+ es->slots[es->nSlots].y1 = es->slots[j].y2 + es->spacing;
+ es->slots[es->nSlots].x2 = es->slots[es->nSlots].x1 + w->width;
+ es->slots[es->nSlots].y2 = es->slots[es->nSlots].y1 + w->height;
+ es->slots[es->nSlots].line = es->slots[j].line;
+
+ es->slots[j].line = 0;
+ }
+
+ cx = es->slots[es->nSlots].x2;
+ if (cx > totalWidth)
+ totalWidth = cx;
+
+ cx += es->spacing;
+
+ ew->slot = &es->slots[es->nSlots];
+ ew->adjust = TRUE;
+
+ es->nSlots++;
+ }
+
+ totalWidth += es->spacing;
+ totalHeight += es->spacing;
+
+ scaleW = (GLfloat) (s->width) / totalWidth;
+ scaleH = (GLfloat) (s->height - 48) / totalHeight;
+
+ es->scale = MIN (MIN (scaleH, scaleW), 1.0f);
+
+ for (i = 0; i < es->nSlots; i++)
+ {
+ es->slots[i].y1 = (float) es->slots[i].y1 * es->scale;
+ es->slots[i].x1 = (float) es->slots[i].x1 * es->scale;
+ es->slots[i].y1 += 24;
+ }
+
+ return TRUE;
+}
+
+static int
+adjustExposeVelocity (CompWindow *w)
+{
+ float dx, dy, ds, adjust, amount;
+ float x1, y1, scale;
+
+ EXPOSE_SCREEN (w->screen);
+ EXPOSE_WINDOW (w);
+
+ if (ew->slot)
+ {
+ x1 = ew->slot->x1;
+ y1 = ew->slot->y1;
+ scale = es->scale;
+ }
+ else
+ {
+ x1 = w->attrib.x;
+ y1 = w->attrib.y;
+ scale = 1.0f;
+ }
+
+ dx = x1 - (w->attrib.x + ew->tx);
+
+ adjust = dx * 0.15f;
+ amount = fabs (dx) * 1.5f;
+ if (amount < 0.5f)
+ amount = 0.5f;
+ else if (amount > 5.0f)
+ amount = 5.0f;
+
+ ew->xVelocity = (amount * ew->xVelocity + adjust) / (amount + 1.0f);
+
+ dy = y1 - (w->attrib.y + ew->ty);
+
+ adjust = dy * 0.15f;
+ amount = fabs (dy) * 1.5f;
+ if (amount < 0.5f)
+ amount = 0.5f;
+ else if (amount > 5.0f)
+ amount = 5.0f;
+
+ ew->yVelocity = (amount * ew->yVelocity + adjust) / (amount + 1.0f);
+
+ ds = scale - ew->scale;
+
+ adjust = ds * 0.1f;
+ amount = fabs (ds) * 7.0f;
+ if (amount < 0.01f)
+ amount = 0.01f;
+ else if (amount > 0.15f)
+ amount = 0.15f;
+
+ ew->scaleVelocity = (amount * ew->scaleVelocity + adjust) /
+ (amount + 1.0f);
+
+ if (fabs (dx) < 0.1f && fabs (ew->xVelocity) < 0.2f &&
+ fabs (dy) < 0.1f && fabs (ew->yVelocity) < 0.2f &&
+ fabs (ds) < 0.001f && fabs (ew->scaleVelocity) < 0.002f)
+ {
+ ew->xVelocity = ew->yVelocity = ew->scaleVelocity = 0.0f;
+ ew->tx = x1 - w->attrib.x;
+ ew->ty = y1 - w->attrib.y;
+ ew->scale = scale;
+
+ return 0;
+ }
+
+ return 1;
+}
+
+static Bool
+exposePaintScreen (CompScreen *s,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ Region region,
+ unsigned int mask)
+{
+ Bool status;
+
+ EXPOSE_SCREEN (s);
+
+ if (es->grabIndex)
+ {
+ mask &= ~PAINT_SCREEN_REGION_MASK;
+ mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
+ }
+
+ UNWRAP (es, s, paintScreen);
+ status = (*s->paintScreen) (s, sAttrib, wAttrib, region, mask);
+ WRAP (es, s, paintScreen, exposePaintScreen);
+
+ return status;
+}
+
+static void
+exposePreparePaintScreen (CompScreen *s,
+ int msSinceLastPaint)
+{
+ EXPOSE_SCREEN (s);
+
+ if (es->grabIndex && es->state != EXPOSE_STATE_WAIT)
+ {
+ CompWindow *w;
+
+ es->moreAdjust = 0;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ EXPOSE_WINDOW (w);
+
+ if (ew->adjust)
+ {
+ ew->adjust = adjustExposeVelocity (w);
+
+ es->moreAdjust |= ew->adjust;
+
+ ew->tx += (ew->xVelocity * msSinceLastPaint) / s->redrawTime;
+ ew->ty += (ew->yVelocity * msSinceLastPaint) / s->redrawTime;
+ ew->scale += (ew->scaleVelocity * msSinceLastPaint) /
+ s->redrawTime;
+ }
+ }
+ }
+
+ UNWRAP (es, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, msSinceLastPaint);
+ WRAP (es, s, preparePaintScreen, exposePreparePaintScreen);
+}
+
+static void
+exposeDonePaintScreen (CompScreen *s)
+{
+ EXPOSE_SCREEN (s);
+
+ if (es->grabIndex)
+ {
+ if (es->moreAdjust)
+ {
+ damageScreen (s);
+ }
+ else
+ {
+ if (es->state == EXPOSE_STATE_IN)
+ {
+ removeScreenGrab (s, es->grabIndex, 0);
+ es->grabIndex = 0;
+ }
+ else
+ es->state = EXPOSE_STATE_WAIT;
+ }
+ }
+
+ UNWRAP (es, s, donePaintScreen);
+ (*s->donePaintScreen) (s);
+ WRAP (es, s, donePaintScreen, exposeDonePaintScreen);
+}
+
+static CompWindow *
+exposeCheckForWindowAt (CompScreen *s,
+ int x,
+ int y)
+{
+ int x1, y1, x2, y2;
+ CompWindow *w;
+
+ for (w = s->reverseWindows; w; w = w->prev)
+ {
+ EXPOSE_WINDOW (w);
+
+ if (ew->slot)
+ {
+ x1 = w->attrib.x + ew->tx;
+ y1 = w->attrib.y + ew->ty;
+ x2 = x1 + ((float) w->width * ew->scale);
+ y2 = y1 + ((float) w->height * ew->scale);
+
+ if (x1 <= x && y1 <= y && x2 > x && y2 > y)
+ return w;
+ }
+ }
+
+ return 0;
+}
+
+static void
+exposeInitiate (CompScreen *s)
+{
+ EXPOSE_SCREEN (s);
+
+ if (layoutThumbs (s))
+ {
+ if (!es->grabIndex)
+ es->grabIndex = pushScreenGrab (s, es->cursor);
+
+ if (es->grabIndex)
+ {
+ damageScreen (s);
+ gettimeofday (&s->lastRedraw, 0);
+ es->state = EXPOSE_STATE_OUT;
+ }
+ }
+}
+
+static void
+exposeTerminate (CompScreen *s)
+{
+ EXPOSE_SCREEN (s);
+
+ if (es->grabIndex)
+ {
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ EXPOSE_WINDOW (w);
+
+ ew->slot = 0;
+ ew->adjust = TRUE;
+ }
+
+ es->state = EXPOSE_STATE_IN;
+
+ damageScreen (s);
+ }
+}
+
+static Bool
+exposeSelectWindow (CompWindow *w)
+{
+ EXPOSE_WINDOW (w);
+
+ if (ew->slot && w->client && w->client != w->screen->activeWindow)
+ {
+ XClientMessageEvent cm;
+
+ cm.type = ClientMessage;
+ cm.display = w->screen->display->display;
+ cm.format = 32;
+
+ cm.message_type = w->screen->display->winActiveAtom;
+ cm.window = w->client;
+
+ cm.data.l[0] = 2;
+ cm.data.l[1] = cm.data.l[2] = cm.data.l[3] = cm.data.l[4] = 0;
+
+ XSendEvent (w->screen->display->display, w->screen->root, FALSE,
+ StructureNotifyMask, (XEvent *) &cm);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+exposeSelectWindowAt (CompScreen *s,
+ int x,
+ int y)
+
+{
+ CompWindow *w;
+
+ w = exposeCheckForWindowAt (s, x, y);
+ if (w)
+ exposeSelectWindow (w);
+}
+
+static void
+exposeNextWindow (CompScreen *s)
+
+{
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ if (s->activeWindow == w->client)
+ break;
+
+ if (w)
+ {
+ for (w = w->next; w; w = w->next)
+ if (exposeSelectWindow (w))
+ return;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (s->activeWindow == w->client)
+ break;
+
+ if (exposeSelectWindow (w))
+ return;
+ }
+ }
+}
+
+static void
+exposeHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ CompScreen *s;
+
+ EXPOSE_DISPLAY (d);
+
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ s = findScreenAtDisplay (d, event->xkey.root);
+ if (s)
+ {
+ EXPOSE_SCREEN (s);
+
+ if (EV_KEY (&es->opt[EXPOSE_SCREEN_OPTION_INITIATE], event))
+ exposeInitiate (s);
+
+ if (EV_KEY (&es->opt[EXPOSE_SCREEN_OPTION_NEXT_WINDOW], event))
+ exposeNextWindow (s);
+
+ if (EV_KEY (&es->opt[EXPOSE_SCREEN_OPTION_TERMINATE], event) ||
+ (event->type == KeyPress &&
+ event->xkey.keycode == s->escapeKeyCode))
+ exposeTerminate (s);
+ }
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ s = findScreenAtDisplay (d, event->xbutton.root);
+ if (s)
+ {
+ EXPOSE_SCREEN (s);
+
+ if (es->grabIndex && es->state != EXPOSE_STATE_IN)
+ exposeSelectWindowAt (s,
+ event->xbutton.x_root,
+ event->xbutton.y_root);
+
+ if (EV_BUTTON (&es->opt[EXPOSE_SCREEN_OPTION_INITIATE], event))
+ exposeInitiate (s);
+
+ if (EV_BUTTON (&es->opt[EXPOSE_SCREEN_OPTION_NEXT_WINDOW], event))
+ exposeNextWindow (s);
+
+ if (EV_BUTTON (&es->opt[EXPOSE_SCREEN_OPTION_TERMINATE], event))
+ exposeTerminate (s);
+ }
+ break;
+ case MotionNotify:
+ s = findScreenAtDisplay (d, event->xmotion.root);
+ if (s)
+ {
+ EXPOSE_SCREEN (s);
+
+ if (es->grabIndex &&
+ es->state != EXPOSE_STATE_IN &&
+ es->opt[EXPOSE_SCREEN_OPTION_SLOPPY_FOCUS].value.b)
+ exposeSelectWindowAt (s,
+ event->xmotion.x_root,
+ event->xmotion.y_root);
+ }
+ default:
+ break;
+ }
+
+ UNWRAP (ed, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (ed, d, handleEvent, exposeHandleEvent);
+
+ switch (event->type) {
+ case CreateNotify:
+ case MapNotify: {
+ CompWindow *w;
+
+ w = findWindowAtDisplay (d, (event->type == CreateNotify) ?
+ event->xcreatewindow.window :
+ event->xmap.window);
+ if (w && isExposeWin (w))
+ {
+ EXPOSE_SCREEN (w->screen);
+
+ if (es->grabIndex && layoutThumbs (w->screen))
+ {
+ es->state = EXPOSE_STATE_OUT;
+ damageScreen (w->screen);
+ gettimeofday (&w->screen->lastRedraw, 0);
+ }
+ }
+ }
+ default:
+ break;
+ }
+}
+
+static Bool
+exposeInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ ExposeDisplay *ed;
+
+ ed = malloc (sizeof (ExposeDisplay));
+ if (!ed)
+ return FALSE;
+
+ ed->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (ed->screenPrivateIndex < 0)
+ {
+ free (ed);
+ return FALSE;
+ }
+
+ WRAP (ed, d, handleEvent, exposeHandleEvent);
+
+ d->privates[displayPrivateIndex].ptr = ed;
+
+ return TRUE;
+}
+
+static void
+exposeFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ EXPOSE_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, ed->screenPrivateIndex);
+
+ UNWRAP (ed, d, handleEvent);
+
+ free (ed);
+}
+
+static Bool
+exposeInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ ExposeScreen *es;
+
+ EXPOSE_DISPLAY (s->display);
+
+ es = malloc (sizeof (ExposeScreen));
+ if (!es)
+ return FALSE;
+
+ es->windowPrivateIndex = allocateWindowPrivateIndex (s);
+ if (es->windowPrivateIndex < 0)
+ {
+ free (es);
+ return FALSE;
+ }
+
+ es->grabIndex = 0;
+
+ es->state = EXPOSE_STATE_NONE;
+
+ es->slots = 0;
+ es->slotsSize = 0;
+
+ es->windows = 0;
+ es->windowsSize = 0;
+
+ es->line = 0;
+ es->lineSize = 0;
+
+ es->scale = 1.0f;
+
+ es->spacing = EXPOSE_SPACING_DEFAULT;
+
+ exposeScreenInitOptions (es, s->display->display);
+
+ addScreenBinding (s, &es->opt[EXPOSE_SCREEN_OPTION_INITIATE].value.bind);
+
+ WRAP (es, s, preparePaintScreen, exposePreparePaintScreen);
+ WRAP (es, s, donePaintScreen, exposeDonePaintScreen);
+ WRAP (es, s, paintScreen, exposePaintScreen);
+ WRAP (es, s, paintWindow, exposePaintWindow);
+
+ es->cursor = XCreateFontCursor (s->display->display, XC_left_ptr);
+
+ s->privates[ed->screenPrivateIndex].ptr = es;
+
+ return TRUE;
+}
+
+static void
+exposeFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ EXPOSE_SCREEN (s);
+
+ UNWRAP (es, s, preparePaintScreen);
+ UNWRAP (es, s, donePaintScreen);
+ UNWRAP (es, s, paintScreen);
+ UNWRAP (es, s, paintWindow);
+
+ if (es->slotsSize)
+ free (es->slots);
+
+ if (es->lineSize)
+ free (es->line);
+
+ if (es->windowsSize)
+ free (es->windows);
+
+ free (es);
+}
+
+static Bool
+exposeInitWindow (CompPlugin *p,
+ CompWindow *w)
+{
+ ExposeWindow *ew;
+
+ EXPOSE_SCREEN (w->screen);
+
+ ew = malloc (sizeof (ExposeWindow));
+ if (!ew)
+ return FALSE;
+
+ ew->slot = 0;
+ ew->scale = 1.0f;
+ ew->tx = ew->ty = 0.0f;
+ ew->adjust = FALSE;
+ ew->xVelocity = ew->yVelocity = ew->scaleVelocity = 0.0f;
+
+ w->privates[es->windowPrivateIndex].ptr = ew;
+
+ return TRUE;
+}
+
+static void
+exposeFiniWindow (CompPlugin *p,
+ CompWindow *w)
+{
+ EXPOSE_WINDOW (w);
+
+ free (ew);
+}
+
+static Bool
+exposeInit (CompPlugin *p)
+{
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+exposeFini (CompPlugin *p)
+{
+ if (displayPrivateIndex >= 0)
+ freeDisplayPrivateIndex (displayPrivateIndex);
+}
+
+CompPluginVTable exposeVTable = {
+ "expose",
+ "Expose",
+ "Expose-like Window Switcher",
+ exposeInit,
+ exposeFini,
+ exposeInitDisplay,
+ exposeFiniDisplay,
+ exposeInitScreen,
+ exposeFiniScreen,
+ exposeInitWindow,
+ exposeFiniWindow,
+ 0, /* GetDisplayOptions */
+ 0, /* SetDisplayOption */
+ exposeGetScreenOptions,
+ exposeSetScreenOption
+};
+
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &exposeVTable;
+}
diff --git a/plugins/fade.c b/plugins/fade.c
new file mode 100644
index 0000000..86eb398
--- /dev/null
+++ b/plugins/fade.c
@@ -0,0 +1,437 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+
+#include <comp.h>
+
+#define FADE_SPEED_DEFAULT 4.0f
+#define FADE_SPEED_MIN 0.1f
+#define FADE_SPEED_MAX 10.0f
+#define FADE_SPEED_PRECISION 0.1f
+
+static int displayPrivateIndex;
+
+typedef struct _FadeDisplay {
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+} FadeDisplay;
+
+#define FADE_SCREEN_OPTION_FADE_SPEED 0
+#define FADE_SCREEN_OPTION_NUM 1
+
+typedef struct _FadeScreen {
+ int windowPrivateIndex;
+ int fadeTime;
+ int steps;
+
+ CompOption opt[FADE_SCREEN_OPTION_NUM];
+
+ PreparePaintScreenProc preparePaintScreen;
+ PaintWindowProc paintWindow;
+} FadeScreen;
+
+typedef struct _FadeWindow {
+ int opacity;
+ int direction;
+ int destroyed;
+} FadeWindow;
+
+#define GET_FADE_DISPLAY(d) \
+ ((FadeDisplay *) (d)->privates[displayPrivateIndex].ptr)
+
+#define FADE_DISPLAY(d) \
+ FadeDisplay *fd = GET_FADE_DISPLAY (d)
+
+#define GET_FADE_SCREEN(s, fd) \
+ ((FadeScreen *) (s)->privates[(fd)->screenPrivateIndex].ptr)
+
+#define FADE_SCREEN(s) \
+ FadeScreen *fs = GET_FADE_SCREEN (s, GET_FADE_DISPLAY (s->display))
+
+#define GET_FADE_WINDOW(w, fs) \
+ ((FadeWindow *) (w)->privates[(fs)->windowPrivateIndex].ptr)
+
+#define FADE_WINDOW(w) \
+ FadeWindow *fw = GET_FADE_WINDOW (w, \
+ GET_FADE_SCREEN (w->screen, \
+ GET_FADE_DISPLAY (w->screen->display)))
+
+#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
+
+static CompOption *
+fadeGetScreenOptions (CompScreen *screen,
+ int *count)
+{
+ FADE_SCREEN (screen);
+
+ *count = NUM_OPTIONS (fs);
+ return fs->opt;
+}
+
+static Bool
+fadeSetScreenOption (CompScreen *screen,
+ char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ FADE_SCREEN (screen);
+
+ o = compFindOption (fs->opt, NUM_OPTIONS (fs), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index) {
+ case FADE_SCREEN_OPTION_FADE_SPEED:
+ if (compSetFloatOption (o, value))
+ {
+ fs->fadeTime = 1000.0f / o->value.f;
+ return TRUE;
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static void
+fadeScreenInitOptions (FadeScreen *fs)
+{
+ CompOption *o;
+
+ o = &fs->opt[FADE_SCREEN_OPTION_FADE_SPEED];
+ o->name = "fade_speed";
+ o->shortDesc = "Fade Speed";
+ o->longDesc = "Window fade speed";
+ o->type = CompOptionTypeFloat;
+ o->value.f = FADE_SPEED_DEFAULT;
+ o->rest.f.min = FADE_SPEED_MIN;
+ o->rest.f.max = FADE_SPEED_MAX;
+ o->rest.f.precision = FADE_SPEED_PRECISION;
+}
+
+static void
+fadePreparePaintScreen (CompScreen *s,
+ int msSinceLastPaint)
+{
+ FADE_SCREEN (s);
+
+ fs->steps = (msSinceLastPaint * OPAQUE) / fs->fadeTime;
+ if (fs->steps < 256)
+ fs->steps = 256;
+
+ UNWRAP (fs, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, msSinceLastPaint);
+ WRAP (fs, s, preparePaintScreen, fadePreparePaintScreen);
+}
+
+static Bool
+fadePaintWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib,
+ Region region,
+ unsigned int mask)
+{
+ CompScreen *s = w->screen;
+ Bool status;
+
+ FADE_SCREEN (s);
+ FADE_WINDOW (w);
+
+ if (fw->opacity < OPAQUE)
+ {
+ GLint opacity;
+
+ opacity = fw->opacity + fs->steps * fw->direction;
+ if (opacity > 0)
+ {
+ if (opacity < OPAQUE)
+ {
+ WindowPaintAttrib fAttrib = *attrib;
+
+ fAttrib.opacity = MULTIPLY_USHORT (opacity, attrib->opacity);
+
+ UNWRAP (fs, s, paintWindow);
+ status = (*s->paintWindow) (w, &fAttrib, region, mask);
+ WRAP (fs, s, paintWindow, fadePaintWindow);
+
+ if (status)
+ {
+ fw->opacity = opacity;
+
+ addWindowDamage (w);
+ }
+ }
+ else
+ {
+ UNWRAP (fs, s, paintWindow);
+ status = (*s->paintWindow) (w, attrib, region, mask);
+ WRAP (fs, s, paintWindow, fadePaintWindow);
+
+ if (status)
+ {
+ fw->opacity = OPAQUE;
+ fw->direction = 0;
+ }
+ }
+ }
+ else
+ {
+ fw->opacity = 0;
+ fw->direction = 0;
+
+ if (fw->destroyed)
+ destroyWindow (w);
+ else
+ unmapWindow (w);
+
+ return (mask & PAINT_WINDOW_SOLID_MASK) ? FALSE : TRUE;
+ }
+ }
+ else
+ {
+ UNWRAP (fs, s, paintWindow);
+ status = (*s->paintWindow) (w, attrib, region, mask);
+ WRAP (fs, s, paintWindow, fadePaintWindow);
+ }
+
+ return status;
+}
+
+static void
+fadeHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ CompWindow *w;
+
+ FADE_DISPLAY (d);
+
+ switch (event->type) {
+ case DestroyNotify:
+ w = findWindowAtDisplay (d, event->xdestroywindow.window);
+ if (w)
+ {
+ FADE_WINDOW (w);
+
+ if (!fw->direction)
+ fw->opacity = OPAQUE - 1;
+
+ fw->direction = -1;
+ fw->destroyed = 1;
+
+ addWindowDamage (w);
+ return;
+ }
+ break;
+ case UnmapNotify:
+ w = findWindowAtDisplay (d, event->xunmap.window);
+ if (w)
+ {
+ FADE_WINDOW (w);
+
+ if (!fw->direction)
+ fw->opacity = OPAQUE - 1;
+
+ fw->direction = -1;
+
+ addWindowDamage (w);
+ return;
+ }
+ break;
+ case MapNotify:
+ w = findWindowAtDisplay (d, event->xmap.window);
+ if (w)
+ {
+ FADE_WINDOW (w);
+
+ if (!fw->direction)
+ fw->opacity = 1;
+
+ fw->direction = 1;
+ }
+ default:
+ break;
+ }
+
+ UNWRAP (fd, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (fd, d, handleEvent, fadeHandleEvent);
+}
+
+static Bool
+fadeInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ FadeDisplay *fd;
+
+ fd = malloc (sizeof (FadeDisplay));
+ if (!fd)
+ return FALSE;
+
+ fd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (fd->screenPrivateIndex < 0)
+ {
+ free (fd);
+ return FALSE;
+ }
+
+ WRAP (fd, d, handleEvent, fadeHandleEvent);
+
+ d->privates[displayPrivateIndex].ptr = fd;
+
+ return TRUE;
+}
+
+static void
+fadeFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ FADE_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, fd->screenPrivateIndex);
+
+ UNWRAP (fd, d, handleEvent);
+
+ free (fd);
+}
+
+static Bool
+fadeInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ FadeScreen *fs;
+
+ FADE_DISPLAY (s->display);
+
+ fs = malloc (sizeof (FadeScreen));
+ if (!fs)
+ return FALSE;
+
+ fs->windowPrivateIndex = allocateWindowPrivateIndex (s);
+ if (fs->windowPrivateIndex < 0)
+ {
+ free (fs);
+ return FALSE;
+ }
+
+ fs->steps = 0;
+ fs->fadeTime = 1000.0f / FADE_SPEED_DEFAULT;
+
+ fadeScreenInitOptions (fs);
+
+ WRAP (fs, s, preparePaintScreen, fadePreparePaintScreen);
+ WRAP (fs, s, paintWindow, fadePaintWindow);
+
+ s->privates[fd->screenPrivateIndex].ptr = fs;
+
+ return TRUE;
+}
+
+static void
+fadeFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ FADE_SCREEN (s);
+
+ freeWindowPrivateIndex (s, fs->windowPrivateIndex);
+
+ UNWRAP (fs, s, preparePaintScreen);
+ UNWRAP (fs, s, paintWindow);
+
+ free (fs);
+}
+
+static Bool
+fadeInitWindow (CompPlugin *p,
+ CompWindow *w)
+{
+ FadeWindow *fw;
+
+ FADE_SCREEN (w->screen);
+
+ fw = malloc (sizeof (FadeWindow));
+ if (!fw)
+ return FALSE;
+
+ fw->opacity = OPAQUE;
+ fw->direction = 0;
+ fw->destroyed = 0;
+
+ w->privates[fs->windowPrivateIndex].ptr = fw;
+
+ return TRUE;
+}
+
+static void
+fadeFiniWindow (CompPlugin *p,
+ CompWindow *w)
+{
+ FADE_WINDOW (w);
+
+ free (fw);
+}
+
+static Bool
+fadeInit (CompPlugin *p)
+{
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+fadeFini (CompPlugin *p)
+{
+ if (displayPrivateIndex >= 0)
+ freeDisplayPrivateIndex (displayPrivateIndex);
+}
+
+static CompPluginVTable fadeVTable = {
+ "fade",
+ "Fading Windows",
+ "Fade in windows when mapped and fade out windows when unmapped",
+ fadeInit,
+ fadeFini,
+ fadeInitDisplay,
+ fadeFiniDisplay,
+ fadeInitScreen,
+ fadeFiniScreen,
+ fadeInitWindow,
+ fadeFiniWindow,
+ 0, /* GetDisplayOptions */
+ 0, /* SetDisplayOption */
+ fadeGetScreenOptions,
+ fadeSetScreenOption
+};
+
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &fadeVTable;
+}
diff --git a/plugins/gconf.c b/plugins/gconf.c
new file mode 100644
index 0000000..9f0a342
--- /dev/null
+++ b/plugins/gconf.c
@@ -0,0 +1,1110 @@
+/*
+ * 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>
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <gconf/gconf-client.h>
+
+#include <comp.h>
+
+#define APP_NAME "/apps/gnome-composite"
+#define KEY_CHANGE_TIMEOUT 250
+
+struct _GConfModifier {
+ char *name;
+ int modifier;
+} modifiers[] = {
+ { "<Shift>", ShiftMask },
+ { "<Control>", ControlMask },
+ { "<Mod1>", Mod1Mask },
+ { "<Mod2>", Mod2Mask },
+ { "<Mod3>", Mod3Mask },
+ { "<Mod4>", Mod4Mask },
+ { "<Mod5>", Mod5Mask },
+ { "<Alt>", CompAltMask },
+ { "<Meta>", CompMetaMask },
+ { "<Super>", CompSuperMask },
+ { "<Hyper>", CompHyperMask },
+ { "<ModeSwitch>", CompModeSwitchMask },
+ { "<NumLock>", CompNumLockMask },
+ { "<ScrollLock>", CompScrollLockMask },
+ { "<Release>", CompReleaseMask }
+};
+
+#define N_MODIFIERS (sizeof (modifiers) / sizeof (struct _GConfModifier))
+
+static int displayPrivateIndex;
+
+typedef struct _GConfDisplay {
+ int screenPrivateIndex;
+
+ GConfClient *client;
+ CompTimeoutHandle timeoutHandle;
+
+ InitPluginForDisplayProc initPluginForDisplay;
+ SetDisplayOptionProc setDisplayOption;
+ SetDisplayOptionForPluginProc setDisplayOptionForPlugin;
+} GConfDisplay;
+
+typedef struct _GConfScreen {
+ InitPluginForScreenProc initPluginForScreen;
+ SetScreenOptionProc setScreenOption;
+ SetScreenOptionForPluginProc setScreenOptionForPlugin;
+} GConfScreen;
+
+#define GET_GCONF_DISPLAY(d) \
+ ((GConfDisplay *) (d)->privates[displayPrivateIndex].ptr)
+
+#define GCONF_DISPLAY(d) \
+ GConfDisplay *gd = GET_GCONF_DISPLAY (d)
+
+#define GET_GCONF_SCREEN(s, gd) \
+ ((GConfScreen *) (s)->privates[(gd)->screenPrivateIndex].ptr)
+
+#define GCONF_SCREEN(s) \
+ GConfScreen *gs = GET_GCONF_SCREEN (s, GET_GCONF_DISPLAY (s->display))
+
+static int
+strcmpskipifequal (char **ptr, char *s)
+{
+ int ret, len;
+
+ len = strlen (s);
+ ret = strncmp (*ptr, s, len);
+ if (ret == 0)
+ *ptr = (*ptr) + len;
+
+ return ret;
+}
+
+static GConfValueType
+gconfTypeFromCompType (CompOptionType type)
+{
+ switch (type) {
+ case CompOptionTypeBool:
+ return GCONF_VALUE_BOOL;
+ case CompOptionTypeInt:
+ return GCONF_VALUE_INT;
+ case CompOptionTypeFloat:
+ return GCONF_VALUE_FLOAT;
+ case CompOptionTypeString:
+ return GCONF_VALUE_STRING;
+ case CompOptionTypeColor:
+ return GCONF_VALUE_STRING;
+ case CompOptionTypeBinding:
+ return GCONF_VALUE_STRING;
+ case CompOptionTypeList:
+ return GCONF_VALUE_LIST;
+ default:
+ break;
+ }
+
+ return GCONF_VALUE_INVALID;
+}
+
+static void
+gconfSetValue (CompDisplay *d,
+ CompOptionValue *value,
+ CompOptionType type,
+ GConfValue *gvalue)
+{
+ switch (type) {
+ case CompOptionTypeBool:
+ gconf_value_set_bool (gvalue, value->b);
+ break;
+ case CompOptionTypeInt:
+ gconf_value_set_int (gvalue, value->i);
+ break;
+ case CompOptionTypeFloat:
+ gconf_value_set_float (gvalue, value->f);
+ break;
+ case CompOptionTypeString:
+ gconf_value_set_string (gvalue, value->s);
+ break;
+ case CompOptionTypeColor: {
+ gchar *color;
+
+ color = g_strdup_printf ("#%.2x%.2x%.2x",
+ value->c[0] / 256,
+ value->c[1] / 256,
+ value->c[2] / 256);
+
+ gconf_value_set_string (gvalue, color);
+
+ g_free (color);
+ } break;
+ case CompOptionTypeBinding: {
+ guint modMask;
+
+ if (value->bind.type == CompBindingTypeButton)
+ modMask = value->bind.u.button.modifiers;
+ else
+ modMask = value->bind.u.key.modifiers;
+
+ if (modMask & (CompPressMask | CompReleaseMask))
+ {
+ gchar *m, *mods = g_strdup ("");
+ gchar *binding;
+ gint i;
+
+ for (i = 0; i < N_MODIFIERS; i++)
+ {
+ if (modMask & modifiers[i].modifier)
+ {
+ m = g_strconcat (mods, modifiers[i].name, NULL);
+ if (m)
+ {
+ free (mods);
+ mods = m;
+ }
+ }
+ }
+
+ if (value->bind.type == CompBindingTypeButton)
+ {
+ binding = g_strdup_printf ("%sButton%d", mods,
+ value->bind.u.button.button);
+ }
+ else
+ {
+ KeySym keysym;
+ gchar *keyname;
+
+ keysym = XKeycodeToKeysym (d->display,
+ value->bind.u.key.keycode,
+ 0);
+ keyname = XKeysymToString (keysym);
+
+ binding = g_strdup_printf ("%s%s", mods,
+ (keyname) ? keyname : "??");
+ }
+
+ gconf_value_set_string (gvalue, binding);
+
+ g_free (binding);
+ g_free (mods);
+ }
+ else
+ {
+ gconf_value_set_string (gvalue, "Disabled");
+ }
+ } break;
+ default:
+ break;
+ }
+}
+
+static void
+gconfSetOption (CompDisplay *d,
+ CompOption *o,
+ gchar *screen,
+ gchar *plugin)
+{
+ GConfValue *gvalue;
+ gchar *key;
+
+ GCONF_DISPLAY (d);
+
+ if (plugin)
+ {
+ key = g_strjoin ("/", APP_NAME "/plugins", plugin, screen, "options",
+ o->name, "value", NULL);
+ }
+ else
+ {
+ key = g_strjoin ("/", APP_NAME "/general", screen, "options", o->name,
+ "value", NULL);
+ }
+
+ switch (o->type) {
+ case CompOptionTypeBool:
+ case CompOptionTypeInt:
+ case CompOptionTypeFloat:
+ case CompOptionTypeString:
+ case CompOptionTypeColor:
+ case CompOptionTypeBinding:
+ gvalue = gconf_value_new (gconfTypeFromCompType (o->type));
+ gconfSetValue (d, &o->value, o->type, gvalue);
+ gconf_client_set (gd->client, key, gvalue, NULL);
+ gconf_value_free (gvalue);
+ break;
+ case CompOptionTypeList: {
+ GConfValueType type;
+ GSList *list = NULL;
+ GConfValue *gv;
+ int i;
+
+ gvalue = gconf_value_new (GCONF_VALUE_LIST);
+
+ type = gconfTypeFromCompType (o->value.list.type);
+
+ for (i = 0; i < o->value.list.nValue; i++)
+ {
+ gv = gconf_value_new (type);
+ gconfSetValue (d, &o->value.list.value[i], o->value.list.type, gv);
+ list = g_slist_append (list, gv);
+ }
+
+ gconf_value_set_list_type (gvalue, type);
+ gconf_value_set_list (gvalue, list);
+ gconf_client_set (gd->client, key, gvalue, NULL);
+
+ for (i = 0; i < o->value.list.nValue; i++)
+ {
+ gv = g_slist_nth_data (list, i);
+ gconf_value_free (gv);
+ }
+ g_slist_free (list);
+ gconf_value_free (gvalue);
+ } break;
+ default:
+ break;
+ }
+
+ g_free (key);
+}
+
+static Bool
+gconfGetValue (CompDisplay *d,
+ CompOptionValue *value,
+ CompOptionType type,
+ GConfValue *gvalue)
+
+{
+ if (type == CompOptionTypeBool &&
+ gvalue->type == GCONF_VALUE_BOOL)
+ {
+ value->b = gconf_value_get_bool (gvalue);
+ return TRUE;
+ }
+ else if (type == CompOptionTypeInt &&
+ gvalue->type == GCONF_VALUE_INT)
+ {
+ value->i = gconf_value_get_int (gvalue);
+ return TRUE;
+ }
+ else if (type == CompOptionTypeFloat &&
+ gvalue->type == GCONF_VALUE_FLOAT)
+ {
+ value->f = gconf_value_get_float (gvalue);
+ return TRUE;
+ }
+ else if (type == CompOptionTypeString &&
+ gvalue->type == GCONF_VALUE_STRING)
+ {
+ value->s = (char *) gconf_value_get_string (gvalue);
+ return TRUE;
+ }
+ else if (type == CompOptionTypeColor &&
+ gvalue->type == GCONF_VALUE_STRING)
+ {
+ const gchar *color;
+ gint c[3];
+
+ color = gconf_value_get_string (gvalue);
+
+ if (sscanf (color, "#%2x%2x%2x", &c[0], &c[1], &c[2]) == 3)
+ {
+ value->c[0] = c[0] * 256;
+ value->c[1] = c[1] * 256;
+ value->c[2] = c[2] * 256;
+ value->c[3] = 0xffff;
+
+ return TRUE;
+ }
+ }
+ else if (type == CompOptionTypeBinding &&
+ gvalue->type == GCONF_VALUE_STRING)
+ {
+ gchar *binding, *ptr;
+ gint i;
+ guint mods = 0;
+
+ binding = (gchar *) gconf_value_get_string (gvalue);
+ if (strcasecmp (binding, "disabled") == 0)
+ {
+ value->bind.type = CompBindingTypeButton;
+ value->bind.u.button.button = 1;
+ value->bind.u.button.modifiers = 0;
+ }
+ else
+ {
+ for (i = 0; i < N_MODIFIERS; i++)
+ {
+ if (strcasestr (binding, modifiers[i].name))
+ mods |= modifiers[i].modifier;
+ }
+
+ /* if not explicetly set to be triggered at release
+ assume it to be triggered at press */
+ if (!(mods & CompReleaseMask))
+ mods |= CompPressMask;
+
+ ptr = strrchr (binding, '>');
+ if (ptr)
+ binding = ptr + 1;
+
+ while (*binding && !isalpha (*binding))
+ binding++;
+
+ if (strcmpskipifequal (&binding, "Button") == 0)
+ {
+ gint button;
+
+ if (sscanf (binding, "%d", &button) == 1)
+ {
+ value->bind.type = CompBindingTypeButton;
+ value->bind.u.button.button = button;
+ value->bind.u.button.modifiers = mods;
+
+ return TRUE;
+ }
+ }
+ else
+ {
+ KeySym keysym;
+
+ keysym = XStringToKeysym (binding);
+ if (keysym != NoSymbol)
+ {
+ KeyCode keycode;
+
+ keycode = XKeysymToKeycode (d->display, keysym);
+ if (keycode)
+ {
+ value->bind.type = CompBindingTypeKey;
+ value->bind.u.key.keycode = keycode;
+ value->bind.u.key.modifiers = mods;
+
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static Bool
+gconfGetOptionValue (CompDisplay *d,
+ GConfEntry *entry)
+{
+ CompPlugin *p = 0;
+ CompScreen *s = 0;
+ CompOption *o, *option;
+ gchar *ptr;
+ gchar *pluginPtr = 0, *optionPtr = 0;
+ gint pluginLen = 0, optionLen = 0;
+ gint nOption;
+ Bool status = FALSE;
+
+ if (!entry)
+ return FALSE;
+
+ ptr = entry->key;
+ if (strncmp (ptr, APP_NAME, strlen (APP_NAME)))
+ return FALSE;
+
+ ptr += strlen (APP_NAME);
+
+ if (strcmpskipifequal (&ptr, "/plugins/") == 0)
+ {
+ pluginPtr = ptr;
+ ptr = strchr (ptr, '/');
+ if (!ptr)
+ return FALSE;
+
+ pluginLen = ptr - pluginPtr;
+ if (pluginLen < 1)
+ return FALSE;
+ }
+ else if (strcmpskipifequal (&ptr, "/general"))
+ return FALSE;
+
+ if (strcmpskipifequal (&ptr, "/screen") == 0)
+ {
+ int screenNum;
+
+ screenNum = strtol (ptr, &ptr, 0);
+
+ for (s = d->screens; s; s = s->next)
+ if (s->screenNum == screenNum)
+ break;
+
+ if (!s || !ptr)
+ return FALSE;
+ }
+ else if (strcmpskipifequal (&ptr, "/allscreens"))
+ return FALSE;
+
+ if (strcmpskipifequal (&ptr, "/options/"))
+ return FALSE;
+
+ optionPtr = ptr;
+ ptr = strchr (ptr, '/');
+ if (!ptr)
+ return FALSE;
+
+ optionLen = ptr - optionPtr;
+ if (optionLen < 1)
+ return FALSE;
+
+ if (strcmp (ptr, "/value") != 0)
+ return FALSE;
+
+ if (pluginPtr)
+ {
+ pluginPtr = g_strndup (pluginPtr, pluginLen);
+
+ option = 0;
+ nOption = 0;
+
+ p = findActivePlugin (pluginPtr);
+ if (p)
+ {
+ if (s)
+ {
+ if (p->vTable->getScreenOptions)
+ option = (*p->vTable->getScreenOptions) (s, &nOption);
+ }
+ else
+ {
+ if (p->vTable->getDisplayOptions)
+ option = (*p->vTable->getDisplayOptions) (d, &nOption);
+ }
+ }
+ }
+ else
+ {
+ if (s)
+ option = compGetScreenOptions (s, &nOption);
+ else
+ option = compGetDisplayOptions (d, &nOption);
+ }
+
+ optionPtr = g_strndup (optionPtr, optionLen);
+
+ o = compFindOption (option, nOption, optionPtr, 0);
+ if (o)
+ {
+ GConfValue *gvalue;
+ CompOptionValue value;
+
+ gvalue = gconf_entry_get_value (entry);
+ if (gvalue)
+ {
+ if (o->type == CompOptionTypeList &&
+ gvalue->type == GCONF_VALUE_LIST)
+ {
+ GConfValueType type;
+
+ value.list.value = 0;
+ value.list.nValue = 0;
+
+ type = gconf_value_get_list_type (gvalue);
+ if (type == gconfTypeFromCompType (o->value.list.type))
+ {
+ GSList *list;
+ int i, length;
+
+ status = TRUE;
+
+ list = gconf_value_get_list (gvalue);
+
+ length = g_slist_length (list);
+
+ if (length)
+ {
+ value.list.value =
+ malloc (sizeof (CompOptionValue) * length);
+ if (value.list.value)
+ {
+ value.list.nValue = length;
+ for (i = 0; i < length; i++)
+ {
+ if (!gconfGetValue (d, &value.list.value[i],
+ o->value.list.type,
+ (GConfValue *) list->data))
+ status = FALSE;
+
+ list = g_slist_next (list);
+ }
+ }
+ else
+ status = FALSE;
+ }
+ }
+ else
+ status = FALSE;
+ }
+ else
+ {
+ status = gconfGetValue (d, &value, o->type, gvalue);
+ }
+
+ if (status)
+ {
+ if (s)
+ {
+ if (pluginPtr)
+ status = (*s->setScreenOptionForPlugin) (s,
+ pluginPtr,
+ optionPtr,
+ &value);
+ else
+ status = (*s->setScreenOption) (s, optionPtr, &value);
+ }
+ else
+ {
+ if (pluginPtr)
+ status = (*d->setDisplayOptionForPlugin) (d,
+ pluginPtr,
+ optionPtr,
+ &value);
+ else
+ status = (*d->setDisplayOption) (d, optionPtr, &value);
+ }
+ }
+
+ if (o->type == CompOptionTypeList &&
+ gvalue->type == GCONF_VALUE_LIST)
+ {
+ if (value.list.nValue && value.list.value)
+ free (value.list.value);
+ }
+ }
+ }
+
+ g_free (optionPtr);
+ if (pluginPtr)
+ g_free (pluginPtr);
+
+ return status;
+}
+
+static void
+gconfInitOption (CompDisplay *d,
+ CompOption *o,
+ gchar *screen,
+ gchar *plugin)
+{
+ GConfEntry *entry;
+ gchar *gconfpath, *key;
+ CompOptionType type;
+
+ GCONF_DISPLAY (d);
+
+ if (plugin)
+ {
+ gconfpath = g_strjoin ("/", APP_NAME "/plugins", plugin, screen,
+ "options", o->name, NULL);
+ }
+ else
+ {
+ gconfpath = g_strjoin ("/", APP_NAME "/general", screen, "options",
+ o->name, NULL);
+ }
+
+ key = g_strconcat (gconfpath, "/short_description", NULL);
+ gconf_client_set_string (gd->client, key, o->shortDesc, NULL);
+ g_free (key);
+
+ key = g_strconcat (gconfpath, "/long_description", NULL);
+ gconf_client_set_string (gd->client, key, o->longDesc, NULL);
+ g_free (key);
+
+ key = g_strconcat (gconfpath, "/type", NULL);
+
+ type = o->type;
+ if (type == CompOptionTypeList)
+ type = o->value.list.type;
+
+ switch (type) {
+ case CompOptionTypeBool:
+ gconf_client_set_string (gd->client, key, "Bool", NULL);
+ break;
+ case CompOptionTypeInt:
+ gconf_client_set_string (gd->client, key, "Int", NULL);
+ break;
+ case CompOptionTypeFloat:
+ gconf_client_set_string (gd->client, key, "Float", NULL);
+ break;
+ case CompOptionTypeString:
+ gconf_client_set_string (gd->client, key, "String", NULL);
+ break;
+ case CompOptionTypeColor:
+ gconf_client_set_string (gd->client, key, "Color", NULL);
+ break;
+ case CompOptionTypeBinding:
+ gconf_client_set_string (gd->client, key, "Binding", NULL);
+ break;
+ default:
+ break;
+ }
+
+ g_free (key);
+ key = g_strconcat (gconfpath, "/min", NULL);
+
+ switch (type) {
+ case CompOptionTypeInt:
+ gconf_client_set_int (gd->client, key, o->rest.i.min, NULL);
+ break;
+ case CompOptionTypeFloat:
+ gconf_client_set_float (gd->client, key, o->rest.f.min, NULL);
+ break;
+ default:
+ break;
+ }
+
+ g_free (key);
+ key = g_strconcat (gconfpath, "/max", NULL);
+
+ switch (type) {
+ case CompOptionTypeInt:
+ gconf_client_set_int (gd->client, key, o->rest.i.max, NULL);
+ break;
+ case CompOptionTypeFloat:
+ gconf_client_set_float (gd->client, key, o->rest.f.max, NULL);
+ break;
+ default:
+ break;
+ }
+
+ g_free (key);
+ key = g_strconcat (gconfpath, "/precision", NULL);
+
+ switch (type) {
+ case CompOptionTypeFloat:
+ gconf_client_set_float (gd->client, key, o->rest.f.precision, NULL);
+ break;
+ default:
+ break;
+ }
+
+ g_free (key);
+ key = g_strconcat (gconfpath, "/choices", NULL);
+
+ switch (type) {
+ case CompOptionTypeString: {
+ GSList *list = NULL;
+ int i;
+
+ for (i = 0; i < o->rest.s.nString; i++)
+ list = g_slist_append (list, o->rest.s.string[i]);
+
+ gconf_client_set_list (gd->client, key, GCONF_VALUE_STRING, list,
+ NULL);
+
+ g_slist_free (list);
+ } break;
+ default:
+ break;
+ }
+
+ g_free (key);
+ key = g_strconcat (gconfpath, "/value", NULL);
+
+ entry = gconf_client_get_entry (gd->client, key, NULL, FALSE, NULL);
+
+ if (!gconfGetOptionValue (d, entry))
+ gconfSetOption (d, o, screen, plugin);
+
+ if (entry)
+ gconf_entry_free (entry);
+
+ g_free (key);
+ g_free (gconfpath);
+}
+
+static void
+gconfInitPlugin (CompDisplay *d,
+ CompPlugin *p)
+{
+ gchar *gconfpath, *key;
+
+ GCONF_DISPLAY (d);
+
+ gconfpath = g_strjoin ("/", APP_NAME "/plugins", p->vTable->name, NULL);
+
+ key = g_strconcat (gconfpath, "/short_description", NULL);
+ gconf_client_set_string (gd->client, key, p->vTable->shortDesc, NULL);
+ g_free (key);
+
+ key = g_strconcat (gconfpath, "/long_description", NULL);
+ gconf_client_set_string (gd->client, key, p->vTable->longDesc, NULL);
+ g_free (key);
+
+ g_free (gconfpath);
+}
+
+static Bool
+gconfSetDisplayOption (CompDisplay *d,
+ char *name,
+ CompOptionValue *value)
+{
+ Bool status;
+
+ GCONF_DISPLAY (d);
+
+ UNWRAP (gd, d, setDisplayOption);
+ status = (*d->setDisplayOption) (d, name, value);
+ WRAP (gd, d, setDisplayOption, gconfSetDisplayOption);
+
+ if (status)
+ {
+ CompOption *option;
+ int nOption;
+
+ option = compGetDisplayOptions (d, &nOption);
+ gconfSetOption (d, compFindOption (option, nOption, name, 0),
+ "allscreens", 0);
+ }
+
+ return status;
+}
+
+static Bool
+gconfSetDisplayOptionForPlugin (CompDisplay *d,
+ char *plugin,
+ char *name,
+ CompOptionValue *value)
+{
+ Bool status;
+
+ GCONF_DISPLAY (d);
+
+ UNWRAP (gd, d, setDisplayOptionForPlugin);
+ status = (*d->setDisplayOptionForPlugin) (d, plugin, name, value);
+ WRAP (gd, d, setDisplayOptionForPlugin, gconfSetDisplayOptionForPlugin);
+
+ if (status)
+ {
+ CompPlugin *p;
+
+ p = findActivePlugin (plugin);
+ if (p && p->vTable->getDisplayOptions)
+ {
+ CompOption *option;
+ int nOption;
+
+ option = (*p->vTable->getDisplayOptions) (d, &nOption);
+ gconfSetOption (d, compFindOption (option, nOption, name, 0),
+ "allscreens", plugin);
+ }
+ }
+
+ return status;
+}
+
+static Bool
+gconfSetScreenOption (CompScreen *s,
+ char *name,
+ CompOptionValue *value)
+{
+ Bool status;
+
+ GCONF_SCREEN (s);
+
+ UNWRAP (gs, s, setScreenOption);
+ status = (*s->setScreenOption) (s, name, value);
+ WRAP (gs, s, setScreenOption, gconfSetScreenOption);
+
+ if (status)
+ {
+ CompOption *option;
+ int nOption;
+ gchar *screen;
+
+ screen = g_strdup_printf ("screen%d", s->screenNum);
+
+ option = compGetScreenOptions (s, &nOption);
+ gconfSetOption (s->display, compFindOption (option, nOption, name, 0),
+ screen, 0);
+
+ g_free (screen);
+ }
+
+ return status;
+}
+
+static Bool
+gconfSetScreenOptionForPlugin (CompScreen *s,
+ char *plugin,
+ char *name,
+ CompOptionValue *value)
+{
+ Bool status;
+
+ GCONF_SCREEN (s);
+
+ UNWRAP (gs, s, setScreenOptionForPlugin);
+ status = (*s->setScreenOptionForPlugin) (s, plugin, name, value);
+ WRAP (gs, s, setScreenOptionForPlugin, gconfSetScreenOptionForPlugin);
+
+ if (status)
+ {
+ CompPlugin *p;
+
+ p = findActivePlugin (plugin);
+ if (p && p->vTable->getScreenOptions)
+ {
+ CompOption *option;
+ int nOption;
+ gchar *screen;
+
+ screen = g_strdup_printf ("screen%d", s->screenNum);
+
+ option = (*p->vTable->getScreenOptions) (s, &nOption);
+ gconfSetOption (s->display,
+ compFindOption (option, nOption, name, 0),
+ screen, plugin);
+
+ g_free (screen);
+ }
+ }
+
+ return status;
+}
+
+static Bool
+gconfInitPluginForDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ Bool status;
+
+ GCONF_DISPLAY (d);
+
+ UNWRAP (gd, d, initPluginForDisplay);
+ status = (*d->initPluginForDisplay) (p, d);
+ WRAP (gd, d, initPluginForDisplay, gconfInitPluginForDisplay);
+
+ if (status)
+ gconfInitPlugin (d, p);
+
+ if (status && p->vTable->getDisplayOptions)
+ {
+ CompOption *option;
+ int nOption;
+
+ option = (*p->vTable->getDisplayOptions) (d, &nOption);
+ while (nOption--)
+ gconfInitOption (d, option++, "allscreens", p->vTable->name);
+ }
+
+ return status;
+}
+
+static Bool
+gconfInitPluginForScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ Bool status;
+
+ GCONF_SCREEN (s);
+
+ UNWRAP (gs, s, initPluginForScreen);
+ status = (*s->initPluginForScreen) (p, s);
+ WRAP (gs, s, initPluginForScreen, gconfInitPluginForScreen);
+
+ if (status && p->vTable->getScreenOptions)
+ {
+ CompOption *option;
+ int nOption;
+ gchar *screen;
+
+ screen = g_strdup_printf ("screen%d", s->screenNum);
+
+ option = (*p->vTable->getScreenOptions) (s, &nOption);
+ while (nOption--)
+ gconfInitOption (s->display, option++, screen, p->vTable->name);
+
+ g_free (screen);
+ }
+
+ return status;
+}
+
+static void
+gconfKeyChanged (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ CompDisplay *display = (CompDisplay *) user_data;
+
+ gconfGetOptionValue (display, entry);
+}
+
+static Bool
+gconfTimeout (void *closure)
+{
+ while (g_main_pending ()) g_main_iteration (FALSE);
+
+ return TRUE;
+}
+
+static Bool
+gconfInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ CompOption *option;
+ int nOption;
+ GConfDisplay *gd;
+
+ gd = malloc (sizeof (GConfDisplay));
+ if (!gd)
+ return FALSE;
+
+ gd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (gd->screenPrivateIndex < 0)
+ {
+ free (gd);
+ return FALSE;
+ }
+
+ gd->client = gconf_client_get_default ();
+
+ gconf_client_add_dir (gd->client, APP_NAME,
+ GCONF_CLIENT_PRELOAD_NONE, NULL);
+
+ WRAP (gd, d, initPluginForDisplay, gconfInitPluginForDisplay);
+ WRAP (gd, d, setDisplayOption, gconfSetDisplayOption);
+ WRAP (gd, d, setDisplayOptionForPlugin, gconfSetDisplayOptionForPlugin);
+
+ d->privates[displayPrivateIndex].ptr = gd;
+
+ option = compGetDisplayOptions (d, &nOption);
+ while (nOption--)
+ gconfInitOption (d, option++, "allscreens", 0);
+
+ gconf_client_notify_add (gd->client, APP_NAME, gconfKeyChanged, d,
+ NULL, NULL);
+
+ gd->timeoutHandle = compAddTimeout (KEY_CHANGE_TIMEOUT, gconfTimeout, 0);
+
+ return TRUE;
+}
+
+static void
+gconfFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ GCONF_DISPLAY (d);
+
+ compRemoveTimeout (gd->timeoutHandle);
+
+ g_object_unref (gd->client);
+
+ freeScreenPrivateIndex (d, gd->screenPrivateIndex);
+
+ free (gd);
+}
+
+static Bool
+gconfInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ CompOption *option;
+ int nOption;
+ GConfScreen *gs;
+ gchar *screen;
+
+ GCONF_DISPLAY (s->display);
+
+ gs = malloc (sizeof (GConfScreen));
+ if (!gs)
+ return FALSE;
+
+ WRAP (gs, s, initPluginForScreen, gconfInitPluginForScreen);
+ WRAP (gs, s, setScreenOption, gconfSetScreenOption);
+ WRAP (gs, s, setScreenOptionForPlugin, gconfSetScreenOptionForPlugin);
+
+ s->privates[gd->screenPrivateIndex].ptr = gs;
+
+ screen = g_strdup_printf ("screen%d", s->screenNum);
+
+ option = compGetScreenOptions (s, &nOption);
+ while (nOption--)
+ gconfInitOption (s->display, option++, screen, 0);
+
+ return TRUE;
+}
+
+static void
+gconfFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ GCONF_SCREEN (s);
+
+ free (gs);
+}
+
+static Bool
+gconfInit (CompPlugin *p)
+{
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+gconfFini (CompPlugin *p)
+{
+ if (displayPrivateIndex >= 0)
+ freeDisplayPrivateIndex (displayPrivateIndex);
+}
+
+CompPluginVTable gconfVTable = {
+ "gconf",
+ "GConf",
+ "GConf Control Backend",
+ gconfInit,
+ gconfFini,
+ gconfInitDisplay,
+ gconfFiniDisplay,
+ gconfInitScreen,
+ gconfFiniScreen,
+ 0, /* InitWindow */
+ 0, /* FiniWindow */
+ 0, /* GetDisplayOptions */
+ 0, /* SetDisplayOption */
+ 0, /* GetScreenOptions */
+ 0 /* SetScreenOption */
+};
+
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &gconfVTable;
+}
diff --git a/plugins/rotate.c b/plugins/rotate.c
new file mode 100644
index 0000000..1202227
--- /dev/null
+++ b/plugins/rotate.c
@@ -0,0 +1,807 @@
+/*
+ * 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 <math.h>
+#include <sys/time.h>
+
+#include <comp.h>
+
+#define ROTATE_POINTER_INVERT_Y_DEFAULT FALSE
+
+#define ROTATE_POINTER_SENSITIVITY_DEFAULT 1.0f
+#define ROTATE_POINTER_SENSITIVITY_MIN 0.01f
+#define ROTATE_POINTER_SENSITIVITY_MAX 100.0f
+#define ROTATE_POINTER_SENSITIVITY_PRECISION 0.01f
+
+#define ROTATE_POINTER_SENSITIVITY_FACTOR 0.05f
+
+#define ROTATE_ACCELERATION_DEFAULT 4.0f
+#define ROTATE_ACCELERATION_MIN 1.0f
+#define ROTATE_ACCELERATION_MAX 20.0f
+#define ROTATE_ACCELERATION_PRECISION 0.1f
+
+#define ROTATE_INITIATE_BUTTON_DEFAULT Button1
+#define ROTATE_INITIATE_MODIFIERS_DEFAULT (CompPressMask | CompSuperMask)
+
+#define ROTATE_TERMINATE_BUTTON_DEFAULT Button1
+#define ROTATE_TERMINATE_MODIFIERS_DEFAULT CompReleaseMask
+
+#define ROTATE_LEFT_KEY_DEFAULT "Left"
+#define ROTATE_LEFT_MODIFIERS_DEFAULT \
+ (CompPressMask | ControlMask | CompSuperMask)
+
+#define ROTATE_RIGHT_KEY_DEFAULT "Right"
+#define ROTATE_RIGHT_MODIFIERS_DEFAULT \
+ (CompPressMask | ControlMask | CompSuperMask)
+
+#define ROTATE_SNAP_TOP_DEFAULT FALSE
+
+static int displayPrivateIndex;
+
+typedef struct _RotateDisplay {
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+} RotateDisplay;
+
+#define ROTATE_SCREEN_OPTION_POINTER_INVERT_Y 0
+#define ROTATE_SCREEN_OPTION_POINTER_SENSITIVITY 1
+#define ROTATE_SCREEN_OPTION_ACCELERATION 2
+#define ROTATE_SCREEN_OPTION_INITIATE 3
+#define ROTATE_SCREEN_OPTION_TERMINATE 4
+#define ROTATE_SCREEN_OPTION_LEFT 5
+#define ROTATE_SCREEN_OPTION_RIGHT 6
+#define ROTATE_SCREEN_OPTION_SNAP_TOP 7
+#define ROTATE_SCREEN_OPTION_NUM 8
+
+typedef struct _RotateScreen {
+ PreparePaintScreenProc preparePaintScreen;
+ DonePaintScreenProc donePaintScreen;
+ PaintScreenProc paintScreen;
+
+ CompOption opt[ROTATE_SCREEN_OPTION_NUM];
+
+ Bool pointerInvertY;
+ float pointerSensitivity;
+ Bool snapTop;
+ float acceleration;
+
+ int grabIndex;
+
+ GLfloat xrot, xVelocity;
+ GLfloat yrot, yVelocity;
+
+ GLfloat baseXrot;
+
+ Bool moving;
+ GLfloat moveTo;
+
+ int prevPointerX;
+ int prevPointerY;
+ XPoint savedPointer;
+ Bool grabbed;
+} RotateScreen;
+
+#define GET_ROTATE_DISPLAY(d) \
+ ((RotateDisplay *) (d)->privates[displayPrivateIndex].ptr)
+
+#define ROTATE_DISPLAY(d) \
+ RotateDisplay *rd = GET_ROTATE_DISPLAY (d)
+
+#define GET_ROTATE_SCREEN(s, rd) \
+ ((RotateScreen *) (s)->privates[(rd)->screenPrivateIndex].ptr)
+
+#define ROTATE_SCREEN(s) \
+ RotateScreen *rs = GET_ROTATE_SCREEN (s, GET_ROTATE_DISPLAY (s->display))
+
+#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
+
+static CompOption *
+rotateGetScreenOptions (CompScreen *screen,
+ int *count)
+{
+ ROTATE_SCREEN (screen);
+
+ *count = NUM_OPTIONS (rs);
+ return rs->opt;
+}
+
+static Bool
+rotateSetScreenOption (CompScreen *screen,
+ char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ ROTATE_SCREEN (screen);
+
+ o = compFindOption (rs->opt, NUM_OPTIONS (rs), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index) {
+ case ROTATE_SCREEN_OPTION_POINTER_INVERT_Y:
+ if (compSetBoolOption (o, value))
+ {
+ rs->pointerInvertY = o->value.b;
+ return TRUE;
+ }
+ break;
+ case ROTATE_SCREEN_OPTION_POINTER_SENSITIVITY:
+ if (compSetFloatOption (o, value))
+ {
+ rs->pointerSensitivity = o->value.f *
+ ROTATE_POINTER_SENSITIVITY_FACTOR;
+ return TRUE;
+ }
+ break;
+ case ROTATE_SCREEN_OPTION_ACCELERATION:
+ if (compSetFloatOption (o, value))
+ {
+ rs->acceleration = o->value.f;
+ return TRUE;
+ }
+ break;
+ case ROTATE_SCREEN_OPTION_INITIATE:
+ case ROTATE_SCREEN_OPTION_LEFT:
+ case ROTATE_SCREEN_OPTION_RIGHT:
+ if (addScreenBinding (screen, &value->bind))
+ {
+ removeScreenBinding (screen, &o->value.bind);
+
+ if (compSetBindingOption (o, value))
+ return TRUE;
+ }
+ break;
+ case ROTATE_SCREEN_OPTION_TERMINATE:
+ if (compSetBindingOption (o, value))
+ return TRUE;
+ break;
+ case ROTATE_SCREEN_OPTION_SNAP_TOP:
+ if (compSetBoolOption (o, value))
+ {
+ rs->snapTop = o->value.b;
+ return TRUE;
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static void
+rotateScreenInitOptions (RotateScreen *rs,
+ Display *display)
+{
+ CompOption *o;
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_POINTER_INVERT_Y];
+ o->name = "invert_y";
+ o->shortDesc = "Pointer Invert Y";
+ o->longDesc = "Invert Y axis for pointer movement";
+ o->type = CompOptionTypeBool;
+ o->value.b = ROTATE_POINTER_INVERT_Y_DEFAULT;
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_POINTER_SENSITIVITY];
+ o->name = "sensitivity";
+ o->shortDesc = "Pointer Sensitivity";
+ o->longDesc = "Sensitivity of pointer movement";
+ o->type = CompOptionTypeFloat;
+ o->value.f = ROTATE_POINTER_SENSITIVITY_DEFAULT;
+ o->rest.f.min = ROTATE_POINTER_SENSITIVITY_MIN;
+ o->rest.f.max = ROTATE_POINTER_SENSITIVITY_MAX;
+ o->rest.f.precision = ROTATE_POINTER_SENSITIVITY_PRECISION;
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_ACCELERATION];
+ o->name = "acceleration";
+ o->shortDesc = "Acceleration";
+ o->longDesc = "Rotation Acceleration";
+ o->type = CompOptionTypeFloat;
+ o->value.f = ROTATE_ACCELERATION_DEFAULT;
+ o->rest.f.min = ROTATE_ACCELERATION_MIN;
+ o->rest.f.max = ROTATE_ACCELERATION_MAX;
+ o->rest.f.precision = ROTATE_ACCELERATION_PRECISION;
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_INITIATE];
+ o->name = "initiate";
+ o->shortDesc = "Initiate";
+ o->longDesc = "Start Rotation";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeButton;
+ o->value.bind.u.button.modifiers = ROTATE_INITIATE_MODIFIERS_DEFAULT;
+ o->value.bind.u.button.button = ROTATE_INITIATE_BUTTON_DEFAULT;
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_TERMINATE];
+ o->name = "terminate";
+ o->shortDesc = "Terminate";
+ o->longDesc = "Stop Rotation";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeButton;
+ o->value.bind.u.button.modifiers = ROTATE_TERMINATE_MODIFIERS_DEFAULT;
+ o->value.bind.u.button.button = ROTATE_TERMINATE_BUTTON_DEFAULT;
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_LEFT];
+ o->name = "rotate_left";
+ o->shortDesc = "Rotate Left";
+ o->longDesc = "Rotate Left";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = ROTATE_LEFT_MODIFIERS_DEFAULT;
+ o->value.bind.u.key.keycode =
+ XKeysymToKeycode (display,
+ XStringToKeysym (ROTATE_LEFT_KEY_DEFAULT));
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_RIGHT];
+ o->name = "rotate_right";
+ o->shortDesc = "Rotate Right";
+ o->longDesc = "Rotate Right";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeKey;
+ o->value.bind.u.key.modifiers = ROTATE_RIGHT_MODIFIERS_DEFAULT;
+ o->value.bind.u.key.keycode =
+ XKeysymToKeycode (display,
+ XStringToKeysym (ROTATE_RIGHT_KEY_DEFAULT));
+
+ o = &rs->opt[ROTATE_SCREEN_OPTION_SNAP_TOP];
+ o->name = "snap_top";
+ o->shortDesc = "Snap To Top Face";
+ o->longDesc = "Snap Cube Rotation to Top Face";
+ o->type = CompOptionTypeBool;
+ o->value.b = ROTATE_SNAP_TOP_DEFAULT;
+}
+
+static int
+adjustVelocity (RotateScreen *rs)
+{
+ float xrot, yrot, adjust, amount;
+
+ if (rs->moving)
+ {
+ xrot = rs->moveTo + (rs->xrot + rs->baseXrot);
+ }
+ else
+ {
+ xrot = rs->xrot;
+ if (rs->xrot < -45.0f)
+ xrot = 90.0f + rs->xrot;
+ else if (rs->xrot > 45.0f)
+ xrot = rs->xrot - 90.0f;
+ }
+
+ adjust = -xrot * 0.05f * rs->acceleration;
+ amount = fabs (xrot);
+ if (amount < 10.0f)
+ amount = 10.0f;
+ else if (amount > 30.0f)
+ amount = 30.0f;
+
+ rs->xVelocity = (amount * rs->xVelocity + adjust) / (amount + 2.0f);
+
+ if (rs->snapTop && rs->yrot > 50.0f)
+ yrot = -(90.f - rs->yrot);
+ else
+ yrot = rs->yrot;
+
+ adjust = -yrot * 0.05f * rs->acceleration;
+ amount = fabs (rs->yrot);
+ if (amount < 10.0f)
+ amount = 10.0f;
+ else if (amount > 30.0f)
+ amount = 30.0f;
+
+ rs->yVelocity = (amount * rs->yVelocity + adjust) / (amount + 2.0f);
+
+ return (fabs (xrot) < 0.1f && fabs (rs->xVelocity) < 0.2f &&
+ fabs (yrot) < 0.1f && fabs (rs->yVelocity) < 0.2f);
+}
+
+static void
+rotatePreparePaintScreen (CompScreen *s,
+ int msSinceLastPaint)
+{
+ ROTATE_SCREEN (s);
+
+ if (rs->grabIndex)
+ {
+ rs->xrot += (rs->xVelocity * msSinceLastPaint) / s->redrawTime;
+ rs->yrot += (rs->yVelocity * msSinceLastPaint) / s->redrawTime;
+
+ if (rs->xrot > 90.0f)
+ {
+ rs->baseXrot += 90.0f;
+ rs->xrot -= 90.0f;
+ }
+ else if (rs->xrot < 0.0f)
+ {
+ rs->baseXrot -= 90.0f;
+ rs->xrot += 90.0f;
+ }
+
+ if (rs->yrot > 100.0f)
+ {
+ rs->yVelocity = -0.5f;
+ rs->yrot = 100.0f;
+ }
+ else if (rs->yrot < -100.0f)
+ {
+ rs->yVelocity = 0.5f;
+ rs->yrot = -100.0f;
+ }
+
+ if (rs->grabbed)
+ {
+ rs->xVelocity /= 1.25f;
+ rs->yVelocity /= 1.25f;
+
+ if (fabs (rs->xVelocity) < 0.01f)
+ rs->xVelocity = 0.0f;
+ if (fabs (rs->yVelocity) < 0.01f)
+ rs->yVelocity = 0.0f;
+ }
+ else if (adjustVelocity (rs))
+ {
+ rs->xVelocity = 0.0f;
+ rs->yVelocity = 0.0f;
+
+ if (fabs (rs->yrot) < 0.1f)
+ {
+ int move;
+
+ rs->xrot += rs->baseXrot;
+ if (rs->xrot < 0.0f)
+ move = (rs->xrot / 90.0f) - 0.5f;
+ else
+ move = (rs->xrot / 90.0f) + 0.5f;
+
+ if (move)
+ {
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (w->attrib.map_state != IsViewable)
+ continue;
+
+ if (w->type == s->display->winDesktopAtom ||
+ w->type == s->display->winDockAtom)
+ continue;
+
+ (*s->invisibleWindowMove) (w, s->width * move, 0);
+
+ w->invisible = WINDOW_INVISIBLE (w);
+
+ XMoveWindow (s->display->display,
+ (w->client) ? w->client : w->id,
+ w->attrib.x, w->attrib.y);
+ }
+ }
+
+ rs->xrot = 0.0f;
+ rs->yrot = 0.0f;
+ rs->baseXrot = rs->moveTo = 0.0f;
+ rs->moving = FALSE;
+
+ removeScreenGrab (s, rs->grabIndex, &rs->savedPointer);
+ rs->grabIndex = 0;
+ }
+ }
+ }
+
+ UNWRAP (rs, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, msSinceLastPaint);
+ WRAP (rs, s, preparePaintScreen, rotatePreparePaintScreen);
+}
+
+static void
+rotateDonePaintScreen (CompScreen *s)
+{
+ ROTATE_SCREEN (s);
+
+ if (rs->grabIndex)
+ {
+ if ((!rs->grabbed && !rs->snapTop) || rs->xVelocity || rs->yVelocity)
+ damageScreen (s);
+ }
+
+ UNWRAP (rs, s, donePaintScreen);
+ (*s->donePaintScreen) (s);
+ WRAP (rs, s, donePaintScreen, rotateDonePaintScreen);
+}
+
+static Bool
+rotatePaintScreen (CompScreen *s,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ Region region,
+ unsigned int mask)
+{
+ Bool status;
+
+ ROTATE_SCREEN (s);
+
+ if (rs->grabIndex)
+ {
+ ScreenPaintAttrib sa = *sAttrib;
+
+ sa.xRotate += rs->baseXrot + rs->xrot;
+ sa.vRotate += rs->yrot;
+
+ mask &= ~PAINT_SCREEN_REGION_MASK;
+ mask |= PAINT_SCREEN_TRANSFORMED_MASK;
+
+ UNWRAP (rs, s, paintScreen);
+ status = (*s->paintScreen) (s, &sa, wAttrib, region, mask);
+ WRAP (rs, s, paintScreen, rotatePaintScreen);
+ }
+ else
+ {
+ UNWRAP (rs, s, paintScreen);
+ status = (*s->paintScreen) (s, sAttrib, wAttrib, region, mask);
+ WRAP (rs, s, paintScreen, rotatePaintScreen);
+ }
+
+ return status;
+}
+
+static void
+rotateInitiate (CompScreen *s,
+ int x,
+ int y)
+{
+ ROTATE_SCREEN (s);
+
+ rs->prevPointerX = x;
+ rs->prevPointerY = y;
+
+ rs->moving = FALSE;
+
+ if (!rs->grabIndex)
+ {
+ rs->grabIndex = pushScreenGrab (s, s->invisibleCursor);
+ if (rs->grabIndex)
+ {
+ rs->savedPointer.x = rs->prevPointerX;
+ rs->savedPointer.y = rs->prevPointerY;
+
+ gettimeofday (&s->lastRedraw, 0);
+ }
+ }
+
+ if (rs->grabIndex)
+ {
+ rs->grabbed = TRUE;
+ rs->snapTop = rs->opt[ROTATE_SCREEN_OPTION_SNAP_TOP].value.b;
+ }
+}
+
+static void
+rotateLeft (CompScreen *s,
+ int x,
+ int y)
+{
+ ROTATE_SCREEN (s);
+
+ if (!rs->grabIndex)
+ rotateInitiate (s, x, y);
+
+ if (rs->grabIndex)
+ {
+ rs->moving = TRUE;
+ rs->moveTo -= 90.0f;
+ rs->grabbed = FALSE;
+ damageScreen (s);
+ }
+}
+
+static void
+rotateRight (CompScreen *s,
+ int x,
+ int y)
+{
+ ROTATE_SCREEN (s);
+
+ if (!rs->grabIndex)
+ rotateInitiate (s, x, y);
+
+ if (rs->grabIndex)
+ {
+ rs->moving = TRUE;
+ rs->moveTo += 90.0f;
+ rs->grabbed = FALSE;
+
+ damageScreen (s);
+ }
+}
+
+static void
+rotateTerminate (CompScreen *s)
+{
+ ROTATE_SCREEN (s);
+
+ if (rs->grabIndex)
+ {
+ rs->grabbed = FALSE;
+ damageScreen (s);
+ }
+}
+
+static void
+rotateHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ CompScreen *s;
+
+ ROTATE_DISPLAY (d);
+
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ s = findScreenAtDisplay (d, event->xkey.root);
+ if (s)
+ {
+ ROTATE_SCREEN (s);
+
+ if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_INITIATE], event))
+ rotateInitiate (s, event->xkey.x_root, event->xkey.y_root);
+
+ if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_LEFT], event))
+ rotateLeft (s, event->xkey.x_root, event->xkey.y_root);
+
+ if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_RIGHT], event))
+ rotateRight (s, event->xkey.x_root, event->xkey.y_root);
+
+ if (EV_KEY (&rs->opt[ROTATE_SCREEN_OPTION_TERMINATE], event))
+ rotateTerminate (s);
+
+ if (event->type == KeyPress &&
+ event->xkey.keycode == s->escapeKeyCode)
+ {
+ rs->snapTop = FALSE;
+ rotateTerminate (s);
+ }
+ }
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ s = findScreenAtDisplay (d, event->xbutton.root);
+ if (s)
+ {
+ ROTATE_SCREEN (s);
+
+ if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_INITIATE], event))
+ rotateInitiate (s,
+ event->xbutton.x_root,
+ event->xbutton.y_root);
+
+ if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_LEFT], event))
+ rotateLeft (s, event->xbutton.x_root, event->xbutton.y_root);
+
+ if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_RIGHT], event))
+ rotateRight (s, event->xbutton.x_root, event->xbutton.y_root);
+
+ if (EV_BUTTON (&rs->opt[ROTATE_SCREEN_OPTION_TERMINATE], event))
+ rotateTerminate (s);
+ }
+ break;
+ case MotionNotify:
+ s = findScreenAtDisplay (d, event->xmotion.root);
+ if (s)
+ {
+ ROTATE_SCREEN (s);
+
+ if (rs->grabIndex && rs->grabbed)
+ {
+ GLfloat pointerDx;
+ GLfloat pointerDy;
+
+ pointerDx = event->xmotion.x_root - rs->prevPointerX;
+ pointerDy = event->xmotion.y_root - rs->prevPointerY;
+ rs->prevPointerX = event->xmotion.x_root;
+ rs->prevPointerY = event->xmotion.y_root;
+
+ if (event->xmotion.x_root < 50 ||
+ event->xmotion.y_root < 50 ||
+ event->xmotion.x_root > s->width - 50 ||
+ event->xmotion.y_root > s->height - 50)
+ {
+ rs->prevPointerX = s->width / 2;
+ rs->prevPointerY = s->height / 2;
+
+ XWarpPointer (d->display, None, s->root, 0, 0, 0, 0,
+ rs->prevPointerX, rs->prevPointerY);
+ }
+
+ if (rs->pointerInvertY)
+ pointerDy = -pointerDy;
+
+ rs->xVelocity += pointerDx * rs->pointerSensitivity;
+ rs->yVelocity += pointerDy * rs->pointerSensitivity;
+
+ damageScreen (s);
+ return;
+ }
+ }
+ default:
+ break;
+ }
+
+ UNWRAP (rd, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (rd, d, handleEvent, rotateHandleEvent);
+}
+
+static Bool
+rotateInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ RotateDisplay *rd;
+
+ rd = malloc (sizeof (RotateDisplay));
+ if (!rd)
+ return FALSE;
+
+ rd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (rd->screenPrivateIndex < 0)
+ {
+ free (rd);
+ return FALSE;
+ }
+
+ WRAP (rd, d, handleEvent, rotateHandleEvent);
+
+ d->privates[displayPrivateIndex].ptr = rd;
+
+ return TRUE;
+}
+
+static void
+rotateFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ ROTATE_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, rd->screenPrivateIndex);
+
+ UNWRAP (rd, d, handleEvent);
+
+ free (rd);
+}
+
+static Bool
+rotateInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ RotateScreen *rs;
+
+ ROTATE_DISPLAY (s->display);
+
+ rs = malloc (sizeof (RotateScreen));
+ if (!rs)
+ return FALSE;
+
+ rs->grabIndex = 0;
+
+ rs->xrot = 0.0f;
+ rs->xVelocity = 0.0f;
+ rs->yrot = 0.0f;
+ rs->yVelocity = 0.0f;
+
+ rs->baseXrot = 0.0f;
+
+ rs->moving = FALSE;
+ rs->moveTo = 0.0f;
+
+ rs->savedPointer.x = 0;
+ rs->savedPointer.y = 0;
+ rs->prevPointerX = 0;
+ rs->prevPointerY = 0;
+
+ rs->grabbed = FALSE;
+ rs->snapTop = FALSE;
+
+ rs->acceleration = ROTATE_ACCELERATION_DEFAULT;
+
+ rs->pointerInvertY = ROTATE_POINTER_INVERT_Y_DEFAULT;
+ rs->pointerSensitivity = ROTATE_POINTER_SENSITIVITY_DEFAULT *
+ ROTATE_POINTER_SENSITIVITY_FACTOR;
+
+ rotateScreenInitOptions (rs, s->display->display);
+
+ addScreenBinding (s, &rs->opt[ROTATE_SCREEN_OPTION_INITIATE].value.bind);
+ addScreenBinding (s, &rs->opt[ROTATE_SCREEN_OPTION_LEFT].value.bind);
+ addScreenBinding (s, &rs->opt[ROTATE_SCREEN_OPTION_RIGHT].value.bind);
+
+ WRAP (rs, s, preparePaintScreen, rotatePreparePaintScreen);
+ WRAP (rs, s, donePaintScreen, rotateDonePaintScreen);
+ WRAP (rs, s, paintScreen, rotatePaintScreen);
+
+ s->privates[rd->screenPrivateIndex].ptr = rs;
+
+ return TRUE;
+}
+
+static void
+rotateFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ ROTATE_SCREEN (s);
+
+ UNWRAP (rs, s, preparePaintScreen);
+ UNWRAP (rs, s, donePaintScreen);
+ UNWRAP (rs, s, paintScreen);
+
+ free (rs);
+}
+
+static Bool
+rotateInit (CompPlugin *p)
+{
+ if (!findActivePlugin ("cube"))
+ {
+ fprintf (stderr, "%s: 'cube' required but not loaded\n", programName);
+ return FALSE;
+ }
+
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+rotateFini (CompPlugin *p)
+{
+ if (displayPrivateIndex >= 0)
+ freeDisplayPrivateIndex (displayPrivateIndex);
+}
+
+CompPluginVTable rotateVTable = {
+ "rotate",
+ "Rotate Cube",
+ "Rotate desktop cube",
+ rotateInit,
+ rotateFini,
+ rotateInitDisplay,
+ rotateFiniDisplay,
+ rotateInitScreen,
+ rotateFiniScreen,
+ 0, /* InitWindow */
+ 0, /* FiniWindow */
+ 0, /* GetDisplayOptions */
+ 0, /* SetDisplayOption */
+ rotateGetScreenOptions,
+ rotateSetScreenOption
+};
+
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &rotateVTable;
+}
diff --git a/plugins/wobbly.c b/plugins/wobbly.c
new file mode 100644
index 0000000..6a18845
--- /dev/null
+++ b/plugins/wobbly.c
@@ -0,0 +1,1496 @@
+/*
+ * 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>
+ */
+
+/*
+ * Spring model implemented by Kristian Hogsberg.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <comp.h>
+
+#define GRID_WIDTH 4
+#define GRID_HEIGHT 4
+
+#define MODEL_MAX_SPRINGS (GRID_WIDTH * GRID_HEIGHT * 2)
+
+typedef struct _xy_pair {
+ float x, y;
+} Point, Vector;
+
+typedef struct _Object {
+ Vector force;
+ Point position;
+ Vector velocity;
+ float theta;
+ Bool immobile;
+} Object;
+
+typedef struct _Spring {
+ Object *a;
+ Object *b;
+ Vector offset;
+} Spring;
+
+typedef struct _Model {
+ Object *objects;
+ int numObjects;
+ Spring springs[MODEL_MAX_SPRINGS];
+ int numSprings;
+ Object *anchorObject;
+ float steps;
+ Vector translate;
+ Vector scale;
+} Model;
+
+#define WOBBLY_FRICTION_DEFAULT 2.5f
+#define WOBBLY_FRICTION_MIN 0.1f
+#define WOBBLY_FRICTION_MAX 10.0f
+#define WOBBLY_FRICTION_PRECISION 0.1f
+
+#define WOBBLY_SPRING_K_DEFAULT 3.5f
+#define WOBBLY_SPRING_K_MIN 0.1f
+#define WOBBLY_SPRING_K_MAX 10.0f
+#define WOBBLY_SPRING_K_PRECISION 0.1f
+
+#define WOBBLY_GRID_SIZE_DEFAULT 64
+#define WOBBLY_GRID_SIZE_MIN 16
+#define WOBBLY_GRID_SIZE_MAX 512
+
+typedef enum {
+ WobblyEffectNone = 0,
+ WobblyEffectExplode,
+ WobblyEffectShiver
+} WobblyEffect;
+
+static char *effectName[] = {
+ "None",
+ "Explode",
+ "Shiver"
+};
+
+static WobblyEffect effectType[] = {
+ WobblyEffectNone,
+ WobblyEffectExplode,
+ WobblyEffectShiver
+};
+
+#define NUM_EFFECT (sizeof (effectType) / sizeof (effectType[0]))
+
+#define WOBBLY_MAP_DEFAULT (effectName[0])
+#define WOBBLY_FOCUS_DEFAULT (effectName[0])
+
+static int displayPrivateIndex;
+
+typedef struct _WobblyDisplay {
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+} WobblyDisplay;
+
+#define WOBBLY_SCREEN_OPTION_FRICTION 0
+#define WOBBLY_SCREEN_OPTION_SPRING_K 1
+#define WOBBLY_SCREEN_OPTION_GRID_SIZE 2
+#define WOBBLY_SCREEN_OPTION_MAP_EFFECT 3
+#define WOBBLY_SCREEN_OPTION_FOCUS_EFFECT 4
+#define WOBBLY_SCREEN_OPTION_NUM 5
+
+typedef struct _WobblyScreen {
+ int windowPrivateIndex;
+ PreparePaintScreenProc preparePaintScreen;
+ DonePaintScreenProc donePaintScreen;
+ PaintScreenProc paintScreen;
+ PaintWindowProc paintWindow;
+ InvisibleWindowMoveProc invisibleWindowMove;
+
+ CompOption opt[WOBBLY_SCREEN_OPTION_NUM];
+
+ Bool wobblyWindows;
+
+ WobblyEffect mapEffect;
+ WobblyEffect focusEffect;
+} WobblyScreen;
+
+typedef struct _WobblyWindow {
+ Model *model;
+ Bool wobbly;
+ GLfloat *vertices;
+ int vertexSize;
+ GLushort *indices;
+ int indexSize;
+} WobblyWindow;
+
+#define GET_WOBBLY_DISPLAY(d) \
+ ((WobblyDisplay *) (d)->privates[displayPrivateIndex].ptr)
+
+#define WOBBLY_DISPLAY(d) \
+ WobblyDisplay *wd = GET_WOBBLY_DISPLAY (d)
+
+#define GET_WOBBLY_SCREEN(s, wd) \
+ ((WobblyScreen *) (s)->privates[(wd)->screenPrivateIndex].ptr)
+
+#define WOBBLY_SCREEN(s) \
+ WobblyScreen *ws = GET_WOBBLY_SCREEN (s, GET_WOBBLY_DISPLAY (s->display))
+
+#define GET_WOBBLY_WINDOW(w, ws) \
+ ((WobblyWindow *) (w)->privates[(ws)->windowPrivateIndex].ptr)
+
+#define WOBBLY_WINDOW(w) \
+ WobblyWindow *ww = GET_WOBBLY_WINDOW (w, \
+ GET_WOBBLY_SCREEN (w->screen, \
+ GET_WOBBLY_DISPLAY (w->screen->display)))
+
+#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
+
+static CompOption *
+wobblyGetScreenOptions (CompScreen *screen,
+ int *count)
+{
+ WOBBLY_SCREEN (screen);
+
+ *count = NUM_OPTIONS (ws);
+ return ws->opt;
+}
+
+static Bool
+wobblySetScreenOption (CompScreen *screen,
+ char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ WOBBLY_SCREEN (screen);
+
+ o = compFindOption (ws->opt, NUM_OPTIONS (ws), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index) {
+ case WOBBLY_SCREEN_OPTION_FRICTION:
+ case WOBBLY_SCREEN_OPTION_SPRING_K:
+ if (compSetFloatOption (o, value))
+ return TRUE;
+ break;
+ case WOBBLY_SCREEN_OPTION_GRID_SIZE:
+ if (compSetIntOption (o, value))
+ return TRUE;
+ break;
+ case WOBBLY_SCREEN_OPTION_MAP_EFFECT:
+ if (compSetStringOption (o, value))
+ {
+ int i;
+
+ for (i = 0; i < NUM_EFFECT; i++)
+ {
+ if (strcmp (o->value.s, effectName[i]) == 0)
+ {
+ ws->mapEffect = effectType[i];
+ return TRUE;
+ }
+ }
+ }
+ break;
+ case WOBBLY_SCREEN_OPTION_FOCUS_EFFECT:
+ if (compSetStringOption (o, value))
+ {
+ int i;
+
+ for (i = 0; i < NUM_EFFECT; i++)
+ {
+ if (strcmp (o->value.s, effectName[i]) == 0)
+ {
+ ws->focusEffect = effectType[i];
+ return TRUE;
+ }
+ }
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static void
+wobblyScreenInitOptions (WobblyScreen *ws)
+{
+ CompOption *o;
+
+ o = &ws->opt[WOBBLY_SCREEN_OPTION_FRICTION];
+ o->name = "friction";
+ o->shortDesc = "Friction";
+ o->longDesc = "Spring Friction";
+ o->type = CompOptionTypeFloat;
+ o->value.f = WOBBLY_FRICTION_DEFAULT;
+ o->rest.f.min = WOBBLY_FRICTION_MIN;
+ o->rest.f.max = WOBBLY_FRICTION_MAX;
+ o->rest.f.precision = WOBBLY_FRICTION_PRECISION;
+
+ o = &ws->opt[WOBBLY_SCREEN_OPTION_SPRING_K];
+ o->name = "spring_k";
+ o->shortDesc = "Spring K";
+ o->longDesc = "Spring Konstant";
+ o->type = CompOptionTypeFloat;
+ o->value.f = WOBBLY_SPRING_K_DEFAULT;
+ o->rest.f.min = WOBBLY_SPRING_K_MIN;
+ o->rest.f.max = WOBBLY_SPRING_K_MAX;
+ o->rest.f.precision = WOBBLY_SPRING_K_PRECISION;
+
+ o = &ws->opt[WOBBLY_SCREEN_OPTION_GRID_SIZE];
+ o->name = "grid_size";
+ o->shortDesc = "Grid Size";
+ o->longDesc = "Vertex Grid Resolution";
+ o->type = CompOptionTypeInt;
+ o->value.i = WOBBLY_GRID_SIZE_DEFAULT;
+ o->rest.i.min = WOBBLY_GRID_SIZE_MIN;
+ o->rest.i.max = WOBBLY_GRID_SIZE_MAX;
+
+ o = &ws->opt[WOBBLY_SCREEN_OPTION_MAP_EFFECT];
+ o->name = "map_effect";
+ o->shortDesc = "Map Effect";
+ o->longDesc = "Map Window Effect";
+ o->type = CompOptionTypeString;
+ o->value.s = strdup (WOBBLY_MAP_DEFAULT);
+ o->rest.s.string = effectName;
+ o->rest.s.nString = NUM_EFFECT;
+
+ o = &ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_EFFECT];
+ o->name = "focus_effect";
+ o->shortDesc = "Focus Effect";
+ o->longDesc = "Focus Window Effect";
+ o->type = CompOptionTypeString;
+ o->value.s = strdup (WOBBLY_FOCUS_DEFAULT);
+ o->rest.s.string = effectName;
+ o->rest.s.nString = NUM_EFFECT;
+}
+
+static void
+objectInit (Object *object,
+ float positionX,
+ float positionY,
+ float velocityX,
+ float velocityY)
+{
+ object->force.x = 0;
+ object->force.y = 0;
+
+ object->position.x = positionX;
+ object->position.y = positionY;
+
+ object->velocity.x = velocityX;
+ object->velocity.y = velocityY;
+
+ object->theta = 0;
+ object->immobile = FALSE;
+}
+
+static void
+springInit (Spring *spring,
+ Object *a,
+ Object *b,
+ float offsetX,
+ float offsetY)
+{
+ spring->a = a;
+ spring->b = b;
+ spring->offset.x = offsetX;
+ spring->offset.y = offsetY;
+}
+
+static void
+modelAddSpring (Model *model,
+ Object *a,
+ Object *b,
+ float offsetX,
+ float offsetY)
+{
+ Spring *spring;
+
+ spring = &model->springs[model->numSprings];
+ model->numSprings++;
+
+ springInit (spring, a, b, offsetX, offsetY);
+}
+
+static void
+modelSetMiddleAnchor (Model *model,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ float w, h;
+
+ if (model->anchorObject)
+ model->anchorObject->immobile = FALSE;
+
+ w = (float) width * model->scale.x;
+ h = (float) height * model->scale.y;
+ x += model->translate.x;
+ y += model->translate.y;
+
+ model->anchorObject = &model->objects[GRID_WIDTH *
+ ((GRID_HEIGHT - 1) / 2) +
+ (GRID_WIDTH - 1) / 2];
+ model->anchorObject->position.x = x +
+ ((GRID_WIDTH - 1) / 2 * w) / (float) (GRID_WIDTH - 1);
+ model->anchorObject->position.y = y +
+ ((GRID_HEIGHT - 1) / 2 * h) / (float) (GRID_HEIGHT - 1);
+
+ model->anchorObject->immobile = TRUE;
+}
+
+static void
+modelInitObjects (Model *model,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ int gridX, gridY, i = 0;
+ float w, h;
+
+ w = (float) width * model->scale.x;
+ h = (float) height * model->scale.y;
+ x += model->translate.x;
+ y += model->translate.y;
+
+ for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
+ {
+ for (gridX = 0; gridX < GRID_WIDTH; gridX++)
+ {
+ objectInit (&model->objects[i],
+ x + (gridX * w) / (float) (GRID_WIDTH - 1),
+ y + (gridY * h) / (float) (GRID_HEIGHT - 1),
+ 0, 0);
+ i++;
+ }
+ }
+
+ modelSetMiddleAnchor (model, x, y, width, height);
+}
+
+static void
+modelAdjustObjectsForExplosion (Model *model,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ int gridX, gridY, i = 0;
+ int vX, vY;
+ float scale;
+ float w, h;
+
+ w = (float) width * model->scale.x;
+ h = (float) height * model->scale.y;
+ x += model->translate.x;
+ y += model->translate.y;
+
+ for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
+ {
+ for (gridX = 0; gridX < GRID_WIDTH; gridX++)
+ {
+ if (!model->objects[i].immobile)
+ {
+ scale = ((float) rand () * 0.1f) / RAND_MAX;
+ vX = (model->objects[i].position.x - (x + w / 2.0f)) * scale;
+ vY = (model->objects[i].position.y - (y + h / 2.0f)) * scale;
+
+ model->objects[i].position.x = x + w / 2.0f;
+ model->objects[i].position.y = y + h / 2.0f;
+
+ model->objects[i].velocity.x += vX;
+ model->objects[i].velocity.y += vY;
+ }
+
+ i++;
+ }
+ }
+}
+
+static void
+modelAdjustObjectsForShiver (Model *model,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ int gridX, gridY, i = 0;
+ float vX, vY;
+ float scale;
+ float w, h;
+
+ w = (float) width * model->scale.x;
+ h = (float) height * model->scale.y;
+ x += model->translate.x;
+ y += model->translate.y;
+
+ for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
+ {
+ for (gridX = 0; gridX < GRID_WIDTH; gridX++)
+ {
+ if (!model->objects[i].immobile)
+ {
+ vX = model->objects[i].position.x - (x + w / 2);
+ vY = model->objects[i].position.y - (y + h / 2);
+
+ vX /= w;
+ vY /= h;
+
+ scale = ((float) rand () * 7.5f) / RAND_MAX;
+
+ model->objects[i].velocity.x += vX * scale;
+ model->objects[i].velocity.y += vY * scale;
+ }
+
+ i++;
+ }
+ }
+}
+
+static void
+modelInitSprings (Model *model,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ int gridX, gridY, i = 0;
+ float hpad, vpad;
+ float w, h;
+
+ model->numSprings = 0;
+
+ w = (float) width * model->scale.x;
+ h = (float) height * model->scale.y;
+
+ hpad = w / (GRID_WIDTH - 1);
+ vpad = h / (GRID_HEIGHT - 1);
+
+ for (gridY = 0; gridY < GRID_HEIGHT; gridY++)
+ {
+ for (gridX = 0; gridX < GRID_WIDTH; gridX++)
+ {
+ if (gridX > 0)
+ modelAddSpring (model,
+ &model->objects[i - 1],
+ &model->objects[i],
+ hpad, 0);
+
+ if (gridY > 0)
+ modelAddSpring (model,
+ &model->objects[i - GRID_WIDTH],
+ &model->objects[i],
+ 0, vpad);
+
+ i++;
+ }
+ }
+}
+
+static void
+modelMove (Model *model,
+ int dx,
+ int dy)
+{
+ int i;
+
+ for (i = 0; i < model->numObjects; i++)
+ {
+ model->objects[i].position.x += dx;
+ model->objects[i].position.y += dy;
+ }
+}
+
+static Model *
+createModel (int x,
+ int y,
+ int width,
+ int height)
+{
+ Model *model;
+
+ model = malloc (sizeof (Model));
+ if (!model)
+ return 0;
+
+ model->numObjects = GRID_WIDTH * GRID_HEIGHT;
+ model->objects = malloc (sizeof (Object) * model->numObjects);
+ if (!model->objects)
+ return 0;
+
+ model->anchorObject = 0;
+ model->numSprings = 0;
+
+ model->steps = 0;
+
+ model->translate.x = 0.0f;
+ model->translate.y = 0.0f;
+
+ model->scale.x = 1.0f;
+ model->scale.y = 1.0f;
+
+ modelInitObjects (model, x, y, width, height);
+ modelInitSprings (model, x, y, width, height);
+
+ return model;
+}
+
+static void
+objectApplyForce (Object *object,
+ float fx,
+ float fy)
+{
+ object->force.x += fx;
+ object->force.y += fy;
+}
+
+static void
+springExertForces (Spring *spring,
+ float k)
+{
+ Vector da, db;
+ Vector a, b;
+
+ a = spring->a->position;
+ b = spring->b->position;
+
+ da.x = 0.5f * (b.x - a.x - spring->offset.x);
+ da.y = 0.5f * (b.y - a.y - spring->offset.y);
+
+ db.x = 0.5f * (a.x - b.x + spring->offset.x);
+ db.y = 0.5f * (a.y - b.y + spring->offset.y);
+
+ objectApplyForce (spring->a, k * da.x, k * da.y);
+ objectApplyForce (spring->b, k * db.x, k * db.y);
+}
+
+static float
+modelStepObject (Model *model,
+ Object *object,
+ float friction)
+{
+ object->theta += 0.05f;
+
+ object->force.x -= friction * object->velocity.x;
+ object->force.y -= friction * object->velocity.y;
+
+ if (object->immobile)
+ {
+ object->velocity.x = 0.0f;
+ object->velocity.y = 0.0f;
+ }
+ else
+ {
+ object->velocity.x += object->force.x / 20.0f;
+ object->velocity.y += object->force.y / 20.0f;
+
+ object->position.x += object->velocity.x;
+ object->position.y += object->velocity.y;
+ }
+
+ object->force.x = 0.0f;
+ object->force.y = 0.0f;
+
+ return fabs (object->velocity.x) + fabs (object->velocity.y);
+}
+
+static Bool
+modelStep (Model *model,
+ float friction,
+ float k,
+ float time)
+{
+ int i, j, steps;
+ float velocitySum = 0.0f;
+
+ model->steps += time / 15.0f;
+ steps = floor (model->steps);
+ model->steps -= steps;
+
+ if (!steps)
+ return TRUE;
+
+ for (j = 0; j < steps; j++)
+ {
+ for (i = 0; i < model->numSprings; i++)
+ springExertForces (&model->springs[i], k);
+
+ for (i = 0; i < model->numObjects; i++)
+ velocitySum += modelStepObject (model,
+ &model->objects[i],
+ friction);
+ }
+
+ return (velocitySum > 0.5f);
+}
+
+static void
+bezierPatchEvaluate (Model *model,
+ float u,
+ float v,
+ float *patchX,
+ float *patchY)
+{
+ float coeffsU[4], coeffsV[4];
+ float x, y;
+ int i, j;
+
+ coeffsU[0] = (1 - u) * (1 - u) * (1 - u);
+ coeffsU[1] = 3 * u * (1 - u) * (1 - u);
+ coeffsU[2] = 3 * u * u * (1 - u);
+ coeffsU[3] = u * u * u;
+
+ coeffsV[0] = (1 - v) * (1 - v) * (1 - v);
+ coeffsV[1] = 3 * v * (1 - v) * (1 - v);
+ coeffsV[2] = 3 * v * v * (1 - v);
+ coeffsV[3] = v * v * v;
+
+ x = y = 0.0f;
+
+ for (i = 0; i < 4; i++)
+ {
+ for (j = 0; j < 4; j++)
+ {
+ x += coeffsU[i] * coeffsV[j] *
+ model->objects[j * GRID_WIDTH + i].position.x;
+ y += coeffsU[i] * coeffsV[j] *
+ model->objects[j * GRID_WIDTH + i].position.y;
+ }
+ }
+
+ *patchX = x;
+ *patchY = y;
+}
+
+static Bool
+wobblyEnsureModel (CompWindow *w)
+{
+ WOBBLY_WINDOW (w);
+
+ if (!ww->model)
+ {
+ ww->model = createModel (w->attrib.x, w->attrib.y,
+ w->width, w->height);
+ if (!ww->model)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static float
+objectDistance (Object *object,
+ float x,
+ float y)
+{
+ float dx, dy;
+
+ dx = object->position.x - x;
+ dy = object->position.y - y;
+
+ return sqrt (dx * dx + dy * dy);
+}
+
+static Object *
+modelFindNearestObject (Model *model,
+ float x,
+ float y)
+{
+ Object *object = &model->objects[0];
+ float distance, minDistance = 0.0;
+ int i;
+
+ for (i = 0; i < model->numObjects; i++)
+ {
+ distance = objectDistance (&model->objects[i], x, y);
+ if (i == 0 || distance < minDistance)
+ {
+ minDistance = distance;
+ object = &model->objects[i];
+ }
+ }
+
+ return object;
+}
+
+static void
+wobblyMoveWindow (CompWindow *w,
+ int dx,
+ int dy)
+{
+ WOBBLY_WINDOW (w);
+
+ if (!wobblyEnsureModel (w))
+ return;
+
+ if (!ww->wobbly)
+ {
+ Window win;
+ int i, x, y;
+ unsigned int ui;
+
+ WOBBLY_SCREEN (w->screen);
+
+ XQueryPointer (w->screen->display->display, w->screen->root,
+ &win, &win, &x, &y, &i, &i, &ui);
+
+ ww->model->anchorObject->immobile = FALSE;
+
+ if (x < w->attrib.x || x > w->attrib.x + w->width ||
+ y < w->attrib.y || y > w->attrib.y + w->height)
+ {
+ x = w->attrib.x + w->width / 2;
+ y = w->attrib.y + w->height / 2;
+ }
+
+ ww->model->anchorObject = modelFindNearestObject (ww->model, x, y);
+ ww->model->anchorObject->immobile = TRUE;
+
+ ww->wobbly = ws->wobblyWindows = TRUE;
+ }
+
+ ww->model->anchorObject->position.x += dx;
+ ww->model->anchorObject->position.y += dy;
+
+ damageScreen (w->screen);
+}
+
+static Bool
+isWobblyWin (CompWindow *w)
+{
+ if (w->type == w->screen->display->winDesktopAtom ||
+ w->type == w->screen->display->winDockAtom)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+wobblyPreparePaintScreen (CompScreen *s,
+ int msSinceLastPaint)
+{
+ WobblyWindow *ww;
+ CompWindow *w;
+
+ WOBBLY_SCREEN (s);
+
+ if (ws->wobblyWindows)
+ {
+ float friction, springK;
+
+ friction = ws->opt[WOBBLY_SCREEN_OPTION_FRICTION].value.f;
+ springK = ws->opt[WOBBLY_SCREEN_OPTION_SPRING_K].value.f;
+
+ ws->wobblyWindows = FALSE;
+ for (w = s->windows; w; w = w->next)
+ {
+ ww = GET_WOBBLY_WINDOW (w, ws);
+
+ if (ww->wobbly)
+ {
+ if (w->attrib.map_state == IsViewable &&
+ modelStep (ww->model, friction, springK, msSinceLastPaint))
+ {
+ ws->wobblyWindows = TRUE;
+ }
+ else
+ {
+ modelSetMiddleAnchor (ww->model,
+ w->attrib.x, w->attrib.y,
+ w->width, w->height);
+ ww->wobbly = FALSE;
+ }
+ }
+ }
+ }
+
+ UNWRAP (ws, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, msSinceLastPaint);
+ WRAP (ws, s, preparePaintScreen, wobblyPreparePaintScreen);
+}
+
+static void
+wobblyDonePaintScreen (CompScreen *s)
+{
+ WOBBLY_SCREEN (s);
+
+ if (ws->wobblyWindows)
+ damageScreen (s);
+
+ UNWRAP (ws, s, donePaintScreen);
+ (*s->donePaintScreen) (s);
+ WRAP (ws, s, donePaintScreen, wobblyDonePaintScreen);
+}
+
+static void
+wobblyTransformWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib)
+{
+ WOBBLY_WINDOW (w);
+ WOBBLY_SCREEN (w->screen);
+
+ if (wobblyEnsureModel (w))
+ {
+ modelSetMiddleAnchor (ww->model,
+ w->attrib.x, w->attrib.y,
+ w->width, w->height);
+
+ if (ww->model->scale.x != attrib->xScale ||
+ ww->model->scale.y != attrib->yScale)
+ {
+ ww->model->scale.x = attrib->xScale;
+ ww->model->scale.y = attrib->yScale;
+
+ modelInitSprings (ww->model,
+ w->attrib.x, w->attrib.y,
+ w->width, w->height);
+
+ ww->wobbly = ws->wobblyWindows = TRUE;
+ }
+
+ if (ww->model->translate.x != attrib->xTranslate ||
+ ww->model->translate.y != attrib->yTranslate)
+ {
+ ww->model->anchorObject->position.x +=
+ attrib->xTranslate - ww->model->translate.x;
+ ww->model->anchorObject->position.y +=
+ attrib->yTranslate - ww->model->translate.y;
+
+ ww->model->translate.x = attrib->xTranslate;
+ ww->model->translate.y = attrib->yTranslate;
+
+ ww->wobbly = ws->wobblyWindows = TRUE;
+ }
+ }
+}
+
+static Bool
+wobblyPaintWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib,
+ Region region,
+ unsigned int mask)
+{
+ BoxPtr pClip;
+ int nClip, nVertices, nIndices;
+ GLushort *i, *indices;
+ GLfloat *v, *vertices;
+ int x1, y1, x2, y2;
+ float width, height;
+ float deformedX, deformedY;
+ int x, y, iw, ih;
+
+ WOBBLY_WINDOW (w);
+ WOBBLY_SCREEN (w->screen);
+
+ if (ww->model)
+ {
+ if (attrib->xTranslate != ww->model->translate.x ||
+ attrib->yTranslate != ww->model->translate.y ||
+ attrib->xScale != ww->model->scale.x ||
+ attrib->yScale != ww->model->scale.y)
+ wobblyTransformWindow (w, attrib);
+ }
+ else
+ {
+ if (attrib->xTranslate != 0.0f ||
+ attrib->yTranslate != 0.0f ||
+ attrib->xScale != 1.0f ||
+ attrib->yScale != 1.0f)
+ {
+ if (isWobblyWin (w))
+ wobblyTransformWindow (w, attrib);
+ }
+ }
+
+ if (ww->wobbly)
+ {
+ GLushort opacity;
+ int gridSize;
+
+ if (!region->numRects)
+ return TRUE;
+
+ if (w->destroyed || w->attrib.map_state != IsViewable)
+ return TRUE;
+
+ if (mask & PAINT_WINDOW_SOLID_MASK)
+ {
+ if (w->alpha)
+ return FALSE;
+
+ opacity = MULTIPLY_USHORT (w->opacity, attrib->opacity);
+ if (opacity != OPAQUE)
+ return FALSE;
+ }
+ else if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ {
+ opacity = MULTIPLY_USHORT (w->opacity, attrib->opacity);
+ if (!w->alpha && opacity == OPAQUE)
+ return FALSE;
+ }
+ else
+ {
+ opacity = MULTIPLY_USHORT (w->opacity, attrib->opacity);
+ if (w->alpha || opacity != OPAQUE)
+ mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+ else
+ mask |= PAINT_WINDOW_SOLID_MASK;
+ }
+
+ gridSize = ws->opt[WOBBLY_SCREEN_OPTION_GRID_SIZE].value.i;
+
+ if (!w->pixmap)
+ bindWindow (w);
+
+ width = w->width;
+ height = w->height;
+
+ nClip = w->region->numRects;
+ pClip = w->region->rects;
+
+ nVertices = 0;
+ nIndices = 0;
+
+ i = ww->indices;
+ v = ww->vertices;
+
+ while (nClip--)
+ {
+ x1 = pClip->x1 - w->attrib.x;
+ y1 = pClip->y1 - w->attrib.y;
+ x2 = pClip->x2 - w->attrib.x;
+ y2 = pClip->y2 - w->attrib.y;
+
+ iw = ((x2 - x1 - 1) / gridSize) + 1;
+ ih = ((y2 - y1 - 1) / gridSize) + 1;
+
+ if (nIndices + (iw * ih * 4) > ww->indexSize)
+ {
+ indices = realloc (ww->indices, sizeof (GLushort) *
+ (ww->indexSize + (iw * ih * 4)));
+ if (!indices)
+ return FALSE;
+
+ ww->indices = indices;
+ ww->indexSize += iw * ih * 4;
+ i = ww->indices + nIndices;
+ }
+
+ iw++;
+ ih++;
+
+ for (y = 0; y < ih - 1; y++)
+ {
+ for (x = 0; x < iw - 1; x++)
+ {
+ *i++ = nVertices + iw * (y + 1) + x;
+ *i++ = nVertices + iw * (y + 1) + x + 1;
+ *i++ = nVertices + iw * y + x + 1;
+ *i++ = nVertices + iw * y + x;
+
+ nIndices += 4;
+ }
+ }
+
+ if (((nVertices + iw * ih) * 4) > ww->vertexSize)
+ {
+ vertices = realloc (ww->vertices,
+ sizeof (GLfloat) *
+ (ww->vertexSize + (iw * ih * 4)));
+ if (!vertices)
+ return FALSE;
+
+ ww->vertices = vertices;
+ ww->vertexSize += iw * ih * 4;
+ v = ww->vertices + (nVertices * 4);
+ }
+
+ for (y = y1;; y += gridSize)
+ {
+ if (y > y2)
+ y = y2;
+
+ for (x = x1;; x += gridSize)
+ {
+ if (x > x2)
+ x = x2;
+
+ bezierPatchEvaluate (ww->model,
+ x / width, y / height,
+ &deformedX, &deformedY);
+
+ *v++ = X_WINDOW_TO_TEXTURE_SPACE (w, x);
+ *v++ = Y_WINDOW_TO_TEXTURE_SPACE (w, y);
+ *v++ = deformedX;
+ *v++ = deformedY;
+
+ nVertices++;
+
+ if (x == x2)
+ break;
+ }
+
+ if (y == y2)
+ break;
+ }
+
+ pClip++;
+ }
+
+ glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, ww->vertices);
+ glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, ww->vertices + 2);
+
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ {
+ glEnable (GL_BLEND);
+ if (opacity != OPAQUE)
+ {
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4us (opacity, opacity, opacity, opacity);
+ }
+ }
+
+ enableTexture (w->screen, &w->texture, COMP_TEXTURE_FILTER_GOOD);
+ glDrawElements (GL_QUADS, nIndices, GL_UNSIGNED_SHORT, ww->indices);
+ disableTexture (&w->texture);
+
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ {
+ if (opacity != OPAQUE)
+ {
+ glColor4usv (defaultColor);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ }
+ glDisable (GL_BLEND);
+ }
+ }
+ else
+ {
+ Bool status;
+
+ WOBBLY_SCREEN (w->screen);
+
+ UNWRAP (ws, w->screen, paintWindow);
+ status = (*w->screen->paintWindow) (w, attrib, region, mask);
+ WRAP (ws, w->screen, paintWindow, wobblyPaintWindow);
+
+ return status;
+ }
+
+ return TRUE;
+}
+
+static void
+wobblyHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ Window activeWindow = 0;
+ CompWindow *w;
+
+ WOBBLY_DISPLAY (d);
+
+ switch (event->type) {
+ case MapNotify:
+ w = findWindowAtDisplay (d, event->xmap.window);
+ if (w && isWobblyWin (w))
+ {
+ WOBBLY_WINDOW (w);
+ WOBBLY_SCREEN (w->screen);
+
+ if (ws->mapEffect && wobblyEnsureModel (w))
+ {
+ switch (ws->mapEffect) {
+ case WobblyEffectExplode:
+ modelAdjustObjectsForExplosion (ww->model,
+ w->attrib.x, w->attrib.y,
+ w->width, w->height);
+ break;
+ case WobblyEffectShiver:
+ modelAdjustObjectsForShiver (ww->model,
+ w->attrib.x, w->attrib.y,
+ w->width, w->height);
+ default:
+ break;
+ }
+
+ ww->wobbly = ws->wobblyWindows = TRUE;
+ damageScreen (w->screen);
+ }
+ }
+ break;
+ case ConfigureNotify:
+ w = findWindowAtDisplay (d, event->xmap.window);
+ if (w && isWobblyWin (w))
+ {
+ if (w->attrib.width != event->xconfigure.width ||
+ w->attrib.height != event->xconfigure.height ||
+ w->attrib.border_width != event->xconfigure.border_width)
+ {
+ int width, height;
+
+ WOBBLY_WINDOW (w);
+ WOBBLY_SCREEN (w->screen);
+
+ width = event->xconfigure.width;
+ width += event->xconfigure.border_width * 2;
+
+ height = event->xconfigure.height;
+ height += event->xconfigure.border_width * 2;
+
+ if (w->attrib.map_state == IsViewable && wobblyEnsureModel (w))
+ {
+ modelSetMiddleAnchor (ww->model,
+ w->attrib.x, w->attrib.y,
+ width, height);
+
+ modelInitSprings (ww->model,
+ w->attrib.x, w->attrib.y,
+ width, height);
+
+ ww->wobbly = ws->wobblyWindows = TRUE;
+ damageScreen (w->screen);
+ }
+ else if (ww->model)
+ {
+ modelInitObjects (ww->model,
+ w->attrib.x, w->attrib.y,
+ width, height);
+
+ modelInitSprings (ww->model,
+ w->attrib.x, w->attrib.y,
+ width, height);
+ }
+ }
+
+ if (w->attrib.x != event->xconfigure.x ||
+ w->attrib.y != event->xconfigure.y)
+ {
+ WOBBLY_WINDOW (w);
+
+ if (w->attrib.map_state == IsViewable && wobblyEnsureModel (w))
+ {
+ wobblyMoveWindow (w,
+ event->xconfigure.x - w->attrib.x,
+ event->xconfigure.y - w->attrib.y);
+ }
+ else if (ww->model)
+ {
+ modelMove (ww->model,
+ event->xconfigure.x - w->attrib.x,
+ event->xconfigure.y - w->attrib.y);
+ }
+ }
+ }
+ break;
+ case PropertyNotify:
+ if (event->xproperty.atom == d->winActiveAtom)
+ {
+ CompScreen *s;
+
+ s = findScreenAtDisplay (d, event->xproperty.window);
+ if (s)
+ activeWindow = s->activeWindow;
+ }
+ default:
+ break;
+ }
+
+ UNWRAP (wd, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (wd, d, handleEvent, wobblyHandleEvent);
+
+ switch (event->type) {
+ case PropertyNotify:
+ if (event->xproperty.atom == d->winActiveAtom)
+ {
+ CompScreen *s;
+
+ s = findScreenAtDisplay (d, event->xproperty.window);
+ if (s && s->activeWindow != activeWindow)
+ {
+ CompWindow *w;
+
+ w = findClientWindowAtScreen (s, s->activeWindow);
+ if (w && isWobblyWin (w))
+ {
+ WOBBLY_WINDOW (w);
+ WOBBLY_SCREEN (w->screen);
+
+ if (ws->focusEffect && wobblyEnsureModel (w))
+ {
+ switch (ws->focusEffect) {
+ case WobblyEffectExplode:
+ modelAdjustObjectsForExplosion (ww->model,
+ w->attrib.x,
+ w->attrib.y,
+ w->width,
+ w->height);
+ break;
+ case WobblyEffectShiver:
+ modelAdjustObjectsForShiver (ww->model,
+ w->attrib.x,
+ w->attrib.y,
+ w->width,
+ w->height);
+ default:
+ break;
+ }
+
+ ww->wobbly = ws->wobblyWindows = TRUE;
+ damageScreen (w->screen);
+ }
+ }
+ }
+ }
+ default:
+ break;
+ }
+}
+
+static Bool
+wobblyPaintScreen (CompScreen *s,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ Region region,
+ unsigned int mask)
+{
+ Bool status;
+
+ WOBBLY_SCREEN (s);
+
+ if (ws->wobblyWindows)
+ {
+ mask &= ~PAINT_SCREEN_REGION_MASK;
+ mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
+ }
+
+ UNWRAP (ws, s, paintScreen);
+ status = (*s->paintScreen) (s, sAttrib, wAttrib, region, mask);
+ WRAP (ws, s, paintScreen, wobblyPaintScreen);
+
+ return status;
+}
+
+static void
+wobblyInvisibleWindowMove (CompWindow *w,
+ int dx,
+ int dy)
+{
+ WOBBLY_SCREEN (w->screen);
+ WOBBLY_WINDOW (w);
+
+ if (ww->model)
+ modelMove (ww->model, dx, dy);
+
+ UNWRAP (ws, w->screen, invisibleWindowMove);
+ (*w->screen->invisibleWindowMove) (w, dx, dy);
+ WRAP (ws, w->screen, invisibleWindowMove, wobblyInvisibleWindowMove);
+}
+
+static Bool
+wobblyInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ WobblyDisplay *wd;
+
+ wd = malloc (sizeof (WobblyDisplay));
+ if (!wd)
+ return FALSE;
+
+ wd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (wd->screenPrivateIndex < 0)
+ {
+ free (wd);
+ return FALSE;
+ }
+
+ WRAP (wd, d, handleEvent, wobblyHandleEvent);
+
+ d->privates[displayPrivateIndex].ptr = wd;
+
+ return TRUE;
+}
+
+static void
+wobblyFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ WOBBLY_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, wd->screenPrivateIndex);
+
+ UNWRAP (wd, d, handleEvent);
+
+ free (wd);
+}
+
+static Bool
+wobblyInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ WobblyScreen *ws;
+
+ WOBBLY_DISPLAY (s->display);
+
+ ws = malloc (sizeof (WobblyScreen));
+ if (!ws)
+ return FALSE;
+
+ ws->windowPrivateIndex = allocateWindowPrivateIndex (s);
+ if (ws->windowPrivateIndex < 0)
+ {
+ free (ws);
+ return FALSE;
+ }
+
+ ws->wobblyWindows = FALSE;
+
+ ws->mapEffect = WobblyEffectShiver;
+ ws->focusEffect = WobblyEffectShiver;
+
+ wobblyScreenInitOptions (ws);
+
+ WRAP (ws, s, preparePaintScreen, wobblyPreparePaintScreen);
+ WRAP (ws, s, donePaintScreen, wobblyDonePaintScreen);
+ WRAP (ws, s, paintScreen, wobblyPaintScreen);
+ WRAP (ws, s, paintWindow, wobblyPaintWindow);
+ WRAP (ws, s, invisibleWindowMove, wobblyInvisibleWindowMove);
+
+ s->privates[wd->screenPrivateIndex].ptr = ws;
+
+ return TRUE;
+}
+
+static void
+wobblyFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ WOBBLY_SCREEN (s);
+
+ freeWindowPrivateIndex (s, ws->windowPrivateIndex);
+
+ free (ws->opt[WOBBLY_SCREEN_OPTION_MAP_EFFECT].value.s);
+ free (ws->opt[WOBBLY_SCREEN_OPTION_FOCUS_EFFECT].value.s);
+
+ UNWRAP (ws, s, preparePaintScreen);
+ UNWRAP (ws, s, donePaintScreen);
+ UNWRAP (ws, s, paintScreen);
+ UNWRAP (ws, s, paintWindow);
+ UNWRAP (ws, s, invisibleWindowMove);
+
+ free (ws);
+}
+
+static Bool
+wobblyInitWindow (CompPlugin *p,
+ CompWindow *w)
+{
+ WobblyWindow *ww;
+
+ WOBBLY_SCREEN (w->screen);
+
+ ww = malloc (sizeof (WobblyWindow));
+ if (!ww)
+ return FALSE;
+
+ ww->vertices = 0;
+ ww->vertexSize = 0;
+
+ ww->indices = 0;
+ ww->indexSize = 0;
+
+ ww->model = 0;
+ ww->wobbly = FALSE;
+
+ w->privates[ws->windowPrivateIndex].ptr = ww;
+
+ return TRUE;
+}
+
+static void
+wobblyFiniWindow (CompPlugin *p,
+ CompWindow *w)
+{
+ WOBBLY_WINDOW (w);
+
+ if (ww->vertices)
+ free (ww->vertices);
+
+ if (ww->indices)
+ free (ww->indices);
+
+ if (ww->model)
+ {
+ free (ww->model->objects);
+ free (ww->model);
+ }
+
+ free (ww);
+}
+
+static Bool
+wobblyInit (CompPlugin *p)
+{
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+wobblyFini (CompPlugin *p)
+{
+ if (displayPrivateIndex >= 0)
+ freeDisplayPrivateIndex (displayPrivateIndex);
+}
+
+CompPluginVTable wobblyVTable = {
+ "wobbly",
+ "Wobbly Windows",
+ "Use spring model for wobbly window effect",
+ wobblyInit,
+ wobblyFini,
+ wobblyInitDisplay,
+ wobblyFiniDisplay,
+ wobblyInitScreen,
+ wobblyFiniScreen,
+ wobblyInitWindow,
+ wobblyFiniWindow,
+ 0, /* GetDisplayOptions */
+ 0, /* SetDisplayOption */
+ wobblyGetScreenOptions,
+ wobblySetScreenOption
+};
+
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &wobblyVTable;
+}
diff --git a/plugins/zoom.c b/plugins/zoom.c
new file mode 100644
index 0000000..94bc4f7
--- /dev/null
+++ b/plugins/zoom.c
@@ -0,0 +1,690 @@
+/*
+ * 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 <math.h>
+#include <sys/time.h>
+
+#include <comp.h>
+
+#define ZOOM_POINTER_INVERT_Y_DEFAULT FALSE
+
+#define ZOOM_POINTER_SENSITIVITY_DEFAULT 1.0f
+#define ZOOM_POINTER_SENSITIVITY_MIN 0.01f
+#define ZOOM_POINTER_SENSITIVITY_MAX 100.0f
+#define ZOOM_POINTER_SENSITIVITY_PRECISION 0.01f
+
+#define ZOOM_POINTER_SENSITIVITY_FACTOR 0.0015f
+
+#define ZOOM_INITIATE_BUTTON_DEFAULT Button3
+#define ZOOM_INITIATE_MODIFIERS_DEFAULT (CompPressMask | CompSuperMask)
+
+#define ZOOM_TERMINATE_BUTTON_DEFAULT Button3
+#define ZOOM_TERMINATE_MODIFIERS_DEFAULT CompReleaseMask
+
+#define ZOOM_IN_BUTTON_DEFAULT Button4
+#define ZOOM_IN_MODIFIERS_DEFAULT (CompPressMask | CompSuperMask)
+
+#define ZOOM_OUT_BUTTON_DEFAULT Button5
+#define ZOOM_OUT_MODIFIERS_DEFAULT (CompPressMask | CompSuperMask)
+
+static int displayPrivateIndex;
+
+typedef struct _ZoomDisplay {
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+} ZoomDisplay;
+
+#define ZOOM_SCREEN_OPTION_POINTER_INVERT_Y 0
+#define ZOOM_SCREEN_OPTION_POINTER_SENSITIVITY 1
+#define ZOOM_SCREEN_OPTION_INITIATE 2
+#define ZOOM_SCREEN_OPTION_TERMINATE 3
+#define ZOOM_SCREEN_OPTION_IN 4
+#define ZOOM_SCREEN_OPTION_OUT 5
+#define ZOOM_SCREEN_OPTION_NUM 6
+
+typedef struct _ZoomScreen {
+ PreparePaintScreenProc preparePaintScreen;
+ DonePaintScreenProc donePaintScreen;
+ PaintScreenProc paintScreen;
+
+ CompOption opt[ZOOM_SCREEN_OPTION_NUM];
+
+ Bool pointerInvertY;
+ float pointerSensitivity;
+
+ int grabIndex;
+
+ GLfloat currentZoom;
+ GLfloat newZoom;
+
+ GLfloat xVelocity;
+ GLfloat yVelocity;
+ GLfloat zVelocity;
+
+ GLfloat xTranslate;
+ GLfloat yTranslate;
+
+ GLfloat xtrans;
+ GLfloat ytrans;
+ GLfloat ztrans;
+
+ int prevPointerX;
+ int prevPointerY;
+ XPoint savedPointer;
+ Bool grabbed;
+} ZoomScreen;
+
+#define GET_ZOOM_DISPLAY(d) \
+ ((ZoomDisplay *) (d)->privates[displayPrivateIndex].ptr)
+
+#define ZOOM_DISPLAY(d) \
+ ZoomDisplay *zd = GET_ZOOM_DISPLAY (d)
+
+#define GET_ZOOM_SCREEN(s, zd) \
+ ((ZoomScreen *) (s)->privates[(zd)->screenPrivateIndex].ptr)
+
+#define ZOOM_SCREEN(s) \
+ ZoomScreen *zs = GET_ZOOM_SCREEN (s, GET_ZOOM_DISPLAY (s->display))
+
+#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
+
+static CompOption *
+zoomGetScreenOptions (CompScreen *screen,
+ int *count)
+{
+ ZOOM_SCREEN (screen);
+
+ *count = NUM_OPTIONS (zs);
+ return zs->opt;
+}
+
+static Bool
+zoomSetScreenOption (CompScreen *screen,
+ char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ ZOOM_SCREEN (screen);
+
+ o = compFindOption (zs->opt, NUM_OPTIONS (zs), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index) {
+ case ZOOM_SCREEN_OPTION_POINTER_INVERT_Y:
+ if (compSetBoolOption (o, value))
+ {
+ zs->pointerInvertY = o->value.b;
+ return TRUE;
+ }
+ break;
+ case ZOOM_SCREEN_OPTION_POINTER_SENSITIVITY:
+ if (compSetFloatOption (o, value))
+ {
+ zs->pointerSensitivity = o->value.f *
+ ZOOM_POINTER_SENSITIVITY_FACTOR;
+ return TRUE;
+ }
+ break;
+ case ZOOM_SCREEN_OPTION_INITIATE:
+ case ZOOM_SCREEN_OPTION_IN:
+ if (addScreenBinding (screen, &value->bind))
+ {
+ removeScreenBinding (screen, &o->value.bind);
+
+ if (compSetBindingOption (o, value))
+ return TRUE;
+ }
+ break;
+ case ZOOM_SCREEN_OPTION_TERMINATE:
+ case ZOOM_SCREEN_OPTION_OUT:
+ if (compSetBindingOption (o, value))
+ return TRUE;
+ break;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static void
+zoomScreenInitOptions (ZoomScreen *zs,
+ Display *display)
+{
+ CompOption *o;
+
+ o = &zs->opt[ZOOM_SCREEN_OPTION_POINTER_INVERT_Y];
+ o->name = "invert_y";
+ o->shortDesc = "Pointer Invert Y";
+ o->longDesc = "Invert Y axis for pointer movement";
+ o->type = CompOptionTypeBool;
+ o->value.b = ZOOM_POINTER_INVERT_Y_DEFAULT;
+
+ o = &zs->opt[ZOOM_SCREEN_OPTION_POINTER_SENSITIVITY];
+ o->name = "sensitivity";
+ o->shortDesc = "Pointer Sensitivity";
+ o->longDesc = "Sensitivity of pointer movement";
+ o->type = CompOptionTypeFloat;
+ o->value.f = ZOOM_POINTER_SENSITIVITY_DEFAULT;
+ o->rest.f.min = ZOOM_POINTER_SENSITIVITY_MIN;
+ o->rest.f.max = ZOOM_POINTER_SENSITIVITY_MAX;
+ o->rest.f.precision = ZOOM_POINTER_SENSITIVITY_PRECISION;
+
+ o = &zs->opt[ZOOM_SCREEN_OPTION_INITIATE];
+ o->name = "initiate";
+ o->shortDesc = "Initiate";
+ o->longDesc = "Zoom In";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeButton;
+ o->value.bind.u.button.modifiers = ZOOM_INITIATE_MODIFIERS_DEFAULT;
+ o->value.bind.u.button.button = ZOOM_INITIATE_BUTTON_DEFAULT;
+
+ o = &zs->opt[ZOOM_SCREEN_OPTION_TERMINATE];
+ o->name = "terminate";
+ o->shortDesc = "Terminate";
+ o->longDesc = "Zoom to Normal View";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeButton;
+ o->value.bind.u.button.modifiers = ZOOM_TERMINATE_MODIFIERS_DEFAULT;
+ o->value.bind.u.button.button = ZOOM_TERMINATE_BUTTON_DEFAULT;
+
+ o = &zs->opt[ZOOM_SCREEN_OPTION_IN];
+ o->name = "zoom_in";
+ o->shortDesc = "Zoom In";
+ o->longDesc = "Zoom In";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeButton;
+ o->value.bind.u.button.modifiers = ZOOM_IN_MODIFIERS_DEFAULT;
+ o->value.bind.u.button.button = ZOOM_IN_BUTTON_DEFAULT;
+
+ o = &zs->opt[ZOOM_SCREEN_OPTION_OUT];
+ o->name = "zoom_out";
+ o->shortDesc = "Zoom Out";
+ o->longDesc = "Zoom Out";
+ o->type = CompOptionTypeBinding;
+ o->value.bind.type = CompBindingTypeButton;
+ o->value.bind.u.button.modifiers = ZOOM_OUT_MODIFIERS_DEFAULT;
+ o->value.bind.u.button.button = ZOOM_OUT_BUTTON_DEFAULT;
+}
+
+#define MIN_Z (0.6f)
+#define MAX_ZOOM (MIN_Z / BASE_Z_TRANSLATE)
+
+static int
+adjustZoomVelocity (ZoomScreen *zs)
+{
+ float d, adjust, amount;
+
+ d = (zs->newZoom - zs->currentZoom) * 200.0f;
+
+ adjust = d * 0.002f;
+ amount = fabs (d);
+ if (amount < 1.0f)
+ amount = 1.0f;
+ else if (amount > 10.0f)
+ amount = 10.0f;
+
+ zs->zVelocity = (amount * zs->zVelocity + adjust) / (amount + 1.0f);
+
+ return (fabs (d) < 0.1f && fabs (zs->zVelocity) < 0.005f);
+}
+
+static void
+zoomPreparePaintScreen (CompScreen *s,
+ int msSinceLastPaint)
+{
+ ZOOM_SCREEN (s);
+
+ if (zs->grabIndex)
+ {
+ zs->xVelocity /= 1.25f;
+ zs->yVelocity /= 1.25f;
+
+ if (fabs (zs->xVelocity) < 0.001f)
+ zs->xVelocity = 0.0f;
+ if (fabs (zs->yVelocity) < 0.001f)
+ zs->yVelocity = 0.0f;
+
+ zs->xTranslate += (zs->xVelocity * msSinceLastPaint) / s->redrawTime;
+ zs->yTranslate += (zs->yVelocity * msSinceLastPaint) / s->redrawTime;
+
+ if (adjustZoomVelocity (zs))
+ {
+ zs->currentZoom = zs->newZoom;
+ zs->zVelocity = 0.0f;
+ }
+ else
+ {
+ zs->currentZoom += (zs->zVelocity * msSinceLastPaint) /
+ s->redrawTime;
+ }
+
+ zs->ztrans = BASE_Z_TRANSLATE * zs->currentZoom;
+ if (zs->ztrans < MIN_Z)
+ {
+ zs->zVelocity = 0.0f;
+ zs->ztrans = MIN_Z;
+ }
+ zs->ztrans -= BASE_Z_TRANSLATE;
+
+ zs->xtrans = -zs->xTranslate * (1.0f - zs->currentZoom);
+ zs->ytrans = zs->yTranslate * (1.0f - zs->currentZoom);
+
+ if (!zs->grabbed)
+ {
+ if (zs->currentZoom == 1.0f && zs->zVelocity == 0.0f)
+ {
+ zs->xVelocity = zs->yVelocity = 0.0f;
+
+ removeScreenGrab (s, zs->grabIndex, &zs->savedPointer);
+ zs->grabIndex = FALSE;
+ }
+ }
+ }
+
+ UNWRAP (zs, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, msSinceLastPaint);
+ WRAP (zs, s, preparePaintScreen, zoomPreparePaintScreen);
+}
+
+static void
+zoomDonePaintScreen (CompScreen *s)
+{
+ ZOOM_SCREEN (s);
+
+ if (zs->grabIndex)
+ {
+ if (zs->currentZoom != zs->newZoom ||
+ zs->xVelocity || zs->yVelocity || zs->zVelocity)
+ damageScreen (s);
+ }
+
+ UNWRAP (zs, s, donePaintScreen);
+ (*s->donePaintScreen) (s);
+ WRAP (zs, s, donePaintScreen, zoomDonePaintScreen);
+}
+
+static Bool
+zoomPaintScreen (CompScreen *s,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ Region region,
+ unsigned int mask)
+{
+ Bool status;
+
+ ZOOM_SCREEN (s);
+
+ if (zs->grabIndex)
+ {
+ ScreenPaintAttrib sa = *sAttrib;
+
+ sa.xTranslate += zs->xtrans;
+ sa.yTranslate += zs->ytrans;
+ sa.zTranslate -= zs->ztrans;
+
+ /* hack to get sides rendered correctly */
+ if (zs->xtrans > 0.0f)
+ sa.xRotate += 0.000001f;
+ else
+ sa.xRotate -= 0.000001f;
+
+ mask &= ~PAINT_SCREEN_REGION_MASK;
+ mask |= PAINT_SCREEN_TRANSFORMED_MASK;
+
+ UNWRAP (zs, s, paintScreen);
+ status = (*s->paintScreen) (s, &sa, wAttrib, region, mask);
+ WRAP (zs, s, paintScreen, zoomPaintScreen);
+ }
+ else
+ {
+ UNWRAP (zs, s, paintScreen);
+ status = (*s->paintScreen) (s, sAttrib, wAttrib, region, mask);
+ WRAP (zs, s, paintScreen, zoomPaintScreen);
+ }
+
+ return status;
+}
+
+static void
+zoomIn (CompScreen *s,
+ int x,
+ int y)
+{
+ ZOOM_SCREEN (s);
+
+ zs->prevPointerX = x;
+ zs->prevPointerY = y;
+
+ if (!zs->grabIndex)
+ {
+ zs->grabIndex = pushScreenGrab (s, s->invisibleCursor);
+
+ zs->savedPointer.x = zs->prevPointerX;
+ zs->savedPointer.y = zs->prevPointerY;
+ }
+
+ if (zs->grabIndex)
+ {
+ zs->grabbed = TRUE;
+
+ if (zs->newZoom > MAX_ZOOM + 0.01f)
+ {
+ zs->newZoom = MAX_ZOOM + (zs->newZoom - MAX_ZOOM) / 2.0f;
+ damageScreen (s);
+ }
+
+ if (zs->currentZoom == 1.0f)
+ {
+ zs->xTranslate = (x - s->width / 2) / (float) s->width;
+ zs->yTranslate = (y - s->height / 2) / (float) s->height;
+
+ zs->xTranslate /= zs->newZoom;
+ zs->yTranslate /= zs->newZoom;
+ }
+
+ gettimeofday (&s->lastRedraw, 0);
+ }
+}
+
+static void
+zoomOut (CompScreen *s)
+{
+ ZOOM_SCREEN (s);
+
+ if (zs->grabIndex)
+ {
+ zs->newZoom = MAX_ZOOM + (zs->newZoom - MAX_ZOOM) * 2.0f;
+ if (zs->newZoom > 0.9f)
+ {
+ zs->grabbed = FALSE;
+ zs->newZoom = 1.0f;
+ }
+
+ damageScreen (s);
+ }
+}
+
+static void
+zoomTerminate (CompScreen *s)
+{
+ ZOOM_SCREEN (s);
+
+ if (zs->grabIndex)
+ {
+ zs->newZoom = 1.0f;
+ zs->grabbed = FALSE;
+ damageScreen (s);
+ }
+}
+
+static void
+zoomHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ CompScreen *s;
+
+ ZOOM_DISPLAY (d);
+
+ switch (event->type) {
+ case KeyPress:
+ case KeyRelease:
+ s = findScreenAtDisplay (d, event->xkey.root);
+ if (s)
+ {
+ ZOOM_SCREEN (s);
+
+ if (EV_KEY (&zs->opt[ZOOM_SCREEN_OPTION_INITIATE], event) ||
+ EV_KEY (&zs->opt[ZOOM_SCREEN_OPTION_IN], event))
+ zoomIn (s,
+ event->xkey.x_root,
+ event->xkey.y_root);
+
+ if (EV_KEY (&zs->opt[ZOOM_SCREEN_OPTION_OUT], event))
+ zoomOut (s);
+
+ if (EV_KEY (&zs->opt[ZOOM_SCREEN_OPTION_TERMINATE], event) ||
+ (event->type == KeyPress &&
+ event->xkey.keycode == s->escapeKeyCode))
+ zoomTerminate (s);
+ }
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ s = findScreenAtDisplay (d, event->xbutton.root);
+ if (s)
+ {
+ ZOOM_SCREEN (s);
+
+ if (EV_BUTTON (&zs->opt[ZOOM_SCREEN_OPTION_INITIATE], event) ||
+ EV_BUTTON (&zs->opt[ZOOM_SCREEN_OPTION_IN], event))
+ zoomIn (s,
+ event->xbutton.x_root,
+ event->xbutton.y_root);
+
+ if (EV_BUTTON (&zs->opt[ZOOM_SCREEN_OPTION_OUT], event))
+ zoomOut (s);
+
+ if (EV_BUTTON (&zs->opt[ZOOM_SCREEN_OPTION_TERMINATE], event))
+ zoomTerminate (s);
+ }
+ break;
+ case MotionNotify:
+ s = findScreenAtDisplay (d, event->xmotion.root);
+ if (s)
+ {
+ ZOOM_SCREEN (s);
+
+ if (zs->grabIndex && zs->grabbed)
+ {
+ GLfloat pointerDx;
+ GLfloat pointerDy;
+
+ pointerDx = event->xmotion.x_root - zs->prevPointerX;
+ pointerDy = event->xmotion.y_root - zs->prevPointerY;
+ zs->prevPointerX = event->xmotion.x_root;
+ zs->prevPointerY = event->xmotion.y_root;
+
+ if (event->xmotion.x_root < 50 ||
+ event->xmotion.y_root < 50 ||
+ event->xmotion.x_root > s->width - 50 ||
+ event->xmotion.y_root > s->height - 50)
+ {
+ zs->prevPointerX = s->width / 2;
+ zs->prevPointerY = s->height / 2;
+
+ XWarpPointer (d->display, None, s->root, 0, 0, 0, 0,
+ zs->prevPointerX, zs->prevPointerY);
+ }
+
+ if (zs->pointerInvertY)
+ pointerDy = -pointerDy;
+
+ zs->xVelocity += pointerDx * zs->pointerSensitivity;
+ zs->yVelocity += pointerDy * zs->pointerSensitivity;
+
+ damageScreen (s);
+ }
+ }
+ default:
+ break;
+ }
+
+ UNWRAP (zd, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (zd, d, handleEvent, zoomHandleEvent);
+}
+
+static Bool
+zoomInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ ZoomDisplay *zd;
+
+ zd = malloc (sizeof (ZoomDisplay));
+ if (!zd)
+ return FALSE;
+
+ zd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (zd->screenPrivateIndex < 0)
+ {
+ free (zd);
+ return FALSE;
+ }
+
+ WRAP (zd, d, handleEvent, zoomHandleEvent);
+
+ d->privates[displayPrivateIndex].ptr = zd;
+
+ return TRUE;
+}
+
+static void
+zoomFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ ZOOM_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, zd->screenPrivateIndex);
+
+ UNWRAP (zd, d, handleEvent);
+
+ free (zd);
+}
+
+static Bool
+zoomInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ ZoomScreen *zs;
+
+ ZOOM_DISPLAY (s->display);
+
+ zs = malloc (sizeof (ZoomScreen));
+ if (!zs)
+ return FALSE;
+
+ zs->grabIndex = 0;
+
+ zs->currentZoom = 1.0f;
+ zs->newZoom = 1.0f;
+
+ zs->xVelocity = 0.0f;
+ zs->yVelocity = 0.0f;
+ zs->zVelocity = 0.0f;
+
+ zs->xTranslate = 0.0f;
+ zs->yTranslate = 0.0f;
+
+ zs->savedPointer.x = 0;
+ zs->savedPointer.y = 0;
+ zs->prevPointerX = 0;
+ zs->prevPointerY = 0;
+
+ zs->grabbed = FALSE;
+
+ zs->pointerInvertY = ZOOM_POINTER_INVERT_Y_DEFAULT;
+ zs->pointerSensitivity = ZOOM_POINTER_SENSITIVITY_DEFAULT *
+ ZOOM_POINTER_SENSITIVITY_FACTOR;
+
+ zoomScreenInitOptions (zs, s->display->display);
+
+ addScreenBinding (s, &zs->opt[ZOOM_SCREEN_OPTION_INITIATE].value.bind);
+ addScreenBinding (s, &zs->opt[ZOOM_SCREEN_OPTION_IN].value.bind);
+
+ WRAP (zs, s, preparePaintScreen, zoomPreparePaintScreen);
+ WRAP (zs, s, donePaintScreen, zoomDonePaintScreen);
+ WRAP (zs, s, paintScreen, zoomPaintScreen);
+
+ s->privates[zd->screenPrivateIndex].ptr = zs;
+
+ return TRUE;
+}
+
+static void
+zoomFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ ZOOM_SCREEN (s);
+
+ UNWRAP (zs, s, preparePaintScreen);
+ UNWRAP (zs, s, donePaintScreen);
+ UNWRAP (zs, s, paintScreen);
+
+ free (zs);
+}
+
+static Bool
+zoomInit (CompPlugin *p)
+{
+ if (!findActivePlugin ("cube"))
+ {
+ fprintf (stderr, "%s: 'cube' required but not loaded\n", programName);
+ return FALSE;
+ }
+
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+zoomFini (CompPlugin *p)
+{
+ if (displayPrivateIndex >= 0)
+ freeDisplayPrivateIndex (displayPrivateIndex);
+}
+
+CompPluginVTable zoomVTable = {
+ "zoom",
+ "Zoom Desktop",
+ "Zoom and pan desktop cube",
+ zoomInit,
+ zoomFini,
+ zoomInitDisplay,
+ zoomFiniDisplay,
+ zoomInitScreen,
+ zoomFiniScreen,
+ 0, /* InitWindow */
+ 0, /* FiniWindow */
+ 0, /* GetDisplayOptions */
+ 0, /* SetDisplayOption */
+ zoomGetScreenOptions,
+ zoomSetScreenOption
+};
+
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &zoomVTable;
+}
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..2705fb3
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,22 @@
+INCLUDES = \
+ @GLXCOMP_CFLAGS@ \
+ -I$(top_srcdir)/include \
+ -DPLUGINDIR=\"$(plugindir)\" \
+ -DIMAGEDIR=\"$(imagedir)\"
+
+bin_PROGRAMS = glxcompmgr
+
+glxcompmgr_LDADD = @GLXCOMP_LIBS@ @GL_LIBS@ -lm
+glxcompmgr_LDFLAGS = -export-dynamic
+glxcompmgr_SOURCES = \
+ glxcompmgr.c \
+ privates.c \
+ texture.c \
+ display.c \
+ screen.c \
+ window.c \
+ event.c \
+ paint.c \
+ option.c \
+ plugin.c \
+ readpng.c
diff --git a/src/display.c b/src/display.c
new file mode 100644
index 0000000..69d01b0
--- /dev/null
+++ b/src/display.c
@@ -0,0 +1,1149 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/poll.h>
+#include <unistd.h>
+
+#define XK_MISCELLANY
+#include <X11/keysymdef.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/shape.h>
+
+#include <comp.h>
+
+static unsigned int virtualModMask[] = {
+ CompAltMask, CompMetaMask, CompSuperMask, CompHyperMask,
+ CompModeSwitchMask, CompNumLockMask, CompScrollLockMask
+};
+
+typedef struct _CompTimeout {
+ struct _CompTimeout *next;
+ int time;
+ int left;
+ CallBackProc callBack;
+ void *closure;
+ CompTimeoutHandle handle;
+} CompTimeout;
+
+static CompTimeout *timeouts = 0;
+static struct timeval lastTimeout;
+static CompTimeoutHandle lastTimeoutHandle = 1;
+
+#define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
+
+static char *textureFilter[] = { "Fast", "Good", "Best" };
+
+#define NUM_TEXTURE_FILTER (sizeof (textureFilter) / sizeof (textureFilter[0]))
+
+CompDisplay *compDisplays = 0;
+
+static CompDisplay compDisplay;
+
+static char *displayPrivateIndices = 0;
+static int displayPrivateLen = 0;
+
+static int
+reallocDisplayPrivate (int size,
+ void *closure)
+{
+ CompDisplay *d = compDisplays;
+ void *privates;
+
+ if (d)
+ {
+ privates = realloc (d->privates, size * sizeof (CompPrivate));
+ if (!privates)
+ return FALSE;
+
+ d->privates = (CompPrivate *) privates;
+ }
+
+ return TRUE;
+}
+
+int
+allocateDisplayPrivateIndex (void)
+{
+ return allocatePrivateIndex (&displayPrivateLen,
+ &displayPrivateIndices,
+ reallocDisplayPrivate,
+ 0);
+}
+
+void
+freeDisplayPrivateIndex (int index)
+{
+ freePrivateIndex (displayPrivateLen, displayPrivateIndices, index);
+}
+
+static void
+compDisplayInitOptions (CompDisplay *display,
+ char **plugin,
+ int nPlugin)
+{
+ CompOption *o;
+ int i;
+
+ o = &display->opt[COMP_DISPLAY_OPTION_ACTIVE_PLUGINS];
+ o->name = "active_plugins";
+ o->shortDesc = "Active Plugins";
+ o->longDesc = "List of currently active plugins";
+ o->type = CompOptionTypeList;
+ o->value.list.type = CompOptionTypeString;
+ o->value.list.nValue = nPlugin;
+ o->value.list.value = malloc (sizeof (CompOptionValue) * nPlugin);
+ for (i = 0; i < nPlugin; i++)
+ o->value.list.value[i].s = strdup (plugin[i]);
+ o->rest.s.string = 0;
+ o->rest.s.nString = 0;
+
+ display->dirtyPluginList = TRUE;
+
+ o = &display->opt[COMP_DISPLAY_OPTION_TEXTURE_FILTER];
+ o->name = "texture_filter";
+ o->shortDesc = "Texture Filter";
+ o->longDesc = "Texture filtering";
+ o->type = CompOptionTypeString;
+ o->value.s = strdup (defaultTextureFilter);
+ o->rest.s.string = textureFilter;
+ o->rest.s.nString = NUM_TEXTURE_FILTER;
+}
+
+CompOption *
+compGetDisplayOptions (CompDisplay *display,
+ int *count)
+{
+ *count = NUM_OPTIONS (display);
+ return display->opt;
+}
+
+static Bool
+setDisplayOption (CompDisplay *display,
+ char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ o = compFindOption (display->opt, NUM_OPTIONS (display), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index) {
+ case COMP_DISPLAY_OPTION_ACTIVE_PLUGINS:
+ if (compSetOptionList (o, value))
+ {
+ display->dirtyPluginList = TRUE;
+ return TRUE;
+ }
+ break;
+ case COMP_DISPLAY_OPTION_TEXTURE_FILTER:
+ if (compSetStringOption (o, value))
+ {
+ CompScreen *s;
+
+ for (s = display->screens; s; s = s->next)
+ damageScreen (s);
+
+ if (strcmp (o->value.s, "Fast") == 0)
+ display->textureFilter = GL_NEAREST;
+ else
+ display->textureFilter = GL_LINEAR;
+
+ return TRUE;
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static Bool
+setDisplayOptionForPlugin (CompDisplay *display,
+ char *plugin,
+ char *name,
+ CompOptionValue *value)
+{
+ CompPlugin *p;
+
+ p = findActivePlugin (plugin);
+ if (p && p->vTable->setDisplayOption)
+ return (*p->vTable->setDisplayOption) (display, name, value);
+
+ return FALSE;
+}
+
+static Bool
+initPluginForDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ return (*p->vTable->initDisplay) (p, d);
+}
+
+static void
+finiPluginForDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ (*p->vTable->finiDisplay) (p, d);
+}
+
+static void
+updatePlugins (CompDisplay *d)
+{
+ CompOption *o;
+ CompPlugin *p, **pop = 0;
+ int nPop, i, j;
+
+ d->dirtyPluginList = FALSE;
+
+ o = &d->opt[COMP_DISPLAY_OPTION_ACTIVE_PLUGINS];
+ for (i = 0; i < d->plugin.list.nValue && i < o->value.list.nValue; i++)
+ {
+ if (strcmp (d->plugin.list.value[i].s, o->value.list.value[i].s))
+ break;
+ }
+
+ nPop = d->plugin.list.nValue - i;
+
+ if (nPop)
+ {
+ pop = malloc (sizeof (CompPlugin *) * nPop);
+ if (!pop)
+ {
+ (*d->setDisplayOption) (d, o->name, &d->plugin);
+ return;
+ }
+ }
+
+ for (j = 0; j < nPop; j++)
+ {
+ pop[j] = popPlugin ();
+ d->plugin.list.nValue--;
+ free (d->plugin.list.value[d->plugin.list.nValue].s);
+ }
+
+ for (; i < o->value.list.nValue; i++)
+ {
+ p = 0;
+ for (j = 0; j < nPop; j++)
+ {
+ if (pop[j] && strcmp (pop[j]->vTable->name,
+ o->value.list.value[i].s) == 0)
+ {
+ if (pushPlugin (pop[j]))
+ {
+ p = pop[j];
+ pop[j] = 0;
+ break;
+ }
+ }
+ }
+
+ if (p == 0)
+ {
+ p = loadPlugin (o->value.list.value[i].s);
+ if (p)
+ {
+ if (!pushPlugin (p))
+ {
+ unloadPlugin (p);
+ p = 0;
+ }
+ }
+ }
+
+ if (p)
+ {
+ CompOptionValue *value;
+
+ value = realloc (d->plugin.list.value, sizeof (CompOption) *
+ (d->plugin.list.nValue + 1));
+ if (value)
+ {
+ value[d->plugin.list.nValue].s = strdup (p->vTable->name);
+
+ d->plugin.list.value = value;
+ d->plugin.list.nValue++;
+ }
+ else
+ {
+ p = popPlugin ();
+ unloadPlugin (p);
+ }
+ }
+ }
+
+ for (j = 0; j < nPop; j++)
+ {
+ if (pop[j])
+ unloadPlugin (pop[j]);
+ }
+
+ if (nPop)
+ free (pop);
+
+ (*d->setDisplayOption) (d, o->name, &d->plugin);
+}
+
+static void
+addTimeout (CompTimeout *timeout)
+{
+ CompTimeout *p = 0, *t;
+
+ for (t = timeouts; t; t = t->next)
+ {
+ if (timeout->time < t->left)
+ break;
+
+ p = t;
+ }
+
+ timeout->next = t;
+ timeout->left = timeout->time;
+
+ if (p)
+ p->next = timeout;
+ else
+ timeouts = timeout;
+}
+
+CompTimeoutHandle
+compAddTimeout (int time,
+ CallBackProc callBack,
+ void *closure)
+{
+ CompTimeout *timeout;
+
+ timeout = malloc (sizeof (CompTimeout));
+ if (!timeout)
+ return 0;
+
+ timeout->time = time;
+ timeout->callBack = callBack;
+ timeout->closure = closure;
+ timeout->handle = lastTimeoutHandle++;
+
+ if (lastTimeoutHandle == MAXSHORT)
+ lastTimeoutHandle = 1;
+
+ if (!timeouts)
+ gettimeofday (&lastTimeout, 0);
+
+ addTimeout (timeout);
+
+ return timeout->handle;
+}
+
+void
+compRemoveTimeout (CompTimeoutHandle handle)
+{
+ CompTimeout *p = 0, *t;
+
+ for (t = timeouts; t; t = t->next)
+ {
+ if (t->handle == handle)
+ break;
+
+ p = t;
+ }
+
+ if (t)
+ {
+ if (p)
+ p->next = t->next;
+ else
+ timeouts = t->next;
+
+ free (t);
+ }
+}
+
+#define TIMEVALDIFF(tv1, tv2) \
+ ((tv1)->tv_sec == (tv2)->tv_sec || (tv1)->tv_usec >= (tv2)->tv_usec) ? \
+ ((((tv1)->tv_sec - (tv2)->tv_sec) * 1000000) + \
+ ((tv1)->tv_usec - (tv2)->tv_usec)) / 1000 : \
+ ((((tv1)->tv_sec - 1 - (tv2)->tv_sec) * 1000000) + \
+ (1000000 + (tv1)->tv_usec - (tv2)->tv_usec)) / 1000
+
+static int
+getTimeToNextRedraw (CompScreen *s,
+ struct timeval *lastTv)
+{
+ struct timeval tv;
+ int diff;
+
+ gettimeofday (&tv, 0);
+
+ diff = TIMEVALDIFF (&tv, lastTv);
+
+ if (diff > s->redrawTime)
+ return 0;
+
+ return s->redrawTime - diff;
+}
+
+static CompWindow *
+findWindowAt (CompDisplay *d,
+ Window root,
+ int x,
+ int y)
+{
+ CompScreen *s;
+ CompWindow *w;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ if (s->root == root && s->maxGrab == 0)
+ {
+ for (w = s->reverseWindows; w; w = w->prev)
+ {
+ if (x >= w->attrib.x &&
+ y >= w->attrib.y &&
+ x < w->attrib.x + w->width &&
+ y < w->attrib.y + w->height)
+ return w;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static Window
+translateToRootWindow (CompDisplay *d,
+ Window child)
+{
+ CompScreen *s;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ if (s->root == child || s->grabWindow == child)
+ return s->root;
+ }
+
+ return child;
+}
+
+void
+updateModifierMappings (CompDisplay *d)
+{
+ XModifierKeymap *modmap;
+ unsigned int i, modMask[CompModNum];
+
+ for (i = 0; i < CompModNum; i++)
+ modMask[i] = 0;
+
+ modmap = XGetModifierMapping (d->display);
+ if (modmap && modmap->max_keypermod > 0)
+ {
+ static int maskTable[] = {
+ ShiftMask, LockMask, ControlMask, Mod1Mask,
+ Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
+ };
+ KeySym keysym;
+ int i, size, mask;
+
+ size = (sizeof (maskTable) / sizeof (int)) * modmap->max_keypermod;
+
+ for (i = 0; i < size; ++i)
+ {
+ if (!modmap->modifiermap[i])
+ continue;
+
+ keysym = XKeycodeToKeysym (d->display, modmap->modifiermap[i], 0);
+ if (keysym)
+ {
+ mask = maskTable[i / modmap->max_keypermod];
+
+ if (keysym == XK_Alt_L ||
+ keysym == XK_Alt_R)
+ {
+ modMask[CompModAlt] |= mask;
+ }
+ else if (keysym == XK_Meta_L ||
+ keysym == XK_Meta_R)
+ {
+ modMask[CompModMeta] |= mask;
+ }
+ else if (keysym == XK_Super_L ||
+ keysym == XK_Super_R)
+ {
+ modMask[CompModSuper] |= mask;
+ }
+ else if (keysym == XK_Hyper_L ||
+ keysym == XK_Hyper_R)
+ {
+ modMask[CompModHyper] |= mask;
+ }
+ else if (keysym == XK_Mode_switch)
+ {
+ modMask[CompModModeSwitch] |= mask;
+ }
+ else if (keysym == XK_Scroll_Lock)
+ {
+ modMask[CompModScrollLock] |= mask;
+ }
+ else if (keysym == XK_Num_Lock)
+ {
+ modMask[CompModNumLock] |= mask;
+ }
+ }
+ }
+
+ if (modmap)
+ XFreeModifiermap (modmap);
+
+ for (i = 0; i < CompModNum; i++)
+ {
+ if (!modMask[i])
+ modMask[i] = CompNoMask;
+ }
+
+ if (memcmp (modMask, d->modMask, sizeof (modMask)))
+ {
+ CompScreen *s;
+
+ memcpy (d->modMask, modMask, sizeof (modMask));
+
+ for (s = d->screens; s; s = s->next)
+ updatePassiveGrabs (s);
+ }
+ }
+}
+
+unsigned int
+virtualToRealModMask (CompDisplay *d,
+ unsigned int modMask)
+{
+ int i;
+
+ for (i = 0; i < CompModNum; i++)
+ {
+ if (modMask & virtualModMask[i])
+ {
+ modMask &= ~virtualModMask[i];
+ modMask |= d->modMask[i];
+ }
+ }
+
+ return (modMask & ~(CompPressMask | CompReleaseMask));
+}
+
+static unsigned int
+realToVirtualModMask (CompDisplay *d,
+ unsigned int modMask)
+{
+ int i;
+
+ for (i = 0; i < CompModNum; i++)
+ {
+ if (modMask & d->modMask[i])
+ modMask |= virtualModMask[i];
+ }
+
+ return modMask;
+}
+
+void
+eventLoop (void)
+{
+ XEvent event;
+ struct pollfd ufd;
+ int timeDiff;
+ struct timeval tv;
+ Region tmpRegion;
+ CompDisplay *display = compDisplays;
+ CompScreen *s = display->screens;
+ int timeToNextRedraw = 0;
+ CompWindow *move = 0;
+ int px = 0, py = 0;
+ CompTimeout *t;
+
+ tmpRegion = XCreateRegion ();
+ if (!tmpRegion)
+ {
+ fprintf (stderr, "%s: Couldn't create region\n", programName);
+ return;
+ }
+
+ ufd.fd = ConnectionNumber (display->display);
+ ufd.events = POLLIN;
+
+ for (;;)
+ {
+ if (display->dirtyPluginList)
+ updatePlugins (display);
+
+ if (restartSignal)
+ {
+ execvp (programName, programArgv);
+ exit (1);
+ }
+
+ while (XPending (display->display))
+ {
+ XNextEvent (display->display, &event);
+
+ /* translate root window */
+ if (testMode)
+ {
+ Window root, child;
+
+ switch (event.type) {
+ case ButtonPress:
+ if (!move)
+ {
+ px = event.xbutton.x;
+ py = event.xbutton.y;
+
+ move = findWindowAt (display, event.xbutton.window,
+ px, py);
+ if (move)
+ {
+ XRaiseWindow (display->display, move->id);
+ continue;
+ }
+ }
+ case ButtonRelease:
+ move = 0;
+
+ root = translateToRootWindow (display,
+ event.xbutton.window);
+ XTranslateCoordinates (display->display,
+ event.xbutton.root, root,
+ event.xbutton.x_root,
+ event.xbutton.y_root,
+ &event.xbutton.x_root,
+ &event.xbutton.y_root,
+ &child);
+ event.xbutton.root = root;
+ break;
+ case KeyPress:
+ case KeyRelease:
+ root = translateToRootWindow (display, event.xkey.window);
+ XTranslateCoordinates (display->display,
+ event.xkey.root, root,
+ event.xkey.x_root,
+ event.xkey.y_root,
+ &event.xkey.x_root,
+ &event.xkey.y_root,
+ &child);
+ event.xkey.root = root;
+ break;
+ case MotionNotify:
+ if (move)
+ {
+ XMoveWindow (display->display, move->id,
+ move->attrib.x + event.xbutton.x - px,
+ move->attrib.y + event.xbutton.y - py);
+
+ px = event.xbutton.x;
+ py = event.xbutton.y;
+ continue;
+ }
+
+ root = translateToRootWindow (display,
+ event.xmotion.window);
+ XTranslateCoordinates (display->display,
+ event.xmotion.root, root,
+ event.xmotion.x_root,
+ event.xmotion.y_root,
+ &event.xmotion.x_root,
+ &event.xmotion.y_root,
+ &child);
+ event.xmotion.root = root;
+ default:
+ break;
+ }
+ }
+
+ /* add virtual modifiers */
+ switch (event.type) {
+ case ButtonPress:
+ event.xbutton.state |= CompPressMask;
+ event.xbutton.state =
+ realToVirtualModMask (display, event.xbutton.state);
+ break;
+ case ButtonRelease:
+ event.xbutton.state |= CompReleaseMask;
+ event.xbutton.state =
+ realToVirtualModMask (display, event.xbutton.state);
+ break;
+ case KeyPress:
+ event.xkey.state |= CompPressMask;
+ event.xkey.state = realToVirtualModMask (display,
+ event.xkey.state);
+ break;
+ case KeyRelease:
+ event.xkey.state |= CompReleaseMask;
+ event.xkey.state = realToVirtualModMask (display,
+ event.xkey.state);
+ break;
+ case MotionNotify:
+ event.xmotion.state =
+ realToVirtualModMask (display, event.xmotion.state);
+ break;
+ default:
+ break;
+ }
+
+ (*display->handleEvent) (display, &event);
+ }
+
+ if (s->allDamaged || REGION_NOT_EMPTY (s->damage))
+ {
+ if (timeToNextRedraw == 0)
+ {
+ /* wait for X drawing requests to finish
+ glXWaitX (); */
+
+ gettimeofday (&tv, 0);
+
+ timeDiff = TIMEVALDIFF (&tv, &s->lastRedraw);
+
+ (*s->preparePaintScreen) (s, timeDiff);
+
+ if (s->allDamaged)
+ {
+ EMPTY_REGION (s->damage);
+ s->allDamaged = 0;
+
+ (*s->paintScreen) (s,
+ &defaultScreenPaintAttrib,
+ &defaultWindowPaintAttrib,
+ &s->region,
+ PAINT_SCREEN_REGION_MASK |
+ PAINT_SCREEN_FULL_MASK);
+
+ glXSwapBuffers (s->display->display, s->root);
+ }
+ else
+ {
+ XIntersectRegion (s->damage, &s->region, tmpRegion);
+
+ EMPTY_REGION (s->damage);
+
+ if ((*s->paintScreen) (s,
+ &defaultScreenPaintAttrib,
+ &defaultWindowPaintAttrib,
+ tmpRegion,
+ PAINT_SCREEN_REGION_MASK))
+ {
+ BoxPtr pBox;
+ int nBox, y;
+
+ glEnable (GL_SCISSOR_TEST);
+ glDrawBuffer (GL_FRONT);
+
+ pBox = tmpRegion->rects;
+ nBox = tmpRegion->numRects;
+ while (nBox--)
+ {
+ y = s->height - pBox->y2;
+
+ glBitmap (0, 0, 0, 0,
+ pBox->x1 - s->rasterX, y - s->rasterY,
+ NULL);
+
+ s->rasterX = pBox->x1;
+ s->rasterY = y;
+
+ glScissor (pBox->x1, y,
+ pBox->x2 - pBox->x1,
+ pBox->y2 - pBox->y1);
+
+ glCopyPixels (pBox->x1, y,
+ pBox->x2 - pBox->x1,
+ pBox->y2 - pBox->y1,
+ GL_COLOR);
+
+ pBox++;
+ }
+
+ glDrawBuffer (GL_BACK);
+ glDisable (GL_SCISSOR_TEST);
+ glFlush ();
+ }
+ else
+ {
+ (*s->paintScreen) (s,
+ &defaultScreenPaintAttrib,
+ &defaultWindowPaintAttrib,
+ &s->region,
+ PAINT_SCREEN_FULL_MASK);
+
+ glXSwapBuffers (s->display->display, s->root);
+ }
+ }
+
+ s->lastRedraw = tv;
+
+ (*s->donePaintScreen) (s);
+
+ /* remove destroyed windows */
+ while (s->pendingDestroys)
+ {
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (w->destroyed)
+ {
+ addWindowDamage (w);
+ removeWindow (w);
+ break;
+ }
+ }
+
+ s->pendingDestroys--;
+ }
+ }
+
+ timeToNextRedraw = getTimeToNextRedraw (s, &s->lastRedraw);
+ if (timeToNextRedraw)
+ timeToNextRedraw = poll (&ufd, 1, timeToNextRedraw);
+ }
+ else
+ {
+ if (timeouts)
+ {
+ if (timeouts->left > 0)
+ poll (&ufd, 1, timeouts->left);
+
+ gettimeofday (&tv, 0);
+
+ timeDiff = TIMEVALDIFF (&tv, &lastTimeout);
+
+ for (t = timeouts; t; t = t->next)
+ t->left -= timeDiff;
+
+ while (timeouts && timeouts->left <= 0)
+ {
+ t = timeouts;
+ if ((*t->callBack) (t->closure))
+ {
+ timeouts = t->next;
+ addTimeout (t);
+ }
+ else
+ {
+ timeouts = t->next;
+ free (t);
+ }
+ }
+
+ s->lastRedraw = lastTimeout = tv;
+ }
+ else
+ {
+ poll (&ufd, 1, 1000);
+ gettimeofday (&s->lastRedraw, 0);
+ }
+
+ /* just redraw immediately */
+ timeToNextRedraw = 0;
+ }
+ }
+}
+
+static int errors = 0;
+static int redirectFailed;
+
+static int
+errorHandler (Display *dpy,
+ XErrorEvent *e)
+{
+
+#ifdef DEBUG
+ char str[128];
+ char *name = 0;
+ int o;
+#endif
+
+ errors++;
+
+ if (e->request_code == compDisplays->compositeOpcode &&
+ e->minor_code == X_CompositeRedirectSubwindows)
+ {
+ redirectFailed = 1;
+ return 0;
+ }
+
+#ifdef DEBUG
+ XGetErrorDatabaseText (dpy, "XlibMessage", "XError", "", str, 128);
+ fprintf (stderr, "%s", str);
+
+ o = e->error_code - compDisplays->damageError;
+ switch (o) {
+ case BadDamage:
+ name = "BadDamage";
+ break;
+ default:
+ break;
+ }
+
+ if (name)
+ {
+ fprintf (stderr, ": %s\n ", name);
+ }
+ else
+ {
+ XGetErrorText (dpy, e->error_code, str, 128);
+ fprintf (stderr, ": %s\n ", str);
+ }
+
+ XGetErrorDatabaseText (dpy, "XlibMessage", "MajorCode", "%d", str, 128);
+ fprintf (stderr, str, e->request_code);
+
+ sprintf (str, "%d", e->request_code);
+ XGetErrorDatabaseText (dpy, "XRequest", str, "", str, 128);
+ if (strcmp (str, ""))
+ fprintf (stderr, " (%s)", str);
+ fprintf (stderr, "\n ");
+
+ XGetErrorDatabaseText (dpy, "XlibMessage", "MinorCode", "%d", str, 128);
+ fprintf (stderr, str, e->minor_code);
+ fprintf (stderr, "\n ");
+
+ XGetErrorDatabaseText (dpy, "XlibMessage", "ResourceID", "%d", str, 128);
+ fprintf (stderr, str, e->resourceid);
+ fprintf (stderr, "\n");
+
+ /* abort (); */
+#endif
+
+ return 0;
+}
+
+int
+compCheckForError (void)
+{
+ int e;
+
+ e = errors;
+ errors = 0;
+
+ return e;
+}
+
+Bool
+addDisplay (char *name,
+ char **plugin,
+ int nPlugin)
+{
+ CompDisplay *d;
+ Display *dpy;
+ int i;
+
+ d = &compDisplay;
+
+ if (displayPrivateLen)
+ {
+ d->privates = malloc (displayPrivateLen * sizeof (CompPrivate));
+ if (!d->privates)
+ return FALSE;
+ }
+ else
+ d->privates = 0;
+
+ d->screenPrivateIndices = 0;
+ d->screenPrivateLen = 0;
+
+ for (i = 0; i < CompModNum; i++)
+ d->modMask[i] = CompNoMask;
+
+ d->plugin.list.type = CompOptionTypeString;
+ d->plugin.list.nValue = 0;
+ d->plugin.list.value = 0;
+
+ compDisplayInitOptions (d, plugin, nPlugin);
+
+ d->textureFilter = GL_LINEAR;
+
+ d->display = dpy = XOpenDisplay (name);
+ if (!d->display)
+ {
+ fprintf (stderr, "%s: Couldn't open display %s\n",
+ programName, XDisplayName (name));
+ return FALSE;
+ }
+
+#ifdef DEBUG
+ XSynchronize (dpy, TRUE);
+#endif
+
+ XSetErrorHandler (errorHandler);
+
+ updateModifierMappings (d);
+
+ d->setDisplayOption = setDisplayOption;
+ d->setDisplayOptionForPlugin = setDisplayOptionForPlugin;
+
+ d->initPluginForDisplay = initPluginForDisplay;
+ d->finiPluginForDisplay = finiPluginForDisplay;
+
+ d->handleEvent = handleEvent;
+ d->handleDamageEvent = handleDamageEvent;
+
+ d->winTypeAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE", 0);
+ d->winDesktopAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", 0);
+ d->winDockAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DOCK", 0);
+ d->winToolbarAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", 0);
+ d->winMenuAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_MENU", 0);
+ d->winUtilAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_UTILITY", 0);
+ d->winSplashAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_SPLASH", 0);
+ d->winDialogAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_DIALOG", 0);
+ d->winNormalAtom = XInternAtom (dpy, "_NET_WM_WINDOW_TYPE_NORMAL", 0);
+ d->winOpacityAtom = XInternAtom (dpy, "_NET_WM_WINDOW_OPACITY", 0);
+ d->winActiveAtom = XInternAtom (dpy, "_NET_ACTIVE_WINDOW", 0);
+
+ d->wmStateAtom = XInternAtom (dpy, "WM_STATE", 0);
+ d->wmDeleteWindowAtom = XInternAtom (dpy, "WM_DELETE_WINDOW", 0);
+
+ d->xBackgroundAtom[0] = XInternAtom (dpy, "_XSETROOT_ID", 0);
+ d->xBackgroundAtom[1] = XInternAtom (dpy, "_XROOTPMAP_ID", 0);
+
+ if (testMode)
+ {
+ d->compositeOpcode = MAXSHORT;
+ d->compositeEvent = MAXSHORT;
+ d->compositeError = MAXSHORT;
+
+ d->damageEvent = MAXSHORT;
+ d->damageError = MAXSHORT;
+ }
+ else
+ {
+ int compositeMajor, compositeMinor;
+
+ if (!XQueryExtension (dpy,
+ COMPOSITE_NAME,
+ &d->compositeOpcode,
+ &d->compositeEvent,
+ &d->compositeError))
+ {
+ fprintf (stderr, "%s: No composite extension\n", programName);
+ return FALSE;
+ }
+
+ XCompositeQueryVersion (dpy, &compositeMajor, &compositeMinor);
+ if (compositeMajor == 0 && compositeMinor < 2)
+ {
+ fprintf (stderr, "%s: Old composite extension\n", programName);
+ return FALSE;
+ }
+
+ if (!XDamageQueryExtension (dpy, &d->damageEvent, &d->damageError))
+ {
+ fprintf (stderr, "%s: No damage extension\n", programName);
+ return FALSE;
+ }
+ }
+
+ d->shapeExtension = XShapeQueryExtension (dpy,
+ &d->shapeEvent,
+ &d->shapeError);
+
+ compDisplays = d;
+
+ if (testMode)
+ {
+ addScreen (d, 0);
+ }
+ else
+ {
+ XGrabServer (dpy);
+
+ for (i = 0; i < ScreenCount (dpy); i++)
+ {
+ redirectFailed = 0;
+ XCompositeRedirectSubwindows (dpy, XRootWindow (dpy, i),
+ CompositeRedirectManual);
+ XSync (dpy, FALSE);
+ if (redirectFailed)
+ {
+ fprintf (stderr, "%s: Another composite manager is already "
+ "running on screen: %d\n", programName, i);
+ }
+ else
+ {
+ if (!addScreen (d, i))
+ {
+ fprintf (stderr, "%s: Failed to manage screen: %d\n",
+ programName, i);
+ }
+ }
+ }
+
+ XUngrabServer (dpy);
+ }
+
+ if (!d->screens)
+ {
+ fprintf (stderr, "%s: No managable screens found on display %s\n",
+ programName, XDisplayName (name));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+CompScreen *
+findScreenAtDisplay (CompDisplay *d,
+ Window root)
+{
+ CompScreen *s;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ if (s->root == root)
+ return s;
+ }
+
+ return 0;
+}
+
+CompWindow *
+findWindowAtDisplay (CompDisplay *d,
+ Window id)
+{
+ CompScreen *s;
+ CompWindow *w;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ w = findWindowAtScreen (s, id);
+ if (w)
+ return w;
+ }
+
+ return 0;
+}
diff --git a/src/event.c b/src/event.c
new file mode 100644
index 0000000..ccabfca
--- /dev/null
+++ b/src/event.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/shape.h>
+
+#include <comp.h>
+
+void
+handleEvent (CompDisplay *display,
+ XEvent *event)
+{
+ CompScreen *s;
+ CompWindow *w;
+
+ switch (event->type) {
+ case Expose:
+ s = findScreenAtDisplay (display, event->xexpose.window);
+ if (s)
+ {
+ int more = event->xexpose.count + 1;
+
+ if (s->nExpose == s->sizeExpose)
+ {
+ if (s->exposeRects)
+ {
+ s->exposeRects = realloc (s->exposeRects,
+ (s->sizeExpose + more) *
+ sizeof (XRectangle));
+ s->sizeExpose += more;
+ }
+ else
+ {
+ s->exposeRects = malloc (more * sizeof (XRectangle));
+ s->sizeExpose = more;
+ }
+ }
+
+ s->exposeRects[s->nExpose].x = event->xexpose.x;
+ s->exposeRects[s->nExpose].y = event->xexpose.y;
+ s->exposeRects[s->nExpose].width = event->xexpose.width;
+ s->exposeRects[s->nExpose].height = event->xexpose.height;
+ s->nExpose++;
+
+ if (event->xexpose.count == 0)
+ {
+ REGION rect;
+
+ rect.rects = &rect.extents;
+ rect.numRects = rect.size = 1;
+
+ while (s->nExpose--)
+ {
+ rect.extents.x1 = s->exposeRects[s->nExpose].x;
+ rect.extents.y1 = s->exposeRects[s->nExpose].y;
+ rect.extents.x2 = rect.extents.x1 +
+ s->exposeRects[s->nExpose].width;
+ rect.extents.y2 = rect.extents.y1 +
+ s->exposeRects[s->nExpose].height;
+
+ damageScreenRegion (s, &rect);
+ }
+ s->nExpose = 0;
+ }
+ }
+ break;
+ case ConfigureNotify:
+ w = findWindowAtDisplay (display, event->xconfigure.window);
+ if (w)
+ {
+ configureWindow (w, &event->xconfigure);
+ }
+ else
+ {
+ s = findScreenAtDisplay (display, event->xconfigure.window);
+ if (s)
+ configureScreen (s, &event->xconfigure);
+ }
+ break;
+ case CreateNotify:
+ s = findScreenAtDisplay (display, event->xcreatewindow.parent);
+ if (s)
+ addWindow (s, event->xcreatewindow.window, 0);
+ break;
+ case DestroyNotify:
+ w = findWindowAtDisplay (display, event->xdestroywindow.window);
+ if (w)
+ {
+ addWindowDamage (w);
+ removeWindow (w);
+ }
+ break;
+ case MapNotify:
+ w = findWindowAtDisplay (display, event->xmap.window);
+ if (w)
+ mapWindow (w);
+ break;
+ case UnmapNotify:
+ w = findWindowAtDisplay (display, event->xunmap.window);
+ if (w)
+ unmapWindow (w);
+ break;
+ case ReparentNotify:
+ s = findScreenAtDisplay (display, event->xreparent.parent);
+ if (s)
+ {
+ addWindow (s, event->xreparent.window, 0);
+ }
+ else
+ {
+ w = findWindowAtDisplay (display, event->xreparent.window);
+ if (w)
+ {
+ addWindowDamage (w);
+ removeWindow (w);
+ }
+ }
+ break;
+ case CirculateNotify:
+ w = findWindowAtDisplay (display, event->xcirculate.window);
+ if (w)
+ circulateWindow (w, &event->xcirculate);
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ case KeyPress:
+ case KeyRelease:
+ break;
+ case PropertyNotify:
+ if (event->xproperty.atom == display->winActiveAtom)
+ {
+ s = findScreenAtDisplay (display, event->xproperty.window);
+ if (s)
+ s->activeWindow = getActiveWindow (display, s->root);
+ }
+ else if (event->xproperty.atom == display->winTypeAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ {
+ Atom type;
+
+ type = getWindowType (display, w->client);
+ if (type != w->type)
+ {
+
+ if (w->attrib.map_state == IsViewable)
+ {
+ if (w->type == display->winDesktopAtom)
+ w->screen->desktopWindowCount--;
+ else if (type == display->winDesktopAtom)
+ w->screen->desktopWindowCount++;
+
+ addWindowDamage (w);
+ }
+ w->type = type;
+ }
+ }
+ }
+ else if (event->xproperty.atom == display->winOpacityAtom)
+ {
+ w = findWindowAtDisplay (display, event->xproperty.window);
+ if (w)
+ {
+ GLuint opacity;
+
+ opacity = getWindowOpacity (display, w->id);
+ if (opacity != w->opacity)
+ {
+ w->opacity = opacity;
+ if (w->attrib.map_state == IsViewable)
+ addWindowDamage (w);
+ }
+ }
+ }
+ else if (event->xproperty.atom == display->xBackgroundAtom[0] ||
+ event->xproperty.atom == display->xBackgroundAtom[1])
+ {
+ s = findScreenAtDisplay (display, event->xproperty.window);
+ if (s)
+ {
+ finiTexture (s, &s->backgroundTexture);
+ initTexture (s, &s->backgroundTexture);
+
+ damageScreen (s);
+ }
+ }
+ break;
+ case MotionNotify:
+ break;
+ case ClientMessage:
+ if (event->xclient.format == 32 &&
+ event->xclient.data.l[0] == display->wmDeleteWindowAtom)
+ exit (0);
+ break;
+ case MappingNotify:
+ updateModifierMappings (display);
+ break;
+ default:
+ if (display->shapeExtension &&
+ event->type == display->shapeEvent + ShapeNotify)
+ {
+ w = findWindowAtDisplay (display, ((XShapeEvent *) event)->window);
+ if (w)
+ updateWindowRegion (w);
+ }
+ else if (event->type == display->damageEvent + XDamageNotify)
+ {
+ (*display->handleDamageEvent) (display,
+ (XDamageNotifyEvent *) event);
+ }
+ break;
+ }
+}
+
+void
+handleDamageEvent (CompDisplay *display,
+ XDamageNotifyEvent *event)
+{
+ CompScreen *screen;
+ REGION rect;
+
+ rect.rects = &rect.extents;
+ rect.numRects = rect.size = 1;
+
+ screen = display->screens;
+ if (screen->next)
+ {
+ CompWindow *w;
+
+ w = findWindowAtDisplay (display, event->drawable);
+ if (!w)
+ return;
+
+ screen = w->screen;
+ }
+
+ rect.extents.x1 = event->geometry.x + event->area.x;
+ rect.extents.y1 = event->geometry.y + event->area.y;
+ rect.extents.x2 = rect.extents.x1 + event->area.width;
+ rect.extents.y2 = rect.extents.y1 + event->area.height;
+
+ damageScreenRegion (screen, &rect);
+}
diff --git a/src/glxcompmgr.c b/src/glxcompmgr.c
new file mode 100644
index 0000000..21673f3
--- /dev/null
+++ b/src/glxcompmgr.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <comp.h>
+
+char *programName;
+char **programArgv;
+int programArgc;
+
+char *backgroundImage = "background.png";
+char *windowImage = "window.png";
+
+REGION emptyRegion;
+GLushort defaultColor[4] = { 0, 0, 0, 0 };
+Window currentRoot = 0;
+
+int defaultRefreshRate = 60;
+char *defaultTextureFilter = "Good";
+
+Bool testMode = FALSE;
+Bool restartSignal = FALSE;
+
+static void
+usage (void)
+{
+ printf ("Usage: %s "
+ "[--display DISPLAY] "
+ "[--bg-image PNG] "
+ "[--window-image PNG]\n "
+ "[--refresh-rate RATE] "
+ "[--fast-filter] "
+ "[--test-mode]\n "
+ "[--help] "
+ "[PLUGIN]...\n",
+ programName);
+}
+
+static void
+signalHandler (int sig)
+{
+ if (sig == SIGHUP)
+ restartSignal = TRUE;
+}
+
+int
+main (int argc, char **argv)
+{
+ char *displayName = 0;
+ char *plugin[256];
+ int i, nPlugin = 0;
+
+ programName = argv[0];
+ programArgc = argc;
+ programArgv = argv;
+
+ signal (SIGHUP, signalHandler);
+
+ emptyRegion.rects = &emptyRegion.extents;
+ emptyRegion.numRects = 0;
+ emptyRegion.extents.x1 = 0;
+ emptyRegion.extents.y1 = 0;
+ emptyRegion.extents.x2 = 0;
+ emptyRegion.extents.y2 = 0;
+ emptyRegion.size = 0;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp (argv[i], "--help"))
+ {
+ usage ();
+ return 0;
+ }
+ else if (!strcmp (argv[i], "--display"))
+ {
+ if (i + 1 < argc)
+ displayName = argv[++i];
+ }
+ else if (!strcmp (argv[i], "--refresh-rate"))
+ {
+ if (i + 1 < argc)
+ {
+ defaultRefreshRate = atoi (programArgv[++i]);
+ defaultRefreshRate = RESTRICT_VALUE (defaultRefreshRate,
+ 1, 1000);
+ }
+ }
+ else if (!strcmp (argv[i], "--fast-filter"))
+ {
+ defaultTextureFilter = "Fast";
+ }
+ else if (!strcmp (argv[i], "--test-mode"))
+ {
+ testMode = TRUE;
+ }
+ else if (!strcmp (argv[i], "--bg-image"))
+ {
+ if (i + 1 < argc)
+ backgroundImage = argv[++i];
+ }
+ else if (!strcmp (argv[i], "--window-image"))
+ {
+ if (i + 1 < argc)
+ windowImage = argv[++i];
+ }
+ else
+ {
+ if (nPlugin < 256)
+ plugin[nPlugin++] = argv[i];
+ }
+ }
+
+ if (!addDisplay (displayName, plugin, nPlugin))
+ return 1;
+
+ eventLoop ();
+
+ return 0;
+}
diff --git a/src/option.c b/src/option.c
new file mode 100644
index 0000000..7369b5e
--- /dev/null
+++ b/src/option.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <comp.h>
+
+CompOption *
+compFindOption (CompOption *option,
+ int nOption,
+ char *name,
+ int *index)
+{
+ int i;
+
+ for (i = 0; i < nOption; i++)
+ {
+ if (strcmp (option[i].name, name) == 0)
+ {
+ if (index)
+ *index = i;
+
+ return &option[i];
+ }
+ }
+
+ return 0;
+}
+
+Bool
+compSetBoolOption (CompOption *option,
+ CompOptionValue *value)
+{
+ option->value.i = (value->b) ? TRUE : FALSE;
+
+ return TRUE;
+}
+
+Bool
+compSetIntOption (CompOption *option,
+ CompOptionValue *value)
+{
+ if (value->i <= option->rest.i.min ||
+ value->i >= option->rest.i.max ||
+ value->i == option->value.i)
+ return FALSE;
+
+ option->value.i = value->i;
+
+ return TRUE;
+}
+
+Bool
+compSetFloatOption (CompOption *option,
+ CompOptionValue *value)
+{
+ float v, p;
+
+ p = 1.0f / option->rest.f.precision;
+ v = ((int) (value->f * p + 0.5f)) / p;
+
+ if (v <= option->rest.f.min ||
+ v >= option->rest.f.max ||
+ v == option->value.f)
+ return FALSE;
+
+ option->value.f = v;
+
+ return TRUE;
+}
+
+Bool
+compSetStringOption (CompOption *option,
+ CompOptionValue *value)
+{
+ if (option->rest.s.nString)
+ {
+ int i;
+
+ if (!value->s)
+ return FALSE;
+
+ for (i = 0; i < option->rest.s.nString; i++)
+ {
+ if (strcmp (option->rest.s.string[i], value->s) == 0)
+ break;
+ }
+
+ if (i == option->rest.s.nString)
+ return FALSE;
+ }
+
+ if (option->value.s == value->s)
+ return FALSE;
+
+ if (option->value.s && value->s)
+ {
+ if (strcmp (option->value.s, value->s) == 0)
+ return FALSE;
+ }
+
+ if (option->value.s)
+ free (option->value.s);
+
+ if (value->s)
+ option->value.s = strdup (value->s);
+ else
+ option->value.s = 0;
+
+ return TRUE;
+}
+
+Bool
+compSetColorOption (CompOption *option,
+ CompOptionValue *value)
+{
+ if (memcmp (value->c, option->value.c, sizeof (value->c)) == 0)
+ return FALSE;
+
+ memcpy (option->value.c, value->c, sizeof (value->c));
+
+ return TRUE;
+}
+
+Bool
+compSetBindingOption (CompOption *option,
+ CompOptionValue *value)
+{
+ CompBinding *binding;
+
+ binding = &option->value.bind;
+ if (value->bind.type == CompBindingTypeButton)
+ {
+ if (binding->type == CompBindingTypeButton &&
+ binding->u.button.button == value->bind.u.button.button &&
+ binding->u.button.modifiers == value->bind.u.button.modifiers)
+ return FALSE;
+ }
+ else
+ {
+ if (binding->type == CompBindingTypeKey &&
+ binding->u.key.keycode == value->bind.u.key.keycode &&
+ binding->u.key.modifiers == value->bind.u.key.modifiers)
+ return FALSE;
+ }
+
+ *binding = value->bind;
+
+ return TRUE;
+}
+
+Bool
+compSetOptionList (CompOption *option,
+ CompOptionValue *value)
+{
+ CompOption o;
+ Bool status = FALSE;
+ int i, min;
+
+ if (value->list.nValue != option->value.list.nValue)
+ {
+ CompOptionValue *v;
+
+ v = malloc (sizeof (CompOptionValue) * value->list.nValue);
+ if (!v)
+ return FALSE;
+
+ min = MIN (value->list.nValue, option->value.list.nValue);
+
+ if (min < option->value.list.nValue)
+ {
+ switch (option->value.list.type) {
+ case CompOptionTypeString:
+ for (i = min; i < option->value.list.nValue; i++)
+ {
+ if (option->value.list.value[i].s)
+ free (option->value.list.value[i].s);
+ }
+ default:
+ break;
+ }
+ }
+
+ memset (v, 0, sizeof (CompOptionValue) * value->list.nValue);
+
+ if (min)
+ memcpy (v, option->value.list.value,
+ sizeof (CompOptionValue) * min);
+
+ if (option->value.list.value)
+ free (option->value.list.value);
+
+ option->value.list.value = v;
+ option->value.list.nValue = value->list.nValue;
+
+ status = TRUE;
+ }
+
+ o = *option;
+ o.type = option->value.list.type;
+
+ for (i = 0; i < value->list.nValue; i++)
+ {
+ o.value = option->value.list.value[i];
+
+ switch (o.type) {
+ case CompOptionTypeBool:
+ status |= compSetBoolOption (&o, &value->list.value[i]);
+ break;
+ case CompOptionTypeInt:
+ status |= compSetIntOption (&o, &value->list.value[i]);
+ break;
+ case CompOptionTypeFloat:
+ status |= compSetFloatOption (&o, &value->list.value[i]);
+ break;
+ case CompOptionTypeString:
+ status |= compSetStringOption (&o, &value->list.value[i]);
+ break;
+ case CompOptionTypeColor:
+ status |= compSetColorOption (&o, &value->list.value[i]);
+ break;
+ case CompOptionTypeBinding:
+ status |= compSetBindingOption (&o, &value->list.value[i]);
+ default:
+ break;
+ }
+
+ option->value.list.value[i] = o.value;
+ }
+
+ return status;
+}
diff --git a/src/paint.c b/src/paint.c
new file mode 100644
index 0000000..5174e95
--- /dev/null
+++ b/src/paint.c
@@ -0,0 +1,555 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <comp.h>
+
+ScreenPaintAttrib defaultScreenPaintAttrib = {
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f
+};
+
+WindowPaintAttrib defaultWindowPaintAttrib = {
+ OPAQUE, 0.0f, 0.0f, 1.0f, 1.0f
+};
+
+void
+preparePaintScreen (CompScreen *screen,
+ int msSinceLastPaint) {}
+
+void
+donePaintScreen (CompScreen *screen) {}
+
+void
+paintTransformedScreen (CompScreen *screen,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ unsigned int mask)
+{
+ CompWindow *w;
+ int windowMask;
+ int backgroundMask;
+
+ glPushMatrix ();
+
+ glTranslatef (sAttrib->xTranslate,
+ sAttrib->yTranslate,
+ sAttrib->zTranslate - BASE_Z_TRANSLATE);
+
+ glRotatef (sAttrib->xRotate, 0.0f, 1.0f, 0.0f);
+ glRotatef (sAttrib->vRotate,
+ 1.0f - sAttrib->xRotate / 90.0f,
+ 0.0f,
+ sAttrib->xRotate / 90.0f);
+ glRotatef (sAttrib->yRotate, 0.0f, 1.0f, 0.0f);
+
+ glTranslatef (-0.5f, -0.5f, 0.5f);
+ glScalef (1.0f / screen->width, -1.0f / screen->height, 1.0f);
+ glTranslatef (0.0f, -screen->height, 0.0f);
+
+ if (mask & PAINT_SCREEN_TRANSFORMED_MASK)
+ {
+ windowMask = PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
+ backgroundMask = PAINT_BACKGROUND_ON_TRANSFORMED_SCREEN_MASK;
+
+ if (mask & PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK)
+ {
+ backgroundMask |= PAINT_BACKGROUND_WITH_STENCIL_MASK;
+
+ (*screen->paintBackground) (screen, &screen->region,
+ backgroundMask);
+
+ glEnable (GL_STENCIL_TEST);
+
+ for (w = screen->windows; w; w = w->next)
+ (*screen->paintWindow) (w, wAttrib, &screen->region,
+ windowMask);
+
+ glDisable (GL_STENCIL_TEST);
+
+ glPopMatrix ();
+
+ return;
+ }
+ }
+ else
+ windowMask = backgroundMask = 0;
+
+ (*screen->paintBackground) (screen, &screen->region, backgroundMask);
+
+ for (w = screen->windows; w; w = w->next)
+ (*screen->paintWindow) (w, wAttrib, &screen->region, windowMask);
+
+ glPopMatrix ();
+}
+
+Bool
+paintScreen (CompScreen *screen,
+ const ScreenPaintAttrib *sAttrib,
+ const WindowPaintAttrib *wAttrib,
+ Region region,
+ unsigned int mask)
+{
+ static Region tmpRegion = NULL;
+ CompWindow *w;
+
+ if (mask & PAINT_SCREEN_REGION_MASK)
+ {
+ if ((mask & PAINT_SCREEN_TRANSFORMED_MASK) ||
+ (mask & PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK))
+ {
+ if (mask & PAINT_SCREEN_FULL_MASK)
+ {
+ (*screen->paintTransformedScreen) (screen, sAttrib, wAttrib,
+ mask);
+
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ /* fall through and redraw region */
+ }
+ else if (mask & PAINT_SCREEN_FULL_MASK)
+ {
+ (*screen->paintTransformedScreen) (screen, sAttrib, wAttrib, mask);
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+
+ if (!tmpRegion)
+ {
+ tmpRegion = XCreateRegion ();
+ if (!tmpRegion)
+ return FALSE;
+ }
+
+ XSubtractRegion (region, &emptyRegion, tmpRegion);
+
+ glPushMatrix ();
+
+ glTranslatef (0.0f, 0.0f, -BASE_Z_TRANSLATE);
+
+ glTranslatef (-0.5f, -0.5f, 0.5f);
+ glScalef (1.0f / screen->width, -1.0f / screen->height, 1.0f);
+ glTranslatef (0.0f, -screen->height, 0.0f);
+
+ /* paint solid windows */
+ for (w = screen->reverseWindows; w; w = w->prev)
+ {
+ if (w->invisible)
+ continue;
+
+ if ((*screen->paintWindow) (w, wAttrib, tmpRegion,
+ PAINT_WINDOW_SOLID_MASK))
+ XSubtractRegion (tmpRegion, w->region, tmpRegion);
+
+ /* copy region */
+ XSubtractRegion (tmpRegion, &emptyRegion, w->clip);
+ }
+
+ (*screen->paintBackground) (screen, tmpRegion, 0);
+
+ /* paint translucent windows */
+ for (w = screen->windows; w; w = w->next)
+ {
+ if (w->invisible)
+ continue;
+
+ (*screen->paintWindow) (w, wAttrib, w->clip,
+ PAINT_WINDOW_TRANSLUCENT_MASK);
+ }
+
+ glPopMatrix ();
+
+ return TRUE;
+}
+
+#define ADD_QUAD(data, w, x1, y1, x2, y2) \
+ if (!(w)->pixmap) \
+ bindWindow (w); \
+ *(data)++ = X_WINDOW_TO_TEXTURE_SPACE (w, x1); \
+ *(data)++ = Y_WINDOW_TO_TEXTURE_SPACE (w, y2); \
+ *(data)++ = (x1); \
+ *(data)++ = (y2); \
+ *(data)++ = X_WINDOW_TO_TEXTURE_SPACE (w, x2); \
+ *(data)++ = Y_WINDOW_TO_TEXTURE_SPACE (w, y2); \
+ *(data)++ = (x2); \
+ *(data)++ = (y2); \
+ *(data)++ = X_WINDOW_TO_TEXTURE_SPACE (w, x2); \
+ *(data)++ = Y_WINDOW_TO_TEXTURE_SPACE (w, y1); \
+ *(data)++ = (x2); \
+ *(data)++ = (y1); \
+ *(data)++ = X_WINDOW_TO_TEXTURE_SPACE (w, x1); \
+ *(data)++ = Y_WINDOW_TO_TEXTURE_SPACE (w, y1); \
+ *(data)++ = (x1); \
+ *(data)++ = (y1)
+
+#define ADD_BOX(data, w, box) \
+ ADD_QUAD (data, w, (box)->x1, (box)->y1, (box)->x2, (box)->y2)
+
+Bool
+paintWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib,
+ Region region,
+ unsigned int mask)
+{
+ BoxPtr pClip;
+ int nClip, n;
+ GLfloat *data, *d;
+ GLushort opacity;
+ int x1, y1, x2, y2;
+
+ if (!region->numRects)
+ return TRUE;
+
+ if (w->destroyed || w->attrib.map_state != IsViewable)
+ return TRUE;
+
+ if (mask & PAINT_WINDOW_SOLID_MASK)
+ {
+ if (w->alpha)
+ return FALSE;
+
+ opacity = MULTIPLY_USHORT (w->opacity, attrib->opacity);
+ if (opacity != OPAQUE)
+ return FALSE;
+ }
+ else if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ {
+ opacity = MULTIPLY_USHORT (w->opacity, attrib->opacity);
+ if (!w->alpha && opacity == OPAQUE)
+ return FALSE;
+ }
+ else
+ {
+ opacity = MULTIPLY_USHORT (w->opacity, attrib->opacity);
+ if (w->alpha || opacity != OPAQUE)
+ mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+ else
+ mask |= PAINT_WINDOW_SOLID_MASK;
+ }
+
+ if (attrib->xTranslate != 0.0f ||
+ attrib->yTranslate != 0.0f ||
+ attrib->xScale != 1.0f ||
+ attrib->yScale != 1.0f)
+ {
+ nClip = w->region->numRects;
+ pClip = w->region->rects;
+
+ mask |= PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
+
+ data = malloc (sizeof (GLfloat) * nClip * 16);
+ if (!data)
+ return FALSE;
+
+ d = data;
+
+ n = nClip;
+ while (nClip--)
+ {
+ x1 = pClip->x1 - w->attrib.x;
+ y1 = pClip->y1 - w->attrib.y;
+ x2 = pClip->x2 - w->attrib.x;
+ y2 = pClip->y2 - w->attrib.y;
+
+ ADD_QUAD (d, w, x1, y1, x2, y2);
+
+ pClip++;
+ }
+ }
+ else
+ {
+ BoxRec clip, full;
+ BoxPtr pExtent = &region->extents;
+ BoxPtr pBox = region->rects;
+ int nBox = region->numRects;
+ int dataSize;
+
+ full.x1 = 0;
+ full.y1 = 0;
+ full.x2 = w->width;
+ full.y2 = w->height;
+
+ x1 = pExtent->x1 - w->attrib.x;
+ y1 = pExtent->y1 - w->attrib.y;
+ x2 = pExtent->x2 - w->attrib.x;
+ y2 = pExtent->y2 - w->attrib.y;
+
+ if (x1 > 0)
+ full.x1 = x1;
+ if (y1 > 0)
+ full.y1 = y1;
+ if (x2 < w->width)
+ full.x2 = x2;
+ if (y2 < w->height)
+ full.y2 = y2;
+
+ if (full.x1 >= full.x2 || full.y1 >= full.y2)
+ return TRUE;
+
+ dataSize = nBox * 16;
+ data = malloc (sizeof (GLfloat) * dataSize);
+ if (!data)
+ return FALSE;
+
+ d = data;
+ n = 0;
+
+ pBox = region->rects;
+ nBox = region->numRects;
+ while (nBox--)
+ {
+ x1 = pBox->x1 - w->attrib.x;
+ y1 = pBox->y1 - w->attrib.y;
+ x2 = pBox->x2 - w->attrib.x;
+ y2 = pBox->y2 - w->attrib.y;
+
+ pBox++;
+
+ if (x1 < full.x1)
+ x1 = full.x1;
+ if (y1 < full.y1)
+ y1 = full.y1;
+ if (x2 > full.x2)
+ x2 = full.x2;
+ if (y2 > full.y2)
+ y2 = full.y2;
+
+ if (x1 < x2 && y1 < y2)
+ {
+ nClip = w->region->numRects;
+
+ if (nClip == 1)
+ {
+ ADD_QUAD (d, w, x1, y1, x2, y2);
+
+ n++;
+ }
+ else
+ {
+ pClip = w->region->rects;
+
+ while (nClip--)
+ {
+ clip.x1 = pClip->x1 - w->attrib.x;
+ clip.y1 = pClip->y1 - w->attrib.y;
+ clip.x2 = pClip->x2 - w->attrib.x;
+ clip.y2 = pClip->y2 - w->attrib.y;
+
+ pClip++;
+
+ if (clip.x1 < x1)
+ clip.x1 = x1;
+ if (clip.y1 < y1)
+ clip.y1 = y1;
+ if (clip.x2 > x2)
+ clip.x2 = x2;
+ if (clip.y2 > y2)
+ clip.y2 = y2;
+
+ if (clip.x1 < clip.x2 && clip.y1 < clip.y2)
+ {
+ if ((n << 4) == dataSize)
+ {
+ dataSize <<= 2;
+ data = realloc (data,
+ sizeof (GLfloat) * dataSize);
+ if (!data)
+ return FALSE;
+
+ d = data + (n * 16);
+ }
+
+ ADD_BOX (d, w, &clip);
+
+ n++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (n)
+ {
+ glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, data);
+ glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, data + 2);
+
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ {
+ glEnable (GL_BLEND);
+ if (opacity != OPAQUE)
+ {
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4us (opacity, opacity, opacity, opacity);
+ }
+ }
+
+ glPushMatrix ();
+
+ if (mask & PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK)
+ {
+ glTranslatef (w->attrib.x + attrib->xTranslate,
+ w->attrib.y + attrib->yTranslate, 0.0f);
+ glScalef (attrib->xScale, attrib->yScale, 0.0f);
+
+ enableTexture (w->screen, &w->texture, COMP_TEXTURE_FILTER_GOOD);
+ }
+ else
+ {
+ glTranslatef (w->attrib.x, w->attrib.y, 0.0f);
+
+ enableTexture (w->screen, &w->texture, COMP_TEXTURE_FILTER_FAST);
+ }
+
+ glDrawArrays (GL_QUADS, 0, n * 4);
+
+ disableTexture (&w->texture);
+
+ glPopMatrix ();
+
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ {
+ if (opacity != OPAQUE)
+ {
+ glColor4usv (defaultColor);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ }
+ glDisable (GL_BLEND);
+ }
+ }
+
+ free (data);
+
+ return TRUE;
+}
+
+void
+paintBackground (CompScreen *s,
+ Region region,
+ unsigned int mask)
+{
+ CompTexture *bg = &s->backgroundTexture;
+ BoxPtr pBox = region->rects;
+ int n, nBox = region->numRects;
+ GLfloat *d, *data;
+
+ if (!nBox)
+ return;
+
+ if (s->desktopWindowCount)
+ {
+ if (bg->name)
+ {
+ finiTexture (s, bg);
+ initTexture (s, bg);
+ }
+
+ if (!(mask & PAINT_BACKGROUND_WITH_STENCIL_MASK))
+ return;
+ }
+ else
+ {
+ if (!bg->name)
+ updateScreenBackground (s, bg);
+ }
+
+ data = malloc (sizeof (GLfloat) * nBox * 16);
+ if (!data)
+ return;
+
+ d = data;
+ n = nBox;
+ while (n--)
+ {
+ *d++ = bg->dx * pBox->x1;
+ *d++ = bg->dy * (s->backgroundHeight - pBox->y2);
+
+ *d++ = pBox->x1;
+ *d++ = pBox->y2;
+
+ *d++ = bg->dx * pBox->x2;
+ *d++ = bg->dy * (s->backgroundHeight - pBox->y2);
+
+ *d++ = pBox->x2;
+ *d++ = pBox->y2;
+
+ *d++ = bg->dx * pBox->x2;
+ *d++ = bg->dy * (s->backgroundHeight - pBox->y1);
+
+ *d++ = pBox->x2;
+ *d++ = pBox->y1;
+
+ *d++ = bg->dx * pBox->x1;
+ *d++ = bg->dy * (s->backgroundHeight - pBox->y1);
+
+ *d++ = pBox->x1;
+ *d++ = pBox->y1;
+
+ pBox++;
+ }
+
+ if (mask & PAINT_BACKGROUND_WITH_STENCIL_MASK)
+ {
+ glEnable (GL_STENCIL_TEST);
+ glStencilFunc (GL_ALWAYS, s->stencilRef, ~0);
+ glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
+ }
+
+ glTexCoordPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, data);
+ glVertexPointer (2, GL_FLOAT, sizeof (GLfloat) * 4, data + 2);
+
+ if (s->desktopWindowCount)
+ {
+ glDrawArrays (GL_QUADS, 0, nBox * 4);
+ }
+ else
+ {
+ if (mask & PAINT_BACKGROUND_ON_TRANSFORMED_SCREEN_MASK)
+ enableTexture (s, bg, COMP_TEXTURE_FILTER_GOOD);
+ else
+ enableTexture (s, bg, COMP_TEXTURE_FILTER_FAST);
+
+ glDrawArrays (GL_QUADS, 0, nBox * 4);
+
+ disableTexture (bg);
+ }
+
+ if (mask & PAINT_BACKGROUND_WITH_STENCIL_MASK)
+ {
+ glStencilFunc (GL_EQUAL, s->stencilRef, ~0);
+ glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
+ glDisable (GL_STENCIL_TEST);
+ }
+
+ free (data);
+}
diff --git a/src/plugin.c b/src/plugin.c
new file mode 100644
index 0000000..b679070
--- /dev/null
+++ b/src/plugin.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+
+#include <comp.h>
+
+#define HOME_PLUGINDIR ".glxcomp/plugins"
+
+CompPlugin *plugins = 0;
+
+static Bool
+initPlugin (CompPlugin *p)
+{
+ CompDisplay *d = compDisplays;
+ int failed = 0;
+
+ if (!(*p->vTable->init) (p))
+ {
+ fprintf (stderr, "%s: InitPlugin '%s' failed\n", programName,
+ p->vTable->name);
+ return FALSE;
+ }
+
+ if (d)
+ {
+ if ((*d->initPluginForDisplay) (p, d))
+ {
+ CompScreen *s, *failedScreen = d->screens;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ if (!p->vTable->initScreen || (*s->initPluginForScreen) (p, s))
+ {
+ CompWindow *w, *failedWindow = s->windows;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ if (p->vTable->initWindow &&
+ !(*p->vTable->initWindow) (p, w))
+ {
+ fprintf (stderr, "%s: Plugin '%s':initWindow "
+ "failed\n", programName, p->vTable->name);
+ failedWindow = w;
+ failed = 1;
+ break;
+ }
+ }
+
+ for (w = s->windows; w != failedWindow; w = w->next)
+ {
+ if (p->vTable->finiWindow)
+ (*p->vTable->finiWindow) (p, w);
+ }
+ }
+ else
+ {
+ fprintf (stderr, "%s: Plugin '%s':initScreen failed\n",
+ programName, p->vTable->name);
+ failedScreen = s;
+ failed = 1;
+ break;
+ }
+ }
+
+ for (s = d->screens; s != failedScreen; s = s->next)
+ (*s->finiPluginForScreen) (p, s);
+ }
+ else
+ {
+ fprintf (stderr, "%s: Plugin '%s':initDisplay failed\n",
+ programName, p->vTable->name);
+
+ failed = 1;
+ (*d->finiPluginForDisplay) (p, d);
+ }
+ }
+
+ if (failed)
+ {
+ (*p->vTable->fini) (p);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+finiPlugin (CompPlugin *p)
+{
+ CompDisplay *d = compDisplays;
+ CompScreen *s;
+
+ if (d)
+ {
+ for (s = d->screens; s; s = s->next)
+ {
+ CompWindow *w = s->windows;
+
+ if (p->vTable->finiWindow)
+ {
+ for (w = s->windows; w; w = w->next)
+ (*p->vTable->finiWindow) (p, w);
+ }
+
+ (*s->finiPluginForScreen) (p, s);
+ }
+
+ (*d->finiPluginForDisplay) (p, d);
+ }
+
+ (*p->vTable->fini) (p);
+}
+
+void
+screenInitPlugins (CompScreen *s)
+{
+ CompPlugin *p;
+ int i, j = 0;
+
+ for (p = plugins; p; p = p->next)
+ j++;
+
+ while (j--)
+ {
+ i = 0;
+ for (p = plugins; i < j; p = p->next)
+ i++;
+
+ if (p->vTable->initScreen)
+ (*s->initPluginForScreen) (p, s);
+ }
+}
+
+void
+screenFiniPlugins (CompScreen *s)
+{
+ CompPlugin *p;
+
+ for (p = plugins; p; p = p->next)
+ {
+ if (p->vTable->finiScreen)
+ (*s->initPluginForScreen) (p, s);
+ }
+}
+
+void
+windowInitPlugins (CompWindow *w)
+{
+ CompPlugin *p;
+
+ for (p = plugins; p; p = p->next)
+ {
+ if (p->vTable->initWindow)
+ (*p->vTable->initWindow) (p, w);
+ }
+}
+
+void
+windowFiniPlugins (CompWindow *w)
+{
+ CompPlugin *p;
+
+ for (p = plugins; p; p = p->next)
+ {
+ if (p->vTable->finiWindow)
+ (*p->vTable->finiWindow) (p, w);
+ }
+}
+
+CompPlugin *
+findActivePlugin (char *name)
+{
+ CompPlugin *p;
+
+ for (p = plugins; p; p = p->next)
+ {
+ if (strcmp (p->vTable->name, name) == 0)
+ return p;
+ }
+
+ return 0;
+}
+
+CompPlugin *
+loadPlugin (char *name)
+{
+ CompPlugin *p;
+ char *file;
+
+ p = malloc (sizeof (CompPlugin));
+ if (!p)
+ return 0;
+
+ file = malloc (strlen (name) + 7);
+ if (!file)
+ {
+ free (p);
+ return 0;
+ }
+
+ sprintf (file, "lib%s.so", name);
+
+ p->next = 0;
+ p->dlhand = 0;
+ p->vTable = 0;
+
+ p->dlhand = dlopen (file, RTLD_LAZY);
+ if (!p->dlhand)
+ {
+ char *home, *plugindir;
+
+ home = getenv ("HOME");
+ if (home)
+ {
+ plugindir = malloc (strlen (home) +
+ strlen (HOME_PLUGINDIR) +
+ strlen (file) + 3);
+ if (plugindir)
+ {
+ sprintf (plugindir, "%s/%s/%s", home, HOME_PLUGINDIR, file);
+ p->dlhand = dlopen (plugindir, RTLD_LAZY);
+ free (plugindir);
+ }
+ }
+
+ if (!p->dlhand)
+ {
+ plugindir = malloc (strlen (PLUGINDIR) + strlen (file) + 2);
+ if (plugindir)
+ {
+ sprintf (plugindir, "%s/%s", PLUGINDIR, file);
+ p->dlhand = dlopen (plugindir, RTLD_LAZY);
+ free (plugindir);
+ }
+ }
+ }
+
+ if (p->dlhand)
+ {
+ PluginGetInfoProc getInfo;
+
+ dlerror ();
+
+ getInfo = (PluginGetInfoProc) dlsym (p->dlhand, "getCompPluginInfo");
+
+ if (dlerror () != 0)
+ getInfo = 0;
+
+ if (getInfo)
+ {
+ p->vTable = (*getInfo) ();
+ if (!p->vTable)
+ {
+ fprintf (stderr, "%s: Couldn't get vtable from '%s' plugin\n",
+ programName, file);
+
+ dlclose (p->dlhand);
+ free (p);
+ p = 0;
+ }
+ }
+ else
+ {
+ fprintf (stderr, "%s: Failed to lookup getCompPluginInfo in '%s' "
+ "plugin\n", programName, file);
+
+ dlclose (p->dlhand);
+ free (p);
+ p = 0;
+ }
+ }
+ else
+ {
+ fprintf (stderr, "%s: Couldn't load plugin '%s'\n", programName,
+ file);
+ free (p);
+ p = 0;
+ }
+
+ free (file);
+
+ return p;
+}
+
+void
+unloadPlugin (CompPlugin *p)
+{
+ dlclose (p->dlhand);
+ free (p);
+}
+
+Bool
+pushPlugin (CompPlugin *p)
+{
+ if (findActivePlugin (p->vTable->name))
+ {
+ fprintf (stderr, "%s: Plugin '%s' already active\n", programName,
+ p->vTable->name);
+
+ return FALSE;
+ }
+
+ p->next = plugins;
+ plugins = p;
+
+ if (!initPlugin (p))
+ {
+ fprintf (stderr, "%s: Couldn't activate plugin '%s'\n", programName,
+ p->vTable->name);
+ plugins = p->next;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+CompPlugin *
+popPlugin (void)
+{
+ CompPlugin *p = plugins;
+
+ if (!p)
+ return 0;
+
+ finiPlugin (p);
+
+ plugins = p->next;
+
+ return p;
+}
diff --git a/src/privates.c b/src/privates.c
new file mode 100644
index 0000000..b004452
--- /dev/null
+++ b/src/privates.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+
+#include <comp.h>
+
+int
+allocatePrivateIndex (int *len,
+ char **indices,
+ ReallocPrivatesProc reallocProc,
+ void *closure)
+{
+ char *newIndices;
+ int i;
+
+ for (i = 0; i < *len; i++)
+ {
+ if (!(*indices)[i])
+ {
+ (*indices)[i] = 1;
+ return i;
+ }
+ }
+
+ newIndices = (char *) realloc (*indices, (*len + 1) * sizeof (char));
+ if (!newIndices)
+ return -1;
+
+ newIndices[*len] = 1;
+ *indices = newIndices;
+
+ if (!(*reallocProc) (*len + 1, closure))
+ return -1;
+
+ return (*len)++;
+}
+
+void
+freePrivateIndex (int len,
+ char *indices,
+ int index)
+{
+ if (index < len)
+ indices[index] = 0;
+}
diff --git a/src/readpng.c b/src/readpng.c
new file mode 100644
index 0000000..a9e1661
--- /dev/null
+++ b/src/readpng.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <png.h>
+#include <setjmp.h>
+
+#include <comp.h>
+
+#define HOME_IMAGEDIR ".glxcomp/images"
+
+static void
+premultiplyData (png_structp png,
+ png_row_infop row_info,
+ png_bytep data)
+{
+ unsigned int i;
+
+ for (i = 0; i < row_info->rowbytes; i += 4)
+ {
+ unsigned char *base = &data[i];
+ unsigned char blue = base[0];
+ unsigned char green = base[1];
+ unsigned char red = base[2];
+ unsigned char alpha = base[3];
+ int p;
+
+ red = (unsigned) red * (unsigned) alpha / 255;
+ green = (unsigned) green * (unsigned) alpha / 255;
+ blue = (unsigned) blue * (unsigned) alpha / 255;
+
+ p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
+ memcpy (base, &p, sizeof (int));
+ }
+}
+
+Bool
+readPng (const char *filename,
+ char **data,
+ unsigned int *width,
+ unsigned int *height)
+{
+ static const int PNG_SIG_SIZE = 8;
+ unsigned char png_sig[PNG_SIG_SIZE];
+ FILE *file;
+ int sig_bytes;
+ png_struct *png;
+ png_info *info;
+ png_uint_32 png_width, png_height;
+ int depth, color_type, interlace, i;
+ unsigned int pixel_size;
+ png_byte **row_pointers;
+
+ file = fopen (filename, "r");
+ if (!file)
+ {
+ char *home, *imagedir;
+
+ home = getenv ("HOME");
+ if (home)
+ {
+ imagedir = malloc (strlen (home) +
+ strlen (HOME_IMAGEDIR) +
+ strlen (filename) + 3);
+ if (imagedir)
+ {
+ sprintf (imagedir, "%s/%s/%s", home, HOME_IMAGEDIR, filename);
+ file = fopen (imagedir, "r");
+ free (imagedir);
+ }
+ }
+
+ if (!file)
+ {
+ imagedir = malloc (strlen (IMAGEDIR) + strlen (filename) + 2);
+ if (imagedir)
+ {
+ sprintf (imagedir, "%s/%s", IMAGEDIR, filename);
+ file = fopen (imagedir, "r");
+ free (imagedir);
+ }
+
+ if (!file)
+ return FALSE;
+ }
+ }
+
+ sig_bytes = fread (png_sig, 1, PNG_SIG_SIZE, file);
+ if (png_check_sig (png_sig, sig_bytes) == 0)
+ {
+ fclose (file);
+ return FALSE;
+ }
+
+ png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png)
+ {
+ fclose (file);
+ return FALSE;
+ }
+
+ info = png_create_info_struct (png);
+ if (info == NULL)
+ {
+ fclose (file);
+ png_destroy_read_struct (&png, NULL, NULL);
+ return FALSE;
+ }
+
+ png_init_io (png, file);
+ png_set_sig_bytes (png, sig_bytes);
+
+ png_read_info (png, info);
+
+ png_get_IHDR (png, info,
+ &png_width, &png_height, &depth,
+ &color_type, &interlace, NULL, NULL);
+ *width = png_width;
+ *height = png_height;
+
+ /* convert palette/gray image to rgb */
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb (png);
+
+ /* expand gray bit depth if needed */
+ if (color_type == PNG_COLOR_TYPE_GRAY && depth < 8)
+ png_set_gray_1_2_4_to_8 (png);
+
+ /* transform transparency to alpha */
+ if (png_get_valid(png, info, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha (png);
+
+ if (depth == 16)
+ png_set_strip_16 (png);
+
+ if (depth < 8)
+ png_set_packing (png);
+
+ /* convert grayscale to RGB */
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb (png);
+
+ if (interlace != PNG_INTERLACE_NONE)
+ png_set_interlace_handling (png);
+
+ png_set_bgr (png);
+ png_set_filler (png, 0xff, PNG_FILLER_AFTER);
+
+ png_set_read_user_transform_fn (png, premultiplyData);
+
+ png_read_update_info (png, info);
+
+ pixel_size = 4;
+ *data = (char *) malloc (png_width * png_height * pixel_size);
+ if (*data == NULL)
+ {
+ fclose (file);
+ return FALSE;
+ }
+
+ row_pointers = (png_byte **) malloc (png_height * sizeof (char *));
+ for (i=0; i < png_height; i++)
+ row_pointers[i] = (png_byte *) (*data + i * png_width * pixel_size);
+
+ png_read_image (png, row_pointers);
+ png_read_end (png, info);
+
+ free (row_pointers);
+ fclose (file);
+
+ png_destroy_read_struct (&png, &info, NULL);
+
+ return TRUE;
+}
diff --git a/src/screen.c b/src/screen.c
new file mode 100644
index 0000000..3664961
--- /dev/null
+++ b/src/screen.c
@@ -0,0 +1,1294 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <dlfcn.h>
+#include <string.h>
+
+#include <comp.h>
+
+#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
+
+static int
+reallocScreenPrivate (int size,
+ void *closure)
+{
+ CompDisplay *d = (CompDisplay *) closure;
+ CompScreen *s;
+ void *privates;
+
+ for (s = d->screens; s; s = s->next)
+ {
+ privates = realloc (s->privates, size * sizeof (CompPrivate));
+ if (!privates)
+ return FALSE;
+
+ s->privates = (CompPrivate *) privates;
+ }
+
+ return TRUE;
+}
+
+int
+allocateScreenPrivateIndex (CompDisplay *display)
+{
+ return allocatePrivateIndex (&display->screenPrivateLen,
+ &display->screenPrivateIndices,
+ reallocScreenPrivate,
+ (void *) display);
+}
+
+void
+freeScreenPrivateIndex (CompDisplay *display,
+ int index)
+{
+ freePrivateIndex (display->screenPrivateLen,
+ display->screenPrivateIndices,
+ index);
+}
+
+CompOption *
+compGetScreenOptions (CompScreen *screen,
+ int *count)
+{
+ *count = NUM_OPTIONS (screen);
+ return screen->opt;
+}
+
+static Bool
+setScreenOption (CompScreen *screen,
+ char *name,
+ CompOptionValue *value)
+{
+ CompOption *o;
+ int index;
+
+ o = compFindOption (screen->opt, NUM_OPTIONS (screen), name, &index);
+ if (!o)
+ return FALSE;
+
+ switch (index) {
+ case COMP_SCREEN_OPTION_REFRESH_RATE:
+ if (compSetIntOption (o, value))
+ {
+ screen->redrawTime = 1000 / o->value.i;
+ return TRUE;
+ }
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+static Bool
+setScreenOptionForPlugin (CompScreen *screen,
+ char *plugin,
+ char *name,
+ CompOptionValue *value)
+{
+ CompPlugin *p;
+
+ p = findActivePlugin (plugin);
+ if (p && p->vTable->setScreenOption)
+ return (*p->vTable->setScreenOption) (screen, name, value);
+
+ return FALSE;
+}
+
+static void
+compScreenInitOptions (CompScreen *screen)
+{
+ CompOption *o;
+
+ o = &screen->opt[COMP_SCREEN_OPTION_REFRESH_RATE];
+ o->name = "refresh_rate";
+ o->shortDesc = "Refresh Rate";
+ o->longDesc = "The rate at which the screen is redrawn (times/second)";
+ o->type = CompOptionTypeInt;
+ o->value.i = defaultRefreshRate;
+ o->rest.i.min = 1;
+ o->rest.i.max = 200;
+}
+
+static Bool
+initPluginForScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ if (p->vTable->initScreen)
+ return (*p->vTable->initScreen) (p, s);
+
+ return FALSE;
+}
+
+static void
+finiPluginForScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ if (p->vTable->finiScreen)
+ (*p->vTable->finiScreen) (p, s);
+}
+
+static void
+frustum (GLfloat left,
+ GLfloat right,
+ GLfloat bottom,
+ GLfloat top,
+ GLfloat nearval,
+ GLfloat farval)
+{
+ GLfloat x, y, a, b, c, d;
+ GLfloat m[16];
+
+ x = (2.0 * nearval) / (right - left);
+ y = (2.0 * nearval) / (top - bottom);
+ a = (right + left) / (right - left);
+ b = (top + bottom) / (top - bottom);
+ c = -(farval + nearval) / ( farval - nearval);
+ d = -(2.0 * farval * nearval) / (farval - nearval);
+
+#define M(row,col) m[col*4+row]
+ M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
+ M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
+ M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
+ M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
+#undef M
+
+ glMultMatrixf (m);
+}
+
+static void
+perspective (GLfloat fovy,
+ GLfloat aspect,
+ GLfloat zNear,
+ GLfloat zFar)
+{
+ GLfloat xmin, xmax, ymin, ymax;
+
+ ymax = zNear * tan (fovy * M_PI / 360.0);
+ ymin = -ymax;
+ xmin = ymin * aspect;
+ xmax = ymax * aspect;
+
+ frustum (xmin, xmax, ymin, ymax, zNear, zFar);
+}
+
+static void
+reshape (CompScreen *s,
+ int w,
+ int h)
+{
+ s->width = w;
+ s->height = h;
+
+ glViewport (0, 0, w, h);
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ perspective (60.0f, 1.0f, 0.1f, 100.0f);
+ glMatrixMode (GL_MODELVIEW);
+
+ s->region.rects = &s->region.extents;
+ s->region.numRects = 1;
+ s->region.extents.x1 = 0;
+ s->region.extents.y1 = 0;
+ s->region.extents.x2 = w;
+ s->region.extents.y2 = h;
+ s->region.size = 1;
+}
+
+void
+configureScreen (CompScreen *s,
+ XConfigureEvent *ce)
+{
+ if (s->attrib.width != ce->width ||
+ s->attrib.height != ce->height)
+ {
+ s->attrib.width = ce->width;
+ s->attrib.height = ce->height;
+
+ reshape (s, ce->width, ce->height);
+
+ damageScreen (s);
+ }
+}
+
+static FuncPtr
+getProcAddress (CompScreen *s,
+ const char *name)
+{
+ static void *dlhand = NULL;
+ FuncPtr funcPtr = NULL;
+
+ if (s->getProcAddress)
+ funcPtr = s->getProcAddress ((GLubyte *) name);
+
+ if (!funcPtr)
+ {
+ if (!dlhand)
+ dlhand = dlopen (NULL, RTLD_LAZY);
+
+ if (dlhand)
+ {
+ dlerror ();
+ funcPtr = (FuncPtr) dlsym (dlhand, name);
+ if (dlerror () != NULL)
+ funcPtr = NULL;
+ }
+ }
+
+ return funcPtr;
+}
+
+void
+updateScreenBackground (CompScreen *screen,
+ CompTexture *texture)
+{
+ Display *dpy = screen->display->display;
+ Atom pixmapAtom, actualType;
+ int actualFormat, i, status;
+ unsigned int width = 1, height = 1, depth = 0;
+ unsigned long nItems;
+ unsigned long bytesAfter;
+ unsigned char *prop;
+ Pixmap pixmap = 0;
+
+ pixmapAtom = XInternAtom (dpy, "PIXMAP", FALSE);
+
+ for (i = 0; pixmap == 0 && i < 2; i++)
+ {
+ status = XGetWindowProperty (dpy, screen->root,
+ screen->display->xBackgroundAtom[i],
+ 0, 4, FALSE, AnyPropertyType,
+ &actualType, &actualFormat, &nItems,
+ &bytesAfter, &prop);
+
+ if (status == Success && nItems && prop)
+ {
+ if (actualType == pixmapAtom &&
+ actualFormat == 32 &&
+ nItems == 1)
+ {
+ Pixmap p;
+
+ memcpy (&p, prop, 4);
+
+ if (p)
+ {
+ unsigned int ui;
+ int i;
+ Window w;
+
+ if (XGetGeometry (dpy, p, &w, &i, &i,
+ &width, &height, &ui, &depth))
+ {
+ if (depth == screen->attrib.depth)
+ pixmap = p;
+ }
+ }
+ }
+
+ XFree (prop);
+ }
+ }
+
+ if (!testMode && pixmap)
+ {
+ if (pixmap == texture->pixmap)
+ return;
+
+ finiTexture (screen, texture);
+ initTexture (screen, texture);
+
+ if (!bindPixmapToTexture (screen, texture, pixmap,
+ width, height, depth))
+ {
+ fprintf (stderr, "%s: Couldn't bind background pixmap 0x%x to "
+ "texture\n", programName, (int) pixmap);
+ }
+ }
+ else
+ {
+ finiTexture (screen, texture);
+ initTexture (screen, texture);
+ }
+
+ if (!texture->name)
+ readImageToTexture (screen, texture, backgroundImage, &width, &height);
+
+ if (texture->target == GL_TEXTURE_2D)
+ {
+ glBindTexture (texture->target, texture->name);
+ glTexParameteri (texture->target, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri (texture->target, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glBindTexture (texture->target, 0);
+ }
+
+ screen->backgroundWidth = width;
+ screen->backgroundHeight = height;
+}
+
+Bool
+addScreen (CompDisplay *display,
+ int screenNum)
+{
+ CompScreen *s;
+ Display *dpy = display->display;
+ static char data = 0;
+ XColor black, dummy;
+ Pixmap bitmap;
+ XVisualInfo templ;
+ XVisualInfo *visinfo;
+ VisualID visualIDs[MAX_DEPTH + 1];
+ Window rootReturn, parentReturn;
+ Window *children;
+ unsigned int nchildren;
+ int defaultDepth, nvisinfo, value, i;
+ const char *glxExtensions, *glExtensions;
+ GLint stencilBits;
+
+ s = malloc (sizeof (CompScreen));
+ if (!s)
+ return FALSE;
+
+ s->windowPrivateIndices = 0;
+ s->windowPrivateLen = 0;
+
+ if (display->screenPrivateLen)
+ {
+ s->privates = malloc (display->screenPrivateLen *
+ sizeof (CompPrivate));
+ if (!s->privates)
+ {
+ free (s);
+ return FALSE;
+ }
+ }
+ else
+ s->privates = 0;
+
+ compScreenInitOptions (s);
+
+ s->redrawTime = 1000 / s->opt[COMP_SCREEN_OPTION_REFRESH_RATE].value.i;
+
+ s->display = display;
+
+ s->damage = XCreateRegion ();
+ if (!s->damage)
+ return FALSE;
+
+ s->buttonGrab = 0;
+ s->nButtonGrab = 0;
+ s->keyGrab = 0;
+ s->nKeyGrab = 0;
+
+ s->grabs = 0;
+ s->grabSize = 0;
+ s->maxGrab = 0;
+
+ s->pendingDestroys = 0;
+
+ s->screenNum = screenNum;
+ s->colormap = DefaultColormap (dpy, screenNum);
+ s->root = XRootWindow (dpy, screenNum);
+
+ if (testMode)
+ {
+ XSetWindowAttributes attrib;
+ XWMHints *wmHints;
+ XSizeHints *normalHints;
+ XClassHint *classHint;
+ int glx_attrib[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_STENCIL_SIZE, 2,
+ GLX_DOUBLEBUFFER,
+ None
+ };
+
+ visinfo = glXChooseVisual (dpy, screenNum, glx_attrib);
+ if (!visinfo)
+ {
+ int glx_attrib2[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ None
+ };
+
+ visinfo = glXChooseVisual (dpy, screenNum, glx_attrib2);
+ if (!visinfo)
+ {
+ fprintf (stderr, "%s: Couldn't find a double buffered "
+ "RGB visual.\n", programName);
+ return FALSE;
+ }
+ }
+
+ attrib.colormap = XCreateColormap (dpy, s->root, visinfo->visual,
+ AllocNone);
+
+ normalHints = XAllocSizeHints ();
+ normalHints->flags = 0;
+ normalHints->x = 0;
+ normalHints->y = 0;
+ normalHints->width = 800;
+ normalHints->height = 600;
+
+ classHint = XAllocClassHint ();
+ classHint->res_name = "glxcompmgr";
+ classHint->res_class = "Glxcompmgr";
+
+ wmHints = XAllocWMHints ();
+ wmHints->flags = InputHint;
+ wmHints->input = TRUE;
+
+ s->root = XCreateWindow (dpy, s->root, 0, 0,
+ normalHints->width, normalHints->height, 0,
+ visinfo->depth, InputOutput, visinfo->visual,
+ CWColormap, &attrib);
+
+ XSetWMProtocols (dpy, s->root, &display->wmDeleteWindowAtom, 1);
+
+ XmbSetWMProperties (dpy, s->root,
+ "glxcompmgr - Test mode", "glxcompmgr",
+ programArgv, programArgc,
+ normalHints, wmHints, classHint);
+
+ s->fake[0] = XCreateWindow (dpy, s->root, 64, 32, 1, 1, 0,
+ visinfo->depth, InputOutput,
+ visinfo->visual,
+ CWColormap, &attrib);
+
+ s->fake[1] = XCreateWindow (dpy, s->root, 256, 256, 1, 1, 0,
+ visinfo->depth, InputOutput,
+ visinfo->visual,
+ CWColormap, &attrib);
+
+ XMapWindow (dpy, s->root);
+
+ XFree (wmHints);
+ XFree (classHint);
+ XFree (normalHints);
+ }
+ else
+ s->fake[0] = s->fake[1] = 0;
+
+ s->escapeKeyCode = XKeysymToKeycode (display->display,
+ XStringToKeysym ("Escape"));
+
+ s->allDamaged = TRUE;
+ s->next = 0;
+ s->exposeRects = 0;
+ s->sizeExpose = 0;
+ s->nExpose = 0;
+
+ s->rasterX = 0;
+ s->rasterY = 0;
+
+ s->windows = 0;
+ s->reverseWindows = 0;
+
+ s->stencilRef = 0x1;
+
+ s->nextRedraw = 0;
+
+ gettimeofday (&s->lastRedraw, 0);
+
+ s->setScreenOption = setScreenOption;
+ s->setScreenOptionForPlugin = setScreenOptionForPlugin;
+
+ s->initPluginForScreen = initPluginForScreen;
+ s->finiPluginForScreen = finiPluginForScreen;
+
+ s->preparePaintScreen = preparePaintScreen;
+ s->donePaintScreen = donePaintScreen;
+ s->paintScreen = paintScreen;
+ s->paintTransformedScreen = paintTransformedScreen;
+ s->paintBackground = paintBackground;
+ s->paintWindow = paintWindow;
+ s->invisibleWindowMove = invisibleWindowMove;
+
+ s->getProcAddress = 0;
+
+ if (s->root)
+ {
+ XSetWindowAttributes attrib;
+
+ attrib.override_redirect = 1;
+ s->grabWindow = XCreateWindow (dpy, s->root, -100, -100, 1, 1, 0,
+ CopyFromParent, CopyFromParent,
+ CopyFromParent, CWOverrideRedirect,
+ &attrib);
+
+ XMapWindow (dpy, s->grabWindow);
+ }
+
+ if (!XGetWindowAttributes (dpy, s->root, &s->attrib))
+ return FALSE;
+
+ s->activeWindow = None;
+
+ templ.visualid = XVisualIDFromVisual (s->attrib.visual);
+
+ visinfo = XGetVisualInfo (dpy, VisualIDMask, &templ, &nvisinfo);
+ if (!nvisinfo)
+ {
+ fprintf (stderr, "%s: Couldn't get visual info for default visual\n",
+ programName);
+ return FALSE;
+ }
+
+ defaultDepth = visinfo->depth;
+
+ if (!XAllocNamedColor (dpy, s->colormap, "black", &black, &dummy))
+ {
+ fprintf (stderr, "%s: Couldn't allocate color\n", programName);
+ return FALSE;
+ }
+
+ bitmap = XCreateBitmapFromData (dpy, s->root, &data, 1, 1);
+ if (!bitmap)
+ {
+ fprintf (stderr, "%s: Couldn't create bitmap\n", programName);
+ return FALSE;
+ }
+
+ s->invisibleCursor = XCreatePixmapCursor (dpy, bitmap, bitmap,
+ &black, &black, 0, 0);
+ if (!s->invisibleCursor)
+ {
+ fprintf (stderr, "%s: Couldn't create invisible cursor\n",
+ programName);
+ return FALSE;
+ }
+
+ XFreePixmap (dpy, bitmap);
+ XFreeColors (dpy, s->colormap, &black.pixel, 1, 0);
+
+ glXGetConfig (dpy, visinfo, GLX_USE_GL, &value);
+ if (!value)
+ {
+ fprintf (stderr, "%s: Root visual is not a GL visual\n",
+ programName);
+ return FALSE;
+ }
+
+ glXGetConfig (dpy, visinfo, GLX_DOUBLEBUFFER, &value);
+ if (!value)
+ {
+ fprintf (stderr,
+ "%s: Root visual is not a double buffered GL visual\n",
+ programName);
+ return FALSE;
+ }
+
+ s->ctx = glXCreateContext (dpy, visinfo, NULL, TRUE);
+ if (!s->ctx)
+ {
+ fprintf (stderr, "%s: glXCreateContext failed\n", programName);
+ return FALSE;
+ }
+
+ XFree (visinfo);
+
+ /* we don't want to allocate back, stencil or depth buffers for pixmaps
+ so lets see if we can find an approriate visual without these buffers */
+ for (i = 0; i <= MAX_DEPTH; i++)
+ {
+ int j, db, stencil, depth;
+
+ visualIDs[i] = 0;
+
+ db = MAXSHORT;
+ stencil = MAXSHORT;
+ depth = MAXSHORT;
+
+ templ.depth = i;
+
+ visinfo = XGetVisualInfo (dpy, VisualDepthMask, &templ, &nvisinfo);
+ for (j = 0; j < nvisinfo; j++)
+ {
+ glXGetConfig (dpy, &visinfo[j], GLX_USE_GL, &value);
+ if (!value)
+ continue;
+
+ glXGetConfig (dpy, &visinfo[j], GLX_DOUBLEBUFFER, &value);
+ if (value > db)
+ continue;
+
+ db = value;
+ glXGetConfig (dpy, &visinfo[j], GLX_STENCIL_SIZE, &value);
+ if (value > stencil)
+ continue;
+
+ stencil = value;
+ glXGetConfig (dpy, &visinfo[j], GLX_DEPTH_SIZE, &value);
+ if (value > depth)
+ continue;
+
+ depth = value;
+ visualIDs[i] = visinfo[j].visualid;
+ }
+
+ if (nvisinfo)
+ XFree (visinfo);
+ }
+
+ /* create contexts for supported depths */
+ for (i = 0; i <= MAX_DEPTH; i++)
+ {
+ templ.visualid = visualIDs[i];
+ s->glxPixmapVisuals[i] = XGetVisualInfo (dpy,
+ VisualIDMask,
+ &templ,
+ &nvisinfo);
+ }
+
+ if (!s->glxPixmapVisuals[defaultDepth])
+ {
+ fprintf (stderr, "%s: No GL visual for default depth, "
+ "this isn't going to work.\n", programName);
+ return FALSE;
+ }
+
+ glXMakeCurrent (dpy, s->root, s->ctx);
+ currentRoot = s->root;
+
+ glxExtensions = glXQueryExtensionsString (s->display->display, screenNum);
+ if (!testMode && !strstr (glxExtensions, "GLX_MESA_render_texture"))
+ {
+ fprintf (stderr, "%s: GLX_MESA_render_texture is missing\n",
+ programName);
+ return FALSE;
+ }
+
+ s->getProcAddress = (GLXGetProcAddressProc)
+ getProcAddress (s, "glXGetProcAddressARB");
+ s->bindTexImage = (GLXBindTexImageProc)
+ getProcAddress (s, "glXBindTexImageMESA");
+ s->releaseTexImage = (GLXReleaseTexImageProc)
+ getProcAddress (s, "glXReleaseTexImageMESA");
+ s->queryDrawable = (GLXQueryDrawableProc)
+ getProcAddress (s, "glXQueryDrawable");
+
+ if (!testMode && !s->bindTexImage)
+ {
+ fprintf (stderr, "%s: glXBindTexImageMESA is missing\n", programName);
+ return FALSE;
+ }
+
+ if (!testMode && !s->releaseTexImage)
+ {
+ fprintf (stderr, "%s: glXReleaseTexImageMESA is missing\n",
+ programName);
+ return FALSE;
+ }
+
+ if (!testMode && !s->queryDrawable)
+ {
+ fprintf (stderr, "%s: glXQueryDrawable is missing\n", programName);
+ return FALSE;
+ }
+
+ glExtensions = (const char *) glGetString (GL_EXTENSIONS);
+ if (strstr (glExtensions, "GL_NV_texture_rectangle") ||
+ strstr (glExtensions, "GL_EXT_texture_rectangle") ||
+ strstr (glExtensions, "GL_ARB_texture_rectangle"))
+ s->textureRectangle = 1;
+
+ if (strstr (glExtensions, "GL_ARB_texture_non_power_of_two"))
+ s->textureNonPowerOfTwo = 1;
+
+ if (!(s->textureRectangle || s->textureNonPowerOfTwo))
+ {
+ fprintf (stderr, "%s: Support for non power of two textures missing\n",
+ programName);
+ return FALSE;
+ }
+
+ initTexture (s, &s->backgroundTexture);
+
+ s->desktopWindowCount = 0;
+
+ glGetIntegerv (GL_STENCIL_BITS, &stencilBits);
+ if (!stencilBits)
+ {
+ fprintf (stderr, "%s: No stencil buffer. Clipping of transformed "
+ "windows is not going to be correct when screen is "
+ "transformed.\n", programName);
+ }
+
+ glClearColor (0.0, 0.0, 0.0, 1.0);
+ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable (GL_CULL_FACE);
+ glDisable (GL_BLEND);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glEnableClientState (GL_VERTEX_ARRAY);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+ glColor4usv (defaultColor);
+
+ s->activeWindow = getActiveWindow (display, s->root);
+
+ reshape (s, s->attrib.width, s->attrib.height);
+
+ s->next = display->screens;
+ display->screens = s;
+
+ screenInitPlugins (s);
+
+ XSelectInput (dpy, s->root,
+ SubstructureNotifyMask |
+ StructureNotifyMask |
+ PropertyChangeMask |
+ ExposureMask |
+ ButtonPressMask |
+ ButtonReleaseMask |
+ ButtonMotionMask);
+
+ XQueryTree (dpy, s->root,
+ &rootReturn, &parentReturn,
+ &children, &nchildren);
+
+ for (i = 0; i < nchildren; i++)
+ {
+ if (children[i] == s->grabWindow)
+ continue;
+
+ addWindow (s, children[i], i ? children[i - 1] : 0);
+ }
+
+ XFree (children);
+
+ return TRUE;
+}
+
+void
+damageScreenRegion (CompScreen *screen,
+ Region region)
+{
+ if (screen->allDamaged)
+ return;
+
+ XUnionRegion (screen->damage, region, screen->damage);
+}
+
+void
+damageScreen (CompScreen *s)
+{
+ s->allDamaged = TRUE;
+}
+
+CompWindow *
+findWindowAtScreen (CompScreen *s,
+ Window id)
+{
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ if (w->id == id)
+ return w;
+
+ return 0;
+}
+
+CompWindow *
+findClientWindowAtScreen (CompScreen *s,
+ Window id)
+{
+ CompWindow *w;
+
+ for (w = s->windows; w; w = w->next)
+ if (w->client == id)
+ return w;
+
+ return 0;
+}
+
+void
+insertWindowIntoScreen (CompScreen *s,
+ CompWindow *w,
+ Window aboveId)
+{
+ CompWindow *p;
+
+ if (s->windows)
+ {
+ for (p = s->windows; p; p = p->next)
+ {
+ if (p->id == aboveId)
+ {
+ w->next = p->next;
+ w->prev = p;
+ if (p->next)
+ p->next->prev = w;
+ p->next = w;
+
+ if (s->reverseWindows == p)
+ s->reverseWindows = w;
+
+ return;
+ }
+
+ if (!p->next)
+ {
+ p->next = w;
+ w->next = NULL;
+ w->prev = p;
+
+ s->reverseWindows = w;
+
+ return;
+ }
+ }
+ }
+ else
+ {
+ s->reverseWindows = s->windows = w;
+ w->prev = w->next = NULL;
+ }
+}
+
+void
+unhookWindowFromScreen (CompScreen *s,
+ CompWindow *w)
+{
+ CompWindow *p;
+
+ if (s->windows == w)
+ {
+ s->windows = w->next;
+ if (w->next)
+ w->next->prev = NULL;
+ }
+
+ if (s->reverseWindows == w)
+ {
+ s->reverseWindows = w->prev;
+ if (w->prev)
+ w->prev->next = NULL;
+ }
+
+ for (p = s->windows; p; p = p->next)
+ {
+ if (p->next == w)
+ {
+ p->next = w->next;
+ if (w->next)
+ w->next->prev = p;
+
+ p->next = w->next;
+ break;
+ }
+ }
+}
+
+#define POINTER_GRAB_MASK (ButtonReleaseMask | \
+ ButtonPressMask | \
+ PointerMotionMask)
+int
+pushScreenGrab (CompScreen *s,
+ Cursor cursor)
+{
+ if (s->maxGrab == 0)
+ {
+ int status;
+
+ status = XGrabPointer (s->display->display, s->grabWindow, TRUE,
+ POINTER_GRAB_MASK,
+ GrabModeAsync, GrabModeAsync,
+ s->root, cursor,
+ CurrentTime);
+
+ if (status == GrabSuccess)
+ {
+ status = XGrabKeyboard (s->display->display,
+ s->grabWindow, TRUE,
+ GrabModeAsync, GrabModeAsync,
+ CurrentTime);
+ if (status != GrabSuccess)
+ {
+ XUngrabPointer (s->display->display, CurrentTime);
+ return 0;
+ }
+ }
+ else
+ return 0;
+ }
+ else
+ {
+ XChangeActivePointerGrab (s->display->display, POINTER_GRAB_MASK,
+ cursor, CurrentTime);
+ }
+
+ if (s->grabSize <= s->maxGrab)
+ {
+ s->grabs = realloc (s->grabs, sizeof (CompGrab) * (s->maxGrab + 1));
+ if (!s->grabs)
+ return 0;
+
+ s->grabSize = s->maxGrab + 1;
+ }
+
+ s->grabs[s->maxGrab].cursor = cursor;
+ s->grabs[s->maxGrab].active = TRUE;
+
+ s->maxGrab++;
+
+ return s->maxGrab;
+}
+
+void
+removeScreenGrab (CompScreen *s,
+ int index,
+ XPoint *restorePointer)
+{
+ int maxGrab;
+
+ index--;
+ if (index < 0 || index >= s->maxGrab)
+ abort ();
+
+ s->grabs[index].cursor = None;
+ s->grabs[index].active = FALSE;
+
+ for (maxGrab = s->maxGrab; maxGrab; maxGrab--)
+ if (s->grabs[maxGrab - 1].active)
+ break;
+
+ if (maxGrab != s->maxGrab)
+ {
+ if (maxGrab)
+ {
+ XChangeActivePointerGrab (s->display->display,
+ POINTER_GRAB_MASK,
+ s->grabs[s->maxGrab - 1].cursor,
+ CurrentTime);
+ }
+ else
+ {
+ if (restorePointer)
+ XWarpPointer (s->display->display, None, s->root, 0, 0, 0, 0,
+ restorePointer->x, restorePointer->y);
+
+ XUngrabPointer (s->display->display, CurrentTime);
+ XUngrabKeyboard (s->display->display, CurrentTime);
+ }
+ s->maxGrab = maxGrab;
+ }
+}
+
+static Bool
+addPassiveKeyGrab (CompScreen *s,
+ CompKeyBinding *key)
+{
+ CompKeyGrab *keyGrab;
+ unsigned int modifiers, mask;
+ int i;
+
+ modifiers = key->modifiers & ~(CompPressMask | CompReleaseMask);
+ if (modifiers == key->modifiers)
+ return TRUE;
+
+ for (i = 0; i < s->nKeyGrab; i++)
+ {
+ if (key->keycode == s->keyGrab[i].keycode &&
+ modifiers == s->keyGrab[i].modifiers)
+ {
+ s->keyGrab[i].count++;
+ return TRUE;
+ }
+ }
+
+ keyGrab = realloc (s->keyGrab, sizeof (CompKeyGrab) * (s->nKeyGrab + 1));
+ if (!keyGrab)
+ return FALSE;
+
+ s->keyGrab = keyGrab;
+
+ mask = virtualToRealModMask (s->display, modifiers);
+ if (!(mask & CompNoMask))
+ {
+ compCheckForError ();
+
+ XGrabKey (s->display->display,
+ key->keycode,
+ mask,
+ s->root,
+ TRUE,
+ GrabModeAsync,
+ GrabModeAsync);
+
+ XSync (s->display->display, FALSE);
+
+ if (compCheckForError ())
+ {
+
+#ifdef DEBUG
+ KeySym keysym;
+ char *keyname;
+
+ keysym = XKeycodeToKeysym (s->display->display,
+ key->keycode,
+ 0);
+ keyname = XKeysymToString (keysym);
+
+ fprintf (stderr, "XGrabKey failed: %s 0x%x\n",
+ keyname, modifiers);
+#endif
+
+ return FALSE;
+ }
+ }
+
+ s->keyGrab[s->nKeyGrab].keycode = key->keycode;
+ s->keyGrab[s->nKeyGrab].modifiers = modifiers;
+ s->keyGrab[s->nKeyGrab].count = 1;
+
+ s->nKeyGrab++;
+
+ return TRUE;
+}
+
+static void
+removePassiveKeyGrab (CompScreen *s,
+ CompKeyBinding *key)
+{
+ unsigned int modifiers, mask;
+ int i;
+
+ modifiers = key->modifiers & ~(CompPressMask | CompReleaseMask);
+ if (modifiers == key->modifiers)
+ return;
+
+ for (i = 0; i < s->nKeyGrab; i++)
+ {
+ if (key->keycode == s->keyGrab[i].keycode &&
+ modifiers == s->keyGrab[i].modifiers)
+ {
+ s->keyGrab[i].count--;
+ if (s->keyGrab[i].count)
+ return;
+
+ s->nKeyGrab--;
+ s->keyGrab = realloc (s->keyGrab,
+ sizeof (CompKeyGrab) * s->nKeyGrab);
+
+ mask = virtualToRealModMask (s->display, modifiers);
+ if (!(mask & CompNoMask))
+ {
+ XUngrabKey (s->display->display,
+ key->keycode,
+ mask,
+ s->root);
+ }
+ }
+ }
+}
+
+static void
+updatePassiveKeyGrabs (CompScreen *s)
+{
+ unsigned int mask;
+ int i;
+
+ XUngrabKey (s->display->display, AnyKey, AnyModifier, s->root);
+
+ for (i = 0; i < s->nKeyGrab; i++)
+ {
+ mask = virtualToRealModMask (s->display, s->keyGrab[i].modifiers);
+ if (!(mask & CompNoMask))
+ {
+ XGrabKey (s->display->display,
+ s->keyGrab[i].keycode,
+ mask,
+ s->root,
+ TRUE,
+ GrabModeAsync,
+ GrabModeAsync);
+ }
+ }
+}
+
+static Bool
+addPassiveButtonGrab (CompScreen *s,
+ CompButtonBinding *button)
+{
+ CompButtonGrab *buttonGrab;
+ unsigned int modifiers, mask;
+ int i;
+
+ modifiers = button->modifiers & ~(CompPressMask | CompReleaseMask);
+ if (modifiers == button->modifiers)
+ return TRUE;
+
+ for (i = 0; i < s->nButtonGrab; i++)
+ {
+ if (button->button == s->buttonGrab[i].button &&
+ modifiers == s->buttonGrab[i].modifiers)
+ {
+ s->buttonGrab[i].count++;
+ return TRUE;
+ }
+ }
+
+ buttonGrab = realloc (s->buttonGrab,
+ sizeof (CompButtonGrab) * (s->nButtonGrab + 1));
+ if (!buttonGrab)
+ return FALSE;
+
+ s->buttonGrab = buttonGrab;
+
+ mask = virtualToRealModMask (s->display, modifiers);
+ if (!(mask & CompNoMask))
+ {
+ compCheckForError ();
+
+ XGrabButton (s->display->display,
+ button->button,
+ mask,
+ s->root,
+ TRUE,
+ POINTER_GRAB_MASK,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ None);
+
+ XSync (s->display->display, FALSE);
+
+ if (compCheckForError ())
+ {
+
+#ifdef DEBUG
+ fprintf (stderr, "XGrabButton failed: %s 0x%x\n",
+ button->button, modifiers);
+#endif
+
+ return FALSE;
+ }
+ }
+
+ s->buttonGrab[s->nButtonGrab].button = button->button;
+ s->buttonGrab[s->nButtonGrab].modifiers = modifiers;
+ s->buttonGrab[s->nButtonGrab].count = 1;
+
+ s->nButtonGrab++;
+
+ return TRUE;
+}
+
+static void
+removePassiveButtonGrab (CompScreen *s,
+ CompButtonBinding *button)
+{
+ unsigned int modifiers, mask;
+ int i;
+
+ modifiers = button->modifiers & ~(CompPressMask | CompReleaseMask);
+ if (modifiers == button->modifiers)
+ return;
+
+ for (i = 0; i < s->nButtonGrab; i++)
+ {
+ if (button->button == s->buttonGrab[i].button &&
+ modifiers == s->buttonGrab[i].modifiers)
+ {
+ s->buttonGrab[i].count--;
+ if (s->buttonGrab[i].count)
+ return;
+
+ s->nButtonGrab--;
+ s->buttonGrab = realloc (s->buttonGrab,
+ sizeof (CompButtonGrab) * s->nButtonGrab);
+
+ mask = virtualToRealModMask (s->display, modifiers);
+ if (!(mask & CompNoMask))
+ {
+ XUngrabButton (s->display->display,
+ button->button,
+ mask,
+ s->root);
+ }
+ }
+ }
+}
+
+static void
+updatePassiveButtonGrabs (CompScreen *s)
+{
+ unsigned int mask;
+ int i;
+
+ XUngrabButton (s->display->display, AnyButton, AnyModifier, s->root);
+
+ for (i = 0; i < s->nButtonGrab; i++)
+ {
+ mask = virtualToRealModMask (s->display, s->buttonGrab[i].modifiers);
+ if (!(mask & CompNoMask))
+ {
+ XGrabButton (s->display->display,
+ s->buttonGrab[i].button,
+ mask,
+ s->root,
+ TRUE,
+ POINTER_GRAB_MASK,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ None);
+ }
+ }
+}
+
+Bool
+addScreenBinding (CompScreen *s,
+ CompBinding *binding)
+{
+ if (binding->type == CompBindingTypeKey)
+ return addPassiveKeyGrab (s, &binding->u.key);
+ else if (binding->type == CompBindingTypeButton)
+ return addPassiveButtonGrab (s, &binding->u.button);
+
+ return FALSE;
+}
+
+void
+removeScreenBinding (CompScreen *s,
+ CompBinding *binding)
+{
+ if (binding->type == CompBindingTypeKey)
+ removePassiveKeyGrab (s, &binding->u.key);
+ else if (binding->type == CompBindingTypeButton)
+ removePassiveButtonGrab (s, &binding->u.button);
+}
+
+void
+updatePassiveGrabs (CompScreen *s)
+{
+ updatePassiveButtonGrabs (s);
+ updatePassiveKeyGrabs (s);
+}
diff --git a/src/texture.c b/src/texture.c
new file mode 100644
index 0000000..6ef4e74
--- /dev/null
+++ b/src/texture.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <comp.h>
+
+void
+initTexture (CompScreen *screen,
+ CompTexture *texture)
+{
+ texture->name = 0;
+ texture->target = GL_TEXTURE_2D;
+ texture->dx = 0.0f;
+ texture->dy = 0.0f;
+ texture->pixmap = None;
+ texture->filter = COMP_TEXTURE_FILTER_FAST;
+}
+
+void
+finiTexture (CompScreen *screen,
+ CompTexture *texture)
+{
+ if (texture->name)
+ {
+ releasePixmapFromTexture (screen, texture);
+ glDeleteTextures (1, &texture->name);
+ }
+}
+
+Bool
+readImageToTexture (CompScreen *screen,
+ CompTexture *texture,
+ char *imageFileName,
+ unsigned int *returnWidth,
+ unsigned int *returnHeight)
+{
+ char *data, *image;
+ unsigned int width, height;
+ int i;
+
+ if (!readPng (imageFileName, &image, &width, &height))
+ {
+ fprintf (stderr, "%s: Failed to load image: %s\n",
+ programName, imageFileName);
+ return FALSE;
+ }
+
+ data = malloc (4 * width * height);
+ if (!data)
+ {
+ free (image);
+ return FALSE;
+ }
+
+ for (i = 0; i < height; i++)
+ memcpy (&data[i * width * 4],
+ &image[(height - i - 1) * width * 4],
+ width * 4);
+
+ free (image);
+
+ releasePixmapFromTexture (screen, texture);
+
+ if (screen->textureNonPowerOfTwo ||
+ (POWER_OF_TWO (width) && POWER_OF_TWO (height)))
+ {
+ texture->target = GL_TEXTURE_2D;
+ texture->dx = 1.0f / width;
+ texture->dy = 1.0f / height;
+ }
+ else
+ {
+ texture->target = GL_TEXTURE_RECTANGLE_NV;
+ texture->dx = texture->dy = 1.0f;
+ }
+
+ if (!texture->name)
+ glGenTextures (1, &texture->name);
+
+ glBindTexture (texture->target, texture->name);
+
+ glTexImage2D (texture->target, 0, GL_RGB, width, height, 0, GL_BGRA,
+
+#if IMAGE_BYTE_ORDER == MSBFirst
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+#else
+ GL_UNSIGNED_BYTE,
+#endif
+
+ data);
+
+ texture->filter = COMP_TEXTURE_FILTER_FAST;
+
+ glTexParameteri (texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri (texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glTexParameteri (texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri (texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glBindTexture (texture->target, 0);
+
+ free (data);
+
+ *returnWidth = width;
+ *returnHeight = height;
+
+ return TRUE;
+}
+
+Bool
+bindPixmapToTexture (CompScreen *screen,
+ CompTexture *texture,
+ Pixmap pixmap,
+ int width,
+ int height,
+ int depth)
+{
+ XVisualInfo *visinfo;
+ unsigned int target;
+
+ visinfo = screen->glxPixmapVisuals[depth];
+ if (!visinfo)
+ {
+ fprintf (stderr, "%s: No GL visual for depth %d\n",
+ programName, depth);
+
+ return FALSE;
+ }
+
+ texture->pixmap = glXCreateGLXPixmap (screen->display->display,
+ visinfo, pixmap);
+ if (!texture->pixmap)
+ {
+ fprintf (stderr, "%s: glXCreateGLXPixmap failed\n", programName);
+
+ return FALSE;
+ }
+
+ if (screen->queryDrawable (screen->display->display,
+ texture->pixmap,
+ GLX_TEXTURE_TARGET_EXT,
+ &target))
+ {
+ fprintf (stderr, "%s: glXQueryDrawable failed\n", programName);
+
+ glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
+ texture->pixmap = None;
+
+ return FALSE;
+ }
+
+ switch (target) {
+ case GLX_TEXTURE_2D_EXT:
+ texture->target = GL_TEXTURE_2D;
+ texture->dx = 1.0f / width;
+ texture->dy = 1.0f / height;
+ break;
+ case GLX_TEXTURE_RECTANGLE_EXT:
+ texture->target = GL_TEXTURE_RECTANGLE_ARB;
+ texture->dx = texture->dy = 1.0f;
+ break;
+ default:
+ fprintf (stderr, "%s: pixmap 0x%x can't be bound to texture\n",
+ programName, (int) pixmap);
+
+ glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
+ texture->pixmap = None;
+
+ return FALSE;
+ }
+
+ if (!texture->name)
+ glGenTextures (1, &texture->name);
+
+ glBindTexture (texture->target, texture->name);
+
+ if (!screen->bindTexImage (screen->display->display,
+ texture->pixmap,
+ GLX_FRONT_LEFT_EXT))
+ {
+ fprintf (stderr, "%s: glXBindTexImage failed\n", programName);
+
+ glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
+ texture->pixmap = None;
+
+ return FALSE;
+ }
+
+ texture->filter = COMP_TEXTURE_FILTER_FAST;
+
+ glTexParameteri (texture->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri (texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glTexParameteri (texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri (texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glBindTexture (texture->target, 0);
+
+ return TRUE;
+}
+
+void
+releasePixmapFromTexture (CompScreen *screen,
+ CompTexture *texture)
+{
+ if (texture->pixmap)
+ {
+ glEnable (texture->target);
+ glBindTexture (texture->target, texture->name);
+
+ screen->releaseTexImage (screen->display->display,
+ texture->pixmap,
+ GLX_FRONT_LEFT_EXT);
+
+ glBindTexture (texture->target, 0);
+ glDisable (texture->target);
+
+ glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
+ texture->pixmap = None;
+ }
+}
+
+void
+enableTexture (CompScreen *screen,
+ CompTexture *texture,
+ CompTextureFilter filter)
+{
+ glEnable (texture->target);
+ glBindTexture (texture->target, texture->name);
+
+ if (filter != texture->filter)
+ {
+ switch (filter) {
+ case COMP_TEXTURE_FILTER_FAST:
+ glTexParameteri (texture->target,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ glTexParameteri (texture->target,
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ break;
+ case COMP_TEXTURE_FILTER_GOOD:
+ glTexParameteri (texture->target,
+ GL_TEXTURE_MIN_FILTER,
+ screen->display->textureFilter);
+ glTexParameteri (texture->target,
+ GL_TEXTURE_MAG_FILTER,
+ screen->display->textureFilter);
+ break;
+ }
+
+ texture->filter = filter;
+ }
+}
+
+void
+disableTexture (CompTexture *texture)
+{
+ glBindTexture (texture->target, 0);
+ glDisable (texture->target);
+}
diff --git a/src/window.c b/src/window.c
new file mode 100644
index 0000000..8c9a126
--- /dev/null
+++ b/src/window.c
@@ -0,0 +1,605 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
+#include <X11/extensions/Xcomposite.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <comp.h>
+
+static int
+reallocWindowPrivates (int size,
+ void *closure)
+{
+ CompScreen *s = (CompScreen *) closure;
+ CompWindow *w;
+ void *privates;
+
+ for (w = s->windows; w; w = w->next)
+ {
+ privates = realloc (w->privates, size * sizeof (CompPrivate));
+ if (!privates)
+ return FALSE;
+
+ w->privates = (CompPrivate *) privates;
+ }
+
+ return TRUE;
+}
+
+int
+allocateWindowPrivateIndex (CompScreen *screen)
+{
+ return allocatePrivateIndex (&screen->windowPrivateLen,
+ &screen->windowPrivateIndices,
+ reallocWindowPrivates,
+ (void *) screen);
+}
+
+void
+freeWindowPrivateIndex (CompScreen *screen,
+ int index)
+{
+ freePrivateIndex (screen->windowPrivateLen,
+ screen->windowPrivateIndices,
+ index);
+}
+
+static Window
+tryChildren (CompDisplay *display,
+ Window win)
+{
+ Window root, parent;
+ Window *children;
+ unsigned int nchildren;
+ unsigned int i;
+ Atom type = None;
+ int format;
+ unsigned long nitems, after;
+ unsigned char *data;
+ Window inf = 0;
+
+ if (!XQueryTree (display->display, win, &root, &parent,
+ &children, &nchildren))
+ return 0;
+
+ for (i = 0; !inf && (i < nchildren); i++)
+ {
+ data = NULL;
+
+ XGetWindowProperty (display->display, children[i],
+ display->wmStateAtom, 0, 0,
+ False, AnyPropertyType, &type, &format, &nitems,
+ &after, &data);
+ if (data)
+ XFree (data);
+
+ if (type)
+ inf = children[i];
+ }
+
+ for (i = 0; !inf && (i < nchildren); i++)
+ inf = tryChildren (display, children[i]);
+
+ if (children)
+ XFree (children);
+
+ return inf;
+}
+
+static Window
+clientWindow (CompDisplay *display,
+ Window win)
+{
+ Atom type = None;
+ int format;
+ unsigned long nitems, after;
+ unsigned char *data = NULL;
+ Window inf;
+
+ XGetWindowProperty (display->display, win, display->wmStateAtom, 0, 0,
+ False, AnyPropertyType, &type, &format, &nitems,
+ &after, &data);
+
+ if (data)
+ XFree (data);
+
+ if (type)
+ return win;
+
+ inf = tryChildren (display, win);
+ if (!inf)
+ inf = win;
+
+ return inf;
+}
+
+Window
+getActiveWindow (CompDisplay *display,
+ Window root)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+
+ result = XGetWindowProperty (display->display, root,
+ display->winActiveAtom, 0L, 1L, False,
+ XA_WINDOW, &actual, &format,
+ &n, &left, &data);
+
+ if (result == Success && n && data)
+ {
+ Window w;
+
+ memcpy (&w, data, sizeof (Window));
+ XFree ((void *) data);
+
+ return w;
+ }
+
+ return None;
+}
+
+Atom
+getWindowType (CompDisplay *display,
+ Window id)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+
+ result = XGetWindowProperty (display->display, id, display->winTypeAtom,
+ 0L, 1L, FALSE, XA_ATOM, &actual, &format,
+ &n, &left, &data);
+
+ if (result == Success && n && data)
+ {
+ Atom a;
+
+ memcpy (&a, data, sizeof (Atom));
+ XFree ((void *) data);
+
+ return a;
+ }
+
+ return display->winNormalAtom;
+}
+
+unsigned short
+getWindowOpacity (CompDisplay *display,
+ Window id)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+
+ result = XGetWindowProperty (display->display, id, display->winOpacityAtom,
+ 0L, 1L, FALSE, XA_CARDINAL, &actual, &format,
+ &n, &left, &data);
+
+ if (result == Success && n && data)
+ {
+ unsigned int o;
+
+ memcpy (&o, data, sizeof (Atom));
+ XFree ((void *) data);
+
+ return (o / 0xffff);
+ }
+
+ return MAXSHORT;
+}
+
+void
+bindWindow (CompWindow *w)
+{
+ if (testMode)
+ {
+ unsigned int width, height;
+
+ if (readImageToTexture (w->screen, &w->texture,
+ windowImage, &width, &height))
+ {
+ XResizeWindow (w->screen->display->display, w->id, width, height);
+
+ w->width = width;
+ w->height = height;
+ }
+
+ w->pixmap = 1;
+ }
+ else
+ {
+ w->pixmap = XCompositeNameWindowPixmap (w->screen->display->display,
+ w->id);
+ if (!w->pixmap)
+ {
+ fprintf (stderr, "%s: XCompositeNameWindowPixmap failed\n",
+ programName);
+ return;
+ }
+
+ if (!bindPixmapToTexture (w->screen, &w->texture, w->pixmap,
+ w->width, w->height,
+ w->attrib.depth))
+ {
+ fprintf (stderr, "%s: Couldn't bind redirected window 0x%x to "
+ "texture\n", programName, (int) w->id);
+ }
+ }
+}
+
+void
+releaseWindow (CompWindow *w)
+{
+ if (w->pixmap)
+ {
+ releasePixmapFromTexture (w->screen, &w->texture);
+
+ if (!testMode)
+ XFreePixmap (w->screen->display->display, w->pixmap);
+
+ w->pixmap = None;
+ }
+}
+
+static void
+freeWindow (CompWindow *w)
+{
+ releaseWindow (w);
+
+ if (w->texture.name)
+ finiTexture (w->screen, &w->texture);
+
+ if (w->clip)
+ XDestroyRegion (w->clip);
+
+ if (w->region)
+ XDestroyRegion (w->region);
+
+ if (w->privates)
+ free (w->privates);
+
+ free (w);
+}
+
+void
+addWindowDamage (CompWindow *w)
+{
+ if (w->attrib.map_state == IsViewable)
+ damageScreenRegion (w->screen, w->region);
+}
+
+void
+updateWindowRegion (CompWindow *w)
+{
+ REGION rect;
+ XRectangle r, *rects, *shapeRects = 0;
+ int i, n = 0;
+
+ EMPTY_REGION (w->region);
+
+ if (w->screen->display->shapeExtension)
+ {
+ int order;
+
+ shapeRects = XShapeGetRectangles (w->screen->display->display, w->id,
+ ShapeBounding, &n, &order);
+ }
+
+ if (n < 2)
+ {
+ r.x = 0;
+ r.y = 0;
+ r.width = w->width;
+ r.height = w->height;
+
+ rects = &r;
+ n = 1;
+ }
+ else
+ {
+ rects = shapeRects;
+ }
+
+ rect.rects = &rect.extents;
+ rect.numRects = rect.size = 1;
+
+ for (i = 0; i < n; i++)
+ {
+ rect.extents.x1 = rects[i].x + w->attrib.x;
+ rect.extents.y1 = rects[i].y + w->attrib.y;
+ rect.extents.x2 = rect.extents.x1 + rects[i].width;
+ rect.extents.y2 = rect.extents.y1 + rects[i].height;
+
+ XUnionRegion (&rect, w->region, w->region);
+ }
+
+ if (shapeRects)
+ XFree (shapeRects);
+}
+
+void
+addWindow (CompScreen *screen,
+ Window id,
+ Window aboveId)
+{
+ CompWindow *w;
+
+ w = (CompWindow *) malloc (sizeof (CompWindow));
+ if (!w)
+ return;
+
+ w->next = NULL;
+ w->prev = NULL;
+
+ w->screen = screen;
+ w->texture.name = 0;
+ w->pixmap = None;
+ w->destroyed = FALSE;
+
+ if (screen->windowPrivateLen)
+ {
+ w->privates = malloc (screen->windowPrivateLen * sizeof (CompPrivate));
+ if (!w->privates)
+ {
+ free (w);
+ return;
+ }
+ }
+ else
+ w->privates = 0;
+
+ w->region = XCreateRegion ();
+ if (!w->region)
+ {
+ freeWindow (w);
+ return;
+ }
+
+ w->clip = XCreateRegion ();
+ if (!w->clip)
+ {
+ freeWindow (w);
+ return;
+ }
+
+ if (!XGetWindowAttributes (screen->display->display, id, &w->attrib))
+ {
+ freeWindow (w);
+ return;
+ }
+
+ XSelectInput (screen->display->display, id, PropertyChangeMask);
+
+ w->id = id;
+ w->client = clientWindow (screen->display, id);
+ w->alpha = (w->attrib.depth == 32);
+ w->opacity = OPAQUE;
+ w->type = getWindowType (screen->display, w->client);
+
+ w->width = w->attrib.width + w->attrib.border_width * 2;
+ w->height = w->attrib.height + w->attrib.border_width * 2;
+
+ if (screen->display->shapeExtension)
+ XShapeSelectInput (screen->display->display, id, ShapeNotifyMask);
+
+ updateWindowRegion (w);
+
+ insertWindowIntoScreen (screen, w, aboveId);
+
+ if (w->attrib.class != InputOnly)
+ {
+ initTexture (screen, &w->texture);
+
+ w->damage = XDamageCreate (screen->display->display, id,
+ XDamageReportRawRectangles);
+ }
+ else
+ {
+ w->damage = None;
+ w->attrib.map_state = IsUnmapped;
+ }
+
+ if (testMode)
+ {
+ w->attrib.map_state = IsViewable;
+ bindWindow (w);
+ }
+
+ w->invisible = WINDOW_INVISIBLE (w);
+
+ if (w->type == w->screen->display->winDesktopAtom)
+ w->screen->desktopWindowCount++;
+
+ windowInitPlugins (w);
+
+ addWindowDamage (w);
+}
+
+void
+removeWindow (CompWindow *w)
+{
+ if (w->attrib.map_state == IsViewable)
+ {
+ if (w->type == w->screen->display->winDesktopAtom)
+ w->screen->desktopWindowCount++;
+ }
+
+ unhookWindowFromScreen (w->screen, w);
+ windowFiniPlugins (w);
+ freeWindow (w);
+}
+
+void
+destroyWindow (CompWindow *w)
+{
+ if (!w->destroyed)
+ {
+ w->destroyed = TRUE;
+ w->screen->pendingDestroys++;
+ }
+}
+
+void
+mapWindow (CompWindow *w)
+{
+ if (w->attrib.class == InputOnly)
+ return;
+
+ if (w->attrib.map_state == IsViewable)
+ return;
+
+ if (w->type == w->screen->display->winDesktopAtom)
+ w->screen->desktopWindowCount++;
+
+ w->attrib.map_state = IsViewable;
+ w->invisible = WINDOW_INVISIBLE (w);
+
+ addWindowDamage (w);
+}
+
+void
+unmapWindow (CompWindow *w)
+{
+ if (w->attrib.map_state != IsViewable)
+ return;
+
+ if (w->type == w->screen->display->winDesktopAtom)
+ w->screen->desktopWindowCount--;
+
+ addWindowDamage (w);
+
+ w->attrib.map_state = IsUnmapped;
+ w->invisible = WINDOW_INVISIBLE (w);
+
+ releaseWindow (w);
+}
+
+static int
+restackWindow (CompWindow *w,
+ Window aboveId)
+{
+ if (w->prev)
+ {
+ if (aboveId == w->prev->id)
+ return 0;
+ }
+ else if (aboveId == None)
+ return 0;
+
+ unhookWindowFromScreen (w->screen, w);
+ insertWindowIntoScreen (w->screen, w, aboveId);
+
+ return 1;
+}
+
+void
+configureWindow (CompWindow *w,
+ XConfigureEvent *ce)
+{
+ Bool damage;
+
+ if (w->attrib.width != ce->width ||
+ w->attrib.height != ce->height ||
+ w->attrib.border_width != ce->border_width)
+ {
+ addWindowDamage (w);
+
+ w->attrib.x = ce->x;
+ w->attrib.y = ce->y;
+ w->attrib.width = ce->width;
+ w->attrib.height = ce->height;
+ w->attrib.border_width = ce->border_width;
+
+ w->width = w->attrib.width + w->attrib.border_width * 2;
+ w->height = w->attrib.height + w->attrib.border_width * 2;
+
+ releaseWindow (w);
+
+ EMPTY_REGION (w->region);
+
+ damage = TRUE;
+ }
+ else if (w->attrib.x != ce->x || w->attrib.y != ce->y)
+ {
+ addWindowDamage (w);
+
+ XOffsetRegion (w->region, ce->x - w->attrib.x, ce->y - w->attrib.y);
+
+ w->attrib.x = ce->x;
+ w->attrib.y = ce->y;
+
+ damage = TRUE;
+ }
+ else
+ damage = FALSE;
+
+ w->attrib.override_redirect = ce->override_redirect;
+
+ w->invisible = WINDOW_INVISIBLE (w);
+
+ if (restackWindow (w, ce->above) || damage)
+ {
+ if (!REGION_NOT_EMPTY (w->region))
+ updateWindowRegion (w);
+
+ addWindowDamage (w);
+ }
+}
+
+void
+circulateWindow (CompWindow *w,
+ XCirculateEvent *ce)
+{
+ Window newAboveId;
+
+ if (ce->place == PlaceOnTop && w->screen->windows)
+ newAboveId = w->screen->windows->id;
+ else
+ newAboveId = 0;
+
+ if (restackWindow (w, newAboveId))
+ addWindowDamage (w);
+}
+
+void
+invisibleWindowMove (CompWindow *w,
+ int dx,
+ int dy)
+{
+ w->attrib.x += dx;
+ w->attrib.y += dy;
+
+ XOffsetRegion (w->region, dx, dy);
+}