Merge remote branch 'master' into texture-debugging

Conflicts:
	clutter/cogl/cogl/cogl-context.h
This commit is contained in:
Neil Roberts 2010-02-01 13:37:19 +00:00
commit 145cc9d3df
66 changed files with 3022 additions and 1231 deletions

1
.gitignore vendored
View File

@ -240,6 +240,7 @@ TAGS
/tests/conform/test-script-named-object
/tests/conform/test-actor-destruction
/tests/conform/test-color-operators
/tests/conform/test-cogl-texture-mipmaps
/tests/micro-bench/test-text-perf
/tests/micro-bench/test-text
/tests/micro-bench/test-picking

49
NEWS
View File

@ -1,3 +1,52 @@
Clutter 1.1.6 (18/01/2010)
===============================================================================
* List of changes since Clutter 1.1.4
o Some fixes for the Win32 backend (bug #1905).
o Profiling support via the UProf library. Configure with
--enable-profile to get a report after each Clutter application is
run.
o Improved conformance tests with coverage reports via gcov.
o ClutterTexture no longer tries to read back texture data into
g_malloc'd memory on unrealize (bug #1842).
o The CGL_* defines from cogl-defines.h have been removed. These
should not have been used by any applications, but if they were
being used then please replace them either with the Cogl enums or
with the appropriate GL_* enum if you are using GL directly.
o Added a delete-event signal to the stage.
o Fix for using cogl_rectangle with different texture coordinates
for multiple layers (bug #1937).
o Fix for using stencil and depth buffers in FBOs on Intel drivers
in Mesa (bug #1873).
o Support for subtitles in ClutterMedia.
o ClutterGLX will now use an RGB visual by default. For
applications (and toolkit integration libraries) that want to
enable the ClutterStage:use-alpha property there is a new
function: clutter_x11_set_use_argb_visual().
o Fix ClutterText to allow using Pango markup and attributes in
the same actor (bug #1940).
Many thanks to:
Alejandro Piñeiro
Damien Lespiau
Emmanuele Bassi
Gord Allot
Halton Huo
Robert Bragg
Samuel Degrande
Clutter 1.1.4 (03/01/2010)
===============================================================================

101
README
View File

@ -1,19 +1,25 @@
Clutter - README
===============================================================================
Clutter is an open source software library for creating fast, visually
rich and animated graphical user interfaces.
Clutter is an open source software library for creating portable, fast,
visually rich and animated graphical user interfaces.
Clutter currently requires:
• GLib >= 2.16.0
• Cairo >= 1.6
• PangoCairo >= 1.20
• OpenGL >= 1.2, OpenGL ES 1.1 or OpenGL ES 2.0
• OpenGL >= 1.3 or 1.2+multitexturing, OpenGL ES 1.1 or OpenGL ES 2.0
• GLX, SDL, WGL or an EGL Implementation
• JSON-GLib >= 0.8 (optional)
• GDK-Pixbuf >= 2.0 (optional)
When running the OpenGL flavor, Clutter requires at least version 1.3
or 1.2 with the multitexturing extension. However to build Clutter
you will need the latest GL headers which can be obtained from:
http://www.khronos.org
If you are building the API reference you will also need:
• GTK-Doc >= 1.11
@ -24,30 +30,53 @@ If you are building the Introspection data you will also need:
If you want built in support for profiling Clutter you will also need:
• UProf 0.2 available from git://git.moblin.org/uprof.git
• UProf >= 0.2
The official website is:
http://www.clutter-project.org
UProf is available from:
The Clutter blog is at
http://www.clutter-project.org/blog
git://git.moblin.org/uprof.git
-------------------------------------------------------------------------------
The official Clutter website is:
http://www.clutter-project.org/
The API reference for the latest stable release and unstable developers
snapshot are available at:
http://www.clutter-project.org/docs/clutter/stable/
http://www.clutter-project.org/docs/clutter/unstable/
New releases of Clutter are available at:
http://www.clutter-project.org/sources/clutter/
The Clutter blog is at:
http://www.clutter-project.org/blog/
To subscribe to the Clutter mailing list, send an email to:
To subscribe to the Clutter mailing list, send mail to:
clutter+subscribe@o-hand.com
The official mailing list archive is:
http://lists.o-hand.com/clutter/
New bug page on Bugzilla:
http://bugzilla.o-hand.com/enter_bug.cgi?product=Clutter
Clutter is licensed under the terms of the GNU Lesser General Public
License, version 2.1 or (at your option) later.
INSTALLATION
BUILDING AND INSTALLATION
===============================================================================
See the INSTALL file. Info on specific Clutter options;
See the INSTALL file.
Clutter has additional command line options for the configure script:
--enable-debug=[no/minimum/yes]
Controls Clutter debugging level:
@ -55,7 +84,7 @@ See the INSTALL file. Info on specific Clutter options;
yes:
All GLib asserts, checks and support for runtime Clutter
debugging notes through CLUTTER_DEBUG. This is the default
value for snapshots.
value for developers snapshots.
minimum:
Just GType cast checks and support for runtime Clutter
@ -65,26 +94,27 @@ See the INSTALL file. Info on specific Clutter options;
no:
No GLib asserts or checks and no support for runtime Clutter
debugging notes. Only use in extreme performance and/or size
optimization cases.
optimization cases, though it is strongly discouraged.
--enable-cogl-debug=[no/minimum/yes]
Controls COGL debugging level (default=minimum):
yes:
Support for COGL debugging notes through COGL_DEBUG and
error checking for each GL primitive.
error checking for each GL primitive. This is useful mostly
to debug COGL itself.
minimum:
Support for COGL debugging notes through COGL_DEBUG. This is
the default for snapshots.
the default for developers snapshots.
no:
Disable support for COGL runtime debugging notes. This is
the default for stable releases.
--enable-maintainer-flags=[no/yes]
Use strict compiler flags. This defaults to 'yes' for snapshots and
to 'no' for stable releases.
Use strict compiler flags. This defaults to 'yes' for developers
snapshots and to 'no' for stable releases.
--enable-gtk-doc
use gtk-doc to build API documentation (default=no). Requires gtk-doc
@ -94,6 +124,17 @@ See the INSTALL file. Info on specific Clutter options;
Build additional documentation. Requires xsltproc for DocBook
conversion, and optionally jw for PDF generation.
--enable-gcov=[no/yes]
Build Clutter with coverage report support, provided by gcov. This
feature only works with the GNU Compiler Suite and gcov installed.
--enable-profile=[no/yes]
Build Clutter with profiling instrumentation. Requires the GNU
C Compiler and the UProf library.
--enable-conform=[yes/no]
Build the Clutter conformance test suite.
--with-flavour=[glx/eglx/eglnative/sdl/osx/win32/fruity]
Select the Clutter backend: (default=glx)
@ -150,7 +191,7 @@ See the INSTALL file. Info on specific Clutter options;
and if it is available, make Clutter depend on it
system:
Only use the system copy of JSON-GLib
Only use the system copy of JSON-GLib and warn if not found
VERSIONING
===============================================================================
@ -167,22 +208,23 @@ the newly added API might still change.
The micro version indicates the origin of the release: even micro
numbers are only used for released archives; odd micro numbers are
only used on the SVN repository.
only used on the Git repository.
HACKING
===============================================================================
If you want to hack on and improve Clutter, check the contained TODO
file for pending tasks, the HACKING file for general implementation guidelines,
HACKING.backends for backend-specific implementation issues. The CODING_STYLE
file contains the rules for writing code conformant to the style guidelines
used throughout Clutter. Remember: the coding style is mandatory; patches
not conforming to it will be rejected.
If you want to hack on and improve Clutter, check the contained TODO file for
pending tasks, the HACKING file for general implementation guidelines, and the
HACKING.backends for backend-specific implementation issues.
The CODING_STYLE file contains the rules for writing code conformant to the
style guidelines used throughout Clutter. Remember: the coding style is
mandatory; patches not conforming to it will be rejected.
BUGS
===============================================================================
Bugs should be reported to the OpenedHand Bugzilla at:
Bugs should be reported to the Clutter Bugzilla at:
http://bugzilla.o-hand.com/enter_bug.cgi?product=Clutter
@ -192,7 +234,7 @@ In the report you should include:
• what system you're running Clutter on;
• which version of Clutter you are using;
• which version of GLib and OpenGL you are using;
• which version of GLib and OpenGL (or OpenGL ES) you are using;
• which video card and which drivers you are using, including output of
glxinfo and xdpyinfo (if applicable);
• how to reproduce the bug.
@ -235,7 +277,8 @@ RELEASE NOTES
===============================================================================
Relevant information for developers with existing Clutter applications
wanting to port to newer releases (See NEWS for general new feature info).
wanting to port to newer releases (see NEWS for general information on new
features).
Release Notes for Clutter 1.2
-------------------------------------------------------------------------------
@ -852,5 +895,3 @@ Release Notes for Clutter 0.3
ClutterGroup::remove signals have been deprecated:
ClutterContainer::actor-added and ClutterContainer::actor-removed should
be used instead.
$LastChangedDate$

View File

@ -1,3 +1,3 @@
SUBDIRS = autotools
SUBDIRS = autotools mingw
EXTRA_DIST = gen-gcov.pl

1
build/mingw/Makefile.am Normal file
View File

@ -0,0 +1 @@
EXTRA_DIST = README mingw-cross-compile.sh

View File

@ -20,6 +20,23 @@ DISTCLEANFILES =
EXTRA_DIST =
BUILT_SOURCES =
if WINSYS_WIN32
# Ideally this resources stuff would go in win32/ but libtool doesn't
# seem to pass on the -Wl argument when linking a convenience library
# so we need to do it here as part of linking the dll. libtool also
# won't let you link against the .o directly because it wants you to
# link against libtool objects for dynamic libraries.
.rc.o :
$(WINDRES) -I$(srcdir)/win32 $< $@
win32/resources.o : $(srcdir)/win32/invisible-cursor.cur
win32_resources = win32/resources.o
win32_resources_ldflag = -Wl,win32/resources.o
endif # WINSYS_WIN32
INCLUDES = \
-I$(top_srcdir) \
-I$(top_srcdir)/clutter/cogl \
@ -67,6 +84,7 @@ source_h = \
$(srcdir)/clutter-color.h \
$(srcdir)/clutter-container.h \
$(srcdir)/clutter-deprecated.h \
$(srcdir)/clutter-device-manager.h \
$(srcdir)/clutter-event.h \
$(srcdir)/clutter-feature.h \
$(srcdir)/clutter-fixed.h \
@ -74,6 +92,7 @@ source_h = \
$(srcdir)/clutter-flow-layout.h \
$(srcdir)/clutter-frame-source.h \
$(srcdir)/clutter-group.h \
$(srcdir)/clutter-input-device.h \
$(srcdir)/clutter-interval.h \
$(srcdir)/clutter-keysyms.h \
$(srcdir)/clutter-layout-manager.h \
@ -137,6 +156,7 @@ source_c = \
$(srcdir)/clutter-clone.c \
$(srcdir)/clutter-color.c \
$(srcdir)/clutter-container.c \
$(srcdir)/clutter-device-manager.c \
clutter-enum-types.c \
$(srcdir)/clutter-event.c \
$(srcdir)/clutter-feature.c \
@ -145,6 +165,7 @@ source_c = \
$(srcdir)/clutter-flow-layout.c \
$(srcdir)/clutter-frame-source.c \
$(srcdir)/clutter-group.c \
$(srcdir)/clutter-input-device.c \
$(srcdir)/clutter-interval.c \
$(srcdir)/clutter-layout-manager.c \
$(srcdir)/clutter-layout-meta.c \
@ -205,7 +226,8 @@ libclutter_@CLUTTER_WINSYS@_@CLUTTER_API_VERSION@_la_DEPENDENCIES = \
$(top_builddir)/clutter/cogl/pango/libcoglpango.la \
$(top_builddir)/clutter/$(CLUTTER_WINSYS)/libclutter-$(CLUTTER_WINSYS).la \
$(clutter_json_dep) \
$(CLUTTER_WINSYS_BASE_LIB)
$(CLUTTER_WINSYS_BASE_LIB) \
$(win32_resources)
libclutter_@CLUTTER_WINSYS@_@CLUTTER_API_VERSION@_la_SOURCES = \
$(source_c) \
@ -219,6 +241,7 @@ libclutter_@CLUTTER_WINSYS@_@CLUTTER_API_VERSION@_la_LDFLAGS = \
-export-dynamic \
-export-symbols-regex "^(clutter|cogl|json).*" \
-rpath $(libdir) \
$(win32_resources_ldflag) \
$(NULL)
lib_LTLIBRARIES = $(CLUTTER_WINSYS_LIB)

View File

@ -308,6 +308,7 @@ struct _ClutterActorPrivate
guint clip_to_allocation : 1;
guint enable_model_view_transform : 1;
guint enable_paint_unmapped : 1;
guint has_pointer : 1;
gfloat clip[4];
@ -429,7 +430,8 @@ enum
PROP_SHOW_ON_SET_PARENT,
PROP_TEXT_DIRECTION
PROP_TEXT_DIRECTION,
PROP_HAS_POINTER
};
enum
@ -2581,7 +2583,7 @@ clutter_actor_set_property (GObject *object,
break;
case PROP_OPACITY:
clutter_actor_set_opacity (actor, g_value_get_uchar (value));
clutter_actor_set_opacity (actor, g_value_get_uint (value));
break;
case PROP_NAME:
@ -2864,7 +2866,7 @@ clutter_actor_get_property (GObject *object,
break;
case PROP_OPACITY:
g_value_set_uchar (value, priv->opacity);
g_value_set_uint (value, priv->opacity);
break;
case PROP_NAME:
@ -3031,6 +3033,10 @@ clutter_actor_get_property (GObject *object,
g_value_set_enum (value, priv->text_direction);
break;
case PROP_HAS_POINTER:
g_value_set_boolean (value, priv->has_pointer);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -3462,12 +3468,12 @@ clutter_actor_class_init (ClutterActorClass *klass)
/**
* ClutterActor:opacity:
*
* Opacity of the actor, between 0 (fully transparent) and
* Opacity of an actor, between 0 (fully transparent) and
* 255 (fully opaque)
*/
pspec = g_param_spec_uchar ("opacity",
pspec = g_param_spec_uint ("opacity",
"Opacity",
"Opacity of actor",
"Opacity of an actor",
0, 255,
255,
CLUTTER_PARAM_READWRITE);
@ -3858,6 +3864,24 @@ clutter_actor_class_init (ClutterActorClass *klass)
PROP_TEXT_DIRECTION,
pspec);
/**
* ClutterActor:has-pointer:
*
* Whether the actor contains the pointer of a #ClutterInputDevice
* or not.
*
* Since: 1.2
*/
pspec = g_param_spec_boolean ("has-pointer",
"Has Pointer",
"Whether the actor contains the pointer "
"of an input device",
FALSE,
CLUTTER_PARAM_READABLE);
g_object_class_install_property (object_class,
PROP_HAS_POINTER,
pspec);
/**
* ClutterActor::destroy:
* @actor: the object which received the signal
@ -9638,6 +9662,20 @@ clutter_actor_set_text_direction (ClutterActor *self,
}
}
void
_clutter_actor_set_has_pointer (ClutterActor *self,
gboolean has_pointer)
{
ClutterActorPrivate *priv = self->priv;
if (priv->has_pointer != has_pointer)
{
priv->has_pointer = has_pointer;
g_object_notify (G_OBJECT (self), "has-pointer");
}
}
/**
* clutter_actor_get_text_direction:
* @self: a #ClutterActor
@ -9748,3 +9786,23 @@ clutter_actor_pop_internal (void)
ctx->internal_child -= 1;
}
/**
* clutter_actor_has_pointer:
* @self: a #ClutterActor
*
* Checks whether an actor contains the the pointer of a
* #ClutterInputDevice
*
* Return value: %TRUE if the actor contains the pointer, and
* %FALSE otherwise
*
* Since: 1.2
*/
gboolean
clutter_actor_has_pointer (ClutterActor *self)
{
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
return self->priv->has_pointer;
}

View File

@ -532,6 +532,7 @@ void clutter_actor_get_transformation_matrix (ClutterActor *self
CoglMatrix *matrix);
gboolean clutter_actor_is_in_clone_paint (ClutterActor *self);
gboolean clutter_actor_has_pointer (ClutterActor *self);
void clutter_actor_set_text_direction (ClutterActor *self,
ClutterTextDirection text_dir);

View File

@ -201,8 +201,11 @@ on_actor_dispose (gpointer user_data,
ClutterAnimation *self = user_data;
if (self->priv->object == actor_pointer)
{
CLUTTER_NOTE (ANIMATION, "Object [%p] was unref'd", actor_pointer);
g_object_unref (self);
}
}
static void
@ -219,6 +222,7 @@ clutter_animation_real_completed (ClutterAnimation *self)
direction = clutter_timeline_get_direction (timeline);
/* explicitly set the final state of the animation */
CLUTTER_NOTE (ANIMATION, "Set final state on object [%p]", priv->object);
g_hash_table_iter_init (&iter, priv->properties);
while (g_hash_table_iter_next (&iter, &key, &value))
{
@ -245,8 +249,14 @@ clutter_animation_real_completed (ClutterAnimation *self)
animation = g_object_get_qdata (priv->object, quark_object_animation);
if (animation == self)
{
CLUTTER_NOTE (ANIMATION, "Unsetting animation for actor [%p]",
priv->object);
g_object_set_qdata (priv->object, quark_object_animation, NULL);
g_object_weak_unref (priv->object, on_actor_dispose, self);
CLUTTER_NOTE (ANIMATION, "Releasing the reference Animation [%p]",
animation);
g_object_unref (animation);
}
}
@ -256,7 +266,9 @@ clutter_animation_finalize (GObject *gobject)
{
ClutterAnimationPrivate *priv = CLUTTER_ANIMATION (gobject)->priv;
CLUTTER_NOTE (ANIMATION, "Destroying properties hash table");
CLUTTER_NOTE (ANIMATION,
"Destroying properties table for Animation [%p]",
gobject);
g_hash_table_destroy (priv->properties);
G_OBJECT_CLASS (clutter_animation_parent_class)->finalize (gobject);
@ -444,7 +456,7 @@ clutter_animation_class_init (ClutterAnimationClass *klass)
gobject_class->finalize = clutter_animation_finalize;
/**
* ClutterAnimation:objct:
* ClutterAnimation:object:
*
* The #GObject to which the animation applies.
*
@ -629,6 +641,7 @@ clutter_animation_validate_bind (ClutterAnimation *animation,
ClutterAnimationPrivate *priv;
GObjectClass *klass;
GParamSpec *pspec;
GType pspec_type;
priv = animation->priv;
@ -667,14 +680,17 @@ clutter_animation_validate_bind (ClutterAnimation *animation,
return NULL;
}
if (!g_value_type_compatible (G_PARAM_SPEC_VALUE_TYPE (pspec), argtype))
pspec_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
if (!g_value_type_compatible (argtype, pspec_type) ||
!g_value_type_transformable (argtype, pspec_type))
{
g_warning ("Cannot bind property '%s': the interval value of "
"type '%s' is not compatible with the property value "
"of type '%s'",
property_name,
g_type_name (argtype),
g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
g_type_name (pspec_type));
return NULL;
}
@ -846,6 +862,7 @@ clutter_animation_update_interval (ClutterAnimation *animation,
ClutterAnimationPrivate *priv;
GObjectClass *klass;
GParamSpec *pspec;
GType pspec_type, int_type;
g_return_if_fail (CLUTTER_IS_ANIMATION (animation));
g_return_if_fail (property_name != NULL);
@ -872,15 +889,18 @@ clutter_animation_update_interval (ClutterAnimation *animation,
return;
}
if (!g_value_type_compatible (G_PARAM_SPEC_VALUE_TYPE (pspec),
clutter_interval_get_value_type (interval)))
pspec_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
int_type = clutter_interval_get_value_type (interval);
if (!g_value_type_compatible (int_type, pspec_type) ||
!g_value_type_transformable (int_type, pspec_type))
{
g_warning ("Cannot update property '%s': the interval value of "
"type '%s' is not compatible with the property value "
"of type '%s'",
property_name,
g_type_name (clutter_interval_get_value_type (interval)),
g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
g_type_name (int_type),
g_type_name (pspec_type));
return;
}
@ -906,6 +926,7 @@ clutter_animation_update (ClutterAnimation *animation,
{
ClutterAnimationPrivate *priv;
ClutterInterval *interval;
GType int_type;
g_return_val_if_fail (CLUTTER_IS_ANIMATION (animation), NULL);
g_return_val_if_fail (property_name != NULL, NULL);
@ -923,14 +944,16 @@ clutter_animation_update (ClutterAnimation *animation,
return NULL;
}
if (!g_value_type_compatible (G_VALUE_TYPE (final),
clutter_interval_get_value_type (interval)))
int_type = clutter_interval_get_value_type (interval);
if (!g_value_type_compatible (G_VALUE_TYPE (final), int_type) ||
!g_value_type_transformable (G_VALUE_TYPE (final), int_type))
{
g_warning ("Cannot update property '%s': the interval value of "
"type '%s' is not compatible with the property value "
"of type '%s'",
property_name,
g_type_name (clutter_interval_get_value_type (interval)),
g_type_name (int_type),
g_type_name (G_VALUE_TYPE (final)));
return NULL;
}
@ -1221,6 +1244,8 @@ clutter_animation_set_mode (ClutterAnimation *animation,
g_object_freeze_notify (G_OBJECT (animation));
alpha = clutter_animation_get_alpha_internal (animation);
g_assert (CLUTTER_IS_ALPHA (alpha));
clutter_alpha_set_mode (alpha, mode);
g_object_notify (G_OBJECT (animation), "mode");
@ -1274,6 +1299,8 @@ clutter_animation_set_duration (ClutterAnimation *animation,
g_object_freeze_notify (G_OBJECT (animation));
timeline = clutter_animation_get_timeline_internal (animation);
g_assert (CLUTTER_IS_TIMELINE (timeline));
clutter_timeline_set_duration (timeline, msecs);
clutter_timeline_rewind (timeline);
@ -1634,11 +1661,23 @@ clutter_animation_setup_property (ClutterAnimation *animation,
*/
if (!g_type_is_a (G_VALUE_TYPE (value), G_VALUE_TYPE (&real_value)))
{
if (!g_value_type_compatible (G_VALUE_TYPE (value),
G_VALUE_TYPE (&real_value)) &&
!g_value_type_compatible (G_VALUE_TYPE (&real_value),
G_VALUE_TYPE (value)))
/* are these two types compatible (can be directly copied)? */
if (g_value_type_compatible (G_VALUE_TYPE (value),
G_VALUE_TYPE (&real_value)))
{
g_value_copy (value, &real_value);
goto done;
}
/* are these two type transformable? */
if (g_value_type_transformable (G_VALUE_TYPE (value),
G_VALUE_TYPE (&real_value)))
{
if (g_value_transform (value, &real_value))
goto done;
}
/* if not compatible and not transformable then we can't do much */
g_warning ("%s: Unable to convert from %s to %s for "
"the property '%s' of object %s",
G_STRLOC,
@ -1649,20 +1688,10 @@ clutter_animation_setup_property (ClutterAnimation *animation,
g_value_unset (&real_value);
return;
}
if (!g_value_transform (value, &real_value))
{
g_warning ("%s: Unable to transform from %s to %s",
G_STRLOC,
g_type_name (G_VALUE_TYPE (value)),
g_type_name (G_VALUE_TYPE (&real_value)));
g_value_unset (&real_value);
return;
}
}
else
g_value_copy (value, &real_value);
done:
/* create an interval and bind it to the property, in case
* it's not a fixed property, otherwise just set it
*/

View File

@ -0,0 +1,321 @@
/*
* 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>
*/
/**
* SECTION:clutter-device-manager
* @short_description: Maintains the list of input devices
*
* #ClutterDeviceManager is a singleton object, owned by Clutter, which
* maintains the list of #ClutterInputDevice<!-- -->s.
*
* Depending on the backend used by Clutter it is possible to use the
* #ClutterDeviceManager::device-added and
* #ClutterDeviceManager::device-removed to monitor addition and removal
* of devices.
*
* #ClutterDeviceManager is available since Clutter 1.2
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-debug.h"
#include "clutter-device-manager.h"
#include "clutter-enum-types.h"
#include "clutter-marshal.h"
#include "clutter-private.h"
#define CLUTTER_DEVICE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER, ClutterDeviceManagerClass))
#define CLUTTER_IS_DEVICE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEVICE_MANAGER))
#define CLUTTER_DEVICE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEVICE_MANAGER, ClutterDeviceManagerClass))
typedef struct _ClutterDeviceManagerClass ClutterDeviceManagerClass;
struct _ClutterDeviceManagerClass
{
GObjectClass parent_instance;
};
enum
{
DEVICE_ADDED,
DEVICE_REMOVED,
LAST_SIGNAL
};
static ClutterDeviceManager *default_manager = NULL;
static guint manager_signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (ClutterDeviceManager, clutter_device_manager, G_TYPE_OBJECT);
static void
clutter_device_manager_class_init (ClutterDeviceManagerClass *klass)
{
/**
* ClutterDeviceManager::device-added:
* @manager: the #ClutterDeviceManager that emitted the signal
* @device: the newly added #ClutterInputDevice
*
* The ::device-added signal is emitted each time a device has been
* added to the #ClutterDeviceManager
*
* Since: 1.2
*/
manager_signals[DEVICE_ADDED] =
g_signal_new (I_("device-added"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
clutter_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
CLUTTER_TYPE_INPUT_DEVICE);
/**
* ClutterDeviceManager::device-removed:
* @manager: the #ClutterDeviceManager that emitted the signal
* @device: the removed #ClutterInputDevice
*
* The ::device-removed signal is emitted each time a device has been
* removed from the #ClutterDeviceManager
*
* Since: 1.2
*/
manager_signals[DEVICE_REMOVED] =
g_signal_new (I_("device-removed"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
clutter_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
CLUTTER_TYPE_INPUT_DEVICE);
}
static void
clutter_device_manager_init (ClutterDeviceManager *self)
{
}
/**
* clutter_device_manager_get_default:
*
* Retrieves the device manager singleton
*
* Return value: (transfer none): the #ClutterDeviceManager singleton.
* The returned instance is owned by Clutter and it should not be
* modified or freed
*
* Since: 1.2
*/
ClutterDeviceManager *
clutter_device_manager_get_default (void)
{
if (G_UNLIKELY (default_manager == NULL))
default_manager = g_object_new (CLUTTER_TYPE_DEVICE_MANAGER, NULL);
return default_manager;
}
/**
* clutter_device_manager_list_devices:
* @device_manager: a #ClutterDeviceManager
*
* Lists all currently registered input devices
*
* Return value: (transfer container) (element-type ClutterInputDevice):
* a newly allocated list of #ClutterInputDevice objects. Use
* g_slist_free() to deallocate it when done
*
* Since: 1.2
*/
GSList *
clutter_device_manager_list_devices (ClutterDeviceManager *device_manager)
{
g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), NULL);
return g_slist_copy (device_manager->devices);
}
/**
* clutter_device_manager_peek_devices:
* @device_manager: a #ClutterDeviceManager
*
* Lists all currently registered input devices
*
* Return value: (transfer none) (element-type ClutterInputDevice):
* a pointer to the internal list of #ClutterInputDevice objects. The
* returned list is owned by the #ClutterDeviceManager and should never
* be modified or freed
*
* Since: 1.2
*/
const GSList *
clutter_device_manager_peek_devices (ClutterDeviceManager *device_manager)
{
g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), NULL);
return device_manager->devices;
}
/**
* clutter_device_manager_get_device:
* @device_manager: a #ClutterDeviceManager
* @device_id: the integer id of a device
*
* Retrieves the #ClutterInputDevice with the given @device_id
*
* Return value: (transfer none): a #ClutterInputDevice or %NULL. The
* returned device is owned by the #ClutterDeviceManager and should
* never be modified or freed
*
* Since: 1.2
*/
ClutterInputDevice *
clutter_device_manager_get_device (ClutterDeviceManager *device_manager,
gint device_id)
{
GSList *l;
g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), NULL);
for (l = device_manager->devices; l != NULL; l = l->next)
{
ClutterInputDevice *device = l->data;
if (device->id == device_id)
return device;
}
return NULL;
}
static gint
input_device_cmp (gconstpointer a,
gconstpointer b)
{
const ClutterInputDevice *device_a = a;
const ClutterInputDevice *device_b = b;
if (device_a->id < device_b->id)
return -1;
if (device_a->id > device_b->id)
return 1;
return 0;
}
/*
* _clutter_device_manager_add_device:
* @device_manager: a #ClutterDeviceManager
* @device: a #ClutterInputDevice
*
* Adds @device to the list of #ClutterInputDevice<!-- -->s maintained
* by @device_manager
*
* The reference count of @device is not increased
*
* The #ClutterDeviceManager::device-added signal is emitted after
* adding @device to the list
*/
void
_clutter_device_manager_add_device (ClutterDeviceManager *device_manager,
ClutterInputDevice *device)
{
g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager));
device_manager->devices = g_slist_insert_sorted (device_manager->devices,
device,
input_device_cmp);
g_signal_emit (device_manager, manager_signals[DEVICE_ADDED], 0, device);
}
/*
* _clutter_device_manager_remove_device:
* @device_manager: a #ClutterDeviceManager
* @device: a #ClutterInputDevice
*
* Removes @device from the list of #ClutterInputDevice<!-- -->s
* maintained by @device_manager
*
* The reference count of @device is not decreased
*
* The #ClutterDeviceManager::device-removed signal is emitted after
* removing @device from the list
*/
void
_clutter_device_manager_remove_device (ClutterDeviceManager *device_manager,
ClutterInputDevice *device)
{
g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager));
if (g_slist_find (device_manager->devices, device) == NULL)
return;
device_manager->devices = g_slist_remove (device_manager->devices, device);
g_signal_emit (device_manager, manager_signals[DEVICE_REMOVED], 0, device);
}
/*
* _clutter_device_manager_update_devices:
* @device_manager: a #ClutterDeviceManager
*
* Updates every #ClutterInputDevice handled by @device_manager
* by performing a pick paint at the coordinates of each pointer
* device
*/
void
_clutter_device_manager_update_devices (ClutterDeviceManager *device_manager)
{
GSList *d;
/* the user disabled motion events delivery on actors; we
* don't perform any picking since the source of the events
* will always be set to be the stage
*/
if (!clutter_get_motion_events_enabled ())
return;
for (d = device_manager->devices; d != NULL; d = d->next)
{
ClutterInputDevice *device = d->data;
ClutterInputDeviceType device_type;
/* we only care about pointer devices */
device_type = clutter_input_device_get_device_type (device);
if (device_type != CLUTTER_POINTER_DEVICE)
continue;
/* out of stage */
if (device->stage == NULL)
continue;
_clutter_input_device_update (device);
}
}

