Compare commits

..

1 Commits

Author SHA1 Message Date
2efd0dfc06 cogl tests: Show the actual output from tests if VERBOSE is set
Writing tests' output to a log file makes them difficult to debug when
the test might be running on an autobuilder or CI system where only
stdout/stderr are recorded. This is particularly troublesome if a
failure is only reproducible on a particular autobuilder.

Recent Automake versions have the convention that detailed output from
failing tests is written to stdout/stderr, not just to log files, when
the VERBOSE environment variable is set; borrow that convention as a
trigger for producing detailed test output.

This was originally cogl!14, but applies equally to mutter's fork of cogl.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1273

Signed-off-by: Simon McVittie <smcv@debian.org>
2020-05-27 15:50:21 +01:00
499 changed files with 24512 additions and 25798 deletions

1
.gitignore vendored
View File

@ -103,4 +103,3 @@ doc/reference/meta.types
.dirstamp
**/tags.*
build/
subprojects/sysprof/

View File

@ -17,7 +17,6 @@ check-commit-log:
build-mutter:
stage: build
needs: []
script:
- meson . build -Dbuildtype=debugoptimized -Db_coverage=true -Degl_device=true -Dwayland_eglstream=true --werror --prefix /usr
- ninja -C build
@ -32,7 +31,6 @@ build-mutter:
build-without-opengl-and-glx:
stage: build
needs: []
script:
- meson . build -Dbuildtype=debugoptimized -Dopengl=false -Dglx=false -Degl_device=true -Dwayland_eglstream=true --werror --prefix /usr
- ninja -C build
@ -46,7 +44,6 @@ build-without-opengl-and-glx:
build-without-native-backend-and-wayland:
stage: build
needs: []
script:
- meson . build -Dbuildtype=debugoptimized -Dnative_backend=false -Dudev=false -Dwayland=false -Dcore_tests=false --werror --prefix /usr
- ninja -C build
@ -62,7 +59,6 @@ test-mutter:
stage: test
dependencies:
- build-mutter
needs: ["build-mutter"]
variables:
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
GSETTINGS_SCHEMA_DIR: "$CI_PROJECT_DIR/build/data"
@ -88,7 +84,6 @@ test-mutter-coverage:
stage: coverage
dependencies:
- test-mutter
needs: ["test-mutter"]
script:
- ninja -C build coverage
- cat build/meson-logs/coverage.txt
@ -105,7 +100,6 @@ can-build-gnome-shell:
stage: test
dependencies:
- build-mutter
needs: ["build-mutter"]
before_script:
- meson install --no-rebuild -C build
script:

View File

@ -17,7 +17,6 @@ RUN dnf -y update && dnf -y upgrade && \
# For running unit tests
dnf install -y xorg-x11-server-Xvfb mesa-dri-drivers dbus dbus-x11 \
'*/xvfb-run' gdm-lib accountsservice-libs gnome-control-center gcovr \
libnma python3-gobject python3-dbusmock \
--setopt=install_weak_deps=False && \
# GNOME Shell

81
NEWS
View File

@ -1,84 +1,3 @@
3.37.90
=======
* Fix using NEAREST filter for backgrounds on scaled monitors [Daniel V.; !1346]
* Screencast fixes and improvements [Jonas; !1361, !1377, !1391]
* Support tap-button-map and tap-drag-lock touchpad settings [Giusy; !1319]
* Fix wine copy & paste [Sebastian; !1369]
* Fix shadows of server-side decorated XWayland windows [Olivier; #1358]
* Replace some loaded terms with more descriptive ones [Olivier; !1396]
* Add API to launch trusted wayland clients [Sergio; #741]
* Skip displays with 'non-desktop' property set [Philipp; !1393]
* Invalidate offscreen effect cache on video memory purge [Daniel V.; !1374]
* Add wl_shm support for 10 bpc and 16 bpc half float formats [Jonas; !804]
* Fixed crashes [Jonas, Erik, Martin; !1365, !1375, #1343]
* Misc. bug fixes and cleanups [Daniel V., Carlos, Olivier, Christian,
Daniel * G., Jonas, Florian; !1370, !1376, !1385, !1352, !1386, !1390,
!1388, !1397, !1398, !1401]
Contributors:
Jonas Ådahl, Sergio Costas, Olivier Fourdan, Carlos Garnacho,
Christian Hergert, Sebastian Keller, Erik Kurzinger, Giusy Margarita,
Daniel García Moreno, Florian Müllner, Daniel van Vugt, Martin Whitaker,
Philipp Zabel
Translators:
Fabio Tomat [fur], Rafael Fontenelle [pt_BR], Jordi Mas [ca],
Yuri Chornoivan [uk], Alexandre Franke [fr]
3.37.3
======
* Support custom keyboard layouts in $XDG_CONFIG_HOME/xkb [Peter; !936]
* Optimize resource scale computation [Jonas D.; !1196, !1276, !1343]
* Allow animating ClutterActor's content property [Georges; !1301]
* Implement backgrounds as ClutterContent [Georges; !1302]
* Add ClutterAlignContraint:pivot-point property [Jonas D.; !737]
* Fix crash on area screenshots with fractional scaling [Sebastian; !1320]
* Do not paint textures of fully obscured windows [Robert; !1326]
* Use a more appropriate combine function on opaque areas [Daniel; !1331]
* Fix remote desktop being broken without screencast session [Olivier; #1307]
* Remove more long-deprecated Clutter APIs [Adam, Georges; !1194, !1332]
* Drive each monitor by its own frame clock [Jonas Å.; !1285]
* Fix copy/paste failures on X11 [Carlos; !1350]
* Mipmap background texture rendering [Daniel; !1347]
* Plugged memory leaks [Sebastian, Jonas D.; !1293, !1281, !1304]
* Misc. bug fixes and cleanups [Jonas Å., Jonas D., Daniel, Corentin, Carlos,
Sebastian, Michel, Robert, Florian; !1288, !1289, !1291, !1296, !1292, !1298,
!1300, !1303, !1290, !1287, !1306, !1305, !1308, !1313, !1250, !1314, !1267,
!1275, !1317, !1270, !1322, !1181, !1282, !1325, !1323, !1240, !1295, !1329,
!1333, !1334, !1336, !1341, #1312, !1345, !1349, !1356, #873, !1310, !1357]
Contributors:
Jonas Dreßler, Michel Dänzer, Olivier Fourdan, Carlos Garnacho,
Peter Hutterer, Adam Jackson, Sebastian Keller, Robert Mader, Florian Müllner,
Georges Basile Stavracas Neto, Corentin Noël, Daniel van Vugt, Jonas Ådahl
3.37.2
======
* Fix move-to-center keybinding with multiple monitors [Sergey; #1073]
* Fix stuck buttons when a virtual device is destroyed [Carlos; !1239]
* Use workarea when centering new windows [Akatsuki; #964]
* Limit mipmap levels when rendering background [Daniel; !1003]
* Broadcast clipboard/primary offers [Carlos; !1253]
* Support primary-selection protocol from wayland-protocols [Carlos; !1255]
* Fix monitor screen cast on X11 [Jonas Å.; !1251]
* Support a "blank" cursor type [Florian; !1244]
* Improve stage view damage tracking [Jonas Å.; !1237]
* Implement touch-mode detecation for the X11 backend [Carlos; !1278]
* Drop external keyboard detection from touch-mode heuristics [Carlos; !1277]
* Optimize actor allocations [Jonas D.; !1247]
* Fixed crashes [Daniel, Carlos, Jonas Å., Jonas D.; !1256, !1258, !1217, !1280]
* Misc. bug fixes and cleanups [Christian, Jonas D., Olivier, Ting-Wei,
Jonas Å., Marco, Corentin, Daniel, Robert, Niels, Florian, Simon; !1231,
!1228, !1238, !1229, !1192, !1236, !1171, !1134, #1126, !1234, !1230, !1210,
!1242, !1243, !1252, !1113, !1232, !1259, !1245, !1265, !1180, !1261, !788,
!1264, !1235, !1218, !1150, !1274, !1271, !1279, !1283, !1272]
Contributors:
Marco Trevisan (Treviño), Akatsuki, Jonas Dreßler, Olivier Fourdan,
Carlos Garnacho, Niels De Graef, Ting-Wei Lan, Robert Mader, Simon McVittie,
Florian Müllner, Corentin Noël, Christian Rauch, Daniel van Vugt,
Sergey Zigachev, Jonas Ådahl
3.37.1
======
* Fix screencasting non-maximized windows [Jonas Å.; !1174]

View File

@ -0,0 +1,147 @@
/* CALLY - The Clutter Accessibility Implementation Library
*
* Copyright (C) 2008 Igalia, S.L.
*
* Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
*
* Based on GailContainer from GAIL
* Copyright 2001, 2002, 2003 Sun Microsystems Inc.
*
* 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:cally-group
* @Title: CallyGroup
* @short_description: Implementation of the ATK interfaces for a #ClutterGroup
* @see_also: #ClutterGroup
*
* #CallyGroup implements the required ATK interfaces of #ClutterGroup
* In particular it exposes each of the Clutter actors contained in the
* group.
*/
#include "clutter-build-config.h"
#include "cally-group.h"
#include "cally-actor-private.h"
static gint cally_group_get_n_children (AtkObject *obj);
static AtkObject* cally_group_ref_child (AtkObject *obj,
gint i);
static void cally_group_real_initialize (AtkObject *obj,
gpointer data);
G_DEFINE_TYPE (CallyGroup, cally_group, CALLY_TYPE_ACTOR)
static void
cally_group_class_init (CallyGroupClass *klass)
{
/* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
class->get_n_children = cally_group_get_n_children;
class->ref_child = cally_group_ref_child;
class->initialize = cally_group_real_initialize;
}
static void
cally_group_init (CallyGroup *group)
{
/* nothing to do yet */
}
/**
* cally_group_new:
* @actor: a #ClutterGroup
*
* Creates a #CallyGroup for @actor
*
* Return value: the newly created #CallyGroup
*
* Since: 1.4
*/
AtkObject *
cally_group_new (ClutterActor *actor)
{
GObject *object = NULL;
AtkObject *accessible = NULL;
g_return_val_if_fail (CLUTTER_IS_GROUP (actor), NULL);
object = g_object_new (CALLY_TYPE_GROUP, NULL);
accessible = ATK_OBJECT (object);
atk_object_initialize (accessible, actor);
return accessible;
}
static gint
cally_group_get_n_children (AtkObject *obj)
{
ClutterActor *actor = NULL;
gint count = 0;
g_return_val_if_fail (CALLY_IS_GROUP (obj), count);
actor = CALLY_GET_CLUTTER_ACTOR (obj);
if (actor == NULL) /* defunct */
return 0;
g_return_val_if_fail (CLUTTER_IS_GROUP(actor), count);
count = clutter_actor_get_n_children (actor);
return count;
}
static AtkObject*
cally_group_ref_child (AtkObject *obj,
gint i)
{
AtkObject *accessible = NULL;
ClutterActor *actor = NULL;
ClutterActor *child = NULL;
g_return_val_if_fail (CALLY_IS_GROUP (obj), NULL);
g_return_val_if_fail ((i >= 0), NULL);
actor = CALLY_GET_CLUTTER_ACTOR (obj);
g_return_val_if_fail (CLUTTER_IS_GROUP(actor), NULL);
child = clutter_actor_get_child_at_index (actor, i);
if (!child)
return NULL;
accessible = clutter_actor_get_accessible (child);
if (accessible != NULL)
g_object_ref (accessible);
return accessible;
}
static void
cally_group_real_initialize (AtkObject *obj,
gpointer data)
{
ATK_OBJECT_CLASS (cally_group_parent_class)->initialize (obj, data);
obj->role = ATK_ROLE_PANEL;
}

View File

@ -0,0 +1,87 @@
/* CALLY - The Clutter Accessibility Implementation Library
*
* Copyright (C) 2008 Igalia, S.L.
*
* Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
*
* Based on GailContainer from GAIL
* Copyright 2001, 2002, 2003 Sun Microsystems Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CALLY_GROUP_H__
#define __CALLY_GROUP_H__
#if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <cally/cally.h> can be included directly."
#endif
#include <cally/cally-actor.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define CALLY_TYPE_GROUP (cally_group_get_type ())
#define CALLY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_GROUP, CallyGroup))
#define CALLY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_GROUP, CallyGroupClass))
#define CALLY_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_GROUP))
#define CALLY_IS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_GROUP))
#define CALLY_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_GROUP, CallyGroupClass))
typedef struct _CallyGroup CallyGroup;
typedef struct _CallyGroupClass CallyGroupClass;
typedef struct _CallyGroupPrivate CallyGroupPrivate;
/**
* CallyGroup:
*
* The <structname>CallyGroup</structname> structure contains only
* private data and should be accessed using the provided API
*
* Since: 1.4
*/
struct _CallyGroup
{
/*< private >*/
CallyActor parent;
CallyGroupPrivate *priv;
};
/**
* CallyGroupClass:
*
* The <structname>CallyGroupClass</structname> structure contains only
* private data
*
* Since: 1.4
*/
struct _CallyGroupClass
{
/*< private >*/
CallyActorClass parent_class;
/* padding for future expansion */
gpointer _padding_dummy[8];
};
CLUTTER_EXPORT
GType cally_group_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
AtkObject* cally_group_new (ClutterActor *actor);
G_END_DECLS
#endif /* __CALLY_GROUP_H__ */

View File

@ -0,0 +1,98 @@
/* CALLY - The Clutter Accessibility Implementation Library
*
* Copyright (C) 2009 Igalia, S.L.
*
* Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:cally-rectangle
* @short_description: Implementation of the ATK interfaces for a #ClutterRectangle
* @see_also: #ClutterRectangle
*
* #CallyRectangle implements the required ATK interfaces of #ClutterRectangle
*
* In particular it sets a proper role for the rectangle.
*/
#include "clutter-build-config.h"
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include "cally-rectangle.h"
#include "cally-actor-private.h"
#include "clutter-color.h"
#include "deprecated/clutter-rectangle.h"
/* AtkObject */
static void cally_rectangle_real_initialize (AtkObject *obj,
gpointer data);
G_DEFINE_TYPE (CallyRectangle, cally_rectangle, CALLY_TYPE_ACTOR)
static void
cally_rectangle_class_init (CallyRectangleClass *klass)
{
/* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
class->initialize = cally_rectangle_real_initialize;
}
static void
cally_rectangle_init (CallyRectangle *rectangle)
{
/* nothing to do yet */
}
/**
* cally_rectangle_new:
* @actor: a #ClutterActor
*
* Creates a new #CallyRectangle for the given @actor. @actor must be
* a #ClutterRectangle.
*
* Return value: the newly created #AtkObject
*
* Since: 1.4
*/
AtkObject*
cally_rectangle_new (ClutterActor *actor)
{
GObject *object = NULL;
AtkObject *accessible = NULL;
g_return_val_if_fail (CLUTTER_IS_RECTANGLE (actor), NULL);
object = g_object_new (CALLY_TYPE_RECTANGLE, NULL);
accessible = ATK_OBJECT (object);
atk_object_initialize (accessible, actor);
return accessible;
}
static void
cally_rectangle_real_initialize (AtkObject *obj,
gpointer data)
{
ATK_OBJECT_CLASS (cally_rectangle_parent_class)->initialize (obj, data);
obj->role = ATK_ROLE_IMAGE;
}

View File

@ -0,0 +1,84 @@
/* CALLY - The Clutter Accessibility Implementation Library
*
* Copyright (C) 2009 Igalia, S.L.
*
* Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CALLY_RECTANGLE_H__
#define __CALLY_RECTANGLE_H__
#if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <cally/cally.h> can be included directly."
#endif
#include <cally/cally-actor.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define CALLY_TYPE_RECTANGLE (cally_rectangle_get_type ())
#define CALLY_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_RECTANGLE, CallyRectangle))
#define CALLY_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_RECTANGLE, CallyRectangleClass))
#define CALLY_IS_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_RECTANGLE))
#define CALLY_IS_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_RECTANGLE))
#define CALLY_RECTANGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_RECTANGLE, CallyRectangleClass))
typedef struct _CallyRectangle CallyRectangle;
typedef struct _CallyRectangleClass CallyRectangleClass;
typedef struct _CallyRectanglePrivate CallyRectanglePrivate;
/**
* CallyRectangle:
*
* The <structname>CallyRectangle</structname> structure contains only private
* data and should be accessed using the provided API
*
* Since: 1.4
*/
struct _CallyRectangle
{
/*< private >*/
CallyActor parent;
CallyRectanglePrivate *priv;
};
/**
* CallyRectangleClass:
*
* The <structname>CallyRectangleClass</structname> structure contains
* only private data
*
* Since: 1.4
*/
struct _CallyRectangleClass
{
/*< private >*/
CallyActorClass parent_class;
/* padding for future expansion */
gpointer _padding_dummy[8];
};
CLUTTER_EXPORT
GType cally_rectangle_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
AtkObject* cally_rectangle_new (ClutterActor *actor);
G_END_DECLS
#endif /* __CALLY_RECTANGLE_H__ */

View File

@ -63,7 +63,7 @@ struct _CallyStagePrivate
G_DEFINE_TYPE_WITH_CODE (CallyStage,
cally_stage,
CALLY_TYPE_ACTOR,
CALLY_TYPE_GROUP,
G_ADD_PRIVATE (CallyStage)
G_IMPLEMENT_INTERFACE (ATK_TYPE_WINDOW,
cally_stage_window_interface_init));

View File

@ -25,7 +25,7 @@
#error "Only <cally/cally.h> can be included directly."
#endif
#include <cally/cally-actor.h>
#include <cally/cally-group.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
@ -52,7 +52,7 @@ typedef struct _CallyStagePrivate CallyStagePrivate;
struct _CallyStage
{
/*< private >*/
CallyActor parent;
CallyGroup parent;
CallyStagePrivate *priv;
};
@ -68,7 +68,7 @@ struct _CallyStage
struct _CallyStageClass
{
/*< private >*/
CallyActorClass parent_class;
CallyGroupClass parent_class;
/* padding for future expansion */
gpointer _padding_dummy[16];

View File

@ -36,8 +36,10 @@
#include "cally.h"
#include "cally-actor.h"
#include "cally-group.h"
#include "cally-stage.h"
#include "cally-text.h"
#include "cally-rectangle.h"
#include "cally-clone.h"
#include "cally-factory.h"
@ -50,8 +52,10 @@
/* factories initialization*/
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_ACTOR, cally_actor, cally_actor_new)
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_GROUP, cally_group, cally_group_new)
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_STAGE, cally_stage, cally_stage_new)
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_TEXT, cally_text, cally_text_new)
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_RECTANGLE, cally_rectangle, cally_rectangle_new)
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_CLONE, cally_clone, cally_clone_new)
/**
@ -69,8 +73,10 @@ cally_accessibility_init (void)
{
/* setting the factories */
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_ACTOR, cally_actor);
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_GROUP, cally_group);
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_STAGE, cally_stage);
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_TEXT, cally_text);
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_RECTANGLE, cally_rectangle);
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_CLONE, cally_clone);
/* Initialize the CallyUtility class */

View File

@ -26,7 +26,9 @@
#include "cally-actor.h"
#include "cally-clone.h"
#include "cally-factory.h"
#include "cally-group.h"
#include "cally-main.h"
#include "cally-rectangle.h"
#include "cally-root.h"
#include "cally-stage.h"
#include "cally-text.h"

View File

@ -615,32 +615,6 @@ clutter_actor_box_scale (ClutterActorBox *box,
box->y2 *= scale;
}
/**
* clutter_actor_box_is_initialized:
* @box: a #ClutterActorBox
*
* Checks if @box has been initialized, a #ClutterActorBox is uninitialized
* if it has a size of -1 at an origin of 0, 0.
*
* Returns: %TRUE if the box is uninitialized, %FALSE if it isn't
*/
gboolean
clutter_actor_box_is_initialized (ClutterActorBox *box)
{
gboolean x1_uninitialized, x2_uninitialized;
gboolean y1_uninitialized, y2_uninitialized;
g_return_val_if_fail (box != NULL, TRUE);
x1_uninitialized = isinf (box->x1);
x2_uninitialized = isinf (box->x2) && signbit (box->x2);
y1_uninitialized = isinf (box->y1);
y2_uninitialized = isinf (box->y2) && signbit (box->y2);
return !x1_uninitialized || !x2_uninitialized ||
!y1_uninitialized || !y2_uninitialized;
}
G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterActorBox, clutter_actor_box,
clutter_actor_box_copy,
clutter_actor_box_free,

View File

@ -110,12 +110,35 @@ typedef ClutterActorTraverseVisitFlags (*ClutterTraverseCallback) (ClutterActor
typedef gboolean (*ClutterForeachCallback) (ClutterActor *actor,
gpointer user_data);
typedef struct _AnchorCoord AnchorCoord;
typedef struct _SizeRequest SizeRequest;
typedef struct _ClutterLayoutInfo ClutterLayoutInfo;
typedef struct _ClutterTransformInfo ClutterTransformInfo;
typedef struct _ClutterAnimationInfo ClutterAnimationInfo;
/* Internal helper struct to represent a point that can be stored in
either direct pixel coordinates or as a fraction of the actor's
size. It is used for the anchor point, scale center and rotation
centers. */
struct _AnchorCoord
{
gboolean is_fractional;
union
{
/* Used when is_fractional == TRUE */
struct
{
gdouble x;
gdouble y;
} fraction;
/* Use when is_fractional == FALSE */
graphene_point3d_t units;
} v;
};
struct _SizeRequest
{
guint age;
@ -160,15 +183,24 @@ ClutterLayoutInfo * _clutter_actor_peek_layout_info
struct _ClutterTransformInfo
{
/* rotation */
/* rotation (angle and center) */
gdouble rx_angle;
AnchorCoord rx_center;
gdouble ry_angle;
AnchorCoord ry_center;
gdouble rz_angle;
AnchorCoord rz_center;
/* scaling */
gdouble scale_x;
gdouble scale_y;
gdouble scale_z;
AnchorCoord scale_center;
/* anchor point */
AnchorCoord anchor;
/* translation */
graphene_point3d_t translation;
@ -281,18 +313,14 @@ void _clutter_actor_detach_clone
void _clutter_actor_queue_redraw_on_clones (ClutterActor *actor);
void _clutter_actor_queue_relayout_on_clones (ClutterActor *actor);
void _clutter_actor_queue_only_relayout (ClutterActor *actor);
void clutter_actor_clear_stage_views_recursive (ClutterActor *actor);
void _clutter_actor_queue_update_resource_scale_recursive (ClutterActor *actor);
float clutter_actor_get_real_resource_scale (ClutterActor *actor);
gboolean _clutter_actor_get_real_resource_scale (ClutterActor *actor,
float *resource_scale);
ClutterPaintNode * clutter_actor_create_texture_paint_node (ClutterActor *self,
CoglTexture *texture);
void clutter_actor_update_stage_views (ClutterActor *self,
int phase);
void clutter_actor_queue_immediate_relayout (ClutterActor *self);
G_END_DECLS
#endif /* __CLUTTER_ACTOR_PRIVATE_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -142,6 +142,11 @@ struct _ClutterActor
* ClutterActorClass:
* @show: signal class handler for #ClutterActor::show; it must chain
* up to the parent's implementation
* @show_all: virtual function for containers and composite actors, to
* determine which children should be shown when calling
* clutter_actor_show_all() on the actor. Defaults to calling
* clutter_actor_show(). This virtual function is deprecated and it
* should not be overridden.
* @hide: signal class handler for #ClutterActor::hide; it must chain
* up to the parent's implementation
* @hide_all: virtual function for containers and composite actors, to
@ -178,10 +183,7 @@ struct _ClutterActor
* implementation.
* @apply_transform: virtual function, used when applying the transformations
* to an actor before painting it or when transforming coordinates or
* the allocation; if the transformation calculated by this function may
* have changed, the cached transformation must be invalidated by calling
* clutter_actor_invalidate_transform(); it must chain up to the parent's
* implementation
* the allocation; it must chain up to the parent's implementation
* @parent_set: signal class handler for the #ClutterActor::parent-set
* @destroy: signal class handler for #ClutterActor::destroy. It must
* chain up to the parent's implementation
@ -224,6 +226,7 @@ struct _ClutterActorClass
/*< public >*/
void (* show) (ClutterActor *self);
void (* show_all) (ClutterActor *self);
void (* hide) (ClutterActor *self);
void (* hide_all) (ClutterActor *self);
void (* realize) (ClutterActor *self);
@ -299,9 +302,6 @@ struct _ClutterActorClass
gboolean (* touch_event) (ClutterActor *self,
ClutterTouchEvent *event);
gboolean (* has_accessible) (ClutterActor *self);
void (* resource_scale_changed) (ClutterActor *self);
float (* calculate_resource_scale) (ClutterActor *self,
int phase);
/*< private >*/
/* padding for future expansion */
@ -419,9 +419,7 @@ CLUTTER_EXPORT
void clutter_actor_allocate (ClutterActor *self,
const ClutterActorBox *box);
CLUTTER_EXPORT
void clutter_actor_allocate_preferred_size (ClutterActor *self,
float x,
float y);
void clutter_actor_allocate_preferred_size (ClutterActor *self);
CLUTTER_EXPORT
void clutter_actor_allocate_available_size (ClutterActor *self,
gfloat x,
@ -456,10 +454,6 @@ void clutter_actor_set_position
gfloat x,
gfloat y);
CLUTTER_EXPORT
gboolean clutter_actor_get_fixed_position (ClutterActor *self,
float *x,
float *y);
CLUTTER_EXPORT
void clutter_actor_get_position (ClutterActor *self,
gfloat *x,
gfloat *y);
@ -599,7 +593,8 @@ gboolean clutter_actor_get_paint_box
ClutterActorBox *box);
CLUTTER_EXPORT
float clutter_actor_get_resource_scale (ClutterActor *self);
gboolean clutter_actor_get_resource_scale (ClutterActor *self,
gfloat *resource_scale);
CLUTTER_EXPORT
gboolean clutter_actor_has_overlaps (ClutterActor *self);
@ -813,11 +808,6 @@ void clutter_actor_set_child_transform
CLUTTER_EXPORT
void clutter_actor_get_child_transform (ClutterActor *self,
ClutterMatrix *transform);
CLUTTER_EXPORT
void clutter_actor_get_transformed_extents (ClutterActor *self,
graphene_rect_t *rect);
CLUTTER_EXPORT
void clutter_actor_get_transformed_position (ClutterActor *self,
gfloat *x,
@ -929,12 +919,6 @@ void clutter_actor_pick_box (ClutterActor *self,
ClutterPickContext *pick_context,
const ClutterActorBox *box);
CLUTTER_EXPORT
GList * clutter_actor_peek_stage_views (ClutterActor *self);
CLUTTER_EXPORT
void clutter_actor_invalidate_transform (ClutterActor *self);
G_END_DECLS
#endif /* __CLUTTER_ACTOR_H__ */

View File

@ -58,7 +58,6 @@ struct _ClutterAlignConstraint
ClutterActor *actor;
ClutterActor *source;
ClutterAlignAxis align_axis;
graphene_point_t pivot;
gfloat factor;
};
@ -73,7 +72,6 @@ enum
PROP_SOURCE,
PROP_ALIGN_AXIS,
PROP_PIVOT_POINT,
PROP_FACTOR,
PROP_LAST
@ -86,11 +84,12 @@ G_DEFINE_TYPE (ClutterAlignConstraint,
CLUTTER_TYPE_CONSTRAINT);
static void
source_queue_relayout (ClutterActor *actor,
ClutterAlignConstraint *align)
source_position_changed (ClutterActor *actor,
GParamSpec *pspec,
ClutterAlignConstraint *align)
{
if (align->actor != NULL)
_clutter_actor_queue_only_relayout (align->actor);
clutter_actor_queue_relayout (align->actor);
}
static void
@ -135,41 +134,35 @@ clutter_align_constraint_update_allocation (ClutterConstraint *constraint,
ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (constraint);
gfloat source_width, source_height;
gfloat actor_width, actor_height;
gfloat offset_x_start, offset_y_start;
gfloat pivot_x, pivot_y;
gfloat source_x, source_y;
if (align->source == NULL)
return;
clutter_actor_box_get_size (allocation, &actor_width, &actor_height);
clutter_actor_get_position (align->source, &source_x, &source_y);
clutter_actor_get_size (align->source, &source_width, &source_height);
pivot_x = align->pivot.x == -1.f
? align->factor
: align->pivot.x;
pivot_y = align->pivot.y == -1.f
? align->factor
: align->pivot.y;
offset_x_start = pivot_x * -actor_width;
offset_y_start = pivot_y * -actor_height;
switch (align->align_axis)
{
case CLUTTER_ALIGN_X_AXIS:
allocation->x1 += offset_x_start + (source_width * align->factor);
allocation->x1 = ((source_width - actor_width) * align->factor)
+ source_x;
allocation->x2 = allocation->x1 + actor_width;
break;
case CLUTTER_ALIGN_Y_AXIS:
allocation->y1 += offset_y_start + (source_height * align->factor);
allocation->y1 = ((source_height - actor_height) * align->factor)
+ source_y;
allocation->y2 = allocation->y1 + actor_height;
break;
case CLUTTER_ALIGN_BOTH:
allocation->x1 += offset_x_start + (source_width * align->factor);
allocation->y1 += offset_y_start + (source_height * align->factor);
allocation->x1 = ((source_width - actor_width) * align->factor)
+ source_x;
allocation->y1 = ((source_height - actor_height) * align->factor)
+ source_y;
allocation->x2 = allocation->x1 + actor_width;
allocation->y2 = allocation->y1 + actor_height;
break;
@ -193,7 +186,7 @@ clutter_align_constraint_dispose (GObject *gobject)
G_CALLBACK (source_destroyed),
align);
g_signal_handlers_disconnect_by_func (align->source,
G_CALLBACK (source_queue_relayout),
G_CALLBACK (source_position_changed),
align);
align->source = NULL;
}
@ -219,10 +212,6 @@ clutter_align_constraint_set_property (GObject *gobject,
clutter_align_constraint_set_align_axis (align, g_value_get_enum (value));
break;
case PROP_PIVOT_POINT:
clutter_align_constraint_set_pivot_point (align, g_value_get_boxed (value));
break;
case PROP_FACTOR:
clutter_align_constraint_set_factor (align, g_value_get_float (value));
break;
@ -251,16 +240,6 @@ clutter_align_constraint_get_property (GObject *gobject,
g_value_set_enum (value, align->align_axis);
break;
case PROP_PIVOT_POINT:
{
graphene_point_t point;
clutter_align_constraint_get_pivot_point (align, &point);
g_value_set_boxed (value, &point);
}
break;
case PROP_FACTOR:
g_value_set_float (value, align->factor);
break;
@ -314,30 +293,6 @@ clutter_align_constraint_class_init (ClutterAlignConstraintClass *klass)
CLUTTER_ALIGN_X_AXIS,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT);
/**
* ClutterAlignConstraint:pivot-point:
*
* The pivot point used by the constraint. The pivot point is the
* point in the constraint actor around which the aligning is applied,
* with (0, 0) being the top left corner of the actor and (1, 1) the
* bottom right corner of the actor.
*
* For example, setting the pivot point to (0.5, 0.5) and using a factor
* of 1 for both axes will align the actors horizontal and vertical
* center point with the bottom right corner of the source actor.
*
* By default, the pivot point is set to (-1, -1), which means it's not
* used and the constrained actor will be aligned to always stay inside
* the source actor.
*/
obj_props[PROP_PIVOT_POINT] =
g_param_spec_boxed ("pivot-point",
P_("Pivot point"),
P_("The pivot point"),
GRAPHENE_TYPE_POINT,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* ClutterAlignConstraint:factor:
*
@ -370,8 +325,6 @@ clutter_align_constraint_init (ClutterAlignConstraint *self)
self->actor = NULL;
self->source = NULL;
self->align_axis = CLUTTER_ALIGN_X_AXIS;
self->pivot.x = -1.f;
self->pivot.y = -1.f;
self->factor = 0.0f;
}
@ -449,15 +402,15 @@ clutter_align_constraint_set_source (ClutterAlignConstraint *align,
G_CALLBACK (source_destroyed),
align);
g_signal_handlers_disconnect_by_func (old_source,
G_CALLBACK (source_queue_relayout),
G_CALLBACK (source_position_changed),
align);
}
align->source = source;
if (align->source != NULL)
{
g_signal_connect (align->source, "queue-relayout",
G_CALLBACK (source_queue_relayout),
g_signal_connect (align->source, "notify::allocation",
G_CALLBACK (source_position_changed),
align);
g_signal_connect (align->source, "destroy",
G_CALLBACK (source_destroyed),
@ -534,60 +487,6 @@ clutter_align_constraint_get_align_axis (ClutterAlignConstraint *align)
return align->align_axis;
}
/**
* clutter_align_constraint_set_pivot_point:
* @align: a #ClutterAlignConstraint
* @pivot_point: A #GraphenePoint
*
* Sets the pivot point used by the constraint, the pivot point is the
* point in the constraint actor around which the aligning is applied,
* with (0, 0) being the top left corner of the actor and (1, 1) the
* bottom right corner of the actor.
*
* If -1 is used, the pivot point is unset and the constrained actor
* will be aligned to always stay inside the source actor.
*/
void
clutter_align_constraint_set_pivot_point (ClutterAlignConstraint *align,
const graphene_point_t *pivot_point)
{
g_return_if_fail (CLUTTER_IS_ALIGN_CONSTRAINT (align));
g_return_if_fail (pivot_point != NULL);
g_return_if_fail (pivot_point->x == -1.f ||
(pivot_point->x >= 0.f && pivot_point->x <= 1.f));
g_return_if_fail (pivot_point->y == -1.f ||
(pivot_point->y >= 0.f && pivot_point->y <= 1.f));
if (graphene_point_equal (&align->pivot, pivot_point))
return;
align->pivot = *pivot_point;
if (align->actor != NULL)
clutter_actor_queue_relayout (align->actor);
g_object_notify_by_pspec (G_OBJECT (align), obj_props[PROP_PIVOT_POINT]);
}
/**
* clutter_align_constraint_get_pivot_point
* @align: a #ClutterAlignConstraint
* @pivot_point: (out caller-allocates): return location for a #GraphenePoint
*
* Gets the pivot point used by the constraint set with
* clutter_align_constraint_set_pivot_point(). If no custom pivot
* point is set, -1 is set.
*/
void
clutter_align_constraint_get_pivot_point (ClutterAlignConstraint *align,
graphene_point_t *pivot_point)
{
g_return_if_fail (CLUTTER_IS_ALIGN_CONSTRAINT (align));
g_return_if_fail (pivot_point != NULL);
*pivot_point = align->pivot;
}
/**
* clutter_align_constraint_set_factor:
* @align: a #ClutterAlignConstraint

View File

@ -67,12 +67,6 @@ void clutter_align_constraint_set_align_axis (ClutterAlignConstrai
CLUTTER_EXPORT
ClutterAlignAxis clutter_align_constraint_get_align_axis (ClutterAlignConstraint *align);
CLUTTER_EXPORT
void clutter_align_constraint_set_pivot_point (ClutterAlignConstraint *align,
const graphene_point_t *pivot_point);
CLUTTER_EXPORT
void clutter_align_constraint_get_pivot_point (ClutterAlignConstraint *align,
graphene_point_t *pivot_point);
CLUTTER_EXPORT
void clutter_align_constraint_set_factor (ClutterAlignConstraint *align,
gfloat factor);
CLUTTER_EXPORT

View File

@ -194,25 +194,3 @@ clutter_animatable_interpolate_value (ClutterAnimatable *animatable,
else
return clutter_interval_compute_value (interval, progress, value);
}
/**
* clutter_animatable_get_actor:
* @animatable: a #ClutterAnimatable
*
* Get animated actor.
*
* Return value: (transfer none): a #ClutterActor
*/
ClutterActor *
clutter_animatable_get_actor (ClutterAnimatable *animatable)
{
ClutterAnimatableInterface *iface;
g_return_val_if_fail (CLUTTER_IS_ANIMATABLE (animatable), NULL);
iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable);
g_return_val_if_fail (iface->get_actor, NULL);
return iface->get_actor (animatable);
}

View File

@ -50,7 +50,6 @@ G_DECLARE_INTERFACE (ClutterAnimatable, clutter_animatable,
* animatable property
* @interpolate_value: virtual function for interpolating the progress
* of a property
* @get_actor: virtual function for getting associated actor
*
* Since: 1.0
*/
@ -73,7 +72,6 @@ struct _ClutterAnimatableInterface
ClutterInterval *interval,
gdouble progress,
GValue *value);
ClutterActor * (* get_actor) (ClutterAnimatable *animatable);
};
CLUTTER_EXPORT
@ -94,9 +92,6 @@ gboolean clutter_animatable_interpolate_value (ClutterAnimatable *animatable,
gdouble progress,
GValue *value);
CLUTTER_EXPORT
ClutterActor * clutter_animatable_get_actor (ClutterAnimatable *animatable);
G_END_DECLS
#endif /* __CLUTTER_ANIMATABLE_H__ */

View File

@ -53,8 +53,6 @@ struct _ClutterBackend
gfloat units_per_em;
gint32 units_serial;
float fallback_resource_scale;
ClutterStageWindow *stage_window;
ClutterInputMethod *input_method;
@ -93,8 +91,6 @@ struct _ClutterBackendClass
ClutterSeat * (* get_default_seat) (ClutterBackend *backend);
gboolean (* is_display_server) (ClutterBackend *backend);
/* signals */
void (* resolution_changed) (ClutterBackend *backend);
void (* font_changed) (ClutterBackend *backend);
@ -138,14 +134,6 @@ void clutter_set_allowed_drivers (const c
CLUTTER_EXPORT
ClutterStageWindow * clutter_backend_get_stage_window (ClutterBackend *backend);
CLUTTER_EXPORT
void clutter_backend_set_fallback_resource_scale (ClutterBackend *backend,
float fallback_resource_scale);
float clutter_backend_get_fallback_resource_scale (ClutterBackend *backend);
gboolean clutter_backend_is_display_server (ClutterBackend *backend);
G_END_DECLS
#endif /* __CLUTTER_BACKEND_PRIVATE_H__ */

View File

@ -58,6 +58,13 @@
#include <cogl/cogl.h>
#ifdef CLUTTER_INPUT_X11
#include "x11/clutter-backend-x11.h"
#endif
#ifdef CLUTTER_WINDOWING_EGL
#include "egl/clutter-backend-eglnative.h"
#endif
#ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
#include <cogl/cogl-wayland-server.h>
#include <wayland-server.h>
@ -415,6 +422,14 @@ clutter_backend_real_get_features (ClutterBackend *backend)
flags |= CLUTTER_FEATURE_STAGE_STATIC;
}
if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE))
{
CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling");
flags |= CLUTTER_FEATURE_SWAP_THROTTLE;
}
else
CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling");
if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
{
CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers complete events");
@ -424,8 +439,23 @@ clutter_backend_real_get_features (ClutterBackend *backend)
return flags;
}
static const char *allowed_backends;
static ClutterBackend * (* custom_backend_func) (void);
static const struct {
const char *name;
ClutterBackend * (* create_backend) (void);
} available_backends[] = {
#ifdef CLUTTER_WINDOWING_X11
{ CLUTTER_WINDOWING_X11, clutter_backend_x11_new },
#endif
#ifdef CLUTTER_WINDOWING_EGL
{ CLUTTER_WINDOWING_EGL, clutter_backend_egl_native_new },
#endif
{ NULL, NULL },
};
void
clutter_set_custom_backend_func (ClutterBackend *(* func) (void))
{
@ -435,13 +465,58 @@ clutter_set_custom_backend_func (ClutterBackend *(* func) (void))
ClutterBackend *
_clutter_create_backend (void)
{
const char *backends_list;
ClutterBackend *retval;
gboolean allow_any;
char **backends;
int i;
g_return_val_if_fail (custom_backend_func, NULL);
if (custom_backend_func)
{
retval = custom_backend_func ();
retval = custom_backend_func ();
if (!retval)
g_error ("Failed to create custom backend.");
if (!retval)
g_error ("Failed to create custom backend.");
return retval;
}
if (allowed_backends == NULL)
allowed_backends = "*";
allow_any = strstr (allowed_backends, "*") != NULL;
backends_list = g_getenv ("CLUTTER_BACKEND");
if (backends_list == NULL)
backends_list = allowed_backends;
backends = g_strsplit (backends_list, ",", 0);
retval = NULL;
for (i = 0; retval == NULL && backends[i] != NULL; i++)
{
const char *backend = backends[i];
gboolean is_any = g_str_equal (backend, "*");
int j;
for (j = 0; available_backends[j].name != NULL; j++)
{
if ((is_any && allow_any) ||
(is_any && strstr (allowed_backends, available_backends[j].name)) ||
g_str_equal (backend, available_backends[j].name))
{
retval = available_backends[j].create_backend ();
if (retval != NULL)
break;
}
}
}
g_strfreev (backends);
if (retval == NULL)
g_error ("No default Clutter backend found.");
return retval;
}
@ -526,8 +601,6 @@ clutter_backend_init (ClutterBackend *self)
self->units_serial = 1;
self->dummy_onscreen = NULL;
self->fallback_resource_scale = 1.f;
}
void
@ -958,22 +1031,3 @@ clutter_backend_get_default_seat (ClutterBackend *backend)
return CLUTTER_BACKEND_GET_CLASS (backend)->get_default_seat (backend);
}
void
clutter_backend_set_fallback_resource_scale (ClutterBackend *backend,
float fallback_resource_scale)
{
backend->fallback_resource_scale = fallback_resource_scale;
}
float
clutter_backend_get_fallback_resource_scale (ClutterBackend *backend)
{
return backend->fallback_resource_scale;
}
gboolean
clutter_backend_is_display_server (ClutterBackend *backend)
{
return CLUTTER_BACKEND_GET_CLASS (backend)->is_display_server (backend);
}

View File

@ -38,14 +38,12 @@
*
* |[<!-- language="C" -->
* // source
* rect[0] = clutter_actor_new ();
* clutter_actor_set_background_color (rect[0], &red_color);
* rect[0] = clutter_rectangle_new_with_color (&red_color);
* clutter_actor_set_position (rect[0], x_pos, y_pos);
* clutter_actor_set_size (rect[0], 100, 100);
*
* // second rectangle
* rect[1] = clutter_actor_new ();
* clutter_actor_set_background_color (rect[1], &green_color);
* rect[1] = clutter_rectangle_new_with_color (&green_color);
* clutter_actor_set_size (rect[1], 100, 100);
* clutter_actor_set_opacity (rect[1], 0);
*
@ -55,8 +53,7 @@
* clutter_actor_add_constraint_with_name (rect[1], "green-y", constraint);
*
* // third rectangle
* rect[2] = clutter_actor_new ();
* clutter_actor_set_background_color (rect[2], &blue_color);
* rect[2] = clutter_rectangle_new_with_color (&blue_color);
* clutter_actor_set_size (rect[2], 100, 100);
* clutter_actor_set_opacity (rect[2], 0);
*
@ -168,9 +165,6 @@ clutter_bind_constraint_update_preferred_size (ClutterConstraint *constraint,
bind->coordinate == CLUTTER_BIND_ALL))
return;
if (clutter_actor_contains (bind->source, actor))
return;
switch (direction)
{
case CLUTTER_ORIENTATION_HORIZONTAL:

View File

@ -167,10 +167,8 @@ get_preferred_size_for_orientation (ClutterBoxLayout *self,
ClutterActor *child;
gint n_children = 0;
gfloat minimum, natural;
float largest_min_size, largest_nat_size;
minimum = natural = 0;
largest_min_size = largest_nat_size = 0;
clutter_actor_iter_init (&iter, container);
while (clutter_actor_iter_next (&iter, &child))
@ -185,22 +183,8 @@ get_preferred_size_for_orientation (ClutterBoxLayout *self,
get_child_size (child, priv->orientation,
for_size, &child_min, &child_nat);
if (priv->is_homogeneous)
{
largest_min_size = MAX (largest_min_size, child_min);
largest_nat_size = MAX (largest_nat_size, child_nat);
}
else
{
minimum += child_min;
natural += child_nat;
}
}
if (priv->is_homogeneous)
{
minimum = largest_min_size * n_children;
natural = largest_nat_size * n_children;
minimum += child_min;
natural += child_nat;
}
if (n_children > 1)
@ -331,8 +315,6 @@ get_preferred_size_for_opposite_orientation (ClutterBoxLayout *self,
}
else
{
size -= (nvis_children - 1) * priv->spacing;
/* Bring children up to size first */
if (isnormal (size) || size == 0)
{

View File

@ -52,8 +52,6 @@
struct _ClutterClonePrivate
{
ClutterActor *clone_source;
float x_scale, y_scale;
gulong source_destroy_id;
};
@ -124,6 +122,8 @@ static void
clutter_clone_apply_transform (ClutterActor *self, CoglMatrix *matrix)
{
ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
ClutterActorBox box, source_box;
gfloat x_scale, y_scale;
/* First chain up and apply all the standard ClutterActor
* transformations... */
@ -134,7 +134,21 @@ clutter_clone_apply_transform (ClutterActor *self, CoglMatrix *matrix)
if (priv->clone_source == NULL)
return;
cogl_matrix_scale (matrix, priv->x_scale, priv->y_scale, 1.f);
/* get our allocated size */
clutter_actor_get_allocation_box (self, &box);
/* and get the allocated size of the source */
clutter_actor_get_allocation_box (priv->clone_source, &source_box);
/* We need to scale what the clone-source actor paints to fill our own
* allocation...
*/
x_scale = clutter_actor_box_get_width (&box)
/ clutter_actor_box_get_width (&source_box);
y_scale = clutter_actor_box_get_height (&box)
/ clutter_actor_box_get_height (&source_box);
cogl_matrix_scale (matrix, x_scale, y_scale, x_scale);
}
static void
@ -230,8 +244,6 @@ clutter_clone_allocate (ClutterActor *self,
{
ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
ClutterActorClass *parent_class;
ClutterActorBox source_box;
float x_scale, y_scale;
/* chain up */
parent_class = CLUTTER_ACTOR_CLASS (clutter_clone_parent_class);
@ -245,31 +257,7 @@ clutter_clone_allocate (ClutterActor *self,
*/
if (clutter_actor_get_parent (priv->clone_source) != NULL &&
!clutter_actor_has_allocation (priv->clone_source))
{
float x = 0.f;
float y = 0.f;
clutter_actor_get_fixed_position (priv->clone_source, &x, &y);
clutter_actor_allocate_preferred_size (priv->clone_source, x, y);
}
clutter_actor_get_allocation_box (priv->clone_source, &source_box);
/* We need to scale what the clone-source actor paints to fill our own
* allocation...
*/
x_scale = clutter_actor_box_get_width (box)
/ clutter_actor_box_get_width (&source_box);
y_scale = clutter_actor_box_get_height (box)
/ clutter_actor_box_get_height (&source_box);
if (!G_APPROX_VALUE (priv->x_scale, x_scale, FLT_EPSILON) ||
!G_APPROX_VALUE (priv->y_scale, y_scale, FLT_EPSILON))
{
priv->x_scale = x_scale;
priv->y_scale = y_scale;
clutter_actor_invalidate_transform (CLUTTER_ACTOR (self));
}
clutter_actor_allocate_preferred_size (priv->clone_source);
#if 0
/* XXX - this is wrong: ClutterClone cannot clone unparented
@ -376,9 +364,6 @@ static void
clutter_clone_init (ClutterClone *self)
{
self->priv = clutter_clone_get_instance_private (self);
self->priv->x_scale = 1.f;
self->priv->y_scale = 1.f;
}
/**

View File

@ -3,7 +3,13 @@
#define __CLUTTER_DEPRECATED_H_INSIDE__
#include "deprecated/clutter-actor.h"
#include "deprecated/clutter-box.h"
#include "deprecated/clutter-container.h"
#include "deprecated/clutter-group.h"
#include "deprecated/clutter-rectangle.h"
#include "deprecated/clutter-stage.h"
#include "deprecated/clutter-timeline.h"
#undef __CLUTTER_DEPRECATED_H_INSIDE__

View File

@ -387,6 +387,44 @@ typedef enum
CLUTTER_MODIFIER_MASK = 0x5c001fff
} ClutterModifierType;
/**
* ClutterKeyboardA11yFlags:
* @CLUTTER_A11Y_KEYBOARD_ENABLED:
* @CLUTTER_A11Y_TIMEOUT_ENABLED:
* @CLUTTER_A11Y_MOUSE_KEYS_ENABLED:
* @CLUTTER_A11Y_SLOW_KEYS_ENABLED:
* @CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS:
* @CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT:
* @CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT:
* @CLUTTER_A11Y_BOUNCE_KEYS_ENABLED:
* @CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT:
* @CLUTTER_A11Y_TOGGLE_KEYS_ENABLED:
* @CLUTTER_A11Y_STICKY_KEYS_ENABLED:
* @CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF:
* @CLUTTER_A11Y_STICKY_KEYS_BEEP:
* @CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP:
*
* Keyboard accessibility features applied to a ClutterInputDevice keyboard.
*
*/
typedef enum
{
CLUTTER_A11Y_KEYBOARD_ENABLED = 1 << 0,
CLUTTER_A11Y_TIMEOUT_ENABLED = 1 << 1,
CLUTTER_A11Y_MOUSE_KEYS_ENABLED = 1 << 2,
CLUTTER_A11Y_SLOW_KEYS_ENABLED = 1 << 3,
CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS = 1 << 4,
CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT = 1 << 5,
CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT = 1 << 6,
CLUTTER_A11Y_BOUNCE_KEYS_ENABLED = 1 << 7,
CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT = 1 << 8,
CLUTTER_A11Y_TOGGLE_KEYS_ENABLED = 1 << 9,
CLUTTER_A11Y_STICKY_KEYS_ENABLED = 1 << 10,
CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF = 1 << 11,
CLUTTER_A11Y_STICKY_KEYS_BEEP = 1 << 12,
CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP = 1 << 13,
} ClutterKeyboardA11yFlags;
/**
* ClutterPointerA11yFlags:
* @CLUTTER_A11Y_POINTER_ENABLED:
@ -819,6 +857,7 @@ typedef enum /*< flags prefix=CLUTTER_EVENT >*/
* @CLUTTER_STAGE_STATE: Stage state change event
* @CLUTTER_DESTROY_NOTIFY: Destroy notification event
* @CLUTTER_CLIENT_MESSAGE: Client message event
* @CLUTTER_DELETE: Stage delete event
* @CLUTTER_TOUCH_BEGIN: A new touch event sequence has started;
* event added in 1.10
* @CLUTTER_TOUCH_UPDATE: A touch event sequence has been updated;
@ -856,6 +895,7 @@ typedef enum /*< prefix=CLUTTER >*/
CLUTTER_STAGE_STATE,
CLUTTER_DESTROY_NOTIFY,
CLUTTER_CLIENT_MESSAGE,
CLUTTER_DELETE,
CLUTTER_TOUCH_BEGIN,
CLUTTER_TOUCH_UPDATE,
CLUTTER_TOUCH_END,
@ -868,8 +908,6 @@ typedef enum /*< prefix=CLUTTER >*/
CLUTTER_PAD_BUTTON_RELEASE,
CLUTTER_PAD_STRIP,
CLUTTER_PAD_RING,
CLUTTER_DEVICE_ADDED,
CLUTTER_DEVICE_REMOVED,
CLUTTER_EVENT_LAST /* helper */
} ClutterEventType;
@ -913,6 +951,7 @@ typedef enum
/**
* ClutterFeatureFlags:
* @CLUTTER_FEATURE_SWAP_THROTTLE: Set if backend throttles buffer swaps.
* @CLUTTER_FEATURE_STAGE_STATIC: Set if stage size if fixed (i.e framebuffer)
* @CLUTTER_FEATURE_STAGE_CURSOR: Set if stage has a graphical cursor.
* @CLUTTER_FEATURE_SHADERS_GLSL: Set if the backend supports GLSL shaders.
@ -927,6 +966,7 @@ typedef enum
*/
typedef enum
{
CLUTTER_FEATURE_SWAP_THROTTLE = (1 << 3),
CLUTTER_FEATURE_STAGE_STATIC = (1 << 6),
CLUTTER_FEATURE_STAGE_CURSOR = (1 << 8),
CLUTTER_FEATURE_SHADERS_GLSL = (1 << 9),
@ -1277,6 +1317,8 @@ typedef enum
* painting the stages
* @CLUTTER_REPAINT_FLAGS_POST_PAINT: Run the repaint function after
* painting the stages
* @CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD: Ensure that a new frame
* is queued after adding the repaint function
*
* Flags to pass to clutter_threads_add_repaint_func_full().
*
@ -1286,6 +1328,7 @@ typedef enum
{
CLUTTER_REPAINT_FLAGS_PRE_PAINT = 1 << 0,
CLUTTER_REPAINT_FLAGS_POST_PAINT = 1 << 1,
CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD = 1 << 2
} ClutterRepaintFlags;
/**
@ -1594,6 +1637,12 @@ typedef enum
CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER,
} ClutterInputDevicePadSource;
typedef enum
{
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE,
CLUTTER_INPUT_DEVICE_MAPPING_RELATIVE,
} ClutterInputDeviceMapping;
typedef enum
{
CLUTTER_INPUT_CONTENT_HINT_COMPLETION = 1 << 0,

View File

@ -407,6 +407,7 @@ clutter_event_get_position (const ClutterEvent *event,
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
@ -414,8 +415,6 @@ clutter_event_get_position (const ClutterEvent *event,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
graphene_point_init (position, 0.f, 0.f);
break;
@ -482,6 +481,7 @@ clutter_event_set_coords (ClutterEvent *event,
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
@ -489,8 +489,6 @@ clutter_event_set_coords (ClutterEvent *event,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
break;
case CLUTTER_ENTER:
@ -1107,6 +1105,7 @@ clutter_event_set_device (ClutterEvent *event,
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_EVENT_LAST:
break;
@ -1162,11 +1161,6 @@ clutter_event_set_device (ClutterEvent *event,
case CLUTTER_PAD_RING:
event->pad_ring.device = device;
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
event->device.device = device;
break;
}
}
@ -1208,6 +1202,7 @@ clutter_event_get_device (const ClutterEvent *event)
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_EVENT_LAST:
break;
@ -1263,11 +1258,6 @@ clutter_event_get_device (const ClutterEvent *event)
case CLUTTER_PAD_RING:
device = event->pad_ring.device;
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
device = event->device.device;
break;
}
return device;
@ -1421,8 +1411,6 @@ clutter_event_copy (const ClutterEvent *event)
sizeof (gdouble) * n_axes);
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
default:
break;
}
@ -1477,9 +1465,6 @@ clutter_event_free (ClutterEvent *event)
case CLUTTER_TOUCH_CANCEL:
g_free (event->touch.axes);
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
break;
default:
break;
@ -1504,17 +1489,40 @@ ClutterEvent *
clutter_event_get (void)
{
ClutterMainContext *context = _clutter_context_get_default ();
ClutterEvent *event;
event = g_async_queue_try_pop (context->events_queue);
if (context->events_queue == NULL)
return NULL;
return event;
if (g_queue_is_empty (context->events_queue))
return NULL;
return g_queue_pop_tail (context->events_queue);
}
static gboolean
spin_context (gpointer data)
/**
* clutter_event_peek:
*
* Returns a pointer to the first event from the event queue but
* does not remove it.
*
* Return value: (transfer none): A #ClutterEvent or NULL if queue empty.
*
* Since: 0.4
*/
ClutterEvent *
clutter_event_peek (void)
{
return G_SOURCE_REMOVE;
ClutterMainContext *context = _clutter_context_get_default ();
g_return_val_if_fail (context != NULL, NULL);
if (context->events_queue == NULL)
return NULL;
if (g_queue_is_empty (context->events_queue))
return NULL;
return g_queue_peek_tail (context->events_queue);
}
void
@ -1522,9 +1530,21 @@ _clutter_event_push (const ClutterEvent *event,
gboolean do_copy)
{
ClutterMainContext *context = _clutter_context_get_default ();
ClutterInputDevice *device;
g_assert (context != NULL);
if (context->events_queue == NULL)
context->events_queue = g_queue_new ();
/* disabled devices don't propagate events */
device = clutter_event_get_device (event);
if (device != NULL)
{
if (!clutter_input_device_get_enabled (device))
return;
}
if (do_copy)
{
ClutterEvent *copy;
@ -1533,8 +1553,7 @@ _clutter_event_push (const ClutterEvent *event,
event = copy;
}
g_async_queue_push (context->events_queue, (gpointer) event);
g_idle_add (spin_context, NULL);
g_queue_push_head (context->events_queue, (gpointer) event);
}
/**
@ -1571,7 +1590,10 @@ clutter_events_pending (void)
g_return_val_if_fail (context != NULL, FALSE);
return g_async_queue_length (context->events_queue) > 0;
if (context->events_queue == NULL)
return FALSE;
return g_queue_is_empty (context->events_queue) == FALSE;
}
/**
@ -1703,6 +1725,7 @@ clutter_event_get_axes (const ClutterEvent *event,
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_ENTER:
case CLUTTER_LEAVE:
case CLUTTER_KEY_PRESS:
@ -1710,8 +1733,6 @@ clutter_event_get_axes (const ClutterEvent *event,
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
break;
case CLUTTER_SCROLL:

View File

@ -121,7 +121,6 @@ typedef struct _ClutterProximityEvent ClutterProximityEvent;
typedef struct _ClutterPadButtonEvent ClutterPadButtonEvent;
typedef struct _ClutterPadStripEvent ClutterPadStripEvent;
typedef struct _ClutterPadRingEvent ClutterPadRingEvent;
typedef struct _ClutterDeviceEvent ClutterDeviceEvent;
/**
* ClutterAnyEvent:
@ -545,17 +544,6 @@ struct _ClutterPadRingEvent
guint32 mode;
};
struct _ClutterDeviceEvent
{
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
ClutterInputDevice *device;
};
/**
* ClutterEvent:
*
@ -582,7 +570,6 @@ union _ClutterEvent
ClutterPadButtonEvent pad_button;
ClutterPadStripEvent pad_strip;
ClutterPadRingEvent pad_ring;
ClutterDeviceEvent device;
};
/**
@ -614,6 +601,8 @@ gboolean clutter_events_pending (void);
CLUTTER_EXPORT
ClutterEvent * clutter_event_get (void);
CLUTTER_EXPORT
ClutterEvent * clutter_event_peek (void);
CLUTTER_EXPORT
void clutter_event_put (const ClutterEvent *event);
CLUTTER_EXPORT

View File

@ -139,11 +139,7 @@ clutter_fixed_layout_allocate (ClutterLayoutManager *manager,
child != NULL;
child = clutter_actor_get_next_sibling (child))
{
float x = 0.f;
float y = 0.f;
clutter_actor_get_fixed_position (child, &x, &y);
clutter_actor_allocate_preferred_size (child, x, y);
clutter_actor_allocate_preferred_size (child);
}
}

View File

@ -1,550 +0,0 @@
/*
* Copyright (C) 2019 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "clutter-build-config.h"
#include "clutter/clutter-frame-clock.h"
#include "clutter/clutter-main.h"
#include "clutter/clutter-private.h"
#include "clutter/clutter-timeline-private.h"
#include "cogl/cogl-trace.h"
enum
{
DESTROY,
N_SIGNALS
};
static guint signals[N_SIGNALS];
/* Wait 2ms after vblank before starting to draw next frame */
#define SYNC_DELAY_US ms2us (2)
typedef struct _ClutterFrameListener
{
const ClutterFrameListenerIface *iface;
gpointer user_data;
} ClutterFrameListener;
typedef struct _ClutterClockSource
{
GSource source;
ClutterFrameClock *frame_clock;
} ClutterClockSource;
typedef enum _ClutterFrameClockState
{
CLUTTER_FRAME_CLOCK_STATE_INIT,
CLUTTER_FRAME_CLOCK_STATE_IDLE,
CLUTTER_FRAME_CLOCK_STATE_SCHEDULED,
CLUTTER_FRAME_CLOCK_STATE_DISPATCHING,
CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED,
} ClutterFrameClockState;
struct _ClutterFrameClock
{
GObject parent;
float refresh_rate;
ClutterFrameListener listener;
GSource *source;
int64_t frame_count;
ClutterFrameClockState state;
int64_t last_presentation_time_us;
gboolean is_next_presentation_time_valid;
int64_t next_presentation_time_us;
gboolean pending_reschedule;
gboolean pending_reschedule_now;
int inhibit_count;
GList *timelines;
};
G_DEFINE_TYPE (ClutterFrameClock, clutter_frame_clock,
G_TYPE_OBJECT)
float
clutter_frame_clock_get_refresh_rate (ClutterFrameClock *frame_clock)
{
return frame_clock->refresh_rate;
}
void
clutter_frame_clock_add_timeline (ClutterFrameClock *frame_clock,
ClutterTimeline *timeline)
{
gboolean is_first;
if (g_list_find (frame_clock->timelines, timeline))
return;
is_first = !frame_clock->timelines;
frame_clock->timelines = g_list_prepend (frame_clock->timelines, timeline);
if (is_first)
clutter_frame_clock_schedule_update (frame_clock);
}
void
clutter_frame_clock_remove_timeline (ClutterFrameClock *frame_clock,
ClutterTimeline *timeline)
{
frame_clock->timelines = g_list_remove (frame_clock->timelines, timeline);
}
static void
advance_timelines (ClutterFrameClock *frame_clock,
int64_t time_us)
{
GList *timelines;
GList *l;
/* 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 frame 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_list_copy (frame_clock->timelines);
g_list_foreach (timelines, (GFunc) g_object_ref, NULL);
for (l = timelines; l; l = l->next)
{
ClutterTimeline *timeline = l->data;
_clutter_timeline_do_tick (timeline, time_us / 1000);
}
g_list_free_full (timelines, g_object_unref);
}
static void
maybe_reschedule_update (ClutterFrameClock *frame_clock)
{
if (frame_clock->pending_reschedule ||
frame_clock->timelines)
{
frame_clock->pending_reschedule = FALSE;
if (frame_clock->pending_reschedule_now)
{
frame_clock->pending_reschedule_now = FALSE;
clutter_frame_clock_schedule_update_now (frame_clock);
}
else
{
clutter_frame_clock_schedule_update (frame_clock);
}
}
}
void
clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
ClutterFrameInfo *frame_info)
{
int64_t presentation_time_us = frame_info->presentation_time;
if (presentation_time_us > frame_clock->last_presentation_time_us ||
((presentation_time_us - frame_clock->last_presentation_time_us) >
INT64_MAX / 2))
{
frame_clock->last_presentation_time_us = presentation_time_us;
}
else
{
g_warning_once ("Bogus presentation time %" G_GINT64_FORMAT
" travelled back in time, using current time.",
presentation_time_us);
frame_clock->last_presentation_time_us = g_get_monotonic_time ();
}
switch (frame_clock->state)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
g_warn_if_reached ();
break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
maybe_reschedule_update (frame_clock);
break;
}
}
static void
calculate_next_update_time_us (ClutterFrameClock *frame_clock,
int64_t *out_next_update_time_us,
int64_t *out_next_presentation_time_us)
{
int64_t last_presentation_time_us;
int64_t now_us;
float refresh_rate;
int64_t refresh_interval_us;
int64_t min_render_time_allowed_us;
int64_t max_render_time_allowed_us;
int64_t last_next_presentation_time_us;
int64_t time_since_last_next_presentation_time_us;
int64_t next_presentation_time_us;
int64_t next_update_time_us;
now_us = g_get_monotonic_time ();
refresh_rate = frame_clock->refresh_rate;
refresh_interval_us = (int64_t) (0.5 + G_USEC_PER_SEC / refresh_rate);
min_render_time_allowed_us = refresh_interval_us / 2;
max_render_time_allowed_us = refresh_interval_us - SYNC_DELAY_US;
if (min_render_time_allowed_us > max_render_time_allowed_us)
min_render_time_allowed_us = max_render_time_allowed_us;
last_presentation_time_us = frame_clock->last_presentation_time_us;
next_presentation_time_us = last_presentation_time_us + refresh_interval_us;
/* Skip ahead to get close to the actual next presentation time. */
if (next_presentation_time_us < now_us)
{
int64_t logical_clock_offset_us;
int64_t logical_clock_phase_us;
int64_t hw_clock_offset_us;
logical_clock_offset_us = now_us % refresh_interval_us;
logical_clock_phase_us = now_us - logical_clock_offset_us;
hw_clock_offset_us = last_presentation_time_us % refresh_interval_us;
next_presentation_time_us = logical_clock_phase_us + hw_clock_offset_us;
}
/* Skip one interval if we got an early presented event. */
last_next_presentation_time_us = frame_clock->next_presentation_time_us;
time_since_last_next_presentation_time_us =
next_presentation_time_us - last_next_presentation_time_us;
if (frame_clock->is_next_presentation_time_valid &&
time_since_last_next_presentation_time_us < (refresh_interval_us / 2))
{
next_presentation_time_us =
frame_clock->next_presentation_time_us + refresh_interval_us;
}
while (next_presentation_time_us < now_us + min_render_time_allowed_us)
next_presentation_time_us += refresh_interval_us;
next_update_time_us = next_presentation_time_us - max_render_time_allowed_us;
*out_next_update_time_us = next_update_time_us;
*out_next_presentation_time_us = next_presentation_time_us;
}
void
clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock)
{
frame_clock->inhibit_count++;
if (frame_clock->inhibit_count == 1)
{
switch (frame_clock->state)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
break;
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
frame_clock->pending_reschedule = TRUE;
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
break;
}
g_source_set_ready_time (frame_clock->source, -1);
}
}
void
clutter_frame_clock_uninhibit (ClutterFrameClock *frame_clock)
{
g_return_if_fail (frame_clock->inhibit_count > 0);
frame_clock->inhibit_count--;
if (frame_clock->inhibit_count == 0)
maybe_reschedule_update (frame_clock);
}
void
clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
{
int64_t next_update_time_us = -1;
if (frame_clock->inhibit_count > 0)
{
frame_clock->pending_reschedule = TRUE;
frame_clock->pending_reschedule_now = TRUE;
return;
}
switch (frame_clock->state)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
next_update_time_us = g_get_monotonic_time ();
break;
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
return;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
frame_clock->pending_reschedule = TRUE;
frame_clock->pending_reschedule_now = TRUE;
return;
}
g_warn_if_fail (next_update_time_us != -1);
g_source_set_ready_time (frame_clock->source, next_update_time_us);
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
frame_clock->is_next_presentation_time_valid = FALSE;
}
void
clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
{
int64_t next_update_time_us = -1;
if (frame_clock->inhibit_count > 0)
{
frame_clock->pending_reschedule = TRUE;
return;
}
switch (frame_clock->state)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
next_update_time_us = g_get_monotonic_time ();
break;
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
calculate_next_update_time_us (frame_clock,
&next_update_time_us,
&frame_clock->next_presentation_time_us);
frame_clock->is_next_presentation_time_valid = TRUE;
break;
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
return;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
frame_clock->pending_reschedule = TRUE;
return;
}
g_warn_if_fail (next_update_time_us != -1);
g_source_set_ready_time (frame_clock->source, next_update_time_us);
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
}
static void
clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
int64_t time_us)
{
int64_t frame_count;
ClutterFrameResult result;
COGL_TRACE_BEGIN_SCOPED (ClutterFrameCLockDispatch, "Frame Clock (dispatch)");
g_source_set_ready_time (frame_clock->source, -1);
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHING;
frame_count = frame_clock->frame_count++;
COGL_TRACE_BEGIN (ClutterFrameClockEvents, "Frame Clock (before frame)");
if (frame_clock->listener.iface->before_frame)
{
frame_clock->listener.iface->before_frame (frame_clock,
frame_count,
frame_clock->listener.user_data);
}
COGL_TRACE_END (ClutterFrameClockEvents);
COGL_TRACE_BEGIN (ClutterFrameClockTimelines, "Frame Clock (timelines)");
advance_timelines (frame_clock, time_us);
COGL_TRACE_END (ClutterFrameClockTimelines);
COGL_TRACE_BEGIN (ClutterFrameClockFrame, "Frame Clock (frame)");
result = frame_clock->listener.iface->frame (frame_clock,
frame_count,
time_us,
frame_clock->listener.user_data);
COGL_TRACE_END (ClutterFrameClockFrame);
switch (frame_clock->state)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
g_warn_if_reached ();
break;
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
switch (result)
{
case CLUTTER_FRAME_RESULT_PENDING_PRESENTED:
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED;
break;
case CLUTTER_FRAME_RESULT_IDLE:
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
maybe_reschedule_update (frame_clock);
break;
}
break;
}
}
static gboolean
frame_clock_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
ClutterClockSource *clock_source = (ClutterClockSource *) source;
ClutterFrameClock *frame_clock = clock_source->frame_clock;
int64_t dispatch_time_us;
dispatch_time_us = g_source_get_time (source);
clutter_frame_clock_dispatch (frame_clock, dispatch_time_us);
return G_SOURCE_CONTINUE;
}
static GSourceFuncs frame_clock_source_funcs = {
NULL,
NULL,
frame_clock_source_dispatch,
NULL
};
static void
init_frame_clock_source (ClutterFrameClock *frame_clock)
{
GSource *source;
ClutterClockSource *clock_source;
g_autofree char *name = NULL;
source = g_source_new (&frame_clock_source_funcs, sizeof (ClutterClockSource));
clock_source = (ClutterClockSource *) source;
name = g_strdup_printf ("Clutter frame clock (%p)", frame_clock);
g_source_set_name (source, name);
g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW);
g_source_set_can_recurse (source, FALSE);
clock_source->frame_clock = frame_clock;
frame_clock->source = source;
g_source_attach (source, NULL);
}
ClutterFrameClock *
clutter_frame_clock_new (float refresh_rate,
const ClutterFrameListenerIface *iface,
gpointer user_data)
{
ClutterFrameClock *frame_clock;
g_assert_cmpfloat (refresh_rate, >, 0.0);
frame_clock = g_object_new (CLUTTER_TYPE_FRAME_CLOCK, NULL);
frame_clock->listener.iface = iface;
frame_clock->listener.user_data = user_data;
init_frame_clock_source (frame_clock);
frame_clock->refresh_rate = refresh_rate;
return frame_clock;
}
void
clutter_frame_clock_destroy (ClutterFrameClock *frame_clock)
{
g_object_run_dispose (G_OBJECT (frame_clock));
g_object_unref (frame_clock);
}
static void
clutter_frame_clock_dispose (GObject *object)
{
ClutterFrameClock *frame_clock = CLUTTER_FRAME_CLOCK (object);
if (frame_clock->source)
{
g_signal_emit (frame_clock, signals[DESTROY], 0);
g_source_destroy (frame_clock->source);
g_clear_pointer (&frame_clock->source, g_source_unref);
}
G_OBJECT_CLASS (clutter_frame_clock_parent_class)->dispose (object);
}
static void
clutter_frame_clock_init (ClutterFrameClock *frame_clock)
{
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_INIT;
}
static void
clutter_frame_clock_class_init (ClutterFrameClockClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = clutter_frame_clock_dispose;
signals[DESTROY] =
g_signal_new (I_("destroy"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE,
0);
}

View File

@ -1,87 +0,0 @@
/*
* Copyright (C) 2019 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CLUTTER_FRAME_CLOCK_H
#define CLUTTER_FRAME_CLOCK_H
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#include <glib.h>
#include <glib-object.h>
#include <stdint.h>
#include "clutter/clutter-types.h"
typedef enum _ClutterFrameResult
{
CLUTTER_FRAME_RESULT_PENDING_PRESENTED,
CLUTTER_FRAME_RESULT_IDLE,
} ClutterFrameResult;
#define CLUTTER_TYPE_FRAME_CLOCK (clutter_frame_clock_get_type ())
CLUTTER_EXPORT
G_DECLARE_FINAL_TYPE (ClutterFrameClock, clutter_frame_clock,
CLUTTER, FRAME_CLOCK,
GObject)
typedef struct _ClutterFrameListenerIface
{
void (* before_frame) (ClutterFrameClock *frame_clock,
int64_t frame_count,
gpointer user_data);
ClutterFrameResult (* frame) (ClutterFrameClock *frame_clock,
int64_t frame_count,
int64_t time_us,
gpointer user_data);
} ClutterFrameListenerIface;
CLUTTER_EXPORT
ClutterFrameClock * clutter_frame_clock_new (float refresh_rate,
const ClutterFrameListenerIface *iface,
gpointer user_data);
CLUTTER_EXPORT
void clutter_frame_clock_destroy (ClutterFrameClock *frame_clock);
CLUTTER_EXPORT
void clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
ClutterFrameInfo *frame_info);
CLUTTER_EXPORT
void clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock);
CLUTTER_EXPORT
void clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock);
CLUTTER_EXPORT
void clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock);
CLUTTER_EXPORT
void clutter_frame_clock_uninhibit (ClutterFrameClock *frame_clock);
void clutter_frame_clock_add_timeline (ClutterFrameClock *frame_clock,
ClutterTimeline *timeline);
void clutter_frame_clock_remove_timeline (ClutterFrameClock *frame_clock,
ClutterTimeline *timeline);
CLUTTER_EXPORT
float clutter_frame_clock_get_refresh_rate (ClutterFrameClock *frame_clock);
#endif /* CLUTTER_FRAME_CLOCK_H */

View File

@ -0,0 +1,96 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CLUTTER_GROUP_H__
#define __CLUTTER_GROUP_H__
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#include <glib-object.h>
#include <clutter/clutter-types.h>
#include <clutter/clutter-actor.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_GROUP (clutter_group_get_type ())
#define CLUTTER_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_GROUP, ClutterGroup))
#define CLUTTER_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_GROUP, ClutterGroupClass))
#define CLUTTER_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_GROUP))
#define CLUTTER_IS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_GROUP))
#define CLUTTER_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_GROUP, ClutterGroupClass))
/* XXX - ClutterGroup is to be considered fully deprecated; the only
* reason we keep this header is because ClutterStage inherits from
* ClutterGroup, and thus we need to have a structure definition for
* the Stage object to expand.
*/
typedef struct _ClutterGroup ClutterGroup;
typedef struct _ClutterGroupClass ClutterGroupClass;
typedef struct _ClutterGroupPrivate ClutterGroupPrivate;
/**
* ClutterGroup:
*
* The #ClutterGroup structure contains only private data
* and should be accessed using the provided API
*
* Since: 0.2
*/
struct _ClutterGroup
{
/*< private >*/
ClutterActor parent_instance;
ClutterGroupPrivate *priv;
};
/**
* ClutterGroupClass:
*
* The #ClutterGroupClass structure contains only private data
*
* Since: 0.2
*/
struct _ClutterGroupClass
{
/*< private >*/
ClutterActorClass parent_class;
/* padding for future expansion */
void (*_clutter_reserved1) (void);
void (*_clutter_reserved2) (void);
void (*_clutter_reserved3) (void);
void (*_clutter_reserved4) (void);
void (*_clutter_reserved5) (void);
void (*_clutter_reserved6) (void);
};
CLUTTER_EXPORT
GType clutter_group_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __CLUTTER_GROUP_H__ */

View File

@ -61,6 +61,15 @@ typedef struct _ClutterScrollInfo
guint last_value_valid : 1;
} ClutterScrollInfo;
typedef struct _ClutterTouchInfo
{
ClutterEventSequence *sequence;
ClutterActor *actor;
float current_x;
float current_y;
} ClutterTouchInfo;
typedef struct _ClutterPtrA11yData
{
int n_btn_pressed;
@ -111,18 +120,25 @@ struct _ClutterInputDevice
/* the current click count */
int click_count;
/* the stage the device is on */
ClutterStage *stage;
/* the current state */
float current_x;
float current_y;
uint32_t current_time;
int current_button_number;
ClutterModifierType current_state;
/* the current touch points targets */
GHashTable *touch_sequence_actors;
/* the current touch points states */
GHashTable *touch_sequences_info;
/* the previous state, used for click count generation */
int previous_x;
int previous_y;
uint32_t previous_time;
int previous_button_number;
ClutterModifierType previous_state;
GArray *axes;
@ -141,6 +157,8 @@ struct _ClutterInputDevice
int n_strips;
int n_mode_groups;
ClutterInputDeviceMapping mapping_mode;
guint has_cursor : 1;
guint is_enabled : 1;
@ -162,11 +180,33 @@ CLUTTER_EXPORT
void clutter_input_device_update_from_tool (ClutterInputDevice *device,
ClutterInputDeviceTool *tool);
CLUTTER_EXPORT
ClutterStage * _clutter_input_device_get_stage (ClutterInputDevice *device);
CLUTTER_EXPORT
void _clutter_input_device_set_stage (ClutterInputDevice *device,
ClutterStage *stage);
CLUTTER_EXPORT
void _clutter_input_device_set_coords (ClutterInputDevice *device,
ClutterEventSequence *sequence,
gfloat x,
gfloat y,
ClutterStage *stage);
CLUTTER_EXPORT
void _clutter_input_device_set_state (ClutterInputDevice *device,
ClutterModifierType state);
CLUTTER_EXPORT
void _clutter_input_device_set_time (ClutterInputDevice *device,
guint32 time_);
void _clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence,
ClutterActor *actor,
gboolean emit_crossing);
CLUTTER_EXPORT
ClutterActor * clutter_input_device_update (ClutterInputDevice *device,
ClutterEventSequence *sequence,
ClutterStage *stage,
gboolean emit_crossing,
ClutterEvent *for_event);
ClutterEventSequence *sequence,
gboolean emit_crossing);
CLUTTER_EXPORT
void _clutter_input_device_add_event_sequence (ClutterInputDevice *device,
ClutterEvent *event);
CLUTTER_EXPORT
void _clutter_input_device_remove_event_sequence (ClutterInputDevice *device,
ClutterEvent *event);
@ -174,12 +214,6 @@ CLUTTER_EXPORT
void _clutter_input_device_set_n_keys (ClutterInputDevice *device,
guint n_keys);
CLUTTER_EXPORT
void clutter_input_device_set_key (ClutterInputDevice *device,
guint index_,
guint keyval,
ClutterModifierType modifiers);
CLUTTER_EXPORT
gboolean _clutter_input_device_translate_axis (ClutterInputDevice *device,
guint index_,
gdouble value,
@ -218,9 +252,4 @@ ClutterInputDeviceTool *
guint64 serial,
ClutterInputDeviceToolType type);
CLUTTER_EXPORT
gboolean clutter_input_device_keycode_to_evdev (ClutterInputDevice *device,
guint hardware_keycode,
guint *evdev_keycode);
#endif /* CLUTTER_INPUT_DEVICE_PRIVATE_H */

View File

@ -61,6 +61,7 @@ enum
PROP_DEVICE_MODE,
PROP_HAS_CURSOR,
PROP_ENABLED,
PROP_N_AXES,
@ -71,10 +72,12 @@ enum
PROP_N_RINGS,
PROP_N_MODE_GROUPS,
PROP_DEVICE_NODE,
PROP_MAPPING_MODE,
PROP_LAST
};
static void _clutter_input_device_free_touch_info (gpointer data);
static void on_cursor_actor_destroy (ClutterActor *actor,
ClutterInputDevice *device);
static void on_cursor_actor_reactive_changed (ClutterActor *actor,
@ -111,7 +114,7 @@ clutter_input_device_dispose (GObject *gobject)
g_clear_pointer (&device->axes, g_array_unref);
g_clear_pointer (&device->keys, g_array_unref);
g_clear_pointer (&device->scroll_info, g_array_unref);
g_clear_pointer (&device->touch_sequence_actors, g_hash_table_unref);
g_clear_pointer (&device->touch_sequences_info, g_hash_table_unref);
if (device->cursor_actor)
{
@ -188,6 +191,10 @@ clutter_input_device_set_property (GObject *gobject,
self->has_cursor = g_value_get_boolean (value);
break;
case PROP_ENABLED:
clutter_input_device_set_enabled (self, g_value_get_boolean (value));
break;
case PROP_VENDOR_ID:
self->vendor_id = g_value_dup_string (value);
break;
@ -212,6 +219,10 @@ clutter_input_device_set_property (GObject *gobject,
self->node_path = g_value_dup_string (value);
break;
case PROP_MAPPING_MODE:
self->mapping_mode = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@ -260,6 +271,10 @@ clutter_input_device_get_property (GObject *gobject,
g_value_set_uint (value, clutter_input_device_get_n_axes (self));
break;
case PROP_ENABLED:
g_value_set_boolean (value, self->is_enabled);
break;
case PROP_VENDOR_ID:
g_value_set_string (value, self->vendor_id);
break;
@ -284,6 +299,10 @@ clutter_input_device_get_property (GObject *gobject,
g_value_set_string (value, self->node_path);
break;
case PROP_MAPPING_MODE:
g_value_set_enum (value, self->mapping_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@ -383,6 +402,25 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass)
FALSE,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
/**
* ClutterInputDevice:enabled:
*
* Whether the device is enabled.
*
* A device with the #ClutterInputDevice:device-mode property set
* to %CLUTTER_INPUT_MODE_MASTER cannot be disabled.
*
* A device must be enabled in order to receive events from it.
*
* Since: 1.6
*/
obj_props[PROP_ENABLED] =
g_param_spec_boolean ("enabled",
P_("Enabled"),
P_("Whether the device is enabled"),
FALSE,
CLUTTER_PARAM_READWRITE);
/**
* ClutterInputDevice:n-axes:
*
@ -468,6 +506,14 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass)
NULL,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
obj_props[PROP_MAPPING_MODE] =
g_param_spec_enum ("mapping-mode",
P_("Device mapping mode"),
P_("Device mapping mode"),
CLUTTER_TYPE_INPUT_DEVICE_MAPPING,
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE,
CLUTTER_PARAM_READWRITE);
gobject_class->dispose = clutter_input_device_dispose;
gobject_class->set_property = clutter_input_device_set_property;
gobject_class->get_property = clutter_input_device_get_property;
@ -482,15 +528,91 @@ clutter_input_device_init (ClutterInputDevice *self)
self->click_count = 0;
self->previous_time = CLUTTER_CURRENT_TIME;
self->previous_x = -1;
self->previous_y = -1;
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;
self->touch_sequence_actors = g_hash_table_new (NULL, NULL);
self->touch_sequences_info =
g_hash_table_new_full (NULL, NULL,
NULL, _clutter_input_device_free_touch_info);
self->inv_touch_sequence_actors = g_hash_table_new (NULL, NULL);
}
static ClutterTouchInfo *
_clutter_input_device_ensure_touch_info (ClutterInputDevice *device,
ClutterEventSequence *sequence,
ClutterStage *stage)
{
ClutterTouchInfo *info;
info = g_hash_table_lookup (device->touch_sequences_info, sequence);
if (info == NULL)
{
info = g_slice_new0 (ClutterTouchInfo);
info->sequence = sequence;
g_hash_table_insert (device->touch_sequences_info, sequence, info);
if (g_hash_table_size (device->touch_sequences_info) == 1)
_clutter_input_device_set_stage (device, stage);
}
return info;
}
/*< private >
* clutter_input_device_set_coords:
* @device: a #ClutterInputDevice
* @sequence: a #ClutterEventSequence or NULL
* @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,
ClutterEventSequence *sequence,
gfloat x,
gfloat y,
ClutterStage *stage)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
if (sequence == NULL)
{
if (device->current_x != x)
device->current_x = x;
if (device->current_y != y)
device->current_y = y;
}
else
{
ClutterTouchInfo *info;
info = _clutter_input_device_ensure_touch_info (device, sequence, stage);
info->current_x = x;
info->current_y = y;
}
}
/*< private >
* 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_get_modifier_state:
* @device: a #ClutterInputDevice
@ -505,17 +627,83 @@ clutter_input_device_init (ClutterInputDevice *self)
ClutterModifierType
clutter_input_device_get_modifier_state (ClutterInputDevice *device)
{
uint32_t modifiers;
ClutterSeat *seat;
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
seat = clutter_input_device_get_seat (device);
return device->current_state;
}
if (!clutter_seat_query_state (seat, device, NULL, NULL, &modifiers))
return 0;
/*< private >
* 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));
return modifiers;
if (device->current_time != time_)
device->current_time = time_;
}
/*< private >
* 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)
{
if (device->stage == stage)
return;
device->stage = stage;
/* we leave the ->cursor_actor in place in order to check
* if we left the stage without crossing it again; this way
* we can emit a leave event on the cursor actor right before
* we emit the leave event on the stage.
*/
}
/*< private >
* clutter_input_device_get_stage:
* @device: a #ClutterInputDevice
*
* Retrieves the stage currently associated with @device.
*
* Return value: The stage currently associated with @device.
*/
ClutterStage *
_clutter_input_device_get_stage (ClutterInputDevice *device)
{
return device->stage;
}
static void
_clutter_input_device_free_touch_info (gpointer data)
{
g_slice_free (ClutterTouchInfo, data);
}
static ClutterActor *
_clutter_input_device_get_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence)
{
ClutterTouchInfo *info;
if (sequence == NULL)
return device->cursor_actor;
info = g_hash_table_lookup (device->touch_sequences_info, sequence);
return info->actor;
}
static void
@ -529,8 +717,12 @@ _clutter_input_device_associate_actor (ClutterInputDevice *device,
{
GList *sequences =
g_hash_table_lookup (device->inv_touch_sequence_actors, actor);
ClutterTouchInfo *info;
ClutterStage *stage = CLUTTER_STAGE (clutter_actor_get_stage (actor));
info = _clutter_input_device_ensure_touch_info (device, sequence, stage);
info->actor = actor;
g_hash_table_insert (device->touch_sequence_actors, sequence, actor);
g_hash_table_insert (device->inv_touch_sequence_actors,
actor, g_list_prepend (sequences, sequence));
}
@ -558,7 +750,13 @@ _clutter_input_device_unassociate_actor (ClutterInputDevice *device,
actor);
for (l = sequences; l != NULL; l = l->next)
g_hash_table_remove (device->touch_sequence_actors, l->data);
{
ClutterTouchInfo *info =
g_hash_table_lookup (device->touch_sequences_info, l->data);
if (info)
info->actor = NULL;
}
g_list_free (sequences);
g_hash_table_remove (device->inv_touch_sequence_actors, actor);
@ -611,31 +809,17 @@ on_cursor_actor_reactive_changed (ClutterActor *actor,
* - set to %TRUE the :has-pointer property of the new pointer
* actor
*/
static void
void
_clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence,
ClutterActor *actor,
gboolean emit_crossing,
graphene_point_t coords,
uint32_t time_)
gboolean emit_crossing)
{
ClutterActor *old_actor = clutter_input_device_get_actor (device, sequence);
ClutterStage *stage = NULL;
ClutterActor *old_actor = _clutter_input_device_get_actor (device, sequence);
if (old_actor == actor)
return;
if (emit_crossing)
{
if (actor)
stage = CLUTTER_STAGE (clutter_actor_get_stage (actor));
else if (old_actor)
stage = CLUTTER_STAGE (clutter_actor_get_stage (old_actor));
if (!stage)
return;
}
if (old_actor != NULL)
{
ClutterActor *tmp_old_actor;
@ -645,12 +829,12 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterEvent *event;
event = clutter_event_new (CLUTTER_LEAVE);
event->crossing.time = time_;
event->crossing.time = device->current_time;
event->crossing.flags = 0;
event->crossing.stage = stage;
event->crossing.stage = device->stage;
event->crossing.source = old_actor;
event->crossing.x = coords.x;
event->crossing.y = coords.y;
event->crossing.x = device->current_x;
event->crossing.y = device->current_y;
event->crossing.related = actor;
event->crossing.sequence = sequence;
clutter_event_set_device (event, device);
@ -666,7 +850,7 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
}
/* processing the event might have destroyed the actor */
tmp_old_actor = clutter_input_device_get_actor (device, sequence);
tmp_old_actor = _clutter_input_device_get_actor (device, sequence);
_clutter_input_device_unassociate_actor (device,
old_actor,
tmp_old_actor == NULL);
@ -682,11 +866,11 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterEvent *event;
event = clutter_event_new (CLUTTER_ENTER);
event->crossing.time = time_;
event->crossing.time = device->current_time;
event->crossing.flags = 0;
event->crossing.stage = stage;
event->crossing.x = coords.x;
event->crossing.y = coords.y;
event->crossing.stage = device->stage;
event->crossing.x = device->current_x;
event->crossing.y = device->current_y;
event->crossing.source = actor;
event->crossing.related = old_actor;
event->crossing.sequence = sequence;
@ -737,6 +921,56 @@ clutter_input_device_get_device_id (ClutterInputDevice *device)
return device->id;
}
/**
* clutter_input_device_set_enabled:
* @device: a #ClutterInputDevice
* @enabled: %TRUE to enable the @device
*
* Enables or disables a #ClutterInputDevice.
*
* Only devices with a #ClutterInputDevice:device-mode property set
* to %CLUTTER_INPUT_MODE_SLAVE or %CLUTTER_INPUT_MODE_FLOATING can
* be disabled.
*
* Since: 1.6
*/
void
clutter_input_device_set_enabled (ClutterInputDevice *device,
gboolean enabled)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
enabled = !!enabled;
if (!enabled && device->device_mode == CLUTTER_INPUT_MODE_MASTER)
return;
if (device->is_enabled == enabled)
return;
device->is_enabled = enabled;
g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_ENABLED]);
}
/**
* clutter_input_device_get_enabled:
* @device: a #ClutterInputDevice
*
* Retrieves whether @device is enabled.
*
* Return value: %TRUE if the device is enabled
*
* Since: 1.6
*/
gboolean
clutter_input_device_get_enabled (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
return device->is_enabled;
}
/**
* clutter_input_device_get_coords:
* @device: a #ClutterInputDevice
@ -758,14 +992,27 @@ clutter_input_device_get_coords (ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *point)
{
ClutterSeat *seat;
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
g_return_val_if_fail (point != NULL, FALSE);
seat = clutter_input_device_get_seat (device);
if (sequence == NULL)
{
point->x = device->current_x;
point->y = device->current_y;
}
else
{
ClutterTouchInfo *info =
g_hash_table_lookup (device->touch_sequences_info, sequence);
return clutter_seat_query_state (seat, device, sequence, point, NULL);
if (info == NULL)
return FALSE;
point->x = info->current_x;
point->y = info->current_y;
}
return TRUE;
}
/*
@ -785,31 +1032,29 @@ clutter_input_device_get_coords (ClutterInputDevice *device,
ClutterActor *
clutter_input_device_update (ClutterInputDevice *device,
ClutterEventSequence *sequence,
ClutterStage *stage,
gboolean emit_crossing,
ClutterEvent *for_event)
gboolean emit_crossing)
{
ClutterStage *stage;
ClutterActor *new_cursor_actor;
ClutterActor *old_cursor_actor;
graphene_point_t point = GRAPHENE_POINT_INIT (-1.0f, -1.0f);
ClutterInputDeviceType device_type = device->device_type;
uint32_t time_;
g_assert (device_type != CLUTTER_KEYBOARD_DEVICE &&
device_type != CLUTTER_PAD_DEVICE);
if (for_event)
stage = device->stage;
if (G_UNLIKELY (stage == NULL))
{
clutter_event_get_coords (for_event, &point.x, &point.y);
time_ = clutter_event_get_time (for_event);
}
else
{
clutter_input_device_get_coords (device, sequence, &point);
time_ = CLUTTER_CURRENT_TIME;
CLUTTER_NOTE (EVENT, "No stage defined for device %d '%s'",
clutter_input_device_get_device_id (device),
clutter_input_device_get_device_name (device));
return NULL;
}
old_cursor_actor = clutter_input_device_get_actor (device, sequence);
clutter_input_device_get_coords (device, sequence, &point);
old_cursor_actor = _clutter_input_device_get_actor (device, sequence);
new_cursor_actor =
_clutter_stage_do_pick (stage, point.x, point.y, CLUTTER_PICK_REACTIVE);
@ -834,34 +1079,47 @@ clutter_input_device_update (ClutterInputDevice *device,
_clutter_input_device_set_actor (device, sequence,
new_cursor_actor,
emit_crossing,
point, time_);
emit_crossing);
return new_cursor_actor;
}
/**
* clutter_input_device_get_actor:
* @device: a #ClutterInputDevice
* @sequence: (allow-none): an optional #ClutterEventSequence
* clutter_input_device_get_pointer_actor:
* @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
*
* Retrieves the #ClutterActor underneath the pointer or touchpoint
* of @device and @sequence.
* 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_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence)
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);
if (sequence == NULL)
return device->cursor_actor;
return device->cursor_actor;
}
return g_hash_table_lookup (device->touch_sequence_actors, sequence);
/**
* clutter_input_device_get_pointer_stage:
* @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
*
* Retrieves the #ClutterStage underneath the pointer of @device
*
* Return value: (transfer none): a pointer to the #ClutterStage or %NULL
*
* Since: 1.2
*/
ClutterStage *
clutter_input_device_get_pointer_stage (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->stage;
}
/**
@ -922,6 +1180,95 @@ clutter_input_device_get_device_mode (ClutterInputDevice *device)
return device->device_mode;
}
/**
* clutter_input_device_update_from_event:
* @device: a #ClutterInputDevice
* @event: a #ClutterEvent
* @update_stage: whether to update the #ClutterStage of the @device
* using the stage of the event
*
* Forcibly updates the state of the @device using a #ClutterEvent
*
* This function should never be used by applications: it is meant
* for integration with embedding toolkits, like clutter-gtk
*
* Embedding toolkits that disable the event collection inside Clutter
* need to use this function to update the state of input devices depending
* on a #ClutterEvent that they are going to submit to the event handling code
* in Clutter though clutter_do_event(). Since the input devices hold the state
* that is going to be used to fill in fields like the #ClutterButtonEvent
* click count, or to emit synthesized events like %CLUTTER_ENTER and
* %CLUTTER_LEAVE, it is necessary for embedding toolkits to also be
* responsible of updating the input device state.
*
* For instance, this might be the code to translate an embedding toolkit
* native motion notification into a Clutter #ClutterMotionEvent and ask
* Clutter to process it:
*
* |[
* ClutterEvent c_event;
*
* translate_native_event_to_clutter (native_event, &c_event);
*
* clutter_do_event (&c_event);
* ]|
*
* Before letting clutter_do_event() process the event, it is necessary to call
* clutter_input_device_update_from_event():
*
* |[
* ClutterEvent c_event;
* ClutterDeviceManager *manager;
* ClutterInputDevice *device;
*
* translate_native_event_to_clutter (native_event, &c_event);
*
* // get the seat
* seat = clutter_backend_get_deafult_seat (clutter_get_default_backend ());
*
* // use the default Core Pointer that Clutter backends register by default
* device = clutter_seat_get_pointer (seat);
*
* // update the state of the input device
* clutter_input_device_update_from_event (device, &c_event, FALSE);
*
* clutter_do_event (&c_event);
* ]|
*
* The @update_stage boolean argument should be used when the input device
* enters and leaves a #ClutterStage; it will use the #ClutterStage field
* of the passed @event to update the stage associated to the input device.
*
* Since: 1.2
*/
void
clutter_input_device_update_from_event (ClutterInputDevice *device,
ClutterEvent *event,
gboolean update_stage)
{
ClutterModifierType event_state;
ClutterEventSequence *sequence;
ClutterStage *event_stage;
gfloat event_x, event_y;
guint32 event_time;
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
g_return_if_fail (event != NULL);
event_state = clutter_event_get_state (event);
event_time = clutter_event_get_time (event);
event_stage = clutter_event_get_stage (event);
sequence = clutter_event_get_event_sequence (event);
clutter_event_get_coords (event, &event_x, &event_y);
_clutter_input_device_set_coords (device, sequence, event_x, event_y, event_stage);
_clutter_input_device_set_state (device, event_state);
_clutter_input_device_set_time (device, event_time);
if (update_stage)
_clutter_input_device_set_stage (device, event_stage);
}
/*< private >
* clutter_input_device_reset_axes:
* @device: a #ClutterInputDevice
@ -1302,6 +1649,31 @@ _clutter_input_device_remove_slave (ClutterInputDevice *master,
master->slaves = g_list_remove (master->slaves, slave);
}
/*< private >
* clutter_input_device_add_sequence:
* @device: a #ClutterInputDevice
* @sequence: a #ClutterEventSequence
*
* Start tracking informations related to a touch point (position,
* actor underneath the touch point).
*/
void
_clutter_input_device_add_event_sequence (ClutterInputDevice *device,
ClutterEvent *event)
{
ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
ClutterStage *stage;
if (sequence == NULL)
return;
stage = clutter_event_get_stage (event);
if (stage == NULL)
return;
_clutter_input_device_ensure_touch_info (device, sequence, stage);
}
/*< private >
* clutter_input_device_remove_sequence:
* @device: a #ClutterInputDevice
@ -1314,25 +1686,25 @@ _clutter_input_device_remove_event_sequence (ClutterInputDevice *device,
ClutterEvent *event)
{
ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
ClutterActor *actor =
g_hash_table_lookup (device->touch_sequence_actors, sequence);
ClutterTouchInfo *info =
g_hash_table_lookup (device->touch_sequences_info, sequence);
if (actor != NULL)
if (info == NULL)
return;
if (info->actor != NULL)
{
GList *sequences =
g_hash_table_lookup (device->inv_touch_sequence_actors, actor);
graphene_point_t point;
g_hash_table_lookup (device->inv_touch_sequence_actors, info->actor);
sequences = g_list_remove (sequences, sequence);
g_hash_table_replace (device->inv_touch_sequence_actors,
actor, sequences);
clutter_event_get_coords (event, &point.x, &point.y);
_clutter_input_device_set_actor (device, sequence, NULL, TRUE, point,
clutter_event_get_time (event));
info->actor, sequences);
_clutter_input_device_set_actor (device, sequence, NULL, TRUE);
}
g_hash_table_remove (device->touch_sequence_actors, sequence);
g_hash_table_remove (device->touch_sequences_info, sequence);
}
/**
@ -2022,6 +2394,43 @@ clutter_input_device_get_device_node (ClutterInputDevice *device)
return device->node_path;
}
ClutterInputDeviceMapping
clutter_input_device_get_mapping_mode (ClutterInputDevice *device)
{
ClutterInputDeviceType device_type;
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE);
device_type = clutter_input_device_get_device_type (device);
g_return_val_if_fail (device_type == CLUTTER_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_ERASER_DEVICE,
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE);
return device->mapping_mode;
}
void
clutter_input_device_set_mapping_mode (ClutterInputDevice *device,
ClutterInputDeviceMapping mapping)
{
ClutterInputDeviceType device_type;
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
device_type = clutter_input_device_get_device_type (device);
g_return_if_fail (device_type == CLUTTER_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_ERASER_DEVICE);
if (device->mapping_mode == mapping)
return;
device->mapping_mode = mapping;
g_object_notify (G_OBJECT (device), "mapping-mode");
}
gboolean
clutter_input_device_is_grouped (ClutterInputDevice *device,
ClutterInputDevice *other_device)

View File

@ -92,14 +92,20 @@ gboolean clutter_input_device_get_coords (ClutterInputDevi
CLUTTER_EXPORT
ClutterModifierType clutter_input_device_get_modifier_state (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterActor * clutter_input_device_get_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence);
ClutterActor * clutter_input_device_get_pointer_actor (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterStage * clutter_input_device_get_pointer_stage (ClutterInputDevice *device);
CLUTTER_EXPORT
const gchar * clutter_input_device_get_device_name (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterInputMode clutter_input_device_get_device_mode (ClutterInputDevice *device);
CLUTTER_EXPORT
gboolean clutter_input_device_get_has_cursor (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_set_enabled (ClutterInputDevice *device,
gboolean enabled);
CLUTTER_EXPORT
gboolean clutter_input_device_get_enabled (ClutterInputDevice *device);
CLUTTER_EXPORT
guint clutter_input_device_get_n_axes (ClutterInputDevice *device);
@ -115,6 +121,11 @@ gboolean clutter_input_device_get_axis_value (ClutterInputDev
CLUTTER_EXPORT
guint clutter_input_device_get_n_keys (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_set_key (ClutterInputDevice *device,
guint index_,
guint keyval,
ClutterModifierType modifiers);
CLUTTER_EXPORT
gboolean clutter_input_device_get_key (ClutterInputDevice *device,
guint index_,
guint *keyval,
@ -125,6 +136,11 @@ ClutterInputDevice * clutter_input_device_get_associated_device (ClutterInput
CLUTTER_EXPORT
GList * clutter_input_device_get_slave_devices (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_update_from_event (ClutterInputDevice *device,
ClutterEvent *event,
gboolean update_stage);
CLUTTER_EXPORT
void clutter_input_device_grab (ClutterInputDevice *device,
ClutterActor *actor);
@ -144,6 +160,11 @@ CLUTTER_EXPORT
ClutterActor * clutter_input_device_sequence_get_grabbed_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence);
CLUTTER_EXPORT
gboolean clutter_input_device_keycode_to_evdev (ClutterInputDevice *device,
guint hardware_keycode,
guint *evdev_keycode);
CLUTTER_EXPORT
const gchar * clutter_input_device_get_vendor_id (ClutterInputDevice *device);
CLUTTER_EXPORT
@ -171,6 +192,12 @@ gint clutter_input_device_get_mode_switch_button_group (Clutt
CLUTTER_EXPORT
const gchar * clutter_input_device_get_device_node (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterInputDeviceMapping clutter_input_device_get_mapping_mode (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_set_mapping_mode (ClutterInputDevice *device,
ClutterInputDeviceMapping mapping);
CLUTTER_EXPORT
gboolean clutter_input_device_is_grouped (ClutterInputDevice *device,
ClutterInputDevice *other_device);

View File

@ -454,7 +454,6 @@ clutter_input_method_forward_key (ClutterInputMethod *im,
ClutterInputMethodPrivate *priv;
ClutterInputDevice *keyboard;
ClutterSeat *seat;
ClutterStageManager *stage_manager;
ClutterStage *stage;
ClutterEvent *event;
@ -465,9 +464,10 @@ clutter_input_method_forward_key (ClutterInputMethod *im,
return;
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
stage_manager = clutter_stage_manager_get_default ();
stage = clutter_stage_manager_get_default_stage (stage_manager);
keyboard = clutter_seat_get_keyboard (seat);
stage = _clutter_input_device_get_stage (keyboard);
if (stage == NULL)
return;
event = clutter_event_new (press ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE);
event->key.time = time_;

View File

@ -32,7 +32,8 @@
* it has been paired, and it controls the allocation of its children.
*
* Any composite or container #ClutterActor subclass can delegate the
* layouting of its children to a #ClutterLayoutManager.
* layouting of its children to a #ClutterLayoutManager. Clutter provides
* a generic container using #ClutterLayoutManager called #ClutterBox.
*
* Clutter provides some simple #ClutterLayoutManager sub-classes, like
* #ClutterFlowLayout and #ClutterBinLayout.
@ -96,7 +97,7 @@
*
* |[
* {
* "type" : "ClutterActor",
* "type" : "ClutterBox",
* "layout-manager" : { "type" : "ClutterGridLayout" },
* "children" : [
* {

View File

@ -61,13 +61,20 @@
#include "clutter-input-pointer-a11y-private.h"
#include "clutter-graphene.h"
#include "clutter-main.h"
#include "clutter-master-clock.h"
#include "clutter-mutter.h"
#include "clutter-paint-node-private.h"
#include "clutter-private.h"
#include "clutter-settings-private.h"
#include "clutter-stage-manager.h"
#include "clutter-stage-private.h"
#include "clutter-backend-private.h"
#ifdef CLUTTER_WINDOWING_X11
#include "x11/clutter-backend-x11.h"
#endif
#ifdef CLUTTER_WINDOWING_EGL
#include "egl/clutter-backend-eglnative.h"
#endif
#include <cogl/cogl.h>
#include <cogl-pango/cogl-pango.h>
@ -76,12 +83,17 @@
/* main context */
static ClutterMainContext *ClutterCntx = NULL;
G_LOCK_DEFINE_STATIC (ClutterCntx);
/* main lock and locking/unlocking functions */
static GMutex clutter_threads_mutex;
/* command line options */
static gboolean clutter_is_initialized = FALSE;
static gboolean clutter_show_fps = FALSE;
static gboolean clutter_fatal_warnings = FALSE;
static gboolean clutter_disable_mipmap_text = FALSE;
static gboolean clutter_use_fuzzy_picking = FALSE;
static gboolean clutter_enable_accessibility = TRUE;
static gboolean clutter_sync_to_vblank = TRUE;
@ -89,6 +101,9 @@ static guint clutter_default_fps = 60;
static ClutterTextDirection clutter_text_direction = CLUTTER_TEXT_DIRECTION_LTR;
static guint clutter_main_loop_level = 0;
static GSList *main_loops = NULL;
/* debug flags */
guint clutter_debug_flags = 0;
guint clutter_paint_debug_flags = 0;
@ -130,6 +145,12 @@ static const GDebugKey clutter_paint_debug_keys[] = {
{ "damage-region", CLUTTER_DEBUG_PAINT_DAMAGE_REGION },
};
static inline void
clutter_threads_init_default (void)
{
g_mutex_init (&clutter_threads_mutex);
}
#define ENVIRONMENT_GROUP "Environment"
#define DEBUG_GROUP "Debug"
@ -175,6 +196,16 @@ clutter_config_read_from_key_file (GKeyFile *keyfile)
else
clutter_disable_mipmap_text = bool_value;
bool_value =
g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP,
"UseFuzzyPicking",
&key_error);
if (key_error != NULL)
g_clear_error (&key_error);
else
clutter_use_fuzzy_picking = bool_value;
bool_value =
g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP,
"EnableAccessibility",
@ -429,15 +460,93 @@ clutter_get_text_direction (void)
return dir;
}
/**
* clutter_main_quit:
*
* Terminates the Clutter mainloop.
*/
void
clutter_main_quit (void)
{
if (main_loops == NULL)
{
g_critical ("Calling clutter_main_quit() without calling clutter_main() "
"is not allowed. If you are using another main loop, use the "
"appropriate API to terminate it.");
return;
}
CLUTTER_NOTE (MISC, "Terminating main loop level %d", clutter_main_loop_level);
g_main_loop_quit (main_loops->data);
}
/**
* clutter_main_level:
*
* Retrieves the depth of the Clutter mainloop.
*
* Return value: The level of the mainloop.
*/
gint
clutter_main_level (void)
{
return clutter_main_loop_level;
}
/**
* clutter_main:
*
* Starts the Clutter mainloop.
*/
void
clutter_main (void)
{
GMainLoop *loop;
if (!_clutter_context_is_initialized ())
{
g_warning ("Called clutter_main() but Clutter wasn't initialised. "
"You must call clutter_init() first.");
return;
}
clutter_main_loop_level++;
CLUTTER_NOTE (MISC, "Entering main loop level %d", clutter_main_loop_level);
loop = g_main_loop_new (NULL, TRUE);
main_loops = g_slist_prepend (main_loops, loop);
if (g_main_loop_is_running (main_loops->data))
{
_clutter_threads_release_lock ();
g_main_loop_run (loop);
_clutter_threads_acquire_lock ();
}
main_loops = g_slist_remove (main_loops, loop);
g_main_loop_unref (loop);
CLUTTER_NOTE (MISC, "Leaving main loop level %d", clutter_main_loop_level);
clutter_main_loop_level--;
}
gboolean
_clutter_threads_dispatch (gpointer data)
{
ClutterThreadsDispatch *dispatch = data;
gboolean ret = FALSE;
_clutter_threads_acquire_lock ();
if (!g_source_is_destroyed (g_main_current_source ()))
ret = dispatch->func (dispatch->data);
_clutter_threads_release_lock ();
return ret;
}
@ -662,6 +771,40 @@ clutter_threads_add_timeout (guint interval,
NULL);
}
void
_clutter_threads_acquire_lock (void)
{
g_mutex_lock (&clutter_threads_mutex);
}
void
_clutter_threads_release_lock (void)
{
/* we need to trylock here, in case the lock hasn't been acquired; on
* various systems trying to release a mutex that hasn't been acquired
* will cause a run-time error. trylock() will either fail, in which
* case we can release the lock we own; or it will succeeds, in which
* case we need to release the lock we just acquired. so we ignore the
* returned value.
*
* see: https://bugs.gnome.org/679439
*/
g_mutex_trylock (&clutter_threads_mutex);
g_mutex_unlock (&clutter_threads_mutex);
}
void
_clutter_context_lock (void)
{
G_LOCK (ClutterCntx);
}
void
_clutter_context_unlock (void)
{
G_UNLOCK (ClutterCntx);
}
gboolean
_clutter_context_is_initialized (void)
{
@ -671,8 +814,8 @@ _clutter_context_is_initialized (void)
return ClutterCntx->is_initialized;
}
ClutterMainContext *
_clutter_context_get_default (void)
static ClutterMainContext *
clutter_context_get_default_unlocked (void)
{
if (G_UNLIKELY (ClutterCntx == NULL))
{
@ -697,14 +840,26 @@ _clutter_context_get_default (void)
ctx->settings = clutter_settings_get_default ();
_clutter_settings_set_backend (ctx->settings, ctx->backend);
ctx->events_queue = g_async_queue_new ();
ctx->last_repaint_id = 1;
}
return ClutterCntx;
}
ClutterMainContext *
_clutter_context_get_default (void)
{
ClutterMainContext *retval;
_clutter_context_lock ();
retval = clutter_context_get_default_unlocked ();
_clutter_context_unlock ();
return retval;
}
static gboolean
clutter_arg_direction_cb (const char *key,
const char *value,
@ -835,6 +990,9 @@ static GOptionEntry clutter_args[] = {
{ "clutter-disable-mipmapped-text", 0, 0, G_OPTION_ARG_NONE,
&clutter_disable_mipmap_text,
N_("Disable mipmapping on text"), NULL },
{ "clutter-use-fuzzy-picking", 0, 0, G_OPTION_ARG_NONE,
&clutter_use_fuzzy_picking,
N_("Use 'fuzzy' picking"), NULL },
#ifdef CLUTTER_ENABLE_DEBUG
{ "clutter-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_debug_cb,
N_("Clutter debugging flags to set"), "FLAGS" },
@ -916,6 +1074,10 @@ pre_parse_hook (GOptionContext *context,
if (env_string)
clutter_disable_mipmap_text = TRUE;
env_string = g_getenv ("CLUTTER_FUZZY_PICK");
if (env_string)
clutter_use_fuzzy_picking = TRUE;
return _clutter_backend_pre_parse (backend, error);
}
@ -1574,11 +1736,6 @@ _clutter_process_event_details (ClutterActor *stage,
ClutterEvent *event)
{
ClutterInputDevice *device = clutter_event_get_device (event);
ClutterMainContext *clutter_context;
ClutterBackend *backend;
clutter_context = _clutter_context_get_default ();
backend = clutter_context->backend;
switch (event->type)
{
@ -1623,9 +1780,7 @@ _clutter_process_event_details (ClutterActor *stage,
emit_crossing_event (event, device);
actor = clutter_input_device_update (device, NULL,
CLUTTER_STAGE (stage), FALSE,
event);
actor = clutter_input_device_update (device, NULL, FALSE);
if (actor != stage)
{
ClutterEvent *crossing;
@ -1666,6 +1821,7 @@ _clutter_process_event_details (ClutterActor *stage,
break;
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_DELETE:
event->any.source = stage;
if (_clutter_event_process_filters (event))
@ -1676,7 +1832,8 @@ _clutter_process_event_details (ClutterActor *stage,
break;
case CLUTTER_MOTION:
if (clutter_backend_is_display_server (backend) &&
#ifdef CLUTTER_WINDOWING_X11
if (!clutter_check_windowing_backend (CLUTTER_WINDOWING_X11) &&
!(event->any.flags & CLUTTER_EVENT_FLAG_SYNTHETIC))
{
if (_clutter_is_input_pointer_a11y_enabled (device))
@ -1687,6 +1844,7 @@ _clutter_process_event_details (ClutterActor *stage,
_clutter_input_pointer_a11y_on_motion_event (device, x, y);
}
}
#endif /* CLUTTER_WINDOWING_X11 */
/* only the stage gets motion events if they are enabled */
if (!clutter_stage_get_motion_events_enabled (CLUTTER_STAGE (stage)) &&
event->any.source == NULL)
@ -1717,7 +1875,8 @@ _clutter_process_event_details (ClutterActor *stage,
G_GNUC_FALLTHROUGH;
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
if (clutter_backend_is_display_server (backend))
#ifdef CLUTTER_WINDOWING_X11
if (!clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
{
if (_clutter_is_input_pointer_a11y_enabled (device) && (event->type != CLUTTER_MOTION))
{
@ -1726,6 +1885,7 @@ _clutter_process_event_details (ClutterActor *stage,
event->type == CLUTTER_BUTTON_PRESS);
}
}
#endif /* CLUTTER_WINDOWING_X11 */
case CLUTTER_SCROLL:
case CLUTTER_TOUCHPAD_PINCH:
case CLUTTER_TOUCHPAD_SWIPE:
@ -1774,9 +1934,21 @@ _clutter_process_event_details (ClutterActor *stage,
break;
}
actor = clutter_input_device_update (device, NULL,
CLUTTER_STAGE (stage),
TRUE, event);
/* 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, NULL, TRUE);
else
{
CLUTTER_NOTE (EVENT, "No device found: picking");
actor = _clutter_stage_do_pick (CLUTTER_STAGE (stage),
x, y,
CLUTTER_PICK_REACTIVE);
}
if (actor == NULL)
break;
@ -1852,6 +2024,9 @@ _clutter_process_event_details (ClutterActor *stage,
sequence =
clutter_event_get_event_sequence (event);
if (event->type == CLUTTER_TOUCH_BEGIN)
_clutter_input_device_add_event_sequence (device, event);
clutter_event_get_coords (event, &x, &y);
/* Only do a pick to find the source if source is not already set
@ -1874,16 +2049,23 @@ _clutter_process_event_details (ClutterActor *stage,
emit_touch_event (event, device);
if (event->type == CLUTTER_TOUCH_END ||
event->type == CLUTTER_TOUCH_CANCEL)
if (event->type == CLUTTER_TOUCH_END)
_clutter_input_device_remove_event_sequence (device, event);
break;
}
actor = clutter_input_device_update (device, sequence,
CLUTTER_STAGE (stage),
TRUE, event);
if (device != NULL)
actor = clutter_input_device_update (device, sequence, TRUE);
else
{
CLUTTER_NOTE (EVENT, "No device found: picking");
actor = _clutter_stage_do_pick (CLUTTER_STAGE (stage),
x, y,
CLUTTER_PICK_REACTIVE);
}
if (actor == NULL)
break;
@ -1902,8 +2084,7 @@ _clutter_process_event_details (ClutterActor *stage,
emit_touch_event (event, device);
if (event->type == CLUTTER_TOUCH_END ||
event->type == CLUTTER_TOUCH_CANCEL)
if (event->type == CLUTTER_TOUCH_END)
_clutter_input_device_remove_event_sequence (device, event);
break;
@ -1935,11 +2116,6 @@ _clutter_process_event_details (ClutterActor *stage,
case CLUTTER_CLIENT_MESSAGE:
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
_clutter_event_process_filters (event);
break;
case CLUTTER_EVENT_LAST:
break;
}
@ -1978,6 +2154,27 @@ _clutter_process_event (ClutterEvent *event)
context->current_event = g_slist_delete_link (context->current_event, context->current_event);
}
/**
* clutter_get_actor_by_gid:
* @id_: a #ClutterActor unique id.
*
* Retrieves the #ClutterActor with @id_.
*
* Return value: (transfer none): the actor with the passed id or %NULL.
* The returned actor does not have its reference count increased.
*
* Since: 0.6
*
* Deprecated: 1.8: The id is deprecated, and this function always returns
* %NULL. Use the proper scene graph API in #ClutterActor to find a child
* of the stage.
*/
ClutterActor *
clutter_get_actor_by_gid (guint32 id_)
{
return NULL;
}
void
clutter_base_init (void)
{
@ -1992,6 +2189,9 @@ clutter_base_init (void)
g_type_init ();
#endif
/* initialise the Big Clutter Lock™ if necessary */
clutter_threads_init_default ();
clutter_graphene_init ();
}
}
@ -2059,7 +2259,9 @@ clutter_threads_remove_repaint_func (guint handle_id)
g_return_if_fail (handle_id > 0);
context = _clutter_context_get_default ();
_clutter_context_lock ();
context = clutter_context_get_default_unlocked ();
l = context->repaint_funcs;
while (l != NULL)
{
@ -2082,6 +2284,8 @@ clutter_threads_remove_repaint_func (guint handle_id)
l = l->next;
}
_clutter_context_unlock ();
}
/**
@ -2180,13 +2384,16 @@ clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags,
g_return_val_if_fail (func != NULL, 0);
context = _clutter_context_get_default ();
_clutter_context_lock ();
context = clutter_context_get_default_unlocked ();
repaint_func = g_slice_new (ClutterRepaintFunction);
repaint_func->id = context->last_repaint_id++;
repaint_func->flags = flags;
/* mask out QUEUE_REDRAW_ON_ADD, since we're going to consume it */
repaint_func->flags = flags & ~CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD;
repaint_func->func = func;
repaint_func->data = data;
repaint_func->notify = notify;
@ -2194,6 +2401,15 @@ clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags,
context->repaint_funcs = g_list_prepend (context->repaint_funcs,
repaint_func);
_clutter_context_unlock ();
if ((flags & CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD) != 0)
{
ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
_clutter_master_clock_ensure_next_iteration (master_clock);
}
return repaint_func->id;
}
@ -2288,16 +2504,39 @@ void
_clutter_clear_events_queue (void)
{
ClutterMainContext *context = _clutter_context_get_default ();
ClutterEvent *event;
/* Lock the queue for as long as it lives */
g_async_queue_lock (context->events_queue);
if (context->events_queue != NULL)
{
g_queue_foreach (context->events_queue,
(GFunc) clutter_event_free,
NULL);
g_queue_free (context->events_queue);
context->events_queue = NULL;
}
}
while ((event = g_async_queue_try_pop_unlocked (context->events_queue)))
clutter_event_free (event);
void
_clutter_clear_events_queue_for_stage (ClutterStage *stage)
{
ClutterMainContext *context = _clutter_context_get_default ();
GList *l, *next;
g_async_queue_unref (context->events_queue);
context->events_queue = NULL;
if (context->events_queue == NULL)
return;
/* Remove any pending events for this stage from the event queue */
for (l = context->events_queue->head; l; l = next)
{
ClutterEvent *event = l->data;
next = l->next;
if (event->any.stage == stage)
{
g_queue_delete_link (context->events_queue, l);
clutter_event_free (event);
}
}
}
ClutterPickMode
@ -2308,6 +2547,58 @@ _clutter_context_get_pick_mode (void)
return context->pick_mode;
}
/**
* clutter_check_windowing_backend:
* @backend_type: the name of the backend to check
*
* Checks the run-time name of the Clutter windowing system backend, using
* the symbolic macros like %CLUTTER_WINDOWING_X11.
*
* This function should be used in conjuction with the compile-time macros
* inside applications and libraries that are using the platform-specific
* windowing system API, to ensure that they are running on the correct
* windowing system; for instance:
*
* |[
* #ifdef CLUTTER_WINDOWING_X11
* if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
* {
* // it is safe to use the clutter_x11_* API
* }
* else
* #endif
* g_error ("Unknown Clutter backend.");
* ]|
*
* Return value: %TRUE if the current Clutter windowing system backend is
* the one checked, and %FALSE otherwise
*
* Since: 1.10
*/
gboolean
clutter_check_windowing_backend (const char *backend_type)
{
ClutterMainContext *context = _clutter_context_get_default ();
g_return_val_if_fail (backend_type != NULL, FALSE);
backend_type = g_intern_string (backend_type);
#ifdef CLUTTER_WINDOWING_EGL
if (backend_type == I_(CLUTTER_WINDOWING_EGL) &&
CLUTTER_IS_BACKEND_EGL_NATIVE (context->backend))
return TRUE;
else
#endif
#ifdef CLUTTER_WINDOWING_X11
if (backend_type == I_(CLUTTER_WINDOWING_X11) &&
CLUTTER_IS_BACKEND_X11 (context->backend))
return TRUE;
else
#endif
return FALSE;
}
/**
* clutter_add_debug_flags: (skip)
*

View File

@ -136,6 +136,14 @@ GOptionGroup * clutter_get_option_group (void);
CLUTTER_EXPORT
GOptionGroup * clutter_get_option_group_without_init (void);
/* Mainloop */
CLUTTER_EXPORT
void clutter_main (void);
CLUTTER_EXPORT
void clutter_main_quit (void);
CLUTTER_EXPORT
gint clutter_main_level (void);
CLUTTER_EXPORT
void clutter_do_event (ClutterEvent *event);
@ -186,6 +194,9 @@ ClutterTextDirection clutter_get_default_text_direction (void);
CLUTTER_EXPORT
guint clutter_get_default_frame_rate (void);
CLUTTER_EXPORT
gboolean clutter_check_windowing_backend (const char *backend_type);
CLUTTER_EXPORT
void clutter_add_debug_flags (ClutterDebugFlag debug_flags,
ClutterDrawDebugFlag draw_flags,

View File

@ -0,0 +1,618 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By: Emmanuele Bassi <ebassi@linux.intel.com>
*
* Copyright (C) 2009 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* SECTION:clutter-master-clock-default
* @short_description: The default master clock for all animations
*
* The #ClutterMasterClockDefault class is the default implementation
* of #ClutterMasterClock.
*/
#include "clutter-build-config.h"
#include <cogl/cogl.h>
#include "clutter-master-clock.h"
#include "clutter-master-clock-default.h"
#include "clutter-debug.h"
#include "clutter-private.h"
#include "clutter-stage-manager-private.h"
#include "clutter-stage-private.h"
#ifdef CLUTTER_ENABLE_DEBUG
#define clutter_warn_if_over_budget(master_clock,start_time,section) G_STMT_START { \
gint64 __delta = g_get_monotonic_time () - start_time; \
gint64 __budget = master_clock->remaining_budget; \
if (__budget > 0 && __delta >= __budget) { \
_clutter_diagnostic_message ("%s took %" G_GINT64_FORMAT " microseconds " \
"more than the remaining budget of %" G_GINT64_FORMAT \
" microseconds", \
section, __delta - __budget, __budget); \
} } G_STMT_END
#else
#define clutter_warn_if_over_budget(master_clock,start_time,section)
#endif
typedef struct _ClutterClockSource ClutterClockSource;
struct _ClutterMasterClockDefault
{
GObject parent_instance;
/* the list of timelines handled by the clock */
GSList *timelines;
/* the current state of the clock, in usecs */
gint64 cur_tick;
#ifdef CLUTTER_ENABLE_DEBUG
gint64 frame_budget;
gint64 remaining_budget;
#endif
/* an idle source, used by the Master Clock to queue
* a redraw on the stage and drive the animations
*/
GSource *source;
guint ensure_next_iteration : 1;
guint paused : 1;
};
struct _ClutterClockSource
{
GSource source;
ClutterMasterClockDefault *master_clock;
};
static gboolean clutter_clock_prepare (GSource *source,
gint *timeout);
static gboolean clutter_clock_check (GSource *source);
static gboolean clutter_clock_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data);
static GSourceFuncs clock_funcs = {
clutter_clock_prepare,
clutter_clock_check,
clutter_clock_dispatch,
NULL
};
static void
clutter_master_clock_iface_init (ClutterMasterClockInterface *iface);
#define clutter_master_clock_default_get_type _clutter_master_clock_default_get_type
G_DEFINE_TYPE_WITH_CODE (ClutterMasterClockDefault,
clutter_master_clock_default,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_MASTER_CLOCK,
clutter_master_clock_iface_init));
/*
* master_clock_is_running:
* @master_clock: a #ClutterMasterClock
*
* Checks if we should currently be advancing timelines or redrawing
* stages.
*
* Return value: %TRUE if the #ClutterMasterClock has at least
* one running timeline
*/
static gboolean
master_clock_is_running (ClutterMasterClockDefault *master_clock)
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
stages = clutter_stage_manager_peek_stages (stage_manager);
if (master_clock->paused)
return FALSE;
if (master_clock->timelines)
return TRUE;
for (l = stages; l; l = l->next)
{
if (clutter_actor_is_mapped (l->data) &&
(_clutter_stage_has_queued_events (l->data) ||
_clutter_stage_needs_update (l->data)))
return TRUE;
}
if (master_clock->ensure_next_iteration)
{
master_clock->ensure_next_iteration = FALSE;
return TRUE;
}
return FALSE;
}
static gint
master_clock_get_swap_wait_time (ClutterMasterClockDefault *master_clock)
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
gint64 min_update_time = -1;
stages = clutter_stage_manager_peek_stages (stage_manager);
for (l = stages; l != NULL; l = l->next)
{
gint64 update_time = _clutter_stage_get_update_time (l->data);
if (min_update_time == -1 ||
(update_time != -1 && update_time < min_update_time))
min_update_time = update_time;
}
if (min_update_time == -1)
{
return -1;
}
else
{
gint64 now = g_source_get_time (master_clock->source);
if (min_update_time < now)
{
return 0;
}
else
{
gint64 delay_us = min_update_time - now;
return (delay_us + 999) / 1000;
}
}
}
static void
master_clock_schedule_stage_updates (ClutterMasterClockDefault *master_clock)
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
stages = clutter_stage_manager_peek_stages (stage_manager);
for (l = stages; l != NULL; l = l->next)
clutter_stage_schedule_update (l->data);
}
static GSList *
master_clock_list_ready_stages (ClutterMasterClockDefault *master_clock)
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
GSList *result;
stages = clutter_stage_manager_peek_stages (stage_manager);
result = NULL;
for (l = stages; l != NULL; l = l->next)
{
gint64 update_time = _clutter_stage_get_update_time (l->data);
/* We carefully avoid to update stages that aren't mapped, because
* they have nothing to render and this could cause a deadlock with
* some of the SwapBuffers implementations (in particular
* GLX_INTEL_swap_event is not emitted if nothing was rendered).
*
* Also, if a stage has a swap-buffers pending we don't want to draw
* to it in case the driver may block the CPU while it waits for the
* next backbuffer to become available.
*
* TODO: We should be able to identify if we are running triple or N
* buffered and in these cases we can still draw if there is 1 swap
* pending so we can hopefully always be ready to swap for the next
* vblank and really match the vsync frequency.
*/
if (clutter_actor_is_mapped (l->data) &&
update_time != -1 && update_time <= master_clock->cur_tick)
result = g_slist_prepend (result, g_object_ref (l->data));
}
return g_slist_reverse (result);
}
static void
master_clock_reschedule_stage_updates (ClutterMasterClockDefault *master_clock,
GSList *stages)
{
const GSList *l;
for (l = stages; l != NULL; l = l->next)
{
/* Clear the old update time */
_clutter_stage_clear_update_time (l->data);
/* And if there is still work to be done, schedule a new one */
if (master_clock->timelines ||
_clutter_stage_has_queued_events (l->data) ||
_clutter_stage_needs_update (l->data))
clutter_stage_schedule_update (l->data);
}
}
/*
* master_clock_next_frame_delay:
* @master_clock: a #ClutterMasterClock
*
* Computes the number of delay before we need to draw the next frame.
*
* Return value: -1 if there is no next frame pending, otherwise the
* number of millseconds before the we need to draw the next frame
*/
static gint
master_clock_next_frame_delay (ClutterMasterClockDefault *master_clock)
{
if (!master_clock_is_running (master_clock))
return -1;
/* If all of the stages are busy waiting for a swap-buffers to complete
* then we wait for one to be ready.. */
return master_clock_get_swap_wait_time (master_clock);
}
static void
master_clock_process_events (ClutterMasterClockDefault *master_clock,
GSList *stages)
{
GSList *l;
#ifdef CLUTTER_ENABLE_DEBUG
gint64 start = g_get_monotonic_time ();
#endif
/* Process queued events */
for (l = stages; l != NULL; l = l->next)
_clutter_stage_process_queued_events (l->data);
#ifdef CLUTTER_ENABLE_DEBUG
if (_clutter_diagnostic_enabled ())
clutter_warn_if_over_budget (master_clock, start, "Event processing");
master_clock->remaining_budget -= (g_get_monotonic_time () - start);
#endif
}
/*
* master_clock_advance_timelines:
* @master_clock: a #ClutterMasterClock
*
* Advances all the timelines held by the master clock. This function
* should be called before calling _clutter_stage_do_update() to
* make sure that all the timelines are advanced and the scene is updated.
*/
static void
master_clock_advance_timelines (ClutterMasterClockDefault *master_clock)
{
GSList *timelines, *l;
#ifdef CLUTTER_ENABLE_DEBUG
gint64 start = g_get_monotonic_time ();
#endif
/* 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 / 1000);
g_slist_free_full (timelines, g_object_unref);
#ifdef CLUTTER_ENABLE_DEBUG
if (_clutter_diagnostic_enabled ())
clutter_warn_if_over_budget (master_clock, start, "Animations");
master_clock->remaining_budget -= (g_get_monotonic_time () - start);
#endif
}
static gboolean
master_clock_update_stages (ClutterMasterClockDefault *master_clock,
GSList *stages)
{
gboolean stages_updated = FALSE;
GSList *l;
#ifdef CLUTTER_ENABLE_DEBUG
gint64 start = g_get_monotonic_time ();
#endif
_clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_PRE_PAINT);
/* Update any stage that needs redraw/relayout after the clock
* is advanced.
*/
for (l = stages; l != NULL; l = l->next)
stages_updated |= _clutter_stage_do_update (l->data);
_clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_POST_PAINT);
#ifdef CLUTTER_ENABLE_DEBUG
if (_clutter_diagnostic_enabled ())
clutter_warn_if_over_budget (master_clock, start, "Updating the stage");
master_clock->remaining_budget -= (g_get_monotonic_time () - start);
#endif
return stages_updated;
}
/*
* clutter_clock_source_new:
* @master_clock: a #ClutterMasterClock for the source
*
* The #ClutterClockSource is an idle GSource that will queue a redraw
* if @master_clock has at least a running #ClutterTimeline. The redraw
* will cause @master_clock to advance all timelines, thus advancing all
* animations as well.
*
* Return value: the newly created #GSource
*/
static GSource *
clutter_clock_source_new (ClutterMasterClockDefault *master_clock)
{
GSource *source = g_source_new (&clock_funcs, sizeof (ClutterClockSource));
ClutterClockSource *clock_source = (ClutterClockSource *) source;
g_source_set_name (source, "Clutter master clock");
g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW);
g_source_set_can_recurse (source, FALSE);
clock_source->master_clock = master_clock;
return source;
}
static gboolean
clutter_clock_prepare (GSource *source,
gint *timeout)
{
ClutterClockSource *clock_source = (ClutterClockSource *) source;
ClutterMasterClockDefault *master_clock = clock_source->master_clock;
int delay;
_clutter_threads_acquire_lock ();
if (G_UNLIKELY (clutter_paint_debug_flags &
CLUTTER_DEBUG_CONTINUOUS_REDRAW))
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
stages = clutter_stage_manager_peek_stages (stage_manager);
/* Queue a full redraw on all of the stages */
for (l = stages; l != NULL; l = l->next)
clutter_actor_queue_redraw (l->data);
}
delay = master_clock_next_frame_delay (master_clock);
_clutter_threads_release_lock ();
*timeout = delay;
return delay == 0;
}
static gboolean
clutter_clock_check (GSource *source)
{
ClutterClockSource *clock_source = (ClutterClockSource *) source;
ClutterMasterClockDefault *master_clock = clock_source->master_clock;
int delay;
_clutter_threads_acquire_lock ();
delay = master_clock_next_frame_delay (master_clock);
_clutter_threads_release_lock ();
return delay == 0;
}
static gboolean
clutter_clock_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
ClutterClockSource *clock_source = (ClutterClockSource *) source;
ClutterMasterClockDefault *master_clock = clock_source->master_clock;
GSList *stages;
CLUTTER_NOTE (SCHEDULER, "Master clock [tick]");
_clutter_threads_acquire_lock ();
COGL_TRACE_BEGIN (ClutterMasterClockTick, "Master Clock (tick)");
/* Get the time to use for this frame */
master_clock->cur_tick = g_source_get_time (source);
#ifdef CLUTTER_ENABLE_DEBUG
master_clock->remaining_budget = master_clock->frame_budget;
#endif
/* We need to protect ourselves against stages being destroyed during
* event handling - master_clock_list_ready_stages() returns a
* list of referenced that we'll unref afterwards.
*/
stages = master_clock_list_ready_stages (master_clock);
/* Each frame is split into three separate phases: */
/* 1. process all the events; each stage goes through its events queue
* and processes each event according to its type, then emits the
* various signals that are associated with the event
*/
master_clock_process_events (master_clock, stages);
/* 2. advance the timelines */
master_clock_advance_timelines (master_clock);
/* 3. relayout and redraw the stages */
master_clock_update_stages (master_clock, stages);
master_clock_reschedule_stage_updates (master_clock, stages);
g_slist_free_full (stages, g_object_unref);
COGL_TRACE_END (ClutterMasterClockTick);
_clutter_threads_release_lock ();
return TRUE;
}
static void
clutter_master_clock_default_finalize (GObject *gobject)
{
ClutterMasterClockDefault *master_clock = CLUTTER_MASTER_CLOCK_DEFAULT (gobject);
g_slist_free (master_clock->timelines);
G_OBJECT_CLASS (clutter_master_clock_default_parent_class)->finalize (gobject);
}
static void
clutter_master_clock_default_class_init (ClutterMasterClockDefaultClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = clutter_master_clock_default_finalize;
}
static void
clutter_master_clock_default_init (ClutterMasterClockDefault *self)
{
GSource *source;
source = clutter_clock_source_new (self);
self->source = source;
self->ensure_next_iteration = FALSE;
self->paused = FALSE;
#ifdef CLUTTER_ENABLE_DEBUG
self->frame_budget = G_USEC_PER_SEC / 60;
#endif
g_source_attach (source, NULL);
}
static void
clutter_master_clock_default_add_timeline (ClutterMasterClock *clock,
ClutterTimeline *timeline)
{
ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock;
gboolean is_first;
if (g_slist_find (master_clock->timelines, timeline))
return;
is_first = master_clock->timelines == NULL;
master_clock->timelines = g_slist_prepend (master_clock->timelines,
timeline);
if (is_first)
{
master_clock_schedule_stage_updates (master_clock);
_clutter_master_clock_start_running (clock);
}
}
static void
clutter_master_clock_default_remove_timeline (ClutterMasterClock *clock,
ClutterTimeline *timeline)
{
ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock;
master_clock->timelines = g_slist_remove (master_clock->timelines,
timeline);
}
static void
clutter_master_clock_default_start_running (ClutterMasterClock *master_clock)
{
/* If called from a different thread, we need to wake up the
* main loop to start running the timelines
*/
g_main_context_wakeup (NULL);
}
static void
clutter_master_clock_default_ensure_next_iteration (ClutterMasterClock *clock)
{
ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock;
master_clock->ensure_next_iteration = TRUE;
}
static void
clutter_master_clock_default_set_paused (ClutterMasterClock *clock,
gboolean paused)
{
ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock;
if (paused && !master_clock->paused)
{
g_clear_pointer (&master_clock->source, g_source_destroy);
}
else if (!paused && master_clock->paused)
{
master_clock->source = clutter_clock_source_new (master_clock);
g_source_attach (master_clock->source, NULL);
}
master_clock->paused = !!paused;
}
static void
clutter_master_clock_iface_init (ClutterMasterClockInterface *iface)
{
iface->add_timeline = clutter_master_clock_default_add_timeline;
iface->remove_timeline = clutter_master_clock_default_remove_timeline;
iface->start_running = clutter_master_clock_default_start_running;
iface->ensure_next_iteration = clutter_master_clock_default_ensure_next_iteration;
iface->set_paused = clutter_master_clock_default_set_paused;
}

View File

@ -0,0 +1,48 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By: Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com>
*
* Copyright (C) 2015 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CLUTTER_MASTER_CLOCK_DEFAULT_H__
#define __CLUTTER_MASTER_CLOCK_DEFAULT_H__
#include <clutter/clutter-timeline.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_MASTER_CLOCK_DEFAULT (_clutter_master_clock_default_get_type ())
#define CLUTTER_MASTER_CLOCK_DEFAULT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MASTER_CLOCK_DEFAULT, ClutterMasterClockDefault))
#define CLUTTER_IS_MASTER_CLOCK_DEFAULT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MASTER_CLOCK_DEFAULT))
#define CLUTTER_MASTER_CLOCK_DEFAULT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_MASTER_CLOCK_DEFAULT, ClutterMasterClockDefaultClass))
typedef struct _ClutterMasterClockDefault ClutterMasterClockDefault;
typedef struct _ClutterMasterClockDefaultClass ClutterMasterClockDefaultClass;
struct _ClutterMasterClockDefaultClass
{
GObjectClass parent_class;
};
GType _clutter_master_clock_default_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __CLUTTER_MASTER_CLOCK_DEFAULT_H__ */

View File

@ -0,0 +1,132 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By: Emmanuele Bassi <ebassi@linux.intel.com>
*
* Copyright (C) 2009 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* SECTION:clutter-master-clock
* @short_description: The master clock for all animations
*
* The #ClutterMasterClock class is responsible for advancing all
* #ClutterTimelines when a stage is being redrawn. The master clock
* makes sure that the scenegraph is always integrally updated before
* painting it.
*/
#include "clutter-build-config.h"
#include "clutter-master-clock.h"
#include "clutter-master-clock-default.h"
#include "clutter-private.h"
G_DEFINE_INTERFACE (ClutterMasterClock, clutter_master_clock, G_TYPE_OBJECT)
static void
clutter_master_clock_default_init (ClutterMasterClockInterface *iface)
{
}
ClutterMasterClock *
_clutter_master_clock_get_default (void)
{
ClutterMainContext *context = _clutter_context_get_default ();
if (G_UNLIKELY (context->master_clock == NULL))
context->master_clock = g_object_new (CLUTTER_TYPE_MASTER_CLOCK_DEFAULT, NULL);
return context->master_clock;
}
/*
* _clutter_master_clock_add_timeline:
* @master_clock: a #ClutterMasterClock
* @timeline: a #ClutterTimeline
*
* Adds @timeline to the list of playing timelines held by the master
* clock.
*/
void
_clutter_master_clock_add_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *timeline)
{
g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->add_timeline (master_clock,
timeline);
}
/*
* _clutter_master_clock_remove_timeline:
* @master_clock: a #ClutterMasterClock
* @timeline: a #ClutterTimeline
*
* Removes @timeline from the list of playing timelines held by the
* master clock.
*/
void
_clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *timeline)
{
g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->remove_timeline (master_clock,
timeline);
}
/*
* _clutter_master_clock_start_running:
* @master_clock: a #ClutterMasterClock
*
* Called when we have events or redraws to process; if the clock
* is stopped, does the processing necessary to wake it up again.
*/
void
_clutter_master_clock_start_running (ClutterMasterClock *master_clock)
{
g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->start_running (master_clock);
}
/**
* _clutter_master_clock_ensure_next_iteration:
* @master_clock: a #ClutterMasterClock
*
* Ensures that the master clock will run at least one iteration
*/
void
_clutter_master_clock_ensure_next_iteration (ClutterMasterClock *master_clock)
{
g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->ensure_next_iteration (master_clock);
}
void
_clutter_master_clock_set_paused (ClutterMasterClock *master_clock,
gboolean paused)
{
g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->set_paused (master_clock,
!!paused);
}

View File

@ -0,0 +1,69 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By: Emmanuele Bassi <ebassi@linux.intel.com>
*
* Copyright (C) 2009 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CLUTTER_MASTER_CLOCK_H__
#define __CLUTTER_MASTER_CLOCK_H__
#include <clutter/clutter-timeline.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_MASTER_CLOCK (clutter_master_clock_get_type ())
G_DECLARE_INTERFACE (ClutterMasterClock, clutter_master_clock,
CLUTTER, MASTER_CLOCK,
GObject)
struct _ClutterMasterClockInterface
{
/*< private >*/
GTypeInterface parent_iface;
void (* add_timeline) (ClutterMasterClock *master_clock,
ClutterTimeline *timeline);
void (* remove_timeline) (ClutterMasterClock *master_clock,
ClutterTimeline *timeline);
void (* start_running) (ClutterMasterClock *master_clock);
void (* ensure_next_iteration) (ClutterMasterClock *master_clock);
void (* set_paused) (ClutterMasterClock *master_clock,
gboolean paused);
};
ClutterMasterClock * _clutter_master_clock_get_default (void);
void _clutter_master_clock_add_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *timeline);
void _clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *timeline);
void _clutter_master_clock_start_running (ClutterMasterClock *master_clock);
void _clutter_master_clock_ensure_next_iteration (ClutterMasterClock *master_clock);
void _clutter_master_clock_set_paused (ClutterMasterClock *master_clock,
gboolean paused);
void _clutter_timeline_advance (ClutterTimeline *timeline,
gint64 tick_time);
gint64 _clutter_timeline_get_delta (ClutterTimeline *timeline);
void _clutter_timeline_do_tick (ClutterTimeline *timeline,
gint64 tick_time);
G_END_DECLS
#endif /* __CLUTTER_MASTER_CLOCK_H__ */

View File

@ -39,10 +39,6 @@
CLUTTER_EXPORT
GList * clutter_stage_peek_stage_views (ClutterStage *stage);
CLUTTER_EXPORT
gboolean clutter_actor_is_effectively_on_stage_view (ClutterActor *self,
ClutterStageView *view);
CLUTTER_EXPORT
void clutter_set_custom_backend_func (ClutterBackend *(* func) (void));
@ -56,7 +52,30 @@ void clutter_stage_capture_into (ClutterStage *stage,
uint8_t *data);
CLUTTER_EXPORT
void clutter_stage_clear_stage_views (ClutterStage *stage);
void clutter_stage_paint_to_framebuffer (ClutterStage *stage,
CoglFramebuffer *framebuffer,
const cairo_rectangle_int_t *rect,
float scale,
ClutterPaintFlag paint_flags);
CLUTTER_EXPORT
gboolean clutter_stage_paint_to_buffer (ClutterStage *stage,
const cairo_rectangle_int_t *rect,
float scale,
uint8_t *data,
int stride,
CoglPixelFormat format,
ClutterPaintFlag paint_flags,
GError **error);
CLUTTER_EXPORT
void clutter_stage_freeze_updates (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_thaw_updates (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_update_resource_scales (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_view_assign_next_scanout (ClutterStageView *stage_view,
@ -68,13 +87,6 @@ gboolean clutter_actor_has_damage (ClutterActor *actor);
CLUTTER_EXPORT
gboolean clutter_actor_has_transitions (ClutterActor *actor);
CLUTTER_EXPORT
ClutterFrameClock * clutter_actor_pick_frame_clock (ClutterActor *self,
ClutterActor **out_actor);
CLUTTER_EXPORT
gboolean clutter_seat_handle_event_post (ClutterSeat *seat,
const ClutterEvent *event);
#undef __CLUTTER_H_INSIDE__
#endif /* __CLUTTER_MUTTER_H__ */

View File

@ -100,8 +100,6 @@ struct _ClutterOffscreenEffectPrivate
int target_height;
gint old_opacity_override;
gulong purge_handler_id;
};
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterOffscreenEffect,
@ -160,12 +158,6 @@ ensure_pipeline_filter_for_scale (ClutterOffscreenEffect *self,
filter, filter);
}
static void
video_memory_purged (ClutterOffscreenEffect *self)
{
g_clear_pointer (&self->priv->offscreen, cogl_object_unref);
}
static gboolean
update_fbo (ClutterEffect *effect,
int target_width,
@ -174,26 +166,8 @@ update_fbo (ClutterEffect *effect,
{
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv;
ClutterActor *stage_actor;
stage_actor = clutter_actor_get_stage (priv->actor);
if (stage_actor != priv->stage)
{
g_clear_signal_handler (&priv->purge_handler_id, priv->stage);
priv->stage = stage_actor;
if (priv->stage)
{
priv->purge_handler_id =
g_signal_connect_object (priv->stage,
"gl-video-memory-purged",
G_CALLBACK (video_memory_purged),
self,
G_CONNECT_SWAPPED);
}
}
priv->stage = clutter_actor_get_stage (priv->actor);
if (priv->stage == NULL)
{
CLUTTER_NOTE (MISC, "The actor '%s' is not part of a stage",
@ -264,8 +238,8 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
gfloat stage_width, stage_height;
gfloat target_width = -1, target_height = -1;
CoglFramebuffer *framebuffer;
float resource_scale;
float ceiled_resource_scale;
gfloat resource_scale;
gfloat ceiled_resource_scale;
graphene_point3d_t local_offset;
gfloat old_viewport[4];
@ -280,11 +254,17 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
stage = _clutter_actor_get_stage_internal (priv->actor);
clutter_actor_get_size (stage, &stage_width, &stage_height);
resource_scale = clutter_actor_get_real_resource_scale (priv->actor);
ceiled_resource_scale = ceilf (resource_scale);
stage_width *= ceiled_resource_scale;
stage_height *= ceiled_resource_scale;
if (_clutter_actor_get_real_resource_scale (priv->actor, &resource_scale))
{
ceiled_resource_scale = ceilf (resource_scale);
stage_width *= ceiled_resource_scale;
stage_height *= ceiled_resource_scale;
}
else
{
/* We are sure we have a resource scale set to a good value at paint */
g_assert_not_reached ();
}
/* Get the minimal bounding box for what we want to paint, relative to the
* parent of priv->actor. Note that we may actually be painting a clone of
@ -437,9 +417,8 @@ clutter_offscreen_effect_paint_texture (ClutterOffscreenEffect *effect,
*/
cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview);
resource_scale = clutter_actor_get_resource_scale (priv->actor);
if (resource_scale != 1.0f)
if (clutter_actor_get_resource_scale (priv->actor, &resource_scale) &&
resource_scale != 1.0f)
{
float paint_scale = 1.0f / resource_scale;
cogl_matrix_scale (&modelview, paint_scale, paint_scale, 1);

View File

@ -33,7 +33,6 @@ typedef enum _ClutterPaintFlag
{
CLUTTER_PAINT_FLAG_NONE = 0,
CLUTTER_PAINT_FLAG_NO_CURSORS = 1 << 0,
CLUTTER_PAINT_FLAG_FORCE_CURSORS = 1 << 1,
} ClutterPaintFlag;
#define CLUTTER_TYPE_PAINT_CONTEXT (clutter_paint_context_get_type ())

View File

@ -1412,7 +1412,6 @@ clutter_layer_node_new (const CoglMatrix *projection,
{
ClutterLayerNode *res;
CoglContext *context;
CoglTexture2D *tex_2d;
CoglTexture *texture;
CoglColor color;
@ -1427,10 +1426,9 @@ clutter_layer_node_new (const CoglMatrix *projection,
/* the texture backing the FBO */
context = clutter_backend_get_cogl_context (clutter_get_default_backend ());
tex_2d = cogl_texture_2d_new_with_size (context,
MAX (res->fbo_width, 1),
MAX (res->fbo_height, 1));
texture = COGL_TEXTURE (tex_2d);
texture = cogl_texture_2d_new_with_size (context,
MAX (res->fbo_width, 1),
MAX (res->fbo_height, 1));
cogl_texture_set_premultiplied (texture, TRUE);
res->offscreen = COGL_FRAMEBUFFER (cogl_offscreen_new_to_texture (texture));

View File

@ -62,7 +62,6 @@
#include "clutter-gesture-action-private.h"
#include "clutter-marshal.h"
#include "clutter-private.h"
#include "clutter-timeline.h"
#include <math.h>
#define FLOAT_EPSILON (1e-15)
@ -137,8 +136,7 @@ enum
static guint pan_signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE_WITH_PRIVATE (ClutterPanAction, clutter_pan_action,
CLUTTER_TYPE_GESTURE_ACTION)
G_DEFINE_TYPE_WITH_PRIVATE (ClutterPanAction, clutter_pan_action, CLUTTER_TYPE_GESTURE_ACTION)
static void
emit_pan (ClutterPanAction *self,
@ -158,18 +156,14 @@ emit_pan (ClutterPanAction *self,
gfloat scroll_threshold = G_PI_4/2;
gfloat drag_angle;
clutter_gesture_action_get_motion_delta (CLUTTER_GESTURE_ACTION (self),
0,
&delta_x,
&delta_y);
clutter_gesture_action_get_motion_delta (CLUTTER_GESTURE_ACTION (self), 0, &delta_x, &delta_y);
if (delta_x != 0.0f)
drag_angle = atanf (delta_y / delta_x);
else
drag_angle = G_PI_2;
if ((drag_angle > -scroll_threshold) &&
(drag_angle < scroll_threshold))
if ((drag_angle > -scroll_threshold) && (drag_angle < scroll_threshold))
priv->pin_state = SCROLL_PINNED_HORIZONTAL;
else if ((drag_angle > (G_PI_2 - scroll_threshold)) ||
(drag_angle < -(G_PI_2 - scroll_threshold)))
@ -288,10 +282,7 @@ gesture_end (ClutterGestureAction *gesture,
gfloat tau;
gint duration;
clutter_gesture_action_get_release_coords (CLUTTER_GESTURE_ACTION (self),
0,
&priv->release_x,
&priv->release_y);
clutter_gesture_action_get_release_coords (CLUTTER_GESTURE_ACTION (self), 0, &priv->release_x, &priv->release_y);
if (!priv->should_interpolate)
{
@ -302,9 +293,7 @@ gesture_end (ClutterGestureAction *gesture,
priv->state = PAN_STATE_INTERPOLATING;
clutter_gesture_action_get_motion_delta (gesture, 0, &delta_x, &delta_y);
velocity = clutter_gesture_action_get_velocity (gesture, 0,
&velocity_x,
&velocity_y);
velocity = clutter_gesture_action_get_velocity (gesture, 0, &velocity_x, &velocity_y);
/* Exponential timing constant v(t) = v(0) * exp(-t/tau)
* tau = 1000ms / (frame_per_second * - ln(decay_per_frame))
@ -315,26 +304,17 @@ gesture_end (ClutterGestureAction *gesture,
/* See where the decreasing velocity reaches $min_velocity px/ms
* v(t) = v(0) * exp(-t/tau) = min_velocity
* t = - tau * ln( min_velocity / |v(0)|) */
duration = - tau * logf (min_velocity / (ABS (velocity) *
priv->acceleration_factor));
duration = - tau * logf (min_velocity / (ABS (velocity) * priv->acceleration_factor));
/* Target point: x(t) = v(0) * tau * [1 - exp(-t/tau)] */
priv->target_x = (velocity_x * priv->acceleration_factor * tau *
(1 - exp ((float)-duration / tau)));
priv->target_y = (velocity_y * priv->acceleration_factor * tau *
(1 - exp ((float)-duration / tau)));
priv->target_x = velocity_x * priv->acceleration_factor * tau * (1 - exp ((float)-duration / tau));
priv->target_y = velocity_y * priv->acceleration_factor * tau * (1 - exp ((float)-duration / tau));
if (ABS (velocity) * priv->acceleration_factor > min_velocity &&
duration > FLOAT_EPSILON)
if (ABS (velocity) * priv->acceleration_factor > min_velocity && duration > FLOAT_EPSILON)
{
ClutterActor *pan_actor =
clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (gesture));
priv->interpolated_x = priv->interpolated_y = 0.0f;
priv->deceleration_timeline = clutter_timeline_new_for_actor (pan_actor,
duration);
clutter_timeline_set_progress_mode (priv->deceleration_timeline,
CLUTTER_EASE_OUT_EXPO);
priv->deceleration_timeline = clutter_timeline_new (duration);
clutter_timeline_set_progress_mode (priv->deceleration_timeline, CLUTTER_EASE_OUT_EXPO);
g_signal_connect (priv->deceleration_timeline, "new_frame",
G_CALLBACK (on_deceleration_new_frame), self);
@ -387,8 +367,7 @@ clutter_pan_action_set_property (GObject *gobject,
break;
case PROP_ACCELERATION_FACTOR :
clutter_pan_action_set_acceleration_factor (self,
g_value_get_double (value));
clutter_pan_action_set_acceleration_factor (self, g_value_get_double (value));
break;
default:
@ -432,11 +411,9 @@ static void
clutter_pan_action_constructed (GObject *gobject)
{
ClutterGestureAction *gesture;
ClutterGestureTriggerEdge edge;
gesture = CLUTTER_GESTURE_ACTION (gobject);
edge = CLUTTER_GESTURE_TRIGGER_EDGE_AFTER;
clutter_gesture_action_set_threshold_trigger_edge (gesture, edge);
clutter_gesture_action_set_threshold_trigger_edge (gesture, CLUTTER_GESTURE_TRIGGER_EDGE_AFTER);
}
static void
@ -463,12 +440,9 @@ clutter_pan_action_set_actor (ClutterActorMeta *meta,
/* make sure we reset the state */
if (priv->state == PAN_STATE_INTERPOLATING)
g_clear_object (&priv->deceleration_timeline);
else if (priv->deceleration_timeline)
clutter_timeline_set_actor (priv->deceleration_timeline, actor);
}
CLUTTER_ACTOR_META_CLASS (clutter_pan_action_parent_class)->set_actor (meta,
actor);
CLUTTER_ACTOR_META_CLASS (clutter_pan_action_parent_class)->set_actor (meta, actor);
}
@ -906,9 +880,7 @@ clutter_pan_action_get_constrained_motion_delta (ClutterPanAction *self,
priv = self->priv;
distance = clutter_pan_action_get_motion_delta (self, point,
&delta_x,
&delta_y);
distance = clutter_pan_action_get_motion_delta (self, point, &delta_x, &delta_y);
switch (priv->pan_axis)
{

View File

@ -37,6 +37,7 @@
#include "clutter-feature.h"
#include "clutter-id-pool.h"
#include "clutter-layout-manager.h"
#include "clutter-master-clock.h"
#include "clutter-settings.h"
#include "clutter-stage-manager.h"
#include "clutter-stage.h"
@ -121,8 +122,11 @@ struct _ClutterMainContext
/* the object holding all the stage instances */
ClutterStageManager *stage_manager;
/* the clock driving all the frame operations */
ClutterMasterClock *master_clock;
/* the main event queue */
GAsyncQueue *events_queue;
GQueue *events_queue;
/* the event filters added via clutter_event_add_filter. these are
* ordered from least recently added to most recently added */
@ -173,6 +177,11 @@ typedef struct
gboolean _clutter_threads_dispatch (gpointer data);
void _clutter_threads_dispatch_free (gpointer data);
CLUTTER_EXPORT
void _clutter_threads_acquire_lock (void);
CLUTTER_EXPORT
void _clutter_threads_release_lock (void);
ClutterMainContext * _clutter_context_get_default (void);
void _clutter_context_lock (void);
void _clutter_context_unlock (void);
@ -307,36 +316,6 @@ gboolean _clutter_run_progress_function (GType gtype,
void clutter_timeline_cancel_delay (ClutterTimeline *timeline);
static inline uint64_t
us (uint64_t us)
{
return us;
}
static inline uint32_t
ms (uint32_t ms)
{
return ms;
}
static inline uint64_t
ms2us (uint64_t ms)
{
return us (ms * 1000);
}
static inline uint32_t
us2ms (uint64_t us)
{
return (uint32_t) (us / 1000);
}
static inline uint64_t
ns2us (uint64_t ns)
{
return us (ns / 1000);
}
G_END_DECLS
#endif /* __CLUTTER_PRIVATE_H__ */

View File

@ -278,26 +278,6 @@ clutter_property_transition_init (ClutterPropertyTransition *self)
self->priv = clutter_property_transition_get_instance_private (self);
}
/**
* clutter_property_transition_new_for_actor:
* @actor: a #ClutterActor
* @property_name: (allow-none): a property of @animatable, or %NULL
*
* Creates a new #ClutterPropertyTransition.
*
* Return value: (transfer full): the newly created #ClutterPropertyTransition.
* Use g_object_unref() when done
*/
ClutterTransition *
clutter_property_transition_new_for_actor (ClutterActor *actor,
const char *property_name)
{
return g_object_new (CLUTTER_TYPE_PROPERTY_TRANSITION,
"actor", actor,
"property-name", property_name,
NULL);
}
/**
* clutter_property_transition_new:
* @property_name: (allow-none): a property of @animatable, or %NULL

View File

@ -78,13 +78,8 @@ struct _ClutterPropertyTransitionClass
CLUTTER_EXPORT
GType clutter_property_transition_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterTransition * clutter_property_transition_new_for_actor (ClutterActor *actor,
const char *property_name);
CLUTTER_EXPORT
ClutterTransition * clutter_property_transition_new (const char *property_name);
CLUTTER_EXPORT
void clutter_property_transition_set_property_name (ClutterPropertyTransition *transition,
const char *property_name);

View File

@ -1523,7 +1523,7 @@ clutter_script_construct_parameters (ClutterScript *script,
continue;
}
if (!(pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)))
if (!(pspec->flags & G_PARAM_CONSTRUCT_ONLY))
{
unparsed = g_list_prepend (unparsed, pinfo);
continue;

View File

@ -50,14 +50,14 @@
* <informalexample><programlisting><![CDATA[
* {
* "id" : "red-button",
* "type" : "ClutterActor",
* "type" : "ClutterRectangle",
* "width" : 100,
* "height" : 100,
* "background-color" : "&num;ff0000ff"
* "color" : "&num;ff0000ff"
* }
* ]]></programlisting></informalexample>
*
* This will produce a red #ClutterActor, 100x100 pixels wide, and
* This will produce a red #ClutterRectangle, 100x100 pixels wide, and
* with a ClutterScript id of "red-button"; it can be retrieved by calling:
*
* |[

View File

@ -27,7 +27,6 @@
#include "clutter-input-device-tool.h"
#include "clutter-input-pointer-a11y-private.h"
#include "clutter-marshal.h"
#include "clutter-mutter.h"
#include "clutter-private.h"
#include "clutter-seat.h"
#include "clutter-virtual-input-device.h"
@ -66,6 +65,9 @@ struct _ClutterSeatPrivate
unsigned int inhibit_unfocus_count;
/* Keyboard a11y */
ClutterKbdA11ySettings kbd_a11y_settings;
/* Pointer a11y */
ClutterPointerA11ySettings pointer_a11y_settings;
};
@ -352,17 +354,6 @@ clutter_seat_get_keyboard (ClutterSeat *seat)
return CLUTTER_SEAT_GET_CLASS (seat)->get_keyboard (seat);
}
/**
* clutter_seat_peek_devices: (skip)
**/
const GList *
clutter_seat_peek_devices (ClutterSeat *seat)
{
g_return_val_if_fail (CLUTTER_IS_SEAT (seat), NULL);
return CLUTTER_SEAT_GET_CLASS (seat)->peek_devices (seat);
}
/**
* clutter_seat_list_devices:
* @seat: a #ClutterSeat
@ -379,7 +370,7 @@ clutter_seat_list_devices (ClutterSeat *seat)
{
g_return_val_if_fail (CLUTTER_IS_SEAT (seat), NULL);
return g_list_copy ((GList *)clutter_seat_peek_devices (seat));
return CLUTTER_SEAT_GET_CLASS (seat)->list_devices (seat);
}
void
@ -402,6 +393,43 @@ clutter_seat_get_keymap (ClutterSeat *seat)
return CLUTTER_SEAT_GET_CLASS (seat)->get_keymap (seat);
}
static gboolean
are_kbd_a11y_settings_equal (ClutterKbdA11ySettings *a,
ClutterKbdA11ySettings *b)
{
return (memcmp (a, b, sizeof (ClutterKbdA11ySettings)) == 0);
}
void
clutter_seat_set_kbd_a11y_settings (ClutterSeat *seat,
ClutterKbdA11ySettings *settings)
{
ClutterSeatClass *seat_class;
ClutterSeatPrivate *priv = clutter_seat_get_instance_private (seat);
g_return_if_fail (CLUTTER_IS_SEAT (seat));
if (are_kbd_a11y_settings_equal (&priv->kbd_a11y_settings, settings))
return;
priv->kbd_a11y_settings = *settings;
seat_class = CLUTTER_SEAT_GET_CLASS (seat);
if (seat_class->apply_kbd_a11y_settings)
seat_class->apply_kbd_a11y_settings (seat, settings);
}
void
clutter_seat_get_kbd_a11y_settings (ClutterSeat *seat,
ClutterKbdA11ySettings *settings)
{
ClutterSeatPrivate *priv = clutter_seat_get_instance_private (seat);
g_return_if_fail (CLUTTER_IS_SEAT (seat));
*settings = priv->kbd_a11y_settings;
}
void
clutter_seat_ensure_a11y_state (ClutterSeat *seat)
{
@ -606,8 +634,8 @@ clutter_seat_create_virtual_device (ClutterSeat *seat,
}
/**
* clutter_seat_get_supported_virtual_device_types: (skip)
**/
* clutter_seat_supported_virtual_device_types: (skip)
*/
ClutterVirtualDeviceType
clutter_seat_get_supported_virtual_device_types (ClutterSeat *seat)
{
@ -635,40 +663,6 @@ clutter_seat_compress_motion (ClutterSeat *seat,
seat_class->compress_motion (seat, event, to_discard);
}
gboolean
clutter_seat_handle_event_post (ClutterSeat *seat,
const ClutterEvent *event)
{
ClutterSeatClass *seat_class;
ClutterInputDevice *device;
g_return_val_if_fail (CLUTTER_IS_SEAT (seat), FALSE);
g_return_val_if_fail (event, FALSE);
seat_class = CLUTTER_SEAT_GET_CLASS (seat);
if (seat_class->handle_event_post)
seat_class->handle_event_post (seat, event);
device = clutter_event_get_source_device (event);
g_assert_true (CLUTTER_IS_INPUT_DEVICE (device));
switch (event->type)
{
case CLUTTER_DEVICE_ADDED:
g_signal_emit (seat, signals[DEVICE_ADDED], 0, device);
break;
case CLUTTER_DEVICE_REMOVED:
g_signal_emit (seat, signals[DEVICE_REMOVED], 0, device);
g_object_run_dispose (G_OBJECT (device));
break;
default:
break;
}
return TRUE;
}
void
clutter_seat_warp_pointer (ClutterSeat *seat,
int x,
@ -688,6 +682,7 @@ clutter_seat_warp_pointer (ClutterSeat *seat,
* requirements are fulfilled:
*
* - A touchscreen is available
* - No external keyboard is attached to the device
* - A tablet mode switch, if present, is enabled
*
* Returns: %TRUE if the device is a tablet that doesn't have an external
@ -704,20 +699,3 @@ clutter_seat_get_touch_mode (ClutterSeat *seat)
return touch_mode;
}
gboolean
clutter_seat_query_state (ClutterSeat *seat,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *coords,
ClutterModifierType *modifiers)
{
g_return_val_if_fail (CLUTTER_IS_SEAT (seat), FALSE);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
return CLUTTER_SEAT_GET_CLASS (seat)->query_state (seat,
device,
sequence,
coords,
modifiers);
}

View File

@ -37,6 +37,24 @@ CLUTTER_EXPORT
G_DECLARE_DERIVABLE_TYPE (ClutterSeat, clutter_seat,
CLUTTER, SEAT, GObject)
/**
* ClutterKbdA11ySettings:
*
* The #ClutterKbdA11ySettings structure contains keyboard accessibility
* settings
*
*/
typedef struct _ClutterKbdA11ySettings
{
ClutterKeyboardA11yFlags controls;
gint slowkeys_delay;
gint debounce_delay;
gint timeout_delay;
gint mousekeys_init_delay;
gint mousekeys_max_speed;
gint mousekeys_accel_time;
} ClutterKbdA11ySettings;
/**
* ClutterPointerA11ySettings:
*
@ -78,7 +96,7 @@ struct _ClutterSeatClass
ClutterInputDevice * (* get_pointer) (ClutterSeat *seat);
ClutterInputDevice * (* get_keyboard) (ClutterSeat *seat);
const GList * (* peek_devices) (ClutterSeat *seat);
GList * (* list_devices) (ClutterSeat *seat);
void (* bell_notify) (ClutterSeat *seat);
@ -88,19 +106,10 @@ struct _ClutterSeatClass
ClutterEvent *event,
const ClutterEvent *to_discard);
gboolean (* handle_event_post) (ClutterSeat *seat,
const ClutterEvent *event);
void (* warp_pointer) (ClutterSeat *seat,
int x,
int y);
gboolean (* query_state) (ClutterSeat *seat,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *coords,
ClutterModifierType *modifiers);
/* Event platform data */
void (* copy_event_data) (ClutterSeat *seat,
const ClutterEvent *src,
@ -108,6 +117,10 @@ struct _ClutterSeatClass
void (* free_event_data) (ClutterSeat *seat,
ClutterEvent *event);
/* Keyboard accessibility */
void (* apply_kbd_a11y_settings) (ClutterSeat *seat,
ClutterKbdA11ySettings *settings);
/* Virtual devices */
ClutterVirtualInputDevice * (* create_virtual_device) (ClutterSeat *seat,
ClutterInputDeviceType device_type);
@ -120,13 +133,18 @@ CLUTTER_EXPORT
ClutterInputDevice * clutter_seat_get_keyboard (ClutterSeat *seat);
CLUTTER_EXPORT
GList * clutter_seat_list_devices (ClutterSeat *seat);
const GList * clutter_seat_peek_devices (ClutterSeat *seat);
CLUTTER_EXPORT
void clutter_seat_bell_notify (ClutterSeat *seat);
CLUTTER_EXPORT
ClutterKeymap * clutter_seat_get_keymap (ClutterSeat *seat);
CLUTTER_EXPORT
void clutter_seat_set_kbd_a11y_settings (ClutterSeat *seat,
ClutterKbdA11ySettings *settings);
CLUTTER_EXPORT
void clutter_seat_get_kbd_a11y_settings (ClutterSeat *seat,
ClutterKbdA11ySettings *settings);
CLUTTER_EXPORT
void clutter_seat_ensure_a11y_state (ClutterSeat *seat);
@ -169,11 +187,4 @@ void clutter_seat_warp_pointer (ClutterSeat *seat,
CLUTTER_EXPORT
gboolean clutter_seat_get_touch_mode (ClutterSeat *seat);
CLUTTER_EXPORT
gboolean clutter_seat_query_state (ClutterSeat *seat,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *coords,
ClutterModifierType *modifiers);
#endif /* CLUTTER_SEAT_H */

View File

@ -40,18 +40,6 @@
#define CLUTTER_IS_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SETTINGS))
#define CLUTTER_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SETTINGS, ClutterSettingsClass))
typedef struct
{
cairo_antialias_t cairo_antialias;
gint clutter_font_antialias;
cairo_hint_style_t cairo_hint_style;
const char *clutter_font_hint_style;
cairo_subpixel_order_t cairo_subpixel_order;
const char *clutter_font_subpixel_order;
} FontSettings;
/**
* ClutterSettings:
*
@ -65,7 +53,6 @@ struct _ClutterSettings
GObject parent_instance;
ClutterBackend *backend;
GSettings *xsettings;
gint double_click_time;
gint double_click_distance;
@ -280,159 +267,6 @@ settings_update_fontmap (ClutterSettings *self,
#endif /* HAVE_PANGO_FT2 */
}
static void
get_font_gsettings (GSettings *xsettings,
FontSettings *output)
{
/* org.gnome.settings-daemon.GsdFontAntialiasingMode */
static const struct
{
cairo_antialias_t cairo_antialias;
gint clutter_font_antialias;
}
antialiasings[] =
{
/* none=0 */ {CAIRO_ANTIALIAS_NONE, 0},
/* grayscale=1 */ {CAIRO_ANTIALIAS_GRAY, 1},
/* rgba=2 */ {CAIRO_ANTIALIAS_SUBPIXEL, 1},
};
/* org.gnome.settings-daemon.GsdFontHinting */
static const struct
{
cairo_hint_style_t cairo_hint_style;
const char *clutter_font_hint_style;
}
hintings[] =
{
/* none=0 */ {CAIRO_HINT_STYLE_NONE, "hintnone"},
/* slight=1 */ {CAIRO_HINT_STYLE_SLIGHT, "hintslight"},
/* medium=2 */ {CAIRO_HINT_STYLE_MEDIUM, "hintmedium"},
/* full=3 */ {CAIRO_HINT_STYLE_FULL, "hintfull"},
};
/* org.gnome.settings-daemon.GsdFontRgbaOrder */
static const struct
{
cairo_subpixel_order_t cairo_subpixel_order;
const char *clutter_font_subpixel_order;
}
rgba_orders[] =
{
/* rgba=0 */ {CAIRO_SUBPIXEL_ORDER_RGB, "rgb"}, /* XXX what is 'rgba'? */
/* rgb=1 */ {CAIRO_SUBPIXEL_ORDER_RGB, "rgb"},
/* bgr=2 */ {CAIRO_SUBPIXEL_ORDER_BGR, "bgr"},
/* vrgb=3 */ {CAIRO_SUBPIXEL_ORDER_VRGB, "vrgb"},
/* vbgr=4 */ {CAIRO_SUBPIXEL_ORDER_VBGR, "vbgr"},
};
guint i;
i = g_settings_get_enum (xsettings, "hinting");
if (i < G_N_ELEMENTS (hintings))
{
output->cairo_hint_style = hintings[i].cairo_hint_style;
output->clutter_font_hint_style = hintings[i].clutter_font_hint_style;
}
else
{
output->cairo_hint_style = CAIRO_HINT_STYLE_DEFAULT;
output->clutter_font_hint_style = NULL;
}
i = g_settings_get_enum (xsettings, "antialiasing");
if (i < G_N_ELEMENTS (antialiasings))
{
output->cairo_antialias = antialiasings[i].cairo_antialias;
output->clutter_font_antialias = antialiasings[i].clutter_font_antialias;
}
else
{
output->cairo_antialias = CAIRO_ANTIALIAS_DEFAULT;
output->clutter_font_antialias = -1;
}
i = g_settings_get_enum (xsettings, "rgba-order");
if (i < G_N_ELEMENTS (rgba_orders))
{
output->cairo_subpixel_order = rgba_orders[i].cairo_subpixel_order;
output->clutter_font_subpixel_order = rgba_orders[i].clutter_font_subpixel_order;
}
else
{
output->cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
output->clutter_font_subpixel_order = NULL;
}
if (output->cairo_antialias == CAIRO_ANTIALIAS_GRAY)
output->clutter_font_subpixel_order = "none";
}
static void
init_font_options (ClutterSettings *self)
{
GSettings *xsettings = self->xsettings;
cairo_font_options_t *options = cairo_font_options_create ();
FontSettings fs;
get_font_gsettings (xsettings, &fs);
cairo_font_options_set_hint_style (options, fs.cairo_hint_style);
cairo_font_options_set_antialias (options, fs.cairo_antialias);
cairo_font_options_set_subpixel_order (options, fs.cairo_subpixel_order);
clutter_backend_set_font_options (self->backend, options);
cairo_font_options_destroy (options);
}
static gboolean
on_xsettings_change_event (GSettings *xsettings,
gpointer keys,
gint n_keys,
gpointer user_data)
{
ClutterSettings *self = CLUTTER_SETTINGS (user_data);
FontSettings fs;
gint hinting;
get_font_gsettings (xsettings, &fs);
hinting = fs.cairo_hint_style == CAIRO_HINT_STYLE_NONE ? 0 : 1;
g_object_set (self,
"font-hinting", hinting,
"font-hint-style", fs.clutter_font_hint_style,
"font-antialias", fs.clutter_font_antialias,
"font-subpixel-order", fs.clutter_font_subpixel_order,
NULL);
return FALSE;
}
static void
load_initial_settings (ClutterSettings *self)
{
static const gchar xsettings_path[] =
"org.gnome.settings-daemon.plugins.xsettings";
GSettingsSchemaSource *source = g_settings_schema_source_get_default ();
GSettingsSchema *schema;
schema = g_settings_schema_source_lookup (source, xsettings_path, TRUE);
if (!schema)
{
g_warning ("Failed to find schema: %s", xsettings_path);
}
else
{
self->xsettings = g_settings_new_full (schema, NULL, NULL);
if (self->xsettings)
{
init_font_options (self);
g_signal_connect (self->xsettings, "change-event",
G_CALLBACK (on_xsettings_change_event),
self);
}
}
}
static void
clutter_settings_finalize (GObject *gobject)
{
@ -442,8 +276,6 @@ clutter_settings_finalize (GObject *gobject)
g_free (self->xft_hint_style);
g_free (self->xft_rgba);
g_clear_object (&self->xsettings);
G_OBJECT_CLASS (clutter_settings_parent_class)->finalize (gobject);
}
@ -908,8 +740,6 @@ _clutter_settings_set_backend (ClutterSettings *settings,
g_assert (CLUTTER_IS_BACKEND (backend));
settings->backend = backend;
load_initial_settings (settings);
}
#define SETTINGS_GROUP "Settings"

View File

@ -40,14 +40,7 @@ void clutter_stage_paint_view (ClutterStage
ClutterStageView *view,
const cairo_region_t *redraw_clip);
void clutter_stage_emit_before_update (ClutterStage *stage,
ClutterStageView *view);
void clutter_stage_emit_before_paint (ClutterStage *stage,
ClutterStageView *view);
void clutter_stage_emit_after_paint (ClutterStage *stage,
ClutterStageView *view);
void clutter_stage_emit_after_update (ClutterStage *stage,
ClutterStageView *view);
void _clutter_stage_emit_after_paint (ClutterStage *stage);
CLUTTER_EXPORT
void _clutter_stage_set_window (ClutterStage *stage,
@ -57,6 +50,11 @@ ClutterStageWindow *_clutter_stage_get_window (ClutterStage
void _clutter_stage_get_projection_matrix (ClutterStage *stage,
CoglMatrix *projection);
void _clutter_stage_dirty_projection (ClutterStage *stage);
void _clutter_stage_set_viewport (ClutterStage *stage,
float x,
float y,
float width,
float height);
void _clutter_stage_get_viewport (ClutterStage *stage,
float *x,
float *y,
@ -65,12 +63,9 @@ void _clutter_stage_get_viewport (ClutterStage
void _clutter_stage_dirty_viewport (ClutterStage *stage);
void _clutter_stage_maybe_setup_viewport (ClutterStage *stage,
ClutterStageView *view);
void clutter_stage_maybe_relayout (ClutterActor *stage);
void clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage);
GSList * clutter_stage_find_updated_devices (ClutterStage *stage);
void clutter_stage_update_devices (ClutterStage *stage,
GSList *devices);
void clutter_stage_update_actor_stage_views (ClutterStage *stage);
void _clutter_stage_maybe_relayout (ClutterActor *stage);
gboolean _clutter_stage_needs_update (ClutterStage *stage);
gboolean _clutter_stage_do_update (ClutterStage *stage);
CLUTTER_EXPORT
void _clutter_stage_queue_event (ClutterStage *stage,
@ -79,6 +74,8 @@ void _clutter_stage_queue_event (ClutterStage *stage,
gboolean _clutter_stage_has_queued_events (ClutterStage *stage);
void _clutter_stage_process_queued_events (ClutterStage *stage);
void _clutter_stage_update_input_devices (ClutterStage *stage);
gint64 _clutter_stage_get_update_time (ClutterStage *stage);
void _clutter_stage_clear_update_time (ClutterStage *stage);
gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage);
void clutter_stage_log_pick (ClutterStage *stage,
@ -133,22 +130,17 @@ gboolean _clutter_stage_update_state (ClutterStage *stag
void _clutter_stage_set_scale_factor (ClutterStage *stage,
int factor);
gboolean _clutter_stage_get_max_view_scale_factor_for_rect (ClutterStage *stage,
graphene_rect_t *rect,
float *view_scale);
void clutter_stage_presented (ClutterStage *stage,
ClutterStageView *view,
void _clutter_stage_presented (ClutterStage *stage,
CoglFrameEvent frame_event,
ClutterFrameInfo *frame_info);
void clutter_stage_queue_actor_relayout (ClutterStage *stage,
ClutterActor *actor);
void clutter_stage_dequeue_actor_relayout (ClutterStage *stage,
ClutterActor *actor);
GList * clutter_stage_get_views_for_rect (ClutterStage *stage,
const graphene_rect_t *rect);
void clutter_stage_set_actor_needs_immediate_relayout (ClutterStage *stage);
G_END_DECLS
#endif /* __CLUTTER_STAGE_PRIVATE_H__ */

View File

@ -19,7 +19,6 @@
#define __CLUTTER_STAGE_VIEW_PRIVATE_H__
#include "clutter/clutter-stage-view.h"
#include "clutter/clutter-types.h"
void clutter_stage_view_after_paint (ClutterStageView *view,
cairo_region_t *redraw_clip);
@ -63,12 +62,4 @@ void clutter_stage_view_transform_rect_to_onscreen (ClutterStageView
int dst_height,
cairo_rectangle_int_t *dst_rect);
void clutter_stage_view_schedule_update (ClutterStageView *view);
CLUTTER_EXPORT
float clutter_stage_view_get_refresh_rate (ClutterStageView *view);
void clutter_stage_view_notify_presented (ClutterStageView *view,
ClutterFrameInfo *frame_info);
#endif /* __CLUTTER_STAGE_VIEW_PRIVATE_H__ */

View File

@ -24,10 +24,8 @@
#include <math.h>
#include "clutter/clutter-damage-history.h"
#include "clutter/clutter-frame-clock.h"
#include "clutter/clutter-private.h"
#include "clutter/clutter-mutter.h"
#include "clutter/clutter-stage-private.h"
#include "cogl/cogl.h"
enum
@ -35,13 +33,11 @@ enum
PROP_0,
PROP_NAME,
PROP_STAGE,
PROP_LAYOUT,
PROP_FRAMEBUFFER,
PROP_OFFSCREEN,
PROP_USE_SHADOWFB,
PROP_SCALE,
PROP_REFRESH_RATE,
PROP_LAST
};
@ -52,8 +48,6 @@ typedef struct _ClutterStageViewPrivate
{
char *name;
ClutterStage *stage;
cairo_rectangle_int_t layout;
float scale;
CoglFramebuffer *framebuffer;
@ -77,22 +71,12 @@ typedef struct _ClutterStageViewPrivate
gboolean has_redraw_clip;
cairo_region_t *redraw_clip;
float refresh_rate;
ClutterFrameClock *frame_clock;
guint dirty_viewport : 1;
guint dirty_projection : 1;
} ClutterStageViewPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageView, clutter_stage_view, G_TYPE_OBJECT)
void
clutter_stage_view_destroy (ClutterStageView *view)
{
g_object_run_dispose (G_OBJECT (view));
g_object_unref (view);
}
void
clutter_stage_view_get_layout (ClutterStageView *view,
cairo_rectangle_int_t *rect)
@ -118,9 +102,9 @@ clutter_stage_view_get_framebuffer (ClutterStageView *view)
clutter_stage_view_get_instance_private (view);
if (priv->offscreen)
return COGL_FRAMEBUFFER (priv->offscreen);
return priv->offscreen;
else if (priv->shadow.framebuffer)
return COGL_FRAMEBUFFER (priv->shadow.framebuffer);
return priv->shadow.framebuffer;
else
return priv->framebuffer;
}
@ -143,9 +127,8 @@ clutter_stage_view_get_onscreen (ClutterStageView *view)
}
static CoglPipeline *
clutter_stage_view_create_offscreen_pipeline (CoglOffscreen *offscreen)
clutter_stage_view_create_framebuffer_pipeline (CoglFramebuffer *framebuffer)
{
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (offscreen);
CoglPipeline *pipeline;
pipeline = cogl_pipeline_new (cogl_framebuffer_get_context (framebuffer));
@ -154,7 +137,7 @@ clutter_stage_view_create_offscreen_pipeline (CoglOffscreen *offscreen)
COGL_PIPELINE_FILTER_NEAREST,
COGL_PIPELINE_FILTER_NEAREST);
cogl_pipeline_set_layer_texture (pipeline, 0,
cogl_offscreen_get_texture (offscreen));
cogl_offscreen_get_texture (framebuffer));
cogl_pipeline_set_layer_wrap_mode (pipeline, 0,
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
@ -175,7 +158,7 @@ clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
return;
priv->offscreen_pipeline =
clutter_stage_view_create_offscreen_pipeline (priv->offscreen);
clutter_stage_view_create_framebuffer_pipeline (priv->offscreen);
if (view_class->setup_offscreen_blit_pipeline)
view_class->setup_offscreen_blit_pipeline (view, priv->offscreen_pipeline);
@ -209,7 +192,7 @@ clutter_stage_view_transform_rect_to_onscreen (ClutterStageView *view
static void
paint_transformed_framebuffer (ClutterStageView *view,
CoglPipeline *pipeline,
CoglOffscreen *src_framebuffer,
CoglFramebuffer *src_framebuffer,
CoglFramebuffer *dst_framebuffer,
const cairo_region_t *redraw_clip)
{
@ -449,13 +432,10 @@ clutter_stage_view_after_paint (ClutterStageView *view,
if (priv->shadow.framebuffer)
{
CoglFramebuffer *shadowfb =
COGL_FRAMEBUFFER (priv->shadow.framebuffer);
paint_transformed_framebuffer (view,
priv->offscreen_pipeline,
priv->offscreen,
shadowfb,
priv->shadow.framebuffer,
redraw_clip);
}
else
@ -528,7 +508,7 @@ find_damaged_tiles (ClutterStageView *view,
stride = cogl_dma_buf_handle_get_stride (current_dma_buf_handle);
bpp = cogl_dma_buf_handle_get_bpp (current_dma_buf_handle);
cogl_framebuffer_finish (COGL_FRAMEBUFFER (priv->shadow.framebuffer));
cogl_framebuffer_finish (priv->shadow.framebuffer);
if (!cogl_dma_buf_handle_sync_read_start (prev_dma_buf_handle, error))
return NULL;
@ -621,7 +601,7 @@ swap_dma_buf_framebuffer (ClutterStageView *view)
clutter_stage_view_get_instance_private (view);
int next_idx;
CoglDmaBufHandle *next_dma_buf_handle;
CoglFramebuffer *next_framebuffer;
CoglOffscreen *next_framebuffer;
next_idx = ((priv->shadow.dma_buf.current_idx + 1) %
G_N_ELEMENTS (priv->shadow.dma_buf.handles));
@ -717,13 +697,12 @@ copy_shadowfb_to_onscreen (ClutterStageView *view,
for (i = 0; i < cairo_region_num_rectangles (damage_region); i++)
{
CoglFramebuffer *shadowfb = COGL_FRAMEBUFFER (priv->shadow.framebuffer);
g_autoptr (GError) error = NULL;
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (damage_region, i, &rect);
if (!cogl_blit_framebuffer (shadowfb,
if (!cogl_blit_framebuffer (priv->shadow.framebuffer,
priv->framebuffer,
rect.x, rect.y,
rect.x, rect.y,
@ -775,7 +754,7 @@ clutter_stage_view_foreach_front_buffer (ClutterStageView *view,
if (priv->offscreen)
{
callback (COGL_FRAMEBUFFER (priv->offscreen), user_data);
callback (priv->offscreen, user_data);
}
else if (priv->shadow.framebuffer)
{
@ -794,7 +773,7 @@ clutter_stage_view_foreach_front_buffer (ClutterStageView *view,
}
else
{
callback (COGL_FRAMEBUFFER (priv->shadow.framebuffer), user_data);
callback (priv->shadow.framebuffer, user_data);
}
}
else
@ -1009,154 +988,6 @@ clutter_stage_view_take_scanout (ClutterStageView *view)
return g_steal_pointer (&priv->next_scanout);
}
void
clutter_stage_view_schedule_update (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
clutter_frame_clock_schedule_update (priv->frame_clock);
}
float
clutter_stage_view_get_refresh_rate (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
return priv->refresh_rate;
}
/**
* clutter_stage_view_get_frame_clock: (skip)
*/
ClutterFrameClock *
clutter_stage_view_get_frame_clock (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
return priv->frame_clock;
}
static void
handle_frame_clock_before_frame (ClutterFrameClock *frame_clock,
int64_t frame_count,
gpointer user_data)
{
ClutterStageView *view = user_data;
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
_clutter_stage_process_queued_events (priv->stage);
}
static ClutterFrameResult
handle_frame_clock_frame (ClutterFrameClock *frame_clock,
int64_t frame_count,
int64_t time_us,
gpointer user_data)
{
ClutterStageView *view = user_data;
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
ClutterStage *stage = priv->stage;
g_autoptr (GSList) devices = NULL;
ClutterFrameResult result;
if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
return CLUTTER_FRAME_RESULT_IDLE;
if (!clutter_actor_is_realized (CLUTTER_ACTOR (stage)))
return CLUTTER_FRAME_RESULT_IDLE;
if (!clutter_actor_is_mapped (CLUTTER_ACTOR (stage)))
return CLUTTER_FRAME_RESULT_IDLE;
_clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_PRE_PAINT);
clutter_stage_emit_before_update (stage, view);
clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
clutter_stage_update_actor_stage_views (stage);
clutter_stage_maybe_finish_queue_redraws (stage);
devices = clutter_stage_find_updated_devices (stage);
if (clutter_stage_view_has_redraw_clip (view))
{
ClutterStageWindow *stage_window;
clutter_stage_emit_before_paint (stage, view);
stage_window = _clutter_stage_get_window (stage);
_clutter_stage_window_redraw_view (stage_window, view);
clutter_stage_emit_after_paint (stage, view);
_clutter_stage_window_finish_frame (stage_window);
result = CLUTTER_FRAME_RESULT_PENDING_PRESENTED;
}
else
{
result = CLUTTER_FRAME_RESULT_IDLE;
}
clutter_stage_update_devices (stage, devices);
_clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_POST_PAINT);
clutter_stage_emit_after_update (stage, view);
return result;
}
static const ClutterFrameListenerIface frame_clock_listener_iface = {
.before_frame = handle_frame_clock_before_frame,
.frame = handle_frame_clock_frame,
};
void
clutter_stage_view_notify_presented (ClutterStageView *view,
ClutterFrameInfo *frame_info)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
clutter_stage_presented (priv->stage, view, frame_info);
clutter_frame_clock_notify_presented (priv->frame_clock, frame_info);
}
static void
sanity_check_framebuffer (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
G_GNUC_UNUSED int fb_width, fb_height;
fb_width = cogl_framebuffer_get_width (priv->framebuffer);
fb_height = cogl_framebuffer_get_height (priv->framebuffer);
g_warn_if_fail (fabsf (roundf (fb_width / priv->scale) -
fb_width / priv->scale) < FLT_EPSILON);
g_warn_if_fail (fabsf (roundf (fb_height / priv->scale) -
fb_height / priv->scale) < FLT_EPSILON);
}
static void
clutter_stage_view_set_framebuffer (ClutterStageView *view,
CoglFramebuffer *framebuffer)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
g_warn_if_fail (!priv->framebuffer);
if (framebuffer)
{
priv->framebuffer = cogl_object_ref (framebuffer);
sanity_check_framebuffer (view);
}
}
static void
clutter_stage_view_get_property (GObject *object,
guint prop_id,
@ -1172,9 +1003,6 @@ clutter_stage_view_get_property (GObject *object,
case PROP_NAME:
g_value_set_string (value, priv->name);
break;
case PROP_STAGE:
g_value_set_boxed (value, &priv->stage);
break;
case PROP_LAYOUT:
g_value_set_boxed (value, &priv->layout);
break;
@ -1190,9 +1018,6 @@ clutter_stage_view_get_property (GObject *object,
case PROP_SCALE:
g_value_set_float (value, priv->scale);
break;
case PROP_REFRESH_RATE:
g_value_set_float (value, priv->refresh_rate);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -1214,15 +1039,26 @@ clutter_stage_view_set_property (GObject *object,
case PROP_NAME:
priv->name = g_value_dup_string (value);
break;
case PROP_STAGE:
priv->stage = g_value_get_object (value);
break;
case PROP_LAYOUT:
layout = g_value_get_boxed (value);
priv->layout = *layout;
break;
case PROP_FRAMEBUFFER:
clutter_stage_view_set_framebuffer (view, g_value_get_boxed (value));
priv->framebuffer = g_value_dup_boxed (value);
#ifndef G_DISABLE_CHECKS
if (priv->framebuffer)
{
int fb_width, fb_height;
fb_width = cogl_framebuffer_get_width (priv->framebuffer);
fb_height = cogl_framebuffer_get_height (priv->framebuffer);
g_warn_if_fail (fabsf (roundf (fb_width / priv->scale) -
fb_width / priv->scale) < FLT_EPSILON);
g_warn_if_fail (fabsf (roundf (fb_height / priv->scale) -
fb_height / priv->scale) < FLT_EPSILON);
}
#endif
break;
case PROP_OFFSCREEN:
priv->offscreen = g_value_dup_boxed (value);
@ -1233,9 +1069,6 @@ clutter_stage_view_set_property (GObject *object,
case PROP_SCALE:
priv->scale = g_value_get_float (value);
break;
case PROP_REFRESH_RATE:
priv->refresh_rate = g_value_get_float (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -1251,10 +1084,6 @@ clutter_stage_view_constructed (GObject *object)
if (priv->use_shadowfb)
init_shadowfb (view);
priv->frame_clock = clutter_frame_clock_new (priv->refresh_rate,
&frame_clock_listener_iface,
view);
G_OBJECT_CLASS (clutter_stage_view_parent_class)->constructed (object);
}
@ -1281,7 +1110,6 @@ clutter_stage_view_dispose (GObject *object)
g_clear_pointer (&priv->offscreen, cogl_object_unref);
g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
g_clear_pointer (&priv->redraw_clip, cairo_region_destroy);
g_clear_pointer (&priv->frame_clock, clutter_frame_clock_destroy);
G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
}
@ -1295,7 +1123,6 @@ clutter_stage_view_init (ClutterStageView *view)
priv->dirty_viewport = TRUE;
priv->dirty_projection = TRUE;
priv->scale = 1.0;
priv->refresh_rate = 60.0;
}
static void
@ -1319,16 +1146,6 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_STAGE] =
g_param_spec_object ("stage",
"The stage",
"The ClutterStage",
CLUTTER_TYPE_STAGE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_LAYOUT] =
g_param_spec_boxed ("layout",
"View layout",
@ -1374,14 +1191,5 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_REFRESH_RATE] =
g_param_spec_float ("refresh-rate",
"Refresh rate",
"Update refresh rate",
1.0, G_MAXFLOAT, 60.0,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, PROP_LAST, obj_props);
}

View File

@ -27,7 +27,6 @@
#include <cogl/cogl.h>
#include "clutter-macros.h"
#include "clutter-frame-clock.h"
#define CLUTTER_TYPE_STAGE_VIEW (clutter_stage_view_get_type ())
CLUTTER_EXPORT
@ -52,9 +51,6 @@ struct _ClutterStageViewClass
cairo_rectangle_int_t *dst_rect);
};
CLUTTER_EXPORT
void clutter_stage_view_destroy (ClutterStageView *view);
CLUTTER_EXPORT
void clutter_stage_view_get_layout (ClutterStageView *view,
cairo_rectangle_int_t *rect);
@ -73,7 +69,4 @@ CLUTTER_EXPORT
void clutter_stage_view_get_offscreen_transformation_matrix (ClutterStageView *view,
CoglMatrix *matrix);
CLUTTER_EXPORT
ClutterFrameClock * clutter_stage_view_get_frame_clock (ClutterStageView *view);
#endif /* __CLUTTER_STAGE_VIEW_H__ */

View File

@ -103,12 +103,81 @@ _clutter_stage_window_get_geometry (ClutterStageWindow *window,
}
void
_clutter_stage_window_redraw_view (ClutterStageWindow *window,
ClutterStageView *view)
_clutter_stage_window_schedule_update (ClutterStageWindow *window,
int sync_delay)
{
ClutterStageWindowInterface *iface;
g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window));
CLUTTER_STAGE_WINDOW_GET_IFACE (window)->redraw_view (window, view);
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
if (iface->schedule_update == NULL)
{
g_assert (!clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS));
return;
}
iface->schedule_update (window, sync_delay);
}
/**
* _clutter_stage_window_get_update_time:
* @window: a #ClutterStageWindow object
*
* See _clutter_stage_get_update_time() for more info.
*
* Returns: The timestamp of the update time
*/
gint64
_clutter_stage_window_get_update_time (ClutterStageWindow *window)
{
ClutterStageWindowInterface *iface;
g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), 0);
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
if (iface->get_update_time == NULL)
{
g_assert (!clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS));
return 0;
}
return iface->get_update_time (window);
}
/**
* _clutter_stage_window_clear_update_time:
* @window: a #ClutterStageWindow object
*
* Clears the update time. See _clutter_stage_clear_update_time() for more info.
*/
void
_clutter_stage_window_clear_update_time (ClutterStageWindow *window)
{
ClutterStageWindowInterface *iface;
g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window));
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
if (iface->clear_update_time == NULL)
{
g_assert (!clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS));
return;
}
iface->clear_update_time (window);
}
void
_clutter_stage_window_redraw (ClutterStageWindow *window)
{
ClutterStageWindowInterface *iface;
g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window));
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
if (iface->redraw)
iface->redraw (window);
}
gboolean

View File

@ -44,8 +44,12 @@ struct _ClutterStageWindowInterface
void (* get_geometry) (ClutterStageWindow *stage_window,
cairo_rectangle_int_t *geometry);
void (* redraw_view) (ClutterStageWindow *stage_window,
ClutterStageView *view);
void (* schedule_update) (ClutterStageWindow *stage_window,
int sync_delay);
gint64 (* get_update_time) (ClutterStageWindow *stage_window);
void (* clear_update_time) (ClutterStageWindow *stage_window);
void (* redraw) (ClutterStageWindow *stage_window);
gboolean (* can_clip_redraws) (ClutterStageWindow *stage_window);
@ -74,12 +78,15 @@ void _clutter_stage_window_resize (ClutterStageWin
CLUTTER_EXPORT
void _clutter_stage_window_get_geometry (ClutterStageWindow *window,
cairo_rectangle_int_t *geometry);
void _clutter_stage_window_schedule_update (ClutterStageWindow *window,
int sync_delay);
gint64 _clutter_stage_window_get_update_time (ClutterStageWindow *window);
void _clutter_stage_window_clear_update_time (ClutterStageWindow *window);
void _clutter_stage_window_set_accept_focus (ClutterStageWindow *window,
gboolean accept_focus);
void _clutter_stage_window_redraw_view (ClutterStageWindow *window,
ClutterStageView *view);
void _clutter_stage_window_redraw (ClutterStageWindow *window);
gboolean _clutter_stage_window_can_clip_redraws (ClutterStageWindow *window);

File diff suppressed because it is too large Load Diff

View File

@ -28,8 +28,8 @@
#error "Only <clutter/clutter.h> can be included directly."
#endif
#include <clutter/clutter-actor.h>
#include <clutter/clutter-types.h>
#include <clutter/clutter-group.h>
#include <clutter/clutter-stage-view.h>
G_BEGIN_DECLS
@ -56,7 +56,7 @@ typedef struct _ClutterStagePrivate ClutterStagePrivate;
struct _ClutterStage
{
/*< private >*/
ClutterActor parent_instance;
ClutterGroup parent_instance;
ClutterStagePrivate *priv;
};
@ -64,6 +64,7 @@ struct _ClutterStage
* ClutterStageClass:
* @activate: handler for the #ClutterStage::activate signal
* @deactivate: handler for the #ClutterStage::deactivate signal
* @delete_event: handler for the #ClutterStage::delete-event signal
*
* The #ClutterStageClass structure contains only private data
*
@ -73,20 +74,23 @@ struct _ClutterStage
struct _ClutterStageClass
{
/*< private >*/
ClutterActorClass parent_class;
ClutterGroupClass parent_class;
/*< public >*/
/* signals */
void (* activate) (ClutterStage *stage);
void (* deactivate) (ClutterStage *stage);
gboolean (* delete_event) (ClutterStage *stage,
ClutterEvent *event);
void (* paint_view) (ClutterStage *stage,
ClutterStageView *view,
const cairo_region_t *redraw_clip);
/*< private >*/
/* padding for future expansion */
gpointer _padding_dummy[31];
gpointer _padding_dummy[30];
};
/**
@ -132,6 +136,9 @@ GType clutter_perspective_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
GType clutter_stage_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterActor * clutter_stage_new (void);
CLUTTER_EXPORT
void clutter_stage_get_perspective (ClutterStage *stage,
ClutterPerspective *perspective);
@ -188,10 +195,11 @@ guchar * clutter_stage_read_pixels (ClutterStage
CLUTTER_EXPORT
void clutter_stage_ensure_viewport (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_ensure_redraw (ClutterStage *stage);
CLUTTER_EXPORT
gboolean clutter_stage_is_redraw_queued_on_view (ClutterStage *stage,
ClutterStageView *view);
gboolean clutter_stage_is_redraw_queued (ClutterStage *stage);
#ifdef CLUTTER_ENABLE_EXPERIMENTAL_API
CLUTTER_EXPORT
@ -212,22 +220,11 @@ gboolean clutter_stage_get_capture_final_size (ClutterStage *stage,
float *scale);
CLUTTER_EXPORT
void clutter_stage_paint_to_framebuffer (ClutterStage *stage,
CoglFramebuffer *framebuffer,
const cairo_rectangle_int_t *rect,
float scale,
ClutterPaintFlag paint_flags);
CLUTTER_EXPORT
gboolean clutter_stage_paint_to_buffer (ClutterStage *stage,
const cairo_rectangle_int_t *rect,
float scale,
uint8_t *data,
int stride,
CoglPixelFormat format,
ClutterPaintFlag paint_flags,
GError **error);
gboolean clutter_stage_capture (ClutterStage *stage,
gboolean paint,
cairo_rectangle_int_t *rect,
ClutterCapture **out_captures,
int *out_n_captures);
CLUTTER_EXPORT
ClutterStageView * clutter_stage_get_view_at (ClutterStage *stage,
float x,

View File

@ -187,6 +187,9 @@ struct _ClutterTextPrivate
ClutterInputContentHintFlags input_hints;
ClutterInputContentPurpose input_purpose;
/* Signal handler for when the :resource-scale changes */
gulong resource_scale_changed_id;
/* bitfields */
guint alignment : 2;
guint wrap : 1;
@ -595,7 +598,9 @@ ensure_effective_pango_scale_attribute (ClutterText *self)
float resource_scale;
ClutterTextPrivate *priv = self->priv;
resource_scale = clutter_actor_get_resource_scale (CLUTTER_ACTOR (self));
if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (self), &resource_scale) ||
resource_scale == 1.0)
return;
if (priv->effective_attrs != NULL)
{
@ -917,6 +922,18 @@ clutter_text_direction_changed_cb (GObject *gobject,
/* no need to queue a relayout: set_text_direction() will do that for us */
}
static void
clutter_text_resource_scale_changed_cb (GObject *gobject,
GParamSpec *pspec)
{
ClutterText *self = CLUTTER_TEXT (gobject);
ClutterTextPrivate *priv = self->priv;
g_clear_pointer (&priv->effective_attrs, pango_attr_list_unref);
clutter_text_dirty_cache (self);
clutter_actor_queue_relayout (CLUTTER_ACTOR (gobject));
}
/*
* clutter_text_create_layout:
* @text: a #ClutterText
@ -1120,7 +1137,8 @@ maybe_create_text_layout_with_resource_scale (ClutterText *text,
{
float resource_scale;
resource_scale = clutter_actor_get_resource_scale (CLUTTER_ACTOR (text));
if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (text), &resource_scale))
return NULL;
return create_text_layout_with_scale (text,
allocation_width,
@ -1152,7 +1170,8 @@ clutter_text_coords_to_position (ClutterText *self,
g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
resource_scale = clutter_actor_get_resource_scale (CLUTTER_ACTOR (self));
if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (self), &resource_scale))
return 0;
/* Take any offset due to scrolling into account, and normalize
* the coordinates to PangoScale units
@ -1280,7 +1299,8 @@ clutter_text_position_to_coords (ClutterText *self,
g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
resource_scale = clutter_actor_get_resource_scale (CLUTTER_ACTOR (self));
if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (self), &resource_scale))
return FALSE;
ret = clutter_text_position_to_coords_internal (self, position,
x, y, line_height);
@ -1756,6 +1776,7 @@ clutter_text_dispose (GObject *gobject)
clutter_text_dirty_cache (self);
g_clear_signal_handler (&priv->direction_changed_id, self);
g_clear_signal_handler (&priv->resource_scale_changed_id, self);
g_clear_signal_handler (&priv->settings_changed_id,
clutter_get_default_backend ());
@ -2620,7 +2641,8 @@ clutter_text_paint (ClutterActor *self,
!clutter_text_should_draw_cursor (text))
return;
resource_scale = clutter_actor_get_resource_scale (CLUTTER_ACTOR (self));
if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (self), &resource_scale))
return;
clutter_actor_box_scale (&alloc, resource_scale);
clutter_actor_box_get_size (&alloc, &alloc_width, &alloc_height);
@ -2852,7 +2874,8 @@ clutter_text_get_paint_volume (ClutterActor *self,
if (!clutter_actor_has_allocation (self))
return FALSE;
resource_scale = clutter_actor_get_resource_scale (self);
if (!clutter_actor_get_resource_scale (self, &resource_scale))
return FALSE;
_clutter_paint_volume_init_static (&priv->paint_volume, self);
@ -2909,7 +2932,8 @@ clutter_text_get_preferred_width (ClutterActor *self,
gfloat layout_width;
gfloat resource_scale;
resource_scale = clutter_actor_get_resource_scale (self);
if (!clutter_actor_get_resource_scale (self, &resource_scale))
resource_scale = 1;
layout = clutter_text_create_layout (text, -1, -1);
pango_layout_get_extents (layout, NULL, &logical_rect);
@ -2965,7 +2989,8 @@ clutter_text_get_preferred_height (ClutterActor *self,
gfloat layout_height;
gfloat resource_scale;
resource_scale = clutter_actor_get_resource_scale (self);
if (!clutter_actor_get_resource_scale (self, &resource_scale))
resource_scale = 1;
if (priv->single_line_mode)
for_width = -1;
@ -3041,33 +3066,6 @@ clutter_text_has_overlaps (ClutterActor *self)
return clutter_text_should_draw_cursor ((ClutterText *) self);
}
static float
clutter_text_calculate_resource_scale (ClutterActor *actor,
int phase)
{
ClutterActorClass *parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class);
float new_resource_scale;
new_resource_scale = parent_class->calculate_resource_scale (actor, phase);
if (phase == 1)
return MAX (new_resource_scale, clutter_actor_get_real_resource_scale (actor));
return new_resource_scale;
}
static void
clutter_text_resource_scale_changed (ClutterActor *actor)
{
ClutterText *text = CLUTTER_TEXT (actor);
ClutterTextPrivate *priv = text->priv;
g_clear_pointer (&priv->effective_attrs, pango_attr_list_unref);
clutter_text_dirty_cache (text);
clutter_actor_queue_immediate_relayout (actor);
}
static void
clutter_text_im_focus (ClutterText *text)
{
@ -3816,8 +3814,6 @@ clutter_text_class_init (ClutterTextClass *klass)
actor_class->key_focus_in = clutter_text_key_focus_in;
actor_class->key_focus_out = clutter_text_key_focus_out;
actor_class->has_overlaps = clutter_text_has_overlaps;
actor_class->calculate_resource_scale = clutter_text_calculate_resource_scale;
actor_class->resource_scale_changed = clutter_text_resource_scale_changed;
/**
* ClutterText:buffer:
@ -4625,6 +4621,11 @@ clutter_text_init (ClutterText *self)
NULL);
priv->input_focus = clutter_text_input_focus_new (self);
priv->resource_scale_changed_id =
g_signal_connect (self, "notify::resource-scale",
G_CALLBACK (clutter_text_resource_scale_changed_cb),
NULL);
}
/**
@ -5326,7 +5327,7 @@ clutter_text_set_selection_bound (ClutterText *self,
if (priv->selection_bound != selection_bound)
{
gint len = clutter_text_buffer_get_length (get_buffer (self));
gint len = clutter_text_buffer_get_length (get_buffer (self));;
if (selection_bound < 0 || selection_bound >= len)
priv->selection_bound = -1;

View File

@ -95,34 +95,22 @@
#include "clutter-build-config.h"
#include "clutter-timeline.h"
#include "deprecated/clutter-timeline.h"
#include "clutter-debug.h"
#include "clutter-easing.h"
#include "clutter-enum-types.h"
#include "clutter-frame-clock.h"
#include "clutter-main.h"
#include "clutter-marshal.h"
#include "clutter-mutter.h"
#include "clutter-master-clock.h"
#include "clutter-private.h"
#include "clutter-scriptable.h"
#include "clutter-timeline-private.h"
#include "deprecated/clutter-timeline.h"
struct _ClutterTimelinePrivate
{
ClutterTimelineDirection direction;
ClutterFrameClock *custom_frame_clock;
ClutterFrameClock *frame_clock;
ClutterActor *frame_clock_actor;
gulong frame_clock_actor_stage_views_handler_id;
ClutterActor *actor;
gulong actor_destroy_handler_id;
gulong actor_stage_views_handler_id;
gulong stage_stage_views_handler_id;
ClutterActor *stage;
guint delay_id;
/* The total length in milliseconds of this timeline */
@ -184,14 +172,13 @@ enum
{
PROP_0,
PROP_ACTOR,
PROP_LOOP,
PROP_DELAY,
PROP_DURATION,
PROP_DIRECTION,
PROP_AUTO_REVERSE,
PROP_REPEAT_COUNT,
PROP_PROGRESS_MODE,
PROP_FRAME_CLOCK,
PROP_LAST
};
@ -212,8 +199,6 @@ enum
static guint timeline_signals[LAST_SIGNAL] = { 0, };
static void update_frame_clock (ClutterTimeline *timeline);
static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterTimeline, clutter_timeline, G_TYPE_OBJECT,
@ -305,196 +290,21 @@ clutter_timeline_add_marker_internal (ClutterTimeline *timeline,
g_hash_table_insert (priv->markers_by_name, marker->name, marker);
}
static void
on_actor_destroyed (ClutterActor *actor,
ClutterTimeline *timeline)
static inline void
clutter_timeline_set_loop_internal (ClutterTimeline *timeline,
gboolean loop)
{
ClutterTimelinePrivate *priv = timeline->priv;
gint old_repeat_count;
priv->actor = NULL;
}
old_repeat_count = timeline->priv->repeat_count;
/**
* clutter_timeline_get_actor:
* @timeline: a #ClutterTimeline
*
* Get the actor the timeline is associated with.
*
* Returns: (transfer none): the associated #ClutterActor
*/
ClutterActor *
clutter_timeline_get_actor (ClutterTimeline *timeline)
{
ClutterTimelinePrivate *priv = timeline->priv;
if (loop)
clutter_timeline_set_repeat_count (timeline, -1);
else
clutter_timeline_set_repeat_count (timeline, 0);
return priv->actor;
}
static void
maybe_add_timeline (ClutterTimeline *timeline)
{
ClutterTimelinePrivate *priv = timeline->priv;
if (!priv->frame_clock)
return;
clutter_frame_clock_add_timeline (priv->frame_clock, timeline);
}
static void
maybe_remove_timeline (ClutterTimeline *timeline)
{
ClutterTimelinePrivate *priv = timeline->priv;
if (!priv->frame_clock)
return;
clutter_frame_clock_remove_timeline (priv->frame_clock, timeline);
}
static void
set_frame_clock_internal (ClutterTimeline *timeline,
ClutterFrameClock *frame_clock)
{
ClutterTimelinePrivate *priv = timeline->priv;
if (priv->frame_clock == frame_clock)
return;
if (priv->frame_clock && priv->is_playing)
maybe_remove_timeline (timeline);
g_set_object (&priv->frame_clock, frame_clock);
g_object_notify_by_pspec (G_OBJECT (timeline),
obj_props[PROP_FRAME_CLOCK]);
if (priv->is_playing)
maybe_add_timeline (timeline);
}
static void
on_stage_stage_views_changed (ClutterActor *stage,
ClutterTimeline *timeline)
{
ClutterTimelinePrivate *priv = timeline->priv;
g_clear_signal_handler (&priv->stage_stage_views_handler_id, priv->stage);
priv->stage = NULL;
update_frame_clock (timeline);
}
static void
on_frame_clock_actor_stage_views_changed (ClutterActor *frame_clock_actor,
ClutterTimeline *timeline)
{
update_frame_clock (timeline);
}
static void
update_frame_clock (ClutterTimeline *timeline)
{
ClutterTimelinePrivate *priv = timeline->priv;
ClutterFrameClock *frame_clock = NULL;
ClutterActor *stage;
ClutterActor *frame_clock_actor;
if (!priv->actor)
goto out;
if (priv->frame_clock_actor)
{
g_clear_signal_handler (&priv->frame_clock_actor_stage_views_handler_id,
priv->frame_clock_actor);
g_clear_weak_pointer (&priv->frame_clock_actor);
}
frame_clock = clutter_actor_pick_frame_clock (priv->actor, &frame_clock_actor);
if (frame_clock)
{
g_set_weak_pointer (&priv->frame_clock_actor, frame_clock_actor);
priv->frame_clock_actor_stage_views_handler_id =
g_signal_connect (frame_clock_actor, "stage-views-changed",
G_CALLBACK (on_frame_clock_actor_stage_views_changed),
timeline);
g_clear_signal_handler (&priv->stage_stage_views_handler_id, priv->stage);
goto out;
}
stage = clutter_actor_get_stage (priv->actor);
if (!stage)
{
if (priv->is_playing)
g_warning ("Timelines with detached actors are not supported");
goto out;
}
if (priv->stage_stage_views_handler_id > 0)
goto out;
priv->stage_stage_views_handler_id =
g_signal_connect (stage, "stage-views-changed",
G_CALLBACK (on_stage_stage_views_changed),
timeline);
priv->stage = stage;
out:
set_frame_clock_internal (timeline, frame_clock);
}
static void
on_actor_stage_views_changed (ClutterActor *actor,
ClutterTimeline *timeline)
{
update_frame_clock (timeline);
}
/**
* clutter_timeline_set_actor:
* @timeline: a #ClutterTimeline
* @actor: (nullable): a #ClutterActor
*
* Set the actor the timeline is associated with.
*/
void
clutter_timeline_set_actor (ClutterTimeline *timeline,
ClutterActor *actor)
{
ClutterTimelinePrivate *priv = timeline->priv;
g_return_if_fail (!actor || (actor && !priv->custom_frame_clock));
if (priv->actor)
{
g_clear_signal_handler (&priv->actor_destroy_handler_id, priv->actor);
g_clear_signal_handler (&priv->actor_stage_views_handler_id, priv->actor);
g_clear_signal_handler (&priv->stage_stage_views_handler_id, priv->stage);
priv->stage = NULL;
priv->actor = NULL;
if (priv->is_playing)
maybe_remove_timeline (timeline);
priv->frame_clock = NULL;
}
priv->actor = actor;
if (priv->actor)
{
priv->actor_destroy_handler_id =
g_signal_connect (priv->actor, "destroy",
G_CALLBACK (on_actor_destroyed),
timeline);
priv->actor_stage_views_handler_id =
g_signal_connect (priv->actor, "stage-views-changed",
G_CALLBACK (on_actor_stage_views_changed),
timeline);
}
update_frame_clock (timeline);
if (old_repeat_count != timeline->priv->repeat_count)
g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_LOOP]);
}
/* Scriptable */
@ -638,8 +448,8 @@ clutter_timeline_set_property (GObject *object,
switch (prop_id)
{
case PROP_ACTOR:
clutter_timeline_set_actor (timeline, g_value_get_object (value));
case PROP_LOOP:
clutter_timeline_set_loop_internal (timeline, g_value_get_boolean (value));
break;
case PROP_DELAY:
@ -666,10 +476,6 @@ clutter_timeline_set_property (GObject *object,
clutter_timeline_set_progress_mode (timeline, g_value_get_enum (value));
break;
case PROP_FRAME_CLOCK:
clutter_timeline_set_frame_clock (timeline, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -687,8 +493,8 @@ clutter_timeline_get_property (GObject *object,
switch (prop_id)
{
case PROP_ACTOR:
g_value_set_object (value, priv->actor);
case PROP_LOOP:
g_value_set_boolean (value, priv->repeat_count != 0);
break;
case PROP_DELAY:
@ -715,10 +521,6 @@ clutter_timeline_get_property (GObject *object,
g_value_set_enum (value, priv->progress_mode);
break;
case PROP_FRAME_CLOCK:
g_value_set_object (value, priv->frame_clock);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -730,14 +532,16 @@ clutter_timeline_finalize (GObject *object)
{
ClutterTimeline *self = CLUTTER_TIMELINE (object);
ClutterTimelinePrivate *priv = self->priv;
ClutterMasterClock *master_clock;
if (priv->markers_by_name)
g_hash_table_destroy (priv->markers_by_name);
if (priv->is_playing)
maybe_remove_timeline (self);
g_clear_object (&priv->frame_clock);
{
master_clock = _clutter_master_clock_get_default ();
_clutter_master_clock_remove_timeline (master_clock, self);
}
G_OBJECT_CLASS (clutter_timeline_parent_class)->finalize (object);
}
@ -752,21 +556,6 @@ clutter_timeline_dispose (GObject *object)
clutter_timeline_cancel_delay (self);
if (priv->actor)
{
g_clear_signal_handler (&priv->actor_destroy_handler_id, priv->actor);
g_clear_signal_handler (&priv->actor_stage_views_handler_id, priv->actor);
g_clear_signal_handler (&priv->stage_stage_views_handler_id, priv->stage);
priv->actor = NULL;
}
if (priv->frame_clock_actor)
{
g_clear_signal_handler (&priv->frame_clock_actor_stage_views_handler_id,
priv->frame_clock_actor);
g_clear_weak_pointer (&priv->frame_clock_actor);
}
if (priv->progress_notify != NULL)
{
priv->progress_notify (priv->progress_data);
@ -784,17 +573,24 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
/**
* ClutterTimeline::actor:
* ClutterTimeline:loop:
*
* The actor the timeline is associated with. This will determine what frame
* clock will drive it.
* Whether the timeline should automatically rewind and restart.
*
* As a side effect, setting this property to %TRUE will set the
* #ClutterTimeline:repeat-count property to -1, while setting this
* property to %FALSE will set the #ClutterTimeline:repeat-count
* property to 0.
*
* Deprecated: 1.10: Use the #ClutterTimeline:repeat-count property instead.
*/
obj_props[PROP_ACTOR] =
g_param_spec_object ("actor",
P_("Actor"),
P_("Associated ClutterActor"),
CLUTTER_TYPE_ACTOR,
G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE);
obj_props[PROP_LOOP] =
g_param_spec_boolean ("loop",
P_("Loop"),
P_("Should the timeline automatically restart"),
FALSE,
CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED);
/**
* ClutterTimeline:delay:
*
@ -893,18 +689,6 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
CLUTTER_LINEAR,
CLUTTER_PARAM_READWRITE);
/**
* ClutterTimeline:frame-clock:
*
* The frame clock driving the timeline.
*/
obj_props[PROP_FRAME_CLOCK] =
g_param_spec_object ("frame-clock",
"Frame clock",
"Frame clock driving the timeline",
CLUTTER_TYPE_FRAME_CLOCK,
G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE);
object_class->dispose = clutter_timeline_dispose;
object_class->finalize = clutter_timeline_finalize;
object_class->set_property = clutter_timeline_set_property;
@ -1187,6 +971,7 @@ set_is_playing (ClutterTimeline *timeline,
gboolean is_playing)
{
ClutterTimelinePrivate *priv = timeline->priv;
ClutterMasterClock *master_clock;
is_playing = !!is_playing;
@ -1195,17 +980,15 @@ set_is_playing (ClutterTimeline *timeline,
priv->is_playing = is_playing;
master_clock = _clutter_master_clock_get_default ();
if (priv->is_playing)
{
priv->waiting_first_tick = TRUE;
priv->current_repeat = 0;
maybe_add_timeline (timeline);
_clutter_master_clock_add_timeline (master_clock, timeline);
}
else
{
maybe_remove_timeline (timeline);
}
_clutter_master_clock_remove_timeline (master_clock, timeline);
}
static gboolean
@ -1402,9 +1185,6 @@ clutter_timeline_start (ClutterTimeline *timeline)
if (priv->duration == 0)
return;
g_warn_if_fail ((priv->actor && clutter_actor_get_stage (priv->actor)) ||
priv->frame_clock);
if (priv->delay)
priv->delay_id = clutter_threads_add_timeout (priv->delay,
delay_timeout_func,
@ -1471,6 +1251,45 @@ clutter_timeline_stop (ClutterTimeline *timeline)
g_signal_emit (timeline, timeline_signals[STOPPED], 0, FALSE);
}
/**
* clutter_timeline_set_loop:
* @timeline: a #ClutterTimeline
* @loop: %TRUE for enable looping
*
* Sets whether @timeline should loop.
*
* This function is equivalent to calling clutter_timeline_set_repeat_count()
* with -1 if @loop is %TRUE, and with 0 if @loop is %FALSE.
*
* Deprecated: 1.10: Use clutter_timeline_set_repeat_count() instead.
*/
void
clutter_timeline_set_loop (ClutterTimeline *timeline,
gboolean loop)
{
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
clutter_timeline_set_loop_internal (timeline, loop);
}
/**
* clutter_timeline_get_loop:
* @timeline: a #ClutterTimeline
*
* Gets whether @timeline is looping
*
* Return value: %TRUE if the timeline is looping
*
* Deprecated: 1.10: Use clutter_timeline_get_repeat_count() instead.
*/
gboolean
clutter_timeline_get_loop (ClutterTimeline *timeline)
{
g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE);
return timeline->priv->repeat_count != 0;
}
/**
* clutter_timeline_rewind:
* @timeline: A #ClutterTimeline
@ -1587,10 +1406,48 @@ clutter_timeline_is_playing (ClutterTimeline *timeline)
}
/**
* clutter_timeline_new:
* @duration_ms: Duration of the timeline in milliseconds
* clutter_timeline_clone:
* @timeline: #ClutterTimeline to duplicate.
*
* Creates a new #ClutterTimeline with a duration of @duration_ms milli seconds.
* Create a new #ClutterTimeline instance which has property values
* matching that of supplied timeline. The cloned timeline will not
* be started and will not be positioned to the current position of
* the original @timeline: you will have to start it with
* clutter_timeline_start().
*
* The only cloned properties are:
*
* - #ClutterTimeline:duration
* - #ClutterTimeline:loop
* - #ClutterTimeline:delay
* - #ClutterTimeline:direction
*
* Return value: (transfer full): a new #ClutterTimeline, cloned
* from @timeline
*
* Since: 0.4
*
* Deprecated: 1.10: Use clutter_timeline_new() or g_object_new()
* instead
*/
ClutterTimeline *
clutter_timeline_clone (ClutterTimeline *timeline)
{
g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL);
return g_object_new (CLUTTER_TYPE_TIMELINE,
"duration", timeline->priv->duration,
"loop", timeline->priv->repeat_count != 0,
"delay", timeline->priv->delay,
"direction", timeline->priv->direction,
NULL);
}
/**
* clutter_timeline_new:
* @msecs: Duration of the timeline in milliseconds
*
* Creates a new #ClutterTimeline with a duration of @msecs.
*
* Return value: the newly created #ClutterTimeline instance. Use
* g_object_unref() when done using it
@ -1598,50 +1455,10 @@ clutter_timeline_is_playing (ClutterTimeline *timeline)
* Since: 0.6
*/
ClutterTimeline *
clutter_timeline_new (guint duration_ms)
clutter_timeline_new (guint msecs)
{
return g_object_new (CLUTTER_TYPE_TIMELINE,
"duration", duration_ms,
NULL);
}
/**
* clutter_timeline_new_for_actor:
* @actor: The #ClutterActor the timeline is associated with
* @duration_ms: Duration of the timeline in milliseconds
*
* Creates a new #ClutterTimeline with a duration of @duration milli seconds.
*
* Return value: the newly created #ClutterTimeline instance. Use
* g_object_unref() when done using it
*/
ClutterTimeline *
clutter_timeline_new_for_actor (ClutterActor *actor,
unsigned int duration_ms)
{
return g_object_new (CLUTTER_TYPE_TIMELINE,
"duration", duration_ms,
"actor", actor,
NULL);
}
/**
* clutter_timeline_new_for_frame_clock:
* @frame_clock: The #ClutterFrameClock the timeline is driven by
* @duration_ms: Duration of the timeline in milliseconds
*
* Creates a new #ClutterTimeline with a duration of @duration_ms milli seconds.
*
* Return value: the newly created #ClutterTimeline instance. Use
* g_object_unref() when done using it
*/
ClutterTimeline *
clutter_timeline_new_for_frame_clock (ClutterFrameClock *frame_clock,
unsigned int duration_ms)
{
return g_object_new (CLUTTER_TYPE_TIMELINE,
"duration", duration_ms,
"frame-clock", frame_clock,
"duration", msecs,
NULL);
}
@ -1907,7 +1724,7 @@ _clutter_timeline_do_tick (ClutterTimeline *timeline,
/* Check the is_playing variable before performing the timeline tick.
* This is necessary, as if a timeline is stopped in response to a
* frame clock generated signal of a different timeline, this code can
* master-clock generated signal of a different timeline, this code can
* still be reached.
*/
if (!priv->is_playing)
@ -2725,32 +2542,3 @@ clutter_timeline_get_cubic_bezier_progress (ClutterTimeline *timeline,
return TRUE;
}
/**
* clutter_timeline_get_frame_clock: (skip)
*/
ClutterFrameClock *
clutter_timeline_get_frame_clock (ClutterTimeline *timeline)
{
g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL);
return timeline->priv->frame_clock;
}
void
clutter_timeline_set_frame_clock (ClutterTimeline *timeline,
ClutterFrameClock *frame_clock)
{
ClutterTimelinePrivate *priv;
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
priv = timeline->priv;
g_assert (!frame_clock || (frame_clock && !priv->actor));
g_return_if_fail (!frame_clock || (frame_clock && !priv->actor));
priv->custom_frame_clock = frame_clock;
if (!priv->actor)
set_frame_clock_internal (timeline, frame_clock);
}

View File

@ -119,19 +119,7 @@ CLUTTER_EXPORT
GType clutter_timeline_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterTimeline * clutter_timeline_new_for_actor (ClutterActor *actor,
unsigned int duration_ms);
CLUTTER_EXPORT
ClutterTimeline * clutter_timeline_new_for_frame_clock (ClutterFrameClock *frame_clock,
unsigned int duration_ms);
CLUTTER_EXPORT
ClutterActor * clutter_timeline_get_actor (ClutterTimeline *timeline);
CLUTTER_EXPORT
void clutter_timeline_set_actor (ClutterTimeline *timeline,
ClutterActor *actor);
ClutterTimeline * clutter_timeline_new (guint msecs);
CLUTTER_EXPORT
guint clutter_timeline_get_duration (ClutterTimeline *timeline);
@ -233,13 +221,6 @@ gint64 clutter_timeline_get_duration_hint
CLUTTER_EXPORT
gint clutter_timeline_get_current_repeat (ClutterTimeline *timeline);
CLUTTER_EXPORT
ClutterFrameClock * clutter_timeline_get_frame_clock (ClutterTimeline *timeline);
CLUTTER_EXPORT
void clutter_timeline_set_frame_clock (ClutterTimeline *timeline,
ClutterFrameClock *frame_clock);
G_END_DECLS
#endif /* _CLUTTER_TIMELINE_H__ */

View File

@ -43,7 +43,6 @@
#include "clutter-debug.h"
#include "clutter-private.h"
#include "clutter-timeline-private.h"
struct _ClutterTransitionGroupPrivate
{

View File

@ -364,7 +364,6 @@ clutter_transition_set_animatable (ClutterTransition *transition,
ClutterAnimatable *animatable)
{
ClutterTransitionPrivate *priv;
ClutterActor *actor;
g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
g_return_if_fail (animatable == NULL || CLUTTER_IS_ANIMATABLE (animatable));
@ -384,9 +383,6 @@ clutter_transition_set_animatable (ClutterTransition *transition,
priv->animatable = g_object_ref (animatable);
clutter_transition_attach (transition, priv->animatable);
}
actor = clutter_animatable_get_actor (animatable);
clutter_timeline_set_actor (CLUTTER_TIMELINE (transition), actor);
}
/**

View File

@ -57,7 +57,6 @@ typedef struct _ClutterActorIter ClutterActorIter;
typedef struct _ClutterPaintNode ClutterPaintNode;
typedef struct _ClutterContent ClutterContent; /* dummy */
typedef struct _ClutterScrollActor ClutterScrollActor;
typedef struct _ClutterFrameClock ClutterFrameClock;
typedef struct _ClutterInterval ClutterInterval;
typedef struct _ClutterAnimatable ClutterAnimatable; /* dummy */
@ -175,20 +174,6 @@ struct _ClutterActorBox
*/
#define CLUTTER_ACTOR_BOX_INIT_ZERO CLUTTER_ACTOR_BOX_INIT (0.f, 0.f, 0.f, 0.f)
/**
* CLUTTER_ACTOR_BOX_UNINITIALIZED:
*
* A simple macro for creating a #ClutterActorBox with a size of -1 when
* declaring it, e.g.:
*
* |[
* ClutterActorBox box = CLUTTER_ACTOR_BOX_UNINITIALIZED;
* ]|
*/
#define CLUTTER_ACTOR_BOX_UNINITIALIZED { .x1 = INFINITY, .y1 = INFINITY, .x2 = -INFINITY, .y2 = -INFINITY }
CLUTTER_EXPORT
GType clutter_actor_box_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
@ -267,9 +252,6 @@ CLUTTER_EXPORT
void clutter_actor_box_scale (ClutterActorBox *box,
gfloat scale);
CLUTTER_EXPORT
gboolean clutter_actor_box_is_initialized (ClutterActorBox *box);
/**
* ClutterKnot:
* @x: X coordinate of the knot

View File

@ -63,9 +63,9 @@
#include "clutter-feature.h"
#include "clutter-fixed-layout.h"
#include "clutter-flow-layout.h"
#include "clutter-frame-clock.h"
#include "clutter-gesture-action.h"
#include "clutter-grid-layout.h"
#include "clutter-group.h"
#include "clutter-image.h"
#include "clutter-input-device.h"
#include "clutter-input-device-tool.h"

View File

@ -47,7 +47,6 @@
#include "clutter-private.h"
#include "clutter-stage-private.h"
#include "clutter-stage-view-private.h"
#include "cogl.h"
#define MAX_STACK_RECTS 256
@ -56,25 +55,17 @@ typedef struct _ClutterStageViewCoglPrivate
/* Damage history, in stage view render target framebuffer coordinate space.
*/
ClutterDamageHistory *damage_history;
guint notify_presented_handle_id;
} ClutterStageViewCoglPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageViewCogl, clutter_stage_view_cogl,
CLUTTER_TYPE_STAGE_VIEW)
typedef struct _ClutterStageCoglPrivate
{
int64_t global_frame_counter;
} ClutterStageCoglPrivate;
static void
clutter_stage_window_iface_init (ClutterStageWindowInterface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterStageCogl,
_clutter_stage_cogl,
G_TYPE_OBJECT,
G_ADD_PRIVATE (ClutterStageCogl)
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init));
@ -86,12 +77,67 @@ enum
PROP_LAST
};
static void
clutter_stage_cogl_schedule_update (ClutterStageWindow *stage_window,
gint sync_delay);
static void
clutter_stage_cogl_unrealize (ClutterStageWindow *stage_window)
{
CLUTTER_NOTE (BACKEND, "Unrealizing Cogl stage [%p]", stage_window);
}
void
_clutter_stage_cogl_presented (ClutterStageCogl *stage_cogl,
CoglFrameEvent frame_event,
ClutterFrameInfo *frame_info)
{
if (frame_event == COGL_FRAME_EVENT_SYNC)
{
/* Early versions of the swap_event implementation in Mesa
* deliver BufferSwapComplete event when not selected for,
* so if we get a swap event we aren't expecting, just ignore it.
*
* https://bugs.freedesktop.org/show_bug.cgi?id=27962
*
* FIXME: This issue can be hidden inside Cogl so we shouldn't
* need to care about this bug here.
*/
if (stage_cogl->pending_swaps > 0)
stage_cogl->pending_swaps--;
}
else if (frame_event == COGL_FRAME_EVENT_COMPLETE)
{
gint64 presentation_time_cogl = frame_info->presentation_time;
if (presentation_time_cogl != 0)
{
ClutterBackend *backend = stage_cogl->backend;
CoglContext *context = clutter_backend_get_cogl_context (backend);
gint64 current_time_cogl = cogl_get_clock_time (context);
gint64 now = g_get_monotonic_time ();
stage_cogl->last_presentation_time =
now + (presentation_time_cogl - current_time_cogl) / 1000;
}
stage_cogl->refresh_rate = frame_info->refresh_rate;
}
_clutter_stage_presented (stage_cogl->wrapper, frame_event, frame_info);
if (frame_event == COGL_FRAME_EVENT_COMPLETE &&
stage_cogl->update_time != -1)
{
ClutterStageWindow *stage_window = CLUTTER_STAGE_WINDOW (stage_cogl);
stage_cogl->update_time = -1;
clutter_stage_cogl_schedule_update (stage_window,
stage_cogl->last_sync_delay);
}
}
static gboolean
clutter_stage_cogl_realize (ClutterStageWindow *stage_window)
{
@ -112,14 +158,101 @@ clutter_stage_cogl_realize (ClutterStageWindow *stage_window)
return TRUE;
}
static int64_t
clutter_stage_cogl_get_frame_counter (ClutterStageWindow *stage_window)
static void
clutter_stage_cogl_schedule_update (ClutterStageWindow *stage_window,
gint sync_delay)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
ClutterStageCoglPrivate *priv =
_clutter_stage_cogl_get_instance_private (stage_cogl);
gint64 now;
float refresh_rate;
gint64 refresh_interval;
int64_t min_render_time_allowed;
int64_t max_render_time_allowed;
int64_t next_presentation_time;
return priv->global_frame_counter;
if (stage_cogl->update_time != -1)
return;
stage_cogl->last_sync_delay = sync_delay;
now = g_get_monotonic_time ();
if (sync_delay < 0)
{
stage_cogl->update_time = now;
return;
}
refresh_rate = stage_cogl->refresh_rate;
if (refresh_rate <= 0.0)
refresh_rate = clutter_get_default_frame_rate ();
refresh_interval = (gint64) (0.5 + G_USEC_PER_SEC / refresh_rate);
if (refresh_interval == 0)
{
stage_cogl->update_time = now;
return;
}
min_render_time_allowed = refresh_interval / 2;
max_render_time_allowed = refresh_interval - 1000 * sync_delay;
/* Be robust in the case of incredibly bogus refresh rate */
if (max_render_time_allowed <= 0)
{
g_warning ("Unsupported monitor refresh rate detected. "
"(Refresh rate: %.3f, refresh interval: %" G_GINT64_FORMAT ")",
refresh_rate,
refresh_interval);
stage_cogl->update_time = now;
return;
}
if (min_render_time_allowed > max_render_time_allowed)
min_render_time_allowed = max_render_time_allowed;
next_presentation_time = stage_cogl->last_presentation_time + refresh_interval;
/* Get next_presentation_time closer to its final value, to reduce
* the number of while iterations below.
*/
if (next_presentation_time < now)
{
int64_t last_virtual_presentation_time = now - now % refresh_interval;
int64_t hardware_clock_phase =
stage_cogl->last_presentation_time % refresh_interval;
next_presentation_time =
last_virtual_presentation_time + hardware_clock_phase;
}
while (next_presentation_time < now + min_render_time_allowed)
next_presentation_time += refresh_interval;
stage_cogl->update_time = next_presentation_time - max_render_time_allowed;
if (stage_cogl->update_time == stage_cogl->last_update_time)
stage_cogl->update_time = stage_cogl->last_update_time + refresh_interval;
}
static gint64
clutter_stage_cogl_get_update_time (ClutterStageWindow *stage_window)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
if (stage_cogl->pending_swaps)
return -1; /* in the future, indefinite */
return stage_cogl->update_time;
}
static void
clutter_stage_cogl_clear_update_time (ClutterStageWindow *stage_window)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
stage_cogl->last_update_time = stage_cogl->update_time;
stage_cogl->update_time = -1;
}
static ClutterActor *
@ -222,35 +355,12 @@ paint_damage_region (ClutterStageWindow *stage_window,
cogl_framebuffer_pop_matrix (framebuffer);
}
typedef struct _NotifyPresentedClosure
{
ClutterStageView *view;
ClutterFrameInfo frame_info;
} NotifyPresentedClosure;
static gboolean
notify_presented_idle (gpointer user_data)
{
NotifyPresentedClosure *closure = user_data;
ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (closure->view);
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
view_priv->notify_presented_handle_id = 0;
clutter_stage_view_notify_presented (closure->view, &closure->frame_info);
return G_SOURCE_REMOVE;
}
static void
swap_framebuffer (ClutterStageWindow *stage_window,
ClutterStageView *view,
cairo_region_t *swap_region,
gboolean swap_with_damage)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
ClutterStageCoglPrivate *priv =
_clutter_stage_cogl_get_instance_private (stage_cogl);
CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
clutter_stage_view_before_swap_buffer (view, swap_region);
@ -259,7 +369,6 @@ swap_framebuffer (ClutterStageWindow *stage_window,
{
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
int *damage, n_rects, i;
CoglFrameInfo *frame_info;
n_rects = cairo_region_num_rectangles (swap_region);
damage = g_newa (int, n_rects * 4);
@ -274,9 +383,6 @@ swap_framebuffer (ClutterStageWindow *stage_window,
damage[i * 4 + 3] = rect.height;
}
frame_info = cogl_frame_info_new (priv->global_frame_counter);
priv->global_frame_counter++;
/* push on the screen */
if (n_rects > 0 && !swap_with_damage)
{
@ -285,8 +391,9 @@ swap_framebuffer (ClutterStageWindow *stage_window,
onscreen);
cogl_onscreen_swap_region (onscreen,
damage, n_rects,
frame_info);
damage, n_rects);
return FALSE;
}
else
{
@ -294,35 +401,18 @@ swap_framebuffer (ClutterStageWindow *stage_window,
onscreen);
cogl_onscreen_swap_buffers_with_damage (onscreen,
damage, n_rects,
frame_info);
damage, n_rects);
return TRUE;
}
}
else
{
ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
NotifyPresentedClosure *closure;
CLUTTER_NOTE (BACKEND, "cogl_framebuffer_finish (framebuffer: %p)",
framebuffer);
cogl_framebuffer_finish (framebuffer);
closure = g_new0 (NotifyPresentedClosure, 1);
closure->view = view;
closure->frame_info = (ClutterFrameInfo) {
.frame_counter = priv->global_frame_counter,
.refresh_rate = clutter_stage_view_get_refresh_rate (view),
.presentation_time = g_get_monotonic_time (),
};
priv->global_frame_counter++;
g_warn_if_fail (view_priv->notify_presented_handle_id == 0);
view_priv->notify_presented_handle_id =
g_idle_add_full (G_PRIORITY_DEFAULT,
notify_presented_idle,
closure, g_free);
return FALSE;
}
}
@ -449,11 +539,11 @@ is_buffer_age_enabled (void)
cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE);
}
static void
clutter_stage_cogl_redraw_view_primary (ClutterStageCogl *stage_cogl,
ClutterStageView *view)
static gboolean
clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
ClutterStageView *view)
{
ClutterStageWindow *stage_window = CLUTTER_STAGE_WINDOW (stage_cogl);
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
@ -461,7 +551,7 @@ clutter_stage_cogl_redraw_view_primary (ClutterStageCogl *stage_cogl,
CoglFramebuffer *onscreen = clutter_stage_view_get_onscreen (view);
cairo_rectangle_int_t view_rect;
gboolean is_full_redraw;
gboolean use_clipped_redraw = TRUE;
gboolean use_clipped_redraw;
gboolean can_blit_sub_buffer;
gboolean has_buffer_age;
gboolean swap_with_damage;
@ -471,7 +561,8 @@ clutter_stage_cogl_redraw_view_primary (ClutterStageCogl *stage_cogl,
cairo_region_t *swap_region;
float fb_scale;
int fb_width, fb_height;
int buffer_age = 0;
int buffer_age;
gboolean res;
clutter_stage_view_get_layout (view, &view_rect);
fb_scale = clutter_stage_view_get_scale (view);
@ -538,7 +629,7 @@ clutter_stage_cogl_redraw_view_primary (ClutterStageCogl *stage_cogl,
redraw_clip = cairo_region_create_rectangle (&view_rect);
}
g_return_if_fail (!cairo_region_is_empty (fb_clip_region));
g_return_val_if_fail (!cairo_region_is_empty (fb_clip_region), FALSE);
swap_with_damage = FALSE;
if (has_buffer_age)
@ -639,12 +730,14 @@ clutter_stage_cogl_redraw_view_primary (ClutterStageCogl *stage_cogl,
cairo_region_destroy (queued_redraw_clip);
}
swap_framebuffer (stage_window,
view,
swap_region,
swap_with_damage);
res = swap_framebuffer (stage_window,
view,
swap_region,
swap_with_damage);
cairo_region_destroy (swap_region);
return res;
}
static void
@ -652,34 +745,62 @@ clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl,
ClutterStageView *view,
CoglScanout *scanout)
{
ClutterStageCoglPrivate *priv =
_clutter_stage_cogl_get_instance_private (stage_cogl);
CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
CoglOnscreen *onscreen;
CoglFrameInfo *frame_info;
g_return_if_fail (cogl_is_onscreen (framebuffer));
onscreen = COGL_ONSCREEN (framebuffer);
frame_info = cogl_frame_info_new (priv->global_frame_counter);
priv->global_frame_counter++;
cogl_onscreen_direct_scanout (onscreen, scanout, frame_info);
cogl_onscreen_direct_scanout (onscreen, scanout);
}
static void
clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
ClutterStageView *view)
clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
g_autoptr (CoglScanout) scanout = NULL;
gboolean swap_event = FALSE;
GList *l;
scanout = clutter_stage_view_take_scanout (view);
if (scanout)
clutter_stage_cogl_scanout_view (stage_cogl, view, scanout);
else
clutter_stage_cogl_redraw_view_primary (stage_cogl, view);
COGL_TRACE_BEGIN (ClutterStageCoglRedraw, "Paint (Cogl Redraw)");
for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
{
ClutterStageView *view = l->data;
g_autoptr (CoglScanout) scanout = NULL;
if (!clutter_stage_view_has_redraw_clip (view))
continue;
scanout = clutter_stage_view_take_scanout (view);
if (scanout)
{
clutter_stage_cogl_scanout_view (stage_cogl,
view,
scanout);
swap_event = TRUE;
}
else
{
swap_event |= clutter_stage_cogl_redraw_view (stage_window, view);
}
}
_clutter_stage_emit_after_paint (stage_cogl->wrapper);
_clutter_stage_window_finish_frame (stage_window);
if (swap_event)
{
/* If we have swap buffer events then cogl_onscreen_swap_buffers
* will return immediately and we need to track that there is a
* swap in progress... */
if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
stage_cogl->pending_swaps++;
}
stage_cogl->frame_count++;
COGL_TRACE_END (ClutterStageCoglRedraw);
}
static void
@ -691,8 +812,10 @@ clutter_stage_window_iface_init (ClutterStageWindowInterface *iface)
iface->resize = clutter_stage_cogl_resize;
iface->show = clutter_stage_cogl_show;
iface->hide = clutter_stage_cogl_hide;
iface->get_frame_counter = clutter_stage_cogl_get_frame_counter;
iface->redraw_view = clutter_stage_cogl_redraw_view;
iface->schedule_update = clutter_stage_cogl_schedule_update;
iface->get_update_time = clutter_stage_cogl_get_update_time;
iface->clear_update_time = clutter_stage_cogl_clear_update_time;
iface->redraw = clutter_stage_cogl_redraw;
}
static void
@ -733,56 +856,22 @@ _clutter_stage_cogl_class_init (ClutterStageCoglClass *klass)
static void
_clutter_stage_cogl_init (ClutterStageCogl *stage)
{
stage->last_presentation_time = 0;
stage->refresh_rate = 0.0;
stage->update_time = -1;
}
static void
frame_cb (CoglOnscreen *onscreen,
CoglFrameEvent frame_event,
CoglFrameInfo *frame_info,
void *user_data)
{
ClutterStageView *view = user_data;
ClutterFrameInfo clutter_frame_info;
if (frame_event == COGL_FRAME_EVENT_SYNC)
return;
clutter_frame_info = (ClutterFrameInfo) {
.frame_counter = cogl_frame_info_get_global_frame_counter (frame_info),
.refresh_rate = cogl_frame_info_get_refresh_rate (frame_info),
.presentation_time = ns2us (cogl_frame_info_get_presentation_time (frame_info)),
};
clutter_stage_view_notify_presented (view, &clutter_frame_info);
}
static void
on_framebuffer_set (ClutterStageView *view)
{
CoglFramebuffer *framebuffer;
framebuffer = clutter_stage_view_get_onscreen (view);
if (framebuffer && cogl_is_onscreen (framebuffer))
{
cogl_onscreen_add_frame_callback (COGL_ONSCREEN (framebuffer),
frame_cb,
view,
NULL);
}
}
static void
clutter_stage_view_cogl_dispose (GObject *object)
clutter_stage_view_cogl_finalize (GObject *object)
{
ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (object);
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
g_clear_handle_id (&view_priv->notify_presented_handle_id, g_source_remove);
g_clear_pointer (&view_priv->damage_history, clutter_damage_history_free);
clutter_damage_history_free (view_priv->damage_history);
G_OBJECT_CLASS (clutter_stage_view_cogl_parent_class)->dispose (object);
G_OBJECT_CLASS (clutter_stage_view_cogl_parent_class)->finalize (object);
}
static void
@ -792,9 +881,6 @@ clutter_stage_view_cogl_init (ClutterStageViewCogl *view_cogl)
clutter_stage_view_cogl_get_instance_private (view_cogl);
view_priv->damage_history = clutter_damage_history_new ();
g_signal_connect (view_cogl, "notify::framebuffer",
G_CALLBACK (on_framebuffer_set), NULL);
}
static void
@ -802,5 +888,5 @@ clutter_stage_view_cogl_class_init (ClutterStageViewCoglClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = clutter_stage_view_cogl_dispose;
object_class->finalize = clutter_stage_view_cogl_finalize;
}

View File

@ -41,6 +41,20 @@ struct _ClutterStageCogl
/* back pointer to the backend */
ClutterBackend *backend;
float refresh_rate;
int pending_swaps;
gint64 last_presentation_time;
gint64 update_time;
int64_t last_update_time;
/* We only enable clipped redraws after 2 frames, since we've seen
* a lot of drivers can struggle to get going and may output some
* junk frames to start with. */
unsigned int frame_count;
gint last_sync_delay;
};
struct _ClutterStageCoglClass

View File

@ -0,0 +1,114 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* 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
* 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/>.
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_ACTOR_DEPRECATED_H__
#define __CLUTTER_ACTOR_DEPRECATED_H__
#include <clutter/clutter-types.h>
G_BEGIN_DECLS
CLUTTER_DEPRECATED
ClutterActor * clutter_get_actor_by_gid (guint32 id_);
CLUTTER_DEPRECATED_FOR(clutter_actor_add_child)
void clutter_actor_set_parent (ClutterActor *self,
ClutterActor *parent);
CLUTTER_DEPRECATED_FOR(clutter_actor_remove_child)
void clutter_actor_unparent (ClutterActor *self);
CLUTTER_DEPRECATED
void clutter_actor_push_internal (ClutterActor *self);
CLUTTER_DEPRECATED
void clutter_actor_pop_internal (ClutterActor *self);
CLUTTER_DEPRECATED
void clutter_actor_show_all (ClutterActor *self);
CLUTTER_DEPRECATED_FOR(clutter_actor_set_z_position)
void clutter_actor_set_depth (ClutterActor *self,
gfloat depth);
CLUTTER_DEPRECATED_FOR(clutter_actor_get_z_position)
gfloat clutter_actor_get_depth (ClutterActor *self);
CLUTTER_DEPRECATED_FOR(clutter_actor_set_rotation_angle)
void clutter_actor_set_rotation (ClutterActor *self,
ClutterRotateAxis axis,
gdouble angle,
gfloat x,
gfloat y,
gfloat z);
CLUTTER_DEPRECATED_FOR(clutter_actor_set_rotation_angle and clutter_actor_set_pivot_point)
void clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
gdouble angle,
ClutterGravity gravity);
CLUTTER_DEPRECATED_FOR(clutter_actor_get_rotation_angle)
gdouble clutter_actor_get_rotation (ClutterActor *self,
ClutterRotateAxis axis,
gfloat *x,
gfloat *y,
gfloat *z);
CLUTTER_DEPRECATED
ClutterGravity clutter_actor_get_z_rotation_gravity (ClutterActor *self);
CLUTTER_DEPRECATED_FOR(clutter_actor_set_scale and clutter_actor_set_pivot_point)
void clutter_actor_set_scale_full (ClutterActor *self,
gdouble scale_x,
gdouble scale_y,
gfloat center_x,
gfloat center_y);
CLUTTER_DEPRECATED_FOR(clutter_actor_get_pivot_point)
void clutter_actor_get_scale_center (ClutterActor *self,
gfloat *center_x,
gfloat *center_y);
CLUTTER_DEPRECATED_FOR(clutter_actor_get_pivot_point)
ClutterGravity clutter_actor_get_scale_gravity (ClutterActor *self);
CLUTTER_DEPRECATED
void clutter_actor_set_anchor_point (ClutterActor *self,
gfloat anchor_x,
gfloat anchor_y);
CLUTTER_DEPRECATED
void clutter_actor_move_anchor_point (ClutterActor *self,
gfloat anchor_x,
gfloat anchor_y);
CLUTTER_DEPRECATED
ClutterGravity clutter_actor_get_anchor_point_gravity (ClutterActor *self);
CLUTTER_DEPRECATED
void clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
ClutterGravity gravity);
CLUTTER_DEPRECATED
void clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
ClutterGravity gravity);
G_END_DECLS
#endif /* __CLUTTER_ACTOR_DEPRECATED_H__ */

View File

@ -0,0 +1,745 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009,2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author:
* Emmanuele Bassi <ebassi@linux.intel.com>
*/
/**
* SECTION:clutter-box
* @short_description: A Generic layout container
*
* #ClutterBox is a #ClutterActor sub-class implementing the #ClutterContainer
* interface. A Box delegates the whole size requisition and size allocation to
* a #ClutterLayoutManager instance.
*
* #ClutterBox is available since Clutter 1.2
*
* #ClutterBox is deprecated since Clutter 1.10; all its relevant API is provided
* by #ClutterActor, via the #ClutterActor:layout-manager property.
*
* ## Using ClutterBox
*
* The following code shows how to create a #ClutterBox with
* a #ClutterLayoutManager sub-class, and how to add children to
* it via clutter_box_pack().
*
* |[<!-- language="C" -->
* ClutterActor *box;
* ClutterLayoutManager *layout;
*
* // Create the layout manager first
* layout = clutter_box_layout_new ();
* clutter_box_layout_set_homogeneous (CLUTTER_BOX_LAYOUT (layout), TRUE);
* clutter_box_layout_set_spacing (CLUTTER_BOX_LAYOUT (layout), 12);
*
* // Then create the ClutterBox actor. The Box will take
* // ownership of the ClutterLayoutManager instance by sinking
* // its floating reference
* box = clutter_box_new (layout);
*
* // Now add children to the Box using the variadic arguments
* // function clutter_box_pack() to set layout properties
* clutter_box_pack (CLUTTER_BOX (box), actor,
* "x-align", CLUTTER_BOX_ALIGNMENT_CENTER,
* "y-align", CLUTTER_BOX_ALIGNMENT_END,
* "expand", TRUE,
* NULL);
* ]|
*
* #ClutterBox's clutter_box_pack() wraps the generic
* clutter_container_add_actor() function, but it also allows setting
* layout properties while adding the new child to the box.
*/
#include "clutter-build-config.h"
#include <glib-object.h>
#include <gobject/gvaluecollector.h>
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include "deprecated/clutter-container.h"
#include "clutter-box.h"
#include "clutter-actor-private.h"
#include "clutter-color.h"
#include "clutter-debug.h"
#include "clutter-enum-types.h"
#include "clutter-marshal.h"
#include "clutter-private.h"
struct _ClutterBoxPrivate
{
ClutterLayoutManager *manager;
guint changed_id;
};
enum
{
PROP_0,
PROP_COLOR,
PROP_COLOR_SET,
PROP_LAST
};
static GParamSpec *obj_props[PROP_LAST] = { NULL, };
static const ClutterColor default_box_color = { 255, 255, 255, 255 };
G_DEFINE_TYPE_WITH_PRIVATE (ClutterBox, clutter_box, CLUTTER_TYPE_ACTOR)
static inline void
clutter_box_set_color_internal (ClutterBox *box,
const ClutterColor *color)
{
clutter_actor_set_background_color (CLUTTER_ACTOR (box), color);
g_object_notify_by_pspec (G_OBJECT (box), obj_props[PROP_COLOR_SET]);
g_object_notify_by_pspec (G_OBJECT (box), obj_props[PROP_COLOR]);
}
static gboolean
clutter_box_real_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
gboolean retval = FALSE;
ClutterActorIter iter;
ClutterActor *child;
/* if we have a background color, and an allocation, then we need to
* set it as the base of our paint volume
*/
retval = clutter_paint_volume_set_from_allocation (volume, actor);
/* bail out early if we don't have any child */
if (clutter_actor_get_n_children (actor) == 0)
return retval;
retval = TRUE;
/* otherwise, union the paint volumes of our children, in case
* any one of them decides to paint outside the parent's allocation
*/
clutter_actor_iter_init (&iter, actor);
while (clutter_actor_iter_next (&iter, &child))
{
const ClutterPaintVolume *child_volume;
/* This gets the paint volume of the child transformed into the
* group's coordinate space... */
child_volume = clutter_actor_get_transformed_paint_volume (child, actor);
if (!child_volume)
return FALSE;
clutter_paint_volume_union (volume, child_volume);
}
return retval;
}
static void
clutter_box_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterBox *self = CLUTTER_BOX (gobject);
switch (prop_id)
{
case PROP_COLOR:
clutter_box_set_color_internal (self, clutter_value_get_color (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_box_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
case PROP_COLOR:
{
ClutterColor color;
clutter_actor_get_background_color (CLUTTER_ACTOR (gobject),
&color);
clutter_value_set_color (value, &color);
}
break;
case PROP_COLOR_SET:
{
gboolean color_set;
g_object_get (gobject, "background-color-set", &color_set, NULL);
g_value_set_boolean (value, color_set);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
clutter_box_real_destroy (ClutterActor *actor)
{
ClutterActor *iter;
iter = clutter_actor_get_first_child (actor);
while (iter != NULL)
{
ClutterActor *next = clutter_actor_get_next_sibling (iter);
clutter_actor_destroy (iter);
iter = next;
}
}
static void
clutter_box_class_init (ClutterBoxClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
actor_class->destroy = clutter_box_real_destroy;
actor_class->get_paint_volume = clutter_box_real_get_paint_volume;
gobject_class->set_property = clutter_box_set_property;
gobject_class->get_property = clutter_box_get_property;
/**
* ClutterBox:color:
*
* The color to be used to paint the background of the
* #ClutterBox. Setting this property will set the
* #ClutterBox:color-set property as a side effect
*
* This property sets the #ClutterActor:background-color property
* internally.
*
* Since: 1.2
*
* Deprecated: 1.10: Use the #ClutterActor:background-color property
*/
obj_props[PROP_COLOR] =
clutter_param_spec_color ("color",
P_("Color"),
P_("The background color of the box"),
&default_box_color,
CLUTTER_PARAM_READWRITE);
/**
* ClutterBox:color-set:
*
* Whether the #ClutterBox:color property has been set.
*
* This property reads the #ClutterActor:background-color-set property
* internally.
*
* Since: 1.2
*
* Deprecated: 1.10: Use the #ClutterActor:background-color-set property
*/
obj_props[PROP_COLOR_SET] =
g_param_spec_boolean ("color-set",
P_("Color Set"),
P_("Whether the background color is set"),
FALSE,
CLUTTER_PARAM_READWRITE);
g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
}
static void
clutter_box_init (ClutterBox *self)
{
self->priv = clutter_box_get_instance_private (self);
}
/**
* clutter_box_new:
* @manager: a #ClutterLayoutManager
*
* Creates a new #ClutterBox. The children of the box will be layed
* out by the passed @manager
*
* Return value: the newly created #ClutterBox actor
*
* Since: 1.2
*
* Deprecated: 1.10: Use clutter_actor_new() instead.
*/
ClutterActor *
clutter_box_new (ClutterLayoutManager *manager)
{
g_return_val_if_fail (CLUTTER_IS_LAYOUT_MANAGER (manager), NULL);
return g_object_new (CLUTTER_TYPE_BOX,
"layout-manager", manager,
NULL);
}
/**
* clutter_box_set_layout_manager:
* @box: a #ClutterBox
* @manager: a #ClutterLayoutManager
*
* Sets the #ClutterLayoutManager for @box
*
* A #ClutterLayoutManager is a delegate object that controls the
* layout of the children of @box
*
* Since: 1.2
*
* Deprecated: 1.10: Use clutter_actor_set_layout_manager() instead.
*/
void
clutter_box_set_layout_manager (ClutterBox *box,
ClutterLayoutManager *manager)
{
clutter_actor_set_layout_manager (CLUTTER_ACTOR (box), manager);
}
/**
* clutter_box_get_layout_manager:
* @box: a #ClutterBox
*
* Retrieves the #ClutterLayoutManager instance used by @box
*
* Return value: (transfer none): a #ClutterLayoutManager. The returned
* #ClutterLayoutManager is owned by the #ClutterBox and it should not
* be unreferenced
*
* Since: 1.2
*
* Deprecated: 1.10: Use clutter_actor_get_layout_manager() instead.
*/
ClutterLayoutManager *
clutter_box_get_layout_manager (ClutterBox *box)
{
return clutter_actor_get_layout_manager (CLUTTER_ACTOR (box));
}
/**
* clutter_box_packv:
* @box: a #ClutterBox
* @actor: a #ClutterActor
* @n_properties: the number of properties to set
* @properties: (array length=n_properties) (element-type utf8): a vector
* containing the property names to set
* @values: (array length=n_properties): a vector containing the property
* values to set
*
* Vector-based variant of clutter_box_pack(), intended for language
* bindings to use
*
* Since: 1.2
*
* Deprecated: 1.10: Use clutter_actor_add_child() instead. To set
* specific layout properties, use clutter_layout_manager_child_set()
*/
void
clutter_box_packv (ClutterBox *box,
ClutterActor *actor,
guint n_properties,
const gchar * const properties[],
const GValue *values)
{
ClutterLayoutManager *manager;
ClutterContainer *container;
ClutterLayoutMeta *meta;
GObjectClass *klass;
gint i;
g_return_if_fail (CLUTTER_IS_BOX (box));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
container = CLUTTER_CONTAINER (box);
clutter_container_add_actor (container, actor);
manager = clutter_actor_get_layout_manager (CLUTTER_ACTOR (box));
if (manager == NULL)
return;
meta = clutter_layout_manager_get_child_meta (manager,
container,
actor);
if (meta == NULL)
return;
klass = G_OBJECT_GET_CLASS (meta);
for (i = 0; i < n_properties; i++)
{
const gchar *pname = properties[i];
GParamSpec *pspec;
pspec = g_object_class_find_property (klass, pname);
if (pspec == NULL)
{
g_warning ("%s: the layout property '%s' for managers "
"of type '%s' (meta type '%s') does not exist",
G_STRLOC,
pname,
G_OBJECT_TYPE_NAME (manager),
G_OBJECT_TYPE_NAME (meta));
break;
}
if (!(pspec->flags & G_PARAM_WRITABLE))
{
g_warning ("%s: the layout property '%s' for managers "
"of type '%s' (meta type '%s') is not writable",
G_STRLOC,
pspec->name,
G_OBJECT_TYPE_NAME (manager),
G_OBJECT_TYPE_NAME (meta));
break;
}
clutter_layout_manager_child_set_property (manager,
container, actor,
pname, &values[i]);
}
}
static inline void
clutter_box_set_property_valist (ClutterBox *box,
ClutterActor *actor,
const gchar *first_property,
va_list var_args)
{
ClutterContainer *container = CLUTTER_CONTAINER (box);
ClutterLayoutManager *manager;
ClutterLayoutMeta *meta;
GObjectClass *klass;
const gchar *pname;
manager = clutter_actor_get_layout_manager (CLUTTER_ACTOR (box));
if (manager == NULL)
return;
meta = clutter_layout_manager_get_child_meta (manager,
container,
actor);
if (meta == NULL)
return;
klass = G_OBJECT_GET_CLASS (meta);
pname = first_property;
while (pname)
{
GValue value = { 0, };
GParamSpec *pspec;
gchar *error;
pspec = g_object_class_find_property (klass, pname);
if (pspec == NULL)
{
g_warning ("%s: the layout property '%s' for managers "
"of type '%s' (meta type '%s') does not exist",
G_STRLOC,
pname,
G_OBJECT_TYPE_NAME (manager),
G_OBJECT_TYPE_NAME (meta));
break;
}
if (!(pspec->flags & G_PARAM_WRITABLE))
{
g_warning ("%s: the layout property '%s' for managers "
"of type '%s' (meta type '%s') is not writable",
G_STRLOC,
pspec->name,
G_OBJECT_TYPE_NAME (manager),
G_OBJECT_TYPE_NAME (meta));
break;
}
G_VALUE_COLLECT_INIT (&value, G_PARAM_SPEC_VALUE_TYPE (pspec),
var_args, 0,
&error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error);
g_free (error);
break;
}
clutter_layout_manager_child_set_property (manager,
container, actor,
pspec->name, &value);
g_value_unset (&value);
pname = va_arg (var_args, gchar*);
}
}
/**
* clutter_box_pack:
* @box: a #ClutterBox
* @actor: a #ClutterActor
* @first_property: the name of the first property to set, or %NULL
* @...: a list of property name and value pairs, terminated by %NULL
*
* Adds @actor to @box and sets layout properties at the same time,
* if the #ClutterLayoutManager used by @box has them
*
* This function is a wrapper around clutter_container_add_actor()
* and clutter_layout_manager_child_set()
*
* Language bindings should use the vector-based clutter_box_packv()
* variant instead
*
* Since: 1.2
*
* Deprecated: 1.10: Use clutter_actor_add_child() instead. To set
* specific layout properties, use clutter_layout_manager_child_set()
*/
void
clutter_box_pack (ClutterBox *box,
ClutterActor *actor,
const gchar *first_property,
...)
{
va_list var_args;
g_return_if_fail (CLUTTER_IS_BOX (box));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
clutter_container_add_actor (CLUTTER_CONTAINER (box), actor);
if (first_property == NULL || *first_property == '\0')
return;
va_start (var_args, first_property);
clutter_box_set_property_valist (box, actor, first_property, var_args);
va_end (var_args);
}
/**
* clutter_box_pack_after:
* @box: a #ClutterBox
* @actor: a #ClutterActor
* @sibling: (allow-none): a #ClutterActor or %NULL
* @first_property: the name of the first property to set, or %NULL
* @...: a list of property name and value pairs, terminated by %NULL
*
* Adds @actor to @box, placing it after @sibling, and sets layout
* properties at the same time, if the #ClutterLayoutManager used by
* @box supports them
*
* If @sibling is %NULL then @actor is placed at the end of the
* list of children, to be allocated and painted after every other child
*
* This function is a wrapper around clutter_container_add_actor(),
* clutter_container_raise_child() and clutter_layout_manager_child_set()
*
* Since: 1.2
*
* Deprecated: 1.10: Use clutter_actor_insert_child_above() instead.
* To set specific layout properties, use clutter_layout_manager_child_set()
*/
void
clutter_box_pack_after (ClutterBox *box,
ClutterActor *actor,
ClutterActor *sibling,
const gchar *first_property,
...)
{
va_list var_args;
g_return_if_fail (CLUTTER_IS_BOX (box));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
clutter_container_add_actor (CLUTTER_CONTAINER (box), actor);
clutter_container_raise_child (CLUTTER_CONTAINER (box), actor, sibling);
if (first_property == NULL || *first_property == '\0')
return;
va_start (var_args, first_property);
clutter_box_set_property_valist (box, actor, first_property, var_args);
va_end (var_args);
}
/**
* clutter_box_pack_before:
* @box: a #ClutterBox
* @actor: a #ClutterActor
* @sibling: (allow-none): a #ClutterActor or %NULL
* @first_property: the name of the first property to set, or %NULL
* @...: a list of property name and value pairs, terminated by %NULL
*
* Adds @actor to @box, placing it before @sibling, and sets layout
* properties at the same time, if the #ClutterLayoutManager used by
* @box supports them
*
* If @sibling is %NULL then @actor is placed at the beginning of the
* list of children, to be allocated and painted below every other child
*
* This function is a wrapper around clutter_container_add_actor(),
* clutter_container_lower_child() and clutter_layout_manager_child_set()
*
* Since: 1.2
*
* Deprecated: 1.10: Use clutter_actor_insert_child_below() instead.
* To set specific layout properties, use clutter_layout_manager_child_set()
*/
void
clutter_box_pack_before (ClutterBox *box,
ClutterActor *actor,
ClutterActor *sibling,
const gchar *first_property,
...)
{
va_list var_args;
g_return_if_fail (CLUTTER_IS_BOX (box));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
clutter_container_add_actor (CLUTTER_CONTAINER (box), actor);
clutter_container_lower_child (CLUTTER_CONTAINER (box), actor, sibling);
if (first_property == NULL || *first_property == '\0')
return;
va_start (var_args, first_property);
clutter_box_set_property_valist (box, actor, first_property, var_args);
va_end (var_args);
}
/**
* clutter_box_pack_at:
* @box: a #ClutterBox
* @actor: a #ClutterActor
* @position: the position to insert the @actor at
* @first_property: the name of the first property to set, or %NULL
* @...: a list of property name and value pairs, terminated by %NULL
*
* Adds @actor to @box, placing it at @position, and sets layout
* properties at the same time, if the #ClutterLayoutManager used by
* @box supports them
*
* If @position is a negative number, or is larger than the number of
* children of @box, the new child is added at the end of the list of
* children
*
* Since: 1.2
*
* Deprecated: 1.10: Use clutter_actor_insert_child_at_index() instead.
* To set specific layout properties, use clutter_layout_manager_child_set()
*/
void
clutter_box_pack_at (ClutterBox *box,
ClutterActor *actor,
gint position,
const gchar *first_property,
...)
{
va_list var_args;
g_return_if_fail (CLUTTER_IS_BOX (box));
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
clutter_actor_insert_child_at_index (CLUTTER_ACTOR (box),
actor,
position);
/* we need to explicitly call this, because we're not going through
* the default code paths provided by clutter_container_add()
*/
clutter_container_create_child_meta (CLUTTER_CONTAINER (box), actor);
g_signal_emit_by_name (box, "actor-added", actor);
if (first_property == NULL || *first_property == '\0')
return;
va_start (var_args, first_property);
clutter_box_set_property_valist (box, actor, first_property, var_args);
va_end (var_args);
}
/**
* clutter_box_set_color:
* @box: a #ClutterBox
* @color: (allow-none): the background color, or %NULL to unset
*
* Sets (or unsets) the background color for @box
*
* Since: 1.2
*
* Deprecated: 1.10: Use clutter_actor_set_background_color() instead.
*/
void
clutter_box_set_color (ClutterBox *box,
const ClutterColor *color)
{
g_return_if_fail (CLUTTER_IS_BOX (box));
clutter_box_set_color_internal (box, color);
}
/**
* clutter_box_get_color:
* @box: a #ClutterBox
* @color: (out caller-allocates): return location for a #ClutterColor
*
* Retrieves the background color of @box
*
* If the #ClutterBox:color-set property is set to %FALSE the
* returned #ClutterColor is undefined
*
* Since: 1.2
*
* Deprecated: 1.10: Use clutter_actor_get_background_color() instead.
*/
void
clutter_box_get_color (ClutterBox *box,
ClutterColor *color)
{
g_return_if_fail (CLUTTER_IS_BOX (box));
g_return_if_fail (color != NULL);
clutter_actor_get_background_color (CLUTTER_ACTOR (box), color);
}

View File

@ -0,0 +1,143 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2009,2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* 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_BOX_H__
#define __CLUTTER_BOX_H__
#include <clutter/clutter-actor.h>
#include <clutter/clutter-container.h>
#include <clutter/clutter-layout-manager.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_BOX (clutter_box_get_type ())
#define CLUTTER_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BOX, ClutterBox))
#define CLUTTER_IS_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BOX))
#define CLUTTER_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BOX, ClutterBoxClass))
#define CLUTTER_IS_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BOX))
#define CLUTTER_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BOX, ClutterBoxClass))
typedef struct _ClutterBox ClutterBox;
typedef struct _ClutterBoxPrivate ClutterBoxPrivate;
typedef struct _ClutterBoxClass ClutterBoxClass;
/**
* ClutterBox:
*
* The #ClutterBox structure contains only private data and should
* be accessed using the provided API
*
* Since: 1.2
*/
struct _ClutterBox
{
/*< private >*/
ClutterActor parent_instance;
ClutterBoxPrivate *priv;
};
/**
* ClutterBoxClass:
*
* The #ClutterBoxClass structure contains only private data
*
* Since: 1.2
*/
struct _ClutterBoxClass
{
/*< private >*/
ClutterActorClass parent_class;
/* padding, for future expansion */
void (*clutter_padding_1) (void);
void (*clutter_padding_2) (void);
void (*clutter_padding_3) (void);
void (*clutter_padding_4) (void);
void (*clutter_padding_5) (void);
void (*clutter_padding_6) (void);
};
CLUTTER_DEPRECATED
GType clutter_box_get_type (void) G_GNUC_CONST;
CLUTTER_DEPRECATED_FOR(clutter_actor_new)
ClutterActor * clutter_box_new (ClutterLayoutManager *manager);
CLUTTER_DEPRECATED_FOR(clutter_actor_set_layout_manager)
void clutter_box_set_layout_manager (ClutterBox *box,
ClutterLayoutManager *manager);
CLUTTER_DEPRECATED_FOR(clutter_actor_get_layout_manager)
ClutterLayoutManager *clutter_box_get_layout_manager (ClutterBox *box);
CLUTTER_DEPRECATED_FOR(clutter_actor_set_background_color)
void clutter_box_set_color (ClutterBox *box,
const ClutterColor *color);
CLUTTER_DEPRECATED_FOR(clutter_actor_get_background_color)
void clutter_box_get_color (ClutterBox *box,
ClutterColor *color);
CLUTTER_DEPRECATED_FOR(clutter_actor_add_child)
void clutter_box_pack (ClutterBox *box,
ClutterActor *actor,
const gchar *first_property,
...);
CLUTTER_DEPRECATED_FOR(clutter_actor_add_child)
void clutter_box_packv (ClutterBox *box,
ClutterActor *actor,
guint n_properties,
const gchar * const properties[],
const GValue *values);
CLUTTER_DEPRECATED_FOR(clutter_actor_insert_child_above)
void clutter_box_pack_after (ClutterBox *box,
ClutterActor *actor,
ClutterActor *sibling,
const gchar *first_property,
...);
CLUTTER_DEPRECATED_FOR(clutter_actor_insert_child_below)
void clutter_box_pack_before (ClutterBox *box,
ClutterActor *actor,
ClutterActor *sibling,
const gchar *first_property,
...);
CLUTTER_DEPRECATED_FOR(clutter_actor_insert_child_at_index)
void clutter_box_pack_at (ClutterBox *box,
ClutterActor *actor,
gint position,
const gchar *first_property,
...);
G_END_DECLS
#endif /* __CLUTTER_BOX_H__ */

View File

@ -0,0 +1,554 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:clutter-group
* @short_description: A fixed layout container
*
* A #ClutterGroup is an Actor which contains multiple child actors positioned
* relative to the #ClutterGroup position. Other operations such as scaling,
* rotating and clipping of the group will apply to the child actors.
*
* A #ClutterGroup's size is defined by the size and position of its children;
* it will be the smallest non-negative size that covers the right and bottom
* edges of all of its children.
*
* Setting the size on a Group using #ClutterActor methods like
* clutter_actor_set_size() will override the natural size of the Group,
* however this will not affect the size of the children and they may still
* be painted outside of the allocation of the group. One way to constrain
* the visible area of a #ClutterGroup to a specified allocation is to
* explicitly set the size of the #ClutterGroup and then use the
* #ClutterActor:clip-to-allocation property.
*
* #ClutterGroup as a concrete class has been superceded by #ClutterActor
* since Clutter 1.10. The type itself is not deprecated as it is used by
* #ClutterStage. You should instantiate #ClutterActor and use its API to
* manage child actors.
*/
#include "clutter-build-config.h"
#include <stdarg.h>
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include "clutter-group.h"
#include "clutter-actor.h"
#include "clutter-actor-private.h"
#include "clutter-container.h"
#include "clutter-fixed-layout.h"
#include "clutter-main.h"
#include "clutter-debug.h"
#include "clutter-enum-types.h"
#include "clutter-marshal.h"
#include "clutter-private.h"
#include "cogl/cogl.h"
struct _ClutterGroupPrivate
{
GList *children;
ClutterLayoutManager *layout;
};
static void clutter_container_iface_init (ClutterContainerIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterGroup, clutter_group, CLUTTER_TYPE_ACTOR,
G_ADD_PRIVATE (ClutterGroup)
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
clutter_container_iface_init));
static gint
sort_by_depth (gconstpointer a,
gconstpointer b)
{
gfloat depth_a = clutter_actor_get_depth (CLUTTER_ACTOR(a));
gfloat depth_b = clutter_actor_get_depth (CLUTTER_ACTOR(b));
if (depth_a < depth_b)
return -1;
if (depth_a > depth_b)
return 1;
return 0;
}
static void
clutter_group_real_add (ClutterContainer *container,
ClutterActor *actor)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv;
g_object_ref (actor);
priv->children = g_list_append (priv->children, actor);
clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
g_signal_emit_by_name (container, "actor-added", actor);
clutter_container_sort_depth_order (container);
g_object_unref (actor);
}
static void
clutter_group_real_actor_added (ClutterContainer *container,
ClutterActor *actor)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv;
/* XXX - children added using clutter_actor_add_child() will
* cause actor-added to be emitted without going through the
* add() virtual function.
*
* if we get an actor-added for a child that is not in our
* list of children already, then we go in compatibility
* mode.
*/
if (g_list_find (priv->children, actor) != NULL)
return;
priv->children = g_list_append (priv->children, actor);
clutter_container_sort_depth_order (container);
}
static void
clutter_group_real_remove (ClutterContainer *container,
ClutterActor *actor)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv;
g_object_ref (actor);
priv->children = g_list_remove (priv->children, actor);
clutter_actor_unparent (actor);
clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
g_signal_emit_by_name (container, "actor-removed", actor);
clutter_actor_queue_redraw (CLUTTER_ACTOR (container));
g_object_unref (actor);
}
static void
clutter_group_real_actor_removed (ClutterContainer *container,
ClutterActor *actor)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv;
/* XXX - same compatibility mode of the ::actor-added implementation */
if (g_list_find (priv->children, actor) == NULL)
return;
priv->children = g_list_remove (priv->children, actor);
}
static void
clutter_group_real_raise (ClutterContainer *container,
ClutterActor *actor,
ClutterActor *sibling)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv;
priv->children = g_list_remove (priv->children, actor);
/* Raise at the top */
if (!sibling)
{
GList *last_item;
last_item = g_list_last (priv->children);
if (last_item)
sibling = last_item->data;
priv->children = g_list_append (priv->children, actor);
}
else
{
gint index_ = g_list_index (priv->children, sibling) + 1;
priv->children = g_list_insert (priv->children, actor, index_);
}
/* set Z ordering a value below, this will then call sort
* as values are equal ordering shouldn't change but Z
* values will be correct.
*
* FIXME: get rid of this crap; this is so utterly broken and wrong on
* so many levels it's not even funny. sadly, we get to keep this until
* we can break API and remove Group for good.
*/
if (sibling &&
clutter_actor_get_depth (sibling) != clutter_actor_get_depth (actor))
{
clutter_actor_set_depth (actor, clutter_actor_get_depth (sibling));
}
clutter_actor_queue_redraw (CLUTTER_ACTOR (container));
}
static void
clutter_group_real_lower (ClutterContainer *container,
ClutterActor *actor,
ClutterActor *sibling)
{
ClutterGroup *self = CLUTTER_GROUP (container);
ClutterGroupPrivate *priv = self->priv;
priv->children = g_list_remove (priv->children, actor);
/* Push to bottom */
if (!sibling)
{
GList *last_item;
last_item = g_list_first (priv->children);
if (last_item)
sibling = last_item->data;
priv->children = g_list_prepend (priv->children, actor);
}
else
{
gint index_ = g_list_index (priv->children, sibling);
priv->children = g_list_insert (priv->children, actor, index_);
}
/* See comment in group_raise for this */
if (sibling &&
clutter_actor_get_depth (sibling) != clutter_actor_get_depth (actor))
{
clutter_actor_set_depth (actor, clutter_actor_get_depth (sibling));
}
clutter_actor_queue_redraw (CLUTTER_ACTOR (container));
}
static void
clutter_group_real_sort_depth_order (ClutterContainer *container)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (container)->priv;
priv->children = g_list_sort (priv->children, sort_by_depth);
clutter_actor_queue_redraw (CLUTTER_ACTOR (container));
}
static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
iface->add = clutter_group_real_add;
iface->actor_added = clutter_group_real_actor_added;
iface->remove = clutter_group_real_remove;
iface->actor_removed = clutter_group_real_actor_removed;
iface->raise = clutter_group_real_raise;
iface->lower = clutter_group_real_lower;
iface->sort_depth_order = clutter_group_real_sort_depth_order;
}
static void
clutter_group_real_paint (ClutterActor *actor,
ClutterPaintContext *paint_context)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv;
CLUTTER_NOTE (PAINT, "ClutterGroup paint enter '%s'",
_clutter_actor_get_debug_name (actor));
g_list_foreach (priv->children, (GFunc) clutter_actor_paint, paint_context);
CLUTTER_NOTE (PAINT, "ClutterGroup paint leave '%s'",
_clutter_actor_get_debug_name (actor));
}
static void
clutter_group_real_pick (ClutterActor *actor,
ClutterPickContext *pick_context)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv;
/* Chain up so we get a bounding box pained (if we are reactive) */
CLUTTER_ACTOR_CLASS (clutter_group_parent_class)->pick (actor, pick_context);
g_list_foreach (priv->children, (GFunc) clutter_actor_pick, pick_context);
}
static void
clutter_group_real_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width,
gfloat *natural_width)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv;
clutter_layout_manager_get_preferred_width (priv->layout,
CLUTTER_CONTAINER (actor),
for_height,
min_width, natural_width);
}
static void
clutter_group_real_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height,
gfloat *natural_height)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv;
clutter_layout_manager_get_preferred_height (priv->layout,
CLUTTER_CONTAINER (actor),
for_width,
min_height, natural_height);
}
static void
clutter_group_real_allocate (ClutterActor *actor,
const ClutterActorBox *allocation)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv;
ClutterActorClass *klass;
klass = CLUTTER_ACTOR_CLASS (clutter_group_parent_class);
klass->allocate (actor, allocation);
if (priv->children == NULL)
return;
clutter_layout_manager_allocate (priv->layout,
CLUTTER_CONTAINER (actor),
allocation);
}
static void
clutter_group_dispose (GObject *object)
{
ClutterGroup *self = CLUTTER_GROUP (object);
ClutterGroupPrivate *priv = self->priv;
/* Note: we are careful to consider that destroying children could
* have the side-effect of destroying other children so
* priv->children may be modified during clutter_actor_destroy. */
while (priv->children != NULL)
{
ClutterActor *child = priv->children->data;
priv->children = g_list_delete_link (priv->children, priv->children);
clutter_actor_destroy (child);
}
if (priv->layout)
{
clutter_layout_manager_set_container (priv->layout, NULL);
g_object_unref (priv->layout);
priv->layout = NULL;
}
G_OBJECT_CLASS (clutter_group_parent_class)->dispose (object);
}
static void
clutter_group_real_show_all (ClutterActor *self)
{
ClutterActorIter iter;
ClutterActor *actor;
clutter_actor_iter_init (&iter, self);
while (clutter_actor_iter_next (&iter, &actor))
clutter_actor_show (actor);
clutter_actor_show (self);
}
static void
clutter_group_real_hide_all (ClutterActor *actor)
{
ClutterActorIter iter;
clutter_actor_hide (actor);
clutter_actor_iter_init (&iter, actor);
while (clutter_actor_iter_next (&iter, &actor))
clutter_actor_hide (actor);
}
static gboolean
clutter_group_real_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv;
GList *l;
if (priv->children == NULL)
return TRUE;
for (l = priv->children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
const ClutterPaintVolume *child_volume;
/* This gets the paint volume of the child transformed into the
* group's coordinate space... */
child_volume = clutter_actor_get_transformed_paint_volume (child, actor);
if (!child_volume)
return FALSE;
clutter_paint_volume_union (volume, child_volume);
}
return TRUE;
}
static void
clutter_group_class_init (ClutterGroupClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
actor_class->get_preferred_width = clutter_group_real_get_preferred_width;
actor_class->get_preferred_height = clutter_group_real_get_preferred_height;
actor_class->allocate = clutter_group_real_allocate;
actor_class->paint = clutter_group_real_paint;
actor_class->pick = clutter_group_real_pick;
actor_class->show_all = clutter_group_real_show_all;
actor_class->hide_all = clutter_group_real_hide_all;
actor_class->get_paint_volume = clutter_group_real_get_paint_volume;
gobject_class->dispose = clutter_group_dispose;
}
static void
clutter_group_init (ClutterGroup *self)
{
ClutterActor *actor = CLUTTER_ACTOR (self);
self->priv = clutter_group_get_instance_private (self);
/* turn on some optimization
*
* XXX - these so-called "optimizations" are insane and should have never
* been used. they introduce some weird behaviour that breaks invariants
* and have to be explicitly worked around.
*
* this flag was set by the ClutterFixedLayout, but since that layout
* manager is now the default for ClutterActor, we set the flag explicitly
* here, to avoid breaking perfectly working actors overriding the
* allocate() virtual function.
*
* also, we keep this flag here so that it can die once we get rid of
* ClutterGroup.
*/
clutter_actor_set_flags (actor, CLUTTER_ACTOR_NO_LAYOUT);
self->priv->layout = clutter_fixed_layout_new ();
g_object_ref_sink (self->priv->layout);
clutter_actor_set_layout_manager (actor, self->priv->layout);
}
/**
* clutter_group_new:
*
* Create a new #ClutterGroup.
*
* Return value: the newly created #ClutterGroup actor
*
* Deprecated: 1.10: Use clutter_actor_new() instead.
*/
ClutterActor *
clutter_group_new (void)
{
return g_object_new (CLUTTER_TYPE_GROUP, NULL);
}
/**
* clutter_group_remove_all:
* @self: A #ClutterGroup
*
* Removes all children actors from the #ClutterGroup.
*
* Deprecated: 1.10: Use clutter_actor_remove_all_children() instead.
*/
void
clutter_group_remove_all (ClutterGroup *self)
{
g_return_if_fail (CLUTTER_IS_GROUP (self));
clutter_actor_remove_all_children (CLUTTER_ACTOR (self));
}
/**
* clutter_group_get_n_children:
* @self: A #ClutterGroup
*
* Gets the number of actors held in the group.
*
* Return value: The number of child actors held in the group.
*
* Since: 0.2
*
* Deprecated: 1.10: Use clutter_actor_get_n_children() instead.
*/
gint
clutter_group_get_n_children (ClutterGroup *self)
{
g_return_val_if_fail (CLUTTER_IS_GROUP (self), 0);
return clutter_actor_get_n_children (CLUTTER_ACTOR (self));
}
/**
* clutter_group_get_nth_child:
* @self: A #ClutterGroup
* @index_: the position of the requested actor.
*
* Gets a groups child held at @index_ in stack.
*
* Return value: (transfer none): A Clutter actor, or %NULL if
* @index_ is invalid.
*
* Since: 0.2
*
* Deprecated: 1.10: Use clutter_actor_get_child_at_index() instead.
*/
ClutterActor *
clutter_group_get_nth_child (ClutterGroup *self,
gint index_)
{
ClutterActor *actor;
g_return_val_if_fail (CLUTTER_IS_GROUP (self), NULL);
actor = CLUTTER_ACTOR (self);
g_return_val_if_fail (index_ <= clutter_actor_get_n_children (actor), NULL);
return clutter_actor_get_child_at_index (actor, index_);
}

View File

@ -0,0 +1,62 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2011 Intel Corp
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_GROUP_DEPRECATED_H__
#define __CLUTTER_GROUP_DEPRECATED_H__
#include <clutter/clutter-types.h>
#include <clutter/clutter-group.h>
G_BEGIN_DECLS
CLUTTER_DEPRECATED_FOR(clutter_actor_new)
ClutterActor * clutter_group_new (void);
CLUTTER_DEPRECATED_FOR(clutter_actor_get_child_at_index)
ClutterActor * clutter_group_get_nth_child (ClutterGroup *self,
gint index_);
CLUTTER_DEPRECATED_FOR(clutter_actor_get_n_children)
gint clutter_group_get_n_children (ClutterGroup *self);
CLUTTER_DEPRECATED_FOR(clutter_actor_remove_all_children)
void clutter_group_remove_all (ClutterGroup *self);
#ifndef CLUTTER_DISABLE_DEPRECATED
/* for Mr. Mallum only */
#define clutter_group_add(group,actor) G_STMT_START { \
ClutterActor *_actor = (ClutterActor *) (actor); \
if (CLUTTER_IS_GROUP ((group)) && CLUTTER_IS_ACTOR ((_actor))) \
{ \
ClutterContainer *_container = (ClutterContainer *) (group); \
clutter_container_add_actor (_container, _actor); \
} } G_STMT_END
#endif /* CLUTTER_DISABLE_DEPRECATED */
G_END_DECLS
#endif /* __CLUTTER_GROUP_DEPRECATED_H__ */

View File

@ -0,0 +1,626 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
/**
* SECTION:clutter-rectangle
* @short_description: An actor that displays a simple rectangle.
*
* #ClutterRectangle is a #ClutterActor which draws a simple filled rectangle.
*
* #ClutterRectangle is deprecated since Clutter 1.10. If you want an actor
* painting a solid color, you can replace it with #ClutterActor and set the
* #ClutterActor:background-color property to the desired #ClutterColor. If
* you are drawing more complex shapes, use #ClutterCanvas to draw using the
* Cairo 2D API instead.
*/
#include "clutter-build-config.h"
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include "deprecated/clutter-rectangle.h"
#include "deprecated/clutter-actor.h"
#include "clutter-actor-private.h"
#include "clutter-color.h"
#include "clutter-debug.h"
#include "clutter-main.h"
#include "clutter-private.h"
#include "cogl/cogl.h"
struct _ClutterRectanglePrivate
{
ClutterColor color;
ClutterColor border_color;
guint border_width;
guint has_border : 1;
};
enum
{
PROP_0,
PROP_COLOR,
PROP_BORDER_COLOR,
PROP_BORDER_WIDTH,
PROP_HAS_BORDER
/* FIXME: Add gradient, rounded corner props etc */
};
static const ClutterColor default_color = { 255, 255, 255, 255 };
static const ClutterColor default_border_color = { 0, 0, 0, 255 };
G_DEFINE_TYPE_WITH_PRIVATE (ClutterRectangle, clutter_rectangle, CLUTTER_TYPE_ACTOR)
static void
clutter_rectangle_paint (ClutterActor *self,
ClutterPaintContext *paint_context)
{
ClutterRectanglePrivate *priv = CLUTTER_RECTANGLE (self)->priv;
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
static CoglPipeline *default_color_pipeline = NULL;
CoglPipeline *content_pipeline;
ClutterActorBox alloc;
CoglColor color;
guint8 tmp_alpha;
CLUTTER_NOTE (PAINT,
"painting rect '%s'",
clutter_actor_get_name (self) ? clutter_actor_get_name (self)
: "unknown");
clutter_actor_get_allocation_box (self, &alloc);
if (G_UNLIKELY (default_color_pipeline == NULL))
{
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
default_color_pipeline = cogl_pipeline_new (ctx);
}
g_assert (default_color_pipeline != NULL);
content_pipeline = cogl_pipeline_copy (default_color_pipeline);
/* compute the composited opacity of the actor taking into
* account the opacity of the color set by the user
*/
tmp_alpha = clutter_actor_get_paint_opacity (self)
* priv->color.alpha
/ 255;
cogl_color_init_from_4ub (&color,
priv->color.red,
priv->color.green,
priv->color.blue,
tmp_alpha);
cogl_color_premultiply (&color);
cogl_pipeline_set_color (content_pipeline, &color);
if (priv->has_border)
{
CoglPipeline *border_pipeline;
border_pipeline = cogl_pipeline_copy (default_color_pipeline);
tmp_alpha = clutter_actor_get_paint_opacity (self)
* priv->border_color.alpha
/ 255;
cogl_color_init_from_4ub (&color,
priv->border_color.red,
priv->border_color.green,
priv->border_color.blue,
tmp_alpha);
cogl_color_premultiply (&color);
cogl_pipeline_set_color (border_pipeline, &color);
/* We paint the border and the content only if the rectangle
* is big enough to show them
*/
if ((priv->border_width * 2) < clutter_actor_box_get_width (&alloc) &&
(priv->border_width * 2) < clutter_actor_box_get_height (&alloc))
{
/* paint the border. this sucks, but it's the only way to make a border */
cogl_framebuffer_draw_rectangle (framebuffer,
border_pipeline,
priv->border_width, 0,
clutter_actor_box_get_width (&alloc),
priv->border_width);
cogl_framebuffer_draw_rectangle (framebuffer,
border_pipeline,
clutter_actor_box_get_width (&alloc) - priv->border_width,
priv->border_width,
clutter_actor_box_get_width (&alloc),
clutter_actor_box_get_height (&alloc));
cogl_framebuffer_draw_rectangle (framebuffer,
border_pipeline,
0, clutter_actor_box_get_height (&alloc) - priv->border_width,
clutter_actor_box_get_width (&alloc) - priv->border_width,
clutter_actor_box_get_height (&alloc));
cogl_framebuffer_draw_rectangle (framebuffer,
border_pipeline,
0, 0,
priv->border_width,
clutter_actor_box_get_height (&alloc) - priv->border_width);
/* now paint the rectangle */
cogl_framebuffer_draw_rectangle (framebuffer,
content_pipeline,
priv->border_width, priv->border_width,
clutter_actor_box_get_width (&alloc) - priv->border_width,
clutter_actor_box_get_height (&alloc) - priv->border_width);
}
else
{
/* Otherwise, we draw a rectangle with the same color
* as the border, since we can only fit that into the
* allocation.
*/
cogl_framebuffer_draw_rectangle (framebuffer,
border_pipeline,
0, 0,
clutter_actor_box_get_width (&alloc),
clutter_actor_box_get_height (&alloc));
}
cogl_object_unref (border_pipeline);
}
else
{
cogl_framebuffer_draw_rectangle (framebuffer,
content_pipeline,
0, 0,
clutter_actor_box_get_width (&alloc),
clutter_actor_box_get_height (&alloc));
}
cogl_object_unref (content_pipeline);
}
static gboolean
clutter_rectangle_get_paint_volume (ClutterActor *self,
ClutterPaintVolume *volume)
{
return _clutter_actor_set_default_paint_volume (self,
CLUTTER_TYPE_RECTANGLE,
volume);
}
static gboolean
clutter_rectangle_has_overlaps (ClutterActor *self)
{
/* Rectangles never need an offscreen redirect because there are
never any overlapping primitives */
return FALSE;
}
static void
clutter_rectangle_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterRectangle *rectangle = CLUTTER_RECTANGLE(object);
switch (prop_id)
{
case PROP_COLOR:
clutter_rectangle_set_color (rectangle, clutter_value_get_color (value));
break;
case PROP_BORDER_COLOR:
clutter_rectangle_set_border_color (rectangle,
clutter_value_get_color (value));
break;
case PROP_BORDER_WIDTH:
clutter_rectangle_set_border_width (rectangle,
g_value_get_uint (value));
break;
case PROP_HAS_BORDER:
rectangle->priv->has_border = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_rectangle_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterRectanglePrivate *priv = CLUTTER_RECTANGLE(object)->priv;
switch (prop_id)
{
case PROP_COLOR:
clutter_value_set_color (value, &priv->color);
break;
case PROP_BORDER_COLOR:
clutter_value_set_color (value, &priv->border_color);
break;
case PROP_BORDER_WIDTH:
g_value_set_uint (value, priv->border_width);
break;
case PROP_HAS_BORDER:
g_value_set_boolean (value, priv->has_border);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_rectangle_finalize (GObject *object)
{
G_OBJECT_CLASS (clutter_rectangle_parent_class)->finalize (object);
}
static void
clutter_rectangle_dispose (GObject *object)
{
G_OBJECT_CLASS (clutter_rectangle_parent_class)->dispose (object);
}
static void
clutter_rectangle_class_init (ClutterRectangleClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
GParamSpec *pspec;
actor_class->paint = clutter_rectangle_paint;
actor_class->get_paint_volume = clutter_rectangle_get_paint_volume;
actor_class->has_overlaps = clutter_rectangle_has_overlaps;
gobject_class->finalize = clutter_rectangle_finalize;
gobject_class->dispose = clutter_rectangle_dispose;
gobject_class->set_property = clutter_rectangle_set_property;
gobject_class->get_property = clutter_rectangle_get_property;
/**
* ClutterRectangle:color:
*
* The color of the rectangle.
*/
pspec = clutter_param_spec_color ("color",
P_("Color"),
P_("The color of the rectangle"),
&default_color,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_COLOR, pspec);
/**
* ClutterRectangle:border-color:
*
* The color of the border of the rectangle.
*
* Since: 0.2
*/
pspec = clutter_param_spec_color ("border-color",
P_("Border Color"),
P_("The color of the border of the rectangle"),
&default_border_color,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_BORDER_COLOR, pspec);
/**
* ClutterRectangle:border-width:
*
* The width of the border of the rectangle, in pixels.
*
* Since: 0.2
*/
g_object_class_install_property (gobject_class,
PROP_BORDER_WIDTH,
g_param_spec_uint ("border-width",
P_("Border Width"),
P_("The width of the border of the rectangle"),
0, G_MAXUINT,
0,
CLUTTER_PARAM_READWRITE));
/**
* ClutterRectangle:has-border:
*
* Whether the #ClutterRectangle should be displayed with a border.
*
* Since: 0.2
*/
g_object_class_install_property (gobject_class,
PROP_HAS_BORDER,
g_param_spec_boolean ("has-border",
P_("Has Border"),
P_("Whether the rectangle should have a border"),
FALSE,
CLUTTER_PARAM_READWRITE));
}
static void
clutter_rectangle_init (ClutterRectangle *self)
{
ClutterRectanglePrivate *priv;
self->priv = priv = clutter_rectangle_get_instance_private (self);
priv->color = default_color;
priv->border_color = default_border_color;
priv->border_width = 0;
priv->has_border = FALSE;
}
/**
* clutter_rectangle_new:
*
* Creates a new #ClutterActor with a rectangular shape.
*
* Return value: a new #ClutterRectangle
*
* Deprecated: 1.10: Use clutter_actor_new() instead
*/
ClutterActor*
clutter_rectangle_new (void)
{
return g_object_new (CLUTTER_TYPE_RECTANGLE, NULL);
}
/**
* clutter_rectangle_new_with_color:
* @color: a #ClutterColor
*
* Creates a new #ClutterActor with a rectangular shape
* and of the given @color.
*
* Return value: a new #ClutterRectangle
*
* Deprecated: 1.10: Use clutter_actor_new() and
* clutter_actor_set_background_color() instead
*/
ClutterActor *
clutter_rectangle_new_with_color (const ClutterColor *color)
{
return g_object_new (CLUTTER_TYPE_RECTANGLE,
"color", color,
NULL);
}
/**
* clutter_rectangle_get_color:
* @rectangle: a #ClutterRectangle
* @color: (out caller-allocates): return location for a #ClutterColor
*
* Retrieves the color of @rectangle.
*
* Deprecated: 1.10: Use #ClutterActor and clutter_actor_get_background_color()
* instead
*/
void
clutter_rectangle_get_color (ClutterRectangle *rectangle,
ClutterColor *color)
{
ClutterRectanglePrivate *priv;
g_return_if_fail (CLUTTER_IS_RECTANGLE (rectangle));
g_return_if_fail (color != NULL);
priv = rectangle->priv;
color->red = priv->color.red;
color->green = priv->color.green;
color->blue = priv->color.blue;
color->alpha = priv->color.alpha;
}
/**
* clutter_rectangle_set_color:
* @rectangle: a #ClutterRectangle
* @color: a #ClutterColor
*
* Sets the color of @rectangle.
*
* Deprecated: 1.10: Use #ClutterActor and clutter_actor_set_background_color()
* instead
*/
void
clutter_rectangle_set_color (ClutterRectangle *rectangle,
const ClutterColor *color)
{
ClutterRectanglePrivate *priv;
g_return_if_fail (CLUTTER_IS_RECTANGLE (rectangle));
g_return_if_fail (color != NULL);
g_object_ref (rectangle);
priv = rectangle->priv;
priv->color.red = color->red;
priv->color.green = color->green;
priv->color.blue = color->blue;
priv->color.alpha = color->alpha;
#if 0
/* FIXME - appears to be causing border to always get drawn */
if (clutter_color_equal (&priv->color, &priv->border_color))
priv->has_border = FALSE;
else
priv->has_border = TRUE;
#endif
clutter_actor_queue_redraw (CLUTTER_ACTOR (rectangle));
g_object_notify (G_OBJECT (rectangle), "color");
g_object_notify (G_OBJECT (rectangle), "has-border");
g_object_unref (rectangle);
}
/**
* clutter_rectangle_get_border_width:
* @rectangle: a #ClutterRectangle
*
* Gets the width (in pixels) of the border used by @rectangle
*
* Return value: the border's width
*
* Since: 0.2
*
* Deprecated: 1.10: Use #ClutterActor and a #ClutterCanvas content
* to draw the border using Cairo
*/
guint
clutter_rectangle_get_border_width (ClutterRectangle *rectangle)
{
g_return_val_if_fail (CLUTTER_IS_RECTANGLE (rectangle), 0);
return rectangle->priv->border_width;
}
/**
* clutter_rectangle_set_border_width:
* @rectangle: a #ClutterRectangle
* @width: the width of the border
*
* Sets the width (in pixel) of the border used by @rectangle.
* A @width of 0 will unset the border.
*
* Since: 0.2
*
* Deprecated: 1.10: Use #ClutterActor and a #ClutterCanvas content
* to draw the border using Cairo
*/
void
clutter_rectangle_set_border_width (ClutterRectangle *rectangle,
guint width)
{
ClutterRectanglePrivate *priv;
g_return_if_fail (CLUTTER_IS_RECTANGLE (rectangle));
priv = rectangle->priv;
if (priv->border_width != width)
{
g_object_ref (rectangle);
priv->border_width = width;
if (priv->border_width != 0)
priv->has_border = TRUE;
else
priv->has_border = FALSE;
clutter_actor_queue_redraw (CLUTTER_ACTOR (rectangle));
g_object_notify (G_OBJECT (rectangle), "border-width");
g_object_notify (G_OBJECT (rectangle), "has-border");
g_object_unref (rectangle);
}
}
/**
* clutter_rectangle_get_border_color:
* @rectangle: a #ClutterRectangle
* @color: (out caller-allocates): return location for a #ClutterColor
*
* Gets the color of the border used by @rectangle and places
* it into @color.
*
* Since: 0.2
*
* Deprecated: 1.10: Use #ClutterActor and a #ClutterCanvas to draw
* the border with Cairo
*/
void
clutter_rectangle_get_border_color (ClutterRectangle *rectangle,
ClutterColor *color)
{
ClutterRectanglePrivate *priv;
g_return_if_fail (CLUTTER_IS_RECTANGLE (rectangle));
g_return_if_fail (color != NULL);
priv = rectangle->priv;
color->red = priv->border_color.red;
color->green = priv->border_color.green;
color->blue = priv->border_color.blue;
color->alpha = priv->border_color.alpha;
}
/**
* clutter_rectangle_set_border_color:
* @rectangle: a #ClutterRectangle
* @color: the color of the border
*
* Sets the color of the border used by @rectangle using @color
*
* Deprecated: 1.10: Use #ClutterActor and a #ClutterCanvas to draw
* the border with Cairo
*/
void
clutter_rectangle_set_border_color (ClutterRectangle *rectangle,
const ClutterColor *color)
{
ClutterRectanglePrivate *priv;
g_return_if_fail (CLUTTER_IS_RECTANGLE (rectangle));
g_return_if_fail (color != NULL);
priv = rectangle->priv;
if (priv->border_color.red != color->red ||
priv->border_color.green != color->green ||
priv->border_color.blue != color->blue ||
priv->border_color.alpha != color->alpha)
{
g_object_ref (rectangle);
priv->border_color.red = color->red;
priv->border_color.green = color->green;
priv->border_color.blue = color->blue;
priv->border_color.alpha = color->alpha;
if (clutter_color_equal (&priv->color, &priv->border_color))
priv->has_border = FALSE;
else
priv->has_border = TRUE;
clutter_actor_queue_redraw (CLUTTER_ACTOR (rectangle));
g_object_notify (G_OBJECT (rectangle), "border-color");
g_object_notify (G_OBJECT (rectangle), "has-border");
g_object_unref (rectangle);
}
}

View File

@ -0,0 +1,117 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_RECTANGLE_H__
#define __CLUTTER_RECTANGLE_H__
#include <glib-object.h>
#include <clutter/clutter-actor.h>
#include <clutter/clutter-color.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_RECTANGLE (clutter_rectangle_get_type())
#define CLUTTER_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_RECTANGLE, ClutterRectangle))
#define CLUTTER_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_RECTANGLE, ClutterRectangleClass))
#define CLUTTER_IS_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_RECTANGLE))
#define CLUTTER_IS_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_RECTANGLE))
#define CLUTTER_RECTANGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_RECTANGLE, ClutterRectangleClass))
typedef struct _ClutterRectangle ClutterRectangle;
typedef struct _ClutterRectangleClass ClutterRectangleClass;
typedef struct _ClutterRectanglePrivate ClutterRectanglePrivate;
/**
* ClutterRectangle:
*
* The #ClutterRectangle structure contains only private data
* and should be accessed using the provided API
*
* Since: 0.2
*/
struct _ClutterRectangle
{
/*< private >*/
ClutterActor parent;
ClutterRectanglePrivate *priv;
};
/**
* ClutterRectangleClass:
*
* The #ClutterRectangleClass structure contains only private data
*
* Since: 0.2
*/
struct _ClutterRectangleClass
{
/*< private >*/
ClutterActorClass parent_class;
/* padding for future expansion */
void (*_clutter_rectangle1) (void);
void (*_clutter_rectangle2) (void);
void (*_clutter_rectangle3) (void);
void (*_clutter_rectangle4) (void);
};
CLUTTER_DEPRECATED
GType clutter_rectangle_get_type (void) G_GNUC_CONST;
CLUTTER_DEPRECATED_FOR(clutter_actor_new)
ClutterActor *clutter_rectangle_new (void);
CLUTTER_DEPRECATED_FOR(clutter_actor_new)
ClutterActor *clutter_rectangle_new_with_color (const ClutterColor *color);
CLUTTER_DEPRECATED_FOR(clutter_actor_get_background_color)
void clutter_rectangle_get_color (ClutterRectangle *rectangle,
ClutterColor *color);
CLUTTER_DEPRECATED_FOR(clutter_actor_set_background_color)
void clutter_rectangle_set_color (ClutterRectangle *rectangle,
const ClutterColor *color);
CLUTTER_DEPRECATED
guint clutter_rectangle_get_border_width (ClutterRectangle *rectangle);
CLUTTER_DEPRECATED
void clutter_rectangle_set_border_width (ClutterRectangle *rectangle,
guint width);
CLUTTER_DEPRECATED
void clutter_rectangle_get_border_color (ClutterRectangle *rectangle,
ClutterColor *color);
CLUTTER_DEPRECATED
void clutter_rectangle_set_border_color (ClutterRectangle *rectangle,
const ClutterColor *color);
G_END_DECLS
#endif /* __CLUTTER_RECTANGLE_H__ */

View File

@ -0,0 +1,91 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2011 Intel Corp
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_STAGE_DEPRECATED_H__
#define __CLUTTER_STAGE_DEPRECATED_H__
#include <clutter/clutter-types.h>
G_BEGIN_DECLS
#ifndef CLUTTER_DISABLE_DEPRECATED
/**
* CLUTTER_STAGE_WIDTH:
*
* Macro that evaluates to the width of the default stage
*
* Since: 0.2
*
* Deprecated: 1.2: Use clutter_actor_get_width() instead
*/
#define CLUTTER_STAGE_WIDTH() (clutter_actor_get_width (clutter_stage_get_default ()))
/**
* CLUTTER_STAGE_HEIGHT:
*
* Macro that evaluates to the height of the default stage
*
* Since: 0.2
*
* Deprecated: 1.2: use clutter_actor_get_height() instead
*/
#define CLUTTER_STAGE_HEIGHT() (clutter_actor_get_height (clutter_stage_get_default ()))
/* Commodity macro, for mallum only */
#define clutter_stage_add(stage,actor) G_STMT_START { \
if (CLUTTER_IS_STAGE ((stage)) && CLUTTER_IS_ACTOR ((actor))) \
{ \
ClutterContainer *_container = (ClutterContainer *) (stage); \
ClutterActor *_actor = (ClutterActor *) (actor); \
clutter_container_add_actor (_container, _actor); \
} } G_STMT_END
#endif /* CLUTTER_DISABLE_DEPRECATED */
CLUTTER_DEPRECATED_FOR(clutter_stage_new)
ClutterActor * clutter_stage_get_default (void);
CLUTTER_DEPRECATED
gboolean clutter_stage_is_default (ClutterStage *stage);
CLUTTER_DEPRECATED_FOR(clutter_actor_queue_redraw)
void clutter_stage_queue_redraw (ClutterStage *stage);
CLUTTER_DEPRECATED_FOR(clutter_actor_set_background_color)
void clutter_stage_set_color (ClutterStage *stage,
const ClutterColor *color);
CLUTTER_DEPRECATED_FOR(clutter_actor_get_background_color)
void clutter_stage_get_color (ClutterStage *stage,
ClutterColor *color);
CLUTTER_DEPRECATED
void clutter_stage_ensure_current (ClutterStage *stage);
G_END_DECLS
#endif /* __CLUTTER_STAGE_DEPRECATED_H__ */

View File

@ -26,8 +26,15 @@
G_BEGIN_DECLS
CLUTTER_DEPRECATED_FOR(clutter_timeline_new_for_actor)
ClutterTimeline * clutter_timeline_new (guint duration_ms);
CLUTTER_DEPRECATED_FOR(clutter_timeline_new)
ClutterTimeline * clutter_timeline_clone (ClutterTimeline *timeline);
CLUTTER_DEPRECATED_FOR(clutter_timeline_set_repeat_count)
void clutter_timeline_set_loop (ClutterTimeline *timeline,
gboolean loop);
CLUTTER_DEPRECATED_FOR(clutter_timeline_get_repeat_count)
gboolean clutter_timeline_get_loop (ClutterTimeline *timeline);
G_END_DECLS

View File

@ -0,0 +1,297 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010,2011 Intel Corporation.
* 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Authors:
* Matthew Allum
* Emmanuele Bassi
* Robert Bragg
* Neil Roberts
*/
#include "clutter-build-config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "clutter-backend-eglnative.h"
/* This is a Cogl based backend */
#include "cogl/clutter-stage-cogl.h"
#include "clutter-debug.h"
#include "clutter-private.h"
#include "clutter-main.h"
#include "clutter-stage-private.h"
#include "clutter-settings-private.h"
#ifdef COGL_HAS_EGL_SUPPORT
#include "clutter-egl.h"
#endif
G_DEFINE_TYPE (ClutterBackendEglNative, clutter_backend_egl_native, CLUTTER_TYPE_BACKEND);
static void
clutter_backend_egl_native_dispose (GObject *gobject)
{
ClutterBackendEglNative *backend_egl_native = CLUTTER_BACKEND_EGL_NATIVE (gobject);
g_clear_object (&backend_egl_native->xsettings);
if (backend_egl_native->event_timer != NULL)
{
g_timer_destroy (backend_egl_native->event_timer);
backend_egl_native->event_timer = NULL;
}
G_OBJECT_CLASS (clutter_backend_egl_native_parent_class)->dispose (gobject);
}
static void
clutter_backend_egl_native_class_init (ClutterBackendEglNativeClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = clutter_backend_egl_native_dispose;
}
typedef struct
{
cairo_antialias_t cairo_antialias;
gint clutter_font_antialias;
cairo_hint_style_t cairo_hint_style;
const char *clutter_font_hint_style;
cairo_subpixel_order_t cairo_subpixel_order;
const char *clutter_font_subpixel_order;
} FontSettings;
static void
get_font_gsettings (GSettings *xsettings,
FontSettings *output)
{
/* org.gnome.settings-daemon.GsdFontAntialiasingMode */
static const struct
{
cairo_antialias_t cairo_antialias;
gint clutter_font_antialias;
}
antialiasings[] =
{
/* none=0 */ {CAIRO_ANTIALIAS_NONE, 0},
/* grayscale=1 */ {CAIRO_ANTIALIAS_GRAY, 1},
/* rgba=2 */ {CAIRO_ANTIALIAS_SUBPIXEL, 1},
};
/* org.gnome.settings-daemon.GsdFontHinting */
static const struct
{
cairo_hint_style_t cairo_hint_style;
const char *clutter_font_hint_style;
}
hintings[] =
{
/* none=0 */ {CAIRO_HINT_STYLE_NONE, "hintnone"},
/* slight=1 */ {CAIRO_HINT_STYLE_SLIGHT, "hintslight"},
/* medium=2 */ {CAIRO_HINT_STYLE_MEDIUM, "hintmedium"},
/* full=3 */ {CAIRO_HINT_STYLE_FULL, "hintfull"},
};
/* org.gnome.settings-daemon.GsdFontRgbaOrder */
static const struct
{
cairo_subpixel_order_t cairo_subpixel_order;
const char *clutter_font_subpixel_order;
}
rgba_orders[] =
{
/* rgba=0 */ {CAIRO_SUBPIXEL_ORDER_RGB, "rgb"}, /* XXX what is 'rgba'? */
/* rgb=1 */ {CAIRO_SUBPIXEL_ORDER_RGB, "rgb"},
/* bgr=2 */ {CAIRO_SUBPIXEL_ORDER_BGR, "bgr"},
/* vrgb=3 */ {CAIRO_SUBPIXEL_ORDER_VRGB, "vrgb"},
/* vbgr=4 */ {CAIRO_SUBPIXEL_ORDER_VBGR, "vbgr"},
};
guint i;
i = g_settings_get_enum (xsettings, "hinting");
if (i < G_N_ELEMENTS (hintings))
{
output->cairo_hint_style = hintings[i].cairo_hint_style;
output->clutter_font_hint_style = hintings[i].clutter_font_hint_style;
}
else
{
output->cairo_hint_style = CAIRO_HINT_STYLE_DEFAULT;
output->clutter_font_hint_style = NULL;
}
i = g_settings_get_enum (xsettings, "antialiasing");
if (i < G_N_ELEMENTS (antialiasings))
{
output->cairo_antialias = antialiasings[i].cairo_antialias;
output->clutter_font_antialias = antialiasings[i].clutter_font_antialias;
}
else
{
output->cairo_antialias = CAIRO_ANTIALIAS_DEFAULT;
output->clutter_font_antialias = -1;
}
i = g_settings_get_enum (xsettings, "rgba-order");
if (i < G_N_ELEMENTS (rgba_orders))
{
output->cairo_subpixel_order = rgba_orders[i].cairo_subpixel_order;
output->clutter_font_subpixel_order = rgba_orders[i].clutter_font_subpixel_order;
}
else
{
output->cairo_subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
output->clutter_font_subpixel_order = NULL;
}
if (output->cairo_antialias == CAIRO_ANTIALIAS_GRAY)
output->clutter_font_subpixel_order = "none";
}
static void
init_font_options (ClutterBackendEglNative *backend_egl_native)
{
GSettings *xsettings = backend_egl_native->xsettings;
cairo_font_options_t *options = cairo_font_options_create ();
FontSettings fs;
get_font_gsettings (xsettings, &fs);
cairo_font_options_set_hint_style (options, fs.cairo_hint_style);
cairo_font_options_set_antialias (options, fs.cairo_antialias);
cairo_font_options_set_subpixel_order (options, fs.cairo_subpixel_order);
clutter_backend_set_font_options (CLUTTER_BACKEND (backend_egl_native),
options);
cairo_font_options_destroy (options);
}
static gboolean
on_xsettings_change_event (GSettings *xsettings,
gpointer keys,
gint n_keys,
gpointer user_data)
{
/*
* A simpler alternative to this function that does not update the screen
* immediately (like macOS :P):
*
* init_font_options (CLUTTER_BACKEND_EGL_NATIVE (user_data));
*
* which has the added benefit of eliminating the need for all the
* FontSettings.clutter_ fields. However the below approach is better for
* testing settings and more consistent with the existing x11 backend...
*/
ClutterSettings *csettings = clutter_settings_get_default ();
FontSettings fs;
gint hinting;
get_font_gsettings (xsettings, &fs);
hinting = fs.cairo_hint_style == CAIRO_HINT_STYLE_NONE ? 0 : 1;
g_object_set (csettings,
"font-hinting", hinting,
"font-hint-style", fs.clutter_font_hint_style,
"font-antialias", fs.clutter_font_antialias,
"font-subpixel-order", fs.clutter_font_subpixel_order,
NULL);
return FALSE;
}
static void
clutter_backend_egl_native_init (ClutterBackendEglNative *backend_egl_native)
{
static const gchar xsettings_path[] = "org.gnome.settings-daemon.plugins.xsettings";
GSettingsSchemaSource *source = g_settings_schema_source_get_default ();
GSettingsSchema *schema = g_settings_schema_source_lookup (source,
xsettings_path,
TRUE);
if (!schema)
{
g_warning ("Failed to find schema: %s", xsettings_path);
}
else
{
backend_egl_native->xsettings = g_settings_new_full (schema, NULL, NULL);
if (backend_egl_native->xsettings)
{
init_font_options (backend_egl_native);
g_signal_connect (backend_egl_native->xsettings, "change-event",
G_CALLBACK (on_xsettings_change_event),
backend_egl_native);
}
}
backend_egl_native->event_timer = g_timer_new ();
}
ClutterBackend *
clutter_backend_egl_native_new (void)
{
return g_object_new (CLUTTER_TYPE_BACKEND_EGL_NATIVE, NULL);
}
/**
* clutter_egl_get_egl_display:
*
* Retrieves the EGL display used by Clutter, if it supports the
* EGL windowing system and if it is running using an EGL backend.
*
* Return value: the EGL display used by Clutter, or 0
*
* Since: 1.6
*/
EGLDisplay
clutter_egl_get_egl_display (void)
{
ClutterBackend *backend;
if (!_clutter_context_is_initialized ())
{
g_critical ("The Clutter backend has not been initialized yet");
return 0;
}
backend = clutter_get_default_backend ();
if (!CLUTTER_IS_BACKEND_EGL_NATIVE (backend))
{
g_critical ("The Clutter backend is not an EGL backend");
return 0;
}
#ifdef COGL_HAS_EGL_SUPPORT
return cogl_egl_context_get_egl_display (backend->cogl_context);
#else
return 0;
#endif
}

View File

@ -0,0 +1,78 @@
/* Clutter.
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2006, 2007 OpenedHand
* Copyright (C) 2010 Intel Corp
* 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Matthew Allum
* Robert Bragg
*/
#ifndef __CLUTTER_BACKEND_EGL_NATIVE_H__
#define __CLUTTER_BACKEND_EGL_NATIVE_H__
#include <glib-object.h>
#include <gio/gio.h>
#include <cogl/cogl.h>
#include <cogl/cogl-egl.h>
#include <clutter/clutter-event.h>
#include <clutter/clutter-backend.h>
#include "clutter-backend-private.h"
G_BEGIN_DECLS
#define CLUTTER_TYPE_BACKEND_EGL_NATIVE (clutter_backend_egl_native_get_type ())
#define CLUTTER_BACKEND_EGL_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_EGL_NATIVE, ClutterBackendEglNative))
#define CLUTTER_IS_BACKEND_EGL_NATIVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_EGL_NATIVE))
#define CLUTTER_BACKEND_EGL_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_EGL_NATIVE, ClutterBackendEglNativeClass))
#define CLUTTER_IS_BACKEND_EGL_NATIVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_EGL_NATIVE))
#define CLUTTER_BACKEND_EGL_NATIVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_EGL_NATIVE, ClutterBackendEglNativeClass))
typedef struct _ClutterBackendEglNative ClutterBackendEglNative;
typedef struct _ClutterBackendEglNativeClass ClutterBackendEglNativeClass;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBackendEglNative, g_object_unref)
struct _ClutterBackendEglNative
{
ClutterBackend parent_instance;
/* event source */
GSource *event_source;
/* event timer */
GTimer *event_timer;
/* "xsettings" is still the defacto place for Xft settings, even in Wayland */
GSettings *xsettings;
};
struct _ClutterBackendEglNativeClass
{
ClutterBackendClass parent_class;
};
CLUTTER_EXPORT
GType clutter_backend_egl_native_get_type (void) G_GNUC_CONST;
ClutterBackend *clutter_backend_egl_native_new (void);
G_END_DECLS
#endif /* __CLUTTER_BACKEND_EGL_NATIVE_H__ */

View File

@ -3,9 +3,9 @@
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By: Emmanuele Bassi <ebassi@linux.intel.com>
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2009 Intel Corporation.
* Copyright (C) 2006 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -19,15 +19,41 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef CLUTTER_TIMELINE_PRIVATE_H
#define CLUTTER_TIMELINE_PRIVATE_H
/**
* SECTION:clutter-egl
* @short_description: EGL specific API
*
* The EGL backend for Clutter provides some EGL specific API
*
* You need to include `clutter-egl.h` to have access to the functions documented here.
*/
void _clutter_timeline_advance (ClutterTimeline *timeline,
int64_t tick_time);
int64_t _clutter_timeline_get_delta (ClutterTimeline *timeline);
void _clutter_timeline_do_tick (ClutterTimeline *timeline,
int64_t tick_time);
#ifndef __CLUTTER_EGL_H__
#define __CLUTTER_EGL_H__
#endif /* CLUTTER_TIMELINE_PRIVATE_H */
#include <glib.h>
#include "clutter-egl-headers.h"
#include <clutter/clutter.h>
G_BEGIN_DECLS
/**
* clutter_egl_get_egl_display:
*
* Retrieves the #EGLDisplay used by Clutter.
*
* Return value: the EGL display
*
* Since: 1.6
*/
CLUTTER_EXPORT
EGLDisplay clutter_egl_get_egl_display (void);
G_END_DECLS
#endif /* __CLUTTER_EGL_H__ */

View File

@ -36,9 +36,9 @@ clutter_headers = [
'clutter-feature.h',
'clutter-fixed-layout.h',
'clutter-flow-layout.h',
'clutter-frame-clock.h',
'clutter-gesture-action.h',
'clutter-grid-layout.h',
'clutter-group.h',
'clutter-image.h',
'clutter-input-device.h',
'clutter-input-device-tool.h',
@ -123,7 +123,6 @@ clutter_sources = [
'clutter-fixed-layout.c',
'clutter-flatten-effect.c',
'clutter-flow-layout.c',
'clutter-frame-clock.c',
'clutter-gesture-action.c',
'clutter-graphene.c',
'clutter-grid-layout.c',
@ -141,6 +140,8 @@ clutter_sources = [
'clutter-layout-manager.c',
'clutter-layout-meta.c',
'clutter-main.c',
'clutter-master-clock.c',
'clutter-master-clock-default.c',
'clutter-offscreen-effect.c',
'clutter-page-turn-effect.c',
'clutter-paint-context.c',
@ -198,6 +199,8 @@ clutter_private_headers = [
'clutter-input-focus-private.h',
'clutter-input-method-private.h',
'clutter-input-pointer-a11y-private.h',
'clutter-master-clock.h',
'clutter-master-clock-default.h',
'clutter-offscreen-effect-private.h',
'clutter-paint-context-private.h',
'clutter-paint-node-private.h',
@ -209,7 +212,6 @@ clutter_private_headers = [
'clutter-stage-private.h',
'clutter-stage-view-private.h',
'clutter-stage-window.h',
'clutter-timeline-private.h',
]
clutter_nonintrospected_sources = [
@ -218,10 +220,21 @@ clutter_nonintrospected_sources = [
]
clutter_deprecated_headers = [
'deprecated/clutter-actor.h',
'deprecated/clutter-box.h',
'deprecated/clutter-container.h',
'deprecated/clutter-group.h',
'deprecated/clutter-rectangle.h',
'deprecated/clutter-stage.h',
'deprecated/clutter-timeline.h',
]
clutter_deprecated_sources = [
'deprecated/clutter-box.c',
'deprecated/clutter-group.c',
'deprecated/clutter-rectangle.c',
]
clutter_backend_sources = []
clutter_backend_nonintrospected_sources = [
'cogl/clutter-stage-cogl.c',
@ -257,6 +270,13 @@ if have_x11
clutter_backend_nonintrospected_sources += clutter_x11_nonintrospected_sources
endif
if have_native_backend
clutter_native_nonintrospected_sources = [
'egl/clutter-backend-eglnative.c',
]
clutter_backend_nonintrospected_sources += clutter_native_nonintrospected_sources
endif
if have_wayland
clutter_wayland_private_headers = [
'wayland/clutter-wayland-compositor.h',
@ -268,8 +288,10 @@ cally_headers = [
'cally/cally-actor.h',
'cally/cally-clone.h',
'cally/cally-factory.h',
'cally/cally-group.h',
'cally/cally.h',
'cally/cally-main.h',
'cally/cally-rectangle.h',
'cally/cally-root.h',
'cally/cally-stage.h',
'cally/cally-text.h',
@ -280,6 +302,8 @@ cally_sources = [
'cally/cally-actor.c',
'cally/cally.c',
'cally/cally-clone.c',
'cally/cally-group.c',
'cally/cally-rectangle.c',
'cally/cally-root.c',
'cally/cally-stage.c',
'cally/cally-text.c',
@ -361,6 +385,7 @@ libmutter_clutter = shared_library(libmutter_clutter_name,
clutter_headers,
clutter_private_headers,
clutter_nonintrospected_sources,
clutter_deprecated_sources,
clutter_deprecated_headers,
clutter_backend_sources,
clutter_backend_nonintrospected_sources,
@ -406,6 +431,7 @@ if have_introspection
clutter_built_headers,
clutter_sources,
clutter_headers,
clutter_deprecated_sources,
clutter_deprecated_headers,
],
nsversion: libmutter_api_version,

View File

@ -98,6 +98,7 @@ static const gchar *atom_names[] = {
/* various flags corresponding to pre init setup calls */
static gboolean clutter_enable_xinput = TRUE;
static gboolean clutter_enable_argb = FALSE;
static gboolean clutter_enable_stereo = FALSE;
static Display *_foreign_dpy = NULL;
@ -239,6 +240,13 @@ clutter_backend_x11_pre_parse (ClutterBackend *backend,
env_string = NULL;
}
env_string = g_getenv ("CLUTTER_DISABLE_ARGB_VISUAL");
if (env_string)
{
clutter_enable_argb = FALSE;
env_string = NULL;
}
env_string = g_getenv ("CLUTTER_DISABLE_XINPUT");
if (env_string)
{
@ -542,12 +550,15 @@ clutter_backend_x11_get_renderer (ClutterBackend *backend,
static gboolean
check_onscreen_template (CoglRenderer *renderer,
CoglSwapChain *swap_chain,
CoglOnscreenTemplate *onscreen_template,
gboolean enable_argb,
gboolean enable_stereo,
GError **error)
{
GError *internal_error = NULL;
cogl_swap_chain_set_has_alpha (swap_chain, enable_argb);
cogl_onscreen_template_set_stereo_enabled (onscreen_template,
clutter_enable_stereo);
@ -562,15 +573,17 @@ check_onscreen_template (CoglRenderer *renderer,
*/
if (cogl_renderer_check_onscreen_template (renderer, onscreen_template, &internal_error))
{
clutter_enable_argb = enable_argb;
clutter_enable_stereo = enable_stereo;
return TRUE;
}
else
{
if (enable_stereo) /* More possibilities to try */
if (enable_argb || enable_stereo) /* More possibilities to try */
CLUTTER_NOTE (BACKEND,
"Creation of a CoglDisplay with, stereo=%s failed: %s",
"Creation of a CoglDisplay with alpha=%s, stereo=%s failed: %s",
enable_argb ? "enabled" : "disabled",
enable_stereo ? "enabled" : "disabled",
internal_error != NULL
? internal_error->message
@ -598,7 +611,8 @@ clutter_backend_x11_get_display (ClutterBackend *backend,
CoglDisplay *display = NULL;
gboolean res = FALSE;
CLUTTER_NOTE (BACKEND, "Creating CoglDisplay, stereo=%s",
CLUTTER_NOTE (BACKEND, "Creating CoglDisplay, alpha=%s, stereo=%s",
clutter_enable_argb ? "enabled" : "disabled",
clutter_enable_stereo ? "enabled" : "disabled");
onscreen_template = cogl_onscreen_template_new (swap_chain);
@ -606,13 +620,22 @@ clutter_backend_x11_get_display (ClutterBackend *backend,
/* It's possible that the current renderer doesn't support transparency
* or doesn't support stereo, so we try the different combinations.
*/
if (clutter_enable_stereo)
res = check_onscreen_template (renderer, onscreen_template,
TRUE, error);
if (clutter_enable_argb && clutter_enable_stereo)
res = check_onscreen_template (renderer, swap_chain, onscreen_template,
TRUE, TRUE, error);
/* Prioritize stereo over alpha */
if (!res && clutter_enable_stereo)
res = check_onscreen_template (renderer, swap_chain, onscreen_template,
FALSE, TRUE, error);
if (!res && clutter_enable_argb)
res = check_onscreen_template (renderer, swap_chain, onscreen_template,
TRUE, FALSE, error);
if (!res)
res = check_onscreen_template (renderer, onscreen_template,
FALSE, error);
res = check_onscreen_template (renderer, swap_chain, onscreen_template,
FALSE, FALSE, error);
if (res)
display = cogl_display_new (renderer, onscreen_template);
@ -906,6 +929,99 @@ clutter_x11_remove_filter (ClutterX11FilterFunc func,
}
}
/**
* clutter_x11_has_composite_extension:
*
* Retrieves whether Clutter is running on an X11 server with the
* XComposite extension
*
* Return value: %TRUE if the XComposite extension is available
*/
gboolean
clutter_x11_has_composite_extension (void)
{
static gboolean have_composite = FALSE, done_check = FALSE;
int error = 0, event = 0;
Display *dpy;
if (done_check)
return have_composite;
if (!_clutter_context_is_initialized ())
{
g_critical ("X11 backend has not been initialised");
return FALSE;
}
dpy = clutter_x11_get_default_display();
if (dpy == NULL)
return FALSE;
if (XCompositeQueryExtension (dpy, &event, &error))
{
int major = 0, minor = 0;
if (XCompositeQueryVersion (dpy, &major, &minor))
{
if (major >= 0 && minor >= 3)
have_composite = TRUE;
}
}
done_check = TRUE;
return have_composite;
}
/**
* clutter_x11_set_use_argb_visual:
* @use_argb: %TRUE if ARGB visuals should be requested by default
*
* Sets whether the Clutter X11 backend should request ARGB visuals by default
* or not.
*
* By default, Clutter requests RGB visuals.
*
* If no ARGB visuals are found, the X11 backend will fall back to
* requesting a RGB visual instead.
*
* ARGB visuals are required for the #ClutterStage:use-alpha property to work.
*
* This function can only be called once, and before clutter_init() is
* called.
*
* Since: 1.2
*/
void
clutter_x11_set_use_argb_visual (gboolean use_argb)
{
if (_clutter_context_is_initialized ())
{
g_warning ("%s() can only be used before calling clutter_init()",
G_STRFUNC);
return;
}
CLUTTER_NOTE (BACKEND, "ARGB visuals are %s",
use_argb ? "enabled" : "disabled");
clutter_enable_argb = use_argb;
}
/**
* clutter_x11_get_use_argb_visual:
*
* Retrieves whether the Clutter X11 backend is using ARGB visuals by default
*
* Return value: %TRUE if ARGB visuals are queried by default
*
* Since: 1.2
*/
gboolean
clutter_x11_get_use_argb_visual (void)
{
return clutter_enable_argb;
}
/**
* clutter_x11_set_use_stereo_stage:
* @use_stereo: %TRUE if the stereo stages should be used if possible.

View File

@ -8,6 +8,12 @@ static const struct {
} _clutter_settings_map[] = {
{ "Net/DoubleClickDistance", "double-click-distance" },
{ "Net/DndDragThreshold", "dnd-drag-threshold" },
{ "Gtk/FontName", "font-name" },
{ "Xft/Antialias", "font-antialias" },
{ "Xft/Hinting", "font-hinting" },
{ "Xft/HintStyle", "font-hint-style" },
{ "Xft/RGBA", "font-subpixel-order" },
{ "Fontconfig/Timestamp", "fontconfig-timestamp" },
};
static const gint _n_clutter_settings_map = G_N_ELEMENTS (_clutter_settings_map);

View File

@ -109,6 +109,14 @@ CLUTTER_EXPORT
void clutter_x11_remove_filter (ClutterX11FilterFunc func,
gpointer data);
CLUTTER_EXPORT
gboolean clutter_x11_has_composite_extension (void);
CLUTTER_EXPORT
void clutter_x11_set_use_argb_visual (gboolean use_argb);
CLUTTER_EXPORT
gboolean clutter_x11_get_use_argb_visual (void);
CLUTTER_EXPORT
void clutter_x11_set_use_stereo_stage (gboolean use_stereo);
CLUTTER_EXPORT

View File

@ -8,7 +8,6 @@ clutter_c_args = [
'-DCLUTTER_SYSCONFDIR="@0@"'.format(join_paths(prefix, sysconfdir)),
'-DCLUTTER_COMPILATION=1',
'-DCOGL_DISABLE_DEPRECATION_WARNINGS',
'-DCOGL_ENABLE_MUTTER_API',
'-DG_LOG_DOMAIN="Clutter"',
]

View File

@ -48,6 +48,7 @@
#include "cogl1-context.h"
#include "cogl-sub-texture.h"
#include "cogl-gtype-private.h"
#include "driver/gl/cogl-pipeline-opengl-private.h"
#include "driver/gl/cogl-texture-gl-private.h"
#include <stdlib.h>

View File

@ -51,6 +51,11 @@
#include <stdio.h>
#include <stdlib.h>
/* This isn't defined in the GLES headers */
#ifndef GL_UNSIGNED_INT
#define GL_UNSIGNED_INT 0x1405
#endif
static void _cogl_attribute_free (CoglAttribute *attribute);
COGL_OBJECT_DEFINE (Attribute, attribute);

View File

@ -351,14 +351,6 @@ _cogl_bitmap_needs_short_temp_buffer (CoglPixelFormat format)
case COGL_PIXEL_FORMAT_BGRA_1010102_PRE:
case COGL_PIXEL_FORMAT_ARGB_2101010_PRE:
case COGL_PIXEL_FORMAT_ABGR_2101010_PRE:
case COGL_PIXEL_FORMAT_RGBA_FP_16161616:
case COGL_PIXEL_FORMAT_BGRA_FP_16161616:
case COGL_PIXEL_FORMAT_ARGB_FP_16161616:
case COGL_PIXEL_FORMAT_ABGR_FP_16161616:
case COGL_PIXEL_FORMAT_RGBA_FP_16161616_PRE:
case COGL_PIXEL_FORMAT_BGRA_FP_16161616_PRE:
case COGL_PIXEL_FORMAT_ARGB_FP_16161616_PRE:
case COGL_PIXEL_FORMAT_ABGR_FP_16161616_PRE:
return TRUE;
}

View File

@ -40,13 +40,13 @@
#define UNPACK_2(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \
1) / 3)
#define UNPACK_4(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \
7) / 0xf)
7) / 15)
#define UNPACK_5(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \
0xf) / 0x1f)
15) / 31)
#define UNPACK_6(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \
0x1f) / 0x3f)
31) / 63)
#define UNPACK_10(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \
0x1ff) / 0x3ff)
511) / 1023)
inline static void
G_PASTE (_cogl_unpack_a_8_, component_size) (const uint8_t *src,
@ -207,8 +207,8 @@ G_PASTE (_cogl_unpack_rgb_565_, component_size) (const uint8_t *src,
uint16_t v = *(const uint16_t *) src;
dst[0] = UNPACK_5 (v >> 11);
dst[1] = UNPACK_6 ((v >> 5) & 0x3f);
dst[2] = UNPACK_5 (v & 0x1f);
dst[1] = UNPACK_6 ((v >> 5) & 63);
dst[2] = UNPACK_5 (v & 31);
dst[3] = UNPACK_BYTE (255);
dst += 4;
src += 2;
@ -225,9 +225,9 @@ G_PASTE (_cogl_unpack_rgba_4444_, component_size) (const uint8_t *src,
uint16_t v = *(const uint16_t *) src;
dst[0] = UNPACK_4 (v >> 12);
dst[1] = UNPACK_4 ((v >> 8) & 0xf);
dst[2] = UNPACK_4 ((v >> 4) & 0xf);
dst[3] = UNPACK_4 (v & 0xf);
dst[1] = UNPACK_4 ((v >> 8) & 15);
dst[2] = UNPACK_4 ((v >> 4) & 15);
dst[3] = UNPACK_4 (v & 15);
dst += 4;
src += 2;
}
@ -243,8 +243,8 @@ G_PASTE (_cogl_unpack_rgba_5551_, component_size) (const uint8_t *src,
uint16_t v = *(const uint16_t *) src;
dst[0] = UNPACK_5 (v >> 11);
dst[1] = UNPACK_5 ((v >> 6) & 0x1f);
dst[2] = UNPACK_5 ((v >> 1) & 0x1f);
dst[1] = UNPACK_5 ((v >> 6) & 31);
dst[2] = UNPACK_5 ((v >> 1) & 31);
dst[3] = UNPACK_1 (v & 1);
dst += 4;
src += 2;
@ -261,8 +261,8 @@ G_PASTE (_cogl_unpack_rgba_1010102_, component_size) (const uint8_t *src,
uint32_t v = *(const uint32_t *) src;
dst[0] = UNPACK_10 (v >> 22);
dst[1] = UNPACK_10 ((v >> 12) & 0x3ff);
dst[2] = UNPACK_10 ((v >> 2) & 0x3ff);
dst[1] = UNPACK_10 ((v >> 12) & 1023);
dst[2] = UNPACK_10 ((v >> 2) & 1023);
dst[3] = UNPACK_2 (v & 3);
dst += 4;
src += 2;
@ -279,8 +279,8 @@ G_PASTE (_cogl_unpack_bgra_1010102_, component_size) (const uint8_t *src,
uint32_t v = *(const uint32_t *) src;
dst[2] = UNPACK_10 (v >> 22);
dst[1] = UNPACK_10 ((v >> 12) & 0x3ff);
dst[0] = UNPACK_10 ((v >> 2) & 0x3ff);
dst[1] = UNPACK_10 ((v >> 12) & 1023);
dst[0] = UNPACK_10 ((v >> 2) & 1023);
dst[3] = UNPACK_2 (v & 3);
dst += 4;
src += 2;
@ -297,9 +297,9 @@ G_PASTE (_cogl_unpack_argb_2101010_, component_size) (const uint8_t *src,
uint32_t v = *(const uint32_t *) src;
dst[3] = UNPACK_2 (v >> 30);
dst[0] = UNPACK_10 ((v >> 20) & 0x3ff);
dst[1] = UNPACK_10 ((v >> 10) & 0x3ff);
dst[2] = UNPACK_10 (v & 0x3ff);
dst[0] = UNPACK_10 ((v >> 20) & 1023);
dst[1] = UNPACK_10 ((v >> 10) & 1023);
dst[2] = UNPACK_10 (v & 1023);
dst += 4;
src += 2;
}
@ -315,22 +315,14 @@ G_PASTE (_cogl_unpack_abgr_2101010_, component_size) (const uint8_t *src,
uint32_t v = *(const uint32_t *) src;
dst[3] = UNPACK_2 (v >> 30);
dst[2] = UNPACK_10 ((v >> 20) & 0x3ff);
dst[1] = UNPACK_10 ((v >> 10) & 0x3ff);
dst[0] = UNPACK_10 (v & 0x3ff);
dst[2] = UNPACK_10 ((v >> 20) & 1023);
dst[1] = UNPACK_10 ((v >> 10) & 1023);
dst[0] = UNPACK_10 (v & 1023);
dst += 4;
src += 2;
}
}
inline static void
G_PASTE (_cogl_unpack_argb_fp_16161616_, component_size) (const uint8_t *src,
component_type *dst,
int width)
{
g_warning ("Not implemented");
}
#undef UNPACK_1
#undef UNPACK_2
#undef UNPACK_4
@ -404,16 +396,6 @@ G_PASTE (_cogl_unpack_, component_size) (CoglPixelFormat format,
case COGL_PIXEL_FORMAT_ABGR_2101010_PRE:
G_PASTE (_cogl_unpack_abgr_2101010_, component_size) (src, dst, width);
break;
case COGL_PIXEL_FORMAT_RGBA_FP_16161616:
case COGL_PIXEL_FORMAT_BGRA_FP_16161616:
case COGL_PIXEL_FORMAT_ARGB_FP_16161616:
case COGL_PIXEL_FORMAT_ABGR_FP_16161616:
case COGL_PIXEL_FORMAT_RGBA_FP_16161616_PRE:
case COGL_PIXEL_FORMAT_BGRA_FP_16161616_PRE:
case COGL_PIXEL_FORMAT_ARGB_FP_16161616_PRE:
case COGL_PIXEL_FORMAT_ABGR_FP_16161616_PRE:
G_PASTE (_cogl_unpack_argb_fp_16161616_, component_size) (src, dst, width);
break;
case COGL_PIXEL_FORMAT_DEPTH_16:
case COGL_PIXEL_FORMAT_DEPTH_32:
case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
@ -432,10 +414,10 @@ G_PASTE (_cogl_unpack_, component_size) (CoglPixelFormat format,
#define PACK_1(b) PACK_SIZE (b, 1)
#define PACK_2(b) PACK_SIZE (b, 3)
#define PACK_4(b) PACK_SIZE (b, 0xf)
#define PACK_5(b) PACK_SIZE (b, 0x1f)
#define PACK_6(b) PACK_SIZE (b, 0x3f)
#define PACK_10(b) PACK_SIZE (b, 0x3ff)
#define PACK_4(b) PACK_SIZE (b, 15)
#define PACK_5(b) PACK_SIZE (b, 31)
#define PACK_6(b) PACK_SIZE (b, 63)
#define PACK_10(b) PACK_SIZE (b, 1023)
inline static void
G_PASTE (_cogl_pack_a_8_, component_size) (const component_type *src,
@ -701,14 +683,6 @@ G_PASTE (_cogl_pack_abgr_2101010_, component_size) (const component_type *src,
}
}
inline static void
G_PASTE (_cogl_pack_argb_fp_16161616_, component_size) (const component_type *src,
uint8_t *dst,
int width)
{
g_warning ("Not implemented");
}
#undef PACK_SIZE
#undef PACK_1
#undef PACK_2
@ -783,16 +757,6 @@ G_PASTE (_cogl_pack_, component_size) (CoglPixelFormat format,
case COGL_PIXEL_FORMAT_ABGR_2101010_PRE:
G_PASTE (_cogl_pack_abgr_2101010_, component_size) (src, dst, width);
break;
case COGL_PIXEL_FORMAT_RGBA_FP_16161616:
case COGL_PIXEL_FORMAT_BGRA_FP_16161616:
case COGL_PIXEL_FORMAT_ARGB_FP_16161616:
case COGL_PIXEL_FORMAT_ABGR_FP_16161616:
case COGL_PIXEL_FORMAT_RGBA_FP_16161616_PRE:
case COGL_PIXEL_FORMAT_BGRA_FP_16161616_PRE:
case COGL_PIXEL_FORMAT_ARGB_FP_16161616_PRE:
case COGL_PIXEL_FORMAT_ABGR_FP_16161616_PRE:
G_PASTE (_cogl_pack_argb_fp_16161616_, component_size) (src, dst, width);
break;
case COGL_PIXEL_FORMAT_DEPTH_16:
case COGL_PIXEL_FORMAT_DEPTH_32:
case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:

View File

@ -34,6 +34,7 @@
#include "cogl-boxed-value.h"
#include "cogl-context-private.h"
#include "driver/gl/cogl-util-gl-private.h"
gboolean
_cogl_boxed_value_equal (const CoglBoxedValue *bva,
@ -285,5 +286,90 @@ _cogl_boxed_value_set_uniform (CoglContext *ctx,
GLint location,
const CoglBoxedValue *value)
{
ctx->driver_vtable->set_uniform (ctx, location, value);
switch (value->type)
{
case COGL_BOXED_NONE:
break;
case COGL_BOXED_INT:
{
const int *ptr;
if (value->count == 1)
ptr = value->v.int_value;
else
ptr = value->v.int_array;
switch (value->size)
{
case 1:
GE( ctx, glUniform1iv (location, value->count, ptr) );
break;
case 2:
GE( ctx, glUniform2iv (location, value->count, ptr) );
break;
case 3:
GE( ctx, glUniform3iv (location, value->count, ptr) );
break;
case 4:
GE( ctx, glUniform4iv (location, value->count, ptr) );
break;
}
}
break;
case COGL_BOXED_FLOAT:
{
const float *ptr;
if (value->count == 1)
ptr = value->v.float_value;
else
ptr = value->v.float_array;
switch (value->size)
{
case 1:
GE( ctx, glUniform1fv (location, value->count, ptr) );
break;
case 2:
GE( ctx, glUniform2fv (location, value->count, ptr) );
break;
case 3:
GE( ctx, glUniform3fv (location, value->count, ptr) );
break;
case 4:
GE( ctx, glUniform4fv (location, value->count, ptr) );
break;
}
}
break;
case COGL_BOXED_MATRIX:
{
const float *ptr;
if (value->count == 1)
ptr = value->v.matrix;
else
ptr = value->v.float_array;
switch (value->size)
{
case 2:
GE( ctx, glUniformMatrix2fv (location, value->count,
FALSE, ptr) );
break;
case 3:
GE( ctx, glUniformMatrix3fv (location, value->count,
FALSE, ptr) );
break;
case 4:
GE( ctx, glUniformMatrix4fv (location, value->count,
FALSE, ptr) );
break;
}
}
break;
}
}

View File

@ -46,6 +46,7 @@
#include "cogl-pipeline-cache.h"
#include "cogl-texture-2d.h"
#include "cogl-sampler-cache-private.h"
#include "cogl-gpu-info-private.h"
#include "cogl-gl-header.h"
#include "cogl-framebuffer-private.h"
#include "cogl-onscreen-private.h"
@ -69,12 +70,14 @@ struct _CoglContext
CoglDriver driver;
/* Information about the GPU and driver which we can use to
determine certain workarounds */
CoglGpuInfo gpu;
/* vtables for the driver functions */
const CoglDriverVtable *driver_vtable;
const CoglTextureDriver *texture_driver;
void *driver_context;
int glsl_major;
int glsl_minor;
@ -121,6 +124,9 @@ struct _CoglContext
CoglMatrixEntry identity_entry;
GArray *texture_units;
int active_texture_unit;
/* Only used for comparing other pipelines when reading pixels. */
CoglPipeline *opaque_color_pipeline;
@ -309,4 +315,18 @@ void
_cogl_context_set_current_modelview_entry (CoglContext *context,
CoglMatrixEntry *entry);
/*
* _cogl_context_get_gl_extensions:
* @context: A CoglContext
*
* Return value: a NULL-terminated array of strings representing the
* supported extensions by the current driver. This array is owned
* by the caller and should be freed with g_strfreev().
*/
char **
_cogl_context_get_gl_extensions (CoglContext *context);
const char *
_cogl_context_get_gl_version (CoglContext *context);
#endif /* __COGL_CONTEXT_PRIVATE_H */

View File

@ -30,7 +30,6 @@
#include "cogl-config.h"
#include "cogl-mutter.h"
#include "cogl-object.h"
#include "cogl-private.h"
#include "cogl-profile.h"
@ -46,12 +45,40 @@
#include "cogl-onscreen-private.h"
#include "cogl-attribute-private.h"
#include "cogl1-context.h"
#include "cogl-gpu-info-private.h"
#include "cogl-gtype-private.h"
#include "winsys/cogl-winsys-private.h"
#include <string.h>
#include <stdlib.h>
/* These aren't defined in the GLES headers */
#ifndef GL_POINT_SPRITE
#define GL_POINT_SPRITE 0x8861
#endif
#ifndef GL_NUM_EXTENSIONS
#define GL_NUM_EXTENSIONS 0x821D
#endif
/* This is a relatively new extension */
#ifndef GL_PURGED_CONTEXT_RESET_NV
#define GL_PURGED_CONTEXT_RESET_NV 0x92BB
#endif
/* These aren't defined in the GLES2 headers */
#ifndef GL_GUILTY_CONTEXT_RESET_ARB
#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253
#endif
#ifndef GL_INNOCENT_CONTEXT_RESET_ARB
#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254
#endif
#ifndef GL_UNKNOWN_CONTEXT_RESET_ARB
#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255
#endif
static void _cogl_context_free (CoglContext *context);
COGL_OBJECT_DEFINE (Context, context);
@ -443,6 +470,94 @@ _cogl_context_set_current_modelview_entry (CoglContext *context,
context->current_modelview_entry = entry;
}
char **
_cogl_context_get_gl_extensions (CoglContext *context)
{
const char *env_disabled_extensions;
char **ret;
/* In GL 3, querying GL_EXTENSIONS is deprecated so we have to build
* the array using glGetStringi instead */
#ifdef HAVE_COGL_GL
if (context->driver == COGL_DRIVER_GL3)
{
int num_extensions, i;
context->glGetIntegerv (GL_NUM_EXTENSIONS, &num_extensions);
ret = g_malloc (sizeof (char *) * (num_extensions + 1));
for (i = 0; i < num_extensions; i++)
{
const char *ext =
(const char *) context->glGetStringi (GL_EXTENSIONS, i);
ret[i] = g_strdup (ext);
}
ret[num_extensions] = NULL;
}
else
#endif
{
const char *all_extensions =
(const char *) context->glGetString (GL_EXTENSIONS);
ret = g_strsplit (all_extensions, " ", 0 /* max tokens */);
}
if ((env_disabled_extensions = g_getenv ("COGL_DISABLE_GL_EXTENSIONS")))
{
char **split_env_disabled_extensions;
char **src, **dst;
if (env_disabled_extensions)
split_env_disabled_extensions =
g_strsplit (env_disabled_extensions,
",",
0 /* no max tokens */);
else
split_env_disabled_extensions = NULL;
for (dst = ret, src = ret;
*src;
src++)
{
char **d;
if (split_env_disabled_extensions)
for (d = split_env_disabled_extensions; *d; d++)
if (!strcmp (*src, *d))
goto disabled;
*(dst++) = *src;
continue;
disabled:
g_free (*src);
continue;
}
*dst = NULL;
if (split_env_disabled_extensions)
g_strfreev (split_env_disabled_extensions);
}
return ret;
}
const char *
_cogl_context_get_gl_version (CoglContext *context)
{
const char *version_override;
if ((version_override = g_getenv ("COGL_OVERRIDE_GL_VERSION")))
return version_override;
else
return (const char *) context->glGetString (GL_VERSION);
}
int64_t
cogl_get_clock_time (CoglContext *context)
{
@ -457,18 +572,24 @@ cogl_get_clock_time (CoglContext *context)
CoglGraphicsResetStatus
cogl_get_graphics_reset_status (CoglContext *context)
{
return context->driver_vtable->get_graphics_reset_status (context);
}
if (!context->glGetGraphicsResetStatus)
return COGL_GRAPHICS_RESET_STATUS_NO_ERROR;
gboolean
cogl_context_is_hardware_accelerated (CoglContext *context)
{
return context->driver_vtable->is_hardware_accelerated (context);
}
switch (context->glGetGraphicsResetStatus ())
{
case GL_GUILTY_CONTEXT_RESET_ARB:
return COGL_GRAPHICS_RESET_STATUS_GUILTY_CONTEXT_RESET;
gboolean
cogl_context_format_supports_upload (CoglContext *ctx,
CoglPixelFormat format)
{
return ctx->texture_driver->format_supports_upload (ctx, format);
case GL_INNOCENT_CONTEXT_RESET_ARB:
return COGL_GRAPHICS_RESET_STATUS_INNOCENT_CONTEXT_RESET;
case GL_UNKNOWN_CONTEXT_RESET_ARB:
return COGL_GRAPHICS_RESET_STATUS_UNKNOWN_CONTEXT_RESET;
case GL_PURGED_CONTEXT_RESET_NV:
return COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET;
default:
return COGL_GRAPHICS_RESET_STATUS_NO_ERROR;
}
}

View File

@ -357,16 +357,6 @@ typedef enum _CoglGraphicsResetStatus
COGL_EXPORT CoglGraphicsResetStatus
cogl_get_graphics_reset_status (CoglContext *context);
/**
* cogl_context_is_hardware_accelerated:
* @context: a #CoglContext pointer
*
* Returns: %TRUE if the @context is hardware accelerated, or %FALSE if
* not.
*/
COGL_EXPORT gboolean
cogl_context_is_hardware_accelerated (CoglContext *context);
G_END_DECLS
#endif /* __COGL_CONTEXT_H__ */

View File

@ -35,7 +35,6 @@
#include "cogl-offscreen.h"
#include "cogl-framebuffer-private.h"
#include "cogl-attribute-private.h"
#include "cogl-sampler-cache-private.h"
typedef struct _CoglDriverVtable CoglDriverVtable;
@ -47,12 +46,6 @@ struct _CoglDriverVtable
void
(* context_deinit) (CoglContext *context);
gboolean
(* is_hardware_accelerated) (CoglContext *context);
CoglGraphicsResetStatus
(* get_graphics_reset_status) (CoglContext *context);
/* TODO: factor this out since this is OpenGL specific and
* so can be ignored by non-OpenGL drivers. */
gboolean
@ -269,19 +262,6 @@ struct _CoglDriverVtable
const void *data,
unsigned int size,
GError **error);
void
(*sampler_init) (CoglContext *context,
CoglSamplerCacheEntry *entry);
void
(*sampler_free) (CoglContext *context,
CoglSamplerCacheEntry *entry);
void
(* set_uniform) (CoglContext *ctx,
GLint location,
const CoglBoxedValue *value);
};
#define COGL_DRIVER_ERROR (_cogl_driver_error_quark ())

Some files were not shown because too many files have changed in this diff Show More