summaryrefslogtreecommitdiff
path: root/plugins/composite
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/composite')
-rw-r--r--plugins/composite/CMakeLists.txt5
-rw-r--r--plugins/composite/compiz-composite.pc.in12
-rw-r--r--plugins/composite/composite.xml.in35
-rw-r--r--plugins/composite/include/composite/composite.h408
-rw-r--r--plugins/composite/src/composite.cpp103
-rw-r--r--plugins/composite/src/privates.h156
-rw-r--r--plugins/composite/src/screen.cpp998
-rw-r--r--plugins/composite/src/window.cpp630
8 files changed, 2347 insertions, 0 deletions
diff --git a/plugins/composite/CMakeLists.txt b/plugins/composite/CMakeLists.txt
new file mode 100644
index 0000000..df247f3
--- /dev/null
+++ b/plugins/composite/CMakeLists.txt
@@ -0,0 +1,5 @@
+find_package (Compiz REQUIRED)
+
+include (CompizPlugin)
+
+compiz_plugin(composite) \ No newline at end of file
diff --git a/plugins/composite/compiz-composite.pc.in b/plugins/composite/compiz-composite.pc.in
new file mode 100644
index 0000000..8459cfe
--- /dev/null
+++ b/plugins/composite/compiz-composite.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: compiz-composite
+Description: Compositing plugin for compiz
+Version: @VERSION@
+
+Requires: compiz
+Libs: @_composite_plugin_LDFLAGS@ -L${libdir} -lcomposite
+Cflags: @COMPIZ_CFLAGS@ @_composite_plugin_CFLAGS@ -I${includedir}/compiz \ No newline at end of file
diff --git a/plugins/composite/composite.xml.in b/plugins/composite/composite.xml.in
new file mode 100644
index 0000000..f43abcd
--- /dev/null
+++ b/plugins/composite/composite.xml.in
@@ -0,0 +1,35 @@
+<compiz>
+ <plugin name="composite" useBcop="true">
+ <_short>Composite</_short>
+ <_long>Composite plugin</_long>
+ <category>General</category>
+ <options>
+ <option name="slow_animations_key" type="key">
+ <_short>Slow Animations</_short>
+ <_long>Toggle use of slow animations</_long>
+ </option>
+ <option name="detect_refresh_rate" type="bool">
+ <_short>Detect Refresh Rate</_short>
+ <_long>Automatic detection of refresh rate</_long>
+ <default>true</default>
+ </option>
+ <option name="refresh_rate" type="int">
+ <_short>Refresh Rate</_short>
+ <_long>The rate at which the screen is redrawn (times/second)</_long>
+ <default>50</default>
+ <min>1</min>
+ <max>200</max>
+ </option>
+ <option name="unredirect_fullscreen_windows" type="bool">
+ <_short>Unredirect Fullscreen Windows</_short>
+ <_long>Allow drawing of fullscreen windows to not be redirected to offscreen pixmaps</_long>
+ <default>false</default>
+ </option>
+ <option name="force_independent_output_painting" type="bool">
+ <_short>Force independent output painting.</_short>
+ <_long>Paint each output device independly, even if the output devices overlap</_long>
+ <default>false</default>
+ </option>
+ </options>
+ </plugin>
+</compiz>
diff --git a/plugins/composite/include/composite/composite.h b/plugins/composite/include/composite/composite.h
new file mode 100644
index 0000000..8593b53
--- /dev/null
+++ b/plugins/composite/include/composite/composite.h
@@ -0,0 +1,408 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#ifndef _COMPIZ_COMPOSITE_H
+#define _COMPIZ_COMPOSITE_H
+
+#include <X11/extensions/Xcomposite.h>
+
+#define COMPIZ_COMPOSITE_ABI 1
+
+#include <core/pluginclasshandler.h>
+#include <core/timer.h>
+#include <core/core.h>
+
+#define COMPOSITE_SCREEN_DAMAGE_PENDING_MASK (1 << 0)
+#define COMPOSITE_SCREEN_DAMAGE_REGION_MASK (1 << 1)
+#define COMPOSITE_SCREEN_DAMAGE_ALL_MASK (1 << 2)
+
+#define OPAQUE 0xffff
+#define COLOR 0xffff
+#define BRIGHT 0xffff
+
+/**
+ * Used to indicate only part of the screen is being redrawn
+ */
+#define PAINT_SCREEN_REGION_MASK (1 << 0)
+/**
+ * Used to indicate that the whole screen is being redrawn
+ */
+#define PAINT_SCREEN_FULL_MASK (1 << 1)
+/**
+ * Used to indicate that every window on this screen will be
+ * transformed, so non-painted areas should be
+ * double-buffered
+ */
+#define PAINT_SCREEN_TRANSFORMED_MASK (1 << 2)
+/**
+ * Used to indicate that some windows on this screen will
+ * be drawn transformed
+ */
+#define PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK (1 << 3)
+/**
+ * Used to indicate that nothing is being drawn on this pass
+ */
+#define PAINT_SCREEN_CLEAR_MASK (1 << 4)
+/**
+ * Used to indicate that occlusion detection is not in use
+ * on this pass
+ */
+#define PAINT_SCREEN_NO_OCCLUSION_DETECTION_MASK (1 << 5)
+/**
+ * Used to indicate that no background will be drawn on this
+ * pass
+ */
+#define PAINT_SCREEN_NO_BACKGROUND_MASK (1 << 6)
+
+
+typedef enum
+{
+ CompositeFPSLimiterModeDisabled = 0,
+ CompositeFPSLimiterModeDefault,
+ CompositeFPSLimiterModeVSyncLike
+} CompositeFPSLimiterMode;
+
+class PrivateCompositeScreen;
+class PrivateCompositeWindow;
+class CompositeScreen;
+class CompositeWindow;
+
+/**
+ * Wrapable function interface for CompositeScreen
+ */
+class CompositeScreenInterface :
+ public WrapableInterface<CompositeScreen, CompositeScreenInterface>
+{
+ public:
+
+ /**
+ * Hook which activates just before the screen is painted,
+ * plugins should use this to calculate animation parameters
+ *
+ * @param msSinceLastPaint Describes how many milliseconds have passed
+ * since the last screen repaint
+ */
+ virtual void preparePaint (int);
+
+ /**
+ * Hook which activates right after the screen is painted,
+ * plugins should use this to run post-paint cleanup, damage handling
+ * and setting next paint variables
+ *
+ */
+ virtual void donePaint ();
+
+ /**
+ * Hookable function which dispatches painting of outputs
+ * to rendering plugins such as OpenGL. Hook this function
+ * to change which outputs are painted, or to paint them
+ * manually if you are rendering
+ */
+ virtual void paint (CompOutput::ptrList &outputs, unsigned int);
+
+ /**
+ * Hookable function which gets a list of windows that need to be
+ * evaluated for repainting
+ */
+ virtual const CompWindowList & getWindowPaintList ();
+};
+
+
+class CompositeScreen :
+ public WrapableHandler<CompositeScreenInterface, 4>,
+ public PluginClassHandler<CompositeScreen, CompScreen, COMPIZ_COMPOSITE_ABI>,
+ public CompOption::Class
+{
+ public:
+
+ class PaintHandler {
+ public:
+ virtual ~PaintHandler () {};
+
+ virtual void paintOutputs (CompOutput::ptrList &outputs,
+ unsigned int mask,
+ const CompRegion &region) = 0;
+
+ virtual bool hasVSync () { return false; };
+
+ virtual void prepareDrawing () {};
+ };
+
+ public:
+ CompositeScreen (CompScreen *s);
+ ~CompositeScreen ();
+
+ CompOption::Vector & getOptions ();
+ bool setOption (const CompString &name, CompOption::Value &value);
+
+ /**
+ * Register a dispatch PaintHandler for a rendering plugin
+ */
+ bool registerPaintHandler (PaintHandler *pHnd);
+ void unregisterPaintHandler ();
+
+ bool compositingActive ();
+
+ /**
+ * Returns the value of an XDamage Extension event signature
+ */
+ int damageEvent ();
+
+ /**
+ * Causes the entire screen to be redrawn on the next
+ * event loop
+ */
+ void damageScreen ();
+
+ /**
+ * Adds a specific region to be redrawn on the next
+ * event loop
+ */
+ void damageRegion (const CompRegion &);
+ void damagePending ();
+
+
+ unsigned int damageMask ();
+ const CompRegion & currentDamage () const;
+
+ void showOutputWindow ();
+ void hideOutputWindow ();
+ void updateOutputWindow ();
+
+ Window overlay ();
+ Window output ();
+
+ int & overlayWindowCount ();
+
+ void setWindowPaintOffset (int x, int y);
+ CompPoint windowPaintOffset ();
+
+ /**
+ * Limits the number of redraws per second
+ */
+ void setFPSLimiterMode (CompositeFPSLimiterMode newMode);
+ CompositeFPSLimiterMode FPSLimiterMode ();
+
+ int redrawTime ();
+ int optimalRedrawTime ();
+
+ bool handlePaintTimeout ();
+
+ WRAPABLE_HND (0, CompositeScreenInterface, void, preparePaint, int);
+ WRAPABLE_HND (1, CompositeScreenInterface, void, donePaint);
+ WRAPABLE_HND (2, CompositeScreenInterface, void, paint,
+ CompOutput::ptrList &outputs, unsigned int);
+
+ WRAPABLE_HND (3, CompositeScreenInterface, const CompWindowList &,
+ getWindowPaintList);
+
+ friend class PrivateCompositeDisplay;
+
+ private:
+ PrivateCompositeScreen *priv;
+
+ public:
+ static bool toggleSlowAnimations (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options);
+};
+
+/*
+ window paint flags
+
+ bit 1-16 are used for read-only flags and they provide
+ information that describe the screen rendering pass
+ currently in process.
+
+ bit 17-32 are writable flags and they provide information
+ that is used to optimize rendering.
+*/
+
+/**
+ * this flag is present when window is being painted
+ * on a transformed screen.
+ */
+#define PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK (1 << 0)
+
+/**
+ * this flag is present when window is being tested
+ * for occlusion of other windows.
+ */
+#define PAINT_WINDOW_OCCLUSION_DETECTION_MASK (1 << 1)
+
+/**
+ * this flag indicates that the window ist painted with
+ * an offset
+ */
+#define PAINT_WINDOW_WITH_OFFSET_MASK (1 << 2)
+
+/**
+ * flag indicate that window is translucent.
+ */
+#define PAINT_WINDOW_TRANSLUCENT_MASK (1 << 16)
+
+/**
+ * flag indicate that window is transformed.
+ */
+#define PAINT_WINDOW_TRANSFORMED_MASK (1 << 17)
+
+/**
+ * flag indicate that core PaintWindow function should
+ * not draw this window.
+ */
+#define PAINT_WINDOW_NO_CORE_INSTANCE_MASK (1 << 18)
+
+/**
+ * flag indicate that blending is required.
+ */
+#define PAINT_WINDOW_BLEND_MASK (1 << 19)
+
+class CompositeWindowInterface :
+ public WrapableInterface<CompositeWindow, CompositeWindowInterface>
+{
+ public:
+
+ /**
+ * Hookable function to determine which parts of the
+ * screen for this window to redraw on the next pass
+ *
+ * @param initial Indicates if this is the first time
+ * this window is being redrawn
+ * @param rect Reference to a rect which describes which
+ * parts of the screen need to be redrawn on next pass
+ */
+ virtual bool damageRect (bool initial, const CompRect &rect);
+};
+
+class CompositeWindow :
+ public WrapableHandler<CompositeWindowInterface, 1>,
+ public PluginClassHandler<CompositeWindow, CompWindow, COMPIZ_COMPOSITE_ABI>
+{
+ public:
+
+ CompositeWindow (CompWindow *w);
+ ~CompositeWindow ();
+
+ /**
+ * Binds the window contents of this window to some offscreen pixmap
+ */
+ bool bind ();
+
+ /**
+ * Releases the pixmap data for this window with XFreePixmap.
+ */
+ void release ();
+
+ /**
+ * Returns the window pixmap
+ */
+ Pixmap pixmap ();
+
+ /**
+ * Forces this window to be composited so that the X Server
+ * stops drawing it and all output is redirected to an
+ * offscreen pixmap
+ */
+ void redirect ();
+
+ /**
+ * Stops this window from being composited, so that the X Server
+ * draws the window on-screen normally and output is not redirected
+ * to an offscreen pixmap
+ */
+
+ void unredirect ();
+
+ /**
+ * Returns true if a window is redirected
+ */
+ bool redirected ();
+ bool overlayWindow ();
+
+ void damageTransformedRect (float xScale,
+ float yScale,
+ float xTranslate,
+ float yTranslate,
+ const CompRect &rect);
+
+ void damageOutputExtents ();
+
+ /**
+ * Causes an area of the window to be redrawn on the
+ * next event loop
+ */
+ void addDamageRect (const CompRect &);
+
+ /**
+ * Causes the window to be redrawn on the next
+ * event loop
+ */
+ void addDamage (bool force = false);
+
+ /**
+ * Returns true if this window will be redrawn or
+ * partially redrawn on the next event loop
+ */
+ bool damaged ();
+
+ /**
+ * Sets screen redraw hints for "damaged" areas
+ * as stated by XDamageNotifyEvent
+ *
+ * @param de An XDamageNotifyEvent to be used to
+ * calculate areas to redraw on the next event loop
+ */
+ void processDamage (XDamageNotifyEvent *de);
+
+ void updateOpacity ();
+ void updateBrightness ();
+ void updateSaturation ();
+
+ /**
+ * Returns the window opacity
+ */
+ unsigned short opacity ();
+ /**
+ * Returns the window brightness
+ */
+ unsigned short brightness ();
+ /**
+ * Returns the window saturation
+ */
+ unsigned short saturation ();
+
+ WRAPABLE_HND (0, CompositeWindowInterface, bool, damageRect,
+ bool, const CompRect &);
+
+ friend class PrivateCompositeWindow;
+ friend class CompositeScreen;
+
+ private:
+ PrivateCompositeWindow *priv;
+};
+
+#endif
diff --git a/plugins/composite/src/composite.cpp b/plugins/composite/src/composite.cpp
new file mode 100644
index 0000000..eccfb22
--- /dev/null
+++ b/plugins/composite/src/composite.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#include <core/core.h>
+#include <composite/composite.h>
+
+#include "privates.h"
+
+class CompositePluginVTable :
+ public CompPlugin::VTableForScreenAndWindow<CompositeScreen, CompositeWindow>
+{
+ public:
+
+ bool init ();
+ void fini ();
+};
+
+COMPIZ_PLUGIN_20090315 (composite, CompositePluginVTable)
+
+CompOption::Vector &
+CompositeScreen::getOptions ()
+{
+ return priv->getOptions ();
+}
+
+bool
+CompositeScreen::setOption (const CompString &name,
+ CompOption::Value &value)
+{
+ return priv->setOption (name, value);
+}
+
+bool
+PrivateCompositeScreen::setOption (const CompString &name,
+ CompOption::Value &value)
+{
+ unsigned int index;
+
+ bool rv = CompositeOptions::setOption (name, value);
+
+ if (!rv || !CompOption::findOption (getOptions (), name, &index))
+ return false;
+
+ switch (index) {
+ case CompositeOptions::DetectRefreshRate:
+ if (optionGetDetectRefreshRate ())
+ detectRefreshRate ();
+ break;
+ case CompositeOptions::RefreshRate:
+ if (optionGetDetectRefreshRate ())
+ return false;
+ redrawTime = 1000 / optionGetRefreshRate ();
+ optimalRedrawTime = redrawTime;
+ break;
+ default:
+ break;
+ }
+
+ return rv;
+}
+
+bool
+CompositePluginVTable::init ()
+{
+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
+ return false;
+
+ CompPrivate p;
+ p.uval = COMPIZ_COMPOSITE_ABI;
+ screen->storeValue ("composite_ABI", p);
+
+ return true;
+}
+
+void
+CompositePluginVTable::fini ()
+{
+ screen->eraseValue ("composite_ABI");
+}
diff --git a/plugins/composite/src/privates.h b/plugins/composite/src/privates.h
new file mode 100644
index 0000000..72514e1
--- /dev/null
+++ b/plugins/composite/src/privates.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#ifndef _COMPOSITE_PRIVATES_H
+#define _COMPOSITE_PRIVATES_H
+
+#include <composite/composite.h>
+#include <core/atoms.h>
+
+#include "composite_options.h"
+
+#if COMPOSITE_MAJOR > 0 || COMPOSITE_MINOR > 2
+#define USE_COW
+extern bool useCow;
+#endif
+
+extern CompPlugin::VTable *compositeVTable;
+
+extern CompWindow *lastDamagedWindow;
+
+class PrivateCompositeScreen :
+ ScreenInterface,
+ public CompositeOptions
+{
+ public:
+ PrivateCompositeScreen (CompositeScreen *cs);
+ ~PrivateCompositeScreen ();
+
+ bool setOption (const CompString &name, CompOption::Value &value);
+
+ void outputChangeNotify ();
+
+ void handleEvent (XEvent *event);
+
+ void makeOutputWindow ();
+
+ bool init ();
+
+ void handleExposeEvent (XExposeEvent *event);
+
+ void detectRefreshRate ();
+
+ int getTimeToNextRedraw (struct timeval *tv);
+
+ public:
+
+ CompositeScreen *cScreen;
+
+ int compositeEvent, compositeError, compositeOpcode;
+ int damageEvent, damageError;
+ int fixesEvent, fixesError, fixesVersion;
+
+ bool shapeExtension;
+ int shapeEvent, shapeError;
+
+ bool randrExtension;
+ int randrEvent, randrError;
+
+ CompRegion damage;
+ unsigned long damageMask;
+
+ CompRegion tmpRegion;
+
+ Window overlay;
+ Window output;
+
+ std::list <CompRect> exposeRects;
+
+ CompPoint windowPaintOffset;
+
+ int overlayWindowCount;
+
+ struct timeval lastRedraw;
+ int nextRedraw;
+ int redrawTime;
+ int optimalRedrawTime;
+ int frameStatus;
+ int timeMult;
+ bool idle;
+ int timeLeft;
+
+ bool slowAnimations;
+
+ CompTimer paintTimer;
+
+ bool active;
+ CompositeScreen::PaintHandler *pHnd;
+
+ CompositeFPSLimiterMode FPSLimiterMode;
+ int frameTimeAccumulator;
+};
+
+class PrivateCompositeWindow : WindowInterface
+{
+ public:
+ PrivateCompositeWindow (CompWindow *w, CompositeWindow *cw);
+ ~PrivateCompositeWindow ();
+
+ void windowNotify (CompWindowNotify n);
+ void resizeNotify (int dx, int dy, int dwidth, int dheight);
+ void moveNotify (int dx, int dy, bool now);
+
+ static void handleDamageRect (CompositeWindow *w,
+ int x,
+ int y,
+ int width,
+ int height);
+
+ public:
+ CompWindow *window;
+ CompositeWindow *cWindow;
+ CompositeScreen *cScreen;
+
+ Pixmap pixmap;
+
+ Damage damage;
+
+ bool damaged;
+ bool redirected;
+ bool overlayWindow;
+ bool bindFailed;
+
+ unsigned short opacity;
+ unsigned short brightness;
+ unsigned short saturation;
+
+ XRectangle *damageRects;
+ int sizeDamage;
+ int nDamage;
+};
+
+#endif
diff --git a/plugins/composite/src/screen.cpp b/plugins/composite/src/screen.cpp
new file mode 100644
index 0000000..ed2bf1e
--- /dev/null
+++ b/plugins/composite/src/screen.cpp
@@ -0,0 +1,998 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/time.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xproto.h>
+#include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/extensions/shape.h>
+
+#include "privates.h"
+
+#include <X11/extensions/shape.h>
+#include <X11/extensions/Xrandr.h>
+
+CompWindow *lastDamagedWindow = 0;
+
+
+void
+PrivateCompositeScreen::handleEvent (XEvent *event)
+{
+ CompWindow *w;
+
+ switch (event->type) {
+
+ case CreateNotify:
+ if (screen->root () == event->xcreatewindow.parent)
+ {
+ /* The first time some client asks for the composite
+ * overlay window, the X server creates it, which causes
+ * an errorneous CreateNotify event. We catch it and
+ * ignore it. */
+ if (overlay == event->xcreatewindow.window)
+ return;
+ }
+ break;
+ case PropertyNotify:
+ if (event->xproperty.atom == Atoms::winOpacity)
+ {
+ w = screen->findWindow (event->xproperty.window);
+ if (w)
+ CompositeWindow::get (w)->updateOpacity ();
+ }
+ else if (event->xproperty.atom == Atoms::winBrightness)
+ {
+ w = screen->findWindow (event->xproperty.window);
+ if (w)
+ CompositeWindow::get (w)->updateBrightness ();
+ }
+ else if (event->xproperty.atom == Atoms::winSaturation)
+ {
+ w = screen->findWindow (event->xproperty.window);
+ if (w)
+ CompositeWindow::get (w)->updateSaturation ();
+ }
+ break;
+ default:
+ if (shapeExtension &&
+ event->type == shapeEvent + ShapeNotify)
+ {
+ w = screen->findWindow (((XShapeEvent *) event)->window);
+ if (w)
+ {
+ if (w->mapNum ())
+ {
+ CompositeWindow::get (w)->addDamage ();
+ }
+ }
+ }
+ break;
+ }
+
+ screen->handleEvent (event);
+
+ switch (event->type) {
+ case Expose:
+ handleExposeEvent (&event->xexpose);
+ break;
+ case ClientMessage:
+ if (event->xclient.message_type == Atoms::winOpacity)
+ {
+ w = screen->findWindow (event->xclient.window);
+ if (w && (w->type () & CompWindowTypeDesktopMask) == 0)
+ {
+ unsigned short opacity = event->xclient.data.l[0] >> 16;
+
+ screen->setWindowProp32 (w->id (),
+ Atoms::winOpacity, opacity);
+ }
+ }
+ else if (event->xclient.message_type ==
+ Atoms::winBrightness)
+ {
+ w = screen->findWindow (event->xclient.window);
+ if (w)
+ {
+ unsigned short brightness = event->xclient.data.l[0] >> 16;
+
+ screen->setWindowProp32 (w->id (),
+ Atoms::winBrightness, brightness);
+ }
+ }
+ else if (event->xclient.message_type ==
+ Atoms::winSaturation)
+ {
+ w = screen->findWindow (event->xclient.window);
+ if (w)
+ {
+ unsigned short saturation = event->xclient.data.l[0] >> 16;
+
+ screen->setWindowProp32 (w->id (),
+ Atoms::winSaturation, saturation);
+ }
+ }
+ break;
+ default:
+ if (event->type == damageEvent + XDamageNotify)
+ {
+ XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
+
+ if (lastDamagedWindow && de->drawable == lastDamagedWindow->id ())
+ {
+ w = lastDamagedWindow;
+ }
+ else
+ {
+ w = screen->findWindow (de->drawable);
+ if (w)
+ lastDamagedWindow = w;
+ }
+
+ if (w)
+ CompositeWindow::get (w)->processDamage (de);
+ }
+ else if (shapeExtension &&
+ event->type == shapeEvent + ShapeNotify)
+ {
+ w = screen->findWindow (((XShapeEvent *) event)->window);
+ if (w)
+ {
+ if (w->mapNum ())
+ {
+ CompositeWindow::get (w)->addDamage ();
+ }
+ }
+ }
+ else if (randrExtension &&
+ event->type == randrEvent + RRScreenChangeNotify)
+ {
+ XRRScreenChangeNotifyEvent *rre;
+
+ rre = (XRRScreenChangeNotifyEvent *) event;
+
+ if (screen->root () == rre->root)
+ detectRefreshRate ();
+ }
+ break;
+ }
+}
+
+int
+CompositeScreen::damageEvent ()
+{
+ return priv->damageEvent;
+}
+
+
+CompositeScreen::CompositeScreen (CompScreen *s) :
+ PluginClassHandler<CompositeScreen, CompScreen, COMPIZ_COMPOSITE_ABI> (s),
+ priv (new PrivateCompositeScreen (this))
+{
+ int compositeMajor, compositeMinor;
+
+ if (!XQueryExtension (s->dpy (), COMPOSITE_NAME,
+ &priv->compositeOpcode,
+ &priv->compositeEvent,
+ &priv->compositeError))
+ {
+ compLogMessage ("core", CompLogLevelFatal,
+ "No composite extension");
+ setFailed ();
+ return;
+ }
+
+ XCompositeQueryVersion (s->dpy (), &compositeMajor, &compositeMinor);
+ if (compositeMajor == 0 && compositeMinor < 2)
+ {
+ compLogMessage ("core", CompLogLevelFatal,
+ "Old composite extension");
+ setFailed ();
+ return;
+ }
+
+ if (!XDamageQueryExtension (s->dpy (), &priv->damageEvent,
+ &priv->damageError))
+ {
+ compLogMessage ("core", CompLogLevelFatal,
+ "No damage extension");
+ setFailed ();
+ return;
+ }
+
+ if (!XFixesQueryExtension (s->dpy (), &priv->fixesEvent, &priv->fixesError))
+ {
+ compLogMessage ("core", CompLogLevelFatal,
+ "No fixes extension");
+ setFailed ();
+ return;
+ }
+
+ priv->shapeExtension = XShapeQueryExtension (s->dpy (), &priv->shapeEvent,
+ &priv->shapeError);
+ priv->randrExtension = XRRQueryExtension (s->dpy (), &priv->randrEvent,
+ &priv->randrError);
+
+ priv->makeOutputWindow ();
+
+ priv->detectRefreshRate ();
+
+ priv->slowAnimations = false;
+
+ if (!priv->init ())
+ {
+ setFailed ();
+ }
+
+}
+
+CompositeScreen::~CompositeScreen ()
+{
+ priv->paintTimer.stop ();
+
+#ifdef USE_COW
+ if (useCow)
+ XCompositeReleaseOverlayWindow (screen->dpy (),
+ screen->root ());
+#endif
+
+ delete priv;
+}
+
+
+PrivateCompositeScreen::PrivateCompositeScreen (CompositeScreen *cs) :
+ cScreen (cs),
+ damageMask (COMPOSITE_SCREEN_DAMAGE_ALL_MASK),
+ overlay (None),
+ output (None),
+ exposeRects (),
+ windowPaintOffset (0, 0),
+ overlayWindowCount (0),
+ nextRedraw (0),
+ redrawTime (1000 / 50),
+ optimalRedrawTime (1000 / 50),
+ frameStatus (0),
+ timeMult (1),
+ idle (true),
+ timeLeft (0),
+ slowAnimations (false),
+ active (false),
+ pHnd (NULL),
+ FPSLimiterMode (CompositeFPSLimiterModeDefault),
+ frameTimeAccumulator (0)
+{
+ gettimeofday (&lastRedraw, 0);
+ // wrap outputChangeNotify
+ ScreenInterface::setHandler (screen);
+
+ optionSetSlowAnimationsKeyInitiate (CompositeScreen::toggleSlowAnimations);
+}
+
+PrivateCompositeScreen::~PrivateCompositeScreen ()
+{
+}
+
+bool
+PrivateCompositeScreen::init ()
+{
+ Display *dpy = screen->dpy ();
+ Window newCmSnOwner = None;
+ Atom cmSnAtom = 0;
+ Time cmSnTimestamp = 0;
+ XEvent event;
+ XSetWindowAttributes attr;
+ Window currentCmSnOwner;
+ char buf[128];
+
+ sprintf (buf, "_NET_WM_CM_S%d", screen->screenNum ());
+ cmSnAtom = XInternAtom (dpy, buf, 0);
+
+ currentCmSnOwner = XGetSelectionOwner (dpy, cmSnAtom);
+
+ if (currentCmSnOwner != None)
+ {
+ if (!replaceCurrentWm)
+ {
+ compLogMessage ("composite", CompLogLevelError,
+ "Screen %d on display \"%s\" already "
+ "has a compositing manager; try using the "
+ "--replace option to replace the current "
+ "compositing manager.",
+ screen->screenNum (), DisplayString (dpy));
+
+ return false;
+ }
+ }
+
+ attr.override_redirect = true;
+ attr.event_mask = PropertyChangeMask;
+
+ newCmSnOwner =
+ XCreateWindow (dpy, screen->root (),
+ -100, -100, 1, 1, 0,
+ CopyFromParent, CopyFromParent,
+ CopyFromParent,
+ CWOverrideRedirect | CWEventMask,
+ &attr);
+
+ XChangeProperty (dpy, newCmSnOwner, Atoms::wmName, Atoms::utf8String, 8,
+ PropModeReplace, (unsigned char *) PACKAGE,
+ strlen (PACKAGE));
+
+ XWindowEvent (dpy, newCmSnOwner, PropertyChangeMask, &event);
+
+ cmSnTimestamp = event.xproperty.time;
+
+ XSetSelectionOwner (dpy, cmSnAtom, newCmSnOwner, cmSnTimestamp);
+
+ if (XGetSelectionOwner (dpy, cmSnAtom) != newCmSnOwner)
+ {
+ compLogMessage ("core", CompLogLevelError,
+ "Could not acquire compositing manager "
+ "selection on screen %d display \"%s\"",
+ screen->screenNum (), DisplayString (dpy));
+
+ return false;
+ }
+
+ /* Send client message indicating that we are now the compositing manager */
+ event.xclient.type = ClientMessage;
+ event.xclient.window = screen->root ();
+ event.xclient.message_type = Atoms::manager;
+ event.xclient.format = 32;
+ event.xclient.data.l[0] = cmSnTimestamp;
+ event.xclient.data.l[1] = cmSnAtom;
+ event.xclient.data.l[2] = 0;
+ event.xclient.data.l[3] = 0;
+ event.xclient.data.l[4] = 0;
+
+ XSendEvent (dpy, screen->root (), FALSE, StructureNotifyMask, &event);
+
+ return true;
+}
+
+
+bool
+CompositeScreen::registerPaintHandler (PaintHandler *pHnd)
+{
+ Display *dpy = screen->dpy ();
+
+ if (priv->active)
+ return false;
+
+ CompScreen::checkForError (dpy);
+
+ XCompositeRedirectSubwindows (dpy, screen->root (),
+ CompositeRedirectManual);
+
+ priv->overlayWindowCount = 0;
+
+ if (CompScreen::checkForError (dpy))
+ {
+ compLogMessage ("composite", CompLogLevelError,
+ "Another composite manager is already "
+ "running on screen: %d", screen->screenNum ());
+
+ return false;
+ }
+
+ foreach (CompWindow *w, screen->windows ())
+ {
+ CompositeWindow *cw = CompositeWindow::get (w);
+ cw->priv->overlayWindow = false;
+ cw->priv->redirected = true;
+ }
+
+ priv->pHnd = pHnd;
+ priv->active = true;
+
+ showOutputWindow ();
+
+ priv->paintTimer.start
+ (boost::bind (&CompositeScreen::handlePaintTimeout, this),
+ priv->optimalRedrawTime, MAXSHORT);
+
+ return true;
+}
+
+void
+CompositeScreen::unregisterPaintHandler ()
+{
+ Display *dpy = screen->dpy ();
+
+ foreach (CompWindow *w, screen->windows ())
+ {
+ CompositeWindow *cw = CompositeWindow::get (w);
+ cw->priv->overlayWindow = false;
+ cw->priv->redirected = false;
+ cw->release ();
+ }
+
+ priv->overlayWindowCount = 0;
+
+ XCompositeUnredirectSubwindows (dpy, screen->root (),
+ CompositeRedirectManual);
+
+ priv->pHnd = NULL;
+ priv->active = false;
+ priv->paintTimer.stop ();
+
+ hideOutputWindow ();
+}
+
+bool
+CompositeScreen::compositingActive ()
+{
+ return priv->active;
+}
+
+void
+CompositeScreen::damageScreen ()
+{
+ if (priv->damageMask == 0)
+ priv->paintTimer.setTimes (priv->paintTimer.minLeft ());
+
+ priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_ALL_MASK;
+ priv->damageMask &= ~COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
+}
+
+void
+CompositeScreen::damageRegion (const CompRegion &region)
+{
+ if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
+ return;
+
+ if (priv->damageMask == 0)
+ priv->paintTimer.setTimes (priv->paintTimer.minLeft ());
+
+ priv->damage += region;
+
+ priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
+
+ /* if the number of damage rectangles grows two much between repaints,
+ we have a lot of overhead just for doing the damage tracking -
+ in order to make sure we're not having too much overhead, damage
+ the whole screen if we have a lot of damage rects */
+
+ if (priv->damage.numRects () > 100)
+ damageScreen ();
+}
+
+void
+CompositeScreen::damagePending ()
+{
+ if (priv->damageMask == 0)
+ priv->paintTimer.setTimes (priv->paintTimer.minLeft ());
+
+ priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_PENDING_MASK;
+}
+
+unsigned int
+CompositeScreen::damageMask ()
+{
+ return priv->damageMask;
+}
+
+void
+CompositeScreen::showOutputWindow ()
+{
+#ifdef USE_COW
+ if (useCow && priv->active)
+ {
+ Display *dpy = screen->dpy ();
+ XserverRegion region;
+
+ region = XFixesCreateRegion (dpy, NULL, 0);
+
+ XFixesSetWindowShapeRegion (dpy,
+ priv->output,
+ ShapeBounding,
+ 0, 0, 0);
+ XFixesSetWindowShapeRegion (dpy,
+ priv->output,
+ ShapeInput,
+ 0, 0, region);
+
+ XFixesDestroyRegion (dpy, region);
+
+ damageScreen ();
+ }
+#endif
+
+}
+
+void
+CompositeScreen::hideOutputWindow ()
+{
+#ifdef USE_COW
+ if (useCow)
+ {
+ Display *dpy = screen->dpy ();
+ XserverRegion region;
+
+ region = XFixesCreateRegion (dpy, NULL, 0);
+
+ XFixesSetWindowShapeRegion (dpy,
+ priv->output,
+ ShapeBounding,
+ 0, 0, region);
+
+ XFixesDestroyRegion (dpy, region);
+ }
+#endif
+
+}
+
+void
+CompositeScreen::updateOutputWindow ()
+{
+#ifdef USE_COW
+ if (useCow && priv->active)
+ {
+ Display *dpy = screen->dpy ();
+ XserverRegion region;
+ CompRegion tmpRegion (screen->region ());
+
+ for (CompWindowList::reverse_iterator rit =
+ screen->windows ().rbegin ();
+ rit != screen->windows ().rend (); rit++)
+ if (CompositeWindow::get (*rit)->overlayWindow ())
+ {
+ tmpRegion -= (*rit)->region ();
+ }
+
+ XShapeCombineRegion (dpy, priv->output, ShapeBounding,
+ 0, 0, tmpRegion.handle (), ShapeSet);
+
+
+ region = XFixesCreateRegion (dpy, NULL, 0);
+
+ XFixesSetWindowShapeRegion (dpy,
+ priv->output,
+ ShapeInput,
+ 0, 0, region);
+
+ XFixesDestroyRegion (dpy, region);
+ }
+#endif
+
+}
+
+void
+PrivateCompositeScreen::makeOutputWindow ()
+{
+#ifdef USE_COW
+ if (useCow)
+ {
+ overlay = XCompositeGetOverlayWindow (screen->dpy (), screen->root ());
+ output = overlay;
+
+ XSelectInput (screen->dpy (), output, ExposureMask);
+ }
+ else
+#endif
+ output = overlay = screen->root ();
+
+ cScreen->hideOutputWindow ();
+}
+
+Window
+CompositeScreen::output ()
+{
+ return priv->output;
+}
+
+Window
+CompositeScreen::overlay ()
+{
+ return priv->overlay;
+}
+
+int &
+CompositeScreen::overlayWindowCount ()
+{
+ return priv->overlayWindowCount;
+}
+
+void
+CompositeScreen::setWindowPaintOffset (int x, int y)
+{
+ priv->windowPaintOffset = CompPoint (x, y);
+}
+
+CompPoint
+CompositeScreen::windowPaintOffset ()
+{
+ return priv->windowPaintOffset;
+}
+
+void
+PrivateCompositeScreen::detectRefreshRate ()
+{
+ if (!noDetection &&
+ optionGetDetectRefreshRate ())
+ {
+ CompString name;
+ CompOption::Value value;
+
+ value.set ((int) 0);
+
+ if (screen->XRandr ())
+ {
+ XRRScreenConfiguration *config;
+
+ config = XRRGetScreenInfo (screen->dpy (),
+ screen->root ());
+ value.set ((int) XRRConfigCurrentRate (config));
+
+ XRRFreeScreenConfigInfo (config);
+ }
+
+ if (value.i () == 0)
+ value.set ((int) 50);
+
+ mOptions[CompositeOptions::DetectRefreshRate].value ().set (false);
+ screen->setOptionForPlugin ("composite", "refresh_rate", value);
+ mOptions[CompositeOptions::DetectRefreshRate].value ().set (true);
+ }
+ else
+ {
+ redrawTime = 1000 / optionGetRefreshRate ();
+ optimalRedrawTime = redrawTime;
+ }
+}
+
+CompositeFPSLimiterMode
+CompositeScreen::FPSLimiterMode ()
+{
+ return priv->FPSLimiterMode;
+}
+
+void
+CompositeScreen::setFPSLimiterMode (CompositeFPSLimiterMode newMode)
+{
+ priv->FPSLimiterMode = newMode;
+}
+
+int
+PrivateCompositeScreen::getTimeToNextRedraw (struct timeval *tv)
+{
+ int diff, next;
+
+ diff = TIMEVALDIFF (tv, &lastRedraw);
+
+ /* handle clock rollback */
+ if (diff < 0)
+ diff = 0;
+
+ bool hasVSyncBehavior =
+ (FPSLimiterMode == CompositeFPSLimiterModeVSyncLike ||
+ (pHnd && pHnd->hasVSync ()));
+
+ if (idle || hasVSyncBehavior)
+ {
+ if (timeMult > 1)
+ {
+ frameStatus = -1;
+ redrawTime = optimalRedrawTime;
+ timeMult--;
+ }
+ }
+ else
+ {
+ if (diff > redrawTime)
+ {
+ if (frameStatus > 0)
+ frameStatus = 0;
+
+ next = optimalRedrawTime * (timeMult + 1);
+ if (diff > next)
+ {
+ frameStatus--;
+ if (frameStatus < -1)
+ {
+ timeMult++;
+ redrawTime = diff = next;
+ }
+ }
+ }
+ else if (diff < redrawTime)
+ {
+ if (frameStatus < 0)
+ frameStatus = 0;
+
+ if (timeMult > 1)
+ {
+ next = optimalRedrawTime * (timeMult - 1);
+ if (diff < next)
+ {
+ frameStatus++;
+ if (frameStatus > 4)
+ {
+ timeMult--;
+ redrawTime = next;
+ }
+ }
+ }
+ }
+ }
+ if (diff >= redrawTime)
+ return 1;
+
+ if (hasVSyncBehavior)
+ return (redrawTime - diff) * 0.7;
+
+ return redrawTime - diff;
+}
+
+int
+CompositeScreen::redrawTime ()
+{
+ return priv->redrawTime;
+}
+
+int
+CompositeScreen::optimalRedrawTime ()
+{
+ return priv->optimalRedrawTime;
+}
+
+bool
+CompositeScreen::handlePaintTimeout ()
+{
+ int timeDiff;
+ struct timeval tv;
+ int timeToNextRedraw;
+
+ gettimeofday (&tv, 0);
+
+ if (priv->damageMask)
+ {
+ if (priv->pHnd)
+ priv->pHnd->prepareDrawing ();
+
+ timeDiff = TIMEVALDIFF (&tv, &priv->lastRedraw);
+
+ /* handle clock rollback */
+ if (timeDiff < 0)
+ timeDiff = 0;
+
+ if (priv->slowAnimations)
+ {
+ int msSinceLastPaint;
+
+ if (priv->FPSLimiterMode == CompositeFPSLimiterModeDisabled)
+ msSinceLastPaint = 1;
+ else
+ msSinceLastPaint =
+ priv->idle ? 2 : (timeDiff * 2) / priv->redrawTime;
+
+ preparePaint (msSinceLastPaint);
+ }
+ else
+ preparePaint (priv->idle ? priv->redrawTime : timeDiff);
+
+ /* substract top most overlay window region */
+ if (priv->overlayWindowCount)
+ {
+ for (CompWindowList::reverse_iterator rit =
+ screen->windows ().rbegin ();
+ rit != screen->windows ().rend (); rit++)
+ {
+ CompWindow *w = (*rit);
+
+ if (w->destroyed () || w->invisible ())
+ continue;
+
+ if (!CompositeWindow::get (w)->redirected ())
+ priv->damage -= w->region ();
+
+ break;
+ }
+
+ if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
+ {
+ priv->damageMask &= ~COMPOSITE_SCREEN_DAMAGE_ALL_MASK;
+ priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
+ }
+ }
+
+ priv->tmpRegion = priv->damage & screen->region ();
+
+ if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_REGION_MASK)
+ {
+ if (priv->tmpRegion == screen->region ())
+ damageScreen ();
+ }
+
+ priv->damage = CompRegion ();
+
+ int mask = priv->damageMask;
+ priv->damageMask = 0;
+
+ CompOutput::ptrList outputs (0);
+
+ if (priv->optionGetForceIndependentOutputPainting ()
+ || !screen->hasOverlappingOutputs ())
+ {
+ foreach (CompOutput &o, screen->outputDevs ())
+ outputs.push_back (&o);
+ }
+ else
+ outputs.push_back (&screen->fullscreenOutput ());
+
+ paint (outputs, mask);
+
+ priv->lastRedraw = tv;
+
+ donePaint ();
+
+ foreach (CompWindow *w, screen->windows ())
+ {
+ if (w->destroyed ())
+ {
+ CompositeWindow::get (w)->addDamage ();
+ break;
+ }
+ }
+
+ priv->idle = false;
+ }
+ else
+ {
+ priv->idle = true;
+ }
+
+ gettimeofday (&tv, 0);
+
+ if (priv->FPSLimiterMode == CompositeFPSLimiterModeDisabled)
+ {
+ if (priv->FPSLimiterMode == CompositeFPSLimiterModeDisabled)
+ {
+ const int msToReturn1After = 100;
+
+ priv->frameTimeAccumulator += priv->redrawTime;
+ if (priv->frameTimeAccumulator > msToReturn1After)
+ {
+ priv->frameTimeAccumulator %= msToReturn1After;
+ timeToNextRedraw = 1;
+ }
+ else
+ timeToNextRedraw = 0;
+ }
+ }
+ else
+ timeToNextRedraw = priv->getTimeToNextRedraw (&tv);
+
+ if (priv->idle)
+ priv->paintTimer.setTimes (timeToNextRedraw, MAXSHORT);
+ else
+ priv->paintTimer.setTimes (timeToNextRedraw);
+ return true;
+}
+
+void
+CompositeScreen::preparePaint (int msSinceLastPaint)
+ WRAPABLE_HND_FUNC (0, preparePaint, msSinceLastPaint)
+
+void
+CompositeScreen::donePaint ()
+ WRAPABLE_HND_FUNC (1, donePaint)
+
+void
+CompositeScreen::paint (CompOutput::ptrList &outputs,
+ unsigned int mask)
+{
+ WRAPABLE_HND_FUNC (2, paint, outputs, mask)
+
+ if (priv->pHnd)
+ priv->pHnd->paintOutputs (outputs, mask, priv->tmpRegion);
+}
+
+const CompWindowList &
+CompositeScreen::getWindowPaintList ()
+{
+ WRAPABLE_HND_FUNC_RETURN (3, const CompWindowList &, getWindowPaintList)
+
+ return screen->windows ();
+}
+
+void
+PrivateCompositeScreen::handleExposeEvent (XExposeEvent *event)
+{
+ if (output == event->window)
+ return;
+
+ exposeRects.push_back (CompRect (event->x,
+ event->y,
+ event->width,
+ event->height));
+
+ if (event->count == 0)
+ {
+ CompRect rect;
+ foreach (CompRect rect, exposeRects)
+ {
+ cScreen->damageRegion (CompRegion (rect));
+ }
+ exposeRects.clear ();
+ }
+}
+
+void
+PrivateCompositeScreen::outputChangeNotify ()
+{
+ screen->outputChangeNotify ();
+#ifdef USE_COW
+ if (useCow)
+ XMoveResizeWindow (screen->dpy (), overlay, 0, 0,
+ screen->width (), screen->height ());
+#endif
+ cScreen->damageScreen ();
+}
+
+bool
+CompositeScreen::toggleSlowAnimations (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompositeScreen *cs = CompositeScreen::get (screen);
+ if (cs)
+ cs->priv->slowAnimations = !cs->priv->slowAnimations;
+
+ return true;
+}
+
+
+void
+CompositeScreenInterface::preparePaint (int msSinceLastPaint)
+ WRAPABLE_DEF (preparePaint, msSinceLastPaint)
+
+void
+CompositeScreenInterface::donePaint ()
+ WRAPABLE_DEF (donePaint)
+
+void
+CompositeScreenInterface::paint (CompOutput::ptrList &outputs,
+ unsigned int mask)
+ WRAPABLE_DEF (paint, outputs, mask)
+
+const CompWindowList &
+CompositeScreenInterface::getWindowPaintList ()
+ WRAPABLE_DEF (getWindowPaintList)
+
+const CompRegion &
+CompositeScreen::currentDamage () const
+{
+ return priv->damage;
+}
diff --git a/plugins/composite/src/window.cpp b/plugins/composite/src/window.cpp
new file mode 100644
index 0000000..a49f7f8
--- /dev/null
+++ b/plugins/composite/src/window.cpp
@@ -0,0 +1,630 @@
+/*
+ * Copyright © 2008 Dennis Kasprzyk
+ * Copyright © 2007 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Dennis Kasprzyk not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Dennis Kasprzyk makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
+ * David Reveman <davidr@novell.com>
+ */
+
+#include "privates.h"
+
+CompositeWindow::CompositeWindow (CompWindow *w) :
+ PluginClassHandler<CompositeWindow, CompWindow, COMPIZ_COMPOSITE_ABI> (w),
+ priv (new PrivateCompositeWindow (w, this))
+{
+ CompScreen *s = screen;
+
+ if (w->windowClass () != InputOnly)
+ {
+ priv->damage = XDamageCreate (s->dpy (), w->id (),
+ XDamageReportRawRectangles);
+ }
+ else
+ {
+ priv->damage = None;
+ }
+
+ priv->opacity = OPAQUE;
+ if (!(w->type () & CompWindowTypeDesktopMask))
+ priv->opacity = s->getWindowProp32 (w->id (),
+ Atoms::winOpacity, OPAQUE);
+
+ priv->brightness = s->getWindowProp32 (w->id (),
+ Atoms::winBrightness, BRIGHT);
+
+ priv->saturation = s->getWindowProp32 (w->id (),
+ Atoms::winSaturation, COLOR);
+
+ if (w->isViewable ())
+ priv->damaged = true;
+}
+
+CompositeWindow::~CompositeWindow ()
+{
+
+ if (priv->damage)
+ XDamageDestroy (screen->dpy (), priv->damage);
+
+ if (!priv->redirected)
+ {
+ priv->cScreen->overlayWindowCount ()--;
+
+ if (priv->cScreen->overlayWindowCount () < 1)
+ priv->cScreen->showOutputWindow ();
+ }
+
+ release ();
+
+ addDamage ();
+
+ if (lastDamagedWindow == priv->window)
+ lastDamagedWindow = NULL;
+
+ delete priv;
+}
+
+PrivateCompositeWindow::PrivateCompositeWindow (CompWindow *w,
+ CompositeWindow *cw) :
+ window (w),
+ cWindow (cw),
+ cScreen (CompositeScreen::get (screen)),
+ pixmap (None),
+ damage (None),
+ damaged (false),
+ redirected (cScreen->compositingActive ()),
+ overlayWindow (false),
+ bindFailed (false),
+ opacity (OPAQUE),
+ brightness (BRIGHT),
+ saturation (COLOR),
+ damageRects (0),
+ sizeDamage (0),
+ nDamage (0)
+{
+ WindowInterface::setHandler (w);
+}
+
+PrivateCompositeWindow::~PrivateCompositeWindow ()
+{
+
+ if (sizeDamage)
+ free (damageRects);
+}
+
+bool
+CompositeWindow::bind ()
+{
+ if (!priv->cScreen->compositingActive ())
+ return false;
+
+ redirect ();
+ if (!priv->pixmap)
+ {
+ XWindowAttributes attr;
+
+ /* don't try to bind window again if it failed previously */
+ if (priv->bindFailed)
+ return false;
+
+ /* We have to grab the server here to make sure that window
+ is mapped when getting the window pixmap */
+ XGrabServer (screen->dpy ());
+ XGetWindowAttributes (screen->dpy (),
+ ROOTPARENT (priv->window), &attr);
+ if (attr.map_state != IsViewable)
+ {
+ XUngrabServer (screen->dpy ());
+ priv->bindFailed = true;
+ return false;
+ }
+
+ priv->pixmap = XCompositeNameWindowPixmap
+ (screen->dpy (), ROOTPARENT (priv->window));
+
+ XUngrabServer (screen->dpy ());
+ }
+ return true;
+}
+
+void
+CompositeWindow::release ()
+{
+ if (priv->pixmap)
+ {
+ XFreePixmap (screen->dpy (), priv->pixmap);
+ priv->pixmap = None;
+ }
+}
+
+Pixmap
+CompositeWindow::pixmap ()
+{
+ return priv->pixmap;
+}
+
+void
+CompositeWindow::redirect ()
+{
+ if (priv->redirected || !priv->cScreen->compositingActive ())
+ return;
+
+ XCompositeRedirectWindow (screen->dpy (),
+ ROOTPARENT (priv->window),
+ CompositeRedirectManual);
+
+ priv->redirected = true;
+
+ if (priv->overlayWindow)
+ {
+ priv->cScreen->overlayWindowCount ()--;
+ priv->overlayWindow = false;
+ }
+
+ if (priv->cScreen->overlayWindowCount () < 1)
+ priv->cScreen->showOutputWindow ();
+ else
+ priv->cScreen->updateOutputWindow ();
+}
+
+void
+CompositeWindow::unredirect ()
+{
+ if (!priv->redirected || !priv->cScreen->compositingActive ())
+ return;
+
+ release ();
+
+ XCompositeUnredirectWindow (screen->dpy (),
+ ROOTPARENT (priv->window),
+ CompositeRedirectManual);
+
+ priv->redirected = false;
+ priv->overlayWindow = true;
+ priv->cScreen->overlayWindowCount ()++;
+
+ if (priv->cScreen->overlayWindowCount () > 0)
+ priv->cScreen->updateOutputWindow ();
+}
+
+bool
+CompositeWindow::redirected ()
+{
+ return priv->redirected;
+}
+
+bool
+CompositeWindow::overlayWindow ()
+{
+ return priv->overlayWindow;
+}
+
+void
+CompositeWindow::damageTransformedRect (float xScale,
+ float yScale,
+ float xTranslate,
+ float yTranslate,
+ const CompRect &rect)
+{
+ int x1, x2, y1, y2;
+
+ x1 = (short) (rect.x1 () * xScale) - 1;
+ y1 = (short) (rect.y1 () * yScale) - 1;
+ x2 = (short) (rect.x2 () * xScale + 0.5f) + 1;
+ y2 = (short) (rect.y2 () * yScale + 0.5f) + 1;
+
+ x1 += (short) xTranslate;
+ y1 += (short) yTranslate;
+ x2 += (short) (xTranslate + 0.5f);
+ y2 += (short) (yTranslate + 0.5f);
+
+ if (x2 > x1 && y2 > y1)
+ {
+ CompWindow::Geometry geom = priv->window->geometry ();
+
+ x1 += geom.x () + geom.border ();
+ y1 += geom.y () + geom.border ();
+ x2 += geom.x () + geom.border ();
+ y2 += geom.y () + geom.border ();
+
+ priv->cScreen->damageRegion (CompRegion (CompRect (x1, y1, x2 - x1, y2 - y1)));
+ }
+}
+
+void
+CompositeWindow::damageOutputExtents ()
+{
+ if (priv->cScreen->damageMask () & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
+ return;
+
+ if (priv->window->shaded () ||
+ (priv->window->isViewable () && priv->damaged))
+ {
+ int x1, x2, y1, y2;
+
+ CompWindow::Geometry geom = priv->window->geometry ();
+ CompWindowExtents output = priv->window->output ();
+
+ /* top */
+ x1 = -output.left - geom.border ();
+ y1 = -output.top - geom.border ();
+ x2 = priv->window->size ().width () + output.right - geom.border ();
+ y2 = -geom.border ();
+
+ if (x1 < x2 && y1 < y2)
+ addDamageRect (CompRect (x1, y1, x2 - x1, y2 - y1));
+
+ /* bottom */
+ y1 = priv->window->size ().height () - geom.border ();
+ y2 = y1 + output.bottom - geom.border ();
+
+ if (x1 < x2 && y1 < y2)
+ addDamageRect (CompRect (x1, y1, x2 - x1, y2 - y1));
+
+ /* left */
+ x1 = -output.left - geom.border ();
+ y1 = -geom.border ();
+ x2 = -geom.border ();
+ y2 = priv->window->size ().height () - geom.border ();
+
+ if (x1 < x2 && y1 < y2)
+ addDamageRect (CompRect (x1, y1, x2 - x1, y2 - y1));
+
+ /* right */
+ x1 = priv->window->size ().width () - geom.border ();
+ x2 = x1 + output.right - geom.border ();
+
+ if (x1 < x2 && y1 < y2)
+ addDamageRect (CompRect (x1, y1, x2 - x1, y2 - y1));
+ }
+}
+
+void
+CompositeWindow::addDamageRect (const CompRect &rect)
+{
+ int x, y;
+
+ if (priv->cScreen->damageMask () & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
+ return;
+
+ if (!damageRect (false, rect))
+ {
+ x = rect.x ();
+ y = rect.y ();
+
+ CompWindow::Geometry geom = priv->window->geometry ();
+ x += geom.x () + geom.border ();
+ y += geom.y () + geom.border ();
+
+ priv->cScreen->damageRegion (CompRegion (CompRect (x, y,
+ rect.width (),
+ rect.height ())));
+ }
+}
+
+void
+CompositeWindow::addDamage (bool force)
+{
+ if (priv->cScreen->damageMask () & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
+ return;
+
+ if (priv->window->shaded () || force ||
+ (priv->window->isViewable () && priv->damaged))
+ {
+ int border = priv->window->geometry ().border ();
+
+ int x1 = -MAX (priv->window->output ().left,
+ priv->window->input ().left) - border;
+ int y1 = -MAX (priv->window->output ().top,
+ priv->window->input ().top) - border;
+ int x2 = priv->window->size ().width () +
+ MAX (priv->window->output ().right,
+ priv->window->input ().right) ;
+ int y2 = priv->window->size ().height () +
+ MAX (priv->window->output ().bottom,
+ priv->window->input ().bottom) ;
+ CompRect r (x1, y1, x2 - x1, y2 - y1);
+
+ addDamageRect (r);
+ }
+}
+
+bool
+CompositeWindow::damaged ()
+{
+ return priv->damaged;
+}
+
+void
+CompositeWindow::processDamage (XDamageNotifyEvent *de)
+{
+ if (priv->window->syncWait ())
+ {
+ if (priv->nDamage == priv->sizeDamage)
+ {
+ priv->damageRects = (XRectangle *) realloc (priv->damageRects,
+ (priv->sizeDamage + 1) *
+ sizeof (XRectangle));
+ priv->sizeDamage += 1;
+ }
+
+ priv->damageRects[priv->nDamage].x = de->area.x;
+ priv->damageRects[priv->nDamage].y = de->area.y;
+ priv->damageRects[priv->nDamage].width = de->area.width;
+ priv->damageRects[priv->nDamage].height = de->area.height;
+ priv->nDamage++;
+ }
+ else
+ {
+ priv->handleDamageRect (this, de->area.x, de->area.y,
+ de->area.width, de->area.height);
+ }
+}
+
+void
+PrivateCompositeWindow::handleDamageRect (CompositeWindow *w,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ bool initial = false;
+
+ if (!w->priv->redirected)
+ return;
+
+ if (!w->priv->damaged)
+ {
+ w->priv->damaged = initial = true;
+ }
+
+ if (!w->damageRect (initial, CompRect (x, y, width, height)))
+ {
+ CompWindow::Geometry geom = w->priv->window->geometry ();
+
+ x += geom.x () + geom.border ();
+ y += geom.y () + geom.border ();
+
+ w->priv->cScreen->damageRegion (CompRegion (CompRect (x, y, width, height)));
+ }
+
+ if (initial)
+ w->damageOutputExtents ();
+}
+
+void
+CompositeWindow::updateOpacity ()
+{
+ unsigned short opacity;
+
+ if (priv->window->type () & CompWindowTypeDesktopMask)
+ return;
+
+ opacity = screen->getWindowProp32 (priv->window->id (),
+ Atoms::winOpacity, OPAQUE);
+
+ if (opacity != priv->opacity)
+ {
+ priv->opacity = opacity;
+ addDamage ();
+ }
+}
+
+void
+CompositeWindow::updateBrightness ()
+{
+ unsigned short brightness;
+
+ brightness = screen->getWindowProp32 (priv->window->id (),
+ Atoms::winBrightness, BRIGHT);
+
+ if (brightness != priv->brightness)
+ {
+ priv->brightness = brightness;
+ addDamage ();
+ }
+}
+
+void
+CompositeWindow::updateSaturation ()
+{
+ unsigned short saturation;
+
+ saturation = screen->getWindowProp32 (priv->window->id (),
+ Atoms::winSaturation, COLOR);
+
+ if (saturation != priv->saturation)
+ {
+ priv->saturation = saturation;
+ addDamage ();
+ }
+}
+
+unsigned short
+CompositeWindow::opacity ()
+{
+ return priv->opacity;
+}
+
+unsigned short
+CompositeWindow::brightness ()
+{
+ return priv->brightness;
+}
+
+unsigned short
+CompositeWindow::saturation ()
+{
+ return priv->saturation;
+}
+
+bool
+CompositeWindow::damageRect (bool initial,
+ const CompRect &rect)
+{
+ WRAPABLE_HND_FUNC_RETURN (0, bool, damageRect, initial, rect)
+ return false;
+}
+
+void
+PrivateCompositeWindow::windowNotify (CompWindowNotify n)
+{
+ switch (n)
+ {
+ case CompWindowNotifyMap:
+ bindFailed = false;
+ damaged = false;
+ break;
+ case CompWindowNotifyUnmap:
+ cWindow->addDamage (true);
+ cWindow->release ();
+
+ if (!redirected && cScreen->compositingActive ())
+ cWindow->redirect ();
+ break;
+ case CompWindowNotifyRestack:
+ case CompWindowNotifyHide:
+ case CompWindowNotifyShow:
+ case CompWindowNotifyAliveChanged:
+ cWindow->addDamage (true);
+ break;
+ case CompWindowNotifyReparent:
+ case CompWindowNotifyUnreparent:
+ if (redirected)
+ {
+ cWindow->release ();
+ }
+ cScreen->damageScreen ();
+ cWindow->addDamage (true);
+ break;
+ case CompWindowNotifyFrameUpdate:
+ cWindow->release ();
+ break;
+ case CompWindowNotifySyncAlarm:
+ {
+ XRectangle *rects;
+
+ rects = damageRects;
+ while (nDamage--)
+ {
+ PrivateCompositeWindow::handleDamageRect (cWindow,
+ rects[nDamage].x,
+ rects[nDamage].y,
+ rects[nDamage].width,
+ rects[nDamage].height);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ window->windowNotify (n);
+}
+
+void
+PrivateCompositeWindow::resizeNotify (int dx, int dy, int dwidth, int dheight)
+{
+ window->resizeNotify (dx, dy, dwidth, dheight);
+
+ Pixmap pixmap = None;
+
+
+ if (window->shaded () || (window->isViewable () && damaged))
+ {
+ int x, y, x1, x2, y1, y2;
+
+ x = window->geometry ().x ();
+ y = window->geometry ().y ();
+
+ x1 = x - window->output ().left - dx;
+ y1 = y - window->output ().top - dy;
+ x2 = x + window->size ().width () +
+ window->output ().right - dx - dwidth;
+ y2 = y + window->size ().height () +
+ window->output ().bottom - dy - dheight;
+
+ cScreen->damageRegion (CompRegion (CompRect (x1, y1, x2 - x1, y2 - y1)));
+ }
+
+ if (window->mapNum () && redirected)
+ {
+ unsigned int actualWidth, actualHeight, ui;
+ Window root;
+ Status result;
+ int i;
+
+ pixmap = XCompositeNameWindowPixmap (screen->dpy (), window->id ());
+ result = XGetGeometry (screen->dpy (), pixmap, &root, &i, &i,
+ &actualWidth, &actualHeight, &ui, &ui);
+
+ if (!result || actualWidth != (unsigned int) window->size ().width () ||
+ actualHeight != (unsigned int) window->size ().height ())
+ {
+ XFreePixmap (screen->dpy (), pixmap);
+ return;
+ }
+ }
+
+ if (!window->mapNum () && window->hasUnmapReference () &&
+ !window->invisible ())
+ {
+ /* keep old pixmap for windows that are unmapped on the client side,
+ * but not yet on our side as it's pretty likely that plugins are
+ * currently using it for animations
+ */
+ }
+ else
+ {
+ cWindow->release ();
+ this->pixmap = pixmap;
+ }
+
+ cWindow->addDamage ();
+}
+
+void
+PrivateCompositeWindow::moveNotify (int dx, int dy, bool now)
+{
+ if (window->shaded () || (window->isViewable () && damaged))
+ {
+ int x, y, x1, x2, y1, y2;
+
+ x = window->geometry ().x ();
+ y = window->geometry ().y ();
+
+ x1 = x - window->output ().left - dx;
+ y1 = y - window->output ().top - dy;
+ x2 = x + window->size ().width () +
+ window->output ().right - dx;
+ y2 = y + window->size ().height () +
+ window->output ().bottom - dy;
+
+ cScreen->damageRegion (CompRegion (CompRect (x1, y1, x2 - x1, y2 - y1)));
+ }
+ cWindow->addDamage ();
+
+ window->moveNotify (dx, dy, now);
+}
+
+bool
+CompositeWindowInterface::damageRect (bool initial, const CompRect &rect)
+ WRAPABLE_DEF (damageRect, initial, rect)