View File

@ -0,0 +1,59 @@
/*
* 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>
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_DEVICE_MANAGER_H__
#define __CLUTTER_DEVICE_MANAGER_H__
#include <glib-object.h>
#include <clutter/clutter-event.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_DEVICE_MANAGER (clutter_device_manager_get_type ())
#define CLUTTER_DEVICE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER, ClutterDeviceManager))
#define CLUTTER_IS_DEVICE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER))
/**
* ClutterDeviceManager:
*
* The #ClutterDeviceManager structure contains only
* private data
*/
typedef struct _ClutterDeviceManager ClutterDeviceManager;
GType clutter_device_manager_get_type (void) G_GNUC_CONST;
ClutterDeviceManager *clutter_device_manager_get_default (void);
GSList * clutter_device_manager_list_devices (ClutterDeviceManager *device_manager);
const GSList * clutter_device_manager_peek_devices (ClutterDeviceManager *device_manager);
ClutterInputDevice * clutter_device_manager_get_device (ClutterDeviceManager *device_manager,
gint device_id);
G_END_DECLS
#endif /* __CLUTTER_DEVICE_MANAGER_H__ */

View File

@ -787,39 +787,3 @@ clutter_get_current_event (void)
return context->current_event;
}
/**
* clutter_input_device_get_device_type:
* @device: a #ClutterInputDevice
*
* Retrieves the type of @device
*
* Return value: the type of the device
*
* Since: 1.0
*/
ClutterInputDeviceType
clutter_input_device_get_device_type (ClutterInputDevice *device)
{
g_return_val_if_fail (device != NULL, CLUTTER_POINTER_DEVICE);
return device->device_type;
}
/**
* clutter_input_device_get_device_id:
* @device: a #ClutterInputDevice
*
* Retrieves the unique identifier of @device
*
* Return value: the identifier of the device
*
* Since: 1.0
*/
gint
clutter_input_device_get_device_id (ClutterInputDevice *device)
{
g_return_val_if_fail (device != NULL, -1);
return device->id;
}

View File

@ -29,6 +29,7 @@
#define __CLUTTER_EVENT_H__
#include <glib-object.h>
#include <clutter/clutter-input-device.h>
#include <clutter/clutter-types.h>
#define CLUTTER_TYPE_EVENT (clutter_event_get_type ())
@ -201,37 +202,6 @@ typedef struct _ClutterScrollEvent ClutterScrollEvent;
typedef struct _ClutterStageStateEvent ClutterStageStateEvent;
typedef struct _ClutterCrossingEvent ClutterCrossingEvent;
/**
* ClutterInputDevice:
*
* Generic representation of an input device. The
* actual contents of this structure depend on the
* backend used.
*/
typedef struct _ClutterInputDevice ClutterInputDevice;
/**
* ClutterInputDeviceType:
* @CLUTTER_POINTER_DEVICE: A pointer device
* @CLUTTER_KEYBOARD_DEVICE: A keyboard device
* @CLUTTER_EXTENSION_DEVICE: A generic extension device
* @CLUTTER_N_DEVICE_TYPES: The number of device types
*
* The types of input devices available.
*
* The #ClutterInputDeviceType enumeration can be extended at later
* date; not every platform supports every input device type.
*
* Since: 1.0
*/
typedef enum {
CLUTTER_POINTER_DEVICE,
CLUTTER_KEYBOARD_DEVICE,
CLUTTER_EXTENSION_DEVICE,
CLUTTER_N_DEVICE_TYPES
} ClutterInputDeviceType;
/**
* ClutterAnyEvent:
* @type: event type
@ -509,9 +479,6 @@ guint32 clutter_keysym_to_unicode (guint k
guint32 clutter_get_current_event_time (void);
G_CONST_RETURN ClutterEvent *clutter_get_current_event (void);
ClutterInputDeviceType clutter_input_device_get_device_type (ClutterInputDevice *device);
gint clutter_input_device_get_device_id (ClutterInputDevice *device);
G_END_DECLS
#endif /* __CLUTTER_EVENT_H__ */

View File

@ -25,9 +25,16 @@
/**
* SECTION:clutter-feature
* @short_description: Query GL features at runtime
* @short_description: Run-time detection of Clutter features
*
* Functions to query available GL features ay runtime
* Parts of Clutter depend on the underlying platform, including the
* capabilities of the backend used and the OpenGL features exposed through the
* Clutter and COGL API.
*
* It is possible to ask whether Clutter has support for specific features at
* run-time.
*
* See also cogl_get_features() and #CoglFeatureFlags
*/
#ifdef HAVE_CONFIG_H

View File

@ -25,14 +25,6 @@
#error "Only <clutter/clutter.h> can be included directly."
#endif
/**
* SECTION:clutter-main
* @short_description: Various 'global' clutter functions.
*
* Functions to retrieve various global Clutter resources and other utility
* functions for mainloops, events and threads
*/
#ifndef __CLUTTER_FEATURE_H__
#define __CLUTTER_FEATURE_H__

View File

@ -39,7 +39,8 @@ struct _ClutterFrameSource
ClutterTimeoutInterval timeout;
};
static gboolean clutter_frame_source_prepare (GSource *source, gint *timeout);
static gboolean clutter_frame_source_prepare (GSource *source,
gint *timeout);
static gboolean clutter_frame_source_check (GSource *source);
static gboolean clutter_frame_source_dispatch (GSource *source,
GSourceFunc callback,
@ -56,7 +57,7 @@ static GSourceFuncs clutter_frame_source_funcs =
/**
* clutter_frame_source_add_full:
* @priority: the priority of the frame source. Typically this will be in the
* range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH.
* range between %G_PRIORITY_DEFAULT and %G_PRIORITY_HIGH.
* @fps: the number of times per second to call the function
* @func: function to call
* @data: data to pass to the function
@ -131,7 +132,8 @@ clutter_frame_source_add (guint fps,
}
static gboolean
clutter_frame_source_prepare (GSource *source, gint *delay)
clutter_frame_source_prepare (GSource *source,
gint *delay)
{
ClutterFrameSource *frame_source = (ClutterFrameSource *) source;
GTimeVal current_time;

View File

@ -277,10 +277,12 @@ clutter_group_real_foreach (ClutterContainer *container,
{
ClutterGroup *group = CLUTTER_GROUP (container);
ClutterGroupPrivate *priv = group->priv;
GList *l;
for (l = priv->children; l; l = l->next)
(* callback) (CLUTTER_ACTOR (l->data), user_data);
/* Using g_list_foreach instead of iterating the list manually
because it has better protection against the current node being
removed. This will happen for example if someone calls
clutter_container_foreach(container, clutter_actor_destroy) */
g_list_foreach (priv->children, (GFunc) callback, user_data);
}
static void

View File

