Merge remote-tracking branch 'nobled/wayland-fixes2'
authorEmmanuele Bassi <ebassi@linux.intel.com>
Fri, 11 Feb 2011 16:45:45 +0000 (16:45 +0000)
committerEmmanuele Bassi <ebassi@linux.intel.com>
Fri, 11 Feb 2011 16:45:45 +0000 (16:45 +0000)
* nobled/wayland-fixes2:
  wayland: fix shm buffers
  wayland: set renderable type on dummy surface
  wayland: check for egl extensions explicitly
  wayland: fall back to shm buffers if drm fails
  wayland: add shm buffer code
  wayland: make buffer handling generic
  wayland: really fix buffer format selection
  wayland: fix pixel format
  wayland: clean up buffer creation code
  wayland: don't require the surfaceless extensions
  wayland: check for API-specific surfaceless extension
  wayland: fix GLES context creation
  wayland: use EGL_NO_SURFACE
  wayland: update to new api
  wayland: fix connecting to default socket
  fix ClutterContainer docs

261 files changed:
.gitignore
Makefile.am
NEWS
README
build/clutter.modules
clutter/Makefile.am
clutter/cally/cally-actor.c
clutter/cally/cally.pc.in
clutter/clutter-actor-private.h
clutter/clutter-actor.c
clutter/clutter-actor.h
clutter/clutter-align-constraint.c
clutter/clutter-align-constraint.h
clutter/clutter-alpha.c
clutter/clutter-animator.c
clutter/clutter-backend-private.h
clutter/clutter-backend.c
clutter/clutter-backend.h
clutter/clutter-behaviour-depth.c
clutter/clutter-behaviour-depth.h
clutter/clutter-behaviour-ellipse.c
clutter/clutter-behaviour-ellipse.h
clutter/clutter-behaviour-opacity.c
clutter/clutter-behaviour-opacity.h
clutter/clutter-behaviour-path.c
clutter/clutter-behaviour-path.h
clutter/clutter-behaviour-rotate.c
clutter/clutter-behaviour-rotate.h
clutter/clutter-behaviour-scale.c
clutter/clutter-behaviour-scale.h
clutter/clutter-behaviour.c
clutter/clutter-behaviour.h
clutter/clutter-bind-constraint.c
clutter/clutter-bind-constraint.h
clutter/clutter-binding-pool.c
clutter/clutter-binding-pool.h
clutter/clutter-blur-effect.c
clutter/clutter-blur-effect.h
clutter/clutter-click-action.c
clutter/clutter-click-action.h
clutter/clutter-clone.c
clutter/clutter-color.c
clutter/clutter-color.h
clutter/clutter-colorize-effect.c
clutter/clutter-colorize-effect.h
clutter/clutter-config.h.in [new file with mode: 0644]
clutter/clutter-container.c
clutter/clutter-container.h
clutter/clutter-debug.h
clutter/clutter-desaturate-effect.c
clutter/clutter-desaturate-effect.h
clutter/clutter-device-manager-private.h
clutter/clutter-device-manager.c
clutter/clutter-device-manager.h
clutter/clutter-drag-action.c
clutter/clutter-event-translator.c [new file with mode: 0644]
clutter/clutter-event-translator.h [new file with mode: 0644]
clutter/clutter-event.c
clutter/clutter-event.h
clutter/clutter-frame-source.h
clutter/clutter-input-device.c
clutter/clutter-input-device.h
clutter/clutter-list-model.c
clutter/clutter-main.c
clutter/clutter-marshal.list
clutter/clutter-model.c
clutter/clutter-model.h
clutter/clutter-offscreen-effect.c
clutter/clutter-page-turn-effect.c
clutter/clutter-page-turn-effect.h
clutter/clutter-path-constraint.c
clutter/clutter-path-constraint.h
clutter/clutter-private.h
clutter/clutter-rectangle.c
clutter/clutter-script-parser.c
clutter/clutter-settings.c
clutter/clutter-settings.h
clutter/clutter-shader.c
clutter/clutter-snap-constraint.c
clutter/clutter-snap-constraint.h
clutter/clutter-stage-private.h
clutter/clutter-stage-window.c
clutter/clutter-stage-window.h
clutter/clutter-stage.c
clutter/clutter-text.c
clutter/clutter-timeline.c
clutter/clutter-timeline.h
clutter/clutter-timeout-pool.c
clutter/clutter-timeout-pool.h
clutter/clutter-types.h
clutter/clutter.h
clutter/cogl/cogl/Makefile.am
clutter/cogl/cogl/cogl-atlas-texture.c
clutter/cogl/cogl/cogl-attribute-private.h [new file with mode: 0644]
clutter/cogl/cogl/cogl-attribute.c [moved from clutter/cogl/cogl/cogl-vertex-attribute.c with 74% similarity]
clutter/cogl/cogl/cogl-attribute.h [moved from clutter/cogl/cogl/cogl-vertex-attribute.h with 64% similarity]
clutter/cogl/cogl/cogl-bitmap-pixbuf.c
clutter/cogl/cogl/cogl-bitmap-private.h
clutter/cogl/cogl/cogl-bitmap.c
clutter/cogl/cogl/cogl-blend-string.c
clutter/cogl/cogl/cogl-buffer-private.h
clutter/cogl/cogl/cogl-buffer.c
clutter/cogl/cogl/cogl-clip-stack.c
clutter/cogl/cogl/cogl-clip-stack.h
clutter/cogl/cogl/cogl-clip-state.c
clutter/cogl/cogl/cogl-clip-state.h
clutter/cogl/cogl/cogl-context.c
clutter/cogl/cogl/cogl-context.h
clutter/cogl/cogl/cogl-debug-options.h
clutter/cogl/cogl/cogl-debug.c
clutter/cogl/cogl/cogl-debug.h
clutter/cogl/cogl/cogl-framebuffer-private.h
clutter/cogl/cogl/cogl-framebuffer.c
clutter/cogl/cogl/cogl-index-array.c
clutter/cogl/cogl/cogl-journal-private.h
clutter/cogl/cogl/cogl-journal.c
clutter/cogl/cogl/cogl-matrix-private.h
clutter/cogl/cogl/cogl-matrix.c
clutter/cogl/cogl/cogl-matrix.h
clutter/cogl/cogl/cogl-object-private.h
clutter/cogl/cogl/cogl-object.c
clutter/cogl/cogl/cogl-path-private.h
clutter/cogl/cogl/cogl-pipeline-fragend-arbfp.c
clutter/cogl/cogl/cogl-pipeline-fragend-fixed.c
clutter/cogl/cogl/cogl-pipeline-fragend-glsl.c
clutter/cogl/cogl/cogl-pipeline-opengl.c
clutter/cogl/cogl/cogl-pipeline-private.h
clutter/cogl/cogl/cogl-pipeline-progend-glsl-private.h
clutter/cogl/cogl/cogl-pipeline-progend-glsl.c
clutter/cogl/cogl/cogl-pipeline-vertend-fixed.c
clutter/cogl/cogl/cogl-pipeline-vertend-glsl.c
clutter/cogl/cogl/cogl-pipeline.c
clutter/cogl/cogl/cogl-point-in-poly-private.h [new file with mode: 0644]
clutter/cogl/cogl/cogl-point-in-poly.c [new file with mode: 0644]
clutter/cogl/cogl/cogl-primitive.c
clutter/cogl/cogl/cogl-primitive.h
clutter/cogl/cogl/cogl-primitives.c
clutter/cogl/cogl/cogl-profile.c
clutter/cogl/cogl/cogl-program.c
clutter/cogl/cogl/cogl-rectangle-map.c
clutter/cogl/cogl/cogl-shader-boilerplate.h
clutter/cogl/cogl/cogl-shader.c
clutter/cogl/cogl/cogl-sub-texture.c
clutter/cogl/cogl/cogl-texture-2d-sliced.c
clutter/cogl/cogl/cogl-texture-2d.c
clutter/cogl/cogl/cogl-texture-3d.c
clutter/cogl/cogl/cogl-texture-private.h
clutter/cogl/cogl/cogl-texture-rectangle.c
clutter/cogl/cogl/cogl-texture.c
clutter/cogl/cogl/cogl-types.h
clutter/cogl/cogl/cogl-util.c
clutter/cogl/cogl/cogl-util.h
clutter/cogl/cogl/cogl-vertex-attribute-private.h [deleted file]
clutter/cogl/cogl/cogl-vertex-buffer-private.h
clutter/cogl/cogl/cogl-vertex-buffer.c
clutter/cogl/cogl/cogl-vertex-buffer.h
clutter/cogl/cogl/cogl.c
clutter/cogl/cogl/cogl.h
clutter/cogl/cogl/cogl2-path.c
clutter/cogl/cogl/driver/gl/cogl-feature-functions-gl.h
clutter/cogl/cogl/driver/gles/cogl-feature-functions-gles.h
clutter/cogl/cogl/driver/gles/cogl-gles.c
clutter/cogl/cogl/driver/gles/cogl-texture-driver-gles.c
clutter/cogl/cogl/winsys/cogl-texture-pixmap-x11.c
clutter/egl/clutter-backend-egl.c
clutter/egl/clutter-event-tslib.c
clutter/egl/clutter-stage-egl.c
clutter/egl/clutter-stage-egl.h
clutter/evdev/clutter-device-manager-evdev.c
clutter/fruity/clutter-backend-fruity.c
clutter/glx/clutter-backend-glx.c
clutter/glx/clutter-event-glx.c [deleted file]
clutter/glx/clutter-glx-texture-pixmap.c
clutter/glx/clutter-glx-texture-pixmap.h
clutter/glx/clutter-stage-glx.c
clutter/glx/clutter-stage-glx.h
clutter/osx/clutter-backend-osx.c
clutter/osx/clutter-backend-osx.h
clutter/osx/clutter-device-manager-osx.c [new file with mode: 0644]
clutter/osx/clutter-device-manager-osx.h [new file with mode: 0644]
clutter/osx/clutter-event-loop-osx.c [new file with mode: 0644]
clutter/osx/clutter-event-loop-osx.h [moved from clutter/glx/clutter-event-glx.h with 61% similarity]
clutter/osx/clutter-event-osx.c
clutter/osx/clutter-stage-osx.c
clutter/osx/clutter-stage-osx.h
clutter/wayland/clutter-input-device-wayland.c
clutter/wayland/clutter-stage-wayland.c
clutter/win32/clutter-backend-win32.c
clutter/win32/clutter-device-manager-win32.c
clutter/win32/clutter-event-win32.c
clutter/win32/clutter-stage-win32.c
clutter/x11/clutter-backend-x11.c
clutter/x11/clutter-backend-x11.h
clutter/x11/clutter-device-manager-core-x11.c [new file with mode: 0644]
clutter/x11/clutter-device-manager-core-x11.h [moved from clutter/x11/clutter-device-manager-x11.h with 89% similarity]
clutter/x11/clutter-device-manager-x11.c [deleted file]
clutter/x11/clutter-device-manager-xi2.c [new file with mode: 0644]
clutter/x11/clutter-device-manager-xi2.h [new file with mode: 0644]
clutter/x11/clutter-event-x11.c
clutter/x11/clutter-input-device-core-x11.c [new file with mode: 0644]
clutter/x11/clutter-input-device-core-x11.h [new file with mode: 0644]
clutter/x11/clutter-input-device-x11.c [deleted file]
clutter/x11/clutter-input-device-x11.h [deleted file]
clutter/x11/clutter-input-device-xi2.c [new file with mode: 0644]
clutter/x11/clutter-input-device-xi2.h [new file with mode: 0644]
clutter/x11/clutter-keymap-x11.c
clutter/x11/clutter-keymap-x11.h
clutter/x11/clutter-stage-x11.c
clutter/x11/clutter-stage-x11.h
clutter/x11/clutter-x11-texture-pixmap.c
configure.ac
doc/HACKING.backends
doc/cookbook/Makefile.am
doc/cookbook/actors.xml
doc/cookbook/animations.xml
doc/cookbook/examples/Makefile.am
doc/cookbook/examples/actors-composite-main.c [new file with mode: 0644]
doc/cookbook/examples/animations-path-circle.c [new file with mode: 0644]
doc/cookbook/examples/animations-path-easing.c [new file with mode: 0644]
doc/cookbook/examples/animations-path.c [new file with mode: 0644]
doc/cookbook/examples/cb-button.c [new file with mode: 0644]
doc/cookbook/examples/cb-button.h [new file with mode: 0644]
doc/cookbook/videos/animations-path.ogv [new file with mode: 0644]
doc/reference/clutter/Makefile.am
doc/reference/clutter/clutter-sections.txt
doc/reference/cogl-2.0/cogl-docs.xml.in
doc/reference/cogl/cogl-docs.xml.in
po/clutter-1.0.pot
po/de.po
po/fr.po
po/id.po
po/it.po
po/pl.po
po/zh_CN.po
tests/conform/Makefile.am
tests/conform/test-cogl-pipeline-user-matrix.c [new file with mode: 0644]
tests/conform/test-cogl-primitive.c
tests/conform/test-conform-main.c
tests/conform/test-model.c
tests/conform/test-path.c
tests/conform/test-timeline-rewind.c
tests/data/test-script-model.json
tests/interactive/test-actors.c
tests/interactive/test-clip.c
tests/interactive/test-cogl-offscreen.c
tests/interactive/test-cogl-primitives.c
tests/interactive/test-cogl-shader-glsl.c
tests/interactive/test-cogl-tex-convert.c
tests/interactive/test-cogl-tex-foreign.c
tests/interactive/test-cogl-tex-getset.c
tests/interactive/test-cogl-tex-polygon.c
tests/interactive/test-cogl-tex-tile.c
tests/interactive/test-cogl-vertex-buffer.c
tests/interactive/test-constraints.c
tests/interactive/test-devices.c
tests/interactive/test-flow-layout.c
tests/interactive/test-paint-wrapper.c
tests/interactive/test-pixmap.c
tests/interactive/test-shader.c
tests/interactive/test-textures.c
tests/micro-bench/test-picking.c

index 68ff6d4..04a2e6c 100644 (file)
@@ -15,6 +15,7 @@ compile
 stamp-enum-types
 stamp-marshal
 /ChangeLog*
+/clutter/clutter-config.h
 /clutter/clutter-enum-types.[ch]
 /clutter/clutter-marshal.[ch]
 /clutter/clutter-version.h
index 11bfa7d..73a7271 100644 (file)
@@ -17,7 +17,7 @@ CLEANFILES = $(pcfiles)
 
 DISTCLEANFILES =
 
-DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-maintainer-flags
+DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-maintainer-flags --enable-docs
 
 # Extra clean files so that maintainer-clean removes *everything*
 MAINTAINERCLEANFILES =         \
diff --git a/NEWS b/NEWS
index 8993ee6..bb16442 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,201 @@
+Clutter 1.6.2                                                        2011-02-07
+===============================================================================
+
+  • List of changes since Clutter 1.6.0
+
+    » Fix building the Clutter Cookbook from the released tarballs.
+
+    » Set the input device field in ClutterEvent even when they
+      have been allocated by Clutter.
+
+    » Fix the color comparison when setting the layer combine constant.
+
+    » Fix memory corruption when removing the last reference on a
+      Cogl vertex buffer object.
+
+    » Fixes for the OSX backend.
+
+  • List of bugs fixed since Clutter 1.6.0
+
+    #2540 - coobook examples do not build from tarball
+    #2544 - Using vertex buffers causes memory corruption when you unref
+            the CoglHandle
+    #2545 - Broken event handling in OS X backend
+    #2549 - Fix lib locations in *.pc.in
+
+Many thanks to:
+
+  Neil Roberts, Viatcheslav Gachkaylo
+
+Clutter 1.6.0                                                        2011-01-31
+===============================================================================
+
+  • List of changes since Clutter 1.5.14
+
+    » Remove more private symbols from the X11 backend.
+
+    » Add CLUTTER_BIND_POSITION and CLUTTER_BIND_SIZE values to the
+      ClutterBindCoordinate enumeration; these are short-hand values
+      for binding both X and Y, or width and height, instead of
+      requiring two ClutterBindConstraint instances.
+
+    » Clean up in the X11 backend to reduce indirection.
+
+    » Small clean ups in the Win32 backend.
+
+    » Make Shift+Backspace behave like Backspace in ClutterText.
+
+    » Emit the ::new-frame signal even on the first frame of
+      ClutterTimeline, to allow setting up the initial state of an
+      animation.
+
+    » Fix an invalid memory access in ClutterAnimator.
+
+    » Flush the per-framebuffer journal when switching between
+      framebuffers.
+
+    » Generalize updating GLES2 uniforms.
+
+    » Add debug code for tracing clipping in Cogl.
+
+    » Improve the OSX event loop, re-using the same implementation
+      as GDK. Also, provide simple, core-like device support.
+
+  • Bugs fixed since Clutter 1.5.14
+
+    #2490 - OS X backend event loop improved
+    #2530 - animator: Animator uses key after freeing it
+    #2534 - Incorrect description of function 'clutter_actor_pop_internal'
+    #2535 - Add recipe about creating a composite actor
+
+Many thanks to:
+
+  Neil Roberts, Robert Bragg, Elliot Smith, Rob Bradford,
+  Viatcheslav Gachkaylo
+
+Clutter 1.5.14                                                       2011-01-24
+===============================================================================
+
+  • List of changes since Clutter 1.5.12
+
+    » Allow getting the state modifiers from a ClutterClickAction.
+
+    » Fix ClutterDragAction to never leave the event delivery in
+      an unwanted state.
+
+    » Optimize state changes for texture and data states.
+
+    » Enable VBO support in Cogl for GLES2.
+
+    » Fix compilation on GLES1.1.
+
+    » Documentation fixes.
+
+    » ClutterGLXTexturePixmap has been deprecated; its parent class
+      ClutterX11TexturePixmap and the low level CoglTexturePixmapX11
+      API provide access to the same features.
+
+    » Be more resilient against timelines controlling the state of
+      other timelines during the clock tick.
+
+    » Provide defines for the windowing platforms, to allow portable
+      applications to include the correct header and select the
+      correct API depending on the target.
+
+    » Introduce a fast path for cogl_read_pixels() that uses the journal
+      to determine the position of a single pixel on the stage; this
+      fast path gracefully degrades to the usual render-based approach,
+      and should speed up picking considerably in the case of opaque
+      quads batched together.
+
+    » Support XInput axis data on valuator devices, and introduce XInput2
+      support for event translation and device hotplugging. The support
+      for XI and XI2 must still be explicitly enabled by the developer,
+      but it is now compiled in by default. It can be disabled at compile
+      time by passing --disable-xinput to the configure script.
+
+    » Clean up the unintentionally leaked internal symbols in the X11
+      and GLX backends.
+
+    » Allow defining the contents of the rows of a ListModel using
+      ClutterScript. This completes the ability to fully define a
+      ClutterListModel inside a UI definition file.
+
+  • Bugs fixed since Clutter 1.5.12
+
+    #1422, key input handler for eglnative
+    #1456, Hinting mishandling
+    #1721, XInput2 support
+    #2268, EGL backend dependent on X11 headers
+    #2400, Don't enable GL_POINT_SPRITE on GLES
+    #2497, should not throw away a program when just the texture
+           object has changed
+    #2512, shader: Don't notify properties when finalizing shaders
+    #2513, script-parser: Also honor properties of type GType
+    #2516, [PATCH] Fails to compile with --with-gles=1.1
+    #2518, introspection: Add missing (out) annotations for get_color()
+    #2520, Add API to get modifier type in ClutterClickAction
+    #2522, ClutterDragAction might indefinitely disable motion events
+    #2524, It's possible to receive a new-frame signal after stopping
+           a timeline
+    #2526, model: Fix some GObject-Introspection annotations
+    #2527, model: Change the column argument type to gint for
+           clutter_model_set_sort
+    #2528, model: Add support to define rows in ClutterScript
+
+Many thanks to:
+
+  Robert Bragg, Neil Roberts, Bastian Winkler, Lucas Rocha, Adel Gadllah,
+  Chris Lord, Damien Lespiau
+
+Clutter 1.5.12                                                       2011-01-11
+===============================================================================
+
+  • List of changes since Clutter 1.5.10
+
+    » Allow disabling the focus when showing a ClutterStage; this also
+      makes Clutter more compliant to the X11 window manager
+      specifications.
+
+    » Avoid state corruption in relayout cycles.
+
+    » Do not crash when destroying actors during CLUTTER_LEAVE events.
+
+    » Remove signal handlers when disposing constraints.
+
+    » Keep the pixel alignment for ClutterAlignConstraint.
+
+    » Do not release compiled ClutterShader during their finalization to
+      avoid a warning.
+
+    » Revert an ABI break on the ClutterContainer pre-requisites.
+
+    » Fix the name of the cogl_normal_in attribute.
+
+    » Do not assume CoglBitmaps are allocated to height * rowstride.
+
+    » Fix the core device list creation on X11.
+
+    » Avoid enabling blending in the Cogl journal, if possible.
+
+    » Documentation fixes.
+
+    » Build fixes for mixed autotools version environment.
+
+    » Improve the performance of getting the number of rows of a
+      ClutterListModel.
+
+    » Don't use obsolete API internally.
+
+    » Build fix for compiling EGL backend with OpenGL under X11.
+
+    » Parse GType object properties in ClutterScript.
+
+Many thanks to:
+
+  Neil Roberts, Johan Bilien, nobled, Adel Gadllah, Damien Lespiau,
+  Kristian Høgsberg, Nguyễn Thái Ngọc Duy, Tomeu Vizoso, Bastian Winkler
+
 Clutter 1.5.10                                                       2010-12-17
 ===============================================================================
 
diff --git a/README b/README
index 3bedaeb..dd3fb9f 100644 (file)
--- a/README
+++ b/README
@@ -9,25 +9,25 @@ REQUIREMENTS
 
 Clutter currently requires:
 
-  • GLib >= 2.26.0
-  • JSON-GLib >= 0.12
-  • Atk >= 1.17
-  • Cairo >= 1.10
-  • PangoCairo >= 1.20
-  • OpenGL >= 1.3 or 1.2+multitexturing, OpenGL ES 1.1 or OpenGL ES 2.0
+  • GLib  2.26.0
+  • JSON-GLib  0.12
+  • Atk  1.17
+  • Cairo  1.10
+  • PangoCairo  1.20
+  • OpenGL ≥ 1.3 (or 1.2+multitexturing), OpenGL ES 1.1 or OpenGL ES 2.0
   • GLX, SDL, WGL or an EGL Implementation
 
 Clutter also has optional dependencies:
 
-  • GDK-Pixbuf >= 2.0 (optional, see --with-imagebackend below)
+  • GDK-Pixbuf  2.0 (optional, see --with-imagebackend below)
 
 On X11, Clutter depends on the following extensions
 
-  • XComposite
+  • XComposite ≥ 0.4
   • XDamage
   • XExt
-  • XFixes
-  • XInput 1.x (if --enable-xinput is passed to configure)
+  • XFixes ≥ 3
+  • XInput 1.x or 2.x
   • XKB
 
 When running the OpenGL flavor, Clutter requires at least version 1.3
@@ -38,7 +38,7 @@ you will need the latest GL headers which can be obtained from:
 
 If you are building the API reference you will also need:
 
-  • GTK-Doc >= 1.13
+  • GTK-Doc  1.13
 
 If you are building the additional documentation you will also need:
 
@@ -47,7 +47,7 @@ If you are building the additional documentation you will also need:
 
 If you are building the Introspection data you will also need:
 
-  • GObject-Introspection >= 0.9.5
+  • GObject-Introspection  0.9.5
 
 GObject-Introspection is available from:
 
@@ -55,7 +55,7 @@ GObject-Introspection is available from:
 
 If you want support for profiling Clutter you will also need:
 
-  • UProf >= 0.3
+  • UProf  0.3
 
 UProf is available from:
 
@@ -78,7 +78,7 @@ New releases of Clutter are available at:
 
    http://source.clutter-project.org/sources/clutter/
 
-The Clutter blog is at:
+The Clutter blog is available at:
 
    http://www.clutter-project.org/blog/
 
@@ -148,9 +148,10 @@ Clutter has additional command line options for the configure script:
         no:
                 Disable support for COGL runtime debugging notes.
 
- --enable-maintainer-flags=[no/yes]
+ --enable-maintainer-flags=[no/yes/error]
         Use strict compiler flags. This defaults to 'yes' for developers
-        snapshots and to 'no' for stable releases.
+        snapshots and to 'no' for stable releases. If 'error' is used, then
+        -Werror will be enabled (if available).
 
  --enable-gtk-doc
        use gtk-doc to build API documentation (default=no). Requires gtk-doc
@@ -178,35 +179,44 @@ Clutter has additional command line options for the configure script:
         Select the Clutter backend: (default=glx)
 
        glx:
-                Fully featured GLX backend. Using Open GL.
+                Fully featured GLX backend.
+
+        opengl-egl-xlib:
+                EGL/Open GL backend for X11.
+
+        wayland:
+                EGL/Open GL backend for Wayland.
 
        eglx:
-                EGL/Open GL ES backend for EGL on X windows implementations
+                EGL/Open GL|ES backend for X11.
 
        eglnative:
-                EGL/Open GL ES backend on 'native windowing system' - i.e
+                EGL/Open GL|ES backend on 'native windowing system' - i.e
                raw framebuffer. Expects the EGL implementation to provide
-                a createNativeWindow() call. Also it optionally supports
-               tslib for touchscreen events.
+                a createNativeWindow() call.
+
+        cex100:
+                EGL/Open GL|ES backend on Intel CE3100 and CE4100 platforms.
+                Requires libgdl.
 
         osx:
                 OS X backend. (EXPERIMENTAL)
 
         win32:
-                Microsoft Windows(tm) WGL backend
+                Microsoft Windows(tm) WGL backend.
 
         fruity:
-                Apple iPod Touch(tm)/iPhone(tm) backend (EXPERIMENTAL)
+                Apple iPod Touch(tm)/iPhone(tm) backend. (EXPERIMENTAL)
 
  --with-imagebackend=[gdk-pixbuf/quartz/internal]
         Select the image loading backend used by COGL
 
         gdk-pixbuf:
                 Depend on gdk-pixbuf-2.0 (default for the glx, eglx,
-                eglnative, win32 flavours and recommended)
+                eglnative, win32 flavours and recommended).
 
         quartz:
-                Depend on CoreGraphics (default for the osx flavour)
+                Depend on CoreGraphics (default for the osx flavour).
 
         internal:
                 Internal JPEG and PNG loader. Should only be used
@@ -284,7 +294,7 @@ If diffing against the Git repository, you should use:
 
   git diff > clutter-patch.diff
 
-Or, better, commit locally and use `git format-patch` to generate a patch
+Or, better: commit locally and use `git format-patch` to generate a patch
 containing authorship details, so that members of the Clutter development
 team can credit your contribution properly.
 
@@ -318,6 +328,64 @@ Release Notes for Clutter 1.6
   both API are not integrated in the Clutter main loop, and are not used
   internally any longer, so they are of relative use.
 
+• It it not necessary any more to provide implementations for the
+  ClutterActor::map() and ClutterActor::unmap() virtual functions, even
+  for composite actors not implementing the ClutterContainer interface.
+
+• ClutterTimeline now guarantees that the ::new-frame signal will be
+  emitted at the beginning of the timeline, as well as guaranteeing that
+  the ::completed signal will be emitted at the end of the timeline.
+
+• ClutterActor will check for the enabled property of ClutterActorMeta
+  instances (actions, constraints and effects), and will not invoke
+  ClutterActorMeta functions on disabled instances. This removes the
+  requirement for checking the property inside the ClutterActorMeta
+  sub-classes.
+
+• ClutterActorBox, ClutterGeometry and ClutterVertex install a progress
+  function for ClutterInterval, allowing the interpolation of properties
+  using them as storage types.
+
+• ClutterColor's clutter_color_from_string() function accepts CSS3 color
+  specifications.
+
+• The previously unused "axes" field in the ClutterButtonEvent,
+  ClutterScrollEvent and ClutterMotionEvent structures is now used on
+  the X11-based backends with XInput support.
+
+• ClutterListModel will honour the filter function when calling
+  clutter_model_get_iter_at_row().
+
+• ClutterClickAction does not use a pointer grab any longer, and uses
+  a capture on the stage instead.
+
+• On all platforms which allow it, ClutterStage will ask the windowing
+  system for an explicit key focus when showing the stage window. This
+  can be disabled using clutter_stage_set_accept_focus().
+
+Release Notes for Cogl 1.6
+-------------------------------------------------------------------------------
+
+• Cogl may internally optimise cogl_read_pixels when only a single
+  pixel is drawn and the entire scene is comprised of solid colour
+  rectangles. Instead of actually rendering the rectangles it will
+  compute the single pixel value in software. This effectively means
+  that Clutter can do software picking without any API changes.
+
+• Internally Cogl now has a GLSL backend as well as the ARBfp and
+  fixed function backends. By default, this backend has the lowest
+  priority but it can be explicitly enabled by setting the
+  COGL_DEBUG environment variable, e.g.:
+
+    export COGL_DEBUG=disable-fixed,disable-arbfp
+
+  for builds of Clutter with debug support enabled.
+
+• Cogl will internally now cache generated ARBfp programs so that it
+  should be able to reuse a previous program even if it was generated
+  for an unrelated CoglMaterial. This makes using one-shot materials
+  less expensive than before although it is still not recommended.
+
 Release Notes for Clutter 1.4
 -------------------------------------------------------------------------------
 
index cff9b49..2acc98b 100644 (file)
@@ -4,7 +4,7 @@
 <!-- vim:set ts=2 expandtab: -->
 <moduleset>
   <repository type="git" name="git.freedesktop.org"
-      href="git://anongit.freedesktop.org/git/"/>
+      href="git://anongit.freedesktop.org/"/>
   <repository type="git" name="git.gnome.org"
       href="git://git.gnome.org/"/>
   <repository type="git" name="git.clutter-project.org"
 
   <autotools id="wayland">
     <branch repo="git.freedesktop.org"
-            module="~krh/wayland" checkoutdir="wayland"/>
+            module="wayland" checkoutdir="wayland"/>
     <dependencies>
       <dep package="mesa"/>
     </dependencies>
index 42c964e..811a7c5 100644 (file)
@@ -232,6 +232,7 @@ source_h_priv = \
        $(srcdir)/clutter-bezier.h                      \
        $(srcdir)/clutter-debug.h                       \
        $(srcdir)/clutter-device-manager-private.h      \
+       $(srcdir)/clutter-event-translator.h            \
        $(srcdir)/clutter-id-pool.h                     \
        $(srcdir)/clutter-keysyms-table.h               \
        $(srcdir)/clutter-master-clock.h                \
@@ -247,6 +248,7 @@ source_h_priv = \
 
 # private source code; these should not be introspected
 source_c_priv = \
+       $(srcdir)/clutter-event-translator.c    \
        $(srcdir)/clutter-id-pool.c             \
        $(srcdir)/clutter-profile.c             \
        $(srcdir)/clutter-timeout-interval.c    \
@@ -264,6 +266,10 @@ built_source_h = \
        clutter-marshal.h                       \
        $(NULL)
 
+# config header
+DISTCLEANFILES += clutter-config.h
+EXTRA_DIST += clutter-config.h.in
+
 # version header
 DISTCLEANFILES += clutter-version.h
 EXTRA_DIST += clutter-version.h.in
@@ -290,9 +296,9 @@ backend_source_built =
 # X11 backend rules
 x11_source_c = \
        $(srcdir)/x11/clutter-backend-x11.c             \
-       $(srcdir)/x11/clutter-device-manager-x11.c      \
+       $(srcdir)/x11/clutter-device-manager-core-x11.c \
        $(srcdir)/x11/clutter-event-x11.c               \
-       $(srcdir)/x11/clutter-input-device-x11.c        \
+       $(srcdir)/x11/clutter-input-device-core-x11.c   \
        $(srcdir)/x11/clutter-keymap-x11.c              \
        $(srcdir)/x11/clutter-stage-x11.c               \
        $(srcdir)/x11/clutter-x11-texture-pixmap.c      \
@@ -305,8 +311,8 @@ x11_source_h = \
 
 x11_source_h_priv = \
        $(srcdir)/x11/clutter-backend-x11.h             \
-       $(srcdir)/x11/clutter-device-manager-x11.h      \
-       $(srcdir)/x11/clutter-input-device-x11.h        \
+       $(srcdir)/x11/clutter-device-manager-core-x11.h \
+       $(srcdir)/x11/clutter-input-device-core-x11.h   \
        $(srcdir)/x11/clutter-keymap-x11.h              \
        $(srcdir)/x11/clutter-settings-x11.h            \
        $(srcdir)/x11/clutter-stage-x11.h               \
@@ -319,6 +325,18 @@ x11_source_c_priv = \
        $(srcdir)/x11/xsettings/xsettings-common.h      \
        $(NULL)
 
+if BUILD_XI2
+x11_source_c += \
+       $(srcdir)/x11/clutter-device-manager-xi2.c      \
+       $(srcdir)/x11/clutter-input-device-xi2.c        \
+       $(NULL)
+
+x11_source_h_priv += \
+       $(srcdir)/x11/clutter-device-manager-xi2.h      \
+       $(srcdir)/x11/clutter-input-device-xi2.h        \
+       $(NULL)
+endif # BUILD_XI2
+
 if SUPPORT_X11
 backend_source_h += $(x11_source_h)
 backend_source_c += $(x11_source_c)
@@ -341,7 +359,6 @@ endif # SUPPORT_X11
 # GLX backend rules
 glx_source_c = \
        $(srcdir)/glx/clutter-backend-glx.c             \
-       $(srcdir)/glx/clutter-event-glx.c               \
        $(srcdir)/glx/clutter-glx-texture-pixmap.c      \
        $(srcdir)/glx/clutter-stage-glx.c               \
        $(NULL)
@@ -353,7 +370,6 @@ glx_source_h = \
 
 glx_source_h_priv = \
        $(srcdir)/glx/clutter-backend-glx.h             \
-       $(srcdir)/glx/clutter-event-glx.h               \
        $(srcdir)/glx/clutter-stage-glx.h               \
        $(NULL)
 
@@ -484,10 +500,16 @@ osx_source_h = $(srcdir)/osx/clutter-osx.h
 
 osx_source_h_priv = \
        $(srcdir)/osx/clutter-backend-osx.h     \
+       $(srcdir)/osx/clutter-event-loop-osx.h  \
        $(srcdir)/osx/clutter-stage-osx.h       \
+       $(srcdir)/osx/clutter-device-manager-osx.h \
        $(NULL)
 
-osx_source_c_priv = $(srcdir)/osx/clutter-event-osx.c
+osx_source_c_priv = \
+       $(srcdir)/osx/clutter-event-loop-osx.c  \
+       $(srcdir)/osx/clutter-event-osx.c       \
+       $(srcdir)/osx/clutter-device-manager-osx.c \
+       $(NULL)
 
 if SUPPORT_OSX
 # we need to tell the compiler that part of our code base is
@@ -612,6 +634,7 @@ DISTCLEANFILES += $(pc_files)
 
 clutter_include_HEADERS = $(source_h) $(top_srcdir)/clutter/clutter.h
 nodist_clutter_include_HEADERS = \
+       $(top_builddir)/clutter/clutter-config.h \
        $(top_builddir)/clutter/clutter-version.h \
        $(built_source_h)
 
index 336bd4a..12eed7e 100644 (file)
@@ -1414,9 +1414,9 @@ cally_actor_add_action (CallyActor      *cally_actor,
  *
  * Return value: added action id, or -1 if failure
  *
- * Since: 1.6
- *
  * Rename to: cally_actor_add_action
+ *
+ * Since: 1.6
  */
 guint
 cally_actor_add_action_full (CallyActor          *cally_actor,
index dbb34fa..aa7030a 100644 (file)
@@ -12,6 +12,6 @@ requires=@CLUTTER_REQUIRES@
 Name: Cally
 Description: Clutter Accessibility Implementation Library
 Version: @VERSION@
-Libs: -L${libdir} -lclutter-${winsys}-${apiversion}
+Libs: -L${libdir} -lclutter-${soname_infix}-${apiversion}
 Cflags: -I${includedir}/clutter-${apiversion}
 Requires: atk clutter-1.0
index eb6ecc7..37bd7d5 100644 (file)
@@ -129,8 +129,10 @@ void _clutter_actor_rerealize (ClutterActor    *self,
                                ClutterCallback  callback,
                                gpointer         data);
 
-void _clutter_actor_set_opacity_parent (ClutterActor *self,
-                                        ClutterActor *parent);
+void _clutter_actor_set_opacity_override (ClutterActor *self,
+                                          gint          opacity);
+void _clutter_actor_set_in_clone_paint (ClutterActor *self,
+                                        gboolean      is_in_clone_paint);
 
 void _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
                                                      gboolean      enable);
index 6a256e6..0ee1914 100644 (file)
 #include "clutter-action.h"
 #include "clutter-actor-meta-private.h"
 #include "clutter-animatable.h"
+#include "clutter-behaviour.h"
 #include "clutter-constraint.h"
 #include "clutter-container.h"
 #include "clutter-debug.h"
 #include "clutter-stage-private.h"
 #include "clutter-units.h"
 
-#undef CLUTTER_DISABLE_DEPRECATED
-#include "clutter-behaviour.h"
-
 typedef struct _ShaderData ShaderData;
 typedef struct _AnchorCoord AnchorCoord;
 
@@ -414,6 +412,7 @@ struct _ClutterActorPrivate
   guint propagated_one_redraw       : 1;
   guint paint_volume_valid          : 1;
   guint last_paint_box_valid        : 1;
+  guint in_clone_paint              : 1;
 
   gfloat clip[4];
 
@@ -438,6 +437,7 @@ struct _ClutterActorPrivate
   gfloat z;
 
   guint8 opacity;
+  gint   opacity_override;
 
   ClutterActor   *parent_actor;
   GList          *children;
@@ -455,8 +455,6 @@ struct _ClutterActorPrivate
 
   PangoContext   *pango_context;
 
-  ClutterActor   *opacity_parent;
-
   ClutterTextDirection text_direction;
 
   gint internal_child;
@@ -2583,9 +2581,9 @@ clutter_actor_paint (ClutterActor *self)
   if (context->pick_mode == CLUTTER_PICK_NONE &&
       /* ignore top-levels, since they might be transparent */
       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
-      /* If the actor is being painted from a clone then check the
-         clone's opacity instead */
-      (priv->opacity_parent ? priv->opacity_parent->priv : priv)->opacity == 0)
+      /* Use the override opacity if its been set */
+      ((priv->opacity_override >= 0) ?
+       priv->opacity_override : priv->opacity) == 0)
     {
       priv->propagated_one_redraw = FALSE;
       return;
@@ -4321,11 +4319,22 @@ clutter_actor_class_init (ClutterActorClass *klass)
 
   /**
    * ClutterActor::destroy:
-   * @actor: the object which received the signal
+   * @actor: the #ClutterActor which emitted the signal
+   *
+   * The ::destroy signal notifies that all references held on the
+   * actor which emitted it should be released.
    *
-   * The ::destroy signal is emitted when an actor is destroyed,
-   * either by direct invocation of clutter_actor_destroy() or
-   * when the #ClutterGroup that contains the actor is destroyed.
+   * The ::destroy signal should be used by all holders of a reference
+   * on @actor.
+   *
+   * This signal might result in the finalization of the #ClutterActor
+   * if all references are released.
+   *
+   * Composite actors and actors implementing the #ClutterContainer
+   * interface should override the default implementation of the
+   * class handler of this signal and call clutter_actor_destroy() on
+   * their children. When overriding the default class handler, it is
+   * required to chain up to the parent's implementation.
    *
    * Since: 0.2
    */
@@ -4892,7 +4901,7 @@ clutter_actor_init (ClutterActor *self)
   priv->cached_width_age = 1;
   priv->cached_height_age = 1;
 
-  priv->opacity_parent = NULL;
+  priv->opacity_override = -1;
   priv->enable_model_view_transform = TRUE;
 
   /* Initialize an empty paint box to start with */
@@ -7056,8 +7065,8 @@ clutter_actor_get_paint_opacity_internal (ClutterActor *self)
   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
     return 255;
 
-  if (priv->opacity_parent != NULL)
-    return clutter_actor_get_paint_opacity_internal (priv->opacity_parent);
+  if (priv->opacity_override >= 0)
+    return priv->opacity_override;
 
   parent = priv->parent_actor;
 
@@ -7701,9 +7710,11 @@ invalidate_queue_redraw_entry (ClutterActor *self,
  *
  * Removes the parent of @self.
  *
- * This function should not be used in applications.  It should be called by
- * implementations of container actors, to dissociate a child from the
- * container.
+ * This function should not be used in applications.
+ *
+ * This function should only be called by implementations of the
+ * #ClutterContainer interface, or by composite actors that do
+ * not implicitly create their children.
  *
  * Since: 0.1.1
  */
@@ -10185,15 +10196,16 @@ clutter_actor_create_pango_layout (ClutterActor *self,
   return layout;
 }
 
-/* Allows overriding the parent traversed when querying an actors paint
- * opacity. Used by ClutterClone. */
+/* Allows overriding the calculated paint opacity. Used by ClutterClone and
+ * ClutterOffscreenEffect.
+ */
 void
-_clutter_actor_set_opacity_parent (ClutterActor *self,
-                                   ClutterActor *parent)
+_clutter_actor_set_opacity_override (ClutterActor *self,
+                                     gint          opacity)
 {
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
 
-  self->priv->opacity_parent = parent;
+  self->priv->opacity_override = opacity;
 }
 
 /* Allows you to disable applying the actors model view transform during
@@ -10557,6 +10569,14 @@ clutter_actor_get_transformation_matrix (ClutterActor *self,
   _clutter_actor_apply_modelview_transform (self, matrix);
 }
 
+void
+_clutter_actor_set_in_clone_paint (ClutterActor *self,
+                                   gboolean      is_in_clone_paint)
+{
+  g_return_if_fail (CLUTTER_IS_ACTOR (self));
+  self->priv->in_clone_paint = is_in_clone_paint;
+}
+
 /**
  * clutter_actor_is_in_clone_paint:
  * @self: a #ClutterActor
@@ -10577,20 +10597,9 @@ clutter_actor_get_transformation_matrix (ClutterActor *self,
 gboolean
 clutter_actor_is_in_clone_paint (ClutterActor *self)
 {
-  ClutterActorPrivate *priv;
-
   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
 
-  /* XXX - keep in sync with the overrides set by ClutterClone:
-   *
-   *  - opacity_parent != NULL
-   *  - enable_model_view_transform == FALSE
-   */
-
-  priv = self->priv;
-
-  return priv->opacity_parent != NULL &&
-         !priv->enable_model_view_transform;
+  return self->priv->in_clone_paint;
 }
 
 static void
@@ -10763,7 +10772,7 @@ clutter_actor_push_internal (ClutterActor *self)
  * clutter_actor_pop_internal:
  * @self: a #ClutterActor
  *
- * Disables the effects of clutter_actor_pop_internal()
+ * Disables the effects of clutter_actor_push_internal()
  *
  * Since: 1.2
  */
index 7a01aac..a3752a9 100644 (file)
@@ -236,7 +236,7 @@ struct _ClutterActorClass
   void (* parent_set)           (ClutterActor          *actor,
                                  ClutterActor          *old_parent);
 
-  void (* destroy)              (ClutterActor          *actor);
+  void (* destroy)              (ClutterActor          *self);
   void (* pick)                 (ClutterActor          *actor,
                                  const ClutterColor    *color);
 
@@ -284,7 +284,7 @@ struct _ClutterActorClass
   void     (* key_focus_in)         (ClutterActor         *actor);
   void     (* key_focus_out)        (ClutterActor         *actor);
 
-  void     (* queue_relayout)       (ClutterActor         *actor);
+  void     (* queue_relayout)       (ClutterActor         *self);
 
   /* accessibility support */
   AtkObject * (* get_accessible)    (ClutterActor         *self);
index a429df9..5951b33 100644 (file)
 #include "clutter-enum-types.h"
 #include "clutter-private.h"
 
+#include <math.h>
+
 #define CLUTTER_ALIGN_CONSTRAINT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ALIGN_CONSTRAINT, ClutterAlignConstraintClass))
 #define CLUTTER_IS_ALIGN_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ALIGN_CONSTRAINT))
 #define CLUTTER_ALIGN_CONSTRAINT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ALIGN_CONSTRAINT, ClutterAlignConstraintClass))
 
-typedef struct _ClutterAlignConstraintClass      ClutterAlignConstraintClass;
-
 struct _ClutterAlignConstraint
 {
   ClutterConstraint parent_instance;
@@ -136,6 +136,7 @@ clutter_align_constraint_update_allocation (ClutterConstraint *constraint,
       actor_width = clutter_actor_box_get_width (allocation);
       allocation->x1 = ((source_width - actor_width) * align->factor)
                      + source_x;
+      allocation->x1 = floorf (allocation->x1 + 0.5);
       allocation->x2 = allocation->x1 + actor_width;
       break;
 
@@ -143,6 +144,7 @@ clutter_align_constraint_update_allocation (ClutterConstraint *constraint,
       actor_height = clutter_actor_box_get_height (allocation);
       allocation->y1 = ((source_height - actor_height) * align->factor)
                      + source_y;
+      allocation->x1 = floorf (allocation->x1 + 0.5);
       allocation->y2 = allocation->y1 + actor_height;
       break;
 
index 6ab2256..8e8c583 100644 (file)
@@ -45,7 +45,8 @@ G_BEGIN_DECLS
  *
  * Since: 1.4
  */
-typedef struct _ClutterAlignConstraint  ClutterAlignConstraint;
+typedef struct _ClutterAlignConstraint          ClutterAlignConstraint;
+typedef struct _ClutterAlignConstraintClass     ClutterAlignConstraintClass;
 
 /**
  * ClutterAlignAxis:
index e65bf09..2628373 100644 (file)
@@ -149,7 +149,7 @@ static GParamSpec *obj_props[PROP_LAST];
 
 static void
 timeline_new_frame_cb (ClutterTimeline *timeline,
-                       guint            current_frame_num,
+                       guint            msecs,
                        ClutterAlpha    *alpha)
 {
   ClutterAlphaPrivate *priv = alpha->priv;
index b2c6127..a506d92 100644 (file)
@@ -1426,7 +1426,6 @@ again:
           ClutterAnimatorKey *prev_key = NULL;
           key->is_inert = is_inert;
 
-          clutter_animator_key_free (key);
 
           /* FIXME: non performant since we reiterate the list many times */
 
@@ -1446,6 +1445,8 @@ again:
                   next_key->ease_in = key->ease_in;
                 }
             }
+
+          clutter_animator_key_free (key);
           priv->score = g_list_remove (priv->score, key);
           goto again;
         }
index 9a69258..cc88903 100644 (file)
@@ -23,6 +23,7 @@
 #define __CLUTTER_BACKEND_PRIVATE_H__
 
 #include <clutter/clutter-backend.h>
+#include "clutter-event-translator.h"
 
 #define CLUTTER_BACKEND_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND, ClutterBackendClass))
 #define CLUTTER_IS_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND))
@@ -31,7 +32,6 @@
 G_BEGIN_DECLS
 
 typedef struct _ClutterBackendPrivate   ClutterBackendPrivate;
-typedef struct _ClutterBackendClass     ClutterBackendClass;
 
 struct _ClutterBackend
 {
@@ -72,6 +72,10 @@ struct _ClutterBackendClass
   void                  (* free_event_data)    (ClutterBackend     *backend,
                                                 ClutterEvent       *event);
 
+  gboolean              (* translate_event)    (ClutterBackend     *backend,
+                                                gpointer            native,
+                                                ClutterEvent       *event);
+
   /* signals */
   void (* resolution_changed) (ClutterBackend *backend);
   void (* font_changed)       (ClutterBackend *backend);
@@ -115,6 +119,16 @@ gfloat        _clutter_backend_get_units_per_em   (ClutterBackend       *backend
 
 gint32 _clutter_backend_get_units_serial (ClutterBackend *backend);
 
+gboolean      _clutter_backend_translate_event   (ClutterBackend   *backend,
+                                                  gpointer          native,
+                                                  ClutterEvent     *event);
+
+void          _clutter_backend_add_event_translator    (ClutterBackend         *backend,
+                                                        ClutterEventTranslator *translator);
+void          _clutter_backend_remove_event_translator (ClutterBackend         *backend,
+                                                        ClutterEventTranslator *translator);
+
+
 G_END_DECLS
 
 #endif /* __CLUTTER_BACKEND_PRIVATE_H__ */
index ff4c973..b677f41 100644 (file)
@@ -68,6 +68,8 @@ struct _ClutterBackendPrivate
 
   gfloat units_per_em;
   gint32 units_serial;
+
+  GList *event_translators;
 };
 
 enum
@@ -84,17 +86,16 @@ static guint backend_signals[LAST_SIGNAL] = { 0, };
 static void
 clutter_backend_dispose (GObject *gobject)
 {
-  ClutterMainContext *clutter_context;
+  ClutterBackendPrivate *priv = CLUTTER_BACKEND (gobject)->priv;
 
-  clutter_context = _clutter_context_get_default ();
+  /* clear the events still in the queue of the main context */
+  _clutter_clear_events_queue ();
 
-  if (clutter_context && clutter_context->events_queue)
+  /* remove all event translators */
+  if (priv->event_translators != NULL)
     {
-      g_queue_foreach (clutter_context->events_queue,
-                       (GFunc) clutter_event_free,
-                       NULL);
-      g_queue_free (clutter_context->events_queue);
-      clutter_context->events_queue = NULL;
+      g_list_free (priv->event_translators);
+      priv->event_translators = NULL;
     }
 
   G_OBJECT_CLASS (clutter_backend_parent_class)->dispose (gobject);
@@ -205,6 +206,51 @@ clutter_backend_real_font_changed (ClutterBackend *backend)
 }
 
 static void
+clutter_backend_real_redraw (ClutterBackend *backend,
+                             ClutterStage   *stage)
+{
+  ClutterStageWindow *impl;
+
+  if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
+    return;
+
+  impl = _clutter_stage_get_window (stage);
+  if (impl == NULL)
+    return;
+
+  _clutter_stage_window_redraw (impl);
+}
+
+static gboolean
+clutter_backend_real_translate_event (ClutterBackend *backend,
+                                      gpointer        native,
+                                      ClutterEvent   *event)
+{
+  ClutterBackendPrivate *priv = backend->priv;
+  GList *l;
+
+  for (l = priv->event_translators;
+       l != NULL;
+       l = l->next)
+    {
+      ClutterEventTranslator *translator = l->data;
+      ClutterTranslateReturn retval;
+
+      retval = _clutter_event_translator_translate_event (translator,
+                                                          native,
+                                                          event);
+
+      if (retval == CLUTTER_TRANSLATE_QUEUE)
+        return TRUE;
+
+      if (retval == CLUTTER_TRANSLATE_REMOVE)
+        return FALSE;
+    }
+
+  return FALSE;
+}
+
+static void
 clutter_backend_class_init (ClutterBackendClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
@@ -243,6 +289,8 @@ clutter_backend_class_init (ClutterBackendClass *klass)
 
   klass->resolution_changed = clutter_backend_real_resolution_changed;
   klass->font_changed = clutter_backend_real_font_changed;
+  klass->translate_event = clutter_backend_real_translate_event;
+  klass->redraw = clutter_backend_real_redraw;
 }
 
 static void
@@ -333,7 +381,6 @@ void
 _clutter_backend_redraw (ClutterBackend *backend,
                          ClutterStage   *stage)
 {
-  ClutterBackendClass *klass;
   CLUTTER_STATIC_COUNTER (redraw_counter,
                           "_clutter_backend_redraw counter",
                           "Increments for each _clutter_backend_redraw call",
@@ -347,9 +394,7 @@ _clutter_backend_redraw (ClutterBackend *backend,
   CLUTTER_COUNTER_INC (_clutter_uprof_context, redraw_counter);
   CLUTTER_TIMER_START (_clutter_uprof_context, redraw_timer);
 
-  klass = CLUTTER_BACKEND_GET_CLASS (backend);
-  if (G_LIKELY (klass->redraw))
-    klass->redraw (backend, stage);
+  CLUTTER_BACKEND_GET_CLASS (backend)->redraw (backend, stage);
 
   CLUTTER_TIMER_STOP (_clutter_uprof_context, redraw_timer);
 }
@@ -499,8 +544,6 @@ _clutter_backend_init_events (ClutterBackend *backend)
   g_return_if_fail (CLUTTER_IS_BACKEND (backend));
   g_return_if_fail (clutter_context != NULL);
 
-  clutter_context->events_queue = g_queue_new ();
-
   klass = CLUTTER_BACKEND_GET_CLASS (backend);
   if (klass->init_events)
     klass->init_events (backend);
@@ -881,3 +924,41 @@ _clutter_backend_get_units_serial (ClutterBackend *backend)
 
   return backend->priv->units_serial;
 }
+
+gboolean
+_clutter_backend_translate_event (ClutterBackend *backend,
+                                  gpointer        native,
+                                  ClutterEvent   *event)
+{
+  g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), FALSE);
+
+  return CLUTTER_BACKEND_GET_CLASS (backend)->translate_event (backend,
+                                                               native,
+                                                               event);
+}
+
+void
+_clutter_backend_add_event_translator (ClutterBackend         *backend,
+                                       ClutterEventTranslator *translator)
+{
+  ClutterBackendPrivate *priv = backend->priv;
+
+  if (g_list_find (priv->event_translators, translator) != NULL)
+    return;
+
+  priv->event_translators =
+    g_list_prepend (priv->event_translators, translator);
+}
+
+void
+_clutter_backend_remove_event_translator (ClutterBackend         *backend,
+                                          ClutterEventTranslator *translator)
+{
+  ClutterBackendPrivate *priv = backend->priv;
+
+  if (g_list_find (priv->event_translators, translator) == NULL)
+    return;
+
+  priv->event_translators =
+    g_list_remove (priv->event_translators, translator);
+}
index 9b74f09..1d18b32 100644 (file)
@@ -45,7 +45,16 @@ G_BEGIN_DECLS
 #define CLUTTER_BACKEND(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND, ClutterBackend))
 #define CLUTTER_IS_BACKEND(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND))
 
+/**
+ * ClutterBackend:
+ *
+ * <structname>ClutterBackend</structname> is an opaque structure whose
+ * members cannot be directly accessed.
+ *
+ * Since: 0.4
+ */
 typedef struct _ClutterBackend          ClutterBackend;
+typedef struct _ClutterBackendClass     ClutterBackendClass;
 
 GType clutter_backend_get_type    (void) G_GNUC_CONST;
 
index 1f22f28..eaf630b 100644 (file)
@@ -27,7 +27,6 @@
 #include "config.h"
 #endif
 
-#undef CLUTTER_DISABLE_DEPRECATED
 #include "clutter-behaviour-depth.h"
 
 #include "clutter-enum-types.h"
index aa701b2..81f0cd3 100644 (file)
@@ -35,7 +35,7 @@
 
 G_BEGIN_DECLS
 
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 
 #define CLUTTER_TYPE_BEHAVIOUR_DEPTH            (clutter_behaviour_depth_get_type ())
 #define CLUTTER_BEHAVIOUR_DEPTH(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BEHAVIOUR_DEPTH, ClutterBehaviourDepth))
index 0414e8f..2502215 100644 (file)
@@ -47,7 +47,6 @@
 #include <math.h>
 #include <stdlib.h>
 
-#undef CLUTTER_DISABLE_DEPRECATED
 #include "clutter-behaviour-ellipse.h"
 
 #include "clutter-debug.h"
index 4802009..302d4f2 100644 (file)
@@ -35,7 +35,7 @@
 
 G_BEGIN_DECLS
 
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 
 #define CLUTTER_TYPE_BEHAVIOUR_ELLIPSE (clutter_behaviour_ellipse_get_type ())
 
index eadc638..46dd838 100644 (file)
@@ -38,7 +38,6 @@
 
 #include <math.h>
 
-#undef CLUTTER_DISABLE_DEPRECATED
 #include "clutter-behaviour-opacity.h"
 
 #include "clutter-private.h"
index f5624e1..aa38ddb 100644 (file)
@@ -35,7 +35,7 @@
 
 G_BEGIN_DECLS
 
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 
 #define CLUTTER_TYPE_BEHAVIOUR_OPACITY (clutter_behaviour_opacity_get_type ())
 
index 811e787..29ca9ec 100644 (file)
@@ -64,7 +64,6 @@
 #include "config.h"
 #endif
 
-#undef CLUTTER_DISABLE_DEPRECATED
 #include "clutter-behaviour-path.h"
 
 #include "clutter-bezier.h"
index 2c3d92f..731aebd 100644 (file)
@@ -36,7 +36,7 @@
 
 G_BEGIN_DECLS
 
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 
 #define CLUTTER_TYPE_BEHAVIOUR_PATH (clutter_behaviour_path_get_type ())
 
index 5dde385..a149c68 100644 (file)
@@ -35,7 +35,6 @@
 #include "config.h"
 #endif
 
-#undef CLUTTER_DISABLE_DEPRECATED
 #include "clutter-behaviour-rotate.h"
 
 #include <math.h>
index 4298397..c30aef9 100644 (file)
@@ -34,7 +34,7 @@
 
 G_BEGIN_DECLS
 
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 
 #define CLUTTER_TYPE_BEHAVIOUR_ROTATE            (clutter_behaviour_rotate_get_type ())
 #define CLUTTER_BEHAVIOUR_ROTATE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BEHAVIOUR_ROTATE, ClutterBehaviourRotate))
index 5b1679b..0c0ebc3 100644 (file)
@@ -37,7 +37,6 @@
 
 #include <math.h>
 
-#undef CLUTTER_DISABLE_DEPRECATED
 #include "clutter-behaviour-scale.h"
 
 #include "clutter-debug.h"
index 849d0c0..3671cab 100644 (file)
@@ -34,7 +34,7 @@
 
 G_BEGIN_DECLS
 
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 
 #define CLUTTER_TYPE_BEHAVIOUR_SCALE            (clutter_behaviour_scale_get_type ())
 #define CLUTTER_BEHAVIOUR_SCALE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BEHAVIOUR_SCALE, ClutterBehaviourScale))
index 5d56b29..3571517 100644 (file)
@@ -71,7 +71,6 @@
 #include "config.h"
 #endif
 
-#undef CLUTTER_DISABLE_DEPRECATED
 #include "clutter-behaviour.h"
 
 #include "clutter-debug.h"
index 4d250da..7f7ddf0 100644 (file)
@@ -36,7 +36,7 @@
 
 G_BEGIN_DECLS
 
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 
 #define CLUTTER_TYPE_BEHAVIOUR clutter_behaviour_get_type()
 
@@ -159,7 +159,7 @@ void          clutter_behaviour_set_alpha      (ClutterBehaviour            *beh
 gboolean      clutter_behaviour_is_applied     (ClutterBehaviour            *behave,
                                                ClutterActor                *actor);
 
-#endif /* CLUTTER_DISABLE_DEPRECATED */
+#endif /* !CLUTTER_DISABLE_DEPRECATED || CLUTTER_COMPILATION */
 
 G_END_DECLS
 
index a655fb9..984aed3 100644 (file)
@@ -97,8 +97,6 @@
 #define CLUTTER_IS_BIND_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BIND_CONSTRAINT))
 #define CLUTTER_BIND_CONSTRAINT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BIND_CONSTRAINT, ClutterBindConstraintClass))
 
-typedef struct _ClutterBindConstraintClass      ClutterBindConstraintClass;
-
 struct _ClutterBindConstraint
 {
   ClutterConstraint parent_instance;
@@ -177,6 +175,13 @@ clutter_bind_constraint_update_allocation (ClutterConstraint *constraint,
       allocation->y2 = allocation->y1 + actor_height;
       break;
 
+    case CLUTTER_BIND_POSITION:
+      allocation->x1 = source_position.x + bind->offset;
+      allocation->y1 = source_position.y + bind->offset;
+      allocation->x2 = allocation->x1 + actor_width;
+      allocation->y2 = allocation->y1 + actor_height;
+      break;
+
     case CLUTTER_BIND_WIDTH:
       allocation->x2 = allocation->x1 + source_width + bind->offset;
       break;
@@ -185,6 +190,11 @@ clutter_bind_constraint_update_allocation (ClutterConstraint *constraint,
       allocation->y2 = allocation->y1 + source_height + bind->offset;
       break;
 
+    case CLUTTER_BIND_SIZE:
+      allocation->x2 = allocation->x1 + source_width + bind->offset;
+      allocation->y2 = allocation->y1 + source_height + bind->offset;
+      break;
+
     default:
       g_assert_not_reached ();
       break;
index b88bfa4..d5486c1 100644 (file)
@@ -45,7 +45,8 @@ G_BEGIN_DECLS
  *
  * Since: 1.4
  */
-typedef struct _ClutterBindConstraint   ClutterBindConstraint;
+typedef struct _ClutterBindConstraint           ClutterBindConstraint;
+typedef struct _ClutterBindConstraintClass      ClutterBindConstraintClass;
 
 /**
  * ClutterBindCoordinate:
@@ -53,6 +54,10 @@ typedef struct _ClutterBindConstraint   ClutterBindConstraint;
  * @CLUTTER_BIND_Y: Bind the Y coordinate
  * @CLUTTER_BIND_WIDTH: Bind the width
  * @CLUTTER_BIND_HEIGHT: Bidng the height
+ * @CLUTTER_BIND_POSITION: Equivalent to to %CLUTTER_BIND_X and
+ *   %CLUTTER_BIND_Y
+ * @CLUTTER_BIND_SIZE: Equivalent to %CLUTTER_BIND_WIDTH and
+ *   %CLUTTER_BIND_HEIGHT
  *
  * Specifies which property should be used in a binding
  *
@@ -62,7 +67,9 @@ typedef enum { /*< prefix=CLUTTER_BIND >*/
   CLUTTER_BIND_X,
   CLUTTER_BIND_Y,
   CLUTTER_BIND_WIDTH,
-  CLUTTER_BIND_HEIGHT
+  CLUTTER_BIND_HEIGHT,
+  CLUTTER_BIND_POSITION,
+  CLUTTER_BIND_SIZE
 } ClutterBindCoordinate;
 
 GType clutter_bind_constraint_get_type (void) G_GNUC_CONST;
index 11cef92..11fbf18 100644 (file)
                                   CLUTTER_HYPER_MASK   | \
                                   CLUTTER_META_MASK)   | CLUTTER_RELEASE_MASK)
 
-typedef struct _ClutterBindingPoolClass ClutterBindingPoolClass;
 typedef struct _ClutterBindingEntry     ClutterBindingEntry;
 
 static GSList *clutter_binding_pools = NULL;
index fd85f26..7fc7408 100644 (file)
@@ -46,6 +46,7 @@ G_BEGIN_DECLS
  * Since: 1.0
  */
 typedef struct _ClutterBindingPool      ClutterBindingPool;
+typedef struct _ClutterBindingPoolClass ClutterBindingPoolClass;
 
 /**
  * ClutterBindingActionFunc:
index e6e51e2..eb2bd57 100644 (file)
@@ -51,8 +51,6 @@
 
 #define BLUR_PADDING    2
 
-typedef struct _ClutterBlurEffectClass  ClutterBlurEffectClass;
-
 /* FIXME - lame shader; we should really have a decoupled
  * horizontal/vertical two pass shader for the gaussian blur
  */
index 130fd09..27466bb 100644 (file)
@@ -46,6 +46,7 @@ G_BEGIN_DECLS
  * Since: 1.4
  */
 typedef struct _ClutterBlurEffect       ClutterBlurEffect;
+typedef struct _ClutterBlurEffectClass  ClutterBlurEffectClass;
 
 GType clutter_blur_effect_get_type (void) G_GNUC_CONST;
 
index 6854882..d3dad3a 100644 (file)
@@ -67,6 +67,7 @@ struct _ClutterClickActionPrivate
   gulong capture_id;
 
   guint press_button;
+  ClutterModifierType modifier_state;
 
   guint is_held    : 1;
   guint is_pressed : 1;
@@ -137,6 +138,7 @@ on_event (ClutterActor       *actor,
 
       priv->is_held = TRUE;
       priv->press_button = clutter_event_get_button (event);
+      priv->modifier_state = clutter_event_get_state (event);
 
       if (priv->stage == NULL)
         priv->stage = clutter_actor_get_stage (actor);
@@ -170,6 +172,7 @@ on_captured_event (ClutterActor       *stage,
 {
   ClutterClickActionPrivate *priv = action->priv;
   ClutterActor *actor;
+  ClutterModifierType modifier_state;
 
   actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action));
 
@@ -195,6 +198,22 @@ on_captured_event (ClutterActor       *stage,
       if (!clutter_actor_contains (actor, clutter_event_get_source (event)))
         return FALSE;
 
+      /* exclude any button-mask so that we can compare
+       * the press and release states properly */
+      modifier_state = clutter_event_get_state (event) &
+                       ~(CLUTTER_BUTTON1_MASK |
+                         CLUTTER_BUTTON2_MASK |
+                         CLUTTER_BUTTON3_MASK |
+                         CLUTTER_BUTTON4_MASK |
+                         CLUTTER_BUTTON5_MASK);
+
+      /* if press and release states don't match we
+       * simply ignore modifier keys. i.e. modifier keys
+       * are expected to be pressed throughout the whole
+       * click */
+      if (modifier_state != priv->modifier_state)
+        priv->modifier_state = 0;
+
       click_action_set_pressed (action, FALSE);
       g_signal_emit (action, click_signals[CLICKED], 0, actor);
       break;
@@ -400,3 +419,21 @@ clutter_click_action_get_button (ClutterClickAction *action)
 
   return action->priv->press_button;
 }
+
+/**
+ * clutter_click_action_get_state:
+ * @action: a #ClutterClickAction
+ *
+ * Retrieves the modifier state of the click action.
+ *
+ * Return value: the modifier state parameter, or 0
+ *
+ * Since: 1.6
+ */
+ClutterModifierType
+clutter_click_action_get_state (ClutterClickAction *action)
+{
+  g_return_val_if_fail (CLUTTER_IS_CLICK_ACTION (action), 0);
+
+  return action->priv->modifier_state;
+}
index 6b2aa71..0617462 100644 (file)
@@ -33,6 +33,7 @@
 #define __CLUTTER_CLICK_ACTION_H__
 
 #include <clutter/clutter-action.h>
+#include <clutter/clutter-event.h>
 
 G_BEGIN_DECLS
 
@@ -95,8 +96,9 @@ GType clutter_click_action_get_type (void) G_GNUC_CONST;
 
 ClutterAction *clutter_click_action_new        (void);
 
-guint          clutter_click_action_get_button (ClutterClickAction *action);
-void           clutter_click_action_release    (ClutterClickAction *action);
+guint                  clutter_click_action_get_button (ClutterClickAction *action);
+ClutterModifierType    clutter_click_action_get_state  (ClutterClickAction *action);
+void                   clutter_click_action_release    (ClutterClickAction *action);
 
 G_END_DECLS
 
index ed33489..b1bc7f6 100644 (file)
@@ -169,13 +169,16 @@ clutter_clone_paint (ClutterActor *self)
                                               : "unknown");
 
   /* The final bits of magic:
-   * - We need to make sure that when the clone-source actor's paint
-   *   method calls clutter_actor_get_paint_opacity, it traverses to
-   *   us and our parent not it's real parent.
+   * - We need to override the paint opacity of the actor with our own
+   *   opacity.
+   * - We need to inform the actor that it's in a clone paint (for the function
+   *   clutter_actor_is_in_clone_paint())
    * - We need to stop clutter_actor_paint applying the model view matrix of
    *   the clone source actor.
    */
-  _clutter_actor_set_opacity_parent (priv->clone_source, self);
+  _clutter_actor_set_in_clone_paint (priv->clone_source, TRUE);
+  _clutter_actor_set_opacity_override (priv->clone_source,
+                                       clutter_actor_get_paint_opacity (self));
   _clutter_actor_set_enable_model_view_transform (priv->clone_source, FALSE);
 
   if (!CLUTTER_ACTOR_IS_MAPPED (priv->clone_source))
@@ -192,7 +195,8 @@ clutter_clone_paint (ClutterActor *self)
     _clutter_actor_set_enable_paint_unmapped (priv->clone_source, FALSE);
 
   _clutter_actor_set_enable_model_view_transform (priv->clone_source, TRUE);
-  _clutter_actor_set_opacity_parent (priv->clone_source, NULL);
+  _clutter_actor_set_opacity_override (priv->clone_source, -1);
+  _clutter_actor_set_in_clone_paint (priv->clone_source, FALSE);
 }
 
 gboolean
index 31f8844..3944c89 100644 (file)
@@ -113,7 +113,7 @@ static const ClutterColor const static_colors[] = {
  * Return value: a pointer to a static color; the returned pointer
  *   is owned by Clutter and it should never be modified or freed
  *
- * Since: 1.4
+ * Since: 1.6
  */
 G_CONST_RETURN ClutterColor *
 clutter_color_get_static (ClutterStaticColor color)
index 6b903e7..3649ce8 100644 (file)
@@ -199,7 +199,7 @@ GParamSpec *clutter_param_spec_color     (const gchar        *name,
  *
  * Named colors, for accessing global colors defined by Clutter
  *
- * Since: 1.4
+ * Since: 1.6
  */
 typedef enum { /*< prefix=CLUTTER_COLOR >*/
   /* CGA/EGA-like palette */
index 65e5f15..133b6ad 100644 (file)
@@ -50,8 +50,6 @@
 #include "clutter-offscreen-effect.h"
 #include "clutter-private.h"
 
-typedef struct _ClutterColorizeEffectClass    ClutterColorizeEffectClass;
-
 struct _ClutterColorizeEffect
 {
   ClutterOffscreenEffect parent_instance;
index 6942f82..6bc4c7e 100644 (file)
@@ -46,7 +46,8 @@ G_BEGIN_DECLS
  *
  * SinceL 1.4
  */
-typedef struct _ClutterColorizeEffect   ClutterColorizeEffect;
+typedef struct _ClutterColorizeEffect           ClutterColorizeEffect;
+typedef struct _ClutterColorizeEffectClass      ClutterColorizeEffectClass;
 
 GType clutter_colorize_effect_get_type (void) G_GNUC_CONST;
 
diff --git a/clutter/clutter-config.h.in b/clutter/clutter-config.h.in
new file mode 100644 (file)
index 0000000..0aeadd2
--- /dev/null
@@ -0,0 +1,16 @@
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only <clutter/clutter.h> can be included directly."
+#endif
+
+#ifndef __CLUTTER_CONFIG_H__
+#define __CLUTTER_CONFIG_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+@CLUTTER_CONFIG_DEFINES@
+
+G_END_DECLS
+
+#endif /* __CLUTTER_CONFIG_H__ */
index 0da2f89..a52a66b 100644 (file)
@@ -98,7 +98,7 @@ static void              child_notify       (ClutterContainer *container,
 
 typedef ClutterContainerIface   ClutterContainerInterface;
 
-G_DEFINE_INTERFACE (ClutterContainer, clutter_container, CLUTTER_TYPE_ACTOR);
+G_DEFINE_INTERFACE (ClutterContainer, clutter_container, G_TYPE_OBJECT);
 
 static void
 clutter_container_default_init (ClutterContainerInterface *iface)
index b9cee5e..a2587a2 100644 (file)
@@ -133,7 +133,7 @@ struct _ClutterContainerIface
                           ClutterActor     *actor);
 
   void (* child_notify)  (ClutterContainer *container,
-                          ClutterActor     *actor,
+                          ClutterActor     *child,
                           GParamSpec       *pspec);
 };
 
index 63d88a2..d85e8c1 100644 (file)
@@ -24,7 +24,8 @@ typedef enum {
   CLUTTER_DEBUG_MULTISTAGE          = 1 << 13,
   CLUTTER_DEBUG_ANIMATION           = 1 << 14,
   CLUTTER_DEBUG_LAYOUT              = 1 << 15,
-  CLUTTER_DEBUG_PICK                = 1 << 16
+  CLUTTER_DEBUG_PICK                = 1 << 16,
+  CLUTTER_DEBUG_EVENTLOOP           = 1 << 17
 } ClutterDebugFlag;
 
 typedef enum {
index e8a2b8c..ed613c1 100644 (file)
@@ -54,8 +54,6 @@
 #include "clutter-offscreen-effect.h"
 #include "clutter-private.h"
 
-typedef struct _ClutterDesaturateEffectClass    ClutterDesaturateEffectClass;
-
 struct _ClutterDesaturateEffect
 {
   ClutterOffscreenEffect parent_instance;
index 7c51a57..d73ed73 100644 (file)
@@ -46,6 +46,7 @@ G_BEGIN_DECLS
  * Since: 1.4
  */
 typedef struct _ClutterDesaturateEffect         ClutterDesaturateEffect;
+typedef struct _ClutterDesaturateEffectClass    ClutterDesaturateEffectClass;
 
 GType clutter_desaturate_effect_get_type (void) G_GNUC_CONST;
 
index ea21926..223cdde 100644 (file)
 #ifndef __CLUTTER_DEVICE_MANAGER_PRIVATE_H__
 #define __CLUTTER_DEVICE_MANAGER_PRIVATE_H__
 
+#include <clutter/clutter-backend.h>
 #include <clutter/clutter-device-manager.h>
 #include <clutter/clutter-event.h>
 
 G_BEGIN_DECLS
 
+typedef struct _ClutterAxisInfo
+{
+  ClutterInputAxis axis;
+
+  gdouble min_axis;
+  gdouble max_axis;
+
+  gdouble min_value;
+  gdouble max_value;
+
+  gdouble resolution;
+} ClutterAxisInfo;
+
+typedef struct _ClutterKeyInfo
+{
+  guint keyval;
+  ClutterModifierType modifiers;
+} ClutterKeyInfo;
+
 struct _ClutterInputDevice
 {
   GObject parent_instance;
@@ -37,9 +57,19 @@ struct _ClutterInputDevice
   gint id;
 
   ClutterInputDeviceType device_type;
+  ClutterInputMode device_mode;
 
   gchar *device_name;
 
+  ClutterDeviceManager *device_manager;
+
+  ClutterBackend *backend;
+
+  /* the associated device */
+  ClutterInputDevice *associated;
+
+  GList *slaves;
+
   /* the actor underneath the pointer */
   ClutterActor *cursor_actor;
 
@@ -65,28 +95,75 @@ struct _ClutterInputDevice
   guint32 previous_time;
   gint previous_button_number;
   ClutterModifierType previous_state;
+
+  GArray *axes;
+
+  guint n_keys;
+  GArray *keys;
+
+  guint has_cursor : 1;
+  guint is_enabled : 1;
+};
+
+struct _ClutterInputDeviceClass
+{
+  GObjectClass parent_class;
+
+  void (* select_stage_events) (ClutterInputDevice *device,
+                                ClutterStage       *stage,
+                                gint                event_mask);
 };
 
 /* device manager */
-void          _clutter_device_manager_add_device     (ClutterDeviceManager *device_manager,
-                                                      ClutterInputDevice   *device);
-void          _clutter_device_manager_remove_device  (ClutterDeviceManager *device_manager,
-                                                      ClutterInputDevice   *device);
-void          _clutter_device_manager_update_devices (ClutterDeviceManager *device_manager);
+void            _clutter_device_manager_add_device              (ClutterDeviceManager *device_manager,
+                                                                 ClutterInputDevice   *device);
+void            _clutter_device_manager_remove_device           (ClutterDeviceManager *device_manager,
+                                                                 ClutterInputDevice   *device);
+void            _clutter_device_manager_update_devices          (ClutterDeviceManager *device_manager);
+void            _clutter_device_manager_select_stage_events     (ClutterDeviceManager *device_manager,
+                                                                 ClutterStage         *stage,
+                                                                 gint                  event_mask);
+ClutterBackend *_clutter_device_manager_get_backend             (ClutterDeviceManager *device_manager);
 
 /* input device */
-void          _clutter_input_device_set_coords       (ClutterInputDevice   *device,
-                                                      gint                  x,
-                                                      gint                  y);
-void          _clutter_input_device_set_state        (ClutterInputDevice   *device,
-                                                      ClutterModifierType   state);
-void          _clutter_input_device_set_time         (ClutterInputDevice   *device,
-                                                      guint32               time_);
-void          _clutter_input_device_set_stage        (ClutterInputDevice   *device,
-                                                      ClutterStage         *stage);
-void          _clutter_input_device_set_actor        (ClutterInputDevice   *device,
-                                                      ClutterActor         *actor);
-ClutterActor *_clutter_input_device_update           (ClutterInputDevice   *device);
+void            _clutter_input_device_set_coords                (ClutterInputDevice   *device,
+                                                                 gint                  x,
+                                                                 gint                  y);
+void            _clutter_input_device_set_state                 (ClutterInputDevice   *device,
+                                                                 ClutterModifierType   state);
+void            _clutter_input_device_set_time                  (ClutterInputDevice   *device,
+                                                                 guint32               time_);
+void            _clutter_input_device_set_stage                 (ClutterInputDevice   *device,
+                                                                 ClutterStage         *stage);
+void            _clutter_input_device_set_actor                 (ClutterInputDevice   *device,
+                                                                 ClutterActor         *actor,
+                                                                 gboolean              emit_crossing);
+ClutterActor *  _clutter_input_device_update                    (ClutterInputDevice   *device,
+                                                                 gboolean              emit_crossing);
+void            _clutter_input_device_set_n_keys                (ClutterInputDevice   *device,
+                                                                 guint                 n_keys);
+guint           _clutter_input_device_add_axis                  (ClutterInputDevice   *device,
+                                                                 ClutterInputAxis      axis,
+                                                                 gdouble               min_value,
+                                                                 gdouble               max_value,
+                                                                 gdouble               resolution);
+void            _clutter_input_device_reset_axes                (ClutterInputDevice   *device);
+
+void            _clutter_input_device_set_associated_device     (ClutterInputDevice   *device,
+                                                                 ClutterInputDevice   *associated);
+void            _clutter_input_device_add_slave                 (ClutterInputDevice   *master,
+                                                                 ClutterInputDevice   *slave);
+void            _clutter_input_device_remove_slave              (ClutterInputDevice   *master,
+                                                                 ClutterInputDevice   *slave);
+
+void            _clutter_input_device_select_stage_events       (ClutterInputDevice   *device,
+                                                                 ClutterStage         *stage,
+                                                                 gint                  event_flags);
+
+gboolean        _clutter_input_device_translate_axis            (ClutterInputDevice   *device,
+                                                                 guint                 index_,
+                                                                 gdouble               value,
+                                                                 gdouble              *axis_value);
 
 G_END_DECLS
 
index ccb911d..53e812c 100644 (file)
@@ -308,6 +308,27 @@ clutter_device_manager_get_core_device (ClutterDeviceManager   *device_manager,
   return manager_class->get_core_device (device_manager, device_type);
 }
 
+void
+_clutter_device_manager_select_stage_events (ClutterDeviceManager *device_manager,
+                                             ClutterStage         *stage,
+                                             gint                  event_flags)
+{
+  ClutterDeviceManagerClass *manager_class;
+  const GSList *devices, *d;
+
+  g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager));
+
+  manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager);
+  devices = manager_class->get_devices (device_manager);
+
+  for (d = devices; d != NULL; d = d->next)
+    {
+      ClutterInputDevice *device = d->data;
+
+      _clutter_input_device_select_stage_events (device, stage, event_flags);
+    }
+}
+
 /*
  * _clutter_device_manager_add_device:
  * @device_manager: a #ClutterDeviceManager
@@ -402,6 +423,14 @@ _clutter_device_manager_update_devices (ClutterDeviceManager *device_manager)
       if (device->stage == NULL)
         continue;
 
-      _clutter_input_device_update (device);
+      _clutter_input_device_update (device, TRUE);
     }
 }
+
+ClutterBackend *
+_clutter_device_manager_get_backend (ClutterDeviceManager *manager)
+{
+  g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (manager), NULL);
+
+  return manager->priv->backend;
+}
index f954662..94cde3d 100644 (file)
@@ -29,6 +29,7 @@
 #define __CLUTTER_DEVICE_MANAGER_H__
 
 #include <clutter/clutter-input-device.h>
+#include <clutter/clutter-stage.h>
 
 G_BEGIN_DECLS
 
index 0b1dce2..5c55408 100644 (file)
@@ -134,7 +134,6 @@ emit_drag_begin (ClutterDragAction *action,
 {
   ClutterDragActionPrivate *priv = action->priv;
 
-  priv->motion_events_enabled = clutter_get_motion_events_enabled ();
   clutter_set_motion_events_enabled (FALSE);
 
   g_signal_emit (action, drag_signals[DRAG_BEGIN], 0,
@@ -310,6 +309,8 @@ on_button_press (ClutterActor      *actor,
                                        &priv->transformed_press_x,
                                        &priv->transformed_press_y);
 
+  priv->motion_events_enabled = clutter_get_motion_events_enabled ();
+
   if (priv->x_drag_threshold == 0 || priv->y_drag_threshold == 0)
     emit_drag_begin (action, actor, event);
   else
diff --git a/clutter/clutter-event-translator.c b/clutter/clutter-event-translator.c
new file mode 100644 (file)
index 0000000..b455496
--- /dev/null
@@ -0,0 +1,38 @@
+#include "config.h"
+
+#include "clutter-event-translator.h"
+
+#include "clutter-backend.h"
+#include "clutter-private.h"
+
+#define clutter_event_translator_get_type       _clutter_event_translator_get_type
+
+typedef ClutterEventTranslatorIface     ClutterEventTranslatorInterface;
+
+G_DEFINE_INTERFACE (ClutterEventTranslator, clutter_event_translator, G_TYPE_OBJECT);
+
+static ClutterTranslateReturn
+default_translate_event (ClutterEventTranslator *translator,
+                         gpointer                native,
+                         ClutterEvent           *event)
+{
+  return CLUTTER_TRANSLATE_CONTINUE;
+}
+
+static void
+clutter_event_translator_default_init (ClutterEventTranslatorIface *iface)
+{
+  iface->translate_event = default_translate_event;
+}
+
+ClutterTranslateReturn
+_clutter_event_translator_translate_event (ClutterEventTranslator *translator,
+                                           gpointer                native,
+                                           ClutterEvent           *translated)
+{
+  ClutterEventTranslatorIface *iface;
+
+  iface = CLUTTER_EVENT_TRANSLATOR_GET_IFACE (translator);
+
+  return iface->translate_event (translator, native, translated);
+}
diff --git a/clutter/clutter-event-translator.h b/clutter/clutter-event-translator.h
new file mode 100644 (file)
index 0000000..f7facc7
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef __CLUTTER_EVENT_TRANSLATOR_H__
+#define __CLUTTER_EVENT_TRANSLATOR_H__
+
+#include <glib-object.h>
+#include <clutter/clutter-event.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_EVENT_TRANSLATOR           (_clutter_event_translator_get_type ())
+#define CLUTTER_EVENT_TRANSLATOR(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_EVENT_TRANSLATOR, ClutterEventTranslator))
+#define CLUTTER_IS_EVENT_TRANSLATOR(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_EVENT_TRANSLATOR))
+#define CLUTTER_EVENT_TRANSLATOR_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_EVENT_TRANSLATOR, ClutterEventTranslatorIface))
+
+typedef struct _ClutterEventTranslator          ClutterEventTranslator;
+typedef struct _ClutterEventTranslatorIface     ClutterEventTranslatorIface;
+
+typedef enum {
+  CLUTTER_TRANSLATE_CONTINUE,
+  CLUTTER_TRANSLATE_REMOVE,
+  CLUTTER_TRANSLATE_QUEUE
+} ClutterTranslateReturn;
+
+struct _ClutterEventTranslatorIface
+{
+  GTypeInterface g_iface;
+
+  ClutterTranslateReturn (* translate_event) (ClutterEventTranslator *translator,
+                                              gpointer                native,
+                                              ClutterEvent           *translated);
+};
+
+GType _clutter_event_translator_get_type (void) G_GNUC_CONST;
+
+ClutterTranslateReturn _clutter_event_translator_translate_event (ClutterEventTranslator *translator,
+                                                                  gpointer                native,
+                                                                  ClutterEvent           *translated);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_EVENT_TRANSLATOR_H__ */
index 12e5825..23c3970 100644 (file)
@@ -47,6 +47,9 @@
 typedef struct _ClutterEventPrivate {
   ClutterEvent base;
 
+  ClutterInputDevice *device;
+  ClutterInputDevice *source_device;
+
   gpointer platform_data;
 } ClutterEventPrivate;
 
@@ -492,38 +495,13 @@ clutter_event_get_device_id (const ClutterEvent *event)
 {
   ClutterInputDevice *device = NULL;
 
-  g_return_val_if_fail (event != NULL, -1);
-
-  switch (event->type)
-    {
-    case CLUTTER_NOTHING:
-    case CLUTTER_STAGE_STATE:
-    case CLUTTER_DESTROY_NOTIFY:
-    case CLUTTER_CLIENT_MESSAGE:
-    case CLUTTER_DELETE:
-    case CLUTTER_ENTER:
-    case CLUTTER_LEAVE:
-      break;
-    case CLUTTER_BUTTON_PRESS:
-    case CLUTTER_BUTTON_RELEASE:
-      device = event->button.device;
-      break;
-    case CLUTTER_MOTION:
-      device = event->motion.device;
-      break;
-    case CLUTTER_SCROLL:
-      device = event->scroll.device;
-      break;
-    case CLUTTER_KEY_PRESS:
-    case CLUTTER_KEY_RELEASE:
-      device = event->scroll.device;
-      break;
-    }
+  g_return_val_if_fail (event != NULL, CLUTTER_POINTER_DEVICE);
 
+  device = clutter_event_get_device (event);
   if (device != NULL)
     return clutter_input_device_get_device_id (device);
-  else
-    return -1;
+
+  return -1;
 }
 
 /**
@@ -544,6 +522,36 @@ clutter_event_get_device_type (const ClutterEvent *event)
 
   g_return_val_if_fail (event != NULL, CLUTTER_POINTER_DEVICE);
 
+  device = clutter_event_get_device (event);
+  if (device != NULL)
+    return clutter_input_device_get_device_type (device);
+
+  return CLUTTER_POINTER_DEVICE;
+}
+
+/**
+ * clutter_event_set_device:
+ * @event: a #ClutterEvent
+ * @device: a #ClutterInputDevice
+ *
+ * Sets the device for @event.
+ *
+ * Since: 1.6
+ */
+void
+clutter_event_set_device (ClutterEvent       *event,
+                          ClutterInputDevice *device)
+{
+  g_return_if_fail (event != NULL);
+  g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device));
+
+  if (is_event_allocated (event))
+    {
+      ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
+
+      real_event->device = device;
+    }
+
   switch (event->type)
     {
     case CLUTTER_NOTHING:
@@ -557,27 +565,22 @@ clutter_event_get_device_type (const ClutterEvent *event)
 
     case CLUTTER_BUTTON_PRESS:
     case CLUTTER_BUTTON_RELEASE:
-      device = event->button.device;
+      event->button.device = device;
       break;
 
     case CLUTTER_MOTION:
-      device = event->motion.device;
+      event->motion.device = device;
       break;
 
     case CLUTTER_SCROLL:
-      device = event->scroll.device;
+      event->scroll.device = device;
       break;
 
     case CLUTTER_KEY_PRESS:
     case CLUTTER_KEY_RELEASE:
-      device = event->scroll.device;
+      event->key.device = device;
       break;
     }
-
-  if (device != NULL)
-    return clutter_input_device_get_device_type (device);
-  else
-    return CLUTTER_POINTER_DEVICE;
 }
 
 /**
@@ -602,6 +605,14 @@ clutter_event_get_device (const ClutterEvent *event)
 
   g_return_val_if_fail (event != NULL, NULL);
 
+  if (is_event_allocated (event))
+    {
+      ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
+
+      if (real_event->device != NULL)
+        return real_event->device;
+    }
+
   switch (event->type)
     {
     case CLUTTER_NOTHING:
@@ -674,13 +685,55 @@ ClutterEvent *
 clutter_event_copy (const ClutterEvent *event)
 {
   ClutterEvent *new_event;
+  ClutterEventPrivate *new_real_event;
+  ClutterInputDevice *device;
+  gint n_axes = 0;
 
   g_return_val_if_fail (event != NULL, NULL);
 
   new_event = clutter_event_new (CLUTTER_NOTHING);
+  new_real_event = (ClutterEventPrivate *) new_event;
+
   *new_event = *event;
 
   if (is_event_allocated (event))
+    {
+      ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
+
+      new_real_event->device = real_event->device;
+      new_real_event->source_device = real_event->source_device;
+    }
+
+  device = clutter_event_get_device (event);
+  if (device != NULL)
+    n_axes = clutter_input_device_get_n_axes (device);
+
+  switch (event->type)
+    {
+    case CLUTTER_BUTTON_PRESS:
+    case CLUTTER_BUTTON_RELEASE:
+      if (event->button.axes != NULL)
+        new_event->button.axes = g_memdup (event->button.axes,
+                                           sizeof (gdouble) * n_axes);
+      break;
+
+    case CLUTTER_SCROLL:
+      if (event->scroll.axes != NULL)
+        new_event->scroll.axes = g_memdup (event->scroll.axes,
+                                           sizeof (gdouble) * n_axes);
+      break;
+
+    case CLUTTER_MOTION:
+      if (event->motion.axes != NULL)
+        new_event->motion.axes = g_memdup (event->motion.axes,
+                                           sizeof (gdouble) * n_axes);
+      break;
+
+    default:
+      break;
+    }
+
+  if (is_event_allocated (event))
     _clutter_backend_copy_event_data (clutter_get_default_backend (),
                                       event,
                                       new_event);
@@ -701,6 +754,25 @@ clutter_event_free (ClutterEvent *event)
     {
       _clutter_backend_free_event_data (clutter_get_default_backend (), event);
 
+      switch (event->type)
+        {
+        case CLUTTER_BUTTON_PRESS:
+        case CLUTTER_BUTTON_RELEASE:
+          g_free (event->button.axes);
+          break;
+
+        case CLUTTER_MOTION:
+          g_free (event->motion.axes);
+          break;
+
+        case CLUTTER_SCROLL:
+          g_free (event->scroll.axes);
+          break;
+
+        default:
+          break;
+        }
+
       g_hash_table_remove (all_events, event);
       g_slice_free (ClutterEventPrivate, (ClutterEventPrivate *) event);
     }
@@ -721,7 +793,7 @@ clutter_event_get (void)
 {
   ClutterMainContext *context = _clutter_context_get_default ();
 
-  if (!context->events_queue)
+  if (context->events_queue == NULL)
     return NULL;
 
   if (g_queue_is_empty (context->events_queue))
@@ -756,6 +828,39 @@ clutter_event_peek (void)
   return g_queue_peek_tail (context->events_queue);
 }
 
+void
+_clutter_event_push (const ClutterEvent *event,
+                     gboolean            do_copy)
+{
+  ClutterMainContext *context = _clutter_context_get_default ();
+  ClutterInputDevice *device;
+
+  g_assert (context != NULL);
+
+  if (context->events_queue == NULL)
+    context->events_queue = g_queue_new ();
+
+  /* disabled devices don't propagate events */
+  device = clutter_event_get_device (event);
+  if (device != NULL)
+    {
+      if (!clutter_input_device_get_enabled (device))
+        return;
+    }
+
+  if (do_copy)
+    {
+      ClutterEvent *copy;
+
+      copy = clutter_event_copy (event);
+      copy->any.flags |= CLUTTER_EVENT_FLAG_SYNTHETIC;
+
+      event = copy;
+    }
+
+  g_queue_push_head (context->events_queue, (gpointer) event);
+}
+
 /**
  * clutter_event_put:
  * @event: a #ClutterEvent
@@ -771,16 +876,7 @@ clutter_event_peek (void)
 void
 clutter_event_put (const ClutterEvent *event)
 {
-  ClutterMainContext *context = _clutter_context_get_default ();
-  ClutterEvent       *event_copy;
-
-  /* FIXME: check queue is valid */
-  g_return_if_fail (context != NULL);
-
-  event_copy = clutter_event_copy (event);
-  event_copy->any.flags |= CLUTTER_EVENT_FLAG_SYNTHETIC;
-
-  g_queue_push_head (context->events_queue, event_copy);
+  _clutter_event_push (event, TRUE);
 }
 
 /**
@@ -799,7 +895,7 @@ clutter_events_pending (void)
 
   g_return_val_if_fail (context != NULL, FALSE);
 
-  if (!context->events_queue)
+  if (context->events_queue == NULL)
     return FALSE;
 
   return g_queue_is_empty (context->events_queue) == FALSE;
@@ -850,3 +946,156 @@ clutter_get_current_event (void)
 
   return context->current_event;
 }
+
+/**
+ * clutter_event_get_source_device:
+ * @event: a #ClutterEvent
+ *
+ * Retrieves the hardware device that originated the event.
+ *
+ * If you need the virtual device, use clutter_event_get_device().
+ *
+ * If no hardware device originated this event, this function will
+ * return the same device as clutter_event_get_device().
+ *
+ * Return value: (transfer none): a pointer to a #ClutterInputDevice
+ *   or %NULL
+ *
+ * Since: 1.6
+ */
+ClutterInputDevice *
+clutter_event_get_source_device (const ClutterEvent *event)
+{
+  ClutterEventPrivate *real_event;
+
+  if (!is_event_allocated (event))
+    return NULL;
+
+  real_event = (ClutterEventPrivate *) event;
+
+  if (real_event->source_device != NULL)
+    return real_event->source_device;
+
+  return clutter_event_get_device (event);
+}
+
+void
+_clutter_event_set_device (ClutterEvent       *event,
+                           ClutterInputDevice *device)
+{
+  switch (event->type)
+    {
+    case CLUTTER_NOTHING:
+    case CLUTTER_STAGE_STATE:
+    case CLUTTER_DESTROY_NOTIFY:
+    case CLUTTER_CLIENT_MESSAGE:
+    case CLUTTER_DELETE:
+    case CLUTTER_ENTER:
+    case CLUTTER_LEAVE:
+      break;
+
+    case CLUTTER_BUTTON_PRESS:
+    case CLUTTER_BUTTON_RELEASE:
+      event->button.device = device;
+      break;
+
+    case CLUTTER_MOTION:
+      event->motion.device = device;
+      break;
+
+    case CLUTTER_SCROLL:
+      event->scroll.device = device;
+      break;
+
+    case CLUTTER_KEY_PRESS:
+    case CLUTTER_KEY_RELEASE:
+      event->key.device = device;
+      break;
+    }
+}
+
+/*< private >
+ * clutter_event_set_source_device:
+ * @event: a #ClutterEvent
+ * @device: a #ClutterInputDevice
+ *
+ * Sets the source #ClutterInputDevice for @event.
+ *
+ * The #ClutterEvent must have been created using clutter_event_new().
+ *
+ * Since: 1.6
+ */
+void
+_clutter_event_set_source_device (ClutterEvent       *event,
+                                  ClutterInputDevice *device)
+{
+  ClutterEventPrivate *real_event;
+
+  if (!is_event_allocated (event))
+    return;
+
+  real_event = (ClutterEventPrivate *) event;
+  real_event->source_device = device;
+}
+
+/**
+ * clutter_event_get_axes:
+ * @event: a #ClutterEvent
+ * @n_axes: (out): return location for the number of axes returned
+ *
+ * Retrieves the array of axes values attached to the event.
+ *
+ * Return value: (transfer none): an array of axis values
+ *
+ * Since: 1.6
+ */
+gdouble *
+clutter_event_get_axes (const ClutterEvent *event,
+                        guint              *n_axes)
+{
+  gdouble *retval = NULL;
+  guint len = 0;
+
+  switch (event->type)
+    {
+    case CLUTTER_NOTHING:
+    case CLUTTER_STAGE_STATE:
+    case CLUTTER_DESTROY_NOTIFY:
+    case CLUTTER_CLIENT_MESSAGE:
+    case CLUTTER_DELETE:
+    case CLUTTER_ENTER:
+    case CLUTTER_LEAVE:
+    case CLUTTER_KEY_PRESS:
+    case CLUTTER_KEY_RELEASE:
+      break;
+
+    case CLUTTER_SCROLL:
+      retval = event->scroll.axes;
+      break;
+
+    case CLUTTER_BUTTON_PRESS:
+    case CLUTTER_BUTTON_RELEASE:
+      retval = event->button.axes;
+      break;
+
+    case CLUTTER_MOTION:
+      retval = event->motion.axes;
+      break;
+    }
+
+  if (retval != NULL)
+    {
+      ClutterInputDevice *device;
+
+      device = clutter_event_get_device (event);
+      if (device != NULL)
+        len = clutter_input_device_get_n_axes (device);
+      else
+        retval = NULL;
+    }
+
+  if (n_axes)
+    *n_axes = len;
+
+  return retval;
+}
index adeb040..ebaa880 100644 (file)
 G_BEGIN_DECLS
 
 /**
- * ClutterModifierType:
- * @CLUTTER_SHIFT_MASK: Mask applied by the Shift key
- * @CLUTTER_LOCK_MASK: Mask applied by the Caps Lock key
- * @CLUTTER_CONTROL_MASK: Mask applied by the Control key
- * @CLUTTER_MOD1_MASK: Mask applied by the first Mod key
- * @CLUTTER_MOD2_MASK: Mask applied by the second Mod key
- * @CLUTTER_MOD3_MASK: Mask applied by the third Mod key
- * @CLUTTER_MOD4_MASK: Mask applied by the fourth Mod key
- * @CLUTTER_MOD5_MASK: Mask applied by the fifth Mod key
- * @CLUTTER_BUTTON1_MASK: Mask applied by the first pointer button
- * @CLUTTER_BUTTON2_MASK: Mask applied by the second pointer button
- * @CLUTTER_BUTTON3_MASK: Mask applied by the third pointer button
- * @CLUTTER_BUTTON4_MASK: Mask applied by the fourth pointer button
- * @CLUTTER_BUTTON5_MASK: Mask applied by the fifth pointer button
- * @CLUTTER_SUPER_MASK: Mask applied by the Super key
- * @CLUTTER_HYPER_MASK: Mask applied by the Hyper key
- * @CLUTTER_META_MASK: Mask applied by the Meta key
- * @CLUTTER_RELEASE_MASK: Mask applied during release
- * @CLUTTER_MODIFIER_MASK: A mask covering all modifier types
- *
- * Masks applied to a #ClutterEvent by modifiers.
- *
- * Since: 0.4
- */
-typedef enum {
-  CLUTTER_SHIFT_MASK    = 1 << 0,
-  CLUTTER_LOCK_MASK     = 1 << 1,
-  CLUTTER_CONTROL_MASK  = 1 << 2,
-  CLUTTER_MOD1_MASK     = 1 << 3,
-  CLUTTER_MOD2_MASK     = 1 << 4,
-  CLUTTER_MOD3_MASK     = 1 << 5,
-  CLUTTER_MOD4_MASK     = 1 << 6,
-  CLUTTER_MOD5_MASK     = 1 << 7,
-  CLUTTER_BUTTON1_MASK  = 1 << 8,
-  CLUTTER_BUTTON2_MASK  = 1 << 9,
-  CLUTTER_BUTTON3_MASK  = 1 << 10,
-  CLUTTER_BUTTON4_MASK  = 1 << 11,
-  CLUTTER_BUTTON5_MASK  = 1 << 12,
-
-  /* bits 15 to 25 are currently unused; bit 29 is used internally */
-
-  CLUTTER_SUPER_MASK    = 1 << 26,
-  CLUTTER_HYPER_MASK    = 1 << 27,
-  CLUTTER_META_MASK     = 1 << 28,
-
-  CLUTTER_RELEASE_MASK  = 1 << 30,
-
-  CLUTTER_MODIFIER_MASK = 0x5c001fff
-} ClutterModifierType;
-
-/**
  * ClutterEventFlags:
  * @CLUTTER_EVENT_NONE: No flag set
  * @CLUTTER_EVENT_FLAG_SYNTHETIC: Synthetic event
@@ -454,12 +403,15 @@ ClutterModifierType    clutter_event_get_state              (const ClutterEvent
 gint                   clutter_event_get_device_id          (const ClutterEvent *event);
 ClutterInputDeviceType clutter_event_get_device_type        (const ClutterEvent *event);
 ClutterInputDevice *   clutter_event_get_device             (const ClutterEvent *event);
+ClutterInputDevice *   clutter_event_get_source_device      (const ClutterEvent *event);
 ClutterActor *         clutter_event_get_source             (const ClutterEvent *event);
 ClutterStage *         clutter_event_get_stage              (const ClutterEvent *event);
 
 void                   clutter_event_get_coords             (const ClutterEvent *event,
                                                              gfloat             *x,
                                                              gfloat             *y);
+gdouble *              clutter_event_get_axes               (const ClutterEvent *event,
+                                                             guint              *n_axes);
 
 guint                  clutter_event_get_key_symbol         (const ClutterEvent *event);
 guint16                clutter_event_get_key_code           (const ClutterEvent *event);
@@ -472,6 +424,9 @@ ClutterActor *         clutter_event_get_related            (const ClutterEvent
 
 ClutterScrollDirection clutter_event_get_scroll_direction   (const ClutterEvent *event);
 
+void                   clutter_event_set_device             (ClutterEvent       *event,
+                                                             ClutterInputDevice *device);
+
 guint32                clutter_keysym_to_unicode            (guint               keyval);
 
 guint32                clutter_get_current_event_time       (void);
index 2a5a35e..a8a40cc 100644 (file)
@@ -32,7 +32,7 @@
 
 G_BEGIN_DECLS
 
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 
 guint clutter_frame_source_add (guint          fps,
                                GSourceFunc    func,
index 0d2652f..133abc4 100644 (file)
@@ -3,7 +3,7 @@
  *
  * An OpenGL based 'interactive canvas' library.
  *
- * Copyright (C) 2009 Intel Corp.
+ * Copyright © 2009, 2010, 2011  Intel Corp.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include "config.h"
 #endif
 
+#include "clutter-input-device.h"
+
 #include "clutter-actor-private.h"
 #include "clutter-debug.h"
 #include "clutter-device-manager-private.h"
 #include "clutter-enum-types.h"
-#include "clutter-input-device.h"
+#include "clutter-marshal.h"
 #include "clutter-private.h"
 #include "clutter-stage-private.h"
 
@@ -47,18 +49,60 @@ enum
 {
   PROP_0,
 
+  PROP_BACKEND,
+
   PROP_ID,
-  PROP_DEVICE_TYPE,
   PROP_NAME,
 
+  PROP_DEVICE_TYPE,
+  PROP_DEVICE_MANAGER,
+  PROP_DEVICE_MODE,
+
+  PROP_HAS_CURSOR,
+  PROP_ENABLED,
+
+  PROP_N_AXES,
+
   PROP_LAST
 };
 
-static GParamSpec *obj_props[PROP_LAST];
+static GParamSpec *obj_props[PROP_LAST] = { NULL, };
 
 G_DEFINE_TYPE (ClutterInputDevice, clutter_input_device, G_TYPE_OBJECT);
 
 static void
+clutter_input_device_dispose (GObject *gobject)
+{
+  ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (gobject);
+
+  g_free (device->device_name);
+
+  if (device->device_mode == CLUTTER_INPUT_MODE_SLAVE)
+    _clutter_input_device_remove_slave (device->associated, device);
+
+  if (device->associated != NULL)
+    {
+      _clutter_input_device_set_associated_device (device->associated, NULL);
+      g_object_unref (device->associated);
+      device->associated = NULL;
+    }
+
+  if (device->axes != NULL)
+    {
+      g_array_free (device->axes, TRUE);
+      device->axes = NULL;
+    }
+
+  if (device->keys != NULL)
+    {
+      g_array_free (device->keys, TRUE);
+      device->keys = NULL;
+    }
+
+  G_OBJECT_CLASS (clutter_input_device_parent_class)->dispose (gobject);
+}
+
+static void
 clutter_input_device_set_property (GObject      *gobject,
                                    guint         prop_id,
                                    const GValue *value,
@@ -76,8 +120,28 @@ clutter_input_device_set_property (GObject      *gobject,
       self->device_type = g_value_get_enum (value);
       break;
 
+    case PROP_DEVICE_MANAGER:
+      self->device_manager = g_value_get_object (value);
+      break;
+
+    case PROP_DEVICE_MODE:
+      self->device_mode = g_value_get_enum (value);
+      break;
+
+    case PROP_BACKEND:
+      self->backend = g_value_get_object (value);
+      break;
+
     case PROP_NAME:
-      self->device_name = g_strdup (g_value_get_string (value));
+      self->device_name = g_value_dup_string (value);
+      break;
+
+    case PROP_HAS_CURSOR:
+      self->has_cursor = g_value_get_boolean (value);
+      break;
+
+    case PROP_ENABLED:
+      clutter_input_device_set_enabled (self, g_value_get_boolean (value));
       break;
 
     default:
@@ -104,10 +168,34 @@ clutter_input_device_get_property (GObject    *gobject,
       g_value_set_enum (value, self->device_type);
       break;
 
+    case PROP_DEVICE_MANAGER:
+      g_value_set_object (value, self->device_manager);
+      break;
+
+    case PROP_DEVICE_MODE:
+      g_value_set_enum (value, self->device_mode);
+      break;
+
+    case PROP_BACKEND:
+      g_value_set_object (value, self->backend);
+      break;
+
     case PROP_NAME:
       g_value_set_string (value, self->device_name);
       break;
 
+    case PROP_HAS_CURSOR:
+      g_value_set_boolean (value, self->has_cursor);
+      break;
+
+    case PROP_N_AXES:
+      g_value_set_uint (value, clutter_input_device_get_n_axes (self));
+      break;
+
+    case PROP_ENABLED:
+      g_value_set_boolean (value, self->is_enabled);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
       break;
@@ -118,10 +206,6 @@ static void
 clutter_input_device_class_init (ClutterInputDeviceClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GParamSpec *pspec;
-
-  gobject_class->set_property = clutter_input_device_set_property;
-  gobject_class->get_property = clutter_input_device_get_property;
 
   /**
    * ClutterInputDevice:id:
@@ -130,15 +214,14 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass)
    *
    * Since: 1.2
    */
-  pspec = g_param_spec_int ("id",
-                            P_("Id"),
-                            P_("Unique identifier of the device"),
-                            -1, G_MAXINT,
-                            0,
-                            CLUTTER_PARAM_READWRITE |
-                            G_PARAM_CONSTRUCT_ONLY);
-  obj_props[PROP_ID] = pspec;
-  g_object_class_install_property (gobject_class, PROP_ID, pspec);
+  obj_props[PROP_ID] =
+    g_param_spec_int ("id",
+                      P_("Id"),
+                      P_("Unique identifier of the device"),
+                      -1, G_MAXINT,
+                      0,
+                      CLUTTER_PARAM_READWRITE |
+                      G_PARAM_CONSTRUCT_ONLY);
 
   /**
    * ClutterInputDevice:name:
@@ -147,14 +230,13 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass)
    *
    * Since: 1.2
    */
-  pspec = g_param_spec_string ("name",
-                               P_("Name"),
-                               P_("The name of the device"),
-                               NULL,
-                               CLUTTER_PARAM_READWRITE |
-                               G_PARAM_CONSTRUCT_ONLY);
-  obj_props[PROP_NAME] = pspec;
-  g_object_class_install_property (gobject_class, PROP_NAME, pspec);
+  obj_props[PROP_NAME] =
+    g_param_spec_string ("name",
+                         P_("Name"),
+                         P_("The name of the device"),
+                         NULL,
+                         CLUTTER_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY);
 
   /**
    * ClutterInputDevice:device-type:
@@ -163,15 +245,110 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass)
    *
    * Since: 1.2
    */
-  pspec = g_param_spec_enum ("device-type",
-                             P_("Device Type"),
-                             P_("The type of the device"),
-                             CLUTTER_TYPE_INPUT_DEVICE_TYPE,
-                             CLUTTER_POINTER_DEVICE,
-                             CLUTTER_PARAM_READWRITE |
-                             G_PARAM_CONSTRUCT_ONLY);
-  obj_props[PROP_DEVICE_TYPE] = pspec;
-  g_object_class_install_property (gobject_class, PROP_DEVICE_TYPE, pspec);
+  obj_props[PROP_DEVICE_TYPE] =
+    g_param_spec_enum ("device-type",
+                       P_("Device Type"),
+                       P_("The type of the device"),
+                       CLUTTER_TYPE_INPUT_DEVICE_TYPE,
+                       CLUTTER_POINTER_DEVICE,
+                       CLUTTER_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY);
+
+  /**
+   * ClutterInputDevice:device-manager:
+   *
+   * The #ClutterDeviceManager instance which owns the device
+   *
+   * Since: 1.6
+   */
+  obj_props[PROP_DEVICE_MANAGER] =
+    g_param_spec_object ("device-manager",
+                         P_("Device Manager"),
+                         P_("The device manager instance"),
+                         CLUTTER_TYPE_DEVICE_MANAGER,
+                         CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+  /**
+   * ClutterInputDevice:mode:
+   *
+   * The mode of the device.
+   *
+   * Since: 1.6
+   */
+  obj_props[PROP_DEVICE_MODE] =
+    g_param_spec_enum ("device-mode",
+                       P_("Device Mode"),
+                       P_("The mode of the device"),
+                       CLUTTER_TYPE_INPUT_MODE,
+                       CLUTTER_INPUT_MODE_FLOATING,
+                       CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+  /**
+   * ClutterInputDevice:has-cursor:
+   *
+   * Whether the device has an on screen cursor following its movement.
+   *
+   * Since: 1.6
+   */
+  obj_props[PROP_HAS_CURSOR] =
+    g_param_spec_boolean ("has-cursor",
+                          P_("Has Cursor"),
+                          P_("Whether the device has a cursor"),
+                          FALSE,
+                          CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+  /**
+   * ClutterInputDevice:enabled:
+   *
+   * Whether the device is enabled.
+   *
+   * A device with the #ClutterInputDevice:device-mode property set
+   * to %CLUTTER_INPUT_MODE_MASTER cannot be disabled.
+   *
+   * A device must be enabled in order to receive events from it.
+   *
+   * Since: 1.6
+   */
+  obj_props[PROP_ENABLED] =
+    g_param_spec_boolean ("enabled",
+                          P_("Enabled"),
+                          P_("Whether the device is enabled"),
+                          FALSE,
+                          CLUTTER_PARAM_READWRITE);
+
+  /**
+   * ClutterInputDevice:n-axes:
+   *
+   * The number of axes of the device.
+   *
+   * Since: 1.6
+   */
+  obj_props[PROP_N_AXES] =
+    g_param_spec_uint ("n-axes",
+                       P_("Number of Axes"),
+                       P_("The number of axes on the device"),
+                       0, G_MAXUINT,
+                       0,
+                       CLUTTER_PARAM_READABLE);
+
+  /**
+   * ClutterInputDevice:backend:
+   *
+   * The #ClutterBackend that created the device.
+   *
+   * Since: 1.6
+   */
+  obj_props[PROP_BACKEND] =
+    g_param_spec_object ("backend",
+                         P_("Backend"),
+                         P_("The backend instance"),
+                         CLUTTER_TYPE_BACKEND,
+                         CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+  gobject_class->dispose = clutter_input_device_dispose;
+  gobject_class->set_property = clutter_input_device_set_property;
+  gobject_class->get_property = clutter_input_device_get_property;
+  g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
 }
 
 static void
@@ -189,8 +366,8 @@ clutter_input_device_init (ClutterInputDevice *self)
   self->current_state = self->previous_state = 0;
 }
 
-/*
- * _clutter_input_device_set_coords:
+/*< private >
+ * clutter_input_device_set_coords:
  * @device: a #ClutterInputDevice
  * @x: X coordinate of the device
  * @y: Y coordinate of the device
@@ -211,8 +388,8 @@ _clutter_input_device_set_coords (ClutterInputDevice *device,
     device->current_y = y;
 }
 
-/*
- * _clutter_input_device_set_state:
+/*< private >
+ * clutter_input_device_set_state:
  * @device: a #ClutterInputDevice
  * @state: a bitmask of modifiers
  *
@@ -227,8 +404,8 @@ _clutter_input_device_set_state (ClutterInputDevice  *device,
   device->current_state = state;
 }
 
-/*
- * _clutter_input_device_set_time:
+/*< private >
+ * clutter_input_device_set_time:
  * @device: a #ClutterInputDevice
  * @time_: the time
  *
@@ -244,10 +421,7 @@ _clutter_input_device_set_time (ClutterInputDevice *device,
     device->current_time = time_;
 }
 
-/*
- * cursor_weak_unref:
- *
- * #ClutterInputDevice keeps a weak reference on the actor
+/* #ClutterInputDevice keeps a weak reference on the actor
  * under its pointer; this function unsets the reference on
  * the actor to avoid keeping around stale pointers
  */
@@ -260,8 +434,8 @@ cursor_weak_unref (gpointer  user_data,
   device->cursor_actor = NULL;
 }
 
-/*
- * _clutter_input_device_set_stage:
+/*< private >
+ * clutter_input_device_set_stage:
  * @device: a #ClutterInputDevice
  * @stage: a #ClutterStage or %NULL
  *
@@ -271,49 +445,23 @@ void
 _clutter_input_device_set_stage (ClutterInputDevice *device,
                                  ClutterStage       *stage)
 {
-  ClutterStage *old_stage;
-
-  g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
+  if (device->stage == stage)
+    return;
 
-  old_stage = device->stage;
   device->stage = stage;
 
-  /* if we left the stage then we also need to unset the
-   * cursor actor (and update its :has-pointer property)
+  /* we leave the ->cursor_actor in place in order to check
+   * if we left the stage without crossing it again; this way
+   * we can emit a leave event on the cursor actor right before
+   * we emit the leave event on the stage.
    */
-  if (device->stage == NULL &&
-      device->cursor_actor != NULL &&
-      device->cursor_actor != CLUTTER_ACTOR (old_stage))
-    {
-      ClutterEvent cev;
-
-      cev.crossing.type = CLUTTER_LEAVE;
-      cev.crossing.time = device->current_time;
-      cev.crossing.flags = 0;
-      cev.crossing.stage = old_stage;
-      cev.crossing.source = device->cursor_actor;
-      cev.crossing.x = device->current_x;
-      cev.crossing.y = device->current_y;
-      cev.crossing.device = device;
-      cev.crossing.related = device->stage != NULL
-                           ? CLUTTER_ACTOR (device->stage)
-                           : CLUTTER_ACTOR (old_stage);
-
-      _clutter_stage_queue_event (old_stage, &cev);
-
-      _clutter_actor_set_has_pointer (device->cursor_actor, FALSE);
-      g_object_weak_unref (G_OBJECT (device->cursor_actor),
-                           cursor_weak_unref,
-                           device);
-    }
-
-  device->cursor_actor = NULL;
 }
 
-/*
- * _clutter_input_device_set_actor:
+/*< private >
+ * clutter_input_device_set_actor:
  * @device: a #ClutterInputDevice
  * @actor: a #ClutterActor
+ * @emit_crossing: %TRUE to emit crossing events
  *
  * Sets the actor under the pointer coordinates of @device
  *
@@ -330,34 +478,41 @@ _clutter_input_device_set_stage (ClutterInputDevice *device,
  */
 void
 _clutter_input_device_set_actor (ClutterInputDevice *device,
-                                 ClutterActor       *actor)
+                                 ClutterActor       *actor,
+                                 gboolean            emit_crossing)
 {
   ClutterActor *old_actor;
-  ClutterEvent cev;
 
-  g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
-
-  if (actor == device->cursor_actor)
+  if (device->cursor_actor == actor)
     return;
 
   old_actor = device->cursor_actor;
+
   if (old_actor != NULL)
     {
-      cev.crossing.type = CLUTTER_LEAVE;
-      cev.crossing.time = device->current_time;
-      cev.crossing.flags = 0;
-      cev.crossing.stage = device->stage;
-      cev.crossing.source = device->cursor_actor;
-      cev.crossing.x = device->current_x;
-      cev.crossing.y = device->current_y;
-      cev.crossing.device = device;
-      cev.crossing.related = actor;
-
-      /* we need to make sure that this event is processed before
-       * any other event we might have queued up until now, so we
-       * go on and synthesize the event emission
-       */
-      _clutter_process_event (&cev);
+      if (emit_crossing)
+        {
+          ClutterEvent *event;
+
+          event = clutter_event_new (CLUTTER_LEAVE);
+          event->crossing.time = device->current_time;
+          event->crossing.flags = 0;
+          event->crossing.stage = device->stage;
+          event->crossing.source = device->cursor_actor;
+          event->crossing.x = device->current_x;
+          event->crossing.y = device->current_y;
+          event->crossing.related = actor;
+          clutter_event_set_device (event, device);
+
+          /* we need to make sure that this event is processed
+           * before any other event we might have queued up until
+           * now, so we go on, and synthesize the event emission
+           * ourselves
+           */
+          _clutter_process_event (event);
+
+          clutter_event_free (event);
+        }
 
       /* processing the event might have destroyed the actor */
       if (device->cursor_actor != NULL)
@@ -373,54 +528,28 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
 
   if (actor != NULL)
     {
-      cev.crossing.type = CLUTTER_ENTER;
-      cev.crossing.time = device->current_time;
-      cev.crossing.flags = 0;
-      cev.crossing.stage = device->stage;
-      cev.crossing.x = device->current_x;
-      cev.crossing.y = device->current_y;
-      cev.crossing.device = device;
-
-      CLUTTER_NOTE (EVENT, "Device '%s' entering '%s' at %d, %d",
-                    device->device_name,
-                    clutter_actor_get_name (actor) != NULL
-                      ? clutter_actor_get_name (actor)
-                      : G_OBJECT_TYPE_NAME (actor),
-                    device->current_x,
-                    device->current_y);
-
-      /* if there is an actor overlapping the Stage boundary and we
-       * don't do this check then we'll emit an ENTER event only on
-       * the actor instead of emitting it on the Stage *and* the
-       * actor
-       */
-      if (old_actor == NULL && actor != CLUTTER_ACTOR (device->stage))
+      if (emit_crossing)
         {
-          cev.crossing.source = CLUTTER_ACTOR (device->stage);
-          cev.crossing.related = NULL;
-
-          CLUTTER_NOTE (EVENT, "Adding Crossing[Enter] event for Stage");
-
-          _clutter_process_event (&cev);
-
-          cev.crossing.source = actor;
-          cev.crossing.related = CLUTTER_ACTOR (device->stage);
-        }
-      else
-        {
-          cev.crossing.source = actor;
-          cev.crossing.related = old_actor;
+          ClutterEvent *event;
+
+          event = clutter_event_new (CLUTTER_ENTER);
+          event->crossing.time = device->current_time;
+          event->crossing.flags = 0;
+          event->crossing.stage = device->stage;
+          event->crossing.x = device->current_x;
+          event->crossing.y = device->current_y;
+          event->crossing.source = actor;
+          event->crossing.related = old_actor;
+          clutter_event_set_device (event, device);
+
+          /* see above */
+          _clutter_process_event (event);
+
+          clutter_event_free (event);
         }
-
-      /* as above: we need to make sure that this event is processed
-       * before any other event we might have queued up until now, so
-       * we go on and synthesize the event emission
-       */
-      _clutter_process_event (&cev);
     }
 
   device->cursor_actor = actor;
-
   if (device->cursor_actor != NULL)
     {
       g_object_weak_ref (G_OBJECT (device->cursor_actor),
@@ -468,6 +597,56 @@ clutter_input_device_get_device_id (ClutterInputDevice *device)
 }
 
 /**
+ * clutter_input_device_set_enabled:
+ * @device: a #ClutterInputDevice
+ * @enabled: %TRUE to enable the @device
+ *
+ * Enables or disables a #ClutterInputDevice.
+ *
+ * Only devices with a #ClutterInputDevice:device-mode property set
+ * to %CLUTTER_INPUT_MODE_SLAVE or %CLUTTER_INPUT_MODE_FLOATING can
+ * be disabled.
+ *
+ * Since: 1.6
+ */
+void
+clutter_input_device_set_enabled (ClutterInputDevice *device,
+                                  gboolean            enabled)
+{
+  g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
+
+  enabled = !!enabled;
+
+  if (!enabled && device->device_mode == CLUTTER_INPUT_MODE_MASTER)
+    return;
+
+  if (device->is_enabled == enabled)
+    return;
+
+  device->is_enabled = enabled;
+
+  g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_ENABLED]);
+}
+
+/**
+ * clutter_input_device_get_enabled:
+ * @device: a #ClutterInputDevice
+ *
+ * Retrieves whether @device is enabled.
+ *
+ * Return value: %TRUE if the device is enabled
+ *
+ * Since: 1.6
+ */
+gboolean
+clutter_input_device_get_enabled (ClutterInputDevice *device)
+{
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
+
+  return device->is_enabled;
+}
+
+/**
  * clutter_input_device_get_device_coords:
  * @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
  * @x: (out): return location for the X coordinate
@@ -483,7 +662,6 @@ clutter_input_device_get_device_coords (ClutterInputDevice *device,
                                         gint               *y)
 {
   g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
-  g_return_if_fail (device->device_type == CLUTTER_POINTER_DEVICE);
 
   if (x)
     *x = device->current_x;
@@ -507,14 +685,16 @@ clutter_input_device_get_device_coords (ClutterInputDevice *device,
  * Since: 1.2
  */
 ClutterActor *
-_clutter_input_device_update (ClutterInputDevice *device)
+_clutter_input_device_update (ClutterInputDevice *device,
+                              gboolean            emit_crossing)
 {
   ClutterStage *stage;
   ClutterActor *new_cursor_actor;
   ClutterActor *old_cursor_actor;
   gint x, y;
 
-  g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL);
+  if (device->device_type == CLUTTER_KEYBOARD_DEVICE)
+    return NULL;
 
   stage = device->stage;
   if (G_UNLIKELY (stage == NULL))
@@ -549,7 +729,7 @@ _clutter_input_device_update (ClutterInputDevice *device)
   if (new_cursor_actor == old_cursor_actor)
     return old_cursor_actor;
 
-  _clutter_input_device_set_actor (device, new_cursor_actor);
+  _clutter_input_device_set_actor (device, new_cursor_actor, emit_crossing);
 
   return device->cursor_actor;
 }
@@ -613,6 +793,44 @@ clutter_input_device_get_device_name (ClutterInputDevice *device)
 }
 
 /**
+ * clutter_input_device_get_has_cursor:
+ * @device: a #ClutterInputDevice
+ *
+ * Retrieves whether @device has a pointer that follows the
+ * device motion.
+ *
+ * Return value: %TRUE if the device has a cursor
+ *
+ * Since: 1.6
+ */
+gboolean
+clutter_input_device_get_has_cursor (ClutterInputDevice *device)
+{
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
+
+  return device->has_cursor;
+}
+
+/**
+ * clutter_input_device_get_device_mode:
+ * @device: a #ClutterInputDevice
+ *
+ * Retrieves the #ClutterInputMode of @device.
+ *
+ * Return value: the device mode
+ *
+ * Since: 1.6
+ */
+ClutterInputMode
+clutter_input_device_get_device_mode (ClutterInputDevice *device)
+{
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
+                        CLUTTER_INPUT_MODE_FLOATING);
+
+  return device->device_mode;
+}
+
+/**
  * clutter_input_device_update_from_event:
  * @device: a #ClutterInputDevice
  * @event: a #ClutterEvent
@@ -700,3 +918,485 @@ clutter_input_device_update_from_event (ClutterInputDevice *device,
   if (update_stage)
     _clutter_input_device_set_stage (device, event_stage);
 }
+
+/*< private >
+ * clutter_input_device_reset_axes:
+ * @device: a #ClutterInputDevice
+ *
+ * Resets the axes on @device
+ */
+void
+_clutter_input_device_reset_axes (ClutterInputDevice *device)
+{
+  if (device->axes != NULL)
+    {
+      g_array_free (device->axes, TRUE);
+      device->axes = NULL;
+
+      g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_N_AXES]);
+    }
+}
+
+/*< private >
+ * clutter_input_device_add_axis:
+ * @device: a #ClutterInputDevice
+ * @axis: the axis type
+ * @minimum: the minimum axis value
+ * @maximum: the maximum axis value
+ * @resolution: the axis resolution
+ *
+ * Adds an axis of type @axis on @device.
+ */
+guint
+_clutter_input_device_add_axis (ClutterInputDevice *device,
+                                ClutterInputAxis    axis,
+                                gdouble             minimum,
+                                gdouble             maximum,
+                                gdouble             resolution)
+{
+  ClutterAxisInfo info;
+  guint pos;
+
+  if (device->axes == NULL)
+    device->axes = g_array_new (FALSE, TRUE, sizeof (ClutterAxisInfo));
+
+  info.axis = axis;
+  info.min_value = minimum;
+  info.max_value = maximum;
+  info.resolution = resolution;
+
+  switch (axis)
+    {
+    case CLUTTER_INPUT_AXIS_X:
+    case CLUTTER_INPUT_AXIS_Y:
+      info.min_axis = 0;
+      info.max_axis = 0;
+      break;
+
+    case CLUTTER_INPUT_AXIS_XTILT:
+    case CLUTTER_INPUT_AXIS_YTILT:
+      info.min_axis = -1;
+      info.max_axis = 1;
+      break;
+
+    default:
+      info.min_axis = 0;
+      info.max_axis = 1;
+      break;
+    }
+
+  device->axes = g_array_append_val (device->axes, info);
+  pos = device->axes->len - 1;
+
+  g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_N_AXES]);
+
+  return pos;
+}
+
+/*< private >
+ * clutter_input_translate_axis:
+ * @device: a #ClutterInputDevice
+ * @index_: the index of the axis
+ * @gint: the absolute value of the axis
+ * @axis_value: (out): the translated value of the axis
+ *
+ * Performs a conversion from the absolute value of the axis
+ * to a relative value.
+ *
+ * The axis at @index_ must not be %CLUTTER_INPUT_AXIS_X or
+ * %CLUTTER_INPUT_AXIS_Y.
+ *
+ * Return value: %TRUE if the conversion was successful
+ */
+gboolean
+_clutter_input_device_translate_axis (ClutterInputDevice *device,
+                                      guint               index_,
+                                      gdouble             value,
+                                      gdouble            *axis_value)
+{
+  ClutterAxisInfo *info;
+  gdouble width;
+  gdouble real_value;
+
+  if (device->axes == NULL || index_ >= device->axes->len)
+    return FALSE;
+
+  info = &g_array_index (device->axes, ClutterAxisInfo, index_);
+
+  if (info->axis == CLUTTER_INPUT_AXIS_X ||
+      info->axis == CLUTTER_INPUT_AXIS_Y)
+    return FALSE;
+
+  width = info->max_value - info->min_value;
+  real_value = (info->max_axis * (value - info->min_value)
+             + info->min_axis * (info->max_value - value))
+             / width;
+
+  if (axis_value)
+    *axis_value = real_value;
+
+  return TRUE;
+}
+
+/**
+ * clutter_input_device_get_axis:
+ * @device: a #ClutterInputDevice
+ * @index_: the index of the axis
+ *
+ * Retrieves the type of axis on @device at the given index.
+ *
+ * Return value: the axis type
+ *
+ * Since: 1.6
+ */
+ClutterInputAxis
+clutter_input_device_get_axis (ClutterInputDevice *device,
+                               guint               index_)
+{
+  ClutterAxisInfo *info;
+
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
+                        CLUTTER_INPUT_AXIS_IGNORE);
+
+  if (device->axes == NULL)
+    return CLUTTER_INPUT_AXIS_IGNORE;
+
+  if (index_ >= device->axes->len)
+    return CLUTTER_INPUT_AXIS_IGNORE;
+
+  info = &g_array_index (device->axes, ClutterAxisInfo, index_);
+
+  return info->axis;
+}
+
+/**
+ * clutter_input_device_get_axis_value:
+ * @device: a #ClutterInputDevice
+ * @axes: (array): an array of axes values, typically
+ *   coming from clutter_event_get_axes()
+ * @axis: the axis to extract
+ * @value: (out): return location for the axis value
+ *
+ * Extracts the value of the given @axis of a #ClutterInputDevice from
+ * an array of axis values.
+ *
+ * An example of typical usage for this function is:
+ *
+ * |[
+ *   ClutterInputDevice *device = clutter_event_get_device (event);
+ *   gdouble *axes = clutter_event_get_axes (event, NULL);
+ *   gdouble pressure_value = 0;
+ *
+ *   clutter_input_device_get_axis_value (device, axes,
+ *                                        CLUTTER_INPUT_AXIS_PRESSURE,
+ *                                        &amp;pressure_value);
+ * ]|
+ *
+ * Return value: %TRUE if the value was set, and %FALSE otherwise
+ *
+ * Since: 1.6
+ */
+gboolean
+clutter_input_device_get_axis_value (ClutterInputDevice *device,
+                                     gdouble            *axes,
+                                     ClutterInputAxis    axis,
+                                     gdouble            *value)
+{
+  gint i;
+
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
+  g_return_val_if_fail (device->axes != NULL, FALSE);
+
+  for (i = 0; i < device->axes->len; i++)
+    {
+      ClutterAxisInfo *info;
+
+      info = &g_array_index (device->axes, ClutterAxisInfo, i);
+
+      if (info->axis == axis)
+        {
+          if (value)
+            *value = axes[i];
+
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+/**
+ * clutter_input_device_get_n_axes:
+ * @device: a #ClutterInputDevice
+ *
+ * Retrieves the number of axes available on @device.
+ *
+ * Return value: the number of axes on the device
+ *
+ * Since: 1.6
+ */
+guint
+clutter_input_device_get_n_axes (ClutterInputDevice *device)
+{
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
+
+  if (device->axes != NULL)
+    return device->axes->len;
+
+  return 0;
+}
+
+/*< private >
+ * clutter_input_device_set_n_keys:
+ * @device: a #ClutterInputDevice
+ * @n_keys: the number of keys of the device
+ *
+ * Initializes the keys of @device.
+ *
+ * Call clutter_input_device_set_key() on each key to set the keyval
+ * and modifiers.
+ */
+void
+_clutter_input_device_set_n_keys (ClutterInputDevice *device,
+                                  guint               n_keys)
+{
+  if (device->keys != NULL)
+    g_array_free (device->keys, TRUE);
+
+  device->n_keys = n_keys;
+  device->keys = g_array_sized_new (FALSE, TRUE,
+                                    sizeof (ClutterKeyInfo),
+                                    n_keys);
+}
+
+/**
+ * clutter_input_device_get_n_keys:
+ * @device: a #ClutterInputDevice
+ *
+ * Retrieves the number of keys registered for @device.
+ *
+ * Return value: the number of registered keys
+ *
+ * Since: 1.6
+ */
+guint
+clutter_input_device_get_n_keys (ClutterInputDevice *device)
+{
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
+
+  return device->n_keys;
+}
+
+/**
+ * clutter_input_device_set_key:
+ * @device: a #ClutterInputDevice
+ * @index_: the index of the key
+ * @keyval: the keyval
+ * @modifiers: a bitmask of modifiers
+ *
+ * Sets the keyval and modifiers at the given @index_ for @device.
+ *
+ * Clutter will use the keyval and modifiers set when filling out
+ * an event coming from the same input device.
+ *
+ * Since: 1.6
+ */
+void
+clutter_input_device_set_key (ClutterInputDevice  *device,
+                              guint                index_,
+                              guint                keyval,
+                              ClutterModifierType  modifiers)
+{
+  ClutterKeyInfo *key_info;
+
+  g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
+  g_return_if_fail (index_ < device->n_keys);
+
+  key_info = &g_array_index (device->keys, ClutterKeyInfo, index_);
+  key_info->keyval = keyval;
+  key_info->modifiers = modifiers;
+}
+
+/**
+ * clutter_input_device_get_key:
+ * @device: a #ClutterInputDevice
+ * @index_: the index of the key
+ * @keyval: (out): return location for the keyval at @index_
+ * @modifiers: (out): return location for the modifiers at @index_
+ *
+ * Retrieves the key set using clutter_input_device_set_key()
+ *
+ * Return value: %TRUE if a key was set at the given index
+ *
+ * Since: 1.6
+ */
+gboolean
+clutter_input_device_get_key (ClutterInputDevice  *device,
+                              guint                index_,
+                              guint               *keyval,
+                              ClutterModifierType *modifiers)
+{
+  ClutterKeyInfo *key_info;
+
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
+
+  if (device->keys == NULL)
+    return FALSE;
+
+  if (index_ > device->keys->len)
+    return FALSE;
+
+  key_info = &g_array_index (device->keys, ClutterKeyInfo, index_);
+
+  if (!key_info->keyval && !key_info->modifiers)
+    return FALSE;
+
+  if (keyval)
+    *keyval = key_info->keyval;
+
+  if (modifiers)
+    *modifiers = key_info->modifiers;
+
+  return TRUE;
+}
+
+/*< private >
+ * clutter_input_device_add_slave:
+ * @master: a #ClutterInputDevice
+ * @slave: a #ClutterInputDevice
+ *
+ * Adds @slave to the list of slave devices of @master
+ *
+ * This function does not increase the reference count of either @master
+ * or @slave.
+ */
+void
+_clutter_input_device_add_slave (ClutterInputDevice *master,
+                                 ClutterInputDevice *slave)
+{
+  if (g_list_find (master->slaves, slave) == NULL)
+    master->slaves = g_list_prepend (master->slaves, slave);
+}
+
+/*< private >
+ * clutter_input_device_remove_slave:
+ * @master: a #ClutterInputDevice
+ * @slave: a #ClutterInputDevice
+ *
+ * Removes @slave from the list of slave devices of @master.
+ *
+ * This function does not decrease the reference count of either @master
+ * or @slave.
+ */
+void
+_clutter_input_device_remove_slave (ClutterInputDevice *master,
+                                    ClutterInputDevice *slave)
+{
+  if (g_list_find (master->slaves, slave) != NULL)
+    master->slaves = g_list_remove (master->slaves, slave);
+}
+
+/**
+ * clutter_input_device_get_slave_devices:
+ * @device: a #ClutterInputDevice
+ *
+ * Retrieves the slave devices attached to @device.
+ *
+ * Return value: (transfer container) (element-type Clutter.InputDevice): a
+ *   list of #ClutterInputDevice, or %NULL. The contents of the list are
+ *   owned by the device. Use g_list_free() when done
+ *
+ * Since: 1.6
+ */
+GList *
+clutter_input_device_get_slave_devices (ClutterInputDevice *device)
+{
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
+
+  return g_list_copy (device->slaves);
+}
+
+/*< internal >
+ * clutter_input_device_set_associated_device:
+ * @device: a #ClutterInputDevice
+ * @associated: (allow-none): a #ClutterInputDevice, or %NULL
+ *
+ * Sets the associated device for @device.
+ *
+ * This function keeps a reference on the associated device.
+ */
+void
+_clutter_input_device_set_associated_device (ClutterInputDevice *device,
+                                             ClutterInputDevice *associated)
+{
+  if (device->associated == associated)
+    return;
+
+  if (device->associated != NULL)
+    g_object_unref (device->associated);
+
+  device->associated = associated;
+  if (device->associated != NULL)
+    g_object_ref (device->associated);
+
+  CLUTTER_NOTE (MISC, "Associating device '%s' to device '%s'",
+                clutter_input_device_get_device_name (device),
+                device->associated != NULL
+                  ? clutter_input_device_get_device_name (device->associated)
+                  : "(none)");
+
+  if (device->device_mode != CLUTTER_INPUT_MODE_MASTER)
+    {
+      if (device->associated != NULL)
+        device->device_mode = CLUTTER_INPUT_MODE_SLAVE;
+      else
+        device->device_mode = CLUTTER_INPUT_MODE_FLOATING;
+
+      g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_DEVICE_MODE]);
+    }
+}
+
+/**
+ * clutter_input_device_get_associated_device:
+ * @device: a #ClutterInputDevice
+ *
+ * Retrieves a pointer to the #ClutterInputDevice that has been
+ * associated to @device.
+ *
+ * If the #ClutterInputDevice:device-mode property of @device is
+ * set to %CLUTTER_INPUT_MODE_MASTER, this function will return
+ * %NULL.
+ *
+ * Return value: (transfer none): a #ClutterInputDevice, or %NULL
+ *
+ * Since: 1.6
+ */
+ClutterInputDevice *
+clutter_input_device_get_associated_device (ClutterInputDevice *device)
+{
+  g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
+
+  return device->associated;
+}
+
+/*< internal >
+ * clutter_input_device_select_stage_events:
+ * @device: a #ClutterInputDevice
+ * @stage: the #ClutterStage to select events on
+ * @event_mask: platform-specific mask of events
+ *
+ * Selects input device events on @stage.
+ *
+ * The implementation of this function depends on the backend used.
+ */
+void
+_clutter_input_device_select_stage_events (ClutterInputDevice *device,
+                                           ClutterStage       *stage,
+                                           gint                event_mask)
+{
+  ClutterInputDeviceClass *device_class;
+
+  device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device);
+  if (device_class->select_stage_events != NULL)
+    device_class->select_stage_events (device, stage, event_mask);
+}
index a07983e..6772a39 100644 (file)
@@ -3,7 +3,7 @@
  *
  * An OpenGL based 'interactive canvas' library.
  *
- * Copyright (C) 2009 Intel Corp.
+ * Copyright © 2009, 2010, 2011  Intel Corp.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -57,6 +57,9 @@ typedef struct _ClutterInputDeviceClass ClutterInputDeviceClass;
  * @CLUTTER_TABLET_DEVICE: A tablet device
  * @CLUTTER_TOUCHPAD_DEVICE: A touchpad device
  * @CLUTTER_TOUCHSCREEN_DEVICE: A touch screen device
+ * @CLUTTER_PEN_DEVICE: A pen device
+ * @CLUTTER_ERASER_DEVICE: An eraser device
+ * @CLUTTER_CURSOR_DEVICE: A cursor device
  * @CLUTTER_N_DEVICE_TYPES: The number of device types
  *
  * The types of input devices available.
@@ -74,38 +77,95 @@ typedef enum {
   CLUTTER_TABLET_DEVICE,
   CLUTTER_TOUCHPAD_DEVICE,
   CLUTTER_TOUCHSCREEN_DEVICE,
+  CLUTTER_PEN_DEVICE,
+  CLUTTER_ERASER_DEVICE,
+  CLUTTER_CURSOR_DEVICE,
 
   CLUTTER_N_DEVICE_TYPES
 } ClutterInputDeviceType;
 
 /**
- * ClutterInputDeviceClass:
+ * ClutterInputMode:
+ * @CLUTTER_INPUT_MODE_MASTER: A master, virtual device
+ * @CLUTTER_INPUT_MODE_SLAVE: A slave, physical device, attached to
+ *   a master device
+ * @CLUTTER_INPUT_MODE_FLOATING: A slave, physical device, not attached
+ *   to a master device
  *
- * The #ClutterInputDeviceClass structure contains only private
- * data and should not be accessed directly
+ * The mode for input devices available.
  *
- * Since: 1.2
+ * Since: 1.6
  */
-struct _ClutterInputDeviceClass
-{
-  /*< private >*/
-  GObjectClass parent_class;
-};
+typedef enum {
+  CLUTTER_INPUT_MODE_MASTER,
+  CLUTTER_INPUT_MODE_SLAVE,
+  CLUTTER_INPUT_MODE_FLOATING
+} ClutterInputMode;
+
+/**
+ * ClutterInputAxis:
+ * @CLUTTER_INPUT_AXIS_IGNORE: Unused axis
+ * @CLUTTER_INPUT_AXIS_X: The position on the X axis
+ * @CLUTTER_INPUT_AXIS_Y: The position of the Y axis
+ * @CLUTTER_INPUT_AXIS_PRESSURE: The pressure information
+ * @CLUTTER_INPUT_AXIS_XTILT: The tilt on the X axis
+ * @CLUTTER_INPUT_AXIS_YTILT: The tile on the Y axis
+ * @CLUTTER_INPUT_AXIS_WHEEL: A wheel
+ *
+ * The type of axes Clutter recognizes on a #ClutterInputDevice
+ *
+ * Since: 1.6
+ */
+typedef enum {
+  CLUTTER_INPUT_AXIS_IGNORE,
+  CLUTTER_INPUT_AXIS_X,
+  CLUTTER_INPUT_AXIS_Y,
+  CLUTTER_INPUT_AXIS_PRESSURE,
+  CLUTTER_INPUT_AXIS_XTILT,
+  CLUTTER_INPUT_AXIS_YTILT,
+  CLUTTER_INPUT_AXIS_WHEEL
+} ClutterInputAxis;
 
 GType clutter_input_device_get_type (void) G_GNUC_CONST;
 
-ClutterInputDeviceType clutter_input_device_get_device_type   (ClutterInputDevice *device);
-gint                   clutter_input_device_get_device_id     (ClutterInputDevice *device);
-void                   clutter_input_device_get_device_coords (ClutterInputDevice *device,
-                                                               gint               *x,
-                                                               gint               *y);
-ClutterActor *         clutter_input_device_get_pointer_actor (ClutterInputDevice *device);
-ClutterStage *         clutter_input_device_get_pointer_stage (ClutterInputDevice *device);
-G_CONST_RETURN gchar * clutter_input_device_get_device_name   (ClutterInputDevice *device);
-
-void                   clutter_input_device_update_from_event (ClutterInputDevice *device,
-                                                               ClutterEvent       *event,
-                                                               gboolean            update_stage);
+ClutterInputDeviceType  clutter_input_device_get_device_type    (ClutterInputDevice  *device);
+gint                    clutter_input_device_get_device_id      (ClutterInputDevice  *device);
+void                    clutter_input_device_get_device_coords  (ClutterInputDevice  *device,
+                                                                 gint                *x,
+                                                                 gint                *y);
+ClutterActor *          clutter_input_device_get_pointer_actor  (ClutterInputDevice  *device);
+ClutterStage *          clutter_input_device_get_pointer_stage  (ClutterInputDevice  *device);
+G_CONST_RETURN gchar *  clutter_input_device_get_device_name    (ClutterInputDevice  *device);
+ClutterInputMode        clutter_input_device_get_device_mode    (ClutterInputDevice  *device);
+gboolean                clutter_input_device_get_has_cursor     (ClutterInputDevice  *device);
+void                    clutter_input_device_set_enabled        (ClutterInputDevice  *device,
+                                                                 gboolean             enabled);
+gboolean                clutter_input_device_get_enabled        (ClutterInputDevice  *device);
+
+guint                   clutter_input_device_get_n_axes         (ClutterInputDevice  *device);
+ClutterInputAxis        clutter_input_device_get_axis           (ClutterInputDevice  *device,
+                                                                 guint                index_);
+gboolean                clutter_input_device_get_axis_value     (ClutterInputDevice  *device,
+                                                                 gdouble             *axes,
+                                                                 ClutterInputAxis     axis,
+                                                                 gdouble             *value);
+
+guint                   clutter_input_device_get_n_keys         (ClutterInputDevice  *device);
+void                    clutter_input_device_set_key            (ClutterInputDevice  *device,
+                                                                 guint                index_,
+                                                                 guint                keyval,
+                                                                 ClutterModifierType  modifiers);
+gboolean                clutter_input_device_get_key            (ClutterInputDevice  *device,
+                                                                 guint                index_,
+                                                                 guint               *keyval,
+                                                                 ClutterModifierType *modifiers);
+
+ClutterInputDevice *    clutter_input_device_get_associated_device (ClutterInputDevice *device);
+GList *                 clutter_input_device_get_slave_devices  (ClutterInputDevice  *device);
+
+void                    clutter_input_device_update_from_event  (ClutterInputDevice  *device,
+                                                                 ClutterEvent        *event,
+                                                                 gboolean             update_stage);
 
 G_END_DECLS
 
index 5548c52..cfd9856 100644 (file)
@@ -621,6 +621,18 @@ clutter_list_model_resort (ClutterModel         *model,
                    &sort_closure);
 }
 
+static guint
+clutter_list_model_get_n_rows (ClutterModel *model)
+{
+  ClutterListModel *list_model = CLUTTER_LIST_MODEL (model);
+
+  /* short-circuit in case we don't have a filter in place */
+  if (!clutter_model_get_filter_set (model))
+    return g_sequence_get_length (list_model->priv->sequence);
+
+  return CLUTTER_MODEL_CLASS (clutter_list_model_parent_class)->get_n_rows (model);
+}
+
 static void
 clutter_list_model_row_removed (ClutterModel     *model,
                                 ClutterModelIter *iter)
@@ -686,6 +698,7 @@ clutter_list_model_class_init (ClutterListModelClass *klass)
   model_class->insert_row      = clutter_list_model_insert_row;
   model_class->remove_row      = clutter_list_model_remove_row;
   model_class->resort          = clutter_list_model_resort;
+  model_class->get_n_rows      = clutter_list_model_get_n_rows;
 
   model_class->row_removed     = clutter_list_model_row_removed;
 }
index d7d16f0..9ff54b8 100644 (file)
@@ -334,7 +334,15 @@ clutter_get_motion_events_enabled (void)
   return context->motion_events_per_actor;
 }
 
-guint _clutter_pix_to_id (guchar pixel[4]);
+static inline ClutterActor *
+_clutter_actor_get_by_id (guint32 id)
+{
+  ClutterMainContext *context = _clutter_context_get_default ();
+
+  g_assert (context->id_pool != NULL);
+
+  return clutter_id_pool_lookup (context->id_pool, id);
+}
 
 void
 _clutter_id_to_color (guint id, ClutterColor *col)
@@ -599,7 +607,7 @@ _clutter_do_pick (ClutterStage   *stage,
         }
 
       id = _clutter_pixel_to_id (pixel);
-      actor = clutter_get_actor_by_gid (id);
+      actor = _clutter_actor_get_by_id (id);
       goto result;
     }
 
@@ -659,9 +667,6 @@ _clutter_do_pick (ClutterStage   *stage,
   else
     _clutter_stage_set_pick_buffer_valid (stage, TRUE, mode);
 
-  /* Make sure Cogl flushes any batched geometry to the GPU driver */
-  cogl_flush ();
-
   /* Read the color of the screen co-ords pixel. RGBA_8888_PRE is used
      even though we don't care about the alpha component because under
      GLES this is the only format that is guaranteed to work so Cogl
@@ -694,7 +699,7 @@ _clutter_do_pick (ClutterStage   *stage,
     }
 
   id = _clutter_pixel_to_id (pixel);
-  actor = clutter_get_actor_by_gid (id);
+  actor = _clutter_actor_get_by_id (id);
 
 result:
 
@@ -2157,7 +2162,7 @@ emit_event (ClutterEvent *event,
   /* reentrancy check */
   if (lock != FALSE)
     {
-      g_warning ("Tried emitting event during event delivery, bailing out.n");
+      g_warning ("Tried emitting event during event delivery, bailing out.");
       return;
     }
 
@@ -2251,24 +2256,42 @@ is_off_stage (ClutterActor *stage,
               gfloat        x,
               gfloat        y)
 {
+  gfloat width, height;
+
+  clutter_actor_get_size (stage, &width, &height);
+
   return (x < 0 ||
           y < 0 ||
-          x >= clutter_actor_get_width (stage) ||
-          y >= clutter_actor_get_height (stage));
+          x >= width ||
+          y >= height);
 }
 
 /**
  * clutter_do_event
  * @event: a #ClutterEvent.
  *
- * Processes an event. This function should never be called by applications.
+ * Processes an event.
+ *
+ * The @event must be a valid #ClutterEvent and have a #ClutterStage
+ * associated to it.
+ *
+ * This function is only useful when embedding Clutter inside another
+ * toolkit, and it should never be called by applications.
  *
  * Since: 0.4
  */
 void
 clutter_do_event (ClutterEvent *event)
 {
-  if (!event->any.stage)
+  /* we need the stage for the event */
+  if (event->any.stage == NULL)
+    {
+      g_warning ("%s: Event does not have a stage: discarding.", G_STRFUNC);
+      return;
+    }
+
+  /* stages in destruction do not process events */
+  if (CLUTTER_ACTOR_IN_DESTRUCTION (event->any.stage))
     return;
 
   /* Instead of processing events when received, we queue them up to
@@ -2296,18 +2319,6 @@ _clutter_process_event_details (ClutterActor        *stage,
         event->any.source = stage;
         break;
 
-      case CLUTTER_LEAVE:
-      case CLUTTER_ENTER:
-        emit_pointer_event (event, device);
-        break;
-
-      case CLUTTER_DESTROY_NOTIFY:
-      case CLUTTER_DELETE:
-        event->any.source = stage;
-        /* the stage did not handle the event, so we just quit */
-        clutter_stage_event (CLUTTER_STAGE (stage), event);
-        break;
-
       case CLUTTER_KEY_PRESS:
       case CLUTTER_KEY_RELEASE:
         {
@@ -2329,6 +2340,65 @@ _clutter_process_event_details (ClutterActor        *stage,
         }
         break;
 
+      case CLUTTER_ENTER:
+        /* if we're entering from outside the stage we need
+         * to check whether the pointer is actually on another
+         * actor, and emit an additional pointer event
+         */
+        if (event->any.source == stage &&
+            event->crossing.related == NULL)
+          {
+            ClutterActor *actor = NULL;
+
+            emit_pointer_event (event, device);
+
+            actor = _clutter_input_device_update (device, FALSE);
+            if (actor != stage)
+              {
+                ClutterEvent *crossing;
+
+                /* we emit the exact same event on the actor */
+                crossing = clutter_event_copy (event);
+                crossing->crossing.related = stage;
+                crossing->crossing.source = actor;
+
+                emit_pointer_event (crossing, device);
+                clutter_event_free (crossing);
+              }
+          }
+        else
+          emit_pointer_event (event, device);
+        break;
+
+      case CLUTTER_LEAVE:
+        /* same as CLUTTER_ENTER above: when leaving the stage
+         * we need to also emit a CLUTTER_LEAVE event on the
+         * actor currently underneath the device, unless it's the
+         * stage
+         */
+        if (event->any.source == stage &&
+            event->crossing.related == NULL &&
+            device->cursor_actor != stage)
+          {
+            ClutterEvent *crossing;
+
+            crossing = clutter_event_copy (event);
+            crossing->crossing.related = stage;
+            crossing->crossing.source = device->cursor_actor;
+
+            emit_pointer_event (crossing, device);
+            clutter_event_free (crossing);
+          }
+        emit_pointer_event (event, device);
+        break;
+
+      case CLUTTER_DESTROY_NOTIFY:
+      case CLUTTER_DELETE:
+        event->any.source = stage;
+        /* the stage did not handle the event, so we just quit */
+        clutter_stage_event (CLUTTER_STAGE (stage), event);
+        break;
+
       case CLUTTER_MOTION:
         /* Only stage gets motion events if clutter_set_motion_events is TRUE,
          * and the event is not a synthetic event with source set.
@@ -2416,7 +2486,7 @@ _clutter_process_event_details (ClutterActor        *stage,
                * get the actor underneath
                */
               if (device != NULL)
-                actor = _clutter_input_device_update (device);
+                actor = _clutter_input_device_update (device, TRUE);
               else
                 {
                   CLUTTER_NOTE (EVENT, "No device found: picking");
@@ -2437,11 +2507,6 @@ _clutter_process_event_details (ClutterActor        *stage,
               actor = event->any.source;
             }
 
-          /* FIXME: for an optimisation should check if there are
-           * actually any reactive actors and avoid the pick all together
-           * (signalling just the stage). Should be big help for gles.
-           */
-
           CLUTTER_NOTE (EVENT,
                         "Reactive event received at %.2f, %.2f - actor: %p",
                         x, y,
@@ -2498,7 +2563,6 @@ _clutter_process_event (ClutterEvent *event)
   context->current_event = NULL;
 }
 
-
 /**
  * clutter_get_actor_by_gid:
  * @id: a #ClutterActor ID.
@@ -2510,16 +2574,10 @@ _clutter_process_event (ClutterEvent *event)
  *
  * Since: 0.6
  */
-ClutterActor*
+ClutterActor *
 clutter_get_actor_by_gid (guint32 id)
 {
-  ClutterMainContext *context;
-
-  context = _clutter_context_get_default ();
-
-  g_return_val_if_fail (context != NULL, NULL);
-
-  return CLUTTER_ACTOR (clutter_id_pool_lookup (context->id_pool, id));
+  return _clutter_actor_get_by_id (id);
 }
 
 void
@@ -3210,3 +3268,47 @@ clutter_get_default_text_direction (void)
 {
   return clutter_text_direction;
 }
+
+/*< private >
+ * clutter_clear_events_queue:
+ *
+ * Clears the events queue stored in the main context.
+ */
+void
+_clutter_clear_events_queue (void)
+{
+  ClutterMainContext *context = _clutter_context_get_default ();
+
+  if (context->events_queue != NULL)
+    {
+      g_queue_foreach (context->events_queue,
+                       (GFunc) clutter_event_free,
+                       NULL);
+      g_queue_free (context->events_queue);
+      context->events_queue = NULL;
+    }
+}
+
+void
+_clutter_clear_events_queue_for_stage (ClutterStage *stage)
+{
+  ClutterMainContext *context = _clutter_context_get_default ();
+  GList *l, *next;
+
+  if (context->events_queue == NULL)
+    return;
+
+  /* Remove any pending events for this stage from the event queue */
+  for (l = context->events_queue->head; l; l = next)
+    {
+      ClutterEvent *event = l->data;
+
+      next = l->next;
+
+      if (event->any.stage == stage)
+        {
+          g_queue_delete_link (context->events_queue, l);
+          clutter_event_free (event);
+        }
+    }
+}
index e5d9d5c..49745ef 100644 (file)
@@ -13,6 +13,7 @@ VOID:INT,INT,INT,INT
 VOID:OBJECT
 VOID:OBJECT,FLOAT,FLOAT
 VOID:OBJECT,FLOAT,FLOAT,FLAGS
+VOID:OBJECT,INT
 VOID:OBJECT,PARAM
 VOID:OBJECT,POINTER
 VOID:OBJECT,UINT
index 74cb1d9..880b73a 100644 (file)
  * <refsect2 id="ClutterModel-script">
  *   <title>ClutterModel custom properties for #ClutterScript</title>
  *   <para>#ClutterModel defines a custom property "columns" for #ClutterScript
- *   which allows defining the column names and types.</para>
- *   <example id="ClutterModel-script-column-example">
- *     <title>Example of the "columns" custom property</title>
+ *   which allows defining the column names and types. It also defines a custom
+ *   "rows" property which allows filling the #ClutterModel with some
+ *   data.</para>
+ *   <example id="ClutterModel-script-example">
+ *     <title>Example of the "columns" and "rows" custom properties</title>
  *     <para>The definition below will create a #ClutterListModel with three
  *     columns: the first one with name "Name" and containing strings; the
  *     second one with name "Score" and containing integers; the third one with
- *     name "Icon" and containing #ClutterTexture<!-- -->s.</para>
+ *     name "Icon" and containing #ClutterTexture<!-- -->s. The model is filled
+ *     with three rows. A row can be defined either with an array that holds
+ *     all columns of a row, or an object that holds "column-name" :
+ *     "column-value" pairs.
+ *     </para>
  *     <programlisting>
  *  {
  *    "type" : "ClutterListModel",
  *      [ "Name", "gchararray" ],
  *      [ "Score", "gint" ],
  *      [ "Icon", "ClutterTexture" ]
+ *    ],
+ *    "rows" : [
+ *      [ "Team 1", 42, { "type" : "ClutterTexture", "filename" : "team1.png" } ],
+ *      [ "Team 2", 23, "team2-icon-script-id" ],
+ *      { "Name" : "Team 3", "Icon" : "team3-icon-script-id" }
  *    ]
  *  }
  *     </programlisting>
 #include "clutter-private.h"
 #include "clutter-debug.h"
 #include "clutter-scriptable.h"
+#include "clutter-script-private.h"
 
 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
 
@@ -252,6 +264,32 @@ clutter_model_real_get_n_columns (ClutterModel *model)
   return priv->n_columns;
 }
 
+static guint
+clutter_model_real_get_n_rows (ClutterModel *model)
+{
+  ClutterModelIter *iter;
+  guint row_count;
+
+  g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0);
+
+  iter = clutter_model_get_first_iter (model);
+  if (iter == NULL)
+    return 0;
+
+  row_count = 0;
+  while (!clutter_model_iter_is_last (iter))
+    {
+      if (clutter_model_filter_iter (model, iter))
+        row_count += 1;
+
+      iter = clutter_model_iter_next (iter);
+    }
+
+  g_object_unref (iter);
+
+  return row_count;
+}
+
 static void 
 clutter_model_finalize (GObject *object)
 {
@@ -314,6 +352,7 @@ clutter_model_class_init (ClutterModelClass *klass)
   klass->get_column_name  = clutter_model_real_get_column_name;
   klass->get_column_type  = clutter_model_real_get_column_type;
   klass->get_n_columns    = clutter_model_real_get_n_columns;
+  klass->get_n_rows       = clutter_model_real_get_n_rows;
 
   /**
    * ClutterModel:filter-set:
@@ -501,49 +540,73 @@ clutter_model_parse_custom_node (ClutterScriptable *scriptable,
                                  const gchar       *name,
                                  JsonNode          *node)
 {
-  GSList *columns = NULL;
-  GList *elements, *l;
-
-  if (strcmp (name, "columns") != 0)
-    return FALSE;
+  if (strcmp (name, "columns") == 0)
+    {
+      GSList *columns = NULL;
+      GList *elements, *l;
 
-  if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
-    return FALSE;
+      if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
+        return FALSE;
 
-  elements = json_array_get_elements (json_node_get_array (node));
+      elements = json_array_get_elements (json_node_get_array (node));
 
-  for (l = elements; l != NULL; l = l->next)
-    {
-      JsonNode *child_node = l->data;
-      JsonArray *array = json_node_get_array (child_node);
-      ColumnInfo *cinfo;
-      const gchar *column_name;
-      const gchar *type_name;
-
-      if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY ||
-          json_array_get_length (array) != 2)
+      for (l = elements; l != NULL; l = l->next)
         {
-          g_warning ("A column must be an array of "
-                     "[\"column-name\", \"GType-name\"] pairs");
-          return FALSE;
+          JsonNode *child_node = l->data;
+          JsonArray *array = json_node_get_array (child_node);
+          ColumnInfo *cinfo;
+          const gchar *column_name;
+          const gchar *type_name;
+
+          if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY ||
+              json_array_get_length (array) != 2)
+            {
+              g_warning ("A column must be an array of "
+                         "[\"column-name\", \"GType-name\"] pairs");
+              return FALSE;
+            }
+
+          column_name = json_array_get_string_element (array, 0);
+          type_name = json_array_get_string_element (array, 1);
+
+          cinfo = g_slice_new0 (ColumnInfo);
+          cinfo->name = g_strdup (column_name);
+          cinfo->type = clutter_script_get_type_from_name (script, type_name);
+
+          columns = g_slist_prepend (columns, cinfo);
         }
 
-      column_name = json_array_get_string_element (array, 0);
-      type_name = json_array_get_string_element (array, 1);
+      g_list_free (elements);
 
-      cinfo = g_slice_new0 (ColumnInfo);
-      cinfo->name = g_strdup (column_name);
-      cinfo->type = clutter_script_get_type_from_name (script, type_name);
+      g_value_init (value, G_TYPE_POINTER);
+      g_value_set_pointer (value, g_slist_reverse (columns));
 
-      columns = g_slist_prepend (columns, cinfo);
+      return TRUE;
     }
+  else if (strcmp (name, "rows") == 0)
+    {
+      GSList *rows = NULL;
+      GList *elements, *l;
 
-  g_list_free (elements);
+      if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
+        return FALSE;
+
+      /*
+       * at this point we have no information about the column types, so
+       * we just copy the json elements and resolve them in the
+       * set_custom_property method
+       */
+      elements = json_array_get_elements (json_node_get_array (node));
+      for (l = elements; l != NULL; l = l->next)
+        rows = g_slist_prepend (rows, json_node_copy (l->data));
+      g_list_free (elements);
 
-  g_value_init (value, G_TYPE_POINTER);
-  g_value_set_pointer (value, g_slist_reverse (columns));
+      g_value_init (value, G_TYPE_POINTER);
+      g_value_set_pointer (value, g_slist_reverse (rows));
 
-  return TRUE;
+      return TRUE;
+    }
+  return FALSE;
 }
 
 static void
@@ -577,6 +640,110 @@ clutter_model_set_custom_property (ClutterScriptable *scriptable,
 
       g_slist_free (columns);
     }
+  else if (strcmp (name, "rows") == 0)
+    {
+      ClutterModel *model = CLUTTER_MODEL (scriptable);
+      GSList *rows, *l;
+      guint n_columns, row = 0;
+
+      rows = g_value_get_pointer (value);
+      n_columns = clutter_model_get_n_columns (model);
+
+      for (l = rows; l; l = l->next)
+        {
+          JsonNode *node = l->data;
+          guint *columns, i, n_values = 0;
+          GValueArray *values;
+
+          if (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY)
+            {
+              JsonArray *array = json_node_get_array (node);
+              if (json_array_get_length (array) != n_columns)
+                {
+                  g_warning ("Row %d contains the wrong count of columns",
+                             g_slist_position (rows, l) + 1);
+                  row++;
+                  continue;
+                }
+
+              n_values = n_columns;
+              columns = g_new (guint, n_values);
+              values = g_value_array_new (n_values);
+
+              for (i = 0; i < n_values; i++)
+                {
+                  GType column_type;
+                  const gchar *column_name;
+                  GValue v = { 0, };
+
+                  column_type = clutter_model_get_column_type (model, i);
+                  column_name = clutter_model_get_column_name (model, i);
+                  columns[i] = i;
+                  g_value_init (&v, column_type);
+                  clutter_script_parse_node (script, &v, column_name,
+                                             json_array_get_element (array, i),
+                                             NULL);
+                  g_value_array_append (values, &v);
+                  g_value_unset (&v);
+                }
+            }
+          else if (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT)
+            {
+              JsonObject *object = json_node_get_object (node);
+              GList *members, *m;
+              guint column = 0;
+
+              n_values = json_object_get_size (object);
+              columns = g_new (guint, n_values);
+              values = g_value_array_new (n_values);
+
+              members = json_object_get_members (object);
+              for (m = members; m; m = m->next)
+                {
+                  const gchar *mname = m->data;
+
+                  for (i = 0; i < clutter_model_get_n_columns (model); i++)
+                    {
+                      const gchar *cname;
+
+                      cname = clutter_model_get_column_name (model, i);
+                      if (strcmp (mname, cname) == 0)
+                        {
+                          JsonNode *member;
+                          GType col_type;
+                          const gchar *col_name;
+                          GValue v = { 0, };
+
+                          col_type = clutter_model_get_column_type (model, i);
+                          col_name = clutter_model_get_column_name (model, i);
+                          columns[column] = i;
+                          g_value_init (&v, col_type);
+                          member = json_object_get_member (object, mname);
+                          clutter_script_parse_node (script, &v,
+                                                     col_name, member,
+                                                     NULL);
+                          g_value_array_append (values, &v);
+                          g_value_unset (&v);
+                          break;
+                        }
+                    }
+                  column++;
+                }
+            }
+          else
+            {
+              row++;
+              continue;
+            }
+
+          clutter_model_insertv (model, row, n_values, columns, values->values);
+          g_value_array_free (values);
+          g_free (columns);
+          json_node_free (node);
+          row++;
+        }
+      g_slist_free (rows);
+    }
 }
 
 
@@ -1373,38 +1540,11 @@ clutter_model_get_last_iter (ClutterModel *model)
 guint
 clutter_model_get_n_rows (ClutterModel *model)
 {
-  ClutterModelClass *klass;
-  guint row_count;
-
   g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0);
 
-  klass = CLUTTER_MODEL_GET_CLASS (model);
-  if (klass->get_n_rows)
-    row_count = klass->get_n_rows (model);
-  else
-    {
-      ClutterModelIter *iter;
-
-      iter = clutter_model_get_first_iter (model);
-      if (iter == NULL)
-        return 0;
-
-      row_count = 0;
-      while (!clutter_model_iter_is_last (iter))
-        {
-          if (clutter_model_filter_iter (model, iter))
-            row_count += 1;
-
-          iter = clutter_model_iter_next (iter);
-        }
-
-      g_object_unref (iter);
-    }
-
-  return row_count;
+  return CLUTTER_MODEL_GET_CLASS (model)->get_n_rows (model);
 }
 
-
 /**
  * clutter_model_set_sorting_column:
  * @model: a #ClutterModel
@@ -1499,7 +1639,7 @@ clutter_model_foreach (ClutterModel            *model,
  * clutter_model_set_sort:
  * @model: a #ClutterModel
  * @column: the column to sort on
- * @func: a #ClutterModelSortFunc, or #NULL
+ * @func: (allow-none): a #ClutterModelSortFunc, or #NULL
  * @user_data: user data to pass to @func, or #NULL
  * @notify: destroy notifier of @user_data, or #NULL
  *
@@ -1509,7 +1649,7 @@ clutter_model_foreach (ClutterModel            *model,
  */
 void
 clutter_model_set_sort (ClutterModel         *model,
-                        guint                 column,
+                        gint                  column,
                         ClutterModelSortFunc  func,
                         gpointer              user_data,
                         GDestroyNotify        notify)
@@ -1536,7 +1676,7 @@ clutter_model_set_sort (ClutterModel         *model,
 /**
  * clutter_model_set_filter:
  * @model: a #ClutterModel
- * @func: a #ClutterModelFilterFunc, or #NULL
+ * @func: (allow-none): a #ClutterModelFilterFunc, or #NULL
  * @user_data: user data to pass to @func, or #NULL
  * @notify: destroy notifier of @user_data, or #NULL
  *
@@ -1962,7 +2102,7 @@ clutter_model_iter_get (ClutterModelIter *iter,
  * clutter_model_iter_get_value:
  * @iter: a #ClutterModelIter
  * @column: column number to retrieve the value from
- * @value: an empty #GValue to set
+ * @value: (out): an empty #GValue to set
  *
  * Sets an initializes @value to that at @column. When done with @value, 
  * g_value_unset() needs to be called to free any allocated memory.
index 0a9e56d..a49ddbb 100644 (file)
@@ -244,7 +244,7 @@ void                  clutter_model_foreach            (ClutterModel     *model,
                                                         ClutterModelForeachFunc func, 
                                                         gpointer          user_data);
 void                  clutter_model_set_sort           (ClutterModel     *model, 
-                                                        guint             column,
+                                                        gint              column,
                                                         ClutterModelSortFunc func, 
                                                         gpointer          user_data,
                                                         GDestroyNotify    notify);
index b6e6900..1fbb17e 100644 (file)
@@ -196,6 +196,7 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect)
   CoglMatrix modelview;
   gfloat fbo_width, fbo_height;
   gfloat width, height;
+  gfloat xexpand, yexpand;
 
   if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
     return FALSE;
@@ -234,13 +235,53 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect)
    * framebuffer. */
   clutter_actor_get_size (priv->stage, &width, &height);
   clutter_actor_box_get_origin (&box, &priv->x_offset, &priv->y_offset);
-  cogl_set_viewport (-priv->x_offset, -priv->y_offset, width, height);
+
+  /* Expand the viewport if the actor is partially off-stage,
+   * otherwise the actor will end up clipped to the stage viewport
+   */
+  xexpand = 0.f;
+  if (priv->x_offset < 0.f)
+    xexpand = -priv->x_offset;
+  if (priv->x_offset + fbo_width > width)
+    xexpand = MAX (xexpand, (priv->x_offset + fbo_width) - width);
+
+  yexpand = 0.f;
+  if (priv->y_offset < 0.f)
+    yexpand = -priv->y_offset;
+  if (priv->y_offset + fbo_height > height)
+    yexpand = MAX (yexpand, (priv->y_offset + fbo_height) - height);
+
+  /* Set the viewport */
+  cogl_set_viewport (-(priv->x_offset + xexpand), -(priv->y_offset + yexpand),
+                     width + (2 * xexpand), height + (2 * yexpand));
 
   /* Copy the stage's projection matrix across to the framebuffer */
   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (priv->stage),
                                         &projection);
   cogl_set_projection_matrix (&projection);
 
+  /* If we've expanded the viewport, make sure to scale the modelview
+   * matrix accordingly (as it's been initialised to work with the
+   * original viewport and not our expanded one).
+   */
+  if (xexpand > 0.f || yexpand > 0.f)
+    {
+      CoglMatrix correction;
+      gfloat new_width, new_height;
+
+      new_width = width + (2 * xexpand);
+      new_height = height + (2 * yexpand);
+
+      cogl_matrix_init_identity (&correction);
+      cogl_matrix_scale (&correction,
+                         width / new_width,
+                         height / new_height,
+                         1);
+
+      cogl_matrix_multiply (&correction, &correction, &modelview);
+      modelview = correction;
+    }
+
   /* Copy the modelview that would have been used if rendering onscreen */
   cogl_set_modelview_matrix (&modelview);
 
@@ -251,6 +292,12 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect)
 
   cogl_push_matrix ();
 
+  /* Override the actor's opacity to fully opaque - we paint the offscreen
+   * texture with the actor's paint opacity, so we need to do this to avoid
+   * multiplying the opacity twice.
+   */
+  _clutter_actor_set_opacity_override (priv->actor, 0xff);
+
   return TRUE;
 }
 
@@ -307,6 +354,9 @@ clutter_offscreen_effect_post_paint (ClutterEffect *effect)
   cogl_matrix_translate (&modelview, priv->x_offset, priv->y_offset, 0.0f);
   cogl_set_modelview_matrix (&modelview);
 
+  /* Remove the opacity override */
+  _clutter_actor_set_opacity_override (priv->actor, -1);
+
   /* paint the target material; this is virtualized for
    * sub-classes that require special hand-holding
    */
index 8afcf85..5fe0748 100644 (file)
@@ -50,8 +50,6 @@
 #define CLUTTER_IS_PAGE_TURN_EFFECT_CLASS(k)    (G_TYPE_CHECK_CLASS_TYPE ((k), CLUTTER_TYPE_PAGE_TURN_EFFECT))
 #define CLUTTER_PAGE_TURN_EFFECT_GET_CLASS(o)   (G_TYPE_INSTANCE_GET_CLASS ((o), CLUTTER_TYPE_PAGE_TURN_EFFECT, ClutterPageTurnEffectClass))
 
-typedef struct _ClutterPageTurnEffectClass      ClutterPageTurnEffectClass;
-
 struct _ClutterPageTurnEffect
 {
   ClutterDeformEffect parent_instance;
index ca95fb8..9a9b2fe 100644 (file)
@@ -49,6 +49,7 @@ G_BEGIN_DECLS
  * Since: 1.4
  */
 typedef struct _ClutterPageTurnEffect           ClutterPageTurnEffect;
+typedef struct _ClutterPageTurnEffectClass      ClutterPageTurnEffectClass;
 
 GType clutter_page_turn_effect_get_type (void) G_GNUC_CONST;
 
index 2ccbc01..3016e01 100644 (file)
@@ -50,8 +50,6 @@
 #define CLUTTER_IS_PATH_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_PATH_CONSTRAINT))
 #define CLUTTER_PATH_CONSTRAINT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_PATH_CONSTRAINT, ClutterPathConstraintClass))
 
-typedef struct _ClutterPathConstraintClass      ClutterPathConstraintClass;
-
 struct _ClutterPathConstraint
 {
   ClutterConstraint parent_instance;
index 339d07c..e65555e 100644 (file)
@@ -46,7 +46,8 @@ G_BEGIN_DECLS
  *
  * Since: 1.6
  */
-typedef struct _ClutterPathConstraint   ClutterPathConstraint;
+typedef struct _ClutterPathConstraint           ClutterPathConstraint;
+typedef struct _ClutterPathConstraintClass      ClutterPathConstraintClass;
 
 GType clutter_path_constraint_get_type (void) G_GNUC_CONST;
 
index 8cf48c5..b06018d 100644 (file)
@@ -99,54 +99,66 @@ typedef enum {
   CLUTTER_INTERNAL_CHILD = 1 << 6
 } ClutterPrivateFlags;
 
+/*
+ * ClutterMainContext:
+ *
+ * The shared state of Clutter
+ */
 struct _ClutterMainContext
 {
-  ClutterBackend  *backend;            /* holds a pointer to the windowing
-                                          system backend */
-  GQueue          *events_queue;       /* the main event queue */
+  /* the main windowing system backend */
+  ClutterBackend *backend;
 
-  guint            is_initialized : 1;
-  guint            motion_events_per_actor : 1;/* set for enter/leave events */
-  guint            defer_display_setup : 1;
-  guint            options_parsed : 1;
+  /* the main event queue */
+  GQueue *events_queue;
 
-  GTimer          *timer;             /* Used for debugging scheduler */
+  /* timer used to print the FPS count */
+  GTimer *timer;
 
-  ClutterPickMode  pick_mode;          /* Indicates pick render mode   */
+  ClutterPickMode  pick_mode;
 
-  gint             num_reactives;      /* Num of reactive actors */
+  /* mapping between reused integer ids and actors */
+  ClutterIDPool *id_pool;
 
-  ClutterIDPool   *id_pool;            /* mapping between reused integer ids
-                                        * and actors
-                                        */
-  guint            frame_rate;         /* Default FPS */
+  /* default FPS; this is only used if we cannot sync to vblank */
+  guint frame_rate;
 
-  ClutterActor    *pointer_grab_actor; /* The actor having the pointer grab
-                                        * (or NULL if there is no pointer grab
-                                        */
-  ClutterActor    *keyboard_grab_actor; /* The actor having the pointer grab
-                                         * (or NULL if there is no pointer
-                                         *  grab)
-                                         */
-  GSList          *shaders;            /* stack of overridden shaders */
+  /* actors with a grab on all devices */
+  ClutterActor *pointer_grab_actor;
+  ClutterActor *keyboard_grab_actor;
 
-  ClutterActor    *motion_last_actor;
+  /* stack of overridden shaders during paint */
+  GSList *shaders;
 
   /* fb bit masks for col<->id mapping in picking */
-  gint fb_r_mask, fb_g_mask, fb_b_mask;
-  gint fb_r_mask_used, fb_g_mask_used, fb_b_mask_used;
+  gint fb_r_mask;
+  gint fb_g_mask;
+  gint fb_b_mask;
+  gint fb_r_mask_used;
+  gint fb_g_mask_used;
+  gint fb_b_mask_used;
 
-  PangoContext     *pango_context;      /* Global Pango context */
-  CoglPangoFontMap *font_map;           /* Global font map */
+  PangoContext *pango_context;  /* Global Pango context */
+  CoglPangoFontMap *font_map;   /* Global font map */
 
   ClutterEvent *current_event;
   guint32 last_event_time;
 
   gulong redraw_count;
 
+  /* list of repaint functions installed through
+   * clutter_threads_add_repaint_func()
+   */
   GList *repaint_funcs;
 
+  /* main settings singleton */
   ClutterSettings *settings;
+
+  /* boolean flags */
+  guint is_initialized          : 1;
+  guint motion_events_per_actor : 1;
+  guint defer_display_setup     : 1;
+  guint options_parsed          : 1;
 };
 
 /* shared between clutter-main.c and clutter-frame-source.c */
@@ -161,18 +173,16 @@ gboolean _clutter_threads_dispatch      (gpointer data);
 void     _clutter_threads_dispatch_free (gpointer data);
 
 #define CLUTTER_CONTEXT()      (_clutter_context_get_default ())
-ClutterMainContext *_clutter_context_get_default (void);
-gboolean            _clutter_context_is_initialized (void);
-PangoContext *_clutter_context_create_pango_context (ClutterMainContext *self);
-PangoContext *_clutter_context_get_pango_context    (ClutterMainContext *self);
-
-#define CLUTTER_PARAM_READABLE  \
-        G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
-#define CLUTTER_PARAM_WRITABLE  \
-        G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
-#define CLUTTER_PARAM_READWRITE \
-        G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |G_PARAM_STATIC_BLURB
+ClutterMainContext *    _clutter_context_get_default            (void);
+gboolean                _clutter_context_is_initialized         (void);
+PangoContext *          _clutter_context_create_pango_context   (ClutterMainContext *self);
+PangoContext *          _clutter_context_get_pango_context      (ClutterMainContext *self);
+
+#define CLUTTER_PARAM_READABLE  (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)
+#define CLUTTER_PARAM_WRITABLE  (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)
+#define CLUTTER_PARAM_READWRITE (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)
 
+/* automagic interning of a static string */
 #define I_(str)  (g_intern_static_string ((str)))
 
 /* mark all properties under the "Property" context */
@@ -189,6 +199,10 @@ gboolean      _clutter_feature_init (GError **error);
 /* Reinjecting queued events for processing */
 void _clutter_process_event (ClutterEvent *event);
 
+/* clears the event queue inside the main context */
+void _clutter_clear_events_queue           (void);
+void _clutter_clear_events_queue_for_stage (ClutterStage *stage);
+
 /* Picking code */
 ClutterActor *_clutter_do_pick (ClutterStage    *stage,
                                gint             x,
@@ -200,7 +214,8 @@ void          _clutter_do_redraw (ClutterStage *stage);
 
 guint         _clutter_pixel_to_id (guchar pixel[4]);
 
-void          _clutter_id_to_color (guint id, ClutterColor *col);
+void          _clutter_id_to_color (guint id,
+                                    ClutterColor *col);
 
 /* use this function as the accumulator if you have a signal with
  * a G_TYPE_BOOLEAN return value; this will stop the emission as
@@ -228,6 +243,13 @@ void     _clutter_event_set_platform_data (ClutterEvent       *event,
                                            gpointer            data);
 gpointer _clutter_event_get_platform_data (const ClutterEvent *event);
 
+void     _clutter_event_push              (const ClutterEvent *event,
+                                           gboolean            do_copy);
+void     _clutter_event_set_device        (ClutterEvent       *event,
+                                           ClutterInputDevice *device);
+void     _clutter_event_set_source_device (ClutterEvent       *event,
+                                           ClutterInputDevice *device);
+
 void                _clutter_util_fully_transform_vertices (const CoglMatrix *modelview,
                                                             const CoglMatrix *projection,
                                                             const int *viewport,
index 1bcab56..110d5f8 100644 (file)
@@ -356,7 +356,7 @@ clutter_rectangle_new_with_color (const ClutterColor *color)
 /**
  * clutter_rectangle_get_color:
  * @rectangle: a #ClutterRectangle
- * @color: return location for a #ClutterColor
+ * @color: (out): return location for a #ClutterColor
  *
  * Retrieves the color of @rectangle.
  */
@@ -476,7 +476,7 @@ clutter_rectangle_set_border_width (ClutterRectangle *rectangle,
 /**
  * clutter_rectangle_get_border_color:
  * @rectangle: a #ClutterRectangle
- * @color: return location for a #ClutterColor
+ * @color: (out): return location for a #ClutterColor
  *
  * Gets the color of the border used by @rectangle and places
  * it into @color.
index 959d25a..debcc39 100644 (file)
@@ -1069,15 +1069,21 @@ clutter_script_parse_node (ClutterScript *script,
        * is a custom member that will be parsed by the Scriptable
        * interface implementantion
        */
-      if (pspec == NULL)
+      if (pspec == NULL && !G_IS_VALUE (value))
         return FALSE;
       else
         {
-          GType p_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
+          GType p_type;
           ObjectInfo *oinfo;
           const gchar *id;
 
-          g_value_init (value, p_type);
+          if (G_IS_VALUE (value))
+            p_type = G_VALUE_TYPE (value);
+          else
+            {
+              p_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
+              g_value_init (value, p_type);
+            }
 
           if (g_type_is_a (p_type, G_TYPE_OBJECT))
             {
@@ -1160,11 +1166,12 @@ clutter_script_parse_node (ClutterScript *script,
       return FALSE;
 
     case JSON_NODE_ARRAY:
-      if (!pspec)
+      if (!pspec && !G_IS_VALUE (value))
         return FALSE;
       else
         {
-          g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+          if (!G_IS_VALUE (value))
+            g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
 
           if (G_VALUE_HOLDS (value, CLUTTER_TYPE_KNOT))
             {
@@ -1236,10 +1243,10 @@ clutter_script_parse_node (ClutterScript *script,
     case JSON_NODE_VALUE:
       json_node_get_value (node, &node_value);
 
-      if (pspec)
-        g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
-      else
+      if (!pspec && !G_IS_VALUE (value))
         g_value_init (value, G_VALUE_TYPE (&node_value));
+      else if (pspec)
+        g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
 
       switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
         {
@@ -1356,6 +1363,15 @@ clutter_script_parse_node (ClutterScript *script,
           break;
         }
 
+      if (G_VALUE_TYPE (value) == G_TYPE_GTYPE &&
+          G_VALUE_HOLDS (&node_value, G_TYPE_STRING))
+        {
+          const gchar *str = g_value_get_string (&node_value);
+          GType type = clutter_script_get_type_from_name (script, str);
+          g_value_set_gtype (value, type);
+          retval = TRUE;
+        }
+
       g_value_unset (&node_value);
       break;
     }
index c9b5f38..455d25c 100644 (file)
@@ -32,8 +32,6 @@
 #define CLUTTER_IS_SETTINGS_CLASS(klass)        (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SETTINGS))
 #define CLUTTER_SETTINGS_GET_CLASS(obj)         (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SETTINGS, ClutterSettingsClass))
 
-typedef struct _ClutterSettingsClass            ClutterSettingsClass;
-
 /**
  * ClutterSettings:
  *
index 9211127..aa254ec 100644 (file)
@@ -14,6 +14,7 @@ G_BEGIN_DECLS
 #define CLUTTER_IS_SETTINGS(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_SETTINGS))
 
 typedef struct _ClutterSettings         ClutterSettings;
+typedef struct _ClutterSettingsClass    ClutterSettingsClass;
 
 GType clutter_settings_get_type (void) G_GNUC_CONST;
 
index c4cfd67..e2109c7 100644 (file)
@@ -95,6 +95,31 @@ static GParamSpec *obj_props[PROP_LAST];
 
 G_DEFINE_TYPE (ClutterShader, clutter_shader, G_TYPE_OBJECT);
 
+static inline void
+clutter_shader_release_internal (ClutterShader *shader)
+{
+  ClutterShaderPrivate *priv = shader->priv;
+
+  if (!priv->compiled)
+    return;
+
+  g_assert (priv->program != COGL_INVALID_HANDLE);
+
+  if (priv->vertex_is_glsl && priv->vertex_shader != COGL_INVALID_HANDLE)
+    cogl_handle_unref (priv->vertex_shader);
+
+  if (priv->fragment_is_glsl && priv->fragment_shader != COGL_INVALID_HANDLE)
+    cogl_handle_unref (priv->fragment_shader);
+
+  if (priv->program != COGL_INVALID_HANDLE)
+    cogl_handle_unref (priv->program);
+
+  priv->vertex_shader = COGL_INVALID_HANDLE;
+  priv->fragment_shader = COGL_INVALID_HANDLE;
+  priv->program = COGL_INVALID_HANDLE;
+  priv->compiled = FALSE;
+}
+
 static void
 clutter_shader_finalize (GObject *object)
 {
@@ -104,8 +129,6 @@ clutter_shader_finalize (GObject *object)
   shader = CLUTTER_SHADER (object);
   priv   = shader->priv;
 
-  clutter_shader_release (shader);
-
   clutter_shaders_list = g_list_remove (clutter_shaders_list, object);
 
   g_free (priv->fragment_source);
@@ -115,6 +138,16 @@ clutter_shader_finalize (GObject *object)
 }
 
 static void
+clutter_shader_dispose (GObject *object)
+{
+  ClutterShader *shader = CLUTTER_SHADER (object);
+
+  clutter_shader_release_internal (shader);
+
+  G_OBJECT_CLASS (clutter_shader_parent_class)->finalize (object);
+}
+
+static void
 clutter_shader_set_property (GObject      *object,
                              guint         prop_id,
                              const GValue *value,
@@ -197,6 +230,7 @@ clutter_shader_class_init (ClutterShaderClass *klass)
   GParamSpec *pspec = NULL;
 
   object_class->finalize      = clutter_shader_finalize;
+  object_class->dispose       = clutter_shader_dispose;
   object_class->set_property  = clutter_shader_set_property;
   object_class->get_property  = clutter_shader_get_property;
   object_class->constructor   = clutter_shader_constructor;
@@ -584,30 +618,9 @@ clutter_shader_compile (ClutterShader  *shader,
 void
 clutter_shader_release (ClutterShader *shader)
 {
-  ClutterShaderPrivate *priv;
-
   g_return_if_fail (CLUTTER_IS_SHADER (shader));
 
-  priv = shader->priv;
-
-  if (!priv->compiled)
-    return;
-
-  g_assert (priv->program != COGL_INVALID_HANDLE);
-
-  if (priv->vertex_is_glsl && priv->vertex_shader != COGL_INVALID_HANDLE)
-    cogl_handle_unref (priv->vertex_shader);
-
-  if (priv->fragment_is_glsl && priv->fragment_shader != COGL_INVALID_HANDLE)
-    cogl_handle_unref (priv->fragment_shader);
-
-  if (priv->program != COGL_INVALID_HANDLE)
-    cogl_handle_unref (priv->program);
-
-  priv->vertex_shader = COGL_INVALID_HANDLE;
-  priv->fragment_shader = COGL_INVALID_HANDLE;
-  priv->program = COGL_INVALID_HANDLE;
-  priv->compiled = FALSE;
+  clutter_shader_release_internal (shader);
 
   _clutter_notify_by_pspec (G_OBJECT (shader), obj_props[PROP_COMPILED]);
 }
index 7384574..e80b4ca 100644 (file)
@@ -53,8 +53,6 @@
 #define CLUTTER_IS_SNAP_CONSTRAINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SNAP_CONSTRAINT))
 #define CLUTTER_SNAP_CONSTRAINT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SNAP_CONSTRAINT, ClutterSnapConstraintClass))
 
-typedef struct _ClutterSnapConstraintClass      ClutterSnapConstraintClass;
-
 struct _ClutterSnapConstraint
 {
   ClutterConstraint parent_instance;
index bbf909d..b800f83 100644 (file)
@@ -45,7 +45,8 @@ G_BEGIN_DECLS
  *
  * Since: 1.6
  */
-typedef struct _ClutterSnapConstraint   ClutterSnapConstraint;
+typedef struct _ClutterSnapConstraint           ClutterSnapConstraint;
+typedef struct _ClutterSnapConstraintClass      ClutterSnapConstraintClass;
 
 /**
  * ClutterSnapEdge:
index 879e162..f61fc9d 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <clutter/clutter-stage-window.h>
 #include <clutter/clutter-stage.h>
+#include <clutter/clutter-input-device.h>
 
 G_BEGIN_DECLS
 
@@ -82,6 +83,13 @@ ClutterStageQueueRedrawEntry *_clutter_stage_queue_actor_redraw            (Clut
                                                                             ClutterPaintVolume           *clip);
 void                          _clutter_stage_queue_redraw_entry_invalidate (ClutterStageQueueRedrawEntry *entry);
 
+void            _clutter_stage_add_device       (ClutterStage       *stage,
+                                                 ClutterInputDevice *device);
+void            _clutter_stage_remove_device    (ClutterStage       *stage,
+                                                 ClutterInputDevice *device);
+gboolean        _clutter_stage_has_device       (ClutterStage       *stage,
+                                                 ClutterInputDevice *device);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_STAGE_PRIVATE_H__ */
index 173f2df..a438d50 100644 (file)
@@ -180,3 +180,15 @@ _clutter_stage_window_set_accept_focus (ClutterStageWindow *window,
   if (iface->set_accept_focus)
     iface->set_accept_focus (window, accept_focus);
 }
+
+void
+_clutter_stage_window_redraw (ClutterStageWindow *window)
+{
+  ClutterStageWindowIface *iface;
+
+  g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window));
+
+  iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
+  if (iface->redraw)
+    iface->redraw (window);
+}
index fb985c1..d616d2b 100644 (file)
@@ -66,6 +66,8 @@ struct _ClutterStageWindowIface
 
   void          (* set_accept_focus)      (ClutterStageWindow *stage_window,
                                            gboolean            accept_focus);
+
+  void          (* redraw)                (ClutterStageWindow *stage_window);
 };
 
 GType clutter_stage_window_get_type (void) G_GNUC_CONST;
@@ -103,6 +105,8 @@ gboolean      _clutter_stage_window_ignoring_redraw_clips (ClutterStageWindow *w
 void          _clutter_stage_window_set_accept_focus      (ClutterStageWindow *window,
                                                            gboolean            accept_focus);
 
+void          _clutter_stage_window_redraw                (ClutterStageWindow *window);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_STAGE_WINDOW_H__ */
index d27c033..750b138 100644 (file)
@@ -135,6 +135,8 @@ struct _ClutterStagePrivate
 
   ClutterPickMode     pick_buffer_mode;
 
+  GHashTable *devices;
+
   guint relayout_pending       : 1;
   guint redraw_pending         : 1;
   guint is_fullscreen          : 1;
@@ -813,6 +815,9 @@ _clutter_stage_do_update (ClutterStage *stage)
 
   priv = stage->priv;
 
+  if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
+    return FALSE;
+
   /* NB: We need to ensure we have an up to date layout *before* we
    * check or clear the pending redraws flag since a relayout may
    * queue a redraw.
@@ -1158,29 +1163,14 @@ clutter_stage_dispose (GObject *object)
 {
   ClutterStage        *stage = CLUTTER_STAGE (object);
   ClutterStagePrivate *priv = stage->priv;
-  ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
-  ClutterMainContext  *context;
-  GList               *l, *next;
+  ClutterStageManager *stage_manager;
 
   clutter_actor_hide (CLUTTER_ACTOR (object));
 
+  stage_manager = clutter_stage_manager_get_default ();
   _clutter_stage_manager_remove_stage (stage_manager, stage);
 
-  context = _clutter_context_get_default ();
-
-  /* Remove any pending events for this stage from the event queue */
-  for (l = context->events_queue->head; l; l = next)
-    {
-      ClutterEvent *event = l->data;
-
-      next = l->next;
-
-      if (event->any.stage == stage)
-        {
-          g_queue_delete_link (context->events_queue, l);
-          clutter_event_free (event);
-        }
-    }
+  _clutter_clear_events_queue_for_stage (stage);
 
   if (priv->impl != NULL)
     {
@@ -1199,13 +1189,15 @@ clutter_stage_finalize (GObject *object)
   ClutterStage *stage = CLUTTER_STAGE (object);
   ClutterStagePrivate *priv = stage->priv;
 
-  g_queue_foreach (priv->event_queue, (GFunc)clutter_event_free, NULL);
+  g_queue_foreach (priv->event_queue, (GFunc) clutter_event_free, NULL);
   g_queue_free (priv->event_queue);
 
-  g_free (stage->priv->title);
+  g_free (priv->title);
 
   g_array_free (priv->paint_volume_stack, TRUE);
 
+  g_hash_table_destroy (priv->devices);
+
   G_OBJECT_CLASS (clutter_stage_parent_class)->finalize (object);
 }
 
@@ -1624,6 +1616,8 @@ clutter_stage_init (ClutterStage *self)
 
   priv->paint_volume_stack =
     g_array_new (FALSE, FALSE, sizeof (ClutterPaintVolume));
+
+  priv->devices = g_hash_table_new (NULL, NULL);
 }
 
 /**
@@ -1690,7 +1684,7 @@ clutter_stage_set_color (ClutterStage       *stage,
 /**
  * clutter_stage_get_color:
  * @stage: A #ClutterStage
- * @color: return location for a #ClutterColor
+ * @color: (out): return location for a #ClutterColor
  *
  * Retrieves the stage color.
  */
@@ -2783,18 +2777,20 @@ clutter_stage_queue_redraw (ClutterStage *stage)
 gboolean
 clutter_stage_is_default (ClutterStage *stage)
 {
+  ClutterStageManager *stage_manager;
   ClutterStageWindow *impl;
 
   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
 
-  if (CLUTTER_ACTOR (stage) == clutter_stage_get_default ())
-    return TRUE;
+  stage_manager = clutter_stage_manager_get_default ();
+  if (stage != clutter_stage_manager_get_default_stage (stage_manager))
+    return FALSE;
 
   impl = _clutter_stage_get_window (stage);
-  if (impl == _clutter_stage_get_default_window ())
-    return TRUE;
+  if (impl != _clutter_stage_get_default_window ())
+    return FALSE;
 
-  return FALSE;
+  return TRUE;
 }
 
 void
@@ -3325,7 +3321,7 @@ _clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage)
 }
 
 /**
- * clutter_stage_get_accept_focus:
+ * clutter_stage_set_accept_focus:
  * @stage: a #ClutterStage
  * @accept_focus: %TRUE to accept focus on show
  *
@@ -3373,3 +3369,35 @@ clutter_stage_get_accept_focus (ClutterStage *stage)
 
   return stage->priv->accept_focus;
 }
+
+void
+_clutter_stage_add_device (ClutterStage       *stage,
+                           ClutterInputDevice *device)
+{
+  ClutterStagePrivate *priv = stage->priv;
+
+  if (g_hash_table_lookup (priv->devices, device) != NULL)
+    return;
+
+  g_hash_table_insert (priv->devices, device, GINT_TO_POINTER (1));
+  _clutter_input_device_set_stage (device, stage);
+}
+
+void
+_clutter_stage_remove_device (ClutterStage       *stage,
+                              ClutterInputDevice *device)
+{
+  ClutterStagePrivate *priv = stage->priv;
+
+  _clutter_input_device_set_stage (device, NULL);
+  g_hash_table_remove (priv->devices, device);
+}
+
+gboolean
+_clutter_stage_has_device (ClutterStage       *stage,
+                           ClutterInputDevice *device)
+{
+  ClutterStagePrivate *priv = stage->priv;
+
+  return g_hash_table_lookup (priv->devices, device) != NULL;
+}
index 2fff78a..9162e24 100644 (file)
@@ -3133,6 +3133,10 @@ clutter_text_class_init (ClutterTextClass *klass)
                                        G_CALLBACK (clutter_text_real_del_prev),
                                        NULL, NULL);
   clutter_binding_pool_install_action (binding_pool, "delete-prev",
+                                       CLUTTER_KEY_BackSpace, CLUTTER_SHIFT_MASK,
+                                       G_CALLBACK (clutter_text_real_del_prev),
+                                       NULL, NULL);
+  clutter_binding_pool_install_action (binding_pool, "delete-prev",
                                        CLUTTER_KEY_BackSpace, CLUTTER_CONTROL_MASK,
                                        G_CALLBACK (clutter_text_real_del_word_prev),
                                        NULL, NULL);
@@ -4122,7 +4126,7 @@ clutter_text_set_color (ClutterText        *self,
 /**
  * clutter_text_get_color:
  * @self: a #ClutterText
- * @color: return location for a #ClutterColor
+ * @color: (out): return location for a #ClutterColor
  *
  * Retrieves the text color as set by clutter_text_set_color().
  *
index e240cf2..a2db02f 100644 (file)
@@ -1253,10 +1253,20 @@ _clutter_timeline_do_tick (ClutterTimeline *timeline,
 
   priv = timeline->priv;
 
+  /* Check the is_playing variable before performing the timeline tick.
+   * This is necessary, as if a timeline is stopped in response to a
+   * master-clock generated signal of a different timeline, this code can
+   * still be reached.
+   */
+  if (!priv->is_playing)
+    return;
+
   if (priv->waiting_first_tick)
     {
       priv->last_frame_time = tick_time;
+      priv->msecs_delta = 0;
       priv->waiting_first_tick = FALSE;
+      clutter_timeline_do_frame (timeline);
     }
   else
     {
index 4cb2fa4..95f2bfa 100644 (file)
@@ -96,7 +96,7 @@ struct _ClutterTimelineClass
   void (*paused)         (ClutterTimeline *timeline);
   
   void (*new_frame)      (ClutterTimeline *timeline,
-                         gint             frame_num);
+                         gint             msecs);
 
   void (*marker_reached) (ClutterTimeline *timeline,
                           const gchar     *marker_name,
index 43baebc..540b321 100644 (file)
@@ -34,7 +34,6 @@
 #include "config.h"
 #endif
 
-#undef CLUTTER_DISABLE_DEPRECATED
 #include "clutter-timeout-pool.h"
 
 #include "clutter-debug.h"
index 9204e44..23f2212 100644 (file)
@@ -39,7 +39,7 @@
 
 G_BEGIN_DECLS
 
-#ifndef CLUTTER_DISABLE_DEPRECATED
+#if !defined(CLUTTER_DISABLE_DEPRECATED) || defined(CLUTTER_COMPILATION)
 
 /**
  * ClutterTimeoutPool: (skip)
index b5951c5..8ad7261 100644 (file)
@@ -489,6 +489,57 @@ void                clutter_paint_volume_union               (ClutterPaintVolume
 gboolean            clutter_paint_volume_set_from_allocation (ClutterPaintVolume       *pv,
                                                               ClutterActor             *actor);
 
+/**
+ * ClutterModifierType:
+ * @CLUTTER_SHIFT_MASK: Mask applied by the Shift key
+ * @CLUTTER_LOCK_MASK: Mask applied by the Caps Lock key
+ * @CLUTTER_CONTROL_MASK: Mask applied by the Control key
+ * @CLUTTER_MOD1_MASK: Mask applied by the first Mod key
+ * @CLUTTER_MOD2_MASK: Mask applied by the second Mod key
+ * @CLUTTER_MOD3_MASK: Mask applied by the third Mod key
+ * @CLUTTER_MOD4_MASK: Mask applied by the fourth Mod key
+ * @CLUTTER_MOD5_MASK: Mask applied by the fifth Mod key
+ * @CLUTTER_BUTTON1_MASK: Mask applied by the first pointer button
+ * @CLUTTER_BUTTON2_MASK: Mask applied by the second pointer button
+ * @CLUTTER_BUTTON3_MASK: Mask applied by the third pointer button
+ * @CLUTTER_BUTTON4_MASK: Mask applied by the fourth pointer button
+ * @CLUTTER_BUTTON5_MASK: Mask applied by the fifth pointer button
+ * @CLUTTER_SUPER_MASK: Mask applied by the Super key
+ * @CLUTTER_HYPER_MASK: Mask applied by the Hyper key
+ * @CLUTTER_META_MASK: Mask applied by the Meta key
+ * @CLUTTER_RELEASE_MASK: Mask applied during release
+ * @CLUTTER_MODIFIER_MASK: A mask covering all modifier types
+ *
+ * Masks applied to a #ClutterEvent by modifiers.
+ *
+ * Since: 0.4
+ */
+typedef enum {
+  CLUTTER_SHIFT_MASK    = 1 << 0,
+  CLUTTER_LOCK_MASK     = 1 << 1,
+  CLUTTER_CONTROL_MASK  = 1 << 2,
+  CLUTTER_MOD1_MASK     = 1 << 3,
+  CLUTTER_MOD2_MASK     = 1 << 4,
+  CLUTTER_MOD3_MASK     = 1 << 5,
+  CLUTTER_MOD4_MASK     = 1 << 6,
+  CLUTTER_MOD5_MASK     = 1 << 7,
+  CLUTTER_BUTTON1_MASK  = 1 << 8,
+  CLUTTER_BUTTON2_MASK  = 1 << 9,
+  CLUTTER_BUTTON3_MASK  = 1 << 10,
+  CLUTTER_BUTTON4_MASK  = 1 << 11,
+  CLUTTER_BUTTON5_MASK  = 1 << 12,
+
+  /* bits 15 to 25 are currently unused; bit 29 is used internally */
+
+  CLUTTER_SUPER_MASK    = 1 << 26,
+  CLUTTER_HYPER_MASK    = 1 << 27,
+  CLUTTER_META_MASK     = 1 << 28,
+
+  CLUTTER_RELEASE_MASK  = 1 << 30,
+
+  CLUTTER_MODIFIER_MASK = 0x5c001fff
+} ClutterModifierType;
+
 G_END_DECLS
 
 #endif /* __CLUTTER_TYPES_H__ */
index 8448a44..3729cf8 100644 (file)
@@ -30,6 +30,8 @@
 
 #include "clutter-deprecated.h"
 
+#include "clutter-config.h"
+
 #include "clutter-action.h"
 #include "clutter-actor.h"
 #include "clutter-actor-meta.h"
index 5ba9a18..87ed889 100644 (file)
@@ -75,7 +75,7 @@ cogl_public_h = \
        $(srcdir)/cogl-index-array.h            \
        $(srcdir)/cogl-vertex-array.h           \
        $(srcdir)/cogl-indices.h                \
-       $(srcdir)/cogl-vertex-attribute.h       \
+       $(srcdir)/cogl-attribute.h              \
        $(srcdir)/cogl-primitive.h              \
        $(srcdir)/cogl.h                        \
        $(NULL)
@@ -201,8 +201,8 @@ cogl_sources_c = \
        $(srcdir)/cogl-vertex-array.c                   \
        $(srcdir)/cogl-indices-private.h                \
        $(srcdir)/cogl-indices.c                        \
-       $(srcdir)/cogl-vertex-attribute-private.h       \
-       $(srcdir)/cogl-vertex-attribute.c               \
+       $(srcdir)/cogl-attribute-private.h              \
+       $(srcdir)/cogl-attribute.c                      \
        $(srcdir)/cogl-primitive-private.h              \
        $(srcdir)/cogl-primitive.c                      \
        $(srcdir)/cogl-matrix.c                         \
@@ -269,6 +269,8 @@ cogl_sources_c = \
        $(srcdir)/cogl-callback-list.h                  \
        $(srcdir)/cogl-callback-list.c                  \
        $(srcdir)/cogl-gtype-private.h                  \
+       $(srcdir)/cogl-point-in-poly-private.h       \
+       $(srcdir)/cogl-point-in-poly.c          \
        $(NULL)
 
 if SUPPORT_XLIB
index e9b4e6b..6f81f97 100644 (file)
@@ -98,14 +98,14 @@ _cogl_atlas_texture_reorganize_cb (void *data)
 {
   CoglAtlas *atlas = data;
 
-  /* We don't know if any pipelines may currently be referenced in
-   * the journal that depend on the current underlying GL texture
-   * storage so we flush the journal before migrating.
+  /* We don't know if any journal entries currently depend on OpenGL
+   * texture coordinates that would be invalidated by reorganizing
+   * this atlas so we flush all journals before migrating.
    *
    * We are assuming that texture atlas migration never happens
    * during a flush so we don't have to consider recursion here.
    */
-  _cogl_journal_flush ();
+  cogl_flush ();
 
   if (atlas->map)
     _cogl_rectangle_map_foreach (atlas->map,
@@ -294,14 +294,15 @@ _cogl_atlas_texture_migrate_out_of_atlas (CoglAtlasTexture *atlas_tex)
     {
       COGL_NOTE (ATLAS, "Migrating texture out of the atlas");
 
-      /* We don't know if any pipelines may currently be referenced in
-       * the journal that depend on the current underlying GL texture
-       * storage so we flush the journal before migrating.
+      /* We don't know if any journal entries currently depend on
+       * OpenGL texture coordinates that would be invalidated by
+       * migrating textures in this atlas so we flush all journals
+       * before migrating.
        *
        * We are assuming that texture atlas migration never happens
        * during a flush so we don't have to consider recursion here.
        */
-      _cogl_journal_flush ();
+      cogl_flush ();
 
       /* Notify cogl-pipeline.c that the texture's underlying GL texture
        * storage is changing so it knows it may need to bind a new texture
@@ -534,7 +535,7 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap      *bmp,
 
   /* Don't put textures in the atlas if the user has explicitly
      requested to disable it */
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_ATLAS))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_ATLAS)))
     return COGL_INVALID_HANDLE;
 
   /* We can't put the texture in the atlas if there are any special
@@ -552,11 +553,9 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap      *bmp,
   if (bmp_width < 1 || bmp_height < 1)
     return COGL_INVALID_HANDLE;
 
-  /* If we can't use FBOs or we can't read back texture data then it
-     will be too slow to migrate textures and we shouldn't use the
-     atlas */
-  if (!cogl_features_available (COGL_FEATURE_TEXTURE_READ_PIXELS) ||
-      !cogl_features_available (COGL_FEATURE_OFFSCREEN))
+  /* If we can't use FBOs then it will be too slow to migrate textures
+     and we shouldn't use the atlas */
+  if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
     return COGL_INVALID_HANDLE;
 
   COGL_NOTE (ATLAS, "Adding texture of size %ix%i", bmp_width, bmp_height);
@@ -577,6 +576,9 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap      *bmp,
      to set as the data for the rectangle in the atlas */
   atlas_tex = g_new (CoglAtlasTexture, 1);
 
+  _cogl_texture_init (COGL_TEXTURE (atlas_tex),
+                      &cogl_atlas_texture_vtable);
+
   atlas_tex->sub_texture = COGL_INVALID_HANDLE;
 
   /* Look for an existing atlas that can hold the texture */
@@ -622,8 +624,6 @@ _cogl_atlas_texture_new_from_bitmap (CoglBitmap      *bmp,
       g_free (atlas_tex);
       return COGL_INVALID_HANDLE;
     }
-
-  atlas_tex->_parent.vtable = &cogl_atlas_texture_vtable;
   atlas_tex->format = internal_format;
   atlas_tex->atlas = atlas;
 
diff --git a/clutter/cogl/cogl/cogl-attribute-private.h b/clutter/cogl/cogl/cogl-attribute-private.h
new file mode 100644 (file)
index 0000000..d7acef6
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2010 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert@linux.intel.com>
+ */
+
+#ifndef __COGL_ATTRIBUTE_PRIVATE_H
+#define __COGL_ATTRIBUTE_PRIVATE_H
+
+#include "cogl-object-private.h"
+#include "cogl-attribute.h"
+
+typedef enum
+{
+  COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY,
+  COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY,
+  COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY,
+  COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY,
+  COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY
+} CoglAttributeNameID;
+
+struct _CoglAttribute
+{
+  CoglObject _parent;
+
+  CoglVertexArray *array;
+  char *name;
+  CoglAttributeNameID name_id;
+  gsize stride;
+  gsize offset;
+  int n_components;
+  CoglAttributeType type;
+  gboolean normalized;
+  unsigned int texture_unit;
+
+  int immutable_ref;
+};
+
+typedef enum
+{
+  COGL_DRAW_SKIP_JOURNAL_FLUSH = 1 << 0,
+  COGL_DRAW_SKIP_PIPELINE_VALIDATION = 1 << 1,
+  COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH = 1 << 2,
+  /* When flushing from the journal the logged pipeline will already
+     contain the legacy state overrides so we don't want to apply them
+     again when we flush the pipeline for drawing */
+  COGL_DRAW_SKIP_LEGACY_STATE = 1 << 3,
+  /* By default the vertex attribute drawing code will assume that if
+     there is a color attribute array enabled then we can't determine
+     if the colors will be opaque so we need to enabling
+     blending. However when drawing from the journal we know what the
+     contents of the color array is so we can override this by passing
+     this flag. */
+  COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE = 1 << 4
+} CoglDrawFlags;
+
+CoglAttribute *
+_cogl_attribute_immutable_ref (CoglAttribute *attribute);
+
+void
+_cogl_attribute_immutable_unref (CoglAttribute *attribute);
+
+void
+_cogl_draw_attributes_array (CoglVerticesMode mode,
+                             int first_vertex,
+                             int n_vertices,
+                             CoglAttribute **attributes,
+                             CoglDrawFlags flags);
+
+void
+_cogl_draw_indexed_attributes_array (CoglVerticesMode mode,
+                                     int first_vertex,
+                                     int n_vertices,
+                                     CoglIndices *indices,
+                                     CoglAttribute **attributes,
+                                     CoglDrawFlags flags);
+
+void
+_cogl_attribute_disable_cached_arrays (void);
+
+#endif /* __COGL_ATTRIBUTE_PRIVATE_H */
+
similarity index 74%
rename from clutter/cogl/cogl/cogl-vertex-attribute.c
rename to clutter/cogl/cogl/cogl-attribute.c
index fe98e30..5cb8986 100644 (file)
@@ -32,8 +32,8 @@
 #include "cogl-context.h"
 #include "cogl-object-private.h"
 #include "cogl-journal-private.h"
-#include "cogl-vertex-attribute.h"
-#include "cogl-vertex-attribute-private.h"
+#include "cogl-attribute.h"
+#include "cogl-attribute-private.h"
 #include "cogl-pipeline.h"
 #include "cogl-pipeline-private.h"
 #include "cogl-pipeline-opengl-private.h"
 
 #endif
 
-static void _cogl_vertex_attribute_free (CoglVertexAttribute *attribute);
+static void _cogl_attribute_free (CoglAttribute *attribute);
 
-COGL_OBJECT_DEFINE (VertexAttribute, vertex_attribute);
+COGL_OBJECT_DEFINE (Attribute, attribute);
 
 #if 0
 gboolean
 validate_gl_attribute (const char *name,
                        int n_components,
-                       CoglVertexAttributeNameID *name_id,
+                       CoglAttributeNameID *name_id,
                        gboolean *normalized,
                        unsigned int *texture_unit)
 {
@@ -116,7 +116,7 @@ validate_gl_attribute (const char *name,
                       "attributes where n_components == 2, 3 or 4");
           return FALSE;
         }
-      *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY;
+      *name_id = COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY;
     }
   else if (strcmp (name, "Color") == 0)
     {
@@ -127,7 +127,7 @@ validate_gl_attribute (const char *name,
                       "n_components == 3 or 4");
           return FALSE;
         }
-      *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY;
+      *name_id = COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY;
       *normalized = TRUE;
     }
   else if (strncmp (name, "MultiTexCoord", strlen ("MultiTexCoord")) == 0)
@@ -138,7 +138,7 @@ validate_gl_attribute (const char *name,
                     "texture unit number, E.g. gl_MultiTexCoord0\n");
          unit = 0;
        }
-      *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY;
+      *name_id = COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY;
     }
   else if (strncmp (name, "Normal") == 0)
     {
@@ -149,7 +149,7 @@ validate_gl_attribute (const char *name,
                       "n_components == 3");
           return FALSE;
         }
-      *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY;
+      *name_id = COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY;
       *normalized = TRUE;
     }
   else
@@ -165,7 +165,7 @@ validate_gl_attribute (const char *name,
 gboolean
 validate_cogl_attribute (const char *name,
                          int n_components,
-                         CoglVertexAttributeNameID *name_id,
+                         CoglAttributeNameID *name_id,
                          gboolean *normalized,
                          unsigned int *texture_unit)
 {
@@ -183,7 +183,7 @@ validate_cogl_attribute (const char *name,
                       "attributes where n_components == 2, 3 or 4");
           return FALSE;
         }
-      *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY;
+      *name_id = COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY;
     }
   else if (strcmp (name, "color_in") == 0)
     {
@@ -194,10 +194,10 @@ validate_cogl_attribute (const char *name,
                       "n_components == 3 or 4");
           return FALSE;
         }
-      *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY;
+      *name_id = COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY;
     }
   else if (strcmp (name, "tex_coord_in") == 0)
-    *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY;
+    *name_id = COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY;
   else if (strncmp (name, "tex_coord", strlen ("tex_coord")) == 0)
     {
       if (sscanf (name, "tex_coord%u_in", texture_unit) != 1)
@@ -207,9 +207,9 @@ validate_cogl_attribute (const char *name,
                      "like \"cogl_tex_coord2_in\"\n");
           return FALSE;
        }
-      *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY;
+      *name_id = COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY;
     }
-  else if (strcmp (name, "normal") == 0)
+  else if (strcmp (name, "normal_in") == 0)
     {
       if (G_UNLIKELY (n_components != 3))
         {
@@ -218,7 +218,7 @@ validate_cogl_attribute (const char *name,
                       "where n_components == 3");
           return FALSE;
         }
-      *name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY;
+      *name_id = COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY;
       *normalized = TRUE;
     }
   else
@@ -230,15 +230,15 @@ validate_cogl_attribute (const char *name,
   return TRUE;
 }
 
-CoglVertexAttribute *
-cogl_vertex_attribute_new (CoglVertexArray *array,
-                           const char *name,
-                           gsize stride,
-                           gsize offset,
-                           int n_components,
-                           CoglVertexAttributeType type)
+CoglAttribute *
+cogl_attribute_new (CoglVertexArray *array,
+                    const char *name,
+                    gsize stride,
+                    gsize offset,
+                    int n_components,
+                    CoglAttributeType type)
 {
-  CoglVertexAttribute *attribute = g_slice_new (CoglVertexAttribute);
+  CoglAttribute *attribute = g_slice_new (CoglAttribute);
   gboolean status;
 
   attribute->array = cogl_object_ref (array);
@@ -265,7 +265,7 @@ cogl_vertex_attribute_new (CoglVertexArray *array,
 #endif
   else
     {
-      attribute->name_id = COGL_VERTEX_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY;
+      attribute->name_id = COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY;
       attribute->normalized = FALSE;
       attribute->texture_unit = 0;
       status = TRUE;
@@ -273,17 +273,17 @@ cogl_vertex_attribute_new (CoglVertexArray *array,
 
   if (!status)
     {
-      _cogl_vertex_attribute_free (attribute);
+      _cogl_attribute_free (attribute);
       return NULL;
     }
 
-  return _cogl_vertex_attribute_object_new (attribute);
+  return _cogl_attribute_object_new (attribute);
 }
 
 gboolean
-cogl_vertex_attribute_get_normalized (CoglVertexAttribute *attribute)
+cogl_attribute_get_normalized (CoglAttribute *attribute)
 {
-  g_return_val_if_fail (cogl_is_vertex_attribute (attribute), FALSE);
+  g_return_val_if_fail (cogl_is_attribute (attribute), FALSE);
 
   return attribute->normalized;
 }
@@ -301,10 +301,10 @@ warn_about_midscene_changes (void)
 }
 
 void
-cogl_vertex_attribute_set_normalized (CoglVertexAttribute *attribute,
+cogl_attribute_set_normalized (CoglAttribute *attribute,
                                       gboolean normalized)
 {
-  g_return_if_fail (cogl_is_vertex_attribute (attribute));
+  g_return_if_fail (cogl_is_attribute (attribute));
 
   if (G_UNLIKELY (attribute->immutable_ref))
     warn_about_midscene_changes ();
@@ -313,18 +313,18 @@ cogl_vertex_attribute_set_normalized (CoglVertexAttribute *attribute,
 }
 
 CoglVertexArray *
-cogl_vertex_attribute_get_array (CoglVertexAttribute *attribute)
+cogl_attribute_get_array (CoglAttribute *attribute)
 {
-  g_return_val_if_fail (cogl_is_vertex_attribute (attribute), NULL);
+  g_return_val_if_fail (cogl_is_attribute (attribute), NULL);
 
   return attribute->array;
 }
 
 void
-cogl_vertex_attribute_set_array (CoglVertexAttribute *attribute,
+cogl_attribute_set_array (CoglAttribute *attribute,
                                  CoglVertexArray *array)
 {
-  g_return_if_fail (cogl_is_vertex_attribute (attribute));
+  g_return_if_fail (cogl_is_attribute (attribute));
 
   if (G_UNLIKELY (attribute->immutable_ref))
     warn_about_midscene_changes ();
@@ -335,33 +335,33 @@ cogl_vertex_attribute_set_array (CoglVertexAttribute *attribute,
   attribute->array = array;
 }
 
-CoglVertexAttribute *
-_cogl_vertex_attribute_immutable_ref (CoglVertexAttribute *vertex_attribute)
+CoglAttribute *
+_cogl_attribute_immutable_ref (CoglAttribute *attribute)
 {
-  g_return_val_if_fail (cogl_is_vertex_attribute (vertex_attribute), NULL);
+  g_return_val_if_fail (cogl_is_attribute (attribute), NULL);
 
-  vertex_attribute->immutable_ref++;
-  _cogl_buffer_immutable_ref (COGL_BUFFER (vertex_attribute->array));
-  return vertex_attribute;
+  attribute->immutable_ref++;
+  _cogl_buffer_immutable_ref (COGL_BUFFER (attribute->array));
+  return attribute;
 }
 
 void
-_cogl_vertex_attribute_immutable_unref (CoglVertexAttribute *vertex_attribute)
+_cogl_attribute_immutable_unref (CoglAttribute *attribute)
 {
-  g_return_if_fail (cogl_is_vertex_attribute (vertex_attribute));
-  g_return_if_fail (vertex_attribute->immutable_ref > 0);
+  g_return_if_fail (cogl_is_attribute (attribute));
+  g_return_if_fail (attribute->immutable_ref > 0);
 
-  vertex_attribute->immutable_ref--;
-  _cogl_buffer_immutable_unref (COGL_BUFFER (vertex_attribute->array));
+  attribute->immutable_ref--;
+  _cogl_buffer_immutable_unref (COGL_BUFFER (attribute->array));
 }
 
 static void
-_cogl_vertex_attribute_free (CoglVertexAttribute *attribute)
+_cogl_attribute_free (CoglAttribute *attribute)
 {
   g_free (attribute->name);
   cogl_object_unref (attribute->array);
 
-  g_slice_free (CoglVertexAttribute, attribute);
+  g_slice_free (CoglAttribute, attribute);
 }
 
 typedef struct
@@ -386,6 +386,8 @@ validate_layer_cb (CoglPipeline *pipeline,
   if (texture == COGL_INVALID_HANDLE)
     goto validated;
 
+  _cogl_texture_flush_journal_rendering (texture);
+
   /* Give the texture a chance to know that we're rendering
      non-quad shaped primitives. If the texture is in an atlas it
      will be migrated */
@@ -474,9 +476,11 @@ set_enabled_arrays (CoglBitmask *value_cache,
 }
 
 static CoglHandle
-enable_gl_state (CoglVertexAttribute **attributes,
+enable_gl_state (CoglDrawFlags flags,
+                 CoglAttribute **attributes,
                  ValidateLayerState *state)
 {
+  CoglFramebuffer *framebuffer = _cogl_get_framebuffer ();
   int i;
 #ifdef MAY_HAVE_PROGRAMABLE_GL
   GLuint generic_index = 0;
@@ -489,6 +493,12 @@ enable_gl_state (CoglVertexAttribute **attributes,
 
   _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
 
+  /* In cogl_read_pixels we have a fast-path when reading a single
+   * pixel and the scene is just comprised of simple rectangles still
+   * in the journal. For this optimization to work we need to track
+   * when the framebuffer really does get drawn to. */
+  _cogl_framebuffer_dirty (framebuffer);
+
   source = cogl_get_source ();
 
   /* Iterate the attributes to work out whether blending needs to be
@@ -497,8 +507,9 @@ enable_gl_state (CoglVertexAttribute **attributes,
   for (i = 0; attributes[i]; i++)
     switch (attributes[i]->name_id)
       {
-      case COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
-        if (!_cogl_pipeline_get_real_blend_enabled (source))
+      case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
+        if ((flags & COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE) == 0 &&
+            !_cogl_pipeline_get_real_blend_enabled (source))
           {
             CoglPipelineBlendEnable blend_enable =
               COGL_PIPELINE_BLEND_ENABLE_ENABLED;
@@ -509,7 +520,7 @@ enable_gl_state (CoglVertexAttribute **attributes,
         skip_gl_color = TRUE;
         break;
 
-      case COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
+      case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
         n_tex_coord_attribs++;
         break;
 
@@ -561,7 +572,8 @@ enable_gl_state (CoglVertexAttribute **attributes,
        */
     }
 
-  if (G_UNLIKELY (ctx->legacy_state_set))
+  if (G_UNLIKELY (ctx->legacy_state_set) &&
+      (flags & COGL_DRAW_SKIP_LEGACY_STATE) == 0)
     {
       /* If we haven't already created a derived pipeline... */
       if (!copy)
@@ -585,7 +597,7 @@ enable_gl_state (CoglVertexAttribute **attributes,
 
   for (i = 0; attributes[i]; i++)
     {
-      CoglVertexAttribute *attribute = attributes[i];
+      CoglAttribute *attribute = attributes[i];
       CoglVertexArray *vertex_array;
       CoglBuffer *buffer;
       void *base;
@@ -593,13 +605,13 @@ enable_gl_state (CoglVertexAttribute **attributes,
       int attrib_location;
 #endif
 
-      vertex_array = cogl_vertex_attribute_get_array (attribute);
+      vertex_array = cogl_attribute_get_array (attribute);
       buffer = COGL_BUFFER (vertex_array);
       base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_VERTEX_ARRAY);
 
       switch (attribute->name_id)
         {
-        case COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
+        case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
 #ifdef HAVE_COGL_GLES2
 
           attrib_location =
@@ -628,7 +640,7 @@ enable_gl_state (CoglVertexAttribute **attributes,
 #endif
 
           break;
-        case COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
+        case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
 #ifdef HAVE_COGL_GLES2
 
           attrib_location =
@@ -655,7 +667,7 @@ enable_gl_state (CoglVertexAttribute **attributes,
 #endif
 
           break;
-        case COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
+        case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
 #ifdef HAVE_COGL_GLES2
 
           attrib_location = _cogl_pipeline_progend_glsl_get_tex_coord_attribute
@@ -683,7 +695,7 @@ enable_gl_state (CoglVertexAttribute **attributes,
 
 #endif
           break;
-        case COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
+        case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
 #ifdef HAVE_COGL_GLES2
 
           attrib_location =
@@ -710,7 +722,7 @@ enable_gl_state (CoglVertexAttribute **attributes,
 
 #endif
           break;
-        case COGL_VERTEX_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
+        case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
           {
 #ifdef MAY_HAVE_PROGRAMABLE_GL
             /* FIXME: go through cogl cache to enable generic array. */
@@ -743,7 +755,7 @@ enable_gl_state (CoglVertexAttribute **attributes,
 }
 
 void
-_cogl_vertex_attribute_disable_cached_arrays (void)
+_cogl_attribute_disable_cached_arrays (void)
 {
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
@@ -754,7 +766,7 @@ _cogl_vertex_attribute_disable_cached_arrays (void)
 /* FIXME: we shouldn't be disabling state after drawing we should
  * just disable the things not needed after enabling state. */
 static void
-disable_gl_state (CoglVertexAttribute **attributes,
+disable_gl_state (CoglAttribute **attributes,
                   CoglPipeline *source)
 {
 #ifdef MAY_HAVE_PROGRAMABLE_GL
@@ -769,30 +781,30 @@ disable_gl_state (CoglVertexAttribute **attributes,
 
   for (i = 0; attributes[i]; i++)
     {
-      CoglVertexAttribute *attribute = attributes[i];
+      CoglAttribute *attribute = attributes[i];
 
       switch (attribute->name_id)
         {
-        case COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
+        case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
           /* GE (glDisableClientState (GL_COLOR_ARRAY)); */
           break;
-        case COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
+        case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
           /* FIXME: go through cogl cache to enable normal array */
 #ifndef HAVE_COGL_GLES2
           GE (glDisableClientState (GL_NORMAL_ARRAY));
 #endif
           break;
-        case COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
+        case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
           /* The enabled state of the texture coord arrays is
              cached in ctx->enabled_texcoord_arrays so we don't
              need to do anything here. The array will be disabled
              by the next drawing primitive if it is not
              required */
           break;
-        case COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
+        case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
           /* GE (glDisableClientState (GL_VERTEX_ARRAY)); */
           break;
-        case COGL_VERTEX_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
+        case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
 #ifdef MAY_HAVE_PROGRAMABLE_GL
           /* FIXME: go through cogl cache to enable generic array */
           GE (glDisableVertexAttribArray (generic_index++));
@@ -830,10 +842,10 @@ static void
 add_line (void *vertices,
           void *indices,
           CoglIndicesType indices_type,
-          CoglVertexAttribute *attribute,
+          CoglAttribute *attribute,
           int start,
           int end,
-          CoglP3Vertex *lines,
+          CoglVertexP3 *lines,
           int *n_line_vertices)
 {
   int start_index = get_index (indices, indices_type, start);
@@ -856,21 +868,21 @@ add_line (void *vertices,
   *n_line_vertices += 2;
 }
 
-static CoglP3Vertex *
-get_wire_lines (CoglVertexAttribute *attribute,
+static CoglVertexP3 *
+get_wire_lines (CoglAttribute *attribute,
                 CoglVerticesMode mode,
                 int n_vertices_in,
                 int *n_vertices_out,
                 CoglIndices *_indices)
 {
-  CoglVertexArray *vertex_array = cogl_vertex_attribute_get_array (attribute);
+  CoglVertexArray *vertex_array = cogl_attribute_get_array (attribute);
   void *vertices;
   CoglIndexArray *index_array;
   void *indices;
   CoglIndicesType indices_type;
   int i;
   int n_lines;
-  CoglP3Vertex *out;
+  CoglVertexP3 *out;
 
   vertices = cogl_buffer_map (COGL_BUFFER (vertex_array),
                               COGL_BUFFER_ACCESS_READ, 0);
@@ -890,7 +902,7 @@ get_wire_lines (CoglVertexAttribute *attribute,
       (n_vertices_in % 3) == 0)
     {
       n_lines = n_vertices_in;
-      out = g_new (CoglP3Vertex, n_lines * 2);
+      out = g_new (CoglVertexP3, n_lines * 2);
       for (i = 0; i < n_vertices_in; i += 3)
         {
           add_line (vertices, indices, indices_type, attribute,
@@ -905,7 +917,7 @@ get_wire_lines (CoglVertexAttribute *attribute,
            n_vertices_in >= 3)
     {
       n_lines = 2 * n_vertices_in - 3;
-      out = g_new (CoglP3Vertex, n_lines * 2);
+      out = g_new (CoglVertexP3, n_lines * 2);
 
       add_line (vertices, indices, indices_type, attribute,
                 0, 1, out, n_vertices_out);
@@ -926,7 +938,7 @@ get_wire_lines (CoglVertexAttribute *attribute,
            n_vertices_in >= 3)
     {
       n_lines = 2 * n_vertices_in - 3;
-      out = g_new (CoglP3Vertex, n_lines * 2);
+      out = g_new (CoglVertexP3, n_lines * 2);
 
       add_line (vertices, indices, indices_type, attribute,
                 0, 1, out, n_vertices_out);
@@ -949,7 +961,7 @@ get_wire_lines (CoglVertexAttribute *attribute,
   else if (mode == GL_QUADS && (n_vertices_in % 4) == 0)
     {
       n_lines = n_vertices_in;
-      out = g_new (CoglP3Vertex, n_lines * 2);
+      out = g_new (CoglVertexP3, n_lines * 2);
 
       for (i = 0; i < n_vertices_in; i += 4)
         {
@@ -976,15 +988,15 @@ static void
 draw_wireframe (CoglVerticesMode mode,
                 int first_vertex,
                 int n_vertices,
-                CoglVertexAttribute **attributes,
+                CoglAttribute **attributes,
                 CoglIndices *indices)
 {
-  CoglVertexAttribute *position = NULL;
+  CoglAttribute *position = NULL;
   int i;
   int n_line_vertices;
   static CoglPipeline *wire_pipeline;
-  CoglVertexAttribute *wire_attribute[2];
-  CoglP3Vertex *lines;
+  CoglAttribute *wire_attribute[2];
+  CoglVertexP3 *lines;
   CoglVertexArray *array;
 
   for (i = 0; attributes[i]; i++)
@@ -1003,14 +1015,14 @@ draw_wireframe (CoglVerticesMode mode,
                           n_vertices,
                           &n_line_vertices,
                           indices);
-  array = cogl_vertex_array_new (sizeof (CoglP3Vertex) * n_line_vertices,
+  array = cogl_vertex_array_new (sizeof (CoglVertexP3) * n_line_vertices,
                                  lines);
   wire_attribute[0] =
-    cogl_vertex_attribute_new (array, "cogl_position_in",
-                               sizeof (CoglP3Vertex),
-                               0,
-                               3,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
+    cogl_attribute_new (array, "cogl_position_in",
+                        sizeof (CoglVertexP3),
+                        0,
+                        3,
+                        COGL_ATTRIBUTE_TYPE_FLOAT);
   wire_attribute[1] = NULL;
   cogl_object_unref (array);
 
@@ -1024,12 +1036,17 @@ draw_wireframe (CoglVerticesMode mode,
   cogl_push_source (wire_pipeline);
 
   /* temporarily disable the wireframe to avoid recursion! */
-  cogl_debug_flags &= ~COGL_DEBUG_WIREFRAME;
-  _cogl_draw_vertex_attributes_array (COGL_VERTICES_MODE_LINES,
-                                      0,
-                                      n_line_vertices,
-                                      wire_attribute);
-  cogl_debug_flags |= COGL_DEBUG_WIREFRAME;
+  COGL_DEBUG_CLEAR_FLAG (COGL_DEBUG_WIREFRAME);
+  _cogl_draw_attributes_array (COGL_VERTICES_MODE_LINES,
+                               0,
+                               n_line_vertices,
+                               wire_attribute,
+                               COGL_DRAW_SKIP_JOURNAL_FLUSH |
+                               COGL_DRAW_SKIP_PIPELINE_VALIDATION |
+                               COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
+                               COGL_DRAW_SKIP_LEGACY_STATE);
+
+  COGL_DEBUG_SET_FLAG (COGL_DEBUG_WIREFRAME);
 
   cogl_pop_source ();
 
@@ -1038,104 +1055,101 @@ draw_wireframe (CoglVerticesMode mode,
 #endif
 
 static void
-_cogl_draw_vertex_attributes_array_real (CoglVerticesMode mode,
-                                         int first_vertex,
-                                         int n_vertices,
-                                         CoglVertexAttribute **attributes,
-                                         ValidateLayerState *state)
+flush_state (CoglDrawFlags flags,
+             ValidateLayerState *state)
 {
-  CoglPipeline *source = enable_gl_state (attributes, state);
-
-  GE (glDrawArrays ((GLenum)mode, first_vertex, n_vertices));
-
-  /* FIXME: we shouldn't be disabling state after drawing we should
-   * just disable the things not needed after enabling state. */
-  disable_gl_state (attributes, source);
+  if (!(flags & COGL_DRAW_SKIP_JOURNAL_FLUSH))
+    {
+      CoglFramebuffer *framebuffer = _cogl_get_framebuffer ();
+      _cogl_journal_flush (framebuffer->journal, framebuffer);
+    }
 
-#ifdef COGL_ENABLE_DEBUG
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_WIREFRAME))
-    draw_wireframe (mode, first_vertex, n_vertices, attributes, NULL);
-#endif
-}
+  state->unit = 0;
+  state->options.flags = 0;
+  state->fallback_layers = 0;
 
-/* This can be used by the CoglJournal to draw attributes skipping the
- * implicit journal flush, the framebuffer flush and pipeline
- * validation. */
-void
-_cogl_draw_vertex_attributes_array (CoglVerticesMode mode,
-                                    int first_vertex,
-                                    int n_vertices,
-                                    CoglVertexAttribute **attributes)
-{
-  ValidateLayerState state;
+  if (!(flags & COGL_DRAW_SKIP_PIPELINE_VALIDATION))
+    cogl_pipeline_foreach_layer (cogl_get_source (),
+                                 validate_layer_cb,
+                                 state);
 
-  state.unit = 0;
-  state.options.flags = 0;
-  state.fallback_layers = 0;
-
-  _cogl_draw_vertex_attributes_array_real (mode, first_vertex, n_vertices,
-                                           attributes, &state);
+  /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
+   * as the pipeline state) when flushing the clip stack, so should
+   * always be done first when preparing to draw. We need to do this
+   * before setting up the array pointers because setting up the clip
+   * stack can cause some drawing which would change the array
+   * pointers. */
+  if (!(flags & COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH))
+    _cogl_framebuffer_flush_state (_cogl_get_framebuffer (), 0);
 }
 
+/* This can be called directly by the CoglJournal to draw attributes
+ * skipping the implicit journal flush, the framebuffer flush and
+ * pipeline validation. */
 void
-cogl_draw_vertex_attributes_array (CoglVerticesMode mode,
-                                   int first_vertex,
-                                   int n_vertices,
-                                   CoglVertexAttribute **attributes)
+_cogl_draw_attributes_array (CoglVerticesMode mode,
+                             int first_vertex,
+                             int n_vertices,
+                             CoglAttribute **attributes,
+                             CoglDrawFlags flags)
 {
   ValidateLayerState state;
+  CoglPipeline *source;
 
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+  flush_state (flags, &state);
 
-  _cogl_journal_flush ();
+  source = enable_gl_state (flags, attributes, &state);
 
-  state.unit = 0;
-  state.options.flags = 0;
-  state.fallback_layers = 0;
+  GE (glDrawArrays ((GLenum)mode, first_vertex, n_vertices));
 
-  cogl_pipeline_foreach_layer (cogl_get_source (),
-                               validate_layer_cb,
-                               &state);
+  /* FIXME: we shouldn't be disabling state after drawing we should
+   * just disable the things not needed after enabling state. */
+  disable_gl_state (attributes, source);
 
-  /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
-   * as the pipeline state) when flushing the clip stack, so should
-   * always be done first when preparing to draw. We need to do this
-   * before setting up the array pointers because setting up the clip
-   * stack can cause some drawing which would change the array
-   * pointers. */
-  _cogl_framebuffer_flush_state (_cogl_get_framebuffer (), 0);
+#ifdef COGL_ENABLE_DEBUG
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME)))
+    draw_wireframe (mode, first_vertex, n_vertices, attributes, NULL);
+#endif
+}
 
-  _cogl_draw_vertex_attributes_array_real (mode, first_vertex, n_vertices,
-                                           attributes, &state);
+void
+cogl_draw_attributes_array (CoglVerticesMode mode,
+                            int first_vertex,
+                            int n_vertices,
+                            CoglAttribute **attributes)
+{
+  _cogl_draw_attributes_array (mode, first_vertex,
+                               n_vertices, attributes,
+                               0 /* no flags */);
 }
 
 void
-cogl_draw_vertex_attributes (CoglVerticesMode mode,
-                             int first_vertex,
-                             int n_vertices,
-                             ...)
+cogl_draw_attributes (CoglVerticesMode mode,
+                      int first_vertex,
+                      int n_vertices,
+                      ...)
 {
   va_list ap;
   int n_attributes;
-  CoglVertexAttribute *attribute;
-  CoglVertexAttribute **attributes;
+  CoglAttribute *attribute;
+  CoglAttribute **attributes;
   int i;
 
   va_start (ap, n_vertices);
-  for (n_attributes = 0; va_arg (ap, CoglVertexAttribute *); n_attributes++)
+  for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++)
     ;
   va_end (ap);
 
-  attributes = g_alloca (sizeof (CoglVertexAttribute *) * (n_attributes + 1));
+  attributes = g_alloca (sizeof (CoglAttribute *) * (n_attributes + 1));
   attributes[n_attributes] = NULL;
 
   va_start (ap, n_vertices);
-  for (i = 0; (attribute = va_arg (ap, CoglVertexAttribute *)); i++)
+  for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++)
     attributes[i] = attribute;
   va_end (ap);
 
-  cogl_draw_vertex_attributes_array (mode, first_vertex, n_vertices,
-                                     attributes);
+  cogl_draw_attributes_array (mode, first_vertex, n_vertices,
+                              attributes);
 }
 
 static size_t
@@ -1153,15 +1167,16 @@ sizeof_index_type (CoglIndicesType type)
   g_return_val_if_reached (0);
 }
 
-static void
-_cogl_draw_indexed_vertex_attributes_array_real (CoglVerticesMode mode,
-                                                 int first_vertex,
-                                                 int n_vertices,
-                                                 CoglIndices *indices,
-                                                 CoglVertexAttribute **attributes,
-                                                 ValidateLayerState *state)
+void
+_cogl_draw_indexed_attributes_array (CoglVerticesMode mode,
+                                     int first_vertex,
+                                     int n_vertices,
+                                     CoglIndices *indices,
+                                     CoglAttribute **attributes,
+                                     CoglDrawFlags flags)
 {
-  CoglPipeline *source = enable_gl_state (attributes, state);
+  ValidateLayerState state;
+  CoglPipeline *source;
   CoglBuffer *buffer;
   void *base;
   size_t array_offset;
@@ -1170,6 +1185,10 @@ _cogl_draw_indexed_vertex_attributes_array_real (CoglVerticesMode mode,
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  flush_state (flags, &state);
+
+  source = enable_gl_state (flags, attributes, &state);
+
   buffer = COGL_BUFFER (cogl_indices_get_array (indices));
   base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_INDEX_ARRAY);
   array_offset = cogl_indices_get_offset (indices);
@@ -1200,100 +1219,54 @@ _cogl_draw_indexed_vertex_attributes_array_real (CoglVerticesMode mode,
   disable_gl_state (attributes, source);
 
 #ifdef COGL_ENABLE_DEBUG
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_WIREFRAME))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME)))
     draw_wireframe (mode, first_vertex, n_vertices, attributes, indices);
 #endif
 }
 
 void
-_cogl_draw_indexed_vertex_attributes_array (CoglVerticesMode mode,
-                                            int first_vertex,
-                                            int n_vertices,
-                                            CoglIndices *indices,
-                                            CoglVertexAttribute **attributes)
-{
-  ValidateLayerState state;
-
-  state.unit = 0;
-  state.options.flags = 0;
-  state.fallback_layers = 0;
-
-  _cogl_draw_indexed_vertex_attributes_array_real (mode,
-                                                   first_vertex,
-                                                   n_vertices,
-                                                   indices,
-                                                   attributes,
-                                                   &state);
-}
-
-void
-cogl_draw_indexed_vertex_attributes_array (CoglVerticesMode mode,
-                                           int first_vertex,
-                                           int n_vertices,
-                                           CoglIndices *indices,
-                                           CoglVertexAttribute **attributes)
+cogl_draw_indexed_attributes_array (CoglVerticesMode mode,
+                                    int first_vertex,
+                                    int n_vertices,
+                                    CoglIndices *indices,
+                                    CoglAttribute **attributes)
 {
-  ValidateLayerState state;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  _cogl_journal_flush ();
-
-  state.unit = 0;
-  state.options.flags = 0;
-  state.fallback_layers = 0;
-
-  cogl_pipeline_foreach_layer (cogl_get_source (),
-                               validate_layer_cb,
-                               &state);
-
-  /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
-   * as the pipeline state) when flushing the clip stack, so should
-   * always be done first when preparing to draw. We need to do this
-   * before setting up the array pointers because setting up the clip
-   * stack can cause some drawing which would change the array
-   * pointers. */
-  _cogl_framebuffer_flush_state (_cogl_get_framebuffer (), 0);
-
-  _cogl_draw_indexed_vertex_attributes_array_real (mode,
-                                                   first_vertex,
-                                                   n_vertices,
-                                                   indices,
-                                                   attributes,
-                                                   &state);
+  _cogl_draw_indexed_attributes_array (mode, first_vertex,
+                                       n_vertices, indices, attributes,
+                                       0 /* no flags */);
 }
 
 void
-cogl_draw_indexed_vertex_attributes (CoglVerticesMode mode,
-                                     int first_vertex,
-                                     int n_vertices,
-                                     CoglIndices *indices,
-                                     ...)
+cogl_draw_indexed_attributes (CoglVerticesMode mode,
+                              int first_vertex,
+                              int n_vertices,
+                              CoglIndices *indices,
+                              ...)
 {
   va_list ap;
   int n_attributes;
-  CoglVertexAttribute **attributes;
+  CoglAttribute **attributes;
   int i;
-  CoglVertexAttribute *attribute;
+  CoglAttribute *attribute;
 
   va_start (ap, indices);
-  for (n_attributes = 0; va_arg (ap, CoglVertexAttribute *); n_attributes++)
+  for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++)
     ;
   va_end (ap);
 
-  attributes = g_alloca (sizeof (CoglVertexAttribute *) * (n_attributes + 1));
+  attributes = g_alloca (sizeof (CoglAttribute *) * (n_attributes + 1));
   attributes[n_attributes] = NULL;
 
   va_start (ap, indices);
-  for (i = 0; (attribute = va_arg (ap, CoglVertexAttribute *)); i++)
+  for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++)
     attributes[i] = attribute;
   va_end (ap);
 
-  cogl_draw_indexed_vertex_attributes_array (mode,
-                                             first_vertex,
-                                             n_vertices,
-                                             indices,
-                                             attributes);
+  cogl_draw_indexed_attributes_array (mode,
+                                      first_vertex,
+                                      n_vertices,
+                                      indices,
+                                      attributes);
 }
 
 
similarity index 64%
rename from clutter/cogl/cogl/cogl-vertex-attribute.h
rename to clutter/cogl/cogl/cogl-attribute.h
index 6557954..70d4c2b 100644 (file)
@@ -28,8 +28,8 @@
 #error "Only <cogl/cogl.h> can be included directly."
 #endif
 
-#ifndef __COGL_VERTEX_ATTRIBUTE_H__
-#define __COGL_VERTEX_ATTRIBUTE_H__
+#ifndef __COGL_ATTRIBUTE_H__
+#define __COGL_ATTRIBUTE_H__
 
 #include <cogl/cogl-vertex-array.h>
 #include <cogl/cogl-indices.h>
 G_BEGIN_DECLS
 
 /**
- * SECTION:cogl-vertex-attribute
- * @short_description: Fuctions for declaring and drawing vertex
+ * SECTION:cogl-attribute
+ * @short_description: Functions for declaring and drawing vertex
  *    attributes
  *
  * FIXME
  */
 
-typedef struct _CoglVertexAttribute CoglVertexAttribute;
+typedef struct _CoglAttribute CoglAttribute;
 
 /**
- * CoglVertexAttributeType:
- * @COGL_VERTEX_ATTRIBUTE_TYPE_BYTE: Data is the same size of a byte
- * @COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_BYTE: Data is the same size of an
- *   unsigned byte
- * @COGL_VERTEX_ATTRIBUTE_TYPE_SHORT: Data is the same size of a short integer
- * @COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_SHORT: Data is the same size of
- *   an unsigned short integer
- * @COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT: Data is the same size of a float
- *
- * Data types for the components of a vertex attribute.
- *
- * Since: 1.4
- * Stability: Unstable
- */
-typedef enum {
-  COGL_VERTEX_ATTRIBUTE_TYPE_BYTE           = 0x1400,
-  COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_BYTE  = 0x1401,
-  COGL_VERTEX_ATTRIBUTE_TYPE_SHORT          = 0x1402,
-  COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_SHORT = 0x1403,
-  COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT          = 0x1406
-} CoglVertexAttributeType;
-
-/**
- * cogl_vertex_attribute_new:
+ * cogl_attribute_new:
  * @array: The #CoglVertexArray containing the actual attribute data
  * @name: The name of the attribute (used to reference it from GLSL)
  * @stride: The number of bytes to jump to get to the next attribute
@@ -145,7 +122,7 @@ typedef enum {
  * mapped into the GPU which can be a bottlneck when dealing with
  * a large number of vertices.
  *
- * Returns: A newly allocated #CoglVertexAttribute describing the
+ * Returns: A newly allocated #CoglAttribute describing the
  *          layout for a list of attribute values stored in @array.
  *
  * Since: 1.4
@@ -153,53 +130,53 @@ typedef enum {
  */
 /* XXX: look for a precedent to see if the stride/offset args should
  * have a different order. */
-CoglVertexAttribute *
-cogl_vertex_attribute_new (CoglVertexArray *array,
-                           const char *name,
-                           gsize stride,
-                           gsize offset,
-                           int components,
-                           CoglVertexAttributeType type);
+CoglAttribute *
+cogl_attribute_new (CoglVertexArray *array,
+                    const char *name,
+                    gsize stride,
+                    gsize offset,
+                    int components,
+                    CoglAttributeType type);
 
 /**
- * cogl_is_vertex_attribute:
+ * cogl_is_attribute:
  * @object: A #CoglObject
  *
- * Gets whether the given object references a #CoglVertexAttribute.
+ * Gets whether the given object references a #CoglAttribute.
  *
- * Return value: %TRUE if the handle references a #CoglVertexAttribute,
+ * Return value: %TRUE if the handle references a #CoglAttribute,
  *   %FALSE otherwise
  */
 gboolean
-cogl_is_vertex_attribute (void *object);
+cogl_is_attribute (void *object);
 
 void
-cogl_draw_vertex_attributes (CoglVerticesMode mode,
-                             int first_vertex,
-                             int n_vertices,
-                             ...) G_GNUC_NULL_TERMINATED;
+cogl_draw_attributes (CoglVerticesMode mode,
+                      int first_vertex,
+                      int n_vertices,
+                      ...) G_GNUC_NULL_TERMINATED;
 
 void
-cogl_draw_vertex_attributes_array (CoglVerticesMode mode,
-                                   int first_vertex,
-                                   int n_vertices,
-                                   CoglVertexAttribute **attributes);
+cogl_draw_attributes_array (CoglVerticesMode mode,
+                            int first_vertex,
+                            int n_vertices,
+                            CoglAttribute **attributes);
 
 void
-cogl_draw_indexed_vertex_attributes (CoglVerticesMode mode,
-                                     int first_vertex,
-                                     int n_vertices,
-                                     CoglIndices *indices,
-                                     ...) G_GNUC_NULL_TERMINATED;
+cogl_draw_indexed_attributes (CoglVerticesMode mode,
+                              int first_vertex,
+                              int n_vertices,
+                              CoglIndices *indices,
+                              ...) G_GNUC_NULL_TERMINATED;
 
 void
-cogl_draw_indexed_vertex_attributes_array (CoglVerticesMode mode,
-                                           int first_vertex,
-                                           int n_vertices,
-                                           CoglIndices *indices,
-                                           CoglVertexAttribute **attributes);
+cogl_draw_indexed_attributes_array (CoglVerticesMode mode,
+                                    int first_vertex,
+                                    int n_vertices,
+                                    CoglIndices *indices,
+                                    CoglAttribute **attributes);
 
 G_END_DECLS
 
-#endif /* __COGL_VERTEX_ATTRIBUTE_H__ */
+#endif /* __COGL_ATTRIBUTE_H__ */
 
index 80ed00c..f0bd0ee 100644 (file)
@@ -198,13 +198,8 @@ _cogl_bitmap_from_file (const char   *filename,
   int               width;
   int               height;
   int               rowstride;
-  int               aligned_rowstride;
   int               bits_per_sample;
   int               n_channels;
-  guint8           *pixels;
-  guint8           *out_data;
-  guint8           *out;
-  int               r;
 
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
@@ -247,55 +242,18 @@ _cogl_bitmap_from_file (const char   *filename,
       return FALSE;
     }
 
-  /* Work out what the rowstride would be if it was packing the data
-     but aligned to 4 bytes */
-  aligned_rowstride = (width * n_channels + 3) & ~3;
-
-  /* The documentation for GdkPixbuf states that is not safe to read
-     all of the data as height*rowstride because the buffer might not
-     be allocated to include the full length of the rowstride for the
-     last row so arguably we should always copy the buffer when
-     rowstride != width*bpp because some places in Cogl assume that it
-     can memcpy(height*rowstride). However that rule is probably only
-     in place so that GdkPixbuf can implement gdk_pixbuf_new_subpixbuf
-     by just sharing the data and setting a large rowstride. That does
-     not apply in this case because we are just creating a new buffer
-     for a file. It seems very unlikely that GdkPixbuf would not
-     allocate the full rowstride in this case and it is highly
-     desirable to avoid copying the buffer. This instead just assumes
-     that whatever buffer pixbuf points into will always be allocated
-     to a 4-byte aligned buffer so we can avoid copying unless the
-     rowstride is unusually large */
-  if (rowstride <= aligned_rowstride)
-    return _cogl_bitmap_new_from_data (gdk_pixbuf_get_pixels (pixbuf),
-                                       pixel_format,
-                                       width,
-                                       height,
-                                       rowstride,
-                                       _cogl_bitmap_unref_pixbuf,
-                                       pixbuf);
-
-  pixels   = gdk_pixbuf_get_pixels (pixbuf);
-  out_data = g_malloc (aligned_rowstride * height);
-  out      = out_data;
-
-  for (r = 0; r < height; ++r)
-    {
-      memcpy (out, pixels, n_channels * width);
-      pixels += rowstride;
-      out += aligned_rowstride;
-    }
-
-  /* Destroy GdkPixbuf object */
-  g_object_unref (pixbuf);
-
-  return _cogl_bitmap_new_from_data (out_data,
+  /* We just use the data directly from the pixbuf so that we don't
+     have to copy to a seperate buffer. Note that Cogl is expected not
+     to read past the end of bpp*width on the last row even if the
+     rowstride is much larger so we don't need to worry about
+     GdkPixbuf's semantics that it may under-allocate the buffer. */
+  return _cogl_bitmap_new_from_data (gdk_pixbuf_get_pixels (pixbuf),
                                      pixel_format,
                                      width,
                                      height,
-                                     aligned_rowstride,
-                                     (CoglBitmapDestroyNotify) g_free,
-                                     NULL);
+                                     rowstride,
+                                     _cogl_bitmap_unref_pixbuf,
+                                     pixbuf);
 }
 
 #else
index d14293f..a1f3066 100644 (file)
@@ -155,6 +155,10 @@ _cogl_bitmap_copy_subregion (CoglBitmap *src,
                             int         width,
                             int         height);
 
+/* Creates a deep copy of the source bitmap */
+CoglBitmap *
+_cogl_bitmap_copy (CoglBitmap *src_bmp);
+
 gboolean
 _cogl_bitmap_get_size_from_file (const char *filename,
                                  int        *width,
@@ -176,6 +180,14 @@ _cogl_bitmap_get_height (CoglBitmap *bitmap);
 int
 _cogl_bitmap_get_rowstride (CoglBitmap *bitmap);
 
+/* Maps the bitmap so that the pixels can be accessed directly or if
+   the bitmap is just a memory bitmap then it just returns the pointer
+   to memory. Note that the bitmap isn't guaranteed to allocated to
+   the full size of rowstride*height so it is not safe to read up to
+   the rowstride of the last row. This will be the case if the user
+   uploads data using gdk_pixbuf_new_subpixbuf with a sub region
+   containing the last row of the pixbuf because in that case the
+   rowstride can be much larger than the width of the image */
 guint8 *
 _cogl_bitmap_map (CoglBitmap *bitmap,
                   CoglBufferAccess access,
index 355a2a2..cc83dda 100644 (file)
@@ -181,6 +181,35 @@ _cogl_bitmap_convert_format_and_premult (CoglBitmap *bmp,
   return dst_bmp;
 }
 
+CoglBitmap *
+_cogl_bitmap_copy (CoglBitmap *src_bmp)
+{
+  CoglBitmap *dst_bmp;
+  CoglPixelFormat src_format = _cogl_bitmap_get_format (src_bmp);
+  int bpp = _cogl_get_format_bpp (src_format);
+  int width = _cogl_bitmap_get_width (src_bmp);
+  int height = _cogl_bitmap_get_height (src_bmp);
+  int dst_rowstride = width * bpp;
+
+  /* Round the rowstride up to the next nearest multiple of 4 bytes */
+  dst_rowstride = (dst_rowstride + 3) & ~3;
+
+  dst_bmp = _cogl_bitmap_new_from_data (g_malloc (dst_rowstride * height),
+                                        src_format,
+                                        width, height,
+                                        dst_rowstride,
+                                        (CoglBitmapDestroyNotify) g_free,
+                                        NULL);
+
+  _cogl_bitmap_copy_subregion (src_bmp,
+                               dst_bmp,
+                               0, 0, /* src_x/y */
+                               0, 0, /* dst_x/y */
+                               width, height);
+
+  return dst_bmp;
+}
+
 void
 _cogl_bitmap_copy_subregion (CoglBitmap *src,
                             CoglBitmap *dst,
index 9912fdf..2e7dd5b 100644 (file)
@@ -197,7 +197,7 @@ error:
                "Invalid texture combine string: %s",
                error_string);
 
-  if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS)
+  if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
     {
       g_debug ("Invalid texture combine string: %s",
                error_string);
@@ -321,7 +321,7 @@ error:
                "blend" : "texture combine",
                error_string);
 
-  if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS)
+  if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
     {
       g_debug ("Invalid %s string: %s",
                context == COGL_BLEND_STRING_CONTEXT_BLENDING ?
@@ -728,7 +728,7 @@ error:
                  offset,
                  error_string);
 
-    if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS)
+    if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
       {
         g_debug ("Syntax error for argument %d at offset %d: %s",
                  current_arg, offset, error_string);
@@ -753,10 +753,10 @@ _cogl_blend_string_compile (const char *string,
   int remaining_argc = 0;
 
 #if 0
-  cogl_debug_flags |= COGL_DEBUG_BLEND_STRINGS;
+  COGL_DEBUG_SET_FLAG (COGL_DEBUG_BLEND_STRINGS);
 #endif
 
-  if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS)
+  if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
     {
       COGL_NOTE (BLEND_STRINGS, "Compiling %s string:\n%s\n",
                  context == COGL_BLEND_STRING_CONTEXT_BLENDING ?
@@ -882,7 +882,7 @@ _cogl_blend_string_compile (const char *string,
 
 finished:
 
-  if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS)
+  if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
     {
       if (current_statement > 0)
         print_statement (0, &statements[0]);
@@ -908,7 +908,7 @@ error:
                    offset,
                    error_string);
 
-      if (cogl_debug_flags & COGL_DEBUG_BLEND_STRINGS)
+      if (COGL_DEBUG_ENABLED (COGL_DEBUG_BLEND_STRINGS))
         {
           g_debug ("Syntax error at offset %d: %s",
                    offset, error_string);
index 28d1a25..fc79e7d 100644 (file)
@@ -56,9 +56,10 @@ struct _CoglBufferVtable
 
 typedef enum _CoglBufferFlags
 {
-  COGL_BUFFER_FLAG_NONE          = 0,
-  COGL_BUFFER_FLAG_BUFFER_OBJECT = 1UL << 0,  /* real openGL buffer object */
-  COGL_BUFFER_FLAG_MAPPED        = 1UL << 1
+  COGL_BUFFER_FLAG_NONE            = 0,
+  COGL_BUFFER_FLAG_BUFFER_OBJECT   = 1UL << 0,  /* real openGL buffer object */
+  COGL_BUFFER_FLAG_MAPPED          = 1UL << 1,
+  COGL_BUFFER_FLAG_MAPPED_FALLBACK = 1UL << 2
 } CoglBufferFlags;
 
 typedef enum {
@@ -145,6 +146,18 @@ _cogl_buffer_immutable_ref (CoglBuffer *buffer);
 void
 _cogl_buffer_immutable_unref (CoglBuffer *buffer);
 
+/* This is a wrapper around cogl_buffer_map for internal use when we
+   want to map the buffer for write only to replace the entire
+   contents. If the map fails then it will fallback to writing to a
+   temporary buffer. When _cogl_buffer_unmap_for_fill_or_fallback is
+   called the temporary buffer will be copied into the array. Note
+   that these calls share a global array so they can not be nested. */
+void *
+_cogl_buffer_map_for_fill_or_fallback (CoglBuffer *buffer);
+
+void
+_cogl_buffer_unmap_for_fill_or_fallback (CoglBuffer *buffer);
+
 G_END_DECLS
 
 #endif /* __COGL_BUFFER_PRIVATE_H__ */
index ab5043a..f61f1af 100644 (file)
 #define glBufferSubData ctx->drv.pf_glBufferSubData
 #define glGetBufferSubData ctx->drv.pf_glGetBufferSubData
 #define glDeleteBuffers ctx->drv.pf_glDeleteBuffers
-#define glMapBuffer ctx->drv.pf_glMapBuffer
-#define glUnmapBuffer ctx->drv.pf_glUnmapBuffer
 
 #endif
 
+/* These two are always accessed through an extension, even on GLES */
+#define glMapBuffer ctx->drv.pf_glMapBuffer
+#define glUnmapBuffer ctx->drv.pf_glUnmapBuffer
+
 #ifndef GL_PIXEL_PACK_BUFFER
 #define GL_PIXEL_PACK_BUFFER 0x88EB
 #endif
 #ifndef GL_ELEMENT_ARRAY_BUFFER
 #define GL_ARRAY_BUFFER 0x8893
 #endif
+#ifndef GL_READ_ONLY
+#define GL_READ_ONLY 0x88B8
+#endif
+#ifndef GL_WRITE_ONLY
+#define GL_WRITE_ONLY 0x88B9
+#endif
+#ifndef GL_READ_WRITE
+#define GL_READ_WRITE 0x88BA
+#endif
 
 /* XXX:
  * The CoglHandle macros don't support any form of inheritance, so for
@@ -131,13 +142,19 @@ bo_map (CoglBuffer       *buffer,
         CoglBufferAccess  access,
         CoglBufferMapHint hints)
 {
-#ifndef COGL_HAS_GLES
   guint8 *data;
   CoglBufferBindTarget target;
   GLenum gl_target;
 
   _COGL_GET_CONTEXT (ctx, NULL);
 
+  if ((access & COGL_BUFFER_ACCESS_READ) &&
+      !cogl_features_available (COGL_FEATURE_MAP_BUFFER_FOR_READ))
+    return NULL;
+  if ((access & COGL_BUFFER_ACCESS_WRITE) &&
+      !cogl_features_available (COGL_FEATURE_MAP_BUFFER_FOR_WRITE))
+    return NULL;
+
   target = buffer->last_target;
   _cogl_buffer_bind (buffer, target);
 
@@ -164,18 +181,11 @@ bo_map (CoglBuffer       *buffer,
   _cogl_buffer_unbind (buffer);
 
   return data;
-
-#else /* COGL_HAS_GLES */
-
-  return NULL;
-
-#endif /* COGL_HAS_GLES */
 }
 
 static void
 bo_unmap (CoglBuffer *buffer)
 {
-#ifndef COGL_HAS_GLES
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   _cogl_buffer_bind (buffer, buffer->last_target);
@@ -184,9 +194,6 @@ bo_unmap (CoglBuffer *buffer)
   buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED;
 
   _cogl_buffer_unbind (buffer);
-#else
-  g_return_if_reached ();
-#endif
 }
 
 static gboolean
@@ -306,16 +313,6 @@ _cogl_buffer_fini (CoglBuffer *buffer)
     g_free (buffer->data);
 }
 
-/* OpenGL ES 1.1 and 2 have a GL_OES_mapbuffer extension that is able to map
- * VBOs for write only, we don't support that in CoglBuffer */
-#if defined (COGL_HAS_GLES)
-GLenum
-_cogl_buffer_access_to_gl_enum (CoglBufferAccess access)
-{
-  return 0;
-}
-
-#else
 GLenum
 _cogl_buffer_access_to_gl_enum (CoglBufferAccess access)
 {
@@ -326,7 +323,6 @@ _cogl_buffer_access_to_gl_enum (CoglBufferAccess access)
   else
     return GL_READ_ONLY;
 }
-#endif
 
 /* OpenGL ES 1.1 and 2 only know about STATIC_DRAW and DYNAMIC_DRAW */
 #if defined (COGL_HAS_GLES)
@@ -474,6 +470,57 @@ cogl_buffer_unmap (CoglBuffer *buffer)
   buffer->vtable.unmap (buffer);
 }
 
+void *
+_cogl_buffer_map_for_fill_or_fallback (CoglBuffer *buffer)
+{
+  void *ret;
+
+  _COGL_GET_CONTEXT (ctx, NULL);
+
+  g_return_val_if_fail (!ctx->buffer_map_fallback_in_use, NULL);
+
+  ctx->buffer_map_fallback_in_use = TRUE;
+
+  ret = cogl_buffer_map (buffer,
+                         COGL_BUFFER_ACCESS_WRITE,
+                         COGL_BUFFER_MAP_HINT_DISCARD);
+
+  if (ret)
+    return ret;
+  else
+    {
+      /* If the map fails then we'll use a temporary buffer to fill
+         the data and then upload it using cogl_buffer_set_data when
+         the buffer is unmapped. The temporary buffer is shared to
+         avoid reallocating it every time */
+      g_byte_array_set_size (ctx->buffer_map_fallback_array, buffer->size);
+
+      buffer->flags |= COGL_BUFFER_FLAG_MAPPED_FALLBACK;
+
+      return ctx->buffer_map_fallback_array->data;
+    }
+}
+
+void
+_cogl_buffer_unmap_for_fill_or_fallback (CoglBuffer *buffer)
+{
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  g_return_if_fail (ctx->buffer_map_fallback_in_use);
+
+  ctx->buffer_map_fallback_in_use = FALSE;
+
+  if ((buffer->flags & COGL_BUFFER_FLAG_MAPPED_FALLBACK))
+    {
+      cogl_buffer_set_data (buffer, 0,
+                            ctx->buffer_map_fallback_array->data,
+                            buffer->size);
+      buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED_FALLBACK;
+    }
+  else
+    cogl_buffer_unmap (buffer);
+}
+
 gboolean
 cogl_buffer_set_data (CoglBuffer   *buffer,
                       gsize         offset,
index ffc0000..ef0313b 100644 (file)
@@ -203,6 +203,14 @@ add_stencil_clip_rectangle (float x_1,
   /* temporarily swap in our special stenciling pipeline */
   cogl_push_source (ctx->stencil_pipeline);
 
+  /* This can be called from the journal code which doesn't flush
+     the matrix stacks between calls so we need to ensure they're
+     flushed now */
+  _cogl_matrix_stack_flush_to_gl (modelview_stack,
+                                  COGL_MATRIX_MODELVIEW);
+  _cogl_matrix_stack_flush_to_gl (projection_stack,
+                                  COGL_MATRIX_PROJECTION);
+
   if (first)
     {
       GE( glEnable (GL_STENCIL_TEST) );
@@ -215,14 +223,6 @@ add_stencil_clip_rectangle (float x_1,
       GE( glStencilFunc (GL_NEVER, 0x1, 0x1) );
       GE( glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) );
 
-      /* This can be called from the journal code which doesn't flush
-         the matrix stacks between calls so we need to ensure they're
-         flushed now */
-      _cogl_matrix_stack_flush_to_gl (modelview_stack,
-                                      COGL_MATRIX_MODELVIEW);
-      _cogl_matrix_stack_flush_to_gl (projection_stack,
-                                      COGL_MATRIX_PROJECTION);
-
       _cogl_rectangle_immediate (x_1, y_1, x_2, y_2);
     }
   else
@@ -532,15 +532,40 @@ _cogl_clip_stack_pop (CoglClipStack *stack)
 }
 
 void
+_cogl_clip_stack_get_bounds (CoglClipStack *stack,
+                             int *scissor_x0,
+                             int *scissor_y0,
+                             int *scissor_x1,
+                             int *scissor_y1)
+{
+  CoglClipStack *entry;
+
+  *scissor_x0 = 0;
+  *scissor_y0 = 0;
+  *scissor_x1 = G_MAXINT;
+  *scissor_y1 = G_MAXINT;
+
+  for (entry = stack; entry; entry = entry->parent)
+    {
+      /* Get the intersection of the current scissor and the bounding
+         box of this clip */
+      *scissor_x0 = MAX (*scissor_x0, entry->bounds_x0);
+      *scissor_y0 = MAX (*scissor_y0, entry->bounds_y0);
+      *scissor_x1 = MIN (*scissor_x1, entry->bounds_x1);
+      *scissor_y1 = MIN (*scissor_y1, entry->bounds_y1);
+    }
+}
+
+void
 _cogl_clip_stack_flush (CoglClipStack *stack)
 {
   int has_clip_planes;
   gboolean using_clip_planes = FALSE;
   gboolean using_stencil_buffer = FALSE;
-  int scissor_x0 = 0;
-  int scissor_y0 = 0;
-  int scissor_x1 = G_MAXINT;
-  int scissor_y1 = G_MAXINT;
+  int scissor_x0;
+  int scissor_y0;
+  int scissor_x1;
+  int scissor_y1;
   CoglMatrixStack *modelview_stack;
   CoglClipStack *entry;
   int scissor_y_start;
@@ -572,6 +597,8 @@ _cogl_clip_stack_flush (CoglClipStack *stack)
   /* If the stack is empty then there's nothing else to do */
   if (stack == NULL)
     {
+      COGL_NOTE (CLIPPING, "Flushed empty clip stack");
+
       ctx->current_clip_stack_uses_stencil = FALSE;
       GE (glDisable (GL_SCISSOR_TEST));
       return;
@@ -581,15 +608,9 @@ _cogl_clip_stack_flush (CoglClipStack *stack)
      clear the stencil buffer then the clear will be clipped to the
      intersection of all of the bounding boxes. This saves having to
      clear the whole stencil buffer */
-  for (entry = stack; entry; entry = entry->parent)
-    {
-      /* Get the intersection of the current scissor and the bounding
-         box of this clip */
-      scissor_x0 = MAX (scissor_x0, entry->bounds_x0);
-      scissor_y0 = MAX (scissor_y0, entry->bounds_y0);
-      scissor_x1 = MIN (scissor_x1, entry->bounds_x1);
-      scissor_y1 = MIN (scissor_y1, entry->bounds_y1);
-    }
+  _cogl_clip_stack_get_bounds (stack,
+                               &scissor_x0, &scissor_y0,
+                               &scissor_x1, &scissor_y1);
 
   /* Enable scissoring as soon as possible */
   if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1)
@@ -617,6 +638,10 @@ _cogl_clip_stack_flush (CoglClipStack *stack)
         }
     }
 
+  COGL_NOTE (CLIPPING, "Flushing scissor to (%i, %i, %i, %i)",
+             scissor_x0, scissor_y0,
+             scissor_x1, scissor_y1);
+
   GE (glEnable (GL_SCISSOR_TEST));
   GE (glScissor (scissor_x0, scissor_y_start,
                  scissor_x1 - scissor_x0,
@@ -632,6 +657,8 @@ _cogl_clip_stack_flush (CoglClipStack *stack)
         {
           CoglClipStackPath *path_entry = (CoglClipStackPath *) entry;
 
+          COGL_NOTE (CLIPPING, "Adding stencil clip for path");
+
           _cogl_matrix_stack_push (modelview_stack);
           _cogl_matrix_stack_set (modelview_stack, &path_entry->matrix);
 
@@ -658,6 +685,8 @@ _cogl_clip_stack_flush (CoglClipStack *stack)
                  them then use that instead */
               if (has_clip_planes)
                 {
+                  COGL_NOTE (CLIPPING, "Adding clip planes clip for rectangle");
+
                   set_clip_planes (rect->x0,
                                    rect->y0,
                                    rect->x1,
@@ -668,6 +697,8 @@ _cogl_clip_stack_flush (CoglClipStack *stack)
                 }
               else
                 {
+                  COGL_NOTE (CLIPPING, "Adding stencil clip for rectangle");
+
                   add_stencil_clip_rectangle (rect->x0,
                                               rect->y0,
                                               rect->x1,
index 2baa4e2..307d7ef 100644 (file)
@@ -171,6 +171,13 @@ CoglClipStack *
 _cogl_clip_stack_pop (CoglClipStack *stack);
 
 void
+_cogl_clip_stack_get_bounds (CoglClipStack *stack,
+                             int *scissor_x0,
+                             int *scissor_y0,
+                             int *scissor_x1,
+                             int *scissor_y1);
+
+void
 _cogl_clip_stack_flush (CoglClipStack *stack);
 
 CoglClipStack *
index 1fc31f1..4e6adca 100644 (file)
@@ -169,14 +169,15 @@ _cogl_clip_state_flush (CoglClipState *clip_state)
 void
 cogl_clip_ensure (void)
 {
+  CoglFramebuffer *framebuffer = _cogl_get_framebuffer ();
   CoglClipState *clip_state;
 
-  clip_state = _cogl_framebuffer_get_clip_state (_cogl_get_framebuffer ());
+  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
   /* Flushing the clip state doesn't cause the journal to be
      flushed. This function may be being called by an external
      application however so it makes sense to flush the journal
      here */
-  _cogl_journal_flush ();
+  _cogl_framebuffer_flush_journal (framebuffer);
   _cogl_clip_state_flush (clip_state);
 }
 
@@ -250,30 +251,15 @@ _cogl_clip_state_destroy (CoglClipState *clip_state)
 }
 
 CoglClipStack *
-_cogl_get_clip_stack (void)
+_cogl_clip_state_get_stack (CoglClipState *clip_state)
 {
-  CoglFramebuffer *framebuffer;
-  CoglClipState *clip_state;
-
-  _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
-
-  framebuffer = _cogl_get_framebuffer ();
-  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
-
   return clip_state->stacks->data;
 }
 
 void
-_cogl_set_clip_stack (CoglClipStack *stack)
+_cogl_clip_state_set_stack (CoglClipState *clip_state,
+                            CoglClipStack *stack)
 {
-  CoglFramebuffer *framebuffer;
-  CoglClipState *clip_state;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  framebuffer = _cogl_get_framebuffer ();
-  clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
-
   /* Replace the top of the stack of stacks */
   _cogl_clip_stack_ref (stack);
   _cogl_clip_stack_unref (clip_state->stacks->data);
index 29cacfd..2358273 100644 (file)
@@ -43,26 +43,11 @@ _cogl_clip_state_destroy (CoglClipState *state);
 void
 _cogl_clip_state_flush (CoglClipState *clip_state);
 
-/*
- * _cogl_get_clip_stack:
- *
- * Gets a pointer to the current clip stack. This can be used to later
- * return to the same clip stack state with _cogl_set_clip_stack(). A
- * reference is not taken on the stack so if you want to keep it you
- * should call _cogl_clip_stack_ref().
- *
- * Return value: a pointer to the current clip stack.
- */
 CoglClipStack *
-_cogl_get_clip_stack (void);
+_cogl_clip_state_get_stack (CoglClipState *clip_state);
 
-/*
- * _cogl_set_clip_stack:
- * @stack: a pointer to the replacement clip stack
- *
- * Replaces the current clip stack with @stack.
- */
 void
-_cogl_set_clip_stack (CoglClipStack *stack);
+_cogl_clip_state_set_stack (CoglClipState *clip_state,
+                            CoglClipStack *clip_stack);
 
 #endif /* __COGL_CLIP_STATE_H */
index c8fb1d7..bea9357 100644 (file)
@@ -62,19 +62,19 @@ static gboolean gl_is_indirect = FALSE;
 static void
 _cogl_init_feature_overrides (CoglContext *ctx)
 {
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_VBOS))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_VBOS)))
     ctx->feature_flags &= ~COGL_FEATURE_VBOS;
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_PBOS))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PBOS)))
     ctx->feature_flags &= ~COGL_FEATURE_PBOS;
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_ARBFP))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_ARBFP)))
     ctx->feature_flags &= ~COGL_FEATURE_SHADERS_ARBFP;
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_GLSL))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_GLSL)))
     ctx->feature_flags &= ~COGL_FEATURE_SHADERS_GLSL;
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_NPOT_TEXTURES))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_NPOT_TEXTURES)))
     ctx->feature_flags &= ~(COGL_FEATURE_TEXTURE_NPOT |
                             COGL_FEATURE_TEXTURE_NPOT_BASIC |
                             COGL_FEATURE_TEXTURE_NPOT_MIPMAP |
@@ -166,10 +166,10 @@ cogl_create_context (void)
   _context->default_gl_texture_2d_tex = COGL_INVALID_HANDLE;
   _context->default_gl_texture_rect_tex = COGL_INVALID_HANDLE;
 
-  _context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry));
-  _context->logged_vertices = g_array_new (FALSE, FALSE, sizeof (GLfloat));
+  _context->framebuffers = NULL;
+
   _context->journal_flush_attributes_array =
-    g_array_new (TRUE, FALSE, sizeof (CoglVertexAttribute *));
+    g_array_new (TRUE, FALSE, sizeof (CoglAttribute *));
   _context->journal_clip_bounds = NULL;
 
   _context->polygon_vertices = g_array_new (FALSE, FALSE, sizeof (float));
@@ -287,14 +287,20 @@ cogl_create_context (void)
 
   _context->atlases = NULL;
 
+  _context->buffer_map_fallback_array = g_byte_array_new ();
+  _context->buffer_map_fallback_in_use = FALSE;
+
   /* As far as I can tell, GL_POINT_SPRITE doesn't have any effect
      unless GL_COORD_REPLACE is enabled for an individual
      layer. Therefore it seems like it should be ok to just leave it
      enabled all the time instead of having to have a set property on
      each pipeline to track whether any layers have point sprite
-     coords enabled */
+     coords enabled. We don't need to do this for GLES2 because point
+     sprites are handled using a builtin varying in the shader. */
+#ifndef HAVE_COGL_GLES2
   if (cogl_features_available (COGL_FEATURE_POINT_SPRITE))
     GE (glEnable (GL_POINT_SPRITE));
+#endif
 
   return TRUE;
 }
@@ -327,10 +333,6 @@ _cogl_destroy_context (void)
   if (_context->texture_pipeline)
     cogl_handle_unref (_context->texture_pipeline);
 
-  if (_context->journal)
-    g_array_free (_context->journal, TRUE);
-  if (_context->logged_vertices)
-    g_array_free (_context->logged_vertices, TRUE);
   if (_context->journal_flush_attributes_array)
     g_array_free (_context->journal_flush_attributes_array, TRUE);
   if (_context->journal_clip_bounds)
@@ -382,6 +384,8 @@ _cogl_destroy_context (void)
   g_hash_table_unref (_context->arbfp_cache);
 #endif
 
+  g_byte_array_free (_context->buffer_map_fallback_array, TRUE);
+
   g_free (_context);
 }
 
index 1d55923..8c0161f 100644 (file)
@@ -109,14 +109,12 @@ typedef struct
   CoglHandle        default_gl_texture_2d_tex;
   CoglHandle        default_gl_texture_rect_tex;
 
-  /* Batching geometry... */
-  /* We journal the texture rectangles we want to submit to OpenGL so
-   * we have an oppertunity to optimise the final order so that we
-   * can batch things together. */
-  GArray           *journal;
-  GArray           *logged_vertices;
+  /* Central list of all framebuffers so all journals can be flushed
+   * at any time. */
+  GList            *framebuffers;
+
+  /* Global journal buffers */
   GArray           *journal_flush_attributes_array;
-  size_t            journal_needed_vbo_len;
   GArray           *journal_clip_bounds;
 
   GArray           *polygon_vertices;
@@ -229,6 +227,12 @@ typedef struct
      stencil buffer */
   gboolean          current_clip_stack_uses_stencil;
 
+  /* This is used as a temporary buffer to fill a CoglBuffer when
+     cogl_buffer_map fails and we only want to map to fill it with new
+     data */
+  GByteArray       *buffer_map_fallback_array;
+  gboolean          buffer_map_fallback_in_use;
+
   CoglContextDriver drv;
   CoglContextWinsys winsys;
 } CoglContext;
index 972c69c..38027f5 100644 (file)
@@ -168,4 +168,14 @@ OPT (DISABLE_BLENDING,
      "disable-program-caches",
      "Disable program caches",
      "Disable fallback caches for arbfp and glsl programs")
-
+OPT (DISABLE_FAST_READ_PIXEL,
+     "Root Cause",
+     "disable-fast-read-pixel",
+     "Disable read pixel optimization",
+     "Disable optimization for reading 1px for simple "
+     "scenes of opaque rectangles")
+OPT (CLIPPING,
+     "Cogl Tracing",
+     "clipping",
+     "Trace clipping",
+     "Logs information about how Cogl is implementing clipping")
index 5c2b5c2..d120502 100644 (file)
@@ -54,7 +54,8 @@ static const GDebugKey cogl_log_debug_keys[] = {
   { "show-source", COGL_DEBUG_SHOW_SOURCE},
   { "offscreen", COGL_DEBUG_OFFSCREEN },
   { "texture-pixmap", COGL_DEBUG_TEXTURE_PIXMAP },
-  { "bitmap", COGL_DEBUG_BITMAP }
+  { "bitmap", COGL_DEBUG_BITMAP },
+  { "clipping", COGL_DEBUG_CLIPPING }
 };
 static const int n_cogl_log_debug_keys =
   G_N_ELEMENTS (cogl_log_debug_keys);
@@ -75,24 +76,65 @@ static const GDebugKey cogl_behavioural_debug_keys[] = {
   { "disable-npot-textures", COGL_DEBUG_DISABLE_NPOT_TEXTURES},
   { "wireframe", COGL_DEBUG_WIREFRAME},
   { "disable-software-clip", COGL_DEBUG_DISABLE_SOFTWARE_CLIP},
-  { "disable-program-caches", COGL_DEBUG_DISABLE_PROGRAM_CACHES}
+  { "disable-program-caches", COGL_DEBUG_DISABLE_PROGRAM_CACHES},
+  { "disable-fast-read-pixel", COGL_DEBUG_DISABLE_FAST_READ_PIXEL}
 };
 static const int n_cogl_behavioural_debug_keys =
   G_N_ELEMENTS (cogl_behavioural_debug_keys);
 
 #endif /* COGL_ENABLE_DEBUG */
 
-unsigned int cogl_debug_flags = 0;
+unsigned int _cogl_debug_flags[COGL_DEBUG_N_INTS];
 
 #ifdef COGL_ENABLE_DEBUG
-static unsigned int
+
+static void
+_cogl_parse_debug_string_for_keys (const char *value,
+                                   gboolean enable,
+                                   const GDebugKey *keys,
+                                   unsigned int nkeys)
+{
+  int int_num, key_num;
+
+  /* g_parse_debug_string expects the value field in GDebugKey to be a
+     mask in a guint but we may have multiple guints so we need to
+     build a separate array for each possible guint */
+
+  for (int_num = 0; int_num < COGL_DEBUG_N_INTS; int_num++)
+    {
+      GDebugKey keys_for_int[sizeof (unsigned int) * 8];
+      unsigned int mask_for_int;
+      int nkeys_for_int = 0;
+
+      for (key_num = 0; key_num < nkeys; key_num++)
+        if (COGL_DEBUG_GET_FLAG_INDEX (keys[key_num].value) == int_num)
+          {
+            keys_for_int[nkeys_for_int] = keys[key_num];
+            keys_for_int[nkeys_for_int].value =
+              COGL_DEBUG_GET_FLAG_MASK (keys[key_num].value);
+            nkeys_for_int++;
+          }
+
+      if (nkeys_for_int > 0)
+        {
+          mask_for_int = g_parse_debug_string (value,
+                                               keys_for_int,
+                                               nkeys_for_int);
+          if (enable)
+            _cogl_debug_flags[int_num] |= mask_for_int;
+          else
+            _cogl_debug_flags[int_num] &= ~mask_for_int;
+        }
+    }
+}
+
+static void
 _cogl_parse_debug_string (const char *value,
+                          gboolean enable,
                           gboolean ignore_help)
 {
-  unsigned int flags = 0;
-
   if (ignore_help && strcmp (value, "help") == 0)
-    return 0;
+    return;
 
   /* We don't want to let g_parse_debug_string handle "all" because
    * literally enabling all the debug options wouldn't be useful to
@@ -104,7 +146,10 @@ _cogl_parse_debug_string (const char *value,
     {
       int i;
       for (i = 0; i < n_cogl_log_debug_keys; i++)
-        flags |= cogl_log_debug_keys[i].value;
+        if (enable)
+          COGL_DEBUG_SET_FLAG (cogl_log_debug_keys[i].value);
+        else
+          COGL_DEBUG_CLEAR_FLAG (cogl_log_debug_keys[i].value);
     }
   else if (strcmp (value, "help") == 0)
     {
@@ -122,17 +167,15 @@ _cogl_parse_debug_string (const char *value,
     }
   else
     {
-      flags |=
-        g_parse_debug_string (value,
-                              cogl_log_debug_keys,
-                              n_cogl_log_debug_keys);
-      flags |=
-        g_parse_debug_string (value,
-                              cogl_behavioural_debug_keys,
-                              n_cogl_behavioural_debug_keys);
+      _cogl_parse_debug_string_for_keys (value,
+                                         enable,
+                                         cogl_log_debug_keys,
+                                         n_cogl_log_debug_keys);
+      _cogl_parse_debug_string_for_keys (value,
+                                         enable,
+                                         cogl_behavioural_debug_keys,
+                                         n_cogl_behavioural_debug_keys);
     }
-
-  return flags;
 }
 
 static gboolean
@@ -140,7 +183,9 @@ cogl_arg_debug_cb (const char *key,
                    const char *value,
                    gpointer    user_data)
 {
-  cogl_debug_flags |= _cogl_parse_debug_string (value, FALSE);
+  _cogl_parse_debug_string (value,
+                            TRUE /* enable the flags */,
+                            FALSE /* don't ignore help */);
   return TRUE;
 }
 
@@ -149,7 +194,9 @@ cogl_arg_no_debug_cb (const char *key,
                       const char *value,
                       gpointer    user_data)
 {
-  cogl_debug_flags &= ~_cogl_parse_debug_string (value, TRUE);
+  _cogl_parse_debug_string (value,
+                            FALSE, /* disable the flags */
+                            TRUE /* ignore help */);
   return TRUE;
 }
 #endif /* COGL_ENABLE_DEBUG */
@@ -176,7 +223,9 @@ pre_parse_hook (GOptionContext  *context,
   env_string = g_getenv ("COGL_DEBUG");
   if (env_string != NULL)
     {
-      cogl_debug_flags |= _cogl_parse_debug_string (env_string, FALSE);
+      _cogl_parse_debug_string (env_string,
+                                TRUE /* enable the flags */,
+                                FALSE /* don't ignore help */);
       env_string = NULL;
     }
 #endif /* COGL_ENABLE_DEBUG */
index 1a06bf7..0cd039f 100644 (file)
 G_BEGIN_DECLS
 
 typedef enum {
-  COGL_DEBUG_SLICING          = 1 << 1,
-  COGL_DEBUG_OFFSCREEN        = 1 << 2,
-  COGL_DEBUG_DRAW             = 1 << 3,
-  COGL_DEBUG_PANGO            = 1 << 4,
-  COGL_DEBUG_RECTANGLES       = 1 << 5,
-  COGL_DEBUG_HANDLE           = 1 << 6,
-  COGL_DEBUG_BLEND_STRINGS    = 1 << 7,
-  COGL_DEBUG_DISABLE_BATCHING = 1 << 8,
-  COGL_DEBUG_DISABLE_VBOS     = 1 << 9,
-  COGL_DEBUG_DISABLE_PBOS     = 1 << 10,
-  COGL_DEBUG_JOURNAL          = 1 << 11,
-  COGL_DEBUG_BATCHING         = 1 << 12,
-  COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM = 1 << 13,
-  COGL_DEBUG_MATRICES         = 1 << 14,
-  COGL_DEBUG_ATLAS            = 1 << 15,
-  COGL_DEBUG_DUMP_ATLAS_IMAGE = 1 << 16,
-  COGL_DEBUG_DISABLE_ATLAS    = 1 << 17,
-  COGL_DEBUG_OPENGL           = 1 << 18,
-  COGL_DEBUG_DISABLE_TEXTURING = 1 << 19,
-  COGL_DEBUG_DISABLE_ARBFP    = 1 << 20,
-  COGL_DEBUG_DISABLE_FIXED    = 1 << 21,
-  COGL_DEBUG_DISABLE_GLSL     = 1 << 22,
-  COGL_DEBUG_SHOW_SOURCE      = 1 << 23,
-  COGL_DEBUG_DISABLE_BLENDING = 1 << 24,
-  COGL_DEBUG_TEXTURE_PIXMAP   = 1 << 25,
-  COGL_DEBUG_BITMAP           = 1 << 26,
-  COGL_DEBUG_DISABLE_NPOT_TEXTURES = 1 << 27,
-  COGL_DEBUG_WIREFRAME        = 1 << 28,
-  COGL_DEBUG_DISABLE_SOFTWARE_CLIP = 1 << 29,
-  COGL_DEBUG_DISABLE_PROGRAM_CACHES = 1 << 30
+  COGL_DEBUG_SLICING,
+  COGL_DEBUG_OFFSCREEN,
+  COGL_DEBUG_DRAW,
+  COGL_DEBUG_PANGO,
+  COGL_DEBUG_RECTANGLES,
+  COGL_DEBUG_HANDLE,
+  COGL_DEBUG_BLEND_STRINGS,
+  COGL_DEBUG_DISABLE_BATCHING,
+  COGL_DEBUG_DISABLE_VBOS,
+  COGL_DEBUG_DISABLE_PBOS,
+  COGL_DEBUG_JOURNAL,
+  COGL_DEBUG_BATCHING,
+  COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM,
+  COGL_DEBUG_MATRICES,
+  COGL_DEBUG_ATLAS,
+  COGL_DEBUG_DUMP_ATLAS_IMAGE,
+  COGL_DEBUG_DISABLE_ATLAS,
+  COGL_DEBUG_OPENGL,
+  COGL_DEBUG_DISABLE_TEXTURING,
+  COGL_DEBUG_DISABLE_ARBFP,
+  COGL_DEBUG_DISABLE_FIXED,
+  COGL_DEBUG_DISABLE_GLSL,
+  COGL_DEBUG_SHOW_SOURCE,
+  COGL_DEBUG_DISABLE_BLENDING,
+  COGL_DEBUG_TEXTURE_PIXMAP,
+  COGL_DEBUG_BITMAP,
+  COGL_DEBUG_DISABLE_NPOT_TEXTURES,
+  COGL_DEBUG_WIREFRAME,
+  COGL_DEBUG_DISABLE_SOFTWARE_CLIP,
+  COGL_DEBUG_DISABLE_PROGRAM_CACHES,
+  COGL_DEBUG_DISABLE_FAST_READ_PIXEL,
+  COGL_DEBUG_CLIPPING,
+
+  COGL_DEBUG_N_FLAGS
 } CoglDebugFlags;
 
 #ifdef COGL_ENABLE_DEBUG
 
+#define COGL_DEBUG_N_INTS ((COGL_DEBUG_N_FLAGS + \
+                            (sizeof (unsigned int) * 8 - 1)) \
+                           / (sizeof (unsigned int) * 8))
+
+/* It would probably make sense to use unsigned long here instead
+   because then on 64-bit systems where it can handle 64-bits just as
+   easily and it can test more bits. However GDebugKey uses a guint
+   for the mask and we need to fit the masks into this */
+extern unsigned int _cogl_debug_flags[COGL_DEBUG_N_INTS];
+
+#define COGL_DEBUG_GET_FLAG_INDEX(flag) \
+  ((flag) / (sizeof (unsigned int) * 8))
+#define COGL_DEBUG_GET_FLAG_MASK(flag) \
+  (1U << ((unsigned int) (flag) & (sizeof (unsigned int) * 8 - 1)))
+
+#define COGL_DEBUG_ENABLED(flag) \
+  (!!(_cogl_debug_flags[COGL_DEBUG_GET_FLAG_INDEX (flag)] & \
+      COGL_DEBUG_GET_FLAG_MASK (flag)))
+
+#define COGL_DEBUG_SET_FLAG(flag) \
+  (_cogl_debug_flags[COGL_DEBUG_GET_FLAG_INDEX (flag)] |= \
+   COGL_DEBUG_GET_FLAG_MASK (flag))
+
+#define COGL_DEBUG_CLEAR_FLAG(flag) \
+  (_cogl_debug_flags[COGL_DEBUG_GET_FLAG_INDEX (flag)] &= \
+   ~COGL_DEBUG_GET_FLAG_MASK (flag))
+
 #ifdef __GNUC__
 #define COGL_NOTE(type,x,a...)                      G_STMT_START {            \
-        if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_##type)) {              \
+        if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_##type))) {            \
           _cogl_profile_trace_message ("[" #type "] " G_STRLOC " & " x, ##a); \
         }                                           } G_STMT_END
 
 #else
 #define COGL_NOTE(type,...)                         G_STMT_START {            \
-        if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_##type)) {              \
+        if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_##type)) {             \
           char *_fmt = g_strdup_printf (__VA_ARGS__);                         \
           _cogl_profile_trace_message ("[" #type "] " G_STRLOC " & %s", _fmt);\
           g_free (_fmt);                                                      \
@@ -85,9 +116,15 @@ typedef enum {
 
 #define COGL_NOTE(type,...) G_STMT_START {} G_STMT_END
 
-#endif /* COGL_ENABLE_DEBUG */
+#define COGL_DEBUG_ENABLED(flag) FALSE
+
+#define COGL_DEBUG_SET_FLAG(flag) \
+  G_STMT_START { } G_STMT_END
 
-extern unsigned int cogl_debug_flags;
+#define COGL_DEBUG_CLEAR_FLAG(flag) \
+  G_STMT_START { } G_STMT_END
+
+#endif /* COGL_ENABLE_DEBUG */
 
 G_END_DECLS
 
index ad6c7ce..6f69d06 100644 (file)
@@ -27,6 +27,7 @@
 #include "cogl-handle.h"
 #include "cogl-matrix-stack.h"
 #include "cogl-clip-state.h"
+#include "cogl-journal-private.h"
 
 typedef enum _CoglFramebufferType {
   COGL_FRAMEBUFFER_TYPE_ONSCREEN,
@@ -57,6 +58,31 @@ struct _CoglFramebuffer
   int                 blue_bits;
   int                 green_bits;
   int                 alpha_bits;
+
+  /* We journal the textured rectangles we want to submit to OpenGL so
+   * we have an oppertunity to batch them together into less draw
+   * calls. */
+  CoglJournal        *journal;
+
+  /* The scene of a given framebuffer may depend on images in other
+   * framebuffers... */
+  GList              *deps;
+
+  /* As part of an optimization for reading-back single pixels from a
+   * framebuffer in some simple cases where the geometry is still
+   * available in the journal we need to track the bounds of the last
+   * region cleared, its color and we need to track when something
+   * does in fact draw to that region so it is no longer clear.
+   */
+  float               clear_color_red;
+  float               clear_color_green;
+  float               clear_color_blue;
+  float               clear_color_alpha;
+  int                 clear_clip_x0;
+  int                 clear_clip_y0;
+  int                 clear_clip_x1;
+  int                 clear_clip_y1;
+  gboolean            clear_clip_dirty;
 };
 
 #define COGL_FRAMEBUFFER(X) ((CoglFramebuffer *)(X))
@@ -87,6 +113,29 @@ typedef struct _CoglOnscreen
 void
 _cogl_framebuffer_state_init (void);
 
+void
+_cogl_clear4f (unsigned long buffers,
+               float red,
+               float green,
+               float blue,
+               float alpha);
+
+void
+_cogl_framebuffer_clear (CoglFramebuffer *framebuffer,
+                         unsigned long buffers,
+                         const CoglColor *color);
+
+void
+_cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
+                           unsigned long buffers,
+                           float red,
+                           float green,
+                           float blue,
+                           float alpha);
+
+void
+_cogl_framebuffer_dirty (CoglFramebuffer *framebuffer);
+
 int
 _cogl_framebuffer_get_width (CoglFramebuffer *framebuffer);
 
@@ -96,6 +145,32 @@ _cogl_framebuffer_get_height (CoglFramebuffer *framebuffer);
 CoglClipState *
 _cogl_framebuffer_get_clip_state (CoglFramebuffer *framebuffer);
 
+/*
+ * _cogl_framebuffer_get_clip_stack:
+ * @framebuffer: A #CoglFramebuffer
+ *
+ * Gets a pointer to the current clip stack. This can be used to later
+ * return to the same clip stack state with
+ * _cogl_framebuffer_set_clip_stack(). A reference is not taken on the
+ * stack so if you want to keep it you should call
+ * _cogl_clip_stack_ref().
+ *
+ * Return value: a pointer to the @framebuffer clip stack.
+ */
+CoglClipStack *
+_cogl_framebuffer_get_clip_stack (CoglFramebuffer *framebuffer);
+
+/*
+ * _cogl_framebuffer_set_clip_stack:
+ * @framebuffer: A #CoglFramebuffer
+ * @stack: a pointer to the replacement clip stack
+ *
+ * Replaces the @framebuffer clip stack with @stack.
+ */
+void
+_cogl_framebuffer_set_clip_stack (CoglFramebuffer *framebuffer,
+                                  CoglClipStack *stack);
+
 void
 _cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer,
                                 int x,
@@ -124,6 +199,30 @@ _cogl_framebuffer_get_modelview_stack (CoglFramebuffer *framebuffer);
 CoglMatrixStack *
 _cogl_framebuffer_get_projection_stack (CoglFramebuffer *framebuffer);
 
+void
+_cogl_framebuffer_add_dependency (CoglFramebuffer *framebuffer,
+                                  CoglFramebuffer *dependency);
+
+void
+_cogl_framebuffer_remove_all_dependencies (CoglFramebuffer *framebuffer);
+
+void
+_cogl_framebuffer_flush_journal (CoglFramebuffer *framebuffer);
+
+void
+_cogl_framebuffer_flush_dependency_journals (CoglFramebuffer *framebuffer);
+
+void
+_cogl_framebuffer_swap_notify (CoglFramebuffer *framebuffer);
+
+gboolean
+_cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer,
+                                       int x,
+                                       int y,
+                                       CoglReadPixelsFlags source,
+                                       CoglPixelFormat format,
+                                       guint8 *pixel);
+
 typedef enum _CoglFramebufferFlushFlags
 {
   /* XXX: When using this, that imples you are going to manually load the
index 48f2a92..23b8511 100644 (file)
@@ -139,6 +139,8 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
                         int width,
                         int height)
 {
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
   framebuffer->type             = type;
   framebuffer->width            = width;
   framebuffer->height           = height;
@@ -155,11 +157,52 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
 
   /* Initialise the clip stack */
   _cogl_clip_state_init (&framebuffer->clip_state);
+
+  framebuffer->journal = _cogl_journal_new ();
+
+  /* Ensure we know the framebuffer->clear_color* members can't be
+   * referenced for our fast-path read-pixel optimization (see
+   * _cogl_journal_try_read_pixel()) until some region of the
+   * framebuffer is initialized.
+   */
+  framebuffer->clear_clip_dirty = TRUE;
+
+  /* XXX: We have to maintain a central list of all framebuffers
+   * because at times we need to be able to flush all known journals.
+   *
+   * Examples where we need to flush all journals are:
+   * - because journal entries can reference OpenGL texture
+   *   coordinates that may not survive texture-atlas reorganization
+   *   so we need the ability to flush those entries.
+   * - because although we generally advise against modifying
+   *   pipelines after construction we have to handle that possibility
+   *   and since pipelines may be referenced in journal entries we
+   *   need to be able to flush them before allowing the pipelines to
+   *   be changed.
+   *
+   * Note we don't maintain a list of journals and associate
+   * framebuffers with journals by e.g. having a journal->framebuffer
+   * reference since that would introduce a circular reference.
+   *
+   * Note: As a future change to try and remove the need to index all
+   * journals it might be possible to defer resolving of OpenGL
+   * texture coordinates for rectangle primitives until we come to
+   * flush a journal. This would mean for instance that a single
+   * rectangle entry in a journal could later be expanded into
+   * multiple quad primitives to handle sliced textures but would mean
+   * we don't have to worry about retaining references to OpenGL
+   * texture coordinates that may later become invalid.
+   */
+  ctx->framebuffers = g_list_prepend (ctx->framebuffers, framebuffer);
 }
 
 void
 _cogl_framebuffer_free (CoglFramebuffer *framebuffer)
 {
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  ctx->framebuffers = g_list_remove (ctx->framebuffers, framebuffer);
+
   _cogl_clip_state_destroy (&framebuffer->clip_state);
 
   cogl_object_unref (framebuffer->modelview_stack);
@@ -167,6 +210,242 @@ _cogl_framebuffer_free (CoglFramebuffer *framebuffer)
 
   cogl_object_unref (framebuffer->projection_stack);
   framebuffer->projection_stack = NULL;
+
+  cogl_object_unref (framebuffer->journal);
+}
+
+/* This version of cogl_clear can be used internally as an alternative
+ * to avoid flushing the journal or the framebuffer state. This is
+ * needed when doing operations that may be called whiling flushing
+ * the journal */
+void
+_cogl_clear4f (unsigned long buffers,
+               float red,
+               float green,
+               float blue,
+               float alpha)
+{
+  GLbitfield gl_buffers = 0;
+
+  if (buffers & COGL_BUFFER_BIT_COLOR)
+    {
+      GE( glClearColor (red, green, blue, alpha) );
+      gl_buffers |= GL_COLOR_BUFFER_BIT;
+    }
+
+  if (buffers & COGL_BUFFER_BIT_DEPTH)
+    gl_buffers |= GL_DEPTH_BUFFER_BIT;
+
+  if (buffers & COGL_BUFFER_BIT_STENCIL)
+    gl_buffers |= GL_STENCIL_BUFFER_BIT;
+
+  if (!gl_buffers)
+    {
+      static gboolean shown = FALSE;
+
+      if (!shown)
+        {
+         g_warning ("You should specify at least one auxiliary buffer "
+                     "when calling cogl_clear");
+        }
+
+      return;
+    }
+
+  GE (glClear (gl_buffers));
+}
+
+void
+_cogl_framebuffer_dirty (CoglFramebuffer *framebuffer)
+{
+  framebuffer->clear_clip_dirty = TRUE;
+}
+
+void
+_cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
+                           unsigned long buffers,
+                           float red,
+                           float green,
+                           float blue,
+                           float alpha)
+{
+  CoglClipStack *clip_stack = _cogl_framebuffer_get_clip_stack (framebuffer);
+  int scissor_x0;
+  int scissor_y0;
+  int scissor_x1;
+  int scissor_y1;
+
+  _cogl_clip_stack_get_bounds (clip_stack,
+                               &scissor_x0, &scissor_y0,
+                               &scissor_x1, &scissor_y1);
+
+  /* NB: the previous clear could have had an arbitrary clip.
+   * NB: everything for the last frame might still be in the journal
+   *     but we can't assume anything about how each entry was
+   *     clipped.
+   * NB: Clutter will scissor its pick renders which would mean all
+   *     journal entries have a common ClipStack entry, but without
+   *     a layering violation Cogl has to explicitly walk the journal
+   *     entries to determine if this is the case.
+   * NB: We have a software only read-pixel optimization in the
+   *     journal that determines the color at a given framebuffer
+   *     coordinate for simple scenes without rendering with the GPU.
+   *     When Clutter is hitting this fast-path we can expect to
+   *     receive calls to clear the framebuffer with an un-flushed
+   *     journal.
+   * NB: To fully support software based picking for Clutter we
+   *     need to be able to reliably detect when the contents of a
+   *     journal can be discarded and when we can skip the call to
+   *     glClear because it matches the previous clear request.
+   */
+
+  /* Note: we don't check for the stencil buffer being cleared here
+   * since there isn't any public cogl api to manipulate the stencil
+   * buffer.
+   *
+   * Note: we check for an exact clip match here because
+   * 1) a smaller clip could mean existing journal entries may
+   *    need to contribute to regions outside the new clear-clip
+   * 2) a larger clip would mean we need to issue a real
+   *    glClear and we only care about cases avoiding a
+   *    glClear.
+   *
+   * Note: Comparing without an epsilon is considered
+   * appropriate here.
+   */
+  if (buffers & COGL_BUFFER_BIT_COLOR &&
+      buffers & COGL_BUFFER_BIT_DEPTH &&
+      !framebuffer->clear_clip_dirty &&
+      framebuffer->clear_color_red == red &&
+      framebuffer->clear_color_green == green &&
+      framebuffer->clear_color_blue == blue &&
+      framebuffer->clear_color_alpha == alpha &&
+      scissor_x0 == framebuffer->clear_clip_x0 &&
+      scissor_y0 == framebuffer->clear_clip_y0 &&
+      scissor_x1 == framebuffer->clear_clip_x1 &&
+      scissor_y1 == framebuffer->clear_clip_y1)
+    {
+      /* NB: We only have to consider the clip state of journal
+       * entries if the current clear is clipped since otherwise we
+       * know every pixel of the framebuffer is affected by the clear
+       * and so all journal entries become redundant and can simply be
+       * discarded.
+       */
+      if (clip_stack)
+        {
+          /*
+           * Note: the function for checking the journal entries is
+           * quite strict. It avoids detailed checking of all entry
+           * clip_stacks by only checking the details of the first
+           * entry and then it only verifies that the remaining
+           * entries share the same clip_stack ancestry. This means
+           * it's possible for some false negatives here but that will
+           * just result in us falling back to a real clear.
+           */
+          if (_cogl_journal_all_entries_within_bounds (framebuffer->journal,
+                                                       scissor_x0, scissor_y0,
+                                                       scissor_x1, scissor_y1))
+            {
+              _cogl_journal_discard (framebuffer->journal);
+              goto cleared;
+            }
+        }
+      else
+        {
+          _cogl_journal_discard (framebuffer->journal);
+          goto cleared;
+        }
+    }
+
+  COGL_NOTE (DRAW, "Clear begin");
+
+  _cogl_framebuffer_flush_journal (framebuffer);
+
+  /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
+   * as the pipeline state) when flushing the clip stack, so should
+   * always be done first when preparing to draw. */
+  _cogl_framebuffer_flush_state (framebuffer, 0);
+
+  _cogl_clear4f (buffers, red, green, blue, alpha);;
+
+  /* This is a debugging variable used to visually display the quad
+   * batches from the journal. It is reset here to increase the
+   * chances of getting the same colours for each frame during an
+   * animation */
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_RECTANGLES)) &&
+      buffers & COGL_BUFFER_BIT_COLOR)
+    {
+      _COGL_GET_CONTEXT (ctxt, NO_RETVAL);
+      ctxt->journal_rectangles_color = 1;
+    }
+
+  COGL_NOTE (DRAW, "Clear end");
+
+cleared:
+
+  if (buffers & COGL_BUFFER_BIT_COLOR && buffers & COGL_BUFFER_BIT_DEPTH)
+    {
+      /* For our fast-path for reading back a single pixel of simple
+       * scenes where the whole frame is in the journal we need to
+       * track the cleared color of the framebuffer in case the point
+       * read doesn't intersect any of the journal rectangles. */
+      framebuffer->clear_clip_dirty = FALSE;
+      framebuffer->clear_color_red = red;
+      framebuffer->clear_color_green = green;
+      framebuffer->clear_color_blue = blue;
+      framebuffer->clear_color_alpha = alpha;
+
+      /* NB: A clear may be scissored so we need to track the extents
+       * that the clear is applicable too... */
+      if (clip_stack)
+        {
+          _cogl_clip_stack_get_bounds (clip_stack,
+                                       &framebuffer->clear_clip_x0,
+                                       &framebuffer->clear_clip_y0,
+                                       &framebuffer->clear_clip_x1,
+                                       &framebuffer->clear_clip_y1);
+        }
+      else
+        {
+          /* FIXME: set degenerate clip */
+        }
+    }
+  else
+    _cogl_framebuffer_dirty (framebuffer);
+}
+
+/* XXX: We'll need to consider if this API is a good approach for the
+ * planned, public, CoglFramebuffer API. A framebuffer may have
+ * multiple color buffers associated with it and the user may want to
+ * only clear a subset of those buffers. Flags aren't a great
+ * mechanism for handling this, but I don't think it would be very
+ * convenient if you had to explicitly enumerate the individual
+ * ancillary buffers to clear them.
+ *
+ * My current expectation is that we'll keep this flag based API but
+ * also add a way to enumerate the individual color buffers for
+ * clearing individually.
+ *
+ * Note: the 'buffers' and 'color' arguments were switched around on
+ * purpose compared to the original cogl_clear API since it was odd
+ * that you would be expected to specify a color before even
+ * necessarily choosing to clear the color buffer.
+ */
+void
+_cogl_framebuffer_clear (CoglFramebuffer *framebuffer,
+                         unsigned long buffers,
+                         const CoglColor *color)
+{
+  _cogl_framebuffer_clear4f (framebuffer, buffers,
+                             cogl_color_get_red_float (color),
+                             cogl_color_get_green_float (color),
+                             cogl_color_get_blue_float (color),
+                             cogl_color_get_alpha_float (color));
+}
+
+void
+_cogl_framebuffer_swap_notify (CoglFramebuffer *framebuffer)
+{
 }
 
 int
@@ -187,6 +466,23 @@ _cogl_framebuffer_get_clip_state (CoglFramebuffer *framebuffer)
   return &framebuffer->clip_state;
 }
 
+CoglClipStack *
+_cogl_framebuffer_get_clip_stack (CoglFramebuffer *framebuffer)
+{
+  CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
+
+  return _cogl_clip_state_get_stack (clip_state);
+}
+
+void
+_cogl_framebuffer_set_clip_stack (CoglFramebuffer *framebuffer,
+                                  CoglClipStack *stack)
+{
+  CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
+
+  _cogl_clip_state_set_stack (clip_state, stack);
+}
+
 void
 _cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer,
                                 int x,
@@ -202,7 +498,7 @@ _cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer,
       framebuffer->viewport_height == height)
     return;
 
-  _cogl_journal_flush ();
+  _cogl_framebuffer_flush_journal (framebuffer);
 
   framebuffer->viewport_x = x;
   framebuffer->viewport_y = y;
@@ -258,6 +554,51 @@ _cogl_framebuffer_get_projection_stack (CoglFramebuffer *framebuffer)
   return framebuffer->projection_stack;
 }
 
+void
+_cogl_framebuffer_add_dependency (CoglFramebuffer *framebuffer,
+                                  CoglFramebuffer *dependency)
+{
+  GList *l;
+
+  for (l = framebuffer->deps; l; l = l->next)
+    {
+      CoglFramebuffer *existing_dep = l->data;
+      if (existing_dep == dependency)
+        return;
+    }
+
+  /* TODO: generalize the primed-array type structure we e.g. use for
+   * cogl_object_set_user_data or for pipeline children as a way to
+   * avoid quite a lot of mid-scene micro allocations here... */
+  framebuffer->deps =
+    g_list_prepend (framebuffer->deps, cogl_object_ref (dependency));
+}
+
+void
+_cogl_framebuffer_remove_all_dependencies (CoglFramebuffer *framebuffer)
+{
+  GList *l;
+  for (l = framebuffer->deps; l; l = l->next)
+    cogl_object_unref (l->data);
+  g_list_free (framebuffer->deps);
+  framebuffer->deps = NULL;
+}
+
+void
+_cogl_framebuffer_flush_journal (CoglFramebuffer *framebuffer)
+{
+  _cogl_journal_flush (framebuffer->journal, framebuffer);
+}
+
+void
+_cogl_framebuffer_flush_dependency_journals (CoglFramebuffer *framebuffer)
+{
+  GList *l;
+  for (l = framebuffer->deps; l; l = l->next)
+    _cogl_framebuffer_flush_journal (l->data);
+  _cogl_framebuffer_remove_all_dependencies (framebuffer);
+}
+
 static inline void
 _cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer)
 {
@@ -356,11 +697,9 @@ try_creating_fbo (CoglOffscreen *offscreen,
       )
     return FALSE;
 
-  /* We are about to generate and bind a new fbo, so we pretend to change framebuffer
-   * state so that the old framebuffer will be rebound again before drawing.
-   * The framebuffer state can't be changed while their are active entries, so flush
-   * first. */
-  _cogl_journal_flush ();
+  /* We are about to generate and bind a new fbo, so we pretend to
+   * change framebuffer state so that the old framebuffer will be
+   * rebound again before drawing. */
   ctx->dirty_bound_framebuffer = 1;
 
   /* Generate framebuffer */
@@ -536,13 +875,17 @@ _cogl_offscreen_new_to_texture_full (CoglHandle texhandle,
 
   if (fbo_created)
     {
+      CoglOffscreen *ret;
+
       _cogl_framebuffer_init (COGL_FRAMEBUFFER (offscreen),
                               COGL_FRAMEBUFFER_TYPE_OFFSCREEN,
                               cogl_texture_get_format (texhandle),
                               data.level_width,
                               data.level_height);
 
-      return _cogl_offscreen_object_new (offscreen);
+      ret = _cogl_offscreen_object_new (offscreen);
+      _cogl_texture_associate_framebuffer (texhandle, COGL_FRAMEBUFFER (ret));
+      return ret;
     }
   else
     {
@@ -679,16 +1022,14 @@ _cogl_set_framebuffer_real (CoglFramebuffer *framebuffer)
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  cogl_flush ();
-
   entry = (CoglFramebuffer **)&ctx->framebuffer_stack->data;
 
   ctx->dirty_bound_framebuffer = 1;
   ctx->dirty_gl_viewport = 1;
 
-  if (framebuffer != COGL_INVALID_HANDLE)
+  if (framebuffer)
     cogl_object_ref (framebuffer);
-  if (*entry != COGL_INVALID_HANDLE)
+  if (*entry)
     cogl_object_unref (*entry);
 
   *entry = framebuffer;
@@ -705,10 +1046,23 @@ _cogl_set_framebuffer_real (CoglFramebuffer *framebuffer)
 void
 cogl_set_framebuffer (CoglFramebuffer *framebuffer)
 {
+  CoglFramebuffer *current;
+
   g_return_if_fail (_cogl_is_framebuffer (framebuffer));
 
-  if (_cogl_get_framebuffer () != framebuffer)
-    _cogl_set_framebuffer_real (framebuffer);
+  current = _cogl_get_framebuffer ();
+  if (current != framebuffer)
+    {
+      /* XXX: eventually we want to remove this implicit journal flush
+       * so we can log into the journal beyond framebuffer changes to
+       * support batching scenes that depend on the results of
+       * mid-scene renders to textures. Current will be NULL when the
+       * framebuffer stack is first created so we need to guard
+       * against that here */
+      if (current)
+        _cogl_framebuffer_flush_journal (current);
+      _cogl_set_framebuffer_real (framebuffer);
+    }
 }
 
 /* XXX: deprecated API */
@@ -741,10 +1095,11 @@ cogl_push_framebuffer (CoglFramebuffer *buffer)
   g_return_if_fail (_cogl_is_framebuffer (buffer));
   g_assert (ctx->framebuffer_stack);
 
-  cogl_flush ();
-
+  /* Copy the top of the stack so that when we call cogl_set_framebuffer
+     it will still know what the old framebuffer was */
   ctx->framebuffer_stack =
-    g_slist_prepend (ctx->framebuffer_stack, COGL_INVALID_HANDLE);
+    g_slist_prepend (ctx->framebuffer_stack,
+                     cogl_object_ref (_cogl_get_framebuffer ()));
 
   cogl_set_framebuffer (buffer);
 }
@@ -770,7 +1125,14 @@ cogl_pop_framebuffer (void)
   to_pop = ctx->framebuffer_stack->data;
   to_restore = ctx->framebuffer_stack->next->data;
 
-  cogl_flush ();
+  if (to_pop != to_restore)
+    {
+      /* XXX: eventually we want to remove this implicit journal flush
+       * so we can log into the journal beyond framebuffer changes to
+       * support batching scenes that depend on the results of
+       * mid-scene renders to textures. */
+      _cogl_framebuffer_flush_journal (to_pop);
+    }
 
   cogl_object_unref (to_pop);
   ctx->framebuffer_stack =
@@ -889,3 +1251,66 @@ _cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer)
   return framebuffer->alpha_bits;
 }
 
+gboolean
+_cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer,
+                                       int x,
+                                       int y,
+                                       CoglReadPixelsFlags source,
+                                       CoglPixelFormat format,
+                                       guint8 *pixel)
+{
+  gboolean found_intersection;
+
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FAST_READ_PIXEL)))
+    return FALSE;
+
+  if (source != COGL_READ_PIXELS_COLOR_BUFFER)
+    return FALSE;
+
+  if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE &&
+      format != COGL_PIXEL_FORMAT_RGBA_8888)
+    return FALSE;
+
+  if (!_cogl_journal_try_read_pixel (framebuffer->journal,
+                                     x, y, format, pixel,
+                                     &found_intersection))
+    return FALSE;
+
+  /* If we can't determine the color from the primitives in the
+   * journal then see if we can use the last recorded clear color
+   */
+
+  /* If _cogl_journal_try_read_pixel() failed even though there was an
+   * intersection of the given point with a primitive in the journal
+   * then we can't fallback to the framebuffer's last clear color...
+   * */
+  if (found_intersection)
+    return TRUE;
+
+  /* If the framebuffer has been rendered too since it was last
+   * cleared then we can't return the last known clear color. */
+  if (framebuffer->clear_clip_dirty)
+    return FALSE;
+
+  if (x >= framebuffer->clear_clip_x0 &&
+      x < framebuffer->clear_clip_x1 &&
+      y >= framebuffer->clear_clip_y0 &&
+      y < framebuffer->clear_clip_y1)
+    {
+
+      /* we currently only care about cases where the premultiplied or
+       * unpremultipled colors are equivalent... */
+      if (framebuffer->clear_color_alpha != 1.0)
+        return FALSE;
+
+      pixel[0] = framebuffer->clear_color_red * 255.0;
+      pixel[1] = framebuffer->clear_color_green * 255.0;
+      pixel[2] = framebuffer->clear_color_blue * 255.0;
+      pixel[3] = framebuffer->clear_color_alpha * 255.0;
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
index d39a145..2a85151 100644 (file)
@@ -89,7 +89,7 @@ cogl_index_array_allocate (CoglIndexArray *indices,
  * data.
  *
  * XXX: I think in the end it'll be that CoglIndices are to
- * CoglIndexArrays as CoglVertexAttributes are to CoglVertices. I.e
+ * CoglIndexArrays as CoglAttributes are to CoglVertices. I.e
  * a CoglIndexArray is a lite subclass of CoglBuffer that simply
  * implies that the buffer will later be bound as indices but doesn't
  * track more detailed meta data. CoglIndices build on a
@@ -98,7 +98,7 @@ cogl_index_array_allocate (CoglIndexArray *indices,
  *
  * XXX: The double plurel form that "Indices" "Array" implies could be
  * a bit confusing. Also to be a bit more consistent with
- * CoglVertexArray vs CoglVertexAttribute it might be best to rename so
+ * CoglVertexArray vs CoglAttribute it might be best to rename so
  * we have CoglIndexArray vs CoglIndices? maybe even
  * CoglIndexRange :-/ ?
  *
index a34a526..44a4af8 100644 (file)
 #include "cogl-handle.h"
 #include "cogl-clip-stack.h"
 
+typedef struct _CoglJournal
+{
+  CoglObject _parent;
+
+  GArray *entries;
+  GArray *vertices;
+  size_t needed_vbo_len;
+
+  int fast_read_pixel_count;
+
+} CoglJournal;
+
 /* To improve batching of geometry when submitting vertices to OpenGL we
  * log the texture rectangles we want to draw to a journal, so when we
  * later flush the journal we aim to batch data, and gl draw calls. */
@@ -43,8 +55,12 @@ typedef struct _CoglJournalEntry
    * later. */
 } CoglJournalEntry;
 
+CoglJournal *
+_cogl_journal_new (void);
+
 void
-_cogl_journal_log_quad (const float  *position,
+_cogl_journal_log_quad (CoglJournal  *journal,
+                        const float  *position,
                         CoglPipeline *pipeline,
                         int           n_layers,
                         CoglHandle    layer0_override_texture,
@@ -52,6 +68,25 @@ _cogl_journal_log_quad (const float  *position,
                         unsigned int  tex_coords_len);
 
 void
-_cogl_journal_flush (void);
+_cogl_journal_flush (CoglJournal *journal,
+                     CoglFramebuffer *framebuffer);
+
+void
+_cogl_journal_discard (CoglJournal *journal);
+
+gboolean
+_cogl_journal_all_entries_within_bounds (CoglJournal *journal,
+                                         float clip_x0,
+                                         float clip_y0,
+                                         float clip_x1,
+                                         float clip_y1);
+
+gboolean
+_cogl_journal_try_read_pixel (CoglJournal *journal,
+                              int x,
+                              int y,
+                              CoglPixelFormat format,
+                              guint8 *pixel,
+                              gboolean *found_intersection);
 
 #endif /* __COGL_JOURNAL_PRIVATE_H */
index 8256788..7ec25cd 100644 (file)
@@ -36,7 +36,8 @@
 #include "cogl-vertex-buffer-private.h"
 #include "cogl-framebuffer-private.h"
 #include "cogl-profile.h"
-#include "cogl-vertex-attribute-private.h"
+#include "cogl-attribute-private.h"
+#include "cogl-point-in-poly-private.h"
 
 #include <string.h>
 #include <gmodule.h>
@@ -74,8 +75,8 @@
  *
  * So for a given number of layers this gets the stride in 32bit words:
  */
-#define SW_TRANSFORM      (!(cogl_debug_flags & \
-                             COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
+#define SW_TRANSFORM      (!(COGL_DEBUG_ENABLED \
+                             (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
 #define POS_STRIDE        (SW_TRANSFORM ? 3 : 2) /* number of 32bit words */
 #define N_POS_COMPONENTS  POS_STRIDE
 #define COLOR_STRIDE      1 /* number of 32bit words */
@@ -92,6 +93,8 @@
 
 typedef struct _CoglJournalFlushState
 {
+  CoglJournal         *journal;
+
   CoglVertexArray     *vertex_array;
   GArray              *attributes;
   int                  current_attribute;
@@ -115,6 +118,31 @@ typedef void (*CoglJournalBatchCallback) (CoglJournalEntry *start,
 typedef gboolean (*CoglJournalBatchTest) (CoglJournalEntry *entry0,
                                           CoglJournalEntry *entry1);
 
+static void _cogl_journal_free (CoglJournal *journal);
+
+COGL_OBJECT_DEFINE (Journal, journal);
+
+static void
+_cogl_journal_free (CoglJournal *journal)
+{
+  if (journal->entries)
+    g_array_free (journal->entries, TRUE);
+  if (journal->vertices)
+    g_array_free (journal->vertices, TRUE);
+  g_slice_free (CoglJournal, journal);
+}
+
+CoglJournal *
+_cogl_journal_new (void)
+{
+  CoglJournal *journal = g_slice_new0 (CoglJournal);
+
+  journal->entries = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry));
+  journal->vertices = g_array_new (FALSE, FALSE, sizeof (float));
+
+  return _cogl_journal_object_new (journal);
+}
+
 static void
 _cogl_journal_dump_logged_quad (guint8 *data, int n_layers)
 {
@@ -163,8 +191,8 @@ _cogl_journal_dump_quad_vertices (guint8 *data, int n_layers)
       guint8 *c = data + (POS_STRIDE * 4) + (i * stride * 4);
       int j;
 
-      if (G_UNLIKELY (cogl_debug_flags &
-                      COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
+      if (G_UNLIKELY (COGL_DEBUG_ENABLED
+                      (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
         g_print ("v%d: x = %f, y = %f, rgba=0x%02X%02X%02X%02X",
                  i, v[0], v[1], c[0], c[1], c[2], c[3]);
       else
@@ -232,7 +260,12 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
                                            void             *data)
 {
   CoglJournalFlushState *state = data;
-  CoglVertexAttribute **attributes;
+  CoglAttribute **attributes;
+  CoglDrawFlags draw_flags = (COGL_DRAW_SKIP_JOURNAL_FLUSH |
+                              COGL_DRAW_SKIP_PIPELINE_VALIDATION |
+                              COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
+                              COGL_DRAW_SKIP_LEGACY_STATE);
+
   COGL_STATIC_TIMER (time_flush_modelview_and_entries,
                      "flush: pipeline+entries", /* parent */
                      "flush: modelview+entries",
@@ -243,10 +276,10 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
 
   COGL_TIMER_START (_cogl_uprof_context, time_flush_modelview_and_entries);
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
     g_print ("BATCHING:     modelview batch len = %d\n", batch_len);
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
     {
       _cogl_matrix_stack_set (state->modelview_stack,
                               &batch_start->model_view);
@@ -254,30 +287,37 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
                                       COGL_MATRIX_MODELVIEW);
     }
 
-  attributes = (CoglVertexAttribute **)state->attributes->data;
+  attributes = (CoglAttribute **)state->attributes->data;
   cogl_push_source (state->source);
 
+  if (!_cogl_pipeline_get_real_blend_enabled (state->source))
+    draw_flags |= COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE;
+
 #ifdef HAVE_COGL_GL
 
   /* XXX: it's rather evil that we sneak in the GL_QUADS enum here... */
-  _cogl_draw_vertex_attributes_array (GL_QUADS,
-                                      state->current_vertex, batch_len * 4,
-                                      attributes);
+  _cogl_draw_attributes_array (GL_QUADS,
+                               state->current_vertex, batch_len * 4,
+                               attributes,
+                               draw_flags);
 
 #else /* HAVE_COGL_GL */
   if (batch_len > 1)
     {
-      _cogl_draw_indexed_vertex_attributes_array (COGL_VERTICES_MODE_TRIANGLES,
-                                                  state->current_vertex * 6 / 4,
-                                                  batch_len * 6,
-                                                  state->indices,
-                                                  attributes);
+      _cogl_draw_indexed_attributes_array (COGL_VERTICES_MODE_TRIANGLES,
+                                           state->current_vertex * 6 / 4,
+                                           batch_len * 6,
+                                           state->indices,
+                                           attributes,
+                                           draw_flags);
+
     }
   else
     {
-      _cogl_draw_vertex_attributes_array (COGL_VERTICES_MODE_TRIANGLE_FAN,
-                                          state->current_vertex, 4,
-                                          attributes);
+      _cogl_draw_attributes_array (COGL_VERTICES_MODE_TRIANGLE_FAN,
+                                   state->current_vertex, 4,
+                                   attributes,
+                                   draw_flags);
     }
 #endif
 
@@ -287,12 +327,12 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
    * issues, visually seeing what is batched and debugging blending
    * issues, plus it looks quite cool.
    */
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_RECTANGLES))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_RECTANGLES)))
     {
       static CoglPipeline *outline = NULL;
       guint8 color_intensity;
       int i;
-      CoglVertexAttribute *loop_attributes[2];
+      CoglAttribute *loop_attributes[2];
 
       _COGL_GET_CONTEXT (ctxt, NO_RETVAL);
 
@@ -320,9 +360,10 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
       loop_attributes[0] = attributes[0]; /* we just want the position */
       loop_attributes[1] = NULL;
       for (i = 0; i < batch_len; i++)
-        _cogl_draw_vertex_attributes_array (COGL_VERTICES_MODE_LINE_LOOP,
-                                            4 * i + state->current_vertex, 4,
-                                            loop_attributes);
+        _cogl_draw_attributes_array (COGL_VERTICES_MODE_LINE_LOOP,
+                                     4 * i + state->current_vertex, 4,
+                                     loop_attributes,
+                                     draw_flags);
 
       /* Go to the next color */
       do
@@ -380,14 +421,14 @@ _cogl_journal_flush_pipeline_and_entries (CoglJournalEntry *batch_start,
 
   COGL_TIMER_START (_cogl_uprof_context, time_flush_pipeline_entries);
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
     g_print ("BATCHING:    pipeline batch len = %d\n", batch_len);
 
   state->source = batch_start->pipeline;
 
   /* If we haven't transformed the quads in software then we need to also break
    * up batches according to changes in the modelview matrix... */
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
     {
       batch_and_call (batch_start,
                       batch_len,
@@ -442,15 +483,14 @@ _cogl_journal_flush_texcoord_vbo_offsets_and_entries (
   /* NB: attributes 0 and 1 are position and color */
 
   for (i = 2; i < state->attributes->len; i++)
-    cogl_object_unref (g_array_index (state->attributes,
-                                      CoglVertexAttribute *, i));
+    cogl_object_unref (g_array_index (state->attributes, CoglAttribute *, i));
 
   g_array_set_size (state->attributes, batch_start->n_layers + 2);
 
   for (i = 0; i < batch_start->n_layers; i++)
     {
-      CoglVertexAttribute **attribute_entry =
-        &g_array_index (state->attributes, CoglVertexAttribute *, i + 2);
+      CoglAttribute **attribute_entry =
+        &g_array_index (state->attributes, CoglAttribute *, i + 2);
       const char *names[] = {
           "cogl_tex_coord0_in",
           "cogl_tex_coord1_in",
@@ -478,14 +518,14 @@ _cogl_journal_flush_texcoord_vbo_offsets_and_entries (
       /* XXX: it may be worth having some form of static initializer for
        * attributes... */
       *attribute_entry =
-        cogl_vertex_attribute_new (state->vertex_array,
-                                   name,
-                                   state->stride,
-                                   state->array_offset +
-                                      (POS_STRIDE + COLOR_STRIDE) * 4 +
-                                      TEX_STRIDE * 4 * i,
-                                   2,
-                                   COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
+        cogl_attribute_new (state->vertex_array,
+                            name,
+                            state->stride,
+                            state->array_offset +
+                            (POS_STRIDE + COLOR_STRIDE) * 4 +
+                            TEX_STRIDE * 4 * i,
+                            2,
+                            COGL_ATTRIBUTE_TYPE_FLOAT);
 
       if (i >= 8)
         g_free (name);
@@ -518,7 +558,7 @@ _cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
   CoglJournalFlushState   *state = data;
   gsize                    stride;
   int                      i;
-  CoglVertexAttribute    **attribute_entry;
+  CoglAttribute          **attribute_entry;
   COGL_STATIC_TIMER (time_flush_vbo_texcoord_pipeline_entries,
                      "flush: clip+vbo+texcoords+pipeline+entries", /* parent */
                      "flush: vbo+texcoords+pipeline+entries",
@@ -531,7 +571,7 @@ _cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
   COGL_TIMER_START (_cogl_uprof_context,
                     time_flush_vbo_texcoord_pipeline_entries);
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
     g_print ("BATCHING:   vbo offset batch len = %d\n", batch_len);
 
   /* XXX NB:
@@ -548,43 +588,40 @@ _cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
   state->stride = stride;
 
   for (i = 0; i < state->attributes->len; i++)
-    cogl_object_unref (g_array_index (state->attributes,
-                                      CoglVertexAttribute *, i));
+    cogl_object_unref (g_array_index (state->attributes, CoglAttribute *, i));
 
   g_array_set_size (state->attributes, 2);
 
-  attribute_entry =
-    &g_array_index (state->attributes, CoglVertexAttribute *, 0);
-  *attribute_entry =
-    cogl_vertex_attribute_new (state->vertex_array,
-                               "cogl_position_in",
-                               stride,
-                               state->array_offset,
-                               N_POS_COMPONENTS,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
-
-  attribute_entry =
-    &g_array_index (state->attributes, CoglVertexAttribute *, 1);
+  attribute_entry = &g_array_index (state->attributes, CoglAttribute *, 0);
+  *attribute_entry = cogl_attribute_new (state->vertex_array,
+                                         "cogl_position_in",
+                                         stride,
+                                         state->array_offset,
+                                         N_POS_COMPONENTS,
+                                         COGL_ATTRIBUTE_TYPE_FLOAT);
+
+  attribute_entry = &g_array_index (state->attributes, CoglAttribute *, 1);
   *attribute_entry =
-    cogl_vertex_attribute_new (state->vertex_array,
-                               "cogl_color_in",
-                               stride,
-                               state->array_offset + (POS_STRIDE * 4),
-                               4,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
+    cogl_attribute_new (state->vertex_array,
+                        "cogl_color_in",
+                        stride,
+                        state->array_offset + (POS_STRIDE * 4),
+                        4,
+                        COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
 
 #ifndef HAVE_COGL_GL
   state->indices = cogl_get_rectangle_indices (batch_len);
 #endif
 
-  /* We only create new VertexAttributes when the stride within the
-   * VertexArray changes. (due to a change in the number of pipeline layers)
-   * While the stride remains constant we walk forward through the above
-   * VertexArray using a vertex offset passed to cogl_draw_vertex_attributes
+  /* We only create new Attributes when the stride within the
+   * VertexArray changes. (due to a change in the number of pipeline
+   * layers) While the stride remains constant we walk forward through
+   * the above VertexArray using a vertex offset passed to
+   * cogl_draw_attributes
    */
   state->current_vertex = 0;
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_JOURNAL)))
     {
       guint8 *verts;
 
@@ -610,7 +647,7 @@ _cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
 
   /* progress forward through the VBO containing all our vertices */
   state->array_offset += (stride * 4 * batch_len);
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_JOURNAL)))
     g_print ("new vbo offset = %lu\n", (unsigned long)state->array_offset);
 
   COGL_TIMER_STOP (_cogl_uprof_context,
@@ -653,7 +690,7 @@ _cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start,
   COGL_TIMER_START (_cogl_uprof_context,
                     time_flush_clip_stack_pipeline_entries);
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
     g_print ("BATCHING:  clip stack batch len = %d\n", batch_len);
 
   _cogl_clip_stack_flush (batch_start->clip_stack);
@@ -664,7 +701,7 @@ _cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start,
    * no further model transform is applied by loading the identity
    * matrix here. We need to do this after flushing the clip stack
    * because the clip stack flushing code can modify the matrix */
-  if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
+  if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))))
     {
       _cogl_matrix_stack_load_identity (state->modelview_stack);
       _cogl_matrix_stack_flush_to_gl (state->modelview_stack,
@@ -780,11 +817,184 @@ typedef struct
   float x_2, y_2;
 } ClipBounds;
 
+static gboolean
+can_software_clip_entry (CoglJournalEntry *journal_entry,
+                         CoglJournalEntry *prev_journal_entry,
+                         CoglClipStack *clip_stack,
+                         ClipBounds *clip_bounds_out)
+{
+  CoglPipeline *pipeline = journal_entry->pipeline;
+  CoglClipStack *clip_entry;
+  int layer_num;
+
+  clip_bounds_out->x_1 = -G_MAXFLOAT;
+  clip_bounds_out->y_1 = -G_MAXFLOAT;
+  clip_bounds_out->x_2 = G_MAXFLOAT;
+  clip_bounds_out->y_2 = G_MAXFLOAT;
+
+  /* Check the pipeline is usable. We can short-cut here for
+     entries using the same pipeline as the previous entry */
+  if (prev_journal_entry == NULL || pipeline != prev_journal_entry->pipeline)
+    {
+      /* If the pipeline has a user program then we can't reliably modify
+         the texture coordinates */
+      if (cogl_pipeline_get_user_program (pipeline))
+        return FALSE;
+
+      /* If any of the pipeline layers have a texture matrix then we can't
+         reliably modify the texture coordinates */
+      for (layer_num = cogl_pipeline_get_n_layers (pipeline) - 1;
+           layer_num >= 0;
+           layer_num--)
+        if (_cogl_pipeline_layer_has_user_matrix (pipeline, layer_num))
+          return FALSE;
+    }
+
+  /* Now we need to verify that each clip entry's matrix is just a
+     translation of the journal entry's modelview matrix. We can
+     also work out the bounds of the clip in modelview space using
+     this translation */
+  for (clip_entry = clip_stack; clip_entry; clip_entry = clip_entry->parent)
+    {
+      float rect_x1, rect_y1, rect_x2, rect_y2;
+      CoglClipStackRect *clip_rect;
+      float tx, ty;
+
+      clip_rect = (CoglClipStackRect *) clip_entry;
+
+      if (!calculate_translation (&clip_rect->matrix,
+                                  &journal_entry->model_view,
+                                  &tx, &ty))
+        return FALSE;
+
+      if (clip_rect->x0 < clip_rect->x1)
+        {
+          rect_x1 = clip_rect->x0;
+          rect_x2 = clip_rect->x1;
+        }
+      else
+        {
+          rect_x1 = clip_rect->x1;
+          rect_x2 = clip_rect->x0;
+        }
+      if (clip_rect->y0 < clip_rect->y1)
+        {
+          rect_y1 = clip_rect->y0;
+          rect_y2 = clip_rect->y1;
+        }
+      else
+        {
+          rect_y1 = clip_rect->y1;
+          rect_y2 = clip_rect->y0;
+        }
+
+      clip_bounds_out->x_1 = MAX (clip_bounds_out->x_1, rect_x1 - tx);
+      clip_bounds_out->y_1 = MAX (clip_bounds_out->y_1, rect_y1 - ty);
+      clip_bounds_out->x_2 = MIN (clip_bounds_out->x_2, rect_x2 - tx);
+      clip_bounds_out->y_2 = MIN (clip_bounds_out->y_2, rect_y2 - ty);
+    }
+
+  return TRUE;
+}
+
+static void
+software_clip_entry (CoglJournalEntry *journal_entry,
+                     float *verts,
+                     ClipBounds *clip_bounds)
+{
+  size_t stride =
+    GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (journal_entry->n_layers);
+  float rx1, ry1, rx2, ry2;
+  float vx1, vy1, vx2, vy2;
+  int layer_num;
+
+  /* Remove the clip on the entry */
+  _cogl_clip_stack_unref (journal_entry->clip_stack);
+  journal_entry->clip_stack = NULL;
+
+  vx1 = verts[0];
+  vy1 = verts[1];
+  vx2 = verts[stride];
+  vy2 = verts[stride + 1];
+
+  if (vx1 < vx2)
+    {
+      rx1 = vx1;
+      rx2 = vx2;
+    }
+  else
+    {
+      rx1 = vx2;
+      rx2 = vx1;
+    }
+  if (vy1 < vy2)
+    {
+      ry1 = vy1;
+      ry2 = vy2;
+    }
+  else
+    {
+      ry1 = vy2;
+      ry2 = vy1;
+    }
+
+  rx1 = CLAMP (rx1, clip_bounds->x_1, clip_bounds->x_2);
+  ry1 = CLAMP (ry1, clip_bounds->y_1, clip_bounds->y_2);
+  rx2 = CLAMP (rx2, clip_bounds->x_1, clip_bounds->x_2);
+  ry2 = CLAMP (ry2, clip_bounds->y_1, clip_bounds->y_2);
+
+  /* Check if the rectangle intersects the clip at all */
+  if (rx1 == rx2 || ry1 == ry2)
+    /* Will set all of the vertex data to 0 in the hope that this
+       will create a degenerate rectangle and the GL driver will
+       be able to clip it quickly */
+    memset (verts, 0, sizeof (float) * stride * 2);
+  else
+    {
+      if (vx1 > vx2)
+        {
+          float t = rx1;
+          rx1 = rx2;
+          rx2 = t;
+        }
+      if (vy1 > vy2)
+        {
+          float t = ry1;
+          ry1 = ry2;
+          ry2 = t;
+        }
+
+      verts[0] = rx1;
+      verts[1] = ry1;
+      verts[stride] = rx2;
+      verts[stride + 1] = ry2;
+
+      /* Convert the rectangle coordinates to a fraction of the original
+         rectangle */
+      rx1 = (rx1 - vx1) / (vx2 - vx1);
+      ry1 = (ry1 - vy1) / (vy2 - vy1);
+      rx2 = (rx2 - vx1) / (vx2 - vx1);
+      ry2 = (ry2 - vy1) / (vy2 - vy1);
+
+      for (layer_num = 0; layer_num < journal_entry->n_layers; layer_num++)
+        {
+          float *t = verts + 2 + 2 * layer_num;
+          float tx1 = t[0], ty1 = t[1];
+          float tx2 = t[stride], ty2 = t[stride + 1];
+          t[0] = rx1 * (tx2 - tx1) + tx1;
+          t[1] = ry1 * (ty2 - ty1) + ty1;
+          t[stride] = rx2 * (tx2 - tx1) + tx1;
+          t[stride + 1] = ry2 * (ty2 - ty1) + ty1;
+        }
+    }
+}
+
 static void
-check_software_clip_for_batch (CoglJournalEntry      *batch_start,
-                               int                    batch_len,
-                               CoglJournalFlushState *state)
+maybe_software_clip_entries (CoglJournalEntry      *batch_start,
+                             int                    batch_len,
+                             CoglJournalFlushState *state)
 {
+  CoglJournal *journal = state->journal;
   CoglClipStack *clip_stack, *clip_entry;
   int entry_num;
 
@@ -823,190 +1033,46 @@ check_software_clip_for_batch (CoglJournalEntry      *batch_start,
   for (entry_num = 0; entry_num < batch_len; entry_num++)
     {
       CoglJournalEntry *journal_entry = batch_start + entry_num;
-      CoglPipeline *pipeline = journal_entry->pipeline;
+      CoglJournalEntry *prev_journal_entry =
+        entry_num ? batch_start + (entry_num - 1) : NULL;
       ClipBounds *clip_bounds = &g_array_index (ctx->journal_clip_bounds,
                                                 ClipBounds, entry_num);
-      int layer_num;
-
-      clip_bounds->x_1 = -G_MAXFLOAT;
-      clip_bounds->y_1 = -G_MAXFLOAT;
-      clip_bounds->x_2 = G_MAXFLOAT;
-      clip_bounds->y_2 = G_MAXFLOAT;
-
-      /* Check the pipeline is usable. We can short-cut here for
-         entries using the same pipeline as the previous entry */
-      if (entry_num == 0 || pipeline != batch_start[entry_num - 1].pipeline)
-        {
-          /* If the pipeline has a user program then we can't reliably modify
-             the texture coordinates */
-          if (cogl_pipeline_get_user_program (pipeline))
-            return;
-
-          /* If any of the pipeline layers have a texture matrix then we can't
-             reliably modify the texture coordinates */
-          for (layer_num = cogl_pipeline_get_n_layers (pipeline) - 1;
-               layer_num >= 0;
-               layer_num--)
-            if (_cogl_pipeline_layer_has_user_matrix (pipeline, layer_num))
-              return;
-        }
-
-      /* Now we need to verify that each clip entry's matrix is just a
-         translation of the journal entry's modelview matrix. We can
-         also work out the bounds of the clip in modelview space using
-         this translation */
-      for (clip_entry = clip_stack; clip_entry; clip_entry = clip_entry->parent)
-        {
-          float rect_x1, rect_y1, rect_x2, rect_y2;
-          CoglClipStackRect *clip_rect;
-          float tx, ty;
-
-          clip_rect = (CoglClipStackRect *) clip_entry;
 
-          if (!calculate_translation (&clip_rect->matrix,
-                                      &journal_entry->model_view,
-                                      &tx, &ty))
-            return;
-
-          if (clip_rect->x0 < clip_rect->x1)
-            {
-              rect_x1 = clip_rect->x0;
-              rect_x2 = clip_rect->x1;
-            }
-          else
-            {
-              rect_x1 = clip_rect->x1;
-              rect_x2 = clip_rect->x0;
-            }
-          if (clip_rect->y0 < clip_rect->y1)
-            {
-              rect_y1 = clip_rect->y0;
-              rect_y2 = clip_rect->y1;
-            }
-          else
-            {
-              rect_y1 = clip_rect->y1;
-              rect_y2 = clip_rect->y0;
-            }
-
-          clip_bounds->x_1 = MAX (clip_bounds->x_1, rect_x1 - tx);
-          clip_bounds->y_1 = MAX (clip_bounds->y_1, rect_y1 - ty);
-          clip_bounds->x_2 = MIN (clip_bounds->x_2, rect_x2 - tx);
-          clip_bounds->y_2 = MIN (clip_bounds->y_2, rect_y2 - ty);
-        }
+      if (!can_software_clip_entry (journal_entry, prev_journal_entry,
+                                    clip_stack,
+                                    clip_bounds))
+        return;
     }
 
   /* If we make it here then we know we can software clip the entire batch */
 
+  COGL_NOTE (CLIPPING, "Software clipping a batch of length %i", batch_len);
+
   for (entry_num = 0; entry_num < batch_len; entry_num++)
     {
       CoglJournalEntry *journal_entry = batch_start + entry_num;
-      float *verts = &g_array_index (ctx->logged_vertices, float,
+      float *verts = &g_array_index (journal->vertices, float,
                                      journal_entry->array_offset + 1);
       ClipBounds *clip_bounds = &g_array_index (ctx->journal_clip_bounds,
                                                 ClipBounds, entry_num);
 
-      size_t stride =
-        GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (journal_entry->n_layers);
-      float rx1, ry1, rx2, ry2;
-      float vx1, vy1, vx2, vy2;
-      int layer_num;
-
-      /* Remove the clip on the entry */
-      _cogl_clip_stack_unref (journal_entry->clip_stack);
-      journal_entry->clip_stack = NULL;
-
-      vx1 = verts[0];
-      vy1 = verts[1];
-      vx2 = verts[stride];
-      vy2 = verts[stride + 1];
-
-      if (vx1 < vx2)
-        {
-          rx1 = vx1;
-          rx2 = vx2;
-        }
-      else
-        {
-          rx1 = vx2;
-          rx2 = vx1;
-        }
-      if (vy1 < vy2)
-        {
-          ry1 = vy1;
-          ry2 = vy2;
-        }
-      else
-        {
-          ry1 = vy2;
-          ry2 = vy1;
-        }
-
-      rx1 = CLAMP (rx1, clip_bounds->x_1, clip_bounds->x_2);
-      ry1 = CLAMP (ry1, clip_bounds->y_1, clip_bounds->y_2);
-      rx2 = CLAMP (rx2, clip_bounds->x_1, clip_bounds->x_2);
-      ry2 = CLAMP (ry2, clip_bounds->y_1, clip_bounds->y_2);
-
-      /* Check if the rectangle intersects the clip at all */
-      if (rx1 == rx2 || ry1 == ry2)
-        /* Will set all of the vertex data to 0 in the hope that this
-           will create a degenerate rectangle and the GL driver will
-           be able to clip it quickly */
-        memset (verts, 0, sizeof (float) * stride * 2);
-      else
-        {
-          if (vx1 > vx2)
-            {
-              float t = rx1;
-              rx1 = rx2;
-              rx2 = t;
-            }
-          if (vy1 > vy2)
-            {
-              float t = ry1;
-              ry1 = ry2;
-              ry2 = t;
-            }
-
-          verts[0] = rx1;
-          verts[1] = ry1;
-          verts[stride] = rx2;
-          verts[stride + 1] = ry2;
-
-          /* Convert the rectangle coordinates to a fraction of the original
-             rectangle */
-          rx1 = (rx1 - vx1) / (vx2 - vx1);
-          ry1 = (ry1 - vy1) / (vy2 - vy1);
-          rx2 = (rx2 - vx1) / (vx2 - vx1);
-          ry2 = (ry2 - vy1) / (vy2 - vy1);
-
-          for (layer_num = 0; layer_num < journal_entry->n_layers; layer_num++)
-            {
-              float *t = verts + 2 + 2 * layer_num;
-              float tx1 = t[0], ty1 = t[1];
-              float tx2 = t[stride], ty2 = t[stride + 1];
-              t[0] = rx1 * (tx2 - tx1) + tx1;
-              t[1] = ry1 * (ty2 - ty1) + ty1;
-              t[stride] = rx2 * (tx2 - tx1) + tx1;
-              t[stride + 1] = ry2 * (ty2 - ty1) + ty1;
-            }
-        }
+      software_clip_entry (journal_entry, verts, clip_bounds);
     }
 
   return;
 }
 
 static void
-_cogl_journal_check_software_clip (CoglJournalEntry *batch_start,
-                                   int               batch_len,
-                                   void             *data)
+_cogl_journal_maybe_software_clip_entries (CoglJournalEntry *batch_start,
+                                           int               batch_len,
+                                           void             *data)
 {
   CoglJournalFlushState *state = data;
 
   COGL_STATIC_TIMER (time_check_software_clip,
                      "Journal Flush", /* parent */
-                     "flush: check software clip",
-                     "Time spent checking for software clip",
+                     "flush: software clipping",
+                     "Time spent software clipping",
                      0 /* no application private data */);
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@@ -1014,7 +1080,7 @@ _cogl_journal_check_software_clip (CoglJournalEntry *batch_start,
   COGL_TIMER_START (_cogl_uprof_context,
                     time_check_software_clip);
 
-  check_software_clip_for_batch (batch_start, batch_len, state);
+  maybe_software_clip_entries (batch_start, batch_len, state);
 
   COGL_TIMER_STOP (_cogl_uprof_context,
                    time_check_software_clip);
@@ -1045,8 +1111,7 @@ upload_vertices (const CoglJournalEntry *entries,
   buffer = COGL_BUFFER (array);
   cogl_buffer_set_update_hint (buffer, COGL_BUFFER_UPDATE_HINT_STATIC);
 
-  vout = cogl_buffer_map (buffer, COGL_BUFFER_ACCESS_WRITE,
-                          COGL_BUFFER_MAP_HINT_DISCARD);
+  vout = _cogl_buffer_map_for_fill_or_fallback (buffer);
   vin = &g_array_index (vertices, float, 0);
 
   /* Expand the number of vertices from 2 to 4 while uploading */
@@ -1062,7 +1127,7 @@ upload_vertices (const CoglJournalEntry *entries,
         memcpy (vout + vb_stride * i + POS_STRIDE, vin, 4);
       vin++;
 
-      if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
+      if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
         {
           vout[vb_stride * 0] = vin[0];
           vout[vb_stride * 0 + 1] = vin[1];
@@ -1115,21 +1180,108 @@ upload_vertices (const CoglJournalEntry *entries,
       vout += vb_stride * 4;
     }
 
-  cogl_buffer_unmap (buffer);
+  _cogl_buffer_unmap_for_fill_or_fallback (buffer);
 
   return array;
 }
 
+void
+_cogl_journal_discard (CoglJournal *journal)
+{
+  int i;
+
+  for (i = 0; i < journal->entries->len; i++)
+    {
+      CoglJournalEntry *entry =
+        &g_array_index (journal->entries, CoglJournalEntry, i);
+      _cogl_pipeline_journal_unref (entry->pipeline);
+      _cogl_clip_stack_unref (entry->clip_stack);
+    }
+
+  g_array_set_size (journal->entries, 0);
+  g_array_set_size (journal->vertices, 0);
+  journal->needed_vbo_len = 0;
+  journal->fast_read_pixel_count = 0;
+}
+
+/* Note: A return value of FALSE doesn't mean 'no' it means
+ * 'unknown' */
+gboolean
+_cogl_journal_all_entries_within_bounds (CoglJournal *journal,
+                                         float clip_x0,
+                                         float clip_y0,
+                                         float clip_x1,
+                                         float clip_y1)
+{
+  CoglJournalEntry *entry = (CoglJournalEntry *)journal->entries->data;
+  CoglClipStack *clip_entry;
+  CoglClipStack *reference = NULL;
+  int bounds_x0;
+  int bounds_y0;
+  int bounds_x1;
+  int bounds_y1;
+  int i;
+
+  if (journal->entries->len == 0)
+    return TRUE;
+
+  /* Find the shortest clip_stack ancestry that leaves us in the
+   * required bounds */
+  for (clip_entry = entry->clip_stack;
+       clip_entry;
+       clip_entry = clip_entry->parent)
+    {
+      _cogl_clip_stack_get_bounds (clip_entry,
+                                   &bounds_x0, &bounds_y0,
+                                   &bounds_x1, &bounds_y1);
+
+      if (bounds_x0 >= clip_x0 && bounds_y0 >= clip_y0 &&
+          bounds_x1 <= clip_x1 && bounds_y1 <= clip_y1)
+        reference = clip_entry;
+      else
+        break;
+    }
+
+  if (!reference)
+    return FALSE;
+
+  /* For the remaining journal entries we will only verify they share
+   * 'reference' as an ancestor in their clip stack since that's
+   * enough to know that they would be within the required bounds.
+   */
+  for (i = 1; i < journal->entries->len; i++)
+    {
+      gboolean found_reference = FALSE;
+      entry = &g_array_index (journal->entries, CoglJournalEntry, i);
+
+      for (clip_entry = entry->clip_stack;
+           clip_entry;
+           clip_entry = clip_entry->parent)
+        {
+          if (clip_entry == reference)
+            {
+              found_reference = TRUE;
+              break;
+            }
+        }
+
+      if (!found_reference)
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
 /* XXX NB: When _cogl_journal_flush() returns all state relating
  * to pipelines, all glEnable flags and current matrix state
  * is undefined.
  */
 void
-_cogl_journal_flush (void)
+_cogl_journal_flush (CoglJournal *journal,
+                     CoglFramebuffer *framebuffer)
 {
   CoglJournalFlushState state;
   int                   i;
-  CoglFramebuffer      *framebuffer;
   CoglMatrixStack      *modelview_stack;
   COGL_STATIC_TIMER (flush_timer,
                      "Mainloop", /* parent */
@@ -1139,42 +1291,59 @@ _cogl_journal_flush (void)
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  if (ctx->journal->len == 0)
+  if (journal->entries->len == 0)
     return;
 
+  /* The entries in this journal may depend on images in other
+   * framebuffers which may require that we flush the journals
+   * associated with those framebuffers before we can flush
+   * this journal... */
+  _cogl_framebuffer_flush_dependency_journals (framebuffer);
+
+  /* Note: we start the timer after flushing dependency journals so
+   * that the timer isn't started recursively. */
   COGL_TIMER_START (_cogl_uprof_context, flush_timer);
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
-    g_print ("BATCHING: journal len = %d\n", ctx->journal->len);
+  cogl_push_framebuffer (framebuffer);
+
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
+    g_print ("BATCHING: journal len = %d\n", journal->entries->len);
+
+  /* NB: the journal deals with flushing the modelview stack and clip
+     state manually */
+  _cogl_framebuffer_flush_state (framebuffer,
+                                 COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW |
+                                 COGL_FRAMEBUFFER_FLUSH_SKIP_CLIP_STATE);
+
+  state.journal = journal;
 
   state.attributes = ctx->journal_flush_attributes_array;
 
-  framebuffer = _cogl_get_framebuffer ();
   modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer);
   state.modelview_stack = modelview_stack;
   state.projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer);
 
-  if (G_UNLIKELY ((cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_CLIP) == 0))
+  if (G_UNLIKELY ((COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_CLIP)) == 0))
     {
       /* We do an initial walk of the journal to analyse the clip stack
          batches to see if we can do software clipping. We do this as a
          separate walk of the journal because we can modify entries and
          this may end up joining together clip stack batches in the next
          iteration. */
-      batch_and_call ((CoglJournalEntry *)ctx->journal->data, /* first entry */
-                      ctx->journal->len, /* max number of entries to consider */
+      batch_and_call ((CoglJournalEntry *)journal->entries->data, /* first entry */
+                      journal->entries->len, /* max number of entries to consider */
                       compare_entry_clip_stacks,
-                      _cogl_journal_check_software_clip, /* callback */
+                      _cogl_journal_maybe_software_clip_entries, /* callback */
                       &state); /* data */
     }
 
   /* We upload the vertices after the clip stack pass in case it
      modifies the entries */
-  state.vertex_array = upload_vertices (&g_array_index (ctx->journal,
+  state.vertex_array = upload_vertices (&g_array_index (journal->entries,
                                                         CoglJournalEntry, 0),
-                                        ctx->journal->len,
-                                        ctx->journal_needed_vbo_len,
-                                        ctx->logged_vertices);
+                                        journal->entries->len,
+                                        journal->needed_vbo_len,
+                                        journal->vertices);
   state.array_offset = 0;
 
   /* batch_and_call() batches a list of journal entries according to some
@@ -1200,53 +1369,44 @@ _cogl_journal_flush (void)
    *      Note: Splitting by modelview changes is skipped when are doing the
    *      vertex transformation in software at log time.
    */
-  batch_and_call ((CoglJournalEntry *)ctx->journal->data, /* first entry */
-                  ctx->journal->len, /* max number of entries to consider */
+  batch_and_call ((CoglJournalEntry *)journal->entries->data, /* first entry */
+                  journal->entries->len, /* max number of entries to consider */
                   compare_entry_clip_stacks,
                   _cogl_journal_flush_clip_stacks_and_entries, /* callback */
                   &state); /* data */
 
   for (i = 0; i < state.attributes->len; i++)
-    cogl_object_unref (g_array_index (state.attributes,
-                                      CoglVertexAttribute *, i));
+    cogl_object_unref (g_array_index (state.attributes, CoglAttribute *, i));
   g_array_set_size (state.attributes, 0);
 
   cogl_object_unref (state.vertex_array);
 
-  for (i = 0; i < ctx->journal->len; i++)
-    {
-      CoglJournalEntry *entry =
-        &g_array_index (ctx->journal, CoglJournalEntry, i);
-      _cogl_pipeline_journal_unref (entry->pipeline);
-      _cogl_clip_stack_unref (entry->clip_stack);
-    }
+  _cogl_journal_discard (journal);
 
-  g_array_set_size (ctx->journal, 0);
-  g_array_set_size (ctx->logged_vertices, 0);
+  cogl_pop_framebuffer ();
 
   COGL_TIMER_STOP (_cogl_uprof_context, flush_timer);
 }
 
-static void
-_cogl_journal_init (void)
+static gboolean
+add_framebuffer_deps_cb (CoglPipelineLayer *layer, void *user_data)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+  CoglFramebuffer *framebuffer = user_data;
+  CoglHandle texture = _cogl_pipeline_layer_get_texture_real (layer);
+  const GList *l;
 
-  /* Here we flush anything that we know must remain constant until the
-   * next the the journal is flushed. Note: This lets up flush things
-   * that themselves depend on the journal, such as clip state. */
+  if (!texture)
+    return TRUE;
 
-  /* NB: the journal deals with flushing the modelview stack and clip
-     state manually */
-  _cogl_framebuffer_flush_state (_cogl_get_framebuffer (),
-                                 COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW |
-                                 COGL_FRAMEBUFFER_FLUSH_SKIP_CLIP_STATE);
+  for (l = _cogl_texture_get_associated_framebuffers (texture); l; l = l->next)
+    _cogl_framebuffer_add_dependency (framebuffer, l->data);
 
-  ctx->journal_needed_vbo_len = 0;
+  return TRUE;
 }
 
 void
-_cogl_journal_log_quad (const float  *position,
+_cogl_journal_log_quad (CoglJournal  *journal,
+                        const float  *position,
                         CoglPipeline *pipeline,
                         int           n_layers,
                         CoglHandle    layer0_override_texture,
@@ -1255,12 +1415,13 @@ _cogl_journal_log_quad (const float  *position,
 {
   gsize            stride;
   int               next_vert;
-  GLfloat          *v;
+  float            *v;
   int               i;
   int               next_entry;
   guint32           disable_layers;
   CoglJournalEntry *entry;
   CoglPipeline     *source;
+  CoglClipStack    *clip_stack;
   CoglPipelineFlushOptions flush_options;
   COGL_STATIC_TIMER (log_timer,
                      "Mainloop", /* parent */
@@ -1272,9 +1433,6 @@ _cogl_journal_log_quad (const float  *position,
 
   COGL_TIMER_START (_cogl_uprof_context, log_timer);
 
-  if (ctx->logged_vertices->len == 0)
-    _cogl_journal_init ();
-
   /* The vertex data is logged into a separate array. The data needs
      to be copied into a vertex array before it's given to GL so we
      only store two vertices per quad and expand it to four while
@@ -1284,15 +1442,14 @@ _cogl_journal_log_quad (const float  *position,
    * about how we pack our vertex data */
   stride = GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (n_layers);
 
-  next_vert = ctx->logged_vertices->len;
-  g_array_set_size (ctx->logged_vertices, next_vert + 2 * stride + 1);
-  v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert);
+  next_vert = journal->vertices->len;
+  g_array_set_size (journal->vertices, next_vert + 2 * stride + 1);
+  v = &g_array_index (journal->vertices, float, next_vert);
 
   /* We calculate the needed size of the vbo as we go because it
      depends on the number of layers in each entry and it's not easy
      calculate based on the length of the logged vertices array */
-  ctx->journal_needed_vbo_len +=
-    GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers) * 4;
+  journal->needed_vbo_len += GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers) * 4;
 
   /* XXX: All the jumping around to fill in this strided buffer doesn't
    * seem ideal. */
@@ -1315,16 +1472,16 @@ _cogl_journal_log_quad (const float  *position,
       memcpy (t + stride, tex_coords + i * 4 + 2, sizeof (float) * 2);
     }
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_JOURNAL)))
     {
       g_print ("Logged new quad:\n");
-      v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert);
+      v = &g_array_index (journal->vertices, float, next_vert);
       _cogl_journal_dump_logged_quad ((guint8 *)v, n_layers);
     }
 
-  next_entry = ctx->journal->len;
-  g_array_set_size (ctx->journal, next_entry + 1);
-  entry = &g_array_index (ctx->journal, CoglJournalEntry, next_entry);
+  next_entry = journal->entries->len;
+  g_array_set_size (journal->entries, next_entry + 1);
+  entry = &g_array_index (journal->entries, CoglJournalEntry, next_entry);
 
   entry->n_layers = n_layers;
   entry->array_offset = next_vert;
@@ -1360,16 +1517,288 @@ _cogl_journal_log_quad (const float  *position,
     }
 
   entry->pipeline = _cogl_pipeline_journal_ref (source);
-  entry->clip_stack = _cogl_clip_stack_ref (_cogl_get_clip_stack ());
+
+  clip_stack = _cogl_framebuffer_get_clip_stack (_cogl_get_framebuffer ());
+  entry->clip_stack = _cogl_clip_stack_ref (clip_stack);
 
   if (G_UNLIKELY (source != pipeline))
     cogl_handle_unref (source);
 
   cogl_get_modelview_matrix (&entry->model_view);
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_BATCHING))
-    _cogl_journal_flush ();
+  _cogl_pipeline_foreach_layer_internal (pipeline,
+                                         add_framebuffer_deps_cb,
+                                         _cogl_get_framebuffer ());
+
+  /* XXX: It doesn't feel very nice that in this case we just assume
+   * that the journal is associated with the current framebuffer. I
+   * think a journal->framebuffer reference would seem nicer here but
+   * the reason we don't have that currently is that it would
+   * introduce a circular reference. */
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_BATCHING)))
+    _cogl_framebuffer_flush_journal (_cogl_get_framebuffer ());
 
   COGL_TIMER_STOP (_cogl_uprof_context, log_timer);
 }
 
+static void
+entry_to_screen_polygon (const CoglJournalEntry *entry,
+                         float *vertices,
+                         float *poly)
+{
+  size_t array_stride =
+    GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (entry->n_layers);
+  CoglMatrixStack *projection_stack;
+  CoglMatrix projection;
+  int i;
+  int viewport[4];
+
+  poly[0] = vertices[0];
+  poly[1] = vertices[1];
+  poly[2] = 0;
+  poly[3] = 1;
+
+  poly[4] = vertices[0];
+  poly[5] = vertices[array_stride + 1];
+  poly[6] = 0;
+  poly[7] = 1;
+
+  poly[8] = vertices[array_stride];
+  poly[9] = vertices[array_stride + 1];
+  poly[10] = 0;
+  poly[11] = 1;
+
+  poly[12] = vertices[array_stride];
+  poly[13] = vertices[1];
+  poly[14] = 0;
+  poly[15] = 1;
+
+  /* TODO: perhaps split the following out into a more generalized
+   * _cogl_transform_points utility...
+   */
+
+  cogl_matrix_transform_points (&entry->model_view,
+                                2, /* n_components */
+                                sizeof (float) * 4, /* stride_in */
+                                poly, /* points_in */
+                                /* strideout */
+                                sizeof (float) * 4,
+                                poly, /* points_out */
+                                4 /* n_points */);
+
+  projection_stack =
+    _cogl_framebuffer_get_projection_stack (_cogl_get_framebuffer ());
+  _cogl_matrix_stack_get (projection_stack, &projection);
+
+  cogl_matrix_project_points (&projection,
+                              3, /* n_components */
+                              sizeof (float) * 4, /* stride_in */
+                              poly, /* points_in */
+                              /* strideout */
+                              sizeof (float) * 4,
+                              poly, /* points_out */
+                              4 /* n_points */);
+
+  _cogl_framebuffer_get_viewport4fv (_cogl_get_framebuffer (),
+                                     viewport);
+
+/* Scale from OpenGL normalized device coordinates (ranging from -1 to 1)
+ * to Cogl window/framebuffer coordinates (ranging from 0 to buffer-size) with
+ * (0,0) being top left. */
+#define VIEWPORT_TRANSFORM_X(x, vp_origin_x, vp_width) \
+    (  ( ((x) + 1.0) * ((vp_width) / 2.0) ) + (vp_origin_x)  )
+/* Note: for Y we first flip all coordinates around the X axis while in
+ * normalized device coodinates */
+#define VIEWPORT_TRANSFORM_Y(y, vp_origin_y, vp_height) \
+    (  ( ((-(y)) + 1.0) * ((vp_height) / 2.0) ) + (vp_origin_y)  )
+
+  /* Scale from normalized device coordinates (in range [-1,1]) to
+   * window coordinates ranging [0,window-size] ... */
+  for (i = 0; i < 4; i++)
+    {
+      float w = poly[4 * i + 3];
+
+      /* Perform perspective division */
+      poly[4 * i] /= w;
+      poly[4 * i + 1] /= w;
+
+      /* Apply viewport transform */
+      poly[4 * i] = VIEWPORT_TRANSFORM_X (poly[4 * i],
+                                          viewport[0], viewport[2]);
+      poly[4 * i + 1] = VIEWPORT_TRANSFORM_Y (poly[4 * i + 1],
+                                              viewport[1], viewport[3]);
+    }
+
+#undef VIEWPORT_TRANSFORM_X
+#undef VIEWPORT_TRANSFORM_Y
+}
+
+static gboolean
+try_checking_point_hits_entry_after_clipping (CoglJournalEntry *entry,
+                                              float *vertices,
+                                              float x,
+                                              float y,
+                                              gboolean *hit)
+{
+  gboolean can_software_clip = TRUE;
+  gboolean needs_software_clip = FALSE;
+  CoglClipStack *clip_entry;
+
+  *hit = TRUE;
+
+  /* Verify that all of the clip stack entries are simple rectangle
+   * clips */
+  for (clip_entry = entry->clip_stack;
+       clip_entry;
+       clip_entry = clip_entry->parent)
+    {
+      if (x < clip_entry->bounds_x0 ||
+          x >= clip_entry->bounds_x1 ||
+          y < clip_entry->bounds_y0 ||
+          y >= clip_entry->bounds_y1)
+        {
+          *hit = FALSE;
+          return TRUE;
+        }
+
+      if (clip_entry->type == COGL_CLIP_STACK_WINDOW_RECT)
+        {
+          /* XXX: technically we could still run the software clip in
+           * this case because for our purposes we know this clip
+           * can be ignored now, but [can_]sofware_clip_entry() doesn't
+           * know this and will bail out. */
+          can_software_clip = FALSE;
+        }
+      else if (clip_entry->type == COGL_CLIP_STACK_RECT)
+        {
+          CoglClipStackRect *rect_entry = (CoglClipStackRect *)entry;
+
+          if (rect_entry->can_be_scissor == FALSE)
+            needs_software_clip = TRUE;
+          /* If can_be_scissor is TRUE then we know it's screen
+           * aligned and the hit test we did above has determined
+           * that we are inside this clip. */
+        }
+      else
+        return FALSE;
+    }
+
+  if (needs_software_clip)
+    {
+      ClipBounds clip_bounds;
+      float poly[16];
+
+      if (!can_software_clip)
+        return FALSE;
+
+      if (!can_software_clip_entry (entry, NULL,
+                                    entry->clip_stack, &clip_bounds))
+        return FALSE;
+
+      software_clip_entry (entry, vertices, &clip_bounds);
+      entry_to_screen_polygon (entry, vertices, poly);
+
+      *hit = _cogl_util_point_in_poly (x, y, poly, sizeof (float) * 4, 4);
+      return TRUE;
+    }
+
+  return TRUE;
+}
+
+gboolean
+_cogl_journal_try_read_pixel (CoglJournal *journal,
+                              int x,
+                              int y,
+                              CoglPixelFormat format,
+                              guint8 *pixel,
+                              gboolean *found_intersection)
+{
+  int i;
+
+  _COGL_GET_CONTEXT (ctx, FALSE);
+
+  /* XXX: this number has been plucked out of thin air, but the idea
+   * is that if so many pixels are being read from the same un-changed
+   * journal than we expect that it will be more efficient to fail
+   * here so we end up flushing and rendering the journal so that
+   * further reads can directly read from the framebuffer. There will
+   * be a bit more lag to flush the render but if there are going to
+   * continue being lots of arbitrary single pixel reads they will end
+   * up faster in the end. */
+  if (journal->fast_read_pixel_count > 50)
+    return FALSE;
+
+  if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE &&
+      format != COGL_PIXEL_FORMAT_RGBA_8888)
+    return FALSE;
+
+  *found_intersection = FALSE;
+
+  /* NB: The most recently added journal entry is the last entry, and
+   * assuming this is a simple scene only comprised of opaque coloured
+   * rectangles with no special pipelines involved (e.g. enabling
+   * depth testing) then we can assume painter's algorithm for the
+   * entries and so our fast read-pixel just needs to walk backwards
+   * through the journal entries trying to intersect each entry with
+   * the given point of interest. */
+  for (i = journal->entries->len - 1; i >= 0; i--)
+    {
+      CoglJournalEntry *entry =
+        &g_array_index (journal->entries, CoglJournalEntry, i);
+      guint8 *color = (guint8 *)&g_array_index (journal->vertices, float,
+                                                entry->array_offset);
+      float *vertices = (float *)color + 1;
+      float poly[16];
+
+      entry_to_screen_polygon (entry, vertices, poly);
+
+      if (!_cogl_util_point_in_poly (x, y, poly, sizeof (float) * 4, 4))
+        continue;
+
+      /* FIXME: the journal should have a back pointer to the
+       * associated framebuffer, because it should be possible to read
+       * a pixel from arbitrary framebuffers without needing to
+       * internally call _cogl_push/pop_framebuffer.
+       */
+      if (entry->clip_stack)
+        {
+          gboolean hit;
+
+          if (!try_checking_point_hits_entry_after_clipping (entry, vertices,
+                                                             x, y, &hit))
+            return FALSE; /* hit couldn't be determined */
+
+          if (!hit)
+            continue;
+        }
+
+      *found_intersection = TRUE;
+
+      /* If we find that the rectangle the point of interest
+       * intersects has any state more complex than a constant opaque
+       * color then we bail out. */
+      if (!_cogl_pipeline_equal (ctx->opaque_color_pipeline, entry->pipeline,
+                                 (COGL_PIPELINE_STATE_ALL &
+                                  ~COGL_PIPELINE_STATE_COLOR),
+                                 COGL_PIPELINE_LAYER_STATE_ALL,
+                                 0))
+        return FALSE;
+
+
+      /* we currently only care about cases where the premultiplied or
+       * unpremultipled colors are equivalent... */
+      if (color[3] != 0xff)
+        return FALSE;
+
+      pixel[0] = color[0];
+      pixel[1] = color[1];
+      pixel[2] = color[2];
+      pixel[3] = color[3];
+
+      goto success;
+    }
+
+success:
+  journal->fast_read_pixel_count++;
+  return TRUE;
+}
index 5b78421..7414e5b 100644 (file)
@@ -32,7 +32,7 @@
 G_BEGIN_DECLS
 
 #define _COGL_MATRIX_DEBUG_PRINT(MATRIX) \
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_MATRICES)) \
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_MATRICES))) \
     { \
       g_print ("%s:\n", G_STRFUNC); \
       _cogl_matrix_print (MATRIX); \
index 73a3463..5da5b47 100644 (file)
@@ -439,232 +439,121 @@ typedef struct _Point4f
 } Point4f;
 
 static void
-_cogl_matrix_transform_points_f2_packed (const CoglMatrix *matrix,
-                                         void *points_in,
-                                         void *points_out,
-                                         int n_points)
+_cogl_matrix_transform_points_f2 (const CoglMatrix *matrix,
+                                  size_t stride_in,
+                                  void *points_in,
+                                  size_t stride_out,
+                                  void *points_out,
+                                  int n_points)
 {
-  Point2f *p = points_in;
-  Point3f *o = points_out;
   int i;
 
   for (i = 0; i < n_points; i++)
     {
-      o[i].x = matrix->xx * p[i].x + matrix->xy * p[i].y +
-               matrix->xw;
-      o[i].y = matrix->yx * p[i].x + matrix->yy * p[i].y +
-               matrix->yw;
-      o[i].z = matrix->zx * p[i].x + matrix->zy * p[i].y +
-               matrix->zw;
-    }
-}
-
-static void
-_cogl_matrix_transform_points_f2_strided (const CoglMatrix *matrix,
-                                          size_t stride_in,
-                                          void *points_in,
-                                          size_t stride_out,
-                                          void *points_out,
-                                          int n_points)
-{
-  int i;
-
-  for (i = 0; i < n_points; i++)
-    {
-      Point2f *p = (Point2f *)((guint8 *)points_in + i * stride_in);
+      Point2f p = *(Point2f *)((guint8 *)points_in + i * stride_in);
       Point3f *o = (Point3f *)((guint8 *)points_out + i * stride_out);
 
-      o->x = matrix->xx * p->x + matrix->xy * p->y + matrix->xw;
-      o->y = matrix->yx * p->x + matrix->yy * p->y + matrix->yw;
-      o->z = matrix->zx * p->x + matrix->zy * p->y + matrix->zw;
-    }
-}
-
-static void
-_cogl_matrix_project_points_f2_packed (const CoglMatrix *matrix,
-                                       void *points_in,
-                                       void *points_out,
-                                       int n_points)
-{
-  Point2f *p = points_in;
-  Point4f *o = points_out;
-  int i;
-
-  for (i = 0; i < n_points; i++)
-    {
-      o[i].x = matrix->xx * p[i].x + matrix->xy * p[i].y +
-               matrix->xw;
-      o[i].y = matrix->yx * p[i].x + matrix->yy * p[i].y +
-               matrix->yw;
-      o[i].z = matrix->zx * p[i].x + matrix->zy * p[i].y +
-               matrix->zw;
-      o[i].w = matrix->wx * p[i].x + matrix->wy * p[i].y +
-               matrix->ww;
+      o->x = matrix->xx * p.x + matrix->xy * p.y + matrix->xw;
+      o->y = matrix->yx * p.x + matrix->yy * p.y + matrix->yw;
+      o->z = matrix->zx * p.x + matrix->zy * p.y + matrix->zw;
     }
 }
 
 static void
-_cogl_matrix_project_points_f2_strided (const CoglMatrix *matrix,
-                                        size_t stride_in,
-                                        void *points_in,
-                                        size_t stride_out,
-                                        void *points_out,
-                                        int n_points)
+_cogl_matrix_project_points_f2 (const CoglMatrix *matrix,
+                                size_t stride_in,
+                                void *points_in,
+                                size_t stride_out,
+                                void *points_out,
+                                int n_points)
 {
   int i;
 
   for (i = 0; i < n_points; i++)
     {
-      Point2f *p = (Point2f *)((guint8 *)points_in + i * stride_in);
+      Point2f p = *(Point2f *)((guint8 *)points_in + i * stride_in);
       Point4f *o = (Point4f *)((guint8 *)points_out + i * stride_out);
 
-      o->x = matrix->xx * p->x + matrix->xy * p->y + matrix->xw;
-      o->y = matrix->yx * p->x + matrix->yy * p->y + matrix->yw;
-      o->z = matrix->zx * p->x + matrix->zy * p->y + matrix->zw;
-      o->w = matrix->wx * p->x + matrix->wy * p->y + matrix->ww;
-    }
-}
-
-static void
-_cogl_matrix_transform_points_f3_packed (const CoglMatrix *matrix,
-                                         void *points_in,
-                                         void *points_out,
-                                         int n_points)
-{
-  Point3f *p = points_in;
-  Point3f *o = points_out;
-  int i;
-
-  for (i = 0; i < n_points; i++)
-    {
-      o[i].x = matrix->xx * p[i].x + matrix->xy * p[i].y +
-               matrix->xz * p[i].z + matrix->xw;
-      o[i].y = matrix->yx * p[i].x + matrix->yy * p[i].y +
-               matrix->yz * p[i].z + matrix->yw;
-      o[i].z = matrix->zx * p[i].x + matrix->zy * p[i].y +
-               matrix->zz * p[i].z + matrix->zw;
+      o->x = matrix->xx * p.x + matrix->xy * p.y + matrix->xw;
+      o->y = matrix->yx * p.x + matrix->yy * p.y + matrix->yw;
+      o->z = matrix->zx * p.x + matrix->zy * p.y + matrix->zw;
+      o->w = matrix->wx * p.x + matrix->wy * p.y + matrix->ww;
     }
 }
 
 static void
-_cogl_matrix_transform_points_f3_strided (const CoglMatrix *matrix,
-                                          size_t stride_in,
-                                          void *points_in,
-                                          size_t stride_out,
-                                          void *points_out,
-                                          int n_points)
+_cogl_matrix_transform_points_f3 (const CoglMatrix *matrix,
+                                  size_t stride_in,
+                                  void *points_in,
+                                  size_t stride_out,
+                                  void *points_out,
+                                  int n_points)
 {
   int i;
 
   for (i = 0; i < n_points; i++)
     {
-      Point3f *p = (Point3f *)((guint8 *)points_in + i * stride_in);
+      Point3f p = *(Point3f *)((guint8 *)points_in + i * stride_in);
       Point3f *o = (Point3f *)((guint8 *)points_out + i * stride_out);
 
-      o->x = matrix->xx * p->x + matrix->xy * p->y +
-             matrix->xz * p->z + matrix->xw;
-      o->y = matrix->yx * p->x + matrix->yy * p->y +
-             matrix->yz * p->z + matrix->yw;
-      o->z = matrix->zx * p->x + matrix->zy * p->y +
-             matrix->zz * p->z + matrix->zw;
+      o->x = matrix->xx * p.x + matrix->xy * p.y +
+             matrix->xz * p.z + matrix->xw;
+      o->y = matrix->yx * p.x + matrix->yy * p.y +
+             matrix->yz * p.z + matrix->yw;
+      o->z = matrix->zx * p.x + matrix->zy * p.y +
+             matrix->zz * p.z + matrix->zw;
     }
 }
 
 static void
-_cogl_matrix_project_points_f3_packed (const CoglMatrix *matrix,
-                                       void *points_in,
-                                       void *points_out,
-                                       int n_points)
+_cogl_matrix_project_points_f3 (const CoglMatrix *matrix,
+                                size_t stride_in,
+                                void *points_in,
+                                size_t stride_out,
+                                void *points_out,
+                                int n_points)
 {
-  Point3f *p = points_in;
-  Point4f *o = points_out;
   int i;
 
   for (i = 0; i < n_points; i++)
     {
-      o[i].x = matrix->xx * p[i].x + matrix->xy * p[i].y +
-               matrix->xz * p[i].z + matrix->xw;
-      o[i].y = matrix->yx * p[i].x + matrix->yy * p[i].y +
-               matrix->yz * p[i].z + matrix->yw;
-      o[i].z = matrix->zx * p[i].x + matrix->zy * p[i].y +
-               matrix->zz * p[i].z + matrix->zw;
-      o[i].w = matrix->wx * p[i].x + matrix->wy * p[i].y +
-               matrix->wz * p[i].z + matrix->ww;
-    }
-}
-
-static void
-_cogl_matrix_project_points_f3_strided (const CoglMatrix *matrix,
-                                        size_t stride_in,
-                                        void *points_in,
-                                        size_t stride_out,
-                                        void *points_out,
-                                        int n_points)
-{
-  int i;
-
-  for (i = 0; i < n_points; i++)
-    {
-      Point3f *p = (Point3f *)((guint8 *)points_in + i * stride_in);
+      Point3f p = *(Point3f *)((guint8 *)points_in + i * stride_in);
       Point4f *o = (Point4f *)((guint8 *)points_out + i * stride_out);
 
-      o->x = matrix->xx * p->x + matrix->xy * p->y +
-             matrix->xz * p->z + matrix->xw;
-      o->y = matrix->yx * p->x + matrix->yy * p->y +
-             matrix->yz * p->z + matrix->yw;
-      o->z = matrix->zx * p->x + matrix->zy * p->y +
-             matrix->zz * p->z + matrix->zw;
-      o->w = matrix->wx * p->x + matrix->wy * p->y +
-             matrix->wz * p->z + matrix->ww;
-    }
-}
-
-static void
-_cogl_matrix_project_points_f4_packed (const CoglMatrix *matrix,
-                                       void *points_in,
-                                       void *points_out,
-                                       int n_points)
-{
-  Point4f *p = points_in;
-  Point4f *o = points_out;
-  int i;
-
-  for (i = 0; i < n_points; i++)
-    {
-      o[i].x = matrix->xx * p[i].x + matrix->xy * p[i].y +
-               matrix->xz * p[i].z + matrix->xw * p[i].w;
-      o[i].y = matrix->yx * p[i].x + matrix->yy * p[i].y +
-               matrix->yz * p[i].z + matrix->yw * p[i].w;
-      o[i].z = matrix->zx * p[i].x + matrix->zy * p[i].y +
-               matrix->zz * p[i].z + matrix->zw * p[i].w;
-      o[i].w = matrix->wx * p[i].x + matrix->wy * p[i].y +
-               matrix->wz * p[i].z + matrix->ww * p[i].w;
+      o->x = matrix->xx * p.x + matrix->xy * p.y +
+             matrix->xz * p.z + matrix->xw;
+      o->y = matrix->yx * p.x + matrix->yy * p.y +
+             matrix->yz * p.z + matrix->yw;
+      o->z = matrix->zx * p.x + matrix->zy * p.y +
+             matrix->zz * p.z + matrix->zw;
+      o->w = matrix->wx * p.x + matrix->wy * p.y +
+             matrix->wz * p.z + matrix->ww;
     }
 }
 
 static void
-_cogl_matrix_project_points_f4_strided (const CoglMatrix *matrix,
-                                        size_t stride_in,
-                                        void *points_in,
-                                        size_t stride_out,
-                                        void *points_out,
-                                        int n_points)
+_cogl_matrix_project_points_f4 (const CoglMatrix *matrix,
+                                size_t stride_in,
+                                void *points_in,
+                                size_t stride_out,
+                                void *points_out,
+                                int n_points)
 {
   int i;
 
   for (i = 0; i < n_points; i++)
     {
-      Point4f *p = (Point4f *)((guint8 *)points_in + i * stride_in);
+      Point4f p = *(Point4f *)((guint8 *)points_in + i * stride_in);
       Point4f *o = (Point4f *)((guint8 *)points_out + i * stride_out);
 
-      o->x = matrix->xx * p->x + matrix->xy * p->y +
-             matrix->xz * p->z + matrix->xw * p->w;
-      o->y = matrix->yx * p->x + matrix->yy * p->y +
-             matrix->yz * p->z + matrix->yw * p->w;
-      o->z = matrix->zx * p->x + matrix->zy * p->y +
-             matrix->zz * p->z + matrix->zw * p->w;
-      o->w = matrix->wx * p->x + matrix->wy * p->y +
-             matrix->wz * p->z + matrix->ww * p->w;
+      o->x = matrix->xx * p.x + matrix->xy * p.y +
+             matrix->xz * p.z + matrix->xw * p.w;
+      o->y = matrix->yx * p.x + matrix->yy * p.y +
+             matrix->yz * p.z + matrix->yw * p.w;
+      o->z = matrix->zx * p.x + matrix->zy * p.y +
+             matrix->zz * p.z + matrix->zw * p.w;
+      o->w = matrix->wx * p.x + matrix->wy * p.y +
+             matrix->wz * p.z + matrix->ww * p.w;
     }
 }
 
@@ -681,31 +570,18 @@ cogl_matrix_transform_points (const CoglMatrix *matrix,
   g_return_if_fail (stride_out >= sizeof (Point3f));
 
   if (n_components == 2)
-    {
-      if (stride_in == sizeof (Point2f) &&
-          stride_out == sizeof (Point3f))
-        _cogl_matrix_transform_points_f2_packed (matrix,
-                                                 points_in, points_out,
-                                                 n_points);
-      else
-        _cogl_matrix_transform_points_f2_strided (matrix,
-                                                  stride_in, points_in,
-                                                  stride_out, points_out,
-                                                  n_points);
-    }
+    _cogl_matrix_transform_points_f2 (matrix,
+                                      stride_in, points_in,
+                                      stride_out, points_out,
+                                      n_points);
   else
     {
       g_return_if_fail (n_components == 3);
 
-      if (stride_in == sizeof (Point3f) && stride_out == stride_in)
-        _cogl_matrix_transform_points_f3_packed (matrix,
-                                                 points_in, points_out,
-                                                 n_points);
-      else
-        _cogl_matrix_transform_points_f3_strided (matrix,
-                                                  stride_in, points_in,
-                                                  stride_out, points_out,
-                                                  n_points);
+      _cogl_matrix_transform_points_f3 (matrix,
+                                        stride_in, points_in,
+                                        stride_out, points_out,
+                                        n_points);
     }
 }
 
@@ -719,44 +595,22 @@ cogl_matrix_project_points (const CoglMatrix *matrix,
                             int n_points)
 {
   if (n_components == 2)
-    {
-      if (stride_in == sizeof (Point2f) &&
-          stride_out == sizeof (Point4f))
-        _cogl_matrix_project_points_f2_packed (matrix,
-                                               points_in, points_out,
-                                               n_points);
-      else
-        _cogl_matrix_project_points_f2_strided (matrix,
-                                                stride_in, points_in,
-                                                stride_out, points_out,
-                                                n_points);
-    }
+    _cogl_matrix_project_points_f2 (matrix,
+                                    stride_in, points_in,
+                                    stride_out, points_out,
+                                    n_points);
   else if (n_components == 3)
-    {
-      if (stride_in == sizeof (Point3f) &&
-          stride_out == sizeof (Point4f))
-        _cogl_matrix_project_points_f3_packed (matrix,
-                                               points_in, points_out,
-                                               n_points);
-      else
-        _cogl_matrix_project_points_f3_strided (matrix,
-                                                stride_in, points_in,
-                                                stride_out, points_out,
-                                                n_points);
-    }
+    _cogl_matrix_project_points_f3 (matrix,
+                                    stride_in, points_in,
+                                    stride_out, points_out,
+                                    n_points);
   else
     {
       g_return_if_fail (n_components == 4);
 
-      if (stride_in == sizeof (Point4f) && stride_out == stride_in)
-        _cogl_matrix_project_points_f4_packed (matrix,
-                                               points_in, points_out,
-                                               n_points);
-      else
-        _cogl_matrix_project_points_f4_strided (matrix,
-                                                stride_in, points_in,
-                                                stride_out, points_out,
-                                                n_points);
+      _cogl_matrix_project_points_f4 (matrix,
+                                      stride_in, points_in,
+                                      stride_out, points_out,
+                                      n_points);
     }
 }
-
index 24c01e6..8e9f207 100644 (file)
@@ -130,7 +130,10 @@ cogl_matrix_init_identity (CoglMatrix *matrix);
  * @b: A 4x4 transformation matrix
  *
  * Multiplies the two supplied matrices together and stores
- * the resulting matrix inside @result
+ * the resulting matrix inside @result.
+ *
+ * <note>It is possible to multiply the @a matrix in-place, so
+ * @result can be equal to @a but can't be equal to @b.</note>
  */
 void
 cogl_matrix_multiply (CoglMatrix *result,
index 2e90f05..e8b4ed0 100644 (file)
 typedef struct _CoglObjectClass CoglHandleClass;
 typedef struct _CoglObject      CoglHandleObject;
 
+/* XXX: sadly we didn't fully consider when we copied the cairo API
+ * for _set_user_data that the callback doesn't get a pointer to the
+ * instance which is desired in most cases. This means you tend to end
+ * up creating micro allocations for the private data just so you can
+ * pair up the data of interest with the original instance for
+ * identification when it is later destroyed.
+ *
+ * Internally we use a small hack to avoid needing these micro
+ * allocations by actually passing the instance as a second argument
+ * to the callback */
+typedef void (*CoglUserDataDestroyInternalCallback) (void *user_data,
+                                                     void *instance);
+
 typedef struct _CoglObjectClass
 {
   GQuark   type;
@@ -48,7 +61,7 @@ typedef struct
 {
   CoglUserDataKey *key;
   void *user_data;
-  CoglUserDataDestroyCallback destroy;
+  CoglUserDataDestroyInternalCallback destroy;
 } CoglUserDataEntry;
 
 /* All Cogl objects inherit from this base object by adding a member:
@@ -253,5 +266,11 @@ _cogl_##type_name##_handle_new (CoglHandle handle)                       \
 #define COGL_HANDLE_DEFINE(TypeName, type_name)                 \
   COGL_HANDLE_DEFINE_WITH_CODE (TypeName, type_name, (void) 0)
 
+void
+_cogl_object_set_user_data (CoglObject *object,
+                            CoglUserDataKey *key,
+                            void *user_data,
+                            CoglUserDataDestroyInternalCallback destroy);
+
 #endif /* __COGL_OBJECT_PRIVATE_H */
 
index f80a0ea..90109eb 100644 (file)
@@ -72,7 +72,7 @@ cogl_object_unref (void *object)
             {
               CoglUserDataEntry *entry = &obj->user_data_entry[i];
               if (entry->destroy)
-                entry->destroy (entry->user_data);
+                entry->destroy (entry->user_data, obj);
             }
 
           if (obj->user_data_array != NULL)
@@ -84,7 +84,7 @@ cogl_object_unref (void *object)
                                     CoglUserDataEntry, i);
 
                   if (entry->destroy)
-                    entry->destroy (entry->user_data);
+                    entry->destroy (entry->user_data, obj);
                 }
               g_array_free (obj->user_data_array, TRUE);
             }
@@ -157,10 +157,10 @@ _cogl_object_find_entry (CoglObject *object, CoglUserDataKey *key)
 }
 
 void
-cogl_object_set_user_data (CoglObject *object,
-                           CoglUserDataKey *key,
-                           void *user_data,
-                           CoglUserDataDestroyCallback destroy)
+_cogl_object_set_user_data (CoglObject *object,
+                            CoglUserDataKey *key,
+                            void *user_data,
+                            CoglUserDataDestroyInternalCallback destroy)
 {
   CoglUserDataEntry new_entry;
   CoglUserDataEntry *entry;
@@ -178,7 +178,7 @@ cogl_object_set_user_data (CoglObject *object,
   if (entry)
     {
       if (G_LIKELY (entry->destroy))
-        entry->destroy (entry->user_data);
+        entry->destroy (entry->user_data, object);
     }
   else
     {
@@ -206,6 +206,16 @@ cogl_object_set_user_data (CoglObject *object,
   *entry = new_entry;
 }
 
+void
+cogl_object_set_user_data (CoglObject *object,
+                           CoglUserDataKey *key,
+                           void *user_data,
+                           CoglUserDataDestroyCallback destroy)
+{
+  _cogl_object_set_user_data (object, key, user_data,
+                              (CoglUserDataDestroyInternalCallback)destroy);
+}
+
 void *
 cogl_object_get_user_data (CoglObject *object, CoglUserDataKey *key)
 {
index ba0b4cb..f3ea622 100644 (file)
@@ -82,10 +82,10 @@ struct _CoglPathData
   CoglVertexArray     *fill_vbo;
   CoglIndices         *fill_vbo_indices;
   unsigned int         fill_vbo_n_indices;
-  CoglVertexAttribute *fill_vbo_attributes[COGL_PATH_N_ATTRIBUTES + 1];
+  CoglAttribute       *fill_vbo_attributes[COGL_PATH_N_ATTRIBUTES + 1];
 
   CoglVertexArray     *stroke_vbo;
-  CoglVertexAttribute **stroke_vbo_attributes;
+  CoglAttribute      **stroke_vbo_attributes;
   unsigned int         stroke_vbo_n_attributes;
 };
 
index 976f317..15dacdf 100644 (file)
@@ -240,8 +240,7 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
     (pipeline,
      COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN &
      ~COGL_PIPELINE_STATE_LAYERS,
-     COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN,
-     COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET);
+     COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN);
   authority_priv = get_arbfp_priv (authority);
   if (authority_priv &&
       authority_priv->arbfp_program_state)
@@ -263,7 +262,7 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
   /* If we haven't yet found an existing program then before we resort to
    * generating a new arbfp program we see if we can find a suitable
    * program in the arbfp_cache. */
-  if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_DISABLE_PROGRAM_CACHES)))
+  if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
     {
       arbfp_program_state = g_hash_table_lookup (ctx->arbfp_cache, authority);
       if (arbfp_program_state)
@@ -336,11 +335,10 @@ _cogl_pipeline_fragend_arbfp_hash (const void *data)
     COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN;
   unsigned long layer_fragment_state =
     COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN;
-  CoglPipelineEvalFlags flags = COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA;
 
   return _cogl_pipeline_hash ((CoglPipeline *)data,
                               fragment_state, layer_fragment_state,
-                              flags);
+                              0);
 }
 
 gboolean
@@ -350,11 +348,10 @@ _cogl_pipeline_fragend_arbfp_equal (const void *a, const void *b)
     COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN;
   unsigned long layer_fragment_state =
     COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN;
-  CoglPipelineEvalFlags flags = COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA;
 
   return _cogl_pipeline_equal ((CoglPipeline *)a, (CoglPipeline *)b,
                                fragment_state, layer_fragment_state,
-                               flags);
+                               0);
 }
 
 static const char *
@@ -894,7 +891,7 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
                        "MOV result.color,output;\n");
       g_string_append (arbfp_program_state->source, "END\n");
 
-      if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_SHOW_SOURCE))
+      if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
         g_message ("pipeline program:\n%s", arbfp_program_state->source->str);
 
       GE (glGenPrograms (1, &arbfp_program_state->gl_program));
@@ -917,7 +914,7 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
 
       arbfp_program_state->source = NULL;
 
-      if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_DISABLE_PROGRAM_CACHES)))
+      if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
         {
           CoglPipeline *key;
 
index 031c424..5c36b52 100644 (file)
@@ -92,7 +92,7 @@ _cogl_pipeline_fragend_fixed_start (CoglPipeline *pipeline,
 {
   CoglHandle user_program;
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_FIXED))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
     return FALSE;
 
   /* If there is a user program with a fragment shader then the
@@ -139,22 +139,19 @@ _cogl_pipeline_fragend_fixed_add_layer (CoglPipeline *pipeline,
     }
 
   /* Handle enabling or disabling the right texture target */
-  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE)
+  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET)
     {
-      CoglPipelineLayer *authority =
+      CoglPipelineLayer *tex_authority =
         _cogl_pipeline_layer_get_authority (layer,
-                                            COGL_PIPELINE_LAYER_STATE_TEXTURE);
-      CoglHandle texture;
-      GLuint     gl_texture;
-      GLenum     gl_target;
-
-      texture = (authority->texture == COGL_INVALID_HANDLE ?
-                 ctx->default_gl_texture_2d_tex :
-                 authority->texture);
-
-      cogl_texture_get_gl_texture (texture,
-                                   &gl_texture,
-                                   &gl_target);
+                                            COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
+      CoglPipelineLayer *target_authority =
+        _cogl_pipeline_layer_get_authority (layer,
+                                            COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET);
+      /* XXX: currently layers with no associated texture fallback to
+       * using ctx->default_gl_texture_2d_tex so they have a texture
+       * target of GL_TEXTURE_2D */
+      GLenum gl_target =
+        tex_authority->texture ? target_authority->target : GL_TEXTURE_2D;
 
       _cogl_set_active_texture_unit (unit_index);
 
@@ -168,7 +165,7 @@ _cogl_pipeline_fragend_fixed_add_layer (CoglPipeline *pipeline,
             GE (glDisable (unit->enabled_gl_target));
 
           /* Enable the new target */
-          if (!G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_TEXTURING))
+          if (!G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)))
             {
               GE (glEnable (gl_target));
               unit->enabled_gl_target = gl_target;
@@ -182,7 +179,7 @@ _cogl_pipeline_fragend_fixed_add_layer (CoglPipeline *pipeline,
        * texture unit has been disabled for some time so we need to assert that
        * it's enabled now.
        */
-      if (!G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_TEXTURING) &&
+      if (!G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)) &&
           !unit->enabled_gl_target == 0)
         {
           _cogl_set_active_texture_unit (unit_index);
index 393bb32..6c273e1 100644 (file)
@@ -240,8 +240,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
         (pipeline,
          COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN &
          ~COGL_PIPELINE_STATE_LAYERS,
-         COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN,
-         COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET);
+         COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN);
 
       authority_priv = get_glsl_priv (authority);
       if (!authority_priv)
index c64a96e..8f42a81 100644 (file)
@@ -252,9 +252,16 @@ _cogl_pipeline_texture_storage_change_notify (CoglHandle texture)
        * we continue to check the rest */
     }
 }
+
 static void
 set_glsl_program (GLuint gl_program)
 {
+#ifdef HAVE_COGL_GLES
+
+  g_return_if_reached ();
+
+#else /* HAVE_COGL_GLES */
+
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   if (ctx->current_gl_program != gl_program)
@@ -272,6 +279,8 @@ set_glsl_program (GLuint gl_program)
           ctx->current_gl_program = 0;
         }
     }
+
+#endif /* HAVE_COGL_GLES */
 }
 
 void
@@ -556,9 +565,10 @@ _cogl_pipeline_flush_color_blend_alpha_depth_state (
                          blend_state->blend_dst_factor_rgb));
     }
 
+#ifndef HAVE_COGL_GLES2
+
   /* Under GLES2 the alpha function is implemented as part of the
      fragment shader */
-#ifndef HAVE_COGL_GLES2
   if (pipelines_difference & (COGL_PIPELINE_STATE_ALPHA_FUNC |
                               COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE))
     {
@@ -571,6 +581,28 @@ _cogl_pipeline_flush_color_blend_alpha_depth_state (
       GE (glAlphaFunc (alpha_state->alpha_func,
                        alpha_state->alpha_func_reference));
     }
+
+  /* Under GLES2 the lighting parameters are implemented as uniforms
+     in the progend */
+  if (pipelines_difference & COGL_PIPELINE_STATE_LIGHTING)
+    {
+      CoglPipeline *authority =
+        _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
+      CoglPipelineLightingState *lighting_state =
+        &authority->big_state->lighting_state;
+
+      GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT,
+                        lighting_state->ambient));
+      GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE,
+                        lighting_state->diffuse));
+      GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,
+                        lighting_state->specular));
+      GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION,
+                        lighting_state->emission));
+      GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS,
+                        &lighting_state->shininess));
+    }
+
 #endif /* HAVE_COGL_GLES2 */
 
   if (pipelines_difference & COGL_PIPELINE_STATE_DEPTH)
@@ -674,11 +706,11 @@ flush_layers_common_gl_state_cb (CoglPipelineLayer *layer, void *user_data)
       return FALSE;
     }
 
-  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE)
+  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
     {
+      unsigned long state = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
       CoglPipelineLayer *authority =
-        _cogl_pipeline_layer_get_authority (layer,
-                                            COGL_PIPELINE_LAYER_STATE_TEXTURE);
+        _cogl_pipeline_layer_get_authority (layer, state);
       CoglHandle texture;
       GLuint     gl_texture;
       GLenum     gl_target;
@@ -909,7 +941,8 @@ compare_layer_differences_cb (CoglPipelineLayer *layer, void *user_data)
    * then we force an update of the texture state...
    */
   if (unit->texture_storage_changed)
-    state->layer_differences[state->i] |= COGL_PIPELINE_LAYER_STATE_TEXTURE;
+    state->layer_differences[state->i] |=
+      COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
 
   state->i++;
 
@@ -1063,7 +1096,8 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
     {
       /* Bail out asap if we've been asked to re-flush the already current
        * pipeline and we can see the pipeline hasn't changed */
-      if (ctx->current_pipeline_age == pipeline->age)
+      if (ctx->current_pipeline_age == pipeline->age &&
+          ctx->current_pipeline_skip_gl_color == skip_gl_color)
         goto done;
 
       pipelines_difference = ctx->current_pipeline_changes_since_flush;
index 2d5b1b3..47007fb 100644 (file)
@@ -116,7 +116,8 @@ typedef enum
 {
   /* sparse state */
   COGL_PIPELINE_LAYER_STATE_UNIT_INDEX,
-  COGL_PIPELINE_LAYER_STATE_TEXTURE_INDEX,
+  COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX,
+  COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX,
   COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
   COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX,
   COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
@@ -130,12 +131,21 @@ typedef enum
   COGL_PIPELINE_LAYER_STATE_COUNT = COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT
 } CoglPipelineLayerStateIndex;
 
+/* XXX: If you add or remove state groups here you may need to update
+ * some of the state masks following this enum too!
+ *
+ * FIXME: perhaps it would be better to rename this enum to
+ * CoglPipelineLayerStateGroup to better convey the fact that a single
+ * enum here can map to multiple properties.
+ */
 typedef enum
 {
   COGL_PIPELINE_LAYER_STATE_UNIT =
     1L<<COGL_PIPELINE_LAYER_STATE_UNIT_INDEX,
-  COGL_PIPELINE_LAYER_STATE_TEXTURE =
-    1L<<COGL_PIPELINE_LAYER_STATE_TEXTURE_INDEX,
+  COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET =
+    1L<<COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX,
+  COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA =
+    1L<<COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX,
   COGL_PIPELINE_LAYER_STATE_FILTERS =
     1L<<COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
   COGL_PIPELINE_LAYER_STATE_WRAP_MODES =
@@ -153,33 +163,48 @@ typedef enum
 
   /* COGL_PIPELINE_LAYER_STATE_TEXTURE_INTERN   = 1L<<8, */
 
-  COGL_PIPELINE_LAYER_STATE_ALL =
-    (1L<<COGL_PIPELINE_LAYER_STATE_COUNT) - 1,
-
-  COGL_PIPELINE_LAYER_STATE_ALL_SPARSE =
-    (1L<<COGL_PIPELINE_LAYER_STATE_COUNT) - 1,
-
-  COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE =
-    COGL_PIPELINE_LAYER_STATE_COMBINE |
-    COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT |
-    COGL_PIPELINE_LAYER_STATE_USER_MATRIX |
-    COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS,
-
-  COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN =
-    COGL_PIPELINE_LAYER_STATE_COMBINE |
-    /* FIXME: Only texture target changes should really affect the
-       codegen, but this is difficult to detect */
-    COGL_PIPELINE_LAYER_STATE_TEXTURE |
-    /* On GLES2 we need to use a different varying for the texture
-       lookups when point sprite coords are enabled */
+} CoglPipelineLayerState;
+
+/*
+ * Various special masks that tag state-groups in different ways...
+ */
+
+#define COGL_PIPELINE_LAYER_STATE_ALL \
+  ((1L<<COGL_PIPELINE_LAYER_STATE_COUNT) - 1)
+
+#define COGL_PIPELINE_LAYER_STATE_ALL_SPARSE \
+  COGL_PIPELINE_LAYER_STATE_ALL
+
+#define COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE \
+  (COGL_PIPELINE_LAYER_STATE_COMBINE | \
+   COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT | \
+   COGL_PIPELINE_LAYER_STATE_USER_MATRIX | \
+   COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS)
+
+#define COGL_PIPELINE_LAYER_STATE_MULTI_PROPERTY \
+  (COGL_PIPELINE_LAYER_STATE_FILTERS | \
+   COGL_PIPELINE_LAYER_STATE_WRAP_MODES | \
+   COGL_PIPELINE_LAYER_STATE_COMBINE)
+
+/* FIXME: Only texture target changes should really affect the
+ * codegen, but this is difficult to detect */
 #ifdef HAVE_COGL_GLES2
-    COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS |
+/* On GLES2 we need to use a different varying for the texture lookups
+ * when point sprite coords are enabled */
+#define COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN \
+  (COGL_PIPELINE_LAYER_STATE_COMBINE | \
+   COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET | \
+   COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS | \
+   COGL_PIPELINE_LAYER_STATE_UNIT)
+#else
+#define COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN \
+  (COGL_PIPELINE_LAYER_STATE_COMBINE | \
+   COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET | \
+   COGL_PIPELINE_LAYER_STATE_UNIT)
 #endif
-    COGL_PIPELINE_LAYER_STATE_UNIT,
 
-  COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN = 0
+#define COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN 0
 
-} CoglPipelineLayerState;
 
 typedef enum
 {
@@ -348,6 +373,7 @@ struct _CoglPipelineLayer
   /* The texture for this layer, or COGL_INVALID_HANDLE for an empty
    * layer */
   CoglHandle                 texture;
+  GLenum                     target;
 
   CoglPipelineFilter         mag_filter;
   CoglPipelineFilter         min_filter;
@@ -394,7 +420,15 @@ typedef enum
 } CoglPipelineStateIndex;
 
 /* Used in pipeline->differences masks and for notifying pipeline
- * state changes... */
+ * state changes.
+ *
+ * XXX: If you add or remove state groups here you may need to update
+ * some of the state masks following this enum too!
+ *
+ * FIXME: perhaps it would be better to rename this enum to
+ * CoglPipelineStateGroup to better convey the fact that a single enum
+ * here can map to multiple properties.
+ */
 typedef enum _CoglPipelineState
 {
   COGL_PIPELINE_STATE_COLOR =
@@ -424,45 +458,60 @@ typedef enum _CoglPipelineState
   COGL_PIPELINE_STATE_REAL_BLEND_ENABLE =
     1L<<COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX,
 
-  COGL_PIPELINE_STATE_ALL =
-    ((1L<<COGL_PIPELINE_STATE_COUNT) - 1),
-
-  COGL_PIPELINE_STATE_ALL_SPARSE =
-    (COGL_PIPELINE_STATE_ALL
-     & ~COGL_PIPELINE_STATE_REAL_BLEND_ENABLE),
-
-  COGL_PIPELINE_STATE_AFFECTS_BLENDING =
-    COGL_PIPELINE_STATE_COLOR |
-    COGL_PIPELINE_STATE_BLEND_ENABLE |
-    COGL_PIPELINE_STATE_LAYERS |
-    COGL_PIPELINE_STATE_LIGHTING |
-    COGL_PIPELINE_STATE_BLEND |
-    COGL_PIPELINE_STATE_USER_SHADER,
-
-  COGL_PIPELINE_STATE_NEEDS_BIG_STATE =
-    COGL_PIPELINE_STATE_LIGHTING |
-    COGL_PIPELINE_STATE_ALPHA_FUNC |
-    COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE |
-    COGL_PIPELINE_STATE_BLEND |
-    COGL_PIPELINE_STATE_USER_SHADER |
-    COGL_PIPELINE_STATE_DEPTH |
-    COGL_PIPELINE_STATE_FOG |
-    COGL_PIPELINE_STATE_POINT_SIZE,
-
-  COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN =
-    COGL_PIPELINE_STATE_LAYERS |
+} CoglPipelineState;
+
+/*
+ * Various special masks that tag state-groups in different ways...
+ */
+
+#define COGL_PIPELINE_STATE_ALL \
+  ((1L<<COGL_PIPELINE_STATE_COUNT) - 1)
+
+#define COGL_PIPELINE_STATE_ALL_SPARSE \
+  (COGL_PIPELINE_STATE_ALL \
+   & ~COGL_PIPELINE_STATE_REAL_BLEND_ENABLE)
+
+#define COGL_PIPELINE_STATE_AFFECTS_BLENDING \
+  (COGL_PIPELINE_STATE_COLOR | \
+   COGL_PIPELINE_STATE_BLEND_ENABLE | \
+   COGL_PIPELINE_STATE_LAYERS | \
+   COGL_PIPELINE_STATE_LIGHTING | \
+   COGL_PIPELINE_STATE_BLEND | \
+   COGL_PIPELINE_STATE_USER_SHADER)
+
+#define COGL_PIPELINE_STATE_NEEDS_BIG_STATE \
+  (COGL_PIPELINE_STATE_LIGHTING | \
+   COGL_PIPELINE_STATE_ALPHA_FUNC | \
+   COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE | \
+   COGL_PIPELINE_STATE_BLEND | \
+   COGL_PIPELINE_STATE_USER_SHADER | \
+   COGL_PIPELINE_STATE_DEPTH | \
+   COGL_PIPELINE_STATE_FOG | \
+   COGL_PIPELINE_STATE_POINT_SIZE)
+
+#define COGL_PIPELINE_STATE_MULTI_PROPERTY \
+  (COGL_PIPELINE_STATE_LAYERS | \
+   COGL_PIPELINE_STATE_LIGHTING | \
+   COGL_PIPELINE_STATE_BLEND | \
+   COGL_PIPELINE_STATE_DEPTH | \
+   COGL_PIPELINE_STATE_FOG)
+
 #ifdef HAVE_COGL_GLES2
   /* Under GLES2 the alpha func becomes part of the fragment program
      so we can't share programs there */
-    COGL_PIPELINE_STATE_ALPHA_FUNC |
+#define COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN \
+  (COGL_PIPELINE_STATE_LAYERS | \
+   COGL_PIPELINE_STATE_ALPHA_FUNC | \
+   COGL_PIPELINE_STATE_USER_SHADER)
+#else
+#define COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN \
+  (COGL_PIPELINE_STATE_LAYERS | \
+   COGL_PIPELINE_STATE_USER_SHADER)
 #endif
-    COGL_PIPELINE_STATE_USER_SHADER,
 
-  COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN =
-    COGL_PIPELINE_STATE_LAYERS |
-    COGL_PIPELINE_STATE_USER_SHADER
-
-} CoglPipelineState;
+#define COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN \
+  (COGL_PIPELINE_STATE_LAYERS | \
+   COGL_PIPELINE_STATE_USER_SHADER)
 
 typedef enum
 {
@@ -555,12 +604,6 @@ typedef struct
   CoglPipelineLayer *layer;
 } CoglPipelineLayerCacheEntry;
 
-/* Flags used for _cogl_pipeline_find_equivalent_parent */
-typedef enum
-{
-  COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET = 1L<<0
-} CoglPipelineFindEquivalentFlags;
-
 /*
  * CoglPipelineDestroyCallback
  * @pipeline: The #CoglPipeline that has been destroyed
@@ -1047,10 +1090,7 @@ _cogl_pipeline_compare_differences (CoglPipeline *pipeline0,
  * semantics */
 typedef enum _CoglPipelineEvalFlags
 {
-  /* When evaluating a pipeline-layer with associated textures then
-   * evaluate the texture target, but don't consider the texture data
-   * itself. */
-  COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA = 1L<<0
+  COGL_PIPELINE_EVAL_FLAG_NONE = 0
 } CoglPipelineEvalFlags;
 
 gboolean
@@ -1115,8 +1155,7 @@ _cogl_pipeline_get_authority (CoglPipeline *pipeline,
 CoglPipeline *
 _cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline,
                                        CoglPipelineState pipeline_state,
-                                       CoglPipelineLayerState layer_state,
-                                       CoglPipelineFindEquivalentFlags flags);
+                                       CoglPipelineLayerState layer_state);
 
 CoglHandle
 _cogl_pipeline_get_layer_texture (CoglPipeline *pipeline,
@@ -1165,6 +1204,9 @@ _cogl_pipeline_layer_get_type (CoglPipelineLayer *layer);
 CoglHandle
 _cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer);
 
+CoglHandle
+_cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer);
+
 CoglPipelineFilter
 _cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer);
 
index 6fe6e4b..c100269 100644 (file)
@@ -29,7 +29,7 @@
 #define __COGL_PIPELINE_PROGEND_GLSL_PRIVATE_H
 
 #include "cogl-pipeline-private.h"
-#include "cogl-vertex-attribute-private.h"
+#include "cogl-attribute-private.h"
 
 extern const CoglPipelineProgend _cogl_pipeline_glsl_progend;
 
index ac2bb70..f096308 100644 (file)
 #define glUniform1f          ctx->drv.pf_glUniform1f
 #define glUniform4fv         ctx->drv.pf_glUniform4fv
 
+#else
+
+/* These are used to generalise updating some uniforms that are
+   required when building for GLES2 */
+
+typedef void (* UpdateUniformFunc) (CoglPipeline *pipeline,
+                                    int uniform_location,
+                                    void *getter_func);
+
+static void update_float_uniform (CoglPipeline *pipeline,
+                                  int uniform_location,
+                                  void *getter_func);
+
+typedef struct
+{
+  const char *uniform_name;
+  void *getter_func;
+  UpdateUniformFunc update_func;
+  CoglPipelineState change;
+} BuiltinUniformData;
+
+static BuiltinUniformData builtin_uniforms[] =
+  {
+    { "cogl_point_size_in",
+      cogl_pipeline_get_point_size, update_float_uniform,
+      COGL_PIPELINE_STATE_POINT_SIZE },
+    { "_cogl_alpha_test_ref",
+      cogl_pipeline_get_alpha_test_reference, update_float_uniform,
+      COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE }
+  };
+
 #endif /* HAVE_COGL_GLES2 */
 
 const CoglPipelineProgend _cogl_pipeline_glsl_progend;
@@ -90,13 +121,8 @@ typedef struct
   int n_tex_coord_attribs;
 
 #ifdef HAVE_COGL_GLES2
-  /* Under GLES2 the alpha test is implemented in the shader. We need
-     a uniform for the reference value */
-  gboolean dirty_alpha_test_reference;
-  GLint alpha_test_reference_uniform;
-
-  gboolean dirty_point_size;
-  GLint point_size_uniform;
+  unsigned long dirty_builtin_uniforms;
+  GLint builtin_uniform_locations[G_N_ELEMENTS (builtin_uniforms)];
 
   /* Under GLES2 we can't use the builtin functions to set attribute
      pointers such as the vertex position. Instead the vertex
@@ -454,37 +480,23 @@ update_constants_cb (CoglPipeline *pipeline,
 #ifdef HAVE_COGL_GLES2
 
 static void
-update_alpha_test_reference (CoglPipeline *pipeline,
-                             GLuint gl_program,
-                             CoglPipelineProgendPrivate *priv)
+update_builtin_uniforms (CoglPipeline *pipeline,
+                         GLuint gl_program,
+                         CoglPipelineProgendPrivate *priv)
 {
-  float alpha_reference;
-
-  if (priv->dirty_alpha_test_reference &&
-      priv->alpha_test_reference_uniform != -1)
-    {
-      alpha_reference = cogl_pipeline_get_alpha_test_reference (pipeline);
-
-      GE( glUniform1f (priv->alpha_test_reference_uniform,
-                       alpha_reference) );
+  int i;
 
-      priv->dirty_alpha_test_reference = FALSE;
-    }
-}
-
-static void
-update_point_size (CoglPipeline *pipeline,
-                   GLuint gl_program,
-                   CoglPipelineProgendPrivate *priv)
-{
-  if (priv->dirty_point_size && priv->point_size_uniform != -1)
-    {
-      float point_size = cogl_pipeline_get_point_size (pipeline);
+  if (priv->dirty_builtin_uniforms == 0)
+    return;
 
-      GE( glUniform1f (priv->point_size_uniform, point_size) );
+  for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
+    if ((priv->dirty_builtin_uniforms & (1 << i)) &&
+        priv->builtin_uniform_locations[i] != -1)
+      builtin_uniforms[i].update_func (pipeline,
+                                       priv->builtin_uniform_locations[i],
+                                       builtin_uniforms[i].getter_func);
 
-      priv->dirty_point_size = FALSE;
-    }
+  priv->dirty_builtin_uniforms = 0;
 }
 
 #endif /* HAVE_COGL_GLES2 */
@@ -525,8 +537,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
           COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN) &
          ~COGL_PIPELINE_STATE_LAYERS,
          COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN |
-         COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN,
-         COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET);
+         COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);
 
       priv = get_glsl_priv (authority);
 
@@ -651,12 +662,15 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
 #ifdef HAVE_COGL_GLES2
   if (program_changed)
     {
+      int i;
+
       clear_attribute_cache (priv);
       clear_flushed_matrix_stacks (priv);
 
-      GE_RET( priv->alpha_test_reference_uniform,
-              glGetUniformLocation (gl_program,
-                                    "_cogl_alpha_test_ref") );
+      for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
+        GE_RET( priv->builtin_uniform_locations[i],
+                glGetUniformLocation (gl_program,
+                                      builtin_uniforms[i].uniform_name) );
 
       GE_RET( priv->modelview_uniform,
               glGetUniformLocation (gl_program,
@@ -669,20 +683,12 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
       GE_RET( priv->mvp_uniform,
               glGetUniformLocation (gl_program,
                                     "cogl_modelview_projection_matrix") );
-
-      GE_RET( priv->point_size_uniform,
-              glGetUniformLocation (gl_program,
-                                    "cogl_point_size_in") );
     }
   if (program_changed ||
       priv->last_used_for_pipeline != pipeline)
-    {
-      priv->dirty_alpha_test_reference = TRUE;
-      priv->dirty_point_size = TRUE;
-    }
+    priv->dirty_builtin_uniforms = ~(unsigned long) 0;
 
-  update_alpha_test_reference (pipeline, gl_program, priv);
-  update_point_size (pipeline, gl_program, priv);
+  update_builtin_uniforms (pipeline, gl_program, priv);
 #endif
 
   if (user_program)
@@ -703,17 +709,18 @@ _cogl_pipeline_progend_glsl_pre_change_notify (CoglPipeline *pipeline,
   if ((change & COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN))
     dirty_glsl_program_state (pipeline);
 #ifdef HAVE_COGL_GLES2
-  else if ((change & COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE))
-    {
-      CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
-      if (priv)
-        priv->dirty_alpha_test_reference = TRUE;
-    }
-  else if ((change & COGL_PIPELINE_STATE_POINT_SIZE))
+  else
     {
-      CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
-      if (priv)
-        priv->dirty_point_size = TRUE;
+      int i;
+
+      for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
+        if ((change & builtin_uniforms[i].change))
+          {
+            CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
+            if (priv)
+              priv->dirty_builtin_uniforms |= 1 << i;
+            return;
+          }
     }
 #endif /* HAVE_COGL_GLES2 */
 }
@@ -912,6 +919,18 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
                                           priv);
 }
 
+static void
+update_float_uniform (CoglPipeline *pipeline,
+                      int uniform_location,
+                      void *getter_func)
+{
+  float (* float_getter_func) (CoglPipeline *) = getter_func;
+  float value;
+
+  value = float_getter_func (pipeline);
+  GE( glUniform1f (uniform_location, value) );
+}
+
 #endif
 
 const CoglPipelineProgend _cogl_pipeline_glsl_progend =
index 8c286ec..57d6191 100644 (file)
@@ -49,7 +49,7 @@ _cogl_pipeline_vertend_fixed_start (CoglPipeline *pipeline,
 {
   CoglProgram *user_program;
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_FIXED))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
     return FALSE;
 
   /* If there is a user program with a vertex shader then the
@@ -83,6 +83,8 @@ _cogl_pipeline_vertend_fixed_add_layer (CoglPipeline *pipeline,
       _cogl_matrix_stack_set (unit->matrix_stack,
                               &authority->big_state->matrix);
 
+      _cogl_set_active_texture_unit (unit_index);
+
       _cogl_matrix_stack_flush_to_gl (unit->matrix_stack, COGL_MATRIX_TEXTURE);
     }
 
@@ -95,25 +97,6 @@ _cogl_pipeline_vertend_fixed_end (CoglPipeline *pipeline,
 {
   _COGL_GET_CONTEXT (ctx, FALSE);
 
-  if (pipelines_difference & COGL_PIPELINE_STATE_LIGHTING)
-    {
-      CoglPipeline *authority =
-        _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
-      CoglPipelineLightingState *lighting_state =
-        &authority->big_state->lighting_state;
-
-      GE (glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT,
-                        lighting_state->ambient));
-      GE (glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE,
-                        lighting_state->diffuse));
-      GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,
-                        lighting_state->specular));
-      GE (glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION,
-                        lighting_state->emission));
-      GE (glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS,
-                        &lighting_state->shininess));
-    }
-
   if (pipelines_difference & COGL_PIPELINE_STATE_POINT_SIZE)
     {
       CoglPipeline *authority =
index cd90165..fda8681 100644 (file)
@@ -157,8 +157,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
         (pipeline,
          COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN &
          ~COGL_PIPELINE_STATE_LAYERS,
-         COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN,
-         0);
+         COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);
 
       priv = get_glsl_priv (authority);
 
@@ -272,6 +271,8 @@ _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
       _cogl_matrix_stack_set (unit->matrix_stack,
                               &authority->big_state->matrix);
 
+      _cogl_set_active_texture_unit (unit_index);
+
       _cogl_matrix_stack_flush_to_gl (unit->matrix_stack, COGL_MATRIX_TEXTURE);
     }
 
index cdd9d7b..93c5234 100644 (file)
@@ -799,7 +799,7 @@ layer_has_alpha_cb (CoglPipelineLayer *layer, void *data)
    */
   tex_authority =
     _cogl_pipeline_layer_get_authority (layer,
-                                        COGL_PIPELINE_LAYER_STATE_TEXTURE);
+                                        COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
   if (tex_authority->texture &&
       cogl_texture_get_format (tex_authority->texture) & COGL_A_BIT)
     {
@@ -837,7 +837,7 @@ _cogl_pipeline_needs_blending_enabled (CoglPipeline    *pipeline,
   CoglPipelineBlendEnable enabled;
   unsigned long other_state;
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_BLENDING))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_BLENDING)))
     return FALSE;
 
   enable_authority =
@@ -1100,21 +1100,63 @@ check_for_blending_change:
 }
 
 static void
-_cogl_pipeline_initialize_sparse_state (CoglPipeline *dest,
-                                        CoglPipeline *src,
-                                        CoglPipelineState state)
+_cogl_pipeline_init_multi_property_sparse_state (CoglPipeline *pipeline,
+                                                 CoglPipelineState change)
 {
-  if (dest == src)
+  CoglPipeline *authority;
+
+  g_return_if_fail (change & COGL_PIPELINE_STATE_ALL_SPARSE);
+
+  if (!(change & COGL_PIPELINE_STATE_MULTI_PROPERTY))
     return;
 
-  g_return_if_fail (state & COGL_PIPELINE_STATE_ALL_SPARSE);
+  authority = _cogl_pipeline_get_authority (pipeline, change);
 
-  if (state != COGL_PIPELINE_STATE_LAYERS)
-    _cogl_pipeline_copy_differences (dest, src, state);
-  else
+  switch (change)
     {
-      dest->n_layers = src->n_layers;
-      dest->layer_differences = NULL;
+    /* XXX: avoid using a default: label so we get a warning if we
+     * don't explicitly handle a newly defined state-group here. */
+    case COGL_PIPELINE_STATE_COLOR:
+    case COGL_PIPELINE_STATE_BLEND_ENABLE:
+    case COGL_PIPELINE_STATE_ALPHA_FUNC:
+    case COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE:
+    case COGL_PIPELINE_STATE_POINT_SIZE:
+    case COGL_PIPELINE_STATE_USER_SHADER:
+    case COGL_PIPELINE_STATE_REAL_BLEND_ENABLE:
+      g_return_if_reached ();
+
+    case COGL_PIPELINE_STATE_LAYERS:
+      pipeline->n_layers = authority->n_layers;
+      pipeline->layer_differences = NULL;
+      break;
+    case COGL_PIPELINE_STATE_LIGHTING:
+      {
+        memcpy (&pipeline->big_state->lighting_state,
+                &authority->big_state->lighting_state,
+                sizeof (CoglPipelineLightingState));
+        break;
+      }
+    case COGL_PIPELINE_STATE_BLEND:
+      {
+        memcpy (&pipeline->big_state->blend_state,
+                &authority->big_state->blend_state,
+                sizeof (CoglPipelineBlendState));
+        break;
+      }
+    case COGL_PIPELINE_STATE_DEPTH:
+      {
+        memcpy (&pipeline->big_state->depth_state,
+                &authority->big_state->depth_state,
+                sizeof (CoglPipelineDepthState));
+        break;
+      }
+    case COGL_PIPELINE_STATE_FOG:
+      {
+        memcpy (&pipeline->big_state->fog_state,
+                &authority->big_state->fog_state,
+                sizeof (CoglPipelineFogState));
+        break;
+      }
     }
 }
 
@@ -1170,7 +1212,6 @@ _cogl_pipeline_pre_change_notify (CoglPipeline     *pipeline,
                                   const CoglColor  *new_color,
                                   gboolean          from_layer_change)
 {
-  CoglPipeline *authority;
   int i;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@@ -1199,7 +1240,12 @@ _cogl_pipeline_pre_change_notify (CoglPipeline     *pipeline,
         }
 
       if (!skip_journal_flush)
-        _cogl_journal_flush ();
+        {
+          /* XXX: note we use cogl_flush() not _cogl_flush_journal() so
+           * we will flush *all* known journals that might reference the
+           * current pipeline. */
+          cogl_flush ();
+        }
     }
 
   /* The fixed function backend has no private state and can't
@@ -1354,14 +1400,32 @@ _cogl_pipeline_pre_change_notify (CoglPipeline     *pipeline,
 
   pipeline->age++;
 
-  /* If changing a sparse property and if the pipeline isn't already an
-   * authority for the state group being modified then we need to
-   * initialize the corresponding state. */
+  if (change & COGL_PIPELINE_STATE_NEEDS_BIG_STATE &&
+      !pipeline->has_big_state)
+    {
+      pipeline->big_state = g_slice_new (CoglPipelineBigState);
+      pipeline->has_big_state = TRUE;
+    }
+
+  /* Note: conceptually we have just been notified that a single
+   * property value is about to change, but since some state-groups
+   * contain multiple properties and 'pipeline' is about to take over
+   * being the authority for the property's corresponding state-group
+   * we need to maintain the integrity of the other property values
+   * too.
+   *
+   * To ensure this we handle multi-property state-groups by copying
+   * all the values from the old-authority to the new...
+   *
+   * We don't have to worry about non-sparse property groups since
+   * we never take over being an authority for such properties so
+   * they automatically maintain integrity.
+   */
   if (change & COGL_PIPELINE_STATE_ALL_SPARSE &&
       !(pipeline->differences & change))
     {
-      authority = _cogl_pipeline_get_authority (pipeline, change);
-      _cogl_pipeline_initialize_sparse_state (pipeline, authority, change);
+      _cogl_pipeline_init_multi_property_sparse_state (pipeline, change);
+      pipeline->differences |= change;
     }
 
   /* Each pipeline has a sorted cache of the layers it depends on
@@ -1639,82 +1703,75 @@ _cogl_get_n_args_for_combine_func (CoglPipelineCombineFunc func)
 }
 
 static void
-_cogl_pipeline_layer_initialize_state (CoglPipelineLayer *dest,
-                                       CoglPipelineLayer *src,
-                                       unsigned long differences)
+_cogl_pipeline_layer_init_multi_property_sparse_state (
+                                                  CoglPipelineLayer *layer,
+                                                  CoglPipelineLayerState change)
 {
-  CoglPipelineLayerBigState *big_state;
-
-  dest->differences |= differences;
-
-  if (differences & COGL_PIPELINE_LAYER_STATE_UNIT)
-    dest->unit_index = src->unit_index;
-
-  if (differences & COGL_PIPELINE_LAYER_STATE_TEXTURE)
-    dest->texture = src->texture;
-
-  if (differences & COGL_PIPELINE_LAYER_STATE_FILTERS)
-    {
-      dest->min_filter = src->min_filter;
-      dest->mag_filter = src->mag_filter;
-    }
-
-  if (differences & COGL_PIPELINE_LAYER_STATE_WRAP_MODES)
-    {
-      dest->wrap_mode_s = src->wrap_mode_s;
-      dest->wrap_mode_t = src->wrap_mode_t;
-      dest->wrap_mode_p = src->wrap_mode_p;
-    }
+  CoglPipelineLayer *authority;
 
-  if (differences & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE)
-    {
-      if (!dest->has_big_state)
-        {
-          dest->big_state = g_slice_new (CoglPipelineLayerBigState);
-          dest->has_big_state = TRUE;
-        }
-      big_state = dest->big_state;
-    }
-  else
+  /* Nothing to initialize in these cases since they are all comprised
+   * of one member which we expect to immediately be overwritten. */
+  if (!(change & COGL_PIPELINE_LAYER_STATE_MULTI_PROPERTY))
     return;
 
-  if (differences & COGL_PIPELINE_LAYER_STATE_COMBINE)
-    {
-      int n_args;
-      int i;
-      GLint func = src->big_state->texture_combine_rgb_func;
-      big_state->texture_combine_rgb_func = func;
-      n_args = _cogl_get_n_args_for_combine_func (func);
-      for (i = 0; i < n_args; i++)
-        {
-          big_state->texture_combine_rgb_src[i] =
-            src->big_state->texture_combine_rgb_src[i];
-          big_state->texture_combine_rgb_op[i] =
-            src->big_state->texture_combine_rgb_op[i];
-        }
+  authority = _cogl_pipeline_layer_get_authority (layer, change);
 
-      func = src->big_state->texture_combine_alpha_func;
-      big_state->texture_combine_alpha_func = func;
-      n_args = _cogl_get_n_args_for_combine_func (func);
-      for (i = 0; i < n_args; i++)
-        {
-          big_state->texture_combine_alpha_src[i] =
-            src->big_state->texture_combine_alpha_src[i];
-          big_state->texture_combine_alpha_op[i] =
-            src->big_state->texture_combine_alpha_op[i];
-        }
+  switch (change)
+    {
+    /* XXX: avoid using a default: label so we get a warning if we
+     * don't explicitly handle a newly defined state-group here. */
+    case COGL_PIPELINE_LAYER_STATE_UNIT:
+    case COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET:
+    case COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA:
+    case COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS:
+    case COGL_PIPELINE_LAYER_STATE_USER_MATRIX:
+    case COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT:
+      g_return_if_reached ();
+
+    /* XXX: technically we could probably even consider these as
+     * single property state-groups from the pov that currently the
+     * corresponding property setters always update all of the values
+     * at the same time. */
+    case COGL_PIPELINE_LAYER_STATE_FILTERS:
+      layer->min_filter = authority->min_filter;
+      layer->mag_filter = authority->mag_filter;
+      break;
+    case COGL_PIPELINE_LAYER_STATE_WRAP_MODES:
+      layer->wrap_mode_s = authority->wrap_mode_s;
+      layer->wrap_mode_t = authority->wrap_mode_t;
+      layer->wrap_mode_p = authority->wrap_mode_p;
+      break;
+    case COGL_PIPELINE_LAYER_STATE_COMBINE:
+      {
+        int n_args;
+        int i;
+        CoglPipelineLayerBigState *src_big_state = authority->big_state;
+        CoglPipelineLayerBigState *dest_big_state = layer->big_state;
+        GLint func = src_big_state->texture_combine_rgb_func;
+
+        dest_big_state->texture_combine_rgb_func = func;
+        n_args = _cogl_get_n_args_for_combine_func (func);
+        for (i = 0; i < n_args; i++)
+          {
+            dest_big_state->texture_combine_rgb_src[i] =
+              src_big_state->texture_combine_rgb_src[i];
+            dest_big_state->texture_combine_rgb_op[i] =
+              src_big_state->texture_combine_rgb_op[i];
+          }
+
+        func = src_big_state->texture_combine_alpha_func;
+        dest_big_state->texture_combine_alpha_func = func;
+        n_args = _cogl_get_n_args_for_combine_func (func);
+        for (i = 0; i < n_args; i++)
+          {
+            dest_big_state->texture_combine_alpha_src[i] =
+              src_big_state->texture_combine_alpha_src[i];
+            dest_big_state->texture_combine_alpha_op[i] =
+              src_big_state->texture_combine_alpha_op[i];
+          }
+        break;
+      }
     }
-
-  if (differences & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT)
-    memcpy (dest->big_state->texture_combine_constant,
-            src->big_state->texture_combine_constant,
-            sizeof (float) * 4);
-
-  if (differences & COGL_PIPELINE_LAYER_STATE_USER_MATRIX)
-    dest->big_state->matrix = src->big_state->matrix;
-
-  if (differences & COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS)
-    dest->big_state->point_sprite_coords = src->big_state->point_sprite_coords;
 }
 
 /* NB: This function will allocate a new derived layer if you are
@@ -1732,7 +1789,6 @@ _cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner,
                                         CoglPipelineLayerState change)
 {
   CoglTextureUnit *unit;
-  CoglPipelineLayer *authority;
 
   /* Identify the case where the layer is new with no owner or
    * dependants and so we don't need to do anything. */
@@ -1792,11 +1848,33 @@ init_layer_state:
   if (required_owner)
     required_owner->age++;
 
-  /* If the pipeline isn't already an authority for the state group
-   * being modified then we need to initialize the corresponding
-   * state. */
-  authority = _cogl_pipeline_layer_get_authority (layer, change);
-  _cogl_pipeline_layer_initialize_state (layer, authority, change);
+  if (change & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE &&
+      !layer->has_big_state)
+    {
+      layer->big_state = g_slice_new (CoglPipelineLayerBigState);
+      layer->has_big_state = TRUE;
+    }
+
+  /* Note: conceptually we have just been notified that a single
+   * property value is about to change, but since some state-groups
+   * contain multiple properties and 'layer' is about to take over
+   * being the authority for the property's corresponding state-group
+   * we need to maintain the integrity of the other property values
+   * too.
+   *
+   * To ensure this we handle multi-property state-groups by copying
+   * all the values from the old-authority to the new...
+   *
+   * We don't have to worry about non-sparse property groups since
+   * we never take over being an authority for such properties so
+   * they automatically maintain integrity.
+   */
+  if (change & COGL_PIPELINE_LAYER_STATE_ALL_SPARSE &&
+      !(layer->differences & change))
+    {
+      _cogl_pipeline_layer_init_multi_property_sparse_state (layer, change);
+      layer->differences |= change;
+    }
 
   return layer;
 }
@@ -2082,7 +2160,7 @@ _cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer)
 {
   CoglPipelineLayer *authority =
     _cogl_pipeline_layer_get_authority (layer,
-                                        COGL_PIPELINE_LAYER_STATE_TEXTURE);
+                                        COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
 
   return authority->texture;
 }
@@ -2171,12 +2249,83 @@ _cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority,
     }
 }
 
-void
-cogl_pipeline_set_layer_texture (CoglPipeline *pipeline,
-                                 int layer_index,
-                                 CoglHandle texture)
+static void
+_cogl_pipeline_set_layer_texture_target (CoglPipeline *pipeline,
+                                         int layer_index,
+                                         GLenum target)
 {
-  CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE;
+  CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET;
+  CoglPipelineLayer *layer;
+  CoglPipelineLayer *authority;
+  CoglPipelineLayer *new;
+
+  /* Note: this will ensure that the layer exists, creating one if it
+   * doesn't already.
+   *
+   * Note: If the layer already existed it's possibly owned by another
+   * pipeline. If the layer is created then it will be owned by
+   * pipeline. */
+  layer = _cogl_pipeline_get_layer (pipeline, layer_index);
+
+  /* Now find the ancestor of the layer that is the authority for the
+   * state we want to change */
+  authority = _cogl_pipeline_layer_get_authority (layer, change);
+
+  if (target == authority->target)
+    return;
+
+  new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
+  if (new != layer)
+    layer = new;
+  else
+    {
+      /* If the original layer we found is currently the authority on
+       * the state we are changing see if we can revert to one of our
+       * ancestors being the authority. */
+      if (layer == authority &&
+          _cogl_pipeline_layer_get_parent (authority) != NULL)
+        {
+          CoglPipelineLayer *parent =
+            _cogl_pipeline_layer_get_parent (authority);
+          CoglPipelineLayer *old_authority =
+            _cogl_pipeline_layer_get_authority (parent, change);
+
+          if (old_authority->target == target)
+            {
+              layer->differences &= ~change;
+
+              g_assert (layer->owner == pipeline);
+              if (layer->differences == 0)
+                _cogl_pipeline_prune_empty_layer_difference (pipeline,
+                                                             layer);
+              goto changed;
+            }
+        }
+    }
+
+  layer->target = target;
+
+  /* If we weren't previously the authority on this state then we need
+   * to extended our differences mask and so it's possible that some
+   * of our ancestry will now become redundant, so we aim to reparent
+   * ourselves if that's true... */
+  if (layer != authority)
+    {
+      layer->differences |= change;
+      _cogl_pipeline_layer_prune_redundant_ancestry (layer);
+    }
+
+changed:
+
+  handle_automatic_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
+}
+
+static void
+_cogl_pipeline_set_layer_texture_data (CoglPipeline *pipeline,
+                                       int layer_index,
+                                       CoglHandle texture)
+{
+  CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
   CoglPipelineLayer *layer;
   CoglPipelineLayer *authority;
   CoglPipelineLayer *new;
@@ -2250,6 +2399,48 @@ changed:
   handle_automatic_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
 }
 
+/* A convenience for querying the target of a given texture that
+ * notably returns 0 for NULL textures - so we can say that a layer
+ * with no associated CoglTexture will have a texture target of 0.
+ */
+static GLenum
+get_texture_target (CoglHandle texture)
+{
+  GLuint ignore_handle;
+  GLenum gl_target;
+
+  if (texture)
+    cogl_texture_get_gl_texture (texture, &ignore_handle, &gl_target);
+  else
+    return 0;/* XXX: An invalid GL target enum */
+
+  return gl_target;
+}
+
+void
+cogl_pipeline_set_layer_texture (CoglPipeline *pipeline,
+                                 int layer_index,
+                                 CoglHandle texture)
+{
+  /* For the convenience of fragend code we separate texture state
+   * into the "target" and the "data", and setting a layer texture
+   * updates both of these properties.
+   *
+   * One example for why this is helpful is that the fragends may
+   * cache programs they generate and want to re-use those programs
+   * with all pipelines having equivalent fragment processing state.
+   * For the sake of determining if pipelines have equivalent fragment
+   * processing state we don't need to compare that the same
+   * underlying texture objects are referenced by the pipelines but we
+   * do need to see if they use the same texture targets. Making this
+   * distinction is much simpler if they are in different state
+   * groups.
+   */
+  _cogl_pipeline_set_layer_texture_target (pipeline, layer_index,
+                                           get_texture_target (texture));
+  _cogl_pipeline_set_layer_texture_data (pipeline, layer_index, texture);
+}
+
 typedef struct
 {
   int i;
@@ -2826,20 +3017,24 @@ _cogl_pipeline_apply_overrides (CoglPipeline *pipeline,
 }
 
 static gboolean
-_cogl_pipeline_layer_texture_equal (CoglPipelineLayer *authority0,
-                                    CoglPipelineLayer *authority1,
-                                    CoglPipelineEvalFlags flags)
+_cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0,
+                                           CoglPipelineLayer *authority1,
+                                           CoglPipelineEvalFlags flags)
+{
+  return authority0->target == authority1->target;
+}
+
+static gboolean
+_cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0,
+                                         CoglPipelineLayer *authority1,
+                                         CoglPipelineEvalFlags flags)
 {
   GLuint gl_handle0, gl_handle1;
-  GLenum gl_target0, gl_target1;
 
-  cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, &gl_target0);
-  cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, &gl_target1);
+  cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, NULL);
+  cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, NULL);
 
-  if (flags & COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA)
-    return (gl_target0 == gl_target1);
-  else
-    return (gl_handle0 == gl_handle1 && gl_target0 == gl_target1);
+  return gl_handle0 == gl_handle1;
 }
 
 /* Determine the mask of differences between two layers.
@@ -3106,13 +3301,23 @@ _cogl_pipeline_layer_equal (CoglPipelineLayer *layer0,
                                             layers_difference,
                                             authorities1);
 
-  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE)
+  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET)
     {
       CoglPipelineLayerStateIndex state_index =
-        COGL_PIPELINE_LAYER_STATE_TEXTURE_INDEX;
-      if (!_cogl_pipeline_layer_texture_equal (authorities0[state_index],
-                                               authorities1[state_index],
-                                               flags))
+        COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX;
+      if (!_cogl_pipeline_layer_texture_target_equal (authorities0[state_index],
+                                                      authorities1[state_index],
+                                                      flags))
+        return FALSE;
+    }
+
+  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
+    {
+      CoglPipelineLayerStateIndex state_index =
+        COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX;
+      if (!_cogl_pipeline_layer_texture_data_equal (authorities0[state_index],
+                                                    authorities1[state_index],
+                                                    flags))
         return FALSE;
     }
 
@@ -4723,7 +4928,7 @@ _cogl_pipeline_layer_free (CoglPipelineLayer *layer)
 {
   _cogl_pipeline_layer_unparent (COGL_PIPELINE_NODE (layer));
 
-  if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE &&
+  if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA &&
       layer->texture != COGL_INVALID_HANDLE)
     cogl_handle_unref (layer->texture);
 
@@ -4780,6 +4985,7 @@ _cogl_pipeline_init_default_layers (void)
   layer->unit_index = 0;
 
   layer->texture = COGL_INVALID_HANDLE;
+  layer->target = 0;
 
   layer->mag_filter = COGL_PIPELINE_FILTER_LINEAR;
   layer->min_filter = COGL_PIPELINE_FILTER_LINEAR;
@@ -5058,6 +5264,7 @@ cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline,
   CoglPipelineLayer     *layer;
   CoglPipelineLayer     *authority;
   CoglPipelineLayer     *new;
+  float                  color_as_floats[4];
 
   g_return_if_fail (cogl_is_pipeline (pipeline));
 
@@ -5073,8 +5280,13 @@ cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline,
    * state we want to change */
   authority = _cogl_pipeline_layer_get_authority (layer, state);
 
+  color_as_floats[0] = cogl_color_get_red_float (constant_color);
+  color_as_floats[1] = cogl_color_get_green_float (constant_color);
+  color_as_floats[2] = cogl_color_get_blue_float (constant_color);
+  color_as_floats[3] = cogl_color_get_alpha_float (constant_color);
+
   if (memcmp (authority->big_state->texture_combine_constant,
-              constant_color, sizeof (float) * 4) == 0)
+              color_as_floats, sizeof (float) * 4) == 0)
     return;
 
   new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
@@ -5095,7 +5307,7 @@ cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline,
           CoglPipelineLayerBigState *old_big_state = old_authority->big_state;
 
           if (memcmp (old_big_state->texture_combine_constant,
-                      constant_color, sizeof (float) * 4) == 0)
+                      color_as_floats, sizeof (float) * 4) == 0)
             {
               layer->differences &= ~state;
 
@@ -5108,14 +5320,9 @@ cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline,
         }
     }
 
-  layer->big_state->texture_combine_constant[0] =
-    cogl_color_get_red_float (constant_color);
-  layer->big_state->texture_combine_constant[1] =
-    cogl_color_get_green_float (constant_color);
-  layer->big_state->texture_combine_constant[2] =
-    cogl_color_get_blue_float (constant_color);
-  layer->big_state->texture_combine_constant[3] =
-    cogl_color_get_alpha_float (constant_color);
+  memcpy (layer->big_state->texture_combine_constant,
+          color_as_floats,
+          sizeof (color_as_floats));
 
   /* If we weren't previously the authority on this state then we need
    * to extended our differences mask and so it's possible that some
@@ -5440,7 +5647,7 @@ _cogl_pipeline_layer_pre_paint (CoglPipelineLayer *layer)
 
   texture_authority =
     _cogl_pipeline_layer_get_authority (layer,
-                                        COGL_PIPELINE_LAYER_STATE_TEXTURE);
+                                        COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
 
   if (texture_authority->texture != COGL_INVALID_HANDLE)
     {
@@ -5679,22 +5886,27 @@ _cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority,
 }
 
 static void
-_cogl_pipeline_layer_hash_texture_state (CoglPipelineLayer *authority,
-                                         CoglPipelineLayer **authorities,
-                                         HashState *state)
+_cogl_pipeline_layer_hash_texture_target_state (CoglPipelineLayer *authority,
+                                                CoglPipelineLayer **authorities,
+                                                HashState *state)
 {
-  GLuint gl_handle;
-  GLenum gl_target;
-  unsigned long hash = state->hash;
+  GLenum gl_target = authority->target;
 
-  cogl_texture_get_gl_texture (authority->texture, &gl_handle, &gl_target);
+  state->hash =
+    _cogl_util_one_at_a_time_hash (state->hash, &gl_target, sizeof (gl_target));
+}
 
-  hash = _cogl_util_one_at_a_time_hash (hash, &gl_target, sizeof (gl_target));
+static void
+_cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority,
+                                              CoglPipelineLayer **authorities,
+                                              HashState *state)
+{
+  GLuint gl_handle;
 
-  if (!(state->flags & COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA))
-    hash = _cogl_util_one_at_a_time_hash (hash, &gl_handle, sizeof (gl_handle));
+  cogl_texture_get_gl_texture (authority->texture, &gl_handle, NULL);
 
-  state->hash = hash;
+  state->hash =
+    _cogl_util_one_at_a_time_hash (state->hash, &gl_handle, sizeof (gl_handle));
 }
 
 static void
@@ -5782,11 +5994,11 @@ _cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority,
   n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func);
   for (i = 0; i < n_args; i++)
     {
-      if (b->texture_combine_rgb_src[i] == GL_CONSTANT_COLOR ||
-          b->texture_combine_rgb_src[i] == GL_CONSTANT_ALPHA)
+      if (b->texture_combine_rgb_src[i] ==
+          COGL_PIPELINE_COMBINE_SOURCE_CONSTANT)
         {
           /* XXX: should we be careful to only hash the alpha
-           * component in the GL_CONSTANT_ALPHA case? */
+           * component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */
           need_hash = TRUE;
           goto done;
         }
@@ -5795,11 +6007,11 @@ _cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority,
   n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func);
   for (i = 0; i < n_args; i++)
     {
-      if (b->texture_combine_alpha_src[i] == GL_CONSTANT_COLOR ||
-          b->texture_combine_alpha_src[i] == GL_CONSTANT_ALPHA)
+      if (b->texture_combine_alpha_src[i] ==
+          COGL_PIPELINE_COMBINE_SOURCE_CONSTANT)
         {
           /* XXX: should we be careful to only hash the alpha
-           * component in the GL_CONSTANT_ALPHA case? */
+           * component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */
           need_hash = TRUE;
           goto done;
         }
@@ -5851,8 +6063,10 @@ _cogl_pipeline_init_layer_state_hash_functions (void)
   CoglPipelineLayerStateIndex _index;
   layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_UNIT_INDEX] =
     _cogl_pipeline_layer_hash_unit_state;
-  layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_TEXTURE_INDEX] =
-    _cogl_pipeline_layer_hash_texture_state;
+  layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX] =
+    _cogl_pipeline_layer_hash_texture_target_state;
+  layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX] =
+    _cogl_pipeline_layer_hash_texture_data_state;
   layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX] =
     _cogl_pipeline_layer_hash_filters_state;
   layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX] =
@@ -5868,7 +6082,7 @@ _cogl_pipeline_init_layer_state_hash_functions (void)
     _cogl_pipeline_layer_hash_point_sprite_state;
 
   /* So we get a big error if we forget to update this code! */
-  g_assert (COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT == 8);
+  g_assert (COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT == 9);
 }
 
 static gboolean
@@ -6229,7 +6443,7 @@ dump_layer_cb (CoglPipelineNode *node, void *user_data)
                               layer->unit_index);
     }
 
-  if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE)
+  if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
     {
       changes = TRUE;
       g_string_append_printf (changes_label,
@@ -6514,43 +6728,6 @@ _cogl_pipeline_need_texture_combine_separate
    return FALSE;
 }
 
-static gboolean
-layers_differ_for_find_equivalent (CoglPipelineLayerState layer_state,
-                                   CoglPipelineFindEquivalentFlags flags,
-                                   CoglPipelineLayer *layer0,
-                                   CoglPipelineLayer *layer1)
-{
-  unsigned long layer_differences;
-
-  if (layer0 == layer1)
-    return FALSE;
-
-  layer_differences =
-    _cogl_pipeline_layer_compare_differences (layer0, layer1);
-
-  if (layer_differences & layer_state)
-    return TRUE;
-
-  /* When generating a shader we need to detect when the texture
-     target changes but we don't care if the texture object
-     changes so we have a flag to handle this special case */
-  if ((flags & COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET) &&
-      (layer_differences & COGL_PIPELINE_LAYER_STATE_TEXTURE))
-    {
-      CoglHandle tex0 = _cogl_pipeline_layer_get_texture (layer0);
-      CoglHandle tex1 = _cogl_pipeline_layer_get_texture (layer1);
-      GLenum gl_target0;
-      GLenum gl_target1;
-
-      cogl_texture_get_gl_texture (tex0, NULL, &gl_target0);
-      cogl_texture_get_gl_texture (tex1, NULL, &gl_target1);
-      if (gl_target0 != gl_target1)
-        return TRUE;
-    }
-
-  return FALSE;
-}
-
 /* This tries to find the oldest ancestor whose pipeline and layer
    state matches the given flags. This is mostly used to detect code
    gen authorities so that we can reduce the numer of programs
@@ -6558,8 +6735,7 @@ layers_differ_for_find_equivalent (CoglPipelineLayerState layer_state,
 CoglPipeline *
 _cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline,
                                        CoglPipelineState pipeline_state,
-                                       CoglPipelineLayerState layer_state,
-                                       CoglPipelineFindEquivalentFlags flags)
+                                       CoglPipelineLayerState layer_state)
 {
   CoglPipeline *authority0;
   CoglPipeline *authority1;
@@ -6619,10 +6795,19 @@ _cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline,
                                              &state);
 
       for (i = 0; i < n_layers; i++)
-        if (layers_differ_for_find_equivalent (layer_state, flags,
-                                               authority0_layers[i],
-                                               authority1_layers[i]))
-          return authority0;
+        {
+          unsigned long layer_differences;
+
+          if (authority0_layers[i] == authority1_layers[i])
+            continue;
+
+          layer_differences =
+            _cogl_pipeline_layer_compare_differences (authority0_layers[i],
+                                                      authority1_layers[i]);
+
+          if (layer_differences & layer_state)
+            return authority0;
+        }
 
       /* Find the next ancestor after that, that also modifies state
        * affecting codegen... */
diff --git a/clutter/cogl/cogl/cogl-point-in-poly-private.h b/clutter/cogl/cogl/cogl-point-in-poly-private.h
new file mode 100644 (file)
index 0000000..0cebdf8
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __COGL_POINT_INT_POLYGON_PRIVATE_H
+#define __COGL_POINT_INT_POLYGON_PRIVATE_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+int
+_cogl_util_point_in_poly (float point_x,
+                          float point_y,
+                          void *vertices,
+                          size_t stride,
+                          int n_vertices);
+
+G_END_DECLS
+
+#endif /* __COGL_POINT_INT_POLYGON_PRIVATE_H */
+
diff --git a/clutter/cogl/cogl/cogl-point-in-poly.c b/clutter/cogl/cogl/cogl-point-in-poly.c
new file mode 100644 (file)
index 0000000..fc38d1d
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Point Inclusion in Polygon Test
+ *
+ * Copyright (c) 1970-2003, Wm. Randolph Franklin
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimers.
+ *    2. Redistributions in binary form must reproduce the above
+ *    copyright notice in the documentation and/or other materials
+ *    provided with the distribution.
+ * 3. The name of W. Randolph Franklin may not be used to endorse or
+ *    promote products derived from this Software without specific
+ *    prior written permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Note:
+ * The algorithm for this point_in_poly() function was learnt from:
+ * http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib.h>
+
+int
+_cogl_util_point_in_poly (float point_x,
+                          float point_y,
+                          void *vertices,
+                          size_t stride,
+                          int n_vertices)
+{
+  int i, j, c = 0;
+
+  for (i = 0, j = n_vertices - 1; i < n_vertices; j = i++)
+    {
+      float vert_xi = *(float *)((guint8 *)vertices + i * stride);
+      float vert_xj = *(float *)((guint8 *)vertices + j * stride);
+      float vert_yi = *(float *)((guint8 *)vertices + i * stride +
+                                 sizeof (float));
+      float vert_yj = *(float *)((guint8 *)vertices + j * stride +
+                                 sizeof (float));
+
+      if (((vert_yi > point_y) != (vert_yj > point_y)) &&
+           (point_x < (vert_xj - vert_xi) * (point_y - vert_yi) /
+            (vert_yj - vert_yi) + vert_xi) )
+         c = !c;
+    }
+
+  return c;
+}
+
index 2edac5f..9b76241 100644 (file)
@@ -32,7 +32,7 @@
 #include "cogl-object-private.h"
 #include "cogl-primitive.h"
 #include "cogl-primitive-private.h"
-#include "cogl-vertex-attribute-private.h"
+#include "cogl-attribute-private.h"
 
 #include <stdarg.h>
 
@@ -44,7 +44,7 @@ COGL_OBJECT_DEFINE (Primitive, primitive);
 CoglPrimitive *
 cogl_primitive_new_with_attributes_array (CoglVerticesMode mode,
                                           int n_vertices,
-                                          CoglVertexAttribute **attributes)
+                                          CoglAttribute **attributes)
 {
   CoglPrimitive *primitive = g_slice_new (CoglPrimitive);
   int i;
@@ -54,15 +54,15 @@ cogl_primitive_new_with_attributes_array (CoglVerticesMode mode,
   primitive->n_vertices = n_vertices;
   primitive->indices = NULL;
   primitive->attributes =
-    g_array_new (TRUE, FALSE, sizeof (CoglVertexAttribute *));
+    g_array_new (TRUE, FALSE, sizeof (CoglAttribute *));
   primitive->immutable_ref = 0;
 
   for (i = 0; attributes[i]; i++)
     {
-      CoglVertexAttribute *attribute = attributes[i];
+      CoglAttribute *attribute = attributes[i];
       cogl_object_ref (attribute);
 
-      g_return_val_if_fail (cogl_is_vertex_attribute (attribute), NULL);
+      g_return_val_if_fail (cogl_is_attribute (attribute), NULL);
 
       g_array_append_val (primitive->attributes, attribute);
     }
@@ -74,10 +74,9 @@ cogl_primitive_new_with_attributes_array (CoglVerticesMode mode,
    new_with_attributes that also unrefs the attributes. It is just
    used for the builtin struct constructors */
 static CoglPrimitive *
-_cogl_primitive_new_with_attributes_array_unref
-                               (CoglVerticesMode mode,
-                                int n_vertices,
-                                CoglVertexAttribute **attributes)
+_cogl_primitive_new_with_attributes_array_unref (CoglVerticesMode mode,
+                                                 int n_vertices,
+                                                 CoglAttribute **attributes)
 {
   CoglPrimitive *primitive;
   int i;
@@ -99,20 +98,20 @@ cogl_primitive_new (CoglVerticesMode mode,
 {
   va_list ap;
   int n_attributes;
-  CoglVertexAttribute **attributes;
+  CoglAttribute **attributes;
   int i;
-  CoglVertexAttribute *attribute;
+  CoglAttribute *attribute;
 
   va_start (ap, n_vertices);
-  for (n_attributes = 0; va_arg (ap, CoglVertexAttribute *); n_attributes++)
+  for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++)
     ;
   va_end (ap);
 
-  attributes = g_alloca (sizeof (CoglVertexAttribute *) * (n_attributes + 1));
+  attributes = g_alloca (sizeof (CoglAttribute *) * (n_attributes + 1));
   attributes[n_attributes] = NULL;
 
   va_start (ap, n_vertices);
-  for (i = 0; (attribute = va_arg (ap, CoglVertexAttribute *)); i++)
+  for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++)
     attributes[i] = attribute;
   va_end (ap);
 
@@ -123,19 +122,18 @@ cogl_primitive_new (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p2 (CoglVerticesMode mode,
                        int n_vertices,
-                       const CoglP2Vertex *data)
+                       const CoglVertexP2 *data)
 {
   CoglVertexArray *array =
-    cogl_vertex_array_new (n_vertices * sizeof (CoglP2Vertex), data);
-  CoglVertexAttribute *attributes[2];
-
-  attributes[0] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_position_in",
-                               sizeof (CoglP2Vertex),
-                               offsetof (CoglP2Vertex, x),
-                               2,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
+    cogl_vertex_array_new (n_vertices * sizeof (CoglVertexP2), data);
+  CoglAttribute *attributes[2];
+
+  attributes[0] = cogl_attribute_new (array,
+                                      "cogl_position_in",
+                                      sizeof (CoglVertexP2),
+                                      offsetof (CoglVertexP2, x),
+                                      2,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
   attributes[1] = NULL;
 
   cogl_object_unref (array);
@@ -147,19 +145,18 @@ cogl_primitive_new_p2 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p3 (CoglVerticesMode mode,
                        int n_vertices,
-                       const CoglP3Vertex *data)
+                       const CoglVertexP3 *data)
 {
   CoglVertexArray *array =
-    cogl_vertex_array_new (n_vertices * sizeof (CoglP3Vertex), data);
-  CoglVertexAttribute *attributes[2];
-
-  attributes[0] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_position_in",
-                               sizeof (CoglP3Vertex),
-                               offsetof (CoglP3Vertex, x),
-                               3,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
+    cogl_vertex_array_new (n_vertices * sizeof (CoglVertexP3), data);
+  CoglAttribute *attributes[2];
+
+  attributes[0] = cogl_attribute_new (array,
+                                      "cogl_position_in",
+                                      sizeof (CoglVertexP3),
+                                      offsetof (CoglVertexP3, x),
+                                      3,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
   attributes[1] = NULL;
 
   cogl_object_unref (array);
@@ -171,26 +168,24 @@ cogl_primitive_new_p3 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p2c4 (CoglVerticesMode mode,
                          int n_vertices,
-                         const CoglP2C4Vertex *data)
+                         const CoglVertexP2C4 *data)
 {
   CoglVertexArray *array =
-    cogl_vertex_array_new (n_vertices * sizeof (CoglP2C4Vertex), data);
-  CoglVertexAttribute *attributes[3];
-
-  attributes[0] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_position_in",
-                               sizeof (CoglP2C4Vertex),
-                               offsetof (CoglP2C4Vertex, x),
-                               2,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
-  attributes[1] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_color_in",
-                               sizeof (CoglP2C4Vertex),
-                               offsetof (CoglP2C4Vertex, r),
-                               4,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
+    cogl_vertex_array_new (n_vertices * sizeof (CoglVertexP2C4), data);
+  CoglAttribute *attributes[3];
+
+  attributes[0] = cogl_attribute_new (array,
+                                      "cogl_position_in",
+                                      sizeof (CoglVertexP2C4),
+                                      offsetof (CoglVertexP2C4, x),
+                                      2,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
+  attributes[1] = cogl_attribute_new (array,
+                                      "cogl_color_in",
+                                      sizeof (CoglVertexP2C4),
+                                      offsetof (CoglVertexP2C4, r),
+                                      4,
+                                      COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
   attributes[2] = NULL;
 
   cogl_object_unref (array);
@@ -202,26 +197,24 @@ cogl_primitive_new_p2c4 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p3c4 (CoglVerticesMode mode,
                          int n_vertices,
-                         const CoglP3C4Vertex *data)
+                         const CoglVertexP3C4 *data)
 {
   CoglVertexArray *array =
-    cogl_vertex_array_new (n_vertices * sizeof (CoglP3C4Vertex), data);
-  CoglVertexAttribute *attributes[3];
-
-  attributes[0] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_position_in",
-                               sizeof (CoglP3C4Vertex),
-                               offsetof (CoglP3C4Vertex, x),
-                               3,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
-  attributes[1] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_color_in",
-                               sizeof (CoglP3C4Vertex),
-                               offsetof (CoglP3C4Vertex, r),
-                               4,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
+    cogl_vertex_array_new (n_vertices * sizeof (CoglVertexP3C4), data);
+  CoglAttribute *attributes[3];
+
+  attributes[0] = cogl_attribute_new (array,
+                                      "cogl_position_in",
+                                      sizeof (CoglVertexP3C4),
+                                      offsetof (CoglVertexP3C4, x),
+                                      3,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
+  attributes[1] = cogl_attribute_new (array,
+                                      "cogl_color_in",
+                                      sizeof (CoglVertexP3C4),
+                                      offsetof (CoglVertexP3C4, r),
+                                      4,
+                                      COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
   attributes[2] = NULL;
 
   cogl_object_unref (array);
@@ -233,26 +226,24 @@ cogl_primitive_new_p3c4 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p2t2 (CoglVerticesMode mode,
                          int n_vertices,
-                         const CoglP2T2Vertex *data)
+                         const CoglVertexP2T2 *data)
 {
   CoglVertexArray *array =
-    cogl_vertex_array_new (n_vertices * sizeof (CoglP2T2Vertex), data);
-  CoglVertexAttribute *attributes[3];
-
-  attributes[0] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_position_in",
-                               sizeof (CoglP2T2Vertex),
-                               offsetof (CoglP2T2Vertex, x),
-                               2,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
-  attributes[1] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_tex_coord0_in",
-                               sizeof (CoglP2T2Vertex),
-                               offsetof (CoglP2T2Vertex, s),
-                               2,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
+    cogl_vertex_array_new (n_vertices * sizeof (CoglVertexP2T2), data);
+  CoglAttribute *attributes[3];
+
+  attributes[0] = cogl_attribute_new (array,
+                                      "cogl_position_in",
+                                      sizeof (CoglVertexP2T2),
+                                      offsetof (CoglVertexP2T2, x),
+                                      2,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
+  attributes[1] = cogl_attribute_new (array,
+                                      "cogl_tex_coord0_in",
+                                      sizeof (CoglVertexP2T2),
+                                      offsetof (CoglVertexP2T2, s),
+                                      2,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
   attributes[2] = NULL;
 
   cogl_object_unref (array);
@@ -264,26 +255,24 @@ cogl_primitive_new_p2t2 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p3t2 (CoglVerticesMode mode,
                          int n_vertices,
-                         const CoglP3T2Vertex *data)
+                         const CoglVertexP3T2 *data)
 {
   CoglVertexArray *array =
-    cogl_vertex_array_new (n_vertices * sizeof (CoglP3T2Vertex), data);
-  CoglVertexAttribute *attributes[3];
-
-  attributes[0] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_position_in",
-                               sizeof (CoglP3T2Vertex),
-                               offsetof (CoglP3T2Vertex, x),
-                               3,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
-  attributes[1] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_tex_coord0_in",
-                               sizeof (CoglP3T2Vertex),
-                               offsetof (CoglP3T2Vertex, s),
-                               2,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
+    cogl_vertex_array_new (n_vertices * sizeof (CoglVertexP3T2), data);
+  CoglAttribute *attributes[3];
+
+  attributes[0] = cogl_attribute_new (array,
+                                      "cogl_position_in",
+                                      sizeof (CoglVertexP3T2),
+                                      offsetof (CoglVertexP3T2, x),
+                                      3,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
+  attributes[1] = cogl_attribute_new (array,
+                                      "cogl_tex_coord0_in",
+                                      sizeof (CoglVertexP3T2),
+                                      offsetof (CoglVertexP3T2, s),
+                                      2,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
   attributes[2] = NULL;
 
   cogl_object_unref (array);
@@ -295,33 +284,30 @@ cogl_primitive_new_p3t2 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p2t2c4 (CoglVerticesMode mode,
                            int n_vertices,
-                           const CoglP2T2C4Vertex *data)
+                           const CoglVertexP2T2C4 *data)
 {
   CoglVertexArray *array =
-    cogl_vertex_array_new (n_vertices * sizeof (CoglP2T2C4Vertex), data);
-  CoglVertexAttribute *attributes[4];
-
-  attributes[0] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_position_in",
-                               sizeof (CoglP2T2C4Vertex),
-                               offsetof (CoglP2T2C4Vertex, x),
-                               2,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
-  attributes[1] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_tex_coord0_in",
-                               sizeof (CoglP2T2C4Vertex),
-                               offsetof (CoglP2T2C4Vertex, s),
-                               2,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
-  attributes[2] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_color_in",
-                               sizeof (CoglP2T2C4Vertex),
-                               offsetof (CoglP2T2C4Vertex, r),
-                               4,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
+    cogl_vertex_array_new (n_vertices * sizeof (CoglVertexP2T2C4), data);
+  CoglAttribute *attributes[4];
+
+  attributes[0] = cogl_attribute_new (array,
+                                      "cogl_position_in",
+                                      sizeof (CoglVertexP2T2C4),
+                                      offsetof (CoglVertexP2T2C4, x),
+                                      2,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
+  attributes[1] = cogl_attribute_new (array,
+                                      "cogl_tex_coord0_in",
+                                      sizeof (CoglVertexP2T2C4),
+                                      offsetof (CoglVertexP2T2C4, s),
+                                      2,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
+  attributes[2] = cogl_attribute_new (array,
+                                      "cogl_color_in",
+                                      sizeof (CoglVertexP2T2C4),
+                                      offsetof (CoglVertexP2T2C4, r),
+                                      4,
+                                      COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
   attributes[3] = NULL;
 
   cogl_object_unref (array);
@@ -333,33 +319,30 @@ cogl_primitive_new_p2t2c4 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p3t2c4 (CoglVerticesMode mode,
                            int n_vertices,
-                           const CoglP3T2C4Vertex *data)
+                           const CoglVertexP3T2C4 *data)
 {
   CoglVertexArray *array =
-    cogl_vertex_array_new (n_vertices * sizeof (CoglP3T2C4Vertex), data);
-  CoglVertexAttribute *attributes[4];
-
-  attributes[0] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_position_in",
-                               sizeof (CoglP3T2C4Vertex),
-                               offsetof (CoglP3T2C4Vertex, x),
-                               3,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
-  attributes[1] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_tex_coord0_in",
-                               sizeof (CoglP3T2C4Vertex),
-                               offsetof (CoglP3T2C4Vertex, s),
-                               2,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
-  attributes[2] =
-    cogl_vertex_attribute_new (array,
-                               "cogl_color_in",
-                               sizeof (CoglP3T2C4Vertex),
-                               offsetof (CoglP3T2C4Vertex, r),
-                               4,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
+    cogl_vertex_array_new (n_vertices * sizeof (CoglVertexP3T2C4), data);
+  CoglAttribute *attributes[4];
+
+  attributes[0] = cogl_attribute_new (array,
+                                      "cogl_position_in",
+                                      sizeof (CoglVertexP3T2C4),
+                                      offsetof (CoglVertexP3T2C4, x),
+                                      3,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
+  attributes[1] = cogl_attribute_new (array,
+                                      "cogl_tex_coord0_in",
+                                      sizeof (CoglVertexP3T2C4),
+                                      offsetof (CoglVertexP3T2C4, s),
+                                      2,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
+  attributes[2] = cogl_attribute_new (array,
+                                      "cogl_color_in",
+                                      sizeof (CoglVertexP3T2C4),
+                                      offsetof (CoglVertexP3T2C4, r),
+                                      4,
+                                      COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
   attributes[3] = NULL;
 
   cogl_object_unref (array);
@@ -375,8 +358,8 @@ free_attributes_list (CoglPrimitive *primitive)
 
   for (i = 0; i < primitive->attributes->len; i++)
     {
-      CoglVertexAttribute *attribute =
-        g_array_index (primitive->attributes, CoglVertexAttribute *, i);
+      CoglAttribute *attribute =
+        g_array_index (primitive->attributes, CoglAttribute *, i);
       cogl_object_unref (attribute);
     }
   g_array_set_size (primitive->attributes, 0);
@@ -406,7 +389,7 @@ warn_about_midscene_changes (void)
 
 void
 cogl_primitive_set_attributes (CoglPrimitive *primitive,
-                               CoglVertexAttribute **attributes)
+                               CoglAttribute **attributes)
 {
   int i;
 
@@ -424,7 +407,7 @@ cogl_primitive_set_attributes (CoglPrimitive *primitive,
   for (i = 0; attributes[i]; i++)
     {
       cogl_object_ref (attributes[i]);
-      g_return_if_fail (cogl_is_vertex_attribute (attributes[i]));
+      g_return_if_fail (cogl_is_attribute (attributes[i]));
       g_array_append_val (primitive->attributes, attributes[i]);
     }
 }
@@ -522,9 +505,9 @@ _cogl_primitive_immutable_ref (CoglPrimitive *primitive)
 
   for (i = 0; i < primitive->attributes->len; i++)
     {
-      CoglVertexAttribute *attribute =
-        g_array_index (primitive->attributes, CoglVertexAttribute *, i);
-      _cogl_vertex_attribute_immutable_ref (attribute);
+      CoglAttribute *attribute =
+        g_array_index (primitive->attributes, CoglAttribute *, i);
+      _cogl_attribute_immutable_ref (attribute);
     }
 
   return primitive;
@@ -542,9 +525,9 @@ _cogl_primitive_immutable_unref (CoglPrimitive *primitive)
 
   for (i = 0; i < primitive->attributes->len; i++)
     {
-      CoglVertexAttribute *attribute =
-        g_array_index (primitive->attributes, CoglVertexAttribute *, i);
-      _cogl_vertex_attribute_immutable_unref (attribute);
+      CoglAttribute *attribute =
+        g_array_index (primitive->attributes, CoglAttribute *, i);
+      _cogl_attribute_immutable_unref (attribute);
     }
 }
 
@@ -552,19 +535,19 @@ _cogl_primitive_immutable_unref (CoglPrimitive *primitive)
 void
 cogl_primitive_draw (CoglPrimitive *primitive)
 {
-  CoglVertexAttribute **attributes =
-    (CoglVertexAttribute **)primitive->attributes->data;
+  CoglAttribute **attributes =
+    (CoglAttribute **)primitive->attributes->data;
 
   if (primitive->indices)
-    cogl_draw_indexed_vertex_attributes_array (primitive->mode,
-                                               primitive->first_vertex,
-                                               primitive->n_vertices,
-                                               primitive->indices,
-                                               attributes);
+    cogl_draw_indexed_attributes_array (primitive->mode,
+                                        primitive->first_vertex,
+                                        primitive->n_vertices,
+                                        primitive->indices,
+                                        attributes);
   else
-    cogl_draw_vertex_attributes_array (primitive->mode,
-                                       primitive->first_vertex,
-                                       primitive->n_vertices,
-                                       attributes);
+    cogl_draw_attributes_array (primitive->mode,
+                                primitive->first_vertex,
+                                primitive->n_vertices,
+                                attributes);
 }
 
index d2eaa53..d286841 100644 (file)
@@ -32,7 +32,7 @@
 #define __COGL_PRIMITIVE_H__
 
 #include <cogl/cogl-vertex-buffer.h> /* for CoglVerticesMode */
-#include <cogl/cogl-vertex-attribute.h>
+#include <cogl/cogl-attribute.h>
 
 G_BEGIN_DECLS
 
@@ -47,7 +47,7 @@ G_BEGIN_DECLS
 typedef struct _CoglPrimitive CoglPrimitive;
 
 /**
- * CoglP2Vertex:
+ * CoglVertexP2:
  * @x: The x component of a position attribute
  * @y: The y component of a position attribute
  *
@@ -60,10 +60,10 @@ typedef struct _CoglPrimitive CoglPrimitive;
 typedef struct
 {
    float x, y;
-} CoglP2Vertex;
+} CoglVertexP2;
 
 /**
- * CoglP3Vertex:
+ * CoglVertexP3:
  * @x: The x component of a position attribute
  * @y: The y component of a position attribute
  * @z: The z component of a position attribute
@@ -77,10 +77,10 @@ typedef struct
 typedef struct
 {
    float x, y, z;
-} CoglP3Vertex;
+} CoglVertexP3;
 
 /**
- * CoglP2C4Vertex:
+ * CoglVertexP2C4:
  * @x: The x component of a position attribute
  * @y: The y component of a position attribute
  * @r: The red component of a color attribute
@@ -98,10 +98,10 @@ typedef struct
 {
    float x, y;
    guint8 r, g, b, a;
-} CoglP2C4Vertex;
+} CoglVertexP2C4;
 
 /**
- * CoglP3C4Vertex:
+ * CoglVertexP3C4:
  * @x: The x component of a position attribute
  * @y: The y component of a position attribute
  * @z: The z component of a position attribute
@@ -120,10 +120,10 @@ typedef struct
 {
    float x, y, z;
    guint8 r, g, b, a;
-} CoglP3C4Vertex;
+} CoglVertexP3C4;
 
 /**
- * CoglP2T2Vertex:
+ * CoglVertexP2T2:
  * @x: The x component of a position attribute
  * @y: The y component of a position attribute
  * @s: The s component of a texture coordinate attribute
@@ -139,10 +139,10 @@ typedef struct
 {
    float x, y;
    float s, t;
-} CoglP2T2Vertex;
+} CoglVertexP2T2;
 
 /**
- * CoglP3T2Vertex:
+ * CoglVertexP3T2:
  * @x: The x component of a position attribute
  * @y: The y component of a position attribute
  * @z: The z component of a position attribute
@@ -159,11 +159,11 @@ typedef struct
 {
    float x, y, z;
    float s, t;
-} CoglP3T2Vertex;
+} CoglVertexP3T2;
 
 
 /**
- * CoglP2T2C4Vertex:
+ * CoglVertexP2T2C4:
  * @x: The x component of a position attribute
  * @y: The y component of a position attribute
  * @s: The s component of a texture coordinate attribute
@@ -184,10 +184,10 @@ typedef struct
    float x, y;
    float s, t;
    guint8 r, g, b, a;
-} CoglP2T2C4Vertex;
+} CoglVertexP2T2C4;
 
 /**
- * CoglP3T2C4Vertex:
+ * CoglVertexP3T2C4:
  * @x: The x component of a position attribute
  * @y: The y component of a position attribute
  * @z: The z component of a position attribute
@@ -209,7 +209,7 @@ typedef struct
    float x, y, z;
    float s, t;
    guint8 r, g, b, a;
-} CoglP3T2C4Vertex;
+} CoglVertexP3T2C4;
 
 /**
  * cogl_primitive_new:
@@ -217,7 +217,7 @@ typedef struct
  * @n_vertices: The number of vertices to process when drawing
  * @Varargs: A %NULL terminated list of attributes
  *
- * Combines a set of #CoglVertexAttribute<!-- -->s with a specific draw @mode
+ * Combines a set of #CoglAttribute<!-- -->s with a specific draw @mode
  * and defines a vertex count so a #CoglPrimitive object can be retained and
  * drawn later with no addition information required.
  *
@@ -235,22 +235,22 @@ cogl_primitive_new (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_with_attributes_array (CoglVerticesMode mode,
                                           int n_vertices,
-                                          CoglVertexAttribute **attributes);
+                                          CoglAttribute **attributes);
 
 /**
  * cogl_primitive_new_p2:
  * @mode: A #CoglVerticesMode defining how to draw the vertices
  * @n_vertices: The number of vertices to process when drawing
- * @data: An array of #CoglP2Vertex vertices
+ * @data: An array of #CoglVertexP2 vertices
  *
  * Provides a convenient way to describe a primitive, such as a single
  * triangle strip or a triangle fan, that will internally allocate the
  * necessary #CoglVertexArray storage, describe the position
- * attribute with a #CoglVertexAttribute and upload your data.
+ * attribute with a #CoglAttribute and upload your data.
  *
  * For example to draw a convex polygon you can do:
  * |[
- * CoglP2Vertex triangle[] =
+ * CoglVertexP2 triangle[] =
  * {
  *   { 0,   300 },
  *   { 150, 0,  },
@@ -279,22 +279,22 @@ cogl_primitive_new_with_attributes_array (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p2 (CoglVerticesMode mode,
                        int n_vertices,
-                       const CoglP2Vertex *data);
+                       const CoglVertexP2 *data);
 
 /**
  * cogl_primitive_new_p3:
  * @mode: A #CoglVerticesMode defining how to draw the vertices
  * @n_vertices: The number of vertices to process when drawing
- * @data: An array of #CoglP3Vertex vertices
+ * @data: An array of #CoglVertexP3 vertices
  *
  * Provides a convenient way to describe a primitive, such as a single
  * triangle strip or a triangle fan, that will internally allocate the
  * necessary #CoglVertexArray storage, describe the position
- * attribute with a #CoglVertexAttribute and upload your data.
+ * attribute with a #CoglAttribute and upload your data.
  *
  * For example to draw a convex polygon you can do:
  * |[
- * CoglP3Vertex triangle[] =
+ * CoglVertexP3 triangle[] =
  * {
  *   { 0,   300, 0 },
  *   { 150, 0,   0 },
@@ -323,24 +323,24 @@ cogl_primitive_new_p2 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p3 (CoglVerticesMode mode,
                        int n_vertices,
-                       const CoglP3Vertex *data);
+                       const CoglVertexP3 *data);
 
 /**
  * cogl_primitive_new_p2c4:
  * @mode: A #CoglVerticesMode defining how to draw the vertices
  * @n_vertices: The number of vertices to process when drawing
- * @data: An array of #CoglP2C4Vertex vertices
+ * @data: An array of #CoglVertexP2C4 vertices
  *
  * Provides a convenient way to describe a primitive, such as a single
  * triangle strip or a triangle fan, that will internally allocate the
  * necessary #CoglVertexArray storage, describe the position
- * and color attributes with #CoglVertexAttribute<!-- -->s and upload
+ * and color attributes with #CoglAttribute<!-- -->s and upload
  * your data.
  *
  * For example to draw a convex polygon with a linear gradient you
  * can do:
  * |[
- * CoglP2C4Vertex triangle[] =
+ * CoglVertexP2C4 triangle[] =
  * {
  *   { 0,   300,  0xff, 0x00, 0x00, 0xff },
  *   { 150, 0,    0x00, 0xff, 0x00, 0xff },
@@ -369,24 +369,24 @@ cogl_primitive_new_p3 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p2c4 (CoglVerticesMode mode,
                          int n_vertices,
-                         const CoglP2C4Vertex *data);
+                         const CoglVertexP2C4 *data);
 
 /**
  * cogl_primitive_new_p3c4:
  * @mode: A #CoglVerticesMode defining how to draw the vertices
  * @n_vertices: The number of vertices to process when drawing
- * @data: An array of #CoglP3C4Vertex vertices
+ * @data: An array of #CoglVertexP3C4 vertices
  *
  * Provides a convenient way to describe a primitive, such as a single
  * triangle strip or a triangle fan, that will internally allocate the
  * necessary #CoglVertexArray storage, describe the position
- * and color attributes with #CoglVertexAttribute<!-- -->s and upload
+ * and color attributes with #CoglAttribute<!-- -->s and upload
  * your data.
  *
  * For example to draw a convex polygon with a linear gradient you
  * can do:
  * |[
- * CoglP3C4Vertex triangle[] =
+ * CoglVertexP3C4 triangle[] =
  * {
  *   { 0,   300, 0,  0xff, 0x00, 0x00, 0xff },
  *   { 150, 0,   0,  0x00, 0xff, 0x00, 0xff },
@@ -415,24 +415,24 @@ cogl_primitive_new_p2c4 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p3c4 (CoglVerticesMode mode,
                          int n_vertices,
-                         const CoglP3C4Vertex *data);
+                         const CoglVertexP3C4 *data);
 
 /**
  * cogl_primitive_new_p2t2:
  * @mode: A #CoglVerticesMode defining how to draw the vertices
  * @n_vertices: The number of vertices to process when drawing
- * @data: An array of #CoglP2T2Vertex vertices
+ * @data: An array of #CoglVertexP2T2 vertices
  *
  * Provides a convenient way to describe a primitive, such as a single
  * triangle strip or a triangle fan, that will internally allocate the
  * necessary #CoglVertexArray storage, describe the position and
- * texture coordinate attributes with #CoglVertexAttribute<!-- -->s and
+ * texture coordinate attributes with #CoglAttribute<!-- -->s and
  * upload your data.
  *
  * For example to draw a convex polygon with texture mapping you can
  * do:
  * |[
- * CoglP2T2Vertex triangle[] =
+ * CoglVertexP2T2 triangle[] =
  * {
  *   { 0,   300,  0.0, 1.0},
  *   { 150, 0,    0.5, 0.0},
@@ -461,24 +461,24 @@ cogl_primitive_new_p3c4 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p2t2 (CoglVerticesMode mode,
                          int n_vertices,
-                         const CoglP2T2Vertex *data);
+                         const CoglVertexP2T2 *data);
 
 /**
  * cogl_primitive_new_p3t2:
  * @mode: A #CoglVerticesMode defining how to draw the vertices
  * @n_vertices: The number of vertices to process when drawing
- * @data: An array of #CoglP3T2Vertex vertices
+ * @data: An array of #CoglVertexP3T2 vertices
  *
  * Provides a convenient way to describe a primitive, such as a single
  * triangle strip or a triangle fan, that will internally allocate the
  * necessary #CoglVertexArray storage, describe the position and
- * texture coordinate attributes with #CoglVertexAttribute<!-- -->s and
+ * texture coordinate attributes with #CoglAttribute<!-- -->s and
  * upload your data.
  *
  * For example to draw a convex polygon with texture mapping you can
  * do:
  * |[
- * CoglP3T2Vertex triangle[] =
+ * CoglVertexP3T2 triangle[] =
  * {
  *   { 0,   300, 0,  0.0, 1.0},
  *   { 150, 0,   0,  0.5, 0.0},
@@ -507,24 +507,24 @@ cogl_primitive_new_p2t2 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p3t2 (CoglVerticesMode mode,
                          int n_vertices,
-                         const CoglP3T2Vertex *data);
+                         const CoglVertexP3T2 *data);
 
 /**
  * cogl_primitive_new_p2t2c4:
  * @mode: A #CoglVerticesMode defining how to draw the vertices
  * @n_vertices: The number of vertices to process when drawing
- * @data: An array of #CoglP2T2C4Vertex vertices
+ * @data: An array of #CoglVertexP2T2C4 vertices
  *
  * Provides a convenient way to describe a primitive, such as a single
  * triangle strip or a triangle fan, that will internally allocate the
  * necessary #CoglVertexArray storage, describe the position, texture
- * coordinate and color attributes with #CoglVertexAttribute<!-- -->s and
+ * coordinate and color attributes with #CoglAttribute<!-- -->s and
  * upload your data.
  *
  * For example to draw a convex polygon with texture mapping and a
  * linear gradient you can do:
  * |[
- * CoglP2T2C4Vertex triangle[] =
+ * CoglVertexP2T2C4 triangle[] =
  * {
  *   { 0,   300,  0.0, 1.0,  0xff, 0x00, 0x00, 0xff},
  *   { 150, 0,    0.5, 0.0,  0x00, 0xff, 0x00, 0xff},
@@ -553,24 +553,24 @@ cogl_primitive_new_p3t2 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p2t2c4 (CoglVerticesMode mode,
                            int n_vertices,
-                           const CoglP2T2C4Vertex *data);
+                           const CoglVertexP2T2C4 *data);
 
 /**
  * cogl_primitive_new_p3t2c4:
  * @mode: A #CoglVerticesMode defining how to draw the vertices
  * @n_vertices: The number of vertices to process when drawing
- * @data: An array of #CoglP3T2C4Vertex vertices
+ * @data: An array of #CoglVertexP3T2C4 vertices
  *
  * Provides a convenient way to describe a primitive, such as a single
  * triangle strip or a triangle fan, that will internally allocate the
  * necessary #CoglVertexArray storage, describe the position, texture
- * coordinate and color attributes with #CoglVertexAttribute<!-- -->s and
+ * coordinate and color attributes with #CoglAttribute<!-- -->s and
  * upload your data.
  *
  * For example to draw a convex polygon with texture mapping and a
  * linear gradient you can do:
  * |[
- * CoglP3T2C4Vertex triangle[] =
+ * CoglVertexP3T2C4 triangle[] =
  * {
  *   { 0,   300, 0,  0.0, 1.0,  0xff, 0x00, 0x00, 0xff},
  *   { 150, 0,   0,  0.5, 0.0,  0x00, 0xff, 0x00, 0xff},
@@ -599,7 +599,7 @@ cogl_primitive_new_p2t2c4 (CoglVerticesMode mode,
 CoglPrimitive *
 cogl_primitive_new_p3t2c4 (CoglVerticesMode mode,
                            int n_vertices,
-                           const CoglP3T2C4Vertex *data);
+                           const CoglVertexP3T2C4 *data);
 int
 cogl_primitive_get_first_vertex (CoglPrimitive *primitive);
 
@@ -624,7 +624,7 @@ cogl_primitive_set_mode (CoglPrimitive *primitive,
 /**
  * cogl_primitive_set_attributes:
  * @primitive: A #CoglPrimitive object
- * @attributes: A %NULL terminated array of #CoglVertexAttribute
+ * @attributes: A %NULL terminated array of #CoglAttribute
  *              pointers
  *
  * Replaces all the attributes of the given #CoglPrimitive object.
@@ -634,7 +634,7 @@ cogl_primitive_set_mode (CoglPrimitive *primitive,
  */
 void
 cogl_primitive_set_attributes (CoglPrimitive *primitive,
-                               CoglVertexAttribute **attributes);
+                               CoglAttribute **attributes);
 
 
 void
index ad38812..8628ee4 100644 (file)
@@ -35,7 +35,7 @@
 #include "cogl-pipeline-opengl-private.h"
 #include "cogl-vertex-buffer-private.h"
 #include "cogl-framebuffer-private.h"
-#include "cogl-vertex-attribute-private.h"
+#include "cogl-attribute-private.h"
 
 #include <string.h>
 #include <math.h>
@@ -68,7 +68,7 @@ typedef struct _TextureSlicedPolygonState
   const CoglTextureVertex *vertices;
   int n_vertices;
   int stride;
-  CoglVertexAttribute **attributes;
+  CoglAttribute **attributes;
 } TextureSlicedPolygonState;
 
 static void
@@ -78,6 +78,7 @@ log_quad_sub_textures_cb (CoglHandle texture_handle,
                           void *user_data)
 {
   TextureSlicedQuadState *state = user_data;
+  CoglFramebuffer *framebuffer = _cogl_get_framebuffer ();
   CoglHandle texture_override;
   float quad_coords[4];
 
@@ -120,7 +121,8 @@ log_quad_sub_textures_cb (CoglHandle texture_handle,
   else
     texture_override = texture_handle;
 
-  _cogl_journal_log_quad (quad_coords,
+  _cogl_journal_log_quad (framebuffer->journal,
+                          quad_coords,
                           state->pipeline,
                           1, /* one layer */
                           texture_override, /* replace the layer0 texture */
@@ -518,6 +520,7 @@ _cogl_multitexture_quad_single_primitive (const float  *position,
   int n_layers = cogl_pipeline_get_n_layers (pipeline);
   ValidateTexCoordsState state;
   float *final_tex_coords = alloca (sizeof (float) * 4 * n_layers);
+  CoglFramebuffer *framebuffer;
 
   _COGL_GET_CONTEXT (ctx, FALSE);
 
@@ -539,7 +542,9 @@ _cogl_multitexture_quad_single_primitive (const float  *position,
   if (state.override_pipeline)
     pipeline = state.override_pipeline;
 
-  _cogl_journal_log_quad (position,
+  framebuffer = _cogl_get_framebuffer ();
+  _cogl_journal_log_quad (framebuffer->journal,
+                          position,
                           pipeline,
                           n_layers,
                           COGL_INVALID_HANDLE, /* no texture override */
@@ -929,21 +934,25 @@ _cogl_rectangle_immediate (float x_1,
       x_2, y_2
     };
   CoglVertexArray *vertex_array;
-  CoglVertexAttribute *attributes[2];
+  CoglAttribute *attributes[2];
 
   vertex_array = cogl_vertex_array_new (sizeof (vertices), vertices);
-  attributes[0] = cogl_vertex_attribute_new (vertex_array,
-                                             "cogl_position_in",
-                                             sizeof (float) * 2, /* stride */
-                                             0, /* offset */
-                                             2, /* n_components */
-                                             COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
+  attributes[0] = cogl_attribute_new (vertex_array,
+                                      "cogl_position_in",
+                                      sizeof (float) * 2, /* stride */
+                                      0, /* offset */
+                                      2, /* n_components */
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
   attributes[1] = NULL;
 
-  _cogl_draw_vertex_attributes_array (COGL_VERTICES_MODE_TRIANGLE_STRIP,
-                                      0, /* first_index */
-                                      4, /* n_vertices */
-                                      attributes);
+  _cogl_draw_attributes_array (COGL_VERTICES_MODE_TRIANGLE_STRIP,
+                               0, /* first_index */
+                               4, /* n_vertices */
+                               attributes,
+                               COGL_DRAW_SKIP_JOURNAL_FLUSH |
+                               COGL_DRAW_SKIP_PIPELINE_VALIDATION |
+                               COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
+
 
   cogl_object_unref (attributes[0]);
   cogl_object_unref (vertex_array);
@@ -1037,7 +1046,7 @@ cogl_polygon (const CoglTextureVertex *vertices,
   ValidateState validate_state;
   int n_layers;
   int n_attributes;
-  CoglVertexAttribute **attributes;
+  CoglAttribute **attributes;
   int i;
   unsigned int stride;
   gsize stride_bytes;
@@ -1058,7 +1067,7 @@ cogl_polygon (const CoglTextureVertex *vertices,
   n_layers = cogl_pipeline_get_n_layers (pipeline);
 
   n_attributes = 1 + n_layers + (use_color ? 1 : 0);
-  attributes = g_alloca (sizeof (CoglVertexAttribute *) * (n_attributes + 1));
+  attributes = g_alloca (sizeof (CoglAttribute *) * (n_attributes + 1));
   attributes[n_attributes] = NULL;
 
   /* Our data is arranged like:
@@ -1073,13 +1082,12 @@ cogl_polygon (const CoglTextureVertex *vertices,
 
   vertex_array = cogl_vertex_array_new (n_vertices * stride_bytes, NULL);
 
-  attributes[0] =
-    cogl_vertex_attribute_new (vertex_array,
-                               "cogl_position_in",
-                               stride_bytes,
-                               0,
-                               3,
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
+  attributes[0] = cogl_attribute_new (vertex_array,
+                                      "cogl_position_in",
+                                      stride_bytes,
+                                      0,
+                                      3,
+                                      COGL_ATTRIBUTE_TYPE_FLOAT);
 
   for (i = 0; i < n_layers; i++)
     {
@@ -1096,26 +1104,25 @@ cogl_polygon (const CoglTextureVertex *vertices,
       char *name = i < 8 ? (char *)names[i] :
         g_strdup_printf ("cogl_tex_coord%d_in", i);
 
-      attributes[i + 1] =
-        cogl_vertex_attribute_new (vertex_array,
-                                   name,
-                                   stride_bytes,
-                                   /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
-                                   12 + 8 * i,
-                                   2,
-                                   COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
+      attributes[i + 1] = cogl_attribute_new (vertex_array,
+                                              name,
+                                              stride_bytes,
+                                              /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
+                                              12 + 8 * i,
+                                              2,
+                                              COGL_ATTRIBUTE_TYPE_FLOAT);
     }
 
   if (use_color)
     {
       attributes[n_attributes - 1] =
-        cogl_vertex_attribute_new (vertex_array,
-                                   "cogl_color_in",
-                                   stride_bytes,
-                                   /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
-                                   12 + 8 * n_layers,
-                                   4,
-                                   COGL_VERTEX_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
+        cogl_attribute_new (vertex_array,
+                            "cogl_color_in",
+                            stride_bytes,
+                            /* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
+                            12 + 8 * n_layers,
+                            4,
+                            COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
     }
 
   /* Convert the vertices into an array of float vertex attributes */
@@ -1159,9 +1166,9 @@ cogl_polygon (const CoglTextureVertex *vertices,
 
   cogl_push_source (pipeline);
 
-  cogl_draw_vertex_attributes_array (COGL_VERTICES_MODE_TRIANGLE_FAN,
-                                     0, n_vertices,
-                                     attributes);
+  cogl_draw_attributes_array (COGL_VERTICES_MODE_TRIANGLE_FAN,
+                              0, n_vertices,
+                              attributes);
 
   cogl_pop_source ();
 
index 8f01d2c..92ef707 100644 (file)
@@ -12,7 +12,7 @@ static gboolean
 debug_option_getter (void *user_data)
 {
   unsigned int shift = GPOINTER_TO_UINT (user_data);
-  return (cogl_debug_flags & (1 << shift)) ? TRUE : FALSE;
+  return COGL_DEBUG_ENABLED (shift);
 }
 
 static void
@@ -21,9 +21,9 @@ debug_option_setter (gboolean value, void *user_data)
   unsigned int shift = GPOINTER_TO_UINT (user_data);
 
   if (value)
-    cogl_debug_flags |= (1 << shift);
+    COGL_DEBUG_SET_FLAG (shift);
   else
-    cogl_debug_flags &= ~(1 << shift);
+    COGL_DEBUG_CLEAR_FLAG (shift);
 }
 
 static void
@@ -45,9 +45,7 @@ _cogl_uprof_init (void)
   _cogl_uprof_context = uprof_context_new ("Cogl");
 #define OPT(MASK_NAME, GROUP, NAME, NAME_FORMATTED, DESCRIPTION) \
   G_STMT_START { \
-    int shift; \
-    for (shift = 0; (COGL_DEBUG_ ## MASK_NAME >> shift) != 1; shift++) \
-        ; \
+    int shift = COGL_DEBUG_ ## MASK_NAME; \
     uprof_context_add_boolean_option (_cogl_uprof_context, \
                                       GROUP, \
                                       NAME, \
index a41c577..9be956f 100644 (file)
 #include "cogl-context.h"
 #include "cogl-handle.h"
 
-#ifndef HAVE_COGL_GLES
-
-#include <string.h>
-
 #include "cogl-shader-private.h"
 #include "cogl-program-private.h"
 
+#include <string.h>
+
 static void _cogl_program_free (CoglProgram *program);
 
 COGL_HANDLE_DEFINE (Program, program);
@@ -394,6 +392,8 @@ cogl_program_uniform_matrix (int uniform_no,
                                    uniform_no, size, count, transpose, value);
 }
 
+#ifndef HAVE_COGL_GLES
+
 /* ARBfp local parameters can be referenced like:
  *
  * "program.local[5]"
@@ -501,6 +501,8 @@ _cogl_program_flush_uniform_glsl (GLint location,
     }
 }
 
+#endif /* HAVE_COGL_GLES */
+
 #ifdef HAVE_COGL_GL
 
 static void
@@ -527,6 +529,12 @@ _cogl_program_flush_uniforms (CoglProgram *program,
                               GLuint gl_program,
                               gboolean gl_program_changed)
 {
+#ifdef HAVE_COGL_GLES
+
+  g_return_if_reached ();
+
+#else /* HAVE_COGL_GLES */
+
   CoglProgramUniform *uniform;
   int i;
 
@@ -575,97 +583,10 @@ _cogl_program_flush_uniforms (CoglProgram *program,
           uniform->dirty = FALSE;
         }
     }
-}
-
-#else /* HAVE_COGL_GLES */
-
-/* No support on regular OpenGL 1.1 */
-
-CoglHandle
-cogl_create_program (void)
-{
-  return COGL_INVALID_HANDLE;
-}
-
-gboolean
-cogl_is_program (CoglHandle handle)
-{
-  return FALSE;
-}
-
-CoglHandle
-cogl_program_ref (CoglHandle handle)
-{
-  return COGL_INVALID_HANDLE;
-}
-
-void
-cogl_program_unref (CoglHandle handle)
-{
-}
-
-void
-cogl_program_attach_shader (CoglHandle program_handle,
-                            CoglHandle shader_handle)
-{
-}
-
-void
-cogl_program_link (CoglHandle program_handle)
-{
-}
-
-void
-cogl_program_use (CoglHandle program_handle)
-{
-}
-
-int
-cogl_program_get_uniform_location (CoglHandle program_handle,
-                                   const char *uniform_name)
-{
-  return 0;
-}
-
-void
-cogl_program_uniform_1f (int uniform_no,
-                         float value)
-{
-}
-
-void
-cogl_program_uniform_1i (int uniform_no,
-                         int value)
-{
-}
-
-void
-cogl_program_uniform_float (int uniform_no,
-                            int size,
-                            int count,
-                            const GLfloat *value)
-{
-}
-
-void
-cogl_program_uniform_int (int uniform_no,
-                          int size,
-                          int count,
-                          const int *value)
-{
-}
 
-void
-cogl_program_uniform_matrix (int uniform_no,
-                             int size,
-                             int count,
-                             gboolean transpose,
-                             const GLfloat *value)
-{
+#endif /* HAVE_COGL_GLES */
 }
 
-#endif /* HAVE_COGL_GLES2 */
-
 CoglShaderLanguage
 _cogl_program_get_language (CoglHandle handle)
 {
index fe9189f..5fa8ab6 100644 (file)
@@ -454,7 +454,7 @@ _cogl_rectangle_map_add (CoglRectangleMap *map,
       map->space_remaining -= rectangle_size;
 
 #ifdef COGL_ENABLE_DEBUG
-      if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DUMP_ATLAS_IMAGE))
+      if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DUMP_ATLAS_IMAGE)))
         {
           _cogl_rectangle_map_dump_image (map);
           /* Dumping the rectangle map is really slow so we might as well
@@ -545,7 +545,7 @@ _cogl_rectangle_map_remove (CoglRectangleMap *map,
     }
 
 #ifdef COGL_ENABLE_DEBUG
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DUMP_ATLAS_IMAGE))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DUMP_ATLAS_IMAGE)))
     {
       _cogl_rectangle_map_dump_image (map);
       /* Dumping the rectangle map is really slow so we might as well
index 115e84b..db7a6b3 100644 (file)
 #include "cogl.h"
 
 
+#ifndef HAVE_COGL_GLES2
+
 #define _COGL_COMMON_SHADER_BOILERPLATE \
   "#define COGL_VERSION 100\n" \
+  "\n" \
+  "#define cogl_modelview_matrix gl_ModelViewMatrix\n" \
+  "#define cogl_modelview_projection_matrix gl_ModelViewProjectionMatrix\n" \
+  "#define cogl_projection_matrix gl_ProjectionMatrix\n" \
+  "#define cogl_texture_matrix gl_TextureMatrix\n" \
   "\n"
 
-#ifndef HAVE_COGL_GLES2
-
 #define _COGL_VERTEX_SHADER_BOILERPLATE \
   _COGL_COMMON_SHADER_BOILERPLATE \
   "#define cogl_position_in gl_Vertex\n" \
   "#define cogl_position_out gl_Position\n" \
   "#define cogl_point_size_out gl_PointSize\n" \
   "#define cogl_color_out gl_FrontColor\n" \
-  "#define cogl_tex_coord_out gl_TexCoord\n" \
-  "\n" \
-  "#define cogl_modelview_matrix gl_ModelViewMatrix\n" \
-  "#define cogl_modelview_projection_matrix gl_ModelViewProjectionMatrix\n" \
-  "#define cogl_projection_matrix gl_ProjectionMatrix\n" \
-  "#define cogl_texture_matrix gl_TextureMatrix\n"
+  "#define cogl_tex_coord_out gl_TexCoord\n"
 
 #define _COGL_FRAGMENT_SHADER_BOILERPLATE \
   _COGL_COMMON_SHADER_BOILERPLATE \
 
 #else /* HAVE_COGL_GLES2 */
 
+#define _COGL_COMMON_SHADER_BOILERPLATE \
+  "#define COGL_VERSION 100\n" \
+  "\n" \
+  "uniform mat4 cogl_modelview_matrix;\n" \
+  "uniform mat4 cogl_modelview_projection_matrix;\n"  \
+  "uniform mat4 cogl_projection_matrix;\n" \
+  "uniform float cogl_point_size_in;\n"
+
 /* This declares all of the variables that we might need. This is
    working on the assumption that the compiler will optimise them out
    if they are not actually used. The GLSL spec for GLES at least
   "attribute vec4 cogl_color_in;\n" \
   "attribute vec4 cogl_position_in;\n" \
   "#define cogl_tex_coord_in cogl_tex_coord0_in;\n" \
-  "attribute vec3 cogl_normal_in;\n" \
-  "\n" \
-  "uniform mat4 cogl_modelview_matrix;\n" \
-  "uniform mat4 cogl_modelview_projection_matrix;\n"  \
-  "uniform mat4 cogl_projection_matrix;\n" \
-  "uniform float cogl_point_size_in;\n"
+  "attribute vec3 cogl_normal_in;\n"
 
 #define _COGL_FRAGMENT_SHADER_BOILERPLATE \
   _COGL_COMMON_SHADER_BOILERPLATE \
index 927976a..28ee0a6 100644 (file)
@@ -52,8 +52,6 @@
 #define GET_CONTEXT(CTXVAR,RETVAL) G_STMT_START { } G_STMT_END
 #endif
 
-#ifndef HAVE_COGL_GLES
-
 static void _cogl_shader_free (CoglShader *shader);
 
 COGL_HANDLE_DEFINE (Shader, shader);
@@ -62,6 +60,8 @@ COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING (shader);
 static void
 _cogl_shader_free (CoglShader *shader)
 {
+#ifndef HAVE_COGL_GLES
+
   /* Frees shader resources but its handle is not
      released! Do that separately before this! */
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@@ -77,6 +77,8 @@ _cogl_shader_free (CoglShader *shader)
     if (shader->gl_handle)
       GE (glDeleteShader (shader->gl_handle));
 
+#endif /* HAVE_COGL_GLES */
+
   g_slice_free (CoglShader, shader);
 }
 
@@ -112,6 +114,8 @@ cogl_create_shader (CoglShaderType type)
 static void
 delete_shader (CoglShader *shader)
 {
+#ifndef HAVE_COGL_GLES
+
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
 #ifdef HAVE_COGL_GL
@@ -128,6 +132,8 @@ delete_shader (CoglShader *shader)
     }
 
   shader->gl_handle = 0;
+
+#endif /* HAVE_COGL_GLES */
 }
 
 void
@@ -193,6 +199,8 @@ _cogl_shader_set_source_with_boilerplate (GLuint shader_gl_handle,
                                           const char **strings_in,
                                           const GLint *lengths_in)
 {
+#ifndef HAVE_COGL_GLES
+
   static const char vertex_boilerplate[] = _COGL_VERTEX_SHADER_BOILERPLATE;
   static const char fragment_boilerplate[] = _COGL_FRAGMENT_SHADER_BOILERPLATE;
 
@@ -267,7 +275,7 @@ _cogl_shader_set_source_with_boilerplate (GLuint shader_gl_handle,
     }
   count += count_in;
 
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_SHOW_SOURCE))
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
     {
       GString *buf = g_string_new (NULL);
       int i;
@@ -293,12 +301,16 @@ _cogl_shader_set_source_with_boilerplate (GLuint shader_gl_handle,
 #ifdef HAVE_COGL_GLES2
   g_free (tex_coord_declarations);
 #endif
+
+#endif /* HAVE_COGL_GLES */
 }
 
 void
 _cogl_shader_compile_real (CoglHandle handle,
                            int n_tex_coord_attribs)
 {
+#ifndef HAVE_COGL_GLES
+
   CoglShader *shader = handle;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@@ -317,7 +329,7 @@ _cogl_shader_compile_real (CoglHandle handle,
 
       GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, shader->gl_handle));
 
-      if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_SHOW_SOURCE))
+      if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
         g_message ("user ARBfp program:\n%s", shader->source);
 
 #ifdef COGL_GL_DEBUG
@@ -393,11 +405,19 @@ _cogl_shader_compile_real (CoglHandle handle,
         }
 #endif
     }
+
+#endif /* HAVE_COGL_GLES */
 }
 
 char *
 cogl_shader_get_info_log (CoglHandle handle)
 {
+#ifdef HAVE_COGL_GLES
+
+  return NULL;
+
+#else /* HAVE_COGL_GLES */
+
   CoglShader *shader;
 
   GET_CONTEXT (ctx, NULL);
@@ -439,6 +459,8 @@ cogl_shader_get_info_log (CoglHandle handle)
       buffer[len] = '\0';
       return g_strdup (buffer);
     }
+
+#endif /* HAVE_COGL_GLES */
 }
 
 CoglShaderType
@@ -461,6 +483,12 @@ cogl_shader_get_type (CoglHandle  handle)
 gboolean
 cogl_shader_is_compiled (CoglHandle handle)
 {
+#ifdef HAVE_COGL_GLES
+
+  return FALSE;
+
+#else /* HAVE_COGL_GLES */
+
   GLint status;
   CoglShader *shader;
 
@@ -501,63 +529,6 @@ cogl_shader_is_compiled (CoglHandle handle)
       else
         return FALSE;
     }
-}
-
-#else /* HAVE_COGL_GLES */
-
-/* No support on regular OpenGL 1.1 */
-
-CoglHandle
-cogl_create_shader (CoglShaderType type)
-{
-  return COGL_INVALID_HANDLE;
-}
-
-gboolean
-cogl_is_shader (CoglHandle handle)
-{
-  return FALSE;
-}
-
-CoglHandle
-cogl_shader_ref (CoglHandle handle)
-{
-  return COGL_INVALID_HANDLE;
-}
-
-void
-cogl_shader_unref (CoglHandle handle)
-{
-}
-
-void
-cogl_shader_source (CoglHandle  shader,
-                    const char   *source)
-{
-}
-
-void
-cogl_shader_compile (CoglHandle shader_handle)
-{
-}
-
-char *
-cogl_shader_get_info_log (CoglHandle handle)
-{
-  return NULL;
-}
-
-CoglShaderType
-cogl_shader_get_type (CoglHandle  handle)
-{
-  return COGL_SHADER_TYPE_VERTEX;
-}
-
-gboolean
-cogl_shader_is_compiled (CoglHandle handle)
-{
-  return FALSE;
-}
 
 #endif /* HAVE_COGL_GLES */
-
+}
index 1730c87..04aca44 100644 (file)
@@ -267,7 +267,8 @@ _cogl_sub_texture_new (CoglHandle next_texture,
   sub_tex = g_new (CoglSubTexture, 1);
 
   tex = COGL_TEXTURE (sub_tex);
-  tex->vtable = &cogl_sub_texture_vtable;
+
+  _cogl_texture_init (tex, &cogl_sub_texture_vtable);
 
   /* If the next texture is also a sub texture we can avoid one level
      of indirection by referencing the full texture of that texture
index 5e3f65a..51590f4 100644 (file)
@@ -907,7 +907,7 @@ _cogl_texture_2d_sliced_init_base (CoglTexture2DSliced *tex_2ds,
 {
   CoglTexture *tex = COGL_TEXTURE (tex_2ds);
 
-  tex->vtable = &cogl_texture_2d_sliced_vtable;
+  _cogl_texture_init (tex, &cogl_texture_2d_sliced_vtable);
 
   tex_2ds->slice_x_spans = NULL;
   tex_2ds->slice_y_spans = NULL;
index 85ddd28..80ec5c7 100644 (file)
@@ -197,7 +197,7 @@ _cogl_texture_2d_create_base (unsigned int     width,
   CoglTexture2D *tex_2d = g_new (CoglTexture2D, 1);
   CoglTexture *tex = COGL_TEXTURE (tex_2d);
 
-  tex->vtable = &cogl_texture_2d_vtable;
+  _cogl_texture_init (tex, &cogl_texture_2d_vtable);
 
   tex_2d->width = width;
   tex_2d->height = height;
index bd2cc4a..19ddb8f 100644 (file)
@@ -178,7 +178,7 @@ _cogl_texture_3d_create_base (unsigned int     width,
   CoglTexture3D *tex_3d = g_new (CoglTexture3D, 1);
   CoglTexture *tex = COGL_TEXTURE (tex_3d);
 
-  tex->vtable = &cogl_texture_3d_vtable;
+  _cogl_texture_init (tex, &cogl_texture_3d_vtable);
 
   tex_3d->width = width;
   tex_3d->height = height;
index 0e45e33..57093cb 100644 (file)
@@ -135,6 +135,7 @@ struct _CoglTextureVtable
 struct _CoglTexture
 {
   CoglHandleObject         _parent;
+  GList                   *framebuffers;
   const CoglTextureVtable *vtable;
 };
 
@@ -166,6 +167,10 @@ struct _CoglTexturePixel
 };
 
 void
+_cogl_texture_init (CoglTexture *texture,
+                    const CoglTextureVtable *vtable);
+
+void
 _cogl_texture_free (CoglTexture *texture);
 
 /* This is used to register a type to the list of handle types that
@@ -285,4 +290,14 @@ _cogl_texture_set_region_from_bitmap (CoglHandle    handle,
                                       unsigned int  dst_height,
                                       CoglBitmap   *bmp);
 
+void
+_cogl_texture_associate_framebuffer (CoglHandle handle,
+                                     CoglFramebuffer *framebuffer);
+
+const GList *
+_cogl_texture_get_associated_framebuffers (CoglHandle handle);
+
+void
+_cogl_texture_flush_journal_rendering (CoglHandle handle);
+
 #endif /* __COGL_TEXTURE_PRIVATE_H */
index 5d6e5cd..cdf9bdf 100644 (file)
@@ -222,7 +222,7 @@ _cogl_texture_rectangle_create_base (unsigned int     width,
   CoglTextureRectangle *tex_rect = g_new (CoglTextureRectangle, 1);
   CoglTexture *tex = COGL_TEXTURE (tex_rect);
 
-  tex->vtable = &cogl_texture_rectangle_vtable;
+  _cogl_texture_init (tex, &cogl_texture_rectangle_vtable);
 
   tex_rect->width = width;
   tex_rect->height = height;
index 15835ab..41aa68b 100644 (file)
@@ -49,6 +49,7 @@
 #include "cogl-pipeline.h"
 #include "cogl-context.h"
 #include "cogl-handle.h"
+#include "cogl-object-private.h"
 #include "cogl-primitives.h"
 #include "cogl-framebuffer-private.h"
 
@@ -119,6 +120,14 @@ cogl_texture_unref (CoglHandle handle)
 }
 
 void
+_cogl_texture_init (CoglTexture *texture,
+                    const CoglTextureVtable *vtable)
+{
+  texture->vtable = vtable;
+  texture->framebuffers = NULL;
+}
+
+void
 _cogl_texture_free (CoglTexture *texture)
 {
   g_free (texture);
@@ -184,27 +193,7 @@ _cogl_texture_prepare_for_upload (CoglBitmap      *src_bmp,
   if (_cogl_texture_needs_premult_conversion (src_format,
                                               dst_format))
     {
-      guint8 *src_data;
-      guint8 *dst_data;
-
-      if ((src_data = _cogl_bitmap_map (src_bmp,
-                                        COGL_BUFFER_ACCESS_READ, 0)) == NULL)
-        return NULL;
-
-      dst_data = g_memdup (src_data,
-                           _cogl_bitmap_get_height (src_bmp) *
-                           _cogl_bitmap_get_rowstride (src_bmp));
-
-      _cogl_bitmap_unmap (src_bmp);
-
-      dst_bmp =
-        _cogl_bitmap_new_from_data (dst_data,
-                                    src_format,
-                                    _cogl_bitmap_get_width (src_bmp),
-                                    _cogl_bitmap_get_height (src_bmp),
-                                    _cogl_bitmap_get_rowstride (src_bmp),
-                                    (CoglBitmapDestroyNotify) g_free,
-                                    NULL);
+      dst_bmp = _cogl_bitmap_copy (src_bmp);
 
       if (!_cogl_bitmap_convert_premult_status (dst_bmp,
                                                 src_format ^
@@ -1493,3 +1482,52 @@ cogl_texture_get_data (CoglHandle       handle,
 
   return byte_size;
 }
+
+static void
+_cogl_texture_framebuffer_destroy_cb (void *user_data,
+                                      void *instance)
+{
+  CoglTexture *tex = user_data;
+  CoglFramebuffer *framebuffer = instance;
+
+  tex->framebuffers = g_list_remove (tex->framebuffers, framebuffer);
+}
+
+void
+_cogl_texture_associate_framebuffer (CoglHandle handle,
+                                     CoglFramebuffer *framebuffer)
+{
+  CoglTexture *tex = COGL_TEXTURE (handle);
+  static CoglUserDataKey framebuffer_destroy_notify_key;
+
+  /* Note: we don't take a reference on the framebuffer here because
+   * that would introduce a circular reference. */
+  tex->framebuffers = g_list_prepend (tex->framebuffers, framebuffer);
+
+  /* Since we haven't taken a reference on the framebuffer we setup
+   * some private data so we will be notified if it is destroyed... */
+  _cogl_object_set_user_data (COGL_OBJECT (framebuffer),
+                              &framebuffer_destroy_notify_key,
+                              tex,
+                              _cogl_texture_framebuffer_destroy_cb);
+}
+
+const GList *
+_cogl_texture_get_associated_framebuffers (CoglHandle handle)
+{
+  CoglTexture *tex = COGL_TEXTURE (handle);
+  return tex->framebuffers;
+}
+
+void
+_cogl_texture_flush_journal_rendering (CoglHandle handle)
+{
+  CoglTexture *tex = COGL_TEXTURE (handle);
+  GList *l;
+
+  /* It could be that a referenced texture is part of a framebuffer
+   * which has an associated journal that must be flushed before it
+   * can be sampled from by the current primitive... */
+  for (l = tex->framebuffers; l; l = l->next)
+    _cogl_framebuffer_flush_journal (l->data);
+}
index 1f49311..6b5ff03 100644 (file)
@@ -252,6 +252,10 @@ typedef enum { /*< prefix=COGL_PIXEL_FORMAT >*/
  * @COGL_FEATURE_POINT_SPRITE: Whether
  *     cogl_material_set_layer_point_sprite_coords_enabled() is supported.
  * @COGL_FEATURE_TEXTURE_3D: 3D texture support
+ * @COGL_FEATURE_MAP_BUFFER_FOR_READ: Whether cogl_buffer_map() is
+ *     supported with CoglBufferAccess including read support.
+ * @COGL_FEATURE_MAP_BUFFER_FOR_WRITE: Whether cogl_buffer_map() is
+ *     supported with CoglBufferAccess including write support.
  *
  * Flags for the supported features.
  *
@@ -278,7 +282,9 @@ typedef enum
   COGL_FEATURE_TEXTURE_NPOT_REPEAT    = (1 << 17),
   COGL_FEATURE_POINT_SPRITE           = (1 << 18),
   COGL_FEATURE_TEXTURE_3D             = (1 << 19),
-  COGL_FEATURE_SHADERS_ARBFP          = (1 << 20)
+  COGL_FEATURE_SHADERS_ARBFP          = (1 << 20),
+  COGL_FEATURE_MAP_BUFFER_FOR_READ    = (1 << 21),
+  COGL_FEATURE_MAP_BUFFER_FOR_WRITE   = (1 << 22)
 } CoglFeatureFlags;
 
 /**
@@ -466,6 +472,28 @@ GQuark
 _cogl_error_quark (void);
 
 /**
+ * CoglAttributeType:
+ * @COGL_ATTRIBUTE_TYPE_BYTE: Data is the same size of a byte
+ * @COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE: Data is the same size of an
+ *   unsigned byte
+ * @COGL_ATTRIBUTE_TYPE_SHORT: Data is the same size of a short integer
+ * @COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT: Data is the same size of
+ *   an unsigned short integer
+ * @COGL_ATTRIBUTE_TYPE_FLOAT: Data is the same size of a float
+ *
+ * Data types for the components of a vertex attribute.
+ *
+ * Since: 1.0
+ */
+typedef enum {
+  COGL_ATTRIBUTE_TYPE_BYTE           = 0x1400,
+  COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE  = 0x1401,
+  COGL_ATTRIBUTE_TYPE_SHORT          = 0x1402,
+  COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT = 0x1403,
+  COGL_ATTRIBUTE_TYPE_FLOAT          = 0x1406
+} CoglAttributeType;
+
+/**
  * CoglIndicesType:
  * @COGL_INDICES_TYPE_UNSIGNED_BYTE: Your indices are unsigned bytes
  * @COGL_INDICES_TYPE_UNSIGNED_SHORT: Your indices are unsigned shorts
index 2916587..d38049a 100644 (file)
@@ -218,3 +218,24 @@ _cogl_util_one_at_a_time_mix (unsigned int hash)
   return hash;
 }
 
+/* The 'ffs' function is part of C99 so it isn't always available */
+#ifndef HAVE_FFS
+
+int
+_cogl_util_ffs (int num)
+{
+  int i = 1;
+
+  if (num == 0)
+    return 0;
+
+  while ((num & 1) == 0)
+    {
+      num >>= 1;
+      i++;
+    }
+
+  return i;
+}
+
+#endif /* HAVE_FFS */
index 0ac56c9..e32fcd6 100644 (file)
@@ -95,4 +95,12 @@ _cogl_util_one_at_a_time_hash (unsigned int hash,
 unsigned int
 _cogl_util_one_at_a_time_mix (unsigned int hash);
 
+/* The 'ffs' function is part of C99 so it isn't always available */
+#ifdef HAVE_FFS
+#define _cogl_util_ffs ffs
+#else
+int
+_cogl_util_ffs (int num);
+#endif
+
 #endif /* __COGL_UTIL_H */
diff --git a/clutter/cogl/cogl/cogl-vertex-attribute-private.h b/clutter/cogl/cogl/cogl-vertex-attribute-private.h
deleted file mode 100644 (file)
index 1eaf6f0..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Cogl
- *
- * An object oriented GL/GLES Abstraction/Utility Layer
- *
- * Copyright (C) 2010 Intel Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- *
- *
- * Authors:
- *   Robert Bragg <robert@linux.intel.com>
- */
-
-#ifndef __COGL_VERTEX_ATTRIBUTE_PRIVATE_H
-#define __COGL_VERTEX_ATTRIBUTE_PRIVATE_H
-
-#include "cogl-object-private.h"
-#include "cogl-vertex-attribute.h"
-
-typedef enum
-{
-  COGL_VERTEX_ATTRIBUTE_NAME_ID_POSITION_ARRAY,
-  COGL_VERTEX_ATTRIBUTE_NAME_ID_COLOR_ARRAY,
-  COGL_VERTEX_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY,
-  COGL_VERTEX_ATTRIBUTE_NAME_ID_NORMAL_ARRAY,
-  COGL_VERTEX_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY
-} CoglVertexAttributeNameID;
-
-struct _CoglVertexAttribute
-{
-  CoglObject _parent;
-
-  CoglVertexArray *array;
-  char *name;
-  CoglVertexAttributeNameID name_id;
-  gsize stride;
-  gsize offset;
-  int n_components;
-  CoglVertexAttributeType type;
-  gboolean normalized;
-  unsigned int texture_unit;
-
-  int immutable_ref;
-};
-
-CoglVertexAttribute *
-_cogl_vertex_attribute_immutable_ref (CoglVertexAttribute *vertex_attribute);
-
-void
-_cogl_vertex_attribute_immutable_unref (CoglVertexAttribute *vertex_attribute);
-
-void
-_cogl_draw_vertex_attributes_array (CoglVerticesMode mode,
-                                    int first_vertex,
-                                    int n_vertices,
-                                    CoglVertexAttribute **attributes);
-
-void
-_cogl_draw_indexed_vertex_attributes_array (CoglVerticesMode mode,
-                                            int first_vertex,
-                                            int n_vertices,
-                                            CoglIndices *indices,
-                                            CoglVertexAttribute **attributes);
-
-void
-_cogl_vertex_attribute_disable_cached_arrays (void);
-
-#endif /* __COGL_VERTEX_ATTRIBUTE_PRIVATE_H */
-
index 0f2127c..096c00b 100644 (file)
@@ -93,14 +93,14 @@ typedef struct _CoglVertexBufferAttrib
     const void           *pointer;
     size_t                vbo_offset;
   } u;
-  CoglVertexAttributeType  type;
+  CoglAttributeType        type;
   size_t                  span_bytes;
   guint16                 stride;
   guint8                  n_components;
   guint8                  texture_unit;
 
   int                      attribute_first;
-  CoglVertexAttribute     *attribute;
+  CoglAttribute           *attribute;
 
 } CoglVertexBufferAttrib;
 
index a778843..f9fac14 100644 (file)
@@ -327,7 +327,7 @@ validate_custom_attribute_name (const char *attribute_name)
  * of all the submitted attributes
  *
  * Note: The CoglVertexBufferAttrib structs are deep copied, except the
- * internal CoglVertexAttribute pointer is set to NULL.
+ * internal CoglAttribute pointer is set to NULL.
  */
 static GList *
 copy_submitted_attributes_list (CoglVertexBuffer *buffer)
@@ -1145,7 +1145,7 @@ update_primitive_attributes (CoglVertexBuffer *buffer)
 {
   GList *l;
   int n_attributes = 0;
-  CoglVertexAttribute **attributes;
+  CoglAttribute **attributes;
   int i;
 
   if (!buffer->dirty_attributes)
@@ -1164,7 +1164,7 @@ update_primitive_attributes (CoglVertexBuffer *buffer)
 
   g_return_if_fail (n_attributes > 0);
 
-  attributes = g_alloca (sizeof (CoglVertexAttribute *) * n_attributes + 1);
+  attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes + 1);
 
   i = 0;
   for (l = buffer->submitted_vbos; l; l = l->next)
@@ -1181,12 +1181,12 @@ update_primitive_attributes (CoglVertexBuffer *buffer)
               if (G_UNLIKELY (!attribute->attribute))
                 {
                   attribute->attribute =
-                    cogl_vertex_attribute_new (cogl_vbo->array,
-                                               attribute->name_without_detail,
-                                               attribute->stride,
-                                               attribute->u.vbo_offset,
-                                               attribute->n_components,
-                                               attribute->type);
+                    cogl_attribute_new (cogl_vbo->array,
+                                        attribute->name_without_detail,
+                                        attribute->stride,
+                                        attribute->u.vbo_offset,
+                                        attribute->n_components,
+                                        attribute->type);
                 }
 
               attributes[i++] = attribute->attribute;
@@ -1475,15 +1475,32 @@ cogl_vertex_buffer_submit (CoglHandle handle)
 
 typedef struct
 {
+  /* We have a ref-count on this private structure because we need to
+     refer to it both from the private data on a pipeline and any weak
+     pipelines that we create from it. If we didn't have the ref count
+     then we would depend on the order of destruction of a
+     CoglPipeline and the weak materials to avoid a crash */
+  unsigned int ref_count;
+
   CoglPipeline *real_source;
 } VertexBufferMaterialPrivate;
 
 static void
+unref_pipeline_priv (VertexBufferMaterialPrivate *priv)
+{
+  if (--priv->ref_count < 1)
+    g_slice_free (VertexBufferMaterialPrivate, priv);
+}
+
+static void
 weak_override_source_destroyed_cb (CoglPipeline *pipeline,
-                 void *user_data)
+                                   void *user_data)
 {
   VertexBufferMaterialPrivate *pipeline_priv = user_data;
   pipeline_priv->real_source = NULL;
+  /* A reference was added when we copied the weak material so we need
+     to unref it here */
+  unref_pipeline_priv (pipeline_priv);
 }
 
 static gboolean
@@ -1531,10 +1548,13 @@ validate_layer_cb (CoglPipeline *pipeline,
       if (need_override_source)
         {
           if (pipeline_priv->real_source == pipeline)
-            pipeline_priv->real_source = source =
-              _cogl_pipeline_weak_copy (pipeline,
-                                        weak_override_source_destroyed_cb,
-                                        pipeline_priv);
+            {
+              pipeline_priv->ref_count++;
+              pipeline_priv->real_source = source =
+                _cogl_pipeline_weak_copy (pipeline,
+                                          weak_override_source_destroyed_cb,
+                                          pipeline_priv);
+            }
 
           cogl_pipeline_set_layer_wrap_mode_s (source, layer_index, wrap_s);
           cogl_pipeline_set_layer_wrap_mode_t (source, layer_index, wrap_t);
@@ -1548,7 +1568,7 @@ validate_layer_cb (CoglPipeline *pipeline,
 static void
 destroy_pipeline_priv_cb (void *user_data)
 {
-  g_slice_free (VertexBufferMaterialPrivate, user_data);
+  unref_pipeline_priv (user_data);
 }
 
 static void
@@ -1581,6 +1601,7 @@ update_primitive_and_draw (CoglVertexBuffer *buffer,
   if (G_UNLIKELY (!pipeline_priv))
     {
       pipeline_priv = g_slice_new0 (VertexBufferMaterialPrivate);
+      pipeline_priv->ref_count = 1;
       cogl_object_set_user_data (COGL_OBJECT (users_source),
                                  &_cogl_vertex_buffer_pipeline_priv_key,
                                  pipeline_priv,
index 4f9217c..631ba09 100644 (file)
@@ -98,28 +98,6 @@ unsigned int
 cogl_vertex_buffer_get_n_vertices (CoglHandle handle);
 
 /**
- * CoglAttributeType:
- * @COGL_ATTRIBUTE_TYPE_BYTE: Data is the same size of a byte
- * @COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE: Data is the same size of an
- *   unsigned byte
- * @COGL_ATTRIBUTE_TYPE_SHORT: Data is the same size of a short integer
- * @COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT: Data is the same size of
- *   an unsigned short integer
- * @COGL_ATTRIBUTE_TYPE_FLOAT: Data is the same size of a float
- *
- * Data types for the components of cogl_vertex_buffer_add()
- *
- * Since: 1.0
- */
-typedef enum {
-  COGL_ATTRIBUTE_TYPE_BYTE = GL_BYTE,
-  COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE = GL_UNSIGNED_BYTE,
-  COGL_ATTRIBUTE_TYPE_SHORT = GL_SHORT,
-  COGL_ATTRIBUTE_TYPE_UNSIGNED_SHORT = GL_UNSIGNED_SHORT,
-  COGL_ATTRIBUTE_TYPE_FLOAT = GL_FLOAT
-} CoglAttributeType;
-
-/**
  * cogl_vertex_buffer_add:
  * @handle: A vertex buffer handle
  * @attribute_name: The name of your attribute. It should be a valid GLSL
@@ -151,7 +129,8 @@ typedef enum {
  *   must remain valid until you either call cogl_vertex_buffer_submit() or
  *   issue a draw call.
  *
- * Adds an attribute to a buffer.
+ * Adds an attribute to a buffer, or replaces a previously added
+ * attribute with the same name.
  *
  * You either can use one of the built-in names such as "gl_Vertex", or
  * "gl_MultiTexCoord0" to add standard attributes, like positions, colors
index 6ce4172..333ef9a 100644 (file)
@@ -45,7 +45,8 @@
 #include "cogl-bitmap-private.h"
 #include "cogl-texture-private.h"
 #include "cogl-texture-driver.h"
-#include "cogl-vertex-attribute-private.h"
+#include "cogl-attribute-private.h"
+#include "cogl-framebuffer-private.h"
 
 #ifdef HAVE_COGL_GL
 #define glClientActiveTexture ctx->drv.pf_glClientActiveTexture
@@ -145,71 +146,12 @@ cogl_check_extension (const char *name, const char *ext)
   return _cogl_check_extension (name, ext);
 }
 
-/* This version of cogl_clear can be used internally as an alternative
-   to avoid flushing the journal or the framebuffer state. This is
-   needed when doing operations that may be called whiling flushing
-   the journal */
-void
-_cogl_clear (const CoglColor *color, unsigned long buffers)
-{
-  GLbitfield gl_buffers = 0;
-
-  if (buffers & COGL_BUFFER_BIT_COLOR)
-    {
-      GE( glClearColor (cogl_color_get_red_float (color),
-                       cogl_color_get_green_float (color),
-                       cogl_color_get_blue_float (color),
-                       cogl_color_get_alpha_float (color)) );
-      gl_buffers |= GL_COLOR_BUFFER_BIT;
-    }
-
-  if (buffers & COGL_BUFFER_BIT_DEPTH)
-    gl_buffers |= GL_DEPTH_BUFFER_BIT;
-
-  if (buffers & COGL_BUFFER_BIT_STENCIL)
-    gl_buffers |= GL_STENCIL_BUFFER_BIT;
-
-  if (!gl_buffers)
-    {
-      static gboolean shown = FALSE;
-
-      if (!shown)
-        {
-         g_warning ("You should specify at least one auxiliary buffer "
-                     "when calling cogl_clear");
-        }
-
-      return;
-    }
-
-  GE (glClear (gl_buffers));
-
-  /* This is a debugging variable used to visually display the quad
-     batches from the journal. It is reset here to increase the
-     chances of getting the same colours for each frame during an
-     animation */
-  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_RECTANGLES))
-    {
-      _COGL_GET_CONTEXT (ctxt, NO_RETVAL);
-      ctxt->journal_rectangles_color = 1;
-    }
-}
-
+/* XXX: it's expected that we'll deprecated this with
+ * cogl_framebuffer_clear at some point. */
 void
 cogl_clear (const CoglColor *color, unsigned long buffers)
 {
-  COGL_NOTE (DRAW, "Clear begin");
-
-  _cogl_journal_flush ();
-
-  /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
-   * as the pipeline state) when flushing the clip stack, so should
-   * always be done first when preparing to draw. */
-  _cogl_framebuffer_flush_state (_cogl_get_framebuffer (), 0);
-
-  _cogl_clear (color, buffers);;
-
-  COGL_NOTE (DRAW, "Clear end");
+  _cogl_framebuffer_clear (_cogl_get_framebuffer (), buffers, color);
 }
 
 static gboolean
@@ -340,7 +282,7 @@ cogl_set_backface_culling_enabled (gboolean setting)
     return;
 
   /* Currently the journal can't track changes to backface culling state... */
-  _cogl_journal_flush ();
+  _cogl_framebuffer_flush_journal (_cogl_get_framebuffer ());
 
   ctx->enable_backface_culling = setting;
 }
@@ -537,7 +479,12 @@ cogl_disable_fog (void)
 void
 cogl_flush (void)
 {
-  _cogl_journal_flush ();
+  GList *l;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  for (l = ctx->framebuffers; l; l = l->next)
+    _cogl_framebuffer_flush_journal (l->data);
 }
 
 void
@@ -550,7 +497,7 @@ _cogl_read_pixels_with_rowstride (int x,
                                   guint8 *pixels,
                                   int rowstride)
 {
-  CoglFramebuffer *framebuffer;
+  CoglFramebuffer *framebuffer = _cogl_get_framebuffer ();
   int              framebuffer_height;
   int              bpp;
   CoglBitmap      *bmp;
@@ -563,11 +510,32 @@ _cogl_read_pixels_with_rowstride (int x,
 
   g_return_if_fail (source == COGL_READ_PIXELS_COLOR_BUFFER);
 
-  /* make sure any batched primitives get emitted to the GL driver before
-   * issuing our read pixels... */
-  cogl_flush ();
+  if (width == 1 && height == 1 && !framebuffer->clear_clip_dirty)
+    {
+      /* If everything drawn so far for this frame is still in the
+       * Journal then if all of the rectangles only have a flat
+       * opaque color we have a fast-path for reading a single pixel
+       * that avoids the relatively high cost of flushing primitives
+       * to be drawn on the GPU (considering how simple the geometry
+       * is in this case) and then blocking on the long GPU pipelines
+       * for the result.
+       */
+      if (_cogl_framebuffer_try_fast_read_pixel (framebuffer,
+                                                 x, y, source, format,
+                                                 pixels))
+        return;
+    }
 
-  framebuffer = _cogl_get_framebuffer ();
+  /* make sure any batched primitives get emitted to the GL driver
+   * before issuing our read pixels...
+   *
+   * XXX: Note we currently use cogl_flush to ensure *all* journals
+   * are flushed here and not _cogl_journal_flush because we don't
+   * track the dependencies between framebuffers so we don't know if
+   * the current framebuffer depends on the contents of other
+   * framebuffers which could also have associated journal entries.
+   */
+  cogl_flush ();
 
   _cogl_framebuffer_flush_state (framebuffer, 0);
 
@@ -771,7 +739,7 @@ cogl_begin_gl (void)
   _cogl_flush_face_winding ();
 
   /* Disable any cached vertex arrays */
-  _cogl_vertex_attribute_disable_cached_arrays ();
+  _cogl_attribute_disable_cached_arrays ();
 }
 
 void
@@ -1143,3 +1111,13 @@ _cogl_error_quark (void)
   return g_quark_from_static_string ("cogl-error-quark");
 }
 
+/* Until Cogl becomes responsible for handling swap-buffer requests
+ * this API is used by Clutter to notify us when it issues a
+ * swap-buffer on our behalf. */
+void
+_cogl_swap_buffers_notify (void)
+{
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  _cogl_framebuffer_swap_notify (_cogl_get_framebuffer ());
+}
index d6170fe..a55b4ed 100644 (file)
@@ -73,7 +73,7 @@
 #include <cogl/cogl-index-array.h>
 #include <cogl/cogl-vertex-array.h>
 #include <cogl/cogl-indices.h>
-#include <cogl/cogl-vertex-attribute.h>
+#include <cogl/cogl-attribute.h>
 #include <cogl/cogl-primitive.h>
 #include <cogl/cogl-pipeline.h>
 #endif
@@ -1293,6 +1293,9 @@ _cogl_driver_error_quark (void);
 void
 _cogl_onscreen_clutter_backend_set_size (int width, int height);
 
+void
+_cogl_swap_buffers_notify (void);
+
 G_END_DECLS
 
 #undef __COGL_H_INSIDE__
index fc81de7..d812290 100644 (file)
@@ -42,7 +42,7 @@
 #include "cogl-texture-private.h"
 #include "cogl-primitives-private.h"
 #include "cogl-private.h"
-#include "cogl-vertex-attribute-private.h"
+#include "cogl-attribute-private.h"
 #include "tesselator/tesselator.h"
 
 #include <string.h>
@@ -233,7 +233,7 @@ _cogl_path_stroke_nodes (CoglPath *path)
     {
       node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
 
-      cogl_draw_vertex_attributes (COGL_VERTICES_MODE_LINE_STRIP,
+      cogl_draw_attributes (COGL_VERTICES_MODE_LINE_STRIP,
                                    0, node->path_size,
                                    data->stroke_vbo_attributes[path_num],
                                    NULL);
@@ -338,11 +338,15 @@ _cogl_path_fill_nodes (CoglPath *path)
 
   _cogl_path_build_fill_vbo (path);
 
-  _cogl_draw_indexed_vertex_attributes_array (COGL_VERTICES_MODE_TRIANGLES,
-                                              0, /* first_vertex */
-                                              path->data->fill_vbo_n_indices,
-                                              path->data->fill_vbo_indices,
-                                              path->data->fill_vbo_attributes);
+  _cogl_draw_indexed_attributes_array
+                                 (COGL_VERTICES_MODE_TRIANGLES,
+                                  0, /* first_vertex */
+                                  path->data->fill_vbo_n_indices,
+                                  path->data->fill_vbo_indices,
+                                  path->data->fill_vbo_attributes,
+                                  COGL_DRAW_SKIP_JOURNAL_FLUSH |
+                                  COGL_DRAW_SKIP_PIPELINE_VALIDATION |
+                                  COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
 }
 
 void
@@ -392,9 +396,9 @@ _cogl_add_path_to_stencil_buffer (CoglPath *path,
            will have set up a scissor for the minimum bounding box of
            all of the clips. That box will likely mean that this
            _cogl_clear won't need to clear the entire
-           buffer. _cogl_clear is used instead of cogl_clear because
+           buffer. _cogl_clear4f is used instead of cogl_clear because
            it won't try to flush the journal */
-        _cogl_clear (NULL, COGL_BUFFER_BIT_STENCIL);
+        _cogl_clear4f (COGL_BUFFER_BIT_STENCIL, 0, 0, 0, 0);
       else
         {
           /* Just clear the bounding box */
@@ -455,17 +459,21 @@ _cogl_add_path_to_stencil_buffer (CoglPath *path,
 void
 cogl2_path_fill (CoglPath *path)
 {
+  CoglFramebuffer *framebuffer;
+
   g_return_if_fail (cogl_is_path (path));
 
   if (path->data->path_nodes->len == 0)
     return;
 
-  _cogl_journal_flush ();
+  framebuffer = _cogl_get_framebuffer ();
+
+  _cogl_framebuffer_flush_journal (framebuffer);
 
   /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
    * as the pipeline state) when flushing the clip stack, so should
    * always be done first when preparing to draw. */
-  _cogl_framebuffer_flush_state (_cogl_get_framebuffer (), 0);
+  _cogl_framebuffer_flush_state (framebuffer, 0);
 
   _cogl_path_fill_nodes (path);
 }
@@ -1439,19 +1447,19 @@ _cogl_path_build_fill_vbo (CoglPath *path)
   g_array_free (tess.vertices, TRUE);
 
   data->fill_vbo_attributes[0] =
-    cogl_vertex_attribute_new (data->fill_vbo,
+    cogl_attribute_new (data->fill_vbo,
                                "cogl_position_in",
                                sizeof (CoglPathTesselatorVertex),
                                G_STRUCT_OFFSET (CoglPathTesselatorVertex, x),
                                2, /* n_components */
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
+                               COGL_ATTRIBUTE_TYPE_FLOAT);
   data->fill_vbo_attributes[1] =
-    cogl_vertex_attribute_new (data->fill_vbo,
+    cogl_attribute_new (data->fill_vbo,
                                "cogl_tex_coord0_in",
                                sizeof (CoglPathTesselatorVertex),
                                G_STRUCT_OFFSET (CoglPathTesselatorVertex, s),
                                2, /* n_components */
-                               COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
+                               COGL_ATTRIBUTE_TYPE_FLOAT);
   /* NULL terminator */
   data->fill_vbo_attributes[2] = NULL;
 
@@ -1480,9 +1488,8 @@ _cogl_path_build_stroke_vbo (CoglPath *path)
                                             sizeof (floatVec2),
                                             NULL);
 
-  vbo_p = cogl_buffer_map (COGL_BUFFER (data->stroke_vbo),
-                           COGL_BUFFER_ACCESS_WRITE,
-                           COGL_BUFFER_MAP_HINT_DISCARD);
+  vbo_p =
+    _cogl_buffer_map_for_fill_or_fallback (COGL_BUFFER (data->stroke_vbo));
 
   /* Copy the vertices in and count the number of sub paths. Each sub
      path will form a separate attribute so we can paint the disjoint
@@ -1502,9 +1509,9 @@ _cogl_path_build_stroke_vbo (CoglPath *path)
       n_attributes++;
     }
 
-  cogl_buffer_unmap (COGL_BUFFER (data->stroke_vbo));
+  _cogl_buffer_unmap_for_fill_or_fallback (COGL_BUFFER (data->stroke_vbo));
 
-  data->stroke_vbo_attributes = g_new (CoglVertexAttribute *, n_attributes);
+  data->stroke_vbo_attributes = g_new (CoglAttribute *, n_attributes);
 
   /* Now we can loop the sub paths again to create the attributes */
   for (i = 0, path_start = 0;
@@ -1514,12 +1521,12 @@ _cogl_path_build_stroke_vbo (CoglPath *path)
       node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
 
       data->stroke_vbo_attributes[i] =
-        cogl_vertex_attribute_new (data->stroke_vbo,
-                                   "cogl_position_in",
-                                   sizeof (floatVec2),
-                                   path_start * sizeof (floatVec2),
-                                   2, /* n_components */
-                                   COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT);
+        cogl_attribute_new (data->stroke_vbo,
+                            "cogl_position_in",
+                            sizeof (floatVec2),
+                            path_start * sizeof (floatVec2),
+                            2, /* n_components */
+                            COGL_ATTRIBUTE_TYPE_FLOAT);
     }
 
   data->stroke_vbo_n_attributes = n_attributes;
index bcbdd7f..e26e4e9 100644 (file)
@@ -295,7 +295,9 @@ COGL_FEATURE_END ()
 COGL_FEATURE_BEGIN (vbos, 1, 5,
                     "ARB\0",
                     "vertex_buffer_object\0",
-                    COGL_FEATURE_VBOS,
+                    COGL_FEATURE_VBOS |
+                    COGL_FEATURE_MAP_BUFFER_FOR_READ |
+                    COGL_FEATURE_MAP_BUFFER_FOR_WRITE,
                     0)
 COGL_FEATURE_FUNCTION (void, glGenBuffers,
                        (GLuint          n,
index 8d0d864..408076e 100644 (file)
@@ -109,3 +109,15 @@ COGL_FEATURE_FUNCTION (void, glTexSubImage3D,
                         GLsizei width, GLsizei height, GLsizei depth,
                         GLenum format, GLenum type, const GLvoid* pixels))
 COGL_FEATURE_END ()
+
+COGL_FEATURE_BEGIN (map_buffer, 255, 255,
+                    "OES\0",
+                    "mapbuffer\0",
+                    COGL_FEATURE_MAP_BUFFER_FOR_WRITE,
+                    0)
+COGL_FEATURE_FUNCTION (void *, glMapBuffer,
+                       (GLenum           target,
+                        GLenum           access))
+COGL_FEATURE_FUNCTION (GLboolean, glUnmapBuffer,
+                       (GLenum           target))
+COGL_FEATURE_END ()
index 8960f86..ad3d397 100644 (file)
@@ -109,12 +109,7 @@ _cogl_features_init (void)
   flags |= COGL_FEATURE_TEXTURE_NPOT_BASIC;
 #endif
 
-  /* FIXME: HACK: We are in the process of overhauling the GLES 2 backend
-   * and consolidating with a CoglMaterial GLSL backend. Currently though
-   * use of CoglBuffers with GLES 2 is broken. */
-#ifndef HAVE_COGL_GLES2
   flags |= COGL_FEATURE_VBOS;
-#endif
 
   /* Both GLES 1.1 and GLES 2.0 support point sprites in core */
   flags |= COGL_FEATURE_POINT_SPRITE;
index b7a573d..02b9816 100644 (file)
@@ -97,6 +97,32 @@ _cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride,
   _cogl_texture_prep_gl_alignment_for_pixels_download (pixels_rowstride);
 }
 
+static CoglBitmap *
+prepare_bitmap_alignment_for_upload (CoglBitmap *src_bmp)
+{
+  CoglPixelFormat format = _cogl_bitmap_get_format (src_bmp);
+  int bpp = _cogl_get_format_bpp (format);
+  int src_rowstride = _cogl_bitmap_get_rowstride (src_bmp);
+  int width = _cogl_bitmap_get_width (src_bmp);
+  int alignment = 1;
+
+  if (src_rowstride == 0)
+    return cogl_object_ref (src_bmp);
+
+  /* Work out the alignment of the source rowstride */
+  alignment = 1 << (_cogl_util_ffs (src_rowstride) - 1);
+  alignment = MIN (alignment, 8);
+
+  /* If the aligned data equals the rowstride then we can upload from
+     the bitmap directly using GL_UNPACK_ALIGNMENT */
+  if (((width * bpp + alignment - 1) & ~(alignment - 1)) == src_rowstride)
+    return cogl_object_ref (src_bmp);
+  /* Otherwise we need to copy the bitmap to pack the alignment
+     because GLES has no GL_ROW_LENGTH */
+  else
+    return _cogl_bitmap_copy (src_bmp);
+}
+
 void
 _cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
                                              GLuint       gl_handle,
@@ -117,37 +143,36 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
   CoglBitmap *slice_bmp;
   int rowstride;
 
-  /* NB: GLES doesn't support the GL_UNPACK_ROW_LENGTH,
-   * GL_UNPACK_SKIP_PIXELS or GL_UNPACK_SKIP_ROWS pixel store options
-   * so we can't directly source a sub-region from source_bmp, we need
-   * to use a transient bitmap instead. */
-
-  /* FIXME: optimize by not copying to intermediate slice bitmap when
-   * source rowstride = bpp * width and the texture image is not
-   * sliced */
-
-  /* Setup temp bitmap for slice subregion */
-  rowstride = bpp * width;
-  slice_bmp = _cogl_bitmap_new_from_data (g_malloc (rowstride * height),
-                                          source_format,
-                                          width,
-                                          height,
-                                          rowstride,
-                                          (CoglBitmapDestroyNotify)
-                                          g_free,
-                                          NULL);
+  /* If we are copying a sub region of the source bitmap then we need
+     to copy it because GLES does not support GL_UNPACK_ROW_LENGTH */
+  if (src_x != 0 || src_y != 0 ||
+      width != _cogl_bitmap_get_width (source_bmp) ||
+      height != _cogl_bitmap_get_height (source_bmp))
+    {
+      rowstride = bpp * width;
+      rowstride = (rowstride + 3) & ~3;
+      slice_bmp =
+        _cogl_bitmap_new_from_data (g_malloc (height * rowstride),
+                                    source_format,
+                                    width, height,
+                                    rowstride,
+                                    (CoglBitmapDestroyNotify) g_free,
+                                    NULL);
+      _cogl_bitmap_copy_subregion (source_bmp,
+                                   slice_bmp,
+                                   src_x, src_y,
+                                   0, 0, /* dst_x/y */
+                                   width, height);
+    }
+  else
+    {
+      slice_bmp = prepare_bitmap_alignment_for_upload (source_bmp);
+      rowstride = _cogl_bitmap_get_rowstride (slice_bmp);
+    }
 
   /* Setup gl alignment to match rowstride and top-left corner */
   _cogl_texture_driver_prep_gl_for_pixels_upload (rowstride, bpp);
 
-  /* Copy subregion data */
-  _cogl_bitmap_copy_subregion (source_bmp,
-                               slice_bmp,
-                               src_x,
-                               src_y,
-                               0, 0,
-                               width, height);
-
   data = _cogl_bitmap_bind (slice_bmp, COGL_BUFFER_ACCESS_READ, 0);
 
   _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
@@ -174,32 +199,14 @@ _cogl_texture_driver_upload_to_gl (GLenum       gl_target,
                                    GLuint       source_gl_type)
 {
   int bpp = _cogl_get_format_bpp (_cogl_bitmap_get_format (source_bmp));
-  int rowstride = _cogl_bitmap_get_rowstride (source_bmp);
+  int rowstride;
   int bmp_width = _cogl_bitmap_get_width (source_bmp);
   int bmp_height = _cogl_bitmap_get_height (source_bmp);
   CoglBitmap *bmp;
   guint8 *data;
 
-  /* If the rowstride can't be specified with just GL_ALIGNMENT alone
-     then we need to copy the bitmap because there is no GL_ROW_LENGTH */
-  if (rowstride / bpp != bmp_width)
-    {
-      bmp = _cogl_bitmap_new_from_data (g_malloc (rowstride * bmp_height),
-                                        _cogl_bitmap_get_format (source_bmp),
-                                        bmp_width,
-                                        bmp_height,
-                                        rowstride,
-                                        (CoglBitmapDestroyNotify) g_free,
-                                        NULL);
-
-      _cogl_bitmap_copy_subregion (source_bmp,
-                                   bmp,
-                                   0, 0, 0, 0,
-                                   bmp_width,
-                                   bmp_height);
-    }
-  else
-    bmp = cogl_object_ref (source_bmp);
+  bmp = prepare_bitmap_alignment_for_upload (source_bmp);
+  rowstride = _cogl_bitmap_get_rowstride (bmp);
 
   /* Setup gl alignment to match rowstride and top-left corner */
   _cogl_texture_driver_prep_gl_for_pixels_upload (rowstride, bpp);
index 54697f8..58bef60 100644 (file)
@@ -533,7 +533,7 @@ cogl_texture_pixmap_x11_new (guint32 pixmap,
 
   _COGL_GET_CONTEXT (ctxt, COGL_INVALID_HANDLE);
 
-  tex->vtable = &cogl_texture_pixmap_x11_vtable;
+  _cogl_texture_init (tex, &cogl_texture_pixmap_x11_vtable);
 
   tex_pixmap->pixmap = pixmap;
   tex_pixmap->image = NULL;
index 5f120fc..4c4a85d 100644 (file)
@@ -290,7 +290,7 @@ retry:
    * a dummy, offscreen override-redirect window to which we can always
    * fall back if no stage is available */
 
-  xvisinfo = clutter_backend_x11_get_visual_info (backend_x11);
+  xvisinfo = _clutter_backend_x11_get_visual_info (backend_x11);
   if (xvisinfo == NULL)
     {
       g_critical ("Unable to find suitable GL visual.");
@@ -505,21 +505,6 @@ clutter_backend_egl_ensure_context (ClutterBackend *backend,
 #endif /* COGL_HAS_XLIB_SUPPORT */
 }
 
-static void
-clutter_backend_egl_redraw (ClutterBackend *backend,
-                            ClutterStage   *stage)
-{
-  ClutterStageWindow *impl;
-
-  impl = _clutter_stage_get_window (stage);
-  if (!impl)
-    return;
-
-  g_assert (CLUTTER_IS_STAGE_EGL (impl));
-
-  _clutter_stage_egl_redraw (CLUTTER_STAGE_EGL (impl), stage);
-}
-
 #ifndef COGL_HAS_XLIB_SUPPORT
 static ClutterDeviceManager *
 clutter_backend_egl_get_device_manager (ClutterBackend *backend)
@@ -679,7 +664,7 @@ check_vblank_env (const char *name)
 static ClutterFeatureFlags
 clutter_backend_egl_get_features (ClutterBackend *backend)
 {
-  ClutterBackendEGL  *backend_egl = CLUTTER_BACKEND_EGL (backend);
+  ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
   const gchar *egl_extensions = NULL;
   const gchar *gl_extensions = NULL;
   ClutterFeatureFlags flags;
@@ -687,8 +672,13 @@ clutter_backend_egl_get_features (ClutterBackend *backend)
   g_assert (backend_egl->egl_context != NULL);
 
 #ifdef COGL_HAS_XLIB_SUPPORT
-  flags = clutter_backend_x11_get_features (backend);
-  flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
+  {
+    ClutterBackendClass *parent_class;
+
+    parent_class = CLUTTER_BACKEND_CLASS (_clutter_backend_egl_parent_class);
+    flags = parent_class->get_features (backend);
+    flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
+  }
 #else
   flags = CLUTTER_FEATURE_STAGE_STATIC;
 #endif
@@ -750,6 +740,7 @@ clutter_backend_egl_create_stage (ClutterBackend  *backend,
 {
 #ifdef COGL_HAS_XLIB_SUPPORT
   ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
+  ClutterEventTranslator *translator;
   ClutterStageWindow *stage;
   ClutterStageX11 *stage_x11;
 
@@ -761,6 +752,10 @@ clutter_backend_egl_create_stage (ClutterBackend  *backend,
   /* copy backend data into the stage */
   stage_x11 = CLUTTER_STAGE_X11 (stage);
   stage_x11->wrapper = wrapper;
+  stage_x11->backend = backend_x11;
+
+  translator = CLUTTER_EVENT_TRANSLATOR (stage_x11);
+  _clutter_backend_add_event_translator (backend, translator);
 
   CLUTTER_NOTE (MISC, "EGLX stage created (display:%p, screen:%d, root:%u)",
                 backend_x11->xdpy,
@@ -869,7 +864,6 @@ _clutter_backend_egl_class_init (ClutterBackendEGLClass *klass)
   backend_class->create_stage       = clutter_backend_egl_create_stage;
   backend_class->create_context     = clutter_backend_egl_create_context;
   backend_class->ensure_context     = clutter_backend_egl_ensure_context;
-  backend_class->redraw             = clutter_backend_egl_redraw;
 
 #ifdef COGL_HAS_XLIB_SUPPORT
   backendx11_class->get_visual_info = clutter_backend_egl_get_visual_info;
index ff1a06d..f53318c 100644 (file)
@@ -274,7 +274,7 @@ clutter_event_dispatch (GSource     *source,
           clicked = FALSE;
         }
 
-      g_queue_push_head (clutter_context->events_queue, event);
+      _clutter_event_push (event, FALSE);
     }
 
   /* Pop an event off the queue if any */
index 6bf8dd7..8642df4 100644 (file)
@@ -42,24 +42,18 @@ clutter_stage_egl_unrealize (ClutterStageWindow *stage_window)
   ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window);
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
 
-  CLUTTER_NOTE (BACKEND, "Unrealizing stage");
+  CLUTTER_NOTE (BACKEND, "Unrealizing EGL stage [%p]", stage_egl);
 
   clutter_x11_trap_x_errors ();
 
-  if (!stage_x11->is_foreign_xwin && stage_x11->xwin != None)
-    {
-      XDestroyWindow (backend_x11->xdpy, stage_x11->xwin);
-      stage_x11->xwin = None;
-    }
-  else
-    stage_x11->xwin = None;
-
   if (stage_egl->egl_surface != EGL_NO_SURFACE)
     {
       eglDestroySurface (clutter_egl_get_egl_display (), stage_egl->egl_surface);
       stage_egl->egl_surface = EGL_NO_SURFACE;
     }
 
+  _clutter_stage_x11_destroy_window_untrapped (stage_x11);
+
   XSync (backend_x11->xdpy, False);
 
   clutter_x11_untrap_x_errors ();
@@ -72,73 +66,19 @@ clutter_stage_egl_realize (ClutterStageWindow *stage_window)
   ClutterStageX11   *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
   ClutterBackend    *backend;
   ClutterBackendEGL *backend_egl;
-  ClutterBackendX11 *backend_x11;
   EGLDisplay         edpy;
 
-  CLUTTER_NOTE (BACKEND, "Realizing main stage");
+  CLUTTER_NOTE (BACKEND, "Realizing stage '%s' [%p]",
+                G_OBJECT_TYPE_NAME (stage_egl),
+                stage_egl);
 
   backend     = clutter_get_default_backend ();
   backend_egl = CLUTTER_BACKEND_EGL (backend);
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
   edpy = clutter_egl_get_egl_display ();
 
-  if (stage_x11->xwin == None)
-    {
-      XSetWindowAttributes xattr;
-      unsigned long mask;
-      XVisualInfo *xvisinfo;
-      gfloat width, height;
-
-      CLUTTER_NOTE (MISC, "Creating stage X window");
-
-      xvisinfo = clutter_backend_x11_get_visual_info (backend_x11);
-      if (xvisinfo == NULL)
-        {
-          g_critical ("Unable to find suitable GL visual.");
-          return FALSE;
-        }
-
-      /* window attributes */
-      xattr.background_pixel = WhitePixel (backend_x11->xdpy,
-                                           backend_x11->xscreen_num);
-      xattr.border_pixel = 0;
-      xattr.colormap = XCreateColormap (backend_x11->xdpy,
-                                        backend_x11->xwin_root,
-                                        xvisinfo->visual,
-                                        AllocNone);
-      mask = CWBorderPixel | CWColormap;
-
-      /* Call get_size - this will either get the geometry size (which
-       * before we create the window is set to 640x480), or if a size
-       * is set, it will get that. This lets you set a size on the
-       * stage before it's realized.
-       */
-      clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper),
-                              &width,
-                              &height);
-      stage_x11->xwin_width = (gint)width;
-      stage_x11->xwin_height = (gint)height;
-
-      stage_x11->xwin = XCreateWindow (backend_x11->xdpy,
-                                       backend_x11->xwin_root,
-                                       0, 0,
-                                       stage_x11->xwin_width,
-                                       stage_x11->xwin_height,
-                                       0,
-                                       xvisinfo->depth,
-                                       InputOutput,
-                                       xvisinfo->visual,
-                                       mask, &xattr);
-
-      CLUTTER_NOTE (BACKEND, "Stage [%p], window: 0x%x, size: %dx%d",
-                    stage_window,
-                    (unsigned int) stage_x11->xwin,
-                    stage_x11->xwin_width,
-                    stage_x11->xwin_height);
-
-      XFree (xvisinfo);
-    }
+  if (!_clutter_stage_x11_create_window (stage_x11))
+    return FALSE;
 
   if (stage_egl->egl_surface == EGL_NO_SURFACE)
     {
@@ -152,38 +92,6 @@ clutter_stage_egl_realize (ClutterStageWindow *stage_window)
   if (stage_egl->egl_surface == EGL_NO_SURFACE)
     g_warning ("Unable to create an EGL surface");
 
-  if (clutter_x11_has_event_retrieval ())
-    {
-      if (clutter_x11_has_xinput ())
-        {
-          XSelectInput (backend_x11->xdpy, stage_x11->xwin,
-                        StructureNotifyMask |
-                        FocusChangeMask |
-                        ExposureMask |
-                        EnterWindowMask | LeaveWindowMask |
-                        PropertyChangeMask);
-#ifdef USE_XINPUT
-          _clutter_x11_select_events (stage_x11->xwin);
-#endif
-        }
-      else
-        XSelectInput (backend_x11->xdpy, stage_x11->xwin,
-                      StructureNotifyMask |
-                      FocusChangeMask |
-                      ExposureMask |
-                      PointerMotionMask |
-                      KeyPressMask | KeyReleaseMask |
-                      ButtonPressMask | ButtonReleaseMask |
-                      EnterWindowMask | LeaveWindowMask |
-                      PropertyChangeMask);
-    }
-
-  /* no user resize... */
-  clutter_stage_x11_fix_window_size (stage_x11,
-                                     stage_x11->xwin_width,
-                                     stage_x11->xwin_height);
-  clutter_stage_x11_set_wm_protocols (stage_x11);
-
   return clutter_stage_egl_parent_iface->realize (stage_window);
 }
 
@@ -361,85 +269,17 @@ clutter_stage_egl_add_redraw_clip (ClutterStageWindow *stage_window,
 }
 
 static void
-clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
+clutter_stage_egl_redraw (ClutterStageWindow *stage_window)
 {
+  ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window);
+  ClutterBackend *backend = clutter_get_default_backend ();
+  ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
+  ClutterActor *wrapper;
+  EGLSurface egl_surface;
+  gboolean may_use_clipped_redraw;
+  gboolean use_clipped_redraw;
 #ifdef COGL_HAS_X11_SUPPORT
-  clutter_stage_egl_parent_iface = g_type_interface_peek_parent (iface);
-
-  iface->realize = clutter_stage_egl_realize;
-  iface->unrealize = clutter_stage_egl_unrealize;
-
-  /* the rest is inherited from ClutterStageX11 */
-
-#else /* COGL_HAS_X11_SUPPORT */
-
-  iface->realize = clutter_stage_egl_realize;
-  iface->unrealize = clutter_stage_egl_unrealize;
-  iface->set_fullscreen = clutter_stage_egl_set_fullscreen;
-  iface->set_title = clutter_stage_egl_set_title;
-  iface->set_cursor_visible = clutter_stage_egl_set_cursor_visible;
-  iface->get_wrapper = clutter_stage_egl_get_wrapper;
-  iface->get_geometry = clutter_stage_egl_get_geometry;
-  iface->resize = clutter_stage_egl_resize;
-  iface->show = clutter_stage_egl_show;
-  iface->hide = clutter_stage_egl_hide;
-
-#endif /* COGL_HAS_X11_SUPPORT */
-
-  iface->add_redraw_clip = clutter_stage_egl_add_redraw_clip;
-  iface->has_redraw_clips = clutter_stage_egl_has_redraw_clips;
-  iface->ignoring_redraw_clips = clutter_stage_egl_ignoring_redraw_clips;
-}
-
-#ifdef COGL_HAS_X11_SUPPORT
-static void
-clutter_stage_egl_dispose (GObject *gobject)
-{
-  G_OBJECT_CLASS (_clutter_stage_egl_parent_class)->dispose (gobject);
-}
-
-static void
-_clutter_stage_egl_class_init (ClutterStageEGLClass *klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
-  gobject_class->dispose = clutter_stage_egl_dispose;
-}
-
-static void
-_clutter_stage_egl_init (ClutterStageEGL *stage)
-{
-  stage->egl_surface = EGL_NO_SURFACE;
-}
-
-#else /* COGL_HAS_X11_SUPPORT */
-
-static void
-_clutter_stage_egl_class_init (ClutterStageEGLClass *klass)
-{
-}
-
-static void
-_clutter_stage_egl_init (ClutterStageEGL *stage)
-{
-  /* Without X we only support one surface and that is associated
-   * with the backend directly instead of the stage */
-}
-
-#endif /* COGL_HAS_X11_SUPPORT */
-
-void
-_clutter_stage_egl_redraw (ClutterStageEGL *stage_egl,
-                           ClutterStage    *stage)
-{
-  ClutterBackend     *backend = clutter_get_default_backend ();
-  ClutterBackendEGL  *backend_egl = CLUTTER_BACKEND_EGL (backend);
-  ClutterActor       *wrapper;
-  EGLSurface          egl_surface;
-  gboolean            may_use_clipped_redraw;
-  gboolean            use_clipped_redraw;
-#ifdef COGL_HAS_X11_SUPPORT
-  ClutterStageX11    *stage_x11 = CLUTTER_STAGE_X11 (stage_egl);
+  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_egl);
 
   wrapper = CLUTTER_ACTOR (stage_x11->wrapper);
   egl_surface = stage_egl->egl_surface;
@@ -480,11 +320,12 @@ _clutter_stage_egl_redraw (ClutterStageEGL *stage_egl,
                                        stage_egl->bounding_redraw_clip.y,
                                        stage_egl->bounding_redraw_clip.width,
                                        stage_egl->bounding_redraw_clip.height);
-      _clutter_stage_do_paint (stage, &stage_egl->bounding_redraw_clip);
+      _clutter_stage_do_paint (CLUTTER_STAGE (wrapper),
+                               &stage_egl->bounding_redraw_clip);
       cogl_clip_pop ();
     }
   else
-    _clutter_stage_do_paint (stage, NULL);
+    _clutter_stage_do_paint (CLUTTER_STAGE (wrapper), NULL);
 
   if (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS &&
       may_use_clipped_redraw)
@@ -522,8 +363,7 @@ _clutter_stage_egl_redraw (ClutterStageEGL *stage_egl,
 
       cogl_push_matrix ();
       cogl_matrix_init_identity (&modelview);
-      _clutter_actor_apply_modelview_transform (CLUTTER_ACTOR (stage),
-                                                &modelview);
+      _clutter_actor_apply_modelview_transform (wrapper, &modelview);
       cogl_set_modelview_matrix (&modelview);
       cogl_set_source (outline);
       cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_LINE_LOOP,
@@ -573,6 +413,7 @@ _clutter_stage_egl_redraw (ClutterStageEGL *stage_egl,
       CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer);
       eglSwapBuffers (backend_egl->edpy, egl_surface);
       CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer);
+      _cogl_swap_buffers_notify ();
     }
 
   /* reset the redraw clipping for the next paint... */
@@ -580,3 +421,72 @@ _clutter_stage_egl_redraw (ClutterStageEGL *stage_egl,
 
   stage_egl->frame_count++;
 }
+
+static void
+clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
+{
+#ifdef COGL_HAS_X11_SUPPORT
+  clutter_stage_egl_parent_iface = g_type_interface_peek_parent (iface);
+
+  iface->realize = clutter_stage_egl_realize;
+  iface->unrealize = clutter_stage_egl_unrealize;
+
+  /* the rest is inherited from ClutterStageX11 */
+
+#else /* COGL_HAS_X11_SUPPORT */
+
+  iface->realize = clutter_stage_egl_realize;
+  iface->unrealize = clutter_stage_egl_unrealize;
+  iface->set_fullscreen = clutter_stage_egl_set_fullscreen;
+  iface->set_title = clutter_stage_egl_set_title;
+  iface->set_cursor_visible = clutter_stage_egl_set_cursor_visible;
+  iface->get_wrapper = clutter_stage_egl_get_wrapper;
+  iface->get_geometry = clutter_stage_egl_get_geometry;
+  iface->resize = clutter_stage_egl_resize;
+  iface->show = clutter_stage_egl_show;
+  iface->hide = clutter_stage_egl_hide;
+
+#endif /* COGL_HAS_X11_SUPPORT */
+
+  iface->add_redraw_clip = clutter_stage_egl_add_redraw_clip;
+  iface->has_redraw_clips = clutter_stage_egl_has_redraw_clips;
+  iface->ignoring_redraw_clips = clutter_stage_egl_ignoring_redraw_clips;
+  iface->redraw = clutter_stage_egl_redraw;
+}
+
+#ifdef COGL_HAS_X11_SUPPORT
+static void
+clutter_stage_egl_dispose (GObject *gobject)
+{
+  G_OBJECT_CLASS (_clutter_stage_egl_parent_class)->dispose (gobject);
+}
+
+static void
+_clutter_stage_egl_class_init (ClutterStageEGLClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->dispose = clutter_stage_egl_dispose;
+}
+
+static void
+_clutter_stage_egl_init (ClutterStageEGL *stage)
+{
+  stage->egl_surface = EGL_NO_SURFACE;
+}
+
+#else /* COGL_HAS_X11_SUPPORT */
+
+static void
+_clutter_stage_egl_class_init (ClutterStageEGLClass *klass)
+{
+}
+
+static void
+_clutter_stage_egl_init (ClutterStageEGL *stage)
+{
+  /* Without X we only support one surface and that is associated
+   * with the backend directly instead of the stage */
+}
+
+#endif /* COGL_HAS_X11_SUPPORT */
index 8dc0401..86e075e 100644 (file)
@@ -18,6 +18,7 @@
 #include "clutter-egl-headers.h"
 #include "clutter-backend-egl.h"
 
+G_BEGIN_DECLS
 
 #define CLUTTER_TYPE_STAGE_EGL                  (_clutter_stage_egl_get_type ())
 #define CLUTTER_STAGE_EGL(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_EGL, ClutterStageEGL))
@@ -69,7 +70,6 @@ struct _ClutterStageEGLClass
 
 GType _clutter_stage_egl_get_type (void) G_GNUC_CONST;
 
-void  _clutter_stage_egl_redraw   (ClutterStageEGL *stage_egl,
-                                  ClutterStage    *stage);
+G_END_DECLS
 
 #endif /* __CLUTTER_STAGE_EGL_H__ */
index 955718f..b87aa4f 100644 (file)
@@ -139,13 +139,10 @@ clutter_event_check (GSource *source)
 static void
 queue_event (ClutterEvent *event)
 {
-  ClutterMainContext *context;
-
   if (event == NULL)
     return;
 
-  context = _clutter_context_get_default ();
-  g_queue_push_head (context->events_queue, event);
+  _clutter_event_push (event, FALSE);
 }
 
 static void
index df1c1e8..054c34b 100644 (file)
@@ -77,6 +77,7 @@ clutter_backend_egl_redraw (ClutterBackend *backend,
   cogl_flush ();
   eglWaitGL();
   eglSwapBuffers (backend_egl->edpy,  stage_egl->egl_surface);
+  _cogl_swap_buffers_notify ();
 }
 
 static ClutterActor *
index d7a6117..df1b7f7 100644 (file)
 #include <GL/gl.h>
 
 #include "clutter-backend-glx.h"
-#include "clutter-event-glx.h"
 #include "clutter-stage-glx.h"
 #include "clutter-glx.h"
 #include "clutter-profile.h"
 
 #include "clutter-debug.h"
+#include "clutter-event-translator.h"
 #include "clutter-event.h"
 #include "clutter-main.h"
 #include "clutter-private.h"
@@ -51,8 +51,9 @@
 
 #include "cogl/cogl.h"
 
+#define clutter_backend_glx_get_type    _clutter_backend_glx_get_type
 
-G_DEFINE_TYPE (ClutterBackendGLX, _clutter_backend_glx, CLUTTER_TYPE_BACKEND_X11);
+G_DEFINE_TYPE (ClutterBackendGLX, clutter_backend_glx, CLUTTER_TYPE_BACKEND_X11);
 
 /* singleton object */
 static ClutterBackendGLX *backend_singleton = NULL;
@@ -69,6 +70,8 @@ static gboolean
 clutter_backend_glx_pre_parse (ClutterBackend  *backend,
                                GError         **error)
 {
+  ClutterBackendClass *parent_class =
+    CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
   const gchar *env_string;
 
   env_string = g_getenv ("CLUTTER_VBLANK");
@@ -78,7 +81,7 @@ clutter_backend_glx_pre_parse (ClutterBackend  *backend,
       env_string = NULL;
     }
 
-  return clutter_backend_x11_pre_parse (backend, error);
+  return parent_class->pre_parse (backend, error);
 }
 
 static gboolean
@@ -87,11 +90,11 @@ clutter_backend_glx_post_parse (ClutterBackend  *backend,
 {
   ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
   ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
-  ClutterBackendClass *backend_class =
-    CLUTTER_BACKEND_CLASS (_clutter_backend_glx_parent_class);
+  ClutterBackendClass *parent_class =
+    CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
   int glx_major, glx_minor;
 
-  if (!backend_class->post_parse (backend, error))
+  if (!parent_class->post_parse (backend, error))
     return FALSE;
 
   if (!glXQueryExtension (backend_x11->xdpy,
@@ -108,8 +111,8 @@ clutter_backend_glx_post_parse (ClutterBackend  *backend,
   /* XXX: Technically we should require >= GLX 1.3 support but for a long
    * time Mesa has exported a hybrid GLX, exporting extensions specified
    * to require GLX 1.3, but still reporting 1.2 via glXQueryVersion. */
-  if (!glXQueryVersion (backend_x11->xdpy, &glx_major, &glx_minor)
-      || !(glx_major == 1 && glx_minor >= 2))
+  if (!glXQueryVersion (backend_x11->xdpy, &glx_major, &glx_minor) ||
+      !(glx_major == 1 && glx_minor >= 2))
     {
       g_set_error (error, CLUTTER_INIT_ERROR,
                    CLUTTER_INIT_ERROR_BACKEND,
@@ -134,8 +137,12 @@ static void
 clutter_backend_glx_add_options (ClutterBackend *backend,
                                  GOptionGroup   *group)
 {
+  ClutterBackendClass *parent_class =
+    CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
+
   g_option_group_add_entries (group, entries);
-  clutter_backend_x11_add_options (backend, group);
+
+  parent_class->add_options (backend, group);
 }
 
 static void
@@ -144,7 +151,7 @@ clutter_backend_glx_finalize (GObject *gobject)
   if (backend_singleton)
     backend_singleton = NULL;
 
-  G_OBJECT_CLASS (_clutter_backend_glx_parent_class)->finalize (gobject);
+  G_OBJECT_CLASS (clutter_backend_glx_parent_class)->finalize (gobject);
 }
 
 static void
@@ -175,7 +182,7 @@ clutter_backend_glx_dispose (GObject *gobject)
       backend_glx->dummy_xwin = None;
     }
 
-  G_OBJECT_CLASS (_clutter_backend_glx_parent_class)->dispose (gobject);
+  G_OBJECT_CLASS (clutter_backend_glx_parent_class)->dispose (gobject);
 }
 
 static GObject *
@@ -188,7 +195,7 @@ clutter_backend_glx_constructor (GType                  gtype,
 
   if (!backend_singleton)
     {
-      parent_class = G_OBJECT_CLASS (_clutter_backend_glx_parent_class);
+      parent_class = G_OBJECT_CLASS (clutter_backend_glx_parent_class);
       retval = parent_class->constructor (gtype, n_params, params);
 
       backend_singleton = CLUTTER_BACKEND_GLX (retval);
@@ -215,12 +222,15 @@ static ClutterFeatureFlags
 clutter_backend_glx_get_features (ClutterBackend *backend)
 {
   ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
+  ClutterBackendClass *parent_class;
   const gchar *glx_extensions = NULL;
   const gchar *gl_extensions = NULL;
   ClutterFeatureFlags flags;
   gboolean use_dri = FALSE;
 
-  flags = clutter_backend_x11_get_features (backend);
+  parent_class = CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
+
+  flags = parent_class->get_features (backend);
   flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
 
   /* this will make sure that the GL context exists */
@@ -495,8 +505,11 @@ _clutter_backend_glx_get_fbconfig (ClutterBackendGLX *backend_glx,
 
 void
 _clutter_backend_glx_blit_sub_buffer (ClutterBackendGLX *backend_glx,
-                                      GLXDrawable drawable,
-                                      int x, int y, int width, int height)
+                                      GLXDrawable        drawable,
+                                      int                x,
+                                      int                y,
+                                      int                width,
+                                      int                height)
 {
   ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend_glx);
 
@@ -759,34 +772,13 @@ clutter_backend_glx_ensure_context (ClutterBackend *backend,
     }
 }
 
-/*
- * FIXME: we should remove backend_class->redraw() and just
- * have stage_window_iface->redraw()
- */
-static void
-clutter_backend_glx_redraw (ClutterBackend *backend,
-                            ClutterStage   *stage)
-{
-  ClutterStageWindow *impl = _clutter_stage_get_window (stage);
-
-  if (G_UNLIKELY (impl == NULL))
-    {
-      CLUTTER_NOTE (BACKEND, "Stage [%p] has no implementation", stage);
-      return;
-    }
-
-  g_assert (CLUTTER_IS_STAGE_GLX (impl));
-
-  _clutter_stage_glx_redraw (CLUTTER_STAGE_GLX (impl),
-                             stage);
-}
-
 static ClutterStageWindow *
 clutter_backend_glx_create_stage (ClutterBackend  *backend,
                                   ClutterStage    *wrapper,
                                   GError         **error)
 {
   ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
+  ClutterEventTranslator *translator;
   ClutterStageWindow *stage_window;
   ClutterStageX11 *stage_x11;
 
@@ -798,6 +790,10 @@ clutter_backend_glx_create_stage (ClutterBackend  *backend,
   /* copy backend data into the stage */
   stage_x11 = CLUTTER_STAGE_X11 (stage_window);
   stage_x11->wrapper = wrapper;
+  stage_x11->backend = backend_x11;
+
+  translator = CLUTTER_EVENT_TRANSLATOR (stage_x11);
+  _clutter_backend_add_event_translator (backend, translator);
 
   CLUTTER_NOTE (BACKEND,
                 "GLX stage created[%p] (dpy:%p, screen:%d, root:%u, wrap:%p)",
@@ -811,7 +807,7 @@ clutter_backend_glx_create_stage (ClutterBackend  *backend,
 }
 
 static void
-_clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
+clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
@@ -826,18 +822,15 @@ _clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
   backend_class->create_stage   = clutter_backend_glx_create_stage;
   backend_class->add_options    = clutter_backend_glx_add_options;
   backend_class->get_features   = clutter_backend_glx_get_features;
-  backend_class->redraw         = clutter_backend_glx_redraw;
   backend_class->create_context = clutter_backend_glx_create_context;
   backend_class->ensure_context = clutter_backend_glx_ensure_context;
 
   backendx11_class->get_visual_info = clutter_backend_glx_get_visual_info;
-  backendx11_class->handle_event = _clutter_backend_glx_handle_event;
 }
 
 static void
-_clutter_backend_glx_init (ClutterBackendGLX *backend_glx)
+clutter_backend_glx_init (ClutterBackendGLX *backend_glx)
 {
-
 }
 
 /* every backend must implement this function */
diff --git a/clutter/glx/clutter-event-glx.c b/clutter/glx/clutter-event-glx.c
deleted file mode 100644 (file)
index dadb3b1..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/* Clutter.
- * An OpenGL based 'interactive canvas' library.
- * Authored By Matthew Allum  <mallum@openedhand.com>
- * Copyright (C) 2006-2007 OpenedHand
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "clutter-x11.h"
-#include "clutter-stage-x11.h"
-#include "clutter-backend-x11.h"
-#include "clutter-stage-glx.h"
-#include "clutter-backend-glx.h"
-
-#include "clutter-private.h"
-#include "clutter-stage-private.h"
-
-#include <clutter/clutter-backend.h>
-#include <clutter/clutter-stage-manager.h>
-
-#include <X11/Xlib.h>
-
-#include <GL/glxext.h>
-
-#include <glib.h>
-
-gboolean
-_clutter_backend_glx_handle_event (ClutterBackendX11 *backend_x11,
-                                  XEvent            *xevent)
-{
-#ifdef GLX_INTEL_swap_event
-  ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend_x11);
-  ClutterStageManager *stage_manager;
-  GLXBufferSwapComplete *swap_complete_event;
-  const GSList *l;
-
-  if (xevent->type != (backend_glx->event_base + GLX_BufferSwapComplete))
-    return FALSE; /* Unhandled */
-
-  swap_complete_event = (GLXBufferSwapComplete *)xevent;
-
-#if 0
-  {
-    const char *event_name;
-    if (swap_complete_event->event_type == GLX_EXCHANGE_COMPLETE_INTEL)
-      event_name = "GLX_EXCHANGE_COMPLETE";
-    else if (swap_complete_event->event_type == GLX_BLIT_COMPLETE_INTEL)
-      event_name = "GLX_BLIT_COMPLETE";
-    else
-      {
-        g_assert (swap_complete_event->event_type == GLX_FLIP_COMPLETE_INTEL);
-        event_name = "GLX_FLIP_COMPLETE";
-      }
-
-    g_print ("XXX: clutter_backend_glx_event_handle event = %s\n",
-             event_name);
-  }
-#endif
-
-  stage_manager = clutter_stage_manager_get_default ();
-
-  for (l = clutter_stage_manager_peek_stages (stage_manager); l; l = l->next)
-    {
-      ClutterStageWindow *stage_win = _clutter_stage_get_window (l->data);
-      ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_win);
-      ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_win);
-
-      if (stage_x11->xwin == swap_complete_event->drawable)
-        {
-         /* Early versions of the swap_event implementation in Mesa
-          * deliver BufferSwapComplete event when not selected for,
-          * so if we get a swap event we aren't expecting, just ignore it.
-          *
-          * https://bugs.freedesktop.org/show_bug.cgi?id=27962
-          */
-          if (stage_glx->pending_swaps > 0)
-            stage_glx->pending_swaps--;
-
-          return TRUE;
-        }
-    }
-
-  return TRUE;
-#else
-  return FALSE;
-#endif
-}
-
index e3ef4db..662764d 100644 (file)
  * may use the extension if it is possible.
  */
 
-
-
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
+
+#include "clutter-glx-texture-pixmap.h"
 
 #include <string.h>
 
-#include "../x11/clutter-x11-texture-pixmap.h"
-#include "clutter-glx-texture-pixmap.h"
+#include <GL/glx.h>
+
+#include "x11/clutter-x11-texture-pixmap.h"
 #include "cogl/winsys/cogl-texture-pixmap-x11.h"
 
 G_DEFINE_TYPE (ClutterGLXTexturePixmap,    \
                clutter_glx_texture_pixmap, \
                CLUTTER_X11_TYPE_TEXTURE_PIXMAP);
 
-
 static void
 clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self)
 {
@@ -83,6 +81,9 @@ clutter_glx_texture_pixmap_class_init (ClutterGLXTexturePixmapClass *klass)
  *   GLX_EXT_texture_from_pixmap OpenGL extension or falling back to the
  *   slower software mechanism.
  *
+ * Deprecated: 1.6: Use cogl_texture_pixmap_x11_is_using_tfp_extension()
+ *   on the texture handle instead.
+ *
  * Since: 0.8
  */
 gboolean
@@ -107,6 +108,8 @@ clutter_glx_texture_pixmap_using_extension (ClutterGLXTexturePixmap *texture)
  * Return value: A new #ClutterGLXTexturePixmap bound to the given X Pixmap
  *
  * Since: 0.8
+ *
+ * Deprecated: 1.6: Use clutter_x11_texture_pixmap_new_with_pixmap() instead
  */
 ClutterActor *
 clutter_glx_texture_pixmap_new_with_pixmap (Pixmap pixmap)
@@ -125,7 +128,9 @@ clutter_glx_texture_pixmap_new_with_pixmap (Pixmap pixmap)
  * Return value: A new #ClutterGLXTexturePixmap bound to the given X window
  *
  * Since: 0.8
- **/
+ *
+ * Deprecated: 1.6: Use clutter_x11_texture_pixmap_new_with_window() instead
+ */
 ClutterActor *
 clutter_glx_texture_pixmap_new_with_window (Window window)
 {
@@ -142,6 +147,8 @@ clutter_glx_texture_pixmap_new_with_window (Window window)
  * Return value: A new #ClutterGLXTexturePixmap
  *
  * Since: 0.8
+ *
+ * Deprecated: 1.6: Use clutter_x11_texture_pixmap_new() instead
  */
 ClutterActor *
 clutter_glx_texture_pixmap_new (void)
index 95275d6..c99ffae 100644 (file)
 #ifndef __CLUTTER_GLX_TEXTURE_PIXMAP_H__
 #define __CLUTTER_GLX_TEXTURE_PIXMAP_H__
 
-#include <glib.h>
-#include <glib-object.h>
 #include <clutter/x11/clutter-x11-texture-pixmap.h>
 
-#include <GL/glx.h>
+#if !defined(CLUTTER_COMPILATION) || defined(CLUTTER_DISABLE_DEPRECATED)
 
 G_BEGIN_DECLS
 
@@ -51,6 +49,8 @@ typedef struct _ClutterGLXTexturePixmapPrivate ClutterGLXTexturePixmapPrivate;
  * The #ClutterGLXTexturePixmapClass structure contains only private data
  *
  * Since: 0.8
+ *
+ * Deprecated: 1.6: Use #ClutterX11TexturePixmapClass instead
  */
 struct _ClutterGLXTexturePixmapClass
 {
@@ -64,6 +64,8 @@ struct _ClutterGLXTexturePixmapClass
  * The #ClutterGLXTexturePixmap structure contains only private data
  *
  * Since: 0.8
+ *
+ * Deprecated: 1.6: Use #ClutterX11TexturePixmap instead
  */
 struct _ClutterGLXTexturePixmap
 {
@@ -85,4 +87,6 @@ gboolean       clutter_glx_texture_pixmap_using_extension (ClutterGLXTexturePixm
 
 G_END_DECLS
 
-#endif
+#endif /* !CLUTTER_DISABLE_DEPRECATED || CLUTTER_COMPILATION */
+
+#endif /* __CLUTTER_GLX_TEXTURE_PIXMAP_H__ */
index ae3c8cd..6d22e54 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "clutter-actor-private.h"
 #include "clutter-debug.h"
+#include "clutter-device-manager.h"
 #include "clutter-event.h"
 #include "clutter-enum-types.h"
 #include "clutter-feature.h"
 #include <drm.h>
 #endif
 
-static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
+static void clutter_stage_window_iface_init     (ClutterStageWindowIface     *iface);
+static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface);
 
-static ClutterStageWindowIface *clutter_stage_glx_parent_iface = NULL;
+static ClutterStageWindowIface *clutter_stage_window_parent_iface = NULL;
+static ClutterEventTranslatorIface *clutter_event_translator_parent_iface = NULL;
+
+#define clutter_stage_glx_get_type      _clutter_stage_glx_get_type
 
 G_DEFINE_TYPE_WITH_CODE (ClutterStageGLX,
-                         _clutter_stage_glx,
+                         clutter_stage_glx,
                          CLUTTER_TYPE_STAGE_X11,
                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
-                                                clutter_stage_window_iface_init));
+                                                clutter_stage_window_iface_init)
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR,
+                                                clutter_event_translator_iface_init));
 
 static void
 clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
@@ -70,7 +77,7 @@ clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
   ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
 
   /* Note unrealize should free up any backend stage related resources */
-  CLUTTER_NOTE (BACKEND, "Unrealizing stage");
+  CLUTTER_NOTE (BACKEND, "Unrealizing GLX stage [%p]", stage_glx);
 
   clutter_x11_trap_x_errors ();
 
@@ -80,19 +87,11 @@ clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
       stage_glx->glxwin = None;
     }
 
-  if (!stage_x11->is_foreign_xwin && stage_x11->xwin != None)
-    {
-      XDestroyWindow (backend_x11->xdpy, stage_x11->xwin);
-      stage_x11->xwin = None;
-    }
-  else
-    stage_x11->xwin = None;
+  _clutter_stage_x11_destroy_window_untrapped (stage_x11);
 
   XSync (backend_x11->xdpy, False);
 
   clutter_x11_untrap_x_errors ();
-
-  CLUTTER_MARK ();
 }
 
 static gboolean
@@ -103,7 +102,6 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window)
   ClutterBackendX11 *backend_x11;
   ClutterBackendGLX *backend_glx;
   ClutterBackend *backend;
-  int event_flags;
 
   CLUTTER_NOTE (ACTOR, "Realizing stage '%s' [%p]",
                 G_OBJECT_TYPE_NAME (stage_window),
@@ -113,62 +111,8 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window)
   backend_glx = CLUTTER_BACKEND_GLX (backend);
   backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
-  if (stage_x11->xwin == None)
-    {
-      XSetWindowAttributes xattr;
-      unsigned long mask;
-      XVisualInfo *xvisinfo;
-      gfloat width, height;
-
-      CLUTTER_NOTE (MISC, "Creating stage X window");
-
-      xvisinfo = clutter_backend_x11_get_visual_info (backend_x11);
-      if (xvisinfo == NULL)
-        {
-          g_critical ("Unable to find suitable GL visual.");
-          return FALSE;
-        }
-
-      /* window attributes */
-      xattr.background_pixel = WhitePixel (backend_x11->xdpy,
-                                           backend_x11->xscreen_num);
-      xattr.border_pixel = 0;
-      xattr.colormap = XCreateColormap (backend_x11->xdpy,
-                                        backend_x11->xwin_root,
-                                        xvisinfo->visual,
-                                        AllocNone);
-      mask = CWBorderPixel | CWColormap;
-
-      /* Call get_size - this will either get the geometry size (which
-       * before we create the window is set to 640x480), or if a size
-       * is set, it will get that. This lets you set a size on the
-       * stage before it's realized.
-       */
-      clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper),
-                              &width,
-                              &height);
-      stage_x11->xwin_width = (gint)width;
-      stage_x11->xwin_height = (gint)height;
-
-      stage_x11->xwin = XCreateWindow (backend_x11->xdpy,
-                                       backend_x11->xwin_root,
-                                       0, 0,
-                                       stage_x11->xwin_width,
-                                       stage_x11->xwin_height,
-                                       0,
-                                       xvisinfo->depth,
-                                       InputOutput,
-                                       xvisinfo->visual,
-                                       mask, &xattr);
-
-      CLUTTER_NOTE (BACKEND, "Stage [%p], window: 0x%x, size: %dx%d",
-                    stage_window,
-                    (unsigned int) stage_x11->xwin,
-                    stage_x11->xwin_width,
-                    stage_x11->xwin_height);
-
-      XFree (xvisinfo);
-    }
+  if (!_clutter_stage_x11_create_window (stage_x11))
+    return FALSE;
 
   if (stage_glx->glxwin == None)
     {
@@ -178,7 +122,8 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window)
 
       /* Try and create a GLXWindow to use with extensions dependent on
        * GLX versions >= 1.3 that don't accept regular X Windows as GLX
-       * drawables. */
+       * drawables.
+       */
       if (glXQueryVersion (backend_x11->xdpy, &major, &minor) &&
           major == 1 && minor >= 3 &&
           _clutter_backend_glx_get_fbconfig (backend_glx, &config))
@@ -190,56 +135,16 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window)
         }
     }
 
-  /* the masks for the events we want to select on a stage window;
-   * KeyPressMask and KeyReleaseMask are necessary even with XI1
-   * because key events are broken with that extension, and will
-   * be fixed by XI2
-   */
-  event_flags = StructureNotifyMask
-              | FocusChangeMask
-              | ExposureMask
-              | PropertyChangeMask
-              | EnterWindowMask
-              | LeaveWindowMask
-              | KeyPressMask
-              | KeyReleaseMask;
-
-  /* if we don't use XI1 then we also want core pointer events */
-  if (!clutter_x11_has_xinput ())
-    event_flags |= (ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
-#ifdef HAVE_XINPUT
-  else
-    _clutter_x11_select_events (stage_x11->xwin);
-#endif
-
-  /* we unconditionally select input events even with event retrieval
-   * disabled because we need to guarantee that the Clutter internal
-   * state is maintained when calling clutter_x11_handle_event() without
-   * requiring applications or embedding toolkits to select events
-   * themselves. if we did that, we'd have to document the events to be
-   * selected, and also update applications and embedding toolkits each
-   * time we added a new mask, or a new class of events.
-   *
-   * see: http://bugzilla.clutter-project.org/show_bug.cgi?id=998
-   * for the rationale of why we did conditional selection. it is now
-   * clear that a compositor should clear out the input region, since
-   * it cannot assume a perfectly clean slate coming from us.
-   *
-   * see: http://bugzilla.clutter-project.org/show_bug.cgi?id=2228
-   * for an example of things that break if we do conditional event
-   * selection.
-   */
-  XSelectInput (backend_x11->xdpy, stage_x11->xwin, event_flags);
-
 #ifdef GLX_INTEL_swap_event
   if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
     {
-      GLXDrawable drawable =
-        stage_glx->glxwin ? stage_glx->glxwin : stage_x11->xwin;
+      GLXDrawable drawable = stage_glx->glxwin
+                           ? stage_glx->glxwin
+                           : stage_x11->xwin;
 
-      /* similarly to above, we unconditionally select this event
-       * because we rely on it to advance the master clock, and
-       * drive redraw/relayout, animations and event handling.
+      /* we unconditionally select this event because we rely on it to
+       * advance the master clock, and drive redraw/relayout, animations
+       * and event handling.
        */
       glXSelectEvent (backend_x11->xdpy,
                       drawable,
@@ -247,16 +152,8 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window)
     }
 #endif /* GLX_INTEL_swap_event */
 
-  /* no user resize.. */
-  clutter_stage_x11_fix_window_size (stage_x11,
-                                     stage_x11->xwin_width,
-                                     stage_x11->xwin_height);
-  clutter_stage_x11_set_wm_protocols (stage_x11);
-
-  CLUTTER_NOTE (BACKEND, "Successfully realized stage");
-
   /* chain up to the StageX11 implementation */
-  return clutter_stage_glx_parent_iface->realize (stage_window);
+  return clutter_stage_window_parent_iface->realize (stage_window);
 }
 
 static int
@@ -268,21 +165,12 @@ clutter_stage_glx_get_pending_swaps (ClutterStageWindow *stage_window)
 }
 
 static void
-clutter_stage_glx_dispose (GObject *gobject)
-{
-  G_OBJECT_CLASS (_clutter_stage_glx_parent_class)->dispose (gobject);
-}
-
-static void
-_clutter_stage_glx_class_init (ClutterStageGLXClass *klass)
+clutter_stage_glx_class_init (ClutterStageGLXClass *klass)
 {
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
-  gobject_class->dispose = clutter_stage_glx_dispose;
 }
 
 static void
-_clutter_stage_glx_init (ClutterStageGLX *stage)
+clutter_stage_glx_init (ClutterStageGLX *stage)
 {
 }
 
@@ -423,22 +311,6 @@ clutter_stage_glx_add_redraw_clip (ClutterStageWindow *stage_window,
   stage_glx->initialized_redraw_clip = TRUE;
 }
 
-static void
-clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
-{
-  clutter_stage_glx_parent_iface = g_type_interface_peek_parent (iface);
-
-  iface->realize = clutter_stage_glx_realize;
-  iface->unrealize = clutter_stage_glx_unrealize;
-  iface->get_pending_swaps = clutter_stage_glx_get_pending_swaps;
-
-  iface->add_redraw_clip = clutter_stage_glx_add_redraw_clip;
-  iface->has_redraw_clips = clutter_stage_glx_has_redraw_clips;
-  iface->ignoring_redraw_clips = clutter_stage_glx_ignoring_redraw_clips;
-
-  /* the rest is inherited from ClutterStageX11 */
-}
-
 #ifdef HAVE_DRM
 static int
 drm_wait_vblank(int fd, drm_wait_vblank_t *vbl)
@@ -489,18 +361,18 @@ wait_for_vblank (ClutterBackendGLX *backend_glx)
     }
 }
 
-void
-_clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
-                          ClutterStage *stage)
+static void
+clutter_stage_glx_redraw (ClutterStageWindow *stage_window)
 {
-  ClutterBackend    *backend;
   ClutterBackendX11 *backend_x11;
   ClutterBackendGLX *backend_glx;
-  ClutterStageX11   *stage_x11;
-  GLXDrawable        drawable;
-  unsigned int       video_sync_count;
-  gboolean           may_use_clipped_redraw;
-  gboolean           use_clipped_redraw;
+  ClutterStageX11 *stage_x11;
+  ClutterStageGLX *stage_glx;
+  GLXDrawable drawable;
+  unsigned int video_sync_count;
+  gboolean may_use_clipped_redraw;
+  gboolean use_clipped_redraw;
+
   CLUTTER_STATIC_TIMER (painting_timer,
                         "Redrawing", /* parent */
                         "Painting actors",
@@ -517,11 +389,14 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
                         "The time spent in _glx_blit_sub_buffer",
                         0 /* no application private data */);
 
-  backend     = clutter_get_default_backend ();
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
-  backend_glx = CLUTTER_BACKEND_GLX (backend);
+  stage_x11 = CLUTTER_STAGE_X11 (stage_window);
+  if (stage_x11->xwin == None)
+    return;
 
-  stage_x11 = CLUTTER_STAGE_X11 (stage_glx);
+  stage_glx = CLUTTER_STAGE_GLX (stage_window);
+
+  backend_x11 = stage_x11->backend;
+  backend_glx = CLUTTER_BACKEND_GLX (backend_x11);
 
   CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer);
 
@@ -535,7 +410,9 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
        * artefacts. See clutter-event-x11.c:event_translate for a
        * detailed explanation */
       G_LIKELY (stage_x11->clipped_redraws_cool_off == 0))
-    may_use_clipped_redraw = TRUE;
+    {
+      may_use_clipped_redraw = TRUE;
+    }
   else
     may_use_clipped_redraw = FALSE;
 
@@ -552,17 +429,19 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
                                        stage_glx->bounding_redraw_clip.y,
                                        stage_glx->bounding_redraw_clip.width,
                                        stage_glx->bounding_redraw_clip.height);
-      _clutter_stage_do_paint (stage, &stage_glx->bounding_redraw_clip);
+      _clutter_stage_do_paint (stage_x11->wrapper,
+                               &stage_glx->bounding_redraw_clip);
       cogl_clip_pop ();
     }
   else
-    _clutter_stage_do_paint (stage, NULL);
+    _clutter_stage_do_paint (stage_x11->wrapper, NULL);
 
-  if (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS &&
-      may_use_clipped_redraw)
+  if (may_use_clipped_redraw &&
+      G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)))
     {
-      ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
       static CoglMaterial *outline = NULL;
+      ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
+      ClutterActor *actor = CLUTTER_ACTOR (stage_x11->wrapper);
       CoglHandle vbo;
       float x_1 = clip->x;
       float x_2 = clip->x + clip->width;
@@ -594,8 +473,7 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
 
       cogl_push_matrix ();
       cogl_matrix_init_identity (&modelview);
-      _clutter_actor_apply_modelview_transform (CLUTTER_ACTOR (stage),
-                                                &modelview);
+      _clutter_actor_apply_modelview_transform (actor, &modelview);
       cogl_set_modelview_matrix (&modelview);
       cogl_set_source (outline);
       cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_LINE_LOOP,
@@ -607,10 +485,9 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
   cogl_flush ();
   CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer);
 
-  if (stage_x11->xwin == None)
-    return;
-
-  drawable = stage_glx->glxwin ? stage_glx->glxwin : stage_x11->xwin;
+  drawable = stage_glx->glxwin
+           ? stage_glx->glxwin
+           : stage_x11->xwin;
 
   /* If we might ever use _clutter_backend_glx_blit_sub_buffer then we
    * always need to keep track of the video_sync_count so that we can
@@ -628,6 +505,7 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
     {
       ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
       ClutterGeometry copy_area;
+      ClutterActor *actor;
 
       CLUTTER_NOTE (BACKEND,
                     "_glx_blit_sub_buffer (window: 0x%lx, "
@@ -646,8 +524,10 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
        * in this case a full redraw should be queued by the resize
        * anyway so it should only exhibit temporary artefacts.
        */
-      copy_area.y = clutter_actor_get_height (CLUTTER_ACTOR (stage))
-        - clip->y - clip->height;
+      actor = CLUTTER_ACTOR (stage_x11->wrapper);
+      copy_area.y = clutter_actor_get_height (actor)
+                  - clip->y
+                  - clip->height;
       copy_area.x = clip->x;
       copy_area.width = clip->width;
       copy_area.height = clip->height;
@@ -675,7 +555,7 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
            * See where we call glXSwapBuffers for more details.
            */
           glFinish ();
-          wait_for_vblank (CLUTTER_BACKEND_GLX (backend));
+          wait_for_vblank (backend_glx);
         }
       else if (backend_glx->get_video_sync)
         {
@@ -684,10 +564,10 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
            * any waits if we can see that the video sync count has
            * already progressed. */
           if (backend_glx->last_video_sync_count == video_sync_count)
-            wait_for_vblank (CLUTTER_BACKEND_GLX (backend));
+            wait_for_vblank (backend_glx);
         }
       else
-        wait_for_vblank (CLUTTER_BACKEND_GLX (backend));
+        wait_for_vblank (backend_glx);
 
       CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer);
       _clutter_backend_glx_blit_sub_buffer (backend_glx,
@@ -697,6 +577,13 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
                                             copy_area.width,
                                             copy_area.height);
       CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer);
+
+      /* NB: unlike glXSwapBuffers, glXCopySubBuffer and
+       * glBlitFramebuffer don't issue an implicit glFlush() so we
+       * have to flush ourselves if we want the request to complete in
+       * finite amount of time since otherwise the driver can batch
+       * the command indefinitely. */
+      glFlush ();
     }
   else
     {
@@ -731,12 +618,14 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
            */
           glFinish ();
 
-          wait_for_vblank (CLUTTER_BACKEND_GLX (backend));
+          wait_for_vblank (backend_glx);
         }
 
       CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer);
       glXSwapBuffers (backend_x11->xdpy, drawable);
       CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer);
+
+      _cogl_swap_buffers_notify ();
     }
 
   backend_glx->last_video_sync_count = video_sync_count;
@@ -747,3 +636,68 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
   stage_glx->frame_count++;
 }
 
+static void
+clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
+{
+  clutter_stage_window_parent_iface = g_type_interface_peek_parent (iface);
+
+  iface->realize = clutter_stage_glx_realize;
+  iface->unrealize = clutter_stage_glx_unrealize;
+  iface->get_pending_swaps = clutter_stage_glx_get_pending_swaps;
+
+  iface->add_redraw_clip = clutter_stage_glx_add_redraw_clip;
+  iface->has_redraw_clips = clutter_stage_glx_has_redraw_clips;
+  iface->ignoring_redraw_clips = clutter_stage_glx_ignoring_redraw_clips;
+  iface->redraw = clutter_stage_glx_redraw;
+
+  /* the rest is inherited from ClutterStageX11 */
+}
+
+static ClutterTranslateReturn
+clutter_stage_glx_translate_event (ClutterEventTranslator *translator,
+                                   gpointer                native,
+                                   ClutterEvent           *event)
+{
+#ifdef GLX_INTEL_swap_event
+  ClutterBackendGLX *backend_glx;
+  XEvent *xevent = native;
+
+  backend_glx = CLUTTER_BACKEND_GLX (clutter_get_default_backend ());
+
+  if (xevent->type == (backend_glx->event_base + GLX_BufferSwapComplete))
+    {
+      ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (translator);
+      ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (translator);
+      GLXBufferSwapComplete *swap_complete_event;
+
+      swap_complete_event = (GLXBufferSwapComplete *) xevent;
+
+      if (stage_x11->xwin == swap_complete_event->drawable)
+        {
+         /* Early versions of the swap_event implementation in Mesa
+          * deliver BufferSwapComplete event when not selected for,
+          * so if we get a swap event we aren't expecting, just ignore it.
+          *
+          * https://bugs.freedesktop.org/show_bug.cgi?id=27962
+          */
+          if (stage_glx->pending_swaps > 0)
+            stage_glx->pending_swaps--;
+
+          return CLUTTER_TRANSLATE_REMOVE;
+        }
+    }
+#endif
+
+  /* chain up to the common X11 implementation */
+  return clutter_event_translator_parent_iface->translate_event (translator,
+                                                                 native,
+                                                                 event);
+}
+
+static void
+clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface)
+{
+  clutter_event_translator_parent_iface = g_type_interface_peek_parent (iface);
+
+  iface->translate_event = clutter_stage_glx_translate_event;
+}
index bc81f0b..54b3fcc 100644 (file)
@@ -69,9 +69,6 @@ struct _ClutterStageGLXClass
 
 GType _clutter_stage_glx_get_type  (void) G_GNUC_CONST;
 
-void  _clutter_stage_glx_redraw    (ClutterStageGLX *stage_glx,
-                                   ClutterStage *stage);
-
 G_END_DECLS
 
 #endif /* __CLUTTER_STAGE_H__ */
index 501743c..fe83daf 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2007-2008  Tommi Komulainen <tommi.komulainen@iki.fi>
  * Copyright (C) 2007  OpenedHand Ltd.
+ * Copyright (C) 2011  Crystalnix <vgachkaylo@crystalnix.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,6 +24,7 @@
 
 #include "clutter-osx.h"
 #include "clutter-backend-osx.h"
+#include "clutter-device-manager-osx.h"
 #include "clutter-stage-osx.h"
 
 #include "clutter-debug.h"
@@ -78,7 +80,7 @@ clutter_backend_osx_create_stage (ClutterBackend  *backend,
 
   CLUTTER_OSX_POOL_ALLOC();
 
-  impl = clutter_stage_osx_new (backend, wrapper);
+  impl = _clutter_stage_osx_new (backend, wrapper);
 
   CLUTTER_NOTE (BACKEND, "create_stage: impl=%p", impl);
 
@@ -87,11 +89,38 @@ clutter_backend_osx_create_stage (ClutterBackend  *backend,
   return impl;
 }
 
+static inline void
+clutter_backend_osx_create_device_manager (ClutterBackendOSX *backend_osx)
+{
+  if (backend_osx->device_manager != NULL)
+    return;
+
+  backend_osx->device_manager = g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_OSX,
+                                              "backend", CLUTTER_BACKEND(backend_osx),
+                                              NULL);
+}
+
+static ClutterDeviceManager *
+clutter_backend_osx_get_device_manager (ClutterBackend *backend)
+{
+  ClutterBackendOSX *backend_osx = CLUTTER_BACKEND_OSX (backend);
+
+  clutter_backend_osx_create_device_manager (backend_osx);
+
+  return backend_osx->device_manager;
+}
+
 static void
 clutter_backend_osx_init_events (ClutterBackend *backend)
 {
+  ClutterBackendOSX *backend_osx = CLUTTER_BACKEND_OSX (backend);
+
+  if (backend_osx->device_manager != NULL)
+    return;
+
   CLUTTER_NOTE (BACKEND, "init_events");
 
+  clutter_backend_osx_create_device_manager (backend_osx);
   _clutter_events_osx_init ();
 }
 
@@ -162,19 +191,6 @@ clutter_backend_osx_ensure_context (ClutterBackend *backend,
   CLUTTER_OSX_POOL_RELEASE();
 }
 
-static void
-clutter_backend_osx_redraw (ClutterBackend *backend, ClutterStage *wrapper)
-{
-  ClutterStageWindow *impl = _clutter_stage_get_window (wrapper);
-  ClutterStageOSX *stage_osx = CLUTTER_STAGE_OSX (impl);
-
-  CLUTTER_OSX_POOL_ALLOC();
-
-  [stage_osx->view setNeedsDisplay: YES];
-
-  CLUTTER_OSX_POOL_RELEASE();
-}
-
 /*************************************************************************/
 
 static void
@@ -221,13 +237,13 @@ clutter_backend_osx_class_init (ClutterBackendOSXClass *klass)
 
   object_class->dispose = clutter_backend_osx_dispose;
 
-  backend_class->post_parse       = clutter_backend_osx_post_parse;
-  backend_class->get_features     = clutter_backend_osx_get_features;
-  backend_class->create_stage     = clutter_backend_osx_create_stage;
-  backend_class->create_context   = clutter_backend_osx_create_context;
-  backend_class->ensure_context   = clutter_backend_osx_ensure_context;
-  backend_class->init_events      = clutter_backend_osx_init_events;
-  backend_class->redraw           = clutter_backend_osx_redraw;
+  backend_class->post_parse         = clutter_backend_osx_post_parse;
+  backend_class->get_features       = clutter_backend_osx_get_features;
+  backend_class->create_stage       = clutter_backend_osx_create_stage;
+  backend_class->create_context     = clutter_backend_osx_create_context;
+  backend_class->ensure_context     = clutter_backend_osx_ensure_context;
+  backend_class->init_events        = clutter_backend_osx_init_events;
+  backend_class->get_device_manager = clutter_backend_osx_get_device_manager;
 }
 
 GType
index 339bcb8..8651bbc 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2007  Tommi Komulainen <tommi.komulainen@iki.fi>
  * Copyright (C) 2007  OpenedHand Ltd.
+ * Copyright (C) 2011  Crystalnix <vgachkaylo@crystalnix.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,6 +24,7 @@
 #define __CLUTTER_BACKEND_OSX_H__
 
 #include "clutter-backend-private.h"
+#include "clutter-device-manager.h"
 
 @class NSOpenGLPixelFormat, NSOpenGLContext;
 
@@ -42,8 +44,9 @@ struct _ClutterBackendOSX
 {
   ClutterBackend parent;
 
-  NSOpenGLPixelFormat *pixel_format;
-  NSOpenGLContext     *context;
+  NSOpenGLPixelFormat  *pixel_format;
+  NSOpenGLContext      *context;
+  ClutterDeviceManager *device_manager;
 };
 
 struct _ClutterBackendOSXClass
diff --git a/clutter/osx/clutter-device-manager-osx.c b/clutter/osx/clutter-device-manager-osx.c
new file mode 100644 (file)
index 0000000..db383c5
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2009  Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "clutter-backend-osx.h"
+#include "clutter-device-manager-osx.h"
+#include "clutter-device-manager-osx.h"
+#include "clutter-stage-osx.h"
+
+#include "clutter-backend.h"
+#include "clutter-debug.h"
+#include "clutter-device-manager-private.h"
+#include "clutter-private.h"
+
+enum
+{
+  PROP_0
+};
+
+G_DEFINE_TYPE (ClutterDeviceManagerOSX,
+               clutter_device_manager_osx,
+               CLUTTER_TYPE_DEVICE_MANAGER);
+
+static void
+clutter_device_manager_osx_constructed (GObject *gobject)
+{
+  ClutterDeviceManager *manager = CLUTTER_DEVICE_MANAGER (gobject);
+  ClutterDeviceManagerOSX *manager_osx;
+  ClutterInputDevice *device;
+
+  device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE,
+                         "id", 0,
+                         "name", "Core Pointer",
+                         "device-type", CLUTTER_POINTER_DEVICE,
+                         "device-mode", CLUTTER_INPUT_MODE_MASTER,
+                         "has-cursor", TRUE,
+                         "enabled", TRUE,
+                         NULL);
+  CLUTTER_NOTE (BACKEND, "Added core pointer device");
+  _clutter_device_manager_add_device (manager, device);
+
+  device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE,
+                         "id", 1,
+                         "name", "Core Keyboard",
+                         "device-type", CLUTTER_KEYBOARD_DEVICE,
+                         "device-mode", CLUTTER_INPUT_MODE_MASTER,
+                         "enabled", TRUE,
+                         NULL);
+  CLUTTER_NOTE (BACKEND, "Added core keyboard device");
+  _clutter_device_manager_add_device (manager, device);
+
+  manager_osx = CLUTTER_DEVICE_MANAGER_OSX (manager);
+
+  _clutter_input_device_set_associated_device (manager_osx->core_pointer,
+                                               manager_osx->core_keyboard);
+  _clutter_input_device_set_associated_device (manager_osx->core_keyboard,
+                                               manager_osx->core_pointer);
+}
+
+static void
+clutter_device_manager_osx_add_device (ClutterDeviceManager *manager,
+                                       ClutterInputDevice   *device)
+{
+  ClutterDeviceManagerOSX *manager_osx = CLUTTER_DEVICE_MANAGER_OSX (manager);
+  ClutterInputDeviceType device_type;
+  gboolean is_pointer, is_keyboard;
+
+  device_type = clutter_input_device_get_device_type (device);
+  is_pointer  = (device_type == CLUTTER_POINTER_DEVICE)  ? TRUE : FALSE;
+  is_keyboard = (device_type == CLUTTER_KEYBOARD_DEVICE) ? TRUE : FALSE;
+
+  manager_osx->devices = g_slist_prepend (manager_osx->devices, device);
+
+  if (is_pointer && manager_osx->core_pointer == NULL)
+    manager_osx->core_pointer = device;
+
+  if (is_keyboard && manager_osx->core_keyboard == NULL)
+    manager_osx->core_keyboard = device;
+}
+
+static void
+clutter_device_manager_osx_remove_device (ClutterDeviceManager *manager,
+                                          ClutterInputDevice   *device)
+{
+  ClutterDeviceManagerOSX *manager_osx = CLUTTER_DEVICE_MANAGER_OSX (manager);
+
+  manager_osx->devices = g_slist_remove (manager_osx->devices, device);
+}
+
+static const GSList *
+clutter_device_manager_osx_get_devices (ClutterDeviceManager *manager)
+{
+  return CLUTTER_DEVICE_MANAGER_OSX (manager)->devices;
+}
+
+static ClutterInputDevice *
+clutter_device_manager_osx_get_core_device (ClutterDeviceManager *manager,
+                                            ClutterInputDeviceType type)
+{
+  ClutterDeviceManagerOSX *manager_osx;
+
+  manager_osx = CLUTTER_DEVICE_MANAGER_OSX (manager);
+
+  switch (type)
+    {
+    case CLUTTER_POINTER_DEVICE:
+      return manager_osx->core_pointer;
+
+    case CLUTTER_KEYBOARD_DEVICE:
+      return manager_osx->core_keyboard;
+
+    case CLUTTER_EXTENSION_DEVICE:
+    default:
+      return NULL;
+    }
+
+  return NULL;
+}
+
+static ClutterInputDevice *
+clutter_device_manager_osx_get_device (ClutterDeviceManager *manager,
+                                       gint                  id)
+{
+  ClutterDeviceManagerOSX *manager_osx = CLUTTER_DEVICE_MANAGER_OSX (manager);
+  GSList *l;
+
+  for (l = manager_osx->devices; l != NULL; l = l->next)
+    {
+      ClutterInputDevice *device = l->data;
+
+      if (clutter_input_device_get_device_id (device) == id)
+        return device;
+    }
+
+  return NULL;
+}
+
+static void
+clutter_device_manager_osx_class_init (ClutterDeviceManagerOSXClass *klass)
+{
+  ClutterDeviceManagerClass *manager_class;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  gobject_class->constructed = clutter_device_manager_osx_constructed;
+  
+  manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass);
+  manager_class->add_device = clutter_device_manager_osx_add_device;
+  manager_class->remove_device = clutter_device_manager_osx_remove_device;
+  manager_class->get_devices = clutter_device_manager_osx_get_devices;
+  manager_class->get_core_device = clutter_device_manager_osx_get_core_device;
+  manager_class->get_device = clutter_device_manager_osx_get_device;
+}
+
+static void
+clutter_device_manager_osx_init (ClutterDeviceManagerOSX *self)
+{
+}
diff --git a/clutter/osx/clutter-device-manager-osx.h b/clutter/osx/clutter-device-manager-osx.h
new file mode 100644 (file)
index 0000000..300513f
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2010  Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+#ifndef __CLUTTER_DEVICE_MANAGER_OSX_H__
+#define __CLUTTER_DEVICE_MANAGER_OSX_H__
+
+#include <clutter/clutter-device-manager.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_DEVICE_MANAGER_OSX            (clutter_device_manager_osx_get_type ())
+#define CLUTTER_DEVICE_MANAGER_OSX(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER_OSX, ClutterDeviceManagerOSX))
+#define CLUTTER_IS_DEVICE_MANAGER_OSX(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER_OSX))
+#define CLUTTER_DEVICE_MANAGER_OSX_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER_OSX, ClutterDeviceManagerOSXClass))
+#define CLUTTER_IS_DEVICE_MANAGER_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEVICE_MANAGER_OSX))
+#define CLUTTER_DEVICE_MANAGER_OSX_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEVICE_MANAGER_OSX, ClutterDeviceManagerOSXClass))
+
+typedef struct _ClutterDeviceManagerOSX         ClutterDeviceManagerOSX;
+typedef struct _ClutterDeviceManagerOSXClass    ClutterDeviceManagerOSXClass;
+
+struct _ClutterDeviceManagerOSX
+{
+  ClutterDeviceManager parent_instance;
+
+  GSList *devices;
+
+  ClutterInputDevice *core_pointer;
+  ClutterInputDevice *core_keyboard;
+};
+
+struct _ClutterDeviceManagerOSXClass
+{
+  ClutterDeviceManagerClass parent_class;
+};
+
+GType clutter_device_manager_osx_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __CLUTTER_DEVICE_MANAGER_OSX_H__ */
diff --git a/clutter/osx/clutter-event-loop-osx.c b/clutter/osx/clutter-event-loop-osx.c
new file mode 100644 (file)
index 0000000..c8fdd3f
--- /dev/null
@@ -0,0 +1,1051 @@
+/* source code taken from gtk+-2.22.1/gdk/quartz/gdkeventloop-quartz.c  */
+/* Clutter -  An OpenGL based 'interactive canvas' library.
+ * OSX backend - event loop
+ *
+ * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2011  Crystalnix <vgachkaylo@crystalnix.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+#include "config.h"
+
+#include "clutter-osx.h"
+#include "clutter-stage-osx.h"
+
+#import <AppKit/AppKit.h>
+#include <glib.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <clutter/clutter-debug.h>
+
+/* 
+ * This file implementations integration between the GLib main loop and
+ * the native system of the Core Foundation run loop and Cocoa event
+ * handling. There are basically two different cases that we need to
+ * handle: either the GLib main loop is in control (the application
+ * has called gtk_main(), or is otherwise iterating the main loop), or
+ * CFRunLoop is in control (we are in a modal operation such as window
+ * resizing or drag-and-drop.)
+ *
+ * When the GLib main loop is in control we integrate in native event
+ * handling in two ways: first we add a GSource that handles checking
+ * whether there are native events available, translating native events
+ * to clutter events, and dispatching GDK events. Second we replace the
+ * "poll function" of the GLib main loop with our own version that knows
+ * how to wait for both the file descriptors and timeouts that GLib is
+ * interested in and also for incoming native events.
+ *
+ * When CFRunLoop is in control, we integrate in GLib main loop handling
+ * by adding a "run loop observer" that gives us notification at various
+ * points in the run loop cycle. We map these points onto the corresponding
+ * stages of the GLib main loop (prepare, check, dispatch), and make the
+ * appropriate calls into GLib.
+ *
+ * Both cases share a single problem: the OS X API's don't allow us to
+ * wait simultaneously for file descriptors and for events. So when we
+ * need to do a blocking wait that includes file descriptor activity, we
+ * push the actual work of calling select() to a helper thread (the
+ * "select thread") and wait for native events in the main thread.
+ *
+ * The main known limitation of this code is that if a callback is triggered
+ * via the OS X run loop while we are "polling" (in either case described
+ * above), iteration of the GLib main loop is not possible from within
+ * that callback. If the programmer tries to do so explicitly, then they
+ * will get a warning from GLib "main loop already active in another thread".
+ */
+
+/******* State for run loop iteration *******/
+
+/* Count of number of times we've gotten an "Entry" notification for
+ * our run loop observer.
+ */
+static int current_loop_level = 0;
+
+/* Run loop level at which we acquired ownership of the GLib main
+ * loop. See note in run_loop_entry(). -1 means that we don't have
+ * ownership
+ */ 
+static int acquired_loop_level = -1;
+
+/* Between run_loop_before_waiting() and run_loop_after_waiting();
+ * whether we we need to call select_thread_collect_poll()
+ */
+static gboolean run_loop_polling_async = FALSE;
+
+/* Between run_loop_before_waiting() and run_loop_after_waiting();
+ * max_prioritiy to pass to g_main_loop_check()
+ */
+static gint run_loop_max_priority;
+
+/* Timer that we've added to wake up the run loop when a GLib timeout
+ */
+static CFRunLoopTimerRef run_loop_timer = NULL;
+
+/* These are the file descriptors that are we are polling out of
+ * the run loop. (We keep the array around and reuse it to avoid
+ * constant allocations.)
+ */
+#define RUN_LOOP_POLLFDS_INITIAL_SIZE 16
+static GPollFD *run_loop_pollfds;
+static guint run_loop_pollfds_size; /* Allocated size of the array */
+static guint run_loop_n_pollfds;    /* Number of file descriptors in the array */
+
+/******* Other global variables *******/
+
+/* Since we count on replacing the GLib main loop poll function as our
+ * method of integrating Cocoa event handling into the GLib main loop
+ * we need to make sure that the poll function is always called even
+ * when there are no file descriptors that need to be polled. To do
+ * this, we add a dummy GPollFD to our event source with a file
+ * descriptor of '-1'. Then any time that GLib is polling the event
+ * source, it will call our poll function.
+ */
+static GPollFD event_poll_fd;
+
+/* Current NSEvents that we've gotten from Cocoa but haven't yet converted
+ * to GdkEvents. We wait until our dispatch() function to do the conversion
+ * since the conversion can conceivably cause signals to be emmitted
+ * or other things that shouldn't happen inside a poll function.
+ */
+static GQueue *current_events;
+
+/* The default poll function for GLib; we replace this with our own
+ * Cocoa-aware version and then call the old version to do actual
+ * file descriptor polling. There's no actual need to chain to the
+ * old one; we could reimplement the same functionality from scratch,
+ * but since the default implementation does the right thing, why
+ * bother.
+ */
+static GPollFunc old_poll_func = NULL;
+
+/* Reference to the run loop of the main thread. (There is a unique
+ * CFRunLoop per thread.)
+ */
+static CFRunLoopRef main_thread_run_loop;
+
+/* Normally the Cocoa main loop maintains an NSAutoReleasePool and frees
+ * it on every iteration. Since we are replacing the main loop we have
+ * to provide this functionality ourself. We free and replace the
+ * auto-release pool in our sources prepare() function.
+ */
+static NSAutoreleasePool *autorelease_pool;
+
+/* Flag when we've called nextEventMatchingMask ourself; this triggers
+ * a run loop iteration, so we need to detect that and avoid triggering
+ * our "run the GLib main looop while the run loop is active machinery.
+ */
+static gboolean getting_events;
+
+/************************************************************
+ *********              Select Thread               *********
+ ************************************************************/
+
+/* The states in our state machine, see comments in select_thread_func()
+ * for descriptiions of each state
+ */
+typedef enum {
+  BEFORE_START,
+  WAITING,
+  POLLING_QUEUED,
+  POLLING_RESTART,
+  POLLING_DESCRIPTORS,
+} SelectThreadState;
+
+static const char *const state_names[]  = {
+  "BEFORE_START",
+  "WAITING",
+  "POLLING_QUEUED",
+  "POLLING_RESTART",
+  "POLLING_DESCRIPTORS"
+};
+
+static SelectThreadState select_thread_state = BEFORE_START;
+
+static pthread_t select_thread;
+static pthread_mutex_t select_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t select_thread_cond = PTHREAD_COND_INITIALIZER;
+
+#define SELECT_THREAD_LOCK() pthread_mutex_lock (&select_thread_mutex)
+#define SELECT_THREAD_UNLOCK() pthread_mutex_unlock (&select_thread_mutex)
+#define SELECT_THREAD_SIGNAL() pthread_cond_signal (&select_thread_cond)
+#define SELECT_THREAD_WAIT() pthread_cond_wait (&select_thread_cond, &select_thread_mutex)
+
+/* These are the file descriptors that the select thread is currently
+ * polling.
+ */
+static GPollFD *current_pollfds;
+static guint current_n_pollfds;
+
+/* These are the file descriptors that the select thread should pick
+ * up and start polling when it has a chance.
+ */
+static GPollFD *next_pollfds;
+static guint next_n_pollfds;
+
+/* Pipe used to wake up the select thread */
+static gint select_thread_wakeup_pipe[2];
+
+/* Run loop source used to wake up the main thread */
+static CFRunLoopSourceRef select_main_thread_source;
+
+/* Events */
+typedef enum {
+  CLUTTER_OSX_EVENT_SUBTYPE_EVENTLOOP
+} ClutterOSXEventSubType;
+
+static void
+select_thread_set_state (SelectThreadState new_state)
+{
+  gboolean old_state;
+
+  if (select_thread_state == new_state)
+    return;
+
+  CLUTTER_NOTE (EVENTLOOP, "EventLoop: Select thread state: %s => %s\n", state_names[select_thread_state], state_names[new_state]);
+
+  old_state = select_thread_state;
+  select_thread_state = new_state;
+  if (old_state == WAITING && new_state != WAITING)
+    SELECT_THREAD_SIGNAL ();
+}
+
+static void
+signal_main_thread (void)
+{
+  CLUTTER_NOTE (EVENTLOOP, "EventLoop: Waking up main thread\n");
+
+  /* If we are in nextEventMatchingMask, then we need to make sure an
+   * event gets queued, otherwise it's enough to simply wake up the
+   * main thread run loop
+   */
+  if (!run_loop_polling_async)
+    CFRunLoopSourceSignal (select_main_thread_source);
+  
+  if (CFRunLoopIsWaiting (main_thread_run_loop))
+    CFRunLoopWakeUp (main_thread_run_loop);
+}
+
+static void *
+select_thread_func (void *arg)
+{
+  char c;
+  
+  SELECT_THREAD_LOCK ();
+
+  while (TRUE)
+    {
+      switch (select_thread_state)
+       {
+       case BEFORE_START:
+         /* The select thread has not been started yet
+          */
+         g_assert_not_reached ();
+         
+       case WAITING:
+         /* Waiting for a set of file descriptors to be submitted by the main thread
+          *
+          *  => POLLING_QUEUED: main thread thread submits a set of file descriptors
+          */ 
+         SELECT_THREAD_WAIT ();
+         break;
+         
+       case POLLING_QUEUED:
+         /* Waiting for a set of file descriptors to be submitted by the main thread
+          *
+          *  => POLLING_DESCRIPTORS: select thread picks up the file descriptors to begin polling
+          */ 
+         if (current_pollfds)
+           g_free (current_pollfds);
+         
+         current_pollfds = next_pollfds;
+         current_n_pollfds = next_n_pollfds;
+
+         next_pollfds = NULL;
+         next_n_pollfds = 0;
+
+         select_thread_set_state (POLLING_DESCRIPTORS);
+         break;
+         
+       case POLLING_RESTART:
+         /* Select thread is currently polling a set of file descriptors, main thread has
+          * began a new iteration with the same set of file descriptors. We don't want to
+          * wake the select thread up and wait for it to restart immediately, but to avoid
+          * a race (described below in select_thread_start_polling()) we need to recheck after
+          * polling completes.
+          *
+          * => POLLING_DESCRIPTORS: select completes, main thread rechecks by polling again
+          * => POLLING_QUEUED: main thread submits a new set of file descriptors to be polled
+          */
+         select_thread_set_state (POLLING_DESCRIPTORS);
+         break;
+
+       case POLLING_DESCRIPTORS:
+         /* In the process of polling the file descriptors
+          *
+          *  => WAITING: polling completes when a file descriptor becomes active
+          *  => POLLING_QUEUED: main thread submits a new set of file descriptors to be polled
+          *  => POLLING_RESTART: main thread begins a new iteration with the same set file descriptors
+          */ 
+         SELECT_THREAD_UNLOCK ();
+         old_poll_func (current_pollfds, current_n_pollfds, -1);
+         SELECT_THREAD_LOCK ();
+
+         read (select_thread_wakeup_pipe[0], &c, 1);
+
+         if (select_thread_state == POLLING_DESCRIPTORS)
+           {
+             signal_main_thread ();
+             select_thread_set_state (WAITING);
+           }
+         break;
+       }
+    }
+}
+
+static void 
+got_fd_activity (void *info)
+{
+  NSEvent *event;
+
+  /* Post a message so we'll break out of the message loop */
+  event = [NSEvent otherEventWithType: NSApplicationDefined
+                            location: NSZeroPoint
+                       modifierFlags: 0
+                           timestamp: 0
+                        windowNumber: 0
+                             context: nil
+                        subtype: CLUTTER_OSX_EVENT_SUBTYPE_EVENTLOOP
+                               data1: 0 
+                               data2: 0];
+
+  [NSApp postEvent:event atStart:YES];
+}
+
+static void
+select_thread_start (void)
+{
+  g_return_if_fail (select_thread_state == BEFORE_START);
+  
+  pipe (select_thread_wakeup_pipe);
+  fcntl (select_thread_wakeup_pipe[0], F_SETFL, O_NONBLOCK);
+
+  CFRunLoopSourceContext source_context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, got_fd_activity };
+  select_main_thread_source = CFRunLoopSourceCreate (NULL, 0, &source_context);
+  
+  CFRunLoopAddSource (main_thread_run_loop, select_main_thread_source, kCFRunLoopCommonModes);
+
+  select_thread_state = WAITING;
+  
+  while (TRUE)
+    {
+      if (pthread_create (&select_thread, NULL, select_thread_func, NULL) == 0)
+         break;
+
+      g_warning ("Failed to create select thread, sleeping and trying again");
+      sleep (1);
+    }
+}
+
+#ifdef G_ENABLE_DEBUG
+static void
+dump_poll_result (GPollFD *ufds,
+                 guint    nfds)
+{
+  gint i;
+
+  for (i = 0; i < nfds; i++)
+    {
+      if (ufds[i].fd >= 0 && ufds[i].revents)
+       {
+         g_print (" %d:", ufds[i].fd);
+         if (ufds[i].revents & G_IO_IN)
+           g_print (" in");
+         if (ufds[i].revents & G_IO_OUT)
+           g_print (" out");
+         if (ufds[i].revents & G_IO_PRI)
+           g_print (" pri");
+         g_print ("\n");
+       }
+    }
+}
+#endif
+
+gboolean
+pollfds_equal (GPollFD *old_pollfds,
+              guint    old_n_pollfds,
+              GPollFD *new_pollfds,
+              guint    new_n_pollfds)
+{
+  gint i;
+  
+  if (old_n_pollfds != new_n_pollfds)
+    return FALSE;
+
+  for (i = 0; i < old_n_pollfds; i++)
+    {
+      if (old_pollfds[i].fd != new_pollfds[i].fd ||
+         old_pollfds[i].events != new_pollfds[i].events)
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
+/* Begins a polling operation with the specified GPollFD array; the 
+ * timeout is used only to tell if the polling operation is blocking
+ * or non-blocking.
+ *
+ * Return value:
+ *  -1: No file descriptors ready, began asynchronous poll
+ *   0: No file descriptors ready, asynchronous poll not needed
+ * > 0: Number of file descriptors ready
+ */
+static gint
+select_thread_start_poll (GPollFD *ufds,
+                         guint    nfds,                          gint     timeout)
+{
+  gint n_ready;
+  gboolean have_new_pollfds = FALSE;
+  gint poll_fd_index = -1;
+  gint i;
+
+  for (i = 0; i < nfds; i++)
+    if (ufds[i].fd == -1)
+      {
+       poll_fd_index = i;
+       break;
+      }
+  
+  if (nfds == 0 ||
+      (nfds == 1 && poll_fd_index >= 0))
+    {
+      CLUTTER_NOTE (EVENTLOOP, "EventLoop: Nothing to poll\n");
+      return 0;
+    }
+
+  /* If we went immediately to an async poll, then we might decide to
+   * dispatch idle functions when higher priority file descriptor sources
+   * are ready to be dispatched. So we always need to first check
+   * check synchronously with a timeout of zero, and only when no
+   * sources are immediately ready, go to the asynchronous poll.
+   *
+   * Of course, if the timeout passed in is 0, then the synchronous
+   * check is sufficient and we never need to do the asynchronous poll.
+   */
+  n_ready = old_poll_func (ufds, nfds, 0);
+  if (n_ready > 0 || timeout == 0)
+    {
+#ifdef G_ENABLE_DEBUG
+      if (CLUTTER_HAS_DEBUG(EVENTLOOP) && n_ready > 0)
+       {
+         g_print ("EventLoop: Found ready file descriptors before waiting\n");
+         dump_poll_result (ufds, nfds);
+       }
+#endif
+  
+      return n_ready;
+    }
+  
+  SELECT_THREAD_LOCK ();
+
+  if (select_thread_state == BEFORE_START)
+    {
+      select_thread_start ();
+    }
+  
+  if (select_thread_state == POLLING_QUEUED)
+    {
+      /* If the select thread hasn't picked up the set of file descriptors yet
+       * then we can simply replace an old stale set with a new set.
+       */
+      if (!pollfds_equal (ufds, nfds, next_pollfds, next_n_pollfds - 1))
+       {
+         g_free (next_pollfds);
+         next_pollfds = NULL;
+         next_n_pollfds = 0;
+         
+         have_new_pollfds = TRUE;
+       }
+    }
+  else if (select_thread_state == POLLING_RESTART || select_thread_state == POLLING_DESCRIPTORS)
+    {
+      /* If we are already in the process of polling the right set of file descriptors,
+       * there's no need for us to immediately force the select thread to stop polling
+       * and then restart again. And avoiding doing so increases the efficiency considerably
+       * in the common case where we have a set of basically inactive file descriptors that
+       * stay unchanged present as we process many events.
+       *
+       * However, we have to be careful that we don't hit the following race condition
+       *  Select Thread              Main Thread
+       *  -----------------          ---------------
+       *  Polling Completes
+       *                             Reads data or otherwise changes file descriptor state
+       *                             Checks if polling is current
+       *                             Does nothing (*)
+       *                             Releases lock
+       *  Acquires lock
+       *  Marks polling as complete
+       *  Wakes main thread
+       *                             Receives old stale file descriptor state
+       * 
+       * To avoid this, when the new set of poll descriptors is the same as the current
+       * one, we transition to the POLLING_RESTART stage at the point marked (*). When
+       * the select thread wakes up from the poll because a file descriptor is active, if
+       * the state is POLLING_RESTART it immediately begins polling same the file descriptor
+       * set again. This normally will just return the same set of active file descriptors
+       * as the first time, but in sequence described above will properly update the
+       * file descriptor state.
+       *
+       * Special case: this RESTART logic is not needed if the only FD is the internal GLib
+       * "wakeup pipe" that is presented when threads are initialized.
+       *
+       * P.S.: The harm in the above sequence is mostly that sources can be signalled
+       *   as ready when they are no longer ready. This may prompt a blocking read
+       *   from a file descriptor that hangs.
+       */
+      if (!pollfds_equal (ufds, nfds, current_pollfds, current_n_pollfds - 1))
+       have_new_pollfds = TRUE;
+      else
+       {
+         if (!((nfds == 1 && poll_fd_index < 0 && g_thread_supported ()) ||
+               (nfds == 2 && poll_fd_index >= 0 && g_thread_supported ())))
+           select_thread_set_state (POLLING_RESTART);
+       }
+    }
+  else
+    have_new_pollfds = TRUE;
+
+  if (have_new_pollfds)
+    {
+      CLUTTER_NOTE (EVENTLOOP, "EventLoop: Submitting a new set of file descriptor to the select thread\n");
+      
+      g_assert (next_pollfds == NULL);
+      
+      next_n_pollfds = nfds + 1;
+      next_pollfds = g_new (GPollFD, nfds + 1);
+      memcpy (next_pollfds, ufds, nfds * sizeof (GPollFD));
+  
+      next_pollfds[nfds].fd = select_thread_wakeup_pipe[0];
+      next_pollfds[nfds].events = G_IO_IN;
+  
+      if (select_thread_state != POLLING_QUEUED && select_thread_state != WAITING)
+       {
+         if (select_thread_wakeup_pipe[1])
+           {
+             char c = 'A';
+             write (select_thread_wakeup_pipe[1], &c, 1);
+           }
+       }
+      
+      select_thread_set_state (POLLING_QUEUED);
+    }
+  
+  SELECT_THREAD_UNLOCK ();
+
+  return -1;
+}
+
+/* End an asynchronous polling operation started with
+ * select_thread_collect_poll(). This must be called if and only if
+ * select_thread_start_poll() return -1. The GPollFD array passed
+ * in must be identical to the one passed to select_thread_start_poll().
+ *
+ * The results of the poll are written into the GPollFD array passed in.
+ *
+ * Return Value: number of file descriptors ready
+ */
+static int
+select_thread_collect_poll (GPollFD *ufds, guint nfds)
+{
+  gint i;
+  gint n_ready = 0;
+  
+  SELECT_THREAD_LOCK ();
+
+  if (select_thread_state == WAITING) /* The poll completed */
+    {
+      for (i = 0; i < nfds; i++)
+       {
+         if (ufds[i].fd == -1)
+           continue;
+         
+         g_assert (ufds[i].fd == current_pollfds[i].fd);
+         g_assert (ufds[i].events == current_pollfds[i].events);
+
+         if (current_pollfds[i].revents)
+           {
+             ufds[i].revents = current_pollfds[i].revents;
+             n_ready++;
+           }
+       }
+      
+#ifdef G_ENABLE_DEBUG
+      if (_gdk_debug_flags & GDK_DEBUG_EVENTLOOP)
+       {
+         g_print ("EventLoop: Found ready file descriptors after waiting\n");
+         dump_poll_result (ufds, nfds);
+       }
+#endif
+    }
+
+  SELECT_THREAD_UNLOCK ();
+
+  return n_ready;
+}
+
+/************************************************************
+ *********             Main Loop Source             *********
+ ************************************************************/
+
+gboolean
+_clutter_osx_event_loop_check_pending (void)
+{
+  return current_events && current_events->head;
+}
+
+NSEvent*
+_clutter_osx_event_loop_get_pending (void)
+{
+  NSEvent *event = NULL;
+
+  if (current_events)
+    event = g_queue_pop_tail (current_events);
+
+  return event;
+}
+
+void
+_clutter_osx_event_loop_release_event (NSEvent *event)
+{
+  [event release];
+}
+
+static gboolean
+clutter_event_prepare (GSource *source,
+                  gint    *timeout)
+{
+  gboolean retval;
+
+  clutter_threads_enter ();
+  
+  *timeout = -1;
+
+  retval = (clutter_events_pending () || _clutter_osx_event_loop_check_pending ());
+
+  clutter_threads_leave ();
+
+  return retval;
+}
+
+static gboolean
+clutter_event_check (GSource *source)
+{
+  gboolean retval;
+
+  clutter_threads_enter ();
+
+  /* XXX: This check isn't right it won't handle a recursive GLib main
+   * loop run within an outer CFRunLoop run. Such loops will pile up
+   * memory. Fixing this requires setting a flag *only* when we call
+   * g_main_context_check() from within the run loop iteraton code,
+   * and also maintaining our own stack of run loops... allocating and
+   * releasing NSAutoReleasePools not properly nested with CFRunLoop
+   * runs seems to cause problems.
+   */
+  if (current_loop_level == 0)
+    {
+      if (autorelease_pool)
+       [autorelease_pool release];
+      autorelease_pool = [[NSAutoreleasePool alloc] init];
+    }
+  
+  retval = (clutter_events_pending () || _clutter_osx_event_loop_check_pending ());
+
+  clutter_threads_leave ();
+
+  return retval;
+}
+
+static gboolean
+clutter_event_dispatch (GSource     *source,
+                   GSourceFunc  callback,
+                   gpointer     user_data)
+{
+  NSEvent *nsevent;
+  ClutterEvent *event;
+
+  clutter_threads_enter ();
+
+  nsevent = _clutter_osx_event_loop_get_pending ();
+  if (nsevent) {
+    clutter_threads_leave ();
+    [NSApp sendEvent:nsevent];
+    clutter_threads_enter ();
+    
+    _clutter_osx_event_loop_release_event (nsevent);
+  }
+  
+  event = clutter_event_get ();
+
+  if (event)
+    {
+      /* forward the event into clutter for emission etc. */
+      clutter_do_event (event);
+      clutter_event_free (event);
+    }
+
+  clutter_threads_leave ();
+
+  return TRUE;
+}
+
+static GSourceFuncs event_funcs = {
+  clutter_event_prepare,
+  clutter_event_check,
+  clutter_event_dispatch,
+  NULL
+};
+
+/************************************************************
+ *********             Our Poll Function            *********
+ ************************************************************/
+
+static gint
+poll_func (GPollFD *ufds,
+          guint    nfds,
+          gint     timeout_)
+{
+  NSEvent *event;
+  NSDate *limit_date;
+  gint n_ready;
+
+  n_ready = select_thread_start_poll (ufds, nfds, timeout_);
+  if (n_ready > 0)
+    timeout_ = 0;
+
+  if (timeout_ == -1)
+    limit_date = [NSDate distantFuture];
+  else if (timeout_ == 0)
+    limit_date = [NSDate distantPast];
+  else
+    limit_date = [NSDate dateWithTimeIntervalSinceNow:timeout_/1000.0];
+
+  getting_events = TRUE;
+  event = [NSApp nextEventMatchingMask: NSAnyEventMask
+                            untilDate: limit_date
+                               inMode: NSDefaultRunLoopMode
+                               dequeue: YES];
+  getting_events = FALSE;
+
+  if (n_ready < 0)
+    n_ready = select_thread_collect_poll (ufds, nfds);
+      
+  if (event &&
+      [event type] == NSApplicationDefined &&
+      [event subtype] == CLUTTER_OSX_EVENT_SUBTYPE_EVENTLOOP)
+    {
+      /* Just used to wake us up; if an event and a FD arrived at the same
+       * time; could have come from a previous iteration in some cases,
+       * but the spurious wake up is harmless if a little inefficient.
+       */
+      event = NULL;
+    }
+
+  if (event) 
+    {
+      if (!current_events)
+        current_events = g_queue_new ();
+      g_queue_push_head (current_events, [event retain]);
+    }
+
+  return n_ready;
+}
+
+/************************************************************
+ *********  Running the main loop out of CFRunLoop  *********
+ ************************************************************/
+
+/* Wrapper around g_main_context_query() that handles reallocating
+ * run_loop_pollfds up to the proper size
+ */
+static gint
+query_main_context (GMainContext *context,
+                   int           max_priority,
+                   int          *timeout)
+{
+  gint nfds;
+  
+  if (!run_loop_pollfds)
+    {
+      run_loop_pollfds_size = RUN_LOOP_POLLFDS_INITIAL_SIZE;
+      run_loop_pollfds = g_new (GPollFD, run_loop_pollfds_size);
+    }
+
+  while ((nfds = g_main_context_query (context, max_priority, timeout,
+                                      run_loop_pollfds, 
+                                      run_loop_pollfds_size)) > run_loop_pollfds_size)
+    {
+      g_free (run_loop_pollfds);
+      run_loop_pollfds_size = nfds;
+      run_loop_pollfds = g_new (GPollFD, nfds);
+    }
+
+  return nfds;
+}
+
+static void
+run_loop_entry (void)
+{
+  current_loop_level++;
+
+  if (acquired_loop_level == -1)
+    {
+      if (g_main_context_acquire (NULL))
+       {
+         CLUTTER_NOTE (EVENTLOOP, "EventLoop: Beginning tracking run loop activity\n");
+         acquired_loop_level = current_loop_level;
+       }
+      else
+       {
+         /* If we fail to acquire the main context, that means someone is iterating
+          * the main context in a different thread; we simply wait until this loop
+          * exits and then try again at next entry. In general, iterating the loop
+          * from a different thread is rare: it is only possible when GDK threading
+          * is initialized and is not frequently used even then. So, we hope that
+          * having GLib main loop iteration blocked in the combination of that and
+          * a native modal operation is a minimal problem. We could imagine using a
+          * thread that does g_main_context_wait() and then wakes us back up, but
+          * the gain doesn't seem worth the complexity.
+          */
+         CLUTTER_NOTE (EVENTLOOP, "EventLoop: Can't acquire main loop; skipping tracking run loop activity\n");
+       }
+    }
+}
+
+static void
+run_loop_before_timers (void)
+{
+}
+
+static void
+run_loop_before_sources (void)
+{
+  GMainContext *context = g_main_context_default ();
+  gint max_priority;
+  gint nfds;
+
+  /* Before we let the CFRunLoop process sources, we want to check if there
+   * are any pending GLib main loop sources more urgent than
+   * G_PRIORITY_DEFAULT that need to be dispatched. (We consider all activity
+   * from the CFRunLoop to have a priority of G_PRIORITY_DEFAULT.) If no
+   * sources are processed by the CFRunLoop, then processing will continue
+   * on to the BeforeWaiting stage where we check for lower priority sources.
+   */
+  
+  g_main_context_prepare (context, &max_priority); 
+  max_priority = MIN (max_priority, G_PRIORITY_DEFAULT);
+
+  /* We ignore the timeout that query_main_context () returns since we'll
+   * always query again before waiting.
+   */
+  nfds = query_main_context (context, max_priority, NULL);
+
+  if (nfds)
+    old_poll_func (run_loop_pollfds, nfds, 0);
+  
+  if (g_main_context_check (context, max_priority, run_loop_pollfds, nfds))
+    {
+      CLUTTER_NOTE (EVENTLOOP, "EventLoop: Dispatching high priority sources\n");
+      g_main_context_dispatch (context);
+    }
+}
+
+static void
+dummy_timer_callback (CFRunLoopTimerRef  timer,
+                     void              *info)
+{
+  /* Nothing; won't normally even be called */
+}
+
+static void
+run_loop_before_waiting (void)
+{
+  GMainContext *context = g_main_context_default ();
+  gint timeout;
+  gint n_ready;
+
+  /* At this point, the CFRunLoop is ready to wait. We start a GMain loop
+   * iteration by calling the check() and query() stages. We start a
+   * poll, and if it doesn't complete immediately we let the run loop
+   * go ahead and sleep. Before doing that, if there was a timeout from
+   * GLib, we set up a CFRunLoopTimer to wake us up.
+   */
+  
+  g_main_context_prepare (context, &run_loop_max_priority); 
+  
+  run_loop_n_pollfds = query_main_context (context, run_loop_max_priority, &timeout);
+
+  n_ready = select_thread_start_poll (run_loop_pollfds, run_loop_n_pollfds, timeout);
+
+  if (n_ready > 0 || timeout == 0)
+    {
+      /* We have stuff to do, no sleeping allowed! */
+      CFRunLoopWakeUp (main_thread_run_loop);
+    }
+  else if (timeout > 0)
+    {
+      /* We need to get the run loop to break out of it's wait when our timeout
+       * expires. We do this by adding a dummy timer that we'll remove immediately
+       * after the wait wakes up.
+       */
+      CLUTTER_NOTE (EVENTLOOP, "EventLoop: Adding timer to wake us up in %d milliseconds\n", timeout);
+      
+      run_loop_timer = CFRunLoopTimerCreate (NULL, /* allocator */
+                                            CFAbsoluteTimeGetCurrent () + timeout / 1000.,
+                                            0, /* interval (0=does not repeat) */
+                                            0, /* flags */
+                                            0, /* order (priority) */
+                                            dummy_timer_callback,
+                                            NULL);
+
+      CFRunLoopAddTimer (main_thread_run_loop, run_loop_timer, kCFRunLoopCommonModes);
+    }
+  
+  run_loop_polling_async = n_ready < 0;
+}
+
+static void
+run_loop_after_waiting (void)
+{
+  GMainContext *context = g_main_context_default ();
+
+  /* After sleeping, we finish of the GMain loop iteratin started in before_waiting()
+   * by doing the check() and dispatch() stages.
+   */
+
+  if (run_loop_timer)
+    {
+      CFRunLoopRemoveTimer (main_thread_run_loop, run_loop_timer, kCFRunLoopCommonModes);
+      CFRelease (run_loop_timer);
+      run_loop_timer = NULL;
+    }
+  
+  if (run_loop_polling_async)
+    {
+      select_thread_collect_poll (run_loop_pollfds, run_loop_n_pollfds);
+      run_loop_polling_async = FALSE;
+    }
+  
+  if (g_main_context_check (context, run_loop_max_priority, run_loop_pollfds, run_loop_n_pollfds))
+    {
+      CLUTTER_NOTE (EVENTLOOP, "EventLoop: Dispatching after waiting\n");
+      g_main_context_dispatch (context);
+    }
+}
+
+static void
+run_loop_exit (void)
+{
+  g_return_if_fail (current_loop_level > 0);
+
+  if (current_loop_level == acquired_loop_level)
+    {
+      g_main_context_release (NULL);
+      acquired_loop_level = -1;
+      CLUTTER_NOTE (EVENTLOOP, "EventLoop: Ended tracking run loop activity\n");
+    }
+  
+  current_loop_level--;
+}
+
+static void
+run_loop_observer_callback (CFRunLoopObserverRef observer,
+                           CFRunLoopActivity    activity,
+                           void                *info)
+{
+  if (getting_events) /* Activity we triggered */
+    return;
+  
+  switch (activity)
+    {
+    case kCFRunLoopEntry:
+      run_loop_entry ();
+      break;
+    case kCFRunLoopBeforeTimers:
+      run_loop_before_timers ();
+      break;
+    case kCFRunLoopBeforeSources:
+      run_loop_before_sources ();
+      break;
+    case kCFRunLoopBeforeWaiting:
+      run_loop_before_waiting ();
+      break;
+    case kCFRunLoopAfterWaiting:
+      run_loop_after_waiting ();
+      break;
+    case kCFRunLoopExit:
+      run_loop_exit ();
+      break;
+    default:
+      break;
+    }
+}
+
+/************************************************************/
+
+void
+_clutter_osx_event_loop_init (void)
+{
+  GSource *source;
+  CFRunLoopObserverRef observer;
+
+  g_assert (old_poll_func == NULL);
+
+  /* Hook into the GLib main loop */
+
+  event_poll_fd.events = G_IO_IN;
+  event_poll_fd.fd = -1;
+
+  source = g_source_new (&event_funcs, sizeof (GSource));
+  g_source_set_name (source, "Clutter OS X event source"); 
+  g_source_add_poll (source, &event_poll_fd);
+  g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
+  g_source_set_can_recurse (source, TRUE);
+  g_source_attach (source, NULL);
+
+  old_poll_func = g_main_context_get_poll_func (NULL);
+  g_main_context_set_poll_func (NULL, poll_func);
+  
+  /* Hook into the the CFRunLoop for the main thread */
+
+  main_thread_run_loop = CFRunLoopGetCurrent ();
+
+  observer = CFRunLoopObserverCreate (NULL, /* default allocator */
+                                     kCFRunLoopAllActivities,
+                                     true, /* repeats: not one-shot */
+                                     0, /* order (priority) */
+                                     run_loop_observer_callback,
+                                     NULL);
+                                    
+  CFRunLoopAddObserver (main_thread_run_loop, observer, kCFRunLoopCommonModes);
+  
+  /* Initialize our autorelease pool */
+
+  autorelease_pool = [[NSAutoreleasePool alloc] init];
+}
similarity index 61%
rename from clutter/glx/clutter-event-glx.h
rename to clutter/osx/clutter-event-loop-osx.h
index 79fa272..1f7dd56 100644 (file)
@@ -1,6 +1,8 @@
-/* Clutter.
- * An OpenGL based 'interactive canvas' library.
- * Copyright (C) 2009 Intel Corporation.
+/* Clutter -  An OpenGL based 'interactive canvas' library.
+ * OSX backend - event loop
+ *
+ * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2011  Crystalnix  <vgachkaylo@crystalnix.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  *
  *
  */
-
-#ifndef __CLUTTER_EVENT_GLX_H__
-#define __CLUTTER_EVENT_GLX_H__
-
-#include <glib.h>
-#include <clutter/clutter-event.h>
-#include <clutter/clutter-backend.h>
-#include <X11/Xlib.h>
+#ifndef __CLUTTER_EVENT_LOOP_OSX_H__
+#define __CLUTTER_EVENT_LOOP_OSX_H__
 
 G_BEGIN_DECLS
 
-gboolean
-_clutter_backend_glx_handle_event (ClutterBackendX11 *backend,
-                                  XEvent            *xevent);
+/* Initialization */
+void _clutter_osx_event_loop_init            (void);
 
 G_END_DECLS
 
-#endif /* __CLUTTER_EVENT_GLX_H__ */
-
+#endif
index e940fc4..a06fa3b 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2007-2008  Tommi Komulainen <tommi.komulainen@iki.fi>
  * Copyright (C) 2007  OpenedHand Ltd.
+ * Copyright (C) 2011  Crystalnix  <vgachkaylo@crystalnix.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include "config.h"
 
 #include "clutter-osx.h"
+
+#include "clutter-device-manager-osx.h"
 #include "clutter-stage-osx.h"
 
 #import <AppKit/AppKit.h>
 
 #include <glib.h>
 #include <clutter/clutter-debug.h>
-#include <clutter/clutter-private.h>
+#include <clutter/clutter-device-manager.h>
 #include <clutter/clutter-keysyms.h>
+#include <clutter/clutter-private.h>
+#include <clutter/clutter-stage-private.h>
 
-/* Overriding the poll function because the events are not delivered over file
- * descriptors and setting up a GSource would just introduce polling.
- */
+#include "clutter-event-loop-osx.h"
 
-static GPollFunc old_poll_func = NULL;
+#define WHEEL_DELTA 1
 
 /*************************************************************************/
 @interface NSEvent (Clutter)
@@ -206,9 +209,75 @@ static GPollFunc old_poll_func = NULL;
 @end
 
 /*************************************************************************/
+
+static void
+take_and_queue_event (ClutterEvent *event)
+{
+  _clutter_event_push (event, FALSE);
+}
+
+static void
+process_scroll_event (ClutterEvent *event,
+                      gboolean isVertical)
+{
+  ClutterStageWindow   *impl;
+  ClutterStageOSX *stage_osx;
+  
+  impl        = _clutter_stage_get_window (event->any.stage);
+  stage_osx   = CLUTTER_STAGE_OSX (impl);
+  
+  gfloat *scroll_pos = isVertical ? &(stage_osx->scroll_pos_y) : &(stage_osx->scroll_pos_x);
+  while (abs (*scroll_pos) >= WHEEL_DELTA) 
+    {
+      ClutterEvent *event_gen = clutter_event_new (CLUTTER_SCROLL);
+
+      event_gen->scroll.time = event->any.time;
+      event_gen->scroll.modifier_state = event->scroll.modifier_state;
+      event_gen->any.stage = event->any.stage;
+
+      event_gen->scroll.x = event->scroll.x;
+      event_gen->scroll.y = event->scroll.y;
+
+      if (*scroll_pos > 0)
+        {
+          event_gen->scroll.direction = isVertical ? CLUTTER_SCROLL_UP : CLUTTER_SCROLL_RIGHT;
+          *scroll_pos -= WHEEL_DELTA;
+        }
+      else
+        {
+          event_gen->scroll.direction = isVertical ? CLUTTER_SCROLL_DOWN : CLUTTER_SCROLL_LEFT;
+          *scroll_pos += WHEEL_DELTA;
+        }
+
+      clutter_event_set_device (event_gen, clutter_event_get_device (event));
+
+      take_and_queue_event (event_gen);
+      
+      CLUTTER_NOTE (EVENT, "scroll %s at %f,%f",
+                    (event_gen->scroll.direction == CLUTTER_SCROLL_UP) ? "UP" :
+                    ( 
+                    (event_gen->scroll.direction == CLUTTER_SCROLL_DOWN) ? "DOWN" :
+                    (
+                    (event_gen->scroll.direction == CLUTTER_SCROLL_RIGHT) ? "RIGHT" : "LEFT")),
+                    event->scroll.x, event->scroll.y);
+    } 
+}
+
 static gboolean
-clutter_event_osx_translate (NSEvent *nsevent, ClutterEvent *event)
+clutter_event_osx_translate (NSEvent *nsevent,
+                             ClutterEvent *event)
 {
+  ClutterDeviceManagerOSX *manager_osx;
+  ClutterStageOSX *stage_osx;
+  ClutterStageWindow *impl;
+  ClutterStage *stage;
+
+  stage       = event->any.stage;
+  impl        = _clutter_stage_get_window (event->any.stage);
+  stage_osx   = CLUTTER_STAGE_OSX (impl);
+  manager_osx = CLUTTER_DEVICE_MANAGER_OSX (clutter_device_manager_get_default ());
+
   event->any.time = [nsevent clutterTime];
 
   switch ([nsevent type])
@@ -228,11 +297,12 @@ clutter_event_osx_translate (NSEvent *nsevent, ClutterEvent *event)
       event->button.click_count = [nsevent clickCount];
       event->motion.modifier_state = [nsevent clutterModifierState];
       [nsevent clutterX:&(event->button.x) y:&(event->button.y)];
+      clutter_event_set_device (event, manager_osx->core_pointer);
 
       CLUTTER_NOTE (EVENT, "button %d %s at %f,%f clicks=%d",
                     (int)[nsevent buttonNumber],
                     event->type == CLUTTER_BUTTON_PRESS ? "press" : "release",
-                    (float)event->button.x, (float)event->button.y,
+                    event->button.x, event->button.y,
                     event->button.click_count);
       return TRUE;
 
@@ -244,12 +314,53 @@ clutter_event_osx_translate (NSEvent *nsevent, ClutterEvent *event)
 
       [nsevent clutterX:&(event->motion.x) y:&(event->motion.y)];
       event->motion.modifier_state = [nsevent clutterModifierState];
+      clutter_event_set_device (event, manager_osx->core_pointer);
 
       CLUTTER_NOTE (EVENT, "motion %d at %f,%f",
                     (int)[nsevent buttonNumber],
-                    (float)event->button.x, (float)event->button.y);
+                    event->button.x, event->button.y);
+      return TRUE;
+
+    case NSMouseEntered:
+      event->type = CLUTTER_ENTER;
+
+      [nsevent clutterX:&(event->crossing.x) y:&(event->crossing.y)];
+      event->crossing.related = NULL;
+      event->crossing.source = CLUTTER_ACTOR (stage);
+      clutter_event_set_device (event, manager_osx->core_pointer);
+
+      _clutter_stage_add_device (stage, manager_osx->core_pointer);
+
+      CLUTTER_NOTE (EVENT, "enter at %f,%f",
+                    event->crossing.x, event->crossing.y);
       return TRUE;
 
+    case NSMouseExited:
+      event->type = CLUTTER_LEAVE;
+
+      [nsevent clutterX:&(event->crossing.x) y:&(event->crossing.y)];
+      event->crossing.related = NULL;
+      event->crossing.source = CLUTTER_ACTOR (stage);
+      clutter_event_set_device (event, manager_osx->core_pointer);
+
+      _clutter_stage_remove_device (stage, manager_osx->core_pointer);
+
+      CLUTTER_NOTE (EVENT, "exit at %f,%f",
+                    event->crossing.x, event->crossing.y);
+      return TRUE;
+
+    case NSScrollWheel:
+      stage_osx->scroll_pos_x += [nsevent deltaX];
+      stage_osx->scroll_pos_y += [nsevent deltaY];
+      
+      [nsevent clutterX:&(event->scroll.x) y:&(event->scroll.y)];
+      event->scroll.modifier_state = [nsevent clutterModifierState];
+      clutter_event_set_device (event, manager_osx->core_pointer);
+      
+      process_scroll_event (event, TRUE);
+      process_scroll_event (event, FALSE);
+      break;
+      
     case NSKeyDown:
       event->type = CLUTTER_KEY_PRESS;
       /* fall through */
@@ -261,6 +372,7 @@ clutter_event_osx_translate (NSEvent *nsevent, ClutterEvent *event)
       event->key.modifier_state = [nsevent clutterModifierState];
       event->key.keyval = [nsevent clutterKeyVal];
       event->key.unicode_value = [[nsevent characters] characterAtIndex:0];
+      clutter_event_set_device (event, manager_osx->core_keyboard);
 
       CLUTTER_NOTE (EVENT, "key %d (%s) (%s) %s, keyval %d",
                     [nsevent keyCode],
@@ -279,160 +391,33 @@ clutter_event_osx_translate (NSEvent *nsevent, ClutterEvent *event)
 }
 
 void
-_clutter_event_osx_put (NSEvent *nsevent, ClutterStage *wrapper)
+_clutter_event_osx_put (NSEvent      *nsevent,
+                        ClutterStage *wrapper)
 {
-  ClutterEvent event = { 0, };
-
-  event.any.stage = wrapper;
+  ClutterEvent *event = clutter_event_new (CLUTTER_NOTHING);
 
-  if (clutter_event_osx_translate (nsevent, &event))
-    {
-      g_assert (event.type != CLUTTER_NOTHING);
-      clutter_event_put (&event);
-    }
-}
-
-typedef struct {
-  CFSocketRef        sock;
-  CFRunLoopSourceRef source;
-
-  gushort            revents;
-} SocketInfo;
-
-static void
-socket_activity_cb (CFSocketRef           sock,
-                    CFSocketCallBackType  cbtype,
-                    CFDataRef             address,
-                    const void           *data,
-                    void                 *info)
-{
-  SocketInfo *si = info;
-
-  if (cbtype & kCFSocketReadCallBack)
-    si->revents |= G_IO_IN;
-  if (cbtype & kCFSocketWriteCallBack)
-    si->revents |= G_IO_OUT;
-}
-
-static gint
-clutter_event_osx_poll_func (GPollFD *ufds, guint nfds, gint timeout)
-{
-  NSDate     *until_date;
-  NSEvent    *nsevent;
-  SocketInfo *sockets = NULL;
-  gint        n_active = 0;
-
-  CLUTTER_OSX_POOL_ALLOC();
-
-  if (timeout == -1)
-    until_date = [NSDate distantFuture];
-  else if (timeout == 0)
-    until_date = [NSDate distantPast];
-  else
-    until_date = [NSDate dateWithTimeIntervalSinceNow:timeout/1000.0];
-
-  /* File descriptors appear to be similar enough to sockets so that they can
-   * be used in CFRunLoopSource.
-   *
-   * We could also launch a thread to call old_poll_func and signal the main
-   * thread. No idea which way is better.
-   */
-  if (nfds > 0)
-    {
-      CFRunLoopRef run_loop;
-
-      run_loop = [[NSRunLoop currentRunLoop] getCFRunLoop];
-      sockets = g_new (SocketInfo, nfds);
-
-      int i;
-      for (i = 0; i < nfds; i++)
-        {
-          SocketInfo *si = &sockets[i];
-          CFSocketCallBackType cbtype;
-
-          cbtype = 0;
-          if (ufds[i].events & G_IO_IN)
-            cbtype |= kCFSocketReadCallBack;
-          if (ufds[i].events & G_IO_OUT)
-            cbtype |= kCFSocketWriteCallBack;
-          /* FIXME: how to handle G_IO_HUP and G_IO_ERR? */
-
-          const CFSocketContext ctxt = {
-            0, si, NULL, NULL, NULL
-          };
-          si->sock = CFSocketCreateWithNative (NULL, ufds[i].fd, cbtype, socket_activity_cb, &ctxt);
-          si->source = CFSocketCreateRunLoopSource (NULL, si->sock, 0);
-          si->revents = 0;
-
-          CFRunLoopAddSource (run_loop, si->source, kCFRunLoopCommonModes);
-        }
-    }
-
-  nsevent = [NSApp nextEventMatchingMask: NSAnyEventMask
-                               untilDate: until_date
-                                  inMode: NSDefaultRunLoopMode
-                                 dequeue: YES];
-
-  /* Push the events to NSApplication which will do some magic(?) and forward
-   * interesting events to our view. While we could do event translation here
-   * we'd also need to filter out clicks on titlebar, and perhaps do special
-   * handling for the first click (couldn't figure it out - always ended up
-   * missing a screen refresh) and maybe other things.
-   */
-  [NSApp sendEvent:nsevent];
+  /* common fields */
+  event->any.stage = wrapper;
+  event->any.time = [nsevent clutterTime];
 
-  if (nfds > 0)
+  if (clutter_event_osx_translate (nsevent, event))
     {
-      int i;
-      for (i = 0; i < nfds; i++)
-        {
-          SocketInfo *si = &sockets[i];
-
-          if ((ufds[i].revents = si->revents) != 0)
-            n_active++;
-
-          /* Invalidating the source also removes it from run loop and
-           * guarantees the callback is never called again.
-           * CFRunLoopRemoveSource removes the source from the loop, but might
-           * still call the callback which would be badly timed.
-           */
-          CFRunLoopSourceInvalidate (si->source);
-          CFRelease (si->source);
-          CFRelease (si->sock);
-        }
+      g_assert (event->type != CLUTTER_NOTHING);
 
-      g_free (sockets);
+      _clutter_event_push (event, FALSE);
     }
-
-  /* FIXME this could result in infinite loop */
-  ClutterEvent *event = clutter_event_get ();
-  while (event)
-    {
-      clutter_do_event (event);
-      clutter_event_free (event);
-      event = clutter_event_get ();
-    }
-
-  CLUTTER_OSX_POOL_RELEASE();
-
-  return n_active;
+  else
+    clutter_event_free (event);
 }
 
 void
 _clutter_events_osx_init (void)
 {
-  g_assert (old_poll_func == NULL);
-
-  old_poll_func = g_main_context_get_poll_func (NULL);
-  g_main_context_set_poll_func (NULL, clutter_event_osx_poll_func);
+  _clutter_osx_event_loop_init ();
 }
 
 void
 _clutter_events_osx_uninit (void)
 {
-  if (old_poll_func)
-    {
-      g_main_context_set_poll_func (NULL, old_poll_func);
-      old_poll_func = NULL;
-    }
+  g_assert_not_reached ();
 }
index aa5fe61..ac6d68b 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2007-2008  Tommi Komulainen <tommi.komulainen@iki.fi>
  * Copyright (C) 2007  OpenedHand Ltd.
+ * Copyright (C) 2011  Crystalnix  <vgachkaylo@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -33,6 +34,8 @@
 
 static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
 
+#define clutter_stage_osx_get_type      _clutter_stage_osx_get_type
+
 G_DEFINE_TYPE_WITH_CODE (ClutterStageOSX,
                          clutter_stage_osx,
                          G_TYPE_OBJECT,
@@ -44,6 +47,7 @@ static void
 clutter_stage_osx_state_update (ClutterStageOSX   *self,
                                 ClutterStageState  unset_flags,
                                 ClutterStageState  set_flags);
+
 static ClutterActor *
 clutter_stage_osx_get_wrapper (ClutterStageWindow *stage_window);
 
@@ -132,6 +136,7 @@ clutter_stage_osx_get_wrapper (ClutterStageWindow *stage_window);
 @interface ClutterGLView : NSOpenGLView
 {
   ClutterStageOSX *stage_osx;
+  NSTrackingRectTag tracking_rect;
 }
 - (void) drawRect: (NSRect) bounds;
 @end
@@ -142,6 +147,7 @@ clutter_stage_osx_get_wrapper (ClutterStageWindow *stage_window);
   if ((self = [super initWithFrame:aFrame pixelFormat:aFormat]) != nil)
     {
       self->stage_osx = aStage;
+      tracking_rect = [self addTrackingRect:[self bounds] owner:self userData:NULL assumeInside:NO];
     }
 
   return self;
@@ -152,6 +158,7 @@ clutter_stage_osx_get_wrapper (ClutterStageWindow *stage_window);
   _clutter_stage_do_paint (CLUTTER_STAGE (self->stage_osx->wrapper), NULL);
   cogl_flush ();
   [[self openGLContext] flushBuffer];
+  _cogl_swap_buffers_notify ();
 }
 
 /* In order to receive key events */
@@ -172,6 +179,9 @@ clutter_stage_osx_get_wrapper (ClutterStageWindow *stage_window);
   stage_osx->requisition_height = [self bounds].size.height;
   clutter_actor_set_size (CLUTTER_ACTOR (self->stage_osx->wrapper),
                           (int)[self bounds].size.width, (int)[self bounds].size.height);
+
+  [self removeTrackingRect:tracking_rect];
+  tracking_rect = [self addTrackingRect:[self bounds] owner:self userData:NULL assumeInside:NO];
 }
 
 /* Simply forward all events that reach our view to clutter. */
@@ -514,6 +524,19 @@ clutter_stage_osx_set_accept_focus (ClutterStageWindow *stage_window,
 }
 
 static void
+clutter_stage_osx_redraw (ClutterStageWindow *stage_window)
+{
+  ClutterStageOSX *stage_osx = CLUTTER_STAGE_OSX (stage_window);
+
+  CLUTTER_OSX_POOL_ALLOC();
+
+  if (stage_osx->view != NULL)
+    [stage_osx->view setNeedsDisplay: YES];
+
+  CLUTTER_OSX_POOL_RELEASE();
+}
+
+static void
 clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
 {
   iface->get_wrapper    = clutter_stage_osx_get_wrapper;
@@ -528,12 +551,13 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
   iface->set_cursor_visible = clutter_stage_osx_set_cursor_visible;
   iface->set_user_resizable = clutter_stage_osx_set_user_resizable;
   iface->set_accept_focus   = clutter_stage_osx_set_accept_focus;
+  iface->redraw             = clutter_stage_osx_redraw;
 }
 
 /*************************************************************************/
 ClutterStageWindow *
-clutter_stage_osx_new (ClutterBackend *backend,
-                       ClutterStage   *wrapper)
+_clutter_stage_osx_new (ClutterBackend *backend,
+                        ClutterStage   *wrapper)
 {
   ClutterStageOSX *self;
 
index 923a95b..af1d7ba 100644 (file)
@@ -31,7 +31,7 @@
 G_BEGIN_DECLS
 
 /* convenience macros */
-#define CLUTTER_TYPE_STAGE_OSX             (clutter_stage_osx_get_type())
+#define CLUTTER_TYPE_STAGE_OSX             (_clutter_stage_osx_get_type())
 #define CLUTTER_STAGE_OSX(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),CLUTTER_TYPE_STAGE_OSX,ClutterStageOSX))
 #define CLUTTER_STAGE_OSX_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),CLUTTER_TYPE_STAGE_OSX,ClutterStage))
 #define CLUTTER_IS_STAGE_OSX(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),CLUTTER_TYPE_STAGE_OSX))
@@ -50,7 +50,7 @@ typedef struct _ClutterStageOSXClass ClutterStageOSXClass;
 
 struct _ClutterStageOSX
 {
-  ClutterGroup parent;
+  GObject parent;
 
   ClutterBackend *backend;
   ClutterStage   *wrapper;
@@ -67,17 +67,20 @@ struct _ClutterStageOSX
   ClutterStageState stage_state;
 
   gboolean acceptFocus;
+
+  gfloat scroll_pos_x;
+  gfloat scroll_pos_y;
 };
 
 struct _ClutterStageOSXClass
 {
-  ClutterGroupClass parent_class;
+  GObjectClass parent_class;
 };
 
-GType           clutter_stage_osx_get_type    (void) G_GNUC_CONST;
+GType _clutter_stage_osx_get_type (void) G_GNUC_CONST;
 
-ClutterStageWindow*   clutter_stage_osx_new (ClutterBackend *backend,
-                                             ClutterStage   *wrapper);
+ClutterStageWindow *    _clutter_stage_osx_new  (ClutterBackend *backend,
+                                                 ClutterStage   *wrapper);
 
 G_END_DECLS
 
index 688aba9..6e52bba 100644 (file)
@@ -74,7 +74,6 @@ clutter_backend_wayland_handle_motion (void *data,
 {
   ClutterInputDeviceWayland *device = data;
   ClutterStageWayland       *stage_wayland = device->pointer_focus;
-  ClutterMainContext        *clutter_context;
   ClutterEvent              *event;
 
   event = clutter_event_new (CLUTTER_MOTION);
@@ -90,8 +89,7 @@ clutter_backend_wayland_handle_motion (void *data,
   device->x = x;
   device->y = y;
 
-  clutter_context = _clutter_context_get_default ();
-  g_queue_push_head (clutter_context->events_queue, event);
+  _clutter_event_push (event, FALSE);
 }
 
 static void
@@ -102,7 +100,6 @@ clutter_backend_wayland_handle_button (void *data,
 {
   ClutterInputDeviceWayland *device = data;
   ClutterStageWayland       *stage_wayland = device->pointer_focus;
-  ClutterMainContext        *clutter_context;
   ClutterEvent              *event;
   ClutterEventType           type;
 
@@ -132,8 +129,7 @@ clutter_backend_wayland_handle_button (void *data,
     break;
   }
 
-  clutter_context = _clutter_context_get_default ();
-  g_queue_push_head (clutter_context->events_queue, event);
+  _clutter_event_push (event, FALSE);
 }
 
 static void
@@ -144,7 +140,6 @@ clutter_backend_wayland_handle_key (void *data,
 {
   ClutterInputDeviceWayland *device = data;
   ClutterStageWayland       *stage_wayland = device->keyboard_focus;
-  ClutterMainContext        *clutter_context;
   ClutterEvent              *event;
 
   event = _clutter_key_event_new_from_evdev ((ClutterInputDevice *) device,
@@ -153,8 +148,7 @@ clutter_backend_wayland_handle_key (void *data,
                                              _time, key, state,
                                              &device->modifier_state);
 
-  clutter_context = _clutter_context_get_default ();
-  g_queue_push_head (clutter_context->events_queue, event);
+  _clutter_event_push (event, FALSE);
 }
 
 static void
@@ -166,7 +160,6 @@ clutter_backend_wayland_handle_pointer_focus (void *data,
 {
   ClutterInputDeviceWayland *device = data;
   ClutterStageWayland       *stage_wayland;
-  ClutterMainContext        *clutter_context;
   ClutterEvent              *event;
 
   if (device->pointer_focus)
@@ -181,8 +174,7 @@ clutter_backend_wayland_handle_pointer_focus (void *data,
       event->crossing.source = CLUTTER_ACTOR (stage_wayland->wrapper);
       event->crossing.device = CLUTTER_INPUT_DEVICE (device);
 
-      clutter_context = _clutter_context_get_default ();
-      g_queue_push_head (clutter_context->events_queue, event);
+      _clutter_event_push (event, FALSE);
 
       device->pointer_focus = NULL;
       _clutter_input_device_set_stage (CLUTTER_INPUT_DEVICE (device), NULL);
@@ -204,8 +196,7 @@ clutter_backend_wayland_handle_pointer_focus (void *data,
       event->motion.source = CLUTTER_ACTOR (stage_wayland->wrapper);
       event->motion.device = CLUTTER_INPUT_DEVICE (device);
 
-      clutter_context = _clutter_context_get_default ();
-      g_queue_push_head (clutter_context->events_queue, event);
+      _clutter_event_push (event, FALSE);
 
       device->surface_x = sx;
       device->surface_y = sy;
@@ -226,7 +217,6 @@ clutter_backend_wayland_handle_keyboard_focus (void *data,
 {
   ClutterInputDeviceWayland *device = data;
   ClutterStageWayland       *stage_wayland;
-  ClutterMainContext        *clutter_context;
   ClutterEvent              *event;
   uint32_t                  *k, *end;
 
@@ -242,8 +232,7 @@ clutter_backend_wayland_handle_keyboard_focus (void *data,
       event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
       event->stage_state.new_state = 0;
 
-      clutter_context = _clutter_context_get_default ();
-      g_queue_push_head (clutter_context->events_queue, event);
+      _clutter_event_push (event, FALSE);
     }
 
   if (surface)
@@ -261,8 +250,7 @@ clutter_backend_wayland_handle_keyboard_focus (void *data,
       for (k = keys->data; k < end; k++)
        device->modifier_state |= device->xkb->map->modmap[*k];
 
-      clutter_context = _clutter_context_get_default ();
-      g_queue_push_head (clutter_context->events_queue, event);
+      _clutter_event_push (event, FALSE);
     }
 }
 
index c691dde..d010474 100644 (file)
@@ -506,6 +506,8 @@ wayland_swap_buffers (ClutterStageWayland *stage_wayland)
   wl_display_frame_callback (backend_wayland->wayland_display,
                             wayland_frame_callback,
                             stage_wayland);
+
+  _cogl_swap_buffers_notify ();
 }
 
 static void
index 9f6720b..4ab3f27 100644 (file)
@@ -478,29 +478,6 @@ clutter_backend_win32_ensure_context (ClutterBackend *backend,
     }
 }
 
-static void
-clutter_backend_win32_redraw (ClutterBackend *backend,
-                             ClutterStage   *stage)
-{
-  ClutterStageWin32  *stage_win32;
-  ClutterStageWindow *impl;
-
-  impl = _clutter_stage_get_window (stage);
-  if (impl == NULL)
-    return;
-
-  g_return_if_fail (CLUTTER_IS_STAGE_WIN32 (impl));
-
-  stage_win32 = CLUTTER_STAGE_WIN32 (impl);
-
-  /* this will cause the stage implementation to be painted */
-  _clutter_stage_do_paint (stage, NULL);
-  cogl_flush ();
-
-  if (stage_win32->client_dc)
-    SwapBuffers (stage_win32->client_dc);
-}
-
 static ClutterStageWindow *
 clutter_backend_win32_create_stage (ClutterBackend  *backend,
                                    ClutterStage    *wrapper,
@@ -577,7 +554,6 @@ clutter_backend_win32_class_init (ClutterBackendWin32Class *klass)
   backend_class->create_stage     = clutter_backend_win32_create_stage;
   backend_class->add_options      = clutter_backend_win32_add_options;
   backend_class->get_features     = clutter_backend_win32_get_features;
-  backend_class->redraw           = clutter_backend_win32_redraw;
   backend_class->create_context   = clutter_backend_win32_create_context;
   backend_class->ensure_context   = clutter_backend_win32_ensure_context;
   backend_class->get_device_manager = clutter_backend_win32_get_device_manager;
index 1e9308a..3527c9c 100644 (file)
@@ -48,12 +48,16 @@ static void
 clutter_device_manager_win32_constructed (GObject *gobject)
 {
   ClutterDeviceManager *manager = CLUTTER_DEVICE_MANAGER (gobject);
+  ClutterDeviceManagerWin32 *manager_win32;
   ClutterInputDevice *device;
 
   device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE,
                          "id", 0,
                          "name", "Core Pointer",
                          "device-type", CLUTTER_POINTER_DEVICE,
+                         "device-mode", CLUTTER_INPUT_MODE_MASTER,
+                         "has-cursor", TRUE,
+                         "enabled", TRUE,
                          NULL);
   CLUTTER_NOTE (BACKEND, "Added core pointer device");
   _clutter_device_manager_add_device (manager, device);
@@ -62,9 +66,18 @@ clutter_device_manager_win32_constructed (GObject *gobject)
                          "id", 1,
                          "name", "Core Keyboard",
                          "device-type", CLUTTER_KEYBOARD_DEVICE,
+                         "device-mode", CLUTTER_INPUT_MODE_MASTER,
+                         "enabled", TRUE,
                          NULL);
   CLUTTER_NOTE (BACKEND, "Added core keyboard device");
   _clutter_device_manager_add_device (manager, device);
+
+  manager_win32 = CLUTTER_DEVICE_MANAGER_WIN32 (manager);
+
+  _clutter_input_device_set_associated_device (manager_win32->core_pointer,
+                                               manager_win32->core_keyboard);
+  _clutter_input_device_set_associated_device (manager_win32->core_keyboard,
+                                               manager_win32->core_pointer);
 }
 
 static void
index 128c62e..c332912 100644 (file)
@@ -129,8 +129,8 @@ static const struct
     { VK_LCONTROL, CLUTTER_KEY_Control_L },
     { VK_RCONTROL, CLUTTER_KEY_Control_R }
   };
-#define CLUTTER_WIN32_KEY_MAP_SIZE (sizeof (clutter_win32_key_map) \
-                                   / sizeof (clutter_win32_key_map[0]))
+
+#define CLUTTER_WIN32_KEY_MAP_SIZE      (G_N_ELEMENTS (clutter_win32_key_map))
 
 static GSource *
 clutter_event_source_new (ClutterBackend *backend)
@@ -140,6 +140,8 @@ clutter_event_source_new (ClutterBackend *backend)
 
   event_source->backend = backend;
 
+  g_source_set_name (source, "Clutter Win32 Event Source");
+
   return source;
 }
 
@@ -204,17 +206,13 @@ get_modifier_state (WPARAM wparam)
   return ret;
 }
 
-static void
+static inline void
 take_and_queue_event (ClutterEvent *event)
 {
-  ClutterMainContext *clutter_context;
-
-  clutter_context = _clutter_context_get_default ();
-
   /* The event is added directly to the queue instead of using
      clutter_event_put so that it can avoid a copy. This takes
      ownership of the event */
-  g_queue_push_head (clutter_context->events_queue, event);
+  _clutter_event_push (event, FALSE);
 }
 
 static inline void
@@ -228,14 +226,16 @@ make_button_event (const MSG *msg,
   ClutterEvent *event = clutter_event_new (release ?
                                            CLUTTER_BUTTON_RELEASE :
                                            CLUTTER_BUTTON_PRESS);
+
+  event->any.stage = stage;
+
   event->button.time = msg->time;
   event->button.x = GET_X_LPARAM (msg->lParam);
   event->button.y = GET_Y_LPARAM (msg->lParam);
   event->button.modifier_state = get_modifier_state (msg->wParam);
   event->button.button = button;
   event->button.click_count = click_count;
-  event->button.device = device;
-  event->any.stage = stage;
+  clutter_event_set_device (event, device);
 
   take_and_queue_event (event);
 }
@@ -512,9 +512,10 @@ clutter_win32_handle_event (const MSG *msg)
           event->scroll.time = msg->time;
           event->scroll.modifier_state =
             get_modifier_state (LOWORD (msg->wParam));
-          event->scroll.device = core_pointer;
           event->any.stage = stage;
 
+          clutter_event_set_device (event, core_pointer);
+
           /* conversion to window coordinates is required */
           pt.x = GET_X_LPARAM (msg->lParam);
           pt.y = GET_Y_LPARAM (msg->lParam);
@@ -545,13 +546,15 @@ clutter_win32_handle_event (const MSG *msg)
         event->motion.x = GET_X_LPARAM (msg->lParam);
         event->motion.y = GET_Y_LPARAM (msg->lParam);
         event->motion.modifier_state = get_modifier_state (msg->wParam);
-        event->motion.device = core_pointer;
         event->any.stage = stage;
 
+        clutter_event_set_device (event, core_pointer);
+
         /* We need to start tracking when the mouse enters the stage if
            we're not already */
         if (!stage_win32->tracking_mouse)
           {
+            ClutterEvent *crossing = clutter_event_new (CLUTTER_ENTER);
             TRACKMOUSEEVENT tmevent;
 
             tmevent.cbSize = sizeof (tmevent);
@@ -559,8 +562,19 @@ clutter_win32_handle_event (const MSG *msg)
             tmevent.hwndTrack = stage_win32->hwnd;
             TrackMouseEvent (&tmevent);
 
+            event->crossing.time = msg->time;
+            event->crossing.x = event->motion.x;
+            event->crossing.y = event->motion.y;
+            event->crossing.stage = stage;
+            event->crossing.source = CLUTTER_ACTOR (stage);
+            event->crossing.related = NULL;
+
+            clutter_event_set_device (event, core_pointer);
+
             /* we entered the stage */
-            _clutter_input_device_set_stage (event->motion.device, stage);
+            _clutter_stage_add_device (stage, event->crossing.device);
+
+            take_and_queue_event (crossing);
 
             stage_win32->tracking_mouse = TRUE;
           }
@@ -576,11 +590,14 @@ clutter_win32_handle_event (const MSG *msg)
         event->crossing.time = msg->time;
         event->crossing.x = msg->pt.x;
         event->crossing.y = msg->pt.y;
-        event->crossing.device = core_pointer;
-        event->any.stage = stage;
+        event->crossing.stage = stage;
+        event->crossing.source = CLUTTER_ACTOR (stage);
+        event->crossing.related = NULL;
+
+        clutter_event_set_device (event, core_pointer);
 
         /* we left the stage */
-        _clutter_input_device_set_stage (event->crossing.device, NULL);
+        _clutter_stage_remove_device (stage, core_pointer);
 
         /* When we get a leave message the mouse tracking is
            automatically cancelled so we'll need to start it again when
@@ -669,9 +686,10 @@ clutter_win32_handle_event (const MSG *msg)
        event->key.time = msg->time;
        event->key.modifier_state = get_key_modifier_state (key_states);
        event->key.hardware_keycode = scan_code;
-        event->key.device = core_keyboard;
         event->any.stage = stage;
 
+        clutter_event_set_device (event, core_keyboard);
+
         take_and_queue_event (event);
       }
       break;
index 6d0588b..540c68a 100644 (file)
@@ -519,6 +519,22 @@ clutter_stage_win32_unrealize (ClutterStageWindow *stage_window)
 }
 
 static void
+clutter_stage_win32_redraw (ClutterStageWindow *stage_window)
+{
+  ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
+
+  /* this will cause the stage implementation to be painted */
+  _clutter_stage_do_paint (stage_win32->wrapper, NULL);
+  cogl_flush ();
+
+  if (stage_win32->client_dc)
+    {
+      SwapBuffers (stage_win32->client_dc);
+      _cogl_swap_buffers_notify ();
+    }
+}
+
+static void
 clutter_stage_win32_dispose (GObject *gobject)
 {
   ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (gobject);
@@ -575,6 +591,7 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
   iface->get_geometry = clutter_stage_win32_get_geometry;
   iface->realize = clutter_stage_win32_realize;
   iface->unrealize = clutter_stage_win32_unrealize;
+  iface->redraw = clutter_stage_win32_redraw;
 }
 
 /**
index 5efb115..d48320e 100644 (file)
@@ -38,8 +38,8 @@
 #include <errno.h>
 
 #include "clutter-backend-x11.h"
-#include "clutter-device-manager-x11.h"
-#include "clutter-input-device-x11.h"
+#include "clutter-device-manager-core-x11.h"
+#include "clutter-device-manager-xi2.h"
 #include "clutter-settings-x11.h"
 #include "clutter-stage-x11.h"
 #include "clutter-x11.h"
 #include <X11/extensions/XInput.h>
 #endif
 
+#if HAVE_XINPUT_2
+#include <X11/extensions/XInput2.h>
+#endif
+
 #include "cogl/cogl.h"
 #include "cogl/cogl-internal.h"
 
 #include "clutter-backend.h"
 #include "clutter-debug.h"
-#include "clutter-device-manager.h"
+#include "clutter-device-manager-private.h"
 #include "clutter-event.h"
 #include "clutter-main.h"
 #include "clutter-private.h"
 
+#define clutter_backend_x11_get_type    _clutter_backend_x11_get_type
+
 G_DEFINE_TYPE (ClutterBackendX11, clutter_backend_x11, CLUTTER_TYPE_BACKEND);
 
 /* atoms; remember to add the code that assigns the atom value to
@@ -120,6 +126,30 @@ xsettings_filter (XEvent       *xevent,
   return CLUTTER_X11_FILTER_CONTINUE;
 }
 
+static ClutterX11FilterReturn
+cogl_xlib_filter (XEvent       *xevent,
+                  ClutterEvent *event,
+                  gpointer      data)
+{
+  ClutterX11FilterReturn retval;
+  CoglXlibFilterReturn ret;
+
+  ret = _cogl_xlib_handle_event (xevent);
+  switch (ret)
+    {
+    case COGL_XLIB_FILTER_REMOVE:
+      retval = CLUTTER_X11_FILTER_REMOVE;
+      break;
+
+    case COGL_XLIB_FILTER_CONTINUE:
+    default:
+      retval = CLUTTER_X11_FILTER_CONTINUE;
+      break;
+    }
+
+  return retval;
+}
+
 static void
 clutter_backend_x11_xsettings_notify (const char       *name,
                                       XSettingsAction   action,
@@ -192,9 +222,91 @@ clutter_backend_x11_xsettings_notify (const char       *name,
   g_object_thaw_notify (G_OBJECT (settings));
 }
 
+static void
+clutter_backend_x11_create_device_manager (ClutterBackendX11 *backend_x11)
+{
+  if (G_UNLIKELY (backend_x11->device_manager == NULL))
+    {
+      ClutterEventTranslator *translator;
+      ClutterBackend *backend;
+
+#if defined(HAVE_XINPUT) || defined(HAVE_XINPUT_2)
+      if (clutter_enable_xinput)
+        {
+          int event_base, first_event, first_error;
+
+          if (XQueryExtension (backend_x11->xdpy, "XInputExtension",
+                               &event_base,
+                               &first_event,
+                               &first_error))
+            {
+#ifdef HAVE_XINPUT_2
+              int major = 2;
+              int minor = 0;
+
+              if (XIQueryVersion (backend_x11->xdpy, &major, &minor) != BadRequest)
+                {
+                  CLUTTER_NOTE (BACKEND, "Creating XI2 device manager");
+                  backend_x11->has_xinput = TRUE;
+                  backend_x11->device_manager =
+                    g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_XI2,
+                                  "backend", backend_x11,
+                                  "opcode", event_base,
+                                  NULL);
+                }
+              else
+#endif /* HAVE_XINPUT_2 */
+                {
+                  CLUTTER_NOTE (BACKEND, "Creating Core+XI device manager");
+                  backend_x11->has_xinput = TRUE;
+                  backend_x11->device_manager =
+                    g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_X11,
+                                  "backend", backend_x11,
+                                  "event-base", first_event,
+                                  NULL);
+
+                }
+            }
+        }
+      else
+#endif /* HAVE_XINPUT || HAVE_XINPUT_2 */
+        {
+          CLUTTER_NOTE (BACKEND, "Creating Core device manager");
+          backend_x11->has_xinput = FALSE;
+          backend_x11->device_manager =
+            g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_X11,
+                          "backend", backend_x11,
+                          NULL);
+        }
+
+      backend = CLUTTER_BACKEND (backend_x11);
+      translator = CLUTTER_EVENT_TRANSLATOR (backend_x11->device_manager);
+      _clutter_backend_add_event_translator (backend, translator);
+    }
+}
+
+static void
+clutter_backend_x11_create_keymap (ClutterBackendX11 *backend_x11)
+{
+  if (backend_x11->keymap == NULL)
+    {
+      ClutterEventTranslator *translator;
+      ClutterBackend *backend;
+
+      backend_x11->keymap =
+        g_object_new (CLUTTER_TYPE_KEYMAP_X11,
+                      "backend", backend_x11,
+                      NULL);
+
+      backend = CLUTTER_BACKEND (backend_x11);
+      translator = CLUTTER_EVENT_TRANSLATOR (backend_x11->keymap);
+      _clutter_backend_add_event_translator (backend, translator);
+    }
+}
+
 gboolean
-clutter_backend_x11_pre_parse (ClutterBackend  *backend,
-                               GError         **error)
+_clutter_backend_x11_pre_parse (ClutterBackend  *backend,
+                                GError         **error)
 {
   const gchar *env_string;
 
@@ -215,12 +327,19 @@ clutter_backend_x11_pre_parse (ClutterBackend  *backend,
       env_string = NULL;
     }
 
+  env_string = g_getenv ("CLUTTER_ENABLE_XINPUT");
+  if (env_string)
+    {
+      clutter_enable_xinput = TRUE;
+      env_string = NULL;
+    }
+
   return TRUE;
 }
 
 gboolean
-clutter_backend_x11_post_parse (ClutterBackend  *backend,
-                                GError         **error)
+_clutter_backend_x11_post_parse (ClutterBackend  *backend,
+                                 GError         **error)
 {
   ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
@@ -271,6 +390,9 @@ clutter_backend_x11_post_parse (ClutterBackend  *backend,
          CoglTexturePixmapX11 */
       _cogl_xlib_set_display (backend_x11->xdpy);
 
+      /* add event filter for Cogl events */
+      clutter_x11_add_filter (cogl_xlib_filter, NULL);
+
       if (clutter_screen == -1)
         backend_x11->xscreen = DefaultScreenOfDisplay (backend_x11->xdpy);
       else
@@ -278,6 +400,8 @@ clutter_backend_x11_post_parse (ClutterBackend  *backend,
                                                 clutter_screen);
 
       backend_x11->xscreen_num = XScreenNumberOfScreen (backend_x11->xscreen);
+      backend_x11->xscreen_width = WidthOfScreen (backend_x11->xscreen);
+      backend_x11->xscreen_height = HeightOfScreen (backend_x11->xscreen);
 
       backend_x11->xwin_root = RootWindow (backend_x11->xdpy,
                                            backend_x11->xscreen_num);
@@ -289,18 +413,11 @@ clutter_backend_x11_post_parse (ClutterBackend  *backend,
 
       g_object_set (settings, "font-dpi", (int) dpi * 1024, NULL);
 
-      /* register input devices */
-      backend_x11->device_manager =
-        g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_X11,
-                      "use-xinput-1", clutter_enable_xinput,
-                      "backend", backend_x11,
-                      NULL);
+      /* create the device manager */
+      clutter_backend_x11_create_device_manager (backend_x11);
 
       /* register keymap */
-      backend_x11->keymap =
-        g_object_new (CLUTTER_TYPE_KEYMAP_X11,
-                      "backend", backend_x11,
-                      NULL);
+      clutter_backend_x11_create_keymap (backend_x11);
 
       /* create XSETTINGS client */
       backend_x11->xsettings =
@@ -310,6 +427,7 @@ clutter_backend_x11_post_parse (ClutterBackend  *backend,
                                        NULL,
                                        backend_x11);
 
+      /* add event filter for XSETTINGS events */
       clutter_x11_add_filter (xsettings_filter, backend_x11);
 
       if (clutter_synchronise)
@@ -374,7 +492,7 @@ static const GOptionEntry entries[] =
     G_OPTION_ARG_NONE, &clutter_synchronise,
     N_("Make X calls synchronous"), NULL
   },
-#ifdef HAVE_XINPUT
+#if defined(HAVE_XINPUT) || defined(HAVE_XINPUT_2)
   {
     "enable-xinput", 0,
     0,
@@ -385,7 +503,7 @@ static const GOptionEntry entries[] =
   { NULL }
 };
 
-void
+static void
 clutter_backend_x11_add_options (ClutterBackend *backend,
                                  GOptionGroup   *group)
 {
@@ -399,6 +517,8 @@ clutter_backend_x11_finalize (GObject *gobject)
 
   g_free (backend_x11->display_name);
 
+  clutter_x11_remove_filter (cogl_xlib_filter, NULL);
+
   clutter_x11_remove_filter (xsettings_filter, backend_x11);
   _clutter_xsettings_client_destroy (backend_x11->xsettings);
 
@@ -435,7 +555,7 @@ clutter_backend_x11_constructor (GType                  gtype,
   GObjectClass *parent_class;
   GObject *retval;
 
-  if (!backend_singleton)
+  if (backend_singleton == NULL)
     {
       parent_class = G_OBJECT_CLASS (clutter_backend_x11_parent_class);
       retval = parent_class->constructor (gtype, n_params, params);
@@ -451,7 +571,7 @@ clutter_backend_x11_constructor (GType                  gtype,
   return g_object_ref (backend_singleton);
 }
 
-ClutterFeatureFlags
+static ClutterFeatureFlags
 clutter_backend_x11_get_features (ClutterBackend *backend)
 {
   return CLUTTER_FEATURE_STAGE_USER_RESIZE | CLUTTER_FEATURE_STAGE_CURSOR;
@@ -480,28 +600,108 @@ clutter_backend_x11_free_event_data (ClutterBackend *backend,
     _clutter_event_x11_free (event_x11);
 }
 
-gboolean
-clutter_backend_x11_handle_event (ClutterBackendX11 *backend_x11,
-                                  XEvent *xevent)
+static ClutterDeviceManager *
+clutter_backend_x11_get_device_manager (ClutterBackend *backend)
 {
-  return FALSE;
+  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
+
+  clutter_backend_x11_create_device_manager (backend_x11);
+
+  return backend_x11->device_manager;
 }
 
-static ClutterDeviceManager *
-clutter_backend_x11_get_device_manager (ClutterBackend *backend)
+static void
+update_last_event_time (ClutterBackendX11 *backend_x11,
+                        XEvent            *xevent)
+{
+  Time current_time = CurrentTime;
+  Time last_time = backend_x11->last_event_time;
+
+  switch (xevent->type)
+    {
+    case KeyPress:
+    case KeyRelease:
+      current_time = xevent->xkey.time;
+      break;
+
+    case ButtonPress:
+    case ButtonRelease:
+      current_time = xevent->xbutton.time;
+      break;
+
+    case MotionNotify:
+      current_time = xevent->xmotion.time;
+      break;
+
+    case EnterNotify:
+    case LeaveNotify:
+      current_time = xevent->xcrossing.time;
+      break;
+
+    case PropertyNotify:
+      current_time = xevent->xproperty.time;
+      break;
+
+    default:
+      break;
+    }
+
+  /* only change the current event time if it's after the previous event
+   * time, or if it is at least 30 seconds earlier - in case the system
+   * clock was changed
+   */
+  if ((current_time != CurrentTime) &&
+      (current_time > last_time || (last_time - current_time > (30 * 1000))))
+    backend_x11->last_event_time = current_time;
+}
+
+static gboolean
+clutter_backend_x11_translate_event (ClutterBackend *backend,
+                                     gpointer        native,
+                                     ClutterEvent   *event)
 {
   ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
+  ClutterBackendClass *parent_class;
+  XEvent *xevent = native;
 
-  if (G_UNLIKELY (backend_x11->device_manager == NULL))
+  /* X11 filter functions have a higher priority */
+  if (backend_x11->event_filters != NULL)
     {
-      backend_x11->device_manager =
-        g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_X11,
-                      "use-xinput-1", clutter_enable_xinput,
-                      "backend", backend_x11,
-                      NULL);
+      GSList *node = backend_x11->event_filters;
+
+      while (node != NULL)
+        {
+          ClutterX11EventFilter *filter = node->data;
+
+          switch (filter->func (xevent, event, filter->data))
+            {
+            case CLUTTER_X11_FILTER_CONTINUE:
+              break;
+
+            case CLUTTER_X11_FILTER_TRANSLATE:
+              return TRUE;
+
+            case CLUTTER_X11_FILTER_REMOVE:
+              return FALSE;
+
+            default:
+              break;
+            }
+
+          node = node->next;
+        }
     }
 
-  return backend_x11->device_manager;
+  /* we update the event time only for events that can
+   * actually reach Clutter's event queue
+   */
+  update_last_event_time (backend_x11, xevent);
+
+  /* chain up to the parent implementation, which will handle
+   * event translators
+   */
+  parent_class = CLUTTER_BACKEND_CLASS (clutter_backend_x11_parent_class);
+  return parent_class->translate_event (backend, native, event);
 }
 
 static void
@@ -509,22 +709,20 @@ clutter_backend_x11_class_init (ClutterBackendX11Class *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
-  ClutterBackendX11Class *backendx11_class = CLUTTER_BACKEND_X11_CLASS (klass);
 
   gobject_class->constructor = clutter_backend_x11_constructor;
   gobject_class->dispose = clutter_backend_x11_dispose;
   gobject_class->finalize = clutter_backend_x11_finalize;
 
-  backend_class->pre_parse = clutter_backend_x11_pre_parse;
-  backend_class->post_parse = clutter_backend_x11_post_parse;
+  backend_class->pre_parse = _clutter_backend_x11_pre_parse;
+  backend_class->post_parse = _clutter_backend_x11_post_parse;
   backend_class->init_events = clutter_backend_x11_init_events;
   backend_class->add_options = clutter_backend_x11_add_options;
   backend_class->get_features = clutter_backend_x11_get_features;
   backend_class->get_device_manager = clutter_backend_x11_get_device_manager;
   backend_class->copy_event_data = clutter_backend_x11_copy_event_data;
   backend_class->free_event_data = clutter_backend_x11_free_event_data;
-
-  backendx11_class->handle_event = clutter_backend_x11_handle_event;
+  backend_class->translate_event = clutter_backend_x11_translate_event;
 }
 
 static void
@@ -613,8 +811,8 @@ clutter_x11_set_display (Display *xdpy)
 {
   if (_clutter_context_is_initialized ())
     {
-      g_critical ("Display connection already exists. You can only call "
-                 "clutter_x11_set_display() before clutter_init()");
+      g_warning ("%s() can only be used before calling clutter_init()",
+                 G_STRFUNC);
       return;
     }
 
@@ -640,8 +838,8 @@ clutter_x11_enable_xinput (void)
 {
   if (_clutter_context_is_initialized ())
     {
-      g_critical ("clutter_x11_enable_xinput() can only be called "
-                  "before clutter_init()");
+      g_warning ("%s() can only be used before calling clutter_init()",
+                 G_STRFUNC);
       return;
     }
 
@@ -678,8 +876,8 @@ clutter_x11_disable_event_retrieval (void)
 {
   if (_clutter_context_is_initialized ())
     {
-      g_warning  ("clutter_x11_disable_event_retrieval() can only be "
-                  "called before clutter_init()");
+      g_warning ("%s() can only be used before calling clutter_init()",
+                 G_STRFUNC);
       return;
     }
 
@@ -723,7 +921,7 @@ clutter_x11_get_default_screen (void)
 }
 
 /**
- * clutter_x11_get_root_window:
+ * clutter_x11_get_root_window: (skip)
  *
  * Retrieves the root window.
  *
@@ -744,7 +942,7 @@ clutter_x11_get_root_window (void)
 }
 
 /**
- * clutter_x11_add_filter:
+ * clutter_x11_add_filter: (skip)
  * @func: a filter function
  * @data: user data to be passed to the filter function, or %NULL
  *
@@ -777,7 +975,7 @@ clutter_x11_add_filter (ClutterX11FilterFunc func,
 }
 
 /**
- * clutter_x11_remove_filter:
+ * clutter_x11_remove_filter: (skip)
  * @func: a filter function
  * @data: user data to be passed to the filter function, or %NULL
  *
@@ -815,43 +1013,6 @@ clutter_x11_remove_filter (ClutterX11FilterFunc func,
     }
 }
 
-void
-_clutter_x11_select_events (Window xwin)
-{
-#ifdef HAVE_XINPUT
-  ClutterDeviceManager *manager;
-  const GSList *l;
-
-  if (G_UNLIKELY (backend_singleton == NULL))
-    {
-      g_critical ("X11 backend has not been initialised");
-
-      return;
-    }
-
-  manager = clutter_device_manager_get_default ();
-
-  for (l = clutter_device_manager_peek_devices (manager);
-       l != NULL;
-       l = l->next)
-  {
-    ClutterInputDevice *device = l->data;
-
-    _clutter_input_device_x11_select_events (device, backend_singleton, xwin);
-  }
-#endif /* HAVE_XINPUT */
-}
-
-ClutterInputDevice *
-_clutter_x11_get_device_for_xid (XID id)
-{
-  ClutterDeviceManager *manager;
-
-  manager = clutter_device_manager_get_default ();
-
-  return clutter_device_manager_get_device (manager, (gint) id);
-}
-
 /**
  * clutter_x11_get_input_devices:
  *
@@ -888,14 +1049,11 @@ clutter_x11_get_input_devices (void)
 gboolean
 clutter_x11_has_xinput (void)
 {
-#ifdef HAVE_XINPUT
-  if (backend_singleton == NULL)
-    {
-      g_critical ("X11 backend has not been initialised");
-      return FALSE;
-    }
+#if defined(HAVE_XINPUT) || defined(HAVE_XINPUT_2)
+  if (backend_singleton != NULL)
+    return backend_singleton->has_xinput;
 
-  return backend_singleton->have_xinput;
+  return FALSE;
 #else
   return FALSE;
 #endif
@@ -920,7 +1078,7 @@ clutter_x11_has_composite_extension (void)
   if (done_check)
     return have_composite;
 
-  if (!backend_singleton)
+  if (!_clutter_context_is_initialized ())
     {
       g_critical ("X11 backend has not been initialised");
       return FALSE;
@@ -997,7 +1155,7 @@ clutter_x11_get_use_argb_visual (void)
 }
 
 XVisualInfo *
-clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11)
+_clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11)
 {
   ClutterBackendX11Class *klass;
 
@@ -1011,7 +1169,7 @@ clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11)
 }
 
 /**
- * clutter_x11_get_visual_info:
+ * clutter_x11_get_visual_info: (skip)
  *
  * Retrieves the <structname>XVisualInfo</structname> used by the Clutter X11
  * backend.
@@ -1029,5 +1187,56 @@ clutter_x11_get_visual_info (void)
 
   backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
 
-  return clutter_backend_x11_get_visual_info (backend_x11);
+  return _clutter_backend_x11_get_visual_info (backend_x11);
+}
+
+gboolean
+_clutter_x11_input_device_translate_screen_coord (ClutterInputDevice *device,
+                                                  gint                stage_root_x,
+                                                  gint                stage_root_y,
+                                                  guint               index_,
+                                                  gdouble             value,
+                                                  gdouble            *axis_value)
+{
+  ClutterAxisInfo *info;
+  ClutterBackendX11 *backend_x11;
+  gdouble width, scale, offset;
+  
+  backend_x11 = CLUTTER_BACKEND_X11 (device->backend);
+
+  if (device->axes == NULL || index_ >= device->axes->len)
+    return FALSE;
+
+  info = &g_array_index (device->axes, ClutterAxisInfo, index_);
+  if (info->axis != CLUTTER_INPUT_AXIS_X ||
+      info->axis != CLUTTER_INPUT_AXIS_Y)
+    {
+      return FALSE;
+    }
+
+  width = info->max_value - info->min_value;
+
+  if (info->axis == CLUTTER_INPUT_AXIS_X)
+    {
+      if (width > 0)
+        scale = backend_x11->xscreen_width / width;
+      else
+        scale = 1;
+
+      offset = - stage_root_x;
+    }
+  else
+    {
+      if (width > 0)
+        scale = backend_x11->xscreen_height / width;
+      else
+        scale = 1;
+
+      offset = - stage_root_y;
+    }
+
+  if (axis_value)
+    *axis_value = offset + scale * (value - info->min_value);
+
+  return TRUE;
 }
index 1947803..0c4a5d8 100644 (file)
 #include <X11/Xatom.h>
 
 #include "clutter-x11.h"
+
 #include "clutter-backend-private.h"
 #include "clutter-keymap-x11.h"
+
 #include "xsettings/xsettings-client.h"
 
 G_BEGIN_DECLS
 
-#define CLUTTER_TYPE_BACKEND_X11                (clutter_backend_x11_get_type ())
+#define CLUTTER_TYPE_BACKEND_X11                (_clutter_backend_x11_get_type ())
 #define CLUTTER_BACKEND_X11(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_X11, ClutterBackendX11))
 #define CLUTTER_IS_BACKEND_X11(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_X11))
 #define CLUTTER_BACKEND_X11_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_X11, ClutterBackendX11Class))
@@ -43,23 +45,39 @@ G_BEGIN_DECLS
 
 typedef struct _ClutterBackendX11       ClutterBackendX11;
 typedef struct _ClutterBackendX11Class  ClutterBackendX11Class;
+typedef struct _ClutterEventX11         ClutterEventX11;
+typedef struct _ClutterX11EventFilter   ClutterX11EventFilter;
 
-typedef struct _ClutterX11EventFilter
+struct _ClutterX11EventFilter
 {
   ClutterX11FilterFunc func;
   gpointer             data;
 
-} ClutterX11EventFilter;
+};
+
+struct _ClutterEventX11
+{
+  /* additional fields for Key events */
+  gint key_group;
+
+  guint key_is_modifier : 1;
+  guint num_lock_set    : 1;
+  guint caps_lock_set   : 1;
+};
 
 struct _ClutterBackendX11
 {
   ClutterBackend parent_instance;
 
   Display *xdpy;
-  Window   xwin_root;
+  gchar   *display_name;
+
   Screen  *xscreen;
   int      xscreen_num;
-  gchar   *display_name;
+  int      xscreen_width;
+  int      xscreen_height;
+
+  Window   xwin_root;
 
   /* event source */
   GSource *event_source;
@@ -78,21 +96,18 @@ struct _ClutterBackendX11
   Atom atom_NET_WM_NAME;
   Atom atom_UTF8_STRING;
 
-  int xi_event_base;
-  int event_types[CLUTTER_X11_XINPUT_LAST_EVENT];
-  gboolean have_xinput;
-
   Time last_event_time;
 
   ClutterDeviceManager *device_manager;
+  gboolean has_xinput;
 
   XSettingsClient *xsettings;
   Window xsettings_xwin;
 
   ClutterKeymapX11 *keymap;
-  int xkb_event_base;
   gboolean use_xkb;
   gboolean have_xkb_autorepeat;
+  guint keymap_serial;
 };
 
 struct _ClutterBackendX11Class
@@ -105,51 +120,16 @@ struct _ClutterBackendX11Class
    * may need to be handled differently for different backends.
    */
   XVisualInfo *(* get_visual_info) (ClutterBackendX11 *backend);
-
-  /*
-   * Different X11 backends may care about some special events so they all have
-   * a chance to intercept them.
-   */
-  gboolean (*handle_event) (ClutterBackendX11 *backend,
-                            XEvent            *xevent);
 };
 
-/* platform-specific event data */
-typedef struct _ClutterEventX11 ClutterEventX11;
-
 void   _clutter_backend_x11_events_init (ClutterBackend *backend);
 void   _clutter_backend_x11_events_uninit (ClutterBackend *backend);
 
-GType clutter_backend_x11_get_type (void) G_GNUC_CONST;
+GType _clutter_backend_x11_get_type (void) G_GNUC_CONST;
 
 /* Private to glx/eglx backends */
-gboolean
-clutter_backend_x11_pre_parse (ClutterBackend  *backend,
-                               GError         **error);
-
-gboolean
-clutter_backend_x11_post_parse (ClutterBackend  *backend,
-                                GError         **error);
-
-gboolean
-clutter_backend_x11_init_stage (ClutterBackend  *backend,
-                                GError         **error);
-
-ClutterActor *
-clutter_backend_x11_get_stage (ClutterBackend *backend);
-
-void
-clutter_backend_x11_add_options (ClutterBackend *backend,
-                                 GOptionGroup   *group);
-
-ClutterFeatureFlags
-clutter_backend_x11_get_features (ClutterBackend *backend);
-
 XVisualInfo *
-clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11);
-
-ClutterInputDevice *
-_clutter_x11_get_device_for_xid (XID id);
+_clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11);
 
 void
 _clutter_x11_select_events (Window xwin);
@@ -163,6 +143,14 @@ _clutter_event_x11_copy (ClutterEventX11 *event_x11);
 void
 _clutter_event_x11_free (ClutterEventX11 *event_x11);
 
+gboolean
+_clutter_x11_input_device_translate_screen_coord (ClutterInputDevice *device,
+                                                  gint                stage_root_x,
+                                                  gint                stage_root_y,
+                                                  guint               index_,
+                                                  gdouble             value,
+                                                  gdouble            *axis_value);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_BACKEND_X11_H__ */
diff --git a/clutter/x11/clutter-device-manager-core-x11.c b/clutter/x11/clutter-device-manager-core-x11.c
new file mode 100644 (file)
index 0000000..2b55f42
--- /dev/null
@@ -0,0 +1,759 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright © 2009, 2010, 2011  Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+#include "config.h"
+
+#include "clutter-device-manager-core-x11.h"
+
+#include "clutter-backend-x11.h"
+#include "clutter-input-device-core-x11.h"
+#include "clutter-stage-x11.h"
+
+#include "clutter-backend.h"
+#include "clutter-debug.h"
+#include "clutter-device-manager-private.h"
+#include "clutter-event-translator.h"
+#include "clutter-stage-private.h"
+#include "clutter-private.h"
+
+#ifdef HAVE_XINPUT
+#include <X11/extensions/XInput.h>
+
+/* old versions of XI.h don't define these */
+#ifndef IsXExtensionKeyboard
+#define IsXExtensionKeyboard 3
+#define IsXExtensionPointer  4
+#endif
+
+#endif /* HAVE_XINPUT */
+
+enum
+{
+  PROP_0,
+
+  PROP_EVENT_BASE,
+
+  PROP_LAST
+};
+
+static GParamSpec *obj_props[PROP_LAST] = { NULL, };
+
+static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface);
+
+#define clutter_device_manager_x11_get_type     _clutter_device_manager_x11_get_type
+
+G_DEFINE_TYPE_WITH_CODE (ClutterDeviceManagerX11,
+                         clutter_device_manager_x11,
+                         CLUTTER_TYPE_DEVICE_MANAGER,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR,
+                                                clutter_event_translator_iface_init));
+
+#ifdef HAVE_XINPUT
+static void
+translate_class_info (ClutterInputDevice *device,
+                      XDeviceInfo        *info)
+{
+  XAnyClassPtr any_class;
+  gint i;
+
+  any_class = info->inputclassinfo;
+
+  for (i = 0; i < info->num_classes; i++)
+    {
+      switch (any_class->class)
+        {
+        case ButtonClass:
+          break;
+
+        case KeyClass:
+          {
+            XKeyInfo *xk_info = (XKeyInfo *) any_class;
+            ClutterInputDeviceX11 *device_x11;
+            guint n_keys;
+
+            device_x11 = CLUTTER_INPUT_DEVICE_X11 (device);
+
+            n_keys = xk_info->max_keycode - xk_info->min_keycode + 1;
+
+            _clutter_input_device_set_n_keys (device, n_keys);
+            device_x11->min_keycode = xk_info->min_keycode;
+            device_x11->max_keycode = xk_info->max_keycode;
+          }
+          break;
+
+        case ValuatorClass:
+          {
+            XValuatorInfo *xv_info = (XValuatorInfo *) any_class;
+            gint j;
+
+            for (j = 0; j < xv_info->num_axes; j++)
+              {
+                ClutterInputAxis axis;
+
+                switch (j)
+                  {
+                  case 0:
+                    axis = CLUTTER_INPUT_AXIS_X;
+                    break;
+
+                  case 1:
+                    axis = CLUTTER_INPUT_AXIS_Y;
+                    break;
+
+                  case 2:
+                    axis = CLUTTER_INPUT_AXIS_PRESSURE;
+                    break;
+
+                  case 3:
+                    axis = CLUTTER_INPUT_AXIS_XTILT;
+                    break;
+
+                  case 4:
+                    axis = CLUTTER_INPUT_AXIS_YTILT;
+                    break;
+
+                  case 5:
+                    axis = CLUTTER_INPUT_AXIS_WHEEL;
+                    break;
+
+                  default:
+                    axis = CLUTTER_INPUT_AXIS_IGNORE;
+                    break;
+                  }
+
+                _clutter_input_device_add_axis (device, axis,
+                                                xv_info->axes[j].min_value,
+                                                xv_info->axes[j].max_value,
+                                                xv_info->axes[j].resolution);
+              }
+          }
+          break;
+        }
+
+      any_class = (XAnyClassPtr) (((char *) any_class) + any_class->length);
+    }
+}
+
+static ClutterInputDevice *
+create_device (ClutterDeviceManagerX11 *manager_x11,
+               ClutterBackendX11       *backend_x11,
+               XDeviceInfo             *info)
+{
+  ClutterInputDeviceType source;
+  ClutterInputDevice *retval;
+
+  if (info->use != IsXExtensionPointer &&
+      info->use != IsXExtensionKeyboard)
+    return NULL;
+
+  if (info->use == IsXExtensionKeyboard)
+    source = CLUTTER_KEYBOARD_DEVICE;
+  else
+    {
+      gchar *name;
+
+      name = g_ascii_strdown (info->name, -1);
+
+      if (strstr (name, "eraser") != NULL)
+        source = CLUTTER_ERASER_DEVICE;
+      else if (strstr (name, "cursor") != NULL)
+        source = CLUTTER_CURSOR_DEVICE;
+      else if (strstr (name, "wacom") != NULL || strstr (name, "pen") != NULL)
+        source = CLUTTER_PEN_DEVICE;
+      else
+        source = CLUTTER_POINTER_DEVICE;
+
+      g_free (name);
+    }
+
+  retval = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_X11,
+                         "name", info->name,
+                         "id", info->id,
+                         "has-cursor", FALSE,
+                         "device-manager", manager_x11,
+                         "device-type", source,
+                         "device-mode", CLUTTER_INPUT_MODE_FLOATING,
+                         "backend", backend_x11,
+                         "enabled", FALSE,
+                         NULL);
+  translate_class_info (retval, info);
+
+  CLUTTER_NOTE (BACKEND,
+                "XI Device '%s' (id: %d) created",
+                info->name,
+                (int) info->id);
+
+  return retval;
+}
+#endif /* HAVE_XINPUT */
+
+static inline void
+translate_key_event (ClutterBackendX11       *backend_x11,
+                     ClutterDeviceManagerX11 *manager_x11,
+                     ClutterEvent            *event,
+                     XEvent                  *xevent)
+{
+  ClutterEventX11 *event_x11;
+  char buffer[256 + 1];
+  int n;
+
+  event->key.type = xevent->xany.type == KeyPress ? CLUTTER_KEY_PRESS
+                                                  : CLUTTER_KEY_RELEASE;
+  event->key.time = xevent->xkey.time;
+
+  clutter_event_set_device (event, manager_x11->core_keyboard);
+
+  /* KeyEvents have platform specific data associated to them */
+  event_x11 = _clutter_event_x11_new ();
+  _clutter_event_set_platform_data (event, event_x11);
+
+  event->key.modifier_state = (ClutterModifierType) xevent->xkey.state;
+  event->key.hardware_keycode = xevent->xkey.keycode;
+
+  /* keyval is the key ignoring all modifiers ('1' vs. '!') */
+  event->key.keyval =
+    _clutter_keymap_x11_translate_key_state (backend_x11->keymap,
+                                             event->key.hardware_keycode,
+                                             event->key.modifier_state,
+                                             NULL);
+
+  event_x11->key_group =
+    _clutter_keymap_x11_get_key_group (backend_x11->keymap,
+                                       event->key.modifier_state);
+  event_x11->key_is_modifier =
+    _clutter_keymap_x11_get_is_modifier (backend_x11->keymap,
+                                         event->key.hardware_keycode);
+  event_x11->num_lock_set =
+    _clutter_keymap_x11_get_num_lock_state (backend_x11->keymap);
+  event_x11->caps_lock_set =
+    _clutter_keymap_x11_get_caps_lock_state (backend_x11->keymap);
+
+  /* unicode_value is the printable representation */
+  n = XLookupString (&xevent->xkey, buffer, sizeof (buffer) - 1, NULL, NULL);
+
+  if (n != NoSymbol)
+    {
+      event->key.unicode_value = g_utf8_get_char_validated (buffer, n);
+      if ((event->key.unicode_value != -1) &&
+          (event->key.unicode_value != -2))
+        goto out;
+    }
+  else
+    event->key.unicode_value = (gunichar)'\0';
+
+out:
+  CLUTTER_NOTE (EVENT,
+                "%s: win:0x%x, key: %12s (%d)",
+                event->any.type == CLUTTER_KEY_PRESS
+                  ? "key press  "
+                  : "key release",
+                (unsigned int) xevent->xkey.window,
+                event->key.keyval ? buffer : "(none)",
+                event->key.keyval);
+  return;
+}
+
+#ifdef HAVE_XINPUT
+static ClutterInputDevice *
+get_device_from_event (ClutterDeviceManagerX11 *manager_x11,
+                       XEvent                  *xevent)
+{
+  guint32 device_id;
+
+  device_id = ((XDeviceButtonEvent *) xevent)->deviceid;
+
+  return g_hash_table_lookup (manager_x11->devices_by_id,
+                              GINT_TO_POINTER (device_id));
+}
+#endif /* HAVE_XINPUT */
+
+static ClutterTranslateReturn
+clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator,
+                                            gpointer                native,
+                                            ClutterEvent           *event)
+{
+  ClutterDeviceManagerX11 *manager_x11;
+  ClutterBackendX11 *backend_x11;
+  ClutterInputDevice *device;
+  ClutterStageX11 *stage_x11;
+  ClutterTranslateReturn res;
+  ClutterStage *stage;
+  XEvent *xevent;
+
+  manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (translator);
+  backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
+  device = NULL;
+
+  xevent = native;
+
+  stage = clutter_x11_get_stage_from_window (xevent->xany.window);
+  if (stage == NULL)
+    return CLUTTER_TRANSLATE_CONTINUE;
+
+  if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
+    return CLUTTER_TRANSLATE_CONTINUE;
+
+  stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage));
+
+  event->any.stage = stage;
+
+  res = CLUTTER_TRANSLATE_CONTINUE;
+
+#ifdef HAVE_XINPUT
+  device = get_device_from_event (manager_x11, xevent);
+  if (device != NULL)
+    {
+      ClutterInputDeviceX11 *device_x11;
+      gboolean retval;
+
+      device_x11 = CLUTTER_INPUT_DEVICE_X11 (device);
+      retval = _clutter_input_device_x11_translate_xi_event (device_x11,
+                                                             stage_x11,
+                                                             xevent,
+                                                             event);
+      if (retval)
+        return CLUTTER_TRANSLATE_QUEUE;
+    }
+#endif /* HAVE_XINPUT */
+
+  switch (xevent->type)
+    {
+    case KeyPress:
+      translate_key_event (backend_x11, manager_x11, event, xevent);
+      _clutter_stage_x11_set_user_time (stage_x11, xevent->xkey.time);
+      res = CLUTTER_TRANSLATE_QUEUE;
+      break;
+
+    case KeyRelease:
+      /* old-style X11 terminals require that even modern X11 send
+       * KeyPress/KeyRelease pairs when auto-repeating. for this
+       * reason modern(-ish) API like XKB has a way to detect
+       * auto-repeat and do a single KeyRelease at the end of a
+       * KeyPress sequence.
+       *
+       * this check emulates XKB's detectable auto-repeat; we peek
+       * the next event and check if it's a KeyPress for the same key
+       * and timestamp - and then ignore it if it matches the
+       * KeyRelease
+       *
+       * if we have XKB, and autorepeat is enabled, then this becomes
+       * a no-op
+       */
+      if (!backend_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
+        {
+          XEvent next_event;
+
+          XPeekEvent (xevent->xkey.display, &next_event);
+
+          if (next_event.type == KeyPress &&
+              next_event.xkey.keycode == xevent->xkey.keycode &&
+              next_event.xkey.time == xevent->xkey.time)
+            {
+              res = CLUTTER_TRANSLATE_REMOVE;
+              break;
+            }
+        }
+
+      translate_key_event (backend_x11, manager_x11, event, xevent);
+      res = CLUTTER_TRANSLATE_QUEUE;
+      break;
+
+    case ButtonPress:
+      CLUTTER_NOTE (EVENT,
+                    "button press: win: 0x%x, coords: %d, %d, button: %d",
+                    (unsigned int) stage_x11->xwin,
+                    xevent->xbutton.x,
+                    xevent->xbutton.y,
+                    xevent->xbutton.button);
+
+      switch (xevent->xbutton.button)
+        {
+        case 4: /* up */
+        case 5: /* down */
+        case 6: /* left */
+        case 7: /* right */
+          event->scroll.type = CLUTTER_SCROLL;
+
+          if (xevent->xbutton.button == 4)
+            event->scroll.direction = CLUTTER_SCROLL_UP;
+          else if (xevent->xbutton.button == 5)
+            event->scroll.direction = CLUTTER_SCROLL_DOWN;
+          else if (xevent->xbutton.button == 6)
+            event->scroll.direction = CLUTTER_SCROLL_LEFT;
+          else
+            event->scroll.direction = CLUTTER_SCROLL_RIGHT;
+
+          event->scroll.time = xevent->xbutton.time;
+          event->scroll.x = xevent->xbutton.x;
+          event->scroll.y = xevent->xbutton.y;
+          event->scroll.modifier_state = xevent->xbutton.state;
+          event->scroll.axes = NULL;
+          break;
+
+        default:
+          event->button.type = event->type = CLUTTER_BUTTON_PRESS;
+          event->button.time = xevent->xbutton.time;
+          event->button.x = xevent->xbutton.x;
+          event->button.y = xevent->xbutton.y;
+          event->button.modifier_state = xevent->xbutton.state;
+          event->button.button = xevent->xbutton.button;
+          event->button.axes = NULL;
+          break;
+        }
+
+      clutter_event_set_device (event, manager_x11->core_pointer);
+
+      _clutter_stage_x11_set_user_time (stage_x11, xevent->xbutton.time);
+      res = CLUTTER_TRANSLATE_QUEUE;
+      break;
+
+    case ButtonRelease:
+      CLUTTER_NOTE (EVENT,
+                    "button press: win: 0x%x, coords: %d, %d, button: %d",
+                    (unsigned int) stage_x11->xwin,
+                    xevent->xbutton.x,
+                    xevent->xbutton.y,
+                    xevent->xbutton.button);
+
+      /* scroll events don't have a corresponding release */
+      if (xevent->xbutton.button == 4 ||
+          xevent->xbutton.button == 5 ||
+          xevent->xbutton.button == 6 ||
+          xevent->xbutton.button == 7)
+        {
+          res = CLUTTER_TRANSLATE_REMOVE;
+          break;
+        }
+
+      event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
+      event->button.time = xevent->xbutton.time;
+      event->button.x = xevent->xbutton.x;
+      event->button.y = xevent->xbutton.y;
+      event->button.modifier_state = xevent->xbutton.state;
+      event->button.button = xevent->xbutton.button;
+      event->button.axes = NULL;
+      clutter_event_set_device (event, manager_x11->core_pointer);
+      res = CLUTTER_TRANSLATE_QUEUE;
+      break;
+
+    case MotionNotify:
+      CLUTTER_NOTE (EVENT,
+                    "motion: win: 0x%x, coords: %d, %d",
+                    (unsigned int) stage_x11->xwin,
+                    xevent->xmotion.x,
+                    xevent->xmotion.y);
+
+      event->motion.type = event->type = CLUTTER_MOTION;
+      event->motion.time = xevent->xmotion.time;
+      event->motion.x = xevent->xmotion.x;
+      event->motion.y = xevent->xmotion.y;
+      event->motion.modifier_state = xevent->xmotion.state;
+      event->motion.axes = NULL;
+      clutter_event_set_device (event, manager_x11->core_pointer);
+      res = CLUTTER_TRANSLATE_QUEUE;
+      break;
+
+    case EnterNotify:
+      CLUTTER_NOTE (EVENT, "Entering the stage (time:%u)",
+                    (unsigned int) xevent->xcrossing.time);
+
+      event->crossing.type = CLUTTER_ENTER;
+      event->crossing.time = xevent->xcrossing.time;
+      event->crossing.x = xevent->xcrossing.x;
+      event->crossing.y = xevent->xcrossing.y;
+      event->crossing.source = CLUTTER_ACTOR (stage);
+      event->crossing.related = NULL;
+      clutter_event_set_device (event, manager_x11->core_pointer);
+
+      _clutter_stage_add_device (stage, manager_x11->core_pointer);
+
+      res = CLUTTER_TRANSLATE_QUEUE;
+      break;
+
+    case LeaveNotify:
+      if (manager_x11->core_pointer->stage == NULL)
+        {
+          CLUTTER_NOTE (EVENT, "Discarding LeaveNotify for "
+                               "ButtonRelease event off-stage");
+          res = CLUTTER_TRANSLATE_REMOVE;
+          break;
+        }
+
+      /* we know that we are leaving the stage here */
+      CLUTTER_NOTE (EVENT, "Leaving the stage (time:%u)",
+                    (unsigned int) xevent->xcrossing.time);
+
+      event->crossing.type = CLUTTER_LEAVE;
+      event->crossing.time = xevent->xcrossing.time;
+      event->crossing.x = xevent->xcrossing.x;
+      event->crossing.y = xevent->xcrossing.y;
+      event->crossing.source = CLUTTER_ACTOR (stage);
+      event->crossing.related = NULL;
+      clutter_event_set_device (event, manager_x11->core_pointer);
+
+      _clutter_stage_remove_device (stage, manager_x11->core_pointer);
+
+      res = CLUTTER_TRANSLATE_QUEUE;
+      break;
+
+    default:
+      break;
+    }
+
+  return res;
+}
+
+static void
+clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface)
+{
+  iface->translate_event = clutter_device_manager_x11_translate_event;
+}
+
+static void
+clutter_device_manager_x11_constructed (GObject *gobject)
+{
+  ClutterDeviceManagerX11 *manager_x11;
+  ClutterBackendX11 *backend_x11;
+  ClutterDeviceManager *manager;
+#ifdef HAVE_XINPUT
+  XDeviceInfo *x_devices = NULL;
+  int i, n_devices;
+#endif /* HAVE_XINPUT */
+
+  manager = CLUTTER_DEVICE_MANAGER (gobject);
+  manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (gobject);
+
+  g_object_get (gobject, "backend", &backend_x11, NULL);
+  g_assert (backend_x11 != NULL);
+
+#ifdef HAVE_XINPUT
+  x_devices = XListInputDevices (backend_x11->xdpy, &n_devices);
+  if (n_devices == 0)
+    {
+      CLUTTER_NOTE (BACKEND, "No XInput devices found");
+      goto default_device;
+    }
+
+  for (i = 0; i < n_devices; i++)
+    {
+      XDeviceInfo *info = x_devices + i;
+      ClutterInputDevice *device;
+
+      CLUTTER_NOTE (BACKEND,
+                    "Considering device %li with type %d, %d of %d",
+                    info->id,
+                    info->use,
+                    i, n_devices);
+
+      device = create_device (manager_x11, backend_x11, info);
+      if (device != NULL)
+        _clutter_device_manager_add_device (manager, device);
+    }
+
+  XFreeDeviceList (x_devices);
+
+default_device:
+#endif /* HAVE_XINPUT */
+
+  /* fallback code in case:
+   *
+   *  - we do not have XInput support compiled in
+   *  - we do not have the XInput extension
+   *
+   * we register two default devices, one for the pointer
+   * and one for the keyboard. this block must also be
+   * executed for the XInput support because XI does not
+   * cover core devices
+   */
+  manager_x11->core_pointer =
+    g_object_new (CLUTTER_TYPE_INPUT_DEVICE,
+                  "name", "Core Pointer",
+                  "has-cursor", TRUE,
+                  "device-type", CLUTTER_POINTER_DEVICE,
+                  "device-manager", manager_x11,
+                  "device-mode", CLUTTER_INPUT_MODE_MASTER,
+                  "backend", backend_x11,
+                  "enabled", TRUE,
+                  NULL);
+  CLUTTER_NOTE (BACKEND, "Added core pointer device");
+
+  manager_x11->core_keyboard =
+    g_object_new (CLUTTER_TYPE_INPUT_DEVICE,
+                  "name", "Core Keyboard",
+                  "has-cursor", FALSE,
+                  "device-type", CLUTTER_KEYBOARD_DEVICE,
+                  "device-manager", manager_x11,
+                  "device-mode", CLUTTER_INPUT_MODE_MASTER,
+                  "backend", backend_x11,
+                  "enabled", TRUE,
+                  NULL);
+  CLUTTER_NOTE (BACKEND, "Added core keyboard device");
+
+  /* associate core devices */
+  _clutter_input_device_set_associated_device (manager_x11->core_pointer,
+                                               manager_x11->core_keyboard);
+  _clutter_input_device_set_associated_device (manager_x11->core_keyboard,
+                                               manager_x11->core_pointer);
+
+  if (G_OBJECT_CLASS (clutter_device_manager_x11_parent_class)->constructed)
+    G_OBJECT_CLASS (clutter_device_manager_x11_parent_class)->constructed (gobject);
+}
+
+static void
+clutter_device_manager_x11_add_device (ClutterDeviceManager *manager,
+                                       ClutterInputDevice   *device)
+{
+  ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
+
+  manager_x11->devices = g_slist_prepend (manager_x11->devices, device);
+  g_hash_table_replace (manager_x11->devices_by_id,
+                        GINT_TO_POINTER (device->id),
+                        device);
+
+  /* blow the cache */
+  g_slist_free (manager_x11->all_devices);
+  manager_x11->all_devices = NULL;
+}
+
+static void
+clutter_device_manager_x11_remove_device (ClutterDeviceManager *manager,
+                                          ClutterInputDevice   *device)
+{
+  ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
+
+  g_hash_table_remove (manager_x11->devices_by_id,
+                       GINT_TO_POINTER (device->id));
+  manager_x11->devices = g_slist_remove (manager_x11->devices, device);
+
+  /* blow the cache */
+  g_slist_free (manager_x11->all_devices);
+  manager_x11->all_devices = NULL;
+}
+
+static const GSList *
+clutter_device_manager_x11_get_devices (ClutterDeviceManager *manager)
+{
+  ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
+
+  /* cache the devices list so that we can keep the core pointer
+   * and keyboard outside of the ManagerX11:devices list
+   */
+  if (manager_x11->all_devices == NULL)
+    {
+      GSList *all_devices = manager_x11->devices;
+
+      all_devices = g_slist_prepend (all_devices, manager_x11->core_keyboard);
+      all_devices = g_slist_prepend (all_devices, manager_x11->core_pointer);
+
+      manager_x11->all_devices = all_devices;
+    }
+    
+  return CLUTTER_DEVICE_MANAGER_X11 (manager)->all_devices;
+}
+
+static ClutterInputDevice *
+clutter_device_manager_x11_get_core_device (ClutterDeviceManager   *manager,
+                                            ClutterInputDeviceType  type)
+{
+  ClutterDeviceManagerX11 *manager_x11;
+
+  manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
+
+  switch (type)
+    {
+    case CLUTTER_POINTER_DEVICE:
+      return manager_x11->core_pointer;
+
+    case CLUTTER_KEYBOARD_DEVICE:
+      return manager_x11->core_keyboard;
+
+    default:
+      return NULL;
+    }
+
+  return NULL;
+}
+
+static ClutterInputDevice *
+clutter_device_manager_x11_get_device (ClutterDeviceManager *manager,
+                                       gint                  id)
+{
+  ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
+
+  return g_hash_table_lookup (manager_x11->devices_by_id,
+                              GINT_TO_POINTER (id));
+}
+
+static void
+clutter_device_manager_x11_set_property (GObject      *gobject,
+                                         guint         prop_id,
+                                         const GValue *value,
+                                         GParamSpec   *pspec)
+{
+  ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_EVENT_BASE:
+      manager_x11->xi_event_base = g_value_get_int (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_device_manager_x11_class_init (ClutterDeviceManagerX11Class *klass)
+{
+  ClutterDeviceManagerClass *manager_class;
+  GObjectClass *gobject_class;
+
+  obj_props[PROP_EVENT_BASE] =
+    g_param_spec_int ("event-base",
+                      "Event Base",
+                      "The first XI event",
+                      -1, G_MAXINT,
+                      -1,
+                      CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->constructed = clutter_device_manager_x11_constructed;
+  gobject_class->set_property = clutter_device_manager_x11_set_property;
+
+  g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
+  
+  manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass);
+  manager_class->add_device = clutter_device_manager_x11_add_device;
+  manager_class->remove_device = clutter_device_manager_x11_remove_device;
+  manager_class->get_devices = clutter_device_manager_x11_get_devices;
+  manager_class->get_core_device = clutter_device_manager_x11_get_core_device;
+  manager_class->get_device = clutter_device_manager_x11_get_device;
+}
+
+static void
+clutter_device_manager_x11_init (ClutterDeviceManagerX11 *self)
+{
+  self->devices_by_id = g_hash_table_new (NULL, NULL);
+}
similarity index 89%
rename from clutter/x11/clutter-device-manager-x11.h
rename to clutter/x11/clutter-device-manager-core-x11.h
index f1fe819..f0f28bc 100644 (file)
@@ -3,7 +3,7 @@
  *
  * An OpenGL based 'interactive canvas' library.
  *
- * Copyright (C) 2009  Intel Corp.
+ * Copyright © 2009, 2010, 2011  Intel Corp.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -28,7 +28,7 @@
 
 G_BEGIN_DECLS
 
-#define CLUTTER_TYPE_DEVICE_MANAGER_X11            (clutter_device_manager_x11_get_type ())
+#define CLUTTER_TYPE_DEVICE_MANAGER_X11            (_clutter_device_manager_x11_get_type ())
 #define CLUTTER_DEVICE_MANAGER_X11(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER_X11, ClutterDeviceManagerX11))
 #define CLUTTER_IS_DEVICE_MANAGER_X11(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER_X11))
 #define CLUTTER_DEVICE_MANAGER_X11_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER_X11, ClutterDeviceManagerX11Class))
@@ -42,6 +42,8 @@ struct _ClutterDeviceManagerX11
 {
   ClutterDeviceManager parent_instance;
 
+  GHashTable *devices_by_id;
+
   /* the list of transient devices */
   GSList *devices;
 
@@ -53,7 +55,7 @@ struct _ClutterDeviceManagerX11
   ClutterInputDevice *core_pointer;
   ClutterInputDevice *core_keyboard;
 
-  guint use_xinput_1 : 1;
+  int xi_event_base;
 };
 
 struct _ClutterDeviceManagerX11Class
@@ -61,7 +63,7 @@ struct _ClutterDeviceManagerX11Class
   ClutterDeviceManagerClass parent_class;
 };
 
-GType clutter_device_manager_x11_get_type (void) G_GNUC_CONST;
+GType _clutter_device_manager_x11_get_type (void) G_GNUC_CONST;
 
 G_END_DECLS
 
diff --git a/clutter/x11/clutter-device-manager-x11.c b/clutter/x11/clutter-device-manager-x11.c
deleted file mode 100644 (file)
index 5c5b2b5..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Clutter.
- *
- * An OpenGL based 'interactive canvas' library.
- *
- * Copyright (C) 2009  Intel Corp.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- *
- * Author: Emmanuele Bassi <ebassi@linux.intel.com>
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "clutter-backend-x11.h"
-#include "clutter-device-manager-x11.h"
-#include "clutter-input-device-x11.h"
-#include "clutter-stage-x11.h"
-
-#include "clutter-backend.h"
-#include "clutter-debug.h"
-#include "clutter-device-manager-private.h"
-#include "clutter-private.h"
-
-#ifdef HAVE_XINPUT
-#include <X11/extensions/XInput.h>
-#endif
-
-enum
-{
-  PROP_0,
-
-  PROP_USE_XINPUT_1,
-
-  PROP_LAST
-};
-
-static GParamSpec *obj_props[PROP_LAST];
-
-G_DEFINE_TYPE (ClutterDeviceManagerX11,
-               clutter_device_manager_x11,
-               CLUTTER_TYPE_DEVICE_MANAGER);
-
-static void
-clutter_device_manager_x11_constructed (GObject *gobject)
-{
-  ClutterDeviceManagerX11 *manager_x11;
-  ClutterBackendX11 *backend_x11;
-  ClutterDeviceManager *manager;
-  ClutterInputDevice *device;
-#ifdef HAVE_XINPUT
-  XDeviceInfo *x_devices = NULL;
-  int res, opcode, event, error;
-  int i, n_devices;
-#endif /* HAVE_XINPUT */
-
-  manager = CLUTTER_DEVICE_MANAGER (gobject);
-  manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (gobject);
-  if (!manager_x11->use_xinput_1)
-    {
-      CLUTTER_NOTE (BACKEND, "XInput support not enabled");
-      goto default_device;
-    }
-
-  g_object_get (gobject, "backend", &backend_x11, NULL);
-  g_assert (backend_x11 != NULL);
-
-#ifdef HAVE_XINPUT
-  res = XQueryExtension (backend_x11->xdpy, "XInputExtension",
-                         &opcode,
-                         &event,
-                         &error);
-  if (!res)
-    {
-      CLUTTER_NOTE (BACKEND, "No XInput extension available");
-      goto default_device;
-    }
-
-  backend_x11->xi_event_base = event;
-
-  x_devices = XListInputDevices (backend_x11->xdpy, &n_devices);
-  if (n_devices == 0)
-    {
-      CLUTTER_NOTE (BACKEND, "No XInput devices found");
-      goto default_device;
-    }
-
-  for (i = 0; i < n_devices; i++)
-    {
-      XDeviceInfo *info = x_devices + i;
-
-      CLUTTER_NOTE (BACKEND,
-                    "Considering device %li with type %d, %d of %d",
-                    info->id,
-                    info->use,
-                    i, n_devices);
-
-      /* we only want 'raw' devices, not virtual ones */
-      if (info->use == IsXExtensionPointer ||
-       /* info->use == IsXExtensionKeyboard || XInput1 is broken */
-          info->use == IsXExtensionDevice)
-        {
-          ClutterInputDeviceType device_type;
-          gint n_events = 0;
-
-          switch (info->use)
-            {
-            case IsXExtensionPointer:
-              device_type = CLUTTER_POINTER_DEVICE;
-              break;
-
-            /* XInput1 is broken for keyboards */
-            case IsXExtensionKeyboard:
-              device_type = CLUTTER_KEYBOARD_DEVICE;
-              break;
-
-            case IsXExtensionDevice:
-            default:
-              device_type = CLUTTER_EXTENSION_DEVICE;
-              break;
-            }
-
-          device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_X11,
-                                 "id", info->id,
-                                 "device-type", device_type,
-                                 "name", info->name,
-                                 NULL);
-          n_events = _clutter_input_device_x11_construct (device, backend_x11);
-
-          _clutter_device_manager_add_device (manager, device);
-
-          if (info->use == IsXExtensionPointer && n_events > 0)
-            backend_x11->have_xinput = TRUE;
-        }
-    }
-
-  XFree (x_devices);
-#endif /* HAVE_XINPUT */
-
-default_device:
-  /* fallback code in case:
-   *
-   *  - we do not have XInput support compiled in
-   *  - we do not have XInput support enabled
-   *  - we do not have the XInput extension
-   *
-   * we register two default devices, one for the pointer
-   * and one for the keyboard. this block must also be
-   * executed for the XInput support because XI does not
-   * cover core devices
-   */
-  device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_X11,
-                         "id", 0,
-                         "name", "Core Pointer",
-                         "device-type", CLUTTER_POINTER_DEVICE,
-                         "is-core", TRUE,
-                         NULL);
-  CLUTTER_NOTE (BACKEND, "Added core pointer device");
-  manager_x11->core_pointer = device;
-
-  device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_X11,
-                         "id", 1,
-                         "name", "Core Keyboard",
-                         "device-type", CLUTTER_KEYBOARD_DEVICE,
-                         "is-core", TRUE,
-                         NULL);
-  CLUTTER_NOTE (BACKEND, "Added core keyboard device");
-  manager_x11->core_keyboard = device;
-
-  if (G_OBJECT_CLASS (clutter_device_manager_x11_parent_class)->constructed)
-    G_OBJECT_CLASS (clutter_device_manager_x11_parent_class)->constructed (gobject);
-}
-
-static void
-clutter_device_manager_x11_add_device (ClutterDeviceManager *manager,
-                                       ClutterInputDevice   *device)
-{
-  ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
-
-  manager_x11->devices = g_slist_prepend (manager_x11->devices, device);
-
-  /* blow the cache */
-  g_slist_free (manager_x11->all_devices);
-  manager_x11->all_devices = NULL;
-}
-
-static void
-clutter_device_manager_x11_remove_device (ClutterDeviceManager *manager,
-                                          ClutterInputDevice   *device)
-{
-  ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
-
-  manager_x11->devices = g_slist_remove (manager_x11->devices, device);
-
-  /* blow the cache */
-  g_slist_free (manager_x11->all_devices);
-  manager_x11->all_devices = NULL;
-}
-
-static const GSList *
-clutter_device_manager_x11_get_devices (ClutterDeviceManager *manager)
-{
-  ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
-
-  /* cache the devices list so that we can keep the core pointer
-   * and keyboard outside of the ManagerX11:devices list
-   */
-  if (manager_x11->all_devices == NULL)
-    {
-      GSList *all_devices;
-
-      all_devices = manager_x11->devices;
-      all_devices = g_slist_prepend (all_devices, manager_x11->core_keyboard);
-      all_devices = g_slist_prepend (all_devices, manager_x11->core_pointer);
-
-      manager_x11->all_devices = all_devices;
-    }
-    
-  return CLUTTER_DEVICE_MANAGER_X11 (manager)->all_devices;
-}
-
-static ClutterInputDevice *
-clutter_device_manager_x11_get_core_device (ClutterDeviceManager *manager,
-                                            ClutterInputDeviceType type)
-{
-  ClutterDeviceManagerX11 *manager_x11;
-
-  manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
-
-  switch (type)
-    {
-    case CLUTTER_POINTER_DEVICE:
-      return manager_x11->core_pointer;
-
-    case CLUTTER_KEYBOARD_DEVICE:
-      return manager_x11->core_keyboard;
-
-    case CLUTTER_EXTENSION_DEVICE:
-    default:
-      return NULL;
-    }
-
-  return NULL;
-}
-
-static ClutterInputDevice *
-clutter_device_manager_x11_get_device (ClutterDeviceManager *manager,
-                                       gint                  id)
-{
-  ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
-  GSList *l;
-
-  for (l = manager_x11->devices; l != NULL; l = l->next)
-    {
-      ClutterInputDevice *device = l->data;
-
-      if (clutter_input_device_get_device_id (device) == id)
-        return device;
-    }
-
-  return NULL;
-}
-
-static void
-clutter_device_manager_x11_set_property (GObject      *gobject,
-                                         guint         prop_id,
-                                         const GValue *value,
-                                         GParamSpec   *pspec)
-{
-  ClutterDeviceManagerX11 *manager_x11;
-
-  manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (gobject);
-
-  switch (prop_id)
-    {
-    case PROP_USE_XINPUT_1:
-      manager_x11->use_xinput_1 = g_value_get_boolean (value);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-clutter_device_manager_x11_get_property (GObject    *gobject,
-                                         guint       prop_id,
-                                         GValue     *value,
-                                         GParamSpec *pspec)
-{
-  ClutterDeviceManagerX11 *manager_x11;
-
-  manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (gobject);
-
-  switch (prop_id)
-    {
-    case PROP_USE_XINPUT_1:
-      g_value_set_boolean (value, manager_x11->use_xinput_1);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-clutter_device_manager_x11_class_init (ClutterDeviceManagerX11Class *klass)
-{
-  ClutterDeviceManagerClass *manager_class;
-  GObjectClass *gobject_class;
-  GParamSpec *pspec;
-
-  gobject_class = G_OBJECT_CLASS (klass);
-  gobject_class->set_property = clutter_device_manager_x11_set_property;
-  gobject_class->get_property = clutter_device_manager_x11_get_property;
-  gobject_class->constructed = clutter_device_manager_x11_constructed;
-  
-  manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass);
-  manager_class->add_device = clutter_device_manager_x11_add_device;
-  manager_class->remove_device = clutter_device_manager_x11_remove_device;
-  manager_class->get_devices = clutter_device_manager_x11_get_devices;
-  manager_class->get_core_device = clutter_device_manager_x11_get_core_device;
-  manager_class->get_device = clutter_device_manager_x11_get_device;
-
-  pspec = g_param_spec_boolean ("use-xinput-1",
-                                "Use XInput 1",
-                                "Use the XInput 1.0 extension",
-                                FALSE,
-                                CLUTTER_PARAM_READWRITE |
-                                G_PARAM_CONSTRUCT_ONLY);
-  obj_props[PROP_USE_XINPUT_1] = pspec;
-  g_object_class_install_property (gobject_class, PROP_USE_XINPUT_1, pspec);
-}
-
-static void
-clutter_device_manager_x11_init (ClutterDeviceManagerX11 *self)
-{
-  self->use_xinput_1 = FALSE;
-}
diff --git a/clutter/x11/clutter-device-manager-xi2.c b/clutter/x11/clutter-device-manager-xi2.c
new file mode 100644 (file)
index 0000000..aff55cf
--- /dev/null
@@ -0,0 +1,1143 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright © 2011  Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+#include "config.h"
+
+#include <stdint.h>
+
+#include "clutter-device-manager-xi2.h"
+
+#include "clutter-backend-x11.h"
+#include "clutter-input-device-xi2.h"
+#include "clutter-stage-x11.h"
+
+#include "clutter-backend.h"
+#include "clutter-debug.h"
+#include "clutter-device-manager-private.h"
+#include "clutter-event-translator.h"
+#include "clutter-stage-private.h"
+#include "clutter-private.h"
+
+#include <X11/extensions/XInput2.h>
+
+enum
+{
+  PROP_0,
+
+  PROP_OPCODE,
+
+  PROP_LAST
+};
+
+static GParamSpec *obj_props[PROP_LAST] = { NULL, };
+
+static const char *clutter_input_axis_atom_names[] = {
+  "Abs X",              /* CLUTTER_INPUT_AXIS_X */
+  "Abs Y",              /* CLUTTER_INPUT_AXIS_Y */
+  "Abs Pressure",       /* CLUTTER_INPUT_AXIS_PRESSURE */
+  "Abs Tilt X",         /* CLUTTER_INPUT_AXIS_XTILT */
+  "Abs Tilt Y",         /* CLUTTER_INPUT_AXIS_YTILT */
+  "Abs Wheel",          /* CLUTTER_INPUT_AXIS_WHEEL */
+};
+
+#define N_AXIS_ATOMS    G_N_ELEMENTS (clutter_input_axis_atom_names)
+
+static Atom clutter_input_axis_atoms[N_AXIS_ATOMS] = { 0, };
+
+static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface);
+
+#define clutter_device_manager_xi2_get_type     _clutter_device_manager_xi2_get_type
+
+G_DEFINE_TYPE_WITH_CODE (ClutterDeviceManagerXI2,
+                         clutter_device_manager_xi2,
+                         CLUTTER_TYPE_DEVICE_MANAGER,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR,
+                                                clutter_event_translator_iface_init));
+
+static void
+translate_valuator_class (Display             *xdisplay,
+                          ClutterInputDevice  *device,
+                          XIValuatorClassInfo *class)
+{
+  static gboolean atoms_initialized = FALSE;
+  ClutterInputAxis axis, i;
+
+  if (G_UNLIKELY (!atoms_initialized))
+    {
+      XInternAtoms (xdisplay,
+                    (char **) clutter_input_axis_atom_names, N_AXIS_ATOMS,
+                    False,
+                    clutter_input_axis_atoms);
+
+      atoms_initialized = TRUE;
+    }
+
+  for (i = CLUTTER_INPUT_AXIS_IGNORE;
+       i <= CLUTTER_INPUT_AXIS_WHEEL;
+       i += 1)
+    {
+      if (clutter_input_axis_atoms[i] == class->label)
+        {
+          axis = i;
+          break;
+        }
+    }
+
+  _clutter_input_device_add_axis (device, axis,
+                                  class->min,
+                                  class->max,
+                                  class->resolution);
+
+  CLUTTER_NOTE (BACKEND,
+                "Added axis '%s' (min:%.2f, max:%.2fd, res:%d) of device %d",
+                clutter_input_axis_atom_names[axis],
+                class->min,
+                class->max,
+                class->resolution,
+                device->id);
+}
+
+static void
+translate_device_classes (Display             *xdisplay,
+                          ClutterInputDevice  *device,
+                          XIAnyClassInfo     **classes,
+                          guint                n_classes)
+{
+  gint i;
+
+  for (i = 0; i < n_classes; i++)
+    {
+      XIAnyClassInfo *class_info = classes[i];
+
+      switch (class_info->type)
+        {
+        case XIKeyClass:
+          {
+            XIKeyClassInfo *key_info = (XIKeyClassInfo *) class_info;
+            gint j;
+
+            _clutter_input_device_set_n_keys (device,
+                                              key_info->num_keycodes);
+
+            for (j = 0; j < key_info->num_keycodes; j++)
+              {
+                clutter_input_device_set_key (device, j,
+                                              key_info->keycodes[i],
+                                              0);
+              }
+          }
+          break;
+
+        case XIValuatorClass:
+          translate_valuator_class (xdisplay, device,
+                                    (XIValuatorClassInfo *) class_info);
+          break;
+
+        default:
+          break;
+        }
+    }
+}
+
+static ClutterInputDevice *
+create_device (ClutterDeviceManagerXI2 *manager_xi2,
+               ClutterBackendX11       *backend_x11,
+               XIDeviceInfo            *info)
+{
+  ClutterInputDeviceType source;
+  ClutterInputDevice *retval;
+  ClutterInputMode mode;
+  gboolean is_enabled;
+
+  if (info->use == XIMasterKeyboard || info->use == XISlaveKeyboard)
+    source = CLUTTER_KEYBOARD_DEVICE;
+  else
+    {
+      gchar *name;
+
+      name = g_ascii_strdown (info->name, -1);
+
+      if (strstr (name, "eraser") != NULL)
+        source = CLUTTER_ERASER_DEVICE;
+      else if (strstr (name, "cursor") != NULL)
+        source = CLUTTER_CURSOR_DEVICE;
+      else if (strstr (name, "wacom") != NULL || strstr (name, "pen") != NULL)
+        source = CLUTTER_PEN_DEVICE;
+      else
+        source = CLUTTER_POINTER_DEVICE;
+
+      g_free (name);
+    }
+
+  switch (info->use)
+    {
+    case XIMasterKeyboard:
+    case XIMasterPointer:
+      mode = CLUTTER_INPUT_MODE_MASTER;
+      is_enabled = TRUE;
+      break;
+
+    case XISlaveKeyboard:
+    case XISlavePointer:
+      mode = CLUTTER_INPUT_MODE_SLAVE;
+      is_enabled = FALSE;
+      break;
+
+    case XIFloatingSlave:
+    default:
+      mode = CLUTTER_INPUT_MODE_FLOATING;
+      is_enabled = FALSE;
+      break;
+    }
+
+  retval = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_XI2,
+                         "name", info->name,
+                         "id", info->deviceid,
+                         "has-cursor", (info->use == XIMasterPointer),
+                         "device-manager", manager_xi2,
+                         "device-type", source,
+                         "device-mode", mode,
+                         "backend", backend_x11,
+                         "enabled", is_enabled,
+                         NULL);
+
+  translate_device_classes (backend_x11->xdpy, retval,
+                            info->classes,
+                            info->num_classes);
+
+  CLUTTER_NOTE (BACKEND, "Created device '%s' (id: %d, has-cursor: %s)",
+                info->name,
+                info->deviceid,
+                info->use == XIMasterPointer ? "yes" : "no");
+
+  return retval;
+}
+
+static ClutterInputDevice *
+add_device (ClutterDeviceManagerXI2 *manager_xi2,
+            ClutterBackendX11       *backend_x11,
+            XIDeviceInfo            *info,
+            gboolean                 in_construction)
+{
+  ClutterInputDevice *device;
+
+  device = create_device (manager_xi2, backend_x11, info);
+
+  /* we don't go through the DeviceManager::add_device() vfunc because
+   * that emits the signal, and we only do it conditionally
+   */
+  g_hash_table_replace (manager_xi2->devices_by_id,
+                        GINT_TO_POINTER (info->deviceid),
+                        g_object_ref (device));
+
+  if (info->use == XIMasterPointer ||
+      info->use == XIMasterKeyboard)
+    {
+      manager_xi2->master_devices =
+        g_list_prepend (manager_xi2->master_devices, device);
+    }
+  else if (info->use == XISlavePointer ||
+           info->use == XISlaveKeyboard ||
+           info->use == XIFloatingSlave)
+    {
+      manager_xi2->slave_devices =
+        g_list_prepend (manager_xi2->slave_devices, device);
+    }
+  else
+    g_warning ("Unhandled device: %s",
+               clutter_input_device_get_device_name (device));
+
+  /* relationships between devices and signal emissions are not
+   * necessary while we're constructing the device manager instance
+   */
+  if (!in_construction)
+    {
+      if (info->use == XISlavePointer || info->use == XISlaveKeyboard)
+        {
+          ClutterInputDevice *master;
+
+          master = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                        GINT_TO_POINTER (info->attachment));
+          _clutter_input_device_set_associated_device (device, master);
+          _clutter_input_device_add_slave (master, device);
+        }
+
+      /* blow the cache */
+      g_slist_free (manager_xi2->all_devices);
+      manager_xi2->all_devices = NULL;
+
+      g_signal_emit_by_name (manager_xi2, "device-added", device);
+    }
+
+  return device;
+}
+
+static void
+remove_device (ClutterDeviceManagerXI2 *manager_xi2,
+               gint                     device_id)
+{
+  ClutterInputDevice *device;
+
+  device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                GINT_TO_POINTER (device_id));
+
+  if (device != NULL)
+    {
+      manager_xi2->master_devices =
+        g_list_remove (manager_xi2->master_devices, device);
+      manager_xi2->slave_devices =
+        g_list_remove (manager_xi2->slave_devices, device);
+
+      /* blow the cache */
+      g_slist_free (manager_xi2->all_devices);
+      manager_xi2->all_devices = NULL;
+
+      g_signal_emit_by_name (manager_xi2, "device-removed", device);
+
+      g_object_run_dispose (G_OBJECT (device));
+
+      g_hash_table_remove (manager_xi2->devices_by_id,
+                           GINT_TO_POINTER (device_id));
+    }
+}
+
+static void
+translate_hierarchy_event (ClutterBackendX11       *backend_x11,
+                           ClutterDeviceManagerXI2 *manager_xi2,
+                           XIHierarchyEvent        *ev)
+{
+  ClutterInputDevice *device;
+  int i;
+
+  for (i = 0; i < ev->num_info; i++)
+    {
+      if (ev->info[i].flags & XIDeviceEnabled)
+        {
+          XIDeviceInfo *info;
+          int n_devices;
+
+          CLUTTER_NOTE (EVENT, "Hierarchy event: device enabled");
+
+          info = XIQueryDevice (backend_x11->xdpy,
+                                ev->info[i].deviceid,
+                                &n_devices);
+          device = add_device (manager_xi2, backend_x11, &info[0], FALSE);
+        }
+      else if (ev->info[i].flags & XIDeviceDisabled)
+        {
+          CLUTTER_NOTE (EVENT, "Hierarchy event: device disabled");
+
+          remove_device (manager_xi2, ev->info[i].deviceid);
+        }
+      else if ((ev->info[i].flags & XISlaveAttached) ||
+               (ev->info[i].flags & XISlaveDetached))
+        {
+          ClutterInputDevice *master, *slave;
+          XIDeviceInfo *info;
+          int n_devices;
+
+          CLUTTER_NOTE (EVENT, "Hierarchy event: slave %s",
+                        (ev->info[i].flags & XISlaveAttached)
+                          ? "attached"
+                          : "detached");
+
+          slave = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                       GINT_TO_POINTER (ev->info[i].deviceid));
+          master = clutter_input_device_get_associated_device (slave);
+
+          /* detach the slave in both cases */
+          if (master != NULL)
+            {
+              _clutter_input_device_remove_slave (master, slave);
+              _clutter_input_device_set_associated_device (slave, NULL);
+            }
+
+          /* and attach the slave to the new master if needed */
+          if (ev->info[i].flags & XISlaveAttached)
+            {
+              info = XIQueryDevice (backend_x11->xdpy,
+                                    ev->info[i].deviceid,
+                                    &n_devices);
+              master = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                            GINT_TO_POINTER (info->attachment));
+              _clutter_input_device_set_associated_device (slave, master);
+              _clutter_input_device_add_slave (master, slave);
+
+              XIFreeDeviceInfo (info);
+            }
+        }
+    }
+}
+
+static void
+clutter_device_manager_xi2_select_events (ClutterDeviceManager *manager,
+                                          Window                xwindow,
+                                          XIEventMask          *event_mask)
+{
+  Display *xdisplay;
+
+  xdisplay = clutter_x11_get_default_display ();
+
+  XISelectEvents (xdisplay, xwindow, event_mask, 1);
+}
+
+static ClutterStage *
+get_event_stage (ClutterEventTranslator *translator,
+                 XIEvent                *xi_event)
+{
+  Window xwindow = None;
+
+  switch (xi_event->evtype)
+    {
+    case XI_KeyPress:
+    case XI_KeyRelease:
+    case XI_ButtonPress:
+    case XI_ButtonRelease:
+    case XI_Motion:
+      {
+        XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
+
+        xwindow = xev->event;
+      }
+      break;
+
+    case XI_Enter:
+    case XI_Leave:
+    case XI_FocusIn:
+    case XI_FocusOut:
+      {
+        XIEnterEvent *xev = (XIEnterEvent *) xi_event;
+
+        xwindow = xev->event;
+      }
+      break;
+
+    default:
+      break;
+    }
+
+  if (xwindow == None)
+    return NULL;
+
+  return clutter_x11_get_stage_from_window (xwindow);
+}
+
+/*
+ * print_key_sym: Translate a symbol to its printable form if any
+ * @symbol: the symbol to translate
+ * @buffer: the buffer where to put the translated string
+ * @len: size of the buffer
+ *
+ * Translates @symbol into a printable representation in @buffer, if possible.
+ *
+ * Return value: The number of bytes of the translated string, 0 if the
+ *               symbol can't be printed
+ *
+ * Note: The code is derived from libX11's src/KeyBind.c
+ *       Copyright 1985, 1987, 1998  The Open Group
+ *
+ * Note: This code works for Latin-1 symbols. clutter_keysym_to_unicode()
+ *       does the work for the other keysyms.
+ */
+static int
+print_keysym (uint32_t symbol,
+              char    *buffer,
+              int      len)
+{
+  unsigned long high_bytes;
+  unsigned char c;
+
+  high_bytes = symbol >> 8;
+  if (!(len &&
+        ((high_bytes == 0) ||
+         ((high_bytes == 0xFF) &&
+          (((symbol >= CLUTTER_KEY_BackSpace) &&
+            (symbol <= CLUTTER_KEY_Clear)) ||
+           (symbol == CLUTTER_KEY_Return) ||
+           (symbol == CLUTTER_KEY_Escape) ||
+           (symbol == CLUTTER_KEY_KP_Space) ||
+           (symbol == CLUTTER_KEY_KP_Tab) ||
+           (symbol == CLUTTER_KEY_KP_Enter) ||
+           ((symbol >= CLUTTER_KEY_KP_Multiply) &&
+            (symbol <= CLUTTER_KEY_KP_9)) ||
+           (symbol == CLUTTER_KEY_KP_Equal) ||
+           (symbol == CLUTTER_KEY_Delete))))))
+    return 0;
+
+  /* if X keysym, convert to ascii by grabbing low 7 bits */
+  if (symbol == CLUTTER_KEY_KP_Space)
+    c = CLUTTER_KEY_space & 0x7F; /* patch encoding botch */
+  else if (high_bytes == 0xFF)
+    c = symbol & 0x7F;
+  else
+    c = symbol & 0xFF;
+
+  buffer[0] = c;
+  return 1;
+}
+
+static gdouble *
+translate_axes (ClutterInputDevice *device,
+                gdouble             x,
+                gdouble             y,
+                ClutterStageX11    *stage_x11,
+                XIValuatorState    *valuators)
+{
+  guint n_axes = clutter_input_device_get_n_axes (device);
+  guint i;
+  gdouble *retval;
+  double *values;
+
+  retval = g_new0 (gdouble, n_axes);
+  values = valuators->values;
+
+  for (i = 0; i < valuators->mask_len * 8; i++)
+    {
+      ClutterInputAxis axis;
+      gdouble val;
+
+      if (!XIMaskIsSet (valuators->mask, i))
+        continue;
+
+      axis = clutter_input_device_get_axis (device, i);
+      val = *values++;
+
+      switch (axis)
+        {
+        case CLUTTER_INPUT_AXIS_X:
+          retval[i] = x;
+          break;
+
+        case CLUTTER_INPUT_AXIS_Y:
+          retval[i] = y;
+          break;
+
+        default:
+          _clutter_input_device_translate_axis (device, i, val, &retval[i]);
+          break;
+        }
+    }
+
+  return retval;
+}
+
+static ClutterTranslateReturn
+clutter_device_manager_xi2_translate_event (ClutterEventTranslator *translator,
+                                            gpointer                native,
+                                            ClutterEvent           *event)
+{
+  ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (translator);
+  ClutterTranslateReturn retval = CLUTTER_TRANSLATE_CONTINUE;
+  ClutterBackendX11 *backend_x11;
+  ClutterStageX11 *stage_x11 = NULL;
+  ClutterStage *stage = NULL;
+  ClutterInputDevice *device, *source_device;
+  XGenericEventCookie *cookie;
+  XIEvent *xi_event;
+  XEvent *xevent;
+
+  backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
+
+  xevent = native;
+
+  cookie = &xevent->xcookie;
+
+  if (!XGetEventData (backend_x11->xdpy, cookie))
+    return CLUTTER_TRANSLATE_CONTINUE;
+
+  if (cookie->type != GenericEvent ||
+      cookie->extension != manager_xi2->opcode)
+    {
+      XFreeEventData (backend_x11->xdpy, cookie);
+      return CLUTTER_TRANSLATE_CONTINUE;
+    }
+
+  xi_event = (XIEvent *) cookie->data;
+
+  if (!(xi_event->evtype == XI_HierarchyChanged ||
+        xi_event->evtype == XI_DeviceChanged))
+    {
+      stage = get_event_stage (translator, xi_event);
+      if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage))
+        {
+          XFreeEventData (backend_x11->xdpy, cookie);
+          return CLUTTER_TRANSLATE_CONTINUE;
+        }
+      else
+        stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage));
+    }
+
+  event->any.stage = stage;
+
+  switch (xi_event->evtype)
+    {
+    case XI_HierarchyChanged:
+      {
+        XIHierarchyEvent *xev = (XIHierarchyEvent *) xi_event;
+
+        translate_hierarchy_event (backend_x11, manager_xi2, xev);
+      }
+      retval = CLUTTER_TRANSLATE_REMOVE;
+      break;
+
+    case XI_DeviceChanged:
+      {
+        XIDeviceChangedEvent *xev = (XIDeviceChangedEvent *) xi_event;
+
+        device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                      GINT_TO_POINTER (xev->deviceid));
+        _clutter_input_device_reset_axes (device);
+        translate_device_classes (backend_x11->xdpy,
+                                  device,
+                                  xev->classes,
+                                  xev->num_classes);
+      }
+      retval = CLUTTER_TRANSLATE_REMOVE;
+      break;
+
+    case XI_KeyPress:
+    case XI_KeyRelease:
+      {
+        XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
+        ClutterEventX11 *event_x11;
+        char buffer[7] = { 0, };
+        gunichar n;
+
+        event->key.type = event->type = (xev->evtype == XI_KeyPress)
+                                      ? CLUTTER_KEY_PRESS
+                                      : CLUTTER_KEY_RELEASE;
+
+        event->key.time = xev->time;
+        event->key.stage = stage;
+        event->key.modifier_state =
+          _clutter_input_device_xi2_translate_state (&xev->mods, &xev->buttons);
+        event->key.hardware_keycode = xev->detail;
+
+          /* keyval is the key ignoring all modifiers ('1' vs. '!') */
+        event->key.keyval =
+          _clutter_keymap_x11_translate_key_state (backend_x11->keymap,
+                                                   event->key.hardware_keycode,
+                                                   event->key.modifier_state,
+                                                   NULL);
+
+        /* KeyEvents have platform specific data associated to them */
+        event_x11 = _clutter_event_x11_new ();
+        _clutter_event_set_platform_data (event, event_x11);
+
+        event_x11->key_group =
+          _clutter_keymap_x11_get_key_group (backend_x11->keymap,
+                                             event->key.modifier_state);
+        event_x11->key_is_modifier =
+          _clutter_keymap_x11_get_is_modifier (backend_x11->keymap,
+                                               event->key.hardware_keycode);
+        event_x11->num_lock_set =
+          _clutter_keymap_x11_get_num_lock_state (backend_x11->keymap);
+        event_x11->caps_lock_set =
+          _clutter_keymap_x11_get_caps_lock_state (backend_x11->keymap);
+
+        source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                             GINT_TO_POINTER (xev->sourceid));
+        _clutter_event_set_source_device (event, source_device);
+
+        device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                      GINT_TO_POINTER (xev->deviceid));
+        _clutter_event_set_device (event, device);
+
+        /* XXX keep this in sync with the evdev device manager */
+        n = print_keysym (event->key.keyval, buffer, sizeof (buffer));
+        if (n == 0)
+          {
+            /* not printable */
+            event->key.unicode_value = (gunichar) '\0';
+          }
+        else
+          {
+            event->key.unicode_value = g_utf8_get_char_validated (buffer, n);
+            if (event->key.unicode_value == -1 ||
+                event->key.unicode_value == -2)
+              event->key.unicode_value = (gunichar) '\0';
+          }
+
+        CLUTTER_NOTE (EVENT,
+                      "%s: win:0x%x device:%d source:%d, key: %12s (%d)",
+                      event->any.type == CLUTTER_KEY_PRESS
+                        ? "key press  "
+                        : "key release",
+                      (unsigned int) stage_x11->xwin,
+                      xev->deviceid,
+                      xev->sourceid,
+                      event->key.keyval ? buffer : "(none)",
+                      event->key.keyval);
+
+        if (xi_event->evtype == XI_KeyPress)
+          _clutter_stage_x11_set_user_time (stage_x11, event->key.time);
+
+        retval = CLUTTER_TRANSLATE_QUEUE;
+      }
+      break;
+
+    case XI_ButtonPress:
+    case XI_ButtonRelease:
+      {
+        XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
+
+        switch (xev->detail)
+          {
+          case 4:
+          case 5:
+          case 6:
+          case 7:
+            event->scroll.type = event->type = CLUTTER_SCROLL;
+
+            if (xev->detail == 4)
+              event->scroll.direction = CLUTTER_SCROLL_UP;
+            else if (xev->detail == 5)
+              event->scroll.direction = CLUTTER_SCROLL_DOWN;
+            else if (xev->detail == 6)
+              event->scroll.direction = CLUTTER_SCROLL_LEFT;
+            else
+              event->scroll.direction = CLUTTER_SCROLL_RIGHT;
+
+            event->scroll.stage = stage;
+
+            event->scroll.time = xev->time;
+            event->scroll.x = xev->event_x;
+            event->scroll.y = xev->event_y;
+            event->scroll.modifier_state =
+              _clutter_input_device_xi2_translate_state (&xev->mods,
+                                                         &xev->buttons);
+
+            source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                                 GINT_TO_POINTER (xev->sourceid));
+            _clutter_event_set_source_device (event, source_device);
+
+            device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                          GINT_TO_POINTER (xev->deviceid));
+            _clutter_event_set_device (event, device);
+
+            event->scroll.axes = translate_axes (event->scroll.device,
+                                                 event->scroll.x,
+                                                 event->scroll.y,
+                                                 stage_x11,
+                                                 &xev->valuators);
+
+            break;
+
+          default:
+            event->button.type = event->type =
+              (xi_event->evtype == XI_ButtonPress) ? CLUTTER_BUTTON_PRESS
+                                                   : CLUTTER_BUTTON_RELEASE;
+
+            event->button.stage = stage;
+
+            event->button.time = xev->time;
+            event->button.x = xev->event_x;
+            event->button.y = xev->event_y;
+            event->button.button = xev->detail;
+            event->button.modifier_state =
+              _clutter_input_device_xi2_translate_state (&xev->mods,
+                                                         &xev->buttons);
+
+            source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                                 GINT_TO_POINTER (xev->sourceid));
+            _clutter_event_set_source_device (event, source_device);
+
+            device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                          GINT_TO_POINTER (xev->deviceid));
+            _clutter_event_set_device (event, device);
+
+            event->button.axes = translate_axes (event->button.device,
+                                                 event->button.x,
+                                                 event->button.y,
+                                                 stage_x11,
+                                                 &xev->valuators);
+            break;
+          }
+
+        if (source_device != NULL && device->stage != NULL)
+          _clutter_input_device_set_stage (source_device, device->stage);
+
+        CLUTTER_NOTE (EVENT,
+                      "%s: win:0x%x, device:%s (button:%d, x:%.2f, y:%.2f, axes:%s)",
+                      event->any.type == CLUTTER_BUTTON_PRESS
+                        ? "button press  "
+                        : "button release",
+                      (unsigned int) stage_x11->xwin,
+                      event->button.device->device_name,
+                      event->button.button,
+                      event->button.x,
+                      event->button.y,
+                      event->button.axes != NULL ? "yes" : "no");
+
+        if (xi_event->evtype == XI_ButtonPress)
+          _clutter_stage_x11_set_user_time (stage_x11, event->button.time);
+
+        retval = CLUTTER_TRANSLATE_QUEUE;
+      }
+      break;
+
+    case XI_Motion:
+      {
+        XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
+
+        event->motion.type = event->type = CLUTTER_MOTION;
+
+        event->motion.stage = stage;
+
+        event->motion.time = xev->time;
+        event->motion.x = xev->event_x;
+        event->motion.y = xev->event_y;
+        event->motion.modifier_state =
+          _clutter_input_device_xi2_translate_state (&xev->mods,
+                                                     &xev->buttons);
+
+        source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                             GINT_TO_POINTER (xev->sourceid));
+        _clutter_event_set_source_device (event, source_device);
+
+        device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                      GINT_TO_POINTER (xev->deviceid));
+        _clutter_event_set_device (event, device);
+
+        event->motion.axes = translate_axes (event->motion.device,
+                                             event->motion.x,
+                                             event->motion.y,
+                                             stage_x11,
+                                             &xev->valuators);
+
+        if (source_device != NULL && device->stage != NULL)
+          _clutter_input_device_set_stage (source_device, device->stage);
+
+        CLUTTER_NOTE (EVENT, "motion: win:0x%x device:%s (x:%.2f, y:%.2f, axes:%s)",
+                      (unsigned int) stage_x11->xwin,
+                      event->motion.device->device_name,
+                      event->motion.x,
+                      event->motion.y,
+                      event->motion.axes != NULL ? "yes" : "no");
+
+        retval = CLUTTER_TRANSLATE_QUEUE;
+      }
+      break;
+
+    case XI_Enter:
+    case XI_Leave:
+      {
+        XIEnterEvent *xev = (XIEnterEvent *) xi_event;
+
+        device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                      GINT_TO_POINTER (xev->deviceid));
+
+        source_device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                             GINT_TO_POINTER (xev->sourceid));
+
+        if (xi_event->evtype == XI_Enter)
+          {
+            event->crossing.type = event->type = CLUTTER_ENTER;
+
+            event->crossing.stage = stage;
+            event->crossing.source = CLUTTER_ACTOR (stage);
+            event->crossing.related = NULL;
+
+            event->crossing.time = xev->time;
+            event->crossing.x = xev->event_x;
+            event->crossing.y = xev->event_y;
+
+            _clutter_stage_add_device (stage, device);
+          }
+        else
+          {
+            if (device->stage == NULL)
+              {
+                CLUTTER_NOTE (EVENT,
+                              "Discarding Leave for ButtonRelease "
+                              "event off-stage");
+
+                retval = CLUTTER_TRANSLATE_REMOVE;
+                break;
+              }
+
+            event->crossing.type = event->type = CLUTTER_LEAVE;
+
+            event->crossing.stage = stage;
+            event->crossing.source = CLUTTER_ACTOR (stage);
+            event->crossing.related = NULL;
+
+            event->crossing.time = xev->time;
+            event->crossing.x = xev->event_x;
+            event->crossing.y = xev->event_y;
+
+            _clutter_stage_remove_device (stage, device);
+          }
+
+        clutter_event_set_device (event, device);
+        _clutter_event_set_source_device (event, source_device);
+
+        retval = CLUTTER_TRANSLATE_QUEUE;
+      }
+      break;
+
+    case XI_FocusIn:
+    case XI_FocusOut:
+      retval = CLUTTER_TRANSLATE_CONTINUE;
+      break;
+    }
+
+  XFreeEventData (backend_x11->xdpy, cookie);
+
+  return retval;
+}
+
+static void
+clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface)
+{
+  iface->translate_event = clutter_device_manager_xi2_translate_event;
+}
+
+static void
+clutter_device_manager_xi2_add_device (ClutterDeviceManager *manager,
+                                       ClutterInputDevice   *device)
+{
+  /* XXX implement */
+}
+
+static void
+clutter_device_manager_xi2_remove_device (ClutterDeviceManager *manager,
+                                          ClutterInputDevice   *device)
+{
+  /* XXX implement */
+}
+
+static const GSList *
+clutter_device_manager_xi2_get_devices (ClutterDeviceManager *manager)
+{
+  ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (manager);
+  GSList *all_devices = NULL;
+  GList *l;
+
+  if (manager_xi2->all_devices != NULL)
+    return manager_xi2->all_devices;
+
+  for (l = manager_xi2->master_devices; l != NULL; l = l->next)
+    all_devices = g_slist_prepend (all_devices, l->data);
+
+  for (l = manager_xi2->slave_devices; l != NULL; l = l->next)
+    all_devices = g_slist_prepend (all_devices, l->data);
+
+  manager_xi2->all_devices = g_slist_reverse (all_devices);
+
+  return manager_xi2->all_devices;
+}
+
+static ClutterInputDevice *
+clutter_device_manager_xi2_get_device (ClutterDeviceManager *manager,
+                                       gint                  id)
+{
+  ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (manager);
+
+  return g_hash_table_lookup (manager_xi2->devices_by_id,
+                              GINT_TO_POINTER (id));
+}
+
+static ClutterInputDevice *
+clutter_device_manager_xi2_get_core_device (ClutterDeviceManager   *manager,
+                                            ClutterInputDeviceType  device_type)
+{
+  ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (manager);
+  ClutterBackendX11 *backend_x11;
+  ClutterInputDevice *device;
+  int device_id;
+
+  backend_x11 =
+    CLUTTER_BACKEND_X11 (_clutter_device_manager_get_backend (manager));
+
+  XIGetClientPointer (backend_x11->xdpy, None, &device_id);
+
+  device = g_hash_table_lookup (manager_xi2->devices_by_id,
+                                GINT_TO_POINTER (device_id));
+
+  switch (device_type)
+    {
+    case CLUTTER_POINTER_DEVICE:
+      return device;
+
+    case CLUTTER_KEYBOARD_DEVICE:
+      return clutter_input_device_get_associated_device (device);
+
+    default:
+      break;
+    }
+
+  return NULL;
+}
+
+static void
+relate_masters (gpointer key,
+                gpointer value,
+                gpointer data)
+{
+  ClutterDeviceManagerXI2 *manager_xi2 = data;
+  ClutterInputDevice *device, *relative;
+
+  device = g_hash_table_lookup (manager_xi2->devices_by_id, key);
+  relative = g_hash_table_lookup (manager_xi2->devices_by_id, value);
+
+  _clutter_input_device_set_associated_device (device, relative);
+  _clutter_input_device_set_associated_device (relative, device);
+}
+
+static void
+relate_slaves (gpointer key,
+               gpointer value,
+               gpointer data)
+{
+  ClutterDeviceManagerXI2 *manager_xi2 = data;
+  ClutterInputDevice *master, *slave;
+
+  master = g_hash_table_lookup (manager_xi2->devices_by_id, key);
+  slave = g_hash_table_lookup (manager_xi2->devices_by_id, value);
+
+  _clutter_input_device_set_associated_device (slave, master);
+  _clutter_input_device_add_slave (master, slave);
+}
+
+static void
+clutter_device_manager_xi2_constructed (GObject *gobject)
+{
+  ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (gobject);
+  ClutterDeviceManager *manager = CLUTTER_DEVICE_MANAGER (gobject);
+  ClutterBackendX11 *backend_x11;
+  GHashTable *masters, *slaves;
+  XIDeviceInfo *info;
+  XIEventMask event_mask;
+  unsigned char mask[2] = { 0, };
+  int n_devices, i;
+
+  backend_x11 =
+    CLUTTER_BACKEND_X11 (_clutter_device_manager_get_backend (manager));
+
+  masters = g_hash_table_new (NULL, NULL);
+  slaves = g_hash_table_new (NULL, NULL);
+
+  info = XIQueryDevice (backend_x11->xdpy, XIAllDevices, &n_devices);
+
+  for (i = 0; i < n_devices; i++)
+    {
+      XIDeviceInfo *xi_device = &info[i];
+      ClutterInputDevice *device;
+
+      device = add_device (manager_xi2, backend_x11, xi_device, TRUE);
+
+      if (xi_device->use == XIMasterPointer ||
+          xi_device->use == XIMasterKeyboard)
+        {
+          g_hash_table_insert (masters,
+                               GINT_TO_POINTER (xi_device->deviceid),
+                               GINT_TO_POINTER (xi_device->attachment));
+        }
+      else if (xi_device->use == XISlavePointer ||
+               xi_device->use == XISlaveKeyboard)
+        {
+          g_hash_table_insert (slaves,
+                               GINT_TO_POINTER (xi_device->deviceid),
+                               GINT_TO_POINTER (xi_device->attachment));
+        }
+    }
+
+  XIFreeDeviceInfo (info);
+
+  g_hash_table_foreach (masters, relate_masters, manager_xi2);
+  g_hash_table_destroy (masters);
+
+  g_hash_table_foreach (slaves, relate_slaves, manager_xi2);
+  g_hash_table_destroy (slaves);
+
+  XISetMask (mask, XI_HierarchyChanged);
+  XISetMask (mask, XI_DeviceChanged);
+
+  event_mask.deviceid = XIAllDevices;
+  event_mask.mask_len = sizeof (mask);
+  event_mask.mask = mask;
+
+  clutter_device_manager_xi2_select_events (manager,
+                                            clutter_x11_get_root_window (),
+                                            &event_mask);
+
+  if (G_OBJECT_CLASS (clutter_device_manager_xi2_parent_class)->constructed)
+    G_OBJECT_CLASS (clutter_device_manager_xi2_parent_class)->constructed (gobject);
+}
+
+static void
+clutter_device_manager_xi2_set_property (GObject      *gobject,
+                                         guint         prop_id,
+                                         const GValue *value,
+                                         GParamSpec   *pspec)
+{
+  ClutterDeviceManagerXI2 *manager_xi2 = CLUTTER_DEVICE_MANAGER_XI2 (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_OPCODE:
+      manager_xi2->opcode = g_value_get_int (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+clutter_device_manager_xi2_class_init (ClutterDeviceManagerXI2Class *klass)
+{
+  ClutterDeviceManagerClass *manager_class;
+  GObjectClass *gobject_class;
+
+  obj_props[PROP_OPCODE] =
+    g_param_spec_int ("opcode",
+                      "Opcode",
+                      "The XI2 opcode",
+                      -1, G_MAXINT,
+                      -1,
+                      CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->constructed = clutter_device_manager_xi2_constructed;
+  gobject_class->set_property = clutter_device_manager_xi2_set_property;
+
+  g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
+  
+  manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass);
+  manager_class->add_device = clutter_device_manager_xi2_add_device;
+  manager_class->remove_device = clutter_device_manager_xi2_remove_device;
+  manager_class->get_devices = clutter_device_manager_xi2_get_devices;
+  manager_class->get_core_device = clutter_device_manager_xi2_get_core_device;
+  manager_class->get_device = clutter_device_manager_xi2_get_device;
+}
+
+static void
+clutter_device_manager_xi2_init (ClutterDeviceManagerXI2 *self)
+{
+  self->devices_by_id = g_hash_table_new_full (NULL, NULL,
+                                               NULL,
+                                               (GDestroyNotify) g_object_unref);
+}
diff --git a/clutter/x11/clutter-device-manager-xi2.h b/clutter/x11/clutter-device-manager-xi2.h
new file mode 100644 (file)
index 0000000..ec54cbd
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright © 2011  Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+#ifndef __CLUTTER_DEVICE_MANAGER_XI2_H__
+#define __CLUTTER_DEVICE_MANAGER_XI2_H__
+
+#include <clutter/clutter-device-manager.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_DEVICE_MANAGER_XI2            (_clutter_device_manager_xi2_get_type ())
+#define CLUTTER_DEVICE_MANAGER_XI2(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER_XI2, ClutterDeviceManagerXI2))
+#define CLUTTER_IS_DEVICE_MANAGER_XI2(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER_XI2))
+#define CLUTTER_DEVICE_MANAGER_XI2_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER_XI2, ClutterDeviceManagerXI2Class))
+#define CLUTTER_IS_DEVICE_MANAGER_XI2_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEVICE_MANAGER_XI2))
+#define CLUTTER_DEVICE_MANAGER_XI2_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEVICE_MANAGER_XI2, ClutterDeviceManagerXI2Class))
+
+typedef struct _ClutterDeviceManagerXI2         ClutterDeviceManagerXI2;
+typedef struct _ClutterDeviceManagerXI2Class    ClutterDeviceManagerXI2Class;
+
+struct _ClutterDeviceManagerXI2
+{
+  ClutterDeviceManager parent_instance;
+
+  GHashTable *devices_by_id;
+
+  GSList *all_devices;
+
+  GList *master_devices;
+  GList *slave_devices;
+
+  ClutterInputDevice *client_pointer;
+
+  int opcode;
+};
+
+struct _ClutterDeviceManagerXI2Class
+{
+  ClutterDeviceManagerClass parent_class;
+};
+
+GType _clutter_device_manager_xi2_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __CLUTTER_DEVICE_MANAGER_XI2_H__ */
index 77b7f4f..38d9c66 100644 (file)
  *      Emmanuele Bassi <ebassi@linux.intel.com>
  */
 
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
-#include "clutter-stage-x11.h"
 #include "clutter-backend-x11.h"
-#include "clutter-keymap-x11.h"
 #include "clutter-x11.h"
 
-#include "clutter-actor-private.h"
 #include "clutter-backend-private.h"
 #include "clutter-debug.h"
-#include "clutter-device-manager-private.h"
 #include "clutter-event.h"
 #include "clutter-main.h"
-#include "clutter-paint-volume-private.h"
 #include "clutter-private.h"
-#include "clutter-stage-private.h"
-
-#include "cogl/cogl-internal.h"
 
 #include <string.h>
 
 #include <glib.h>
 
-#ifdef HAVE_XFIXES
-#include <X11/extensions/Xfixes.h>
-#endif
-
-#include <X11/Xatom.h>
-
-#ifdef HAVE_XINPUT
-#include <X11/extensions/XInput.h>
-#endif
-
-#ifdef HAVE_XKB
-#include <X11/XKBlib.h>
-#endif
-
+#if 0
 /* XEMBED protocol support for toolkit embedding */
 #define XEMBED_MAPPED                   (1 << 0)
 #define MAX_SUPPORTED_XEMBED_VERSION    1
@@ -83,6 +60,7 @@
 #define XEMBED_ACTIVATE_ACCELERATOR     14
 
 static Window ParentEmbedderWin = None;
+#endif
 
 typedef struct _ClutterEventSource      ClutterEventSource;
 
@@ -94,16 +72,6 @@ struct _ClutterEventSource
   GPollFD event_poll_fd;
 };
 
-struct _ClutterEventX11
-{
-  /* additional fields for Key events */
-  gint key_group;
-
-  guint key_is_modifier : 1;
-  guint num_lock_set    : 1;
-  guint caps_lock_set   : 1;
-};
-
 ClutterEventX11 *
 _clutter_event_x11_new (void)
 {
@@ -148,7 +116,6 @@ clutter_event_source_new (ClutterBackend *backend)
   GSource *source = g_source_new (&event_funcs, sizeof (ClutterEventSource));
   ClutterEventSource *event_source = (ClutterEventSource *) source;
 
-  g_source_set_name (source, "Clutter X11 Event");
   event_source->backend = backend;
 
   return source;
@@ -160,6 +127,7 @@ check_xpending (ClutterBackend *backend)
   return XPending (CLUTTER_BACKEND_X11 (backend)->xdpy);
 }
 
+#if 0
 static gboolean
 xembed_send_message (ClutterBackendX11 *backend_x11,
                      Window             window,
@@ -208,6 +176,7 @@ xembed_set_info (ClutterBackendX11 *backend_x11,
                    backend_x11->atom_XEMBED_INFO, 32,
                    PropModeReplace, (unsigned char *) list, 2);
 }
+#endif
 
 void
 _clutter_backend_x11_events_init (ClutterBackend *backend)
@@ -216,6 +185,7 @@ _clutter_backend_x11_events_init (ClutterBackend *backend)
   GSource *source;
   ClutterEventSource *event_source;
   int connection_number;
+  gchar *name;
 
   connection_number = ConnectionNumber (backend_x11->xdpy);
   CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number);
@@ -224,6 +194,11 @@ _clutter_backend_x11_events_init (ClutterBackend *backend)
   event_source = (ClutterEventSource *) source;
   g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
 
+  name = g_strdup_printf ("Clutter X11 Event (connection: %d)",
+                          connection_number);
+  g_source_set_name (source, name);
+  g_free (name);
+
   event_source->event_poll_fd.fd = connection_number;
   event_source->event_poll_fd.events = G_IO_IN;
 
@@ -253,916 +228,21 @@ _clutter_backend_x11_events_uninit (ClutterBackend *backend)
 }
 
 static void
-update_last_event_time (ClutterBackendX11 *backend_x11,
-                        XEvent            *xevent)
-{
-  Time current_time = CurrentTime;
-  Time last_time = backend_x11->last_event_time;
-
-  switch (xevent->type)
-    {
-    case KeyPress:
-    case KeyRelease:
-      current_time = xevent->xkey.time;
-      break;
-
-    case ButtonPress:
-    case ButtonRelease:
-      current_time = xevent->xbutton.time;
-      break;
-
-    case MotionNotify:
-      current_time = xevent->xmotion.time;
-      break;
-
-    case EnterNotify:
-    case LeaveNotify:
-      current_time = xevent->xcrossing.time;
-      break;
-
-    case PropertyNotify:
-      current_time = xevent->xproperty.time;
-      break;
-
-    default:
-      break;
-    }
-
-  /* only change the current event time if it's after the previous event
-   * time, or if it is at least 30 seconds earlier - in case the system
-   * clock was changed
-   */
-  if ((current_time != CurrentTime) &&
-      (current_time > last_time || (last_time - current_time > (30 * 1000))))
-    backend_x11->last_event_time = current_time;
-}
-
-static void
-set_user_time (ClutterBackendX11 *backend_x11,
-               Window            *xwindow,
-               long               timestamp)
-{
-  if (timestamp != CLUTTER_CURRENT_TIME)
-    {
-      XChangeProperty (backend_x11->xdpy, *xwindow,
-                       backend_x11->atom_NET_WM_USER_TIME,
-                       XA_CARDINAL, 32, PropModeReplace,
-                       (unsigned char *) &timestamp, 1);
-    }
-}
-
-#ifdef HAVE_XINPUT
-static void
-convert_xdevicekey_to_xkey (XDeviceKeyEvent *xkev,
-                            XEvent          *xevent)
-{
-  xevent->xany.type = xevent->xkey.type = xkev->type;
-  xevent->xkey.serial = xkev->serial;
-  xevent->xkey.display = xkev->display;
-  xevent->xkey.window = xkev->window;
-  xevent->xkey.root = xkev->root;
-  xevent->xkey.subwindow = xkev->subwindow;
-  xevent->xkey.time = xkev->time;
-  xevent->xkey.x = xkev->x;
-  xevent->xkey.y = xkev->y;
-  xevent->xkey.x_root = xkev->x_root;
-  xevent->xkey.y_root = xkev->y_root;
-  xevent->xkey.state = xkev->state;
-  xevent->xkey.keycode = xkev->keycode;
-  xevent->xkey.same_screen = xkev->same_screen;
-}
-#endif /* HAVE_XINPUT */
-
-static inline void
-translate_key_event (ClutterBackendX11 *backend_x11,
-                     ClutterEvent      *event,
-                     XEvent            *xevent)
-{
-  ClutterEventX11 *event_x11;
-  char buffer[256 + 1];
-  int n;
-
-  /* KeyEvents have platform specific data associated to them */
-  event_x11 = _clutter_event_x11_new ();
-  _clutter_event_set_platform_data (event, event_x11);
-
-  event->key.time = xevent->xkey.time;
-  event->key.modifier_state = (ClutterModifierType) xevent->xkey.state;
-  event->key.hardware_keycode = xevent->xkey.keycode;
-
-  /* keyval is the key ignoring all modifiers ('1' vs. '!') */
-  event->key.keyval =
-    _clutter_keymap_x11_translate_key_state (backend_x11->keymap,
-                                             event->key.hardware_keycode,
-                                             event->key.modifier_state,
-                                             NULL);
-
-  event_x11->key_group =
-    _clutter_keymap_x11_get_key_group (backend_x11->keymap,
-                                       event->key.modifier_state);
-  event_x11->key_is_modifier =
-    _clutter_keymap_x11_get_is_modifier (backend_x11->keymap,
-                                         event->key.hardware_keycode);
-  event_x11->num_lock_set =
-    _clutter_keymap_x11_get_num_lock_state (backend_x11->keymap);
-  event_x11->caps_lock_set =
-    _clutter_keymap_x11_get_caps_lock_state (backend_x11->keymap);
-
-  /* unicode_value is the printable representation */
-  n = XLookupString (&xevent->xkey, buffer, sizeof (buffer) - 1, NULL, NULL);
-
-  if (n != NoSymbol)
-    {
-      event->key.unicode_value = g_utf8_get_char_validated (buffer, n);
-      if ((event->key.unicode_value != -1) &&
-          (event->key.unicode_value != -2))
-        goto out;
-    }
-  else
-    event->key.unicode_value = (gunichar)'\0';
-
-out:
-  return;
-}
-
-static gboolean
-handle_wm_protocols_event (ClutterBackendX11 *backend_x11,
-                           Window             window,
-                           XEvent            *xevent)
-{
-  Atom atom = (Atom) xevent->xclient.data.l[0];
-
-  if (atom == backend_x11->atom_WM_DELETE_WINDOW &&
-      xevent->xany.window == window)
-    {
-      /* the WM_DELETE_WINDOW is a request: we do not destroy
-       * the window right away, as it might contain vital data;
-       * we relay the event to the application and we let it
-       * handle the request
-       */
-      CLUTTER_NOTE (EVENT, "delete window:\txid: %ld",
-                    xevent->xclient.window);
-
-      set_user_time (backend_x11,
-                     &window,
-                     xevent->xclient.data.l[1]);
-
-      return TRUE;
-    }
-  else if (atom == backend_x11->atom_NET_WM_PING &&
-           xevent->xany.window == window)
-    {
-      XClientMessageEvent xclient = xevent->xclient;
-
-      xclient.window = backend_x11->xwin_root;
-      XSendEvent (backend_x11->xdpy, xclient.window,
-                  False,
-                  SubstructureRedirectMask | SubstructureNotifyMask,
-                  (XEvent *) &xclient);
-      return FALSE;
-    }
-
-  /* do not send any of the WM_PROTOCOLS events to the queue */
-  return FALSE;
-}
-
-static gboolean
-handle_xembed_event (ClutterBackendX11 *backend_x11,
-                     XEvent            *xevent)
-{
-  ClutterActor *stage;
-
-  stage = clutter_stage_get_default ();
-
-  switch (xevent->xclient.data.l[1])
-    {
-    case XEMBED_EMBEDDED_NOTIFY:
-      CLUTTER_NOTE (EVENT, "got XEMBED_EMBEDDED_NOTIFY from %lx",
-                    xevent->xclient.data.l[3]);
-
-      ParentEmbedderWin = xevent->xclient.data.l[3];
-
-      clutter_actor_realize (stage);
-      clutter_actor_show (stage);
-
-      xembed_set_info (backend_x11,
-                       clutter_x11_get_stage_window (CLUTTER_STAGE (stage)),
-                       XEMBED_MAPPED);
-      break;
-    case XEMBED_WINDOW_ACTIVATE:
-      CLUTTER_NOTE (EVENT, "got XEMBED_WINDOW_ACTIVATE");
-      break;
-    case XEMBED_WINDOW_DEACTIVATE:
-      CLUTTER_NOTE (EVENT, "got XEMBED_WINDOW_DEACTIVATE");
-      break;
-    case XEMBED_FOCUS_IN:
-      CLUTTER_NOTE (EVENT, "got XEMBED_FOCUS_IN");
-      if (ParentEmbedderWin)
-        xembed_send_message (backend_x11, ParentEmbedderWin,
-                             XEMBED_FOCUS_NEXT,
-                             0, 0, 0);
-      break;
-    default:
-      CLUTTER_NOTE (EVENT, "got unknown XEMBED message");
-      break;
-    }
-
-  /* do not propagate the XEMBED events to the stage */
-  return FALSE;
-}
-
-static gboolean
-clipped_redraws_cool_off_cb (void *data)
-{
-  ClutterStageX11 *stage_x11 = data;
-
-  stage_x11->clipped_redraws_cool_off = 0;
-
-  return FALSE;
-}
-
-static gboolean
-event_translate (ClutterBackend *backend,
-                 ClutterEvent   *event,
-                 XEvent         *xevent)
-{
-  ClutterBackendX11 *backend_x11;
-  ClutterStageX11 *stage_x11;
-  ClutterStage *stage;
-  ClutterStageWindow *impl;
-  ClutterDeviceManager *manager;
-  gboolean res, not_yet_handled = FALSE;
-  Window xwindow, stage_xwindow;
-  ClutterInputDevice *device;
-
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
-
-  xwindow = xevent->xany.window;
-
-  if (backend_x11->event_filters)
-    {
-      GSList *node;
-
-      node = backend_x11->event_filters;
-
-      while (node)
-        {
-          ClutterX11EventFilter *filter = node->data;
-
-          switch (filter->func (xevent, event, filter->data))
-            {
-            case CLUTTER_X11_FILTER_CONTINUE:
-              break;
-            case CLUTTER_X11_FILTER_TRANSLATE:
-              return TRUE;
-            case CLUTTER_X11_FILTER_REMOVE:
-              return FALSE;
-            default:
-              break;
-            }
-
-          node = node->next;
-        }
-    }
-
-  /* Pass the event through Cogl */
-  if (_cogl_xlib_handle_event (xevent) == COGL_XLIB_FILTER_REMOVE)
-    return FALSE;
-
-  /* Do further processing only on events for the stage window (the x11
-   * filters might be getting events for other windows, so do not mess
-   * them about.
-   */
-  stage = clutter_x11_get_stage_from_window (xwindow);
-  if (stage == NULL)
-    return FALSE;
-
-  impl = _clutter_stage_get_window (stage);
-  stage_x11 = CLUTTER_STAGE_X11 (impl);
-  stage_xwindow = xwindow; /* clutter_x11_get_stage_window (stage); */
-
-  event->any.stage = stage;
-
-  res = TRUE;
-
-  update_last_event_time (backend_x11, xevent);
-
-  manager = clutter_device_manager_get_default ();
-
-  switch (xevent->type)
-    {
-    case ConfigureNotify:
-      if (!stage_x11->is_foreign_xwin)
-        {
-          CLUTTER_NOTE (BACKEND, "%s: ConfigureNotify[%x] (%d, %d)",
-                        G_STRLOC,
-                        (unsigned int) stage_x11->xwin,
-                        xevent->xconfigure.width,
-                        xevent->xconfigure.height);
-
-          /* Queue a relayout - we want glViewport to be called
-           * with the correct values, and this is done in ClutterStage
-           * via _cogl_onscreen_clutter_backend_set_size ().
-           *
-           * We queue a relayout, because if this ConfigureNotify is
-           * in response to a size we set in the application, the
-           * set_size above is essentially a null-op.
-           *
-           * Make sure we do this only when the size has changed,
-           * otherwise we end up relayouting on window moves.
-           */
-          if ((stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN) ||
-              (stage_x11->xwin_width != xevent->xconfigure.width) ||
-              (stage_x11->xwin_height != xevent->xconfigure.height))
-            {
-              clutter_actor_queue_relayout (CLUTTER_ACTOR (stage));
-            }
-
-          /* If we're fullscreened, we want these variables to
-           * represent the size of the window before it was set
-           * to fullscreen.
-           */
-          if (!(stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN))
-            {
-              stage_x11->xwin_width = xevent->xconfigure.width;
-              stage_x11->xwin_height = xevent->xconfigure.height;
-            }
-
-          clutter_actor_set_size (CLUTTER_ACTOR (stage),
-                                  xevent->xconfigure.width,
-                                  xevent->xconfigure.height);
-
-          /* XXX: This is a workaround for a race condition when
-           * resizing windows while there are in-flight
-           * glXCopySubBuffer blits happening.
-           *
-           * The problem stems from the fact that rectangles for the
-           * blits are described relative to the bottom left of the
-           * window and because we can't guarantee control over the X
-           * window gravity used when resizing so the gravity is
-           * typically NorthWest not SouthWest.
-           *
-           * This means if you grow a window vertically the server
-           * will make sure to place the old contents of the window
-           * at the top-left/north-west of your new larger window, but
-           * that may happen asynchronous to GLX preparing to do a
-           * blit specified relative to the bottom-left/south-west of
-           * the window (based on the old smaller window geometry).
-           *
-           * When the GLX issued blit finally happens relative to the
-           * new bottom of your window, the destination will have
-           * shifted relative to the top-left where all the pixels you
-           * care about are so it will result in a nasty artefact
-           * making resizing look very ugly!
-           *
-           * We can't currently fix this completely, in-part because
-           * the window manager tends to trample any gravity we might
-           * set.  This workaround instead simply disables blits for a
-           * while if we are notified of any resizes happening so if
-           * the user is resizing a window via the window manager then
-           * they may see an artefact for one frame but then we will
-           * fallback to redrawing the full stage until the cooling
-           * off period is over.
-           */
-          if (stage_x11->clipped_redraws_cool_off)
-            g_source_remove (stage_x11->clipped_redraws_cool_off);
-          stage_x11->clipped_redraws_cool_off =
-            g_timeout_add_seconds (1, clipped_redraws_cool_off_cb, stage_x11);
-
-          CLUTTER_UNSET_PRIVATE_FLAGS (stage_x11->wrapper,
-                                       CLUTTER_IN_RESIZE);
-
-          /* the resize process is complete, so we can ask the stage
-           * to set up the GL viewport with the new size
-           */
-          clutter_stage_ensure_viewport (stage);
-        }
-      res = FALSE;
-      break;
-
-    case PropertyNotify:
-      if (xevent->xproperty.atom == backend_x11->atom_NET_WM_STATE &&
-          xevent->xproperty.window == stage_xwindow &&
-          !stage_x11->is_foreign_xwin)
-        {
-          Atom     type;
-          gint     format;
-          gulong   n_items, bytes_after;
-          guchar  *data = NULL;
-          gboolean fullscreen_set = FALSE;
-
-          clutter_x11_trap_x_errors ();
-          XGetWindowProperty (backend_x11->xdpy, stage_xwindow,
-                              backend_x11->atom_NET_WM_STATE,
-                              0, G_MAXLONG,
-                              False, XA_ATOM,
-                              &type, &format, &n_items,
-                              &bytes_after, &data);
-          clutter_x11_untrap_x_errors ();
-
-          if (type != None && data != NULL)
-            {
-              Atom *atoms = (Atom *) data;
-              gulong i;
-              gboolean is_fullscreen = FALSE;
-
-              for (i = 0; i < n_items; i++)
-                {
-                  if (atoms[i] == backend_x11->atom_NET_WM_STATE_FULLSCREEN)
-                    fullscreen_set = TRUE;
-                }
-
-              is_fullscreen =
-                (stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN);
-
-              if (fullscreen_set != is_fullscreen)
-                {
-                  if (fullscreen_set)
-                    stage_x11->state |= CLUTTER_STAGE_STATE_FULLSCREEN;
-                  else
-                    stage_x11->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN;
-
-                  stage_x11->fullscreening = fullscreen_set;
-
-                  event->type = CLUTTER_STAGE_STATE;
-                  event->stage_state.changed_mask =
-                    CLUTTER_STAGE_STATE_FULLSCREEN;
-                  event->stage_state.new_state = stage_x11->state;
-                }
-              else
-                res = FALSE;
-
-              XFree (data);
-            }
-          else
-            res = FALSE;
-        }
-      else
-        res = FALSE;
-      break;
-
-    case MapNotify:
-      res = FALSE;
-      break;
-
-    case UnmapNotify:
-      res = FALSE;
-      break;
-
-    case FocusIn:
-      if (!(stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED))
-        {
-          /* TODO: check xevent->xfocus.detail ? */
-          stage_x11->state |= CLUTTER_STAGE_STATE_ACTIVATED;
-
-          event->type = CLUTTER_STAGE_STATE;
-          event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
-          event->stage_state.new_state = stage_x11->state;
-        }
-      else
-        res = FALSE;
-      break;
-
-    case FocusOut:
-      if (stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED)
-        {
-          stage_x11->state &= ~CLUTTER_STAGE_STATE_ACTIVATED;
-
-          event->type = CLUTTER_STAGE_STATE;
-          event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
-          event->stage_state.new_state = stage_x11->state;
-        }
-      else
-        res = FALSE;
-      break;
-
-    case Expose:
-      {
-        XExposeEvent *expose = (XExposeEvent *)xevent;
-        ClutterPaintVolume clip;
-        ClutterVertex origin;
-
-        CLUTTER_NOTE (MULTISTAGE, "expose for stage: %p, redrawing", stage);
-        CLUTTER_NOTE (MULTISTAGE,
-                      "expose for stage: %p, "
-                      "redrawing (x=%d, y=%d, width=%d, height=%d)",
-                      stage,
-                      expose->x,
-                      expose->y,
-                      expose->width,
-                      expose->height);
-
-        origin.x = expose->x;
-        origin.y = expose->y;
-        origin.z = 0;
-
-        _clutter_paint_volume_init_static (CLUTTER_ACTOR (stage), &clip);
-
-        clutter_paint_volume_set_origin (&clip, &origin);
-        clutter_paint_volume_set_width (&clip, expose->width);
-        clutter_paint_volume_set_height (&clip, expose->height);
-
-        _clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), 0, &clip);
-
-        clutter_paint_volume_free (&clip);
-
-        res = FALSE;
-      }
-      break;
-    case DestroyNotify:
-      CLUTTER_NOTE (EVENT, "destroy notify:\txid: %ld",
-                    xevent->xdestroywindow.window);
-      if (xevent->xdestroywindow.window == stage_xwindow &&
-          !stage_x11->is_foreign_xwin)
-        event->type = event->any.type = CLUTTER_DESTROY_NOTIFY;
-      else
-        res = FALSE;
-      break;
-
-    case ClientMessage:
-      CLUTTER_NOTE (EVENT, "client message");
-
-      event->type = event->any.type = CLUTTER_CLIENT_MESSAGE;
-
-      if (xevent->xclient.message_type == backend_x11->atom_XEMBED)
-        res = handle_xembed_event (backend_x11, xevent);
-      else if (xevent->xclient.message_type == backend_x11->atom_WM_PROTOCOLS)
-        {
-          res = handle_wm_protocols_event (backend_x11, stage_xwindow, xevent);
-          event->type = event->any.type = CLUTTER_DELETE;
-        }
-      break;
-
-    case KeyPress:
-      event->key.type = event->type = CLUTTER_KEY_PRESS;
-      event->key.device =
-        clutter_device_manager_get_core_device (manager,
-                                                CLUTTER_KEYBOARD_DEVICE);
-
-      translate_key_event (backend_x11, event, xevent);
-
-      set_user_time (backend_x11, &xwindow, xevent->xkey.time);
-      break;
-              
-    case KeyRelease:
-      /* old-style X11 terminals require that even modern X11 send
-       * KeyPress/KeyRelease pairs when auto-repeating. for this
-       * reason modern(-ish) API like XKB has a way to detect
-       * auto-repeat and do a single KeyRelease at the end of a
-       * KeyPress sequence.
-       *
-       * this check emulates XKB's detectable auto-repeat; we peek
-       * the next event and check if it's a KeyPress for the same key
-       * and timestamp - and then ignore it if it matches the
-       * KeyRelease
-       *
-       * if we have XKB, and autorepeat is enabled, then this becomes
-       * a no-op
-       */
-      if (!backend_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
-        {
-          XEvent next_event;
-
-          XPeekEvent (xevent->xkey.display, &next_event);
-
-          if (next_event.type == KeyPress &&
-              next_event.xkey.keycode == xevent->xkey.keycode &&
-              next_event.xkey.time == xevent->xkey.time)
-            {
-              res = FALSE;
-              break;
-            }
-        }
-
-      event->key.type = event->type = CLUTTER_KEY_RELEASE;
-      event->key.device =
-        clutter_device_manager_get_core_device (manager,
-                                                CLUTTER_KEYBOARD_DEVICE);
-
-      translate_key_event (backend_x11, event, xevent);
-      break;
-
-    default:
-      /* ignore every other event */
-      not_yet_handled = TRUE;
-      break;
-    }
-
-  /* Input device event handling.. */
-  if (not_yet_handled)
-    {
-      device = clutter_device_manager_get_core_device (manager,
-                                                       CLUTTER_POINTER_DEVICE);
-
-      /* Regular X event */
-      switch (xevent->type)
-        {
-        case ButtonPress:
-          switch (xevent->xbutton.button)
-            {
-            case 4: /* up */
-            case 5: /* down */
-            case 6: /* left */
-            case 7: /* right */
-              event->scroll.type = event->type = CLUTTER_SCROLL;
-
-              if (xevent->xbutton.button == 4)
-                event->scroll.direction = CLUTTER_SCROLL_UP;
-              else if (xevent->xbutton.button == 5)
-                event->scroll.direction = CLUTTER_SCROLL_DOWN;
-              else if (xevent->xbutton.button == 6)
-                event->scroll.direction = CLUTTER_SCROLL_LEFT;
-              else
-                event->scroll.direction = CLUTTER_SCROLL_RIGHT;
-
-              event->scroll.time = xevent->xbutton.time;
-              event->scroll.x = xevent->xbutton.x;
-              event->scroll.y = xevent->xbutton.y;
-              event->scroll.modifier_state = xevent->xbutton.state;
-              event->scroll.device = device;
-              break;
-
-            default:
-              event->button.type = event->type = CLUTTER_BUTTON_PRESS;
-              event->button.time = xevent->xbutton.time;
-              event->button.x = xevent->xbutton.x;
-              event->button.y = xevent->xbutton.y;
-              event->button.modifier_state = xevent->xbutton.state;
-              event->button.button = xevent->xbutton.button;
-              event->button.device = device;
-              break;
-            }
-
-          set_user_time (backend_x11, &xwindow, event->button.time);
-
-          res = TRUE;
-          break;
-
-        case ButtonRelease:
-          /* scroll events don't have a corresponding release */
-          if (xevent->xbutton.button == 4 ||
-              xevent->xbutton.button == 5 ||
-              xevent->xbutton.button == 6 ||
-              xevent->xbutton.button == 7)
-            {
-              res = FALSE;
-              goto out;
-            }
-
-          event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
-          event->button.time = xevent->xbutton.time;
-          event->button.x = xevent->xbutton.x;
-          event->button.y = xevent->xbutton.y;
-          event->button.modifier_state = xevent->xbutton.state;
-          event->button.button = xevent->xbutton.button;
-          event->button.device = device;
-
-          res = TRUE;
-          break;
-
-        case MotionNotify:
-          event->motion.type = event->type = CLUTTER_MOTION;
-          event->motion.time = xevent->xmotion.time;
-          event->motion.x = xevent->xmotion.x;
-          event->motion.y = xevent->xmotion.y;
-          event->motion.modifier_state = xevent->xmotion.state;
-          event->motion.device = device;
-
-          res = TRUE;
-          break;
-
-        case EnterNotify:
-          /* we know that we are entering the stage here */
-          _clutter_input_device_set_stage (device, stage);
-          CLUTTER_NOTE (EVENT, "Entering the stage");
-
-          /* Convert enter notifies to motion events because X
-             doesn't emit the corresponding motion notify */
-          event->motion.type = event->type = CLUTTER_MOTION;
-          event->motion.time = xevent->xcrossing.time;
-          event->motion.x = xevent->xcrossing.x;
-          event->motion.y = xevent->xcrossing.y;
-          event->motion.modifier_state = xevent->xcrossing.state;
-          event->motion.source = CLUTTER_ACTOR (stage);
-          event->motion.device = device;
-
-          res = TRUE;
-          break;
-
-        case LeaveNotify:
-          if (device->stage == NULL)
-            {
-              CLUTTER_NOTE (EVENT,
-                            "Discarding LeaveNotify for ButtonRelease "
-                            "event off-stage");
-              res = FALSE;
-              goto out;
-            }
-
-          /* we know that we are leaving the stage here */
-          _clutter_input_device_set_stage (device, NULL);
-          CLUTTER_NOTE (EVENT, "Leaving the stage (time:%u)",
-                        event->crossing.time);
-
-          event->crossing.type = event->type = CLUTTER_LEAVE;
-          event->crossing.time = xevent->xcrossing.time;
-          event->crossing.x = xevent->xcrossing.x;
-          event->crossing.y = xevent->xcrossing.y;
-          event->crossing.source = CLUTTER_ACTOR (stage);
-          event->crossing.device = device;
-          res = TRUE;
-          break;
-
-        default:
-          res = FALSE;
-          break;
-        }
-    }
-
-    /* XInput fun...*/
-  if (!res && clutter_x11_has_xinput ())
-    {
-#ifdef HAVE_XINPUT
-      int *ev_types = backend_x11->event_types;
-      int button_press, button_release;
-      int key_press, key_release;
-      int motion_notify;
-
-      button_press   = ev_types[CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT];
-      button_release = ev_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT];
-      motion_notify  = ev_types[CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT];
-      key_press      = ev_types[CLUTTER_X11_XINPUT_KEY_PRESS_EVENT];
-      key_release    = ev_types[CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT];
-
-      CLUTTER_NOTE (EVENT, "XInput event type: %d", xevent->type);
-
-      if (xevent->type == button_press)
-        {
-          XDeviceButtonEvent *xbev = (XDeviceButtonEvent *) xevent;
-
-          device = _clutter_x11_get_device_for_xid (xbev->deviceid);
-          _clutter_input_device_set_stage (device, stage);
-
-          CLUTTER_NOTE (EVENT,
-                        "XI ButtonPress for %li ('%s') at %d, %d",
-                        xbev->deviceid,
-                        device->device_name,
-                        xbev->x,
-                        xbev->y);
-
-          switch (xbev->button)
-            {
-            case 4:
-            case 5:
-            case 6:
-            case 7:
-              event->scroll.type = event->type = CLUTTER_SCROLL;
-
-              if (xbev->button == 4)
-                event->scroll.direction = CLUTTER_SCROLL_UP;
-              else if (xbev->button == 5)
-                event->scroll.direction = CLUTTER_SCROLL_DOWN;
-              else if (xbev->button == 6)
-                event->scroll.direction = CLUTTER_SCROLL_LEFT;
-              else
-                event->scroll.direction = CLUTTER_SCROLL_RIGHT;
-
-              event->scroll.time = xbev->time;
-              event->scroll.x = xbev->x;
-              event->scroll.y = xbev->y;
-              event->scroll.modifier_state = xbev->state;
-              event->scroll.device = device;
-              break;
-
-            default:
-              event->button.type = event->type = CLUTTER_BUTTON_PRESS;
-              event->button.time = xbev->time;
-              event->button.x = xbev->x;
-              event->button.y = xbev->y;
-              event->button.modifier_state = xbev->state;
-              event->button.button = xbev->button;
-              event->button.device = device;
-              break;
-            }
-
-          set_user_time (backend_x11, &xwindow, xbev->time);
-
-          res = TRUE;
-        }
-      else if (xevent->type == button_release)
-        {
-          XDeviceButtonEvent *xbev = (XDeviceButtonEvent *)xevent;
-
-          device = _clutter_x11_get_device_for_xid (xbev->deviceid);
-          _clutter_input_device_set_stage (device, stage);
-
-          CLUTTER_NOTE (EVENT, "XI ButtonRelease for %li ('%s') at %d, %d",
-                        xbev->deviceid,
-                        device->device_name,
-                        xbev->x,
-                        xbev->y);
-
-          /* scroll events don't have a corresponding release */
-          if (xbev->button == 4 ||
-              xbev->button == 5 ||
-              xbev->button == 6 ||
-              xbev->button == 7)
-            {
-              res = FALSE;
-              goto out;
-            }
-
-          event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
-          event->button.time = xbev->time;
-          event->button.x = xbev->x;
-          event->button.y = xbev->y;
-          event->button.modifier_state = xbev->state;
-          event->button.button = xbev->button;
-          event->button.device = device;
-
-          res = TRUE;
-        }
-      else if (xevent->type == motion_notify)
-        {
-          XDeviceMotionEvent *xmev = (XDeviceMotionEvent *)xevent;
-
-          device = _clutter_x11_get_device_for_xid (xmev->deviceid);
-          _clutter_input_device_set_stage (device, stage);
-
-          CLUTTER_NOTE (EVENT, "XI Motion for %li ('%s') at %d, %d",
-                        xmev->deviceid,
-                        device->device_name,
-                        xmev->x,
-                        xmev->y);
-
-          event->motion.type = event->type = CLUTTER_MOTION;
-          event->motion.time = xmev->time;
-          event->motion.x = xmev->x;
-          event->motion.y = xmev->y;
-          event->motion.modifier_state = xmev->state;
-          event->motion.device = device;
-
-          res = TRUE;
-        }
-      else if (xevent->type == key_press || xevent->type == key_release)
-        {
-          /* the XInput 1.x handling of key presses/releases is broken:
-           * it makes key repeat, key presses and releases outside the
-           * window not generate events even when the window has focus
-           */
-          XDeviceKeyEvent *xkev = (XDeviceKeyEvent *) xevent;
-          XEvent xevent_converted;
-
-          convert_xdevicekey_to_xkey (xkev, &xevent_converted);
-
-          event->key.type = event->type = (xevent->type == key_press)
-                                          ? CLUTTER_KEY_PRESS
-                                          : CLUTTER_KEY_RELEASE;
-
-          translate_key_event (backend_x11, event, &xevent_converted);
-
-          if (xevent->type == key_press)
-            set_user_time (backend_x11, &xwindow, xkev->time);
-        }
-      else
-#endif /* HAVE_XINPUT */
-        {
-          CLUTTER_NOTE (EVENT, "Uknown Event");
-          res = FALSE;
-        }
-    }
-
-out:
-  return res;
-}
-
-static void
 events_queue (ClutterBackend *backend)
 {
   ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
-  ClutterBackendX11Class *backend_x11_class =
-    CLUTTER_BACKEND_X11_GET_CLASS (backend_x11);
-  ClutterEvent      *event;
-  Display           *xdisplay = backend_x11->xdpy;
-  XEvent             xevent;
-  ClutterMainContext  *clutter_context;
-
-  clutter_context = _clutter_context_get_default ();
+  Display *xdisplay = backend_x11->xdpy;
+  ClutterEvent *event;
+  XEvent xevent;
 
   while (!clutter_events_pending () && XPending (xdisplay))
     {
       XNextEvent (xdisplay, &xevent);
 
-      if (backend_x11_class->handle_event (backend_x11, &xevent))
-        continue;
-
       event = clutter_event_new (CLUTTER_NOTHING);
 
-      if (event_translate (backend, event, &xevent))
-        {
-         /* push directly here to avoid copy of queue_put */
-         g_queue_push_head (clutter_context->events_queue, event);
-        }
+      if (_clutter_backend_translate_event (backend, &xevent, event))
+        _clutter_event_push (event, FALSE);
       else
         clutter_event_free (event);
     }
@@ -1192,12 +272,10 @@ events_queue (ClutterBackend *backend)
 ClutterX11FilterReturn
 clutter_x11_handle_event (XEvent *xevent)
 {
-  ClutterBackend      *backend;
-  ClutterBackendX11Class *backend_x11_class;
-  ClutterEvent        *event;
-  ClutterMainContext  *clutter_context;
   ClutterX11FilterReturn result;
-  gint                 spin = 1;
+  ClutterBackend *backend;
+  ClutterEvent *event;
+  gint spin = 1;
 
   /* The return values here are someone approximate; we return
    * CLUTTER_X11_FILTER_REMOVE if a clutter event is
@@ -1212,23 +290,15 @@ clutter_x11_handle_event (XEvent *xevent)
 
   clutter_threads_enter ();
 
-  clutter_context = _clutter_context_get_default ();
-  backend = clutter_context->backend;
-  backend_x11_class = CLUTTER_BACKEND_X11_GET_CLASS (backend);
-
-  /* If the backend just observed the event and didn't want it
-   * removed it could return FALSE, so assume that a TRUE return
-   * means that our caller should also do no further processing. */
-  if (backend_x11_class->handle_event (CLUTTER_BACKEND_X11(backend), xevent))
-    return CLUTTER_X11_FILTER_REMOVE;
+  backend = clutter_get_default_backend ();
 
   event = clutter_event_new (CLUTTER_NOTHING);
 
-  if (event_translate (backend, event, xevent))
+  if (_clutter_backend_translate_event (backend, xevent, event))
     {
-      /* push directly here to avoid copy of queue_put */
+      _clutter_event_push (event, FALSE);
+
       result = CLUTTER_X11_FILTER_REMOVE;
-      g_queue_push_head (clutter_context->events_queue, event);
     }
   else
     {
@@ -1253,7 +323,7 @@ clutter_x11_handle_event (XEvent *xevent)
       --spin;
     }
 
- out:
+out:
   clutter_threads_leave ();
 
   return result;
@@ -1312,8 +382,7 @@ clutter_event_dispatch (GSource     *source,
 
   /* Pop an event off the queue if any */
   event = clutter_event_get ();
-
-  if (event)
+  if (event != NULL)
     {
       /* forward the event into clutter for emission etc. */
       clutter_do_event (event);
@@ -1326,7 +395,7 @@ clutter_event_dispatch (GSource     *source,
 }
 
 /**
- * clutter_x11_get_current_event_time:
+ * clutter_x11_get_current_event_time: (skip)
  *
  * Retrieves the timestamp of the last X11 event processed by
  * Clutter. This might be different from the timestamp returned
diff --git a/clutter/x11/clutter-input-device-core-x11.c b/clutter/x11/clutter-input-device-core-x11.c
new file mode 100644 (file)
index 0000000..216bddc
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright © 2010, 2011  Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+#include "config.h"
+
+#include "clutter-input-device-core-x11.h"
+
+#include "clutter-debug.h"
+#include "clutter-device-manager-private.h"
+#include "clutter-private.h"
+#include "clutter-stage-private.h"
+
+#include "clutter-backend-x11.h"
+#include "clutter-stage-x11.h"
+
+#ifdef HAVE_XINPUT
+#include <X11/extensions/XInput.h>
+#endif
+
+#define MAX_DEVICE_CLASSES      13
+
+typedef struct _ClutterInputDeviceClass         ClutterInputDeviceX11Class;
+
+/* a specific X11 input device */
+struct _ClutterInputDeviceX11
+{
+  ClutterInputDevice device;
+
+#ifdef HAVE_XINPUT
+  XDevice *xdevice;
+
+  XEventClass event_classes[MAX_DEVICE_CLASSES];
+  int num_classes;
+
+  int button_press_type;
+  int button_release_type;
+  int motion_notify_type;
+  int state_notify_type;
+  int key_press_type;
+  int key_release_type;
+#endif /* HAVE_XINPUT */
+
+  gint *axis_data;
+
+  gint min_keycode;
+  gint max_keycode;
+};
+
+#define clutter_input_device_x11_get_type       _clutter_input_device_x11_get_type
+
+G_DEFINE_TYPE (ClutterInputDeviceX11,
+               clutter_input_device_x11,
+               CLUTTER_TYPE_INPUT_DEVICE);
+
+static void
+clutter_input_device_x11_select_stage_events (ClutterInputDevice *device,
+                                              ClutterStage       *stage,
+                                              gint                event_mask)
+{
+#if HAVE_XINPUT
+  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (device->backend);
+  ClutterInputDeviceX11 *device_x11;
+  ClutterStageX11 *stage_x11;
+  XEventClass class;
+  gint i;
+
+  device_x11 = CLUTTER_INPUT_DEVICE_X11 (device);
+
+  stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage));
+
+  i = 0;
+
+  if (event_mask & ButtonPressMask)
+    {
+      DeviceButtonPress (device_x11->xdevice,
+                         device_x11->button_press_type,
+                         class);
+      if (class != 0)
+        device_x11->event_classes[i++] = class;
+
+      DeviceButtonPressGrab (device_x11->xdevice, 0, class);
+      if (class != 0)
+        device_x11->event_classes[i++] = class;
+    }
+
+  if (event_mask & ButtonReleaseMask)
+    {
+      DeviceButtonRelease (device_x11->xdevice,
+                           device_x11->button_release_type,
+                           class);
+      if (class != 0)
+        device_x11->event_classes[i++] = class;
+    }
+
+  if (event_mask & PointerMotionMask)
+    {
+      DeviceMotionNotify (device_x11->xdevice,
+                          device_x11->motion_notify_type,
+                          class);
+      if (class != 0)
+        device_x11->event_classes[i++] = class;
+
+      DeviceStateNotify (device_x11->xdevice,
+                         device_x11->state_notify_type,
+                         class);
+      if (class != 0)
+        device_x11->event_classes[i++] = class;
+    }
+
+  if (event_mask & KeyPressMask)
+    {
+      DeviceKeyPress (device_x11->xdevice,
+                      device_x11->key_press_type,
+                      class);
+      if (class != 0)
+        device_x11->event_classes[i++] = class;
+    }
+
+  if (event_mask & KeyReleaseMask)
+    {
+      DeviceKeyRelease (device_x11->xdevice,
+                        device_x11->key_release_type,
+                        class);
+      if (class != 0)
+        device_x11->event_classes[i++] = class;
+    }
+
+  device_x11->num_classes = i;
+
+  XSelectExtensionEvent (backend_x11->xdpy,
+                         stage_x11->xwin,
+                         device_x11->event_classes,
+                         device_x11->num_classes);
+#endif /* HAVE_XINPUT */
+}
+
+static void
+clutter_input_device_x11_dispose (GObject *gobject)
+{
+  ClutterInputDeviceX11 *device_x11 = CLUTTER_INPUT_DEVICE_X11 (gobject);
+
+#ifdef HAVE_XINPUT
+  if (device_x11->xdevice)
+    {
+      ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (gobject);
+      ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (device->backend);
+
+      XCloseDevice (backend_x11->xdpy, device_x11->xdevice);
+      device_x11->xdevice = NULL;
+    }
+#endif /* HAVE_XINPUT */
+
+  g_free (device_x11->axis_data);
+
+  G_OBJECT_CLASS (clutter_input_device_x11_parent_class)->dispose (gobject);
+}
+
+static void
+clutter_input_device_x11_constructed (GObject *gobject)
+{
+#ifdef HAVE_XINPUT
+  ClutterInputDeviceX11 *device_x11 = CLUTTER_INPUT_DEVICE_X11 (gobject);
+  ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (gobject);
+  ClutterBackendX11 *backend_x11;
+
+  backend_x11 = CLUTTER_BACKEND_X11 (device->backend);
+
+  clutter_x11_trap_x_errors ();
+
+  device_x11->xdevice = XOpenDevice (backend_x11->xdpy, device->id);
+
+  if (clutter_x11_untrap_x_errors ())
+    {
+      g_warning ("Device '%s' cannot be opened",
+                 clutter_input_device_get_device_name (device));
+    }
+#endif /* HAVE_XINPUT */
+
+  if (G_OBJECT_CLASS (clutter_input_device_x11_parent_class)->constructed)
+    G_OBJECT_CLASS (clutter_input_device_x11_parent_class)->constructed (gobject);
+}
+
+static void
+clutter_input_device_x11_class_init (ClutterInputDeviceX11Class *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterInputDeviceClass *device_class = CLUTTER_INPUT_DEVICE_CLASS (klass);
+
+  gobject_class->constructed = clutter_input_device_x11_constructed;
+  gobject_class->dispose = clutter_input_device_x11_dispose;
+
+  device_class->select_stage_events = clutter_input_device_x11_select_stage_events;
+}
+
+static void
+clutter_input_device_x11_init (ClutterInputDeviceX11 *self)
+{
+}
+
+#ifdef HAVE_XINPUT
+static void
+update_axes (ClutterInputDeviceX11 *device_x11,
+             guint                  n_axes,
+             gint                   first_axis,
+             gint                  *axes_data)
+{
+  ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (device_x11);
+  gint i;
+
+  if (device_x11->axis_data == NULL)
+    {
+      device_x11->axis_data =
+        g_new0 (gint, clutter_input_device_get_n_axes (device));
+    }
+
+  for (i = 0; i < n_axes; i++)
+    device_x11->axis_data[first_axis + i] = axes_data[i];
+}
+
+static gdouble *
+translate_axes (ClutterInputDeviceX11 *device_x11,
+                ClutterStageX11       *stage_x11,
+                gfloat                *event_x,
+                gfloat                *event_y)
+{
+  ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (device_x11);
+  gint root_x, root_y;
+  gint n_axes, i;
+  gdouble x, y;
+  gdouble *retval;
+
+  if (!_clutter_stage_x11_get_root_coords (stage_x11, &root_x, &root_y))
+    return NULL;
+
+  x = y = 0.0f;
+  n_axes = clutter_input_device_get_n_axes (device);
+
+  retval = g_new0 (gdouble, n_axes);
+
+  for (i = 0; i < n_axes; i++)
+    {
+      ClutterInputAxis axis;
+
+      axis = clutter_input_device_get_axis (device, i);
+      switch (axis)
+        {
+        case CLUTTER_INPUT_AXIS_X:
+        case CLUTTER_INPUT_AXIS_Y:
+          _clutter_x11_input_device_translate_screen_coord (device,
+                                                            root_x, root_y,
+                                                            i,
+                                                            device_x11->axis_data[i],
+                                                            &retval[i]);
+          if (axis == CLUTTER_INPUT_AXIS_X)
+            x = retval[i];
+          else if (axis == CLUTTER_INPUT_AXIS_Y)
+            y = retval[i];
+          break;
+
+        default:
+          _clutter_input_device_translate_axis (device, i,
+                                                device_x11->axis_data[i],
+                                                &retval[i]);
+          break;
+        }
+    }
+
+  if (event_x)
+    *event_x = x;
+
+  if (event_y)
+    *event_y = y;
+
+  return retval;
+}
+
+/*
+ * translate_state:
+ * @state: the keyboard state of the core device
+ * @device_state: the button state of the device
+ *
+ * Trivially translates the state and the device state into a
+ * single bitmask.
+ */
+static guint
+translate_state (guint state,
+                 guint device_state)
+{
+  return device_state | (state & 0xff);
+}
+#endif /* HAVE_XINPUT */
+
+gboolean
+_clutter_input_device_x11_translate_xi_event (ClutterInputDeviceX11 *device_x11,
+                                              ClutterStageX11       *stage_x11,
+                                              XEvent                *xevent,
+                                              ClutterEvent          *event)
+{
+#ifdef HAVE_XINPUT
+  ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (device_x11);
+
+  if ((xevent->type == device_x11->button_press_type) ||
+      (xevent->type == device_x11->button_release_type))
+    {
+      XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *) xevent;
+
+      event->button.type = event->type =
+        (xdbe->type == device_x11->button_press_type) ? CLUTTER_BUTTON_PRESS
+                                                      : CLUTTER_BUTTON_RELEASE;
+      event->button.device = device;
+      event->button.time = xdbe->time;
+      event->button.button = xdbe->button;
+      event->button.modifier_state =
+        translate_state (xdbe->state, xdbe->device_state);
+
+      update_axes (device_x11,
+                   xdbe->axes_count,
+                   xdbe->first_axis,
+                   xdbe->axis_data);
+
+      event->button.axes = translate_axes (device_x11, stage_x11,
+                                           &event->button.x,
+                                           &event->button.y);
+
+      _clutter_stage_x11_set_user_time (stage_x11, event->button.time);
+
+      return TRUE;
+    }
+
+  if ((xevent->type == device_x11->key_press_type) ||
+      (xevent->type == device_x11->key_release_type))
+    {
+      XDeviceKeyEvent *xdke = (XDeviceKeyEvent *) xevent;
+
+      if (xdke->keycode < device_x11->min_keycode ||
+          xdke->keycode >= device_x11->max_keycode)
+        {
+          g_warning ("Invalid device key code received: %d", xdke->keycode);
+          return FALSE;
+        }
+
+      clutter_input_device_get_key (device,
+                                    xdke->keycode - device_x11->min_keycode,
+                                    &event->key.keyval,
+                                    &event->key.modifier_state);
+      if (event->key.keyval == 0)
+        return FALSE;
+
+      event->key.type = event->type =
+        (xdke->type == device_x11->key_press_type) ? CLUTTER_KEY_PRESS
+                                                   : CLUTTER_KEY_RELEASE;
+      event->key.time = xdke->time;
+      event->key.modifier_state |=
+        translate_state (xdke->state, xdke->device_state);
+      event->key.device = device;
+
+#if 0
+      if ((event->key.keyval >= 0x20) && (event->key.keyval <= 0xff))
+        {
+          event->key.unicode = (gunichar) event->key.keyval;
+        }
+#endif
+
+      _clutter_stage_x11_set_user_time (stage_x11, event->key.time);
+
+      return TRUE;
+    }
+
+  if (xevent->type == device_x11->motion_notify_type)
+    {
+      XDeviceMotionEvent *xdme = (XDeviceMotionEvent *) xevent;
+
+      event->motion.type = event->type = CLUTTER_MOTION;
+      event->motion.time = xdme->time;
+      event->motion.modifier_state =
+        translate_state (xdme->state, xdme->device_state);
+      event->motion.device = device;
+
+      event->motion.axes =
+        g_new0 (gdouble, clutter_input_device_get_n_axes (device));
+
+      update_axes (device_x11,
+                   xdme->axes_count,
+                   xdme->first_axis,
+                   xdme->axis_data);
+
+      event->motion.axes = translate_axes (device_x11, stage_x11,
+                                           &event->motion.x,
+                                           &event->motion.y);
+
+      return TRUE;
+    }
+
+  if (xevent->type == device_x11->state_notify_type)
+    {
+      XDeviceStateNotifyEvent *xdse = (XDeviceStateNotifyEvent *) xevent;
+      XInputClass *input_class = (XInputClass *) xdse->data;
+      gint n_axes = clutter_input_device_get_n_axes (device);
+      int i;
+
+      for (i = 0; i < xdse->num_classes; i++)
+        {
+          if (input_class->class == ValuatorClass)
+            {
+              int *axis_data = ((XValuatorState *) input_class)->valuators;
+
+              update_axes (device_x11, n_axes, 0, axis_data);
+            }
+
+          input_class =
+            (XInputClass *)(((char *) input_class) + input_class->length);
+        }
+    }
+#endif /* HAVE_XINPUT */
+
+  return FALSE;
+}
diff --git a/clutter/x11/clutter-input-device-core-x11.h b/clutter/x11/clutter-input-device-core-x11.h
new file mode 100644 (file)
index 0000000..14354df
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright © 2010, 2011  Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+#ifndef __CLUTTER_INPUT_DEVICE_X11_H__
+#define __CLUTTER_INPUT_DEVICE_X11_H__
+
+#include <clutter/clutter-input-device.h>
+#include <X11/Xlib.h>
+
+#include "clutter-stage-x11.h"
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_INPUT_DEVICE_X11           (_clutter_input_device_x11_get_type ())
+#define CLUTTER_INPUT_DEVICE_X11(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE_X11, ClutterInputDeviceX11))
+#define CLUTTER_IS_INPUT_DEVICE_X11(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE_X11))
+
+typedef struct _ClutterInputDeviceX11           ClutterInputDeviceX11;
+
+GType _clutter_input_device_x11_get_type (void) G_GNUC_CONST;
+
+gboolean _clutter_input_device_x11_translate_xi_event (ClutterInputDeviceX11 *device_x11,
+                                                       ClutterStageX11       *stage_x11,
+                                                       XEvent                *xevent,
+                                                       ClutterEvent          *event);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_INPUT_DEVICE_X11_H__ */
diff --git a/clutter/x11/clutter-input-device-x11.c b/clutter/x11/clutter-input-device-x11.c
deleted file mode 100644 (file)
index 342950c..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "clutter-input-device-x11.h"
-
-#include "clutter-debug.h"
-#include "clutter-device-manager-private.h"
-#include "clutter-private.h"
-
-#ifdef HAVE_XINPUT
-#include <X11/extensions/XInput.h>
-#endif
-
-typedef struct _ClutterInputDeviceClass         ClutterInputDeviceX11Class;
-
-/* a specific X11 input device */
-struct _ClutterInputDeviceX11
-{
-  ClutterInputDevice device;
-
-#ifdef HAVE_XINPUT
-  XDevice           *xdevice;
-  XEventClass        xevent_list[5];   /* MAX 5 event types */
-  int                num_events;
-#endif
-
-  guint is_core : 1;
-};
-
-enum
-{
-  PROP_0,
-
-  PROP_IS_CORE,
-
-  PROP_LAST
-};
-
-static GParamSpec *obj_props[PROP_LAST];
-
-G_DEFINE_TYPE (ClutterInputDeviceX11,
-               clutter_input_device_x11,
-               CLUTTER_TYPE_INPUT_DEVICE);
-
-static void
-clutter_input_device_x11_set_property (GObject      *gobject,
-                                       guint         prop_id,
-                                       const GValue *value,
-                                       GParamSpec   *pspec)
-{
-  ClutterInputDeviceX11 *self = CLUTTER_INPUT_DEVICE_X11 (gobject);
-
-  switch (prop_id)
-    {
-    case PROP_IS_CORE:
-      self->is_core = g_value_get_boolean (value);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-clutter_input_device_x11_get_property (GObject    *gobject,
-                                       guint       prop_id,
-                                       GValue     *value,
-                                       GParamSpec *pspec)
-{
-  ClutterInputDeviceX11 *self = CLUTTER_INPUT_DEVICE_X11 (gobject);
-
-  switch (prop_id)
-    {
-    case PROP_IS_CORE:
-      g_value_set_boolean (value, self->is_core);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-clutter_input_device_x11_class_init (ClutterInputDeviceX11Class *klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GParamSpec *pspec;
-
-  gobject_class->set_property = clutter_input_device_x11_set_property;
-  gobject_class->get_property = clutter_input_device_x11_get_property;
-
-  pspec = g_param_spec_boolean ("is-core",
-                                "Is Core",
-                                "Whether the device is a core one",
-                                FALSE,
-                                CLUTTER_PARAM_READWRITE |
-                                G_PARAM_CONSTRUCT_ONLY);
-  obj_props[PROP_IS_CORE] = pspec;
-  g_object_class_install_property (gobject_class, PROP_IS_CORE, pspec);
-}
-
-static void
-clutter_input_device_x11_init (ClutterInputDeviceX11 *self)
-{
-  self->is_core = FALSE;
-}
-
-gint
-_clutter_input_device_x11_construct (ClutterInputDevice *device,
-                                     ClutterBackendX11  *backend)
-{
-  int n_events = 0;
-
-#ifdef HAVE_XINPUT
-  ClutterInputDeviceX11 *device_x11;
-  XDevice *x_device = NULL;
-  gint device_id;
-  int i;
-
-  device_x11 = CLUTTER_INPUT_DEVICE_X11 (device);
-  device_id = clutter_input_device_get_device_id (device);
-
-  clutter_x11_trap_x_errors ();
-
-  /* retrieve the X11 device */
-  x_device = XOpenDevice (backend->xdpy, device_id);
-
-  if (clutter_x11_untrap_x_errors () || x_device == NULL)
-    {
-      CLUTTER_NOTE (BACKEND, "Unable to open device %i", device_id);
-      return 0;
-    }
-
-  device_x11->xdevice = x_device;
-
-  CLUTTER_NOTE (BACKEND,
-                "Registering XINPUT device with XID: %li",
-                x_device->device_id);
-
-  /* We must go through all the classes supported by this device and
-   * register the appropriate events we want. Each class only appears
-   * once. We need to store the types with the stage since they are
-   * created dynamically by the server. They are not device specific.
-   */
-  for (i = 0; i < x_device->num_classes; i++)
-    {
-      XInputClassInfo *xclass_info = x_device->classes + i;
-      int *button_press, *button_release, *motion_notify;
-      int *key_press, *key_release;
-
-      button_press =
-        &backend->event_types[CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT];
-      button_release =
-        &backend->event_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT];
-      motion_notify =
-        &backend->event_types[CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT];
-
-      key_press =
-        &backend->event_types[CLUTTER_X11_XINPUT_KEY_PRESS_EVENT];
-      key_release =
-        &backend->event_types[CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT];
-
-      switch (xclass_info->input_class)
-        {
-        /* event though XInput 1.x is broken for keyboard-like devices
-         * it might still be useful to track them down; the core keyboard
-         * will handle the right events anyway
-         */
-        case KeyClass:
-          DeviceKeyPress (x_device,
-                          *key_press,
-                          device_x11->xevent_list[n_events]);
-          n_events++;
-
-          DeviceKeyRelease (x_device,
-                            *key_release,
-                            device_x11->xevent_list[n_events]);
-          n_events++;
-          break;
-
-        case ButtonClass:
-          DeviceButtonPress (x_device,
-                             *button_press,
-                             device_x11->xevent_list[n_events]);
-          n_events++;
-
-          DeviceButtonRelease (x_device,
-                               *button_release,
-                               device_x11->xevent_list[n_events]);
-          n_events++;
-          break;
-
-        case ValuatorClass:
-          DeviceMotionNotify (x_device,
-                              *motion_notify,
-                              device_x11->xevent_list[n_events]);
-          n_events++;
-          break;
-        }
-    }
-
-  device_x11->num_events = n_events;
-#endif /* HAVE_XINPUT */
-
-  return n_events;
-}
-
-void
-_clutter_input_device_x11_select_events (ClutterInputDevice *device,
-                                         ClutterBackendX11  *backend_x11,
-                                         Window              xwin)
-{
-#if HAVE_XINPUT
-  ClutterInputDeviceX11 *device_x11;
-
-  device_x11 = CLUTTER_INPUT_DEVICE_X11 (device);
-
-  if (device_x11->xdevice == None || device_x11->num_events == 0)
-    return;
-
-  XSelectExtensionEvent (backend_x11->xdpy, xwin,
-                         device_x11->xevent_list,
-                         device_x11->num_events);
-#endif /* HAVE_XINPUT */
-}
diff --git a/clutter/x11/clutter-input-device-x11.h b/clutter/x11/clutter-input-device-x11.h
deleted file mode 100644 (file)
index b8d60ac..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __CLUTTER_INPUT_DEVICE_X11_H__
-#define __CLUTTER_INPUT_DEVICE_X11_H__
-
-#include <clutter/clutter-input-device.h>
-#include "clutter-backend-x11.h"
-
-G_BEGIN_DECLS
-
-#define CLUTTER_TYPE_INPUT_DEVICE_X11           (clutter_input_device_x11_get_type ())
-#define CLUTTER_INPUT_DEVICE_X11(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE_X11, ClutterInputDeviceX11))
-#define CLUTTER_IS_INPUT_DEVICE_X11(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE_X11))
-
-typedef struct _ClutterInputDeviceX11           ClutterInputDeviceX11;
-
-GType clutter_input_device_x11_get_type (void) G_GNUC_CONST;
-
-gint _clutter_input_device_x11_construct (ClutterInputDevice *device,
-                                          ClutterBackendX11  *backend);
-void _clutter_input_device_x11_select_events (ClutterInputDevice *device,
-                                              ClutterBackendX11  *backend,
-                                              Window              xwin);
-
-G_END_DECLS
-
-#endif /* __CLUTTER_INPUT_DEVICE_X11_H__ */
diff --git a/clutter/x11/clutter-input-device-xi2.c b/clutter/x11/clutter-input-device-xi2.c
new file mode 100644 (file)
index 0000000..a17d2bd
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright © 2011  Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+#include "config.h"
+
+#include "clutter-input-device-xi2.h"
+
+#include "clutter-debug.h"
+#include "clutter-device-manager-private.h"
+#include "clutter-private.h"
+#include "clutter-stage-private.h"
+
+#include "clutter-backend-x11.h"
+#include "clutter-stage-x11.h"
+
+#include <X11/extensions/XInput2.h>
+
+typedef struct _ClutterInputDeviceClass         ClutterInputDeviceXI2Class;
+
+/* a specific XI2 input device */
+struct _ClutterInputDeviceXI2
+{
+  ClutterInputDevice device;
+
+  gint device_id;
+};
+
+#define N_BUTTONS       5
+
+#define clutter_input_device_xi2_get_type       _clutter_input_device_xi2_get_type
+
+G_DEFINE_TYPE (ClutterInputDeviceXI2,
+               clutter_input_device_xi2,
+               CLUTTER_TYPE_INPUT_DEVICE);
+
+static void
+clutter_input_device_xi2_select_stage_events (ClutterInputDevice *device,
+                                              ClutterStage       *stage,
+                                              gint                event_mask)
+{
+  ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device);
+  ClutterBackendX11 *backend_x11;
+  ClutterStageX11 *stage_x11;
+  XIEventMask xi_event_mask;
+  unsigned char *mask;
+  int len;
+
+  backend_x11 = CLUTTER_BACKEND_X11 (device->backend);
+  stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage));
+
+  len = XIMaskLen (XI_LASTEVENT);
+  mask = g_new0 (unsigned char, len);
+
+  if (event_mask & PointerMotionMask)
+    XISetMask (mask, XI_Motion);
+
+  if (event_mask & ButtonPressMask)
+    XISetMask (mask, XI_ButtonPress);
+
+  if (event_mask & ButtonReleaseMask)
+    XISetMask (mask, XI_ButtonRelease);
+
+  if (event_mask & KeyPressMask)
+    XISetMask (mask, XI_KeyPress);
+
+  if (event_mask & KeyReleaseMask)
+    XISetMask (mask, XI_KeyRelease);
+
+  if (event_mask & EnterWindowMask)
+    XISetMask (mask, XI_Enter);
+
+  if (event_mask & LeaveWindowMask)
+    XISetMask (mask, XI_Leave);
+
+  xi_event_mask.deviceid = device_xi2->device_id;
+  xi_event_mask.mask = mask;
+  xi_event_mask.mask_len = len;
+
+  CLUTTER_NOTE (BACKEND, "Selecting device id '%d' events",
+                device_xi2->device_id);
+
+  XISelectEvents (backend_x11->xdpy, stage_x11->xwin, &xi_event_mask, 1);
+
+  g_free (mask);
+}
+
+static void
+clutter_input_device_xi2_constructed (GObject *gobject)
+{
+  ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (gobject);
+
+  g_object_get (gobject, "id", &device_xi2->device_id, NULL);
+
+  if (G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->constructed)
+    G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->constructed (gobject);
+}
+
+static void
+clutter_input_device_xi2_class_init (ClutterInputDeviceXI2Class *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterInputDeviceClass *device_class = CLUTTER_INPUT_DEVICE_CLASS (klass);
+
+  gobject_class->constructed = clutter_input_device_xi2_constructed;
+
+  device_class->select_stage_events = clutter_input_device_xi2_select_stage_events;
+}
+
+static void
+clutter_input_device_xi2_init (ClutterInputDeviceXI2 *self)
+{
+}
+
+guint
+_clutter_input_device_xi2_translate_state (XIModifierState *modifiers_state,
+                                           XIButtonState   *buttons_state)
+{
+  guint retval = 0;
+
+  if (modifiers_state)
+    retval = (guint) modifiers_state->effective;
+
+  if (buttons_state)
+    {
+      int len, i;
+
+      len = MIN (N_BUTTONS, buttons_state->mask_len * 8);
+
+      for (i = 0; i < len; i++)
+        {
+          if (!XIMaskIsSet (buttons_state->mask, i))
+            continue;
+
+          switch (i)
+            {
+            case 1:
+              retval |= CLUTTER_BUTTON1_MASK;
+              break;
+
+            case 2:
+              retval |= CLUTTER_BUTTON2_MASK;
+              break;
+
+            case 3:
+              retval |= CLUTTER_BUTTON3_MASK;
+              break;
+
+            case 4:
+              retval |= CLUTTER_BUTTON4_MASK;
+              break;
+
+            case 5:
+              retval |= CLUTTER_BUTTON5_MASK;
+              break;
+
+            default:
+              break;
+            }
+        }
+    }
+
+  return retval;
+}
diff --git a/clutter/x11/clutter-input-device-xi2.h b/clutter/x11/clutter-input-device-xi2.h
new file mode 100644 (file)
index 0000000..b16e172
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright © 2011  Intel Corp.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Emmanuele Bassi <ebassi@linux.intel.com>
+ */
+
+#ifndef __CLUTTER_INPUT_DEVICE_XI2_H__
+#define __CLUTTER_INPUT_DEVICE_XI2_H__
+
+#include <clutter/clutter-input-device.h>
+#include <X11/extensions/XInput2.h>
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_INPUT_DEVICE_XI2           (_clutter_input_device_xi2_get_type ())
+#define CLUTTER_INPUT_DEVICE_XI2(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE_XI2, ClutterInputDeviceXI2))
+#define CLUTTER_IS_INPUT_DEVICE_XI2(obj)        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE_XI2))
+
+typedef struct _ClutterInputDeviceXI2           ClutterInputDeviceXI2;
+
+GType _clutter_input_device_xi2_get_type (void) G_GNUC_CONST;
+
+guint _clutter_input_device_xi2_translate_state (XIModifierState *modifiers_state,
+                                                 XIButtonState   *buttons_state);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_INPUT_DEVICE_XI2_H__ */
index 33b690e..8534c62 100644 (file)
  * Author: Emmanuele Bassi <ebassi@linux.intel.com>
  */
 
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include "clutter-keymap-x11.h"
 #include "clutter-backend-x11.h"
 
 #include "clutter-debug.h"
+#include "clutter-event-translator.h"
 #include "clutter-private.h"
 
 #include <X11/Xatom.h>
 
-#ifdef HAVE_XINPUT
-#include <X11/extensions/XInput.h>
-#endif
-
 #ifdef HAVE_XKB
 #include <X11/XKBlib.h>
 #endif
@@ -58,6 +53,8 @@ struct _ClutterKeymapX11
 
 #ifdef HAVE_XKB
   XkbDescPtr xkb_desc;
+  int xkb_event_base;
+  guint xkb_map_serial;
 #endif
 
   guint caps_lock_state : 1;
@@ -78,9 +75,15 @@ enum
   PROP_LAST
 };
 
-static GParamSpec *obj_props[PROP_LAST];
+static GParamSpec *obj_props[PROP_LAST] = { NULL, };
+
+static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface);
+
+#define clutter_keymap_x11_get_type     _clutter_keymap_x11_get_type
 
-G_DEFINE_TYPE (ClutterKeymapX11, clutter_keymap_x11, G_TYPE_OBJECT);
+G_DEFINE_TYPE_WITH_CODE (ClutterKeymapX11, clutter_keymap_x11, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR,
+                                                clutter_event_translator_iface_init));
 
 #ifdef HAVE_XKB
 
@@ -154,6 +157,24 @@ get_xkb (ClutterKeymapX11 *keymap_x11)
 
       update_modmap (backend_x11->xdpy, keymap_x11);
     }
+  else if (keymap_x11->xkb_map_serial != backend_x11->keymap_serial)
+    {
+      int flags = XkbKeySymsMask
+                | XkbKeyTypesMask
+                | XkbModifierMapMask
+                | XkbVirtualModsMask;
+
+      CLUTTER_NOTE (BACKEND, "Updating XKB keymap");
+
+      XkbGetUpdatedMap (backend_x11->xdpy, flags, keymap_x11->xkb_desc);
+
+      flags = XkbGroupNamesMask | XkbVirtualModNamesMask;
+      XkbGetNames (backend_x11->xdpy, flags, keymap_x11->xkb_desc);
+
+      update_modmap (backend_x11->xdpy, keymap_x11);
+
+      keymap_x11->xkb_map_serial = backend_x11->keymap_serial;
+    }
 
   if (keymap_x11->num_lock_mask == 0)
     keymap_x11->num_lock_mask = XkbKeysymToModifiers (backend_x11->xdpy,
@@ -187,40 +208,6 @@ update_locked_mods (ClutterKeymapX11 *keymap_x11,
     g_signal_emit_by_name (keymap_x11->backend, "key-lock-changed");
 #endif
 }
-
-static ClutterX11FilterReturn
-xkb_filter (XEvent       *xevent,
-            ClutterEvent *event,
-            gpointer      data)
-{
-  ClutterBackendX11 *backend_x11 = data;
-  ClutterKeymapX11 *keymap_x11 = backend_x11->keymap;
-
-  g_assert (keymap_x11 != NULL);
-
-  if (!backend_x11->use_xkb)
-    return CLUTTER_X11_FILTER_CONTINUE;
-
-  if (xevent->type == backend_x11->xkb_event_base)
-    {
-      XkbEvent *xkb_event = (XkbEvent *) xevent;
-
-      CLUTTER_NOTE (BACKEND, "Received XKB event [%d]",
-                    xkb_event->any.xkb_type);
-
-      switch (xkb_event->any.xkb_type)
-        {
-        case XkbStateNotify:
-          update_locked_mods (keymap_x11, xkb_event->state.locked_mods);
-          break;
-
-        default:
-          break;
-        }
-    }
-
-  return CLUTTER_X11_FILTER_CONTINUE;
-}
 #endif /* HAVE_XKB */
 
 static void
@@ -232,7 +219,7 @@ clutter_keymap_x11_constructed (GObject *gobject)
   g_assert (keymap_x11->backend != NULL);
   backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend);
 
-#if HAVE_XKB
+#ifdef HAVE_XKB
   {
     gint xkb_major = XkbMajorVersion;
     gint xkb_minor = XkbMinorVersion;
@@ -243,7 +230,9 @@ clutter_keymap_x11_constructed (GObject *gobject)
         xkb_minor = XkbMinorVersion;
 
         if (XkbQueryExtension (backend_x11->xdpy,
-                               NULL, &backend_x11->xkb_event_base, NULL,
+                               NULL,
+                               &keymap_x11->xkb_event_base,
+                               NULL,
                                &xkb_major, &xkb_minor))
           {
             Bool detectable_autorepeat_supported;
@@ -258,9 +247,7 @@ clutter_keymap_x11_constructed (GObject *gobject)
             XkbSelectEventDetails (backend_x11->xdpy,
                                    XkbUseCoreKbd, XkbStateNotify,
                                    XkbAllStateComponentsMask,
-                                   XkbGroupLockMask|XkbModifierLockMask);
-
-            clutter_x11_add_filter (xkb_filter, backend_x11);
+                                   XkbGroupLockMask | XkbModifierLockMask);
 
             /* enable XKB autorepeat */
             XkbSetDetectableAutoRepeat (backend_x11->xdpy,
@@ -302,10 +289,14 @@ static void
 clutter_keymap_x11_finalize (GObject *gobject)
 {
   ClutterKeymapX11 *keymap;
+  ClutterEventTranslator *translator;
 
   keymap = CLUTTER_KEYMAP_X11 (gobject);
+  translator = CLUTTER_EVENT_TRANSLATOR (keymap);
 
 #ifdef HAVE_XKB
+  _clutter_backend_remove_event_translator (keymap->backend, translator);
+
   if (keymap->xkb_desc != NULL)
     XkbFreeKeyboard (keymap->xkb_desc, XkbAllComponentsMask, True);
 #endif
@@ -317,20 +308,18 @@ static void
 clutter_keymap_x11_class_init (ClutterKeymapX11Class *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GParamSpec *pspec;
+
+  obj_props[PROP_BACKEND] =
+    g_param_spec_object ("backend",
+                         P_("Backend"),
+                         P_("The Clutter backend"),
+                         CLUTTER_TYPE_BACKEND,
+                         CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
 
   gobject_class->constructed = clutter_keymap_x11_constructed;
   gobject_class->set_property = clutter_keymap_x11_set_property;
   gobject_class->finalize = clutter_keymap_x11_finalize;
-
-  pspec = g_param_spec_object ("backend",
-                               "Backend",
-                               "The Clutter backend",
-                               CLUTTER_TYPE_BACKEND,
-                               CLUTTER_PARAM_WRITABLE |
-                               G_PARAM_CONSTRUCT_ONLY);
-  obj_props[PROP_BACKEND] = pspec;
-  g_object_class_install_property (gobject_class, PROP_BACKEND, pspec);
+  g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
 }
 
 static void
@@ -338,6 +327,59 @@ clutter_keymap_x11_init (ClutterKeymapX11 *keymap)
 {
 }
 
+static ClutterTranslateReturn
+clutter_keymap_x11_translate_event (ClutterEventTranslator *translator,
+                                    gpointer                native,
+                                    ClutterEvent           *event)
+{
+  ClutterKeymapX11 *keymap_x11 = CLUTTER_KEYMAP_X11 (translator);
+  ClutterBackendX11 *backend_x11;
+  ClutterTranslateReturn retval;
+  XEvent *xevent;
+
+  backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend);
+  if (!backend_x11->use_xkb)
+    return CLUTTER_TRANSLATE_CONTINUE;
+
+  xevent = native;
+
+  retval = CLUTTER_TRANSLATE_CONTINUE;
+
+#ifdef HAVE_XKB
+  if (xevent->type == keymap_x11->xkb_event_base)
+    {
+      XkbEvent *xkb_event = (XkbEvent *) xevent;
+
+      switch (xkb_event->any.xkb_type)
+        {
+        case XkbStateNotify:
+          CLUTTER_NOTE (EVENT, "Updating locked modifiers");
+          update_locked_mods (keymap_x11, xkb_event->state.locked_mods);
+          retval = CLUTTER_TRANSLATE_REMOVE;
+          break;
+
+        case XkbMapNotify:
+          CLUTTER_NOTE (EVENT, "Updating keyboard mapping");
+          XkbRefreshKeyboardMapping (&xkb_event->map);
+          backend_x11->keymap_serial += 1;
+          retval = CLUTTER_TRANSLATE_REMOVE;
+          break;
+
+        default:
+          break;
+        }
+    }
+#endif /* HAVE_XKB */
+
+  return retval;
+}
+
+static void
+clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface)
+{
+  iface->translate_event = clutter_keymap_x11_translate_event;
+}
+
 gint
 _clutter_keymap_x11_get_key_group (ClutterKeymapX11    *keymap,
                                    ClutterModifierType  state)
index 34abf39..7f6b422 100644 (file)
 
 G_BEGIN_DECLS
 
-#define CLUTTER_TYPE_KEYMAP_X11         (clutter_keymap_x11_get_type ())
+#define CLUTTER_TYPE_KEYMAP_X11         (_clutter_keymap_x11_get_type ())
 #define CLUTTER_KEYMAP_X11(obj)         (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_KEYMAP_X11, ClutterKeymapX11))
 #define CLUTTER_IS_KEYMAP_X11(obj)      (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_KEYMAP_X11))
 
 typedef struct _ClutterKeymapX11        ClutterKeymapX11;
 
-GType clutter_keymap_x11_get_type (void) G_GNUC_CONST;
+GType _clutter_keymap_x11_get_type (void) G_GNUC_CONST;
 
 gint     _clutter_keymap_x11_get_key_group       (ClutterKeymapX11    *keymap,
                                                   ClutterModifierType  state);
index a3666d6..a601b36 100644 (file)
@@ -19,9 +19,9 @@
  *
  */
 
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
+
+#include <math.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 
 #include "clutter-actor-private.h"
 #include "clutter-debug.h"
-#include "clutter-main.h"
-#include "clutter-feature.h"
-#include "clutter-event.h"
+#include "clutter-device-manager-private.h"
 #include "clutter-enum-types.h"
+#include "clutter-event-translator.h"
+#include "clutter-event.h"
+#include "clutter-feature.h"
+#include "clutter-main.h"
+#include "clutter-paint-volume-private.h"
 #include "clutter-private.h"
 #include "clutter-stage-private.h"
 
 
 #define STAGE_X11_IS_MAPPED(s)  ((((ClutterStageX11 *) (s))->wm_state & STAGE_X11_WITHDRAWN) == 0)
 
-static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
+static void clutter_stage_window_iface_init     (ClutterStageWindowIface     *iface);
+static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface);
+
+static GHashTable *clutter_stages_by_xid = NULL;
+
+#define clutter_stage_x11_get_type      _clutter_stage_x11_get_type
 
 G_DEFINE_TYPE_WITH_CODE (ClutterStageX11,
                          clutter_stage_x11,
                          G_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
-                                                clutter_stage_window_iface_init));
+                                                clutter_stage_window_iface_init)
+                         G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR,
+                                                clutter_event_translator_iface_init));
 
 #define _NET_WM_STATE_REMOVE        0    /* remove/unset property */
 #define _NET_WM_STATE_ADD           1    /* add/set property */
@@ -84,9 +94,9 @@ send_wmspec_change_state (ClutterBackendX11 *backend_x11,
   xclient.data.l[4] = 0;
 
   XSendEvent (backend_x11->xdpy, 
-              DefaultRootWindow(backend_x11->xdpy), 
+              DefaultRootWindow (backend_x11->xdpy),
               False,
-              SubstructureRedirectMask|SubstructureNotifyMask,
+              SubstructureRedirectMask | SubstructureNotifyMask,
               (XEvent *)&xclient);
 }
 
@@ -114,24 +124,20 @@ update_state (ClutterStageX11   *stage_x11,
     }
 }
 
-void
+static void
 clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11,
                                    gint             new_width,
                                    gint             new_height)
 {
-  ClutterBackend *backend = clutter_get_default_backend ();
-  ClutterBackendX11 *backend_x11;
-  gboolean resize;
-
-  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
-
-  resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
 
   if (stage_x11->xwin != None && !stage_x11->is_foreign_xwin)
     {
       guint min_width, min_height;
       XSizeHints *size_hints;
+      gboolean resize;
+
+      resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
 
       size_hints = XAllocSizeHints();
 
@@ -173,17 +179,13 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11,
     }
 }
 
-void
+static void
 clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11)
 {
-  ClutterBackend *backend = clutter_get_default_backend ();
-  ClutterBackendX11 *backend_x11;
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
   Atom protocols[2];
   int n = 0;
   
-  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
-
   protocols[n++] = backend_x11->atom_WM_DELETE_WINDOW;
   protocols[n++] = backend_x11->atom_NET_WM_PING;
 
@@ -194,12 +196,8 @@ static void
 clutter_stage_x11_get_geometry (ClutterStageWindow *stage_window,
                                 ClutterGeometry    *geometry)
 {
-  ClutterBackend *backend = clutter_get_default_backend ();
-  ClutterBackendX11 *backend_x11;
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
-
-  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
 
   /* If we're fullscreen, return the size of the display. */
   if ((stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN) &&
@@ -220,9 +218,8 @@ clutter_stage_x11_resize (ClutterStageWindow *stage_window,
                           gint                width,
                           gint                height)
 {
-  ClutterBackend *backend = clutter_get_default_backend ();
-  ClutterBackendX11 *backend_x11;
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
   gboolean resize;
 
   if (stage_x11->is_foreign_xwin)
@@ -243,9 +240,6 @@ clutter_stage_x11_resize (ClutterStageWindow *stage_window,
 
   resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
 
-  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
-
   if (width == 0 || height == 0)
     {
       /* Should not happen, if this turns up we need to debug it and
@@ -289,8 +283,7 @@ clutter_stage_x11_resize (ClutterStageWindow *stage_window,
 static inline void
 set_wm_pid (ClutterStageX11 *stage_x11)
 {
-  ClutterBackend *backend = clutter_get_default_backend ();
-  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
   long pid;
 
   if (stage_x11->xwin == None || stage_x11->is_foreign_xwin)
@@ -314,11 +307,7 @@ set_wm_pid (ClutterStageX11 *stage_x11)
 static inline void
 set_wm_title (ClutterStageX11 *stage_x11)
 {
-  ClutterBackend *backend = clutter_get_default_backend ();
-  ClutterBackendX11 *backend_x11;
-
-  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
 
   if (stage_x11->xwin == None || stage_x11->is_foreign_xwin)
     return;
@@ -345,11 +334,7 @@ set_wm_title (ClutterStageX11 *stage_x11)
 static inline void
 set_cursor_visible (ClutterStageX11 *stage_x11)
 {
-  ClutterBackend *backend = clutter_get_default_backend ();
-  ClutterBackendX11 *backend_x11;
-
-  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
 
   if (stage_x11->xwin == None)
     return;
@@ -393,11 +378,68 @@ static gboolean
 clutter_stage_x11_realize (ClutterStageWindow *stage_window)
 {
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
+  ClutterDeviceManager *device_manager;
+  int event_flags;
 
   set_wm_pid (stage_x11);
   set_wm_title (stage_x11);
   set_cursor_visible (stage_x11);
 
+
+  /* the masks for the events we want to select on a stage window;
+   * KeyPressMask and KeyReleaseMask are necessary even with XI1
+   * because key events are broken with that extension, and will
+   * be fixed by XI2
+   */
+  event_flags = StructureNotifyMask
+              | FocusChangeMask
+              | ExposureMask
+              | PropertyChangeMask
+              | EnterWindowMask
+              | LeaveWindowMask
+              | KeyPressMask
+              | KeyReleaseMask
+              | ButtonPressMask
+              | ButtonReleaseMask
+              | PointerMotionMask;
+
+  /* we unconditionally select input events even with event retrieval
+   * disabled because we need to guarantee that the Clutter internal
+   * state is maintained when calling clutter_x11_handle_event() without
+   * requiring applications or embedding toolkits to select events
+   * themselves. if we did that, we'd have to document the events to be
+   * selected, and also update applications and embedding toolkits each
+   * time we added a new mask, or a new class of events.
+   *
+   * see: http://bugzilla.clutter-project.org/show_bug.cgi?id=998
+   * for the rationale of why we did conditional selection. it is now
+   * clear that a compositor should clear out the input region, since
+   * it cannot assume a perfectly clean slate coming from us.
+   *
+   * see: http://bugzilla.clutter-project.org/show_bug.cgi?id=2228
+   * for an example of things that break if we do conditional event
+   * selection.
+   */
+  XSelectInput (backend_x11->xdpy, stage_x11->xwin, event_flags);
+
+  /* input events also depent on the actual device, so we need to
+   * use the device manager to let every device select them, using
+   * the event mask we passed to XSelectInput as the template
+   */
+  device_manager = clutter_device_manager_get_default ();
+  _clutter_device_manager_select_stage_events (device_manager,
+                                               stage_x11->wrapper,
+                                               event_flags);
+
+  /* no user resize.. */
+  clutter_stage_x11_fix_window_size (stage_x11,
+                                     stage_x11->xwin_width,
+                                     stage_x11->xwin_height);
+  clutter_stage_x11_set_wm_protocols (stage_x11);
+
+  CLUTTER_NOTE (BACKEND, "Successfully realized stage");
+
   return TRUE;
 }
 
@@ -405,18 +447,18 @@ static void
 clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
                                   gboolean            is_fullscreen)
 {
-  ClutterBackend *backend = clutter_get_default_backend ();
-  ClutterBackendX11 *backend_x11;
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
   ClutterStage *stage = stage_x11->wrapper;
+  gboolean was_fullscreen;
 
-  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
-
-  if (stage == NULL)
+  if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage))
     return;
 
-  if (!!(stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN) == is_fullscreen)
+  was_fullscreen = ((stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN) != 0);
+  is_fullscreen = !!is_fullscreen;
+
+  if (was_fullscreen == is_fullscreen)
     return;
 
   CLUTTER_NOTE (BACKEND, "%ssetting fullscreen", is_fullscreen ? "" : "un");
@@ -511,7 +553,7 @@ clutter_stage_x11_set_cursor_visible (ClutterStageWindow *stage_window,
 {
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
 
-  stage_x11->is_cursor_visible = (cursor_visible == TRUE);
+  stage_x11->is_cursor_visible = !!cursor_visible;
   set_cursor_visible (stage_x11);
 }
 
@@ -540,8 +582,7 @@ clutter_stage_x11_set_user_resizable (ClutterStageWindow *stage_window,
 static inline void
 update_wm_hints (ClutterStageX11 *stage_x11)
 {
-  ClutterBackend *backend;
-  ClutterBackendX11 *backend_x11;
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
   XWMHints wm_hints;
 
   if (stage_x11->wm_state & STAGE_X11_WITHDRAWN)
@@ -550,10 +591,6 @@ update_wm_hints (ClutterStageX11 *stage_x11)
   if (stage_x11->is_foreign_xwin)
     return;
 
-  backend = clutter_get_default_backend ();
-  g_assert (CLUTTER_IS_BACKEND_X11 (backend));
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
-
   wm_hints.flags = StateHint | InputHint;
   wm_hints.initial_state = NormalState;
   wm_hints.input = stage_x11->accept_focus ? True : False;
@@ -594,12 +631,8 @@ static void
 clutter_stage_x11_show (ClutterStageWindow *stage_window,
                         gboolean            do_raise)
 {
-  ClutterBackend *backend = clutter_get_default_backend ();
-  ClutterBackendX11 *backend_x11;
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
-
-  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
 
   if (stage_x11->xwin != None)
     {
@@ -637,12 +670,8 @@ clutter_stage_x11_show (ClutterStageWindow *stage_window,
 static void
 clutter_stage_x11_hide (ClutterStageWindow *stage_window)
 {
-  ClutterBackend *backend = clutter_get_default_backend ();
-  ClutterBackendX11 *backend_x11;
   ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
-
-  g_return_if_fail (CLUTTER_IS_BACKEND_X11 (backend));
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
 
   if (stage_x11->xwin != None)
     {
@@ -677,6 +706,12 @@ clutter_stage_x11_finalize (GObject *gobject)
 static void
 clutter_stage_x11_dispose (GObject *gobject)
 {
+  ClutterEventTranslator *translator = CLUTTER_EVENT_TRANSLATOR (gobject);
+  ClutterBackendX11 *backend = CLUTTER_STAGE_X11 (gobject)->backend;
+
+  _clutter_backend_remove_event_translator (CLUTTER_BACKEND (backend),
+                                            translator);
+
   G_OBJECT_CLASS (clutter_stage_x11_parent_class)->dispose (gobject);
 }
 
@@ -724,8 +759,353 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
   iface->realize = clutter_stage_x11_realize;
 }
 
+static inline void
+set_user_time (ClutterBackendX11 *backend_x11,
+               ClutterStageX11   *stage_x11,
+               long               timestamp)
+{
+  if (timestamp != CLUTTER_CURRENT_TIME)
+    {
+      XChangeProperty (backend_x11->xdpy,
+                       stage_x11->xwin,
+                       backend_x11->atom_NET_WM_USER_TIME,
+                       XA_CARDINAL, 32,
+                       PropModeReplace,
+                       (unsigned char *) &timestamp, 1);
+    }
+}
+
+static gboolean
+handle_wm_protocols_event (ClutterBackendX11 *backend_x11,
+                           ClutterStageX11   *stage_x11,
+                           XEvent            *xevent)
+{
+  Atom atom = (Atom) xevent->xclient.data.l[0];
+
+  if (atom == backend_x11->atom_WM_DELETE_WINDOW &&
+      xevent->xany.window == stage_x11->xwin)
+    {
+      /* the WM_DELETE_WINDOW is a request: we do not destroy
+       * the window right away, as it might contain vital data;
+       * we relay the event to the application and we let it
+       * handle the request
+       */
+      CLUTTER_NOTE (EVENT, "Delete stage %s[%p], win:0x%x",
+                    _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage_x11->wrapper)),
+                    stage_x11->wrapper,
+                    (unsigned int) stage_x11->xwin);
+
+      set_user_time (backend_x11, stage_x11, xevent->xclient.data.l[1]);
+
+      return TRUE;
+    }
+  else if (atom == backend_x11->atom_NET_WM_PING &&
+           xevent->xany.window == stage_x11->xwin)
+    {
+      XClientMessageEvent xclient = xevent->xclient;
+
+      xclient.window = backend_x11->xwin_root;
+      XSendEvent (backend_x11->xdpy, xclient.window,
+                  False,
+                  SubstructureRedirectMask | SubstructureNotifyMask,
+                  (XEvent *) &xclient);
+      return FALSE;
+    }
+
+  /* do not send any of the WM_PROTOCOLS events to the queue */
+  return FALSE;
+}
+
+static gboolean
+clipped_redraws_cool_off_cb (void *data)
+{
+  ClutterStageX11 *stage_x11 = data;
+
+  stage_x11->clipped_redraws_cool_off = 0;
+
+  return FALSE;
+}
+
+static ClutterTranslateReturn
+clutter_stage_x11_translate_event (ClutterEventTranslator *translator,
+                                   gpointer                native,
+                                   ClutterEvent           *event)
+{
+  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (translator);
+  ClutterTranslateReturn res = CLUTTER_TRANSLATE_CONTINUE;
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
+  Window stage_xwindow = stage_x11->xwin;
+  XEvent *xevent = native;
+  ClutterStage *stage;
+
+  stage = clutter_x11_get_stage_from_window (xevent->xany.window);
+  if (stage == NULL)
+    return CLUTTER_TRANSLATE_CONTINUE;
+
+  switch (xevent->type)
+    {
+    case ConfigureNotify:
+      if (!stage_x11->is_foreign_xwin)
+        {
+          gboolean size_changed = FALSE;
+
+          CLUTTER_NOTE (BACKEND, "ConfigureNotify[%x] (%d, %d)",
+                        (unsigned int) stage_x11->xwin,
+                        xevent->xconfigure.width,
+                        xevent->xconfigure.height);
+
+          /* When fullscreen, we'll keep the xwin_width/height
+             variables to track the old size of the window and we'll
+             assume all ConfigureNotifies constitute a size change */
+          if ((stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN))
+            size_changed = TRUE;
+          else if ((stage_x11->xwin_width != xevent->xconfigure.width) ||
+                   (stage_x11->xwin_height != xevent->xconfigure.height))
+            {
+              size_changed = TRUE;
+              stage_x11->xwin_width = xevent->xconfigure.width;
+              stage_x11->xwin_height = xevent->xconfigure.height;
+            }
+
+          clutter_actor_set_size (CLUTTER_ACTOR (stage),
+                                  xevent->xconfigure.width,
+                                  xevent->xconfigure.height);
+
+          CLUTTER_UNSET_PRIVATE_FLAGS (stage_x11->wrapper, CLUTTER_IN_RESIZE);
+
+          if (size_changed)
+            {
+              /* XXX: This is a workaround for a race condition when
+               * resizing windows while there are in-flight
+               * glXCopySubBuffer blits happening.
+               *
+               * The problem stems from the fact that rectangles for the
+               * blits are described relative to the bottom left of the
+               * window and because we can't guarantee control over the X
+               * window gravity used when resizing so the gravity is
+               * typically NorthWest not SouthWest.
+               *
+               * This means if you grow a window vertically the server
+               * will make sure to place the old contents of the window
+               * at the top-left/north-west of your new larger window, but
+               * that may happen asynchronous to GLX preparing to do a
+               * blit specified relative to the bottom-left/south-west of
+               * the window (based on the old smaller window geometry).
+               *
+               * When the GLX issued blit finally happens relative to the
+               * new bottom of your window, the destination will have
+               * shifted relative to the top-left where all the pixels you
+               * care about are so it will result in a nasty artefact
+               * making resizing look very ugly!
+               *
+               * We can't currently fix this completely, in-part because
+               * the window manager tends to trample any gravity we might
+               * set.  This workaround instead simply disables blits for a
+               * while if we are notified of any resizes happening so if
+               * the user is resizing a window via the window manager then
+               * they may see an artefact for one frame but then we will
+               * fallback to redrawing the full stage until the cooling
+               * off period is over.
+               */
+              if (stage_x11->clipped_redraws_cool_off)
+                g_source_remove (stage_x11->clipped_redraws_cool_off);
+
+              stage_x11->clipped_redraws_cool_off =
+                g_timeout_add_seconds (1, clipped_redraws_cool_off_cb,
+                                       stage_x11);
+
+              /* Queue a relayout - we want glViewport to be called
+               * with the correct values, and this is done in ClutterStage
+               * via _cogl_onscreen_clutter_backend_set_size ().
+               *
+               * We queue a relayout, because if this ConfigureNotify is
+               * in response to a size we set in the application, the
+               * set_size() call above is essentially a null-op.
+               *
+               * Make sure we do this only when the size has changed,
+               * otherwise we end up relayouting on window moves.
+               */
+              clutter_actor_queue_relayout (CLUTTER_ACTOR (stage));
+
+              /* the resize process is complete, so we can ask the stage
+               * to set up the GL viewport with the new size
+               */
+              clutter_stage_ensure_viewport (stage);
+            }
+        }
+      break;
+
+    case PropertyNotify:
+      if (xevent->xproperty.atom == backend_x11->atom_NET_WM_STATE &&
+          xevent->xproperty.window == stage_xwindow &&
+          !stage_x11->is_foreign_xwin)
+        {
+          Atom     type;
+          gint     format;
+          gulong   n_items, bytes_after;
+          guchar  *data = NULL;
+          gboolean fullscreen_set = FALSE;
+
+          clutter_x11_trap_x_errors ();
+          XGetWindowProperty (backend_x11->xdpy, stage_xwindow,
+                              backend_x11->atom_NET_WM_STATE,
+                              0, G_MAXLONG,
+                              False, XA_ATOM,
+                              &type, &format, &n_items,
+                              &bytes_after, &data);
+          clutter_x11_untrap_x_errors ();
+
+          if (type != None && data != NULL)
+            {
+              Atom *atoms = (Atom *) data;
+              gulong i;
+              gboolean is_fullscreen = FALSE;
+
+              for (i = 0; i < n_items; i++)
+                {
+                  if (atoms[i] == backend_x11->atom_NET_WM_STATE_FULLSCREEN)
+                    fullscreen_set = TRUE;
+                }
+
+              is_fullscreen =
+                (stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN);
+
+              if (fullscreen_set != is_fullscreen)
+                {
+                  if (fullscreen_set)
+                    stage_x11->state |= CLUTTER_STAGE_STATE_FULLSCREEN;
+                  else
+                    stage_x11->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN;
+
+                  stage_x11->fullscreening = fullscreen_set;
+
+                  event->any.type = CLUTTER_STAGE_STATE;
+                  event->any.source = CLUTTER_ACTOR (stage);
+                  event->any.stage = stage;
+                  event->stage_state.changed_mask =
+                    CLUTTER_STAGE_STATE_FULLSCREEN;
+                  event->stage_state.new_state = stage_x11->state;
+
+                  res = CLUTTER_TRANSLATE_QUEUE;
+                }
+
+              XFree (data);
+            }
+        }
+      break;
+
+    case FocusIn:
+      if (!(stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED))
+        {
+          /* TODO: check the detail? */
+          stage_x11->state |= CLUTTER_STAGE_STATE_ACTIVATED;
+
+          event->type = CLUTTER_STAGE_STATE;
+          event->any.source = CLUTTER_ACTOR (stage);
+          event->any.stage = stage;
+          event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
+          event->stage_state.new_state = stage_x11->state;
+
+          res = CLUTTER_TRANSLATE_QUEUE;
+        }
+      break;
+
+    case FocusOut:
+      if (stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED)
+        {
+          /* TODO: check the detail? */
+          stage_x11->state &= ~CLUTTER_STAGE_STATE_ACTIVATED;
+
+          event->any.type = CLUTTER_STAGE_STATE;
+          event->any.source = CLUTTER_ACTOR (stage);
+          event->any.stage = stage;
+          event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
+          event->stage_state.new_state = stage_x11->state;
+
+          res = CLUTTER_TRANSLATE_QUEUE;
+        }
+      break;
+
+    case Expose:
+      {
+        XExposeEvent *expose = (XExposeEvent *) xevent;
+        ClutterPaintVolume clip;
+        ClutterVertex origin;
+
+        CLUTTER_NOTE (EVENT,
+                      "expose for stage: %s[%p], win:0x%x - "
+                      "redrawing area (x: %d, y: %d, width: %d, height: %d)",
+                      _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)),
+                      stage,
+                      (unsigned int) stage_xwindow,
+                      expose->x,
+                      expose->y,
+                      expose->width,
+                      expose->height);
+
+        origin.x = expose->x;
+        origin.y = expose->y;
+        origin.z = 0;
+
+        _clutter_paint_volume_init_static (CLUTTER_ACTOR (stage), &clip);
+
+        clutter_paint_volume_set_origin (&clip, &origin);
+        clutter_paint_volume_set_width (&clip, expose->width);
+        clutter_paint_volume_set_height (&clip, expose->height);
+
+        _clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), 0, &clip);
+
+        clutter_paint_volume_free (&clip);
+      }
+      break;
+
+    case DestroyNotify:
+      CLUTTER_NOTE (EVENT,
+                    "Destroy notification received for stage %s[%p], win:0x%x",
+                    _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)),
+                    stage,
+                    (unsigned int) stage_xwindow);
+      event->any.type = CLUTTER_DESTROY_NOTIFY;
+      event->any.stage = stage;
+      res = CLUTTER_TRANSLATE_QUEUE;
+      break;
+
+    case ClientMessage:
+      CLUTTER_NOTE (EVENT, "Client message for stage %s[%p], win:0x%x",
+                    _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)),
+                    stage,
+                    (unsigned int) stage_xwindow);
+      if (handle_wm_protocols_event (backend_x11, stage_x11, xevent))
+        {
+          event->any.type = CLUTTER_DELETE;
+          event->any.stage = stage;
+          res = CLUTTER_TRANSLATE_QUEUE;
+        }
+      break;
+
+    case MappingNotify:
+      CLUTTER_NOTE (EVENT, "Refresh keyboard mapping");
+      XRefreshKeyboardMapping (&xevent->xmapping);
+      backend_x11->keymap_serial += 1;
+      res = CLUTTER_TRANSLATE_REMOVE;
+      break;
+
+    default:
+      res = CLUTTER_TRANSLATE_CONTINUE;
+      break;
+    }
+
+  return res;
+}
+
+static void
+clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface)
+{
+  iface->translate_event = clutter_stage_x11_translate_event;
+}
+
 /**
- * clutter_x11_get_stage_window:
+ * clutter_x11_get_stage_window: (skip)
  * @stage: a #ClutterStage
  *
  * Gets the stages X Window.
@@ -761,30 +1141,22 @@ clutter_x11_get_stage_window (ClutterStage *stage)
 ClutterStage *
 clutter_x11_get_stage_from_window (Window win)
 {
-  ClutterStageManager *stage_manager;
-  const GSList        *stages, *s;
+  ClutterStageX11 *stage_x11;
 
-  stage_manager = clutter_stage_manager_get_default ();
-  stages = clutter_stage_manager_peek_stages (stage_manager);
+  if (clutter_stages_by_xid == NULL)
+    return NULL;
 
-  /* XXX: might use a hash here for performance resaon */
-  for (s = stages; s != NULL; s = s->next)
-    {
-      ClutterStage *stage = s->data;
-      ClutterStageWindow *impl;
+  stage_x11 = g_hash_table_lookup (clutter_stages_by_xid,
+                                   GINT_TO_POINTER (win));
 
-      impl = _clutter_stage_get_window (stage);
-      g_assert (CLUTTER_IS_STAGE_X11 (impl));
-
-      if (CLUTTER_STAGE_X11 (impl)->xwin == win)
-        return stage;
-    }
+  if (stage_x11 != NULL)
+    return stage_x11->wrapper;
 
   return NULL;
 }
 
 /**
- * clutter_x11_get_stage_visual:
+ * clutter_x11_get_stage_visual: (skip)
  * @stage: a #ClutterStage
  *
  * Returns an XVisualInfo suitable for creating a foreign window for the given
@@ -811,7 +1183,7 @@ clutter_x11_get_stage_visual (ClutterStage *stage)
   g_return_val_if_fail (CLUTTER_IS_BACKEND_X11 (backend), NULL);
   backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
-  return clutter_backend_x11_get_visual_info (backend_x11);
+  return _clutter_backend_x11_get_visual_info (backend_x11);
 }
 
 typedef struct {
@@ -826,8 +1198,7 @@ set_foreign_window_callback (ClutterActor *actor,
                              void         *data)
 {
   ForeignWindowData *fwd = data;
-  ClutterBackend *backend = clutter_get_default_backend ();
-  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
+  ClutterBackendX11 *backend_x11 = fwd->stage_x11->backend;
 
   CLUTTER_NOTE (BACKEND, "Setting foreign window (0x%x)",
                 (unsigned int) fwd->xwindow);
@@ -847,6 +1218,13 @@ set_foreign_window_callback (ClutterActor *actor,
 
   clutter_actor_set_geometry (actor, &fwd->geom);
 
+  if (clutter_stages_by_xid == NULL)
+    clutter_stages_by_xid = g_hash_table_new (NULL, NULL);
+
+  g_hash_table_insert (clutter_stages_by_xid,
+                       GINT_TO_POINTER (fwd->stage_x11->xwin),
+                       fwd->stage_x11);
+
   /* calling this with the stage unrealized will unset the stage
    * from the GL context; once the stage is realized the GL context
    * will be set again
@@ -869,7 +1247,6 @@ gboolean
 clutter_x11_set_stage_foreign (ClutterStage *stage,
                                Window        xwindow)
 {
-  ClutterBackend *backend = clutter_get_default_backend ();
   ClutterBackendX11 *backend_x11;
   ClutterStageX11 *stage_x11;
   ClutterStageWindow *impl;
@@ -881,16 +1258,15 @@ clutter_x11_set_stage_foreign (ClutterStage *stage,
   ForeignWindowData fwd;
   XVisualInfo *xvisinfo;
 
-  g_return_val_if_fail (CLUTTER_IS_BACKEND_X11 (backend), FALSE);
-  backend_x11 = CLUTTER_BACKEND_X11 (backend);
-
   g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
   g_return_val_if_fail (!CLUTTER_ACTOR_IN_DESTRUCTION (stage), FALSE);
   g_return_val_if_fail (xwindow != None, FALSE);
 
-  actor = CLUTTER_ACTOR (stage);
+  impl = _clutter_stage_get_window (stage);
+  stage_x11 = CLUTTER_STAGE_X11 (impl);
+  backend_x11 = stage_x11->backend;
 
-  xvisinfo = clutter_backend_x11_get_visual_info (backend_x11);
+  xvisinfo = _clutter_backend_x11_get_visual_info (backend_x11);
   g_return_val_if_fail (xvisinfo != NULL, FALSE);
 
   clutter_x11_trap_x_errors ();
@@ -925,9 +1301,6 @@ clutter_x11_set_stage_foreign (ClutterStage *stage,
       return FALSE;
     }
 
-  impl = _clutter_stage_get_window (stage);
-  stage_x11 = CLUTTER_STAGE_X11 (impl);
-
   fwd.stage_x11 = stage_x11;
   fwd.xwindow = xwindow;
 
@@ -942,6 +1315,8 @@ clutter_x11_set_stage_foreign (ClutterStage *stage,
   fwd.geom.width = width;
   fwd.geom.height = height;
 
+  actor = CLUTTER_ACTOR (stage);
+
   _clutter_actor_rerealize (actor,
                             set_foreign_window_callback,
                             &fwd);
@@ -955,7 +1330,145 @@ clutter_x11_set_stage_foreign (ClutterStage *stage,
    * in the Cogl viewport changing when _clutter_do_redraw
    * calls _clutter_stage_maybe_setup_viewport().
    */
-  clutter_actor_queue_relayout (CLUTTER_ACTOR (stage));
+  clutter_actor_queue_relayout (actor);
 
   return TRUE;
 }
+
+void
+_clutter_stage_x11_destroy_window_untrapped (ClutterStageX11 *stage_x11)
+{
+  Window xwin = stage_x11->xwin;
+
+  if (clutter_stages_by_xid != NULL)
+    g_hash_table_remove (clutter_stages_by_xid, GINT_TO_POINTER (xwin));
+
+  if (!stage_x11->is_foreign_xwin && xwin != None)
+    {
+      ClutterBackendX11 *backend_x11 = stage_x11->backend;
+
+      g_assert (clutter_stages_by_xid != NULL);
+
+      XDestroyWindow (backend_x11->xdpy, xwin);
+      stage_x11->xwin = None;
+    }
+  else
+    stage_x11->xwin = None;
+}
+
+void
+_clutter_stage_x11_destroy_window (ClutterStageX11 *stage_x11)
+{
+  if (stage_x11->xwin == None)
+    return;
+
+  clutter_x11_trap_x_errors ();
+
+  _clutter_stage_x11_destroy_window_untrapped (stage_x11);
+
+  clutter_x11_untrap_x_errors ();
+}
+
+gboolean
+_clutter_stage_x11_create_window (ClutterStageX11 *stage_x11)
+{
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
+  XSetWindowAttributes xattr;
+  XVisualInfo *xvisinfo;
+  unsigned long mask;
+  gfloat width, height;
+
+  if (stage_x11->xwin != None)
+    return TRUE;
+
+  CLUTTER_NOTE (MISC, "Creating stage X window");
+
+  xvisinfo = _clutter_backend_x11_get_visual_info (backend_x11);
+  if (xvisinfo == NULL)
+    {
+      g_critical ("Unable to find suitable GL visual.");
+      return FALSE;
+    }
+
+  /* window attributes */
+  xattr.background_pixel = WhitePixel (backend_x11->xdpy,
+                                       backend_x11->xscreen_num);
+  xattr.border_pixel = 0;
+  xattr.colormap = XCreateColormap (backend_x11->xdpy,
+                                    backend_x11->xwin_root,
+                                    xvisinfo->visual,
+                                    AllocNone);
+  mask = CWBorderPixel | CWColormap;
+
+  /* Call get_size - this will either get the geometry size (which
+   * before we create the window is set to 640x480), or if a size
+   * is set, it will get that. This lets you set a size on the
+   * stage before it's realized.
+   *
+   * we also round to the nearest integer because stage sizes
+   * should always be in pixels
+   */
+  clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper), &width, &height);
+  stage_x11->xwin_width = floorf (width + 0.5);
+  stage_x11->xwin_height = floorf (height + 0.5);
+
+  stage_x11->xwin = XCreateWindow (backend_x11->xdpy,
+                                   backend_x11->xwin_root,
+                                   0, 0,
+                                   stage_x11->xwin_width,
+                                   stage_x11->xwin_height,
+                                   0,
+                                   xvisinfo->depth,
+                                   InputOutput,
+                                   xvisinfo->visual,
+                                   mask, &xattr);
+
+  CLUTTER_NOTE (BACKEND, "Stage [%p], window: 0x%x, size: %dx%d",
+                stage_x11,
+                (unsigned int) stage_x11->xwin,
+                stage_x11->xwin_width,
+                stage_x11->xwin_height);
+
+  XFree (xvisinfo);
+
+  if (clutter_stages_by_xid == NULL)
+    clutter_stages_by_xid = g_hash_table_new (NULL, NULL);
+
+  g_hash_table_insert (clutter_stages_by_xid,
+                       GINT_TO_POINTER (stage_x11->xwin),
+                       stage_x11);
+
+  return TRUE;
+}
+
+void
+_clutter_stage_x11_set_user_time (ClutterStageX11 *stage_x11,
+                                  guint32          user_time)
+{
+  set_user_time (stage_x11->backend, stage_x11, user_time);
+}
+
+gboolean
+_clutter_stage_x11_get_root_coords (ClutterStageX11 *stage_x11,
+                                    gint            *root_x,
+                                    gint            *root_y)
+{
+  ClutterBackendX11 *backend_x11 = stage_x11->backend;
+  gint return_val;
+  Window child;
+  gint tx, ty;
+
+  return_val = XTranslateCoordinates (backend_x11->xdpy,
+                                      stage_x11->xwin,
+                                      backend_x11->xwin_root,
+                                      0, 0, &tx, &ty,
+                                      &child);
+
+  if (root_x)
+    *root_x = tx;
+
+  if (root_y)
+    *root_y = ty;
+
+  return (return_val == 0);
+}
index b62c2d2..f963e52 100644 (file)
@@ -31,7 +31,7 @@
 
 G_BEGIN_DECLS
 
-#define CLUTTER_TYPE_STAGE_X11                  (clutter_stage_x11_get_type ())
+#define CLUTTER_TYPE_STAGE_X11                  (_clutter_stage_x11_get_type ())
 #define CLUTTER_STAGE_X11(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_X11, ClutterStageX11))
 #define CLUTTER_IS_STAGE_X11(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_X11))
 #define CLUTTER_STAGE_X11_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_X11, ClutterStageX11Class))
@@ -67,10 +67,9 @@ struct _ClutterStageX11
 
   ClutterStageX11State wm_state;
 
-  int event_types[CLUTTER_X11_XINPUT_LAST_EVENT];
-  GList *devices;
-
+  /* backpointers */
   ClutterStage *wrapper;
+  ClutterBackendX11 *backend;
 };
 
 struct _ClutterStageX11Class
@@ -78,17 +77,17 @@ struct _ClutterStageX11Class
   ClutterGroupClass parent_class;
 };
 
-GType clutter_stage_x11_get_type (void) G_GNUC_CONST;
+GType _clutter_stage_x11_get_type (void) G_GNUC_CONST;
 
 /* Private to subclasses */
-void clutter_stage_x11_fix_window_size  (ClutterStageX11 *stage_x11,
-                                         gint             new_width,
-                                         gint             new_height);
-void clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11);
-void clutter_stage_x11_map              (ClutterStageX11 *stage_x11);
-void clutter_stage_x11_unmap            (ClutterStageX11 *stage_x11);
-
-GList *clutter_stage_x11_get_input_devices (ClutterStageX11 *stage_x11);
+gboolean        _clutter_stage_x11_create_window                (ClutterStageX11 *stage_x11);
+void            _clutter_stage_x11_destroy_window_untrapped     (ClutterStageX11 *stage_x11);
+void            _clutter_stage_x11_destroy_window               (ClutterStageX11 *stage_x11);
+void            _clutter_stage_x11_set_user_time                (ClutterStageX11 *stage_x11,
+                                                                 guint32          user_time);
+gboolean        _clutter_stage_x11_get_root_coords              (ClutterStageX11 *stage_x11,
+                                                                 gint            *root_x,
+                                                                 gint            *root_y);
 
 G_END_DECLS
 
index f9681eb..3acadce 100644 (file)
@@ -663,7 +663,7 @@ clutter_x11_texture_pixmap_class_init (ClutterX11TexturePixmapClass *klass)
    * ClutterX11TexturePixmap::update-area:
    * @texture: the object which received the signal
    *
-   * The ::hide signal is emitted to ask the texture to update its
+   * The ::update-area signal is emitted to ask the texture to update its
    * content from its source pixmap.
    *
    * Since: 0.8
index 881f4df..42ff1fa 100644 (file)
@@ -5,28 +5,16 @@
 # Making a point release:
 # - increase clutter_micro_version to the next even number
 # - increase clutter_interface_age to the next even number
-#   UNLESS there was an API addition/deprecation, in which case
-#   - set clutter_interface_age to 0
 # After the release:
 # - increase clutter_micro_version to the next odd number
 # - increase clutter_interface_version to the next odd number
 m4_define([clutter_major_version], [1])
-m4_define([clutter_minor_version], [5])
-m4_define([clutter_micro_version], [11])
+m4_define([clutter_minor_version], [6])
+m4_define([clutter_micro_version], [3])
 
-m4_define([clutter_release_status],
-          [m4_if(m4_eval(clutter_micro_version % 2), [1], [git],
-                 [m4_if(m4_eval(clutter_minor_version % 2), [1], [snapshot],
-                                                                 [release])])])
-
-m4_define([clutter_version], [clutter_major_version.clutter_minor_version.clutter_micro_version])
-
-# change this only when breaking the API
-m4_define([clutter_api_version], [1.0])
-
-# increase the interface age by 1 for each release; if the API changes,
-# set to 0. interface_age and binary_age are used to create the soname
-# of the shared object:
+# • for stable releases: increase the interface age by 1 for each release;
+#   if the API changes, set to 0. interface_age and binary_age are used to
+#   create the soname of the shared object:
 #
 #  (<minor> * 100 + <micro>) - <interface_age>
 #
@@ -42,9 +30,21 @@ m4_define([clutter_api_version], [1.0])
 #   clutter 1.2.10 -> 100 * 2 + 10 = 210, interface age = 4 -> 206
 #   ...
 #
-m4_define([clutter_interface_age], [0])
+# • for development releases: keep clutter_interface_age to 0
+m4_define([clutter_interface_age], [3])
+
 m4_define([clutter_binary_age], [m4_eval(100 * clutter_minor_version + clutter_micro_version)])
 
+m4_define([clutter_release_status],
+          [m4_if(m4_eval(clutter_micro_version % 2), [1], [git],
+                 [m4_if(m4_eval(clutter_minor_version % 2), [1], [snapshot],
+                                                                 [release])])])
+
+m4_define([clutter_version], [clutter_major_version.clutter_minor_version.clutter_micro_version])
+
+# change this only when breaking the API
+m4_define([clutter_api_version], [1.0])
+
 AC_PREREQ([2.63])
 
 AC_INIT([clutter],
@@ -94,6 +94,10 @@ AC_MSG_RESULT([$platform_win32])
 AC_SUBST(CLUTTER_LT_VERSION)
 AC_SUBST(CLUTTER_LT_LDFLAGS)
 
+dnl The 'ffs' function is part of C99 so it isn't always
+dnl available. Cogl has a fallback if needed.
+AC_CHECK_FUNCS([ffs])
+
 dnl ========================================================================
 
 # Checks for programs.
@@ -668,6 +672,35 @@ dnl using the define also.
 AC_DEFINE([COGL_ENABLE_EXPERIMENTAL_2_0_API], [1],
           [Can use Cogl 2.0 API internally])
 
+dnl === Clutter configuration =================================================
+
+CLUTTER_CONFIG_DEFINES=
+
+# windowing systems
+AS_IF([test "x$SUPPORT_XLIB" = "x1"],
+      [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
+#define CLUTTER_WINDOWING_X11 1"])
+AS_IF([test "x$SUPPORT_GLX" = "x1"],
+      [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
+#define CLUTTER_WINDOWING_GLX 1"])
+AS_IF([test "x$SUPPORT_EGL" = "x1"],
+      [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
+#define CLUTTER_WINDOWING_EGL 1"])
+AS_IF([test "x$SUPPORT_WAYLAND" = "x1"],
+      [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
+#define CLUTTER_WINDOWING_WAYLAND 1"])
+AS_IF([test "x$SUPPORT_OSX" = "x1"],
+      [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
+#define CLUTTER_WINDOWING_OSX 1"])
+AS_IF([test "x$SUPPORT_WIN32" = "x1"],
+      [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
+#define CLUTTER_WINDOWING_WIN32 1"])
+AS_IF([test "x$SUPPORT_CEX100" = "x1"],
+      [CLUTTER_CONFIG_DEFINES="$CLUTTER_CONFIG_DEFINES
+#define CLUTTER_WINDOWING_CEX100 1"])
+
+AC_SUBST([CLUTTER_CONFIG_DEFINES])
+
 dnl === Clutter substitutions =================================================
 # Eventually the idea of a winsys should be hidden from Clutter and moved
 # into Cogl, but for now we have CLUTTER_WINSYS...
@@ -827,29 +860,47 @@ AS_IF([test "x$SUPPORT_XLIB" = "x1"],
               [AC_MSG_ERROR([not found])]
         )
 
-        # XINPUT (optional)
-        xinput=no
+        # XI (optional)
         AC_ARG_ENABLE([xinput],
-                      [AS_HELP_STRING([--enable-xinput], [Use the XINPUT X extension])],
-                      [
-                        AS_IF([test "x$enableval" = "xyes"],
-                              [PKG_CHECK_MODULES(XINPUT, [xi], [xinput=yes], [xinput=no])]
-                        )
-                      ],
-                      [xinput=no])
+                      [AS_HELP_STRING([--enable-xinput], [Use the XI X extension])],
+                      [],
+                      [enable_xinput=yes])
 
-        AS_CASE([$xinput],
+        AS_IF([test "x$enable_xinput" = "xyes"],
+              [
+                PKG_CHECK_EXISTS([xi], [have_xinput=yes], [have_xinput=no])
+              ],
+              [
+                have_xinput=no
+              ])
+
+        AS_CASE([$have_xinput],
 
                 [yes],
                 [
-                  AC_DEFINE(HAVE_XINPUT, 1, [Use the XINPUT X extension])
-
-                  X11_LIBS="$X11_LIBS -lXi"
+                  AC_CHECK_HEADERS([X11/extensions/XInput2.h],
+                                   [
+                                     have_xinput2=yes
+                                     AC_DEFINE([HAVE_XINPUT_2],
+                                               [1],
+                                               [Define to 1 if XI2 is available])
+                                   ],
+                                   [
+                                     have_xinput2=no
+                                     AC_DEFINE([HAVE_XINPUT],
+                                               [1],
+                                               [Define to 1 if XInput is available])
+                                   ])
+
+                  X11_LIBS="$X11_LIBS $XINPUT_LIBS"
                   X11_PC_FILES="$X11_PC_FILES xi"
                 ],
 
                 [no],
-                [],
+                [have_xinput2=no],
+
+                [*],
+                [AC_MSG_ERROR([Invalid argument for --enable-xinput])]
         )
 
         # XKB
@@ -876,6 +927,7 @@ AS_IF([test "x$SUPPORT_XLIB" = "x1"],
       ]
 )
 
+AM_CONDITIONAL([BUILD_XI2], [test "x$have_xinput2" = "xyes"])
 AM_CONDITIONAL(X11_TESTS, [test "x$x11_tests" = "xyes"])
 
 dnl === Enable debug level ====================================================
@@ -1009,22 +1061,38 @@ AC_SUBST([GCOV_LDFLAGS])
 
 dnl === Enable strict compiler flags ==========================================
 
-# use strict compiler flags only on development releases
-m4_define([maintainer_flags_default], [m4_if(m4_eval(clutter_minor_version % 2), [1], [yes], [no])])
+# use strict compiler flags only when building from git; the rules for
+# distcheck will take care of turning this on when making a release
+m4_define([maintainer_flags_default], [m4_if(m4_eval(clutter_micro_version % 2), [1], [yes], [no])])
 AC_ARG_ENABLE([maintainer-flags],
-              [AC_HELP_STRING([--enable-maintainer-flags=@<:@no/yes@:>@],
+              [AC_HELP_STRING([--enable-maintainer-flags=@<:@no/yes/error@:>@],
                               [Use strict compiler flags @<:@default=maintainer_flags_default@:>@])],
               [],
               [enable_maintainer_flags=maintainer_flags_default])
 
-AS_IF([test "x$enable_maintainer_flags" = "xyes" && test "x$GCC" = "xyes"],
-      [
-        AS_COMPILER_FLAGS([MAINTAINER_CFLAGS],
-                          ["-Wall -Wshadow -Wcast-align -Wuninitialized
-                            -Wno-strict-aliasing -Wempty-body -Wformat
-                            -Wformat-security -Winit-self
-                            -Wdeclaration-after-statement -Wvla"])
-      ]
+MAINTAINER_COMPILER_FLAGS="-Wall -Wshadow -Wcast-align -Wuninitialized
+                           -Wno-strict-aliasing -Wempty-body -Wformat
+                           -Wformat-security -Winit-self
+                           -Wdeclaration-after-statement -Wvla"
+
+AS_CASE([$enable_maintainer_flags],
+        [yes],
+        [
+          AS_COMPILER_FLAGS([MAINTAINER_CFLAGS], [$MAINTAINER_COMPILER_FLAGS])
+        ],
+
+        [no],
+        [
+        ],
+
+        [error],
+        [
+          MAINTAINER_COMPILER_FLAGS="$MAINTAINER_COMPILER_FLAGS -Werror"
+          AS_COMPILER_FLAGS([MAINTAINER_CFLAGS], [$MAINTAINER_COMPILER_FLAGS])
+        ],
+
+        [*],
+        [AC_MSG_ERROR([Invalid option for --enable-maintainer-flags])]
 )
 
 AC_SUBST(MAINTAINER_CFLAGS)
@@ -1116,6 +1184,7 @@ AC_CONFIG_FILES([
        build/mingw/Makefile
 
        clutter/Makefile
+        clutter/clutter-config.h
        clutter/clutter-version.h
        clutter/clutter-$CLUTTER_API_VERSION.pc:clutter/clutter.pc.in
 
@@ -1223,7 +1292,8 @@ fi
 
 if test "x$SUPPORT_XLIB" = "x1"; then
 echo "        Enable XComposite: ${have_xcomposite}"
-echo "        Enable XInput 1.0: ${xinput}"
+echo "        Enable XInput: ${have_xinput}"
+echo "        Enable XI2: ${have_xinput2}"
 echo "        Enable XKB: ${have_xkb}"
 echo "        Enable X11 tests: ${x11_tests}"
 fi
index c56e681..0c80370 100644 (file)
@@ -1,5 +1,5 @@
 IMPLEMENTING BACKENDS
-=====================
+===============================================================================
 
 Clutter supports multiple backends for handling windowing systems and
 GL/GLES API on different platforms.
@@ -21,11 +21,16 @@ create a new sub-directory under clutter/clutter containing:
   <backend>/clutter-stage-<backend>.h
   <backend>/clutter-stage-<backend>.c
 
-  -- The implementation of the stage actor.
+  -- The implementation of the stage window
+
+  <backend>/clutter-device-manager-<backend>.h
+  <backend>/clutter-device-manager-<backend>.c
+
+  -- The implementation of the input device manager
 
   <backend>/clutter-event-<backend>.c
 
-  -- The event handling code (optional).
+  -- Event-specific code (optional)
 
   <backend>/clutter-<backend>.h
 
@@ -35,7 +40,7 @@ create a new sub-directory under clutter/clutter containing:
 
 
 Implementing ClutterBackend
----------------------------
+-------------------------------------------------------------------------------
 
 Each backend must implement the
 
@@ -108,12 +113,6 @@ can be overridden:
      drawing surface or should unset the drawing surface from the
      drawing context.
 
-  ClutterBackend::redraw
-  -- This function is used to draw the passed ClutterStage; the backend
-     must call clutter_actor_paint() on the ClutterStage that has been
-     passed as a parameter and then perform backend-specific tasks, like
-     waiting for vertical blanking and swapping the buffers.
-
   ClutterBackend::create_stage
   -- This function is used to create the stage implementation. It will
      receive as an argument the ClutterStage instance that is "wrapping"
@@ -121,8 +120,13 @@ can be overridden:
      its stage implementation, initialise it and then return it; in case
      of error, the backend must return NULL and set the passed GError.
 
+  ClutterBackend::get_device_manager
+  -- This function is used to return the ClutterDeviceManager instance
+     that is going to be returned by clutter_device_manager_get_default()
+     and that should be used internally by input event translation.
+
 Implementing the stage
-----------------------
+-------------------------------------------------------------------------------
 
 ClutterStage acts as a wrapper object relaying all the drawing operations
 to the actual implementation. The implementation of the stage can be any
@@ -139,6 +143,7 @@ The stage implementation actor must implement:
   • ClutterStageWindow::show() and ::hide()
   • ClutterStageWindow::resize()
   • ClutterStageWindow::get_geometry()
+  • ClutterStageWindow::redraw()
 
 The ::get_wrapper() implementation should return the pointer to the
 ClutterStage actor using the ClutterStageWindow implementation.
@@ -159,6 +164,10 @@ the native window handle created in ::realize().
 The ::resize() virtual function implementation should cause an update
 of the COGL viewport.
 
+The ::redraw() virtual function implementation should contain the platform
+specific drawing logic, and call _clutter_stage_do_paint() on the ClutterStage
+wrapper instance to cause the scene to be painted.
+
 The stage implementation actor can optionally implement:
 
   • ClutterStageWindow::get_pending_swaps()
@@ -167,9 +176,32 @@ The get_pending_swaps() implementation should return the number of swap
 buffer requests pending completion. This is only relevent for backends
 that also support CLUTTER_FEATURE_SWAP_EVENTS.
 
+If the stage window is supposed to handle events, then it should also implement
+the ClutterEventTranslator interface; this interface has a single virtual
+function:
+
+  • ClutterEventTranslator::translate_event()
+
+which gets passed a pointer to the native event data structure, and a pointer
+to a newly-allocated, empty ClutterEvent. The EventTranslator implementation
+should then decide between three options:
+
+  - translate the native event and return CLUTTER_TRANSLATE_QUEUE to
+    let Clutter queue it up in the events queue;
+  - return CLUTTER_TRANSLATE_CONTINUE to let other event translators handle
+    the event;
+  - return CLUTTER_TRANSLATE_REMOVE to ignore the event.
+
+Implementing ClutterDeviceManager
+-------------------------------------------------------------------------------
+
+Backends with input devices should provide a ClutterDeviceManager
+implementation to handle addition, removal and input device event translation
+through the ClutterEventTranslator interface.
+
 NOTES
-=====
+===============================================================================
 
-If the platform is using X11 you should probably subclass ClutterBackendX11
-and ClutterStageX11, which will provide you with a ready to use code
-implementation for event handling and window management.
+• If the platform is using X11 you should probably subclass ClutterBackendX11
+  and ClutterStageX11, which will provide you with a ready to use code
+  implementation for event handling and window management.
index 814dd54..6fad1b4 100644 (file)
@@ -8,14 +8,14 @@ HTML_DIR = $(datadir)/gtk-doc/html
 TARGET_DIR = $(HTML_DIR)/clutter-cookbook
 
 XML_FILES = \
-       actors.xml              \
-       animations.xml          \
-       events.xml              \
-       introduction.xml        \
-       text.xml                \
-       textures.xml            \
-       layouts.xml             \
-       script.xml              \
+       $(srcdir)/actors.xml            \
+       $(srcdir)/animations.xml        \
+       $(srcdir)/events.xml            \
+       $(srcdir)/introduction.xml      \
+       $(srcdir)/text.xml              \
+       $(srcdir)/textures.xml          \
+       $(srcdir)/layouts.xml           \
+       $(srcdir)/script.xml            \
        $(NULL)
 
 XSLTOPTS = \
@@ -25,46 +25,48 @@ XSLTOPTS = \
        --stringparam  section.autolabel 1                      \
        --stringparam gtkdoc.bookname "clutter-cookbook"        \
        --stringparam gtkdoc.version @CLUTTER_API_VERSION@      \
-       --stringparam callout.graphics 0        \
+       --stringparam callout.graphics 0                        \
        --path $(top_srcdir)/doc/common                         \
        --xinclude
 
 XSL_BASE_URI  = http://docbook.sourceforge.net/release/xsl/current
 XSL_XHTML_URI = $(XSL_BASE_URI)/xhtml/docbook.xsl
 
-HTML_FILES = html/*.html
-CSS_FILES = html/*.css
+HTML_FILES = $(top_builddir)/doc/cookbook/html/*.html
+CSS_FILES = $(top_builddir)/doc/cookbook/html/*.css
 IMAGE_FILES = \
-       images/clutter-logo.png \
-       images/textures-reflection.png \
-       images/actors-opacity.png \
-       images/actors-opacity-container-affects-opacity.png \
-       images/text-shadow.png \
-       images/textures-sub-texture.png \
-       images/layouts-stacking-diff-actor-sizes.png \
-       images/events-pointer-motion-stacking.png       \
-       images/layouts-bind-constraint-stage.png        \
+       $(srcdir)/images/clutter-logo.png \
+       $(srcdir)/images/textures-reflection.png \
+       $(srcdir)/images/actors-opacity.png \
+       $(srcdir)/images/actors-opacity-container-affects-opacity.png \
+       $(srcdir)/images/text-shadow.png \
+       $(srcdir)/images/textures-sub-texture.png \
+       $(srcdir)/images/layouts-stacking-diff-actor-sizes.png \
+       $(srcdir)/images/events-pointer-motion-stacking.png     \
+       $(srcdir)/images/layouts-bind-constraint-stage.png      \
        $(NULL)
+
 VIDEO_FILES = \
-       videos/animations-fading-out.ogv \
-       videos/animations-fading-in-then-out.ogv \
-       videos/animations-rotating-x-minus-45.ogv \
-       videos/animations-rotating-y-45.ogv \
-       videos/animations-rotating-z-90.ogv \
-       videos/animations-rotating-x-minus-180-with-y-minus-96.ogv \
-       videos/animations-rotating-x-minus-180-with-z-minus-96.ogv \
-       videos/animations-rotating-x-centered.ogv \
-       videos/animations-rotating-y-centered.ogv \
-       videos/animations-rotating-z-centered.ogv \
-       videos/animations-rotating-container-reverses-direction.ogv \
-       videos/textures-split-go.ogv \
-       videos/events-mouse-scroll.ogv \
-       videos/textures-crossfade-two-textures.ogv \
-       videos/animations-complex.ogv \
-       videos/animations-reuse.ogv \
-       videos/animations-moving-anchors.ogv \
-       videos/animations-moving-depth.ogv \
-       videos/animations-looping.ogv \
+       $(srcdir)/videos/animations-fading-out.ogv \
+       $(srcdir)/videos/animations-fading-in-then-out.ogv \
+       $(srcdir)/videos/animations-path.ogv \
+       $(srcdir)/videos/animations-rotating-x-minus-45.ogv \
+       $(srcdir)/videos/animations-rotating-y-45.ogv \
+       $(srcdir)/videos/animations-rotating-z-90.ogv \
+       $(srcdir)/videos/animations-rotating-x-minus-180-with-y-minus-96.ogv \
+       $(srcdir)/videos/animations-rotating-x-minus-180-with-z-minus-96.ogv \
+       $(srcdir)/videos/animations-rotating-x-centered.ogv \
+       $(srcdir)/videos/animations-rotating-y-centered.ogv \
+       $(srcdir)/videos/animations-rotating-z-centered.ogv \
+       $(srcdir)/videos/animations-rotating-container-reverses-direction.ogv \
+       $(srcdir)/videos/textures-split-go.ogv \
+       $(srcdir)/videos/events-mouse-scroll.ogv \
+       $(srcdir)/videos/textures-crossfade-two-textures.ogv \
+       $(srcdir)/videos/animations-complex.ogv \
+       $(srcdir)/videos/animations-reuse.ogv \
+       $(srcdir)/videos/animations-moving-anchors.ogv \
+       $(srcdir)/videos/animations-moving-depth.ogv \
+       $(srcdir)/videos/animations-looping.ogv \
        $(NULL)
 
 EXTRA_DIST = \
@@ -76,7 +78,8 @@ EXTRA_DIST = \
 
 CLEANFILES = \
        pdf-build.stamp \
-       html-build.stamp
+       html-build.stamp \
+       clutter-cookbook.html
 
 pdf-build.stamp: clutter-cookbook.xml $(XML_FILES)
        SP_ENCODING=XML SP_CHARSET_FIXED=YES \
@@ -97,8 +100,8 @@ html-build.stamp: clutter-cookbook.xml $(XML_FILES)
                        cp $$file html/videos/ ; \
                done \
        fi && \
-       cp images/* html/images/ && \
-       cp examples/*.c html/examples/ && \
+       cp $(top_srcdir)/doc/cookbook/images/* html/images/ && \
+       cp $(top_srcdir)/doc/cookbook/examples/*.c html/examples/ && \
        echo timestamp > $(@F)
 
 if ENABLE_PDFS
@@ -120,10 +123,12 @@ clean-local:
        rm -f *.stamp
 
 uninstall-local:
+       @rm -rf $(DESTDIR)$(TARGET_DIR)
+       @rm -f $(DESTDIR)$(TARGET_DIR)/clutter-cookbook.devhelp
 
 install-data-local:
-       installfiles=`echo ./html/*`; \
-       if test "$$installfiles" = './html/*'; \
+       installfiles=`echo $(top_builddir)/doc/cookbook/html/*`; \
+       if test "$$installfiles" = '$(top_builddir)/doc/cookbook/html/*'; \
        then echo '-- Nothing to install' ; \
        else \
          $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR) ; \
@@ -134,7 +139,7 @@ install-data-local:
            fi \
          done; \
        fi; \
-       if [ -d ./images ]; \
+       if [ -d $(top_srcdir)/doc/cookbook/images ]; \
        then \
          $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR)/images ; \
          for file in `ls $(IMAGE_FILES)`; do \
@@ -145,18 +150,18 @@ install-data-local:
            fi \
          done; \
        fi; \
-       if [ -d ./videos ] && [[ "$(VIDEO_FILES)" != "" ]] ; \
+       if [ -d $(top_srcdir)/doc/cookbook/videos ]; \
        then \
          $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR)/videos ; \
-    for file in `ls $(VIDEO_FILES)`; do \
-      if [ -f $$file ]; \
-      then \
-        basefile=`echo $$file | sed -e 's,^.*/,,'`; \
-        $(INSTALL_DATA) $$file $(DESTDIR)$(TARGET_DIR)/videos/$$basefile; \
-      fi \
-    done; \
+         for file in `ls $(VIDEO_FILES)`; do \
+           if [ -f $$file ]; \
+           then \
+             basefile=`echo $$file | sed -e 's,^.*/,,'`; \
+             $(INSTALL_DATA) $$file $(DESTDIR)$(TARGET_DIR)/videos/$$basefile; \
+           fi \
+         done; \
        fi; \
-       $(INSTALL_DATA) html/clutter-cookbook.devhelp $(DESTDIR)$(TARGET_DIR)/clutter-cookbook.devhelp
+       $(INSTALL_DATA) $(top_builddir)/doc/cookbook/html/clutter-cookbook.devhelp $(DESTDIR)$(TARGET_DIR)/clutter-cookbook.devhelp
 
 .PHONY : doc
 
index d590fce..c1fc63f 100644 (file)
@@ -1,7 +1,8 @@
 <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 
-<chapter id="actors">
+<chapter id="actors"
+         xmlns:xi="http://www.w3.org/2003/XInclude">
   <title>Actors</title>
 
   <epigraph>
 
   </section>
 
+  <section id="actors-composite">
+    <title>Implementing a simple custom actor</title>
+
+    <section id="actors-composite-problem">
+      <title>Problem</title>
+
+      <para>You want to implement your own <type>ClutterActor</type>;
+      for example, a very simple button widget. But you want to base it
+      on existing Clutter primitives (rectangles, text) to minimise
+      the work required.</para>
+    </section>
+
+    <section id="actors-composite-solution">
+      <title>Solution</title>
+
+      <para>Implement a custom actor composed from a <type>ClutterBox</type>
+      packed with other <type>ClutterActors</type>. The custom actor
+      provides a facade over these internal actors, simplifying
+      access to their properties and behavior.</para>
+
+      <para>In this recipe, we subclass <type>ClutterActor</type> using this
+      approach to create a very simple button widget, <type>CbButton</type>.
+      It is not a complete button implementation: see
+      <ulink url="http://git.clutter-project.org/mx/tree/mx/mx-button.c">
+      <type>MxButton</type></ulink> for a more comprehensive example
+      (and the basis for this recipe). But this recipe does cover the most
+      important parts of a <type>ClutterActor</type> implementation,
+      as well some useful <type>GObject</type>-related code.</para>
+
+      <tip>
+        <para>As Clutter is a GObject-based library, it relies
+        heavily on GObject concepts and idioms. If you are unfamiliar with
+        GObject, please read
+        <ulink url="http://library.gnome.org/devel/gobject/unstable/">the GObject
+        Reference Manual</ulink> before proceeding. You might also find
+        <ulink url="http://diuf.unifr.ch/pai/wiki/doku.php/research:projects:gobject_tutorial">this
+        tutorial</ulink> a useful introduction.</para>
+      </tip>
+
+      <para>The code for this solution is structured like standard GObject
+      C library code:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>The header file <filename>cb-button.h</filename>
+          declares the class' public API (function prototypes, macros,
+          structs).</para>
+        </listitem>
+        <listitem>
+          <para>The code file <filename>cb-button.c</filename>
+          contains the class implementation.</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>One more example file, <filename>actors-composite-main.c</filename>,
+      shows how to use <type>CbButton</type> in an application.</para>
+
+      <para>Each of these files is described in more detail below.</para>
+
+      <note>
+        <para>In a more realistic context, <type>CbButton</type> would
+        have some build infrastructure (for example, autotooling)
+        so it could be compiled, installed, and reused in a variety of
+        applications. However, for the purposes of cookbook examples,
+        these issues are ignored here.</para>
+
+        <para>If you <emphasis>are</emphasis> planning on building
+        your own widgets using Clutter as part of an application, or
+        to create your own library, the
+        <ulink url="http://git.clutter-project.org/mx/">Mx toolkit</ulink>
+        provides an excellent example of how to autotool your project.</para>
+      </note>
+
+      <example id="actors-composite-cb-button-h">
+        <title><filename>cb-button.h</filename>: header file</title>
+
+        <para>This defines the public API for the class, including
+        GObject type macros, class and object structures, and
+        function prototypes.</para>
+
+        <programlisting>
+<xi:include href="examples/cb-button.h" parse="text">
+<xi:fallback>a code sample should be here... but isn't</xi:fallback>
+</xi:include>
+        </programlisting>
+      </example>
+
+      <example id="actors-composite-cb-button-c">
+        <title><filename>cb-button.c</filename>: <type>ClutterActor</type>
+        and GObject implementation</title>
+
+        <para>This is the main C code file which implements both
+        the GObject and Clutter elements of <type>CbButton</type>.
+        The example below is liberally commented, and also gives some samples
+        of annotations to generate
+        <ulink url="http://www.gtk.org/gtk-doc/">gtk-docs</ulink> for the
+        widget. The
+        <link linkend="actors-composite-discussion-clutter-virtual-functions">discussion
+        section</link> comments more specifically about the Clutter-specific
+        parts of it.</para>
+
+        <programlisting>
+<xi:include href="examples/cb-button.c" parse="text">
+<xi:fallback>a code sample should be here... but isn't</xi:fallback>
+</xi:include>
+        </programlisting>
+      </example>
+
+      <example id="actors-composite-actors-composite-main-c">
+        <title><filename>actors-composite-main.c</filename>: trivial
+        application demonstrating usage of <type>CbButton</type></title>
+
+        <para>Note how any of the <type>ClutterActor</type>
+        functions (like <function>clutter_actor_set_size()</function>
+        and <function>clutter_actor_add_constraint()</function>) can
+        be applied to instances of our <type>ClutterActor</type>
+        implementation.</para>
+
+        <programlisting>
+<xi:include href="examples/actors-composite-main.c" parse="text">
+<xi:fallback>a code sample should be here... but isn't</xi:fallback>
+</xi:include>
+        </programlisting>
+      </example>
+
+    </section>
+
+    <section id="actors-composite-discussion">
+      <title>Discussion</title>
+
+      <para>The actor implemented here is based on
+      simple composition: bundling several actors together and wrapping
+      their behavior and properties. In the example here, we make use of a
+      <type>ClutterLayoutManager</type> to handle positioning of
+      the <type>ClutterText</type>; we change the background color of
+      the button by changing the color of the
+      <type>ClutterBox</type>; and we use a <type>ClutterClickAction</type>
+      to simplify implementation of a click signal.</para>
+
+      <para>You may find that this approach is appropriate if you need
+      to implement a simple rectangular actor. However, it puts some
+      constraints on the outline of the actor, making it harder to
+      use a custom outline: for example, a rectangle with rounded corners
+      or a shape which can't be approximated by a rectangle. Such cases
+      require both <function>pick()</function> and <function>paint()</function>
+      implementations using Cogl (or similar): see
+      <link linkend="actors-non-rectangular">this recipe</link>
+      for more details.</para>
+
+      <para>The composition approach may also be inappropriate where
+      you need to do a lot of custom animation and drawing; and it is
+      likely to be inappropriate for implementing a container
+      actor. See the notes on implementing a new actor in the Clutter
+      reference manual for more details of what may be required
+      in these cases.</para>
+
+      <section id="actors-composite-discussion-clutter-virtual-functions">
+        <title>Implementing <type>ClutterActor</type> virtual functions</title>
+
+        <para>While most of the <type>CbButton</type> implementation
+        revolves around GObject, there are some elements of it
+        specific to Clutter. Due to the simplicity of
+        the <type>CbButton</type> actor, the implementation of
+        these functions is fairly trivial, as explained below:</para>
+
+        <itemizedlist>
+
+          <listitem>
+
+            <formalpara>
+              <title>Object destruction:
+              <function>cb_button_destroy()</function></title>
+
+              <para><type>ClutterActor</type> subclasses based
+              on composition should implement the <function>destroy()</function>
+              virtual function. This is called on an actor when its
+              container is destroyed to clean up the resources
+              allocated to the actor; it also emits a
+              <emphasis>destroy</emphasis> signal which other code can
+              hook onto.</para>
+            </formalpara>
+
+            <para>In the case of <type>CbButton</type>, the
+            <function>destroy()</function> implementation calls
+            <function>clutter_actor_destroy()</function> on the child
+            <type>ClutterBox</type>, then sets that child to
+            <constant>NULL</constant>. Finally, it checks for a
+            <function>destroy()</function> implementation on the parent
+            class, then calls it if one exists.</para>
+
+          </listitem>
+
+          <listitem>
+
+            <formalpara>
+              <title>Size requisition:
+              <function>cb_button_get_preferred_height()</function>
+              and <function>cb_button_get_preferred_width()</function></title>
+
+              <para>During the size requisition phase, Clutter asks each
+              actor the minimum size it should be to remain useful,
+              and the maximum size it would be if unconstrained. This is done
+              by calling the <function>get_preferred_height()</function>
+              and <function>get_preferred_width()</function> functions
+              on each actor in turn.</para>
+            </formalpara>
+
+            <para>If an actor will only ever be explictly sized
+            (via <function>clutter_actor_set_size()</function>,
+            <function>clutter_actor_set_height()</function> and/or
+            <function>clutter_actor_set_width()</function>),
+            there is no need to implement the <function>get_preferred_*()</function>
+            functions. (Some actors like <type>ClutterRectangle</type>
+            work this way and require explicit sizing.)</para>
+
+            <para>However, if an actor's size should be negotiated during
+            the size requisition phase, you can implement these functions,
+            using the size of the child actors as a basis for the
+            preferred height and width. In the case of
+            <type>CbButton</type>, a preferred height and width can be
+            computed; these are based on the height and width of
+            the child <type>ClutterBox</type>, plus 20 pixels on each
+            axis. Because the size of the box is itself dependent on
+            the size of the <type>ClutterText</type> inside it, the net
+            result is that the <type>CbButton</type> preferred size
+            is the size of the text actor inside it, plus 20 pixels on each
+            axis.</para>
+
+          </listitem>
+
+          <listitem>
+
+            <formalpara>
+              <title>Allocation:
+              <function>cb_button_allocate()</function></title>
+
+              <para>The requests gathered during size requisition
+              are then negotiated by Clutter, each actor
+              receiving some allocation of the available space. At the
+              end of this process, each actor is allocated a
+              <emphasis>box</emphasis>, representing the space available
+              to it on the stage.</para>
+            </formalpara>
+
+            <para>An actor implementation is responsible for distributing
+            space from its allocation box to its children as it sees
+            fit. In the case of <type>CbButton</type>, there is only a single
+            <type>ClutterBox</type> actor which needs allocation;
+            <function>cb_button_allocate()</function> therefore
+            allocates all of the button's space to its child
+            <type>ClutterBox</type>.</para>
+
+          </listitem>
+
+          <listitem>
+
+            <formalpara>
+              <title>Painting and picking:
+              <function>cb_button_paint()</function></title>
+
+              <para>Clutter works its way through the actors on the
+              stage, following the actor hierarchy (top level
+              actors directly inside the stage first);
+              <function>clutter_actor_paint()</function>
+              is called on each actor. This, in turn, calls the actor's
+              <function>paint()</function> implementation. If the actor
+              is a container, it may iterate over its children,
+              calling <function>paint()</function> on each; the children
+              may call <function>paint()</function> on their children...;
+              and so on, until the leaves of the actor hierarchy are
+              reached.</para>
+            </formalpara>
+
+            <para>As our actor consists of a single <type>ClutterBox</type>
+            child, its <function>paint()</function> implementation simply
+            has to retrieve the reference to that <type>ClutterBox</type>
+            (from its private structure) and call
+            <function>clutter_actor_paint()</function>
+            on it. Painting of the <type>ClutterBox's</type> child
+            (the <type>ClutterText</type>) is handled by the
+            <type>ClutterBox</type>.</para>
+
+            <para>In cases where an actor is non-rectangular, you also
+            need to implement a <function>pick()</function> function.
+            (This is used to determine which actor was the recipient of
+            an event occurring within the stage.) However, because
+            the actor in this recipe is a simple rectangle, there is no
+            need to implement <function>pick()</function>.</para>
+
+          </listitem>
+
+        </itemizedlist>
+
+      </section>
+
+    </section>
+
+  </section>
+
   <section id="actors-allocation-notify">
     <title>Knowing when an actor's position or size changes</title>
 
index dfdcf43..4d65555 100644 (file)
@@ -3055,4 +3055,275 @@ g_object_set (actor,
 
   </section>
 
+  <section id="animations-path">
+    <title>Animating an actor along a curved path</title>
+
+    <section>
+      <title>Problem</title>
+
+      <para>You want to animate an actor along a curved path: for
+      example, to move an actor in a circle or spiral.</para>
+    </section>
+
+    <section>
+      <title>Solution</title>
+
+      <para>Create a <type>ClutterPath</type> to describe the
+      path the actor should move along; then create a
+      <type>ClutterPathConstraint</type> based on that path:</para>
+
+      <informalexample>
+        <programlisting>
+ClutterPath *path;
+ClutterConstraint *constraint;
+
+/* create the path */
+path = clutter_path_new ();
+
+/* first node is at 30,60 */
+clutter_path_add_move_to (path, 30, 60);
+
+/* add a curve to the top-right of the stage, with control
+ * points relative to the start point at 30,60
+ */
+clutter_path_add_rel_curve_to (path,
+                               120, 180,
+                               180, 120,
+                               240, 0);
+
+/* create a constraint based on the path */
+constraint = clutter_path_constraint_new (path, 0.0);
+        </programlisting>
+      </informalexample>
+
+      <note>
+        <para>For more on the types of curve and line segment available,
+        see the <type>ClutterPath</type> API documentation.</para>
+      </note>
+
+      <para>Next, add the constraint to an actor; in this case, the
+      actor is a red rectangle:</para>
+
+      <informalexample>
+        <programlisting>
+ClutterActor *rectangle;
+ClutterActor *stage = clutter_stage_new ();
+
+/* ...set size stage, color, etc... */
+
+const ClutterColor *red_color = clutter_color_new (255, 0, 0, 255);
+
+rectangle = clutter_rectangle_new_with_color (red_color);
+clutter_actor_set_size (rectangle, 60, 60);
+
+/* add the constraint to the rectangle; note that this
+ * puts the rectangle at the start of the path, i.e. at position 30,60;
+ * we also give the constraint a name, so we can use it from an implicit
+ * animation
+ */
+clutter_actor_add_constraint_with_name (rectangle, "path", constraint);
+
+/* add the rectangle to the stage */
+clutter_container_add_actor (CLUTTER_CONTAINER (stage), rectangle);
+        </programlisting>
+      </informalexample>
+
+      <para>Note how the constraint has to be assigned a name (here, "path")
+      to make it accessible via implicit animations.</para>
+
+      <para>Finally, animate the constraint's <varname>offset</varname>
+      property; which in turn moves the actor along the path:</para>
+
+      <informalexample>
+        <programlisting>
+ClutterTimeline *timeline;
+
+/* create a timeline with 1000 milliseconds duration, which loops
+ * indefinitely and reverses its direction each time it completes
+ */
+timeline = clutter_timeline_new (1000);
+clutter_timeline_set_loop (timeline, TRUE);
+clutter_timeline_set_auto_reverse (timeline, TRUE);
+
+/* animate the offset property on the constraint from 0.0 to 1.0;
+ * note the syntax used to refer to the constraints metadata for the
+ * rectangle actor:
+ *
+ *   "@constraints.&lt;constraint name&gt;.&lt;property&gt;"
+ */
+clutter_actor_animate_with_timeline (rectangle, CLUTTER_LINEAR, timeline,
+                                     "@constraints.path.offset", 1.0,
+                                     NULL);
+
+/* ...show the stage, run the mainloop, free memory on exit... */
+        </programlisting>
+      </informalexample>
+
+      <para>The <link linkend="animations-path-example-1">full
+      example</link> shows how these fragments fit together.
+      The animation produced by this example looks
+      like this:</para>
+
+      <inlinemediaobject>
+        <videoobject>
+          <videodata fileref="videos/animations-path.ogv"/>
+        </videoobject>
+        <alt>
+          <para>Video showing animation of an actor along a curved
+          path using <type>ClutterPathConstraint</type></para>
+        </alt>
+      </inlinemediaobject>
+
+      <para>The <link linkend="animations-path-example-2">second full
+      example</link> animates an actor around a simulated circle
+      using a more complex <type>ClutterPath</type>.</para>
+
+    </section>
+
+    <section>
+      <title>Discussion</title>
+
+      <para>Animating an actor using <type>ClutterPathConstraint</type>
+      is the recommended way to animate actors along curved paths. It
+      replaces the older <type>ClutterBehaviourPath</type>.</para>
+
+      <para>A <type>ClutterPathConstraint</type> constrains an
+      actor's <varname>x</varname> and <varname>y</varname> properties
+      to a position along such a <type>ClutterPath</type>: a path through
+      2D space. The <type>ClutterPath</type> itself is composed of nodes
+      (x,y positions in 2D space), connected by straight lines or (cubic)
+      <ulink url="http://en.wikipedia.org/wiki/B%C3%A9zier_curve">Bézier
+      curves</ulink>.</para>
+
+      <note>
+        <para><type>ClutterPath</type> doesn't have to be used in animations:
+        it can also be used in drawing (see the
+        <link linkend="actors-non-rectangular">non-rectangular actor
+        recipe</link>).</para>
+      </note>
+
+      <para>The actor's position along the path is determined by the constraint's
+      <varname>offset</varname> property, which has a
+      value between 0.0 and 1.0. When the offset is 0.0, the actor
+      is at the beginning of the path; when the actor is at 1.0, the
+      actor is at the end of the path. Between 0.0 and 1.0, the actor
+      is some fraction of the way along the path.</para>
+
+      <para>If you immediately set the <varname>offset</varname> for the
+      constraint (e.g. to <code>0.5</code>), the actor is instantly placed
+      at that position along the path: for <code>offset = 0.5</code>,
+      at the halfway point.</para>
+
+      <para>By contrast, to animate an actor along a path, you
+      <emphasis>animate</emphasis> the offset property of a
+      <type>ClutterPathConstraint</type>. The actor's position
+      along the path is dependent on the progress of the animation:
+      when the animation starts, the actor is at the beginning of the path;
+      by the end of the animation, it will have reached its end.</para>
+
+      <para>If you animate the constraint using a linear easing mode,
+      the progress of the animation matches progress along the path: at
+      half-way through the animation, the actor will be half-way along
+      the path.</para>
+
+      <para>However, if you are using a non-linear easing mode
+      (e.g. a quintic or cubic mode), the offset along the path and
+      progress through the animation may differ. This is because the
+      offset along the path is computed from the alpha value at that
+      point in the animation; this in turn depends on the alpha function
+      applied by the animation. (See the
+      <link linkend="animations-introduction">animations introduction</link>
+      for more details about alphas.)</para>
+
+      <para>One way to think about this is to imagine the actor
+      making a journey along the path. The alpha function governs the
+      actor's speed, including how it speeds up and slows down
+      during its journey. The actor's speed may be constant
+      (as in a linear easing mode). Alternatively, the actor's speed
+      may not be constant: it might start out fast then slow down
+      (ease out); or start slow and speed up (ease in); or start and
+      end fast, but slow down in the middle (ease in and ease out); or
+      some other more complex arrangement (as in the bounce and elastic
+      easing modes). So where the actor is on the path at a particular
+      time doesn't directly relate to how long it's been travelling:
+      the position is determined both by how long it's been travelling,
+      and changes in its speed throughout the journey.</para>
+
+      <section>
+        <title>Other ways to animate along a path</title>
+
+        <para><type>ClutterPathConstraint</type> is the only
+        decent way of animating along curves in a predictable
+        and manageable fashion. It can also be used to animate along
+        paths composed of straight lines, though this isn't essential: you
+        can do straight line animations directly with <type>ClutterAnimator</type>,
+        <type>ClutterState</type> or implicit animations. But if
+        you need to animate between more than a half a dozen sets of
+        points joined by straight lines, <type>ClutterPathConstraint</type>
+        makes sense then too.</para>
+
+        <para>It is also possible to animate actors over very simple, non-Bézier
+        curves without using <type>ClutterPathConstraint</type>. This
+        can be done by animating the actor's position properties using
+        a non-linear easing mode (see the <type>ClutterAlpha</type>
+        documentation for available modes, or write your own custom
+        alpha function). <link linkend="animations-path-example-3">This
+        example</link> shows how to animate two actors on
+        curved paths around each other without
+        <type>ClutterPathConstraint</type>.</para>
+
+        <para>However, it is difficult to precisely calculate paths
+        with this approach. It is also only practical where you have a
+        very simple curve: if you want to chain together several curved
+        motions (as in the <link linkend="animations-path-example-2">circle
+        example</link>), this quickly becomes unwieldy.</para>
+
+        <tip>
+          <para>
+          If you want physics-based animation, look at
+          <ulink url="http://git.clutter-project.org/clutter-box2d/">clutter-box2d</ulink>.
+          </para>
+        </tip>
+
+      </section>
+
+    </section>
+
+    <section id="animations-path-examples">
+      <title>Full examples</title>
+
+      <example id="animations-path-example-1">
+        <title>Using a <type>ClutterPathConstraint</type> with
+        implicit animations to move an actor along a curved path</title>
+        <programlisting>
+<xi:include href="examples/animations-path.c" parse="text">
+  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
+</xi:include>
+        </programlisting>
+      </example>
+
+      <example id="animations-path-example-2">
+        <title>Using a <type>ClutterPathConstraint</type> with
+        <type>ClutterAnimator</type> to animate an actor on
+        a simulated circular path</title>
+        <programlisting>
+<xi:include href="examples/animations-path-circle.c" parse="text">
+  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
+</xi:include>
+        </programlisting>
+      </example>
+
+      <example id="animations-path-example-3">
+        <title>Animating actors on curved paths using easing modes</title>
+        <programlisting>
+<xi:include href="examples/animations-path-easing.c" parse="text">
+  <xi:fallback>a code sample should be here... but isn't</xi:fallback>
+</xi:include>
+        </programlisting>
+      </example>
+
+    </section>
+
+  </section>
+
 </chapter>
index 7021274..2e4e28a 100644 (file)
@@ -3,42 +3,46 @@ include $(top_srcdir)/build/autotools/Makefile.am.silent
 NULL =
 
 noinst_PROGRAMS = \
-       animations-complex      \
-       animations-looping-animator     \
-       animations-looping-implicit     \
-       animations-looping-state        \
-       animations-moving-animator      \
-       animations-moving-implicit      \
-       animations-moving-state \
-       animations-reuse        \
-       animations-rotating     \
-       animations-scaling      \
-       animations-scaling-zoom \
-       text-shadow             \
-       textures-reflection     \
-       textures-split-go       \
-       textures-sub-texture    \
+       actors-composite-main                   \
+       animations-complex                      \
+       animations-looping-animator             \
+       animations-looping-implicit             \
+       animations-looping-state                \
+       animations-moving-animator              \
+       animations-moving-implicit              \
+       animations-moving-state                 \
+       animations-path                 \
+       animations-path-circle                  \
+       animations-path-easing                  \
+       animations-reuse                        \
+       animations-rotating                     \
+       animations-scaling                      \
+       animations-scaling-zoom                 \
+       text-shadow                             \
+       textures-reflection                     \
+       textures-split-go                       \
+       textures-sub-texture                    \
        layouts-bind-constraint-allocation      \
-       layouts-bind-constraint-overlay \
-       layouts-bind-constraint-stage   \
-       layouts-box \
-       layouts-box-menu \
-       layouts-box-property-effects \
-       layouts-stacking \
+       layouts-bind-constraint-overlay         \
+       layouts-bind-constraint-stage           \
+       layouts-box                             \
+       layouts-box-menu                        \
+       layouts-box-property-effects            \
+       layouts-stacking                        \
        layouts-stacking-diff-sized-actors      \
-       events-mouse-scroll \
-       events-pointer-motion   \
-       events-pointer-motion-crossing  \
-       events-pointer-motion-stacked   \
-       events-pointer-motion-scribbler \
-       textures-crossfade      \
-       textures-crossfade-cogl \
-       textures-crossfade-slideshow    \
-       script-ui       \
-       script-signals  \
-       events-buttons  \
-       events-buttons-click    \
-       events-buttons-lasso    \
+       events-mouse-scroll                     \
+       events-pointer-motion                   \
+       events-pointer-motion-crossing          \
+       events-pointer-motion-stacked           \
+       events-pointer-motion-scribbler         \
+       textures-crossfade                      \
+       textures-crossfade-cogl                 \
+       textures-crossfade-slideshow            \
+       script-ui                               \
+       script-signals                          \
+       events-buttons                          \
+       events-buttons-click                    \
+       events-buttons-lasso                    \
        $(NULL)
 
 INCLUDES = \
@@ -62,6 +66,7 @@ AM_CFLAGS = \
 
 AM_LDFLAGS = $(CLUTTER_LIBS) -export-dynamic
 
+actors_composite_main_SOURCES              = cb-button.c cb-button.h actors-composite-main.c
 animations_complex_SOURCES                 = animations-complex.c
 animations_looping_animator_SOURCES        = animations-looping-animator.c
 animations_looping_implicit_SOURCES        = animations-looping-implicit.c
@@ -69,6 +74,9 @@ animations_looping_state_SOURCES           = animations-looping-state.c
 animations_moving_animator_SOURCES         = animations-moving-animator.c
 animations_moving_implicit_SOURCES         = animations-moving-implicit.c
 animations_moving_state_SOURCES            = animations-moving-state.c
+animations_path_SOURCES                    = animations-path.c
+animations_path_circle_SOURCES             = animations-path-circle.c
+animations_path_easing_SOURCES             = animations-path-easing.c
 animations_reuse_SOURCES                   = animations-reuse.c
 animations_rotating_SOURCES                = animations-rotating.c
 animations_scaling_SOURCES                 = animations-scaling.c
diff --git a/doc/cookbook/examples/actors-composite-main.c b/doc/cookbook/examples/actors-composite-main.c
new file mode 100644 (file)
index 0000000..2df5fa9
--- /dev/null
@@ -0,0 +1,79 @@
+#include <stdlib.h>
+#include "cb-button.h"
+
+/* colors */
+static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff };
+static const ClutterColor white_color = { 0xff, 0xff, 0xff, 0xff };
+static const ClutterColor yellow_color = { 0x88, 0x88, 0x00, 0xff };
+
+/* click handler */
+static void
+clicked (CbButton *button,
+         gpointer  data)
+{
+  const gchar *current_text;
+
+  g_debug ("Clicked");
+
+  current_text = cb_button_get_text (button);
+
+  if (g_strcmp0 (current_text, "hello") == 0)
+    cb_button_set_text (button, "world");
+  else
+    cb_button_set_text (button, "hello");
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  ClutterActor *stage;
+  ClutterActor *button;
+  ClutterConstraint *align_x_constraint;
+  ClutterConstraint *align_y_constraint;
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_new ();
+  clutter_actor_set_size (stage, 400, 400);
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
+
+  button = cb_button_new ();
+  cb_button_set_text (CB_BUTTON (button), "hello");
+
+  /* the following is equivalent to the two lines above:
+   *
+   *  button = g_object_new (CB_TYPE_BUTTON,
+   *                         "text", "winkle",
+   *                         NULL);
+   *
+   * because we defined a set_property function, which can accept
+   * a PROP_TEXT parameter, GObject can create a button and set one
+   * or more properties with a single call to g_object_new()
+   */
+
+  /* note that the size of the button is left to Clutter's size requisition */
+  cb_button_set_text_color (CB_BUTTON (button), &white_color);
+  cb_button_set_background_color (CB_BUTTON (button), &yellow_color);
+  g_signal_connect (button, "clicked", G_CALLBACK (clicked), NULL);
+
+  align_x_constraint = clutter_align_constraint_new (stage,
+                                                     CLUTTER_ALIGN_X_AXIS,
+                                                     0.5);
+
+  align_y_constraint = clutter_align_constraint_new (stage,
+                                                     CLUTTER_ALIGN_Y_AXIS,
+                                                     0.5);
+
+  clutter_actor_add_constraint (button, align_x_constraint);
+  clutter_actor_add_constraint (button, align_y_constraint);
+
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), button);
+
+  clutter_actor_show (stage);
+
+  clutter_main ();
+
+  return EXIT_SUCCESS;
+}
diff --git a/doc/cookbook/examples/animations-path-circle.c b/doc/cookbook/examples/animations-path-circle.c
new file mode 100644 (file)
index 0000000..23a13e6
--- /dev/null
@@ -0,0 +1,128 @@
+#include <stdlib.h>
+#include <clutter/clutter.h>
+
+#define STAGE_SIDE 400.0
+
+static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff };
+static const ClutterColor red_color = { 0xff, 0x00, 0x00, 0xff };
+
+/* Build a "circular" path out of 4 Bezier curves
+ *
+ * code modified from
+ * http://git.clutter-project.org/dax/tree/dax/dax-traverser-clutter.c#n328
+ *
+ * see http://www.whizkidtech.redprince.net/bezier/circle/
+ * for further explanation
+ */
+static ClutterPath *
+build_circular_path (gfloat cx,
+                     gfloat cy,
+                     gfloat r)
+{
+  ClutterPath *path;
+  static gfloat kappa = 4 * (G_SQRT2 - 1) / 3;
+
+  path = clutter_path_new ();
+
+  clutter_path_add_move_to (path, cx + r, cy);
+  clutter_path_add_curve_to (path,
+                             cx + r, cy + r * kappa,
+                             cx + r * kappa, cy + r,
+                             cx, cy + r);
+  clutter_path_add_curve_to (path,
+                             cx - r * kappa, cy + r,
+                             cx - r, cy + r * kappa,
+                             cx - r, cy);
+  clutter_path_add_curve_to (path,
+                             cx - r, cy - r * kappa,
+                             cx - r * kappa, cy - r,
+                             cx, cy - r);
+  clutter_path_add_curve_to (path,
+                             cx + r * kappa, cy - r,
+                             cx + r, cy - r * kappa,
+                             cx + r, cy);
+  clutter_path_add_close (path);
+
+  return path;
+}
+
+static gboolean
+key_pressed_cb (ClutterActor *actor,
+                ClutterEvent *event,
+                gpointer      user_data)
+{
+  ClutterTimeline *timeline = CLUTTER_TIMELINE (user_data);
+
+  if (!clutter_timeline_is_playing (timeline))
+    clutter_timeline_start (timeline);
+
+  return TRUE;
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  ClutterPath *path;
+  ClutterConstraint *constraint;
+  ClutterAnimator *animator;
+  ClutterTimeline *timeline;
+  ClutterActor *stage;
+  ClutterActor *rectangle;
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_new ();
+  clutter_actor_set_size (stage, STAGE_SIDE, STAGE_SIDE);
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
+
+  rectangle = clutter_rectangle_new_with_color (&red_color);
+  clutter_actor_set_size (rectangle, STAGE_SIDE / 8, STAGE_SIDE / 8);
+  clutter_actor_set_position (rectangle,
+                              STAGE_SIDE / 2,
+                              STAGE_SIDE / 2);
+
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage),
+                               rectangle);
+
+  /* set up a path and make a constraint with it */
+  path = build_circular_path (STAGE_SIDE / 2,
+                              STAGE_SIDE / 2,
+                              STAGE_SIDE / 4);
+  constraint = clutter_path_constraint_new (path, 0.0);
+
+  /* apply the constraint to the rectangle; note that there
+   * is no need to name the constraint, as we will be animating
+   * the constraint's offset property directly using ClutterAnimator
+   */
+  clutter_actor_add_constraint (rectangle, constraint);
+
+  /* animation to animate the path offset */
+  animator = clutter_animator_new ();
+  clutter_animator_set_duration (animator, 5000);
+
+  /* use ClutterAnimator to animate the constraint directly */
+  clutter_animator_set (animator,
+                        constraint, "offset", CLUTTER_LINEAR, 0.0, 0.0,
+                        constraint, "offset", CLUTTER_LINEAR, 1.0, 1.0,
+                        NULL);
+
+  timeline = clutter_animator_get_timeline (animator);
+  clutter_timeline_set_loop (timeline, TRUE);
+  clutter_timeline_set_auto_reverse (timeline, TRUE);
+
+  g_signal_connect (stage,
+                    "key-press-event",
+                    G_CALLBACK (key_pressed_cb),
+                    timeline);
+
+  clutter_actor_show (stage);
+
+  clutter_main ();
+
+  /* clean up */
+  g_object_unref (animator);
+
+  return EXIT_SUCCESS;
+}
diff --git a/doc/cookbook/examples/animations-path-easing.c b/doc/cookbook/examples/animations-path-easing.c
new file mode 100644 (file)
index 0000000..8a1da76
--- /dev/null
@@ -0,0 +1,104 @@
+#include <stdlib.h>
+#include <clutter/clutter.h>
+
+typedef struct {
+  ClutterActor *red;
+  ClutterActor *green;
+  ClutterTimeline *timeline;
+} State;
+
+static const ClutterColor stage_color = { 0x33, 0x33, 0x55, 0xff };
+static const ClutterColor red_color = { 0xff, 0x00, 0x00, 0xff };
+static const ClutterColor green_color = { 0x00, 0xff, 0x00, 0xff };
+
+static void
+reverse_timeline (ClutterTimeline *timeline)
+{
+  ClutterTimelineDirection dir = clutter_timeline_get_direction (timeline);
+
+  if (dir == CLUTTER_TIMELINE_FORWARD)
+    dir = CLUTTER_TIMELINE_BACKWARD;
+  else
+    dir = CLUTTER_TIMELINE_FORWARD;
+
+  clutter_timeline_set_direction (timeline, dir);
+}
+
+/* a key press either starts the timeline or reverses it */
+static gboolean
+key_pressed_cb (ClutterActor *actor,
+                ClutterEvent *event,
+                gpointer      user_data)
+{
+  State *state = (State *) user_data;
+
+  if (clutter_timeline_is_playing (state->timeline))
+    reverse_timeline (state->timeline);
+  else
+    clutter_timeline_start (state->timeline);
+
+  return TRUE;
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  State *state = g_new0 (State, 1);
+
+  ClutterActor *stage;
+  ClutterAnimator *animator;
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_new ();
+  clutter_actor_set_size (stage, 400, 400);
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
+
+  state->red = clutter_rectangle_new_with_color (&red_color);
+  clutter_actor_set_size (state->red, 100, 100);
+  clutter_actor_set_position (state->red, 300, 300);
+
+  state->green = clutter_rectangle_new_with_color (&green_color);
+  clutter_actor_set_size (state->green, 100, 100);
+  clutter_actor_set_position (state->green, 0, 0);
+
+  animator = clutter_animator_new ();
+  clutter_animator_set_duration (animator, 1000);
+
+  clutter_animator_set (animator,
+                        state->red, "x", CLUTTER_LINEAR, 0.0, 300.0,
+                        state->red, "y", CLUTTER_LINEAR, 0.0, 300.0,
+                        state->red, "x", CLUTTER_LINEAR, 1.0, 0.0,
+                        state->red, "y", CLUTTER_EASE_IN_QUINT, 1.0, 0.0,
+                        NULL);
+
+  clutter_animator_set (animator,
+                        state->green, "x", CLUTTER_LINEAR, 0.0, 0.0,
+                        state->green, "y", CLUTTER_LINEAR, 0.0, 0.0,
+                        state->green, "x", CLUTTER_LINEAR, 1.0, 300.0,
+                        state->green, "y", CLUTTER_EASE_IN_QUINT, 1.0, 300.0,
+                        NULL);
+
+  state->timeline = clutter_animator_get_timeline (animator);
+
+  clutter_timeline_set_auto_reverse (state->timeline, TRUE);
+
+  g_signal_connect (stage,
+                    "key-press-event",
+                    G_CALLBACK (key_pressed_cb),
+                    state);
+
+  clutter_container_add (CLUTTER_CONTAINER (stage), state->red, state->green, NULL);
+
+  clutter_actor_show (stage);
+
+  clutter_main ();
+
+  g_object_unref (animator);
+
+  g_free (state);
+
+  return EXIT_SUCCESS;
+}
diff --git a/doc/cookbook/examples/animations-path.c b/doc/cookbook/examples/animations-path.c
new file mode 100644 (file)
index 0000000..c368657
--- /dev/null
@@ -0,0 +1,61 @@
+#include <stdlib.h>
+#include <clutter/clutter.h>
+
+int
+main (int   argc,
+      char *argv[])
+{
+  ClutterActor *stage;
+  ClutterPath *path;
+  ClutterConstraint *constraint;
+  ClutterActor *rectangle;
+  ClutterTimeline *timeline;
+
+  const ClutterColor *stage_color = clutter_color_new (51, 51, 85, 255);
+  const ClutterColor *red_color = clutter_color_new (255, 0, 0, 255);
+
+  clutter_init (&argc, &argv);
+
+  stage = clutter_stage_new ();
+  clutter_actor_set_size (stage, 360, 300);
+  clutter_stage_set_color (CLUTTER_STAGE (stage), stage_color);
+  g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
+
+  /* create the path */
+  path = clutter_path_new ();
+  clutter_path_add_move_to (path, 30, 60);
+
+  /* add a curve round to the top-right of the stage */
+  clutter_path_add_rel_curve_to (path,
+                                 120, 180,
+                                 180, 120,
+                                 240, 0);
+
+  /* create a constraint based on the path */
+  constraint = clutter_path_constraint_new (path, 0.0);
+
+  /* put a rectangle at the start of the path */
+  rectangle = clutter_rectangle_new_with_color (red_color);
+  clutter_actor_set_size (rectangle, 60, 60);
+
+  /* add the constraint to the rectangle */
+  clutter_actor_add_constraint_with_name (rectangle, "path", constraint);
+
+  /* add the rectangle to the stage */
+  clutter_container_add_actor (CLUTTER_CONTAINER (stage), rectangle);
+
+  /* set up the timeline */
+  timeline = clutter_timeline_new (1000);
+  clutter_timeline_set_loop (timeline, TRUE);
+  clutter_timeline_set_auto_reverse (timeline, TRUE);
+
+  clutter_actor_animate_with_timeline (rectangle, CLUTTER_LINEAR, timeline,
+                                       "@constraints.path.offset", 1.0,
+                                       NULL);
+
+  clutter_actor_show (stage);
+
+  clutter_main ();
+
+  return EXIT_SUCCESS;
+}
diff --git a/doc/cookbook/examples/cb-button.c b/doc/cookbook/examples/cb-button.c
new file mode 100644 (file)
index 0000000..0260d14
--- /dev/null
@@ -0,0 +1,451 @@
+#include "cb-button.h"
+
+/**
+ * SECTION:cb-button
+ * @short_description: Button widget
+ *
+ * A button widget with support for a text label and background color.
+ */
+
+/* convenience macro for GType implementations; see:
+ * http://library.gnome.org/devel/gobject/2.27/gobject-Type-Information.html#G-DEFINE-TYPE:CAPS
+ */
+G_DEFINE_TYPE (CbButton, cb_button, CLUTTER_TYPE_ACTOR);
+
+/* macro for accessing the object's private structure */
+#define CB_BUTTON_GET_PRIVATE(obj) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CB_TYPE_BUTTON, CbButtonPrivate))
+
+/* private structure - should only be accessed through the public API;
+ * this is used to store member variables whose properties
+ * need to be accessible from the implementation; for example, if we
+ * intend to create wrapper functions which modify properties on the
+ * actors composing an object, we should keep a reference to the actors
+ * here
+ *
+ * this is also the place where other state variables go:
+ * for example, you might record the current state of the button
+ * (toggled on or off) or a background image
+ */
+struct _CbButtonPrivate
+{
+  ClutterActor  *child;
+  ClutterActor  *label;
+  ClutterAction *click_action;
+  gchar         *text;
+};
+
+/* enumerates property identifiers for this class;
+ * note that property identifiers should be non-zero integers,
+ * so we add an unused PROP_0 to occupy the 0 position in the enum
+ */
+enum {
+  PROP_0,
+  PROP_TEXT
+};
+
+/* enumerates signal identifiers for this class;
+ * LAST_SIGNAL is not used as a signal identifier, but is instead
+ * used to delineate the size of the cache array for signals (see below)
+ */
+enum {
+  CLICKED,
+  LAST_SIGNAL
+};
+
+/* cache array for signals */
+static guint cb_button_signals[LAST_SIGNAL] = { 0, };
+
+/* from http://mail.gnome.org/archives/gtk-devel-list/2004-July/msg00158.html:
+ *
+ * "The finalize method finishes releasing the remaining
+ * resources just before the object itself will be freed from memory, and
+ * therefore it will only be called once. The two step process helps break
+ * cyclic references. Both dispose and finalize must chain up to their
+ * parent objects by calling their parent's respective methods *after* they
+ * have disposed or finalized their own members."
+ */
+static void
+cb_button_finalize (GObject *gobject)
+{
+  CbButtonPrivate *priv = CB_BUTTON (gobject)->priv;
+
+  g_free (priv->text);
+
+  /* call the parent class' finalize() method */
+  G_OBJECT_CLASS (cb_button_parent_class)->finalize (gobject);
+}
+
+/* enables objects to be uniformly treated as GObjects;
+ * also exposes properties so they become scriptable, e.g.
+ * through ClutterScript
+ */
+static void
+cb_button_set_property (GObject      *gobject,
+                        guint         prop_id,
+                        const GValue *value,
+                        GParamSpec   *pspec)
+{
+  CbButton *button = CB_BUTTON (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_TEXT:
+      cb_button_set_text (button, g_value_get_string (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+/* enables objects to be uniformly treated as GObjects */
+static void
+cb_button_get_property (GObject    *gobject,
+                        guint       prop_id,
+                        GValue     *value,
+                        GParamSpec *pspec)
+{
+  CbButtonPrivate *priv = CB_BUTTON (gobject)->priv;
+
+  switch (prop_id)
+    {
+    case PROP_TEXT:
+      g_value_set_string (value, priv->text);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+/* ClutterActor implementation
+ *
+ * we only implement destroy(), get_preferred_height(), get_preferred_width(),
+ * allocate(), and paint(), as this is the minimum we can get away with
+ */
+
+/* composite actors should implement destroy(), and inside their
+ * implementation destroy any actors they are composed from;
+ * in this case, we just destroy the child ClutterBox
+ */
+static void
+cb_button_destroy (ClutterActor *self)
+{
+  CbButtonPrivate *priv = CB_BUTTON (self)->priv;
+
+  /* we just destroy the child, and let the child
+   * deal with destroying _its_ children; note that we have a guard
+   * here in case the child has already been destroyed
+   */
+  if (priv->child)
+    {
+      clutter_actor_destroy (priv->child);
+      priv->child = NULL;
+    }
+
+  /* chain up to destroy() on the parent ClutterActorClass;
+   * note that we check the parent class has a destroy() implementation
+   * before calling it
+   */
+  if (CLUTTER_ACTOR_CLASS (cb_button_parent_class)->destroy)
+    CLUTTER_ACTOR_CLASS (cb_button_parent_class)->destroy (self);
+}
+
+/* get_preferred_height and get_preferred_width defer to the
+ * internal ClutterBox, adding 20px padding on each axis;
+ * min_*_p is the minimum height or width the actor should occupy
+ * to be useful; natural_*_p is the height or width the actor
+ * would occupy if not constrained
+ *
+ * note that if we required explicit sizing for CbButtons
+ * (i.e. a developer must set their height and width),
+ * we wouldn't need to implement these functions
+ */
+static void
+cb_button_get_preferred_height (ClutterActor *self,
+                                gfloat for_width,
+                                gfloat *min_height_p,
+                                gfloat *natural_height_p)
+{
+  CbButtonPrivate *priv = CB_BUTTON (self)->priv;
+
+  clutter_actor_get_preferred_height (priv->child,
+                                      for_width,
+                                      min_height_p,
+                                      natural_height_p);
+
+  *min_height_p += 20.0;
+  *natural_height_p += 20.0;
+}
+
+static void
+cb_button_get_preferred_width (ClutterActor *self,
+                               gfloat for_height,
+                               gfloat *min_width_p,
+                               gfloat *natural_width_p)
+{
+  CbButtonPrivate *priv = CB_BUTTON (self)->priv;
+
+  clutter_actor_get_preferred_width (priv->child,
+                                     for_height,
+                                     min_width_p,
+                                     natural_width_p);
+
+  *min_width_p += 20.0;
+  *natural_width_p += 20.0;
+}
+
+/* use the actor's allocation for the ClutterBox */
+static void
+cb_button_allocate (ClutterActor          *actor,
+                    const ClutterActorBox *box,
+                    ClutterAllocationFlags flags)
+{
+  CbButtonPrivate *priv = CB_BUTTON (actor)->priv;
+  ClutterActorBox child_box = { 0, };
+
+  /* set the allocation for the whole button */
+  CLUTTER_ACTOR_CLASS (cb_button_parent_class)->allocate (actor, box, flags);
+
+  /* make the child (the ClutterBox) fill the parent;
+   * note that this allocation box is relative to the
+   * coordinates of the whole button actor, so we can't just
+   * use the box passed into this function; instead, it
+   * is adjusted to span the whole of the actor, from its
+   * top-left corner (0,0) to its bottom-right corner
+   * (width,height)
+   */
+  child_box.x1 = 0.0;
+  child_box.y1 = 0.0;
+  child_box.x2 = clutter_actor_box_get_width (box);
+  child_box.y2 = clutter_actor_box_get_height (box);
+
+  clutter_actor_allocate (priv->child, &child_box, flags);
+}
+
+/* paint function implementation: just calls paint() on the ClutterBox */
+static void
+cb_button_paint (ClutterActor *actor)
+{
+  CbButtonPrivate *priv = CB_BUTTON (actor)->priv;
+
+  clutter_actor_paint (priv->child);
+}
+
+/* proxy ClickAction signals so they become signals from the actor */
+static void
+cb_button_clicked (ClutterClickAction *action,
+                   ClutterActor       *actor,
+                   gpointer            user_data)
+{
+  /* emit signal via the cache array */
+  g_signal_emit (actor, cb_button_signals[CLICKED], 0);
+}
+
+/* GObject class and instance initialization functions; note that
+ * these have been placed after the Clutter implementation, as
+ * they refer to the static function implementations above
+ */
+
+/* class init: attach functions to superclasses, define properties
+ * and signals
+ */
+static void
+cb_button_class_init (CbButtonClass *klass)
+{
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GParamSpec *pspec;
+
+  gobject_class->finalize = cb_button_finalize;
+  gobject_class->set_property = cb_button_set_property;
+  gobject_class->get_property = cb_button_get_property;
+
+  actor_class->destroy = cb_button_destroy;
+  actor_class->get_preferred_height = cb_button_get_preferred_height;
+  actor_class->get_preferred_width = cb_button_get_preferred_width;
+  actor_class->allocate = cb_button_allocate;
+  actor_class->paint = cb_button_paint;
+
+  g_type_class_add_private (klass, sizeof (CbButtonPrivate));
+
+  /**
+   * CbButton:text:
+   *
+   * The text shown on the #CbButton
+   */
+  pspec = g_param_spec_string ("text",
+                               "Text",
+                               "Text of the button",
+                               NULL,
+                               G_PARAM_READWRITE);
+  g_object_class_install_property (gobject_class, PROP_TEXT, pspec);
+
+  /**
+   * CbButton::clicked:
+   * @button: the #CbButton that emitted the signal
+   *
+   * The ::clicked signal is emitted when the internal #ClutterClickAction
+   * associated with a #CbButton emits its own ::clicked signal
+   */
+  cb_button_signals[CLICKED] =
+    g_signal_new ("clicked",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (CbButtonClass, clicked),
+                  NULL,
+                  NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE,
+                  0);
+}
+
+/* object init: create a private structure and pack
+ * composed ClutterActors into it
+ */
+static void
+cb_button_init (CbButton *self)
+{
+  CbButtonPrivate *priv;
+  ClutterLayoutManager *layout;
+
+  priv = self->priv = CB_BUTTON_GET_PRIVATE (self);
+
+  clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
+
+  /* the only child of this actor is a ClutterBox with a
+   * ClutterBinLayout: painting and allocation of the actor basically
+   * involves painting and allocating this child box
+   */
+  layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
+                                   CLUTTER_BIN_ALIGNMENT_CENTER);
+
+  priv->child = clutter_box_new (layout);
+
+  /* set the parent of the ClutterBox to this instance */
+  clutter_actor_set_parent (priv->child,
+                            CLUTTER_ACTOR (self));
+
+  /* add text label to the button; see the ClutterText API docs
+   * for more information about available properties
+   */
+  priv->label = g_object_new (CLUTTER_TYPE_TEXT,
+                              "line-alignment", PANGO_ALIGN_CENTER,
+                              "ellipsize", PANGO_ELLIPSIZE_END,
+                              NULL);
+
+  clutter_container_add_actor (CLUTTER_CONTAINER (priv->child),
+                               priv->label);
+
+  /* add a ClutterClickAction on this actor, so we can proxy its
+   * "clicked" signal into a signal from this actor
+   */
+  priv->click_action = clutter_click_action_new ();
+  clutter_actor_add_action (CLUTTER_ACTOR (self), priv->click_action);
+
+  g_signal_connect (priv->click_action,
+                    "clicked",
+                    G_CALLBACK (cb_button_clicked),
+                    NULL);
+}
+
+/* public API */
+/* examples of public API functions which wrap functions
+ * on internal actors
+ */
+
+/**
+ * cb_button_set_text:
+ * @self: a #CbButton
+ * @text: the text to display on the button
+ *
+ * Set the text on the button
+ */
+void
+cb_button_set_text (CbButton    *self,
+                    const gchar *text)
+{
+  CbButtonPrivate *priv;
+
+  /* public API should check its arguments;
+   * see also g_return_val_if_fail for functions which
+   * return a value
+   */
+  g_return_if_fail (CB_IS_BUTTON (self));
+
+  priv = self->priv;
+
+  g_free (priv->text);
+
+  if (text)
+    priv->text = g_strdup (text);
+  else
+    priv->text = g_strdup ("");
+
+  /* call a function on the ClutterText inside the layout */
+  clutter_text_set_text (CLUTTER_TEXT (priv->label), priv->text);
+}
+
+/**
+ * cb_button_set_background_color:
+ * @self: a #CbButton
+ * @color: the #ClutterColor to use for the button's background
+ *
+ * Set the color of the button's background
+ */
+void
+cb_button_set_background_color (CbButton           *self,
+                                const ClutterColor *color)
+{
+  g_return_if_fail (CB_IS_BUTTON (self));
+
+  clutter_box_set_color (CLUTTER_BOX (self->priv->child), color);
+}
+
+/**
+ * cb_button_set_text_color:
+ * @self: a #CbButton
+ * @color: the #ClutterColor to use as the color for the button text
+ *
+ * Set the color of the text on the button
+ */
+void
+cb_button_set_text_color (CbButton           *self,
+                          const ClutterColor *color)
+{
+  g_return_if_fail (CB_IS_BUTTON (self));
+
+  clutter_text_set_color (CLUTTER_TEXT (self->priv->label), color);
+}
+
+/**
+ * cb_button_get_text:
+ * @self: a #CbButton
+ *
+ * Get the text displayed on the button
+ *
+ * Returns: the button's text. This must not be freed by the application.
+ */
+G_CONST_RETURN gchar *
+cb_button_get_text (CbButton *self)
+{
+  g_return_val_if_fail (CB_IS_BUTTON (self), NULL);
+
+  return self->priv->text;
+}
+
+/**
+ * cb_button_new:
+ *
+ * Creates a new #CbButton instance
+ *
+ * Returns: a new #CbButton
+ */
+ClutterActor *
+cb_button_new (void)
+{
+  return g_object_new (CB_TYPE_BUTTON, NULL);
+}
diff --git a/doc/cookbook/examples/cb-button.h b/doc/cookbook/examples/cb-button.h
new file mode 100644 (file)
index 0000000..9362a49
--- /dev/null
@@ -0,0 +1,84 @@
+/* inclusion guard */
+#ifndef __CB_BUTTON_H__
+#define __CB_BUTTON_H__
+
+/* include any dependencies */
+#include <clutter/clutter.h>
+
+/* GObject implementation */
+
+/* declare this function signature to remove compilation errors with -Wall;
+ * the cb_button_get_type() function is actually added via the
+ * G_DEFINE_TYPE macro in the .c file
+ */
+GType cb_button_get_type (void);
+
+/* GObject type macros */
+/* returns the class type identifier (GType) for CbButton */
+#define CB_TYPE_BUTTON            (cb_button_get_type ())
+
+/* cast obj to a CbButton object structure*/
+#define CB_BUTTON(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), CB_TYPE_BUTTON, CbButton))
+
+/* check whether obj is a CbButton */
+#define CB_IS_BUTTON(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CB_TYPE_BUTTON))
+
+/* cast klass to CbButtonClass class structure */
+#define CB_BUTTON_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), CB_TYPE_BUTTON, CbButtonClass))
+
+/* check whether klass is a member of the CbButtonClass */
+#define CB_IS_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CB_TYPE_BUTTON))
+
+/* get the CbButtonClass structure for a CbButton obj */
+#define CB_BUTTON_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), CB_TYPE_BUTTON, CbButtonClass))
+
+/*
+ * Private instance fields; see
+ * http://www.gotw.ca/gotw/024.htm for the rationale
+ */
+typedef struct _CbButtonPrivate CbButtonPrivate;
+typedef struct _CbButton        CbButton;
+typedef struct _CbButtonClass   CbButtonClass;
+
+/* object structure */
+struct _CbButton
+{
+  /*<private>*/
+  ClutterActor parent_instance;
+
+  /* structure containing private members */
+  /*<private>*/
+  CbButtonPrivate *priv;
+};
+
+/* class structure */
+struct _CbButtonClass
+{
+  /* signals */
+  void (* clicked)(CbButton *button);
+
+  /*<private>*/
+  ClutterActorClass parent_class;
+};
+
+/* public API */
+
+/* constructor - note this returns a ClutterActor instance */
+ClutterActor *cb_button_new (void);
+
+/* getter */
+G_CONST_RETURN gchar * cb_button_get_text (CbButton *self);
+
+/* setters - these are wrappers round functions
+ * which change properties of the internal actors
+ */
+void cb_button_set_text (CbButton    *self,
+                         const gchar *text);
+
+void cb_button_set_background_color (CbButton           *self,
+                                     const ClutterColor *color);
+
+void cb_button_set_text_color (CbButton           *self,
+                               const ClutterColor *color);
+
+#endif /* __CB_BUTTON_H__ */
diff --git a/doc/cookbook/videos/animations-path.ogv b/doc/cookbook/videos/animations-path.ogv
new file mode 100644 (file)
index 0000000..13578c8
Binary files /dev/null and b/doc/cookbook/videos/animations-path.ogv differ
index a1866b8..adc4785 100644 (file)
@@ -70,10 +70,12 @@ IGNORE_HFILES=\
        clutter-backend-private.h       \
         clutter-bezier.h               \
        clutter-color-static.h          \
+       clutter-config.h                \
        clutter-debug.h                 \
        clutter-deprecated.h            \
        clutter-device-manager-private.h        \
        clutter-enum-types.h            \
+       clutter-event-translator.h      \
        clutter-id-pool.h               \
        clutter-keysyms.h               \
        clutter-keysyms-compat.h        \
index 447b73f..baf505d 100644 (file)
@@ -893,6 +893,7 @@ clutter_behaviour_ellipse_get_type
 <SECTION>
 <FILE>clutter-backend</FILE>
 <TITLE>ClutterBackend</TITLE>
+ClutterBackend
 clutter_get_default_backend
 clutter_backend_set_resolution
 clutter_backend_get_resolution
@@ -912,9 +913,7 @@ CLUTTER_IS_BACKEND_CLASS
 CLUTTER_BACKEND_GET_CLASS
 CLUTTER_TYPE_BACKEND
 <SUBSECTION Private>
-ClutterBackend
 ClutterBackendClass
-ClutterBackendPrivate
 clutter_backend_get_type
 </SECTION>
 
@@ -1030,6 +1029,7 @@ clutter_event_get_time
 clutter_event_get_source
 clutter_event_get_stage
 clutter_event_get_flags
+clutter_event_get_axes
 
 <SUBSECTION>
 clutter_event_get
@@ -1054,9 +1054,11 @@ clutter_event_get_related
 clutter_event_get_scroll_direction
 
 <SUBSECTION>
+clutter_event_set_device
 clutter_event_get_device
 clutter_event_get_device_id
 clutter_event_get_device_type
+clutter_event_get_source_device
 
 <SUBSECTION>
 clutter_get_current_event_time
@@ -1073,14 +1075,35 @@ clutter_event_get_type
 <FILE>clutter-input-device</FILE>
 <TITLE>ClutterInputDevice</TITLE>
 ClutterInputDeviceType
+ClutterInputAxis
+ClutterInputMode
 ClutterInputDevice
-ClutterInputDeviceClass
 clutter_input_device_get_device_id
 clutter_input_device_get_device_type
 clutter_input_device_get_device_name
+clutter_input_device_get_device_mode
+clutter_input_device_get_has_cursor
+clutter_input_device_set_enabled
+clutter_input_device_get_enabled
+clutter_input_device_get_associated_device
+clutter_input_device_get_slave_devices
+
+<SUBSECTION>
+clutter_input_device_get_n_keys
+clutter_input_device_set_key
+clutter_input_device_get_key
+
+<SUBSECTION>
+clutter_input_device_get_n_axes
+clutter_input_device_get_axis
+clutter_input_device_get_axis_value
+
+<SUBSECTION>
 clutter_input_device_get_device_coords
 clutter_input_device_get_pointer_actor
 clutter_input_device_get_pointer_stage
+
+<SUBSECTION>
 clutter_input_device_update_from_event
 
 <SUBSECTION Standard>
@@ -1092,6 +1115,7 @@ CLUTTER_IS_INPUT_DEVICE_CLASS
 CLUTTER_INPUT_DEVICE_GET_CLASS
 
 <SUBSECTION Private>
+ClutterInputDeviceClass
 clutter_input_device_get_type
 </SECTION>
 
@@ -1843,6 +1867,7 @@ CLUTTER_IS_BINDING_POOL
 CLUTTER_TYPE_BINDING_POOL
 
 <SUBSECTION Private>
+ClutterBindingPoolClass
 clutter_binding_pool_get_type
 </SECTION>
 
@@ -2320,11 +2345,12 @@ clutter_bind_constraint_set_coordinate
 clutter_bind_constraint_get_coordinate
 clutter_bind_constraint_set_offset
 clutter_bind_constraint_get_offset
-
 <SUBSECTION Standard>
 CLUTTER_TYPE_BIND_CONSTRAINT
 CLUTTER_BIND_CONSTRAINT
 CLUTTER_IS_BIND_CONSTRAINT
+<SUBSECTION Private>
+ClutterBindConstraintClass
 clutter_bind_constraint_get_type
 </SECTION>
 
@@ -2345,6 +2371,9 @@ clutter_align_constraint_get_factor
 CLUTTER_TYPE_ALIGN_CONSTRAINT
 CLUTTER_ALIGN_CONSTRAINT
 CLUTTER_IS_ALIGN_CONSTRAINT
+
+<SUBSECTION Private>
+ClutterAlignConstraintClass
 clutter_align_constraint_get_type
 </SECTION>
 
@@ -2402,6 +2431,9 @@ ClutterClickAction
 ClutterClickActionClass
 clutter_click_action_new
 clutter_click_action_get_button
+clutter_click_action_get_state
+
+<SUBSECTION>
 clutter_click_action_release
 
 <SUBSECTION Standard>
@@ -2487,6 +2519,7 @@ CLUTTER_TYPE_BLUR_EFFECT
 CLUTTER_BLUR_EFFECT
 CLUTTER_IS_BLUR_EFFECT
 <SUBSECTION Private>
+ClutterBlurEffectClass
 clutter_blur_effect_get_type
 </SECTION>
 
@@ -2502,6 +2535,7 @@ CLUTTER_TYPE_COLORIZE_EFFECT
 CLUTTER_COLORIZE_EFFECT
 CLUTTER_IS_COLORIZE_EFFECT
 <SUBSECTION Private>
+ClutterColorizeEffectClass
 clutter_colorize_effect_get_type
 </SECTION>
 
@@ -2517,6 +2551,7 @@ CLUTTER_TYPE_DESATURATE_EFFECT
 CLUTTER_DESATURATE_EFFECT
 CLUTTER_IS_DESATURATE_EFFECT
 <SUBSECTION Private>
+ClutterDesaturateEffectClass
 clutter_desaturate_effect_get_type
 </SECTION>
 
@@ -2557,6 +2592,7 @@ CLUTTER_TYPE_PAGE_TURN_EFFECT
 CLUTTER_PAGE_TURN_EFFECT
 CLUTTER_IS_PAGE_TURN_EFFECT
 <SUBSECTION Private>
+ClutterPageTurnEffectClass
 clutter_page_turn_effect_get_type
 </SECTION>
 
@@ -2569,6 +2605,7 @@ CLUTTER_TYPE_SETTINGS
 CLUTTER_SETTINGS
 CLUTTER_IS_SETTINGS
 <SUBSECTION Private>
+ClutterSettingsClass
 clutter_settings_get_type
 </SECTION>
 
@@ -2585,6 +2622,7 @@ CLUTTER_PATH_CONSTRAINT
 CLUTTER_IS_PATH_CONSTRAINT
 CLUTTER_TYPE_PATH_CONSTRAINT
 <SUBSECTION Private>
+ClutterPathConstraintClass
 clutter_path_constraint_get_type
 </SECTION>
 
@@ -2604,5 +2642,6 @@ CLUTTER_SNAP_CONSTRAINT
 CLUTTER_IS_SNAP_CONSTRAINT
 CLUTTER_TYPE_SNAP_CONSTRAINT
 <SUBSECTION Private>
+ClutterSnapConstraintClass
 clutter_snap_constraint_get_type
 </SECTION>
index 5b991c6..f0f9a29 100644 (file)
@@ -77,7 +77,7 @@
 
     <section id="cogl-buffer-layout-apis">
       <title>Describing the layout of GPU Memory</title>
-      <xi:include href="xml/cogl-vertex-attribute.xml"/>
+      <xi:include href="xml/cogl-attribute.xml"/>
       <xi:include href="xml/cogl-indices.xml"/>
     </section>
 
index 167f95f..c6f2942 100644 (file)
@@ -71,6 +71,7 @@
     <xi:include href="xml/cogl-matrix.xml"/>
     <xi:include href="xml/cogl-shaders.xml"/>
     <xi:include href="xml/cogl-offscreen.xml"/>
+    <xi:include href="xml/cogl-bitmap.xml"/>
     <xi:include href="xml/cogl-fixed.xml"/>
     <xi:include href="xml/cogl-gtype.xml"/>
 
index d0191e0..bc244e9 100644 (file)
@@ -6,10 +6,10 @@
 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: clutter 1.5.10\n"
+"Project-Id-Version: clutter 1.6.2\n"
 "Report-Msgid-Bugs-To: http://bugzilla.clutter-project.org/enter_bug.cgi?"
 "product=clutter\n"
-"POT-Creation-Date: 2010-12-17 15:51+0000\n"
+"POT-Creation-Date: 2011-02-07 15:50+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -18,380 +18,380 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: clutter/clutter-actor.c:3480
+#: clutter/clutter-actor.c:3478
 msgid "X coordinate"
 msgstr ""
 
-#: clutter/clutter-actor.c:3481
+#: clutter/clutter-actor.c:3479
 msgid "X coordinate of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3496
+#: clutter/clutter-actor.c:3494
 msgid "Y coordinate"
 msgstr ""
 
-#: clutter/clutter-actor.c:3497
+#: clutter/clutter-actor.c:3495
 msgid "Y coordinate of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3512 clutter/clutter-behaviour-ellipse.c:475
+#: clutter/clutter-actor.c:3510 clutter/clutter-behaviour-ellipse.c:474
 msgid "Width"
 msgstr ""
 
-#: clutter/clutter-actor.c:3513
+#: clutter/clutter-actor.c:3511
 msgid "Width of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3527 clutter/clutter-behaviour-ellipse.c:491
+#: clutter/clutter-actor.c:3525 clutter/clutter-behaviour-ellipse.c:490
 msgid "Height"
 msgstr ""
 
-#: clutter/clutter-actor.c:3528
+#: clutter/clutter-actor.c:3526
 msgid "Height of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3546
+#: clutter/clutter-actor.c:3544
 msgid "Fixed X"
 msgstr ""
 
-#: clutter/clutter-actor.c:3547
+#: clutter/clutter-actor.c:3545
 msgid "Forced X position of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3565
+#: clutter/clutter-actor.c:3563
 msgid "Fixed Y"
 msgstr ""
 
-#: clutter/clutter-actor.c:3566
+#: clutter/clutter-actor.c:3564
 msgid "Forced Y position of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3582
+#: clutter/clutter-actor.c:3580
 msgid "Fixed position set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3583
+#: clutter/clutter-actor.c:3581
 msgid "Whether to use fixed positioning for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3605
+#: clutter/clutter-actor.c:3603
 msgid "Min Width"
 msgstr ""
 
-#: clutter/clutter-actor.c:3606
+#: clutter/clutter-actor.c:3604
 msgid "Forced minimum width request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3625
+#: clutter/clutter-actor.c:3623
 msgid "Min Height"
 msgstr ""
 
-#: clutter/clutter-actor.c:3626
+#: clutter/clutter-actor.c:3624
 msgid "Forced minimum height request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3645
+#: clutter/clutter-actor.c:3643
 msgid "Natural Width"
 msgstr ""
 
-#: clutter/clutter-actor.c:3646
+#: clutter/clutter-actor.c:3644
 msgid "Forced natural width request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3665
+#: clutter/clutter-actor.c:3663
 msgid "Natural Height"
 msgstr ""
 
-#: clutter/clutter-actor.c:3666
+#: clutter/clutter-actor.c:3664
 msgid "Forced natural height request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3682
+#: clutter/clutter-actor.c:3680
 msgid "Minimum width set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3683
+#: clutter/clutter-actor.c:3681
 msgid "Whether to use the min-width property"
 msgstr ""
 
-#: clutter/clutter-actor.c:3698
+#: clutter/clutter-actor.c:3696
 msgid "Minimum height set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3699
+#: clutter/clutter-actor.c:3697
 msgid "Whether to use the min-height property"
 msgstr ""
 
-#: clutter/clutter-actor.c:3714
+#: clutter/clutter-actor.c:3712
 msgid "Natural width set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3715
+#: clutter/clutter-actor.c:3713
 msgid "Whether to use the natural-width property"
 msgstr ""
 
-#: clutter/clutter-actor.c:3732
+#: clutter/clutter-actor.c:3730
 msgid "Natural height set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3733
+#: clutter/clutter-actor.c:3731
 msgid "Whether to use the natural-height property"
 msgstr ""
 
-#: clutter/clutter-actor.c:3752
+#: clutter/clutter-actor.c:3750
 msgid "Allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:3753
+#: clutter/clutter-actor.c:3751
 msgid "The actor's allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:3809
+#: clutter/clutter-actor.c:3807
 msgid "Request Mode"
 msgstr ""
 
-#: clutter/clutter-actor.c:3810
+#: clutter/clutter-actor.c:3808
 msgid "The actor's request mode"
 msgstr ""
 
-#: clutter/clutter-actor.c:3825
+#: clutter/clutter-actor.c:3823
 msgid "Depth"
 msgstr ""
 
-#: clutter/clutter-actor.c:3826
+#: clutter/clutter-actor.c:3824
 msgid "Position on the Z axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:3840
+#: clutter/clutter-actor.c:3838
 msgid "Opacity"
 msgstr ""
 
-#: clutter/clutter-actor.c:3841
+#: clutter/clutter-actor.c:3839
 msgid "Opacity of an actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3856
+#: clutter/clutter-actor.c:3854
 msgid "Visible"
 msgstr ""
 
-#: clutter/clutter-actor.c:3857
+#: clutter/clutter-actor.c:3855
 msgid "Whether the actor is visible or not"
 msgstr ""
 
-#: clutter/clutter-actor.c:3872
+#: clutter/clutter-actor.c:3870
 msgid "Mapped"
 msgstr ""
 
-#: clutter/clutter-actor.c:3873
+#: clutter/clutter-actor.c:3871
 msgid "Whether the actor will be painted"
 msgstr ""
 
-#: clutter/clutter-actor.c:3887
+#: clutter/clutter-actor.c:3885
 msgid "Realized"
 msgstr ""
 
-#: clutter/clutter-actor.c:3888
+#: clutter/clutter-actor.c:3886
 msgid "Whether the actor has been realized"
 msgstr ""
 
-#: clutter/clutter-actor.c:3904
+#: clutter/clutter-actor.c:3902
 msgid "Reactive"
 msgstr ""
 
-#: clutter/clutter-actor.c:3905
+#: clutter/clutter-actor.c:3903
 msgid "Whether the actor is reactive to events"
 msgstr ""
 
-#: clutter/clutter-actor.c:3917
+#: clutter/clutter-actor.c:3915
 msgid "Has Clip"
 msgstr ""
 
-#: clutter/clutter-actor.c:3918
+#: clutter/clutter-actor.c:3916
 msgid "Whether the actor has a clip set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3933
+#: clutter/clutter-actor.c:3931
 msgid "Clip"
 msgstr ""
 
-#: clutter/clutter-actor.c:3934
+#: clutter/clutter-actor.c:3932
 msgid "The clip region for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3948 clutter/clutter-actor-meta.c:205
-#: clutter/clutter-binding-pool.c:320 clutter/clutter-input-device.c:151
+#: clutter/clutter-actor.c:3946 clutter/clutter-actor-meta.c:205
+#: clutter/clutter-binding-pool.c:319 clutter/clutter-input-device.c:235
 msgid "Name"
 msgstr ""
 
-#: clutter/clutter-actor.c:3949
+#: clutter/clutter-actor.c:3947
 msgid "Name of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3963
+#: clutter/clutter-actor.c:3961
 msgid "Scale X"
 msgstr ""
 
-#: clutter/clutter-actor.c:3964
+#: clutter/clutter-actor.c:3962
 msgid "Scale factor on the X axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:3979
+#: clutter/clutter-actor.c:3977
 msgid "Scale Y"
 msgstr ""
 
-#: clutter/clutter-actor.c:3980
+#: clutter/clutter-actor.c:3978
 msgid "Scale factor on the Y axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:3995
+#: clutter/clutter-actor.c:3993
 msgid "Scale Center X"
 msgstr ""
 
-#: clutter/clutter-actor.c:3996
+#: clutter/clutter-actor.c:3994
 msgid "Horizontal scale center"
 msgstr ""
 
-#: clutter/clutter-actor.c:4011
+#: clutter/clutter-actor.c:4009
 msgid "Scale Center Y"
 msgstr ""
 
-#: clutter/clutter-actor.c:4012
+#: clutter/clutter-actor.c:4010
 msgid "Vertical scale center"
 msgstr ""
 
-#: clutter/clutter-actor.c:4027
+#: clutter/clutter-actor.c:4025
 msgid "Scale Gravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4028
+#: clutter/clutter-actor.c:4026
 msgid "The center of scaling"
 msgstr ""
 
-#: clutter/clutter-actor.c:4045
+#: clutter/clutter-actor.c:4043
 msgid "Rotation Angle X"
 msgstr ""
 
-#: clutter/clutter-actor.c:4046
+#: clutter/clutter-actor.c:4044
 msgid "The rotation angle on the X axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4061
+#: clutter/clutter-actor.c:4059
 msgid "Rotation Angle Y"
 msgstr ""
 
-#: clutter/clutter-actor.c:4062
+#: clutter/clutter-actor.c:4060
 msgid "The rotation angle on the Y axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4077
+#: clutter/clutter-actor.c:4075
 msgid "Rotation Angle Z"
 msgstr ""
 
-#: clutter/clutter-actor.c:4078
+#: clutter/clutter-actor.c:4076
 msgid "The rotation angle on the Z axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4093
+#: clutter/clutter-actor.c:4091
 msgid "Rotation Center X"
 msgstr ""
 
-#: clutter/clutter-actor.c:4094
+#: clutter/clutter-actor.c:4092
 msgid "The rotation center on the X axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4110
+#: clutter/clutter-actor.c:4108
 msgid "Rotation Center Y"
 msgstr ""
 
-#: clutter/clutter-actor.c:4111
+#: clutter/clutter-actor.c:4109
 msgid "The rotation center on the Y axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4127
+#: clutter/clutter-actor.c:4125
 msgid "Rotation Center Z"
 msgstr ""
 
-#: clutter/clutter-actor.c:4128
+#: clutter/clutter-actor.c:4126
 msgid "The rotation center on the Z axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4144
+#: clutter/clutter-actor.c:4142
 msgid "Rotation Center Z Gravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4145
+#: clutter/clutter-actor.c:4143
 msgid "Center point for rotation around the Z axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4163
+#: clutter/clutter-actor.c:4161
 msgid "Anchor X"
 msgstr ""
 
-#: clutter/clutter-actor.c:4164
+#: clutter/clutter-actor.c:4162
 msgid "X coordinate of the anchor point"
 msgstr ""
 
-#: clutter/clutter-actor.c:4180
+#: clutter/clutter-actor.c:4178
 msgid "Anchor Y"
 msgstr ""
 
-#: clutter/clutter-actor.c:4181
+#: clutter/clutter-actor.c:4179
 msgid "Y coordinate of the anchor point"
 msgstr ""
 
-#: clutter/clutter-actor.c:4196
+#: clutter/clutter-actor.c:4194
 msgid "Anchor Gravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4197
+#: clutter/clutter-actor.c:4195
 msgid "The anchor point as a ClutterGravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4216
+#: clutter/clutter-actor.c:4214
 msgid "Show on set parent"
 msgstr ""
 
-#: clutter/clutter-actor.c:4217
+#: clutter/clutter-actor.c:4215
 msgid "Whether the actor is shown when parented"
 msgstr ""
 
-#: clutter/clutter-actor.c:4237
+#: clutter/clutter-actor.c:4235
 msgid "Clip to Allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:4238
+#: clutter/clutter-actor.c:4236
 msgid "Sets the clip region to track the actor's allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:4248
+#: clutter/clutter-actor.c:4246
 msgid "Text Direction"
 msgstr ""
 
-#: clutter/clutter-actor.c:4249
+#: clutter/clutter-actor.c:4247
 msgid "Direction of the text"
 msgstr ""
 
-#: clutter/clutter-actor.c:4267
+#: clutter/clutter-actor.c:4265
 msgid "Has Pointer"
 msgstr ""
 
-#: clutter/clutter-actor.c:4268
+#: clutter/clutter-actor.c:4266
 msgid "Whether the actor contains the pointer of an input device"
 msgstr ""
 
-#: clutter/clutter-actor.c:4285
+#: clutter/clutter-actor.c:4283
 msgid "Actions"
 msgstr ""
 
-#: clutter/clutter-actor.c:4286
+#: clutter/clutter-actor.c:4284
 msgid "Adds an action to the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:4300
+#: clutter/clutter-actor.c:4298
 msgid "Constraints"
 msgstr ""
 
-#: clutter/clutter-actor.c:4301
+#: clutter/clutter-actor.c:4299
 msgid "Adds a constraint to the actor"
 msgstr ""
 
@@ -407,7 +407,8 @@ msgstr ""
 msgid "The name of the meta"
 msgstr ""
 
-#: clutter/clutter-actor-meta.c:219 clutter/clutter-shader.c:261
+#: clutter/clutter-actor-meta.c:219 clutter/clutter-input-device.c:314
+#: clutter/clutter-shader.c:295
 msgid "Enabled"
 msgstr ""
 
@@ -415,34 +416,34 @@ msgstr ""
 msgid "Whether the meta is enabled"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:231
-#: clutter/clutter-bind-constraint.c:286 clutter/clutter-clone.c:322
+#: clutter/clutter-align-constraint.c:252
+#: clutter/clutter-bind-constraint.c:316 clutter/clutter-clone.c:322
 msgid "Source"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:232
+#: clutter/clutter-align-constraint.c:253
 msgid "The source of the alignment"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:245
+#: clutter/clutter-align-constraint.c:266
 msgid "Align Axis"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:246
+#: clutter/clutter-align-constraint.c:267
 msgid "The axis to align the position to"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:265
-#: clutter/clutter-desaturate-effect.c:309
+#: clutter/clutter-align-constraint.c:286
+#: clutter/clutter-desaturate-effect.c:307
 msgid "Factor"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:266
+#: clutter/clutter-align-constraint.c:287
 msgid "The alignment factor, between 0.0 and 1.0"
 msgstr ""
 
 #: clutter/clutter-alpha.c:339 clutter/clutter-animation.c:523
-#: clutter/clutter-animator.c:1801
+#: clutter/clutter-animator.c:1802
 msgid "Timeline"
 msgstr ""
 
@@ -478,7 +479,7 @@ msgstr ""
 msgid "The mode of the animation"
 msgstr ""
 
-#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1785
+#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1786
 #: clutter/clutter-media.c:194 clutter/clutter-state.c:1282
 msgid "Duration"
 msgstr ""
@@ -499,7 +500,7 @@ msgstr ""
 msgid "The timeline used by the animation"
 msgstr ""
 
-#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:299
+#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:298
 msgid "Alpha"
 msgstr ""
 
@@ -507,215 +508,215 @@ msgstr ""
 msgid "The alpha used by the animation"
 msgstr ""
 
-#: clutter/clutter-animator.c:1786
+#: clutter/clutter-animator.c:1787
 msgid "The duration of the animation"
 msgstr ""
 
-#: clutter/clutter-animator.c:1802
+#: clutter/clutter-animator.c:1803
 msgid "The timeline of the animation"
 msgstr ""
 
-#: clutter/clutter-behaviour.c:300
+#: clutter/clutter-behaviour.c:299
 msgid "Alpha Object to drive the behaviour"
 msgstr ""
 
-#: clutter/clutter-behaviour-depth.c:175
+#: clutter/clutter-behaviour-depth.c:174
 msgid "Start Depth"
 msgstr ""
 
-#: clutter/clutter-behaviour-depth.c:176
+#: clutter/clutter-behaviour-depth.c:175
 msgid "Initial depth to apply"
 msgstr ""
 
-#: clutter/clutter-behaviour-depth.c:191
+#: clutter/clutter-behaviour-depth.c:190
 msgid "End Depth"
 msgstr ""
 
-#: clutter/clutter-behaviour-depth.c:192
+#: clutter/clutter-behaviour-depth.c:191
 msgid "Final depth to apply"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-ellipse.c:394
 msgid "Start Angle"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:396
-#: clutter/clutter-behaviour-rotate.c:277
+#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-rotate.c:276
 msgid "Initial angle"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-ellipse.c:410
 msgid "End Angle"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:412
-#: clutter/clutter-behaviour-rotate.c:295
+#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-rotate.c:294
 msgid "Final angle"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:427
+#: clutter/clutter-behaviour-ellipse.c:426
 msgid "Angle x tilt"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:428
+#: clutter/clutter-behaviour-ellipse.c:427
 msgid "Tilt of the ellipse around x axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:443
+#: clutter/clutter-behaviour-ellipse.c:442
 msgid "Angle y tilt"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:444
+#: clutter/clutter-behaviour-ellipse.c:443
 msgid "Tilt of the ellipse around y axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:459
+#: clutter/clutter-behaviour-ellipse.c:458
 msgid "Angle z tilt"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:460
+#: clutter/clutter-behaviour-ellipse.c:459
 msgid "Tilt of the ellipse around z axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:476
+#: clutter/clutter-behaviour-ellipse.c:475
 msgid "Width of the ellipse"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:492
+#: clutter/clutter-behaviour-ellipse.c:491
 msgid "Height of ellipse"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:507
+#: clutter/clutter-behaviour-ellipse.c:506
 msgid "Center"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:508
+#: clutter/clutter-behaviour-ellipse.c:507
 msgid "Center of ellipse"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:522
-#: clutter/clutter-behaviour-rotate.c:330
+#: clutter/clutter-behaviour-ellipse.c:521
+#: clutter/clutter-behaviour-rotate.c:329
 msgid "Direction"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:523
-#: clutter/clutter-behaviour-rotate.c:331
+#: clutter/clutter-behaviour-ellipse.c:522
+#: clutter/clutter-behaviour-rotate.c:330
 msgid "Direction of rotation"
 msgstr ""
 
-#: clutter/clutter-behaviour-opacity.c:178
+#: clutter/clutter-behaviour-opacity.c:177
 msgid "Opacity Start"
 msgstr ""
 
-#: clutter/clutter-behaviour-opacity.c:179
+#: clutter/clutter-behaviour-opacity.c:178
 msgid "Initial opacity level"
 msgstr ""
 
-#: clutter/clutter-behaviour-opacity.c:196
+#: clutter/clutter-behaviour-opacity.c:195
 msgid "Opacity End"
 msgstr ""
 
-#: clutter/clutter-behaviour-opacity.c:197
+#: clutter/clutter-behaviour-opacity.c:196
 msgid "Final opacity level"
 msgstr ""
 
-#: clutter/clutter-behaviour-path.c:220
+#: clutter/clutter-behaviour-path.c:219
 msgid "Path"
 msgstr ""
 
-#: clutter/clutter-behaviour-path.c:221
+#: clutter/clutter-behaviour-path.c:220
 msgid "The ClutterPath object representing the path to animate along"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:276
+#: clutter/clutter-behaviour-rotate.c:275
 msgid "Angle Begin"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:294
+#: clutter/clutter-behaviour-rotate.c:293
 msgid "Angle End"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:312
+#: clutter/clutter-behaviour-rotate.c:311
 msgid "Axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:313
+#: clutter/clutter-behaviour-rotate.c:312
 msgid "Axis of rotation"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:348
+#: clutter/clutter-behaviour-rotate.c:347
 msgid "Center X"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:349
+#: clutter/clutter-behaviour-rotate.c:348
 msgid "X coordinate of the center of rotation"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:366
+#: clutter/clutter-behaviour-rotate.c:365
 msgid "Center Y"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:367
+#: clutter/clutter-behaviour-rotate.c:366
 msgid "Y coordinate of the center of rotation"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:384
+#: clutter/clutter-behaviour-rotate.c:383
 msgid "Center Z"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:385
+#: clutter/clutter-behaviour-rotate.c:384
 msgid "Z coordinate of the center of rotation"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:219
+#: clutter/clutter-behaviour-scale.c:218
 msgid "X Start Scale"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:220
+#: clutter/clutter-behaviour-scale.c:219
 msgid "Initial scale on the X axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:238
+#: clutter/clutter-behaviour-scale.c:237
 msgid "X End Scale"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:239
+#: clutter/clutter-behaviour-scale.c:238
 msgid "Final scale on the X axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:257
+#: clutter/clutter-behaviour-scale.c:256
 msgid "Y Start Scale"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:258
+#: clutter/clutter-behaviour-scale.c:257
 msgid "Initial scale on the Y axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:276
+#: clutter/clutter-behaviour-scale.c:275
 msgid "Y End Scale"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:277
+#: clutter/clutter-behaviour-scale.c:276
 msgid "Final scale on the Y axis"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:287
+#: clutter/clutter-bind-constraint.c:317
 msgid "The source of the binding"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:300
+#: clutter/clutter-bind-constraint.c:330
 msgid "Coordinate"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:301
+#: clutter/clutter-bind-constraint.c:331
 msgid "The coordinate to bind"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:315
+#: clutter/clutter-bind-constraint.c:345
 msgid "Offset"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:316
+#: clutter/clutter-bind-constraint.c:346
 msgid "The offset in pixels to apply to the binding"
 msgstr ""
 
@@ -745,7 +746,7 @@ msgstr ""
 msgid "Default vertical alignment for the actors inside the layout manager"
 msgstr ""
 
-#: clutter/clutter-binding-pool.c:321
+#: clutter/clutter-binding-pool.c:320
 msgid "The unique name of the binding pool"
 msgstr ""
 
@@ -758,7 +759,7 @@ msgid "The layout manager used by the box"
 msgstr ""
 
 #: clutter/clutter-box.c:514 clutter/clutter-rectangle.c:258
-#: clutter/clutter-stage.c:1307
+#: clutter/clutter-stage.c:1317
 msgid "Color"
 msgstr ""
 
@@ -895,19 +896,19 @@ msgstr ""
 msgid "The actor wrapped by this data"
 msgstr ""
 
-#: clutter/clutter-click-action.c:283
+#: clutter/clutter-click-action.c:302
 msgid "Pressed"
 msgstr ""
 
-#: clutter/clutter-click-action.c:284
+#: clutter/clutter-click-action.c:303
 msgid "Whether the clickable should be in pressed state"
 msgstr ""
 
-#: clutter/clutter-click-action.c:297
+#: clutter/clutter-click-action.c:316
 msgid "Held"
 msgstr ""
 
-#: clutter/clutter-click-action.c:298
+#: clutter/clutter-click-action.c:317
 msgid "Whether the clickable has a grab"
 msgstr ""
 
@@ -915,11 +916,11 @@ msgstr ""
 msgid "Specifies the actor to be cloned"
 msgstr ""
 
-#: clutter/clutter-colorize-effect.c:309
+#: clutter/clutter-colorize-effect.c:307
 msgid "Tint"
 msgstr ""
 
-#: clutter/clutter-colorize-effect.c:310
+#: clutter/clutter-colorize-effect.c:308
 msgid "The tint to apply"
 msgstr ""
 
@@ -947,11 +948,11 @@ msgstr ""
 msgid "The material to be used when painting the back of the actor"
 msgstr ""
 
-#: clutter/clutter-desaturate-effect.c:310
+#: clutter/clutter-desaturate-effect.c:308
 msgid "The desaturation factor"
 msgstr ""
 
-#: clutter/clutter-device-manager.c:130
+#: clutter/clutter-device-manager.c:130 clutter/clutter-input-device.c:343
 msgid "Backend"
 msgstr ""
 
@@ -959,35 +960,35 @@ msgstr ""
 msgid "The ClutterBackend of the device manager"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:490
+#: clutter/clutter-drag-action.c:491
 msgid "Horizontal Drag Threshold"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:491
+#: clutter/clutter-drag-action.c:492
 msgid "The horizontal amount of pixels required to start dragging"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:510
+#: clutter/clutter-drag-action.c:511
 msgid "Vertical Drag Threshold"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:511
+#: clutter/clutter-drag-action.c:512
 msgid "The vertical amount of pixels required to start dragging"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:532
+#: clutter/clutter-drag-action.c:533
 msgid "Drag Handle"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:533
+#: clutter/clutter-drag-action.c:534
 msgid "The actor that is being dragged"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:546
+#: clutter/clutter-drag-action.c:547
 msgid "Drag Axis"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:547
+#: clutter/clutter-drag-action.c:548
 msgid "Constraints the dragging to an axis"
 msgstr ""
 
@@ -1051,26 +1052,66 @@ msgstr ""
 msgid "Maximum height for each row"
 msgstr ""
 
-#: clutter/clutter-input-device.c:134
+#: clutter/clutter-input-device.c:219
 msgid "Id"
 msgstr ""
 
-#: clutter/clutter-input-device.c:135
+#: clutter/clutter-input-device.c:220
 msgid "Unique identifier of the device"
 msgstr ""
 
-#: clutter/clutter-input-device.c:152
+#: clutter/clutter-input-device.c:236
 msgid "The name of the device"
 msgstr ""
 
-#: clutter/clutter-input-device.c:167
+#: clutter/clutter-input-device.c:250
 msgid "Device Type"
 msgstr ""
 
-#: clutter/clutter-input-device.c:168
+#: clutter/clutter-input-device.c:251
 msgid "The type of the device"
 msgstr ""
 
+#: clutter/clutter-input-device.c:266
+msgid "Device Manager"
+msgstr ""
+
+#: clutter/clutter-input-device.c:267
+msgid "The device manager instance"
+msgstr ""
+
+#: clutter/clutter-input-device.c:280
+msgid "Device Mode"
+msgstr ""
+
+#: clutter/clutter-input-device.c:281
+msgid "The mode of the device"
+msgstr ""
+
+#: clutter/clutter-input-device.c:295
+msgid "Has Cursor"
+msgstr ""
+
+#: clutter/clutter-input-device.c:296
+msgid "Whether the device has a cursor"
+msgstr ""
+
+#: clutter/clutter-input-device.c:315
+msgid "Whether the device is enabled"
+msgstr ""
+
+#: clutter/clutter-input-device.c:328
+msgid "Number of Axes"
+msgstr ""
+
+#: clutter/clutter-input-device.c:329
+msgid "The number of axes on the device"
+msgstr ""
+
+#: clutter/clutter-input-device.c:344
+msgid "The backend instance"
+msgstr ""
+
 #: clutter/clutter-interval.c:397
 msgid "Value Type"
 msgstr ""
@@ -1087,59 +1128,59 @@ msgstr ""
 msgid "The manager that created this data"
 msgstr ""
 
-#: clutter/clutter-main.c:756
+#: clutter/clutter-main.c:753
 msgid "default:LTR"
 msgstr ""
 
-#: clutter/clutter-main.c:1560
+#: clutter/clutter-main.c:1557
 msgid "Show frames per second"
 msgstr ""
 
-#: clutter/clutter-main.c:1562
+#: clutter/clutter-main.c:1559
 msgid "Default frame rate"
 msgstr ""
 
-#: clutter/clutter-main.c:1564
+#: clutter/clutter-main.c:1561
 msgid "Make all warnings fatal"
 msgstr ""
 
-#: clutter/clutter-main.c:1567
+#: clutter/clutter-main.c:1564
 msgid "Direction for the text"
 msgstr ""
 
-#: clutter/clutter-main.c:1570
+#: clutter/clutter-main.c:1567
 msgid "Disable mipmapping on text"
 msgstr ""
 
-#: clutter/clutter-main.c:1573
+#: clutter/clutter-main.c:1570
 msgid "Use 'fuzzy' picking"
 msgstr ""
 
-#: clutter/clutter-main.c:1576
+#: clutter/clutter-main.c:1573
 msgid "Clutter debugging flags to set"
 msgstr ""
 
-#: clutter/clutter-main.c:1578
+#: clutter/clutter-main.c:1575
 msgid "Clutter debugging flags to unset"
 msgstr ""
 
-#: clutter/clutter-main.c:1582
+#: clutter/clutter-main.c:1579
 msgid "Clutter profiling flags to set"
 msgstr ""
 
-#: clutter/clutter-main.c:1584
+#: clutter/clutter-main.c:1581
 msgid "Clutter profiling flags to unset"
 msgstr ""
 
-#: clutter/clutter-main.c:1587
+#: clutter/clutter-main.c:1584
 msgid "Enable accessibility"
 msgstr ""
 
-#: clutter/clutter-main.c:1774
+#: clutter/clutter-main.c:1771
 msgid "Clutter Options"
 msgstr ""
 
-#: clutter/clutter-main.c:1775
+#: clutter/clutter-main.c:1772
 msgid "Show Clutter Options"
 msgstr ""
 
@@ -1255,44 +1296,44 @@ msgstr ""
 msgid "The path of the currently parsed file"
 msgstr ""
 
-#: clutter/clutter-shader.c:215
+#: clutter/clutter-shader.c:249
 msgid "Vertex Source"
 msgstr ""
 
-#: clutter/clutter-shader.c:216
+#: clutter/clutter-shader.c:250
 msgid "Source of vertex shader"
 msgstr ""
 
-#: clutter/clutter-shader.c:230
+#: clutter/clutter-shader.c:264
 msgid "Fragment Source"
 msgstr ""
 
-#: clutter/clutter-shader.c:231
+#: clutter/clutter-shader.c:265
 msgid "Source of fragment shader"
 msgstr ""
 
-#: clutter/clutter-shader.c:246
+#: clutter/clutter-shader.c:280
 msgid "Compiled"
 msgstr ""
 
-#: clutter/clutter-shader.c:247
+#: clutter/clutter-shader.c:281
 msgid "Whether the shader is compiled and linked"
 msgstr ""
 
-#: clutter/clutter-shader.c:262
+#: clutter/clutter-shader.c:296
 msgid "Whether the shader is enabled"
 msgstr ""
 
-#: clutter/clutter-shader.c:467
+#: clutter/clutter-shader.c:501
 #, c-format
 msgid "%s compilation failed: %s"
 msgstr ""
 
-#: clutter/clutter-shader.c:468
+#: clutter/clutter-shader.c:502
 msgid "Vertex shader"
 msgstr ""
 
-#: clutter/clutter-shader.c:469
+#: clutter/clutter-shader.c:503
 msgid "Fragment shader"
 msgstr ""
 
@@ -1304,98 +1345,106 @@ msgstr ""
 msgid "The type of shader used"
 msgstr ""
 
-#: clutter/clutter-stage.c:1249
+#: clutter/clutter-stage.c:1259
 msgid "Fullscreen Set"
 msgstr ""
 
-#: clutter/clutter-stage.c:1250
+#: clutter/clutter-stage.c:1260
 msgid "Whether the main stage is fullscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1266
+#: clutter/clutter-stage.c:1276
 msgid "Offscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1267
+#: clutter/clutter-stage.c:1277
 msgid "Whether the main stage should be rendered offscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1279 clutter/clutter-text.c:2643
+#: clutter/clutter-stage.c:1289 clutter/clutter-text.c:2667
 msgid "Cursor Visible"
 msgstr ""
 
-#: clutter/clutter-stage.c:1280
+#: clutter/clutter-stage.c:1290
 msgid "Whether the mouse pointer is visible on the main stage"
 msgstr ""
 
-#: clutter/clutter-stage.c:1294
+#: clutter/clutter-stage.c:1304
 msgid "User Resizable"
 msgstr ""
 
-#: clutter/clutter-stage.c:1295
+#: clutter/clutter-stage.c:1305
 msgid "Whether the stage is able to be resized via user interaction"
 msgstr ""
 
-#: clutter/clutter-stage.c:1308
+#: clutter/clutter-stage.c:1318
 msgid "The color of the stage"
 msgstr ""
 
-#: clutter/clutter-stage.c:1322
+#: clutter/clutter-stage.c:1332
 msgid "Perspective"
 msgstr ""
 
-#: clutter/clutter-stage.c:1323
+#: clutter/clutter-stage.c:1333
 msgid "Perspective projection parameters"
 msgstr ""
 
-#: clutter/clutter-stage.c:1338
+#: clutter/clutter-stage.c:1348
 msgid "Title"
 msgstr ""
 
-#: clutter/clutter-stage.c:1339
+#: clutter/clutter-stage.c:1349
 msgid "Stage Title"
 msgstr ""
 
-#: clutter/clutter-stage.c:1354
+#: clutter/clutter-stage.c:1364
 msgid "Use Fog"
 msgstr ""
 
-#: clutter/clutter-stage.c:1355
+#: clutter/clutter-stage.c:1365
 msgid "Whether to enable depth cueing"
 msgstr ""
 
-#: clutter/clutter-stage.c:1369
+#: clutter/clutter-stage.c:1379
 msgid "Fog"
 msgstr ""
 
-#: clutter/clutter-stage.c:1370
+#: clutter/clutter-stage.c:1380
 msgid "Settings for the depth cueing"
 msgstr ""
 
-#: clutter/clutter-stage.c:1386
+#: clutter/clutter-stage.c:1396
 msgid "Use Alpha"
 msgstr ""
 
-#: clutter/clutter-stage.c:1387
+#: clutter/clutter-stage.c:1397
 msgid "Whether to honour the alpha component of the stage color"
 msgstr ""
 
-#: clutter/clutter-stage.c:1403
+#: clutter/clutter-stage.c:1413
 msgid "Key Focus"
 msgstr ""
 
-#: clutter/clutter-stage.c:1404
+#: clutter/clutter-stage.c:1414
 msgid "The currently key focused actor"
 msgstr ""
 
-#: clutter/clutter-stage.c:1420
+#: clutter/clutter-stage.c:1430
 msgid "No Clear Hint"
 msgstr ""
 
-#: clutter/clutter-stage.c:1421
+#: clutter/clutter-stage.c:1431
 msgid "Whether the stage should clear its contents"
 msgstr ""
 
+#: clutter/clutter-stage.c:1444
+msgid "Accept Focus"
+msgstr ""
+
+#: clutter/clutter-stage.c:1445
+msgid "Whether the stage should accept focus on show"
+msgstr ""
+
 #: clutter/clutter-state.c:1268
 msgid "State"
 msgstr ""
@@ -1408,191 +1457,191 @@ msgstr ""
 msgid "Default transition duration"
 msgstr ""
 
-#: clutter/clutter-text.c:2530
+#: clutter/clutter-text.c:2554
 msgid "Font Name"
 msgstr ""
 
-#: clutter/clutter-text.c:2531
+#: clutter/clutter-text.c:2555
 msgid "The font to be used by the text"
 msgstr ""
 
-#: clutter/clutter-text.c:2548
+#: clutter/clutter-text.c:2572
 msgid "Font Description"
 msgstr ""
 
-#: clutter/clutter-text.c:2549
+#: clutter/clutter-text.c:2573
 msgid "The font description to be used"
 msgstr ""
 
-#: clutter/clutter-text.c:2565
+#: clutter/clutter-text.c:2589
 msgid "Text"
 msgstr ""
 
-#: clutter/clutter-text.c:2566
+#: clutter/clutter-text.c:2590
 msgid "The text to render"
 msgstr ""
 
-#: clutter/clutter-text.c:2580
+#: clutter/clutter-text.c:2604
 msgid "Font Color"
 msgstr ""
 
-#: clutter/clutter-text.c:2581
+#: clutter/clutter-text.c:2605
 msgid "Color of the font used by the text"
 msgstr ""
 
-#: clutter/clutter-text.c:2595
+#: clutter/clutter-text.c:2619
 msgid "Editable"
 msgstr ""
 
-#: clutter/clutter-text.c:2596
+#: clutter/clutter-text.c:2620
 msgid "Whether the text is editable"
 msgstr ""
 
-#: clutter/clutter-text.c:2611
+#: clutter/clutter-text.c:2635
 msgid "Selectable"
 msgstr ""
 
-#: clutter/clutter-text.c:2612
+#: clutter/clutter-text.c:2636
 msgid "Whether the text is selectable"
 msgstr ""
 
-#: clutter/clutter-text.c:2626
+#: clutter/clutter-text.c:2650
 msgid "Activatable"
 msgstr ""
 
-#: clutter/clutter-text.c:2627
+#: clutter/clutter-text.c:2651
 msgid "Whether pressing return causes the activate signal to be emitted"
 msgstr ""
 
-#: clutter/clutter-text.c:2644
+#: clutter/clutter-text.c:2668
 msgid "Whether the input cursor is visible"
 msgstr ""
 
-#: clutter/clutter-text.c:2658 clutter/clutter-text.c:2659
+#: clutter/clutter-text.c:2682 clutter/clutter-text.c:2683
 msgid "Cursor Color"
 msgstr ""
 
-#: clutter/clutter-text.c:2673
+#: clutter/clutter-text.c:2697
 msgid "Cursor Color Set"
 msgstr ""
 
-#: clutter/clutter-text.c:2674
+#: clutter/clutter-text.c:2698
 msgid "Whether the cursor color has been set"
 msgstr ""
 
-#: clutter/clutter-text.c:2689
+#: clutter/clutter-text.c:2713
 msgid "Cursor Size"
 msgstr ""
 
-#: clutter/clutter-text.c:2690
+#: clutter/clutter-text.c:2714
 msgid "The width of the cursor, in pixels"
 msgstr ""
 
-#: clutter/clutter-text.c:2704
+#: clutter/clutter-text.c:2728
 msgid "Cursor Position"
 msgstr ""
 
-#: clutter/clutter-text.c:2705
+#: clutter/clutter-text.c:2729
 msgid "The cursor position"
 msgstr ""
 
-#: clutter/clutter-text.c:2720
+#: clutter/clutter-text.c:2744
 msgid "Selection-bound"
 msgstr ""
 
-#: clutter/clutter-text.c:2721
+#: clutter/clutter-text.c:2745
 msgid "The cursor position of the other end of the selection"
 msgstr ""
 
-#: clutter/clutter-text.c:2736 clutter/clutter-text.c:2737
+#: clutter/clutter-text.c:2760 clutter/clutter-text.c:2761
 msgid "Selection Color"
 msgstr ""
 
-#: clutter/clutter-text.c:2751
+#: clutter/clutter-text.c:2775
 msgid "Selection Color Set"
 msgstr ""
 
-#: clutter/clutter-text.c:2752
+#: clutter/clutter-text.c:2776
 msgid "Whether the selection color has been set"
 msgstr ""
 
-#: clutter/clutter-text.c:2767
+#: clutter/clutter-text.c:2791
 msgid "Attributes"
 msgstr ""
 
-#: clutter/clutter-text.c:2768
+#: clutter/clutter-text.c:2792
 msgid "A list of style attributes to apply to the contents of the actor"
 msgstr ""
 
-#: clutter/clutter-text.c:2790
+#: clutter/clutter-text.c:2814
 msgid "Use markup"
 msgstr ""
 
-#: clutter/clutter-text.c:2791
+#: clutter/clutter-text.c:2815
 msgid "Whether or not the text includes Pango markup"
 msgstr ""
 
-#: clutter/clutter-text.c:2807
+#: clutter/clutter-text.c:2831
 msgid "Line wrap"
 msgstr ""
 
-#: clutter/clutter-text.c:2808
+#: clutter/clutter-text.c:2832
 msgid "If set, wrap the lines if the text becomes too wide"
 msgstr ""
 
-#: clutter/clutter-text.c:2823
+#: clutter/clutter-text.c:2847
 msgid "Line wrap mode"
 msgstr ""
 
-#: clutter/clutter-text.c:2824
+#: clutter/clutter-text.c:2848
 msgid "Control how line-wrapping is done"
 msgstr ""
 
-#: clutter/clutter-text.c:2839
+#: clutter/clutter-text.c:2863
 msgid "Ellipsize"
 msgstr ""
 
-#: clutter/clutter-text.c:2840
+#: clutter/clutter-text.c:2864
 msgid "The preferred place to ellipsize the string"
 msgstr ""
 
-#: clutter/clutter-text.c:2856
+#: clutter/clutter-text.c:2880
 msgid "Line Alignment"
 msgstr ""
 
-#: clutter/clutter-text.c:2857
+#: clutter/clutter-text.c:2881
 msgid "The preferred alignment for the string, for multi-line text"
 msgstr ""
 
-#: clutter/clutter-text.c:2873
+#: clutter/clutter-text.c:2897
 msgid "Justify"
 msgstr ""
 
-#: clutter/clutter-text.c:2874
+#: clutter/clutter-text.c:2898
 msgid "Whether the text should be justified"
 msgstr ""
 
-#: clutter/clutter-text.c:2889
+#: clutter/clutter-text.c:2913
 msgid "Password Character"
 msgstr ""
 
-#: clutter/clutter-text.c:2890
+#: clutter/clutter-text.c:2914
 msgid "If non-zero, use this character to display the actor's contents"
 msgstr ""
 
-#: clutter/clutter-text.c:2904
+#: clutter/clutter-text.c:2928
 msgid "Max Length"
 msgstr ""
 
-#: clutter/clutter-text.c:2905
+#: clutter/clutter-text.c:2929
 msgid "Maximum length of the text inside the actor"
 msgstr ""
 
-#: clutter/clutter-text.c:2928
+#: clutter/clutter-text.c:2952
 msgid "Single Line Mode"
 msgstr ""
 
-#: clutter/clutter-text.c:2929
+#: clutter/clutter-text.c:2953
 msgid "Whether the text should be a single line"
 msgstr ""
 
@@ -1711,23 +1760,23 @@ msgstr ""
 msgid "Shape actor with alpha channel when picking"
 msgstr ""
 
-#: clutter/glx/clutter-backend-glx.c:128
+#: clutter/glx/clutter-backend-glx.c:131
 msgid "VBlank method to be used (none, dri or glx)"
 msgstr ""
 
-#: clutter/x11/clutter-backend-x11.c:364
+#: clutter/x11/clutter-backend-x11.c:473
 msgid "X display to use"
 msgstr ""
 
-#: clutter/x11/clutter-backend-x11.c:370
+#: clutter/x11/clutter-backend-x11.c:479
 msgid "X screen to use"
 msgstr ""
 
-#: clutter/x11/clutter-backend-x11.c:375
+#: clutter/x11/clutter-backend-x11.c:484
 msgid "Make X calls synchronous"
 msgstr ""
 
-#: clutter/x11/clutter-backend-x11.c:382
+#: clutter/x11/clutter-backend-x11.c:491
 msgid "Enable XInput support"
 msgstr ""
 
index cbe832d..e112e0c 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: clutter_1.0 1.0.8\n"
 "Report-Msgid-Bugs-To: http://bugzilla.clutter-project.org/enter_bug.cgi?"
 "product=clutter\n"
-"POT-Creation-Date: 2010-12-17 15:51+0000\n"
+"POT-Creation-Date: 2011-02-07 15:50+0000\n"
 "PO-Revision-Date: 2009-11-24 21:04+0100\n"
 "Last-Translator: Chris Leick <c.leick@vollbio.de>\n"
 "Language-Team: German <debian-l10n-german@lists.debian.org>\n"
@@ -18,389 +18,389 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
 
-#: clutter/clutter-actor.c:3480
+#: clutter/clutter-actor.c:3478
 msgid "X coordinate"
 msgstr "X-Koordinate"
 
-#: clutter/clutter-actor.c:3481
+#: clutter/clutter-actor.c:3479
 msgid "X coordinate of the actor"
 msgstr "X-Koordinate des Akteurs"
 
-#: clutter/clutter-actor.c:3496
+#: clutter/clutter-actor.c:3494
 msgid "Y coordinate"
 msgstr "Y-Koordinate"
 
-#: clutter/clutter-actor.c:3497
+#: clutter/clutter-actor.c:3495
 msgid "Y coordinate of the actor"
 msgstr "Y-Koordinate des Aktuers"
 
-#: clutter/clutter-actor.c:3512 clutter/clutter-behaviour-ellipse.c:475
+#: clutter/clutter-actor.c:3510 clutter/clutter-behaviour-ellipse.c:474
 msgid "Width"
 msgstr "Breite"
 
-#: clutter/clutter-actor.c:3513
+#: clutter/clutter-actor.c:3511
 msgid "Width of the actor"
 msgstr "Breite des Akteurs"
 
-#: clutter/clutter-actor.c:3527 clutter/clutter-behaviour-ellipse.c:491
+#: clutter/clutter-actor.c:3525 clutter/clutter-behaviour-ellipse.c:490
 msgid "Height"
 msgstr "Höhe"
 
-#: clutter/clutter-actor.c:3528
+#: clutter/clutter-actor.c:3526
 msgid "Height of the actor"
 msgstr "Höhe des Akteurs"
 
-#: clutter/clutter-actor.c:3546
+#: clutter/clutter-actor.c:3544
 msgid "Fixed X"
 msgstr "Fixiertes X"
 
-#: clutter/clutter-actor.c:3547
+#: clutter/clutter-actor.c:3545
 msgid "Forced X position of the actor"
 msgstr "Forcierte X-Position des Akteurs"
 
-#: clutter/clutter-actor.c:3565
+#: clutter/clutter-actor.c:3563
 msgid "Fixed Y"
 msgstr "Fixiertes Y"
 
-#: clutter/clutter-actor.c:3566
+#: clutter/clutter-actor.c:3564
 msgid "Forced Y position of the actor"
 msgstr "Forcierte Y-Position des Akteurs"
 
-#: clutter/clutter-actor.c:3582
+#: clutter/clutter-actor.c:3580
 msgid "Fixed position set"
 msgstr "Fixierte Position gesetzt"
 
-#: clutter/clutter-actor.c:3583
+#: clutter/clutter-actor.c:3581
 #, fuzzy
 msgid "Whether to use fixed positioning for the actor"
 msgstr "Benutze fixierte Position für den Akteur"
 
-#: clutter/clutter-actor.c:3605
+#: clutter/clutter-actor.c:3603
 msgid "Min Width"
 msgstr "Minimale Breite"
 
-#: clutter/clutter-actor.c:3606
+#: clutter/clutter-actor.c:3604
 msgid "Forced minimum width request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3625
+#: clutter/clutter-actor.c:3623
 msgid "Min Height"
 msgstr "Minimale Höhe"
 
-#: clutter/clutter-actor.c:3626
+#: clutter/clutter-actor.c:3624
 msgid "Forced minimum height request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3645
+#: clutter/clutter-actor.c:3643
 msgid "Natural Width"
 msgstr "Natürliche Breite"
 
-#: clutter/clutter-actor.c:3646
+#: clutter/clutter-actor.c:3644
 msgid "Forced natural width request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3665
+#: clutter/clutter-actor.c:3663
 msgid "Natural Height"
 msgstr "Natürliche Höhe"
 
-#: clutter/clutter-actor.c:3666
+#: clutter/clutter-actor.c:3664
 msgid "Forced natural height request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3682
+#: clutter/clutter-actor.c:3680
 msgid "Minimum width set"
 msgstr "Minimale Breite gesetzt"
 
-#: clutter/clutter-actor.c:3683
+#: clutter/clutter-actor.c:3681
 #, fuzzy
 msgid "Whether to use the min-width property"
 msgstr "Benutze min-width Eigenschaft"
 
-#: clutter/clutter-actor.c:3698
+#: clutter/clutter-actor.c:3696
 msgid "Minimum height set"
 msgstr "Minimale Höhe gesetzt"
 
-#: clutter/clutter-actor.c:3699
+#: clutter/clutter-actor.c:3697
 #, fuzzy
 msgid "Whether to use the min-height property"
 msgstr "Benutze min-height Eigenschaft"
 
-#: clutter/clutter-actor.c:3714
+#: clutter/clutter-actor.c:3712
 msgid "Natural width set"
 msgstr "Natürliche Breite gesetzt"
 
-#: clutter/clutter-actor.c:3715
+#: clutter/clutter-actor.c:3713
 #, fuzzy
 msgid "Whether to use the natural-width property"
 msgstr "Benutze natural-width Eigenschaft"
 
-#: clutter/clutter-actor.c:3732
+#: clutter/clutter-actor.c:3730
 msgid "Natural height set"
 msgstr "Natürliche Höhe gesetzt"
 
-#: clutter/clutter-actor.c:3733
+#: clutter/clutter-actor.c:3731
 #, fuzzy
 msgid "Whether to use the natural-height property"
 msgstr "Benutze natural-height Eigenschaft"
 
-#: clutter/clutter-actor.c:3752
+#: clutter/clutter-actor.c:3750
 msgid "Allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:3753
+#: clutter/clutter-actor.c:3751
 msgid "The actor's allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:3809
+#: clutter/clutter-actor.c:3807
 msgid "Request Mode"
 msgstr ""
 
-#: clutter/clutter-actor.c:3810
+#: clutter/clutter-actor.c:3808
 msgid "The actor's request mode"
 msgstr ""
 
-#: clutter/clutter-actor.c:3825
+#: clutter/clutter-actor.c:3823
 msgid "Depth"
 msgstr "Tiefe"
 
-#: clutter/clutter-actor.c:3826
+#: clutter/clutter-actor.c:3824
 msgid "Position on the Z axis"
 msgstr "Position auf der Z-Achse"
 
-#: clutter/clutter-actor.c:3840
+#: clutter/clutter-actor.c:3838
 msgid "Opacity"
 msgstr "Undurchsichtigkeit"
 
-#: clutter/clutter-actor.c:3841
+#: clutter/clutter-actor.c:3839
 msgid "Opacity of an actor"
 msgstr "Undurchsichtigkeit des Akteurs"
 
-#: clutter/clutter-actor.c:3856
+#: clutter/clutter-actor.c:3854
 msgid "Visible"
 msgstr "Sichtbar"
 
-#: clutter/clutter-actor.c:3857
+#: clutter/clutter-actor.c:3855
 msgid "Whether the actor is visible or not"
 msgstr "Ob der Akteur sichtbar ist oder nicht"
 
-#: clutter/clutter-actor.c:3872
+#: clutter/clutter-actor.c:3870
 msgid "Mapped"
 msgstr ""
 
-#: clutter/clutter-actor.c:3873
+#: clutter/clutter-actor.c:3871
 msgid "Whether the actor will be painted"
 msgstr "Ob der Akteur gezeichnet wird"
 
-#: clutter/clutter-actor.c:3887
+#: clutter/clutter-actor.c:3885
 msgid "Realized"
 msgstr ""
 
-#: clutter/clutter-actor.c:3888
+#: clutter/clutter-actor.c:3886
 msgid "Whether the actor has been realized"
 msgstr ""
 
-#: clutter/clutter-actor.c:3904
+#: clutter/clutter-actor.c:3902
 msgid "Reactive"
 msgstr ""
 
-#: clutter/clutter-actor.c:3905
+#: clutter/clutter-actor.c:3903
 msgid "Whether the actor is reactive to events"
 msgstr ""
 
-#: clutter/clutter-actor.c:3917
+#: clutter/clutter-actor.c:3915
 msgid "Has Clip"
 msgstr ""
 
-#: clutter/clutter-actor.c:3918
+#: clutter/clutter-actor.c:3916
 msgid "Whether the actor has a clip set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3933
+#: clutter/clutter-actor.c:3931
 msgid "Clip"
 msgstr ""
 
-#: clutter/clutter-actor.c:3934
+#: clutter/clutter-actor.c:3932
 #, fuzzy
 msgid "The clip region for the actor"
 msgstr "Richtung des Textes"
 
-#: clutter/clutter-actor.c:3948 clutter/clutter-actor-meta.c:205
-#: clutter/clutter-binding-pool.c:320 clutter/clutter-input-device.c:151
+#: clutter/clutter-actor.c:3946 clutter/clutter-actor-meta.c:205
+#: clutter/clutter-binding-pool.c:319 clutter/clutter-input-device.c:235
 msgid "Name"
 msgstr "Name"
 
-#: clutter/clutter-actor.c:3949
+#: clutter/clutter-actor.c:3947
 msgid "Name of the actor"
 msgstr "Name des Akteurs"
 
-#: clutter/clutter-actor.c:3963
+#: clutter/clutter-actor.c:3961
 #, fuzzy
 msgid "Scale X"
 msgstr "Skaliere X"
 
-#: clutter/clutter-actor.c:3964
+#: clutter/clutter-actor.c:3962
 msgid "Scale factor on the X axis"
 msgstr "Skalierungsfaktor auf der X-Achse"
 
-#: clutter/clutter-actor.c:3979
+#: clutter/clutter-actor.c:3977
 #, fuzzy
 msgid "Scale Y"
 msgstr "Skaliere Y"
 
-#: clutter/clutter-actor.c:3980
+#: clutter/clutter-actor.c:3978
 msgid "Scale factor on the Y axis"
 msgstr "Skalierungsfaktor auf der Y-Achse"
 
-#: clutter/clutter-actor.c:3995
+#: clutter/clutter-actor.c:3993
 msgid "Scale Center X"
 msgstr "Skalierungszentrum X"
 
-#: clutter/clutter-actor.c:3996
+#: clutter/clutter-actor.c:3994
 msgid "Horizontal scale center"
 msgstr "Horizontales Skalierungszentrum"
 
-#: clutter/clutter-actor.c:4011
+#: clutter/clutter-actor.c:4009
 msgid "Scale Center Y"
 msgstr "Skalierungszentrum Y"
 
-#: clutter/clutter-actor.c:4012
+#: clutter/clutter-actor.c:4010
 msgid "Vertical scale center"
 msgstr "Vertikales Skalierungszentrum"
 
-#: clutter/clutter-actor.c:4027
+#: clutter/clutter-actor.c:4025
 msgid "Scale Gravity"
 msgstr "Skalierungsanziehungskraft"
 
-#: clutter/clutter-actor.c:4028
+#: clutter/clutter-actor.c:4026
 msgid "The center of scaling"
 msgstr "Skalierungszentrum"
 
-#: clutter/clutter-actor.c:4045
+#: clutter/clutter-actor.c:4043
 msgid "Rotation Angle X"
 msgstr "Rotationswinkel X"
 
-#: clutter/clutter-actor.c:4046
+#: clutter/clutter-actor.c:4044
 msgid "The rotation angle on the X axis"
 msgstr "Der Rotationswinkel auf der X-Achse"
 
-#: clutter/clutter-actor.c:4061
+#: clutter/clutter-actor.c:4059
 msgid "Rotation Angle Y"
 msgstr "Rotationswinkel Y"
 
-#: clutter/clutter-actor.c:4062
+#: clutter/clutter-actor.c:4060
 msgid "The rotation angle on the Y axis"
 msgstr "Der Rotationswinkel auf der Y-Achse"
 
-#: clutter/clutter-actor.c:4077
+#: clutter/clutter-actor.c:4075
 msgid "Rotation Angle Z"
 msgstr "Rotationswinkel Z"
 
-#: clutter/clutter-actor.c:4078
+#: clutter/clutter-actor.c:4076
 msgid "The rotation angle on the Z axis"
 msgstr "Der Rotationswinkel auf der Z-Achse"
 
-#: clutter/clutter-actor.c:4093
+#: clutter/clutter-actor.c:4091
 msgid "Rotation Center X"
 msgstr "Rotationszentrum X"
 
-#: clutter/clutter-actor.c:4094
+#: clutter/clutter-actor.c:4092
 msgid "The rotation center on the X axis"
 msgstr "Das Rotationszentrum auf der X-Achse"
 
-#: clutter/clutter-actor.c:4110
+#: clutter/clutter-actor.c:4108
 msgid "Rotation Center Y"
 msgstr "Rotationszentrum Y"
 
-#: clutter/clutter-actor.c:4111
+#: clutter/clutter-actor.c:4109
 msgid "The rotation center on the Y axis"
 msgstr "Das Rotationszentrum auf der Y-Achse"
 
-#: clutter/clutter-actor.c:4127
+#: clutter/clutter-actor.c:4125
 msgid "Rotation Center Z"
 msgstr "Rotationszentrum Z"
 
-#: clutter/clutter-actor.c:4128
+#: clutter/clutter-actor.c:4126
 msgid "The rotation center on the Z axis"
 msgstr "Das Rotationszentrum auf der Z-Achse"
 
-#: clutter/clutter-actor.c:4144
+#: clutter/clutter-actor.c:4142
 #, fuzzy
 msgid "Rotation Center Z Gravity"
 msgstr "Rotationszentrum Z Anziehungskraft"
 
-#: clutter/clutter-actor.c:4145
+#: clutter/clutter-actor.c:4143
 msgid "Center point for rotation around the Z axis"
 msgstr "Rotationsmittelpunkt um die Z-Achse"
 
-#: clutter/clutter-actor.c:4163
+#: clutter/clutter-actor.c:4161
 msgid "Anchor X"
 msgstr "Anker X"
 
-#: clutter/clutter-actor.c:4164
+#: clutter/clutter-actor.c:4162
 msgid "X coordinate of the anchor point"
 msgstr "X-Koordinate des Ankerpunktes"
 
-#: clutter/clutter-actor.c:4180
+#: clutter/clutter-actor.c:4178
 msgid "Anchor Y"
 msgstr "Anker Y"
 
-#: clutter/clutter-actor.c:4181
+#: clutter/clutter-actor.c:4179
 msgid "Y coordinate of the anchor point"
 msgstr "Y-Koordinate des Ankerpunktes"
 
-#: clutter/clutter-actor.c:4196
+#: clutter/clutter-actor.c:4194
 msgid "Anchor Gravity"
 msgstr "Anker-Anziehungskraft"
 
-#: clutter/clutter-actor.c:4197
+#: clutter/clutter-actor.c:4195
 msgid "The anchor point as a ClutterGravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4216
+#: clutter/clutter-actor.c:4214
 msgid "Show on set parent"
 msgstr ""
 
-#: clutter/clutter-actor.c:4217
+#: clutter/clutter-actor.c:4215
 msgid "Whether the actor is shown when parented"
 msgstr ""
 
-#: clutter/clutter-actor.c:4237
+#: clutter/clutter-actor.c:4235
 msgid "Clip to Allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:4238
+#: clutter/clutter-actor.c:4236
 msgid "Sets the clip region to track the actor's allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:4248
+#: clutter/clutter-actor.c:4246
 msgid "Text Direction"
 msgstr "Textrichtung"
 
-#: clutter/clutter-actor.c:4249
+#: clutter/clutter-actor.c:4247
 msgid "Direction of the text"
 msgstr "Richtung des Textes"
 
-#: clutter/clutter-actor.c:4267
+#: clutter/clutter-actor.c:4265
 msgid "Has Pointer"
 msgstr ""
 
-#: clutter/clutter-actor.c:4268
+#: clutter/clutter-actor.c:4266
 msgid "Whether the actor contains the pointer of an input device"
 msgstr ""
 
-#: clutter/clutter-actor.c:4285
+#: clutter/clutter-actor.c:4283
 msgid "Actions"
 msgstr "Aktionen"
 
-#: clutter/clutter-actor.c:4286
+#: clutter/clutter-actor.c:4284
 msgid "Adds an action to the actor"
 msgstr "Fügt dem Akteur eine Aktion hinzu"
 
-#: clutter/clutter-actor.c:4300
+#: clutter/clutter-actor.c:4298
 msgid "Constraints"
 msgstr "Einschränkungen"
 
-#: clutter/clutter-actor.c:4301
+#: clutter/clutter-actor.c:4299
 msgid "Adds a constraint to the actor"
 msgstr "Fügt dem Akteur eine Beschränkung hinzu"
 
@@ -416,7 +416,8 @@ msgstr ""
 msgid "The name of the meta"
 msgstr ""
 
-#: clutter/clutter-actor-meta.c:219 clutter/clutter-shader.c:261
+#: clutter/clutter-actor-meta.c:219 clutter/clutter-input-device.c:314
+#: clutter/clutter-shader.c:295
 #, fuzzy
 msgid "Enabled"
 msgstr "Aktiv"
@@ -425,34 +426,34 @@ msgstr "Aktiv"
 msgid "Whether the meta is enabled"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:231
-#: clutter/clutter-bind-constraint.c:286 clutter/clutter-clone.c:322
+#: clutter/clutter-align-constraint.c:252
+#: clutter/clutter-bind-constraint.c:316 clutter/clutter-clone.c:322
 msgid "Source"
 msgstr "Quelle"
 
-#: clutter/clutter-align-constraint.c:232
+#: clutter/clutter-align-constraint.c:253
 msgid "The source of the alignment"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:245
+#: clutter/clutter-align-constraint.c:266
 msgid "Align Axis"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:246
+#: clutter/clutter-align-constraint.c:267
 msgid "The axis to align the position to"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:265
-#: clutter/clutter-desaturate-effect.c:309
+#: clutter/clutter-align-constraint.c:286
+#: clutter/clutter-desaturate-effect.c:307
 msgid "Factor"
 msgstr "Faktor"
 
-#: clutter/clutter-align-constraint.c:266
+#: clutter/clutter-align-constraint.c:287
 msgid "The alignment factor, between 0.0 and 1.0"
 msgstr ""
 
 #: clutter/clutter-alpha.c:339 clutter/clutter-animation.c:523
-#: clutter/clutter-animator.c:1801
+#: clutter/clutter-animator.c:1802
 msgid "Timeline"
 msgstr "Zeitleiste"
 
@@ -488,7 +489,7 @@ msgstr ""
 msgid "The mode of the animation"
 msgstr "Animationsmodus"
 
-#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1785
+#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1786
 #: clutter/clutter-media.c:194 clutter/clutter-state.c:1282
 msgid "Duration"
 msgstr "Dauer"
@@ -510,7 +511,7 @@ msgstr ""
 msgid "The timeline used by the animation"
 msgstr "Die von der Animation benutzte Zeitleiste"
 
-#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:299
+#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:298
 #, fuzzy
 msgid "Alpha"
 msgstr "Alpha"
@@ -519,224 +520,224 @@ msgstr "Alpha"
 msgid "The alpha used by the animation"
 msgstr ""
 
-#: clutter/clutter-animator.c:1786
+#: clutter/clutter-animator.c:1787
 msgid "The duration of the animation"
 msgstr "Die Dauer der Animation"
 
-#: clutter/clutter-animator.c:1802
+#: clutter/clutter-animator.c:1803
 msgid "The timeline of the animation"
 msgstr "Die Zeitleiste der Animation"
 
-#: clutter/clutter-behaviour.c:300
+#: clutter/clutter-behaviour.c:299
 msgid "Alpha Object to drive the behaviour"
 msgstr ""
 
-#: clutter/clutter-behaviour-depth.c:175
+#: clutter/clutter-behaviour-depth.c:174
 msgid "Start Depth"
 msgstr "Starttiefe"
 
-#: clutter/clutter-behaviour-depth.c:176
+#: clutter/clutter-behaviour-depth.c:175
 msgid "Initial depth to apply"
 msgstr "Anzuwendende initiale Tiefe"
 
-#: clutter/clutter-behaviour-depth.c:191
+#: clutter/clutter-behaviour-depth.c:190
 msgid "End Depth"
 msgstr "Endtiefe"
 
-#: clutter/clutter-behaviour-depth.c:192
+#: clutter/clutter-behaviour-depth.c:191
 msgid "Final depth to apply"
 msgstr "Anzuwendende finale Tiefe"
 
-#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-ellipse.c:394
 msgid "Start Angle"
 msgstr "Startwinkel"
 
-#: clutter/clutter-behaviour-ellipse.c:396
-#: clutter/clutter-behaviour-rotate.c:277
+#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-rotate.c:276
 msgid "Initial angle"
 msgstr "Initialer Winkel"
 
-#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-ellipse.c:410
 msgid "End Angle"
 msgstr "Endwinkel"
 
-#: clutter/clutter-behaviour-ellipse.c:412
-#: clutter/clutter-behaviour-rotate.c:295
+#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-rotate.c:294
 msgid "Final angle"
 msgstr "Finaler Winkel"
 
-#: clutter/clutter-behaviour-ellipse.c:427
+#: clutter/clutter-behaviour-ellipse.c:426
 msgid "Angle x tilt"
 msgstr "Winkel Neigung x"
 
-#: clutter/clutter-behaviour-ellipse.c:428
+#: clutter/clutter-behaviour-ellipse.c:427
 msgid "Tilt of the ellipse around x axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:443
+#: clutter/clutter-behaviour-ellipse.c:442
 msgid "Angle y tilt"
 msgstr "Winkel Neigung y"
 
-#: clutter/clutter-behaviour-ellipse.c:444
+#: clutter/clutter-behaviour-ellipse.c:443
 msgid "Tilt of the ellipse around y axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:459
+#: clutter/clutter-behaviour-ellipse.c:458
 msgid "Angle z tilt"
 msgstr "Winkel Neigung z"
 
-#: clutter/clutter-behaviour-ellipse.c:460
+#: clutter/clutter-behaviour-ellipse.c:459
 msgid "Tilt of the ellipse around z axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:476
+#: clutter/clutter-behaviour-ellipse.c:475
 msgid "Width of the ellipse"
 msgstr "Breite der Ellipse"
 
-#: clutter/clutter-behaviour-ellipse.c:492
+#: clutter/clutter-behaviour-ellipse.c:491
 msgid "Height of ellipse"
 msgstr "Höhe der Ellipse"
 
-#: clutter/clutter-behaviour-ellipse.c:507
+#: clutter/clutter-behaviour-ellipse.c:506
 #, fuzzy
 msgid "Center"
 msgstr "Zentrum/Mittelpunk"
 
-#: clutter/clutter-behaviour-ellipse.c:508
+#: clutter/clutter-behaviour-ellipse.c:507
 #, fuzzy
 msgid "Center of ellipse"
 msgstr "Zentrum/Mittelpunkt der Ellipse"
 
-#: clutter/clutter-behaviour-ellipse.c:522
-#: clutter/clutter-behaviour-rotate.c:330
+#: clutter/clutter-behaviour-ellipse.c:521
+#: clutter/clutter-behaviour-rotate.c:329
 msgid "Direction"
 msgstr "Richtung"
 
-#: clutter/clutter-behaviour-ellipse.c:523
-#: clutter/clutter-behaviour-rotate.c:331
+#: clutter/clutter-behaviour-ellipse.c:522
+#: clutter/clutter-behaviour-rotate.c:330
 msgid "Direction of rotation"
 msgstr "Rotationsrichtung"
 
-#: clutter/clutter-behaviour-opacity.c:178
+#: clutter/clutter-behaviour-opacity.c:177
 msgid "Opacity Start"
 msgstr "Start-Deckungskraft"
 
-#: clutter/clutter-behaviour-opacity.c:179
+#: clutter/clutter-behaviour-opacity.c:178
 msgid "Initial opacity level"
 msgstr "Initialer Deckungskraftgrad"
 
-#: clutter/clutter-behaviour-opacity.c:196
+#: clutter/clutter-behaviour-opacity.c:195
 msgid "Opacity End"
 msgstr "End-Deckungskraft"
 
-#: clutter/clutter-behaviour-opacity.c:197
+#: clutter/clutter-behaviour-opacity.c:196
 msgid "Final opacity level"
 msgstr "Finaler Deckungskraftgrad"
 
-#: clutter/clutter-behaviour-path.c:220
+#: clutter/clutter-behaviour-path.c:219
 msgid "Path"
 msgstr "Pfad"
 
-#: clutter/clutter-behaviour-path.c:221
+#: clutter/clutter-behaviour-path.c:220
 msgid "The ClutterPath object representing the path to animate along"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:276
+#: clutter/clutter-behaviour-rotate.c:275
 msgid "Angle Begin"
 msgstr "Winkel Anfang"
 
-#: clutter/clutter-behaviour-rotate.c:294
+#: clutter/clutter-behaviour-rotate.c:293
 msgid "Angle End"
 msgstr "Winkel Ende"
 
-#: clutter/clutter-behaviour-rotate.c:312
+#: clutter/clutter-behaviour-rotate.c:311
 msgid "Axis"
 msgstr "Achse"
 
-#: clutter/clutter-behaviour-rotate.c:313
+#: clutter/clutter-behaviour-rotate.c:312
 msgid "Axis of rotation"
 msgstr "Rotationsachse"
 
-#: clutter/clutter-behaviour-rotate.c:348
+#: clutter/clutter-behaviour-rotate.c:347
 #, fuzzy
 msgid "Center X"
 msgstr "Zentrum/Mittelpunkt X"
 
-#: clutter/clutter-behaviour-rotate.c:349
+#: clutter/clutter-behaviour-rotate.c:348
 msgid "X coordinate of the center of rotation"
 msgstr "X-Koordinate des Rotationszentrums"
 
-#: clutter/clutter-behaviour-rotate.c:366
+#: clutter/clutter-behaviour-rotate.c:365
 #, fuzzy
 msgid "Center Y"
 msgstr "Zentrum/Mittelpunkt Y"
 
-#: clutter/clutter-behaviour-rotate.c:367
+#: clutter/clutter-behaviour-rotate.c:366
 msgid "Y coordinate of the center of rotation"
 msgstr "Y-Koordinate des Rotationszentrums"
 
-#: clutter/clutter-behaviour-rotate.c:384
+#: clutter/clutter-behaviour-rotate.c:383
 #, fuzzy
 msgid "Center Z"
 msgstr "Zentrum/Mittelpunkt Y"
 
-#: clutter/clutter-behaviour-rotate.c:385
+#: clutter/clutter-behaviour-rotate.c:384
 msgid "Z coordinate of the center of rotation"
 msgstr "Z-Koordinate des Rotationszentrums"
 
-#: clutter/clutter-behaviour-scale.c:219
+#: clutter/clutter-behaviour-scale.c:218
 #, fuzzy
 msgid "X Start Scale"
 msgstr "Startskalierung X"
 
-#: clutter/clutter-behaviour-scale.c:220
+#: clutter/clutter-behaviour-scale.c:219
 msgid "Initial scale on the X axis"
 msgstr "Initiale Skalierung auf der X-Achse"
 
-#: clutter/clutter-behaviour-scale.c:238
+#: clutter/clutter-behaviour-scale.c:237
 #, fuzzy
 msgid "X End Scale"
 msgstr "Endskalierung X"
 
-#: clutter/clutter-behaviour-scale.c:239
+#: clutter/clutter-behaviour-scale.c:238
 msgid "Final scale on the X axis"
 msgstr "Finale Skalierung auf der X-Achse"
 
-#: clutter/clutter-behaviour-scale.c:257
+#: clutter/clutter-behaviour-scale.c:256
 #, fuzzy
 msgid "Y Start Scale"
 msgstr "Startskalierung Y"
 
-#: clutter/clutter-behaviour-scale.c:258
+#: clutter/clutter-behaviour-scale.c:257
 msgid "Initial scale on the Y axis"
 msgstr "Initiale Skalierung auf der Y-Achse"
 
-#: clutter/clutter-behaviour-scale.c:276
+#: clutter/clutter-behaviour-scale.c:275
 #, fuzzy
 msgid "Y End Scale"
 msgstr "Endskalierung Y"
 
-#: clutter/clutter-behaviour-scale.c:277
+#: clutter/clutter-behaviour-scale.c:276
 msgid "Final scale on the Y axis"
 msgstr "Finale Skalierung auf der Y-Achse"
 
-#: clutter/clutter-bind-constraint.c:287
+#: clutter/clutter-bind-constraint.c:317
 msgid "The source of the binding"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:300
+#: clutter/clutter-bind-constraint.c:330
 msgid "Coordinate"
 msgstr "Koordinate"
 
-#: clutter/clutter-bind-constraint.c:301
+#: clutter/clutter-bind-constraint.c:331
 msgid "The coordinate to bind"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:315
+#: clutter/clutter-bind-constraint.c:345
 msgid "Offset"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:316
+#: clutter/clutter-bind-constraint.c:346
 msgid "The offset in pixels to apply to the binding"
 msgstr ""
 
@@ -768,7 +769,7 @@ msgstr ""
 msgid "Default vertical alignment for the actors inside the layout manager"
 msgstr ""
 
-#: clutter/clutter-binding-pool.c:321
+#: clutter/clutter-binding-pool.c:320
 msgid "The unique name of the binding pool"
 msgstr ""
 
@@ -781,7 +782,7 @@ msgid "The layout manager used by the box"
 msgstr ""
 
 #: clutter/clutter-box.c:514 clutter/clutter-rectangle.c:258
-#: clutter/clutter-stage.c:1307
+#: clutter/clutter-stage.c:1317
 msgid "Color"
 msgstr "Farbe"
 
@@ -920,19 +921,19 @@ msgstr ""
 msgid "The actor wrapped by this data"
 msgstr ""
 
-#: clutter/clutter-click-action.c:283
+#: clutter/clutter-click-action.c:302
 msgid "Pressed"
 msgstr ""
 
-#: clutter/clutter-click-action.c:284
+#: clutter/clutter-click-action.c:303
 msgid "Whether the clickable should be in pressed state"
 msgstr ""
 
-#: clutter/clutter-click-action.c:297
+#: clutter/clutter-click-action.c:316
 msgid "Held"
 msgstr ""
 
-#: clutter/clutter-click-action.c:298
+#: clutter/clutter-click-action.c:317
 msgid "Whether the clickable has a grab"
 msgstr ""
 
@@ -940,11 +941,11 @@ msgstr ""
 msgid "Specifies the actor to be cloned"
 msgstr ""
 
-#: clutter/clutter-colorize-effect.c:309
+#: clutter/clutter-colorize-effect.c:307
 msgid "Tint"
 msgstr ""
 
-#: clutter/clutter-colorize-effect.c:310
+#: clutter/clutter-colorize-effect.c:308
 msgid "The tint to apply"
 msgstr ""
 
@@ -973,11 +974,11 @@ msgstr ""
 msgid "The material to be used when painting the back of the actor"
 msgstr ""
 
-#: clutter/clutter-desaturate-effect.c:310
+#: clutter/clutter-desaturate-effect.c:308
 msgid "The desaturation factor"
 msgstr ""
 
-#: clutter/clutter-device-manager.c:130
+#: clutter/clutter-device-manager.c:130 clutter/clutter-input-device.c:343
 msgid "Backend"
 msgstr ""
 
@@ -985,35 +986,35 @@ msgstr ""
 msgid "The ClutterBackend of the device manager"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:490
+#: clutter/clutter-drag-action.c:491
 msgid "Horizontal Drag Threshold"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:491
+#: clutter/clutter-drag-action.c:492
 msgid "The horizontal amount of pixels required to start dragging"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:510
+#: clutter/clutter-drag-action.c:511
 msgid "Vertical Drag Threshold"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:511
+#: clutter/clutter-drag-action.c:512
 msgid "The vertical amount of pixels required to start dragging"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:532
+#: clutter/clutter-drag-action.c:533
 msgid "Drag Handle"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:533
+#: clutter/clutter-drag-action.c:534
 msgid "The actor that is being dragged"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:546
+#: clutter/clutter-drag-action.c:547
 msgid "Drag Axis"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:547
+#: clutter/clutter-drag-action.c:548
 msgid "Constraints the dragging to an axis"
 msgstr ""
 
@@ -1077,26 +1078,68 @@ msgstr ""
 msgid "Maximum height for each row"
 msgstr ""
 
-#: clutter/clutter-input-device.c:134
+#: clutter/clutter-input-device.c:219
 msgid "Id"
 msgstr ""
 
-#: clutter/clutter-input-device.c:135
+#: clutter/clutter-input-device.c:220
 msgid "Unique identifier of the device"
 msgstr ""
 
-#: clutter/clutter-input-device.c:152
+#: clutter/clutter-input-device.c:236
 msgid "The name of the device"
 msgstr ""
 
-#: clutter/clutter-input-device.c:167
+#: clutter/clutter-input-device.c:250
 msgid "Device Type"
 msgstr ""
 
-#: clutter/clutter-input-device.c:168
+#: clutter/clutter-input-device.c:251
 msgid "The type of the device"
 msgstr ""
 
+#: clutter/clutter-input-device.c:266
+msgid "Device Manager"
+msgstr ""
+
+#: clutter/clutter-input-device.c:267
+msgid "The device manager instance"
+msgstr ""
+
+#: clutter/clutter-input-device.c:280
+msgid "Device Mode"
+msgstr ""
+
+#: clutter/clutter-input-device.c:281
+#, fuzzy
+msgid "The mode of the device"
+msgstr "Animationsmodus"
+
+#: clutter/clutter-input-device.c:295
+msgid "Has Cursor"
+msgstr ""
+
+#: clutter/clutter-input-device.c:296
+msgid "Whether the device has a cursor"
+msgstr ""
+
+#: clutter/clutter-input-device.c:315
+#, fuzzy
+msgid "Whether the device is enabled"
+msgstr "Ob der Akteur gezeichnet wird"
+
+#: clutter/clutter-input-device.c:328
+msgid "Number of Axes"
+msgstr ""
+
+#: clutter/clutter-input-device.c:329
+msgid "The number of axes on the device"
+msgstr ""
+
+#: clutter/clutter-input-device.c:344
+msgid "The backend instance"
+msgstr ""
+
 #: clutter/clutter-interval.c:397
 msgid "Value Type"
 msgstr ""
@@ -1113,61 +1156,61 @@ msgstr ""
 msgid "The manager that created this data"
 msgstr ""
 
-#: clutter/clutter-main.c:756
+#: clutter/clutter-main.c:753
 msgid "default:LTR"
 msgstr "default:LTR"
 
-#: clutter/clutter-main.c:1560
+#: clutter/clutter-main.c:1557
 msgid "Show frames per second"
 msgstr "Bilder pro Sekunde anzeigen"
 
-#: clutter/clutter-main.c:1562
+#: clutter/clutter-main.c:1559
 msgid "Default frame rate"
 msgstr "Vorgabebildfrequenz"
 
-#: clutter/clutter-main.c:1564
+#: clutter/clutter-main.c:1561
 msgid "Make all warnings fatal"
 msgstr "Alle Warnungen fatal machen"
 
-#: clutter/clutter-main.c:1567
+#: clutter/clutter-main.c:1564
 msgid "Direction for the text"
 msgstr "Richtung des Textes"
 
-#: clutter/clutter-main.c:1570
+#: clutter/clutter-main.c:1567
 msgid "Disable mipmapping on text"
 msgstr "Mip-Mapping für Text ausschalten"
 
-#: clutter/clutter-main.c:1573
+#: clutter/clutter-main.c:1570
 msgid "Use 'fuzzy' picking"
 msgstr "»Unscharfes« Herausgreifen benutzen"
 
-#: clutter/clutter-main.c:1576
+#: clutter/clutter-main.c:1573
 msgid "Clutter debugging flags to set"
 msgstr "zu setzende Clutter-Fehlersuchmerkmale"
 
-#: clutter/clutter-main.c:1578
+#: clutter/clutter-main.c:1575
 msgid "Clutter debugging flags to unset"
 msgstr "zu entfernende Clutter-Fehlersuchmerkmale"
 
-#: clutter/clutter-main.c:1582
+#: clutter/clutter-main.c:1579
 #, fuzzy
 msgid "Clutter profiling flags to set"
 msgstr "zu setzende Clutter-Fehlersuchmerkmale"
 
-#: clutter/clutter-main.c:1584
+#: clutter/clutter-main.c:1581
 #, fuzzy
 msgid "Clutter profiling flags to unset"
 msgstr "zu entfernende Clutter-Fehlersuchmerkmale"
 
-#: clutter/clutter-main.c:1587
+#: clutter/clutter-main.c:1584
 msgid "Enable accessibility"
 msgstr ""
 
-#: clutter/clutter-main.c:1774
+#: clutter/clutter-main.c:1771
 msgid "Clutter Options"
 msgstr "Clutter-Optionen"
 
-#: clutter/clutter-main.c:1775
+#: clutter/clutter-main.c:1772
 msgid "Show Clutter Options"
 msgstr "Clutter-Optionen anzeigen"
 
@@ -1283,48 +1326,48 @@ msgstr ""
 msgid "The path of the currently parsed file"
 msgstr ""
 
-#: clutter/clutter-shader.c:215
+#: clutter/clutter-shader.c:249
 #, fuzzy
 msgid "Vertex Source"
 msgstr "Vertex-Shader"
 
-#: clutter/clutter-shader.c:216
+#: clutter/clutter-shader.c:250
 #, fuzzy
 msgid "Source of vertex shader"
 msgstr "Vertex-Shader"
 
-#: clutter/clutter-shader.c:230
+#: clutter/clutter-shader.c:264
 #, fuzzy
 msgid "Fragment Source"
 msgstr "Fragment-Shader"
 
-#: clutter/clutter-shader.c:231
+#: clutter/clutter-shader.c:265
 #, fuzzy
 msgid "Source of fragment shader"
 msgstr "Fragment-Shader"
 
-#: clutter/clutter-shader.c:246
+#: clutter/clutter-shader.c:280
 msgid "Compiled"
 msgstr ""
 
-#: clutter/clutter-shader.c:247
+#: clutter/clutter-shader.c:281
 msgid "Whether the shader is compiled and linked"
 msgstr ""
 
-#: clutter/clutter-shader.c:262
+#: clutter/clutter-shader.c:296
 msgid "Whether the shader is enabled"
 msgstr ""
 
-#: clutter/clutter-shader.c:467
+#: clutter/clutter-shader.c:501
 #, c-format
 msgid "%s compilation failed: %s"
 msgstr "%s-Kompilierung fehlgeschlagen: %s"
 
-#: clutter/clutter-shader.c:468
+#: clutter/clutter-shader.c:502
 msgid "Vertex shader"
 msgstr "Vertex-Shader"
 
-#: clutter/clutter-shader.c:469
+#: clutter/clutter-shader.c:503
 msgid "Fragment shader"
 msgstr "Fragment-Shader"
 
@@ -1336,98 +1379,106 @@ msgstr ""
 msgid "The type of shader used"
 msgstr ""
 
-#: clutter/clutter-stage.c:1249
+#: clutter/clutter-stage.c:1259
 msgid "Fullscreen Set"
 msgstr ""
 
-#: clutter/clutter-stage.c:1250
+#: clutter/clutter-stage.c:1260
 msgid "Whether the main stage is fullscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1266
+#: clutter/clutter-stage.c:1276
 msgid "Offscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1267
+#: clutter/clutter-stage.c:1277
 msgid "Whether the main stage should be rendered offscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1279 clutter/clutter-text.c:2643
+#: clutter/clutter-stage.c:1289 clutter/clutter-text.c:2667
 msgid "Cursor Visible"
 msgstr ""
 
-#: clutter/clutter-stage.c:1280
+#: clutter/clutter-stage.c:1290
 msgid "Whether the mouse pointer is visible on the main stage"
 msgstr ""
 
-#: clutter/clutter-stage.c:1294
+#: clutter/clutter-stage.c:1304
 msgid "User Resizable"
 msgstr ""
 
-#: clutter/clutter-stage.c:1295
+#: clutter/clutter-stage.c:1305
 msgid "Whether the stage is able to be resized via user interaction"
 msgstr ""
 
-#: clutter/clutter-stage.c:1308
+#: clutter/clutter-stage.c:1318
 msgid "The color of the stage"
 msgstr ""
 
-#: clutter/clutter-stage.c:1322
+#: clutter/clutter-stage.c:1332
 msgid "Perspective"
 msgstr ""
 
-#: clutter/clutter-stage.c:1323
+#: clutter/clutter-stage.c:1333
 msgid "Perspective projection parameters"
 msgstr ""
 
-#: clutter/clutter-stage.c:1338
+#: clutter/clutter-stage.c:1348
 msgid "Title"
 msgstr ""
 
-#: clutter/clutter-stage.c:1339
+#: clutter/clutter-stage.c:1349
 msgid "Stage Title"
 msgstr ""
 
-#: clutter/clutter-stage.c:1354
+#: clutter/clutter-stage.c:1364
 msgid "Use Fog"
 msgstr ""
 
-#: clutter/clutter-stage.c:1355
+#: clutter/clutter-stage.c:1365
 msgid "Whether to enable depth cueing"
 msgstr ""
 
-#: clutter/clutter-stage.c:1369
+#: clutter/clutter-stage.c:1379
 msgid "Fog"
 msgstr ""
 
-#: clutter/clutter-stage.c:1370
+#: clutter/clutter-stage.c:1380
 msgid "Settings for the depth cueing"
 msgstr ""
 
-#: clutter/clutter-stage.c:1386
+#: clutter/clutter-stage.c:1396
 msgid "Use Alpha"
 msgstr ""
 
-#: clutter/clutter-stage.c:1387
+#: clutter/clutter-stage.c:1397
 msgid "Whether to honour the alpha component of the stage color"
 msgstr ""
 
-#: clutter/clutter-stage.c:1403
+#: clutter/clutter-stage.c:1413
 msgid "Key Focus"
 msgstr ""
 
-#: clutter/clutter-stage.c:1404
+#: clutter/clutter-stage.c:1414
 msgid "The currently key focused actor"
 msgstr ""
 
-#: clutter/clutter-stage.c:1420
+#: clutter/clutter-stage.c:1430
 msgid "No Clear Hint"
 msgstr ""
 
-#: clutter/clutter-stage.c:1421
+#: clutter/clutter-stage.c:1431
 msgid "Whether the stage should clear its contents"
 msgstr ""
 
+#: clutter/clutter-stage.c:1444
+msgid "Accept Focus"
+msgstr ""
+
+#: clutter/clutter-stage.c:1445
+msgid "Whether the stage should accept focus on show"
+msgstr ""
+
 #: clutter/clutter-state.c:1268
 msgid "State"
 msgstr ""
@@ -1441,191 +1492,191 @@ msgstr ""
 msgid "Default transition duration"
 msgstr "Vorgabebildfrequenz"
 
-#: clutter/clutter-text.c:2530
+#: clutter/clutter-text.c:2554
 msgid "Font Name"
 msgstr ""
 
-#: clutter/clutter-text.c:2531
+#: clutter/clutter-text.c:2555
 msgid "The font to be used by the text"
 msgstr ""
 
-#: clutter/clutter-text.c:2548
+#: clutter/clutter-text.c:2572
 msgid "Font Description"
 msgstr ""
 
-#: clutter/clutter-text.c:2549
+#: clutter/clutter-text.c:2573
 msgid "The font description to be used"
 msgstr ""
 
-#: clutter/clutter-text.c:2565
+#: clutter/clutter-text.c:2589
 msgid "Text"
 msgstr ""
 
-#: clutter/clutter-text.c:2566
+#: clutter/clutter-text.c:2590
 msgid "The text to render"
 msgstr ""
 
-#: clutter/clutter-text.c:2580
+#: clutter/clutter-text.c:2604
 msgid "Font Color"
 msgstr ""
 
-#: clutter/clutter-text.c:2581
+#: clutter/clutter-text.c:2605
 msgid "Color of the font used by the text"
 msgstr ""
 
-#: clutter/clutter-text.c:2595
+#: clutter/clutter-text.c:2619
 msgid "Editable"
 msgstr ""
 
-#: clutter/clutter-text.c:2596
+#: clutter/clutter-text.c:2620
 msgid "Whether the text is editable"
 msgstr ""
 
-#: clutter/clutter-text.c:2611
+#: clutter/clutter-text.c:2635
 msgid "Selectable"
 msgstr ""
 
-#: clutter/clutter-text.c:2612
+#: clutter/clutter-text.c:2636
 msgid "Whether the text is selectable"
 msgstr ""
 
-#: clutter/clutter-text.c:2626
+#: clutter/clutter-text.c:2650
 msgid "Activatable"
 msgstr ""
 
-#: clutter/clutter-text.c:2627
+#: clutter/clutter-text.c:2651
 msgid "Whether pressing return causes the activate signal to be emitted"
 msgstr ""
 
-#: clutter/clutter-text.c:2644
+#: clutter/clutter-text.c:2668
 msgid "Whether the input cursor is visible"
 msgstr ""
 
-#: clutter/clutter-text.c:2658 clutter/clutter-text.c:2659
+#: clutter/clutter-text.c:2682 clutter/clutter-text.c:2683
 msgid "Cursor Color"
 msgstr ""
 
-#: clutter/clutter-text.c:2673
+#: clutter/clutter-text.c:2697
 msgid "Cursor Color Set"
 msgstr ""
 
-#: clutter/clutter-text.c:2674
+#: clutter/clutter-text.c:2698
 msgid "Whether the cursor color has been set"
 msgstr ""
 
-#: clutter/clutter-text.c:2689
+#: clutter/clutter-text.c:2713
 msgid "Cursor Size"
 msgstr ""
 
-#: clutter/clutter-text.c:2690
+#: clutter/clutter-text.c:2714
 msgid "The width of the cursor, in pixels"
 msgstr ""
 
-#: clutter/clutter-text.c:2704
+#: clutter/clutter-text.c:2728
 msgid "Cursor Position"
 msgstr ""
 
-#: clutter/clutter-text.c:2705
+#: clutter/clutter-text.c:2729
 msgid "The cursor position"
 msgstr ""
 
-#: clutter/clutter-text.c:2720
+#: clutter/clutter-text.c:2744
 msgid "Selection-bound"
 msgstr ""
 
-#: clutter/clutter-text.c:2721
+#: clutter/clutter-text.c:2745
 msgid "The cursor position of the other end of the selection"
 msgstr ""
 
-#: clutter/clutter-text.c:2736 clutter/clutter-text.c:2737
+#: clutter/clutter-text.c:2760 clutter/clutter-text.c:2761
 msgid "Selection Color"
 msgstr ""
 
-#: clutter/clutter-text.c:2751
+#: clutter/clutter-text.c:2775
 msgid "Selection Color Set"
 msgstr ""
 
-#: clutter/clutter-text.c:2752
+#: clutter/clutter-text.c:2776
 msgid "Whether the selection color has been set"
 msgstr ""
 
-#: clutter/clutter-text.c:2767
+#: clutter/clutter-text.c:2791
 msgid "Attributes"
 msgstr ""
 
-#: clutter/clutter-text.c:2768
+#: clutter/clutter-text.c:2792
 msgid "A list of style attributes to apply to the contents of the actor"
 msgstr ""
 
-#: clutter/clutter-text.c:2790
+#: clutter/clutter-text.c:2814
 msgid "Use markup"
 msgstr ""
 
-#: clutter/clutter-text.c:2791
+#: clutter/clutter-text.c:2815
 msgid "Whether or not the text includes Pango markup"
 msgstr ""
 
-#: clutter/clutter-text.c:2807
+#: clutter/clutter-text.c:2831
 msgid "Line wrap"
 msgstr ""
 
-#: clutter/clutter-text.c:2808
+#: clutter/clutter-text.c:2832
 msgid "If set, wrap the lines if the text becomes too wide"
 msgstr ""
 
-#: clutter/clutter-text.c:2823
+#: clutter/clutter-text.c:2847
 msgid "Line wrap mode"
 msgstr ""
 
-#: clutter/clutter-text.c:2824
+#: clutter/clutter-text.c:2848
 msgid "Control how line-wrapping is done"
 msgstr ""
 
-#: clutter/clutter-text.c:2839
+#: clutter/clutter-text.c:2863
 msgid "Ellipsize"
 msgstr ""
 
-#: clutter/clutter-text.c:2840
+#: clutter/clutter-text.c:2864
 msgid "The preferred place to ellipsize the string"
 msgstr ""
 
-#: clutter/clutter-text.c:2856
+#: clutter/clutter-text.c:2880
 msgid "Line Alignment"
 msgstr ""
 
-#: clutter/clutter-text.c:2857
+#: clutter/clutter-text.c:2881
 msgid "The preferred alignment for the string, for multi-line text"
 msgstr ""
 
-#: clutter/clutter-text.c:2873
+#: clutter/clutter-text.c:2897
 msgid "Justify"
 msgstr ""
 
-#: clutter/clutter-text.c:2874
+#: clutter/clutter-text.c:2898
 msgid "Whether the text should be justified"
 msgstr ""
 
-#: clutter/clutter-text.c:2889
+#: clutter/clutter-text.c:2913
 msgid "Password Character"
 msgstr ""
 
-#: clutter/clutter-text.c:2890
+#: clutter/clutter-text.c:2914
 msgid "If non-zero, use this character to display the actor's contents"
 msgstr ""
 
-#: clutter/clutter-text.c:2904
+#: clutter/clutter-text.c:2928
 msgid "Max Length"
 msgstr ""
 
-#: clutter/clutter-text.c:2905
+#: clutter/clutter-text.c:2929
 msgid "Maximum length of the text inside the actor"
 msgstr ""
 
-#: clutter/clutter-text.c:2928
+#: clutter/clutter-text.c:2952
 msgid "Single Line Mode"
 msgstr ""
 
-#: clutter/clutter-text.c:2929
+#: clutter/clutter-text.c:2953
 msgid "Whether the text should be a single line"
 msgstr ""
 
@@ -1746,23 +1797,23 @@ msgstr ""
 msgid "Shape actor with alpha channel when picking"
 msgstr ""
 
-#: clutter/glx/clutter-backend-glx.c:128
+#: clutter/glx/clutter-backend-glx.c:131
 msgid "VBlank method to be used (none, dri or glx)"
 msgstr "zu benutzende VBlank-Methode (none, dri oder glx)"
 
-#: clutter/x11/clutter-backend-x11.c:364
+#: clutter/x11/clutter-backend-x11.c:473
 msgid "X display to use"
 msgstr "zu benutzende X-Anzeige"
 
-#: clutter/x11/clutter-backend-x11.c:370
+#: clutter/x11/clutter-backend-x11.c:479
 msgid "X screen to use"
 msgstr "zu benutzender X-Bildschirm"
 
-#: clutter/x11/clutter-backend-x11.c:375
+#: clutter/x11/clutter-backend-x11.c:484
 msgid "Make X calls synchronous"
 msgstr "X-Aufrufe synchronisieren"
 
-#: clutter/x11/clutter-backend-x11.c:382
+#: clutter/x11/clutter-backend-x11.c:491
 msgid "Enable XInput support"
 msgstr "XInput-Unterstützung einschalten"
 
index bf98909..acbfd2c 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: clutter 1.3.14\n"
 "Report-Msgid-Bugs-To: http://bugzilla.clutter-project.org/enter_bug.cgi?"
 "product=clutter\n"
-"POT-Creation-Date: 2010-12-17 15:51+0000\n"
+"POT-Creation-Date: 2011-02-07 15:50+0000\n"
 "PO-Revision-Date: 2010-10-05 09:02+0100\n"
 "Last-Translator: Damien Lespiau <damien.lespiau@gmail.com>\n"
 "Language-Team: GNOME French Team <gnomefr@traduc.org>\n"
@@ -19,380 +19,380 @@ msgstr ""
 "X-Poedit-Language: French\n"
 "X-Poedit-Country: FRANCE\n"
 
-#: clutter/clutter-actor.c:3480
+#: clutter/clutter-actor.c:3478
 msgid "X coordinate"
 msgstr "Coordonnée X"
 
-#: clutter/clutter-actor.c:3481
+#: clutter/clutter-actor.c:3479
 msgid "X coordinate of the actor"
 msgstr "Coordonnée X de l'acteur"
 
-#: clutter/clutter-actor.c:3496
+#: clutter/clutter-actor.c:3494
 msgid "Y coordinate"
 msgstr "Coordonnée Y"
 
-#: clutter/clutter-actor.c:3497
+#: clutter/clutter-actor.c:3495
 msgid "Y coordinate of the actor"
 msgstr "Coordonnée X de l'acteur"
 
-#: clutter/clutter-actor.c:3512 clutter/clutter-behaviour-ellipse.c:475
+#: clutter/clutter-actor.c:3510 clutter/clutter-behaviour-ellipse.c:474
 msgid "Width"
 msgstr "Largeur"
 
-#: clutter/clutter-actor.c:3513
+#: clutter/clutter-actor.c:3511
 msgid "Width of the actor"
 msgstr "Largeur de l'acteur"
 
-#: clutter/clutter-actor.c:3527 clutter/clutter-behaviour-ellipse.c:491
+#: clutter/clutter-actor.c:3525 clutter/clutter-behaviour-ellipse.c:490
 msgid "Height"
 msgstr "Hauteur"
 
-#: clutter/clutter-actor.c:3528
+#: clutter/clutter-actor.c:3526
 msgid "Height of the actor"
 msgstr "Hauteur de l'acteur"
 
-#: clutter/clutter-actor.c:3546
+#: clutter/clutter-actor.c:3544
 msgid "Fixed X"
 msgstr "Position fixe selon l'axe X"
 
-#: clutter/clutter-actor.c:3547
+#: clutter/clutter-actor.c:3545
 msgid "Forced X position of the actor"
 msgstr "Position fixe de l'acteur selon l'axe X"
 
-#: clutter/clutter-actor.c:3565
+#: clutter/clutter-actor.c:3563
 msgid "Fixed Y"
 msgstr "Position fixe selon l'axe Y"
 
-#: clutter/clutter-actor.c:3566
+#: clutter/clutter-actor.c:3564
 msgid "Forced Y position of the actor"
 msgstr "Position fixe de l'acteur selon l'axe Y"
 
-#: clutter/clutter-actor.c:3582
+#: clutter/clutter-actor.c:3580
 msgid "Fixed position set"
 msgstr "Position fixe renseignée"
 
-#: clutter/clutter-actor.c:3583
+#: clutter/clutter-actor.c:3581
 msgid "Whether to use fixed positioning for the actor"
 msgstr "Si l'acteur utilise un positionnement fixe ou non"
 
-#: clutter/clutter-actor.c:3605
+#: clutter/clutter-actor.c:3603
 msgid "Min Width"
 msgstr "Largeur minimale"
 
-#: clutter/clutter-actor.c:3606
+#: clutter/clutter-actor.c:3604
 msgid "Forced minimum width request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3625
+#: clutter/clutter-actor.c:3623
 msgid "Min Height"
 msgstr "Hauteur maximale"
 
-#: clutter/clutter-actor.c:3626
+#: clutter/clutter-actor.c:3624
 msgid "Forced minimum height request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3645
+#: clutter/clutter-actor.c:3643
 msgid "Natural Width"
 msgstr "Largeur naturelle"
 
-#: clutter/clutter-actor.c:3646
+#: clutter/clutter-actor.c:3644
 msgid "Forced natural width request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3665
+#: clutter/clutter-actor.c:3663
 msgid "Natural Height"
 msgstr "Hauteur Naturelle"
 
-#: clutter/clutter-actor.c:3666
+#: clutter/clutter-actor.c:3664
 msgid "Forced natural height request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3682
+#: clutter/clutter-actor.c:3680
 msgid "Minimum width set"
 msgstr "Largeur minimale renseignée"
 
-#: clutter/clutter-actor.c:3683
+#: clutter/clutter-actor.c:3681
 msgid "Whether to use the min-width property"
 msgstr "Si la largeur minimale a été renseignée ou non"
 
-#: clutter/clutter-actor.c:3698
+#: clutter/clutter-actor.c:3696
 msgid "Minimum height set"
 msgstr "Hauteur minimale renseignée"
 
-#: clutter/clutter-actor.c:3699
+#: clutter/clutter-actor.c:3697
 msgid "Whether to use the min-height property"
 msgstr "Si la hauteur minimale a été renseignée ou non"
 
-#: clutter/clutter-actor.c:3714
+#: clutter/clutter-actor.c:3712
 msgid "Natural width set"
 msgstr "Largeur naturelle renseignée"
 
-#: clutter/clutter-actor.c:3715
+#: clutter/clutter-actor.c:3713
 msgid "Whether to use the natural-width property"
 msgstr "Si la largeur naturelle a été renseignée ou non"
 
-#: clutter/clutter-actor.c:3732
+#: clutter/clutter-actor.c:3730
 msgid "Natural height set"
 msgstr "Haueur naturelle renseignée"
 
-#: clutter/clutter-actor.c:3733
+#: clutter/clutter-actor.c:3731
 msgid "Whether to use the natural-height property"
 msgstr "Si la hauteur naturelle a été renseignée ou non"
 
-#: clutter/clutter-actor.c:3752
+#: clutter/clutter-actor.c:3750
 msgid "Allocation"
 msgstr "Allocation"
 
-#: clutter/clutter-actor.c:3753
+#: clutter/clutter-actor.c:3751
 msgid "The actor's allocation"
 msgstr "L'allocation de l'acteur"
 
-#: clutter/clutter-actor.c:3809
+#: clutter/clutter-actor.c:3807
 msgid "Request Mode"
 msgstr ""
 
-#: clutter/clutter-actor.c:3810
+#: clutter/clutter-actor.c:3808
 msgid "The actor's request mode"
 msgstr ""
 
-#: clutter/clutter-actor.c:3825
+#: clutter/clutter-actor.c:3823
 msgid "Depth"
 msgstr "Profondeur"
 
-#: clutter/clutter-actor.c:3826
+#: clutter/clutter-actor.c:3824
 msgid "Position on the Z axis"
 msgstr "Position sur l'axe Z"
 
-#: clutter/clutter-actor.c:3840
+#: clutter/clutter-actor.c:3838
 msgid "Opacity"
 msgstr "Opacité"
 
-#: clutter/clutter-actor.c:3841
+#: clutter/clutter-actor.c:3839
 msgid "Opacity of an actor"
 msgstr "Opacité d'un acteur"
 
-#: clutter/clutter-actor.c:3856
+#: clutter/clutter-actor.c:3854
 msgid "Visible"
 msgstr "Visible"
 
-#: clutter/clutter-actor.c:3857
+#: clutter/clutter-actor.c:3855
 msgid "Whether the actor is visible or not"
 msgstr "Si un acteur est visible ou non"
 
-#: clutter/clutter-actor.c:3872
+#: clutter/clutter-actor.c:3870
 msgid "Mapped"
 msgstr ""
 
-#: clutter/clutter-actor.c:3873
+#: clutter/clutter-actor.c:3871
 msgid "Whether the actor will be painted"
 msgstr "Si l'acteur sera peint"
 
-#: clutter/clutter-actor.c:3887
+#: clutter/clutter-actor.c:3885
 msgid "Realized"
 msgstr "Réalisé"
 
-#: clutter/clutter-actor.c:3888
+#: clutter/clutter-actor.c:3886
 msgid "Whether the actor has been realized"
 msgstr "Si l'acteur a été réalisé"
 
-#: clutter/clutter-actor.c:3904
+#: clutter/clutter-actor.c:3902
 msgid "Reactive"
 msgstr "Réactif"
 
-#: clutter/clutter-actor.c:3905
+#: clutter/clutter-actor.c:3903
 msgid "Whether the actor is reactive to events"
 msgstr "Si l'acteur est réactif ou pas"
 
-#: clutter/clutter-actor.c:3917
+#: clutter/clutter-actor.c:3915
 msgid "Has Clip"
 msgstr "A une région de rognage"
 
-#: clutter/clutter-actor.c:3918
+#: clutter/clutter-actor.c:3916
 msgid "Whether the actor has a clip set"
 msgstr "Si l'acteur a une région de rognage ou pas"
 
-#: clutter/clutter-actor.c:3933
+#: clutter/clutter-actor.c:3931
 msgid "Clip"
 msgstr "Rognage"
 
-#: clutter/clutter-actor.c:3934
+#: clutter/clutter-actor.c:3932
 msgid "The clip region for the actor"
 msgstr "Le région de rognage de l'acteur"
 
-#: clutter/clutter-actor.c:3948 clutter/clutter-actor-meta.c:205
-#: clutter/clutter-binding-pool.c:320 clutter/clutter-input-device.c:151
+#: clutter/clutter-actor.c:3946 clutter/clutter-actor-meta.c:205
+#: clutter/clutter-binding-pool.c:319 clutter/clutter-input-device.c:235
 msgid "Name"
 msgstr "Nom"
 
-#: clutter/clutter-actor.c:3949
+#: clutter/clutter-actor.c:3947
 msgid "Name of the actor"
 msgstr "Nom de l'acteur"
 
-#: clutter/clutter-actor.c:3963
+#: clutter/clutter-actor.c:3961
 msgid "Scale X"
 msgstr "Homothétie (X)"
 
-#: clutter/clutter-actor.c:3964
+#: clutter/clutter-actor.c:3962
 msgid "Scale factor on the X axis"
 msgstr "Facteur d'homothétie sur l'axe X"
 
-#: clutter/clutter-actor.c:3979
+#: clutter/clutter-actor.c:3977
 msgid "Scale Y"
 msgstr "Homothétie (Y)"
 
-#: clutter/clutter-actor.c:3980
+#: clutter/clutter-actor.c:3978
 msgid "Scale factor on the Y axis"
 msgstr "Facteur d'homothétie sur l'axe Y"
 
-#: clutter/clutter-actor.c:3995
+#: clutter/clutter-actor.c:3993
 msgid "Scale Center X"
 msgstr "Centre d'homothétie (X)"
 
-#: clutter/clutter-actor.c:3996
+#: clutter/clutter-actor.c:3994
 msgid "Horizontal scale center"
 msgstr ""
 
-#: clutter/clutter-actor.c:4011
+#: clutter/clutter-actor.c:4009
 msgid "Scale Center Y"
 msgstr "Centre d'homothétie (Y)"
 
-#: clutter/clutter-actor.c:4012
+#: clutter/clutter-actor.c:4010
 msgid "Vertical scale center"
 msgstr ""
 
-#: clutter/clutter-actor.c:4027
+#: clutter/clutter-actor.c:4025
 msgid "Scale Gravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4028
+#: clutter/clutter-actor.c:4026
 msgid "The center of scaling"
 msgstr "Le centre d'homothétie"
 
-#: clutter/clutter-actor.c:4045
+#: clutter/clutter-actor.c:4043
 msgid "Rotation Angle X"
 msgstr "Angle de rotation (X)"
 
-#: clutter/clutter-actor.c:4046
+#: clutter/clutter-actor.c:4044
 msgid "The rotation angle on the X axis"
 msgstr "L'angle de rotation autour de l'axe X"
 
-#: clutter/clutter-actor.c:4061
+#: clutter/clutter-actor.c:4059
 msgid "Rotation Angle Y"
 msgstr "Angle de rotation (Y)"
 
-#: clutter/clutter-actor.c:4062
+#: clutter/clutter-actor.c:4060
 msgid "The rotation angle on the Y axis"
 msgstr "L'angle de rotation autour de l'axe Y"
 
-#: clutter/clutter-actor.c:4077
+#: clutter/clutter-actor.c:4075
 msgid "Rotation Angle Z"
 msgstr "Angle de rotation (Z)"
 
-#: clutter/clutter-actor.c:4078
+#: clutter/clutter-actor.c:4076
 msgid "The rotation angle on the Z axis"
 msgstr "L'angle de rotation autour de l'axe Z"
 
-#: clutter/clutter-actor.c:4093
+#: clutter/clutter-actor.c:4091
 msgid "Rotation Center X"
 msgstr "Centre de rotation (X)"
 
-#: clutter/clutter-actor.c:4094
+#: clutter/clutter-actor.c:4092
 msgid "The rotation center on the X axis"
 msgstr "Le centre de rotation sur l'axe X"
 
-#: clutter/clutter-actor.c:4110
+#: clutter/clutter-actor.c:4108
 msgid "Rotation Center Y"
 msgstr "Centre de rotation (Y)"
 
-#: clutter/clutter-actor.c:4111
+#: clutter/clutter-actor.c:4109
 msgid "The rotation center on the Y axis"
 msgstr "Le centre de rotation sur l'axe Y"
 
-#: clutter/clutter-actor.c:4127
+#: clutter/clutter-actor.c:4125
 msgid "Rotation Center Z"
 msgstr "Centre de rotation (Z)"
 
-#: clutter/clutter-actor.c:4128
+#: clutter/clutter-actor.c:4126
 msgid "The rotation center on the Z axis"
 msgstr "Le centre de rotation sur l'axe Y"
 
-#: clutter/clutter-actor.c:4144
+#: clutter/clutter-actor.c:4142
 msgid "Rotation Center Z Gravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4145
+#: clutter/clutter-actor.c:4143
 msgid "Center point for rotation around the Z axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4163
+#: clutter/clutter-actor.c:4161
 msgid "Anchor X"
 msgstr ""
 
-#: clutter/clutter-actor.c:4164
+#: clutter/clutter-actor.c:4162
 msgid "X coordinate of the anchor point"
 msgstr ""
 
-#: clutter/clutter-actor.c:4180
+#: clutter/clutter-actor.c:4178
 msgid "Anchor Y"
 msgstr ""
 
-#: clutter/clutter-actor.c:4181
+#: clutter/clutter-actor.c:4179
 msgid "Y coordinate of the anchor point"
 msgstr ""
 
-#: clutter/clutter-actor.c:4196
+#: clutter/clutter-actor.c:4194
 msgid "Anchor Gravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4197
+#: clutter/clutter-actor.c:4195
 msgid "The anchor point as a ClutterGravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4216
+#: clutter/clutter-actor.c:4214
 msgid "Show on set parent"
 msgstr ""
 
-#: clutter/clutter-actor.c:4217
+#: clutter/clutter-actor.c:4215
 msgid "Whether the actor is shown when parented"
 msgstr ""
 
-#: clutter/clutter-actor.c:4237
+#: clutter/clutter-actor.c:4235
 msgid "Clip to Allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:4238
+#: clutter/clutter-actor.c:4236
 msgid "Sets the clip region to track the actor's allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:4248
+#: clutter/clutter-actor.c:4246
 msgid "Text Direction"
 msgstr "Direction du texte"
 
-#: clutter/clutter-actor.c:4249
+#: clutter/clutter-actor.c:4247
 msgid "Direction of the text"
 msgstr "La direction du texte"
 
-#: clutter/clutter-actor.c:4267
+#: clutter/clutter-actor.c:4265
 msgid "Has Pointer"
 msgstr "Contient pointeur"
 
-#: clutter/clutter-actor.c:4268
+#: clutter/clutter-actor.c:4266
 msgid "Whether the actor contains the pointer of an input device"
 msgstr "Si l'acteur contient le pointer d'un périphérique d'entrée"
 
-#: clutter/clutter-actor.c:4285
+#: clutter/clutter-actor.c:4283
 msgid "Actions"
 msgstr "Actions"
 
-#: clutter/clutter-actor.c:4286
+#: clutter/clutter-actor.c:4284
 msgid "Adds an action to the actor"
 msgstr "Ajoute une action à l'acteur"
 
-#: clutter/clutter-actor.c:4300
+#: clutter/clutter-actor.c:4298
 msgid "Constraints"
 msgstr "Contraintes"
 
-#: clutter/clutter-actor.c:4301
+#: clutter/clutter-actor.c:4299
 msgid "Adds a constraint to the actor"
 msgstr "Ajoute une contrainte à l'acteur"
 
@@ -408,7 +408,8 @@ msgstr "L'acteur attaché au méta"
 msgid "The name of the meta"
 msgstr "Le nom du méta"
 
-#: clutter/clutter-actor-meta.c:219 clutter/clutter-shader.c:261
+#: clutter/clutter-actor-meta.c:219 clutter/clutter-input-device.c:314
+#: clutter/clutter-shader.c:295
 msgid "Enabled"
 msgstr "Activé"
 
@@ -416,34 +417,34 @@ msgstr "Activé"
 msgid "Whether the meta is enabled"
 msgstr "Si le méta est activé"
 
-#: clutter/clutter-align-constraint.c:231
-#: clutter/clutter-bind-constraint.c:286 clutter/clutter-clone.c:322
+#: clutter/clutter-align-constraint.c:252
+#: clutter/clutter-bind-constraint.c:316 clutter/clutter-clone.c:322
 msgid "Source"
 msgstr "Source"
 
-#: clutter/clutter-align-constraint.c:232
+#: clutter/clutter-align-constraint.c:253
 msgid "The source of the alignment"
 msgstr "La source de l'alignement"
 
-#: clutter/clutter-align-constraint.c:245
+#: clutter/clutter-align-constraint.c:266
 msgid "Align Axis"
 msgstr "L'axe d'alignement"
 
-#: clutter/clutter-align-constraint.c:246
+#: clutter/clutter-align-constraint.c:267
 msgid "The axis to align the position to"
 msgstr "L'axe par rapport auquel aligner la position"
 
-#: clutter/clutter-align-constraint.c:265
-#: clutter/clutter-desaturate-effect.c:309
+#: clutter/clutter-align-constraint.c:286
+#: clutter/clutter-desaturate-effect.c:307
 msgid "Factor"
 msgstr "Facteur"
 
-#: clutter/clutter-align-constraint.c:266
+#: clutter/clutter-align-constraint.c:287
 msgid "The alignment factor, between 0.0 and 1.0"
 msgstr "Le facteur d'alignement, entre 0.0 et 1.0"
 
 #: clutter/clutter-alpha.c:339 clutter/clutter-animation.c:523
-#: clutter/clutter-animator.c:1801
+#: clutter/clutter-animator.c:1802
 msgid "Timeline"
 msgstr ""
 
@@ -479,7 +480,7 @@ msgstr "L'object sur lequel l'animation s'applique"
 msgid "The mode of the animation"
 msgstr "Le mode d'animation"
 
-#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1785
+#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1786
 #: clutter/clutter-media.c:194 clutter/clutter-state.c:1282
 msgid "Duration"
 msgstr "Durée"
@@ -500,7 +501,7 @@ msgstr "Si l'animation doit boucler"
 msgid "The timeline used by the animation"
 msgstr ""
 
-#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:299
+#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:298
 msgid "Alpha"
 msgstr "Alpha"
 
@@ -508,215 +509,215 @@ msgstr "Alpha"
 msgid "The alpha used by the animation"
 msgstr "L'alpha utilisé pour l'animation"
 
-#: clutter/clutter-animator.c:1786
+#: clutter/clutter-animator.c:1787
 msgid "The duration of the animation"
 msgstr "La durée de l'animation"
 
-#: clutter/clutter-animator.c:1802
+#: clutter/clutter-animator.c:1803
 msgid "The timeline of the animation"
 msgstr ""
 
-#: clutter/clutter-behaviour.c:300
+#: clutter/clutter-behaviour.c:299
 msgid "Alpha Object to drive the behaviour"
 msgstr "Object alpha a partir duquel dériver le comportement"
 
-#: clutter/clutter-behaviour-depth.c:175
+#: clutter/clutter-behaviour-depth.c:174
 msgid "Start Depth"
 msgstr "Profondeur de départ"
 
-#: clutter/clutter-behaviour-depth.c:176
+#: clutter/clutter-behaviour-depth.c:175
 msgid "Initial depth to apply"
 msgstr "Profondeur initiale à appliquer"
 
-#: clutter/clutter-behaviour-depth.c:191
+#: clutter/clutter-behaviour-depth.c:190
 msgid "End Depth"
 msgstr "Profondeur d'arrivée"
 
-#: clutter/clutter-behaviour-depth.c:192
+#: clutter/clutter-behaviour-depth.c:191
 msgid "Final depth to apply"
 msgstr "Profondeur finale à appliquer"
 
-#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-ellipse.c:394
 msgid "Start Angle"
 msgstr "Angle de départ"
 
-#: clutter/clutter-behaviour-ellipse.c:396
-#: clutter/clutter-behaviour-rotate.c:277
+#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-rotate.c:276
 msgid "Initial angle"
 msgstr "Angle initial"
 
-#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-ellipse.c:410
 msgid "End Angle"
 msgstr "Angle d'arrivée"
 
-#: clutter/clutter-behaviour-ellipse.c:412
-#: clutter/clutter-behaviour-rotate.c:295
+#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-rotate.c:294
 msgid "Final angle"
 msgstr "Angle final"
 
-#: clutter/clutter-behaviour-ellipse.c:427
+#: clutter/clutter-behaviour-ellipse.c:426
 msgid "Angle x tilt"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:428
+#: clutter/clutter-behaviour-ellipse.c:427
 msgid "Tilt of the ellipse around x axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:443
+#: clutter/clutter-behaviour-ellipse.c:442
 msgid "Angle y tilt"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:444
+#: clutter/clutter-behaviour-ellipse.c:443
 msgid "Tilt of the ellipse around y axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:459
+#: clutter/clutter-behaviour-ellipse.c:458
 msgid "Angle z tilt"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:460
+#: clutter/clutter-behaviour-ellipse.c:459
 msgid "Tilt of the ellipse around z axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:476
+#: clutter/clutter-behaviour-ellipse.c:475
 msgid "Width of the ellipse"
 msgstr "Largeur de l'éllipse"
 
-#: clutter/clutter-behaviour-ellipse.c:492
+#: clutter/clutter-behaviour-ellipse.c:491
 msgid "Height of ellipse"
 msgstr "Hauteur de l'éllipse"
 
-#: clutter/clutter-behaviour-ellipse.c:507
+#: clutter/clutter-behaviour-ellipse.c:506
 msgid "Center"
 msgstr "Centre"
 
-#: clutter/clutter-behaviour-ellipse.c:508
+#: clutter/clutter-behaviour-ellipse.c:507
 msgid "Center of ellipse"
 msgstr "Centre de l'éllipse"
 
-#: clutter/clutter-behaviour-ellipse.c:522
-#: clutter/clutter-behaviour-rotate.c:330
+#: clutter/clutter-behaviour-ellipse.c:521
+#: clutter/clutter-behaviour-rotate.c:329
 msgid "Direction"
 msgstr "Direction"
 
-#: clutter/clutter-behaviour-ellipse.c:523
-#: clutter/clutter-behaviour-rotate.c:331
+#: clutter/clutter-behaviour-ellipse.c:522
+#: clutter/clutter-behaviour-rotate.c:330
 msgid "Direction of rotation"
 msgstr "Direction de la rotation"
 
-#: clutter/clutter-behaviour-opacity.c:178
+#: clutter/clutter-behaviour-opacity.c:177
 msgid "Opacity Start"
 msgstr "Opacité de départ"
 
-#: clutter/clutter-behaviour-opacity.c:179
+#: clutter/clutter-behaviour-opacity.c:178
 msgid "Initial opacity level"
 msgstr "Niveau initial d'opacité"
 
-#: clutter/clutter-behaviour-opacity.c:196
+#: clutter/clutter-behaviour-opacity.c:195
 msgid "Opacity End"
 msgstr "Opactité d'arrivée"
 
-#: clutter/clutter-behaviour-opacity.c:197
+#: clutter/clutter-behaviour-opacity.c:196
 msgid "Final opacity level"
 msgstr "Niveau final d'opacité"
 
-#: clutter/clutter-behaviour-path.c:220
+#: clutter/clutter-behaviour-path.c:219
 msgid "Path"
 msgstr "Chemin"
 
-#: clutter/clutter-behaviour-path.c:221
+#: clutter/clutter-behaviour-path.c:220
 msgid "The ClutterPath object representing the path to animate along"
 msgstr "L'objet ClutterPatch qui représente le chemin que l'animation suit"
 
-#: clutter/clutter-behaviour-rotate.c:276
+#: clutter/clutter-behaviour-rotate.c:275
 msgid "Angle Begin"
 msgstr "Angle de départ"
 
-#: clutter/clutter-behaviour-rotate.c:294
+#: clutter/clutter-behaviour-rotate.c:293
 msgid "Angle End"
 msgstr "Angle d'arrivée"
 
-#: clutter/clutter-behaviour-rotate.c:312
+#: clutter/clutter-behaviour-rotate.c:311
 msgid "Axis"
 msgstr "Axe"
 
-#: clutter/clutter-behaviour-rotate.c:313
+#: clutter/clutter-behaviour-rotate.c:312
 msgid "Axis of rotation"
 msgstr "Axe de rotation"
 
-#: clutter/clutter-behaviour-rotate.c:348
+#: clutter/clutter-behaviour-rotate.c:347
 msgid "Center X"
 msgstr "Centre (X)"
 
-#: clutter/clutter-behaviour-rotate.c:349
+#: clutter/clutter-behaviour-rotate.c:348
 msgid "X coordinate of the center of rotation"
 msgstr "Coordonnée X du centre de rotation"
 
-#: clutter/clutter-behaviour-rotate.c:366
+#: clutter/clutter-behaviour-rotate.c:365
 msgid "Center Y"
 msgstr "Centre (Y)"
 
-#: clutter/clutter-behaviour-rotate.c:367
+#: clutter/clutter-behaviour-rotate.c:366
 msgid "Y coordinate of the center of rotation"
 msgstr "Coordonnée Y du centre de rotation"
 
-#: clutter/clutter-behaviour-rotate.c:384
+#: clutter/clutter-behaviour-rotate.c:383
 msgid "Center Z"
 msgstr "Centre (Z)"
 
-#: clutter/clutter-behaviour-rotate.c:385
+#: clutter/clutter-behaviour-rotate.c:384
 msgid "Z coordinate of the center of rotation"
 msgstr "Coordonnée Z du centre de rotation"
 
-#: clutter/clutter-behaviour-scale.c:219
+#: clutter/clutter-behaviour-scale.c:218
 msgid "X Start Scale"
 msgstr "Homothétie (X) de départ"
 
-#: clutter/clutter-behaviour-scale.c:220
+#: clutter/clutter-behaviour-scale.c:219
 msgid "Initial scale on the X axis"
 msgstr "Facteur initial d'homothétie selon l'axe X"
 
-#: clutter/clutter-behaviour-scale.c:238
+#: clutter/clutter-behaviour-scale.c:237
 msgid "X End Scale"
 msgstr "Homothétie (X) de départ"
 
-#: clutter/clutter-behaviour-scale.c:239
+#: clutter/clutter-behaviour-scale.c:238
 msgid "Final scale on the X axis"
 msgstr "Facteur final d'homothétie selon l'axe X"
 
-#: clutter/clutter-behaviour-scale.c:257
+#: clutter/clutter-behaviour-scale.c:256
 msgid "Y Start Scale"
 msgstr "Homothétie (Y) de départ"
 
-#: clutter/clutter-behaviour-scale.c:258
+#: clutter/clutter-behaviour-scale.c:257
 msgid "Initial scale on the Y axis"
 msgstr "Facteur initial d'homothétie selon l'axe Y"
 
-#: clutter/clutter-behaviour-scale.c:276
+#: clutter/clutter-behaviour-scale.c:275
 msgid "Y End Scale"
 msgstr "Homothétie (Y) de départ"
 
-#: clutter/clutter-behaviour-scale.c:277
+#: clutter/clutter-behaviour-scale.c:276
 msgid "Final scale on the Y axis"
 msgstr "Facteur final d'homothétie selon l'axe X"
 
-#: clutter/clutter-bind-constraint.c:287
+#: clutter/clutter-bind-constraint.c:317
 msgid "The source of the binding"
 msgstr "La source du lien"
 
-#: clutter/clutter-bind-constraint.c:300
+#: clutter/clutter-bind-constraint.c:330
 msgid "Coordinate"
 msgstr "Coordonnée"
 
-#: clutter/clutter-bind-constraint.c:301
+#: clutter/clutter-bind-constraint.c:331
 msgid "The coordinate to bind"
 msgstr "La coordonnée à lier"
 
-#: clutter/clutter-bind-constraint.c:315
+#: clutter/clutter-bind-constraint.c:345
 msgid "Offset"
 msgstr "Décalage"
 
-#: clutter/clutter-bind-constraint.c:316
+#: clutter/clutter-bind-constraint.c:346
 msgid "The offset in pixels to apply to the binding"
 msgstr "Le décalage, en pixels, à appliquer au lien"
 
@@ -748,7 +749,7 @@ msgstr ""
 msgid "Default vertical alignment for the actors inside the layout manager"
 msgstr ""
 
-#: clutter/clutter-binding-pool.c:321
+#: clutter/clutter-binding-pool.c:320
 msgid "The unique name of the binding pool"
 msgstr ""
 
@@ -761,7 +762,7 @@ msgid "The layout manager used by the box"
 msgstr ""
 
 #: clutter/clutter-box.c:514 clutter/clutter-rectangle.c:258
-#: clutter/clutter-stage.c:1307
+#: clutter/clutter-stage.c:1317
 msgid "Color"
 msgstr "Couleur"
 
@@ -902,19 +903,19 @@ msgstr "Le conteneur qui a créé cette donnée"
 msgid "The actor wrapped by this data"
 msgstr ""
 
-#: clutter/clutter-click-action.c:283
+#: clutter/clutter-click-action.c:302
 msgid "Pressed"
 msgstr ""
 
-#: clutter/clutter-click-action.c:284
+#: clutter/clutter-click-action.c:303
 msgid "Whether the clickable should be in pressed state"
 msgstr ""
 
-#: clutter/clutter-click-action.c:297
+#: clutter/clutter-click-action.c:316
 msgid "Held"
 msgstr ""
 
-#: clutter/clutter-click-action.c:298
+#: clutter/clutter-click-action.c:317
 msgid "Whether the clickable has a grab"
 msgstr ""
 
@@ -922,11 +923,11 @@ msgstr ""
 msgid "Specifies the actor to be cloned"
 msgstr ""
 
-#: clutter/clutter-colorize-effect.c:309
+#: clutter/clutter-colorize-effect.c:307
 msgid "Tint"
 msgstr "Teinte"
 
-#: clutter/clutter-colorize-effect.c:310
+#: clutter/clutter-colorize-effect.c:308
 msgid "The tint to apply"
 msgstr "La teinte à appliquer"
 
@@ -955,11 +956,11 @@ msgstr ""
 msgid "The material to be used when painting the back of the actor"
 msgstr ""
 
-#: clutter/clutter-desaturate-effect.c:310
+#: clutter/clutter-desaturate-effect.c:308
 msgid "The desaturation factor"
 msgstr ""
 
-#: clutter/clutter-device-manager.c:130
+#: clutter/clutter-device-manager.c:130 clutter/clutter-input-device.c:343
 msgid "Backend"
 msgstr ""
 
@@ -967,35 +968,35 @@ msgstr ""
 msgid "The ClutterBackend of the device manager"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:490
+#: clutter/clutter-drag-action.c:491
 msgid "Horizontal Drag Threshold"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:491
+#: clutter/clutter-drag-action.c:492
 msgid "The horizontal amount of pixels required to start dragging"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:510
+#: clutter/clutter-drag-action.c:511
 msgid "Vertical Drag Threshold"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:511
+#: clutter/clutter-drag-action.c:512
 msgid "The vertical amount of pixels required to start dragging"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:532
+#: clutter/clutter-drag-action.c:533
 msgid "Drag Handle"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:533
+#: clutter/clutter-drag-action.c:534
 msgid "The actor that is being dragged"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:546
+#: clutter/clutter-drag-action.c:547
 msgid "Drag Axis"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:547
+#: clutter/clutter-drag-action.c:548
 msgid "Constraints the dragging to an axis"
 msgstr ""
 
@@ -1059,26 +1060,72 @@ msgstr ""
 msgid "Maximum height for each row"
 msgstr ""
 
-#: clutter/clutter-input-device.c:134
+#: clutter/clutter-input-device.c:219
 msgid "Id"
 msgstr ""
 
-#: clutter/clutter-input-device.c:135
+#: clutter/clutter-input-device.c:220
 msgid "Unique identifier of the device"
 msgstr ""
 
-#: clutter/clutter-input-device.c:152
+#: clutter/clutter-input-device.c:236
 msgid "The name of the device"
 msgstr "Le nom du périphérique"
 
-#: clutter/clutter-input-device.c:167
+#: clutter/clutter-input-device.c:250
 msgid "Device Type"
 msgstr "Type de périphérique"
 
-#: clutter/clutter-input-device.c:168
+#: clutter/clutter-input-device.c:251
 msgid "The type of the device"
 msgstr "Le type du  périphérique"
 
+#: clutter/clutter-input-device.c:266
+#, fuzzy
+msgid "Device Manager"
+msgstr "Gestionnaire"
+
+#: clutter/clutter-input-device.c:267
+msgid "The device manager instance"
+msgstr ""
+
+#: clutter/clutter-input-device.c:280
+#, fuzzy
+msgid "Device Mode"
+msgstr "Type de périphérique"
+
+#: clutter/clutter-input-device.c:281
+#, fuzzy
+msgid "The mode of the device"
+msgstr "Le nom du périphérique"
+
+#: clutter/clutter-input-device.c:295
+msgid "Has Cursor"
+msgstr ""
+
+#: clutter/clutter-input-device.c:296
+#, fuzzy
+msgid "Whether the device has a cursor"
+msgstr "Si l'acteur a une région de rognage ou pas"
+
+#: clutter/clutter-input-device.c:315
+#, fuzzy
+msgid "Whether the device is enabled"
+msgstr "Si le méta est activé"
+
+#: clutter/clutter-input-device.c:328
+msgid "Number of Axes"
+msgstr ""
+
+#: clutter/clutter-input-device.c:329
+#, fuzzy
+msgid "The number of axes on the device"
+msgstr "Le nom du périphérique"
+
+#: clutter/clutter-input-device.c:344
+msgid "The backend instance"
+msgstr ""
+
 #: clutter/clutter-interval.c:397
 msgid "Value Type"
 msgstr "Type de valeur"
@@ -1095,59 +1142,59 @@ msgstr "Gestionnaire"
 msgid "The manager that created this data"
 msgstr "Le gestionnaire qui a créé ces données"
 
-#: clutter/clutter-main.c:756
+#: clutter/clutter-main.c:753
 msgid "default:LTR"
 msgstr "default:LTR"
 
-#: clutter/clutter-main.c:1560
+#: clutter/clutter-main.c:1557
 msgid "Show frames per second"
 msgstr ""
 
-#: clutter/clutter-main.c:1562
+#: clutter/clutter-main.c:1559
 msgid "Default frame rate"
 msgstr ""
 
-#: clutter/clutter-main.c:1564
+#: clutter/clutter-main.c:1561
 msgid "Make all warnings fatal"
 msgstr ""
 
-#: clutter/clutter-main.c:1567
+#: clutter/clutter-main.c:1564
 msgid "Direction for the text"
 msgstr ""
 
-#: clutter/clutter-main.c:1570
+#: clutter/clutter-main.c:1567
 msgid "Disable mipmapping on text"
 msgstr ""
 
-#: clutter/clutter-main.c:1573
+#: clutter/clutter-main.c:1570
 msgid "Use 'fuzzy' picking"
 msgstr ""
 
-#: clutter/clutter-main.c:1576
+#: clutter/clutter-main.c:1573
 msgid "Clutter debugging flags to set"
 msgstr ""
 
-#: clutter/clutter-main.c:1578
+#: clutter/clutter-main.c:1575
 msgid "Clutter debugging flags to unset"
 msgstr ""
 
-#: clutter/clutter-main.c:1582
+#: clutter/clutter-main.c:1579
 msgid "Clutter profiling flags to set"
 msgstr ""
 
-#: clutter/clutter-main.c:1584
+#: clutter/clutter-main.c:1581
 msgid "Clutter profiling flags to unset"
 msgstr ""
 
-#: clutter/clutter-main.c:1587
+#: clutter/clutter-main.c:1584
 msgid "Enable accessibility"
 msgstr ""
 
-#: clutter/clutter-main.c:1774
+#: clutter/clutter-main.c:1771
 msgid "Clutter Options"
 msgstr ""
 
-#: clutter/clutter-main.c:1775
+#: clutter/clutter-main.c:1772
 msgid "Show Clutter Options"
 msgstr ""
 
@@ -1263,44 +1310,44 @@ msgstr "Nom de fichier"
 msgid "The path of the currently parsed file"
 msgstr ""
 
-#: clutter/clutter-shader.c:215
+#: clutter/clutter-shader.c:249
 msgid "Vertex Source"
 msgstr ""
 
-#: clutter/clutter-shader.c:216
+#: clutter/clutter-shader.c:250
 msgid "Source of vertex shader"
 msgstr ""
 
-#: clutter/clutter-shader.c:230
+#: clutter/clutter-shader.c:264
 msgid "Fragment Source"
 msgstr ""
 
-#: clutter/clutter-shader.c:231
+#: clutter/clutter-shader.c:265
 msgid "Source of fragment shader"
 msgstr ""
 
-#: clutter/clutter-shader.c:246
+#: clutter/clutter-shader.c:280
 msgid "Compiled"
 msgstr ""
 
-#: clutter/clutter-shader.c:247
+#: clutter/clutter-shader.c:281
 msgid "Whether the shader is compiled and linked"
 msgstr ""
 
-#: clutter/clutter-shader.c:262
+#: clutter/clutter-shader.c:296
 msgid "Whether the shader is enabled"
 msgstr ""
 
-#: clutter/clutter-shader.c:467
+#: clutter/clutter-shader.c:501
 #, c-format
 msgid "%s compilation failed: %s"
 msgstr ""
 
-#: clutter/clutter-shader.c:468
+#: clutter/clutter-shader.c:502
 msgid "Vertex shader"
 msgstr ""
 
-#: clutter/clutter-shader.c:469
+#: clutter/clutter-shader.c:503
 msgid "Fragment shader"
 msgstr ""
 
@@ -1312,98 +1359,107 @@ msgstr ""
 msgid "The type of shader used"
 msgstr ""
 
-#: clutter/clutter-stage.c:1249
+#: clutter/clutter-stage.c:1259
 msgid "Fullscreen Set"
 msgstr ""
 
-#: clutter/clutter-stage.c:1250
+#: clutter/clutter-stage.c:1260
 msgid "Whether the main stage is fullscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1266
+#: clutter/clutter-stage.c:1276
 msgid "Offscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1267
+#: clutter/clutter-stage.c:1277
 msgid "Whether the main stage should be rendered offscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1279 clutter/clutter-text.c:2643
+#: clutter/clutter-stage.c:1289 clutter/clutter-text.c:2667
 msgid "Cursor Visible"
 msgstr ""
 
-#: clutter/clutter-stage.c:1280
+#: clutter/clutter-stage.c:1290
 msgid "Whether the mouse pointer is visible on the main stage"
 msgstr ""
 
-#: clutter/clutter-stage.c:1294
+#: clutter/clutter-stage.c:1304
 msgid "User Resizable"
 msgstr ""
 
-#: clutter/clutter-stage.c:1295
+#: clutter/clutter-stage.c:1305
 msgid "Whether the stage is able to be resized via user interaction"
 msgstr ""
 
-#: clutter/clutter-stage.c:1308
+#: clutter/clutter-stage.c:1318
 msgid "The color of the stage"
 msgstr ""
 
-#: clutter/clutter-stage.c:1322
+#: clutter/clutter-stage.c:1332
 msgid "Perspective"
 msgstr ""
 
-#: clutter/clutter-stage.c:1323
+#: clutter/clutter-stage.c:1333
 msgid "Perspective projection parameters"
 msgstr ""
 
-#: clutter/clutter-stage.c:1338
+#: clutter/clutter-stage.c:1348
 msgid "Title"
 msgstr ""
 
-#: clutter/clutter-stage.c:1339
+#: clutter/clutter-stage.c:1349
 msgid "Stage Title"
 msgstr "Titre de la scène"
 
-#: clutter/clutter-stage.c:1354
+#: clutter/clutter-stage.c:1364
 msgid "Use Fog"
 msgstr "Utilise le brouillard"
 
-#: clutter/clutter-stage.c:1355
+#: clutter/clutter-stage.c:1365
 msgid "Whether to enable depth cueing"
 msgstr ""
 
-#: clutter/clutter-stage.c:1369
+#: clutter/clutter-stage.c:1379
 msgid "Fog"
 msgstr "Brouillard"
 
-#: clutter/clutter-stage.c:1370
+#: clutter/clutter-stage.c:1380
 msgid "Settings for the depth cueing"
 msgstr ""
 
-#: clutter/clutter-stage.c:1386
+#: clutter/clutter-stage.c:1396
 msgid "Use Alpha"
 msgstr ""
 
-#: clutter/clutter-stage.c:1387
+#: clutter/clutter-stage.c:1397
 msgid "Whether to honour the alpha component of the stage color"
 msgstr ""
 
-#: clutter/clutter-stage.c:1403
+#: clutter/clutter-stage.c:1413
 msgid "Key Focus"
 msgstr ""
 
-#: clutter/clutter-stage.c:1404
+#: clutter/clutter-stage.c:1414
 msgid "The currently key focused actor"
 msgstr ""
 
-#: clutter/clutter-stage.c:1420
+#: clutter/clutter-stage.c:1430
 msgid "No Clear Hint"
 msgstr ""
 
-#: clutter/clutter-stage.c:1421
+#: clutter/clutter-stage.c:1431
 msgid "Whether the stage should clear its contents"
 msgstr ""
 
+#: clutter/clutter-stage.c:1444
+msgid "Accept Focus"
+msgstr ""
+
+#: clutter/clutter-stage.c:1445
+#, fuzzy
+msgid "Whether the stage should accept focus on show"
+msgstr "Si le texte doit être affiché en une seule ligne ou non"
+
 #: clutter/clutter-state.c:1268
 msgid "State"
 msgstr "État"
@@ -1416,192 +1472,192 @@ msgstr ""
 msgid "Default transition duration"
 msgstr ""
 
-#: clutter/clutter-text.c:2530
+#: clutter/clutter-text.c:2554
 msgid "Font Name"
 msgstr "Nom de la police"
 
-#: clutter/clutter-text.c:2531
+#: clutter/clutter-text.c:2555
 msgid "The font to be used by the text"
 msgstr "La police à utiliser par le texte"
 
-#: clutter/clutter-text.c:2548
+#: clutter/clutter-text.c:2572
 msgid "Font Description"
 msgstr "Description de la police"
 
-#: clutter/clutter-text.c:2549
+#: clutter/clutter-text.c:2573
 msgid "The font description to be used"
 msgstr "La description de la police à utiliser"
 
-#: clutter/clutter-text.c:2565
+#: clutter/clutter-text.c:2589
 msgid "Text"
 msgstr "Texte"
 
-#: clutter/clutter-text.c:2566
+#: clutter/clutter-text.c:2590
 msgid "The text to render"
 msgstr "Le texte à afficher"
 
-#: clutter/clutter-text.c:2580
+#: clutter/clutter-text.c:2604
 msgid "Font Color"
 msgstr "Couleur de la police"
 
-#: clutter/clutter-text.c:2581
+#: clutter/clutter-text.c:2605
 msgid "Color of the font used by the text"
 msgstr "La Couleur de la police utilisée par le texte"
 
-#: clutter/clutter-text.c:2595
+#: clutter/clutter-text.c:2619
 msgid "Editable"
 msgstr "Éditable"
 
-#: clutter/clutter-text.c:2596
+#: clutter/clutter-text.c:2620
 msgid "Whether the text is editable"
 msgstr ""
 
-#: clutter/clutter-text.c:2611
+#: clutter/clutter-text.c:2635
 msgid "Selectable"
 msgstr ""
 
-#: clutter/clutter-text.c:2612
+#: clutter/clutter-text.c:2636
 msgid "Whether the text is selectable"
 msgstr ""
 
-#: clutter/clutter-text.c:2626
+#: clutter/clutter-text.c:2650
 msgid "Activatable"
 msgstr ""
 
-#: clutter/clutter-text.c:2627
+#: clutter/clutter-text.c:2651
 msgid "Whether pressing return causes the activate signal to be emitted"
 msgstr ""
 
-#: clutter/clutter-text.c:2644
+#: clutter/clutter-text.c:2668
 msgid "Whether the input cursor is visible"
 msgstr ""
 
-#: clutter/clutter-text.c:2658 clutter/clutter-text.c:2659
+#: clutter/clutter-text.c:2682 clutter/clutter-text.c:2683
 msgid "Cursor Color"
 msgstr "La couleur du curseur"
 
-#: clutter/clutter-text.c:2673
+#: clutter/clutter-text.c:2697
 msgid "Cursor Color Set"
 msgstr "Couleur du curseur renseignée"
 
-#: clutter/clutter-text.c:2674
+#: clutter/clutter-text.c:2698
 msgid "Whether the cursor color has been set"
 msgstr "Si la couleur du curseur a été renseignée ou non"
 
-#: clutter/clutter-text.c:2689
+#: clutter/clutter-text.c:2713
 msgid "Cursor Size"
 msgstr "Taille du curseur"
 
-#: clutter/clutter-text.c:2690
+#: clutter/clutter-text.c:2714
 msgid "The width of the cursor, in pixels"
 msgstr "La taille du curseur, en pixels"
 
-#: clutter/clutter-text.c:2704
+#: clutter/clutter-text.c:2728
 #, fuzzy
 msgid "Cursor Position"
 msgstr "La position du curseur"
 
-#: clutter/clutter-text.c:2705
+#: clutter/clutter-text.c:2729
 msgid "The cursor position"
 msgstr "La position du curseur"
 
-#: clutter/clutter-text.c:2720
+#: clutter/clutter-text.c:2744
 msgid "Selection-bound"
 msgstr ""
 
-#: clutter/clutter-text.c:2721
+#: clutter/clutter-text.c:2745
 msgid "The cursor position of the other end of the selection"
 msgstr ""
 
-#: clutter/clutter-text.c:2736 clutter/clutter-text.c:2737
+#: clutter/clutter-text.c:2760 clutter/clutter-text.c:2761
 msgid "Selection Color"
 msgstr ""
 
-#: clutter/clutter-text.c:2751
+#: clutter/clutter-text.c:2775
 msgid "Selection Color Set"
 msgstr ""
 
-#: clutter/clutter-text.c:2752
+#: clutter/clutter-text.c:2776
 msgid "Whether the selection color has been set"
 msgstr ""
 
-#: clutter/clutter-text.c:2767
+#: clutter/clutter-text.c:2791
 msgid "Attributes"
 msgstr ""
 
-#: clutter/clutter-text.c:2768
+#: clutter/clutter-text.c:2792
 msgid "A list of style attributes to apply to the contents of the actor"
 msgstr ""
 
-#: clutter/clutter-text.c:2790
+#: clutter/clutter-text.c:2814
 msgid "Use markup"
 msgstr ""
 
-#: clutter/clutter-text.c:2791
+#: clutter/clutter-text.c:2815
 msgid "Whether or not the text includes Pango markup"
 msgstr ""
 
-#: clutter/clutter-text.c:2807
+#: clutter/clutter-text.c:2831
 msgid "Line wrap"
 msgstr ""
 
-#: clutter/clutter-text.c:2808
+#: clutter/clutter-text.c:2832
 msgid "If set, wrap the lines if the text becomes too wide"
 msgstr ""
 
-#: clutter/clutter-text.c:2823
+#: clutter/clutter-text.c:2847
 msgid "Line wrap mode"
 msgstr ""
 
-#: clutter/clutter-text.c:2824
+#: clutter/clutter-text.c:2848
 msgid "Control how line-wrapping is done"
 msgstr ""
 
-#: clutter/clutter-text.c:2839
+#: clutter/clutter-text.c:2863
 msgid "Ellipsize"
 msgstr ""
 
-#: clutter/clutter-text.c:2840
+#: clutter/clutter-text.c:2864
 msgid "The preferred place to ellipsize the string"
 msgstr ""
 
-#: clutter/clutter-text.c:2856
+#: clutter/clutter-text.c:2880
 msgid "Line Alignment"
 msgstr ""
 
-#: clutter/clutter-text.c:2857
+#: clutter/clutter-text.c:2881
 msgid "The preferred alignment for the string, for multi-line text"
 msgstr ""
 
-#: clutter/clutter-text.c:2873
+#: clutter/clutter-text.c:2897
 msgid "Justify"
 msgstr ""
 
-#: clutter/clutter-text.c:2874
+#: clutter/clutter-text.c:2898
 msgid "Whether the text should be justified"
 msgstr ""
 
-#: clutter/clutter-text.c:2889
+#: clutter/clutter-text.c:2913
 msgid "Password Character"
 msgstr ""
 
-#: clutter/clutter-text.c:2890
+#: clutter/clutter-text.c:2914
 msgid "If non-zero, use this character to display the actor's contents"
 msgstr ""
 
-#: clutter/clutter-text.c:2904
+#: clutter/clutter-text.c:2928
 msgid "Max Length"
 msgstr "Longueur maximale"
 
-#: clutter/clutter-text.c:2905
+#: clutter/clutter-text.c:2929
 msgid "Maximum length of the text inside the actor"
 msgstr "Longueur maximale du texte à l'intérieur de l'acteur"
 
-#: clutter/clutter-text.c:2928
+#: clutter/clutter-text.c:2952
 msgid "Single Line Mode"
 msgstr "Mode ligne"
 
-#: clutter/clutter-text.c:2929
+#: clutter/clutter-text.c:2953
 msgid "Whether the text should be a single line"
 msgstr "Si le texte doit être affiché en une seule ligne ou non"
 
@@ -1726,23 +1782,23 @@ msgstr ""
 msgid "Shape actor with alpha channel when picking"
 msgstr ""
 
-#: clutter/glx/clutter-backend-glx.c:128
+#: clutter/glx/clutter-backend-glx.c:131
 msgid "VBlank method to be used (none, dri or glx)"
 msgstr ""
 
-#: clutter/x11/clutter-backend-x11.c:364
+#: clutter/x11/clutter-backend-x11.c:473
 msgid "X display to use"
 msgstr "Affichage X à utiliser"
 
-#: clutter/x11/clutter-backend-x11.c:370
+#: clutter/x11/clutter-backend-x11.c:479
 msgid "X screen to use"
 msgstr "Écran X à utiliser"
 
-#: clutter/x11/clutter-backend-x11.c:375
+#: clutter/x11/clutter-backend-x11.c:484
 msgid "Make X calls synchronous"
 msgstr "Rendre les appels X synchrones"
 
-#: clutter/x11/clutter-backend-x11.c:382
+#: clutter/x11/clutter-backend-x11.c:491
 msgid "Enable XInput support"
 msgstr "Activer le support XInput"
 
index acc5783..5d8315f 100644 (file)
--- a/po/id.po
+++ b/po/id.po
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: clutter 1.3.14\n"
 "Report-Msgid-Bugs-To: http://bugzilla.clutter-project.org/enter_bug.cgi?"
 "product=clutter\n"
-"POT-Creation-Date: 2010-12-17 15:51+0000\n"
+"POT-Creation-Date: 2011-02-07 15:50+0000\n"
 "PO-Revision-Date: 2010-10-05 20:42+0700\n"
 "Last-Translator: Andika Triwidada <andika@gmail.com>\n"
 "Language-Team: GNOME Indonesian Translation Team <gnome@i15n.org>\n"
@@ -20,381 +20,381 @@ msgstr ""
 "X-Poedit-Language: Indonesian\n"
 "X-Poedit-Country: Indonesia\n"
 
-#: clutter/clutter-actor.c:3480
+#: clutter/clutter-actor.c:3478
 msgid "X coordinate"
 msgstr "Koordinat X"
 
-#: clutter/clutter-actor.c:3481
+#: clutter/clutter-actor.c:3479
 msgid "X coordinate of the actor"
 msgstr "Koordinat X dari aktor"
 
-#: clutter/clutter-actor.c:3496
+#: clutter/clutter-actor.c:3494
 msgid "Y coordinate"
 msgstr "Koordinat Y"
 
-#: clutter/clutter-actor.c:3497
+#: clutter/clutter-actor.c:3495
 msgid "Y coordinate of the actor"
 msgstr "Koordinat Y dari aktor"
 
-#: clutter/clutter-actor.c:3512 clutter/clutter-behaviour-ellipse.c:475
+#: clutter/clutter-actor.c:3510 clutter/clutter-behaviour-ellipse.c:474
 msgid "Width"
 msgstr "Lebar"
 
-#: clutter/clutter-actor.c:3513
+#: clutter/clutter-actor.c:3511
 msgid "Width of the actor"
 msgstr "Lebar aktor"
 
-#: clutter/clutter-actor.c:3527 clutter/clutter-behaviour-ellipse.c:491
+#: clutter/clutter-actor.c:3525 clutter/clutter-behaviour-ellipse.c:490
 msgid "Height"
 msgstr "Tinggi"
 
-#: clutter/clutter-actor.c:3528
+#: clutter/clutter-actor.c:3526
 msgid "Height of the actor"
 msgstr "Tinggi aktor"
 
-#: clutter/clutter-actor.c:3546
+#: clutter/clutter-actor.c:3544
 msgid "Fixed X"
 msgstr "X Tetap"
 
-#: clutter/clutter-actor.c:3547
+#: clutter/clutter-actor.c:3545
 msgid "Forced X position of the actor"
 msgstr "Posisi X aktor yang dipaksakan"
 
-#: clutter/clutter-actor.c:3565
+#: clutter/clutter-actor.c:3563
 msgid "Fixed Y"
 msgstr "Y Tetap"
 
-#: clutter/clutter-actor.c:3566
+#: clutter/clutter-actor.c:3564
 msgid "Forced Y position of the actor"
 msgstr "Posisi Y aktor yang dipaksakan"
 
-#: clutter/clutter-actor.c:3582
+#: clutter/clutter-actor.c:3580
 msgid "Fixed position set"
 msgstr "Posisi yang ditetapkan ditata"
 
-#: clutter/clutter-actor.c:3583
+#: clutter/clutter-actor.c:3581
 msgid "Whether to use fixed positioning for the actor"
 msgstr "Apakah memakai penempatan yang ditetapkan bagi aktor"
 
-#: clutter/clutter-actor.c:3605
+#: clutter/clutter-actor.c:3603
 msgid "Min Width"
 msgstr "Lebar Min"
 
-#: clutter/clutter-actor.c:3606
+#: clutter/clutter-actor.c:3604
 msgid "Forced minimum width request for the actor"
 msgstr "Permintaan lebar minimal yang dipaksakan bagi aktor"
 
-#: clutter/clutter-actor.c:3625
+#: clutter/clutter-actor.c:3623
 msgid "Min Height"
 msgstr "Tinggi Min"
 
-#: clutter/clutter-actor.c:3626
+#: clutter/clutter-actor.c:3624
 msgid "Forced minimum height request for the actor"
 msgstr "Permintaan tinggi minimal yang dipaksakan bagi aktor"
 
-#: clutter/clutter-actor.c:3645
+#: clutter/clutter-actor.c:3643
 msgid "Natural Width"
 msgstr "Lebar Alami"
 
-#: clutter/clutter-actor.c:3646
+#: clutter/clutter-actor.c:3644
 msgid "Forced natural width request for the actor"
 msgstr "Permintaan lebar alami yang dipaksakan bagi aktor"
 
-#: clutter/clutter-actor.c:3665
+#: clutter/clutter-actor.c:3663
 msgid "Natural Height"
 msgstr "Tinggi Alami"
 
-#: clutter/clutter-actor.c:3666
+#: clutter/clutter-actor.c:3664
 msgid "Forced natural height request for the actor"
 msgstr "Permintaan tinggi alami yang dipaksakan bagi aktor"
 
-#: clutter/clutter-actor.c:3682
+#: clutter/clutter-actor.c:3680
 msgid "Minimum width set"
 msgstr "Lebar minimal ditata"
 
-#: clutter/clutter-actor.c:3683
+#: clutter/clutter-actor.c:3681
 msgid "Whether to use the min-width property"
 msgstr "Apakah memakai properti min-width"
 
-#: clutter/clutter-actor.c:3698
+#: clutter/clutter-actor.c:3696
 msgid "Minimum height set"
 msgstr "Tinggi minimal ditata"
 
-#: clutter/clutter-actor.c:3699
+#: clutter/clutter-actor.c:3697
 msgid "Whether to use the min-height property"
 msgstr "Apakah memakai properti min-height"
 
-#: clutter/clutter-actor.c:3714
+#: clutter/clutter-actor.c:3712
 msgid "Natural width set"
 msgstr "Lebar alami ditata"
 
-#: clutter/clutter-actor.c:3715
+#: clutter/clutter-actor.c:3713
 msgid "Whether to use the natural-width property"
 msgstr "Apakah memakai properti natural-width"
 
-#: clutter/clutter-actor.c:3732
+#: clutter/clutter-actor.c:3730
 msgid "Natural height set"
 msgstr "Tinggi alami ditata"
 
-#: clutter/clutter-actor.c:3733
+#: clutter/clutter-actor.c:3731
 msgid "Whether to use the natural-height property"
 msgstr "Apakah memakai properti natural-height"
 
-#: clutter/clutter-actor.c:3752
+#: clutter/clutter-actor.c:3750
 msgid "Allocation"
 msgstr "Alokasi"
 
-#: clutter/clutter-actor.c:3753
+#: clutter/clutter-actor.c:3751
 msgid "The actor's allocation"
 msgstr "Alokasi aktor"
 
-#: clutter/clutter-actor.c:3809
+#: clutter/clutter-actor.c:3807
 msgid "Request Mode"
 msgstr "Moda Permintaan"
 
-#: clutter/clutter-actor.c:3810
+#: clutter/clutter-actor.c:3808
 msgid "The actor's request mode"
 msgstr "Moda permintaan aktor"
 
-#: clutter/clutter-actor.c:3825
+#: clutter/clutter-actor.c:3823
 msgid "Depth"
 msgstr "Kedalaman"
 
-#: clutter/clutter-actor.c:3826
+#: clutter/clutter-actor.c:3824
 msgid "Position on the Z axis"
 msgstr "Posisi pada sumbu Z"
 
-#: clutter/clutter-actor.c:3840
+#: clutter/clutter-actor.c:3838
 #, fuzzy
 msgid "Opacity"
 msgstr "Ketransparanan"
 
-#: clutter/clutter-actor.c:3841
+#: clutter/clutter-actor.c:3839
 msgid "Opacity of an actor"
 msgstr "Tingkat transparansi aktor"
 
-#: clutter/clutter-actor.c:3856
+#: clutter/clutter-actor.c:3854
 msgid "Visible"
 msgstr "Tampak"
 
-#: clutter/clutter-actor.c:3857
+#: clutter/clutter-actor.c:3855
 msgid "Whether the actor is visible or not"
 msgstr "Apakah aktor nampak atau tidak"
 
-#: clutter/clutter-actor.c:3872
+#: clutter/clutter-actor.c:3870
 msgid "Mapped"
 msgstr "Dipetakan"
 
-#: clutter/clutter-actor.c:3873
+#: clutter/clutter-actor.c:3871
 msgid "Whether the actor will be painted"
 msgstr "Apakah aktor akan digambar"
 
-#: clutter/clutter-actor.c:3887
+#: clutter/clutter-actor.c:3885
 msgid "Realized"
 msgstr "Direalisasikan"
 
-#: clutter/clutter-actor.c:3888
+#: clutter/clutter-actor.c:3886
 msgid "Whether the actor has been realized"
 msgstr "Apakah aktor telah direalisasikan"
 
-#: clutter/clutter-actor.c:3904
+#: clutter/clutter-actor.c:3902
 msgid "Reactive"
 msgstr "Reaktif"
 
-#: clutter/clutter-actor.c:3905
+#: clutter/clutter-actor.c:3903
 msgid "Whether the actor is reactive to events"
 msgstr "Apakah aktor reaktif terhadap kejadian"
 
-#: clutter/clutter-actor.c:3917
+#: clutter/clutter-actor.c:3915
 msgid "Has Clip"
 msgstr "Punya Klip"
 
-#: clutter/clutter-actor.c:3918
+#: clutter/clutter-actor.c:3916
 msgid "Whether the actor has a clip set"
 msgstr "Apakah aktor telah ditata punya klip"
 
-#: clutter/clutter-actor.c:3933
+#: clutter/clutter-actor.c:3931
 msgid "Clip"
 msgstr "Klip"
 
-#: clutter/clutter-actor.c:3934
+#: clutter/clutter-actor.c:3932
 msgid "The clip region for the actor"
 msgstr "Wilayah klip bagi aktor"
 
-#: clutter/clutter-actor.c:3948 clutter/clutter-actor-meta.c:205
-#: clutter/clutter-binding-pool.c:320 clutter/clutter-input-device.c:151
+#: clutter/clutter-actor.c:3946 clutter/clutter-actor-meta.c:205
+#: clutter/clutter-binding-pool.c:319 clutter/clutter-input-device.c:235
 msgid "Name"
 msgstr "Nama"
 
-#: clutter/clutter-actor.c:3949
+#: clutter/clutter-actor.c:3947
 msgid "Name of the actor"
 msgstr "Nama aktor"
 
-#: clutter/clutter-actor.c:3963
+#: clutter/clutter-actor.c:3961
 msgid "Scale X"
 msgstr "Skala X"
 
-#: clutter/clutter-actor.c:3964
+#: clutter/clutter-actor.c:3962
 msgid "Scale factor on the X axis"
 msgstr "Faktor skala pada sumbu X"
 
-#: clutter/clutter-actor.c:3979
+#: clutter/clutter-actor.c:3977
 msgid "Scale Y"
 msgstr "Skala Y"
 
-#: clutter/clutter-actor.c:3980
+#: clutter/clutter-actor.c:3978
 msgid "Scale factor on the Y axis"
 msgstr "Faktor skala pada sumbu Y"
 
-#: clutter/clutter-actor.c:3995
+#: clutter/clutter-actor.c:3993
 msgid "Scale Center X"
 msgstr "Pusat Skala X"
 
-#: clutter/clutter-actor.c:3996
+#: clutter/clutter-actor.c:3994
 msgid "Horizontal scale center"
 msgstr "Pusat skala horisontal"
 
-#: clutter/clutter-actor.c:4011
+#: clutter/clutter-actor.c:4009
 msgid "Scale Center Y"
 msgstr "Pusat Skala Y"
 
-#: clutter/clutter-actor.c:4012
+#: clutter/clutter-actor.c:4010
 msgid "Vertical scale center"
 msgstr "Pusat skala vertikal"
 
-#: clutter/clutter-actor.c:4027
+#: clutter/clutter-actor.c:4025
 msgid "Scale Gravity"
 msgstr "Gravitasi Skala"
 
-#: clutter/clutter-actor.c:4028
+#: clutter/clutter-actor.c:4026
 msgid "The center of scaling"
 msgstr "Pusat penskalaan"
 
-#: clutter/clutter-actor.c:4045
+#: clutter/clutter-actor.c:4043
 msgid "Rotation Angle X"
 msgstr "Sudut Rotasi X"
 
-#: clutter/clutter-actor.c:4046
+#: clutter/clutter-actor.c:4044
 msgid "The rotation angle on the X axis"
 msgstr "Sudut rotasi dari sumbu X"
 
-#: clutter/clutter-actor.c:4061
+#: clutter/clutter-actor.c:4059
 msgid "Rotation Angle Y"
 msgstr "Sudut Rotasi Y"
 
-#: clutter/clutter-actor.c:4062
+#: clutter/clutter-actor.c:4060
 msgid "The rotation angle on the Y axis"
 msgstr "Sudut rotasi dari sumbu Y"
 
-#: clutter/clutter-actor.c:4077
+#: clutter/clutter-actor.c:4075
 msgid "Rotation Angle Z"
 msgstr "Sudut Rotasi Z"
 
-#: clutter/clutter-actor.c:4078
+#: clutter/clutter-actor.c:4076
 msgid "The rotation angle on the Z axis"
 msgstr "Sudut rotasi dari sumbu Z"
 
-#: clutter/clutter-actor.c:4093
+#: clutter/clutter-actor.c:4091
 msgid "Rotation Center X"
 msgstr "Pusat Rotasi X"
 
-#: clutter/clutter-actor.c:4094
+#: clutter/clutter-actor.c:4092
 msgid "The rotation center on the X axis"
 msgstr "Pusat rotasi pada sumbu X"
 
-#: clutter/clutter-actor.c:4110
+#: clutter/clutter-actor.c:4108
 msgid "Rotation Center Y"
 msgstr "Pusat Rotasi Y"
 
-#: clutter/clutter-actor.c:4111
+#: clutter/clutter-actor.c:4109
 msgid "The rotation center on the Y axis"
 msgstr "Pusat rotasi pada sumbu Y"
 
-#: clutter/clutter-actor.c:4127
+#: clutter/clutter-actor.c:4125
 msgid "Rotation Center Z"
 msgstr "Pusat Rotasi Z"
 
-#: clutter/clutter-actor.c:4128
+#: clutter/clutter-actor.c:4126
 msgid "The rotation center on the Z axis"
 msgstr "Pusat rotasi pada sumbu Z"
 
-#: clutter/clutter-actor.c:4144
+#: clutter/clutter-actor.c:4142
 msgid "Rotation Center Z Gravity"
 msgstr "Gravitasi Z Pusat Rotasi"
 
-#: clutter/clutter-actor.c:4145
+#: clutter/clutter-actor.c:4143
 msgid "Center point for rotation around the Z axis"
 msgstr "Titik pusat rotasi seputar sumbu Z"
 
-#: clutter/clutter-actor.c:4163
+#: clutter/clutter-actor.c:4161
 msgid "Anchor X"
 msgstr "Jangkar X"
 
-#: clutter/clutter-actor.c:4164
+#: clutter/clutter-actor.c:4162
 msgid "X coordinate of the anchor point"
 msgstr "Koordinat X titik jangkar"
 
-#: clutter/clutter-actor.c:4180
+#: clutter/clutter-actor.c:4178
 msgid "Anchor Y"
 msgstr "Jangkar Y"
 
-#: clutter/clutter-actor.c:4181
+#: clutter/clutter-actor.c:4179
 msgid "Y coordinate of the anchor point"
 msgstr "Koordinat Y titik jangkar"
 
-#: clutter/clutter-actor.c:4196
+#: clutter/clutter-actor.c:4194
 msgid "Anchor Gravity"
 msgstr "Gravitasi Jangkar"
 
-#: clutter/clutter-actor.c:4197
+#: clutter/clutter-actor.c:4195
 msgid "The anchor point as a ClutterGravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4216
+#: clutter/clutter-actor.c:4214
 msgid "Show on set parent"
 msgstr ""
 
-#: clutter/clutter-actor.c:4217
+#: clutter/clutter-actor.c:4215
 msgid "Whether the actor is shown when parented"
 msgstr ""
 
-#: clutter/clutter-actor.c:4237
+#: clutter/clutter-actor.c:4235
 msgid "Clip to Allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:4238
+#: clutter/clutter-actor.c:4236
 msgid "Sets the clip region to track the actor's allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:4248
+#: clutter/clutter-actor.c:4246
 msgid "Text Direction"
 msgstr "Arah Teks"
 
-#: clutter/clutter-actor.c:4249
+#: clutter/clutter-actor.c:4247
 msgid "Direction of the text"
 msgstr "Arah teks"
 
-#: clutter/clutter-actor.c:4267
+#: clutter/clutter-actor.c:4265
 msgid "Has Pointer"
 msgstr "Punya Penunjuk"
 
-#: clutter/clutter-actor.c:4268
+#: clutter/clutter-actor.c:4266
 msgid "Whether the actor contains the pointer of an input device"
 msgstr "Apakah aktor memuat penunjuk dari suatu perangkat masukan"
 
-#: clutter/clutter-actor.c:4285
+#: clutter/clutter-actor.c:4283
 msgid "Actions"
 msgstr "Aksi"
 
-#: clutter/clutter-actor.c:4286
+#: clutter/clutter-actor.c:4284
 msgid "Adds an action to the actor"
 msgstr "Tambahkan aksi ke aktor"
 
-#: clutter/clutter-actor.c:4300
+#: clutter/clutter-actor.c:4298
 msgid "Constraints"
 msgstr "Kendala"
 
-#: clutter/clutter-actor.c:4301
+#: clutter/clutter-actor.c:4299
 msgid "Adds a constraint to the actor"
 msgstr "Tambahkan kendala ke aktor"
 
@@ -411,7 +411,8 @@ msgstr ""
 msgid "The name of the meta"
 msgstr "Perubah Meta"
 
-#: clutter/clutter-actor-meta.c:219 clutter/clutter-shader.c:261
+#: clutter/clutter-actor-meta.c:219 clutter/clutter-input-device.c:314
+#: clutter/clutter-shader.c:295
 #, fuzzy
 msgid "Enabled"
 msgstr "Diaktifkan"
@@ -421,35 +422,35 @@ msgstr "Diaktifkan"
 msgid "Whether the meta is enabled"
 msgstr "Menentukan apkaah aksi diaktifkan"
 
-#: clutter/clutter-align-constraint.c:231
-#: clutter/clutter-bind-constraint.c:286 clutter/clutter-clone.c:322
+#: clutter/clutter-align-constraint.c:252
+#: clutter/clutter-bind-constraint.c:316 clutter/clutter-clone.c:322
 msgid "Source"
 msgstr "Sumber"
 
-#: clutter/clutter-align-constraint.c:232
+#: clutter/clutter-align-constraint.c:253
 msgid "The source of the alignment"
 msgstr "Sumber perataan"
 
-#: clutter/clutter-align-constraint.c:245
+#: clutter/clutter-align-constraint.c:266
 #, fuzzy
 msgid "Align Axis"
 msgstr "Rata kanan"
 
-#: clutter/clutter-align-constraint.c:246
+#: clutter/clutter-align-constraint.c:267
 msgid "The axis to align the position to"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:265
-#: clutter/clutter-desaturate-effect.c:309
+#: clutter/clutter-align-constraint.c:286
+#: clutter/clutter-desaturate-effect.c:307
 msgid "Factor"
 msgstr "Faktor"
 
-#: clutter/clutter-align-constraint.c:266
+#: clutter/clutter-align-constraint.c:287
 msgid "The alignment factor, between 0.0 and 1.0"
 msgstr ""
 
 #: clutter/clutter-alpha.c:339 clutter/clutter-animation.c:523
-#: clutter/clutter-animator.c:1801
+#: clutter/clutter-animator.c:1802
 msgid "Timeline"
 msgstr ""
 
@@ -488,7 +489,7 @@ msgstr ""
 msgid "The mode of the animation"
 msgstr "Mode animasi gambar"
 
-#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1785
+#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1786
 #: clutter/clutter-media.c:194 clutter/clutter-state.c:1282
 msgid "Duration"
 msgstr "Durasi"
@@ -509,7 +510,7 @@ msgstr ""
 msgid "The timeline used by the animation"
 msgstr ""
 
-#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:299
+#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:298
 msgid "Alpha"
 msgstr "Alfa"
 
@@ -517,244 +518,244 @@ msgstr "Alfa"
 msgid "The alpha used by the animation"
 msgstr ""
 
-#: clutter/clutter-animator.c:1786
+#: clutter/clutter-animator.c:1787
 #, fuzzy
 msgid "The duration of the animation"
 msgstr "Durasi animasi"
 
-#: clutter/clutter-animator.c:1802
+#: clutter/clutter-animator.c:1803
 #, fuzzy
 msgid "The timeline of the animation"
 msgstr "Pilih sebuah animasi"
 
-#: clutter/clutter-behaviour.c:300
+#: clutter/clutter-behaviour.c:299
 msgid "Alpha Object to drive the behaviour"
 msgstr ""
 
-#: clutter/clutter-behaviour-depth.c:175
+#: clutter/clutter-behaviour-depth.c:174
 #, fuzzy
 msgid "Start Depth"
 msgstr "_Kedalaman Warna:"
 
-#: clutter/clutter-behaviour-depth.c:176
+#: clutter/clutter-behaviour-depth.c:175
 msgid "Initial depth to apply"
 msgstr ""
 
-#: clutter/clutter-behaviour-depth.c:191
+#: clutter/clutter-behaviour-depth.c:190
 #, fuzzy
 msgid "End Depth"
 msgstr "_Kedalaman Warna:"
 
-#: clutter/clutter-behaviour-depth.c:192
+#: clutter/clutter-behaviour-depth.c:191
 msgid "Final depth to apply"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-ellipse.c:394
 #, fuzzy
 msgid "Start Angle"
 msgstr "Menu S_udut"
 
-#: clutter/clutter-behaviour-ellipse.c:396
-#: clutter/clutter-behaviour-rotate.c:277
+#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-rotate.c:276
 #, fuzzy
 msgid "Initial angle"
 msgstr "Menu S_udut"
 
-#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-ellipse.c:410
 #, fuzzy
 msgid "End Angle"
 msgstr "Menu S_udut"
 
-#: clutter/clutter-behaviour-ellipse.c:412
-#: clutter/clutter-behaviour-rotate.c:295
+#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-rotate.c:294
 #, fuzzy
 msgid "Final angle"
 msgstr "Menu S_udut"
 
-#: clutter/clutter-behaviour-ellipse.c:427
+#: clutter/clutter-behaviour-ellipse.c:426
 #, fuzzy
 msgid "Angle x tilt"
 msgstr "Menu S_udut"
 
-#: clutter/clutter-behaviour-ellipse.c:428
+#: clutter/clutter-behaviour-ellipse.c:427
 msgid "Tilt of the ellipse around x axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:443
+#: clutter/clutter-behaviour-ellipse.c:442
 #, fuzzy
 msgid "Angle y tilt"
 msgstr "Menu S_udut"
 
-#: clutter/clutter-behaviour-ellipse.c:444
+#: clutter/clutter-behaviour-ellipse.c:443
 msgid "Tilt of the ellipse around y axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:459
+#: clutter/clutter-behaviour-ellipse.c:458
 #, fuzzy
 msgid "Angle z tilt"
 msgstr "Menu S_udut"
 
-#: clutter/clutter-behaviour-ellipse.c:460
+#: clutter/clutter-behaviour-ellipse.c:459
 msgid "Tilt of the ellipse around z axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:476
+#: clutter/clutter-behaviour-ellipse.c:475
 #, fuzzy
 msgid "Width of the ellipse"
 msgstr "_Lebar tetap:"
 
-#: clutter/clutter-behaviour-ellipse.c:492
+#: clutter/clutter-behaviour-ellipse.c:491
 #, fuzzy
 msgid "Height of ellipse"
 msgstr "<b>Tinggi:</b> %d piksel\n"
 
-#: clutter/clutter-behaviour-ellipse.c:507
+#: clutter/clutter-behaviour-ellipse.c:506
 #, fuzzy
 msgid "Center"
 msgstr "Tengah"
 
-#: clutter/clutter-behaviour-ellipse.c:508
+#: clutter/clutter-behaviour-ellipse.c:507
 #, fuzzy
 msgid "Center of ellipse"
 msgstr "Pusat Pengaturan"
 
-#: clutter/clutter-behaviour-ellipse.c:522
-#: clutter/clutter-behaviour-rotate.c:330
+#: clutter/clutter-behaviour-ellipse.c:521
+#: clutter/clutter-behaviour-rotate.c:329
 msgid "Direction"
 msgstr "Arah"
 
-#: clutter/clutter-behaviour-ellipse.c:523
-#: clutter/clutter-behaviour-rotate.c:331
+#: clutter/clutter-behaviour-ellipse.c:522
+#: clutter/clutter-behaviour-rotate.c:330
 #, fuzzy
 msgid "Direction of rotation"
 msgstr "Putaran Jarum Jam"
 
-#: clutter/clutter-behaviour-opacity.c:178
+#: clutter/clutter-behaviour-opacity.c:177
 #, fuzzy
 msgid "Opacity Start"
 msgstr "Jalankan program"
 
-#: clutter/clutter-behaviour-opacity.c:179
+#: clutter/clutter-behaviour-opacity.c:178
 msgid "Initial opacity level"
 msgstr ""
 
-#: clutter/clutter-behaviour-opacity.c:196
+#: clutter/clutter-behaviour-opacity.c:195
 #, fuzzy
 msgid "Opacity End"
 msgstr "KP_End"
 
-#: clutter/clutter-behaviour-opacity.c:197
+#: clutter/clutter-behaviour-opacity.c:196
 msgid "Final opacity level"
 msgstr ""
 
-#: clutter/clutter-behaviour-path.c:220
+#: clutter/clutter-behaviour-path.c:219
 msgid "Path"
 msgstr "Path"
 
-#: clutter/clutter-behaviour-path.c:221
+#: clutter/clutter-behaviour-path.c:220
 msgid "The ClutterPath object representing the path to animate along"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:276
+#: clutter/clutter-behaviour-rotate.c:275
 #, fuzzy
 msgid "Angle Begin"
 msgstr "KP_Begin"
 
-#: clutter/clutter-behaviour-rotate.c:294
+#: clutter/clutter-behaviour-rotate.c:293
 #, fuzzy
 msgid "Angle End"
 msgstr "KP_End"
 
-#: clutter/clutter-behaviour-rotate.c:312
+#: clutter/clutter-behaviour-rotate.c:311
 #, fuzzy
 msgid "Axis"
 msgstr "Sumbu"
 
-#: clutter/clutter-behaviour-rotate.c:313
+#: clutter/clutter-behaviour-rotate.c:312
 #, fuzzy
 msgid "Axis of rotation"
 msgstr "Putaran Jarum Jam"
 
-#: clutter/clutter-behaviour-rotate.c:348
+#: clutter/clutter-behaviour-rotate.c:347
 msgid "Center X"
 msgstr "Pusat X"
 
-#: clutter/clutter-behaviour-rotate.c:349
+#: clutter/clutter-behaviour-rotate.c:348
 msgid "X coordinate of the center of rotation"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:366
+#: clutter/clutter-behaviour-rotate.c:365
 msgid "Center Y"
 msgstr "Pusat Y"
 
-#: clutter/clutter-behaviour-rotate.c:367
+#: clutter/clutter-behaviour-rotate.c:366
 msgid "Y coordinate of the center of rotation"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:384
+#: clutter/clutter-behaviour-rotate.c:383
 msgid "Center Z"
 msgstr "Pusat Z"
 
-#: clutter/clutter-behaviour-rotate.c:385
+#: clutter/clutter-behaviour-rotate.c:384
 msgid "Z coordinate of the center of rotation"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:219
+#: clutter/clutter-behaviour-scale.c:218
 #, fuzzy
 msgid "X Start Scale"
 msgstr "Skala Beaufort"
 
-#: clutter/clutter-behaviour-scale.c:220
+#: clutter/clutter-behaviour-scale.c:219
 msgid "Initial scale on the X axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:238
+#: clutter/clutter-behaviour-scale.c:237
 #, fuzzy
 msgid "X End Scale"
 msgstr "Skala Beaufort"
 
-#: clutter/clutter-behaviour-scale.c:239
+#: clutter/clutter-behaviour-scale.c:238
 msgid "Final scale on the X axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:257
+#: clutter/clutter-behaviour-scale.c:256
 #, fuzzy
 msgid "Y Start Scale"
 msgstr "Skala Beaufort"
 
-#: clutter/clutter-behaviour-scale.c:258
+#: clutter/clutter-behaviour-scale.c:257
 msgid "Initial scale on the Y axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:276
+#: clutter/clutter-behaviour-scale.c:275
 #, fuzzy
 msgid "Y End Scale"
 msgstr "Skala Beaufort"
 
-#: clutter/clutter-behaviour-scale.c:277
+#: clutter/clutter-behaviour-scale.c:276
 msgid "Final scale on the Y axis"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:287
+#: clutter/clutter-bind-constraint.c:317
 #, fuzzy
 msgid "The source of the binding"
 msgstr "Asal IP"
 
-#: clutter/clutter-bind-constraint.c:300
+#: clutter/clutter-bind-constraint.c:330
 #, fuzzy
 msgid "Coordinate"
 msgstr "Koordinat X"
 
-#: clutter/clutter-bind-constraint.c:301
+#: clutter/clutter-bind-constraint.c:331
 #, fuzzy
 msgid "The coordinate to bind"
 msgstr "Koordinat X dari kotak untuk merekam"
 
-#: clutter/clutter-bind-constraint.c:315
+#: clutter/clutter-bind-constraint.c:345
 msgid "Offset"
 msgstr "Ofset"
 
-#: clutter/clutter-bind-constraint.c:316
+#: clutter/clutter-bind-constraint.c:346
 msgid "The offset in pixels to apply to the binding"
 msgstr ""
 
@@ -786,7 +787,7 @@ msgstr ""
 msgid "Default vertical alignment for the actors inside the layout manager"
 msgstr ""
 
-#: clutter/clutter-binding-pool.c:321
+#: clutter/clutter-binding-pool.c:320
 msgid "The unique name of the binding pool"
 msgstr ""
 
@@ -799,7 +800,7 @@ msgid "The layout manager used by the box"
 msgstr ""
 
 #: clutter/clutter-box.c:514 clutter/clutter-rectangle.c:258
-#: clutter/clutter-stage.c:1307
+#: clutter/clutter-stage.c:1317
 msgid "Color"
 msgstr "Warna"
 
@@ -953,20 +954,20 @@ msgstr ""
 msgid "The actor wrapped by this data"
 msgstr ""
 
-#: clutter/clutter-click-action.c:283
+#: clutter/clutter-click-action.c:302
 #, fuzzy
 msgid "Pressed"
 msgstr "ditekan"
 
-#: clutter/clutter-click-action.c:284
+#: clutter/clutter-click-action.c:303
 msgid "Whether the clickable should be in pressed state"
 msgstr ""
 
-#: clutter/clutter-click-action.c:297
+#: clutter/clutter-click-action.c:316
 msgid "Held"
 msgstr ""
 
-#: clutter/clutter-click-action.c:298
+#: clutter/clutter-click-action.c:317
 msgid "Whether the clickable has a grab"
 msgstr ""
 
@@ -974,11 +975,11 @@ msgstr ""
 msgid "Specifies the actor to be cloned"
 msgstr ""
 
-#: clutter/clutter-colorize-effect.c:309
+#: clutter/clutter-colorize-effect.c:307
 msgid "Tint"
 msgstr ""
 
-#: clutter/clutter-colorize-effect.c:310
+#: clutter/clutter-colorize-effect.c:308
 #, fuzzy
 msgid "The tint to apply"
 msgstr "Stash yang akan Diterapkan"
@@ -1010,12 +1011,12 @@ msgstr "Riwayat sebelumnya"
 msgid "The material to be used when painting the back of the actor"
 msgstr ""
 
-#: clutter/clutter-desaturate-effect.c:310
+#: clutter/clutter-desaturate-effect.c:308
 #, fuzzy
 msgid "The desaturation factor"
 msgstr "Faktor koreksi"
 
-#: clutter/clutter-device-manager.c:130
+#: clutter/clutter-device-manager.c:130 clutter/clutter-input-device.c:343
 #, fuzzy
 msgid "Backend"
 msgstr "Backend"
@@ -1025,37 +1026,37 @@ msgstr "Backend"
 msgid "The ClutterBackend of the device manager"
 msgstr "Peran perangkat di dalam manajer"
 
-#: clutter/clutter-drag-action.c:490
+#: clutter/clutter-drag-action.c:491
 msgid "Horizontal Drag Threshold"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:491
+#: clutter/clutter-drag-action.c:492
 msgid "The horizontal amount of pixels required to start dragging"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:510
+#: clutter/clutter-drag-action.c:511
 msgid "Vertical Drag Threshold"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:511
+#: clutter/clutter-drag-action.c:512
 msgid "The vertical amount of pixels required to start dragging"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:532
+#: clutter/clutter-drag-action.c:533
 #, fuzzy
 msgid "Drag Handle"
 msgstr "Tampilkan handle"
 
-#: clutter/clutter-drag-action.c:533
+#: clutter/clutter-drag-action.c:534
 msgid "The actor that is being dragged"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:546
+#: clutter/clutter-drag-action.c:547
 #, fuzzy
 msgid "Drag Axis"
 msgstr " _Drag"
 
-#: clutter/clutter-drag-action.c:547
+#: clutter/clutter-drag-action.c:548
 msgid "Constraints the dragging to an axis"
 msgstr ""
 
@@ -1129,29 +1130,76 @@ msgstr "Tinggi baris seragam"
 msgid "Maximum height for each row"
 msgstr ""
 
-#: clutter/clutter-input-device.c:134
+#: clutter/clutter-input-device.c:219
 msgid "Id"
 msgstr "Id"
 
-#: clutter/clutter-input-device.c:135
+#: clutter/clutter-input-device.c:220
 msgid "Unique identifier of the device"
 msgstr ""
 
-#: clutter/clutter-input-device.c:152
+#: clutter/clutter-input-device.c:236
 #, fuzzy
 msgid "The name of the device"
 msgstr "Nama perangkat"
 
-#: clutter/clutter-input-device.c:167
+#: clutter/clutter-input-device.c:250
 #, fuzzy
 msgid "Device Type"
 msgstr "_Tipe perangkat:"
 
-#: clutter/clutter-input-device.c:168
+#: clutter/clutter-input-device.c:251
 #, fuzzy
 msgid "The type of the device"
 msgstr "_Tipe perangkat:"
 
+#: clutter/clutter-input-device.c:266
+#, fuzzy
+msgid "Device Manager"
+msgstr "Manajer"
+
+#: clutter/clutter-input-device.c:267
+msgid "The device manager instance"
+msgstr ""
+
+#: clutter/clutter-input-device.c:280
+#, fuzzy
+msgid "Device Mode"
+msgstr "_Tipe perangkat:"
+
+#: clutter/clutter-input-device.c:281
+#, fuzzy
+msgid "The mode of the device"
+msgstr "Nama perangkat"
+
+#: clutter/clutter-input-device.c:295
+#, fuzzy
+msgid "Has Cursor"
+msgstr "Bingkai Jendela"
+
+#: clutter/clutter-input-device.c:296
+#, fuzzy
+msgid "Whether the device has a cursor"
+msgstr "Apakah aktor telah ditata punya klip"
+
+#: clutter/clutter-input-device.c:315
+#, fuzzy
+msgid "Whether the device is enabled"
+msgstr "Menentukan apkaah aksi diaktifkan"
+
+#: clutter/clutter-input-device.c:328
+msgid "Number of Axes"
+msgstr ""
+
+#: clutter/clutter-input-device.c:329
+#, fuzzy
+msgid "The number of axes on the device"
+msgstr "Nama perangkat"
+
+#: clutter/clutter-input-device.c:344
+msgid "The backend instance"
+msgstr ""
+
 #: clutter/clutter-interval.c:397
 #, fuzzy
 msgid "Value Type"
@@ -1169,66 +1217,66 @@ msgstr "Manajer"
 msgid "The manager that created this data"
 msgstr ""
 
-#: clutter/clutter-main.c:756
+#: clutter/clutter-main.c:753
 #, fuzzy
 msgid "default:LTR"
 msgstr "default:LTR"
 
-#: clutter/clutter-main.c:1560
+#: clutter/clutter-main.c:1557
 msgid "Show frames per second"
 msgstr ""
 
-#: clutter/clutter-main.c:1562
+#: clutter/clutter-main.c:1559
 msgid "Default frame rate"
 msgstr ""
 
-#: clutter/clutter-main.c:1564
+#: clutter/clutter-main.c:1561
 #, fuzzy
 msgid "Make all warnings fatal"
 msgstr "Buat semua peringatan menjadi pesan fatal"
 
-#: clutter/clutter-main.c:1567
+#: clutter/clutter-main.c:1564
 #, fuzzy
 msgid "Direction for the text"
 msgstr "Fonta untuk teks"
 
-#: clutter/clutter-main.c:1570
+#: clutter/clutter-main.c:1567
 msgid "Disable mipmapping on text"
 msgstr ""
 
-#: clutter/clutter-main.c:1573
+#: clutter/clutter-main.c:1570
 msgid "Use 'fuzzy' picking"
 msgstr ""
 
-#: clutter/clutter-main.c:1576
+#: clutter/clutter-main.c:1573
 #, fuzzy
 msgid "Clutter debugging flags to set"
 msgstr "Bendera debug Gdk yang hendak dipasang"
 
-#: clutter/clutter-main.c:1578
+#: clutter/clutter-main.c:1575
 #, fuzzy
 msgid "Clutter debugging flags to unset"
 msgstr "Bendera debug Gdk yang hendak dilepas"
 
-#: clutter/clutter-main.c:1582
+#: clutter/clutter-main.c:1579
 msgid "Clutter profiling flags to set"
 msgstr ""
 
-#: clutter/clutter-main.c:1584
+#: clutter/clutter-main.c:1581
 msgid "Clutter profiling flags to unset"
 msgstr ""
 
-#: clutter/clutter-main.c:1587
+#: clutter/clutter-main.c:1584
 #, fuzzy
 msgid "Enable accessibility"
 msgstr "Aktifkan Aksesibilitas"
 
-#: clutter/clutter-main.c:1774
+#: clutter/clutter-main.c:1771
 #, fuzzy
 msgid "Clutter Options"
 msgstr "Pilihan GTK+"
 
-#: clutter/clutter-main.c:1775
+#: clutter/clutter-main.c:1772
 #, fuzzy
 msgid "Show Clutter Options"
 msgstr "Tampilkan opsi pengawa-kutuan"
@@ -1366,48 +1414,48 @@ msgstr "Nama Berkas"
 msgid "The path of the currently parsed file"
 msgstr ""
 
-#: clutter/clutter-shader.c:215
+#: clutter/clutter-shader.c:249
 #, fuzzy
 msgid "Vertex Source"
 msgstr "Asal IP"
 
-#: clutter/clutter-shader.c:216
+#: clutter/clutter-shader.c:250
 msgid "Source of vertex shader"
 msgstr ""
 
-#: clutter/clutter-shader.c:230
+#: clutter/clutter-shader.c:264
 #, fuzzy
 msgid "Fragment Source"
 msgstr "Asal IP"
 
-#: clutter/clutter-shader.c:231
+#: clutter/clutter-shader.c:265
 msgid "Source of fragment shader"
 msgstr ""
 
-#: clutter/clutter-shader.c:246
+#: clutter/clutter-shader.c:280
 msgid "Compiled"
 msgstr ""
 
-#: clutter/clutter-shader.c:247
+#: clutter/clutter-shader.c:281
 msgid "Whether the shader is compiled and linked"
 msgstr ""
 
-#: clutter/clutter-shader.c:262
+#: clutter/clutter-shader.c:296
 #, fuzzy
 msgid "Whether the shader is enabled"
 msgstr "Menentukan apkaah aksi diaktifkan"
 
-#: clutter/clutter-shader.c:467
+#: clutter/clutter-shader.c:501
 #, fuzzy, c-format
 msgid "%s compilation failed: %s"
 msgstr "Pemasangan Gagal"
 
-#: clutter/clutter-shader.c:468
+#: clutter/clutter-shader.c:502
 #, fuzzy
 msgid "Vertex shader"
 msgstr "Bahasa CG Shader"
 
-#: clutter/clutter-shader.c:469
+#: clutter/clutter-shader.c:503
 #, fuzzy
 msgid "Fragment shader"
 msgstr "Bahasa CG Shader"
@@ -1422,104 +1470,113 @@ msgstr "Tipe Latar"
 msgid "The type of shader used"
 msgstr "Jenis arsip terakhir yang digunakan"
 
-#: clutter/clutter-stage.c:1249
+#: clutter/clutter-stage.c:1259
 #, fuzzy
 msgid "Fullscreen Set"
 msgstr "<small>Tata...</small>"
 
-#: clutter/clutter-stage.c:1250
+#: clutter/clutter-stage.c:1260
 msgid "Whether the main stage is fullscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1266
+#: clutter/clutter-stage.c:1276
 msgid "Offscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1267
+#: clutter/clutter-stage.c:1277
 msgid "Whether the main stage should be rendered offscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1279 clutter/clutter-text.c:2643
+#: clutter/clutter-stage.c:1289 clutter/clutter-text.c:2667
 #, fuzzy
 msgid "Cursor Visible"
 msgstr "Kursor Nampak"
 
-#: clutter/clutter-stage.c:1280
+#: clutter/clutter-stage.c:1290
 msgid "Whether the mouse pointer is visible on the main stage"
 msgstr ""
 
-#: clutter/clutter-stage.c:1294
+#: clutter/clutter-stage.c:1304
 #, fuzzy
 msgid "User Resizable"
 msgstr "_Ganti Pengguna"
 
-#: clutter/clutter-stage.c:1295
+#: clutter/clutter-stage.c:1305
 msgid "Whether the stage is able to be resized via user interaction"
 msgstr ""
 
-#: clutter/clutter-stage.c:1308
+#: clutter/clutter-stage.c:1318
 #, fuzzy
 msgid "The color of the stage"
 msgstr "Pilih warna"
 
-#: clutter/clutter-stage.c:1322
+#: clutter/clutter-stage.c:1332
 msgid "Perspective"
 msgstr ""
 
-#: clutter/clutter-stage.c:1323
+#: clutter/clutter-stage.c:1333
 msgid "Perspective projection parameters"
 msgstr ""
 
-#: clutter/clutter-stage.c:1338
+#: clutter/clutter-stage.c:1348
 msgid "Title"
 msgstr "Judul"
 
-#: clutter/clutter-stage.c:1339
+#: clutter/clutter-stage.c:1349
 #, fuzzy
 msgid "Stage Title"
 msgstr "Jabatan"
 
-#: clutter/clutter-stage.c:1354
+#: clutter/clutter-stage.c:1364
 msgid "Use Fog"
 msgstr "Gunakan Kabut"
 
-#: clutter/clutter-stage.c:1355
+#: clutter/clutter-stage.c:1365
 msgid "Whether to enable depth cueing"
 msgstr ""
 
-#: clutter/clutter-stage.c:1369
+#: clutter/clutter-stage.c:1379
 msgid "Fog"
 msgstr "Kabut"
 
-#: clutter/clutter-stage.c:1370
+#: clutter/clutter-stage.c:1380
 msgid "Settings for the depth cueing"
 msgstr ""
 
-#: clutter/clutter-stage.c:1386
+#: clutter/clutter-stage.c:1396
 msgid "Use Alpha"
 msgstr "Gunakan Alfa"
 
-#: clutter/clutter-stage.c:1387
+#: clutter/clutter-stage.c:1397
 msgid "Whether to honour the alpha component of the stage color"
 msgstr ""
 
-#: clutter/clutter-stage.c:1403
+#: clutter/clutter-stage.c:1413
 #, fuzzy
 msgid "Key Focus"
 msgstr "Ambil Fokus"
 
-#: clutter/clutter-stage.c:1404
+#: clutter/clutter-stage.c:1414
 msgid "The currently key focused actor"
 msgstr ""
 
-#: clutter/clutter-stage.c:1420
+#: clutter/clutter-stage.c:1430
 msgid "No Clear Hint"
 msgstr ""
 
-#: clutter/clutter-stage.c:1421
+#: clutter/clutter-stage.c:1431
 msgid "Whether the stage should clear its contents"
 msgstr ""
 
+#: clutter/clutter-stage.c:1444
+#, fuzzy
+msgid "Accept Focus"
+msgstr "Ambil Fokus"
+
+#: clutter/clutter-stage.c:1445
+msgid "Whether the stage should accept focus on show"
+msgstr ""
+
 #: clutter/clutter-state.c:1268
 #, fuzzy
 msgid "State"
@@ -1533,210 +1590,210 @@ msgstr ""
 msgid "Default transition duration"
 msgstr ""
 
-#: clutter/clutter-text.c:2530
+#: clutter/clutter-text.c:2554
 msgid "Font Name"
 msgstr "Nama Fonta"
 
-#: clutter/clutter-text.c:2531
+#: clutter/clutter-text.c:2555
 msgid "The font to be used by the text"
 msgstr ""
 
-#: clutter/clutter-text.c:2548
+#: clutter/clutter-text.c:2572
 #, fuzzy
 msgid "Font Description"
 msgstr "Deskripsi fonta"
 
-#: clutter/clutter-text.c:2549
+#: clutter/clutter-text.c:2573
 #, fuzzy
 msgid "The font description to be used"
 msgstr "Jenis huruf yang digunakan ketika mencetak"
 
-#: clutter/clutter-text.c:2565
+#: clutter/clutter-text.c:2589
 msgid "Text"
 msgstr "Teks"
 
-#: clutter/clutter-text.c:2566
+#: clutter/clutter-text.c:2590
 #, fuzzy
 msgid "The text to render"
 msgstr "Teks yang hendak ditulis"
 
-#: clutter/clutter-text.c:2580
+#: clutter/clutter-text.c:2604
 msgid "Font Color"
 msgstr "Warna Fonta"
 
-#: clutter/clutter-text.c:2581
+#: clutter/clutter-text.c:2605
 msgid "Color of the font used by the text"
 msgstr ""
 
-#: clutter/clutter-text.c:2595
+#: clutter/clutter-text.c:2619
 #, fuzzy
 msgid "Editable"
 msgstr "Dapat diedit"
 
-#: clutter/clutter-text.c:2596
+#: clutter/clutter-text.c:2620
 #, fuzzy
 msgid "Whether the text is editable"
 msgstr "Apakah entri ini dapat diterjemahkan"
 
-#: clutter/clutter-text.c:2611
+#: clutter/clutter-text.c:2635
 #, fuzzy
 msgid "Selectable"
 msgstr "Dapat dipilih"
 
-#: clutter/clutter-text.c:2612
+#: clutter/clutter-text.c:2636
 #, fuzzy
 msgid "Whether the text is selectable"
 msgstr "Menentukan apakah teks ini disembunyikan"
 
-#: clutter/clutter-text.c:2626
+#: clutter/clutter-text.c:2650
 #, fuzzy
 msgid "Activatable"
 msgstr "Dapat diaktifkan"
 
-#: clutter/clutter-text.c:2627
+#: clutter/clutter-text.c:2651
 msgid "Whether pressing return causes the activate signal to be emitted"
 msgstr ""
 
-#: clutter/clutter-text.c:2644
+#: clutter/clutter-text.c:2668
 msgid "Whether the input cursor is visible"
 msgstr ""
 
-#: clutter/clutter-text.c:2658 clutter/clutter-text.c:2659
+#: clutter/clutter-text.c:2682 clutter/clutter-text.c:2683
 msgid "Cursor Color"
 msgstr "Warna Kursor"
 
-#: clutter/clutter-text.c:2673
+#: clutter/clutter-text.c:2697
 #, fuzzy
 msgid "Cursor Color Set"
 msgstr "Warna latar belakang sudah diset"
 
-#: clutter/clutter-text.c:2674
+#: clutter/clutter-text.c:2698
 msgid "Whether the cursor color has been set"
 msgstr ""
 
-#: clutter/clutter-text.c:2689
+#: clutter/clutter-text.c:2713
 msgid "Cursor Size"
 msgstr "Ukuran Kursor"
 
-#: clutter/clutter-text.c:2690
+#: clutter/clutter-text.c:2714
 #, fuzzy
 msgid "The width of the cursor, in pixels"
 msgstr "Lebar cuplikan layar (dalam piksel):"
 
-#: clutter/clutter-text.c:2704
+#: clutter/clutter-text.c:2728
 #, fuzzy
 msgid "Cursor Position"
 msgstr "Posisi Kursor"
 
-#: clutter/clutter-text.c:2705
+#: clutter/clutter-text.c:2729
 #, fuzzy
 msgid "The cursor position"
 msgstr "Posisi Kursor"
 
-#: clutter/clutter-text.c:2720
+#: clutter/clutter-text.c:2744
 #, fuzzy
 msgid "Selection-bound"
 msgstr "Batas Seleksi"
 
-#: clutter/clutter-text.c:2721
+#: clutter/clutter-text.c:2745
 msgid "The cursor position of the other end of the selection"
 msgstr ""
 
-#: clutter/clutter-text.c:2736 clutter/clutter-text.c:2737
+#: clutter/clutter-text.c:2760 clutter/clutter-text.c:2761
 msgid "Selection Color"
 msgstr "Warna Pilihan"
 
-#: clutter/clutter-text.c:2751
+#: clutter/clutter-text.c:2775
 msgid "Selection Color Set"
 msgstr "Warna Pilihan Ditata"
 
-#: clutter/clutter-text.c:2752
+#: clutter/clutter-text.c:2776
 msgid "Whether the selection color has been set"
 msgstr "Apakah warna pilihan telah ditata"
 
-#: clutter/clutter-text.c:2767
+#: clutter/clutter-text.c:2791
 msgid "Attributes"
 msgstr "Atribut"
 
-#: clutter/clutter-text.c:2768
+#: clutter/clutter-text.c:2792
 msgid "A list of style attributes to apply to the contents of the actor"
 msgstr ""
 
-#: clutter/clutter-text.c:2790
+#: clutter/clutter-text.c:2814
 #, fuzzy
 msgid "Use markup"
 msgstr "Gunakan markup"
 
-#: clutter/clutter-text.c:2791
+#: clutter/clutter-text.c:2815
 msgid "Whether or not the text includes Pango markup"
 msgstr ""
 
-#: clutter/clutter-text.c:2807
+#: clutter/clutter-text.c:2831
 #, fuzzy
 msgid "Line wrap"
 msgstr "Potong baris"
 
-#: clutter/clutter-text.c:2808
+#: clutter/clutter-text.c:2832
 #, fuzzy
 msgid "If set, wrap the lines if the text becomes too wide"
 msgstr "Jika ini diset, baris akan dipotong bila terlalu lebar."
 
-#: clutter/clutter-text.c:2823
+#: clutter/clutter-text.c:2847
 #, fuzzy
 msgid "Line wrap mode"
 msgstr "Mode pelipatan baris"
 
-#: clutter/clutter-text.c:2824
+#: clutter/clutter-text.c:2848
 msgid "Control how line-wrapping is done"
 msgstr ""
 
-#: clutter/clutter-text.c:2839
+#: clutter/clutter-text.c:2863
 #, fuzzy
 msgid "Ellipsize"
 msgstr "Elipsis"
 
-#: clutter/clutter-text.c:2840
+#: clutter/clutter-text.c:2864
 msgid "The preferred place to ellipsize the string"
 msgstr ""
 
-#: clutter/clutter-text.c:2856
+#: clutter/clutter-text.c:2880
 msgid "Line Alignment"
 msgstr "Perataan Baris"
 
-#: clutter/clutter-text.c:2857
+#: clutter/clutter-text.c:2881
 msgid "The preferred alignment for the string, for multi-line text"
 msgstr ""
 
-#: clutter/clutter-text.c:2873
+#: clutter/clutter-text.c:2897
 msgid "Justify"
 msgstr "Diratakan"
 
-#: clutter/clutter-text.c:2874
+#: clutter/clutter-text.c:2898
 msgid "Whether the text should be justified"
 msgstr ""
 
-#: clutter/clutter-text.c:2889
+#: clutter/clutter-text.c:2913
 msgid "Password Character"
 msgstr "Karakter Sandi"
 
-#: clutter/clutter-text.c:2890
+#: clutter/clutter-text.c:2914
 msgid "If non-zero, use this character to display the actor's contents"
 msgstr ""
 
-#: clutter/clutter-text.c:2904
+#: clutter/clutter-text.c:2928
 msgid "Max Length"
 msgstr "Panjang Maks"
 
-#: clutter/clutter-text.c:2905
+#: clutter/clutter-text.c:2929
 msgid "Maximum length of the text inside the actor"
 msgstr ""
 
-#: clutter/clutter-text.c:2928
+#: clutter/clutter-text.c:2952
 #, fuzzy
 msgid "Single Line Mode"
 msgstr "Moda Satu Baris"
 
-#: clutter/clutter-text.c:2929
+#: clutter/clutter-text.c:2953
 msgid "Whether the text should be a single line"
 msgstr ""
 
@@ -1865,26 +1922,26 @@ msgstr ""
 msgid "Shape actor with alpha channel when picking"
 msgstr ""
 
-#: clutter/glx/clutter-backend-glx.c:128
+#: clutter/glx/clutter-backend-glx.c:131
 msgid "VBlank method to be used (none, dri or glx)"
 msgstr ""
 
-#: clutter/x11/clutter-backend-x11.c:364
+#: clutter/x11/clutter-backend-x11.c:473
 #, fuzzy
 msgid "X display to use"
 msgstr "Tampilan X yang digunakan"
 
-#: clutter/x11/clutter-backend-x11.c:370
+#: clutter/x11/clutter-backend-x11.c:479
 #, fuzzy
 msgid "X screen to use"
 msgstr "Layar X yang digunakan"
 
-#: clutter/x11/clutter-backend-x11.c:375
+#: clutter/x11/clutter-backend-x11.c:484
 #, fuzzy
 msgid "Make X calls synchronous"
 msgstr "Buat panggilan X sinkronus"
 
-#: clutter/x11/clutter-backend-x11.c:382
+#: clutter/x11/clutter-backend-x11.c:491
 #, fuzzy
 msgid "Enable XInput support"
 msgstr "Aktifkan dukungan IPv4"
index ead61d0..60bd57f 100644 (file)
--- a/po/it.po
+++ b/po/it.po
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: clutter\n"
 "Report-Msgid-Bugs-To: http://bugzilla.clutter-project.org/enter_bug.cgi?"
 "product=clutter\n"
-"POT-Creation-Date: 2010-12-17 15:51+0000\n"
+"POT-Creation-Date: 2011-02-07 15:50+0000\n"
 "PO-Revision-Date: 2010-08-20 16:59+0200\n"
 "Last-Translator: Luca Ferretti\n"
 "Language-Team: Italian <tp@lists.linux.it>\n"
@@ -17,381 +17,381 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: clutter/clutter-actor.c:3480
+#: clutter/clutter-actor.c:3478
 msgid "X coordinate"
 msgstr "Coordinata X"
 
-#: clutter/clutter-actor.c:3481
+#: clutter/clutter-actor.c:3479
 msgid "X coordinate of the actor"
 msgstr "Coordinata X dell'attore"
 
-#: clutter/clutter-actor.c:3496
+#: clutter/clutter-actor.c:3494
 msgid "Y coordinate"
 msgstr "Coordinata Y"
 
-#: clutter/clutter-actor.c:3497
+#: clutter/clutter-actor.c:3495
 msgid "Y coordinate of the actor"
 msgstr "Coordinata Y dell'attore"
 
-#: clutter/clutter-actor.c:3512 clutter/clutter-behaviour-ellipse.c:475
+#: clutter/clutter-actor.c:3510 clutter/clutter-behaviour-ellipse.c:474
 msgid "Width"
 msgstr "Larghezza"
 
-#: clutter/clutter-actor.c:3513
+#: clutter/clutter-actor.c:3511
 msgid "Width of the actor"
 msgstr "Larghezza dell'attore"
 
-#: clutter/clutter-actor.c:3527 clutter/clutter-behaviour-ellipse.c:491
+#: clutter/clutter-actor.c:3525 clutter/clutter-behaviour-ellipse.c:490
 msgid "Height"
 msgstr "Altezza"
 
-#: clutter/clutter-actor.c:3528
+#: clutter/clutter-actor.c:3526
 msgid "Height of the actor"
 msgstr "Altezza dell'attore"
 
-#: clutter/clutter-actor.c:3546
+#: clutter/clutter-actor.c:3544
 msgid "Fixed X"
 msgstr "Fissata X"
 
-#: clutter/clutter-actor.c:3547
+#: clutter/clutter-actor.c:3545
 msgid "Forced X position of the actor"
 msgstr "Posizione X forzata dell'attore"
 
-#: clutter/clutter-actor.c:3565
+#: clutter/clutter-actor.c:3563
 msgid "Fixed Y"
 msgstr "Fissata Y"
 
-#: clutter/clutter-actor.c:3566
+#: clutter/clutter-actor.c:3564
 msgid "Forced Y position of the actor"
 msgstr "Posizione Y forzata dell'attore"
 
-#: clutter/clutter-actor.c:3582
+#: clutter/clutter-actor.c:3580
 msgid "Fixed position set"
 msgstr "Imposta posizione fissa"
 
-#: clutter/clutter-actor.c:3583
+#: clutter/clutter-actor.c:3581
 msgid "Whether to use fixed positioning for the actor"
 msgstr "Se usare il posizionamento fisso per l'attore"
 
-#: clutter/clutter-actor.c:3605
+#: clutter/clutter-actor.c:3603
 msgid "Min Width"
 msgstr "Larghezza minima"
 
-#: clutter/clutter-actor.c:3606
+#: clutter/clutter-actor.c:3604
 msgid "Forced minimum width request for the actor"
 msgstr "Larghezza minima forzata richiesta per l'attore"
 
-#: clutter/clutter-actor.c:3625
+#: clutter/clutter-actor.c:3623
 msgid "Min Height"
 msgstr "Altezza minima"
 
-#: clutter/clutter-actor.c:3626
+#: clutter/clutter-actor.c:3624
 msgid "Forced minimum height request for the actor"
 msgstr "Altezza minima forzata richiesta per l'attore"
 
-#: clutter/clutter-actor.c:3645
+#: clutter/clutter-actor.c:3643
 msgid "Natural Width"
 msgstr "Larghezza naturale"
 
-#: clutter/clutter-actor.c:3646
+#: clutter/clutter-actor.c:3644
 msgid "Forced natural width request for the actor"
 msgstr "Larghezza naturale forzata richiesta per l'attore"
 
-#: clutter/clutter-actor.c:3665
+#: clutter/clutter-actor.c:3663
 msgid "Natural Height"
 msgstr "Altezza naturale"
 
-#: clutter/clutter-actor.c:3666
+#: clutter/clutter-actor.c:3664
 msgid "Forced natural height request for the actor"
 msgstr "Altezza naturale forzata richiesta per l'attore"
 
-#: clutter/clutter-actor.c:3682
+#: clutter/clutter-actor.c:3680
 msgid "Minimum width set"
 msgstr "Imposta larghezza minima"
 
-#: clutter/clutter-actor.c:3683
+#: clutter/clutter-actor.c:3681
 msgid "Whether to use the min-width property"
 msgstr "Se utilizzare la proprietà larghezza minima"
 
-#: clutter/clutter-actor.c:3698
+#: clutter/clutter-actor.c:3696
 msgid "Minimum height set"
 msgstr "Imposta altezza minima"
 
-#: clutter/clutter-actor.c:3699
+#: clutter/clutter-actor.c:3697
 msgid "Whether to use the min-height property"
 msgstr "Se usare la proprietà altezza minima"
 
-#: clutter/clutter-actor.c:3714
+#: clutter/clutter-actor.c:3712
 msgid "Natural width set"
 msgstr "Imposta larghezza naturale"
 
-#: clutter/clutter-actor.c:3715
+#: clutter/clutter-actor.c:3713
 msgid "Whether to use the natural-width property"
 msgstr "Se usare la proprietà larghezza naturale"
 
-#: clutter/clutter-actor.c:3732
+#: clutter/clutter-actor.c:3730
 msgid "Natural height set"
 msgstr "Imposta altezza naturale"
 
-#: clutter/clutter-actor.c:3733
+#: clutter/clutter-actor.c:3731
 msgid "Whether to use the natural-height property"
 msgstr "Se usare la proprietà altezza naturale"
 
-#: clutter/clutter-actor.c:3752
+#: clutter/clutter-actor.c:3750
 msgid "Allocation"
 msgstr "Allocazione"
 
-#: clutter/clutter-actor.c:3753
+#: clutter/clutter-actor.c:3751
 msgid "The actor's allocation"
 msgstr "Assegnazione dell'attore"
 
-#: clutter/clutter-actor.c:3809
+#: clutter/clutter-actor.c:3807
 msgid "Request Mode"
 msgstr "Modalità richiesta"
 
-#: clutter/clutter-actor.c:3810
+#: clutter/clutter-actor.c:3808
 msgid "The actor's request mode"
 msgstr "La modalità richiesta dell'attore"
 
-#: clutter/clutter-actor.c:3825
+#: clutter/clutter-actor.c:3823
 msgid "Depth"
 msgstr "Profondità"
 
-#: clutter/clutter-actor.c:3826
+#: clutter/clutter-actor.c:3824
 msgid "Position on the Z axis"
 msgstr "Posizione sull'asse Z"
 
-#: clutter/clutter-actor.c:3840
+#: clutter/clutter-actor.c:3838
 msgid "Opacity"
 msgstr "Opacità"
 
-#: clutter/clutter-actor.c:3841
+#: clutter/clutter-actor.c:3839
 msgid "Opacity of an actor"
 msgstr "Opacità di un attore"
 
-#: clutter/clutter-actor.c:3856
+#: clutter/clutter-actor.c:3854
 msgid "Visible"
 msgstr "Visibile"
 
-#: clutter/clutter-actor.c:3857
+#: clutter/clutter-actor.c:3855
 msgid "Whether the actor is visible or not"
 msgstr "Se l'attore è visibile o meno"
 
-#: clutter/clutter-actor.c:3872
+#: clutter/clutter-actor.c:3870
 msgid "Mapped"
 msgstr "Mappato"
 
-#: clutter/clutter-actor.c:3873
+#: clutter/clutter-actor.c:3871
 msgid "Whether the actor will be painted"
 msgstr "Se l'attore sarà disegnato"
 
-#: clutter/clutter-actor.c:3887
+#: clutter/clutter-actor.c:3885
 msgid "Realized"
 msgstr "Realizzato"
 
-#: clutter/clutter-actor.c:3888
+#: clutter/clutter-actor.c:3886
 msgid "Whether the actor has been realized"
 msgstr "Se l'attore è stato realizzato"
 
-#: clutter/clutter-actor.c:3904
+#: clutter/clutter-actor.c:3902
 msgid "Reactive"
 msgstr "Reattivo"
 
-#: clutter/clutter-actor.c:3905
+#: clutter/clutter-actor.c:3903
 msgid "Whether the actor is reactive to events"
 msgstr "Se l'attore è reattivo agli eventi"
 
-#: clutter/clutter-actor.c:3917
+#: clutter/clutter-actor.c:3915
 msgid "Has Clip"
 msgstr ""
 
-#: clutter/clutter-actor.c:3918
+#: clutter/clutter-actor.c:3916
 msgid "Whether the actor has a clip set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3933
+#: clutter/clutter-actor.c:3931
 msgid "Clip"
 msgstr ""
 
-#: clutter/clutter-actor.c:3934
+#: clutter/clutter-actor.c:3932
 msgid "The clip region for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3948 clutter/clutter-actor-meta.c:205
-#: clutter/clutter-binding-pool.c:320 clutter/clutter-input-device.c:151
+#: clutter/clutter-actor.c:3946 clutter/clutter-actor-meta.c:205
+#: clutter/clutter-binding-pool.c:319 clutter/clutter-input-device.c:235
 msgid "Name"
 msgstr "Nome"
 
-#: clutter/clutter-actor.c:3949
+#: clutter/clutter-actor.c:3947
 msgid "Name of the actor"
 msgstr "Nome dell'attore"
 
-#: clutter/clutter-actor.c:3963
+#: clutter/clutter-actor.c:3961
 msgid "Scale X"
 msgstr "Scala X"
 
-#: clutter/clutter-actor.c:3964
+#: clutter/clutter-actor.c:3962
 msgid "Scale factor on the X axis"
 msgstr "Fattore di scala sull'asse X"
 
-#: clutter/clutter-actor.c:3979
+#: clutter/clutter-actor.c:3977
 msgid "Scale Y"
 msgstr "Scala Y"
 
-#: clutter/clutter-actor.c:3980
+#: clutter/clutter-actor.c:3978
 msgid "Scale factor on the Y axis"
 msgstr "Fattore di scala sull'asse Y"
 
-#: clutter/clutter-actor.c:3995
+#: clutter/clutter-actor.c:3993
 msgid "Scale Center X"
 msgstr "Scala centrale X"
 
-#: clutter/clutter-actor.c:3996
+#: clutter/clutter-actor.c:3994
 msgid "Horizontal scale center"
 msgstr "Scala centrale orizzontale"
 
-#: clutter/clutter-actor.c:4011
+#: clutter/clutter-actor.c:4009
 msgid "Scale Center Y"
 msgstr "Scala centrale Y"
 
-#: clutter/clutter-actor.c:4012
+#: clutter/clutter-actor.c:4010
 msgid "Vertical scale center"
 msgstr "Scala centrale verticale"
 
-#: clutter/clutter-actor.c:4027
+#: clutter/clutter-actor.c:4025
 msgid "Scale Gravity"
 msgstr "Scala di gravità"
 
-#: clutter/clutter-actor.c:4028
+#: clutter/clutter-actor.c:4026
 msgid "The center of scaling"
 msgstr "Il centro della scala"
 
-#: clutter/clutter-actor.c:4045
+#: clutter/clutter-actor.c:4043
 msgid "Rotation Angle X"
 msgstr "Angolo di rotazione X"
 
-#: clutter/clutter-actor.c:4046
+#: clutter/clutter-actor.c:4044
 msgid "The rotation angle on the X axis"
 msgstr "L'angolo di rotazione sull'asse X"
 
-#: clutter/clutter-actor.c:4061
+#: clutter/clutter-actor.c:4059
 msgid "Rotation Angle Y"
 msgstr "Angolo di rotazione Y"
 
-#: clutter/clutter-actor.c:4062
+#: clutter/clutter-actor.c:4060
 msgid "The rotation angle on the Y axis"
 msgstr "L'angolo di rotazione sull'asse Y"
 
-#: clutter/clutter-actor.c:4077
+#: clutter/clutter-actor.c:4075
 msgid "Rotation Angle Z"
 msgstr "Angolo di rotazione Z"
 
-#: clutter/clutter-actor.c:4078
+#: clutter/clutter-actor.c:4076
 msgid "The rotation angle on the Z axis"
 msgstr "L'angolo di rotazione sull'asse Z"
 
-#: clutter/clutter-actor.c:4093
+#: clutter/clutter-actor.c:4091
 msgid "Rotation Center X"
 msgstr "Rotazione centrale X"
 
-#: clutter/clutter-actor.c:4094
+#: clutter/clutter-actor.c:4092
 msgid "The rotation center on the X axis"
 msgstr "La rotazione centrale sull'asse X"
 
-#: clutter/clutter-actor.c:4110
+#: clutter/clutter-actor.c:4108
 msgid "Rotation Center Y"
 msgstr "Rotazione centrale Y"
 
-#: clutter/clutter-actor.c:4111
+#: clutter/clutter-actor.c:4109
 msgid "The rotation center on the Y axis"
 msgstr "La rotazione centrale sull'asse Y"
 
-#: clutter/clutter-actor.c:4127
+#: clutter/clutter-actor.c:4125
 msgid "Rotation Center Z"
 msgstr "Rotazione centrale Z"
 
-#: clutter/clutter-actor.c:4128
+#: clutter/clutter-actor.c:4126
 msgid "The rotation center on the Z axis"
 msgstr "La rotazione centrale sull'asse Z"
 
-#: clutter/clutter-actor.c:4144
+#: clutter/clutter-actor.c:4142
 msgid "Rotation Center Z Gravity"
 msgstr "Gravità della rotazione centrale Z"
 
-#: clutter/clutter-actor.c:4145
+#: clutter/clutter-actor.c:4143
 msgid "Center point for rotation around the Z axis"
 msgstr "Punto centrale per la rotazione sull'asse Z"
 
-#: clutter/clutter-actor.c:4163
+#: clutter/clutter-actor.c:4161
 msgid "Anchor X"
 msgstr "Ancoraggio X"
 
-#: clutter/clutter-actor.c:4164
+#: clutter/clutter-actor.c:4162
 msgid "X coordinate of the anchor point"
 msgstr "Coordinata X del punto di ancoraggio"
 
-#: clutter/clutter-actor.c:4180
+#: clutter/clutter-actor.c:4178
 msgid "Anchor Y"
 msgstr "Ancoraggio Y"
 
-#: clutter/clutter-actor.c:4181
+#: clutter/clutter-actor.c:4179
 msgid "Y coordinate of the anchor point"
 msgstr "Coordinata Y del punto di ancoraggio"
 
-#: clutter/clutter-actor.c:4196
+#: clutter/clutter-actor.c:4194
 msgid "Anchor Gravity"
 msgstr "Gravità di ancoraggio"
 
-#: clutter/clutter-actor.c:4197
+#: clutter/clutter-actor.c:4195
 #, fuzzy
 msgid "The anchor point as a ClutterGravity"
 msgstr "Il punto di ancoraggio come ClutterGravity"
 
-#: clutter/clutter-actor.c:4216
+#: clutter/clutter-actor.c:4214
 msgid "Show on set parent"
 msgstr "Mostra su imposta genitore"
 
-#: clutter/clutter-actor.c:4217
+#: clutter/clutter-actor.c:4215
 msgid "Whether the actor is shown when parented"
 msgstr "Se l'attore è mostrato quando genitore"
 
-#: clutter/clutter-actor.c:4237
+#: clutter/clutter-actor.c:4235
 msgid "Clip to Allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:4238
+#: clutter/clutter-actor.c:4236
 msgid "Sets the clip region to track the actor's allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:4248
+#: clutter/clutter-actor.c:4246
 msgid "Text Direction"
 msgstr "Direzione del testo"
 
-#: clutter/clutter-actor.c:4249
+#: clutter/clutter-actor.c:4247
 msgid "Direction of the text"
 msgstr "Direzione del testo"
 
-#: clutter/clutter-actor.c:4267
+#: clutter/clutter-actor.c:4265
 msgid "Has Pointer"
 msgstr "Ha il puntatore"
 
-#: clutter/clutter-actor.c:4268
+#: clutter/clutter-actor.c:4266
 msgid "Whether the actor contains the pointer of an input device"
 msgstr "Se l'attore contiene il puntatore di un dispositivo di input"
 
-#: clutter/clutter-actor.c:4285
+#: clutter/clutter-actor.c:4283
 msgid "Actions"
 msgstr "Azioni"
 
-#: clutter/clutter-actor.c:4286
+#: clutter/clutter-actor.c:4284
 msgid "Adds an action to the actor"
 msgstr "Aggiunge un'azione per l'attore"
 
-#: clutter/clutter-actor.c:4300
+#: clutter/clutter-actor.c:4298
 msgid "Constraints"
 msgstr "Vincoli"
 
-#: clutter/clutter-actor.c:4301
+#: clutter/clutter-actor.c:4299
 msgid "Adds a constraint to the actor"
 msgstr "Aggiunge un vincolo per l'attore"
 
@@ -407,7 +407,8 @@ msgstr "L'attore collegato al meta"
 msgid "The name of the meta"
 msgstr "Il nome del meta"
 
-#: clutter/clutter-actor-meta.c:219 clutter/clutter-shader.c:261
+#: clutter/clutter-actor-meta.c:219 clutter/clutter-input-device.c:314
+#: clutter/clutter-shader.c:295
 msgid "Enabled"
 msgstr "Attivato"
 
@@ -415,34 +416,34 @@ msgstr "Attivato"
 msgid "Whether the meta is enabled"
 msgstr "Se il meta è attivato"
 
-#: clutter/clutter-align-constraint.c:231
-#: clutter/clutter-bind-constraint.c:286 clutter/clutter-clone.c:322
+#: clutter/clutter-align-constraint.c:252
+#: clutter/clutter-bind-constraint.c:316 clutter/clutter-clone.c:322
 msgid "Source"
 msgstr "Origine"
 
-#: clutter/clutter-align-constraint.c:232
+#: clutter/clutter-align-constraint.c:253
 msgid "The source of the alignment"
 msgstr "L'origine dell'allineamento"
 
-#: clutter/clutter-align-constraint.c:245
+#: clutter/clutter-align-constraint.c:266
 msgid "Align Axis"
 msgstr "Allinea le assi"
 
-#: clutter/clutter-align-constraint.c:246
+#: clutter/clutter-align-constraint.c:267
 msgid "The axis to align the position to"
 msgstr "Le assi alle quali allineare la posizione"
 
-#: clutter/clutter-align-constraint.c:265
-#: clutter/clutter-desaturate-effect.c:309
+#: clutter/clutter-align-constraint.c:286
+#: clutter/clutter-desaturate-effect.c:307
 msgid "Factor"
 msgstr "Fattore"
 
-#: clutter/clutter-align-constraint.c:266
+#: clutter/clutter-align-constraint.c:287
 msgid "The alignment factor, between 0.0 and 1.0"
 msgstr "Il fattore di allineamento, tra 0.0 e 1.0"
 
 #: clutter/clutter-alpha.c:339 clutter/clutter-animation.c:523
-#: clutter/clutter-animator.c:1801
+#: clutter/clutter-animator.c:1802
 msgid "Timeline"
 msgstr ""
 
@@ -478,7 +479,7 @@ msgstr "Oggetto a cui l'animazione si applica"
 msgid "The mode of the animation"
 msgstr "La modalità di animazione"
 
-#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1785
+#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1786
 #: clutter/clutter-media.c:194 clutter/clutter-state.c:1282
 msgid "Duration"
 msgstr "Durata"
@@ -499,7 +500,7 @@ msgstr "Se l'animazione deve ciclare"
 msgid "The timeline used by the animation"
 msgstr ""
 
-#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:299
+#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:298
 msgid "Alpha"
 msgstr "Alpha"
 
@@ -507,216 +508,216 @@ msgstr "Alpha"
 msgid "The alpha used by the animation"
 msgstr "L'alpha usato dall'animazione"
 
-#: clutter/clutter-animator.c:1786
+#: clutter/clutter-animator.c:1787
 msgid "The duration of the animation"
 msgstr "La durata dell'animazione"
 
-#: clutter/clutter-animator.c:1802
+#: clutter/clutter-animator.c:1803
 #, fuzzy
 msgid "The timeline of the animation"
 msgstr "La timeline di animazione"
 
-#: clutter/clutter-behaviour.c:300
+#: clutter/clutter-behaviour.c:299
 msgid "Alpha Object to drive the behaviour"
 msgstr "Oggetto alpha per guidare il comportamento"
 
-#: clutter/clutter-behaviour-depth.c:175
+#: clutter/clutter-behaviour-depth.c:174
 msgid "Start Depth"
 msgstr "Profondità iniziale"
 
-#: clutter/clutter-behaviour-depth.c:176
+#: clutter/clutter-behaviour-depth.c:175
 msgid "Initial depth to apply"
 msgstr "Profondità iniziale da applicare"
 
-#: clutter/clutter-behaviour-depth.c:191
+#: clutter/clutter-behaviour-depth.c:190
 msgid "End Depth"
 msgstr "Profondità finale"
 
-#: clutter/clutter-behaviour-depth.c:192
+#: clutter/clutter-behaviour-depth.c:191
 msgid "Final depth to apply"
 msgstr "Profondità finale da applicare"
 
-#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-ellipse.c:394
 msgid "Start Angle"
 msgstr "Angolo iniziale"
 
-#: clutter/clutter-behaviour-ellipse.c:396
-#: clutter/clutter-behaviour-rotate.c:277
+#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-rotate.c:276
 msgid "Initial angle"
 msgstr "Angolo iniziale"
 
-#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-ellipse.c:410
 msgid "End Angle"
 msgstr "Angolo finale"
 
-#: clutter/clutter-behaviour-ellipse.c:412
-#: clutter/clutter-behaviour-rotate.c:295
+#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-rotate.c:294
 msgid "Final angle"
 msgstr "Angolo finale"
 
-#: clutter/clutter-behaviour-ellipse.c:427
+#: clutter/clutter-behaviour-ellipse.c:426
 msgid "Angle x tilt"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:428
+#: clutter/clutter-behaviour-ellipse.c:427
 msgid "Tilt of the ellipse around x axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:443
+#: clutter/clutter-behaviour-ellipse.c:442
 msgid "Angle y tilt"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:444
+#: clutter/clutter-behaviour-ellipse.c:443
 msgid "Tilt of the ellipse around y axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:459
+#: clutter/clutter-behaviour-ellipse.c:458
 msgid "Angle z tilt"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:460
+#: clutter/clutter-behaviour-ellipse.c:459
 msgid "Tilt of the ellipse around z axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:476
+#: clutter/clutter-behaviour-ellipse.c:475
 msgid "Width of the ellipse"
 msgstr "Larghezza dell'ellisse"
 
-#: clutter/clutter-behaviour-ellipse.c:492
+#: clutter/clutter-behaviour-ellipse.c:491
 msgid "Height of ellipse"
 msgstr "Altezza dell'ellisse"
 
-#: clutter/clutter-behaviour-ellipse.c:507
+#: clutter/clutter-behaviour-ellipse.c:506
 msgid "Center"
 msgstr "Centro"
 
-#: clutter/clutter-behaviour-ellipse.c:508
+#: clutter/clutter-behaviour-ellipse.c:507
 msgid "Center of ellipse"
 msgstr "Centro dell'ellisse"
 
-#: clutter/clutter-behaviour-ellipse.c:522
-#: clutter/clutter-behaviour-rotate.c:330
+#: clutter/clutter-behaviour-ellipse.c:521
+#: clutter/clutter-behaviour-rotate.c:329
 msgid "Direction"
 msgstr "Direzione"
 
-#: clutter/clutter-behaviour-ellipse.c:523
-#: clutter/clutter-behaviour-rotate.c:331
+#: clutter/clutter-behaviour-ellipse.c:522
+#: clutter/clutter-behaviour-rotate.c:330
 msgid "Direction of rotation"
 msgstr "Direzione della rotazione"
 
-#: clutter/clutter-behaviour-opacity.c:178
+#: clutter/clutter-behaviour-opacity.c:177
 msgid "Opacity Start"
 msgstr "Opacità iniziale"
 
-#: clutter/clutter-behaviour-opacity.c:179
+#: clutter/clutter-behaviour-opacity.c:178
 msgid "Initial opacity level"
 msgstr "Livello di opacità iniziale"
 
-#: clutter/clutter-behaviour-opacity.c:196
+#: clutter/clutter-behaviour-opacity.c:195
 msgid "Opacity End"
 msgstr "Opacità finale"
 
-#: clutter/clutter-behaviour-opacity.c:197
+#: clutter/clutter-behaviour-opacity.c:196
 msgid "Final opacity level"
 msgstr "Livello di opacità finale"
 
-#: clutter/clutter-behaviour-path.c:220
+#: clutter/clutter-behaviour-path.c:219
 msgid "Path"
 msgstr "Percorso"
 
-#: clutter/clutter-behaviour-path.c:221
+#: clutter/clutter-behaviour-path.c:220
 msgid "The ClutterPath object representing the path to animate along"
 msgstr "L'oggetto ClutterPath che rappresenta il percorso dell'animazione"
 
-#: clutter/clutter-behaviour-rotate.c:276
+#: clutter/clutter-behaviour-rotate.c:275
 msgid "Angle Begin"
 msgstr "Angolo iniziale"
 
-#: clutter/clutter-behaviour-rotate.c:294
+#: clutter/clutter-behaviour-rotate.c:293
 msgid "Angle End"
 msgstr "Angolo finale"
 
-#: clutter/clutter-behaviour-rotate.c:312
+#: clutter/clutter-behaviour-rotate.c:311
 msgid "Axis"
 msgstr "Assi"
 
-#: clutter/clutter-behaviour-rotate.c:313
+#: clutter/clutter-behaviour-rotate.c:312
 msgid "Axis of rotation"
 msgstr "Assi di rotazione"
 
-#: clutter/clutter-behaviour-rotate.c:348
+#: clutter/clutter-behaviour-rotate.c:347
 msgid "Center X"
 msgstr "Centro X"
 
-#: clutter/clutter-behaviour-rotate.c:349
+#: clutter/clutter-behaviour-rotate.c:348
 msgid "X coordinate of the center of rotation"
 msgstr "Coordinata X del centro di rotazione"
 
-#: clutter/clutter-behaviour-rotate.c:366
+#: clutter/clutter-behaviour-rotate.c:365
 msgid "Center Y"
 msgstr "Centro Y"
 
-#: clutter/clutter-behaviour-rotate.c:367
+#: clutter/clutter-behaviour-rotate.c:366
 msgid "Y coordinate of the center of rotation"
 msgstr "Coordinata Y del centro di rotazione"
 
-#: clutter/clutter-behaviour-rotate.c:384
+#: clutter/clutter-behaviour-rotate.c:383
 msgid "Center Z"
 msgstr "Centro"
 
-#: clutter/clutter-behaviour-rotate.c:385
+#: clutter/clutter-behaviour-rotate.c:384
 msgid "Z coordinate of the center of rotation"
 msgstr "Coordinata Z del centro di rotazione"
 
-#: clutter/clutter-behaviour-scale.c:219
+#: clutter/clutter-behaviour-scale.c:218
 msgid "X Start Scale"
 msgstr "Scala iniziale X"
 
-#: clutter/clutter-behaviour-scale.c:220
+#: clutter/clutter-behaviour-scale.c:219
 msgid "Initial scale on the X axis"
 msgstr "Scala iniziale sull'asse X"
 
-#: clutter/clutter-behaviour-scale.c:238
+#: clutter/clutter-behaviour-scale.c:237
 msgid "X End Scale"
 msgstr "Scala finale X"
 
-#: clutter/clutter-behaviour-scale.c:239
+#: clutter/clutter-behaviour-scale.c:238
 msgid "Final scale on the X axis"
 msgstr "Scala finale sull'asse X"
 
-#: clutter/clutter-behaviour-scale.c:257
+#: clutter/clutter-behaviour-scale.c:256
 msgid "Y Start Scale"
 msgstr "Scala iniziale Y"
 
-#: clutter/clutter-behaviour-scale.c:258
+#: clutter/clutter-behaviour-scale.c:257
 msgid "Initial scale on the Y axis"
 msgstr "Scala iniziale sull'asse U"
 
-#: clutter/clutter-behaviour-scale.c:276
+#: clutter/clutter-behaviour-scale.c:275
 msgid "Y End Scale"
 msgstr "Scala finale Y"
 
-#: clutter/clutter-behaviour-scale.c:277
+#: clutter/clutter-behaviour-scale.c:276
 msgid "Final scale on the Y axis"
 msgstr "Scala finale sull'asse Y"
 
-#: clutter/clutter-bind-constraint.c:287
+#: clutter/clutter-bind-constraint.c:317
 msgid "The source of the binding"
 msgstr "L'origine dell'associazione"
 
-#: clutter/clutter-bind-constraint.c:300
+#: clutter/clutter-bind-constraint.c:330
 msgid "Coordinate"
 msgstr "Coordinata"
 
-#: clutter/clutter-bind-constraint.c:301
+#: clutter/clutter-bind-constraint.c:331
 msgid "The coordinate to bind"
 msgstr "La coordinata da associare"
 
-#: clutter/clutter-bind-constraint.c:315
+#: clutter/clutter-bind-constraint.c:345
 msgid "Offset"
 msgstr "Spostamento"
 
-#: clutter/clutter-bind-constraint.c:316
+#: clutter/clutter-bind-constraint.c:346
 msgid "The offset in pixels to apply to the binding"
 msgstr "Lo spostamento in pixel da applicare all'associazione"
 
@@ -748,7 +749,7 @@ msgid "Default vertical alignment for the actors inside the layout manager"
 msgstr ""
 "Allineamento verticale predefinito per l'attore dentro il gestore di layout"
 
-#: clutter/clutter-binding-pool.c:321
+#: clutter/clutter-binding-pool.c:320
 msgid "The unique name of the binding pool"
 msgstr "Il nome unico dell'insieme di associazione"
 
@@ -761,7 +762,7 @@ msgid "The layout manager used by the box"
 msgstr "Il gestore di layout usato dal box"
 
 #: clutter/clutter-box.c:514 clutter/clutter-rectangle.c:258
-#: clutter/clutter-stage.c:1307
+#: clutter/clutter-stage.c:1317
 msgid "Color"
 msgstr "Colore"
 
@@ -904,19 +905,19 @@ msgstr "Il contenitore che ha creato questo dato"
 msgid "The actor wrapped by this data"
 msgstr ""
 
-#: clutter/clutter-click-action.c:283
+#: clutter/clutter-click-action.c:302
 msgid "Pressed"
 msgstr "Premuto"
 
-#: clutter/clutter-click-action.c:284
+#: clutter/clutter-click-action.c:303
 msgid "Whether the clickable should be in pressed state"
 msgstr "Se il cliccabile dovrebbe essere in stato premuto"
 
-#: clutter/clutter-click-action.c:297
+#: clutter/clutter-click-action.c:316
 msgid "Held"
 msgstr "Mantenuto"
 
-#: clutter/clutter-click-action.c:298
+#: clutter/clutter-click-action.c:317
 msgid "Whether the clickable has a grab"
 msgstr "Se il cliccabile ha la maniglia"
 
@@ -924,11 +925,11 @@ msgstr "Se il cliccabile ha la maniglia"
 msgid "Specifies the actor to be cloned"
 msgstr "Specifica l'attore da clonare"
 
-#: clutter/clutter-colorize-effect.c:309
+#: clutter/clutter-colorize-effect.c:307
 msgid "Tint"
 msgstr "Tinta"
 
-#: clutter/clutter-colorize-effect.c:310
+#: clutter/clutter-colorize-effect.c:308
 msgid "The tint to apply"
 msgstr "La tinta da applicare"
 
@@ -956,11 +957,11 @@ msgstr "Materiale posteriore"
 msgid "The material to be used when painting the back of the actor"
 msgstr "Il materiale da usare nel disegno del posteriore dell'attore"
 
-#: clutter/clutter-desaturate-effect.c:310
+#: clutter/clutter-desaturate-effect.c:308
 msgid "The desaturation factor"
 msgstr "Il fattore desaturazione"
 
-#: clutter/clutter-device-manager.c:130
+#: clutter/clutter-device-manager.c:130 clutter/clutter-input-device.c:343
 msgid "Backend"
 msgstr ""
 
@@ -968,35 +969,35 @@ msgstr ""
 msgid "The ClutterBackend of the device manager"
 msgstr "Il ClutterBackend del gestore di dispositivo"
 
-#: clutter/clutter-drag-action.c:490
+#: clutter/clutter-drag-action.c:491
 msgid "Horizontal Drag Threshold"
 msgstr "Soglia di trascinamento orizzontale"
 
-#: clutter/clutter-drag-action.c:491
+#: clutter/clutter-drag-action.c:492
 msgid "The horizontal amount of pixels required to start dragging"
 msgstr "Il numero di pixel orizzontali richiesto per iniziare il trascinamento"
 
-#: clutter/clutter-drag-action.c:510
+#: clutter/clutter-drag-action.c:511
 msgid "Vertical Drag Threshold"
 msgstr "Soglia di trascinamento verticale"
 
-#: clutter/clutter-drag-action.c:511
+#: clutter/clutter-drag-action.c:512
 msgid "The vertical amount of pixels required to start dragging"
 msgstr "Il numero di pixel verticali richiesto per iniziare il trascinamento"
 
-#: clutter/clutter-drag-action.c:532
+#: clutter/clutter-drag-action.c:533
 msgid "Drag Handle"
 msgstr "Maniglia di trascinamento"
 
-#: clutter/clutter-drag-action.c:533
+#: clutter/clutter-drag-action.c:534
 msgid "The actor that is being dragged"
 msgstr "L'attore che si sta trascinando"
 
-#: clutter/clutter-drag-action.c:546
+#: clutter/clutter-drag-action.c:547
 msgid "Drag Axis"
 msgstr "Asse di trascinamento"
 
-#: clutter/clutter-drag-action.c:547
+#: clutter/clutter-drag-action.c:548
 msgid "Constraints the dragging to an axis"
 msgstr "Vincoli di trascinamento di un asse"
 
@@ -1060,26 +1061,73 @@ msgstr "Altezza di riga massima"
 msgid "Maximum height for each row"
 msgstr "Altezza massima di ogni riga"
 
-#: clutter/clutter-input-device.c:134
+#: clutter/clutter-input-device.c:219
 msgid "Id"
 msgstr "Id"
 
-#: clutter/clutter-input-device.c:135
+#: clutter/clutter-input-device.c:220
 msgid "Unique identifier of the device"
 msgstr "Identificativo unico del dispositivo"
 
-#: clutter/clutter-input-device.c:152
+#: clutter/clutter-input-device.c:236
 msgid "The name of the device"
 msgstr "Il nome del dispositivo"
 
-#: clutter/clutter-input-device.c:167
+#: clutter/clutter-input-device.c:250
 msgid "Device Type"
 msgstr "Tipo di dispositivo"
 
-#: clutter/clutter-input-device.c:168
+#: clutter/clutter-input-device.c:251
 msgid "The type of the device"
 msgstr "Il tipo di dispositivo"
 
+#: clutter/clutter-input-device.c:266
+#, fuzzy
+msgid "Device Manager"
+msgstr "Gestore"
+
+#: clutter/clutter-input-device.c:267
+msgid "The device manager instance"
+msgstr ""
+
+#: clutter/clutter-input-device.c:280
+#, fuzzy
+msgid "Device Mode"
+msgstr "Tipo di dispositivo"
+
+#: clutter/clutter-input-device.c:281
+#, fuzzy
+msgid "The mode of the device"
+msgstr "Il nome del dispositivo"
+
+#: clutter/clutter-input-device.c:295
+#, fuzzy
+msgid "Has Cursor"
+msgstr "Ha bordo"
+
+#: clutter/clutter-input-device.c:296
+#, fuzzy
+msgid "Whether the device has a cursor"
+msgstr "Se il cliccabile ha la maniglia"
+
+#: clutter/clutter-input-device.c:315
+#, fuzzy
+msgid "Whether the device is enabled"
+msgstr "Se l'ombreggiatore è abilitato"
+
+#: clutter/clutter-input-device.c:328
+msgid "Number of Axes"
+msgstr ""
+
+#: clutter/clutter-input-device.c:329
+#, fuzzy
+msgid "The number of axes on the device"
+msgstr "Il nome del dispositivo"
+
+#: clutter/clutter-input-device.c:344
+msgid "The backend instance"
+msgstr ""
+
 #: clutter/clutter-interval.c:397
 msgid "Value Type"
 msgstr "Tipo di valore"
@@ -1096,59 +1144,59 @@ msgstr "Gestore"
 msgid "The manager that created this data"
 msgstr "Il gestore che ha creato questo dato"
 
-#: clutter/clutter-main.c:756
+#: clutter/clutter-main.c:753
 msgid "default:LTR"
 msgstr "default:LTR"
 
-#: clutter/clutter-main.c:1560
+#: clutter/clutter-main.c:1557
 msgid "Show frames per second"
 msgstr "Mostra i fotogrammi per secondo"
 
-#: clutter/clutter-main.c:1562
+#: clutter/clutter-main.c:1559
 msgid "Default frame rate"
 msgstr "Framerate predefinito"
 
-#: clutter/clutter-main.c:1564
+#: clutter/clutter-main.c:1561
 msgid "Make all warnings fatal"
 msgstr "Rende tutti i warning critici"
 
-#: clutter/clutter-main.c:1567
+#: clutter/clutter-main.c:1564
 msgid "Direction for the text"
 msgstr "Direzione del testo"
 
-#: clutter/clutter-main.c:1570
+#: clutter/clutter-main.c:1567
 msgid "Disable mipmapping on text"
 msgstr "Disabilita il mipmapping sul testo"
 
-#: clutter/clutter-main.c:1573
+#: clutter/clutter-main.c:1570
 msgid "Use 'fuzzy' picking"
 msgstr "Usa il picking \"fuzzy\""
 
-#: clutter/clutter-main.c:1576
+#: clutter/clutter-main.c:1573
 msgid "Clutter debugging flags to set"
 msgstr "Flag per il debug di Clutter da attivare"
 
-#: clutter/clutter-main.c:1578
+#: clutter/clutter-main.c:1575
 msgid "Clutter debugging flags to unset"
 msgstr "Flag per il debug di Clutter da disattivare"
 
-#: clutter/clutter-main.c:1582
+#: clutter/clutter-main.c:1579
 msgid "Clutter profiling flags to set"
 msgstr "Flag per il profiling di Clutter da attivare"
 
-#: clutter/clutter-main.c:1584
+#: clutter/clutter-main.c:1581
 msgid "Clutter profiling flags to unset"
 msgstr "Flag per il profiling di Clutter da disattivare"
 
-#: clutter/clutter-main.c:1587
+#: clutter/clutter-main.c:1584
 msgid "Enable accessibility"
 msgstr "Attiva l'accessibilità"
 
-#: clutter/clutter-main.c:1774
+#: clutter/clutter-main.c:1771
 msgid "Clutter Options"
 msgstr "Opzioni di Clutter"
 
-#: clutter/clutter-main.c:1775
+#: clutter/clutter-main.c:1772
 msgid "Show Clutter Options"
 msgstr "Mostra le opzioni di Clutter"
 
@@ -1266,48 +1314,48 @@ msgstr "Nome del file"
 msgid "The path of the currently parsed file"
 msgstr "Il percorso del file attuale analizzato"
 
-#: clutter/clutter-shader.c:215
+#: clutter/clutter-shader.c:249
 msgid "Vertex Source"
 msgstr "Origine vertice"
 
-#: clutter/clutter-shader.c:216
+#: clutter/clutter-shader.c:250
 #, fuzzy
 msgid "Source of vertex shader"
 msgstr "Origine dell'ombreggiatore di vertice"
 
-#: clutter/clutter-shader.c:230
+#: clutter/clutter-shader.c:264
 msgid "Fragment Source"
 msgstr "Origine frammento"
 
-#: clutter/clutter-shader.c:231
+#: clutter/clutter-shader.c:265
 #, fuzzy
 msgid "Source of fragment shader"
 msgstr "Origine dell'ombreggiatore di frammento"
 
-#: clutter/clutter-shader.c:246
+#: clutter/clutter-shader.c:280
 msgid "Compiled"
 msgstr "Compilato"
 
-#: clutter/clutter-shader.c:247
+#: clutter/clutter-shader.c:281
 #, fuzzy
 msgid "Whether the shader is compiled and linked"
 msgstr "Se l'ombreggiatore è compilato e collegato"
 
-#: clutter/clutter-shader.c:262
+#: clutter/clutter-shader.c:296
 #, fuzzy
 msgid "Whether the shader is enabled"
 msgstr "Se l'ombreggiatore è abilitato"
 
-#: clutter/clutter-shader.c:467
+#: clutter/clutter-shader.c:501
 #, c-format
 msgid "%s compilation failed: %s"
 msgstr "Compilazione di %s non riuscita: %s"
 
-#: clutter/clutter-shader.c:468
+#: clutter/clutter-shader.c:502
 msgid "Vertex shader"
 msgstr "Vertex shader"
 
-#: clutter/clutter-shader.c:469
+#: clutter/clutter-shader.c:503
 msgid "Fragment shader"
 msgstr "Fragment shader"
 
@@ -1321,99 +1369,109 @@ msgstr "Tipo di ombreggiatore"
 msgid "The type of shader used"
 msgstr "Il tipo di ombreggiatore usato"
 
-#: clutter/clutter-stage.c:1249
+#: clutter/clutter-stage.c:1259
 msgid "Fullscreen Set"
 msgstr "Imposta a schermo intero"
 
-#: clutter/clutter-stage.c:1250
+#: clutter/clutter-stage.c:1260
 msgid "Whether the main stage is fullscreen"
 msgstr "Se il livello principale è a schermo intero"
 
-#: clutter/clutter-stage.c:1266
+#: clutter/clutter-stage.c:1276
 msgid "Offscreen"
 msgstr "Fuorischermo"
 
-#: clutter/clutter-stage.c:1267
+#: clutter/clutter-stage.c:1277
 msgid "Whether the main stage should be rendered offscreen"
 msgstr "Se il livello principale dovrebbe essere renderizzato fuori schermo"
 
-#: clutter/clutter-stage.c:1279 clutter/clutter-text.c:2643
+#: clutter/clutter-stage.c:1289 clutter/clutter-text.c:2667
 msgid "Cursor Visible"
 msgstr "Cursore visibile"
 
-#: clutter/clutter-stage.c:1280
+#: clutter/clutter-stage.c:1290
 msgid "Whether the mouse pointer is visible on the main stage"
 msgstr "Se il puntatore del mouse è visibile sul livello principale"
 
-#: clutter/clutter-stage.c:1294
+#: clutter/clutter-stage.c:1304
 msgid "User Resizable"
 msgstr "Ridimensionabile dall'utente"
 
-#: clutter/clutter-stage.c:1295
+#: clutter/clutter-stage.c:1305
 msgid "Whether the stage is able to be resized via user interaction"
 msgstr ""
 "Se il livello può essere ridimensionato attraverso l'interazione dell'utente"
 
-#: clutter/clutter-stage.c:1308
+#: clutter/clutter-stage.c:1318
 msgid "The color of the stage"
 msgstr "Il colore del livello"
 
-#: clutter/clutter-stage.c:1322
+#: clutter/clutter-stage.c:1332
 msgid "Perspective"
 msgstr "Prospettiva"
 
-#: clutter/clutter-stage.c:1323
+#: clutter/clutter-stage.c:1333
 msgid "Perspective projection parameters"
 msgstr "Parametri di proiezione prospettica"
 
-#: clutter/clutter-stage.c:1338
+#: clutter/clutter-stage.c:1348
 msgid "Title"
 msgstr "Titolo"
 
-#: clutter/clutter-stage.c:1339
+#: clutter/clutter-stage.c:1349
 msgid "Stage Title"
 msgstr "Titolo del livello"
 
-#: clutter/clutter-stage.c:1354
+#: clutter/clutter-stage.c:1364
 msgid "Use Fog"
 msgstr "Usa nebbia"
 
-#: clutter/clutter-stage.c:1355
+#: clutter/clutter-stage.c:1365
 msgid "Whether to enable depth cueing"
 msgstr ""
 
-#: clutter/clutter-stage.c:1369
+#: clutter/clutter-stage.c:1379
 msgid "Fog"
 msgstr "Nebbia"
 
-#: clutter/clutter-stage.c:1370
+#: clutter/clutter-stage.c:1380
 msgid "Settings for the depth cueing"
 msgstr ""
 
-#: clutter/clutter-stage.c:1386
+#: clutter/clutter-stage.c:1396
 msgid "Use Alpha"
 msgstr "Usa Alpha"
 
-#: clutter/clutter-stage.c:1387
+#: clutter/clutter-stage.c:1397
 msgid "Whether to honour the alpha component of the stage color"
 msgstr "Se rispettare il componente alpha del colore del livello"
 
-#: clutter/clutter-stage.c:1403
+#: clutter/clutter-stage.c:1413
 msgid "Key Focus"
 msgstr "Fuoco chiave"
 
-#: clutter/clutter-stage.c:1404
+#: clutter/clutter-stage.c:1414
 msgid "The currently key focused actor"
 msgstr "L'attore chiave attuale con fuoco"
 
-#: clutter/clutter-stage.c:1420
+#: clutter/clutter-stage.c:1430
 msgid "No Clear Hint"
 msgstr ""
 
-#: clutter/clutter-stage.c:1421
+#: clutter/clutter-stage.c:1431
 msgid "Whether the stage should clear its contents"
 msgstr "Se il livello dovrebbe cancellare il suo contenuto"
 
+#: clutter/clutter-stage.c:1444
+#, fuzzy
+msgid "Accept Focus"
+msgstr "Fuoco chiave"
+
+#: clutter/clutter-stage.c:1445
+#, fuzzy
+msgid "Whether the stage should accept focus on show"
+msgstr "Se il livello dovrebbe cancellare il suo contenuto"
+
 #: clutter/clutter-state.c:1268
 msgid "State"
 msgstr "Stato"
@@ -1426,192 +1484,192 @@ msgstr ""
 msgid "Default transition duration"
 msgstr ""
 
-#: clutter/clutter-text.c:2530
+#: clutter/clutter-text.c:2554
 msgid "Font Name"
 msgstr "Nome carattere"
 
-#: clutter/clutter-text.c:2531
+#: clutter/clutter-text.c:2555
 msgid "The font to be used by the text"
 msgstr "Il carattere utilizzato dal testo"
 
-#: clutter/clutter-text.c:2548
+#: clutter/clutter-text.c:2572
 msgid "Font Description"
 msgstr "Descrizione carattere"
 
-#: clutter/clutter-text.c:2549
+#: clutter/clutter-text.c:2573
 msgid "The font description to be used"
 msgstr "La descrizione del carattere da usare"
 
-#: clutter/clutter-text.c:2565
+#: clutter/clutter-text.c:2589
 msgid "Text"
 msgstr "Testo"
 
-#: clutter/clutter-text.c:2566
+#: clutter/clutter-text.c:2590
 msgid "The text to render"
 msgstr "Il testo da riprodurre"
 
-#: clutter/clutter-text.c:2580
+#: clutter/clutter-text.c:2604
 msgid "Font Color"
 msgstr "Colore carattere"
 
-#: clutter/clutter-text.c:2581
+#: clutter/clutter-text.c:2605
 msgid "Color of the font used by the text"
 msgstr "Il colore del carattere usato dal testo"
 
-#: clutter/clutter-text.c:2595
+#: clutter/clutter-text.c:2619
 msgid "Editable"
 msgstr "Modificabile"
 
-#: clutter/clutter-text.c:2596
+#: clutter/clutter-text.c:2620
 msgid "Whether the text is editable"
 msgstr "Se il testo è modificabile"
 
-#: clutter/clutter-text.c:2611
+#: clutter/clutter-text.c:2635
 msgid "Selectable"
 msgstr "Selezionabile"
 
-#: clutter/clutter-text.c:2612
+#: clutter/clutter-text.c:2636
 msgid "Whether the text is selectable"
 msgstr "Se il testo è selezionabile"
 
-#: clutter/clutter-text.c:2626
+#: clutter/clutter-text.c:2650
 msgid "Activatable"
 msgstr "Attivabile"
 
-#: clutter/clutter-text.c:2627
+#: clutter/clutter-text.c:2651
 msgid "Whether pressing return causes the activate signal to be emitted"
 msgstr "Se la pressione di invio causa l'emissione del segnale activate"
 
-#: clutter/clutter-text.c:2644
+#: clutter/clutter-text.c:2668
 msgid "Whether the input cursor is visible"
 msgstr "Se il cursore di input è visibile"
 
-#: clutter/clutter-text.c:2658 clutter/clutter-text.c:2659
+#: clutter/clutter-text.c:2682 clutter/clutter-text.c:2683
 msgid "Cursor Color"
 msgstr "Colore del cursore"
 
-#: clutter/clutter-text.c:2673
+#: clutter/clutter-text.c:2697
 msgid "Cursor Color Set"
 msgstr "Imposta colore cursore"
 
-#: clutter/clutter-text.c:2674
+#: clutter/clutter-text.c:2698
 msgid "Whether the cursor color has been set"
 msgstr "Se il colore del cursore è stato impostato"
 
-#: clutter/clutter-text.c:2689
+#: clutter/clutter-text.c:2713
 msgid "Cursor Size"
 msgstr "Dimensione cursore"
 
-#: clutter/clutter-text.c:2690
+#: clutter/clutter-text.c:2714
 msgid "The width of the cursor, in pixels"
 msgstr "La larghezza del cursore, in pixel"
 
-#: clutter/clutter-text.c:2704
+#: clutter/clutter-text.c:2728
 msgid "Cursor Position"
 msgstr "Posizione cursore"
 
-#: clutter/clutter-text.c:2705
+#: clutter/clutter-text.c:2729
 msgid "The cursor position"
 msgstr "La posizione del cursore"
 
-#: clutter/clutter-text.c:2720
+#: clutter/clutter-text.c:2744
 msgid "Selection-bound"
 msgstr "Rettangolo di selezione"
 
-#: clutter/clutter-text.c:2721
+#: clutter/clutter-text.c:2745
 msgid "The cursor position of the other end of the selection"
 msgstr "La posizione del cursore dell'altro capo della selezione"
 
-#: clutter/clutter-text.c:2736 clutter/clutter-text.c:2737
+#: clutter/clutter-text.c:2760 clutter/clutter-text.c:2761
 msgid "Selection Color"
 msgstr "Colore selezione"
 
-#: clutter/clutter-text.c:2751
+#: clutter/clutter-text.c:2775
 msgid "Selection Color Set"
 msgstr "Imposta il colore selezione"
 
-#: clutter/clutter-text.c:2752
+#: clutter/clutter-text.c:2776
 msgid "Whether the selection color has been set"
 msgstr "Se il colore della selezione è stato impostato"
 
-#: clutter/clutter-text.c:2767
+#: clutter/clutter-text.c:2791
 msgid "Attributes"
 msgstr "Attributi"
 
-#: clutter/clutter-text.c:2768
+#: clutter/clutter-text.c:2792
 msgid "A list of style attributes to apply to the contents of the actor"
 msgstr "Una lista di attributi di stile da applicare ai contenuti degli attori"
 
-#: clutter/clutter-text.c:2790
+#: clutter/clutter-text.c:2814
 msgid "Use markup"
 msgstr "Usa marcatura"
 
-#: clutter/clutter-text.c:2791
+#: clutter/clutter-text.c:2815
 msgid "Whether or not the text includes Pango markup"
 msgstr "Se il testo include o meno la marcatura Pango"
 
-#: clutter/clutter-text.c:2807
+#: clutter/clutter-text.c:2831
 msgid "Line wrap"
 msgstr "Ritorno a capo"
 
-#: clutter/clutter-text.c:2808
+#: clutter/clutter-text.c:2832
 msgid "If set, wrap the lines if the text becomes too wide"
 msgstr "Se impostato, manda a capo le righe se il testo diviene troppo largo"
 
-#: clutter/clutter-text.c:2823
+#: clutter/clutter-text.c:2847
 msgid "Line wrap mode"
 msgstr "Modalità ritorno a capo"
 
-#: clutter/clutter-text.c:2824
+#: clutter/clutter-text.c:2848
 msgid "Control how line-wrapping is done"
 msgstr "Controlla come il ritorno a capo è fatto"
 
-#: clutter/clutter-text.c:2839
+#: clutter/clutter-text.c:2863
 msgid "Ellipsize"
 msgstr "Punteggiatura"
 
-#: clutter/clutter-text.c:2840
+#: clutter/clutter-text.c:2864
 msgid "The preferred place to ellipsize the string"
 msgstr "Il punto preferito per punteggiare la stringa"
 
-#: clutter/clutter-text.c:2856
+#: clutter/clutter-text.c:2880
 msgid "Line Alignment"
 msgstr "Allineamento riga"
 
-#: clutter/clutter-text.c:2857
+#: clutter/clutter-text.c:2881
 msgid "The preferred alignment for the string, for multi-line text"
 msgstr "L'allineamento preferito per la stringa, per il testo a righe multiple"
 
-#: clutter/clutter-text.c:2873
+#: clutter/clutter-text.c:2897
 msgid "Justify"
 msgstr "Giustifica"
 
-#: clutter/clutter-text.c:2874
+#: clutter/clutter-text.c:2898
 msgid "Whether the text should be justified"
 msgstr "Se il testo dovrebbe essere giustificato"
 
-#: clutter/clutter-text.c:2889
+#: clutter/clutter-text.c:2913
 msgid "Password Character"
 msgstr "Carattere password"
 
-#: clutter/clutter-text.c:2890
+#: clutter/clutter-text.c:2914
 msgid "If non-zero, use this character to display the actor's contents"
 msgstr ""
 "Se non zero, usa questo carattere per mostrare il contenuto degli attori"
 
-#: clutter/clutter-text.c:2904
+#: clutter/clutter-text.c:2928
 msgid "Max Length"
 msgstr "Lunghezza massima"
 
-#: clutter/clutter-text.c:2905
+#: clutter/clutter-text.c:2929
 msgid "Maximum length of the text inside the actor"
 msgstr "Lunghezza massima del testo all'interno dell'attore"
 
-#: clutter/clutter-text.c:2928
+#: clutter/clutter-text.c:2952
 msgid "Single Line Mode"
 msgstr "Modalità linea singola"
 
-#: clutter/clutter-text.c:2929
+#: clutter/clutter-text.c:2953
 msgid "Whether the text should be a single line"
 msgstr "Se il testo dovrebbe essere in una linea singola"
 
@@ -1740,23 +1798,23 @@ msgstr "Cattura con Alpha"
 msgid "Shape actor with alpha channel when picking"
 msgstr "Attore di forma con canale alpha nella cattura"
 
-#: clutter/glx/clutter-backend-glx.c:128
+#: clutter/glx/clutter-backend-glx.c:131
 msgid "VBlank method to be used (none, dri or glx)"
 msgstr "Metodo VBlank da usare (none, dri o glx)"
 
-#: clutter/x11/clutter-backend-x11.c:364
+#: clutter/x11/clutter-backend-x11.c:473
 msgid "X display to use"
 msgstr "Display X da usare"
 
-#: clutter/x11/clutter-backend-x11.c:370
+#: clutter/x11/clutter-backend-x11.c:479
 msgid "X screen to use"
 msgstr "Schermo X da usare"
 
-#: clutter/x11/clutter-backend-x11.c:375
+#: clutter/x11/clutter-backend-x11.c:484
 msgid "Make X calls synchronous"
 msgstr "Rende le chiamate a X sincrone"
 
-#: clutter/x11/clutter-backend-x11.c:382
+#: clutter/x11/clutter-backend-x11.c:491
 msgid "Enable XInput support"
 msgstr "Abilita il supporto a XInput"
 
index 76983d8..4425f52 100644 (file)
--- a/po/pl.po
+++ b/po/pl.po
@@ -6,7 +6,7 @@ msgstr ""
 "Project-Id-Version: pl\n"
 "Report-Msgid-Bugs-To: http://bugzilla.clutter-project.org/enter_bug.cgi?"
 "product=clutter\n"
-"POT-Creation-Date: 2010-12-17 15:51+0000\n"
+"POT-Creation-Date: 2011-02-07 15:50+0000\n"
 "PO-Revision-Date: 2010-10-01 17:03+0200\n"
 "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
 "Language-Team: Polish <trans-pl@lists.fedoraproject.org>\n"
@@ -17,380 +17,380 @@ msgstr ""
 "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
 "|| n%100>=20) ? 1 : 2);\n"
 
-#: clutter/clutter-actor.c:3480
+#: clutter/clutter-actor.c:3478
 msgid "X coordinate"
 msgstr "Współrzędna X"
 
-#: clutter/clutter-actor.c:3481
+#: clutter/clutter-actor.c:3479
 msgid "X coordinate of the actor"
 msgstr "Współrzędna X aktora"
 
-#: clutter/clutter-actor.c:3496
+#: clutter/clutter-actor.c:3494
 msgid "Y coordinate"
 msgstr "Współrzędna Y"
 
-#: clutter/clutter-actor.c:3497
+#: clutter/clutter-actor.c:3495
 msgid "Y coordinate of the actor"
 msgstr "Współrzędna Y aktora"
 
-#: clutter/clutter-actor.c:3512 clutter/clutter-behaviour-ellipse.c:475
+#: clutter/clutter-actor.c:3510 clutter/clutter-behaviour-ellipse.c:474
 msgid "Width"
 msgstr "Szerokość"
 
-#: clutter/clutter-actor.c:3513
+#: clutter/clutter-actor.c:3511
 msgid "Width of the actor"
 msgstr "Szerokość aktora"
 
-#: clutter/clutter-actor.c:3527 clutter/clutter-behaviour-ellipse.c:491
+#: clutter/clutter-actor.c:3525 clutter/clutter-behaviour-ellipse.c:490
 msgid "Height"
 msgstr "Wysokość"
 
-#: clutter/clutter-actor.c:3528
+#: clutter/clutter-actor.c:3526
 msgid "Height of the actor"
 msgstr "Wysokość aktora"
 
-#: clutter/clutter-actor.c:3546
+#: clutter/clutter-actor.c:3544
 msgid "Fixed X"
 msgstr "Stała współrzędna X"
 
-#: clutter/clutter-actor.c:3547
+#: clutter/clutter-actor.c:3545
 msgid "Forced X position of the actor"
 msgstr "Wymuszone położenie X aktora"
 
-#: clutter/clutter-actor.c:3565
+#: clutter/clutter-actor.c:3563
 msgid "Fixed Y"
 msgstr "Stała współrzędna Y"
 
-#: clutter/clutter-actor.c:3566
+#: clutter/clutter-actor.c:3564
 msgid "Forced Y position of the actor"
 msgstr "Wymuszone położenie Y aktora"
 
-#: clutter/clutter-actor.c:3582
+#: clutter/clutter-actor.c:3580
 msgid "Fixed position set"
 msgstr "Ustawienie stałego położenia"
 
-#: clutter/clutter-actor.c:3583
+#: clutter/clutter-actor.c:3581
 msgid "Whether to use fixed positioning for the actor"
 msgstr "Określa, czy używać stałego położenia aktora"
 
-#: clutter/clutter-actor.c:3605
+#: clutter/clutter-actor.c:3603
 msgid "Min Width"
 msgstr "Minimalna szerokość"
 
-#: clutter/clutter-actor.c:3606
+#: clutter/clutter-actor.c:3604
 msgid "Forced minimum width request for the actor"
 msgstr "Wymuszone żądanie minimalnej szerokości aktora"
 
-#: clutter/clutter-actor.c:3625
+#: clutter/clutter-actor.c:3623
 msgid "Min Height"
 msgstr "Minimalna wysokość"
 
-#: clutter/clutter-actor.c:3626
+#: clutter/clutter-actor.c:3624
 msgid "Forced minimum height request for the actor"
 msgstr "Wymuszone żądanie minimalnej wysokości aktora"
 
-#: clutter/clutter-actor.c:3645
+#: clutter/clutter-actor.c:3643
 msgid "Natural Width"
 msgstr "Naturalna szerokość"
 
-#: clutter/clutter-actor.c:3646
+#: clutter/clutter-actor.c:3644
 msgid "Forced natural width request for the actor"
 msgstr "Wymuszone żądanie naturalnej szerokości aktora"
 
-#: clutter/clutter-actor.c:3665
+#: clutter/clutter-actor.c:3663
 msgid "Natural Height"
 msgstr "Naturalna wysokość"
 
-#: clutter/clutter-actor.c:3666
+#: clutter/clutter-actor.c:3664
 msgid "Forced natural height request for the actor"
 msgstr "Wymuszone żądanie naturalnej wysokości aktora"
 
-#: clutter/clutter-actor.c:3682
+#: clutter/clutter-actor.c:3680
 msgid "Minimum width set"
 msgstr "Ustawienie minimalnej szerokości"
 
-#: clutter/clutter-actor.c:3683
+#: clutter/clutter-actor.c:3681
 msgid "Whether to use the min-width property"
 msgstr "Określa, czy używać właściwości \"min-width\""
 
-#: clutter/clutter-actor.c:3698
+#: clutter/clutter-actor.c:3696
 msgid "Minimum height set"
 msgstr "Ustawienie minimalnej wysokości"
 
-#: clutter/clutter-actor.c:3699
+#: clutter/clutter-actor.c:3697
 msgid "Whether to use the min-height property"
 msgstr "Określa, czy używać właściwości \"min-height\""
 
-#: clutter/clutter-actor.c:3714
+#: clutter/clutter-actor.c:3712
 msgid "Natural width set"
 msgstr "Ustawienie naturalnej szerokości"
 
-#: clutter/clutter-actor.c:3715
+#: clutter/clutter-actor.c:3713
 msgid "Whether to use the natural-width property"
 msgstr "Określa, czy używać właściwości \"natural-width\""
 
-#: clutter/clutter-actor.c:3732
+#: clutter/clutter-actor.c:3730
 msgid "Natural height set"
 msgstr "Ustawienie naturalnej wysokości"
 
-#: clutter/clutter-actor.c:3733
+#: clutter/clutter-actor.c:3731
 msgid "Whether to use the natural-height property"
 msgstr "Określa, czy używać właściwości \"natural-height\""
 
-#: clutter/clutter-actor.c:3752
+#: clutter/clutter-actor.c:3750
 msgid "Allocation"
 msgstr "Przydzielenie"
 
-#: clutter/clutter-actor.c:3753
+#: clutter/clutter-actor.c:3751
 msgid "The actor's allocation"
 msgstr "Przydzielenie aktora"
 
-#: clutter/clutter-actor.c:3809
+#: clutter/clutter-actor.c:3807
 msgid "Request Mode"
 msgstr "Tryb żądania"
 
-#: clutter/clutter-actor.c:3810
+#: clutter/clutter-actor.c:3808
 msgid "The actor's request mode"
 msgstr "Tryb żądania aktora"
 
-#: clutter/clutter-actor.c:3825
+#: clutter/clutter-actor.c:3823
 msgid "Depth"
 msgstr "Głębia"
 
-#: clutter/clutter-actor.c:3826
+#: clutter/clutter-actor.c:3824
 msgid "Position on the Z axis"
 msgstr "Położenie na osi Z"
 
-#: clutter/clutter-actor.c:3840
+#: clutter/clutter-actor.c:3838
 msgid "Opacity"
 msgstr "Nieprzezroczystość"
 
-#: clutter/clutter-actor.c:3841
+#: clutter/clutter-actor.c:3839
 msgid "Opacity of an actor"
 msgstr "Nieprzezroczystość aktora"
 
-#: clutter/clutter-actor.c:3856
+#: clutter/clutter-actor.c:3854
 msgid "Visible"
 msgstr "Widoczny"
 
-#: clutter/clutter-actor.c:3857
+#: clutter/clutter-actor.c:3855
 msgid "Whether the actor is visible or not"
 msgstr "Określa, czy aktor jest widoczny"
 
-#: clutter/clutter-actor.c:3872
+#: clutter/clutter-actor.c:3870
 msgid "Mapped"
 msgstr "Mapowany"
 
-#: clutter/clutter-actor.c:3873
+#: clutter/clutter-actor.c:3871
 msgid "Whether the actor will be painted"
 msgstr "Określa, czy aktor będzie pomalowany"
 
-#: clutter/clutter-actor.c:3887
+#: clutter/clutter-actor.c:3885
 msgid "Realized"
 msgstr "Zrealizowany"
 
-#: clutter/clutter-actor.c:3888
+#: clutter/clutter-actor.c:3886
 msgid "Whether the actor has been realized"
 msgstr "Określa, czy aktor został zrealizowany"
 
-#: clutter/clutter-actor.c:3904
+#: clutter/clutter-actor.c:3902
 msgid "Reactive"
 msgstr "Reakcyjny"
 
-#: clutter/clutter-actor.c:3905
+#: clutter/clutter-actor.c:3903
 msgid "Whether the actor is reactive to events"
 msgstr "Określa, czy aktor reaguje na zdarzenia"
 
-#: clutter/clutter-actor.c:3917
+#: clutter/clutter-actor.c:3915
 msgid "Has Clip"
 msgstr "Posiada klamrę"
 
-#: clutter/clutter-actor.c:3918
+#: clutter/clutter-actor.c:3916
 msgid "Whether the actor has a clip set"
 msgstr "Określa, czy aktor posiada ustawioną klamrę"
 
-#: clutter/clutter-actor.c:3933
+#: clutter/clutter-actor.c:3931
 msgid "Clip"
 msgstr "Klamra"
 
-#: clutter/clutter-actor.c:3934
+#: clutter/clutter-actor.c:3932
 msgid "The clip region for the actor"
 msgstr "Obszar klamry aktora"
 
-#: clutter/clutter-actor.c:3948 clutter/clutter-actor-meta.c:205
-#: clutter/clutter-binding-pool.c:320 clutter/clutter-input-device.c:151
+#: clutter/clutter-actor.c:3946 clutter/clutter-actor-meta.c:205
+#: clutter/clutter-binding-pool.c:319 clutter/clutter-input-device.c:235
 msgid "Name"
 msgstr "Nazwa"
 
-#: clutter/clutter-actor.c:3949
+#: clutter/clutter-actor.c:3947
 msgid "Name of the actor"
 msgstr "Nazwa aktora"
 
-#: clutter/clutter-actor.c:3963
+#: clutter/clutter-actor.c:3961
 msgid "Scale X"
 msgstr "Skalowanie współrzędnej X"
 
-#: clutter/clutter-actor.c:3964
+#: clutter/clutter-actor.c:3962
 msgid "Scale factor on the X axis"
 msgstr "Czynnik skalowania na osi X"
 
-#: clutter/clutter-actor.c:3979
+#: clutter/clutter-actor.c:3977
 msgid "Scale Y"
 msgstr "Skalowanie współrzędnej Y"
 
-#: clutter/clutter-actor.c:3980
+#: clutter/clutter-actor.c:3978
 msgid "Scale factor on the Y axis"
 msgstr "Czynnik skalowania na osi Y"
 
-#: clutter/clutter-actor.c:3995
+#: clutter/clutter-actor.c:3993
 msgid "Scale Center X"
 msgstr "Środek skalowania współrzędnej X"
 
-#: clutter/clutter-actor.c:3996
+#: clutter/clutter-actor.c:3994
 msgid "Horizontal scale center"
 msgstr "Poziomy środek skalowania"
 
-#: clutter/clutter-actor.c:4011
+#: clutter/clutter-actor.c:4009
 msgid "Scale Center Y"
 msgstr "Środek skalowania współrzędnej Y"
 
-#: clutter/clutter-actor.c:4012
+#: clutter/clutter-actor.c:4010
 msgid "Vertical scale center"
 msgstr "Pionowy środek skalowania"
 
-#: clutter/clutter-actor.c:4027
+#: clutter/clutter-actor.c:4025
 msgid "Scale Gravity"
 msgstr "Grawitacja skalowania"
 
-#: clutter/clutter-actor.c:4028
+#: clutter/clutter-actor.c:4026
 msgid "The center of scaling"
 msgstr "Środek skalowania"
 
-#: clutter/clutter-actor.c:4045
+#: clutter/clutter-actor.c:4043
 msgid "Rotation Angle X"
 msgstr "Kąt obrotu współrzędnej X"
 
-#: clutter/clutter-actor.c:4046
+#: clutter/clutter-actor.c:4044
 msgid "The rotation angle on the X axis"
 msgstr "Kąt obrotu na osi X"
 
-#: clutter/clutter-actor.c:4061
+#: clutter/clutter-actor.c:4059
 msgid "Rotation Angle Y"
 msgstr "Kąt obrotu współrzędnej Y"
 
-#: clutter/clutter-actor.c:4062
+#: clutter/clutter-actor.c:4060
 msgid "The rotation angle on the Y axis"
 msgstr "Kąt obrotu na osi Y"
 
-#: clutter/clutter-actor.c:4077
+#: clutter/clutter-actor.c:4075
 msgid "Rotation Angle Z"
 msgstr "Kąt obrotu współrzędnej Z"
 
-#: clutter/clutter-actor.c:4078
+#: clutter/clutter-actor.c:4076
 msgid "The rotation angle on the Z axis"
 msgstr "Kąt obrotu na osi Z"
 
-#: clutter/clutter-actor.c:4093
+#: clutter/clutter-actor.c:4091
 msgid "Rotation Center X"
 msgstr "Środek obrotu współrzędnej X"
 
-#: clutter/clutter-actor.c:4094
+#: clutter/clutter-actor.c:4092
 msgid "The rotation center on the X axis"
 msgstr "Środek obrotu na osi X"
 
-#: clutter/clutter-actor.c:4110
+#: clutter/clutter-actor.c:4108
 msgid "Rotation Center Y"
 msgstr "Środek obrotu współrzędnej Y"
 
-#: clutter/clutter-actor.c:4111
+#: clutter/clutter-actor.c:4109
 msgid "The rotation center on the Y axis"
 msgstr "Środek obrotu na osi Y"
 
-#: clutter/clutter-actor.c:4127
+#: clutter/clutter-actor.c:4125
 msgid "Rotation Center Z"
 msgstr "Środek obrotu współrzędnej Z"
 
-#: clutter/clutter-actor.c:4128
+#: clutter/clutter-actor.c:4126
 msgid "The rotation center on the Z axis"
 msgstr "Środek obrotu na osi Z"
 
-#: clutter/clutter-actor.c:4144
+#: clutter/clutter-actor.c:4142
 msgid "Rotation Center Z Gravity"
 msgstr "Grawitacja środka obrotu współrzędnej Z"
 
-#: clutter/clutter-actor.c:4145
+#: clutter/clutter-actor.c:4143
 msgid "Center point for rotation around the Z axis"
 msgstr "Punkt środkowy dla obrotu wokół osi Z"
 
-#: clutter/clutter-actor.c:4163
+#: clutter/clutter-actor.c:4161
 msgid "Anchor X"
 msgstr "Kotwica współrzędnej X"
 
-#: clutter/clutter-actor.c:4164
+#: clutter/clutter-actor.c:4162
 msgid "X coordinate of the anchor point"
 msgstr "Współrzędna X punktu kotwicy"
 
-#: clutter/clutter-actor.c:4180
+#: clutter/clutter-actor.c:4178
 msgid "Anchor Y"
 msgstr "Kotwica współrzędnej Y"
 
-#: clutter/clutter-actor.c:4181
+#: clutter/clutter-actor.c:4179
 msgid "Y coordinate of the anchor point"
 msgstr "Współrzędna Y punktu kotwicy"
 
-#: clutter/clutter-actor.c:4196
+#: clutter/clutter-actor.c:4194
 msgid "Anchor Gravity"
 msgstr "Grawitacja kotwicy"
 
-#: clutter/clutter-actor.c:4197
+#: clutter/clutter-actor.c:4195
 msgid "The anchor point as a ClutterGravity"
 msgstr "Punkt kotwicy jako \"ClutterGravity\""
 
-#: clutter/clutter-actor.c:4216
+#: clutter/clutter-actor.c:4214
 msgid "Show on set parent"
 msgstr "Wyświetlanie na ustawionym rodzicu"
 
-#: clutter/clutter-actor.c:4217
+#: clutter/clutter-actor.c:4215
 msgid "Whether the actor is shown when parented"
 msgstr "Określa, czy aktor jest wyświetlany, kiedy posiada rodzica"
 
-#: clutter/clutter-actor.c:4237
+#: clutter/clutter-actor.c:4235
 msgid "Clip to Allocation"
 msgstr "Klamra do przydziału"
 
-#: clutter/clutter-actor.c:4238
+#: clutter/clutter-actor.c:4236
 msgid "Sets the clip region to track the actor's allocation"
 msgstr "Ustawia obszar klamry do śledzenia przydzielenia aktora"
 
-#: clutter/clutter-actor.c:4248
+#: clutter/clutter-actor.c:4246
 msgid "Text Direction"
 msgstr "Kierunek tekstu"
 
-#: clutter/clutter-actor.c:4249
+#: clutter/clutter-actor.c:4247
 msgid "Direction of the text"
 msgstr "Kierunek tekstu"
 
-#: clutter/clutter-actor.c:4267
+#: clutter/clutter-actor.c:4265
 msgid "Has Pointer"
 msgstr "Posiada wskaźnik"
 
-#: clutter/clutter-actor.c:4268
+#: clutter/clutter-actor.c:4266
 msgid "Whether the actor contains the pointer of an input device"
 msgstr "Określa, czy aktor zawiera wskaźnik urządzenia wejścia"
 
-#: clutter/clutter-actor.c:4285
+#: clutter/clutter-actor.c:4283
 msgid "Actions"
 msgstr "Działania"
 
-#: clutter/clutter-actor.c:4286
+#: clutter/clutter-actor.c:4284
 msgid "Adds an action to the actor"
 msgstr "Dodaje działania do aktora"
 
-#: clutter/clutter-actor.c:4300
+#: clutter/clutter-actor.c:4298
 msgid "Constraints"
 msgstr "Ograniczenia"
 
-#: clutter/clutter-actor.c:4301
+#: clutter/clutter-actor.c:4299
 msgid "Adds a constraint to the actor"
 msgstr "Dodaje ograniczenie do aktora"
 
@@ -406,7 +406,8 @@ msgstr "Aktor dołączony do mety"
 msgid "The name of the meta"
 msgstr "Nazwa mety"
 
-#: clutter/clutter-actor-meta.c:219 clutter/clutter-shader.c:261
+#: clutter/clutter-actor-meta.c:219 clutter/clutter-input-device.c:314
+#: clutter/clutter-shader.c:295
 msgid "Enabled"
 msgstr "Włączone"
 
@@ -414,34 +415,34 @@ msgstr "Włączone"
 msgid "Whether the meta is enabled"
 msgstr "Określa, czy meta jest włączona"
 
-#: clutter/clutter-align-constraint.c:231
-#: clutter/clutter-bind-constraint.c:286 clutter/clutter-clone.c:322
+#: clutter/clutter-align-constraint.c:252
+#: clutter/clutter-bind-constraint.c:316 clutter/clutter-clone.c:322
 msgid "Source"
 msgstr "Źródło"
 
-#: clutter/clutter-align-constraint.c:232
+#: clutter/clutter-align-constraint.c:253
 msgid "The source of the alignment"
 msgstr "Źródło wyrównania"
 
-#: clutter/clutter-align-constraint.c:245
+#: clutter/clutter-align-constraint.c:266
 msgid "Align Axis"
 msgstr "Osie wyrównania"
 
-#: clutter/clutter-align-constraint.c:246
+#: clutter/clutter-align-constraint.c:267
 msgid "The axis to align the position to"
 msgstr "Osie, do których wyrównać położenie"
 
-#: clutter/clutter-align-constraint.c:265
-#: clutter/clutter-desaturate-effect.c:309
+#: clutter/clutter-align-constraint.c:286
+#: clutter/clutter-desaturate-effect.c:307
 msgid "Factor"
 msgstr "Czynnik"
 
-#: clutter/clutter-align-constraint.c:266
+#: clutter/clutter-align-constraint.c:287
 msgid "The alignment factor, between 0.0 and 1.0"
 msgstr "Czynnik wyrównania, między 0.0 a 1.0"
 
 #: clutter/clutter-alpha.c:339 clutter/clutter-animation.c:523
-#: clutter/clutter-animator.c:1801
+#: clutter/clutter-animator.c:1802
 msgid "Timeline"
 msgstr "Oś czasu"
 
@@ -477,7 +478,7 @@ msgstr "Obiekt, do którego animacja jest zastosowywana"
 msgid "The mode of the animation"
 msgstr "Tryb animacji"
 
-#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1785
+#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1786
 #: clutter/clutter-media.c:194 clutter/clutter-state.c:1282
 msgid "Duration"
 msgstr "Czas trwania"
@@ -498,7 +499,7 @@ msgstr "Określa, czy animacja powinna być zapętlona"
 msgid "The timeline used by the animation"
 msgstr "Oś czasu używana przez animację"
 
-#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:299
+#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:298
 msgid "Alpha"
 msgstr "Alfa"
 
@@ -506,215 +507,215 @@ msgstr "Alfa"
 msgid "The alpha used by the animation"
 msgstr "Alfa używana przez animację"
 
-#: clutter/clutter-animator.c:1786
+#: clutter/clutter-animator.c:1787
 msgid "The duration of the animation"
 msgstr "Czas trwania animacji"
 
-#: clutter/clutter-animator.c:1802
+#: clutter/clutter-animator.c:1803
 msgid "The timeline of the animation"
 msgstr "Oś czasu animacji"
 
-#: clutter/clutter-behaviour.c:300
+#: clutter/clutter-behaviour.c:299
 msgid "Alpha Object to drive the behaviour"
 msgstr "Obiekt alfa prowadzący zachowanie"
 
-#: clutter/clutter-behaviour-depth.c:175
+#: clutter/clutter-behaviour-depth.c:174
 msgid "Start Depth"
 msgstr "Głębia początkowa"
 
-#: clutter/clutter-behaviour-depth.c:176
+#: clutter/clutter-behaviour-depth.c:175
 msgid "Initial depth to apply"
 msgstr "Początkowa głębia do zastosowania"
 
-#: clutter/clutter-behaviour-depth.c:191
+#: clutter/clutter-behaviour-depth.c:190
 msgid "End Depth"
 msgstr "Głębia końcowa"
 
-#: clutter/clutter-behaviour-depth.c:192
+#: clutter/clutter-behaviour-depth.c:191
 msgid "Final depth to apply"
 msgstr "Końcowa głębia do zastosowania"
 
-#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-ellipse.c:394
 msgid "Start Angle"
 msgstr "Kąt początkowy"
 
-#: clutter/clutter-behaviour-ellipse.c:396
-#: clutter/clutter-behaviour-rotate.c:277
+#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-rotate.c:276
 msgid "Initial angle"
 msgstr "Kąt początkowy"
 
-#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-ellipse.c:410
 msgid "End Angle"
 msgstr "Kąt końcowy"
 
-#: clutter/clutter-behaviour-ellipse.c:412
-#: clutter/clutter-behaviour-rotate.c:295
+#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-rotate.c:294
 msgid "Final angle"
 msgstr "Kąt końcowy"
 
-#: clutter/clutter-behaviour-ellipse.c:427
+#: clutter/clutter-behaviour-ellipse.c:426
 msgid "Angle x tilt"
 msgstr "Nachylenie kąta współrzędnej X"
 
-#: clutter/clutter-behaviour-ellipse.c:428
+#: clutter/clutter-behaviour-ellipse.c:427
 msgid "Tilt of the ellipse around x axis"
 msgstr "Nachylenie elipsy wokół osi X"
 
-#: clutter/clutter-behaviour-ellipse.c:443
+#: clutter/clutter-behaviour-ellipse.c:442
 msgid "Angle y tilt"
 msgstr "Nachylenie kąta współrzędnej Y"
 
-#: clutter/clutter-behaviour-ellipse.c:444
+#: clutter/clutter-behaviour-ellipse.c:443
 msgid "Tilt of the ellipse around y axis"
 msgstr "Nachylenie elipsy wokół osi Y"
 
-#: clutter/clutter-behaviour-ellipse.c:459
+#: clutter/clutter-behaviour-ellipse.c:458
 msgid "Angle z tilt"
 msgstr "Nachylenie kąta współrzędnej Z"
 
-#: clutter/clutter-behaviour-ellipse.c:460
+#: clutter/clutter-behaviour-ellipse.c:459
 msgid "Tilt of the ellipse around z axis"
 msgstr "Nachylenie elipsy wokół osi Z"
 
-#: clutter/clutter-behaviour-ellipse.c:476
+#: clutter/clutter-behaviour-ellipse.c:475
 msgid "Width of the ellipse"
 msgstr "Szerokość alipsy"
 
-#: clutter/clutter-behaviour-ellipse.c:492
+#: clutter/clutter-behaviour-ellipse.c:491
 msgid "Height of ellipse"
 msgstr "Wysokość elipsy"
 
-#: clutter/clutter-behaviour-ellipse.c:507
+#: clutter/clutter-behaviour-ellipse.c:506
 msgid "Center"
 msgstr "Środek"
 
-#: clutter/clutter-behaviour-ellipse.c:508
+#: clutter/clutter-behaviour-ellipse.c:507
 msgid "Center of ellipse"
 msgstr "Środek elipsy"
 
-#: clutter/clutter-behaviour-ellipse.c:522
-#: clutter/clutter-behaviour-rotate.c:330
+#: clutter/clutter-behaviour-ellipse.c:521
+#: clutter/clutter-behaviour-rotate.c:329
 msgid "Direction"
 msgstr "Kierunek"
 
-#: clutter/clutter-behaviour-ellipse.c:523
-#: clutter/clutter-behaviour-rotate.c:331
+#: clutter/clutter-behaviour-ellipse.c:522
+#: clutter/clutter-behaviour-rotate.c:330
 msgid "Direction of rotation"
 msgstr "Kierunek obrotu"
 
-#: clutter/clutter-behaviour-opacity.c:178
+#: clutter/clutter-behaviour-opacity.c:177
 msgid "Opacity Start"
 msgstr "Początkowa nieprzezroczystość"
 
-#: clutter/clutter-behaviour-opacity.c:179
+#: clutter/clutter-behaviour-opacity.c:178
 msgid "Initial opacity level"
 msgstr "Początkowy poziom nieprzezroczystości"
 
-#: clutter/clutter-behaviour-opacity.c:196
+#: clutter/clutter-behaviour-opacity.c:195
 msgid "Opacity End"
 msgstr "Końcowa nieprzezroczystość"
 
-#: clutter/clutter-behaviour-opacity.c:197
+#: clutter/clutter-behaviour-opacity.c:196
 msgid "Final opacity level"
 msgstr "Końcowy poziom nieprzezroczystości"
 
-#: clutter/clutter-behaviour-path.c:220
+#: clutter/clutter-behaviour-path.c:219
 msgid "Path"
 msgstr "Ścieżka"
 
-#: clutter/clutter-behaviour-path.c:221
+#: clutter/clutter-behaviour-path.c:220
 msgid "The ClutterPath object representing the path to animate along"
 msgstr "Obiekt \"ClutterPath\" przedstawiający ścieżkę, na której animować"
 
-#: clutter/clutter-behaviour-rotate.c:276
+#: clutter/clutter-behaviour-rotate.c:275
 msgid "Angle Begin"
 msgstr "Kąt początkowy"
 
-#: clutter/clutter-behaviour-rotate.c:294
+#: clutter/clutter-behaviour-rotate.c:293
 msgid "Angle End"
 msgstr "Kąt końcowy"
 
-#: clutter/clutter-behaviour-rotate.c:312
+#: clutter/clutter-behaviour-rotate.c:311
 msgid "Axis"
 msgstr "Oś"
 
-#: clutter/clutter-behaviour-rotate.c:313
+#: clutter/clutter-behaviour-rotate.c:312
 msgid "Axis of rotation"
 msgstr "Oś obrotu"
 
-#: clutter/clutter-behaviour-rotate.c:348
+#: clutter/clutter-behaviour-rotate.c:347
 msgid "Center X"
 msgstr "Środek współrzędnej X"
 
-#: clutter/clutter-behaviour-rotate.c:349
+#: clutter/clutter-behaviour-rotate.c:348
 msgid "X coordinate of the center of rotation"
 msgstr "Współrzędna X środka obrotu"
 
-#: clutter/clutter-behaviour-rotate.c:366
+#: clutter/clutter-behaviour-rotate.c:365
 msgid "Center Y"
 msgstr "Środek współrzędnej Y"
 
-#: clutter/clutter-behaviour-rotate.c:367
+#: clutter/clutter-behaviour-rotate.c:366
 msgid "Y coordinate of the center of rotation"
 msgstr "Współrzędna Y środka obrotu"
 
-#: clutter/clutter-behaviour-rotate.c:384
+#: clutter/clutter-behaviour-rotate.c:383
 msgid "Center Z"
 msgstr "Środek współrzędnej Z"
 
-#: clutter/clutter-behaviour-rotate.c:385
+#: clutter/clutter-behaviour-rotate.c:384
 msgid "Z coordinate of the center of rotation"
 msgstr "Współrzędna Z środka obrotu"
 
-#: clutter/clutter-behaviour-scale.c:219
+#: clutter/clutter-behaviour-scale.c:218
 msgid "X Start Scale"
 msgstr "Początkowe skalowanie współrzędnej X"
 
-#: clutter/clutter-behaviour-scale.c:220
+#: clutter/clutter-behaviour-scale.c:219
 msgid "Initial scale on the X axis"
 msgstr "Początkowe skalowanie na osi X"
 
-#: clutter/clutter-behaviour-scale.c:238
+#: clutter/clutter-behaviour-scale.c:237
 msgid "X End Scale"
 msgstr "Końcowe skalowanie współrzędnej X"
 
-#: clutter/clutter-behaviour-scale.c:239
+#: clutter/clutter-behaviour-scale.c:238
 msgid "Final scale on the X axis"
 msgstr "Końcowe skalowanie na osi X"
 
-#: clutter/clutter-behaviour-scale.c:257
+#: clutter/clutter-behaviour-scale.c:256
 msgid "Y Start Scale"
 msgstr "Początkowe skalowanie współrzędnej Y"
 
-#: clutter/clutter-behaviour-scale.c:258
+#: clutter/clutter-behaviour-scale.c:257
 msgid "Initial scale on the Y axis"
 msgstr "Początkowe skalowanie na osi Y"
 
-#: clutter/clutter-behaviour-scale.c:276
+#: clutter/clutter-behaviour-scale.c:275
 msgid "Y End Scale"
 msgstr "Końcowe skalowanie współrzędnej Y"
 
-#: clutter/clutter-behaviour-scale.c:277
+#: clutter/clutter-behaviour-scale.c:276
 msgid "Final scale on the Y axis"
 msgstr "Końcowe skalowanie na osi Y"
 
-#: clutter/clutter-bind-constraint.c:287
+#: clutter/clutter-bind-constraint.c:317
 msgid "The source of the binding"
 msgstr "Źródło dowiązania"
 
-#: clutter/clutter-bind-constraint.c:300
+#: clutter/clutter-bind-constraint.c:330
 msgid "Coordinate"
 msgstr "Współrzędna"
 
-#: clutter/clutter-bind-constraint.c:301
+#: clutter/clutter-bind-constraint.c:331
 msgid "The coordinate to bind"
 msgstr "Współrzędna do dowiązania"
 
-#: clutter/clutter-bind-constraint.c:315
+#: clutter/clutter-bind-constraint.c:345
 msgid "Offset"
 msgstr "Offset"
 
-#: clutter/clutter-bind-constraint.c:316
+#: clutter/clutter-bind-constraint.c:346
 msgid "The offset in pixels to apply to the binding"
 msgstr "Offset w pikselach do zastosowania do dowiązania"
 
@@ -744,7 +745,7 @@ msgstr "Domyślne poziome wyrównanie aktora wewnątrz menedżera warstw"
 msgid "Default vertical alignment for the actors inside the layout manager"
 msgstr "Domyślne pionowe wyrównanie aktora wewnątrz menedżera warstw"
 
-#: clutter/clutter-binding-pool.c:321
+#: clutter/clutter-binding-pool.c:320
 msgid "The unique name of the binding pool"
 msgstr "Unikalna nazwa puli dowiązania"
 
@@ -757,7 +758,7 @@ msgid "The layout manager used by the box"
 msgstr "Menedżer warstw używany przez to pole"
 
 #: clutter/clutter-box.c:514 clutter/clutter-rectangle.c:258
-#: clutter/clutter-stage.c:1307
+#: clutter/clutter-stage.c:1317
 msgid "Color"
 msgstr "Kolor"
 
@@ -900,19 +901,19 @@ msgstr "Kontener, który utworzył te dane"
 msgid "The actor wrapped by this data"
 msgstr "Aktor opakowany przez te dane"
 
-#: clutter/clutter-click-action.c:283
+#: clutter/clutter-click-action.c:302
 msgid "Pressed"
 msgstr "Wciśnięte"
 
-#: clutter/clutter-click-action.c:284
+#: clutter/clutter-click-action.c:303
 msgid "Whether the clickable should be in pressed state"
 msgstr "Określa, czy element klikalny jest w stanie wciśniętym"
 
-#: clutter/clutter-click-action.c:297
+#: clutter/clutter-click-action.c:316
 msgid "Held"
 msgstr "Przytrzymane"
 
-#: clutter/clutter-click-action.c:298
+#: clutter/clutter-click-action.c:317
 msgid "Whether the clickable has a grab"
 msgstr "Określa, czy element klikalny posiada przytrzymanie"
 
@@ -920,11 +921,11 @@ msgstr "Określa, czy element klikalny posiada przytrzymanie"
 msgid "Specifies the actor to be cloned"
 msgstr "Podaje aktora do sklonowania"
 
-#: clutter/clutter-colorize-effect.c:309
+#: clutter/clutter-colorize-effect.c:307
 msgid "Tint"
 msgstr "Odcień"
 
-#: clutter/clutter-colorize-effect.c:310
+#: clutter/clutter-colorize-effect.c:308
 msgid "The tint to apply"
 msgstr "Odcień do zastosowania"
 
@@ -952,11 +953,11 @@ msgstr "Materiał tyłu"
 msgid "The material to be used when painting the back of the actor"
 msgstr "Materiał używany podczas malowania tyłu aktora"
 
-#: clutter/clutter-desaturate-effect.c:310
+#: clutter/clutter-desaturate-effect.c:308
 msgid "The desaturation factor"
 msgstr "Czynnik usuwania nasycenia"
 
-#: clutter/clutter-device-manager.c:130
+#: clutter/clutter-device-manager.c:130 clutter/clutter-input-device.c:343
 msgid "Backend"
 msgstr "Mechanizm"
 
@@ -964,35 +965,35 @@ msgstr "Mechanizm"
 msgid "The ClutterBackend of the device manager"
 msgstr "Mechanizm \"ClutterBackend\" menedżera urządzeń"
 
-#: clutter/clutter-drag-action.c:490
+#: clutter/clutter-drag-action.c:491
 msgid "Horizontal Drag Threshold"
 msgstr "Poziomy próg przeciągnięcia"
 
-#: clutter/clutter-drag-action.c:491
+#: clutter/clutter-drag-action.c:492
 msgid "The horizontal amount of pixels required to start dragging"
 msgstr "Liczba poziomych pikseli wymaganych do rozpoczęcia przeciągania"
 
-#: clutter/clutter-drag-action.c:510
+#: clutter/clutter-drag-action.c:511
 msgid "Vertical Drag Threshold"
 msgstr "Pionowy próg przeciągnięcia"
 
-#: clutter/clutter-drag-action.c:511
+#: clutter/clutter-drag-action.c:512
 msgid "The vertical amount of pixels required to start dragging"
 msgstr "Liczba pionowych pikseli wymaganych do rozpoczęcia przeciągania"
 
-#: clutter/clutter-drag-action.c:532
+#: clutter/clutter-drag-action.c:533
 msgid "Drag Handle"
 msgstr "Uchwyt przeciągnięcia"
 
-#: clutter/clutter-drag-action.c:533
+#: clutter/clutter-drag-action.c:534
 msgid "The actor that is being dragged"
 msgstr "Przeciągany aktor"
 
-#: clutter/clutter-drag-action.c:546
+#: clutter/clutter-drag-action.c:547
 msgid "Drag Axis"
 msgstr "Osie przeciągnięcia"
 
-#: clutter/clutter-drag-action.c:547
+#: clutter/clutter-drag-action.c:548
 msgid "Constraints the dragging to an axis"
 msgstr "Ogranicza przeciągnięcia do osi"
 
@@ -1056,26 +1057,73 @@ msgstr "Maksymalna wysokość wiersza"
 msgid "Maximum height for each row"
 msgstr "Maksymalna wysokość każdego wiersza"
 
-#: clutter/clutter-input-device.c:134
+#: clutter/clutter-input-device.c:219
 msgid "Id"
 msgstr "Identyfikator"
 
-#: clutter/clutter-input-device.c:135
+#: clutter/clutter-input-device.c:220
 msgid "Unique identifier of the device"
 msgstr "Unikalny identyfikator urządzenia"
 
-#: clutter/clutter-input-device.c:152
+#: clutter/clutter-input-device.c:236
 msgid "The name of the device"
 msgstr "Nazwa urządzenia"
 
-#: clutter/clutter-input-device.c:167
+#: clutter/clutter-input-device.c:250
 msgid "Device Type"
 msgstr "Typ urządzenia"
 
-#: clutter/clutter-input-device.c:168
+#: clutter/clutter-input-device.c:251
 msgid "The type of the device"
 msgstr "Typ urządzenia"
 
+#: clutter/clutter-input-device.c:266
+#, fuzzy
+msgid "Device Manager"
+msgstr "Menedżer"
+
+#: clutter/clutter-input-device.c:267
+msgid "The device manager instance"
+msgstr ""
+
+#: clutter/clutter-input-device.c:280
+#, fuzzy
+msgid "Device Mode"
+msgstr "Typ urządzenia"
+
+#: clutter/clutter-input-device.c:281
+#, fuzzy
+msgid "The mode of the device"
+msgstr "Nazwa urządzenia"
+
+#: clutter/clutter-input-device.c:295
+#, fuzzy
+msgid "Has Cursor"
+msgstr "Posiada krawędź"
+
+#: clutter/clutter-input-device.c:296
+#, fuzzy
+msgid "Whether the device has a cursor"
+msgstr "Określa, czy element klikalny posiada przytrzymanie"
+
+#: clutter/clutter-input-device.c:315
+#, fuzzy
+msgid "Whether the device is enabled"
+msgstr "Określa, czy cieniowanie jest włączone"
+
+#: clutter/clutter-input-device.c:328
+msgid "Number of Axes"
+msgstr ""
+
+#: clutter/clutter-input-device.c:329
+#, fuzzy
+msgid "The number of axes on the device"
+msgstr "Nazwa urządzenia"
+
+#: clutter/clutter-input-device.c:344
+msgid "The backend instance"
+msgstr ""
+
 #: clutter/clutter-interval.c:397
 msgid "Value Type"
 msgstr "Typ wartości"
@@ -1092,59 +1140,59 @@ msgstr "Menedżer"
 msgid "The manager that created this data"
 msgstr "Menedżer, który utworzył te dane"
 
-#: clutter/clutter-main.c:756
+#: clutter/clutter-main.c:753
 msgid "default:LTR"
 msgstr "default:LTR"
 
-#: clutter/clutter-main.c:1560
+#: clutter/clutter-main.c:1557
 msgid "Show frames per second"
 msgstr "Wyświetla liczbę klatek na sekundę"
 
-#: clutter/clutter-main.c:1562
+#: clutter/clutter-main.c:1559
 msgid "Default frame rate"
 msgstr "Domyślna liczba klatek na sekundę"
 
-#: clutter/clutter-main.c:1564
+#: clutter/clutter-main.c:1561
 msgid "Make all warnings fatal"
 msgstr "Wszystkie ostrzeżenia są krytyczne"
 
-#: clutter/clutter-main.c:1567
+#: clutter/clutter-main.c:1564
 msgid "Direction for the text"
 msgstr "Kierunek tekstu"
 
-#: clutter/clutter-main.c:1570
+#: clutter/clutter-main.c:1567
 msgid "Disable mipmapping on text"
 msgstr "Wyłącza mipmapowanie na tekście"
 
-#: clutter/clutter-main.c:1573
+#: clutter/clutter-main.c:1570
 msgid "Use 'fuzzy' picking"
 msgstr "Używa wybierania \"rozmytego\""
 
-#: clutter/clutter-main.c:1576
+#: clutter/clutter-main.c:1573
 msgid "Clutter debugging flags to set"
 msgstr "Flagi debugowania biblioteki Clutter do ustawienia"
 
-#: clutter/clutter-main.c:1578
+#: clutter/clutter-main.c:1575
 msgid "Clutter debugging flags to unset"
 msgstr "Flagi debugowania biblioteki Clutter do usunięcia"
 
-#: clutter/clutter-main.c:1582
+#: clutter/clutter-main.c:1579
 msgid "Clutter profiling flags to set"
 msgstr "Flagi profilowania biblioteki Clutter do ustawienia"
 
-#: clutter/clutter-main.c:1584
+#: clutter/clutter-main.c:1581
 msgid "Clutter profiling flags to unset"
 msgstr "Flagi profilowania biblioteki Clutter do usunięcia"
 
-#: clutter/clutter-main.c:1587
+#: clutter/clutter-main.c:1584
 msgid "Enable accessibility"
 msgstr "Włącza dostępność"
 
-#: clutter/clutter-main.c:1774
+#: clutter/clutter-main.c:1771
 msgid "Clutter Options"
 msgstr "Opcje biblioteki Clutter"
 
-#: clutter/clutter-main.c:1775
+#: clutter/clutter-main.c:1772
 msgid "Show Clutter Options"
 msgstr "Wyświetla opcje biblioteki Clutter"
 
@@ -1260,44 +1308,44 @@ msgstr "Nazwa pliku"
 msgid "The path of the currently parsed file"
 msgstr "Ścieżka do obecnie przetwarzanego pliku"
 
-#: clutter/clutter-shader.c:215
+#: clutter/clutter-shader.c:249
 msgid "Vertex Source"
 msgstr "Źródło wierzchołków"
 
-#: clutter/clutter-shader.c:216
+#: clutter/clutter-shader.c:250
 msgid "Source of vertex shader"
 msgstr "Źródło cieniowania wierzchołkowego"
 
-#: clutter/clutter-shader.c:230
+#: clutter/clutter-shader.c:264
 msgid "Fragment Source"
 msgstr "Źródło fragmentów"
 
-#: clutter/clutter-shader.c:231
+#: clutter/clutter-shader.c:265
 msgid "Source of fragment shader"
 msgstr "Źródło cieniowania fragmentów"
 
-#: clutter/clutter-shader.c:246
+#: clutter/clutter-shader.c:280
 msgid "Compiled"
 msgstr "Skompilowany"
 
-#: clutter/clutter-shader.c:247
+#: clutter/clutter-shader.c:281
 msgid "Whether the shader is compiled and linked"
 msgstr "Określa, czy cieniowanie jest skompilowane i skonsolidowane"
 
-#: clutter/clutter-shader.c:262
+#: clutter/clutter-shader.c:296
 msgid "Whether the shader is enabled"
 msgstr "Określa, czy cieniowanie jest włączone"
 
-#: clutter/clutter-shader.c:467
+#: clutter/clutter-shader.c:501
 #, c-format
 msgid "%s compilation failed: %s"
 msgstr "Kompilacja %s się nie powiodła: %s"
 
-#: clutter/clutter-shader.c:468
+#: clutter/clutter-shader.c:502
 msgid "Vertex shader"
 msgstr "Cieniowanie wierzchołkowe"
 
-#: clutter/clutter-shader.c:469
+#: clutter/clutter-shader.c:503
 msgid "Fragment shader"
 msgstr "Cieniowanie fragmentów"
 
@@ -1309,98 +1357,108 @@ msgstr "Typ cieniowania"
 msgid "The type of shader used"
 msgstr "Typ używanego cieniowania"
 
-#: clutter/clutter-stage.c:1249
+#: clutter/clutter-stage.c:1259
 msgid "Fullscreen Set"
 msgstr "Ustawienie pełnego ekranu"
 
-#: clutter/clutter-stage.c:1250
+#: clutter/clutter-stage.c:1260
 msgid "Whether the main stage is fullscreen"
 msgstr "Określa, czy główna scena jest na pełnym ekranie"
 
-#: clutter/clutter-stage.c:1266
+#: clutter/clutter-stage.c:1276
 msgid "Offscreen"
 msgstr "Poza ekranem"
 
-#: clutter/clutter-stage.c:1267
+#: clutter/clutter-stage.c:1277
 msgid "Whether the main stage should be rendered offscreen"
 msgstr "Określa, czy główna scena powinna być wyświetlana poza ekranem"
 
-#: clutter/clutter-stage.c:1279 clutter/clutter-text.c:2643
+#: clutter/clutter-stage.c:1289 clutter/clutter-text.c:2667
 msgid "Cursor Visible"
 msgstr "Widoczność kursora"
 
-#: clutter/clutter-stage.c:1280
+#: clutter/clutter-stage.c:1290
 msgid "Whether the mouse pointer is visible on the main stage"
 msgstr "Określa, czy kursor myszy jest widoczny na głównej scenie"
 
-#: clutter/clutter-stage.c:1294
+#: clutter/clutter-stage.c:1304
 msgid "User Resizable"
 msgstr "Użytkownik może zmieniać rozmiar"
 
-#: clutter/clutter-stage.c:1295
+#: clutter/clutter-stage.c:1305
 msgid "Whether the stage is able to be resized via user interaction"
 msgstr "Określa, czy można zmieniać rozmiar sceny przez działania użytkownika"
 
-#: clutter/clutter-stage.c:1308
+#: clutter/clutter-stage.c:1318
 msgid "The color of the stage"
 msgstr "Kolor sceny"
 
-#: clutter/clutter-stage.c:1322
+#: clutter/clutter-stage.c:1332
 msgid "Perspective"
 msgstr "Perspektywa"
 
-#: clutter/clutter-stage.c:1323
+#: clutter/clutter-stage.c:1333
 msgid "Perspective projection parameters"
 msgstr "Parametry projekcji perspektywy"
 
-#: clutter/clutter-stage.c:1338
+#: clutter/clutter-stage.c:1348
 msgid "Title"
 msgstr "Tytuł"
 
-#: clutter/clutter-stage.c:1339
+#: clutter/clutter-stage.c:1349
 msgid "Stage Title"
 msgstr "Tytuł sceny"
 
-#: clutter/clutter-stage.c:1354
+#: clutter/clutter-stage.c:1364
 msgid "Use Fog"
 msgstr "Użycie mgły"
 
-#: clutter/clutter-stage.c:1355
+#: clutter/clutter-stage.c:1365
 msgid "Whether to enable depth cueing"
 msgstr "Określa, czy włączyć wskazówki głębi"
 
-#: clutter/clutter-stage.c:1369
+#: clutter/clutter-stage.c:1379
 msgid "Fog"
 msgstr "Mgła"
 
-#: clutter/clutter-stage.c:1370
+#: clutter/clutter-stage.c:1380
 msgid "Settings for the depth cueing"
 msgstr "Ustawienia dla wskazówek głębi"
 
-#: clutter/clutter-stage.c:1386
+#: clutter/clutter-stage.c:1396
 msgid "Use Alpha"
 msgstr "Użycie alfy"
 
-#: clutter/clutter-stage.c:1387
+#: clutter/clutter-stage.c:1397
 msgid "Whether to honour the alpha component of the stage color"
 msgstr "Określa, czy uwzględniać składnik alfa koloru sceny"
 
-#: clutter/clutter-stage.c:1403
+#: clutter/clutter-stage.c:1413
 msgid "Key Focus"
 msgstr "Aktywny klawisz"
 
-#: clutter/clutter-stage.c:1404
+#: clutter/clutter-stage.c:1414
 msgid "The currently key focused actor"
 msgstr "Aktor obecnie posiadający aktywny klawisz"
 
-#: clutter/clutter-stage.c:1420
+#: clutter/clutter-stage.c:1430
 msgid "No Clear Hint"
 msgstr "Bez wskazówki czyszczenia"
 
-#: clutter/clutter-stage.c:1421
+#: clutter/clutter-stage.c:1431
 msgid "Whether the stage should clear its contents"
 msgstr "Określa, czy scena powinna czyścić swoją zawartość"
 
+#: clutter/clutter-stage.c:1444
+#, fuzzy
+msgid "Accept Focus"
+msgstr "Aktywny klawisz"
+
+#: clutter/clutter-stage.c:1445
+#, fuzzy
+msgid "Whether the stage should accept focus on show"
+msgstr "Określa, czy scena powinna czyścić swoją zawartość"
+
 #: clutter/clutter-state.c:1268
 msgid "State"
 msgstr "Stan"
@@ -1414,193 +1472,193 @@ msgstr ""
 msgid "Default transition duration"
 msgstr "Domyślny czas trwania przejścia"
 
-#: clutter/clutter-text.c:2530
+#: clutter/clutter-text.c:2554
 msgid "Font Name"
 msgstr "Nazwa czcionki"
 
-#: clutter/clutter-text.c:2531
+#: clutter/clutter-text.c:2555
 msgid "The font to be used by the text"
 msgstr "Czcionka używana przez tekst"
 
-#: clutter/clutter-text.c:2548
+#: clutter/clutter-text.c:2572
 msgid "Font Description"
 msgstr "Opis czcionki"
 
-#: clutter/clutter-text.c:2549
+#: clutter/clutter-text.c:2573
 msgid "The font description to be used"
 msgstr "Używany opis czcionki"
 
-#: clutter/clutter-text.c:2565
+#: clutter/clutter-text.c:2589
 msgid "Text"
 msgstr "Tekst"
 
-#: clutter/clutter-text.c:2566
+#: clutter/clutter-text.c:2590
 msgid "The text to render"
 msgstr "Tekst do wyświetlenia"
 
-#: clutter/clutter-text.c:2580
+#: clutter/clutter-text.c:2604
 msgid "Font Color"
 msgstr "Kolor czcionki"
 
-#: clutter/clutter-text.c:2581
+#: clutter/clutter-text.c:2605
 msgid "Color of the font used by the text"
 msgstr "Kolor czcionki używanej przez tekst"
 
-#: clutter/clutter-text.c:2595
+#: clutter/clutter-text.c:2619
 msgid "Editable"
 msgstr "Można modyfikować"
 
-#: clutter/clutter-text.c:2596
+#: clutter/clutter-text.c:2620
 msgid "Whether the text is editable"
 msgstr "Określa, czy tekst można modyfikować"
 
-#: clutter/clutter-text.c:2611
+#: clutter/clutter-text.c:2635
 msgid "Selectable"
 msgstr "Można skalować"
 
-#: clutter/clutter-text.c:2612
+#: clutter/clutter-text.c:2636
 msgid "Whether the text is selectable"
 msgstr "Określa, czy tekst można skalować"
 
-#: clutter/clutter-text.c:2626
+#: clutter/clutter-text.c:2650
 msgid "Activatable"
 msgstr "Można aktywować"
 
-#: clutter/clutter-text.c:2627
+#: clutter/clutter-text.c:2651
 msgid "Whether pressing return causes the activate signal to be emitted"
 msgstr ""
 "Określa, czy wciśnięcie klawisza Return powoduje wysłanie sygnały aktywacji"
 
-#: clutter/clutter-text.c:2644
+#: clutter/clutter-text.c:2668
 msgid "Whether the input cursor is visible"
 msgstr "Określa, czy kursor wejścia jest widoczny"
 
-#: clutter/clutter-text.c:2658 clutter/clutter-text.c:2659
+#: clutter/clutter-text.c:2682 clutter/clutter-text.c:2683
 msgid "Cursor Color"
 msgstr "Kolor kursora"
 
-#: clutter/clutter-text.c:2673
+#: clutter/clutter-text.c:2697
 msgid "Cursor Color Set"
 msgstr "Ustawienie koloru kursora"
 
-#: clutter/clutter-text.c:2674
+#: clutter/clutter-text.c:2698
 msgid "Whether the cursor color has been set"
 msgstr "Określa, czy kolor kursora został ustawiony"
 
-#: clutter/clutter-text.c:2689
+#: clutter/clutter-text.c:2713
 msgid "Cursor Size"
 msgstr "Rozmiar kursora"
 
-#: clutter/clutter-text.c:2690
+#: clutter/clutter-text.c:2714
 msgid "The width of the cursor, in pixels"
 msgstr "Szerokość kursora w pikselach"
 
-#: clutter/clutter-text.c:2704
+#: clutter/clutter-text.c:2728
 msgid "Cursor Position"
 msgstr "Położenie kursora"
 
-#: clutter/clutter-text.c:2705
+#: clutter/clutter-text.c:2729
 msgid "The cursor position"
 msgstr "Położenie kursora"
 
-#: clutter/clutter-text.c:2720
+#: clutter/clutter-text.c:2744
 msgid "Selection-bound"
 msgstr "Powiązanie zaznaczenia"
 
-#: clutter/clutter-text.c:2721
+#: clutter/clutter-text.c:2745
 msgid "The cursor position of the other end of the selection"
 msgstr "Położenie kursora na drugim końcu zaznaczenia"
 
-#: clutter/clutter-text.c:2736 clutter/clutter-text.c:2737
+#: clutter/clutter-text.c:2760 clutter/clutter-text.c:2761
 msgid "Selection Color"
 msgstr "Kolor zaznaczenia"
 
-#: clutter/clutter-text.c:2751
+#: clutter/clutter-text.c:2775
 msgid "Selection Color Set"
 msgstr "Ustawienie koloru zaznaczenia"
 
-#: clutter/clutter-text.c:2752
+#: clutter/clutter-text.c:2776
 msgid "Whether the selection color has been set"
 msgstr "Określa, czy kolor zaznaczenia został ustawiony"
 
-#: clutter/clutter-text.c:2767
+#: clutter/clutter-text.c:2791
 msgid "Attributes"
 msgstr "Atrybuty"
 
-#: clutter/clutter-text.c:2768
+#: clutter/clutter-text.c:2792
 msgid "A list of style attributes to apply to the contents of the actor"
 msgstr "Lista atrybutów stylu do zastosowania do zawartości aktora"
 
-#: clutter/clutter-text.c:2790
+#: clutter/clutter-text.c:2814
 msgid "Use markup"
 msgstr "Użycie znaczników"
 
-#: clutter/clutter-text.c:2791
+#: clutter/clutter-text.c:2815
 msgid "Whether or not the text includes Pango markup"
 msgstr "Określa, czy tekst zawiera znaczniki biblioteki Pango"
 
-#: clutter/clutter-text.c:2807
+#: clutter/clutter-text.c:2831
 msgid "Line wrap"
 msgstr "Zawijanie wierszy"
 
-#: clutter/clutter-text.c:2808
+#: clutter/clutter-text.c:2832
 msgid "If set, wrap the lines if the text becomes too wide"
 msgstr "Jeśli ustawione, zawija wiersze, jeśli tekst staje się za szeroki"
 
-#: clutter/clutter-text.c:2823
+#: clutter/clutter-text.c:2847
 msgid "Line wrap mode"
 msgstr "Tryb zawijania wierszy"
 
-#: clutter/clutter-text.c:2824
+#: clutter/clutter-text.c:2848
 msgid "Control how line-wrapping is done"
 msgstr "Kontroluje, jak wykonywać zawijanie wierszy"
 
-#: clutter/clutter-text.c:2839
+#: clutter/clutter-text.c:2863
 msgid "Ellipsize"
 msgstr "Przycięcie"
 
-#: clutter/clutter-text.c:2840
+#: clutter/clutter-text.c:2864
 msgid "The preferred place to ellipsize the string"
 msgstr "Preferowane miejsce do przycięcia ciągu"
 
-#: clutter/clutter-text.c:2856
+#: clutter/clutter-text.c:2880
 msgid "Line Alignment"
 msgstr "Wyrównanie wiersza"
 
-#: clutter/clutter-text.c:2857
+#: clutter/clutter-text.c:2881
 msgid "The preferred alignment for the string, for multi-line text"
 msgstr "Preferowane wyrównanie ciągu dla tekstu wielowierszowego"
 
-#: clutter/clutter-text.c:2873
+#: clutter/clutter-text.c:2897
 msgid "Justify"
 msgstr "Justowanie"
 
-#: clutter/clutter-text.c:2874
+#: clutter/clutter-text.c:2898
 msgid "Whether the text should be justified"
 msgstr "Określa, czy tekst powinien być justowany"
 
-#: clutter/clutter-text.c:2889
+#: clutter/clutter-text.c:2913
 msgid "Password Character"
 msgstr "Znak hasła"
 
-#: clutter/clutter-text.c:2890
+#: clutter/clutter-text.c:2914
 msgid "If non-zero, use this character to display the actor's contents"
 msgstr ""
 "Jeśli nie wynosi zero, używa tego znaku do wyświetlania zawartości aktora"
 
-#: clutter/clutter-text.c:2904
+#: clutter/clutter-text.c:2928
 msgid "Max Length"
 msgstr "Maksymalna długość"
 
-#: clutter/clutter-text.c:2905
+#: clutter/clutter-text.c:2929
 msgid "Maximum length of the text inside the actor"
 msgstr "Maksymalna długość tekstu w aktorze"
 
-#: clutter/clutter-text.c:2928
+#: clutter/clutter-text.c:2952
 msgid "Single Line Mode"
 msgstr "Tryb pojedynczego wiersza"
 
-#: clutter/clutter-text.c:2929
+#: clutter/clutter-text.c:2953
 msgid "Whether the text should be a single line"
 msgstr "Określa, czy tekst powinien być pojedynczym wierszem"
 
@@ -1733,23 +1791,23 @@ msgstr "Wybieranie za pomocą alfy"
 msgid "Shape actor with alpha channel when picking"
 msgstr "Kształtowanie aktora za pomocą kanału alfa podczas wybierania"
 
-#: clutter/glx/clutter-backend-glx.c:128
+#: clutter/glx/clutter-backend-glx.c:131
 msgid "VBlank method to be used (none, dri or glx)"
 msgstr "Używana metoda VBlank (\"none\" (brak), \"dri\" lub \"glx\")"
 
-#: clutter/x11/clutter-backend-x11.c:364
+#: clutter/x11/clutter-backend-x11.c:473
 msgid "X display to use"
 msgstr "Używany ekran X"
 
-#: clutter/x11/clutter-backend-x11.c:370
+#: clutter/x11/clutter-backend-x11.c:479
 msgid "X screen to use"
 msgstr "Używany ekran X"
 
-#: clutter/x11/clutter-backend-x11.c:375
+#: clutter/x11/clutter-backend-x11.c:484
 msgid "Make X calls synchronous"
 msgstr "Synchroniczne wywołania X"
 
-#: clutter/x11/clutter-backend-x11.c:382
+#: clutter/x11/clutter-backend-x11.c:491
 msgid "Enable XInput support"
 msgstr "Włącza obsługę XInput"
 
index 78c4e96..a9f2a2c 100644 (file)
@@ -9,7 +9,7 @@ msgstr ""
 "Project-Id-Version: clutter master\n"
 "Report-Msgid-Bugs-To: http://bugzilla.clutter-project.org/enter_bug.cgi?"
 "product=clutter\n"
-"POT-Creation-Date: 2010-12-17 15:51+0000\n"
+"POT-Creation-Date: 2011-02-07 15:50+0000\n"
 "PO-Revision-Date: 2010-09-30 15:09+0800\n"
 "Last-Translator: Aron Xu <happyaron.xu@gmail.com>\n"
 "Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
@@ -18,381 +18,381 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: clutter/clutter-actor.c:3480
+#: clutter/clutter-actor.c:3478
 msgid "X coordinate"
 msgstr "X 坐标"
 
-#: clutter/clutter-actor.c:3481
+#: clutter/clutter-actor.c:3479
 msgid "X coordinate of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3496
+#: clutter/clutter-actor.c:3494
 msgid "Y coordinate"
 msgstr "Y 坐标"
 
-#: clutter/clutter-actor.c:3497
+#: clutter/clutter-actor.c:3495
 msgid "Y coordinate of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3512 clutter/clutter-behaviour-ellipse.c:475
+#: clutter/clutter-actor.c:3510 clutter/clutter-behaviour-ellipse.c:474
 msgid "Width"
 msgstr "宽度"
 
-#: clutter/clutter-actor.c:3513
+#: clutter/clutter-actor.c:3511
 msgid "Width of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3527 clutter/clutter-behaviour-ellipse.c:491
+#: clutter/clutter-actor.c:3525 clutter/clutter-behaviour-ellipse.c:490
 msgid "Height"
 msgstr "高度"
 
-#: clutter/clutter-actor.c:3528
+#: clutter/clutter-actor.c:3526
 msgid "Height of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3546
+#: clutter/clutter-actor.c:3544
 msgid "Fixed X"
 msgstr "固定 X 坐标"
 
-#: clutter/clutter-actor.c:3547
+#: clutter/clutter-actor.c:3545
 msgid "Forced X position of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3565
+#: clutter/clutter-actor.c:3563
 msgid "Fixed Y"
 msgstr "固定 Y 坐标"
 
-#: clutter/clutter-actor.c:3566
+#: clutter/clutter-actor.c:3564
 msgid "Forced Y position of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3582
+#: clutter/clutter-actor.c:3580
 msgid "Fixed position set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3583
+#: clutter/clutter-actor.c:3581
 msgid "Whether to use fixed positioning for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3605
+#: clutter/clutter-actor.c:3603
 msgid "Min Width"
 msgstr "最小宽度"
 
-#: clutter/clutter-actor.c:3606
+#: clutter/clutter-actor.c:3604
 msgid "Forced minimum width request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3625
+#: clutter/clutter-actor.c:3623
 msgid "Min Height"
 msgstr "最小高度"
 
-#: clutter/clutter-actor.c:3626
+#: clutter/clutter-actor.c:3624
 msgid "Forced minimum height request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3645
+#: clutter/clutter-actor.c:3643
 msgid "Natural Width"
 msgstr ""
 
-#: clutter/clutter-actor.c:3646
+#: clutter/clutter-actor.c:3644
 msgid "Forced natural width request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3665
+#: clutter/clutter-actor.c:3663
 msgid "Natural Height"
 msgstr ""
 
-#: clutter/clutter-actor.c:3666
+#: clutter/clutter-actor.c:3664
 msgid "Forced natural height request for the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3682
+#: clutter/clutter-actor.c:3680
 msgid "Minimum width set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3683
+#: clutter/clutter-actor.c:3681
 msgid "Whether to use the min-width property"
 msgstr ""
 
-#: clutter/clutter-actor.c:3698
+#: clutter/clutter-actor.c:3696
 msgid "Minimum height set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3699
+#: clutter/clutter-actor.c:3697
 msgid "Whether to use the min-height property"
 msgstr ""
 
-#: clutter/clutter-actor.c:3714
+#: clutter/clutter-actor.c:3712
 msgid "Natural width set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3715
+#: clutter/clutter-actor.c:3713
 msgid "Whether to use the natural-width property"
 msgstr ""
 
-#: clutter/clutter-actor.c:3732
+#: clutter/clutter-actor.c:3730
 msgid "Natural height set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3733
+#: clutter/clutter-actor.c:3731
 msgid "Whether to use the natural-height property"
 msgstr ""
 
-#: clutter/clutter-actor.c:3752
+#: clutter/clutter-actor.c:3750
 msgid "Allocation"
 msgstr "分配"
 
-#: clutter/clutter-actor.c:3753
+#: clutter/clutter-actor.c:3751
 msgid "The actor's allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:3809
+#: clutter/clutter-actor.c:3807
 msgid "Request Mode"
 msgstr "请求模式"
 
-#: clutter/clutter-actor.c:3810
+#: clutter/clutter-actor.c:3808
 msgid "The actor's request mode"
 msgstr ""
 
-#: clutter/clutter-actor.c:3825
+#: clutter/clutter-actor.c:3823
 msgid "Depth"
 msgstr "色深"
 
-#: clutter/clutter-actor.c:3826
+#: clutter/clutter-actor.c:3824
 msgid "Position on the Z axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:3840
+#: clutter/clutter-actor.c:3838
 msgid "Opacity"
 msgstr "透明度"
 
-#: clutter/clutter-actor.c:3841
+#: clutter/clutter-actor.c:3839
 msgid "Opacity of an actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3856
+#: clutter/clutter-actor.c:3854
 msgid "Visible"
 msgstr "可见性"
 
-#: clutter/clutter-actor.c:3857
+#: clutter/clutter-actor.c:3855
 msgid "Whether the actor is visible or not"
 msgstr ""
 
-#: clutter/clutter-actor.c:3872
+#: clutter/clutter-actor.c:3870
 msgid "Mapped"
 msgstr ""
 
-#: clutter/clutter-actor.c:3873
+#: clutter/clutter-actor.c:3871
 msgid "Whether the actor will be painted"
 msgstr ""
 
-#: clutter/clutter-actor.c:3887
+#: clutter/clutter-actor.c:3885
 msgid "Realized"
 msgstr ""
 
-#: clutter/clutter-actor.c:3888
+#: clutter/clutter-actor.c:3886
 msgid "Whether the actor has been realized"
 msgstr ""
 
-#: clutter/clutter-actor.c:3904
+#: clutter/clutter-actor.c:3902
 msgid "Reactive"
 msgstr "重新激活"
 
-#: clutter/clutter-actor.c:3905
+#: clutter/clutter-actor.c:3903
 msgid "Whether the actor is reactive to events"
 msgstr ""
 
-#: clutter/clutter-actor.c:3917
+#: clutter/clutter-actor.c:3915
 msgid "Has Clip"
 msgstr ""
 
-#: clutter/clutter-actor.c:3918
+#: clutter/clutter-actor.c:3916
 msgid "Whether the actor has a clip set"
 msgstr ""
 
-#: clutter/clutter-actor.c:3933
+#: clutter/clutter-actor.c:3931
 msgid "Clip"
 msgstr ""
 
-#: clutter/clutter-actor.c:3934
+#: clutter/clutter-actor.c:3932
 #, fuzzy
 msgid "The clip region for the actor"
 msgstr "文本方向"
 
-#: clutter/clutter-actor.c:3948 clutter/clutter-actor-meta.c:205
-#: clutter/clutter-binding-pool.c:320 clutter/clutter-input-device.c:151
+#: clutter/clutter-actor.c:3946 clutter/clutter-actor-meta.c:205
+#: clutter/clutter-binding-pool.c:319 clutter/clutter-input-device.c:235
 msgid "Name"
 msgstr "名称"
 
-#: clutter/clutter-actor.c:3949
+#: clutter/clutter-actor.c:3947
 msgid "Name of the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:3963
+#: clutter/clutter-actor.c:3961
 msgid "Scale X"
 msgstr "缩放 X 坐标"
 
-#: clutter/clutter-actor.c:3964
+#: clutter/clutter-actor.c:3962
 msgid "Scale factor on the X axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:3979
+#: clutter/clutter-actor.c:3977
 msgid "Scale Y"
 msgstr "缩放 Y 坐标"
 
-#: clutter/clutter-actor.c:3980
+#: clutter/clutter-actor.c:3978
 msgid "Scale factor on the Y axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:3995
+#: clutter/clutter-actor.c:3993
 msgid "Scale Center X"
 msgstr ""
 
-#: clutter/clutter-actor.c:3996
+#: clutter/clutter-actor.c:3994
 msgid "Horizontal scale center"
 msgstr ""
 
-#: clutter/clutter-actor.c:4011
+#: clutter/clutter-actor.c:4009
 msgid "Scale Center Y"
 msgstr ""
 
-#: clutter/clutter-actor.c:4012
+#: clutter/clutter-actor.c:4010
 msgid "Vertical scale center"
 msgstr ""
 
-#: clutter/clutter-actor.c:4027
+#: clutter/clutter-actor.c:4025
 msgid "Scale Gravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4028
+#: clutter/clutter-actor.c:4026
 msgid "The center of scaling"
 msgstr ""
 
-#: clutter/clutter-actor.c:4045
+#: clutter/clutter-actor.c:4043
 msgid "Rotation Angle X"
 msgstr ""
 
-#: clutter/clutter-actor.c:4046
+#: clutter/clutter-actor.c:4044
 msgid "The rotation angle on the X axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4061
+#: clutter/clutter-actor.c:4059
 msgid "Rotation Angle Y"
 msgstr ""
 
-#: clutter/clutter-actor.c:4062
+#: clutter/clutter-actor.c:4060
 msgid "The rotation angle on the Y axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4077
+#: clutter/clutter-actor.c:4075
 msgid "Rotation Angle Z"
 msgstr ""
 
-#: clutter/clutter-actor.c:4078
+#: clutter/clutter-actor.c:4076
 msgid "The rotation angle on the Z axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4093
+#: clutter/clutter-actor.c:4091
 msgid "Rotation Center X"
 msgstr ""
 
-#: clutter/clutter-actor.c:4094
+#: clutter/clutter-actor.c:4092
 msgid "The rotation center on the X axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4110
+#: clutter/clutter-actor.c:4108
 msgid "Rotation Center Y"
 msgstr ""
 
-#: clutter/clutter-actor.c:4111
+#: clutter/clutter-actor.c:4109
 msgid "The rotation center on the Y axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4127
+#: clutter/clutter-actor.c:4125
 msgid "Rotation Center Z"
 msgstr ""
 
-#: clutter/clutter-actor.c:4128
+#: clutter/clutter-actor.c:4126
 msgid "The rotation center on the Z axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4144
+#: clutter/clutter-actor.c:4142
 msgid "Rotation Center Z Gravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4145
+#: clutter/clutter-actor.c:4143
 msgid "Center point for rotation around the Z axis"
 msgstr ""
 
-#: clutter/clutter-actor.c:4163
+#: clutter/clutter-actor.c:4161
 msgid "Anchor X"
 msgstr ""
 
-#: clutter/clutter-actor.c:4164
+#: clutter/clutter-actor.c:4162
 msgid "X coordinate of the anchor point"
 msgstr ""
 
-#: clutter/clutter-actor.c:4180
+#: clutter/clutter-actor.c:4178
 msgid "Anchor Y"
 msgstr ""
 
-#: clutter/clutter-actor.c:4181
+#: clutter/clutter-actor.c:4179
 msgid "Y coordinate of the anchor point"
 msgstr ""
 
-#: clutter/clutter-actor.c:4196
+#: clutter/clutter-actor.c:4194
 msgid "Anchor Gravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4197
+#: clutter/clutter-actor.c:4195
 msgid "The anchor point as a ClutterGravity"
 msgstr ""
 
-#: clutter/clutter-actor.c:4216
+#: clutter/clutter-actor.c:4214
 msgid "Show on set parent"
 msgstr ""
 
-#: clutter/clutter-actor.c:4217
+#: clutter/clutter-actor.c:4215
 msgid "Whether the actor is shown when parented"
 msgstr ""
 
-#: clutter/clutter-actor.c:4237
+#: clutter/clutter-actor.c:4235
 msgid "Clip to Allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:4238
+#: clutter/clutter-actor.c:4236
 msgid "Sets the clip region to track the actor's allocation"
 msgstr ""
 
-#: clutter/clutter-actor.c:4248
+#: clutter/clutter-actor.c:4246
 msgid "Text Direction"
 msgstr "文本方向"
 
-#: clutter/clutter-actor.c:4249
+#: clutter/clutter-actor.c:4247
 msgid "Direction of the text"
 msgstr "文本的方向"
 
-#: clutter/clutter-actor.c:4267
+#: clutter/clutter-actor.c:4265
 msgid "Has Pointer"
 msgstr ""
 
-#: clutter/clutter-actor.c:4268
+#: clutter/clutter-actor.c:4266
 msgid "Whether the actor contains the pointer of an input device"
 msgstr ""
 
-#: clutter/clutter-actor.c:4285
+#: clutter/clutter-actor.c:4283
 msgid "Actions"
 msgstr "动作"
 
-#: clutter/clutter-actor.c:4286
+#: clutter/clutter-actor.c:4284
 msgid "Adds an action to the actor"
 msgstr ""
 
-#: clutter/clutter-actor.c:4300
+#: clutter/clutter-actor.c:4298
 msgid "Constraints"
 msgstr ""
 
-#: clutter/clutter-actor.c:4301
+#: clutter/clutter-actor.c:4299
 msgid "Adds a constraint to the actor"
 msgstr ""
 
@@ -408,7 +408,8 @@ msgstr ""
 msgid "The name of the meta"
 msgstr ""
 
-#: clutter/clutter-actor-meta.c:219 clutter/clutter-shader.c:261
+#: clutter/clutter-actor-meta.c:219 clutter/clutter-input-device.c:314
+#: clutter/clutter-shader.c:295
 msgid "Enabled"
 msgstr "启用"
 
@@ -416,34 +417,34 @@ msgstr "启用"
 msgid "Whether the meta is enabled"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:231
-#: clutter/clutter-bind-constraint.c:286 clutter/clutter-clone.c:322
+#: clutter/clutter-align-constraint.c:252
+#: clutter/clutter-bind-constraint.c:316 clutter/clutter-clone.c:322
 msgid "Source"
 msgstr "来源"
 
-#: clutter/clutter-align-constraint.c:232
+#: clutter/clutter-align-constraint.c:253
 msgid "The source of the alignment"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:245
+#: clutter/clutter-align-constraint.c:266
 msgid "Align Axis"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:246
+#: clutter/clutter-align-constraint.c:267
 msgid "The axis to align the position to"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:265
-#: clutter/clutter-desaturate-effect.c:309
+#: clutter/clutter-align-constraint.c:286
+#: clutter/clutter-desaturate-effect.c:307
 msgid "Factor"
 msgstr ""
 
-#: clutter/clutter-align-constraint.c:266
+#: clutter/clutter-align-constraint.c:287
 msgid "The alignment factor, between 0.0 and 1.0"
 msgstr ""
 
 #: clutter/clutter-alpha.c:339 clutter/clutter-animation.c:523
-#: clutter/clutter-animator.c:1801
+#: clutter/clutter-animator.c:1802
 msgid "Timeline"
 msgstr "时间轴"
 
@@ -479,7 +480,7 @@ msgstr "应用动画的对象"
 msgid "The mode of the animation"
 msgstr "动画的模式"
 
-#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1785
+#: clutter/clutter-animation.c:494 clutter/clutter-animator.c:1786
 #: clutter/clutter-media.c:194 clutter/clutter-state.c:1282
 msgid "Duration"
 msgstr "时长"
@@ -500,7 +501,7 @@ msgstr "动画是否循环"
 msgid "The timeline used by the animation"
 msgstr "动画使用的时间轴"
 
-#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:299
+#: clutter/clutter-animation.c:537 clutter/clutter-behaviour.c:298
 msgid "Alpha"
 msgstr "Alpha"
 
@@ -508,216 +509,216 @@ msgstr "Alpha"
 msgid "The alpha used by the animation"
 msgstr "动画使用的 alpha"
 
-#: clutter/clutter-animator.c:1786
+#: clutter/clutter-animator.c:1787
 msgid "The duration of the animation"
 msgstr "动画的时长"
 
-#: clutter/clutter-animator.c:1802
+#: clutter/clutter-animator.c:1803
 msgid "The timeline of the animation"
 msgstr "动画的时间轴"
 
-#: clutter/clutter-behaviour.c:300
+#: clutter/clutter-behaviour.c:299
 msgid "Alpha Object to drive the behaviour"
 msgstr ""
 
-#: clutter/clutter-behaviour-depth.c:175
+#: clutter/clutter-behaviour-depth.c:174
 msgid "Start Depth"
 msgstr "起始色深"
 
-#: clutter/clutter-behaviour-depth.c:176
+#: clutter/clutter-behaviour-depth.c:175
 msgid "Initial depth to apply"
 msgstr "应用的初始色深"
 
-#: clutter/clutter-behaviour-depth.c:191
+#: clutter/clutter-behaviour-depth.c:190
 msgid "End Depth"
 msgstr "终点色深"
 
-#: clutter/clutter-behaviour-depth.c:192
+#: clutter/clutter-behaviour-depth.c:191
 msgid "Final depth to apply"
 msgstr "应用的终点色深"
 
-#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-ellipse.c:394
 msgid "Start Angle"
 msgstr "起始角度"
 
-#: clutter/clutter-behaviour-ellipse.c:396
-#: clutter/clutter-behaviour-rotate.c:277
+#: clutter/clutter-behaviour-ellipse.c:395
+#: clutter/clutter-behaviour-rotate.c:276
 msgid "Initial angle"
 msgstr "初始的角度"
 
-#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-ellipse.c:410
 msgid "End Angle"
 msgstr "终点角度"
 
-#: clutter/clutter-behaviour-ellipse.c:412
-#: clutter/clutter-behaviour-rotate.c:295
+#: clutter/clutter-behaviour-ellipse.c:411
+#: clutter/clutter-behaviour-rotate.c:294
 msgid "Final angle"
 msgstr "终点的角度"
 
-#: clutter/clutter-behaviour-ellipse.c:427
+#: clutter/clutter-behaviour-ellipse.c:426
 msgid "Angle x tilt"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:428
+#: clutter/clutter-behaviour-ellipse.c:427
 msgid "Tilt of the ellipse around x axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:443
+#: clutter/clutter-behaviour-ellipse.c:442
 msgid "Angle y tilt"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:444
+#: clutter/clutter-behaviour-ellipse.c:443
 msgid "Tilt of the ellipse around y axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:459
+#: clutter/clutter-behaviour-ellipse.c:458
 msgid "Angle z tilt"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:460
+#: clutter/clutter-behaviour-ellipse.c:459
 msgid "Tilt of the ellipse around z axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:476
+#: clutter/clutter-behaviour-ellipse.c:475
 msgid "Width of the ellipse"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:492
+#: clutter/clutter-behaviour-ellipse.c:491
 msgid "Height of ellipse"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:507
+#: clutter/clutter-behaviour-ellipse.c:506
 msgid "Center"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:508
+#: clutter/clutter-behaviour-ellipse.c:507
 msgid "Center of ellipse"
 msgstr ""
 
-#: clutter/clutter-behaviour-ellipse.c:522
-#: clutter/clutter-behaviour-rotate.c:330
+#: clutter/clutter-behaviour-ellipse.c:521
+#: clutter/clutter-behaviour-rotate.c:329
 msgid "Direction"
 msgstr "方向"
 
-#: clutter/clutter-behaviour-ellipse.c:523
-#: clutter/clutter-behaviour-rotate.c:331
+#: clutter/clutter-behaviour-ellipse.c:522
+#: clutter/clutter-behaviour-rotate.c:330
 #, fuzzy
 msgid "Direction of rotation"
 msgstr "文本方向"
 
-#: clutter/clutter-behaviour-opacity.c:178
+#: clutter/clutter-behaviour-opacity.c:177
 msgid "Opacity Start"
 msgstr ""
 
-#: clutter/clutter-behaviour-opacity.c:179
+#: clutter/clutter-behaviour-opacity.c:178
 msgid "Initial opacity level"
 msgstr ""
 
-#: clutter/clutter-behaviour-opacity.c:196
+#: clutter/clutter-behaviour-opacity.c:195
 msgid "Opacity End"
 msgstr ""
 
-#: clutter/clutter-behaviour-opacity.c:197
+#: clutter/clutter-behaviour-opacity.c:196
 msgid "Final opacity level"
 msgstr ""
 
-#: clutter/clutter-behaviour-path.c:220
+#: clutter/clutter-behaviour-path.c:219
 msgid "Path"
 msgstr "路径"
 
-#: clutter/clutter-behaviour-path.c:221
+#: clutter/clutter-behaviour-path.c:220
 msgid "The ClutterPath object representing the path to animate along"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:276
+#: clutter/clutter-behaviour-rotate.c:275
 msgid "Angle Begin"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:294
+#: clutter/clutter-behaviour-rotate.c:293
 msgid "Angle End"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:312
+#: clutter/clutter-behaviour-rotate.c:311
 msgid "Axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:313
+#: clutter/clutter-behaviour-rotate.c:312
 msgid "Axis of rotation"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:348
+#: clutter/clutter-behaviour-rotate.c:347
 msgid "Center X"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:349
+#: clutter/clutter-behaviour-rotate.c:348
 msgid "X coordinate of the center of rotation"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:366
+#: clutter/clutter-behaviour-rotate.c:365
 msgid "Center Y"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:367
+#: clutter/clutter-behaviour-rotate.c:366
 msgid "Y coordinate of the center of rotation"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:384
+#: clutter/clutter-behaviour-rotate.c:383
 msgid "Center Z"
 msgstr ""
 
-#: clutter/clutter-behaviour-rotate.c:385
+#: clutter/clutter-behaviour-rotate.c:384
 msgid "Z coordinate of the center of rotation"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:219
+#: clutter/clutter-behaviour-scale.c:218
 msgid "X Start Scale"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:220
+#: clutter/clutter-behaviour-scale.c:219
 msgid "Initial scale on the X axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:238
+#: clutter/clutter-behaviour-scale.c:237
 msgid "X End Scale"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:239
+#: clutter/clutter-behaviour-scale.c:238
 msgid "Final scale on the X axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:257
+#: clutter/clutter-behaviour-scale.c:256
 msgid "Y Start Scale"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:258
+#: clutter/clutter-behaviour-scale.c:257
 msgid "Initial scale on the Y axis"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:276
+#: clutter/clutter-behaviour-scale.c:275
 msgid "Y End Scale"
 msgstr ""
 
-#: clutter/clutter-behaviour-scale.c:277
+#: clutter/clutter-behaviour-scale.c:276
 msgid "Final scale on the Y axis"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:287
+#: clutter/clutter-bind-constraint.c:317
 msgid "The source of the binding"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:300
+#: clutter/clutter-bind-constraint.c:330
 msgid "Coordinate"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:301
+#: clutter/clutter-bind-constraint.c:331
 msgid "The coordinate to bind"
 msgstr ""
 
-#: clutter/clutter-bind-constraint.c:315
+#: clutter/clutter-bind-constraint.c:345
 msgid "Offset"
 msgstr "偏移"
 
-#: clutter/clutter-bind-constraint.c:316
+#: clutter/clutter-bind-constraint.c:346
 msgid "The offset in pixels to apply to the binding"
 msgstr ""
 
@@ -747,7 +748,7 @@ msgstr ""
 msgid "Default vertical alignment for the actors inside the layout manager"
 msgstr ""
 
-#: clutter/clutter-binding-pool.c:321
+#: clutter/clutter-binding-pool.c:320
 msgid "The unique name of the binding pool"
 msgstr ""
 
@@ -760,7 +761,7 @@ msgid "The layout manager used by the box"
 msgstr ""
 
 #: clutter/clutter-box.c:514 clutter/clutter-rectangle.c:258
-#: clutter/clutter-stage.c:1307
+#: clutter/clutter-stage.c:1317
 msgid "Color"
 msgstr "色彩"
 
@@ -897,19 +898,19 @@ msgstr ""
 msgid "The actor wrapped by this data"
 msgstr ""
 
-#: clutter/clutter-click-action.c:283
+#: clutter/clutter-click-action.c:302
 msgid "Pressed"
 msgstr "按下时"
 
-#: clutter/clutter-click-action.c:284
+#: clutter/clutter-click-action.c:303
 msgid "Whether the clickable should be in pressed state"
 msgstr ""
 
-#: clutter/clutter-click-action.c:297
+#: clutter/clutter-click-action.c:316
 msgid "Held"
 msgstr "保持时"
 
-#: clutter/clutter-click-action.c:298
+#: clutter/clutter-click-action.c:317
 msgid "Whether the clickable has a grab"
 msgstr ""
 
@@ -917,11 +918,11 @@ msgstr ""
 msgid "Specifies the actor to be cloned"
 msgstr ""
 
-#: clutter/clutter-colorize-effect.c:309
+#: clutter/clutter-colorize-effect.c:307
 msgid "Tint"
 msgstr ""
 
-#: clutter/clutter-colorize-effect.c:310
+#: clutter/clutter-colorize-effect.c:308
 msgid "The tint to apply"
 msgstr ""
 
@@ -950,11 +951,11 @@ msgstr ""
 msgid "The material to be used when painting the back of the actor"
 msgstr ""
 
-#: clutter/clutter-desaturate-effect.c:310
+#: clutter/clutter-desaturate-effect.c:308
 msgid "The desaturation factor"
 msgstr ""
 
-#: clutter/clutter-device-manager.c:130
+#: clutter/clutter-device-manager.c:130 clutter/clutter-input-device.c:343
 msgid "Backend"
 msgstr "后端"
 
@@ -962,35 +963,35 @@ msgstr "后端"
 msgid "The ClutterBackend of the device manager"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:490
+#: clutter/clutter-drag-action.c:491
 msgid "Horizontal Drag Threshold"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:491
+#: clutter/clutter-drag-action.c:492
 msgid "The horizontal amount of pixels required to start dragging"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:510
+#: clutter/clutter-drag-action.c:511
 msgid "Vertical Drag Threshold"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:511
+#: clutter/clutter-drag-action.c:512
 msgid "The vertical amount of pixels required to start dragging"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:532
+#: clutter/clutter-drag-action.c:533
 msgid "Drag Handle"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:533
+#: clutter/clutter-drag-action.c:534
 msgid "The actor that is being dragged"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:546
+#: clutter/clutter-drag-action.c:547
 msgid "Drag Axis"
 msgstr ""
 
-#: clutter/clutter-drag-action.c:547
+#: clutter/clutter-drag-action.c:548
 msgid "Constraints the dragging to an axis"
 msgstr ""
 
@@ -1054,26 +1055,72 @@ msgstr "最大行高"
 msgid "Maximum height for each row"
 msgstr "每行的最大高度"
 
-#: clutter/clutter-input-device.c:134
+#: clutter/clutter-input-device.c:219
 msgid "Id"
 msgstr "ID"
 
-#: clutter/clutter-input-device.c:135
+#: clutter/clutter-input-device.c:220
 msgid "Unique identifier of the device"
 msgstr "设备识别符"
 
-#: clutter/clutter-input-device.c:152
+#: clutter/clutter-input-device.c:236
 msgid "The name of the device"
 msgstr "设备名称"
 
-#: clutter/clutter-input-device.c:167
+#: clutter/clutter-input-device.c:250
 msgid "Device Type"
 msgstr "设备类型"
 
-#: clutter/clutter-input-device.c:168
+#: clutter/clutter-input-device.c:251
 msgid "The type of the device"
 msgstr "设备的类型"
 
+#: clutter/clutter-input-device.c:266
+#, fuzzy
+msgid "Device Manager"
+msgstr "管理器"
+
+#: clutter/clutter-input-device.c:267
+msgid "The device manager instance"
+msgstr ""
+
+#: clutter/clutter-input-device.c:280
+#, fuzzy
+msgid "Device Mode"
+msgstr "设备类型"
+
+#: clutter/clutter-input-device.c:281
+#, fuzzy
+msgid "The mode of the device"
+msgstr "设备名称"
+
+#: clutter/clutter-input-device.c:295
+#, fuzzy
+msgid "Has Cursor"
+msgstr "带有边界"
+
+#: clutter/clutter-input-device.c:296
+msgid "Whether the device has a cursor"
+msgstr ""
+
+#: clutter/clutter-input-device.c:315
+#, fuzzy
+msgid "Whether the device is enabled"
+msgstr "文本是否可以编辑"
+
+#: clutter/clutter-input-device.c:328
+msgid "Number of Axes"
+msgstr ""
+
+#: clutter/clutter-input-device.c:329
+#, fuzzy
+msgid "The number of axes on the device"
+msgstr "设备名称"
+
+#: clutter/clutter-input-device.c:344
+msgid "The backend instance"
+msgstr ""
+
 #: clutter/clutter-interval.c:397
 msgid "Value Type"
 msgstr "值类型"
@@ -1090,59 +1137,59 @@ msgstr "管理器"
 msgid "The manager that created this data"
 msgstr "创建此数据的管理器"
 
-#: clutter/clutter-main.c:756
+#: clutter/clutter-main.c:753
 msgid "default:LTR"
 msgstr "default:LTR"
 
-#: clutter/clutter-main.c:1560
+#: clutter/clutter-main.c:1557
 msgid "Show frames per second"
 msgstr "显示帧速率"
 
-#: clutter/clutter-main.c:1562
+#: clutter/clutter-main.c:1559
 msgid "Default frame rate"
 msgstr "默认帧率"
 
-#: clutter/clutter-main.c:1564
+#: clutter/clutter-main.c:1561
 msgid "Make all warnings fatal"
 msgstr "视所有警告为致命错误"
 
-#: clutter/clutter-main.c:1567
+#: clutter/clutter-main.c:1564
 msgid "Direction for the text"
 msgstr "文本方向"
 
-#: clutter/clutter-main.c:1570
+#: clutter/clutter-main.c:1567
 msgid "Disable mipmapping on text"
 msgstr "在文本上禁用 MIP 映射"
 
-#: clutter/clutter-main.c:1573
+#: clutter/clutter-main.c:1570
 msgid "Use 'fuzzy' picking"
 msgstr "使用模糊选取"
 
-#: clutter/clutter-main.c:1576
+#: clutter/clutter-main.c:1573
 msgid "Clutter debugging flags to set"
 msgstr "要设置的 Clutter 调试标志"
 
-#: clutter/clutter-main.c:1578
+#: clutter/clutter-main.c:1575
 msgid "Clutter debugging flags to unset"
 msgstr "要取消设置的 Clutter 调试标志"
 
-#: clutter/clutter-main.c:1582
+#: clutter/clutter-main.c:1579
 msgid "Clutter profiling flags to set"
 msgstr "要设置的 Clutter 性能分析标志"
 
-#: clutter/clutter-main.c:1584
+#: clutter/clutter-main.c:1581
 msgid "Clutter profiling flags to unset"
 msgstr "要取消设置的 Clutter 性能分析标志"
 
-#: clutter/clutter-main.c:1587
+#: clutter/clutter-main.c:1584
 msgid "Enable accessibility"
 msgstr "启用辅助功能"
 
-#: clutter/clutter-main.c:1774
+#: clutter/clutter-main.c:1771
 msgid "Clutter Options"
 msgstr "Clutter 选项"
 
-#: clutter/clutter-main.c:1775
+#: clutter/clutter-main.c:1772
 msgid "Show Clutter Options"
 msgstr "显示 Clutter 选项"
 
@@ -1258,48 +1305,48 @@ msgstr "文件名"
 msgid "The path of the currently parsed file"
 msgstr ""
 
-#: clutter/clutter-shader.c:215
+#: clutter/clutter-shader.c:249
 #, fuzzy
 msgid "Vertex Source"
 msgstr "顶点着色引擎"
 
-#: clutter/clutter-shader.c:216
+#: clutter/clutter-shader.c:250
 #, fuzzy
 msgid "Source of vertex shader"
 msgstr "顶点着色引擎"
 
-#: clutter/clutter-shader.c:230
+#: clutter/clutter-shader.c:264
 #, fuzzy
 msgid "Fragment Source"
 msgstr "片段着色引擎"
 
-#: clutter/clutter-shader.c:231
+#: clutter/clutter-shader.c:265
 #, fuzzy
 msgid "Source of fragment shader"
 msgstr "片段着色引擎"
 
-#: clutter/clutter-shader.c:246
+#: clutter/clutter-shader.c:280
 msgid "Compiled"
 msgstr ""
 
-#: clutter/clutter-shader.c:247
+#: clutter/clutter-shader.c:281
 msgid "Whether the shader is compiled and linked"
 msgstr ""
 
-#: clutter/clutter-shader.c:262
+#: clutter/clutter-shader.c:296
 msgid "Whether the shader is enabled"
 msgstr ""
 
-#: clutter/clutter-shader.c:467
+#: clutter/clutter-shader.c:501
 #, c-format
 msgid "%s compilation failed: %s"
 msgstr "%s 编译失败:%s"
 
-#: clutter/clutter-shader.c:468
+#: clutter/clutter-shader.c:502
 msgid "Vertex shader"
 msgstr "顶点着色引擎"
 
-#: clutter/clutter-shader.c:469
+#: clutter/clutter-shader.c:503
 msgid "Fragment shader"
 msgstr "片段着色引擎"
 
@@ -1311,98 +1358,107 @@ msgstr "着色引擎类型"
 msgid "The type of shader used"
 msgstr "使用的着色引擎类型"
 
-#: clutter/clutter-stage.c:1249
+#: clutter/clutter-stage.c:1259
 msgid "Fullscreen Set"
 msgstr ""
 
-#: clutter/clutter-stage.c:1250
+#: clutter/clutter-stage.c:1260
 msgid "Whether the main stage is fullscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1266
+#: clutter/clutter-stage.c:1276
 msgid "Offscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1267
+#: clutter/clutter-stage.c:1277
 msgid "Whether the main stage should be rendered offscreen"
 msgstr ""
 
-#: clutter/clutter-stage.c:1279 clutter/clutter-text.c:2643
+#: clutter/clutter-stage.c:1289 clutter/clutter-text.c:2667
 msgid "Cursor Visible"
 msgstr ""
 
-#: clutter/clutter-stage.c:1280
+#: clutter/clutter-stage.c:1290
 msgid "Whether the mouse pointer is visible on the main stage"
 msgstr ""
 
-#: clutter/clutter-stage.c:1294
+#: clutter/clutter-stage.c:1304
 msgid "User Resizable"
 msgstr "用户可改变大小"
 
-#: clutter/clutter-stage.c:1295
+#: clutter/clutter-stage.c:1305
 msgid "Whether the stage is able to be resized via user interaction"
 msgstr ""
 
-#: clutter/clutter-stage.c:1308
+#: clutter/clutter-stage.c:1318
 msgid "The color of the stage"
 msgstr ""
 
-#: clutter/clutter-stage.c:1322
+#: clutter/clutter-stage.c:1332
 msgid "Perspective"
 msgstr ""
 
-#: clutter/clutter-stage.c:1323
+#: clutter/clutter-stage.c:1333
 msgid "Perspective projection parameters"
 msgstr ""
 
-#: clutter/clutter-stage.c:1338
+#: clutter/clutter-stage.c:1348
 msgid "Title"
 msgstr "标题"
 
-#: clutter/clutter-stage.c:1339
+#: clutter/clutter-stage.c:1349
 msgid "Stage Title"
 msgstr ""
 
-#: clutter/clutter-stage.c:1354
+#: clutter/clutter-stage.c:1364
 msgid "Use Fog"
 msgstr ""
 
-#: clutter/clutter-stage.c:1355
+#: clutter/clutter-stage.c:1365
 msgid "Whether to enable depth cueing"
 msgstr ""
 
-#: clutter/clutter-stage.c:1369
+#: clutter/clutter-stage.c:1379
 msgid "Fog"
 msgstr ""
 
-#: clutter/clutter-stage.c:1370
+#: clutter/clutter-stage.c:1380
 msgid "Settings for the depth cueing"
 msgstr ""
 
-#: clutter/clutter-stage.c:1386
+#: clutter/clutter-stage.c:1396
 msgid "Use Alpha"
 msgstr "使用 Alpha"
 
-#: clutter/clutter-stage.c:1387
+#: clutter/clutter-stage.c:1397
 msgid "Whether to honour the alpha component of the stage color"
 msgstr ""
 
-#: clutter/clutter-stage.c:1403
+#: clutter/clutter-stage.c:1413
 msgid "Key Focus"
 msgstr ""
 
-#: clutter/clutter-stage.c:1404
+#: clutter/clutter-stage.c:1414
 msgid "The currently key focused actor"
 msgstr ""
 
-#: clutter/clutter-stage.c:1420
+#: clutter/clutter-stage.c:1430
 msgid "No Clear Hint"
 msgstr ""
 
-#: clutter/clutter-stage.c:1421
+#: clutter/clutter-stage.c:1431
 msgid "Whether the stage should clear its contents"
 msgstr ""
 
+#: clutter/clutter-stage.c:1444
+msgid "Accept Focus"
+msgstr ""
+
+#: clutter/clutter-stage.c:1445
+#, fuzzy
+msgid "Whether the stage should accept focus on show"
+msgstr "文本是否只应使用一行"
+
 #: clutter/clutter-state.c:1268
 msgid "State"
 msgstr ""
@@ -1416,192 +1472,192 @@ msgstr ""
 msgid "Default transition duration"
 msgstr "默认帧率"
 
-#: clutter/clutter-text.c:2530
+#: clutter/clutter-text.c:2554
 msgid "Font Name"
 msgstr "字体名称"
 
-#: clutter/clutter-text.c:2531
+#: clutter/clutter-text.c:2555
 msgid "The font to be used by the text"
 msgstr "文本使用的字体"
 
-#: clutter/clutter-text.c:2548
+#: clutter/clutter-text.c:2572
 msgid "Font Description"
 msgstr "字体描述"
 
-#: clutter/clutter-text.c:2549
+#: clutter/clutter-text.c:2573
 msgid "The font description to be used"
 msgstr "使用的字体描述"
 
-#: clutter/clutter-text.c:2565
+#: clutter/clutter-text.c:2589
 msgid "Text"
 msgstr "文本"
 
-#: clutter/clutter-text.c:2566
+#: clutter/clutter-text.c:2590
 msgid "The text to render"
 msgstr "要渲染的文本"
 
-#: clutter/clutter-text.c:2580
+#: clutter/clutter-text.c:2604
 msgid "Font Color"
 msgstr "字体颜色"
 
-#: clutter/clutter-text.c:2581
+#: clutter/clutter-text.c:2605
 msgid "Color of the font used by the text"
 msgstr "文本字体使用的颜色"
 
-#: clutter/clutter-text.c:2595
+#: clutter/clutter-text.c:2619
 msgid "Editable"
 msgstr "可编辑"
 
-#: clutter/clutter-text.c:2596
+#: clutter/clutter-text.c:2620
 msgid "Whether the text is editable"
 msgstr "文本是否可以编辑"
 
-#: clutter/clutter-text.c:2611
+#: clutter/clutter-text.c:2635
 msgid "Selectable"
 msgstr "可选择"
 
-#: clutter/clutter-text.c:2612
+#: clutter/clutter-text.c:2636
 msgid "Whether the text is selectable"
 msgstr "文本是否可以选择"
 
-#: clutter/clutter-text.c:2626
+#: clutter/clutter-text.c:2650
 msgid "Activatable"
 msgstr "可激活"
 
-#: clutter/clutter-text.c:2627
+#: clutter/clutter-text.c:2651
 msgid "Whether pressing return causes the activate signal to be emitted"
 msgstr ""
 
-#: clutter/clutter-text.c:2644
+#: clutter/clutter-text.c:2668
 msgid "Whether the input cursor is visible"
 msgstr ""
 
-#: clutter/clutter-text.c:2658 clutter/clutter-text.c:2659
+#: clutter/clutter-text.c:2682 clutter/clutter-text.c:2683
 msgid "Cursor Color"
 msgstr "指针颜色"
 
-#: clutter/clutter-text.c:2673
+#: clutter/clutter-text.c:2697
 msgid "Cursor Color Set"
 msgstr ""
 
-#: clutter/clutter-text.c:2674
+#: clutter/clutter-text.c:2698
 msgid "Whether the cursor color has been set"
 msgstr ""
 
-#: clutter/clutter-text.c:2689
+#: clutter/clutter-text.c:2713
 msgid "Cursor Size"
 msgstr "指针大小"
 
-#: clutter/clutter-text.c:2690
+#: clutter/clutter-text.c:2714
 msgid "The width of the cursor, in pixels"
 msgstr "指针的宽度,以像素计"
 
-#: clutter/clutter-text.c:2704
+#: clutter/clutter-text.c:2728
 #, fuzzy
 msgid "Cursor Position"
 msgstr "指针位置"
 
-#: clutter/clutter-text.c:2705
+#: clutter/clutter-text.c:2729
 msgid "The cursor position"
 msgstr "指针位置"
 
-#: clutter/clutter-text.c:2720
+#: clutter/clutter-text.c:2744
 msgid "Selection-bound"
 msgstr "选区边界"
 
-#: clutter/clutter-text.c:2721
+#: clutter/clutter-text.c:2745
 msgid "The cursor position of the other end of the selection"
 msgstr ""
 
-#: clutter/clutter-text.c:2736 clutter/clutter-text.c:2737
+#: clutter/clutter-text.c:2760 clutter/clutter-text.c:2761
 msgid "Selection Color"
 msgstr "选区颜色"
 
-#: clutter/clutter-text.c:2751
+#: clutter/clutter-text.c:2775
 msgid "Selection Color Set"
 msgstr ""
 
-#: clutter/clutter-text.c:2752
+#: clutter/clutter-text.c:2776
 msgid "Whether the selection color has been set"
 msgstr ""
 
-#: clutter/clutter-text.c:2767
+#: clutter/clutter-text.c:2791
 msgid "Attributes"
 msgstr "属性"
 
-#: clutter/clutter-text.c:2768
+#: clutter/clutter-text.c:2792
 msgid "A list of style attributes to apply to the contents of the actor"
 msgstr ""
 
-#: clutter/clutter-text.c:2790
+#: clutter/clutter-text.c:2814
 msgid "Use markup"
 msgstr "使用标记"
 
-#: clutter/clutter-text.c:2791
+#: clutter/clutter-text.c:2815
 msgid "Whether or not the text includes Pango markup"
 msgstr ""
 
-#: clutter/clutter-text.c:2807
+#: clutter/clutter-text.c:2831
 msgid "Line wrap"
 msgstr "换行"
 
-#: clutter/clutter-text.c:2808
+#: clutter/clutter-text.c:2832
 msgid "If set, wrap the lines if the text becomes too wide"
 msgstr ""
 
-#: clutter/clutter-text.c:2823
+#: clutter/clutter-text.c:2847
 msgid "Line wrap mode"
 msgstr "换行模式"
 
-#: clutter/clutter-text.c:2824
+#: clutter/clutter-text.c:2848
 msgid "Control how line-wrapping is done"
 msgstr "控制换行行为"
 
-#: clutter/clutter-text.c:2839
+#: clutter/clutter-text.c:2863
 msgid "Ellipsize"
 msgstr ""
 
-#: clutter/clutter-text.c:2840
+#: clutter/clutter-text.c:2864
 msgid "The preferred place to ellipsize the string"
 msgstr ""
 
-#: clutter/clutter-text.c:2856
+#: clutter/clutter-text.c:2880
 msgid "Line Alignment"
 msgstr ""
 
-#: clutter/clutter-text.c:2857
+#: clutter/clutter-text.c:2881
 msgid "The preferred alignment for the string, for multi-line text"
 msgstr ""
 
-#: clutter/clutter-text.c:2873
+#: clutter/clutter-text.c:2897
 msgid "Justify"
 msgstr ""
 
-#: clutter/clutter-text.c:2874
+#: clutter/clutter-text.c:2898
 msgid "Whether the text should be justified"
 msgstr ""
 
-#: clutter/clutter-text.c:2889
+#: clutter/clutter-text.c:2913
 msgid "Password Character"
 msgstr "密码字符"
 
-#: clutter/clutter-text.c:2890
+#: clutter/clutter-text.c:2914
 msgid "If non-zero, use this character to display the actor's contents"
 msgstr ""
 
-#: clutter/clutter-text.c:2904
+#: clutter/clutter-text.c:2928
 msgid "Max Length"
 msgstr "最大长度"
 
-#: clutter/clutter-text.c:2905
+#: clutter/clutter-text.c:2929
 msgid "Maximum length of the text inside the actor"
 msgstr ""
 
-#: clutter/clutter-text.c:2928
+#: clutter/clutter-text.c:2952
 msgid "Single Line Mode"
 msgstr "单行模式"
 
-#: clutter/clutter-text.c:2929
+#: clutter/clutter-text.c:2953
 msgid "Whether the text should be a single line"
 msgstr "文本是否只应使用一行"
 
@@ -1720,23 +1776,23 @@ msgstr ""
 msgid "Shape actor with alpha channel when picking"
 msgstr ""
 
-#: clutter/glx/clutter-backend-glx.c:128
+#: clutter/glx/clutter-backend-glx.c:131
 msgid "VBlank method to be used (none, dri or glx)"
 msgstr "要使用的 VBlank 方式(none、dir 或 glx)"
 
-#: clutter/x11/clutter-backend-x11.c:364
+#: clutter/x11/clutter-backend-x11.c:473
 msgid "X display to use"
 msgstr "要使用的 X 显示"
 
-#: clutter/x11/clutter-backend-x11.c:370
+#: clutter/x11/clutter-backend-x11.c:479
 msgid "X screen to use"
 msgstr "要使用的 X 屏幕"
 
-#: clutter/x11/clutter-backend-x11.c:375
+#: clutter/x11/clutter-backend-x11.c:484
 msgid "Make X calls synchronous"
 msgstr "使 X 调用同步"
 
-#: clutter/x11/clutter-backend-x11.c:382
+#: clutter/x11/clutter-backend-x11.c:491
 msgid "Enable XInput support"
 msgstr "启用 XInput 支持"
 
index 463764a..5d7e295 100644 (file)
@@ -32,6 +32,7 @@ units_sources += \
        test-cogl-depth-test.c                  \
        test-cogl-fixed.c                       \
        test-cogl-materials.c                   \
+       test-cogl-pipeline-user-matrix.c        \
        test-cogl-viewport.c                    \
        test-cogl-multitexture.c                \
        test-cogl-npot-texture.c                \
diff --git a/tests/conform/test-cogl-pipeline-user-matrix.c b/tests/conform/test-cogl-pipeline-user-matrix.c
new file mode 100644 (file)
index 0000000..afbeaaf
--- /dev/null
@@ -0,0 +1,144 @@
+#include <clutter/clutter.h>
+#include <string.h>
+
+#include "test-conform-common.h"
+
+static const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
+
+static void
+paint_cb (ClutterActor *stage)
+{
+  /* This texture is painted mirrored around the x-axis */
+  guint8 data0[] = {
+    0xff, 0x00, 0x00, /* red -> becomes bottom left */
+    0x00, 0xff, 0x00, /* green -> becomes bottom right */
+    0x00, 0x00, 0xff, /* blue -> becomes top left */
+    0xff, 0x00, 0xff  /* magenta -> becomes top right */
+  };
+  /* This texture is painted mirrored about the y-axis */
+  guint8 data1[] = {
+    0x00, 0xff, 0x00, /* green -> becomes top right */
+    0xff, 0xff, 0x00, /* yellow -> becomes top left */
+    0xff, 0x00, 0xff, /* magenta -> becomes bottom right */
+    0x00, 0xff, 0xff  /* cyan -> becomes bottom left */
+  };
+  CoglHandle tex0, tex1;
+  CoglPipeline *pipeline;
+  CoglMatrix matrix;
+  int width, height;
+  guint8 *pixels, *p;
+
+  width = clutter_actor_get_width (stage);
+  height = clutter_actor_get_height (stage);
+
+  tex0 = cogl_texture_new_from_data (2, 2,
+                                     COGL_TEXTURE_NO_ATLAS,
+                                     COGL_PIXEL_FORMAT_RGB_888,
+                                     COGL_PIXEL_FORMAT_ANY,
+                                     6,
+                                     data0);
+  tex1 = cogl_texture_new_from_data (2, 2,
+                                     COGL_TEXTURE_NO_ATLAS,
+                                     COGL_PIXEL_FORMAT_RGB_888,
+                                     COGL_PIXEL_FORMAT_ANY,
+                                     6,
+                                     data1);
+
+  pipeline = cogl_pipeline_new ();
+
+  /* Set the two textures as layers */
+  cogl_pipeline_set_layer_texture (pipeline, 0, tex0);
+  cogl_pipeline_set_layer_filters (pipeline, 0,
+                                   COGL_PIPELINE_FILTER_NEAREST,
+                                   COGL_PIPELINE_FILTER_NEAREST);
+  cogl_pipeline_set_layer_texture (pipeline, 1, tex1);
+  cogl_pipeline_set_layer_filters (pipeline, 1,
+                                   COGL_PIPELINE_FILTER_NEAREST,
+                                   COGL_PIPELINE_FILTER_NEAREST);
+
+  /* Set a combine mode so that the two textures get added together */
+  cogl_pipeline_set_layer_combine (pipeline, 1,
+                                   "RGBA=ADD(PREVIOUS, TEXTURE)",
+                                   NULL);
+
+  /* Set a matrix on the first layer so that it will mirror about the y-axis */
+  cogl_matrix_init_identity (&matrix);
+  cogl_matrix_translate (&matrix, 0.0f, 1.0f, 0.0f);
+  cogl_matrix_scale (&matrix, 1.0f, -1.0f, 1.0f);
+  cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
+
+  /* Set a matrix on the second layer so that it will mirror about the x-axis */
+  cogl_matrix_init_identity (&matrix);
+  cogl_matrix_translate (&matrix, 1.0f, 0.0f, 0.0f);
+  cogl_matrix_scale (&matrix, -1.0f, 1.0f, 1.0f);
+  cogl_pipeline_set_layer_matrix (pipeline, 1, &matrix);
+
+  cogl_set_source (pipeline);
+  cogl_rectangle (0, 0, width, height);
+
+  cogl_handle_unref (tex1);
+  cogl_handle_unref (tex0);
+  cogl_object_unref (pipeline);
+
+  /* The textures are setup so that when added together with the
+     correct matrices then all of the pixels should be white. We can
+     verify this by reading back the entire stage */
+  pixels = g_malloc (width * height * 4);
+
+  cogl_read_pixels (0, 0, width, height,
+                    COGL_READ_PIXELS_COLOR_BUFFER,
+                    COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+                    pixels);
+
+  for (p = pixels + width * height * 4; p > pixels;)
+    {
+      p -= 4;
+      g_assert_cmpint (p[0], ==, 0xff);
+      g_assert_cmpint (p[1], ==, 0xff);
+      g_assert_cmpint (p[2], ==, 0xff);
+    }
+
+  g_free (pixels);
+
+  clutter_main_quit ();
+}
+
+static gboolean
+queue_redraw (gpointer stage)
+{
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
+
+  return TRUE;
+}
+
+void
+test_cogl_pipeline_user_matrix (TestConformSimpleFixture *fixture,
+                                gconstpointer data)
+{
+  ClutterActor *stage;
+  guint idle_source;
+  guint paint_handler;
+
+  stage = clutter_stage_get_default ();
+
+  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+
+  /* We force continuous redrawing of the stage, since we need to skip
+   * the first few frames, and we wont be doing anything else that
+   * will trigger redrawing. */
+  idle_source = g_idle_add (queue_redraw, stage);
+
+  paint_handler = g_signal_connect_after (stage, "paint",
+                                          G_CALLBACK (paint_cb),
+                                          NULL);
+
+  clutter_actor_show (stage);
+
+  clutter_main ();
+
+  g_source_remove (idle_source);
+  g_signal_handler_disconnect (stage, paint_handler);
+
+  if (g_test_verbose ())
+    g_print ("OK\n");
+}
index d901de5..649ab81 100644 (file)
@@ -12,7 +12,7 @@ typedef CoglPrimitive * (* TestPrimFunc) (ClutterColor *expected_color);
 static CoglPrimitive *
 test_prim_p2 (ClutterColor *expected_color)
 {
-  static const CoglP2Vertex verts[] =
+  static const CoglVertexP2 verts[] =
     { { 0, 0 }, { 0, 10 }, { 10, 0 } };
 
   return cogl_primitive_new_p2 (COGL_VERTICES_MODE_TRIANGLES,
@@ -23,7 +23,7 @@ test_prim_p2 (ClutterColor *expected_color)
 static CoglPrimitive *
 test_prim_p3 (ClutterColor *expected_color)
 {
-  static const CoglP3Vertex verts[] =
+  static const CoglVertexP3 verts[] =
     { { 0, 0, 0 }, { 0, 10, 0 }, { 10, 0, 0 } };
 
   return cogl_primitive_new_p3 (COGL_VERTICES_MODE_TRIANGLES,
@@ -34,7 +34,7 @@ test_prim_p3 (ClutterColor *expected_color)
 static CoglPrimitive *
 test_prim_p2c4 (ClutterColor *expected_color)
 {
-  static const CoglP2C4Vertex verts[] =
+  static const CoglVertexP2C4 verts[] =
     { { 0, 0, 255, 255, 0, 255 },
       { 0, 10, 255, 255, 0, 255 },
       { 10, 0, 255, 255, 0, 255 } };
@@ -51,7 +51,7 @@ test_prim_p2c4 (ClutterColor *expected_color)
 static CoglPrimitive *
 test_prim_p3c4 (ClutterColor *expected_color)
 {
-  static const CoglP3C4Vertex verts[] =
+  static const CoglVertexP3C4 verts[] =
     { { 0, 0, 0, 255, 255, 0, 255 },
       { 0, 10, 0, 255, 255, 0, 255 },
       { 10, 0, 0, 255, 255, 0, 255 } };
@@ -68,7 +68,7 @@ test_prim_p3c4 (ClutterColor *expected_color)
 static CoglPrimitive *
 test_prim_p2t2 (ClutterColor *expected_color)
 {
-  static const CoglP2T2Vertex verts[] =
+  static const CoglVertexP2T2 verts[] =
     { { 0, 0, 1, 0 },
       { 0, 10, 1, 0 },
       { 10, 0, 1, 0 } };
@@ -83,7 +83,7 @@ test_prim_p2t2 (ClutterColor *expected_color)
 static CoglPrimitive *
 test_prim_p3t2 (ClutterColor *expected_color)
 {
-  static const CoglP3T2Vertex verts[] =
+  static const CoglVertexP3T2 verts[] =
     { { 0, 0, 0, 1, 0 },
       { 0, 10, 0, 1, 0 },
       { 10, 0, 0, 1, 0 } };
@@ -98,7 +98,7 @@ test_prim_p3t2 (ClutterColor *expected_color)
 static CoglPrimitive *
 test_prim_p2t2c4 (ClutterColor *expected_color)
 {
-  static const CoglP2T2C4Vertex verts[] =
+  static const CoglVertexP2T2C4 verts[] =
     { { 0, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff },
       { 0, 10, 1, 0, 0xff, 0xff, 0xf0, 0xff },
       { 10, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff } };
@@ -114,7 +114,7 @@ test_prim_p2t2c4 (ClutterColor *expected_color)
 static CoglPrimitive *
 test_prim_p3t2c4 (ClutterColor *expected_color)
 {
-  static const CoglP3T2C4Vertex verts[] =
+  static const CoglVertexP3T2C4 verts[] =
     { { 0, 0, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff },
       { 0, 10, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff },
       { 10, 0, 0, 1, 0, 0xff, 0xff, 0xf0, 0xff } };
index 84d610e..fae6a20 100644 (file)
@@ -213,6 +213,7 @@ main (int argc, char **argv)
   TEST_CONFORM_SIMPLE ("/cogl", test_cogl_fixed);
   TEST_CONFORM_SIMPLE ("/cogl", test_cogl_backface_culling);
   TEST_CONFORM_SIMPLE ("/cogl", test_cogl_materials);
+  TEST_CONFORM_SIMPLE ("/cogl", test_cogl_pipeline_user_matrix);
   TEST_CONFORM_SIMPLE ("/cogl", test_cogl_blend_strings);
   TEST_CONFORM_SIMPLE ("/cogl", test_cogl_premult);
   TEST_CONFORM_SIMPLE ("/cogl", test_cogl_readpixels);
index b9fb279..e702063 100644 (file)
@@ -363,6 +363,8 @@ test_list_model_from_script (TestConformSimpleFixture *fixture,
   gchar *test_file;
   const gchar *name;
   GType type;
+  ClutterModelIter *iter;
+  GValue value = { 0, };
 
   test_file = clutter_test_get_data_file ("test-script-model.json");
   clutter_script_load_from_file (script, test_file, &error);
@@ -397,4 +399,37 @@ test_list_model_from_script (TestConformSimpleFixture *fixture,
 
   g_assert (strcmp (name, "actor-column") == 0);
   g_assert (type == CLUTTER_TYPE_RECTANGLE);
+
+  g_assert (clutter_model_get_n_rows (CLUTTER_MODEL (model)) == 3);
+
+  iter = clutter_model_get_iter_at_row (CLUTTER_MODEL (model), 0);
+  clutter_model_iter_get_value (iter, 0, &value);
+  g_assert (G_VALUE_HOLDS_STRING (&value));
+  g_assert (strcmp (g_value_get_string (&value), "text-row-1") == 0);
+  g_value_unset (&value);
+
+  clutter_model_iter_get_value (iter, 1, &value);
+  g_assert (G_VALUE_HOLDS_INT (&value));
+  g_assert (g_value_get_int (&value) == 1);
+  g_value_unset (&value);
+
+  clutter_model_iter_get_value (iter, 2, &value);
+  g_assert (G_VALUE_HOLDS_OBJECT (&value));
+  g_assert (g_value_get_object (&value) == NULL);
+  g_value_unset (&value);
+
+  iter = clutter_model_iter_next (iter);
+  clutter_model_iter_get_value (iter, 2, &value);
+  g_assert (G_VALUE_HOLDS_OBJECT (&value));
+  g_assert (CLUTTER_IS_RECTANGLE (g_value_get_object (&value)));
+  g_value_unset (&value);
+
+  iter = clutter_model_iter_next (iter);
+  clutter_model_iter_get_value (iter, 2, &value);
+  g_assert (G_VALUE_HOLDS_OBJECT (&value));
+  g_assert (CLUTTER_IS_RECTANGLE (g_value_get_object (&value)));
+  g_assert (strcmp (clutter_actor_get_name (g_value_get_object (&value)),
+                    "actor-row-3") == 0);
+  g_value_unset (&value);
+  g_object_unref (iter);
 }
index 30a4d2c..b2de235 100644 (file)
@@ -466,12 +466,18 @@ path_test_convert_to_cairo_path (CallbackData *data)
           last_point = path_start;
 
           /* Cairo always adds a move to after every close so we need
-             to insert one here */
-          memmove (data->nodes + i + 2, data->nodes + i + 1,
-                   (data->n_nodes - i - 1) * sizeof (ClutterPathNode));
-          data->nodes[i + 1].type = CLUTTER_PATH_MOVE_TO;
-          data->nodes[i + 1].points[0] = last_point;
-          data->n_nodes++;
+             to insert one here. Since Cairo commit 166453c1abf2 it
+             doesn't seem to do this anymore so will assume that if
+             Cairo's minor version is >= 11 then it includes that
+             commit */
+          if (cairo_version () < CAIRO_VERSION_ENCODE (1, 11, 0))
+            {
+              memmove (data->nodes + i + 2, data->nodes + i + 1,
+                       (data->n_nodes - i - 1) * sizeof (ClutterPathNode));
+              data->nodes[i + 1].type = CLUTTER_PATH_MOVE_TO;
+              data->nodes[i + 1].points[0] = last_point;
+              data->n_nodes++;
+            }
           break;
         }
     }
index 888affb..f9dbf91 100644 (file)
@@ -35,11 +35,9 @@ watchdog_timeout (TestState *state)
 
 static void
 new_frame_cb (ClutterTimeline *timeline,
-              gint frame_num,
+              gint elapsed_time,
               TestState *state)
 {
-  gint elapsed_time = clutter_timeline_get_elapsed_time (timeline);
-
   if (elapsed_time == TEST_TIMELINE_DURATION)
     {
       g_test_message ("new-frame signal received (end of timeline)");
index 075bfbe..9bd6aef 100644 (file)
@@ -5,5 +5,13 @@
     [ "text-column", "gchararray" ],
     [ "int-column", "gint" ],
     [ "actor-column", "ClutterRectangle" ]
+  ],
+  "rows" : [
+    [ "text-row-1", 1, null ],
+    [ "text-row-2", 2, { "type" : "ClutterRectangle", "color" : "blue" } ],
+    {
+      "int-column" : 3,
+      "actor-column" : { "type" : "ClutterRectangle", "name" : "actor-row-3" }
+    }
   ]
 }
index 108583b..f742c72 100644 (file)
@@ -38,6 +38,26 @@ static GOptionEntry super_oh_entries[] = {
   { NULL }
 };
 
+static void
+on_group_destroy (ClutterActor *actor,
+                  SuperOH      *oh)
+{
+  oh->group = NULL;
+}
+
+static void
+on_hand_destroy (ClutterActor *actor,
+                 SuperOH      *oh)
+{
+  int i;
+
+  for (i = 0; i < n_hands; i++)
+    {
+      if (oh->hand[i] == actor)
+        oh->hand[i] = NULL;
+    }
+}
+
 static gboolean
 on_button_press_event (ClutterActor *actor,
                        ClutterEvent *event,
@@ -80,7 +100,10 @@ input_cb (ClutterActor *stage,
           gint i;
 
           for (i = 0; i < n_hands; i++)
-            clutter_actor_show (oh->hand[i]);
+            {
+              if (oh->hand[i] != NULL)
+                clutter_actor_show (oh->hand[i]);
+            }
 
           return TRUE;
         }
@@ -100,23 +123,24 @@ frame_cb (ClutterTimeline *timeline,
   float rotation = clutter_timeline_get_progress (timeline) * 360.0f;
 
   /* Rotate everything clockwise about stage center*/
-
-  clutter_actor_set_rotation (oh->group,
-                              CLUTTER_Z_AXIS,
-                              rotation,
-                             oh->stage_width / 2,
-                              oh->stage_height / 2,
-                             0);
+  if (oh->group != NULL)
+    clutter_actor_set_rotation (oh->group,
+                                CLUTTER_Z_AXIS,
+                                rotation,
+                                oh->stage_width / 2,
+                                oh->stage_height / 2,
+                                0);
 
   for (i = 0; i < n_hands; i++)
     {
       /* Rotate each hand around there centers - to get this we need
        * to take into account any scaling.
        */
-      clutter_actor_set_rotation (oh->hand[i],
-                                  CLUTTER_Z_AXIS,
-                                  -6.0 * rotation,
-                                  0, 0, 0);
+      if (oh->hand[i] != NULL)
+        clutter_actor_set_rotation (oh->hand[i],
+                                    CLUTTER_Z_AXIS,
+                                    -6.0 * rotation,
+                                    0, 0, 0);
     }
 }
 
@@ -192,6 +216,7 @@ test_actors_main (int argc, char *argv[])
   /* create a new group to hold multiple actors in a group */
   oh->group = clutter_group_new();
   clutter_actor_set_name (oh->group, "Group");
+  g_signal_connect (oh->group, "destroy", G_CALLBACK (on_group_destroy), oh);
 
   oh->hand = g_new (ClutterActor*, n_hands);
 
@@ -245,6 +270,10 @@ test_actors_main (int argc, char *argv[])
                         G_CALLBACK (on_button_press_event),
                         oh);
 
+      g_signal_connect (oh->hand[i], "destroy",
+                        G_CALLBACK (on_hand_destroy),
+                        oh);
+
       if (i % 2)
        clutter_behaviour_apply (oh->scaler_1, oh->hand[i]);
       else
@@ -266,6 +295,8 @@ test_actors_main (int argc, char *argv[])
 
   clutter_main ();
 
+  clutter_timeline_stop (oh->timeline);
+
   /* clean up */
   g_object_unref (oh->scaler_1);
   g_object_unref (oh->scaler_2);
index a8a8c3c..95ede02 100644 (file)
@@ -1,5 +1,6 @@
 #include <clutter/clutter.h>
 #include <gmodule.h>
+#include <math.h>
 
 typedef struct _CallbackData CallbackData;
 typedef struct _Clip Clip;
@@ -8,7 +9,7 @@ typedef enum
   {
     CLIP_NONE,
     CLIP_RECTANGLE,
-    CLIP_ELLIPSE,
+    CLIP_ROTATED_RECTANGLE,
     CLIP_SHAPES
   } ClipType;
 
@@ -77,11 +78,19 @@ make_clip_path (Clip *clip)
                            clip->y2);
       break;
 
-    case CLIP_ELLIPSE:
-      cogl_path_ellipse ((clip->x1 + clip->x2) / 2,
-                         (clip->y1 + clip->y2) / 2,
-                         (clip->x2 - clip->x1) / 2,
-                         (clip->y2 - clip->y1) / 2);
+    case CLIP_ROTATED_RECTANGLE:
+      {
+        int size = MIN (ABS (clip->x2 - clip->x1),
+                        ABS (clip->y2 - clip->y1));
+        int cx = (clip->x1 + clip->x2) / 2;
+        int cy = (clip->y1 + clip->y2) / 2;
+
+        cogl_path_move_to (cx - size / 2, cy);
+        cogl_path_line_to (cx, cy - size / 2);
+        cogl_path_line_to (cx + size / 2, cy);
+        cogl_path_line_to (cx, cy + size / 2);
+        cogl_path_close ();
+      }
       break;
 
     case CLIP_SHAPES:
@@ -138,6 +147,24 @@ on_paint (ClutterActor *actor, CallbackData *data)
                                   clip->y1,
                                   clip->x2,
                                   clip->y2);
+      else if (clip->type == CLIP_ROTATED_RECTANGLE)
+        {
+          float size = MIN (ABS (clip->x2 - clip->x1),
+                            ABS (clip->y2 - clip->y1));
+          int cx = (clip->x1 + clip->x2) / 2;
+          int cy = (clip->y1 + clip->y2) / 2;
+
+          size = sqrtf ((size / 2) * (size / 2) * 2);
+
+          cogl_push_matrix ();
+
+          /* Rotate 45° about the centre point */
+          cogl_translate (cx, cy, 0.0f);
+          cogl_rotate (45.0f, 0.0f, 0.0f, 1.0f);
+          cogl_clip_push_rectangle (-size / 2, -size / 2, size / 2, size / 2);
+
+          cogl_pop_matrix ();
+        }
       else
         {
           make_clip_path (clip);
@@ -207,7 +234,7 @@ on_button_press (ClutterActor *stage, ClutterButtonEvent *event,
   data->current_clip.type
     = event->button == 1 ? CLIP_RECTANGLE
     : event->button == 2 ? CLIP_SHAPES
-    : CLIP_ELLIPSE;
+    : CLIP_ROTATED_RECTANGLE;
 
   clutter_actor_queue_redraw (stage);
 
index b8073ba..76338a7 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <glib.h>
 #include <gmodule.h>
 #include <stdlib.h>
index 37ad4b4..e9ecf98 100644 (file)
@@ -1,10 +1,10 @@
-#include <config.h>
-#undef COGL_ENABLE_EXPERIMENTAL_2_0_API
 #include <glib.h>
 #include <gmodule.h>
 #include <stdlib.h>
-#include <clutter/clutter.h>
+
+#undef COGL_ENABLE_EXPERIMENTAL_2_0_API
 #include <cogl/cogl.h>
+#include <clutter/clutter.h>
 
 typedef void (*PaintFunc) (void);
 
index 3c83e92..21ebe31 100644 (file)
@@ -328,7 +328,9 @@ test_cogl_shader_glsl_main (int argc, char *argv[])
 
   file = g_build_filename (TESTS_DATADIR, "redhand.png", NULL);
   error = NULL;
-  redhand = cogl_texture_new_from_file (file, 0, COGL_PIXEL_FORMAT_ANY,
+  redhand = cogl_texture_new_from_file (file,
+                                        COGL_TEXTURE_NO_ATLAS,
+                                        COGL_PIXEL_FORMAT_ANY,
                                         &error);
   if (redhand == COGL_INVALID_HANDLE)
     g_error ("image load failed: %s", error->message);
index 271ee9f..fe6ad79 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <glib.h>
 #include <gmodule.h>
 #include <stdlib.h>
index a07fb12..3f059b9 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <glib.h>
 #include <gmodule.h>
 #include <stdlib.h>
index ffada94..20cf081 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <glib.h>
 #include <gmodule.h>
 #include <stdlib.h>
index 1c3b1be..05c8b8b 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <glib.h>
 #include <gmodule.h>
 #include <stdlib.h>
index 6b16d33..37eb864 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <glib.h>
 #include <gmodule.h>
 #include <stdlib.h>
index 8d13447..c1fa1b5 100644 (file)
@@ -1,4 +1,3 @@
-#include <config.h>
 #include <glib.h>
 #include <gmodule.h>
 #include <stdlib.h>
index 9efb55d..9ebbea4 100644 (file)
@@ -152,7 +152,6 @@ test_constraints_main (int argc, char *argv[])
       clutter_color_from_string (&rect_color, colors[i]);
       rect = clutter_rectangle_new ();
       clutter_rectangle_set_color (CLUTTER_RECTANGLE (rect), &rect_color);
-      clutter_actor_set_size (rect, 128, 128);
       clutter_actor_set_opacity (rect, 0);
       clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);
 
@@ -162,6 +161,9 @@ test_constraints_main (int argc, char *argv[])
       constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_Y, 0.0);
       clutter_actor_add_constraint_with_name (rect, "y-bind", constraint);
 
+      constraint = clutter_bind_constraint_new (rects[Center], CLUTTER_BIND_SIZE, 0.0);
+      clutter_actor_add_constraint_with_name (rect, "size-bind", constraint);
+
       rects[i] = rect;
     }
 
index e286a06..fe060db 100644 (file)
@@ -4,9 +4,9 @@
 #include <clutter/x11/clutter-x11.h>
 
 typedef struct {
+  ClutterActor *stage;
 
   GHashTable *devices;
-
 } TestDevicesApp;
 
 static const gchar *
@@ -26,6 +26,47 @@ device_type_name (ClutterInputDevice *device)
     case CLUTTER_EXTENSION_DEVICE:
       return "Extension";
 
+    case CLUTTER_PEN_DEVICE:
+      return "Pen";
+
+    case CLUTTER_ERASER_DEVICE:
+      return "Eraser";
+
+    case CLUTTER_CURSOR_DEVICE:
+      return "Cursor";
+
+    default:
+      return "Unknown";
+    }
+
+  g_warn_if_reached ();
+
+  return NULL;
+}
+
+static const gchar *
+axis_type_name (ClutterInputAxis axis)
+{
+  switch (axis)
+    {
+    case CLUTTER_INPUT_AXIS_X:
+      return "Absolute X";
+
+    case CLUTTER_INPUT_AXIS_Y:
+      return "Absolute Y";
+
+    case CLUTTER_INPUT_AXIS_PRESSURE:
+      return "Pressure";
+
+    case CLUTTER_INPUT_AXIS_XTILT:
+      return "X Tilt";
+
+    case CLUTTER_INPUT_AXIS_YTILT:
+      return "Y Tilt";
+
+    case CLUTTER_INPUT_AXIS_WHEEL:
+      return "Wheel";
+
     default:
       return "Unknown";
     }
@@ -36,23 +77,67 @@ device_type_name (ClutterInputDevice *device)
 }
 
 static gboolean
-stage_motion_event_cb (ClutterActor *actor, 
-                       ClutterEvent *event, 
-                       gpointer userdata)
+stage_button_event_cb (ClutterActor   *actor,
+                       ClutterEvent   *event,
+                       TestDevicesApp *app)
 {
-  TestDevicesApp *app = (TestDevicesApp *)userdata;
   ClutterInputDevice *device;
+  ClutterInputDevice *source_device;
   ClutterActor *hand = NULL;
+  gdouble *axes;
+  guint n_axes, i;
 
   device = clutter_event_get_device (event);
+  source_device = clutter_event_get_source_device (event);
 
   hand = g_hash_table_lookup (app->devices, device);
 
-  g_print ("Device: '%s' (id:%d, type:%s)\n",
+  g_print ("Device: '%s' (id:%d, type: %s, source: '%s', axes: %d)\n",
            clutter_input_device_get_device_name (device),
            clutter_input_device_get_device_id (device),
-           device_type_name (device));
+           device_type_name (device),
+           source_device != device
+             ? clutter_input_device_get_device_name (source_device)
+             : "<same>",
+           clutter_input_device_get_n_axes (device));
+
+  if (hand != NULL)
+    {
+      gfloat event_x, event_y;
+
+      clutter_event_get_coords (event, &event_x, &event_y);
+      clutter_actor_set_position (hand, event_x, event_y);
+    }
+
+  axes = clutter_event_get_axes (event, &n_axes);
+  for (i = 0; i < n_axes; i++)
+    {
+      ClutterInputAxis axis;
+
+      axis = clutter_input_device_get_axis (device, i);
+      if (axis == CLUTTER_INPUT_AXIS_IGNORE)
+        continue;
+
+      g_print ("\tAxis[%2d][%s].value: %.2f\n",
+               i,
+               axis_type_name (axis),
+               axes[i]);
+    }
+
+  return FALSE;
+}
+
+static gboolean
+stage_motion_event_cb (ClutterActor   *actor,
+                       ClutterEvent   *event,
+                       TestDevicesApp *app)
+{
+  ClutterInputDevice *device;
+  ClutterActor *hand = NULL;
+
+  device = clutter_event_get_device (event);
 
+  hand = g_hash_table_lookup (app->devices, device);
   if (hand != NULL)
     {
       gfloat event_x, event_y;
@@ -66,12 +151,70 @@ stage_motion_event_cb (ClutterActor *actor,
   return FALSE;
 }
 
+static void
+manager_device_added_cb (ClutterDeviceManager *manager,
+                         ClutterInputDevice   *device,
+                         TestDevicesApp       *app)
+{
+  ClutterInputDeviceType device_type;
+  ClutterActor *hand = NULL;
+
+  g_print ("got a %s device '%s' with id %d\n",
+           device_type_name (device),
+           clutter_input_device_get_device_name (device),
+           clutter_input_device_get_device_id (device));
+
+  device_type = clutter_input_device_get_device_type (device);
+  if (device_type == CLUTTER_POINTER_DEVICE ||
+      device_type == CLUTTER_PEN_DEVICE ||
+      device_type == CLUTTER_POINTER_DEVICE)
+    {
+      g_print ("*** enabling device '%s' ***\n",
+               clutter_input_device_get_device_name (device));
+
+      clutter_input_device_set_enabled (device, TRUE);
+
+      hand = clutter_texture_new_from_file (TESTS_DATADIR
+                                            G_DIR_SEPARATOR_S
+                                            "redhand.png",
+                                            NULL);
+      g_hash_table_insert (app->devices, device, hand);
+
+      clutter_container_add_actor (CLUTTER_CONTAINER (app->stage), hand);
+    }
+}
+
+static void
+manager_device_removed_cb (ClutterDeviceManager *manager,
+                           ClutterInputDevice   *device,
+                           TestDevicesApp       *app)
+{
+  ClutterInputDeviceType device_type;
+  ClutterActor *hand = NULL;
+
+  g_print ("removed a %s device '%s' with id %d\n",
+           device_type_name (device),
+           clutter_input_device_get_device_name (device),
+           clutter_input_device_get_device_id (device));
+
+  device_type = clutter_input_device_get_device_type (device);
+  if (device_type == CLUTTER_POINTER_DEVICE ||
+      device_type == CLUTTER_PEN_DEVICE ||
+      device_type == CLUTTER_POINTER_DEVICE)
+    {
+      hand = g_hash_table_lookup (app->devices, device);
+      if (hand != NULL)
+        clutter_container_add_actor (CLUTTER_CONTAINER (app->stage), hand);
+
+      g_hash_table_remove (app->devices, device);
+    }
+}
+
 G_MODULE_EXPORT int
 test_devices_main (int argc, char **argv)
 {
   ClutterActor *stage;
   TestDevicesApp *app;
-  ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff };
   ClutterDeviceManager *manager;
   const GSList *stage_devices, *l;
 
@@ -83,17 +226,31 @@ test_devices_main (int argc, char **argv)
   app = g_new0 (TestDevicesApp, 1);
   app->devices = g_hash_table_new (g_direct_hash, g_direct_equal) ;
 
-  stage = clutter_stage_get_default ();
-  clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
-  //clutter_stage_fullscreen (CLUTTER_STAGE (stage));
-
+  stage = clutter_stage_new ();
+  clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_LightSkyBlue);
+  clutter_stage_set_title (CLUTTER_STAGE (stage), "Devices");
+  clutter_stage_hide_cursor (CLUTTER_STAGE (stage));
+  g_signal_connect (stage,
+                    "destroy", G_CALLBACK (clutter_main_quit),
+                    NULL);
   g_signal_connect (stage, 
-                    "motion-event", G_CALLBACK(stage_motion_event_cb),
+                    "motion-event", G_CALLBACK (stage_motion_event_cb),
                     app);
+  g_signal_connect (stage,
+                    "button-press-event", G_CALLBACK (stage_button_event_cb),
+                    app);
+  app->stage = stage;
 
   clutter_actor_show_all (stage);
 
   manager = clutter_device_manager_get_default ();
+  g_signal_connect (manager,
+                    "device-added", G_CALLBACK (manager_device_added_cb),
+                    app);
+  g_signal_connect (manager,
+                    "device-removed", G_CALLBACK (manager_device_removed_cb),
+                    app);
+
   stage_devices = clutter_device_manager_peek_devices (manager);
 
   if (stage_devices == NULL)
@@ -105,15 +262,21 @@ test_devices_main (int argc, char **argv)
       ClutterInputDeviceType device_type;
       ClutterActor *hand = NULL;
 
-      g_print ("got a %s device '%s' with id %d...\n",
+      g_print ("got a %s device '%s' with id %d\n",
                device_type_name (device),
                clutter_input_device_get_device_name (device),
                clutter_input_device_get_device_id (device));
 
       device_type = clutter_input_device_get_device_type (device);
       if (device_type == CLUTTER_POINTER_DEVICE ||
-          device_type == CLUTTER_EXTENSION_DEVICE)
+          device_type == CLUTTER_PEN_DEVICE ||
+          device_type == CLUTTER_POINTER_DEVICE)
         {
+          g_print ("*** enabling device '%s' ***\n",
+                   clutter_input_device_get_device_name (device));
+
+          clutter_input_device_set_enabled (device, TRUE);
+
           hand = clutter_texture_new_from_file (TESTS_DATADIR
                                                 G_DIR_SEPARATOR_S
                                                 "redhand.png",
index 22b3cba..9f32308 100644 (file)
@@ -110,10 +110,7 @@ test_flow_layout_main (int argc, char *argv[])
   clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
 
   if (!fixed_size)
-    {
-      clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_WIDTH, 0.0));
-      clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_HEIGHT, 0.0));
-    }
+    clutter_actor_add_constraint (box, clutter_bind_constraint_new (stage, CLUTTER_BIND_SIZE, 0.0));
 
   clutter_actor_set_position (box, 0, 0);
 
index e97c097..45a52ef 100644 (file)
@@ -1,7 +1,3 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <gmodule.h>
 
 #undef CLUTTER_DISABLE_DEPRECATED
@@ -16,7 +12,7 @@
 #include <stdlib.h>
 #include <glib.h>
 
-#ifdef HAVE_CLUTTER_GLX
+#ifdef CLUTTER_WINDOWING_X11
 #include "clutter/x11/clutter-x11.h"
 #endif
 
@@ -205,7 +201,7 @@ test_paint_wrapper_main (int argc, char *argv[])
 
   error = NULL;
 
-#ifdef HAVE_CLUTTER_GLX
+#ifdef CLUTTER_WINDOWING_X11
   clutter_x11_set_use_argb_visual (TRUE);
 #endif
 
index 3668654..2058580 100644 (file)
@@ -1,4 +1,6 @@
-#include <config.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
 #include <stdlib.h>
 #include <string.h>
@@ -7,16 +9,13 @@
 #undef CLUTTER_DISABLE_DEPRECATED
 #include <clutter/clutter.h>
 
-#if HAVE_CLUTTER_GLX
+#ifdef CLUTTER_WINDOWING_X11
 
-#include <clutter/x11/clutter-x11.h>
-#include <clutter/x11/clutter-x11-texture-pixmap.h>
+# include <clutter/x11/clutter-x11.h>
+# include <clutter/x11/clutter-x11-texture-pixmap.h>
 
-#include <clutter/glx/clutter-glx.h>
-#include <clutter/glx/clutter-glx-texture-pixmap.h>
-
-#include <X11/Xlib.h>
-#include <X11/extensions/Xcomposite.h>
+# include <X11/Xlib.h>
+# include <X11/extensions/Xcomposite.h>
 
 #define IMAGE   TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png"
 
@@ -24,7 +23,6 @@
 # include <gdk-pixbuf/gdk-pixbuf.h>
 
 static gboolean disable_x11 = FALSE;
-static gboolean disable_glx = FALSE;
 static gboolean disable_animation = FALSE;
 
 static GOptionEntry g_options[] =
@@ -35,12 +33,6 @@ static GOptionEntry g_options[] =
     &disable_x11,
     "Disable redirection through X11 pixmap",
     NULL },
-  { "disable-glx",
-    0, 0,
-    G_OPTION_ARG_NONE,
-    &disable_glx,
-    "Disable redirection through GLX pixmap",
-    NULL },
   { "disable-animation",
     0, 0,
     G_OPTION_ARG_NONE,
@@ -320,35 +312,6 @@ test_pixmap_main (int argc, char **argv)
         clutter_behaviour_apply (depth_behavior, group);
     }
 
-#ifdef HAVE_CLUTTER_GLX
-  /* a window with glx */
-  if (!disable_glx)
-    {
-      group = clutter_group_new ();
-      clutter_container_add_actor (CLUTTER_CONTAINER (stage), group);
-      label = clutter_text_new_with_text ("fixed",
-                                          "ClutterGLXTexture (Window)");
-      clutter_container_add_actor (CLUTTER_CONTAINER (group), label);
-      tex = clutter_glx_texture_pixmap_new_with_window (win_remote);
-      clutter_container_add_actor (CLUTTER_CONTAINER (group), tex);
-      clutter_actor_set_position (tex, 0, 20);
-      clutter_x11_texture_pixmap_set_automatic (CLUTTER_X11_TEXTURE_PIXMAP (tex),
-                                               TRUE);
-      clutter_texture_set_filter_quality (CLUTTER_TEXTURE (tex),
-                                         CLUTTER_TEXTURE_QUALITY_HIGH);
-      clutter_actor_set_position (group,
-                                 clutter_actor_get_width (stage)
-                                 - clutter_actor_get_width (tex),
-                                 0);
-      if (!disable_animation)
-        clutter_behaviour_apply (depth_behavior, group);
-
-      if (!clutter_glx_texture_pixmap_using_extension (
-                                     CLUTTER_GLX_TEXTURE_PIXMAP (tex)))
-       g_print ("NOTE: Using fallback path, not GLX TFP!\n");
-    }
-#endif /* HAVE_CLUTTER_GLX */
-
   if (group)
     row_height = clutter_actor_get_height (group);
   else
@@ -400,6 +363,12 @@ test_pixmap_main (int argc, char **argv)
   return EXIT_SUCCESS;
 }
 
-#else /* HAVE_CLUTTER_GLX */
-int test_pixmap_main (int argc, char **argv) { return EXIT_SUCCESS; };
-#endif /* HAVE_CLUTTER_GLX */
+#else
+
+int
+test_pixmap_main (int argc, char **argv)
+{
+  return EXIT_SUCCESS;
+};
+
+#endif /* CLUTTER_WINDOWING_X11 */
index c552fef..66bc928 100644 (file)
@@ -144,7 +144,7 @@ static ShaderSource shaders[]=
      FRAGMENT_SHADER_VARS
      "float get_avg_rel(sampler2D texB, float dx, float dy)"
      "{"
-     "  vec4 colorB = texture2D (texB, cogl_tex_coord_in.st + vec2(dx, dy));"
+     "  vec4 colorB = texture2D (texB, cogl_tex_coord_in[0].st + vec2(dx, dy));"
      "  return (colorB.r + colorB.g + colorB.b) / 3.0;"
      "}"
      FRAGMENT_SHADER_BEGIN
index 58a601d..fba4736 100644 (file)
@@ -1,7 +1,3 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <gmodule.h>
 
index 3e86761..8e2c00c 100644 (file)
@@ -53,30 +53,16 @@ do_events (ClutterActor *stage)
     }
 }
 
-static gboolean
-fps_cb (gpointer data)
+static void
+on_paint (ClutterActor *stage, gconstpointer *data)
 {
-  ClutterActor *stage = CLUTTER_ACTOR (data);
-
-  static GTimer *timer = NULL;
-  static gint fps = 0;
-
-  if (!timer)
-    {
-      timer = g_timer_new ();
-      g_timer_start (timer);
-    }
-
-  if (g_timer_elapsed (timer, NULL) >= 1)
-    {
-      printf ("fps: %d\n", fps);
-      g_timer_start (timer);
-      fps = 0;
-    }
-
-  clutter_actor_paint (stage);
   do_events (stage);
-  ++fps;
+}
+
+static gboolean
+queue_redraw (gpointer stage)
+{
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
 
   return TRUE;
 }
@@ -90,6 +76,10 @@ main (int argc, char **argv)
   ClutterColor color = { 0x00, 0x00, 0x00, 0xff };
   ClutterActor *stage, *rect;
 
+  g_setenv ("CLUTTER_VBLANK", "none", FALSE);
+  g_setenv ("CLUTTER_DEFAULT_FPS", "1000", FALSE);
+  g_setenv ("CLUTTER_SHOW_FPS", "1", FALSE);
+
   clutter_init_with_args (&argc, &argv,
                           NULL,
                           entries,
@@ -134,7 +124,9 @@ main (int argc, char **argv)
 
   clutter_actor_show (stage);
 
-  g_idle_add (fps_cb, (gpointer)stage);
+  g_idle_add (queue_redraw, stage);
+
+  g_signal_connect (stage, "paint", G_CALLBACK (on_paint), NULL);
 
   clutter_main ();