summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Spilsbury <Sam@XPS-SUSE.site>2008-11-01 13:32:36 +0900
committerSam Spilsbury <Sam@XPS-SUSE.site>2008-11-01 13:32:36 +0900
commit2ca917365fc13de029561c00b316503bfd8b434f (patch)
tree2102ff137c4e0a2962134a9ce173cd0ab39def0e
parent7df5326d0f2d13e78fa1333bdc2d06a3735208fa (diff)
downloadcompiz-mpx-ir-2ca917365fc13de029561c00b316503bfd8b434f.tar.gz
compiz-mpx-ir-2ca917365fc13de029561c00b316503bfd8b434f.tar.bz2
Add Compiz-Fusion and Unofficial plugins Input Redirection and MPX Patches
-rw-r--r--fusion/plugins/dodge/0001--MPX-Inclusion.patch397
-rw-r--r--fusion/plugins/expo/0001-MPX-Inclusion.patch732
-rw-r--r--fusion/plugins/ezoom/0001-MPX-Support.patch884
-rw-r--r--fusion/plugins/firepaint/0001-MPX-Support.patch260
-rw-r--r--fusion/plugins/freewins/0001-MPX-Support.patch1179
-rw-r--r--fusion/plugins/freewins/0002-Input-Redirection-Support.patch164
-rw-r--r--fusion/plugins/ghost/0001--MPX-Inclusion.patch85
-rw-r--r--fusion/plugins/group/0001-MPX-Support.patch1533
-rw-r--r--fusion/plugins/mag/0001-MPX-Inclusion.patch1373
-rw-r--r--fusion/plugins/mousepoll/0001--MPX-Inclusion.patch362
-rw-r--r--fusion/plugins/mousetrails/0001-MPX-Support.patch571
-rwxr-xr-xfusion/plugins/newton/Makefile463
-rw-r--r--fusion/plugins/newton/Makefile~463
-rw-r--r--fusion/plugins/newton/build/.libs/chipmunk.obin0 -> 5596 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/cpArbiter.obin0 -> 18156 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/cpArray.obin0 -> 6480 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/cpBB.obin0 -> 4600 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/cpBody.obin0 -> 12792 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/cpCollision.obin0 -> 21028 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/cpHashSet.obin0 -> 10060 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/cpJoint.obin0 -> 30132 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/cpPolyShape.obin0 -> 12384 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/cpShape.obin0 -> 15524 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/cpSpace.obin0 -> 29040 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/cpSpaceHash.obin0 -> 19744 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/cpVect.obin0 -> 5852 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/libnewton.abin0 -> 360088 bytes
l---------fusion/plugins/newton/build/.libs/libnewton.la1
-rw-r--r--fusion/plugins/newton/build/.libs/libnewton.lai35
l---------fusion/plugins/newton/build/.libs/libnewton.so1
l---------fusion/plugins/newton/build/.libs/libnewton.so.01
-rwxr-xr-xfusion/plugins/newton/build/.libs/libnewton.so.0.0.0bin0 -> 272699 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/newton.obin0 -> 93616 bytes
-rw-r--r--fusion/plugins/newton/build/.libs/newton_options.obin0 -> 83616 bytes
-rw-r--r--fusion/plugins/newton/build/chipmunk.lo12
-rw-r--r--fusion/plugins/newton/build/chipmunk.obin0 -> 5256 bytes
-rw-r--r--fusion/plugins/newton/build/compiz-newton.schema148
-rw-r--r--fusion/plugins/newton/build/cpArbiter.lo12
-rw-r--r--fusion/plugins/newton/build/cpArbiter.obin0 -> 17544 bytes
-rw-r--r--fusion/plugins/newton/build/cpArray.lo12
-rw-r--r--fusion/plugins/newton/build/cpArray.obin0 -> 5988 bytes
-rw-r--r--fusion/plugins/newton/build/cpBB.lo12
-rw-r--r--fusion/plugins/newton/build/cpBB.obin0 -> 4332 bytes
-rw-r--r--fusion/plugins/newton/build/cpBody.lo12
-rw-r--r--fusion/plugins/newton/build/cpBody.obin0 -> 11988 bytes
-rw-r--r--fusion/plugins/newton/build/cpCollision.lo12
-rw-r--r--fusion/plugins/newton/build/cpCollision.obin0 -> 20344 bytes
-rw-r--r--fusion/plugins/newton/build/cpHashSet.lo12
-rw-r--r--fusion/plugins/newton/build/cpHashSet.obin0 -> 9456 bytes
-rw-r--r--fusion/plugins/newton/build/cpJoint.lo12
-rw-r--r--fusion/plugins/newton/build/cpJoint.obin0 -> 29120 bytes
-rw-r--r--fusion/plugins/newton/build/cpPolyShape.lo12
-rw-r--r--fusion/plugins/newton/build/cpPolyShape.obin0 -> 11884 bytes
-rw-r--r--fusion/plugins/newton/build/cpShape.lo12
-rw-r--r--fusion/plugins/newton/build/cpShape.obin0 -> 14604 bytes
-rw-r--r--fusion/plugins/newton/build/cpSpace.lo12
-rw-r--r--fusion/plugins/newton/build/cpSpace.obin0 -> 27312 bytes
-rw-r--r--fusion/plugins/newton/build/cpSpaceHash.lo12
-rw-r--r--fusion/plugins/newton/build/cpSpaceHash.obin0 -> 18868 bytes
-rw-r--r--fusion/plugins/newton/build/cpVect.lo12
-rw-r--r--fusion/plugins/newton/build/cpVect.obin0 -> 5424 bytes
-rw-r--r--fusion/plugins/newton/build/libnewton.la35
-rw-r--r--fusion/plugins/newton/build/newton.lo12
-rw-r--r--fusion/plugins/newton/build/newton.obin0 -> 91808 bytes
-rw-r--r--fusion/plugins/newton/build/newton.xml95
-rw-r--r--fusion/plugins/newton/build/newton_options.c635
-rw-r--r--fusion/plugins/newton/build/newton_options.h145
-rw-r--r--fusion/plugins/newton/build/newton_options.lo12
-rw-r--r--fusion/plugins/newton/build/newton_options.obin0 -> 80740 bytes
-rw-r--r--fusion/plugins/newton/chipmunk.c69
-rw-r--r--fusion/plugins/newton/chipmunk.h90
-rw-r--r--fusion/plugins/newton/cpArbiter.c263
-rw-r--r--fusion/plugins/newton/cpArbiter.h85
-rw-r--r--fusion/plugins/newton/cpArray.c114
-rw-r--r--fusion/plugins/newton/cpArray.h45
-rw-r--r--fusion/plugins/newton/cpBB.c46
-rw-r--r--fusion/plugins/newton/cpBB.h53
-rw-r--r--fusion/plugins/newton/cpBody.c180
-rw-r--r--fusion/plugins/newton/cpBody.h110
-rw-r--r--fusion/plugins/newton/cpCollision.c372
-rw-r--r--fusion/plugins/newton/cpCollision.h23
-rw-r--r--fusion/plugins/newton/cpHashSet.c219
-rw-r--r--fusion/plugins/newton/cpHashSet.h79
-rw-r--r--fusion/plugins/newton/cpJoint.c553
-rw-r--r--fusion/plugins/newton/cpJoint.h122
-rw-r--r--fusion/plugins/newton/cpPolyShape.c139
-rw-r--r--fusion/plugins/newton/cpPolyShape.h76
-rw-r--r--fusion/plugins/newton/cpShape.c244
-rw-r--r--fusion/plugins/newton/cpShape.h133
-rw-r--r--fusion/plugins/newton/cpSpace.c530
-rw-r--r--fusion/plugins/newton/cpSpace.h113
-rw-r--r--fusion/plugins/newton/cpSpaceHash.c455
-rw-r--r--fusion/plugins/newton/cpSpaceHash.h100
-rw-r--r--fusion/plugins/newton/cpVect.c63
-rw-r--r--fusion/plugins/newton/cpVect.h106
-rw-r--r--fusion/plugins/newton/needsdif0
-rwxr-xr-xfusion/plugins/newton/newton.c1325
-rw-r--r--fusion/plugins/newton/newton.c~1326
-rwxr-xr-xfusion/plugins/newton/newton.xml.in95
-rwxr-xr-xfusion/plugins/newton/plugin.info2
-rw-r--r--fusion/plugins/newton/prime.h68
-rwxr-xr-xfusion/plugins/newton/setupbuild7
-rw-r--r--fusion/plugins/ring/0001-X-Input-2-Support.patch456
-rw-r--r--fusion/plugins/ring/0002-Add-Input-Redirection-Support.patch111
-rw-r--r--fusion/plugins/scaleaddon/0001-MPX-Support.patch254
-rw-r--r--fusion/plugins/shelf/0001-Input-Redirection-Support.patch109
-rw-r--r--fusion/plugins/shift/0001-Input-Redirection-Support.patch164
-rw-r--r--fusion/plugins/showmouse/0001-MPX-Inclusion.patch518
-rw-r--r--fusion/plugins/thumbnail/0001--MPX-Inclusion.patch1313
-rw-r--r--fusion/plugins/wizard/CMakeLists.txt3
-rw-r--r--fusion/plugins/wizard/Makefile533
-rw-r--r--fusion/plugins/wizard/plugin.info3
-rwxr-xr-xfusion/plugins/wizard/setupbuild7
-rw-r--r--fusion/plugins/wizard/wizard.c1568
-rw-r--r--fusion/plugins/wizard/wizard.xml.in855
-rw-r--r--fusion/plugins/wizard/wizard_tex.h2825
116 files changed, 25666 insertions, 0 deletions
diff --git a/fusion/plugins/dodge/0001--MPX-Inclusion.patch b/fusion/plugins/dodge/0001--MPX-Inclusion.patch
new file mode 100644
index 0000000..74d5841
--- /dev/null
+++ b/fusion/plugins/dodge/0001--MPX-Inclusion.patch
@@ -0,0 +1,397 @@
+From 02bd32794014787ccc1db968dcabbbad1d798b5b Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Wed, 29 Oct 2008 15:23:50 +0900
+Subject: [PATCH] * MPX Inclusion
+
+---
+ dodge.c | 265 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
+ 1 files changed, 221 insertions(+), 44 deletions(-)
+
+diff --git a/dodge.c b/dodge.c
+index 5bc3e9a..96a76a5 100644
+--- a/dodge.c
++++ b/dodge.c
+@@ -60,6 +60,15 @@ typedef struct _DodgeWindow
+ Bool isdodge;
+ } DodgeWindow;
+
++typedef struct _DodgeDevice
++{
++ CompDevice *dev;
++ int px;
++ int py;
++ struct _DodgeDevice *next;
++
++} DodgeDevice;
++
+ typedef struct _DodgeScreen
+ {
+ PaintOutputProc paintOutput;
+@@ -74,8 +83,7 @@ typedef struct _DodgeScreen
+ int windowPrivateIndex;
+ CompWindow *window;
+
+- int px;
+- int py;
++ DodgeDevice *devices;
+
+ int model;
+ int padding;
+@@ -88,7 +96,6 @@ typedef struct _DodgeScreen
+
+ } DodgeScreen;
+
+-
+ #define GET_DODGE_DISPLAY(d) \
+ ((DodgeDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
+
+@@ -124,10 +131,180 @@ typedef struct _DodgeScreen
+ #define WIN_H(w) ((w)->height + (w)->input.top + (w)->input.bottom)
+
+ #define WIN_CX(w) (WIN_X(w) + WIN_W(w)/2)
+-#define WIN_CY(w) (WIN_Y(w) + WIN_H(w)/2)
++#define WIN_CY(w) (WIN_Y(w) + WIN_H(w)/2)
++
++/* Device management */
++
++static Bool
++dodgeAddDevToList (CompScreen *s,
++ CompDevice *dev)
++{
++ DODGE_SCREEN (s);
++
++ DodgeDevice *run;
++
++ if (!ds->devices)
++ {
++ ds->devices = calloc (1, sizeof(DodgeDevice));
++ if (!ds->devices)
++ return FALSE;
++ ds->devices->dev = dev;
++ ds->devices->next = NULL;
++ }
++ else
++ {
++ for (run = ds->devices; run->next; run = run->next);
++
++ run->next = calloc (1, sizeof(DodgeDevice));
++ if (!run->next)
++ return FALSE;
++ run->next->dev = dev;
++ run->next->next = NULL;
++ }
++ return TRUE;
++}
++
++static void
++dodgeRemoveDevFromList (CompScreen *s,
++ CompDevice *dev)
++{
++ DODGE_SCREEN (s);
++
++ DodgeDevice *run = NULL;
++
++ if (!ds->devices)
++ return;
++
++ for (run = ds->devices; run; run = run->next)
++ if (run->dev == dev)
++ break;
++
++ if (run == ds->devices)
++ {
++ if (ds->devices->next)
++ ds->devices = ds->devices->next;
++ else
++ ds->devices = NULL;
++
++ if (run)
++ free (run);
++ }
++ else
++ {
++ for (run = ds->devices; run; run = run->next)
++ {
++ if (run->dev == dev)
++ break;
++ }
++
++ DodgeDevice *selected = run;
++
++ if (selected)
++ if (selected->next)
++ {
++ run = selected->next;
++ if (selected)
++ free(selected);
++ }
++ }
++}
++
++static void
++dodgeCheckList (CompScreen *s,
++ MousepollDevice *list)
++{
++ DODGE_SCREEN (s);
++ Bool ok = FALSE;
++ MousepollDevice *run;
++ DodgeDevice *ptr;
++ CompDevice *addDev = NULL, *removeDev = NULL;
++
++ do
++ {
++ for (run = list; run; run = run->next)
++ {
++ addDev = run->dev;
++ for (ptr = ds->devices; ptr; ptr = ptr->next)
++ {
++ if (ptr->dev == run->dev)
++ {
++ addDev = NULL;
++ break;
++ }
++ }
++ if (addDev) break;
++ }
++
++ for (ptr = ds->devices; ptr; ptr = ptr->next)
++ {
++ removeDev = ptr->dev;
++ for (run = list; run; run = run->next)
++ {
++ if (run->dev == ptr->dev)
++ {
++ removeDev = NULL;
++ break;
++ }
++ }
++ if (removeDev) break;
++ }
++
++ if (addDev)
++ dodgeAddDevToList (s, addDev);
++
++ if (removeDev)
++ dodgeRemoveDevFromList (s, removeDev);
++
++ if (addDev || removeDev)
++ ok = FALSE;
++ else
++ ok = TRUE;
++ } while (!ok);
++}
++
++
++static void
++positionUpdate (CompScreen *s, MousepollDevice *mDev)
++{
++ DODGE_SCREEN (s);
++ MousepollDevice *run;
++ DodgeDevice *dev;
++
++ dodgeCheckList (s, mDev);
++
++ if (ds->active)
++ {
++ for (run = mDev; run; run = run->next)
++ {
++ for (dev = ds->devices; dev; dev = dev->next)
++ {
++ if (dev->dev == run->dev)
++ {
++ dev->px = run->posX;
++ dev->py = run->posY;
++
++ /* damage a small area around the mouse to prevent jerkiness */
++
++ REGION r;
++
++ r.rects = &r.extents;
++ r.numRects = r.size = 1;
++ r.extents.x1 = dev->px - PADDING;
++ r.extents.x2 = dev->px + PADDING;
++ r.extents.y1 = dev->py - PADDING;
++ r.extents.y2 = dev->py + PADDING;
++
++ damageScreenRegion(s, &r);
++
++ }
++ }
++ }
++ }
++
++}
+
+ static int
+-dodgestep (CompWindow *w, int ms, int away)
++dodgestep (CompWindow *w, int ms, int away, int px, int py)
+ {
+ DODGE_WINDOW (w);
+ DODGE_SCREEN (w->screen);
+@@ -138,8 +315,8 @@ dodgestep (CompWindow *w, int ms, int away)
+ {
+ case ModelSimpleAvoid:
+ /* increase velocity away from the pointer */
+- dx = WIN_CX(w) - ds->px;
+- dy = WIN_CY(w) - ds->py;
++ dx = WIN_CX(w) - px;
++ dy = WIN_CY(w) - py;
+
+ dp = sqrt(dx*dx + dy*dy);
+ if(WIN_W(w)/2 + PADDING - abs(dx) >
+@@ -157,15 +334,15 @@ dodgestep (CompWindow *w, int ms, int away)
+ }
+ break;
+ case ModelReturnToPosition:
+- if ((ds->px > dw->ox - WIN_W(w)/2 - PADDING &&
+- ds->py > dw->oy - WIN_H(w)/2 - PADDING &&
+- ds->px < dw->ox + WIN_W(w)/2 + PADDING &&
+- ds->py < dw->oy + WIN_H(w)/2 + PADDING) &&
++ if ((px > dw->ox - WIN_W(w)/2 - PADDING &&
++ py > dw->oy - WIN_H(w)/2 - PADDING &&
++ px < dw->ox + WIN_W(w)/2 + PADDING &&
++ py < dw->oy + WIN_H(w)/2 + PADDING) &&
+ !ds->exiting && away)
+ {
+ /* increase velocity away from / toward the pointer */
+- dx = WIN_CX(w) - ds->px;
+- dy = WIN_CY(w) - ds->py;
++ dx = WIN_CX(w) - px;
++ dy = WIN_CY(w) - py;
+
+ dp = sqrt(dx*dx + dy*dy);
+ if(WIN_W(w)/2 + PADDING - abs(dx) >
+@@ -195,10 +372,10 @@ dodgestep (CompWindow *w, int ms, int away)
+ }
+ break;
+ case ModelOffScreen:
+- if ((ds->px > dw->ox - WIN_W(w)/2 - PADDING &&
+- ds->py > dw->oy - WIN_H(w)/2 - PADDING &&
+- ds->px < dw->ox + WIN_W(w)/2 + PADDING &&
+- ds->py < dw->oy + WIN_H(w)/2 + PADDING) &&
++ if ((px > dw->ox - WIN_W(w)/2 - PADDING &&
++ py > dw->oy - WIN_H(w)/2 - PADDING &&
++ px < dw->ox + WIN_W(w)/2 + PADDING &&
++ py < dw->oy + WIN_H(w)/2 + PADDING) &&
+ !ds->exiting && away)
+ {
+ switch (dw->pos)
+@@ -280,6 +457,7 @@ dodgePreparePaintScreen (CompScreen *s,
+ int ms)
+ {
+ DODGE_SCREEN (s);
++ DODGE_DISPLAY (s->display);
+ CompWindow *w;
+ /* if another plugin has grabbed the screen we don't want to interfere
+ * except for expo or rotate cube, in which case windows return to their original
+@@ -294,15 +472,21 @@ dodgePreparePaintScreen (CompScreen *s,
+
+ if (ds->active)
+ {
++ if (!ds->pollHandle)
++ ds->pollHandle = (*dd->mpFunc->addPositionPolling) (s, NULL, positionUpdate);
+ ds->movelock = TRUE;
+ ds->moreAdjust = FALSE;
+ for (w = s->windows; w; w = w->next)
+ {
+ DODGE_WINDOW (w);
+ if (dw->isdodge)
++ {
++ DodgeDevice *dev;
++ for (dev = ds->devices; dev; dev = dev->next)
+ dodgestep(w,ms,!otherScreenGrabExist(s,"dodge",0)
+ && (w->screen->display->activeWindow != w->id
+- || dodgeGetDodgeActive (s->display)));
++ || dodgeGetDodgeActive (s->display)), dev->px, dev->py);
++ }
+ }
+ ds->movelock = FALSE;
+ }
+@@ -322,10 +506,22 @@ static void
+ dodgeDonePaintScreen (CompScreen *s)
+ {
+ DODGE_SCREEN(s);
++ DODGE_DISPLAY (s->display);
+ if (ds->active && ds->moreAdjust)
+ {
+ damageScreen(s);
+ }
++
++ if (!ds->active && ds->pollHandle)
++ {
++ (*dd->mpFunc->removePositionPolling) (s, ds->pollHandle);
++ DodgeDevice *dev;
++ for (dev = ds->devices; dev; dev = dev->next)
++ dodgeRemoveDevFromList (s, dev->dev);
++
++ ds->devices = NULL;
++ ds->pollHandle = 0;
++ }
+ UNWRAP (ds, s, donePaintScreen);
+ (*s->donePaintScreen) (s);
+ WRAP (ds, s, donePaintScreen, dodgeDonePaintScreen);
+@@ -481,29 +677,6 @@ dodgeWindowResizeNotify (CompWindow *w,
+ }
+
+ static void
+-positionUpdate (CompScreen *s, int x, int y)
+-{
+- DODGE_SCREEN (s);
+- ds->px = x;
+- ds->py = y;
+- if (ds->active)
+- {
+- /* damage a small area around the mouse to prevent jerkiness */
+- REGION r;
+-
+- r.rects = &r.extents;
+- r.numRects = r.size = 1;
+- r.extents.x1 = ds->px - PADDING;
+- r.extents.x2 = ds->px + PADDING;
+- r.extents.y1 = ds->py - PADDING;
+- r.extents.y2 = ds->py + PADDING;
+-
+- damageScreenRegion(s,&r);
+- }
+-
+-}
+-
+-static void
+ dodgeStateChange (CompWindow *w,
+ unsigned int last)
+ {
+@@ -646,7 +819,10 @@ dodgeInitScreen (CompPlugin *p,
+
+ ds->active = FALSE;
+ ds->exiting = FALSE;
++ ds->movelock = FALSE;
+ ds->moreAdjust = FALSE;
++ ds->devices = NULL;
++ ds->pollHandle = 0;
+
+ WRAP (ds, s, preparePaintScreen, dodgePreparePaintScreen);
+ WRAP (ds, s, windowStateChangeNotify, dodgeStateChange);
+@@ -656,9 +832,7 @@ dodgeInitScreen (CompPlugin *p,
+
+ ds->windowPrivateIndex = allocateWindowPrivateIndex (s);
+ s->base.privates[dd->screenPrivateIndex].ptr = ds;
+-
+- (*dd->mpFunc->getCurrentPosition) (s, &ds->px, &ds->py);
+- ds->pollHandle = (*dd->mpFunc->addPositionPolling) (s, positionUpdate);
++
+ return TRUE;
+ }
+
+@@ -675,6 +849,9 @@ dodgeFiniScreen (CompPlugin *p,
+ UNWRAP (ds, s, donePaintScreen);
+
+ (*dd->mpFunc->removePositionPolling) (s, ds->pollHandle);
++ DodgeDevice *dev;
++ for (dev = ds->devices; dev; dev = dev->next)
++ dodgeRemoveDevFromList (s, dev->dev);
+ free (ds);
+ }
+
+--
+1.5.6
+
diff --git a/fusion/plugins/expo/0001-MPX-Inclusion.patch b/fusion/plugins/expo/0001-MPX-Inclusion.patch
new file mode 100644
index 0000000..bdca88d
--- /dev/null
+++ b/fusion/plugins/expo/0001-MPX-Inclusion.patch
@@ -0,0 +1,732 @@
+From 256f7a71cea755d9d48a8f2652d2e15e19ad6766 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Wed, 29 Oct 2008 15:22:46 +0900
+Subject: [PATCH] * MPX Inclusion
+
+---
+ expo.c | 478 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
+ 1 files changed, 414 insertions(+), 64 deletions(-)
+
+diff --git a/expo.c b/expo.c
+index 46fa27b..5f9f201 100644
+--- a/expo.c
++++ b/expo.c
+@@ -57,6 +57,18 @@ typedef enum
+ VPUpdatePrevious
+ } VPUpdateMode;
+
++typedef struct _ExpoDevice
++{
++ CompDevice *dev;
++ int grabIndex;
++ DnDState dndState;
++ CompWindow *dndWindow;
++ int prevCursorX, prevCursorY;
++ int newCursorX, newCursorY;
++ struct _ExpoDevice *next;
++} ExpoDevice;
++
++
+ typedef struct _ExpoDisplay
+ {
+ int screenPrivateIndex;
+@@ -94,6 +106,8 @@ typedef struct _ExpoScreen
+ /* Window being dragged in expo mode */
+ DnDState dndState;
+ CompWindow *dndWindow;
++
++ ExpoDevice *devices;
+
+ int prevCursorX, prevCursorY;
+ int newCursorX, newCursorY;
+@@ -128,6 +142,8 @@ typedef struct _ExpoScreen
+ GLfloat *winNormals;
+ unsigned int winNormSize;
+
++ CompTransform lastTransform;
++
+ } ExpoScreen;
+
+ typedef struct _xyz_tuple
+@@ -232,18 +248,28 @@ expoDnDInit (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
+ Window xid;
++ int deviceid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+ s = findScreenAtDisplay (d, xid);
+
+- if (s)
++ deviceid = getIntOptionNamed (option, nOption, "device", -1);
++ dev = compFindDeviceById (d, deviceid);
++
++ if (s && dev)
+ {
++ ExpoDevice *eDev;
+ EXPO_SCREEN (s);
+
++ for (eDev = es->devices; eDev; eDev = eDev->next)
++ if (eDev->dev == dev)
++ break;
++
+ if (es->expoMode)
+ {
+- es->dndState = DnDStart;
++ eDev->dndState = DnDStart;
+ action->state |= CompActionStateTermButton;
+ damageScreen(s);
+ }
+@@ -264,9 +290,19 @@ expoDnDFini (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
++ ExpoDevice *eDev;
+ Window xid;
++ int deviceid;
++ Bool terminate = TRUE;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
++ deviceid = getIntOptionNamed (option, nOption, "device", -1);
++
++ dev = compFindDeviceById (d, deviceid);
++
++ if (!dev)
++ return FALSE;
+
+ for (s = d->screens; s; s = s->next)
+ {
+@@ -275,23 +311,196 @@ expoDnDFini (CompDisplay *d,
+ if (xid && (s->root != xid))
+ continue;
+
+- if (es->dndState == DnDDuring || es->dndState == DnDStart)
++ for (eDev = es->devices; eDev; eDev = eDev->next)
+ {
+- if (es->dndWindow)
+- expoFinishWindowMovement (es->dndWindow);
++ if (eDev->dev == dev)
++ {
++ if (eDev->dndState == DnDDuring || eDev->dndState == DnDStart)
++ {
++ if (eDev->dndWindow)
++ expoFinishWindowMovement (eDev->dndWindow);
+
+- es->dndState = DnDNone;
+- es->dndWindow = NULL;
+- action->state &= ~CompActionStateTermButton;
+- damageScreen (s);
++ eDev->dndState = DnDNone;
++ eDev->dndWindow = NULL;
++ damageScreen (s);
+
+- return TRUE;
++ break;
++ }
++ }
+ }
++
++ for (eDev = es->devices; eDev; eDev = eDev->next)
++ if (eDev->dndState != DnDNone)
++ terminate = FALSE;
++
++ if (terminate)
++ action->state &= ~CompActionStateTermButton;
++
++ return TRUE;
+ }
+
+ return FALSE;
+ }
+
++/* Device Management */
++
++static Bool
++expoGrabDevice (CompScreen *s,
++ ExpoDevice *eDev)
++{
++ if (!eDev->grabIndex)
++ {
++ eDev->grabIndex = pushDeviceGrab (s, eDev->dev, None, "expo");
++ }
++ if (eDev->grabIndex)
++ return TRUE;
++ return FALSE;
++}
++
++static Bool
++expoAddDeviceToList (CompScreen *s,
++ CompDevice *dev)
++{
++ EXPO_SCREEN (s);
++
++ if (!es->devices)
++ {
++ es->devices = calloc (1, sizeof(ExpoDevice));
++ if (!es->devices)
++ return FALSE;
++ es->devices->dev = dev;
++ es->devices->grabIndex = 0;
++ es->devices->dndWindow = NULL;
++ es->devices->dndState = DnDNone;
++ es->devices->next = NULL;
++ }
++ else
++ {
++ ExpoDevice *run;
++ for (run = es->devices; run->next; run = run->next); /* Last device in list */
++
++ run->next = calloc (1, sizeof(ExpoDevice));
++ if (!run->next)
++ return FALSE;
++ run->next->dev = dev;
++ run->next->grabIndex = 0;
++ run->next->dndWindow = NULL;
++ run->next->dndState = DnDNone;
++ run->next->next = NULL;
++ }
++
++ return TRUE;
++
++}
++
++static Bool
++expoRemoveDeviceFromList (CompScreen *s,
++ ExpoDevice *dev)
++{
++ EXPO_SCREEN (s);
++ ExpoDevice *run;
++
++ if (!es->devices)
++ return FALSE;
++
++
++ if (dev == es->devices)
++ {
++ if (es->devices->next)
++ es->devices = es->devices->next;
++
++ if (dev)
++ free (dev);
++ }
++ else
++ {
++ for (run = es->devices; run; run = run->next)
++ {
++ if (run == dev)
++ {
++ if (run->next)
++ run = run->next;
++ else
++ run = NULL;
++
++ if (dev)
++ free (dev);
++ }
++ }
++ }
++
++ return TRUE;
++}
++
++static void
++expoCheckList (CompScreen *s)
++{
++ EXPO_SCREEN (s);
++ CompDevice *addDev, *ptr;
++ ExpoDevice *removeDev, *run;
++ Bool ok;
++
++ do
++ {
++ addDev = NULL;
++ removeDev = NULL;
++
++ for (ptr = s->display->devices; ptr->id != -1; ptr++)
++ {
++
++ if (ptr->use != IsXPointer)
++ continue;
++
++ if (!es->devices)
++ addDev = ptr;
++ else
++ for (run = es->devices; run; run = run->next)
++ {
++ addDev = ptr;
++ if (run->dev == ptr)
++ {
++ addDev = NULL;
++ break;
++ }
++ }
++ if (addDev)
++ break;
++ }
++ for (run = es->devices; run; run = run->next)
++ {
++ for (ptr = s->display->devices; ptr->id != -1; ptr++)
++ {
++ if (ptr->use != IsXPointer)
++ continue;
++
++ removeDev = run;
++ if (ptr == run->dev)
++ {
++ removeDev = NULL;
++ break;
++ }
++ }
++ if (removeDev)
++ break;
++ }
++
++ if (addDev)
++ expoAddDeviceToList (s, addDev);
++
++ if (removeDev)
++ expoRemoveDeviceFromList (s, removeDev);
++
++ if (!addDev && !removeDev)
++ ok = TRUE;
++ else
++ ok = FALSE;
++
++ } while (!ok);
++
++}
++
++
++
+ static Bool
+ expoTermExpo (CompDisplay *d,
+ CompAction *action,
+@@ -300,6 +509,7 @@ expoTermExpo (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ ExpoDevice *eDev;
+
+ for (s = d->screens; s; s = s->next)
+ {
+@@ -310,22 +520,29 @@ expoTermExpo (CompDisplay *d,
+
+ es->expoMode = FALSE;
+
+- if (es->dndState != DnDNone)
+- expoDnDFini (d, action, state, option, nOption);
+-
+ if (state & CompActionStateCancel)
+ es->vpUpdateMode = VPUpdatePrevious;
+ else
+ es->vpUpdateMode = VPUpdateMouseOver;
+
+- es->dndState = DnDNone;
+- es->dndWindow = 0;
+-
+ removeScreenAction (s, expoGetDndButton (d));
+ removeScreenAction (s, expoGetExitButton (d));
+ removeScreenAction (s, expoGetNextVpButton (d));
+ removeScreenAction (s, expoGetPrevVpButton (d));
+
++ for (eDev = es->devices; eDev; eDev = eDev->next)
++ {
++
++ if (eDev->dndState != DnDNone)
++ expoDnDFini (d, action, state, option, nOption);
++
++ eDev->dndState = DnDNone;
++ eDev->dndWindow = 0;
++
++ removeDeviceGrab (s, eDev->dev, eDev->grabIndex, NULL);
++ eDev->grabIndex = 0;
++ }
++
+ damageScreen (s);
+ focusDefaultWindow (s);
+ }
+@@ -341,6 +558,7 @@ expoExpo (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ ExpoDevice *eDev;
+ Window xid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+@@ -350,13 +568,13 @@ expoExpo (CompDisplay *d,
+ {
+ EXPO_SCREEN (s);
+
+- if (otherScreenGrabExist (s, "expo", 0))
+- return FALSE;
++ /*if (otherScreenGrabExist (s, "expo", 0))
++ return FALSE;*/
+
+ if (!es->expoMode)
+ {
+- if (!es->grabIndex)
+- es->grabIndex = pushScreenGrab (s, None, "expo");
++ /*if (!es->grabIndex)
++ es->grabIndex = pushScreenGrab (s, None, "expo");*/
+
+ es->expoMode = TRUE;
+ es->anyClick = FALSE;
+@@ -369,11 +587,18 @@ expoExpo (CompDisplay *d,
+ es->selectedVX = es->origVX = s->x;
+ es->selectedVY = es->origVY = s->y;
+
++ expoCheckList (s);
++
+ addScreenAction (s, expoGetDndButton (d));
+ addScreenAction (s, expoGetExitButton (d));
+ addScreenAction (s, expoGetNextVpButton (d));
+ addScreenAction (s, expoGetPrevVpButton (d));
+
++ for (eDev = es->devices; eDev; eDev = eDev->next)
++ {
++ expoGrabDevice (s, eDev);
++ }
++
+ damageScreen (s);
+ }
+ else
+@@ -600,6 +825,93 @@ expoHandleEvent (CompDisplay *d,
+ break;
+ }
+
++ if (event->type == d->xi_kpress)
++ {
++ XDeviceKeyEvent *kev = (XDeviceKeyEvent *) event;
++ s = findScreenAtDisplay (d, kev->root);
++
++ if (s)
++ {
++ EXPO_SCREEN (s);
++
++ if (es->expoMode)
++ {
++ if (kev->keycode == ed->leftKey)
++ expoMoveFocusViewport (s, -1, 0);
++ else if (kev->keycode == ed->rightKey)
++ expoMoveFocusViewport (s, 1, 0);
++ else if (kev->keycode == ed->upKey)
++ expoMoveFocusViewport (s, 0, -1);
++ else if (kev->keycode == ed->downKey)
++ expoMoveFocusViewport (s, 0, 1);
++ }
++ }
++ }
++ else if (event->type == d->xi_btpress)
++ {
++ XDeviceButtonEvent *bev = (XDeviceButtonEvent *) event;
++ s = findScreenAtDisplay (d, bev->root);
++
++ if (s)
++ {
++ EXPO_SCREEN (s);
++
++ if (es->expoMode && bev->button == Button1)
++ {
++ es->anyClick = TRUE;
++ if (es->clickTime == 0)
++ {
++ es->clickTime = bev->time;
++ }
++ else if (bev->time - es->clickTime <=
++ expoGetDoubleClickTime (d))
++ {
++ es->doubleClick = TRUE;
++ }
++ else
++ {
++ es->clickTime = bev->time;
++ es->doubleClick = FALSE;
++ }
++ damageScreen(s);
++ }
++ }
++ }
++ else if (event->type == d->xi_btrelease)
++ {
++ XDeviceButtonEvent *bev = (XDeviceButtonEvent *) event;
++ s = findScreenAtDisplay (d, bev->root);
++
++ if (s)
++ {
++ EXPO_SCREEN (s);
++
++ if (es->expoMode)
++ {
++ if (bev->button == Button1)
++ {
++ if (bev->time - es->clickTime >
++ expoGetDoubleClickTime (d))
++ {
++ es->clickTime = 0;
++ es->doubleClick = FALSE;
++ }
++ else if (es->doubleClick)
++ {
++ CompAction *action;
++
++ es->clickTime = 0;
++ es->doubleClick = FALSE;
++
++ action = expoGetExpoKey (d);
++ expoTermExpo (d, action, 0, NULL, 0);
++ es->anyClick = TRUE;
++ }
++ }
++ }
++ }
++ }
++
+ UNWRAP (ed, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (ed, d, handleEvent, expoHandleEvent);
+@@ -1029,28 +1341,34 @@ expoPaintWall (CompScreen *s,
+ DEFAULT_Z_CAMERA - es->curveDistance);
+ }
+
++ es->lastTransform = sTransform3;
++
+ paintTransformedOutput (s, sAttrib, &sTransform3, &s->region,
+ output, mask);
+
+ if (!reflection)
+ {
+- int cursor[2] = { pointerX, pointerY };
+-
+- invertTransformedVertex (s, sAttrib, &sTransform3,
+- output, cursor);
+-
+- if ((cursor[0] > 0) && (cursor[0] < s->width) &&
+- (cursor[1] > 0) && (cursor[1] < s->height))
++ ExpoDevice *eDev;
++ for (eDev = es->devices; eDev; eDev = eDev->next)
+ {
+- es->newCursorX = i * s->width + cursor[0];
+- es->newCursorY = j * s->height + cursor[1];
++ int cursor[2] = { eDev->dev->pointerX, eDev->dev->pointerY };
+
+- if (es->anyClick || es->dndState != DnDNone)
++ invertTransformedVertex (s, sAttrib, &sTransform3,
++ output, cursor);
++
++ if ((cursor[0] > 0) && (cursor[0] < s->width) &&
++ (cursor[1] > 0) && (cursor[1] < s->height))
+ {
+- /* Used to save last viewport interaction was in */
+- es->selectedVX = i;
+- es->selectedVY = j;
+- es->anyClick = FALSE;
++ eDev->newCursorX = i * s->width + cursor[0];
++ eDev->newCursorY = j * s->height + cursor[1];
++
++ if (es->anyClick || eDev->dndState != DnDNone)
++ {
++ /* Used to save last viewport interaction was in */
++ es->selectedVX = i;
++ es->selectedVY = j;
++ es->anyClick = FALSE;
++ }
+ }
+ }
+ }
+@@ -1395,7 +1713,6 @@ expoDrawWindowTexture (CompWindow *w,
+ }
+
+ v = w->vertices + (w->vertexStride - 3);
+-
+ for (i = 0; i < w->vCount; i++)
+ {
+ x = ((float)(v[0] + offX - (s->width / 2)) * es->curveAngle) /
+@@ -1498,6 +1815,7 @@ expoDonePaintScreen (CompScreen * s)
+ EXPO_SCREEN (s);
+
+ int i;
++ ExpoDevice *eDev;
+
+ switch (es->vpUpdateMode) {
+ case VPUpdateMouseOver:
+@@ -1517,7 +1835,7 @@ expoDonePaintScreen (CompScreen * s)
+ break;
+ }
+
+- if ((es->expoCam > 0.0f && es->expoCam < 1.0f) || es->dndState != DnDNone)
++ if ((es->expoCam > 0.0f && es->expoCam < 1.0f))
+ damageScreen (s);
+
+ if (es->expoCam == 1.0f)
+@@ -1525,34 +1843,41 @@ expoDonePaintScreen (CompScreen * s)
+ if (es->vpActivity[i] != 0.0 && es->vpActivity[i] != 1.0)
+ damageScreen (s);
+
+- if (es->grabIndex && es->expoCam <= 0.0f && !es->expoMode)
++ for (eDev = es->devices; eDev; eDev = eDev->next)
++ if (eDev->dndState != DnDNone)
++ damageScreen (s);
++
++ if (es->expoMode)
+ {
+- removeScreenGrab (s, es->grabIndex, 0);
+- es->grabIndex = 0;
++ expoCheckList (s);
++ for (eDev = es->devices; eDev; eDev = eDev->next)
++ expoGrabDevice (s, eDev);
+ }
+
+ UNWRAP (es, s, donePaintScreen);
+ (*s->donePaintScreen) (s);
+ WRAP (es, s, donePaintScreen, expoDonePaintScreen);
+
+- switch (es->dndState) {
+- case DnDDuring:
++ for (eDev = es->devices; eDev; eDev = eDev->next)
++ {
++ switch (eDev->dndState) {
++ case DnDDuring:
+ {
+- int dx = es->newCursorX - es->prevCursorX;
+- int dy = es->newCursorY - es->prevCursorY;
++ int dx = eDev->newCursorX - eDev->prevCursorX;
++ int dy = eDev->newCursorY - eDev->prevCursorY;
+
+- if (es->dndWindow)
+- moveWindow (es->dndWindow, dx, dy, TRUE,
++ if (eDev->dndWindow)
++ moveWindow (eDev->dndWindow, dx, dy, TRUE,
+ expoGetExpoImmediateMove (s->display));
+
+- es->prevCursorX = es->newCursorX;
+- es->prevCursorY = es->newCursorY;
++ eDev->prevCursorX = eDev->newCursorX;
++ eDev->prevCursorY = eDev->newCursorY;
+
+ damageScreen (s);
+ }
+ break;
+
+- case DnDStart:
++ case DnDStart:
+ {
+ CompWindow *w;
+
+@@ -1578,26 +1903,26 @@ expoDonePaintScreen (CompScreen * s)
+ xOffset = s->hsize * s->width;
+ yOffset = s->vsize * s->height;
+
+- nx = es->newCursorX - (s->x * s->width);
+- ny = es->newCursorY - (s->y * s->height);
+-
++ nx = eDev->newCursorX - (s->x * s->width);
++ ny = eDev->newCursorY - (s->y * s->height);
++
+ inWindow = ((nx >= WIN_X (w)) &&
+ (nx <= WIN_X (w) + WIN_W (w))) ||
+- ((nx >= (WIN_X (w) + xOffset)) &&
++ ((nx >= (WIN_X (w) + xOffset)) &&
+ (nx <= (WIN_X (w) + WIN_W (w) +
+ xOffset)));
+
+ inWindow &= ((ny >= WIN_Y (w)) &&
+ (ny <= WIN_Y (w) + WIN_H (w))) ||
+- ((ny >= (WIN_Y (w) + yOffset)) &&
++ ((ny >= (WIN_Y (w) + yOffset)) &&
+ (ny <= (WIN_Y (w) + WIN_H (w) +
+ yOffset)));
+
+ if (!inWindow)
+ continue;
+
+- es->dndState = DnDDuring;
+- es->dndWindow = w;
++ eDev->dndState = DnDDuring;
++ eDev->dndWindow = w;
+
+ (*s->windowGrabNotify) (w, nx, ny, 0,
+ CompWindowGrabMoveMask |
+@@ -1607,24 +1932,47 @@ expoDonePaintScreen (CompScreen * s)
+
+ if (w)
+ {
+- raiseWindow (es->dndWindow);
+- moveInputFocusToWindow (es->dndWindow);
++ raiseWindow (eDev->dndWindow);
++ moveInputFocusToWindow (eDev->dndWindow);
+ }
+ else
+ {
+ /* no window was hovered */
+- es->dndState = DnDNone;
++ eDev->dndState = DnDNone;
+ }
+
+- es->prevCursorX = es->newCursorX;
+- es->prevCursorY = es->newCursorY;
++ eDev->prevCursorX = eDev->newCursorX;
++ eDev->prevCursorY = eDev->newCursorY;
+ }
+ break;
+- default:
+- break;
++ default:
++ break;
++ }
+ }
+ }
+
++/*static void
++expoCreateMesh (CompWindow *w
++ CompMesh *mesh)
++{
++ int i;
++ int nTriangles = mesh->width * mesh->height * 2;
++ int out;
++ CompTransform expoTransform;
++
++ EXPO_SCREEN (s);
++
++ for (i = 0; i < nTriangles; i++)
++ {
++ int point1[2] = { xFixedToInt(mesh->triangles[i].p1.x), xFixedToInt(mesh->triangles[i].p1.y) }
++ int point2[2] = { xFixedToInt(mesh->triangles[i].p2.x), xFixedToInt(mesh->triangles[i].p2.y) }
++ int point3[2] = { xFixedToInt(mesh->triangles[i].p3.x), xFixedToInt(mesh->triangles[i].p3.y) }
++
++ out = outputDeviceForPoint (w->screen, point1[0]. point1[1]);
++
++ invertTransformedVertex (s, &es->lastSAttrib, &es->lastTransform,
++ &s->outputDev[out], point1);*/
++
+ static Bool
+ expoInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+@@ -1717,6 +2065,8 @@ expoInitScreen (CompPlugin *p,
+
+ es->grabIndex = 0;
+
++ es->devices = NULL;
++
+ es->expoActive = FALSE;
+ es->expoCam = 0.0f;
+ es->expoMode = 0;
+@@ -1755,11 +2105,11 @@ expoFiniScreen (CompPlugin *p,
+ {
+ EXPO_SCREEN (s);
+
+- if (es->grabIndex)
++ /*if (es->grabIndex)
+ {
+ removeScreenGrab (s, es->grabIndex, 0);
+ es->grabIndex = 0;
+- }
++ }*/
+
+ XDestroyRegion (es->tmpRegion);
+
+--
+1.5.6
+
diff --git a/fusion/plugins/ezoom/0001-MPX-Support.patch b/fusion/plugins/ezoom/0001-MPX-Support.patch
new file mode 100644
index 0000000..60ab0c2
--- /dev/null
+++ b/fusion/plugins/ezoom/0001-MPX-Support.patch
@@ -0,0 +1,884 @@
+From 6e859e431d39129d605dd6122fba121bf391e13d Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Fri, 31 Oct 2008 15:29:18 +0900
+Subject: [PATCH] MPX Support
+
+---
+ ezoom.c | 494 +++++++++++++++++++++++++++++++++++++++++++++++++++++----------
+ 1 files changed, 415 insertions(+), 79 deletions(-)
+
+diff --git a/ezoom.c b/ezoom.c
+index 90bf4ca..5a85522 100644
+--- a/ezoom.c
++++ b/ezoom.c
+@@ -64,6 +64,10 @@
+ * An other minor annoynance is that mouse sensitivity seems to increase as
+ * you zoom in, since the mouse isn't really zoomed at all.
+ *
++ * 3.
++ * We can redirect input now, so we can pan around the zoom area without having
++ * to draw a scaled cursor.
++ *
+ * Todo:
+ * - Different multihead modes
+ */
+@@ -159,6 +163,18 @@ typedef struct _CursorTexture
+ int hotY;
+ } CursorTexture;
+
++typedef struct _ZoomDevice
++{
++ CompDevice *dev;
++ int mouseX;
++ int mouseY;
++ Box box;
++ int grabIndex;
++ /* FIXME: CursorTexture cursor */
++ struct _ZoomDevice *next;
++} ZoomDevice;
++
++
+ typedef struct _ZoomDisplay {
+ HandleEventProc handleEvent;
+ MousePollFunc *mpFunc;
+@@ -179,6 +195,10 @@ typedef struct _ZoomDisplay {
+ *
+ * currentZoom is actual zoomed value
+ *
++ * maxZoom is what we have zoomed into with the mouse, and when considering
++ * multiple cursors, this is the maximum amount of zoom permitted when the
++ * cursors get closer together.
++ *
+ * real[XY]Translate are the currently used values in the same range as
+ * [xy]Translate, and [xy]trans is adjusted for the zoom level in place.
+ * [xyz]trans should never be modified except in updateActualTranslates()
+@@ -190,6 +210,7 @@ typedef struct _ZoomArea {
+ unsigned long int viewport;
+ GLfloat currentZoom;
+ GLfloat newZoom;
++ GLfloat maxZoom;
+ GLfloat xVelocity;
+ GLfloat yVelocity;
+ GLfloat zVelocity;
+@@ -209,6 +230,8 @@ typedef struct _ZoomScreen {
+ PositionPollingHandle pollHandle;
+ CompOption opt[SOPT_NUM];
+ ZoomArea *zooms;
++ ZoomDevice *devices;
++ Bool moreMice;
+ int nZooms;
+ int mouseX;
+ int mouseY;
+@@ -222,10 +245,10 @@ typedef struct _ZoomScreen {
+ } ZoomScreen;
+
+ static void syncCenterToMouse (CompScreen *s);
+-static void updateMouseInterval (CompScreen *s, int x, int y);
++static void updateMouseInterval (CompScreen *s, MousepollDevice *mDev);
+ static void cursorZoomActive (CompScreen *s);
+ static void cursorZoomInactive (CompScreen *s);
+-static void restrainCursor (CompScreen *s, int out);
++static void restrainCursors (CompScreen *s, int out);
+
+ static void drawCursor (CompScreen *s,
+ CompOutput *output,
+@@ -380,6 +403,7 @@ initialiseZoomArea (ZoomArea *za, int out)
+ za->output = out;
+ za->currentZoom = 1.0f;
+ za->newZoom = 1.0f;
++ za->maxZoom = 1.0f;
+ za->xVelocity = 0.0f;
+ za->yVelocity = 0.0f;
+ za->zVelocity = 0.0f;
+@@ -488,6 +512,7 @@ zoomPreparePaintScreen (CompScreen *s,
+ {
+ int steps;
+ float amount, chunk;
++ CompWindow *w;
+
+ amount = msSinceLastPaint * 0.05f * zs->opt[SOPT_SPEED].value.f;
+ steps = amount / (0.5f * zs->opt[SOPT_TIMESTEP].value.f);
+@@ -515,6 +540,10 @@ zoomPreparePaintScreen (CompScreen *s,
+ }
+ if (zs->opt[SOPT_SYNC_MOUSE].value.b)
+ syncCenterToMouse (s);
++
++ for (w = s->windows; w; w = w->next)
++ updateMesh (w);
++
+ }
+ UNWRAP (zs, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, msSinceLastPaint);
+@@ -553,12 +582,12 @@ drawBox (CompScreen *s,
+ CompTransform zTransform = *transform;
+ int x1,x2,y1,y2;
+ int inx1, inx2, iny1, iny2;
+- int out = output->id;
++ int out = output->id;
+
+ transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &zTransform);
+ convertToZoomed (s, out, box.x1, box.y1, &inx1, &iny1);
+ convertToZoomed (s, out, box.x2, box.y2, &inx2, &iny2);
+-
++
+ x1 = MIN (inx1, inx2);
+ y1 = MIN (iny1, iny2);
+ x2 = MAX (inx1, inx2);
+@@ -576,10 +605,10 @@ drawBox (CompScreen *s,
+ glVertex2i (x2, y2);
+ glVertex2i (x1, y2);
+ glEnd ();
++ glPopMatrix ();
+ glColor4usv (defaultColor);
+ glDisable (GL_BLEND);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+- glPopMatrix ();
+ }
+ /* Apply the zoom if we are grabbed.
+ * Make sure to use the correct filter.
+@@ -594,6 +623,7 @@ zoomPaintOutput (CompScreen *s,
+ {
+ Bool status;
+ int out = output->id;
++ ZoomDevice *zDev;
+ ZOOM_SCREEN (s);
+
+
+@@ -642,8 +672,9 @@ zoomPaintOutput (CompScreen *s,
+ mask);
+ WRAP (zs, s, paintOutput, zoomPaintOutput);
+ }
+- if (zs->grabIndex)
+- drawBox (s, transform, output, zs->box);
++ for (zDev = zs->devices; zDev; zDev = zDev->next)
++ if (zDev->grabIndex)
++ drawBox (s, transform, output, zDev->box);
+
+ return status;
+ }
+@@ -710,7 +741,7 @@ setCenter (CompScreen *s, int x, int y, Bool instant)
+ }
+
+ if (zs->opt[SOPT_MOUSE_PAN].value.b)
+- restrainCursor (s, out);
++ restrainCursors (s, out);
+ }
+
+ /* Zooms the area described.
+@@ -750,7 +781,7 @@ setZoomArea (CompScreen *s,
+ }
+
+ if (zs->opt[SOPT_MOUSE_PAN].value.b)
+- restrainCursor (s, out);
++ restrainCursors (s, out);
+ }
+
+ /* Moves the zoom area to the window specified */
+@@ -795,16 +826,15 @@ enableMousePolling (CompScreen *s)
+ ZOOM_SCREEN (s);
+ ZOOM_DISPLAY (s->display);
+ zs->pollHandle =
+- (*zd->mpFunc->addPositionPolling) (s, updateMouseInterval);
++ (*zd->mpFunc->addPositionPolling) (s, NULL, updateMouseInterval);
+ zs->lastChange = time(NULL);
+- (*zd->mpFunc->getCurrentPosition) (s, &zs->mouseX, &zs->mouseY);
+ }
+
+ /* Sets the zoom (or scale) level.
+ * Cleans up if we are suddenly zoomed out.
+ */
+ static void
+-setScale (CompScreen *s, int out, float value)
++setScale (CompScreen *s, int out, float value, Bool action)
+ {
+ ZOOM_SCREEN(s);
+
+@@ -832,6 +862,8 @@ setScale (CompScreen *s, int out, float value)
+ value = zs->opt[SOPT_MINIMUM_ZOOM].value.f;
+
+ zs->zooms[out].newZoom = value;
++ if (action)
++ zs->zooms[out].maxZoom = value;
+ damageScreen(s);
+ }
+
+@@ -839,9 +871,9 @@ setScale (CompScreen *s, int out, float value)
+ * Convenince function for setting the scale factor for an area.
+ */
+ static inline void
+-setScaleBigger (CompScreen *s, int out, float x, float y)
++setScaleBigger (CompScreen *s, int out, float x, float y, Bool action)
+ {
+- setScale (s, out, x > y ? x : y);
++ setScale (s, out, x > y ? x : y, action);
+ }
+
+ /* Mouse code...
+@@ -862,6 +894,9 @@ syncCenterToMouse (CompScreen *s)
+ CompOutput *o;
+ ZOOM_SCREEN (s);
+
++ if (zs->moreMice)
++ return;
++
+ out = outputDeviceForPoint (s, zs->mouseX, zs->mouseY);
+ o = &s->outputDev[out];
+
+@@ -1101,19 +1136,98 @@ ensureVisibilityArea (CompScreen *s,
+ return ;
+ }
+
++/* Ensures that all cursors are visible in the ZoomArea
++ * This is done by taking the max width and height and applying
++ * padding etc.
++ */
++
++static void
++ensureCursorsVisiblity (CompScreen *s)
++{
++ ZoomDevice *zDev;
++ int totalX, totalY;
++ int out;
++ int x, y;
++ int zoomedX, zoomedY;
++ int top, bottom, left, right;
++ int width, height;
++ ZOOM_SCREEN (s);
++
++ for (out = 0; out < zs->nZooms; out++)
++ {
++ int nCursors = 0;
++ totalX = totalY = 0;
++ top = left = 0;
++ bottom = s->height +1;
++ right = s->width + 1;
++ for (zDev = zs->devices; zDev; zDev = zDev->next)
++ {
++ if (outputDeviceForPoint (s, zDev->mouseX, zDev-> mouseY) != out)
++ continue;
++
++ convertToZoomedTarget (s, out, zDev->mouseX - zs->cursor.hotX,
++ zDev->mouseY - zs->cursor.hotY, &zoomedX, &zoomedY);
++
++ totalX += zoomedX;
++ totalY += zoomedY;
++
++ if (zoomedY > top)
++ top = zoomedY;
++
++ if (zoomedY < bottom)
++ bottom = zoomedY;
++
++ if (zoomedX > left)
++ left = zoomedX;
++
++ if (zoomedX < right)
++ right = zoomedX;
++
++ nCursors++;
++ }
++
++ width = MAX (right, left) - MIN(left, right); // + padding
++ height = MAX (top, bottom) - MIN(bottom, top); // + padding
++
++ if (nCursors)
++ {
++
++ x = totalX / nCursors;
++ y = totalY / nCursors;
++
++ width = MAX (fabs(width), zs->zooms[out].maxZoom * s->outputDev[out].width); /* Or find the scale */
++ height = MAX (fabs(height), zs->zooms[out].maxZoom * s->outputDev[out].height); /* Ditto */
++
++ /* Catch out errornous things from first poll. FIXME: Bad */
++
++ if (width/s->outputDev[out].width <= 1.10f && height/s->outputDev[out].height <= 1.10f)
++ {
++
++ setScaleBigger (s, out, (float) width/s->outputDev[out].width,
++ (float) height/s->outputDev[out].height, FALSE);
++ ensureVisibilityArea (s, x, y, x + (width / 2.0f), y + (height / 2.0f), zs->opt[SOPT_RESTRAIN_MARGIN].value.i,
++ CENTER);
++
++ }
++
++ }
++ }
++}
++
+ /* Ensures that the cursor is visible on the given head.
+ * Note that we check if currentZoom is 1.0f, because that often means that
+ * mouseX and mouseY is not up-to-date (since the polling timer just
+ * started).
+ */
+ static void
+-restrainCursor (CompScreen *s, int out)
++restrainCursors (CompScreen *s, int out)
+ {
+ int x1, y1, x2, y2, margin;
+ int diffX = 0, diffY = 0;
+ int north, south, east, west;
+ float z;
+ CompOutput *o = &s->outputDev[out];
++ ZoomDevice *zDev;
+ ZOOM_SCREEN (s);
+ ZOOM_DISPLAY (s->display);
+
+@@ -1127,15 +1241,19 @@ restrainCursor (CompScreen *s, int out)
+ if (zs->zooms[out].currentZoom == 1.0f)
+ {
+ zs->lastChange = time(NULL);
+- (*zd->mpFunc->getCurrentPosition) (s, &zs->mouseX, &zs->mouseY);
++ for (zDev = zs->devices; zDev; zDev = zDev->next)
++ (*zd->mpFunc->getCurrentPosition) (s, zDev->dev, &zDev->mouseX, &zDev->mouseY);
+ }
+
+- convertToZoomedTarget (s, out, zs->mouseX - zs->cursor.hotX,
+- zs->mouseY - zs->cursor.hotY, &x1, &y1);
++ for (zDev = zs->devices; zDev; zDev = zDev->next)
++ {
++
++ convertToZoomedTarget (s, out, zDev->mouseX - zs->cursor.hotX,
++ zDev->mouseY - zs->cursor.hotY, &x1, &y1);
+ convertToZoomedTarget
+ (s, out,
+- zs->mouseX - zs->cursor.hotX + zs->cursor.width,
+- zs->mouseY - zs->cursor.hotY + zs->cursor.height,
++ zDev->mouseX - zs->cursor.hotX + zs->cursor.width,
++ zDev->mouseY - zs->cursor.hotY + zs->cursor.height,
+ &x2, &y2);
+
+ if ((x2 - x1 > o->region.extents.x2 - o->region.extents.x1) ||
+@@ -1152,9 +1270,10 @@ restrainCursor (CompScreen *s, int out)
+ diffY = y1 - o->region.extents.y1 - margin;
+
+ if (abs(diffX)*z > 0 || abs(diffY)*z > 0)
+- warpPointer (s,
+- (int) (zs->mouseX - pointerX) - (int) ((float)diffX * z),
+- (int) (zs->mouseY - pointerY) - (int) ((float)diffY * z));
++ warpDevicePointer (s, zDev->dev,
++ (int) (zDev->mouseX) - (int) ((float)diffX * z),
++ (int) (zDev->mouseY) - (int) ((float)diffY * z));
++ }
+ }
+
+ /* Check if the cursor is still visible.
+@@ -1164,28 +1283,31 @@ restrainCursor (CompScreen *s, int out)
+ * FIXME: The second ensureVisibility (sync with restrain).
+ */
+ static void
+-cursorMoved (CompScreen *s)
++cursorMoved (CompScreen *s, int x, int y)
+ {
+ int out;
+ ZOOM_SCREEN (s);
+
+- out = outputDeviceForPoint (s, zs->mouseX, zs->mouseY);
++ out = outputDeviceForPoint (s, x, y);
+ if (isActive (s, out))
+ {
+ if (zs->opt[SOPT_RESTRAIN_MOUSE].value.b)
+- restrainCursor (s, out);
++ restrainCursors (s, out);
+
+ if (zs->opt[SOPT_MOUSE_PAN].value.b)
+ {
+- ensureVisibilityArea (s,
+- zs->mouseX - zs->cursor.hotX,
+- zs->mouseY - zs->cursor.hotY,
+- zs->mouseX + zs->cursor.width -
+- zs->cursor.hotX,
+- zs->mouseY + zs->cursor.height -
+- zs->cursor.hotY,
+- zs->opt[SOPT_RESTRAIN_MARGIN].value.i,
+- NORTHWEST);
++ if (!zs->moreMice)
++ ensureVisibilityArea (s,
++ zs->mouseX - zs->cursor.hotX,
++ zs->mouseY - zs->cursor.hotY,
++ zs->mouseX + zs->cursor.width -
++ zs->cursor.hotX,
++ zs->mouseY + zs->cursor.height -
++ zs->cursor.hotY,
++ zs->opt[SOPT_RESTRAIN_MARGIN].value.i,
++ NORTHWEST);
++ else
++ ensureCursorsVisiblity (s);
+ }
+
+ cursorZoomActive (s);
+@@ -1196,6 +1318,131 @@ cursorMoved (CompScreen *s)
+ }
+ }
+
++/* Device management */
++
++static Bool
++zoomAddDevToList (CompScreen *s,
++ CompDevice *dev)
++{
++ ZOOM_SCREEN (s);
++
++ ZoomDevice *run;
++
++ if (!zs->devices)
++ {
++ zs->devices = calloc (1, sizeof(ZoomDevice));
++ if (!zs->devices)
++ return FALSE;
++ zs->devices->dev = dev;
++ zs->devices->next = NULL;
++ }
++ else
++ {
++ for (run = zs->devices; run->next; run = run->next);
++
++ run->next = calloc (1, sizeof(ZoomDevice));
++ if (!run->next)
++ return FALSE;
++ run->next->dev = dev;
++ run->next->next = NULL;
++ }
++ return TRUE;
++}
++
++static void
++zoomRemoveDevFromList (CompScreen *s,
++ CompDevice *dev)
++{
++ ZOOM_SCREEN (s);
++
++ ZoomDevice *run;
++
++ if (!zs->devices)
++ return;
++
++ if (run == zs->devices)
++ {
++ if (zs->devices->next)
++ zs->devices = zs->devices->next;
++ else
++ zs->devices = NULL;
++
++ if (run)
++ free (run);
++ }
++ else
++ {
++ for (run = zs->devices; run; run = run->next)
++ {
++ if (run->dev == dev)
++ break;
++ }
++
++ ZoomDevice *selected = run;
++
++ if (selected)
++ if (selected->next)
++ {
++ run = selected->next;
++ if (selected)
++ free(selected);
++ }
++ }
++}
++
++static void
++zoomCheckList (CompScreen *s,
++ MousepollDevice *list)
++{
++ ZOOM_SCREEN (s);
++ Bool ok = FALSE;
++ MousepollDevice *run;
++ ZoomDevice *ptr;
++ CompDevice *addDev = NULL, *removeDev = NULL;
++
++ do
++ {
++ for (run = list; run; run = run->next)
++ {
++ addDev = run->dev;
++ for (ptr = zs->devices; ptr; ptr = ptr->next)
++ {
++ if (ptr->dev == run->dev)
++ {
++ addDev = NULL;
++ break;
++ }
++ }
++ if (addDev) break;
++ }
++
++ for (ptr = zs->devices; ptr; ptr = ptr->next)
++ {
++ removeDev = ptr->dev;
++ for (run = list; run; run = run->next)
++ {
++ if (run->dev == ptr->dev)
++ {
++ removeDev = NULL;
++ break;
++ }
++ }
++ if (removeDev) break;
++ }
++
++ if (addDev)
++ zoomAddDevToList (s, addDev);
++
++ if (removeDev)
++ zoomRemoveDevFromList (s, removeDev);
++
++ if (addDev || removeDev)
++ ok = FALSE;
++ else
++ ok = TRUE;
++ } while (!ok);
++}
++
+ /* Update the mouse position.
+ * Based on the zoom engine in use, we will have to move the zoom area.
+ * This might have to be added to a timer.
+@@ -1205,24 +1452,45 @@ updateMousePosition (CompScreen *s, int x, int y)
+ {
+ ZOOM_SCREEN(s);
+ int out;
+- zs->mouseX = x;
+- zs->mouseY = y;
+- out = outputDeviceForPoint (s, zs->mouseX, zs->mouseY);
++ //zs->mouseX = x;
++ //zs->mouseY = y;
++ out = outputDeviceForPoint (s, x, y);
+ zs->lastChange = time(NULL);
+- if (zs->opt[SOPT_SYNC_MOUSE].value.b && !isInMovement (s, out))
+- setCenter (s, zs->mouseX, zs->mouseY, TRUE);
+- cursorMoved (s);
++ /*if (zs->opt[SOPT_SYNC_MOUSE].value.b && !isInMovement (s, out))
++ setCenter (s, zs->mouseX, zs->mouseY, TRUE);*/
++ cursorMoved (s, x, y);
+ damageScreen (s);
+ }
+
+ /* Timeout handler to poll the mouse. Returns false (and thereby does not
+ * get re-added to the queue) when zoom is not active. */
+ static void
+-updateMouseInterval (CompScreen *s, int x, int y)
++updateMouseInterval (CompScreen *s, MousepollDevice *mDev)
+ {
+ ZOOM_SCREEN (s);
++ ZoomDevice *zDev;
++
++ zoomCheckList (s, mDev);
++
++ for (; mDev; mDev = mDev->next)
++ {
++ for (zDev = zs->devices; zDev; zDev = zDev->next)
++ if (zDev->dev == mDev->dev)
++ {
++ zDev->mouseX = mDev->posX;
++ zDev->mouseY = mDev->posY;
++ }
++
++ if (zs->devices->next)
++ zs->moreMice = TRUE;
++ else
++ {
++ zs->moreMice = FALSE;
++ zs->mouseX = mDev->posX;
++ zs->mouseY = mDev->posY;
++ }
+
+- updateMousePosition(s, x, y);
++ updateMousePosition(s, mDev->posX, mDev->posY);
+
+ if (!zs->grabbed)
+ {
+@@ -1230,7 +1498,8 @@ updateMouseInterval (CompScreen *s, int x, int y)
+ if (zs->pollHandle)
+ (*zd->mpFunc->removePositionPolling) (s, zs->pollHandle);
+ zs->pollHandle = 0;
+- cursorMoved (s);
++ cursorMoved (s, mDev->posX, mDev->posY);
++ }
+ }
+ }
+
+@@ -1254,6 +1523,7 @@ drawCursor (CompScreen *s,
+ const CompTransform *transform)
+ {
+ int out = output->id;
++ ZoomDevice *zDev;
+ ZOOM_SCREEN (s);
+
+ if (zs->cursor.isSet)
+@@ -1273,8 +1543,11 @@ drawCursor (CompScreen *s,
+ return;
+ }
+
++ for (zDev = zs->devices; zDev; zDev = zDev->next)
++ {
++ sTransform = *transform;
+ transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
+- convertToZoomed (s, out, zs->mouseX, zs->mouseY, &ax, &ay);
++ convertToZoomed (s, out, zDev->mouseX, zDev->mouseY, &ax, &ay);
+ glPushMatrix ();
+ glLoadMatrixf (sTransform.m);
+ glTranslatef ((float) ax, (float) ay, 0.0f);
+@@ -1305,7 +1578,9 @@ drawCursor (CompScreen *s,
+ glDisable (GL_BLEND);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
+ glDisable (GL_TEXTURE_RECTANGLE_ARB);
++ glTranslatef ((float) -ax, (float) -ay, 0.0f);
+ glPopMatrix ();
++ }
+ }
+ }
+
+@@ -1505,11 +1780,11 @@ setZoomAreaAction (CompDisplay *d,
+ o = &s->outputDev[out];
+ if (scale && WIDTH && HEIGHT)
+ setScaleBigger (s, out, (float) WIDTH/o->width,
+- (float) HEIGHT/o->height);
++ (float) HEIGHT/o->height, TRUE);
+ #undef WIDTH
+ #undef HEIGHT
+ if (restrain)
+- restrainCursor (s, out);
++ restrainCursors (s, out);
+ }
+ return TRUE;
+ }
+@@ -1563,11 +1838,11 @@ ensureVisibilityAction (CompDisplay *d,
+ #define HEIGHT (y2 - y1)
+ if (scale && WIDTH && HEIGHT)
+ setScaleBigger (s, out, (float) WIDTH/o->width,
+- (float) HEIGHT/o->height);
++ (float) HEIGHT/o->height, TRUE);
+ #undef WIDTH
+ #undef HEIGHT
+ if (restrain)
+- restrainCursor (s, out);
++ restrainCursors (s, out);
+ }
+ return TRUE;
+ }
+@@ -1580,19 +1855,42 @@ zoomBoxActivate (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
++ ZoomDevice *zDev;
+ int xid;
++ int deviceid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+ s = findScreenAtDisplay (d, xid);
+
+- if (s)
++ deviceid = getIntOptionNamed (option, nOption, "device", -1);
++ dev = compFindDeviceById (d, deviceid);
++
++ if (s && dev)
+ {
+ ZOOM_SCREEN (s);
+- zs->grabIndex = pushScreenGrab (s, None, "ezoom");
+- zs->box.x1 = pointerX;
+- zs->box.y1 = pointerY;
+- zs->box.x2 = pointerX;
+- zs->box.y2 = pointerY;
++
++ for (zDev = zs->devices; zDev; zDev = zDev->next)
++ if (zDev->dev == dev)
++ break;
++
++ if (!zDev)
++ {
++ if (!zoomAddDevToList (s, dev))
++ return FALSE;
++
++ for (zDev = zs->devices; zDev; zDev = zDev->next)
++ if (zDev->dev == dev)
++ break;
++ if (!zDev)
++ return FALSE;
++ }
++
++ zDev->grabIndex = pushDeviceGrab (s, dev, None, "ezoom");
++ zDev->box.x1 = dev->pointerX;
++ zDev->box.y1 = dev->pointerY;
++ zDev->box.x2 = dev->pointerX;
++ zDev->box.y2 = dev->pointerY;
+ if (state & CompActionStateInitButton)
+ action->state |= CompActionStateTermButton;
+ return TRUE;
+@@ -1608,36 +1906,48 @@ zoomBoxDeactivate (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
++ ZoomDevice *zDev;
+ int xid;
++ int deviceid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+
++ deviceid = getIntOptionNamed (option, nOption, "device", -1);
++ dev = compFindDeviceById (d, deviceid);
++
+ for (s = d->screens; s; s = s->next)
+ {
+ int x, y, width, height;
+ ZOOM_SCREEN (s);
+
+- if (zs->grabIndex)
++ for (zDev = zs->devices; zDev; zDev = zDev->next)
+ {
+ int out;
+ CompOutput *o;
+
+- removeScreenGrab (s, zs->grabIndex, NULL);
+- zs->grabIndex = 0;
++ if (zDev->dev != dev)
++ continue;
++
++ if (zDev->grabIndex)
++ {
++ removeDeviceGrab (s, zDev->dev, zDev->grabIndex, NULL);
++ zDev->grabIndex = 0;
+
+- zs->box.x2 = pointerX;
+- zs->box.y2 = pointerY;
++ zDev->box.x2 = dev->pointerX;
++ zDev->box.y2 = dev->pointerY;
+
+- x = MIN (zs->box.x1, zs->box.x2);
+- y = MIN (zs->box.y1, zs->box.y2);
+- width = MAX (zs->box.x1, zs->box.x2) - x;
+- height = MAX (zs->box.y1, zs->box.y2) - y;
+-
+- out = outputDeviceForGeometry (s, x,y,width,height,0);
+- o = &s->outputDev[out];
+- setScaleBigger (s, out, (float) width/o->width, (float)
+- height/o->height);
+- setZoomArea (s, x,y,width,height,FALSE);
++ x = MIN (zDev->box.x1, zDev->box.x2);
++ y = MIN (zDev->box.y1, zDev->box.y2);
++ width = MAX (zDev->box.x1, zDev->box.x2) - x;
++ height = MAX (zDev->box.y1, zDev->box.y2) - y;
++
++ out = outputDeviceForGeometry (s, x,y,width,height,0);
++ o = &s->outputDev[out];
++ setScaleBigger (s, out, (float) width/o->width, (float)
++ height/o->height, TRUE);
++ setZoomArea (s, x,y,width,height,FALSE);
++ }
+ }
+ }
+ return FALSE;
+@@ -1653,22 +1963,27 @@ zoomIn (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
++ int deviceid;
+ Window xid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+ s = findScreenAtDisplay (d, xid);
+
+- if (s)
++ deviceid = getIntOptionNamed (option, nOption, "device", -1);
++ dev = compFindDeviceById (d, deviceid);
++
++ if (s && dev)
+ {
+- int out = outputDeviceForPoint (s, pointerX, pointerY);
++ int out = outputDeviceForPoint (s, dev->pointerX, dev->pointerY);
+ ZOOM_SCREEN (s);
+
+- if (zs->opt[SOPT_SYNC_MOUSE].value.b && !isInMovement (s, out))
+- setCenter (s, pointerX, pointerY, TRUE);
++ /*if (zs->opt[SOPT_SYNC_MOUSE].value.b && !isInMovement (s, out))
++ setCenter (s, pointerX, pointerY, TRUE);*/
+
+ setScale (s, out,
+ zs->zooms[out].newZoom /
+- zs->opt[SOPT_ZOOM_FACTOR].value.f);
++ zs->opt[SOPT_ZOOM_FACTOR].value.f, TRUE);
+ }
+ return TRUE;
+ }
+@@ -1731,7 +2046,7 @@ zoomSpecific (CompDisplay *d,
+ if (otherScreenGrabExist (s, 0))
+ return FALSE;
+
+- setScale (s, out, target);
++ setScale (s, out, target, TRUE);
+
+ w = findWindowAtDisplay(d, d->activeWindow);
+ if (zd->opt[DOPT_SPECIFIC_TARGET_FOCUS].value.b
+@@ -1819,7 +2134,7 @@ zoomToWindow (CompDisplay *d,
+ out = outputDeviceForWindow (w);
+ o = &s->outputDev[out];
+ setScaleBigger (s, out, (float) width/o->width,
+- (float) height/o->height);
++ (float) height/o->height, FALSE);
+ zoomAreaToWindow (w);
+ return TRUE;
+ }
+@@ -2021,7 +2336,7 @@ zoomOut (CompDisplay *d,
+
+ setScale (s, out,
+ zs->zooms[out].newZoom *
+- zs->opt[SOPT_ZOOM_FACTOR].value.f);
++ zs->opt[SOPT_ZOOM_FACTOR].value.f, TRUE);
+ }
+
+ return TRUE;
+@@ -2111,7 +2426,7 @@ focusTrack (CompDisplay *d,
+
+ setScaleBigger (w->screen, out,
+ (float) width / w->screen->outputDev[out].width,
+- (float) height/w->screen->outputDev[out].height);
++ (float) height/w->screen->outputDev[out].height, FALSE);
+ }
+ zoomAreaToWindow (w);
+ }
+@@ -2157,6 +2472,26 @@ zoomHandleEvent (CompDisplay *d,
+ zoomUpdateCursor (s, &zs->cursor);
+ }
+ }
++ if (event->type == d->xi_motion)
++ {
++ XDeviceMotionEvent *mev = (XDeviceMotionEvent *) event;
++ CompDevice *dev = compFindDeviceById (d, mev->deviceid);
++ CompScreen *s = findScreenAtDisplay (d, mev->root);
++ ZoomDevice *zDev;
++
++ if (s && dev)
++ {
++ ZOOM_SCREEN (s);
++ for (zDev = zs->devices; zDev; zDev = zDev->next)
++ {
++ if (zDev->dev == dev)
++ {
++ zDev->box.x2 = dev->pointerX;
++ zDev->box.y2 = dev->pointerY;
++ }
++ }
++ }
++ }
+ break;
+ }
+ UNWRAP (zd, d, handleEvent);
+@@ -2375,6 +2710,7 @@ zoomInitScreen (CompPlugin *p,
+ zs->cursor.isSet = FALSE;
+ zs->cursorHidden = FALSE;
+ zs->pollHandle = 0;
++ zs->devices = NULL;
+
+ WRAP (zs, s, preparePaintScreen, zoomPreparePaintScreen);
+ WRAP (zs, s, donePaintScreen, zoomDonePaintScreen);
+--
+1.5.6
+
diff --git a/fusion/plugins/firepaint/0001-MPX-Support.patch b/fusion/plugins/firepaint/0001-MPX-Support.patch
new file mode 100644
index 0000000..1c86a58
--- /dev/null
+++ b/fusion/plugins/firepaint/0001-MPX-Support.patch
@@ -0,0 +1,260 @@
+From b95c7b5bc0992bf0f964525362814e96b5544f13 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Fri, 31 Oct 2008 16:21:57 +0900
+Subject: [PATCH] MPX Support
+
+---
+ firepaint.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++----------
+ 1 files changed, 121 insertions(+), 24 deletions(-)
+
+diff --git a/firepaint.c b/firepaint.c
+index 825ca69..73a2352 100644
+--- a/firepaint.c
++++ b/firepaint.c
+@@ -20,6 +20,7 @@
+ */
+
+ #include <compiz-core.h>
++#include <string.h>
+
+ #include "firepaint_options.h"
+ #include "firepaint_tex.h"
+@@ -79,7 +80,6 @@ typedef struct _ParticleSystem
+ }
+ ParticleSystem;
+
+-
+ static void
+ initParticles (int numParticles,
+ ParticleSystem *ps)
+@@ -361,11 +361,19 @@ finiParticles (ParticleSystem * ps)
+
+ #define NUM_ADD_POINTS 1000
+
++
++typedef struct _FireGrab
++{
++ CompDevice *dev;
++ int grabIndex;
++ struct _FireGrab *next;
++} FireGrab;
++
+ typedef struct _FireDisplay
+ {
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+-
++ FireGrab *grabs;
+ }
+ FireDisplay;
+
+@@ -409,8 +417,9 @@ fireAddPoint (CompScreen *s,
+ Bool requireGrab)
+ {
+ FIRE_SCREEN (s);
++ FIRE_DISPLAY (s->display);
+
+- if (!requireGrab || fs->grabIndex)
++ if (!requireGrab || fd->grabs)
+ {
+ if (fs->pointsSize < fs->numPoints + 1)
+ {
+@@ -426,6 +435,17 @@ fireAddPoint (CompScreen *s,
+ }
+ }
+
++static FireGrab *
++fireGrabByDev (CompDisplay *d,
++ CompDevice *dev)
++{
++ FireGrab *run;
++ FIRE_DISPLAY (d);
++ for (run = fd->grabs; run; run = run->next)
++ if (run->dev->id == dev->id)
++ return run;
++ return NULL;
++}
+
+ static Bool
+ fireAddParticle (CompDisplay *d,
+@@ -455,7 +475,6 @@ fireAddParticle (CompDisplay *d,
+ return FALSE;
+ }
+
+-
+ static Bool
+ fireInitiate (CompDisplay *d,
+ CompAction *action,
+@@ -464,21 +483,47 @@ fireInitiate (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
+ Window xid;
++ int deviceID;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
++ deviceID = getIntOptionNamed (option, nOption, "device", -1);
+
+ s = findScreenAtDisplay (d, xid);
++ dev = compFindDeviceById (d, deviceID);
+
+- if (s)
++ if (!dev)
++ return FALSE;
++
++ if (!s)
++ return FALSE;
++
++ FIRE_DISPLAY (d);
++ FireGrab *run;
++
++ if (!fd->grabs)
+ {
+- FIRE_SCREEN (s);
++ fd->grabs = calloc (1, sizeof (FireGrab) + 10);
++ if (!fd->grabs)
++ return FALSE;
+
+- if (otherScreenGrabExist (s, 0) )
+- return FALSE;
++ fd->grabs->dev = dev;
++ fd->grabs->grabIndex = pushDeviceGrab (s, dev, None, "firepaint");
++ fd->grabs->next = NULL;
++ }
++ else
++ {
++ for (run = fd->grabs; run->next; run = run->next);
+
+- if (!fs->grabIndex)
+- fs->grabIndex = pushScreenGrab (s, None, "firepaint");
++ run->next = calloc (1, sizeof (FireGrab) + 10);
++ if (!run->next)
++ return FALSE;
++
++ run->next->dev = dev;
++ run->next->grabIndex = pushDeviceGrab (s, dev, None, "firepaint");
++ run->next->next = NULL;
++ }
+
+ if (state & CompActionStateInitButton)
+ action->state |= CompActionStateTermButton;
+@@ -486,10 +531,7 @@ fireInitiate (CompDisplay *d,
+ if (state & CompActionStateInitKey)
+ action->state |= CompActionStateTermKey;
+
+- fireAddPoint (s, pointerX, pointerY, TRUE);
+-
+- }
+-
++ fireAddPoint (s, dev->pointerX, dev->pointerY, TRUE);
+ return TRUE;
+ }
+
+@@ -501,24 +543,66 @@ fireTerminate (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
++ FireGrab *grab;
+ Window xid;
++ int deviceID;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
++ deviceID = getIntOptionNamed (option, nOption, "device", -1);
+
+- for (s = d->screens; s; s = s->next)
+- {
+- FIRE_SCREEN (s);
++ dev = compFindDeviceById (d, deviceID);
++ s = findScreenAtDisplay (d, xid);
+
+- if (xid && s->root != xid)
+- continue;
++ FIRE_DISPLAY (d);
+
+- if (fs->grabIndex)
+- {
+- removeScreenGrab (s, fs->grabIndex, NULL);
+- fs->grabIndex = 0;
+- }
++ if (!fd->grabs)
++ return FALSE;
++
++ if (!s)
++ return FALSE;
++
++ if (!dev)
++ return FALSE;
++
++ grab = fireGrabByDev (d, dev);
++
++ if (!grab)
++ return FALSE;
++
++ if (!grab->grabIndex)
++ return FALSE;
++
++ FireGrab *run;
++ removeDeviceGrab (s, dev, grab->grabIndex, NULL);
++ grab->grabIndex = 0;
++
++ if (grab == fd->grabs)
++ {
++ if (grab->next)
++ fd->grabs = grab->next;
++ else
++ fd->grabs = NULL;
+ }
++ else
++ {
++ for (run = fd->grabs; run; run = run->next)
++ if (run->next)
++ {
++ if (run->next == grab)
++ {
++ if (run->next->next)
++ run->next = run->next->next;
++ else
++ run->next = NULL;
++ }
++ }
++ }
++
++ if (grab)
++ free (grab);
+
++ if (!fd->grabs)
+ action->state &= ~ (CompActionStateTermKey | CompActionStateTermButton);
+
+ return FALSE;
+@@ -793,6 +877,17 @@ fireHandleEvent (CompDisplay *d,
+ fireAddPoint (s, pointerX, pointerY, TRUE);
+
+ default:
++ if (event->type == d->xi_motion)
++ {
++ XDeviceMotionEvent* mev = (XDeviceMotionEvent*) event;
++ int deviceID = mev->deviceid;
++ CompDevice *dev = compFindDeviceById (d, deviceID);
++ CompScreen *s = findScreenAtDisplay (d, mev->root);
++
++ if (dev)
++ if (s)
++ fireAddPoint (s, mev->x_root, mev->y_root, TRUE);
++ }
+ break;
+ }
+
+@@ -823,6 +918,8 @@ fireInitDisplay (CompPlugin *p,
+ return FALSE;
+ }
+
++ fd->grabs = NULL;
++
+ d->base.privates[displayPrivateIndex].ptr = fd;
+
+ WRAP (fd, d, handleEvent, fireHandleEvent);
+--
+1.5.6
+
diff --git a/fusion/plugins/freewins/0001-MPX-Support.patch b/fusion/plugins/freewins/0001-MPX-Support.patch
new file mode 100644
index 0000000..35b5957
--- /dev/null
+++ b/fusion/plugins/freewins/0001-MPX-Support.patch
@@ -0,0 +1,1179 @@
+From 3b7d6689b873003934787f8644ea5fc24c8ae000 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Fri, 31 Oct 2008 18:24:14 +0900
+Subject: [PATCH] MPX Support
+
+---
+ action.c | 622 ++++++++++++++++++++++++++++++++----------------------------
+ events.c | 298 +++++++++++++++++++++++++++++-
+ freewins.c | 3 +
+ freewins.h | 27 +++
+ 4 files changed, 655 insertions(+), 295 deletions(-)
+
+diff --git a/action.c b/action.c
+index a306e31..d158059 100644
+--- a/action.c
++++ b/action.c
+@@ -57,14 +57,15 @@
+ /* Initiate Mouse Rotation */
+ Bool
+ initiateFWRotate (CompDisplay *d,
+- CompAction *action,
+- CompActionState state,
+- CompOption *option,
+- int nOption)
++ CompAction *action,
++ CompActionState state,
++ CompOption *option,
++ int nOption)
+ {
+ CompWindow* w;
+ CompWindow *useW;
+ CompScreen* s;
++ CompDevice* dev;
+ FWWindowInputInfo *info;
+ Window xid, root;
+ int x, y, mods;
+@@ -78,240 +79,260 @@ initiateFWRotate (CompDisplay *d,
+ root = getIntOptionNamed (option, nOption, "root", 0);
+ s = findScreenAtDisplay (d, root);
+
+- if (s && w)
+- {
++ int id = getIntOptionNamed (option, nOption, "device", -1);
+
+- FREEWINS_SCREEN (s);
++ dev = compFindDeviceById (d, id);
+
+- for (info = fws->transformedWindows; info; info = info->next)
++ if (dev)
+ {
+- if (info->ipw)
+- if (w->id == info->ipw)
++ /* Check to see if the device is in-use */
++
++ FWGrab *check;
++
++ for (check = fwd->grabs; check; check = check->next)
++ {
++ if (check->dev->id == dev->id)
++ return FALSE;
++ }
++
++ if (s && w)
++ {
++
++ FREEWINS_SCREEN (s);
++
++ for (info = fws->transformedWindows; info; info = info->next)
++ {
++ if (info->ipw)
++ if (w->id == info->ipw)
+ /* The window we just grabbed was actually
+ * an IPW, get the real window instead
+ */
+- useW = FWGetRealWindow (w);
+- }
++ useW = FWGetRealWindow (w);
++ }
+
+- fws->rotateCursor = XCreateFontCursor (s->display->display, XC_fleur);
++ fws->rotateCursor = XCreateFontCursor (s->display->display, XC_fleur);
+
+- if (!otherScreenGrabExist (s, "freewins", 0))
+- if (!fws->grabIndex)
+- fws->grabIndex = pushScreenGrab (s, fws->rotateCursor, "freewins");
++ if (!otherScreenGrabExist (s, "freewins", 0))
++ if (!fws->grabIndex)
++ FWCreateGrab (useW, dev, grabRotate);
+
+- }
++ FWGrab *grab;
+
+- if (useW)
+- {
+-
+- if (matchEval (freewinsGetShapeWindowTypes (useW->screen), useW))
++ for (grab = fwd->grabs; grab; grab = grab->next)
++ {
++ if (grab->dev->id == dev->id)
++ break;
++ }
++ }
++
++ if (useW)
+ {
+- FREEWINS_WINDOW (useW);
++ if (matchEval (freewinsGetShapeWindowTypes (useW->screen), useW))
++ {
++ FREEWINS_WINDOW (useW);
+
+- x = getIntOptionNamed (option, nOption, "x",
+- useW->attrib.x + (useW->width / 2));
+- y = getIntOptionNamed (option, nOption, "y",
+- useW->attrib.y + (useW->height / 2));
++ x = getIntOptionNamed (option, nOption, "x",
++ useW->attrib.x + (useW->width / 2));
++ y = getIntOptionNamed (option, nOption, "y",
++ useW->attrib.y + (useW->height / 2));
+
+- mods = getIntOptionNamed (option, nOption, "modifiers", 0);
+-
+- fwd->grabWindow = useW;
+-
+- fww->grab = grabRotate;
++ mods = getIntOptionNamed (option, nOption, "modifiers", 0);
+
+- /* Save current scales and angles */
+-
+- fww->animate.oldAngX = fww->transform.angX;
+- fww->animate.oldAngY = fww->transform.angY;
+- fww->animate.oldAngZ = fww->transform.angZ;
+- fww->animate.oldScaleX = fww->transform.scaleX;
+- fww->animate.oldScaleY = fww->transform.scaleY;
+-
+- if (pointerY > fww->iMidY)
+- {
+- if (pointerX > fww->iMidX)
++ /* Save current scales and angles */
++
++ fww->animate.oldAngX = fww->transform.angX;
++ fww->animate.oldAngY = fww->transform.angY;
++ fww->animate.oldAngZ = fww->transform.angZ;
++ fww->animate.oldScaleX = fww->transform.scaleX;
++ fww->animate.oldScaleY = fww->transform.scaleY;
++ if (dev->pointerY > fww->iMidY)
++ {
++ if (dev->pointerX > fww->iMidX)
+ fww->corner = CornerBottomRight;
+- else if (pointerX < fww->iMidX)
++ else if (dev->pointerX < fww->iMidX)
+ fww->corner = CornerBottomLeft;
+- }
+- else if (pointerY < fww->iMidY)
+- {
+- if (pointerX > fww->iMidX)
++ }
++ else if (dev->pointerY < fww->iMidY)
++ {
++ if (dev->pointerX > fww->iMidX)
+ fww->corner = CornerTopRight;
+- else if (pointerX < fww->iMidX)
++ else if (dev->pointerX < fww->iMidX)
+ fww->corner = CornerTopLeft;
+- }
++ }
+
+- switch (freewinsGetZAxisRotation (s))
+- {
+- case ZAxisRotationAlways3d:
+- fww->can3D = TRUE;
+- fww->can2D = FALSE; break;
+- case ZAxisRotationAlways2d:
+- fww->can3D = FALSE;
+- fww->can2D = TRUE; break;
+- case ZAxisRotationDetermineOnClick:
+- case ZAxisRotationSwitch:
+- FWDetermineZAxisClick (useW, pointerX, pointerY, FALSE); break;
+- case ZAxisRotationInterchangable:
+- fww->can3D = TRUE;
+- fww->can2D = TRUE; break;
+- default:
+- break;
+- }
++ switch (freewinsGetZAxisRotation (s))
++ {
++ case ZAxisRotationAlways3d:
++ fww->can3D = TRUE;
++ fww->can2D = FALSE; break;
++ case ZAxisRotationAlways2d:
++ fww->can3D = FALSE;
++ fww->can2D = TRUE; break;
++ case ZAxisRotationDetermineOnClick:
++ case ZAxisRotationSwitch:
++ FWDetermineZAxisClick (useW, dev->pointerX, dev->pointerY, FALSE);
++ break;
++ case ZAxisRotationInterchangable:
++ fww->can3D = TRUE;
++ fww->can2D = TRUE; break;
++ default:
++ break;
++ }
+
+- /* Set the rotation axis */
++ /* Set the rotation axis */
+
+- switch (freewinsGetRotationAxis (w->screen))
+- {
+- case RotationAxisAlwaysCentre:
+- default:
+- FWCalculateInputOrigin (w,
+- WIN_REAL_X (fwd->grabWindow) +
+- WIN_REAL_W (fwd->grabWindow) / 2.0f,
+- WIN_REAL_Y (fwd->grabWindow) +
+- WIN_REAL_H (fwd->grabWindow) / 2.0f);
+- FWCalculateOutputOrigin (w,
+- WIN_OUTPUT_X (fwd->grabWindow) +
+- WIN_OUTPUT_W (fwd->grabWindow) / 2.0f,
+- WIN_OUTPUT_Y (fwd->grabWindow) +
+- WIN_OUTPUT_H (fwd->grabWindow) / 2.0f);
+- break;
+- case RotationAxisClickPoint:
+- FWCalculateInputOrigin (fwd->grabWindow, fwd->click_root_x, fwd->click_root_y);
+- FWCalculateOutputOrigin (fwd->grabWindow, fwd->click_root_x, fwd->click_root_y);
+- break;
+- case RotationAxisOppositeToClick:
+- FWCalculateInputOrigin (fwd->grabWindow, w->attrib.x + w->width - fwd->click_root_x,
+- w->attrib.y + w->height - fwd->click_root_y);
+- FWCalculateOutputOrigin (fwd->grabWindow, w->attrib.x + w->width - fwd->click_root_x,
+- w->attrib.y + w->height - fwd->click_root_y);
+- break;
+- }
++ switch (freewinsGetRotationAxis (w->screen))
++ {
++ case RotationAxisClickPoint:
++ FWCalculateInputOrigin (useW, fwd->click_root_x, fwd->click_root_y);
++ FWCalculateOutputOrigin (useW, fwd->click_root_x, fwd->click_root_y);
++ break;
++ case RotationAxisOppositeToClick:
++ FWCalculateInputOrigin (useW, w->attrib.x + w->width - fwd->click_root_x,
++ w->attrib.y + w->height - fwd->click_root_y);
++ FWCalculateOutputOrigin (useW, w->attrib.x + w->width - fwd->click_root_x,
++ w->attrib.y + w->height - fwd->click_root_y);
++ break;
++ case RotationAxisAlwaysCentre:
++ default:
++ FWCalculateInputOrigin (w,
++ WIN_REAL_X (useW) +
++ WIN_REAL_W (useW) / 2.0f,
++ WIN_REAL_Y (useW) +
++ WIN_REAL_H (useW) / 2.0f);
++ FWCalculateOutputOrigin (w,
++ WIN_OUTPUT_X (useW) +
++ WIN_OUTPUT_W (useW) / 2.0f,
++ WIN_OUTPUT_Y (useW) +
++ WIN_OUTPUT_H (useW) / 2.0f);
++ break;
++ }
+
+- /* Announce that we grabbed the window */
++ /* Announce that we grabbed the window */
+
+- (useW->screen->windowGrabNotify) (useW, x, y, mods,
+- CompWindowGrabMoveMask |
+- CompWindowGrabButtonMask);
++ (useW->screen->windowGrabNotify) (useW, x, y, mods,
++ CompWindowGrabMoveMask |
++ CompWindowGrabButtonMask);
+
+- /* Shape the window beforehand and avoid a stale grab*/
+- if (FWCanShape (useW))
+- if (FWHandleWindowInputInfo (useW))
+- FWAdjustIPW (useW);
+-
+-
+- if (state & CompActionStateInitButton)
++ /*Shape the window beforehand and avoid a stale grab*/
++ if (FWCanShape (useW))
++ if (FWHandleWindowInputInfo (useW))
++ FWAdjustIPW (useW);
++
++ if (state & CompActionStateInitButton)
+ action->state |= CompActionStateTermButton;
+
+- if (state & CompActionStateInitKey)
++ if (state & CompActionStateInitKey)
+ action->state |= CompActionStateTermKey;
+
++ }
+ }
+ }
++
+ return TRUE;
+ }
+
++// check to see if the deviceID is still in use, if so bail out.
+
+ Bool
+ terminateFWRotate (CompDisplay *d,
+- CompAction *action,
+- CompActionState state,
+- CompOption *option,
+- int nOption)
++ CompAction *action,
++ CompActionState state,
++ CompOption *option,
++ int nOption)
+ {
+-
+ CompScreen *s;
++ CompDevice *dev;
++ FWGrab *grab;
++ int id;
+
+ FREEWINS_DISPLAY (d);
+
+- for (s = d->screens; s; s = s->next)
+- {
+- FREEWINS_SCREEN (s);
++ id = getIntOptionNamed (option, nOption, "device", -1);
++ dev = compFindDeviceById (d, id);
+
+- if (fwd->grabWindow && fws->grabIndex)
+- {
+- FREEWINS_WINDOW (fwd->grabWindow);
+- if (fww->grab == grabRotate)
+- {
+- int distX, distY;
++ if (dev)
++ {
++ grab = FWGrabForDevice (d, dev);
+
+- (fwd->grabWindow->screen->windowUngrabNotify) (fwd->grabWindow);
++ if (grab)
++ {
++ for (s = d->screens; s; s = s->next)
++ {
++ FREEWINS_SCREEN (s);
+
+- switch (freewinsGetRotationAxis (fwd->grabWindow->screen))
++ if (grab->w)
+ {
+- case RotationAxisClickPoint:
+- case RotationAxisOppositeToClick:
+-
+- distX = (fww->outputRect.x1 +
+- (fww->outputRect.x2 - fww->outputRect.x1) / 2.0f) -
+- (WIN_REAL_X (fwd->grabWindow) +
+- WIN_REAL_W (fwd->grabWindow) / 2.0f);
+- distY = (fww->outputRect.y1 +
+- (fww->outputRect.y2 - fww->outputRect.y1) / 2.0f) -
+- (WIN_REAL_Y (fwd->grabWindow) +
+- WIN_REAL_H (fwd->grabWindow) / 2.0f);
+-
+- moveWindow (fwd->grabWindow, distX, distY, TRUE, TRUE);
+- syncWindowPosition (fwd->grabWindow);
+-
+- FWCalculateInputOrigin (fwd->grabWindow, WIN_REAL_X (fwd->grabWindow) +
+- WIN_REAL_W (fwd->grabWindow) / 2.0f,
+- WIN_REAL_Y (fwd->grabWindow) +
+- WIN_REAL_H (fwd->grabWindow) / 2.0f);
+- FWCalculateOutputOrigin(fwd->grabWindow,
+- WIN_OUTPUT_X (fwd->grabWindow) +
+- WIN_OUTPUT_W (fwd->grabWindow) / 2.0f,
+- WIN_OUTPUT_Y (fwd->grabWindow) +
+- WIN_OUTPUT_H (fwd->grabWindow) / 2.0f);
++ FREEWINS_WINDOW (grab->w);
++ if (grab->type == grabRotate)
++ {
++
++ int distX, distY;
++
++ (grab->w->screen->windowUngrabNotify) (grab->w);
++
++ switch (freewinsGetRotationAxis (grab->w->screen))
++ {
++ case RotationAxisClickPoint:
++ case RotationAxisOppositeToClick:
++ distX = (fww->outputRect.x1 +
++ (fww->outputRect.x2 - fww->outputRect.x1) / 2.0f) -
++ (WIN_REAL_X (grab->w) +
++ WIN_REAL_W (grab->w) / 2.0f);
++ distY = (fww->outputRect.y1 +
++ (fww->outputRect.y2 - fww->outputRect.y1) / 2.0f) -
++ (WIN_REAL_Y (grab->w) +
++ WIN_REAL_H (grab->w) / 2.0f);
++
++ moveWindow (grab->w, distX, distY, TRUE, TRUE);
++ syncWindowPosition (grab->w);
++
++ FWCalculateInputOrigin (grab->w, WIN_REAL_X (grab->w) +
++ WIN_REAL_W (grab->w) / 2.0f,
++ WIN_REAL_Y (grab->w) +
++ WIN_REAL_H (grab->w) / 2.0f);
++ FWCalculateOutputOrigin(grab->w,
++ WIN_OUTPUT_X (grab->w) +
++ WIN_OUTPUT_W (grab->w) / 2.0f,
++ WIN_OUTPUT_Y (grab->w) +
++ WIN_OUTPUT_H (grab->w) / 2.0f);
+
+- break;
+- default:
+- break;
+- }
++ break;
++ default:
++ break;
++ }
++
++ if (FWCanShape (grab->w))
++ if (FWHandleWindowInputInfo (grab->w))
++ FWAdjustIPW (grab->w);
+
+- if (FWCanShape (fwd->grabWindow))
+- if (FWHandleWindowInputInfo (fwd->grabWindow))
+- FWAdjustIPW (fwd->grabWindow);
+
+- removeScreenGrab(s, fws->grabIndex, 0);
+- fws->grabIndex = 0;
+- fwd->grabWindow = NULL;
+- fww->grab = grabNone;
+-
++ FWRemoveGrab (grab->w, dev);
++ fws->grabIndex = 0;
++
++ }
++ }
+ }
+ }
+ }
+
+- action->state &= ~ (CompActionStateTermKey | CompActionStateTermButton);
++ if (!fwd->grabs)
++ action->state &= ~ (CompActionStateTermKey | CompActionStateTermButton);
+
+ return FALSE;
+ }
+
+-/*static void FWMoveWindowToCorrectPosition (CompWindow *w, float distX, float distY)
+-{
+-
+- FREEWINS_WINDOW (w);
+-
+- fprintf(stderr, "distX is %f distY is %f midX and midY are %f %f\n", distX, distY, fww->iMidX, fww->iMidY);
+-
+- moveWindow (w, distX * (1 + (1 - fww->transform.scaleX)), distY * (1 + (1 - fww->transform.scaleY)), TRUE, FALSE);
+-
+- syncWindowPosition (w);
+-}*/
+-
+-
+ /* Initiate Scaling */
+ Bool
+ initiateFWScale (CompDisplay *d,
+- CompAction *action,
+- CompActionState state,
+- CompOption *option,
+- int nOption)
++ CompAction *action,
++ CompActionState state,
++ CompOption *option,
++ int nOption)
+ {
+-
+ CompWindow* w;
+ CompWindow *useW;
++ CompDevice *dev;
+ CompScreen* s;
+ FWWindowInputInfo *info;
+ Window xid, root;
+@@ -326,192 +347,205 @@ initiateFWScale (CompDisplay *d,
+ root = getIntOptionNamed (option, nOption, "root", 0);
+ s = findScreenAtDisplay (d, root);
+
+- if (s && w && useW)
++ int id = getIntOptionNamed (option, nOption, "device", -1);
++ dev = compFindDeviceById(d, id);
++
++ if (dev)
+ {
++ /* Check to see if the device is in-use */
++
++ FWGrab *check;
++
++ for (check = fwd->grabs; check; check = check->next)
++ {
++ if (check->dev->id == dev->id)
++ return FALSE;
++ }
++
++ if (s && w && useW)
++ {
+
+ FREEWINS_SCREEN (s);
+
+- for (info = fws->transformedWindows; info; info = info->next)
+- {
+- if (w->id == info->ipw)
++ for (info = fws->transformedWindows; info; info = info->next)
++ {
++ if (w->id == info->ipw)
+ /* The window we just grabbed was actually
+ * an IPW, get the real window instead
+ */
+- useW = FWGetRealWindow (w);
+- }
++ useW = FWGetRealWindow (w);
++ }
+
+ fws->rotateCursor = XCreateFontCursor (s->display->display, XC_plus);
+
+ if (!otherScreenGrabExist(s, "freewins", 0))
+- if (!fws->grabIndex)
+- fws->grabIndex = pushScreenGrab (s, fws->rotateCursor, "freewins");
++ FWCreateGrab (useW, dev, grabScale);
+
+ }
+
+ if (useW)
+- {
++ {
+ if (matchEval (freewinsGetShapeWindowTypes (useW->screen), useW))
+ {
+-
+- FREEWINS_WINDOW (useW);
++ FREEWINS_WINDOW (useW);
+
+- x = getIntOptionNamed (option, nOption, "x",
++ x = getIntOptionNamed (option, nOption, "x",
+ useW->attrib.x + (useW->width / 2));
+- y = getIntOptionNamed (option, nOption, "y",
++ y = getIntOptionNamed (option, nOption, "y",
+ useW->attrib.y + (useW->height / 2));
+
+- mods = getIntOptionNamed (option, nOption, "modifiers", 0);
+-
+- fwd->grabWindow = useW;
+-
+- /* Find out the corner we clicked in */
++ mods = getIntOptionNamed (option, nOption, "modifiers", 0);
+
+- float MidX = fww->inputRect.x1 + ((fww->inputRect.x2 - fww->inputRect.x1) / 2.0f);
+- float MidY = fww->inputRect.y1 + ((fww->inputRect.y2 - fww->inputRect.y1) / 2.0f);
++ /* Find out the corner we clicked in */
+
+- /* Check for Y axis clicking (Top / Bottom) */
+- if (pointerY > MidY)
+- {
+- /* Check for X axis clicking (Left / Right) */
+- if (pointerX > MidX)
+- fww->corner = CornerBottomRight;
+- else if (pointerX < MidX)
+- fww->corner = CornerBottomLeft;
+- }
+- else if (pointerY < MidY)
+- {
+- /* Check for X axis clicking (Left / Right) */
+- if (pointerX > MidX)
+- fww->corner = CornerTopRight;
+- else if (pointerX < MidX)
+- fww->corner = CornerTopLeft;
+- }
++ float MidX = fww->inputRect.x1 + ((fww->inputRect.x2 - fww->inputRect.x1) / 2.0f);
++ float MidY = fww->inputRect.y1 + ((fww->inputRect.y2 - fww->inputRect.y1) / 2.0f);
+
++ /* Check for Y axis clicking (Top / Bottom) */
++ if (dev->pointerY > MidY)
++ {
++ /* Check for X axis clicking (Left / Right) */
++ if (dev->pointerX > MidX)
++ fww->corner = CornerBottomRight;
++ else if (dev->pointerX < MidX)
++ fww->corner = CornerBottomLeft;
++ }
++ else if (pointerY < MidY)
++ {
++ /* Check for X axis clicking (Left / Right) */
++ if (dev->pointerX > MidX)
++ fww->corner = CornerTopRight;
++ else if (dev->pointerX < MidX)
++ fww->corner = CornerTopLeft;
++ }
+
+- switch (freewinsGetScaleMode (w->screen))
+- {
+- case ScaleModeToCentre:
+- FWCalculateInputOrigin(useW, WIN_REAL_X (w) + WIN_REAL_W (w) / 2.0f,
+- WIN_REAL_Y (useW) + WIN_REAL_H (useW) / 2.0f);
+- FWCalculateOutputOrigin(useW, WIN_OUTPUT_X (w) + WIN_OUTPUT_W (w) / 2.0f,
+- WIN_OUTPUT_Y (w) + WIN_OUTPUT_H (w) / 2.0f);
+- break;
+- /**
+- *Experimental scale to corners mode
+- */
+- case ScaleModeToOppositeCorner:
++ switch (freewinsGetScaleMode (w->screen))
++ {
++ case ScaleModeToCentre:
++ FWCalculateInputOrigin(useW, WIN_REAL_X (w) + WIN_REAL_W (w) / 2.0f,
++ WIN_REAL_Y (useW) + WIN_REAL_H (useW) / 2.0f);
++ FWCalculateOutputOrigin(useW, WIN_OUTPUT_X (w) + WIN_OUTPUT_W (w) / 2.0f,
++ WIN_OUTPUT_Y (w) + WIN_OUTPUT_H (w) / 2.0f);
++ break;
++ /**
++ * Experimental scale to corners mode
++ */
++ case ScaleModeToOppositeCorner:
+ switch (fww->corner)
+ {
+ case CornerBottomRight:
+- /* Translate origin to the top left of the window */
+- //FWMoveWindowToCorrectPosition (w, fww->inputRect.x1 - WIN_REAL_X (useW), fww->inputRect.y1 - WIN_REAL_Y (useW));
+- FWCalculateInputOrigin (useW, WIN_REAL_X (useW), WIN_REAL_Y (useW));
+- break;
++ /* Translate origin to the top left of the window */
++ FWCalculateInputOrigin (useW, WIN_REAL_X (useW), WIN_REAL_Y (useW));
++ break;
+ case CornerBottomLeft:
+- /* Translate origin to the top right of the window */
+- //FWMoveWindowToCorrectPosition (w, fww->inputRect.x2 - (WIN_REAL_X (useW) + WIN_REAL_W (useW)), fww->inputRect.y1 - WIN_REAL_Y (useW));
+- FWCalculateInputOrigin (useW, WIN_REAL_X (useW) + (WIN_REAL_W (useW)), WIN_REAL_Y (useW));
+- break;
++ /* Translate origin to the top right of the window */
++ FWCalculateInputOrigin (useW, WIN_REAL_X (useW) + (WIN_REAL_W (useW)), WIN_REAL_Y (useW));
++ break;
+ case CornerTopRight:
+- /* Translate origin to the bottom left of the window */
+- //FWMoveWindowToCorrectPosition (w, fww->inputRect.x1 - WIN_REAL_X (useW) , fww->inputRect.y1 - (WIN_REAL_Y (useW) + WIN_REAL_H (useW)));
+- FWCalculateInputOrigin (useW, WIN_REAL_X (useW), WIN_REAL_Y (useW) + (WIN_REAL_H (useW)));
+- break;
++ /* Translate origin to the bottom left of the window */
++ FWCalculateInputOrigin (useW, WIN_REAL_X (useW), WIN_REAL_Y (useW) + (WIN_REAL_H (useW)));
++ break;
+ case CornerTopLeft:
+- /* Translate origin to the bottom right of the window */
+- //FWMoveWindowToCorrectPosition (w, fww->inputRect.x1 -(WIN_REAL_X (useW) + WIN_REAL_W (useW)) , fww->inputRect.y1 - (WIN_REAL_Y (useW) + WIN_REAL_H (useW)));
+- FWCalculateInputOrigin (useW, WIN_REAL_X (useW) + (WIN_REAL_W (useW)), WIN_REAL_Y (useW) + (WIN_REAL_H (useW)));
+- break;
+- }
+- break;
+- }
+-
+- fww->grab = grabScale;
++ /* Translate origin to the bottom right of the window */
++ FWCalculateInputOrigin (useW, WIN_REAL_X (useW) + (WIN_REAL_W (useW)), WIN_REAL_Y (useW) + (WIN_REAL_H (useW)));
++ break;
++ }
++ default:
++ break;
++ }
+
+- /* Announce that we grabbed the window */
++ /* Announce that we grabbed the window */
+
+- (w->screen->windowGrabNotify) (w, x, y, mods,
+- CompWindowGrabMoveMask |
+- CompWindowGrabButtonMask);
++ (w->screen->windowGrabNotify) (w, x, y, mods,
++ CompWindowGrabMoveMask |
++ CompWindowGrabButtonMask);
+
+- /*Shape the window beforehand and avoid a stale grab*/
+- if (FWCanShape (useW))
+- if (FWHandleWindowInputInfo (useW))
+- FWAdjustIPW (useW);
+-
+- if (state & CompActionStateInitButton)
+- action->state |= CompActionStateTermButton;
++ /* Shape the window beforehand and avoid a stale grab*/
++ if (FWCanShape (useW))
++ if (FWHandleWindowInputInfo (useW))
++ FWAdjustIPW (useW);
++
++ if (state & CompActionStateInitButton)
++ action->state |= CompActionStateTermButton;
+
+- if (state & CompActionStateInitKey)
++ if (state & CompActionStateInitKey)
+ action->state |= CompActionStateTermKey;
+-
++
+ }
+ }
++ }
+
+ return TRUE;
+ }
+
++// check to see if the deviceID is still in use, if so bail out.
++
+ Bool
+ terminateFWScale (CompDisplay *d,
+- CompAction *action,
+- CompActionState state,
+- CompOption *option,
+- int nOption)
++ CompAction *action,
++ CompActionState state,
++ CompOption *option,
++ int nOption)
+ {
+-
+ FREEWINS_DISPLAY (d);
+
+ CompScreen *s;
++ CompDevice *dev;
++ FWGrab *grab;
++ int id;
++
++ id = getIntOptionNamed (option, nOption, "device", -1);
++ dev = compFindDeviceById (d, id);
++
++ for (grab = fwd->grabs; grab; grab = grab->next)
++ {
++ if (grab->dev->id == dev->id)
++ break;
++ }
+
+ for (s = d->screens; s; s = s->next)
+ {
+- FREEWINS_SCREEN (s);
+
+- if (fwd->grabWindow && fws->grabIndex)
++ if (grab->w)
+ {
+- FREEWINS_WINDOW (fwd->grabWindow);
+- if (fww->grab == grabScale)
++ FREEWINS_WINDOW (grab->w);
++
++ if (grab->type == grabScale)
+ {
+- (fwd->grabWindow->screen->windowUngrabNotify) (fwd->grabWindow);
++ (grab->w->screen->windowUngrabNotify) (grab->w);
+
+- if (FWCanShape (fwd->grabWindow))
+- if (FWHandleWindowInputInfo (fwd->grabWindow))
+- FWAdjustIPW (fwd->grabWindow);
++ if (FWCanShape (grab->w))
++ if (FWHandleWindowInputInfo (grab->w))
++ FWAdjustIPW (grab->w);
+
+- switch (freewinsGetScaleMode (fwd->grabWindow->screen))
++ switch (freewinsGetScaleMode (grab->w->screen))
+ {
+ int distX, distY;
+
+ case ScaleModeToOppositeCorner:
+- distX = (fww->outputRect.x1 + (fww->outputRect.x2 - fww->outputRect.x1) / 2.0f) - (WIN_REAL_X (fwd->grabWindow) + WIN_REAL_W (fwd->grabWindow) / 2.0f);
+- distY = (fww->outputRect.y1 + (fww->outputRect.y2 - fww->outputRect.y1) / 2.0f) - (WIN_REAL_Y (fwd->grabWindow) + WIN_REAL_H (fwd->grabWindow) / 2.0f);
+-
+- moveWindow(fwd->grabWindow, distX, distY, TRUE, TRUE);
+- syncWindowPosition (fwd->grabWindow);
+-
+- FWCalculateInputOrigin (fwd->grabWindow, WIN_REAL_X (fwd->grabWindow) +
+- WIN_REAL_W (fwd->grabWindow) / 2.0f,
+- WIN_REAL_Y (fwd->grabWindow) +
+- WIN_REAL_H (fwd->grabWindow) / 2.0f);
+- FWCalculateOutputOrigin (fwd->grabWindow, WIN_OUTPUT_X (fwd->grabWindow) +
+- WIN_OUTPUT_W (fwd->grabWindow) / 2.0f,
+- WIN_OUTPUT_Y (fwd->grabWindow) +
+- WIN_OUTPUT_H (fwd->grabWindow) / 2.0f);
+-
++ distX = (fww->outputRect.x1 + (fww->outputRect.x2 - fww->outputRect.x1) / 2.0f) - (WIN_REAL_X (grab->w) + WIN_REAL_W (grab->w) / 2.0f);
++ distY = (fww->outputRect.y1 + (fww->outputRect.y2 - fww->outputRect.y1) / 2.0f) - (WIN_REAL_Y (grab->w) + WIN_REAL_H (grab->w) / 2.0f);
++ moveWindow(grab->w, distX, distY, TRUE, TRUE);
++ syncWindowPosition (grab->w);
++ FWCalculateInputOrigin(grab->w, WIN_REAL_X (grab->w) +
++ WIN_REAL_W (grab->w) / 2.0f,
++ WIN_REAL_Y (grab->w) +
++ WIN_REAL_H (grab->w) / 2.0f);
++ FWCalculateOutputOrigin(grab->w, WIN_OUTPUT_X (grab->w) +
++ WIN_OUTPUT_W (grab->w) / 2.0f,
++ WIN_OUTPUT_Y (grab->w) +
++ WIN_OUTPUT_H (grab->w) / 2.0f);
+ break;
+- default:
++ default:
+ break;
+-
+ }
+
+- removeScreenGrab(s, fws->grabIndex, 0);
+- fws->grabIndex = 0;
+- fwd->grabWindow = NULL;
+- fww->grab = grabNone;
++ FWRemoveGrab(grab->w, dev);
+ }
+ }
+ }
+
++ if (!fwd->grabs)
+ action->state &= ~ (CompActionStateTermKey | CompActionStateTermButton);
+
+ return FALSE;
+diff --git a/events.c b/events.c
+index 61f5e2b..16781cb 100644
+--- a/events.c
++++ b/events.c
+@@ -493,6 +493,213 @@ static void FWHandleScaleMotionEvent (CompWindow *w, float dx, float dy, int x,
+ FWHandleSnap(w);
+ }
+
++
++/* Handled as grabs per window */
++
++static void
++FWHandleMPMotionEvent (CompDisplay *d, CompWindow *w)
++{
++ int nDyDx = 1;
++ int nGrab = 0;
++ FWGrab *counter;
++ FWGrab *grab;
++ Bool typex = TRUE; /* Too lazy to implement and enum here, TRUE = First, FALSE = Second */
++ Bool typey = TRUE; /* Too lazy to implement and enum here, TRUE = First, FALSE = Second */
++
++ FREEWINS_DISPLAY (d);
++ FREEWINS_WINDOW (w);
++
++ for (counter = fwd->grabs; counter; counter = counter->next)
++ if (counter->w->id == w->id)
++ nDyDx++;
++
++ int dx[nDyDx];
++ int dy[nDyDx];
++
++ /* This algorithm works as follows:
++ * With one pointer, we are only able to achieve rotation on two planes,
++ * whether that be X / Y, X / Z or Y / Z or X, Y, Z on thier own. This
++ * is because the mouse is only a 2D input device, hence we can only recognize
++ * motion in 2 Directions. However with multiple input devices, we can
++ * recognize certain movement patterns that would allow us to do X, Y and
++ * Z at the same time.
++ *
++ * The first is all pointers in the same direction. This is a kind of push and
++ * pushes the rotation in that direction on the X / Y axis.
++ *
++ * The second is both pointers moving away from or towards each other. This
++ * action triggers two things. The first is scaling, if up/down then scale on
++ * Y and vice versa for X. Also it triggers z Rotation if the angle with the
++ * center of the window changes.
++ */
++
++ Bool lastX = fwd->grabs->directionX, lastY = fwd->grabs->directionY;
++
++ for (grab = fwd->grabs; grab; grab = grab->next)
++ if (grab->w->id == w->id)
++ {
++ dx[nGrab] = grab->dev->pointerX - grab->dev->lastPointerX;
++ dy[nGrab] = grab->dev->pointerY - grab->dev->lastPointerY;
++ nGrab++;
++
++ if (lastX != grab->directionX)
++ typex = FALSE;
++
++ if (lastY != grab->directionY)
++ typey = FALSE;
++
++ }
++ /* This is kind of static at the moment, check to see if the devices are moving away
++ * from each other, they could be moving up, but away from each other at the same time
++ * that calls for some interesting stuff =)
++ */
++
++ if (typex)
++ {
++ int totalDx = 0;
++ for (nGrab = 0; nGrab < (nDyDx - 1); nGrab++)
++ {
++ totalDx += dy[nGrab];
++ }
++ fww->animate.destAngX -= totalDx;
++ }
++ else
++ {
++
++ /* Z rotation */
++
++ float totalDAngle;
++ float distX, distY;
++ float dDistX, dDistY;
++ int maxX = 0, maxY = 0;
++ int minX = fwd->grabs->dev->pointerX, minY = fwd->grabs->dev->pointerY;
++ float lastdistX, lastdistY;
++ int lastmaxX = 0, lastmaxY = 0;
++ int lastminX = fwd->grabs->dev->lastPointerX, lastminY = fwd->grabs->dev->lastPointerY;
++ for (grab = fwd->grabs; grab; grab = grab->next)
++ {
++ float oldAngle, newAngle, dAngle;
++ if (grab->dev)
++ {
++ oldAngle = atan((grab->dev->lastPointerX - fww->iMidX) /
++ (grab->dev->lastPointerY - fww->iMidY));
++ newAngle = atan((grab->dev->pointerX - fww->iMidX) /
++ (grab->dev->pointerY - fww->iMidY));
++ dAngle = newAngle - oldAngle;
++
++ /* Scaling */
++
++ if (grab->dev->lastPointerX > lastmaxX)
++ lastmaxX = grab->dev->lastPointerX;
++ if (grab->dev->lastPointerY > lastmaxY)
++ lastmaxY = grab->dev->lastPointerY;
++
++ if (grab->dev->lastPointerX < lastminX)
++ lastminX = grab->dev->lastPointerX;
++ if (grab->dev->lastPointerY < lastminY)
++ lastminY = grab->dev->lastPointerY;
++
++ if (grab->dev->pointerX > maxX)
++ maxX = grab->dev->pointerX;
++ if (grab->dev->pointerY > maxY)
++ maxY = grab->dev->pointerY;
++
++ if (grab->dev->pointerX < minX)
++ minX = grab->dev->pointerX;
++ if (grab->dev->pointerY < minY)
++ minY = grab->dev->pointerY;
++
++ fww->can2D = TRUE;
++ fww->animate.destAngZ += grab->dev->pointerX - grab->dev->lastPointerX;
++
++ }
++ totalDAngle += dAngle;
++ }
++
++ distX = maxX - minX;
++ distY = maxY - minY;
++
++ lastdistX = lastmaxX - lastminX;
++ lastdistY = lastmaxY - lastminY;
++
++ dDistX = distX - lastdistX;
++ dDistY = distY - lastdistY;
++
++ fww->animate.destScaleX += dDistX / 1000 /* WAAAYYYY too sensitive :P */;
++ fww->animate.destScaleY += dDistY / 1000;
++
++ }
++ if (typey)
++ {
++
++ int totalDx = 0;
++ for (nGrab = 0; nGrab < (nDyDx - 1); nGrab++)
++ {
++ totalDx += dx[nGrab];
++ }
++ fww->animate.destAngY += totalDx;
++ }
++ else
++ {
++ /* Z rotation */
++
++ float totalDAngle;
++ float distX, distY;
++ float dDistX, dDistY;
++ int maxX = 0, maxY = 0;
++ int minX = fwd->grabs->dev->pointerX, minY = fwd->grabs->dev->pointerY;
++ float lastdistX, lastdistY;
++ int lastmaxX = 0, lastmaxY = 0;
++ int lastminX = fwd->grabs->dev->lastPointerX, lastminY = fwd->grabs->dev->lastPointerY;
++ for (grab = fwd->grabs; grab; grab = grab->next)
++ {
++ float oldAngle, newAngle, dAngle;
++ if (grab->dev)
++ {
++ oldAngle = atan((grab->dev->lastPointerX - fww->iMidX) /
++ (grab->dev->lastPointerY - fww->iMidY));
++ newAngle = atan((grab->dev->pointerX - fww->iMidX) /
++ (grab->dev->pointerY - fww->iMidY));
++ dAngle = newAngle - oldAngle;
++
++ /* Scaling */
++
++ if (grab->dev->lastPointerX > lastmaxX)
++ lastmaxX = grab->dev->lastPointerX;
++ if (grab->dev->lastPointerY > lastmaxY)
++ lastmaxY = grab->dev->lastPointerY;
++
++ if (grab->dev->lastPointerX < lastminX)
++ lastminX = grab->dev->lastPointerX;
++ if (grab->dev->lastPointerY < lastminY)
++ lastminY = grab->dev->lastPointerY;
++
++ if (grab->dev->pointerX > maxX)
++ maxX = grab->dev->pointerX;
++ if (grab->dev->pointerY > maxY)
++ maxY = grab->dev->pointerY;
++
++ if (grab->dev->pointerX < minX)
++ minX = grab->dev->pointerX;
++ if (grab->dev->pointerY < minY)
++ minY = grab->dev->pointerY;
++
++ }
++ totalDAngle += dAngle;
++ }
++
++ distX = maxX - minX;
++ distY = maxY - minY;
++
++ lastdistX = lastmaxX - lastminX;
++ lastdistY = lastmaxY - lastminY;
++
++ dDistX = distX - lastdistX;
++ dDistY = distY - lastdistY;
++ }
++
++}
++
+ static void
+ FWHandleButtonReleaseEvent (CompWindow *w)
+ {
+@@ -817,8 +1024,97 @@ void FWHandleEvent(CompDisplay *d, XEvent *ev){
+ }
+ }
+ }
++ if (ev->type == d->xi_motion)
++ {
++ XDeviceMotionEvent* mev = (XDeviceMotionEvent*)ev;
++
++ CompDevice *dev = compFindDeviceById (d, mev->deviceid);
++
++ if (dev)
++ {
++
++ FWGrab *grab = FWGrabForDevice (d, dev);
++ FWGrab *count;
++
++ if (grab)
++ {
++
++ CompWindow *win = grab->w;
++
++ if (win)
++ {
++
++ dx = ((float)(dev->pointerX - dev->lastPointerX) / win->screen->width) * \
++ freewinsGetMouseSensitivity (win->screen);
++ dy = ((float)(dev->pointerY - dev->lastPointerY) / win->screen->height) * \
++ freewinsGetMouseSensitivity (win->screen);
++
++ if (dx > 0)
++ grab->directionX = TRUE;
++ else if (dx < 0)
++ grab->directionX = FALSE;
++
++ if (dy > 0)
++ grab->directionY = TRUE;
++ else if (dy < 0)
++ grab->directionY = FALSE;
++
++ int nGrabs = 0;
++
++ for (count = fwd->grabs; count; count = count->next)
++ if (count->w == win)
++ nGrabs++;
++
++ if (nGrabs > 1)
++ FWHandleMPMotionEvent (win->screen->display, win);
++ else
++ {
++ if (matchEval (freewinsGetShapeWindowTypes (win->screen), win))
++ {
++ if (grab->type == grabMove || grab->type == grabResize)
++ {
++ FREEWINS_SCREEN (win->screen);
++ FWWindowInputInfo *info;
++ CompWindow *w = win;
++ for (info = fws->transformedWindows; info; info = info->next)
++ {
++ if (win->id == info->ipw)
++ /* The window we just grabbed was actually
++ * an IPW, get the real window instead
++ */
++ w = FWGetRealWindow (win);
++ }
++ switch (grab->type)
++ {
++ case grabMove:
++ FWHandleIPWMoveMotionEvent (w, dev->pointerX, dev->pointerY); break;
++ case grabResize:
++ FWHandleIPWResizeMotionEvent (w, dev->pointerX, dev->pointerY); break;
++ default:
++ break;
++ }
++ }
++
++ if (grab->type == grabRotate)
++ {
++ FWHandleRotateMotionEvent(win, dx, dy, dev->pointerX, dev->pointerY);
++ }
++ if (grab->type == grabScale)
++ {
++ FWHandleScaleMotionEvent(win, dx * 3, dy * 3, dev->pointerX, dev->pointerY);
++ }
++
++ if(dx != 0.0 || dy != 0.0)
++ FWDamageArea (win);
++ }
++ }
++ }
++ }
++ }
++ }
++ break;
+ }
+-
++
+ UNWRAP(fwd, d, handleEvent);
+ (*d->handleEvent)(d, ev);
+ WRAP(fwd, d, handleEvent, FWHandleEvent);
+diff --git a/freewins.c b/freewins.c
+index 26d83d9..aeb2a21 100644
+--- a/freewins.c
++++ b/freewins.c
+@@ -338,6 +338,9 @@ freewinsInitDisplay (CompPlugin *p,
+ fwd->lastGrabWindow = 0;
+ fwd->axisHelp = FALSE;
+ fwd->hoverWindow = 0;
++
++ fwd->nGrab = 0;
++ fwd->grabs = NULL;
+
+ if ((fwd->screenPrivateIndex = allocateScreenPrivateIndex (d)) < 0 )
+ {
+diff --git a/freewins.h b/freewins.h
+index a534d0f..4f88496 100644
+--- a/freewins.h
++++ b/freewins.h
+@@ -187,6 +187,19 @@ typedef struct _FWTrackball
+
+ } FWTrackball;
+
++typedef struct _FWGrab
++{
++ CompWindow *w;
++ CompDevice *dev;
++ int grabIndex;
++ FWGrabType type;
++ FWAxisType axis;
++ Cursor cursor;
++ Bool directionX; /* TRUE = Right, FALSE = Left */
++ Bool directionY; /* TRUE = Up. FALSE = Down */
++ struct _FWGrab *next;
++} FWGrab;
++
+ /* Transformation info */
+ typedef struct _FWTransformedWindowInfo
+ {
+@@ -261,6 +274,9 @@ typedef struct _FWDisplay
+ CompWindow *hoverWindow;
+ CompWindow *lastGrabWindow;
+
++ FWGrab *grabs;
++ int nGrab;
++
+ Bool axisHelp;
+ Bool snap;
+ Bool invert;
+@@ -537,6 +553,17 @@ void FWAdjustIPW (CompWindow *w);
+
+ void FWAdjustIPWStacking (CompScreen *s);
+
++/* grab.c */
++
++Bool FWCreateGrab (CompWindow *w,
++ CompDevice *dev,
++ FWGrabType type);
++
++Bool FWRemoveGrab (CompWindow *w, CompDevice *dev);
++
++FWGrab* FWGrabForDevice (CompDisplay *d,
++ CompDevice *dev);
++
+ /* util.c */
+
+ void
+--
+1.5.6
+
diff --git a/fusion/plugins/freewins/0002-Input-Redirection-Support.patch b/fusion/plugins/freewins/0002-Input-Redirection-Support.patch
new file mode 100644
index 0000000..2b490ef
--- /dev/null
+++ b/fusion/plugins/freewins/0002-Input-Redirection-Support.patch
@@ -0,0 +1,164 @@
+From cfce9126a9b7f14e8f45106fc8ab7a5326622248 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Fri, 31 Oct 2008 18:33:43 +0900
+Subject: [PATCH] Input Redirection Support
+
+---
+ events.c | 34 ++++++++++++++++++++++++++++++++++
+ freewins.h | 10 +++++++++-
+ freewins.xml.in | 25 ++++++++++++++++++++-----
+ input.c | 9 +++++++--
+ util.c | 2 +-
+ 5 files changed, 71 insertions(+), 9 deletions(-)
+
+diff --git a/events.c b/events.c
+index 16781cb..3a59ee2 100644
+--- a/events.c
++++ b/events.c
+@@ -1136,3 +1136,37 @@ void FWHandleEvent(CompDisplay *d, XEvent *ev){
+ break;
+ }
+ }
++
++void
++FWTransformMesh (CompWindow *w,
++ CompTransform *transform,
++ CompMesh *mesh,
++ int meshIter,
++ Bool needsProjection)
++{
++ CompTransform FWTransform = *transform;
++ Bool project = needsProjection;
++
++ FREEWINS_SCREEN (w->screen);
++ FREEWINS_WINDOW (w);
++
++ if (fww->transformed)
++ {
++
++ FWModifyMatrix (w, &FWTransform,
++ fww->transform.angX,
++ fww->transform.angY,
++ fww->transform.angZ,
++ fww->iMidX, fww->iMidY , 0.0f,
++ fww->transform.scaleX, fww->transform.scaleY, 1.0f, 0.0f, 0.0f);
++
++ }
++
++ if ((fww->transform.angX > 0.0f || fww->transform.angX < 0.0f) ||
++ (fww->transform.angY > 0.0f || fww->transform.angY < 0.0f))
++ project = TRUE;
++
++ UNWRAP (fws, w->screen, transformMesh);
++ (*w->screen->transformMesh) (w, &FWTransform, mesh, meshIter, project);
++ WRAP (fws, w->screen, transformMesh, FWTransformMesh);
++}
+diff --git a/freewins.h b/freewins.h
+index 4f88496..247b79f 100644
+--- a/freewins.h
++++ b/freewins.h
+@@ -301,6 +301,8 @@ typedef struct _FWScreen
+ WindowResizeNotifyProc windowResizeNotify;
+ WindowMoveNotifyProc windowMoveNotify;
+
++ TransformMeshProc transformMesh;
++
+ FWWindowInputInfo *transformedWindows;
+
+ Cursor rotateCursor;
+@@ -537,9 +539,15 @@ Bool toggleFWAxis (CompDisplay *d,
+
+ /* event.c */
+
+- void FWHandleEvent (CompDisplay *d,
++void FWHandleEvent (CompDisplay *d,
+ XEvent *ev);
+
++void FWTransformMesh (CompWindow *w,
++ CompTransform *transform,
++ CompMesh *mesh,
++ int nMesh,
++ Bool needsProjection);
++
+ /* input.c */
+
+ /** Use FWHandleWindowInputInfo() instead
+diff --git a/freewins.xml.in b/freewins.xml.in
+index fe87124..a1ffe0a 100644
+--- a/freewins.xml.in
++++ b/freewins.xml.in
+@@ -262,7 +262,7 @@
+ <option type="int" name="rotation_axis">
+ <_short>Rotation Axis</_short>
+ <_long>How Freely Transformable Windows should determine the rotation axis</_long>
+- <desc>
++ <desc>
+ <value>0</value><name>Always Centre</name>
+ </desc>
+ <desc>
+@@ -339,10 +339,25 @@
+ <_long>Window types that should be Shaped. Disable problematic windows here</_long>
+ <default>(Toolbar | Utility | Dialog | ModalDialog | Normal)</default>
+ </option>
+- <option type="bool" name="shape_input">
+- <_short>Prevent input</_short>
+- <_long>Prevent input in transformed windows</_long>
+- <default>True</default>
++ <option type="int" name="input_handling_mode">
++ <_short>Input Handling Mode</_short>
++ <_long>How freewins should handle input</_long>
++ <desc>
++ <value>0</value><name>Dont Handle</name>
++ </desc>
++ <desc>
++ <value>1</value><name>Just Shape</name>
++ </desc>
++ <desc>
++ <value>2</value><name>Prevent Input</name>
++ </desc>
++ <desc>
++ <value>3</value><name>Fake Redirection</name>
++ </desc>
++ <desc>
++ <value>4</value><name>Real Redirection</name>
++ </desc>
++ <default>2</default>
+ </option>
+ <option type="bool" name="immediate_moves">
+ <_short>Immediate Moves</_short>
+diff --git a/input.c b/input.c
+index 5a11efa..daa66b8 100644
+--- a/input.c
++++ b/input.c
+@@ -425,8 +425,13 @@ FWHandleWindowInputInfo (CompWindow *w)
+ return FALSE;
+
+ fww->input->w = w;
+- FWShapeInput (w);
+- FWCreateIPW (w);
++ if (freewinsGetInputHandlingMode (w->screen) != InputHandlingModeRealRedirection)
++ {
++ if (freewinsGetInputHandlingMode (w->screen) > 0)
++ FWShapeInput (w);
++ if (freewinsGetInputHandlingMode (w->screen) > 1)
++ FWCreateIPW (w);
++ }
+ FWAddWindowToList (fww->input);
+ }
+
+diff --git a/util.c b/util.c
+index 0ef58eb..7b860e4 100644
+--- a/util.c
++++ b/util.c
+@@ -499,7 +499,7 @@ Bool
+ FWCanShape (CompWindow *w)
+ {
+
+- if (!freewinsGetShapeInput (w->screen))
++ if (freewinsGetInputHandlingMode (w->screen) < 1)
+ return FALSE;
+
+ if (!w->screen->display->shapeExtension)
+--
+1.5.6
+
diff --git a/fusion/plugins/ghost/0001--MPX-Inclusion.patch b/fusion/plugins/ghost/0001--MPX-Inclusion.patch
new file mode 100644
index 0000000..c54d055
--- /dev/null
+++ b/fusion/plugins/ghost/0001--MPX-Inclusion.patch
@@ -0,0 +1,85 @@
+From d654fcde1d578c22acfeef56f1df801e69cd63b0 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Wed, 29 Oct 2008 15:24:11 +0900
+Subject: [PATCH] * MPX Inclusion
+
+---
+ ghost.c | 40 ++++++++++++++++++++++++----------------
+ 1 files changed, 24 insertions(+), 16 deletions(-)
+
+diff --git a/ghost.c b/ghost.c
+index 7f76aa5..84a275c 100644
+--- a/ghost.c
++++ b/ghost.c
+@@ -364,6 +364,7 @@ ghostPreparePaintScreen (CompScreen *s,
+ {
+ if (gw->animate == ANIMATE_DOWN)
+ {
++ fprintf(stderr, "animating a window\n");
+ gw->opacity = fmax(gw->opacity - (gw->opacity - topacity) * ms * SPEED,topacity);
+ gw->saturation = fmax(gw->saturation - (gw->saturation - tsat) * ms * SPEED,tsat );
+ gw->brightness = fmax(gw->brightness - (gw->brightness - tbright) * ms * SPEED,tbright );
+@@ -400,29 +401,36 @@ ghostPreparePaintScreen (CompScreen *s,
+ }
+
+ static void
+-positionUpdate (CompScreen *s, int x, int y)
++positionUpdate (CompScreen *s, MousepollDevice *mDev)
+ {
+ CompWindow *w;
+ if (!ghostGetFadeOnMouseover(s->display))
+ return;
+ if (otherScreenGrabExist(s, "ghost", 0))
+ return;
+- for (w = s->windows; w; w = w->next)
++
++ for (; mDev; mDev = mDev->next)
+ {
+- GHOST_WINDOW (w);
+- if(gw->isghost &&
+- x > WIN_X(w) &&
+- x < WIN_X(w) + WIN_W(w) &&
+- y > WIN_Y(w) &&
+- y < WIN_Y(w) + WIN_H(w))
++ for (w = s->windows; w; w = w->next)
+ {
+- gw->faded = TRUE;
+- gw->animate = ANIMATE_DOWN;
+- addWindowDamage (w);
+- } else {
+- gw->faded = FALSE;
+- gw->animate = ANIMATE_UP;
+- addWindowDamage (w);
++ GHOST_WINDOW (w);
++ if(gw->isghost &&
++ mDev->posX > WIN_X(w) &&
++ mDev->posX < WIN_X(w) + WIN_W(w) &&
++ mDev->posY > WIN_Y(w) &&
++ mDev->posY < WIN_Y(w) + WIN_H(w))
++ {
++ fprintf(stderr, "cursor is in window -- fading down\n");
++ gw->faded = TRUE;
++ gw->animate = ANIMATE_DOWN;
++ addWindowDamage (w);
++ }
++ else
++ {
++ gw->faded = FALSE;
++ gw->animate = ANIMATE_UP;
++ addWindowDamage (w);
++ }
+ }
+ }
+ }
+@@ -518,7 +526,7 @@ ghostInitScreen (CompPlugin *p,
+ gs->windowPrivateIndex = allocateWindowPrivateIndex (s);
+ s->base.privates[gd->screenPrivateIndex].ptr = gs;
+
+- gs->pollHandle = (*gd->mpFunc->addPositionPolling) (s, positionUpdate);
++ gs->pollHandle = (*gd->mpFunc->addPositionPolling) (s, NULL, positionUpdate);
+
+ return TRUE;
+ }
+--
+1.5.6
+
diff --git a/fusion/plugins/group/0001-MPX-Support.patch b/fusion/plugins/group/0001-MPX-Support.patch
new file mode 100644
index 0000000..38ee4db
--- /dev/null
+++ b/fusion/plugins/group/0001-MPX-Support.patch
@@ -0,0 +1,1533 @@
+From e2c33b2c30b966dd2bb6deddf78f53aa64f74462 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Fri, 31 Oct 2008 16:38:19 +0900
+Subject: [PATCH] MPX Support
+
+---
+ group-internal.h | 18 ++
+ group.c | 496 ++++++++++++++++++++++++++++++++++++++++++++++--------
+ paint.c | 148 ++++++++++++-----
+ selection.c | 119 ++++++++++---
+ tab.c | 186 +++++++++++++++++++--
+ 5 files changed, 818 insertions(+), 149 deletions(-)
+
+diff --git a/group-internal.h b/group-internal.h
+index f3d4244..baed490 100644
+--- a/group-internal.h
++++ b/group-internal.h
+@@ -378,6 +378,22 @@ typedef struct _GroupResizeInfo {
+ XRectangle origGeometry;
+ } GroupResizeInfo;
+
++typedef struct _GroupGrab {
++ CompDevice *dev;
++ GroupScreenGrabState state;
++ int grabIndex;
++
++ int x1, x2, y1, y2;
++
++ GroupTabBarSlot *draggedSlot;
++ CompTimeoutHandle dragHoverTimeoutHandle;
++ Bool dragged;
++ int prevX, prevY; /* Buffer for mouse coordinates */
++
++ struct _GroupGrab *next;
++} GroupGrab;
++
++
+ /*
+ * GroupDisplay structure
+ */
+@@ -428,6 +444,8 @@ typedef struct _GroupScreen {
+ GroupSelection *groups;
+ GroupSelection tmpSel;
+
++ GroupGrab *grabs;
++
+ Bool queued;
+
+ GroupScreenGrabState grabState;
+diff --git a/group.c b/group.c
+index 3a1d4e0..e73796b 100644
+--- a/group.c
++++ b/group.c
+@@ -257,6 +257,125 @@ groupGrabScreen (CompScreen *s,
+ gs->grabState = newState;
+ }
+
++/* Device Management */
++
++/*
++ * groupGrabDevice
++ *
++ */
++
++static void
++groupRemoveGrab (CompScreen *s,
++ GroupGrab *grab)
++{
++ GroupGrab *run;
++ GROUP_SCREEN (s);
++
++ if (!gs->grabs)
++ return;
++
++ for (run = gs->grabs; run; run = run->next)
++ if (run == grab)
++ break;
++
++ if (run == gs->grabs)
++ {
++ if (gs->grabs->next)
++ gs->grabs = gs->grabs->next;
++ else
++ gs->grabs = NULL;
++ }
++ else
++ {
++ if (run->next)
++ run = run->next;
++ else
++ run = NULL;
++ }
++
++ if (grab)
++ free (grab);
++}
++
++GroupGrab *
++groupAddGrab (CompScreen *s)
++{
++ GroupGrab *run;
++ GroupGrab *grab;
++ GROUP_SCREEN (s);
++
++ if (!gs->grabs)
++ {
++ gs->grabs = calloc (1, sizeof (GroupGrab));
++ if (!gs->grabs)
++ return NULL;
++ gs->grabs->next = NULL;
++ grab = gs->grabs;
++ return grab;
++ }
++ else
++ {
++ for (run = gs->grabs; run->next; run = run->next);
++
++ run->next = calloc (1, sizeof (GroupGrab));
++ if (!run->next)
++ return NULL;
++ run->next->next = NULL;
++ grab = run->next;
++ return grab;
++ }
++}
++
++void
++groupGrabDevice (CompScreen *s,
++ CompDevice *dev,
++ GroupGrab *grab,
++ GroupScreenGrabState newState)
++{
++ if (grab)
++ {
++ if ((grab->state != newState) && grab->grabIndex)
++ {
++ removeDeviceGrab (s, dev, grab->grabIndex, NULL);
++ grab->grabIndex = 0;
++
++ switch (newState)
++ {
++ case ScreenGrabSelect:
++ grab->grabIndex = pushDeviceGrab (s, dev, None, "group");
++ break;
++ case ScreenGrabTabDrag:
++ grab->grabIndex = pushDeviceGrab (s, dev, None, "group-drag");
++ break;
++ case ScreenGrabNone:
++ groupRemoveGrab (s, grab);
++ break;
++ default:
++ break;
++ }
++ }
++ else
++ {
++ grab->dev = dev;
++ grab->state = newState;
++ switch (newState)
++ {
++ case ScreenGrabSelect:
++ grab->grabIndex = pushDeviceGrab (s, dev, None, "group");
++ break;
++ case ScreenGrabTabDrag:
++ grab->grabIndex = pushDeviceGrab (s, dev, None, "group-drag");
++ break;
++ case ScreenGrabNone:
++ groupRemoveGrab (s, grab);
++ break;
++ default:
++ break;
++ }
++ }
++ }
++}
++
+ /*
+ * groupRaiseWindows
+ *
+@@ -348,6 +467,9 @@ void
+ groupDeleteGroupWindow (CompWindow *w)
+ {
+ GroupSelection *group;
++ GroupGrab *grab;
++ GroupTabBarSlot *draggedSlot = NULL;
++ Bool dragged = FALSE;
+
+ GROUP_WINDOW (w);
+ GROUP_SCREEN (w->screen);
+@@ -359,8 +481,25 @@ groupDeleteGroupWindow (CompWindow *w)
+
+ if (group->tabBar && gw->slot)
+ {
+- if (gs->draggedSlot && gs->dragged &&
+- gs->draggedSlot->window->id == w->id)
++ if (gs->draggedSlot)
++ {
++ draggedSlot = gs->draggedSlot;
++ dragged = gs->dragged;
++ }
++ else
++ {
++ for (grab = gs->grabs; grab; grab = grab->next)
++ {
++ if (grab->draggedSlot && grab->dragged &&
++ grab->draggedSlot->window->id == w->id)
++ {
++ draggedSlot = grab->draggedSlot;
++ dragged = grab->dragged;
++ }
++ }
++ }
++ if (draggedSlot && dragged &&
++ draggedSlot->window->id == w->id)
+ {
+ groupUnhookTabBarSlot (group->tabBar, gw->slot, FALSE);
+ }
+@@ -973,16 +1112,108 @@ groupUnsetIgnore (CompDisplay *d,
+ */
+ static void
+ groupHandleButtonPressEvent (CompScreen *s,
+- XEvent *event)
++ XEvent *event,
++ Bool xi)
+ {
+ GroupSelection *group;
++ XDeviceButtonEvent *bev;
++ CompDevice *dev;
+ int xRoot, yRoot, button;
+
+ GROUP_SCREEN (s);
+
+- xRoot = event->xbutton.x_root;
+- yRoot = event->xbutton.y_root;
+- button = event->xbutton.button;
++
++ if (xi)
++ {
++ bev = (XDeviceButtonEvent *) event;
++ xRoot = bev->x_root;
++ yRoot = bev->y_root;
++ button = bev->button;
++ dev = compFindDeviceById (s->display, bev->deviceid);
++ }
++ else
++ {
++ xRoot = event->xbutton.x_root;
++ yRoot = event->xbutton.y_root;
++ button = event->xbutton.button;
++ }
++
++ /* Pseudocode idea for XI */
++
++ if (xi)
++ {
++ for (group = gs->groups; group; group = group->next)
++ {
++
++ if (group->inputPrevention != event->xbutton.window)
++ continue;
++
++ if (!group->tabBar)
++ continue;
++
++ switch (button)
++ {
++ case Button1:
++ {
++ GroupTabBarSlot *slot;
++ for (slot = group->tabBar->slots; slot; slot = slot->next)
++ {
++ if (XPointInRegion (slot->region, xRoot, yRoot))
++ {
++ GroupGrab *grab = groupAddGrab (s);
++ grab->draggedSlot = slot;
++ grab->dragged = FALSE;
++ grab->prevX = xRoot;
++ grab->prevY = yRoot;
++
++ if (!otherDeviceGrabExist(dev, "group", "group-drag"))
++ groupGrabDevice (s, dev, grab, ScreenGrabTabDrag);
++ }
++ }
++ }
++ break;
++ case Button4:
++ case Button5:
++ {
++ CompWindow *topTab = NULL;
++ GroupWindow *gw;
++
++ if (group->nextTopTab)
++ topTab = NEXT_TOP_TAB (group);
++ else if (group->topTab)
++ {
++ /* If there are no tabbing animations,
++ topTab is never NULL. */
++ topTab = TOP_TAB (group);
++ }
++
++ if (!topTab)
++ return;
++
++ gw = GET_GROUP_WINDOW (topTab, gs);
++
++ if (button == Button4)
++ {
++ if (gw->slot->prev)
++ groupChangeTab (gw->slot->prev, RotateLeft);
++ else
++ groupChangeTab (gw->group->tabBar->revSlots,
++ RotateLeft);
++ }
++ else
++ {
++ if (gw->slot->next)
++ groupChangeTab (gw->slot->next, RotateRight);
++ else
++ groupChangeTab (gw->group->tabBar->slots, RotateRight);
++ }
++ break;
++ }
++ }
++ }
++ }
++ else
++ {
+
+ for (group = gs->groups; group; group = group->next)
+ {
+@@ -1007,8 +1238,8 @@ groupHandleButtonPressEvent (CompScreen *s,
+ gs->prevX = xRoot;
+ gs->prevY = yRoot;
+
+- if (!otherScreenGrabExist(s, "group", "group-drag"))
+- groupGrabScreen (s, ScreenGrabTabDrag);
++ /*if (!otherScreenGrabExist(s, "group", "group-drag"))
++ groupGrabScreen (s, ScreenGrabTabDrag);*/
+ }
+ }
+ }
+@@ -1055,6 +1286,7 @@ groupHandleButtonPressEvent (CompScreen *s,
+
+ break;
+ }
++ }
+ }
+
+ /*
+@@ -1063,42 +1295,81 @@ groupHandleButtonPressEvent (CompScreen *s,
+ */
+ static void
+ groupHandleButtonReleaseEvent (CompScreen *s,
+- XEvent *event)
++ XEvent *event,
++ Bool xi)
+ {
+- GroupSelection *group;
++ GroupSelection *group = NULL;
++ GroupTabBarSlot *draggedSlot = NULL;
++ GroupGrab *grab = NULL;
++ CompDevice *dev = NULL;
++ XDeviceButtonEvent *bev;
+ int vx, vy;
++ int button;
+ Region newRegion;
+ Bool inserted = FALSE;
+ Bool wasInTabBar = FALSE;
++ Bool dragged = FALSE;
+
+ GROUP_SCREEN (s);
+
+- if (event->xbutton.button != 1)
++ if (xi)
++ {
++ bev = (XDeviceButtonEvent *) event;
++ button = bev->button;
++ dev = compFindDeviceById (s->display, bev->deviceid);
++ for (grab = gs->grabs; grab; grab = grab->next)
++ if (grab->dev == dev)
++ break;
++ if (grab)
++ {
++ draggedSlot = grab->draggedSlot;
++ dragged = grab->dragged;
++ }
++ }
++ else
++ {
++ button = event->xbutton.button;
++ draggedSlot = gs->draggedSlot;
++ dragged = gs->dragged;
++ }
++
++ if (button != 1)
++ return;
++
++ if (!draggedSlot)
+ return;
+
+- if (!gs->draggedSlot)
++ if (!draggedSlot->window)
+ return;
+
+- if (!gs->dragged)
++ if (!dragged)
+ {
+- groupChangeTab (gs->draggedSlot, RotateUncertain);
+- gs->draggedSlot = NULL;
++ groupChangeTab (draggedSlot, RotateUncertain);
++ draggedSlot = NULL;
+
+- if (gs->grabState == ScreenGrabTabDrag)
+- groupGrabScreen (s, ScreenGrabNone);
++ if (grab)
++ {
++ if (grab->state == ScreenGrabTabDrag)
++ groupGrabDevice (s, dev, grab, ScreenGrabNone);
++ }
++ else
++ {
++ if (gs->grabState == ScreenGrabTabDrag)
++ groupGrabScreen (s, ScreenGrabNone);
++ }
+
+ return;
+ }
+
+- GROUP_WINDOW (gs->draggedSlot->window);
++ GROUP_WINDOW (draggedSlot->window);
+
+ newRegion = XCreateRegion ();
+ if (!newRegion)
+ return;
+
+- XUnionRegion (newRegion, gs->draggedSlot->region, newRegion);
++ XUnionRegion (newRegion, draggedSlot->region, newRegion);
+
+- groupGetDrawOffsetForSlot (gs->draggedSlot, &vx, &vy);
++ groupGetDrawOffsetForSlot (draggedSlot, &vx, &vy);
+ XOffsetRegion (newRegion, vx, vy);
+
+ for (group = gs->groups; group; group = group->next)
+@@ -1142,35 +1413,35 @@ groupHandleButtonReleaseEvent (CompScreen *s,
+ XRectangle rect;
+ Bool inSlot;
+
+- if (slot == gs->draggedSlot)
++ if (slot == draggedSlot)
+ continue;
+
+ slotRegion = XCreateRegion ();
+ if (!slotRegion)
+ continue;
+
+- if (slot->prev && slot->prev != gs->draggedSlot)
++ if (slot->prev && slot->prev != draggedSlot)
+ {
+ rect.x = slot->prev->region->extents.x2;
+ }
+- else if (slot->prev && slot->prev == gs->draggedSlot &&
+- gs->draggedSlot->prev)
++ else if (slot->prev && slot->prev == draggedSlot &&
++ draggedSlot->prev)
+ {
+- rect.x = gs->draggedSlot->prev->region->extents.x2;
++ rect.x = draggedSlot->prev->region->extents.x2;
+ }
+ else
+ rect.x = group->tabBar->region->extents.x1;
+
+ rect.y = slot->region->extents.y1;
+
+- if (slot->next && slot->next != gs->draggedSlot)
++ if (slot->next && slot->next != draggedSlot)
+ {
+ rect.width = slot->next->region->extents.x1 - rect.x;
+ }
+- else if (slot->next && slot->next == gs->draggedSlot &&
+- gs->draggedSlot->next)
++ else if (slot->next && slot->next == draggedSlot &&
++ draggedSlot->next)
+ {
+- rect.width = gs->draggedSlot->next->region->extents.x1 - rect.x;
++ rect.width = draggedSlot->next->region->extents.x1 - rect.x;
+ }
+ else
+ rect.width = group->tabBar->region->extents.x2;
+@@ -1192,11 +1463,11 @@ groupHandleButtonReleaseEvent (CompScreen *s,
+ if (!inSlot)
+ continue;
+
+- tmpDraggedSlot = gs->draggedSlot;
++ tmpDraggedSlot = draggedSlot;
+
+ if (group != gw->group)
+ {
+- CompWindow *w = gs->draggedSlot->window;
++ CompWindow *w = draggedSlot->window;
+ GroupSelection *tmpGroup = gw->group;
+ int oldPosX = WIN_CENTER_X (w);
+ int oldPosY = WIN_CENTER_Y (w);
+@@ -1214,8 +1485,8 @@ groupHandleButtonReleaseEvent (CompScreen *s,
+ }
+
+ /* Change the group. */
+- groupDeleteGroupWindow (gs->draggedSlot->window);
+- groupAddWindowToGroup (gs->draggedSlot->window, group, 0);
++ groupDeleteGroupWindow (draggedSlot->window);
++ groupAddWindowToGroup (draggedSlot->window, group, 0);
+
+ /* we saved the original center position in oldPosX/Y before -
+ now we should apply that to the new main tab offset */
+@@ -1227,22 +1498,25 @@ groupHandleButtonReleaseEvent (CompScreen *s,
+ }
+ }
+ else
+- groupUnhookTabBarSlot (group->tabBar, gs->draggedSlot, TRUE);
++ groupUnhookTabBarSlot (group->tabBar, draggedSlot, TRUE);
+
+- gs->draggedSlot = NULL;
+- gs->dragged = FALSE;
++ //draggedSlot = NULL;
++ if (grab)
++ grab->dragged = FALSE;
++ else
++ gs->dragged = FALSE;
+ inserted = TRUE;
+
+- if ((tmpDraggedSlot->region->extents.x1 +
+- tmpDraggedSlot->region->extents.x2 + (2 * vx)) / 2 >
++ if ((draggedSlot->region->extents.x1 +
++ draggedSlot->region->extents.x2 + (2 * vx)) / 2 >
+ (slot->region->extents.x1 + slot->region->extents.x2) / 2)
+ {
+ groupInsertTabBarSlotAfter (group->tabBar,
+- tmpDraggedSlot, slot);
++ draggedSlot, slot);
+ }
+ else
+ groupInsertTabBarSlotBefore (group->tabBar,
+- tmpDraggedSlot, slot);
++ draggedSlot, slot);
+
+ groupDamageTabBarRegion (group);
+
+@@ -1266,14 +1540,17 @@ groupHandleButtonReleaseEvent (CompScreen *s,
+
+ if (!inserted)
+ {
+- CompWindow *draggedSlotWindow = gs->draggedSlot->window;
++ CompWindow *draggedSlotWindow = draggedSlot->window;
+ GroupSelection *tmpGroup;
+
+ for (tmpGroup = gs->groups; tmpGroup; tmpGroup = tmpGroup->next)
+ groupTabSetVisibility (tmpGroup, FALSE, PERMANENT);
+
+- gs->draggedSlot = NULL;
+- gs->dragged = FALSE;
++ draggedSlot = NULL;
++ if (grab)
++ grab->dragged = FALSE;
++ else
++ gs->dragged = FALSE;
+
+ if (groupGetDndUngroupWindow (s) && !wasInTabBar)
+ {
+@@ -1292,8 +1569,16 @@ groupHandleButtonReleaseEvent (CompScreen *s,
+ damageScreen (s);
+ }
+
+- if (gs->grabState == ScreenGrabTabDrag)
+- groupGrabScreen (s, ScreenGrabNone);
++ if (grab)
++ {
++ if (grab->state == ScreenGrabTabDrag)
++ groupGrabDevice (s, dev, grab, ScreenGrabNone);
++ }
++ else
++ {
++ if (gs->grabState == ScreenGrabTabDrag)
++ groupGrabScreen (s, ScreenGrabNone);
++ }
+
+ if (gs->dragHoverTimeoutHandle)
+ {
+@@ -1312,37 +1597,80 @@ groupHandleButtonReleaseEvent (CompScreen *s,
+
+ static void
+ groupHandleMotionEvent (CompScreen *s,
++ XEvent *event,
+ int xRoot,
+- int yRoot)
++ int yRoot,
++ Bool xi)
+ {
++ GroupScreenGrabState grabState = ScreenGrabNone;
++ Bool dragged = FALSE;
++ GroupTabBarSlot *draggedSlot = NULL;
++ GroupGrab *grab;
++ CompDevice *dev;
++ XDeviceMotionEvent *mev;
++ int *prevX, *prevY;
+ GROUP_SCREEN (s);
+
+- if (gs->grabState == ScreenGrabTabDrag)
++ if (xi)
++ {
++ mev = (XDeviceMotionEvent *) event;
++ dev = compFindDeviceById (s->display, mev->deviceid);
++ if (dev)
++ {
++ for (grab = gs->grabs; grab; grab = grab->next)
++ if (grab->dev == dev)
++ break;
++
++ if (grab)
++ {
++ grabState = grab->state;
++ dragged = grab->dragged;
++ draggedSlot = grab->draggedSlot;
++ prevX = &grab->prevX;
++ prevY = &grab->prevY;
++ //if (!draggedSlot)
++ //groupGrabDevice (s, dev, grab, ScreenGrabNone);
++ }
++ }
++ }
++ else
++ {
++ grabState = gs->grabState;
++ dragged = gs->dragged;
++ draggedSlot = gs->draggedSlot;
++ prevX = &gs->prevX;
++ prevY = &gs->prevY;
++ }
++
++
++ if (grabState == ScreenGrabTabDrag && draggedSlot)
+ {
+ int dx, dy;
+ int vx, vy;
+ REGION reg;
+- Region draggedRegion = gs->draggedSlot->region;
++ Region draggedRegion = draggedSlot->region;
+
+ reg.rects = &reg.extents;
+ reg.numRects = 1;
++ dx = xRoot - *prevX;
++ dy = yRoot - *prevY;
+
+- dx = xRoot - gs->prevX;
+- dy = yRoot - gs->prevY;
+-
+- if (gs->dragged || abs (dx) > RADIUS || abs (dy) > RADIUS)
++ if (dragged || abs (dx) > RADIUS || abs (dy) > RADIUS)
+ {
+- gs->prevX = xRoot;
+- gs->prevY = yRoot;
++ *prevX = xRoot;
++ *prevY = yRoot;
+
+- if (!gs->dragged)
++ if (!dragged)
+ {
+ GroupSelection *group;
+ BoxRec *box;
+
+- GROUP_WINDOW (gs->draggedSlot->window);
++ GROUP_WINDOW (draggedSlot->window);
+
+- gs->dragged = TRUE;
++ if (grab)
++ grab->dragged = TRUE;
++ else
++ gs->dragged = TRUE;
+
+ for (group = gs->groups; group; group = group->next)
+ groupTabSetVisibility (group, TRUE, PERMANENT);
+@@ -1352,7 +1680,7 @@ groupHandleMotionEvent (CompScreen *s,
+ box->x1, box->x2);
+ }
+
+- groupGetDrawOffsetForSlot (gs->draggedSlot, &vx, &vy);
++ groupGetDrawOffsetForSlot (draggedSlot, &vx, &vy);
+
+ reg.extents.x1 = draggedRegion->extents.x1 + vx;
+ reg.extents.y1 = draggedRegion->extents.y1 + vy;
+@@ -1360,10 +1688,10 @@ groupHandleMotionEvent (CompScreen *s,
+ reg.extents.y2 = draggedRegion->extents.y2 + vy;
+ damageScreenRegion (s, &reg);
+
+- XOffsetRegion (gs->draggedSlot->region, dx, dy);
+- gs->draggedSlot->springX =
+- (gs->draggedSlot->region->extents.x1 +
+- gs->draggedSlot->region->extents.x2) / 2;
++ XOffsetRegion (draggedSlot->region, dx, dy);
++ draggedSlot->springX =
++ (draggedSlot->region->extents.x1 +
++ draggedSlot->region->extents.x2) / 2;
+
+ reg.extents.x1 = draggedRegion->extents.x1 + vx;
+ reg.extents.y1 = draggedRegion->extents.y1 + vy;
+@@ -1372,9 +1700,12 @@ groupHandleMotionEvent (CompScreen *s,
+ damageScreenRegion (s, &reg);
+ }
+ }
+- else if (gs->grabState == ScreenGrabSelect)
++ else if (grabState == ScreenGrabSelect)
+ {
+- groupDamageSelectionRect (s, xRoot, yRoot);
++ if (grab)
++ groupDamageSelectionRect (s, xRoot, yRoot, grab->x1, grab->y1, &grab->x2, &grab->y2);
++ else
++ groupDamageSelectionRect (s, xRoot, yRoot, gs->x1, gs->y1, &gs->x2, &gs->y2);
+ }
+ }
+
+@@ -1387,6 +1718,7 @@ groupHandleEvent (CompDisplay *d,
+ XEvent *event)
+ {
+ GROUP_DISPLAY (d);
++ Bool xi = FALSE;
+
+ switch (event->type) {
+ case MotionNotify:
+@@ -1394,7 +1726,7 @@ groupHandleEvent (CompDisplay *d,
+ CompScreen *s;
+ s = findScreenAtDisplay (d, event->xmotion.root);
+ if (s)
+- groupHandleMotionEvent (s, pointerX, pointerY);
++ groupHandleMotionEvent (s, event, pointerX, pointerY, xi);
+ }
+ break;
+
+@@ -1403,7 +1735,7 @@ groupHandleEvent (CompDisplay *d,
+ CompScreen *s;
+ s = findScreenAtDisplay (d, event->xbutton.root);
+ if (s)
+- groupHandleButtonPressEvent (s, event);
++ groupHandleButtonPressEvent (s, event, xi);
+ }
+ break;
+
+@@ -1412,10 +1744,39 @@ groupHandleEvent (CompDisplay *d,
+ CompScreen *s;
+ s = findScreenAtDisplay (d, event->xbutton.root);
+ if (s)
+- groupHandleButtonReleaseEvent (s, event);
++ groupHandleButtonReleaseEvent (s, event, xi);
+ }
+ break;
++ default:
++ if (event->type == d->xi_motion)
++ {
++ xi = TRUE;
++ XDeviceMotionEvent *mev = (XDeviceMotionEvent *) event;
++ CompScreen *s = findScreenAtDisplay (d, mev->root);
++ CompDevice *dev = compFindDeviceById (d, mev->deviceid);
++ if (s && dev)
++ groupHandleMotionEvent (s, event, dev->pointerX, dev->pointerY, xi);
++ }
++ else if (event->type == d->xi_btpress)
++ {
++ xi = TRUE;
++ XDeviceButtonEvent *bev = (XDeviceButtonEvent *) event;
++ CompScreen *s = findScreenAtDisplay (d, bev->root);
++ if (s)
++ groupHandleButtonPressEvent (s, event, xi);
++ }
++ else if (event->type == d->xi_btrelease)
++ {
++ xi = TRUE;
++ XDeviceButtonEvent *bev = (XDeviceButtonEvent *) event;
++ CompScreen *s = findScreenAtDisplay (d, bev->root);
++ if (s)
++ groupHandleButtonReleaseEvent (s, event, xi);
++ }
++ break;
++ }
+
++ switch (event->type){
+ case MapNotify:
+ {
+ CompWindow *cw, *w;
+@@ -1635,6 +1996,7 @@ groupHandleEvent (CompDisplay *d,
+ if (w->id != w->screen->grabWindow)
+ groupUpdateTabBars (w->screen, w->id);
+
++ /* TODO: XI version of this */
+ if (gw->group)
+ {
+ if (gs->draggedSlot && gs->dragged &&
+diff --git a/paint.c b/paint.c
+index 103429a..2cf5fab 100644
+--- a/paint.c
++++ b/paint.c
+@@ -317,50 +317,49 @@ groupPaintSelectionOutline (CompScreen *s,
+ const ScreenPaintAttrib *sa,
+ const CompTransform *transform,
+ CompOutput *output,
+- Bool transformed)
++ Bool transformed,
++ int ax1,
++ int ax2,
++ int ay1,
++ int ay2)
+ {
+ int x1, x2, y1, y2;
+
+- GROUP_SCREEN (s);
++ x1 = MIN (ax1, ax2);
++ y1 = MIN (ay1, ay2);
++ x2 = MAX (ax1, ax2);
++ y2 = MAX (ay1, ay2);
+
+- x1 = MIN (gs->x1, gs->x2);
+- y1 = MIN (gs->y1, gs->y2);
+- x2 = MAX (gs->x1, gs->x2);
+- y2 = MAX (gs->y1, gs->y2);
++ CompTransform sTransform = *transform;
+
+- if (gs->grabState == ScreenGrabSelect)
++ if (transformed)
+ {
+- CompTransform sTransform = *transform;
+-
+- if (transformed)
+- {
+- (*s->applyScreenTransform) (s, sa, output, &sTransform);
+- transformToScreenSpace (s, output, -sa->zTranslate, &sTransform);
+- } else
+- transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
+-
+- glPushMatrix ();
+- glLoadMatrixf (sTransform.m);
+-
+- glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+- glEnable (GL_BLEND);
+-
+- glColor4usv (groupGetFillColorOption (s)->value.c);
+- glRecti (x1, y2, x2, y1);
+-
+- glColor4usv (groupGetLineColorOption (s)->value.c);
+- glBegin (GL_LINE_LOOP);
+- glVertex2i (x1, y1);
+- glVertex2i (x2, y1);
+- glVertex2i (x2, y2);
+- glVertex2i (x1, y2);
+- glEnd ();
+-
+- glColor4usv (defaultColor);
+- glDisable (GL_BLEND);
+- glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+- glPopMatrix ();
+- }
++ (*s->applyScreenTransform) (s, sa, output, &sTransform);
++ transformToScreenSpace (s, output, -sa->zTranslate, &sTransform);
++ } else
++ transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
++
++ glPushMatrix ();
++ glLoadMatrixf (sTransform.m);
++
++ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
++ glEnable (GL_BLEND);
++
++ glColor4usv (groupGetFillColorOption (s)->value.c);
++ glRecti (x1, y2, x2, y1);
++
++ glColor4usv (groupGetLineColorOption (s)->value.c);
++ glBegin (GL_LINE_LOOP);
++ glVertex2i (x1, y1);
++ glVertex2i (x2, y1);
++ glVertex2i (x2, y2);
++ glVertex2i (x1, y2);
++ glEnd ();
++
++ glColor4usv (defaultColor);
++ glDisable (GL_BLEND);
++ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
++ glPopMatrix ();
+ }
+
+ /*
+@@ -383,9 +382,12 @@ groupPreparePaintScreen (CompScreen *s,
+ while (group)
+ {
+ GroupTabBar *bar = group->tabBar;
++ GroupGrab *grab;
+
+ if (bar)
+ {
++ for (grab = gs->grabs; grab; grab = grab->next)
++ groupApplyForces (s, bar, (grab->dragged) ? grab->draggedSlot : NULL);
+ groupApplyForces (s, bar, (gs->dragged) ? gs->draggedSlot : NULL);
+ groupApplySpeeds (s, group, msSinceLastPaint);
+
+@@ -433,11 +435,14 @@ groupPaintOutput (CompScreen *s,
+ unsigned int mask)
+ {
+ GroupSelection *group;
++ GroupGrab *grab;
+ Bool status;
+
+ GROUP_SCREEN (s);
+ GROUP_DISPLAY (s->display);
+
++
++ /* MPXofy this */
+ gs->painted = FALSE;
+ gs->vpX = s->x;
+ gs->vpY = s->y;
+@@ -462,6 +467,7 @@ groupPaintOutput (CompScreen *s,
+ }
+ }
+
++
+ UNWRAP (gs, s, paintOutput);
+ status = (*s->paintOutput) (s, sAttrib, transform, region, output, mask);
+ WRAP (gs, s, paintOutput, groupPaintOutput);
+@@ -481,16 +487,52 @@ groupPaintOutput (CompScreen *s,
+ glLoadMatrixf (wTransform.m);
+
+ /* prevent tab bar drawing.. */
+- state = gw->group->tabBar->state;
+- gw->group->tabBar->state = PaintOff;
++ if (gw->group->tabBar)
++ {
++ state = gw->group->tabBar->state;
++ gw->group->tabBar->state = PaintOff;
++ }
+ groupPaintThumb (NULL, gs->draggedSlot, &wTransform, OPAQUE);
++ if (gw->group->tabBar)
+ gw->group->tabBar->state = state;
+
+ glPopMatrix ();
+ }
+ else if (gs->grabState == ScreenGrabSelect)
+ {
+- groupPaintSelectionOutline (s, sAttrib, transform, output, FALSE);
++ groupPaintSelectionOutline (s, sAttrib, transform, output, FALSE, gs->x1, gs->x2, gs->y1, gs->y2);
++ }
++
++ for (grab = gs->grabs; grab; grab = grab->next)
++ {
++ if ((grab->state == ScreenGrabTabDrag) && grab->draggedSlot)
++ {
++ CompTransform wTransform = *transform;
++ PaintState state;
++
++ GROUP_WINDOW (grab->draggedSlot->window);
++
++ transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &wTransform);
++
++ glPushMatrix ();
++ glLoadMatrixf (wTransform.m);
++
++ /* prevent tab bar drawing.. */
++ if (gw->group->tabBar)
++ {
++ state = gw->group->tabBar->state;
++ gw->group->tabBar->state = PaintOff;
++ }
++ groupPaintThumb (NULL, grab->draggedSlot, &wTransform, OPAQUE);
++ if (gw->group->tabBar)
++ gw->group->tabBar->state = state;
++
++ glPopMatrix ();
++ }
++ else if (grab->state == ScreenGrabSelect)
++ {
++ groupPaintSelectionOutline (s, sAttrib, transform, output, FALSE, grab->x1, grab->x2, grab->y1, grab->y2);
++ }
+ }
+ }
+
+@@ -509,6 +551,7 @@ groupPaintTransformedOutput (CompScreen *s,
+ CompOutput *output,
+ unsigned int mask)
+ {
++ GroupGrab *grab;
+ GROUP_SCREEN (s);
+
+ UNWRAP (gs, s, paintTransformedOutput);
+@@ -535,7 +578,28 @@ groupPaintTransformedOutput (CompScreen *s,
+ }
+ else if (gs->grabState == ScreenGrabSelect)
+ {
+- groupPaintSelectionOutline (s, sa, transform, output, TRUE);
++ groupPaintSelectionOutline (s, sa, transform, output, TRUE, gs->x1, gs->x2, gs->y1, gs->y2);
++ }
++
++ for (grab = gs->grabs; grab; grab = grab->next)
++ {
++ if ((grab->state == ScreenGrabTabDrag) && grab->draggedSlot)
++ {
++ CompTransform wTransform = *transform;
++
++ transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &wTransform);
++
++ glPushMatrix ();
++ glLoadMatrixf (wTransform.m);
++
++ groupPaintThumb (NULL, grab->draggedSlot, &wTransform, OPAQUE);
++
++ glPopMatrix ();
++ }
++ else if (grab->state == ScreenGrabSelect)
++ {
++ groupPaintSelectionOutline (s, sa, transform, output, TRUE, grab->x1, grab->x2, grab->y1, grab->y2);
++ }
+ }
+ }
+ }
+diff --git a/selection.c b/selection.c
+index 4a91351..5c1946e 100644
+--- a/selection.c
++++ b/selection.c
+@@ -282,28 +282,58 @@ groupSelect (CompDisplay *d,
+ int nOption)
+ {
+ Window xid;
++ int deviceid;
++ int mouseX, mouseY;
+ CompWindow *w;
++ CompDevice *dev;
++ GroupGrab *grab;
+
+ xid = getIntOptionNamed (option, nOption, "window", 0);
+ w = findWindowAtDisplay (d, xid);
++
++ deviceid = getIntOptionNamed (option, nOption, "device", -1);
++ dev = compFindDeviceById (d, deviceid);
++
+ if (w)
+ {
+ GROUP_SCREEN (w->screen);
+
+ if (gs->grabState == ScreenGrabNone)
+ {
+- groupGrabScreen (w->screen, ScreenGrabSelect);
+-
+ if (state & CompActionStateInitKey)
+ action->state |= CompActionStateTermKey;
+
+ if (state & CompActionStateInitButton)
+ action->state |= CompActionStateTermButton;
+
+- gs->x1 = gs->x2 = pointerX;
+- gs->y1 = gs->y2 = pointerY;
+- }
++ if (dev)
++ {
++ for (grab = gs->grabs; grab; grab = grab->next)
++ if (grab->dev == dev && grab->state == ScreenGrabNone)
++ break;
++
++ if (!grab)
++ grab = groupAddGrab (w->screen);
++
++ if (grab)
++ {
++ if (!grab->grabIndex)
++ groupGrabDevice (w->screen, dev, grab, ScreenGrabSelect);
+
++ if (groupGetCurrentDeviceMousePosition (w->screen, dev, &mouseX, &mouseY))
++ {
++ grab->x1 = grab->x2 = mouseX;
++ grab->y1 = grab->y2 = mouseY;
++ }
++ }
++ }
++ else
++ {
++ groupGrabScreen (w->screen, ScreenGrabSelect);
++ gs->x1 = gs->x2 = pointerX;
++ gs->y1 = gs->y2 = pointerY;
++ }
++ }
+ return TRUE;
+ }
+
+@@ -322,19 +352,49 @@ groupSelectTerminate (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
++ GroupGrab *grab;
+ Window xid;
++ int deviceid;
++ int x1, x2, y1, y2;
+
+ xid = getIntOptionNamed(option, nOption, "root", 0);
+ s = findScreenAtDisplay (d, xid);
++
++ deviceid = getIntOptionNamed (option, nOption, "device", -1);
++ dev = compFindDeviceById (d, deviceid);
++
+ if (s)
+ {
+ GROUP_SCREEN (s);
++ if (dev)
++ {
++ for (grab = gs->grabs; grab; grab = grab->next)
++ if (grab->dev == dev)
++ break;
+
+- if (gs->grabState == ScreenGrabSelect)
++ if (grab)
++ {
++ if (grab->state == ScreenGrabSelect)
++ {
++ x1 = grab->x1;
++ x2 = grab->x2;
++ y1 = grab->y1;
++ y2 = grab->y2;
++ groupGrabDevice (s, dev, grab, ScreenGrabNone);
++ }
++ }
++ }
++ else if (gs->grabState == ScreenGrabSelect)
+ {
+ groupGrabScreen (s, ScreenGrabNone);
++ x1 = gs->x1;
++ x2 = gs->x2;
++ y1 = gs->y1;
++ y2 = gs->y2;
++ }
+
+- if (gs->x1 != gs->x2 && gs->y1 != gs->y2)
++ if (x1 != x2 && y1 != y2)
+ {
+ Region reg;
+ XRectangle rect;
+@@ -344,12 +404,12 @@ groupSelectTerminate (CompDisplay *d,
+ reg = XCreateRegion ();
+ if (reg)
+ {
+- rect.x = MIN (gs->x1, gs->x2) - 2;
+- rect.y = MIN (gs->y1, gs->y2) - 2;
+- rect.width = MAX (gs->x1, gs->x2) -
+- MIN (gs->x1, gs->x2) + 4;
+- rect.height = MAX (gs->y1, gs->y2) -
+- MIN (gs->y1, gs->y2) + 4;
++ rect.x = MIN (x1, x2) - 2;
++ rect.y = MIN (y1, y2) - 2;
++ rect.width = MAX (x1, x2) -
++ MIN (x1, x2) + 4;
++ rect.height = MAX (y1, y2) -
++ MIN (y1, y2) + 4;
+ XUnionRectWithRegion (&rect, reg, reg);
+
+ damageScreenRegion (s, reg);
+@@ -370,10 +430,9 @@ groupSelectTerminate (CompDisplay *d,
+ XDestroyRegion (reg);
+ }
+ }
+- }
+- }
+-
++ if (!gs->grabs)
+ action->state &= ~(CompActionStateTermKey | CompActionStateTermButton);
++ }
+
+ return FALSE;
+ }
+@@ -385,27 +444,29 @@ groupSelectTerminate (CompDisplay *d,
+ void
+ groupDamageSelectionRect (CompScreen *s,
+ int xRoot,
+- int yRoot)
++ int yRoot,
++ int x1,
++ int y1,
++ int *x2,
++ int *y2)
+ {
+ REGION reg;
+
+- GROUP_SCREEN (s);
+-
+ reg.rects = &reg.extents;
+ reg.numRects = 1;
+
+- reg.extents.x1 = MIN (gs->x1, gs->x2) - 5;
+- reg.extents.y1 = MIN (gs->y1, gs->y2) - 5;
+- reg.extents.x2 = MAX (gs->x1, gs->x2) + 5;
+- reg.extents.y2 = MAX (gs->y1, gs->y2) + 5;
++ reg.extents.x1 = MIN (x1, *x2) - 5;
++ reg.extents.y1 = MIN (y1, *y2) - 5;
++ reg.extents.x2 = MAX (x1, *x2) + 5;
++ reg.extents.y2 = MAX (y1, *y2) + 5;
+ damageScreenRegion (s, &reg);
+
+- gs->x2 = xRoot;
+- gs->y2 = yRoot;
++ (*x2) = xRoot;
++ (*y2) = yRoot;
+
+- reg.extents.x1 = MIN (gs->x1, gs->x2) - 5;
+- reg.extents.y1 = MIN (gs->y1, gs->y2) - 5;
+- reg.extents.x2 = MAX (gs->x1, gs->x2) + 5;
+- reg.extents.y2 = MAX (gs->y1, gs->y2) + 5;
++ reg.extents.x1 = MIN (x1, *x2) - 5;
++ reg.extents.y1 = MIN (y1, *y2) - 5;
++ reg.extents.x2 = MAX (x1, *x2) + 5;
++ reg.extents.y2 = MAX (y1, *y2) + 5;
+ damageScreenRegion (s, &reg);
+ }
+diff --git a/tab.c b/tab.c
+index 2e57b69..90dbaf3 100644
+--- a/tab.c
++++ b/tab.c
+@@ -55,6 +55,30 @@ groupGetCurrentMousePosition (CompScreen *s,
+ return result;
+ }
+
++Bool
++groupGetCurrentDeviceMousePosition (CompScreen *s,
++ CompDevice *dev,
++ int *x,
++ int *y)
++{
++ unsigned int rmask;
++ int mouseX, mouseY, winX, winY;
++ Window root;
++ Window child;
++ Bool result;
++
++ result = XQueryDevicePointer (s->display->display, dev->dev, s->root, &root,
++ &child, &mouseX, &mouseY, &winX, &winY, &rmask);
++
++ if (result)
++ {
++ (*x) = mouseX;
++ (*y) = mouseY;
++ }
++
++ return result;
++}
++
+ /*
+ * groupGetClippingRegion
+ *
+@@ -376,6 +400,8 @@ groupGetDrawOffsetForSlot (GroupTabBarSlot *slot,
+ {
+ CompWindow *w, *topTab;
+ CompScreen *s;
++ GroupGrab *grab;
++ Bool notDragged = TRUE;
+ int vx, vy, x, y;
+
+ if (!slot || !slot->window)
+@@ -384,10 +410,30 @@ groupGetDrawOffsetForSlot (GroupTabBarSlot *slot,
+ w = slot->window;
+ s = w->screen;
+
++ if (!w)
++ return;
++
++ if (!s)
++ return;
++
+ GROUP_WINDOW (w);
+ GROUP_SCREEN (s);
+
+- if (slot != gs->draggedSlot)
++ if (slot == gs->draggedSlot)
++ {
++ notDragged = FALSE;
++ }
++ else
++ {
++ for (grab = gs->grabs; grab; grab = grab->next)
++ if (slot == grab->draggedSlot)
++ {
++ notDragged = FALSE;
++ break;
++ }
++ }
++
++ if (notDragged)
+ {
+ if (hoffset)
+ *hoffset = 0;
+@@ -933,7 +979,9 @@ groupUpdateTabBars (CompScreen *s,
+ Window enteredWin)
+ {
+ CompWindow *w = NULL;
++ CompDevice *dev;
+ GroupSelection *hoveredGroup = NULL;
++ GroupSelection *group;
+
+ GROUP_SCREEN (s);
+
+@@ -960,7 +1008,11 @@ groupUpdateTabBars (CompScreen *s,
+ int mouseX, mouseY;
+ /* it is grouped and tabbed, so now we have to
+ check if we hovered the title bar or the frame */
+- if (groupGetCurrentMousePosition (s, &mouseX, &mouseY))
++ for (dev = s->display->devices; dev->id != -1; dev++)
++ {
++ if (dev->use != IsXPointer)
++ continue;
++ if (groupGetCurrentDeviceMousePosition (s, dev, &mouseX, &mouseY))
+ {
+ XRectangle rect;
+ Region reg = XCreateRegion();
+@@ -978,6 +1030,7 @@ groupUpdateTabBars (CompScreen *s,
+
+ XDestroyRegion (reg);
+ }
++ }
+ }
+ }
+
+@@ -1002,9 +1055,68 @@ groupUpdateTabBars (CompScreen *s,
+ }
+
+ /* if we found a hovered tab bar different than the last one
+- (or left a tab bar), hide the old one */
+- if (gs->lastHoveredGroup && (hoveredGroup != gs->lastHoveredGroup))
+- groupTabSetVisibility (gs->lastHoveredGroup, FALSE, 0);
++ (or left a tab bar), hide the old one, ONLY if it isn't hovered anymore */
++ /*if (gs->lastHoveredGroup && (hoveredGroup != gs->lastHoveredGroup))
++ groupTabSetVisibility (gs->lastHoveredGroup, FALSE, 0);*/
++
++ for (group = gs->groups; group; group = group->next)
++ {
++ Bool hovered = FALSE;
++ int mouseX, mouseY;
++ int i = 0;
++ if (group == hoveredGroup)
++ continue;
++
++ if (group->tabBar && ((group->tabBar->state == PaintOn) ||
++ (group->tabBar->state == PaintPermanentOn) ||
++ (group->tabBar->state == PaintFadeIn)))
++ {
++ for (dev = s->display->devices; dev->id != -1; dev++)
++ {
++ if (dev->use != IsXPointer)
++ continue;
++ if (groupGetCurrentDeviceMousePosition (s, dev, &mouseX, &mouseY))
++ {
++ XRectangle rectFrame;
++ Region regFrame = XCreateRegion();
++ Region regBar = group->tabBar->region;
++ if (!regFrame)
++ return;
++
++ if (!regBar)
++ return;
++
++ for (i = 0; i < group->nWins; i++)
++ {
++ CompWindow *win = group->windows[i];
++
++ rectFrame.x = WIN_X (win) - win->input.left;
++ rectFrame.y = WIN_Y (win) - win->input.top;
++ rectFrame.width = WIN_WIDTH (win) + win->input.right;
++ rectFrame.height = WIN_Y (win) - rectFrame.y;
++ XUnionRectWithRegion (&rectFrame, regFrame, regFrame);
++
++ if ((XPointInRegion (regFrame, mouseX, mouseY)))
++ {
++ hovered = TRUE;
++ break;
++ }
++ }
++
++ if (XPointInRegion (regBar, mouseX, mouseY))
++ hovered = TRUE;
++
++ XDestroyRegion (regFrame);
++ if (hovered)
++ break;
++ }
++ }
++ if (hovered)
++ groupTabSetVisibility (group, TRUE, 0);
++ else
++ groupTabSetVisibility (group, FALSE, 0);
++ }
++ }
+
+ /* if we entered a tab bar (or title bar), show the tab bar */
+ if (hoveredGroup && HAS_TOP_WIN (hoveredGroup) &&
+@@ -1720,8 +1832,10 @@ groupRecalcTabBarPos (GroupSelection *group,
+ {
+ GroupTabBarSlot *slot;
+ GroupTabBar *bar;
++ GroupGrab *grab;
+ CompWindow *topTab;
+- Bool isDraggedSlotGroup = FALSE;
++ Bool grabIsDragged = FALSE;
++ int nDraggedSlots = 0;
+ int space, barWidth;
+ int thumbSize;
+ int tabsWidth = 0, tabsHeight = 0;
+@@ -1742,7 +1856,21 @@ groupRecalcTabBarPos (GroupSelection *group,
+ {
+ if (slot == gs->draggedSlot && gs->dragged)
+ {
+- isDraggedSlotGroup = TRUE;
++ nDraggedSlots++;
++ continue;
++ }
++ for (grab = gs->grabs; grab; grab = grab->next)
++ {
++ grabIsDragged = FALSE;
++ if (slot == grab->draggedSlot && grab->dragged)
++ {
++ grabIsDragged = TRUE;
++ break;
++ }
++ }
++ if (grabIsDragged)
++ {
++ nDraggedSlots++;
+ continue;
+ }
+
+@@ -1765,16 +1893,16 @@ groupRecalcTabBarPos (GroupSelection *group,
+ tabsHeight = thumbSize;
+ }
+
+- if (isDraggedSlotGroup)
+- tabsWidth -= thumbSize;
++ if (nDraggedSlots)
++ tabsWidth -= thumbSize * nDraggedSlots;
+ }
+
+ barWidth = space * (bar->nSlots + 1) + tabsWidth;
+
+- if (isDraggedSlotGroup)
++ if (nDraggedSlots)
+ {
+ /* 1 tab is missing, so we have 1 less border */
+- barWidth -= space;
++ barWidth -= space * nDraggedSlots;
+ }
+
+ if (maxX2 - minX1 < barWidth)
+@@ -1798,6 +1926,18 @@ groupRecalcTabBarPos (GroupSelection *group,
+ {
+ if (slot == gs->draggedSlot && gs->dragged)
+ continue;
++ for (grab = gs->grabs; grab; grab = grab->next)
++ {
++ grabIsDragged = FALSE;
++ if (slot == grab->draggedSlot && grab->dragged)
++ {
++ grabIsDragged = TRUE;
++ break;
++ }
++ }
++ if (grabIsDragged)
++ continue;
++
+
+ groupRecalcSlotPos (slot, currentSlot);
+ XOffsetRegion (slot->region,
+@@ -1942,6 +2082,9 @@ groupInsertTabBarSlotBefore (GroupTabBar *bar,
+ GroupTabBarSlot *prev = nextSlot->prev;
+ CompWindow *w = slot->window;
+
++ if (w)
++ {
++
+ GROUP_WINDOW (w);
+
+ if (prev)
+@@ -1967,6 +2110,7 @@ groupInsertTabBarSlotBefore (GroupTabBar *bar,
+ (bar->region->extents.x1 +
+ bar->region->extents.x2) / 2,
+ bar->region->extents.x1, bar->region->extents.x2);
++ }
+ }
+
+ /*
+@@ -1981,6 +2125,9 @@ groupInsertTabBarSlotAfter (GroupTabBar *bar,
+ GroupTabBarSlot *next = prevSlot->next;
+ CompWindow *w = slot->window;
+
++ if (w)
++ {
++
+ GROUP_WINDOW (w);
+
+ if (next)
+@@ -2006,6 +2153,8 @@ groupInsertTabBarSlotAfter (GroupTabBar *bar,
+ (bar->region->extents.x1 +
+ bar->region->extents.x2) / 2,
+ bar->region->extents.x1, bar->region->extents.x2);
++
++ }
+ }
+
+ /*
+@@ -2146,6 +2295,7 @@ groupDeleteTabBarSlot (GroupTabBar *bar,
+ GroupTabBarSlot *slot)
+ {
+ CompWindow *w = slot->window;
++ GroupGrab *grab = NULL;
+
+ GROUP_WINDOW (w);
+ GROUP_SCREEN (w->screen);
+@@ -2163,6 +2313,20 @@ groupDeleteTabBarSlot (GroupTabBar *bar,
+ if (gs->grabState == ScreenGrabTabDrag)
+ groupGrabScreen (w->screen, ScreenGrabNone);
+ }
++ else
++ {
++ for (grab = gs->grabs; grab; grab = grab->next)
++ {
++ if (slot == grab->draggedSlot)
++ {
++ grab->draggedSlot = NULL;
++ grab->dragged = FALSE;
++
++ if (grab->state == ScreenGrabTabDrag)
++ groupGrabDevice (w->screen , grab->dev, grab, ScreenGrabNone);
++ }
++ }
++ }
+
+ gw->slot = NULL;
+ groupUpdateWindowProperty (w);
+--
+1.5.6
+
diff --git a/fusion/plugins/mag/0001-MPX-Inclusion.patch b/fusion/plugins/mag/0001-MPX-Inclusion.patch
new file mode 100644
index 0000000..ec2cf65
--- /dev/null
+++ b/fusion/plugins/mag/0001-MPX-Inclusion.patch
@@ -0,0 +1,1373 @@
+From 78b452dda80c9b8b2fc700de728f4d4bfb6daa12 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Wed, 29 Oct 2008 15:22:12 +0900
+Subject: [PATCH] * MPX Inclusion
+
+---
+ mag.c | 913 +++++++++++++++++++++++++++++++++++++++--------------------------
+ 1 files changed, 553 insertions(+), 360 deletions(-)
+
+diff --git a/mag.c b/mag.c
+index 5496927..59e06dd 100644
+--- a/mag.c
++++ b/mag.c
+@@ -60,8 +60,10 @@ typedef struct _MagImage
+ }
+ MagImage;
+
+-typedef struct _MagScreen
++typedef struct _MagDevice
+ {
++ CompDevice *dev;
++
+ int posX;
+ int posY;
+
+@@ -71,18 +73,25 @@ typedef struct _MagScreen
+ GLfloat zTarget;
+ GLfloat zoom;
+
+- MagModeEnum mode;
+-
+- GLuint texture;
++ GLuint program;
+ GLenum target;
++ GLuint texture;
+
+ int width;
+ int height;
+
++ struct _MagDevice *next;
++
++} MagDevice;
++
++typedef struct _MagScreen
++{
++ MagDevice *devices;
++
+ MagImage overlay;
+ MagImage mask;
+
+- GLuint program;
++ MagModeEnum mode;
+
+ PositionPollingHandle pollHandle;
+
+@@ -122,43 +131,18 @@ static const char *fisheyeFpString =
+
+ "END";
+
+-static void
+-magCleanup (CompScreen *s)
+-{
+- MAG_SCREEN (s);
+-
+- if (ms->overlay.loaded)
+- {
+- ms->overlay.loaded = FALSE;
+- finiTexture (s, &ms->overlay.tex);
+- initTexture (s, &ms->overlay.tex);
+- }
+- if (ms->mask.loaded)
+- {
+- ms->mask.loaded = FALSE;
+- finiTexture (s, &ms->mask.tex);
+- initTexture (s, &ms->mask.tex);
+- }
+
+- if (ms->program)
+- {
+- (*s->deletePrograms) (1, &ms->program);
+- ms->program = 0;
+- }
+-}
+
+ static Bool
+-loadFragmentProgram (CompScreen *s)
++loadFragmentProgram (CompScreen *s, MagDevice *dev)
+ {
+ char buffer[1024];
+ GLint errorPos;
+
+- MAG_SCREEN (s);
+-
+ if (!s->fragmentProgram)
+ return FALSE;
+
+- if (ms->target == GL_TEXTURE_2D)
++ if (dev->target == GL_TEXTURE_2D)
+ sprintf (buffer, fisheyeFpString, "2D");
+ else
+ sprintf (buffer, fisheyeFpString, "RECT");
+@@ -166,10 +150,10 @@ loadFragmentProgram (CompScreen *s)
+ /* clear errors */
+ glGetError ();
+
+- if (!ms->program)
+- (*s->genPrograms) (1, &ms->program);
++ if (!dev->program)
++ (*s->genPrograms) (1, &dev->program);
+
+- (*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, ms->program);
++ (*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, dev->program);
+ (*s->programString) (GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen (buffer), buffer);
+@@ -180,8 +164,8 @@ loadFragmentProgram (CompScreen *s)
+ compLogMessage ("mag", CompLogLevelError,
+ "failed to fisheye program");
+
+- (*s->deletePrograms) (1, &ms->program);
+- ms->program = 0;
++ (*s->deletePrograms) (1, &dev->program);
++ dev->program = 0;
+
+ return FALSE;
+ }
+@@ -245,11 +229,180 @@ loadImages (CompScreen *s)
+ }
+
+ static void
++magCleanup (CompScreen *s)
++{
++ MAG_SCREEN (s);
++
++ if (ms->overlay.loaded)
++ {
++ ms->overlay.loaded = FALSE;
++ finiTexture (s, &ms->overlay.tex);
++ initTexture (s, &ms->overlay.tex);
++ }
++ if (ms->mask.loaded)
++ {
++ ms->mask.loaded = FALSE;
++ finiTexture (s, &ms->mask.tex);
++ initTexture (s, &ms->mask.tex);
++ }
++}
++
++static void
++magCleanupDevice (CompScreen *s, MagDevice *dev)
++{
++ glDeleteTextures (1, &dev->target);
++
++ if (dev->program)
++ {
++ (*s->deletePrograms) (1, &dev->program);
++ dev->program = 0;
++ }
++}
++
++
++/* Get device info, add to list, etc */
++
++static void
++magInitDevice (CompScreen *s,
++ MagDevice *dev)
++{
++
++ MAG_SCREEN (s);
++
++ glGenTextures (1, &dev->texture);
++
++ if (s->textureNonPowerOfTwo)
++ dev->target = GL_TEXTURE_2D;
++ else
++ dev->target = GL_TEXTURE_RECTANGLE_ARB;
++
++ glEnable (dev->target);
++
++ /* Bind the texture */
++ glBindTexture (dev->target, dev->texture);
++
++ /* Load the parameters */
++ glTexParameteri (dev->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
++ glTexParameteri (dev->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
++ glTexParameteri (dev->target, GL_TEXTURE_WRAP_S, GL_CLAMP);
++ glTexParameteri (dev->target, GL_TEXTURE_WRAP_T, GL_CLAMP);
++
++ glTexImage2D (dev->target, 0, GL_RGB, 0, 0, 0,
++ GL_RGB, GL_UNSIGNED_BYTE, NULL);
++
++ dev->zoom = 1.0;
++ dev->zVelocity = 0.0;
++ dev->zTarget = 1.0;
++
++ dev->width = 0;
++ dev->height = 0;
++
++ glBindTexture (dev->target, 0);
++
++ glDisable (dev->target);
++
++ dev->program = 0;
++
++ switch (magGetMode (s))
++ {
++ case ModeImageOverlay:
++ if (loadImages (s))
++ ms->mode = ModeImageOverlay;
++ else
++ ms->mode = ModeSimple;
++ break;
++ case ModeFisheye:
++ if (loadFragmentProgram (s, dev))
++ ms->mode = ModeFisheye;
++ else
++ ms->mode = ModeSimple;
++ break;
++ default:
++ ms->mode = ModeSimple;
++ }
++
++}
++
++static MagDevice *
++magAddDeviceToList (CompScreen *s,
++ CompDevice *dev)
++{
++ MAG_SCREEN (s);
++ MagDevice *mDev;
++
++ if (!ms->devices)
++ {
++ ms->devices = calloc (1, sizeof (MagDevice));
++ if (!ms->devices)
++ return NULL;
++ ms->devices->dev = dev;
++ ms->devices->next = NULL;
++ magInitDevice (s, ms->devices);
++ return ms->devices;
++ }
++ else
++ {
++ for (mDev = ms->devices; mDev->next; mDev = mDev->next);
++ /* List exhausted */
++
++ mDev->next = calloc (1, sizeof (MagDevice));
++ if (!mDev->next)
++ return NULL;
++ mDev->next->dev = dev;
++ mDev->next->next = NULL;
++ magInitDevice (s, mDev->next);
++ return mDev->next;
++ }
++ return NULL;
++}
++
++static void
++magRemoveDeviceFromList (CompScreen *s,
++ MagDevice *dev)
++{
++ MAG_SCREEN (s);
++ MagDevice *run;
++
++ if (!ms->devices)
++ return;
++
++ if (dev == ms->devices)
++ {
++ if (ms->devices->next)
++ ms->devices = ms->devices->next;
++ else
++ ms->devices = NULL;
++
++ magCleanupDevice (s, dev);
++ if (dev)
++ free (dev);
++ }
++ else
++ {
++ for (run = ms->devices; run; run = run->next)
++ {
++ if (run->next)
++ if (run->next == dev)
++ {
++ if (run->next->next)
++ run->next = run->next->next;
++ else
++ run = NULL;
++
++ magCleanupDevice (s, dev);
++ if (dev)
++ free (dev);
++ }
++ }
++ }
++}
++static void
+ magOptionsChanged (CompScreen *s,
+ CompOption *opt,
+ MagScreenOptions num)
+ {
+ MAG_SCREEN (s);
++ MagDevice *dev;
+
+ magCleanup (s);
+
+@@ -262,21 +415,31 @@ magOptionsChanged (CompScreen *s,
+ ms->mode = ModeSimple;
+ break;
+ case ModeFisheye:
+- if (loadFragmentProgram (s))
+- ms->mode = ModeFisheye;
+- else
+- ms->mode = ModeSimple;
++ {
++ MagDevice *dev;
++ for (dev = ms->devices; dev; dev = dev->next)
++ {
++ if (loadFragmentProgram (s, dev))
++ ms->mode = ModeFisheye;
++ else
++ {
++ ms->mode = ModeSimple;
++ break;
++ }
++ }
+ break;
++ }
+ default:
+ ms->mode = ModeSimple;
+ }
+
+- if (ms->zoom != 1.0)
+- damageScreen (s);
++ for (dev = ms->devices; dev; dev = dev->next)
++ if (dev->zoom != 1.0)
++ damageScreen (s);
+ }
+
+ static void
+-damageRegion (CompScreen *s)
++damageRegion (CompScreen *s, MagDevice *dev)
+ {
+ REGION r;
+
+@@ -297,26 +460,26 @@ damageRegion (CompScreen *s)
+ w += 2 * b;
+ h += 2 * b;
+
+- r.extents.x1 = MAX (0, MIN (ms->posX - (w / 2), s->width - w));
++ r.extents.x1 = MAX (0, MIN (dev->posX - (w / 2), s->width - w));
+ r.extents.x2 = r.extents.x1 + w;
+- r.extents.y1 = MAX (0, MIN (ms->posY - (h / 2), s->height - h));
++ r.extents.y1 = MAX (0, MIN (dev->posY - (h / 2), s->height - h));
+ r.extents.y2 = r.extents.y1 + h;
+ }
+ break;
+ case ModeImageOverlay:
+- r.extents.x1 = ms->posX - magGetXOffset (s);
++ r.extents.x1 = dev->posX - magGetXOffset (s);
+ r.extents.x2 = r.extents.x1 + ms->overlay.width;
+- r.extents.y1 = ms->posY - magGetYOffset (s);
++ r.extents.y1 = dev->posY - magGetYOffset (s);
+ r.extents.y2 = r.extents.y1 + ms->overlay.height;
+ break;
+ case ModeFisheye:
+ {
+ int radius = magGetRadius (s);
+
+- r.extents.x1 = MAX (0.0, ms->posX - radius);
+- r.extents.x2 = MIN (s->width, ms->posX + radius);
+- r.extents.y1 = MAX (0.0, ms->posY - radius);
+- r.extents.y2 = MIN (s->height, ms->posY + radius);
++ r.extents.x1 = MAX (0.0, dev->posX - radius);
++ r.extents.x2 = MIN (s->width, dev->posX + radius);
++ r.extents.y1 = MAX (0.0, dev->posY - radius);
++ r.extents.y2 = MIN (s->height, dev->posY + radius);
+ }
+ break;
+ }
+@@ -326,28 +489,37 @@ damageRegion (CompScreen *s)
+
+ static void
+ positionUpdate (CompScreen *s,
+- int x,
+- int y)
++ MousepollDevice *dev)
+ {
+ MAG_SCREEN (s);
+
+- damageRegion (s);
++ MagDevice *mDev;
++
++ for (; dev; dev = dev->next)
++ {
++ for (mDev = ms->devices; mDev; mDev = mDev->next)
++ {
++ if (dev->dev == mDev->dev)
++ {
++
++ damageRegion (s, mDev);
+
+- ms->posX = x;
+- ms->posY = y;
++ mDev->posX = dev->posX;
++ mDev->posY = dev->posY;
+
+- damageRegion (s);
++ damageRegion (s, mDev);
++ }
++ }
++ }
+ }
+
+ static int
+-adjustZoom (CompScreen *s, float chunk)
++adjustZoom (MagDevice *dev, float chunk)
+ {
+ float dx, adjust, amount;
+ float change;
+
+- MAG_SCREEN(s);
+-
+- dx = ms->zTarget - ms->zoom;
++ dx = dev->zTarget - dev->zoom;
+
+ adjust = dx * 0.15f;
+ amount = fabs(dx) * 1.5f;
+@@ -356,23 +528,23 @@ adjustZoom (CompScreen *s, float chunk)
+ else if (amount > 2.0f)
+ amount = 2.0f;
+
+- ms->zVelocity = (amount * ms->zVelocity + adjust) / (amount + 1.0f);
++ dev->zVelocity = (amount * dev->zVelocity + adjust) / (amount + 1.0f);
+
+- if (fabs (dx) < 0.002f && fabs (ms->zVelocity) < 0.004f)
++ if (fabs (dx) < 0.002f && fabs (dev->zVelocity) < 0.004f)
+ {
+- ms->zVelocity = 0.0f;
+- ms->zoom = ms->zTarget;
++ dev->zVelocity = 0.0f;
++ dev->zoom = dev->zTarget;
+ return FALSE;
+ }
+
+- change = ms->zVelocity * chunk;
++ change = dev->zVelocity * chunk;
+ if (!change)
+ {
+- if (ms->zVelocity)
++ if (dev->zVelocity)
+ change = (dx > 0) ? 0.01 : -0.01;
+ }
+
+- ms->zoom += change;
++ dev->zoom += change;
+
+ return TRUE;
+ }
+@@ -384,36 +556,42 @@ magPreparePaintScreen (CompScreen *s,
+ MAG_SCREEN (s);
+ MAG_DISPLAY (s->display);
+
+- if (ms->adjust)
++ MagDevice *dev;
++
++ for (dev = ms->devices; dev; dev = dev->next)
+ {
+- int steps;
+- float amount, chunk;
+
+- amount = time * 0.35f * magGetSpeed (s);
+- steps = amount / (0.5f * magGetTimestep (s));
++ if (dev->adjust)
++ {
++ int steps;
++ float amount, chunk;
+
+- if (!steps)
+- steps = 1;
++ amount = time * 0.35f * magGetSpeed (s);
++ steps = amount / (0.5f * magGetTimestep (s));
+
+- chunk = amount / (float) steps;
++ if (!steps)
++ steps = 1;
+
+- while (steps--)
+- {
+- ms->adjust = adjustZoom (s, chunk);
+- if (ms->adjust)
+- break;
+- }
+- }
++ chunk = amount / (float) steps;
+
+- if (ms->zoom != 1.0)
+- {
+- if (!ms->pollHandle)
++ while (steps--)
++ {
++ dev->adjust = adjustZoom (dev, chunk);
++ if (dev->adjust)
++ break;
++ }
++ }
++
++ if (dev->zoom != 1.0)
+ {
+- (*md->mpFunc->getCurrentPosition) (s, &ms->posX, &ms->posY);
+- ms->pollHandle =
+- (*md->mpFunc->addPositionPolling) (s, positionUpdate);
++ if (!ms->pollHandle)
++ {
++ (*md->mpFunc->getCurrentPosition) (s, dev, &dev->posX, &dev->posY);
++ ms->pollHandle =
++ (*md->mpFunc->addPositionPolling) (s, NULL, positionUpdate);
++ }
++ damageRegion (s, dev);
+ }
+- damageRegion (s);
+ }
+
+ UNWRAP (ms, s, preparePaintScreen);
+@@ -427,39 +605,51 @@ magDonePaintScreen (CompScreen *s)
+ MAG_SCREEN (s);
+ MAG_DISPLAY (s->display);
+
+- if (ms->adjust)
+- damageRegion (s);
++ MagDevice *dev;
+
+- if (!ms->adjust && ms->zoom == 1.0 && (ms->width || ms->height))
++ if (ms->devices)
++ for (dev = ms->devices; dev; dev = dev->next)
+ {
+- glEnable (ms->target);
+
+- glBindTexture (ms->target, ms->texture);
++ if (dev->adjust)
++ damageRegion (s, dev);
++
++ if (!dev->adjust && dev->zoom == 1.0 && (dev->width || dev->height))
++ {
++ glEnable (dev->target);
++
++ glBindTexture (dev->target, dev->texture);
+
+- glTexImage2D (ms->target, 0, GL_RGB, 0, 0, 0,
++ glTexImage2D (dev->target, 0, GL_RGB, 0, 0, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, NULL);
+
+- ms->width = 0;
+- ms->height = 0;
+-
+- glBindTexture (ms->target, 0);
++ dev->width = 0;
++ dev->height = 0;
+
+- glDisable (ms->target);
+- }
++ glBindTexture (dev->target, 0);
+
+- if (ms->zoom == 1.0 && !ms->adjust && ms->pollHandle)
+- {
+- (*md->mpFunc->removePositionPolling) (s, ms->pollHandle);
+- ms->pollHandle = 0;
+- }
++ glDisable (dev->target);
++ }
++
++ if (dev->zoom == 1.0 && !dev->adjust && dev->zTarget == 1.0)
++ {
++ magRemoveDeviceFromList (s, dev);
+
++ if (!ms->devices)
++ {
++ (*md->mpFunc->removePositionPolling) (s, ms->pollHandle);
++ ms->pollHandle = 0;
++ }
++ }
++
++ }
+ UNWRAP (ms, s, donePaintScreen);
+ (*s->donePaintScreen) (s);
+ WRAP (ms, s, donePaintScreen, magDonePaintScreen);
+ }
+
+ static void
+-magPaintSimple (CompScreen *s)
++magPaintSimple (CompScreen *s, MagDevice *dev)
+ {
+ float pw, ph, bw, bh;
+ int x1, x2, y1, y2;
+@@ -470,171 +660,170 @@ magPaintSimple (CompScreen *s)
+ unsigned short *color;
+ float tmp;
+
+- MAG_SCREEN (s);
+-
+ w = magGetBoxWidth (s);
+ h = magGetBoxHeight (s);
+
+ kScreen = magGetKeepScreen (s);
+
+- x1 = ms->posX - (w / 2);
+- if (kScreen)
++ x1 = dev->posX - (w / 2);
++ if (kScreen)
+ x1 = MAX (0, MIN (x1, s->width - w));
+- x2 = x1 + w;
+- y1 = ms->posY - (h / 2);
+- if (kScreen)
++ x2 = x1 + w;
++ y1 = dev->posY - (h / 2);
++ if (kScreen)
+ y1 = MAX (0, MIN (y1, s->height - h));
+- y2 = y1 + h;
+-
+- cw = ceil ((float)w / (ms->zoom * 2.0)) * 2.0;
+- ch = ceil ((float)h / (ms->zoom * 2.0)) * 2.0;
+- cw = MIN (w, cw + 2);
+- ch = MIN (h, ch + 2);
+- cx = (w - cw) / 2;
+- cy = (h - ch) / 2;
++ y2 = y1 + h;
+
+- cx = MAX (0, MIN (w - cw, cx));
+- cy = MAX (0, MIN (h - ch, cy));
++ cw = ceil ((float)w / (dev->zoom * 2.0)) * 2.0;
++ ch = ceil ((float)h / (dev->zoom * 2.0)) * 2.0;
++ cw = MIN (w, cw + 2);
++ ch = MIN (h, ch + 2);
++ cx = (w - cw) / 2;
++ cy = (h - ch) / 2;
+
+- if (x1 != (ms->posX - (w / 2)))
+- {
++ cx = MAX (0, MIN (w - cw, cx));
++ cy = MAX (0, MIN (h - ch, cy));
++
++ if (x1 != (dev->posX - (w / 2)))
++ {
+ cx = 0;
+ cw = w;
+- }
+- if (y1 != (ms->posY - (h / 2)))
+- {
++ }
++ if (y1 != (dev->posY - (h / 2)))
++ {
+ cy = 0;
+ ch = h;
+- }
++ }
+
+- glEnable (ms->target);
++ glEnable (dev->target);
+
+- glBindTexture (ms->target, ms->texture);
++ glBindTexture (dev->target, dev->texture);
+
+- if (ms->width != w || ms->height != h)
+- {
+- glCopyTexImage2D(ms->target, 0, GL_RGB, x1, s->height - y2,
++ if (dev->width != w || dev->height != h)
++ {
++ glCopyTexImage2D(dev->target, 0, GL_RGB, x1, s->height - y2,
+ w, h, 0);
+- ms->width = w;
+- ms->height = h;
+- }
+- else
+- glCopyTexSubImage2D (ms->target, 0, cx, cy,
++ dev->width = w;
++ dev->height = h;
++ }
++ else
++ glCopyTexSubImage2D (dev->target, 0, cx, cy,
+ x1 + cx, s->height - y2 + cy, cw, ch);
+
+- if (ms->target == GL_TEXTURE_2D)
+- {
+- pw = 1.0 / ms->width;
+- ph = 1.0 / ms->height;
+- }
+- else
+- {
++ if (dev->target == GL_TEXTURE_2D)
++ {
++ pw = 1.0 / dev->width;
++ ph = 1.0 / dev->height;
++ }
++ else
++ {
+ pw = 1.0;
+ ph = 1.0;
+- }
++ }
+
+- glMatrixMode (GL_PROJECTION);
+- glPushMatrix ();
+- glLoadIdentity ();
+- glMatrixMode (GL_MODELVIEW);
+- glPushMatrix ();
+- glLoadIdentity ();
++ glMatrixMode (GL_PROJECTION);
++ glPushMatrix ();
++ glLoadIdentity ();
++ glMatrixMode (GL_MODELVIEW);
++ glPushMatrix ();
++ glLoadIdentity ();
+
+- vc[0] = ((x1 * 2.0) / s->width) - 1.0;
+- vc[1] = ((x2 * 2.0) / s->width) - 1.0;
+- vc[2] = ((y1 * -2.0) / s->height) + 1.0;
+- vc[3] = ((y2 * -2.0) / s->height) + 1.0;
++ vc[0] = ((x1 * 2.0) / s->width) - 1.0;
++ vc[1] = ((x2 * 2.0) / s->width) - 1.0;
++ vc[2] = ((y1 * -2.0) / s->height) + 1.0;
++ vc[3] = ((y2 * -2.0) / s->height) + 1.0;
+
+- tc[0] = 0.0;
+- tc[1] = w * pw;
+- tc[2] = h * ph;
+- tc[3] = 0.0;
++ tc[0] = 0.0;
++ tc[1] = w * pw;
++ tc[2] = h * ph;
++ tc[3] = 0.0;
+
+- glColor4usv (defaultColor);
++ glColor4usv (defaultColor);
+
+- glPushMatrix ();
++ glPushMatrix ();
+
+- glTranslatef ((float)(ms->posX - (s->width / 2)) * 2 / s->width,
+- (float)(ms->posY - (s->height / 2)) * 2 / -s->height, 0.0);
++ glTranslatef ((float)(dev->posX - (s->width / 2)) * 2 / s->width,
++ (float)(dev->posY - (s->height / 2)) * 2 / -s->height, 0.0);
+
+- glScalef (ms->zoom, ms->zoom, 1.0);
++ glScalef (dev->zoom, dev->zoom, 1.0);
+
+- glTranslatef ((float)((s->width / 2) - ms->posX) * 2 / s->width,
+- (float)((s->height / 2) - ms->posY) * 2 / -s->height, 0.0);
++ glTranslatef ((float)((s->width / 2) - dev->posX) * 2 / s->width,
++ (float)((s->height / 2) - dev->posY) * 2 / -s->height, 0.0);
+
+- glScissor (x1, s->height - y2, w, h);
++ glScissor (x1, s->height - y2, w, h);
+
+- glEnable (GL_SCISSOR_TEST);
++ glEnable (GL_SCISSOR_TEST);
+
+- glBegin (GL_QUADS);
+- glTexCoord2f (tc[0], tc[2]);
+- glVertex2f (vc[0], vc[2]);
+- glTexCoord2f (tc[0], tc[3]);
+- glVertex2f (vc[0], vc[3]);
+- glTexCoord2f (tc[1], tc[3]);
+- glVertex2f (vc[1], vc[3]);
+- glTexCoord2f (tc[1], tc[2]);
+- glVertex2f (vc[1], vc[2]);
+- glEnd ();
++ glBegin (GL_QUADS);
++ glTexCoord2f (tc[0], tc[2]);
++ glVertex2f (vc[0], vc[2]);
++ glTexCoord2f (tc[0], tc[3]);
++ glVertex2f (vc[0], vc[3]);
++ glTexCoord2f (tc[1], tc[3]);
++ glVertex2f (vc[1], vc[3]);
++ glTexCoord2f (tc[1], tc[2]);
++ glVertex2f (vc[1], vc[2]);
++ glEnd ();
+
+- glDisable (GL_SCISSOR_TEST);
++ glDisable (GL_SCISSOR_TEST);
+
+- glPopMatrix ();
++ glPopMatrix ();
+
+- glBindTexture (ms->target, 0);
++ glBindTexture (dev->target, 0);
+
+- glDisable (ms->target);
++ glDisable (dev->target);
+
+- glEnable (GL_BLEND);
+- glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
++ glEnable (GL_BLEND);
++ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+- tmp = MIN (1.0, (ms->zoom - 1) * 3.0);
++ tmp = MIN (1.0, (dev->zoom - 1) * 3.0);
+
+- bw = bh = magGetBorder (s);
++ bw = bh = magGetBorder (s);
+
+- bw = bw * 2.0 / s->width;
+- bh = bh * 2.0 / s->height;
++ bw = bw * 2.0 / s->width;
++ bh = bh * 2.0 / s->height;
+
+- bw = bh = magGetBorder (s);
++ bw = bh = magGetBorder (s);
+
+- bw *= 2.0 / (float)s->width;
+- bh *= 2.0 / (float)s->height;
++ bw *= 2.0 / (float)s->width;
++ bh *= 2.0 / (float)s->height;
+
+- color = magGetBoxColor (s);
++ color = magGetBoxColor (s);
+
+- glColor4us (color[0], color[1], color[2], color[3] * tmp);
++ glColor4us (color[0], color[1], color[2], color[3] * tmp);
+
+- glBegin (GL_QUADS);
+- glVertex2f (vc[0] - bw, vc[2] + bh);
+- glVertex2f (vc[0] - bw, vc[2]);
+- glVertex2f (vc[1] + bw, vc[2]);
+- glVertex2f (vc[1] + bw, vc[2] + bh);
+- glVertex2f (vc[0] - bw, vc[3]);
+- glVertex2f (vc[0] - bw, vc[3] - bh);
+- glVertex2f (vc[1] + bw, vc[3] - bh);
+- glVertex2f (vc[1] + bw, vc[3]);
+- glVertex2f (vc[0] - bw, vc[2]);
+- glVertex2f (vc[0] - bw, vc[3]);
+- glVertex2f (vc[0], vc[3]);
+- glVertex2f (vc[0], vc[2]);
+- glVertex2f (vc[1], vc[2]);
+- glVertex2f (vc[1], vc[3]);
+- glVertex2f (vc[1] + bw, vc[3]);
+- glVertex2f (vc[1] + bw, vc[2]);
+- glEnd();
++ glBegin (GL_QUADS);
++ glVertex2f (vc[0] - bw, vc[2] + bh);
++ glVertex2f (vc[0] - bw, vc[2]);
++ glVertex2f (vc[1] + bw, vc[2]);
++ glVertex2f (vc[1] + bw, vc[2] + bh);
++ glVertex2f (vc[0] - bw, vc[3]);
++ glVertex2f (vc[0] - bw, vc[3] - bh);
++ glVertex2f (vc[1] + bw, vc[3] - bh);
++ glVertex2f (vc[1] + bw, vc[3]);
++ glVertex2f (vc[0] - bw, vc[2]);
++ glVertex2f (vc[0] - bw, vc[3]);
++ glVertex2f (vc[0], vc[3]);
++ glVertex2f (vc[0], vc[2]);
++ glVertex2f (vc[1], vc[2]);
++ glVertex2f (vc[1], vc[3]);
++ glVertex2f (vc[1] + bw, vc[3]);
++ glVertex2f (vc[1] + bw, vc[2]);
++ glEnd();
+
+- glColor4usv (defaultColor);
+- glDisable (GL_BLEND);
+- glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
++ glColor4usv (defaultColor);
++ glDisable (GL_BLEND);
++ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
++
++ glPopMatrix();
++ glMatrixMode (GL_PROJECTION);
++ glPopMatrix ();
++ glMatrixMode (GL_MODELVIEW);
+
+- glPopMatrix();
+- glMatrixMode (GL_PROJECTION);
+- glPopMatrix ();
+- glMatrixMode (GL_MODELVIEW);
+ }
+
+ static void
+-magPaintImage (CompScreen *s)
++magPaintImage (CompScreen *s, MagDevice *dev)
+ {
+ float pw, ph;
+ int x1, x2, y1, y2;
+@@ -651,42 +840,42 @@ magPaintImage (CompScreen *s)
+ xOff = MIN (w, magGetXOffset (s));
+ yOff = MIN (h, magGetYOffset (s));
+
+- x1 = ms->posX - xOff;
++ x1 = dev->posX - xOff;
+ x2 = x1 + w;
+- y1 = ms->posY - yOff;
++ y1 = dev->posY - yOff;
+ y2 = y1 + h;
+
+- cw = ceil ((float)w / (ms->zoom * 2.0)) * 2.0;
+- ch = ceil ((float)h / (ms->zoom * 2.0)) * 2.0;
++ cw = ceil ((float)w / (dev->zoom * 2.0)) * 2.0;
++ ch = ceil ((float)h / (dev->zoom * 2.0)) * 2.0;
+ cw = MIN (w, cw + 2);
+ ch = MIN (h, ch + 2);
+- cx = floor (xOff - (xOff / ms->zoom));
+- cy = h - ch - floor (yOff - (yOff / ms->zoom));
++ cx = floor (xOff - (xOff / dev->zoom));
++ cy = h - ch - floor (yOff - (yOff / dev->zoom));
+
+ cx = MAX (0, MIN (w - cw, cx));
+ cy = MAX (0, MIN (h - ch, cy));
+
+ glPushAttrib (GL_TEXTURE_BIT);
+
+- glEnable (ms->target);
++ glEnable (dev->target);
+
+- glBindTexture (ms->target, ms->texture);
++ glBindTexture (dev->target, dev->texture);
+
+- if (ms->width != w || ms->height != h)
++ if (dev->width != w || dev->height != h)
+ {
+- glCopyTexImage2D(ms->target, 0, GL_RGB, x1, s->height - y2,
++ glCopyTexImage2D(dev->target, 0, GL_RGB, x1, s->height - y2,
+ w, h, 0);
+- ms->width = w;
+- ms->height = h;
++ dev->width = w;
++ dev->height = h;
+ }
+ else
+- glCopyTexSubImage2D (ms->target, 0, cx, cy,
++ glCopyTexSubImage2D (dev->target, 0, cx, cy,
+ x1 + cx, s->height - y2 + cy, cw, ch);
+
+- if (ms->target == GL_TEXTURE_2D)
++ if (dev->target == GL_TEXTURE_2D)
+ {
+- pw = 1.0 / ms->width;
+- ph = 1.0 / ms->height;
++ pw = 1.0 / dev->width;
++ ph = 1.0 / dev->height;
+ }
+ else
+ {
+@@ -706,11 +895,11 @@ magPaintImage (CompScreen *s)
+ vc[2] = ((y1 * -2.0) / s->height) + 1.0;
+ vc[3] = ((y2 * -2.0) / s->height) + 1.0;
+
+- tc[0] = xOff - (xOff / ms->zoom);
+- tc[1] = tc[0] + (w / ms->zoom);
++ tc[0] = xOff - (xOff / dev->zoom);
++ tc[1] = tc[0] + (w / dev->zoom);
+
+- tc[2] = h - (yOff - (yOff / ms->zoom));
+- tc[3] = tc[2] - (h / ms->zoom);
++ tc[2] = h - (yOff - (yOff / dev->zoom));
++ tc[3] = tc[2] - (h / dev->zoom);
+
+ tc[0] *= pw;
+ tc[1] *= pw;
+@@ -752,11 +941,11 @@ magPaintImage (CompScreen *s)
+ disableTexture (s, &ms->mask.tex);
+ (*s->activeTexture) (GL_TEXTURE0_ARB);
+
+- glBindTexture (ms->target, 0);
++ glBindTexture (dev->target, 0);
+
+- glDisable (ms->target);
++ glDisable (dev->target);
+
+- tmp = MIN (1.0, (ms->zoom - 1) * 3.0);
++ tmp = MIN (1.0, (dev->zoom - 1) * 3.0);
+
+ glColor4f (tmp, tmp, tmp, tmp);
+
+@@ -794,7 +983,7 @@ magPaintImage (CompScreen *s)
+ }
+
+ static void
+-magPaintFisheye (CompScreen *s)
++magPaintFisheye (CompScreen *s, MagDevice *dev)
+ {
+ float pw, ph;
+ float radius, zoom, base;
+@@ -802,37 +991,35 @@ magPaintFisheye (CompScreen *s)
+ float vc[4];
+ int size;
+
+- MAG_SCREEN (s);
+-
+ radius = magGetRadius (s);
+ base = 0.5 + (0.0015 * radius);
+- zoom = (ms->zoom * base) + 1.0 - base;
++ zoom = (dev->zoom * base) + 1.0 - base;
+
+ size = radius + 1;
+
+- x1 = MAX (0.0, ms->posX - size);
+- x2 = MIN (s->width, ms->posX + size);
+- y1 = MAX (0.0, ms->posY - size);
+- y2 = MIN (s->height, ms->posY + size);
++ x1 = MAX (0.0, dev->posX - size);
++ x2 = MIN (s->width, dev->posX + size);
++ y1 = MAX (0.0, dev->posY - size);
++ y2 = MIN (s->height, dev->posY + size);
+
+- glEnable (ms->target);
++ glEnable (dev->target);
+
+- glBindTexture (ms->target, ms->texture);
++ glBindTexture (dev->target, dev->texture);
+
+- if (ms->width != 2 * size || ms->height != 2 * size)
++ if (dev->width != 2 * size || dev->height != 2 * size)
+ {
+- glCopyTexImage2D(ms->target, 0, GL_RGB, x1, s->height - y2,
++ glCopyTexImage2D(dev->target, 0, GL_RGB, x1, s->height - y2,
+ size * 2, size * 2, 0);
+- ms->width = ms->height = 2 * size;
++ dev->width = dev->height = 2 * size;
+ }
+ else
+- glCopyTexSubImage2D (ms->target, 0, 0, 0,
++ glCopyTexSubImage2D (dev->target, 0, 0, 0,
+ x1, s->height - y2, x2 - x1, y2 - y1);
+
+- if (ms->target == GL_TEXTURE_2D)
++ if (dev->target == GL_TEXTURE_2D)
+ {
+- pw = 1.0 / ms->width;
+- ph = 1.0 / ms->height;
++ pw = 1.0 / dev->width;
++ ph = 1.0 / dev->height;
+ }
+ else
+ {
+@@ -850,10 +1037,10 @@ magPaintFisheye (CompScreen *s)
+ glColor4usv (defaultColor);
+
+ glEnable (GL_FRAGMENT_PROGRAM_ARB);
+- (*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, ms->program);
++ (*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, dev->program);
+
+ (*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB, 0,
+- ms->posX, s->height - ms->posY,
++ dev->posX, s->height - dev->posY,
+ 1.0 / radius, 0.0f);
+ (*s->programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB, 1,
+ pw, ph, M_PI / radius,
+@@ -862,10 +1049,10 @@ magPaintFisheye (CompScreen *s)
+ -x1 * pw, -(s->height - y2) * ph,
+ -M_PI / 2.0, 0.0);
+
+- x1 = MAX (0.0, ms->posX - radius);
+- x2 = MIN (s->width, ms->posX + radius);
+- y1 = MAX (0.0, ms->posY - radius);
+- y2 = MIN (s->height, ms->posY + radius);
++ x1 = MAX (0.0, dev->posX - radius);
++ x2 = MIN (s->width, dev->posX + radius);
++ y1 = MAX (0.0, dev->posY - radius);
++ y2 = MIN (s->height, dev->posY + radius);
+
+ vc[0] = ((x1 * 2.0) / s->width) - 1.0;
+ vc[1] = ((x2 * 2.0) / s->width) - 1.0;
+@@ -895,9 +1082,9 @@ magPaintFisheye (CompScreen *s)
+ glPopMatrix ();
+ glMatrixMode (GL_MODELVIEW);
+
+- glBindTexture (ms->target, 0);
++ glBindTexture (dev->target, 0);
+
+- glDisable (ms->target);
++ glDisable (dev->target);
+ }
+
+ static void
+@@ -907,6 +1094,7 @@ magPaintScreen (CompScreen *s,
+ unsigned int mask)
+ {
+ XRectangle r;
++ MagDevice *dev;
+
+ MAG_SCREEN (s);
+
+@@ -914,7 +1102,10 @@ magPaintScreen (CompScreen *s,
+ (*s->paintScreen) (s, outputs, numOutput, mask);
+ WRAP (ms, s, paintScreen, magPaintScreen);
+
+- if (ms->zoom == 1.0)
++ for (dev = ms->devices; dev; dev = dev->next)
++ {
++
++ if (dev->zoom == 1.0)
+ return;
+
+ r.x = 0;
+@@ -934,13 +1125,14 @@ magPaintScreen (CompScreen *s,
+ switch (ms->mode)
+ {
+ case ModeImageOverlay:
+- magPaintImage (s);
++ magPaintImage (s, dev);
+ break;
+ case ModeFisheye:
+- magPaintFisheye (s);
++ magPaintFisheye (s, dev);
+ break;
+ default:
+- magPaintSimple (s);
++ magPaintSimple (s, dev);
++ }
+ }
+
+ }
+@@ -953,6 +1145,7 @@ magTerminate (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ MagDevice *dev;
+ Window xid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+@@ -962,9 +1155,12 @@ magTerminate (CompDisplay *d,
+ {
+ MAG_SCREEN (s);
+
+- ms->zTarget = 1.0;
+- ms->adjust = TRUE;
+- damageScreen (s);
++ for (dev = ms->devices; dev; dev = dev->next)
++ {
++ dev->zTarget = 1.0;
++ dev->adjust = TRUE;
++ damageScreen (s);
++ }
+
+ return TRUE;
+ }
+@@ -981,6 +1177,8 @@ magInitiate (CompDisplay *d,
+ CompScreen *s;
+ Window xid;
+ float factor;
++ MagDevice *mDev;
++ CompDevice *dev;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+ factor = getFloatOptionNamed (option, nOption, "factor", 0.0);
+@@ -990,27 +1188,49 @@ magInitiate (CompDisplay *d,
+ {
+ MAG_SCREEN (s);
+
+- if (factor == 0.0 && ms->zTarget != 1.0)
+- return magTerminate (d, action, state, option, nOption);
+-
+- if (ms->mode == ModeFisheye)
++ for (dev = s->display->devices; dev->id != -1; dev++)
+ {
+- if (factor != 1.0)
+- factor = magGetZoomFactor (s) * 3;
+-
+- ms->zTarget = MAX (1.0, MIN (10.0, factor));
++ if (dev->use != IsXPointer)
++ continue;
++
++ for (mDev = ms->devices; mDev; mDev = mDev->next)
++ if (mDev->dev == dev)
++ break;
++
++ if (!mDev) /* This devices is not in the list */
++ mDev = magAddDeviceToList (s, dev);
++
++ if (!mDev)
++ return FALSE;
++
++ if (factor == 0.0 && mDev->zTarget != 1.0)
++ return magTerminate (d, action, state, option, nOption);
++
++ if (ms->mode == ModeFisheye)
++ {
++ if (factor != 1.0)
++ factor = magGetZoomFactor (s) * 3;
++
++ mDev->zTarget = MAX (1.0, MIN (10.0, factor));
++ }
++ else
++ {
++ if (factor != 1.0)
++ factor = magGetZoomFactor (s);
++
++ mDev->zTarget = MAX (1.0, MIN (64.0, factor));
++ }
++ mDev->adjust = TRUE;
++ damageScreen (s);
+ }
+- else
+- {
+- if (factor != 1.0)
+- factor = magGetZoomFactor (s);
+-
+- ms->zTarget = MAX (1.0, MIN (64.0, factor));
+- }
+- ms->adjust = TRUE;
+- damageScreen (s);
+
+ return TRUE;
++ if (state & CompActionStateInitButton)
++ action->state |= CompActionStateTermButton;
++
++ if (state & CompActionStateInitKey)
++ action->state |= CompActionStateTermKey;
++
+ }
+ return FALSE;
+ }
+@@ -1023,20 +1243,36 @@ magZoomIn (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
++ int deviceid;
+ Window xid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
++ deviceid = getIntOptionNamed (option, nOption, "device", -1);
++
+
++ dev = compFindDeviceById (d, deviceid);
+ s = findScreenAtDisplay (d, xid);
+- if (s)
++ if (s && dev)
+ {
+ MAG_SCREEN (s);
++ MagDevice *run;
++
++ for (run = ms->devices; run; run = run->next)
++ if (run->dev == dev)
++ break;
++
++ if (!run)
++ run = magAddDeviceToList (s, dev);
++
++ if (!run)
++ return FALSE;
+
+ if (ms->mode == ModeFisheye)
+- ms->zTarget = MIN (10.0, ms->zTarget + 1.0);
++ run->zTarget = MIN (10.0, run->zTarget + 1.0);
+ else
+- ms->zTarget = MIN (64.0, ms->zTarget * 1.2);
+- ms->adjust = TRUE;
++ run->zTarget = MIN (64.0, run->zTarget * 1.2);
++ run->adjust = TRUE;
+ damageScreen (s);
+
+ return TRUE;
+@@ -1052,20 +1288,32 @@ magZoomOut (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
++ int deviceid;
+ Window xid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
++ deviceid = getIntOptionNamed (option, nOption, "device", -1);
+
+ s = findScreenAtDisplay (d, xid);
+- if (s)
++ dev = compFindDeviceById (d, deviceid);
++ if (s && dev)
+ {
++ MagDevice *run;
+ MAG_SCREEN (s);
+
++ for (run = ms->devices; run; run = run->next)
++ if (run->dev == dev)
++ break;
++
++ if (!run)
++ return FALSE;
++
+ if (ms->mode == ModeFisheye)
+- ms->zTarget = MAX (1.0, ms->zTarget - 1.0);
++ run->zTarget = MAX (1.0, run->zTarget - 1.0);
+ else
+- ms->zTarget = MAX (1.0, ms->zTarget / 1.2);
+- ms->adjust = TRUE;
++ run->zTarget = MAX (1.0, run->zTarget / 1.2);
++ run->adjust = TRUE;
+ damageScreen (s);
+
+ return TRUE;
+@@ -1092,69 +1340,17 @@ magInitScreen (CompPlugin *p,
+ WRAP (ms, s, preparePaintScreen, magPreparePaintScreen);
+ WRAP (ms, s, donePaintScreen, magDonePaintScreen);
+
+- ms->zoom = 1.0;
+- ms->zVelocity = 0.0;
+- ms->zTarget = 1.0;
+-
+ ms->pollHandle = 0;
+
+- glGenTextures (1, &ms->texture);
+-
+- if (s->textureNonPowerOfTwo)
+- ms->target = GL_TEXTURE_2D;
+- else
+- ms->target = GL_TEXTURE_RECTANGLE_ARB;
+-
+- glEnable (ms->target);
+-
+- /* Bind the texture */
+- glBindTexture (ms->target, ms->texture);
+-
+- /* Load the parameters */
+- glTexParameteri (ms->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+- glTexParameteri (ms->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+- glTexParameteri (ms->target, GL_TEXTURE_WRAP_S, GL_CLAMP);
+- glTexParameteri (ms->target, GL_TEXTURE_WRAP_T, GL_CLAMP);
+-
+- glTexImage2D (ms->target, 0, GL_RGB, 0, 0, 0,
+- GL_RGB, GL_UNSIGNED_BYTE, NULL);
+-
+- ms->width = 0;
+- ms->height = 0;
+-
+- glBindTexture (ms->target, 0);
+-
+- glDisable (ms->target);
+-
+ initTexture (s, &ms->overlay.tex);
+ initTexture (s, &ms->mask.tex);
+ ms->overlay.loaded = FALSE;
+ ms->mask.loaded = FALSE;
+
+- ms->program = 0;
+-
+ magSetOverlayNotify (s, magOptionsChanged);
+ magSetMaskNotify (s, magOptionsChanged);
+ magSetModeNotify (s, magOptionsChanged);
+
+- switch (magGetMode (s))
+- {
+- case ModeImageOverlay:
+- if (loadImages (s))
+- ms->mode = ModeImageOverlay;
+- else
+- ms->mode = ModeSimple;
+- break;
+- case ModeFisheye:
+- if (loadFragmentProgram (s))
+- ms->mode = ModeFisheye;
+- else
+- ms->mode = ModeSimple;
+- break;
+- default:
+- ms->mode = ModeSimple;
+- }
+-
+ if (!s->fragmentProgram)
+ compLogMessage ("mag", CompLogLevelWarn,
+ "GL_ARB_fragment_program not supported. "
+@@ -1179,10 +1375,7 @@ magFiniScreen (CompPlugin *p,
+ if (ms->pollHandle)
+ (*md->mpFunc->removePositionPolling) (s, ms->pollHandle);
+
+- if (ms->zoom)
+- damageScreen (s);
+-
+- glDeleteTextures (1, &ms->target);
++ damageScreen (s);
+
+ magCleanup (s);
+
+--
+1.5.6
+
diff --git a/fusion/plugins/mousepoll/0001--MPX-Inclusion.patch b/fusion/plugins/mousepoll/0001--MPX-Inclusion.patch
new file mode 100644
index 0000000..718754c
--- /dev/null
+++ b/fusion/plugins/mousepoll/0001--MPX-Inclusion.patch
@@ -0,0 +1,362 @@
+From 12410397c3182f503db96ff9437b3baf2cd03665 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Wed, 29 Oct 2008 15:24:51 +0900
+Subject: [PATCH] * MPX Inclusion
+
+---
+ compiz-mousepoll.h | 12 +++-
+ mousepoll.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++------
+ 2 files changed, 193 insertions(+), 23 deletions(-)
+
+diff --git a/compiz-mousepoll.h b/compiz-mousepoll.h
+index cf1b64b..50207fc 100644
+--- a/compiz-mousepoll.h
++++ b/compiz-mousepoll.h
+@@ -25,12 +25,19 @@
+
+ typedef int PositionPollingHandle;
+
++typedef struct _MousepollDevice {
++ int posX;
++ int posY;
++ CompDevice *dev;
++ struct _MousepollDevice *next;
++} MousepollDevice;
++
+ typedef void (*PositionUpdateProc) (CompScreen *s,
+- int x,
+- int y);
++ MousepollDevice *devices);
+
+ typedef PositionPollingHandle
+ (*AddPositionPollingProc) (CompScreen *s,
++ CompDevice *dev,
+ PositionUpdateProc update);
+
+ typedef void
+@@ -39,6 +46,7 @@ typedef void
+
+ typedef void
+ (*GetCurrentPositionProc) (CompScreen *s,
++ CompDevice *dev,
+ int *x,
+ int *y);
+
+diff --git a/mousepoll.c b/mousepoll.c
+index d64d641..41245b3 100644
+--- a/mousepoll.c
++++ b/mousepoll.c
+@@ -29,14 +29,20 @@ static CompMetadata mousepollMetadata;
+ static int displayPrivateIndex;
+ static int functionsPrivateIndex;
+
++static void
++mousepollCheckList (CompDisplay *d);
++
+ typedef struct _MousepollClient MousepollClient;
+
+ struct _MousepollClient {
+ MousepollClient *next;
+ MousepollClient *prev;
++ CompDevice *dev;
+
+ PositionPollingHandle id;
+ PositionUpdateProc update;
++ int posX;
++ int posY;
+ };
+
+ typedef enum _MousepollDisplayOptions
+@@ -49,6 +55,7 @@ typedef enum _MousepollDisplayOptions
+
+ typedef struct _MousepollDisplay {
+ int screenPrivateIndex;
++ MousepollDevice *devices;
+
+ CompOption opt[MP_DISPLAY_OPTION_NUM];
+ } MousepollDisplay;
+@@ -59,9 +66,6 @@ typedef struct _MousepollScreen {
+ PositionPollingHandle freeId;
+
+ CompTimeoutHandle updateHandle;
+- int posX;
+- int posY;
+-
+ } MousepollScreen;
+
+ #define GET_MOUSEPOLL_DISPLAY(d) \
+@@ -87,10 +91,14 @@ getMousePosition (CompScreen *s)
+ int winX, winY;
+ unsigned int maskReturn;
+ Bool status;
++ MousepollDevice *dev;
+
+- MOUSEPOLL_SCREEN (s);
++ MOUSEPOLL_DISPLAY (s->display);
+
+- status = XQueryPointer (s->display->display, s->root,
++ for (dev = md->devices; dev; dev = dev->next)
++ {
++
++ status = XQueryDevicePointer (s->display->display, dev->dev->dev, s->root,
+ &root_return, &child_return,
+ &rootX, &rootY, &winX, &winY, &maskReturn);
+
+@@ -98,13 +106,14 @@ getMousePosition (CompScreen *s)
+ s->root != root_return)
+ return FALSE;
+
+- if ((rootX != ms->posX || rootY != ms->posY))
++ if ((rootX != dev->posX || rootY != dev->posY))
+ {
+- ms->posX = rootX;
+- ms->posY = rootY;
+- return TRUE;
++ dev->posX = rootX;
++ dev->posY = rootY;
++ /* dev->change = TRUE */
+ }
+- return FALSE;
++ }
++ return TRUE;
+ }
+
+ static Bool
+@@ -114,19 +123,22 @@ updatePosition (void *c)
+ MousepollClient *mc;
+
+ MOUSEPOLL_SCREEN (s);
++ MOUSEPOLL_DISPLAY (s->display);
++
++ mousepollCheckList (s->display);
+
+ if (!ms->clients)
+ return FALSE;
+
++ MousepollClient *next;
++ for (mc = ms->clients; mc; mc = next)
++ {
+ if (getMousePosition (s))
+ {
+- MousepollClient *next;
+- for (mc = ms->clients; mc; mc = next)
+- {
+ next = mc->next;
+ if (mc->update)
+- (*mc->update) (s, ms->posX, ms->posY);
+- }
++ (*mc->update) (s, md->devices);
++ }
+ }
+
+ return TRUE;
+@@ -134,6 +146,7 @@ updatePosition (void *c)
+
+ static PositionPollingHandle
+ mousepollAddPositionPolling (CompScreen *s,
++ CompDevice *dev,
+ PositionUpdateProc update)
+ {
+ MOUSEPOLL_SCREEN (s);
+@@ -150,6 +163,7 @@ mousepollAddPositionPolling (CompScreen *s,
+ start = TRUE;
+
+ mc->update = update;
++ mc->dev = dev;
+ mc->id = ms->freeId;
+ ms->freeId++;
+
+@@ -212,20 +226,164 @@ mousepollRemovePositionPolling (CompScreen *s,
+
+ static void
+ mousepollGetCurrentPosition (CompScreen *s,
++ CompDevice *dev,
+ int *x,
+ int *y)
+ {
+ MOUSEPOLL_SCREEN (s);
++ MOUSEPOLL_DISPLAY (s->display);
++ MousepollDevice *mDev;
+
+- if (!ms->clients)
+- getMousePosition (s);
++ mousepollCheckList (s->display);
++
++ getMousePosition (s);
++
++ for (mDev = md->devices; mDev; mDev = mDev->next)
++ if (mDev->dev == dev)
++ break;
+
+ if (x)
+- *x = ms->posX;
++ *x = mDev->posX;
+ if (y)
+- *y = ms->posY;
++ *y = mDev->posY;
++}
++
++static Bool
++mousepollAddDeviceToList (CompDisplay *d,
++ CompDevice *dev)
++{
++ MOUSEPOLL_DISPLAY (d);
++
++ if (!md->devices)
++ {
++ md->devices = calloc (1, sizeof(MousepollDevice));
++ if (!md->devices)
++ return FALSE;
++ md->devices->dev = dev;
++ md->devices->next = NULL;
++ }
++ else
++ {
++ MousepollDevice *run;
++ for (run = md->devices; run->next; run = run->next); /* Last device in list */
++
++ run->next = calloc (1, sizeof(MousepollDevice));
++ if (!run->next)
++ return FALSE;
++ run->next->dev = dev;
++ run->next->next = NULL;
++ }
++
++ return TRUE;
++
+ }
+
++static Bool
++mousepollRemoveDeviceFromList (CompDisplay *d,
++ MousepollDevice *dev)
++{
++ MOUSEPOLL_DISPLAY (d);
++ MousepollDevice *run;
++
++ if (!md->devices)
++ return FALSE;
++
++
++ if (dev == md->devices)
++ {
++ if (md->devices->next)
++ md->devices = md->devices->next;
++ if (dev)
++ free (dev);
++ }
++ else
++ {
++ for (run = md->devices; run; run = run->next)
++ {
++ if (run == dev)
++ {
++ if (run->next)
++ run = run->next;
++ else
++ run = NULL;
++ if (dev)
++ free (dev);
++ }
++ }
++ }
++
++ return TRUE;
++}
++
++static void
++mousepollCheckList (CompDisplay *d)
++{
++ MOUSEPOLL_DISPLAY (d);
++ CompDevice *addDev, *ptr;
++ MousepollDevice *removeDev, *run;
++ Bool ok;
++
++ do
++ {
++ addDev = NULL;
++ removeDev = NULL;
++
++ for (ptr = d->devices; ptr->id != -1; ptr++)
++ {
++
++ if (ptr->use != IsXPointer)
++ continue;
++
++ if (!md->devices)
++ addDev = ptr;
++ else
++ for (run = md->devices; run; run = run->next)
++ {
++ addDev = ptr;
++ if (run->dev == ptr)
++ {
++ addDev = NULL;
++ break;
++ }
++ }
++ if (addDev)
++ break;
++ }
++ for (run = md->devices; run; run = run->next)
++ {
++ for (ptr = d->devices; ptr->id != -1; ptr++)
++ {
++ if (ptr->use != IsXPointer)
++ continue;
++
++ removeDev = run;
++ if (ptr == run->dev)
++ {
++ removeDev = NULL;
++ break;
++ }
++ }
++ if (removeDev)
++ break;
++ }
++
++ if (addDev)
++ mousepollAddDeviceToList (d, addDev);
++
++ if (removeDev)
++ mousepollRemoveDeviceFromList (d, removeDev);
++
++ if (!addDev && !removeDev)
++ ok = TRUE;
++ else
++ ok = FALSE;
++
++ } while (!ok);
++
++}
++
++
++
+ static const CompMetadataOptionInfo mousepollDisplayOptionInfo[] = {
+ { "abi", "int", 0, 0, 0 },
+ { "index", "int", 0, 0, 0 },
+@@ -329,6 +487,10 @@ mousepollInitDisplay (CompPlugin *p,
+
+ d->base.privates[displayPrivateIndex].ptr = md;
+ d->base.privates[functionsPrivateIndex].ptr = &mousepollFunctions;
++
++ md->devices = NULL;
++ //mousepollCheckList (d);
++
+ return TRUE;
+ }
+
+@@ -354,8 +516,8 @@ mousepollInitScreen (CompPlugin *p,
+ if (!ms)
+ return FALSE;
+
+- ms->posX = 0;
+- ms->posY = 0;
++ /*ms->posX = 0;
++ ms->posY = 0;*/
+
+ ms->clients = NULL;
+ ms->freeId = 1;
+--
+1.5.6
+
diff --git a/fusion/plugins/mousetrails/0001-MPX-Support.patch b/fusion/plugins/mousetrails/0001-MPX-Support.patch
new file mode 100644
index 0000000..80aea98
--- /dev/null
+++ b/fusion/plugins/mousetrails/0001-MPX-Support.patch
@@ -0,0 +1,571 @@
+From fccbc399fb19d647391a339fb196f749662d7db5 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Sat, 1 Nov 2008 13:25:48 +0900
+Subject: [PATCH] MPX Support
+
+---
+ mousetrails.c | 347 +++++++++++++++++++++++++++++++++++++++++++-------------
+ 1 files changed, 266 insertions(+), 81 deletions(-)
+
+diff --git a/mousetrails.c b/mousetrails.c
+index 15e3695..3962cfc 100644
+--- a/mousetrails.c
++++ b/mousetrails.c
+@@ -126,6 +126,16 @@ typedef struct _ParticleSystem
+
+ static int displayPrivateIndex = 0;
+
++typedef struct _mousetrailsDevice
++{
++ CompDevice *dev;
++ int posX;
++ int posY;
++
++ ParticleSystem *ps;
++ struct _mousetrailsDevice *next;
++} mousetrailsDevice;
++
+ typedef struct _mousetrailsDisplay
+ {
+ int screenPrivateIndex;
+@@ -142,6 +152,7 @@ typedef struct _mousetrailsScreen
+ Bool active;
+
+ ParticleSystem *ps;
++ mousetrailsDevice *devices;
+
+ PositionPollingHandle pollHandle;
+
+@@ -398,6 +409,7 @@ Bool status;*/
+ static void
+ genNewParticles(CompScreen *s,
+ ParticleSystem *ps,
++ mousetrailsDevice *mDev,
+ int time)
+ {
+
+@@ -406,12 +418,10 @@ genNewParticles(CompScreen *s,
+ ps->atSkip = (ps->atSkip + 1) % ps->skip;
+ if (ps->atSkip != 0) return;
+
+- MOUSETRAILS_SCREEN(s);
+-
+ Bool rColor = mousetrailsGetRandom (s);
+ //float life = mousetrailsGetLife (s);
+ int sizeFactor = ps->sizeFactor;
+- float threshold = ps->threshold;
++ //float threshold = ps->threshold;
+ //float lifeNeg = 1 - life;
+ //float fadeExtra = 0.05f * (1.01 - life);
+ int cursorIndex = 0;
+@@ -443,15 +453,15 @@ genNewParticles(CompScreen *s,
+ }
+ else
+ {*/
+- livex = ss->posX;
+- livey = ss->posY;
++ livex = mDev->posX;
++ livey = mDev->posY;
+ //}
+
+ int deltax = livex - ps->x;
+ int deltay = livey - ps->y;
+ int delta = deltax * deltax + deltay * deltay;
+- ss->ps->x = livex;
+- ss->ps->y = livey;
++ ps->x = livex;
++ ps->y = livey;
+ //if (delta < threshold * threshold) return;
+ if (delta < 1 ) return;
+
+@@ -564,28 +574,26 @@ genNewParticles(CompScreen *s,
+ // damageRegion() seems to cause blockiness or jitters on the background window when scrolling, like on a webpage
+
+ static void
+-damageRegion (CompScreen *s)
++damageRegion (CompScreen *s, mousetrailsDevice *mDev)
+ {
+ REGION r;
+ int i;
+ Particle *p;
+ float w, h, x1, x2, y1, y2;
+
+- MOUSETRAILS_SCREEN (s);
+-
+- if (ss->ps->numDisplayedParticles == 0) return;
+-
+- if (!ss->ps)
++ if (!mDev->ps)
+ return;
+
++ if (mDev->ps->numDisplayedParticles == 0) return;
++
+ x1 = s->width;
+ x2 = 0;
+ y1 = s->height;
+ y2 = 0;
+
+- p = ss->ps->particles;
++ p = mDev->ps->particles;
+
+- for (i = 0; i < ss->ps->numParticles; i++, p++)
++ for (i = 0; i < mDev->ps->numParticles; i++, p++)
+ {
+ if (p->a > 0.001f){
+ w = p->width / 2;
+@@ -619,6 +627,7 @@ int mousetrailsCursorUpdate (CompScreen *s)
+
+ Display * dpy = s->display->display;
+ XFixesCursorImage *ci = XFixesGetCursorImage(dpy);
++ mousetrailsDevice *mDev;
+
+ /* Hack to avoid changing to an invisible (bugged)cursor image.
+ * Example: The animated firefox cursors.
+@@ -626,28 +635,28 @@ int mousetrailsCursorUpdate (CompScreen *s)
+ if (ci->width <= 1 && ci->height <= 1)
+ {
+ XFree (ci);
+- return ss->ps->lastCursorIndex;
++ return ss->devices->ps->lastCursorIndex; /* See below */
+ }
+
+ // only update cursor if necessary (instead of all the time)
+- if (ci->cursor_serial == ss->ps->lastCursorSerial)
++ if (ci->cursor_serial == ss->devices->ps->lastCursorSerial)
+ {
+ XFree (ci);
+- return ss->ps->lastCursorIndex;
++ return ss->devices->ps->lastCursorIndex;
+ }
+
+ // see if cursor already exists in textures
+ int i;
+ for (i = 0; i < TEXTURES_SIZE; i++){
+- if (ci->cursor_serial == ss->ps->cursors[i].cursor_serial){
+- ss->ps->lastCursorSerial = ci->cursor_serial;
++ if (ci->cursor_serial == ss->devices->ps->cursors[i].cursor_serial){
++ ss->devices->ps->lastCursorSerial = ci->cursor_serial;
+ XFree (ci);
+ return i;
+ }
+ }
+
+ // otherwise grab the new cursor into textures
+- int fillTexture = (ss->ps->lastTextureFilled + 1) % TEXTURES_SIZE;
++ int fillTexture = (ss->devices->ps->lastTextureFilled + 1) % TEXTURES_SIZE;
+
+ unsigned char *pixels = malloc(ci->width * ci->height * 4);
+
+@@ -660,22 +669,32 @@ int mousetrailsCursorUpdate (CompScreen *s)
+ pixels[(i * 4) + 3] = (pix >> 24) & 0xff;
+ }
+
+- glBindTexture(GL_TEXTURE_2D, ss->ps->cursors[fillTexture].texture);
++ // save data for this cursor FIXME: It looks like there isn't
++ // a device specific XFixesCursorUpdate event at this point,
++ // however given the way MPX works, it looks as though all cursors
++ // are drawn the same. This needs to be adjusted once we have a
++ // XI2 XFixesCursorUpdate event.
+
+- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
++ for (mDev = ss->devices; mDev; mDev = mDev->next)
++ {
++ if (mDev->ps)
++ {
++ glBindTexture(GL_TEXTURE_2D, mDev->ps->cursors[fillTexture].texture);
+
+- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ci->width, ci->height, 0,
+- GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+- glBindTexture(GL_TEXTURE_2D, 0);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+- // save data for this cursor
+- ss->ps->cursors[fillTexture].cursor_serial = ss->ps->lastCursorSerial = ci->cursor_serial;
+- ss->ps->cursors[fillTexture].xhot = ci->xhot;
+- ss->ps->cursors[fillTexture].yhot = ci->yhot;
+- ss->ps->cursors[fillTexture].width = ci->width;
+- ss->ps->cursors[fillTexture].height = ci->height;
+- ss->ps->lastTextureFilled = fillTexture;
++ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ci->width, ci->height, 0,
++ GL_RGBA, GL_UNSIGNED_BYTE, pixels);
++ glBindTexture(GL_TEXTURE_2D, 0);
++ mDev->ps->cursors[fillTexture].cursor_serial = mDev->ps->lastCursorSerial = ci->cursor_serial;
++ mDev->ps->cursors[fillTexture].xhot = ci->xhot;
++ mDev->ps->cursors[fillTexture].yhot = ci->yhot;
++ mDev->ps->cursors[fillTexture].width = ci->width;
++ mDev->ps->cursors[fillTexture].height = ci->height;
++ mDev->ps->lastTextureFilled = fillTexture;
++ }
++ }
+
+ XFree (ci);
+ free (pixels);
+@@ -684,15 +703,159 @@ int mousetrailsCursorUpdate (CompScreen *s)
+ }
+
+
++static Bool
++mousetrailsAddDevToList (CompScreen *s,
++ CompDevice *dev)
++{
++ MOUSETRAILS_SCREEN (s);
++
++ mousetrailsDevice *run;
++
++ if (!ss->devices)
++ {
++ ss->devices = calloc (1, sizeof(mousetrailsDevice));
++ if (!ss->devices)
++ return FALSE;
++ ss->devices->dev = dev;
++ ss->devices->next = NULL;
++ }
++ else
++ {
++ for (run = ss->devices; run->next; run = run->next);
++
++ run->next = calloc (1, sizeof(mousetrailsDevice));
++ if (!run->next)
++ return FALSE;
++ run->next->dev = dev;
++ run->next->next = NULL;
++ }
++ return TRUE;
++}
++
++/*static void
++mousetrailsFiniDevice (mousetrailsDevice *dev)
++{
++ if (dev->emitter)
++ dev->emitter->in_use = FALSE;
++ if (dev->gpoint)
++ dev->gpoint->in_use = FALSE;
++}*/
++
++static void
++mousetrailsRemoveDevFromList (CompScreen *s,
++ CompDevice *dev)
++{
++ MOUSETRAILS_SCREEN (s);
++
++ mousetrailsDevice *run;
++
++ if (!ss->devices)
++ return;
++
++ if (run == ss->devices)
++ {
++ if (ss->devices->next)
++ ss->devices = ss->devices->next;
++ else
++ ss->devices = NULL;
++
++ if (run)
++ free (run);
++ }
++ else
++ {
++ for (run = ss->devices; run; run = run->next)
++ {
++ if (run->dev == dev)
++ break;
++ }
++
++ mousetrailsDevice *selected = run;
++
++ if (selected)
++ if (selected->next)
++ {
++ run = selected->next;
++ free(selected);
++ }
++ }
++}
++
++static void
++mousetrailsCheckList (CompScreen *s,
++ MousepollDevice *list)
++{
++ MOUSETRAILS_SCREEN (s);
++ Bool ok = FALSE;
++ MousepollDevice *run;
++ mousetrailsDevice *ptr;
++ CompDevice *addDev = NULL, *removeDev = NULL;
++
++ do
++ {
++ for (run = list; run; run = run->next)
++ {
++ addDev = run->dev;
++ for (ptr = ss->devices; ptr; ptr = ptr->next)
++ {
++ if (ptr->dev == run->dev)
++ {
++ addDev = NULL;
++ break;
++ }
++ }
++ if (addDev) break;
++ }
++
++ for (ptr = ss->devices; ptr; ptr = ptr->next)
++ {
++ removeDev = ptr->dev;
++ for (run = list; run; run = run->next)
++ {
++ if (run->dev == ptr->dev)
++ {
++ removeDev = NULL;
++ break;
++ }
++ }
++ if (removeDev) break;
++ }
++
++ if (addDev)
++ mousetrailsAddDevToList (s, addDev);
++
++ if (removeDev)
++ mousetrailsRemoveDevFromList (s, removeDev);
++
++ if (addDev || removeDev)
++ ok = FALSE;
++ else
++ ok = TRUE;
++ } while (!ok);
++}
++
++
+ static void
+ positionUpdate (CompScreen *s,
+- int x,
+- int y)
++ MousepollDevice *mDev)
+ {
+ MOUSETRAILS_SCREEN (s);
++ MousepollDevice *run;
++ mousetrailsDevice *ptr;
+
+- ss->posX = x;
+- ss->posY = y;
++ mousetrailsCheckList (s, mDev);
++
++ for (run = mDev; run; run = run->next)
++ {
++ for (ptr = ss->devices; ptr; ptr = ptr->next)
++ {
++ if (ptr->dev == run->dev)
++ {
++ ptr->posX = run->posX;
++ ptr->posY = run->posY;
++ }
++ }
++ }
+ }
+
+
+@@ -704,50 +867,56 @@ mousetrailsPreparePaintScreen (CompScreen *s,
+
+ MOUSETRAILS_SCREEN (s);
+ MOUSETRAILS_DISPLAY (s->display);
++ mousetrailsDevice *mDev;
+
+ //Bool useMousepoll = mousetrailsGetMousepoll (s);
+
+ if (ss->active && !ss->pollHandle/* && useMousepoll*/)
+ {
+- (*sd->mpFunc->getCurrentPosition) (s, &ss->posX, &ss->posY);
+- ss->pollHandle = (*sd->mpFunc->addPositionPolling) (s, positionUpdate);
++ ss->pollHandle = (*sd->mpFunc->addPositionPolling) (s, NULL, positionUpdate);
+ }
+
+- if (ss->active && !ss->ps)
++ if (ss->active)
+ {
+- ss->ps = calloc(1, sizeof(ParticleSystem));
+- if (!ss->ps)
++ for (mDev = ss->devices; mDev; mDev = mDev->next)
++ {
++ if (!mDev->ps)
++ {
++ mDev->ps = calloc(1, sizeof(ParticleSystem));
++ if (!mDev->ps)
+ {
+ UNWRAP (ss, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, time);
+ WRAP (ss, s, preparePaintScreen, mousetrailsPreparePaintScreen);
+ return;
+ }
+- initParticles(mousetrailsGetNumParticles (s), ss->ps);
+-
+- ss->ps->slowdown = mousetrailsGetSlowdown (s);
+- ss->ps->initialAlpha = mousetrailsGetAlpha (s) ;
+- ss->ps->threshold = mousetrailsGetThreshold (s) ;
+- ss->ps->colorrate = mousetrailsGetColorrate (s) ;
+- ss->ps->sizeFactor = mousetrailsGetSize (s) ;
+- ss->ps->skip = mousetrailsGetSkip (s) ;
+- ss->ps->blendMode = GL_ONE_MINUS_SRC_ALPHA;
++ initParticles(mousetrailsGetNumParticles (s), mDev->ps);
++
++ mDev->ps->slowdown = mousetrailsGetSlowdown (s);
++ mDev->ps->initialAlpha = mousetrailsGetAlpha (s) ;
++ mDev->ps->threshold = mousetrailsGetThreshold (s) ;
++ mDev->ps->colorrate = mousetrailsGetColorrate (s) ;
++ mDev->ps->sizeFactor = mousetrailsGetSize (s) ;
++ mDev->ps->skip = mousetrailsGetSkip (s) ;
++ mDev->ps->blendMode = GL_ONE_MINUS_SRC_ALPHA;
+ //ss->ps->useMousepoll = mousetrailsGetMousepoll (s);
+
+ mousetrailsCursorUpdate(s);
++ }
++ if (mDev->ps && mDev->ps->active)
++ {
++ updateParticles (mDev->ps, time);
++ damageRegion (s, mDev);
++ }
++ if (mDev->ps && ss->active)
++ {
++ genNewParticles (s, mDev->ps, mDev, time);
++ }
++
++ }
+
+ }
+
+-
+- if (ss->ps && ss->ps->active)
+- {
+- updateParticles (ss->ps, time);
+- damageRegion (s);
+- }
+-
+- if (ss->ps && ss->active)
+- genNewParticles (s, ss->ps, time);
+-
+ UNWRAP (ss, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, time);
+ WRAP (ss, s, preparePaintScreen, mousetrailsPreparePaintScreen);
+@@ -758,23 +927,27 @@ mousetrailsPreparePaintScreen (CompScreen *s,
+ static void
+ mousetrailsDonePaintScreen (CompScreen *s)
+ {
++ mousetrailsDevice *mDev;
+ MOUSETRAILS_SCREEN (s);
+ MOUSETRAILS_DISPLAY (s->display);
+
+- if (ss->active || (ss->ps && ss->ps->active))
+- damageRegion (s);
+-
+- if (!ss->active && ss->pollHandle && ss->ps->useMousepoll)
++ for (mDev = ss->devices; mDev; mDev = mDev->next)
+ {
++ if (ss->active || (mDev->ps && mDev->ps->active))
++ damageRegion (s, mDev);
++
++ if (!ss->active && ss->pollHandle)
++ {
+ (*sd->mpFunc->removePositionPolling) (s, ss->pollHandle);
+ ss->pollHandle = 0;
+- }
+-
+- if (!ss->active && ss->ps && !ss->ps->active)
+- {
+- finiParticles (ss->ps);
+- free (ss->ps);
+- ss->ps = NULL;
++ }
++
++ if (!ss->active && mDev->ps && !mDev->ps->active)
++ {
++ finiParticles (mDev->ps);
++ free (mDev->ps);
++ mDev->ps = NULL;
++ }
+ }
+
+ UNWRAP (ss, s, donePaintScreen);
+@@ -791,7 +964,9 @@ mousetrailsPaintOutput (CompScreen *s,
+ unsigned int mask)
+ {
+ Bool status;
++ Bool paint = FALSE;
+ CompTransform sTransform;
++ mousetrailsDevice *mDev;
+
+ MOUSETRAILS_SCREEN (s);
+
+@@ -801,8 +976,14 @@ mousetrailsPaintOutput (CompScreen *s,
+
+
+
+- if (!ss->ps || !ss->ps->active)
+- return status;
++ for (mDev = ss->devices; mDev; mDev = mDev->next)
++ {
++ if (mDev->ps)
++ paint = TRUE;
++ }
++
++ if (!paint)
++ return status;
+
+ // this doesn't seem to work
+ // if (mask & PAINT_SCREEN_TRANSFORMED_MASK) return FALSE;
+@@ -814,7 +995,9 @@ mousetrailsPaintOutput (CompScreen *s,
+ glPushMatrix ();
+ glLoadMatrixf (sTransform.m);
+
+- drawParticles (s, ss->ps);
++ for (mDev = ss->devices; mDev; mDev = mDev->next)
++ if (mDev->ps)
++ drawParticles (s, mDev->ps);
+
+ glPopMatrix();
+
+@@ -832,6 +1015,7 @@ mousetrailsTerminate (CompDisplay *d,
+ {
+ CompScreen *s;
+ Window xid;
++ mousetrailsDevice *mDev;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+
+@@ -841,7 +1025,8 @@ mousetrailsTerminate (CompDisplay *d,
+ MOUSETRAILS_SCREEN (s);
+
+ ss->active = FALSE;
+- damageRegion (s);
++ for (mDev = ss->devices; mDev; mDev = mDev->next)
++ damageRegion (s, mDev);
+
+ return TRUE;
+ }
+@@ -900,7 +1085,7 @@ mousetrailsInitScreen (CompPlugin *p,
+
+ ss->pollHandle = 0;
+
+- ss->ps = NULL;
++ ss->devices = NULL;
+
+ return TRUE;
+ }
+@@ -918,11 +1103,11 @@ mousetrailsFiniScreen (CompPlugin *p,
+ UNWRAP (ss, s, preparePaintScreen);
+ UNWRAP (ss, s, donePaintScreen);
+
+- if (ss->pollHandle && ss->ps->useMousepoll)
++ if (ss->pollHandle)
+ (*sd->mpFunc->removePositionPolling) (s, ss->pollHandle);
+
+- if (ss->ps && ss->ps->active)
+- damageScreen (s);
++ /*if (ss->ps && ss->ps->active)
++ damageScreen (s);*/
+
+ //Free the pointer
+ free (ss);
+--
+1.5.6
+
diff --git a/fusion/plugins/newton/Makefile b/fusion/plugins/newton/Makefile
new file mode 100755
index 0000000..39e663d
--- /dev/null
+++ b/fusion/plugins/newton/Makefile
@@ -0,0 +1,463 @@
+##
+#
+# Compiz plugin Makefile
+#
+# Copyright : (C) 2007 by Dennis Kasprzyk
+# E-mail : onestone@deltatauchi.de
+#
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+##
+
+# plugin.info file contents
+#
+# PLUGIN = foo
+# PKG_DEP = pango
+# LDFLAGS_ADD = -lGLU
+# CFLAGS_ADD = -I/usr/include/foo
+#
+
+#load config file
+include plugin.info
+
+
+ifeq ($(BUILD_GLOBAL),true)
+ PREFIX = $(shell pkg-config --variable=prefix compiz)
+ CLIBDIR = $(shell pkg-config --variable=libdir compiz)
+ CINCDIR = $(shell pkg-config --variable=includedir compiz)
+ PKGDIR = $(CLIBDIR)/pkgconfig
+ DESTDIR = $(shell pkg-config --variable=libdir compiz)/compiz
+ XMLDIR = $(shell pkg-config --variable=prefix compiz)/share/compiz
+ IMAGEDIR = $(shell pkg-config --variable=prefix compiz)/share/compiz
+ DATADIR = $(shell pkg-config --variable=prefix compiz)/share/compiz
+else
+ DESTDIR = $(HOME)/.compiz/plugins
+ XMLDIR = $(HOME)/.compiz/metadata
+ IMAGEDIR = $(HOME)/.compiz/images
+ DATADIR = $(HOME)/.compiz/data
+endif
+
+BUILDDIR = build
+
+ECHO = `which echo`
+
+CC = gcc
+CPP = g++
+LIBTOOL = libtool
+INSTALL = install
+
+BCOP = `pkg-config --variable=bin bcop`
+
+CFLAGS = -g -Wall -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -fno-strict-aliasing `pkg-config --cflags $(PKG_DEP) compiz ` $(CFLAGS_ADD)
+LDFLAGS = `pkg-config --libs $(PKG_DEP) compiz ` $(LDFLAGS_ADD)
+
+DEFINES = -DIMAGEDIR=$(IMAGEDIR) -DDATADIR=$(DATADIR)
+
+POFILEDIR = $(shell if [ -n "$(PODIR)" ]; then $(ECHO) $(PODIR); else $(ECHO) ./po;fi )
+
+is-bcop-target := $(shell if [ -e $(PLUGIN).xml.in ]; then cat $(PLUGIN).xml.in | grep "useBcop=\"true\""; \
+ else if [ -e $(PLUGIN).xml ]; then cat $(PLUGIN).xml | grep "useBcop=\"true\""; fi; fi)
+
+trans-target := $(shell if [ -e $(PLUGIN).xml.in -o -e $(PLUGIN).xml ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN).xml;fi )
+
+bcop-target := $(shell if [ -n "$(is-bcop-target)" ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN).xml; fi )
+bcop-target-src := $(shell if [ -n "$(is-bcop-target)" ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN)_options.c; fi )
+bcop-target-hdr := $(shell if [ -n "$(is-bcop-target)" ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN)_options.h; fi )
+
+gen-schemas := $(shell if [ -e $(PLUGIN).xml.in -o -e $(PLUGIN).xml -a -n "`pkg-config --variable=xsltdir compiz-gconf`" ]; then $(ECHO) true; fi )
+schema-target := $(shell if [ -n "$(gen-schemas)" ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN).xml; fi )
+schema-output := $(shell if [ -n "$(gen-schemas)" ]; then $(ECHO) $(BUILDDIR)/compiz-$(PLUGIN).schema; fi )
+
+ifeq ($(BUILD_GLOBAL),true)
+ pkg-target := $(shell if [ -e compiz-$(PLUGIN).pc.in -a -n "$(PREFIX)" -a -d "$(PREFIX)" ]; then $(ECHO) "$(BUILDDIR)/compiz-$(PLUGIN).pc"; fi )
+ hdr-install-target := $(shell if [ -e compiz-$(PLUGIN).pc.in -a -n "$(PREFIX)" -a -d "$(PREFIX)" -a -e $(PLUGIN).h ]; then $(ECHO) "$(PLUGIN).h"; fi )
+endif
+
+# find all the object files
+
+c-objs := $(patsubst %.c,%.lo,$(shell find -name '*.c' 2> /dev/null | grep -v "$(BUILDDIR)/" | sed -e 's/^.\///'))
+c-objs += $(patsubst %.cpp,%.lo,$(shell find -name '*.cpp' 2> /dev/null | grep -v "$(BUILDDIR)/" | sed -e 's/^.\///'))
+c-objs += $(patsubst %.cxx,%.lo,$(shell find -name '*.cxx' 2> /dev/null | grep -v "$(BUILDDIR)/" | sed -e 's/^.\///'))
+c-objs := $(filter-out $(bcop-target-src:.c=.lo),$(c-objs))
+
+h-files := $(shell find -name '*.h' 2> /dev/null | grep -v "$(BUILDDIR)/" | sed -e 's/^.\///')
+h-files += $(bcop-target-hdr)
+h-files += $(shell pkg-config --variable=includedir compiz)/compiz/compiz-core.h
+
+all-c-objs := $(addprefix $(BUILDDIR)/,$(c-objs))
+all-c-objs += $(bcop-target-src:.c=.lo)
+
+# additional files
+
+data-files := $(shell find data/ -name '*' -type f 2> /dev/null | sed -e 's/data\///')
+image-files := $(shell find images/ -name '*' -type f 2> /dev/null | sed -e 's/images\///')
+
+# system include path parameter, -isystem doesn't work on old gcc's
+inc-path-param = $(shell if [ -z "`gcc --version | head -n 1 | grep ' 3'`" ]; then $(ECHO) "-isystem"; else $(ECHO) "-I"; fi)
+
+# default color settings
+color := $(shell if [ $$TERM = "dumb" ]; then $(ECHO) "no"; else $(ECHO) "yes"; fi)
+
+#
+# Do it.
+#
+
+.PHONY: $(BUILDDIR) build-dir trans-target bcop-build pkg-creation schema-creation c-build-objs c-link-plugin
+
+all: $(BUILDDIR) build-dir trans-target bcop-build pkg-creation schema-creation c-build-objs c-link-plugin
+
+trans-build: $(trans-target)
+
+bcop-build: $(bcop-target-hdr) $(bcop-target-src)
+
+schema-creation: $(schema-output)
+
+c-build-objs: $(all-c-objs)
+
+c-link-plugin: $(BUILDDIR)/lib$(PLUGIN).la
+
+pkg-creation: $(pkg-target)
+
+#
+# Create build directory
+#
+
+$(BUILDDIR) :
+ @mkdir -p $(BUILDDIR)
+
+$(DESTDIR) :
+ @mkdir -p $(DESTDIR)
+
+#
+# fallback if xml.in doesn't exists
+#
+$(BUILDDIR)/%.xml: %.xml
+ @cp $< $@
+
+#
+# Translating
+#
+$(BUILDDIR)/%.xml: %.xml.in
+ @if [ -d $(POFILEDIR) ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mtranslate \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "translate $< -> $@"; \
+ fi; \
+ intltool-merge -x -u $(POFILEDIR) $< $@ > /dev/null; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mtranslate : \033[34m$< -> $@\033[0m"; \
+ fi; \
+ else \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mconvert \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "convert $< -> $@"; \
+ fi; \
+ cat $< | sed -e 's;<_;<;g' -e 's;</_;</;g' > $@; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mconvert : \033[34m$< -> $@\033[0m"; \
+ fi; \
+ fi
+
+#
+# BCOP'ing
+
+$(BUILDDIR)/%_options.h: $(BUILDDIR)/%.xml
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mbcop'ing \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "bcop'ing $< -> $@"; \
+ fi
+ @$(BCOP) --header=$@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mbcop'ing : \033[34m$< -> $@\033[0m"; \
+ fi
+
+$(BUILDDIR)/%_options.c: $(BUILDDIR)/%.xml
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mbcop'ing \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "bcop'ing $< -> $@"; \
+ fi
+ @$(BCOP) --source=$@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mbcop'ing : \033[34m$< -> $@\033[0m"; \
+ fi
+
+#
+# Schema generation
+
+$(BUILDDIR)/compiz-%.schema: $(BUILDDIR)/%.xml
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mschema'ing\033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "schema'ing $< -> $@"; \
+ fi
+ @xsltproc `pkg-config --variable=xsltdir compiz-gconf`/schemas.xslt $< > $@
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mschema : \033[34m$< -> $@\033[0m"; \
+ fi
+
+#
+# pkg config file generation
+
+$(BUILDDIR)/compiz-%.pc: compiz-%.pc.in
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mpkgconfig \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "pkgconfig $< -> $@"; \
+ fi
+ @COMPIZREQUIRES=`cat $(PKGDIR)/compiz.pc | grep Requires | sed -e 's;Requires: ;;g'`; \
+ COMPIZCFLAGS=`cat $(PKGDIR)/compiz.pc | grep Cflags | sed -e 's;Cflags: ;;g'`; \
+ sed -e 's;@prefix@;$(PREFIX);g' -e 's;\@libdir@;$(CLIBDIR);g' \
+ -e 's;@includedir@;$(CINCDIR);g' -e 's;\@VERSION@;0.0.1;g' \
+ -e "s;@COMPIZ_REQUIRES@;$$COMPIZREQUIRES;g" \
+ -e "s;@COMPIZ_CFLAGS@;$$COMPIZCFLAGS;g" $< > $@;
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mpkgconfig : \033[34m$< -> $@\033[0m"; \
+ fi
+
+#
+# Compiling
+#
+
+$(BUILDDIR)/%.lo: %.c $(h-files)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5mcompiling \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "compiling $< -> $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=compile $(CC) $(CFLAGS) $(DEFINES) -I$(BUILDDIR) -c -o $@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mcompiling : \033[34m$< -> $@\033[0m"; \
+ fi
+
+$(BUILDDIR)/%.lo: $(BUILDDIR)/%.c $(h-files)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5mcompiling \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "compiling $< -> $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=compile $(CC) $(CFLAGS) $(DEFINES) -I$(BUILDDIR) -c -o $@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mcompiling : \033[34m$< -> $@\033[0m"; \
+ fi
+
+$(BUILDDIR)/%.lo: %.cpp $(h-files)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5mcompiling \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "compiling $< -> $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=compile $(CPP) $(CFLAGS) $(DEFINES) -I$(BUILDDIR) -c -o $@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mcompiling : \033[34m$< -> $@\033[0m"; \
+ fi
+
+$(BUILDDIR)/%.lo: %.cxx $(h-files)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5mcompiling \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "compiling $< -> $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=compile $(CPP) $(CFLAGS) $(DEFINES) -I$(BUILDDIR) -c -o $@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mcompiling : \033[34m$< -> $@\033[0m"; \
+ fi
+
+#
+# Linking
+#
+
+cxx-rpath-prefix := -Wl,-rpath,
+
+$(BUILDDIR)/lib$(PLUGIN).la: $(all-c-objs)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mlinking \033[0m: \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "linking : $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=link $(CC) $(LDFLAGS) -rpath $(DESTDIR) -o $@ $(all-c-objs)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mlinking : \033[34m$@\033[0m"; \
+ fi
+
+
+clean:
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mremoving \033[0m: \033[0;31m./$(BUILDDIR)\033[0m"; \
+ else \
+ $(ECHO) "removing : ./$(BUILDDIR)"; \
+ fi
+ @rm -rf $(BUILDDIR)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mremoving : \033[34m./$(BUILDDIR)\033[0m"; \
+ fi
+
+
+install: $(DESTDIR) all
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(DESTDIR)/lib$(PLUGIN).so\033[0m"; \
+ else \
+ $(ECHO) "install : $(DESTDIR)/lib$(PLUGIN).so"; \
+ fi
+ @mkdir -p $(DESTDIR)
+ @$(INSTALL) $(BUILDDIR)/.libs/lib$(PLUGIN).so $(DESTDIR)/lib$(PLUGIN).so
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(DESTDIR)/lib$(PLUGIN).so\033[0m"; \
+ fi
+ @if [ -e $(BUILDDIR)/$(PLUGIN).xml ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(XMLDIR)/$(PLUGIN).xml\033[0m"; \
+ else \
+ $(ECHO) "install : $(XMLDIR)/$(PLUGIN).xml"; \
+ fi; \
+ mkdir -p $(XMLDIR); \
+ cp $(BUILDDIR)/$(PLUGIN).xml $(XMLDIR)/$(PLUGIN).xml; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(XMLDIR)/$(PLUGIN).xml\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(hdr-install-target)" ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(CINCDIR)/compiz/$(hdr-install-target)\033[0m"; \
+ else \
+ $(ECHO) "install : $(CINCDIR)/compiz/$(hdr-install-target)"; \
+ fi; \
+ cp $(hdr-install-target) $(CINCDIR)/compiz/$(hdr-install-target); \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(CINCDIR)/compiz/$(hdr-install-target)\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(pkg-target)" ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(PKGDIR)/compiz-$(PLUGIN).pc\033[0m"; \
+ else \
+ $(ECHO) "install : $(PKGDIR)/compiz-$(PLUGIN).pc"; \
+ fi; \
+ cp $(pkg-target) $(PKGDIR)/compiz-$(PLUGIN).pc; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(PKGDIR)/compiz-$(PLUGIN).pc\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(schema-output)" -a -e "$(schema-output)" ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(schema-output)\033[0m"; \
+ else \
+ $(ECHO) "install : $(schema-output)"; \
+ fi; \
+ gconftool-2 --install-schema-file=$(schema-output) > /dev/null; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(schema-output)\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(data-files)" ]; then \
+ mkdir -p $(DATADIR); \
+ for FILE in $(data-files); do \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(DATADIR)/$$FILE\033[0m"; \
+ else \
+ $(ECHO) "install : $(DATADIR)/$$FILE"; \
+ fi; \
+ cp data/$$FILE $(DATADIR)/$$FILE; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(DATADIR)/$$FILE\033[0m"; \
+ fi; \
+ done \
+ fi
+ @if [ -n "$(image-files)" ]; then \
+ mkdir -p $(IMAGEDIR); \
+ for FILE in $(image-files); do \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(IMAGEDIR)/$$FILE\033[0m"; \
+ else \
+ $(ECHO) "install : $(IMAGEDIR)/$$FILE"; \
+ fi; \
+ cp images/$$FILE $(IMAGEDIR)/$$FILE; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(IMAGEDIR)/$$FILE\033[0m"; \
+ fi; \
+ done \
+ fi
+
+uninstall:
+ @if [ -e $(DESTDIR)/lib$(PLUGIN).so ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(DESTDIR)/lib$(PLUGIN).so\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(DESTDIR)/lib$(PLUGIN).so"; \
+ fi; \
+ rm -f $(DESTDIR)/lib$(PLUGIN).so; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(DESTDIR)/lib$(PLUGIN).so\033[0m"; \
+ fi; \
+ fi
+ @if [ -e $(XMLDIR)/$(PLUGIN).xml ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(XMLDIR)/$(PLUGIN).xml\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(XMLDIR)/$(PLUGIN).xml"; \
+ fi; \
+ rm -f $(XMLDIR)/$(PLUGIN).xml; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(XMLDIR)/$(PLUGIN).xml\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(hdr-install-target)" -a -e $(CINCDIR)/compiz/$(hdr-install-target) ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(CINCDIR)/compiz/$(hdr-install-target)\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(CINCDIR)/compiz/$(hdr-install-target)"; \
+ fi; \
+ rm -f $(CINCDIR)/compiz/$(hdr-install-target); \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(CINCDIR)/compiz/$(hdr-install-target)\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(pkg-target)" -a -e $(PKGDIR)/compiz-$(PLUGIN).pc ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(PKGDIR)/compiz-$(PLUGIN).pc\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(PKGDIR)/compiz-$(PLUGIN).pc"; \
+ fi; \
+ rm -f $(PKGDIR)/compiz-$(PLUGIN).pc; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(PKGDIR)/compiz-$(PLUGIN).pc\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(data-files)" ]; then \
+ for FILE in $(data-files); do \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(DATADIR)/$$FILE\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(DATADIR)/$$FILE"; \
+ fi; \
+ rm -f $(DATADIR)/$$FILE; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(DATADIR)/$$FILE\033[0m"; \
+ fi; \
+ done \
+ fi
+ @if [ -n "$(image-files)" ]; then \
+ for FILE in $(image-files); do \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(IMAGEDIR)/$$FILE\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(IMAGEDIR)/$$FILE"; \
+ fi; \
+ rm -f $(IMAGEDIR)/$$FILE; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(IMAGEDIR)/$$FILE\033[0m"; \
+ fi; \
+ done \
+ fi
diff --git a/fusion/plugins/newton/Makefile~ b/fusion/plugins/newton/Makefile~
new file mode 100644
index 0000000..e1835ab
--- /dev/null
+++ b/fusion/plugins/newton/Makefile~
@@ -0,0 +1,463 @@
+##
+#
+# Compiz plugin Makefile
+#
+# Copyright : (C) 2007 by Dennis Kasprzyk
+# E-mail : onestone@deltatauchi.de
+#
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+##
+
+# plugin.info file contents
+#
+# PLUGIN = foo
+# PKG_DEP = pango
+# LDFLAGS_ADD = -lGLU
+# CFLAGS_ADD = -I/usr/include/foo
+#
+
+#load config file
+include plugin.info
+
+
+ifeq ($(BUILD_GLOBAL),true)
+ PREFIX = $(shell pkg-config --variable=prefix compiz)
+ CLIBDIR = $(shell pkg-config --variable=libdir compiz)
+ CINCDIR = $(shell pkg-config --variable=includedir compiz)
+ PKGDIR = $(CLIBDIR)/pkgconfig
+ DESTDIR = $(shell pkg-config --variable=libdir compiz)/compiz
+ XMLDIR = $(shell pkg-config --variable=prefix compiz)/share/compiz
+ IMAGEDIR = $(shell pkg-config --variable=prefix compiz)/share/compiz
+ DATADIR = $(shell pkg-config --variable=prefix compiz)/share/compiz
+else
+ DESTDIR = $(HOME)/.compiz/plugins
+ XMLDIR = $(HOME)/.compiz/metadata
+ IMAGEDIR = $(HOME)/.compiz/images
+ DATADIR = $(HOME)/.compiz/data
+endif
+
+BUILDDIR = build
+
+ECHO = `which echo`
+
+CC = gcc
+CPP = g++
+LIBTOOL = libtool
+INSTALL = install
+
+BCOP = `pkg-config --variable=bin bcop`
+
+CFLAGS = -g -Wall -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -fno-strict-aliasing `pkg-config --cflags $(PKG_DEP) compiz ` $(CFLAGS_ADD)
+LDFLAGS = `pkg-config --libs $(PKG_DEP) compiz ` $(LDFLAGS_ADD)
+
+DEFINES = -DIMAGEDIR=$(IMAGEDIR) -DDATADIR=$(DATADIR)
+
+POFILEDIR = $(shell if [ -n "$(PODIR)" ]; then $(ECHO) $(PODIR); else $(ECHO) ./po;fi )
+
+is-bcop-target := $(shell if [ -e $(PLUGIN).xml.in ]; then cat $(PLUGIN).xml.in | grep "useBcop=\"true\""; \
+ else if [ -e $(PLUGIN).xml ]; then cat $(PLUGIN).xml | grep "useBcop=\"true\""; fi; fi)
+
+trans-target := $(shell if [ -e $(PLUGIN).xml.in -o -e $(PLUGIN).xml ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN).xml;fi )
+
+bcop-target := $(shell if [ -n "$(is-bcop-target)" ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN).xml; fi )
+bcop-target-src := $(shell if [ -n "$(is-bcop-target)" ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN)_options.c; fi )
+bcop-target-hdr := $(shell if [ -n "$(is-bcop-target)" ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN)_options.h; fi )
+
+gen-schemas := $(shell if [ -e $(PLUGIN).xml.in -o -e $(PLUGIN).xml -a -n "`pkg-config --variable=xsltdir compiz-gconf`" ]; then $(ECHO) true; fi )
+schema-target := $(shell if [ -n "$(gen-schemas)" ]; then $(ECHO) $(BUILDDIR)/$(PLUGIN).xml; fi )
+schema-output := $(shell if [ -n "$(gen-schemas)" ]; then $(ECHO) $(BUILDDIR)/compiz-$(PLUGIN).schema; fi )
+
+ifeq ($(BUILD_GLOBAL),true)
+ pkg-target := $(shell if [ -e compiz-$(PLUGIN).pc.in -a -n "$(PREFIX)" -a -d "$(PREFIX)" ]; then $(ECHO) "$(BUILDDIR)/compiz-$(PLUGIN).pc"; fi )
+ hdr-install-target := $(shell if [ -e compiz-$(PLUGIN).pc.in -a -n "$(PREFIX)" -a -d "$(PREFIX)" -a -e $(PLUGIN).h ]; then $(ECHO) "$(PLUGIN).h"; fi )
+endif
+
+# find all the object files
+
+c-objs := $(patsubst %.c,%.lo,$(shell find -name '*.c' 2> /dev/null | grep -v "$(BUILDDIR)/" | sed -e 's/^.\///'))
+c-objs += $(patsubst %.cpp,%.lo,$(shell find -name '*.cpp' 2> /dev/null | grep -v "$(BUILDDIR)/" | sed -e 's/^.\///'))
+c-objs += $(patsubst %.cxx,%.lo,$(shell find -name '*.cxx' 2> /dev/null | grep -v "$(BUILDDIR)/" | sed -e 's/^.\///'))
+c-objs := $(filter-out $(bcop-target-src:.c=.lo),$(c-objs))
+
+h-files := $(shell find -name '*.h' 2> /dev/null | grep -v "$(BUILDDIR)/" | sed -e 's/^.\///')
+h-files += $(bcop-target-hdr)
+h-files += $(shell pkg-config --variable=includedir compiz)/compiz/compiz.h
+
+all-c-objs := $(addprefix $(BUILDDIR)/,$(c-objs))
+all-c-objs += $(bcop-target-src:.c=.lo)
+
+# additional files
+
+data-files := $(shell find data/ -name '*' -type f 2> /dev/null | sed -e 's/data\///')
+image-files := $(shell find images/ -name '*' -type f 2> /dev/null | sed -e 's/images\///')
+
+# system include path parameter, -isystem doesn't work on old gcc's
+inc-path-param = $(shell if [ -z "`gcc --version | head -n 1 | grep ' 3'`" ]; then $(ECHO) "-isystem"; else $(ECHO) "-I"; fi)
+
+# default color settings
+color := $(shell if [ $$TERM = "dumb" ]; then $(ECHO) "no"; else $(ECHO) "yes"; fi)
+
+#
+# Do it.
+#
+
+.PHONY: $(BUILDDIR) build-dir trans-target bcop-build pkg-creation schema-creation c-build-objs c-link-plugin
+
+all: $(BUILDDIR) build-dir trans-target bcop-build pkg-creation schema-creation c-build-objs c-link-plugin
+
+trans-build: $(trans-target)
+
+bcop-build: $(bcop-target-hdr) $(bcop-target-src)
+
+schema-creation: $(schema-output)
+
+c-build-objs: $(all-c-objs)
+
+c-link-plugin: $(BUILDDIR)/lib$(PLUGIN).la
+
+pkg-creation: $(pkg-target)
+
+#
+# Create build directory
+#
+
+$(BUILDDIR) :
+ @mkdir -p $(BUILDDIR)
+
+$(DESTDIR) :
+ @mkdir -p $(DESTDIR)
+
+#
+# fallback if xml.in doesn't exists
+#
+$(BUILDDIR)/%.xml: %.xml
+ @cp $< $@
+
+#
+# Translating
+#
+$(BUILDDIR)/%.xml: %.xml.in
+ @if [ -d $(POFILEDIR) ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mtranslate \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "translate $< -> $@"; \
+ fi; \
+ intltool-merge -x -u $(POFILEDIR) $< $@ > /dev/null; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mtranslate : \033[34m$< -> $@\033[0m"; \
+ fi; \
+ else \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mconvert \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "convert $< -> $@"; \
+ fi; \
+ cat $< | sed -e 's;<_;<;g' -e 's;</_;</;g' > $@; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mconvert : \033[34m$< -> $@\033[0m"; \
+ fi; \
+ fi
+
+#
+# BCOP'ing
+
+$(BUILDDIR)/%_options.h: $(BUILDDIR)/%.xml
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mbcop'ing \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "bcop'ing $< -> $@"; \
+ fi
+ @$(BCOP) --header=$@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mbcop'ing : \033[34m$< -> $@\033[0m"; \
+ fi
+
+$(BUILDDIR)/%_options.c: $(BUILDDIR)/%.xml
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mbcop'ing \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "bcop'ing $< -> $@"; \
+ fi
+ @$(BCOP) --source=$@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mbcop'ing : \033[34m$< -> $@\033[0m"; \
+ fi
+
+#
+# Schema generation
+
+$(BUILDDIR)/compiz-%.schema: $(BUILDDIR)/%.xml
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mschema'ing\033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "schema'ing $< -> $@"; \
+ fi
+ @xsltproc `pkg-config --variable=xsltdir compiz-gconf`/schemas.xslt $< > $@
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mschema : \033[34m$< -> $@\033[0m"; \
+ fi
+
+#
+# pkg config file generation
+
+$(BUILDDIR)/compiz-%.pc: compiz-%.pc.in
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mpkgconfig \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "pkgconfig $< -> $@"; \
+ fi
+ @COMPIZREQUIRES=`cat $(PKGDIR)/compiz.pc | grep Requires | sed -e 's;Requires: ;;g'`; \
+ COMPIZCFLAGS=`cat $(PKGDIR)/compiz.pc | grep Cflags | sed -e 's;Cflags: ;;g'`; \
+ sed -e 's;@prefix@;$(PREFIX);g' -e 's;\@libdir@;$(CLIBDIR);g' \
+ -e 's;@includedir@;$(CINCDIR);g' -e 's;\@VERSION@;0.0.1;g' \
+ -e "s;@COMPIZ_REQUIRES@;$$COMPIZREQUIRES;g" \
+ -e "s;@COMPIZ_CFLAGS@;$$COMPIZCFLAGS;g" $< > $@;
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mpkgconfig : \033[34m$< -> $@\033[0m"; \
+ fi
+
+#
+# Compiling
+#
+
+$(BUILDDIR)/%.lo: %.c $(h-files)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5mcompiling \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "compiling $< -> $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=compile $(CC) $(CFLAGS) $(DEFINES) -I$(BUILDDIR) -c -o $@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mcompiling : \033[34m$< -> $@\033[0m"; \
+ fi
+
+$(BUILDDIR)/%.lo: $(BUILDDIR)/%.c $(h-files)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5mcompiling \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "compiling $< -> $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=compile $(CC) $(CFLAGS) $(DEFINES) -I$(BUILDDIR) -c -o $@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mcompiling : \033[34m$< -> $@\033[0m"; \
+ fi
+
+$(BUILDDIR)/%.lo: %.cpp $(h-files)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5mcompiling \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "compiling $< -> $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=compile $(CPP) $(CFLAGS) $(DEFINES) -I$(BUILDDIR) -c -o $@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mcompiling : \033[34m$< -> $@\033[0m"; \
+ fi
+
+$(BUILDDIR)/%.lo: %.cxx $(h-files)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5mcompiling \033[0m: \033[0;32m$< \033[0m-> \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "compiling $< -> $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=compile $(CPP) $(CFLAGS) $(DEFINES) -I$(BUILDDIR) -c -o $@ $<
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mcompiling : \033[34m$< -> $@\033[0m"; \
+ fi
+
+#
+# Linking
+#
+
+cxx-rpath-prefix := -Wl,-rpath,
+
+$(BUILDDIR)/lib$(PLUGIN).la: $(all-c-objs)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mlinking \033[0m: \033[0;31m$@\033[0m"; \
+ else \
+ $(ECHO) "linking : $@"; \
+ fi
+ @$(LIBTOOL) --quiet --mode=link $(CC) $(LDFLAGS) -rpath $(DESTDIR) -o $@ $(all-c-objs)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mlinking : \033[34m$@\033[0m"; \
+ fi
+
+
+clean:
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e -n "\033[0;1;5mremoving \033[0m: \033[0;31m./$(BUILDDIR)\033[0m"; \
+ else \
+ $(ECHO) "removing : ./$(BUILDDIR)"; \
+ fi
+ @rm -rf $(BUILDDIR)
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0mremoving : \033[34m./$(BUILDDIR)\033[0m"; \
+ fi
+
+
+install: $(DESTDIR) all
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(DESTDIR)/lib$(PLUGIN).so\033[0m"; \
+ else \
+ $(ECHO) "install : $(DESTDIR)/lib$(PLUGIN).so"; \
+ fi
+ @mkdir -p $(DESTDIR)
+ @$(INSTALL) $(BUILDDIR)/.libs/lib$(PLUGIN).so $(DESTDIR)/lib$(PLUGIN).so
+ @if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(DESTDIR)/lib$(PLUGIN).so\033[0m"; \
+ fi
+ @if [ -e $(BUILDDIR)/$(PLUGIN).xml ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(XMLDIR)/$(PLUGIN).xml\033[0m"; \
+ else \
+ $(ECHO) "install : $(XMLDIR)/$(PLUGIN).xml"; \
+ fi; \
+ mkdir -p $(XMLDIR); \
+ cp $(BUILDDIR)/$(PLUGIN).xml $(XMLDIR)/$(PLUGIN).xml; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(XMLDIR)/$(PLUGIN).xml\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(hdr-install-target)" ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(CINCDIR)/compiz/$(hdr-install-target)\033[0m"; \
+ else \
+ $(ECHO) "install : $(CINCDIR)/compiz/$(hdr-install-target)"; \
+ fi; \
+ cp $(hdr-install-target) $(CINCDIR)/compiz/$(hdr-install-target); \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(CINCDIR)/compiz/$(hdr-install-target)\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(pkg-target)" ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(PKGDIR)/compiz-$(PLUGIN).pc\033[0m"; \
+ else \
+ $(ECHO) "install : $(PKGDIR)/compiz-$(PLUGIN).pc"; \
+ fi; \
+ cp $(pkg-target) $(PKGDIR)/compiz-$(PLUGIN).pc; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(PKGDIR)/compiz-$(PLUGIN).pc\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(schema-output)" -a -e "$(schema-output)" ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(schema-output)\033[0m"; \
+ else \
+ $(ECHO) "install : $(schema-output)"; \
+ fi; \
+ gconftool-2 --install-schema-file=$(schema-output) > /dev/null; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(schema-output)\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(data-files)" ]; then \
+ mkdir -p $(DATADIR); \
+ for FILE in $(data-files); do \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(DATADIR)/$$FILE\033[0m"; \
+ else \
+ $(ECHO) "install : $(DATADIR)/$$FILE"; \
+ fi; \
+ cp data/$$FILE $(DATADIR)/$$FILE; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(DATADIR)/$$FILE\033[0m"; \
+ fi; \
+ done \
+ fi
+ @if [ -n "$(image-files)" ]; then \
+ mkdir -p $(IMAGEDIR); \
+ for FILE in $(image-files); do \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5minstall \033[0m: \033[0;31m$(IMAGEDIR)/$$FILE\033[0m"; \
+ else \
+ $(ECHO) "install : $(IMAGEDIR)/$$FILE"; \
+ fi; \
+ cp images/$$FILE $(IMAGEDIR)/$$FILE; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0minstall : \033[34m$(IMAGEDIR)/$$FILE\033[0m"; \
+ fi; \
+ done \
+ fi
+
+uninstall:
+ @if [ -e $(DESTDIR)/lib$(PLUGIN).so ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(DESTDIR)/lib$(PLUGIN).so\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(DESTDIR)/lib$(PLUGIN).so"; \
+ fi; \
+ rm -f $(DESTDIR)/lib$(PLUGIN).so; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(DESTDIR)/lib$(PLUGIN).so\033[0m"; \
+ fi; \
+ fi
+ @if [ -e $(XMLDIR)/$(PLUGIN).xml ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(XMLDIR)/$(PLUGIN).xml\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(XMLDIR)/$(PLUGIN).xml"; \
+ fi; \
+ rm -f $(XMLDIR)/$(PLUGIN).xml; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(XMLDIR)/$(PLUGIN).xml\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(hdr-install-target)" -a -e $(CINCDIR)/compiz/$(hdr-install-target) ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(CINCDIR)/compiz/$(hdr-install-target)\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(CINCDIR)/compiz/$(hdr-install-target)"; \
+ fi; \
+ rm -f $(CINCDIR)/compiz/$(hdr-install-target); \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(CINCDIR)/compiz/$(hdr-install-target)\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(pkg-target)" -a -e $(PKGDIR)/compiz-$(PLUGIN).pc ]; then \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(PKGDIR)/compiz-$(PLUGIN).pc\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(PKGDIR)/compiz-$(PLUGIN).pc"; \
+ fi; \
+ rm -f $(PKGDIR)/compiz-$(PLUGIN).pc; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(PKGDIR)/compiz-$(PLUGIN).pc\033[0m"; \
+ fi; \
+ fi
+ @if [ -n "$(data-files)" ]; then \
+ for FILE in $(data-files); do \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(DATADIR)/$$FILE\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(DATADIR)/$$FILE"; \
+ fi; \
+ rm -f $(DATADIR)/$$FILE; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(DATADIR)/$$FILE\033[0m"; \
+ fi; \
+ done \
+ fi
+ @if [ -n "$(image-files)" ]; then \
+ for FILE in $(image-files); do \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -n -e "\033[0;1;5muninstall \033[0m: \033[0;31m$(IMAGEDIR)/$$FILE\033[0m"; \
+ else \
+ $(ECHO) "uninstall : $(IMAGEDIR)/$$FILE"; \
+ fi; \
+ rm -f $(IMAGEDIR)/$$FILE; \
+ if [ '$(color)' != 'no' ]; then \
+ $(ECHO) -e "\r\033[0muninstall : \033[34m$(IMAGEDIR)/$$FILE\033[0m"; \
+ fi; \
+ done \
+ fi
diff --git a/fusion/plugins/newton/build/.libs/chipmunk.o b/fusion/plugins/newton/build/.libs/chipmunk.o
new file mode 100644
index 0000000..da016b3
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/chipmunk.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/cpArbiter.o b/fusion/plugins/newton/build/.libs/cpArbiter.o
new file mode 100644
index 0000000..4f4f735
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/cpArbiter.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/cpArray.o b/fusion/plugins/newton/build/.libs/cpArray.o
new file mode 100644
index 0000000..371a720
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/cpArray.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/cpBB.o b/fusion/plugins/newton/build/.libs/cpBB.o
new file mode 100644
index 0000000..372780a
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/cpBB.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/cpBody.o b/fusion/plugins/newton/build/.libs/cpBody.o
new file mode 100644
index 0000000..af15563
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/cpBody.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/cpCollision.o b/fusion/plugins/newton/build/.libs/cpCollision.o
new file mode 100644
index 0000000..f2bd5ea
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/cpCollision.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/cpHashSet.o b/fusion/plugins/newton/build/.libs/cpHashSet.o
new file mode 100644
index 0000000..e274098
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/cpHashSet.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/cpJoint.o b/fusion/plugins/newton/build/.libs/cpJoint.o
new file mode 100644
index 0000000..2ce13f6
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/cpJoint.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/cpPolyShape.o b/fusion/plugins/newton/build/.libs/cpPolyShape.o
new file mode 100644
index 0000000..31d5548
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/cpPolyShape.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/cpShape.o b/fusion/plugins/newton/build/.libs/cpShape.o
new file mode 100644
index 0000000..256d566
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/cpShape.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/cpSpace.o b/fusion/plugins/newton/build/.libs/cpSpace.o
new file mode 100644
index 0000000..ab709e6
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/cpSpace.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/cpSpaceHash.o b/fusion/plugins/newton/build/.libs/cpSpaceHash.o
new file mode 100644
index 0000000..d32ef0e
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/cpSpaceHash.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/cpVect.o b/fusion/plugins/newton/build/.libs/cpVect.o
new file mode 100644
index 0000000..0439b12
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/cpVect.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/libnewton.a b/fusion/plugins/newton/build/.libs/libnewton.a
new file mode 100644
index 0000000..a9fc5c1
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/libnewton.a
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/libnewton.la b/fusion/plugins/newton/build/.libs/libnewton.la
new file mode 120000
index 0000000..0fdb012
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/libnewton.la
@@ -0,0 +1 @@
+../libnewton.la \ No newline at end of file
diff --git a/fusion/plugins/newton/build/.libs/libnewton.lai b/fusion/plugins/newton/build/.libs/libnewton.lai
new file mode 100644
index 0000000..9ea46bb
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/libnewton.lai
@@ -0,0 +1,35 @@
+# libnewton.la - a libtool library file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='libnewton.so.0'
+
+# Names of this library.
+library_names='libnewton.so.0.0.0 libnewton.so.0 libnewton.so'
+
+# The name of the static archive.
+old_library='libnewton.a'
+
+# Libraries that this one depends upon.
+dependency_libs=' -L/opt/xserver-xir-install/lib /opt/xserver-xir-install/lib/libX11-xcb.la /opt/xserver-xir-install/lib/libXcomposite.la /usr/lib/libXdamage.la /usr/lib/libXrandr.la /usr/lib/libXrender.la /usr/lib/libXinerama.la /usr/lib/libXext.la /opt/xserver-xir-install/lib/libXi.la /opt/xserver-xir-install/lib/libXext.la /usr/lib/libxslt.la -lGLU /usr/lib/libstartup-notification-1.la /usr/lib/libSM.la /opt/xserver-xir-install/lib/libX11.la /opt/xserver-xir-install/lib/libxcb-xlib.la /opt/xserver-xir-install/lib/libxcb.la /opt/xserver-xir-install/lib/libXau.la -lXdmcp /usr/lib/libXfixes.la /usr/lib/libX11.la /usr/lib/libxcb-xlib.la /usr/lib/libxcb.la -lXau -lICE /usr/lib/libxml2.la -ldl -lz -lm -lGL'
+
+# Version information for libnewton.
+current=0
+age=0
+revision=0
+
+# Is this an already installed library?
+installed=yes
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=no
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/opt/xserver-xir-install/lib/compiz'
diff --git a/fusion/plugins/newton/build/.libs/libnewton.so b/fusion/plugins/newton/build/.libs/libnewton.so
new file mode 120000
index 0000000..4b386e4
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/libnewton.so
@@ -0,0 +1 @@
+libnewton.so.0.0.0 \ No newline at end of file
diff --git a/fusion/plugins/newton/build/.libs/libnewton.so.0 b/fusion/plugins/newton/build/.libs/libnewton.so.0
new file mode 120000
index 0000000..4b386e4
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/libnewton.so.0
@@ -0,0 +1 @@
+libnewton.so.0.0.0 \ No newline at end of file
diff --git a/fusion/plugins/newton/build/.libs/libnewton.so.0.0.0 b/fusion/plugins/newton/build/.libs/libnewton.so.0.0.0
new file mode 100755
index 0000000..7c873e4
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/libnewton.so.0.0.0
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/newton.o b/fusion/plugins/newton/build/.libs/newton.o
new file mode 100644
index 0000000..a4b447b
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/newton.o
Binary files differ
diff --git a/fusion/plugins/newton/build/.libs/newton_options.o b/fusion/plugins/newton/build/.libs/newton_options.o
new file mode 100644
index 0000000..0fad0c7
--- /dev/null
+++ b/fusion/plugins/newton/build/.libs/newton_options.o
Binary files differ
diff --git a/fusion/plugins/newton/build/chipmunk.lo b/fusion/plugins/newton/build/chipmunk.lo
new file mode 100644
index 0000000..280f811
--- /dev/null
+++ b/fusion/plugins/newton/build/chipmunk.lo
@@ -0,0 +1,12 @@
+# build/chipmunk.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/chipmunk.o'
+
+# Name of the non-PIC object.
+non_pic_object='chipmunk.o'
+
diff --git a/fusion/plugins/newton/build/chipmunk.o b/fusion/plugins/newton/build/chipmunk.o
new file mode 100644
index 0000000..4162e36
--- /dev/null
+++ b/fusion/plugins/newton/build/chipmunk.o
Binary files differ
diff --git a/fusion/plugins/newton/build/compiz-newton.schema b/fusion/plugins/newton/build/compiz-newton.schema
new file mode 100644
index 0000000..4f33121
--- /dev/null
+++ b/fusion/plugins/newton/build/compiz-newton.schema
@@ -0,0 +1,148 @@
+<?xml version="1.0"?>
+<gconfschemafile>
+ <schemalist>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/trigger_physics_key</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/trigger_physics_key</applyto>
+ <owner>compiz</owner>
+ <type>string</type>
+ <default>&lt;Super&gt;p</default>
+ <locale name="C">
+ <short>Trigger Physics on the window</short>
+ <long> Toggle physics on the selected window. </long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/mouse_invert_key</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/mouse_invert_key</applyto>
+ <owner>compiz</owner>
+ <type>string</type>
+ <default>&lt;Super&gt;i</default>
+ <locale name="C">
+ <short>Invert mouse attraction/repulsion</short>
+ <long> Inverts mouse attraction or repulsion. </long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/toggle_miniwindow_key</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/toggle_miniwindow_key</applyto>
+ <owner>compiz</owner>
+ <type>string</type>
+ <default>&lt;Super&gt;t</default>
+ <locale name="C">
+ <short>Toggle miniwindow</short>
+ <long> Toggles miniwindow for current window. </long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/miniwindowsize</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/miniwindowsize</applyto>
+ <owner>compiz</owner>
+ <type>int</type>
+ <default>64</default>
+ <locale name="C">
+ <short>Iconified window size</short>
+ <long> Size of the iconified window in pixels. (12 - 256)</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/bounce_constant</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/bounce_constant</applyto>
+ <owner>compiz</owner>
+ <type>float</type>
+ <default>0.8</default>
+ <locale name="C">
+ <short>Bounce elasticity</short>
+ <long> Elasticity of the windows (0 means no bounce, 1 is perfect elasticity). (0 - 1)</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/friction_constant</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/friction_constant</applyto>
+ <owner>compiz</owner>
+ <type>float</type>
+ <default>0.6</default>
+ <locale name="C">
+ <short>Fluid friction</short>
+ <long> Fluidity of the desktop (0 means solid, and 1 totally liquid). (0 - 1)</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/window_elasticity_constant</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/window_elasticity_constant</applyto>
+ <owner>compiz</owner>
+ <type>int</type>
+ <default>10</default>
+ <locale name="C">
+ <short>Repulsion</short>
+ <long> Elasticity constant of windows. (0 - 100)</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/gravity</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/gravity</applyto>
+ <owner>compiz</owner>
+ <type>int</type>
+ <default>100</default>
+ <locale name="C">
+ <short>Gravity</short>
+ <long> Constant force. (-500 - 500)</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/mouse_attraction</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/mouse_attraction</applyto>
+ <owner>compiz</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Mouse attraction</short>
+ <long> Attracts/repels the windows to the mouse. </long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/mouse_attraction_mode</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/mouse_attraction_mode</applyto>
+ <owner>compiz</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Attract by default</short>
+ <long> Attracts the windows to the mouse when the invert action key is not pressed. </long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/mouse_strength</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/mouse_strength</applyto>
+ <owner>compiz</owner>
+ <type>int</type>
+ <default>10</default>
+ <locale name="C">
+ <short>Mouse attraction strength</short>
+ <long> Strength of the attraction/repulsion force. (0 - 100)</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/mouse_stop</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/mouse_stop</applyto>
+ <owner>compiz</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Stop Hovered windows</short>
+ <long> Stops the windows under the pointer. </long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/compiz/plugins/newton/allscreens/options/draw_miniwindows</key>
+ <applyto>/apps/compiz/plugins/newton/allscreens/options/draw_miniwindows</applyto>
+ <owner>compiz</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Draw miniwindows</short>
+ <long> Draw miniwindows for newly created windows. </long>
+ </locale>
+ </schema>
+ </schemalist>
+</gconfschemafile>
diff --git a/fusion/plugins/newton/build/cpArbiter.lo b/fusion/plugins/newton/build/cpArbiter.lo
new file mode 100644
index 0000000..8c66f00
--- /dev/null
+++ b/fusion/plugins/newton/build/cpArbiter.lo
@@ -0,0 +1,12 @@
+# build/cpArbiter.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/cpArbiter.o'
+
+# Name of the non-PIC object.
+non_pic_object='cpArbiter.o'
+
diff --git a/fusion/plugins/newton/build/cpArbiter.o b/fusion/plugins/newton/build/cpArbiter.o
new file mode 100644
index 0000000..eca5b4c
--- /dev/null
+++ b/fusion/plugins/newton/build/cpArbiter.o
Binary files differ
diff --git a/fusion/plugins/newton/build/cpArray.lo b/fusion/plugins/newton/build/cpArray.lo
new file mode 100644
index 0000000..e99aae7
--- /dev/null
+++ b/fusion/plugins/newton/build/cpArray.lo
@@ -0,0 +1,12 @@
+# build/cpArray.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/cpArray.o'
+
+# Name of the non-PIC object.
+non_pic_object='cpArray.o'
+
diff --git a/fusion/plugins/newton/build/cpArray.o b/fusion/plugins/newton/build/cpArray.o
new file mode 100644
index 0000000..a212922
--- /dev/null
+++ b/fusion/plugins/newton/build/cpArray.o
Binary files differ
diff --git a/fusion/plugins/newton/build/cpBB.lo b/fusion/plugins/newton/build/cpBB.lo
new file mode 100644
index 0000000..d1f688e
--- /dev/null
+++ b/fusion/plugins/newton/build/cpBB.lo
@@ -0,0 +1,12 @@
+# build/cpBB.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/cpBB.o'
+
+# Name of the non-PIC object.
+non_pic_object='cpBB.o'
+
diff --git a/fusion/plugins/newton/build/cpBB.o b/fusion/plugins/newton/build/cpBB.o
new file mode 100644
index 0000000..5cbc477
--- /dev/null
+++ b/fusion/plugins/newton/build/cpBB.o
Binary files differ
diff --git a/fusion/plugins/newton/build/cpBody.lo b/fusion/plugins/newton/build/cpBody.lo
new file mode 100644
index 0000000..75091af
--- /dev/null
+++ b/fusion/plugins/newton/build/cpBody.lo
@@ -0,0 +1,12 @@
+# build/cpBody.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/cpBody.o'
+
+# Name of the non-PIC object.
+non_pic_object='cpBody.o'
+
diff --git a/fusion/plugins/newton/build/cpBody.o b/fusion/plugins/newton/build/cpBody.o
new file mode 100644
index 0000000..8d4c967
--- /dev/null
+++ b/fusion/plugins/newton/build/cpBody.o
Binary files differ
diff --git a/fusion/plugins/newton/build/cpCollision.lo b/fusion/plugins/newton/build/cpCollision.lo
new file mode 100644
index 0000000..e08c33f
--- /dev/null
+++ b/fusion/plugins/newton/build/cpCollision.lo
@@ -0,0 +1,12 @@
+# build/cpCollision.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/cpCollision.o'
+
+# Name of the non-PIC object.
+non_pic_object='cpCollision.o'
+
diff --git a/fusion/plugins/newton/build/cpCollision.o b/fusion/plugins/newton/build/cpCollision.o
new file mode 100644
index 0000000..a835304
--- /dev/null
+++ b/fusion/plugins/newton/build/cpCollision.o
Binary files differ
diff --git a/fusion/plugins/newton/build/cpHashSet.lo b/fusion/plugins/newton/build/cpHashSet.lo
new file mode 100644
index 0000000..c09a227
--- /dev/null
+++ b/fusion/plugins/newton/build/cpHashSet.lo
@@ -0,0 +1,12 @@
+# build/cpHashSet.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/cpHashSet.o'
+
+# Name of the non-PIC object.
+non_pic_object='cpHashSet.o'
+
diff --git a/fusion/plugins/newton/build/cpHashSet.o b/fusion/plugins/newton/build/cpHashSet.o
new file mode 100644
index 0000000..7254de7
--- /dev/null
+++ b/fusion/plugins/newton/build/cpHashSet.o
Binary files differ
diff --git a/fusion/plugins/newton/build/cpJoint.lo b/fusion/plugins/newton/build/cpJoint.lo
new file mode 100644
index 0000000..3be8839
--- /dev/null
+++ b/fusion/plugins/newton/build/cpJoint.lo
@@ -0,0 +1,12 @@
+# build/cpJoint.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/cpJoint.o'
+
+# Name of the non-PIC object.
+non_pic_object='cpJoint.o'
+
diff --git a/fusion/plugins/newton/build/cpJoint.o b/fusion/plugins/newton/build/cpJoint.o
new file mode 100644
index 0000000..3d29094
--- /dev/null
+++ b/fusion/plugins/newton/build/cpJoint.o
Binary files differ
diff --git a/fusion/plugins/newton/build/cpPolyShape.lo b/fusion/plugins/newton/build/cpPolyShape.lo
new file mode 100644
index 0000000..ffee29c
--- /dev/null
+++ b/fusion/plugins/newton/build/cpPolyShape.lo
@@ -0,0 +1,12 @@
+# build/cpPolyShape.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/cpPolyShape.o'
+
+# Name of the non-PIC object.
+non_pic_object='cpPolyShape.o'
+
diff --git a/fusion/plugins/newton/build/cpPolyShape.o b/fusion/plugins/newton/build/cpPolyShape.o
new file mode 100644
index 0000000..d136306
--- /dev/null
+++ b/fusion/plugins/newton/build/cpPolyShape.o
Binary files differ
diff --git a/fusion/plugins/newton/build/cpShape.lo b/fusion/plugins/newton/build/cpShape.lo
new file mode 100644
index 0000000..4bdbe91
--- /dev/null
+++ b/fusion/plugins/newton/build/cpShape.lo
@@ -0,0 +1,12 @@
+# build/cpShape.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/cpShape.o'
+
+# Name of the non-PIC object.
+non_pic_object='cpShape.o'
+
diff --git a/fusion/plugins/newton/build/cpShape.o b/fusion/plugins/newton/build/cpShape.o
new file mode 100644
index 0000000..a750e90
--- /dev/null
+++ b/fusion/plugins/newton/build/cpShape.o
Binary files differ
diff --git a/fusion/plugins/newton/build/cpSpace.lo b/fusion/plugins/newton/build/cpSpace.lo
new file mode 100644
index 0000000..20c139e
--- /dev/null
+++ b/fusion/plugins/newton/build/cpSpace.lo
@@ -0,0 +1,12 @@
+# build/cpSpace.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/cpSpace.o'
+
+# Name of the non-PIC object.
+non_pic_object='cpSpace.o'
+
diff --git a/fusion/plugins/newton/build/cpSpace.o b/fusion/plugins/newton/build/cpSpace.o
new file mode 100644
index 0000000..472ae13
--- /dev/null
+++ b/fusion/plugins/newton/build/cpSpace.o
Binary files differ
diff --git a/fusion/plugins/newton/build/cpSpaceHash.lo b/fusion/plugins/newton/build/cpSpaceHash.lo
new file mode 100644
index 0000000..bd816a0
--- /dev/null
+++ b/fusion/plugins/newton/build/cpSpaceHash.lo
@@ -0,0 +1,12 @@
+# build/cpSpaceHash.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/cpSpaceHash.o'
+
+# Name of the non-PIC object.
+non_pic_object='cpSpaceHash.o'
+
diff --git a/fusion/plugins/newton/build/cpSpaceHash.o b/fusion/plugins/newton/build/cpSpaceHash.o
new file mode 100644
index 0000000..bbe99c0
--- /dev/null
+++ b/fusion/plugins/newton/build/cpSpaceHash.o
Binary files differ
diff --git a/fusion/plugins/newton/build/cpVect.lo b/fusion/plugins/newton/build/cpVect.lo
new file mode 100644
index 0000000..14903ad
--- /dev/null
+++ b/fusion/plugins/newton/build/cpVect.lo
@@ -0,0 +1,12 @@
+# build/cpVect.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/cpVect.o'
+
+# Name of the non-PIC object.
+non_pic_object='cpVect.o'
+
diff --git a/fusion/plugins/newton/build/cpVect.o b/fusion/plugins/newton/build/cpVect.o
new file mode 100644
index 0000000..5a39209
--- /dev/null
+++ b/fusion/plugins/newton/build/cpVect.o
Binary files differ
diff --git a/fusion/plugins/newton/build/libnewton.la b/fusion/plugins/newton/build/libnewton.la
new file mode 100644
index 0000000..3df888d
--- /dev/null
+++ b/fusion/plugins/newton/build/libnewton.la
@@ -0,0 +1,35 @@
+# libnewton.la - a libtool library file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='libnewton.so.0'
+
+# Names of this library.
+library_names='libnewton.so.0.0.0 libnewton.so.0 libnewton.so'
+
+# The name of the static archive.
+old_library='libnewton.a'
+
+# Libraries that this one depends upon.
+dependency_libs=' -L/opt/xserver-xir-install/lib /opt/xserver-xir-install/lib/libX11-xcb.la /opt/xserver-xir-install/lib/libXcomposite.la /usr/lib/libXdamage.la /usr/lib/libXrandr.la /usr/lib/libXrender.la /usr/lib/libXinerama.la /usr/lib/libXext.la /opt/xserver-xir-install/lib/libXi.la /opt/xserver-xir-install/lib/libXext.la /usr/lib/libxslt.la -lGLU /usr/lib/libstartup-notification-1.la /usr/lib/libSM.la /opt/xserver-xir-install/lib/libX11.la /opt/xserver-xir-install/lib/libxcb-xlib.la /opt/xserver-xir-install/lib/libxcb.la /opt/xserver-xir-install/lib/libXau.la -lXdmcp /usr/lib/libXfixes.la /usr/lib/libX11.la /usr/lib/libxcb-xlib.la /usr/lib/libxcb.la -lXau -lICE /usr/lib/libxml2.la -ldl -lz -lm -lGL'
+
+# Version information for libnewton.
+current=0
+age=0
+revision=0
+
+# Is this an already installed library?
+installed=no
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=no
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/opt/xserver-xir-install/lib/compiz'
diff --git a/fusion/plugins/newton/build/newton.lo b/fusion/plugins/newton/build/newton.lo
new file mode 100644
index 0000000..755e632
--- /dev/null
+++ b/fusion/plugins/newton/build/newton.lo
@@ -0,0 +1,12 @@
+# build/newton.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/newton.o'
+
+# Name of the non-PIC object.
+non_pic_object='newton.o'
+
diff --git a/fusion/plugins/newton/build/newton.o b/fusion/plugins/newton/build/newton.o
new file mode 100644
index 0000000..955f930
--- /dev/null
+++ b/fusion/plugins/newton/build/newton.o
Binary files differ
diff --git a/fusion/plugins/newton/build/newton.xml b/fusion/plugins/newton/build/newton.xml
new file mode 100644
index 0000000..d7984b3
--- /dev/null
+++ b/fusion/plugins/newton/build/newton.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0"?>
+<compiz>
+ <plugin name="newton" useBcop="true">
+ <short>Newton</short>
+ <long>Creates iconified windows that can be selected to select the main window and are affected by physics. </long>
+ <category>Window Management</category>
+ <deps>
+ <requirement>
+ <plugin>mousepoll</plugin>
+ </requirement>
+ </deps>
+ <display>
+ <group>
+ <short>Bindings</short>
+ <option name="trigger_physics_key" type="key">
+ <short>Trigger Physics on the window</short>
+ <long> Toggle physics on the selected window. </long>
+ <default>&lt;Super&gt;p</default>
+ </option>
+ <option name="mouse_invert_key" type="key">
+ <short>Invert mouse attraction/repulsion</short>
+ <long> Inverts mouse attraction or repulsion. </long>
+ <default>&lt;Super&gt;i</default>
+ </option>
+ <option name="toggle_miniwindow_key" type="key">
+ <short>Toggle miniwindow</short>
+ <long> Toggles miniwindow for current window. </long>
+ <default>&lt;Super&gt;t</default>
+ </option>
+ </group>
+ <option name="miniwindowsize" type="int">
+ <short>Iconified window size</short>
+ <long> Size of the iconified window in pixels. </long>
+ <default>64</default>
+ <min>12</min>
+ <max>256</max>
+ </option>
+ <option name="bounce_constant" type="float">
+ <short>Bounce elasticity</short>
+ <long> Elasticity of the windows (0 means no bounce, 1 is perfect elasticity). </long>
+ <default>0.8</default>
+ <min>0</min>
+ <max>1</max>
+ </option>
+ <option name="friction_constant" type="float">
+ <short>Fluid friction</short>
+ <long> Fluidity of the desktop (0 means solid, and 1 totally liquid). </long>
+ <default>0.6</default>
+ <min>0</min>
+ <max>1</max>
+ </option>
+ <option name="window_elasticity_constant" type="int">
+ <short>Repulsion</short>
+ <long> Elasticity constant of windows. </long>
+ <default>10</default>
+ <min>0</min>
+ <max>100</max>
+ </option>
+ <option name="gravity" type="int">
+ <short>Gravity</short>
+ <long> Constant force. </long>
+ <default>100</default>
+ <min>-500</min>
+ <max>500</max>
+ </option>
+ <option name="mouse_attraction" type="bool">
+ <short>Mouse attraction</short>
+ <long> Attracts/repels the windows to the mouse. </long>
+ <default>true</default>
+ </option>
+ <option name="mouse_attraction_mode" type="bool">
+ <short>Attract by default</short>
+ <long> Attracts the windows to the mouse when the invert action key is not pressed. </long>
+ <default>false</default>
+ </option>
+ <option name="mouse_strength" type="int">
+ <short>Mouse attraction strength</short>
+ <long> Strength of the attraction/repulsion force. </long>
+ <default>10</default>
+ <min>0</min>
+ <max>100</max>
+ </option>
+ <option name="mouse_stop" type="bool">
+ <short>Stop Hovered windows</short>
+ <long> Stops the windows under the pointer. </long>
+ <default>true</default>
+ </option>
+ <option name="draw_miniwindows" type="bool">
+ <short>Draw miniwindows</short>
+ <long> Draw miniwindows for newly created windows. </long>
+ <default>true</default>
+ </option>
+ </display>
+ </plugin>
+</compiz>
diff --git a/fusion/plugins/newton/build/newton_options.c b/fusion/plugins/newton/build/newton_options.c
new file mode 100644
index 0000000..3893577
--- /dev/null
+++ b/fusion/plugins/newton/build/newton_options.c
@@ -0,0 +1,635 @@
+/*
+ * This file is autogenerated with bcop:
+ * The Compiz option code generator
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <compiz-core.h>
+
+#include "newton_options.h"
+
+static int NewtonOptionsDisplayPrivateIndex;
+
+static CompMetadata newtonOptionsMetadata;
+
+static CompPluginVTable *newtonPluginVTable = NULL;
+CompPluginVTable newtonOptionsVTable;
+
+#define NEWTON_OPTIONS_DISPLAY(d) PLUGIN_DISPLAY(d, NewtonOptions, o)
+#define NEWTON_OPTIONS_SCREEN(s) PLUGIN_SCREEN(s, NewtonOptions, o)
+
+typedef struct _NewtonOptionsDisplay
+{
+ int screenPrivateIndex;
+
+ CompOption opt[NewtonDisplayOptionNum];
+ newtonDisplayOptionChangeNotifyProc notify[NewtonDisplayOptionNum];
+} NewtonOptionsDisplay;
+
+typedef struct _NewtonOptionsScreen
+{
+} NewtonOptionsScreen;
+
+CompAction * newtonGetTriggerPhysicsKey (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionTriggerPhysicsKey].value.action;
+}
+
+void newtonSetTriggerPhysicsKeyInitiate (CompDisplay *d, CompActionCallBackProc init)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->opt[NewtonDisplayOptionTriggerPhysicsKey].value.action.initiate = init;
+}
+
+void newtonSetTriggerPhysicsKeyTerminate (CompDisplay *d, CompActionCallBackProc term)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->opt[NewtonDisplayOptionTriggerPhysicsKey].value.action.terminate = term;
+}
+
+CompOption * newtonGetTriggerPhysicsKeyOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionTriggerPhysicsKey];
+}
+
+void newtonSetTriggerPhysicsKeyNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionTriggerPhysicsKey] = notify;
+}
+
+CompAction * newtonGetMouseInvertKey (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionMouseInvertKey].value.action;
+}
+
+void newtonSetMouseInvertKeyInitiate (CompDisplay *d, CompActionCallBackProc init)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->opt[NewtonDisplayOptionMouseInvertKey].value.action.initiate = init;
+}
+
+void newtonSetMouseInvertKeyTerminate (CompDisplay *d, CompActionCallBackProc term)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->opt[NewtonDisplayOptionMouseInvertKey].value.action.terminate = term;
+}
+
+CompOption * newtonGetMouseInvertKeyOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionMouseInvertKey];
+}
+
+void newtonSetMouseInvertKeyNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionMouseInvertKey] = notify;
+}
+
+CompAction * newtonGetToggleMiniwindowKey (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionToggleMiniwindowKey].value.action;
+}
+
+void newtonSetToggleMiniwindowKeyInitiate (CompDisplay *d, CompActionCallBackProc init)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->opt[NewtonDisplayOptionToggleMiniwindowKey].value.action.initiate = init;
+}
+
+void newtonSetToggleMiniwindowKeyTerminate (CompDisplay *d, CompActionCallBackProc term)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->opt[NewtonDisplayOptionToggleMiniwindowKey].value.action.terminate = term;
+}
+
+CompOption * newtonGetToggleMiniwindowKeyOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionToggleMiniwindowKey];
+}
+
+void newtonSetToggleMiniwindowKeyNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionToggleMiniwindowKey] = notify;
+}
+
+int newtonGetMiniwindowsize (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return od->opt[NewtonDisplayOptionMiniwindowsize].value.i;
+}
+
+CompOption * newtonGetMiniwindowsizeOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionMiniwindowsize];
+}
+
+void newtonSetMiniwindowsizeNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionMiniwindowsize] = notify;
+}
+
+float newtonGetBounceConstant (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return od->opt[NewtonDisplayOptionBounceConstant].value.f;
+}
+
+CompOption * newtonGetBounceConstantOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionBounceConstant];
+}
+
+void newtonSetBounceConstantNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionBounceConstant] = notify;
+}
+
+float newtonGetFrictionConstant (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return od->opt[NewtonDisplayOptionFrictionConstant].value.f;
+}
+
+CompOption * newtonGetFrictionConstantOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionFrictionConstant];
+}
+
+void newtonSetFrictionConstantNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionFrictionConstant] = notify;
+}
+
+int newtonGetWindowElasticityConstant (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return od->opt[NewtonDisplayOptionWindowElasticityConstant].value.i;
+}
+
+CompOption * newtonGetWindowElasticityConstantOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionWindowElasticityConstant];
+}
+
+void newtonSetWindowElasticityConstantNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionWindowElasticityConstant] = notify;
+}
+
+int newtonGetGravity (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return od->opt[NewtonDisplayOptionGravity].value.i;
+}
+
+CompOption * newtonGetGravityOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionGravity];
+}
+
+void newtonSetGravityNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionGravity] = notify;
+}
+
+Bool newtonGetMouseAttraction (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return od->opt[NewtonDisplayOptionMouseAttraction].value.b;
+}
+
+CompOption * newtonGetMouseAttractionOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionMouseAttraction];
+}
+
+void newtonSetMouseAttractionNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionMouseAttraction] = notify;
+}
+
+Bool newtonGetMouseAttractionMode (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return od->opt[NewtonDisplayOptionMouseAttractionMode].value.b;
+}
+
+CompOption * newtonGetMouseAttractionModeOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionMouseAttractionMode];
+}
+
+void newtonSetMouseAttractionModeNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionMouseAttractionMode] = notify;
+}
+
+int newtonGetMouseStrength (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return od->opt[NewtonDisplayOptionMouseStrength].value.i;
+}
+
+CompOption * newtonGetMouseStrengthOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionMouseStrength];
+}
+
+void newtonSetMouseStrengthNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionMouseStrength] = notify;
+}
+
+Bool newtonGetMouseStop (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return od->opt[NewtonDisplayOptionMouseStop].value.b;
+}
+
+CompOption * newtonGetMouseStopOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionMouseStop];
+}
+
+void newtonSetMouseStopNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionMouseStop] = notify;
+}
+
+Bool newtonGetDrawMiniwindows (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return od->opt[NewtonDisplayOptionDrawMiniwindows].value.b;
+}
+
+CompOption * newtonGetDrawMiniwindowsOption (CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[NewtonDisplayOptionDrawMiniwindows];
+}
+
+void newtonSetDrawMiniwindowsNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ od->notify[NewtonDisplayOptionDrawMiniwindows] = notify;
+}
+
+CompOption * newtonGetDisplayOption (CompDisplay *d, NewtonDisplayOptions num)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ return &od->opt[num];
+}
+
+static const CompMetadataOptionInfo newtonOptionsDisplayOptionInfo[] = {
+ { "trigger_physics_key", "key", 0, 0, 0 },
+ { "mouse_invert_key", "key", 0, 0, 0 },
+ { "toggle_miniwindow_key", "key", 0, 0, 0 },
+ { "miniwindowsize", "int", "<min>12</min><max>256</max>", 0, 0 },
+ { "bounce_constant", "float", "<min>0</min><max>1</max>", 0, 0 },
+ { "friction_constant", "float", "<min>0</min><max>1</max>", 0, 0 },
+ { "window_elasticity_constant", "int", "<min>0</min><max>100</max>", 0, 0 },
+ { "gravity", "int", "<min>-500</min><max>500</max>", 0, 0 },
+ { "mouse_attraction", "bool", 0, 0, 0 },
+ { "mouse_attraction_mode", "bool", 0, 0, 0 },
+ { "mouse_strength", "int", "<min>0</min><max>100</max>", 0, 0 },
+ { "mouse_stop", "bool", 0, 0, 0 },
+ { "draw_miniwindows", "bool", 0, 0, 0 },
+};
+
+static Bool newtonOptionsSetDisplayOption (CompPlugin *plugin, CompDisplay *d, const char *name, CompOptionValue *value)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ CompOption *o;
+ int index;
+
+ o = compFindOption (od->opt, NewtonDisplayOptionNum, name, &index);
+
+ if (!o)
+ return FALSE;
+
+ switch (index)
+ {
+ case NewtonDisplayOptionTriggerPhysicsKey:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionTriggerPhysicsKey])
+ (*od->notify[NewtonDisplayOptionTriggerPhysicsKey]) (d, o, NewtonDisplayOptionTriggerPhysicsKey);
+ return TRUE;
+ }
+ break;
+ case NewtonDisplayOptionMouseInvertKey:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionMouseInvertKey])
+ (*od->notify[NewtonDisplayOptionMouseInvertKey]) (d, o, NewtonDisplayOptionMouseInvertKey);
+ return TRUE;
+ }
+ break;
+ case NewtonDisplayOptionToggleMiniwindowKey:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionToggleMiniwindowKey])
+ (*od->notify[NewtonDisplayOptionToggleMiniwindowKey]) (d, o, NewtonDisplayOptionToggleMiniwindowKey);
+ return TRUE;
+ }
+ break;
+ case NewtonDisplayOptionMiniwindowsize:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionMiniwindowsize])
+ (*od->notify[NewtonDisplayOptionMiniwindowsize]) (d, o, NewtonDisplayOptionMiniwindowsize);
+ return TRUE;
+ }
+ break;
+ case NewtonDisplayOptionBounceConstant:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionBounceConstant])
+ (*od->notify[NewtonDisplayOptionBounceConstant]) (d, o, NewtonDisplayOptionBounceConstant);
+ return TRUE;
+ }
+ break;
+ case NewtonDisplayOptionFrictionConstant:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionFrictionConstant])
+ (*od->notify[NewtonDisplayOptionFrictionConstant]) (d, o, NewtonDisplayOptionFrictionConstant);
+ return TRUE;
+ }
+ break;
+ case NewtonDisplayOptionWindowElasticityConstant:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionWindowElasticityConstant])
+ (*od->notify[NewtonDisplayOptionWindowElasticityConstant]) (d, o, NewtonDisplayOptionWindowElasticityConstant);
+ return TRUE;
+ }
+ break;
+ case NewtonDisplayOptionGravity:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionGravity])
+ (*od->notify[NewtonDisplayOptionGravity]) (d, o, NewtonDisplayOptionGravity);
+ return TRUE;
+ }
+ break;
+ case NewtonDisplayOptionMouseAttraction:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionMouseAttraction])
+ (*od->notify[NewtonDisplayOptionMouseAttraction]) (d, o, NewtonDisplayOptionMouseAttraction);
+ return TRUE;
+ }
+ break;
+ case NewtonDisplayOptionMouseAttractionMode:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionMouseAttractionMode])
+ (*od->notify[NewtonDisplayOptionMouseAttractionMode]) (d, o, NewtonDisplayOptionMouseAttractionMode);
+ return TRUE;
+ }
+ break;
+ case NewtonDisplayOptionMouseStrength:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionMouseStrength])
+ (*od->notify[NewtonDisplayOptionMouseStrength]) (d, o, NewtonDisplayOptionMouseStrength);
+ return TRUE;
+ }
+ break;
+ case NewtonDisplayOptionMouseStop:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionMouseStop])
+ (*od->notify[NewtonDisplayOptionMouseStop]) (d, o, NewtonDisplayOptionMouseStop);
+ return TRUE;
+ }
+ break;
+ case NewtonDisplayOptionDrawMiniwindows:
+ if (compSetDisplayOption (d, o, value))
+ {
+ if (od->notify[NewtonDisplayOptionDrawMiniwindows])
+ (*od->notify[NewtonDisplayOptionDrawMiniwindows]) (d, o, NewtonDisplayOptionDrawMiniwindows);
+ return TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+static CompOption * newtonOptionsGetDisplayOptions (CompPlugin *plugin, CompDisplay *d, int *count)
+{
+ NEWTON_OPTIONS_DISPLAY(d);
+ *count = NewtonDisplayOptionNum;
+ return od->opt;
+}
+
+static Bool newtonOptionsInitScreen (CompPlugin *p, CompScreen *s)
+{
+ NewtonOptionsScreen *os;
+
+ NEWTON_OPTIONS_DISPLAY (s->display);
+
+ os = calloc (1, sizeof(NewtonOptionsScreen));
+ if (!os)
+ return FALSE;
+
+ s->base.privates[od->screenPrivateIndex].ptr = os;
+
+
+ return TRUE;
+}
+
+static void newtonOptionsFiniScreen (CompPlugin *p, CompScreen *s)
+{
+ NEWTON_OPTIONS_SCREEN (s);
+
+ free (os);
+}
+
+static Bool newtonOptionsInitDisplay (CompPlugin *p, CompDisplay *d)
+{
+ NewtonOptionsDisplay *od;
+
+
+ od = calloc (1, sizeof(NewtonOptionsDisplay));
+ if (!od)
+ return FALSE;
+
+ od->screenPrivateIndex = allocateScreenPrivateIndex(d);
+ if (od->screenPrivateIndex < 0)
+ {
+ free(od);
+ return FALSE;
+ }
+
+ d->base.privates[NewtonOptionsDisplayPrivateIndex].ptr = od;
+
+ if (!compInitDisplayOptionsFromMetadata (d, &newtonOptionsMetadata, newtonOptionsDisplayOptionInfo, od->opt, NewtonDisplayOptionNum))
+ {
+ free (od);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void newtonOptionsFiniDisplay (CompPlugin *p, CompDisplay *d)
+{
+ NEWTON_OPTIONS_DISPLAY (d);
+
+ freeScreenPrivateIndex(d, od->screenPrivateIndex);
+
+ compFiniDisplayOptions (d, od->opt, NewtonDisplayOptionNum);
+
+ free (od);
+}
+
+static Bool newtonOptionsInit (CompPlugin *p)
+{
+ NewtonOptionsDisplayPrivateIndex = allocateDisplayPrivateIndex();
+ if (NewtonOptionsDisplayPrivateIndex < 0)
+ return FALSE;
+
+ if (!compInitPluginMetadataFromInfo (&newtonOptionsMetadata, "newton",newtonOptionsDisplayOptionInfo, NewtonDisplayOptionNum, 0, 0))
+ return FALSE;
+
+ compAddMetadataFromFile (&newtonOptionsMetadata, "newton");
+ if (newtonPluginVTable && newtonPluginVTable->init)
+ return newtonPluginVTable->init (p);
+ return TRUE;
+}
+
+static void newtonOptionsFini (CompPlugin *p)
+{
+ if (newtonPluginVTable && newtonPluginVTable->fini)
+ newtonPluginVTable->fini (p);
+
+ if (NewtonOptionsDisplayPrivateIndex >= 0)
+ freeDisplayPrivateIndex (NewtonOptionsDisplayPrivateIndex);
+
+ compFiniMetadata (&newtonOptionsMetadata);
+}
+
+static CompBool newtonOptionsInitObject (CompPlugin *p, CompObject *o)
+{
+ static InitPluginObjectProc dispTab[] = {
+ (InitPluginObjectProc) 0,
+ (InitPluginObjectProc) newtonOptionsInitDisplay,
+ (InitPluginObjectProc) newtonOptionsInitScreen
+ };
+
+ RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
+}
+
+static void newtonOptionsFiniObject (CompPlugin *p, CompObject *o)
+{
+ static FiniPluginObjectProc dispTab[] = {
+ (FiniPluginObjectProc) 0,
+ (FiniPluginObjectProc) newtonOptionsFiniDisplay,
+ (FiniPluginObjectProc) newtonOptionsFiniScreen
+ };
+
+ DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
+}
+
+static CompBool newtonOptionsInitObjectWrapper (CompPlugin *p, CompObject *o)
+{
+ CompBool rv = TRUE;
+ rv = newtonOptionsInitObject (p, o);
+ if (newtonPluginVTable->initObject)
+ rv &= newtonPluginVTable->initObject (p, o);
+ return rv;
+}
+
+static void newtonOptionsFiniObjectWrapper (CompPlugin *p, CompObject *o)
+{
+ if (newtonPluginVTable->finiObject)
+ newtonPluginVTable->finiObject (p, o);
+ newtonOptionsFiniObject (p, o);
+}
+
+static CompOption * newtonOptionsGetObjectOptions (CompPlugin *p, CompObject *o, int *count)
+{
+ static GetPluginObjectOptionsProc dispTab[] = {
+ (GetPluginObjectOptionsProc) 0,
+ (GetPluginObjectOptionsProc) newtonOptionsGetDisplayOptions,
+ };
+
+ *count = 0;
+ RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab),
+ NULL, (p, o, count));
+}
+
+static CompBool newtonOptionsSetObjectOption (CompPlugin *p, CompObject *o, const char *name, CompOptionValue *value)
+{
+ static SetPluginObjectOptionProc dispTab[] = {
+ (SetPluginObjectOptionProc) 0,
+ (SetPluginObjectOptionProc) newtonOptionsSetDisplayOption,
+ };
+
+ RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), FALSE,
+ (p, o, name, value));
+}
+
+static CompMetadata *
+newtonOptionsGetMetadata (CompPlugin *plugin)
+{
+ return &newtonOptionsMetadata;
+}
+
+CompPluginVTable *getCompPluginInfo20070830 (void)
+{
+ if (!newtonPluginVTable)
+ {
+ newtonPluginVTable = getCompPluginInfo ();
+ memcpy(&newtonOptionsVTable, newtonPluginVTable, sizeof(CompPluginVTable));
+ newtonOptionsVTable.getMetadata = newtonOptionsGetMetadata;
+ newtonOptionsVTable.init = newtonOptionsInit;
+ newtonOptionsVTable.fini = newtonOptionsFini;
+ newtonOptionsVTable.initObject = newtonOptionsInitObjectWrapper;
+ newtonOptionsVTable.finiObject = newtonOptionsFiniObjectWrapper;
+ newtonOptionsVTable.getObjectOptions = newtonOptionsGetObjectOptions;
+ newtonOptionsVTable.setObjectOption = newtonOptionsSetObjectOption;
+
+ }
+ return &newtonOptionsVTable;
+}
+
diff --git a/fusion/plugins/newton/build/newton_options.h b/fusion/plugins/newton/build/newton_options.h
new file mode 100644
index 0000000..ec224d3
--- /dev/null
+++ b/fusion/plugins/newton/build/newton_options.h
@@ -0,0 +1,145 @@
+/*
+ * This file is autogenerated with bcop:
+ * The Compiz option code generator
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _NEWTON_OPTIONS_H
+#define _NEWTON_OPTIONS_H
+
+#include <compiz-common.h>
+
+COMPIZ_BEGIN_DECLS
+
+CompPluginVTable * getCompPluginInfo (void);
+
+typedef enum
+{
+ NewtonDisplayOptionTriggerPhysicsKey,
+ NewtonDisplayOptionMouseInvertKey,
+ NewtonDisplayOptionToggleMiniwindowKey,
+ NewtonDisplayOptionMiniwindowsize,
+ NewtonDisplayOptionBounceConstant,
+ NewtonDisplayOptionFrictionConstant,
+ NewtonDisplayOptionWindowElasticityConstant,
+ NewtonDisplayOptionGravity,
+ NewtonDisplayOptionMouseAttraction,
+ NewtonDisplayOptionMouseAttractionMode,
+ NewtonDisplayOptionMouseStrength,
+ NewtonDisplayOptionMouseStop,
+ NewtonDisplayOptionDrawMiniwindows,
+ NewtonDisplayOptionNum
+} NewtonDisplayOptions;
+
+typedef void (*newtonDisplayOptionChangeNotifyProc) (CompDisplay *display, CompOption *opt, NewtonDisplayOptions num);
+
+CompOption *newtonGetDisplayOption (CompDisplay *d, NewtonDisplayOptions num);
+
+typedef enum
+{
+ NewtonScreenOptionNum
+} NewtonScreenOptions;
+
+typedef void (*newtonScreenOptionChangeNotifyProc) (CompScreen *screen, CompOption *opt, NewtonScreenOptions num);
+
+CompOption *newtonGetScreenOption (CompScreen *s, NewtonScreenOptions num);
+
+CompAction * newtonGetTriggerPhysicsKey (CompDisplay *d);
+void newtonSetTriggerPhysicsKeyInitiate (CompDisplay *d, CompActionCallBackProc init);
+void newtonSetTriggerPhysicsKeyTerminate (CompDisplay *d, CompActionCallBackProc term);
+CompOption * newtonGetTriggerPhysicsKeyOption (CompDisplay *d);
+void newtonSetTriggerPhysicsKeyNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+CompAction * newtonGetMouseInvertKey (CompDisplay *d);
+void newtonSetMouseInvertKeyInitiate (CompDisplay *d, CompActionCallBackProc init);
+void newtonSetMouseInvertKeyTerminate (CompDisplay *d, CompActionCallBackProc term);
+CompOption * newtonGetMouseInvertKeyOption (CompDisplay *d);
+void newtonSetMouseInvertKeyNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+CompAction * newtonGetToggleMiniwindowKey (CompDisplay *d);
+void newtonSetToggleMiniwindowKeyInitiate (CompDisplay *d, CompActionCallBackProc init);
+void newtonSetToggleMiniwindowKeyTerminate (CompDisplay *d, CompActionCallBackProc term);
+CompOption * newtonGetToggleMiniwindowKeyOption (CompDisplay *d);
+void newtonSetToggleMiniwindowKeyNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+int newtonGetMiniwindowsize (CompDisplay *d);
+CompOption * newtonGetMiniwindowsizeOption (CompDisplay *d);
+void newtonSetMiniwindowsizeNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+float newtonGetBounceConstant (CompDisplay *d);
+CompOption * newtonGetBounceConstantOption (CompDisplay *d);
+void newtonSetBounceConstantNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+float newtonGetFrictionConstant (CompDisplay *d);
+CompOption * newtonGetFrictionConstantOption (CompDisplay *d);
+void newtonSetFrictionConstantNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+int newtonGetWindowElasticityConstant (CompDisplay *d);
+CompOption * newtonGetWindowElasticityConstantOption (CompDisplay *d);
+void newtonSetWindowElasticityConstantNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+int newtonGetGravity (CompDisplay *d);
+CompOption * newtonGetGravityOption (CompDisplay *d);
+void newtonSetGravityNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+Bool newtonGetMouseAttraction (CompDisplay *d);
+CompOption * newtonGetMouseAttractionOption (CompDisplay *d);
+void newtonSetMouseAttractionNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+Bool newtonGetMouseAttractionMode (CompDisplay *d);
+CompOption * newtonGetMouseAttractionModeOption (CompDisplay *d);
+void newtonSetMouseAttractionModeNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+int newtonGetMouseStrength (CompDisplay *d);
+CompOption * newtonGetMouseStrengthOption (CompDisplay *d);
+void newtonSetMouseStrengthNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+Bool newtonGetMouseStop (CompDisplay *d);
+CompOption * newtonGetMouseStopOption (CompDisplay *d);
+void newtonSetMouseStopNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+Bool newtonGetDrawMiniwindows (CompDisplay *d);
+CompOption * newtonGetDrawMiniwindowsOption (CompDisplay *d);
+void newtonSetDrawMiniwindowsNotify (CompDisplay *d, newtonDisplayOptionChangeNotifyProc notify);
+
+#ifndef GENERIC_PRIVATE_DEFINES
+#define GENERIC_PRIVATE_DEFINES
+
+#define GET_PLUGIN_CORE(object, plugin) \
+ ((plugin##Core *) (object)->base.privates[plugin##CorePrivateIndex].ptr)
+#define PLUGIN_CORE(object, plugin, prefix) \
+ plugin##Core * prefix##c = GET_PLUGIN_CORE (object, plugin)
+
+#define GET_PLUGIN_DISPLAY(object, plugin) \
+ ((plugin##Display *) \
+ (object)->base.privates[plugin##DisplayPrivateIndex].ptr)
+#define PLUGIN_DISPLAY(object, plugin, prefix) \
+ plugin##Display * prefix##d = GET_PLUGIN_DISPLAY (object, plugin)
+
+#define GET_PLUGIN_SCREEN(object, parent, plugin) \
+ ((plugin##Screen *) \
+ (object)->base.privates[(parent)->screenPrivateIndex].ptr)
+#define PLUGIN_SCREEN(object, plugin, prefix) \
+ plugin##Screen * prefix##s = \
+ GET_PLUGIN_SCREEN (object, \
+ GET_PLUGIN_DISPLAY ((object)->display, plugin), plugin)
+
+#define GET_PLUGIN_WINDOW(object, parent, plugin) \
+ ((plugin##Window *) \
+ (object)->base.privates[(parent)->windowPrivateIndex].ptr)
+#define PLUGIN_WINDOW(object, plugin, prefix) \
+ plugin##Window * prefix##w = \
+ GET_PLUGIN_WINDOW (object, \
+ GET_PLUGIN_SCREEN ((object)->screen, \
+ GET_PLUGIN_DISPLAY ((object)->screen->display, plugin), plugin), plugin)
+
+#endif
+
+COMPIZ_END_DECLS
+
+#endif
diff --git a/fusion/plugins/newton/build/newton_options.lo b/fusion/plugins/newton/build/newton_options.lo
new file mode 100644
index 0000000..47bb199
--- /dev/null
+++ b/fusion/plugins/newton/build/newton_options.lo
@@ -0,0 +1,12 @@
+# build/newton_options.lo - a libtool object file
+# Generated by ltmain.sh - GNU libtool 1.5.26 (1.1220.2.492 2008/01/30 06:40:56)
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object='.libs/newton_options.o'
+
+# Name of the non-PIC object.
+non_pic_object='newton_options.o'
+
diff --git a/fusion/plugins/newton/build/newton_options.o b/fusion/plugins/newton/build/newton_options.o
new file mode 100644
index 0000000..9197cf3
--- /dev/null
+++ b/fusion/plugins/newton/build/newton_options.o
Binary files differ
diff --git a/fusion/plugins/newton/chipmunk.c b/fusion/plugins/newton/chipmunk.c
new file mode 100644
index 0000000..9d5f08a
--- /dev/null
+++ b/fusion/plugins/newton/chipmunk.c
@@ -0,0 +1,69 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include "stdlib.h"
+
+#include "chipmunk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void cpInitCollisionFuncs(void);
+#ifdef __cplusplus
+}
+#endif
+
+
+void
+cpInitChipmunk(void)
+{
+ cpInitCollisionFuncs();
+}
+
+cpFloat
+cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset)
+{
+ return (1.0f/2.0f)*m*(r1*r1 + r2*r2) + m*cpvdot(offset, offset);
+}
+
+cpFloat
+cpMomentForPoly(cpFloat m, const int numVerts, cpVect *verts, cpVect offset)
+{
+ cpVect *tVerts = (cpVect *)calloc(numVerts, sizeof(cpVect));
+ for(int i=0; i<numVerts; i++)
+ tVerts[i] = cpvadd(verts[i], offset);
+
+ cpFloat sum1 = 0.0f;
+ cpFloat sum2 = 0.0f;
+ for(int i=0; i<numVerts; i++){
+ cpVect v1 = tVerts[i];
+ cpVect v2 = tVerts[(i+1)%numVerts];
+
+ cpFloat a = cpvcross(v2, v1);
+ cpFloat b = cpvdot(v1, v1) + cpvdot(v1, v2) + cpvdot(v2, v2);
+
+ sum1 += a*b;
+ sum2 += a;
+ }
+
+ free(tVerts);
+ return (m*sum1)/(6.0f*sum2);
+}
diff --git a/fusion/plugins/newton/chipmunk.h b/fusion/plugins/newton/chipmunk.h
new file mode 100644
index 0000000..835d975
--- /dev/null
+++ b/fusion/plugins/newton/chipmunk.h
@@ -0,0 +1,90 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef float cpFloat;
+
+static inline cpFloat
+cpfmax(cpFloat a, cpFloat b)
+{
+ return (a > b) ? a : b;
+}
+
+static inline cpFloat
+cpfmin(cpFloat a, cpFloat b)
+{
+ return (a < b) ? a : b;
+}
+
+static inline cpFloat
+cpfclamp(cpFloat f, cpFloat min, cpFloat max){
+ return cpfmin(cpfmax(f, min), max);
+}
+
+#ifndef INFINITY
+ #ifdef _MSC_VER
+ union MSVC_EVIL_FLOAT_HACK
+ {
+ unsigned __int8 Bytes[4];
+ float Value;
+ };
+ static union MSVC_EVIL_FLOAT_HACK INFINITY_HACK = {{0x00, 0x00, 0x80, 0x7F}};
+ #define INFINITY (INFINITY_HACK.Value)
+ #else
+ #define INFINITY (1e1000)
+ #endif
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include "cpVect.h"
+#include "cpBB.h"
+#include "cpBody.h"
+#include "cpArray.h"
+#include "cpHashSet.h"
+#include "cpSpaceHash.h"
+
+#include "cpShape.h"
+#include "cpPolyShape.h"
+
+#include "cpArbiter.h"
+#include "cpCollision.h"
+
+#include "cpJoint.h"
+
+#include "cpSpace.h"
+
+#define CP_HASH_COEF (3344921057ul)
+#define CP_HASH_PAIR(A, B) ((unsigned int)(A)*CP_HASH_COEF ^ (unsigned int)(B)*CP_HASH_COEF)
+
+void cpInitChipmunk(void);
+
+cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset);
+cpFloat cpMomentForPoly(cpFloat m, int numVerts, cpVect *verts, cpVect offset);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/fusion/plugins/newton/cpArbiter.c b/fusion/plugins/newton/cpArbiter.c
new file mode 100644
index 0000000..98de38e
--- /dev/null
+++ b/fusion/plugins/newton/cpArbiter.c
@@ -0,0 +1,263 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "chipmunk.h"
+
+cpFloat cp_bias_coef = 0.1f;
+cpFloat cp_collision_slop = 0.1f;
+
+cpContact*
+cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, unsigned int hash)
+{
+ con->p = p;
+ con->n = n;
+ con->dist = dist;
+
+ con->jnAcc = 0.0f;
+ con->jtAcc = 0.0f;
+ con->jBias = 0.0f;
+
+ con->hash = hash;
+
+ return con;
+}
+
+cpVect
+cpContactsSumImpulses(cpContact *contacts, int numContacts)
+{
+ cpVect sum = cpvzero;
+
+ for(int i=0; i<numContacts; i++){
+ cpContact *con = &contacts[i];
+ cpVect j = cpvmult(con->n, con->jnAcc);
+ sum = cpvadd(sum, j);
+ }
+
+ return sum;
+}
+
+cpVect
+cpContactsSumImpulsesWithFriction(cpContact *contacts, int numContacts)
+{
+ cpVect sum = cpvzero;
+
+ for(int i=0; i<numContacts; i++){
+ cpContact *con = &contacts[i];
+ cpVect t = cpvperp(con->n);
+ cpVect j = cpvadd(cpvmult(con->n, con->jnAcc), cpvmult(t, con->jtAcc));
+ sum = cpvadd(sum, j);
+ }
+
+ return sum;
+}
+
+cpArbiter*
+cpArbiterAlloc(void)
+{
+ return (cpArbiter *)calloc(1, sizeof(cpArbiter));
+}
+
+cpArbiter*
+cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b, int stamp)
+{
+ arb->numContacts = 0;
+ arb->contacts = NULL;
+
+ arb->a = a;
+ arb->b = b;
+
+ arb->stamp = stamp;
+
+ return arb;
+}
+
+cpArbiter*
+cpArbiterNew(cpShape *a, cpShape *b, int stamp)
+{
+ return cpArbiterInit(cpArbiterAlloc(), a, b, stamp);
+}
+
+void
+cpArbiterDestroy(cpArbiter *arb)
+{
+ free(arb->contacts);
+}
+
+void
+cpArbiterFree(cpArbiter *arb)
+{
+ if(arb) cpArbiterDestroy(arb);
+ free(arb);
+}
+
+void
+cpArbiterInject(cpArbiter *arb, cpContact *contacts, int numContacts)
+{
+ // Iterate over the possible pairs to look for hash value matches.
+ for(int i=0; i<arb->numContacts; i++){
+ cpContact *old = &arb->contacts[i];
+
+ for(int j=0; j<numContacts; j++){
+ cpContact *new_contact = &contacts[j];
+
+ // This could trigger false possitives.
+ if(new_contact->hash == old->hash){
+ // Copy the persistant contact information.
+ new_contact->jnAcc = old->jnAcc;
+ new_contact->jtAcc = old->jtAcc;
+ }
+ }
+ }
+
+ free(arb->contacts);
+
+ arb->contacts = contacts;
+ arb->numContacts = numContacts;
+}
+
+void
+cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv)
+{
+ cpShape *shapea = arb->a;
+ cpShape *shapeb = arb->b;
+
+ cpFloat e = shapea->e * shapeb->e;
+ arb->u = shapea->u * shapeb->u;
+ arb->target_v = cpvsub(shapeb->surface_v, shapea->surface_v);
+
+ cpBody *a = shapea->body;
+ cpBody *b = shapeb->body;
+
+ for(int i=0; i<arb->numContacts; i++){
+ cpContact *con = &arb->contacts[i];
+
+ // Calculate the offsets.
+ con->r1 = cpvsub(con->p, a->p);
+ con->r2 = cpvsub(con->p, b->p);
+
+ // Calculate the mass normal.
+ cpFloat mass_sum = a->m_inv + b->m_inv;
+
+ cpFloat r1cn = cpvcross(con->r1, con->n);
+ cpFloat r2cn = cpvcross(con->r2, con->n);
+ cpFloat kn = mass_sum + a->i_inv*r1cn*r1cn + b->i_inv*r2cn*r2cn;
+ con->nMass = 1.0f/kn;
+
+ // Calculate the mass tangent.
+ cpVect t = cpvperp(con->n);
+ cpFloat r1ct = cpvcross(con->r1, t);
+ cpFloat r2ct = cpvcross(con->r2, t);
+ cpFloat kt = mass_sum + a->i_inv*r1ct*r1ct + b->i_inv*r2ct*r2ct;
+ con->tMass = 1.0f/kt;
+
+ // Calculate the target bias velocity.
+ con->bias = -cp_bias_coef*dt_inv*cpfmin(0.0f, con->dist + cp_collision_slop);
+ con->jBias = 0.0f;
+
+ // Calculate the target bounce velocity.
+ cpVect v1 = cpvadd(a->v, cpvmult(cpvperp(con->r1), a->w));
+ cpVect v2 = cpvadd(b->v, cpvmult(cpvperp(con->r2), b->w));
+ con->bounce = cpvdot(con->n, cpvsub(v2, v1))*e;
+ }
+}
+
+void
+cpArbiterApplyCachedImpulse(cpArbiter *arb)
+{
+ cpShape *shapea = arb->a;
+ cpShape *shapeb = arb->b;
+
+ arb->u = shapea->u * shapeb->u;
+ arb->target_v = cpvsub(shapeb->surface_v, shapea->surface_v);
+
+ cpBody *a = shapea->body;
+ cpBody *b = shapeb->body;
+
+ for(int i=0; i<arb->numContacts; i++){
+ cpContact *con = &arb->contacts[i];
+
+ cpVect t = cpvperp(con->n);
+ cpVect j = cpvadd(cpvmult(con->n, con->jnAcc), cpvmult(t, con->jtAcc));
+ cpBodyApplyImpulse(a, cpvneg(j), con->r1);
+ cpBodyApplyImpulse(b, j, con->r2);
+ }
+}
+
+void
+cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef)
+{
+ cpBody *a = arb->a->body;
+ cpBody *b = arb->b->body;
+
+ for(int i=0; i<arb->numContacts; i++){
+ cpContact *con = &arb->contacts[i];
+ cpVect n = con->n;
+ cpVect r1 = con->r1;
+ cpVect r2 = con->r2;
+
+ // Calculate the relative bias velocities.
+ cpVect vb1 = cpvadd(a->v_bias, cpvmult(cpvperp(r1), a->w_bias));
+ cpVect vb2 = cpvadd(b->v_bias, cpvmult(cpvperp(r2), b->w_bias));
+ cpFloat vbn = cpvdot(cpvsub(vb2, vb1), n);
+
+ // Calculate and clamp the bias impulse.
+ cpFloat jbn = (con->bias - vbn)*con->nMass;
+ cpFloat jbnOld = con->jBias;
+ con->jBias = cpfmax(jbnOld + jbn, 0.0f);
+ jbn = con->jBias - jbnOld;
+
+ // Apply the bias impulse.
+ cpVect jb = cpvmult(n, jbn);
+ cpBodyApplyBiasImpulse(a, cpvneg(jb), r1);
+ cpBodyApplyBiasImpulse(b, jb, r2);
+
+ // Calculate the relative velocity.
+ cpVect v1 = cpvadd(a->v, cpvmult(cpvperp(r1), a->w));
+ cpVect v2 = cpvadd(b->v, cpvmult(cpvperp(r2), b->w));
+ cpVect vr = cpvsub(v2, v1);
+ cpFloat vrn = cpvdot(vr, n);
+
+ // Calculate and clamp the normal impulse.
+ cpFloat jn = -(con->bounce*eCoef + vrn)*con->nMass;
+ cpFloat jnOld = con->jnAcc;
+ con->jnAcc = cpfmax(jnOld + jn, 0.0f);
+ jn = con->jnAcc - jnOld;
+
+ // Calculate the relative tangent velocity.
+ cpVect t = cpvperp(n);
+ cpFloat vrt = cpvdot(cpvadd(vr, arb->target_v), t);
+
+ // Calculate and clamp the friction impulse.
+ cpFloat jtMax = arb->u*con->jnAcc;
+ cpFloat jt = -vrt*con->tMass;
+ cpFloat jtOld = con->jtAcc;
+ con->jtAcc = cpfclamp(jtOld + jt, -jtMax, jtMax);
+ jt = con->jtAcc - jtOld;
+
+ // Apply the final impulse.
+ cpVect j = cpvadd(cpvmult(n, jn), cpvmult(t, jt));
+ cpBodyApplyImpulse(a, cpvneg(j), r1);
+ cpBodyApplyImpulse(b, j, r2);
+ }
+}
diff --git a/fusion/plugins/newton/cpArbiter.h b/fusion/plugins/newton/cpArbiter.h
new file mode 100644
index 0000000..d061b85
--- /dev/null
+++ b/fusion/plugins/newton/cpArbiter.h
@@ -0,0 +1,85 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+// Determines how fast penetrations resolve themselves.
+extern cpFloat cp_bias_coef;
+// Amount of allowed penetration. Used to reduce vibrating contacts.
+extern cpFloat cp_collision_slop;
+
+// Data structure for contact points.
+typedef struct cpContact{
+ // Contact point and normal.
+ cpVect p, n;
+ // Penetration distance.
+ cpFloat dist;
+
+ // Calculated by cpArbiterPreStep().
+ cpVect r1, r2;
+ cpFloat nMass, tMass, bounce;
+
+ // Persistant contact information.
+ cpFloat jnAcc, jtAcc, jBias;
+ cpFloat bias;
+
+ // Hash value used to (mostly) uniquely identify a contact.
+ unsigned int hash;
+} cpContact;
+
+// Contacts are always allocated in groups.
+cpContact* cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, unsigned int hash);
+
+// Sum the contact impulses. (Can be used after cpSpaceStep() returns)
+cpVect cpContactsSumImpulses(cpContact *contacts, int numContacts);
+cpVect cpContactsSumImpulsesWithFriction(cpContact *contacts, int numContacts);
+
+// Data structure for tracking collisions between shapes.
+typedef struct cpArbiter{
+ // Information on the contact points between the objects.
+ int numContacts;
+ cpContact *contacts;
+
+ // The two shapes involved in the collision.
+ cpShape *a, *b;
+
+ // Calculated by cpArbiterPreStep().
+ cpFloat u;
+ cpVect target_v;
+
+ // Time stamp of the arbiter. (from cpSpace)
+ int stamp;
+} cpArbiter;
+
+// Basic allocation/destruction functions.
+cpArbiter* cpArbiterAlloc(void);
+cpArbiter* cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b, int stamp);
+cpArbiter* cpArbiterNew(cpShape *a, cpShape *b, int stamp);
+
+void cpArbiterDestroy(cpArbiter *arb);
+void cpArbiterFree(cpArbiter *arb);
+
+// These functions are all intended to be used internally.
+// Inject new contact points into the arbiter while preserving contact history.
+void cpArbiterInject(cpArbiter *arb, cpContact *contacts, int numContacts);
+// Precalculate values used by the solver.
+void cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv);
+void cpArbiterApplyCachedImpulse(cpArbiter *arb);
+// Run an iteration of the solver on the arbiter.
+void cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef);
diff --git a/fusion/plugins/newton/cpArray.c b/fusion/plugins/newton/cpArray.c
new file mode 100644
index 0000000..68ed76d
--- /dev/null
+++ b/fusion/plugins/newton/cpArray.c
@@ -0,0 +1,114 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "chipmunk.h"
+
+
+//#define CP_ARRAY_INCREMENT 10
+
+// NOTE: cpArray is rarely used and will probably go away.
+
+cpArray*
+cpArrayAlloc(void)
+{
+ return (cpArray *)calloc(1, sizeof(cpArray));
+}
+
+cpArray*
+cpArrayInit(cpArray *arr, int size)
+{
+ arr->num = 0;
+
+ size = (size ? size : 4);
+ arr->max = size;
+ arr->arr = (void **)malloc(size*sizeof(void**));
+
+ return arr;
+}
+
+cpArray*
+cpArrayNew(int size)
+{
+ return cpArrayInit(cpArrayAlloc(), size);
+}
+
+void
+cpArrayDestroy(cpArray *arr)
+{
+ free(arr->arr);
+}
+
+void
+cpArrayFree(cpArray *arr)
+{
+ if(!arr) return;
+ cpArrayDestroy(arr);
+ free(arr);
+}
+
+void
+cpArrayPush(cpArray *arr, void *object)
+{
+ if(arr->num == arr->max){
+ arr->max *= 2;
+ arr->arr = (void **)realloc(arr->arr, arr->max*sizeof(void**));
+ }
+
+ arr->arr[arr->num] = object;
+ arr->num++;
+}
+
+void
+cpArrayDeleteIndex(cpArray *arr, int index)
+{
+ int last = --arr->num;
+ arr->arr[index] = arr->arr[last];
+}
+
+void
+cpArrayDeleteObj(cpArray *arr, void *obj)
+{
+ for(int i=0; i<arr->num; i++){
+ if(arr->arr[i] == obj){
+ cpArrayDeleteIndex(arr, i);
+ return;
+ }
+ }
+}
+
+void
+cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data)
+{
+ for(int i=0; i<arr->num; i++)
+ iterFunc(arr->arr[i], data);
+}
+
+int
+cpArrayContains(cpArray *arr, void *ptr)
+{
+ for(int i=0; i<arr->num; i++)
+ if(arr->arr[i] == ptr) return 1;
+
+ return 0;
+}
diff --git a/fusion/plugins/newton/cpArray.h b/fusion/plugins/newton/cpArray.h
new file mode 100644
index 0000000..7e597ad
--- /dev/null
+++ b/fusion/plugins/newton/cpArray.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+// NOTE: cpArray is rarely used and will probably go away.
+
+typedef struct cpArray{
+ int num, max;
+ void **arr;
+} cpArray;
+
+typedef void (*cpArrayIter)(void *ptr, void *data);
+
+cpArray *cpArrayAlloc(void);
+cpArray *cpArrayInit(cpArray *arr, int size);
+cpArray *cpArrayNew(int size);
+
+void cpArrayDestroy(cpArray *arr);
+void cpArrayFree(cpArray *arr);
+
+void cpArrayClear(cpArray *arr);
+
+void cpArrayPush(cpArray *arr, void *object);
+void cpArrayDeleteIndex(cpArray *arr, int index);
+void cpArrayDeleteObj(cpArray *arr, void *obj);
+
+void cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data);
+int cpArrayContains(cpArray *arr, void *ptr);
diff --git a/fusion/plugins/newton/cpBB.c b/fusion/plugins/newton/cpBB.c
new file mode 100644
index 0000000..569855c
--- /dev/null
+++ b/fusion/plugins/newton/cpBB.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <math.h>
+
+#include "chipmunk.h"
+
+cpVect
+cpBBClampVect(const cpBB bb, const cpVect v)
+{
+ cpFloat x = cpfmin(cpfmax(bb.l, v.x), bb.r);
+ cpFloat y = cpfmin(cpfmax(bb.b, v.y), bb.t);
+ return cpv(x, y);
+}
+
+cpVect
+cpBBWrapVect(const cpBB bb, const cpVect v)
+{
+ cpFloat ix = fabsf(bb.r - bb.l);
+ cpFloat modx = fmodf(v.x - bb.l, ix);
+ cpFloat x = (modx > 0.0f) ? modx : modx + ix;
+
+ cpFloat iy = fabsf(bb.t - bb.b);
+ cpFloat mody = fmodf(v.y - bb.b, iy);
+ cpFloat y = (mody > 0.0f) ? mody : mody + iy;
+
+ return cpv(x + bb.l, y + bb.b);
+}
diff --git a/fusion/plugins/newton/cpBB.h b/fusion/plugins/newton/cpBB.h
new file mode 100644
index 0000000..9ddaf48
--- /dev/null
+++ b/fusion/plugins/newton/cpBB.h
@@ -0,0 +1,53 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+typedef struct cpBB{
+ cpFloat l, b, r ,t;
+} cpBB;
+
+static inline cpBB
+cpBBNew(const cpFloat l, const cpFloat b,
+ const cpFloat r, const cpFloat t)
+{
+ cpBB bb = {l, b, r, t};
+ return bb;
+}
+
+static inline int
+cpBBintersects(const cpBB a, const cpBB b)
+{
+ return (a.l<=b.r && b.l<=a.r && a.b<=b.t && b.b<=a.t);
+}
+
+static inline int
+cpBBcontainsBB(const cpBB bb, const cpBB other)
+{
+ return (bb.l < other.l && bb.r > other.r && bb.b < other.b && bb.t > other.t);
+}
+
+static inline int
+cpBBcontainsVect(const cpBB bb, const cpVect v)
+{
+ return (bb.l < v.x && bb.r > v.x && bb.b < v.y && bb.t > v.y);
+}
+
+cpVect cpBBClampVect(const cpBB bb, const cpVect v); // clamps the vector to lie within the bbox
+cpVect cpBBWrapVect(const cpBB bb, const cpVect v); // wrap a vector to a bbox
diff --git a/fusion/plugins/newton/cpBody.c b/fusion/plugins/newton/cpBody.c
new file mode 100644
index 0000000..aed8c19
--- /dev/null
+++ b/fusion/plugins/newton/cpBody.c
@@ -0,0 +1,180 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <float.h>
+
+#include "chipmunk.h"
+
+cpBody*
+cpBodyAlloc(void)
+{
+ return (cpBody *)malloc(sizeof(cpBody));
+}
+
+cpBody*
+cpBodyInit(cpBody *body, cpFloat m, cpFloat i)
+{
+ body->velocity_func = cpBodyUpdateVelocity;
+ body->position_func = cpBodyUpdatePosition;
+
+ cpBodySetMass(body, m);
+ cpBodySetMoment(body, i);
+
+ body->p = cpvzero;
+ body->v = cpvzero;
+ body->f = cpvzero;
+
+ cpBodySetAngle(body, 0.0f);
+ body->w = 0.0f;
+ body->t = 0.0f;
+
+ body->v_bias = cpvzero;
+ body->w_bias = 0.0f;
+
+ body->data = NULL;
+// body->active = 1;
+
+ return body;
+}
+
+cpBody*
+cpBodyNew(cpFloat m, cpFloat i)
+{
+ return cpBodyInit(cpBodyAlloc(), m, i);
+}
+
+void cpBodyDestroy(cpBody *body){}
+
+void
+cpBodyFree(cpBody *body)
+{
+ if(body) cpBodyDestroy(body);
+ free(body);
+}
+
+void
+cpBodySetMass(cpBody *body, cpFloat m)
+{
+ body->m = m;
+ body->m_inv = 1.0f/m;
+}
+
+void
+cpBodySetMoment(cpBody *body, cpFloat i)
+{
+ body->i = i;
+ body->i_inv = 1.0f/i;
+}
+
+void
+cpBodySetAngle(cpBody *body, cpFloat a)
+{
+ body->a = fmod(a, (cpFloat)M_PI*2.0f);
+ body->rot = cpvforangle(a);
+}
+
+void
+cpBodySlew(cpBody *body, cpVect pos, cpFloat dt)
+{
+ cpVect delta = cpvsub(pos, body->p);
+ body->v = cpvmult(delta, 1.0/dt);
+}
+
+void
+cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
+{
+ body->v = cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt));
+ body->w = body->w*damping + body->t*body->i_inv*dt;
+}
+
+void
+cpBodyUpdatePosition(cpBody *body, cpFloat dt)
+{
+ body->p = cpvadd(body->p, cpvmult(cpvadd(body->v, body->v_bias), dt));
+ cpBodySetAngle(body, body->a + (body->w + body->w_bias)*dt);
+
+ body->v_bias = cpvzero;
+ body->w_bias = 0.0f;
+}
+
+void
+cpBodyResetForces(cpBody *body)
+{
+ body->f = cpvzero;
+ body->t = 0.0f;
+}
+
+void
+cpBodyApplyForce(cpBody *body, cpVect f, cpVect r)
+{
+ body->f = cpvadd(body->f, f);
+ body->t += cpvcross(r, f);
+}
+
+void
+cpDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt)
+{
+ // Calculate the world space anchor coordinates.
+ cpVect r1 = cpvrotate(anchr1, a->rot);
+ cpVect r2 = cpvrotate(anchr2, b->rot);
+
+ cpVect delta = cpvsub(cpvadd(b->p, r2), cpvadd(a->p, r1));
+ cpFloat dist = cpvlength(delta);
+ cpVect n = dist ? cpvmult(delta, 1.0f/dist) : cpvzero;
+
+ cpFloat f_spring = (dist - rlen)*k;
+
+ // Calculate the world relative velocities of the anchor points.
+ cpVect v1 = cpvadd(a->v, cpvmult(cpvperp(r1), a->w));
+ cpVect v2 = cpvadd(b->v, cpvmult(cpvperp(r2), b->w));
+
+ // Calculate the damping force.
+ // This really should be in the impulse solver and can produce problems when using large damping values.
+ cpFloat vrn = cpvdot(cpvsub(v2, v1), n);
+ cpFloat f_damp = vrn*cpfmin(dmp, 1.0f/(dt*(a->m_inv + b->m_inv)));
+
+ // Apply!
+ cpVect f = cpvmult(n, f_spring + f_damp);
+ cpBodyApplyForce(a, f, r1);
+ cpBodyApplyForce(b, cpvneg(f), r2);
+}
+
+//int
+//cpBodyMarkLowEnergy(cpBody *body, cpFloat dvsq, int max)
+//{
+// cpFloat ke = body->m*cpvdot(body->v, body->v);
+// cpFloat re = body->i*body->w*body->w;
+//
+// if(ke + re > body->m*dvsq)
+// body->active = 1;
+// else if(body->active)
+// body->active = (body->active + 1)%(max + 1);
+// else {
+// body->v = cpvzero;
+// body->v_bias = cpvzero;
+// body->w = 0.0f;
+// body->w_bias = 0.0f;
+// }
+//
+// return body->active;
+//}
diff --git a/fusion/plugins/newton/cpBody.h b/fusion/plugins/newton/cpBody.h
new file mode 100644
index 0000000..14d9599
--- /dev/null
+++ b/fusion/plugins/newton/cpBody.h
@@ -0,0 +1,110 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+struct cpBody;
+typedef void (*cpBodyVelocityFunc)(struct cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);
+typedef void (*cpBodyPositionFunc)(struct cpBody *body, cpFloat dt);
+
+
+typedef struct cpBody{
+ // Function that is called to integrate the body's velocity. (Defaults to cpBodyUpdateVelocity)
+ cpBodyVelocityFunc velocity_func;
+
+ // Function that is called to integrate the body's position. (Defaults to cpBodyUpdatePosition)
+ cpBodyPositionFunc position_func;
+
+ // Mass and it's inverse.
+ cpFloat m, m_inv;
+ // Moment of inertia and it's inverse.
+ cpFloat i, i_inv;
+
+ // NOTE: v_bias and w_bias are used internally for penetration/joint correction.
+ // Linear components of motion (position, velocity, and force)
+ cpVect p, v, f, v_bias;
+ // Angular components of motion (angle, angular velocity, and torque)
+ cpFloat a, w, t, w_bias;
+ // Unit length
+ cpVect rot;
+
+ // User defined data pointer.
+ void *data;
+// int active;
+} cpBody;
+
+// Basic allocation/destruction functions
+cpBody *cpBodyAlloc(void);
+cpBody *cpBodyInit(cpBody *body, cpFloat m, cpFloat i);
+cpBody *cpBodyNew(cpFloat m, cpFloat i);
+
+void cpBodyDestroy(cpBody *body);
+void cpBodyFree(cpBody *body);
+
+// Setters for some of the special properties (mandatory!)
+void cpBodySetMass(cpBody *body, cpFloat m);
+void cpBodySetMoment(cpBody *body, cpFloat i);
+void cpBodySetAngle(cpBody *body, cpFloat a);
+
+// Modify the velocity of an object so that it will
+void cpBodySlew(cpBody *body, cpVect pos, cpFloat dt);
+
+// Integration functions.
+void cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);
+void cpBodyUpdatePosition(cpBody *body, cpFloat dt);
+
+// Convert body local to world coordinates
+static inline cpVect
+cpBodyLocal2World(cpBody *body, cpVect v)
+{
+ return cpvadd(body->p, cpvrotate(v, body->rot));
+}
+
+// Convert world to body local coordinates
+static inline cpVect
+cpBodyWorld2Local(cpBody *body, cpVect v)
+{
+ return cpvunrotate(cpvsub(v, body->p), body->rot);
+}
+
+// Apply an impulse (in world coordinates) to the body.
+static inline void
+cpBodyApplyImpulse(cpBody *body, cpVect j, cpVect r)
+{
+ body->v = cpvadd(body->v, cpvmult(j, body->m_inv));
+ body->w += body->i_inv*cpvcross(r, j);
+}
+
+// Not intended for external use. Used by cpArbiter.c and cpJoint.c.
+static inline void
+cpBodyApplyBiasImpulse(cpBody *body, cpVect j, cpVect r)
+{
+ body->v_bias = cpvadd(body->v_bias, cpvmult(j, body->m_inv));
+ body->w_bias += body->i_inv*cpvcross(r, j);
+}
+
+// Zero the forces on a body.
+void cpBodyResetForces(cpBody *body);
+// Apply a force (in world coordinates) to a body.
+void cpBodyApplyForce(cpBody *body, cpVect f, cpVect r);
+
+// Apply a damped spring force between two bodies.
+void cpDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt);
+
+//int cpBodyMarkLowEnergy(cpBody *body, cpFloat dvsq, int max);
diff --git a/fusion/plugins/newton/cpCollision.c b/fusion/plugins/newton/cpCollision.c
new file mode 100644
index 0000000..7697237
--- /dev/null
+++ b/fusion/plugins/newton/cpCollision.c
@@ -0,0 +1,372 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "chipmunk.h"
+
+typedef int (*collisionFunc)(cpShape*, cpShape*, cpContact**);
+
+static collisionFunc *colfuncs = NULL;
+
+// Add contact points for circle to circle collisions.
+// Used by several collision tests.
+static int
+circle2circleQuery(cpVect p1, cpVect p2, cpFloat r1, cpFloat r2, cpContact **con)
+{
+ cpFloat mindist = r1 + r2;
+ cpVect delta = cpvsub(p2, p1);
+ cpFloat distsq = cpvlengthsq(delta);
+ if(distsq >= mindist*mindist) return 0;
+
+ cpFloat dist = sqrtf(distsq);
+ // To avoid singularities, do nothing in the case of dist = 0.
+ cpFloat non_zero_dist = (dist ? dist : INFINITY);
+
+ // Allocate and initialize the contact.
+ (*con) = (cpContact *)malloc(sizeof(cpContact));
+ cpContactInit(
+ (*con),
+ cpvadd(p1, cpvmult(delta, 0.5 + (r1 - 0.5*mindist)/non_zero_dist)),
+ cpvmult(delta, 1.0/non_zero_dist),
+ dist - mindist,
+ 0
+ );
+
+ return 1;
+}
+
+// Collide circle shapes.
+static int
+circle2circle(cpShape *shape1, cpShape *shape2, cpContact **arr)
+{
+ cpCircleShape *circ1 = (cpCircleShape *)shape1;
+ cpCircleShape *circ2 = (cpCircleShape *)shape2;
+
+ return circle2circleQuery(circ1->tc, circ2->tc, circ1->r, circ2->r, arr);
+}
+
+// Collide circles to segment shapes.
+static int
+circle2segment(cpShape *circleShape, cpShape *segmentShape, cpContact **con)
+{
+ cpCircleShape *circ = (cpCircleShape *)circleShape;
+ cpSegmentShape *seg = (cpSegmentShape *)segmentShape;
+
+ // Radius sum
+ cpFloat rsum = circ->r + seg->r;
+
+ // Calculate normal distance from segment.
+ cpFloat dn = cpvdot(seg->tn, circ->tc) - cpvdot(seg->ta, seg->tn);
+ cpFloat dist = fabs(dn) - rsum;
+ if(dist > 0.0f) return 0;
+
+ // Calculate tangential distance along segment.
+ cpFloat dt = -cpvcross(seg->tn, circ->tc);
+ cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
+ cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
+
+ // Decision tree to decide which feature of the segment to collide with.
+ if(dt < dtMin){
+ if(dt < (dtMin - rsum)){
+ return 0;
+ } else {
+ return circle2circleQuery(circ->tc, seg->ta, circ->r, seg->r, con);
+ }
+ } else {
+ if(dt < dtMax){
+ cpVect n = (dn < 0.0f) ? seg->tn : cpvneg(seg->tn);
+ (*con) = (cpContact *)malloc(sizeof(cpContact));
+ cpContactInit(
+ (*con),
+ cpvadd(circ->tc, cpvmult(n, circ->r + dist*0.5f)),
+ n,
+ dist,
+ 0
+ );
+ return 1;
+ } else {
+ if(dt < (dtMax + rsum)) {
+ return circle2circleQuery(circ->tc, seg->tb, circ->r, seg->r, con);
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+// Helper function for allocating contact point lists.
+static cpContact *
+addContactPoint(cpContact **arr, int *max, int *num)
+{
+ if(*arr == NULL){
+ // Allocate the array if it hasn't been done.
+ (*max) = 2;
+ (*num) = 0;
+ (*arr) = (cpContact *)malloc((*max)*sizeof(cpContact));
+ } else if(*num == *max){
+ // Extend it if necessary.
+ (*max) *= 2;
+ (*arr) = (cpContact *)realloc(*arr, (*max)*sizeof(cpContact));
+ }
+
+ cpContact *con = &(*arr)[*num];
+ (*num)++;
+
+ return con;
+}
+
+// Find the minimum separating axis for the give poly and axis list.
+static inline int
+findMSA(cpPolyShape *poly, cpPolyShapeAxis *axes, int num, cpFloat *min_out)
+{
+ int min_index = 0;
+ cpFloat min = cpPolyShapeValueOnAxis(poly, axes->n, axes->d);
+ if(min > 0.0) return -1;
+
+ for(int i=1; i<num; i++){
+ cpFloat dist = cpPolyShapeValueOnAxis(poly, axes[i].n, axes[i].d);
+ if(dist > 0.0) {
+ return -1;
+ } else if(dist > min){
+ min = dist;
+ min_index = i;
+ }
+ }
+
+ (*min_out) = min;
+ return min_index;
+}
+
+// Add contacts for penetrating vertexes.
+static inline int
+findVerts(cpContact **arr, cpPolyShape *poly1, cpPolyShape *poly2, cpVect n, cpFloat dist)
+{
+ int max = 0;
+ int num = 0;
+
+ for(int i=0; i<poly1->numVerts; i++){
+ cpVect v = poly1->tVerts[i];
+ if(cpPolyShapeContainsVert(poly2, v))
+ cpContactInit(addContactPoint(arr, &max, &num), v, n, dist, CP_HASH_PAIR(poly1, i));
+ }
+
+ for(int i=0; i<poly2->numVerts; i++){
+ cpVect v = poly2->tVerts[i];
+ if(cpPolyShapeContainsVert(poly1, v))
+ cpContactInit(addContactPoint(arr, &max, &num), v, n, dist, CP_HASH_PAIR(poly2, i));
+ }
+
+ // if(!num)
+ // addContactPoint(arr, &size, &num, cpContactNew(shape1->body->p, n, dist, 0));
+
+ return num;
+}
+
+// Collide poly shapes together.
+static int
+poly2poly(cpShape *shape1, cpShape *shape2, cpContact **arr)
+{
+ cpPolyShape *poly1 = (cpPolyShape *)shape1;
+ cpPolyShape *poly2 = (cpPolyShape *)shape2;
+
+ cpFloat min1;
+ int mini1 = findMSA(poly2, poly1->tAxes, poly1->numVerts, &min1);
+ if(mini1 == -1) return 0;
+
+ cpFloat min2;
+ int mini2 = findMSA(poly1, poly2->tAxes, poly2->numVerts, &min2);
+ if(mini2 == -1) return 0;
+
+ // There is overlap, find the penetrating verts
+ if(min1 > min2)
+ return findVerts(arr, poly1, poly2, poly1->tAxes[mini1].n, min1);
+ else
+ return findVerts(arr, poly1, poly2, cpvneg(poly2->tAxes[mini2].n), min2);
+}
+
+// Like cpPolyValueOnAxis(), but for segments.
+static inline float
+segValueOnAxis(cpSegmentShape *seg, cpVect n, cpFloat d)
+{
+ cpFloat a = cpvdot(n, seg->ta) - seg->r;
+ cpFloat b = cpvdot(n, seg->tb) - seg->r;
+ return cpfmin(a, b) - d;
+}
+
+// Identify vertexes that have penetrated the segment.
+static inline void
+findPointsBehindSeg(cpContact **arr, int *max, int *num, cpSegmentShape *seg, cpPolyShape *poly, cpFloat pDist, cpFloat coef)
+{
+ cpFloat dta = cpvcross(seg->tn, seg->ta);
+ cpFloat dtb = cpvcross(seg->tn, seg->tb);
+ cpVect n = cpvmult(seg->tn, coef);
+
+ for(int i=0; i<poly->numVerts; i++){
+ cpVect v = poly->tVerts[i];
+ if(cpvdot(v, n) < cpvdot(seg->tn, seg->ta)*coef + seg->r){
+ cpFloat dt = cpvcross(seg->tn, v);
+ if(dta >= dt && dt >= dtb){
+ cpContactInit(addContactPoint(arr, max, num), v, n, pDist, CP_HASH_PAIR(poly, i));
+ }
+ }
+ }
+}
+
+// This one is complicated and gross. Just don't go there...
+// TODO: Comment me!
+static int
+seg2poly(cpShape *shape1, cpShape *shape2, cpContact **arr)
+{
+ cpSegmentShape *seg = (cpSegmentShape *)shape1;
+ cpPolyShape *poly = (cpPolyShape *)shape2;
+ cpPolyShapeAxis *axes = poly->tAxes;
+
+ cpFloat segD = cpvdot(seg->tn, seg->ta);
+ cpFloat minNorm = cpPolyShapeValueOnAxis(poly, seg->tn, segD) - seg->r;
+ cpFloat minNeg = cpPolyShapeValueOnAxis(poly, cpvneg(seg->tn), -segD) - seg->r;
+ if(minNeg > 0.0f || minNorm > 0.0f) return 0;
+
+ int mini = 0;
+ cpFloat poly_min = segValueOnAxis(seg, axes->n, axes->d);
+ if(poly_min > 0.0f) return 0;
+ for(int i=0; i<poly->numVerts; i++){
+ cpFloat dist = segValueOnAxis(seg, axes[i].n, axes[i].d);
+ if(dist > 0.0f){
+ return 0;
+ } else if(dist > poly_min){
+ poly_min = dist;
+ mini = i;
+ }
+ }
+
+ int max = 0;
+ int num = 0;
+
+ cpVect poly_n = cpvneg(axes[mini].n);
+
+ cpVect va = cpvadd(seg->ta, cpvmult(poly_n, seg->r));
+ cpVect vb = cpvadd(seg->tb, cpvmult(poly_n, seg->r));
+ if(cpPolyShapeContainsVert(poly, va))
+ cpContactInit(addContactPoint(arr, &max, &num), va, poly_n, poly_min, CP_HASH_PAIR(seg, 0));
+ if(cpPolyShapeContainsVert(poly, vb))
+ cpContactInit(addContactPoint(arr, &max, &num), vb, poly_n, poly_min, CP_HASH_PAIR(seg, 1));
+
+ // Floating point precision problems here.
+ // This will have to do for now.
+ poly_min -= cp_collision_slop;
+ if(minNorm >= poly_min || minNeg >= poly_min) {
+ if(minNorm > minNeg)
+ findPointsBehindSeg(arr, &max, &num, seg, poly, minNorm, 1.0f);
+ else
+ findPointsBehindSeg(arr, &max, &num, seg, poly, minNeg, -1.0f);
+ }
+
+ return num;
+}
+
+// This one is less gross, but still gross.
+// TODO: Comment me!
+static int
+circle2poly(cpShape *shape1, cpShape *shape2, cpContact **con)
+{
+ cpCircleShape *circ = (cpCircleShape *)shape1;
+ cpPolyShape *poly = (cpPolyShape *)shape2;
+ cpPolyShapeAxis *axes = poly->tAxes;
+
+ int mini = 0;
+ cpFloat min = cpvdot(axes->n, circ->tc) - axes->d - circ->r;
+ for(int i=0; i<poly->numVerts; i++){
+ cpFloat dist = cpvdot(axes[i].n, circ->tc) - axes[i].d - circ->r;
+ if(dist > 0.0){
+ return 0;
+ } else if(dist > min) {
+ min = dist;
+ mini = i;
+ }
+ }
+
+ cpVect n = axes[mini].n;
+ cpVect a = poly->tVerts[mini];
+ cpVect b = poly->tVerts[(mini + 1)%poly->numVerts];
+ cpFloat dta = cpvcross(n, a);
+ cpFloat dtb = cpvcross(n, b);
+ cpFloat dt = cpvcross(n, circ->tc);
+
+ if(dt < dtb){
+ return circle2circleQuery(circ->tc, b, circ->r, 0.0f, con);
+ } else if(dt < dta) {
+ (*con) = (cpContact *)malloc(sizeof(cpContact));
+ cpContactInit(
+ (*con),
+ cpvsub(circ->tc, cpvmult(n, circ->r + min/2.0f)),
+ cpvneg(n),
+ min,
+ 0
+ );
+
+ return 1;
+ } else {
+ return circle2circleQuery(circ->tc, a, circ->r, 0.0f, con);
+ }
+}
+
+static void
+addColFunc(cpShapeType a, cpShapeType b, collisionFunc func)
+{
+ colfuncs[a + b*CP_NUM_SHAPES] = func;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ // Initializes the array of collision functions.
+ // Called by cpInitChipmunk().
+ void
+ cpInitCollisionFuncs(void)
+ {
+ if(!colfuncs)
+ colfuncs = (collisionFunc *)calloc(CP_NUM_SHAPES*CP_NUM_SHAPES, sizeof(collisionFunc));
+
+ addColFunc(CP_CIRCLE_SHAPE, CP_CIRCLE_SHAPE, circle2circle);
+ addColFunc(CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, circle2segment);
+ addColFunc(CP_SEGMENT_SHAPE, CP_POLY_SHAPE, seg2poly);
+ addColFunc(CP_CIRCLE_SHAPE, CP_POLY_SHAPE, circle2poly);
+ addColFunc(CP_POLY_SHAPE, CP_POLY_SHAPE, poly2poly);
+ }
+#ifdef __cplusplus
+}
+#endif
+
+int
+cpCollideShapes(cpShape *a, cpShape *b, cpContact **arr)
+{
+ // Their shape types must be in order.
+ assert(a->klass->type <= b->klass->type);
+
+ collisionFunc cfunc = colfuncs[a->klass->type + b->klass->type*CP_NUM_SHAPES];
+ return (cfunc) ? cfunc(a, b, arr) : 0;
+}
diff --git a/fusion/plugins/newton/cpCollision.h b/fusion/plugins/newton/cpCollision.h
new file mode 100644
index 0000000..e87a6db
--- /dev/null
+++ b/fusion/plugins/newton/cpCollision.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+// Collides two cpShape structures. (this function is lonely :( )
+int cpCollideShapes(cpShape *a, cpShape *b, cpContact **arr);
diff --git a/fusion/plugins/newton/cpHashSet.c b/fusion/plugins/newton/cpHashSet.c
new file mode 100644
index 0000000..ae95ea4
--- /dev/null
+++ b/fusion/plugins/newton/cpHashSet.c
@@ -0,0 +1,219 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "chipmunk.h"
+#include "prime.h"
+
+void
+cpHashSetDestroy(cpHashSet *set)
+{
+ // Free the chains.
+ for(int i=0; i<set->size; i++){
+ // Free the bins in the chain.
+ cpHashSetBin *bin = set->table[i];
+ while(bin){
+ cpHashSetBin *next = bin->next;
+ free(bin);
+ bin = next;
+ }
+ }
+
+ // Free the table.
+ free(set->table);
+}
+
+void
+cpHashSetFree(cpHashSet *set)
+{
+ if(set) cpHashSetDestroy(set);
+ free(set);
+}
+
+cpHashSet *
+cpHashSetAlloc(void)
+{
+ return (cpHashSet *)calloc(1, sizeof(cpHashSet));
+}
+
+cpHashSet *
+cpHashSetInit(cpHashSet *set, int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans)
+{
+ set->size = next_prime(size);
+ set->entries = 0;
+
+ set->eql = eqlFunc;
+ set->trans = trans;
+
+ set->default_value = NULL;
+
+ set->table = (cpHashSetBin **)calloc(set->size, sizeof(cpHashSetBin *));
+
+ return set;
+}
+
+cpHashSet *
+cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans)
+{
+ return cpHashSetInit(cpHashSetAlloc(), size, eqlFunc, trans);
+}
+
+static int
+setIsFull(cpHashSet *set)
+{
+ return (set->entries >= set->size);
+}
+
+static void
+cpHashSetResize(cpHashSet *set)
+{
+ // Get the next approximate doubled prime.
+ int newSize = next_prime(set->size + 1);
+ // Allocate a new table.
+ cpHashSetBin **newTable = (cpHashSetBin **)calloc(newSize, sizeof(cpHashSetBin *));
+
+ // Iterate over the chains.
+ for(int i=0; i<set->size; i++){
+ // Rehash the bins into the new table.
+ cpHashSetBin *bin = set->table[i];
+ while(bin){
+ cpHashSetBin *next = bin->next;
+
+ int index = bin->hash%newSize;
+ bin->next = newTable[index];
+ newTable[index] = bin;
+
+ bin = next;
+ }
+ }
+
+ free(set->table);
+
+ set->table = newTable;
+ set->size = newSize;
+}
+
+void *
+cpHashSetInsert(cpHashSet *set, unsigned int hash, void *ptr, void *data)
+{
+ int index = hash%set->size;
+
+ // Find the bin with the matching element.
+ cpHashSetBin *bin = set->table[index];
+ while(bin && !set->eql(ptr, bin->elt))
+ bin = bin->next;
+
+ // Create it necessary.
+ if(!bin){
+ bin = (cpHashSetBin *)malloc(sizeof(cpHashSetBin));
+ bin->hash = hash;
+ bin->elt = set->trans(ptr, data); // Transform the pointer.
+
+ bin->next = set->table[index];
+ set->table[index] = bin;
+
+ set->entries++;
+
+ // Resize the set if it's full.
+ if(setIsFull(set))
+ cpHashSetResize(set);
+ }
+
+ return bin->elt;
+}
+
+void *
+cpHashSetRemove(cpHashSet *set, unsigned int hash, void *ptr)
+{
+ int index = hash%set->size;
+
+ // Pointer to the previous bin pointer.
+ cpHashSetBin **prev_ptr = &set->table[index];
+ // Pointer the the current bin.
+ cpHashSetBin *bin = set->table[index];
+
+ // Find the bin
+ while(bin && !set->eql(ptr, bin->elt)){
+ prev_ptr = &bin->next;
+ bin = bin->next;
+ }
+
+ // Remove it if it exists.
+ if(bin){
+ // Update the previos bin pointer to point to the next bin.
+ (*prev_ptr) = bin->next;
+ set->entries--;
+
+ void *return_value = bin->elt;
+ free(bin);
+ return return_value;
+ }
+
+ return NULL;
+}
+
+void *
+cpHashSetFind(cpHashSet *set, unsigned int hash, void *ptr)
+{
+ int index = hash%set->size;
+ cpHashSetBin *bin = set->table[index];
+ while(bin && !set->eql(ptr, bin->elt))
+ bin = bin->next;
+
+ return (bin ? bin->elt : set->default_value);
+}
+
+void
+cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data)
+{
+ for(int i=0; i<set->size; i++){
+ cpHashSetBin *bin;
+ for(bin = set->table[i]; bin; bin = bin->next)
+ func(bin->elt, data);
+ }
+}
+
+void
+cpHashSetReject(cpHashSet *set, cpHashSetRejectFunc func, void *data)
+{
+ // Iterate over all the chains.
+ for(int i=0; i<set->size; i++){
+ // The rest works similarly to cpHashSetRemove() above.
+ cpHashSetBin **prev_ptr = &set->table[i];
+ cpHashSetBin *bin = set->table[i];
+ while(bin){
+ cpHashSetBin *next = bin->next;
+
+ if(func(bin->elt, data)){
+ prev_ptr = &bin->next;
+ } else {
+ (*prev_ptr) = next;
+
+ set->entries--;
+ free(bin);
+ }
+
+ bin = next;
+ }
+ }
+}
diff --git a/fusion/plugins/newton/cpHashSet.h b/fusion/plugins/newton/cpHashSet.h
new file mode 100644
index 0000000..edd453c
--- /dev/null
+++ b/fusion/plugins/newton/cpHashSet.h
@@ -0,0 +1,79 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+// cpHashSet uses a chained hashtable implementation.
+// Other than the transformation functions, there is nothing fancy going on.
+
+// cpHashSetBin's form the linked lists in the chained hash table.
+typedef struct cpHashSetBin {
+ // Pointer to the element.
+ void *elt;
+ // Hash value of the element.
+ unsigned int hash;
+ // Next element in the chain.
+ struct cpHashSetBin *next;
+} cpHashSetBin;
+
+// Equality function. Returns true if ptr is equal to elt.
+typedef int (*cpHashSetEqlFunc)(void *ptr, void *elt);
+// Used by cpHashSetInsert(). Called to transform the ptr into an element.
+typedef void *(*cpHashSetTransFunc)(void *ptr, void *data);
+// Iterator function for a hashset.
+typedef void (*cpHashSetIterFunc)(void *elt, void *data);
+// Reject function. Returns true if elt should be dropped.
+typedef int (*cpHashSetRejectFunc)(void *elt, void *data);
+
+typedef struct cpHashSet {
+ // Number of elements stored in the table.
+ int entries;
+ // Number of cells in the table.
+ int size;
+
+ cpHashSetEqlFunc eql;
+ cpHashSetTransFunc trans;
+
+ // Default value returned by cpHashSetFind() when no element is found.
+ // Defaults to NULL.
+ void *default_value;
+
+ cpHashSetBin **table;
+} cpHashSet;
+
+// Basic allocation/destruction functions.
+void cpHashSetDestroy(cpHashSet *set);
+void cpHashSetFree(cpHashSet *set);
+
+cpHashSet *cpHashSetAlloc(void);
+cpHashSet *cpHashSetInit(cpHashSet *set, int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans);
+cpHashSet *cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans);
+
+// Insert an element into the set, returns the element.
+// If it doesn't already exist, the transformation function is applied.
+void *cpHashSetInsert(cpHashSet *set, unsigned int hash, void *ptr, void *data);
+// Remove and return an element from the set.
+void *cpHashSetRemove(cpHashSet *set, unsigned int hash, void *ptr);
+// Find an element in the set. Returns the default value if the element isn't found.
+void *cpHashSetFind(cpHashSet *set, unsigned int hash, void *ptr);
+
+// Iterate over a hashset.
+void cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data);
+// Iterate over a hashset while rejecting certain elements.
+void cpHashSetReject(cpHashSet *set, cpHashSetRejectFunc func, void *data);
diff --git a/fusion/plugins/newton/cpJoint.c b/fusion/plugins/newton/cpJoint.c
new file mode 100644
index 0000000..94db41e
--- /dev/null
+++ b/fusion/plugins/newton/cpJoint.c
@@ -0,0 +1,553 @@
+/* Copyright (c) 2007 Scott Lembcke
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* 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
+* AUTHORS OR COPYRIGHT HOLDERS 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.
+*/
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "chipmunk.h"
+
+// TODO: Comment me!
+
+cpFloat cp_joint_bias_coef = 0.1f;
+
+void cpJointDestroy(cpJoint *joint){}
+
+void
+cpJointFree(cpJoint *joint)
+{
+ if(joint) cpJointDestroy(joint);
+ free(joint);
+}
+
+static void
+cpJointInit(cpJoint *joint, const cpJointClass *klass, cpBody *a, cpBody *b)
+{
+ joint->klass = klass;
+ joint->a = a;
+ joint->b = b;
+}
+
+
+static inline cpVect
+relative_velocity(cpVect r1, cpVect v1, cpFloat w1, cpVect r2, cpVect v2, cpFloat w2){
+ cpVect v1_sum = cpvadd(v1, cpvmult(cpvperp(r1), w1));
+ cpVect v2_sum = cpvadd(v2, cpvmult(cpvperp(r2), w2));
+
+ return cpvsub(v2_sum, v1_sum);
+}
+
+static inline cpFloat
+scalar_k(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n)
+{
+ cpFloat mass_sum = a->m_inv + b->m_inv;
+ cpFloat r1cn = cpvcross(r1, n);
+ cpFloat r2cn = cpvcross(r2, n);
+
+ return mass_sum + a->i_inv*r1cn*r1cn + b->i_inv*r2cn*r2cn;
+}
+
+static inline void
+apply_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)
+{
+ cpBodyApplyImpulse(a, cpvneg(j), r1);
+ cpBodyApplyImpulse(b, j, r2);
+}
+
+static inline void
+apply_bias_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)
+{
+ cpBodyApplyBiasImpulse(a, cpvneg(j), r1);
+ cpBodyApplyBiasImpulse(b, j, r2);
+}
+
+
+static void
+pinJointPreStep(cpJoint *joint, cpFloat dt_inv)
+{
+ cpBody *a = joint->a;
+ cpBody *b = joint->b;
+ cpPinJoint *jnt = (cpPinJoint *)joint;
+
+ jnt->r1 = cpvrotate(jnt->anchr1, a->rot);
+ jnt->r2 = cpvrotate(jnt->anchr2, b->rot);
+
+ cpVect delta = cpvsub(cpvadd(b->p, jnt->r2), cpvadd(a->p, jnt->r1));
+ cpFloat dist = cpvlength(delta);
+ jnt->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));
+
+ // calculate mass normal
+ jnt->nMass = 1.0f/scalar_k(a, b, jnt->r1, jnt->r2, jnt->n);
+
+ // calculate bias velocity
+ jnt->bias = -cp_joint_bias_coef*dt_inv*(dist - jnt->dist);
+ jnt->jBias = 0.0f;
+
+ // apply accumulated impulse
+ cpVect j = cpvmult(jnt->n, jnt->jnAcc);
+ apply_impulses(a, b, jnt->r1, jnt->r2, j);
+}
+
+static void
+pinJointApplyImpulse(cpJoint *joint)
+{
+ cpBody *a = joint->a;
+ cpBody *b = joint->b;
+
+ cpPinJoint *jnt = (cpPinJoint *)joint;
+ cpVect n = jnt->n;
+ cpVect r1 = jnt->r1;
+ cpVect r2 = jnt->r2;
+
+ //calculate bias impulse
+ cpVect vbr = relative_velocity(r1, a->v_bias, a->w_bias, r2, b->v_bias, b->w_bias);
+ cpFloat vbn = cpvdot(vbr, n);
+
+ cpFloat jbn = (jnt->bias - vbn)*jnt->nMass;
+ jnt->jBias += jbn;
+
+ cpVect jb = cpvmult(n, jbn);
+ apply_bias_impulses(a, b, jnt->r1, jnt->r2, jb);
+
+ // compute relative velocity
+ cpVect vr = relative_velocity(r1, a->v, a->w, r2, b->v, b->w);
+ cpFloat vrn = cpvdot(vr, n);
+
+ // compute normal impulse
+ cpFloat jn = -vrn*jnt->nMass;
+ jnt->jnAcc =+ jn;
+
+ // apply impulse
+ cpVect j = cpvmult(n, jn);
+ apply_impulses(a, b, jnt->r1, jnt->r2, j);
+}
+
+static const cpJointClass pinJointClass = {
+ CP_PIN_JOINT,
+ pinJointPreStep,
+ pinJointApplyImpulse,
+};
+
+cpPinJoint *
+cpPinJointAlloc(void)
+{
+ return (cpPinJoint *)malloc(sizeof(cpPinJoint));
+}
+
+cpPinJoint *
+cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
+{
+ cpJointInit((cpJoint *)joint, &pinJointClass, a, b);
+
+ joint->anchr1 = anchr1;
+ joint->anchr2 = anchr2;
+
+ cpVect p1 = cpvadd(a->p, cpvrotate(anchr1, a->rot));
+ cpVect p2 = cpvadd(b->p, cpvrotate(anchr2, b->rot));
+ joint->dist = cpvlength(cpvsub(p2, p1));
+
+ joint->jnAcc = 0.0;
+
+ return joint;
+}
+
+cpJoint *
+cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
+{
+ return (cpJoint *)cpPinJointInit(cpPinJointAlloc(), a, b, anchr1, anchr2);
+}
+
+
+
+
+static void
+slideJointPreStep(cpJoint *joint, cpFloat dt_inv)
+{
+ cpBody *a = joint->a;
+ cpBody *b = joint->b;
+ cpSlideJoint *jnt = (cpSlideJoint *)joint;
+
+ jnt->r1 = cpvrotate(jnt->anchr1, a->rot);
+ jnt->r2 = cpvrotate(jnt->anchr2, b->rot);
+
+ cpVect delta = cpvsub(cpvadd(b->p, jnt->r2), cpvadd(a->p, jnt->r1));
+ cpFloat dist = cpvlength(delta);
+ cpFloat pdist = 0.0;
+ if(dist > jnt->max) {
+ pdist = dist - jnt->max;
+ } else if(dist < jnt->min) {
+ pdist = jnt->min - dist;
+ dist = -dist;
+ }
+ jnt->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));
+
+ // calculate mass normal
+ jnt->nMass = 1.0f/scalar_k(a, b, jnt->r1, jnt->r2, jnt->n);
+
+ // calculate bias velocity
+ jnt->bias = -cp_joint_bias_coef*dt_inv*(pdist);
+ jnt->jBias = 0.0f;
+
+ // apply accumulated impulse
+ if(!jnt->bias) //{
+ // if bias is 0, then the joint is not at a limit.
+ jnt->jnAcc = 0.0f;
+// } else {
+ cpVect j = cpvmult(jnt->n, jnt->jnAcc);
+ apply_impulses(a, b, jnt->r1, jnt->r2, j);
+// }
+}
+
+static void
+slideJointApplyImpulse(cpJoint *joint)
+{
+ cpSlideJoint *jnt = (cpSlideJoint *)joint;
+ if(!jnt->bias) return; // early exit
+
+ cpBody *a = joint->a;
+ cpBody *b = joint->b;
+
+ cpVect n = jnt->n;
+ cpVect r1 = jnt->r1;
+ cpVect r2 = jnt->r2;
+
+ //calculate bias impulse
+ cpVect vbr = relative_velocity(r1, a->v_bias, a->w_bias, r2, b->v_bias, b->w_bias);
+ cpFloat vbn = cpvdot(vbr, n);
+
+ cpFloat jbn = (jnt->bias - vbn)*jnt->nMass;
+ cpFloat jbnOld = jnt->jBias;
+ jnt->jBias = cpfmin(jbnOld + jbn, 0.0f);
+ jbn = jnt->jBias - jbnOld;
+
+ cpVect jb = cpvmult(n, jbn);
+ apply_bias_impulses(a, b, jnt->r1, jnt->r2, jb);
+
+ // compute relative velocity
+ cpVect vr = relative_velocity(r1, a->v, a->w, r2, b->v, b->w);
+ cpFloat vrn = cpvdot(vr, n);
+
+ // compute normal impulse
+ cpFloat jn = -vrn*jnt->nMass;
+ cpFloat jnOld = jnt->jnAcc;
+ jnt->jnAcc = cpfmin(jnOld + jn, 0.0f);
+ jn = jnt->jnAcc - jnOld;
+
+ // apply impulse
+ cpVect j = cpvmult(n, jn);
+ apply_impulses(a, b, jnt->r1, jnt->r2, j);
+}
+
+static const cpJointClass slideJointClass = {
+ CP_SLIDE_JOINT,
+ slideJointPreStep,
+ slideJointApplyImpulse,
+};
+
+cpSlideJoint *
+cpSlideJointAlloc(void)
+{
+ return (cpSlideJoint *)malloc(sizeof(cpSlideJoint));
+}
+
+cpSlideJoint *
+cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)
+{
+ cpJointInit((cpJoint *)joint, &slideJointClass, a, b);
+
+ joint->anchr1 = anchr1;
+ joint->anchr2 = anchr2;
+ joint->min = min;
+ joint->max = max;
+
+ joint->jnAcc = 0.0;
+
+ return joint;
+}
+
+cpJoint *
+cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)
+{
+ return (cpJoint *)cpSlideJointInit(cpSlideJointAlloc(), a, b, anchr1, anchr2, min, max);
+}
+
+
+
+
+static void
+pivotJointPreStep(cpJoint *joint, cpFloat dt_inv)
+{
+ cpBody *a = joint->a;
+ cpBody *b = joint->b;
+ cpPivotJoint *jnt = (cpPivotJoint *)joint;
+
+ jnt->r1 = cpvrotate(jnt->anchr1, a->rot);
+ jnt->r2 = cpvrotate(jnt->anchr2, b->rot);
+
+ // calculate mass matrix
+ // If I wasn't lazy, this wouldn't be so gross...
+ cpFloat k11, k12, k21, k22;
+
+ cpFloat m_sum = a->m_inv + b->m_inv;
+ k11 = m_sum; k12 = 0.0f;
+ k21 = 0.0f; k22 = m_sum;
+
+ cpFloat r1xsq = jnt->r1.x * jnt->r1.x * a->i_inv;
+ cpFloat r1ysq = jnt->r1.y * jnt->r1.y * a->i_inv;
+ cpFloat r1nxy = -jnt->r1.x * jnt->r1.y * a->i_inv;
+ k11 += r1ysq; k12 += r1nxy;
+ k21 += r1nxy; k22 += r1xsq;
+
+ cpFloat r2xsq = jnt->r2.x * jnt->r2.x * b->i_inv;
+ cpFloat r2ysq = jnt->r2.y * jnt->r2.y * b->i_inv;
+ cpFloat r2nxy = -jnt->r2.x * jnt->r2.y * b->i_inv;
+ k11 += r2ysq; k12 += r2nxy;
+ k21 += r2nxy; k22 += r2xsq;
+
+ cpFloat det_inv = 1.0f/(k11*k22 - k12*k21);
+ jnt->k1 = cpv( k22*det_inv, -k12*det_inv);
+ jnt->k2 = cpv(-k21*det_inv, k11*det_inv);
+
+
+ // calculate bias velocity
+ cpVect delta = cpvsub(cpvadd(b->p, jnt->r2), cpvadd(a->p, jnt->r1));
+ jnt->bias = cpvmult(delta, -cp_joint_bias_coef*dt_inv);
+ jnt->jBias = cpvzero;
+
+ // apply accumulated impulse
+ apply_impulses(a, b, jnt->r1, jnt->r2, jnt->jAcc);
+}
+
+static void
+pivotJointApplyImpulse(cpJoint *joint)
+{
+ cpBody *a = joint->a;
+ cpBody *b = joint->b;
+
+ cpPivotJoint *jnt = (cpPivotJoint *)joint;
+ cpVect r1 = jnt->r1;
+ cpVect r2 = jnt->r2;
+ cpVect k1 = jnt->k1;
+ cpVect k2 = jnt->k2;
+
+ //calculate bias impulse
+ cpVect vbr = relative_velocity(r1, a->v_bias, a->w_bias, r2, b->v_bias, b->w_bias);
+ vbr = cpvsub(jnt->bias, vbr);
+
+ cpVect jb = cpv(cpvdot(vbr, k1), cpvdot(vbr, k2));
+ jnt->jBias = cpvadd(jnt->jBias, jb);
+
+ apply_bias_impulses(a, b, jnt->r1, jnt->r2, jb);
+
+ // compute relative velocity
+ cpVect vr = relative_velocity(r1, a->v, a->w, r2, b->v, b->w);
+
+ // compute normal impulse
+ cpVect j = cpv(-cpvdot(vr, k1), -cpvdot(vr, k2));
+ jnt->jAcc = cpvadd(jnt->jAcc, j);
+
+ // apply impulse
+ apply_impulses(a, b, jnt->r1, jnt->r2, j);
+}
+
+static const cpJointClass pivotJointClass = {
+ CP_PIVOT_JOINT,
+ pivotJointPreStep,
+ pivotJointApplyImpulse,
+};
+
+cpPivotJoint *
+cpPivotJointAlloc(void)
+{
+ return (cpPivotJoint *)malloc(sizeof(cpPivotJoint));
+}
+
+cpPivotJoint *
+cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect pivot)
+{
+ cpJointInit((cpJoint *)joint, &pivotJointClass, a, b);
+
+ joint->anchr1 = cpvunrotate(cpvsub(pivot, a->p), a->rot);
+ joint->anchr2 = cpvunrotate(cpvsub(pivot, b->p), b->rot);
+
+ joint->jAcc = cpvzero;
+
+ return joint;
+}
+
+cpJoint *
+cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot)
+{
+ return (cpJoint *)cpPivotJointInit(cpPivotJointAlloc(), a, b, pivot);
+}
+
+
+
+
+static void
+grooveJointPreStep(cpJoint *joint, cpFloat dt_inv)
+{
+ cpBody *a = joint->a;
+ cpBody *b = joint->b;
+ cpGrooveJoint *jnt = (cpGrooveJoint *)joint;
+
+ // calculate endpoints in worldspace
+ cpVect ta = cpBodyLocal2World(a, jnt->grv_a);
+ cpVect tb = cpBodyLocal2World(a, jnt->grv_b);
+
+ // calculate axis
+ cpVect n = cpvrotate(jnt->grv_n, a->rot);
+ cpFloat d = cpvdot(ta, n);
+
+ jnt->grv_tn = n;
+ jnt->r2 = cpvrotate(jnt->anchr2, b->rot);
+
+ // calculate tangential distance along the axis of r2
+ cpFloat td = cpvcross(cpvadd(b->p, jnt->r2), n);
+ // calculate clamping factor and r2
+ if(td <= cpvcross(ta, n)){
+ jnt->clamp = 1.0f;
+ jnt->r1 = cpvsub(ta, a->p);
+ } else if(td >= cpvcross(tb, n)){
+ jnt->clamp = -1.0f;
+ jnt->r1 = cpvsub(tb, a->p);
+ } else {
+ jnt->clamp = 0.0f;
+ jnt->r1 = cpvsub(cpvadd(cpvmult(cpvperp(n), -td), cpvmult(n, d)), a->p);
+ }
+
+ // calculate mass matrix
+ // If I wasn't lazy and wrote a proper matrix class, this wouldn't be so gross...
+ cpFloat k11, k12, k21, k22;
+ cpFloat m_sum = a->m_inv + b->m_inv;
+
+ // start with I*m_sum
+ k11 = m_sum; k12 = 0.0f;
+ k21 = 0.0f; k22 = m_sum;
+
+ // add the influence from r1
+ cpFloat r1xsq = jnt->r1.x * jnt->r1.x * a->i_inv;
+ cpFloat r1ysq = jnt->r1.y * jnt->r1.y * a->i_inv;
+ cpFloat r1nxy = -jnt->r1.x * jnt->r1.y * a->i_inv;
+ k11 += r1ysq; k12 += r1nxy;
+ k21 += r1nxy; k22 += r1xsq;
+
+ // add the influnce from r2
+ cpFloat r2xsq = jnt->r2.x * jnt->r2.x * b->i_inv;
+ cpFloat r2ysq = jnt->r2.y * jnt->r2.y * b->i_inv;
+ cpFloat r2nxy = -jnt->r2.x * jnt->r2.y * b->i_inv;
+ k11 += r2ysq; k12 += r2nxy;
+ k21 += r2nxy; k22 += r2xsq;
+
+ // invert
+ cpFloat det_inv = 1.0f/(k11*k22 - k12*k21);
+ jnt->k1 = cpv( k22*det_inv, -k12*det_inv);
+ jnt->k2 = cpv(-k21*det_inv, k11*det_inv);
+
+
+ // calculate bias velocity
+ cpVect delta = cpvsub(cpvadd(b->p, jnt->r2), cpvadd(a->p, jnt->r1));
+ jnt->bias = cpvmult(delta, -cp_joint_bias_coef*dt_inv);
+ jnt->jBias = cpvzero;
+
+ // apply accumulated impulse
+ apply_impulses(a, b, jnt->r1, jnt->r2, jnt->jAcc);
+}
+
+static inline cpVect
+grooveConstrain(cpGrooveJoint *jnt, cpVect j){
+ cpVect n = jnt->grv_tn;
+ cpVect jn = cpvmult(n, cpvdot(j, n));
+
+ cpVect t = cpvperp(n);
+ cpFloat coef = (jnt->clamp*cpvcross(j, n) > 0.0f) ? 1.0f : 0.0f;
+ cpVect jt = cpvmult(t, cpvdot(j, t)*coef);
+
+ return cpvadd(jn, jt);
+}
+
+static void
+grooveJointApplyImpulse(cpJoint *joint)
+{
+ cpBody *a = joint->a;
+ cpBody *b = joint->b;
+
+ cpGrooveJoint *jnt = (cpGrooveJoint *)joint;
+ cpVect r1 = jnt->r1;
+ cpVect r2 = jnt->r2;
+ cpVect k1 = jnt->k1;
+ cpVect k2 = jnt->k2;
+
+ //calculate bias impulse
+ cpVect vbr = relative_velocity(r1, a->v_bias, a->w_bias, r2, b->v_bias, b->w_bias);
+ vbr = cpvsub(jnt->bias, vbr);
+
+ cpVect jb = cpv(cpvdot(vbr, k1), cpvdot(vbr, k2));
+ cpVect jbOld = jnt->jBias;
+ jnt->jBias = grooveConstrain(jnt, cpvadd(jbOld, jb));
+ jb = cpvsub(jnt->jBias, jbOld);
+
+ apply_bias_impulses(a, b, jnt->r1, jnt->r2, jb);
+
+ // compute impulse
+ cpVect vr = relative_velocity(r1, a->v, a->w, r2, b->v, b->w);
+
+ cpVect j = cpv(-cpvdot(vr, k1), -cpvdot(vr, k2));
+ cpVect jOld = jnt->jAcc;
+ jnt->jAcc = grooveConstrain(jnt, cpvadd(jOld, j));
+ j = cpvsub(jnt->jAcc, jOld);
+
+ // apply impulse
+ apply_impulses(a, b, jnt->r1, jnt->r2, j);
+}
+
+static const cpJointClass grooveJointClass = {
+ CP_GROOVE_JOINT,
+ grooveJointPreStep,
+ grooveJointApplyImpulse,
+};
+
+cpGrooveJoint *
+cpGrooveJointAlloc(void)
+{
+ return (cpGrooveJoint *)malloc(sizeof(cpGrooveJoint));
+}
+
+cpGrooveJoint *
+cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)
+{
+ cpJointInit((cpJoint *)joint, &grooveJointClass, a, b);
+
+ joint->grv_a = groove_a;
+ joint->grv_b = groove_b;
+ joint->grv_n = cpvperp(cpvnormalize(cpvsub(groove_b, groove_a)));
+ joint->anchr2 = anchr2;
+
+ joint->jAcc = cpvzero;
+
+ return joint;
+}
+
+cpJoint *
+cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)
+{
+ return (cpJoint *)cpGrooveJointInit(cpGrooveJointAlloc(), a, b, groove_a, groove_b, anchr2);
+}
+
diff --git a/fusion/plugins/newton/cpJoint.h b/fusion/plugins/newton/cpJoint.h
new file mode 100644
index 0000000..37cb406
--- /dev/null
+++ b/fusion/plugins/newton/cpJoint.h
@@ -0,0 +1,122 @@
+/* Copyright (c) 2007 Scott Lembcke
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* 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
+* AUTHORS OR COPYRIGHT HOLDERS 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.
+*/
+
+// TODO: Comment me!
+
+extern cpFloat cp_joint_bias_coef;
+
+typedef enum cpJointType {
+ CP_PIN_JOINT,
+ CP_PIVOT_JOINT,
+ CP_SLIDE_JOINT,
+ CP_GROOVE_JOINT,
+ CP_CUSTOM_JOINT, // For user definable joint types.
+} cpJointType;
+
+struct cpJoint;
+struct cpJointClass;
+
+typedef struct cpJointClass {
+ cpJointType type;
+
+ void (*preStep)(struct cpJoint *joint, cpFloat dt_inv);
+ void (*applyImpulse)(struct cpJoint *joint);
+} cpJointClass;
+
+typedef struct cpJoint {
+ const cpJointClass *klass;
+
+ cpBody *a, *b;
+} cpJoint;
+
+void cpJointDestroy(cpJoint *joint);
+void cpJointFree(cpJoint *joint);
+
+
+typedef struct cpPinJoint {
+ cpJoint joint;
+ cpVect anchr1, anchr2;
+ cpFloat dist;
+
+ cpVect r1, r2;
+ cpVect n;
+ cpFloat nMass;
+
+ cpFloat jnAcc, jBias;
+ cpFloat bias;
+} cpPinJoint;
+
+cpPinJoint *cpPinJointAlloc(void);
+cpPinJoint *cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
+cpJoint *cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
+
+
+typedef struct cpSlideJoint {
+ cpJoint joint;
+ cpVect anchr1, anchr2;
+ cpFloat min, max;
+
+ cpVect r1, r2;
+ cpVect n;
+ cpFloat nMass;
+
+ cpFloat jnAcc, jBias;
+ cpFloat bias;
+} cpSlideJoint;
+
+cpSlideJoint *cpSlideJointAlloc(void);
+cpSlideJoint *cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);
+cpJoint *cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);
+
+
+typedef struct cpPivotJoint {
+ cpJoint joint;
+ cpVect anchr1, anchr2;
+
+ cpVect r1, r2;
+ cpVect k1, k2;
+
+ cpVect jAcc, jBias;
+ cpVect bias;
+} cpPivotJoint;
+
+cpPivotJoint *cpPivotJointAlloc(void);
+cpPivotJoint *cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect pivot);
+cpJoint *cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot);
+
+
+typedef struct cpGrooveJoint {
+ cpJoint joint;
+ cpVect grv_n, grv_a, grv_b;
+ cpVect anchr2;
+
+ cpVect grv_tn;
+ cpFloat clamp;
+ cpVect r1, r2;
+ cpVect k1, k2;
+
+ cpVect jAcc, jBias;
+ cpVect bias;
+} cpGrooveJoint;
+
+cpGrooveJoint *cpGrooveJointAlloc(void);
+cpGrooveJoint *cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2);
+cpJoint *cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2);
diff --git a/fusion/plugins/newton/cpPolyShape.c b/fusion/plugins/newton/cpPolyShape.c
new file mode 100644
index 0000000..a9375b4
--- /dev/null
+++ b/fusion/plugins/newton/cpPolyShape.c
@@ -0,0 +1,139 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "chipmunk.h"
+
+cpPolyShape *
+cpPolyShapeAlloc(void)
+{
+ return (cpPolyShape *)calloc(1, sizeof(cpPolyShape));
+}
+
+static void
+cpPolyShapeTransformVerts(cpPolyShape *poly, cpVect p, cpVect rot)
+{
+ cpVect *src = poly->verts;
+ cpVect *dst = poly->tVerts;
+
+ for(int i=0; i<poly->numVerts; i++)
+ dst[i] = cpvadd(p, cpvrotate(src[i], rot));
+}
+
+static void
+cpPolyShapeTransformAxes(cpPolyShape *poly, cpVect p, cpVect rot)
+{
+ cpPolyShapeAxis *src = poly->axes;
+ cpPolyShapeAxis *dst = poly->tAxes;
+
+ for(int i=0; i<poly->numVerts; i++){
+ cpVect n = cpvrotate(src[i].n, rot);
+ dst[i].n = n;
+ dst[i].d = cpvdot(p, n) + src[i].d;
+ }
+}
+
+static cpBB
+cpPolyShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
+{
+ cpPolyShape *poly = (cpPolyShape *)shape;
+
+ cpFloat l, b, r, t;
+
+ cpPolyShapeTransformAxes(poly, p, rot);
+ cpPolyShapeTransformVerts(poly, p, rot);
+
+ cpVect *verts = poly->tVerts;
+ l = r = verts[0].x;
+ b = t = verts[0].y;
+
+ // TODO do as part of cpPolyShapeTransformVerts?
+ for(int i=1; i<poly->numVerts; i++){
+ cpVect v = verts[i];
+
+ l = cpfmin(l, v.x);
+ r = cpfmax(r, v.x);
+
+ b = cpfmin(b, v.y);
+ t = cpfmax(t, v.y);
+ }
+
+ return cpBBNew(l, b, r, t);
+}
+
+static void
+cpPolyShapeDestroy(cpShape *shape)
+{
+ cpPolyShape *poly = (cpPolyShape *)shape;
+
+ free(poly->verts);
+ free(poly->tVerts);
+
+ free(poly->axes);
+ free(poly->tAxes);
+}
+
+static int
+cpPolyShapePointQuery(cpShape *shape, cpVect p){
+ // TODO Check against BB first?
+ return cpPolyShapeContainsVert((cpPolyShape *)shape, p);
+}
+
+static const cpShapeClass polyClass = {
+ CP_POLY_SHAPE,
+ cpPolyShapeCacheData,
+ cpPolyShapeDestroy,
+ cpPolyShapePointQuery,
+};
+
+cpPolyShape *
+cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset)
+{
+ poly->numVerts = numVerts;
+
+ poly->verts = (cpVect *)calloc(numVerts, sizeof(cpVect));
+ poly->tVerts = (cpVect *)calloc(numVerts, sizeof(cpVect));
+ poly->axes = (cpPolyShapeAxis *)calloc(numVerts, sizeof(cpPolyShapeAxis));
+ poly->tAxes = (cpPolyShapeAxis *)calloc(numVerts, sizeof(cpPolyShapeAxis));
+
+ for(int i=0; i<numVerts; i++){
+ cpVect a = cpvadd(offset, verts[i]);
+ cpVect b = cpvadd(offset, verts[(i+1)%numVerts]);
+ cpVect n = cpvnormalize(cpvperp(cpvsub(b, a)));
+
+ poly->verts[i] = a;
+ poly->axes[i].n = n;
+ poly->axes[i].d = cpvdot(n, a);
+ }
+
+ cpShapeInit((cpShape *)poly, &polyClass, body);
+
+ return poly;
+}
+
+cpShape *
+cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset)
+{
+ return (cpShape *)cpPolyShapeInit(cpPolyShapeAlloc(), body, numVerts, verts, offset);
+}
diff --git a/fusion/plugins/newton/cpPolyShape.h b/fusion/plugins/newton/cpPolyShape.h
new file mode 100644
index 0000000..6f24e0a
--- /dev/null
+++ b/fusion/plugins/newton/cpPolyShape.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+// Axis structure used by cpPolyShape.
+typedef struct cpPolyShapeAxis{
+ // normal
+ cpVect n;
+ // distance from origin
+ cpFloat d;
+} cpPolyShapeAxis;
+
+// Convex polygon shape structure.
+typedef struct cpPolyShape{
+ cpShape shape;
+
+ // Vertex and axis lists.
+ int numVerts;
+ cpVect *verts;
+ cpPolyShapeAxis *axes;
+
+ // Transformed vertex and axis lists.
+ cpVect *tVerts;
+ cpPolyShapeAxis *tAxes;
+} cpPolyShape;
+
+// Basic allocation functions.
+cpPolyShape *cpPolyShapeAlloc(void);
+cpPolyShape *cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset);
+cpShape *cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset);
+
+// Returns the minimum distance of the polygon to the axis.
+static inline cpFloat
+cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d)
+{
+ cpVect *verts = poly->tVerts;
+ cpFloat min = cpvdot(n, verts[0]);
+
+ int i;
+ for(i=1; i<poly->numVerts; i++)
+ min = cpfmin(min, cpvdot(n, verts[i]));
+
+ return min - d;
+}
+
+// Returns true if the polygon contains the vertex.
+static inline int
+cpPolyShapeContainsVert(cpPolyShape *poly, cpVect v)
+{
+ cpPolyShapeAxis *axes = poly->tAxes;
+
+ int i;
+ for(i=0; i<poly->numVerts; i++){
+ cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;
+ if(dist > 0.0) return 0;
+ }
+
+ return 1;
+}
diff --git a/fusion/plugins/newton/cpShape.c b/fusion/plugins/newton/cpShape.c
new file mode 100644
index 0000000..4359118
--- /dev/null
+++ b/fusion/plugins/newton/cpShape.c
@@ -0,0 +1,244 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include "chipmunk.h"
+#include "math.h"
+
+unsigned int SHAPE_ID_COUNTER = 0;
+
+void
+cpResetShapeIdCounter(void)
+{
+ SHAPE_ID_COUNTER = 0;
+}
+
+
+cpShape*
+cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)
+{
+ shape->klass = klass;
+
+ shape->id = SHAPE_ID_COUNTER;
+ SHAPE_ID_COUNTER++;
+
+ assert(body != NULL);
+ shape->body = body;
+
+ shape->e = 0.0f;
+ shape->u = 0.0f;
+ shape->surface_v = cpvzero;
+
+ shape->collision_type = 0;
+ shape->group = 0;
+ shape->layers = 0xFFFF;
+
+ shape->data = NULL;
+
+ cpShapeCacheBB(shape);
+
+ return shape;
+}
+
+void
+cpShapeDestroy(cpShape *shape)
+{
+ if(shape->klass->destroy) shape->klass->destroy(shape);
+}
+
+void
+cpShapeFree(cpShape *shape)
+{
+ if(shape) cpShapeDestroy(shape);
+ free(shape);
+}
+
+cpBB
+cpShapeCacheBB(cpShape *shape)
+{
+ cpBody *body = shape->body;
+
+ shape->bb = shape->klass->cacheData(shape, body->p, body->rot);
+ return shape->bb;
+}
+
+int
+cpShapePointQuery(cpShape *shape, cpVect p){
+ return shape->klass->pointQuery(shape, p);
+}
+
+
+
+cpCircleShape *
+cpCircleShapeAlloc(void)
+{
+ return (cpCircleShape *)calloc(1, sizeof(cpCircleShape));
+}
+
+static inline cpBB
+bbFromCircle(const cpVect c, const cpFloat r)
+{
+ return cpBBNew(c.x-r, c.y-r, c.x+r, c.y+r);
+}
+
+static cpBB
+cpCircleShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
+{
+ cpCircleShape *circle = (cpCircleShape *)shape;
+
+ circle->tc = cpvadd(p, cpvrotate(circle->c, rot));
+ return bbFromCircle(circle->tc, circle->r);
+}
+
+static int
+cpCircleShapePointQuery(cpShape *shape, cpVect p){
+ cpCircleShape *circle = (cpCircleShape *)shape;
+
+ cpFloat distSQ = cpvlengthsq(cpvsub(circle->tc, p));
+ return distSQ <= (circle->r*circle->r);
+}
+
+static const cpShapeClass circleClass = {
+ CP_CIRCLE_SHAPE,
+ cpCircleShapeCacheData,
+ NULL,
+ cpCircleShapePointQuery,
+};
+
+cpCircleShape *
+cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset)
+{
+ circle->c = offset;
+ circle->r = radius;
+
+ cpShapeInit((cpShape *)circle, &circleClass, body);
+
+ return circle;
+}
+
+cpShape *
+cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset)
+{
+ return (cpShape *)cpCircleShapeInit(cpCircleShapeAlloc(), body, radius, offset);
+}
+
+cpSegmentShape *
+cpSegmentShapeAlloc(void)
+{
+ return (cpSegmentShape *)calloc(1, sizeof(cpSegmentShape));
+}
+
+static cpBB
+cpSegmentShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
+{
+ cpSegmentShape *seg = (cpSegmentShape *)shape;
+
+ seg->ta = cpvadd(p, cpvrotate(seg->a, rot));
+ seg->tb = cpvadd(p, cpvrotate(seg->b, rot));
+ seg->tn = cpvrotate(seg->n, rot);
+
+ cpFloat l,r,s,t;
+
+ if(seg->ta.x < seg->tb.x){
+ l = seg->ta.x;
+ r = seg->tb.x;
+ } else {
+ l = seg->tb.x;
+ r = seg->ta.x;
+ }
+
+ if(seg->ta.y < seg->tb.y){
+ s = seg->ta.y;
+ t = seg->tb.y;
+ } else {
+ s = seg->tb.y;
+ t = seg->ta.y;
+ }
+
+ cpFloat rad = seg->r;
+ return cpBBNew(l - rad, s - rad, r + rad, t + rad);
+}
+
+static int
+cpSegmentShapePointQuery(cpShape *shape, cpVect p){
+ cpSegmentShape *seg = (cpSegmentShape *)shape;
+
+ // Calculate normal distance from segment.
+ cpFloat dn = cpvdot(seg->tn, p) - cpvdot(seg->ta, seg->tn);
+ cpFloat dist = fabs(dn) - seg->r;
+ if(dist > 0.0f) return 0;
+
+ // Calculate tangential distance along segment.
+ cpFloat dt = -cpvcross(seg->tn, p);
+ cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
+ cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
+
+ // Decision tree to decide which feature of the segment to collide with.
+ if(dt <= dtMin){
+ if(dt < (dtMin - seg->r)){
+ return 0;
+ } else {
+ return cpvlengthsq(cpvsub(seg->ta, p)) < (seg->r*seg->r);
+ }
+ } else {
+ if(dt < dtMax){
+ return 1;
+ } else {
+ if(dt < (dtMax + seg->r)) {
+ return cpvlengthsq(cpvsub(seg->tb, p)) < (seg->r*seg->r);
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static const cpShapeClass segmentClass = {
+ CP_SEGMENT_SHAPE,
+ cpSegmentShapeCacheData,
+ NULL,
+ cpSegmentShapePointQuery,
+};
+
+cpSegmentShape *
+cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat r)
+{
+ seg->a = a;
+ seg->b = b;
+ seg->n = cpvperp(cpvnormalize(cpvsub(b, a)));
+
+ seg->r = r;
+
+ cpShapeInit((cpShape *)seg, &segmentClass, body);
+
+ return seg;
+}
+
+cpShape*
+cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat r)
+{
+ return (cpShape *)cpSegmentShapeInit(cpSegmentShapeAlloc(), body, a, b, r);
+}
diff --git a/fusion/plugins/newton/cpShape.h b/fusion/plugins/newton/cpShape.h
new file mode 100644
index 0000000..e1f7281
--- /dev/null
+++ b/fusion/plugins/newton/cpShape.h
@@ -0,0 +1,133 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+// For determinism, you can reset the shape id counter.
+void cpResetShapeIdCounter(void);
+
+// Enumeration of shape types.
+typedef enum cpShapeType{
+ CP_CIRCLE_SHAPE,
+ CP_SEGMENT_SHAPE,
+ CP_POLY_SHAPE,
+ CP_NUM_SHAPES
+} cpShapeType;
+
+// Forward declarations required for defining the cpShape and cpShapeClass structs.
+struct cpShape;
+struct cpShapeClass;
+
+// Shape class. Holds function pointers and type data.
+typedef struct cpShapeClass {
+ cpShapeType type;
+
+ // Called by cpShapeCacheBB().
+ cpBB (*cacheData)(struct cpShape *shape, cpVect p, cpVect rot);
+ // Called to by cpShapeDestroy().
+ void (*destroy)(struct cpShape *shape);
+
+ // called by cpShapeQueryPoint
+ int (*pointQuery)(struct cpShape *shape, cpVect p);
+} cpShapeClass;
+
+// Basic shape struct that the others inherit from.
+typedef struct cpShape{
+ const cpShapeClass *klass;
+
+ // Unique id used as the hash value.
+ unsigned int id;
+ // Cached BBox for the shape.
+ cpBB bb;
+
+ // User defined collision type for the shape.
+ unsigned int collision_type;
+ // User defined collision group for the shape.
+ unsigned int group;
+ // User defined layer bitmask for the shape.
+ unsigned int layers;
+
+ // User defined data pointer for the shape.
+ void *data;
+
+ // cpBody that the shape is attached to.
+ cpBody *body;
+
+ // Coefficient of restitution. (elasticity)
+ cpFloat e;
+ // Coefficient of friction.
+ cpFloat u;
+ // Surface velocity used when solving for friction.
+ cpVect surface_v;
+} cpShape;
+
+// Low level shape initialization func.
+cpShape* cpShapeInit(cpShape *shape, const struct cpShapeClass *klass, cpBody *body);
+
+// Basic destructor functions. (allocation functions are not shared)
+void cpShapeDestroy(cpShape *shape);
+void cpShapeFree(cpShape *shape);
+
+// Cache the BBox of the shape.
+cpBB cpShapeCacheBB(cpShape *shape);
+
+// Test if a point lies within a shape.
+int cpShapePointQuery(cpShape *shape, cpVect p);
+
+// Test if a segment collides with a shape.
+// Returns [0-1] if the segment collides and -1 otherwise.
+// 0 would be a collision at point a, 1 would be a collision at point b.
+//cpFloat cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b);
+
+
+// Circle shape structure.
+typedef struct cpCircleShape{
+ cpShape shape;
+
+ // Center. (body space coordinates)
+ cpVect c;
+ // Radius.
+ cpFloat r;
+
+ // Transformed center. (world space coordinates)
+ cpVect tc;
+} cpCircleShape;
+
+// Basic allocation functions for cpCircleShape.
+cpCircleShape *cpCircleShapeAlloc(void);
+cpCircleShape *cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset);
+cpShape *cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset);
+
+// Segment shape structure.
+typedef struct cpSegmentShape{
+ cpShape shape;
+
+ // Endpoints and normal of the segment. (body space coordinates)
+ cpVect a, b, n;
+ // Radius of the segment. (Thickness)
+ cpFloat r;
+
+ // Transformed endpoints and normal. (world space coordinates)
+ cpVect ta, tb, tn;
+} cpSegmentShape;
+
+// Basic allocation functions for cpSegmentShape.
+cpSegmentShape* cpSegmentShapeAlloc(void);
+cpSegmentShape* cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat r);
+cpShape* cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat r);
diff --git a/fusion/plugins/newton/cpSpace.c b/fusion/plugins/newton/cpSpace.c
new file mode 100644
index 0000000..31ef3fb
--- /dev/null
+++ b/fusion/plugins/newton/cpSpace.c
@@ -0,0 +1,530 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+
+#include "chipmunk.h"
+
+int cp_contact_persistence = 3;
+
+// Equal function for contactSet.
+static int
+contactSetEql(void *ptr, void *elt)
+{
+ cpShape **shapes = (cpShape **)ptr;
+ cpShape *a = shapes[0];
+ cpShape *b = shapes[1];
+
+ cpArbiter *arb = (cpArbiter *)elt;
+
+ return ((a == arb->a && b == arb->b) || (b == arb->a && a == arb->b));
+}
+
+// Transformation function for contactSet.
+static void *
+contactSetTrans(void *ptr, void *data)
+{
+ cpShape **shapes = (cpShape **)ptr;
+ cpShape *a = shapes[0];
+ cpShape *b = shapes[1];
+
+ cpSpace *space = (cpSpace *)data;
+
+ return cpArbiterNew(a, b, space->stamp);
+}
+
+// Collision pair function wrapper struct.
+typedef struct collFuncData {
+ cpCollFunc func;
+ void *data;
+} collFuncData;
+
+// Equals function for collFuncSet.
+static int
+collFuncSetEql(void *ptr, void *elt)
+{
+ unsigned int *ids = (unsigned int *)ptr;
+ unsigned int a = ids[0];
+ unsigned int b = ids[1];
+
+ cpCollPairFunc *pair = (cpCollPairFunc *)elt;
+
+ return ((a == pair->a && b == pair->b) || (b == pair->a && a == pair->b));
+}
+
+// Transformation function for collFuncSet.
+static void *
+collFuncSetTrans(void *ptr, void *data)
+{
+ unsigned int *ids = (unsigned int *)ptr;
+ collFuncData *funcData = (collFuncData *)data;
+
+ cpCollPairFunc *pair = (cpCollPairFunc *)malloc(sizeof(cpCollPairFunc));
+ pair->a = ids[0];
+ pair->b = ids[1];
+ pair->func = funcData->func;
+ pair->data = funcData->data;
+
+ return pair;
+}
+
+// Default collision pair function.
+static int
+alwaysCollide(cpShape *a, cpShape *b, cpContact *arr, int numCon, cpFloat normal_coef, void *data)
+{
+ return 1;
+}
+
+// BBfunc callback for the spatial hash.
+static cpBB
+bbfunc(void *ptr)
+{
+ cpShape *shape = (cpShape *)ptr;
+ return shape->bb;
+}
+
+// Iterator functions for destructors.
+static void freeWrap(void *ptr, void *unused){ free( ptr);}
+static void shapeFreeWrap(void *ptr, void *unused){ cpShapeFree((cpShape *) ptr);}
+static void arbiterFreeWrap(void *ptr, void *unused){ cpArbiterFree((cpArbiter *)ptr);}
+static void bodyFreeWrap(void *ptr, void *unused){ cpBodyFree((cpBody *) ptr);}
+static void jointFreeWrap(void *ptr, void *unused){ cpJointFree((cpJoint *) ptr);}
+
+cpSpace*
+cpSpaceAlloc(void)
+{
+ return (cpSpace *)calloc(1, sizeof(cpSpace));
+}
+
+#define DEFAULT_DIM_SIZE 100.0f
+#define DEFAULT_COUNT 1000
+#define DEFAULT_ITERATIONS 10
+#define DEFAULT_ELASTIC_ITERATIONS 0
+
+cpSpace*
+cpSpaceInit(cpSpace *space)
+{
+ space->iterations = DEFAULT_ITERATIONS;
+ space->elasticIterations = DEFAULT_ELASTIC_ITERATIONS;
+// space->sleepTicks = 300;
+
+ space->gravity = cpvzero;
+ space->damping = 1.0f;
+
+ space->stamp = 0;
+
+ space->staticShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, &bbfunc);
+ space->activeShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, &bbfunc);
+
+ space->bodies = cpArrayNew(0);
+ space->arbiters = cpArrayNew(0);
+ space->contactSet = cpHashSetNew(0, contactSetEql, contactSetTrans);
+
+ space->joints = cpArrayNew(0);
+
+ cpCollPairFunc pairFunc = {0, 0, alwaysCollide, NULL};
+ space->defaultPairFunc = pairFunc;
+ space->collFuncSet = cpHashSetNew(0, collFuncSetEql, collFuncSetTrans);
+ space->collFuncSet->default_value = &space->defaultPairFunc;
+
+ return space;
+}
+
+cpSpace*
+cpSpaceNew(void)
+{
+ return cpSpaceInit(cpSpaceAlloc());
+}
+
+void
+cpSpaceDestroy(cpSpace *space)
+{
+ cpSpaceHashFree(space->staticShapes);
+ cpSpaceHashFree(space->activeShapes);
+
+ cpArrayFree(space->bodies);
+
+ cpArrayFree(space->joints);
+
+ if(space->contactSet)
+ cpHashSetEach(space->contactSet, &arbiterFreeWrap, NULL);
+ cpHashSetFree(space->contactSet);
+ cpArrayFree(space->arbiters);
+
+ if(space->collFuncSet)
+ cpHashSetEach(space->collFuncSet, &freeWrap, NULL);
+ cpHashSetFree(space->collFuncSet);
+}
+
+void
+cpSpaceFree(cpSpace *space)
+{
+ if(space) cpSpaceDestroy(space);
+ free(space);
+}
+
+void
+cpSpaceFreeChildren(cpSpace *space)
+{
+ cpSpaceHashEach(space->staticShapes, &shapeFreeWrap, NULL);
+ cpSpaceHashEach(space->activeShapes, &shapeFreeWrap, NULL);
+ cpArrayEach(space->bodies, &bodyFreeWrap, NULL);
+ cpArrayEach(space->joints, &jointFreeWrap, NULL);
+}
+
+void
+cpSpaceAddCollisionPairFunc(cpSpace *space, unsigned int a, unsigned int b,
+ cpCollFunc func, void *data)
+{
+ unsigned int ids[] = {a, b};
+ unsigned int hash = CP_HASH_PAIR(a, b);
+ // Remove any old function so the new one will get added.
+ cpSpaceRemoveCollisionPairFunc(space, a, b);
+
+ collFuncData funcData = {func, data};
+ cpHashSetInsert(space->collFuncSet, hash, ids, &funcData);
+}
+
+void
+cpSpaceRemoveCollisionPairFunc(cpSpace *space, unsigned int a, unsigned int b)
+{
+ unsigned int ids[] = {a, b};
+ unsigned int hash = CP_HASH_PAIR(a, b);
+ cpCollPairFunc *old_pair = (cpCollPairFunc *)cpHashSetRemove(space->collFuncSet, hash, ids);
+ free(old_pair);
+}
+
+void
+cpSpaceSetDefaultCollisionPairFunc(cpSpace *space, cpCollFunc func, void *data)
+{
+ cpCollPairFunc pairFunc = {0, 0, (func ? func : alwaysCollide), (func ? data : NULL)};
+ space->defaultPairFunc = pairFunc;
+}
+
+void
+cpSpaceAddShape(cpSpace *space, cpShape *shape)
+{
+ cpSpaceHashInsert(space->activeShapes, shape, shape->id, shape->bb);
+}
+
+void
+cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
+{
+ cpShapeCacheBB(shape);
+ cpSpaceHashInsert(space->staticShapes, shape, shape->id, shape->bb);
+}
+
+void
+cpSpaceAddBody(cpSpace *space, cpBody *body)
+{
+ cpArrayPush(space->bodies, body);
+}
+
+void
+cpSpaceAddJoint(cpSpace *space, cpJoint *joint)
+{
+ cpArrayPush(space->joints, joint);
+}
+
+void
+cpSpaceRemoveShape(cpSpace *space, cpShape *shape)
+{
+ cpSpaceHashRemove(space->activeShapes, shape, shape->id);
+}
+
+void
+cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)
+{
+ cpSpaceHashRemove(space->staticShapes, shape, shape->id);
+}
+
+void
+cpSpaceRemoveBody(cpSpace *space, cpBody *body)
+{
+ cpArrayDeleteObj(space->bodies, body);
+}
+
+void
+cpSpaceRemoveJoint(cpSpace *space, cpJoint *joint)
+{
+ cpArrayDeleteObj(space->joints, joint);
+}
+
+void
+cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data)
+{
+ cpArray *bodies = space->bodies;
+
+ for(int i=0; i<bodies->num; i++)
+ func((cpBody *)bodies->arr[i], data);
+}
+
+// Iterator function used for updating shape BBoxes.
+static void
+updateBBCache(void *ptr, void *unused)
+{
+ cpShape *shape = (cpShape *)ptr;
+ cpShapeCacheBB(shape);
+}
+
+void
+cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count)
+{
+ cpSpaceHashResize(space->staticShapes, dim, count);
+ cpSpaceHashRehash(space->staticShapes);
+}
+
+void
+cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count)
+{
+ cpSpaceHashResize(space->activeShapes, dim, count);
+}
+
+void
+cpSpaceRehashStatic(cpSpace *space)
+{
+ cpSpaceHashEach(space->staticShapes, &updateBBCache, NULL);
+ cpSpaceHashRehash(space->staticShapes);
+}
+
+typedef struct pointQueryFuncPair {
+ cpSpacePointQueryFunc func;
+ void *data;
+} pointQueryFuncPair;
+
+static int
+pointQueryHelper(void *point, void *obj, void *data)
+{
+ cpShape *shape = (cpShape *)obj;
+ pointQueryFuncPair *pair = (pointQueryFuncPair *)data;
+
+ if(cpShapePointQuery(shape, *((cpVect *)point)))
+ pair->func(shape, pair->data);
+
+ return 1; // return value needed for historical reasons (value is ignored)
+}
+
+static void
+pointQuery(cpSpaceHash *hash, cpVect point, cpSpacePointQueryFunc func, void *data)
+{
+ pointQueryFuncPair pair = {func, data};
+ cpSpaceHashPointQuery(hash, point, pointQueryHelper, &pair);
+}
+
+void
+cpSpaceShapePointQuery(cpSpace *space, cpVect point, cpSpacePointQueryFunc func, void *data)
+{
+ pointQuery(space->activeShapes, point, func, data);
+}
+
+void
+cpSpaceStaticShapePointQuery(cpSpace *space, cpVect point, cpSpacePointQueryFunc func, void *data)
+{
+ pointQuery(space->staticShapes, point, func, data);
+}
+
+static inline int
+queryReject(cpShape *a, cpShape *b)
+{
+ return
+ // BBoxes must overlap
+ !cpBBintersects(a->bb, b->bb)
+ // Don't collide shapes attached to the same body.
+ || a->body == b->body
+ // Don't collide objects in the same non-zero group
+ || (a->group && b->group && a->group == b->group)
+ // Don't collide objects that don't share at least on layer.
+ || !(a->layers & b->layers);
+}
+
+// Callback from the spatial hash.
+// TODO: Refactor this into separate functions?
+static int
+queryFunc(void *p1, void *p2, void *data)
+{
+ // Cast the generic pointers from the spatial hash back to usefull types
+ cpShape *a = (cpShape *)p1;
+ cpShape *b = (cpShape *)p2;
+ cpSpace *space = (cpSpace *)data;
+
+ // Reject any of the simple cases
+ if(queryReject(a,b)) return 0;
+
+ // Shape 'a' should have the lower shape type. (required by cpCollideShapes() )
+ if(a->klass->type > b->klass->type){
+ cpShape *temp = a;
+ a = b;
+ b = temp;
+ }
+
+ // Find the collision pair function for the shapes.
+ unsigned int ids[] = {a->collision_type, b->collision_type};
+ unsigned int hash = CP_HASH_PAIR(a->collision_type, b->collision_type);
+ cpCollPairFunc *pairFunc = (cpCollPairFunc *)cpHashSetFind(space->collFuncSet, hash, ids);
+ if(!pairFunc->func) return 0; // A NULL pair function means don't collide at all.
+
+ // Narrow-phase collision detection.
+ cpContact *contacts = NULL;
+ int numContacts = cpCollideShapes(a, b, &contacts);
+ if(!numContacts) return 0; // Shapes are not colliding.
+
+ // The collision pair function requires objects to be ordered by their collision types.
+ cpShape *pair_a = a;
+ cpShape *pair_b = b;
+ cpFloat normal_coef = 1.0f;
+
+ // Swap them if necessary.
+ if(pair_a->collision_type != pairFunc->a){
+ cpShape *temp = pair_a;
+ pair_a = pair_b;
+ pair_b = temp;
+ normal_coef = -1.0f;
+ }
+
+ if(pairFunc->func(pair_a, pair_b, contacts, numContacts, normal_coef, pairFunc->data)){
+ // The collision pair function OKed the collision. Record the contact information.
+
+ // Get an arbiter from space->contactSet for the two shapes.
+ // This is where the persistant contact magic comes from.
+ cpShape *shape_pair[] = {a, b};
+ cpArbiter *arb = (cpArbiter *)cpHashSetInsert(space->contactSet, CP_HASH_PAIR(a, b), shape_pair, space);
+
+ // Timestamp the arbiter.
+ arb->stamp = space->stamp;
+ arb->a = a; arb->b = b; // TODO: Investigate why this is still necessary?
+ // Inject the new contact points into the arbiter.
+ cpArbiterInject(arb, contacts, numContacts);
+
+ // Add the arbiter to the list of active arbiters.
+ cpArrayPush(space->arbiters, arb);
+
+ return numContacts;
+ } else {
+ // The collision pair function rejected the collision.
+
+ free(contacts);
+ return 0;
+ }
+}
+
+// Iterator for active/static hash collisions.
+static void
+active2staticIter(void *ptr, void *data)
+{
+ cpShape *shape = (cpShape *)ptr;
+ cpSpace *space = (cpSpace *)data;
+ cpSpaceHashQuery(space->staticShapes, shape, shape->bb, &queryFunc, space);
+}
+
+// Hashset reject func to throw away old arbiters.
+static int
+contactSetReject(void *ptr, void *data)
+{
+ cpArbiter *arb = (cpArbiter *)ptr;
+ cpSpace *space = (cpSpace *)data;
+
+ if((space->stamp - arb->stamp) > cp_contact_persistence){
+ cpArbiterFree(arb);
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+cpSpaceStep(cpSpace *space, cpFloat dt)
+{
+ if(!dt) return; // prevents div by zero.
+ cpFloat dt_inv = 1.0f/dt;
+
+ cpArray *bodies = space->bodies;
+ cpArray *arbiters = space->arbiters;
+ cpArray *joints = space->joints;
+
+ // Empty the arbiter list.
+ cpHashSetReject(space->contactSet, &contactSetReject, space);
+ space->arbiters->num = 0;
+
+ // Integrate positions.
+ for(int i=0; i<bodies->num; i++){
+ cpBody *body = (cpBody *)bodies->arr[i];
+ body->position_func(body, dt);
+ }
+
+ // Pre-cache BBoxes and shape data.
+ cpSpaceHashEach(space->activeShapes, &updateBBCache, NULL);
+
+ // Collide!
+ cpSpaceHashEach(space->activeShapes, &active2staticIter, space);
+ cpSpaceHashQueryRehash(space->activeShapes, &queryFunc, space);
+
+ // Prestep the arbiters.
+ for(int i=0; i<arbiters->num; i++)
+ cpArbiterPreStep((cpArbiter *)arbiters->arr[i], dt_inv);
+
+ // Prestep the joints.
+ for(int i=0; i<joints->num; i++){
+ cpJoint *joint = (cpJoint *)joints->arr[i];
+ joint->klass->preStep(joint, dt_inv);
+ }
+
+ for(int i=0; i<space->elasticIterations; i++){
+ for(int j=0; j<arbiters->num; j++)
+ cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j], 1.0f);
+
+ for(int j=0; j<joints->num; j++){
+ cpJoint *joint = (cpJoint *)joints->arr[j];
+ joint->klass->applyImpulse(joint);
+ }
+ }
+
+ // Integrate velocities.
+ cpFloat damping = pow(1.0f/space->damping, -dt);
+ for(int i=0; i<bodies->num; i++){
+ cpBody *body = (cpBody *)bodies->arr[i];
+ body->velocity_func(body, space->gravity, damping, dt);
+ }
+
+ for(int i=0; i<arbiters->num; i++)
+ cpArbiterApplyCachedImpulse((cpArbiter *)arbiters->arr[i]);
+
+ // Run the impulse solver.
+ for(int i=0; i<space->iterations; i++){
+ for(int j=0; j<arbiters->num; j++)
+ cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j], 0.0f);
+
+ for(int j=0; j<joints->num; j++){
+ cpJoint *joint = (cpJoint *)joints->arr[j];
+ joint->klass->applyImpulse(joint);
+ }
+ }
+
+// cpFloat dvsq = cpvdot(space->gravity, space->gravity);
+// dvsq *= dt*dt * space->damping*space->damping;
+// for(int i=0; i<bodies->num; i++)
+// cpBodyMarkLowEnergy(bodies->arr[i], dvsq, space->sleepTicks);
+
+ // Increment the stamp.
+ space->stamp++;
+}
diff --git a/fusion/plugins/newton/cpSpace.h b/fusion/plugins/newton/cpSpace.h
new file mode 100644
index 0000000..8441f9a
--- /dev/null
+++ b/fusion/plugins/newton/cpSpace.h
@@ -0,0 +1,113 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+// Number of frames that contact information should persist.
+extern int cp_contact_persistence;
+
+// User collision pair function.
+typedef int (*cpCollFunc)(cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, void *data);
+
+// Structure for holding collision pair function information.
+// Used internally.
+typedef struct cpCollPairFunc {
+ unsigned int a;
+ unsigned int b;
+ cpCollFunc func;
+ void *data;
+} cpCollPairFunc;
+
+typedef struct cpSpace{
+ // Number of iterations to use in the impulse solver.
+ int iterations;
+ int elasticIterations;
+// int sleepTicks;
+
+ // Self explanatory.
+ cpVect gravity;
+ cpFloat damping;
+
+ // Time stamp. Is incremented on every call to cpSpaceStep().
+ int stamp;
+
+ // The static and active shape spatial hashes.
+ cpSpaceHash *staticShapes;
+ cpSpaceHash *activeShapes;
+
+ // List of bodies in the system.
+ cpArray *bodies;
+ // List of active arbiters for the impulse solver.
+ cpArray *arbiters;
+ // Persistant contact set.
+ cpHashSet *contactSet;
+
+ // List of joints in the system.
+ cpArray *joints;
+
+ // Set of collisionpair functions.
+ cpHashSet *collFuncSet;
+ // Default collision pair function.
+ cpCollPairFunc defaultPairFunc;
+} cpSpace;
+
+// Basic allocation/destruction functions.
+cpSpace* cpSpaceAlloc(void);
+cpSpace* cpSpaceInit(cpSpace *space);
+cpSpace* cpSpaceNew(void);
+
+void cpSpaceDestroy(cpSpace *space);
+void cpSpaceFree(cpSpace *space);
+
+// Convenience function. Frees all referenced entities. (bodies, shapes and joints)
+void cpSpaceFreeChildren(cpSpace *space);
+
+// Collision pair function management functions.
+void cpSpaceAddCollisionPairFunc(cpSpace *space, unsigned int a, unsigned int b,
+ cpCollFunc func, void *data);
+void cpSpaceRemoveCollisionPairFunc(cpSpace *space, unsigned int a, unsigned int b);
+void cpSpaceSetDefaultCollisionPairFunc(cpSpace *space, cpCollFunc func, void *data);
+
+// Add and remove entities from the system.
+void cpSpaceAddShape(cpSpace *space, cpShape *shape);
+void cpSpaceAddStaticShape(cpSpace *space, cpShape *shape);
+void cpSpaceAddBody(cpSpace *space, cpBody *body);
+void cpSpaceAddJoint(cpSpace *space, cpJoint *joint);
+
+void cpSpaceRemoveShape(cpSpace *space, cpShape *shape);
+void cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape);
+void cpSpaceRemoveBody(cpSpace *space, cpBody *body);
+void cpSpaceRemoveJoint(cpSpace *space, cpJoint *joint);
+
+// Point query callback function
+typedef void (*cpSpacePointQueryFunc)(cpShape *shape, void *data);
+void cpSpaceShapePointQuery(cpSpace *space, cpVect point, cpSpacePointQueryFunc func, void *data);
+void cpSpaceStaticShapePointQuery(cpSpace *space, cpVect point, cpSpacePointQueryFunc func, void *data);
+
+// Iterator function for iterating the bodies in a space.
+typedef void (*cpSpaceBodyIterator)(cpBody *body, void *data);
+void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data);
+
+// Spatial hash management functions.
+void cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count);
+void cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count);
+void cpSpaceRehashStatic(cpSpace *space);
+
+// Update the space.
+void cpSpaceStep(cpSpace *space, cpFloat dt);
diff --git a/fusion/plugins/newton/cpSpaceHash.c b/fusion/plugins/newton/cpSpaceHash.c
new file mode 100644
index 0000000..094107e
--- /dev/null
+++ b/fusion/plugins/newton/cpSpaceHash.c
@@ -0,0 +1,455 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+
+#include "chipmunk.h"
+#include "prime.h"
+
+static cpHandle*
+cpHandleAlloc(void)
+{
+ return (cpHandle *)malloc(sizeof(cpHandle));
+}
+
+static cpHandle*
+cpHandleInit(cpHandle *hand, void *obj)
+{
+ hand->obj = obj;
+ hand->retain = 0;
+ hand->stamp = 0;
+
+ return hand;
+}
+
+static cpHandle*
+cpHandleNew(void *obj)
+{
+ return cpHandleInit(cpHandleAlloc(), obj);
+}
+
+static inline void
+cpHandleRetain(cpHandle *hand)
+{
+ hand->retain++;
+}
+
+static inline void
+cpHandleFree(cpHandle *hand)
+{
+ free(hand);
+}
+
+static inline void
+cpHandleRelease(cpHandle *hand)
+{
+ hand->retain--;
+ if(hand->retain == 0)
+ cpHandleFree(hand);
+}
+
+
+cpSpaceHash*
+cpSpaceHashAlloc(void)
+{
+ return (cpSpaceHash *)calloc(1, sizeof(cpSpaceHash));
+}
+
+// Frees the old table, and allocates a new one.
+static void
+cpSpaceHashAllocTable(cpSpaceHash *hash, int numcells)
+{
+ free(hash->table);
+
+ hash->numcells = numcells;
+ hash->table = (cpSpaceHashBin **)calloc(numcells, sizeof(cpSpaceHashBin *));
+}
+
+// Equality function for the handleset.
+static int
+handleSetEql(void *obj, void *elt)
+{
+ cpHandle *hand = (cpHandle *)elt;
+ return (obj == hand->obj);
+}
+
+// Transformation function for the handleset.
+static void *
+handleSetTrans(void *obj, void *unused)
+{
+ cpHandle *hand = cpHandleNew(obj);
+ cpHandleRetain(hand);
+
+ return hand;
+}
+
+cpSpaceHash*
+cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpaceHashBBFunc bbfunc)
+{
+ cpSpaceHashAllocTable(hash, next_prime(numcells));
+ hash->celldim = celldim;
+ hash->bbfunc = bbfunc;
+
+ hash->bins = NULL;
+ hash->handleSet = cpHashSetNew(0, &handleSetEql, &handleSetTrans);
+
+ hash->stamp = 1;
+
+ return hash;
+}
+
+cpSpaceHash*
+cpSpaceHashNew(cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc)
+{
+ return cpSpaceHashInit(cpSpaceHashAlloc(), celldim, cells, bbfunc);
+}
+
+static inline void
+clearHashCell(cpSpaceHash *hash, int index)
+{
+ cpSpaceHashBin *bin = hash->table[index];
+ while(bin){
+ cpSpaceHashBin *next = bin->next;
+
+ // Release the lock on the handle.
+ cpHandleRelease(bin->handle);
+ // Recycle the bin.
+ bin->next = hash->bins;
+ hash->bins = bin;
+
+ bin = next;
+ }
+
+ hash->table[index] = NULL;
+}
+
+// Clear all cells in the hashtable.
+static void
+clearHash(cpSpaceHash *hash)
+{
+ for(int i=0; i<hash->numcells; i++)
+ clearHashCell(hash, i);
+}
+
+// Free the recycled hash bins.
+static void
+freeBins(cpSpaceHash *hash)
+{
+ cpSpaceHashBin *bin = hash->bins;
+ while(bin){
+ cpSpaceHashBin *next = bin->next;
+ free(bin);
+ bin = next;
+ }
+}
+
+// Hashset iterator function to free the handles.
+static void
+handleFreeWrap(void *elt, void *unused)
+{
+ cpHandle *hand = (cpHandle *)elt;
+ cpHandleFree(hand);
+}
+
+void
+cpSpaceHashDestroy(cpSpaceHash *hash)
+{
+ clearHash(hash);
+ freeBins(hash);
+
+ // Free the handles.
+ cpHashSetEach(hash->handleSet, &handleFreeWrap, NULL);
+ cpHashSetFree(hash->handleSet);
+
+ free(hash->table);
+}
+
+void
+cpSpaceHashFree(cpSpaceHash *hash)
+{
+ if(!hash) return;
+ cpSpaceHashDestroy(hash);
+ free(hash);
+}
+
+void
+cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells)
+{
+ // Clear the hash to release the old handle locks.
+ clearHash(hash);
+
+ hash->celldim = celldim;
+ cpSpaceHashAllocTable(hash, next_prime(numcells));
+}
+
+// Return true if the chain contains the handle.
+static inline int
+containsHandle(cpSpaceHashBin *bin, cpHandle *hand)
+{
+ while(bin){
+ if(bin->handle == hand) return 1;
+ bin = bin->next;
+ }
+
+ return 0;
+}
+
+// Get a recycled or new bin.
+static inline cpSpaceHashBin *
+getEmptyBin(cpSpaceHash *hash)
+{
+ cpSpaceHashBin *bin = hash->bins;
+
+ // Make a new one if necessary.
+ if(bin == NULL) return (cpSpaceHashBin *)malloc(sizeof(cpSpaceHashBin));
+
+ hash->bins = bin->next;
+ return bin;
+}
+
+// The hash function itself.
+static inline unsigned int
+hash_func(unsigned int x, unsigned int y, unsigned int n)
+{
+ return (x*2185031351ul ^ y*4232417593ul) % n;
+}
+
+static inline void
+hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb)
+{
+ // Find the dimensions in cell coordinates.
+ cpFloat dim = hash->celldim;
+ int l = bb.l/dim;
+ int r = bb.r/dim;
+ int b = bb.b/dim;
+ int t = bb.t/dim;
+
+ int n = hash->numcells;
+ for(int i=l; i<=r; i++){
+ for(int j=b; j<=t; j++){
+ int index = hash_func(i,j,n);
+ cpSpaceHashBin *bin = hash->table[index];
+
+ // Don't add an object twice to the same cell.
+ if(containsHandle(bin, hand)) continue;
+
+ cpHandleRetain(hand);
+ // Insert a new bin for the handle in this cell.
+ cpSpaceHashBin *newBin = getEmptyBin(hash);
+ newBin->handle = hand;
+ newBin->next = bin;
+ hash->table[index] = newBin;
+ }
+ }
+}
+
+void
+cpSpaceHashInsert(cpSpaceHash *hash, void *obj, unsigned int id, cpBB bb)
+{
+ cpHandle *hand = (cpHandle *)cpHashSetInsert(hash->handleSet, id, obj, NULL);
+ hashHandle(hash, hand, bb);
+}
+
+void
+cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, unsigned int id)
+{
+ cpHandle *hand = (cpHandle *)cpHashSetFind(hash->handleSet, id, obj);
+ hashHandle(hash, hand, hash->bbfunc(obj));
+}
+
+// Hashset iterator function for rehashing the spatial hash. (hash hash hash hash?)
+static void
+handleRehashHelper(void *elt, void *data)
+{
+ cpHandle *hand = (cpHandle *)elt;
+ cpSpaceHash *hash = (cpSpaceHash *)data;
+
+ hashHandle(hash, hand, hash->bbfunc(hand->obj));
+}
+
+void
+cpSpaceHashRehash(cpSpaceHash *hash)
+{
+ clearHash(hash);
+
+ // Rehash all of the handles.
+ cpHashSetEach(hash->handleSet, &handleRehashHelper, hash);
+}
+
+void
+cpSpaceHashRemove(cpSpaceHash *hash, void *obj, unsigned int id)
+{
+ cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, id, obj);
+
+ if(hand){
+ hand->obj = NULL;
+ cpHandleRelease(hand);
+ }
+}
+
+// Used by the cpSpaceHashEach() iterator.
+typedef struct eachPair {
+ cpSpaceHashIterator func;
+ void *data;
+} eachPair;
+
+// Calls the user iterator function. (Gross I know.)
+static void
+eachHelper(void *elt, void *data)
+{
+ cpHandle *hand = (cpHandle *)elt;
+ eachPair *pair = (eachPair *)data;
+
+ pair->func(hand->obj, pair->data);
+}
+
+// Iterate over the objects in the spatial hash.
+void
+cpSpaceHashEach(cpSpaceHash *hash, cpSpaceHashIterator func, void *data)
+{
+ // Bundle the callback up to send to the hashset iterator.
+ eachPair pair = {func, data};
+
+ cpHashSetEach(hash->handleSet, &eachHelper, &pair);
+}
+
+// Calls the callback function for the objects in a given chain.
+static inline void
+query(cpSpaceHash *hash, cpSpaceHashBin *bin, void *obj, cpSpaceHashQueryFunc func, void *data)
+{
+ for(; bin; bin = bin->next){
+ cpHandle *hand = bin->handle;
+ void *other = hand->obj;
+
+ // Skip over certain conditions
+ if(
+ // Have we already tried this pair in this query?
+ hand->stamp == hash->stamp
+ // Is obj the same as other?
+ || obj == other
+ // Has other been removed since the last rehash?
+ || !other
+ ) continue;
+
+ func(obj, other, data);
+
+ // Stamp that the handle was checked already against this object.
+ hand->stamp = hash->stamp;
+ }
+}
+
+void
+cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpaceHashQueryFunc func, void *data)
+{
+ cpFloat dim = hash->celldim;
+ int index = hash_func((int)(point.x/dim), (int)(point.y/dim), hash->numcells);
+
+ query(hash, hash->table[index], &point, func, data);
+
+ // Increment the stamp.
+ // Only one cell is checked, but query() requires it anyway.
+ hash->stamp++;
+}
+
+void
+cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data)
+{
+ // Get the dimensions in cell coordinates.
+ cpFloat dim = hash->celldim;
+ int l = bb.l/dim;
+ int r = bb.r/dim;
+ int b = bb.b/dim;
+ int t = bb.t/dim;
+
+ int n = hash->numcells;
+
+ // Iterate over the cells and query them.
+ for(int i=l; i<=r; i++){
+ for(int j=b; j<=t; j++){
+ int index = hash_func(i,j,n);
+ query(hash, hash->table[index], obj, func, data);
+ }
+ }
+
+ // Increment the stamp.
+ hash->stamp++;
+}
+
+// Similar to struct eachPair above.
+typedef struct queryRehashPair {
+ cpSpaceHash *hash;
+ cpSpaceHashQueryFunc func;
+ void *data;
+} queryRehashPair;
+
+// Hashset iterator func used with cpSpaceHashQueryRehash().
+static void
+handleQueryRehashHelper(void *elt, void *data)
+{
+ cpHandle *hand = (cpHandle *)elt;
+
+ // Unpack the user callback data.
+ queryRehashPair *pair = (queryRehashPair *)data;
+ cpSpaceHash *hash = pair->hash;
+ cpSpaceHashQueryFunc func = pair->func;
+
+ cpFloat dim = hash->celldim;
+ int n = hash->numcells;
+
+ void *obj = hand->obj;
+ cpBB bb = hash->bbfunc(obj);
+
+ int l = bb.l/dim;
+ int r = bb.r/dim;
+ int b = bb.b/dim;
+ int t = bb.t/dim;
+
+ for(int i=l; i<=r; i++){
+ for(int j=b; j<=t; j++){
+ int index = hash_func(i,j,n);
+ cpSpaceHashBin *bin = hash->table[index];
+
+ if(containsHandle(bin, hand)) continue;
+ query(hash, bin, obj, func, pair->data);
+
+ cpHandleRetain(hand);
+ cpSpaceHashBin *newBin = getEmptyBin(hash);
+ newBin->handle = hand;
+ newBin->next = bin;
+ hash->table[index] = newBin;
+ }
+ }
+
+ // Increment the stamp for each object we hash.
+ hash->stamp++;
+}
+
+void
+cpSpaceHashQueryRehash(cpSpaceHash *hash, cpSpaceHashQueryFunc func, void *data)
+{
+ clearHash(hash);
+
+ queryRehashPair pair = {hash, func, data};
+ cpHashSetEach(hash->handleSet, &handleQueryRehashHelper, &pair);
+}
diff --git a/fusion/plugins/newton/cpSpaceHash.h b/fusion/plugins/newton/cpSpaceHash.h
new file mode 100644
index 0000000..8da6ba1
--- /dev/null
+++ b/fusion/plugins/newton/cpSpaceHash.h
@@ -0,0 +1,100 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+// The spatial hash is Chipmunk's default (and currently only) spatial index type.
+// Based on a chained hash table.
+
+// Used internally to track objects added to the hash
+typedef struct cpHandle{
+ // Pointer to the object
+ void *obj;
+ // Retain count
+ int retain;
+ // Query stamp. Used to make sure two objects
+ // aren't identified twice in the same query.
+ int stamp;
+} cpHandle;
+
+// Linked list element for in the chains.
+typedef struct cpSpaceHashBin{
+ cpHandle *handle;
+ struct cpSpaceHashBin *next;
+} cpSpaceHashBin;
+
+// BBox callback. Called whenever the hash needs a bounding box from an object.
+typedef cpBB (*cpSpaceHashBBFunc)(void *obj);
+
+typedef struct cpSpaceHash{
+ // Number of cells in the table.
+ int numcells;
+ // Dimentions of the cells.
+ cpFloat celldim;
+
+ // BBox callback.
+ cpSpaceHashBBFunc bbfunc;
+
+ // Hashset of all the handles.
+ cpHashSet *handleSet;
+
+ cpSpaceHashBin **table;
+ // List of recycled bins.
+ cpSpaceHashBin *bins;
+
+ // Incremented on each query. See cpHandle.stamp.
+ int stamp;
+} cpSpaceHash;
+
+//Basic allocation/destruction functions.
+cpSpaceHash *cpSpaceHashAlloc(void);
+cpSpaceHash *cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc);
+cpSpaceHash *cpSpaceHashNew(cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc);
+
+void cpSpaceHashDestroy(cpSpaceHash *hash);
+void cpSpaceHashFree(cpSpaceHash *hash);
+
+// Resize the hashtable. (Does not rehash! You must call cpSpaceHashRehash() if needed.)
+void cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells);
+
+// Add an object to the hash.
+void cpSpaceHashInsert(cpSpaceHash *hash, void *obj, unsigned int id, cpBB bb);
+// Remove an object from the hash.
+void cpSpaceHashRemove(cpSpaceHash *hash, void *obj, unsigned int id);
+
+// Iterator function
+typedef void (*cpSpaceHashIterator)(void *obj, void *data);
+// Iterate over the objects in the hash.
+void cpSpaceHashEach(cpSpaceHash *hash, cpSpaceHashIterator func, void *data);
+
+// Rehash the contents of the hash.
+void cpSpaceHashRehash(cpSpaceHash *hash);
+// Rehash only a specific object.
+void cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, unsigned int id);
+
+// Query callback.
+typedef int (*cpSpaceHashQueryFunc)(void *obj1, void *obj2, void *data);
+// Point query the hash. A reference to the query point is passed as obj1 to the query callback.
+void cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpaceHashQueryFunc func, void *data);
+// Query the hash for a given BBox.
+void cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data);
+// Run a query for the object, then insert it. (Optimized case)
+void cpSpaceHashQueryInsert(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data);
+// Rehashes while querying for each object. (Optimized case)
+void cpSpaceHashQueryRehash(cpSpaceHash *hash, cpSpaceHashQueryFunc func, void *data);
diff --git a/fusion/plugins/newton/cpVect.c b/fusion/plugins/newton/cpVect.c
new file mode 100644
index 0000000..c7192a7
--- /dev/null
+++ b/fusion/plugins/newton/cpVect.c
@@ -0,0 +1,63 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+#include "stdio.h"
+#include "math.h"
+
+#include "chipmunk.h"
+
+cpFloat
+cpvlength(const cpVect v)
+{
+ return sqrtf( cpvdot(v, v) );
+}
+
+cpFloat
+cpvlengthsq(const cpVect v)
+{
+ return cpvdot(v, v);
+}
+
+cpVect
+cpvnormalize(const cpVect v)
+{
+ return cpvmult( v, 1.0f/cpvlength(v) );
+}
+
+cpVect
+cpvforangle(const cpFloat a)
+{
+ return cpv(cos(a), sin(a));
+}
+
+cpFloat
+cpvtoangle(const cpVect v)
+{
+ return atan2(v.y, v.x);
+}
+
+char*
+cpvstr(const cpVect v)
+{
+ static char str[256];
+ sprintf(str, "(% .3f, % .3f)", v.x, v.y);
+ return str;
+}
diff --git a/fusion/plugins/newton/cpVect.h b/fusion/plugins/newton/cpVect.h
new file mode 100644
index 0000000..c70c7ef
--- /dev/null
+++ b/fusion/plugins/newton/cpVect.h
@@ -0,0 +1,106 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+typedef struct cpVect{
+ cpFloat x,y;
+} cpVect;
+
+static const cpVect cpvzero={0.0f,0.0f};
+
+static inline cpVect
+cpv(const cpFloat x, const cpFloat y)
+{
+ cpVect v = {x, y};
+ return v;
+}
+
+static inline cpVect
+cpvadd(const cpVect v1, const cpVect v2)
+{
+ return cpv(v1.x + v2.x, v1.y + v2.y);
+}
+
+static inline cpVect
+cpvneg(const cpVect v)
+{
+ return cpv(-v.x, -v.y);
+}
+
+static inline cpVect
+cpvsub(const cpVect v1, const cpVect v2)
+{
+ return cpv(v1.x - v2.x, v1.y - v2.y);
+}
+
+static inline cpVect
+cpvmult(const cpVect v, const cpFloat s)
+{
+ return cpv(v.x*s, v.y*s);
+}
+
+static inline cpFloat
+cpvdot(const cpVect v1, const cpVect v2)
+{
+ return v1.x*v2.x + v1.y*v2.y;
+}
+
+static inline cpFloat
+cpvcross(const cpVect v1, const cpVect v2)
+{
+ return v1.x*v2.y - v1.y*v2.x;
+}
+
+static inline cpVect
+cpvperp(const cpVect v)
+{
+ return cpv(-v.y, v.x);
+}
+
+static inline cpVect
+cpvrperp(const cpVect v)
+{
+ return cpv(v.y, -v.x);
+}
+
+static inline cpVect
+cpvproject(const cpVect v1, const cpVect v2)
+{
+ return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2));
+}
+
+static inline cpVect
+cpvrotate(const cpVect v1, const cpVect v2)
+{
+ return cpv(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x);
+}
+
+static inline cpVect
+cpvunrotate(const cpVect v1, const cpVect v2)
+{
+ return cpv(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y);
+}
+
+cpFloat cpvlength(const cpVect v);
+cpFloat cpvlengthsq(const cpVect v); // no sqrt() call
+cpVect cpvnormalize(const cpVect v);
+cpVect cpvforangle(const cpFloat a); // convert radians to a normalized vector
+cpFloat cpvtoangle(const cpVect v); // convert a vector to radians
+char *cpvstr(const cpVect v); // get a string representation of a vector
diff --git a/fusion/plugins/newton/needsdif b/fusion/plugins/newton/needsdif
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fusion/plugins/newton/needsdif
diff --git a/fusion/plugins/newton/newton.c b/fusion/plugins/newton/newton.c
new file mode 100755
index 0000000..320d8e3
--- /dev/null
+++ b/fusion/plugins/newton/newton.c
@@ -0,0 +1,1325 @@
+/*
+ * Compiz Fusion Newton plugin
+ *
+ * Copyright (c) 2008 Patrick Nicolas <patrick.nicolas@rez-gif.supelec.fr>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Author(s):
+ * Patrick Nicolas <patrick.nicolas@rez-gif.supelec.fr>
+ *
+ * Description:
+ *
+ */
+
+#include <compiz-core.h>
+#include "newton_options.h"
+#include <compiz-mousepoll.h>
+#include <X11/Xatom.h>
+#include <math.h>
+#include "chipmunk.h"
+
+static int displayPrivateIndex;
+
+#define GET_NEWTON_DISPLAY(d) \
+ ((NewtonDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
+
+#define NEWTON_DISPLAY(d) \
+ NewtonDisplay *nd = GET_NEWTON_DISPLAY (d)
+
+#define GET_NEWTON_SCREEN(s, nd) \
+ ((NewtonScreen *) (s)->base.privates[(nd)->screenPrivateIndex].ptr)
+
+#define NEWTON_SCREEN(s) \
+ NewtonScreen *ns = GET_NEWTON_SCREEN (s, GET_NEWTON_DISPLAY (s->display))
+
+#define GET_NEWTON_WINDOW(w, ns) \
+ ((NewtonWindow *) (w)->base.privates[(ns)->windowPrivateIndex].ptr)
+
+#define NEWTON_WINDOW(w) \
+ NewtonWindow *nw = GET_NEWTON_WINDOW (w, \
+ GET_NEWTON_SCREEN (w->screen, \
+ GET_NEWTON_DISPLAY (w->screen->display)))
+
+typedef struct _NewtonDisplay {
+ int screenPrivateIndex;
+
+ Bool mouseInvert;
+
+ MousePollFunc *mpFunc;
+ HandleEventProc handleEvent;
+} NewtonDisplay;
+
+typedef struct _NewtonWaitingSpace {
+ struct _NewtonWaitingSpace *next;
+
+ Window child;
+ Window parent;
+} NewtonWaitingSpace;
+
+typedef struct _NewtonDevice {
+ CompDevice *dev;
+
+ int mouseX;
+ int mouseY;
+
+ struct _NewtonDevice *next;
+} NewtonDevice;
+
+typedef struct _NewtonScreen {
+ int windowPrivateIndex;
+ int mouseX,mouseY;
+
+ cpSpace *space;
+
+ NewtonWaitingSpace *waitingSpace;
+ NewtonDevice *devices;
+
+ PositionPollingHandle pollHandle;
+ PaintWindowProc paintWindow;
+ PreparePaintScreenProc preparePaintScreen;
+ GetAllowedActionsForWindowProc getAllowedActionsForWindow;
+
+} NewtonScreen;
+
+typedef struct _NewtonWindow {
+ Window child;
+ Window parent;
+
+ cpBody *body;
+ cpShape *shape;
+
+ Bool movable;
+ Bool repulsion;
+ Bool wasHovered;
+} NewtonWindow;
+
+
+static Bool
+isNewtonWindow (CompWindow *w)
+{
+ if (!w->mapNum || w->attrib.map_state != IsViewable)
+ {
+ return FALSE;
+ }
+
+ if (!(w->inputHint || (w->protocols & CompWindowProtocolTakeFocusMask)))
+ return FALSE;
+
+ if (w->wmType & (CompWindowTypeDockMask | CompWindowTypeDesktopMask))
+ return FALSE;
+
+ if (w->attrib.override_redirect)
+ return FALSE;
+
+ if (w->state & CompWindowStateSkipTaskbarMask)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+newtonFreeWaitingSpace (CompScreen *s)
+{
+ NEWTON_SCREEN (s);
+ NewtonWaitingSpace *wSpace, *wSpace1;
+ wSpace1 = NULL;
+
+ for (wSpace = ns->waitingSpace; wSpace ; wSpace = wSpace->next)
+ {
+ if (wSpace1)
+ free (wSpace1);
+ wSpace1 = wSpace;
+ }
+ if (wSpace1)
+ free (wSpace1);
+ ns->waitingSpace = NULL;
+}
+
+static void
+newtonWaitForChild (CompWindow* w,
+ Window child)
+{
+ NEWTON_SCREEN (w->screen);
+ NewtonWaitingSpace *wSpace;
+
+ wSpace = malloc (sizeof (NewtonWaitingSpace));
+ wSpace->next = ns->waitingSpace;
+ wSpace->child = child;
+ wSpace->parent = w->id;
+
+ ns->waitingSpace = wSpace;
+}
+
+static Window
+newtonFindParent (CompWindow *w)
+{
+ NEWTON_SCREEN (w->screen);
+ NewtonWaitingSpace *wSpace;
+ Window parent;
+
+ parent = 0;
+ wSpace = ns->waitingSpace;
+
+ while (!parent && wSpace)
+ {
+ if (wSpace->child == w->id)
+ parent = wSpace->parent;
+ wSpace = wSpace->next;
+ }
+ return parent;
+}
+
+/* Device management */
+
+static Bool
+newtonAddDevToList (CompScreen *s,
+ CompDevice *dev)
+{
+ NEWTON_SCREEN (s);
+
+ NewtonDevice *run;
+
+ if (!ns->devices)
+ {
+ ns->devices = calloc (1, sizeof(NewtonDevice));
+ if (!ns->devices)
+ return FALSE;
+ ns->devices->dev = dev;
+ ns->devices->next = NULL;
+ }
+ else
+ {
+ for (run = ns->devices; run->next; run = run->next);
+ run->next = calloc (1, sizeof(NewtonDevice));
+ if (!run->next)
+ return FALSE;
+ run->next->dev = dev;
+ run->next->next = NULL;
+ }
+ return TRUE;
+}
+
+static void
+newtonRemoveDevFromList (CompScreen *s,
+ CompDevice *dev)
+{
+ NEWTON_SCREEN (s);
+
+ NewtonDevice *run;
+
+ if (!ns->devices)
+ return;
+
+ if (run == ns->devices)
+ {
+ if (ns->devices->next)
+ ns->devices = ns->devices->next;
+ else
+ ns->devices = NULL;
+ if (run)
+ free (run);
+ }
+ else
+ {
+ for (run = ns->devices; run; run = run->next)
+ {
+ if (run->dev == dev)
+ break;
+ }
+
+ NewtonDevice *selected = run;
+
+ if (selected)
+ if (selected->next)
+ {
+ selected = selected->next;
+ if (selected)
+ free(selected);
+ }
+ }
+}
+
+static void
+newtonCheckList (CompScreen *s,
+ MousepollDevice *list)
+{
+ NEWTON_SCREEN (s);
+ Bool ok = FALSE;
+ MousepollDevice *run;
+ NewtonDevice *ptr;
+ CompDevice *addDev = NULL, *removeDev = NULL;
+
+ do
+ {
+ for (run = list; run; run = run->next)
+ {
+ addDev = run->dev;
+ for (ptr = ns->devices; ptr; ptr = ptr->next)
+ {
+ if (ptr->dev == run->dev)
+ {
+ addDev = NULL;
+ break;
+ }
+ }
+ if (addDev) break;
+ }
+
+ for (ptr = ns->devices; ptr; ptr = ptr->next)
+ {
+ removeDev = ptr->dev;
+ for (run = list; run; run = run->next)
+ {
+ if (run->dev == ptr->dev)
+ {
+ removeDev = NULL;
+ break;
+ }
+ }
+ if (removeDev) break;
+ }
+
+ if (addDev)
+ newtonAddDevToList (s, addDev);
+
+ if (removeDev)
+ newtonRemoveDevFromList (s, removeDev);
+
+ if (addDev || removeDev)
+ ok = FALSE;
+ else
+ ok = TRUE;
+ } while (!ok);
+}
+
+static void
+positionUpdate (CompScreen *s,
+ MousepollDevice *mDev)
+{
+ NEWTON_SCREEN (s);
+ MousepollDevice *run = mDev;
+ NewtonDevice *nDev;
+
+ newtonCheckList (s, mDev);
+
+ for (; run; run = run->next)
+ {
+ for (nDev = ns->devices; nDev; nDev = nDev->next)
+ {
+ if (nDev->dev == run->dev)
+ {
+ nDev->mouseX = run->posX;
+ nDev->mouseY = run->posY;
+ }
+ }
+ }
+}
+
+static Bool
+newtonAddMiniwindow (CompWindow *w)
+{
+ int x,y;
+ int width, height;
+ XSetWindowAttributes attr;
+ Atom state[4];
+ int nState = 0;
+ float ratio;
+ XSizeHints xsh;
+ XWMHints xwmh;
+ NEWTON_WINDOW (w);
+
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.override_redirect= TRUE;
+
+ x = w-> serverX + w->width /2;
+ y = w-> serverY + w->height/2;
+
+ ratio = (float) w->width / w->height;
+ width = (ratio>1.0f) ? newtonGetMiniwindowsize (w->screen->display) : ratio * newtonGetMiniwindowsize (w->screen->display) ;
+ height = (ratio<1.0f) ? newtonGetMiniwindowsize (w->screen->display) : newtonGetMiniwindowsize (w->screen->display) / ratio;
+
+ nw->child = XCreateWindow (w->screen->display->display,
+ w->screen->root,
+ x,//x
+ y,//y
+ width,//width
+ height,//heigth
+ 0,//border width
+ 0,//depth
+ InputOutput,//window class
+ CopyFromParent,// visual
+ CWOverrideRedirect | CWBackPixel | CWBorderPixel,
+ &attr);
+ newtonWaitForChild (w, nw->child);
+
+ xsh.flags = PSize | PPosition | PWinGravity;
+ xsh.width = width;
+ xsh.height = height;
+ xsh.win_gravity = StaticGravity;
+
+ xwmh.flags = InputHint;
+ xwmh.input = 0;
+
+ XSetWMProperties (w->screen->display->display,
+ nw->child,
+ NULL,
+ NULL,
+ programArgv, programArgc,
+ &xsh,
+ &xwmh,
+ NULL);
+
+ state[nState++] = w->screen->display->winStateAboveAtom;
+ //state[nState++] = w->screen->display->winStateStickyAtom;
+ state[nState++] = w->screen->display->winStateSkipTaskbarAtom;
+ state[nState++] = w->screen->display->winStateSkipPagerAtom;
+
+ XChangeProperty (w->screen->display->display,
+ nw->child,
+ w->screen->display->winStateAtom,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char *) state,
+ nState);
+
+ XChangeProperty (w->screen->display->display, nw->child,
+ w->screen->display->winTypeAtom,
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *) &w->screen->display->winTypeUtilAtom, 1);
+
+ setWindowProp (w->screen->display, nw->child,
+ w->screen->display->winDesktopAtom,
+ 0xffffffff);
+
+ XMapWindow (w->screen->display->display, nw->child);
+
+ return TRUE;
+}
+
+static Bool
+newtonToggleMiniwindow (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ CompWindow *w = findWindowAtDisplay (d, d->activeWindow);
+ if (!w)
+ return TRUE;
+ NEWTON_WINDOW (w);
+
+ if (nw->child)
+ {
+ XDestroyWindow (w->screen->display->display, nw->child);
+ nw->child = 0;
+ }
+ else
+ {
+ newtonAddMiniwindow (w);
+ }
+ return TRUE;
+}
+
+static void
+newtonGetAllowedActionsForWindow (CompWindow *w,
+ unsigned int *setActions,
+ unsigned int *clearActions)
+{
+ NEWTON_SCREEN (w->screen);
+ NEWTON_WINDOW (w);
+
+ UNWRAP (ns, w->screen, getAllowedActionsForWindow);
+ (*w->screen->getAllowedActionsForWindow) (w, setActions, clearActions);
+ WRAP (ns, w->screen, getAllowedActionsForWindow, newtonGetAllowedActionsForWindow);
+
+ if (nw->parent)
+ *clearActions |= CompWindowActionMoveMask|CompWindowActionResizeMask|CompWindowActionMinimizeMask|CompWindowActionCloseMask;
+}
+
+static void
+newtonUpdateMiniwindowSize (CompWindow *w)
+{
+ NEWTON_WINDOW (w);
+ NEWTON_SCREEN (w->screen);
+ XWindowChanges xwc;
+ CompWindow *parentCW;
+ float ratio;
+ int size = newtonGetMiniwindowsize (w->screen->display);
+
+ parentCW = findWindowAtDisplay (w->screen->display, nw->parent);
+
+ if (!parentCW)
+ return;
+
+ ratio = (float) parentCW->width / parentCW->height;
+ xwc.width = (ratio>1.0f) ? size : ratio * size;
+ xwc.height = (ratio<1.0f)? size : size / ratio;
+
+ cpVect verts[] = {cpv (-xwc.width/2 , -xwc.height/2),
+ cpv (-xwc.width/2 , xwc.height/2),
+ cpv ( xwc.width/2 , xwc.height/2),
+ cpv ( xwc.width/2 , -xwc.height/2)};
+
+ if (nw->shape)
+ {
+ cpSpaceRemoveShape (ns->space, nw->shape);
+ cpShapeFree (nw->shape);
+ nw->shape = cpPolyShapeNew (nw->body,
+ 4,
+ verts,
+ cpvzero);
+ nw->shape->e = 0.0; nw->shape->u = 0.8;
+ cpSpaceAddShape (ns->space, nw->shape);
+ cpBodySetMass (nw->body, xwc.width*xwc.height);
+ }
+ XConfigureWindow (w->screen->display->display,
+ w->id,
+ CWWidth | CWHeight,
+ &xwc);
+ addWindowDamage (w);
+}
+
+static void
+newtonSetPhysics (CompWindow *w)
+{
+ NEWTON_WINDOW (w);
+ NEWTON_SCREEN (w->screen);
+ cpVect verts[] = {
+ cpv (-w->width/2 , -w->height/2),
+ cpv (-w->width/2 , w->height/2),
+ cpv ( w->width/2 , w->height/2),
+ cpv ( w->width/2 , -w->height/2)
+ };
+
+ if (!nw->body)
+ {
+ nw->body = cpBodyNew (w->width * w->height, INFINITY);
+ nw->body->p = cpv (w->attrib.x + w->width/2,
+ w->attrib.y + w->height/2);
+ cpSpaceAddBody(ns->space, nw->body);
+ }
+
+ if (!nw->shape)
+ {
+ nw->shape = cpPolyShapeNew (nw->body,
+ 4,
+ verts,
+ cpvzero);
+ nw->shape->e = newtonGetBounceConstant (w->screen->display); nw->shape->u = 0.8;
+ cpSpaceAddShape (ns->space, nw->shape);
+ nw->movable = TRUE;
+ }
+}
+
+static void
+newtonSetNoPhysics (CompWindow *w)
+{
+ NEWTON_WINDOW (w);
+ NEWTON_SCREEN (w->screen);
+
+ if (nw->body)
+ {
+ cpSpaceRemoveBody (ns->space, nw->body);
+ cpBodyFree (nw->body);
+ nw->body = NULL;
+ }
+ if (nw->shape)
+ {
+ cpSpaceRemoveShape (ns->space, nw->shape);
+ cpShapeFree (nw->shape);
+ nw->shape = NULL;
+ }
+ nw->movable = FALSE;
+}
+
+static void
+newtonHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ CompWindow *w;
+ NewtonWindow *nw;
+ NewtonScreen *ns;
+
+ NEWTON_DISPLAY (d);
+
+ UNWRAP (nd, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (nd, d, handleEvent, newtonHandleEvent);
+
+ switch (event->type)
+ {
+ case ButtonPress:
+ w = findWindowAtDisplay (d, event->xbutton.window);
+ if (w)
+ {
+ ns = GET_NEWTON_SCREEN (w->screen, nd);
+ nw = GET_NEWTON_WINDOW (w, ns);
+ // when a window is clicked and it has a parent, the parent window is selected
+ if (nw->parent)
+ sendWindowActivationRequest (w->screen, nw->parent);
+ }
+ break;
+
+ case MapNotify:
+ w = findWindowAtDisplay (d, event->xmap.window);
+ if (w)
+ {
+ ns = GET_NEWTON_SCREEN (w->screen, nd);
+ nw = GET_NEWTON_WINDOW (w, ns);
+ if (isNewtonWindow (w))
+ {
+ nw->repulsion = TRUE;
+ if (! findWindowAtDisplay (d, nw->child))
+ newtonAddMiniwindow(w);
+ }
+ }
+ break;
+
+ case UnmapNotify:
+ w = findWindowAtDisplay (d, event->xunmap.window);
+ if (w)
+ {
+ ns = GET_NEWTON_SCREEN (w->screen, nd);
+ nw = GET_NEWTON_WINDOW (w, ns);
+ nw->repulsion = FALSE;
+
+ newtonSetNoPhysics (w);
+ }
+
+ break;
+
+ case ConfigureNotify:
+ w = findWindowAtDisplay (d, event->xconfigure.window);
+ if (w)
+ {
+ ns = GET_NEWTON_SCREEN (w->screen, nd);
+ nw = GET_NEWTON_WINDOW (w, ns);
+ CompWindow *wchild = findWindowAtDisplay (d,nw->child);
+
+ if (wchild)
+ newtonUpdateMiniwindowSize(wchild);
+ }
+ }
+}
+
+static Bool
+newtonTogglePhysics (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ CompWindow *w = findWindowAtDisplay (d, d->activeWindow);
+ if (!w)
+ return TRUE;
+
+ NEWTON_WINDOW (w);
+
+ if (!nw->shape)
+ {
+ newtonSetPhysics (w);
+ }
+ else
+ {
+ newtonSetNoPhysics (w);
+ }
+
+ return TRUE;
+
+}
+
+static Bool
+newtonToggleMovable (CompWindow *w)
+{
+ NEWTON_WINDOW (w);
+ NEWTON_SCREEN (w->screen);
+
+ if (nw->shape && nw->body)
+ {
+ if (nw->movable)
+ {
+ nw->movable = FALSE;
+ cpSpaceRemoveBody (ns->space, nw->body);
+ nw->body->v = cpvzero;
+ }
+ else
+ {
+ nw->body->p = cpv (w->attrib.x + w->width/2,
+ w->attrib.y + w->height/2);
+ nw->movable = TRUE;
+ cpSpaceAddBody (ns->space, nw->body);
+ }
+ }
+ return TRUE;
+}
+
+static Bool
+newtonMouseInvert (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ NEWTON_DISPLAY (d);
+ nd->mouseInvert = !nd->mouseInvert;
+
+ return TRUE;
+}
+
+static void
+newtonMiniwindowsizeNotify (CompDisplay *d,
+ CompOption *opt,
+ NewtonDisplayOptions num)
+{
+ CompScreen *s;
+ CompWindow *w;
+
+ NewtonWindow *nw;
+ NewtonScreen *ns;
+ NEWTON_DISPLAY (d);
+
+ for (s = d->screens ; s ; s = s->next)
+ {
+ ns = GET_NEWTON_SCREEN (s, nd);
+ cpSpaceResizeActiveHash(ns->space, newtonGetMiniwindowsize (d), 500);
+ for (w = s->windows; w; w = w->next)
+ {
+ nw = GET_NEWTON_WINDOW (w, ns);
+ if (nw->parent)
+ newtonUpdateMiniwindowSize (w);
+ }
+ }
+}
+
+static void
+newtonElasticityNotify (CompDisplay *d,
+ CompOption *opt,
+ NewtonDisplayOptions num)
+{
+ CompScreen *s;
+ CompWindow *w;
+
+ NewtonWindow *nw;
+ NewtonScreen *ns;
+ NEWTON_DISPLAY (d);
+
+ cpFloat elasticity = newtonGetBounceConstant (d);
+
+ for (s = d->screens ; s ; s = s->next)
+ {
+ ns = GET_NEWTON_SCREEN (s, nd);
+ for (w = s->windows; w; w = w->next)
+ {
+ nw = GET_NEWTON_WINDOW (w, ns);
+ if (nw->shape)
+ nw->shape->e = elasticity;
+ }
+ }
+}
+
+static void
+newtonGravityNotify (CompDisplay *d,
+ CompOption *opt,
+ NewtonDisplayOptions num)
+{
+ CompScreen *s;
+ NewtonScreen *ns;
+ NEWTON_DISPLAY (d);
+ for (s = d->screens ; s ; s = s->next)
+ {
+ ns = GET_NEWTON_SCREEN (s, nd);
+ ns->space->gravity = cpv (0,(cpFloat)newtonGetGravity (d));
+ }
+}
+
+static void
+newtonFrictionNotify (CompDisplay *d,
+ CompOption *opt,
+ NewtonDisplayOptions num)
+{
+ CompScreen *s;
+ NewtonScreen *ns;
+ NEWTON_DISPLAY (d);
+ for (s = d->screens ; s ; s = s->next)
+ {
+ ns = GET_NEWTON_SCREEN (s, nd);
+ ns->space->damping = (cpFloat)newtonGetFrictionConstant (d);
+ }
+}
+
+static void
+newtonPreparePaintScreen (CompScreen *s,
+ int msSinceLastPaint)
+{
+ CompWindow *w, *w1;
+ NewtonWindow *nw, *nw1;
+
+ NEWTON_SCREEN (s);
+ NEWTON_DISPLAY (s->display);
+
+ //mouse position
+ if ( (newtonGetMouseAttraction (s->display) || newtonGetMouseStop (s->display))
+ && !ns->pollHandle)
+ {
+ ns->pollHandle = (*nd->mpFunc->addPositionPolling) (s, NULL, positionUpdate);
+ }
+
+ //calculate forces
+ for (w = s->windows; w; w = w->next)
+ {
+ nw = GET_NEWTON_WINDOW (w,ns);
+
+ if (nw->shape && nw->body)
+ {
+ cpBodyResetForces (nw->body);
+ //---repulsion between windows---
+ for (w1=s->reverseWindows; w1; w1=w1->prev)
+ {
+ nw1 = GET_NEWTON_WINDOW (w1,ns);
+
+ if ( (w != w1)
+ && nw1->repulsion
+ && ! ((w->screen != w1->screen)
+ || (w1->attrib.x > w->attrib.x + w->width)
+ || (w1->attrib.x + w1->width < w->attrib.x)
+ || (w1->attrib.y > w->attrib.y + w->height)
+ || (w1->attrib.y + w1->height < w->attrib.y) ) )
+ {
+ int xc,xc1,yc,yc1;
+ xc = w->attrib.x + w->width/2;
+ xc1= w1->attrib.x + w1->width/2;
+ yc = w->attrib.y + w->height/2;
+ yc1= w1->attrib.y + w1->height/2;
+
+
+//+------------------+
+//| |
+//| (xc1,yc1) |
+//| + |
+//| +------+----------+
+//| | | |
+//+-----------+------+ |
+// | + |
+// | (xc,yc) |
+// | |
+// +-----------------+
+//
+//We assume the horizontal repulsion is proportional to the length of the
+//overlapping portion. same thing for the vertical strength.
+//
+//In this situation the horizontal component is :
+//k * (x1+width1 - x)
+//
+//we determine the direction (and the sides to consider) by checking the relative
+//position of the centers (xc1 < xc in our situation)
+
+ //horizontal component
+ if (xc > xc1)
+ {
+ cpBodyApplyForce (nw->body,
+ cpv ((cpFloat) 10*newtonGetWindowElasticityConstant (s->display) *
+ (w->attrib.x + w->width - w1->attrib.x),
+ 0),
+ cpvzero);
+ }
+ else
+ {
+ cpBodyApplyForce (nw->body,
+ cpv ((cpFloat) -10*newtonGetWindowElasticityConstant (s->display) *
+ (w1->attrib.x + w1->width - w->attrib.x),
+ 0),
+ cpvzero);
+ }
+ //vertical component
+ if (yc > yc1)
+ {
+ cpBodyApplyForce (nw->body,
+ cpv (0,
+ (cpFloat) 10*newtonGetWindowElasticityConstant (s->display) *
+ (w->attrib.y + w->height - w1->attrib.y)),
+ cpvzero);
+ }
+ else
+ {
+ cpBodyApplyForce (nw->body,
+ cpv (0,
+ (cpFloat) -10*newtonGetWindowElasticityConstant (s->display) *
+ (w1->attrib.y + w1->height - w->attrib.y)),
+ cpvzero);
+ }
+
+ }
+ }
+
+ //---mouse attraction---
+ if (newtonGetMouseAttraction (s->display))
+ {
+ NewtonDevice *nDev;
+ int distanceX, distanceY, d2;
+ for (nDev = ns->devices; nDev; nDev = nDev->next)
+ {
+ distanceX = nw->body->p.x - nDev->mouseX;
+ distanceY = nw->body->p.y - nDev->mouseY;
+ d2 = distanceX*distanceX + distanceY*distanceY;
+ d2 = (d2<100)?100:d2;
+
+ if (d2 != 0)
+ {
+ cpBodyApplyForce (nw->body,
+ cpv ((cpFloat) 1000000000*(nd->mouseInvert?-1:1)*newtonGetMouseStrength (s->display) * distanceX / (sqrt (d2) * d2),
+ (cpFloat) 1000000000*(nd->mouseInvert?-1:1)*newtonGetMouseStrength (s->display) * distanceY / (sqrt (d2) * d2)),
+ cpvzero);
+ }
+ }
+ }
+
+ //---stop if under mouse---
+ if (newtonGetMouseStop (s->display))
+ {
+ NewtonDevice *nDev;
+ for (nDev = ns->devices; nDev; nDev = nDev->next)
+ {
+ if (w->region && XPointInRegion (w->region, nDev->mouseX, nDev->mouseY))
+ {
+ if (!nw->wasHovered && nw->movable)
+ {
+ cpSpaceRemoveBody (ns->space, nw->body);
+ nw->body->v = cpvzero;
+ nw->wasHovered = TRUE;
+ }
+ }
+ else
+ {
+ if (nw->wasHovered && nw->movable)
+ {
+ cpSpaceAddBody (ns->space, nw->body);
+ nw->wasHovered = FALSE;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ cpSpaceStep (ns->space, (cpFloat) msSinceLastPaint/1000);
+
+ //---update positions---
+ for (w = s->windows; w; w = w->next)
+ {
+ nw = GET_NEWTON_WINDOW (w,ns);
+ if (nw->body)
+ {
+ if (nw->movable && !nw->wasHovered)
+ {
+ moveWindow (w,
+ (int)nw->body->p.x - w->width /2 - w->attrib.x,
+ (int)nw->body->p.y - w->height /2 - w->attrib.y,
+ TRUE,
+ FALSE);
+ syncWindowPosition (w);
+ }
+ else
+ {
+ nw->body->p = cpv(w->attrib.x + w->width/2,
+ w->attrib.y + w->height/2);
+ }
+ }
+
+ }
+
+ UNWRAP (ns, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, msSinceLastPaint);
+ WRAP (ns, s, preparePaintScreen, newtonPreparePaintScreen);
+}
+
+static Bool
+newtonPaintWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib,
+ const CompTransform *transform,
+ Region region,
+ unsigned int mask)
+{
+ Bool status;
+ CompWindow *wchild, *parentCW;
+
+ NEWTON_WINDOW (w);
+ NEWTON_SCREEN (w->screen);
+
+ UNWRAP (ns, w->screen, paintWindow);
+ status = (*w->screen->paintWindow) (w, attrib, transform, region, mask);
+ WRAP (ns, w->screen, paintWindow, newtonPaintWindow);
+
+ if (nw->parent)
+ {
+ mask |= PAINT_WINDOW_TRANSFORMED_MASK;
+
+ parentCW = findWindowAtDisplay (w->screen->display, nw->parent);
+
+ if (parentCW && parentCW->mapNum && parentCW->texture->pixmap)
+ {
+ CompTransform xTransform = *transform;
+ AddWindowGeometryProc oldAddWindowGeometry;
+ WindowPaintAttrib xAttrib = *attrib;
+ FragmentAttrib fragment;
+
+ xAttrib.xScale = (float) w->width / parentCW->width;
+ xAttrib.yScale = xAttrib.xScale;
+
+ xAttrib.xTranslate = w->attrib.x - parentCW->attrib.x + parentCW->input.left * xAttrib.xScale;
+ xAttrib.yTranslate = w->attrib.y - parentCW->attrib.y + parentCW->input.top * xAttrib.yScale;
+
+ initFragmentAttrib (&fragment, &xAttrib);
+
+ if (parentCW->alpha || fragment.opacity != OPAQUE)
+ mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+
+ matrixTranslate (&xTransform, parentCW->attrib.x, parentCW->attrib.y, 0.0f);
+ matrixScale (&xTransform, xAttrib.xScale, xAttrib.yScale, 1.0f);
+ matrixTranslate (&xTransform,
+ xAttrib.xTranslate / xAttrib.xScale - parentCW->attrib.x,
+ xAttrib.yTranslate / xAttrib.yScale - parentCW->attrib.y,
+ 0.0f);
+ glPushMatrix ();
+ glLoadMatrixf (xTransform.m);
+
+ oldAddWindowGeometry = w->screen->addWindowGeometry;
+ w->screen->addWindowGeometry = addWindowGeometry;
+ (w->screen->drawWindow) (parentCW, &xTransform, &fragment, &infiniteRegion, mask);
+ w->screen->addWindowGeometry = oldAddWindowGeometry;
+
+ glPopMatrix ();
+
+ }
+ else
+ {
+ //TODO : draw something (icon maybe)
+ }
+
+ }
+ else
+ {
+
+ wchild = findWindowAtDisplay (w->screen->display, nw->child);
+ if (wchild)
+ addWindowDamage (wchild);
+ }
+
+ return status;
+}
+
+static Bool
+newtonInitWindow (CompPlugin *p,
+ CompWindow *w)
+{
+ NewtonWindow *nw;
+
+ NEWTON_SCREEN (w->screen);
+
+ nw = malloc (sizeof (NewtonWindow));
+ if (!nw)
+ return FALSE;
+
+ w->base.privates[ns->windowPrivateIndex].ptr = nw;
+
+ nw->repulsion = FALSE;
+ nw->wasHovered = FALSE;
+
+ nw->parent = newtonFindParent (w);
+
+ nw->shape = NULL;
+ nw->body = NULL;
+
+ nw->child = NULL;
+
+ if (nw->parent)
+ {
+ //the window is a child window, it can be moved (by physics)
+ newtonSetPhysics (w);
+ nw->repulsion = TRUE;
+ }
+ else
+ {
+ if (isNewtonWindow (w))
+ {
+ nw->repulsion = TRUE;
+ if (newtonGetDrawMiniwindows (w->screen->display))
+ {
+ //the window needs a miniwindow, let's create it
+ newtonAddMiniwindow (w);
+ }
+ }
+ else
+ {
+ if (w->region
+ && (w->state & CompWindowStateSkipTaskbarMask)
+ && w->mapNum
+ && ! (w->wmType & CompWindowTypeDesktopMask))
+ {
+ newtonSetPhysics (w);
+ newtonToggleMovable (w);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+newtonFiniWindow (CompPlugin *p,
+ CompWindow *w)
+{
+ NEWTON_WINDOW (w);
+
+ if (nw->child)
+ {
+ XDestroyWindow (w->screen->display->display, nw->child);
+ }
+ newtonSetNoPhysics (w);
+
+ free (nw);
+}
+
+static Bool
+newtonInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ NewtonDisplay *nd;
+ int mousepollIndex;
+
+ if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+ !checkPluginABI ("mousepoll", MOUSEPOLL_ABIVERSION))
+ return FALSE;
+
+ if (!getPluginDisplayIndex (d, "mousepoll", &mousepollIndex))
+ return FALSE;
+
+ nd = malloc (sizeof (NewtonDisplay));
+ if (!nd)
+ return FALSE;
+
+ nd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (nd->screenPrivateIndex < 0)
+ {
+ free (nd);
+ return FALSE;
+ }
+
+ nd->mpFunc = d->base.privates[mousepollIndex].ptr;
+
+ nd->mouseInvert = newtonGetMouseAttractionMode (d);
+
+ newtonSetMiniwindowsizeNotify (d, newtonMiniwindowsizeNotify);
+ newtonSetGravityNotify (d, newtonGravityNotify);
+ newtonSetBounceConstantNotify (d, newtonElasticityNotify);
+ newtonSetFrictionConstantNotify (d, newtonFrictionNotify);
+ newtonSetTriggerPhysicsKeyInitiate (d, newtonTogglePhysics);
+ newtonSetMouseInvertKeyInitiate (d, newtonMouseInvert);
+ newtonSetMouseInvertKeyTerminate (d, newtonMouseInvert);
+ newtonSetToggleMiniwindowKeyInitiate (d, newtonToggleMiniwindow);
+
+ WRAP (nd, d, handleEvent, newtonHandleEvent);
+
+ d->base.privates[displayPrivateIndex].ptr = nd;
+
+ return TRUE;
+}
+
+static void
+newtonFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ NEWTON_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, nd->screenPrivateIndex);
+
+ UNWRAP (nd, d, handleEvent);
+
+ free (nd);
+}
+
+static Bool
+newtonInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ NewtonScreen *ns;
+ cpShape *shape;
+ cpBody *staticBody;
+ REGION *region;
+ int i;
+
+ NEWTON_DISPLAY (s->display);
+
+ ns = malloc (sizeof (NewtonScreen));
+ if (!ns)
+ return FALSE;
+
+ ns->windowPrivateIndex = allocateWindowPrivateIndex (s);
+
+ ns->pollHandle = 0;
+
+ ns->waitingSpace = NULL;
+ ns->devices = NULL;
+
+ ns->space = cpSpaceNew ();
+ ns->space->gravity = cpv(0, newtonGetGravity (s->display));
+ ns->space->damping = newtonGetFrictionConstant (s->display);
+ cpSpaceResizeActiveHash(ns->space, newtonGetMiniwindowsize(s->display), 500);
+
+ staticBody = cpBodyNew(INFINITY, INFINITY);
+
+ shape = cpSegmentShapeNew (staticBody, cpv (s->x,s->y), cpv (s->x + s->width ,s->y), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ shape = cpSegmentShapeNew (staticBody, cpv (s->x + s->width,s->y), cpv (s->x + s->width,s->y + s->height), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ shape = cpSegmentShapeNew (staticBody, cpv (s->x + s->width,s->y + s->height), cpv (s->x,s->y + s->height), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ shape = cpSegmentShapeNew (staticBody, cpv (s->x,s->y + s->height), cpv (s->x,s->y), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ region = XCreateRegion ();
+ XUnionRegion (region, &s->region, region);
+ for (i=0; i < s->nOutputDev ; i++)
+ {
+ XSubtractRegion (region, &s->outputDev[i].region, region);
+ }
+ for (i=0; i< region->numRects ; i++)
+ {
+ shape = cpSegmentShapeNew (staticBody,
+ cpv (region->rects[i].x1,region->rects[i].y1),
+ cpv (region->rects[i].x1,region->rects[i].y2), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ shape = cpSegmentShapeNew (staticBody,
+ cpv (region->rects[i].x1,region->rects[i].y2),
+ cpv (region->rects[i].x2,region->rects[i].y2), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ shape = cpSegmentShapeNew (staticBody,
+ cpv (region->rects[i].x2,region->rects[i].y2),
+ cpv (region->rects[i].x2,region->rects[i].y1), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ shape = cpSegmentShapeNew (staticBody,
+ cpv (region->rects[i].x2,region->rects[i].y1),
+ cpv (region->rects[i].x1,region->rects[i].y1), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+ }
+
+ WRAP (ns, s, paintWindow, newtonPaintWindow);
+ WRAP (ns, s, preparePaintScreen, newtonPreparePaintScreen);
+ WRAP (ns, s, getAllowedActionsForWindow, newtonGetAllowedActionsForWindow);
+
+ s->base.privates[nd->screenPrivateIndex].ptr = ns;
+
+ return TRUE;
+}
+
+static void
+newtonFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ NEWTON_SCREEN (s);
+ NEWTON_DISPLAY (s->display);
+
+ freeWindowPrivateIndex (s, ns->windowPrivateIndex);
+
+ cpSpaceFree (ns->space);
+
+ newtonFreeWaitingSpace (s);
+
+ if (ns->pollHandle)
+ (*nd->mpFunc->removePositionPolling) (s, ns->pollHandle);
+
+ UNWRAP (ns, s, paintWindow);
+ UNWRAP (ns, s, preparePaintScreen);
+ UNWRAP (ns, s, getAllowedActionsForWindow);
+
+ free (ns);
+}
+
+static CompBool
+newtonInitObject (CompPlugin *p,
+ CompObject *o)
+{
+ static InitPluginObjectProc dispTab[] = {
+ (InitPluginObjectProc) 0, /* InitCore */
+ (InitPluginObjectProc) newtonInitDisplay,
+ (InitPluginObjectProc) newtonInitScreen,
+ (InitPluginObjectProc) newtonInitWindow
+ };
+
+ RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
+}
+
+static void
+newtonFiniObject (CompPlugin *p,
+ CompObject *o)
+{
+ static FiniPluginObjectProc dispTab[] = {
+ (FiniPluginObjectProc) 0, /* FiniCore */
+ (FiniPluginObjectProc) newtonFiniDisplay,
+ (FiniPluginObjectProc) newtonFiniScreen,
+ (FiniPluginObjectProc) newtonFiniWindow
+ };
+
+ DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
+}
+
+static Bool
+newtonInit (CompPlugin *p)
+{
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ {
+ return FALSE;
+ }
+ cpInitChipmunk ();
+
+ return TRUE;
+}
+
+static void
+newtonFini (CompPlugin *p)
+{
+ freeDisplayPrivateIndex (displayPrivateIndex);
+}
+
+
+CompPluginVTable newtonVTable = {
+ "newton",
+ 0,//switchGetMetadata,
+ newtonInit,
+ newtonFini,
+ newtonInitObject,
+ newtonFiniObject,
+ 0,//switchGetObjectOptions,
+ 0,//switchSetObjectOption
+};
+
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &newtonVTable;
+}
diff --git a/fusion/plugins/newton/newton.c~ b/fusion/plugins/newton/newton.c~
new file mode 100644
index 0000000..f233d9f
--- /dev/null
+++ b/fusion/plugins/newton/newton.c~
@@ -0,0 +1,1326 @@
+/*
+ * Compiz Fusion Newton plugin
+ *
+ * Copyright (c) 2008 Patrick Nicolas <patrick.nicolas@rez-gif.supelec.fr>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Author(s):
+ * Patrick Nicolas <patrick.nicolas@rez-gif.supelec.fr>
+ *
+ * Description:
+ *
+ */
+
+#include <compiz-core.h>
+#include "newton_options.h"
+#include <compiz-mousepoll.h>
+#include <X11/Xatom.h>
+#include <math.h>
+#include "chipmunk.h"
+
+static int displayPrivateIndex;
+
+#define GET_NEWTON_DISPLAY(d) \
+ ((NewtonDisplay *) (d)->base.privates[displayPrivateIndex].ptr)
+
+#define NEWTON_DISPLAY(d) \
+ NewtonDisplay *nd = GET_NEWTON_DISPLAY (d)
+
+#define GET_NEWTON_SCREEN(s, nd) \
+ ((NewtonScreen *) (s)->base.privates[(nd)->screenPrivateIndex].ptr)
+
+#define NEWTON_SCREEN(s) \
+ NewtonScreen *ns = GET_NEWTON_SCREEN (s, GET_NEWTON_DISPLAY (s->display))
+
+#define GET_NEWTON_WINDOW(w, ns) \
+ ((NewtonWindow *) (w)->base.privates[(ns)->windowPrivateIndex].ptr)
+
+#define NEWTON_WINDOW(w) \
+ NewtonWindow *nw = GET_NEWTON_WINDOW (w, \
+ GET_NEWTON_SCREEN (w->screen, \
+ GET_NEWTON_DISPLAY (w->screen->display)))
+
+typedef struct _NewtonDisplay {
+ int screenPrivateIndex;
+
+ Bool mouseInvert;
+
+ MousePollFunc *mpFunc;
+ HandleEventProc handleEvent;
+} NewtonDisplay;
+
+typedef struct _NewtonWaitingSpace {
+ struct _NewtonWaitingSpace *next;
+
+ Window child;
+ Window parent;
+} NewtonWaitingSpace;
+
+typedef struct _NewtonDevice {
+ CompDevice *dev;
+
+ int mouseX;
+ int mouseY;
+
+ struct _NewtonDevice *next;
+} NewtonDevice;
+
+typedef struct _NewtonScreen {
+ int windowPrivateIndex;
+ int mouseX,mouseY;
+
+ cpSpace *space;
+
+ NewtonWaitingSpace *waitingSpace;
+ NewtonDevice *devices;
+
+ PositionPollingHandle pollHandle;
+ PaintWindowProc paintWindow;
+ PreparePaintScreenProc preparePaintScreen;
+ GetAllowedActionsForWindowProc getAllowedActionsForWindow;
+
+} NewtonScreen;
+
+typedef struct _NewtonWindow {
+ Window child;
+ Window parent;
+
+ cpBody *body;
+ cpShape *shape;
+
+ Bool movable;
+ Bool repulsion;
+ Bool wasHovered;
+} NewtonWindow;
+
+
+static Bool
+isNewtonWindow (CompWindow *w)
+{
+ if (!w->mapNum || w->attrib.map_state != IsViewable)
+ {
+ return FALSE;
+ }
+
+ if (!(w->inputHint || (w->protocols & CompWindowProtocolTakeFocusMask)))
+ return FALSE;
+
+ if (w->wmType & (CompWindowTypeDockMask | CompWindowTypeDesktopMask))
+ return FALSE;
+
+ if (w->attrib.override_redirect)
+ return FALSE;
+
+ if (w->state & CompWindowStateSkipTaskbarMask)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+newtonFreeWaitingSpace (CompScreen *s)
+{
+ NEWTON_SCREEN (s);
+ NewtonWaitingSpace *wSpace, *wSpace1;
+ wSpace1 = NULL;
+
+ for (wSpace = ns->waitingSpace; wSpace ; wSpace = wSpace->next)
+ {
+ if (wSpace1)
+ free (wSpace1);
+ wSpace1 = wSpace;
+ }
+ if (wSpace1)
+ free (wSpace1);
+ ns->waitingSpace = NULL;
+}
+
+static void
+newtonWaitForChild (CompWindow* w,
+ Window child)
+{
+ NEWTON_SCREEN (w->screen);
+ NewtonWaitingSpace *wSpace;
+
+ wSpace = malloc (sizeof (NewtonWaitingSpace));
+ wSpace->next = ns->waitingSpace;
+ wSpace->child = child;
+ wSpace->parent = w->id;
+
+ ns->waitingSpace = wSpace;
+}
+
+static Window
+newtonFindParent (CompWindow *w)
+{
+ NEWTON_SCREEN (w->screen);
+ NewtonWaitingSpace *wSpace;
+ Window parent;
+
+ parent = 0;
+ wSpace = ns->waitingSpace;
+
+ while (!parent && wSpace)
+ {
+ if (wSpace->child == w->id)
+ parent = wSpace->parent;
+ wSpace = wSpace->next;
+ }
+ return parent;
+}
+
+/* Device management */
+
+static Bool
+newtonAddDevToList (CompScreen *s,
+ CompDevice *dev)
+{
+ NEWTON_SCREEN (s);
+
+ NewtonDevice *run;
+
+ if (!ns->devices)
+ {
+ ns->devices = calloc (1, sizeof(NewtonDevice));
+ if (!ns->devices)
+ return FALSE;
+ ns->devices->dev = dev;
+ ns->devices->next = NULL;
+ }
+ else
+ {
+ for (run = ns->devices; run->next; run = run->next);
+ run->next = calloc (1, sizeof(NewtonDevice));
+ if (!run->next)
+ return FALSE;
+ run->next->dev = dev;
+ run->next->next = NULL;
+ }
+ return TRUE;
+}
+
+static void
+newtonRemoveDevFromList (CompScreen *s,
+ CompDevice *dev)
+{
+ NEWTON_SCREEN (s);
+
+ NewtonDevice *run;
+
+ if (!ns->devices)
+ return;
+
+ if (run == ns->devices)
+ {
+ if (ns->devices->next)
+ ns->devices = ns->devices->next;
+ else
+ ns->devices = NULL;
+ if (run)
+ free (run);
+ }
+ else
+ {
+ for (run = ns->devices; run; run = run->next)
+ {
+ if (run->dev == dev)
+ break;
+ }
+
+ NewtonDevice *selected = run;
+
+ if (selected)
+ if (selected->next)
+ {
+ selected = selected->next;
+ if (selected)
+ free(selected);
+ }
+ }
+}
+
+static void
+newtonCheckList (CompScreen *s,
+ MousepollDevice *list)
+{
+ NEWTON_SCREEN (s);
+ Bool ok = FALSE;
+ MousepollDevice *run;
+ NewtonDevice *ptr;
+ CompDevice *addDev = NULL, *removeDev = NULL;
+
+ do
+ {
+ for (run = list; run; run = run->next)
+ {
+ addDev = run->dev;
+ for (ptr = ns->devices; ptr; ptr = ptr->next)
+ {
+ if (ptr->dev == run->dev)
+ {
+ addDev = NULL;
+ break;
+ }
+ }
+ if (addDev) break;
+ }
+
+ for (ptr = ns->devices; ptr; ptr = ptr->next)
+ {
+ removeDev = ptr->dev;
+ for (run = list; run; run = run->next)
+ {
+ if (run->dev == ptr->dev)
+ {
+ removeDev = NULL;
+ break;
+ }
+ }
+ if (removeDev) break;
+ }
+
+ if (addDev)
+ newtonAddDevToList (s, addDev);
+
+ if (removeDev)
+ newtonRemoveDevFromList (s, removeDev);
+
+ if (addDev || removeDev)
+ ok = FALSE;
+ else
+ ok = TRUE;
+ } while (!ok);
+}
+
+static void
+positionUpdate (CompScreen *s,
+ MousepollDevice *mDev)
+{
+ NEWTON_SCREEN (s);
+ MousepollDevice *run = mDev;
+ NewtonDevice *nDev;
+
+ newtonCheckList (s, mDev);
+
+ for (; run; run = run->next)
+ {
+ for (nDev = ns->devices; nDev; nDev = nDev->next)
+ {
+ if (nDev->dev == run->dev)
+ {
+ nDev->mouseX = run->posX;
+ nDev->mouseY = run->posY;
+ }
+ }
+ }
+}
+
+static Bool
+newtonAddMiniwindow (CompWindow *w)
+{
+ int x,y;
+ int width, height;
+ XSetWindowAttributes attr;
+ Atom state[4];
+ int nState = 0;
+ float ratio;
+ XSizeHints xsh;
+ XWMHints xwmh;
+ NEWTON_WINDOW (w);
+
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.override_redirect= TRUE;
+
+ x = w-> serverX + w->width /2;
+ y = w-> serverY + w->height/2;
+
+ ratio = (float) w->width / w->height;
+ width = (ratio>1.0f) ? newtonGetMiniwindowsize (w->screen->display) : ratio * newtonGetMiniwindowsize (w->screen->display) ;
+ height = (ratio<1.0f) ? newtonGetMiniwindowsize (w->screen->display) : newtonGetMiniwindowsize (w->screen->display) / ratio;
+
+ nw->child = XCreateWindow (w->screen->display->display,
+ w->screen->root,
+ x,//x
+ y,//y
+ width,//width
+ height,//heigth
+ 0,//border width
+ 0,//depth
+ InputOutput,//window class
+ CopyFromParent,// visual
+ CWOverrideRedirect | CWBackPixel | CWBorderPixel,
+ &attr);
+ newtonWaitForChild (w, nw->child);
+
+ xsh.flags = PSize | PPosition | PWinGravity;
+ xsh.width = width;
+ xsh.height = height;
+ xsh.win_gravity = StaticGravity;
+
+ xwmh.flags = InputHint;
+ xwmh.input = 0;
+
+ XSetWMProperties (w->screen->display->display,
+ nw->child,
+ NULL,
+ NULL,
+ programArgv, programArgc,
+ &xsh,
+ &xwmh,
+ NULL);
+
+ state[nState++] = w->screen->display->winStateAboveAtom;
+ //state[nState++] = w->screen->display->winStateStickyAtom;
+ state[nState++] = w->screen->display->winStateSkipTaskbarAtom;
+ state[nState++] = w->screen->display->winStateSkipPagerAtom;
+
+ XChangeProperty (w->screen->display->display,
+ nw->child,
+ w->screen->display->winStateAtom,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char *) state,
+ nState);
+
+ XChangeProperty (w->screen->display->display, nw->child,
+ w->screen->display->winTypeAtom,
+ XA_ATOM, 32, PropModeReplace,
+ (unsigned char *) &w->screen->display->winTypeUtilAtom, 1);
+
+ setWindowProp (w->screen->display, nw->child,
+ w->screen->display->winDesktopAtom,
+ 0xffffffff);
+
+ XMapWindow (w->screen->display->display, nw->child);
+
+ return TRUE;
+}
+
+static Bool
+newtonToggleMiniwindow (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ CompWindow *w = findWindowAtDisplay (d, d->activeWindow);
+ if (!w)
+ return TRUE;
+ NEWTON_WINDOW (w);
+
+ if (nw->child)
+ {
+ XDestroyWindow (w->screen->display->display, nw->child);
+ nw->child = 0;
+ }
+ else
+ {
+ newtonAddMiniwindow (w);
+ }
+ return TRUE;
+}
+
+static void
+newtonGetAllowedActionsForWindow (CompWindow *w,
+ unsigned int *setActions,
+ unsigned int *clearActions)
+{
+ NEWTON_SCREEN (w->screen);
+ NEWTON_WINDOW (w);
+
+ UNWRAP (ns, w->screen, getAllowedActionsForWindow);
+ (*w->screen->getAllowedActionsForWindow) (w, setActions, clearActions);
+ WRAP (ns, w->screen, getAllowedActionsForWindow, newtonGetAllowedActionsForWindow);
+
+ if (nw->parent)
+ *clearActions |= CompWindowActionMoveMask|CompWindowActionResizeMask|CompWindowActionMinimizeMask|CompWindowActionCloseMask;
+}
+
+static void
+newtonUpdateMiniwindowSize (CompWindow *w)
+{
+ NEWTON_WINDOW (w);
+ NEWTON_SCREEN (w->screen);
+ XWindowChanges xwc;
+ CompWindow *parentCW;
+ float ratio;
+ int size = newtonGetMiniwindowsize (w->screen->display);
+
+ parentCW = findWindowAtDisplay (w->screen->display, nw->parent);
+
+ if (!parentCW)
+ return;
+
+ ratio = (float) parentCW->width / parentCW->height;
+ xwc.width = (ratio>1.0f) ? size : ratio * size;
+ xwc.height = (ratio<1.0f)? size : size / ratio;
+
+ cpVect verts[] = {cpv (-xwc.width/2 , -xwc.height/2),
+ cpv (-xwc.width/2 , xwc.height/2),
+ cpv ( xwc.width/2 , xwc.height/2),
+ cpv ( xwc.width/2 , -xwc.height/2)};
+
+ if (nw->shape)
+ {
+ cpSpaceRemoveShape (ns->space, nw->shape);
+ cpShapeFree (nw->shape);
+ nw->shape = cpPolyShapeNew (nw->body,
+ 4,
+ verts,
+ cpvzero);
+ nw->shape->e = 0.0; nw->shape->u = 0.8;
+ cpSpaceAddShape (ns->space, nw->shape);
+ cpBodySetMass (nw->body, xwc.width*xwc.height);
+ }
+ XConfigureWindow (w->screen->display->display,
+ w->id,
+ CWWidth | CWHeight,
+ &xwc);
+ addWindowDamage (w);
+}
+
+static void
+newtonSetPhysics (CompWindow *w)
+{
+ NEWTON_WINDOW (w);
+ NEWTON_SCREEN (w->screen);
+ cpVect verts[] = {
+ cpv (-w->width/2 , -w->height/2),
+ cpv (-w->width/2 , w->height/2),
+ cpv ( w->width/2 , w->height/2),
+ cpv ( w->width/2 , -w->height/2)
+ };
+
+ if (!nw->body)
+ {
+ nw->body = cpBodyNew (w->width * w->height, INFINITY);
+ nw->body->p = cpv (w->attrib.x + w->width/2,
+ w->attrib.y + w->height/2);
+ cpSpaceAddBody(ns->space, nw->body);
+ }
+
+ if (!nw->shape)
+ {
+ nw->shape = cpPolyShapeNew (nw->body,
+ 4,
+ verts,
+ cpvzero);
+ nw->shape->e = newtonGetBounceConstant (w->screen->display); nw->shape->u = 0.8;
+ cpSpaceAddShape (ns->space, nw->shape);
+ nw->movable = TRUE;
+ }
+}
+
+static void
+newtonSetNoPhysics (CompWindow *w)
+{
+ NEWTON_WINDOW (w);
+ NEWTON_SCREEN (w->screen);
+
+ if (nw->body)
+ {
+ cpSpaceRemoveBody (ns->space, nw->body);
+ cpBodyFree (nw->body);
+ nw->body = NULL;
+ }
+ if (nw->shape)
+ {
+ cpSpaceRemoveShape (ns->space, nw->shape);
+ cpShapeFree (nw->shape);
+ nw->shape = NULL;
+ }
+ nw->movable = FALSE;
+}
+
+static void
+newtonHandleEvent (CompDisplay *d,
+ XEvent *event)
+{
+ CompWindow *w;
+ NewtonWindow *nw;
+ NewtonScreen *ns;
+
+ NEWTON_DISPLAY (d);
+
+ UNWRAP (nd, d, handleEvent);
+ (*d->handleEvent) (d, event);
+ WRAP (nd, d, handleEvent, newtonHandleEvent);
+
+ switch (event->type)
+ {
+ case ButtonPress:
+ w = findWindowAtDisplay (d, event->xbutton.window);
+ if (w)
+ {
+ ns = GET_NEWTON_SCREEN (w->screen, nd);
+ nw = GET_NEWTON_WINDOW (w, ns);
+ // when a window is clicked and it has a parent, the parent window is selected
+ if (nw->parent)
+ sendWindowActivationRequest (w->screen, nw->parent);
+ }
+ break;
+
+ case MapNotify:
+ w = findWindowAtDisplay (d, event->xmap.window);
+ if (w)
+ {
+ ns = GET_NEWTON_SCREEN (w->screen, nd);
+ nw = GET_NEWTON_WINDOW (w, ns);
+ if (isNewtonWindow (w))
+ {
+ nw->repulsion = TRUE;
+ if (! findWindowAtDisplay (d, nw->child))
+ newtonAddMiniwindow(w);
+ }
+ }
+ break;
+
+ case UnmapNotify:
+ w = findWindowAtDisplay (d, event->xunmap.window);
+ if (w)
+ {
+ ns = GET_NEWTON_SCREEN (w->screen, nd);
+ nw = GET_NEWTON_WINDOW (w, ns);
+ nw->repulsion = FALSE;
+
+ newtonSetNoPhysics (w);
+ }
+
+ break;
+
+ case ConfigureNotify:
+ w = findWindowAtDisplay (d, event->xconfigure.window);
+ if (w)
+ {
+ ns = GET_NEWTON_SCREEN (w->screen, nd);
+ nw = GET_NEWTON_WINDOW (w, ns);
+ CompWindow *wchild = findWindowAtDisplay (d,nw->child);
+
+ if (wchild)
+ newtonUpdateMiniwindowSize(wchild);
+ }
+ }
+}
+
+static Bool
+newtonTogglePhysics (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ CompWindow *w = findWindowAtDisplay (d, d->activeWindow);
+ if (!w)
+ return TRUE;
+
+ NEWTON_WINDOW (w);
+
+ if (!nw->shape)
+ {
+ newtonSetPhysics (w);
+ }
+ else
+ {
+ newtonSetNoPhysics (w);
+ }
+
+ return TRUE;
+
+}
+
+static Bool
+newtonToggleMovable (CompWindow *w)
+{
+ NEWTON_WINDOW (w);
+ NEWTON_SCREEN (w->screen);
+
+ if (nw->shape && nw->body)
+ {
+ if (nw->movable)
+ {
+ nw->movable = FALSE;
+ cpSpaceRemoveBody (ns->space, nw->body);
+ nw->body->v = cpvzero;
+ }
+ else
+ {
+ nw->body->p = cpv (w->attrib.x + w->width/2,
+ w->attrib.y + w->height/2);
+ nw->movable = TRUE;
+ cpSpaceAddBody (ns->space, nw->body);
+ }
+ }
+ return TRUE;
+}
+
+static Bool
+newtonMouseInvert (CompDisplay *d,
+ CompAction *action,
+ CompActionState state,
+ CompOption *option,
+ int nOption)
+{
+ NEWTON_DISPLAY (d);
+ nd->mouseInvert = !nd->mouseInvert;
+
+ return TRUE;
+}
+
+static void
+newtonMiniwindowsizeNotify (CompDisplay *d,
+ CompOption *opt,
+ NewtonDisplayOptions num)
+{
+ CompScreen *s;
+ CompWindow *w;
+
+ NewtonWindow *nw;
+ NewtonScreen *ns;
+ NEWTON_DISPLAY (d);
+
+ for (s = d->screens ; s ; s = s->next)
+ {
+ ns = GET_NEWTON_SCREEN (s, nd);
+ cpSpaceResizeActiveHash(ns->space, newtonGetMiniwindowsize (d), 500);
+ for (w = s->windows; w; w = w->next)
+ {
+ nw = GET_NEWTON_WINDOW (w, ns);
+ if (nw->parent)
+ newtonUpdateMiniwindowSize (w);
+ }
+ }
+}
+
+static void
+newtonElasticityNotify (CompDisplay *d,
+ CompOption *opt,
+ NewtonDisplayOptions num)
+{
+ CompScreen *s;
+ CompWindow *w;
+
+ NewtonWindow *nw;
+ NewtonScreen *ns;
+ NEWTON_DISPLAY (d);
+
+ cpFloat elasticity = newtonGetBounceConstant (d);
+
+ for (s = d->screens ; s ; s = s->next)
+ {
+ ns = GET_NEWTON_SCREEN (s, nd);
+ for (w = s->windows; w; w = w->next)
+ {
+ nw = GET_NEWTON_WINDOW (w, ns);
+ if (nw->shape)
+ nw->shape->e = elasticity;
+ }
+ }
+}
+
+static void
+newtonGravityNotify (CompDisplay *d,
+ CompOption *opt,
+ NewtonDisplayOptions num)
+{
+ CompScreen *s;
+ NewtonScreen *ns;
+ NEWTON_DISPLAY (d);
+ for (s = d->screens ; s ; s = s->next)
+ {
+ ns = GET_NEWTON_SCREEN (s, nd);
+ ns->space->gravity = cpv (0,(cpFloat)newtonGetGravity (d));
+ }
+}
+
+static void
+newtonFrictionNotify (CompDisplay *d,
+ CompOption *opt,
+ NewtonDisplayOptions num)
+{
+ CompScreen *s;
+ NewtonScreen *ns;
+ NEWTON_DISPLAY (d);
+ for (s = d->screens ; s ; s = s->next)
+ {
+ ns = GET_NEWTON_SCREEN (s, nd);
+ ns->space->damping = (cpFloat)newtonGetFrictionConstant (d);
+ }
+}
+
+static void
+newtonPreparePaintScreen (CompScreen *s,
+ int msSinceLastPaint)
+{
+ CompWindow *w, *w1;
+ NewtonWindow *nw, *nw1;
+
+ NEWTON_SCREEN (s);
+ NEWTON_DISPLAY (s->display);
+
+ //mouse position
+ if ( (newtonGetMouseAttraction (s->display) || newtonGetMouseStop (s->display))
+ && !ns->pollHandle)
+ {
+ //(*nd->mpFunc->getCurrentPosition) (s, &ns->mouseX, &ns->mouseY);
+ ns->pollHandle = (*nd->mpFunc->addPositionPolling) (s, NULL, positionUpdate);
+ }
+
+ //calculate forces
+ for (w = s->windows; w; w = w->next)
+ {
+ nw = GET_NEWTON_WINDOW (w,ns);
+
+ if (nw->shape && nw->body)
+ {
+ cpBodyResetForces (nw->body);
+ //---repulsion between windows---
+ for (w1=s->reverseWindows; w1; w1=w1->prev)
+ {
+ nw1 = GET_NEWTON_WINDOW (w1,ns);
+
+ if ( (w != w1)
+ && nw1->repulsion
+ && ! ((w->screen != w1->screen)
+ || (w1->attrib.x > w->attrib.x + w->width)
+ || (w1->attrib.x + w1->width < w->attrib.x)
+ || (w1->attrib.y > w->attrib.y + w->height)
+ || (w1->attrib.y + w1->height < w->attrib.y) ) )
+ {
+ int xc,xc1,yc,yc1;
+ xc = w->attrib.x + w->width/2;
+ xc1= w1->attrib.x + w1->width/2;
+ yc = w->attrib.y + w->height/2;
+ yc1= w1->attrib.y + w1->height/2;
+
+
+//+------------------+
+//| |
+//| (xc1,yc1) |
+//| + |
+//| +------+----------+
+//| | | |
+//+-----------+------+ |
+// | + |
+// | (xc,yc) |
+// | |
+// +-----------------+
+//
+//We assume the horizontal repulsion is proportional to the length of the
+//overlapping portion. same thing for the vertical strength.
+//
+//In this situation the horizontal component is :
+//k * (x1+width1 - x)
+//
+//we determine the direction (and the sides to consider) by checking the relative
+//position of the centers (xc1 < xc in our situation)
+
+ //horizontal component
+ if (xc > xc1)
+ {
+ cpBodyApplyForce (nw->body,
+ cpv ((cpFloat) 10*newtonGetWindowElasticityConstant (s->display) *
+ (w->attrib.x + w->width - w1->attrib.x),
+ 0),
+ cpvzero);
+ }
+ else
+ {
+ cpBodyApplyForce (nw->body,
+ cpv ((cpFloat) -10*newtonGetWindowElasticityConstant (s->display) *
+ (w1->attrib.x + w1->width - w->attrib.x),
+ 0),
+ cpvzero);
+ }
+ //vertical component
+ if (yc > yc1)
+ {
+ cpBodyApplyForce (nw->body,
+ cpv (0,
+ (cpFloat) 10*newtonGetWindowElasticityConstant (s->display) *
+ (w->attrib.y + w->height - w1->attrib.y)),
+ cpvzero);
+ }
+ else
+ {
+ cpBodyApplyForce (nw->body,
+ cpv (0,
+ (cpFloat) -10*newtonGetWindowElasticityConstant (s->display) *
+ (w1->attrib.y + w1->height - w->attrib.y)),
+ cpvzero);
+ }
+
+ }
+ }
+
+ //---mouse attraction---
+ if (newtonGetMouseAttraction (s->display))
+ {
+ NewtonDevice *nDev;
+ int distanceX, distanceY, d2;
+ for (nDev = ns->devices; nDev; nDev = nDev->next)
+ {
+ distanceX = nw->body->p.x - nDev->mouseX;
+ distanceY = nw->body->p.y - nDev->mouseY;
+ d2 = distanceX*distanceX + distanceY*distanceY;
+ d2 = (d2<100)?100:d2;
+
+ if (d2 != 0)
+ {
+ cpBodyApplyForce (nw->body,
+ cpv ((cpFloat) 1000000000*(nd->mouseInvert?-1:1)*newtonGetMouseStrength (s->display) * distanceX / (sqrt (d2) * d2),
+ (cpFloat) 1000000000*(nd->mouseInvert?-1:1)*newtonGetMouseStrength (s->display) * distanceY / (sqrt (d2) * d2)),
+ cpvzero);
+ }
+ }
+ }
+
+ //---stop if under mouse---
+ if (newtonGetMouseStop (s->display))
+ {
+ NewtonDevice *nDev;
+ for (nDev = ns->devices; nDev; nDev = nDev->next)
+ {
+ if (w->region && XPointInRegion (w->region, nDev->mouseX, nDev->mouseY))
+ {
+ if (!nw->wasHovered && nw->movable)
+ {
+ cpSpaceRemoveBody (ns->space, nw->body);
+ nw->body->v = cpvzero;
+ nw->wasHovered = TRUE;
+ }
+ }
+ else
+ {
+ if (nw->wasHovered && nw->movable)
+ {
+ cpSpaceAddBody (ns->space, nw->body);
+ nw->wasHovered = FALSE;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ cpSpaceStep (ns->space, (cpFloat) msSinceLastPaint/1000);
+
+ //---update positions---
+ for (w = s->windows; w; w = w->next)
+ {
+ nw = GET_NEWTON_WINDOW (w,ns);
+ if (nw->body)
+ {
+ if (nw->movable && !nw->wasHovered)
+ {
+ moveWindow (w,
+ (int)nw->body->p.x - w->width /2 - w->attrib.x,
+ (int)nw->body->p.y - w->height /2 - w->attrib.y,
+ TRUE,
+ FALSE);
+ syncWindowPosition (w);
+ }
+ else
+ {
+ nw->body->p = cpv(w->attrib.x + w->width/2,
+ w->attrib.y + w->height/2);
+ }
+ }
+
+ }
+
+ UNWRAP (ns, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, msSinceLastPaint);
+ WRAP (ns, s, preparePaintScreen, newtonPreparePaintScreen);
+}
+
+static Bool
+newtonPaintWindow (CompWindow *w,
+ const WindowPaintAttrib *attrib,
+ const CompTransform *transform,
+ Region region,
+ unsigned int mask)
+{
+ Bool status;
+ CompWindow *wchild, *parentCW;
+
+ NEWTON_WINDOW (w);
+ NEWTON_SCREEN (w->screen);
+
+ UNWRAP (ns, w->screen, paintWindow);
+ status = (*w->screen->paintWindow) (w, attrib, transform, region, mask);
+ WRAP (ns, w->screen, paintWindow, newtonPaintWindow);
+
+ if (nw->parent)
+ {
+ mask |= PAINT_WINDOW_TRANSFORMED_MASK;
+
+ parentCW = findWindowAtDisplay (w->screen->display, nw->parent);
+
+ if (parentCW && parentCW->mapNum && parentCW->texture->pixmap)
+ {
+ CompTransform xTransform = *transform;
+ AddWindowGeometryProc oldAddWindowGeometry;
+ WindowPaintAttrib xAttrib = *attrib;
+ FragmentAttrib fragment;
+
+ xAttrib.xScale = (float) w->width / parentCW->width;
+ xAttrib.yScale = xAttrib.xScale;
+
+ xAttrib.xTranslate = w->attrib.x - parentCW->attrib.x + parentCW->input.left * xAttrib.xScale;
+ xAttrib.yTranslate = w->attrib.y - parentCW->attrib.y + parentCW->input.top * xAttrib.yScale;
+
+ initFragmentAttrib (&fragment, &xAttrib);
+
+ if (parentCW->alpha || fragment.opacity != OPAQUE)
+ mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+
+ matrixTranslate (&xTransform, parentCW->attrib.x, parentCW->attrib.y, 0.0f);
+ matrixScale (&xTransform, xAttrib.xScale, xAttrib.yScale, 1.0f);
+ matrixTranslate (&xTransform,
+ xAttrib.xTranslate / xAttrib.xScale - parentCW->attrib.x,
+ xAttrib.yTranslate / xAttrib.yScale - parentCW->attrib.y,
+ 0.0f);
+ glPushMatrix ();
+ glLoadMatrixf (xTransform.m);
+
+ oldAddWindowGeometry = w->screen->addWindowGeometry;
+ w->screen->addWindowGeometry = addWindowGeometry;
+ (w->screen->drawWindow) (parentCW, &xTransform, &fragment, &infiniteRegion, mask);
+ w->screen->addWindowGeometry = oldAddWindowGeometry;
+
+ glPopMatrix ();
+
+ }
+ else
+ {
+ //TODO : draw something (icon maybe)
+ }
+
+ }
+ else
+ {
+
+ wchild = findWindowAtDisplay (w->screen->display, nw->child);
+ if (wchild)
+ addWindowDamage (wchild);
+ }
+
+ return status;
+}
+
+static Bool
+newtonInitWindow (CompPlugin *p,
+ CompWindow *w)
+{
+ NewtonWindow *nw;
+
+ NEWTON_SCREEN (w->screen);
+
+ nw = malloc (sizeof (NewtonWindow));
+ if (!nw)
+ return FALSE;
+
+ w->base.privates[ns->windowPrivateIndex].ptr = nw;
+
+ nw->repulsion = FALSE;
+ nw->wasHovered = FALSE;
+
+ nw->parent = newtonFindParent (w);
+
+ nw->shape = NULL;
+ nw->body = NULL;
+
+ nw->child = NULL;
+
+ if (nw->parent)
+ {
+ //the window is a child window, it can be moved (by physics)
+ newtonSetPhysics (w);
+ nw->repulsion = TRUE;
+ }
+ else
+ {
+ if (isNewtonWindow (w))
+ {
+ nw->repulsion = TRUE;
+ if (newtonGetDrawMiniwindows (w->screen->display))
+ {
+ //the window needs a miniwindow, let's create it
+ newtonAddMiniwindow (w);
+ }
+ }
+ else
+ {
+ if (w->region
+ && (w->state & CompWindowStateSkipTaskbarMask)
+ && w->mapNum
+ && ! (w->wmType & CompWindowTypeDesktopMask))
+ {
+ newtonSetPhysics (w);
+ newtonToggleMovable (w);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+newtonFiniWindow (CompPlugin *p,
+ CompWindow *w)
+{
+ NEWTON_WINDOW (w);
+
+ if (nw->child)
+ {
+ XDestroyWindow (w->screen->display->display, nw->child);
+ }
+ newtonSetNoPhysics (w);
+
+ free (nw);
+}
+
+static Bool
+newtonInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ NewtonDisplay *nd;
+ int mousepollIndex;
+
+ if (!checkPluginABI ("core", CORE_ABIVERSION) ||
+ !checkPluginABI ("mousepoll", MOUSEPOLL_ABIVERSION))
+ return FALSE;
+
+ if (!getPluginDisplayIndex (d, "mousepoll", &mousepollIndex))
+ return FALSE;
+
+ nd = malloc (sizeof (NewtonDisplay));
+ if (!nd)
+ return FALSE;
+
+ nd->screenPrivateIndex = allocateScreenPrivateIndex (d);
+ if (nd->screenPrivateIndex < 0)
+ {
+ free (nd);
+ return FALSE;
+ }
+
+ nd->mpFunc = d->base.privates[mousepollIndex].ptr;
+
+ nd->mouseInvert = newtonGetMouseAttractionMode (d);
+
+ newtonSetMiniwindowsizeNotify (d, newtonMiniwindowsizeNotify);
+ newtonSetGravityNotify (d, newtonGravityNotify);
+ newtonSetBounceConstantNotify (d, newtonElasticityNotify);
+ newtonSetFrictionConstantNotify (d, newtonFrictionNotify);
+ newtonSetTriggerPhysicsKeyInitiate (d, newtonTogglePhysics);
+ newtonSetMouseInvertKeyInitiate (d, newtonMouseInvert);
+ newtonSetMouseInvertKeyTerminate (d, newtonMouseInvert);
+ newtonSetToggleMiniwindowKeyInitiate (d, newtonToggleMiniwindow);
+
+ WRAP (nd, d, handleEvent, newtonHandleEvent);
+
+ d->base.privates[displayPrivateIndex].ptr = nd;
+
+ return TRUE;
+}
+
+static void
+newtonFiniDisplay (CompPlugin *p,
+ CompDisplay *d)
+{
+ NEWTON_DISPLAY (d);
+
+ freeScreenPrivateIndex (d, nd->screenPrivateIndex);
+
+ UNWRAP (nd, d, handleEvent);
+
+ free (nd);
+}
+
+static Bool
+newtonInitScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ NewtonScreen *ns;
+ cpShape *shape;
+ cpBody *staticBody;
+ REGION *region;
+ int i;
+
+ NEWTON_DISPLAY (s->display);
+
+ ns = malloc (sizeof (NewtonScreen));
+ if (!ns)
+ return FALSE;
+
+ ns->windowPrivateIndex = allocateWindowPrivateIndex (s);
+
+ ns->pollHandle = 0;
+
+ ns->waitingSpace = NULL;
+ ns->devices = NULL;
+
+ ns->space = cpSpaceNew ();
+ ns->space->gravity = cpv(0, newtonGetGravity (s->display));
+ ns->space->damping = newtonGetFrictionConstant (s->display);
+ cpSpaceResizeActiveHash(ns->space, newtonGetMiniwindowsize(s->display), 500);
+
+ staticBody = cpBodyNew(INFINITY, INFINITY);
+
+ shape = cpSegmentShapeNew (staticBody, cpv (s->x,s->y), cpv (s->x + s->width ,s->y), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ shape = cpSegmentShapeNew (staticBody, cpv (s->x + s->width,s->y), cpv (s->x + s->width,s->y + s->height), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ shape = cpSegmentShapeNew (staticBody, cpv (s->x + s->width,s->y + s->height), cpv (s->x,s->y + s->height), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ shape = cpSegmentShapeNew (staticBody, cpv (s->x,s->y + s->height), cpv (s->x,s->y), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ region = XCreateRegion ();
+ XUnionRegion (region, &s->region, region);
+ for (i=0; i < s->nOutputDev ; i++)
+ {
+ XSubtractRegion (region, &s->outputDev[i].region, region);
+ }
+ for (i=0; i< region->numRects ; i++)
+ {
+ shape = cpSegmentShapeNew (staticBody,
+ cpv (region->rects[i].x1,region->rects[i].y1),
+ cpv (region->rects[i].x1,region->rects[i].y2), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ shape = cpSegmentShapeNew (staticBody,
+ cpv (region->rects[i].x1,region->rects[i].y2),
+ cpv (region->rects[i].x2,region->rects[i].y2), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ shape = cpSegmentShapeNew (staticBody,
+ cpv (region->rects[i].x2,region->rects[i].y2),
+ cpv (region->rects[i].x2,region->rects[i].y1), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+
+ shape = cpSegmentShapeNew (staticBody,
+ cpv (region->rects[i].x2,region->rects[i].y1),
+ cpv (region->rects[i].x1,region->rects[i].y1), 0.0f);
+ shape->e = 1.0; shape->u = 0;
+ cpSpaceAddStaticShape(ns->space, shape);
+ }
+
+ WRAP (ns, s, paintWindow, newtonPaintWindow);
+ WRAP (ns, s, preparePaintScreen, newtonPreparePaintScreen);
+ WRAP (ns, s, getAllowedActionsForWindow, newtonGetAllowedActionsForWindow);
+
+ s->base.privates[nd->screenPrivateIndex].ptr = ns;
+
+ return TRUE;
+}
+
+static void
+newtonFiniScreen (CompPlugin *p,
+ CompScreen *s)
+{
+ NEWTON_SCREEN (s);
+ NEWTON_DISPLAY (s->display);
+
+ freeWindowPrivateIndex (s, ns->windowPrivateIndex);
+
+ cpSpaceFree (ns->space);
+
+ newtonFreeWaitingSpace (s);
+
+ if (ns->pollHandle)
+ (*nd->mpFunc->removePositionPolling) (s, ns->pollHandle);
+
+ UNWRAP (ns, s, paintWindow);
+ UNWRAP (ns, s, preparePaintScreen);
+ UNWRAP (ns, s, getAllowedActionsForWindow);
+
+ free (ns);
+}
+
+static CompBool
+newtonInitObject (CompPlugin *p,
+ CompObject *o)
+{
+ static InitPluginObjectProc dispTab[] = {
+ (InitPluginObjectProc) 0, /* InitCore */
+ (InitPluginObjectProc) newtonInitDisplay,
+ (InitPluginObjectProc) newtonInitScreen,
+ (InitPluginObjectProc) newtonInitWindow
+ };
+
+ RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
+}
+
+static void
+newtonFiniObject (CompPlugin *p,
+ CompObject *o)
+{
+ static FiniPluginObjectProc dispTab[] = {
+ (FiniPluginObjectProc) 0, /* FiniCore */
+ (FiniPluginObjectProc) newtonFiniDisplay,
+ (FiniPluginObjectProc) newtonFiniScreen,
+ (FiniPluginObjectProc) newtonFiniWindow
+ };
+
+ DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
+}
+
+static Bool
+newtonInit (CompPlugin *p)
+{
+ displayPrivateIndex = allocateDisplayPrivateIndex ();
+ if (displayPrivateIndex < 0)
+ {
+ return FALSE;
+ }
+ cpInitChipmunk ();
+
+ return TRUE;
+}
+
+static void
+newtonFini (CompPlugin *p)
+{
+ freeDisplayPrivateIndex (displayPrivateIndex);
+}
+
+
+CompPluginVTable newtonVTable = {
+ "newton",
+ 0,//switchGetMetadata,
+ newtonInit,
+ newtonFini,
+ newtonInitObject,
+ newtonFiniObject,
+ 0,//switchGetObjectOptions,
+ 0,//switchSetObjectOption
+};
+
+CompPluginVTable *
+getCompPluginInfo (void)
+{
+ return &newtonVTable;
+}
diff --git a/fusion/plugins/newton/newton.xml.in b/fusion/plugins/newton/newton.xml.in
new file mode 100755
index 0000000..5182f11
--- /dev/null
+++ b/fusion/plugins/newton/newton.xml.in
@@ -0,0 +1,95 @@
+<?xml version="1.0"?>
+<compiz>
+ <plugin name="newton" useBcop="true">
+ <_short>Newton</_short>
+ <_long>Creates iconified windows that can be selected to select the main window and are affected by physics. </_long>
+ <category>Window Management</category>
+ <deps>
+ <requirement>
+ <plugin>mousepoll</plugin>
+ </requirement>
+ </deps>
+ <display>
+ <group>
+ <_short>Bindings</_short>
+ <option name="trigger_physics_key" type="key">
+ <_short>Trigger Physics on the window</_short>
+ <_long> Toggle physics on the selected window. </_long>
+ <default>&lt;Super&gt;p</default>
+ </option>
+ <option name="mouse_invert_key" type="key">
+ <_short>Invert mouse attraction/repulsion</_short>
+ <_long> Inverts mouse attraction or repulsion. </_long>
+ <default>&lt;Super&gt;i</default>
+ </option>
+ <option name="toggle_miniwindow_key" type="key">
+ <_short>Toggle miniwindow</_short>
+ <_long> Toggles miniwindow for current window. </_long>
+ <default>&lt;Super&gt;t</default>
+ </option>
+ </group>
+ <option name="miniwindowsize" type="int">
+ <_short>Iconified window size</_short>
+ <_long> Size of the iconified window in pixels. </_long>
+ <default>64</default>
+ <min>12</min>
+ <max>256</max>
+ </option>
+ <option name="bounce_constant" type="float">
+ <_short>Bounce elasticity</_short>
+ <_long> Elasticity of the windows (0 means no bounce, 1 is perfect elasticity). </_long>
+ <default>0.8</default>
+ <min>0</min>
+ <max>1</max>
+ </option>
+ <option name="friction_constant" type="float">
+ <_short>Fluid friction</_short>
+ <_long> Fluidity of the desktop (0 means solid, and 1 totally liquid). </_long>
+ <default>0.6</default>
+ <min>0</min>
+ <max>1</max>
+ </option>
+ <option name="window_elasticity_constant" type="int">
+ <_short>Repulsion</_short>
+ <_long> Elasticity constant of windows. </_long>
+ <default>10</default>
+ <min>0</min>
+ <max>100</max>
+ </option>
+ <option name="gravity" type="int">
+ <_short>Gravity</_short>
+ <_long> Constant force. </_long>
+ <default>100</default>
+ <min>-500</min>
+ <max>500</max>
+ </option>
+ <option name="mouse_attraction" type="bool">
+ <_short>Mouse attraction</_short>
+ <_long> Attracts/repels the windows to the mouse. </_long>
+ <default>true</default>
+ </option>
+ <option name="mouse_attraction_mode" type="bool">
+ <_short>Attract by default</_short>
+ <_long> Attracts the windows to the mouse when the invert action key is not pressed. </_long>
+ <default>false</default>
+ </option>
+ <option name="mouse_strength" type="int">
+ <_short>Mouse attraction strength</_short>
+ <_long> Strength of the attraction/repulsion force. </_long>
+ <default>10</default>
+ <min>0</min>
+ <max>100</max>
+ </option>
+ <option name="mouse_stop" type="bool">
+ <_short>Stop Hovered windows</_short>
+ <_long> Stops the windows under the pointer. </_long>
+ <default>true</default>
+ </option>
+ <option name="draw_miniwindows" type="bool">
+ <_short>Draw miniwindows</_short>
+ <_long> Draw miniwindows for newly created windows. </_long>
+ <default>true</default>
+ </option>
+ </display>
+ </plugin>
+</compiz>
diff --git a/fusion/plugins/newton/plugin.info b/fusion/plugins/newton/plugin.info
new file mode 100755
index 0000000..65509e3
--- /dev/null
+++ b/fusion/plugins/newton/plugin.info
@@ -0,0 +1,2 @@
+PLUGIN = newton
+CFLAGS_ADD = -std=c99
diff --git a/fusion/plugins/newton/prime.h b/fusion/plugins/newton/prime.h
new file mode 100644
index 0000000..15ce456
--- /dev/null
+++ b/fusion/plugins/newton/prime.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2007 Scott Lembcke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ */
+
+// Used for resizing hash tables.
+// Values approximately double.
+
+static int primes[] = {
+ 5, //2^2 + 1
+ 11, //2^3 + 3
+ 17, //2^4 + 1
+ 37, //2^5 + 5
+ 67, //2^6 + 3
+ 131, //2^7 + 3
+ 257, //2^8 + 1
+ 521, //2^9 + 9
+ 1031, //2^10 + 7
+ 2053, //2^11 + 5
+ 4099, //2^12 + 3
+ 8209, //2^13 + 17
+ 16411, //2^14 + 27
+ 32771, //2^15 + 3
+ 65537, //2^16 + 1
+ 131101, //2^17 + 29
+ 262147, //2^18 + 3
+ 524309, //2^19 + 21
+ 1048583, //2^20 + 7
+ 2097169, //2^21 + 17
+ 4194319, //2^22 + 15
+ 8388617, //2^23 + 9
+ 16777259, //2^24 + 43
+ 33554467, //2^25 + 35
+ 67108879, //2^26 + 15
+ 134217757, //2^27 + 29
+ 268435459, //2^28 + 3
+ 536870923, //2^29 + 11
+ 1073741827, //2^30 + 3
+ 0,
+};
+
+static int
+next_prime(int n)
+{
+ int i = 0;
+ while(n > primes[i]){
+ i++;
+ assert(primes[i]); // realistically this should never happen
+ }
+
+ return primes[i];
+}
diff --git a/fusion/plugins/newton/setupbuild b/fusion/plugins/newton/setupbuild
new file mode 100755
index 0000000..5be755d
--- /dev/null
+++ b/fusion/plugins/newton/setupbuild
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+export PKG_CONFIG_PATH=/opt/xserver-xir-install/lib/pkgconfig:${PKG_CONFIG_PATH}
+export LD_LIBRARY_PATH=/opt/xserver-xir-install/lib/:${LD_LIBRARY_PATH}
+export LD_RUN_PATH=/opt/xserver-xir-install/lib/:${LD_RUN_PATH}
+make
+make install
diff --git a/fusion/plugins/ring/0001-X-Input-2-Support.patch b/fusion/plugins/ring/0001-X-Input-2-Support.patch
new file mode 100644
index 0000000..5dd0a4d
--- /dev/null
+++ b/fusion/plugins/ring/0001-X-Input-2-Support.patch
@@ -0,0 +1,456 @@
+From 4de84abf3311116d616cf8a083efdca19131f16d Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Fri, 31 Oct 2008 15:02:27 +0900
+Subject: [PATCH] X Input 2 Support
+
+---
+ ring.c | 266 +++++++++++++++++++++++++++++++++++++++++++++++----------------
+ 1 files changed, 198 insertions(+), 68 deletions(-)
+
+diff --git a/ring.c b/ring.c
+index 1c36ec0..f43fe22 100644
+--- a/ring.c
++++ b/ring.c
+@@ -67,6 +67,12 @@ typedef struct _RingDrawSlot {
+ RingSlot **slot;
+ } RingDrawSlot;
+
++typedef struct _RingGrab {
++ CompDevice *dev;
++ int grabIndex;
++ struct _RingGrab *next;
++} RingGrab;
++
+ typedef struct _RingDisplay {
+ int screenPrivateIndex;
+ HandleEventProc handleEvent;
+@@ -86,6 +92,7 @@ typedef struct _RingScreen {
+
+ RingState state;
+ RingType type;
++ RingGrab *grabs;
+ Bool moreAdjust;
+ Bool rotateAdjust;
+
+@@ -97,6 +104,9 @@ typedef struct _RingScreen {
+
+ Cursor cursor;
+
++ unsigned int clickTime;
++ Bool doubleClick;
++
+ /* only used for sorting */
+ CompWindow **windows;
+ RingDrawSlot *drawSlots;
+@@ -236,9 +246,6 @@ ringRenderWindowTitle (CompScreen *s)
+ if (!rd->textAvailable)
+ return;
+
+- if (!rs->selectedWindow)
+- return;
+-
+ if (!ringGetWindowTitle (s))
+ return;
+
+@@ -790,7 +797,7 @@ switchToWindow (CompScreen *s,
+
+ RING_SCREEN (s);
+
+- if (!rs->grabIndex)
++ if (!rs->grabs)
+ return;
+
+ for (cur = 0; cur < rs->nWindows; cur++)
+@@ -1044,6 +1051,7 @@ ringPreparePaintScreen (CompScreen *s,
+ rw->tx += rw->xVelocity * chunk;
+ rw->ty += rw->yVelocity * chunk;
+ rw->scale += rw->scaleVelocity * chunk;
++ updateMesh (w);
+ }
+ else if (rw->slot)
+ {
+@@ -1093,6 +1101,91 @@ ringDonePaintScreen (CompScreen *s)
+ WRAP (rs, s, donePaintScreen, ringDonePaintScreen);
+ }
+
++/* Device Management */
++
++/*
++ * ringGrabDevice
++ *
++ */
++
++static void
++ringRemoveGrab (CompScreen *s,
++ RingGrab *grab)
++{
++ RingGrab *run;
++ RING_SCREEN (s);
++
++ if (!rs->grabs)
++ return;
++
++ for (run = rs->grabs; run; run = run->next)
++ if (run == grab)
++ break;
++
++ if (run == rs->grabs)
++ {
++ if (rs->grabs->next)
++ rs->grabs = rs->grabs->next;
++ else
++ rs->grabs = NULL;
++ }
++ else
++ {
++ if (run->next)
++ run = run->next;
++ else
++ run = NULL;
++ }
++
++ if (grab)
++ free (grab);
++}
++
++static RingGrab *
++ringAddGrab (CompScreen *s)
++{
++ RingGrab *run;
++ RingGrab *grab;
++ RING_SCREEN (s);
++
++ if (!rs->grabs)
++ {
++ rs->grabs = calloc (1, sizeof (RingGrab));
++ if (!rs->grabs)
++ return NULL;
++ rs->grabs->next = NULL;
++ grab = rs->grabs;
++ return grab;
++ }
++ else
++ {
++ for (run = rs->grabs; run->next; run = run->next);
++
++ run->next = calloc (1, sizeof (RingGrab));
++ if (!run->next)
++ return NULL;
++ run->next->next = NULL;
++ grab = run->next;
++ return grab;
++ }
++}
++
++static void
++ringGrabDevice (CompScreen *s,
++ CompDevice *dev,
++ RingGrab *grab,
++ Bool cursor)
++{
++ if (grab)
++ {
++ grab->dev = dev;
++ if (cursor)
++ grab->grabIndex = pushDeviceGrab (s, dev, None, "ring");
++ else
++ grab->grabIndex = pushDeviceGrab (s, dev, s->invisibleCursor, "ring");
++ }
++}
++
+ static Bool
+ ringTerminate (CompDisplay *d,
+ CompAction *action,
+@@ -1101,6 +1194,7 @@ ringTerminate (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ RingGrab *grab, *next;
+ Window xid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+@@ -1112,10 +1206,18 @@ ringTerminate (CompDisplay *d,
+ if (xid && s->root != xid)
+ continue;
+
+- if (rs->grabIndex)
+- {
+- removeScreenGrab (s, rs->grabIndex, 0);
+- rs->grabIndex = 0;
++ grab = rs->grabs;
++
++ while (grab)
++ {
++ if (grab->grabIndex)
++ removeDeviceGrab (s, grab->dev, grab->grabIndex, NULL);
++
++ next = grab->next;
++
++ ringRemoveGrab (s, grab);
++
++ grab = next;
+ }
+
+ if (rs->state != RingStateNone)
+@@ -1163,6 +1265,8 @@ ringInitiate (CompScreen *s,
+ int nOption)
+ {
+ CompMatch *match;
++ RingGrab *grab;
++ CompDevice *dev;
+ int count;
+
+ RING_SCREEN (s);
+@@ -1189,28 +1293,30 @@ ringInitiate (CompScreen *s,
+ if (count < 1)
+ return FALSE;
+
+- if (!rs->grabIndex)
++ for (dev = s->display->devices; dev->id != -1; dev++)
+ {
+- if (ringGetSelectWithMouse (s))
+- rs->grabIndex = pushScreenGrab (s, rs->cursor, "ring");
+- else
+- rs->grabIndex = pushScreenGrab (s, s->invisibleCursor, "ring");
+- }
++ for (grab = rs->grabs; grab; grab = grab->next)
++ if (grab->dev == dev)
++ break;
+
+- if (rs->grabIndex)
+- {
+- rs->state = RingStateOut;
++ if (!grab)
++ grab = ringAddGrab (s);
+
+- if (!ringCreateWindowList (s))
+- return FALSE;
++ if (grab)
++ ringGrabDevice (s, dev, grab, ringGetSelectWithMouse (s));
++ }
+
+- rs->selectedWindow = rs->windows[0]->id;
+- ringRenderWindowTitle (s);
+- rs->rotTarget = 0;
++ rs->state = RingStateOut;
+
+- rs->moreAdjust = TRUE;
+- damageScreen (s);
+- }
++ if (!ringCreateWindowList (s))
++ return FALSE;
++
++ rs->selectedWindow = rs->windows[0]->id;
++ ringRenderWindowTitle (s);
++ rs->rotTarget = 0;
++
++ rs->moreAdjust = TRUE;
++ damageScreen (s);
+
+ return TRUE;
+ }
+@@ -1341,11 +1447,9 @@ ringPrevGroup (CompDisplay *d,
+ static void
+ ringWindowSelectAt (CompScreen *s,
+ int x,
+- int y,
+- Bool terminate)
++ int y)
+ {
+- int i;
+- Window selected = None;
++ int i;
+
+ RING_SCREEN (s);
+
+@@ -1368,37 +1472,22 @@ ringWindowSelectAt (CompScreen *s,
+ (y <= (rw->ty + w->attrib.y + (w->attrib.height * rw->scale))))
+ {
+ /* we have found one, select it */
+- selected = w->id;
++ rs->selectedWindow = w->id;
+ break;
+ }
+ }
+ }
+
+- if (selected && terminate)
++ if (i >= 0)
+ {
+ CompOption o;
+
+- o.type = CompOptionTypeInt;
+- o.name = "root";
++ o.type = CompOptionTypeInt;
++ o.name = "root";
+ o.value.i = s->root;
+
+- rs->selectedWindow = selected;
+-
+ ringTerminate (s->display, NULL, 0, &o, 1);
+ }
+- else if (!terminate && (selected != rs->selectedWindow || !rs->textPixmap))
+- {
+- if (!selected)
+- {
+- ringFreeWindowTitle (s);
+- }
+- else
+- {
+- rs->selectedWindow = selected;
+- ringRenderWindowTitle (s);
+- }
+- damageScreen (s);
+- }
+ }
+
+ static void
+@@ -1465,7 +1554,7 @@ ringWindowRemove (CompDisplay *d,
+ return;
+ }
+
+- if (!rs->grabIndex)
++ if (!rs->grabs)
+ return;
+
+ if (ringUpdateWindowList (w->screen))
+@@ -1481,8 +1570,6 @@ static void
+ ringHandleEvent (CompDisplay *d,
+ XEvent *event)
+ {
+- CompScreen *s;
+-
+ RING_DISPLAY (d);
+
+ UNWRAP (rd, d, handleEvent);
+@@ -1498,7 +1585,7 @@ ringHandleEvent (CompDisplay *d,
+ if (w)
+ {
+ RING_SCREEN (w->screen);
+- if (rs->grabIndex && (w->id == rs->selectedWindow))
++ if (rs->grabs && (w->id == rs->selectedWindow))
+ {
+ ringRenderWindowTitle (w->screen);
+ damageScreen (w->screen);
+@@ -1509,37 +1596,75 @@ ringHandleEvent (CompDisplay *d,
+ case ButtonPress:
+ if (event->xbutton.button == Button1)
+ {
++ CompScreen *s;
+ s = findScreenAtDisplay (d, event->xbutton.root);
+ if (s)
+ {
+ RING_SCREEN (s);
++ if (rs->clickTime == 0)
++ {
++ rs->clickTime = event->xbutton.time;
++ }
++ else if (event->xbutton.time - rs->clickTime <=
++ ringGetDoubleClickTime (d))
++ {
++
++ rs->doubleClick = TRUE;
++ }
++ else
++ {
++ rs->clickTime = event->xbutton.time;
++ rs->doubleClick = FALSE;
++ }
+
+- if (rs->grabIndex)
++ if (rs->doubleClick)
+ ringWindowSelectAt (s,
+ event->xbutton.x_root,
+- event->xbutton.y_root,
+- TRUE);
++ event->xbutton.y_root);
+ }
+ }
+ break;
+- case MotionNotify:
+- s = findScreenAtDisplay (d, event->xmotion.root);
+- if (s)
+- {
+- RING_SCREEN (s);
+-
+- if (rs->grabIndex)
+- ringWindowSelectAt (s,
+- event->xmotion.x_root,
+- event->xmotion.y_root,
+- FALSE);
+- }
+ case UnmapNotify:
+ ringWindowRemove (d, event->xunmap.window);
+ break;
+ case DestroyNotify:
+ ringWindowRemove (d, event->xdestroywindow.window);
+ break;
++ default:
++ if (event->type == d->xi_btpress)
++ {
++ XDeviceButtonEvent *bev = (XDeviceButtonEvent *) event;
++
++ if (bev->button == Button1)
++ {
++ CompScreen *s;
++ s = findScreenAtDisplay (d, bev->root);
++ if (s)
++ {
++ RING_SCREEN (s);
++ if (rs->clickTime == 0)
++ {
++ rs->clickTime = event->xbutton.time;
++ }
++ else if (event->xbutton.time - rs->clickTime <=
++ ringGetDoubleClickTime (d))
++ {
++
++ rs->doubleClick = TRUE;
++ }
++ else
++ {
++ rs->clickTime = event->xbutton.time;
++ rs->doubleClick = FALSE;
++ }
++
++ if (rs->doubleClick)
++ ringWindowSelectAt (s,
++ bev->x_root,
++ bev->y_root);
++ }
++ }
++ }
+ }
+ }
+
+@@ -1555,7 +1680,7 @@ ringDamageWindowRect (CompWindow *w,
+
+ if (initial)
+ {
+- if (rs->grabIndex && isRingWin (w))
++ if (rs->grabs && isRingWin (w))
+ {
+ ringAddWindowToList (s, w);
+ if (ringUpdateWindowList (s))
+@@ -1689,6 +1814,8 @@ ringInitScreen (CompPlugin *p,
+ rs->drawSlots = NULL;
+ rs->windowsSize = 0;
+
++ rs->grabs = NULL;
++
+ rs->paintingSwitcher = FALSE;
+
+ rs->selectedWindow = None;
+@@ -1701,6 +1828,9 @@ ringInitScreen (CompPlugin *p,
+
+ rs->textPixmap = None;
+
++ rs->doubleClick = FALSE;
++ rs->clickTime = 0;
++
+ matchInit (&rs->match);
+
+ WRAP (rs, s, preparePaintScreen, ringPreparePaintScreen);
+--
+1.5.6
+
diff --git a/fusion/plugins/ring/0002-Add-Input-Redirection-Support.patch b/fusion/plugins/ring/0002-Add-Input-Redirection-Support.patch
new file mode 100644
index 0000000..16dc0d1
--- /dev/null
+++ b/fusion/plugins/ring/0002-Add-Input-Redirection-Support.patch
@@ -0,0 +1,111 @@
+From 277fcb2a076f6b9ca3b52799eaccceb72ff5b8a3 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Fri, 31 Oct 2008 15:05:41 +0900
+Subject: [PATCH] Add Input Redirection Support
+
+---
+ ring.c | 39 +++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 39 insertions(+), 0 deletions(-)
+
+diff --git a/ring.c b/ring.c
+index f43fe22..d1568af 100644
+--- a/ring.c
++++ b/ring.c
+@@ -87,6 +87,7 @@ typedef struct _RingScreen {
+ PaintOutputProc paintOutput;
+ PaintWindowProc paintWindow;
+ DamageWindowRectProc damageWindowRect;
++ TransformMeshProc transformMesh;
+
+ int grabIndex;
+
+@@ -1208,6 +1209,7 @@ ringTerminate (CompDisplay *d,
+
+ grab = rs->grabs;
+
++ if (!d->opt[COMP_DISPLAY_OPTION_REDIRECT_INPUT].value.b)
+ while (grab)
+ {
+ if (grab->grabIndex)
+@@ -1293,6 +1295,7 @@ ringInitiate (CompScreen *s,
+ if (count < 1)
+ return FALSE;
+
++ if (!d->opt[COMP_DISPLAY_OPTION_REDIRECT_INPUT].value.b)
+ for (dev = s->display->devices; dev->id != -1; dev++)
+ {
+ for (grab = rs->grabs; grab; grab = grab->next)
+@@ -1603,6 +1606,7 @@ ringHandleEvent (CompDisplay *d,
+ RING_SCREEN (s);
+ if (rs->clickTime == 0)
+ {
++ fprintf(stderr, "setting to time\n");
+ rs->clickTime = event->xbutton.time;
+ }
+ else if (event->xbutton.time - rs->clickTime <=
+@@ -1644,6 +1648,7 @@ ringHandleEvent (CompDisplay *d,
+ RING_SCREEN (s);
+ if (rs->clickTime == 0)
+ {
++ fprintf(stderr, "setting to time\n");
+ rs->clickTime = event->xbutton.time;
+ }
+ else if (event->xbutton.time - rs->clickTime <=
+@@ -1716,6 +1721,38 @@ ringDamageWindowRect (CompWindow *w,
+ return status;
+ }
+
++static void
++ringTransformMesh (CompWindow *w,
++ CompTransform *transform,
++ CompMesh *mesh,
++ int meshIter,
++ Bool needsProjection)
++{
++ RING_SCREEN (w->screen);
++ int i;
++ int nTriangles = mesh->width * mesh->height * 2;
++ CompTransform ringTransform = *transform;
++
++ if (TRUE)
++ {
++ RING_WINDOW (w);
++ if (rw->slot)
++ {
++ matrixTranslate (&ringTransform, w->attrib.x, w->attrib.y, 0.0f);
++ matrixScale (&ringTransform, rw->scale, rw->scale, 1.0f);
++ matrixTranslate (&ringTransform,
++ rw->tx / rw->scale - w->attrib.x,
++ rw->ty / rw->scale - w->attrib.y,
++ 0.0f);
++
++ }
++ }
++
++ UNWRAP (rs, w->screen, transformMesh);
++ (*w->screen->transformMesh) (w, &ringTransform, mesh, meshIter, needsProjection);
++ WRAP (rs, w->screen, transformMesh, ringTransformMesh);
++}
++
+ static Bool
+ ringInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+@@ -1838,6 +1875,7 @@ ringInitScreen (CompPlugin *p,
+ WRAP (rs, s, paintOutput, ringPaintOutput);
+ WRAP (rs, s, paintWindow, ringPaintWindow);
+ WRAP (rs, s, damageWindowRect, ringDamageWindowRect);
++ WRAP (rs, s, transformMesh, ringTransformMesh);
+
+ rs->cursor = XCreateFontCursor (s->display->display, XC_left_ptr);
+
+@@ -1859,6 +1897,7 @@ ringFiniScreen (CompPlugin *p,
+ UNWRAP (rs, s, paintOutput);
+ UNWRAP (rs, s, paintWindow);
+ UNWRAP (rs, s, damageWindowRect);
++ UNWRAP (rs, s, transformMesh);
+
+ matchFini (&rs->match);
+
+--
+1.5.6
+
diff --git a/fusion/plugins/scaleaddon/0001-MPX-Support.patch b/fusion/plugins/scaleaddon/0001-MPX-Support.patch
new file mode 100644
index 0000000..ccc7886
--- /dev/null
+++ b/fusion/plugins/scaleaddon/0001-MPX-Support.patch
@@ -0,0 +1,254 @@
+From dc6b648e5690e9a1ed83a488a6da3f64a5986527 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Fri, 31 Oct 2008 15:40:16 +0900
+Subject: [PATCH] MPX Support
+
+---
+ scaleaddon.c | 94 ++++++++++++++++++++++++++++++++++++---------------------
+ 1 files changed, 59 insertions(+), 35 deletions(-)
+
+diff --git a/scaleaddon.c b/scaleaddon.c
+index ae876ab..21f51fe 100644
+--- a/scaleaddon.c
++++ b/scaleaddon.c
+@@ -126,10 +126,13 @@ scaleaddonRenderWindowTitle (CompWindow *w)
+ int stride;
+ void *data;
+ CompScreen *s = w->screen;
++ Bool render = FALSE;
+ ScaleaddonWindowTitleEnum winTitleMode;
++ ScaleDevice *sDev;
+
+ ADDON_DISPLAY (s->display);
+ SCALE_SCREEN (s);
++ SCALE_DISPLAY (s->display);
+ SCALE_WINDOW (w);
+ ADDON_WINDOW (w);
+
+@@ -145,10 +148,25 @@ scaleaddonRenderWindowTitle (CompWindow *w)
+ if (winTitleMode == WindowTitleNoDisplay)
+ return;
+
+- if (winTitleMode == WindowTitleHighlightedWindowOnly &&
+- ad->highlightedWindow != w->id)
++ if (winTitleMode == WindowTitleHighlightedWindowOnly)
+ {
+- return;
++ if (sd->selectedWindow == w->id)
++ render = TRUE;
++ else
++ {
++ for (sDev = ss->devices; sDev; sDev = sDev->next)
++ {
++ if (sDev->selectedWindow == w->id)
++ {
++ render = TRUE;
++ break;
++ }
++ }
++ }
++ if (!render)
++ {
++ return;
++ }
+ }
+
+ scale = sw->slot->scale;
+@@ -311,30 +329,18 @@ scaleaddonDrawWindowHighlight (CompWindow *w)
+ static void
+ scaleaddonCheckWindowHighlight (CompScreen *s)
+ {
+- CompDisplay *d = s->display;
+-
+- ADDON_DISPLAY (d);
+-
+- if (ad->highlightedWindow != ad->lastHighlightedWindow)
+- {
+ CompWindow *w;
+
+- w = findWindowAtDisplay (d, ad->highlightedWindow);
+- if (w)
+- {
+- scaleaddonRenderWindowTitle (w);
+- addWindowDamage (w);
+- }
+-
+- w = findWindowAtDisplay (d, ad->lastHighlightedWindow);
+- if (w)
++ for (w = s->windows; w; w = w->next)
+ {
+- scaleaddonRenderWindowTitle (w);
+- addWindowDamage (w);
++ SCALE_WINDOW (w);
++ if (sw->slot)
++ {
++ scaleaddonRenderWindowTitle (w);
++ addWindowDamage (w);
++ }
+ }
+
+- ad->lastHighlightedWindow = ad->highlightedWindow;
+- }
+ }
+
+ static CompWindow*
+@@ -374,18 +380,22 @@ scaleaddonCloseWindow (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
+ Window xid;
++ int deviceid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
++ deviceid = getIntOptionNamed (option, nOption, "device", -1);
+
+ s = findScreenAtDisplay (d, xid);
+- if (s)
++ dev = compFindDeviceById (d, deviceid);
++ if (s && dev)
+ {
+ CompWindow *w;
+
+ SCALE_SCREEN (s);
+
+- if (!ss->grabIndex)
++ if (!ss->grab)
+ return FALSE;
+
+ if (state & CompActionStateInitKey)
+@@ -394,7 +404,7 @@ scaleaddonCloseWindow (CompDisplay *d,
+ w = findWindowAtDisplay (d, sd->hoveredWindow);
+ }
+ else
+- w = scaleaddonCheckForWindowAt (s, pointerX, pointerY);
++ w = scaleaddonCheckForWindowAt (s, dev->pointerX, dev->pointerY);
+
+ if (w)
+ {
+@@ -414,11 +424,15 @@ scaleaddonPullWindow (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
+ Window xid;
++ int deviceid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
++ deviceid = getIntOptionNamed (option, nOption, "device", -1);
+
+ s = findScreenAtDisplay (d, xid);
++ dev = compFindDeviceById (d, deviceid);
+ if (s)
+ {
+ CompWindow *w;
+@@ -434,7 +448,7 @@ scaleaddonPullWindow (CompDisplay *d,
+ w = findWindowAtDisplay (d, sd->hoveredWindow);
+ }
+ else
+- w = scaleaddonCheckForWindowAt (s, pointerX, pointerY);
++ w = scaleaddonCheckForWindowAt (s, dev->pointerX, dev->pointerY);
+
+ if (w)
+ {
+@@ -475,7 +489,7 @@ scaleaddonPullWindow (CompDisplay *d,
+ moveWindowToViewportPosition (w, x, y, TRUE);
+
+ /* Select this window when ending scale */
+- (*ss->selectWindow) (w);
++ (*ss->selectWindow) (w, NULL);
+
+ /* stop scaled window dissapearing */
+ sw->tx -= (s->x - vx) * s->width;
+@@ -529,18 +543,22 @@ scaleaddonZoomWindow (CompDisplay *d,
+ int nOption)
+ {
+ CompScreen *s;
++ CompDevice *dev;
+ Window xid;
++ int deviceid;
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
++ deviceid = getIntOptionNamed (option, nOption, "device", -1);
+
+ s = findScreenAtDisplay (d, xid);
+- if (s)
++ dev = compFindDeviceById (d, deviceid);
++ if (s && dev)
+ {
+ CompWindow *w;
+
+ SCALE_SCREEN (s);
+
+- if (!ss->grabIndex)
++ if (!ss->grab)
+ return FALSE;
+
+ if (state & CompActionStateInitKey)
+@@ -549,7 +567,7 @@ scaleaddonZoomWindow (CompDisplay *d,
+ w = findWindowAtDisplay (d, sd->hoveredWindow);
+ }
+ else
+- w = scaleaddonCheckForWindowAt (s, pointerX, pointerY);
++ w = scaleaddonCheckForWindowAt (s, dev->pointerX, dev->pointerY);
+
+ if (w)
+ {
+@@ -679,9 +697,11 @@ scaleaddonScalePaintDecoration (CompWindow *w,
+ unsigned int mask)
+ {
+ CompScreen *s = w->screen;
++ ScaleDevice *sDev;
+
+ ADDON_SCREEN (s);
+ SCALE_SCREEN (s);
++ SCALE_DISPLAY (s->display);
+ ADDON_WINDOW (w);
+
+ UNWRAP (as, ss, scalePaintDecoration);
+@@ -692,10 +712,12 @@ scaleaddonScalePaintDecoration (CompWindow *w,
+ {
+ if (scaleaddonGetWindowHighlight (s))
+ {
+- ADDON_DISPLAY (s->display);
+-
+- if (w->id == ad->highlightedWindow)
++ if (w->id == sd->selectedWindow)
+ scaleaddonDrawWindowHighlight (w);
++
++ for (sDev = ss->devices; sDev; sDev = sDev->next)
++ if (w->id == sDev->selectedWindow && sDev->selectedWindow != sd->selectedWindow)
++ scaleaddonDrawWindowHighlight (w);
+ }
+
+ if (aw->textPixmap)
+@@ -704,7 +726,8 @@ scaleaddonScalePaintDecoration (CompWindow *w,
+ }
+
+ static void
+-scaleaddonSelectWindow (CompWindow *w)
++scaleaddonSelectWindow (CompWindow *w,
++ ScaleDevice *sDev)
+ {
+ CompScreen *s = w->screen;
+
+@@ -717,7 +740,7 @@ scaleaddonSelectWindow (CompWindow *w)
+ scaleaddonCheckWindowHighlight (s);
+
+ UNWRAP (as, ss, selectWindow);
+- (*ss->selectWindow) (w);
++ (*ss->selectWindow) (w, sDev);
+ WRAP (as, ss, selectWindow, scaleaddonSelectWindow);
+ }
+
+@@ -820,6 +843,7 @@ scaleaddonHandleCompizEvent (CompDisplay *d,
+ removeScreenAction (s, scaleaddonGetCloseButton (d));
+ removeScreenAction (s, scaleaddonGetZoomButton (d));
+ removeScreenAction (s, scaleaddonGetPullButton (d));
++
+ }
+ }
+ }
+--
+1.5.6
+
diff --git a/fusion/plugins/shelf/0001-Input-Redirection-Support.patch b/fusion/plugins/shelf/0001-Input-Redirection-Support.patch
new file mode 100644
index 0000000..28aca59
--- /dev/null
+++ b/fusion/plugins/shelf/0001-Input-Redirection-Support.patch
@@ -0,0 +1,109 @@
+From 098ed60cd71581a8bd13a649ec355032b27f4dbe Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Fri, 31 Oct 2008 15:16:53 +0900
+Subject: [PATCH] Input Redirection Support
+
+---
+ shelf.c | 37 +++++++++++++++++++++++++++++++++++++
+ 1 files changed, 37 insertions(+), 0 deletions(-)
+
+diff --git a/shelf.c b/shelf.c
+index e6b636c..0a027e3 100644
+--- a/shelf.c
++++ b/shelf.c
+@@ -77,6 +77,7 @@ typedef struct {
+ DamageWindowRectProc damageWindowRect;
+ PreparePaintScreenProc preparePaintScreen;
+ WindowMoveNotifyProc windowMoveNotify;
++ TransformMeshProc transformMesh;
+ } ShelfScreen;
+
+ typedef struct {
+@@ -243,6 +244,7 @@ shelfPreparePaintScreen (CompScreen *s,
+ is running */
+ for (w = s->windows; w; w = w->next)
+ GET_SHELF_WINDOW (w, ss)->steps = steps;
++
+
+ UNWRAP (ss, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, msSinceLastPaint);
+@@ -375,6 +377,9 @@ shelfHandleShelfInfo (CompWindow *w)
+ {
+ SHELF_WINDOW (w);
+
++ if (w->screen->display->opt[COMP_DISPLAY_OPTION_REDIRECT_INPUT].value.b)
++ return FALSE;
++
+ if (sw->targetScale == 1.0f && sw->info)
+ {
+ if (sw->info->ipw)
+@@ -767,6 +772,7 @@ shelfPaintWindow (CompWindow *w,
+ sw->scale += (float) sw->steps * (sw->targetScale - sw->scale);
+ if (fabsf (sw->targetScale - sw->scale) < 0.005)
+ sw->scale = sw->targetScale;
++
+ }
+
+ if (sw->scale != 1.0f)
+@@ -786,6 +792,8 @@ shelfPaintWindow (CompWindow *w,
+
+ mask |= PAINT_WINDOW_TRANSFORMED_MASK;
+
++ updateMesh (w);
++
+ /* FIXME: should better use DonePaintScreen for that */
+ if (sw->scale != sw->targetScale)
+ addWindowDamage (w);
+@@ -843,6 +851,33 @@ shelfWindowMoveNotify (CompWindow *w,
+ WRAP (ss, w->screen, windowMoveNotify, shelfWindowMoveNotify);
+ }
+
++static void
++shelfTransformMesh (CompWindow *w,
++ CompTransform *transform,
++ CompMesh *mesh,
++ int nMesh,
++ Bool needsProjection)
++{
++ SHELF_WINDOW (w);
++ SHELF_SCREEN (w->screen);
++
++ float xTranslate, yTranslate;
++ CompTransform mTransform = *transform;
++
++ xTranslate = w->input.left * (sw->scale - 1.0f);
++ yTranslate = w->input.top * (sw->scale - 1.0f);
++
++ matrixTranslate (&mTransform, w->attrib.x, w->attrib.y, 0);
++ matrixScale (&mTransform, sw->scale, sw->scale, 0);
++ matrixTranslate (&mTransform,
++ xTranslate / sw->scale - w->attrib.x,
++ yTranslate / sw->scale - w->attrib.y,
++ 0.0f);
++
++ UNWRAP (ss, w->screen, transformMesh);
++ (*w->screen->transformMesh) (w, &mTransform, mesh, nMesh, needsProjection);
++ WRAP (ss, w->screen, transformMesh, shelfTransformMesh);
++}
+ /* Configuration, initialization, boring stuff. --------------------- */
+ static Bool
+ shelfInitScreen (CompPlugin *p,
+@@ -877,6 +912,7 @@ shelfInitScreen (CompPlugin *p,
+ WRAP (ss, s, paintOutput, shelfPaintOutput);
+ WRAP (ss, s, damageWindowRect, shelfDamageWindowRect);
+ WRAP (ss, s, windowMoveNotify, shelfWindowMoveNotify);
++ WRAP (ss, s, transformMesh, shelfTransformMesh);
+
+ s->base.privates[sd->screenPrivateIndex].ptr = ss;
+
+@@ -894,6 +930,7 @@ shelfFiniScreen (CompPlugin *p,
+ UNWRAP (ss, s, paintOutput);
+ UNWRAP (ss, s, damageWindowRect);
+ UNWRAP (ss, s, windowMoveNotify);
++ UNWRAP (ss, s, transformMesh);
+
+ freeWindowPrivateIndex (s, ss->windowPrivateIndex);
+
+--
+1.5.6
+
diff --git a/fusion/plugins/shift/0001-Input-Redirection-Support.patch b/fusion/plugins/shift/0001-Input-Redirection-Support.patch
new file mode 100644
index 0000000..8d0758f
--- /dev/null
+++ b/fusion/plugins/shift/0001-Input-Redirection-Support.patch
@@ -0,0 +1,164 @@
+From 85ca54e597a23d0069901cba316bf719661220f9 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Fri, 31 Oct 2008 15:12:07 +0900
+Subject: [PATCH] Input Redirection Support
+
+---
+ shift.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 76 insertions(+), 2 deletions(-)
+
+diff --git a/shift.c b/shift.c
+index 4978c9f..1739772 100644
+--- a/shift.c
++++ b/shift.c
+@@ -103,6 +103,7 @@ typedef struct _ShiftScreen {
+ PaintOutputProc paintOutput;
+ PaintWindowProc paintWindow;
+ DamageWindowRectProc damageWindowRect;
++ TransformMeshProc transformMesh;
+
+ int grabIndex;
+
+@@ -170,6 +171,8 @@ typedef struct _ShiftWindow {
+ float opacityVelocity;
+ float brightnessVelocity;
+
++ int meshIter;
++
+ Bool active;
+ } ShiftWindow;
+
+@@ -553,6 +556,8 @@ shiftPaintWindow (CompWindow *w,
+ matrixTranslate (&wTransform, -w->attrib.x - (w->width / 2),
+ -w->attrib.y - (w->attrib.height / 2), 0.0f);
+
++ updateMesh (w);
++
+ glPushMatrix ();
+ glLoadMatrixf (wTransform.m);
+
+@@ -1746,7 +1751,7 @@ shiftTerm (CompScreen *s, Bool cancel)
+
+ if (ss->grabIndex)
+ {
+- removeScreenGrab (s, ss->grabIndex, 0);
++ //removeScreenGrab (s, ss->grabIndex, 0);
+ ss->grabIndex = 0;
+ }
+
+@@ -1833,7 +1838,7 @@ shiftInitiateScreen (CompScreen *s,
+ return FALSE;
+
+ if (!ss->grabIndex)
+- ss->grabIndex = pushScreenGrab (s, s->invisibleCursor, "shift");
++ ss->grabIndex = 1;//pushScreenGrab (s, s->invisibleCursor, "shift");
+
+
+ if (ss->grabIndex)
+@@ -2394,6 +2399,69 @@ shiftDamageWindowRect (CompWindow *w,
+ return status;
+ }
+
++static void
++shiftTransformMesh (CompWindow *w,
++ CompTransform *transform,
++ CompMesh *mesh,
++ int meshIter,
++ Bool needsProjection)
++{
++ SHIFT_SCREEN (w->screen);
++ CompTransform shiftTransform = *transform;
++ Bool project = needsProjection;
++
++ SHIFT_WINDOW (w);
++
++ if (!ss->reflectActive)
++ {
++ if (sw->active)
++ {
++ ShiftSlot *slot;
++ if (meshIter == sw->meshIter)
++ slot = &sw->slots[1];
++ else
++ slot = &sw->slots[0];
++
++ float sx = ss->anim * slot->tx;
++ float sy = ss->anim * slot->ty;
++ float sz = ss->anim * slot->z;
++ float srot = (ss->anim * slot->rotation);
++ float sscale;
++
++ if (slot->primary)
++ sscale = (ss->anim * slot->scale) + (1 - ss->anim);
++ else
++ sscale = ss->anim * slot->scale;
++
++ matrixTranslate (&shiftTransform, sx, sy, sz);
++
++ matrixTranslate (&shiftTransform,
++ w->attrib.x + (w->attrib.width * sscale / 2),
++ w->attrib.y + (w->attrib.height * sscale / 2.0),
++ 0.0f);
++
++ matrixScale (&shiftTransform, ss->output->width, -ss->output->height,
++ 1.0f);
++
++ matrixRotate (&shiftTransform, srot, 0.0, 1.0, 0.0);
++
++ matrixScale (&shiftTransform, 1.0f / ss->output->width,
++ -1.0f / ss->output->height, 1.0f);
++
++ matrixScale (&shiftTransform, sscale, sscale, 1.0f);
++ matrixTranslate (&shiftTransform, -w->attrib.x - (w->width / 2),
++ -w->attrib.y - (w->attrib.height / 2), 0.0f);
++
++ project = TRUE;
++ }
++ }
++
++ UNWRAP (ss, w->screen, transformMesh);
++ (*w->screen->transformMesh) (w, &shiftTransform, mesh, meshIter, project);
++ WRAP (ss, w->screen, transformMesh, shiftTransformMesh);
++
++}
++
+ static Bool
+ shiftInitDisplay (CompPlugin *p,
+ CompDisplay *d)
+@@ -2542,6 +2610,7 @@ shiftInitScreen (CompPlugin *p,
+ WRAP (ss, s, paintOutput, shiftPaintOutput);
+ WRAP (ss, s, paintWindow, shiftPaintWindow);
+ WRAP (ss, s, damageWindowRect, shiftDamageWindowRect);
++ WRAP (ss, s, transformMesh, shiftTransformMesh);
+
+ ss->cursor = XCreateFontCursor (s->display->display, XC_left_ptr);
+
+@@ -2564,6 +2633,7 @@ shiftFiniScreen (CompPlugin *p,
+ UNWRAP (ss, s, paintOutput);
+ UNWRAP (ss, s, paintWindow);
+ UNWRAP (ss, s, damageWindowRect);
++ UNWRAP (ss, s, transformMesh);
+
+ matchFini (&ss->match);
+
+@@ -2597,6 +2667,8 @@ shiftInitWindow (CompPlugin *p,
+
+ sw->brightness = 1.0;
+ sw->opacity = 1.0;
++
++ sw->meshIter = incrementMesh (w) - 1;
+
+ w->base.privates[ss->windowPrivateIndex].ptr = sw;
+
+@@ -2609,6 +2681,8 @@ shiftFiniWindow (CompPlugin *p,
+ {
+ SHIFT_WINDOW (w);
+
++ decrementMesh (w, sw->meshIter);
++
+ free (sw);
+ }
+
+--
+1.5.6
+
diff --git a/fusion/plugins/showmouse/0001-MPX-Inclusion.patch b/fusion/plugins/showmouse/0001-MPX-Inclusion.patch
new file mode 100644
index 0000000..5b5e065
--- /dev/null
+++ b/fusion/plugins/showmouse/0001-MPX-Inclusion.patch
@@ -0,0 +1,518 @@
+From d1243367970e220c316f9f570ac73881a681ebb7 Mon Sep 17 00:00:00 2001
+From: Sam Spilsbury <Sam@XPS-SUSE.site>
+Date: Wed, 29 Oct 2008 15:22:30 +0900
+Subject: [PATCH] * MPX Inclusion
+
+---
+ showmouse.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++-------------
+ 1 files changed, 242 insertions(+), 67 deletions(-)
+
+diff --git a/showmouse.c b/showmouse.c
+index 7e9acfb..3fc4d7f 100644
+--- a/showmouse.c
++++ b/showmouse.c
+@@ -93,27 +93,33 @@ typedef struct _ParticleSystem
+
+ static int displayPrivateIndex = 0;
+
++typedef struct _ShowmouseDevice
++{
++ int posX;
++ int posY;
++
++ ParticleSystem *ps;
++ float rot;
++
++ CompDevice *dev;
++ struct _ShowmouseDevice *next;
++} ShowmouseDevice;
++
+ typedef struct _ShowmouseDisplay
+ {
+ int screenPrivateIndex;
+
+ MousePollFunc *mpFunc;
++ ShowmouseDevice *devices;
+ }
+ ShowmouseDisplay;
+
+ typedef struct _ShowmouseScreen
+ {
+- int posX;
+- int posY;
+-
+ Bool active;
+
+- ParticleSystem *ps;
+-
+- float rot;
+-
+ PositionPollingHandle pollHandle;
+-
++
+ PreparePaintScreenProc preparePaintScreen;
+ DonePaintScreenProc donePaintScreen;
+ PaintOutputProc paintOutput;
+@@ -352,11 +358,11 @@ finiParticles (ParticleSystem * ps)
+ }
+
+ static void
+-genNewParticles(CompScreen *s,
++genNewParticles(CompScreen *s,
++ ShowmouseDevice *dev,
+ ParticleSystem *ps,
+ int time)
+ {
+- SHOWMOUSE_SCREEN(s);
+
+ Bool rColor = showmouseGetRandom (s);
+ float life = showmouseGetLife (s);
+@@ -387,10 +393,10 @@ genNewParticles(CompScreen *s,
+ int radius = showmouseGetRadius (s);
+ for (i = 0; i < nE; i++)
+ {
+- pos[i][0] = sin (ss->rot + (i * rA)) * radius;
+- pos[i][0] += ss->posX;
+- pos[i][1] = cos (ss->rot + (i * rA)) * radius;
+- pos[i][1] += ss->posY;
++ pos[i][0] = sin (dev->rot + (i * rA)) * radius;
++ pos[i][0] += dev->posX;
++ pos[i][1] = cos (dev->rot + (i * rA)) * radius;
++ pos[i][1] += dev->posY;
+ }
+
+ for (i = 0; i < ps->numParticles && max_new > 0; i++, part++)
+@@ -458,16 +464,15 @@ genNewParticles(CompScreen *s,
+
+
+ static void
+-damageRegion (CompScreen *s)
++damageRegion (CompScreen *s,
++ ShowmouseDevice *dev)
+ {
+ REGION r;
+ int i;
+ Particle *p;
+ float w, h, x1, x2, y1, y2;
+
+- SHOWMOUSE_SCREEN (s);
+-
+- if (!ss->ps)
++ if (!dev->ps)
+ return;
+
+ x1 = s->width;
+@@ -475,9 +480,9 @@ damageRegion (CompScreen *s)
+ y1 = s->height;
+ y2 = 0;
+
+- p = ss->ps->particles;
++ p = dev->ps->particles;
+
+- for (i = 0; i < ss->ps->numParticles; i++, p++)
++ for (i = 0; i < dev->ps->numParticles; i++, p++)
+ {
+ w = p->width / 2;
+ h = p->height / 2;
+@@ -502,15 +507,154 @@ damageRegion (CompScreen *s)
+ damageScreenRegion (s, &r);
+ }
+
++/* Device management */
++
++static Bool
++showmouseAddDevToList (CompDisplay *d,
++ CompDevice *dev)
++{
++ SHOWMOUSE_DISPLAY (d);
++
++ ShowmouseDevice *run;
++
++ if (!sd->devices)
++ {
++ sd->devices = calloc (1, sizeof(ShowmouseDevice));
++ if (!sd->devices)
++ return FALSE;
++ sd->devices->dev = dev;
++ sd->devices->ps = NULL;
++ sd->devices->next = NULL;
++ }
++ else
++ {
++ for (run = sd->devices; run->next; run = run->next);
++
++ run->next = calloc (1, sizeof(ShowmouseDevice));
++ if (!run->next)
++ return FALSE;
++ run->next->dev = dev;
++ run->next->ps = NULL;
++ run->next->next = NULL;
++ }
++ return TRUE;
++}
++
++static void
++showmouseRemoveDevFromList (CompDisplay *d,
++ CompDevice *dev)
++{
++ SHOWMOUSE_DISPLAY (d);
++
++ ShowmouseDevice *run = NULL;
++
++ for (run = sd->devices; run; run = run->next)
++ if (run->dev == dev)
++ break;
++
++ if (run == sd->devices)
++ {
++ if (sd->devices->next)
++ sd->devices = sd->devices->next;
++ else
++ sd->devices = NULL;
++
++ if (run)
++ free (run);
++ }
++ else
++ {
++ for (run = sd->devices; run; run = run->next)
++ {
++ if (run->dev == dev)
++ break;
++ }
++
++ ShowmouseDevice *selected = run;
++
++ if (selected)
++ if (selected->next)
++ {
++ run = run->next;
++ free(selected);
++ }
++ }
++}
++
++static void
++showmouseCheckList (CompDisplay *d,
++ MousepollDevice *list)
++{
++ SHOWMOUSE_DISPLAY (d);
++ Bool ok = FALSE;
++ MousepollDevice *run;
++ ShowmouseDevice *ptr;
++ CompDevice *addDev = NULL, *removeDev = NULL;
++
++ do
++ {
++ for (run = list; run; run = run->next)
++ {
++ addDev = run->dev;
++ for (ptr = sd->devices; ptr; ptr = ptr->next)
++ {
++ if (ptr->dev == run->dev)
++ {
++ addDev = NULL;
++ break;
++ }
++ }
++ if (addDev) break;
++ }
++
++ for (ptr = sd->devices; ptr; ptr = ptr->next)
++ {
++ removeDev = ptr->dev;
++ for (run = list; run; run = run->next)
++ {
++ if (run->dev == ptr->dev)
++ {
++ removeDev = NULL;
++ break;
++ }
++ }
++ if (removeDev) break;
++ }
++
++ if (addDev)
++ showmouseAddDevToList (d, addDev);
++
++ if (removeDev)
++ showmouseRemoveDevFromList (d, removeDev);
++
++ if (addDev || removeDev)
++ ok = FALSE;
++ else
++ ok = TRUE;
++ } while (!ok);
++}
++
+ static void
+ positionUpdate (CompScreen *s,
+- int x,
+- int y)
++ MousepollDevice *dev)
+ {
+- SHOWMOUSE_SCREEN (s);
++ SHOWMOUSE_DISPLAY (s->display);
++
++ MousepollDevice *run;
++ ShowmouseDevice *ptr;
+
+- ss->posX = x;
+- ss->posY = y;
++ // if size in list has changed
++ showmouseCheckList (s->display, dev);
++
++ /* List should be in sync */
++ for (run = dev; run; run = run->next)
++ {
++ for (ptr = sd->devices; ptr; ptr = ptr->next)
++ if (ptr->dev == run->dev) break;
++ ptr->posX = run->posX;
++ ptr->posY = run->posY;
++
++ }
+ }
+
+
+@@ -521,31 +665,29 @@ showmousePreparePaintScreen (CompScreen *s,
+ SHOWMOUSE_SCREEN (s);
+ SHOWMOUSE_DISPLAY (s->display);
+
+- if (ss->active && !ss->pollHandle)
+- {
+- (*sd->mpFunc->getCurrentPosition) (s, &ss->posX, &ss->posY);
+- ss->pollHandle = (*sd->mpFunc->addPositionPolling) (s, positionUpdate);
+- }
++ ShowmouseDevice *dev;
+
+- if (ss->active && !ss->ps)
++ for (dev = sd->devices; dev; dev = dev->next)
++ {
++ if (ss->active && !dev->ps)
+ {
+- ss->ps = calloc(1, sizeof(ParticleSystem));
+- if (!ss->ps)
++ dev->ps = calloc(1, sizeof(ParticleSystem));
++ if (!dev->ps)
+ {
+ UNWRAP (ss, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, time);
+ WRAP (ss, s, preparePaintScreen, showmousePreparePaintScreen);
+ return;
+ }
+- initParticles(showmouseGetNumParticles (s), ss->ps);
++ initParticles(showmouseGetNumParticles (s), dev->ps);
+
+- ss->ps->slowdown = showmouseGetSlowdown (s);
+- ss->ps->darken = showmouseGetDarken (s);
+- ss->ps->blendMode = (showmouseGetBlend(s)) ? GL_ONE :
++ dev->ps->slowdown = showmouseGetSlowdown (s);
++ dev->ps->darken = showmouseGetDarken (s);
++ dev->ps->blendMode = (showmouseGetBlend(s)) ? GL_ONE :
+ GL_ONE_MINUS_SRC_ALPHA;
+
+- glGenTextures(1, &ss->ps->tex);
+- glBindTexture(GL_TEXTURE_2D, ss->ps->tex);
++ glGenTextures(1, &dev->ps->tex);
++ glBindTexture(GL_TEXTURE_2D, dev->ps->tex);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+@@ -555,18 +697,18 @@ showmousePreparePaintScreen (CompScreen *s,
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+- ss->rot = fmod (ss->rot + (((float)time / 1000.0) * 2 * M_PI *
++ dev->rot = fmod (dev->rot + (((float)time / 1000.0) * 2 * M_PI *
+ showmouseGetRotationSpeed (s)), 2 * M_PI);
+
+- if (ss->ps && ss->ps->active)
++ if (dev->ps && dev->ps->active)
+ {
+- updateParticles (ss->ps, time);
+- damageRegion (s);
++ updateParticles (dev->ps, time);
++ damageRegion (s, dev);
+ }
+
+- if (ss->ps && ss->active)
+- genNewParticles (s, ss->ps, time);
+-
++ if (dev->ps && ss->active)
++ genNewParticles (s, dev, dev->ps, time);
++ }
+ UNWRAP (ss, s, preparePaintScreen);
+ (*s->preparePaintScreen) (s, time);
+ WRAP (ss, s, preparePaintScreen, showmousePreparePaintScreen);
+@@ -575,23 +717,29 @@ showmousePreparePaintScreen (CompScreen *s,
+ static void
+ showmouseDonePaintScreen (CompScreen *s)
+ {
+- SHOWMOUSE_SCREEN (s);
+- SHOWMOUSE_DISPLAY (s->display);
+
+- if (ss->active || (ss->ps && ss->ps->active))
+- damageRegion (s);
++ ShowmouseDevice *dev;
+
++ SHOWMOUSE_SCREEN (s);
++ SHOWMOUSE_DISPLAY (s->display);
+ if (!ss->active && ss->pollHandle)
+ {
+ (*sd->mpFunc->removePositionPolling) (s, ss->pollHandle);
+ ss->pollHandle = 0;
+ }
+
+- if (!ss->active && ss->ps && !ss->ps->active)
++ for (dev = sd->devices; dev; dev = dev->next)
+ {
+- finiParticles (ss->ps);
+- free (ss->ps);
+- ss->ps = NULL;
++
++ if (ss->active || (dev->ps && dev->ps->active))
++ damageRegion (s, dev);
++ if (!ss->active && dev->ps && !dev->ps->active)
++ {
++ finiParticles (dev->ps);
++ free (dev->ps);
++ dev->ps = NULL;
++ showmouseRemoveDevFromList (s, dev);
++ }
+ }
+
+ UNWRAP (ss, s, donePaintScreen);
+@@ -607,16 +755,30 @@ showmousePaintOutput (CompScreen *s,
+ CompOutput *output,
+ unsigned int mask)
+ {
+- Bool status;
++ Bool status, ps;
+ CompTransform sTransform;
++ ShowmouseDevice *dev;
+
+ SHOWMOUSE_SCREEN (s);
++ SHOWMOUSE_DISPLAY (s->display);
+
+ UNWRAP (ss, s, paintOutput);
+ status = (*s->paintOutput) (s, sa, transform, region, output, mask);
+ WRAP (ss, s, paintOutput, showmousePaintOutput);
+
+- if (!ss->ps || !ss->ps->active)
++ for (dev = sd->devices; dev; dev = dev->next)
++ {
++ if (dev->ps)
++ {
++ if (dev->ps->active)
++ {
++ ps = TRUE;
++ break;
++ }
++ }
++ }
++
++ if (!ps)
+ return status;
+
+ matrixGetIdentity (&sTransform);
+@@ -626,8 +788,12 @@ showmousePaintOutput (CompScreen *s,
+ glPushMatrix ();
+ glLoadMatrixf (sTransform.m);
+
+- drawParticles (s, ss->ps);
+-
++ for (dev = sd->devices; dev; dev = dev->next)
++ {
++ if (dev->ps)
++ if (dev->ps->active)
++ drawParticles (s, dev->ps);
++ }
+ glPopMatrix();
+
+ glColor4usv (defaultColor);
+@@ -644,6 +810,9 @@ showmouseTerminate (CompDisplay *d,
+ {
+ CompScreen *s;
+ Window xid;
++ ShowmouseDevice *dev;
++
++ SHOWMOUSE_DISPLAY (d);
+
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+
+@@ -653,7 +822,8 @@ showmouseTerminate (CompDisplay *d,
+ SHOWMOUSE_SCREEN (s);
+
+ ss->active = FALSE;
+- damageRegion (s);
++ for (dev = sd->devices; dev; dev = dev->next)
++ damageRegion (s, dev);
+
+ return TRUE;
+ }
+@@ -670,6 +840,8 @@ showmouseInitiate (CompDisplay *d,
+ CompScreen *s;
+ Window xid;
+
++ SHOWMOUSE_DISPLAY (d);
++
+ xid = getIntOptionNamed (option, nOption, "root", 0);
+
+ s = findScreenAtDisplay (d, xid);
+@@ -681,7 +853,7 @@ showmouseInitiate (CompDisplay *d,
+ return showmouseTerminate (d, action, state, option, nOption);
+
+ ss->active = TRUE;