@ -0,0 +1,524 @@
/*
* 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>
*/
/**
* SECTION:clutter-input-device
* @short_description: An input device managed by Clutter
*
* #ClutterInputDevice represents an input device known to Clutter.
*
* The #ClutterInputDevice class holds the state of the device, but
* its contents are usually defined by the Clutter backend in use.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-debug.h"
#include "clutter-enum-types.h"
#include "clutter-input-device.h"
#include "clutter-private.h"
enum
{
PROP_0,
PROP_ID,
PROP_DEVICE_TYPE,
PROP_NAME
};
G_DEFINE_TYPE (ClutterInputDevice, clutter_input_device, G_TYPE_OBJECT);
static void
clutter_input_device_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject);
switch (prop_id)
{
case PROP_ID:
self->id = g_value_get_int (value);
break;
case PROP_DEVICE_TYPE:
self->device_type = g_value_get_enum (value);
break;
case PROP_NAME:
self->device_name = g_strdup (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_input_device_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject);
switch (prop_id)
{
case PROP_ID:
g_value_set_int (value, self->id);
break;
case PROP_DEVICE_TYPE:
g_value_set_enum (value, self->device_type);
break;
case PROP_NAME:
g_value_set_string (value, self->device_name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
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:
*
* The unique identifier of the device
*
* Since: 1.2
*/
pspec = g_param_spec_int ("id",
"Id",
"Unique identifier of the device",
-1, G_MAXINT,
0,
CLUTTER_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (gobject_class, PROP_ID, pspec);
/**
* ClutterInputDevice:name:
*
* The name of the device
*
* Since: 1.2
*/
pspec = g_param_spec_string ("name",
"Name",
"The name of the device",
NULL,
CLUTTER_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (gobject_class, PROP_NAME, pspec);
/**
* ClutterInputDevice:device-type:
*
* The type of the device
*
* Since: 1.2
*/
pspec = g_param_spec_enum ("device-type",
"Device Type",
"The type of the device",
CLUTTER_TYPE_INPUT_DEVICE_TYPE,
CLUTTER_POINTER_DEVICE,
CLUTTER_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (gobject_class, PROP_DEVICE_TYPE, pspec);
}
static void
clutter_input_device_init (ClutterInputDevice *self)
{
self->id = -1;
self->device_type = CLUTTER_POINTER_DEVICE;
self->click_count = 0;
self->current_time = self->previous_time = CLUTTER_CURRENT_TIME;
self->current_x = self->previous_x = -1;
self->current_y = self->previous_y = -1;
self->current_button_number = self->previous_button_number = -1;
self->current_state = self->previous_state = 0;
}
/*
* _clutter_input_device_set_coords:
* @device: a #ClutterInputDevice
* @x: X coordinate of the device
* @y: Y coordinate of the device
*
* Stores the last known coordinates of the device
*/
void
_clutter_input_device_set_coords (ClutterInputDevice *device,
gint x,
gint y)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
if (device->current_x != x)
device->current_x = x;
if (device->current_y != y)
device->current_y = y;
}
/*
* _clutter_input_device_set_state:
* @device: a #ClutterInputDevice
* @state: a bitmask of modifiers
*
* Stores the last known modifiers state of the device
*/
void
_clutter_input_device_set_state (ClutterInputDevice *device,
ClutterModifierType state)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
device->current_state = state;
}
/*
* _clutter_input_device_set_time:
* @device: a #ClutterInputDevice
* @time_: the time
*
* Stores the last known event time of the device
*/
void
_clutter_input_device_set_time (ClutterInputDevice *device,
guint32 time_)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
if (device->current_time != time_)
device->current_time = time_;
}
/*
* cursor_weak_unref:
*
* #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
*/
static void
cursor_weak_unref (gpointer user_data,
GObject *object_pointer)
{
ClutterInputDevice *device = user_data;
device->cursor_actor = NULL;
}
/*
* _clutter_input_device_set_stage:
* @device: a #ClutterInputDevice
* @stage: a #ClutterStage or %NULL
*
* Stores the stage under the device
*/
void
_clutter_input_device_set_stage (ClutterInputDevice *device,
ClutterStage *stage)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
device->stage = stage;
/* if we left the stage then we also need to unset the
* cursor actor (and update its :has-pointer property)
*/
if (device->stage == NULL && device->cursor_actor != NULL)
{
_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:
* @device: a #ClutterInputDevice
* @actor: a #ClutterActor
*
* Sets the actor under the pointer coordinates of @device
*
* This function is called by _clutter_input_device_update()
* and it will:
*
* - queue a %CLUTTER_LEAVE event on the previous pointer actor
* of @device, if any
* - set to %FALSE the :has-pointer property of the previous
* pointer actor of @device, if any
* - queue a %CLUTTER_ENTER event on the new pointer actor
* - set to %TRUE the :has-pointer property of the new pointer
* actor
*/
void
_clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterActor *actor)
{
ClutterActor *old_actor;
ClutterEvent cev;
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
if (actor == device->cursor_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);
_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;
}
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.source = actor;
cev.crossing.x = device->current_x;
cev.crossing.y = device->current_y;
cev.crossing.device = device;
cev.crossing.related = old_actor;
/* 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),
cursor_weak_unref,
device);
_clutter_actor_set_has_pointer (device->cursor_actor, TRUE);
}
}
/**
* clutter_input_device_get_device_type:
* @device: a #ClutterInputDevice
*
* Retrieves the type of @device
*
* Return value: the type of the device
*
* Since: 1.0
*/
ClutterInputDeviceType
clutter_input_device_get_device_type (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
CLUTTER_POINTER_DEVICE);
return device->device_type;
}
/**
* clutter_input_device_get_device_id:
* @device: a #ClutterInputDevice
*
* Retrieves the unique identifier of @device
*
* Return value: the identifier of the device
*
* Since: 1.0
*/
gint
clutter_input_device_get_device_id (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), -1);
return device->id;
}
/**
* clutter_input_device_get_device_coords:
* @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
* @x: (out): return location for the X coordinate
* @y: (out): return location for the Y coordinate
*
* Retrieves the latest coordinates of the pointer of @device
*
* Since: 1.2
*/
void
clutter_input_device_get_device_coords (ClutterInputDevice *device,
gint *x,
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;
if (y)
*y = device->current_y;
}
/*
* _clutter_input_device_update:
* @device: a #ClutterInputDevice
*
* Updates the input @device by determining the #ClutterActor underneath the
* pointer's cursor
*
* This function calls _clutter_input_device_set_actor() if needed.
*
* This function only works for #ClutterInputDevice of type
* %CLUTTER_POINTER_DEVICE.
*
* Since: 1.2
*/
ClutterActor *
_clutter_input_device_update (ClutterInputDevice *device)
{
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);
clutter_input_device_get_device_coords (device, &x, &y);
stage = device->stage;
old_cursor_actor = device->cursor_actor;
new_cursor_actor = _clutter_do_pick (stage, x, y, CLUTTER_PICK_REACTIVE);
/* if the pick could not find an actor then we do not update the
* input device, to avoid ghost enter/leave events; the pick should
* never fail, except for bugs in the glReadPixels() implementation
* in which case this is the safest course of action anyway
*/
if (new_cursor_actor == NULL)
return NULL;
CLUTTER_NOTE (EVENT,
"Actor under cursor (device %d, at %d, %d): %s",
clutter_input_device_get_device_id (device),
x, y,
clutter_actor_get_name (new_cursor_actor) != NULL
? clutter_actor_get_name (new_cursor_actor)
: G_OBJECT_TYPE_NAME (new_cursor_actor));
/* short-circuit here */
if (new_cursor_actor == old_cursor_actor)
return old_cursor_actor;
_clutter_input_device_set_actor (device, new_cursor_actor);
return device->cursor_actor;
}
/**
* clutter_input_device_get_pointer_actor:
* @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
*
* Retrieves the #ClutterActor underneath the pointer of @device
*
* Return value: (transfer none): a pointer to the #ClutterActor or %NULL
*
* Since: 1.2
*/
ClutterActor *
clutter_input_device_get_pointer_actor (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL);
return device->cursor_actor;
}
/**
* clutter_input_device_get_device_name:
* @device: a #ClutterInputDevice
*
* Retrieves the name of the @device
*
* Return value: the name of the device, or %NULL. The returned string
* is owned by the #ClutterInputDevice and should never be modified
* or freed
*
* Since: 1.2
*/
G_CONST_RETURN gchar *
clutter_input_device_get_device_name (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
return device->device_name;
}

View File

@ -0,0 +1,99 @@
/*
* 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>
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_INPUT_DEVICE_H__
#define __CLUTTER_INPUT_DEVICE_H__
#include <clutter/clutter-types.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_INPUT_DEVICE (clutter_input_device_get_type ())
#define CLUTTER_INPUT_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE, ClutterInputDevice))
#define CLUTTER_IS_INPUT_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE))
#define CLUTTER_INPUT_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_INPUT_DEVICE, ClutterInputDeviceClass))
#define CLUTTER_IS_INPUT_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_INPUT_DEVICE))
#define CLUTTER_INPUT_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_INPUT_DEVICE, ClutterInputDeviceClass))
/**
* ClutterInputDevice:
*
* Generic representation of an input device. The actual contents of this
* structure depend on the backend used.
*/
typedef struct _ClutterInputDevice ClutterInputDevice;
typedef struct _ClutterInputDeviceClass ClutterInputDeviceClass;
/**
* ClutterInputDeviceType:
* @CLUTTER_POINTER_DEVICE: A pointer device
* @CLUTTER_KEYBOARD_DEVICE: A keyboard device
* @CLUTTER_EXTENSION_DEVICE: A generic extension device
* @CLUTTER_N_DEVICE_TYPES: The number of device types
*
* The types of input devices available.
*
* The #ClutterInputDeviceType enumeration can be extended at later
* date; not every platform supports every input device type.
*
* Since: 1.0
*/
typedef enum {
CLUTTER_POINTER_DEVICE,
CLUTTER_KEYBOARD_DEVICE,
CLUTTER_EXTENSION_DEVICE,
CLUTTER_N_DEVICE_TYPES
} ClutterInputDeviceType;
/**
* ClutterInputDeviceClass:
*
* The #ClutterInputDeviceClass structure contains only private
* data and should not be accessed directly
*
* Since: 1.2
*/
struct _ClutterInputDeviceClass
{
/*< private >*/
GObjectClass parent_class;
};
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);
G_CONST_RETURN gchar * clutter_input_device_get_device_name (ClutterInputDevice *device);
G_END_DECLS
#endif /* __CLUTTER_INPUT_DEVICE_H__ */

View File

@ -2045,68 +2045,92 @@ event_click_count_generate (ClutterEvent *event)
static guint32 previous_time = 0;
static gint previous_button_number = -1;
ClutterInputDevice *device = NULL;
ClutterBackend *backend;
guint double_click_time;
guint double_click_distance;
backend = _clutter_context_get_default ()->backend;
backend = clutter_get_default_backend ();
double_click_distance = clutter_backend_get_double_click_distance (backend);
double_click_time = clutter_backend_get_double_click_time (backend);
if (event->button.device != NULL)
device = clutter_event_get_device (event);
if (device != NULL)
{
click_count = event->button.device->click_count;
previous_x = event->button.device->previous_x;
previous_y = event->button.device->previous_y;
previous_time = event->button.device->previous_time;
previous_button_number = event->button.device->previous_button_number;
click_count = device->click_count;
previous_x = device->previous_x;
previous_y = device->previous_y;
previous_time = device->previous_time;
previous_button_number = device->previous_button_number;
CLUTTER_NOTE (EVENT,
"Restoring previous click count:%d (device:%d, time:%u)",
click_count,
clutter_input_device_get_device_id (device),
previous_time);
}
else
{
CLUTTER_NOTE (EVENT,
"Restoring previous click count:%d (time:%u)",
click_count,
previous_time);
}
switch (event->type)
switch (clutter_event_type (event))
{
case CLUTTER_BUTTON_PRESS:
case CLUTTER_SCROLL:
/* check if we are in time and within distance to increment an
* existing click count
*/
if (event->button.time < previous_time + double_click_time &&
if (event->button.button == previous_button_number &&
event->button.time < (previous_time + double_click_time) &&
(ABS (event->button.x - previous_x) <= double_click_distance) &&
(ABS (event->button.y - previous_y) <= double_click_distance)
&& event->button.button == previous_button_number)
(ABS (event->button.y - previous_y) <= double_click_distance))
{
click_count ++;
CLUTTER_NOTE (EVENT, "Increase click count (button: %d, time: %u)",
event->button.button,
event->button.time);
click_count += 1;
}
else /* start a new click count*/
{
CLUTTER_NOTE (EVENT, "Reset click count (button: %d, time: %u)",
event->button.button,
event->button.time);
click_count = 1;
previous_button_number = event->button.button;
}
/* store time and position for this click for comparison with
* next event
*/
previous_time = event->button.time;
previous_x = event->button.x;
previous_y = event->button.y;
previous_time = event->button.time;
/* fallthrough */
case CLUTTER_BUTTON_RELEASE:
event->button.click_count = click_count;
break;
default:
g_assert (NULL);
}
if (event->button.device != NULL)
if (event->type == CLUTTER_BUTTON_PRESS && device != NULL)
{
event->button.device->click_count = click_count;
event->button.device->previous_x = previous_x;
event->button.device->previous_y = previous_y;
event->button.device->previous_time = previous_time;
event->button.device->previous_button_number = previous_button_number;
}
}
CLUTTER_NOTE (EVENT, "Storing click count: %d (device:%d, time:%u)",
click_count,
clutter_input_device_get_device_id (device),
previous_time);
device->click_count = click_count;
device->previous_x = previous_x;
device->previous_y = previous_y;
device->previous_time = previous_time;
device->previous_button_number = previous_button_number;
}
}
static inline void
emit_event (ClutterEvent *event,
@ -2118,7 +2142,7 @@ emit_event (ClutterEvent *event,
ClutterActor *actor;
gint i = 0;
if (!event->any.source)
if (event->any.source == NULL)
{
CLUTTER_NOTE (EVENT, "No source set, discarding event");
return;
@ -2182,136 +2206,38 @@ static inline void
emit_pointer_event (ClutterEvent *event,
ClutterInputDevice *device)
{
/* Using the global variable directly, since it has to be initialized
* at this point
*/
ClutterMainContext *context = ClutterCntx;
ClutterMainContext *context = _clutter_context_get_default ();
if (G_UNLIKELY (context->pointer_grab_actor != NULL &&
device == NULL))
if (context->pointer_grab_actor == NULL &&
(device == NULL || device->pointer_grab_actor == NULL))
{
/* no grab, time to capture and bubble */
emit_event (event, FALSE);
}
else
{
if (context->pointer_grab_actor != NULL)
{
/* global grab */
clutter_actor_event (context->pointer_grab_actor, event, FALSE);
}
else if (G_UNLIKELY (device != NULL &&
device->pointer_grab_actor != NULL))
else if (device != NULL && device->pointer_grab_actor != NULL)
{
/* per device grab */
clutter_actor_event (device->pointer_grab_actor, event, FALSE);
}
else
{
/* no grab, time to capture and bubble */
emit_event (event, FALSE);
}
}
static inline void
emit_keyboard_event (ClutterEvent *event)
{
ClutterMainContext *context = ClutterCntx;
ClutterMainContext *context = _clutter_context_get_default ();
if (G_UNLIKELY (context->keyboard_grab_actor != NULL))
clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
else
if (context->keyboard_grab_actor == NULL)
emit_event (event, TRUE);
}
static void
unset_motion_last_actor (ClutterActor *actor, ClutterInputDevice *dev)
{
ClutterMainContext *context = ClutterCntx;
if (dev == NULL)
context->motion_last_actor = NULL;
else
dev->motion_last_actor = NULL;
}
static void
set_motion_last_actor (ClutterActor *motion_current_actor,
ClutterInputDevice *device)
{
ClutterMainContext *context = ClutterCntx;
ClutterActor *last_actor = context->motion_last_actor;
if (device != NULL)
last_actor = device->motion_last_actor;
if (last_actor && last_actor != motion_current_actor)
{
g_signal_handlers_disconnect_by_func
(last_actor,
G_CALLBACK (unset_motion_last_actor),
device);
}
if (motion_current_actor && last_actor != motion_current_actor)
{
g_signal_connect (motion_current_actor, "destroy",
G_CALLBACK (unset_motion_last_actor),
device);
}
if (device != NULL)
device->motion_last_actor = motion_current_actor;
else
context->motion_last_actor = motion_current_actor;
}
static inline void
generate_enter_leave_events (ClutterEvent *event)
{
ClutterMainContext *context = ClutterCntx;
ClutterActor *motion_current_actor = event->motion.source;
ClutterActor *last_actor = context->motion_last_actor;
ClutterInputDevice *device = clutter_event_get_device (event);
if (device != NULL)
last_actor = device->motion_last_actor;
if (last_actor != motion_current_actor)
{
if (motion_current_actor)
{
ClutterEvent cev;
gfloat x, y;
cev.crossing.device = device;
clutter_event_get_coords (event, &x, &y);
if (context->motion_last_actor)
{
cev.crossing.type = CLUTTER_LEAVE;
cev.crossing.time = event->any.time;
cev.crossing.flags = 0;
cev.crossing.x = x;
cev.crossing.y = y;
cev.crossing.source = last_actor;
cev.crossing.stage = event->any.stage;
cev.crossing.related = motion_current_actor;
emit_pointer_event (&cev, device);
}
cev.crossing.type = CLUTTER_ENTER;
cev.crossing.time = event->any.time;
cev.crossing.flags = 0;
cev.crossing.x = x;
cev.crossing.y = y;
cev.crossing.source = motion_current_actor;
cev.crossing.stage = event->any.stage;
if (context->motion_last_actor)
cev.crossing.related = last_actor;
else
cev.crossing.related = NULL;
emit_pointer_event (&cev, device);
}
}
set_motion_last_actor (motion_current_actor, device);
clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
}
/**
@ -2345,6 +2271,8 @@ _clutter_process_event_details (ClutterActor *stage,
{
ClutterInputDevice *device = NULL;
device = clutter_event_get_device (event);
switch (event->type)
{
case CLUTTER_NOTHING:
@ -2352,23 +2280,8 @@ _clutter_process_event_details (ClutterActor *stage,
break;
case CLUTTER_LEAVE:
/* The source is set for generated events, not for events
* resulting from the cursor leaving the stage
*/
if (event->any.source == NULL)
{
ClutterActor *last_actor = context->motion_last_actor;
if (event->crossing.device != NULL)
last_actor = event->crossing.device->motion_last_actor;
event->any.source = last_actor;
set_motion_last_actor (NULL, event->crossing.device);
}
/* flow through */
case CLUTTER_ENTER:
emit_pointer_event (event, event->crossing.device);
emit_pointer_event (event, device);
break;
case CLUTTER_DESTROY_NOTIFY:
@ -2400,8 +2313,6 @@ _clutter_process_event_details (ClutterActor *stage,
break;
case CLUTTER_MOTION:
device = event->motion.device;
/* Only stage gets motion events if clutter_set_motion_events is TRUE,
* and the event is not a synthetic event with source set.
*/
@ -2434,8 +2345,7 @@ _clutter_process_event_details (ClutterActor *stage,
break;
}
/* fallthrough */
/* fallthrough from motion */
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
case CLUTTER_SCROLL:
@ -2462,18 +2372,29 @@ _clutter_process_event_details (ClutterActor *stage,
x, y);
event->button.source = stage;
emit_pointer_event (event, event->button.device);
event->button.click_count = 1;
emit_pointer_event (event, device);
}
break;
}
/* Map the event to a reactive actor */
/* if the backend provides a device then we should
* already have everything we need to update it and
* get the actor underneath
*/
if (device != NULL)
actor = _clutter_input_device_update (device);
else
{
CLUTTER_NOTE (EVENT, "No device found: picking");
actor = _clutter_do_pick (CLUTTER_STAGE (stage),
x, y,
CLUTTER_PICK_REACTIVE);
}
event->any.source = actor;
if (!actor)
if (event->any.source == NULL)
break;
}
else
@ -2482,7 +2403,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.
@ -2493,33 +2413,12 @@ _clutter_process_event_details (ClutterActor *stage,
x, y,
actor);
/* Create, enter/leave events if needed */
generate_enter_leave_events (event);
if (event->type != CLUTTER_MOTION)
{
/* Generate click count */
event_click_count_generate (event);
}
if (device == NULL)
{
switch (event->type)
{
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
device = event->button.device;
break;
case CLUTTER_SCROLL:
device = event->scroll.device;
break;
case CLUTTER_MOTION:
/* already handled in the MOTION case of the switch */
default:
break;
}
}
emit_pointer_event (event, device);
break;
}
@ -3023,9 +2922,19 @@ clutter_get_font_flags (void)
/**
* clutter_get_input_device_for_id:
* @id: a device id
* @id: the unique id for a device
*
* Retrieves the #ClutterInputDevice from its id.
* Retrieves the #ClutterInputDevice from its @id. This is a convenience
* wrapper for clutter_device_manager_get_device() and it is functionally
* equivalent to:
*
* |[
* ClutterDeviceManager *manager;
* ClutterInputDevice *device;
*
* manager = clutter_device_manager_get_default ();
* device = clutter_device_manager_get_device (manager, id);
* ]|
*
* Return value: (transfer none): a #ClutterInputDevice, or %NULL
*
@ -3034,23 +2943,11 @@ clutter_get_font_flags (void)
ClutterInputDevice *
clutter_get_input_device_for_id (gint id)
{
GSList *item;
ClutterInputDevice *device = NULL;
ClutterMainContext *context;
ClutterDeviceManager *manager;
context = _clutter_context_get_default ();
manager = clutter_device_manager_get_default ();
for (item = context->input_devices;
item != NULL;
item = item->next)
{
device = item->data;
if (device->id == id)
return device;
}
return NULL;
return clutter_device_manager_get_device (manager, id);
}
/**

View File

@ -12,6 +12,7 @@ VOID:INT,INT,INT,INT
VOID:OBJECT
VOID:OBJECT,OBJECT,PARAM
VOID:OBJECT,POINTER
VOID:POINTER
VOID:STRING,BOOLEAN,BOOLEAN
VOID:STRING,INT
VOID:UINT

View File

@ -294,8 +294,7 @@ clutter_clock_dispatch (GSource *source,
master_clock->updated_stages = FALSE;
/* Process queued events
*/
/* Process queued events */
for (l = stages; l != NULL; l = l->next)
_clutter_stage_process_queued_events (l->data);
@ -446,7 +445,7 @@ _clutter_master_clock_start_running (ClutterMasterClock *master_clock)
void
_clutter_master_clock_advance (ClutterMasterClock *master_clock)
{
GSList *l, *next;
GSList *timelines, *l;
CLUTTER_STATIC_TIMER (master_timeline_advance,
"Master Clock",
@ -456,23 +455,38 @@ _clutter_master_clock_advance (ClutterMasterClock *master_clock)
g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
/* we protect ourselves from timelines being removed during
* the advancement by other timelines
*/
g_slist_foreach (master_clock->timelines, (GFunc) g_object_ref, NULL);
CLUTTER_TIMER_START (_clutter_uprof_context, master_timeline_advance);
for (l = master_clock->timelines; l != NULL; l = next)
{
next = l->next;
/* we protect ourselves from timelines being removed during
* the advancement by other timelines by copying the list of
* timelines, taking a reference on them, iterating over the
* copied list and then releasing the reference.
*
* we cannot simply take a reference on the timelines and still
* use the list held by the master clock because the do_tick()
* might result in the creation of a new timeline, which gets
* added at the end of the list with no reference increase and
* thus gets disposed at the end of the iteration.
*
* this implies that a newly added timeline will not be advanced
* by this clock iteration, which is perfectly fine since we're
* in its first cycle.
*
* we also cannot steal the master clock timelines list because
* a timeline might be removed as the direct result of do_tick()
* and remove_timeline() would not find the timeline, failing
* and leaving a dangling pointer behind.
*/
timelines = g_slist_copy (master_clock->timelines);
g_slist_foreach (timelines, (GFunc) g_object_ref, NULL);
for (l = timelines; l != NULL; l = l->next)
clutter_timeline_do_tick (l->data, &master_clock->cur_tick);
}
g_slist_foreach (timelines, (GFunc) g_object_unref, NULL);
g_slist_free (timelines);
CLUTTER_TIMER_STOP (_clutter_uprof_context, master_timeline_advance);
g_slist_foreach (master_clock->timelines, (GFunc) g_object_unref, NULL);
}
/**

View File

@ -41,6 +41,7 @@
#include "pango/cogl-pango.h"
#include "clutter-backend.h"
#include "clutter-device-manager.h"
#include "clutter-event.h"
#include "clutter-feature.h"
#include "clutter-id-pool.h"
@ -52,6 +53,8 @@
G_BEGIN_DECLS
typedef struct _ClutterMainContext ClutterMainContext;
typedef enum {
CLUTTER_ACTOR_UNUSED_FLAG = 0,
@ -82,21 +85,54 @@ typedef enum {
struct _ClutterInputDevice
{
GObject parent_instance;
gint id;
ClutterInputDeviceType device_type;
ClutterActor *pointer_grab_actor;
ClutterActor *motion_last_actor;
gchar *device_name;
/* the actor underneath the pointer */
ClutterActor *cursor_actor;
/* the actor that has a grab in place for the device */
ClutterActor *pointer_grab_actor;
/* the current click count */
gint click_count;
/* the stage the device is on */
ClutterStage *stage;
/* the current state */
gint current_x;
gint current_y;
guint32 current_time;
gint current_button_number;
ClutterModifierType current_state;
/* the previous state, used for click count generation */
gint previous_x;
gint previous_y;
guint32 previous_time;
gint previous_button_number;
ClutterModifierType previous_state;
};
typedef struct _ClutterMainContext ClutterMainContext;
struct _ClutterStageManager
{
GObject parent_instance;
GSList *stages;
};
struct _ClutterDeviceManager
{
GObject parent_instance;
GSList *devices;
};
struct _ClutterMainContext
{
@ -138,9 +174,6 @@ struct _ClutterMainContext
PangoContext *pango_context; /* Global Pango context */
CoglPangoFontMap *font_map; /* Global font map */
GSList *input_devices; /* For extra input devices, i.e
MultiTouch */
ClutterEvent *current_event;
guint32 last_event_time;
@ -170,21 +203,34 @@ PangoContext *_clutter_context_get_pango_context (ClutterMainContext *self);
#define I_(str) (g_intern_static_string ((str)))
/* 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);
/* 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);
/* stage manager */
struct _ClutterStageManager
{
GObject parent_instance;
GSList *stages;
};
void _clutter_stage_manager_add_stage (ClutterStageManager *stage_manager,
ClutterStage *stage);
void _clutter_stage_manager_remove_stage (ClutterStageManager *stage_manager,
ClutterStage *stage);
/* stage */
void _clutter_stage_set_window (ClutterStage *stage,
ClutterStageWindow *stage_window);
ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage);
@ -198,6 +244,7 @@ void _clutter_stage_queue_event (ClutterStage *stage,
ClutterEvent *event);
gboolean _clutter_stage_has_queued_events (ClutterStage *stage);
void _clutter_stage_process_queued_events (ClutterStage *stage);
void _clutter_stage_update_input_devices (ClutterStage *stage);
/* vfuncs implemented by backend */
GType _clutter_backend_impl_get_type (void);
@ -271,6 +318,9 @@ void _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
void _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
gboolean enable);
void _clutter_actor_set_has_pointer (ClutterActor *self,
gboolean has_pointer);
void _clutter_run_repaint_functions (void);
gint32 _clutter_backend_get_units_serial (ClutterBackend *backend);

