summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/CMakeLists.txt9
-rw-r--r--plugins/annotate/CMakeLists.txt5
-rw-r--r--plugins/annotate/annotate.xml.in92
-rw-r--r--plugins/annotate/src/annotate.cpp980
-rw-r--r--plugins/annotate/src/annotate.h213
-rw-r--r--plugins/blur/CMakeLists.txt16
-rw-r--r--plugins/blur/blur.xml.in112
-rw-r--r--plugins/blur/src/blur.cpp2335
-rw-r--r--plugins/blur/src/blur.h241
-rw-r--r--plugins/clone/CMakeLists.txt5
-rw-r--r--plugins/clone/clone.xml.in22
-rw-r--r--plugins/clone/src/clone.cpp595
-rw-r--r--plugins/clone/src/clone.h147
-rw-r--r--plugins/commands/CMakeLists.txt5
-rw-r--r--plugins/commands/commands.xml.in385
-rw-r--r--plugins/commands/src/commands.cpp132
-rw-r--r--plugins/commands/src/commands.h50
-rw-r--r--plugins/compiztoolbox/CMakeLists.txt5
-rw-r--r--plugins/compiztoolbox/compiz-compiztoolbox.pc.in12
-rw-r--r--plugins/compiztoolbox/compiztoolbox.xml.in13
-rw-r--r--plugins/compiztoolbox/include/compiztoolbox/compiztoolbox.h168
-rw-r--r--plugins/compiztoolbox/src/compiztoolbox.cpp737
-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
-rw-r--r--plugins/copytex/CMakeLists.txt5
-rw-r--r--plugins/copytex/copytex.xml.in12
-rw-r--r--plugins/copytex/src/copytex.cpp341
-rw-r--r--plugins/copytex/src/copytex.h114
-rw-r--r--plugins/cube/CMakeLists.txt5
-rw-r--r--plugins/cube/compiz-cube.pc.in12
-rw-r--r--plugins/cube/cube.xml.in188
-rw-r--r--plugins/cube/include/cube/cube.h179
-rw-r--r--plugins/cube/src/cube.cpp1897
-rw-r--r--plugins/cube/src/privates.h196
-rw-r--r--plugins/dbus/CMakeLists.txt37
-rw-r--r--plugins/dbus/dbus.xml.in14
-rw-r--r--plugins/dbus/src/dbus.cpp2044
-rw-r--r--plugins/dbus/src/dbus.h185
-rw-r--r--plugins/decor/CMakeLists.txt14
-rw-r--r--plugins/decor/decor.xml.in75
-rw-r--r--plugins/decor/src/decor.cpp1746
-rw-r--r--plugins/decor/src/decor.h234
-rw-r--r--plugins/fade/CMakeLists.txt5
-rw-r--r--plugins/fade/fade.xml.in85
-rw-r--r--plugins/fade/src/fade.cpp398
-rw-r--r--plugins/fade/src/fade.h102
-rw-r--r--plugins/glib/CMakeLists.txt5
-rw-r--r--plugins/glib/glib.xml.in14
-rw-r--r--plugins/glib/src/glib.cpp177
-rw-r--r--plugins/glib/src/private.h77
-rw-r--r--plugins/gnomecompat/CMakeLists.txt5
-rw-r--r--plugins/gnomecompat/gnomecompat.xml.in59
-rw-r--r--plugins/gnomecompat/src/gnomecompat.cpp131
-rw-r--r--plugins/gnomecompat/src/gnomecompat.h53
-rw-r--r--plugins/imgpng/CMakeLists.txt5
-rw-r--r--plugins/imgpng/imgpng.xml.in16
-rw-r--r--plugins/imgpng/src/imgpng.cpp358
-rw-r--r--plugins/imgpng/src/imgpng.h69
-rw-r--r--plugins/imgsvg/CMakeLists.txt5
-rw-r--r--plugins/imgsvg/imgsvg.xml.in24
-rw-r--r--plugins/imgsvg/src/imgsvg.cpp637
-rw-r--r--plugins/imgsvg/src/imgsvg.h136
-rw-r--r--plugins/ini/CMakeLists.txt5
-rw-r--r--plugins/ini/ini.xml.in13
-rw-r--r--plugins/ini/src/ini.cpp611
-rw-r--r--plugins/ini/src/ini.h106
-rw-r--r--plugins/inotify/CMakeLists.txt10
-rw-r--r--plugins/inotify/inotify.xml.in14
-rw-r--r--plugins/inotify/src/inotify.cpp169
-rw-r--r--plugins/inotify/src/inotify.h66
-rw-r--r--plugins/kde/CMakeLists.txt22
-rw-r--r--plugins/kde/kde.xml.in15
-rw-r--r--plugins/kde/src/dispatcher.cpp262
-rw-r--r--plugins/kde/src/dispatcher.h79
-rw-r--r--plugins/kde/src/kde.cpp68
-rw-r--r--plugins/kde/src/kde.h60
-rw-r--r--plugins/kde/src/socket.cpp67
-rw-r--r--plugins/kde/src/socket.h44
-rw-r--r--plugins/kde/src/timer.cpp69
-rw-r--r--plugins/kde/src/timer.h55
-rw-r--r--plugins/move/CMakeLists.txt5
-rw-r--r--plugins/move/move.xml.in48
-rw-r--r--plugins/move/src/move.cpp730
-rw-r--r--plugins/move/src/move.h129
-rw-r--r--plugins/obs/CMakeLists.txt5
-rw-r--r--plugins/obs/obs.xml.in161
-rw-r--r--plugins/obs/src/obs.cpp332
-rw-r--r--plugins/obs/src/obs.h102
-rw-r--r--plugins/opengl/CMakeLists.txt8
-rw-r--r--plugins/opengl/compiz-opengl.pc.in12
-rw-r--r--plugins/opengl/include/opengl/fragment.h124
-rw-r--r--plugins/opengl/include/opengl/matrix.h66
-rw-r--r--plugins/opengl/include/opengl/opengl.h590
-rw-r--r--plugins/opengl/include/opengl/texture.h220
-rw-r--r--plugins/opengl/include/opengl/vector.h127
-rw-r--r--plugins/opengl/opengl.xml.in48
-rw-r--r--plugins/opengl/src/fragment.cpp1105
-rw-r--r--plugins/opengl/src/matrix.cpp439
-rw-r--r--plugins/opengl/src/opengl.cpp101
-rw-r--r--plugins/opengl/src/paint.cpp1262
-rw-r--r--plugins/opengl/src/privatefragment.h54
-rw-r--r--plugins/opengl/src/privates.h172
-rw-r--r--plugins/opengl/src/privatetexture.h85
-rw-r--r--plugins/opengl/src/screen.cpp1193
-rw-r--r--plugins/opengl/src/texture.cpp615
-rw-r--r--plugins/opengl/src/vector.cpp276
-rw-r--r--plugins/opengl/src/window.cpp363
-rw-r--r--plugins/place/CMakeLists.txt5
-rw-r--r--plugins/place/place.xml.in168
-rw-r--r--plugins/place/src/place.cpp1680
-rw-r--r--plugins/place/src/place.h140
-rw-r--r--plugins/regex/CMakeLists.txt5
-rw-r--r--plugins/regex/regex.xml.in14
-rw-r--r--plugins/regex/src/regex.cpp309
-rw-r--r--plugins/regex/src/regexplugin.h74
-rw-r--r--plugins/resize/CMakeLists.txt5
-rw-r--r--plugins/resize/resize.xml.in115
-rw-r--r--plugins/resize/src/resize.cpp1414
-rw-r--r--plugins/resize/src/resize.h174
-rw-r--r--plugins/rotate/CMakeLists.txt5
-rw-r--r--plugins/rotate/rotate.xml.in278
-rw-r--r--plugins/rotate/src/rotate.cpp1080
-rw-r--r--plugins/rotate/src/rotate.h173
-rw-r--r--plugins/scale/CMakeLists.txt5
-rw-r--r--plugins/scale/compiz-scale.pc.in12
-rw-r--r--plugins/scale/include/scale/scale.h166
-rw-r--r--plugins/scale/scale.xml.in179
-rw-r--r--plugins/scale/src/privates.h187
-rw-r--r--plugins/scale/src/scale.cpp1782
-rw-r--r--plugins/screenshot/CMakeLists.txt5
-rw-r--r--plugins/screenshot/screenshot.xml.in36
-rw-r--r--plugins/screenshot/src/screenshot.cpp362
-rw-r--r--plugins/screenshot/src/screenshot.h83
-rw-r--r--plugins/switcher/CMakeLists.txt5
-rw-r--r--plugins/switcher/src/switcher.cpp1186
-rw-r--r--plugins/switcher/src/switcher.h175
-rw-r--r--plugins/switcher/switcher.xml.in167
-rw-r--r--plugins/water/CMakeLists.txt5
-rw-r--r--plugins/water/src/water.cpp1356
-rw-r--r--plugins/water/src/water.h179
-rw-r--r--plugins/water/water.xml.in64
-rw-r--r--plugins/wobbly/CMakeLists.txt5
-rw-r--r--plugins/wobbly/src/wobbly.cpp2380
-rw-r--r--plugins/wobbly/src/wobbly.h369
-rw-r--r--plugins/wobbly/wobbly.xml.in126
-rw-r--r--plugins/zoom/CMakeLists.txt5
-rw-r--r--plugins/zoom/src/zoom.cpp742
-rw-r--r--plugins/zoom/src/zoom.h112
-rw-r--r--plugins/zoom/zoom.xml.in66
155 files changed, 43790 insertions, 0 deletions
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
new file mode 100644
index 0000000..ed5baa0
--- /dev/null
+++ b/plugins/CMakeLists.txt
@@ -0,0 +1,9 @@
+set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
+include (CompizDefaults)
+include (CompizCommon)
+
+set (COMPIZ_FOUND "true")
+
+add_definitions ( -DHAVE_CONFIG_H)
+
+compiz_add_plugins_in_folder (${CMAKE_CURRENT_SOURCE_DIR}) \ No newline at end of file
diff --git a/plugins/annotate/CMakeLists.txt b/plugins/annotate/CMakeLists.txt
new file mode 100644
index 0000000..9c7bcc4
--- /dev/null
+++ b/plugins/annotate/CMakeLists.txt
@@ -0,0 +1,5 @@
+find_package (Compiz REQUIRED)
+
+include (CompizPlugin)
+
+compiz_plugin(annotate PLUGINDEPS composite opengl PKGDEPS pangocairo cairo cairo-xlib-xrender)
diff --git a/plugins/annotate/annotate.xml.in b/plugins/annotate/annotate.xml.in
new file mode 100644
index 0000000..e397d15
--- /dev/null
+++ b/plugins/annotate/annotate.xml.in
@@ -0,0 +1,92 @@
+<compiz>
+ <plugin name="annotate" useBcop="true">
+ <_short>Annotate</_short>
+ <_long>Annotate plugin</_long>
+ <category>Extras</category>
+ <deps>
+ <relation type="after">
+ <plugin>decor</plugin>
+ </relation>
+ <requirement>
+ <plugin>opengl</plugin>
+ </requirement>
+ </deps>
+ <options>
+ <option name="initiate_free_draw_button" type="button">
+ <_short>Initiate Free Draw</_short>
+ <_long>Initiate freehand drawing</_long>
+ <default>&lt;Super&gt;&lt;Alt&gt;Button1</default>
+ </option>
+ <option name="initiate_line_button" type="button">
+ <_short>Initiate Line</_short>
+ <_long>Initiate line drawing</_long>
+ <default>&lt;Super&gt;&lt;Alt&gt;Button2</default>
+ </option>
+ <option name="initiate_rectangle_button" type="button">
+ <_short>Initiate Rectangle</_short>
+ <_long>Initiate rectangle drawing</_long>
+ <default>&lt;Super&gt;&lt;Alt&gt;&lt;Shift&gt;Button1</default>
+ </option>
+ <option name="initiate_ellipse_button" type="button">
+ <_short>Initiate Ellipse</_short>
+ <_long>Initiate ellipse drawing</_long>
+ <default>&lt;Super&gt;&lt;Alt&gt;&lt;Shift&gt;Button2</default>
+ </option>
+ <option name="draw" type="action">
+ <_short>Draw</_short>
+ <_long>Draw using tool</_long>
+ <allowed/>
+ </option>
+ <option name="erase_button" type="button">
+ <_short>Initiate Erase</_short>
+ <_long>Initiate annotate erasing</_long>
+ <default>&lt;Super&gt;&lt;Alt&gt;Button3</default>
+ </option>
+ <option name="clear_key" type="key">
+ <_short>Clear</_short>
+ <_long>Clear</_long>
+ <default>&lt;Super&gt;&lt;Alt&gt;k</default>
+ </option>
+ <option name="clear_button" type="button">
+ <_short>Clear</_short>
+ <_long>Clear</_long>
+ </option>
+ <option name="draw_shapes_from_center" type="bool">
+ <_short>Draw shapes from center</_short>
+ <_long>Uses the initial click point as the center of shapes.</_long>
+ <default>true</default>
+ </option>
+ <option name="fill_color" type="color">
+ <_short>Annotate Fill Color</_short>
+ <_long>Fill color for annotations</_long>
+ <default>
+ <red>0xffff</red>
+ <alpha>0x8888</alpha>
+ </default>
+ </option>
+ <option name="stroke_color" type="color">
+ <_short>Annotate Stroke Color</_short>
+ <_long>Stroke color for annotations</_long>
+ <default>
+ <green>0xffff</green>
+ </default>
+ </option>
+ <option name="erase_width" type="float">
+ <_short>Erase width</_short>
+ <_long>Erase size</_long>
+ <default>20.0</default>
+ <min>1.0</min>
+ <max>100.0</max>
+ <precision>0.1</precision>
+ </option>
+ <option name="stroke_width" type="float">
+ <_short>Stroke width</_short>
+ <_long>Stroke width for annotations</_long>
+ <default>3.0</default>
+ <min>1.0</min>
+ <max>100.0</max>
+ <precision>0.1</precision>
+ </option>
+ </options>
+ </plugin>
+</compiz>
diff --git a/plugins/annotate/src/annotate.cpp b/plugins/annotate/src/annotate.cpp
new file mode 100644
index 0000000..16949b0
--- /dev/null
+++ b/plugins/annotate/src/annotate.cpp
@@ -0,0 +1,980 @@
+/*
+ * Copyright © 2006 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include "annotate.h"
+
+COMPIZ_PLUGIN_20090315 (annotate, AnnoPluginVTable);
+
+void
+AnnoScreen::cairoClear (cairo_t *cr)
+{
+ cairo_save (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ cairo_paint (cr);
+ cairo_restore (cr);
+
+ content = false;
+}
+
+cairo_t *
+AnnoScreen::cairoContext ()
+{
+ if (!cairo)
+ {
+ XRenderPictFormat *format;
+ Screen *xScreen;
+ int w, h;
+
+ xScreen = ScreenOfDisplay (screen->dpy (), screen->screenNum ());
+
+ w = screen->width ();
+ h = screen->height ();
+
+ format = XRenderFindStandardFormat (screen->dpy (),
+ PictStandardARGB32);
+
+ pixmap = XCreatePixmap (screen->dpy (), screen->root (), w, h, 32);
+
+ texture = GLTexture::bindPixmapToTexture (pixmap, w, h, 32);
+
+ if (texture.empty ())
+ {
+ compLogMessage ("annotate", CompLogLevelError,
+ "Couldn't bind pixmap 0x%x to texture",
+ (int) pixmap);
+
+ XFreePixmap (screen->dpy (), pixmap);
+
+ return NULL;
+ }
+
+ damage = XDamageCreate (screen->dpy (), pixmap,
+ XDamageReportRawRectangles);
+
+ surface =
+ cairo_xlib_surface_create_with_xrender_format (screen->dpy (),
+ pixmap, xScreen,
+ format, w, h);
+
+ cairo = cairo_create (surface);
+
+ if (cairoBuffer.size ())
+ {
+ cairo_t *cr = cairo_create (surface);
+ int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, w);
+ cairo_surface_t *raw_source =
+ cairo_image_surface_create_for_data ((unsigned char *)
+ cairoBuffer.c_str (),
+ CAIRO_FORMAT_ARGB32,
+ w, h, stride);
+
+ if (cr && raw_source)
+ {
+ cairo_set_source_surface (cr, raw_source, 0, 0);
+ cairo_paint (cr);
+
+ cairo_surface_destroy (raw_source);
+ cairo_destroy (cr);
+ cairoBuffer.clear ();
+ }
+ }
+ else
+ cairoClear (cairo);
+ }
+
+ return cairo;
+}
+
+void
+AnnoScreen::setSourceColor (cairo_t *cr,
+ unsigned short *color)
+{
+ cairo_set_source_rgba (cr,
+ (double) color[0] / 0xffff,
+ (double) color[1] / 0xffff,
+ (double) color[2] / 0xffff,
+ (double) color[3] / 0xffff);
+}
+
+void
+AnnoScreen::drawEllipse (double xc,
+ double yc,
+ double radiusX,
+ double radiusY,
+ unsigned short *fillColor,
+ unsigned short *strokeColor,
+ double strokeWidth)
+{
+ cairo_t *cr;
+
+ cr = cairoContext ();
+ if (cr)
+ {
+ setSourceColor (cr, fillColor);
+ cairo_save (cr);
+ cairo_translate (cr, xc, yc);
+ if (radiusX > radiusY)
+ {
+ cairo_scale (cr, 1.0, radiusY/radiusX);
+ cairo_arc (cr, 0, 0, radiusX, 0, 2 * M_PI);
+ }
+ else
+ {
+ cairo_scale (cr, radiusX/radiusY, 1.0);
+ cairo_arc (cr, 0, 0, radiusY, 0, 2 * M_PI);
+ }
+ cairo_restore (cr);
+ cairo_fill_preserve (cr);
+ cairo_set_line_width (cr, strokeWidth);
+ setSourceColor (cr, strokeColor);
+ cairo_stroke (cr);
+
+ content = true;
+ }
+}
+
+void
+AnnoScreen::drawRectangle (double x,
+ double y,
+ double w,
+ double h,
+ unsigned short *fillColor,
+ unsigned short *strokeColor,
+ double strokeWidth)
+{
+ cairo_t *cr;
+
+ cr = cairoContext ();
+ if (cr)
+ {
+ double ex1, ey1, ex2, ey2;
+
+ setSourceColor (cr, fillColor);
+ cairo_rectangle (cr, x, y, w, h);
+ cairo_fill_preserve (cr);
+ cairo_set_line_width (cr, strokeWidth);
+ cairo_stroke_extents (cr, &ex1, &ey1, &ex2, &ey2);
+ setSourceColor (cr, strokeColor);
+ cairo_stroke (cr);
+
+ content = true;
+ }
+}
+
+void
+AnnoScreen::drawLine (double x1,
+ double y1,
+ double x2,
+ double y2,
+ double width,
+ unsigned short *color)
+{
+ cairo_t *cr;
+
+ cr = cairoContext ();
+ if (cr)
+ {
+ double ex1, ey1, ex2, ey2;
+
+ cairo_set_line_width (cr, width);
+ cairo_move_to (cr, x1, y1);
+ cairo_line_to (cr, x2, y2);
+ cairo_stroke_extents (cr, &ex1, &ey1, &ex2, &ey2);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ setSourceColor (cr, color);
+ cairo_stroke (cr);
+
+ content = true;
+ }
+}
+
+void
+AnnoScreen::drawText (double x,
+ double y,
+ const char *text,
+ const char *fontFamily,
+ double fontSize,
+ cairo_font_slant_t fontSlant,
+ cairo_font_weight_t fontWeight,
+ unsigned short *fillColor,
+ unsigned short *strokeColor,
+ double strokeWidth)
+{
+ REGION reg;
+ cairo_t *cr;
+
+ cr = cairoContext ();
+ if (cr)
+ {
+ cairo_text_extents_t extents;
+
+ cairo_set_line_width (cr, strokeWidth);
+ setSourceColor (cr, fillColor);
+ cairo_select_font_face (cr, fontFamily, fontSlant, fontWeight);
+ cairo_set_font_size (cr, fontSize);
+ cairo_text_extents (cr, text, &extents);
+ cairo_save (cr);
+ cairo_move_to (cr, x, y);
+ cairo_text_path (cr, text);
+ cairo_fill_preserve (cr);
+ setSourceColor (cr, strokeColor);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+ reg.rects = &reg.extents;
+ reg.numRects = 1;
+
+ reg.extents.x1 = x;
+ reg.extents.y1 = y + extents.y_bearing - 2.0;
+ reg.extents.x2 = x + extents.width + 20.0;
+ reg.extents.y2 = y + extents.height;
+
+ content = true;
+ }
+}
+
+/* DBUS Interface (TODO: plugin interface) */
+
+/* Here, you can use DBUS or any other plugin via the action system to draw on
+ * the screen using cairo. Parameters are as follows:
+ * "tool": ["rectangle", "circle", "line", "text"] default: "line"
+ * - This allows you to select what you want to draw
+ * Tool-specific parameters:
+ * - * "circle"
+ * - * - "xc" float, default: 0 - X Center
+ * - * - "yc" float, default: 0 - Y Center
+ * - * - "radius" float, default: 0 - Radius
+ * - * "rectangle"
+ * - * - "x" float, default: 0 - X Point
+ * - * - "y" float, default: 0 - Y Point
+ * - * - "width" float, default: 0 - Width
+ * - * - "height" float, default: 0 - Height
+ * - * "line"
+ * - * - "x1" float, default: 0 - X Point 1
+ * - * - "y1" float, default: 0 - Y Point 1
+ * - * - "x2" float, default: 0 - X Point 2
+ * - * - "y2" float, default: 0 - Y Point 2
+ * - * "text"
+ * - * - "slant" string, default: "" - ["oblique", "italic", ""] - Text Slant
+ * - * - "weight" string, default: " - ["bold", ""] - Text Weight
+ * - * - "text" string, default: "" - Any Character - The text to display
+ * - * - "family" float, default: "Sans" - The font family
+ * - * - "size" float, default: 36.0 - Font Size
+ * - * - "x" float, default: 0 - X Point
+ * - * - "u" float, default: 0 - Y Point
+ * Other parameters are:
+ * - * - "fill_color" float, default: 0 - Drawing Fill Color
+ * - * - "stroke_color" float, default: 0 - Drawing Border Color
+ * - * - "line_width" float, default: 0 - Drawing Width
+ * - * - "stroke_width" float, default: 0 - Drawing Height
+ * - * - All of these are taken from the builtin options if not provided
+ */
+
+bool
+AnnoScreen::draw (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options)
+{
+ cairo_t *cr;
+
+ cr = cairoContext ();
+ if (cr)
+ {
+ const char *tool;
+ unsigned short *fillColor, *strokeColor;
+ double strokeWidth;
+
+ tool =
+ CompOption::getStringOptionNamed (options, "tool", "line").c_str ();
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+
+ fillColor = optionGetFillColor ();
+ fillColor = CompOption::getColorOptionNamed (options, "fill_color",
+ fillColor);
+
+ strokeColor = optionGetStrokeColor ();
+ strokeColor = CompOption::getColorOptionNamed (options,
+ "stroke_color", strokeColor);
+
+ strokeWidth = optionGetStrokeWidth ();
+ strokeWidth = CompOption::getFloatOptionNamed (options, "stroke_width",
+ strokeWidth);
+
+ if (strcasecmp (tool, "rectangle") == 0)
+ {
+ double x, y, w, h;
+
+ x = CompOption::getFloatOptionNamed (options, "x", 0);
+ y = CompOption::getFloatOptionNamed (options, "y", 0);
+ w = CompOption::getFloatOptionNamed (options, "w", 100);
+ h = CompOption::getFloatOptionNamed (options, "h", 100);
+
+ drawRectangle (x, y, w, h, fillColor, strokeColor,
+ strokeWidth);
+ }
+ else if (strcasecmp (tool, "ellipse") == 0)
+ {
+ double xc, yc, xr, yr;
+
+ xc = CompOption::getFloatOptionNamed (options, "xc", 0);
+ yc = CompOption::getFloatOptionNamed (options, "yc", 0);
+ xr = CompOption::getFloatOptionNamed (options, "radiusX", 100);
+ yr = CompOption::getFloatOptionNamed (options, "radiusY", 100);
+
+ drawEllipse (xc, yc, xr, yr, fillColor, strokeColor,
+ strokeWidth);
+ }
+ else if (strcasecmp (tool, "line") == 0)
+ {
+ double x1, y1, x2, y2;
+
+ x1 = CompOption::getFloatOptionNamed (options, "x1", 0);
+ y1 = CompOption::getFloatOptionNamed (options, "y1", 0);
+ x2 = CompOption::getFloatOptionNamed (options, "x2", 100);
+ y2 = CompOption::getFloatOptionNamed (options, "y2", 100);
+
+ drawLine (x1, y1, x2, y2, strokeWidth, fillColor);
+ }
+ else if (strcasecmp (tool, "text") == 0)
+ {
+ double x, y, size;
+ const char *text, *family;
+ cairo_font_slant_t slant;
+ cairo_font_weight_t weight;
+ const char *str;
+
+ str =
+ CompOption::getStringOptionNamed (options, "slant", "").c_str ();
+ if (strcasecmp (str, "oblique") == 0)
+ slant = CAIRO_FONT_SLANT_OBLIQUE;
+ else if (strcasecmp (str, "italic") == 0)
+ slant = CAIRO_FONT_SLANT_ITALIC;
+ else
+ slant = CAIRO_FONT_SLANT_NORMAL;
+
+ str =
+ CompOption::getStringOptionNamed (options, "weight", "").c_str ();
+ if (strcasecmp (str, "bold") == 0)
+ weight = CAIRO_FONT_WEIGHT_BOLD;
+ else
+ weight = CAIRO_FONT_WEIGHT_NORMAL;
+
+ x = CompOption::getFloatOptionNamed (options, "x", 0);
+ y = CompOption::getFloatOptionNamed (options, "y", 0);
+ text =
+ CompOption::getStringOptionNamed (options, "text", "").c_str ();
+ family = CompOption::getStringOptionNamed (options, "family",
+ "Sans").c_str ();
+ size = CompOption::getFloatOptionNamed (options, "size", 36.0);
+
+ drawText (x, y, text, family, size, slant, weight,
+ fillColor, strokeColor, strokeWidth);
+ }
+ }
+
+ return true;
+}
+
+bool
+AnnoScreen::terminate (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options)
+{
+ if (grabIndex)
+ {
+ screen->removeGrab (grabIndex, NULL);
+ grabIndex = 0;
+ }
+
+ action->setState (action->state () & ~(CompAction::StateTermKey |
+ CompAction::StateTermButton));
+
+ switch (drawMode)
+ {
+ case LineMode:
+ drawLine (initialPointerX, initialPointerY,
+ lineVector.x (), lineVector.y (),
+ optionGetStrokeWidth (),
+ optionGetStrokeColor ());
+ break;
+
+ case RectangleMode:
+ drawRectangle (rectangle.x (),
+ rectangle.y (),
+ rectangle.width (),
+ rectangle.height (),
+ optionGetFillColor (),
+ optionGetStrokeColor (),
+ optionGetStrokeWidth ());
+ break;
+
+ case EllipseMode:
+ drawEllipse (ellipse.center.x (),
+ ellipse.center.y (),
+ ellipse.radiusX,
+ ellipse.radiusY,
+ optionGetFillColor (),
+ optionGetStrokeColor (),
+ optionGetStrokeWidth ());
+ break;
+
+ default:
+ break;
+ }
+
+ drawMode = NoMode;
+
+ return false;
+}
+
+bool
+AnnoScreen::initiateErase (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options)
+{
+ if (screen->otherGrabExist (NULL))
+ return false;
+
+ if (!grabIndex)
+ grabIndex = screen->pushGrab (None, "annotate");
+
+ if (state & CompAction::StateInitButton)
+ action->setState (action->state () | CompAction::StateTermButton);
+
+ if (state & CompAction::StateInitKey)
+ action->setState (action->state () | CompAction::StateTermKey);
+
+ annoLastPointerX = pointerX;
+ annoLastPointerY = pointerY;
+
+ drawMode = EraseMode;
+
+ screen->handleEventSetEnabled (this, true);
+
+ return false;
+}
+
+bool
+AnnoScreen::initiateFreeDraw (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options)
+{
+ if (screen->otherGrabExist (NULL))
+ return false;
+
+ if (!grabIndex)
+ grabIndex = screen->pushGrab (None, "annotate");
+
+ if (state & CompAction::StateInitButton)
+ action->setState (action->state () | CompAction::StateTermButton);
+
+ if (state & CompAction::StateInitKey)
+ action->setState (action->state () | CompAction::StateTermKey);
+
+ annoLastPointerX = pointerX;
+ annoLastPointerY = pointerY;
+
+ drawMode = FreeDrawMode;
+
+ screen->handleEventSetEnabled (this, true);
+
+ return true;
+}
+
+bool
+AnnoScreen::initiateLine (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options)
+{
+ if (screen->otherGrabExist (NULL))
+ return false;
+
+ if (!grabIndex)
+ grabIndex = screen->pushGrab (None, "annotate");
+
+ if (state & CompAction::StateInitButton)
+ action->setState (action->state () | CompAction::StateTermButton);
+
+ if (state & CompAction::StateInitKey)
+ action->setState (action->state () | CompAction::StateTermKey);
+
+ initialPointerX = pointerX;
+ initialPointerY = pointerY;
+
+ drawMode = LineMode;
+
+ screen->handleEventSetEnabled (this, true);
+
+ return true;
+}
+
+bool
+AnnoScreen::initiateRectangle (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options)
+{
+ if (screen->otherGrabExist (NULL))
+ return false;
+
+ if (!grabIndex)
+ grabIndex = screen->pushGrab (None, "annotate");
+
+ if (state & CompAction::StateInitButton)
+ action->setState (action->state () | CompAction::StateTermButton);
+
+ if (state & CompAction::StateInitKey)
+ action->setState (action->state () | CompAction::StateTermKey);
+
+ drawMode = RectangleMode;
+
+ initialPointerX = pointerX;
+ initialPointerY = pointerY;
+ rectangle.setGeometry (initialPointerX, initialPointerY, 0, 0);
+ lastRect = rectangle;
+
+ screen->handleEventSetEnabled (this, true);
+
+ return true;
+}
+
+bool
+AnnoScreen::initiateEllipse (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options)
+{
+ if (screen->otherGrabExist (NULL))
+ return false;
+
+ if (!grabIndex)
+ grabIndex = screen->pushGrab (None, "annotate");
+
+ if (state & CompAction::StateInitButton)
+ action->setState (action->state () | CompAction::StateTermButton);
+
+ if (state & CompAction::StateInitKey)
+ action->setState (action->state () | CompAction::StateTermKey);
+
+ drawMode = EllipseMode;
+
+ initialPointerX = pointerX;
+ initialPointerY = pointerY;
+ ellipse.radiusX = 0;
+ ellipse.radiusY = 0;
+ lastRect.setGeometry (initialPointerX, initialPointerY, 0, 0);
+
+ screen->handleEventSetEnabled (this, true);
+
+ return true;
+}
+
+bool
+AnnoScreen::clear (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options)
+{
+ if (content)
+ {
+ cairo_t *cr;
+
+ cr = cairoContext ();
+ if (cr)
+ cairoClear (cairo);
+
+ cScreen->damageScreen ();
+
+ /* We don't need to refresh the screen or handle events anymore */
+ screen->handleEventSetEnabled (this, false);
+ gScreen->glPaintOutputSetEnabled (this, false);
+ }
+
+ return true;
+}
+
+bool
+AnnoScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ bool status;
+
+ status = gScreen->glPaintOutput (attrib, transform, region, output, mask);
+
+ if (status)
+ {
+ CompRect rect;
+ GLMatrix sTransform = transform;
+ int numRect;
+ int pos = 0;
+ float vectorX, vectorY, offset;
+ int angle;
+
+ offset = optionGetStrokeWidth () / 2;
+
+ /* This replaced prepareXCoords (s, output, -DEFAULT_Z_CAMERA) */
+ sTransform.toScreenSpace (output, -DEFAULT_Z_CAMERA);
+
+ glPushMatrix ();
+ glLoadMatrixf (sTransform.getMatrix ());
+
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+ glEnable (GL_BLEND);
+
+ if (content && !region.isEmpty ())
+ {
+ foreach (GLTexture *tex, texture)
+ {
+ CompRect::vector rect = region.rects ();
+ numRect = region.rects ().size ();
+
+ tex->enable (GLTexture::Fast);
+
+ glBegin (GL_QUADS);
+
+ while (numRect--)
+ {
+ glTexCoord2f (
+ COMP_TEX_COORD_X (tex->matrix (), rect.at (pos).x1 ()),
+ COMP_TEX_COORD_Y (tex->matrix (), rect.at (pos).y2 ()));
+ glVertex2i (rect.at (pos).x1 (), rect.at (pos).y2 ());
+
+ glTexCoord2f (
+ COMP_TEX_COORD_X (tex->matrix (), rect.at (pos).x2 ()),
+ COMP_TEX_COORD_Y (tex->matrix (), rect.at (pos).y2 ()));
+ glVertex2i (rect.at (pos).x2 (), rect.at (pos).y2 ());
+
+ glTexCoord2f (
+ COMP_TEX_COORD_X (tex->matrix (), rect.at (pos).x2 ()),
+ COMP_TEX_COORD_Y (tex->matrix (), rect.at (pos).y1 ()));
+ glVertex2i (rect.at (pos).x2 (), rect.at (pos).y1 ());
+
+ glTexCoord2f (
+ COMP_TEX_COORD_X (tex->matrix (), rect.at (pos).x1 ()),
+ COMP_TEX_COORD_Y (tex->matrix (), rect.at (pos).y1 ()));
+ glVertex2i (rect.at (pos).x1 (), rect.at (pos).y1 ());
+
+ pos++;
+ }
+
+ glEnd ();
+ tex->disable ();
+ }
+ }
+
+ switch (drawMode)
+ {
+ case LineMode:
+ glColor4usv (optionGetStrokeColor ());
+ glLineWidth (optionGetStrokeWidth ());
+ glBegin (GL_LINES);
+ glVertex2i (initialPointerX, initialPointerY);
+ glVertex2i (lineVector.x (), lineVector.y ());
+ glEnd ();
+ break;
+
+ case RectangleMode:
+ /* fill rectangle */
+ glColor4usv (optionGetFillColor ());
+ glRecti (rectangle.x1 (), rectangle.y2 (),
+ rectangle.x2 (), rectangle.y1 ());
+
+ /* draw rectangle outline */
+ glColor4usv (optionGetStrokeColor ());
+ glRecti (rectangle.x1 () - offset, rectangle.y2 (),
+ rectangle.x1 () + offset, rectangle.y1 ());
+ glRecti (rectangle.x2 () - offset, rectangle.y2 (),
+ rectangle.x2 () + offset, rectangle.y1 ());
+ glRecti (rectangle.x1 () - offset, rectangle.y1 () + offset,
+ rectangle.x2 () + offset, rectangle.y1 () - offset);
+ glRecti (rectangle.x1 () - offset, rectangle.y2 () + offset,
+ rectangle.x2 () + offset, rectangle.y2 () - offset);
+ break;
+
+ case EllipseMode:
+ /* fill ellipse */
+ glColor4usv (optionGetFillColor ());
+
+ glBegin (GL_TRIANGLE_FAN);
+ glVertex2d (ellipse.center.x (), ellipse.center.y ());
+ for (angle = 0; angle <= 360; angle += 1)
+ {
+ vectorX = ellipse.center.x () +
+ (ellipse.radiusX * sinf (angle * DEG2RAD));
+ vectorY = ellipse.center.y () +
+ (ellipse.radiusY * cosf (angle * DEG2RAD));
+ glVertex2d (vectorX, vectorY);
+ }
+ glVertex2d (ellipse.center.x (), ellipse.center.y () +
+ ellipse.radiusY);
+ glEnd();
+
+ /* draw ellipse outline */
+ glColor4usv (optionGetStrokeColor ());
+ glLineWidth (optionGetStrokeWidth ());
+
+ glBegin (GL_TRIANGLE_STRIP);
+ glVertex2d (ellipse.center.x (), ellipse.center.y () +
+ ellipse.radiusY - offset);
+ for (angle = 360; angle >= 0; angle -= 1)
+ {
+ vectorX = ellipse.center.x () + ((ellipse.radiusX -
+ offset) * sinf (angle * DEG2RAD));
+ vectorY = ellipse.center.y () + ((ellipse.radiusY -
+ offset) * cosf (angle * DEG2RAD));
+ glVertex2d (vectorX, vectorY);
+ vectorX = ellipse.center.x () + ((ellipse.radiusX +
+ offset) * sinf (angle * DEG2RAD));
+ vectorY = ellipse.center.y () + ((ellipse.radiusY +
+ offset) * cosf (angle * DEG2RAD));
+ glVertex2d (vectorX, vectorY);
+ }
+ glVertex2d (ellipse.center.x (), ellipse.center.y () +
+ ellipse.radiusY + offset);
+ glEnd();
+ break;
+
+ default:
+ break;
+ }
+
+ /* clean up */
+ glColor4usv (defaultColor);
+ glDisable (GL_BLEND);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ glPopMatrix ();
+ }
+
+ return status;
+}
+
+void
+AnnoScreen::handleMotionEvent (int xRoot,
+ int yRoot)
+{
+ static unsigned short clearColor[] = { 0, 0, 0, 0 };
+
+ CompRect damageRect;
+
+ if (grabIndex)
+ {
+ switch (drawMode)
+ {
+ case EraseMode:
+ drawLine (annoLastPointerX, annoLastPointerY,
+ xRoot, yRoot,
+ optionGetEraseWidth (), clearColor);
+ break;
+
+ case FreeDrawMode:
+ drawLine (annoLastPointerX, annoLastPointerY,
+ xRoot, yRoot,
+ optionGetStrokeWidth (),
+ optionGetStrokeColor ());
+ break;
+
+ case LineMode:
+ lineVector.setX (xRoot);
+ lineVector.setY (yRoot);
+
+ damageRect.setGeometry (MIN(initialPointerX, lineVector.x ()),
+ MIN(initialPointerY, lineVector.y ()),
+ abs (lineVector.x () - initialPointerX),
+ abs (lineVector.y () - initialPointerY));
+ break;
+
+ case RectangleMode:
+ if (optionGetDrawShapesFromCenter ())
+ rectangle.setGeometry (initialPointerX -
+ abs (xRoot - initialPointerX),
+ initialPointerY -
+ abs (yRoot - initialPointerY),
+ (abs (xRoot - initialPointerX)) * 2,
+ (abs (yRoot - initialPointerY)) * 2);
+ else
+ rectangle.setGeometry (MIN(initialPointerX, xRoot),
+ MIN(initialPointerY, yRoot),
+ abs (xRoot - initialPointerX),
+ abs (yRoot - initialPointerY));
+
+ damageRect = rectangle;
+ break;
+
+ case EllipseMode:
+ if (optionGetDrawShapesFromCenter ())
+ {
+ ellipse.center.setX (initialPointerX);
+ ellipse.center.setY (initialPointerY);
+ }
+ else
+ {
+ ellipse.center.setX (initialPointerX +
+ (xRoot - initialPointerX) / 2);
+ ellipse.center.setY (initialPointerY +
+ (yRoot - initialPointerY) / 2);
+ }
+
+ ellipse.radiusX = abs (xRoot - ellipse.center.x ());
+ ellipse.radiusY = abs (yRoot - ellipse.center.y ());
+
+ damageRect = CompRect (ellipse.center.x () - ellipse.radiusX,
+ ellipse.center.y () - ellipse.radiusY,
+ ellipse.radiusX * 2,
+ ellipse.radiusY * 2);
+ break;
+
+ default:
+ break;
+ }
+
+ if (cScreen && (drawMode == LineMode ||
+ drawMode == RectangleMode ||
+ drawMode == EllipseMode))
+ {
+ /* Add border width to the damage region */
+ damageRect.setGeometry (damageRect.x () -
+ (optionGetStrokeWidth () / 2),
+ damageRect.y () -
+ (optionGetStrokeWidth () / 2),
+ damageRect.width () +
+ optionGetStrokeWidth () + 1,
+ damageRect.height () +
+ optionGetStrokeWidth () + 1);
+
+ cScreen->damageRegion (damageRect);
+ cScreen->damageRegion (lastRect);
+
+ lastRect = damageRect;
+ }
+
+ annoLastPointerX = xRoot;
+ annoLastPointerY = yRoot;
+
+ gScreen->glPaintOutputSetEnabled (this, true);
+ }
+}
+
+void
+AnnoScreen::handleEvent (XEvent *event)
+{
+ switch (event->type) {
+ case MotionNotify:
+ handleMotionEvent (pointerX, pointerY);
+ case EnterNotify:
+ case LeaveNotify:
+ handleMotionEvent (pointerX, pointerY);
+ default:
+ if (event->type == cScreen->damageEvent () + XDamageNotify)
+ {
+ XDamageNotifyEvent *de = (XDamageNotifyEvent *) event;
+ if (pixmap == de->drawable)
+ cScreen->damageRegion (CompRegion (CompRect (de->area)));
+ }
+ break;
+ }
+
+ screen->handleEvent (event);
+}
+
+void
+AnnoScreen::postLoad ()
+{
+ if (content)
+ {
+ cairoContext ();
+
+ gScreen->glPaintOutputSetEnabled (this, true);
+ }
+}
+
+AnnoScreen::AnnoScreen (CompScreen *screen) :
+ PluginClassHandler <AnnoScreen, CompScreen> (screen),
+ PluginStateWriter <AnnoScreen> (this, screen->root ()),
+ cScreen (CompositeScreen::get (screen)),
+ gScreen (GLScreen::get (screen)),
+ grabIndex (0),
+ pixmap (None),
+ surface (NULL),
+ cairo (NULL),
+ content (false),
+ damage (None)
+{
+ ScreenInterface::setHandler (screen, false);
+ GLScreenInterface::setHandler (gScreen, false);
+
+ optionSetDrawInitiate
+ (boost::bind (&AnnoScreen::draw, this, _1, _2, _3));
+ optionSetEraseButtonInitiate
+ (boost::bind (&AnnoScreen::initiateErase, this, _1, _2, _3));
+ optionSetEraseButtonTerminate
+ (boost::bind (&AnnoScreen::terminate, this, _1, _2, _3));
+ optionSetInitiateFreeDrawButtonInitiate
+ (boost::bind (&AnnoScreen::initiateFreeDraw, this, _1, _2, _3));
+ optionSetInitiateFreeDrawButtonTerminate
+ (boost::bind (&AnnoScreen::terminate, this, _1, _2, _3));
+ optionSetInitiateLineButtonInitiate
+ (boost::bind (&AnnoScreen::initiateLine, this, _1, _2, _3));
+ optionSetInitiateLineButtonTerminate
+ (boost::bind (&AnnoScreen::terminate, this, _1, _2, _3));
+ optionSetInitiateRectangleButtonInitiate
+ (boost::bind (&AnnoScreen::initiateRectangle, this, _1, _2, _3));
+ optionSetInitiateRectangleButtonTerminate
+ (boost::bind (&AnnoScreen::terminate, this, _1, _2, _3));
+ optionSetInitiateEllipseButtonInitiate
+ (boost::bind (&AnnoScreen::initiateEllipse, this, _1, _2, _3));
+ optionSetInitiateEllipseButtonTerminate
+ (boost::bind (&AnnoScreen::terminate, this, _1, _2, _3));
+ optionSetClearKeyInitiate
+ (boost::bind (&AnnoScreen::clear, this, _1, _2, _3));
+ drawMode = NoMode;
+}
+
+AnnoScreen::~AnnoScreen ()
+{
+ writeSerializedData ();
+
+ if (cairo)
+ cairo_destroy (cairo);
+ if (surface)
+ cairo_surface_destroy (surface);
+ if (pixmap)
+ XFreePixmap (screen->dpy (), pixmap);
+ if (damage)
+ XDamageDestroy (screen->dpy (), damage);
+}
+
+bool
+AnnoPluginVTable::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/plugins/annotate/src/annotate.h b/plugins/annotate/src/annotate.h
new file mode 100644
index 0000000..4ae2b6a
--- /dev/null
+++ b/plugins/annotate/src/annotate.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright © 2006 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <cmath>
+#include <cairo-xlib-xrender.h>
+
+#include <core/core.h>
+#include <core/serialization.h>
+#include <opengl/opengl.h>
+#include <composite/composite.h>
+
+#include "annotate_options.h"
+
+static int annoLastPointerX = 0;
+static int annoLastPointerY = 0;
+static int initialPointerX = 0;
+static int initialPointerY = 0;
+
+typedef struct _Ellipse
+{
+ CompPoint center;
+ int radiusX;
+ int radiusY;
+} Ellipse;
+
+enum DrawMode
+{
+ NoMode = 0,
+ EraseMode,
+ FreeDrawMode,
+ LineMode,
+ RectangleMode,
+ EllipseMode,
+ TextMode
+};
+
+class AnnoScreen :
+ public PluginClassHandler <AnnoScreen, CompScreen>,
+ public PluginStateWriter <AnnoScreen>,
+ public ScreenInterface,
+ public GLScreenInterface,
+ public AnnotateOptions
+{
+ public:
+ AnnoScreen (CompScreen *screen);
+ ~AnnoScreen ();
+
+ CompositeScreen *cScreen;
+ GLScreen *gScreen;
+
+ CompScreen::GrabHandle grabIndex;
+
+ Pixmap pixmap;
+ GLTexture::List texture;
+ cairo_surface_t *surface;
+ cairo_t *cairo;
+ CompString cairoBuffer; // used for serialization
+ bool content;
+ Damage damage;
+
+ CompRect rectangle, lastRect;
+ DrawMode drawMode;
+
+ CompPoint lineVector;
+ Ellipse ellipse;
+
+ template <class Archive>
+ void serialize (Archive & ar, const unsigned int count)
+ {
+ /* FIXME:
+ * cairo_surface_get_image_data is broken or something
+ * so serializing cairo bits is next to impossible at the moment
+ *
+ * ar & cairoBuffer;
+ * ar & content;
+ */
+ }
+
+ void postLoad ();
+
+ void handleEvent (XEvent *);
+
+ bool glPaintOutput (const GLScreenPaintAttrib &,
+ const GLMatrix &, const CompRegion &,
+ CompOutput *, unsigned int);
+
+ void
+ cairoClear (cairo_t *cr);
+
+ cairo_t *
+ cairoContext ();
+
+ void
+ setSourceColor (cairo_t *cr,
+ unsigned short *color);
+
+ void
+ drawLine (double x1,
+ double y1,
+ double x2,
+ double y2,
+ double width,
+ unsigned short *color);
+
+ void
+ drawRectangle (double x,
+ double y,
+ double w,
+ double h,
+ unsigned short *fillColor,
+ unsigned short *strokeColor,
+ double strokeWidth);
+
+ void
+ drawEllipse (double xc,
+ double yc,
+ double radiusX,
+ double radiusY,
+ unsigned short *fillColor,
+ unsigned short *strokeColor,
+ double strokeWidth);
+
+ void
+ drawText (double x,
+ double y,
+ const char *text,
+ const char *fontFamily,
+ double fontSize,
+ cairo_font_slant_t fontSlant,
+ cairo_font_weight_t fontWeight,
+ unsigned short *fillColor,
+ unsigned short *strokeColor,
+ double strokeWidth);
+
+/* Actions */
+
+ bool
+ draw (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options);
+
+ bool
+ terminate (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options);
+
+ bool
+ initiateErase (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options);
+
+ bool
+ initiateFreeDraw (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options);
+
+ bool
+ initiateLine (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options);
+
+ bool
+ initiateRectangle (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options);
+
+ bool
+ initiateEllipse (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options);
+
+ bool
+ clear (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector& options);
+
+ void
+ handleMotionEvent (int xRoot,
+ int yRoot);
+
+};
+
+#define ANNO_SCREEN(s) \
+ AnnoScreen *as = get (s);
+
+class AnnoPluginVTable :
+ public CompPlugin::VTableForScreen <AnnoScreen>
+{
+ public:
+ bool init ();
+};
diff --git a/plugins/blur/CMakeLists.txt b/plugins/blur/CMakeLists.txt
new file mode 100644
index 0000000..d625cdf
--- /dev/null
+++ b/plugins/blur/CMakeLists.txt
@@ -0,0 +1,16 @@
+find_package (Compiz REQUIRED)
+
+include (CompizPlugin)
+
+find_package (OpenGL)
+
+if (OPENGL_GLU_FOUND)
+ compiz_plugin(blur PLUGINDEPS composite opengl LIBRARIES decoration ${OPENGL_glu_LIBRARY} INCDIRS ${OPENGL_INCLUDE_DIR})
+
+ if (COMPIZ_BUILD_WITH_RPATH)
+ set_target_properties (
+ blur PROPERTIES
+ INSTALL_RPATH "${COMPIZ_LIBDIR}"
+ )
+ endif (COMPIZ_BUILD_WITH_RPATH)
+endif ()
diff --git a/plugins/blur/blur.xml.in b/plugins/blur/blur.xml.in
new file mode 100644
index 0000000..b8af0b0
--- /dev/null
+++ b/plugins/blur/blur.xml.in
@@ -0,0 +1,112 @@
+<compiz>
+ <plugin name="blur" useBcop="true">
+ <_short>Blur Windows</_short>
+ <_long>Blur windows</_long>
+ <category>Effects</category>
+ <feature>blur</feature>
+ <deps>
+ <relation type="before">
+ <plugin>video</plugin>
+ </relation>
+ <relation type="after">
+ <plugin>decor</plugin>
+ </relation>
+ <requirement>
+ <plugin>opengl</plugin>
+ </requirement>
+ </deps>
+ <options>
+ <option name="pulse" type="bell">
+ <_short>Pulse</_short>
+ <_long>Pulse effect</_long>
+ </option>
+ <option name="blur_speed" type="float">
+ <_short>Blur Speed</_short>
+ <_long>Window blur speed</_long>
+ <default>3.5</default>
+ <min>0.1</min>
+ <max>10.0</max>
+ <precision>0.1</precision>
+ </option>
+ <option name="focus_blur_match" type="match">
+ <_short>Focus blur windows</_short>
+ <_long>Windows that should be affected by focus blur</_long>
+ <default>toolbar | menu | utility | normal | dialog | modaldialog</default>
+ </option>
+ <option name="focus_blur" type="bool">
+ <_short>Focus Blur</_short>
+ <_long>Blur windows that doesn't have focus</_long>
+ <default>false</default>
+ </option>
+ <option name="alpha_blur_match" type="match">
+ <_short>Alpha blur windows</_short>
+ <_long>Windows that should be use alpha blur by default</_long>
+ <default></default>
+ </option>
+ <option name="alpha_blur" type="bool">
+ <_short>Alpha Blur</_short>
+ <_long>Blur behind translucent parts of windows</_long>
+ <default>true</default>
+ </option>
+ <option name="filter" type="int">
+ <_short>Blur Filter</_short>
+ <_long>Filter method used for blurring</_long>
+ <default>0</default>
+ <min>0</min>
+ <max>2</max>
+ <desc>
+ <value>0</value>
+ <_name>4xBilinear</_name>
+ </desc>
+ <desc>
+ <value>1</value>
+ <_name>Gaussian</_name>
+ </desc>
+ <desc>
+ <value>2</value>
+ <_name>Mipmap</_name>
+ </desc>
+ </option>
+ <option name="gaussian_radius" type="int">
+ <_short>Gaussian Radius</_short>
+ <_long>Gaussian radius</_long>
+ <default>3</default>
+ <min>1</min>
+ <max>15</max>
+ </option>
+ <option name="gaussian_strength" type="float">
+ <_short>Gaussian Strength</_short>
+ <_long>Gaussian strength</_long>
+ <default>1.0</default>
+ <min>0.0</min>
+ <max>1.0</max>
+ <precision>0.1</precision>
+ </option>
+ <option name="mipmap_lod" type="float">
+ <_short>Mipmap LOD</_short>
+ <_long>Mipmap level-of-detail</_long>
+ <default>2.5</default>
+ <min>0.1</min>
+ <max>5.0</max>
+ <precision>0.1</precision>
+ </option>
+ <option name="saturation" type="int">
+ <_short>Blur Saturation</_short>
+ <_long>Blur saturation</_long>
+ <default>100</default>
+ <min>0</min>
+ <max>100</max>
+ </option>
+ <option name="occlusion" type="bool">
+ <_short>Blur Occlusion</_short>
+ <_long>Disable blurring of screen regions obscured by other windows.</_long>
+ <default>true</default>
+ </option>
+ <option name="independent_tex" type="bool">
+ <_short>Independent texture fetch</_short>
+ <_long>Use the available texture units to do as many as possible independent texture fetches.</_long>
+ <default>false</default>
+ </option>
+ </options>
+ </plugin>
+</compiz>
diff --git a/plugins/blur/src/blur.cpp b/plugins/blur/src/blur.cpp
new file mode 100644
index 0000000..555b7d0
--- /dev/null
+++ b/plugins/blur/src/blur.cpp
@@ -0,0 +1,2335 @@
+/*
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <blur.h>
+
+COMPIZ_PLUGIN_20090315 (blur, BlurPluginVTable)
+
+/* pascal triangle based kernel generator */
+static int
+blurCreateGaussianLinearKernel (int radius,
+ float strength,
+ float *amp,
+ float *pos,
+ int *optSize)
+{
+ float factor = 0.5f + (strength / 2.0f);
+ float buffer1[BLUR_GAUSSIAN_RADIUS_MAX * 3];
+ float buffer2[BLUR_GAUSSIAN_RADIUS_MAX * 3];
+ float *ar1 = buffer1;
+ float *ar2 = buffer2;
+ float *tmp;
+ float sum = 0;
+ int size = (radius * 2) + 1;
+ int mySize = ceil (radius / 2.0f);
+ int i, j;
+
+ ar1[0] = 1.0;
+ ar1[1] = 1.0;
+
+ for (i = 3; i <= size; i++)
+ {
+ ar2[0] = 1;
+
+ for (j = 1; j < i - 1; j++)
+ ar2[j] = (ar1[j - 1] + ar1[j]) * factor;
+
+ ar2[i - 1] = 1;
+
+ tmp = ar1;
+ ar1 = ar2;
+ ar2 = tmp;
+ }
+
+ /* normalize */
+ for (i = 0; i < size; i++)
+ sum += ar1[i];
+
+ if (sum != 0.0f)
+ sum = 1.0f / sum;
+
+ for (i = 0; i < size; i++)
+ ar1[i] *= sum;
+
+ i = 0;
+ j = 0;
+
+ if (radius & 1)
+ {
+ pos[i] = radius;
+ amp[i] = ar1[i];
+ i = 1;
+ j = 1;
+ }
+
+ for (; i < mySize; i++)
+ {
+ pos[i] = radius - j;
+ pos[i] -= ar1[j + 1] / (ar1[j] + ar1[j + 1]);
+ amp[i] = ar1[j] + ar1[j + 1];
+
+ j += 2;
+ }
+
+ pos[mySize] = 0.0;
+ amp[mySize] = ar1[radius];
+
+ *optSize = mySize;
+
+ return radius;
+}
+
+void
+BlurScreen::updateFilterRadius ()
+{
+ switch (optionGetFilter ()) {
+ case BlurOptions::Filter4xbilinear:
+ filterRadius = 2;
+ break;
+ case BlurOptions::FilterGaussian: {
+ int radius = optionGetGaussianRadius ();
+ float strength = optionGetGaussianStrength ();
+
+ blurCreateGaussianLinearKernel (radius, strength, amp, pos,
+ &numTexop);
+
+ filterRadius = radius;
+ } break;
+ case BlurOptions::FilterMipmap: {
+ float lod = optionGetMipmapLod ();
+
+ filterRadius = powf (2.0f, ceilf (lod));
+ } break;
+ }
+}
+
+
+void
+BlurScreen::blurReset ()
+{
+ updateFilterRadius ();
+
+ foreach (BlurFunction &bf, srcBlurFunctions)
+ GLFragment::destroyFragmentFunction (bf.id);
+ srcBlurFunctions.clear ();
+ foreach (BlurFunction &bf, dstBlurFunctions)
+ GLFragment::destroyFragmentFunction (bf.id);
+ dstBlurFunctions.clear ();
+
+ width = height = 0;
+
+ if (program)
+ {
+ GL::deletePrograms (1, &program);
+ program = 0;
+ }
+}
+
+static CompRegion
+regionFromBoxes (std::vector<BlurBox> boxes,
+ int width,
+ int height)
+{
+ CompRegion region;
+ int x1, x2, y1, y2;
+
+ foreach (BlurBox &box, boxes)
+ {
+ decor_apply_gravity (box.p1.gravity, box.p1.x, box.p1.y,
+ width, height,
+ &x1, &y1);
+
+
+ decor_apply_gravity (box.p2.gravity, box.p2.x, box.p2.y,
+ width, height,
+ &x2, &y2);
+
+ if (x2 > x1 && y2 > y1)
+ region += CompRect (x1, y1, x2 - x1, y2 - y1);
+ }
+
+ return region;
+}
+
+void
+BlurWindow::updateRegion ()
+{
+ CompRegion region;
+
+ if (state[BLUR_STATE_DECOR].threshold)
+ {
+ region += CompRect (-window->output ().left,
+ -window->output ().top,
+ window->width () + window->output ().right,
+ window->height () + window->output ().bottom);
+
+ region -= CompRect (0, 0, window->width (), window->height ());
+
+ state[BLUR_STATE_DECOR].clipped = false;
+
+ if (!state[BLUR_STATE_DECOR].box.empty ())
+ {
+ CompRegion q = regionFromBoxes (state[BLUR_STATE_DECOR].box,
+ window->width (),
+ window->height ());
+ if (!q.isEmpty ())
+ {
+ q &= region;
+ if (q != region)
+ {
+ region = q;
+ state[BLUR_STATE_DECOR].clipped = true;
+ }
+ }
+ }
+ }
+
+ if (state[BLUR_STATE_CLIENT].threshold)
+ {
+ CompRegion r (0, 0, window->width (), window->height ());
+
+ state[BLUR_STATE_CLIENT].clipped = false;
+
+ if (!state[BLUR_STATE_CLIENT].box.empty ())
+ {
+ CompRegion q = regionFromBoxes (state[BLUR_STATE_CLIENT].box,
+ window->width (),
+ window->height ());
+ if (!q.isEmpty ())
+ {
+ q &= r;
+
+ if (q != r)
+ state[BLUR_STATE_CLIENT].clipped = true;
+
+ region += q;
+ }
+ }
+ else
+ {
+ region += r;
+ }
+ }
+
+ this->region = region;
+ if (!region.isEmpty ())
+ this->region.translate (window->x (), window->y ());
+}
+
+void
+BlurWindow::setBlur (int state,
+ int threshold,
+ std::vector<BlurBox> box)
+{
+
+ this->state[state].threshold = threshold;
+ this->state[state].box = box;
+
+ updateRegion ();
+
+ cWindow->addDamage ();
+}
+
+void
+BlurWindow::updateAlphaMatch ()
+{
+ if (!propSet[BLUR_STATE_CLIENT])
+ {
+ CompMatch *match;
+
+ match = &bScreen->optionGetAlphaBlurMatch ();
+ if (match->evaluate (window))
+ {
+ if (!state[BLUR_STATE_CLIENT].threshold)
+ setBlur (BLUR_STATE_CLIENT, 4, std::vector<BlurBox> ());
+ }
+ else
+ {
+ if (state[BLUR_STATE_CLIENT].threshold)
+ setBlur (BLUR_STATE_CLIENT, 0, std::vector<BlurBox> ());
+ }
+ }
+}
+
+void
+BlurWindow::updateMatch ()
+{
+ CompMatch *match;
+ bool focus;
+
+ updateAlphaMatch ();
+
+ match = &bScreen->optionGetFocusBlurMatch ();
+
+ focus = GL::fragmentProgram && match->evaluate (window);
+ if (focus != focusBlur)
+ {
+ focusBlur = focus;
+ cWindow->addDamage ();
+ }
+}
+
+
+
+void
+BlurWindow::update (int state)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *propData;
+ int threshold = 0;
+ std::vector<BlurBox> boxes;
+
+ result = XGetWindowProperty (screen->dpy (), window->id (),
+ bScreen->blurAtom[state], 0L, 8192L, false,
+ XA_INTEGER, &actual, &format,
+ &n, &left, &propData);
+
+ if (result == Success && n && propData)
+ {
+ propSet[state] = true;
+
+ if (n >= 2)
+ {
+ long *data = (long *) propData;
+ BlurBox box;
+
+ threshold = data[0];
+
+ if ((n - 2) / 6)
+ {
+ unsigned int i;
+
+ data += 2;
+
+ for (i = 0; i < (n - 2) / 6; i++)
+ {
+ box.p1.gravity = *data++;
+ box.p1.x = *data++;
+ box.p1.y = *data++;
+ box.p2.gravity = *data++;
+ box.p2.x = *data++;
+ box.p2.y = *data++;
+
+ boxes.push_back (box);
+ }
+
+ }
+ }
+
+ XFree (propData);
+ }
+ else
+ {
+ propSet[state] = false;
+ }
+
+ setBlur (state, threshold, boxes);
+
+ updateAlphaMatch ();
+}
+
+void
+BlurScreen::preparePaint (int msSinceLastPaint)
+{
+ if (moreBlur)
+ {
+ int steps;
+ bool focus = optionGetFocusBlur ();
+ bool focusBlur;
+
+ steps = (msSinceLastPaint * 0xffff) / blurTime;
+ if (steps < 12)
+ steps = 12;
+
+ moreBlur = false;
+
+ foreach (CompWindow *w, screen->windows ())
+ {
+ BLUR_WINDOW (w);
+
+ focusBlur = bw->focusBlur && focus;
+
+ if (!bw->pulse &&
+ (!focusBlur || w->id () == screen->activeWindow ()))
+ {
+ if (bw->blur)
+ {
+ bw->blur -= steps;
+ if (bw->blur > 0)
+ moreBlur = true;
+ else
+ bw->blur = 0;
+ }
+ }
+ else
+ {
+ if (bw->blur < 0xffff)
+ {
+ if (bw->pulse)
+ {
+ bw->blur += steps * 2;
+
+ if (bw->blur >= 0xffff)
+ {
+ bw->blur = 0xffff - 1;
+ bw->pulse = false;
+ }
+
+ moreBlur = true;
+ }
+ else
+ {
+ bw->blur += steps;
+ if (bw->blur < 0xffff)
+ moreBlur = true;
+ else
+ bw->blur = 0xffff;
+ }
+ }
+ }
+ }
+ }
+
+ cScreen->preparePaint (msSinceLastPaint);
+
+ if (cScreen->damageMask () & COMPOSITE_SCREEN_DAMAGE_REGION_MASK)
+ {
+ /* walk from bottom to top and expand damage */
+ if (alphaBlur)
+ {
+ int x1, y1, x2, y2;
+ int count = 0;
+ CompRegion damage (cScreen->currentDamage ());
+
+ foreach (CompWindow *w, screen->windows ())
+ {
+ BLUR_WINDOW (w);
+
+ if (!w->isViewable () || !CompositeWindow::get (w)->damaged ())
+ continue;
+
+ if (!bw->region.isEmpty ())
+ {
+ CompRect r = bw->region.boundingRect ();
+ CompRect d = damage.boundingRect ();
+ x1 = r.x1 () - filterRadius;
+ y1 = r.y1 () - filterRadius;
+ x2 = r.x2 () + filterRadius;
+ y2 = r.y2 () + filterRadius;
+
+ if (x1 < d.x2 () &&
+ y1 < d.y2 () &&
+ x2 > d.x1 () &&
+ y2 > d.y1 ())
+ {
+ damage.shrink (-filterRadius, -filterRadius);
+ count++;
+ }
+ }
+ }
+
+ if (count)
+ cScreen->damageRegion (damage);
+
+ this->count = count;
+ }
+ }
+}
+
+bool
+BlurScreen::glPaintOutput (const GLScreenPaintAttrib &sAttrib,
+ const GLMatrix &transform, const CompRegion &region,
+ CompOutput *output, unsigned int mask)
+{
+ bool status;
+
+ if (alphaBlur)
+ {
+ stencilBox = region.boundingRect ();
+ this->region = region;
+
+ if (mask & PAINT_SCREEN_REGION_MASK)
+ {
+ /* we need to redraw more than the screen region being updated */
+ if (count)
+ {
+ this->region.shrink (-filterRadius * 2, -filterRadius * 2);
+
+ this->region &= screen->region ();
+ }
+ }
+ }
+
+ if (!blurOcclusion)
+ {
+ occlusion = CompRegion ();
+
+ foreach (CompWindow *w, screen->windows ())
+ BlurWindow::get (w)->clip = CompRegion ();
+ }
+
+ this->output = output;
+
+ if (alphaBlur)
+ status = gScreen->glPaintOutput (sAttrib, transform, this->region, output, mask);
+ else
+ status = gScreen->glPaintOutput (sAttrib, transform, region, output, mask);
+
+ return status;
+}
+
+void
+BlurScreen::glPaintTransformedOutput (const GLScreenPaintAttrib &sAttrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output, unsigned int mask)
+{
+ if (!blurOcclusion)
+ {
+ occlusion = CompRegion ();
+
+ foreach (CompWindow *w, screen->windows ())
+ BlurWindow::get (w)->clip = CompRegion ();
+ }
+
+ gScreen->glPaintTransformedOutput (sAttrib, transform, region, output, mask);
+}
+
+void
+BlurScreen::donePaint ()
+{
+ if (moreBlur)
+ {
+ foreach (CompWindow *w, screen->windows ())
+ {
+ BLUR_WINDOW (w);
+
+ if (bw->blur > 0 && bw->blur < 0xffff)
+ bw->cWindow->addDamage ();
+ }
+ }
+
+ cScreen->donePaint ();
+}
+
+bool
+BlurWindow::glPaint (const GLWindowPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region, unsigned int mask)
+{
+
+ bool status = gWindow->glPaint (attrib, transform, region, mask);
+
+ if (!bScreen->blurOcclusion &&
+ (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK))
+ {
+ clip = bScreen->occlusion;
+
+ if (!(gWindow->lastMask () & PAINT_WINDOW_NO_CORE_INSTANCE_MASK) &&
+ !(gWindow->lastMask () & PAINT_WINDOW_TRANSFORMED_MASK) &&
+ !this->region.isEmpty ())
+ bScreen->occlusion += this->region;
+ }
+
+ return status;
+}
+
+GLFragment::FunctionId
+BlurScreen::getSrcBlurFragmentFunction (GLTexture *texture,
+ int param)
+{
+ GLFragment::FunctionData data;
+ BlurFunction function;
+ int target;
+
+ if (texture->target () == GL_TEXTURE_2D)
+ target = COMP_FETCH_TARGET_2D;
+ else
+ target = COMP_FETCH_TARGET_RECT;
+
+ foreach (BlurFunction &bf, srcBlurFunctions)
+ if (bf.param == param && bf.target == target)
+ return bf.id;
+
+ if (data.status ())
+ {
+ static const char *temp[] = { "offset0", "offset1", "sum" };
+ unsigned int i;
+
+ for (i = 0; i < sizeof (temp) / sizeof (temp[0]); i++)
+ data.addTempHeaderOp (temp[i]);
+
+ data.addDataOp (
+ "MUL offset0, program.env[%d].xyzw, { 1.0, 1.0, 0.0, 0.0 };"
+ "MUL offset1, program.env[%d].zwww, { 1.0, 1.0, 0.0, 0.0 };",
+ param, param);
+
+
+ switch (optionGetFilter ()) {
+ case BlurOptions::Filter4xbilinear:
+ default:
+ data.addFetchOp ("output", "offset0", target);
+ data.addDataOp ("MUL sum, output, 0.25;");
+ data.addFetchOp ("output", "-offset0", target);
+ data.addDataOp ("MAD sum, output, 0.25, sum;");
+ data.addFetchOp ("output", "offset1", target);
+ data.addDataOp ("MAD sum, output, 0.25, sum;");
+ data.addFetchOp ("output", "-offset1", target);
+ data.addDataOp ("MAD output, output, 0.25, sum;");
+ break;
+ }
+
+ if (!data.status ())
+ return 0;
+
+ function.id = data.createFragmentFunction ("blur");
+ function.target = target;
+ function.param = param;
+ function.unit = 0;
+
+ srcBlurFunctions.push_back (function);
+
+ return function.id;
+ }
+
+ return 0;
+}
+
+GLFragment::FunctionId
+BlurScreen::getDstBlurFragmentFunction (GLTexture *texture,
+ int param,
+ int unit,
+ int numITC,
+ int startTC)
+{
+ BlurFunction function;
+ GLFragment::FunctionData data;
+ int target;
+ char *targetString;
+
+ if (texture->target () == GL_TEXTURE_2D)
+ {
+ target = COMP_FETCH_TARGET_2D;
+ targetString = (char *) "2D";
+ }
+ else
+ {
+ target = COMP_FETCH_TARGET_RECT;
+ targetString = (char *) "RECT";
+ }
+
+ foreach (BlurFunction &function, dstBlurFunctions)
+ if (function.param == param &&
+ function.target == target &&
+ function.unit == unit &&
+ function.numITC == numITC &&
+ function.startTC == startTC)
+ return function.id;
+
+ if (data.status ())
+ {
+ static const char *temp[] = { "fCoord", "mask", "sum", "dst" };
+ int i, j;
+ char str[1024];
+ int saturation = optionGetSaturation ();
+ int numIndirect;
+ int numIndirectOp;
+ int base, end, ITCbase;
+
+ for (i = 0; (unsigned int) i < sizeof (temp) / sizeof (temp[0]); i++)
+ data.addTempHeaderOp (temp[i]);
+
+ if (saturation < 100)
+ data.addTempHeaderOp ("sat");
+
+ switch (optionGetFilter ()) {
+ case BlurOptions::Filter4xbilinear: {
+ static const char *filterTemp[] = {
+ "t0", "t1", "t2", "t3",
+ "s0", "s1", "s2", "s3"
+ };
+
+ for (i = 0;
+ (unsigned int) i < sizeof (filterTemp) / sizeof (filterTemp[0]);
+ i++)
+ data.addTempHeaderOp (filterTemp[i]);
+
+ data.addFetchOp ("output", NULL, target);
+ data.addColorOp ("output", "output");
+
+ data.addDataOp (
+ "MUL fCoord, fragment.position, program.env[%d];",
+ param);
+
+
+ data.addDataOp (
+ "ADD t0, fCoord, program.env[%d];"
+ "TEX s0, t0, texture[%d], %s;"
+
+ "SUB t1, fCoord, program.env[%d];"
+ "TEX s1, t1, texture[%d], %s;"
+
+ "MAD t2, program.env[%d], { -1.0, 1.0, 0.0, 0.0 }, fCoord;"
+ "TEX s2, t2, texture[%d], %s;"
+
+ "MAD t3, program.env[%d], { 1.0, -1.0, 0.0, 0.0 }, fCoord;"
+ "TEX s3, t3, texture[%d], %s;"
+
+ "MUL_SAT mask, output.a, program.env[%d];"
+
+ "MUL sum, s0, 0.25;"
+ "MAD sum, s1, 0.25, sum;"
+ "MAD sum, s2, 0.25, sum;"
+ "MAD sum, s3, 0.25, sum;",
+
+ param + 2, unit, targetString,
+ param + 2, unit, targetString,
+ param + 2, unit, targetString,
+ param + 2, unit, targetString,
+ param + 1);
+
+ } break;
+ case BlurOptions::FilterGaussian: {
+
+ /* try to use only half of the available temporaries to keep
+ other plugins working */
+ if ((maxTemp / 2) - 4 >
+ (numTexop + (numTexop - numITC)) * 2)
+ {
+ numIndirect = 1;
+ numIndirectOp = numTexop;
+ }
+ else
+ {
+ i = MAX (((maxTemp / 2) - 4) / 4, 1);
+ numIndirect = ceil ((float)numTexop / (float)i);
+ numIndirectOp = ceil ((float)numTexop / (float)numIndirect);
+ }
+
+ /* we need to define all coordinate temporaries if we have
+ multiple indirection steps */
+ j = (numIndirect > 1) ? 0 : numITC;
+
+ for (i = 0; i < numIndirectOp * 2; i++)
+ {
+ snprintf (str, 1024, "pix_%d", i);
+ data.addTempHeaderOp (str);
+ }
+
+ for (i = j * 2; i < numIndirectOp * 2; i++)
+ {
+ snprintf (str, 1024, "coord_%d", i);
+ data.addTempHeaderOp (str);
+ }
+
+ data.addFetchOp ("output", NULL, target);
+ data.addColorOp ("output", "output");
+
+ data.addDataOp (
+ "MUL fCoord, fragment.position, program.env[%d];",
+ param);
+
+
+ data.addDataOp ("TEX sum, fCoord, texture[%d], %s;",
+ unit + 1, targetString);
+
+
+ data.addDataOp ("MUL_SAT mask, output.a, program.env[%d];"
+ "MUL sum, sum, %f;",
+ param + 1, amp[numTexop]);
+
+ for (j = 0; j < numIndirect; j++)
+ {
+ base = j * numIndirectOp;
+ end = MIN ((j + 1) * numIndirectOp, numTexop) - base;
+
+ ITCbase = MAX (numITC - base, 0);
+
+ for (i = ITCbase; i < end; i++)
+ {
+ data.addDataOp (
+ "ADD coord_%d, fCoord, {0.0, %g, 0.0, 0.0};"
+ "SUB coord_%d, fCoord, {0.0, %g, 0.0, 0.0};",
+ i * 2, pos[base + i] * ty,
+ (i * 2) + 1, pos[base + i] * ty);
+ }
+
+ for (i = 0; i < ITCbase; i++)
+ {
+ data.addDataOp (
+ "TXP pix_%d, fragment.texcoord[%d], texture[%d], %s;"
+ "TXP pix_%d, fragment.texcoord[%d], texture[%d], %s;",
+ i * 2, startTC + ((i + base) * 2),
+ unit + 1, targetString,
+ (i * 2) + 1, startTC + 1 + ((i + base) * 2),
+ unit + 1, targetString);
+ }
+
+ for (i = ITCbase; i < end; i++)
+ {
+ data.addDataOp (
+ "TEX pix_%d, coord_%d, texture[%d], %s;"
+ "TEX pix_%d, coord_%d, texture[%d], %s;",
+ i * 2, i * 2,
+ unit + 1, targetString,
+ (i * 2) + 1, (i * 2) + 1,
+ unit + 1, targetString);
+ }
+
+ for (i = 0; i < end * 2; i++)
+ {
+ data.addDataOp (
+ "MAD sum, pix_%d, %f, sum;",
+ i, amp[base + (i / 2)]);
+ }
+ }
+
+ } break;
+ case BlurOptions::FilterMipmap:
+ data.addFetchOp ("output", NULL, target);
+ data.addColorOp ("output", "output");
+
+ data.addDataOp (
+ "MUL fCoord, fragment.position, program.env[%d].xyzz;"
+ "MOV fCoord.w, program.env[%d].w;"
+ "TXB sum, fCoord, texture[%d], %s;"
+ "MUL_SAT mask, output.a, program.env[%d];",
+ param, param, unit, targetString,
+ param + 1);
+
+ break;
+ }
+
+ if (saturation < 100)
+ {
+ data.addDataOp (
+ "MUL sat, sum, { 1.0, 1.0, 1.0, 0.0 };"
+ "DP3 sat, sat, { %f, %f, %f, %f };"
+ "LRP sum.xyz, %f, sum, sat;",
+ RED_SATURATION_WEIGHT, GREEN_SATURATION_WEIGHT,
+ BLUE_SATURATION_WEIGHT, 0.0f, saturation / 100.0f);
+ }
+
+ data.addDataOp (
+ "MAD dst, mask, -output.a, mask;"
+ "MAD output.rgb, sum, dst.a, output;"
+ "ADD output.a, output.a, dst.a;");
+
+ if (!data.status ())
+ {
+ return 0;
+ }
+
+
+
+ function.id = data.createFragmentFunction ("blur");
+ function.target = target;
+ function.param = param;
+ function.unit = unit;
+ function.numITC = numITC;
+ function.startTC = startTC;
+
+ dstBlurFunctions.push_back (function);
+
+ return function.id;
+ }
+
+ return 0;
+}
+
+bool
+BlurScreen::projectVertices (CompOutput *output,
+ const GLMatrix &transform,
+ const float *object,
+ float *scr,
+ int n)
+{
+ GLdouble dProjection[16];
+ GLdouble dModel[16];
+ GLint viewport[4];
+ double x, y, z;
+ int i;
+
+ viewport[0] = output->x1 ();
+ viewport[1] = screen->height () - output->y2 ();
+ viewport[2] = output->width ();
+ viewport[3] = output->height ();
+
+ for (i = 0; i < 16; i++)
+ {
+ dModel[i] = transform.getMatrix ()[i];
+ dProjection[i] = gScreen->projectionMatrix ()[i];
+ }
+
+ while (n--)
+ {
+ if (!gluProject (object[0], object[1], object[2],
+ dModel, dProjection, viewport,
+ &x, &y, &z))
+ return false;
+
+ scr[0] = x;
+ scr[1] = y;
+
+ object += 3;
+ scr += 2;
+ }
+
+ return true;
+}
+
+bool
+BlurScreen::loadFragmentProgram (GLuint *program,
+ const char *string)
+{
+ GLint errorPos;
+
+ /* clear errors */
+ glGetError ();
+
+ if (!*program)
+ (*GL::genPrograms) (1, program);
+
+ (*GL::bindProgram) (GL_FRAGMENT_PROGRAM_ARB, *program);
+ (*GL::programString) (GL_FRAGMENT_PROGRAM_ARB,
+ GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen (string), string);
+
+ glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
+ if (glGetError () != GL_NO_ERROR || errorPos != -1)
+ {
+ compLogMessage ("blur", CompLogLevelError,
+ "Failed to load blur program %s", string);
+
+ (*GL::deletePrograms) (1, program);
+ *program = 0;
+
+ return false;
+ }
+
+ return true;
+}
+
+bool
+BlurScreen::loadFilterProgram (int numITC)
+{
+ char buffer[4096];
+ char *targetString;
+ char *str = buffer;
+ int i, j;
+ int numIndirect;
+ int numIndirectOp;
+ int base, end, ITCbase;
+
+ if (target == GL_TEXTURE_2D)
+ targetString = (char *) "2D";
+ else
+ targetString = (char *) "RECT";
+
+ str += sprintf (str,
+ "!!ARBfp1.0"
+ "ATTRIB texcoord = fragment.texcoord[0];"
+ "TEMP sum;");
+
+ if (maxTemp - 1 > (numTexop + (numTexop - numITC)) * 2)
+ {
+ numIndirect = 1;
+ numIndirectOp = numTexop;
+ }
+ else
+ {
+ i = (maxTemp - 1) / 4;
+ numIndirect = ceil ((float)numTexop / (float)i);
+ numIndirectOp = ceil ((float)numTexop / (float)numIndirect);
+ }
+
+ /* we need to define all coordinate temporaries if we have
+ multiple indirection steps */
+ j = (numIndirect > 1) ? 0 : numITC;
+
+ for (i = 0; i < numIndirectOp; i++)
+ str += sprintf (str,"TEMP pix_%d, pix_%d;", i * 2, (i * 2) + 1);
+
+ for (i = j; i < numIndirectOp; i++)
+ str += sprintf (str,"TEMP coord_%d, coord_%d;", i * 2, (i * 2) + 1);
+
+ str += sprintf (str,
+ "TEX sum, texcoord, texture[0], %s;",
+ targetString);
+
+ str += sprintf (str,
+ "MUL sum, sum, %f;",
+ amp[numTexop]);
+
+ for (j = 0; j < numIndirect; j++)
+ {
+ base = j * numIndirectOp;
+ end = MIN ((j + 1) * numIndirectOp, numTexop) - base;
+
+ ITCbase = MAX (numITC - base, 0);
+
+ for (i = ITCbase; i < end; i++)
+ str += sprintf (str,
+ "ADD coord_%d, texcoord, {%g, 0.0, 0.0, 0.0};"
+ "SUB coord_%d, texcoord, {%g, 0.0, 0.0, 0.0};",
+ i * 2, pos[base + i] * tx,
+ (i * 2) + 1, pos[base + i] * tx);
+
+ for (i = 0; i < ITCbase; i++)
+ str += sprintf (str,
+ "TEX pix_%d, fragment.texcoord[%d], texture[0], %s;"
+ "TEX pix_%d, fragment.texcoord[%d], texture[0], %s;",
+ i * 2, ((i + base) * 2) + 1, targetString,
+ (i * 2) + 1, ((i + base) * 2) + 2, targetString);
+
+ for (i = ITCbase; i < end; i++)
+ str += sprintf (str,
+ "TEX pix_%d, coord_%d, texture[0], %s;"
+ "TEX pix_%d, coord_%d, texture[0], %s;",
+ i * 2, i * 2, targetString,
+ (i * 2) + 1, (i * 2) + 1, targetString);
+
+ for (i = 0; i < end * 2; i++)
+ str += sprintf (str,
+ "MAD sum, pix_%d, %f, sum;",
+ i, amp[base + (i / 2)]);
+ }
+
+ str += sprintf (str,
+ "MOV result.color, sum;"
+ "END");
+
+ return loadFragmentProgram (&program, buffer);
+}
+
+bool
+BlurScreen::fboPrologue ()
+{
+ if (!fbo)
+ return false;
+
+ (*GL::bindFramebuffer) (GL_FRAMEBUFFER_EXT, fbo);
+
+ /* bind texture and check status the first time */
+ if (!fboStatus)
+ {
+ (*GL::framebufferTexture2D) (GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT0_EXT,
+ target, texture[1],
+ 0);
+
+ int currStatus = (*GL::checkFramebufferStatus) (GL_FRAMEBUFFER_EXT);
+ if (currStatus != GL_FRAMEBUFFER_COMPLETE_EXT)
+ {
+ compLogMessage ("blur", CompLogLevelError,
+ "Framebuffer incomplete");
+
+ (*GL::bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0);
+ (*GL::deleteFramebuffers) (1, &fbo);
+
+ fbo = 0;
+
+ return false;
+ }
+ else
+ fboStatus = true;
+ }
+
+ glPushAttrib (GL_VIEWPORT_BIT | GL_ENABLE_BIT);
+
+ glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
+ glReadBuffer (GL_COLOR_ATTACHMENT0_EXT);
+
+ glDisable (GL_CLIP_PLANE0);
+ glDisable (GL_CLIP_PLANE1);
+ glDisable (GL_CLIP_PLANE2);
+ glDisable (GL_CLIP_PLANE3);
+
+ glViewport (0, 0, width, height);
+ glMatrixMode (GL_PROJECTION);
+ glPushMatrix ();
+ glLoadIdentity ();
+ glOrtho (0.0, width, 0.0, height, -1.0, 1.0);
+ glMatrixMode (GL_MODELVIEW);
+ glPushMatrix ();
+ glLoadIdentity ();
+
+ return true;
+}
+
+void
+BlurScreen::fboEpilogue ()
+{
+ (*GL::bindFramebuffer) (GL_FRAMEBUFFER_EXT, 0);
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ glMatrixMode (GL_MODELVIEW);
+ glLoadIdentity ();
+ glDepthRange (0, 1);
+ glViewport (-1, -1, 2, 2);
+ glRasterPos2f (0, 0);
+
+ gScreen->resetRasterPos ();
+
+ glMatrixMode (GL_PROJECTION);
+ glPopMatrix ();
+ glMatrixMode (GL_MODELVIEW);
+ glPopMatrix ();
+
+ glDrawBuffer (GL_BACK);
+ glReadBuffer (GL_BACK);
+
+ glPopAttrib ();
+}
+
+bool
+BlurScreen::fboUpdate (BoxPtr pBox,
+ int nBox)
+{
+ int i, y, iTC = 0;
+ bool wasCulled = glIsEnabled (GL_CULL_FACE);
+
+ if (GL::maxTextureUnits && optionGetIndependentTex ())
+ iTC = MIN ((GL::maxTextureUnits - 1) / 2, numTexop);
+
+ if (!program)
+ if (!loadFilterProgram (iTC))
+ return false;
+
+ if (!fboPrologue ())
+ return false;
+
+ glDisable (GL_CULL_FACE);
+
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ glBindTexture (target, texture[0]);
+
+ glEnable (GL_FRAGMENT_PROGRAM_ARB);
+ (*GL::bindProgram) (GL_FRAGMENT_PROGRAM_ARB, program);
+
+ glBegin (GL_QUADS);
+
+ while (nBox--)
+ {
+ y = screen->height () - pBox->y2;
+
+ for (i = 0; i < iTC; i++)
+ {
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2),
+ tx * (pBox->x1 + pos[i]),
+ ty * y);
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2) + 1,
+ tx * (pBox->x1 - pos[i]),
+ ty * y);
+ }
+
+ glTexCoord2f (tx * pBox->x1, ty * y);
+ glVertex2i (pBox->x1, y);
+
+ for (i = 0; i < iTC; i++)
+ {
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2),
+ tx * (pBox->x2 + pos[i]),
+ ty * y);
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2) + 1,
+ tx * (pBox->x2 - pos[i]),
+ ty * y);
+ }
+
+ glTexCoord2f (tx * pBox->x2, ty * y);
+ glVertex2i (pBox->x2, y);
+
+ y = screen->height () - pBox->y1;
+
+ for (i = 0; i < iTC; i++)
+ {
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2),
+ tx * (pBox->x2 + pos[i]),
+ ty * y);
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2) + 1,
+ tx * (pBox->x2 - pos[i]),
+ ty * y);
+ }
+
+ glTexCoord2f (tx * pBox->x2, ty * y);
+ glVertex2i (pBox->x2, y);
+
+ for (i = 0; i < iTC; i++)
+ {
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2),
+ tx * (pBox->x1 + pos[i]),
+ ty * y);
+ (*GL::multiTexCoord2f) (GL_TEXTURE1_ARB + (i * 2) + 1,
+ tx * (pBox->x1 - pos[i]),
+ ty * y);
+ }
+
+ glTexCoord2f (tx * pBox->x1, ty * y);
+ glVertex2i (pBox->x1, y);
+
+ pBox++;
+ }
+
+ glEnd ();
+
+ glDisable (GL_FRAGMENT_PROGRAM_ARB);
+
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ if (wasCulled)
+ glEnable (GL_CULL_FACE);
+
+ fboEpilogue ();
+
+ return true;
+}
+
+#define MAX_VERTEX_PROJECT_COUNT 20
+
+void
+BlurWindow::projectRegion (CompOutput *output,
+ const GLMatrix &transform)
+{
+ float scrv[MAX_VERTEX_PROJECT_COUNT * 2];
+ float vertices[MAX_VERTEX_PROJECT_COUNT * 3];
+ int nVertices, nQuadCombine;
+ int i, j, stride;
+ float *v, *vert;
+ float minX, maxX, minY, maxY, minZ, maxZ;
+ float *scr;
+
+ GLTexture::MatrixList ml;
+ GLWindow::Geometry *gm;
+
+ gWindow->geometry ().reset ();
+ gWindow->glAddGeometry (ml, bScreen->tmpRegion2, infiniteRegion);
+
+ if (!gWindow->geometry ().vCount)
+ return;
+
+ gm = &gWindow->geometry ();
+
+ nVertices = (gm->indexCount) ? gm->indexCount: gm->vCount;
+ nQuadCombine = 1;
+
+ stride = gm->vertexStride;
+ vert = gm->vertices + (stride - 3);
+
+ /* we need to find the best value here */
+ if (nVertices <= MAX_VERTEX_PROJECT_COUNT)
+ {
+ for (i = 0; i < nVertices; i++)
+ {
+ if (gm->indexCount)
+ {
+ v = vert + (stride * gm->indices[i]);
+ }
+ else
+ {
+ v = vert + (stride * i);
+ }
+
+ vertices[i * 3] = v[0];
+ vertices[(i * 3) + 1] = v[1];
+ vertices[(i * 3) + 2] = v[2];
+ }
+ }
+ else
+ {
+ minX = screen->width ();
+ maxX = 0;
+ minY = screen->height ();
+ maxY = 0;
+ minZ = 1000000;
+ maxZ = -1000000;
+
+ for (i = 0; i < gm->vCount; i++)
+ {
+ v = vert + (stride * i);
+
+ if (v[0] < minX)
+ minX = v[0];
+
+ if (v[0] > maxX)
+ maxX = v[0];
+
+ if (v[1] < minY)
+ minY = v[1];
+
+ if (v[1] > maxY)
+ maxY = v[1];
+
+ if (v[2] < minZ)
+ minZ = v[2];
+
+ if (v[2] > maxZ)
+ maxZ = v[2];
+ }
+
+ vertices[0] = vertices[9] = minX;
+ vertices[1] = vertices[4] = minY;
+ vertices[3] = vertices[6] = maxX;
+ vertices[7] = vertices[10] = maxY;
+ vertices[2] = vertices[5] = maxZ;
+ vertices[8] = vertices[11] = maxZ;
+
+ nVertices = 4;
+
+ if (maxZ != minZ)
+ {
+ vertices[12] = vertices[21] = minX;
+ vertices[13] = vertices[16] = minY;
+ vertices[15] = vertices[18] = maxX;
+ vertices[19] = vertices[22] = maxY;
+ vertices[14] = vertices[17] = minZ;
+ vertices[20] = vertices[23] = minZ;
+ nQuadCombine = 2;
+ }
+ }
+
+ if (!bScreen->projectVertices (output, transform, vertices, scrv,
+ nVertices * nQuadCombine))
+ return;
+
+ for (i = 0; i < nVertices / 4; i++)
+ {
+ scr = scrv + (i * 4 * 2);
+
+ minX = screen->width ();
+ maxX = 0;
+ minY = screen->height ();
+ maxY = 0;
+
+ for (j = 0; j < 8 * nQuadCombine; j += 2)
+ {
+ if (scr[j] < minX)
+ minX = scr[j];
+
+ if (scr[j] > maxX)
+ maxX = scr[j];
+
+ if (scr[j + 1] < minY)
+ minY = scr[j + 1];
+
+ if (scr[j + 1] > maxY)
+ maxY = scr[j + 1];
+ }
+
+ int x1, y1, x2, y2;
+
+ x1 = minX - bScreen->filterRadius;
+ y1 = screen->height () - maxY - bScreen->filterRadius;
+ x2 = maxX + bScreen->filterRadius + 0.5f;
+ y2 = screen->height () - minY + bScreen->filterRadius + 0.5f;
+
+
+ bScreen->tmpRegion3 += CompRect (x1, y1, x2 - x1, y2 - y1);
+
+ }
+}
+
+bool
+BlurWindow::updateDstTexture (const GLMatrix &transform,
+ CompRect *pExtents,
+ int clientThreshold)
+{
+ int y;
+ int filter;
+
+ filter = bScreen->optionGetFilter ();
+
+ bScreen->tmpRegion3 = CompRegion ();
+
+ if (filter == BlurOptions::FilterGaussian)
+ {
+
+ if (state[BLUR_STATE_DECOR].threshold)
+ {
+ int xx, yy, ww, hh;
+ // top
+ xx = window->x () - window->output ().left;
+ yy = window->y () - window->output ().top;
+ ww = window->width () + window->output ().left +
+ window->output ().right;
+ hh = window->output ().top;
+
+ bScreen->tmpRegion2 = bScreen->tmpRegion.intersected (
+ CompRect (xx, yy, ww, hh));
+
+ if (!bScreen->tmpRegion2.isEmpty ())
+ projectRegion (bScreen->output, transform);
+
+ // bottom
+ xx = window->x () - window->output ().left;
+ yy = window->y () + window->height ();
+ ww = window->width () + window->output ().left +
+ window->output ().right;
+ hh = window->output ().bottom;
+
+ bScreen->tmpRegion2 = bScreen->tmpRegion.intersected (
+ CompRect (xx, yy, ww, hh));
+
+ if (!bScreen->tmpRegion2.isEmpty ())
+ projectRegion (bScreen->output, transform);
+
+ // left
+ xx = window->x () - window->output ().left;
+ yy = window->y ();
+ ww = window->output ().left;
+ hh = window->height ();
+
+ bScreen->tmpRegion2 = bScreen->tmpRegion.intersected (
+ CompRect (xx, yy, ww, hh));
+
+ if (!bScreen->tmpRegion2.isEmpty ())
+ projectRegion (bScreen->output, transform);
+
+ // right
+ xx = window->x () + window->width ();
+ yy = window->y ();
+ ww = window->output ().right;
+ hh = window->height ();
+
+ bScreen->tmpRegion2 = bScreen->tmpRegion.intersected (
+ CompRect (xx, yy, ww, hh));
+
+ if (!bScreen->tmpRegion2.isEmpty ())
+ projectRegion (bScreen->output, transform);
+ }
+
+ if (clientThreshold)
+ {
+ // center
+ bScreen->tmpRegion2 = bScreen->tmpRegion.intersected (
+ CompRect (window->x (),
+ window->y (),
+ window->width (),
+ window->height ()));
+
+ if (!bScreen->tmpRegion2.isEmpty ())
+ projectRegion (bScreen->output, transform);
+ }
+ }
+ else
+ {
+ // center
+ bScreen->tmpRegion2 = bScreen->tmpRegion;
+
+ if (!bScreen->tmpRegion2.isEmpty ())
+ projectRegion (bScreen->output, transform);
+ }
+
+ bScreen->tmpRegion = bScreen->region.intersected (bScreen->tmpRegion3);
+
+ if (bScreen->tmpRegion.isEmpty ())
+ return false;
+
+ *pExtents = bScreen->tmpRegion.boundingRect ();
+
+ if (!bScreen->texture[0] || bScreen->width != screen->width () ||
+ bScreen->height != screen->height ())
+ {
+ int i, textures = 1;
+
+ bScreen->width = screen->width ();
+ bScreen->height = screen->height ();
+
+ if (GL::textureNonPowerOfTwo ||
+ (POWER_OF_TWO (bScreen->width) && POWER_OF_TWO (bScreen->height)))
+ {
+ bScreen->target = GL_TEXTURE_2D;
+ bScreen->tx = 1.0f / bScreen->width;
+ bScreen->ty = 1.0f / bScreen->height;
+ }
+ else
+ {
+ bScreen->target = GL_TEXTURE_RECTANGLE_NV;
+ bScreen->tx = 1;
+ bScreen->ty = 1;
+ }
+
+ if (filter == BlurOptions::FilterGaussian)
+ {
+ if (GL::fbo && !bScreen->fbo)
+ (*GL::genFramebuffers) (1, &bScreen->fbo);
+
+ if (!bScreen->fbo)
+ compLogMessage ("blur", CompLogLevelError,
+ "Failed to create framebuffer object");
+
+ textures = 2;
+ }
+
+ bScreen->fboStatus = false;
+
+ for (i = 0; i < textures; i++)
+ {
+ if (!bScreen->texture[i])
+ glGenTextures (1, &bScreen->texture[i]);
+
+ glBindTexture (bScreen->target, bScreen->texture[i]);
+
+ glTexImage2D (bScreen->target, 0, GL_RGB,
+ bScreen->width,
+ bScreen->height,
+ 0, GL_BGRA,
+
+#if IMAGE_BYTE_ORDER == MSBFirst
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+#else
+ GL_UNSIGNED_BYTE,
+#endif
+
+ NULL);
+
+ glTexParameteri (bScreen->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (bScreen->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ if (filter == BlurOptions::FilterMipmap)
+ {
+ if (!GL::fbo)
+ {
+ compLogMessage ("blur", CompLogLevelWarn,
+ "GL_EXT_framebuffer_object extension "
+ "is required for mipmap filter");
+ }
+ else if (bScreen->target != GL_TEXTURE_2D)
+ {
+ compLogMessage ("blur", CompLogLevelWarn,
+ "GL_ARB_texture_non_power_of_two "
+ "extension is required for mipmap filter");
+ }
+ else
+ {
+ glTexParameteri (bScreen->target, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri (bScreen->target, GL_TEXTURE_MAG_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR);
+ }
+ }
+
+ glTexParameteri (bScreen->target, GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE);
+ glTexParameteri (bScreen->target, GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE);
+
+ glCopyTexSubImage2D (bScreen->target, 0, 0, 0, 0, 0,
+ bScreen->width, bScreen->height);
+ }
+ }
+ else
+ {
+ glBindTexture (bScreen->target, bScreen->texture[0]);
+
+ CompRect br = bScreen->tmpRegion.boundingRect ();
+
+ y = screen->height () - br.y2 ();
+
+ glCopyTexSubImage2D (bScreen->target, 0,
+ br.x1 (), y,
+ br.x1 (), y,
+ br.width (),
+ br.height ());
+ }
+
+ switch (filter) {
+ case BlurOptions::FilterGaussian:
+ return bScreen->fboUpdate (bScreen->tmpRegion.handle ()->rects,
+ bScreen->tmpRegion.numRects ());
+ case BlurOptions::FilterMipmap:
+ if (GL::generateMipmap)
+ (*GL::generateMipmap) (bScreen->target);
+ break;
+ case BlurOptions::Filter4xbilinear:
+ break;
+ }
+
+ glBindTexture (bScreen->target, 0);
+
+ return true;
+}
+
+bool
+BlurWindow::glDraw (const GLMatrix &transform,
+ GLFragment::Attrib &attrib,
+ const CompRegion &region,
+ unsigned int mask)
+{
+ bool status;
+
+ if (bScreen->alphaBlur && !region.isEmpty ())
+ {
+ int clientThreshold;
+
+ /* only care about client window blurring when it's translucent */
+ if (mask & PAINT_WINDOW_TRANSLUCENT_MASK)
+ clientThreshold = state[BLUR_STATE_CLIENT].threshold;
+ else
+ clientThreshold = 0;
+
+ if (state[BLUR_STATE_DECOR].threshold || clientThreshold)
+ {
+ bool clipped = false;
+ CompRect box (0, 0, 0, 0);
+ CompRegion reg;
+
+ bScreen->mvp = GLMatrix (bScreen->gScreen->projectionMatrix ());
+ bScreen->mvp *= transform;
+
+ if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
+ reg = infiniteRegion;
+ else
+ reg = region;
+
+ bScreen->tmpRegion = this->region.intersected (reg);
+ if (!bScreen->blurOcclusion &&
+ !(mask & PAINT_WINDOW_TRANSFORMED_MASK))
+ bScreen->tmpRegion -= clip;
+
+ if (updateDstTexture (transform, &box, clientThreshold))
+ {
+ if (clientThreshold)
+ {
+ if (state[BLUR_STATE_CLIENT].clipped)
+ {
+ if (bScreen->stencilBits)
+ {
+ state[BLUR_STATE_CLIENT].active = true;
+ clipped = true;
+ }
+ }
+ else
+ {
+ state[BLUR_STATE_CLIENT].active = true;
+ }
+ }
+
+ if (state[BLUR_STATE_DECOR].threshold)
+ {
+ if (state[BLUR_STATE_DECOR].clipped)
+ {
+ if (bScreen->stencilBits)
+ {
+ state[BLUR_STATE_DECOR].active = true;
+ clipped = true;
+ }
+ }
+ else
+ {
+ state[BLUR_STATE_DECOR].active = true;
+ }
+ }
+
+ if (!bScreen->blurOcclusion && !clip.isEmpty ())
+ clipped = true;
+ }
+
+ if (!bScreen->blurOcclusion)
+ bScreen->tmpRegion = this->region - clip;
+ else
+ bScreen->tmpRegion = this->region;
+
+ if (!clientThreshold)
+ {
+ bScreen->tmpRegion -= CompRect (window->x (),
+ window->x () + window->width (),
+ window->y (),
+ window->y () + window->height ());
+ }
+
+ if (clipped)
+ {
+ GLTexture::MatrixList ml;
+
+ gWindow->geometry ().reset ();
+
+ gWindow->glAddGeometry (ml, bScreen->tmpRegion, reg);
+ if (gWindow->geometry ().vCount)
+ {
+ CompRect clearBox = bScreen->stencilBox;
+
+ bScreen->stencilBox = box;
+
+ glEnable (GL_STENCIL_TEST);
+ glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ if (clearBox.x2 () > clearBox.x1 () &&
+ clearBox.y2 () > clearBox.y1 ())
+ {
+ glPushAttrib (GL_SCISSOR_BIT);
+ glEnable (GL_SCISSOR_TEST);
+ glScissor (clearBox.x1 (),
+ screen->height () - clearBox.y2 (),
+ clearBox.width (),
+ clearBox.height ());
+ glClear (GL_STENCIL_BUFFER_BIT);
+ glPopAttrib ();
+ }
+
+ glStencilFunc (GL_ALWAYS, 0x1, ~0);
+ glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
+
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+ gWindow->glDrawGeometry ();
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDisable (GL_STENCIL_TEST);
+ }
+ }
+ }
+ }
+
+ status = gWindow->glDraw (transform, attrib, region, mask);
+
+ state[BLUR_STATE_CLIENT].active = false;
+ state[BLUR_STATE_DECOR].active = false;
+
+ return status;
+}
+
+void
+BlurWindow::glDrawTexture (GLTexture *texture,
+ GLFragment::Attrib &attrib,
+ unsigned int mask)
+{
+ int state = BLUR_STATE_DECOR;
+
+ foreach (GLTexture *tex, gWindow->textures ())
+ if (texture == tex)
+ state = BLUR_STATE_CLIENT;
+
+ if (blur || this->state[state].active)
+ {
+ GLFragment::Attrib fa (attrib);
+ int param, function;
+ int unit = 0;
+ GLfloat dx, dy;
+ int iTC = 0;
+
+ if (blur)
+ {
+ param = fa.allocParameters (1);
+
+ function = bScreen->getSrcBlurFragmentFunction (texture, param);
+ if (function)
+ {
+ fa.addFunction (function);
+
+ dx = ((texture->matrix ().xx / 2.1f) * blur) / 65535.0f;
+ dy = ((texture->matrix ().yy / 2.1f) * blur) / 65535.0f;
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param, dx, dy, dx, -dy);
+
+ /* bi-linear filtering is required */
+ mask |= PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
+ }
+ }
+
+ if (this->state[state].active)
+ {
+ GLFragment::Attrib dstFa (fa);
+ float threshold = (float) this->state[state].threshold;
+
+ switch (bScreen->optionGetFilter ()) {
+ case BlurOptions::Filter4xbilinear:
+ dx = bScreen->tx / 2.1f;
+ dy = bScreen->ty / 2.1f;
+
+ param = dstFa.allocParameters (3);
+ unit = dstFa.allocTextureUnits (1);
+
+ function = bScreen->getDstBlurFragmentFunction (
+ texture, param, unit, 0, 0);
+ if (function)
+ {
+ dstFa.addFunction (function);
+
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + unit);
+ glBindTexture (bScreen->target, bScreen->texture[0]);
+ (*GL::activeTexture) (GL_TEXTURE0_ARB);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param,
+ bScreen->tx, bScreen->ty,
+ 0.0f, 0.0f);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param + 1,
+ threshold, threshold,
+ threshold, threshold);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param + 2,
+ dx, dy, 0.0f, 0.0f);
+ }
+ break;
+ case BlurOptions::FilterGaussian:
+ if (bScreen->optionGetIndependentTex ())
+ {
+ /* leave one free texture unit for fragment position */
+ iTC = MAX (0, GL::maxTextureUnits -
+ (gWindow->geometry ().texUnits + 1));
+ if (iTC)
+ iTC = MIN (iTC / 2, bScreen->numTexop);
+ }
+
+ param = dstFa.allocParameters (2);
+ unit = dstFa.allocTextureUnits (2);
+
+ function = bScreen->getDstBlurFragmentFunction (
+ texture, param, unit, iTC,
+ gWindow->geometry ().texUnits);
+
+ if (function)
+ {
+ int i;
+
+ dstFa.addFunction (function);
+
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + unit);
+ glBindTexture (bScreen->target, bScreen->texture[0]);
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + unit + 1);
+ glBindTexture (bScreen->target, bScreen->texture[1]);
+ (*GL::activeTexture) (GL_TEXTURE0_ARB);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param, bScreen->tx,
+ bScreen->ty, 0.0f, 0.0f);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param + 1,
+ threshold, threshold,
+ threshold, threshold);
+
+ if (iTC)
+ {
+ GLMatrix tm, rm;
+ float s_gen[4], t_gen[4], q_gen[4];
+
+ for (i = 0; i < 16; i++)
+ tm[i] = 0;
+ tm[0] = (bScreen->output->width () / 2.0) *
+ bScreen->tx;
+ tm[5] = (bScreen->output->height () / 2.0) *
+ bScreen->ty;
+ tm[10] = 1;
+
+ tm[12] = (bScreen->output->width () / 2.0 +
+ bScreen->output->x1 ()) * bScreen->tx;
+ tm[13] = (bScreen->output->height () / 2.0 +
+ screen->height () -
+ bScreen->output->y2 ()) * bScreen->ty;
+ tm[14] = 1;
+ tm[15] = 1;
+
+ tm *= bScreen->mvp;
+
+ for (i = 0; i < iTC; i++)
+ {
+ (*GL::activeTexture) (GL_TEXTURE0_ARB +
+ gWindow->geometry ().texUnits + (i * 2));
+
+ rm.reset ();
+ rm[13] = bScreen->ty * bScreen->pos[i];
+ rm *= tm;
+
+ s_gen[0] = rm[0];
+ s_gen[1] = rm[4];
+ s_gen[2] = rm[8];
+ s_gen[3] = rm[12];
+ t_gen[0] = rm[1];
+ t_gen[1] = rm[5];
+ t_gen[2] = rm[9];
+ t_gen[3] = rm[13];
+ q_gen[0] = rm[3];
+ q_gen[1] = rm[7];
+ q_gen[2] = rm[11];
+ q_gen[3] = rm[15];
+
+ glTexGenfv (GL_T, GL_OBJECT_PLANE, t_gen);
+ glTexGenfv (GL_S, GL_OBJECT_PLANE, s_gen);
+ glTexGenfv (GL_Q, GL_OBJECT_PLANE, q_gen);
+
+ glTexGeni (GL_S, GL_TEXTURE_GEN_MODE,
+ GL_OBJECT_LINEAR);
+ glTexGeni (GL_T, GL_TEXTURE_GEN_MODE,
+ GL_OBJECT_LINEAR);
+ glTexGeni (GL_Q, GL_TEXTURE_GEN_MODE,
+ GL_OBJECT_LINEAR);
+
+ glEnable (GL_TEXTURE_GEN_S);
+ glEnable (GL_TEXTURE_GEN_T);
+ glEnable (GL_TEXTURE_GEN_Q);
+
+ (*GL::activeTexture) (GL_TEXTURE0_ARB +
+ gWindow->geometry ().texUnits +
+ 1 + (i * 2));
+
+ rm.reset ();
+
+ rm[13] = -bScreen->ty * bScreen->pos[i];
+ rm *= tm;
+
+ s_gen[0] = rm[0];
+ s_gen[1] = rm[4];
+ s_gen[2] = rm[8];
+ s_gen[3] = rm[12];
+ t_gen[0] = rm[1];
+ t_gen[1] = rm[5];
+ t_gen[2] = rm[9];
+ t_gen[3] = rm[13];
+ q_gen[0] = rm[3];
+ q_gen[1] = rm[7];
+ q_gen[2] = rm[11];
+ q_gen[3] = rm[15];
+
+ glTexGenfv (GL_T, GL_OBJECT_PLANE, t_gen);
+ glTexGenfv (GL_S, GL_OBJECT_PLANE, s_gen);
+ glTexGenfv (GL_Q, GL_OBJECT_PLANE, q_gen);
+
+ glTexGeni (GL_S, GL_TEXTURE_GEN_MODE,
+ GL_OBJECT_LINEAR);
+ glTexGeni (GL_T, GL_TEXTURE_GEN_MODE,
+ GL_OBJECT_LINEAR);
+ glTexGeni (GL_Q, GL_TEXTURE_GEN_MODE,
+ GL_OBJECT_LINEAR);
+
+ glEnable (GL_TEXTURE_GEN_S);
+ glEnable (GL_TEXTURE_GEN_T);
+ glEnable (GL_TEXTURE_GEN_Q);
+ }
+
+ (*GL::activeTexture) (GL_TEXTURE0_ARB);
+ }
+
+ }
+ break;
+ case BlurOptions::FilterMipmap:
+ param = dstFa.allocParameters (2);
+ unit = dstFa.allocTextureUnits (1);
+
+ function =
+ bScreen->getDstBlurFragmentFunction (texture, param,
+ unit, 0, 0);
+ if (function)
+ {
+ float lod =
+ bScreen->optionGetMipmapLod ();
+
+ dstFa.addFunction (function);
+
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + unit);
+ glBindTexture (bScreen->target, bScreen->texture[0]);
+ (*GL::activeTexture) (GL_TEXTURE0_ARB);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param,
+ bScreen->tx, bScreen->ty,
+ 0.0f, lod);
+
+ (*GL::programEnvParameter4f) (GL_FRAGMENT_PROGRAM_ARB,
+ param + 1,
+ threshold, threshold,
+ threshold, threshold);
+ }
+ break;
+ }
+
+ if (this->state[state].clipped ||
+ (!bScreen->blurOcclusion && !clip.isEmpty ()))
+ {
+ glEnable (GL_STENCIL_TEST);
+
+ glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
+ glStencilFunc (GL_EQUAL, 0x1, ~0);
+
+ /* draw region with destination blur */
+ gWindow->glDrawTexture (texture, dstFa, mask);
+
+ glStencilFunc (GL_EQUAL, 0, ~0);
+
+ /* draw region without destination blur */
+ gWindow->glDrawTexture (texture, fa, mask);
+
+ glDisable (GL_STENCIL_TEST);
+ }
+ else
+ {
+ /* draw with destination blur */
+ gWindow->glDrawTexture (texture, dstFa, mask);
+ }
+ }
+ else
+ {
+ gWindow->glDrawTexture (texture, fa, mask);
+ }
+
+ if (unit)
+ {
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + unit);
+ glBindTexture (bScreen->target, 0);
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + unit + 1);
+ glBindTexture (bScreen->target, 0);
+ (*GL::activeTexture) (GL_TEXTURE0_ARB);
+ }
+
+ if (iTC)
+ {
+ int i;
+ for (i = gWindow->geometry ().texUnits;
+ i < gWindow->geometry ().texUnits + (2 * iTC); i++)
+ {
+ (*GL::activeTexture) (GL_TEXTURE0_ARB + i);
+ glDisable (GL_TEXTURE_GEN_S);
+ glDisable (GL_TEXTURE_GEN_T);
+ glDisable (GL_TEXTURE_GEN_Q);
+ }
+ (*GL::activeTexture) (GL_TEXTURE0_ARB);
+ }
+ }
+ else
+ {
+ gWindow->glDrawTexture (texture, attrib, mask);
+ }
+}
+
+void
+BlurScreen::handleEvent (XEvent *event)
+{
+ Window activeWindow = screen->activeWindow ();
+
+ screen->handleEvent (event);
+
+ if (screen->activeWindow () != activeWindow)
+ {
+ CompWindow *w;
+
+ w = screen->findWindow (activeWindow);
+ if (w)
+ {
+ if (optionGetFocusBlur ())
+ {
+ CompositeWindow::get (w)->addDamage ();
+ moreBlur = true;
+ }
+ }
+
+ w = screen->findWindow (screen->activeWindow ());
+ if (w)
+ {
+ if (optionGetFocusBlur ())
+ {
+ CompositeWindow::get (w)->addDamage ();
+ moreBlur = true;
+ }
+ }
+ }
+
+ if (event->type == PropertyNotify)
+ {
+ int i;
+
+ for (i = 0; i < BLUR_STATE_NUM; i++)
+ {
+ if (event->xproperty.atom == blurAtom[i])
+ {
+ CompWindow *w;
+
+ w = screen->findWindow (event->xproperty.window);
+ if (w)
+ BlurWindow::get (w)->update (i);
+ }
+ }
+ }
+}
+
+void
+BlurWindow::resizeNotify (int dx,
+ int dy,
+ int dwidth,
+ int dheight)
+{
+ if (bScreen->alphaBlur)
+ {
+ if (state[BLUR_STATE_CLIENT].threshold ||
+ state[BLUR_STATE_DECOR].threshold)
+ updateRegion ();
+ }
+
+ window->resizeNotify (dx, dy, dwidth, dheight);
+
+}
+
+void
+BlurWindow::moveNotify (int dx,
+ int dy,
+ bool immediate)
+{
+ if (!region.isEmpty ())
+ region.translate (dx, dy);
+
+ window->moveNotify (dx, dy, immediate);
+}
+
+static bool
+blurPulse (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w;
+ int xid;
+
+ xid = CompOption::getIntOptionNamed (options, "window",
+ screen->activeWindow ());
+
+ w = screen->findWindow (xid);
+ if (w && GL::fragmentProgram)
+ {
+ BLUR_SCREEN (screen);
+ BLUR_WINDOW (w);
+
+ bw->pulse = true;
+ bs->moreBlur = true;
+
+ bw->cWindow->addDamage ();
+ }
+
+ return false;
+}
+
+void
+BlurScreen::matchExpHandlerChanged ()
+{
+ screen->matchExpHandlerChanged ();
+
+ /* match options are up to date after the call to matchExpHandlerChanged */
+ foreach (CompWindow *w, screen->windows ())
+ BlurWindow::get (w)->updateMatch ();
+
+}
+
+void
+BlurScreen::matchPropertyChanged (CompWindow *w)
+{
+ BlurWindow::get (w)->updateMatch ();
+
+ screen->matchPropertyChanged (w);
+}
+
+bool
+BlurScreen::setOption (const CompString &name, CompOption::Value &value)
+{
+ unsigned int index;
+
+ bool rv = BlurOptions::setOption (name, value);
+
+ if (!rv || !CompOption::findOption (getOptions (), name, &index))
+ return false;
+
+ switch (index) {
+ case BlurOptions::BlurSpeed:
+ blurTime = 1000.0f / optionGetBlurSpeed ();
+ break;
+ case BlurOptions::FocusBlurMatch:
+ case BlurOptions::AlphaBlurMatch:
+ foreach (CompWindow *w, screen->windows ())
+ BlurWindow::get (w)->updateMatch ();
+
+ moreBlur = true;
+ cScreen->damageScreen ();
+ break;
+ case BlurOptions::FocusBlur:
+ moreBlur = true;
+ cScreen->damageScreen ();
+ break;
+ case BlurOptions::AlphaBlur:
+ if (GL::fragmentProgram && optionGetAlphaBlur ())
+ alphaBlur = true;
+ else
+ alphaBlur = false;
+
+ cScreen->damageScreen ();
+ break;
+ case BlurOptions::Filter:
+ blurReset ();
+ cScreen->damageScreen ();
+ break;
+ case BlurOptions::GaussianRadius:
+ case BlurOptions::GaussianStrength:
+ case BlurOptions::IndependentTex:
+ if (optionGetFilter () == BlurOptions::FilterGaussian)
+ {
+ blurReset ();
+ cScreen->damageScreen ();
+ }
+ break;
+ case BlurOptions::MipmapLod:
+ if (optionGetFilter () == BlurOptions::FilterMipmap)
+ {
+ blurReset ();
+ cScreen->damageScreen ();
+ }
+ break;
+ case BlurOptions::Saturation:
+ blurReset ();
+ cScreen->damageScreen ();
+ break;
+ case BlurOptions::Occlusion:
+ blurOcclusion = optionGetOcclusion ();
+ blurReset ();
+ cScreen->damageScreen ();
+ break;
+ default:
+ break;
+ }
+
+ return rv;
+}
+
+BlurScreen::BlurScreen (CompScreen *screen) :
+ PluginClassHandler<BlurScreen,CompScreen> (screen),
+ gScreen (GLScreen::get (screen)),
+ cScreen (CompositeScreen::get (screen)),
+ moreBlur (false),
+ filterRadius (0),
+ srcBlurFunctions (0),
+ dstBlurFunctions (0),
+ output (NULL),
+ count (0),
+ program (0),
+ maxTemp (32),
+ fbo (0),
+ fboStatus (0)
+{
+
+ blurAtom[BLUR_STATE_CLIENT] =
+ XInternAtom (screen->dpy (), "_COMPIZ_WM_WINDOW_BLUR", 0);
+ blurAtom[BLUR_STATE_DECOR] =
+ XInternAtom (screen->dpy (), DECOR_BLUR_ATOM_NAME, 0);
+
+ blurTime = 1000.0f / optionGetBlurSpeed ();
+ blurOcclusion = optionGetOcclusion ();
+
+ for (int i = 0; i < 2; i++)
+ texture[i] = 0;
+
+ glGetIntegerv (GL_STENCIL_BITS, &stencilBits);
+ if (!stencilBits)
+ compLogMessage ("blur", CompLogLevelWarn,
+ "No stencil buffer. Region based blur disabled");
+
+ /* We need GL_ARB_fragment_program for blur */
+ if (GL::fragmentProgram)
+ alphaBlur = optionGetAlphaBlur ();
+ else
+ alphaBlur = false;
+
+ if (GL::fragmentProgram)
+ {
+ int tmp[4];
+ GL::getProgramiv (GL_FRAGMENT_PROGRAM_ARB,
+ GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB,
+ tmp);
+ maxTemp = tmp[0];
+ }
+
+ updateFilterRadius ();
+
+ optionSetPulseInitiate (blurPulse);
+
+ ScreenInterface::setHandler (screen, true);
+ CompositeScreenInterface::setHandler (cScreen, true);
+ GLScreenInterface::setHandler (gScreen, true);
+}
+
+
+BlurScreen::~BlurScreen ()
+{
+ foreach (BlurFunction &bf, srcBlurFunctions)
+ GLFragment::destroyFragmentFunction (bf.id);
+ foreach (BlurFunction &bf, dstBlurFunctions)
+ GLFragment::destroyFragmentFunction (bf.id);
+
+ cScreen->damageScreen ();
+
+ if (fbo)
+ (*GL::deleteFramebuffers) (1, &fbo);
+
+ for (int i = 0; i < 2; i++)
+ if (texture[i])
+ glDeleteTextures (1, &texture[i]);
+
+}
+
+BlurWindow::BlurWindow (CompWindow *w) :
+ PluginClassHandler<BlurWindow,CompWindow> (w),
+ window (w),
+ cWindow (CompositeWindow::get (w)),
+ gWindow (GLWindow::get (w)),
+ bScreen (BlurScreen::get (screen)),
+ blur (0),
+ pulse (false),
+ focusBlur (false)
+{
+ for (int i = 0; i < BLUR_STATE_NUM; i++)
+ {
+ state[i].threshold = 0;
+ state[i].clipped = false;
+ state[i].active = false;
+
+ propSet[i] = false;
+ }
+
+ update (BLUR_STATE_CLIENT);
+ update (BLUR_STATE_DECOR);
+
+ updateMatch ();
+
+
+ WindowInterface::setHandler (window, true);
+ GLWindowInterface::setHandler (gWindow, true);
+}
+
+BlurWindow::~BlurWindow ()
+{
+}
+
+bool
+BlurPluginVTable::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/plugins/blur/src/blur.h b/plugins/blur/src/blur.h
new file mode 100644
index 0000000..a03c5dd
--- /dev/null
+++ b/plugins/blur/src/blur.h
@@ -0,0 +1,241 @@
+/*
+ * 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
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <core/core.h>
+#include <composite/composite.h>
+#include <opengl/opengl.h>
+#include <decoration.h>
+
+#include <X11/Xatom.h>
+#include <GL/glu.h>
+
+#include "blur_options.h"
+
+#define BLUR_GAUSSIAN_RADIUS_MAX 15
+
+struct BlurFunction {
+
+ GLFragment::FunctionId id;
+
+ int target;
+ int param;
+ int unit;
+ int startTC;
+ int numITC;
+};
+
+struct BlurBox {
+ decor_point_t p1;
+ decor_point_t p2;
+};
+
+#define BLUR_STATE_CLIENT 0
+#define BLUR_STATE_DECOR 1
+#define BLUR_STATE_NUM 2
+
+struct BlurState {
+ int threshold;
+ std::vector<BlurBox> box;
+ bool active;
+ bool clipped;
+};
+
+class BlurScreen :
+ public ScreenInterface,
+ public CompositeScreenInterface,
+ public GLScreenInterface,
+ public PluginClassHandler<BlurScreen,CompScreen>,
+ public BlurOptions
+{
+ public:
+ BlurScreen (CompScreen *screen);
+ ~BlurScreen ();
+
+ bool setOption (const CompString &name, CompOption::Value &value);
+
+ void handleEvent (XEvent *);
+
+ virtual void matchExpHandlerChanged ();
+ virtual void matchPropertyChanged (CompWindow *window);
+
+ void preparePaint (int);
+ void donePaint ();
+
+ bool glPaintOutput (const GLScreenPaintAttrib &,
+ const GLMatrix &, const CompRegion &,
+ CompOutput *, unsigned int);
+ void glPaintTransformedOutput (const GLScreenPaintAttrib &,
+ const GLMatrix &,
+ const CompRegion &,
+ CompOutput *, unsigned int);
+
+ void updateFilterRadius ();
+ void blurReset ();
+
+ GLFragment::FunctionId getSrcBlurFragmentFunction (GLTexture *, int);
+ GLFragment::FunctionId getDstBlurFragmentFunction (GLTexture *texture,
+ int param,
+ int unit,
+ int numITC,
+ int startTC);
+
+ bool projectVertices (CompOutput *output,
+ const GLMatrix &transform,
+ const float *object,
+ float *scr,
+ int n);
+
+ bool loadFragmentProgram (GLuint *program,
+ const char *string);
+
+ bool loadFilterProgram (int numITC);
+
+ bool fboPrologue ();
+ void fboEpilogue ();
+ bool fboUpdate (BoxPtr pBox, int nBox);
+
+
+ public:
+ GLScreen *gScreen;
+ CompositeScreen *cScreen;
+
+ Atom blurAtom[BLUR_STATE_NUM];
+
+ bool alphaBlur;
+
+ int blurTime;
+ bool moreBlur;
+
+ bool blurOcclusion;
+
+ int filterRadius;
+
+ std::vector<BlurFunction> srcBlurFunctions;
+ std::vector<BlurFunction> dstBlurFunctions;
+
+ CompRegion region;
+ CompRegion tmpRegion;
+ CompRegion tmpRegion2;
+ CompRegion tmpRegion3;
+ CompRegion occlusion;
+
+ CompRect stencilBox;
+ GLint stencilBits;
+
+ CompOutput *output;
+ int count;
+
+ GLuint texture[2];
+
+ GLenum target;
+ float tx;
+ float ty;
+ int width;
+ int height;
+
+ GLuint program;
+ int maxTemp;
+ GLuint fbo;
+ bool fboStatus;
+
+ float amp[BLUR_GAUSSIAN_RADIUS_MAX];
+ float pos[BLUR_GAUSSIAN_RADIUS_MAX];
+ int numTexop;
+
+ GLMatrix mvp;
+};
+
+class BlurWindow :
+ public WindowInterface,
+ public GLWindowInterface,
+ public PluginClassHandler<BlurWindow,CompWindow>
+{
+
+ public:
+
+ BlurWindow (CompWindow *window);
+ ~BlurWindow ();
+
+ void resizeNotify (int dx, int dy, int dwidth, int dheight);
+ void moveNotify (int dx, int dy, bool immediate);
+
+ bool glPaint (const GLWindowPaintAttrib &, const GLMatrix &,
+ const CompRegion &, unsigned int);
+ bool glDraw (const GLMatrix &, GLFragment::Attrib &,
+ const CompRegion &, unsigned int);
+ void glDrawTexture (GLTexture *texture, GLFragment::Attrib &,
+ unsigned int);
+
+ void updateRegion ();
+
+ void setBlur (int state,
+ int threshold,
+ std::vector<BlurBox> box);
+
+ void updateAlphaMatch ();
+ void updateMatch ();
+ void update (int state);
+
+ void projectRegion (CompOutput *output,
+ const GLMatrix &transform);
+
+ bool updateDstTexture (const GLMatrix &transform,
+ CompRect *pExtents,
+ int clientThreshold);
+
+ public:
+ CompWindow *window;
+ CompositeWindow *cWindow;
+ GLWindow *gWindow;
+ BlurScreen *bScreen;
+
+ int blur;
+ bool pulse;
+ bool focusBlur;
+
+ BlurState state[BLUR_STATE_NUM];
+ bool propSet[BLUR_STATE_NUM];
+
+ CompRegion region;
+ CompRegion clip;
+};
+
+#define BLUR_SCREEN(s) \
+ BlurScreen *bs = BlurScreen::get (s)
+
+#define BLUR_WINDOW(w) \
+ BlurWindow *bw = BlurWindow::get (w)
+
+class BlurPluginVTable :
+ public CompPlugin::VTableForScreenAndWindow<BlurScreen,BlurWindow>
+{
+ public:
+
+ bool init ();
+};
diff --git a/plugins/clone/CMakeLists.txt b/plugins/clone/CMakeLists.txt
new file mode 100644
index 0000000..4820bb4
--- /dev/null
+++ b/plugins/clone/CMakeLists.txt
@@ -0,0 +1,5 @@
+find_package (Compiz REQUIRED)
+
+include (CompizPlugin)
+
+compiz_plugin (clone PLUGINDEPS composite opengl)
diff --git a/plugins/clone/clone.xml.in b/plugins/clone/clone.xml.in
new file mode 100644
index 0000000..952dcbe
--- /dev/null
+++ b/plugins/clone/clone.xml.in
@@ -0,0 +1,22 @@
+<compiz>
+ <plugin name="clone" useBcop="true">
+ <_short>Clone Output</_short>
+ <_long>Output clone handler</_long>
+ <category>Desktop</category>
+ <deps>
+ <requirement>
+ <plugin>opengl</plugin>
+ </requirement>
+ <relation type="after">
+ <plugin>decor</plugin>
+ </relation>
+ </deps>
+ <options>
+ <option name="initiate_button" type="button">
+ <_short>Initiate</_short>
+ <_long>Initiate clone selection</_long>
+ <default>&lt;Super&gt;&lt;Shift&gt;Button1</default>
+ </option>
+ </options>
+ </plugin>
+</compiz>
diff --git a/plugins/clone/src/clone.cpp b/plugins/clone/src/clone.cpp
new file mode 100644
index 0000000..ac3413d
--- /dev/null
+++ b/plugins/clone/src/clone.cpp
@@ -0,0 +1,595 @@
+/*
+ * Copyright © 2006 Novell, Inc.
+ *
+ * clone.cpp
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Ported to Compiz 0.9 by:
+ * Copyright (c) 2009 Sam Spilsbury <smspillaz@gmail.com>
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include "clone.h"
+
+COMPIZ_PLUGIN_20090315 (clone, ClonePluginVTable);
+
+static void togglePaintFunctions (CloneScreen *cs, bool enabled)
+{
+ screen->handleEventSetEnabled (cs, enabled);
+ cs->cScreen->preparePaintSetEnabled (cs, enabled);
+ cs->gScreen->glPaintOutputSetEnabled (cs, enabled);
+ cs->cScreen->donePaintSetEnabled (cs, enabled);
+
+ foreach (CompWindow *w, screen->windows ())
+ {
+ CLONE_WINDOW (w);
+
+ cw->gWindow->glPaintSetEnabled (cw, enabled);
+ }
+}
+
+void
+CloneScreen::finish ()
+{
+ grab = false;
+
+ if (src != dst)
+ {
+ Clone *fClone = NULL;
+ /* check if we should replace current clone */
+ foreach (Clone *iClone, clones)
+ {
+ if (iClone->dst == dst)
+ {
+ fClone = iClone;
+ break;
+ }
+ }
+
+ /* no existing clone for this destination, we must allocate one */
+ if (!fClone)
+ {
+ fClone = new Clone ();
+
+ XSetWindowAttributes attr;
+ int x, y;
+
+ attr.override_redirect = true;
+
+ x = (int) screen->outputDevs ()[dst].x1 ();
+ y = (int) screen->outputDevs ()[dst].y1 ();
+
+ fClone->input =
+ XCreateWindow (screen->dpy (),
+ screen->root (), x, y,
+ (int) screen->outputDevs ()[dst].width (),
+ (int) screen->outputDevs ()[dst].height (),
+ 0, 0, InputOnly, CopyFromParent,
+ CWOverrideRedirect, &attr);
+ XMapRaised (screen->dpy (), fClone->input);
+
+ clones.push_back (fClone);
+ }
+
+ if (fClone)
+ {
+ fClone->src = src;
+ fClone->dst = dst;
+ }
+ }
+
+ if (grabbedOutput != dst)
+ {
+ /* remove clone */
+ foreach (Clone *iClone, clones)
+ {
+ if (iClone->dst == grabbedOutput)
+ {
+ XDestroyWindow (screen->dpy (), iClone->input);
+ clones.remove (iClone);
+ delete iClone;
+ break;
+ }
+ }
+ }
+}
+
+void
+CloneScreen::preparePaint (int msSinceLastPaint)
+{
+ if (grab)
+ {
+ if (grabHandle)
+ {
+ offset -= msSinceLastPaint * 0.005f;
+ if (offset < 0.0f)
+ offset = 0.0f;
+ }
+ else
+ {
+ offset += msSinceLastPaint * 0.005f;
+ if (offset >= 1.0f)
+ offset = 1.0f;
+ }
+ }
+
+ cScreen->preparePaint (msSinceLastPaint);
+
+ foreach (Clone *iClone, clones)
+ {
+ CompOutput *srcOutput = &(screen->outputDevs () [iClone->src]);
+ CompOutput *dstOutput = &(screen->outputDevs () [iClone->dst]);
+ CompRegion dstOutputRegion (*dstOutput);
+ CompRegion srcOutputRegion (*srcOutput);
+ int dx, dy;
+
+ dx = dstOutput->x1 () - srcOutput->x1 ();
+ dy = dstOutput->y1 () - srcOutput->y1 ();
+
+ if (cScreen->damageMask () & COMPOSITE_SCREEN_DAMAGE_REGION_MASK)
+ {
+ if (srcOutput->width () != dstOutput->width () ||
+ srcOutput->height () != dstOutput->height ())
+ {
+ cScreen->damageRegion (dstOutputRegion);
+ iClone->region = srcOutputRegion;
+ }
+ else
+ {
+ CompRegion currentDamageRegion = cScreen->currentDamage ();
+ iClone->region = currentDamageRegion - dstOutputRegion;
+ iClone->region.translate (dx, dy);
+ currentDamageRegion = iClone->region + currentDamageRegion;
+ cScreen->damageRegion (currentDamageRegion);
+ iClone->region = currentDamageRegion - srcOutputRegion;
+ iClone->region.translate (-dx, -dy);
+ }
+ }
+ else
+ {
+ iClone->region = srcOutputRegion;
+ }
+ }
+}
+
+void
+CloneScreen::donePaint ()
+{
+ if (grab)
+ {
+ if (offset == 1.0f)
+ finish ();
+
+ cScreen->damageScreen ();
+ }
+
+ cScreen->donePaint ();
+
+ if (!grab && clones.empty ())
+ togglePaintFunctions (this, false);
+}
+
+bool
+CloneScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+
+{
+ bool status;
+ unsigned int dstForThisOutput, outputId = 0;
+ CompRegion sRegion = region;
+
+ dstForThisOutput = outputId =
+ ((unsigned int) output->id () != (unsigned int) ~0) ?
+ output->id () : 0;
+
+ if (!grab || (unsigned int) grabbedOutput != outputId)
+ {
+ foreach (Clone *iClone, clones)
+ {
+ if ((unsigned int) iClone->dst == outputId)
+ {
+ sRegion = iClone->region;
+ dstForThisOutput = (unsigned int) iClone->src;
+
+ if (screen->outputDevs ()[dstForThisOutput].width () !=
+ screen->outputDevs ()[outputId].width () ||
+ screen->outputDevs ()[dstForThisOutput].height () !=
+ screen->outputDevs ()[outputId].height ())
+ transformed = true;
+ else
+ transformed = false;
+
+ break;
+ }
+ }
+ }
+
+ if (output->id () != (unsigned int) ~0)
+ status = gScreen->glPaintOutput (attrib, transform, sRegion,
+ &screen->outputDevs ()[dstForThisOutput], mask);
+ else
+ status =
+ gScreen->glPaintOutput (attrib, transform, sRegion, output, mask);
+
+ if (grab)
+ {
+ GLMatrix sTransform = transform;
+ GLenum filter;
+ float zoom1, zoom2x, zoom2y, x1, y1, x2, y2;
+ float zoomX, zoomY;
+ int dx, dy;
+
+ zoom1 = 160.0f / screen->outputDevs ()[src].height ();
+
+ x1 = x - (screen->outputDevs ()[src].x1 () * zoom1);
+ y1 = y - (screen->outputDevs ()[src].y1 () * zoom1);
+
+ x1 -= (screen->outputDevs ()[src].width () * zoom1) / 2;
+ y1 -= (screen->outputDevs ()[src].height () * zoom1) / 2;
+
+ if (grabHandle)
+ {
+ x2 = screen->outputDevs ()[grabbedOutput].x1 () -
+ screen->outputDevs ()[src].x1 ();
+ y2 = screen->outputDevs ()[grabbedOutput].y1 () -
+ screen->outputDevs ()[src].y1 ();
+
+ zoom2x = (float) screen->outputDevs ()[grabbedOutput].width () /
+ screen->outputDevs ()[src].width ();
+ zoom2y = (float) screen->outputDevs ()[grabbedOutput].height () /
+ screen->outputDevs ()[src].height ();
+ }
+ else
+ {
+ x2 = screen->outputDevs ()[dst].x1 () -
+ screen->outputDevs ()[src].x1 ();
+ y2 = screen->outputDevs ()[dst].y1 () -
+ screen->outputDevs ()[src].y1 ();
+
+ zoom2x = (float) screen->outputDevs ()[dst].width () /
+ screen->outputDevs ()[src].width ();
+ zoom2y = (float) screen->outputDevs ()[dst].height () /
+ screen->outputDevs ()[src].height ();
+ }
+
+ /* XXX: hmm.. why do I need this.. */
+ if (x2 < 0.0f)
+ x2 *= zoom2x;
+ if (y2 < 0.0f)
+ y2 *= zoom2y;
+
+ dx = x1 * (1.0f - offset) + x2 * offset;
+ dy = y1 * (1.0f - offset) + y2 * offset;
+
+ zoomX = zoom1 * (1.0f - offset) + zoom2x * offset;
+ zoomY = zoom1 * (1.0f - offset) + zoom2y * offset;
+
+ sTransform.translate (-0.5f, -0.5f, -DEFAULT_Z_CAMERA);
+ sTransform.scale (1.0f / screen->outputDevs ()[outputId].width (),
+ -1.0f / screen->outputDevs ()[outputId].height (),
+ 1.0f);
+ sTransform.translate (dx - screen->outputDevs ()[outputId].x1 (),
+ dy - screen->outputDevs ()[outputId].y2 (),
+ 0.0f);
+ sTransform.scale (zoomX, zoomY, 1.0f);
+
+ glPushMatrix ();
+ glLoadMatrixf (sTransform.getMatrix ());
+
+ filter = gScreen->textureFilter ();
+
+ if (offset == 0.0f)
+ gScreen->setTextureFilter (GL_LINEAR_MIPMAP_LINEAR);
+
+ CompRegion srcOutputRegion (screen->outputDevs ()[src]);
+
+ foreach (CompWindow *w, screen->windows ())
+ {
+ GLMatrix gTransform = transform;
+ gTransform.translate (-100, 0, 0);
+ CLONE_WINDOW (w);
+ if (w->destroyed ())
+ continue;
+
+ if (!w->shaded ())
+ {
+ if (!w->isViewable () || !cw->cWindow->damaged ())
+ continue;
+ }
+
+ cw->gWindow->glPaint (cw->gWindow->paintAttrib (), sTransform,
+ srcOutputRegion,
+ PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK);
+ }
+
+ gScreen->setTextureFilter (filter);
+
+ glPopMatrix ();
+ }
+
+ return status;
+}
+
+bool
+CloneWindow::glPaint (const GLWindowPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ unsigned int mask)
+{
+ CLONE_SCREEN (screen);
+
+ if (!cs->clones.empty () && cs->transformed)
+ mask |= PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK;
+
+ return gWindow->glPaint (attrib, transform, region, mask);
+
+}
+
+bool
+CloneScreen::initiate (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector options)
+{
+ std::list <Clone *>::iterator it = clones.begin ();
+ if (grab || screen->otherGrabExist ("clone", NULL))
+ return false;
+
+ if (!grabHandle)
+ grabHandle = screen->pushGrab (None, "clone");
+
+ grab = true;
+
+ x = CompOption::getIntOptionNamed (options, "x", 0);
+ y = CompOption::getIntOptionNamed (options, "y", 0);
+
+ src = grabbedOutput = screen->outputDeviceForPoint (x, y);
+
+ /* trace source */
+ while (it != clones.end ())
+ {
+ if ((*it)->dst == src)
+ {
+ src = (*it)->src;
+ it = clones.begin ();
+ }
+ else
+ {
+ it++;
+ }
+ }
+
+ togglePaintFunctions (this, true);
+
+ if (state & CompAction::StateInitButton)
+ action->setState (action->state () | CompAction::StateTermButton);
+
+ return true;
+
+}
+
+bool
+CloneScreen::terminate (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector options)
+{
+ if (grabHandle)
+ {
+ int x, y;
+
+ screen->removeGrab (grabHandle, NULL);
+ grabHandle = NULL;
+
+ x = CompOption::getIntOptionNamed (options, "x", 0);
+ y = CompOption::getIntOptionNamed (options, "y", 0);
+
+ dst = screen->outputDeviceForPoint (x, y);
+
+ cScreen->damageScreen ();
+ }
+
+ action->setState (action->state () & ~(CompAction::StateTermKey |
+ CompAction::StateTermButton));
+
+ return false;
+}
+
+void
+CloneScreen::setStrutsForCloneWindow (Clone *clone)
+{
+ CompOutput *output = &screen->outputDevs ()[clone->dst];
+ X