diff options
Diffstat (limited to 'src/winreflect.cpp')
-rw-r--r-- | src/winreflect.cpp | 342 |
1 files changed, 342 insertions, 0 deletions
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 ®ion, + 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 ®ion, + 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 ®ion, + 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; +} + |