View File

@ -69,6 +69,7 @@
#include "clutter-id-pool.h"
#include "clutter-container.h"
#include "clutter-profile.h"
#include "clutter-input-device.h"
#include "cogl/cogl.h"
@ -113,7 +114,8 @@ enum
PROP_USER_RESIZE,
PROP_USE_FOG,
PROP_FOG,
PROP_USE_ALPHA
PROP_USE_ALPHA,
PROP_KEY_FOCUS
};
enum
@ -454,6 +456,7 @@ _clutter_stage_queue_event (ClutterStage *stage,
{
ClutterStagePrivate *priv;
gboolean first_event;
ClutterInputDevice *device;
g_return_if_fail (CLUTTER_IS_STAGE (stage));
@ -461,14 +464,31 @@ _clutter_stage_queue_event (ClutterStage *stage,
first_event = priv->event_queue->length == 0;
g_queue_push_tail (priv->event_queue,
clutter_event_copy (event));
g_queue_push_tail (priv->event_queue, clutter_event_copy (event));
if (first_event)
{
ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
_clutter_master_clock_start_running (master_clock);
}
/* if needed, update the state of the input device of the event.
* we do it here to avoid calling the same code from every backend
* event processing function
*/
device = clutter_event_get_device (event);
if (device != NULL)
{
ClutterModifierType event_state = clutter_event_get_state (event);
guint32 event_time = clutter_event_get_time (event);
gfloat event_x, event_y;
clutter_event_get_coords (event, &event_x, &event_y);
_clutter_input_device_set_coords (device, event_x, event_y);
_clutter_input_device_set_state (device, event_state);
_clutter_input_device_set_time (device, event_time);
}
}
gboolean
@ -487,7 +507,7 @@ void
_clutter_stage_process_queued_events (ClutterStage *stage)
{
ClutterStagePrivate *priv;
GList *events, *l;;
GList *events, *l;
g_return_if_fail (CLUTTER_IS_STAGE (stage));
@ -506,7 +526,7 @@ _clutter_stage_process_queued_events (ClutterStage *stage)
priv->event_queue->tail = NULL;
priv->event_queue->length = 0;
for (l = events; l; l = l->next)
for (l = events; l != NULL; l = l->next)
{
ClutterEvent *event;
ClutterEvent *next_event;
@ -694,6 +714,10 @@ clutter_stage_set_property (GObject *object,
clutter_stage_set_use_alpha (stage, g_value_get_boolean (value));
break;
case PROP_KEY_FOCUS:
clutter_stage_set_key_focus (stage, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -750,6 +774,10 @@ clutter_stage_get_property (GObject *gobject,
g_value_set_boolean (value, priv->use_alpha);
break;
case PROP_KEY_FOCUS:
g_value_set_object (value, priv->key_focused_actor);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@ -994,6 +1022,23 @@ clutter_stage_class_init (ClutterStageClass *klass)
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_USE_ALPHA, pspec);
/**
* ClutterStage:key-focus:
*
* The #ClutterActor that will receive key events from the underlying
* windowing system.
*
* If %NULL, the #ClutterStage will receive the events.
*
* Since: 1.2
*/
pspec = g_param_spec_object ("key-focus",
"Key Focus",
"The currently key focused actor",
CLUTTER_TYPE_ACTOR,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_KEY_FOCUS, pspec);
/**
* ClutterStage::fullscreen
* @stage: the stage which was fullscreened
@ -1749,6 +1794,8 @@ clutter_stage_set_key_focus (ClutterStage *stage,
}
else
g_signal_emit_by_name (stage, "key-focus-in");
g_object_notify (G_OBJECT (stage), "key-focus");
}
/**

View File

@ -260,6 +260,7 @@ clutter_text_clear_selection (ClutterText *self)
if (priv->selection_bound != priv->position)
{
priv->selection_bound = priv->position;
g_object_notify (G_OBJECT (self), "selection-bound");
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
}
@ -803,6 +804,7 @@ clutter_text_delete_selection (ClutterText *self)
priv->position = start_index;
priv->selection_bound = start_index;
/* Not required to be guarded by g_object_freeze/thaw_notify */
if (priv->position != old_position)
g_object_notify (G_OBJECT (self), "position");
@ -812,6 +814,21 @@ clutter_text_delete_selection (ClutterText *self)
return TRUE;
}
/*
* Utility function to update both cursor position and selection bound
* at once
*/
static inline void
clutter_text_set_positions (ClutterText *self,
gint new_pos,
gint new_bound)
{
g_object_freeze_notify (G_OBJECT (self));
clutter_text_set_cursor_position (self, new_pos);
clutter_text_set_selection_bound (self, new_bound);
g_object_thaw_notify (G_OBJECT (self));
}
static inline void
clutter_text_set_text_internal (ClutterText *self,
const gchar *text)
@ -857,8 +874,7 @@ clutter_text_set_text_internal (ClutterText *self,
if (priv->n_bytes == 0)
{
clutter_text_set_cursor_position (self, -1);
clutter_text_set_selection_bound (self, -1);
clutter_text_set_positions (self, -1, -1);
}
clutter_text_dirty_cache (self);
@ -1493,8 +1509,7 @@ clutter_text_button_press (ClutterActor *actor,
*/
if (priv->text == NULL || priv->text[0] == '\0')
{
clutter_text_set_cursor_position (self, -1);
clutter_text_set_selection_bound (self, -1);
clutter_text_set_positions (self, -1, -1);
return TRUE;
}
@ -1519,8 +1534,7 @@ clutter_text_button_press (ClutterActor *actor,
*/
if (event->click_count == 1)
{
clutter_text_set_cursor_position (self, offset);
clutter_text_set_selection_bound (self, offset);
clutter_text_set_positions (self, offset, offset);
}
else if (event->click_count == 2)
{
@ -1565,8 +1579,7 @@ clutter_text_motion (ClutterActor *actor,
clutter_text_set_cursor_position (self, offset);
else
{
clutter_text_set_cursor_position (self, offset);
clutter_text_set_selection_bound (self, offset);
clutter_text_set_positions (self, offset, offset);
}
return TRUE;
@ -1896,6 +1909,8 @@ clutter_text_real_move_left (ClutterText *self,
len = priv->n_chars;
g_object_freeze_notify (G_OBJECT (self));
if (pos != 0 && len != 0)
{
if (modifiers & CLUTTER_CONTROL_MASK)
@ -1919,6 +1934,8 @@ clutter_text_real_move_left (ClutterText *self,
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
clutter_text_clear_selection (self);
g_object_thaw_notify (G_OBJECT (self));
return TRUE;
}
@ -1935,6 +1952,8 @@ clutter_text_real_move_right (ClutterText *self,
len = priv->n_chars;
g_object_freeze_notify (G_OBJECT (self));
if (pos != -1 && len !=0)
{
if (modifiers & CLUTTER_CONTROL_MASK)
@ -1954,6 +1973,8 @@ clutter_text_real_move_right (ClutterText *self,
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
clutter_text_clear_selection (self);
g_object_thaw_notify (G_OBJECT (self));
return TRUE;
}
@ -1970,6 +1991,8 @@ clutter_text_real_move_up (ClutterText *self,
gint index_, trailing;
gint x;
g_object_freeze_notify (G_OBJECT (self));
layout = clutter_text_get_layout (self);
if (priv->position == 0)
@ -2007,6 +2030,8 @@ clutter_text_real_move_up (ClutterText *self,
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
clutter_text_clear_selection (self);
g_object_thaw_notify (G_OBJECT (self));
return TRUE;
}
@ -2023,6 +2048,8 @@ clutter_text_real_move_down (ClutterText *self,
gint index_, trailing;
gint x;
g_object_freeze_notify (G_OBJECT (self));
layout = clutter_text_get_layout (self);
if (priv->position == 0)
@ -2056,6 +2083,8 @@ clutter_text_real_move_down (ClutterText *self,
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
clutter_text_clear_selection (self);
g_object_thaw_notify (G_OBJECT (self));
return TRUE;
}
@ -2068,12 +2097,16 @@ clutter_text_real_line_start (ClutterText *self,
ClutterTextPrivate *priv = self->priv;
gint position;
g_object_freeze_notify (G_OBJECT (self));
position = clutter_text_move_line_start (self, priv->position);
clutter_text_set_cursor_position (self, position);
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
clutter_text_clear_selection (self);
g_object_thaw_notify (G_OBJECT (self));
return TRUE;
}
@ -2086,12 +2119,16 @@ clutter_text_real_line_end (ClutterText *self,
ClutterTextPrivate *priv = self->priv;
gint position;
g_object_freeze_notify (G_OBJECT (self));
position = clutter_text_move_line_end (self, priv->position);
clutter_text_set_cursor_position (self, position);
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
clutter_text_clear_selection (self);
g_object_thaw_notify (G_OBJECT (self));
return TRUE;
}
@ -2101,8 +2138,7 @@ clutter_text_real_select_all (ClutterText *self,
guint keyval,
ClutterModifierType modifiers)
{
clutter_text_set_cursor_position (self, 0);
clutter_text_set_selection_bound (self, self->priv->n_chars);
clutter_text_set_positions (self, 0, self->priv->n_chars);
return TRUE;
}
@ -2151,15 +2187,13 @@ clutter_text_real_del_prev (ClutterText *self,
{
clutter_text_delete_text (self, len - 1, len);
clutter_text_set_cursor_position (self, -1);
clutter_text_set_selection_bound (self, -1);
clutter_text_set_positions (self, -1, -1);
}
else
{
clutter_text_delete_text (self, pos - 1, pos);
clutter_text_set_cursor_position (self, pos - 1);
clutter_text_set_selection_bound (self, pos - 1);
clutter_text_set_positions (self, pos - 1, pos - 1);
}
}
@ -3260,12 +3294,7 @@ clutter_text_set_selection (ClutterText *self,
start_pos = MIN (priv->n_chars, start_pos);
end_pos = MIN (priv->n_chars, end_pos);
g_object_freeze_notify (G_OBJECT (self));
clutter_text_set_cursor_position (self, start_pos);
clutter_text_set_selection_bound (self, end_pos);
g_object_thaw_notify (G_OBJECT (self));
clutter_text_set_positions (self, start_pos, end_pos);
}
/**
@ -4349,8 +4378,7 @@ clutter_text_insert_unichar (ClutterText *self,
if (priv->position >= 0)
{
clutter_text_set_cursor_position (self, priv->position + 1);
clutter_text_set_selection_bound (self, priv->position);
clutter_text_set_positions (self, priv->position + 1, priv->position);
}
g_string_free (new, TRUE);
@ -4397,8 +4425,9 @@ clutter_text_insert_text (ClutterText *self,
if (position >= 0 && priv->position >= position)
{
clutter_text_set_cursor_position (self, priv->position + g_utf8_strlen (text, -1));
clutter_text_set_selection_bound (self, priv->position);
clutter_text_set_positions (self,
priv->position + g_utf8_strlen (text, -1),
priv->position);
}
g_string_free (new, TRUE);

View File

@ -52,9 +52,12 @@ _clutter_timeout_interval_prepare (const GTimeVal *current_time,
ClutterTimeoutInterval *interval,
gint *delay)
{
guint elapsed_time
= _clutter_timeout_interval_get_ticks (current_time, interval);
guint new_frame_num = elapsed_time * interval->fps / 1000;
guint elapsed_time, new_frame_num;
elapsed_time = _clutter_timeout_interval_get_ticks (current_time,
interval);
new_frame_num = elapsed_time * interval->fps
/ 1000;
/* If time has gone backwards or the time since the last frame is
greater than the two frames worth then reset the time and do a
@ -67,6 +70,7 @@ _clutter_timeout_interval_prepare (const GTimeVal *current_time,
/* Reset the start time */
interval->start_time = *current_time;
/* Move the start time as if one whole frame has elapsed */
g_time_val_add (&interval->start_time, -(gint) frame_time * 1000);
@ -74,12 +78,14 @@ _clutter_timeout_interval_prepare (const GTimeVal *current_time,
if (delay)
*delay = 0;
return TRUE;
}
else if (new_frame_num > interval->frame_count)
{
if (delay)
*delay = 0;
return TRUE;
}
else
@ -87,6 +93,7 @@ _clutter_timeout_interval_prepare (const GTimeVal *current_time,
if (delay)
*delay = ((interval->frame_count + 1) * 1000 / interval->fps
- elapsed_time);
return FALSE;
}
}
@ -99,9 +106,10 @@ _clutter_timeout_interval_dispatch (ClutterTimeoutInterval *interval,
if ((* callback) (user_data))
{
interval->frame_count++;
return TRUE;
}
else
return FALSE;
}

View File

@ -359,12 +359,6 @@ clutter_timeout_pool_finalize (GSource *source)
* always sorted, so that the extraction of the next timeout function is
* a constant time operation.
*
* Inside Clutter, every #ClutterTimeline share the same timeout pool, unless
* the CLUTTER_TIMELINE=no-pool environment variable is set.
*
* #ClutterTimeoutPool is part of the #ClutterTimeline implementation
* and should not be used by application developers.
*
* Return value: the newly created #ClutterTimeoutPool. The created pool
* is owned by the GLib default context and will be automatically
* destroyed when the context is destroyed. It is possible to force
@ -412,7 +406,7 @@ clutter_timeout_pool_new (gint priority)
* won't be called again. If @notify is not %NULL, the @notify function
* will be called. The first call to @func will be at the end of @interval.
*
* Since version 0.8 this will try to compensate for delays. For
* Since Clutter 0.8 this will try to compensate for delays. For
* example, if @func takes half the interval time to execute then the
* function will be called again half the interval time after it
* finished. Before version 0.8 it would not fire until a full
@ -478,7 +472,8 @@ clutter_timeout_pool_remove (ClutterTimeoutPool *pool,
clutter_timeout_find_by_id)))
{
clutter_timeout_unref (l->data);
pool->dispatched_timeouts
= g_list_delete_link (pool->dispatched_timeouts, l);
pool->dispatched_timeouts =
g_list_delete_link (pool->dispatched_timeouts, l);
}
}

View File

@ -51,12 +51,14 @@
#include "clutter-clone.h"
#include "clutter-color.h"
#include "clutter-container.h"
#include "clutter-device-manager.h"
#include "clutter-event.h"
#include "clutter-feature.h"
#include "clutter-fixed-layout.h"
#include "clutter-flow-layout.h"
#include "clutter-frame-source.h"
#include "clutter-group.h"
#include "clutter-input-device.h"
#include "clutter-interval.h"
#include "clutter-keysyms.h"
#include "clutter-layout-manager.h"

View File

@ -115,6 +115,12 @@ typedef struct
CoglAtlas *atlas;
CoglHandle atlas_texture;
/* This debugging variable is used to pick a colour for visually
displaying the quad batches. It needs to be global so that it can
be reset by cogl_clear. It needs to be reset to increase the
chances of getting the same colour during an animation */
guint8 journal_rectangles_color;
CoglContextDriver drv;
} CoglContext;

View File

@ -101,6 +101,8 @@ CoglTextureUnit *
_cogl_get_texture_unit (int index_);
void
_cogl_destroy_texture_units (void);
guint
_cogl_get_max_texture_image_units (void);
void
_cogl_flush_face_winding (void);

View File

@ -225,30 +225,51 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
}
#endif
/* DEBUGGING CODE XXX:
* This path will cause all rectangles to be drawn with a red, green
* or blue outline with no blending. This may e.g. help with debugging
* texture slicing issues or blending issues, plus it looks quite cool.
/* DEBUGGING CODE XXX: This path will cause all rectangles to be
* drawn with a coloured outline. Each batch will be rendered with
* the same color. This may e.g. help with debugging texture slicing
* issues, visually seeing what is batched and debugging blending
* issues, plus it looks quite cool.
*/
if (cogl_debug_flags & COGL_DEBUG_RECTANGLES)
{
static CoglHandle outline = COGL_INVALID_HANDLE;
static int color = 0;
guint8 color_intensity;
int i;
_COGL_GET_CONTEXT (ctxt, NO_RETVAL);
if (outline == COGL_INVALID_HANDLE)
outline = cogl_material_new ();
cogl_enable (COGL_ENABLE_VERTEX_ARRAY);
for (i = 0; i < batch_len; i++, color = (color + 1) % 3)
{
/* The least significant three bits represent the three
components so that the order of colours goes red, green,
yellow, blue, magenta, cyan. Black and white are skipped. The
next two bits give four scales of intensity for those colours
in the order 0xff, 0xcc, 0x99, and 0x66. This gives a total
of 24 colours. If there are more than 24 batches on the stage
then it will wrap around */
color_intensity = 0xff - 0x33 * (ctxt->journal_rectangles_color >> 3);
cogl_material_set_color4ub (outline,
color == 0 ? 0xff : 0x00,
color == 1 ? 0xff : 0x00,
color == 2 ? 0xff : 0x00,
(ctxt->journal_rectangles_color & 1) ?
color_intensity : 0,
(ctxt->journal_rectangles_color & 2) ?
color_intensity : 0,
(ctxt->journal_rectangles_color & 4) ?
color_intensity : 0,
0xff);
_cogl_material_flush_gl_state (outline, NULL);
GE( glDrawArrays (GL_LINE_LOOP, 4 * i, 4) );
}
cogl_enable (COGL_ENABLE_VERTEX_ARRAY);
for (i = 0; i < batch_len; i++)
GE( glDrawArrays (GL_LINE_LOOP, 4 * i + state->vertex_offset, 4) );
/* Go to the next color */
do
ctxt->journal_rectangles_color = ((ctxt->journal_rectangles_color + 1) &
((1 << 5) - 1));
/* We don't want to use black or white */
while ((ctxt->journal_rectangles_color & 0x07) == 0
|| (ctxt->journal_rectangles_color & 0x07) == 0x07);
}
state->vertex_offset += (4 * batch_len);
@ -779,8 +800,7 @@ _cogl_journal_log_quad (float x_1,
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
cogl_get_modelview_matrix (&entry->model_view);
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_BATCHING
|| cogl_debug_flags & COGL_DEBUG_RECTANGLES))
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_BATCHING))
_cogl_journal_flush ();
COGL_TIMER_STOP (_cogl_uprof_context, log_timer);

View File

@ -48,12 +48,6 @@
#include "../gles/cogl-gles2-wrapper.h"
#endif
#ifdef HAVE_COGL_GLES
#define COGL_MATERIAL_MAX_TEXTURE_UNITS GL_MAX_TEXTURE_UNITS
#else
#define COGL_MATERIAL_MAX_TEXTURE_UNITS GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
#endif
#ifdef HAVE_COGL_GL
#define glActiveTexture ctx->drv.pf_glActiveTexture
#define glClientActiveTexture ctx->drv.pf_glClientActiveTexture
@ -828,7 +822,7 @@ cogl_material_set_layer (CoglHandle material_handle,
_cogl_material_pre_change_notify (material, FALSE, NULL);
material->n_layers = g_list_length (material->layers);
if (material->n_layers >= COGL_MATERIAL_MAX_TEXTURE_UNITS)
if (material->n_layers >= _cogl_get_max_texture_image_units ())
{
if (!(material->flags & COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING))
{
@ -1551,7 +1545,7 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
layer->flags &= ~COGL_MATERIAL_LAYER_FLAG_DIRTY;
if ((i+1) >= COGL_MATERIAL_MAX_TEXTURE_UNITS)
if ((i+1) >= _cogl_get_max_texture_image_units ())
break;
}

View File

@ -120,8 +120,8 @@ typedef struct _CoglTextureVertex CoglTextureVertex;
* @COGL_PIXEL_FORMAT_RGB_565: RGB, 16 bits
* @COGL_PIXEL_FORMAT_RGBA_4444: RGBA, 16 bits
* @COGL_PIXEL_FORMAT_RGBA_5551: RGBA, 16 bits
* @COGL_PIXEL_FORMAT_YUV: FIXME
* @COGL_PIXEL_FORMAT_G_8: FIXME
* @COGL_PIXEL_FORMAT_YUV: Not currently supported
* @COGL_PIXEL_FORMAT_G_8: Single luminance component
* @COGL_PIXEL_FORMAT_RGB_888: RGB, 24 bits
* @COGL_PIXEL_FORMAT_BGR_888: BGR, 24 bits
* @COGL_PIXEL_FORMAT_RGBA_8888: RGBA, 32 bits
@ -135,7 +135,23 @@ typedef struct _CoglTextureVertex CoglTextureVertex;
* @COGL_PIXEL_FORMAT_RGBA_4444_PRE: Premultiplied RGBA, 16 bits
* @COGL_PIXEL_FORMAT_RGBA_5551_PRE: Premultiplied RGBA, 16 bits
*
* Pixel formats used by COGL.
* Pixel formats used by COGL. For the formats with a byte per
* component, the order of the components specify the order in
* increasing memory addresses. So for example
* %COGL_PIXEL_FORMAT_RGB_888 would have the red component in the
* lowest address, green in the next address and blue after that
* regardless of the endinanness of the system.
*
* For the 16-bit formats the component order specifies the order
* within a 16-bit number from most significant bit to least
* significant. So for %COGL_PIXEL_FORMAT_RGB_565, the red component
* would be in bits 11-15, the green component would be in 6-11 and
* the blue component would be in 1-5. Therefore the order in memory
* depends on the endianness of the system.
*
* When uploading a texture %COGL_PIXEL_FORMAT_ANY can be used as the
* internal format. Cogl will try to pick the best format to use
* internally and convert the texture data if necessary.
*
* Since: 0.8
*/

View File

@ -237,8 +237,8 @@ cogl_fixed_get_type (void)
g_value_register_transform_func (_cogl_fixed_type, G_TYPE_FLOAT,
cogl_value_transform_fixed_float);
g_value_register_transform_func (G_TYPE_FLOAT, _cogl_fixed_type,
cogl_value_transform_float_fixed);
g_value_register_transform_func (_cogl_fixed_type, G_TYPE_DOUBLE,
cogl_value_transform_fixed_double);
g_value_register_transform_func (G_TYPE_DOUBLE, _cogl_fixed_type,

View File

@ -1512,7 +1512,7 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
GLuint generic_index = 0;
#endif
gulong enable_flags = 0;
guint max_texcoord_attrib_unit = 0;
guint max_texcoord_attrib_unit = -1;
const GList *layers;
guint32 fallback_layers = 0;
guint32 disable_layers = ~0;

View File

@ -40,6 +40,7 @@
#include "cogl-winsys.h"
#include "cogl-framebuffer-private.h"
#include "cogl-matrix-private.h"
#include "cogl-journal-private.h"
#if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES)
#include "cogl-gles2-wrapper.h"
@ -155,6 +156,16 @@ cogl_clear (const CoglColor *color, gulong buffers)
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;
}
COGL_NOTE (DRAW, "Clear end");
}
@ -729,10 +740,11 @@ cogl_end_gl (void)
}
static CoglTextureUnit *
_cogl_texture_unit_new (void)
_cogl_texture_unit_new (int index_)
{
CoglTextureUnit *unit = g_new0 (CoglTextureUnit, 1);
unit->matrix_stack = _cogl_matrix_stack_new ();
unit->index = index_;
return unit;
}
@ -766,7 +778,7 @@ _cogl_get_texture_unit (int index_)
/* NB: if we now insert a new layer before l, that will maintain order.
*/
unit = _cogl_texture_unit_new ();
unit = _cogl_texture_unit_new (index_);
/* Note: see comment after for() loop above */
ctx->texture_units =
@ -787,6 +799,36 @@ _cogl_destroy_texture_units (void)
g_list_free (ctx->texture_units);
}
/*
* This is more complicated than that, another pass needs to be done when
* cogl have a neat way of saying if we are using the fixed function pipeline
* or not (for the GL case):
* MAX_TEXTURE_UNITS: fixed function pipeline, a texture unit has both a
* sampler and a set of texture coordinates
* MAX_TEXTURE_IMAGE_UNITS: number of samplers one can use from a fragment
* program/shader (ARBfp1.0 asm/GLSL)
* MAX_VERTEX_TEXTURE_UNITS: number of samplers one can use from a vertex
* program/shader (can be 0)
* MAX_COMBINED_TEXTURE_IMAGE_UNITS: Maximum samplers one can use, counting both
* the vertex and fragment shaders
*
* If both the vertex shader and the fragment processing stage access the same
* texture image unit, then that counts as using two texture image units
* against the latter limit: http://www.opengl.org/sdk/docs/man/xhtml/glGet.xml
*
* Note that, for now, we use GL_MAX_TEXTURE_UNITS as we are exposing the
* fixed function pipeline.
*/
guint
_cogl_get_max_texture_image_units (void)
{
GLint nb_texture_image_units;
GE( glGetIntegerv(GL_MAX_TEXTURE_UNITS, &nb_texture_image_units) );
return nb_texture_image_units;
}
void
cogl_push_matrix (void)
{

View File

@ -33,4 +33,4 @@ libclutter_win32_la_SOURCES = \
CLEANFILES = clutter-win32-$(CLUTTER_API_VERSION).pc
EXTRA_DIST = clutter-win32.pc.in
EXTRA_DIST = clutter-win32.pc.in resources.rc invisible-cursor.cur

View File

@ -31,6 +31,7 @@
#include "../clutter-event.h"
#include "../clutter-main.h"
#include "../clutter-input-device.h"
#include "../clutter-debug.h"
#include "../clutter-private.h"
#include "../clutter-version.h"
@ -47,6 +48,8 @@ static ClutterBackendWin32 *backend_singleton = NULL;
static gchar *clutter_vblank_name = NULL;
static HINSTANCE clutter_hinst = NULL;
gboolean
clutter_backend_win32_pre_parse (ClutterBackend *backend,
GError **error)
@ -62,11 +65,45 @@ clutter_backend_win32_pre_parse (ClutterBackend *backend,
static void
clutter_backend_win32_init_events (ClutterBackend *backend)
{
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
ClutterDeviceManager *manager;
ClutterInputDevice *device;
CLUTTER_NOTE (EVENT, "initialising the event loop");
manager = clutter_device_manager_get_default ();
device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE,
"id", 0,
"name", "Core Pointer",
"device-type", CLUTTER_POINTER_DEVICE,
NULL);
_clutter_device_manager_add_device (manager, device);
backend_win32->core_pointer = device;
device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE,
"id", 1,
"name", "Core Keyboard",
"device-type", CLUTTER_KEYBOARD_DEVICE,
NULL);
_clutter_device_manager_add_device (manager, device);
backend_win32->core_keyboard = device;
_clutter_backend_win32_events_init (backend);
}
HCURSOR
_clutter_backend_win32_get_invisible_cursor (ClutterBackend *backend)
{
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
if (backend_win32->invisible_cursor == NULL)
backend_win32->invisible_cursor =
LoadCursor (clutter_hinst, MAKEINTRESOURCE (42));
return backend_win32->invisible_cursor;
}
static const GOptionEntry entries[] =
{
{
@ -353,6 +390,7 @@ clutter_backend_win32_init (ClutterBackendWin32 *backend_win32)
backend_win32->gl_context = NULL;
backend_win32->no_event_retrieval = FALSE;
backend_win32->invisible_cursor = NULL;
/* FIXME: get from GetSystemMetric? */
clutter_backend_set_double_click_time (backend, 250);
@ -370,3 +408,13 @@ _clutter_backend_impl_get_type (void)
{
return clutter_backend_win32_get_type ();
}
BOOL WINAPI
DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
{
if (reason == DLL_PROCESS_ATTACH)
/* Store the module handle so that we can use it to load resources */
clutter_hinst = hinst;
return TRUE;
}

View File

@ -48,7 +48,12 @@ struct _ClutterBackendWin32
HGLRC gl_context;
gboolean no_event_retrieval;
HCURSOR invisible_cursor;
GSource *event_source;
ClutterInputDevice *core_pointer;
ClutterInputDevice *core_keyboard;
};
struct _ClutterBackendWin32Class
@ -68,6 +73,8 @@ clutter_backend_win32_add_options (ClutterBackend *backend,
ClutterFeatureFlags
clutter_backend_win32_get_features (ClutterBackend *backend);
HCURSOR _clutter_backend_win32_get_invisible_cursor (ClutterBackend *backend);
G_END_DECLS
#endif /* __CLUTTER_BACKEND_WIN32_H__ */

View File

@ -201,9 +201,13 @@ get_modifier_state (WPARAM wparam)
return ret;
}
static void
make_button_event (const MSG *msg, ClutterEvent *event,
int button, int click_count, gboolean release)
static inline void
make_button_event (const MSG *msg,
ClutterEvent *event,
int button,
int click_count,
gboolean release,
ClutterInputDevice *device)
{
event->type = release ? CLUTTER_BUTTON_RELEASE : CLUTTER_BUTTON_PRESS;
event->button.time = msg->time;
@ -212,6 +216,7 @@ make_button_event (const MSG *msg, ClutterEvent *event,
event->button.modifier_state = get_modifier_state (msg->wParam);
event->button.button = button;
event->button.click_count = click_count;
event->button.device = device;
}
/**
@ -429,39 +434,39 @@ message_translate (ClutterBackend *backend,
break;
case WM_LBUTTONDOWN:
make_button_event (msg, event, 1, 1, FALSE);
make_button_event (msg, event, 1, 1, FALSE, backend_win32->core_pointer);
break;
case WM_MBUTTONDOWN:
make_button_event (msg, event, 2, 1, FALSE);
make_button_event (msg, event, 2, 1, FALSE, backend_win32->core_pointer);
break;
case WM_RBUTTONDOWN:
make_button_event (msg, event, 3, 1, FALSE);
make_button_event (msg, event, 3, 1, FALSE, backend_win32->core_pointer);
break;
case WM_LBUTTONUP:
make_button_event (msg, event, 1, 1, TRUE);
make_button_event (msg, event, 1, 1, TRUE, backend_win32->core_pointer);
break;
case WM_MBUTTONUP:
make_button_event (msg, event, 2, 1, TRUE);
make_button_event (msg, event, 2, 1, TRUE, backend_win32->core_pointer);
break;
case WM_RBUTTONUP:
make_button_event (msg, event, 3, 1, TRUE);
make_button_event (msg, event, 3, 1, TRUE, backend_win32->core_pointer);
break;
case WM_LBUTTONDBLCLK:
make_button_event (msg, event, 1, 2, FALSE);
make_button_event (msg, event, 1, 2, FALSE, backend_win32->core_pointer);
break;
case WM_MBUTTONDBLCLK:
make_button_event (msg, event, 2, 2, FALSE);
make_button_event (msg, event, 2, 2, FALSE, backend_win32->core_pointer);
break;
case WM_RBUTTONDBLCLK:
make_button_event (msg, event, 3, 2, FALSE);
make_button_event (msg, event, 3, 2, FALSE, backend_win32->core_pointer);
break;
case WM_MOUSEWHEEL:
@ -469,8 +474,8 @@ message_translate (ClutterBackend *backend,
event->type = CLUTTER_SCROLL;
event->scroll.time = msg->time;
event->scroll.modifier_state
= get_modifier_state (LOWORD (msg->wParam));
event->scroll.modifier_state = get_modifier_state (LOWORD (msg->wParam));
event->scroll.device = backend_win32->core_pointer;
/* conversion to window coordinates is required */
{
@ -500,7 +505,9 @@ message_translate (ClutterBackend *backend,
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);
/* We need to start tracking when the mouse leaves the stage if
event->motion.device = backend_win32->core_pointer;
/* We need to start tracking when the mouse enters the stage if
we're not already */
if (!stage_win32->tracking_mouse)
{
@ -511,6 +518,9 @@ message_translate (ClutterBackend *backend,
tmevent.hwndTrack = stage_win32->hwnd;
TrackMouseEvent (&tmevent);
/* we entered the stage */
_clutter_input_device_set_stage (event->motion.device, stage);
stage_win32->tracking_mouse = TRUE;
}
break;
@ -520,6 +530,10 @@ message_translate (ClutterBackend *backend,
event->crossing.time = msg->time;
event->crossing.x = msg->pt.x;
event->crossing.y = msg->pt.y;
event->crossing.device = backend_win32->core_pointer;
/* we left the stage */
_clutter_input_device_set_stage (event->crossing.device, NULL);
/* When we get a leave message the mouse tracking is
automatically cancelled so we'll need to start it again when
@ -604,6 +618,7 @@ message_translate (ClutterBackend *backend,
event->key.time = msg->time;
event->key.modifier_state = get_key_modifier_state (key_states);
event->key.hardware_keycode = scan_code;
event->key.device = backend_win32->core_keyboard;
}
break;
@ -616,6 +631,20 @@ message_translate (ClutterBackend *backend,
}
break;
case WM_SETCURSOR:
/* If the cursor is in the window's client area and the stage's
cursor should be invisible then we'll set a blank cursor
instead */
if (LOWORD (msg->lParam) == HTCLIENT && !stage_win32->is_cursor_visible)
{
if (call_def_window_proc)
*call_def_window_proc = FALSE;
_clutter_stage_win32_update_cursor (stage_win32);
}
res = FALSE;
break;
default:
/* ignore every other message */
res = FALSE;

View File

@ -216,17 +216,51 @@ clutter_stage_win32_set_title (ClutterStageWindow *stage_window,
SetWindowTextW (stage_win32->hwnd, stage_win32->wtitle);
}
void
_clutter_stage_win32_update_cursor (ClutterStageWin32 *stage_win32)
{
HCURSOR cursor;
if (stage_win32->is_cursor_visible)
cursor = (HCURSOR) GetClassLongPtrW (stage_win32->hwnd, GCL_HCURSOR);
else
{
ClutterBackend *backend = clutter_get_default_backend ();
/* The documentation implies that we can just use
SetCursor(NULL) to get rid of the cursor but apparently this
doesn't work very well so instead we create an invisible
cursor */
cursor = _clutter_backend_win32_get_invisible_cursor (backend);
}
SetCursor (cursor);
}
static void
clutter_stage_win32_set_cursor_visible (ClutterStageWindow *stage_window,
gboolean cursor_visible)
{
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
if (stage_win32->is_cursor_visible != cursor_visible &&
stage_win32->tracking_mouse)
ShowCursor (cursor_visible);
if (stage_win32->is_cursor_visible != cursor_visible)
{
POINT cursor_pos;
RECT client_rect;
stage_win32->is_cursor_visible = cursor_visible;
/* If the cursor is already over the client area of the window
then we need to update it immediately */
GetCursorPos (&cursor_pos);
if (WindowFromPoint (cursor_pos) == stage_win32->hwnd &&
ScreenToClient (stage_win32->hwnd, &cursor_pos) &&
GetClientRect (stage_win32->hwnd, &client_rect) &&
cursor_pos.x >= client_rect.left &&
cursor_pos.y >= client_rect.top &&
cursor_pos.x < client_rect.right &&
cursor_pos.y < client_rect.bottom)
_clutter_stage_win32_update_cursor (stage_win32);
}
}
static LONG
@ -442,7 +476,7 @@ clutter_stage_win32_realize (ClutterStageWindow *stage_window)
win_xpos = stage_win32->fullscreen_rect.left;
win_ypos = stage_win32->fullscreen_rect.top;
win_width = stage_win32->fullscreen_rect.right - win_xpos;
win_height = stage_win32->fullscreen_rect.left - win_ypos;
win_height = stage_win32->fullscreen_rect.bottom - win_ypos;
}
else
{

View File

@ -80,6 +80,8 @@ LRESULT CALLBACK _clutter_stage_win32_window_proc (HWND hwnd,
void _clutter_stage_win32_get_min_max_info (ClutterStageWin32 *stage_win32,
MINMAXINFO *min_max_info);
void _clutter_stage_win32_update_cursor (ClutterStageWin32 *stage_win32);
G_END_DECLS
#endif /* __CLUTTER_STAGE_H__ */

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 B

View File

@ -0,0 +1 @@
42 CURSOR "invisible-cursor.cur"

View File

@ -43,6 +43,8 @@ libclutter_x11_la_SOURCES = \
clutter-backend-x11.h \
clutter-backend-x11.c \
clutter-event-x11.c \
clutter-input-device-x11.h \
clutter-input-device-x11.c \
clutter-stage-x11.h \
clutter-stage-x11.c \
clutter-x11-enum-types.h \

View File

@ -37,6 +37,7 @@
#include <errno.h>
#include "clutter-backend-x11.h"
#include "clutter-input-device-x11.h"
#include "clutter-stage-x11.h"
#include "clutter-x11.h"
@ -46,31 +47,16 @@
#include <X11/extensions/XInput.h>
#endif
#include "../clutter-event.h"
#include "../clutter-main.h"
#include "../clutter-debug.h"
#include "../clutter-private.h"
#include "cogl/cogl.h"
#include "../clutter-debug.h"
#include "../clutter-device-manager.h"
#include "../clutter-event.h"
#include "../clutter-main.h"
#include "../clutter-private.h"
G_DEFINE_TYPE (ClutterBackendX11, clutter_backend_x11, CLUTTER_TYPE_BACKEND);
struct _ClutterX11XInputDevice
{
ClutterInputDevice device;
#ifdef HAVE_XINPUT
XDevice *xdevice;
XEventClass xevent_list[5]; /* MAX 5 event types */
int num_events;
#endif
};
#ifdef HAVE_XINPUT
void _clutter_x11_register_xinput ();
#endif
/* atoms; remember to add the code that assigns the atom value to
* the member of the ClutterBackendX11 structure if you add an
* atom name here. do not change the order!
@ -109,6 +95,129 @@ static gboolean clutter_synchronise = FALSE;
static int TrappedErrorCode = 0;
static int (* old_error_handler) (Display *, XErrorEvent *);
static void
clutter_x11_register_input_devices (ClutterBackendX11 *backend)
{
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_get_default ();
if (!clutter_enable_xinput)
{
CLUTTER_NOTE (BACKEND, "XInput support not enabled");
goto default_device;
}
#ifdef HAVE_XINPUT
res = XQueryExtension (backend->xdpy, "XInputExtension",
&opcode,
&event,
&error);
if (!res)
{
CLUTTER_NOTE (BACKEND, "No XInput extension available");
goto default_device;
}
backend->xi_event_base = event;
x_devices = XListInputDevices (backend->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:
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);
_clutter_device_manager_add_device (manager, device);
if (info->use == IsXExtensionPointer && n_events > 0)
backend->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");
_clutter_device_manager_add_device (manager, device);
backend->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");
_clutter_device_manager_add_device (manager, device);
backend->core_keyboard = device;
}
gboolean
clutter_backend_x11_pre_parse (ClutterBackend *backend,
GError **error)
@ -199,9 +308,8 @@ clutter_backend_x11_post_parse (ClutterBackend *backend,
clutter_backend_set_resolution (backend, dpi);
#ifdef HAVE_XINPUT
_clutter_x11_register_xinput ();
#endif
/* register input devices */
clutter_x11_register_input_devices (backend_x11);
if (clutter_synchronise)
XSynchronize (backend_x11->xdpy, True);
@ -644,239 +752,29 @@ clutter_x11_remove_filter (ClutterX11FilterFunc func,
}
}
void
_clutter_x11_register_xinput ()
{
#ifdef HAVE_XINPUT
XDeviceInfo *xdevices = NULL;
XDeviceInfo *info = NULL;
XDevice *xdevice = NULL;
XInputClassInfo *xclass_info = NULL;
gint opcode, event, error;
gint res;
gint num_devices = 0;
gint num_events = 0;
gint i = 0, j = 0;
gboolean have_an_xpointer = FALSE;
ClutterBackendX11 *x11b;
ClutterX11XInputDevice *device = NULL;
ClutterMainContext *context;
GSList *input_devices = NULL;
if (!backend_singleton)
{
g_critical ("X11 backend has not been initialised");
return;
}
if (!clutter_enable_xinput)
{
CLUTTER_NOTE (BACKEND, "Not enabling XInput");
return;
}
context = _clutter_context_get_default ();
backend_singleton->have_xinput = FALSE;
/* is the XInput extension available? */
res = XQueryExtension (backend_singleton->xdpy, "XInputExtension",
&opcode, &event,
&error);
if (!res)
{
CLUTTER_NOTE (BACKEND, "X Input extension not available");
return;
}
x11b = backend_singleton;
xdevices = XListInputDevices (x11b->xdpy, &num_devices);
CLUTTER_NOTE (BACKEND, "%d XINPUT devices found", num_devices);
if (num_devices == 0)
return;
for (i = 0; i < num_devices; i++)
{
info = xdevices + i;
num_events = 0;
CLUTTER_NOTE (BACKEND, "Considering %li with type %d",
info->id,
info->use);
/* Only want 'raw' devices themselves not virtual ones */
if (info->use == IsXExtensionPointer ||
/*info->use == IsXExtensionKeyboard || XInput 1.x is broken */
info->use == IsXExtensionDevice)
{
clutter_x11_trap_x_errors ();
xdevice = XOpenDevice (backend_singleton->xdpy, info->id);
if (clutter_x11_untrap_x_errors () || xdevice == NULL)
continue;
/* Create the appropriate Clutter device */
device = g_slice_new0 (ClutterX11XInputDevice);
device->device.id = info->id;
switch (info->use)
{
case IsXExtensionPointer:
device->device.device_type = CLUTTER_POINTER_DEVICE;
have_an_xpointer = TRUE;
break;
#if 0
/* XInput 1.x is broken for keyboards: */
case IsXExtensionKeyboard:
device->device.type = CLUTTER_KEYBOARD_DEVICE;
break;
#endif
case IsXExtensionDevice:
device->device.device_type = CLUTTER_EXTENSION_DEVICE;
break;
}
/* FIXME: some kind of general device_init() call should do below */
device->device.click_count = 0;
device->device.previous_time = 0;
device->device.previous_x = -1;
device->device.previous_y = -1;
device->device.previous_button_number = -1;
device->num_events = 0;
device->xdevice = xdevice;
CLUTTER_NOTE (BACKEND, "Registering XINPUT device with XID: %li",
xdevice->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 (j = 0; j < xdevice->num_classes; j++)
{
xclass_info = xdevice->classes + j;
switch (xclass_info->input_class)
{
#if 0
/* XInput 1.x is broken for keyboards: */
case KeyClass:
DeviceKeyPress (xdevice,
x11b->event_types[CLUTTER_X11_XINPUT_KEY_PRESS_EVENT],
device->xevent_list [num_events]);
num_events++;
DeviceKeyRelease (xdevice,
x11b->event_types[CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT],
device->xevent_list [num_events]);
num_events++;
break;
#endif
case ButtonClass:
DeviceButtonPress (xdevice,
x11b->event_types[CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT],
device->xevent_list [num_events]);
num_events++;
DeviceButtonRelease (xdevice,
x11b->event_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT],
device->xevent_list [num_events]);
num_events++;
break;
case ValuatorClass:
DeviceMotionNotify (xdevice,
x11b->event_types[CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT],
device->xevent_list [num_events]);
num_events++;
break;
}
}
if (info->use == IsXExtensionPointer && num_events > 0)
have_an_xpointer = TRUE;
device->num_events = num_events;
input_devices = g_slist_prepend (input_devices, device);
}
}
XFree (xdevices);
if (!have_an_xpointer)
{
GSList *l;
/* Something is likely wrong with Xinput setup so we basically
* abort here and fall back to lofi regular xinput.
*/
g_warning ("No usuable XInput pointing devices found");
for (l = input_devices; l != NULL; l = l->next)
g_slice_free (ClutterX11XInputDevice, l->data);
g_slist_free (input_devices);
context->input_devices = NULL;
return;
}
/* store the list of input devices */
context->input_devices = g_slist_reverse (input_devices);
/* why yes, we are awesome */
backend_singleton->have_xinput = TRUE;
#endif /* HAVE_XINPUT */
}
void
_clutter_x11_unregister_xinput ()
{
}
void
_clutter_x11_select_events (Window xwin)
{
#ifdef HAVE_XINPUT
GSList *list_it;
ClutterX11XInputDevice *device = NULL;
ClutterDeviceManager *manager;
const GSList *l;
ClutterMainContext *context;
context = _clutter_context_get_default ();
if (!backend_singleton)
if (G_UNLIKELY (backend_singleton == NULL))
{
g_critical ("X11 backend has not been initialised");
return;
}
for (list_it = context->input_devices;
list_it != NULL;
list_it = list_it->next)
{
device = (ClutterX11XInputDevice *)list_it->data;
manager = clutter_device_manager_get_default ();
XSelectExtensionEvent (backend_singleton->xdpy,
xwin,
device->xevent_list,
device->num_events);
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 */
}
@ -884,49 +782,34 @@ _clutter_x11_select_events (Window xwin)
ClutterInputDevice *
_clutter_x11_get_device_for_xid (XID id)
{
#ifdef HAVE_XINPUT
ClutterMainContext *context;
GSList *l;
ClutterDeviceManager *manager;
context = _clutter_context_get_default ();
manager = clutter_device_manager_get_default ();
if (!backend_singleton)
{
g_critical ("X11 backend has not been initialised");
return NULL;
return clutter_device_manager_get_device (manager, (gint) id);
}
for (l = context->input_devices; l != NULL; l = l->next)
{
ClutterX11XInputDevice *device = l->data;
if (device->xdevice->device_id == id)
return (ClutterInputDevice *) device;
}
#endif /* HAVE_XINPUT */
return NULL;
}
/* FIXME: This nasty little func needs moving elsewhere.. */
/**
* clutter_x11_get_input_devices:
*
* Retrieves a pointer to the list of input devices
*
* Deprecated: 1.2: Use clutter_device_manager_peek_devices() instead
*
* Since: 0.8
*
* Return value: a pointer to the internal list of input devices; the
* returned list is owned by Clutter and should not be modified or
* freed
*/
G_CONST_RETURN GSList *
clutter_x11_get_input_devices (void)
{
#ifdef HAVE_XINPUT
ClutterMainContext *context;
ClutterDeviceManager *manager;
if (!backend_singleton)
{
g_critical ("X11 backend has not been initialised");
return NULL;
}
manager = clutter_device_manager_get_default ();
context = _clutter_context_get_default ();
return context->input_devices;
#else /* !HAVE_XINPUT */
return NULL;
#endif /* HAVE_XINPUT */
return clutter_device_manager_peek_devices (manager);
}
/**
@ -943,7 +826,7 @@ gboolean
clutter_x11_has_xinput (void)
{
#ifdef HAVE_XINPUT
if (!backend_singleton)
if (backend_singleton == NULL)
{
g_critical ("X11 backend has not been initialised");
return FALSE;

View File

@ -76,10 +76,14 @@ 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;
ClutterInputDevice *core_pointer;
ClutterInputDevice *core_keyboard;
};
struct _ClutterBackendX11Class
@ -125,12 +129,6 @@ clutter_backend_x11_get_features (ClutterBackend *backend);
XVisualInfo *
clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11);
void
_clutter_x11_register_xinput (void);
void
_clutter_x11_unregister_xinput (void);
ClutterInputDevice *
_clutter_x11_get_device_for_xid (XID id);

View File

@ -1,7 +1,8 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
* Authored By Matthew Allum <mallum@openedhand.com>
* Copyright (C) 2006-2007 OpenedHand
*
* Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
* Copyright (C) 2009, 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
@ -17,6 +18,10 @@
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Authored by:
* Matthew Allum <mallum@openedhand.com>
* Emmanuele Bassi <ebassi@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
@ -183,7 +188,6 @@ _clutter_backend_x11_events_init (ClutterBackend *backend)
g_source_add_poll (source, &event_source->event_poll_fd);
g_source_set_can_recurse (source, TRUE);
g_source_attach (source, NULL);
}
void
@ -263,9 +267,10 @@ set_user_time (ClutterBackendX11 *backend_x11,
}
}
#if 0 /* See XInput keyboard comment below HAVE_XINPUT */
#ifdef HAVE_XINPUT
static void
convert_xdevicekey_to_xkey (XDeviceKeyEvent *xkev, XEvent *xevent)
convert_xdevicekey_to_xkey (XDeviceKeyEvent *xkev,
XEvent *xevent)
{
xevent->xany.type = xevent->xkey.type = xkev->type;
xevent->xkey.serial = xkev->serial;
@ -416,6 +421,8 @@ event_translate (ClutterBackend *backend,
ClutterStageWindow *impl;
gboolean res, not_yet_handled = FALSE;
Window xwindow, stage_xwindow;
ClutterDeviceManager *manager;
ClutterInputDevice *device;
backend_x11 = CLUTTER_BACKEND_X11 (backend);
@ -424,13 +431,12 @@ event_translate (ClutterBackend *backend,
if (backend_x11->event_filters)
{
GSList *node;
ClutterX11EventFilter *filter;
node = backend_x11->event_filters;
while (node)
{
filter = node->data;
ClutterX11EventFilter *filter = node->data;
switch (filter->func (xevent, event, filter->data))
{
@ -448,16 +454,16 @@ event_translate (ClutterBackend *backend,
}
}
/*
* 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.
/* 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;
manager = clutter_device_manager_get_default ();
impl = _clutter_stage_get_window (stage);
stage_x11 = CLUTTER_STAGE_X11 (impl);
stage_xwindow = xwindow; /* clutter_x11_get_stage_window (stage); */
@ -621,6 +627,8 @@ event_translate (ClutterBackend *backend,
case KeyPress:
event->key.type = event->type = CLUTTER_KEY_PRESS;
event->key.device = backend_x11->core_keyboard;
translate_key_event (backend, event, xevent);
set_user_time (backend_x11, &xwindow, xevent->xkey.time);
@ -654,6 +662,8 @@ event_translate (ClutterBackend *backend,
}
event->key.type = event->type = CLUTTER_KEY_RELEASE;
event->key.device = backend_x11->core_keyboard;
translate_key_event (backend, event, xevent);
break;
@ -666,14 +676,11 @@ event_translate (ClutterBackend *backend,
/* Input device event handling.. */
if (not_yet_handled)
{
if (!clutter_x11_has_xinput ())
{
device = backend_x11->core_pointer;
/* Regular X event */
switch (xevent->type)
{
/* KeyPress / KeyRelease should reside here if XInput
* worked properly
*/
case ButtonPress:
switch (xevent->xbutton.button)
{
@ -696,8 +703,9 @@ event_translate (ClutterBackend *backend,
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;
@ -705,11 +713,13 @@ event_translate (ClutterBackend *backend,
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:
@ -720,7 +730,7 @@ event_translate (ClutterBackend *backend,
xevent->xbutton.button == 7)
{
res = FALSE;
break;
goto out;
}
event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
@ -729,6 +739,9 @@ event_translate (ClutterBackend *backend,
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:
@ -737,9 +750,16 @@ event_translate (ClutterBackend *backend,
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;
@ -747,34 +767,70 @@ event_translate (ClutterBackend *backend,
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:
/* ignore every other event */
res = FALSE;
break;
}
}
else
{ /* XInput fun.. Needs clean up. */
/* 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 == ev_types [CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT])
if (xevent->type == button_press)
{
XDeviceButtonEvent *xbev = (XDeviceButtonEvent *) xevent;
CLUTTER_NOTE (EVENT, "XINPUT Button press event for %li at %d, %d",
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);
@ -799,7 +855,7 @@ event_translate (ClutterBackend *backend,
event->scroll.x = xbev->x;
event->scroll.y = xbev->y;
event->scroll.modifier_state = xbev->state;
event->scroll.device = _clutter_x11_get_device_for_xid (xbev->deviceid);
event->scroll.device = device;
break;
default:
@ -809,19 +865,24 @@ event_translate (ClutterBackend *backend,
event->button.y = xbev->y;
event->button.modifier_state = xbev->state;
event->button.button = xbev->button;
event->button.device = _clutter_x11_get_device_for_xid (xbev->deviceid);
event->button.device = device;
break;
}
set_user_time (backend_x11, &xwindow, xbev->time);
res = TRUE;
}
else if (xevent->type
== ev_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT])
else if (xevent->type == button_release)
{
XDeviceButtonEvent *xbev = (XDeviceButtonEvent *)xevent;
CLUTTER_NOTE (EVENT, "XINPUT Button release event for %li at %d, %d",
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);
@ -831,7 +892,8 @@ event_translate (ClutterBackend *backend,
xbev->button == 6 ||
xbev->button == 7)
{
return FALSE;
res = FALSE;
goto out;
}
event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
@ -840,15 +902,20 @@ event_translate (ClutterBackend *backend,
event->button.y = xbev->y;
event->button.modifier_state = xbev->state;
event->button.button = xbev->button;
event->button.device = _clutter_x11_get_device_for_xid (xbev->deviceid);
event->button.device = device;
res = TRUE;
}
else if (xevent->type
== ev_types [CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT])
else if (xevent->type == motion_notify)
{
XDeviceMotionEvent *xmev = (XDeviceMotionEvent *)xevent;
CLUTTER_NOTE(EVENT, "XINPUT Motion event for %li at %d, %d",
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);
@ -857,39 +924,30 @@ event_translate (ClutterBackend *backend,
event->motion.x = xmev->x;
event->motion.y = xmev->y;
event->motion.modifier_state = xmev->state;
event->motion.device = _clutter_x11_get_device_for_xid (xmev->deviceid);
}
#if 0
/* the Xinput handling of key presses/releases disabled for now since
* it makes keyrepeat, and key presses and releases outside the window
* not generate events even when the window has focus
*/
event->motion.device = device;
else if (xevent->type
== ev_types [CLUTTER_X11_XINPUT_KEY_PRESS_EVENT])
res = TRUE;
}
else if (xevent->type == key_press || xevent->type == key_release)
{
XEvent xevent_converted;
/* 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 = CLUTTER_KEY_PRESS;
event->key.type = event->type = (xevent->type == key_press)
? CLUTTER_KEY_PRESS
: CLUTTER_KEY_RELEASE;
translate_key_event (backend, event, &xevent_converted);
if (xevent->type == key_press)
set_user_time (backend_x11, &xwindow, xkev->time);
}
else if (xevent->type
== ev_types [CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT])
{
XEvent xevent_converted;
XDeviceKeyEvent *xkev = (XDeviceKeyEvent *)xevent;
convert_xdevicekey_to_xkey (xkev, &xevent_converted);
event->key.type = event->type = CLUTTER_KEY_RELEASE;
translate_key_event (backend, event, &xevent_converted);
}
#endif
else
#endif /* HAVE_XINPUT */
{
@ -897,8 +955,8 @@ event_translate (ClutterBackend *backend,
res = FALSE;
}
}
}
out:
return res;
}

View File

@ -0,0 +1,221 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "clutter-input-device-x11.h"
#include "../clutter-debug.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
};
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);
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 */
}

View File

@ -0,0 +1,25 @@
#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__ */

View File

@ -121,14 +121,16 @@ gboolean clutter_x11_has_event_retrieval (void);
ClutterStage *clutter_x11_get_stage_from_window (Window win);
#ifndef CLUTTER_DISABLE_DEPRECATED
G_CONST_RETURN GSList* clutter_x11_get_input_devices (void);
#endif
void clutter_x11_enable_xinput (void);
gboolean clutter_x11_has_xinput (void);
gboolean clutter_x11_has_composite_extension (void);
void clutter_X11_set_use_argb_visual (gboolean use_argb);
void clutter_x11_set_use_argb_visual (gboolean use_argb);
gboolean clutter_x11_get_use_argb_visual (void);
Time clutter_x11_get_current_event_time (void);

View File

@ -12,7 +12,7 @@
# - increase clutter_interface_version to the next odd number
m4_define([clutter_major_version], [1])
m4_define([clutter_minor_version], [1])
m4_define([clutter_micro_version], [5])
m4_define([clutter_micro_version], [7])
m4_define([clutter_release_status],
[m4_if(m4_eval(clutter_micro_version % 2), [1], [git],
@ -56,7 +56,7 @@ AC_CONFIG_HEADERS([config.h])
AC_CONFIG_AUX_DIR([build])
AC_CONFIG_MACRO_DIR([build/autotools])
AM_INIT_AUTOMAKE([1.9.6 foreign])
AM_INIT_AUTOMAKE([1.9.6 foreign -Wno-portability no-define])
CLUTTER_MAJOR_VERSION=clutter_major_version
CLUTTER_MINOR_VERSION=clutter_minor_version
@ -364,11 +364,18 @@ AS_CASE([$CLUTTER_WINSYS],
WIN32_CFLAGS="-D_WIN32_WINNT=0x0500"
WIN32_LIBS="-lopengl32 -lgdi32 -lwinmm"
CLUTTER_LT_LDFLAGS="$CLUTTER_LT_LDFLAGS -no-undefined"
AC_CHECK_TOOL(WINDRES, windres, no)
if test "$WINDRES" = no; then
AC_MSG_ERROR([*** windres is required])
fi
],
[AC_MSG_ERROR([Invalid backend for Clutter: use glx, sdl, osx, win32, eglx, eglnative or fruity])]
)
AM_CONDITIONAL(WINSYS_WIN32, [test "x$CLUTTER_WINSYS" = "xwin32"])
# at this point we must have a GL header to check
AS_IF([test "x$clutter_gl_header" = "x"], [AC_MSG_ERROR([Internal error: no GL header set])])
AC_CHECK_HEADERS([$clutter_gl_header],
@ -689,6 +696,18 @@ AS_CASE([$enable_cogl_debug],
AC_SUBST(COGL_DEBUG_CFLAGS)
dnl === Conformance test suite ================================================
AC_ARG_ENABLE([conformance],
[AC_HELP_STRING([--enable-conformance=@<:@no/yes@:>@],
[Build conformance test suite @<:@default=yes@:>@])],
[],
[enable_conformance=yes])
AM_CONDITIONAL([BUILD_TESTS], [test "x$enable_conformance" = "xyes"])
dnl === Profiling =============================================================
m4_define([profile_default], [no])
AC_ARG_ENABLE(profile,
AC_HELP_STRING([--enable-profile=@<:@no/yes@:>@],
@ -698,22 +717,27 @@ AC_ARG_ENABLE(profile,
AS_CASE([$enable_profile],
[yes], [
if test "x$GCC" = "xyes"; then
[yes],
[
AS_IF([test "x$GCC" = "xyes"],
[
PKG_CHECK_MODULES([PROFILE_DEP], [uprof-0.2])
CLUTTER_PROFILE_CFLAGS=" -DCLUTTER_ENABLE_PROFILE -DCOGL_ENABLE_PROFILE $PROFILE_DEP_CFLAGS"
CLUTTER_PROFILE_LDFLAGS=" $PROFILE_DEP_LIBS"
if test "x$enable_debug" = "xyes"; then
CLUTTER_PROFILE_CFLAGS+=" -DUPROF_DEBUG"
fi
else
AC_MSG_ERROR([--enable-profile is currently only supported if using GCC])
fi
AS_IF([test "x$enable_debug" = "xyes"], [CLUTTER_PROFILE_CFLAGS+=" -DUPROF_DEBUG"])
],
[no], [
[
AC_MSG_ERROR([--enable-profile is currently only supported if using GCC])
])
],
[no],
[
CLUTTER_PROFILE_CFLAGS=""
CLUTTER_PROFILE_LDFLAGS=""
],
[*], [AC_MSG_ERROR([Invalid value for --enable-profile])]
)
AM_CONDITIONAL(PROFILE, test "x$enable_profile" != "xno")
@ -735,15 +759,20 @@ and gcov)])],
AS_IF([test "x$enable_gcov" = "xyes" && test "x$GCC" = "xyes"],
[
AS_IF([test "x$enable_conformance" = "xno"],
[AC_MSG_WARN([Conformance test suite is disabled, the coverage report will be incomplete])],
[AC_MSG_RESULT([yes])]
)
GCOV_CFLAGS="-g -O0 -fprofile-arcs -ftest-coverage"
GCOV_LDFLAGS="-lgcov"
]
],
[AC_MSG_RESULT([no])]
)
AM_CONDITIONAL([GCOV_ENABLED], [test "x$enable_gcov" = "xyes"])
AC_SUBST([GCOV_CFLAGS])
AC_SUBST([GCOV_LDFLAGS])
AC_MSG_RESULT([$enable_gcov])
dnl === Enable strict compiler flags ==========================================
@ -868,6 +897,7 @@ AC_CONFIG_FILES([
Makefile
build/Makefile
build/autotools/Makefile
build/mingw/Makefile
clutter/Makefile
clutter/clutter-version.h
clutter/clutter-json.h
@ -945,7 +975,7 @@ echo " Build Additional Documentation: ${enable_docs} (Generate PDF: ${en
echo ""
echo " • Extra:"
echo " Build introspection data: ${enable_introspection}"
echo " Build test suite: ${enable_glibtest}"
echo " Build conformance test suite: ${enable_conformance}"
if test "x$have_json" = "xyes"; then
echo " JSON-GLib: system"

View File

@ -57,7 +57,7 @@ Short explanation of the commit
Longer explanation explaining exactly what's changed, whether any
external or private interfaces changed, what bugs were fixed (with bug
tracker reference if applicable) and so forth. Be concise but not too
brief.
brief. Don't be afraid of using UTF-8, or even ASCII art.
=== end example commit ===
Always add a brief description of the commit to the _first_ line of

View File

@ -68,6 +68,7 @@ IGNORE_HFILES=\
clutter-debug.h \
clutter-deprecated.h \
clutter-enum-types.h \
clutter-id-pool.h \
clutter-json.h \
clutter-keysyms.h \
clutter-keysyms-table.h \
@ -75,7 +76,7 @@ IGNORE_HFILES=\
clutter-master-clock.h \
clutter-model-private.h \
clutter-private.h \
clutter-id-pool.h \
clutter-profile.h \
clutter-script-private.h \
clutter-stage-window.h \
clutter-timeout-interval.h \

View File

@ -298,13 +298,12 @@ main (int argc, char *argv[])
ClutterBehaviour *behave;
ClutterAlpha *alpha;
ClutterActor *stage, *actor;
GdkPixbuf *pixbuf;
clutter_init (&amp;argc, &amp;argv);
stage = clutter_stage_get_default ();
actor = clutter_texture_new_from_file ("ohpowers.png, NULL);
actor = clutter_texture_new_from_file ("ohpowers.png", NULL);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), actor);
/* set up the animation to be 4 seconds long */
@ -315,7 +314,7 @@ main (int argc, char *argv[])
* alpha will take a reference on the timeline so we can safely
* release the reference we hold
*/
alpha = clutter_alpha_new_full (timeline, CLUTTER_EASE_SINE_IN_OUT);
alpha = clutter_alpha_new_full (timeline, CLUTTER_EASE_IN_OUT_SINE);
g_object_unref (timeline);
/* the behaviour will own the alpha by sinking its floating
@ -385,9 +384,9 @@ main (int argc, char *argv[])
position and a new set of coordinates. The animation takes 200
milliseconds to complete and uses a linear progression.</para>
<programlisting>
clutter_actor_animate (actor, CLUTTER_LINEAR, 200
"x", 200,
"y", 200,
clutter_actor_animate (actor, CLUTTER_LINEAR, 200,
"x", 200.0f,
"y", 200.0f,
NULL);
</programlisting>
</example>

View File

@ -139,8 +139,11 @@
<xi:include href="xml/clutter-main.xml"/>
<xi:include href="xml/clutter-shader.xml"/>
<xi:include href="xml/clutter-stage-manager.xml"/>
<xi:include href="xml/clutter-input-device.xml"/>
<xi:include href="xml/clutter-device-manager.xml"/>
<xi:include href="xml/clutter-units.xml"/>
<xi:include href="xml/clutter-util.xml"/>
<xi:include href="xml/clutter-feature.xml"/>
<xi:include href="xml/clutter-version.xml"/>
</chapter>

View File

@ -404,6 +404,7 @@ clutter_actor_create_pango_layout
clutter_actor_is_in_clone_paint
clutter_actor_set_text_direction
clutter_actor_get_text_direction
clutter_actor_has_pointer
<SUBSECTION>
ClutterActorBox
@ -874,7 +875,7 @@ clutter_param_fixed_get_type
<SECTION>
<FILE>clutter-feature</FILE>
<TITLE>GL Features</TITLE>
<TITLE>Features</TITLE>
ClutterFeatureFlags
clutter_feature_available
clutter_feature_get_all
@ -940,7 +941,6 @@ ClutterMotionEvent
ClutterScrollEvent
ClutterStageStateEvent
ClutterCrossingEvent
ClutterInputDevice
clutter_event_new
clutter_event_copy
clutter_event_free
@ -977,13 +977,9 @@ clutter_event_get_related
clutter_event_get_scroll_direction
<SUBSECTION>
ClutterInputDeviceType
clutter_event_get_device
clutter_event_get_device_id
clutter_event_get_device_type
clutter_get_input_device_for_id
clutter_input_device_get_device_id
clutter_input_device_get_device_type
<SUBSECTION>
clutter_get_current_event_time
@ -996,6 +992,51 @@ ClutterAnyEvent
clutter_event_get_type
</SECTION>
<SECTION>
<FILE>clutter-input-device</FILE>
<TITLE>ClutterInputDevice</TITLE>
ClutterInputDeviceType
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_coords
clutter_input_device_get_pointer_actor
<SUBSECTION Standard>
CLUTTER_TYPE_INPUT_DEVICE
CLUTTER_INPUT_DEVICE
CLUTTER_INPUT_DEVICE_CLASS
CLUTTER_IS_INPUT_DEVICE
CLUTTER_IS_INPUT_DEVICE_CLASS
CLUTTER_INPUT_DEVICE_GET_CLASS
<SUBSECTION Private>
clutter_input_device_get_type
</SECTION>
<SECTION>
<FILE>clutter-device-manager</FILE>
<TITLE>ClutterDeviceManager</TITLE>
ClutterDeviceManager
clutter_device_manager_get_default
clutter_device_manager_list_devices
clutter_device_manager_peek_devices
clutter_device_manager_get_device
<SUBSECTION>
clutter_get_input_device_for_id
<SUBSECTION Standard>
CLUTTER_TYPE_DEVICE_MANAGER
CLUTTER_DEVICE_MANAGER
CLUTTER_IS_DEVICE_MANAGER
<SUBSECTION Private>
clutter_device_manager_get_type
</SECTION>
<SECTION>
<FILE>clutter-main</FILE>
<TITLE>General</TITLE>

View File

@ -40,3 +40,5 @@ clutter_fixed_layout_get_type
clutter_bin_layout_get_type
clutter_flow_layout_get_type
clutter_box_layout_get_type
clutter_input_device_get_type
clutter_device_manager_get_type

View File

@ -59,14 +59,13 @@ to this OpenGL code:
<programlisting>
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_COLOR);
glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_COLOR);
</programlisting>
</section>

View File

@ -1,13 +1,28 @@
SUBDIRS = data conform interactive micro-bench tools
SUBDIRS = data interactive micro-bench tools
if BUILD_TESTS
SUBDIRS += conform
endif
DIST_SUBDIRS = data conform interactive micro-bench tools
EXTRA_DIST = README
.PHONY: test conform
if BUILD_TESTS
test conform:
$(MAKE) -C ./conform test
.PHONY: test-report full-report
( cd ./conform && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$?
test-report full-report:
$(MAKE) -C ./conform $(@)
( cd ./conform && $(MAKE) $(AM_MAKEFLAGS) $@ ) || exit $$?
else
test conform:
@true
test-report full-report:
@true
endif # BUILD_TESTS
.PHONY: test conform test-report full-report
# run make test as part of make check
check-local: test

View File

@ -41,9 +41,9 @@ check_pixel (GLubyte *pixel, guint32 color)
g_print (" expected = %x, %x, %x, %x\n",
r, g, b, a);
/* FIXME - allow for hardware in-precision */
g_assert (pixel[RED] == r);
g_assert (pixel[GREEN] == g);
g_assert (pixel[BLUE] == b);
g_assert_cmpint (pixel[RED], ==, r);
g_assert_cmpint (pixel[GREEN], ==, g);
g_assert_cmpint (pixel[BLUE], ==, b);
/* FIXME
* We ignore the alpha, since we don't know if our render target is

View File

@ -180,6 +180,7 @@ test_texture_fbo (TestConformSimpleFixture *fixture,
{
TestState state;
guint idle_source;
gulong paint_handler;
ClutterActor *actor;
int ypos = 0;
@ -236,12 +237,15 @@ test_texture_fbo (TestConformSimpleFixture *fixture,
* will trigger redrawing. */
idle_source = g_idle_add (queue_redraw, state.stage);
g_signal_connect_after (state.stage, "paint", G_CALLBACK (on_paint), &state);
paint_handler = g_signal_connect_after (state.stage, "paint",
G_CALLBACK (on_paint), &state);
clutter_actor_show_all (state.stage);
clutter_main ();
g_signal_handler_disconnect (state.stage, paint_handler);
g_source_remove (idle_source);
/* Remove all of the actors from the stage */

View File

@ -12,14 +12,21 @@
typedef struct _TestMultiLayerMaterialState
{
ClutterActor *group;
CoglHandle material;
CoglHandle alpha_tex;
CoglHandle redhand_tex;
CoglHandle light_tex0;
gfloat *tex_coords;
CoglMatrix tex_matrix;
CoglMatrix rot_matrix;
ClutterTimeline *timeline;
CoglHandle material0;
CoglMatrix tex_matrix0;
CoglMatrix rot_matrix0;
CoglHandle light_tex0;
CoglHandle material1;
CoglMatrix tex_matrix1;
CoglMatrix rot_matrix1;
CoglHandle light_tex1;
} TestMultiLayerMaterialState;
@ -31,10 +38,15 @@ frame_cb (ClutterTimeline *timeline,
{
TestMultiLayerMaterialState *state = data;
cogl_matrix_multiply (&state->tex_matrix,
&state->tex_matrix,
&state->rot_matrix);
cogl_material_set_layer_matrix (state->material, 2, &state->tex_matrix);
cogl_matrix_multiply (&state->tex_matrix0,
&state->tex_matrix0,
&state->rot_matrix0);
cogl_material_set_layer_matrix (state->material0, 2, &state->tex_matrix0);
cogl_matrix_multiply (&state->tex_matrix1,
&state->tex_matrix1,
&state->rot_matrix1);
cogl_material_set_layer_matrix (state->material1, 2, &state->tex_matrix1);
}
static void
@ -42,18 +54,51 @@ material_rectangle_paint (ClutterActor *actor, gpointer data)
{
TestMultiLayerMaterialState *state = data;
cogl_set_source (state->material);
cogl_rectangle_with_multitexture_coords (0, 0, 200, 200,
cogl_push_matrix ();
cogl_translate (150, 15, 0);
cogl_set_source (state->material0);
cogl_rectangle_with_multitexture_coords (0, 0, 200, 213,
state->tex_coords,
12);
cogl_translate (-300, -30, 0);
cogl_set_source (state->material1);
cogl_rectangle_with_multitexture_coords (0, 0, 200, 213,
state->tex_coords,
12);
cogl_pop_matrix ();
}
static void
animation_completed_cb (ClutterAnimation *animation,
TestMultiLayerMaterialState *state)
{
static gboolean go_back = FALSE;
gdouble new_rotation_y;
if (go_back)
new_rotation_y = 30;
else
new_rotation_y = -30;
go_back = !go_back;
clutter_actor_animate_with_timeline (state->group,
CLUTTER_LINEAR,
state->timeline,
"rotation-angle-y", new_rotation_y,
"signal-after::completed",
animation_completed_cb, state,
NULL);
}
G_MODULE_EXPORT int
test_cogl_multitexture_main (int argc, char *argv[])
{
GError *error = NULL;
ClutterTimeline *timeline;
ClutterBehaviour *r_behave;
ClutterActor *stage;
ClutterColor stage_color = { 0x61, 0x56, 0x56, 0xff };
TestMultiLayerMaterialState *state = g_new0 (TestMultiLayerMaterialState, 1);
@ -113,55 +158,71 @@ test_cogl_multitexture_main (int argc, char *argv[])
if (!state->light_tex0)
g_critical ("Failed to load light0.png: %s", error->message);
state->light_tex1 =
cogl_texture_new_from_file (files[2],
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_ANY,
&error);
if (!state->light_tex1)
g_critical ("Failed to load light0.png: %s", error->message);
g_strfreev (files);
state->material = cogl_material_new ();
cogl_material_set_layer (state->material, 0, state->alpha_tex);
cogl_material_set_layer (state->material, 1, state->redhand_tex);
cogl_material_set_layer (state->material, 2, state->light_tex0);
state->material0 = cogl_material_new ();
cogl_material_set_layer (state->material0, 0, state->alpha_tex);
cogl_material_set_layer (state->material0, 1, state->redhand_tex);
cogl_material_set_layer (state->material0, 2, state->light_tex0);
state->material1 = cogl_material_new ();
cogl_material_set_layer (state->material1, 0, state->alpha_tex);
cogl_material_set_layer (state->material1, 1, state->redhand_tex);
cogl_material_set_layer (state->material1, 2, state->light_tex1);
state->tex_coords = tex_coords;
cogl_matrix_init_identity (&state->tex_matrix);
cogl_matrix_init_identity (&state->rot_matrix);
cogl_matrix_init_identity (&state->tex_matrix0);
cogl_matrix_init_identity (&state->tex_matrix1);
cogl_matrix_init_identity (&state->rot_matrix0);
cogl_matrix_init_identity (&state->rot_matrix1);
cogl_matrix_translate (&state->rot_matrix, 0.5, 0.5, 0);
cogl_matrix_rotate (&state->rot_matrix, 10.0, 0, 0, 1.0);
cogl_matrix_translate (&state->rot_matrix, -0.5, -0.5, 0);
cogl_matrix_translate (&state->rot_matrix0, 0.5, 0.5, 0);
cogl_matrix_rotate (&state->rot_matrix0, 10.0, 0, 0, 1.0);
cogl_matrix_translate (&state->rot_matrix0, -0.5, -0.5, 0);
cogl_matrix_translate (&state->rot_matrix1, 0.5, 0.5, 0);
cogl_matrix_rotate (&state->rot_matrix1, -10.0, 0, 0, 1.0);
cogl_matrix_translate (&state->rot_matrix1, -0.5, -0.5, 0);
clutter_actor_set_anchor_point (state->group, 86, 125);
clutter_container_add_actor (CLUTTER_CONTAINER(stage),
state->group);
timeline = clutter_timeline_new (7692);
clutter_timeline_set_loop (timeline, TRUE);
state->timeline = clutter_timeline_new (2812);
g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), state);
g_signal_connect (state->timeline, "new-frame", G_CALLBACK (frame_cb), state);
r_behave =
clutter_behaviour_rotate_new (clutter_alpha_new_full (timeline,
CLUTTER_LINEAR),
CLUTTER_Y_AXIS,
CLUTTER_ROTATE_CW,
0.0, 360.0);
/* Apply it to our actor */
clutter_behaviour_apply (r_behave, state->group);
clutter_actor_animate_with_timeline (state->group,
CLUTTER_LINEAR,
state->timeline,
"rotation-angle-y", 30.0,
"signal-after::completed",
animation_completed_cb, state,
NULL);
/* start the timeline and thus the animations */
clutter_timeline_start (timeline);
clutter_timeline_start (state->timeline);
clutter_actor_show_all (stage);
clutter_main();
cogl_handle_unref (state->material);
cogl_handle_unref (state->material1);
cogl_handle_unref (state->material0);
cogl_handle_unref (state->alpha_tex);
cogl_handle_unref (state->redhand_tex);
cogl_handle_unref (state->light_tex0);
cogl_handle_unref (state->light_tex1);
g_free (state);
g_object_unref (r_behave);
return 0;
}

View File

@ -9,7 +9,31 @@ typedef struct {
} TestDevicesApp;
static const gchar *
device_type_name (ClutterInputDevice *device)
{
ClutterInputDeviceType d_type;
d_type = clutter_input_device_get_device_type (device);
switch (d_type)
{
case CLUTTER_POINTER_DEVICE:
return "Pointer";
case CLUTTER_KEYBOARD_DEVICE:
return "Keyboard";
case CLUTTER_EXTENSION_DEVICE:
return "Extension";
default:
return "Unknown";
}
g_warn_if_reached ();
return NULL;
}
static gboolean
stage_motion_event_cb (ClutterActor *actor,
@ -24,6 +48,11 @@ stage_motion_event_cb (ClutterActor *actor,
hand = g_hash_table_lookup (app->devices, device);
g_print ("Device: '%s' (id:%d, type:%s)\n",
clutter_input_device_get_device_name (device),
clutter_input_device_get_device_id (device),
device_type_name (device));
if (hand != NULL)
{
gfloat event_x, event_y;
@ -43,6 +72,7 @@ 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;
/* force enabling X11 support */
@ -63,10 +93,11 @@ test_devices_main (int argc, char **argv)
clutter_actor_show_all (stage);
stage_devices = clutter_x11_get_input_devices ();
manager = clutter_device_manager_get_default ();
stage_devices = clutter_device_manager_peek_devices (manager);
if (stage_devices == NULL)
g_error ("No extended input devices found.");
g_error ("No input devices found.");
for (l = stage_devices; l != NULL; l = l->next)
{
@ -74,12 +105,15 @@ test_devices_main (int argc, char **argv)
ClutterInputDeviceType device_type;
ClutterActor *hand = NULL;
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_POINTER_DEVICE)
{
g_print ("got a pointer device 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)
{
hand = clutter_texture_new_from_file (TESTS_DATADIR
G_DIR_SEPARATOR_S
"redhand.png",

View File

@ -48,6 +48,8 @@ static gboolean recenter = FALSE;
static ClutterActor *main_stage = NULL;
static ClutterActor *easing_mode_label = NULL;
static ClutterAnimation *last_animation = NULL;
static void
on_animation_completed (ClutterAnimation *animation,
ClutterActor *rectangle)
@ -113,10 +115,12 @@ on_button_press (ClutterActor *actor,
"y", event->y,
NULL);
if (recenter)
if (recenter && last_animation != animation)
g_signal_connect_after (animation, "completed",
G_CALLBACK (on_animation_completed),
rectangle);
last_animation = animation;
}
return TRUE;

View File

@ -27,6 +27,12 @@ get_event_type_name (const ClutterEvent *event)
case CLUTTER_LEAVE:
return "LEAVE";
case CLUTTER_MOTION:
return "MOTION";
case CLUTTER_DELETE:
return "DELETE";
default:
return "EVENT";
}
@ -127,26 +133,33 @@ fill_keybuf (char *keybuf, ClutterKeyEvent *event)
sprintf (keybuf, "'%s' ", utf8);
/* key combination (<Mod1>s, <Shift><Mod1>S, <Ctrl><Mod1>Delete) */
len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->keyval),
utf8);
len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->keyval), utf8);
utf8[len] = '\0';
if (event->modifier_state & CLUTTER_SHIFT_MASK)
strcat (keybuf, "<Shift>");
if (event->modifier_state & CLUTTER_LOCK_MASK)
strcat (keybuf, "<Lock>");
if (event->modifier_state & CLUTTER_CONTROL_MASK)
strcat (keybuf, "<Control>");
if (event->modifier_state & CLUTTER_MOD1_MASK)
strcat (keybuf, "<Mod1>");
if (event->modifier_state & CLUTTER_MOD2_MASK)
strcat (keybuf, "<Mod2>");
if (event->modifier_state & CLUTTER_MOD3_MASK)
strcat (keybuf, "<Mod3>");
if (event->modifier_state & CLUTTER_MOD4_MASK)
strcat (keybuf, "<Mod4>");
if (event->modifier_state & CLUTTER_MOD5_MASK)
strcat (keybuf, "<Mod5>");
strcat (keybuf, utf8);
}
@ -156,62 +169,83 @@ input_cb (ClutterActor *actor,
gpointer data)
{
ClutterStage *stage = CLUTTER_STAGE (clutter_stage_get_default ());
gchar keybuf[128], *source = (gchar*)data;
ClutterActor *source_actor = clutter_event_get_source (event);
gchar keybuf[128];
switch (event->type)
{
case CLUTTER_KEY_PRESS:
fill_keybuf (keybuf, &event->key);
printf ("[%s] KEY PRESS %s", source, keybuf);
printf ("[%s] KEY PRESS %s",
clutter_actor_get_name (source_actor),
keybuf);
break;
case CLUTTER_KEY_RELEASE:
fill_keybuf (keybuf, &event->key);
printf ("[%s] KEY RELEASE %s", source, keybuf);
printf ("[%s] KEY RELEASE %s",
clutter_actor_get_name (source_actor),
keybuf);
break;
case CLUTTER_MOTION:
g_print ("[%s] MOTION", source);
g_print ("[%s] MOTION",
clutter_actor_get_name (source_actor));
break;
case CLUTTER_ENTER:
g_print ("[%s] ENTER", source);
g_print ("[%s] ENTER (from:%s)",
clutter_actor_get_name (source_actor),
clutter_event_get_related (event) != NULL
? clutter_actor_get_name (clutter_event_get_related (event))
: "<out of stage>");
break;
case CLUTTER_LEAVE:
g_print ("[%s] LEAVE", source);
g_print ("[%s] LEAVE (to:%s)",
clutter_actor_get_name (source_actor),
clutter_event_get_related (event) != NULL
? clutter_actor_get_name (clutter_event_get_related (event))
: "<out of stage>");
break;
case CLUTTER_BUTTON_PRESS:
g_print ("[%s] BUTTON PRESS (click count:%i)",
source, event->button.click_count);
g_print ("[%s] BUTTON PRESS (button:%i, click count:%i)",
clutter_actor_get_name (source_actor),
clutter_event_get_button (event),
clutter_event_get_click_count (event));
break;
case CLUTTER_BUTTON_RELEASE:
g_print ("[%s] BUTTON RELEASE (click count:%i)",
source, event->button.click_count);
g_print ("[%s] BUTTON RELEASE (button:%i, click count:%i)",
clutter_actor_get_name (source_actor),
clutter_event_get_button (event),
clutter_event_get_click_count (event));
if (clutter_event_get_source (event) == CLUTTER_ACTOR (stage))
if (source_actor == CLUTTER_ACTOR (stage))
clutter_stage_set_key_focus (stage, NULL);
else if (clutter_event_get_source (event) == actor
&& clutter_actor_get_parent (actor) == CLUTTER_ACTOR (stage))
else if (source_actor == actor &&
clutter_actor_get_parent (actor) == CLUTTER_ACTOR (stage))
clutter_stage_set_key_focus (stage, actor);
break;
case CLUTTER_SCROLL:
g_print ("[%s] BUTTON SCROLL (click count:%i)",
source, event->button.click_count);
g_print ("[%s] BUTTON SCROLL (direction:%s)",
clutter_actor_get_name (source_actor),
clutter_event_get_scroll_direction (event) == CLUTTER_SCROLL_UP
? "up"
: "down");
break;
case CLUTTER_STAGE_STATE:
g_print ("[%s] STAGE STATE", source);
g_print ("[%s] STAGE STATE", clutter_actor_get_name (source_actor));
break;
case CLUTTER_DESTROY_NOTIFY:
g_print ("[%s] DESTROY NOTIFY", source);
g_print ("[%s] DESTROY NOTIFY", clutter_actor_get_name (source_actor));
break;
case CLUTTER_CLIENT_MESSAGE:
g_print ("[%s] CLIENT MESSAGE", source);
g_print ("[%s] CLIENT MESSAGE", clutter_actor_get_name (source_actor));
break;
case CLUTTER_DELETE:
g_print ("[%s] DELETE", source);
g_print ("[%s] DELETE", clutter_actor_get_name (source_actor));
break;
case CLUTTER_NOTHING:
return FALSE;
}
if (clutter_event_get_source (event) == actor)
if (source_actor == actor)
g_print (" *source*");
g_print ("\n");
@ -234,8 +268,8 @@ test_events_main (int argc, char *argv[])
stage = clutter_stage_get_default ();
clutter_actor_set_name (stage, "Stage");
g_signal_connect (stage, "event", G_CALLBACK (input_cb), "stage");
g_signal_connect (stage, "fullscreen",
G_CALLBACK (stage_state_cb), "fullscreen");
g_signal_connect (stage, "unfullscreen",
@ -244,24 +278,21 @@ test_events_main (int argc, char *argv[])
G_CALLBACK (stage_state_cb), "activate");
g_signal_connect (stage, "deactivate",
G_CALLBACK (stage_state_cb), "deactivate");
g_signal_connect (stage, "captured-event", G_CALLBACK (capture_cb), NULL);
/*g_signal_connect (stage, "captured-event", G_CALLBACK (capture_cb), NULL);*/
focus_box = clutter_rectangle_new_with_color (&ncol);
clutter_actor_set_name (focus_box, "Focus Box");
clutter_container_add (CLUTTER_CONTAINER(stage), focus_box, NULL);
actor = clutter_rectangle_new_with_color (&rcol);
clutter_actor_set_name (actor, "Red Box");
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 100, 100);
clutter_actor_set_reactive (actor, TRUE);
clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "red box");
g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
/* Toggle motion - enter/leave capture */
g_signal_connect (actor, "button-press-event",
G_CALLBACK (red_button_cb), NULL);
@ -269,27 +300,22 @@ test_events_main (int argc, char *argv[])
clutter_stage_set_key_focus (CLUTTER_STAGE (stage), actor);
actor = clutter_rectangle_new_with_color (&gcol);
clutter_actor_set_name (actor, "Green Box");
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 250, 100);
clutter_actor_set_reactive (actor, TRUE);
clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "green box");
g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
g_signal_connect (actor, "captured-event", G_CALLBACK (capture_cb), NULL);
actor = clutter_rectangle_new_with_color (&bcol);
clutter_actor_set_name (actor, "Blue Box");
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_position (actor, 400, 100);
clutter_actor_set_reactive (actor, TRUE);
clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "blue box");
g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
@ -299,20 +325,19 @@ test_events_main (int argc, char *argv[])
/* non reactive */
actor = clutter_rectangle_new_with_color (&ncol);
clutter_actor_set_name (actor, "Black Box");
clutter_actor_set_size (actor, 400, 50);
clutter_actor_set_position (actor, 100, 250);
clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL);
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "blue box");
g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
g_signal_connect (stage, "key-focus-in", G_CALLBACK (key_focus_in_cb),
focus_box);
/* non reactive group, with reactive child */
actor = clutter_rectangle_new_with_color (&ycol);
clutter_actor_set_name (actor, "Yellow Box");
clutter_actor_set_size (actor, 100, 100);
clutter_actor_set_reactive (actor, TRUE);