summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Spilsbury <smspillaz@gmail.com>2010-08-19 07:40:44 +0800
committerSam Spilsbury <smspillaz@gmail.com>2010-08-19 07:40:44 +0800
commit32970c2be62f5322bb97126d9c541564d7b34f46 (patch)
treef6121fd7805aa33060f62263d8d1c0dde67cf315
parent2a225e2bf07e92e9974f77f05d325995c87584b8 (diff)
downloadwinreflect-32970c2be62f5322bb97126d9c541564d7b34f46.tar.gz
winreflect-32970c2be62f5322bb97126d9c541564d7b34f46.tar.bz2
New plugin: Reflective Surface
-rw-r--r--CMakeLists.txt5
-rw-r--r--src/winreflect.cpp342
-rw-r--r--src/winreflect.h125
-rw-r--r--winreflect.xml.in27
4 files changed, 499 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..c87aebf
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,5 @@
+find_package (Compiz REQUIRED)
+
+include (CompizPlugin)
+
+compiz_plugin (winreflect PLUGINDEPS composite opengl) \ No newline at end of file
diff --git a/src/winreflect.cpp b/src/winreflect.cpp
new file mode 100644
index 0000000..2c7a7e2
--- /dev/null
+++ b/src/winreflect.cpp
@@ -0,0 +1,342 @@
+/*
+ *
+ * Compiz Window reflection plugin
+ *
+ * winreflect.h
+ *
+ * Copyright : (C) 2007 by Sam Spilsbury
+ * Email : <smspillaz@gmail.com>
+ *
+ * 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.
+ *
+ */
+
+#include "winreflect.h"
+
+COMPIZ_PLUGIN_20090315 (winreflect, WinrelfectPluginVTable);
+
+void
+WinreflectScreen::updateReflectionProperty (Window id)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *propData;
+ bool validProperty = false;
+ bool found = false;
+ CompRegion reg (emptyRegion);
+
+ result = XGetWindowProperty (screen->dpy (), id,
+ mReflectedRegionAtom, 0, 32768,
+ false, AnyPropertyType, &actual, &format,
+ &n, &left, &propData);
+
+ if (result == Success && propData)
+ {
+ if (format == 32 && actual == XA_CARDINAL &&
+ n > 0 && (n % 4 == 0))
+ {
+ long *data = (long *) propData;
+ unsigned int nBox = n / 4;
+
+ while (nBox--)
+ {
+ int x, y, w, h;
+ x = *data++;
+ y = *data++;
+ w = *data++;
+ h = *data++;
+
+ CompRect r (x, y, w, h);
+
+ reg += r;
+ }
+
+ validProperty = true;
+ }
+
+ XFree (propData);
+ }
+
+ foreach (ReflectionRegion r, mReflectedRegions)
+ {
+ if (r.id == id)
+ {
+ ReflectionRegion nR (reg);
+
+ nR.id = id;
+
+ found = true;
+ mReflectedRegions.remove (r);
+
+ if (validProperty)
+ mReflectedRegions.push_back (nR);
+
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ ReflectionRegion nR (reg);
+
+ nR.id = id;
+
+ mReflectedRegions.push_back (nR);
+ }
+
+}
+
+void
+WinreflectScreen::optionChange (CompOption *opt,
+ Options num)
+{
+ switch (num)
+ {
+ case WinreflectOptions::ReflectDocks:
+ {
+ if (opt->value ().b ())
+ {
+ foreach (CompWindow *w, screen->windows ())
+ {
+ if (w->type () == CompWindowTypeDockMask)
+ {
+ CompRect in (w->inputRect ());
+ ReflectionRegion r (in);
+
+ r.id = w->id ();
+
+ mReflectedRegions.push_back (r);
+ }
+ }
+ }
+ else
+ {
+ std::list <ReflectionRegion>::iterator it = mReflectedRegions.begin ();
+
+ while (it != mReflectedRegions.end ())
+ {
+ ReflectionRegion r = *it;
+ CompWindow *w = screen->findWindow (r.id);
+
+ if (w && w->type () == CompWindowTypeDockMask)
+ {
+ mReflectedRegions.remove (r);
+ it = mReflectedRegions.begin ();
+ }
+ it++;
+ }
+ }
+ }
+ default:
+ break;
+ }
+}
+
+void
+WinreflectScreen::handleEvent (XEvent *event)
+{
+ switch (event->type)
+ {
+ case PropertyNotify:
+ if (event->xproperty.atom == mReflectedRegionAtom)
+ updateReflectionProperty (event->xproperty.window);
+ break;
+ case DestroyNotify:
+ foreach (ReflectionRegion &r, mReflectedRegions)
+ {
+ if (event->xdestroywindow.window == r.id)
+ {
+ mReflectedRegions.remove (r);
+ break;
+ }
+ }
+ break;
+ case ConfigureNotify:
+ foreach (ReflectionRegion &r, mReflectedRegions)
+ {
+ if (event->xconfigure.window = r.id)
+ {
+ CompWindow *w = screen->findWindow (r.id);
+
+ if (w->type () == CompWindowTypeDockMask &&
+ optionGetReflectDocks ())
+ {
+ CompRect in (w->inputRect ());
+ ReflectionRegion nR (in);
+
+ mReflectedRegions.remove (r);
+
+ nR.id = w->id ();
+
+ mReflectedRegions.push_back (nR);
+
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ screen->handleEvent (event);
+}
+
+bool
+WinreflectScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
+
+ mIsTransformed = false;
+
+ return gScreen->glPaintOutput (attrib, transform, region, output, mask);
+}
+
+void
+WinreflectScreen::glPaintTransformedOutput (const GLScreenPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ mIsTransformed = true;
+
+ return gScreen->glPaintTransformedOutput (attrib, transform, region, output, mask);
+}
+
+bool
+WinreflectWindow::glPaint (const GLWindowPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ unsigned int mask)
+{
+ WINREFLECT_SCREEN (screen);
+
+ GLFragment::Attrib fA (attrib);
+ GLMatrix wTransform (transform);
+ int cull, cullInv;
+ bool status = false;
+ glGetIntegerv (GL_CULL_FACE_MODE, &cull);
+ cullInv = (cull == GL_BACK)? GL_FRONT : GL_BACK;
+
+ status |= gWindow->glPaint (attrib, transform, region, mask);
+
+ if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK ||
+ mask & PAINT_WINDOW_NO_CORE_INSTANCE_MASK)
+ return status;
+
+ if (ws->mIsTransformed)
+ return status;
+
+ foreach (ReflectionRegion reg, ws->mReflectedRegions)
+ {
+ CompRegion reflectiveRegion ((CompRegion &) reg);
+
+ reflectiveRegion.translate (0, -reflectiveRegion.boundingRect ().height ());
+ reflectiveRegion = reflectiveRegion.united ((CompRegion &) reg);
+
+ /* Don't bother if the window doesn't intersect the reflective region */
+ if (!(CompRegion (window->outputRect ()).intersects (reflectiveRegion)))
+ continue;
+
+ fA.setOpacity (fA.getOpacity () * ((float) ws->optionGetOpacity () / 100.0f));
+
+ wTransform.translate (0.0, reg.boundingRect ().top () * 2, 0.0f);
+ wTransform.scale (1.0f, -1.0f, 1.0f);
+
+ if (window->alpha () || fA.getOpacity () != OPAQUE)
+ mask |= PAINT_WINDOW_TRANSLUCENT_MASK;
+
+ mask |= PAINT_WINDOW_TRANSFORMED_MASK;
+
+ glPushMatrix ();
+ glLoadMatrixf (wTransform.getMatrix ());
+
+ glPushAttrib (GL_SCISSOR_BIT);
+ glEnable (GL_SCISSOR_TEST);
+ glCullFace (cullInv);
+
+ /* For every single rect that the client gave us, draw another clipped reflected window
+ * FIXME: this approach really sucks and is a waste of CPU time for complicated shapes
+ * is there some other clever GL function we can use here?
+ */
+
+ foreach (const CompRect &r, reg.rects ())
+ {
+ CompRect clipBox (r);
+
+ glScissor (clipBox.x1 (), screen->height () - clipBox.y2 (), clipBox.width (), clipBox.height ());
+
+ status = gWindow->glDraw (wTransform, fA, region, mask);
+ }
+
+ glCullFace (cull);
+ glDisable (GL_SCISSOR_TEST);
+ glPopAttrib ();
+ glPopMatrix ();
+
+ }
+
+ return status;
+}
+
+bool
+WinreflectWindow::damageRect (bool initial, const CompRect &rect)
+{
+ CompRegion r = window->region ();
+
+ r = r.united (r.translated (0, r.boundingRect ().height ()));
+ r.shrink (-100, -100);
+
+ WinreflectScreen::get (screen)->cScreen->damageRegion (r);
+
+ return cWindow->damageRect (initial, rect);
+}
+
+WinreflectWindow::WinreflectWindow (CompWindow *w) :
+ PluginClassHandler <WinreflectWindow, CompWindow> (w),
+ window (w),
+ cWindow (CompositeWindow::get (w)),
+ gWindow (GLWindow::get (w))
+{
+ CompositeWindowInterface::setHandler (cWindow);
+ GLWindowInterface::setHandler (gWindow);
+}
+
+WinreflectScreen::WinreflectScreen (CompScreen *s) :
+ PluginClassHandler <WinreflectScreen, CompScreen> (s),
+ cScreen (CompositeScreen::get (s)),
+ gScreen (GLScreen::get (s)),
+ mReflectedRegionAtom (XInternAtom (s->dpy (), "_COMPIZ_NET_CM_REFLECTED_REGION", FALSE)),
+ mIsTransformed (false)
+{
+ ScreenInterface::setHandler (screen);
+ GLScreenInterface::setHandler (gScreen);
+
+ optionSetReflectDocksNotify (boost::bind (&WinreflectScreen::optionChange, this, _1, _2));
+}
+
+bool
+WinrelfectPluginVTable::init ()
+{
+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) ||
+ !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) ||
+ !CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
+ return false;
+
+ return true;
+}
+
diff --git a/src/winreflect.h b/src/winreflect.h
new file mode 100644
index 0000000..30c0483
--- /dev/null
+++ b/src/winreflect.h
@@ -0,0 +1,125 @@
+/*
+ *
+ * Compiz Window reflection plugin
+ *
+ * winreflect.h
+ *
+ * Copyright : (C) 2007 by Sam Spilsbury
+ * Email : <smspillaz@gmail.com>
+ *
+ * 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.
+ *
+ */
+
+#include <core/core.h>
+#include <composite/composite.h>
+#include <opengl/opengl.h>
+
+#include "winreflect_options.h"
+
+#include <X11/Xatom.h>
+
+class ReflectionRegion :
+ public CompRegion
+{
+ public:
+
+ ReflectionRegion (CompRect &r) :
+ CompRegion::CompRegion (r) {};
+
+ ReflectionRegion (CompRegion &r) :
+ CompRegion::CompRegion (r) {};
+
+ unsigned int id;
+};
+
+
+class WinreflectScreen :
+ public PluginClassHandler <WinreflectScreen, CompScreen>,
+ public ScreenInterface,
+ public GLScreenInterface,
+ public WinreflectOptions
+{
+ public:
+
+ WinreflectScreen (CompScreen *);
+
+ public:
+
+ CompositeScreen *cScreen;
+ GLScreen *gScreen;
+
+ void
+ updateReflectionProperty (Window id);
+
+ void
+ handleEvent (XEvent *);
+
+ void
+ optionChange (CompOption *, Options);
+
+ bool
+ glPaintOutput (const GLScreenPaintAttrib &,
+ const GLMatrix &,
+ const CompRegion &,
+ CompOutput *,
+ unsigned int );
+
+ void
+ glPaintTransformedOutput (const GLScreenPaintAttrib &,
+ const GLMatrix &,
+ const CompRegion &,
+ CompOutput *,
+ unsigned int );
+
+ std::list<ReflectionRegion> mReflectedRegions;
+ Atom mReflectedRegionAtom;
+
+ bool mIsTransformed;
+};
+
+#define WINREFLECT_SCREEN(s) \
+ WinreflectScreen *ws = WinreflectScreen::get (s)
+
+class WinreflectWindow :
+ public PluginClassHandler <WinreflectWindow, CompWindow>,
+ public CompositeWindowInterface,
+ public GLWindowInterface
+{
+ public:
+
+ CompWindow *window;
+ CompositeWindow *cWindow;
+ GLWindow *gWindow;
+
+ WinreflectWindow (CompWindow *w);
+
+ bool
+ glPaint (const GLWindowPaintAttrib &,
+ const GLMatrix &,
+ const CompRegion &,
+ unsigned int );
+
+ bool
+ damageRect (bool,
+ const CompRect &);
+};
+
+#define WINREFLECT_WINDOW(w) \
+ WinreflectWindow *ww = WinreflectWindow::get (w)
+
+class WinrelfectPluginVTable :
+ public CompPlugin::VTableForScreenAndWindow <WinreflectScreen, WinreflectWindow>
+{
+ public:
+
+ bool init ();
+};
diff --git a/winreflect.xml.in b/winreflect.xml.in
new file mode 100644
index 0000000..ced1220
--- /dev/null
+++ b/winreflect.xml.in
@@ -0,0 +1,27 @@
+<compiz>
+ <plugin name="winreflect" useBcop="true">
+ <_short>Window Reflections</_short>
+ <_long>Reflect windows in specified areas</_long>
+ <deps>
+ <requirement>
+ <plugin>opengl</plugin>
+ <plugin>composite</plugin>
+ </requirement>
+ </deps>
+ <options>
+ <option name="opacity" type="int">
+ <_short>Opacity</_short>
+ <_long>Opacity of relfected windows</_long>
+ <default>100</default>
+ <min>0</min>
+ <max>100</max>
+ </option>
+ <option name="reflect_docks" type="bool">
+ <_short>Reflect Docks</_short>
+ <_long>Add reflection area to docks by default. Note that this will not look correct on nonrectangular docks, they should set a hint instead</_long>
+ <default>false</default>
+ </option>
+ </options>
+ </plugin>
+</compiz>
+